From 2516d3002df8a1d4cd89ebba3df84a19cff1397d Mon Sep 17 00:00:00 2001 From: sunguangming Date: Wed, 2 Aug 2023 16:24:51 +0800 Subject: [PATCH] * Add group tasks page. --- module/execution/control.php | 8 +- module/execution/css/grouptask.ui.css | 36 +++ module/execution/ui/grouptask.html.php | 378 +++++++++++++++++++++++++ module/index/config.php | 1 - 4 files changed, 416 insertions(+), 7 deletions(-) create mode 100644 module/execution/css/grouptask.ui.css create mode 100644 module/execution/ui/grouptask.html.php diff --git a/module/execution/control.php b/module/execution/control.php index 4b1d8bafc0..3c05cca0a9 100644 --- a/module/execution/control.php +++ b/module/execution/control.php @@ -246,12 +246,6 @@ class execution extends control $execution = $this->commonAction($executionID); $executionID = $execution->id; - /* Save session. */ - $this->app->session->set('taskList', $this->app->getURI(true), 'execution'); - - /* Header and session. */ - $this->view->title = $execution->name . $this->lang->colon . $this->lang->execution->task; - /* Get tasks and group them. */ if(empty($groupBy))$groupBy = 'story'; if($groupBy == 'story' and $execution->lifetime == 'ops') @@ -433,6 +427,8 @@ class execution extends control /* Assign. */ $this->app->loadLang('tree'); + + $this->view->title = $execution->name . $this->lang->colon . $this->lang->execution->task; $this->view->members = $this->execution->getTeamMembers($executionID); $this->view->tasks = $groupTasks; $this->view->tabID = 'task'; diff --git a/module/execution/css/grouptask.ui.css b/module/execution/css/grouptask.ui.css new file mode 100644 index 0000000000..dd1dac8067 --- /dev/null +++ b/module/execution/css/grouptask.ui.css @@ -0,0 +1,36 @@ +.table-group-btns {width: 200px;} +.group-menu {padding: 1px 5px !important;} +.group-menu .btn {font-size: 14px; color: #3C4353;} +.fixed-header-copy .group-menu .btn {background-color: transparent; color: #fff;} +.fixed-header-copy .group-menu .btn .icon {background: transparent !important; color: #fff; opacity: .5;} +.icon-caret-right.text-muted {color: #CBD0DB;} +.segments-list {max-width: 700px; margin: 10px;} +.segments-list .table-col {vertical-align: middle;} +.segments-list .segments {width: 150px; margin: 0 auto;} +.segment {float: left; line-height: 18px;} +.segment + .segment > .segment-title:before {content: '/'; display: inline-block; padding: 0 4px;} +.segment + .segment > .segment-value {padding-left: 10px;} +.segment-title {color: #828A9D; font-size: 12px;} +.segment-value {font-weight: bold;} + +.table {background: #fff} +.table .divider {border-bottom: 10px solid #efefef;} +.table .c-side {border-right: 10px solid #efefef !important;} +.table .divider-top {border-top: 10px solid #efefef;} + +.table .c-user{width: 100px} +.table .c-progress {width: 60px;} +.table th{text-align: center} +.table .text-center {text-align: center} +.table .text-right {text-align: right} + +.group-menu > .dropdown > .dropdown-menu {right: 0; width: 100%;} + +.c-side {padding: 0 !important; position: relative; min-height: 100px; width: 200px} +.group-header > a {line-height: 20px; display: block; max-height: 40px; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden;} +.group-header > .groupSummary {margin-top: 10px; line-height: 24px;} +.main-table > .table {box-shadow: none;} +.c-side-lg .group-header {display: flex; flex-direction: column; position: absolute; top: 0; right: 0; left: 0; bottom: 0; justify-content: space-between;} +.is-firefox .group-header:before {content: ' '; position: absolute; top: 0; right: 0; left: 0; bottom: 0; background: #fff; z-index: 0;} +.is-firefox .group-header > a, +.is-firefox .group-header > .groupSummary {position: relative; z-index: 1;} diff --git a/module/execution/ui/grouptask.html.php b/module/execution/ui/grouptask.html.php new file mode 100644 index 0000000000..f4aa53bd5d --- /dev/null +++ b/module/execution/ui/grouptask.html.php @@ -0,0 +1,378 @@ + + * @package execution + * @link https://www.zentao.net + */ +namespace zin; + +$groupList = array(); +foreach($lang->execution->groups as $key => $value) +{ + $link = createLink('executon', 'grouptask', "executionID={$executionID}&groupBy={$key}"); + $groupList[] = array( + 'text' => $value, + 'url' => $link, + ); +} + +$thead = function() use($lang, $groupList, $groupBy, $allCount) +{ + return h::tr + ( + $allCount ? setClass('divider') : null, + h::th + ( + setClass('c-side text-left has-btn group-menu'), + dropdown + ( + btn + ( + setClass('ghost btn square btn-default'), + $lang->execution->groups[$groupBy] + ), + set::items($groupList) + ) + ), + h::th + ( + setClass('c-id'), + $lang->task->id + ), + h::th + ( + setClass('c-pri'), + $lang->priAB + ), + h::th + ( + setClass('c-name'), + $lang->task->name + ), + h::th + ( + setClass('c-status'), + $lang->task->status + ), + h::th + ( + setClass('c-user'), + $lang->task->assignedTo + ), + h::th + ( + setClass('c-user'), + $lang->task->finishedBy + ), + h::th + ( + setClass('c-hours'), + $lang->task->estimateAB + ), + h::th + ( + setClass('c-hours'), + $lang->task->consumedAB + ), + h::th + ( + setClass('c-hours'), + $lang->task->leftAB + ), + h::th + ( + setClass('c-progress'), + $lang->task->progressAB + ), + h::th + ( + setClass('c-type'), + $lang->typeAB + ), + h::th + ( + setClass('c-date'), + $lang->task->deadline + ), + h::th + ( + setClass('c-actions'), + $lang->actions + ) + ); +}; + +$tbody = function() use($tasks, $lang, $groupBy, $users) +{ + $tbody = array(); + $groupIndex = 1; + foreach($tasks as $groupKey => $groupTasks) + { + $groupWait = 0; + $groupDone = 0; + $groupDoing = 0; + $groupClosed = 0; + $groupEstimate = 0.0; + $groupConsumed = 0.0; + $groupLeft = 0.0; + + $groupName = $groupKey; + if($groupBy == 'story') $groupName = empty($groupName) ? $lang->task->noStory : zget($groupByList, $groupKey); + if($groupBy == 'assignedTo' and $groupName == '') $groupName = $this->lang->task->noAssigned; + + $groupSum = 0; + foreach($groupTasks as $taskKey => $task) + { + if($groupBy == 'story') + { + if($task->parent >= 0) + { + $groupEstimate += $task->estimate; + $groupConsumed += $task->consumed; + if($task->status != 'cancel' && $task->status != 'closed') $groupLeft += $task->left; + } + } + else + { + if($task->parent >= 0) + { + $groupEstimate += $task->estimate; + $groupConsumed += $task->consumed; + if($groupBy == 'status' || ($task->status != 'cancel' && $task->status != 'closed')) $groupLeft += $task->left; + } + } + + if($task->status == 'wait') $groupWait++; + if($task->status == 'doing') $groupDoing++; + if($task->status == 'done') $groupDone++; + if($task->status == 'closed') $groupClosed++; + } + + $groupSum = count($groupTasks); + + $i = 0; + foreach($groupTasks as $task) + { + $assignedToStyle = $task->assignedTo == $app->user->account ? "style='color:red'" : ''; + $taskLink = $this->createLink('task','view',"taskID=$task->id"); + + $tbody[] = h::tr + ( + set(array('data-id' => $groupIndex)), + ($groupIndex > 1 and $i == 0) ? setClass('divider-top') : null, + $i == 0 ? h::td + ( + $groupSum > 4 ? setClass('c-side text-left group-toggle text-top c-side-lg') : setClass('c-side text-left group-toggle text-top'), + set::rowspan($groupSum), + div + ( + setClass('group-header'), + a + ( + setClass('groupBtn'), + set::href('###'), + icon('caret-down'), + $groupName, + ), + div + ( + setClass('groupSummary small'), + ($groupBy == 'assignedTo' and isset($members[$task->assignedTo])) ? html(sprintf($lang->execution->memberHoursAB, zget($users, $task->assignedTo), $members[$task->assignedTo]->totalHours)) : null, + html(sprintf($lang->execution->groupSummaryAB, $groupSum, $groupWait, $groupDoing, $groupEstimate . $lang->execution->workHourUnit, $groupConsumed . $lang->execution->workHourUnit, $groupLeft . $lang->execution->workHourUnit)) + ), + ), + ) : null, + h::td(sprintf('%03d', (string)$task->id)), + h::td + ( + span + ( + setClass("pri-{$task->pri}"), + $task->pri + ) + ), + h::td + ( + !empty($task->team) ? span(setClass('label gray-pale rounded-xl'), $lang->task->multipleAB) : null, + $task->parent > 0 ? span(setClass('label gray-pale rounded-xl'), $lang->task->childrenAB) : null, + (isset($task->children) && $task->children == true) ? span(setClass('label gray-pale rounded-xl'), $lang->task->parentAB) : null, + a(set::href(createLink('task', 'view', "task=$task->id")), $task->name) + ), + h::td + ( + setClass('text-center'), + span + ( + setClass("status-{$task->status}"), + $lang->task->statusList[$task->status] + ) + ), + h::td + ( + setClass('text-center'), + span + ( + set(array('style' => $assignedToStyle)), + $task->assignedToRealName + ) + ), + h::td + ( + setClass('text-center'), + \zget($users, $task->finishedBy) + ), + h::td + ( + setClass('text-right'), + $task->estimate . $lang->execution->workHourUnit + ), + h::td + ( + setClass('text-right'), + $task->consumed . $lang->execution->workHourUnit + ), + h::td + ( + setClass('text-right'), + $task->left . $lang->execution->workHourUnit + ), + h::td + ( + setClass('text-right'), + $task->progress . '%' + ), + h::td + ( + setClass('text-center'), + \zget($lang->task->typeList, $task->type) + ), + h::td + ( + setClass('text-center'), + isset($task->delay) ? setClass('delayed') : null, + (substr($task->deadline, 0, 4) > 0) ? substr($task->deadline, 5, 6) : null + ), + common::canModify('execution', $execution) ? h::td + ( + setClass('text-center'), + common::hasPriv('task', 'assignTo') ? btn + ( + set + ( + array + ( + 'url' => createLink('task', 'assignTo', "executionID=$task->execution&taskID=$task->id"), + 'data-toggle' => 'modal', + 'class' => 'btn ghost toolbar-item text-primary square size-sm', + 'icon' => 'hand-right' + ) + ) + ) : null, + common::hasPriv('task', 'edit') ? btn + ( + set + ( + array + ( + 'url' => createLink('task', 'edit', "taskID=$task->id"), + 'class' => 'btn ghost toolbar-item text-primary square size-sm', + 'icon' => 'edit' + ) + ) + ) : null, + common::hasPriv('task', 'edit') ? btn + ( + set + ( + array + ( + 'url' => createLink('task', 'delete', "taskID=$task->id"), + 'data-confirm' => $lang->task->confirmDelete, + 'class' => 'btn ghost toolbar-item text-primary square size-sm ajax-submit', + 'icon' => 'trash' + ) + ) + ) : null, + ) + : h::td() + ); + + $i ++; + } + + if($i != 0) + { + $tbody[] = h::tr + ( + $groupIndex > 1 ? setClass('hidden group-toggle group-summary divider-top') : setClass('hidden group-summary group-toggle'), + set(array('data-id' => $groupIndex)), + h::td + ( + setClass('c-side'), + a + ( + setClass('summaryBtn'), + set::href('###'), + icon('caret-right'), + $groupName, + ), + ), + h::td + ( + set::colspan(13), + ($groupBy == 'assignedTo' and isset($members[$task->assignedTo])) ? html(sprintf($lang->execution->memberHours, zget($users, $task->assignedTo), $members[$task->assignedTo]->totalHours)) : null, + ($groupBy == 'assignedTo' and $task->assignedTo and !isset($members[$task->assignedTo])) ? html(sprintf($lang->execution->memberHours, zget($users, $task->assignedTo), '0.0')) : null, + ($groupBy == 'assignedTo' and empty($task->assignedTo)) ? div + ( + setClass('table-col'), + div + ( + setClass('segments'), + div + ( + setClass('segment'), + div + ( + setClass('segment-title'), + $groupName + ) + ) + ) + ) : null, + html(sprintf($lang->execution->countSummary, $groupSum, $groupDoing, $groupWait)), + html(sprintf($lang->execution->timeSummary, $groupEstimate . $lang->execution->workHourUnit, $groupConsumed . $lang->execution->workHourUnit, $groupLeft . $lang->execution->workHourUnit)), + ) + ); + } + + $groupIndex ++; + } + + return $tbody; +}; + +if($tasks) +{ + div + ( + set::id('tasksTable'), + h::table + ( + setClass('table condensed'), + $thead(), + $tbody(), + ) + ); +} +else +{ + div + ( + setClass('canvas text-center py-8'), + $lang->task->noTask + ); +} diff --git a/module/index/config.php b/module/index/config.php index c5990c366b..e287b8f24f 100644 --- a/module/index/config.php +++ b/module/index/config.php @@ -28,7 +28,6 @@ $config->index->oldPages[] = 'product-kanban'; $config->index->oldPages[] = 'program-kanban'; $config->index->oldPages[] = 'project-kanban'; $config->index->oldPages[] = 'execution-taskkanban'; -$config->index->oldPages[] = 'execution-grouptask'; $config->index->oldPages[] = 'kanban-space'; $config->index->oldPages[] = 'screen-browse'; $config->index->oldPages[] = 'pivot-preview';