Merge branch 'stagetasktree'
This commit is contained in:
@@ -271,6 +271,7 @@ $filter->project->task->cookie['projectTaskOrder'] = 'reg::orderBy';
|
||||
$filter->project->task->cookie['windowWidth'] = 'int';
|
||||
$filter->project->export->cookie['checkedItem'] = 'reg::checked';
|
||||
$filter->project->execution->cookie['pagerExecutionAll'] = 'int';
|
||||
$filter->project->execution->cookie['showTask'] = 'code';
|
||||
|
||||
$filter->projectstory->story->cookie['storyModuleParam'] = 'int';
|
||||
$filter->projectstory->story->cookie['pagerProductBrowse'] = 'int';
|
||||
|
||||
@@ -245,7 +245,7 @@ $lang->scrum->menu->settings['subMenu']->group = array('link' => "{$lang->
|
||||
/* Waterfall menu. */
|
||||
$lang->waterfall->menu = new stdclass();
|
||||
$lang->waterfall->menu->index = array('link' => "$lang->dashboard|project|index|project=%s");
|
||||
$lang->waterfall->menu->execution = array('link' => "{$lang->stage->common}|project|execution|status=all&projectID=%s", 'subModule' => 'programplan');
|
||||
$lang->waterfall->menu->execution = array('link' => "{$lang->stage->common}|project|execution|status=all&projectID=%s", 'subModule' => 'programplan,task');
|
||||
$lang->waterfall->menu->story = array('link' => "$lang->SRCommon|projectstory|story|project=%s", 'subModule' => 'projectstory,tree', 'exclude' => 'projectstory-track');
|
||||
$lang->waterfall->menu->design = array('link' => "{$lang->design->common}|design|browse|project=%s");
|
||||
$lang->waterfall->menu->qa = array('link' => "{$lang->qa->common}|project|bug|projectID=%s", 'subModule' => 'testcase,testtask,bug,testreport', 'alias' => 'bug,testtask,testcase,testreport');
|
||||
|
||||
@@ -3668,18 +3668,6 @@ class execution extends control
|
||||
$from = $this->app->tab;
|
||||
if($from == 'execution') $this->session->set('executionList', $this->app->getURI(true), 'execution');
|
||||
|
||||
if($from == 'project')
|
||||
{
|
||||
$projects = $this->project->getPairsByProgram();
|
||||
$projectID = $this->project->saveState($projectID, $projects);
|
||||
$project = $this->loadModel('project')->getByID($projectID);
|
||||
$this->view->project = $project;
|
||||
$this->project->setMenu($projectID);
|
||||
|
||||
if(!$projectID) return print(js::locate($this->createLink('project', 'browse')));
|
||||
if(!empty($project->model) and $project->model == 'kanban' and !(defined('RUN_MODE') and RUN_MODE == 'api')) return print(js::locate($this->createLink('project', 'index', "projectID=$projectID")));
|
||||
}
|
||||
|
||||
if($this->app->viewType == 'mhtml')
|
||||
{
|
||||
if($this->app->rawModule == 'project' and $this->app->rawMethod == 'execution')
|
||||
|
||||
@@ -4305,6 +4305,100 @@ class executionModel extends model
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print execution nested list.
|
||||
*
|
||||
* @param object $execution
|
||||
* @param int $isChild
|
||||
* @param array $users
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function printNestedList($execution, $isChild = false, $users, $productID)
|
||||
{
|
||||
$this->loadModel('task');
|
||||
$this->loadModel('execution');
|
||||
$this->loadModel('programplan');
|
||||
|
||||
if(!$isChild)
|
||||
{
|
||||
$trClass = 'is-top-level table-nest-child-hide';
|
||||
$trAttrs = "data-id='$execution->id' data-order='$execution->order' data-nested='true'";
|
||||
}
|
||||
else
|
||||
{
|
||||
$trClass = 'is-nest-child';
|
||||
$trAttrs = "data-id={$execution->id} data-parent={$execution->parent}";
|
||||
$trAttrs .= " data-nest-parent='$execution->parent' data-order='$execution->order' data-nest-path=',$execution->parent,$execution->id,'";
|
||||
}
|
||||
|
||||
$burns = join(',', $execution->burns);
|
||||
echo "<tr $trAttrs class=$trClass>";
|
||||
echo "<td><span id=$execution->id class='table-nest-icon icon table-nest-toggle'></span>";
|
||||
if($this->config->systemMode == 'new')
|
||||
{
|
||||
$spanClass = $execution->type == 'stage' ? 'label-warning' : 'label-info';
|
||||
echo "<span class='project-type-label label label-outline $spanClass'>{$this->lang->execution->typeList[$execution->type]}</span>";
|
||||
}
|
||||
echo html::a(helper::createLink('execution', 'view', "executionID=$execution->id"), $execution->name);
|
||||
echo '<td>' . zget($users, $execution->PM) . '</td>';
|
||||
echo "<td class='status-{$execution->status}'>" . zget($this->lang->project->statusList, $execution->status) . '</td>';
|
||||
echo '<td>' . html::ring($execution->hours->progress) . '</td>';
|
||||
echo '<td>' . $execution->begin . '</td>';
|
||||
echo '<td>' . $execution->end . '</td>';
|
||||
echo "<td class='hours' title='{$execution->hours->totalEstimate}{$this->lang->execution->workHour}'>" . $execution->hours->totalEstimate . $this->lang->execution->workHourUnit . '</td>';
|
||||
echo "<td class='hours' title='{$execution->hours->totalConsumed}{$this->lang->execution->workHour}'>" . $execution->hours->totalConsumed . $this->lang->execution->workHourUnit . '</td>';
|
||||
echo "<td class='hours' title='{$execution->hours->totalLeft}{$this->lang->execution->workHour}'>" . $execution->hours->totalLeft . $this->lang->execution->workHourUnit . '</td>';
|
||||
echo "<td id='spark-{$execution->id} class='sparkline text-left no-padding' values='$burns'></td>";
|
||||
echo '<td class="c-actions">';
|
||||
common::printIcon('execution', 'start', "executionID={$execution->id}", $execution, 'list', '', '', 'iframe', true);
|
||||
$class = !empty($execution->children) ? 'disabled' : '';
|
||||
common::printIcon('task', 'create', "executionID={$execution->id}", $execution, 'list', '', '', $class, false, "data-app='execution'");
|
||||
|
||||
if($execution->grade == 1 && $this->loadModel('programplan')->isCreateTask($execution->id))
|
||||
{
|
||||
common::printIcon('programplan', 'create', "program={$execution->parent}&productID=$productID&planID=$execution->id", $execution, 'list', 'split', '', '', '', '', $this->lang->programplan->createSubPlan);
|
||||
}
|
||||
else
|
||||
{
|
||||
$disabled = ($execution->grade == 2) ? ' disabled' : '';
|
||||
echo common::hasPriv('programplan', 'create') ? html::a('javascript:alert("' . $this->lang->programplan->error->createdTask . '");', '<i class="icon-programplan-create icon-split"></i>', '', 'class="btn ' . $disabled . '"') : '';
|
||||
}
|
||||
|
||||
common::printIcon('programplan', 'edit', "stageID=$execution->id&projectID=$execution->project", $execution, 'list', '', '', 'iframe', true);
|
||||
|
||||
$disabled = !empty($execution->children) ? ' disabled' : '';
|
||||
if($execution->status != 'closed' and common::hasPriv('execution', 'close', $execution))
|
||||
{
|
||||
common::printIcon('execution', 'close', "stageID=$execution->id", $execution, 'list', 'off', 'hiddenwin' , $disabled . ' iframe', true, '', $this->lang->programplan->close);
|
||||
}
|
||||
elseif($execution->status == 'closed' and common::hasPriv('execution', 'activate', $execution))
|
||||
{
|
||||
common::printIcon('execution', 'activate', "stageID=$execution->id", $execution, 'list', 'magic', 'hiddenwin' , $disabled . ' iframe', true, '', $this->lang->programplan->activate);
|
||||
}
|
||||
|
||||
if(common::hasPriv('execution', 'delete', $execution))
|
||||
{
|
||||
common::printIcon('execution', 'delete', "stageID=$execution->id&confirm=no", $execution, 'list', 'trash', 'hiddenwin' , $disabled, '', '', $this->lang->programplan->delete);
|
||||
echo '</td>';
|
||||
echo '</tr>';
|
||||
|
||||
if(!empty($execution->children))
|
||||
{
|
||||
foreach($execution->children as $child) $this->printNestedList($child, true, $users, $productID);
|
||||
}
|
||||
|
||||
if(!empty($execution->tasks))
|
||||
{
|
||||
foreach($execution->tasks as $task)
|
||||
{
|
||||
$showmore = (count($execution->tasks) == 50) && ($task == end($execution->tasks));
|
||||
echo $this->task->buildNestedList($execution, $task, false, $showmore, $users);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update user view of execution and it's product.
|
||||
*
|
||||
|
||||
@@ -23,6 +23,7 @@ $lang->programplan->createSubPlan = '创建二级阶段';
|
||||
$lang->programplan->parent = '父阶段';
|
||||
$lang->programplan->emptyParent = '无';
|
||||
$lang->programplan->name = '阶段名称';
|
||||
$lang->programplan->status = '阶段进度';
|
||||
$lang->programplan->PM = '阶段负责人';
|
||||
$lang->programplan->acl = '访问控制';
|
||||
$lang->programplan->subStageName = '子阶段名称';
|
||||
|
||||
@@ -962,10 +962,37 @@ class project extends control
|
||||
*/
|
||||
public function execution($status = 'all', $projectID = 0, $orderBy = 'order_asc', $productID = 0, $recTotal = 0, $recPerPage = 100, $pageID = 1)
|
||||
{
|
||||
$uri = $this->app->getURI(true);
|
||||
$this->app->session->set('executionList', $uri, 'project');
|
||||
$this->loadModel('execution');
|
||||
$this->loadModel('task');
|
||||
$this->loadModel('programplan');
|
||||
|
||||
echo $this->fetch('execution', 'all', "status=$status&projectID=$projectID&orderBy=$orderBy&productID=$productID&recTotal=$recTotal&recPerPage=$recPerPage&pageID=$pageID");
|
||||
$projects = $this->project->getPairsByProgram();
|
||||
$projectID = $this->project->saveState($projectID, $projects);
|
||||
$project = $this->project->getByID($projectID);
|
||||
$this->project->setMenu($projectID);
|
||||
|
||||
if(!$projectID) return print(js::locate($this->createLink('project', 'browse')));
|
||||
if(!empty($project->model) and $project->model == 'kanban' and !(defined('RUN_MODE') and RUN_MODE == 'api')) return print(js::locate($this->createLink('project', 'index', "projectID=$projectID")));
|
||||
|
||||
/* Load pager and get tasks. */
|
||||
$this->app->loadClass('pager', $static = true);
|
||||
$pager = new pager($recTotal, $recPerPage, $pageID);
|
||||
|
||||
$this->view->title = $this->lang->execution->allExecutions;
|
||||
$this->view->position[] = $this->lang->execution->allExecutions;
|
||||
|
||||
$this->view->executionStats = $this->project->getStats($projectID, $status, $productID, 0, 30, $orderBy, $pager, $this->cookie->showTask);
|
||||
$this->view->productList = $this->loadModel('product')->getProductPairsByProject($projectID);
|
||||
$this->view->productID = $productID;
|
||||
$this->view->projectID = $projectID;
|
||||
$this->view->project = $project;
|
||||
$this->view->pager = $pager;
|
||||
$this->view->orderBy = $orderBy;
|
||||
$this->view->users = $this->loadModel('user')->getPairs('noletter');
|
||||
$this->view->status = $status;
|
||||
$this->view->isStage = (isset($project->model) and $project->model == 'waterfall') ? true : false;
|
||||
|
||||
$this->display();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
#executionList > thead > tr > th .table-nest-toggle-global {top: 6px}
|
||||
#executionList > thead > tr > th .table-nest-toggle-global:before {color: #a6aab8;}
|
||||
#mainMenu .pull-left .checkbox-primary {margin-top: 5px;}
|
||||
.main-table tbody>tr>td:first-child, .main-table thead>tr>th:first-child { padding-left: 8px; }
|
||||
@@ -0,0 +1,82 @@
|
||||
$(function()
|
||||
{
|
||||
$('input[name^="showTask"]').click(function()
|
||||
{
|
||||
var show = $(this).is(':checked') ? 1 : 0;
|
||||
$.cookie('showTask', show, {expires:config.cookieLife, path:config.webRoot});
|
||||
window.location.reload();
|
||||
});
|
||||
})
|
||||
|
||||
window.addEventListener('scroll', this.handleScroll)
|
||||
function handleScroll(e)
|
||||
{
|
||||
var relative = 200; // 相对距离
|
||||
$('tr.showmore').each(function()
|
||||
{
|
||||
var $showmore = $(this);
|
||||
var offsetTop = $showmore[0].offsetTop;
|
||||
if(offsetTop == 0) return true;
|
||||
|
||||
if(getScrollTop() + getWindowHeight() >= offsetTop - relative)
|
||||
{
|
||||
throttle(loadData($showmore), 150)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function loadData($showmore)
|
||||
{
|
||||
$showmore.removeClass('showmore');
|
||||
|
||||
var executionID = $showmore.attr('data-parent');
|
||||
var maxTaskID = $showmore.attr('data-id');
|
||||
var link = createLink('task', 'ajaxGetTasks', 'executionID=' + executionID + '&maxTaskID=' + maxTaskID);
|
||||
$.get(link, function(data)
|
||||
{
|
||||
$showmore.before(data);
|
||||
$(".iframe").modalTrigger({type:'iframe'});
|
||||
|
||||
$('#executionForm').table('initNestedList');
|
||||
})
|
||||
}
|
||||
|
||||
function throttle(fn, threshhold)
|
||||
{
|
||||
var last;
|
||||
var timer;
|
||||
threshhold || (threshhold = 250);
|
||||
|
||||
return function()
|
||||
{
|
||||
var context = this;
|
||||
var args = arguments;
|
||||
|
||||
var now = +new Date()
|
||||
|
||||
if (last && now < last + threshhold)
|
||||
{
|
||||
clearTimeout(timer);
|
||||
timer = setTimeout(function ()
|
||||
{
|
||||
last = now
|
||||
fn.apply(context, args)
|
||||
}, threshhold)
|
||||
}
|
||||
else
|
||||
{
|
||||
last = now
|
||||
fn.apply(context, args)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getScrollTop()
|
||||
{
|
||||
return scrollTop = document.body.scrollTop + document.documentElement.scrollTop
|
||||
}
|
||||
|
||||
function getWindowHeight()
|
||||
{
|
||||
return document.compatMode == "CSS1Compat" ? windowHeight = document.documentElement.clientHeight : windowHeight = document.body.clientHeight
|
||||
}
|
||||
@@ -2306,7 +2306,7 @@ class projectModel extends model
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getStats($projectID = 0, $status = 'undone', $productID = 0, $branch = 0, $itemCounts = 30, $orderBy = 'id_asc', $pager = null)
|
||||
public function getStats($projectID = 0, $status = 'undone', $productID = 0, $branch = 0, $itemCounts = 30, $orderBy = 'id_asc', $pager = null, $withTasks = false)
|
||||
{
|
||||
if(empty($productID))
|
||||
{
|
||||
@@ -2382,6 +2382,31 @@ class projectModel extends model
|
||||
$burns[$executionID] = $executionBurns;
|
||||
}
|
||||
|
||||
if($withTasks)
|
||||
{
|
||||
$executionTasks = $this->dao->select('*')->from(TABLE_TASK)
|
||||
->where('deleted')->eq(0)
|
||||
->andWhere('status')->ne('closed')
|
||||
->andWhere('execution')->in(array_keys($executions))
|
||||
->orderBy('id_asc')
|
||||
->fetchGroup('execution', 'id');
|
||||
|
||||
foreach($executionTasks as $executionID => $tasks)
|
||||
{
|
||||
foreach($tasks as $task)
|
||||
{
|
||||
if($task->parent > 0)
|
||||
{
|
||||
if(isset($executionTasks[$executionID][$task->parent]))
|
||||
{
|
||||
$executionTasks[$executionID][$task->parent]->children[$task->id] = $task;
|
||||
unset($executionTasks[$executionID][$task->id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Process executions. */
|
||||
$parents = array();
|
||||
$children = array();
|
||||
@@ -2407,6 +2432,11 @@ class projectModel extends model
|
||||
|
||||
$execution->children = array();
|
||||
$execution->grade == 1 ? $parents[$execution->id] = $execution : $children[$execution->parent][] = $execution;
|
||||
if(isset($executionTasks) and isset($executionTasks[$execution->id]))
|
||||
{
|
||||
$tasks = array_chunk($executionTasks[$execution->id], 50, true);
|
||||
$execution->tasks = $tasks[0];
|
||||
}
|
||||
}
|
||||
|
||||
/* In the case of the waterfall model, calculate the sub-stage. */
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
<?php include '../../common/view/header.html.php';?>
|
||||
<?php js::set('projectID', $projectID);?>
|
||||
<div id='mainMenu' class='clearfix'>
|
||||
<div class='btn-toolbar pull-left'>
|
||||
<div class='btn-group'>
|
||||
<?php $viewName = $productID != 0 ? zget($productList,$productID) : $lang->product->allProduct;?>
|
||||
<a href='javascript:;' class='btn btn-link btn-limit' data-toggle='dropdown'><span class='text' title='<?php echo $viewName;?>'><?php echo $viewName;?></span> <span class='caret'></span></a>
|
||||
<ul class='dropdown-menu' style='max-height:240px; max-width: 300px; overflow-y:auto'>
|
||||
<?php
|
||||
$class = '';
|
||||
if($productID == 0) $class = 'class="active"';
|
||||
echo "<li $class>" . html::a($this->createLink('project', 'execution', "status=$status&projectID=$projectID&orderby=$orderBy"), $lang->product->allProduct) . "</li>";
|
||||
foreach($productList as $key => $product)
|
||||
{
|
||||
$class = $productID == $key ? 'class="active"' : '';
|
||||
echo "<li $class>" . html::a($this->createLink('project', 'execution', "status=$status&projectID=$projectID&orderby=$orderBy&productID=$key"), $product) . "</li>";
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
</div>
|
||||
<?php foreach($lang->execution->featureBar['all'] as $key => $label):?>
|
||||
<?php $label = "<span class='text'>$label</span>";?>
|
||||
<?php if($status == $key) $label .= " <span class='label label-light label-badge'>{$pager->recTotal}</span>";?>
|
||||
<?php echo html::a($this->createLink('project', 'execution', "status=$key&projectID=$projectID&orderBy=$orderBy&productID=$productID"), $label, '', "class='btn btn-link' id='{$key}Tab'");?>
|
||||
<?php endforeach;?>
|
||||
<?php echo html::checkbox('showTask', array('1' => $lang->programplan->stageCustom->task), '', $this->cookie->showTask ? 'checked=checked' : '');?>
|
||||
</div>
|
||||
<div class='btn-toolbar pull-right'>
|
||||
<?php common::printLink('execution', 'export', "status=$status&productID=$productID&orderBy=$orderBy&from=project", "<i class='icon-export muted'> </i> " . $lang->export, '', "class='btn btn-link export'")?>
|
||||
<?php if(common::hasPriv('programplan', 'create') and $isStage):?>
|
||||
<?php echo html::a($this->createLink('programplan', 'create', "projectID=$projectID&productID=$productID"), "<i class='icon icon-plus'></i> " . $lang->programplan->create, '', "class='btn btn-primary'");?>
|
||||
<?php else: ?>
|
||||
<?php if(common::hasPriv('execution', 'create')) echo html::a($this->createLink('execution', 'create', "projectID=$projectID"), "<i class='icon icon-sm icon-plus'></i> " . $lang->execution->create, '', "class='btn btn-primary create-execution-btn' data-app='execution' onclick='$(this).removeAttr(\"data-toggle\")'");?>
|
||||
<?php endif;?>
|
||||
</div>
|
||||
</div>
|
||||
<div id='mainContent' class="main-row fade">
|
||||
<?php if(empty($executionStats)):?>
|
||||
<div class="table-empty-tip">
|
||||
<p>
|
||||
<span class="text-muted"><?php echo $lang->execution->noExecution;?></span>
|
||||
<?php if($status == "all"):?>
|
||||
<?php if(common::hasPriv('programplan', 'create') and $isStage):?>
|
||||
<?php echo html::a($this->createLink('programplan', 'create', "projectID=$projectID&productID=$productID"), "<i class='icon icon-plus'></i> " . $lang->programplan->create, '', "class='btn btn-info'");?>
|
||||
<?php else: ?>
|
||||
<?php if(common::hasPriv('execution', 'create')):?>
|
||||
<?php echo html::a($this->createLink('execution', 'create', "projectID=$projectID"), "<i class='icon icon-plus'></i> " . $lang->execution->create, '', "class='btn btn-info' data-app='execution'");?>
|
||||
<?php endif;?>
|
||||
<?php endif;?>
|
||||
<?php endif;?>
|
||||
</p>
|
||||
</div>
|
||||
<?php else:?>
|
||||
<?php $canBatchEdit = common::hasPriv('execution', 'batchEdit'); ?>
|
||||
<form class='main-table' id='executionForm' method='post' data-ride='table' data-nested='true' data-expand-nest-child='false' data-checkable='false' data-enable-empty-nested-row='true' data-replace-id='executionTableList' data-preserve-nested='true'>
|
||||
<table class="table table-from table-fixed table-nested" id="executionList">
|
||||
<?php $vars = "status=$status&orderBy=%s";?>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class='table-nest-title'>
|
||||
<a class='table-nest-toggle icon table-nest-toggle-global' data-expand-text='<?php echo $lang->expand; ?>' data-collapse-text='<?php echo $lang->collapse;?>'></a>
|
||||
<?php echo $lang->nameAB;?>
|
||||
</th>
|
||||
<th class='c-user'><?php echo $lang->execution->owner;?></th>
|
||||
<th class='c-status'><?php echo $lang->project->status;?></th>
|
||||
<th class='c-hours'><?php echo $lang->project->progress;?></th>
|
||||
<th class='c-date'><?php echo $lang->programplan->begin;?></th>
|
||||
<th class='c-date'><?php echo $lang->programplan->end;?></th>
|
||||
<th class='c-hours'><?php echo $lang->task->estimateAB;?></th>
|
||||
<th class='c-hours'><?php echo $lang->task->consumedAB;?></th>
|
||||
<th class='c-hours'><?php echo $lang->task->leftAB;?> </th>
|
||||
<th class='c-progress'><?php echo $lang->execution->burn;?> </th>
|
||||
<th class='text-center c-actions-6'><?php echo $lang->actions;?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="executionTableList">
|
||||
<?php foreach($executionStats as $execution):?>
|
||||
<?php $this->execution->printNestedList($execution, false, $users, $productID);?>
|
||||
<?php endforeach;?>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class='table-footer'>
|
||||
<?php $pager->show('right', 'pagerjs');?>
|
||||
</div>
|
||||
</form>
|
||||
<?php endif;?>
|
||||
</div>
|
||||
<?php js::set('status', $status)?>
|
||||
<?php js::set('orderBy', $orderBy)?>
|
||||
<script>
|
||||
$("#<?php echo $status;?>Tab").addClass('btn-active-text');
|
||||
</script>
|
||||
<?php include '../../common/view/footer.html.php';?>
|
||||
@@ -3931,7 +3931,7 @@ class storyModel extends model
|
||||
if($story->stage == 'projected') $title = $this->lang->story->subDivideTip['projected'];
|
||||
}
|
||||
}
|
||||
$menu .= $this->buildMenu('story', 'batchCreate', "productID=$story->product&branch=$story->branch&module=$story->module&$params&executionID={$this->session->project}", $story, $type, 'split', '', 'showinonlybody', '', '', $title);
|
||||
$menu .= $this->buildMenu('story', 'batchCreate', "productID=$story->product&branch=$story->branch&module=$story->module&$params", $story, $type, 'split', '', 'showinonlybody', '', '', $title);
|
||||
}
|
||||
if($this->app->rawModule == 'projectstory' and $this->config->vision != 'lite') $menu .= $this->buildMenu('projectstory', 'unlinkStory', "projectID={$this->session->project}&$params", $story, $type, 'unlink', 'hiddenwin', 'showinonlybody');
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ class task extends control
|
||||
$executionID = $this->execution->saveState($executionID, $executions);
|
||||
$execution = $this->execution->getById($executionID);
|
||||
$this->execution->setMenu($executionID);
|
||||
if($this->app->tab == 'project') $this->loadModel('project')->setMenu($this->session->project);
|
||||
|
||||
$this->execution->getLimitedExecution();
|
||||
$limitedExecutions = !empty($_SESSION['limitedExecutions']) ? $_SESSION['limitedExecutions'] : '';
|
||||
@@ -347,6 +348,7 @@ class task extends control
|
||||
|
||||
/* Set menu. */
|
||||
$this->execution->setMenu($execution->id);
|
||||
if($this->app->tab == 'project') $this->loadModel('project')->setMenu($this->session->project);
|
||||
|
||||
/* When common task are child tasks, query whether common task are consumed. */
|
||||
$taskConsumed = 0;
|
||||
@@ -575,6 +577,8 @@ class task extends control
|
||||
}
|
||||
}
|
||||
|
||||
if($this->app->tab == 'project') $this->loadModel('project')->setMenu($this->session->project);
|
||||
|
||||
$tasks = $this->task->getParentTaskPairs($this->view->execution->id, $this->view->task->parent);
|
||||
if(isset($tasks[$taskID])) unset($tasks[$taskID]);
|
||||
|
||||
@@ -899,6 +903,7 @@ class task extends control
|
||||
$this->session->set('executionList', $this->app->getURI(true), 'execution');
|
||||
|
||||
$this->commonAction($taskID);
|
||||
if($this->app->tab == 'project') $this->loadModel('project')->setMenu($this->session->project);
|
||||
|
||||
$taskID = (int)$taskID;
|
||||
$task = $this->task->getById($taskID, true);
|
||||
@@ -1862,6 +1867,54 @@ class task extends control
|
||||
echo html::select('task', empty($tasks) ? array('' => '') : $tasks, $taskID, "class='form-control'");
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax get tasks for execution list.
|
||||
*
|
||||
* @param int $executionID
|
||||
* @param int $maxTaskID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function ajaxGetTasks($executionID, $maxTaskID = 0)
|
||||
{
|
||||
$this->loadModel('task');
|
||||
$this->loadModel('execution');
|
||||
$execution = $this->dao->findById($executionID)->from(TABLE_EXECUTION)->fetch();
|
||||
|
||||
$tasks = $this->dao->select('*')->from(TABLE_TASK)
|
||||
->where('deleted')->eq(0)
|
||||
->andWhere('status')->ne('closed')
|
||||
->andWhere('execution')->eq($executionID)
|
||||
->andWhere('id')->gt($maxTaskID)
|
||||
->orderBy('id_asc')
|
||||
->fetchAll('id');
|
||||
|
||||
$users = $this->loadModel('user')->getPairs('noletter|nodeleted');
|
||||
foreach($tasks as $task)
|
||||
{
|
||||
if($task->parent > 0)
|
||||
{
|
||||
if(isset($tasks[$task->parent]))
|
||||
{
|
||||
$tasks[$task->parent]->children[$task->id] = $task;
|
||||
unset($tasks[$task->id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$list = '';
|
||||
$tasks = array_chunk($tasks, 50, true);
|
||||
$tasks = $tasks[0];
|
||||
$count = count($tasks);
|
||||
foreach($tasks as $task)
|
||||
{
|
||||
$showmore = ($count == 50) && ($task == end($tasks));
|
||||
$list .= $this->task->buildNestedList($execution, $task, false, $showmore, $users);
|
||||
}
|
||||
|
||||
die($list);
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX: get the actions of a task. for web app.
|
||||
*
|
||||
|
||||
@@ -3734,6 +3734,64 @@ class taskModel extends model
|
||||
->fetchPairs('actor');
|
||||
}
|
||||
|
||||
/**
|
||||
* Build nested list.
|
||||
*
|
||||
* @param objecct $execution
|
||||
* @param object $task
|
||||
* @param bool $isChild
|
||||
* @param bool $showmore
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function buildNestedList($execution, $task, $isChild = false, $showmore = false, $users)
|
||||
{
|
||||
$showmore = $showmore ? 'showmore' : '';
|
||||
$trAttrs = "data-id=$task->id";
|
||||
if(!$isChild)
|
||||
{
|
||||
$path = $execution->grade == 2 ? "$execution->parent,$execution->id,$task->id," : ",$execution->id,$task->id,";
|
||||
$trAttrs .= " data-parent=$execution->id data-nest-parent=$execution->id data-nest-path=$path";
|
||||
if(empty($task->children)) $trAttrs .= " data-nested='false'";
|
||||
$trClass = empty($task->children) ? '' : " has-nest-child";
|
||||
}
|
||||
else
|
||||
{
|
||||
$path = $execution->grade == 2 ? "$execution->parent,$execution->id,$task->parent,$task->id," : ",$execution->id,$task->parent,$task->id,";
|
||||
$trClass = 'is-nest-child no-nest';
|
||||
$trAttrs .= " data-nested='false' data-parent=$task->parent data-nest-parent=$task->parent data-nest-path=$path";
|
||||
}
|
||||
|
||||
$list = "<tr $trAttrs class='$trClass $showmore'>";
|
||||
$list .= '<td>';
|
||||
if($task->parent > 0) $list .= '<span class="label label-badge label-light" title="' . $this->lang->task->children . '">' . $this->lang->task->childrenAB . '</span> ';
|
||||
$list .= html::a(helper::createLink('task', 'view', "id=$task->id"), $task->name, '', "data-app='project'");
|
||||
$list .= '</td>';
|
||||
$list .= '<td>' . zget($users, $task->assignedTo, '') . '</td>';
|
||||
$list .= "<td class='status-{$task->status}'>" . $this->processStatus('task', $task) . '</td>';
|
||||
$list .= '<td></td>';
|
||||
$list .= '<td>' . $task->estStarted . '</td>';
|
||||
$list .= '<td>' . $task->deadline . '</td>';
|
||||
$list .= '<td>' . $task->estimate . $this->lang->execution->workHourUnit . '</td>';
|
||||
$list .= '<td>' . $task->consumed . $this->lang->execution->workHourUnit . '</td>';
|
||||
$list .= '<td>' . $task->left . $this->lang->execution->workHourUnit . '</td>';
|
||||
$list .= '<td></td>';
|
||||
$list .= '<td class="c-actions">';
|
||||
$list .= $this->buildOperateMenu($task, 'browse');
|
||||
$list .= '</td></tr>';
|
||||
|
||||
if(!empty($task->children))
|
||||
{
|
||||
foreach($task->children as $child)
|
||||
{
|
||||
$showmore = (count($task->children) == 50) && ($child == end($task->children));
|
||||
$list .= $this->buildNestedList($execution, $child, true, $showmore, $users);
|
||||
}
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build task menu.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user