diff --git a/module/product/control.php b/module/product/control.php index b7be9b7d2c..8519c41426 100755 --- a/module/product/control.php +++ b/module/product/control.php @@ -832,6 +832,7 @@ class product extends control $this->view->browseType = $browseType; $this->view->param = $param; $this->view->storyType = $storyType; + $this->view->users = $this->loadModel('user')->getPairs('noletter|nodeleted'); $this->display(); } diff --git a/module/product/js/track.ui.js b/module/product/js/track.ui.js index d7a60b1d2a..279742ad6b 100644 --- a/module/product/js/track.ui.js +++ b/module/product/js/track.ui.js @@ -8,7 +8,7 @@ window.getItem = function(info) info.item.content.push({html: "
" + langStoryStatusList[info.item.status] + "
"}); info.item.content.push({html: "
" + langStoryStageList[info.item.stage] + '
'}) } - if(col == 'project' || col == 'execution') + else if(col == 'project' || col == 'execution') { let delayHtml = ''; let titleHtml = info.item.title; @@ -20,6 +20,37 @@ window.getItem = function(info) info.item.content.push({html: "
" + langProjectStatusList[info.item.status] + "
"}); info.item.content.push({component: 'ProgressCircle', props: {percent: info.item.progress, size: 24}}); } + else if(col == 'task') + { + console.log(info); + titleHtml = "" + info.item.title + ""; + info.item.title = {html: "
" + langTaskPriList[info.item.pri] + " " + titleHtml + '
'} + info.item.content = []; + if(info.item.parent == '-1') info.item.content.push({html: ""}); + info.item.content.push({html: "
" + langTaskStatusList[info.item.status] + "
"}); + if(info.item.assignedTo) info.item.content.push({html: " " + (typeof(users[info.item.assignedTo]) ? users[info.item.assignedTo] : info.item.assignedTo)}); + info.item.content.push({component: 'ProgressCircle', props: {percent: info.item.progress, size: 24}}); + } +} + +window.itemRender = function(info) +{ + if(info.col == 'task' && info.item.parent > '0') info.item.className.push('hidden parent-' + info.item.parent); +} + +window.toggleChildren = function(obj, parentID) +{ + console.log(obj); + if($(obj).hasClass('is-expanded')) + { + $(obj).removeClass('is-expanded').addClass('is-collapsed'); + $('.parent-' + parentID).addClass('hidden') + } + else + { + $(obj).removeClass('is-collapsed').addClass('is-expanded'); + $('.parent-' + parentID).removeClass('hidden') + } } window.canDrop = function(){ return false;} diff --git a/module/product/ui/track.html.php b/module/product/ui/track.html.php index d7dce3cb87..f3862dfd93 100644 --- a/module/product/ui/track.html.php +++ b/module/product/ui/track.html.php @@ -45,10 +45,15 @@ toolbar ); $this->loadModel('project'); -jsVar('langStoryPriList', $lang->story->priList); -jsVar('langStoryStatusList', $lang->story->statusList); -jsVar('langStoryStageList', $lang->story->stageList); +$this->loadModel('task'); +jsVar('langStoryPriList', $lang->story->priList); +jsVar('langStoryStatusList', $lang->story->statusList); +jsVar('langStoryStageList', $lang->story->stageList); jsVar('langProjectStatusList', $lang->project->statusList); +jsVar('langTaskPriList', $lang->task->priList); +jsVar('langTaskStatusList', $lang->task->statusList); +jsVar('langChildren', $lang->task->childrenAB); +jsVar('users', $users); empty($tracks) ? div(setClass('dtable-empty-tip bg-white shadow'), span(setClass('text-gray'), $lang->noData)) : div ( @@ -56,7 +61,7 @@ empty($tracks) ? div(setClass('dtable-empty-tip bg-white shadow'), span(setClass zui::kanbanList ( set::key('kanban'), - set::items(array(array('data' => $tracks, 'getItem' => jsRaw('window.getItem'), 'canDrop' => jsRaw('window.canDrop')))), + set::items(array(array('data' => $tracks, 'getItem' => jsRaw('window.getItem'), 'itemRender' => jsRaw('window.itemRender'), 'canDrop' => jsRaw('window.canDrop')))), set::height('calc(100vh - 130px)') ), pager(setClass('justify-end')) diff --git a/module/story/tao.php b/module/story/tao.php index 51e995a48a..9601529c13 100644 --- a/module/story/tao.php +++ b/module/story/tao.php @@ -2197,7 +2197,7 @@ class storyTao extends storyModel $executions = zget($projectGroup, 'execution', array()); $designs = zget($designGroup, 'design', array()); $commits = zget($designGroup, 'commit', array()); - $tasks = $this->dao->select('id,pri,status,name as title,assignedTo,story')->from(TABLE_TASK)->where('story')->in($storyIdList)->andWhere('deleted')->eq(0)->orderBy('parent')->fetchGroup('story', 'id'); + $tasks = $this->getTasksForTrack($storyIdList); $cases = $this->dao->select('id,pri,status,title,story')->from(TABLE_CASE)->where('story')->in($storyIdList)->andWhere('deleted')->eq(0)->fetchGroup('story', 'id'); $bugs = $this->dao->select('id,pri,status,title,story')->from(TABLE_BUG)->where('story')->in($storyIdList)->andWhere('deleted')->eq(0)->fetchGroup('story', 'id'); $storyGrade = $this->getGradeGroup(); @@ -2297,4 +2297,43 @@ class storyTao extends storyModel return $storyGroup; } + + /** + * 根据需求ID列表获取关联的任务 + * Get linked tasks by story id list. + * + * @param array $storyIdList + * @access public + * @return array + */ + public function getTasksForTrack(array $storyIdList): array + { + $stmt = $this->dao->select('id,pri,status,name as title,assignedTo,story,estimate,consumed,`left`,parent')->from(TABLE_TASK)->where('story')->in($storyIdList)->andWhere('deleted')->eq(0)->orderBy('parent')->query(); + $tasks = array(); + while($task = $stmt->fetch()) + { + $task->progress = 0; + if($task->consumed + $task->left) $task->progress = round(($task->consumed / ($task->consumed + $task->left)) * 100, 2); + + if($task->parent > 0 && isset($tasks[$task->parent])) + { + $tasks[$task->parent]->children[$task->id] = $task; + } + else + { + $tasks[$task->id] = $task; + } + } + + $taskGroup = array(); + foreach($tasks as $task) + { + $children = !empty($task->children) ? $task->children : array(); + unset($task->children); + + $taskGroup[$task->story][$task->id] = $task; + foreach($children as $subTask) $taskGroup[$subTask->story][$subTask->id] = $subTask; + } + return $taskGroup; + } }