Files
EasySoft-ZenTaoPMS/module/project/ui/view.html.php
T
2023-07-07 08:27:40 +08:00

518 lines
14 KiB
PHP

<?php
declare(strict_types=1);
/**
* The view file of project 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 Yanyi Cao <caoyanyi@easycorp.ltd>
* @package project
* @link https://www.zentao.net
*/
namespace zin;
$blocks = array(
array(
'id' => 1,
'size' => 'sm',
'domID' => 'dynamicBlock',
),
array(
'id' => 2,
'size' => 'sm',
'domID' => 'memberBlock',
),
array(
'id' => 3,
'size' => 'xl',
'domID' => 'basicBlock',
),
array(
'id' => 4,
'size' => 'smWide',
'domID' => 'historyBlock',
)
);
jsVar('blocks', $blocks);
jsVar('confirmDeleteTip', $lang->project->confirmDelete);
/* Construct suitable actions for the current project. */
$operateMenus = array();
foreach($config->project->view->operateList['main'] as $operate)
{
if(!common::hasPriv('project', $operate)) continue;
if(!$this->project->isClickable($project, $operate)) continue;
$action = $config->project->actionList[$operate];
$action['text'] = $action['hint'];
$operateMenus[] = $action;
}
/* Construct common actions for project. */
$commonActions = array();
foreach($config->project->view->operateList['common'] as $operate)
{
if(!common::hasPriv('project', $operate)) continue;
$settings = $config->project->actionList[$operate];
$settings['text'] = '';
$commonActions[] = $settings;
}
dashboard
(
setID('projectDashBoard'),
set::blocks($blocks),
set::blockMenu(false),
);
div
(
setClass('w-2/3 text-center fixed actions-menu'),
floatToolbar
(
isAjaxRequest('modal') ? null : to::prefix(backBtn(set::icon('back'), $lang->goback)),
set::main($operateMenus),
set::suffix($commonActions),
set::object($project)
)
);
div
(
setID('dynamicBlock'),
setClass('hidden'),
panel
(
to::heading
(
div
(
set('class', 'panel-title'),
$lang->execution->latestDynamic,
)
),
to::headingActions
(
common::hasPriv('project', 'dynamic') ? btn
(
setClass('ghost text-gray'),
set::url(createLink('project', 'dynamic', "projectID={$projectID}&type=all")),
$lang->more
) : null
),
set::bodyClass('pt-0'),
dynamic()
)
);
/* Related members. */
$membersDom = array();
foreach(array('PM', 'PO', 'QD', 'RD') as $field)
{
if(empty($project->$field)) continue;
$membersDom[] = div
(
setClass('flex-initial w-1/2 py-1'),
icon('person', setClass('mr-2')),
zget($users, $project->$field),
span
(
setClass('text-gray ml-2'),
"( {$lang->project->$field} )"
)
);
unset($teamMembers[$project->$field]);
}
$memberCount = count($membersDom);
foreach($teamMembers as $teamMember)
{
if($memberCount >= 10) break;
$membersDom[] = div
(
setClass('flex-initial w-1/2 py-1'),
icon('person', setClass('mr-2')),
zget($users, $teamMember->account),
);
$memberCount ++;
}
if(common::hasPriv('project', 'manageMembers'))
{
$membersDom[] = div
(
setClass('flex-initial w-1/2 py-1'),
a
(
setClass('ghost text-gray'),
icon('plus', setClass('bg-primary-50 text-primary mr-2')),
span($lang->project->manageMembers),
set::href(createLink('project', 'manageMembers', "projectID={$projectID}"))
)
);
}
div
(
setID('memberBlock'),
setClass('hidden'),
panel
(
to::heading
(
div
(
set('class', 'panel-title'),
$lang->execution->relatedMember
)
),
to::headingActions
(
common::hasPriv('project', 'team') ? btn
(
setClass('ghost text-gray'),
set::url(createLink('project', 'team', "projectID={$projectID}")),
$lang->more
) : null
),
set::bodyClass('flex flex-wrap pt-0'),
$membersDom
)
);
/* History list. */
div
(
setID('historyBlock'),
setClass('hidden'),
div
(
history()
)
);
/* Basic info. */
$programDom = null;
if($project->grade > 1)
{
foreach($programList as $programID => $name)
{
if(common::hasPriv('program', 'product'))
{
$programList[$programID] = html::a
(
$this->createLink('program', 'product', "programID={$programID}"),
$name
);
}
}
$programDom = div
(
icon('program mr-2'),
html($programList ? implode('/ ', $programList) : '')
);
}
$productsDom = array();
if(!empty($project->hasProduct))
{
foreach($products as $productID => $product)
{
foreach($product->branches as $branchID)
{
$branchName = isset($branchGroups[$productID][$branchID]) ? '/' . $branchGroups[$productID][$branchID] : '';
$productsDom[] = div
(
setClass('flex-initial w-1/2 py-1'),
icon('product mr-2'),
a
(
set::href(createLink('product', 'browse', "productID=$productID&branch=$branchID")),
span($product->name . $branchName)
)
);
}
}
}
$plansDom = array();
foreach($products as $productID => $product)
{
foreach($product->plans as $planIDList)
{
$planIDList = explode(',', $planIDList);
foreach($planIDList as $planID)
{
if(isset($planGroup[$productID][$planID]))
{
$plansDom[] = div
(
setClass('mt-2 clip'),
hasPriv('productplan', 'view') ? a
(
set::href(createLink('productplan', 'view', "planID={$planID}")),
icon('calendar text-gray mr-1'),
$product->name . '/' . $planGroup[$productID][$planID]
) : span
(
$product->name . '/' . $planGroup[$productID][$planID]
)
);
}
}
}
}
$basicInfo = null;
if(empty($project->hasProduct) && !empty($config->URAndSR) && $project->model !== 'kanban' && isset($lang->project->menu->storyGroup))
{
$basicInfo = tableData
(
set::useTable(false),
item
(
set::name($lang->story->common),
$statData->storyCount
),
item
(
set::name($lang->requirement->common),
$statData->requirementCount
),
item
(
set::name($lang->task->common),
$statData->taskCount
),
item
(
set::name($lang->bug->common),
$statData->bugCount
),
item
(
set::name($lang->project->budget),
$statData->budget
),
);
}
else
{
$basicInfo = tableData
(
set::useTable(false),
item
(
set::name($lang->story->common),
$statData->storyCount
),
item
(
set::name($lang->task->common),
$statData->taskCount
),
item
(
set::name($lang->bug->common),
$statData->bugCount
),
item
(
set::name($lang->project->budget),
$statData->budget
),
);
}
$totalEstimate = $workhour->totalConsumed + $workhour->totalLeft;
$progress = 0;
if($project->model == 'waterfall')
{
$progress = $this->project->getWaterfallProgress($project->id);
}
elseif($totalEstimate > 0)
{
$progress = floor($workhour->totalConsumed / $totalEstimate * 1000) / 1000 * 100;
}
$aclList = $project->parent ? $lang->project->subAclList : $lang->project->aclList;
div
(
setID('basicBlock'),
setClass('hidden'),
sectionList
(
section
(
setClass('border-b pb-4'),
div
(
label
(
setClass('text-dark'),
$project->id
),
!empty($config->setCode) ? label
(
setClass('dark-outline text-dark mx-2'),
$project->code
) : null,
span(setClass('article-h2'), $project->name),
),
$project->desc ? div
(
setClass('mt-2'),
$project->desc
) : null,
div
(
setClass('mt-2'),
$config->vision == 'rnd' ? label
(
setClass('secondary-pale ring-secondary text-primary'),
zget($lang->project->projectTypeList, $project->hasProduct)
) : null,
$project->deleted ? label
(
setClass('danger-outline text-danger ml-2'),
$lang->project->deleted
) : null,
$project->lifetime ? label
(
setClass('secondary-outline text-primary ml-2'),
zget($lang->execution->lifeTimeList, $project->lifetime, '')
) : null,
isset($project->delay) ? label
(
setClass('danger-outline text-danger ml-2'),
$lang->project->delayed
) : null,
label
(
setClass("status-{$project->status} ml-2"),
$this->processStatus('project', $project)
),
)
),
section
(
setClass('border-b pb-4'),
set::title($lang->project->parent),
$programDom
),
!empty($project->hasProduct) ? section
(
setClass('border-b pb-4 linked-products'),
set::title($lang->project->manageProducts),
to::actions(btn
(
setClass('ghost text-gray'),
set::url(createLink('project', 'manageproducts', "projectID={$project->id}")),
$lang->more
)),
div
(
setClass('flex flex-wrap'),
$productsDom
)
) : null,
section
(
setClass('border-b pb-4'),
set::title($lang->execution->linkPlan),
$plansDom
),
section
(
setClass('border-b pb-4'),
set::title($lang->execution->lblStats),
div
(
setClass('flex flex-nowrap items-center'),
span($lang->project->progress . ' ' . $progress . $lang->percent),
div
(
setClass('progress flex-auto ml-2 h-2'),
div
(
setClass('progress-bar'),
set('role', 'progressbar'),
setStyle(['width' => $progress . $lang->percent]),
)
)
),
div
(
setClass('pt-1 project-info project-statitic-hours'),
tableData
(
set::useTable(false),
item
(
set::name($lang->project->begin),
$project->begin
),
item
(
set::name($lang->project->realBeganAB),
helper::isZeroDate($project->realBegan) ? '' : $project->realBegan
),
item
(
set::name($lang->project->end),
$project->end = $project->end == LONG_TIME ? $this->lang->project->longTime : $project->end
),
item
(
set::name($lang->project->realEndAB),
helper::isZeroDate($project->realEnd) ? '' : $project->realEnd
),
item
(
set::name($lang->execution->totalEstimate),
(float)$workhour->totalEstimate . $lang->execution->workHour
),
item
(
set::name($lang->execution->totalDays),
(float)$project->days . $lang->execution->day
),
item
(
set::name($lang->execution->totalConsumed),
(float)$workhour->totalConsumed . $lang->execution->workHour
),
item
(
set::name($lang->execution->totalHours),
(float)$workhour->totalHours . $lang->execution->workHour
),
item
(
set::name($lang->execution->totalLeft),
(float)$workhour->totalLeft . $lang->execution->workHour
),
)
)
),
section
(
setClass('border-b pb-4 project-info'),
set::title($lang->execution->basicInfo),
$basicInfo
),
section
(
set::title($lang->project->acl),
p($aclList[$project->acl])
)
)
);
render();