2023-05-16 10:50:42 +08:00

340 lines
14 KiB
PHP

<?php
/**
* Process a task, judge it's status.
* Extend for php warning.
*
* @param object $task
* @access private
* @return object
*/
public function processTask($task)
{
$today = helper::today();
/* Delayed or not?. */
if($task->status !== 'done' and $task->status !== 'cancel' and $task->status != 'closed')
{
if(!empty($task->deadline) and !helper::isZeroDate($task->deadline))
{
$delay = helper::diffDate($today, $task->deadline);
if($delay > 0) $task->delay = $delay;
}
}
/* Story changed or not. */
$task->needConfirm = false;
if(!empty($task->storyStatus) and $task->storyStatus == 'active' and $task->latestStoryVersion > $task->storyVersion) $task->needConfirm = true;
/* Set product type for task. */
if(isset($task->product) and $task->product)
{
$product = $this->loadModel('product')->getById($task->product);
$task->productType = $product->type;
}
/* Set closed realname. */
if($task->assignedTo == 'closed') $task->assignedToRealName = 'Closed';
/* Compute task progress. */
if($task->consumed == 0 and $task->left == 0)
{
$task->progress = 0;
}
elseif($task->consumed != 0 and $task->left == 0)
{
$task->progress = 100;
}
else
{
$task->progress = round($task->consumed / ($task->consumed + $task->left), 2) * 100;
}
if($task->mode == 'multi')
{
$teamMembers = $this->dao->select('t1.realname')->from(TABLE_USER)->alias('t1')
->leftJoin(TABLE_TASKTEAM)->alias('t2')
->on('t1.account = t2.account')
->where('t2.task')->eq($task->id)
->fetchPairs();
$task->teamMembers= join(',', array_keys($teamMembers));
}
return $task;
}
public function printCell($col, $task, $users, $browseType, $branchGroups, $modulePairs = array(), $mode = 'datatable', $child = false, $showBranch = false)
{
$canBatchEdit = common::hasPriv('task', 'batchEdit', !empty($task) ? $task : null);
$canBatchClose = (common::hasPriv('task', 'batchClose', !empty($task) ? $task : null) && strtolower($browseType) != 'closedBy');
$canBatchCancel = common::hasPriv('task', 'batchCancel', !empty($task) ? $task : null);
$canBatchChangeModule = common::hasPriv('task', 'batchChangeModule', !empty($task) ? $task : null);
$canBatchAssignTo = common::hasPriv('task', 'batchAssignTo', !empty($task) ? $task : null);
$canBatchAction = $canBatchEdit or $canBatchClose or $canBatchCancel or $canBatchChangeModule or $canBatchAssignTo;
$storyChanged = (!empty($task->storyStatus) and $task->storyStatus == 'active' and $task->latestStoryVersion > $task->storyVersion and !in_array($task->status, array('cancel', 'closed')));
$designChange = ($task->designName && $task->latestDesignVersion > $task->designVersion);
$canView = common::hasPriv('task', 'view');
$taskLink = helper::createLink('task', 'view', "taskID=$task->id");
$account = $this->app->user->account;
$id = $col->id;
if($col->show)
{
$class = "c-{$id}";
if($id == 'status') $class .= ' task-' . $task->status;
if($id == 'id') $class .= ' cell-id';
if($id == 'name') $class .= ' text-left';
if($id == 'deadline' and isset($task->delay)) $class .= ' text-center delayed';
if($id == 'assignedTo') $class .= ' has-btn text-left';
if($id == 'lane') $class .= ' text-left';
if(strpos('progress', $id) !== false) $class .= ' text-right';
$title = '';
if($id == 'name')
{
$title = " title='{$task->name}'";
if(!empty($task->children)) $class .= ' has-child';
}
if($id == 'story') $title = " title='{$task->storyTitle}'";
if($id == 'estimate' || $id == 'consumed' || $id == 'left')
{
$value = round($task->$id, 1);
$title = " title='{$value} {$this->lang->execution->workHour}'";
}
if($id == 'lane') $title = " title='{$task->lane}'";
echo "<td class='" . $class . "'" . $title . ">";
if($this->config->edition != 'open') $this->loadModel('flow')->printFlowCell('task', $task, $id);
switch($id)
{
case 'id':
if($canBatchAction)
{
echo html::checkbox('taskIDList', array($task->id => '')) . html::a(helper::createLink('task', 'view', "taskID=$task->id"), sprintf('%03d', $task->id));
}
else
{
printf('%03d', $task->id);
}
break;
case 'pri':
echo "<span class='label-pri label-pri-" . $task->pri . "' title='" . zget($this->lang->task->priList, $task->pri, $task->pri) . "'>";
echo zget($this->lang->task->priList, $task->pri, $task->pri);
echo "</span>";
break;
case 'name':
if($showBranch) $showBranch = isset($this->config->execution->task->showBranch) ? $this->config->execution->task->showBranch : 1;
if($task->parent > 0 and isset($task->parentName)) $task->name = "{$task->parentName} / {$task->name}";
if(!empty($task->product) and isset($branchGroups[$task->product][$task->branch]) and $showBranch) echo "<span class='label label-badge label-outline'>" . $branchGroups[$task->product][$task->branch] . '</span> ';
if($task->module and isset($modulePairs[$task->module])) echo "<span class='label label-gray label-badge'>" . $modulePairs[$task->module] . '</span> ';
if($task->parent > 0) echo '<span class="label label-badge label-light" title="' . $this->lang->task->children . '">' . $this->lang->task->childrenAB . '</span> ';
if(!empty($task->team)) echo '<span class="label label-badge label-light" title="' . $this->lang->task->multiple . '">' . $this->lang->task->multipleAB . '</span> ';
echo $canView ? html::a($taskLink, $task->name, null, "style='color: $task->color' title='$task->name'") : "<span style='color: $task->color'>$task->name</span>";
if(!empty($task->children)) echo '<a class="task-toggle" data-id="' . $task->id . '"><i class="icon icon-angle-right"></i></a>';
if($task->fromBug) echo html::a(helper::createLink('bug', 'view', "id=$task->fromBug"), "[BUG#$task->fromBug]", '', "class='bug'");
break;
case 'type':
echo $this->lang->task->typeList[$task->type];
break;
case 'status':
if($storyChanged)
{
print("<span class='status-story status-changed' title='{$this->lang->story->changed}'>{$this->lang->story->changed}</span>");
}
elseif($designChange)
{
print("<span class='status-design status-changed' title='{$this->lang->task->designChanged}'>{$this->lang->task->designChanged}</span>");
}
else
{
$statusLabel = $this->processStatus('task', $task);
print("<span class='status-task status-{$task->status}' title='{$statusLabel}'> " . $statusLabel . "</span>");
}
break;
case 'estimate':
echo round($task->estimate, 1) . ' ' . $this->lang->execution->workHourUnit;
break;
case 'consumed':
echo round($task->consumed, 1) . ' ' . $this->lang->execution->workHourUnit;
break;
case 'left':
echo round($task->left, 1) . ' ' . $this->lang->execution->workHourUnit;
break;
case 'design':
echo $task->designName ? html::a(helper::createLink('design', 'view', "id=$task->design"), $task->designName) : '';
break;
case 'progress':
echo "{$task->progress}%";
break;
case 'deadline':
if(substr($task->deadline, 0, 4) > 0) echo '<span>' . substr($task->deadline, 5, 6). '</span>';
break;
case 'openedBy':
echo zget($users, $task->openedBy);
break;
case 'openedDate':
echo substr($task->openedDate, 5, 11);
break;
case 'estStarted':
echo helper::isZeroDate($task->estStarted) ? '' : substr($task->estStarted, 5, 11);
break;
case 'realStarted':
echo helper::isZeroDate($task->realStarted) ? '' : substr($task->realStarted, 5, 11);
break;
case 'assignedTo':
$this->printAssignedHtml($task, $users);
break;
case 'lane':
echo mb_substr($task->lane, 0, 8);
break;
case 'assignedDate':
echo helper::isZeroDate($task->assignedDate) ? '' : substr($task->assignedDate, 5, 11);
break;
case 'finishedBy':
echo zget($users, $task->finishedBy);
break;
case 'finishedDate':
echo helper::isZeroDate($task->finishedDate) ? '' : substr($task->finishedDate, 5, 11);
break;
case 'canceledBy':
echo zget($users, $task->canceledBy);
break;
case 'canceledDate':
echo helper::isZeroDate($task->canceledDate) ? '' : substr($task->canceledDate, 5, 11);
break;
case 'closedBy':
echo zget($users, $task->closedBy);
break;
case 'closedDate':
echo helper::isZeroDate($task->closedDate) ? '' : substr($task->closedDate, 5, 11);
break;
case 'closedReason':
echo $this->lang->task->reasonList[$task->closedReason];
break;
case 'story':
if(!empty($task->storyID))
{
if(common::hasPriv('story', 'view'))
{
echo html::a(helper::createLink('story', 'view', "storyid=$task->storyID", 'html', true), "<i class='icon icon-{$this->lang->icons['story']}'></i>", '', "class='iframe' title='{$task->storyTitle}'");
}
else
{
echo "<i class='icon icon-{$this->lang->icons['story']}' title='{$task->storyTitle}'></i>";
}
}
break;
case 'mailto':
$mailto = explode(',', $task->mailto);
foreach($mailto as $account)
{
$account = trim($account);
if(empty($account)) continue;
echo zget($users, $account) . ' &nbsp;';
}
break;
case 'lastEditedBy':
echo zget($users, $task->lastEditedBy);
break;
case 'lastEditedDate':
echo helper::isZeroDate($task->lastEditedDate) ? '' : substr($task->lastEditedDate, 5, 11);
break;
case 'actions':
echo $this->buildOperateMenu($task, 'browse');
break;
}
echo '</td>';
}
}
/**
* Build task browse action menu.
*
* @param object $task
* @access public
* @return string
*/
public function buildOperateBrowseMenu($task)
{
$menu = '';
$params = "taskID=$task->id";
$storyChanged = !empty($task->storyStatus) && $task->storyStatus == 'active' && $task->latestStoryVersion > $task->storyVersion && !in_array($task->status, array('cancel', 'closed'));
$designChange = isset($task->designName) ? $task->designName && $task->latestDesignVersion > $task->designVersion : false;
if($storyChanged) return $this->buildMenu('task', 'confirmStoryChange', $params, $task, 'browse', '', 'hiddenwin');
if($designChange) return $this->buildMenu('task', 'confirmDesignChange', $params, $task, 'browse', 'search', 'hiddenwin');
$canStart = ($task->status != 'pause' and common::hasPriv('task', 'start'));
$canRestart = ($task->status == 'pause' and common::hasPriv('task', 'restart'));
$canFinish = common::hasPriv('task', 'finish');
$canClose = common::hasPriv('task', 'close');
$canRecordEstimate = common::hasPriv('task', 'recordEstimate');
$canEdit = common::hasPriv('task', 'edit');
$canBatchCreate = ($this->config->vision == 'rnd' and common::hasPriv('task', 'batchCreate'));
if($task->status != 'pause') $menu .= $this->buildMenu('task', 'start', $params, $task, 'browse', '', '', 'iframe', true);
if($task->status == 'pause') $menu .= $this->buildMenu('task', 'restart', $params, $task, 'browse', '', '', 'iframe', true);
$menu .= $this->buildMenu('task', 'finish', $params, $task, 'browse', '', '', 'iframe', true);
$menu .= $this->buildMenu('task', 'close', $params, $task, 'browse', '', '', 'iframe', true);
if(($canStart or $canRestart or $canFinish or $canClose) and ($canRecordEstimate or $canEdit or $canBatchCreate))
{
$menu .= "<div class='dividing-line'></div>";
}
$menu .= $this->buildMenu('task', 'recordEstimate', $params, $task, 'browse', 'time', '', 'iframe', true);
$menu .= $this->buildMenu('task', 'edit', $params, $task, 'browse');
if($this->config->vision == 'rnd')
{
$menu .= $this->buildMenu('task', 'batchCreate', "execution=$task->execution&storyID=$task->story&moduleID=$task->module&taskID=$task->id&ifame=0", $task, 'browse', 'split', '', '', '', '', $this->lang->task->children);
}
return $menu;
}
/**
* Gets the version record of the task.
*
* @param $taskID
* @param $version
* @access public
* @return void
*/
public function getTaskSpec($taskID, $version)
{
return $this->dao->select('*')->from(TABLE_TASKSPEC)
->where('task')->eq($taskID)
->andWhere('version')->eq($version)
->fetch();
}
public function activate($taskID, $extra = '')
{
$changes = parent::activate($taskID, $extra);
$now = helper::now();
$this->dao->update(TABLE_TASK)->set('activatedDate')->eq($now)->where('id')->eq($taskID)->exec();
return $changes;
}
public function update($taskID)
{
$result = parent::update($taskID);
/* Update planDuration. */
if($result)
{
$estStarted = $this->post->estStarted;
$deadline = $this->post->deadline;
$planDuration = $this->loadModel('holiday')->getActualWorkingDays($estStarted, $deadline);
$planDuration = count($planDuration);
$this->dao->update(TABLE_TASK)->set('planDuration')->eq($planDuration)->where('id')->eq($taskID)->exec();
}
return $result;
}