* Code for story and requirement.

This commit is contained in:
Yagami
2020-08-25 11:09:42 +08:00
parent 297be48bcc
commit ad619c4909
16 changed files with 568 additions and 119 deletions
+8 -7
View File
@@ -1178,7 +1178,7 @@ class block extends control
$begin = $program->begin;
$today = helper::today();
$end = date('Y-m-d', strtotime("$today + 7 days"));
$end = date('Y-m-d', strtotime($today));
$projects = $this->project->getProjectsByProgram($program);
$projectIdList = array_keys($projects);
@@ -1188,14 +1188,15 @@ class block extends control
$charts['AC'] = '[';
$i = 1;
$start = $begin;
$longProgram = helper::diffDate($today, $begin) / 7 > 10;
while($start < $end)
{
$charts['labels'][] = $this->lang->milestone->chart->time . $i . $this->lang->milestone->chart->week;
$sunday = $this->weekly->getThisSunday($start);
$charts['PV'] .= $this->milestone->getPV($projectIdList, $begin, $sunday) . ',';
$charts['EV'] .= $this->milestone->getEV($projectIdList, $begin, $sunday) . ',';
$charts['AC'] .= $this->milestone->getAC($projectIdList, $begin, $sunday) . ',';
$start = date('Y-m-d', strtotime("$start + 7 days"));
$charts['labels'][] = $longProgram ? $this->lang->milestone->chart->time . $i . $this->lang->milestone->chart->month : $this->lang->milestone->chart->time . $i . $this->lang->milestone->chart->week;
$stageEnd = $longProgram ? date('Y-m-t', strtotime($start)) : $this->weekly->getThisSunday($start);
$charts['PV'] .= $this->milestone->getPV($projectIdList, $begin, $stageEnd) . ',';
$charts['EV'] .= $this->milestone->getEV($projectIdList, $begin, $stageEnd) . ',';
$charts['AC'] .= $this->milestone->getAC($projectIdList, $begin, $stageEnd) . ',';
$start = $longProgram ? date('Y-m-d', strtotime("$start + 1 month")) : date('Y-m-d', strtotime("$start + 7 days"));
$i ++;
}
@@ -148,8 +148,8 @@ $(function()
<div class="program-info">
<h4><?php echo $lang->program->allInput;?></h4>
<div class='info'>
<span><i class='icon icon-group'></i> <?php echo $program->teamCount;?></span>
<span><i class='icon icon-clock'></i> <?php echo $program->estimate;?></span>
<span><i class='icon icon-group'></i> <?php echo sprintf($lang->program->membersUnit, $program->teamCount);?></span>
<span><i class='icon icon-clock'></i> <?php echo sprintf($lang->program->hoursUnit, $program->estimate);?></span>
<span><i class='icon icon-cost'></i> <?php echo $program->budget . ' ' . zget($lang->program->unitList, $program->budgetUnit);?></span>
</div>
</div>
+1
View File
@@ -81,6 +81,7 @@ $lang->milestone->chart = new stdclass();
$lang->milestone->chart->title = '到目前为止项目进展趋势图';
$lang->milestone->chart->time = '第';
$lang->milestone->chart->week = '周';
$lang->milestone->chart->month = '月';
$lang->milestone->chart->workhour = '研发工作量分析图';
$lang->milestone->otherproblem = '6.其它问题';
+1
View File
@@ -180,6 +180,7 @@ class product extends control
$this->view->position[] = $this->products[$productID];
$this->view->position[] = $this->lang->product->browse;
$this->view->productID = $productID;
$this->view->program = $this->loadModel('project')->getById($this->session->program);
$this->view->product = $this->product->getById($productID);
$this->view->productName = $this->products[$productID];
$this->view->moduleID = $moduleID;
+1 -1
View File
@@ -24,7 +24,7 @@ js::set('unfoldID', $config->product->browse->unfoldID);
js::set('unfoldAll', $lang->project->treeLevel['all']);
js::set('foldAll', $lang->project->treeLevel['root']);
js::set('storyType', $storyType);
$lang->story->create = $storyType == 'story' ? $lang->story->createStory : $lang->story->createRequirement;
if($program->template == 'cmmi') $lang->story->create = $storyType == 'story' ? $lang->story->createStory : $lang->story->createRequirement;
?>
<div id="mainMenu" class="clearfix">
<div id="sidebarHeader">
+1 -1
View File
@@ -74,7 +74,7 @@ class programplan extends control
$this->app->loadLang('stage');
$program = $this->loadModel('project')->getById($programID);
$stages = $planID ? array() : $this->loadModel('stage')->getStages();
$stages = $planID ? array() : $this->loadModel('stage')->getStages('id_asc');
$plans = $this->programplan->getList($programID, $this->productID, $planID);
$title = $this->lang->programplan->create . $this->lang->colon . $program->name;
+42 -4
View File
@@ -752,8 +752,11 @@ class story extends control
$this->view->fromBug = $fromBug;
$this->view->cases = $cases;
$this->view->story = $story;
$this->view->track = $this->story->getTrackByID($story->id);
$this->view->users = $users;
$this->view->relations = $this->story->getStoryRelation($story->id, $story->type);
$this->view->projects = $this->loadModel('project')->getPairs('nocode');
$this->view->program = $this->project->getByID($story->program);
$this->view->actions = $this->action->getList('story', $storyID);
$this->view->storyModule = $storyModule;
$this->view->modulePath = $modulePath;
@@ -1166,6 +1169,26 @@ class story extends control
die(js::locate($this->session->storyList, 'parent'));
}
/**
* Story track.
*
* @param int $productID
* @access public
* @return void
*/
public function track($productID)
{
$products = $this->loadModel('product')->getPairs($this->session->program);
$productID = $this->product->saveState($productID, $products);
$this->product->setMenu($products, $productID, 0, 0, '');
$tracks = $this->story->getTracks($productID);
$this->view->tracks = $tracks;
$this->view->title = $this->lang->story->track;
$this->view->posision[] = $this->lang->story->track;
$this->display();
}
/**
* Tasks of a story.
*
@@ -1260,21 +1283,36 @@ class story extends control
* @access public
* @return void
*/
public function linkStory($storyID, $type = 'linkStories', $browseType = '', $param = 0)
public function linkStory($storyID, $type = 'linkStories', $linkedStoryID = 0, $browseType = '', $queryID = 0)
{
$this->commonAction($storyID);
if($type == 'remove')
{
$result = $this->story->unlinkStory($storyID, $linkedStoryID);
die(js::reload('parent'));
}
if($_POST)
{
$this->story->linkStories($storyID);
if(dao::isError()) die(js::error(dao::getError()));
die(js::closeModal('parent.parent', 'this'));
}
/* Get story, product, products, and queryID. */
$story = $this->story->getById($storyID);
$products = $this->product->getPairs();
$queryID = ($browseType == 'bySearch') ? (int)$param : 0;
$queryID = 0;
/* Build search form. */
$actionURL = $this->createLink('story', 'linkStory', "storyID=$storyID&type=$type&browseType=bySearch&queryID=myQueryID", '', true);
$actionURL = $this->createLink('story', 'linkStory', "storyID=$storyID&type=$type&linkedStoryID=$linkedStoryID&browseType=bySearch&queryID=myQueryID", '', true);
$this->loadModel('product')->buildSearchForm($story->product, $products, $queryID, $actionURL);
/* Get stories to link. */
$stories2Link = $this->story->getStories2Link($storyID, $type, $browseType, $queryID);
$storyType = $story->type;
$stories2Link = $this->story->getStories2Link($storyID, $type, $browseType, $queryID, $storyType);
/* Assign. */
$this->view->title = $this->lang->story->linkStory . "STORY" . $this->lang->colon .$this->lang->story->linkStory;
+1
View File
@@ -1,3 +1,4 @@
.side-col .cell{padding:0px;}
.side-col #legendProjectAndTask .list-unstyled{padding:10px; border-top:0px; margin:0px;}
.col-4 .cell .tab-content .text-top{padding-top: 1px}
#legendStories ul li{padding: 10px 0 0 12px; line-height: 20px}
+14
View File
@@ -8,4 +8,18 @@ $(function()
/* Add for task #5385. */
if(config.onlybody == 'yes') $('.main-actions').css('width', '100%')
$('#unlinkStory').click(function()
{
if($('.removeButton').hasClass('hide'))
{
$('.removeButton').removeClass('hide');
$(this).text(cancel);
}
else
{
$('.removeButton').addClass('hide');
$(this).text(unlink);
}
})
});
+55 -43
View File
@@ -9,49 +9,56 @@
* @version $Id: en.php 5141 2013-07-15 05:57:15Z chencongzhi520@gmail.com $
* @link http://www.zentao.net
*/
$lang->story->create = "Create Story";
$lang->story->batchCreate = "Batch Create";
$lang->story->change = "Change";
$lang->story->changeAction = "Change Story";
$lang->story->changed = 'Change';
$lang->story->assignTo = 'Assign';
$lang->story->assignAction = 'Assign Story';
$lang->story->review = 'Review';
$lang->story->reviewAction = 'Review Story';
$lang->story->needReview = 'Need Review';
$lang->story->batchReview = 'Batch Review';
$lang->story->edit = "Edit Story";
$lang->story->batchEdit = "Batch Edit";
$lang->story->subdivide = 'Decompose';
$lang->story->subdivideAction = 'Decompose Story';
$lang->story->splitRequirent = 'Decompose';
$lang->story->close = 'Close';
$lang->story->closeAction = 'Close Story';
$lang->story->batchClose = 'Batch Close';
$lang->story->activate = 'Activate';
$lang->story->activateAction = 'Activate Story';
$lang->story->delete = "Delete";
$lang->story->deleteAction = "Delete Story";
$lang->story->view = "Story Detail";
$lang->story->setting = "Settings";
$lang->story->tasks = "Linked Tasks";
$lang->story->bugs = "Linked Bugs";
$lang->story->cases = "Linked Cases";
$lang->story->taskCount = 'Tasks';
$lang->story->bugCount = 'Bugs';
$lang->story->caseCount = 'Cases';
$lang->story->taskCountAB = 'T';
$lang->story->bugCountAB = 'B';
$lang->story->caseCountAB = 'C';
$lang->story->linkStory = 'Link Story';
$lang->story->unlinkStory = 'UnLinked';
$lang->story->export = "Export Data";
$lang->story->exportAction = "Export Story";
$lang->story->zeroCase = "Stories without cases";
$lang->story->zeroTask = "Only list stories without tasks";
$lang->story->reportChart = "Report";
$lang->story->reportAction = "Story Report";
$lang->story->copyTitle = "Copy Title";
$lang->story->create = "Create Story";
$lang->story->createStory = 'Create Story';
$lang->story->createRequirement = 'Create Requirement';
$lang->story->requirement = 'Requirement';
$lang->story->story = 'Story';
$lang->story->batchCreate = "Batch Create";
$lang->story->change = "Change";
$lang->story->changeAction = "Change Story";
$lang->story->changed = 'Change';
$lang->story->assignTo = 'Assign';
$lang->story->assignAction = 'Assign Story';
$lang->story->review = 'Review';
$lang->story->reviewAction = 'Review Story';
$lang->story->needReview = 'Need Review';
$lang->story->batchReview = 'Batch Review';
$lang->story->edit = "Edit Story";
$lang->story->batchEdit = "Batch Edit";
$lang->story->subdivide = 'Decompose';
$lang->story->link = 'Link';
$lang->story->unlink = 'Unlink';
$lang->story->track = 'Track';
$lang->story->subdivideAction = 'Decompose Story';
$lang->story->splitRequirent = 'Decompose';
$lang->story->close = 'Close';
$lang->story->closeAction = 'Close Story';
$lang->story->batchClose = 'Batch Close';
$lang->story->activate = 'Activate';
$lang->story->activateAction = 'Activate Story';
$lang->story->delete = "Delete";
$lang->story->deleteAction = "Delete Story";
$lang->story->view = "Story Detail";
$lang->story->setting = "Settings";
$lang->story->tasks = "Linked Tasks";
$lang->story->bugs = "Linked Bugs";
$lang->story->cases = "Linked Cases";
$lang->story->taskCount = 'Tasks';
$lang->story->bugCount = 'Bugs';
$lang->story->caseCount = 'Cases';
$lang->story->taskCountAB = 'T';
$lang->story->bugCountAB = 'B';
$lang->story->caseCountAB = 'C';
$lang->story->linkStory = 'Link Story';
$lang->story->unlinkStory = 'UnLinked';
$lang->story->export = "Export Data";
$lang->story->exportAction = "Export Story";
$lang->story->zeroCase = "Stories without cases";
$lang->story->zeroTask = "Only list stories without tasks";
$lang->story->reportChart = "Report";
$lang->story->reportAction = "Story Report";
$lang->story->copyTitle = "Copy Title";
$lang->story->batchChangePlan = "Batch Change Plans";
$lang->story->batchChangeBranch = "Batch Change Branches";
$lang->story->batchChangeStage = "Batch Change Phases";
@@ -120,6 +127,11 @@ $lang->story->allStories = 'All Stories';
$lang->story->unclosed = 'Unclosed';
$lang->story->deleted = 'Deleted';
$lang->story->released = 'Released Stories';
$lang->story->design = 'Designs';
$lang->story->case = 'Cases';
$lang->story->bug = 'Bugs';
$lang->story->repoCommit = 'Commits';
$lang->story->noRequirement = 'No Requirements';
$lang->story->ditto = 'Ditto';
$lang->story->dittoNotice = 'This story is not linked to the same product as the last one is!';
+10
View File
@@ -12,6 +12,8 @@
$lang->story->create = "提{$lang->storyCommon}";
$lang->story->createStory = '添加软需';
$lang->story->createRequirement = '添加用需';
$lang->story->requirement = '用户需求';
$lang->story->story = '软件需求';
$lang->story->batchCreate = "批量创建";
$lang->story->change = "变更";
$lang->story->changeAction = "变更{$lang->storyCommon}";
@@ -25,6 +27,9 @@ $lang->story->batchReview = '批量评审';
$lang->story->edit = "编辑";
$lang->story->batchEdit = "批量编辑";
$lang->story->subdivide = '细分';
$lang->story->link = '关联';
$lang->story->unlink = '移除';
$lang->story->track = '跟踪矩阵';
$lang->story->subdivideAction = "细分{$lang->storyCommon}";
$lang->story->splitRequirent = '拆分';
$lang->story->close = '关闭';
@@ -122,6 +127,11 @@ $lang->story->allStories = "所有{$lang->storyCommon}";
$lang->story->unclosed = '未关闭';
$lang->story->deleted = '已删除';
$lang->story->released = "已发布{$lang->storyCommon}数";
$lang->story->design = '相关设计';
$lang->story->case = '相关用例';
$lang->story->bug = '相关Bug';
$lang->story->repoCommit = '相关提交';
$lang->story->noRequirement = '无需求';
$lang->story->ditto = '同上';
$lang->story->dittoNotice = "该{$lang->storyCommon}与上一{$lang->storyCommon}不属于同一产品!";
+268 -15
View File
@@ -1572,30 +1572,43 @@ class storyModel extends model
/**
* Get stories to link.
*
* @param int $storyID
* @param string $type
* @param string $browseType
* @param int $queryID
* @param int $storyID
* @param string $type
* @param string $browseType
* @param int $queryID
* @param varchar $storyType
* @access public
* @return array
*/
public function getStories2Link($storyID, $type = 'linkStories', $browseType = 'bySearch', $queryID = 0)
public function getStories2Link($storyID, $type = 'linkStories', $browseType = 'bySearch', $queryID = 0, $storyType = 'story')
{
$story = $this->getById($storyID);
$linkedStories = $this->getRelation($storyID, $story->type);
$linkedStories = empty($linkedStories) ? array() : $linkedStories;
$tmpStoryType = $storyType == 'story' ? 'requirement' : 'story';
if($browseType == 'bySearch')
{
$story = $this->getById($storyID);
$stories2Link = $this->getBySearch($story->product, $queryID, 'id', null, '', $story->branch);
{
$stories2Link = $this->getBySearch($story->product, $queryID, 'id', null, '', $story->branch, $tmpStoryType);
foreach($stories2Link as $key => $story2Link)
{
{
if($story2Link->id == $storyID) unset($stories2Link[$key]);
if(in_array($story2Link->id, explode(',', $story->$type))) unset($stories2Link[$key]);
}
return $stories2Link;
}
}
}
else
{
return array();
}
{
$status = $storyType == 'story' ? 'active' : 'all';
$stories2Link = $this->getProductStories($story->product, $story->branch, 0, $status, $tmpStoryType, $orderBy = 'id_desc');
}
foreach($stories2Link as $id => $story)
{
if(in_array($story->id, array_keys($linkedStories))) unset($stories2Link[$id]);
if($storyType == 'story' && $story->status == 'draft') unset($stories2Link[$id]);
}
return $stories2Link;
}
/**
@@ -3135,4 +3148,244 @@ class storyModel extends model
return array($toList, $ccList);
}
/**
* Get tracks.
*
* @param int $productID
* @access public
* @return bool|array
*/
public function getTracks($productID)
{
$requirements = $this->getProductStories($productID, 0, 0, 'all', 'requirement', 'id_desc');
foreach($requirements as $requirement)
{
$stories = $this->getRelation($requirement->id, 'requirement');
$stories = empty($stories) ? array() : $stories;
foreach($stories as $id => $title)
{
$stories[$id] = new stdclass();
$stories[$id]->title = $title;
$stories[$id]->case = $this->loadModel('testcase')->getStoryCases($id);
$stories[$id]->bug = $this->loadModel('bug')->getStoryBugs($id);
$stories[$id]->design = $this->dao->select('id, name')->from(TABLE_DESIGN)->where('story')->eq($id)->fetchAll('id');
$stories[$id]->revision = $this->dao->select('BID, extra')->from(TABLE_RELATION)->where('AType')->eq('design')->andWhere('BType')->eq('commit')->andWhere('AID')->in(array_keys($stories[$id]->design))->fetchPairs();
}
$requirement->track = $stories;
}
/* Get no requirements story. */
$stories = $this->getProductStories($productID, 0, 0, 'all', 'story', 'id_desc');
foreach($stories as $id => $story)
{
$counts = $this->getStoryRelationCounts($story->id, 'story');
if($counts != 0)
{
unset($stories[$id]);
continue;
}
$title = $stories[$id]->title;
$stories[$id] = new stdclass();
$stories[$id]->title = $title;
$stories[$id]->case = $this->loadModel('testcase')->getStoryCases($id);
$stories[$id]->bug = $this->loadModel('bug')->getStoryBugs($id);
$stories[$id]->design = $this->dao->select('id, name')->from(TABLE_DESIGN)->where('story')->eq($id)->fetchAll('id');
$stories[$id]->revision = $this->dao->select('BID, extra')->from(TABLE_RELATION)->where('AType')->eq('design')->andWhere('BType')->eq('commit')->andWhere('AID')->in(array_keys($stories[$id]->design))->fetchPairs();
}
$requirements['noRequirement'] = $stories;
return $requirements;
}
/**
* Get track by id.
*
* @param int $storyID
* @access public
* @return bool|array
*/
public function getTrackByID($storyID)
{
$requirement = $this->getByID($storyID);
$stories = $this->getRelation($requirement->id, 'requirement');
$track = array();
$stories = empty($stories) ? array() : $stories;
foreach($stories as $id => $title)
{
$track[$id] = new stdclass();
$track[$id]->title = $title;
$track[$id]->case = $this->loadModel('testcase')->getStoryCases($id);
$track[$id]->bug = $this->loadModel('bug')->getStoryBugs($id);
$track[$id]->design = $this->dao->select('id, name')->from(TABLE_DESIGN)->where('story')->eq($id)->fetchAll('id');
$track[$id]->story = $this->getByID($id);
$track[$id]->revision = $this->dao->select('BID, extra')->from(TABLE_RELATION)->where('AType')->eq('design')->andWhere('BType')->eq('commit')->andWhere('AID')->in(array_keys($track[$id]->design))->fetchPairs();
}
return $track;
}
/**
* Obtain the direct relationship between UR and SR.
*
* @param int $storyID
* @param string $storyType
* @param string $storyType
* @access public
* @return int
*/
public function getStoryRelation($storyID, $storyType, $fields = array())
{
$conditionField = ($storyType == 'story') ? 'BID' : 'AID';
$storyType = ($storyType == 'story') ? 'AID' : 'BID';
$relations = $this->dao->select($storyType)->from(TABLE_RELATION)
->where('AType')->eq('requirement')
->andWhere('BType')->eq('story')
->andWhere('relation')->eq('subdivideinto')
->andWhere($conditionField)->eq($storyID)
->fetchAll($storyType);
if(empty($relations)) return array();
$fields = empty($fields) ? '*' : implode(',', $fields);
$story = $this->dao->select($fields)->from(TABLE_STORY)
->where('id')->in(array_keys($relations))
->andWhere('deleted')->eq(0)
->orderBy('id_desc')
->fetchAll();
return $story;
}
/**
* Link stories.
*
* @param int $storyID
* @access public
* @return void
*/
public function linkStories($storyID)
{
$story = $this->getByID($storyID);
$stories = $this->post->stories;
$isStory = ($story->type == 'story');
foreach($stories as $id)
{
$requirement = $this->getByID($id);
$data = new stdclass();
$data->program = $this->session->program;
$data->product = $this->session->product;
$data->AType = 'requirement';
$data->BType = 'story';
$data->relation = 'subdivideinto';
$data->AID = $isStory ? $id : $storyID;
$data->BID = $isStory ? $storyID : $id;
$data->AVersion = $isStory ? $requirement->version : $story->version;
$data->BVersion = $isStory ? $story->version : $requirement->version;
$this->dao->insert(TABLE_RELATION)->data($data)->autoCheck()->exec();
$data->AType = 'story';
$data->BType = 'requirement';
$data->relation = 'subdividedfrom';
$data->AID = $isStory ? $storyID : $id;
$data->BID = $isStory ? $id : $storyID;
$data->AVersion = $isStory ? $story->version : $requirement->version;
$data->BVersion = $isStory ? $requirement->version : $story->version;
$this->dao->insert(TABLE_RELATION)->data($data)->autoCheck()->exec();
}
}
/**
* Unlink story.
*
* @param int $storyID
* @param int $linkedStoryID
* @access public
* @return void
*/
public function unlinkStory($storyID, $linkedStoryID)
{
$idList = "$storyID,$linkedStoryID";
$this->dao->delete()->from(TABLE_RELATION)
->where('AType')->in('story,requirement')
->andWhere('BType')->in('story,requirement')
->andWhere('relation')->in('subdivideinto,subdividedfrom')
->andWhere('AID')->in($idList)
->andWhere('BID')->in($idList)
->exec();
return !dao::isError();
}
/**
* Get story relations.
*
* @param int $storyID
* @param varchar $storyType
* @access public
* @return int
*/
public function getRelation($storyID, $storyType, $extraField = array())
{
$BType = $storyType == 'story' ? 'requirement' : 'story';
$relation = $storyType == 'story' ? 'subdividedfrom' : 'subdivideinto';
$relations = $this->dao->select('BID')->from(TABLE_RELATION)
->where('AType')->eq($storyType)
->andWhere('BType')->eq($BType)
->andWhere('relation')->eq($relation)
->andWhere('AID')->eq($storyID)
->fetchPairs();
if(!empty($relations))
{
if(empty($extraField))
{
return $this->dao->select('id, title')
->from(TABLE_STORY)
->where('deleted')->eq(0)
->andWhere('id')->in($relations)
->fetchPairs();
}
else
{
return $this->dao->select(implode($extraField, ','))
->from(TABLE_STORY)
->where('deleted')->eq(0)
->andWhere('id')->in($relations)
->fetchAll('id');
}
}
}
/**
* Get software requirements associated with user needs.
*
* @param array $storyID
* @param string $storyType
* @access public
* @return int
*/
public function getStoryRelationCounts($storyID, $storyType = '')
{
$selectField = ($storyType == 'story') ? 'AID' : 'BID';
$conditionField = ($storyType == 'story') ? 'BID' : 'AID';
$relations = $this->dao->select('count('. $selectField .') as id')->from(TABLE_RELATION)
->where('AType')->eq('requirement')
->andWhere('BType')->eq('story')
->andWhere('relation')->eq('subdivideinto')
->andWhere($conditionField)->eq($storyID)
->fetch('id');
return $relations;
}
}
-28
View File
@@ -219,34 +219,6 @@
<td><?php echo html::input('duplicateStory', $story->duplicateStory, "class='form-control'");?></td>
</tr>
<?php endif;?>
<tr>
<th class='linkThWidth'><?php echo $lang->story->linkStories;?></th>
<td><?php echo html::a($this->createLink('story', 'linkStory', "storyID=$story->id&type=linkStories", '', true), $lang->story->linkStory, '', "data-toggle='modal' data-type='iframe' data-width='95%'");?></td>
</tr>
<tr>
<th></th>
<td>
<ul class='list-unstyled'>
<?php
if($story->linkStories)
{
$linkStories = explode(',', $story->linkStories);
foreach($linkStories as $linkStoryID)
{
if(isset($story->extraStories[$linkStoryID]))
{
echo "<li><div class='checkbox-primary'>";
echo "<input type='checkbox' checked='checked' name='linkStories[]' value=$linkStoryID />";
echo "<label>#{$linkStoryID} {$story->extraStories[$linkStoryID]}</label>";
echo '</div></li>';
}
}
}
?>
<span id='linkStoriesBox'></span>
</ul>
</td>
</tr>
<?php if($story->status == 'closed'):?>
<tr class='text-top'>
<th><?php echo $lang->story->childStories;?></th>
+4 -18
View File
@@ -36,11 +36,11 @@
<?php echo $lang->idAB;?>
</th>
<th class='c-pri'><?php echo $lang->priAB;?></th>
<th><?php echo $lang->story->product;?></th>
<th><?php echo $lang->story->title;?></th>
<th><?php echo $lang->story->plan;?></th>
<th class='w-80px'><?php echo $lang->story->status;?></th>
<?php if($story->type == 'requirement'):?>
<th class='w-80px'><?php echo $lang->story->stage;?></th>
<?php endif;?>
<th class='w-user'><?php echo $lang->openedByAB;?></th>
<th class='w-80px'><?php echo $lang->story->estimateAB;?></th>
</tr>
@@ -58,11 +58,11 @@
<?php echo html::a($storyLink, sprintf('%03d', $story2Link->id));?>
</td>
<td class='c-pri'><span class='label-pri <?php echo 'label-pri-' . $story2Link->pri?>' title='<?php echo zget($lang->story->priList, $story2Link->pri, $story2Link->pri);?>'><?php echo zget($lang->story->priList, $story2Link->pri, $story2Link->pri);?></span></td>
<td><?php echo html::a($this->createLink('product', 'browse', "productID=$story2Link->product&branch=$story2Link->branch"), $products[$story2Link->product], '_blank');?></td>
<td class='text-left nobr' title="<?php echo $story2Link->title?>"><?php echo html::a($storyLink, $story2Link->title, '_blank');?></td>
<td><?php echo $story2Link->planTitle;?></td>
<td><?php echo $this->processStatus('story', $story2Link);?></td>
<?php if($story->type == 'requirement'):?>
<td><?php echo zget($lang->story->stageList, $story2Link->stage);?></td>
<?php endif;?>
<td><?php echo zget($users, $story2Link->openedBy);?></td>
<td><?php echo $story2Link->estimate;?></td>
</tr>
@@ -87,20 +87,6 @@ $(function()
$('#linkStoryForm').table();
setTimeout(function(){$('#linkStoryForm .table-footer').removeClass('fixed-footer');}, 100);
<?php endif;?>
$('#submit').click(function(){
var output = '';
$('#linkStoryForm').find('tr.checked').each(function(){
var storyID = $(this).find('td.c-id').find('div.checkbox-primary input').attr('value');
var storyName = "#" + storyID + ' ' + $(this).find('td').eq(3).attr('title');
var checkbox = "<li><div class='checkbox-primary'><input type='checkbox' checked='checked' name='" + linkType + "[]' " + "value=" + storyID + " /><label>" + storyName + "</label></div></li>";
output += checkbox;
});
$.closeModal();
parent.$('#' + linkType + 'Box').html(output);
return false;
});
});
</script>
<?php include '../../common/view/footer.html.php';?>
+86
View File
@@ -0,0 +1,86 @@
<?php include '../../common/view/header.html.php';?>
<?php js::set('storyType', 'track');?>
<style>
.table td{white-space:nowrap;text-overflow:ellipsis;overflow:hidden;}
.requirement{background: #fff}
.main-table tbody>tr:hover { background-color: #fff; }
.main-table tbody>tr:nth-child(odd):hover { background-color: #f5f5f5; }
</style>
<div id="mainContent" class="main-row fade">
<div class="main-col">
<?php if(empty($tracks)):?>
<div class="table-empty-tip">
<p>
<span class="text-muted"><?php echo $lang->noData;?></span>
</p>
</div>
<?php else:?>
<div class='main-table' data-ride="table">
<table class='table table-bordered' id="trackList">
<thead>
<tr>
<th><?php echo $lang->story->requirement;?></th>
<th><?php echo $lang->story->story;?></th>
<th><?php echo $lang->story->design;?></th>
<th><?php echo $lang->story->case;?></th>
<th><?php echo $lang->story->repoCommit;?></th>
<th><?php echo $lang->story->bug;?></th>
</tr>
</thead>
<tbody>
<?php foreach($tracks as $key => $requirement):?>
<?php $track = ($key == 'noRequirement') ? $requirement : $requirement->track;?>
<?php $rowspan = count($track);?>
<tr>
<td <?php if($rowspan != 0) echo "rowspan=" . $rowspan;?> class='requirement'>
<?php echo $key == 'noRequirement' ? $lang->story->noRequirement : html::a($this->createLink('story', 'view', "storyID=$requirement->id"), $requirement->title, '', "title=$requirement->title");?>
<?php if($key != 'noRequirement'):?>
<span class="label label-primary label-outline"><?php echo zget($lang->story->statusList, $requirement->status);?></span>
<?php endif;?>
</td>
<?php if(count($track) != 0):?>
<?php $i = 1;?>
<?php foreach($track as $storyID => $story):?>
<?php if($i != 1) echo '<tr>';?>
<td style='padding-left: 10px;'><?php echo html::a($this->createLink('story', 'view', "storyID=$storyID"), $story->title, '',"title='$story->title'");?></td>
<td>
<?php foreach($story->design as $designID => $design):?>
<?php echo html::a($this->createLink('design', 'view', "designID=$designID"), $design->name, '', "title='$design->name'") . '<br/>';?>
<?php endforeach;?>
</td>
<td>
<?php foreach($story->case as $caseID => $case):?>
<?php echo html::a($this->createLink('testcase', 'view', "caseID=$caseID"), $case->title, '', "title='$case->title'") . '<br/>';?>
<?php endforeach;?>
</td>
<td>
<?php foreach($story->revision as $revision => $repoID):?>
<?php
echo html::a($this->createLink('design', 'revision', "repoID=$revision"), '#'. $revision) . '<br/>';
?>
<?php endforeach;?>
</td>
<td>
<?php foreach($story->bug as $bugID => $bug):?>
<?php echo html::a($this->createLink('bug', 'view', "bugID=$bugID"), $bug->title, '', "title='$bug->title'") . '<br/>';?>
<?php endforeach;?>
</td>
<?php if($i != 1) echo '</tr>';?>
<?php $i++;?>
<?php endforeach;?>
<?php else:?>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<?php endif;?>
</tr>
<?php endforeach;?>
</tbody>
</table>
</div>
<?php endif;?>
</div>
</div>
<?php include '../../common/view/footer.html.php';?>
+74
View File
@@ -62,6 +62,56 @@
<div class="detail-title"><?php echo $lang->story->legendVerify;?></div>
<div class="detail-content article-content"><?php echo $story->verify;?></div>
</div>
<?php if($story->type == 'requirement'):?>
<?php if(!empty($track)):?>
<div class="detail">
<div class="detail-title"><?php echo $lang->story->track;?></div>
<div class="detail-content article-content main-table">
<table class="table">
<thead>
<tr>
<th class="w-120px"><?php echo $lang->story->story;?></th>
<th class="w-120px"><?php echo $lang->story->design;?></th>
<th class="w-120px"><?php echo $lang->story->case;?></th>
<th class="w-60px"><?php echo $lang->story->repoCommit;?></th>
<th class="w-120px"><?php echo $lang->story->bug;?></th>
</tr>
</thead>
<tbody>
<?php foreach($track as $storyID => $storyInfo):?>
<tr>
<td style='padding-left: 10px;'><?php echo html::a($this->createLink('story', 'view', "storyID=$storyID"), $storyInfo->title, '', "title='$storyInfo->title'");?>
</td>
<td>
<?php foreach($storyInfo->design as $designID => $design):?>
<?php echo html::a($this->createLink('design', 'view', "designID=$designID"), $design->name, '', "title='$design->name'") . '<br/>';?>
<?php endforeach;?>
</td>
<td>
<?php foreach($storyInfo->case as $caseID => $case):?>
<?php echo html::a($this->createLink('testcase', 'view', "caseID=$caseID"), $case->title, '', "title='$case->title'") . '<br/>';?>
<?php endforeach;?>
</td>
<td>
<?php foreach($storyInfo->revision as $revision => $repoID):?>
<?php
echo html::a($this->createLink('design', 'revision', "repoID=$revision"), '#'. $revision) . '<br/>';
?>
<?php endforeach;?>
</td>
<td>
<?php foreach($storyInfo->bug as $bugID => $bug):?>
<?php echo html::a($this->createLink('bug', 'view', "bugID=$bugID"), $bug->title, '', "title='$bug->title'") . '<br/>';?>
<?php endforeach;?>
</td>
</tr>
<?php endforeach;?>
</tbody>
</table>
</div>
</div>
<?php endif;?>
<?php endif;?>
<?php echo $this->fetch('file', 'printFiles', array('files' => $story->files, 'fieldset' => 'true'));?>
<?php $actionFormLink = $this->createLink('action', 'comment', "objectType=story&objectID=$story->id");?>
<?php if(!empty($story->children)):?>
@@ -334,12 +384,34 @@
<ul class='nav nav-tabs'>
<?php if($config->global->flow == 'onlyStory'):?>
<li class='active'><a href='#legendRelated' data-toggle='tab'><?php echo $lang->story->legendRelated;?></a></li>
<?php elseif($program->template == 'cmmi'):?>
<li class='active'><a href='#legendStories' data-toggle='tab'><?php echo $story->type == 'story' ? $lang->story->requirement : $lang->story->story;?></a></li>
<li><a href='#legendProjectAndTask' data-toggle='tab'><?php echo $lang->story->legendProjectAndTask;?></a></li>
<li><a href='#legendRelated' data-toggle='tab'><?php echo $lang->story->legendRelated;?></a></li>
<?php else:?>
<li class='active'><a href='#legendProjectAndTask' data-toggle='tab'><?php echo $lang->story->legendProjectAndTask;?></a></li>
<li><a href='#legendRelated' data-toggle='tab'><?php echo $lang->story->legendRelated;?></a></li>
<?php endif;?>
</ul>
<div class='tab-content'>
<?php if($program->template == 'cmmi'):?>
<div class='tab-pane active' id='legendStories'>
<ul class="list-unstyled">
<?php
$relation = array();
foreach($relations as $item) $relation[$item->id] = $item->title;
foreach($relation as $id => $title)
{
echo "<li title='$title'>" . html::a($this->createLink('story', 'view', "id=$id", '', true), "#$id $title", '', "class='iframe' data-width='80%'");
echo html::a($this->createLink('story', 'linkStory', "storyID=$story->id&type=remove&linkedID=$id"), '<i class="icon icon-close"></i>', 'hiddenwin', "class='deleter hide removeButton'");
}
?>
<?php $linkLang = ($story->type == 'story') ? $lang->story->requirement : $lang->story->story;?>
<li><?php echo html::a($this->createLink('story', 'linkStory', "storyID=$story->id", '', true), $lang->story->link . $linkLang, '', "class='btn btn-info iframe' data-width='95%' id='linkButton'");?>
<?php if(!empty($relations)) echo html::a('javascript:void(0)', $lang->story->unlink . $linkLang, '', "class='btn btn-info' id='unlinkStory'");?></li>
</ul>
</div>
<?php endif;?>
<?php if($config->global->flow != 'onlyStory'):?>
<div class='tab-pane active' id='legendProjectAndTask'>
<ul class="list-unstyled">
@@ -454,6 +526,8 @@ js::set('productID', $story->product);
js::set('branch', $story->branch);
js::set('moduleID', $story->module);
js::set('storyType', $story->type);
js::set('unlink', $lang->story->unlink);
js::set('cancel', $lang->cancel);
?>
<?php include '../../common/view/syntaxhighlighter.html.php';?>
<?php include '../../common/view/footer.html.php';?>