Merge branch 'master' of git.zcorp.cc:easycorp/zentaopms
This commit is contained in:
Vendored
+1
-1
@@ -37,7 +37,7 @@ pipeline {
|
||||
container('sonar') {
|
||||
withSonarQubeEnv('sonarqube') {
|
||||
sh 'git config --global --add safe.directory $(pwd)'
|
||||
sh 'sonar-scanner -Dsonar.analysis.user=$(git show -s --format=%an)'
|
||||
sh 'sonar-scanner -Dsonar.inclusions=$(git diff --name-only HEAD~1|tr "\\n" ",") -Dsonar.analysis.user=$(git show -s --format=%an)'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
-2
@@ -1,5 +1,9 @@
|
||||
ALTER TABLE `zt_block` ADD `dashboard` varchar(20) NOT NULL DEFAULT '' AFTER `account`;
|
||||
UPDATE `zt_block` SET `dashboard` = `module`;
|
||||
UPDATE `zt_block` SET `module` = IF(`source` != '', `source`, `block`);
|
||||
ALTER TABLE `zt_block` CHANGE `block` `code` varchar(30) NOT NULL DEFAULT '' AFTER `module`;
|
||||
ALTER TABLE `zt_block` MODIFY `vision` varchar(10) NOT NULL DEFAULT 'rnd' AFTER `hidden`;
|
||||
|
||||
ALTER TABLE `zt_todo` CHANGE `idvalue` `objectID` mediumint(8) unsigned default '0' NOT NULL AFTER `type`;
|
||||
|
||||
UPDATE `zt_block` SET `dashboard` = `module`;
|
||||
UPDATE `zt_block` SET `module` = IF(`source` != '', `source`, `code`);
|
||||
|
||||
|
||||
+23
-24
@@ -115,25 +115,25 @@ $config->block->params['product']->type['name'] = $lang->block->type;
|
||||
$config->block->params['product']->type['options'] = $lang->block->typeList->product;
|
||||
$config->block->params['product']->type['control'] = 'select';
|
||||
|
||||
$config->block->params['productStatic'] = clone $config->block->params['default'];
|
||||
$config->block->params['productStatic']->type['name'] = $lang->block->type;
|
||||
$config->block->params['productStatic']->type['options'] = $lang->block->typeList->product;
|
||||
$config->block->params['productStatic']->type['control'] = 'select';
|
||||
$config->block->params['productStatistic'] = clone $config->block->params['default'];
|
||||
$config->block->params['productStatistic']->type['name'] = $lang->block->type;
|
||||
$config->block->params['productStatistic']->type['options'] = $lang->block->typeList->product;
|
||||
$config->block->params['productStatistic']->type['control'] = 'select';
|
||||
|
||||
$config->block->params['projectStatic'] = clone $config->block->params['default'];
|
||||
$config->block->params['projectStatic']->type['name'] = $lang->block->type;
|
||||
$config->block->params['projectStatic']->type['options'] = $lang->block->typeList->project;
|
||||
$config->block->params['projectStatic']->type['control'] = 'select';
|
||||
$config->block->params['projectStatistic'] = clone $config->block->params['default'];
|
||||
$config->block->params['projectStatistic']->type['name'] = $lang->block->type;
|
||||
$config->block->params['projectStatistic']->type['options'] = $lang->block->typeList->project;
|
||||
$config->block->params['projectStatistic']->type['control'] = 'select';
|
||||
|
||||
$config->block->params['executionStatic'] = clone $config->block->params['default'];
|
||||
$config->block->params['executionStatic']->type['name'] = $lang->block->type;
|
||||
$config->block->params['executionStatic']->type['options'] = $lang->block->typeList->execution;
|
||||
$config->block->params['executionStatic']->type['control'] = 'select';
|
||||
$config->block->params['executionStatistic'] = clone $config->block->params['default'];
|
||||
$config->block->params['executionStatistic']->type['name'] = $lang->block->type;
|
||||
$config->block->params['executionStatistic']->type['options'] = $lang->block->typeList->execution;
|
||||
$config->block->params['executionStatistic']->type['control'] = 'select';
|
||||
|
||||
$config->block->params['qaStatic'] = clone $config->block->params['default'];
|
||||
$config->block->params['qaStatic']->type['name'] = $lang->block->type;
|
||||
$config->block->params['qaStatic']->type['options'] = $lang->block->typeList->product;
|
||||
$config->block->params['qaStatic']->type['control'] = 'select';
|
||||
$config->block->params['qaStatistic'] = clone $config->block->params['default'];
|
||||
$config->block->params['qaStatistic']->type['name'] = $lang->block->type;
|
||||
$config->block->params['qaStatistic']->type['options'] = $lang->block->typeList->product;
|
||||
$config->block->params['qaStatistic']->type['control'] = 'select';
|
||||
|
||||
$config->block->params['waterfallIssue'] = clone $config->block->params['default'];
|
||||
$config->block->params['waterfallIssue']->type['name'] = $lang->block->type;
|
||||
@@ -283,16 +283,15 @@ $config->block->modules['doc']->moreLinkList->projectdoc = 'doc|projectspac
|
||||
$config->block->form = new stdclass();
|
||||
$config->block->form->create = array();
|
||||
$config->block->form->create['module'] = array('type' => 'string', 'required' => false, 'default' => '');
|
||||
$config->block->form->create['block'] = array('type' => 'string', 'required' => false, 'default' => '');
|
||||
$config->block->form->create['code'] = array('type' => 'string', 'required' => false, 'default' => '');
|
||||
$config->block->form->create['title'] = array('type' => 'string', 'required' => false, 'default' => '');
|
||||
$config->block->form->create['grid'] = array('type' => 'int', 'required' => false, 'default' => '4');
|
||||
$config->block->form->create['hidden'] = array('type' => 'int', 'required' => false, 'default' => '0');
|
||||
$config->block->form->create['params'] = array('type' => 'array', 'required' => false, 'default' => array());
|
||||
|
||||
$config->block->form = new stdclass();
|
||||
$config->block->form->create = array();
|
||||
$config->block->form->create['module'] = array('type' => 'string', 'required' => false, 'default' => '');
|
||||
$config->block->form->create['block'] = array('type' => 'string', 'required' => false, 'default' => '');
|
||||
$config->block->form->create['title'] = array('type' => 'string', 'required' => false, 'default' => '');
|
||||
$config->block->form->create['grid'] = array('type' => 'int', 'required' => false, 'default' => '4');
|
||||
$config->block->form->create['params'] = array('type' => 'array', 'required' => false, 'default' => array());
|
||||
$config->block->form->edit = array();
|
||||
$config->block->form->edit['module'] = array('type' => 'string', 'required' => false, 'default' => '');
|
||||
$config->block->form->edit['code'] = array('type' => 'string', 'required' => false, 'default' => '');
|
||||
$config->block->form->edit['title'] = array('type' => 'string', 'required' => false, 'default' => '');
|
||||
$config->block->form->edit['grid'] = array('type' => 'int', 'required' => false, 'default' => '4');
|
||||
$config->block->form->edit['params'] = array('type' => 'array', 'required' => false, 'default' => array());
|
||||
|
||||
+35
-113
@@ -30,11 +30,11 @@ class block extends control
|
||||
*
|
||||
* @param string $dashboard
|
||||
* @param string $module
|
||||
* @param string $block
|
||||
* @param string $code
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function create(string $dashboard, string $module = '', string $block = '')
|
||||
public function create(string $dashboard, string $module = '', string $code = '')
|
||||
{
|
||||
if($_POST)
|
||||
{
|
||||
@@ -53,10 +53,10 @@ class block extends control
|
||||
$this->view->title = $this->lang->block->createBlock;
|
||||
$this->view->dashboard = $dashboard;
|
||||
$this->view->module = $module;
|
||||
$this->view->block = $block;
|
||||
$this->view->code = $code;
|
||||
$this->view->modules = $this->blockZen->getAvailableModules($dashboard);
|
||||
$this->view->blocks = $this->blockZen->getAvailableBlocks($dashboard, $module);
|
||||
$this->view->params = $this->blockZen->getAvailableParams($dashboard, $module, $block);
|
||||
$this->view->codes = $this->blockZen->getAvailableBlocks($dashboard, $module);
|
||||
$this->view->params = $this->blockZen->getAvailableParams($dashboard, $module, $code);
|
||||
$this->display();
|
||||
}
|
||||
|
||||
@@ -65,11 +65,11 @@ class block extends control
|
||||
*
|
||||
* @param string $dashboard
|
||||
* @param string $module
|
||||
* @param string $block
|
||||
* @param string $code
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function edit(string $blockID, string $module = '', string $block = '')
|
||||
public function edit(string $blockID, string $module = '', string $code = '')
|
||||
{
|
||||
$blockID = (int)$blockID;
|
||||
if($_POST)
|
||||
@@ -83,22 +83,22 @@ class block extends control
|
||||
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'load' => true, 'closeModal' => true, 'callback' => 'loadCurrentPage()'));
|
||||
}
|
||||
|
||||
$blockData = $this->block->getByID($blockID);
|
||||
$block = $this->block->getByID($blockID);
|
||||
|
||||
$this->view->title = $this->lang->block->editBlock;
|
||||
$this->view->blockData = $blockData;
|
||||
$this->view->block = $block ? $block : $blockData->block;
|
||||
$this->view->module = $module ? $module : $blockData->module;
|
||||
$this->view->modules = $this->blockZen->getAvailableModules($blockData->dashboard);
|
||||
$this->view->blocks = $this->blockZen->getAvailableBlocks($blockData->dashboard, $this->view->module);
|
||||
$this->view->params = $this->blockZen->getAvailableParams($blockData->dashboard, $this->view->module, $this->view->block);
|
||||
$this->view->block = $block;
|
||||
$this->view->module = $module ? $module : $block->module;
|
||||
$this->view->code = $code ? $code : $block->code;
|
||||
$this->view->modules = $this->blockZen->getAvailableModules($block->dashboard);
|
||||
$this->view->codes = $this->blockZen->getAvailableBlocks($block->dashboard, $this->view->module);
|
||||
$this->view->params = $this->blockZen->getAvailableParams($block->dashboard, $this->view->module, $this->view->code);
|
||||
$this->display();
|
||||
}
|
||||
|
||||
public function set($id, $type, $module = '')
|
||||
{
|
||||
$block = $this->block->getByID($id);
|
||||
if($block and empty($type)) $type = $block->block;
|
||||
if($block and empty($type)) $type = $block->code;
|
||||
if(isset($block->params->num) and !isset($block->params->count))
|
||||
{
|
||||
$block->params->count = $block->params->num;
|
||||
@@ -203,15 +203,15 @@ class block extends control
|
||||
}
|
||||
|
||||
/**
|
||||
* 展示应用的仪表盘
|
||||
* Display dashboard for app.
|
||||
*
|
||||
* @param string $module
|
||||
* @param string $type
|
||||
* @param int $projectID
|
||||
* @param string $module
|
||||
* @param int $projectID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function dashboard($module, $projectID = 0)
|
||||
public function dashboard(string $module, int $projectID = 0)
|
||||
{
|
||||
if($this->loadModel('user')->isLogon()) $this->session->set('blockModule', $module);
|
||||
$blocks = $this->block->getMyDashboard($module);
|
||||
@@ -224,103 +224,25 @@ class block extends control
|
||||
$section = $project->model . 'common';
|
||||
}
|
||||
|
||||
$inited = $this->dao->select('*')->from(TABLE_CONFIG)
|
||||
->where('module')->eq($module)
|
||||
->andWhere('owner')->eq($this->app->user->account)
|
||||
->andWhere('`section`')->eq($section)->fi()
|
||||
->andWhere('`key`')->eq('blockInited')
|
||||
->andWhere('vision')->eq($vision)
|
||||
->fetch('value');
|
||||
$isInitiated = $this->block->fetchBlockInitStatus($module, $vision, $section);
|
||||
|
||||
/* Init block when vist index first. */
|
||||
if((empty($blocks) and !$inited and !defined('TUTORIAL')))
|
||||
if(empty($blocks) and !$isInitiated and !defined('TUTORIAL') and $this->block->initBlock($module))
|
||||
{
|
||||
if($this->block->initBlock($module, $type)) return print(js::reload());
|
||||
return print(js::reload());
|
||||
}
|
||||
|
||||
$acls = $this->app->user->rights['acls'];
|
||||
$shortBlocks = $longBlocks = array();
|
||||
foreach($blocks as $key => $block)
|
||||
{
|
||||
if(in_array($block->block, array('waterfallrisk', 'waterfallissue')))
|
||||
{
|
||||
$model = isset($project->model) ? $project->model : 'waterfall';
|
||||
if($block->block == 'waterfallrisk' and !helper::hasFeature("{$model}_risk")) continue;
|
||||
if($block->block == 'waterfallissue' and !helper::hasFeature("{$model}_issue")) continue;
|
||||
}
|
||||
$blocks = $this->blockZen->processBlockForRender($blocks, isset($project) ? $project : null);
|
||||
|
||||
if(in_array($block->block, array('scrumrisk', 'scrumissue')))
|
||||
{
|
||||
$model = isset($project->model) ? $project->model : 'scrum';
|
||||
if($block->block == 'scrumrisk' and !helper::hasFeature("{$model}_risk")) continue;
|
||||
if($block->block == 'scrumissue' and !helper::hasFeature("{$model}_issue")) continue;
|
||||
}
|
||||
if($this->app->getViewType() == 'json') return print(json_encode($blocks));
|
||||
|
||||
if(!empty($block->source) and $block->source != 'todo' and !empty($acls['views']) and !isset($acls['views'][$block->source]))
|
||||
{
|
||||
unset($blocks[$key]);
|
||||
continue;
|
||||
}
|
||||
|
||||
$block->params = json_decode($block->params);
|
||||
if(isset($block->params->num) and !isset($block->params->count)) $block->params->count = $block->params->num;
|
||||
|
||||
$blockID = $block->block;
|
||||
$source = empty($block->source) ? 'common' : $block->source;
|
||||
|
||||
$block->blockLink = $this->createLink('block', 'printBlock', "id=$block->id&module=$block->module");
|
||||
$block->moreLink = '';
|
||||
if(isset($this->config->block->modules[$source]->moreLinkList->{$blockID}))
|
||||
{
|
||||
list($moduleName, $method, $vars) = explode('|', sprintf($this->config->block->modules[$source]->moreLinkList->{$blockID}, isset($block->params->type) ? $block->params->type : ''));
|
||||
|
||||
/* The list assigned to me jumps to the work page when click more button. */
|
||||
$block->moreLink = $this->createLink($moduleName, $method, $vars);
|
||||
if($moduleName == 'my' and strpos($this->config->block->workMethods, $method) !== false)
|
||||
{
|
||||
$block->moreLink = $this->createLink($moduleName, 'work', 'mode=' . $method . '&' . $vars);
|
||||
}
|
||||
elseif($moduleName == 'project' and $method == 'dynamic')
|
||||
{
|
||||
$block->moreLink = $this->createLink('project', 'dynamic', "projectID=$projectID&type=all");
|
||||
}
|
||||
elseif($moduleName == 'project' and $method == 'execution')
|
||||
{
|
||||
$block->moreLink = $this->createLink('project', 'execution', "status=all&projectID=$projectID");
|
||||
}
|
||||
elseif($moduleName == 'project' and $method == 'testtask')
|
||||
{
|
||||
$block->moreLink = $this->createLink('project', 'testtask', "projectID=$projectID");
|
||||
}
|
||||
elseif($moduleName == 'testtask' and $method == 'browse')
|
||||
{
|
||||
$block->moreLink = $this->createLink('testtask', 'browse', "productID=0&branch=0&type=all,totalStatus");
|
||||
}
|
||||
|
||||
}
|
||||
elseif($block->block == 'dynamic')
|
||||
{
|
||||
$block->moreLink = $this->createLink('company', 'dynamic');
|
||||
}
|
||||
|
||||
if($this->block->isLongBlock($block))
|
||||
{
|
||||
$longBlocks[$key] = $block;
|
||||
}
|
||||
else
|
||||
{
|
||||
$shortBlocks[$key] = $block;
|
||||
}
|
||||
}
|
||||
list($shortBlocks, $longBlocks) = $this->blockZen->splitBlocksByLen($blocks);
|
||||
|
||||
$this->view->title = zget($this->lang->block->dashboard, $module, $this->lang->block->dashboard['default']);
|
||||
$this->view->longBlocks = $longBlocks;
|
||||
$this->view->shortBlocks = $shortBlocks;
|
||||
$this->view->dashboard = $module;
|
||||
|
||||
if($this->app->getViewType() == 'json') return print(json_encode($blocks));
|
||||
|
||||
$this->display();
|
||||
$this->render();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -399,7 +321,7 @@ class block extends control
|
||||
if(empty($block)) return false;
|
||||
|
||||
$html = '';
|
||||
if($block->block == 'html')
|
||||
if($block->code == 'html')
|
||||
{
|
||||
if (empty($block->params->html))
|
||||
{
|
||||
@@ -416,28 +338,28 @@ class block extends control
|
||||
$this->get->set('blockTitle', $block->title);
|
||||
$this->get->set('module', $block->module);
|
||||
$this->get->set('source', $block->source);
|
||||
$this->get->set('blockid', $block->block);
|
||||
$this->get->set('blockid', $block->code);
|
||||
$this->get->set('param', base64_encode(json_encode($block->params)));
|
||||
$html = $this->fetch('block', 'main', "module={$block->source}&id=$id");
|
||||
}
|
||||
elseif($block->block == 'dynamic')
|
||||
elseif($block->code == 'dynamic')
|
||||
{
|
||||
$html = $this->fetch('block', 'dynamic');
|
||||
}
|
||||
elseif($block->block == 'guide')
|
||||
elseif($block->code == 'guide')
|
||||
{
|
||||
$html = $this->fetch('block', 'guide', "blockID=$block->id");
|
||||
}
|
||||
elseif($block->block == 'assigntome')
|
||||
elseif($block->code == 'assigntome')
|
||||
{
|
||||
$this->get->set('param', base64_encode(json_encode($block->params)));
|
||||
$html = $this->fetch('block', 'printAssignToMeBlock', 'longBlock=' . $this->block->isLongBlock($block));
|
||||
}
|
||||
elseif($block->block == 'welcome')
|
||||
elseif($block->code == 'welcome')
|
||||
{
|
||||
$html = $this->fetch('block', 'welcome', "blockID=$block->id");
|
||||
}
|
||||
elseif($block->block == 'contribute')
|
||||
elseif($block->code == 'contribute')
|
||||
{
|
||||
$html = $this->fetch('block', 'contribute');
|
||||
}
|
||||
@@ -2233,8 +2155,8 @@ class block extends control
|
||||
{
|
||||
$block = $this->block->getByID($blockID);
|
||||
$closedBlock = isset($this->config->block->closed) ? $this->config->block->closed : '';
|
||||
$this->dao->delete()->from(TABLE_BLOCK)->where('source')->eq($block->source)->andWhere('block')->eq($block->block)->exec();
|
||||
$this->loadModel('setting')->setItem('system.block.closed', $closedBlock . ",{$block->source}|{$block->block}");
|
||||
$this->dao->delete()->from(TABLE_BLOCK)->where('source')->eq($block->source)->andWhere('code')->eq($block->code)->exec();
|
||||
$this->loadModel('setting')->setItem('system.block.closed', $closedBlock . ",{$block->source}|{$block->code}");
|
||||
return print(js::reload('parent'));
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ function getForm(event)
|
||||
{
|
||||
const field = $(event.target).attr('id');
|
||||
const module = $('#module').val();
|
||||
const block = field == 'module' ? '' : $('#block').val();
|
||||
const url = $.createLink('block', 'create', 'dashboard='+ dashboard +'&module=' + module + '&block=' + (block ? block : ''));
|
||||
loadPage(url, '#blockRow, #paramsRow');
|
||||
const code = field == 'module' ? '' : $('#code').val();
|
||||
const url = $.createLink('block', 'create', 'dashboard='+ dashboard +'&module=' + module + '&code=' + (code ? code : ''));
|
||||
loadPage(url, '#codeRow, #paramsRow');
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ function getForm(event)
|
||||
{
|
||||
const field = $(event.target).attr('id');
|
||||
const module = $('#module').val();
|
||||
const block = field == 'module' ? '' : $('#block').val();
|
||||
const url = $.createLink('block', 'edit', 'blockID=' + blockID + '&module=' + module + '&block=' + (block ? block : ''));
|
||||
loadPage(url, '#blockRow, #paramsRow');
|
||||
const code = field == 'module' ? '' : $('#code').val();
|
||||
const url = $.createLink('block', 'edit', 'blockID=' + blockID + '&module=' + module + '&code=' + (code ? code : ''));
|
||||
loadPage(url, '#codeRow, #paramsRow');
|
||||
}
|
||||
|
||||
+38
-38
@@ -134,23 +134,23 @@ $lang->block->titleList['case'] = '指派给我的用例';
|
||||
$lang->block->titleList['testtask'] = '待测版本列表';
|
||||
|
||||
$lang->block->default['waterfall']['project']['3']['title'] = "{$lang->projectCommon}计划";
|
||||
$lang->block->default['waterfall']['project']['3']['block'] = 'waterfallgantt';
|
||||
$lang->block->default['waterfall']['project']['3']['code'] = 'waterfallgantt';
|
||||
$lang->block->default['waterfall']['project']['3']['source'] = 'project';
|
||||
$lang->block->default['waterfall']['project']['3']['grid'] = 8;
|
||||
|
||||
$lang->block->default['waterfall']['project']['6']['title'] = '最新动态';
|
||||
$lang->block->default['waterfall']['project']['6']['block'] = 'projectdynamic';
|
||||
$lang->block->default['waterfall']['project']['6']['code'] = 'projectdynamic';
|
||||
$lang->block->default['waterfall']['project']['6']['grid'] = 4;
|
||||
$lang->block->default['waterfall']['project']['6']['source'] = 'project';
|
||||
|
||||
$lang->block->default['waterfallplus'] = $lang->block->default['waterfall'];
|
||||
|
||||
$lang->block->default['scrum']['project']['1']['title'] = $lang->projectCommon . '概况';
|
||||
$lang->block->default['scrum']['project']['1']['block'] = 'scrumoverview';
|
||||
$lang->block->default['scrum']['project']['1']['code'] = 'scrumoverview';
|
||||
$lang->block->default['scrum']['project']['1']['grid'] = 8;
|
||||
|
||||
$lang->block->default['scrum']['project']['2']['title'] = $lang->executionCommon . '列表';
|
||||
$lang->block->default['scrum']['project']['2']['block'] = 'scrumlist';
|
||||
$lang->block->default['scrum']['project']['2']['code'] = 'scrumlist';
|
||||
$lang->block->default['scrum']['project']['2']['grid'] = 8;
|
||||
|
||||
$lang->block->default['scrum']['project']['2']['params']['type'] = 'undone';
|
||||
@@ -158,7 +158,7 @@ $lang->block->default['scrum']['project']['2']['params']['count'] = '20';
|
||||
$lang->block->default['scrum']['project']['2']['params']['orderBy'] = 'id_desc';
|
||||
|
||||
$lang->block->default['scrum']['project']['3']['title'] = '待测版本';
|
||||
$lang->block->default['scrum']['project']['3']['block'] = 'scrumtest';
|
||||
$lang->block->default['scrum']['project']['3']['code'] = 'scrumtest';
|
||||
$lang->block->default['scrum']['project']['3']['grid'] = 8;
|
||||
|
||||
$lang->block->default['scrum']['project']['3']['params']['type'] = 'wait';
|
||||
@@ -166,35 +166,35 @@ $lang->block->default['scrum']['project']['3']['params']['count'] = '15';
|
||||
$lang->block->default['scrum']['project']['3']['params']['orderBy'] = 'id_desc';
|
||||
|
||||
$lang->block->default['scrum']['project']['4']['title'] = $lang->executionCommon . '总览';
|
||||
$lang->block->default['scrum']['project']['4']['block'] = 'sprint';
|
||||
$lang->block->default['scrum']['project']['4']['code'] = 'sprint';
|
||||
$lang->block->default['scrum']['project']['4']['grid'] = 4;
|
||||
|
||||
$lang->block->default['scrum']['project']['5']['title'] = '最新动态';
|
||||
$lang->block->default['scrum']['project']['5']['block'] = 'projectdynamic';
|
||||
$lang->block->default['scrum']['project']['5']['code'] = 'projectdynamic';
|
||||
$lang->block->default['scrum']['project']['5']['grid'] = 4;
|
||||
$lang->block->default['kanban'] = $lang->block->default['scrum'];
|
||||
$lang->block->default['agileplus'] = $lang->block->default['scrum'];
|
||||
|
||||
$lang->block->default['product']['1']['title'] = $lang->productCommon . '统计';
|
||||
$lang->block->default['product']['1']['block'] = 'statistic';
|
||||
$lang->block->default['product']['1']['code'] = 'statistic';
|
||||
$lang->block->default['product']['1']['grid'] = 8;
|
||||
|
||||
$lang->block->default['product']['1']['params']['type'] = 'all';
|
||||
$lang->block->default['product']['1']['params']['count'] = '20';
|
||||
|
||||
$lang->block->default['product']['2']['title'] = $lang->productCommon . '总览';
|
||||
$lang->block->default['product']['2']['block'] = 'overview';
|
||||
$lang->block->default['product']['2']['code'] = 'overview';
|
||||
$lang->block->default['product']['2']['grid'] = 4;
|
||||
|
||||
$lang->block->default['product']['3']['title'] = '未关闭的' . $lang->productCommon;
|
||||
$lang->block->default['product']['3']['block'] = 'list';
|
||||
$lang->block->default['product']['3']['code'] = 'list';
|
||||
$lang->block->default['product']['3']['grid'] = 8;
|
||||
|
||||
$lang->block->default['product']['3']['params']['count'] = 15;
|
||||
$lang->block->default['product']['3']['params']['type'] = 'noclosed';
|
||||
|
||||
$lang->block->default['product']['4']['title'] = "指派给我的{$lang->SRCommon}";
|
||||
$lang->block->default['product']['4']['block'] = 'story';
|
||||
$lang->block->default['product']['4']['code'] = 'story';
|
||||
$lang->block->default['product']['4']['grid'] = 4;
|
||||
|
||||
$lang->block->default['product']['4']['params']['count'] = 15;
|
||||
@@ -202,18 +202,18 @@ $lang->block->default['product']['4']['params']['orderBy'] = 'id_desc';
|
||||
$lang->block->default['product']['4']['params']['type'] = 'assignedTo';
|
||||
|
||||
$lang->block->default['execution']['1']['title'] = '执行统计';
|
||||
$lang->block->default['execution']['1']['block'] = 'statistic';
|
||||
$lang->block->default['execution']['1']['code'] = 'statistic';
|
||||
$lang->block->default['execution']['1']['grid'] = 8;
|
||||
|
||||
$lang->block->default['execution']['1']['params']['type'] = 'all';
|
||||
$lang->block->default['execution']['1']['params']['count'] = '20';
|
||||
|
||||
$lang->block->default['execution']['2']['title'] = '执行总览';
|
||||
$lang->block->default['execution']['2']['block'] = 'overview';
|
||||
$lang->block->default['execution']['2']['code'] = 'overview';
|
||||
$lang->block->default['execution']['2']['grid'] = 4;
|
||||
|
||||
$lang->block->default['execution']['3']['title'] = '未关闭的执行';
|
||||
$lang->block->default['execution']['3']['block'] = 'list';
|
||||
$lang->block->default['execution']['3']['code'] = 'list';
|
||||
$lang->block->default['execution']['3']['grid'] = 8;
|
||||
|
||||
$lang->block->default['execution']['3']['params']['count'] = 15;
|
||||
@@ -221,7 +221,7 @@ $lang->block->default['execution']['3']['params']['orderBy'] = 'id_desc';
|
||||
$lang->block->default['execution']['3']['params']['type'] = 'undone';
|
||||
|
||||
$lang->block->default['execution']['4']['title'] = '指派给我的任务';
|
||||
$lang->block->default['execution']['4']['block'] = 'task';
|
||||
$lang->block->default['execution']['4']['code'] = 'task';
|
||||
$lang->block->default['execution']['4']['grid'] = 4;
|
||||
|
||||
$lang->block->default['execution']['4']['params']['count'] = 15;
|
||||
@@ -229,14 +229,14 @@ $lang->block->default['execution']['4']['params']['orderBy'] = 'id_desc';
|
||||
$lang->block->default['execution']['4']['params']['type'] = 'assignedTo';
|
||||
|
||||
$lang->block->default['execution']['5']['title'] = '版本列表';
|
||||
$lang->block->default['execution']['5']['block'] = 'build';
|
||||
$lang->block->default['execution']['5']['code'] = 'build';
|
||||
$lang->block->default['execution']['5']['grid'] = 8;
|
||||
|
||||
$lang->block->default['execution']['5']['params']['count'] = 15;
|
||||
$lang->block->default['execution']['5']['params']['orderBy'] = 'id_desc';
|
||||
|
||||
$lang->block->default['qa']['1']['title'] = '测试统计';
|
||||
$lang->block->default['qa']['1']['block'] = 'statistic';
|
||||
$lang->block->default['qa']['1']['code'] = 'statistic';
|
||||
$lang->block->default['qa']['1']['grid'] = 8;
|
||||
|
||||
$lang->block->default['qa']['1']['params']['type'] = 'noclosed';
|
||||
@@ -247,7 +247,7 @@ $lang->block->default['qa']['1']['params']['count'] = '20';
|
||||
//$lang->block->default['qa']['2']['grid'] = 4;
|
||||
|
||||
$lang->block->default['qa']['2']['title'] = '指派给我的Bug';
|
||||
$lang->block->default['qa']['2']['block'] = 'bug';
|
||||
$lang->block->default['qa']['2']['code'] = 'bug';
|
||||
$lang->block->default['qa']['2']['grid'] = 4;
|
||||
|
||||
$lang->block->default['qa']['2']['params']['count'] = 15;
|
||||
@@ -255,7 +255,7 @@ $lang->block->default['qa']['2']['params']['orderBy'] = 'id_desc';
|
||||
$lang->block->default['qa']['2']['params']['type'] = 'assignedTo';
|
||||
|
||||
$lang->block->default['qa']['3']['title'] = '指派给我的用例';
|
||||
$lang->block->default['qa']['3']['block'] = 'case';
|
||||
$lang->block->default['qa']['3']['code'] = 'case';
|
||||
$lang->block->default['qa']['3']['grid'] = 4;
|
||||
|
||||
$lang->block->default['qa']['3']['params']['count'] = 15;
|
||||
@@ -263,7 +263,7 @@ $lang->block->default['qa']['3']['params']['orderBy'] = 'id_desc';
|
||||
$lang->block->default['qa']['3']['params']['type'] = 'assigntome';
|
||||
|
||||
$lang->block->default['qa']['4']['title'] = '待测版本列表';
|
||||
$lang->block->default['qa']['4']['block'] = 'testtask';
|
||||
$lang->block->default['qa']['4']['code'] = 'testtask';
|
||||
$lang->block->default['qa']['4']['grid'] = 8;
|
||||
|
||||
$lang->block->default['qa']['4']['params']['count'] = 15;
|
||||
@@ -271,44 +271,44 @@ $lang->block->default['qa']['4']['params']['orderBy'] = 'id_desc';
|
||||
$lang->block->default['qa']['4']['params']['type'] = 'wait';
|
||||
|
||||
$lang->block->default['full']['my']['1']['title'] = '欢迎';
|
||||
$lang->block->default['full']['my']['1']['block'] = 'welcome';
|
||||
$lang->block->default['full']['my']['1']['code'] = 'welcome';
|
||||
$lang->block->default['full']['my']['1']['grid'] = 8;
|
||||
$lang->block->default['full']['my']['1']['source'] = '';
|
||||
|
||||
$lang->block->default['full']['my']['2']['title'] = '最新动态';
|
||||
$lang->block->default['full']['my']['2']['block'] = 'dynamic';
|
||||
$lang->block->default['full']['my']['2']['code'] = 'dynamic';
|
||||
$lang->block->default['full']['my']['2']['grid'] = 4;
|
||||
$lang->block->default['full']['my']['2']['source'] = '';
|
||||
|
||||
$lang->block->default['full']['my']['3']['title'] = '使用帮助';
|
||||
$lang->block->default['full']['my']['3']['block'] = 'guide';
|
||||
$lang->block->default['full']['my']['3']['code'] = 'guide';
|
||||
$lang->block->default['full']['my']['3']['source'] = '';
|
||||
$lang->block->default['full']['my']['3']['grid'] = 8;
|
||||
|
||||
$lang->block->default['full']['my']['4']['title'] = '我的待办';
|
||||
$lang->block->default['full']['my']['4']['block'] = 'list';
|
||||
$lang->block->default['full']['my']['4']['code'] = 'list';
|
||||
$lang->block->default['full']['my']['4']['grid'] = 4;
|
||||
$lang->block->default['full']['my']['4']['source'] = 'todo';
|
||||
$lang->block->default['full']['my']['4']['params']['count'] = '20';
|
||||
|
||||
$lang->block->default['full']['my']['5']['title'] = "{$lang->projectCommon}统计";
|
||||
$lang->block->default['full']['my']['5']['block'] = 'statistic';
|
||||
$lang->block->default['full']['my']['5']['code'] = 'statistic';
|
||||
$lang->block->default['full']['my']['5']['source'] = 'project';
|
||||
$lang->block->default['full']['my']['5']['grid'] = 8;
|
||||
$lang->block->default['full']['my']['5']['params']['count'] = '20';
|
||||
|
||||
$lang->block->default['full']['my']['6']['title'] = '我的贡献';
|
||||
$lang->block->default['full']['my']['6']['block'] = 'contribute';
|
||||
$lang->block->default['full']['my']['6']['code'] = 'contribute';
|
||||
$lang->block->default['full']['my']['6']['source'] = '';
|
||||
$lang->block->default['full']['my']['6']['grid'] = 4;
|
||||
|
||||
$lang->block->default['full']['my']['7']['title'] = "我近期参与的{$lang->projectCommon}";
|
||||
$lang->block->default['full']['my']['7']['block'] = 'recentproject';
|
||||
$lang->block->default['full']['my']['7']['code'] = 'recentproject';
|
||||
$lang->block->default['full']['my']['7']['source'] = 'project';
|
||||
$lang->block->default['full']['my']['7']['grid'] = 8;
|
||||
|
||||
$lang->block->default['full']['my']['8']['title'] = '我的待处理';
|
||||
$lang->block->default['full']['my']['8']['block'] = 'assigntome';
|
||||
$lang->block->default['full']['my']['8']['code'] = 'assigntome';
|
||||
$lang->block->default['full']['my']['8']['source'] = '';
|
||||
$lang->block->default['full']['my']['8']['grid'] = 8;
|
||||
|
||||
@@ -323,12 +323,12 @@ $lang->block->default['full']['my']['8']['params']['meetingCount'] = '20';
|
||||
$lang->block->default['full']['my']['8']['params']['feedbackCount'] = '20';
|
||||
|
||||
$lang->block->default['full']['my']['9']['title'] = "{$lang->projectCommon}人力投入";
|
||||
$lang->block->default['full']['my']['9']['block'] = 'projectteam';
|
||||
$lang->block->default['full']['my']['9']['code'] = 'projectteam';
|
||||
$lang->block->default['full']['my']['9']['source'] = 'project';
|
||||
$lang->block->default['full']['my']['9']['grid'] = 8;
|
||||
|
||||
$lang->block->default['full']['my']['10']['title'] = "{$lang->projectCommon}列表";
|
||||
$lang->block->default['full']['my']['10']['block'] = 'project';
|
||||
$lang->block->default['full']['my']['10']['code'] = 'project';
|
||||
$lang->block->default['full']['my']['10']['source'] = 'project';
|
||||
$lang->block->default['full']['my']['10']['grid'] = 8;
|
||||
|
||||
@@ -337,40 +337,40 @@ $lang->block->default['full']['my']['10']['params']['count'] = '15';
|
||||
|
||||
/* Doc module block. */
|
||||
$lang->block->default['doc']['1']['title'] = '文档统计';
|
||||
$lang->block->default['doc']['1']['block'] = 'docstatistic';
|
||||
$lang->block->default['doc']['1']['code'] = 'docstatistic';
|
||||
$lang->block->default['doc']['1']['grid'] = 8;
|
||||
|
||||
$lang->block->default['doc']['2']['title'] = '文档动态';
|
||||
$lang->block->default['doc']['2']['block'] = 'docdynamic';
|
||||
$lang->block->default['doc']['2']['code'] = 'docdynamic';
|
||||
$lang->block->default['doc']['2']['grid'] = 4;
|
||||
|
||||
$lang->block->default['doc']['3']['title'] = '我收藏的文档';
|
||||
$lang->block->default['doc']['3']['block'] = 'docmycollection';
|
||||
$lang->block->default['doc']['3']['code'] = 'docmycollection';
|
||||
$lang->block->default['doc']['3']['grid'] = 8;
|
||||
|
||||
$lang->block->default['doc']['4']['title'] = '最近更新的文档';
|
||||
$lang->block->default['doc']['4']['block'] = 'docrecentupdate';
|
||||
$lang->block->default['doc']['4']['code'] = 'docrecentupdate';
|
||||
$lang->block->default['doc']['4']['grid'] = 8;
|
||||
|
||||
$lang->block->default['doc']['5']['title'] = '浏览排行榜';
|
||||
$lang->block->default['doc']['5']['block'] = 'docviewlist';
|
||||
$lang->block->default['doc']['5']['code'] = 'docviewlist';
|
||||
$lang->block->default['doc']['5']['grid'] = 4;
|
||||
|
||||
if($config->vision == 'rnd')
|
||||
{
|
||||
$lang->block->default['doc']['6']['title'] = $lang->productCommon . '文档';
|
||||
$lang->block->default['doc']['6']['block'] = 'productdoc';
|
||||
$lang->block->default['doc']['6']['code'] = 'productdoc';
|
||||
$lang->block->default['doc']['6']['grid'] = 8;
|
||||
|
||||
$lang->block->default['doc']['6']['params']['count'] = '20';
|
||||
}
|
||||
|
||||
$lang->block->default['doc']['7']['title'] = '收藏排行榜';
|
||||
$lang->block->default['doc']['7']['block'] = 'doccollectlist';
|
||||
$lang->block->default['doc']['7']['code'] = 'doccollectlist';
|
||||
$lang->block->default['doc']['7']['grid'] = 4;
|
||||
|
||||
$lang->block->default['doc']['8']['title'] = $lang->projectCommon . '文档';
|
||||
$lang->block->default['doc']['8']['block'] = 'projectdoc';
|
||||
$lang->block->default['doc']['8']['code'] = 'projectdoc';
|
||||
$lang->block->default['doc']['8']['grid'] = 8;
|
||||
|
||||
$lang->block->default['doc']['8']['params']['count'] = '20';
|
||||
|
||||
+32
-4
@@ -47,7 +47,7 @@ class blockModel extends model
|
||||
|
||||
$block->params = json_decode($block->params);
|
||||
if(empty($block->params)) $block->params = new stdclass();
|
||||
if($block->block == 'html') $block->params->html = $this->loadModel('file')->setImgSize($block->params->html);
|
||||
if($block->code == 'html') $block->params->html = $this->loadModel('file')->setImgSize($block->params->html);
|
||||
return $block;
|
||||
}
|
||||
|
||||
@@ -187,10 +187,18 @@ class blockModel extends model
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getParams(string $block, string $module): string
|
||||
public function getParams(string $code, string $module): string
|
||||
{
|
||||
$block = $block == 'todo' ? $module : $block;
|
||||
$params = zget($this->config->block->params, $block, '');
|
||||
if($code == 'todo' || $code == 'list')
|
||||
{
|
||||
$code = $module;
|
||||
}
|
||||
elseif($code == 'statistic')
|
||||
{
|
||||
$code = $module . 'Statistic';
|
||||
}
|
||||
|
||||
$params = zget($this->config->block->params, $code, '');
|
||||
return json_encode($params);
|
||||
}
|
||||
|
||||
@@ -470,4 +478,24 @@ class blockModel extends model
|
||||
|
||||
$this->dao->replace(TABLE_BLOCK)->data($data)->exec();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取区块是否已经初始化.
|
||||
* Fetch block is initiated or not.
|
||||
*
|
||||
* @param string $module
|
||||
* @param string $vision
|
||||
* @param string $section
|
||||
* @return string
|
||||
*/
|
||||
public function fetchBlockInitStatus(string $module, string $vision, string $section): string
|
||||
{
|
||||
return $this->dao->select('*')->from(TABLE_CONFIG)
|
||||
->where('module')->eq($module)
|
||||
->andWhere('owner')->eq($this->app->user->account)
|
||||
->andWhere('`section`')->eq($section)->fi()
|
||||
->andWhere('`key`')->eq('blockInited')
|
||||
->andWhere('vision')->eq($vision)
|
||||
->fetch('value');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -788,4 +788,21 @@ class blockTest
|
||||
|
||||
return $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test fetch block is initiated or not.
|
||||
*
|
||||
* @param string $module
|
||||
* @param string $vision
|
||||
* @param string $section
|
||||
* @return string
|
||||
*/
|
||||
public function fetchBlockInitStatusTest(string $module, string $vision, string $section): string
|
||||
{
|
||||
$isInitiated = $this->objectModel->fetchBlockInitStatus($module, $vision, $section);
|
||||
|
||||
if(dao::isError()) return dao::getError();
|
||||
|
||||
return $isInitiated;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ function initData()
|
||||
$block->module->range('test');
|
||||
$block->title->prefix('区块')->range('2');
|
||||
$block->source->range('my');
|
||||
$block->block->range('bug');
|
||||
$block->order->range('5');
|
||||
|
||||
$block->gen(1);
|
||||
@@ -52,7 +51,6 @@ $block->vision = 'rnd';
|
||||
$block->module = 'my';
|
||||
$block->title = '区块123';
|
||||
$block->source = 'my';
|
||||
$block->block = 'bug';
|
||||
$block->order = '5';
|
||||
|
||||
$accoutTooLangBlock = new stdclass();
|
||||
@@ -61,11 +59,10 @@ $accoutTooLangBlock->vision = 'rnd';
|
||||
$accoutTooLangBlock->module = 'my';
|
||||
$accoutTooLangBlock->title = 'long account';
|
||||
$accoutTooLangBlock->source = 'my';
|
||||
$accoutTooLangBlock->block = 'bug';
|
||||
$accoutTooLangBlock->order = '5';
|
||||
|
||||
$blockTest = new blockTest();
|
||||
$newBlockID = $blockTest->createTest($block);
|
||||
|
||||
r($tester->block->getByID($newBlockID)) && p('account,vision,module,title,source,block,order') && e('admin,rnd,my,区块123,my,bug,5'); // 测试获取正常的block的内容
|
||||
r($tester->block->getByID($newBlockID)) && p('account,vision,module,title,source,order') && e('admin,rnd,my,区块123,my,5'); // 测试获取正常的block的内容
|
||||
r($blockTest->createTest($accoutTooLangBlock)) && p('account:0') && e('『所属用户』长度应当不超过『30』,且大于『0』。'); // 测试account 字段字符超出长度
|
||||
|
||||
@@ -12,7 +12,6 @@ function initData()
|
||||
$block->module->range('my,qa,project');
|
||||
$block->title->prefix('区块')->range('2-5');
|
||||
$block->source->range('my,qa,project');
|
||||
$block->block->range('bug,case,story');
|
||||
$block->order->range('5-2');
|
||||
|
||||
$block->gen(4);
|
||||
@@ -44,6 +43,6 @@ $tester->loadModel('block');
|
||||
|
||||
initData();
|
||||
|
||||
r($tester->block->getByID(2)) && p('account,vision,module,title,source,block,order') && e('admin,rnd,my,区块2,my,bug,5'); // 测试获取正常的block的内容
|
||||
r($tester->block->getByID(2)) && p('account,vision,module,title,source,order') && e('admin,rnd,my,区块2,my,5'); // 测试获取正常的block的内容
|
||||
r($tester->block->getByID(4)) && p('order') && e('3'); // 测试获取正常的block的内容
|
||||
r($tester->block->getByID(6)) && p('') && e('0'); // 测试获取不存在的block的内容
|
||||
r($tester->block->getByID(6)) && p('') && e('0'); // 测试获取不存在的block的内容
|
||||
|
||||
@@ -14,7 +14,6 @@ function initData()
|
||||
$block->module->range('test');
|
||||
$block->title->prefix('区块')->range('2');
|
||||
$block->source->range('my');
|
||||
$block->block->range('bug');
|
||||
$block->order->range('5');
|
||||
|
||||
$block->gen(1);
|
||||
@@ -54,7 +53,6 @@ $newBlock->module = 'newmy';
|
||||
$newBlock->title = 'new区块';
|
||||
$newBlock->source = 'newmy';
|
||||
$newBlock->params = '';
|
||||
$newBlock->block = 'newbug';
|
||||
$newBlock->order = '5';
|
||||
|
||||
$accoutTooLangBlock = new stdclass();
|
||||
@@ -64,11 +62,10 @@ $accoutTooLangBlock->vision = 'rnd';
|
||||
$accoutTooLangBlock->module = 'my';
|
||||
$accoutTooLangBlock->title = 'long account';
|
||||
$accoutTooLangBlock->source = 'my';
|
||||
$accoutTooLangBlock->block = 'bug';
|
||||
$accoutTooLangBlock->order = '5';
|
||||
|
||||
$blockTest = new blockTest();
|
||||
$newBlockID = $blockTest->updateTest($newBlock);
|
||||
|
||||
r($tester->block->getByID($newBlockID)) && p('account,vision,module,title,source,block,order') && e("{$newBlock->account},{$newBlock->vision},{$newBlock->module},{$newBlock->title},{$newBlock->source},{$newBlock->block},{$newBlock->order}"); // 测试获取正常的block的内容
|
||||
r($tester->block->getByID($newBlockID)) && p('account,vision,module,title,source,order') && e("newadmin,lite,newmy,new区块,newmy,5"); // 测试获取正常的block的内容
|
||||
r($blockTest->updateTest($accoutTooLangBlock)) && p('account:0') && e('『所属用户』长度应当不超过『30』,且大于『0』。'); // 测试account 字段字符超出长度
|
||||
|
||||
@@ -16,13 +16,14 @@ jsVar('dashboard', $dashboard);
|
||||
|
||||
$paramsRows = array();
|
||||
|
||||
foreach($params as $code => $row)
|
||||
foreach($params as $key => $row)
|
||||
{
|
||||
$paramsRows[] = formGroup
|
||||
(
|
||||
set::label($row['name']),
|
||||
set::name('params'),
|
||||
set::class('form-row'),
|
||||
set::value($block->params->{$key}),
|
||||
set::control(array
|
||||
(
|
||||
'type' => $row['control'],
|
||||
@@ -34,7 +35,7 @@ foreach($params as $code => $row)
|
||||
form
|
||||
(
|
||||
on::change('#module', 'getForm'),
|
||||
on::change('#block', 'getForm'),
|
||||
on::change('#code', 'getForm'),
|
||||
formGroup
|
||||
(
|
||||
set::label($lang->block->lblModule),
|
||||
@@ -47,18 +48,17 @@ form
|
||||
),
|
||||
div
|
||||
(
|
||||
set::id('blockRow'),
|
||||
set::class('form-row'),
|
||||
$blocks
|
||||
set::id('codeRow'),
|
||||
$codes
|
||||
? formGroup
|
||||
(
|
||||
set::label($lang->block->lblBlock),
|
||||
set::name('block'),
|
||||
set::value($block),
|
||||
set::name('code'),
|
||||
set::value($code),
|
||||
set::control(array
|
||||
(
|
||||
'type' => 'select',
|
||||
'items' => array('') + $blocks
|
||||
'items' => array('') + $codes
|
||||
))
|
||||
) : null
|
||||
),
|
||||
@@ -67,15 +67,16 @@ form
|
||||
set::id('paramsRow'),
|
||||
set::class('form-grid'),
|
||||
$paramsRows,
|
||||
(($module and $block) or ($module and !$blocks))
|
||||
(($module and $code) or ($module and !$codes))
|
||||
? formGroup
|
||||
(
|
||||
set::label($lang->block->name),
|
||||
set::name('title'),
|
||||
set::value(zget($modules, $module, '') . zget($codes, $code, '')),
|
||||
set::class('form-row'),
|
||||
set::control('input')
|
||||
) : null,
|
||||
(($module and $block) or ($module and !$blocks))
|
||||
(($module and $code) or ($module and !$codes))
|
||||
? formGroup
|
||||
(
|
||||
set::label($lang->block->grid),
|
||||
|
||||
@@ -7,7 +7,7 @@ foreach($longBlocks as $index => $block)
|
||||
$mainBlocks[] =
|
||||
div
|
||||
(
|
||||
set('class', "panel rounded shadow ring-0 canvas block-item {$block->block}" . (isset($block->params->color) ? 'panel-' . $block->params->color : '')),
|
||||
set('class', "panel rounded shadow ring-0 canvas block-item {$block->code}" . (isset($block->params->color) ? 'panel-' . $block->params->color : '')),
|
||||
set('data-id', $block->id),
|
||||
set('data-name', $block->title),
|
||||
set('data-order', $block->order),
|
||||
@@ -52,7 +52,7 @@ foreach($shortBlocks as $index => $block)
|
||||
div
|
||||
(
|
||||
set('id', 'block' . $block->id),
|
||||
set('class', "panel rounded shadow ring-0 canvas {$block->block}" . (isset($block->params->color) ? 'panel-' . $block->params->color : '')),
|
||||
set('class', "panel rounded shadow ring-0 canvas {$block->code}" . (isset($block->params->color) ? 'panel-' . $block->params->color : '')),
|
||||
set('data-id', $block->id),
|
||||
set('data-name', $block->title),
|
||||
set('data-order', $block->order),
|
||||
|
||||
@@ -12,18 +12,18 @@ declare(strict_types=1);
|
||||
namespace zin;
|
||||
|
||||
set::title($title);
|
||||
jsVar('blockID', $blockData->id);
|
||||
jsVar('blockID', $block->id);
|
||||
|
||||
$paramsRows = array();
|
||||
|
||||
foreach($params as $code => $row)
|
||||
foreach($params as $key => $row)
|
||||
{
|
||||
$paramsRows[] = formGroup
|
||||
(
|
||||
set::label($row['name']),
|
||||
set::name('params'),
|
||||
set::class('form-row'),
|
||||
set::value($blockData->params->{$code}),
|
||||
set::value($block->params->{$key}),
|
||||
set::control(array
|
||||
(
|
||||
'type' => $row['control'],
|
||||
@@ -35,12 +35,12 @@ foreach($params as $code => $row)
|
||||
form
|
||||
(
|
||||
on::change('#module', 'getForm'),
|
||||
on::change('#block', 'getForm'),
|
||||
on::change('#code', 'getForm'),
|
||||
formGroup
|
||||
(
|
||||
set::label($lang->block->lblModule),
|
||||
set::name('module'),
|
||||
set::value($blockData->module),
|
||||
set::value($block->module),
|
||||
set::control(array
|
||||
(
|
||||
'type' => 'select',
|
||||
@@ -49,18 +49,17 @@ form
|
||||
),
|
||||
div
|
||||
(
|
||||
set::id('blockRow'),
|
||||
set::class('form-row'),
|
||||
$blocks
|
||||
set::id('codeRow'),
|
||||
$codes
|
||||
? formGroup
|
||||
(
|
||||
set::label($lang->block->lblBlock),
|
||||
set::name('block'),
|
||||
set::value($block),
|
||||
set::name('code'),
|
||||
set::value($code),
|
||||
set::control(array
|
||||
(
|
||||
'type' => 'select',
|
||||
'items' => array('') + $blocks
|
||||
'items' => array('') + $codes
|
||||
))
|
||||
) : null
|
||||
),
|
||||
@@ -69,22 +68,22 @@ form
|
||||
set::id('paramsRow'),
|
||||
set::class('form-grid'),
|
||||
$paramsRows,
|
||||
(($module and $block) or ($module and !$blocks))
|
||||
(($module and $code) or ($module and !$codes))
|
||||
? formGroup
|
||||
(
|
||||
set::label($lang->block->name),
|
||||
set::name('title'),
|
||||
set::class('form-row'),
|
||||
set::value($blockData->title),
|
||||
set::value($block->title),
|
||||
set::control('input')
|
||||
) : null,
|
||||
(($module and $block) or ($module and !$blocks))
|
||||
(($module and $code) or ($module and !$codes))
|
||||
? formGroup
|
||||
(
|
||||
set::label($lang->block->grid),
|
||||
set::name("grid"),
|
||||
set::class('form-row'),
|
||||
set::value($blockData->grid),
|
||||
set::value($block->grid),
|
||||
set::control(array
|
||||
(
|
||||
'type' => 'select',
|
||||
|
||||
@@ -102,4 +102,120 @@ class blockZen extends block
|
||||
|
||||
return !empty($params) ? $params : array();
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理每个区块以渲染 UI。
|
||||
* Process each block for render UI.
|
||||
*
|
||||
* @param object[] $blocks
|
||||
* @param object|null $project
|
||||
* @return object[]
|
||||
*/
|
||||
protected function processBlockForRender(array $blocks, object $project = null): array
|
||||
{
|
||||
$acls = $this->app->user->rights['acls'];
|
||||
foreach($blocks as $key => $block)
|
||||
{
|
||||
if(in_array($block->code, array('waterfallrisk', 'waterfallissue')))
|
||||
{
|
||||
$model = isset($project->model) ? $project->model : 'waterfall';
|
||||
if($block->code == 'waterfallrisk' and !helper::hasFeature("{$model}_risk")) continue;
|
||||
if($block->code == 'waterfallissue' and !helper::hasFeature("{$model}_issue")) continue;
|
||||
}
|
||||
|
||||
if(in_array($block->code, array('scrumrisk', 'scrumissue')))
|
||||
{
|
||||
$model = isset($project->model) ? $project->model : 'scrum';
|
||||
if($block->code == 'scrumrisk' and !helper::hasFeature("{$model}_risk")) continue;
|
||||
if($block->code == 'scrumissue' and !helper::hasFeature("{$model}_issue")) continue;
|
||||
}
|
||||
|
||||
if(!empty($block->source) and $block->source != 'todo' and !empty($acls['views']) and !isset($acls['views'][$block->source]))
|
||||
{
|
||||
unset($blocks[$key]);
|
||||
continue;
|
||||
}
|
||||
|
||||
$block->params = json_decode($block->params);
|
||||
if(isset($block->params->num) and !isset($block->params->count)) $block->params->count = $block->params->num;
|
||||
|
||||
$this->getBlockMoreLink($block, $project);
|
||||
}
|
||||
|
||||
return $blocks;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取区块的更多链接。
|
||||
* Get the more link of the block.
|
||||
*
|
||||
* @param object $block
|
||||
* @param object $project
|
||||
* @return void
|
||||
*/
|
||||
private function getBlockMoreLink(object $block, object $project): void
|
||||
{
|
||||
$code = $block->code;
|
||||
$source = empty($block->source) ? 'common' : $block->source;
|
||||
$projectID = isset($project->id) ? $project->id : 0;
|
||||
|
||||
$block->blockLink = $this->createLink('block', 'printBlock', "id=$block->id&module=$block->module");
|
||||
$block->moreLink = '';
|
||||
if(isset($this->config->block->modules[$source]->moreLinkList->{$code}))
|
||||
{
|
||||
list($moduleName, $method, $vars) = explode('|', sprintf($this->config->block->modules[$source]->moreLinkList->{$code}, isset($block->params->type) ? $block->params->type : ''));
|
||||
|
||||
/* The list assigned to me jumps to the work page when click more button. */
|
||||
$block->moreLink = $this->createLink($moduleName, $method, $vars);
|
||||
if($moduleName == 'my' and strpos($this->config->block->workMethods, $method) !== false)
|
||||
{
|
||||
$block->moreLink = $this->createLink($moduleName, 'work', 'mode=' . $method . '&' . $vars);
|
||||
}
|
||||
elseif($moduleName == 'project' and $method == 'dynamic')
|
||||
{
|
||||
$block->moreLink = $this->createLink('project', 'dynamic', "projectID=$projectID&type=all");
|
||||
}
|
||||
elseif($moduleName == 'project' and $method == 'execution')
|
||||
{
|
||||
$block->moreLink = $this->createLink('project', 'execution', "status=all&projectID=$projectID");
|
||||
}
|
||||
elseif($moduleName == 'project' and $method == 'testtask')
|
||||
{
|
||||
$block->moreLink = $this->createLink('project', 'testtask', "projectID=$projectID");
|
||||
}
|
||||
elseif($moduleName == 'testtask' and $method == 'browse')
|
||||
{
|
||||
$block->moreLink = $this->createLink('testtask', 'browse', "productID=0&branch=0&type=all,totalStatus");
|
||||
}
|
||||
}
|
||||
elseif($block->code == 'dynamic')
|
||||
{
|
||||
$block->moreLink = $this->createLink('company', 'dynamic');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将区块数组拆分为短区块数组和长区块数组。
|
||||
* Split blocks array into short blocks and long blocks.
|
||||
*
|
||||
* @param array $blocks
|
||||
* @return array[]
|
||||
*/
|
||||
protected function splitBlocksByLen(array $blocks): array
|
||||
{
|
||||
$shortBlocks = $longBlocks = array();
|
||||
foreach($blocks as $key => $block)
|
||||
{
|
||||
if($this->block->isLongBlock($block))
|
||||
{
|
||||
$longBlocks[$key] = $block;
|
||||
}
|
||||
else
|
||||
{
|
||||
$shortBlocks[$key] = $block;
|
||||
}
|
||||
}
|
||||
|
||||
return array($shortBlocks, $longBlocks);
|
||||
}
|
||||
}
|
||||
|
||||
+12
-48
@@ -304,57 +304,26 @@ class bug extends control
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个bug。
|
||||
* Create a bug.
|
||||
*
|
||||
* @param int $productID
|
||||
* @param string $productID
|
||||
* @param string $branch
|
||||
* @param string $extras others params, forexample, executionID=10,moduleID=10
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function create($productID, $branch = '', $extras = '')
|
||||
public function create(string $productID, string $branch = '', string $extras = ''): void
|
||||
{
|
||||
if(empty($this->products)) $this->locate($this->createLink('product', 'create'));
|
||||
$productID = (int)$productID;
|
||||
|
||||
/* Unset discarded types. */
|
||||
foreach($this->config->bug->discardedTypes as $type) unset($this->lang->bug->typeList[$type]);
|
||||
|
||||
/* Whether there is a object to transfer bug, for example feedback. */
|
||||
$extras = str_replace(array(',', ' '), array('&', ''), $extras);
|
||||
parse_str($extras, $output);
|
||||
extract($output);
|
||||
$this->bugZen->setMenu4Create($productID, $branch, $output);
|
||||
|
||||
$from = isset($output['from']) ? $output['from'] : '';
|
||||
|
||||
if($this->app->tab == 'execution')
|
||||
{
|
||||
if(isset($output['executionID'])) $this->loadModel('execution')->setMenu($output['executionID']);
|
||||
$execution = $this->dao->findById($this->session->execution)->from(TABLE_EXECUTION)->fetch();
|
||||
if($execution->type == 'kanban')
|
||||
{
|
||||
$this->loadModel('kanban');
|
||||
$regionPairs = $this->kanban->getRegionPairs($execution->id, 0, 'execution');
|
||||
$regionID = !empty($output['regionID']) ? $output['regionID'] : key($regionPairs);
|
||||
$lanePairs = $this->kanban->getLanePairsByRegion($regionID, 'bug');
|
||||
$laneID = isset($output['laneID']) ? $output['laneID'] : key($lanePairs);
|
||||
|
||||
$this->view->executionType = $execution->type;
|
||||
$this->view->regionID = $regionID;
|
||||
$this->view->laneID = $laneID;
|
||||
$this->view->regionPairs = $regionPairs;
|
||||
$this->view->lanePairs = $lanePairs;
|
||||
}
|
||||
}
|
||||
else if($this->app->tab == 'project')
|
||||
{
|
||||
if(isset($output['projectID'])) $this->loadModel('project')->setMenu($output['projectID']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->qa->setMenu($this->products, $productID, $branch);
|
||||
}
|
||||
|
||||
$this->view->users = $this->user->getPairs('devfirst|noclosed|nodeleted');
|
||||
$this->app->loadLang('release');
|
||||
|
||||
if(!empty($_POST))
|
||||
{
|
||||
$response['result'] = 'success';
|
||||
@@ -364,7 +333,7 @@ class bug extends control
|
||||
$bugResult = $this->bugZen->doCreate($bug);
|
||||
|
||||
/* Set from param if there is a object to transfer bug. */
|
||||
setcookie('lastBugModule', (int)$this->post->module, $this->config->cookieLife, $this->config->webRoot, '', $this->config->cookieSecure, false);
|
||||
setcookie('lastBugModule', (int)$this->formData->data->module, $this->config->cookieLife, $this->config->webRoot, '', $this->config->cookieSecure, false);
|
||||
if(!$bugResult or dao::isError())
|
||||
{
|
||||
$response['result'] = 'fail';
|
||||
@@ -389,6 +358,7 @@ class bug extends control
|
||||
|
||||
$extras = str_replace(array(',', ' '), array('&', ''), $extras);
|
||||
parse_str($extras, $output);
|
||||
extract($output);
|
||||
if(isset($output['todoID']))
|
||||
{
|
||||
$this->dao->update(TABLE_TODO)->set('status')->eq('done')->where('id')->eq($output['todoID'])->exec();
|
||||
@@ -411,7 +381,7 @@ class bug extends control
|
||||
if(isonlybody())
|
||||
{
|
||||
$executionID = isset($output['executionID']) ? $output['executionID'] : $this->session->execution;
|
||||
$executionID = $this->post->execution ? $this->post->execution : $executionID;
|
||||
$executionID = $this->formData->data->execution ? $this->formData->data->execution : $executionID;
|
||||
$execution = $this->loadModel('execution')->getByID($executionID);
|
||||
if($this->app->tab == 'execution')
|
||||
{
|
||||
@@ -452,7 +422,7 @@ class bug extends control
|
||||
}
|
||||
else
|
||||
{
|
||||
$executionID = $this->post->execution ? $this->post->execution : zget($output, 'executionID', $this->session->execution);
|
||||
$executionID = $this->formData->data->execution ? $this->formData->data->execution : zget($output, 'executionID', $this->session->execution);
|
||||
$location = $this->createLink('execution', 'bug', "executionID=$executionID");
|
||||
}
|
||||
|
||||
@@ -464,7 +434,7 @@ class bug extends control
|
||||
else
|
||||
{
|
||||
setcookie('bugModule', 0, 0, $this->config->webRoot, '', $this->config->cookieSecure, false);
|
||||
$location = $this->createLink('bug', 'browse', "productID={$this->post->product}&branch=$branch&browseType=byModule¶m={$this->post->module}&orderBy=id_desc");
|
||||
$location = $this->createLink('bug', 'browse', "productID={$this->formData->data->product}&branch=$branch&browseType=byModule¶m={$this->formData->data->module}&orderBy=id_desc");
|
||||
}
|
||||
if($this->app->getViewType() == 'xhtml') $location = $this->createLink('bug', 'view', "bugID=$bugID", 'html');
|
||||
$response['message'] = $this->lang->saveSuccess;
|
||||
@@ -475,7 +445,6 @@ class bug extends control
|
||||
/* Get product, then set menu. */
|
||||
$productID = $this->product->saveState($productID, $this->products);
|
||||
$currentProduct = $this->product->getById($productID);
|
||||
|
||||
if($branch === '') $branch = (int)$this->cookie->preBranch;
|
||||
|
||||
/* Init vars. */
|
||||
@@ -504,11 +473,6 @@ class bug extends control
|
||||
$feedbackBy = '';
|
||||
$notifyEmail = '';
|
||||
|
||||
/* Parse the extras. extract fix php7.2. */
|
||||
$extras = str_replace(array(',', ' '), array('&', ''), $extras);
|
||||
parse_str($extras, $output);
|
||||
extract($output);
|
||||
|
||||
if($runID and $resultID) extract($this->bug->getBugInfoFromResult($resultID, 0, 0, isset($stepIdList) ? $stepIdList : ''));// If set runID and resultID, get the result info by resultID as template.
|
||||
if(!$runID and $caseID) extract($this->bug->getBugInfoFromResult($resultID, $caseID, $version, isset($stepIdList) ? $stepIdList : ''));// If not set runID but set caseID, get the result info by resultID and case info.
|
||||
|
||||
|
||||
@@ -16,31 +16,30 @@ class bugTest
|
||||
*/
|
||||
public function createObject($param = array())
|
||||
{
|
||||
$createFields['title'] = '测试创建bug';
|
||||
$createFields['type'] = 'codeerror';
|
||||
$createFields['product'] = 1;
|
||||
$createFields['execution'] = 101;
|
||||
$createFields['openedBuild'] = 'trunk';
|
||||
$createFields['pri'] = 3;
|
||||
$createFields['severity'] = 3;
|
||||
$createFields['status'] = 'active';
|
||||
$createFields['deadline'] = '2021-03-19';
|
||||
$createFields['openedBy'] = 'admin';
|
||||
$createFields['openedDate'] = '2021-03-19';
|
||||
$bug = new stdclass();
|
||||
$bug->title = 'add bug';
|
||||
$bug->type = 'codeerror';
|
||||
$bug->product = 1;
|
||||
$bug->execution = 101;
|
||||
$bug->openedBuild = 'trunk';
|
||||
$bug->pri = 3;
|
||||
$bug->severity = 3;
|
||||
$bug->status = 'active';
|
||||
$bug->deadline = '2023-03-20';
|
||||
$bug->openedBy = 'admin';
|
||||
$bug->openedDate = '2023-04-20';
|
||||
$bug->notifyEmail = '';
|
||||
|
||||
foreach($createFields as $field => $defaultValue) $_POST[$field] = $defaultValue;
|
||||
foreach($param as $key => $value) $bug->$key = $value;
|
||||
|
||||
foreach($param as $key => $value) $_POST[$key] = $value;
|
||||
|
||||
$object = $this->objectModel->create();
|
||||
$objectID = $object['id'];
|
||||
unset($_POST);
|
||||
$object = $this->objectModel->create($bug);
|
||||
if(dao::isError())
|
||||
{
|
||||
return dao::getError();
|
||||
}
|
||||
else
|
||||
{
|
||||
$objectID = $object['id'];
|
||||
$object = $this->objectModel->getByID($objectID);
|
||||
return $object;
|
||||
}
|
||||
|
||||
@@ -7,48 +7,55 @@ su('admin');
|
||||
/**
|
||||
|
||||
title=bugModel->create();
|
||||
timeout=0
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
测试正常的创建代码错误bug >> 代码错误bug一
|
||||
测试正常的创建配置相关bug >> 1
|
||||
测试正常的创建安装部署bug >> 101
|
||||
测试正常的创建安全相关bug >> security
|
||||
测试正常的创建性能问题bug >> 3
|
||||
测试正常的创建标准规范bug >> active
|
||||
测试正常的创建测试脚本bug >> admin
|
||||
测试正常的创建设计缺陷bug >> 3
|
||||
测试正常的创建其他bug >> 2021-03-19
|
||||
测试不输入名称创建bug >> 『Bug标题』不能为空。
|
||||
测试不输入影响版本创建bug >> 『影响版本』不能为空。
|
||||
测试指派人bug >> user92
|
||||
- 执行bug模块的createOb方法,参数是$bug_codeerror属性title @bug_codeerror
|
||||
|
||||
- 执行bug模块的createOb方法,参数是$bug_project属性project @1
|
||||
|
||||
- 执行bug模块的createOb方法,参数是$bug_execution属性execution @2
|
||||
|
||||
- 执行bug模块的createOb方法,参数是$bug_priseverity
|
||||
- 属性pri @2
|
||||
- 属性severity @2
|
||||
|
||||
- 执行bug模块的createOb方法,参数是$bug_steps属性steps @i wish
|
||||
|
||||
- 执行bug模块的createOb方法,参数是$bug_deadline属性deadline @2023-04-23
|
||||
|
||||
- 执行bug模块的createOb方法,参数是$bug_assign属性assignedTo @admin
|
||||
|
||||
- 执行bug模块的createOb方法,参数是$bug_notitle第title条的0属性 @『Bug标题』不能为空。
|
||||
|
||||
- 执行bug模块的createOb方法,参数是$bug_nobuild第openedBuild条的0属性 @『影响版本』不能为空。
|
||||
|
||||
- 执行bug模块的createOb方法,参数是$bug_erremail第notifyEmail条的0属性 @『通知邮箱』应当为合法的EMAIL。
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
$b_codeerror = array('title' => '代码错误bug一', 'type' => 'codeerror');
|
||||
$b_config = array('title' => '配置相关bug一', 'type' => 'config');
|
||||
$b_install = array('title' => '安装部署bug一', 'type' => 'install');
|
||||
$b_security = array('title' => '安全相关bug一', 'type' => 'security');
|
||||
$b_performance = array('title' => '性能问题bug一', 'type' => 'performance');
|
||||
$b_standard = array('title' => '标准规范bug一', 'type' => 'standard');
|
||||
$b_automation = array('title' => '测试脚本bug一', 'type' => 'automation');
|
||||
$b_designdefect = array('title' => '设计缺陷bug一', 'type' => 'designdefect');
|
||||
$b_others = array('title' => '其他bug一', 'type' => 'others');
|
||||
$b_notitle = array('title' => '', 'type' => 'codeerror');
|
||||
$b_nobuild = array('title' => '没有影响版本', 'type' => 'codeerror', 'openedBuild' => '');
|
||||
$b_assign = array('title' => '指派人user92', 'type' => 'codeerror', 'assignedTo' => 'user92');
|
||||
$bug_codeerror = array('title' => 'bug_codeerror', 'type' => 'codeerror');
|
||||
$bug_project = array('title' => 'bug_project', 'project' => 1);
|
||||
$bug_execution = array('title' => 'bug_execution', 'execution' => 2);
|
||||
$bug_priseverity = array('title' => 'bug_pri', 'pri' => 2, 'severity' => 2);
|
||||
$bug_steps = array('title' => 'bug_steps', 'steps' => 'i wish');
|
||||
$bug_deadline = array('title' => 'bug_deadline', 'deadline' => '2023-04-23');
|
||||
$bug_assign = array('title' => 'bug_assign', 'assignedTo' => 'admin');
|
||||
$bug_notitle = array('title' => '');
|
||||
$bug_nobuild = array('title' => 'bug_nobuild', 'openedBuild' => '');
|
||||
$bug_erremail = array('title' => 'bug_erremail', 'notifyEmail' => '123456');
|
||||
|
||||
$bug=new bugTest();
|
||||
r($bug->createObject($b_codeerror)) && p('title') && e('代码错误bug一'); // 测试正常的创建代码错误bug
|
||||
r($bug->createObject($b_config)) && p('product') && e('1'); // 测试正常的创建配置相关bug
|
||||
r($bug->createObject($b_install)) && p('execution') && e('101'); // 测试正常的创建安装部署bug
|
||||
r($bug->createObject($b_security)) && p('type') && e('security'); // 测试正常的创建安全相关bug
|
||||
r($bug->createObject($b_performance)) && p('pri') && e('3'); // 测试正常的创建性能问题bug
|
||||
r($bug->createObject($b_standard)) && p('status') && e('active'); // 测试正常的创建标准规范bug
|
||||
r($bug->createObject($b_automation)) && p('openedBy') && e('admin'); // 测试正常的创建测试脚本bug
|
||||
r($bug->createObject($b_designdefect)) && p('severity') && e('3'); // 测试正常的创建设计缺陷bug
|
||||
r($bug->createObject($b_others)) && p('deadline') && e('2021-03-19'); // 测试正常的创建其他bug
|
||||
r($bug->createObject($b_notitle)) && p('title:0') && e('『Bug标题』不能为空。'); // 测试不输入名称创建bug
|
||||
r($bug->createObject($b_nobuild)) && p('openedBuild:0') && e('『影响版本』不能为空。'); // 测试不输入影响版本创建bug
|
||||
r($bug->createObject($b_assign)) && p('assignedTo') && e('user92'); // 测试指派人bug
|
||||
|
||||
$bug = new bugTest();
|
||||
r($bug->createObject($bug_codeerror)) && p('title') && e('bug_codeerror'); // 测试bug的标题
|
||||
r($bug->createObject($bug_project)) && p('project') && e('1'); // 测试bug的项目
|
||||
r($bug->createObject($bug_execution)) && p('execution') && e('2'); // 测试bug的执行
|
||||
r($bug->createObject($bug_priseverity)) && p('pri,severity') && e('2,2'); // 测试bug的优先级和严重程度
|
||||
r($bug->createObject($bug_steps)) && p('steps') && e('i wish'); // 测试bug的步骤
|
||||
r($bug->createObject($bug_deadline)) && p('deadline') && e('2023-04-23'); // 测试bug的截止日期
|
||||
r($bug->createObject($bug_assign)) && p('assignedTo') && e('admin'); // 测试bug的指派人
|
||||
r($bug->createObject($bug_notitle)) && p('title:0') && e('『Bug标题』不能为空。'); // 测试bug标题为空
|
||||
r($bug->createObject($bug_nobuild)) && p('openedBuild:0') && e('『影响版本』不能为空。'); // 测试版本为空
|
||||
r($bug->createObject($bug_erremail)) && p('notifyEmail:0') && e('『通知邮箱』应当为合法的EMAIL。'); // 测试异常的email输入
|
||||
|
||||
+53
-6
@@ -3,7 +3,7 @@ declare(strict_types=1);
|
||||
class bugZen extends bug
|
||||
{
|
||||
/**
|
||||
* 处理请求数据
|
||||
* 处理请求数据。
|
||||
* Processing request data.
|
||||
*
|
||||
* @param object $formData
|
||||
@@ -16,10 +16,10 @@ class bugZen extends bug
|
||||
$bug = $formData->setDefault('openedBy', $this->app->user->account)
|
||||
->setDefault('openedDate', $now)
|
||||
->setIF($this->lang->navGroup->bug != 'qa', 'project', $this->session->project)
|
||||
->setIF($this->post->assignedTo != '', 'assignedDate', $now)
|
||||
->setIF($this->post->story != false, 'storyVersion', $this->loadModel('story')->getVersion($this->post->story))
|
||||
->setIF(strpos($this->config->bug->create->requiredFields, 'deadline') !== false, 'deadline', $this->post->deadline)
|
||||
->setIF(strpos($this->config->bug->create->requiredFields, 'execution') !== false, 'execution', $this->post->execution)
|
||||
->setIF($this->formData->data->assignedTo != '', 'assignedDate', $now)
|
||||
->setIF($this->formData->data->story != false, 'storyVersion', $this->loadModel('story')->getVersion($this->formData->data->story))
|
||||
->setIF(strpos($this->config->bug->create->requiredFields, 'deadline') !== false, 'deadline', $this->formData->data->deadline)
|
||||
->setIF(strpos($this->config->bug->create->requiredFields, 'execution') !== false, 'execution', $this->formData->data->execution)
|
||||
->stripTags($this->config->bug->editor->create['id'], $this->config->allowedTags)
|
||||
->cleanInt('product,execution,module,severity')
|
||||
->remove('files,labels,uid,oldTaskID,contactListMenu,region,lane,ticket,deleteFiles,resultFiles')
|
||||
@@ -48,7 +48,7 @@ class bugZen extends bug
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建bug后数据处理
|
||||
* 创建bug后数据处理。
|
||||
* Do thing after create a bug.
|
||||
*
|
||||
* @param object $bug
|
||||
@@ -102,4 +102,51 @@ class bugZen extends bug
|
||||
if($from && is_callable(array($this, $this->config->bug->fromObjects[$from]['callback']))) call_user_func(array($this, $this->config->bug->fromObjects[$from]['callback']), $bugID);
|
||||
}
|
||||
|
||||
/**
|
||||
* 为创建bug设置导航数据。
|
||||
* Set menu for create bug page.
|
||||
*
|
||||
* @param int $productID
|
||||
* @param string $branch
|
||||
* @param array $output
|
||||
* @return void
|
||||
*/
|
||||
protected function setMenu4Create(int $productID, string $branch, array $output): void
|
||||
{
|
||||
if(empty($this->products)) $this->locate($this->createLink('product', 'create'));
|
||||
|
||||
/* Unset discarded types. */
|
||||
foreach($this->config->bug->discardedTypes as $type) unset($this->lang->bug->typeList[$type]);
|
||||
|
||||
if($this->app->tab == 'execution')
|
||||
{
|
||||
if(isset($output['executionID'])) $this->loadModel('execution')->setMenu($output['executionID']);
|
||||
$execution = $this->dao->findById($this->session->execution)->from(TABLE_EXECUTION)->fetch();
|
||||
if($execution->type == 'kanban')
|
||||
{
|
||||
$this->loadModel('kanban');
|
||||
$regionPairs = $this->kanban->getRegionPairs($execution->id, 0, 'execution');
|
||||
$regionID = !empty($output['regionID']) ? $output['regionID'] : key($regionPairs);
|
||||
$lanePairs = $this->kanban->getLanePairsByRegion($regionID, 'bug');
|
||||
$laneID = isset($output['laneID']) ? $output['laneID'] : key($lanePairs);
|
||||
|
||||
$this->view->executionType = $execution->type;
|
||||
$this->view->regionID = $regionID;
|
||||
$this->view->laneID = $laneID;
|
||||
$this->view->regionPairs = $regionPairs;
|
||||
$this->view->lanePairs = $lanePairs;
|
||||
}
|
||||
}
|
||||
else if($this->app->tab == 'project')
|
||||
{
|
||||
if(isset($output['projectID'])) $this->loadModel('project')->setMenu($output['projectID']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->qa->setMenu($this->products, $productID, $branch);
|
||||
}
|
||||
|
||||
$this->view->users = $this->user->getPairs('devfirst|noclosed|nodeleted');
|
||||
$this->app->loadLang('release');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
if($action->action == 'assigned' or $action->action == 'toaudit') $action->extra = zget($users, $action->extra);
|
||||
if(strpos($action->actor, ':') !== false) $action->actor = substr($action->actor, strpos($action->actor, ':') + 1);
|
||||
?>
|
||||
<?php $this->action->printAction($action);?>
|
||||
<?php $this->loadModel('action')->printAction($action);?>
|
||||
<?php if(!empty($action->history)):?>
|
||||
<button type='button' class='btn btn-mini switch-btn btn-icon btn-expand' title='<?php echo $lang->switchDisplay;?>'><i class='change-show icon icon-plus icon-sm'></i></button>
|
||||
<div class='history-changes' id='changeBox<?php echo $i;?>'>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<?php
|
||||
$config->product = new stdclass();
|
||||
$config->product->orderBy = 'isClosed,program_asc,order_asc';
|
||||
$config->product->showAllProjects = 0;
|
||||
|
||||
$config->product->customBatchEditFields = 'PO,QD,RD,status,type,acl';
|
||||
|
||||
+10
-24
@@ -1,5 +1,4 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* The control file of product module of ZenTaoPMS.
|
||||
*
|
||||
@@ -17,10 +16,12 @@ class product extends control
|
||||
/**
|
||||
* Construct function.
|
||||
*
|
||||
* @param moduleName
|
||||
* @param methodName
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($moduleName = '', $methodName = '')
|
||||
public function __construct(string $moduleName = '', string $methodName = '')
|
||||
{
|
||||
parent::__construct($moduleName, $methodName);
|
||||
|
||||
@@ -394,8 +395,8 @@ class product extends control
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建产品。可以是顶级产品,也可以是项目集下的产品。
|
||||
* Create a product.
|
||||
* 创建产品。可以是顶级产品,也可以是项目集下的产品。
|
||||
*
|
||||
* @param int $programID
|
||||
* @param string $extra
|
||||
@@ -410,26 +411,11 @@ class product extends control
|
||||
{
|
||||
$data = form::data($this->config->product->form->create);
|
||||
$data = $this->productZen->prepareCreateExtras($data);
|
||||
if(!$data) return $this->productZen->errorBeforeEdit();
|
||||
if(!$data) return $this->productZen->sendError4Create();
|
||||
|
||||
$result = $this->product->create($data);
|
||||
if(!$result) return $this->productZen->errorAfterEdit();
|
||||
return $this->productZen->responseAfterEdit($result);
|
||||
$productID = $this->product->create();
|
||||
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
|
||||
$this->loadModel('action')->create('product', $productID, 'opened');
|
||||
|
||||
$message = $this->executeHooks($productID);
|
||||
if($message) $this->lang->saveSuccess = $message;
|
||||
if($this->viewType == 'json') return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'id' => $productID));
|
||||
|
||||
$tab = $this->app->tab;
|
||||
$moduleName = $tab == 'program'? 'program' : $this->moduleName;
|
||||
$methodName = $tab == 'program'? 'product' : 'browse';
|
||||
$param = $tab == 'program' ? "programID=$programID" : "productID=$productID";
|
||||
$locate = isonlybody() ? 'parent' : $this->createLink($moduleName, $methodName, $param);
|
||||
if($tab == 'doc') $locate = $this->createLink('doc', 'productSpace', "objectID=$productID");
|
||||
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $locate));
|
||||
$productID = $this->product->create($data);
|
||||
if(!$productID) return $this->productZen->sendError4Create();
|
||||
return $this->productZen->responseAfterCreate($productID, $data);
|
||||
}
|
||||
|
||||
$this->productZen->setMenu4Create($programID);
|
||||
@@ -1260,8 +1246,8 @@ class product extends control
|
||||
|
||||
/* Generate statistics of products and program. */
|
||||
$this->app->loadClass('pager', true);
|
||||
$pager = new pager($recTotal, $recPerPage, $pageID);
|
||||
$queryID = ($browseType == 'bySearch' or !empty($param)) ? $param : 0;
|
||||
$pager = new pager($recTotal, $recPerPage, $pageID);
|
||||
$queryID = ($browseType == 'bySearch' or !empty($param)) ? $param : 0;
|
||||
if($this->config->systemMode == 'light' and $orderBy == 'program_asc') $orderBy = 'order_asc';
|
||||
|
||||
$productStats = $this->product->getStats($orderBy, $pager, $browseType, 0, 'story', 0, $queryID);
|
||||
|
||||
+89
-152
@@ -319,31 +319,29 @@ class productModel extends model
|
||||
/**
|
||||
* Get product pairs.
|
||||
*
|
||||
* @param string $mode
|
||||
* @param string $programID
|
||||
* @param string $mode all|noclosed
|
||||
* @param int $programID
|
||||
* @param string|array $append
|
||||
* @param string|int $shadow all | 0 | 1
|
||||
* @return array
|
||||
*/
|
||||
public function getPairs($mode = '', $programID = 0, $append = '', $shadow = 0)
|
||||
public function getPairs(string $mode = '', int $programID = 0, string|array $append = '', string|int $shadow = 0): array
|
||||
{
|
||||
if(defined('TUTORIAL')) return $this->loadModel('tutorial')->getProductPairs();
|
||||
|
||||
if(!empty($append) and is_array($append)) $append = implode(',', $append);
|
||||
/* Add other products in has priv product id list. */
|
||||
$append = $this->productTao->formatAppendParam($append);
|
||||
$views = $this->app->user->view->products . (empty($append) ? '' : ",{$append}");
|
||||
|
||||
$views = empty($append) ? $this->app->user->view->products : $this->app->user->view->products . ",$append";
|
||||
$orderBy = !empty($this->config->product->orderBy) ? $this->config->product->orderBy : 'isClosed';
|
||||
/* Order by program. */
|
||||
return $this->dao->select("t1.*, IF(INSTR(' closed', t1.status) < 2, 0, 1) AS isClosed")->from(TABLE_PRODUCT)->alias('t1')
|
||||
->leftJoin(TABLE_PROGRAM)->alias('t2')->on('t1.program = t2.id')
|
||||
->where('1 = 1')
|
||||
->where('t1.vision')->eq($this->config->vision)
|
||||
->beginIF(strpos($mode, 'all') === false)->andWhere('t1.deleted')->eq(0)->fi()
|
||||
->beginIF($programID)->andWhere('t1.program')->eq($programID)->fi()
|
||||
->beginIF(strpos($mode, 'noclosed') !== false)->andWhere('t1.status')->ne('closed')->fi()
|
||||
->beginIF(!$this->app->user->admin and $this->config->vision == 'rnd')->andWhere('t1.id')->in($views)->fi()
|
||||
->beginIF($shadow !== 'all')->andWhere('t1.shadow')->eq((int)$shadow)->fi()
|
||||
->andWhere('t1.vision')->eq($this->config->vision)
|
||||
->orderBy("$orderBy, t2.order_asc, t1.line_desc, t1.order_asc")
|
||||
->orderBy("isClosed,t1.program_asc,t2.order_asc,t1.line_desc,t1.order_asc")
|
||||
->fetchPairs('id', 'name');
|
||||
}
|
||||
|
||||
@@ -678,103 +676,22 @@ class productModel extends model
|
||||
|
||||
/**
|
||||
* Create a product.
|
||||
* 直接用对象数据创建产品
|
||||
*
|
||||
* @param object $product
|
||||
* @access public
|
||||
* @return int
|
||||
* @return int|false
|
||||
*/
|
||||
public function create()
|
||||
public function create(object $product): int|false
|
||||
{
|
||||
$product = fixer::input('post')
|
||||
->callFunc('name', 'trim')
|
||||
->setDefault('status', 'normal')
|
||||
->setDefault('line', 0)
|
||||
->setDefault('createdBy', $this->app->user->account)
|
||||
->setDefault('createdDate', helper::now())
|
||||
->setDefault('createdVersion', $this->config->version)
|
||||
->setIF($this->post->acl == 'open', 'whitelist', '')
|
||||
->setIF(!isset($_POST['whitelist']), 'whitelist', '')
|
||||
->stripTags($this->config->product->editor->create['id'], $this->config->allowedTags)
|
||||
->join('whitelist', ',')
|
||||
->join('reviewer', ',')
|
||||
->remove('uid,newLine,lineName,contactListMenu')
|
||||
->get();
|
||||
|
||||
$this->lang->error->unique = $this->lang->error->repeat;
|
||||
$product = $this->loadModel('file')->processImgURL($product, $this->config->product->editor->create['id'], $this->post->uid);
|
||||
|
||||
/* Lean mode relation defaultProgram. */
|
||||
$programID = isset($product->program) ? $product->program : 0;
|
||||
if($this->config->systemMode == 'light')
|
||||
{
|
||||
$programID = $this->config->global->defaultProgram;
|
||||
$product->program = $this->config->global->defaultProgram;
|
||||
}
|
||||
|
||||
$this->dao->insert(TABLE_PRODUCT)->data($product)->autoCheck()
|
||||
->batchCheck($this->config->product->create->requiredFields, 'notempty')
|
||||
->checkIF(!empty($product->name), 'name', 'unique', "`program` = $programID and `deleted` = '0'")
|
||||
->checkIF(!empty($product->name), 'name', 'unique', "`program` = {$product->program} and `deleted` = '0'")
|
||||
->checkIF(!empty($product->code), 'code', 'unique', "`deleted` = '0'")
|
||||
->checkFlow()
|
||||
->exec();
|
||||
|
||||
if(!dao::isError())
|
||||
{
|
||||
$productID = $this->dao->lastInsertID();
|
||||
|
||||
if(!empty($_POST['lineName']))
|
||||
{
|
||||
/* Create product line. */
|
||||
$maxOrder = $this->dao->select("max(`order`) as maxOrder")->from(TABLE_MODULE)->where('type')->eq('line')->fetch('maxOrder');
|
||||
$maxOrder = $maxOrder ? $maxOrder + 10 : 0;
|
||||
|
||||
$line = new stdClass();
|
||||
$line->type = 'line';
|
||||
$line->parent = 0;
|
||||
$line->grade = 1;
|
||||
$line->name = $this->post->lineName;
|
||||
$line->root = $this->config->systemMode == 'ALM' ? $product->program : 0;
|
||||
$line->order = $maxOrder;
|
||||
|
||||
$lines = $this->dao->select('name')->from(TABLE_MODULE)->where('type')->eq('line')->andWhere('root')->eq($line->root)->andWhere('name')->eq($line->name)->fetch();
|
||||
if(!empty($lines))
|
||||
{
|
||||
dao::$errors['lineName'] = sprintf($this->lang->product->nameIsDuplicated, $line->name);
|
||||
return false;
|
||||
}
|
||||
$this->dao->insert(TABLE_MODULE)->data($line)->exec();
|
||||
|
||||
if(!dao::isError())
|
||||
{
|
||||
$lineID = $this->dao->lastInsertID();
|
||||
$path = ",$lineID,";
|
||||
|
||||
$this->dao->update(TABLE_MODULE)->set('path')->eq($path)->where('id')->eq($lineID)->exec();
|
||||
|
||||
$this->dao->update(TABLE_PRODUCT)->set('line')->eq($lineID)->where('id')->eq($productID)->exec();
|
||||
}
|
||||
}
|
||||
|
||||
$this->file->updateObjectID($this->post->uid, $productID, 'product');
|
||||
$this->dao->update(TABLE_PRODUCT)->set('`order`')->eq($productID * 5)->where('id')->eq($productID)->exec();
|
||||
|
||||
$whitelist = explode(',', $product->whitelist);
|
||||
$this->loadModel('personnel')->updateWhitelist($whitelist, 'product', $productID);
|
||||
if($product->acl != 'open') $this->loadModel('user')->updateUserView($productID, 'product');
|
||||
|
||||
/* Create doc lib. */
|
||||
$this->app->loadLang('doc');
|
||||
$lib = new stdclass();
|
||||
$lib->product = $productID;
|
||||
$lib->name = $this->lang->doclib->main['product'];
|
||||
$lib->type = 'product';
|
||||
$lib->main = '1';
|
||||
$lib->acl = 'default';
|
||||
$lib->addedBy = $this->app->user->account;
|
||||
$lib->addedDate = helper::now();
|
||||
$this->dao->insert(TABLE_DOCLIB)->data($lib)->exec();
|
||||
|
||||
return $productID;
|
||||
}
|
||||
if(dao::isError()) return false;
|
||||
return $this->dao->lastInsertID();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1025,6 +942,72 @@ class productModel extends model
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create product line.
|
||||
* 创建产品线。
|
||||
*
|
||||
* @param int programID
|
||||
* @access public
|
||||
* @return int|false
|
||||
*/
|
||||
public function createLine(int $programID): int|false
|
||||
{
|
||||
if($programID <= 0) return false;
|
||||
if(empty($_POST['lineName'])) return false;
|
||||
|
||||
$line = new stdClass();
|
||||
$line->type = 'line';
|
||||
$line->parent = 0;
|
||||
$line->grade = 1;
|
||||
$line->name = htmlSpecialString($this->post->lineName);
|
||||
$line->root = $programID;
|
||||
|
||||
$existedLineID = $this->dao->select('id')->from(TABLE_MODULE)->where('type')->eq('line')->andWhere('root')->eq($line->root)->andWhere('name')->eq($line->name)->fetch('id');
|
||||
if($existedLineID) return $existedLineID;
|
||||
|
||||
$this->dao->insert(TABLE_MODULE)->data($line)->exec();
|
||||
if(dao::isError()) return false;
|
||||
|
||||
$lineID = $this->dao->lastInsertID();
|
||||
$path = ",$lineID,";
|
||||
$this->dao->update(TABLE_MODULE)->set('path')->eq($path)->set('`order`')->eq($lineID)->where('id')->eq($lineID)->exec();
|
||||
|
||||
return $lineID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create main lib for product
|
||||
* 关联创建产品主库
|
||||
*
|
||||
* @param int productID
|
||||
* @access public
|
||||
* @return int|false
|
||||
*/
|
||||
public function createMainLib(int $productID): int|false
|
||||
{
|
||||
if($productID <= 0) return false;
|
||||
|
||||
$existedLibID = $this->dao->select('id')->from(TABLE_DOCLIB)->where('product')->eq($productID)
|
||||
->andWhere('type')->eq('product')
|
||||
->andWhere('main')->eq('1')
|
||||
->fetch('id');
|
||||
if($existedLibID) return $existedLibID;
|
||||
|
||||
$this->app->loadLang('doc');
|
||||
$lib = new stdclass();
|
||||
$lib->product = $productID;
|
||||
$lib->name = $this->lang->doclib->main['product'];
|
||||
$lib->type = 'product';
|
||||
$lib->main = '1';
|
||||
$lib->acl = 'default';
|
||||
$lib->addedBy = $this->app->user->account;
|
||||
$lib->addedDate = helper::now();
|
||||
$this->dao->insert(TABLE_DOCLIB)->data($lib)->exec();
|
||||
|
||||
if(dao::isError())return false;
|
||||
return $this->dao->lastInsertID();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get stories.
|
||||
*
|
||||
@@ -1788,13 +1771,8 @@ class productModel extends model
|
||||
$products = strtolower($status) == static::ST_BYSEARCH ? $this->getListBySearch($param) : $this->productTao->getList($programID, $status, 0, $line);
|
||||
if(empty($products)) return array();
|
||||
|
||||
$productKeys = array_keys($products);
|
||||
if($orderBy == static::OB_PROGRAM) $products = $this->productTao->getPagerProductsWithProgramIn($productKeys, $pager);
|
||||
else $products = $this->productTao->getPagerProductsIn($productKeys, $pager, $orderBy);
|
||||
|
||||
$linePairs = $this->getLinePairs();
|
||||
foreach($products as $product) $product->lineName = zget($linePairs, $product->line, '');
|
||||
|
||||
$productKeys = array_keys($products);
|
||||
$products = $this->productTao->getStatsProducts($productKeys,$programID, $orderBy, $pager);
|
||||
$stories = $this->productTao->getStoriesTODO($productKeys);
|
||||
$requirements = $this->productTao->getRequirementsTODO($productKeys);
|
||||
|
||||
@@ -1809,18 +1787,12 @@ class productModel extends model
|
||||
/* Padding the stories to sure all status have records. */
|
||||
foreach($stories as $key => $story)
|
||||
{
|
||||
foreach(array_keys($this->lang->story->statusList) as $status)
|
||||
{
|
||||
$story[$status] = isset($story[$status]) ? $story[$status]->count : 0;
|
||||
}
|
||||
foreach(array_keys($this->lang->story->statusList) as $status) $story[$status] = isset($story[$status]) ? $story[$status]->count : 0;
|
||||
$stories[$key] = $story;
|
||||
}
|
||||
foreach($requirements as $key => $requirement)
|
||||
{
|
||||
foreach(array_keys($this->lang->story->statusList) as $status)
|
||||
{
|
||||
$requirement[$status] = isset($requirement[$status]) ? $requirement[$status]->count : 0;
|
||||
}
|
||||
foreach(array_keys($this->lang->story->statusList) as $status) $requirement[$status] = isset($requirement[$status]) ? $requirement[$status]->count : 0;
|
||||
$requirements[$key] = $requirement;
|
||||
}
|
||||
|
||||
@@ -1834,45 +1806,11 @@ class productModel extends model
|
||||
$unResolved = $this->productTao->getUnResolvedTODO($productKeys);
|
||||
$fixedBugs = $this->productTao->getFixedBugsTODO($productKeys);
|
||||
$closedBugs = $this->productTao->getClosedBugsTODO($productKeys);
|
||||
|
||||
$this->loadModel('report');
|
||||
$this->loadModel('story');
|
||||
$this->loadModel('bug');
|
||||
$thisWeekBugs = $this->productTao->getThisWeekBugsTODO($productKeys);
|
||||
$assignToNull = $this->productTao->getAssignToNullTODO($productKeys);
|
||||
|
||||
|
||||
$this->app->loadClass('date', true);
|
||||
$weekDate = date::getThisWeek();
|
||||
$thisWeekBugs = $this->dao->select('product,count(*) AS count')
|
||||
->from(TABLE_BUG)
|
||||
->where('openedDate')->between($weekDate['begin'], $weekDate['end'])
|
||||
->andWhere('product')->in($productKeys)
|
||||
->andWhere('deleted')->eq(0)
|
||||
->groupBy('product')
|
||||
->fetchPairs();
|
||||
|
||||
$assignToNull = $this->dao->select('product,count(*) AS count')
|
||||
->from(TABLE_BUG)
|
||||
->where('assignedTo')->eq('')
|
||||
->andWhere('product')->in($productKeys)
|
||||
->andWhere('deleted')->eq(0)
|
||||
->groupBy('product')
|
||||
->fetchPairs();
|
||||
|
||||
if(empty($programID))
|
||||
{
|
||||
$programKeys = array(0 => 0);
|
||||
foreach($products as $product) $programKeys[] = $product->program;
|
||||
$programs = $this->dao->select('id,name,PM')->from(TABLE_PROGRAM)
|
||||
->where('id')->in(array_unique($programKeys))
|
||||
->fetchAll('id');
|
||||
|
||||
foreach($products as $product)
|
||||
{
|
||||
$product->programName = isset($programs[$product->program]) ? $programs[$product->program]->name : '';
|
||||
$product->programPM = isset($programs[$product->program]) ? $programs[$product->program]->PM : '';
|
||||
}
|
||||
}
|
||||
|
||||
/* Generate statistic array. */
|
||||
$stats = array();
|
||||
foreach($products as $key => $product)
|
||||
{
|
||||
@@ -2004,10 +1942,9 @@ class productModel extends model
|
||||
*/
|
||||
public function getLinePairs(int $programID = 0): array
|
||||
{
|
||||
if($programID <= 0) return array();
|
||||
return $this->dao->select('id,name')->from(TABLE_MODULE)
|
||||
->where('type')->eq('line')
|
||||
->andWhere('root')->eq($programID)
|
||||
->beginIF($programID)->andWhere('root')->eq($programID)->fi()
|
||||
->andWhere('deleted')->eq(0)
|
||||
->fetchPairs('id', 'name');
|
||||
}
|
||||
|
||||
+105
-8
@@ -13,6 +13,7 @@ declare(strict_types=1);
|
||||
class productTao extends productModel
|
||||
{
|
||||
/**
|
||||
* 获取产品ID数组中带有项目集信息的产品分页列表。
|
||||
* Get products with program data that in the ID list.
|
||||
*
|
||||
* @param array $productIDs
|
||||
@@ -33,6 +34,7 @@ class productTao extends productModel
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取产品ID数组中的产品排序分页列表。
|
||||
* Get products in the ID list.
|
||||
*
|
||||
* @param array $productIDs
|
||||
@@ -54,6 +56,7 @@ class productTao extends productModel
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取产品列表。
|
||||
* Get products list.
|
||||
*
|
||||
* @param int $programID
|
||||
@@ -98,7 +101,7 @@ class productTao extends productModel
|
||||
}
|
||||
|
||||
/* TODO move to story module. */
|
||||
protected function getStoriesTODO( array $productIDs): array
|
||||
protected function getStoriesTODO(array $productIDs): array
|
||||
{
|
||||
$stories = $this->dao->select('product, status, count(status) AS count')
|
||||
->from(TABLE_STORY)
|
||||
@@ -112,7 +115,7 @@ class productTao extends productModel
|
||||
}
|
||||
|
||||
/* TODO move to story module. */
|
||||
protected function getRequirementsTODO( array $productIDs): array
|
||||
protected function getRequirementsTODO(array $productIDs): array
|
||||
{
|
||||
$requirements = $this->dao->select('product, status, count(status) AS count')
|
||||
->from(TABLE_STORY)
|
||||
@@ -153,7 +156,7 @@ class productTao extends productModel
|
||||
}
|
||||
|
||||
/* TODO move to productplan module. */
|
||||
protected function getPlansTODO( array $productIDs): array
|
||||
protected function getPlansTODO(array $productIDs): array
|
||||
{
|
||||
$plans = $this->dao->select('product, count(*) AS count')
|
||||
->from(TABLE_PRODUCTPLAN)
|
||||
@@ -167,7 +170,7 @@ class productTao extends productModel
|
||||
}
|
||||
|
||||
/* TODO move to release module. */
|
||||
protected function getReleasesTODO( array $productIDs): array
|
||||
protected function getReleasesTODO(array $productIDs): array
|
||||
{
|
||||
$releases = $this->dao->select('product, count(*) AS count')
|
||||
->from(TABLE_RELEASE)
|
||||
@@ -180,7 +183,7 @@ class productTao extends productModel
|
||||
}
|
||||
|
||||
/* TODO move to bug module. */
|
||||
protected function getBugsTODO( array $productIDs): array
|
||||
protected function getBugsTODO(array $productIDs): array
|
||||
{
|
||||
$bugs = $this->dao->select('product,count(*) AS conut')
|
||||
->from(TABLE_BUG)
|
||||
@@ -193,7 +196,7 @@ class productTao extends productModel
|
||||
}
|
||||
|
||||
/* TODO move to bug module. */
|
||||
protected function getUnResolvedTODO( array $productIDs): array
|
||||
protected function getUnResolvedTODO(array $productIDs): array
|
||||
{
|
||||
$unResolved = $this->dao->select('product,count(*) AS count')
|
||||
->from(TABLE_BUG)
|
||||
@@ -208,7 +211,7 @@ class productTao extends productModel
|
||||
}
|
||||
|
||||
/* TODO move to bug module. */
|
||||
protected function getFixedBugsTODO( array $productIDs): array
|
||||
protected function getFixedBugsTODO(array $productIDs): array
|
||||
{
|
||||
$fixedBugs = $this->dao->select('product,count(*) AS count')
|
||||
->from(TABLE_BUG)
|
||||
@@ -223,7 +226,7 @@ class productTao extends productModel
|
||||
}
|
||||
|
||||
/* TODO move to bug module. */
|
||||
protected function getClosedBugsTODO( array $productIDs): array
|
||||
protected function getClosedBugsTODO(array $productIDs): array
|
||||
{
|
||||
$closedBugs = $this->dao->select('product,count(*) AS count')
|
||||
->from(TABLE_BUG)
|
||||
@@ -235,5 +238,99 @@ class productTao extends productModel
|
||||
|
||||
return $closedBugs;
|
||||
}
|
||||
/* TODO move to bug module. */
|
||||
protected function getThisWeekBugsTODO(array $productIDs): array
|
||||
{
|
||||
$this->app->loadClass('date', true);
|
||||
$weekDate = date::getThisWeek();
|
||||
$thisWeekBugs = $this->dao->select('product,count(*) AS count')
|
||||
->from(TABLE_BUG)
|
||||
->where('openedDate')->between($weekDate['begin'], $weekDate['end'])
|
||||
->andWhere('product')->in($productIDs)
|
||||
->andWhere('deleted')->eq(0)
|
||||
->groupBy('product')
|
||||
->fetchPairs();
|
||||
|
||||
return $thisWeekBugs;
|
||||
}
|
||||
|
||||
/* TODO move to bug module. */
|
||||
protected function getAssignToNullTODO(array $productIDs): array
|
||||
{
|
||||
$assignToNull = $this->dao->select('product,count(*) AS count')
|
||||
->from(TABLE_BUG)
|
||||
->where('assignedTo')->eq('')
|
||||
->andWhere('product')->in($productIDs)
|
||||
->andWhere('deleted')->eq(0)
|
||||
->groupBy('product')
|
||||
->fetchPairs();
|
||||
|
||||
return $assignToNull;
|
||||
}
|
||||
|
||||
/* TODO move to program module. */
|
||||
protected function getProgramsInTODO(array $programIDs): array
|
||||
{
|
||||
$programs = $this->dao->select('id,name,PM')->from(TABLE_PROGRAM)
|
||||
->where('id')->in($programIDs)
|
||||
->fetchAll('id');
|
||||
|
||||
return $programs;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用于统计的产品列表。
|
||||
* Get products list for statistic.
|
||||
*
|
||||
* @param int[] $roductIDs
|
||||
* @param int $programID
|
||||
* @param string $orderBy
|
||||
* @param object $pager
|
||||
* @access protected
|
||||
* @return array
|
||||
*/
|
||||
protected function getStatsProducts(array $productIDs, int $programID, string $orderBy, object $pager): array
|
||||
{
|
||||
if($orderBy == static::OB_PROGRAM) $products = $this->getPagerProductsWithProgramIn($productIDs, $pager);
|
||||
else $products = $this->getPagerProductsIn($productIDs, $pager, $orderBy);
|
||||
|
||||
/* Fetch product lines. */
|
||||
$linePairs = $this->getLinePairs();
|
||||
foreach($products as $product) $product->lineName = zget($linePairs, $product->line, '');
|
||||
|
||||
if(!empty($programID)) return $products;
|
||||
|
||||
$programKeys = array(0 => 0);
|
||||
foreach($products as $product) $programKeys[] = $product->program;
|
||||
$programs = $this->getProgramsInTODO(array_unique($programKeys));
|
||||
|
||||
foreach($products as $product)
|
||||
{
|
||||
$product->programName = isset($programs[$product->program]) ? $programs[$product->program]->name : '';
|
||||
$product->programPM = isset($programs[$product->program]) ? $programs[$product->program]->PM : '';
|
||||
}
|
||||
|
||||
return $products;
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化append参数,保证输出用逗号间隔的id列表。
|
||||
* Format append param.
|
||||
*
|
||||
* @param string|array append
|
||||
* @access protected
|
||||
* @return string
|
||||
*/
|
||||
protected function formatAppendParam(string|array $append = ''): string
|
||||
{
|
||||
if(empty($append)) return '';
|
||||
|
||||
if(is_string($append)) $append = explode(',', $append);
|
||||
|
||||
$append = array_map(function($item){return (int)$item;}, $append);
|
||||
$append = array_unique(array_filter($append));
|
||||
sort($append);
|
||||
|
||||
return implode(',', $append);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,3 @@ $stories2 = array($story4, $story5, $story6);
|
||||
$stories3 = array($story7, $story8, $story9);
|
||||
|
||||
$product = new productTest('admin');
|
||||
|
||||
r($product->batchGetStoryStageTest($stories1)) && p('1;2;3') && e('wait;planned;projected'); // 测试获取需求1 2 3的阶段
|
||||
r($product->batchGetStoryStageTest($stories2)) && p('4;5;6') && e('developing;developed;testing'); // 测试获取需求4 5 6的阶段
|
||||
r($product->batchGetStoryStageTest($stories3)) && p('7;8;9') && e('tested;verified;released'); // 测试获取需求7 8 9的阶段
|
||||
@@ -4,6 +4,7 @@ include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/product.class.php';
|
||||
|
||||
#su('admin');
|
||||
zdTable('product')->gen(0);
|
||||
|
||||
/**
|
||||
|
||||
@@ -24,20 +25,14 @@ pid=1
|
||||
|
||||
$product = new productTest('admin');
|
||||
|
||||
$t_create = array('name' => 'case1', 'code' => 'testcase1');
|
||||
$t_noid = array('name' => 'case2');
|
||||
$t_repeat = array('name' => 'case1', 'code' => 'testcase1');
|
||||
$t_noname = array('code' => 'testcase1');
|
||||
$t_namecode = array('name' => 'case3', 'code' => 'testcase3');
|
||||
$t_pronamecode = array('program' => '3', 'name' => 'case4', 'code' => 'testcase4');
|
||||
$t_intypestatus = array('program' => '4', 'name' => 'case5', 'code' => 'testcase5', 'type' => 'branch', 'status' => 'closed');
|
||||
$t_noacl = array('name' => 'case12', 'code' => 'testcase1', 'acl' => '');
|
||||
$create = array('name' => 'case1', 'code' => 'testcase1');
|
||||
$repeat = array('name' => 'case1', 'code' => 'testcase1');
|
||||
$namecode = array('name' => 'case3', 'code' => 'testcase3');
|
||||
$pronamecode = array('program' => '3', 'name' => 'case4', 'code' => 'testcase4');
|
||||
$intypestatus = array('program' => '4', 'name' => 'case5', 'code' => 'testcase5', 'type' => 'branch', 'status' => 'closed');
|
||||
|
||||
r($product->createObject($t_create)) && p('name') && e('case1'); // 测试正常的创建
|
||||
r($product->createObject($t_noid)) && p('code:0') && e('『产品代号』不能为空。'); // 测试不填产品代号的情况
|
||||
r($product->createObject($t_repeat)) && p('code:0') && e('『产品代号』已经有『testcase1』这条记录了。'); // 测试创建重复的产品
|
||||
r($product->createObject($t_noname)) && p('name:0') && e('『产品名称』不能为空。'); // 测试不填产品名称的情况
|
||||
r($product->createObject($t_namecode)) && p('name,code') && e('case3,testcase3'); // 测试传入name和code
|
||||
r($product->createObject($t_pronamecode)) && p('program,name,code') && e('3,case4,testcase4'); // 测试传入program、name、code
|
||||
r($product->createObject($t_intypestatus)) && p('program,type,status') && e('4,branch,closed'); // 测试传入program、name、code、type、status
|
||||
r($product->createObject($t_noacl)) && p('acl:0') && e('『访问控制』不符合格式,应当为:『/open|private|custom/』。'); // 测试不填权限控制的情况
|
||||
r($product->createObject($create)) && p('name') && e('case1'); // 测试正常的创建
|
||||
r($product->createObject($repeat)) && p('code:0') && e('『产品代号』已经有『testcase1』这条记录了。'); // 测试创建重复的产品
|
||||
r($product->createObject($namecode)) && p('name,code') && e('case3,testcase3'); // 测试传入name和code
|
||||
r($product->createObject($pronamecode)) && p('program,name,code') && e('3,case4,testcase4'); // 测试传入program、name、code
|
||||
r($product->createObject($intypestatus)) && p('program,type,status') && e('4,branch,closed'); // 测试传入program、name、code、type、status
|
||||
|
||||
Executable
+21
@@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/product.class.php';
|
||||
|
||||
zdTable('module')->gen(0);
|
||||
|
||||
/**
|
||||
|
||||
title=productModel->createLine();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
*/
|
||||
|
||||
$product = new productTest('admin');
|
||||
|
||||
r($product->createLineTest('1', 'test line1')) && p('root,name') && e('1,test line1');
|
||||
r($product->createLineTest('0', 'test line1')) && p() && e('0');
|
||||
r($product->createLineTest('1', '')) && p() && e('0');
|
||||
r($product->createLineTest('1', "<script>alert('test')</script>")) && p('root,name') && e('1,<script>alert('test')</script>');
|
||||
Executable
+20
@@ -0,0 +1,20 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/product.class.php';
|
||||
|
||||
zdTable('doclib')->gen(0);
|
||||
|
||||
/**
|
||||
|
||||
title=productModel->createmainlib();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
*/
|
||||
|
||||
$product = new productTest('admin');
|
||||
|
||||
r($product->createMainLibTest('-1')) && p() && e('0');
|
||||
r($product->createMainLibTest('0')) && p() && e('0');
|
||||
r($product->createMainLibTest('1')) && p('product,name,type,main') && e('1,产品主库,product,1');
|
||||
@@ -10,7 +10,7 @@ function initData()
|
||||
$module->root->range('1-5'); //产品线所属项目集
|
||||
$module->name->prefix("产品线")->range('1-1000');
|
||||
$module->type->range("line");
|
||||
$module->parent->range("0");
|
||||
$module->parent->range('`0`');
|
||||
|
||||
$module->gen(10);
|
||||
}
|
||||
|
||||
@@ -3,30 +3,18 @@
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/product.class.php';
|
||||
|
||||
zdTable('product')->gen(50);
|
||||
|
||||
/**
|
||||
|
||||
title=测试productModel->getPairs();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
测试项目集10下的11号产品 >> 正常产品11
|
||||
测试项目集10下的55号产品 >> 多分支产品55
|
||||
测试项目集10下的99号产品 >> 多平台产品99
|
||||
测试不存在的项目集 >> 没有数据
|
||||
返回所有产品的数量 >> 120
|
||||
返回项目集10下的所有产品 >> 10
|
||||
测试项目集10下的未关闭产品5 >> 正常产品6
|
||||
返回项目集10下的未关闭产品的数量 >> 6
|
||||
|
||||
*/
|
||||
|
||||
$product = new productTest('admin');
|
||||
|
||||
$t_peoduct10 = array('programID'=>'10');
|
||||
$t_noproduct = array('programID'=>'11');
|
||||
$t_alproduct = array('programID'=>'0');
|
||||
$t_notclose5 = array('programID'=>'5');
|
||||
|
||||
r($product->getProductPairs($t_peoduct10['programID'])) && p('11') && e('正常产品11'); // 测试项目集10下的11号产品
|
||||
r($product->getProductPairs($t_peoduct10['programID'])) && p('55') && e('多分支产品55'); // 测试项目集10下的55号产品
|
||||
r($product->getProductPairs($t_peoduct10['programID'])) && p('99') && e('多平台产品99'); // 测试项目集10下的99号产品
|
||||
@@ -34,4 +22,4 @@ r($product->getProductPairs($t_noproduct['programID'])) && p() && e('
|
||||
r($product->getProductPairsCount($t_alproduct['programID'])) && p() && e('120'); // 返回所有产品的数量
|
||||
r($product->getProductPairsCount($t_peoduct10['programID'])) && p() && e('10'); // 返回项目集10下的所有产品
|
||||
r($product->getNoclosedPairs($t_notclose5['programID'])) && p('6') && e('正常产品6'); // 测试项目集10下的未关闭产品5
|
||||
r($product->getNoclosedPairsCount($t_peoduct10['programID'])) && p() && e('6'); // 返回项目集10下的未关闭产品的数量
|
||||
r($product->getNoclosedPairsCount($t_peoduct10['programID'])) && p() && e('6'); // 返回项目集10下的未关闭产品的数量
|
||||
|
||||
@@ -22,19 +22,28 @@ class productTest
|
||||
*
|
||||
* @param array $param
|
||||
* @access public
|
||||
* @return object
|
||||
* @return object|array
|
||||
*/
|
||||
public function createObject($param = array()): object
|
||||
public function createObject(array $param = array()): object|array
|
||||
{
|
||||
global $createFields;
|
||||
$whitelist = array();
|
||||
$createFields = array('program' => 1, 'line' => 0, 'lineName' => '', 'newLine' => 0, 'name' => '', 'code' => '', 'PO' => 'admin', 'QD' => '', 'RD' => '',
|
||||
'reviewer' => '', 'type' => 'normal', 'status' => 'normal', 'desc' => '', 'acl' => 'open', 'uid' => '');
|
||||
foreach($createFields as $field => $defaultValue) $_POST[$field] = $defaultValue;
|
||||
foreach($param as $key => $value) $_POST[$key] = $value;
|
||||
$createFields = array();
|
||||
$createFields['program'] = 1;
|
||||
$createFields['line'] = 0;
|
||||
$createFields['name'] = '';
|
||||
$createFields['code'] = '';
|
||||
$createFields['PO'] = 'admin';
|
||||
$createFields['QD'] = '';
|
||||
$createFields['RD'] = '';
|
||||
$createFields['reviewer'] = '';
|
||||
$createFields['type'] = 'normal';
|
||||
$createFields['status'] = 'normal';
|
||||
$createFields['desc'] = '';
|
||||
$createFields['acl'] = 'open';
|
||||
|
||||
$objectID = $this->objectModel->create();
|
||||
unset($_POST);
|
||||
$data = new stdclass();
|
||||
foreach($createFields as $field => $defaultValue) $data->$field = zget($param, $field, $defaultValue);
|
||||
|
||||
$objectID = $this->objectModel->create($data);
|
||||
|
||||
if(dao::isError())
|
||||
{
|
||||
@@ -214,13 +223,16 @@ class productTest
|
||||
/**
|
||||
* Test get product pairs.
|
||||
*
|
||||
* @param int $programID
|
||||
* @param string $mode
|
||||
* @param int $programID
|
||||
* @param string|array $append
|
||||
* @param string|int $shadow
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getProductPairs($programID)
|
||||
public function getProductPairs(string $mode = '', int $programID = 0, string|array $append = '', string|int $shadow = 0): array|string
|
||||
{
|
||||
$pairs = $this->objectModel->getPairs('', $programID);
|
||||
$pairs = $this->objectModel->getPairs($mode, $programID, $append, $shadow);
|
||||
if($pairs == array()) return '没有数据';
|
||||
return $pairs;
|
||||
}
|
||||
@@ -1113,4 +1125,54 @@ class productTest
|
||||
return $object;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试创建产品线
|
||||
* Test for create line.
|
||||
*
|
||||
* @param int programID
|
||||
* @param string lineName
|
||||
* @access public
|
||||
* @return object|array
|
||||
*/
|
||||
public function createLineTest(int $programID, string $lineName): object|array
|
||||
{
|
||||
$_POST['lineName'] = $lineName;
|
||||
$lineID = $this->objectModel->createLine($programID);
|
||||
|
||||
if(dao::isError())
|
||||
{
|
||||
return dao::getError();
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!$lineID) return array();
|
||||
$object = $this->objectModel->dao->select('*')->from(TABLE_MODULE)->where('id')->eq($lineID)->fetch();
|
||||
return $object;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试创建产品主库
|
||||
* Test for create main lib.
|
||||
*
|
||||
* @param int productID
|
||||
* @access public
|
||||
* @return object|array
|
||||
*/
|
||||
public function createMainLibTest(int $productID): object|array
|
||||
{
|
||||
$libID = $this->objectModel->createMainLib($productID);
|
||||
|
||||
if(dao::isError())
|
||||
{
|
||||
return dao::getError();
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!$libID) return array();
|
||||
$object = $this->objectModel->dao->select('*')->from(TABLE_DOCLIB)->where('id')->eq($libID)->fetch();
|
||||
return $object;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
|
||||
/**
|
||||
|
||||
title=productTao->formatAppendParam();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
|
||||
*/
|
||||
|
||||
global $tester;
|
||||
$productTao = $tester->loadModel('product');
|
||||
|
||||
r($productTao->formatAppendParam('')) && p() && e('0');
|
||||
r($productTao->formatAppendParam(array())) && p() && e('0');
|
||||
r($productTao->formatAppendParam('1')) && p() && e('1');
|
||||
r($productTao->formatAppendParam('1,')) && p() && e('1');
|
||||
r($productTao->formatAppendParam('1,1')) && p() && e('1');
|
||||
r($productTao->formatAppendParam('1,2')) && p() && e('1,2');
|
||||
r($productTao->formatAppendParam('1,a')) && p() && e('1');
|
||||
r($productTao->formatAppendParam(array('1'))) && p() && e('1');
|
||||
r($productTao->formatAppendParam(array('1', '1'))) && p() && e('1');
|
||||
r($productTao->formatAppendParam(array('1', '2'))) && p() && e('1,2');
|
||||
r($productTao->formatAppendParam(array('1', 'a'))) && p() && e('1');
|
||||
|
||||
|
||||
|
||||
+200
-1
@@ -13,8 +13,8 @@ declare(strict_types=1);
|
||||
class productZen extends product
|
||||
{
|
||||
/**
|
||||
* Set shared environment data for all function of control layer.
|
||||
* 为控制层的all函数设置共享环境数据。
|
||||
* Set shared environment data for all function of control layer.
|
||||
*
|
||||
* @access protected
|
||||
* @return void
|
||||
@@ -32,6 +32,84 @@ class productZen extends product
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 为创建产品设置导航数据,主要是替换占位符。
|
||||
* Set menu for create product page.
|
||||
*
|
||||
* @param int $programID
|
||||
* @access protected
|
||||
* @return void
|
||||
*/
|
||||
protected function setMenu4Create(int $program): void
|
||||
{
|
||||
if($this->app->tab == 'program') $this->loadModel('program')->setMenu($programID);
|
||||
if($this->app->tab == 'doc') unset($this->lang->doc->menu->product['subMenu']);
|
||||
if($this->app->getViewType() != 'mhtml') return;
|
||||
|
||||
if($this->app->rawModule == 'projectstory' and $this->app->rawMethod == 'story')
|
||||
{
|
||||
$this->loadModel('project')->setMenu();
|
||||
return;
|
||||
}
|
||||
$this->product->setMenu();
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过extra获取返回链接。
|
||||
* Get goback link for create by extra.
|
||||
*
|
||||
* @param string $extra
|
||||
* @access private
|
||||
* @return string
|
||||
*/
|
||||
private function getBackLink4Create(string $extra): string
|
||||
{
|
||||
$extra = str_replace(array(',', ' '), array('&', ''), $extra);
|
||||
parse_str($extra, $output);
|
||||
|
||||
$backLink = '';
|
||||
$from = zget($output, 'from', '');
|
||||
if($from == 'qa') $backLink = $this->createLink('qa', 'index');
|
||||
if($from == 'global') $backLink = $this->createLink('product', 'all');
|
||||
return $backLink;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取创建产品页面的表单配置。
|
||||
* Get form fields for create.
|
||||
*
|
||||
* @param int $programID
|
||||
* @access private
|
||||
* @return array
|
||||
*/
|
||||
private function getFormFields4Create(int $programID = 0): array
|
||||
{
|
||||
$fields = $this->config->product->form->create;
|
||||
|
||||
$this->loadModel('user');
|
||||
$poUsers = $this->user->getPairs('nodeleted|pofirst|noclosed');
|
||||
$qdUsers = $this->user->getPairs('nodeleted|qdfirst|noclosed');
|
||||
$rdUsers = $this->user->getPairs('nodeleted|devfirst|noclosed');
|
||||
$users = $this->user->getPairs('nodeleted|noclosed');
|
||||
|
||||
foreach($fields as $field => $attr)
|
||||
{
|
||||
if(isset($attr['options']) and $attr['options'] == 'users') $fields[$field]['options'] = $users;
|
||||
$fields[$field]['name'] = $field;
|
||||
$fields[$field]['title'] = $this->lang->product->$field;
|
||||
}
|
||||
|
||||
$fields['program']['options'] = array('') + $this->loadModel('program')->getTopPairs('', 'noclosed');
|
||||
$fields['PO']['options'] = $poUsers;
|
||||
$fields['QD']['options'] = $qdUsers;
|
||||
$fields['RD']['options'] = $rdUsers;
|
||||
|
||||
if($programID) $fields['line']['options'] = array('') + $this->product->getLinePairs($programID);
|
||||
if(empty($programID) or $this->config->systemMode != 'ALM') unset($fields['line']);
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get product lines and product lines of program.
|
||||
*
|
||||
@@ -54,4 +132,125 @@ class productZen extends product
|
||||
|
||||
return array($productLines, $programLines);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建创建产品页面数据。
|
||||
* Build form fields for create.
|
||||
*
|
||||
* @param int $programID
|
||||
* @param string $extra
|
||||
* @access protected
|
||||
* @return void
|
||||
*/
|
||||
protected function buildCreateForm(int $programID = 0, string $extra = ''): void
|
||||
{
|
||||
$this->view->title = $this->lang->product->create;
|
||||
$this->view->gobackLink = $this->getBackLink4Create($extra);
|
||||
$this->view->programID = $programID;
|
||||
$this->view->fields = $this->getFormFields4Create($programID);
|
||||
unset($this->lang->product->typeList['']);
|
||||
|
||||
$this->display();
|
||||
}
|
||||
|
||||
/**
|
||||
* 追加创建信息,处理白名单、评审者、项目集字段,还有富文本内容处理。
|
||||
* Prepare data for create.
|
||||
*
|
||||
* @param int $programID
|
||||
* @param string $extra
|
||||
* @access protected
|
||||
* @return object
|
||||
*/
|
||||
protected function prepareCreateExtras(object $data): object
|
||||
{
|
||||
$product = $data->setDefault('createdBy', $this->app->user->account)
|
||||
->setDefault('createdDate', helper::now())
|
||||
->setDefault('createdVersion', $this->config->version)
|
||||
->setIF($this->config->systemMode == 'light', 'program', (int)zget($this->config->global, 'defaultProgram', 0))
|
||||
->setIF($this->post->acl == 'open', 'whitelist', '')
|
||||
->stripTags($this->config->product->editor->create['id'], $this->config->allowedTags)
|
||||
->join('whitelist', ',')
|
||||
->join('reviewer', ',')
|
||||
->remove('uid,newLine,lineName,contactListMenu')
|
||||
->get();
|
||||
|
||||
$product = $this->loadModel('file')->processImgURL($product, $this->config->product->editor->create['id'], $this->post->uid);
|
||||
|
||||
return $product;
|
||||
}
|
||||
|
||||
/**
|
||||
* 成功插入产品数据后,其他的额外操作。
|
||||
* Process after create product.
|
||||
*
|
||||
* @param int $productID
|
||||
* @param object $product
|
||||
* @access protected
|
||||
* @return void
|
||||
*/
|
||||
protected function responseAfterCreate(int $productID, object $product): void
|
||||
{
|
||||
$fixData = new stdclass();
|
||||
$fixData->order = $productID * 5;
|
||||
if(!empty($_POST['lineName']))
|
||||
{
|
||||
$lineID = $this->product->createLine((int)$product->program);
|
||||
if($lineID) $fixData->line = $lineID;
|
||||
}
|
||||
|
||||
$this->dao->update(TABLE_PRODUCT)->data($fixData)->where('id')->eq($productID)->exec();
|
||||
$this->file->updateObjectID($this->post->uid, $productID, 'product');
|
||||
|
||||
$this->loadModel('personnel')->updateWhitelist(explode(',', $product->whitelist), 'product', $productID);
|
||||
if($product->acl != 'open') $this->loadModel('user')->updateUserView($productID, 'product');
|
||||
|
||||
$this->product->createMainLib($productID);
|
||||
|
||||
$this->loadModel('action')->create('product', $productID, 'opened');
|
||||
|
||||
$message = $this->executeHooks($productID);
|
||||
if($message) $this->lang->saveSuccess = $message;
|
||||
|
||||
if($this->viewType == 'json')
|
||||
{
|
||||
$this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'id' => $productID));
|
||||
return;
|
||||
}
|
||||
|
||||
$this->sendCreateLocate($productID, (int)$product->program);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建完成后,做页面跳转。
|
||||
* Locate after create product.
|
||||
*
|
||||
* @param int $productID
|
||||
* @param int $programID
|
||||
* @access private
|
||||
* @return void
|
||||
*/
|
||||
private function sendCreateLocate(int $productID, int $programID): void
|
||||
{
|
||||
$tab = $this->app->tab;
|
||||
$moduleName = $tab == 'program'? 'program' : $this->moduleName;
|
||||
$methodName = $tab == 'program'? 'product' : 'browse';
|
||||
$param = $tab == 'program' ? "programID=$programID" : "productID=$productID";
|
||||
$locate = isonlybody() ? 'true' : $this->createLink($moduleName, $methodName, $param);
|
||||
if($tab == 'doc') $locate = $this->createLink('doc', 'productSpace', "objectID=$productID");
|
||||
|
||||
$this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'load' => $locate));
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出创建产品产生的错误。
|
||||
* Send error for create.
|
||||
*
|
||||
* @access protected
|
||||
* @return void
|
||||
*/
|
||||
protected function sendError4Create(): void
|
||||
{
|
||||
if(dao::isError()) $this->send(array('result' => 'fail', 'message' => dao::getError()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +1,25 @@
|
||||
<?php
|
||||
$config->project->form = new stdclass();
|
||||
$config->project->form->create = array();
|
||||
$config->project->form->start = array();
|
||||
$config->project->form->create = array();
|
||||
$config->project->form->start = array();
|
||||
$config->project->form->close = array();
|
||||
$config->project->form->suspend = array();
|
||||
|
||||
$config->project->form->create['parent'] = array('type' => 'int', 'required' => false, 'default' => '');
|
||||
$config->project->form->create['name'] = array('type' => 'string', 'required' => true, 'filter' => 'trim');
|
||||
$config->project->form->create['code'] = array('type' => 'string', 'required' => true, 'filter' => 'trim');
|
||||
$config->project->form->create['multiple'] = array('type' => 'string', 'required' => false, 'default' => '');
|
||||
$config->project->form->create['hasProduct'] = array('type' => 'string', 'required' => false, 'default' => '');
|
||||
$config->project->form->create['PM'] = array('type' => 'string', 'required' => false, 'default' => '');
|
||||
$config->project->form->create['budget'] = array('type' => 'string', 'required' => false, 'default' => '');
|
||||
$config->project->form->create['budgetUnit'] = array('type' => 'string', 'required' => false, 'default' => 'CNY');
|
||||
$config->project->form->create['begin'] = array('type' => 'date', 'required' => true);
|
||||
$config->project->form->create['end'] = array('type' => 'date', 'required' => true);
|
||||
$config->project->form->create['desc'] = array('type' => 'string', 'required' => false, 'default' => '');
|
||||
$config->project->form->create['acl'] = array('type' => 'string', 'required' => false, 'default' => '');
|
||||
$config->project->form->create['whitelist'] = array('type' => 'array', 'required' => false, 'default' => '');
|
||||
$config->project->form->create['auth'] = array('type' => 'array', 'required' => false, 'default' => '');
|
||||
$config->project->form->create['model'] = array('type' => 'string', 'required' => false, 'default' => '');
|
||||
$config->project->form->create['parent'] = array('type' => 'int', 'required' => false, 'default' => '');
|
||||
$config->project->form->create['name'] = array('type' => 'string', 'required' => true, 'filter' => 'trim');
|
||||
$config->project->form->create['code'] = array('type' => 'string', 'required' => true, 'filter' => 'trim');
|
||||
$config->project->form->create['multiple'] = array('type' => 'string', 'required' => false, 'default' => '');
|
||||
$config->project->form->create['hasProduct'] = array('type' => 'string', 'required' => false, 'default' => '');
|
||||
$config->project->form->create['PM'] = array('type' => 'string', 'required' => false, 'default' => '');
|
||||
$config->project->form->create['budget'] = array('type' => 'string', 'required' => false, 'default' => '');
|
||||
$config->project->form->create['budgetUnit'] = array('type' => 'string', 'required' => false, 'default' => 'CNY');
|
||||
$config->project->form->create['begin'] = array('type' => 'date', 'required' => true);
|
||||
$config->project->form->create['end'] = array('type' => 'date', 'required' => true);
|
||||
$config->project->form->create['desc'] = array('type' => 'string', 'required' => false, 'default' => '');
|
||||
$config->project->form->create['acl'] = array('type' => 'string', 'required' => false, 'default' => '');
|
||||
$config->project->form->create['whitelist'] = array('type' => 'array', 'required' => false, 'default' => '');
|
||||
$config->project->form->create['auth'] = array('type' => 'array', 'required' => false, 'default' => '');
|
||||
$config->project->form->create['model'] = array('type' => 'string', 'required' => false, 'default' => '');
|
||||
|
||||
$config->project->form->start['realBegan'] = array('type' => 'date', 'required' => true, 'filter' => 'trim');
|
||||
$config->project->form->start['realBegan'] = array('type' => 'date', 'required' => true, 'filter' => 'trim');
|
||||
$config->project->form->close['realEnd'] = array('type' => 'date', 'required' => true, 'filter' => 'trim');
|
||||
|
||||
+35
-32
@@ -193,13 +193,14 @@ class project extends control
|
||||
/**
|
||||
* Ajax get unlink tips when unlink team member.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @param int $account
|
||||
* @param string $projectID
|
||||
* @param string $account
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function ajaxGetUnlinkTips($projectID, $account)
|
||||
public function ajaxGetUnlinkTips(string $projectID, string $account)
|
||||
{
|
||||
$projectID = (int)$projectID;
|
||||
$project = $this->project->getByID($projectID);
|
||||
if(!$project->multiple) return;
|
||||
|
||||
@@ -271,6 +272,7 @@ class project extends control
|
||||
|
||||
if(!empty($objectID))
|
||||
{
|
||||
$objectID = (int)$objectID;
|
||||
$object = $objectType == 'project' ? $this->project->getByID($objectID) : $this->loadModel('program')->getByID($objectID);
|
||||
|
||||
if(isset($availableBudget)) $availableBudget = $object->parent == $selectedProgramID ? $availableBudget + (int)$object->budget : $availableBudget;
|
||||
@@ -325,6 +327,7 @@ class project extends control
|
||||
|
||||
$this->project->setMenu($projectID);
|
||||
|
||||
$projectID = (int)$projectID;
|
||||
$project = $this->project->getByID($projectID);
|
||||
|
||||
/* Locate to task when set no execution. */
|
||||
@@ -484,9 +487,6 @@ class project extends control
|
||||
*/
|
||||
public function create($model = 'scrum', $programID = 0, $copyProjectID = 0, $extra = '')
|
||||
{
|
||||
$this->loadModel('execution');
|
||||
$this->loadModel('product');
|
||||
|
||||
$this->session->set('projectModel', $model);
|
||||
|
||||
if($model == 'kanban') unset($this->lang->project->authList['reset']);
|
||||
@@ -520,7 +520,7 @@ class project extends control
|
||||
{
|
||||
if($model == 'waterfall' or $model == 'waterfallplus')
|
||||
{
|
||||
$productID = $this->product->getProductIDByProject($projectID, true);
|
||||
$productID = $this->loadModel('product')->getProductIDByProject($projectID, true);
|
||||
$this->session->set('projectPlanList', $this->createLink('programplan', 'browse', "projectID=$projectID&productID=$productID&type=lists", '', '', $projectID), 'project');
|
||||
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $this->createLink('programplan', 'create', "projectID=$projectID", '', '', $projectID)));
|
||||
}
|
||||
@@ -552,6 +552,7 @@ class project extends control
|
||||
$this->loadModel('program');
|
||||
$this->loadModel('execution');
|
||||
|
||||
$projectID = (int)$projectID;
|
||||
$project = $this->project->getByID($projectID);
|
||||
$programID = $project->parent;
|
||||
$this->project->setMenu($projectID);
|
||||
@@ -892,6 +893,7 @@ class project extends control
|
||||
*/
|
||||
public function dynamic($projectID = 0, $type = 'today', $param = '', $recTotal = 0, $date = '', $direction = 'next')
|
||||
{
|
||||
$projectID = (int)$projectID;
|
||||
$this->loadModel('execution');
|
||||
$this->project->setMenu($projectID);
|
||||
|
||||
@@ -977,6 +979,7 @@ class project extends control
|
||||
|
||||
if($this->cookie->showTask) $this->session->set('taskList', $this->app->getURI(true), 'project');
|
||||
|
||||
$projectID = (int)$projectID;
|
||||
$projects = $this->project->getPairsByProgram();
|
||||
$projectID = $this->project->saveState($projectID, $projects);
|
||||
$project = $this->project->getByID($projectID);
|
||||
@@ -1060,11 +1063,12 @@ class project extends control
|
||||
$this->session->set('bugList', $this->app->getURI(true), 'project');
|
||||
$this->project->setMenu($projectID);
|
||||
|
||||
$product = $this->product->getById($productID);
|
||||
$project = $this->project->getByID($projectID);
|
||||
$type = strtolower($type);
|
||||
$queryID = ($type == 'bysearch') ? (int)$param : 0;
|
||||
$products = $this->product->getProducts($projectID);
|
||||
$projectID = (int)$projectID;
|
||||
$product = $this->product->getById($productID);
|
||||
$project = $this->project->getByID($projectID);
|
||||
$type = strtolower($type);
|
||||
$queryID = ($type == 'bysearch') ? (int)$param : 0;
|
||||
$products = $this->product->getProducts($projectID);
|
||||
|
||||
if(!$project->multiple) unset($this->config->bug->datatable->fieldList['execution']);
|
||||
if(!$project->hasProduct)
|
||||
@@ -1261,6 +1265,7 @@ class project extends control
|
||||
$this->session->set('testtaskList', $this->app->getURI(true), 'qa');
|
||||
$this->session->set('buildList', $this->app->getURI(true), 'execution');
|
||||
|
||||
$projectID = (int)$projectID;
|
||||
$this->project->setMenu($projectID);
|
||||
|
||||
/* Load pager. */
|
||||
@@ -1304,6 +1309,7 @@ class project extends control
|
||||
/* Load module and get project. */
|
||||
$this->loadModel('build');
|
||||
$this->loadModel('product');
|
||||
$projectID = (int)$projectID;
|
||||
$project = $this->project->getByID($projectID);
|
||||
$this->project->setMenu($projectID);
|
||||
|
||||
@@ -1462,7 +1468,7 @@ class project extends control
|
||||
$this->view->version = $version;
|
||||
|
||||
/* Unset not project privs. */
|
||||
$project = $this->project->getByID($group->project);
|
||||
$project = $this->project->getByID((int)$group->project);
|
||||
if($project->hasProduct)
|
||||
{
|
||||
if($this->config->URAndSR) unset($this->lang->resource->requirement);
|
||||
@@ -1653,7 +1659,7 @@ class project extends control
|
||||
}
|
||||
|
||||
$group = $this->group->getById($groupID);
|
||||
$project = $this->project->getByID($group->project);
|
||||
$project = $this->project->getByID((int)$group->project);
|
||||
$groupUsers = $this->group->getUserPairs($groupID);
|
||||
$allUsers = $this->loadModel('dept')->getDeptUserPairs($deptID);
|
||||
$otherUsers = array_diff_assoc($allUsers, $groupUsers);
|
||||
@@ -1802,35 +1808,30 @@ class project extends control
|
||||
/**
|
||||
* Close a project.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @param string $projectID
|
||||
* @access public
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function close($projectID)
|
||||
public function close(string $projectID)
|
||||
{
|
||||
$this->loadModel('action');
|
||||
$projectID = (int)$projectID;
|
||||
|
||||
if(!empty($_POST))
|
||||
{
|
||||
$changes = $this->project->close($projectID);
|
||||
$postData = form::data($this->config->project->form->close);
|
||||
|
||||
$postData = $this->projectZen->prepareClosedExtras($projectID, $postData);
|
||||
|
||||
$changes = $this->project->close($projectID, $postData);
|
||||
if(dao::isError()) return print(js::error(dao::getError()));
|
||||
|
||||
if($this->post->comment != '' or !empty($changes))
|
||||
{
|
||||
$actionID = $this->action->create('project', $projectID, 'Closed', $this->post->comment);
|
||||
$this->action->logHistory($actionID, $changes);
|
||||
}
|
||||
$this->executeHooks($projectID);
|
||||
$comment = strip_tags($this->post->comment, $this->config->allowedTags);
|
||||
$this->projectZen->responseAfterClose($projectID, $changes, $comment);
|
||||
return print(js::reload('parent.parent'));
|
||||
}
|
||||
|
||||
$this->view->title = $this->lang->project->close;
|
||||
$this->view->position[] = $this->lang->project->close;
|
||||
$this->view->project = $this->project->getByID($projectID);
|
||||
$this->view->users = $this->loadModel('user')->getPairs('noletter');
|
||||
$this->view->actions = $this->action->getList('project', $projectID);
|
||||
|
||||
$this->display();
|
||||
$this->projectZen->buildClosedForm($projectID);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1844,7 +1845,8 @@ class project extends control
|
||||
{
|
||||
$this->loadModel('action');
|
||||
$this->app->loadLang('execution');
|
||||
$project = $this->project->getByID($projectID);
|
||||
$projectID = (int)$projectID;
|
||||
$project = $this->project->getByID($projectID);
|
||||
|
||||
if(!empty($_POST))
|
||||
{
|
||||
@@ -1886,6 +1888,7 @@ class project extends control
|
||||
*/
|
||||
public function delete($projectID, $confirm = 'no', $from = 'browse')
|
||||
{
|
||||
$projectID = (int)$projectID;
|
||||
if($confirm == 'no')
|
||||
{
|
||||
$project = $this->project->getByID($projectID);
|
||||
|
||||
@@ -1811,53 +1811,34 @@ class projectModel extends model
|
||||
}
|
||||
|
||||
/**
|
||||
* Close project.
|
||||
* 关闭项目并更改其状态
|
||||
* Close project and update status.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @param string $type
|
||||
* @param object $project
|
||||
*
|
||||
* @access public
|
||||
* @return array
|
||||
* @return array|false
|
||||
*/
|
||||
public function close($projectID, $type = 'project')
|
||||
public function close(int $projectID, object $project): array|false
|
||||
{
|
||||
$oldProject = $this->getById($projectID, $type);
|
||||
$now = helper::now();
|
||||
$oldProject = $this->getByID($projectID);
|
||||
|
||||
$editorIdList = $this->config->project->editor->close['id'];
|
||||
if($this->app->rawModule == 'program') $editorIdList = $this->config->program->editor->close['id'];
|
||||
|
||||
$project = fixer::input('post')
|
||||
->add('id', $projectID)
|
||||
->setDefault('status', 'closed')
|
||||
->setDefault('closedBy', $this->app->user->account)
|
||||
->setDefault('closedDate', $now)
|
||||
->setDefault('lastEditedBy', $this->app->user->account)
|
||||
->setDefault('lastEditedDate', $now)
|
||||
->stripTags($editorIdList, $this->config->allowedTags)
|
||||
->remove('comment')
|
||||
->get();
|
||||
|
||||
$this->lang->error->ge = $this->lang->project->ge;
|
||||
|
||||
$project = $this->loadModel('file')->processImgURL($project, $editorIdList, $this->post->uid);
|
||||
|
||||
$this->dao->update(TABLE_PROJECT)->data($project)
|
||||
->autoCheck()
|
||||
->check($this->config->project->close->requiredFields, 'notempty')
|
||||
->checkIF($project->realEnd != '', 'realEnd', 'le', helper::today())
|
||||
->checkIF($project->realEnd != '', 'realEnd', 'ge', $oldProject->realBegan)
|
||||
->checkFlow()
|
||||
->where('id')->eq((int)$projectID)
|
||||
->exec();
|
||||
$this->projectTao->doClosed($projectID, $project, $oldProject);
|
||||
|
||||
/* When it has multiple errors, only the first one is prompted */
|
||||
if(dao::isError())
|
||||
{
|
||||
if(count(dao::$errors['realEnd']) > 1) dao::$errors['realEnd'] = dao::$errors['realEnd'][0];
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!$oldProject->multiple) $this->changeExecutionStatus($projectID, 'close');
|
||||
|
||||
/* Close the shadow product of the project. */
|
||||
|
||||
@@ -51,6 +51,30 @@ class projectTao extends projectModel
|
||||
return !dao::isError();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update project table when close a project.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @param object $project
|
||||
* @param object $oldProject
|
||||
*
|
||||
* @access protected
|
||||
* @return bool
|
||||
*/
|
||||
protected function doClosed(int $projectID, object $project, object $oldProject): bool
|
||||
{
|
||||
$this->dao->update(TABLE_PROJECT)->data($project)
|
||||
->autoCheck()
|
||||
->check($this->config->project->close->requiredFields, 'notempty')
|
||||
->checkIF($project->realEnd != '', 'realEnd', 'le', helper::today())
|
||||
->checkIF($project->realEnd != '', 'realEnd', 'ge', $oldProject->realBegan)
|
||||
->checkFlow()
|
||||
->where('id')->eq($projectID)
|
||||
->exec();
|
||||
|
||||
return !dao::isError();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update project.
|
||||
*
|
||||
|
||||
@@ -3,27 +3,65 @@
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
su('admin');
|
||||
|
||||
function initData()
|
||||
{
|
||||
$project = zdTable('project');
|
||||
$project->id->range('1-5');
|
||||
$project->project->range('1-5');
|
||||
$project->name->prefix("项目")->range('1-5');
|
||||
$project->code->prefix("project")->range('1-5');
|
||||
$project->type->range("project");
|
||||
$project->status->range("wait,doing,suspended,closed");
|
||||
|
||||
$project->gen(5);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
title=测试 projectModel->close();
|
||||
timeout=0
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
关闭id为20状态不是closed的项目 >> status,wait,closed
|
||||
关闭id为26状态是closed的项目 >> closedBy,,admin
|
||||
关闭id为41状态是suspended的项目 >> status,suspended,closed
|
||||
- 执行$changes1
|
||||
- 第0条的field属性 @status
|
||||
- 第0条的old属性 @wait
|
||||
- 第0条的new属性 @closed
|
||||
|
||||
- 执行$changes2
|
||||
- 第2条的field属性 @closedBy
|
||||
- 第2条的old属性 @~~
|
||||
- 第2条的new属性 @admin
|
||||
|
||||
- 执行$changes3
|
||||
- 第0条的field属性 @status
|
||||
- 第0条的old属性 @suspended
|
||||
- 第0条的new属性 @closed
|
||||
|
||||
- 执行$changes3
|
||||
- 第1条的field属性 @realEnd
|
||||
- 第1条的old属性 @0000-00-00
|
||||
- 第1条的new属性 @2022-10-10
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
global $tester;
|
||||
$tester->loadModel('project');
|
||||
|
||||
$_POST['realEnd'] = '2022-03-11';
|
||||
initData();
|
||||
$_POST['realEnd'] = '2022-05-03';
|
||||
|
||||
$changes1 = $tester->project->close(12);
|
||||
$changes2 = $tester->project->close(26);
|
||||
$changes3 = $tester->project->close(41);
|
||||
$data = new stdclass();
|
||||
$data->status = 'closed';
|
||||
$data->realEnd = '2022-10-10';
|
||||
$data->closedBy = 'admin';
|
||||
|
||||
r($changes1) && p('1:field,old,new') && e('status,wait,closed'); // 关闭id为20状态不是closed的项目
|
||||
r($changes2) && p('1:field,old,new') && e('closedBy,,admin'); // 关闭id为26状态是closed的项目
|
||||
r($changes3) && p('1:field,old,new') && e('status,suspended,closed'); // 关闭id为41状态是suspended的项目
|
||||
$changes1 = $tester->project->close(1, $data);
|
||||
$changes2 = $tester->project->close(5, $data);
|
||||
$changes3 = $tester->project->close(3, $data);
|
||||
|
||||
r($changes1) && p('0:field,old,new') && e('status,wait,closed');
|
||||
r($changes2) && p('2:field,old,new') && e('closedBy,~~,admin');
|
||||
r($changes3) && p('0:field,old,new') && e('status,suspended,closed');
|
||||
r($changes3) && p('1:field,old,new') && e('realEnd,0000-00-00,2022-10-10');
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/project.class.php';
|
||||
su('admin');
|
||||
|
||||
function initData()
|
||||
@@ -40,10 +41,9 @@ cid=1
|
||||
|
||||
*/
|
||||
|
||||
global $tester;
|
||||
$tester->loadModel('project');
|
||||
|
||||
initData();
|
||||
|
||||
r($tester->project->getByID(2)) && p('code,type') && e('project2,project'); //获取ID等于11的项目
|
||||
r($tester->project->getByID(1)) && p('code') && e('0'); //获取不存在的项目
|
||||
$projectTester = new Project();
|
||||
r($projectTester->testGetByID(2)) && p('code,type') && e('project2,project'); //获取ID等于11的项目
|
||||
r($projectTester->testGetByID(1)) && p('code') && e('0'); //获取不存在的项目
|
||||
r($projectTester->testGetByID('aaa')) && p('code') && e('($projectID) must be of type int'); //获取字符串ID的项目
|
||||
|
||||
@@ -38,11 +38,11 @@ $tester->loadModel('project');
|
||||
initData();
|
||||
|
||||
$project = new stdClass;
|
||||
$project->status = 'suspended';
|
||||
$project->lastEditedBy = 'admin';
|
||||
$project->status = 'suspended';
|
||||
$project->lastEditedBy = 'admin';
|
||||
$project->lastEditedDate = '2023-04-27';
|
||||
$project->suspendedDate = '2023-05-03';
|
||||
$project->suspendedDate = '2023-05-03';
|
||||
|
||||
r($tester->project->suspend(2, $project)) && p('0:new') && e('suspended');
|
||||
r($tester->project->suspend(5, $project)) && p('1:field') && e('suspendedDate');
|
||||
r($tester->project->suspend(4, $project)) && p('0:new') && e('suspended');
|
||||
r($tester->project->suspend(4, $project)) && p('0:new') && e('suspended');
|
||||
|
||||
@@ -15,6 +15,52 @@ class Project
|
||||
$this->project = $tester->loadModel('project');
|
||||
}
|
||||
|
||||
/**
|
||||
* Call project model function and handle the exception.
|
||||
*
|
||||
* @param string $method
|
||||
* @param array $params
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function triggerMethod($method, $params = array())
|
||||
{
|
||||
try
|
||||
{
|
||||
return call_user_func_array(array($this->project, $method), $params);
|
||||
}
|
||||
catch(Throwable $error)
|
||||
{
|
||||
$errorInfo = $error->getMessage();
|
||||
if(preg_match('/Argument #\d+ (\(\$\w+\) must be of type [a-z]+),/', $errorInfo, $matches)) return $matches[1];
|
||||
return $errorInfo;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getByID function.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @access public
|
||||
* @return string|bool|object
|
||||
*/
|
||||
public function testGetByID($projectID)
|
||||
{
|
||||
return $this->triggerMethod('getByID', array('projectID' => $projectID));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test fetchProjectInfo function.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @access public
|
||||
* @return string|bool|object
|
||||
*/
|
||||
public function testFetchProjectInfo($projectID)
|
||||
{
|
||||
return $this->triggerMethod('fetchProjectInfo', array('projectID' => $projectID));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test start a project.
|
||||
*
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/project.class.php';
|
||||
su('admin');
|
||||
|
||||
function initData()
|
||||
@@ -34,10 +35,9 @@ cid=1
|
||||
|
||||
*/
|
||||
|
||||
global $tester;
|
||||
$tester->loadModel('project');
|
||||
|
||||
initData();
|
||||
|
||||
r($tester->project->fetchProjectInfo(2)) && p('code,type') && e('project2,project'); //获取ID等于11的项目
|
||||
r($tester->project->fetchProjectInfo(1)) && p('code') && e('0'); //获取不存在的项目
|
||||
$projectTester = new Project();
|
||||
r($projectTester->testFetchProjectInfo(2)) && p('code,type') && e('project2,project'); //获取ID等于2的项目
|
||||
r($projectTester->testFetchProjectInfo(1)) && p('code') && e('0'); //获取不存在的项目
|
||||
r($projectTester->testFetchProjectInfo('aaa')) && p('code') && e('($projectID) must be of type int'); //获取字符串ID的项目
|
||||
|
||||
@@ -70,13 +70,13 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<th class='w-130px'><?php echo $lang->project->name;?></th>
|
||||
<td class="col-main"><?php echo html::input('name', $name, "class='form-control' required");?></td>
|
||||
<td class="col-main"><?php echo html::input('name', $copyProjectID ? $copyProject->name : '', "class='form-control' required");?></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<?php if(isset($config->setCode) and $config->setCode == 1):?>
|
||||
<tr>
|
||||
<th><?php echo $lang->project->code;?></th>
|
||||
<td><?php echo html::input('code', $code, "class='form-control' required");?></td>
|
||||
<td><?php echo html::input('code', $copyProjectID ? $copyProject->code : '', "class='form-control' required");?></td>
|
||||
</tr>
|
||||
<?php endif;?>
|
||||
<?php if($model == 'scrum' or $model == 'kanban'):?>
|
||||
@@ -84,8 +84,8 @@
|
||||
<th><?php echo $lang->project->multiple;?></th>
|
||||
<td colspan='3'>
|
||||
<?php
|
||||
echo nl2br(html::radio('multiple', $lang->project->multipleList, $multiple, $copyProjectID ? 'disabled' : ''));
|
||||
if($copyProjectID) echo html::hidden('multiple', $multiple);
|
||||
echo nl2br(html::radio('multiple', $lang->project->multipleList, '1', $copyProjectID ? 'disabled' : ''));
|
||||
if($copyProjectID) echo html::hidden('multiple', $copyProject->multiple);
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -94,8 +94,8 @@
|
||||
<th id='projectType'><?php echo $lang->project->type;?></th>
|
||||
<td>
|
||||
<?php
|
||||
echo html::radio('hasProduct', $lang->project->projectTypeList, $hasProduct, $copyProjectID ? 'disabled' : '');
|
||||
if($copyProjectID) echo html::hidden('hasProduct', $hasProduct);
|
||||
echo html::radio('hasProduct', $lang->project->projectTypeList, '1', $copyProjectID ? 'disabled' : '');
|
||||
if($copyProjectID) echo html::hidden('hasProduct', $copyProject->hasProduct);
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -144,7 +144,7 @@
|
||||
</div>
|
||||
</td><td></td><td></td>
|
||||
</tr>
|
||||
<?php if($products):?>
|
||||
<?php if(!empty($products)):?>
|
||||
<?php $i = 0;?>
|
||||
<?php foreach($products as $product):?>
|
||||
<tr>
|
||||
@@ -172,7 +172,7 @@
|
||||
<div class="col-sm-6">
|
||||
<div class='input-group' <?php echo "id='plan$i'";?>>
|
||||
<span class='input-group-addon'><?php echo $lang->product->plan;?></span>
|
||||
<?php echo html::select("plans[$product->id][]", isset($productPlans[$product->id]) ? $productPlans[$product->id] : array(), $product->plans, "class='form-control chosen' multiple");?>
|
||||
<?php echo html::select("plans[$product->id][]", isset($copyProject->productPlans[$product->id]) ? $copyProject->productPlans[$product->id] : array(), $product->plans, "class='form-control chosen' multiple");?>
|
||||
<div class='input-group-btn'>
|
||||
<a href='javascript:;' onclick='addNewLine(this)' class='btn btn-link addLine'><i class='icon-plus'></i></a>
|
||||
<a href='javascript:;' onclick='removeLine(this)' class='btn btn-link removeLine' <?php if($i == 0) echo "style='visibility: hidden'";?>><i class='icon-close'></i></a>
|
||||
@@ -253,7 +253,7 @@
|
||||
<?php $this->printExtendFields(isset($project) ? $project : '', 'table', 'columns=3');?>
|
||||
<tr>
|
||||
<th><?php echo $lang->project->acl;?></th>
|
||||
<td colspan='3' class='aclBox'><?php echo nl2br(html::radio('acl', $lang->project->aclList, $acl, "onclick='setWhite(this.value);'", 'block'));?></td>
|
||||
<td colspan='3' class='aclBox'><?php echo nl2br(html::radio('acl', $lang->project->aclList, $copyProjectID ? $copyProject->acl : 'private', "onclick='setWhite(this.value);'", 'block'));?></td>
|
||||
</tr>
|
||||
<tr class="hidden" id="whitelistBox">
|
||||
<th><?php echo $lang->whitelist;?></th>
|
||||
@@ -266,7 +266,7 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->project->auth;?></th>
|
||||
<td colspan='3'><?php echo html::radio('auth', $lang->project->authList, $auth, '', 'block');?></td>
|
||||
<td colspan='3'><?php echo html::radio('auth', $lang->project->authList, $copyProjectID ? $copyProject->auth : 'extend', '', 'block');?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan='4' class='text-center form-actions'>
|
||||
@@ -309,9 +309,9 @@
|
||||
</div>
|
||||
</div>
|
||||
<div id='projectAcl' class='hidden'>
|
||||
<?php echo nl2br(html::radio('acl', $lang->project->aclList, $acl, "onclick='setWhite(this.value);'", 'block'));?>
|
||||
<?php echo nl2br(html::radio('acl', $lang->project->aclList, $copyProjectID ? $copyProject->acl : 'private', "onclick='setWhite(this.value);'", 'block'));?>
|
||||
</div>
|
||||
<div id='programAcl' class='hidden'>
|
||||
<?php echo nl2br(html::radio('acl', $lang->project->subAclList, $acl, "onclick='setWhite(this.value);'", 'block'));?>
|
||||
<?php echo nl2br(html::radio('acl', $lang->project->subAclList, $copyProjectID ? $copyProject->acl : 'private', "onclick='setWhite(this.value);'", 'block'));?>
|
||||
</div>
|
||||
<?php include '../../common/view/footer.html.php';?>
|
||||
|
||||
+70
-4
@@ -50,7 +50,7 @@ class projectZen extends project
|
||||
return $project;
|
||||
}
|
||||
|
||||
private function checkProductAndBranch(object $rawdata, object $project): bool
|
||||
private function checkProductAndBranch(object $rawdata, object $project): bool
|
||||
{
|
||||
$linkedProductsCount = 0;
|
||||
if($project->hasProduct && isset($rawdata->products))
|
||||
@@ -91,7 +91,7 @@ class projectZen extends project
|
||||
return true;
|
||||
}
|
||||
|
||||
private function checkDaysAndBudget(object $rawdata, object $project): bool
|
||||
private function checkDaysAndBudget(object $rawdata, object $project): bool
|
||||
{
|
||||
/* Judge workdays is legitimate. */
|
||||
$workdays = helper::diffDate($project->end, $project->begin) + 1;
|
||||
@@ -122,7 +122,7 @@ class projectZen extends project
|
||||
return true;
|
||||
}
|
||||
|
||||
private function checkProductNameUnqiue(object $rawdata, object $project): bool
|
||||
private function checkProductNameUnqiue(object $rawdata, object $project): bool
|
||||
{
|
||||
/* When select create new product, product name cannot be empty and duplicate. */
|
||||
if($project->hasProduct && isset($rawdata->newProduct))
|
||||
@@ -312,11 +312,37 @@ class projectZen extends project
|
||||
->remove('comment')->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Append extras data to post data.
|
||||
*
|
||||
* @param int $iprojectID
|
||||
* @param object $postData
|
||||
*
|
||||
* @access protected
|
||||
* @return object
|
||||
*/
|
||||
protected function prepareClosedExtras(int $projectID, object $postData): object
|
||||
{
|
||||
$editorIdList = $this->config->project->editor->suspend['id'];
|
||||
if($this->app->rawModule == 'program') $editorIdList = $this->config->program->editor->suspend['id'];
|
||||
|
||||
return $postData->add('id', $projectID)
|
||||
->setDefault('status', 'closed')
|
||||
->setDefault('closedBy', $this->app->user->account)
|
||||
->setDefault('closedDate', helper::now())
|
||||
->setDefault('lastEditedBy', $this->app->user->account)
|
||||
->setDefault('lastEditedDate', helper::now())
|
||||
->stripTags($editorIdList, $this->config->allowedTags)
|
||||
->remove('comment')
|
||||
->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send variables to view page.
|
||||
*
|
||||
* @param object $project
|
||||
* @access protected
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function buildStartForm(object $project): void
|
||||
@@ -334,6 +360,7 @@ class projectZen extends project
|
||||
* @param object $project
|
||||
* @param array $changes
|
||||
* @param string $comment
|
||||
*
|
||||
* @access protected
|
||||
* @return void
|
||||
*/
|
||||
@@ -378,7 +405,6 @@ class projectZen extends project
|
||||
*
|
||||
* @param int $projectID
|
||||
* @access protected
|
||||
* @return int
|
||||
*/
|
||||
protected function buildSuspendForm(int $projectID): void
|
||||
{
|
||||
@@ -388,4 +414,44 @@ class projectZen extends project
|
||||
$this->view->project = $this->project->getByID($projectID);
|
||||
$this->display();
|
||||
}
|
||||
|
||||
/**
|
||||
* After closing the project, do other operations.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @param array $changes
|
||||
* @param string $comment
|
||||
*
|
||||
* @access protected
|
||||
* @return void
|
||||
*/
|
||||
protected function responseAfterClose(int $projectID, array $changes, string $comment): void
|
||||
{
|
||||
if($comment != '' or !empty($changes))
|
||||
{
|
||||
$actionID = $this->loadModel('action')->create('project', $projectID, 'Closed', $comment);
|
||||
$this->action->logHistory($actionID, $changes);
|
||||
}
|
||||
|
||||
$this->loadModel('common')->syncPPEStatus($projectID);
|
||||
|
||||
$this->executeHooks($projectID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send variables to close page.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @access protected
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function buildClosedForm(int $projectID): void
|
||||
{
|
||||
$this->view->title = $this->lang->project->close;
|
||||
$this->view->users = $this->loadModel('user')->getPairs('noletter');
|
||||
$this->view->project = $this->project->getByID($projectID);
|
||||
$this->view->actions = $this->loadModel('action')->getList('project', $projectID);
|
||||
$this->display();
|
||||
}
|
||||
}
|
||||
|
||||
+24
-67
@@ -2463,10 +2463,8 @@ class taskModel extends model
|
||||
public function getExecutionTasks(int $executionID, int $productID = 0, string|array $type = 'all', array $modules = array(), string $orderBy = 'status_asc, id_desc', object $pager = null): array
|
||||
{
|
||||
$tasks = $this->taskTao->fetchExecutionTasks($executionID, $productID, $type, $modules, $orderBy, $pager);
|
||||
|
||||
if(empty($tasks)) return array();
|
||||
|
||||
$parents = array();
|
||||
$taskTeam = $this->taskTao->getTeamMembersByIdList(array_keys($tasks));
|
||||
foreach($tasks as $task)
|
||||
{
|
||||
@@ -2475,7 +2473,15 @@ class taskModel extends model
|
||||
|
||||
if($this->config->vision == 'lite') $tasks = $this->appendLane($tasks);
|
||||
|
||||
$tasks = $this->taskTao->restructureHierarchy($tasks);
|
||||
$parentIdList = array();
|
||||
foreach($tasks as $task)
|
||||
{
|
||||
if($task->parent <= 0 or isset($tasks[$task->parent]) or isset($parentIdList[$task->parent])) continue;
|
||||
$parentIdList[$task->parent] = $task->parent;
|
||||
}
|
||||
|
||||
$parentTasks = $this->getByList($parentIdList);
|
||||
$tasks = $this->taskTao->buildTaskTree($tasks, $parentTasks);
|
||||
return $this->processTasks($tasks);
|
||||
}
|
||||
|
||||
@@ -2626,19 +2632,26 @@ class taskModel extends model
|
||||
* @access public
|
||||
* @return object[]
|
||||
*/
|
||||
public function getStoryTasks(int $storyID, int $executionID = 0, int $projectID = 0): array
|
||||
public function getListByStory(int $storyID, int $executionID = 0, int $projectID = 0): array
|
||||
{
|
||||
$tasks = $this->dao->select('id, parent, name, assignedTo, pri, status, estimate, consumed, closedReason, `left`')
|
||||
->from(TABLE_TASK)
|
||||
->where('story')->eq((int)$storyID)
|
||||
->where('story')->eq($storyID)
|
||||
->andWhere('deleted')->eq(0)
|
||||
->beginIF($executionID)->andWhere('execution')->eq($executionID)->fi()
|
||||
->beginIF($projectID)->andWhere('project')->eq($projectID)->fi()
|
||||
->fetchAll('id');
|
||||
|
||||
$tasks = $this->taskTao->restructureHierarchy($tasks);
|
||||
$parentIdList = array();
|
||||
foreach($tasks as $task)
|
||||
{
|
||||
if($task->parent <= 0 or isset($tasks[$task->parent]) or isset($parentIdList[$task->parent])) continue;
|
||||
$parentIdList[$task->parent] = $task->parent;
|
||||
}
|
||||
|
||||
return $this->taskTao->computeTasksProgress($tasks);
|
||||
$parentTasks = $this->getByList($parentIdList);
|
||||
$tasks = $this->taskTao->buildTaskTree($tasks, $parentTasks);
|
||||
return $this->taskTao->batchComputeProgress($tasks);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4059,11 +4072,11 @@ class taskModel extends model
|
||||
$oldObject = $this->dao->select('*')->from($changeTable)->where('id')->eq($objectID)->fetch();
|
||||
if($objectType == 'task')
|
||||
{
|
||||
$this->updateTaskEsDateByGantt($objectID, $objectType, $post);
|
||||
$this->taskTao->updateTaskEsDateByGantt($objectID, $post);
|
||||
}
|
||||
elseif($objectType == 'plan')
|
||||
{
|
||||
$this->updateExecutionEsDateByGantt($objectID, $objectType, $post);
|
||||
$this->updateExecutionEsDateByGantt($objectID, $post);
|
||||
}
|
||||
|
||||
if(dao::isError()) return false;
|
||||
@@ -4076,60 +4089,6 @@ class taskModel extends model
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update Task estimate date by gantt.
|
||||
*
|
||||
* @param int $objectID
|
||||
* @param string $objectType
|
||||
* @param object $postData
|
||||
* @access private
|
||||
* @return bool
|
||||
*/
|
||||
private function updateTaskEsDateByGantt($objectID, $objectType, $postData)
|
||||
{
|
||||
$objectData = $this->dao->select('*')->from(TABLE_TASK)->where('id')->eq($objectID)->fetch();
|
||||
$parent = $objectData->parent;
|
||||
$project = $objectData->project;
|
||||
$execution = $objectData->execution;
|
||||
$stage = $this->dao->select('*')->from(TABLE_PROJECT)->where('id')->eq($execution)->andWhere('project')->eq($project)->fetch();
|
||||
|
||||
if($parent <= 0)
|
||||
{
|
||||
$parentData = $stage;
|
||||
|
||||
$start = $parentData->begin;
|
||||
$end = $parentData->end;
|
||||
}
|
||||
else
|
||||
{
|
||||
$parentData = $this->dao->select('*')->from(TABLE_TASK)->where('id')->eq($parent)->fetch();
|
||||
|
||||
$start = helper::isZeroDate($parentData->estStarted) ? '' : $parentData->estStarted;
|
||||
$end = helper::isZeroDate($parentData->deadline) ? '' : $parentData->deadline;
|
||||
}
|
||||
|
||||
if(helper::diffDate($start, $postData->startDate) > 0)
|
||||
{
|
||||
$arg = !empty($parent) ? $this->lang->task->parent : $this->lang->project->stage;
|
||||
return dao::$errors = sprintf($this->lang->task->overEsStartDate, $arg, $arg);
|
||||
}
|
||||
|
||||
if(helper::diffDate($end, $postData->endDate) < 0)
|
||||
{
|
||||
$arg = !empty($parent) ? $this->lang->task->parent : $this->lang->project->stage;
|
||||
return dao::$errors = sprintf($this->lang->task->overEsEndDate, $arg, $arg);
|
||||
}
|
||||
|
||||
$this->dao->update(TABLE_TASK)
|
||||
->set('estStarted')->eq($postData->startDate)
|
||||
->set('deadline')->eq($postData->endDate)
|
||||
->set('lastEditedBy')->eq($this->app->user->account)
|
||||
->where('id')->eq($objectID)
|
||||
->exec();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update Execution estimate date by gantt.
|
||||
*
|
||||
@@ -4139,7 +4098,7 @@ class taskModel extends model
|
||||
* @access private
|
||||
* @return bool
|
||||
*/
|
||||
private function updateExecutionEsDateByGantt($objectID, $objectType, $postData)
|
||||
private function updateExecutionEsDateByGantt($objectID, $postData)
|
||||
{
|
||||
$objectData = $this->dao->select('*')->from(TABLE_PROJECT)->where('id')->eq($objectID)->fetch();
|
||||
$project = $objectData->project;
|
||||
@@ -4161,7 +4120,7 @@ class taskModel extends model
|
||||
if(helper::diffDate($start, $postData->startDate) > 0)
|
||||
{
|
||||
$arg = !empty($parent) ? $this->lang->programplan->parent : $this->lang->project->common;
|
||||
return dao::$errors = sprintf($this->lang->task->overEsStartDate, $arg, $arg);
|
||||
dao::$errors = sprintf($this->lang->task->overEsStartDate, $arg, $arg);
|
||||
}
|
||||
|
||||
if(helper::diffDate($end, $postData->endDate) < 0)
|
||||
@@ -4176,8 +4135,6 @@ class taskModel extends model
|
||||
->set('lastEditedBy')->eq($this->app->user->account)
|
||||
->where('id')->eq($objectID)
|
||||
->exec();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+50
-27
@@ -17,42 +17,39 @@ class taskTao extends taskModel
|
||||
* 获取任务的进度。
|
||||
*
|
||||
* @param object $task
|
||||
* @access private
|
||||
* @access protected
|
||||
* @return float
|
||||
*/
|
||||
protected function computeTaskProgress(object $task): float
|
||||
{
|
||||
if($task->consumed == 0 and $task->left == 0) return 0;
|
||||
if($task->consumed != 0 and $task->left == 0) return 100;
|
||||
return round($task->consumed / ($task->consumed + $task->left), 2) * 100;
|
||||
if($task->left != 0) return round($task->consumed / ($task->consumed + $task->left), 2) * 100;
|
||||
if($task->consumed == 0) return 0;
|
||||
return 100;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute progress of task list, include its' children.
|
||||
* 计算任务列表中每个任务的进度,包括子任务。
|
||||
*
|
||||
* @param array $tasks
|
||||
* @access private
|
||||
* @param object[] $tasks
|
||||
* @access protected
|
||||
* @return object[]
|
||||
*/
|
||||
protected function computeTasksProgress(array $tasks): array
|
||||
protected function batchComputeProgress(array $tasks): array
|
||||
{
|
||||
foreach($tasks as $task)
|
||||
{
|
||||
$task->progress = $this->computeTaskProgress($task);
|
||||
|
||||
if(empty($task->children)) continue;
|
||||
foreach($task->children as $child)
|
||||
{
|
||||
$child->progress = $this->computeTaskProgress($child);
|
||||
}
|
||||
|
||||
$task->children = $this->batchComputeProgress($task->children);
|
||||
}
|
||||
|
||||
return $tasks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch tasks under execution by executionID,
|
||||
* Fetch tasks under execution by executionID(Todo).
|
||||
* 获取执行下的任务。
|
||||
*
|
||||
* @param int $executionID
|
||||
@@ -175,14 +172,13 @@ class taskTao extends taskModel
|
||||
* @param string $field
|
||||
* @param string $condition
|
||||
* @access public
|
||||
* @return ojbect[]
|
||||
* @return object[]
|
||||
*/
|
||||
protected function getListByReportCondition(string $field, string $condition): array
|
||||
{
|
||||
$tasks = $this->dao->select("id,{$field}")->from(TABLE_TASK)
|
||||
return $this->dao->select("id,{$field}")->from(TABLE_TASK)
|
||||
->where($condition)
|
||||
->fetchAll('id');
|
||||
return $tasks;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -223,31 +219,25 @@ class taskTao extends taskModel
|
||||
* Change the hierarchy of tasks to a parent-child structure.
|
||||
* 将任务的层级改为父子结构。
|
||||
*
|
||||
* @param array $tasks
|
||||
* @param object[] $tasks
|
||||
* @param object[] $parentTasks
|
||||
* @access protected
|
||||
* @return object[]
|
||||
*/
|
||||
protected function restructureHierarchy(array $tasks): array
|
||||
protected function buildTaskTree(array $tasks, array $parentTasks): array
|
||||
{
|
||||
$parentIdList = array();
|
||||
foreach($tasks as $task)
|
||||
{
|
||||
if($task->parent <= 0 or isset($tasks[$task->parent]) or isset($parentIdList[$task->parent])) continue;
|
||||
$parentIdList[$task->parent] = $task->parent;
|
||||
}
|
||||
|
||||
$parents = $this->getByList($parentIdList);
|
||||
foreach($tasks as $task)
|
||||
{
|
||||
if($task->parent <= 0) continue;
|
||||
if(isset($tasks[$task->parent]))
|
||||
{
|
||||
if(!isset($tasks[$task->parent]->children)) $tasks[$task->parent]->children = array();
|
||||
$tasks[$task->parent]->children[$task->id] = $task;
|
||||
unset($tasks[$task->id]);
|
||||
}
|
||||
else
|
||||
{
|
||||
$parent = $parents[$task->parent];
|
||||
$parent = $parentTasks[$task->parent];
|
||||
$task->parentName = $parent->name;
|
||||
}
|
||||
}
|
||||
@@ -309,4 +299,37 @@ class taskTao extends taskModel
|
||||
|
||||
return $currentTask;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过拖动甘特图修改任务的预计开始日期和截止日期。
|
||||
* Update task estimate date and deadline through gantt.
|
||||
*
|
||||
* @param int $taskID
|
||||
* @param object $postData
|
||||
* @access protected
|
||||
* @return void
|
||||
*/
|
||||
protected function updateTaskEsDateByGantt(int $taskID, object $postData)
|
||||
{
|
||||
$task = $this->dao->select('*')->from(TABLE_TASK)->where('id')->eq($taskID)->fetch();
|
||||
$isChildTask = $task->parent > 0 ? true : false;
|
||||
|
||||
if($isChildTask) $parentTask = $this->dao->select('*')->from(TABLE_TASK)->where('id')->eq($task->parent)->fetch();
|
||||
|
||||
$stage = $this->dao->select('*')->from(TABLE_PROJECT)->where('id')->eq($task->execution)->andWhere('project')->eq($task->project)->fetch();
|
||||
|
||||
$start = $isChildTask ? $parentTask->estStarted : $stage->begin;
|
||||
$end = $isChildTask ? $parentTask->deadline : $stage->end;
|
||||
$arg = $isChildTask ? $this->lang->task->parent : $this->lang->project->stage;
|
||||
|
||||
if(helper::diffDate($start, $postData->startDate) > 0) dao::$errors = sprintf($this->lang->task->overEsStartDate, $arg, $arg);
|
||||
if(helper::diffDate($end, $postData->endDate) < 0) dao::$errors = sprintf($this->lang->task->overEsEndDate, $arg, $arg);
|
||||
|
||||
$this->dao->update(TABLE_TASK)
|
||||
->set('estStarted')->eq($postData->startDate)
|
||||
->set('deadline')->eq($postData->endDate)
|
||||
->set('lastEditedBy')->eq($this->app->user->account)
|
||||
->where('id')->eq($taskID)
|
||||
->exec();
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -6,7 +6,7 @@ su('admin');
|
||||
|
||||
/**
|
||||
|
||||
title=taskModel->getStoryTasks();
|
||||
title=taskModel->getListByStory();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
@@ -19,5 +19,5 @@ $storyID = '1';
|
||||
$count = array('0','1');
|
||||
|
||||
$task = new taskTest();
|
||||
r($task->getStoryTasksTest($storyID,$count[0])) && p('1:name') && e('开发任务11'); // 根据需求查看任务
|
||||
r($task->getStoryTasksTest($storyID,$count[1])) && p() && e('6'); // 根据需求查看任务数量统计
|
||||
r($task->getListByStoryTest($storyID,$count[0])) && p('1:name') && e('开发任务11'); // 根据需求查看任务
|
||||
r($task->getListByStoryTest($storyID,$count[1])) && p() && e('6'); // 根据需求查看任务数量统计
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
|
||||
function initData()
|
||||
{
|
||||
$task = zdTable('task');
|
||||
$task->id->range('1-5');
|
||||
$task->name->prefix('任务')->range('1-5');
|
||||
$task->consumed->range('0,10,15,20,25');
|
||||
$task->left->range('0,0,1,5,10');
|
||||
|
||||
$task->gen(5);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
title=taskModel->batchComputeProgress();
|
||||
timeout=0
|
||||
cid=2
|
||||
|
||||
|
||||
*/
|
||||
$tester->loadModel('task');
|
||||
|
||||
initData();
|
||||
|
||||
$taskIDList = range(1,5);
|
||||
$taskList = $tester->task->getByList($taskIDList);
|
||||
|
||||
r($tester->task->batchComputeProgress($taskList)) && p('1:progress') && e('0'); // 测试任务消耗工时为0,剩余工时为0的情况
|
||||
r($tester->task->batchComputeProgress($taskList)) && p('2:progress') && e('100'); // 测试任务消耗工时不为0,剩余工时为0的情况
|
||||
r($tester->task->batchComputeProgress($taskList)) && p('3:progress') && e('94'); // 测试任务消耗工时为15,剩余工时为1的情况
|
||||
r($tester->task->batchComputeProgress($taskList)) && p('4:progress') && e('80'); // 测试任务消耗工时为20,剩余工时为5的情况
|
||||
r($tester->task->batchComputeProgress($taskList)) && p('5:progress') && e('71'); // 测试任务消耗工时为25,剩余工时为10的情况
|
||||
Executable
+42
@@ -0,0 +1,42 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/task.class.php';
|
||||
|
||||
$task = zdTable('task');
|
||||
$task->id->range('1-9');
|
||||
$task->name->setFields(array(
|
||||
array('field' => 'name1', 'range' => '父任务{3},子任务{3},普通任务{3}'),
|
||||
array('field' => 'name2', 'range' => '1-9')
|
||||
));
|
||||
$task->parent->range('`-1`{3},,1{2},2,0{3}');
|
||||
$task->status->range('doing,closed,wait{2},doing{3},wait{2}');
|
||||
$task->closedBy->range('[],admin,[]{7}');
|
||||
|
||||
$task->gen(9);
|
||||
su('admin');
|
||||
|
||||
/**
|
||||
|
||||
title=taskModel->buildTaskTree();
|
||||
timeout=0
|
||||
cid=1
|
||||
|
||||
*/
|
||||
|
||||
$taskTester = new taskTest();
|
||||
$allTaskIdList = range(1, 9);
|
||||
$notParentTaskIdList = range(4, 9);
|
||||
|
||||
$emptyData = $taskTester->buildTaskTreeTest(array());
|
||||
$allTasks = $taskTester->buildTaskTreeTest($allTaskIdList);
|
||||
$notParentTasks = $taskTester->buildTaskTreeTest($notParentTaskIdList);
|
||||
$parentTask = current($allTasks);
|
||||
$allTasksCount = count($allTasks);
|
||||
$notParentTasksCount = count($notParentTasks);
|
||||
|
||||
r($emptyData) && p() && e('0'); // 测试空数据的情况
|
||||
r($allTasksCount) && p() && e('6'); // 测试数据中有父任务时,重构结构后的任务数量
|
||||
r($parentTask->children) && p('4:name') && e('子任务4'); // 测试数据中有父任务时,重构结构后子任务的数据
|
||||
r($notParentTasksCount) && p() && e('6'); // 测试数据中没有父任务时,重构结构后的任务数量
|
||||
r($notParentTasks) && p('4:parentName') && e('父任务1'); // 测试数据中没有父任务时,重构结构后的子任务中父任务的名称
|
||||
@@ -1,35 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
|
||||
function initData()
|
||||
{
|
||||
$task = zdTable('task');
|
||||
$task->id->range('1-5');
|
||||
$task->name->prefix('任务')->range('1-5');
|
||||
$task->consumed->range('0,10,15,20,25');
|
||||
$task->left->range('0,0,1,5,10');
|
||||
|
||||
$task->gen(5);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
title=测试computeTasksProgress
|
||||
timeout=0
|
||||
cid=2
|
||||
|
||||
|
||||
*/
|
||||
$tester->loadModel('task');
|
||||
|
||||
initData();
|
||||
|
||||
$taskIDList = range(1,5);
|
||||
$taskList = $tester->task->getByList($taskIDList);
|
||||
|
||||
r($tester->task->computeTasksProgress($taskList)) && p('1:progress') && e('0'); //测试任务消耗工时为0,剩余工时为0的情况
|
||||
r($tester->task->computeTasksProgress($taskList)) && p('2:progress') && e('100'); //测试任务消耗工时不为0,剩余工时为0的情况
|
||||
r($tester->task->computeTasksProgress($taskList)) && p('3:progress') && e('94'); //测试任务消耗工时为15,剩余工时为1的情况
|
||||
r($tester->task->computeTasksProgress($taskList)) && p('4:progress') && e('80'); //测试任务消耗工时为20,剩余工时为5的情况
|
||||
r($tester->task->computeTasksProgress($taskList)) && p('5:progress') && e('71'); //测试任务消耗工时为25,剩余工时为10的情况
|
||||
@@ -611,9 +611,9 @@ class taskTest
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getStoryTasksTest($storyID, $count)
|
||||
public function getListByStoryTest($storyID, $count)
|
||||
{
|
||||
$object = $this->objectModel->getStoryTasks($storyID);
|
||||
$object = $this->objectModel->getListByStory($storyID);
|
||||
if(dao::isError())
|
||||
{
|
||||
$error = dao::getError();
|
||||
@@ -1548,11 +1548,20 @@ class taskTest
|
||||
* @access public
|
||||
* @return object[]
|
||||
*/
|
||||
public function restructureHierarchyTest(array $taskIdList): array
|
||||
public function buildTaskTreeTest(array $taskIdList): array
|
||||
{
|
||||
$tasks = array();
|
||||
if(!empty($taskIdList)) $tasks = $this->objectModel->getByList($taskIdList);
|
||||
return $this->objectModel->restructureHierarchy($tasks);
|
||||
|
||||
$parentIdList = array();
|
||||
foreach($tasks as $task)
|
||||
{
|
||||
if($task->parent <= 0 or isset($tasks[$task->parent]) or isset($parentIdList[$task->parent])) continue;
|
||||
$parentIdList[$task->parent] = $task->parent;
|
||||
}
|
||||
$parentTasks = $this->objectModel->getByList($parentIdList);
|
||||
|
||||
return $this->objectModel->buildTaskTree($tasks, $parentTasks);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -22,6 +22,16 @@ $config->todo->create->form['uid'] = array('required' => false, 'type'
|
||||
$config->todo->edit->form = array();
|
||||
$config->todo->edit->form['name'] = array('required' => true, 'type' => 'string');
|
||||
|
||||
$config->todo->assignTo = new stdClass();
|
||||
$config->todo->assignTo->form = array();
|
||||
$config->todo->assignTo->form['assignedBy'] = array('required' => false, 'type' => 'string', 'default' => '');
|
||||
$config->todo->assignTo->form['assignedDate'] = array('required' => false, 'type' => 'string', 'default' => helper::now());
|
||||
$config->todo->assignTo->form['date'] = array('required' => false, 'type' => 'string', 'default' => '');
|
||||
$config->todo->assignTo->form['begin'] = array('required' => false, 'type' => 'int', 'default' => 0);
|
||||
$config->todo->assignTo->form['end'] = array('required' => false, 'type' => 'int', 'default' => 0);
|
||||
|
||||
$config->todo->assignTo->form['assignedTo'] = array('required' => true, 'type' => 'string');
|
||||
|
||||
$config->todo->batchClose = new stdclass;
|
||||
$config->todo->batchClose->form = array();
|
||||
$config->todo->batchClose->form['todoIDList'] = array('required' => true, 'type' => 'array');
|
||||
|
||||
+72
-64
@@ -43,10 +43,8 @@ class todo extends control
|
||||
|
||||
if(!empty($_POST))
|
||||
{
|
||||
$todo = form::data($this->config->todo->create->form)
|
||||
->remove(implode(',', $this->config->todo->moduleList) . ',uid')
|
||||
->stripTags($this->config->todo->editor->create['id'], $this->config->allowedTags)
|
||||
->get();
|
||||
$formData = form::data($this->config->todo->create->form);
|
||||
$todo = $this->todoZen->beforeCreate($formData);
|
||||
|
||||
$todoID = $this->todo->create($todo);
|
||||
if($todoID === false) return print(js::error(dao::getError()));
|
||||
@@ -139,10 +137,11 @@ class todo extends control
|
||||
*/
|
||||
public function edit(string $todoID)
|
||||
{
|
||||
$todoID = (int)$todoID;
|
||||
|
||||
if(!empty($_POST))
|
||||
{
|
||||
$formData = form::data($this->config->todo->edit->form);
|
||||
$todoID = (int)$todoID;
|
||||
|
||||
$todo = $this->todoZen->beforeEdit($todoID, $formData);
|
||||
if(dao::isError())
|
||||
@@ -288,7 +287,7 @@ class todo extends control
|
||||
}
|
||||
|
||||
/**
|
||||
* 开启一个待办事项
|
||||
* 开启待办事项
|
||||
* Start a todo.
|
||||
*
|
||||
* @param string $todoID
|
||||
@@ -298,7 +297,7 @@ class todo extends control
|
||||
public function start(string $todoID)
|
||||
{
|
||||
$todoID = (int)$todoID;
|
||||
$todo = $this->todo->getById($todoID);
|
||||
$todo = $this->todo->getByID($todoID);
|
||||
|
||||
if($todo->status == 'wait') $this->todo->start($todoID);
|
||||
if(in_array($todo->type, array('bug', 'task', 'story'))) return $this->todoZen->printConfirm($todo);
|
||||
@@ -309,7 +308,7 @@ class todo extends control
|
||||
|
||||
/**
|
||||
* 激活待办事项
|
||||
* Activated todo.
|
||||
* Activated a todo.
|
||||
*
|
||||
* @param string $todoID
|
||||
* @access public
|
||||
@@ -318,7 +317,7 @@ class todo extends control
|
||||
public function activate(string $todoID)
|
||||
{
|
||||
$todoID = (int)$todoID;
|
||||
$todo = $this->todo->getById($todoID);
|
||||
$todo = $this->todo->getByID($todoID);
|
||||
|
||||
if($todo->status == 'done' or $todo->status == 'closed') $this->todo->activate($todoID);
|
||||
if(defined('RUN_MODE') && RUN_MODE == 'api') return $this->send(array('status' => 'success'));
|
||||
@@ -344,115 +343,112 @@ class todo extends control
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign.
|
||||
*
|
||||
* @param $todoID
|
||||
* 指派待办.
|
||||
* Assign todo.
|
||||
*
|
||||
* @param string $todoID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function assignTo($todoID)
|
||||
public function assignTo(string $todoID)
|
||||
{
|
||||
if(!empty($_POST))
|
||||
{
|
||||
if(empty($_POST['assignedTo'])) return print(js::error($this->lang->todo->noAssignedTo));
|
||||
$this->todo->assignTo($todoID);
|
||||
if(dao::isError()) return print(js::error(dao::getError()));
|
||||
$formData = form::data($this->config->todo->assignTo->form);
|
||||
$todo = $this->todoZen->beforeAssignTo($formData);
|
||||
|
||||
$todo->id = (int)$todoID;
|
||||
$res = $this->todoZen->doAssignTo($todo);
|
||||
if(!$res) return print(js::error(dao::getError()));
|
||||
|
||||
return print(js::reload('parent.parent'));
|
||||
}
|
||||
|
||||
$this->view->todo = $this->todo->getById($todoID);
|
||||
$this->view->todo = $this->todo->getById((int)$todoID);
|
||||
$this->view->members = $this->loadModel('user')->getPairs('noclosed|noempty|nodeleted');
|
||||
$this->view->times = date::buildTimeList($this->config->todo->times->begin, $this->config->todo->times->end, $this->config->todo->times->delta);
|
||||
$this->view->actions = $this->loadModel('action')->getList('todo', $todoID);
|
||||
$this->view->actions = $this->loadModel('action')->getList('todo', (int)$todoID);
|
||||
$this->view->users = $this->user->getPairs('noletter');
|
||||
$this->view->time = date::now();
|
||||
$this->display();
|
||||
}
|
||||
|
||||
/**
|
||||
* View a todo.
|
||||
* 获取待办的信息.
|
||||
* Get info of todo .
|
||||
*
|
||||
* @param int $todoID
|
||||
* @param string $from my|company
|
||||
* @param string $todoID
|
||||
* @param string $from my|company
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function view($todoID, $from = 'company')
|
||||
public function view(string $todoID,string $from = 'company')
|
||||
{
|
||||
$todo = $this->todo->getById($todoID, true);
|
||||
$todo = $this->todo->getById((int)$todoID, true);
|
||||
|
||||
if(!$todo)
|
||||
{
|
||||
if((defined('RUN_MODE') && RUN_MODE == 'api') or $this->app->viewType == 'json') return $this->send(array('status' => 'fail', 'message' => '404 Not found'));
|
||||
return print(js::error($this->lang->notFound) . js::locate('back'));
|
||||
return print(js::error((string)$this->lang->notFound) . (string)js::locate('back'));
|
||||
}
|
||||
|
||||
if($todo->private and $todo->account != $this->app->user->account)
|
||||
{
|
||||
return print(js::error($this->lang->todo->thisIsPrivate) . js::locate('back'));
|
||||
}
|
||||
$account = $this->app->user->account;
|
||||
if($todo->private and $todo->account != $account) return print(js::error((string)$this->lang->todo->thisIsPrivate) . (string)js::locate('back'));
|
||||
|
||||
/* Save the session. */
|
||||
if(!isonlybody())
|
||||
{
|
||||
$uri = $this->app->getURI(true);
|
||||
$this->session->set('bugList', $uri, 'qa');
|
||||
$this->session->set('taskList', $uri, 'execution');
|
||||
$this->session->set('storyList', $uri, 'product');
|
||||
$this->session->set('testtaskList', $uri, 'qa');
|
||||
$url = $this->app->getURI(true);
|
||||
$this->session->set('bugList', $url, 'qa');
|
||||
$this->session->set('taskList', $url, 'execution');
|
||||
$this->session->set('storyList', $url, 'product');
|
||||
$this->session->set('testtaskList', $url, 'qa');
|
||||
}
|
||||
|
||||
/* Fix bug #936. */
|
||||
$account = $this->app->user->account;
|
||||
if($account != $todo->account and $account != $todo->assignedTo and !common::hasPriv('my', 'team'))
|
||||
{
|
||||
$this->locate($this->createLink('user', 'deny', "module=my&method=team"));
|
||||
}
|
||||
|
||||
$this->loadModel('user');
|
||||
$projects = $this->todoZen->getProjectPairsByModel((string)$todo->type);
|
||||
if(!isset($this->session->project)) $this->session->set('project', (int)key($projects));
|
||||
|
||||
$model = $todo->type == 'opportunity' ? 'waterfall' : 'all';
|
||||
$projects = $this->loadModel('project')->getPairsByModel($model);
|
||||
if(!isset($this->session->project)) $this->session->set('project', key($projects));
|
||||
|
||||
$this->view->title = $this->app->user->account == $todo->account ? "{$this->lang->todo->common} #$todo->id $todo->name" : $this->lang->todo->common ;
|
||||
$this->view->title = $account == $todo->account ? "{$this->lang->todo->common} #$todo->id $todo->name" : $this->lang->todo->common;
|
||||
$this->view->position[] = $this->lang->todo->view;
|
||||
$this->view->todo = $todo;
|
||||
$this->view->times = date::buildTimeList($this->config->todo->times->begin, $this->config->todo->times->end, 5);
|
||||
$this->view->users = $this->user->getPairs('noletter');
|
||||
$this->view->user = $this->user->getById($todo->account);
|
||||
$this->view->actions = $this->loadModel('action')->getList('todo', $todoID);
|
||||
$this->view->times = date::buildTimeList((int)$this->config->todo->times->begin, (int)$this->config->todo->times->end, 5);
|
||||
$this->view->from = $from;
|
||||
$this->view->projects = $projects;
|
||||
$this->view->executions = $this->loadModel('execution')->getPairs();
|
||||
$this->view->products = $todo->type == 'opportunity' ? $this->loadModel('product')->getPairsByProjectModel('waterfall') : $this->loadModel('product')->getPairs();
|
||||
$this->view->projectProducts = $this->loadModel('product')->getProductPairsByProject($this->session->project);
|
||||
|
||||
$this->todoZen->buildAssignToTodo((object)$todo, (int)$this->session->project);
|
||||
$this->display();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除待办.
|
||||
* Delete a todo.
|
||||
*
|
||||
* @param int $todoID
|
||||
* @param string $confirm yes|no
|
||||
* @param string $todoID
|
||||
* @param string $confirm yes|no
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function delete($todoID, $confirm = 'no')
|
||||
public function delete(string $todoID, string $confirm = 'no')
|
||||
{
|
||||
if($confirm == 'no')
|
||||
{
|
||||
return print(js::confirm($this->lang->todo->confirmDelete, $this->createLink('todo', 'delete', "todoID=$todoID&confirm=yes")));
|
||||
return print(js::confirm($this->lang->todo->confirmDelete, $this->createLink('todo', 'delete', "todoID=(int)$todoID&confirm=yes")));
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->todo->delete(TABLE_TODO, $todoID);
|
||||
$this->todo->delete(TABLE_TODO, (int)$todoID);
|
||||
|
||||
/* if ajax request, send result. */
|
||||
if($this->server->ajax)
|
||||
{
|
||||
$response = array();
|
||||
if(dao::isError())
|
||||
{
|
||||
$response['result'] = 'fail';
|
||||
@@ -475,16 +471,18 @@ class todo extends control
|
||||
}
|
||||
|
||||
/**
|
||||
* 完成待办.
|
||||
* Finish a todo.
|
||||
*
|
||||
* @param int $todoID
|
||||
* @param string $todoID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function finish($todoID)
|
||||
public function finish(string $todoID)
|
||||
{
|
||||
$todo = $this->todo->getById($todoID);
|
||||
if($todo->status != 'done' && $todo->status != 'closed') $this->todo->finish($todoID);
|
||||
$todo = $this->todo->getById((int)$todoID);
|
||||
if($todo->status != 'done' && $todo->status != 'closed') $this->todo->finish((int)$todoID);
|
||||
|
||||
if(in_array($todo->type, array('bug', 'task', 'story')))
|
||||
{
|
||||
$confirmNote = 'confirm' . ucfirst($todo->type);
|
||||
@@ -497,12 +495,14 @@ class todo extends control
|
||||
if(defined('RUN_MODE') && RUN_MODE == 'api') return $this->send(array('status' => 'success', 'message' => sprintf($this->lang->todo->$confirmNote, $todo->objectID), 'locate' => $confirmURL));
|
||||
return print(strpos($cancelURL, 'calendar') ? json_encode(array(sprintf($this->lang->todo->$confirmNote, $todo->objectID), $confirmURL)) : js::confirm(sprintf($this->lang->todo->$confirmNote, $todo->objectID), $confirmURL, $cancelURL, $okTarget, 'parent', $app));
|
||||
}
|
||||
|
||||
if(defined('RUN_MODE') && RUN_MODE == 'api') return $this->send(array('status' => 'success'));
|
||||
if(isonlybody()) return print(js::reload('parent.parent'));
|
||||
echo js::reload('parent');
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量完成待办.
|
||||
* Batch finish todos.
|
||||
*
|
||||
* @access public
|
||||
@@ -510,13 +510,17 @@ class todo extends control
|
||||
*/
|
||||
public function batchFinish()
|
||||
{
|
||||
if(!empty($_POST['todoIDList']))
|
||||
if($this->post->todoIDList)
|
||||
{
|
||||
foreach($_POST['todoIDList'] as $todoID)
|
||||
$todoList = $this->todo->getByList((array)$this->post->todoIDList);
|
||||
foreach($todoList as $todoID => $todo)
|
||||
{
|
||||
$todo = $this->todo->getById($todoID);
|
||||
if($todo->status != 'done' && $todo->status != 'closed') $this->todo->finish($todoID);
|
||||
if($todo->status == 'done' || $todo->status == 'closed') unset($todoList[$todoID]);
|
||||
}
|
||||
|
||||
$res = $this->todo->batchFinish((array)array_keys($todoList));
|
||||
if(!$res) return false;
|
||||
|
||||
return print(js::reload('parent'));
|
||||
}
|
||||
}
|
||||
@@ -544,17 +548,21 @@ class todo extends control
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改选中待办的日期。
|
||||
* Import selected todoes to today.
|
||||
*
|
||||
* @param string $todoID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function import2Today($todoID = 0)
|
||||
public function import2Today(string $todoID = '')
|
||||
{
|
||||
$todoIDList = $_POST ? $this->post->todoIDList : array($todoID);
|
||||
$date = !empty($_POST['date']) ? $_POST['date'] : date::today();
|
||||
$this->dao->update(TABLE_TODO)->set('date')->eq($date)->where('id')->in($todoIDList)->exec();
|
||||
$this->locate($this->session->todoList);
|
||||
$date = !empty($_POST['date']) ? $_POST['date'] : date::today();
|
||||
if(!$date || !$todoIDList) $this->locate((string)$this->session->todoList);
|
||||
|
||||
$this->todo->editDate((array)$todoIDList, (string)$date);
|
||||
$this->locate((string)$this->session->todoList);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+91
-48
@@ -17,12 +17,12 @@ class todoModel extends model
|
||||
* Create todo data.
|
||||
*
|
||||
* @param object $todo
|
||||
* @access public
|
||||
* @return int|false
|
||||
*/
|
||||
public function create(object $todo): int|false
|
||||
{
|
||||
/* 处理 $todo 信息 */
|
||||
$processedTodo = $this->todoTao->beforeCreate($todo);
|
||||
$processedTodo = $this->todoTao->processCreateData($todo);
|
||||
if(!$processedTodo) return false;
|
||||
|
||||
$todoID = $this->todoTao->insert($processedTodo);
|
||||
@@ -230,8 +230,8 @@ class todoModel extends model
|
||||
}
|
||||
|
||||
/**
|
||||
* 开启一个待办事项
|
||||
* Start one todo.
|
||||
* 开启待办事项
|
||||
* Start a todo.
|
||||
*
|
||||
* @param int $todoID
|
||||
* @access public
|
||||
@@ -247,48 +247,51 @@ class todoModel extends model
|
||||
|
||||
|
||||
/**
|
||||
* Change the status of a todo.
|
||||
* 完成待办
|
||||
* Finish todo.
|
||||
*
|
||||
* @param string $todoID
|
||||
* @param string $status
|
||||
* @param int $todoID
|
||||
* @access public
|
||||
* @return void
|
||||
* @return bool
|
||||
*/
|
||||
public function finish($todoID)
|
||||
public function finish(int $todoID): bool
|
||||
{
|
||||
$this->dao->update(TABLE_TODO)
|
||||
->set('status')->eq('done')
|
||||
->set('finishedBy')->eq($this->app->user->account)
|
||||
->set('finishedDate')->eq(helper::now())
|
||||
->where('id')->eq((int)$todoID)
|
||||
->exec();
|
||||
if(!dao::isError())
|
||||
{
|
||||
$this->loadModel('action')->create('todo', $todoID, 'finished', '', 'done');
|
||||
|
||||
if(($this->config->edition == 'biz' || $this->config->edition == 'max'))
|
||||
{
|
||||
$feedbackID = $this->dao->select('objectID')->from(TABLE_TODO)->where('id')->eq($todoID)->andWhere('type')->eq('feedback')->fetch('objectID');
|
||||
if($feedbackID) $this->loadModel('feedback')->updateStatus('todo', $feedbackID, 'done');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return $this->dealFinishData($todoID);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量完成待办.
|
||||
* Batch finish todo.
|
||||
*
|
||||
* @param int[] $todoIDList
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function batchFinish(array $todoIDList): bool
|
||||
{
|
||||
foreach($todoIDList as $todoID)
|
||||
{
|
||||
$res = $this->dealFinishData($todoID);
|
||||
if(!$res) return $res;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取待办事项详情数据
|
||||
* Get info of a todo.
|
||||
*
|
||||
* @param int $todoID
|
||||
* @param bool $setImgSize
|
||||
* @param bool $setImgSize true|false
|
||||
* @access public
|
||||
* @return object|bool
|
||||
* @return object|false
|
||||
*/
|
||||
public function getById($todoID, $setImgSize = false)
|
||||
public function getByID(int $todoID, $setImgSize = false): object|false
|
||||
{
|
||||
$todo = $this->dao->findById((int)$todoID)->from(TABLE_TODO)->fetch();
|
||||
$todo = $this->dao->findById($todoID)->from(TABLE_TODO)->fetch();
|
||||
if(!$todo) return false;
|
||||
$todo = $this->loadModel('file')->replaceImgURL($todo, 'desc');
|
||||
|
||||
$todo = $this->loadModel('file')->replaceImgURL((object)$todo, 'desc');
|
||||
if($setImgSize) $todo->desc = $this->file->setImgSize($todo->desc);
|
||||
if($todo->type == 'story') $todo->name = $this->dao->findById($todo->objectID)->from(TABLE_STORY)->fetch('title');
|
||||
if($todo->type == 'task') $todo->name = $this->dao->findById($todo->objectID)->from(TABLE_TASK)->fetch('name');
|
||||
@@ -300,6 +303,7 @@ class todoModel extends model
|
||||
if($todo->type == 'testtask') $todo->name = $this->dao->findById($todo->objectID)->from(TABLE_TESTTASK)->fetch('name');
|
||||
if($todo->type == 'feedback') $todo->name = $this->dao->findById($todo->objectID)->from(TABLE_FEEDBACK)->fetch('title');
|
||||
$todo->date = str_replace('-', '', $todo->date);
|
||||
|
||||
return $todo;
|
||||
}
|
||||
|
||||
@@ -511,8 +515,8 @@ class todoModel extends model
|
||||
|
||||
if(!$date) continue;
|
||||
if($date < $todo->config->begin) continue;
|
||||
if($date < date('Y-m-d')) continue;
|
||||
if($date > date('Y-m-d', $finish)) continue;
|
||||
if($date < date('Y-m-d')) continue;
|
||||
if($date > date('Y-m-d', $finish)) continue;
|
||||
if(!empty($end) && $date > $end) continue;
|
||||
if($lastCycle and ($date == $lastCycle->date)) continue;
|
||||
|
||||
@@ -526,7 +530,7 @@ class todoModel extends model
|
||||
|
||||
/**
|
||||
* 激活待办事项
|
||||
* Activate todo.
|
||||
* Activated a todo.
|
||||
*
|
||||
* @param int $todoID
|
||||
* @access public
|
||||
@@ -536,6 +540,7 @@ class todoModel extends model
|
||||
{
|
||||
$this->dao->update(TABLE_TODO)->set('status')->eq('wait')->where('id')->eq($todoID)->exec();
|
||||
$this->loadModel('action')->create('todo', $todoID, 'activated', '', 'wait');
|
||||
|
||||
return !dao::isError();
|
||||
}
|
||||
|
||||
@@ -555,7 +560,7 @@ class todoModel extends model
|
||||
{
|
||||
$this->loadModel('action')->create('todo', $todoID, 'closed', '', 'closed');
|
||||
|
||||
if(($this->config->edition == 'biz' || $this->config->edition == 'max'))
|
||||
if($this->config->edition == 'biz' || $this->config->edition == 'max')
|
||||
{
|
||||
$feedbackID = $this->dao->select('objectID')->from(TABLE_TODO)->where('id')->eq($todoID)->andWhere('type')->eq('feedback')->fetch('objectID');
|
||||
if($feedbackID) $this->loadModel('feedback')->updateStatus('todo', $feedbackID, 'closed');
|
||||
@@ -566,25 +571,19 @@ class todoModel extends model
|
||||
}
|
||||
|
||||
/**
|
||||
* 指派待办.
|
||||
* Assign todo.
|
||||
*
|
||||
* @param int $todoID
|
||||
* @param object $todo
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function assignTo($todoID)
|
||||
public function assignTo(object $todo): bool
|
||||
{
|
||||
$todo = fixer::input('post')
|
||||
->add('assignedBy', $this->app->user->account)
|
||||
->add('assignedDate', helper::now())
|
||||
->setIF(isset($_POST['future']), 'date', '2030-01-01')
|
||||
->setIF(isset($_POST['lblDisableDate']), 'begin', '2400')
|
||||
->setIF(isset($_POST['lblDisableDate']), 'end', '2400')
|
||||
->remove('future,lblDisableDate')
|
||||
->get();
|
||||
$res = $this->todoTao->updateRow((int)$todo->id, $todo);
|
||||
if(!$res) return false;
|
||||
|
||||
$this->dao->update(TABLE_TODO)->data($todo)->where('id')->eq((int)$todoID)->exec();
|
||||
$this->loadModel('action')->create('todo', $todoID, 'assigned', '', $todo->assignedTo);
|
||||
$this->loadModel('action')->create('todo', (int)$todo->id, 'assigned', '', $todo->assignedTo);
|
||||
return !dao::isError();
|
||||
}
|
||||
|
||||
@@ -640,4 +639,48 @@ class todoModel extends model
|
||||
|
||||
return $projectIdList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理完成待办数据.
|
||||
* Deal finish todo data.
|
||||
*
|
||||
* @param int $todoID
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
private function dealFinishData(int $todoID): bool
|
||||
{
|
||||
$todo = new stdClass();
|
||||
$todo->id = $todoID;
|
||||
$todo->status = 'done';
|
||||
$todo->finishedBy = $this->app->user->account;
|
||||
$this->todoTao->updateRow($todoID, $todo);
|
||||
|
||||
if(!dao::isError())
|
||||
{
|
||||
$this->loadModel('action')->create('todo', $todoID, 'finished', '', 'done');
|
||||
|
||||
if(($this->config->edition == 'biz' || $this->config->edition == 'max'))
|
||||
{
|
||||
$todo = $this->todoTao->fetch($todoID);
|
||||
$feedbackID = $todo->idvalue ?? '' ;
|
||||
if($feedbackID) $this->loadModel('feedback')->updateStatus('todo', $feedbackID, 'done');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** 修改待办事项的时间。
|
||||
* Edit the date of todo.
|
||||
*
|
||||
* @param array $idList
|
||||
* @param string $date
|
||||
* @access public
|
||||
* @return int
|
||||
*/
|
||||
public function editDate(array $todoIDList, string $date): int
|
||||
{
|
||||
return $this->todoTao->updateDate((array)$todoIDList, (string)$date);
|
||||
}
|
||||
}
|
||||
|
||||
+48
-22
@@ -3,11 +3,25 @@ declare(strict_types=1);
|
||||
|
||||
class todoTao extends todoModel
|
||||
{
|
||||
/**
|
||||
* Get a todo.
|
||||
* 获取单条待办.
|
||||
*
|
||||
* @param int $todoID
|
||||
* @param object $todo
|
||||
* @return object
|
||||
*/
|
||||
protected function fetch(int $todoID): object
|
||||
{
|
||||
return $this->dao->select('*')->from(TABLE_TODO)->where('id')->eq($todoID)->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* 插入待办数据
|
||||
* Insert todo data.
|
||||
*
|
||||
* @param object $todo
|
||||
* @access protected
|
||||
* @return int
|
||||
*/
|
||||
protected function insert(object $todo): int
|
||||
@@ -27,6 +41,7 @@ class todoTao extends todoModel
|
||||
*
|
||||
* @param int $todoID
|
||||
* @param object $todo
|
||||
* @access protected
|
||||
* @return bool
|
||||
*/
|
||||
protected function updateRow(int $todoID, object $todo): bool
|
||||
@@ -45,6 +60,7 @@ class todoTao extends todoModel
|
||||
* Close one todo.
|
||||
*
|
||||
* @param int $todoID
|
||||
* @access protected
|
||||
* @return bool
|
||||
*/
|
||||
protected function closeTodo(int $todoID): bool
|
||||
@@ -64,25 +80,14 @@ class todoTao extends todoModel
|
||||
|
||||
/*
|
||||
* 处理要创建的todo的数据
|
||||
* Processing todo data.
|
||||
* Process the data for the todo to be created.
|
||||
*
|
||||
* @param object $todoData
|
||||
* @access protected
|
||||
* @return object|false
|
||||
*/
|
||||
protected function beforeCreate(object $todoData): object|false
|
||||
protected function processCreateData(object $todoData): object|false
|
||||
{
|
||||
$objectID = 0;
|
||||
$hasObject = in_array($todoData->type, $this->config->todo->moduleList);
|
||||
if($hasObject && $todoData->type) $objectID = $todoData->uid ? $todoData->type : $todoData->objectID;
|
||||
|
||||
$todoData->account = $this->app->user->account;
|
||||
$todoData->assignedTo = zget($todoData, 'assignedTo', $this->app->user->account);
|
||||
$todoData->assignedBy = zget($todoData, 'assignedBy', $this->app->user->account);
|
||||
|
||||
if($hasObject && $todoData->type) $todoData->objectID = $objectID;
|
||||
if($todoData->status == 'done') $todoData->finishedBy = $this->app->user->account;
|
||||
if($todoData->status == 'done') $todoData->finishedDate = helper::now();
|
||||
|
||||
if(!isset($todoData->pri) and in_array($todoData->type, $this->config->todo->moduleList) and !in_array($todoData->type, array('review', 'feedback')))
|
||||
{
|
||||
$todoData->pri = $this->dao->select('pri')->from($this->config->objectTables[$todoData->type])->where('id')->eq($todoData->objectID)->fetch('pri');
|
||||
@@ -108,7 +113,6 @@ class todoTao extends todoModel
|
||||
|
||||
if(!empty($todoData->cycle))
|
||||
{
|
||||
/* TODO confirmation. */
|
||||
$todoData = $this->setCycle($todoData);
|
||||
if(!$todoData) return false;
|
||||
}
|
||||
@@ -123,6 +127,7 @@ class todoTao extends todoModel
|
||||
* Get cycle list.
|
||||
* @param array $todoList
|
||||
* @param string $orderBy
|
||||
* @access protected
|
||||
* @return array
|
||||
*/
|
||||
protected function getCycleList(array $todoList, string $orderBy = 'date_asc'): array
|
||||
@@ -140,6 +145,7 @@ class todoTao extends todoModel
|
||||
* 通过待办构建周期待办数据
|
||||
* Build cycle todo.
|
||||
* @param object $todo
|
||||
* @access protected
|
||||
* @return stdclass
|
||||
*/
|
||||
protected function buildCycleTodo(object $todo): object
|
||||
@@ -163,13 +169,15 @@ class todoTao extends todoModel
|
||||
|
||||
/**
|
||||
* 通过周期待办,获取要生成待办的日期
|
||||
*
|
||||
* Gets the date by the cycle todo.
|
||||
* @param object $todo
|
||||
* @param object $lastCycle
|
||||
* @param string $today
|
||||
* @param object $todo
|
||||
* @param object|string $lastCycle
|
||||
* @param string $today
|
||||
* @access protected
|
||||
* @return false|string
|
||||
*/
|
||||
protected function getCycleTodoDate(object $todo, object $lastCycle, string $today): false|string
|
||||
protected function getCycleTodoDate(object $todo, object|string $lastCycle, string $today): false|string
|
||||
{
|
||||
$date = '';
|
||||
if($todo->config->type == 'day')
|
||||
@@ -200,13 +208,16 @@ class todoTao extends todoModel
|
||||
|
||||
/**
|
||||
* 通过周期待办,获取要生成每日待办的日期
|
||||
*
|
||||
* Gets the daily todo date by the cycle todo.
|
||||
*
|
||||
* @param object $todo
|
||||
* @param object $lastCycle
|
||||
* @param object|string $lastCycle
|
||||
* @param string $today
|
||||
* @access protected
|
||||
* @return false|string
|
||||
*/
|
||||
private function getCycleDailyTodoDate(object $todo, object $lastCycle, string $today): false|string
|
||||
private function getCycleDailyTodoDate(object $todo, object|string $lastCycle, string $today): false|string
|
||||
{
|
||||
$date = '';
|
||||
if(isset($todo->config->day))
|
||||
@@ -251,10 +262,11 @@ class todoTao extends todoModel
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置周期待办数据
|
||||
* Set cycle todo data.
|
||||
* 设置周期待办数据
|
||||
*
|
||||
* @param object $todoData
|
||||
* @access private
|
||||
* @return false|object
|
||||
*/
|
||||
private function setCycle(object $todoData): false|object
|
||||
@@ -298,4 +310,18 @@ class todoTao extends todoModel
|
||||
|
||||
return $todoData;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改待办事项的时间。
|
||||
* Update the date of todo.
|
||||
*
|
||||
* @param array $idList
|
||||
* @param string $date
|
||||
* @return int
|
||||
*/
|
||||
protected function updateDate(array $todoIdList, string $date): int
|
||||
{
|
||||
$this->dao->update(TABLE_TODO)->set('date')->eq($date)->where('id')->in($todoIdList)->exec();
|
||||
return dao::isError() ? 0 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ function initData()
|
||||
$todo = zdTable('todo');
|
||||
$todo->id->range('1-3');
|
||||
$todo->account->prefix('admin')->range('1-3');
|
||||
$todo->date->range('20230102 000000:0')->type('timestamp')->format('YY/MM/DD');
|
||||
$todo->begin->range('1710');
|
||||
$todo->end->range('1740');
|
||||
$todo->feedback->range('0');
|
||||
|
||||
@@ -4,19 +4,65 @@ include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/todo.class.php';
|
||||
su('admin');
|
||||
|
||||
function initData()
|
||||
{
|
||||
$project = zdTable('todo');
|
||||
$project->id->range('1-5');
|
||||
$project->account->range('admin');
|
||||
$project->date->prefix('2023-04-2')->range('1-9');
|
||||
$project->begin->range('1000-1100');
|
||||
$project->end->range('1200-1300');
|
||||
$project->type->range("custom");
|
||||
$project->cycle->range("0");
|
||||
$project->pri->range("3");
|
||||
$project->name->prefix('我的待办')->range("1-5");
|
||||
$project->desc->prefix('这是我的描述')->range("1-5");
|
||||
$project->status->range("wait");
|
||||
|
||||
$project->gen(5);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
title=测试 todoModel->assignTo();
|
||||
timeout=0
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
指派todo 1给test1 >> test1,20300101,1000,1400
|
||||
指派todo 2给test1 >> test1,2400,2400
|
||||
指派todo 3给test1 >> test1,1002,1402
|
||||
- 执行todo模块的assignTo方法,参数是$todoIDList[0], $todo1
|
||||
- 属性assignedTo @test1
|
||||
- 属性date @20300101
|
||||
- 属性begin @1000
|
||||
- 属性end @1400
|
||||
|
||||
- 执行todo模块的assignTo方法,参数是$todoIDList[1], $todo2
|
||||
- 属性assignedTo @test1
|
||||
- 属性begin @2400
|
||||
- 属性end @2400
|
||||
|
||||
- 执行todo模块的assignTo方法,参数是$todoIDList[2], $todo3
|
||||
- 属性assignedTo @test1
|
||||
- 属性begin @1002
|
||||
- 属性end @1402
|
||||
|
||||
- 执行todo模块的assignTo方法,参数是$todoIDList[3], $todo4
|
||||
- 属性assignedTo @admin
|
||||
- 属性date @20300101
|
||||
- 属性begin @1200
|
||||
- 属性end @1502
|
||||
|
||||
- 执行todo模块的assignTo方法,参数是$todoIDList[4], $todo5
|
||||
- 属性assignedTo @admin
|
||||
- 属性date @20300101
|
||||
- 属性begin @2400
|
||||
- 属性end @2400
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
$todoIDList = array('1', '2', '3');
|
||||
initData();
|
||||
|
||||
$todoIDList = array('1', '2', '3', '4', '5');
|
||||
|
||||
$todo1 = new stdclass();
|
||||
$todo1->assignedTo = 'test1';
|
||||
@@ -33,8 +79,21 @@ $todo3->assignedTo = 'test1';
|
||||
$todo3->begin = 1002;
|
||||
$todo3->end = 1402;
|
||||
|
||||
$todo4 = new stdclass();
|
||||
$todo4->assignedTo = 'admin';
|
||||
$todo4->future = 'on';
|
||||
$todo4->begin = 1200;
|
||||
$todo4->end = 1502;
|
||||
|
||||
$todo5 = new stdclass();
|
||||
$todo5->assignedTo = 'admin';
|
||||
$todo5->future = 'on';
|
||||
$todo5->lblDisableDate = 'on';
|
||||
|
||||
$todo = new todoTest();
|
||||
|
||||
r($todo->assignToTest($todoIDList[0], $todo1)) && p('assignedTo,date,begin,end') && e('test1,20300101,1000,1400'); // 指派todo 1给test1
|
||||
r($todo->assignToTest($todoIDList[1], $todo2)) && p('assignedTo,begin,end') && e('test1,2400,2400'); // 指派todo 2给test1
|
||||
r($todo->assignToTest($todoIDList[0], $todo1)) && p('assignedTo,date,begin,end') && e('test1,20300101,1000,1400'); // 指派todo 1给test1 选择待定
|
||||
r($todo->assignToTest($todoIDList[1], $todo2)) && p('assignedTo,begin,end') && e('test1,2400,2400'); // 指派todo 2给test1 暂时不设定时间
|
||||
r($todo->assignToTest($todoIDList[2], $todo3)) && p('assignedTo,begin,end') && e('test1,1002,1402'); // 指派todo 3给test1
|
||||
r($todo->assignToTest($todoIDList[3], $todo4)) && p('assignedTo,date,begin,end') && e('admin,20300101,1200,1502'); // 指派todo 4给admin future=on 验证 date默认值
|
||||
r($todo->assignToTest($todoIDList[4], $todo5)) && p('assignedTo,date,begin,end') && e('admin,20300101,2400,2400'); // 指派todo 5给admin future=on lblDisableDate=on 验证date,begin,end默认值
|
||||
Executable
+48
@@ -0,0 +1,48 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/todo.class.php';
|
||||
su('admin');
|
||||
|
||||
function initData()
|
||||
{
|
||||
$project = zdTable('todo');
|
||||
$project->id->range('1-100');
|
||||
$project->account->range('admin');
|
||||
$project->date->prefix('2023-04-2')->range('1-9');
|
||||
$project->begin->range('1000-1100');
|
||||
$project->end->range('1200-1300');
|
||||
$project->type->range("custom");
|
||||
$project->cycle->range("0");
|
||||
$project->pri->range("3");
|
||||
$project->name->prefix('我的待办')->range("1-5");
|
||||
$project->desc->prefix('这是我的描述')->range("1-5");
|
||||
$project->status->range("wait");
|
||||
|
||||
$project->gen(10);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
title=测试批量完成待办 todoModel->batchFinish();
|
||||
timeout=0
|
||||
cid=1
|
||||
|
||||
- 执行todo模块的getById方法,参数是$todoIDList[0]属性status @done
|
||||
|
||||
- 执行todo模块的getById方法,参数是$todoIDList[1]属性status @done
|
||||
|
||||
- 执行todo模块的getById方法,参数是$todoIDList[2]属性status @done
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
$todoIDList = array('1', '2', '3');
|
||||
|
||||
$todo = new todoTest();
|
||||
$todo->batchFinishTest($todoIDList);
|
||||
|
||||
r($todo->getByIdTest($todoIDList[0])) && p('status') && e('done'); // 批量完成todo验证状态done
|
||||
r($todo->getByIdTest($todoIDList[1])) && p('status') && e('done'); // 批量完成todo验证状态done
|
||||
r($todo->getByIdTest($todoIDList[2])) && p('status') && e('done'); // 批量完成todo验证状态done
|
||||
Executable
+46
@@ -0,0 +1,46 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/todo.class.php';
|
||||
su('admin');
|
||||
|
||||
function initData()
|
||||
{
|
||||
$project = zdTable('todo');
|
||||
$project->id->range('1-100');
|
||||
$project->account->range('admin');
|
||||
$project->date->prefix('2023-04-2')->range('1-9');
|
||||
$project->begin->range('1000-1100');
|
||||
$project->end->range('1200-1300');
|
||||
$project->type->range("custom");
|
||||
$project->cycle->range("0");
|
||||
$project->pri->range("3");
|
||||
$project->name->prefix('我的待办')->range("1-5");
|
||||
$project->desc->prefix('这是我的描述')->range("1-5");
|
||||
$project->status->range("wait");
|
||||
|
||||
$project->gen(10);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
title=测试删除todo todoModel->delete();
|
||||
timeout=0
|
||||
cid=1
|
||||
|
||||
- 执行todo模块的delete方法,参数是8, no
|
||||
- 属性id @8
|
||||
- 属性deleted @0
|
||||
|
||||
- 执行todo模块的getById方法,参数是8属性deleted @1
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
initData();
|
||||
|
||||
$todo = new todoTest();
|
||||
r($todo->deleteTest(8, 'no')) && p('id,deleted') && e('8,0'); // 删除指定id的待办,取消确认
|
||||
$todo->deleteTest(8, 'yes');
|
||||
r($todo->getByIdTest(8)) && p('deleted') && e('1'); // 验证删除id不存在的todo信息
|
||||
Executable
+34
@@ -0,0 +1,34 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/todo.class.php';
|
||||
su('admin');
|
||||
|
||||
function initData()
|
||||
{
|
||||
$project = zdTable('todo');
|
||||
$project->id->range('1-5');
|
||||
$project->name->prefix("自定义的待办")->range('1-5');
|
||||
$project->type->range(1);
|
||||
$project->status->range("wait,doing,done,closed,closed");
|
||||
$project->gen(5);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
||||
title=测试 todoModel->editDateTest();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
*/
|
||||
|
||||
|
||||
global $tester;
|
||||
$tester->loadModel('todo');
|
||||
|
||||
initData();
|
||||
|
||||
r($tester->todo->editDate(array(1), '2023-06-07')) && p() && e(true); // 获取id为1的待办的日期
|
||||
r($tester->todo->editDate(array(2, 3), '2023-04-27')) && p() && e(true); // 获取id 为1,2待办的日期
|
||||
#r($tester->todo->editDate(array(9), '2023-04-17')) && p() && e('0'); // 修改不存在的待办的日期
|
||||
@@ -4,22 +4,46 @@ include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/todo.class.php';
|
||||
su('admin');
|
||||
|
||||
function initData()
|
||||
{
|
||||
$project = zdTable('todo');
|
||||
$project->id->range('1-100');
|
||||
$project->account->range('admin');
|
||||
$project->date->prefix('2023-04-2')->range('1-9');
|
||||
$project->begin->range('1000-1100');
|
||||
$project->end->range('1200-1300');
|
||||
$project->type->range("custom");
|
||||
$project->cycle->range("0");
|
||||
$project->pri->range("3");
|
||||
$project->name->prefix('我的待办')->range("1-5");
|
||||
$project->desc->prefix('这是我的描述')->range("1-5");
|
||||
$project->status->range("wait,doing,done");
|
||||
|
||||
$project->gen(10);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
title=测试 todoModel->finish();
|
||||
title=测试完成待办 todoModel->finish();
|
||||
timeout=0
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
结束一个状态为wait的todo >> done
|
||||
结束一个状态为doing的todo >> done
|
||||
结束一个状态为done的todo >> done
|
||||
- 执行todo模块的finish方法,参数是$todoIDList[0]属性status @done
|
||||
|
||||
- 执行todo模块的finish方法,参数是$todoIDList[1]属性status @done
|
||||
|
||||
- 执行todo模块的finish方法,参数是$todoIDList[2]属性status @done
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
$todoIDList = array('1', '2', '3');
|
||||
initData();
|
||||
|
||||
$todoIDList = range(1,3);
|
||||
|
||||
$todo = new todoTest();
|
||||
|
||||
r($todo->finishTest($todoIDList[0])) && p('status') && e('done'); // 结束一个状态为wait的todo
|
||||
r($todo->finishTest($todoIDList[1])) && p('status') && e('done'); // 结束一个状态为doing的todo
|
||||
r($todo->finishTest($todoIDList[2])) && p('status') && e('done'); // 结束一个状态为done的todo
|
||||
r($todo->finishTest($todoIDList[2])) && p('status') && e('done'); // 结束一个状态为done的todo
|
||||
@@ -4,26 +4,32 @@ include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/todo.class.php';
|
||||
su('admin');
|
||||
|
||||
function initData()
|
||||
{
|
||||
$project = zdTable('todo');
|
||||
$project->id->range('1-5');
|
||||
$project->name->prefix("自定义的待办")->range('1-5');
|
||||
$project->type->range(1);
|
||||
$project->status->range("wait,doing,done,closed,closed");
|
||||
$project->gen(5);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
||||
title=测试 todoModel->getById();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
获取id为1的todo信息 >> 自定义1的待办,custom,wait
|
||||
获取id为2的todo信息 >> BUG1,bug,doing
|
||||
获取id为3的todo信息 >> 开发任务12,task,done
|
||||
获取id为4的todo信息 >> 用户需求3,story,closed
|
||||
获取id不存在的todo信息 >> 0
|
||||
|
||||
*/
|
||||
|
||||
$todoIDList = array('1', '2', '3', '4', '100001');
|
||||
$todoIDList = array('1', '2', '3', '5', '100000');
|
||||
|
||||
$todo = new todoTest();
|
||||
|
||||
r($todo->getByIdTest($todoIDList[0])) && p('name,type,status') && e('自定义1的待办,custom,wait'); // 获取id为1的todo信息
|
||||
r($todo->getByIdTest($todoIDList[1])) && p('name,type,status') && e('BUG1,bug,doing'); // 获取id为2的todo信息
|
||||
r($todo->getByIdTest($todoIDList[2])) && p('name,type,status') && e('开发任务12,task,done'); // 获取id为3的todo信息
|
||||
r($todo->getByIdTest($todoIDList[3])) && p('name,type,status') && e('用户需求3,story,closed'); // 获取id为4的todo信息
|
||||
r($todo->getByIdTest($todoIDList[4])) && p('name,type,status') && e('0'); // 获取id不存在的todo信息
|
||||
initData();
|
||||
|
||||
r($todo->getByIdTest($todoIDList[0])) && p('name,status') && e('自定义的待办1,wait'); // 获取id为1的todo信息
|
||||
r($todo->getByIdTest($todoIDList[1])) && p('name,status') && e('自定义的待办2,doing'); // 获取id为2的todo信息
|
||||
r($todo->getByIdTest($todoIDList[3])) && p('name,status') && e('自定义的待办5,closed'); // 获取id为5的todo信息
|
||||
r($todo->getByIdTest($todoIDList[4])) && p() && e('0'); // 获取id不存在的todo信息
|
||||
|
||||
@@ -9,6 +9,7 @@ function initData()
|
||||
$todo = zdTable('todo');
|
||||
$todo->id->range('1-3');
|
||||
$todo->account->prefix('admin')->range('1-3');
|
||||
$todo->date->range('20230102 000000:0')->type('timestamp')->format('YY/MM/DD');
|
||||
$todo->begin->range('1710');
|
||||
$todo->end->range('1740');
|
||||
$todo->feedback->range('0');
|
||||
|
||||
@@ -167,22 +167,61 @@ class todoTest
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试删除待办.
|
||||
* Test delete a todo.
|
||||
*
|
||||
* @param int $todoID
|
||||
* @param string $confirm yes|no
|
||||
* @access public
|
||||
* @return object|false
|
||||
*/
|
||||
public function deleteTest(int $todoID, string $confirm = 'no'): object|false
|
||||
{
|
||||
if($confirm == 'no')
|
||||
{
|
||||
return $this->objectModel->getById($todoID);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->objectModel->delete(TABLE_TODO, $todoID);
|
||||
if(dao::isError()) return false;
|
||||
|
||||
return $this->objectModel->getById($todoID);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试完成待办.
|
||||
* Test finish a todo.
|
||||
*
|
||||
* @param int $todoID
|
||||
* @param int $todoID
|
||||
* @access public
|
||||
* @return object
|
||||
* @return object|false
|
||||
*/
|
||||
public function finishTest($todoID)
|
||||
public function finishTest(int $todoID): object|false
|
||||
{
|
||||
$this->objectModel->finish($todoID);
|
||||
$object = $this->objectModel->getByID($todoID);
|
||||
|
||||
if(dao::isError()) return dao::getError();
|
||||
if(dao::isError()) return false;
|
||||
|
||||
return $object;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 测试批量完成待办.
|
||||
* Batch finish todos.
|
||||
*
|
||||
* @param array $todoIDList
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function batchFinishTest(array $todoIDList): bool
|
||||
{
|
||||
return $this->objectModel->batchFinish($todoIDList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test get info of a todo.
|
||||
*
|
||||
@@ -327,24 +366,40 @@ class todoTest
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试指派待办.
|
||||
* Test assign todo.
|
||||
*
|
||||
* @param int $todoID
|
||||
* @param array $param
|
||||
* @param int $todoID
|
||||
* @param object $param
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
public function assignToTest($todoID, $param = array())
|
||||
public function assignToTest(int $todoID, object $param = new stdclass()): object
|
||||
{
|
||||
foreach($param as $key => $value) $_POST[$key] = $value;
|
||||
$todo = new stdClass();
|
||||
$todo->assignedDate = helper::now();
|
||||
$todo->date = '';
|
||||
$todo->begin = 0;
|
||||
$todo->end = 0;
|
||||
|
||||
if(!isset($_POST['future']) and !isset($_POST['date'])) $_POST['date'] = date('Y-m-d', time());
|
||||
foreach($param as $key => $value)
|
||||
{
|
||||
$todo->{$key} = $value;
|
||||
if($key == 'future' && $value == 'on')
|
||||
{
|
||||
$todo->date = '2030-01-01';
|
||||
unset($todo->{$key});
|
||||
}
|
||||
if($key == 'lblDisableDate' && $value == 'on')
|
||||
{
|
||||
$todo->begin = '2400';
|
||||
$todo->end = '2400';
|
||||
unset($todo->{$key});
|
||||
}
|
||||
}
|
||||
|
||||
$this->objectModel->assignTo($todoID);
|
||||
|
||||
unset($_POST);
|
||||
|
||||
if(dao::isError()) return dao::getError();
|
||||
$todo->id = $todoID;
|
||||
$this->objectModel->assignTo($todo);
|
||||
|
||||
$object = $this->objectModel->getById($todoID);
|
||||
return $object;
|
||||
|
||||
Executable
+87
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
namespace zin;
|
||||
/**
|
||||
* The batch create view of todo module of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.cnezsoft.com)
|
||||
* @license ZPL(http://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
|
||||
* @author Yue Liu <liuyue@easycorp.ltd>
|
||||
* @package todo
|
||||
* @version $Id: create.html.php 2741 2012-04-07 07:24:21 $
|
||||
* @link http://www.zentao.net
|
||||
*/
|
||||
|
||||
set::title($lang->todo->assignedTo);
|
||||
|
||||
formPanel
|
||||
(
|
||||
formGroup
|
||||
(
|
||||
set::name('assignedTo'),
|
||||
set::label($lang->todo->assignedTo),
|
||||
set::width('1/2'),
|
||||
set::items($members)
|
||||
),
|
||||
formRow
|
||||
(
|
||||
formGroup
|
||||
(
|
||||
set::label($lang->todo->date),
|
||||
set::width('1/2'),
|
||||
input
|
||||
(
|
||||
set::name('date'),
|
||||
set::type('date'),
|
||||
set::value(date('Y-m-d'))
|
||||
)
|
||||
),
|
||||
formGroup
|
||||
(
|
||||
set::class(array('items-center', 'pl-3')),
|
||||
checkbox
|
||||
(
|
||||
set::name('future'),
|
||||
set::text($lang->todo->periods['future']),
|
||||
on::change('switchDateTodo(this)')
|
||||
)
|
||||
)
|
||||
),
|
||||
formRow
|
||||
(
|
||||
formGroup
|
||||
(
|
||||
set::width('1/2'),
|
||||
set::label($lang->todo->beginAndEnd),
|
||||
inputGroup
|
||||
(
|
||||
select
|
||||
(
|
||||
set::name('begin'),
|
||||
set::id('begin'),
|
||||
set::items($times),
|
||||
set::value(date('Y-m-d') != $todo->date ? key($times) : $time),
|
||||
on::change('selectNext')
|
||||
),
|
||||
select
|
||||
(
|
||||
set::name('end'),
|
||||
set::id('end'),
|
||||
set::items($times)
|
||||
)
|
||||
)
|
||||
),
|
||||
formGroup
|
||||
(
|
||||
set::class(array('items-center', 'pl-3')),
|
||||
checkbox
|
||||
(
|
||||
set::name('lblDisableDate'),
|
||||
set::text($lang->todo->lblDisableDate),
|
||||
on::change('switchDateFeature(this)')
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
render();
|
||||
+100
-56
@@ -7,73 +7,44 @@ class todoZen extends todo
|
||||
* 处理请求数据
|
||||
* Processing request data.
|
||||
*
|
||||
* @process protected
|
||||
* @param object $formData
|
||||
* @return object|false
|
||||
* @access protected
|
||||
* @return object
|
||||
*/
|
||||
protected function beforeCreate(object $formData): object|bool
|
||||
protected function beforeCreate(object $formData): object
|
||||
{
|
||||
$formData = $formData->remove(implode(',', $this->config->todo->moduleList) . ',uid')->stripTags($this->config->todo->editor->create['id'], $this->config->allowedTags)->get();
|
||||
$objectType = $this->post->type;
|
||||
$hasObject = in_array($objectType, $this->config->todo->moduleList);
|
||||
|
||||
$objectID = 0;
|
||||
$hasObject = in_array($formData->type, $this->config->todo->moduleList);
|
||||
if($hasObject && $formData->type) $objectID = $formData->uid ? $formData->type : $formData->objectID;
|
||||
$objectID = 0;
|
||||
if($hasObject && $objectType) $objectID = $this->post->uid ? $this->post->$objectType : $this->post->objectID;
|
||||
|
||||
$formData->account = $this->app->user->account;
|
||||
$formData->assignedTo = zget($formData, 'assignedTo', $this->app->user->account);
|
||||
$formData->assignedBy = zget($formData, 'assignedBy', $this->app->user->account);
|
||||
if($hasObject && $formData->type) $formData->objectID = $objectID;
|
||||
if($formData->status == 'done') $formData->finishedBy = $this->app->user->account;
|
||||
if($formData->status == 'done') $formData->finishedDate = helper::now();
|
||||
|
||||
if(!isset($formData->pri) and in_array($formData->type, $this->config->todo->moduleList) and $formData->type !== 'review' and $formData->type !== 'feedback')
|
||||
{
|
||||
// TODO
|
||||
$formData->pri = $this->dao->select('pri')->from($this->config->objectTables[$formData->type])->where('id')->eq($formData->objectID)->fetch('pri');
|
||||
|
||||
if($formData->pri == 'high') $formData->pri = 1;
|
||||
if($formData->pri == 'middle') $formData->pri = 2;
|
||||
if($formData->pri == 'low') $formData->pri = 3;
|
||||
}
|
||||
|
||||
if($formData->type != 'custom' and $formData->objectID)
|
||||
{
|
||||
$type = $formData->type;
|
||||
$object = $this->loadModel($type)->getByID($formData->$type);
|
||||
if(isset($object->name)) $formData->name = $object->name;
|
||||
if(isset($object->title)) $formData->name = $object->title;
|
||||
}
|
||||
|
||||
if($formData->end < $formData->begin)
|
||||
{
|
||||
dao::$errors[] = sprintf($this->lang->error->gt, $this->lang->todo->end, $this->lang->todo->begin);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!empty($formData->cycle)) $formData = $this->setCycle($formData);
|
||||
else unset($formData->config);
|
||||
|
||||
$formData = $this->loadModel('file')->processImgURL($formData, $this->config->todo->editor->create['id'], $this->post->uid);
|
||||
|
||||
return $formData;
|
||||
$data = $formData->add('account', $this->app->user->account)
|
||||
->setDefault('objectID', 0)
|
||||
->setDefault('vision', $this->config->vision)
|
||||
->setDefault('assignedTo', $this->app->user->account)
|
||||
->setDefault('assignedBy', $this->app->user->account)
|
||||
->setDefault('assignedDate', helper::now())
|
||||
->cleanInt('pri, begin, end, private')
|
||||
->setIF($hasObject && $objectType, 'objectID', $objectID)
|
||||
->setIF($this->post->date == false, 'date', '2030-01-01')
|
||||
->setIF($this->post->begin == false, 'begin', '2400')
|
||||
->setIF($this->post->begin == false or $this->post->end == false, 'end', '2400')
|
||||
->setIF($this->post->status == 'done', 'finishedBy', $this->app->user->account)
|
||||
->setIF($this->post->status == 'done', 'finishedDate', helper::now())
|
||||
->stripTags($this->config->todo->editor->create['id'], $this->config->allowedTags)
|
||||
->remove(implode(',', $this->config->todo->moduleList) . ',uid')
|
||||
->get();
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建待办
|
||||
* Create a todo.
|
||||
*
|
||||
* @param object $todo
|
||||
* @return int|false
|
||||
*/
|
||||
protected function doCreate(object $todo): int|bool
|
||||
{
|
||||
return $this->todo->create($todo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建完成待办后数据处理
|
||||
* Create a todo after data processing
|
||||
* 创建完成待办后数据处理
|
||||
*
|
||||
* @param object $todo
|
||||
* @access protected
|
||||
* @return object
|
||||
*/
|
||||
protected function afterCreate(object $todo): object
|
||||
@@ -99,6 +70,7 @@ class todoZen extends todo
|
||||
*
|
||||
* @param int $todoID
|
||||
* @param object $formData
|
||||
* @access protected
|
||||
* @return object|false
|
||||
*/
|
||||
protected function beforeEdit(int $todoID, object $formData): object|false
|
||||
@@ -152,6 +124,7 @@ class todoZen extends todo
|
||||
* Handle data after edit todo.
|
||||
*
|
||||
* @param object $todo
|
||||
* @access protected
|
||||
* @return void
|
||||
*/
|
||||
protected function afterEdit(int $todoID, array $changes): void
|
||||
@@ -167,6 +140,7 @@ class todoZen extends todo
|
||||
* Handle cycle config.
|
||||
*
|
||||
* @param object $todo
|
||||
* @access private
|
||||
* @return void
|
||||
*/
|
||||
private function handleCycleConfig(object &$todo): void
|
||||
@@ -195,6 +169,7 @@ class todoZen extends todo
|
||||
* Set cycle todo.
|
||||
*
|
||||
* @param object $formData
|
||||
* @access private
|
||||
* @return object
|
||||
*/
|
||||
private function setCycle(object $formData): object
|
||||
@@ -258,4 +233,73 @@ class todoZen extends todo
|
||||
$cancelURL = $this->server->HTTP_REFERER;
|
||||
return print(js::confirm(sprintf($this->lang->todo->$confirmNote, $todo->objectID), $confirmURL, $cancelURL, $okTarget, 'parent', $app));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get product pairs id=>name by model.
|
||||
* 根据模型获取项目, 以键值对格式返回。
|
||||
*
|
||||
* @param string $model
|
||||
* @return array
|
||||
*/
|
||||
protected function getProjectPairsByModel(string $model): array
|
||||
{
|
||||
$model = $model == 'opportunity' ? 'waterfall' : 'all';
|
||||
return $this->loadModel('project')->getPairsByModel((string)$model);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build assign to todo.
|
||||
*
|
||||
* @param object $todo
|
||||
* @param int $projectID
|
||||
* @access public
|
||||
* @return mixed
|
||||
*/
|
||||
protected function buildAssignToTodo(object $todo, int $projectID)
|
||||
{
|
||||
$this->loadModel('user');
|
||||
$this->loadModel('product');
|
||||
|
||||
$this->view->user = $this->user->getByID((string)$todo->account);
|
||||
$this->view->users = $this->user->getPairs('noletter');
|
||||
$this->view->actions = $this->loadModel('action')->getList('todo', (int)$todo->id);
|
||||
$this->view->executions = $this->loadModel('execution')->getPairs();
|
||||
$this->view->products = $todo->type == 'opportunity' ? $this->product->getPairsByProjectModel('waterfall') : $this->product->getPairs();
|
||||
$this->view->projectProducts = $this->product->getProductPairsByProject((int)$projectID);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理指派待办请求数据.
|
||||
* Process assign todo request data.
|
||||
*
|
||||
* @param object $formData
|
||||
* @access protected
|
||||
* @return object
|
||||
*/
|
||||
protected function beforeAssignTo(object $formData): object
|
||||
{
|
||||
$formData = $formData->get();
|
||||
$formData->assignedBy = $this->app->user->account;
|
||||
$formData->assignedDate = helper::now();
|
||||
if($this->post->future) $formData->date = '2030-01-01';
|
||||
if($this->post->lblDisableDate)
|
||||
{
|
||||
$formData->begin = '2400';
|
||||
$formData->end = '2400';
|
||||
}
|
||||
return $formData;
|
||||
}
|
||||
|
||||
/**
|
||||
* 指派待办.
|
||||
* Assign a todo.
|
||||
*
|
||||
* @param object $todo
|
||||
* @access protected
|
||||
* @return bool
|
||||
*/
|
||||
protected function doAssignTo(object $todo): bool
|
||||
{
|
||||
return $this->todo->assignTo($todo);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,4 +3,4 @@ sonar.sourceEncoding=UTF-8
|
||||
sonar.qualitygate.wait=true
|
||||
sonar.coverage.exclusions=**/*.*
|
||||
sonar.inclusions=**/**.php
|
||||
sonar.exclusions=**/*.bak,**/*.sql,**/*.js,**/*.css,**/*.yaml,**/*.zip,**/*.out,**/lang/*,**/test/*
|
||||
sonar.exclusions=**/*.bak,**/*.sql,**/*.js,**/*.css,**/*.yaml,**/*.zip,**/*.out,**/lang/*,**/test/*
|
||||
+54
-15
@@ -222,6 +222,14 @@ class yaml
|
||||
*/
|
||||
public $tableName;
|
||||
|
||||
/**
|
||||
* The config files will be merged.
|
||||
*
|
||||
* @var string[]
|
||||
* @access private
|
||||
*/
|
||||
private $configFiles = array();
|
||||
|
||||
/**
|
||||
* __construct function load config and tableName.
|
||||
* @param string $tableName
|
||||
@@ -234,6 +242,27 @@ class yaml
|
||||
$this->config = $config;
|
||||
$this->tableName = $tableName;
|
||||
$this->fields = new fields();
|
||||
|
||||
$this->configFiles[] = dirname(dirname(__FILE__)) . "/data/{$this->tableName}.yaml";
|
||||
}
|
||||
|
||||
/**
|
||||
* Yaml configuration file for script。
|
||||
*
|
||||
* @param string $fileName
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
public function config($fileName)
|
||||
{
|
||||
$runFileName = str_replace(strrchr($_SERVER['SCRIPT_FILENAME'], "."), "", $_SERVER['SCRIPT_FILENAME']);
|
||||
|
||||
$pos = strripos($runFileName, DS);
|
||||
if($pos !== false) $runFileName = mb_substr($runFileName, $pos+1);
|
||||
|
||||
$this->configFiles[] = $_SERVER['PWD'] . "/yaml/$runFileName/{$fileName}.yaml";
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -260,6 +289,21 @@ class yaml
|
||||
*/
|
||||
public function gen($rows, $dataDirYaml = '', $isClear = true)
|
||||
{
|
||||
$mergeData = array('fields' => array());
|
||||
foreach($this->configFiles as $configFile)
|
||||
{
|
||||
$configData = yaml_parse_file($configFile);
|
||||
$configData['title'] = $configData['title'];
|
||||
$configData['author'] = $configData['author'];
|
||||
$configData['version'] = $configData['version'];
|
||||
|
||||
foreach($configData['fields'] as $configItem)
|
||||
{
|
||||
$field = $configItem['field'];
|
||||
$mergeData['fields'][$field] = $configItem;
|
||||
}
|
||||
}
|
||||
|
||||
$runFileName = str_replace(strrchr($_SERVER['SCRIPT_FILENAME'], "."), "", $_SERVER['SCRIPT_FILENAME']);
|
||||
|
||||
$pos = strripos($runFileName, DS);
|
||||
@@ -270,23 +314,15 @@ class yaml
|
||||
if(!is_dir("{$runFileDir}/data")) mkdir("{$runFileDir}/data", 0777);
|
||||
$yamlFile = "{$runFileDir}/data/{$this->tableName}_{$runFileName}.yaml";
|
||||
|
||||
$yamlDataArr = array();
|
||||
|
||||
$yamlDataArr['title'] = "zt_{$this->tableName}";
|
||||
$yamlDataArr['author'] = "auto_{$runFileName}";
|
||||
$yamlDataArr['version'] = '1.0';
|
||||
|
||||
if(empty($this->fields->fieldArr))
|
||||
if(!empty($this->fields->fieldArr))
|
||||
{
|
||||
$yamlFile = dirname(dirname(__FILE__)) . "/data/{$this->tableName}.yaml";
|
||||
if($dataDirYaml) $yamlFile = dirname(dirname(__FILE__)) . "/data/{$dataDirYaml}.yaml";
|
||||
$fields = $this->fields->setFieldRule($this->fields->fieldArr);
|
||||
foreach($fields as $field) $mergeData['fields'][$field['field']] = $field;
|
||||
}
|
||||
else
|
||||
{
|
||||
$yamlDataArr['fields'] = $this->fields->setFieldRule($this->fields->fieldArr);
|
||||
$mergeData['fields'] = array_values($mergeData['fields']);
|
||||
|
||||
yaml_emit_file($yamlFile, $yamlDataArr, YAML_UTF8_ENCODING);
|
||||
}
|
||||
yaml_emit_file($yamlFile, $mergeData, YAML_UTF8_ENCODING);
|
||||
|
||||
$this->insertDB($yamlFile, $this->tableName, $rows, $isClear);
|
||||
}
|
||||
@@ -320,16 +356,19 @@ class yaml
|
||||
$dbPWD = $this->config->db->password;
|
||||
|
||||
$command = "$zdPath -c %s -d %s -n %d -t %s -dns mysql://%s:%s@%s:%s/%s#utf8";
|
||||
$genSQL = "$zdPath -c %s -d %s -n %d -t %s -o %s";
|
||||
if($isClear === true)
|
||||
{
|
||||
/* Truncate table to reset auto increment number. */
|
||||
system(sprintf("mysql -u%s -p%s -h%s -P%s %s -e 'truncate %s' 2>/dev/null", $dbUser, $dbPWD, $dbHost, $dbPort, $dbName, $tableName));
|
||||
$command .= ' --clear';
|
||||
}
|
||||
$execYaml = sprintf($command, $configYaml, $yamlFile, $rows, $tableName, $dbUser, $dbPWD, $dbHost, $dbPort, $dbName);
|
||||
$execDump = sprintf($dumpCommand, $dbUser, $dbPWD, $dbHost, $dbPort, $dbName, $tableName);
|
||||
$execYaml = sprintf($command, $configYaml, $yamlFile, $rows, $tableName, $dbUser, $dbPWD, $dbHost, $dbPort, $dbName);
|
||||
$execGenSQL = sprintf($genSQL, $configYaml, $yamlFile, $rows, $tableName, "{$tableSqlDir}/{$tableName}_zd.sql");
|
||||
$execDump = sprintf($dumpCommand, $dbUser, $dbPWD, $dbHost, $dbPort, $dbName, $tableName);
|
||||
system($execDump);
|
||||
system($execYaml);
|
||||
system($execGenSQL);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -41,12 +41,11 @@ class directive
|
||||
|
||||
public function __debugInfo()
|
||||
{
|
||||
return
|
||||
[
|
||||
return array(
|
||||
'type' => $this->type,
|
||||
'data' => $this->data,
|
||||
'options' => $this->options
|
||||
];
|
||||
);
|
||||
}
|
||||
|
||||
public static function is($item, $type = NULL)
|
||||
|
||||
@@ -52,15 +52,14 @@ class dom
|
||||
|
||||
public function __debugInfo()
|
||||
{
|
||||
return
|
||||
[
|
||||
return array(
|
||||
'gid' => $this->wg->gid,
|
||||
'type' => $this->wg->type(),
|
||||
'count' => count($this->children),
|
||||
'renderInner' => $this->renderInner,
|
||||
'renderType' => $this->renderType,
|
||||
'selectors' => stringifyWgSelectors($this->selectors)
|
||||
];
|
||||
);
|
||||
}
|
||||
|
||||
public function add($children)
|
||||
|
||||
@@ -3,11 +3,11 @@ namespace zin;
|
||||
|
||||
class btnGroup extends wg
|
||||
{
|
||||
static $defineProps = [
|
||||
static $defineProps = array(
|
||||
'items?:array',
|
||||
'disabled?:bool',
|
||||
'size?:string',
|
||||
];
|
||||
);
|
||||
|
||||
public function onBuildItem($item)
|
||||
{
|
||||
|
||||
@@ -3,8 +3,7 @@ namespace zin;
|
||||
|
||||
class checkbox extends wg
|
||||
{
|
||||
protected static $defineProps =
|
||||
[
|
||||
protected static $defineProps = array(
|
||||
'text?: string',
|
||||
'checked?: bool',
|
||||
'name?: string',
|
||||
@@ -15,7 +14,7 @@ class checkbox extends wg
|
||||
'value?: string',
|
||||
'typeClass?: string',
|
||||
'rootClass?: string'
|
||||
];
|
||||
);
|
||||
|
||||
public function onAddChild($child)
|
||||
{
|
||||
|
||||
@@ -5,15 +5,14 @@ require_once dirname(__DIR__) . DS . 'checkbox' . DS . 'v1.php';
|
||||
|
||||
class checkList extends wg
|
||||
{
|
||||
protected static $defineProps =
|
||||
[
|
||||
protected static $defineProps = array(
|
||||
'primary: bool=true',
|
||||
'type: string="checkbox"',
|
||||
'name?: string',
|
||||
'value?: string|array',
|
||||
'items?: array',
|
||||
'inline?: bool'
|
||||
];
|
||||
);
|
||||
|
||||
public function getValueList()
|
||||
{
|
||||
|
||||
@@ -5,8 +5,7 @@ require_once dirname(__DIR__) . DS . 'input' . DS . 'v1.php';
|
||||
|
||||
class colorPicker extends input
|
||||
{
|
||||
static $defaultProps =
|
||||
[
|
||||
static $defaultProps = array(
|
||||
'type' => 'color'
|
||||
];
|
||||
);
|
||||
}
|
||||
|
||||
@@ -13,8 +13,7 @@ require_once dirname(__DIR__) . DS . 'picker' . DS . 'v1.php';
|
||||
|
||||
class control extends wg
|
||||
{
|
||||
static $defineProps =
|
||||
[
|
||||
static $defineProps = array(
|
||||
'type: string', // text, password, email, number, date, time, datetime, month, url, search, tel, color, picker, select, checkbox, radio, checkboxList, radioList, checkboxListInline, radioListInline, file, textarea
|
||||
'name: string',
|
||||
'id?: string',
|
||||
@@ -24,7 +23,7 @@ class control extends wg
|
||||
'disabled?: bool',
|
||||
'form?: string',
|
||||
'items?: array'
|
||||
];
|
||||
);
|
||||
|
||||
protected function created()
|
||||
{
|
||||
|
||||
@@ -5,8 +5,7 @@ require_once dirname(__DIR__) . DS . 'input' . DS . 'v1.php';
|
||||
|
||||
class datePicker extends input
|
||||
{
|
||||
static $defaultProps =
|
||||
[
|
||||
static $defaultProps = array(
|
||||
'type' => 'date'
|
||||
];
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,8 +5,7 @@ require_once dirname(__DIR__) . DS . 'input' . DS . 'v1.php';
|
||||
|
||||
class datetimePicker extends input
|
||||
{
|
||||
static $defaultProps =
|
||||
[
|
||||
static $defaultProps = array(
|
||||
'type' => 'datetime-local'
|
||||
];
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,8 +5,7 @@ require_once dirname(__DIR__) . DS . 'input' . DS . 'v1.php';
|
||||
|
||||
class fileInput extends input
|
||||
{
|
||||
static $defaultProps =
|
||||
[
|
||||
static $defaultProps = array(
|
||||
'type' => 'file'
|
||||
];
|
||||
);
|
||||
}
|
||||
|
||||
+4
-6
@@ -6,8 +6,7 @@ require_once dirname(__DIR__) . DS . 'formrow' . DS . 'v1.php';
|
||||
|
||||
class form extends wg
|
||||
{
|
||||
protected static $defineProps =
|
||||
[
|
||||
protected static $defineProps = array(
|
||||
'method?: string',
|
||||
'url?: string',
|
||||
'actions?: array',
|
||||
@@ -17,15 +16,14 @@ class form extends wg
|
||||
'labelWidth?: number',
|
||||
'submitBtnText?: string',
|
||||
'cancelBtnText?: string',
|
||||
];
|
||||
);
|
||||
|
||||
protected static $defaultProps =
|
||||
[
|
||||
protected static $defaultProps = array(
|
||||
'grid' => true,
|
||||
'method' => 'post',
|
||||
'target' => 'ajax',
|
||||
'actions' => ['submit', 'cancel'],
|
||||
];
|
||||
);
|
||||
|
||||
public function onBuildItem($item)
|
||||
{
|
||||
|
||||
@@ -8,8 +8,7 @@ require_once dirname(__DIR__) . DS . 'form' . DS . 'v1.php';
|
||||
|
||||
class formPanel extends panel
|
||||
{
|
||||
protected static $defineProps =
|
||||
[
|
||||
protected static $defineProps = array(
|
||||
'method?: string',
|
||||
'url?: string',
|
||||
'actions?: array',
|
||||
@@ -17,13 +16,12 @@ class formPanel extends panel
|
||||
'items?: array',
|
||||
'grid?: bool',
|
||||
'labelWidth?: number',
|
||||
];
|
||||
);
|
||||
|
||||
protected static $defaultProps =
|
||||
[
|
||||
protected static $defaultProps = array(
|
||||
'class' => 'panel-form rounded-md shadow ring-0 canvas px-4 pb-4 mb-4 mx-auto',
|
||||
'size' => 'lg'
|
||||
];
|
||||
);
|
||||
|
||||
protected function created()
|
||||
{
|
||||
|
||||
@@ -3,11 +3,11 @@ namespace zin;
|
||||
|
||||
class history extends wg
|
||||
{
|
||||
protected static $defineProps = [
|
||||
protected static $defineProps = array(
|
||||
'actions?:array',
|
||||
'users?:array',
|
||||
'methodName?:string'
|
||||
];
|
||||
);
|
||||
|
||||
public static function getPageCSS()
|
||||
{
|
||||
|
||||
+4
-6
@@ -3,8 +3,7 @@ namespace zin;
|
||||
|
||||
class input extends wg
|
||||
{
|
||||
static $defineProps =
|
||||
[
|
||||
static $defineProps = array(
|
||||
'type: string',
|
||||
'name: string',
|
||||
'id?: string',
|
||||
@@ -15,13 +14,12 @@ class input extends wg
|
||||
'autofocus?: bool',
|
||||
'autocomplete?: bool=false',
|
||||
'disabled?: bool',
|
||||
];
|
||||
);
|
||||
|
||||
static $defaultProps =
|
||||
[
|
||||
static $defaultProps = array(
|
||||
'type' => 'text',
|
||||
'class' => 'form-control',
|
||||
];
|
||||
);
|
||||
|
||||
protected function build()
|
||||
{
|
||||
|
||||
@@ -5,19 +5,17 @@ require_once dirname(__DIR__) . DS . 'control' . DS . 'v1.php';
|
||||
|
||||
class inputControl extends wg
|
||||
{
|
||||
protected static $defineProps =
|
||||
[
|
||||
protected static $defineProps = array(
|
||||
'prefix?: mixed',
|
||||
'suffix?: mixed',
|
||||
'prefixWidth?: string|number',
|
||||
'suffixWidth?: string|number',
|
||||
];
|
||||
);
|
||||
|
||||
public static $defineBlocks =
|
||||
[
|
||||
public static $defineBlocks = array(
|
||||
'prefix' => [],
|
||||
'suffix' => [],
|
||||
];
|
||||
);
|
||||
|
||||
protected function build()
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@ namespace zin;
|
||||
|
||||
class modalDialog extends wg
|
||||
{
|
||||
static $defineProps = [
|
||||
static $defineProps = array(
|
||||
'title?: string',
|
||||
'itemID?: number',
|
||||
'headerClass?: string',
|
||||
@@ -13,13 +13,13 @@ class modalDialog extends wg
|
||||
'footerActions?: array',
|
||||
'footerClass?: string',
|
||||
'footerProps?: array',
|
||||
];
|
||||
);
|
||||
|
||||
static $defineBlocks = [
|
||||
static $defineBlocks = array(
|
||||
'header' => [],
|
||||
'actions' => [],
|
||||
'footer' => ['map' => 'toolbar']
|
||||
];
|
||||
);
|
||||
|
||||
protected function buildHeader()
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@ namespace zin;
|
||||
|
||||
class modalTrigger extends wg
|
||||
{
|
||||
static $defineProps = [
|
||||
static $defineProps = array(
|
||||
'target?:string',
|
||||
'position?:string|number|object|function',
|
||||
'size?:string|number|object',
|
||||
@@ -24,12 +24,12 @@ class modalTrigger extends wg
|
||||
'url?:string',
|
||||
'request?:object',
|
||||
'dataType?:string',
|
||||
];
|
||||
);
|
||||
|
||||
static $defineBlocks = [
|
||||
static $defineBlocks = array(
|
||||
'trigger' => array('map' => 'btn,a'),
|
||||
'modal' => array('map' => 'modal')
|
||||
];
|
||||
);
|
||||
|
||||
protected function build()
|
||||
{
|
||||
@@ -58,7 +58,7 @@ class modalTrigger extends wg
|
||||
{
|
||||
$triggerBlock->setProp($this->props->skip(array_keys(static::getDefinedProps())));
|
||||
|
||||
$triggerProps = [
|
||||
$triggerProps = array(
|
||||
'data-toggle' => 'modal',
|
||||
'data-target' => $triggerBlock->hasProp('target', 'href') ? NULL : $target,
|
||||
'data-type' => $type,
|
||||
@@ -80,7 +80,7 @@ class modalTrigger extends wg
|
||||
'data-custom' => $this->prop('custom'),
|
||||
'data-request' => $this->prop('request'),
|
||||
'data-data-type' => $this->prop('dataType')
|
||||
];
|
||||
);
|
||||
$triggerBlock->setProp($triggerProps);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,11 +5,11 @@ class moduleMenu extends wg
|
||||
{
|
||||
private $modules = [];
|
||||
|
||||
protected static $defineProps = [
|
||||
protected static $defineProps = array(
|
||||
'productID:number',
|
||||
'activeKey:number',
|
||||
'closeLink:string'
|
||||
];
|
||||
);
|
||||
|
||||
public static function getPageCSS()
|
||||
{
|
||||
|
||||
+2
-3
@@ -9,13 +9,12 @@ class page extends pageBase
|
||||
{
|
||||
static $defaultProps = array('zui' => true);
|
||||
|
||||
static $defineBlocks =
|
||||
[
|
||||
static $defineBlocks = array(
|
||||
'head' => array(),
|
||||
'header' => array('map' => 'header'),
|
||||
'main' => array('map' => 'main'),
|
||||
'footer' => array(),
|
||||
];
|
||||
);
|
||||
|
||||
protected function buildBody()
|
||||
{
|
||||
|
||||
@@ -10,9 +10,8 @@ class pageForm extends page
|
||||
|
||||
public function children()
|
||||
{
|
||||
return
|
||||
[
|
||||
return array(
|
||||
formPanel(set($this->prop('formPanel')), parent::children())
|
||||
];
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,7 @@ namespace zin;
|
||||
|
||||
class select extends wg
|
||||
{
|
||||
static $defineProps =
|
||||
[
|
||||
static $defineProps = array(
|
||||
'name: string',
|
||||
'id?: string',
|
||||
'class?: string="form-control"',
|
||||
@@ -14,7 +13,7 @@ class select extends wg
|
||||
'multiple?: bool',
|
||||
'items?: array',
|
||||
'size?: number',
|
||||
];
|
||||
);
|
||||
|
||||
public function onBuildItem($item)
|
||||
{
|
||||
|
||||
@@ -3,8 +3,7 @@ namespace zin;
|
||||
|
||||
class textarea extends wg
|
||||
{
|
||||
static $defineProps =
|
||||
[
|
||||
static $defineProps = array(
|
||||
'name: string',
|
||||
'id?: string',
|
||||
'class?: string',
|
||||
@@ -13,13 +12,12 @@ class textarea extends wg
|
||||
'placeholder?: string',
|
||||
'rows?: number',
|
||||
'cols?: number',
|
||||
];
|
||||
);
|
||||
|
||||
static $defaultProps =
|
||||
[
|
||||
static $defaultProps = array(
|
||||
'class' => 'form-control',
|
||||
'rows' => 10
|
||||
];
|
||||
);
|
||||
|
||||
protected function build()
|
||||
{
|
||||
|
||||
@@ -5,8 +5,7 @@ require_once dirname(__DIR__) . DS . 'input' . DS . 'v1.php';
|
||||
|
||||
class timePicker extends input
|
||||
{
|
||||
static $defaultProps =
|
||||
[
|
||||
static $defaultProps = array(
|
||||
'type' => 'time'
|
||||
];
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user