* code for task #47149.
This commit is contained in:
@@ -1 +1,3 @@
|
||||
ALTER TABLE `zt_project` ADD `vision` varchar(10) NOT NULL DEFAULT 'common' AFTER `order`;
|
||||
ALTER TABLE `zt_product` ADD `vision` varchar(10) NOT NULL DEFAULT 'common' AFTER `order`;
|
||||
ALTER TABLE `zt_doclib` ADD `vision` varchar(10) NOT NULL DEFAULT 'common' AFTER `order`;
|
||||
|
||||
@@ -7,7 +7,6 @@ $lang->mainNav->menuOrder[35] = 'doc';
|
||||
$lang->mainNav->menuOrder[45] = 'system';
|
||||
$lang->mainNav->menuOrder[65] = 'admin';
|
||||
|
||||
|
||||
/* My menu. */
|
||||
$lang->my->menu = new stdclass();
|
||||
$lang->my->menu->index = array('link' => "$lang->dashboard|my|index");
|
||||
@@ -50,3 +49,6 @@ $lang->scrum->menu->settings['subMenu'] = new stdclass();
|
||||
$lang->scrum->menu->settings['subMenu']->view = array('link' => "$lang->overview|project|view|project=%s", 'alias' => 'edit');
|
||||
$lang->scrum->menu->settings['subMenu']->members = array('link' => "{$lang->team->common}|project|team|project=%s", 'alias' => 'managemembers,team');
|
||||
$lang->scrum->menu->settings['subMenu']->whitelist = array('link' => "{$lang->whitelist}|project|whitelist|project=%s", 'subModule' => 'personnel');
|
||||
|
||||
$lang->URCommon = '目标';
|
||||
$lang->SRCommon = '目标';
|
||||
|
||||
@@ -0,0 +1,187 @@
|
||||
<?php
|
||||
class product extends control
|
||||
{
|
||||
public function browse($productID = 0, $branch = '', $browseType = '', $param = 0, $storyType = 'story', $orderBy = '', $recTotal = 0, $recPerPage = 20, $pageID = 1, $projectID = 0)
|
||||
{
|
||||
|
||||
/* Load datatable and execution. */
|
||||
$this->loadModel('datatable');
|
||||
$this->loadModel('execution');
|
||||
$this->loadModel('user');
|
||||
|
||||
$projectProducts = $this->loadModel('product')->getProducts($projectID);
|
||||
$productPlans = $this->execution->getPlans($projectProducts);
|
||||
|
||||
$this->products = array();
|
||||
foreach($projectProducts as $productID => $product) $this->products[$productID] = $product->name;
|
||||
|
||||
$productID = key($projectProducts);
|
||||
$product = $projectProducts[$productID];
|
||||
|
||||
$showBranch = $this->loadModel('branch')->showBranch($productID, 0, $projectID);
|
||||
if(!empty($product)) $this->session->set('currentProductType', $product->type);
|
||||
|
||||
/* Set menu. */
|
||||
$this->session->set('storyList', $this->app->getURI(true), 'project');
|
||||
$this->loadModel('project')->setMenu($projectID);
|
||||
|
||||
$branches = $this->loadModel('branch')->getList($productID, $projectID, 'all');
|
||||
$branch = ($this->cookie->preBranch !== '' and $branch === '' and isset($branches[$this->cookie->preBranch])) ? $this->cookie->preBranch : $branch;
|
||||
$branchID = $branch;
|
||||
|
||||
/* Lower browse type. */
|
||||
$browseType = strtolower($browseType);
|
||||
|
||||
/* Set product, module and query. */
|
||||
setcookie('preProductID', $productID, $this->config->cookieLife, $this->config->webRoot, '', $this->config->cookieSecure, true);
|
||||
setcookie('preBranch', $branch, $this->config->cookieLife, $this->config->webRoot, '', $this->config->cookieSecure, true);
|
||||
|
||||
if($this->cookie->preProductID != $productID or $this->cookie->preBranch != $branch)
|
||||
{
|
||||
$_COOKIE['storyModule'] = 0;
|
||||
setcookie('storyModule', 0, 0, $this->config->webRoot, '', $this->config->cookieSecure, false);
|
||||
}
|
||||
|
||||
if($browseType == 'bymodule' or $browseType == '')
|
||||
{
|
||||
setcookie('storyModule', (int)$param, 0, $this->config->webRoot, '', $this->config->cookieSecure, false);
|
||||
if($this->app->tab == 'project') setcookie('storyModuleParam', (int)$param, 0, $this->config->webRoot, '', $this->config->cookieSecure, false);
|
||||
$_COOKIE['storyBranch'] = 'all';
|
||||
setcookie('storyBranch', 'all', 0, $this->config->webRoot, '', $this->config->cookieSecure, false);
|
||||
if($browseType == '') setcookie('treeBranch', $branch, 0, $this->config->webRoot, '', $this->config->cookieSecure, false);
|
||||
}
|
||||
|
||||
$cookieModule = $this->app->tab == 'project' ? $this->cookie->storyModuleParam : $this->cookie->storyModule;
|
||||
$moduleID = ($browseType == 'bymodule') ? (int)$param : (($browseType == 'bysearch') ? 0 : ($cookieModule ? $cookieModule : 0));
|
||||
$queryID = ($browseType == 'bysearch') ? (int)$param : 0;
|
||||
|
||||
/* Set moduleTree. */
|
||||
$createModuleLink = $storyType == 'story' ? 'createStoryLink' : 'createRequirementLink';
|
||||
if($browseType == '')
|
||||
{
|
||||
setcookie('treeBranch', $branch, 0, $this->config->webRoot, '', $this->config->cookieSecure, false);
|
||||
$browseType = 'unclosed';
|
||||
}
|
||||
else
|
||||
{
|
||||
$branch = $this->cookie->treeBranch;
|
||||
}
|
||||
|
||||
/* If in project story and not chose product, get project story mdoules. */
|
||||
$moduleTree = $this->loadModel('tree')->getTreeMenu($productID, 'story', $startModuleID = 0, array('treeModel', $createModuleLink), array('projectID' => $projectID, 'productID' => $productID), 'all', "¶m=$param&storyType=$storyType");
|
||||
|
||||
if($browseType != 'bymodule') $this->session->set('storyBrowseType', $browseType);
|
||||
|
||||
/* Process the order by field. */
|
||||
if(!$orderBy) $orderBy = $this->cookie->productStoryOrder ? $this->cookie->productStoryOrder : 'id_desc';
|
||||
setcookie('productStoryOrder', $orderBy, 0, $this->config->webRoot, '', $this->config->cookieSecure, true);
|
||||
|
||||
/* Append id for secend sort. */
|
||||
$sort = common::appendOrder($orderBy);
|
||||
|
||||
/* Load pager. */
|
||||
$this->app->loadClass('pager', $static = true);
|
||||
if($this->app->getViewType() == 'xhtml') $recPerPage = 10;
|
||||
$pager = new pager($recTotal, $recPerPage, $pageID);
|
||||
|
||||
/* Display of branch label. */
|
||||
$showBranch = $this->loadModel('branch')->showBranch($productID);
|
||||
|
||||
$product = $this->product->getById($productID);
|
||||
|
||||
/* Get stories. */
|
||||
$stories = $this->product->getStories($productID, $branchID, $browseType, $queryID, $moduleID, $storyType, $sort, $pager);
|
||||
|
||||
/* Display status of branch. */
|
||||
$branchOption = array();
|
||||
$branchTagOption = array();
|
||||
foreach($branches as $branchInfo)
|
||||
{
|
||||
$branchOption[$branchInfo->id] = $branchInfo->name;
|
||||
$branchTagOption[$branchInfo->id] = $branchInfo->name . ($branchInfo->status == 'closed' ? ' (' . $this->lang->branch->statusList['closed'] . ')' : '');
|
||||
}
|
||||
|
||||
/* Process the sql, get the conditon partion, save it to session. */
|
||||
$this->loadModel('common')->saveQueryCondition($this->dao->get(), 'story', ($browseType != 'bysearch' and $browseType != 'reviewbyme' and $this->app->rawModule != 'projectstory'));
|
||||
|
||||
if(!empty($stories)) $stories = $this->loadModel('story')->mergeReviewer($stories);
|
||||
|
||||
/* Get related tasks, bugs, cases count of each story. */
|
||||
$storyIdList = array();
|
||||
foreach($stories as $story)
|
||||
{
|
||||
$storyIdList[$story->id] = $story->id;
|
||||
if(!empty($story->children))
|
||||
{
|
||||
foreach($story->children as $child) $storyIdList[$child->id] = $child->id;
|
||||
}
|
||||
}
|
||||
$storyTasks = $this->loadModel('task')->getStoryTaskCounts($storyIdList);
|
||||
$storyBugs = $this->loadModel('bug')->getStoryBugCounts($storyIdList);
|
||||
$storyCases = $this->loadModel('testcase')->getStoryCaseCounts($storyIdList);
|
||||
|
||||
/* Change for requirement story title. */
|
||||
if($storyType == 'requirement')
|
||||
{
|
||||
$this->lang->story->title = str_replace($this->lang->SRCommon, $this->lang->URCommon, $this->lang->story->title);
|
||||
$this->lang->story->create = str_replace($this->lang->SRCommon, $this->lang->URCommon, $this->lang->story->create);
|
||||
$this->config->product->search['fields']['title'] = $this->lang->story->title;
|
||||
unset($this->config->product->search['fields']['plan']);
|
||||
unset($this->config->product->search['fields']['stage']);
|
||||
}
|
||||
|
||||
/* Build search form. */
|
||||
$rawModule = $this->app->rawModule;
|
||||
$rawMethod = $this->app->rawMethod;
|
||||
|
||||
$params = $rawModule == 'projectstory' ? "projectID=$projectID&" : '';
|
||||
$actionURL = $this->createLink($rawModule, $rawMethod, $params . "productID=$productID&branch=$branch&browseType=bySearch&queryID=myQueryID&storyType=$storyType");
|
||||
|
||||
$this->config->product->search['onMenuBar'] = 'yes';
|
||||
$this->product->buildSearchForm($productID, $this->products, $queryID, $actionURL, $branch);
|
||||
|
||||
$showModule = !empty($this->config->datatable->productBrowse->showModule) ? $this->config->datatable->productBrowse->showModule : '';
|
||||
|
||||
$productName = ($this->app->rawModule == 'projectstory' and empty($productID)) ? $this->lang->product->all : $this->products[$productID];
|
||||
|
||||
/* Assign. */
|
||||
$this->view->title = $productName . $this->lang->colon . $this->lang->product->browse;
|
||||
$this->view->position[] = $productName;
|
||||
$this->view->position[] = $this->lang->product->browse;
|
||||
$this->view->productID = $productID;
|
||||
$this->view->product = $product;
|
||||
$this->view->productName = $productName;
|
||||
$this->view->moduleID = $moduleID;
|
||||
$this->view->stories = $stories;
|
||||
$this->view->plans = $this->loadModel('productplan')->getPairs($productID, $branch === 'all' ? '' : $branch, '', true);
|
||||
$this->view->productPlans = isset($productPlans) ? array(0 => '') + $productPlans : array();
|
||||
$this->view->summary = $this->product->summary($stories, $storyType);
|
||||
$this->view->moduleTree = $moduleTree;
|
||||
$this->view->parentModules = $this->tree->getParents($moduleID);
|
||||
$this->view->pager = $pager;
|
||||
$this->view->users = $this->user->getPairs('noletter|pofirst|nodeleted');
|
||||
$this->view->orderBy = $orderBy;
|
||||
$this->view->browseType = $browseType;
|
||||
$this->view->modules = $this->tree->getOptionMenu($productID, 'story', 0, $branchID);
|
||||
$this->view->moduleID = $moduleID;
|
||||
$this->view->moduleName = ($moduleID and $moduleID !== 'all') ? $this->tree->getById($moduleID)->name : $this->lang->tree->all;
|
||||
$this->view->branch = $branch;
|
||||
$this->view->branchID = $branchID;
|
||||
$this->view->branchOption = $branchOption;
|
||||
$this->view->branchTagOption = $branchTagOption;
|
||||
$this->view->showBranch = $showBranch;
|
||||
$this->view->storyStages = $this->product->batchGetStoryStage($stories);
|
||||
$this->view->setModule = true;
|
||||
$this->view->storyTasks = $storyTasks;
|
||||
$this->view->storyBugs = $storyBugs;
|
||||
$this->view->storyCases = $storyCases;
|
||||
$this->view->param = $param;
|
||||
$this->view->projectID = $projectID;
|
||||
$this->view->products = $this->products;
|
||||
$this->view->projectProducts = isset($projectProducts) ? $projectProducts : array();
|
||||
$this->view->storyType = $storyType;
|
||||
$this->view->from = $this->app->tab;
|
||||
$this->view->modulePairs = $showModule ? $this->tree->getModulePairs($productID, 'story', $showModule) : array();
|
||||
$this->display();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,700 @@
|
||||
<?php
|
||||
/**
|
||||
* The browse view file of product module of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2015 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
|
||||
* @license ZPL (http://zpl.pub/page/zplv12.html)
|
||||
* @author Chunsheng Wang <chunsheng@cnezsoft.com>
|
||||
* @package product
|
||||
* @version $Id: browse.html.php 4909 2013-06-26 07:23:50Z chencongzhi520@gmail.com $
|
||||
* @link http://www.zentao.net
|
||||
*/
|
||||
?>
|
||||
<?php
|
||||
if(empty($productID))
|
||||
{
|
||||
$productID = key($projectProducts);
|
||||
$product = $projectProducts[$productID];
|
||||
$productName = $product->name;
|
||||
}
|
||||
?>
|
||||
<?php include $this->app->getModuleRoot() . '/common/view/header.html.php';?>
|
||||
<?php include $this->app->getModuleRoot() . '/common/view/datatable.fix.html.php';?>
|
||||
<style>
|
||||
body {margin-bottom: 25px;}
|
||||
#mainMenu .btn-toolbar .btn-group .dropdown-menu .btn-active-text:hover .text {color: #fff;}
|
||||
#mainMenu .btn-toolbar .btn-group .dropdown-menu .btn-active-text:hover .text:after {border-bottom: unset;}
|
||||
.body-modal #mainMenu>.btn-toolbar {width: auto;}
|
||||
</style>
|
||||
<?php js::set('browseType', $browseType);?>
|
||||
<?php js::set('productID', $productID);?>
|
||||
<?php js::set('projectID', $projectID);?>
|
||||
<?php js::set('branch', $branch);?>
|
||||
<?php js::set('rawModule', $this->app->rawModule);?>
|
||||
<?php js::set('productType', $this->app->tab == 'product' ? $product->type : '');?>
|
||||
<?php
|
||||
$unfoldStories = isset($config->product->browse->unfoldStories) ? json_decode($config->product->browse->unfoldStories, true) : array();
|
||||
$unfoldStories = zget($unfoldStories, $productID, array());
|
||||
js::set('unfoldStories', $unfoldStories);
|
||||
js::set('unfoldAll', $lang->execution->treeLevel['all']);
|
||||
js::set('foldAll', $lang->execution->treeLevel['root']);
|
||||
js::set('storyType', $storyType);
|
||||
$lang->story->createCommon = $storyType == 'story' ? $lang->story->createStory : $lang->story->createRequirement;
|
||||
$isProjectStory = $this->app->rawModule == 'projectstory';
|
||||
$projectIDParam = $isProjectStory ? "projectID=$projectID&" : '';
|
||||
?>
|
||||
<style>
|
||||
.btn-group .icon-close:before {font-size: 5px; vertical-align: 25%;}
|
||||
.btn-group a i.icon-plus, .btn-group a i.icon-link {font-size: 16px;}
|
||||
.btn-group a.btn-secondary, .btn-group a.btn-primary {border-right: 1px solid rgba(255,255,255,0.2);}
|
||||
.btn-group button.dropdown-toggle.btn-secondary, .btn-group button.dropdown-toggle.btn-primary {padding:6px;}
|
||||
</style>
|
||||
<div id="mainMenu" class="clearfix">
|
||||
<?php if(!$isProjectStory):?>
|
||||
<div id="sidebarHeader">
|
||||
<div class="title" title="<?php echo $moduleName;?>">
|
||||
<?php
|
||||
echo $moduleName;
|
||||
if($moduleID and $moduleID !== 'all')
|
||||
{
|
||||
$removeLink = $browseType == 'bymodule' ? $this->createLink($this->app->rawModule, $this->app->rawMethod, $projectIDParam . "productID=$productID&branch=$branch&browseType=$browseType¶m=0&storyType=$storyType&orderBy=$orderBy&recTotal=0&recPerPage={$pager->recPerPage}") : 'javascript:removeCookieByKey("storyModule")';
|
||||
echo html::a($removeLink, "<i class='icon icon-sm icon-close'></i>", '', "class='text-muted'");
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif;?>
|
||||
<div class="btn-toolbar pull-left">
|
||||
<?php if($isProjectStory): ?>
|
||||
<div class="btn-group">
|
||||
<a href="javascript:;" class="btn btn-link" style="padding-right: 0;"> <?php echo $moduleName;?> </a>
|
||||
<?php
|
||||
if($moduleID)
|
||||
{
|
||||
$removeLink = $browseType == 'bymodule' ? $this->createLink($this->app->rawModule, $this->app->rawMethod, $projectIDParam . "productID=$productID&branch=$branch&browseType=$browseType¶m=0&storyType=$storyType&orderBy=$orderBy&recTotal=0&recPerPage={$pager->recPerPage}") : 'javascript:removeCookieByKey("storyModuleParam")';
|
||||
echo html::a($removeLink, "<i class='icon icon-sm icon-close'></i>", '', "class='text-muted btn btn-link' style='padding-left: 0;'");
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<?php endif;?>
|
||||
<?php
|
||||
if(!commonModel::isTutorialMode())
|
||||
{
|
||||
foreach(customModel::getFeatureMenu($this->app->rawModule, $this->app->rawMethod) as $menuItem)
|
||||
{
|
||||
if(isset($menuItem->hidden)) continue;
|
||||
if($menuItem->name == 'emptysr' && $storyType == 'story') continue;
|
||||
$menuBrowseType = strpos($menuItem->name, 'QUERY') === 0 ? 'bySearch' : $menuItem->name;
|
||||
if($menuItem->name == 'more')
|
||||
{
|
||||
if(!empty($lang->product->moreSelects))
|
||||
{
|
||||
$moreLabel = $lang->more;
|
||||
$moreLabelActive = '';
|
||||
$storyBrowseType = $this->session->storyBrowseType;
|
||||
if(isset($lang->product->moreSelects[$storyBrowseType]))
|
||||
{
|
||||
$moreLabel = "<span class='text'>{$lang->product->moreSelects[$storyBrowseType]}</span> <span class='label label-light label-badge'>{$pager->recTotal}</span>";
|
||||
$moreLabelActive = 'btn-active-text';
|
||||
}
|
||||
echo '<div class="btn-group" id="more">';
|
||||
echo html::a('javascript:;', $moreLabel . " <span class='caret'></span>", '', "data-toggle='dropdown' class='btn btn-link $moreLabelActive'");
|
||||
echo "<ul class='dropdown-menu'>";
|
||||
foreach($lang->product->moreSelects as $key => $value)
|
||||
{
|
||||
$active = $key == $storyBrowseType ? 'btn-active-text' : '';
|
||||
echo '<li>' . html::a($this->createLink($this->app->rawModule, $this->app->rawMethod, $projectIDParam . "productID=$productID&branch=$branch&browseType=$key¶m=0&storyType=$storyType"), "<span class='text'>{$value}</span>", '', "class='btn btn-link $active'") . '</li>';
|
||||
}
|
||||
echo '</ul></div>';
|
||||
}
|
||||
}
|
||||
elseif($menuItem->name == 'QUERY')
|
||||
{
|
||||
$searchBrowseLink = $this->createLink($this->app->rawModule, $this->app->rawMethod, $projectIDParam . "productID=$productID&branch=$branch&browseType=$menuBrowseType¶m=%s&storyType=$storyType");
|
||||
$isBySearch = $this->session->storyBrowseType == 'bysearch';
|
||||
include $this->app->getModuleRoot() . '/common/view/querymenu.html.php';
|
||||
}
|
||||
else
|
||||
{
|
||||
$menuItemName = strtolower($menuItem->name);
|
||||
echo html::a($this->createLink($this->app->rawModule, $this->app->rawMethod, $projectIDParam . "productID=$productID&branch=$branch&browseType=$menuBrowseType¶m=0&storyType=$storyType"), "<span class='text'>$menuItem->text</span>" . ($menuItemName == $this->session->storyBrowseType ? ' <span class="label label-light label-badge">' . $pager->recTotal . '</span>' : ''), '', "id='{$menuItem->name}Tab' class='btn btn-link" . ($this->session->storyBrowseType == $menuItemName ? ' btn-active-text' : '') . "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
<a class="btn btn-link querybox-toggle" id='bysearchTab'><i class="icon icon-search muted"></i> <?php echo $lang->product->searchStory;?></a>
|
||||
</div>
|
||||
<?php if(!isonlybody()):?>
|
||||
<div class="btn-toolbar pull-right">
|
||||
<?php if($this->app->rawModule != 'projectstory') common::printIcon('story', 'report', "productID=$productID&branchID=$branch&storyType=$storyType&browseType=$browseType&moduleID=$moduleID&chartType=pie", '', 'button', 'bar-chart muted'); ?>
|
||||
<div class="btn-group">
|
||||
<button class="btn pull-right btn-link" data-toggle="dropdown"><i class="icon icon-export muted"></i> <span class="text"><?php echo $lang->export ?></span> <span class="caret"></span></button>
|
||||
<ul class="dropdown-menu" id='exportActionMenu'>
|
||||
<?php
|
||||
$tab = $isProjectStory ? 'project' : 'product';
|
||||
$class = common::hasPriv('story', 'export') ? '' : "class=disabled";
|
||||
$misc = common::hasPriv('story', 'export') ? "data-toggle='modal' data-type='iframe' class='export' data-app='$tab'" : "class=disabled";
|
||||
$link = common::hasPriv('story', 'export') ? $this->createLink('story', 'export', "productID=$productID&orderBy=$orderBy&projectID=0&browseType=$browseType&type=$storyType") : '#';
|
||||
echo "<li $class>" . html::a($link, $lang->story->export, '', $misc) . "</li>";
|
||||
?>
|
||||
</ul>
|
||||
</div>
|
||||
<?php if(common::canModify('product', $product)):?>
|
||||
<div class='btn-group dropdown'>
|
||||
<?php
|
||||
$createStoryLink = $this->createLink('story', 'create', "product=$productID&branch=$branch&moduleID=$moduleID&storyID=0&projectID=$projectID&bugID=0&planID=0&todoID=0&extra=&type=$storyType");
|
||||
$batchCreateLink = $this->createLink('story', 'batchCreate', "productID=$productID&branch=$branch&moduleID=$moduleID&storyID=0&project=$projectID&plan=0&type=$storyType");
|
||||
|
||||
$buttonLink = '';
|
||||
$buttonTitle = '';
|
||||
$buttonType = $from == 'project' ? 'btn-secondary' : 'btn-primary';
|
||||
if(common::hasPriv('story', 'batchCreate'))
|
||||
{
|
||||
$buttonLink = empty($productID) ? '' : $batchCreateLink;
|
||||
$buttonTitle = $lang->story->batchCreate;
|
||||
}
|
||||
if(common::hasPriv('story', 'create'))
|
||||
{
|
||||
$buttonLink = $createStoryLink;
|
||||
$buttonTitle = $lang->story->create;
|
||||
}
|
||||
|
||||
$hidden = empty($buttonLink) ? 'hidden' : '';
|
||||
echo html::a($buttonLink, "<i class='icon icon-plus'></i> $buttonTitle", '', "class='btn $buttonType $hidden create-story-btn' data-app='$tab'");
|
||||
?>
|
||||
<?php if(!empty($productID) and common::hasPriv('story', 'batchCreate') and common::hasPriv('story', 'create')): ?>
|
||||
<button type='button' class="btn <?php echo $buttonType?> dropdown-toggle" data-toggle='dropdown'><span class='caret'></span></button>
|
||||
<ul class='dropdown-menu pull-right'>
|
||||
<li>
|
||||
<?php
|
||||
if(commonModel::isTutorialMode())
|
||||
{
|
||||
$wizardParams = helper::safe64Encode("productID=$productID&branch=$branch&moduleID=$moduleID");
|
||||
if($isProjectStory) $wizardParams = helper::safe64Encode("productID=$productID&branch=$branch&moduleID=$moduleID&storyID=&projectID=$projectID");
|
||||
$link = $this->createLink('tutorial', 'wizard', "module=story&method=create¶ms=$wizardParams");
|
||||
echo html::a($link, $lang->story->createCommon, '', "data-app='$tab'");
|
||||
}
|
||||
else
|
||||
{
|
||||
echo html::a($createStoryLink, $lang->story->create, '', "data-group='$tab'");
|
||||
}
|
||||
?>
|
||||
</li>
|
||||
<li><?php echo html::a($batchCreateLink, $lang->story->batchCreate, '', "data-group='$tab'");?></li>
|
||||
</ul>
|
||||
<?php endif;?>
|
||||
</div>
|
||||
<?php endif;?>
|
||||
</div>
|
||||
<?php endif;?>
|
||||
</div>
|
||||
<?php if($this->app->getViewType() == 'xhtml'):?>
|
||||
<div id="xx-title">
|
||||
<strong>
|
||||
<?php echo $this->product->getByID($productID)->name ?>
|
||||
</strong>
|
||||
<div class="linkButton" onclick="handleLinkButtonClick()">
|
||||
<span title="<?php echo $lang->viewDetails;?>">
|
||||
<i class="icon icon-import icon-rotate-270"></i>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif;?>
|
||||
<div id="mainContent" class="main-row fade">
|
||||
<div class="side-col" id="sidebar">
|
||||
<div class="sidebar-toggle"><i class="icon icon-angle-left"></i></div>
|
||||
<div class="cell">
|
||||
<?php if(!$moduleTree):?>
|
||||
<hr class="space">
|
||||
<div class="text-center text-muted">
|
||||
<?php echo $lang->product->noModule;?>
|
||||
</div>
|
||||
<hr class="space">
|
||||
<?php endif;?>
|
||||
<?php echo $moduleTree;?>
|
||||
<div class="text-center">
|
||||
<?php if($productID) common::printLink('tree', 'browse', "rootID=$productID&view=story¤tModuleID=0&branch=$branchID", $lang->tree->manage, '', "class='btn btn-info btn-wide'");?>
|
||||
<hr class="space-sm" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="main-col">
|
||||
<div class="cell<?php if($browseType == 'bysearch') echo ' show';?>" id="queryBox" data-module='story'></div>
|
||||
<?php if(empty($stories)):?>
|
||||
<div class="table-empty-tip">
|
||||
<p>
|
||||
<span class="text-muted"><?php echo $storyType == 'story' ? $lang->story->noStory : $lang->story->noRequirement;?></span>
|
||||
<?php if(common::canModify('product', $product) and common::hasPriv('story', 'create')):?>
|
||||
<?php echo html::a($this->createLink('story', 'create', "productID={$productID}&branch={$branch}&moduleID={$moduleID}&storyID=0&projectID=$projectID&bugID=0&planID=0&todoID=0&extra=&type=$storyType"), "<i class='icon icon-plus'></i> " . $lang->story->createCommon, '', "class='btn btn-info' data-app='$from'");?>
|
||||
<?php endif;?>
|
||||
</p>
|
||||
</div>
|
||||
<?php else:?>
|
||||
<form class="main-table table-story skip-iframe-modal" method="post" id='productStoryForm'>
|
||||
<div class="table-header fixed-right">
|
||||
<nav class="btn-toolbar pull-right"></nav>
|
||||
</div>
|
||||
<?php
|
||||
$datatableId = $this->moduleName . ucfirst($this->methodName);
|
||||
$useDatatable = (isset($config->datatable->$datatableId->mode) and $config->datatable->$datatableId->mode == 'datatable');
|
||||
$vars = "productID=$productID&branch=$branch&browseType=$browseType¶m=$param&storyType=$storyType&orderBy=%s&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}";
|
||||
if($from == 'project') $vars = "projectID=$projectID&productID=$productID&branch=$branch&browseType=$browseType¶m=$param&storyType=$storyType&orderBy=%s&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}";
|
||||
|
||||
if($useDatatable) $this->app->getModuleRoot() . '/common/view/datatable.html.php';
|
||||
$setting = $this->datatable->getSetting('product');
|
||||
$widths = $this->datatable->setFixedFieldWidth($setting);
|
||||
$columns = 0;
|
||||
|
||||
$canBeChanged = common::canModify('product', $product);
|
||||
$canBatchEdit = ($canBeChanged and common::hasPriv('story', 'batchEdit'));
|
||||
$canBatchClose = (common::hasPriv('story', 'batchClose') and strtolower($browseType) != 'closedbyme' and strtolower($browseType) != 'closedstory');
|
||||
$canBatchReview = ($canBeChanged and common::hasPriv('story', 'batchReview'));
|
||||
$canBatchChangeStage = ($canBeChanged and common::hasPriv('story', 'batchChangeStage'));
|
||||
$canBatchChangeBranch = ($canBeChanged and common::hasPriv('story', 'batchChangeBranch'));
|
||||
$canBatchChangeModule = ($canBeChanged and common::hasPriv('story', 'batchChangeModule'));
|
||||
$canBatchChangePlan = ($canBeChanged and common::hasPriv('story', 'batchChangePlan'));
|
||||
$canBatchAssignTo = ($canBeChanged and common::hasPriv('story', 'batchAssignTo'));
|
||||
$canBatchUnlink = ($canBeChanged and $this->app->tab == 'project' and common::hasPriv('projectstory', 'batchUnlinkStory'));
|
||||
$canBatchImportToLib = ($canBeChanged and $this->app->tab == 'project' and isset($this->config->maxVersion) and common::hasPriv('story', 'batchImportToLib'));
|
||||
|
||||
$canBatchAction = ($canBatchEdit or $canBatchClose or $canBatchReview or $canBatchChangeStage or $canBatchChangeModule or $canBatchChangePlan or $canBatchAssignTo or $canBatchUnlink or $canBatchImportToLib);
|
||||
?>
|
||||
<?php if(!$useDatatable) echo '<div class="table-responsive">';?>
|
||||
<table class='table has-sort-head<?php if($useDatatable) echo ' datatable';?>' id='storyList' data-fixed-left-width='<?php echo $widths['leftWidth']?>' data-fixed-right-width='<?php echo $widths['rightWidth']?>'>
|
||||
<thead>
|
||||
<tr>
|
||||
<?php if($this->app->getViewType() == 'xhtml'):?>
|
||||
<?php
|
||||
foreach($setting as $key => $value)
|
||||
{
|
||||
if($value->id == 'title' || $value->id == 'id' || $value->id == 'pri' || $value->id == 'status')
|
||||
{
|
||||
if($storyType == 'requirement' and (in_array($value->id, array('plan', 'stage')))) $value->show = false;
|
||||
|
||||
if($value->show)
|
||||
{
|
||||
$this->datatable->printHead($value, $orderBy, $vars, $canBatchAction);
|
||||
$columns ++;
|
||||
}
|
||||
}
|
||||
}?>
|
||||
<?php else:?>
|
||||
<?php
|
||||
foreach($setting as $key => $value)
|
||||
{
|
||||
if($storyType == 'requirement' and (in_array($value->id, array('plan', 'stage')))) $value->show = false;
|
||||
|
||||
if($value->show)
|
||||
{
|
||||
$this->datatable->printHead($value, $orderBy, $vars, $canBatchAction);
|
||||
$columns ++;
|
||||
}
|
||||
}
|
||||
?>
|
||||
<?php endif;?>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach($stories as $story):?>
|
||||
<tr data-id='<?php echo $story->id?>' data-estimate='<?php echo $story->estimate?>' data-cases='<?php echo zget($storyCases, $story->id, 0);?>'>
|
||||
<?php $story->from = $from;?>
|
||||
<?php if($this->app->getViewType() == 'xhtml'):?>
|
||||
<?php
|
||||
foreach($setting as $key => $value)
|
||||
{
|
||||
if($value->id == 'title' || $value->id == 'id' || $value->id == 'pri' || $value->id == 'status')
|
||||
{
|
||||
$this->story->printCell($value, $story, $users, $branchOption, $storyStages, $modulePairs, $storyTasks, $storyBugs, $storyCases, $useDatatable ? 'datatable' : 'table');
|
||||
}
|
||||
}?>
|
||||
<?php else:?>
|
||||
<?php foreach($setting as $key => $value) $this->story->printCell($value, $story, $users, $branchOption, $storyStages, $modulePairs, $storyTasks, $storyBugs, $storyCases, $useDatatable ? 'datatable' : 'table');?>
|
||||
<?php endif;?>
|
||||
</tr>
|
||||
<?php if(!empty($story->children)):?>
|
||||
<?php $i = 0;?>
|
||||
<?php foreach($story->children as $key => $child):?>
|
||||
<?php $child->from = $from;?>
|
||||
<?php $class = $i == 0 ? ' table-child-top' : '';?>
|
||||
<?php $class .= ($i + 1 == count($story->children)) ? ' table-child-bottom' : '';?>
|
||||
<tr class='table-children<?php echo $class;?> parent-<?php echo $story->id;?>' data-id='<?php echo $child->id?>' data-status='<?php echo $child->status?>' data-estimate='<?php echo $child->estimate?>'>
|
||||
<?php if($this->app->getViewType() == 'xhtml'):?>
|
||||
<?php
|
||||
foreach($setting as $key => $value)
|
||||
{
|
||||
if($value->id == 'title' || $value->id == 'id' || $value->id == 'pri' || $value->id == 'status')
|
||||
{
|
||||
$this->story->printCell($value, $child, $users, $branchOption, $storyStages, $modulePairs, $storyTasks, $storyBugs, $storyCases, $useDatatable ? 'datatable' : 'table', $storyType);
|
||||
}
|
||||
}?>
|
||||
<?php else:?>
|
||||
<?php foreach($setting as $key => $value) $this->story->printCell($value, $child, $users, $branchOption, $storyStages, $modulePairs, $storyTasks, $storyBugs, $storyCases, $useDatatable ? 'datatable' : 'table', $storyType);?>
|
||||
<?php endif;?>
|
||||
</tr>
|
||||
<?php $i ++;?>
|
||||
<?php endforeach;?>
|
||||
<?php endif;?>
|
||||
<?php endforeach;?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php if(!$useDatatable) echo '</div>';?>
|
||||
<div class="table-footer">
|
||||
<?php if($canBatchAction):?>
|
||||
<div class="checkbox-primary check-all"><label><?php echo $lang->selectAll?></label></div>
|
||||
<?php endif;?>
|
||||
<div class="table-actions btn-toolbar">
|
||||
<div class='btn-group dropup'>
|
||||
<?php
|
||||
$disabled = $canBatchEdit ? '' : "disabled='disabled'";
|
||||
$actionLink = $this->createLink('story', 'batchEdit', "productID=$productID&projectID=$projectID&branch=$branch&storyType=$storyType");
|
||||
?>
|
||||
<?php echo html::commonButton($lang->edit, "data-form-action='$actionLink' $disabled");?>
|
||||
<button type='button' class='btn dropdown-toggle' data-toggle='dropdown'><span class='caret'></span></button>
|
||||
<ul class='dropdown-menu'>
|
||||
<?php
|
||||
$class = $canBatchClose ? '' : "class='disabled'";
|
||||
$actionLink = $this->createLink('story', 'batchClose', "productID=$productID&projectID=0&storyType=$storyType");
|
||||
$misc = $canBatchClose ? "onclick=\"setFormAction('$actionLink', '', '#productStoryForm')\"" : '';
|
||||
echo "<li $class>" . html::a('#', $lang->close, '', $misc) . "</li>";
|
||||
|
||||
$class = $canBatchUnlink ? '' : "class='disabled'";
|
||||
echo "<li $class>" . html::a('#', $lang->story->unlink, '', "id='batchUnlinkStory'") . "</li>";
|
||||
|
||||
if($canBatchReview)
|
||||
{
|
||||
echo "<li class='dropdown-submenu'>";
|
||||
echo html::a('javascript:;', $lang->story->review, '', "id='reviewItem'");
|
||||
echo "<ul class='dropdown-menu'>";
|
||||
unset($lang->story->reviewResultList['']);
|
||||
unset($lang->story->reviewResultList['revert']);
|
||||
foreach($lang->story->reviewResultList as $key => $result)
|
||||
{
|
||||
$actionLink = $this->createLink('story', 'batchReview', "result=$key");
|
||||
if($key == 'reject')
|
||||
{
|
||||
echo "<li class='dropdown-submenu'>";
|
||||
echo html::a('#', $result, '', "id='rejectItem'");
|
||||
echo "<ul class='dropdown-menu'>";
|
||||
unset($lang->story->reasonList['']);
|
||||
unset($lang->story->reasonList['subdivided']);
|
||||
unset($lang->story->reasonList['duplicate']);
|
||||
|
||||
foreach($lang->story->reasonList as $key => $reason)
|
||||
{
|
||||
$actionLink = $this->createLink('story', 'batchReview', "result=reject&reason=$key");
|
||||
echo "<li>";
|
||||
echo html::a('#', $reason, '', "onclick=\"setFormAction('$actionLink', 'hiddenwin', '#productStoryForm')\"");
|
||||
echo "</li>";
|
||||
}
|
||||
echo '</ul></li>';
|
||||
}
|
||||
else
|
||||
{
|
||||
echo '<li>' . html::a('#', $result, '', "onclick=\"setFormAction('$actionLink', 'hiddenwin', '#productStoryForm')\"") . '</li>';
|
||||
}
|
||||
}
|
||||
echo '</ul></li>';
|
||||
}
|
||||
else
|
||||
{
|
||||
$class= "class='disabled'";
|
||||
echo "<li $class>" . html::a('javascript:;', $lang->story->review, '', $class) . '</li>';
|
||||
}
|
||||
|
||||
if($canBatchChangeBranch and $this->session->currentProductType and $this->session->currentProductType != 'normal' and $productID)
|
||||
{
|
||||
$withSearch = count($branchTagOption) > 8;
|
||||
echo "<li class='dropdown-submenu'>";
|
||||
echo html::a('javascript:;', $lang->product->branchName[$this->session->currentProductType], '', "id='branchItem'");
|
||||
echo "<div class='dropdown-menu" . ($withSearch ? ' with-search':'') . "'>";
|
||||
echo "<ul class='dropdown-list'>";
|
||||
foreach($branchTagOption as $id => $branchName)
|
||||
{
|
||||
$actionLink = $this->createLink('story', 'batchChangeBranch', "branchID=$id");
|
||||
echo "<li class='option' data-key='$id'>" . html::a('#', $branchName, '', "onclick=\"setFormAction('$actionLink', 'hiddenwin', '#productStoryForm')\"") . "</li>";
|
||||
}
|
||||
echo '</ul>';
|
||||
if($withSearch) echo "<div class='menu-search'><div class='input-group input-group-sm'><input type='text' class='form-control' placeholder=''><span class='input-group-addon'><i class='icon-search'></i></span></div></div>";
|
||||
echo '</div></li>';
|
||||
}
|
||||
|
||||
if($storyType == 'story')
|
||||
{
|
||||
if($canBatchChangeStage)
|
||||
{
|
||||
echo "<li class='dropdown-submenu'>";
|
||||
echo html::a('javascript:;', $lang->story->stageAB, '', "id='stageItem'");
|
||||
echo "<ul class='dropdown-menu'>";
|
||||
foreach($lang->story->stageList as $key => $stage)
|
||||
{
|
||||
if(empty($key)) continue;
|
||||
if(strpos('tested|verified|released|closed', $key) === false) continue;
|
||||
$actionLink = $this->createLink('story', 'batchChangeStage', "stage=$key");
|
||||
echo "<li>" . html::a('#', $stage, '', "onclick=\"setFormAction('$actionLink', 'hiddenwin', '#productStoryForm')\"") . "</li>";
|
||||
}
|
||||
echo '</ul></li>';
|
||||
}
|
||||
else
|
||||
{
|
||||
$class= "class='disabled'";
|
||||
echo "<li $class>" . html::a('javascript:;', $lang->story->stageAB, '', $class) . '</li>';
|
||||
}
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<?php $isShowModuleBTN = ($this->app->tab == 'project' and $browseType != 'bybranch') ? false : true;?>
|
||||
<?php if($canBatchChangeModule and $productID and $branchID !== 'all' and $isShowModuleBTN):?>
|
||||
<div class="btn-group dropup">
|
||||
<button data-toggle="dropdown" type="button" class="btn"><?php echo $lang->story->moduleAB;?> <span class="caret"></span></button>
|
||||
<?php $withSearch = count($modules) > 8;?>
|
||||
<div class="dropdown-menu search-list<?php if($withSearch) echo ' search-box-sink';?>" data-ride="searchList">
|
||||
<?php if($withSearch):?>
|
||||
<div class="input-control search-box has-icon-left has-icon-right search-example">
|
||||
<input id="moduleSearchBox" type="search" autocomplete="off" class="form-control search-input">
|
||||
<label for="moduleSearchBox" class="input-control-icon-left search-icon"><i class="icon icon-search"></i></label>
|
||||
<a class="input-control-icon-right search-clear-btn"><i class="icon icon-close icon-sm"></i></a>
|
||||
</div>
|
||||
<?php $modulesPinYin = common::convert2Pinyin($modules);
|
||||
?>
|
||||
<?php endif;?>
|
||||
<div class="list-group">
|
||||
<?php
|
||||
foreach($modules as $moduleId => $module)
|
||||
{
|
||||
$searchKey = $withSearch ? ('data-key="' . zget($modulesPinYin, $module, '') . '"') : '';
|
||||
$actionLink = $this->createLink('story', 'batchChangeModule', "moduleID=$moduleId");
|
||||
echo html::a('#', empty($module) ? '/' : $module, '', "$searchKey onclick=\"setFormAction('$actionLink', 'hiddenwin', '#productStoryForm')\"");
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif;?>
|
||||
<?php if($canBatchChangePlan and $storyType == 'story'):?>
|
||||
<div class="btn-group dropup">
|
||||
<button data-toggle="dropdown" type="button" class="btn"><?php echo $lang->story->planAB;?> <span class="caret"></span></button>
|
||||
<?php
|
||||
unset($plans['']);
|
||||
$plans = array(0 => $lang->null) + $plans;
|
||||
$withSearch = count($plans) > 8;
|
||||
?>
|
||||
<div class="dropdown-menu search-list<?php if($withSearch) echo ' search-box-sink';?>" data-ride="searchList">
|
||||
<?php if($withSearch):?>
|
||||
<div class="input-control search-box has-icon-left has-icon-right search-example">
|
||||
<input id="planSearchBox" type="search" autocomplete="off" class="form-control search-input">
|
||||
<label for="planSearchBox" class="input-control-icon-left search-icon"><i class="icon icon-search"></i></label>
|
||||
<a class="input-control-icon-right search-clear-btn"><i class="icon icon-close icon-sm"></i></a>
|
||||
</div>
|
||||
<?php $plansPinYin = common::convert2Pinyin($plans);?>
|
||||
<?php endif;?>
|
||||
<div class="list-group">
|
||||
<?php
|
||||
foreach($plans as $planID => $plan)
|
||||
{
|
||||
$position = stripos($plan, '/');
|
||||
$planLabel = $position === false ? $plan : ('<span class="label label-outline label-badge">' . substr($plan, 0, $position) . '</span>' . substr($plan, $position + 1));
|
||||
$searchKey = $withSearch ? ('data-key="' . zget($plansPinYin, $plan, '') . '"') : '';
|
||||
$actionLink = $this->createLink('story', 'batchChangePlan', "planID=$planID");
|
||||
echo html::a('#', $planLabel, '', "$searchKey title='{$plan}' onclick=\"setFormAction('$actionLink', 'hiddenwin', '#productStoryForm')\" onmouseover=\"setBadgeStyle(this, true);\" onmouseout=\"setBadgeStyle(this, false)\"");
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif;?>
|
||||
|
||||
<?php if($canBatchAssignTo):?>
|
||||
<div class="btn-group dropup">
|
||||
<button data-toggle="dropdown" type="button" class="btn"><?php echo $lang->story->assignedTo;?> <span class="caret"></span></button>
|
||||
<?php
|
||||
$withSearch = count($users) > 10;
|
||||
$actionLink = $this->createLink('story', 'batchAssignTo', "productID=$productID");
|
||||
echo html::select('assignedTo', $users, '', 'class="hidden"');
|
||||
?>
|
||||
<div class="dropdown-menu search-list<?php if($withSearch) echo ' search-box-sink';?>" data-ride="searchList">
|
||||
<?php if($withSearch):?>
|
||||
<?php $usersPinYin = common::convert2Pinyin($users);?>
|
||||
<div class="input-control search-box has-icon-left has-icon-right search-example">
|
||||
<input id="userSearchBox" type="search" autocomplete="off" class="form-control search-input">
|
||||
<label for="userSearchBox" class="input-control-icon-left search-icon"><i class="icon icon-search"></i></label>
|
||||
<a class="input-control-icon-right search-clear-btn"><i class="icon icon-close icon-sm"></i></a>
|
||||
</div>
|
||||
<?php endif;?>
|
||||
<div class="list-group">
|
||||
<?php foreach ($users as $key => $value):?>
|
||||
<?php
|
||||
if(empty($key) or $key == 'closed') continue;
|
||||
$searchKey = $withSearch ? ('data-key="' . zget($usersPinYin, $value, '') . " @$key\"") : "data-key='@$key'";
|
||||
echo html::a("javascript:$(\"#assignedTo\").val(\"$key\");setFormAction(\"$actionLink\", \"hiddenwin\", \"#productStoryForm\")", $value, '', $searchKey);
|
||||
?>
|
||||
<?php endforeach;?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif;?>
|
||||
|
||||
<?php if($canBatchImportToLib):?>
|
||||
<?php echo html::a('#batchImportToLib', $lang->story->importToLib, '', 'class="btn" data-toggle="modal" id="importToLib"');?>
|
||||
<?php endif;?>
|
||||
</div>
|
||||
<div class="table-statistic"><?php echo $summary;?></div>
|
||||
<?php $pager->show('right', 'pagerjs');?>
|
||||
</div>
|
||||
</form>
|
||||
<?php endif;?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal fade" id="linkStoryByPlan">
|
||||
<div class="modal-dialog mw-500px">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="icon icon-close"></i></button>
|
||||
<h4 class="modal-title"><?php echo $lang->execution->linkStoryByPlan;?></h4><?php echo '(' . $lang->project->linkStoryByPlanTips . ')';?>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class='input-group'>
|
||||
<?php echo html::select('plan', zget($productPlans, $productID, ''), '', "class='form-control chosen' id='plan'");?>
|
||||
<span class='input-group-btn'><?php echo html::commonButton($lang->execution->linkStory, "id='toTaskButton'", 'btn btn-primary');?></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="batchImportToLib">
|
||||
<div class="modal-dialog mw-500px">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="icon icon-close"></i></button>
|
||||
<h4 class="modal-title"><?php echo $lang->story->importToLib;?></h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form method='post' class='form-ajax' action='<?php echo $this->createLink('story', 'batchImportToLib');?>'>
|
||||
<table class='table table-form'>
|
||||
<tr>
|
||||
<th><?php echo $lang->story->lib;?></th>
|
||||
<td>
|
||||
<?php echo html::select('lib', $libs, '', "class='form-control chosen' required");?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php if(!common::hasPriv('assetlib', 'approveStory') and !common::hasPriv('assetlib', 'batchApproveStory')):?>
|
||||
<tr>
|
||||
<th><?php echo $lang->story->approver;?></th>
|
||||
<td>
|
||||
<?php echo html::select('assignedTo', $approvers, '', "class='form-control chosen'");?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif;?>
|
||||
<tr>
|
||||
<td colspan='2' class='text-center'>
|
||||
<?php echo html::hidden('storyIdList', '');?>
|
||||
<?php echo html::submitButton($lang->import, '', 'btn btn-primary');?>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="batchUnlinkStoryTip">
|
||||
<div class="modal-dialog mw-700px">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="icon icon-close"></i></button>
|
||||
<h4 class="modal-title"><strong><?php echo $lang->projectstory->batchUnlinkTip;?></strong></h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<table class='table'>
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php echo $lang->story->title;?></th>
|
||||
<th class='w-200px'><?php echo $lang->story->link . $lang->execution->common;?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td colspan='2' class='text-center'>
|
||||
<?php echo html::commonButton($lang->projectstory->confirm, 'data-dismiss="modal" id="confirmBtn"', 'btn btn-primary');?>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
var moduleID = <?php echo $moduleID?>;
|
||||
var branchID = $.cookie('storyBranch');
|
||||
$('#module<?php echo $moduleID;?>').closest('li').addClass('active');
|
||||
$('#branch' + branchID).closest('li').addClass('active');
|
||||
|
||||
$(function()
|
||||
{
|
||||
// Update table summary text.
|
||||
<?php $storyCommon = $storyType == 'requirement' ? $lang->URCommon : $lang->SRCommon;?>
|
||||
var checkedSummary = '<?php echo str_replace('%storyCommon%', $storyCommon, $lang->product->checkedSummary)?>';
|
||||
$('#productStoryForm').table(
|
||||
{
|
||||
statisticCreator: function(table)
|
||||
{
|
||||
var $checkedRows = table.getTable().find(table.isDataTable ? '.datatable-row-left.checked' : 'tbody>tr.checked');
|
||||
var $originTable = table.isDataTable ? table.$.find('.datatable-origin') : null;
|
||||
var checkedTotal = $checkedRows.length;
|
||||
if(!checkedTotal) return;
|
||||
|
||||
var checkedEstimate = 0;
|
||||
var checkedCase = 0;
|
||||
$checkedRows.each(function()
|
||||
{
|
||||
var $row = $(this);
|
||||
if ($originTable)
|
||||
{
|
||||
$row = $originTable.find('tbody>tr[data-id="' + $row.data('id') + '"]');
|
||||
}
|
||||
var data = $row.data();
|
||||
checkedEstimate += data.estimate;
|
||||
if(data.cases > 0) checkedCase += 1;
|
||||
});
|
||||
var rate = Math.round(checkedCase / checkedTotal * 10000 / 100) + '' + '%';
|
||||
return checkedSummary.replace('%total%', checkedTotal)
|
||||
.replace('%estimate%', checkedEstimate.toFixed(1))
|
||||
.replace('%rate%', rate);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Set the color of the badge to white.
|
||||
*
|
||||
* @param object obj
|
||||
* @param bool isShow
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function setBadgeStyle(obj, isShow)
|
||||
{
|
||||
var $label = $(obj);
|
||||
if(isShow == true)
|
||||
{
|
||||
$label.find('.label-badge').css({"color":"#fff", "border-color":"#fff"});
|
||||
}
|
||||
else
|
||||
{
|
||||
$label.find('.label-badge').css({"color":"#838a9d", "border-color":"#838a9d"});
|
||||
}
|
||||
}
|
||||
|
||||
function handleLinkButtonClick()
|
||||
{
|
||||
var xxcUrl = "xxc:openInApp/zentao-integrated/" + encodeURIComponent(window.location.href.replace(/.display=card/, '').replace(/\.xhtml/, '.html'));
|
||||
window.open(xxcUrl);
|
||||
}
|
||||
</script>
|
||||
<?php include $this->app->getModuleRoot() . '/common/view/footer.html.php';?>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?php if($this->app->rawModule == 'projectstory'):?>
|
||||
<script>
|
||||
$('td.c-actions .icon-projectstory-unlinkStory').parent().remove();
|
||||
$('td.c-actions .icon-testcase-create').parent().remove();
|
||||
</script>
|
||||
<?php endif;?>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?php
|
||||
unset($lang->projectstory->featureBar['story']['changed']);
|
||||
unset($lang->projectstory->featureBar['story']['linkedExecution']);
|
||||
unset($lang->projectstory->featureBar['story']['unlinkedExecution']);
|
||||
@@ -0,0 +1,2 @@
|
||||
<?php
|
||||
$lang->story->children = '子目标';
|
||||
@@ -780,8 +780,22 @@ class baseControl
|
||||
* 设置公共扩展。
|
||||
* set common extension.
|
||||
*/
|
||||
$commonActionExtFile = $actionExtPath['common'] . strtolower($methodName) . '.php';
|
||||
$file2Included = file_exists($commonActionExtFile) ? $commonActionExtFile : $moduleControlFile;
|
||||
$file2Included = $moduleControlFile;
|
||||
|
||||
$commonActionExtFile = $actionExtPath['custom'] . strtolower($methodName) . '.php';
|
||||
if(file_exists($commonActionExtFile)) $file2Included = $commonActionExtFile;
|
||||
|
||||
if(!empty($actionExtPath['vision']))
|
||||
{
|
||||
$commonActionExtFile = $actionExtPath['vision'] . strtolower($methodName) . '.php';
|
||||
if(file_exists($commonActionExtFile)) $file2Included = $commonActionExtFile;
|
||||
}
|
||||
|
||||
if(!empty($actionExtPath['common']))
|
||||
{
|
||||
$commonActionExtFile = $actionExtPath['common'] . strtolower($methodName) . '.php';
|
||||
if(file_exists($commonActionExtFile)) $file2Included = $commonActionExtFile;
|
||||
}
|
||||
|
||||
if(!empty($actionExtPath['site']))
|
||||
{
|
||||
|
||||
@@ -139,6 +139,9 @@ class router extends baseRouter
|
||||
*/
|
||||
public function setCommonLang()
|
||||
{
|
||||
if(defined('COMMONLANGSETTED')) return true;
|
||||
define('COMMONLANGSETTED', true);
|
||||
|
||||
if(!defined('ITERATION_KEY')) define('ITERATION_KEY', 0);
|
||||
if(!defined('SPRINT_KEY')) define('SPRINT_KEY', 1);
|
||||
if(!defined('PRODUCT_KEY')) define('PRODUCT_KEY', 0);
|
||||
|
||||
@@ -901,6 +901,7 @@ class projectModel extends model
|
||||
$lib->main = '1';
|
||||
$lib->acl = $project->acl != 'program' ? $project->acl : 'custom';
|
||||
$lib->users = ',' . implode(',', array_filter($authorizedUsers)) . ',';
|
||||
$lib->vision = zget($project, 'vision', 'common');
|
||||
$this->dao->insert(TABLE_DOCLIB)->data($lib)->exec();
|
||||
|
||||
$this->updateProducts($projectID);
|
||||
@@ -918,6 +919,7 @@ class projectModel extends model
|
||||
$product->createdDate = helper::now();
|
||||
$product->status = 'normal';
|
||||
$product->createdVersion = $this->config->version;
|
||||
$product->vision = zget($project, 'vision', 'common');
|
||||
|
||||
$this->dao->insert(TABLE_PRODUCT)->data($product)->exec();
|
||||
$productID = $this->dao->lastInsertId();
|
||||
|
||||
@@ -398,7 +398,7 @@ class story extends control
|
||||
if($storyID)
|
||||
{
|
||||
$story = $this->story->getById($storyID);
|
||||
if($story->status != 'active' or $story->stage != 'wait' or $story->parent > 0) die(js::alert($this->lang->story->errorNotSubdivide) . js::locate('back'));
|
||||
if(($story->status != 'active' or $story->stage != 'wait' or $story->parent > 0) and $this->config->vision != 'lite') die(js::alert($this->lang->story->errorNotSubdivide) . js::locate('back'));
|
||||
}
|
||||
|
||||
if(!empty($_POST))
|
||||
|
||||
@@ -3515,6 +3515,7 @@ class storyModel extends model
|
||||
if($action == 'createcase') return $story->type != 'requirement';
|
||||
if($action == 'batchcreate' and $story->parent > 0) return false;
|
||||
if($action == 'batchcreate' and $story->type == 'requirement' and $story->status != 'closed') return $story->status != 'draft';
|
||||
if($action == 'batchcreate' and $config->vision == 'lite' and ($story->status == 'active' and ($story->stage == 'wait' or $story->stage == 'projected'))) return true;
|
||||
if($action == 'batchcreate' and ($story->status != 'active' or $story->stage != 'wait' or !empty($story->plan))) return false;
|
||||
|
||||
return true;
|
||||
@@ -3943,7 +3944,7 @@ class storyModel extends model
|
||||
common::printIcon('story', 'close', $vars, $story, 'list', '', '', 'iframe', true);
|
||||
common::printIcon('story', 'edit', $vars . "&from=$story->from", $story, 'list', '', '', '', false, "data-group=$story->from");
|
||||
if($story->type != 'requirement') common::printIcon('story', 'createCase', "productID=$story->product&branch=$story->branch&module=0&from=¶m=0&$vars", $story, 'list', 'sitemap', '', '', false, "data-app='qa'");
|
||||
if($this->app->rawModule != 'projectstory') common::printIcon('story', 'batchCreate', "productID=$story->product&branch=$story->branch&module=$story->module&storyID=$story->id", $story, 'list', 'split', '', '', '', '', $this->lang->story->subdivide);
|
||||
if($this->app->rawModule != 'projectstory' OR $this->config->vision == 'lite') common::printIcon('story', 'batchCreate', "productID=$story->product&branch=$story->branch&module=$story->module&storyID=$story->id", $story, 'list', 'split', '', '', '', '', $this->lang->story->subdivide);
|
||||
if($this->app->rawModule == 'projectstory') common::printIcon('projectstory', 'unlinkStory', "projectID={$this->session->project}&storyID=$story->id", '', 'list', 'unlink', 'hiddenwin');
|
||||
}
|
||||
else
|
||||
|
||||
@@ -405,18 +405,16 @@ class treeModel extends model
|
||||
|
||||
$manage = $userFunc[1] == 'createManageLink' ? true : false;
|
||||
$product = $this->loadModel('product')->getById($rootID);
|
||||
|
||||
$onlyGetLinked = ($projectID and $this->config->vision != 'lite');
|
||||
if(strpos('story|bug|case', $type) !== false and $branch === 'all' and empty($projectID))
|
||||
{
|
||||
if($product->type != 'normal') $branches = array(BRANCH_MAIN => $this->lang->branch->main) + $this->loadModel('branch')->getPairs($rootID, 'noempty');
|
||||
}
|
||||
elseif(($type == 'story' and $this->app->rawModule == 'projectstory') or ($type == 'case' and $this->app->tab == 'project'))
|
||||
{
|
||||
if($product->type != 'normal' and $projectID)
|
||||
{
|
||||
$branches += $this->branch->getPairs($product->id, 'noempty', $projectID);
|
||||
}
|
||||
|
||||
$executionModules = $this->getTaskTreeModules($projectID, true, $type);
|
||||
if($product->type != 'normal' and $projectID) $branches += $this->branch->getPairs($product->id, 'noempty', $projectID);
|
||||
if($onlyGetLinked) $executionModules = $this->getTaskTreeModules($projectID, true, $type);
|
||||
}
|
||||
|
||||
/* Add for task #1945. check the module has case or no. */
|
||||
@@ -427,7 +425,7 @@ class treeModel extends model
|
||||
$stmt = $this->dbh->query($this->buildMenuQuery($rootID, $type, $startModule, $branch));
|
||||
while($module = $stmt->fetch())
|
||||
{
|
||||
if(!$projectID)
|
||||
if(!$onlyGetLinked)
|
||||
{
|
||||
$this->buildTree($treeMenu, $module, $type, $userFunc, $extra, $branch);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user