diff --git a/db/update17.4.sql b/db/update17.4.sql index 3c90e379ff..0b52eaead8 100644 --- a/db/update17.4.sql +++ b/db/update17.4.sql @@ -217,3 +217,5 @@ INSERT IGNORE INTO `zt_workflowfield` (`module`, `field`, `type`, `length`, `nam ('productplan', 'createdDate', 'datetime', '', '创建时间', 'datetime', '', '', '', '', '', 12, 0, 0, '0', '0', '0', '1', 1, 'buildin', '', '', '2022-08-02 14:49', '', '0000-00-00 00:00:00'), ('release', 'createdBy', 'varchar', '30', '由谁创建', 'select', '', 'user', '', '', '', 14, 0, 0, '0', '0', '0', '1', 1, 'buildin', '', '', '2022-08-02 14:49', '', '0000-00-00 00:00:00'), ('release', 'createdDate', 'datetime', '', '创建时间', 'datetime', '', '', '', '', '', 15, 0, 0, '0', '0', '0', '1', 1, 'buildin', '', '', '2022-08-02 14:49', '', '0000-00-00 00:00:00'); + +UPDATE `zt_project` SET `closedDate`='' AND `closedBy`='' WHERE `status` != 'closed'; diff --git a/module/block/control.php b/module/block/control.php index fecf665e14..1b826ea93b 100644 --- a/module/block/control.php +++ b/module/block/control.php @@ -599,7 +599,7 @@ class block extends control { $limit = ($this->viewType == 'json' or !isset($this->params->count)) ? 0 : (int)$this->params->count; $todos = $this->loadModel('todo')->getList('all', $this->app->user->account, 'wait, doing', $limit, $pager = null, $orderBy = 'date, begin'); - $uri = $this->app->getURI(true); + $uri = $this->createLink('my', 'index'); $this->session->set('todoList', $uri, 'my'); $this->session->set('bugList', $uri, 'qa'); @@ -629,7 +629,7 @@ class block extends control */ public function printTaskBlock() { - $this->session->set('taskList', $this->app->getURI(true), 'execution'); + $this->session->set('taskList', $this->createLink('my', 'index'), 'execution'); if(preg_match('/[^a-zA-Z0-9_]/', $this->params->type)) return; $account = $this->app->user->account; @@ -647,7 +647,7 @@ class block extends control */ public function printBugBlock() { - $this->session->set('bugList', $this->app->getURI(true), 'qa'); + $this->session->set('bugList', $this->createLink('my', 'index'), 'qa'); if(preg_match('/[^a-zA-Z0-9_]/', $this->params->type)) return; $projectID = $this->lang->navGroup->qa == 'project' ? $this->session->project : 0; @@ -663,7 +663,7 @@ class block extends control */ public function printCaseBlock() { - $this->session->set('caseList', $this->app->getURI(true), 'qa'); + $this->session->set('caseList', $this->createLink('my', 'index'), 'qa'); $this->app->loadLang('testcase'); $this->app->loadLang('testtask'); @@ -708,9 +708,10 @@ class block extends control { $this->app->loadLang('testtask'); - $this->session->set('productList', $this->app->getURI(true), 'product'); - $this->session->set('testtaskList', $this->app->getURI(true), 'qa'); - $this->session->set('buildList', $this->app->getURI(true), 'execution'); + $uri = $this->createLink('my', 'index'); + $this->session->set('productList', $uri, 'product'); + $this->session->set('testtaskList', $uri, 'qa'); + $this->session->set('buildList', $uri, 'execution'); if(preg_match('/[^a-zA-Z0-9_]/', $this->params->type)) return; $this->view->testtasks = $this->dao->select('distinct t1.*,t2.name as productName,t3.name as buildName,t4.name as projectName')->from(TABLE_TESTTASK)->alias('t1') @@ -736,7 +737,7 @@ class block extends control */ public function printStoryBlock() { - $this->session->set('storyList', $this->app->getURI(true), 'product'); + $this->session->set('storyList', $this->createLink('my', 'index'), 'product'); if(preg_match('/[^a-zA-Z0-9_]/', $this->params->type)) return; $this->app->loadClass('pager', $static = true); diff --git a/module/block/view/dashboard.html.php b/module/block/view/dashboard.html.php index 9746ce22e8..5390ef52c8 100644 --- a/module/block/view/dashboard.html.php +++ b/module/block/view/dashboard.html.php @@ -59,7 +59,7 @@ $useGuest = $this->app->user->account == 'guest'; - fetch('block', 'printBlock', "id=$block->id&module=$module")?> +
@@ -94,7 +94,7 @@ $useGuest = $this->app->user->account == 'guest'; - fetch('block', 'printBlock', "id=$block->id&module=$module")?> +
@@ -136,6 +136,11 @@ $(function() }); } setTimeout(checkRemind, 1000); + + $('#dashboard .row .panel').each(function() + { + refreshBlock($(this)); + }) }); getExtViewFile(__FILE__)){include $extView; return helper::cd();}?> diff --git a/module/bug/model.php b/module/bug/model.php index f4e4c1f5cd..f4e2b71060 100644 --- a/module/bug/model.php +++ b/module/bug/model.php @@ -1720,8 +1720,8 @@ class bugModel extends model ->beginIF($type != 'closedBy' and $this->app->moduleName == 'block')->andWhere('t1.status')->ne('closed')->fi() ->beginIF($type != 'all' and $type != 'bySearch')->andWhere("t1.`$type`")->eq($account)->fi() ->beginIF($type == 'bySearch' and $moduleName == 'workBug')->andWhere("t1.assignedTo")->eq($account)->fi() - ->beginIF($type == 'bySearch' and $moduleName == 'contributeBug') ->beginIF($type == 'assignedTo' and $moduleName == 'workBug')->andWhere('t1.status')->ne('closed')->fi() + ->beginIF($type == 'bySearch' and $moduleName == 'contributeBug') ->andWhere('t1.openedBy', 1)->eq($account) ->orWhere('t1.closedBy')->eq($account) ->orWhere('t1.resolvedBy')->eq($account) diff --git a/module/execution/config.php b/module/execution/config.php index f9b0af12cf..46880f681f 100644 --- a/module/execution/config.php +++ b/module/execution/config.php @@ -119,6 +119,39 @@ $config->execution->search['params']['canceledDate'] = array('operator' => '=' $config->execution->search['params']['lastEditedDate'] = array('operator' => '=', 'control' => 'input', 'values' => '', 'class' => 'date'); $config->execution->search['params']['activatedDate'] = array('operator' => '=', 'control' => 'input', 'values' => '', 'class' => 'date'); +$app->loadLang('execution'); +$config->execution->all = new stdclass(); +$config->execution->all->search['module'] = 'execution'; +$config->execution->all->search['fields']['name'] = $lang->execution->execName; +$config->execution->all->search['fields']['id'] = $lang->execution->execId; +$config->execution->all->search['fields']['status'] = $lang->execution->execStatus; +$config->execution->all->search['fields']['project'] = $lang->execution->project; +$config->execution->all->search['fields']['PM'] = $lang->execution->owner; +$config->execution->all->search['fields']['openedBy'] = $lang->execution->openedBy; +$config->execution->all->search['fields']['openedDate'] = $lang->execution->openedDate; +$config->execution->all->search['fields']['begin'] = $lang->execution->begin; +$config->execution->all->search['fields']['end'] = $lang->execution->end; +$config->execution->all->search['fields']['realBegan'] = $lang->execution->realBegan; +$config->execution->all->search['fields']['realEnd'] = $lang->execution->realEnd; +$config->execution->all->search['fields']['closedBy'] = $lang->execution->closedBy; +$config->execution->all->search['fields']['lastEditedDate'] = $lang->execution->lastEditedDate; +$config->execution->all->search['fields']['closedDate'] = $lang->execution->closedDate; + +$config->execution->all->search['params']['name'] = array('operator' => 'include', 'control' => 'input', 'values' => ''); +$config->execution->all->search['params']['id'] = array('operator' => '=', 'control' => 'input', 'values' => ''); +$config->execution->all->search['params']['status'] = array('operator' => '=', 'control' => 'select', 'values' => array('') + $lang->execution->statusList); +$config->execution->all->search['params']['project'] = array('operator' => '=', 'control' => 'select', 'values' => ''); +$config->execution->all->search['params']['PM'] = array('operator' => '=', 'control' => 'select', 'values' => 'users'); +$config->execution->all->search['params']['openedBy'] = array('operator' => '=', 'control' => 'select', 'values' => 'users'); +$config->execution->all->search['params']['openedDate'] = array('operator' => '=', 'control' => 'input', 'values' => '', 'class' => 'date'); +$config->execution->all->search['params']['begin'] = array('operator' => '=', 'control' => 'input', 'values' => '', 'class' => 'date'); +$config->execution->all->search['params']['end'] = array('operator' => '=', 'control' => 'input', 'values' => '', 'class' => 'date'); +$config->execution->all->search['params']['realBegan'] = array('operator' => '=', 'control' => 'input', 'values' => '', 'class' => 'date'); +$config->execution->all->search['params']['realEnd'] = array('operator' => '=', 'control' => 'input', 'values' => '', 'class' => 'date'); +$config->execution->all->search['params']['closedBy'] = array('operator' => '=', 'control' => 'select', 'values' => 'users'); +$config->execution->all->search['params']['lastEditedDate'] = array('operator' => '=', 'control' => 'input', 'values' => '', 'class' => 'date'); +$config->execution->all->search['params']['closedDate'] = array('operator' => '=', 'control' => 'input', 'values' => '', 'class' => 'date'); + $config->printKanban = new stdClass(); $config->printKanban->col['story'] = 1; $config->printKanban->col['wait'] = 2; diff --git a/module/execution/control.php b/module/execution/control.php index d1b3a9c8f4..a8a7f93e52 100644 --- a/module/execution/control.php +++ b/module/execution/control.php @@ -241,7 +241,7 @@ class execution extends control $this->view->moduleID = $moduleID; $this->view->moduleTree = $this->tree->getTaskTreeMenu($executionID, $productID, $startModuleID = 0, array('treeModel', 'createTaskLink'), $extra); $this->view->memberPairs = $memberPairs; - $this->view->branchGroups = $this->loadModel('branch')->getByProducts(array_keys($products), 'noempty'); + $this->view->branchGroups = $this->loadModel('branch')->getByProducts(array_keys($products)); $this->view->setModule = true; $this->view->canBeChanged = common::canModify('execution', $execution); // Determines whether an object is editable. $this->view->showBranch = $showBranch; @@ -3678,13 +3678,14 @@ class execution extends control * @param int $projectID * @param string $orderBy * @param int $productID + * @param string $param * @param int $recTotal * @param int $recPerPage * @param int $pageID * @access public * @return void */ - public function all($status = 'undone', $projectID = 0, $orderBy = 'order_asc', $productID = 0, $recTotal = 0, $recPerPage = 100, $pageID = 1) + public function all($status = 'undone', $projectID = 0, $orderBy = 'order_asc', $productID = 0, $param = '', $recTotal = 0, $recPerPage = 100, $pageID = 1) { $this->app->loadLang('my'); $this->app->loadLang('product'); @@ -3714,10 +3715,14 @@ class execution extends control $this->app->loadClass('pager', $static = true); $pager = new pager($recTotal, $recPerPage, $pageID); + $queryID = ($status == 'bySearch') ? (int)$param : 0; + $actionURL = $this->createLink('execution', 'all', "status=bySearch&projectID=$projectID&orderBy=$orderBy&productID=$productID¶m=myQueryID"); + $this->execution->buildSearchFrom($queryID, $actionURL); + $this->view->title = $this->lang->execution->allExecutions; $this->view->position[] = $this->lang->execution->allExecutions; - $executionStats = $this->project->getStats($projectID, $status, $productID, 0, 30, $orderBy, $pager); + $executionStats = $this->project->getStats($projectID, $status, $productID, 0, 30, $orderBy, $pager, false, $queryID); $parentIdList = array(); foreach($executionStats as $execution) @@ -3742,6 +3747,7 @@ class execution extends control $this->view->users = $this->loadModel('user')->getPairs('noletter'); $this->view->status = $status; $this->view->from = $from; + $this->view->param = $param; $this->view->isStage = (isset($project->model) and $project->model == 'waterfall') ? true : false; $this->display(); diff --git a/module/execution/css/all.css b/module/execution/css/all.css index 36584c5c7a..f13f24181c 100644 --- a/module/execution/css/all.css +++ b/module/execution/css/all.css @@ -35,3 +35,4 @@ canvas {height: 28px;} .parent.has-child.c-name.flex, .table-child-bottom > .c-name.flex {border-bottom: 1px solid #cbd0db !important;} .parent.has-child.c-name.flex {margin-bottom: -2px !important;} #tableCustomBtn {padding-bottom: 5px;} +#bysearchTab {margin-left: 5px;} diff --git a/module/execution/lang/de.php b/module/execution/lang/de.php index e3a93dd771..0261d10f35 100644 --- a/module/execution/lang/de.php +++ b/module/execution/lang/de.php @@ -137,6 +137,7 @@ $lang->execution->batchCreateTask = 'Batch create task'; $lang->execution->kanbanNoLinkProduct = "Kanban not linked {$lang->productCommon}"; $lang->execution->myTask = "My Task"; $lang->execution->list = "{$lang->executionCommon} List"; +$lang->execution->allProject = 'All'; /* Fields of zt_team. */ $lang->execution->root = 'Root'; diff --git a/module/execution/lang/en.php b/module/execution/lang/en.php index 37254e4b4c..3d8cbb0fdf 100644 --- a/module/execution/lang/en.php +++ b/module/execution/lang/en.php @@ -137,11 +137,12 @@ $lang->execution->batchCreateTask = 'Batch create task'; $lang->execution->kanbanNoLinkProduct = "Kanban not linked {$lang->productCommon}"; $lang->execution->myTask = "My Task"; $lang->execution->list = 'List'; +$lang->execution->allProject = 'All'; /* Fields of zt_team. */ $lang->execution->root = 'Root'; -$lang->execution->estimate = 'estimate'; -$lang->execution->consumed = 'consumed'; +$lang->execution->estimate = 'Estimate'; +$lang->execution->consumed = 'Consumed'; $lang->execution->left = 'Left'; if($this->config->systemMode == 'new') $lang->execution->copyTeamTip = "copy Project/{$lang->execution->common} team members"; diff --git a/module/execution/lang/fr.php b/module/execution/lang/fr.php index 60f4d20c71..6352bcc766 100644 --- a/module/execution/lang/fr.php +++ b/module/execution/lang/fr.php @@ -137,6 +137,7 @@ $lang->execution->batchCreateTask = 'Batch create task'; $lang->execution->kanbanNoLinkProduct = "Kanban not linked {$lang->productCommon}"; $lang->execution->myTask = "My Task"; $lang->execution->list = "{$lang->executionCommon} List"; +$lang->execution->allProject = 'Tous'; /* Fields of zt_team. */ $lang->execution->root = 'Root'; diff --git a/module/execution/lang/zh-cn.php b/module/execution/lang/zh-cn.php index 5025ccf4de..363002d338 100644 --- a/module/execution/lang/zh-cn.php +++ b/module/execution/lang/zh-cn.php @@ -137,6 +137,7 @@ $lang->execution->batchCreateTask = '批量建任务'; $lang->execution->kanbanNoLinkProduct = "看板没有关联{$lang->productCommon}"; $lang->execution->myTask = "我的任务"; $lang->execution->list = '列表'; +$lang->execution->allProject = '全部项目'; /* Fields of zt_team. */ $lang->execution->root = '源ID'; diff --git a/module/execution/model.php b/module/execution/model.php index 1cce86f1be..9a090b9465 100644 --- a/module/execution/model.php +++ b/module/execution/model.php @@ -949,6 +949,8 @@ class executionModel extends model ->setDefault('status', 'doing') ->setDefault('lastEditedBy', $this->app->user->account) ->setDefault('lastEditedDate', $now) + ->setDefault('closedBy', '') + ->setDefault('closedDate', '') ->stripTags($this->config->execution->editor->activate['id'], $this->config->allowedTags) ->remove('comment,readjustTime,readjustTask') ->get(); @@ -4722,4 +4724,23 @@ class executionModel extends model echo ''; } } + + /* + * Build search form + * + * @param int $queryID + * @param string $actionURL + * @return void + * */ + public function buildSearchFrom($queryID, $actionURL) + { + $this->config->execution->all->search['queryID'] = $queryID; + $this->config->execution->all->search['actionURL'] = $actionURL; + + $projectPairs = array(0 => ''); + $projectPairs += $this->loadModel('project')->getPairsByProgram(); + $this->config->execution->all->search['params']['project']['values'] = $projectPairs + array('all' => $this->lang->execution->allProject); + + $this->loadModel('search')->setSearchParams($this->config->execution->all->search); + } } diff --git a/module/execution/view/all.html.php b/module/execution/view/all.html.php index 512b25aae3..beb720a7e2 100644 --- a/module/execution/view/all.html.php +++ b/module/execution/view/all.html.php @@ -59,6 +59,7 @@ js::set('isCNLang', !$this->loadModel('common')->checkNotCN()) execution->selectProject}'");?> + execution->byQuery;?>
" . $lang->export, '', "class='btn btn-link export'")?> @@ -70,6 +71,7 @@ js::set('isCNLang', !$this->loadModel('common')->checkNotCN())
+

@@ -92,7 +94,7 @@ js::set('isCNLang', !$this->loadModel('common')->checkNotCN())

recTotal}&recPerPage={$pager->recPerPage}&pageID={$pager->pageID}"; + $vars = "status=$status&projectID=$projectID&orderBy=%s&productID=$productID¶m=$param&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}&pageID={$pager->pageID}"; if($useDatatable) include '../../common/view/datatable.html.php'; else include '../../common/view/tablesorter.html.php'; diff --git a/module/execution/view/grouptask.html.php b/module/execution/view/grouptask.html.php index d531a87e5c..6446735df7 100644 --- a/module/execution/view/grouptask.html.php +++ b/module/execution/view/grouptask.html.php @@ -226,6 +226,7 @@
assignedTo])) printf($lang->execution->memberHours, zget($users, $task->assignedTo), $members[$task->assignedTo]->totalHours);?> + assignedTo and !isset($members[$task->assignedTo])) printf($lang->execution->memberHours, zget($users, $task->assignedTo), '0.0');?> assignedTo)):?>
diff --git a/module/kanban/js/view.js b/module/kanban/js/view.js index 7e39e60137..5bec4a50a1 100644 --- a/module/kanban/js/view.js +++ b/module/kanban/js/view.js @@ -407,7 +407,7 @@ function renderKanbanItem(item, $item) $user.html(renderUsersAvatar(assignedTo, item.id)).attr('title', title); } - if(kanban.performable == 1) + if(kanban.performable == 1 && (item.fromType == '' || item.fromType == 'execution')) { var $progress = $item.children('.progress-box'); if(!$progress.length) $progress = $('
' + item.progress + '%
').appendTo($item); @@ -1189,7 +1189,7 @@ function createCardMenu(options) var items = []; if(privs.includes('editCard') && card.fromType == '') items.push({label: kanbanLang.editCard, icon: 'edit', url: createLink('kanban', 'editCard', 'cardID=' + card.id, '', 'true'), className: 'iframe', attrs: {'data-toggle': 'modal', 'data-width': '80%'}}); if(privs.includes('deleteCard')) items.push({label: card.fromType == '' ? kanbanLang.deleteCard : kanbanLang.removeCard, icon: card.fromType == '' ? 'trash' : 'unlink', url: createLink('kanban', 'deleteCard', 'cardID=' + card.id), attrs: {'target': 'hiddenwin'}}); - if(kanban.performable == 1) + if(kanban.performable == 1 && card.fromType == '') { if(card.status == 'done') { diff --git a/module/kanban/model.php b/module/kanban/model.php index f4c67e50d7..e95c66f0b8 100644 --- a/module/kanban/model.php +++ b/module/kanban/model.php @@ -1207,6 +1207,10 @@ class kanbanModel extends model ->andWhere('action')->eq('opened') ->fetchPairs(); } + elseif($fromType == 'execution') + { + $executionProgress = $this->loadModel('project')->computerProgress($objects); + } /* Data for constructing the card. */ foreach($objectCards as $objectID => $cardsInfo) @@ -1231,6 +1235,7 @@ class kanbanModel extends model if($delay > 0) $objectCard->delay = $delay; } $objectCard->execType = $object->type; + $objectCard->progress = isset($executionProgress[$objectID]->progress) ? $executionProgress[$objectID]->progress : 0; } $objectCard->desc = strip_tags(htmlspecialchars_decode($object->desc)); diff --git a/module/kanban/view/viewarchivedcard.html.php b/module/kanban/view/viewarchivedcard.html.php index 74a334d0c1..d12d129862 100644 --- a/module/kanban/view/viewarchivedcard.html.php +++ b/module/kanban/view/viewarchivedcard.html.php @@ -47,7 +47,12 @@ #archivedCards .card-item .has-color .info > .label-pri {border-color: #FFFFFF;} #archivedCards .card-item .has-color .progress-box > .progress-number {color: #FFFFFF;} #archivedCards .progress-box {width: 97%;} -#performable {padding: 25px 10px !important;} +#archivedCards .no-progress {padding: 7px 10px !important;} +#archivedCards .has-progress {padding: 21px 10px !important;} +#archivedCards .has-desc.has-progress {padding: 26px 10px !important;} +#archivedCards .has-desc.no-progress {padding: 19px 10px !important;} +#archivedCards .has-avatar.has-progress {padding: 24px 10px !important;} +#archivedCards .has-avatar.no-progress {padding: 9px 10px !important;} loadLang('execution'); @@ -71,6 +76,7 @@ js::set('systemMode', $this->config->systemMode);
color == '#b10b0b') $color = 'has-color red'; if($card->color == '#cfa227') $color = 'has-color yellow'; @@ -98,7 +104,11 @@ js::set('systemMode', $this->config->systemMode); $name = isset($card->title) ? $card->title : $card->name; if(common::hasPriv($card->fromType, 'view')) echo html::a($this->createLink($card->fromType, 'view', "id=$card->fromID"), $name, '', "class='cardName' title='$name'"); if(!common::hasPriv($card->fromType, 'view')) echo "
$name
"; - if($card->fromType == 'productplan' or $card->fromType == 'build') echo "
$card->desc
"; + if($card->fromType == 'productplan' or $card->fromType == 'build') + { + echo "
$card->desc
"; + if(!empty($card->desc)) $class .= ' has-desc'; + } echo "
"; if(isset($lang->{$card->fromType}->statusList[$card->objectStatus])) echo "" . $lang->{$card->fromType}->statusList[$card->objectStatus] . ''; if(isset($card->date) and !helper::isZeroDate($card->date)) echo "" . date("Y-m-d", strtotime($card->date)) . "" @@ -147,6 +157,7 @@ js::set('systemMode', $this->config->systemMode); if($count > 2) continue; echo html::smallAvatar(array('avatar' => $usersAvatar[$account], 'account' => $account, 'name' => $users[$account]), 'avatar-circle'); $count ++; + $class .= ' has-avatar'; } ?> 2) echo "...";?> @@ -159,11 +170,12 @@ js::set('systemMode', $this->config->systemMode); echo "
"; echo html::smallAvatar(array('avatar' => $usersAvatar[$assignedToList], 'account' => $assignedToList, 'name' => $users[$assignedToList]), 'avatar-circle'); echo "
"; + $class .= ' has-avatar'; } ?>
- performable):?> + performable and ($card->fromType == 'execution' or empty($card->fromType))):?>
@@ -173,7 +185,8 @@ js::set('systemMode', $this->config->systemMode);
-
performable) echo "id='performable'";?>> + performable) and ($card->fromType == 'execution' or empty($card->fromType))) ? ' has-progress' : ' no-progress';?> +
config->CRKanban) and $this->config->CRKanban == '0' and $kanban->status == 'closed'); $canRestore = (commonModel::hasPriv('kanban', 'restoreCard') and $CRKanban); diff --git a/module/productplan/view/view.html.php b/module/productplan/view/view.html.php index 64e329c22f..815900cdc4 100644 --- a/module/productplan/view/view.html.php +++ b/module/productplan/view/view.html.php @@ -189,7 +189,7 @@ parent > 0) echo "story->children}>{$lang->story->childrenAB}"; - echo html::a($viewLink , $story->title); + echo html::a($viewLink , $story->title, '', "style='color: $story->color'"); ?> openedBy);?> diff --git a/module/project/js/execution.js b/module/project/js/execution.js index 43337d4ee6..2d050e7b6e 100644 --- a/module/project/js/execution.js +++ b/module/project/js/execution.js @@ -180,7 +180,7 @@ function showEditCheckbox(show) executionID = $tr.attr('data-id'); if(show) { - var marginLeft = $tr.find('td:first').find('span.table-nest-icon').css('margin-left'); + var marginLeft = '7px'; $tr.find('td:first').prepend("
"); $tr.find('td:first').find('.checkbox-primary').css('margin-left', marginLeft).css('width', '14'); diff --git a/module/project/model.php b/module/project/model.php index ea8da3f551..485448c5fb 100644 --- a/module/project/model.php +++ b/module/project/model.php @@ -259,7 +259,7 @@ class projectModel extends model { if($project->parent == 0) return ''; - $parentName = $this->dao->select('id,name')->from(TABLE_PROGRAM)->where('id')->in(trim($project->path, ','))->andWhere('grade')->lt($project->grade)->fetchPairs(); + $parentName = $this->dao->select('id,name')->from(TABLE_PROGRAM)->where('id')->in(trim($project->path, ','))->andWhere('grade')->lt($project->grade)->orderBy('grade asc')->fetchPairs(); $parentProgram = ''; foreach($parentName as $name) $parentProgram .= $name . '/'; @@ -2329,17 +2329,48 @@ class projectModel extends model * @param int $projectID * @param string $status * @param int $productID + * @param int $branch * @param int $itemCounts * @param string $orderBy * @param object $pager + * @param bool $withTasks + * @param int $queryID * @access public * @return array */ - public function getStats($projectID = 0, $status = 'undone', $productID = 0, $branch = 0, $itemCounts = 30, $orderBy = 'id_asc', $pager = null, $withTasks = false) + public function getStats($projectID = 0, $status = 'undone', $productID = 0, $branch = 0, $itemCounts = 30, $orderBy = 'id_asc', $pager = null, $withTasks = false, $queryID = 0) { if(empty($productID)) { $myExecutionIDList = array(); + $query = ''; + if($status == 'bySearch') + { + $status = 'all'; + if($queryID) + { + $query = $this->loadModel('search')->getQuery($queryID); + if($query) + { + $this->session->set('executionQuery', $query->sql); + $this->session->set('executionForm', $query->form); + } + else + { + $this->session->set('executionQuery', ' 1 = 1'); + } + } + else + { + if($this->session->executionQuery == false) $this->session->set('executionQuery', ' 1 = 1'); + } + $query = $this->session->executionQuery; + $allProject = "`project` = 'all'"; + + if(strpos($query, $allProject) !== false) $query = str_replace($allProject, '1', $query); + $query = preg_replace('/(`\w*`)/', 't1.$1',$query); + } + if($status == 'involved') { $myExecutionIDList = $this->dao->select('root')->from(TABLE_TEAM) @@ -2351,6 +2382,7 @@ class projectModel extends model $executions = $this->dao->select('t1.*,t2.name projectName, t2.model as projectModel')->from(TABLE_EXECUTION)->alias('t1') ->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id') ->where('t1.type')->in('sprint,stage,kanban') + ->beginIF(!empty($query))->andWhere($query)->fi() ->beginIF($projectID != 0)->andWhere('t1.project')->eq($projectID)->fi() ->beginIF($projectID == 0 and $this->config->vision)->andWhere('t1.vision')->eq($this->config->vision)->fi() ->beginIF(!empty($myExecutionIDList))->andWhere('t1.id')->in(array_keys($myExecutionIDList))->fi() diff --git a/module/story/model.php b/module/story/model.php index f6695b0d96..08046f7cba 100644 --- a/module/story/model.php +++ b/module/story/model.php @@ -1841,15 +1841,20 @@ class storyModel extends model if($oldStory->branch) $story->plan = $planID; /* Append the plan id to plan field if product is multi and story is all branch. */ - if($this->session->currentProductType != 'normal' and empty($story->branch) and $planID != 0) + if($this->session->currentProductType != 'normal' and empty($story->branch)) { $branchPlanPairs = $this->dao->select('branch, id as plan')->from(TABLE_PRODUCTPLAN) ->where('product')->eq($oldStory->product) ->andWhere('id')->in($oldStory->plan) ->fetchPairs(); - if(isset($branchPlanPairs[$plan->branch])) $branchPlanPairs[$plan->branch] = $planID; - - $story->plan = $oldStory->plan ? ',' . implode(',', $branchPlanPairs) : ",$planID"; + if($planID == 0 and !empty($oldStory->plan) and isset($branchPlanPairs[0]) and $branchPlanPairs[0] != $planID) $unlinkPlans[$branchPlanPairs[0]] = empty($unlinkPlans[$branchPlanPairs[0]]) ? $storyID : "{$unlinkPlans[$branchPlanPairs[0]]},$storyID"; + if($planID != 0) + { + if(!empty($oldStory->plan) and isset($branchPlanPairs[$plan->branch]) and $branchPlanPairs[$plan->branch] != $planID) $unlinkPlans[$branchPlanPairs[$plan->branch]] = empty($unlinkPlans[$branchPlanPairs[$plan->branch]]) ? $storyID : "{$unlinkPlans[$branchPlanPairs[$plan->branch]]},$storyID"; + if(isset($branchPlanPairs[$plan->branch])) $branchPlanPairs[$plan->branch] = $planID; + $story->plan = $oldStory->plan ? ',' . implode(',', $branchPlanPairs) : ",$planID"; + if($story->plan != $oldStory->plan and !empty($planID)) $link2Plans[$planID] = empty($link2Plans[$planID]) ? $storyID : "{$link2Plans[$planID]},$storyID"; + } } /* Change stage. */ @@ -1878,8 +1883,8 @@ class storyModel extends model if(!dao::isError()) { $allChanges[$storyID] = common::createChanges($oldStory, $story); - if($story->plan != $oldStory->plan and !empty($oldStory->plan)) $unlinkPlans[$oldStory->plan] = empty($unlinkPlans[$oldStory->plan]) ? $storyID : "{$unlinkPlans[$oldStory->plan]},$storyID"; - if($story->plan != $oldStory->plan and !empty($story->plan)) $link2Plans[$story->plan] = empty($link2Plans[$story->plan]) ? $storyID : "{$link2Plans[$story->plan]},$storyID"; + if($story->plan != $oldStory->plan and !empty($oldStory->plan) and strpos($story->plan, ',') === false) $unlinkPlans[$oldStory->plan] = empty($unlinkPlans[$oldStory->plan]) ? $storyID : "{$unlinkPlans[$oldStory->plan]},$storyID"; + if($story->plan != $oldStory->plan and !empty($story->plan) and strpos($story->plan, ',') === false) $link2Plans[$story->plan] = empty($link2Plans[$story->plan]) ? $storyID : "{$link2Plans[$story->plan]},$storyID"; } } diff --git a/module/task/model.php b/module/task/model.php index 1a1e762fc9..19e8927876 100644 --- a/module/task/model.php +++ b/module/task/model.php @@ -63,6 +63,7 @@ class taskModel extends model $requiredFields = str_replace(",story,", ',', "$requiredFields"); $requiredFields = str_replace(",estStarted,", ',', "$requiredFields"); $requiredFields = str_replace(",deadline,", ',', "$requiredFields"); + $requiredFields = str_replace(",module,", ',', "$requiredFields"); } $this->loadModel('file'); @@ -3630,6 +3631,18 @@ class taskModel extends model public function printAssignedHtml($task, $users) { $btnTextClass = ''; + if(!empty($task->team) and $task->mode == 'multi' and $task->status != 'closed') + { + $assignedToText = $this->lang->task->team; + + $teamMembers = array(); + foreach($task->team as $teamMember) $teamMembers[] = zget($users, $teamMember->account); + $assignedToTitle = implode($this->lang->comma, $teamMembers); + } + else + { + $assignedToText = $assignedToTitle = zget($users, $task->assignedTo); + } $assignedToText = (!empty($task->team) and $task->mode == 'multi' and $task->status != 'closed') ? $this->lang->task->team : zget($users, $task->assignedTo); if(empty($task->assignedTo)) @@ -3642,7 +3655,7 @@ class taskModel extends model $btnClass = $task->assignedTo == 'closed' ? ' disabled' : ''; $btnClass = "iframe btn btn-icon-left btn-sm {$btnClass}"; $assignToLink = $task->assignedTo == 'closed' ? '#' : helper::createLink('task', 'assignTo', "executionID=$task->execution&taskID=$task->id", '', true); - $assignToHtml = html::a($assignToLink, " {$assignedToText}", '', "class='$btnClass'"); + $assignToHtml = html::a($assignToLink, " {$assignedToText}", '', "class='$btnClass'"); echo !common::hasPriv('task', 'assignTo', $task) ? "{$assignedToText}" : $assignToHtml; } diff --git a/module/user/js/login.js b/module/user/js/login.js index 31fe0854f2..9349326727 100644 --- a/module/user/js/login.js +++ b/module/user/js/login.js @@ -3,6 +3,8 @@ if(window.self !== window.top) window.top.location.href = window.location.href; $(document).ready(function() { + timeoutID = null; + /* Fix bug for misc-ping */ $('#hiddenwin').removeAttr('id'); @@ -33,10 +35,19 @@ $(document).ready(function() var link = createLink('user', 'login'); var keepLogin = $('#keepLoginon').attr('checked') == 'checked' ? 1 : 0; var captcha = $('#captcha').length == 1 ? $('#captcha').val() : ''; + var timeout = true; + + clearTimeout(timeoutID); + timeoutID = setTimeout(function() + { + if(timeout) alert(loginTimeoutTip); + }, 4000); $.get(createLink('user', 'refreshRandom'), function(data) { var rand = data; + timeout = false; + $.ajax ({ url: link, diff --git a/module/user/lang/de.php b/module/user/lang/de.php index d52a0e5dc7..33808bfb72 100644 --- a/module/user/lang/de.php +++ b/module/user/lang/de.php @@ -251,6 +251,7 @@ $lang->user->error->noEmail = 'The user does not register email. Please $lang->user->error->errorEmail = 'The account does not match the email. Please enter a new one.'; $lang->user->error->emailSetting = 'No email is configured in the system. Contact the admin to reset the email.'; $lang->user->error->sendMailFail = 'Message sending failed, please try again!'; +$lang->user->error->loginTimeoutTip = 'Login failed, please check if the proxy service is normal.'; $lang->user->contactFieldList['phone'] = $lang->user->phone; $lang->user->contactFieldList['mobile'] = $lang->user->mobile; diff --git a/module/user/lang/en.php b/module/user/lang/en.php index f1460a4f46..0f314ec1c6 100644 --- a/module/user/lang/en.php +++ b/module/user/lang/en.php @@ -251,6 +251,7 @@ $lang->user->error->noEmail = 'The user does not register email. Please $lang->user->error->errorEmail = 'The account does not match the email. Please enter a new one.'; $lang->user->error->emailSetting = 'No email is configured in the system. Contact the admin to reset the email.'; $lang->user->error->sendMailFail = 'Message sending failed, please try again!'; +$lang->user->error->loginTimeoutTip = 'Login failed, please check if the proxy service is normal.'; $lang->user->contactFieldList['phone'] = $lang->user->phone; $lang->user->contactFieldList['mobile'] = $lang->user->mobile; diff --git a/module/user/lang/fr.php b/module/user/lang/fr.php index 4df771cfe6..622a42e2b3 100644 --- a/module/user/lang/fr.php +++ b/module/user/lang/fr.php @@ -251,6 +251,7 @@ $lang->user->error->noEmail = 'The user does not register email. Please $lang->user->error->errorEmail = 'The account does not match the email. Please enter a new one.'; $lang->user->error->emailSetting = 'No email is configured in the system. Contact the admin to reset the email.'; $lang->user->error->sendMailFail = 'Message sending failed, please try again!'; +$lang->user->error->loginTimeoutTip = 'Échec de la connexion, veuillez vérifier si le service proxy est activé.'; $lang->user->contactFieldList['phone'] = $lang->user->phone; $lang->user->contactFieldList['mobile'] = $lang->user->mobile; diff --git a/module/user/lang/zh-cn.php b/module/user/lang/zh-cn.php index 74af4e7151..37cafcb434 100644 --- a/module/user/lang/zh-cn.php +++ b/module/user/lang/zh-cn.php @@ -251,6 +251,7 @@ $lang->user->error->noEmail = '该用户未绑定邮箱,请联系管 $lang->user->error->errorEmail = '用户名和邮箱不匹配,请重新输入。'; $lang->user->error->emailSetting = '系统未配置发信邮箱,请联系管理员重置。'; $lang->user->error->sendMailFail = '邮件发送失败,请重试!'; +$lang->user->error->loginTimeoutTip = '系统登录失败,请检查代理服务是否正常'; $lang->user->contactFieldList['phone'] = $lang->user->phone; $lang->user->contactFieldList['mobile'] = $lang->user->mobile; diff --git a/module/user/view/login.html.php b/module/user/view/login.html.php index 8490a2a58d..0530a028ad 100644 --- a/module/user/view/login.html.php +++ b/module/user/view/login.html.php @@ -11,6 +11,7 @@ include '../../common/view/header.lite.html.php'; if(empty($config->notMd5Pwd))js::import($jsRoot . 'md5.js'); ?> +user->error->loginTimeoutTip);?>
diff --git a/test/model/todo/createbycycle.php b/test/model/todo/createbycycle.php index a1639b9ed8..959f65f5d6 100755 --- a/test/model/todo/createbycycle.php +++ b/test/model/todo/createbycycle.php @@ -2,6 +2,7 @@ switchDB(); su('admin'); /** @@ -12,25 +13,28 @@ pid=1 测试创建周期日待办 >> 11 测试创建周期周待办 >> 9 -测试创建周期月待办 >> 70 +测试创建周期月待办 >> `%d` */ +$days = 31; +$begin = call_user_func_array('date', array('Y-m-d')); +$end = call_user_func_array('date', array('Y-m-d', strtotime("+$days days"))); $todo1 = new stdclass(); $todo1->name = 'cycle生成的待办1'; -$todo1->config = '{"specify":{"month":"0","day":"1"},"day":"1","type":"day","beforeDays":11,"end":"","begin":"2022-03-23"}'; +$todo1->config = '{"specify":{"month":"0","day":"1"},"day":"1","type":"day","beforeDays":11,"end":"' . $end . '","begin":"' . $begin . '"}'; $todo2 = new stdclass(); $todo2->name = 'cycle生成的待办2'; -$todo2->config = '{"specify":{"month":"0","day":"1"},"week":"2,4,7","type":"week","beforeDays":31,"end":"","begin":"2022-03-23"}'; +$todo2->config = '{"specify":{"month":"0","day":"1"},"week":"2,4,7","type":"week","beforeDays":31,"end":"' . $end . '","begin":"' . $begin . '"}'; $todo3 = new stdclass(); $todo3->name = 'cycle生成的待办3'; -$todo3->config = '{"specify":{"month":"0","day":"1"},"month":"1,8,13,15,27,29,30","type":"month","beforeDays":301,"end":"","begin":"2022-03-23"}'; +$todo3->config = '{"specify":{"month":"0","day":"1"},"month":"1,8,13,15,27,29,30","type":"month","beforeDays":301,"end":"' . $end . '","begin":"' . $begin . '"}'; $todo = new todoTest(); -r($todo->createByCycleTest($todo1)) && p() && e('11'); // 测试创建周期日待办 -r($todo->createByCycleTest($todo2)) && p() && e('9'); // 测试创建周期周待办 -r($todo->createByCycleTest($todo3)) && p() && e('70'); // 测试创建周期月待办 -system("./ztest init"); +r($todo->createByCycleTest($todo1)) && p() && e('11'); // 测试创建周期日待办 +r($todo->createByCycleTest($todo2)) && p() && e('9'); // 测试创建周期周待办 +r($todo->createByCycleTest($todo3)) && p() && e('`%d`'); // 测试创建周期月待办 +$db->restoreDB();