* Add group tasks page.
This commit is contained in:
@@ -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';
|
||||
|
||||
@@ -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;}
|
||||
@@ -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
|
||||
);
|
||||
}
|
||||
@@ -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';
|
||||
|
||||
Reference in New Issue
Block a user