* Add group tasks page.

This commit is contained in:
sunguangming
2023-08-02 16:25:03 +08:00
parent 118fe0e21a
commit 2516d3002d
4 changed files with 416 additions and 7 deletions
+2 -6
View File
@@ -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';
+36
View File
@@ -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;}
+378
View File
@@ -0,0 +1,378 @@
<?php
declare(strict_types=1);
/**
* The group task view file of execution module of ZenTaoPMS.
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @author Sun Guangming<sunguangming@easycorp.ltd>
* @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
);
}
-1
View File
@@ -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';