Merge branch 'master' of github.com:easysoft/zentaopms

This commit is contained in:
chenfeiCF
2015-11-10 17:30:37 +08:00
10 changed files with 115 additions and 42 deletions

View File

@@ -42,7 +42,9 @@ class branchModel extends model
$branches = $this->dao->select('*')->from(TABLE_BRANCH)->where('product')->eq($productID)->andWhere('deleted')->eq(0)->orderBy('id_asc')->fetchPairs('id', 'name');
if(strpos($params, 'noempty') === false)
{
$product = $this->loadModel('product')->getById($productID);
$product = $this->loadModel('product')->getById($productID);
if($product->type == 'normal') return array();
$branches = array('0' => $this->lang->branch->all . $this->lang->product->branchName[$product->type]) + $branches;
}
return $branches;

View File

@@ -183,13 +183,16 @@ class product extends control
}
$this->loadModel('search')->setSearchParams($this->config->product->search);
$storyIdList = array();
foreach($stories as $story) $storyIdList[$story->id] = $story->id;
$this->view->productID = $productID;
$this->view->productName = $this->products[$productID];
$this->view->moduleID = $moduleID;
$this->view->stories = $stories;
$this->view->plans = $this->loadModel('productplan')->getPairs($productID, $branch);
$this->view->summary = $this->product->summary($stories);
$this->view->moduleTree = $this->tree->getTreeMenu($productID, $viewType = 'story', $startModuleID = 0, array('treeModel', 'createStoryLink'));
$this->view->moduleTree = $this->tree->getTreeMenu($productID, $viewType = 'story', $startModuleID = 0, array('treeModel', 'createStoryLink'), '', $branch);
$this->view->parentModules = $this->tree->getParents($moduleID);
$this->view->pager = $pager;
$this->view->users = $this->user->getPairs('nodeleted|noletter|pofirst');
@@ -197,6 +200,8 @@ class product extends control
$this->view->browseType = $browseType;
$this->view->moduleID = $moduleID;
$this->view->branch = $branch;
$this->view->branches = $this->loadModel('branch')->getPairs($productID);
$this->view->storyStages = $this->story->getStoryStages($storyIdList);
$this->display();
}

View File

@@ -17,4 +17,7 @@ $(function()
$option.toggleClass('hide', $option.text().toString().toLowerCase().indexOf(val) < 0 && $option.data('key').toString().toLowerCase().indexOf(val) < 0);
});
});
$('.popoverStage').mouseover(function(){$(this).popover('show')});
$('.popoverStage').mouseout(function(){$(this).popover('hide')});
})

View File

@@ -58,7 +58,7 @@
<a class='side-handle' data-id='productTree'><i class='icon-caret-left'></i></a>
<div class='side-body'>
<div class='panel panel-sm'>
<div class='panel-heading nobr'><?php echo html::icon($lang->icons['product']);?> <strong><?php echo $productName;?></strong></div>
<div class='panel-heading nobr'><?php echo html::icon($lang->icons['product']);?> <strong><?php echo $branch ? $branches[$branch] : $productName;?></strong></div>
<div class='panel-body'>
<?php echo $moduleTree;?>
<div class='text-right'>
@@ -100,14 +100,30 @@
<?php if($canView) echo html::a($viewLink, sprintf('%03d', $story->id)); else printf('%03d', $story->id);?>
</td>
<td><span class='<?php echo 'pri' . zget($lang->story->priList, $story->pri, $story->pri);?>'><?php echo zget($lang->story->priList, $story->pri, $story->pri)?></span></td>
<td class='text-left' title="<?php echo $story->title?>"><nobr><?php echo html::a($viewLink, $story->title);?></nobr></td>
<td class='text-left' title="<?php echo $story->title?>"><nobr>
<?php if($story->branch) echo "<span class='label label-info label-badge'>{$branches[$story->branch]}</span>"?>
<?php echo html::a($viewLink, $story->title);?>
</nobr></td>
<td title="<?php echo $story->planTitle?>"><?php echo $story->planTitle;?></td>
<td><?php echo $lang->story->sourceList[$story->source];?></td>
<td><?php echo zget($users, $story->openedBy, $story->openedBy);?></td>
<td><?php echo zget($users, $story->assignedTo, $story->assignedTo);?></td>
<td><?php echo $story->estimate;?></td>
<td class='story-<?php echo $story->status;?>'><?php echo $lang->story->statusList[$story->status];?></td>
<td><?php echo $lang->story->stageList[$story->stage];?></td>
<td>
<?php
echo "<div" . (isset($storyStages[$story->id]) ? " class='popoverStage' data-toggle='popover' data-placement='bottom' data-target='\$next'" : '') . "'>";
echo $lang->story->stageList[$story->stage];
if(isset($storyStages[$story->id])) echo "<span class='pull-right'><i class='icon icon-caret-down'></i></span>";
echo '</div>';
if(isset($storyStages[$story->id]))
{
echo "<div class='popover'>";
foreach($storyStages[$story->id] as $storyBranch => $storyStage) echo $branches[$storyBranch] . ": " . $lang->story->stageList[$storyStage->stage] . '<br />';
echo "</div>";
}
?>
</td>
<td class='text-right'>
<?php
$vars = "story={$story->id}";

View File

@@ -177,8 +177,8 @@ class releaseModel extends model
$this->dao->update(TABLE_RELEASE)->set('stories')->eq($release->stories)->where('id')->eq((int)$releaseID)->exec();
if($release->stories)
{
$this->dao->update(TABLE_STORY)->set('stage')->eq('released')->where('id')->in($release->stories)->exec();
$this->dao->update(TABLE_STORYSTAGE)->set('stage')->eq('released')->where('story')->in($release->stories)->andWhere('branch')->eq($release->branch)->exec();
$this->loadModel('story');
foreach($this->post->stories as $storyID) $this->story->setStage($storyID);
}
}

View File

@@ -850,43 +850,46 @@ class storyModel extends model
* Set stage of a story.
*
* @param int $storyID
* @param string $customStage
* @access public
* @return bool
*/
public function setStage($storyID, $customStage = '')
public function setStage($storyID)
{
$storyID = (int)$storyID;
/* Custom stage defined, use it. */
if($customStage)
{
$this->dao->update(TABLE_STORY)->set('stage')->eq($customStage)->where('id')->eq((int)$storyID)->exec();
return true;
}
/* Get projects which status is doing. */
$this->dao->delete()->from(TABLE_STORYSTAGE)->where('story')->eq($storyID)->exec();
$story = $this->dao->findById($storyID)->from(TABLE_STORY)->fetch();
$product = $this->dao->findById($story->product)->from(TABLE_PRODUCT)->fetch();
$projects = $this->dao->select('t1.project,t3.branch')->from(TABLE_PROJECTSTORY)->alias('t1')
->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id')
->leftJoin(TABLE_PROJECTPRODUCT)->alias('t3')->on('t1.project = t3.project')
->where('t1.story')->eq($storyID)
->andWhere('t2.status')->ne('done')
->andWhere('t2.deleted')->eq(0)
->fetchPairs('project', 'branch');
$hasBranch = ($product->type != 'normal' and empty($story->branch));
$stages = array();
if($hasBranch and $story->plan)
{
$plans = $this->dao->select('*')->from(TABLE_PRODUCTPLAN)->where('id')->in($story->plan)->fetchPairs('branch', 'branch');
foreach($plans as $branch) $stages[$branch] = 'planned';
}
/* If no projects, in plan, stage is planned. No plan, wait. */
if(!$projects)
{
$this->dao->update(TABLE_STORY)->set('stage')->eq('wait')->where('id')->eq($storyID)->andWhere('plan')->eq('')->exec();
foreach($stages as $branch => $stage) $this->dao->insert(TABLE_STORYSTAGE)->set('story')->eq($storyID)->set('branch')->eq($branch)->set('stage')->eq($stage)->exec();
$this->dao->update(TABLE_STORY)->set('stage')->eq('planned')->where('id')->eq($storyID)->andWhere('plan')->ne('')->exec();
return true;
}
$story = $this->dao->findById($storyID)->from(TABLE_STORY)->fetch();
$product = $this->dao->findById($story->product)->from(TABLE_PRODUCT)->fetch();
$branches = array();
foreach($projects as $projectID => $branch) $branches[$branch] = $branch;
unset($branches[0]);
if($hasBranch)
{
foreach($projects as $projectID => $branch) $stages[$branch] = 'projected';
}
/* Search related tasks. */
$tasks = $this->dao->select('type,project,status')->from(TABLE_TASK)
@@ -898,19 +901,14 @@ class storyModel extends model
->fetchGroup('type');
/* No tasks, then the stage is projected. */
$hasBranch = ($product->type != 'normal' and empty($story->branch) and $branches);
if(!$tasks)
{
if($hasBranch)
{
foreach($branches as $branch) $this->dao->insert(TABLE_STORYSTAGE)->set('story')->eq($storyID)->set('branch')->eq($branch)->set('stage')->eq('projected')->exec();
}
foreach($stages as $branch => $stage) $this->dao->insert(TABLE_STORYSTAGE)->set('story')->eq($storyID)->set('branch')->eq($branch)->set('stage')->eq('projected')->exec();
$this->dao->update(TABLE_STORY)->set('stage')->eq('projected')->where('id')->eq($storyID)->exec();
return true;
}
/* Get current stage and set as default value. */
$taskProjects = array();
$currentStage = $story->stage;
$stage = $currentStage;
@@ -930,15 +928,14 @@ class storyModel extends model
$branch = $projects[$task->project];
if(!isset($branchStatusList[$branch])) $branchStatusList[$branch] = $statusList;
$branchStatusList[$branch][$task->type][$status] ++;
$taskProjects[$task->project] = $task->project;
if($type == 'devel')
{
if(!isset($develTasks[$branch])) $develTasks[$branch] = 0;
if(!isset($branchDevelTasks[$branch])) $branchDevelTasks[$branch] = 0;
$branchDevelTasks[$branch] ++;
}
elseif($type == 'test')
{
if(!isset($testTasks[$branch])) $testTasks[$branch] = 0;
if(!isset($branchTestTasks[$branch])) $branchTestTasks[$branch] = 0;
$branchTestTasks[$branch] ++;
}
}
@@ -963,14 +960,31 @@ class storyModel extends model
if(($statusList['devel']['wait'] > 0 or $statusList['devel']['doing'] > 0) and $statusList['test']['done'] == $testTasks and $testTasks > 0) $stage = 'testing';
if($statusList['devel']['done'] == $develTasks and $develTasks > 0 and $statusList['test']['done'] == $testTasks and $testTasks > 0) $stage = 'tested';
if($hasBranch and $branch) $this->dao->insert(TABLE_STORYSTAGE)->set('story')->eq($storyID)->set('branch')->eq($branch)->set('stage')->eq($stage)->exec();
$this->dao->update(TABLE_STORY)->set('stage')->eq($stage)->where('id')->eq($storyID)->exec();
$stages[$branch] = $stage;
}
foreach($projects as $projectID => $branch)
$releases = $this->dao->select('*')->from(TABLE_RELEASE)->where("CONCAT(',', stories, ',')")->like("%,$storyID,%")->andWhere('deleted')->eq(0)->fetchPairs('branch', 'branch');
foreach($releases as $branch) $stages[$branch] = 'released';
if($hasBranch)
{
if(isset($taskProjects[$projectID])) continue;
$this->dao->insert(TABLE_STORYSTAGE)->set('story')->eq($storyID)->set('branch')->eq($branch)->set('stage')->eq('projected')->exec();
$stageList = join(',', array_keys($this->lang->story->stageList));
$minStagePos = strlen($stageList);
$minStage = '';
foreach($stages as $branch => $stage)
{
$this->dao->insert(TABLE_STORYSTAGE)->set('story')->eq($storyID)->set('branch')->eq($branch)->set('stage')->eq($stage)->exec();
if(strpos($stageList, $stage) !== false and strpos($stageList, $stage) < $minStagePos)
{
$minStage = $stage;
$minStagePos = strpos($stageList, $stage);
}
}
$this->dao->update(TABLE_STORY)->set('stage')->eq($minStage)->where('id')->eq($storyID)->exec();
}
else
{
$this->dao->update(TABLE_STORY)->set('stage')->eq(current($stages))->where('id')->eq($storyID)->exec();
}
return;
@@ -993,10 +1007,11 @@ class storyModel extends model
{
unset($branch[0]);
$branch = join(',', $branch);
if($branch) $branch = "0,$branch";
}
$stories = $this->dao->select('*')->from(TABLE_STORY)
->where('product')->in($productID)
->beginIF($branch)->andWhere("branch")->in("0,$branch")->fi()
->beginIF($branch)->andWhere("branch")->in("$branch")->fi()
->beginIF(!empty($moduleIds))->andWhere('module')->in($moduleIds)->fi()
->beginIF($status and $status != 'all')->andWhere('status')->in($status)->fi()
->andWhere('deleted')->eq(0)
@@ -1476,6 +1491,20 @@ class storyModel extends model
return $allStories;
}
/**
* Get story stages.
*
* @param array $stories
* @access public
* @return array
*/
public function getStoryStages($stories)
{
return $this->dao->select('*')->from(TABLE_STORYSTAGE)
->where('story')->in($stories)
->fetchGroup('story', 'branch');
}
/**
* Check need confirm.
*
@@ -1826,16 +1855,27 @@ class storyModel extends model
public function mergePlanTitle($productID, $stories, $branch = 0)
{
$query = $this->dao->get();
if(is_array($branch))
{
unset($branch[0]);
$branch = join(',', $branch);
if($branch) $branch = "0,$branch";
}
$plans = $this->dao->select('id,title')->from(TABLE_PRODUCTPLAN)
->where('product')->in($productID)
->beginIF($branch)->andWhere('branch')->in("0,$branch")->fi()
->beginIF($branch)->andWhere('branch')->in($branch)->fi()
->andWhere('deleted')->eq(0)
->fetchPairs('id', 'title');
$stages = $this->dao->select('*')->from(TABLE_STORYSTAGE)->where('branch')->in($branch)->fetchGroup('story', 'branch');
$branch = trim(str_replace(',0,', '', ",$branch,"), ',');
$branch = empty($branch) ? 0 : $branch;
foreach($stories as $story)
{
$story->planTitle = '';
$storyPlans = explode(',', trim($story->plan, ','));
foreach($storyPlans as $planID) $story->planTitle .= zget($plans, $planID) . ' ';
if(empty($story->branch) and isset($stages[$story->id][$branch])) $story->stage = $stages[$story->id][$branch]->stage;
}
/* For save session query. */

View File

@@ -30,7 +30,6 @@ class tree extends control
$product = $this->loadModel('product')->getById($rootID);
if($product->type != 'normal') $this->view->branches = $this->loadModel('branch')->getPairs($product->id);
$this->view->root = $product;
$this->view->productModules = $this->tree->getOptionMenu($rootID, 'story');
}
/* The viewType is doc. */
elseif(strpos($viewType, 'doc') !== false)
@@ -65,6 +64,7 @@ class tree extends control
$this->view->allProduct = $products;
$this->view->currentProduct = $currentProduct;
$this->view->productModules = $this->tree->getOptionMenu($currentProduct, 'story');
$title = $product->name . $this->lang->colon . $this->lang->tree->manageProduct;
$position[] = html::a($this->createLink('product', 'browse', "product=$rootID"), $product->name);

View File

@@ -22,7 +22,7 @@ function syncModule(rootID, type)
{
if(value)
{
$('#sonModule .input-group:last').after($inputgroup);
$('#sonModule').append($inputgroup);
$('#sonModule .input-group:last input').val(value);
}
})

View File

@@ -271,15 +271,16 @@ class treeModel extends model
{
$branches = array($branch => '');
$manage = $userFunc[1] == 'createManageLink' ? true : false;
$product = $this->loadModel('product')->getById($rootID);
if(strpos('story|bug|case', $type) !== false and empty($branch))
{
$product = $this->loadModel('product')->getById($rootID);
if($product->type != 'normal') $branches = array('null' => '') + $this->loadModel('branch')->getPairs($rootID, 'noempty');
}
/* Add for task #1945. check the module has case or no. */
if($type == 'case' and !empty($extra)) $this->loadModel('testtask');
$lastMenu = '';
$lastMenu = '';
$firstBranch = true;
foreach($branches as $branchID => $branch)
{
$treeMenu = array();
@@ -290,6 +291,11 @@ class treeModel extends model
if(!empty($branchID) and $branch and $branchID != 'null')
{
$linkHtml = $manage ? html::a(inlink('browse', "root=$rootID&viewType=$type&currentModuleID=0&branch=$branchID"), $branch) : $this->createBranchLink($type, $rootID, $branchID, $branch);
if($firstBranch and $product->type != 'normal')
{
$linkHtml = $this->lang->product->branchName[$product->type] . '<ul><li>' . $linkHtml;
$firstBranch = false;
}
$lastMenu .= "<li>$linkHtml<ul>" . @array_shift($treeMenu) . "</ul></li>\n";
}
else
@@ -298,6 +304,7 @@ class treeModel extends model
}
}
if(!$firstBranch) $lastMenu .= '</li></ul>';
$lastMenu = "<ul class='tree'>$lastMenu</ul>\n";
return $lastMenu;
}

View File

@@ -86,7 +86,7 @@
echo html::input("modules[]", '', 'class="form-control"');
if($hasBranch) echo '<span class="input-group-addon fix-border" style="padding:0px"></span>' . html::select("branch[]", $branches, $branch, 'class="form-control"');
echo "<span class='input-group-addon fix-border'><a href='javascript:;' onclick='addItem(this)'><i class='icon icon-plus'></i></a></span>";
echo "<span class='input-group-addon fix-border'><a href='javascript:;' onclick='deleteItem(this)'><i class='icon icon-remove'></i></a></span>";
echo "<span class='input-group-addon'><a href='javascript:;' onclick='deleteItem(this)'><i class='icon icon-remove'></i></a></span>";
echo '</div>';
}
?>