Merge branch 'master' of github.com:easysoft/zentaopms
This commit is contained in:
@@ -130,6 +130,7 @@ define('TABLE_TESTRESULT', '`' . $config->db->prefix . 'testresult`');
|
||||
define('TABLE_USERTPL', '`' . $config->db->prefix . 'usertpl`');
|
||||
|
||||
define('TABLE_PRODUCT', '`' . $config->db->prefix . 'product`');
|
||||
define('TABLE_BRANCH', '`' . $config->db->prefix . 'branch`');
|
||||
define('TABLE_STORY', '`' . $config->db->prefix . 'story`');
|
||||
define('TABLE_STORYSPEC', '`' . $config->db->prefix . 'storyspec`');
|
||||
define('TABLE_PRODUCTPLAN', '`' . $config->db->prefix . 'productplan`');
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
ALTER TABLE `zt_action` CHANGE `extra` `extra` text COLLATE 'utf8_general_ci' NOT NULL AFTER `comment`;
|
||||
ALTER TABLE `zt_release` ADD `leftBugs` text COLLATE 'utf8_general_ci' NOT NULL AFTER `bugs`;
|
||||
ALTER TABLE `zt_release` ADD `status` varchar(20) COLLATE 'utf8_general_ci' NOT NULL DEFAULT 'normal' AFTER `desc`;
|
||||
ALTER TABLE `zt_product` ADD `type` varchar(30) COLLATE 'utf8_general_ci' NOT NULL DEFAULT 'normal' AFTER `code`;
|
||||
|
||||
ALTER TABLE `zt_projectproduct` ADD `branch` mediumint(8) unsigned NOT NULL;
|
||||
ALTER TABLE `zt_productplan` ADD `branch` mediumint(8) unsigned NOT NULL AFTER `product`;
|
||||
ALTER TABLE `zt_build` ADD `branch` mediumint(8) unsigned NOT NULL AFTER `product`;
|
||||
ALTER TABLE `zt_release` ADD `branch` mediumint(8) unsigned NOT NULL AFTER `product`;
|
||||
ALTER TABLE `zt_bug` ADD `branch` mediumint(8) unsigned NOT NULL AFTER `product`;
|
||||
ALTER TABLE `zt_case` ADD `branch` mediumint(8) unsigned NOT NULL AFTER `product`;
|
||||
ALTER TABLE `zt_module` ADD `branch` varchar(50) COLLATE 'utf8_general_ci' unsigned NOT NULL AFTER `root`;
|
||||
ALTER TABLE `zt_story` ADD `branch` varchar(50) COLLATE 'utf8_general_ci' NOT NULL AFTER `product`;
|
||||
|
||||
CREATE TABLE `zt_branch` (
|
||||
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
`product` mediumint unsigned NOT NULL,
|
||||
`name` varchar(255) COLLATE 'utf8_general_ci' NOT NULL,
|
||||
`deleted` enum('0','1') COLLATE 'utf8_general_ci' NOT NULL DEFAULT '0'
|
||||
);
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
/**
|
||||
* The control file of branch of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2015 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
|
||||
* @license ZPL (http://zpl.pub/page/zplv11.html)
|
||||
* @author Yidong Wang <yidong@cnezsoft.com>
|
||||
* @package branch
|
||||
* @version $Id$
|
||||
* @link http://www.zentao.net
|
||||
*/
|
||||
class branch extends control
|
||||
{
|
||||
public function manage($productID)
|
||||
{
|
||||
if($_POST)
|
||||
{
|
||||
$this->branch->manage($productID);
|
||||
die(js::reload('parent'));
|
||||
}
|
||||
$this->view->title = $this->lang->branch->manage;
|
||||
$this->view->position[] = $this->lang->branch->manage;
|
||||
|
||||
$this->loadModel('product')->setMenu($this->product->getPairs('nocode'), $productID);
|
||||
|
||||
$this->view->product = $this->product->getById($productID);
|
||||
$this->view->branches = $this->branch->getPairs($productID, 'noempty');
|
||||
$this->display();
|
||||
}
|
||||
|
||||
public function ajaxGetDropMenu($productID, $module, $method, $extra)
|
||||
{
|
||||
$this->view->link = $this->loadModel('product')->getProductLink($module, $method, $extra, true);
|
||||
$this->view->productID = $productID;
|
||||
$this->view->module = $module;
|
||||
$this->view->method = $method;
|
||||
$this->view->extra = $extra;
|
||||
$this->view->branches = $this->branch->getPairs($productID);
|
||||
$this->display();
|
||||
}
|
||||
|
||||
public function ajaxGetMatchedItems($keywords, $module, $method, $extra, $objectID)
|
||||
{
|
||||
$this->view->link = $this->loadModel('product')->getProductLink($module, $method, $extra, true);
|
||||
$this->view->branches = $this->dao->select('*')->from(TABLE_BRANCH)->where('deleted')->eq(0)->andWhere('product')->eq($objectID)->andWhere('name')->like("%$keywords%")->orderBy('id desc')->fetchPairs('id', 'name');
|
||||
$this->view->productID = $objectID;
|
||||
$this->view->keywords = $keywords;
|
||||
$this->display();
|
||||
}
|
||||
|
||||
public function ajaxGetBranches($productID)
|
||||
{
|
||||
$product = $this->loadModel('product')->getById($productID);
|
||||
if($product->type == 'normal') die();
|
||||
|
||||
$branches = $this->branch->getPairs($productID);
|
||||
die(html::select('branch[]', $branches, '', "class='form-control'"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
<?php
|
||||
$lang->branch->manage = '分支管理';
|
||||
|
||||
$lang->branch->all = '所有';
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
/**
|
||||
* The model file of branch module of ZenTaoCMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2015 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
|
||||
* @license ZPL (http://zpl.pub/page/zplv11.html)
|
||||
* @author Yidong Wang <yidong@cnezsoft.com>
|
||||
* @package branch
|
||||
* @version $Id$
|
||||
* @link http://www.zentao.net
|
||||
*/
|
||||
class branchModel extends model
|
||||
{
|
||||
public function getPairs($productID, $params = '')
|
||||
{
|
||||
$branches = $this->dao->select('*')->from(TABLE_BRANCH)->where('product')->eq($productID)->andWhere('deleted')->eq(0)->orderBy('id_desc')->fetchPairs('id', 'name');
|
||||
if(strpos($params, 'noempty') === false) $branches = array('0' => $this->lang->branch->all) + $branches;
|
||||
return $branches;
|
||||
}
|
||||
|
||||
public function manage($productID)
|
||||
{
|
||||
$oldBranches = $this->getPairs($productID, 'noempty');
|
||||
$data = fixer::input('post')->get();
|
||||
if(isset($data->branch))
|
||||
{
|
||||
foreach($data->branch as $branchID => $branch)
|
||||
{
|
||||
if($oldBranches[$branchID] != $branch) $this->dao->update(TABLE_BRANCH)->set('name')->eq($branch)->where('id')->eq($branchID)->exec();
|
||||
}
|
||||
}
|
||||
foreach($data->newbranch as $branch)
|
||||
{
|
||||
if(empty($branch)) continue;
|
||||
$this->dao->insert(TABLE_BRANCH)->set('name')->eq($branch)->set('product')->eq($productID)->exec();
|
||||
}
|
||||
|
||||
return dao::isError();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php js::set('productID', $productID);?>
|
||||
<?php js::set('module', $module);?>
|
||||
<?php js::set('method', $method);?>
|
||||
<?php js::set('extra', $extra);?>
|
||||
<input type='text' class='form-control' id='search' value='' placeholder='<?php echo $this->app->loadLang('search')->search->common;?>'/>
|
||||
<div id='searchResult'>
|
||||
<div id='defaultMenu' class='search-list'>
|
||||
<ul>
|
||||
<?php
|
||||
foreach($branches as $branchID => $branch)
|
||||
{
|
||||
echo "<li>" . html::a(sprintf($link, $productID, $branchID), "<i class='icon-cube'></i> " . $branch, '', "class='text-important'"). "</li>";
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,11 @@
|
||||
<div class='search-list'>
|
||||
<ul>
|
||||
<?php if(!$branches) echo "<li class='no-result-tip'>" . sprintf($lang->product->noMatched, $keywords) . '</li>';?>
|
||||
<?php
|
||||
foreach($branches as $batchID => $branch)
|
||||
{
|
||||
echo "<li>" . html::a(sprintf($link, $productID, $branchID), "<i class='icon-cube'></i> " . $branch). "</li>";
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
/**
|
||||
* The manage view file of branch module of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2015 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
|
||||
* @license ZPL (http://zpl.pub/page/zplv11.html)
|
||||
* @author Yidong Wang <yidong@cnezsoft.com>
|
||||
* @package branch
|
||||
* @version $Id$
|
||||
* @link http://www.zentao.net
|
||||
*/
|
||||
?>
|
||||
<?php include '../../common/view/header.html.php';?>
|
||||
<div class="container mw-700px">
|
||||
<div id="titlebar">
|
||||
<div class="heading"><strong><?php echo $lang->branch->manage?></strong></div>
|
||||
</div>
|
||||
<form method='post' target='hiddenwin'>
|
||||
<table class="table table-form">
|
||||
<?php foreach($branches as $branchID => $branch):?>
|
||||
<tr>
|
||||
<td class='w-50px'></td>
|
||||
<td class="w-200px"><?php echo html::input("branch[$branchID]", $branch, "class='form-control'")?> </td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<?php endforeach;?>
|
||||
<?php for($i = 0; $i < 5; $i++):?>
|
||||
<tr>
|
||||
<td class='w-50px'></td>
|
||||
<td class="w-200px"><?php echo html::input("newbranch[$i]", '', "class='form-control'")?> </td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<?php endfor;?>
|
||||
<tr>
|
||||
<td class='w-50px'></td>
|
||||
<td class="w-200px"><?php echo html::submitButton()?> </td><td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
<?php include '../../common/view/footer.html.php';?>
|
||||
|
||||
+12
-7
@@ -216,7 +216,7 @@ class bug extends control
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function create($productID, $extras = '')
|
||||
public function create($productID, $branch = 0, $extras = '')
|
||||
{
|
||||
$this->view->users = $this->user->getPairs('nodeleted|devfirst|noclosed');
|
||||
if(empty($this->products)) $this->locate($this->createLink('product', 'create'));
|
||||
@@ -253,7 +253,9 @@ class bug extends control
|
||||
|
||||
/* Get product, then set menu. */
|
||||
$productID = $this->product->saveState($productID, $this->products);
|
||||
$this->bug->setMenu($this->products, $productID);
|
||||
$product = $this->product->getById($productID);
|
||||
$branches = $product->type == 'normal' ? array() : $this->loadModel('branch')->getPairs($productID);
|
||||
$this->bug->setMenu($this->products, $productID, $branch);
|
||||
|
||||
/* Init vars. */
|
||||
$moduleID = 0;
|
||||
@@ -314,7 +316,7 @@ class bug extends control
|
||||
else
|
||||
{
|
||||
$builds = $this->loadModel('build')->getProductBuildPairs($productID, 'noempty,release,noterminate,nodone');
|
||||
$stories = $this->story->getProductStoryPairs($productID);
|
||||
$stories = $this->story->getProductStoryPairs($productID, $branch);
|
||||
}
|
||||
|
||||
/* Set team members of the latest project as assignedTo list. */
|
||||
@@ -358,6 +360,9 @@ class bug extends control
|
||||
$this->view->keywords = $keywords;
|
||||
$this->view->severity = $severity;
|
||||
$this->view->type = $type;
|
||||
$this->view->product = $product;
|
||||
$this->view->branch = $branch;
|
||||
$this->view->branches = $branches;
|
||||
|
||||
$this->display();
|
||||
}
|
||||
@@ -371,7 +376,7 @@ class bug extends control
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function batchCreate($productID, $projectID = 0, $moduleID = 0)
|
||||
public function batchCreate($productID, $branch = 0, $projectID = 0, $moduleID = 0)
|
||||
{
|
||||
if(!empty($_POST))
|
||||
{
|
||||
@@ -393,7 +398,7 @@ class bug extends control
|
||||
else
|
||||
{
|
||||
$builds = $this->loadModel('build')->getProductBuildPairs($productID, 'noempty');
|
||||
$stories = $this->story->getProductStoryPairs($productID);
|
||||
$stories = $this->story->getProductStoryPairs($productID, $branch);
|
||||
}
|
||||
|
||||
if($this->session->bugImagesFile)
|
||||
@@ -557,11 +562,11 @@ class bug extends control
|
||||
$this->view->bug = $bug;
|
||||
$this->view->productID = $productID;
|
||||
$this->view->productName = $this->products[$productID];
|
||||
$this->view->plans = $this->loadModel('productplan')->getPairs($productID);
|
||||
$this->view->plans = $this->loadModel('productplan')->getPairs($productID, $bug->branch);
|
||||
$this->view->moduleOptionMenu = $this->tree->getOptionMenu($productID, $viewType = 'bug', $startModuleID = 0);
|
||||
$this->view->currentModuleID = $currentModuleID;
|
||||
$this->view->projects = $this->product->getProjectPairs($bug->product);
|
||||
$this->view->stories = $bug->project ? $this->story->getProjectStoryPairs($bug->project) : $this->story->getProductStoryPairs($bug->product);
|
||||
$this->view->stories = $bug->project ? $this->story->getProjectStoryPairs($bug->project) : $this->story->getProductStoryPairs($bug->product, $bug->branch);
|
||||
$this->view->tasks = $this->task->getProjectTaskPairs($bug->project);
|
||||
$this->view->users = $this->user->getPairs('nodeleted', "$bug->assignedTo,$bug->resolvedBy,$bug->closedBy,$bug->openedBy");
|
||||
$this->view->openedBuilds = $openedBuilds;
|
||||
|
||||
@@ -141,7 +141,7 @@ function loadProductModules(productID)
|
||||
*/
|
||||
function loadProductStories(productID)
|
||||
{
|
||||
link = createLink('story', 'ajaxGetProductStories', 'productID=' + productID + '&moduleId=0&storyID=' + oldStoryID);
|
||||
link = createLink('story', 'ajaxGetProductStories', 'productID=' + productID + '&branch=0&moduleId=0&storyID=' + oldStoryID);
|
||||
$('#storyIdBox').load(link, function(){$('#story').chosen(defaultChosenOptions);});
|
||||
}
|
||||
|
||||
@@ -281,7 +281,9 @@ function loadProjectBuilds(projectID)
|
||||
*/
|
||||
function setStories(moduleID, productID)
|
||||
{
|
||||
link = createLink('story', 'ajaxGetProductStories', 'productID=' + productID + '&moduleID=' + moduleID);
|
||||
var branch = $('#branch').val();
|
||||
if(typeof(branch) == 'undefined') branch = 0;
|
||||
link = createLink('story', 'ajaxGetProductStories', 'productID=' + productID + '&branch=' + branch + '&moduleID=' + moduleID);
|
||||
$.get(link, function(stories)
|
||||
{
|
||||
if(!stories) stories = '<select id="story" name="story" class="form-control"></select>';
|
||||
|
||||
@@ -280,6 +280,7 @@ class build extends control
|
||||
$this->loadModel('product');
|
||||
|
||||
/* Build search form. */
|
||||
$product = $this->product->getByID($build->product);
|
||||
$queryID = ($browseType == 'bySearch') ? (int)$param : 0;
|
||||
unset($this->config->product->search['fields']['product']);
|
||||
unset($this->config->product->search['fields']['project']);
|
||||
@@ -289,6 +290,15 @@ class build extends control
|
||||
$this->config->product->search['params']['plan']['values'] = $this->loadModel('productplan')->getForProducts(array($build->product => $build->product));
|
||||
$this->config->product->search['params']['module']['values'] = $this->tree->getOptionMenu($build->product, $viewType = 'story', $startModuleID = 0);
|
||||
$this->config->product->search['params']['status'] = array('operator' => '=', 'control' => 'select', 'values' => $this->lang->story->statusList);
|
||||
if($product->type == 'normal')
|
||||
{
|
||||
unset($this->config->product->search['fields']['branch']);
|
||||
unset($this->config->product->search['params']['branch']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->config->product->search['params']['branch']['values'] = array('' => '') + $this->loadModel('branch')->getPairs($product->id, 'noempty');
|
||||
}
|
||||
$this->loadModel('search')->setSearchParams($this->config->product->search);
|
||||
|
||||
if($browseType == 'bySearch')
|
||||
|
||||
@@ -35,11 +35,12 @@ $lang->product->menuOrder[20] = 'release';
|
||||
$lang->product->menuOrder[25] = 'roadmap';
|
||||
$lang->product->menuOrder[30] = 'doc';
|
||||
$lang->product->menuOrder[35] = 'project';
|
||||
$lang->product->menuOrder[40] = 'module';
|
||||
$lang->product->menuOrder[45] = 'view';
|
||||
$lang->product->menuOrder[50] = 'order';
|
||||
$lang->product->menuOrder[55] = 'create';
|
||||
$lang->product->menuOrder[60] = 'all';
|
||||
$lang->product->menuOrder[40] = 'branch';
|
||||
$lang->product->menuOrder[45] = 'module';
|
||||
$lang->product->menuOrder[50] = 'view';
|
||||
$lang->product->menuOrder[55] = 'order';
|
||||
$lang->product->menuOrder[60] = 'create';
|
||||
$lang->product->menuOrder[65] = 'all';
|
||||
$lang->story->menuOrder = $lang->product->menuOrder;
|
||||
$lang->productplan->menuOrder = $lang->product->menuOrder;
|
||||
$lang->release->menuOrder = $lang->product->menuOrder;
|
||||
|
||||
@@ -177,6 +177,7 @@ $lang->product->menu->plan = array('link' => '计划|productplan|browse|produ
|
||||
$lang->product->menu->release = array('link' => '发布|release|browse|productID=%s', 'subModule' => 'release');
|
||||
$lang->product->menu->roadmap = '路线图|product|roadmap|productID=%s';
|
||||
$lang->product->menu->doc = array('link' => '文档|product|doc|productID=%s', 'subModule' => 'doc');
|
||||
$lang->product->menu->branch = '分支|branch|manage|productID=%s';
|
||||
$lang->product->menu->module = '模块|tree|browse|productID=%s&view=story';
|
||||
$lang->product->menu->view = array('link' => '概况|product|view|productID=%s', 'alias' => 'edit');
|
||||
$lang->product->menu->project = "{$lang->projectCommon}|product|project|status=all&productID=%s";
|
||||
@@ -186,7 +187,9 @@ $lang->product->menu->all = array('link' => "<i class='icon-cubes'></i> 
|
||||
$lang->story = new stdclass();
|
||||
$lang->productplan = new stdclass();
|
||||
$lang->release = new stdclass();
|
||||
$lang->branch = new stdclass();
|
||||
|
||||
$lang->branch->menu = $lang->product->menu;
|
||||
$lang->story->menu = $lang->product->menu;
|
||||
$lang->productplan->menu = $lang->product->menu;
|
||||
$lang->release->menu = $lang->product->menu;
|
||||
|
||||
@@ -27,7 +27,7 @@ $lang->file->confirmDelete = " 您确定删除该附件吗?";
|
||||
$lang->file->errorFileSize = " 文件大小已经超过限制,可能不能成功上传!";
|
||||
$lang->file->errorFileUpload = " 文件上传失败,文件大小可能超出限制";
|
||||
$lang->file->errorSuffix = '压缩包格式错误,只能上传zip压缩包!';
|
||||
$lang->file->errorExtract = '解压缩失败!可能文件已经损坏';
|
||||
$lang->file->errorExtract = '解压缩失败!可能文件已经损坏,或压缩包里含有非法上传文件。';
|
||||
$lang->file->uploadImagesExplain = <<<EOD
|
||||
<p>1、上传文件为包含图片的zip压缩包,程序会以文件名作为标题,以图片作为内容。</p>
|
||||
<p>2、如果文件名可以开头含有 数字+下划线,以方便排序,程序会将他们忽略。</p>
|
||||
|
||||
@@ -403,8 +403,14 @@ class fileModel extends model
|
||||
if(is_dir($filePath)) $classFile->removeDir($filePath);
|
||||
|
||||
$this->app->loadClass('pclzip', true);
|
||||
$zip = new pclzip($zipFile);
|
||||
$zip = new pclzip($zipFile);
|
||||
$files = $zip->listContent();
|
||||
foreach($files as $uploadFile)
|
||||
{
|
||||
$extension = substr(strrchr($uploadFile['filename'], '.'), 1);
|
||||
if(empty($extension) or strpos($this->config->file->dangers, $extension) !== false) return false;
|
||||
}
|
||||
|
||||
if($zip->extract(PCLZIP_OPT_PATH, $filePath) == 0) return false;
|
||||
return $filePath;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ $config->product->search['fields']['status'] = $lang->story->status;
|
||||
$config->product->search['fields']['pri'] = $lang->story->pri;
|
||||
|
||||
$config->product->search['fields']['product'] = $lang->story->product;
|
||||
$config->product->search['fields']['branch'] = $lang->story->branch;
|
||||
$config->product->search['fields']['module'] = $lang->story->module;
|
||||
$config->product->search['fields']['plan'] = $lang->story->plan;
|
||||
$config->product->search['fields']['estimate'] = $lang->story->estimate;
|
||||
@@ -44,6 +45,7 @@ $config->product->search['params']['stage'] = array('operator' => '=',
|
||||
$config->product->search['params']['pri'] = array('operator' => '=', 'control' => 'select', 'values' => $lang->story->priList);
|
||||
|
||||
$config->product->search['params']['product'] = array('operator' => '=', 'control' => 'select', 'values' => '');
|
||||
$config->product->search['params']['branch'] = array('operator' => '=', 'control' => 'select', 'values' => '');
|
||||
$config->product->search['params']['module'] = array('operator' => 'belong', 'control' => 'select', 'values' => '');
|
||||
$config->product->search['params']['plan'] = array('operator' => '=', 'control' => 'select', 'values' => '');
|
||||
$config->product->search['params']['estimate'] = array('operator' => '=', 'control' => 'input', 'values' => '');
|
||||
|
||||
+33
-21
@@ -79,9 +79,9 @@ class product extends control
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function project($status = 'all', $productID = 0)
|
||||
public function project($status = 'all', $productID = 0, $branch = 0)
|
||||
{
|
||||
$this->product->setMenu($this->products, $productID);
|
||||
$this->product->setMenu($this->products, $productID, $branch);
|
||||
|
||||
$this->app->loadLang('my');
|
||||
$this->view->projectStats = $this->loadModel('project')->getProjectStats($status, $productID);
|
||||
@@ -106,7 +106,7 @@ class product extends control
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function browse($productID = 0, $browseType = 'unclosed', $param = 0, $orderBy = '', $recTotal = 0, $recPerPage = 20, $pageID = 1)
|
||||
public function browse($productID = 0, $branch = '', $browseType = 'unclosed', $param = 0, $orderBy = '', $recTotal = 0, $recPerPage = 20, $pageID = 1)
|
||||
{
|
||||
/* Lower browse type. */
|
||||
$browseType = strtolower($browseType);
|
||||
@@ -117,11 +117,13 @@ class product extends control
|
||||
|
||||
/* Set product, module and query. */
|
||||
$productID = $this->product->saveState($productID, $this->products);
|
||||
$product = $this->product->getById($productID);
|
||||
if($branch === '') $branch = $this->session->branch;
|
||||
$moduleID = ($browseType == 'bymodule') ? (int)$param : 0;
|
||||
$queryID = ($browseType == 'bysearch') ? (int)$param : 0;
|
||||
|
||||
/* Set menu. */
|
||||
$this->product->setMenu($this->products, $productID);
|
||||
$this->product->setMenu($this->products, $productID, $branch);
|
||||
|
||||
/* Process the order by field. */
|
||||
if(!$orderBy) $orderBy = $this->cookie->productStoryOrder ? $this->cookie->productStoryOrder : 'id_desc';
|
||||
@@ -146,37 +148,46 @@ class product extends control
|
||||
{
|
||||
$unclosedStatus = $this->lang->story->statusList;
|
||||
unset($unclosedStatus['closed']);
|
||||
$stories = $this->story->getProductStories($productID, 0, array_keys($unclosedStatus), $sort, $pager);
|
||||
$stories = $this->story->getProductStories($productID, $branch, 0, array_keys($unclosedStatus), $sort, $pager);
|
||||
}
|
||||
if($browseType == 'allstory') $stories = $this->story->getProductStories($productID, 0, 'all', $sort, $pager);
|
||||
if($browseType == 'bymodule') $stories = $this->story->getProductStories($productID, $this->tree->getAllChildID($moduleID), 'all', $sort, $pager);
|
||||
if($browseType == 'allstory') $stories = $this->story->getProductStories($productID, $branch, 0, 'all', $sort, $pager);
|
||||
if($browseType == 'bymodule') $stories = $this->story->getProductStories($productID, $branch, $this->tree->getAllChildID($moduleID), 'all', $sort, $pager);
|
||||
if($browseType == 'bysearch') $stories = $this->story->getBySearch($productID, $queryID, $sort, $pager);
|
||||
if($browseType == 'assignedtome')$stories = $this->story->getByAssignedTo($productID, $this->app->user->account, $sort, $pager);
|
||||
if($browseType == 'openedbyme') $stories = $this->story->getByOpenedBy($productID, $this->app->user->account, $sort, $pager);
|
||||
if($browseType == 'reviewedbyme')$stories = $this->story->getByReviewedBy($productID, $this->app->user->account, $sort, $pager);
|
||||
if($browseType == 'closedbyme') $stories = $this->story->getByClosedBy($productID, $this->app->user->account, $sort, $pager);
|
||||
if($browseType == 'draftstory') $stories = $this->story->getByStatus($productID, 'draft', $sort, $pager);
|
||||
if($browseType == 'activestory') $stories = $this->story->getByStatus($productID, 'active', $sort, $pager);
|
||||
if($browseType == 'changedstory')$stories = $this->story->getByStatus($productID, 'changed', $sort, $pager);
|
||||
if($browseType == 'willclose') $stories = $this->story->getWillClose($productID, $sort, $pager);
|
||||
if($browseType == 'closedstory') $stories = $this->story->getByStatus($productID, 'closed', $sort, $pager);
|
||||
if($browseType == 'assignedtome')$stories = $this->story->getByAssignedTo($productID, $branch, $this->app->user->account, $sort, $pager);
|
||||
if($browseType == 'openedbyme') $stories = $this->story->getByOpenedBy($productID, $branch, $this->app->user->account, $sort, $pager);
|
||||
if($browseType == 'reviewedbyme')$stories = $this->story->getByReviewedBy($productID, $branch, $this->app->user->account, $sort, $pager);
|
||||
if($browseType == 'closedbyme') $stories = $this->story->getByClosedBy($productID, $branch, $this->app->user->account, $sort, $pager);
|
||||
if($browseType == 'draftstory') $stories = $this->story->getByStatus($productID, $branch, 'draft', $sort, $pager);
|
||||
if($browseType == 'activestory') $stories = $this->story->getByStatus($productID, $branch, 'active', $sort, $pager);
|
||||
if($browseType == 'changedstory')$stories = $this->story->getByStatus($productID, $branch, 'changed', $sort, $pager);
|
||||
if($browseType == 'willclose') $stories = $this->story->getWillClose($productID, $branch, $sort, $pager);
|
||||
if($browseType == 'closedstory') $stories = $this->story->getByStatus($productID, $branch, 'closed', $sort, $pager);
|
||||
|
||||
/* Process the sql, get the conditon partion, save it to session. */
|
||||
$this->loadModel('common')->saveQueryCondition($this->dao->get(), 'story');
|
||||
|
||||
/* Build search form. */
|
||||
$this->config->product->search['actionURL'] = $this->createLink('product', 'browse', "productID=$productID&browseType=bySearch&queryID=myQueryID");
|
||||
$this->config->product->search['actionURL'] = $this->createLink('product', 'browse', "productID=$productID&branch=$branch&browseType=bySearch&queryID=myQueryID");
|
||||
$this->config->product->search['queryID'] = $queryID;
|
||||
$this->config->product->search['params']['plan']['values'] = $this->loadModel('productplan')->getPairs($productID);
|
||||
$this->config->product->search['params']['product']['values'] = array($productID => $this->products[$productID], 'all' => $this->lang->product->allProduct);
|
||||
$this->config->product->search['params']['module']['values'] = $this->tree->getOptionMenu($productID, $viewType = 'story', $startModuleID = 0);
|
||||
if($product->type == 'normal')
|
||||
{
|
||||
unset($this->config->product->search['fields']['branch']);
|
||||
unset($this->config->product->search['params']['branch']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->config->product->search['params']['branch']['values'] = array('' => '') + $this->loadModel('branch')->getPairs($productID, 'noempty');
|
||||
}
|
||||
$this->loadModel('search')->setSearchParams($this->config->product->search);
|
||||
|
||||
$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);
|
||||
$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->parentModules = $this->tree->getParents($moduleID);
|
||||
@@ -185,6 +196,7 @@ class product extends control
|
||||
$this->view->orderBy = $orderBy;
|
||||
$this->view->browseType = $browseType;
|
||||
$this->view->moduleID = $moduleID;
|
||||
$this->view->branch = $branch;
|
||||
$this->display();
|
||||
}
|
||||
|
||||
@@ -505,14 +517,14 @@ class product extends control
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function ajaxGetPlans($productID, $planID = 0, $needCreate = false)
|
||||
public function ajaxGetPlans($productID, $branch = 0, $planID = 0, $needCreate = false)
|
||||
{
|
||||
$plans = $this->loadModel('productplan')->getPairs($productID);
|
||||
$plans = $this->loadModel('productplan')->getPairs($productID, $branch);
|
||||
$output = html::select('plan', $plans, $planID, "class='form-control chosen'");
|
||||
if(count($plans) == 1 and $needCreate)
|
||||
{
|
||||
$output .= "<span class='input-group-addon'>";
|
||||
$output .= html::a($this->createLink('productplan', 'create', "productID=$productID"), $this->lang->productplan->create, '_blank');
|
||||
$output .= html::a($this->createLink('productplan', 'create', "productID=$productID&branch=$branch"), $this->lang->productplan->create, '_blank');
|
||||
$output .= ' ';
|
||||
$output .= html::a("javascript:loadProductPlans($productID)", $this->lang->refresh);
|
||||
$output .= '</span>';
|
||||
|
||||
@@ -58,6 +58,7 @@ $lang->product->company = '所属公司';
|
||||
$lang->product->name = "{$lang->productCommon}名称";
|
||||
$lang->product->code = "{$lang->productCommon}代号";
|
||||
$lang->product->order = '排序';
|
||||
$lang->product->type = "{$lang->productCommon}类型";
|
||||
$lang->product->status = '状态';
|
||||
$lang->product->desc = "{$lang->productCommon}描述";
|
||||
$lang->product->PO = "{$lang->productCommon}负责人";
|
||||
@@ -83,6 +84,11 @@ $lang->product->allStory = '全部需求';
|
||||
$lang->product->allProduct = '全部' . $lang->productCommon;
|
||||
$lang->product->allProductsOfProject = '全部关联' . $lang->productCommon;
|
||||
|
||||
$lang->product->typeList[''] = '';
|
||||
$lang->product->typeList['normal'] = '正常';
|
||||
$lang->product->typeList['branch'] = '多分支';
|
||||
$lang->product->typeList['platform'] = '多平台';
|
||||
|
||||
$lang->product->statusList[''] = '';
|
||||
$lang->product->statusList['normal'] = '正常';
|
||||
$lang->product->statusList['closed'] = '结束';
|
||||
|
||||
@@ -22,7 +22,7 @@ class productModel extends model
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function setMenu($products, $productID, $extra = '')
|
||||
public function setMenu($products, $productID, $branch = 0, $extra = '')
|
||||
{
|
||||
/* Has access privilege?. */
|
||||
if($products and !isset($products[$productID]) and !$this->checkPriv($this->getById($productID)))
|
||||
@@ -38,7 +38,7 @@ class productModel extends model
|
||||
if($currentModule == 'story' and $currentMethod != 'create' and $currentMethod != 'batchcreate') $currentModule = 'product';
|
||||
if($currentMethod == 'report') $currentMethod = 'browse';
|
||||
|
||||
$selectHtml = $this->select($products, $productID, $currentModule, $currentMethod, $extra);
|
||||
$selectHtml = $this->select($products, $productID, $currentModule, $currentMethod, $extra, $branch);
|
||||
foreach($this->lang->product->menu as $key => $menu)
|
||||
{
|
||||
$replace = $key == 'list' ? $selectHtml : $productID;
|
||||
@@ -57,13 +57,21 @@ class productModel extends model
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function select($products, $productID, $currentModule, $currentMethod, $extra = '')
|
||||
public function select($products, $productID, $currentModule, $currentMethod, $extra = '', $branch = 0)
|
||||
{
|
||||
if(!$productID) return;
|
||||
|
||||
setCookie("lastProduct", $productID, $this->config->cookieLife, $this->config->webRoot);
|
||||
setCookie("lastBranch", "$productID-$branch", $this->config->cookieLife, $this->config->webRoot);
|
||||
$currentProduct = $this->getById($productID);
|
||||
$output = "<a id='currentItem' href=\"javascript:showDropMenu('product', '$productID', '$currentModule', '$currentMethod', '$extra')\">{$currentProduct->name} <span class='icon-caret-down'></span></a><div id='dropMenu'><i class='icon icon-spin icon-spinner'></i></div>";
|
||||
$output = "<a id='currentItem' href=\"javascript:showDropMenu('product', '$productID', '$currentModule', '$currentMethod', '$extra')\">{$currentProduct->name} <span class='icon-caret-down'></span></a><div id='dropMenu'><i class='icon icon-spin icon-spinner'></i></div>";
|
||||
if($currentProduct->type != 'normal')
|
||||
{
|
||||
$branches = $this->loadModel('branch')->getPairs($productID);
|
||||
$branchName = isset($branches[$branch]) ? $branches[$branch] : $branches[0];
|
||||
$output .= '</li><li>';
|
||||
$output .= "<a id='currentBranch' href=\"javascript:showDropMenu('branch', '$productID', '$currentModule', '$currentMethod', '$extra')\">{$branchName} <span class='icon-caret-down'></span></a><div id='dropMenu'><i class='icon icon-spin icon-spinner'></i></div>";
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
@@ -81,6 +89,14 @@ class productModel extends model
|
||||
if($productID == 0 and $this->cookie->lastProduct) $this->session->set('product', (int)$this->cookie->lastProduct);
|
||||
if($productID == 0 and $this->session->product == '') $this->session->set('product', key($products));
|
||||
if(!isset($products[$this->session->product])) $this->session->set('product', key($products));
|
||||
|
||||
if($this->cookie->lastBranch)
|
||||
{
|
||||
list($lastProduct, $branch) = explode('-', $this->cookie->lastBranch);
|
||||
$branch = $lastProduct == $this->session->product ? $branch : 0;
|
||||
$this->session->set('branch', (int)$branch);
|
||||
}
|
||||
|
||||
return $this->session->product;
|
||||
}
|
||||
|
||||
@@ -662,28 +678,32 @@ class productModel extends model
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function getProductLink($module, $method, $extra)
|
||||
public function getProductLink($module, $method, $extra, $branch = false)
|
||||
{
|
||||
$link = '';
|
||||
if(strpos('product,roadmap,bug,testcase,testtask,story', $module) !== false)
|
||||
{
|
||||
if($module == 'product' && $method == 'project')
|
||||
{
|
||||
$link = helper::createLink($module, $method, "status=all&productID=%s");
|
||||
$link = helper::createLink($module, $method, "status=all&productID=%s" . ($branch ? "&branch=%s" : ''));
|
||||
}
|
||||
elseif($module == 'product' && $method == 'index')
|
||||
{
|
||||
$link = helper::createLink($module, $method, "locate=no&productID=%s");
|
||||
}
|
||||
elseif($module == 'product' && $method == 'browse')
|
||||
{
|
||||
$link = helper::createLink($module, $method, "productID=%s" . ($branch ? "&branch=%s" : ''));
|
||||
}
|
||||
else
|
||||
{
|
||||
$link = helper::createLink($module, $method, "productID=%s");
|
||||
$link = helper::createLink($module, $method, "productID=%s&branch=%s");
|
||||
}
|
||||
}
|
||||
else if($module == 'productplan' || $module == 'release')
|
||||
{
|
||||
if($method != 'browse' && $method != 'create') $method = 'browse';
|
||||
$link = helper::createLink($module, $method, "productID=%s");
|
||||
$link = helper::createLink($module, $method, "productID=%s" . ($branch ? "&branch=%s" : ''));
|
||||
}
|
||||
else if($module == 'tree')
|
||||
{
|
||||
|
||||
@@ -15,17 +15,17 @@
|
||||
<?php js::set('browseType', $browseType);?>
|
||||
<div id='featurebar'>
|
||||
<ul class='nav'>
|
||||
<li id='unclosedTab'> <?php echo html::a($this->inlink('browse', "productID=$productID&browseType=unclosed"), $lang->product->unclosed);?></li>
|
||||
<li id='allstoryTab'> <?php echo html::a($this->inlink('browse', "productID=$productID&browseType=allStory"), $lang->product->allStory);?></li>
|
||||
<li id='assignedtomeTab'> <?php echo html::a($this->inlink('browse', "productID=$productID&browseType=assignedtome"), $lang->product->assignedToMe);?></li>
|
||||
<li id='openedbymeTab'> <?php echo html::a($this->inlink('browse', "productID=$productID&browseType=openedByMe"), $lang->product->openedByMe);?></li>
|
||||
<li id='reviewedbymeTab'> <?php echo html::a($this->inlink('browse', "productID=$productID&browseType=reviewedByMe"), $lang->product->reviewedByMe);?></li>
|
||||
<li id='closedbymeTab'> <?php echo html::a($this->inlink('browse', "productID=$productID&browseType=closedByMe"), $lang->product->closedByMe);?></li>
|
||||
<li id='draftstoryTab'> <?php echo html::a($this->inlink('browse', "productID=$productID&browseType=draftStory"), $lang->product->draftStory);?></li>
|
||||
<li id='activestoryTab'> <?php echo html::a($this->inlink('browse', "productID=$productID&browseType=activeStory"), $lang->product->activeStory);?></li>
|
||||
<li id='changedstoryTab'> <?php echo html::a($this->inlink('browse', "productID=$productID&browseType=changedStory"), $lang->product->changedStory);?></li>
|
||||
<li id='willcloseTab'> <?php echo html::a($this->inlink('browse', "productID=$productID&browseType=willClose"), $lang->product->willClose);?></li>
|
||||
<li id='closedstoryTab'> <?php echo html::a($this->inlink('browse', "productID=$productID&browseType=closedStory"), $lang->product->closedStory);?></li>
|
||||
<li id='unclosedTab'> <?php echo html::a($this->inlink('browse', "productID=$productID&branch=$branch&browseType=unclosed"), $lang->product->unclosed);?></li>
|
||||
<li id='allstoryTab'> <?php echo html::a($this->inlink('browse', "productID=$productID&branch=$branch&browseType=allStory"), $lang->product->allStory);?></li>
|
||||
<li id='assignedtomeTab'> <?php echo html::a($this->inlink('browse', "productID=$productID&branch=$branch&browseType=assignedtome"), $lang->product->assignedToMe);?></li>
|
||||
<li id='openedbymeTab'> <?php echo html::a($this->inlink('browse', "productID=$productID&branch=$branch&browseType=openedByMe"), $lang->product->openedByMe);?></li>
|
||||
<li id='reviewedbymeTab'> <?php echo html::a($this->inlink('browse', "productID=$productID&branch=$branch&browseType=reviewedByMe"), $lang->product->reviewedByMe);?></li>
|
||||
<li id='closedbymeTab'> <?php echo html::a($this->inlink('browse', "productID=$productID&branch=$branch&browseType=closedByMe"), $lang->product->closedByMe);?></li>
|
||||
<li id='draftstoryTab'> <?php echo html::a($this->inlink('browse', "productID=$productID&branch=$branch&browseType=draftStory"), $lang->product->draftStory);?></li>
|
||||
<li id='activestoryTab'> <?php echo html::a($this->inlink('browse', "productID=$productID&branch=$branch&browseType=activeStory"), $lang->product->activeStory);?></li>
|
||||
<li id='changedstoryTab'> <?php echo html::a($this->inlink('browse', "productID=$productID&branch=$branch&browseType=changedStory"), $lang->product->changedStory);?></li>
|
||||
<li id='willcloseTab'> <?php echo html::a($this->inlink('browse', "productID=$productID&branch=$branch&browseType=willClose"), $lang->product->willClose);?></li>
|
||||
<li id='closedstoryTab'> <?php echo html::a($this->inlink('browse', "productID=$productID&branch=$branch&browseType=closedStory"), $lang->product->closedStory);?></li>
|
||||
<li id='bysearchTab'><a href='javascript:;'><i class='icon-search icon'></i> <?php echo $lang->product->searchStory;?></a></li>
|
||||
</ul>
|
||||
<div class='actions'>
|
||||
@@ -47,8 +47,8 @@
|
||||
</div>
|
||||
<div class='btn-group'>
|
||||
<?php
|
||||
common::printIcon('story', 'batchCreate', "productID=$productID&moduleID=$moduleID", '', 'button', 'plus-sign');
|
||||
common::printIcon('story', 'create', "productID=$productID&moduleID=$moduleID", '', 'button', 'plus');
|
||||
common::printIcon('story', 'batchCreate', "productID=$productID&branch=$branch&moduleID=$moduleID", '', 'button', 'plus-sign');
|
||||
common::printIcon('story', 'create', "productID=$productID&branch=$branch&moduleID=$moduleID", '', 'button', 'plus');
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
@@ -74,7 +74,7 @@
|
||||
<table class='table table-condensed table-hover table-striped tablesorter table-fixed' id='storyList'>
|
||||
<thead>
|
||||
<tr>
|
||||
<?php $vars = "productID=$productID&browseType=$browseType¶m=$moduleID&orderBy=%s&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}";?>
|
||||
<?php $vars = "productID=$productID&branch=$branch&browseType=$browseType¶m=$moduleID&orderBy=%s&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}";?>
|
||||
<th class='w-id'> <?php common::printOrderLink('id', $orderBy, $vars, $lang->idAB);?></th>
|
||||
<th class='w-pri'> <?php common::printOrderLink('pri', $orderBy, $vars, $lang->priAB);?></th>
|
||||
<th class='w-p30'> <?php common::printOrderLink('title', $orderBy, $vars, $lang->story->title);?></th>
|
||||
@@ -130,7 +130,7 @@
|
||||
<?php
|
||||
$canBatchEdit = common::hasPriv('story', 'batchEdit');
|
||||
$disabled = $canBatchEdit ? '' : "disabled='disabled'";
|
||||
$actionLink = $this->createLink('story', 'batchEdit', "productID=$productID&projectID=0");
|
||||
$actionLink = $this->createLink('story', 'batchEdit', "productID=$productID&projectID=0&branch=$branch");
|
||||
?>
|
||||
<div class='btn-group dropup'>
|
||||
<?php echo html::commonButton($lang->edit, "onclick=\"setFormAction('$actionLink')\" $disabled");?>
|
||||
|
||||
@@ -41,6 +41,10 @@
|
||||
<th><?php echo $lang->product->RD;?></th>
|
||||
<td><?php echo html::select('RD', $rdUsers, '', "class='form-control chosen'");?></td><td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->product->type;?></th>
|
||||
<td><?php echo html::select('type', $lang->product->typeList, 'normal', "class='form-control'");?></td><td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->product->desc;?></th>
|
||||
<td colspan='2'><?php echo html::textarea('desc', '', "rows='8' class='form-control'");?></td>
|
||||
|
||||
@@ -42,6 +42,10 @@
|
||||
<th><?php echo $lang->product->RD;?></th>
|
||||
<td><?php echo html::select('RD', $rdUsers, $product->RD, "class='form-control chosen'");?></td><td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->product->type;?></th>
|
||||
<td><?php echo html::select('type', $lang->product->typeList, $product->type, "class='form-control'");?></td><td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->product->status;?></th>
|
||||
<td><?php echo html::select('status', $lang->product->statusList, $product->status, "class='form-control'");?></td><td></td>
|
||||
|
||||
@@ -81,6 +81,10 @@
|
||||
<th><?php echo $lang->product->RD;?></th>
|
||||
<td><?php echo $users[$product->RD];?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->product->type;?></th>
|
||||
<td><?php echo $lang->product->typeList[$product->type];?></td><td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->product->status;?></th>
|
||||
<td class='product-<?php echo $product->status?>'><?php echo $lang->product->statusList[$product->status];?></td>
|
||||
|
||||
@@ -18,12 +18,15 @@ class productplan extends control
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function commonAction($productID)
|
||||
public function commonAction($productID, $branch = 0)
|
||||
{
|
||||
$this->loadModel('product');
|
||||
$this->view->product = $this->product->getById($productID);
|
||||
$this->view->position[] = html::a($this->createLink('product', 'browse', "productID={$this->view->product->id}"), $this->view->product->name);
|
||||
$this->product->setMenu($this->product->getPairs(), $productID);
|
||||
$product = $this->product->getById($productID);
|
||||
$this->view->product = $product;
|
||||
$this->view->branch = $branch;
|
||||
$this->view->branches = $product->type == 'normal' ? array() : $this->loadModel('branch')->getPairs($productID);
|
||||
$this->view->position[] = html::a($this->createLink('product', 'browse', "productID={$this->view->product->id}&branch=$branch"), $this->view->product->name);
|
||||
$this->product->setMenu($this->product->getPairs(), $productID, $branch);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -33,17 +36,17 @@ class productplan extends control
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function create($product = '')
|
||||
public function create($product = '', $branch = 0)
|
||||
{
|
||||
if(!empty($_POST))
|
||||
{
|
||||
$planID = $this->productplan->create();
|
||||
if(dao::isError()) die(js::error(dao::getError()));
|
||||
$this->loadModel('action')->create('productplan', $planID, 'opened');
|
||||
die(js::locate($this->createLink('productplan', 'browse', "productID=$product"), 'parent'));
|
||||
die(js::locate($this->createLink('productplan', 'browse', "productID=$product&branch=$branch"), 'parent'));
|
||||
}
|
||||
|
||||
$this->commonAction($product);
|
||||
$this->commonAction($product, $branch);
|
||||
$lastPlan = $this->productplan->getLast($product);
|
||||
if($lastPlan)
|
||||
{
|
||||
@@ -54,7 +57,7 @@ class productplan extends control
|
||||
|
||||
$begin = date('Y-m-d', strtotime("+$delta days", $timestamp));
|
||||
}
|
||||
$this->view->begin = $lastPlan ? $begin : '';
|
||||
$this->view->begin = $lastPlan ? $begin : '';
|
||||
|
||||
$this->view->title = $this->view->product->name . $this->lang->colon . $this->lang->productplan->create;
|
||||
$this->view->position[] = $this->lang->productplan->common;
|
||||
@@ -84,7 +87,7 @@ class productplan extends control
|
||||
}
|
||||
|
||||
$plan = $this->productplan->getByID($planID);
|
||||
$this->commonAction($plan->product);
|
||||
$this->commonAction($plan->product, $plan->branch);
|
||||
$this->view->title = $this->view->product->name . $this->lang->colon . $this->lang->productplan->edit;
|
||||
$this->view->position[] = $this->lang->productplan->edit;
|
||||
$this->view->plan = $plan;
|
||||
@@ -98,13 +101,13 @@ class productplan extends control
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function batchEdit($productID)
|
||||
public function batchEdit($productID, $branch = 0)
|
||||
{
|
||||
if(isset($_POST['planIDList']))
|
||||
{
|
||||
$this->commonAction($productID);
|
||||
$this->commonAction($productID, $branch);
|
||||
$this->view->title = $this->lang->productplan->batchEdit;
|
||||
$this->view->position[] = html::a(inlink('browse', "productID=$productID"), $this->lang->productplan->common);
|
||||
$this->view->position[] = html::a(inlink('browse', "productID=$productID&branch=$branch"), $this->lang->productplan->common);
|
||||
$this->view->position[] = $this->lang->productplan->batchEdit;
|
||||
|
||||
$this->view->plans = $this->productplan->getByIDList($this->post->planIDList);
|
||||
@@ -119,7 +122,7 @@ class productplan extends control
|
||||
$actionID = $this->action->create('productplan', $planID, 'Edited');
|
||||
$this->action->logHistory($actionID, $change);
|
||||
}
|
||||
die(js::locate(inlink('browse', "productID=$productID"), 'parent'));
|
||||
die(js::locate(inlink('browse', "productID=$productID&branch=$branch"), 'parent'));
|
||||
}
|
||||
die(js::locate('back'));
|
||||
}
|
||||
@@ -158,7 +161,7 @@ class productplan extends control
|
||||
}
|
||||
$this->send($response);
|
||||
}
|
||||
die(js::locate(inlink('browse', "productID=$plan->product"), 'parent'));
|
||||
die(js::locate(inlink('browse', "productID=$plan->product&branch=$plan->branch"), 'parent'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,7 +176,7 @@ class productplan extends control
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function browse($productID = 0, $orderBy = 'begin_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1 )
|
||||
public function browse($productID = 0, $branch = 0, $orderBy = 'begin_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1 )
|
||||
{
|
||||
/* Load pager. */
|
||||
$this->app->loadClass('pager', $static = true);
|
||||
@@ -183,13 +186,13 @@ class productplan extends control
|
||||
$sort = $this->loadModel('common')->appendOrder($orderBy);
|
||||
|
||||
$this->session->set('productPlanList', $this->app->getURI(true));
|
||||
$this->commonAction($productID);
|
||||
$this->commonAction($productID, $branch);
|
||||
$products = $this->product->getPairs();
|
||||
$this->view->title = $products[$productID] . $this->lang->colon . $this->lang->productplan->browse;
|
||||
$this->view->position[] = $this->lang->productplan->browse;
|
||||
$this->view->productID = $productID;
|
||||
$this->view->orderBy = $orderBy;
|
||||
$this->view->plans = $this->productplan->getList($productID, $pager, $sort);
|
||||
$this->view->plans = $this->productplan->getList($productID, $branch, $pager, $sort);
|
||||
$this->view->pager = $pager;
|
||||
$this->display();
|
||||
}
|
||||
@@ -213,7 +216,7 @@ class productplan extends control
|
||||
|
||||
$plan = $this->productplan->getByID($planID, true);
|
||||
if(!$plan) die(js::error($this->lang->notFound) . js::locate('back'));
|
||||
$this->commonAction($plan->product);
|
||||
$this->commonAction($plan->product, $plan->branch);
|
||||
$products = $this->product->getPairs();
|
||||
$this->view->title = "PLAN #$plan->id $plan->title/" . $products[$plan->product];
|
||||
$this->view->position[] = $this->lang->productplan->view;
|
||||
@@ -239,9 +242,9 @@ class productplan extends control
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function ajaxGetProductplans($productID)
|
||||
public function ajaxGetProductplans($productID, $branch = 0)
|
||||
{
|
||||
$plans = $this->productplan->getPairs($productID);
|
||||
$plans = $this->productplan->getPairs($productID, $branch);
|
||||
die(html::select('plan', $plans, '', "class='form-control'"));
|
||||
}
|
||||
|
||||
@@ -263,7 +266,7 @@ class productplan extends control
|
||||
$this->loadModel('story');
|
||||
$this->loadModel('tree');
|
||||
$plan = $this->productplan->getByID($planID);
|
||||
$this->commonAction($plan->product);
|
||||
$this->commonAction($plan->product, $plan->branch);
|
||||
$products = $this->product->getPairs();
|
||||
|
||||
/* Build search form. */
|
||||
@@ -278,6 +281,15 @@ class productplan extends control
|
||||
$storyStatusList = $this->lang->story->statusList;
|
||||
unset($storyStatusList['closed']);
|
||||
$this->config->product->search['params']['status'] = array('operator' => '=', 'control' => 'select', 'values' => $storyStatusList);
|
||||
if($this->view->product->type == 'normal')
|
||||
{
|
||||
unset($this->config->product->search['fields']['branch']);
|
||||
unset($this->config->product->search['params']['branch']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->config->product->search['params']['branch']['values'] = array('' => '') + $this->loadModel('branch')->getPairs($this->view->product->id, 'noempty');
|
||||
}
|
||||
$this->loadModel('search')->setSearchParams($this->config->product->search);
|
||||
|
||||
if($browseType == 'bySearch')
|
||||
@@ -290,7 +302,7 @@ class productplan extends control
|
||||
}
|
||||
else
|
||||
{
|
||||
$allStories = $this->story->getProductStories($this->view->product->id, $moduleID = '0', $status = 'draft,active,changed');
|
||||
$allStories = $this->story->getProductStories($this->view->product->id, $plan->branch, $moduleID = '0', $status = 'draft,active,changed');
|
||||
}
|
||||
|
||||
$this->view->allStories = $allStories;
|
||||
@@ -377,7 +389,7 @@ class productplan extends control
|
||||
|
||||
$this->loadModel('bug');
|
||||
$plan = $this->productplan->getByID($planID);
|
||||
$this->commonAction($plan->product);
|
||||
$this->commonAction($plan->product, $plan->branch);
|
||||
$products = $this->product->getPairs('nocode');
|
||||
$productID = $plan->product;
|
||||
$queryID = ($browseType == 'bysearch') ? (int)$param : 0;
|
||||
|
||||
@@ -39,6 +39,7 @@ $lang->productplan->confirmUnlinkBug = "您确认移除该Bug吗?";
|
||||
|
||||
$lang->productplan->id = '编号';
|
||||
$lang->productplan->product = $lang->productCommon;
|
||||
$lang->productplan->branch = '所属分支';
|
||||
$lang->productplan->title = '名称';
|
||||
$lang->productplan->desc = '描述';
|
||||
$lang->productplan->begin = '开始日期';
|
||||
|
||||
@@ -65,10 +65,11 @@ class productplanModel extends model
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
public function getList($product = 0, $pager = null, $orderBy = 'begin_desc')
|
||||
public function getList($product = 0, $branch = 0, $pager = null, $orderBy = 'begin_desc')
|
||||
{
|
||||
return $this->dao->select('*')->from(TABLE_PRODUCTPLAN)->where('product')->eq($product)
|
||||
->andWhere('deleted')->eq(0)
|
||||
->beginIF(!empty($branch))->andWhere('branch')->eq($branch)->fi()
|
||||
->orderBy($orderBy)
|
||||
->page($pager)
|
||||
->fetchAll();
|
||||
@@ -82,15 +83,14 @@ class productplanModel extends model
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getPairs($product = 0, $expired = '')
|
||||
public function getPairs($product = 0, $branch = 0, $expired = '')
|
||||
{
|
||||
$date = date('Y-m-d');
|
||||
return array('' => '') + $this->dao->select('id,CONCAT(title, " [", begin, " ~ ", end, "]") as title')->from(TABLE_PRODUCTPLAN)
|
||||
->where('product')->in($product)
|
||||
->andWhere('deleted')->eq(0)
|
||||
->beginIF($expired == 'unexpired')
|
||||
->andWhere('end')->gt($date)
|
||||
->fi()
|
||||
->beginIF($branch)->andWhere("branch")->eq($branch)->fi()
|
||||
->beginIF($expired == 'unexpired')->andWhere('end')->gt($date)->fi()
|
||||
->orderBy('begin desc')->fetchPairs();
|
||||
}
|
||||
|
||||
|
||||
@@ -15,13 +15,13 @@
|
||||
<div id='titlebar'>
|
||||
<div class='heading'><i class='icon-flag'></i> <?php echo $lang->productplan->browse;?> </div>
|
||||
<div class='actions'>
|
||||
<?php common::printIcon('productplan', 'create', "productID=$product->id", '', 'button', 'plus');?>
|
||||
<?php common::printIcon('productplan', 'create', "productID=$product->id&branch=$branch", '', 'button', 'plus');?>
|
||||
</div>
|
||||
</div>
|
||||
<form method='post' action='<?php echo inlink('batchEdit', "productID=$product->id")?>'>
|
||||
<form method='post' action='<?php echo inlink('batchEdit', "productID=$product->id&branch=$branch")?>'>
|
||||
<table class='table' id="productplan">
|
||||
<thead>
|
||||
<?php $vars = "productID=$productID&orderBy=%s&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}"; ?>
|
||||
<?php $vars = "productID=$productID&branch=$branch&orderBy=%s&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}"; ?>
|
||||
<tr class='colhead'>
|
||||
<th class='w-id'> <?php common::printOrderLink('id', $orderBy, $vars, $lang->idAB);?></th>
|
||||
<th> <?php common::printOrderLink('title', $orderBy, $vars, $lang->productplan->title);?></th>
|
||||
|
||||
@@ -27,6 +27,12 @@
|
||||
<th class='w-80px'><?php echo $lang->productplan->product;?></th>
|
||||
<td class='w-p25-f'><?php echo $product->name;?></td><td></td>
|
||||
</tr>
|
||||
<?php if($product->type != 'normal'):?>
|
||||
<tr>
|
||||
<th><?php echo $lang->productplan->branch;?></th>
|
||||
<td><?php echo html::select('branch', $branches, $branch, "class='form-control'");?></td>
|
||||
</tr>
|
||||
<?php endif;?>
|
||||
<tr>
|
||||
<th><?php echo $lang->productplan->title;?></th>
|
||||
<td><?php echo html::input('title', '', "class='form-control'");?></td>
|
||||
|
||||
@@ -28,6 +28,12 @@
|
||||
<th class='w-80px'><?php echo $lang->productplan->product;?></th>
|
||||
<td class='w-p25-f'><?php echo $product->name;?></td><td></td>
|
||||
</tr>
|
||||
<?php if($product->type != 'normal'):?>
|
||||
<tr>
|
||||
<th><?php echo $lang->productplan->branch;?></th>
|
||||
<td><?php echo html::select('branch', $branches, $plan->branch, 'class="form-control"');?></td>
|
||||
</tr>
|
||||
<?php endif;?>
|
||||
<tr>
|
||||
<th><?php echo $lang->productplan->title;?></th>
|
||||
<td><?php echo html::input('title', $plan->title, 'class="form-control"');?></td>
|
||||
|
||||
@@ -1527,6 +1527,8 @@ class project extends control
|
||||
$this->config->product->search['params']['plan']['values'] = $this->loadModel('productplan')->getForProducts($products);
|
||||
unset($this->lang->story->statusList['draft']);
|
||||
$this->config->product->search['params']['status'] = array('operator' => '=', 'control' => 'select', 'values' => $this->lang->story->statusList);
|
||||
unset($this->config->product->search['fields']['branch']);
|
||||
unset($this->config->product->search['params']['branch']);
|
||||
$this->loadModel('search')->setSearchParams($this->config->product->search);
|
||||
|
||||
$title = $project->name . $this->lang->colon . $this->lang->project->linkStory;
|
||||
@@ -1539,7 +1541,7 @@ class project extends control
|
||||
}
|
||||
else
|
||||
{
|
||||
$allStories = $this->story->getProductStories(array_keys($products), $moduleID = '0', $status = 'active');
|
||||
$allStories = $this->story->getProductStories(array_keys($products), 0, $moduleID = '0', $status = 'active');
|
||||
}
|
||||
$prjStories = $this->story->getProjectStoryPairs($projectID);
|
||||
|
||||
|
||||
@@ -551,7 +551,7 @@ class projectModel extends model
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getList($status = 'all', $limit = 0, $productID = 0)
|
||||
public function getList($status = 'all', $limit = 0, $productID = 0, $branch = 0)
|
||||
{
|
||||
if($productID != 0)
|
||||
{
|
||||
@@ -563,6 +563,7 @@ class projectModel extends model
|
||||
->andWhere('t2.deleted')->eq(0)
|
||||
->andWhere('t2.iscat')->eq(0)
|
||||
->beginIF($status == 'undone')->andWhere('t2.status')->ne('done')->fi()
|
||||
->beginIF($branch != 0)->andWhere('t1.branch')->like(",$branch,")->fi()
|
||||
->beginIF($status == 'isdoing')->andWhere('t2.status')->ne('done')->andWhere('t2.status')->ne('suspended')->fi()
|
||||
->beginIF($status != 'all' and $status != 'isdoing' and $status != 'undone')->andWhere('status')->in($status)->fi()
|
||||
->orderBy('order_desc')
|
||||
@@ -630,10 +631,10 @@ class projectModel extends model
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function getProjectStats($status = 'undone', $productID = 0, $itemCounts = 30, $orderBy = 'order_desc', $pager = null)
|
||||
public function getProjectStats($status = 'undone', $productID = 0, $branch, $itemCounts = 30, $orderBy = 'order_desc', $pager = null)
|
||||
{
|
||||
/* Init vars. */
|
||||
$projects = $this->getList($status, 0, $productID);
|
||||
$projects = $this->getList($status, 0, $productID, $branch);
|
||||
foreach($projects as $projectID => $project)
|
||||
{
|
||||
if(!$this->checkPriv($project)) unset($projects[$projectID]);
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
<?php echo html::a($storyLink, sprintf('%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><?php echo html::a($this->createLink('product', 'browse', "productID=$story->product"), $products[$story->product], '_blank');?></td>
|
||||
<td><?php echo html::a($this->createLink('product', 'browse', "productID=$story->product&branch=$story->branch"), $products[$story->product], '_blank');?></td>
|
||||
<td class='text-left nobr' title="<?php echo $story->title?>"><?php echo html::a($storyLink, $story->title);?></td>
|
||||
<td><?php echo $story->planTitle;?></td>
|
||||
<td><?php echo $users[$story->openedBy];?></td>
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
common::printIcon('story', 'export', "productID=$productID&orderBy=id_desc", '', 'button', '', '', 'export');
|
||||
|
||||
$this->lang->story->create = $this->lang->project->createStory;
|
||||
if($productID) common::printIcon('story', 'create', "productID=$productID&moduleID=0&story=0&project=$project->id");
|
||||
if($productID) common::printIcon('story', 'create', "productID=$productID&branch=&moduleID=0&story=0&project=$project->id");
|
||||
|
||||
common::printIcon('project', 'linkStory', "project=$project->id", '', 'button', 'link');
|
||||
?>
|
||||
|
||||
@@ -18,11 +18,14 @@ class release extends control
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function commonAction($productID)
|
||||
public function commonAction($productID, $branch = 0)
|
||||
{
|
||||
$this->loadModel('product');
|
||||
$this->view->product = $this->product->getById($productID);
|
||||
$this->view->position[] = html::a($this->createLink('product', 'browse', "productID={$this->view->product->id}"), $this->view->product->name);
|
||||
$product = $this->product->getById($productID);
|
||||
$this->view->product = $product;
|
||||
$this->view->branch = $branch;
|
||||
$this->view->branches = $product->type == 'normal' ? array() : $this->loadModel('branch')->getPairs($product->id);
|
||||
$this->view->position[] = html::a($this->createLink('product', 'browse', "productID={$this->view->product->id}&branch=$branch"), $this->view->product->name);
|
||||
$this->product->setMenu($this->product->getPairs(), $productID);
|
||||
}
|
||||
|
||||
@@ -332,6 +335,7 @@ class release extends control
|
||||
$this->loadModel('product');
|
||||
|
||||
/* Build search form. */
|
||||
$product = $this->product->getByID($release->product);
|
||||
$queryID = ($browseType == 'bySearch') ? (int)$param : 0;
|
||||
unset($this->config->product->search['fields']['product']);
|
||||
unset($this->config->product->search['fields']['project']);
|
||||
@@ -341,6 +345,15 @@ class release extends control
|
||||
$this->config->product->search['params']['plan']['values'] = $this->loadModel('productplan')->getForProducts(array($release->product => $release->product));
|
||||
$this->config->product->search['params']['module']['values'] = $this->tree->getOptionMenu($release->product, $viewType = 'story', $startModuleID = 0);
|
||||
$this->config->product->search['params']['status'] = array('operator' => '=', 'control' => 'select', 'values' => $this->lang->story->statusList);
|
||||
if($product->type == 'normal')
|
||||
{
|
||||
unset($this->config->product->search['fields']['branch']);
|
||||
unset($this->config->product->search['params']['branch']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->config->product->search['params']['branch']['values'] = array('' => '') + $this->loadModel('branch')->getPairs($product->id, 'noempty');
|
||||
}
|
||||
$this->loadModel('search')->setSearchParams($this->config->product->search);
|
||||
|
||||
if($browseType == 'bySearch')
|
||||
|
||||
+38
-29
@@ -35,7 +35,7 @@ class story extends control
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function create($productID = 0, $moduleID = 0, $storyID = 0, $projectID = 0, $bugID = 0)
|
||||
public function create($productID = 0, $branch = 0, $moduleID = 0, $storyID = 0, $projectID = 0, $bugID = 0)
|
||||
{
|
||||
if(!empty($_POST))
|
||||
{
|
||||
@@ -77,7 +77,7 @@ class story extends control
|
||||
if($this->post->newStory)
|
||||
{
|
||||
$response['message'] = $this->lang->story->successSaved . $this->lang->story->newStory;
|
||||
$response['locate'] = $this->createLink('story', 'create', "productID=$productID&moduleID=$moduleID&story=0&projectID=$projectID&bugID=$bugID");
|
||||
$response['locate'] = $this->createLink('story', 'create', "productID=$productID&branch=$branch&moduleID=$moduleID&story=0&projectID=$projectID&bugID=$bugID");
|
||||
$this->send($response);
|
||||
}
|
||||
if($projectID == 0)
|
||||
@@ -106,7 +106,7 @@ class story extends control
|
||||
}
|
||||
|
||||
$users = $this->user->getPairs('nodeleted|pdfirst|noclosed');
|
||||
$moduleOptionMenu = $this->tree->getOptionMenu($productID, $viewType = 'story');
|
||||
$moduleOptionMenu = $this->tree->getOptionMenu($productID, $viewType = 'story', 0, $branch);
|
||||
|
||||
/* Set menu. */
|
||||
$this->product->setMenu($products, $product->id);
|
||||
@@ -158,7 +158,7 @@ class story extends control
|
||||
}
|
||||
|
||||
$this->view->title = $product->name . $this->lang->colon . $this->lang->story->create;
|
||||
$this->view->position[] = html::a($this->createLink('product', 'browse', "product=$productID"), $product->name);
|
||||
$this->view->position[] = html::a($this->createLink('product', 'browse', "product=$productID&branch=$branch"), $product->name);
|
||||
$this->view->position[] = $this->lang->story->common;
|
||||
$this->view->position[] = $this->lang->story->create;
|
||||
$this->view->products = $products;
|
||||
@@ -170,6 +170,8 @@ class story extends control
|
||||
$this->view->planID = $planID;
|
||||
$this->view->source = $source;
|
||||
$this->view->pri = $pri;
|
||||
$this->view->branch = $branch;
|
||||
$this->view->branches = $product->type != 'normal' ? $this->loadModel('branch')->getPairs($productID) : array();
|
||||
$this->view->productID = $productID;
|
||||
$this->view->product = $product;
|
||||
$this->view->projectID = $projectID;
|
||||
@@ -192,27 +194,27 @@ class story extends control
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function batchCreate($productID = 0, $moduleID = 0)
|
||||
public function batchCreate($productID = 0, $branch = 0, $moduleID = 0)
|
||||
{
|
||||
if(!empty($_POST))
|
||||
{
|
||||
$mails = $this->story->batchCreate($productID);
|
||||
$mails = $this->story->batchCreate($productID, $branch);
|
||||
if(dao::isError()) die(js::error(dao::getError()));
|
||||
|
||||
foreach($mails as $mail)
|
||||
{
|
||||
$this->sendmail($mail->storyID, $mail->actionID);
|
||||
}
|
||||
die(js::locate($this->createLink('product', 'browse', "productID=$productID"), 'parent'));
|
||||
die(js::locate($this->createLink('product', 'browse', "productID=$productID&branch=$branch"), 'parent'));
|
||||
}
|
||||
|
||||
/* Set products and module. */
|
||||
$product = $this->product->getById($productID);
|
||||
$products = $this->product->getPairs();
|
||||
$moduleOptionMenu = $this->tree->getOptionMenu($productID, $viewType = 'story');
|
||||
$moduleOptionMenu = $this->tree->getOptionMenu($productID, $viewType = 'story', 0, $branch);
|
||||
|
||||
/* Set menu. */
|
||||
$this->product->setMenu($products, $product->id);
|
||||
$this->product->setMenu($products, $product->id, $branch);
|
||||
|
||||
/* Init vars. */
|
||||
$planID = 0;
|
||||
@@ -241,13 +243,14 @@ class story extends control
|
||||
|
||||
$moduleOptionMenu['same'] = $this->lang->story->same;
|
||||
$plans = $this->loadModel('productplan')->getPairs($productID, 'unexpired');
|
||||
$plans['same'] = $this->lang->story->same;
|
||||
$priList = (array)$this->lang->story->priList;
|
||||
$priList['same'] = $this->lang->story->same;
|
||||
$plans['same'] = $this->lang->story->same;
|
||||
$priList = (array)$this->lang->story->priList;
|
||||
$priList['same'] = $this->lang->story->same;
|
||||
$branches['same'] = $this->lang->story->same;
|
||||
|
||||
$this->view->title = $product->name . $this->lang->colon . $this->lang->story->batchCreate;
|
||||
$this->view->productName = $product->name;
|
||||
$this->view->position[] = html::a($this->createLink('product', 'browse', "product=$productID"), $product->name);
|
||||
$this->view->position[] = html::a($this->createLink('product', 'browse', "product=$productID&branch=$branch"), $product->name);
|
||||
$this->view->position[] = $this->lang->story->common;
|
||||
$this->view->position[] = $this->lang->story->batchCreate;
|
||||
$this->view->products = $products;
|
||||
@@ -261,6 +264,8 @@ class story extends control
|
||||
$this->view->estimate = $estimate;
|
||||
$this->view->storyTitle = $title;
|
||||
$this->view->spec = $spec;
|
||||
$this->view->branches = $branches;
|
||||
$this->view->branch = $branch;
|
||||
|
||||
$this->display();
|
||||
}
|
||||
@@ -278,13 +283,13 @@ class story extends control
|
||||
$story = $this->story->getById($storyID);
|
||||
$product = $this->product->getById($story->product);
|
||||
$products = $this->product->getPairs();
|
||||
$moduleOptionMenu = $this->tree->getOptionMenu($product->id, $viewType = 'story');
|
||||
$moduleOptionMenu = $this->tree->getOptionMenu($product->id, $viewType = 'story', 0, $story->branch);
|
||||
|
||||
/* Set menu. */
|
||||
$this->product->setMenu($products, $product->id);
|
||||
|
||||
/* Assign. */
|
||||
$this->view->position[] = html::a($this->createLink('product', 'browse', "product=$product->id"), $product->name);
|
||||
$this->view->position[] = html::a($this->createLink('product', 'browse', "product=$product->id&branch=$story->branch"), $product->name);
|
||||
$this->view->position[] = $this->lang->story->common;
|
||||
$this->view->product = $product;
|
||||
$this->view->products = $products;
|
||||
@@ -320,11 +325,14 @@ class story extends control
|
||||
$this->commonAction($storyID);
|
||||
|
||||
/* Assign. */
|
||||
$story = $this->story->getById($storyID, 0, true);
|
||||
$story = $this->story->getById($storyID, 0, true);
|
||||
$product = $this->loadModel('product')->getById($story->product);
|
||||
$this->view->title = $this->lang->story->edit . "STORY" . $this->lang->colon . $this->view->story->title;
|
||||
$this->view->position[] = $this->lang->story->edit;
|
||||
$this->view->story = $story;
|
||||
$this->view->users = $this->user->getPairs('nodeleted|pofirst', "$story->assignedTo,$story->openedBy,$story->closedBy");
|
||||
$this->view->product = $product;
|
||||
$this->view->branches = $product->type == 'normal' ? array() : $this->loadModel('branch')->getPairs($story->product);
|
||||
$this->display();
|
||||
}
|
||||
|
||||
@@ -336,7 +344,7 @@ class story extends control
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function batchEdit($productID = 0, $projectID = 0)
|
||||
public function batchEdit($productID = 0, $projectID = 0, $branch = 0)
|
||||
{
|
||||
if($this->post->titles)
|
||||
{
|
||||
@@ -365,9 +373,9 @@ class story extends control
|
||||
/* The stories of a product. */
|
||||
if($productID)
|
||||
{
|
||||
$this->product->setMenu($this->product->getPairs('nodeleted'), $productID);
|
||||
$this->product->setMenu($this->product->getPairs('nodeleted'), $productID, $branch);
|
||||
$product = $this->product->getByID($productID);
|
||||
$this->view->position[] = html::a($this->createLink('product', 'browse', "product=$product->id"), $product->name);
|
||||
$this->view->position[] = html::a($this->createLink('product', 'browse', "product=$product->id&branch=$branch"), $product->name);
|
||||
$this->view->title = $product->name . $this->lang->colon . $this->lang->story->batchEdit;
|
||||
|
||||
}
|
||||
@@ -399,8 +407,8 @@ class story extends control
|
||||
$this->loadModel('productplan');
|
||||
foreach($stories as $story)
|
||||
{
|
||||
$moduleOptionMenus[$story->product] = $this->tree->getOptionMenu($story->product, $viewType = 'story');
|
||||
$productPlans[$story->product] = $this->productplan->getPairs($story->product);
|
||||
$moduleOptionMenus[$story->product] = $this->tree->getOptionMenu($story->product, $viewType = 'story', 0, $branch);
|
||||
$productPlans[$story->product] = $this->productplan->getPairs($story->product, $branch);
|
||||
}
|
||||
|
||||
/* Judge whether the editedStories is too large and set session. */
|
||||
@@ -507,7 +515,7 @@ class story extends control
|
||||
if(!$story) die(js::error($this->lang->notFound) . js::locate('back'));
|
||||
|
||||
$story->files = $this->loadModel('file')->getByObject('story', $storyID);
|
||||
$product = $this->dao->findById($story->product)->from(TABLE_PRODUCT)->fields('name, id')->fetch();
|
||||
$product = $this->dao->findById($story->product)->from(TABLE_PRODUCT)->fields('name, id, type')->fetch();
|
||||
$plan = $this->dao->findById($story->plan)->from(TABLE_PRODUCTPLAN)->fetch('title');
|
||||
$bugs = $this->dao->select('id,title')->from(TABLE_BUG)->where('story')->eq($storyID)->andWhere('deleted')->eq(0)->fetchAll();
|
||||
$fromBug = $this->dao->select('id,title')->from(TABLE_BUG)->where('toStory')->eq($storyID)->fetch();
|
||||
@@ -525,13 +533,14 @@ class story extends control
|
||||
}
|
||||
|
||||
$title = "STORY #$story->id $story->title - $product->name";
|
||||
$position[] = html::a($this->createLink('product', 'browse', "product=$product->id"), $product->name);
|
||||
$position[] = html::a($this->createLink('product', 'browse', "product=$product->id&branch=$story->branch"), $product->name);
|
||||
$position[] = $this->lang->story->common;
|
||||
$position[] = $this->lang->story->view;
|
||||
|
||||
$this->view->title = $title;
|
||||
$this->view->position = $position;
|
||||
$this->view->product = $product;
|
||||
$this->view->branches = $product->type == 'normal' ? array() : $this->loadModel('branch')->getPairs($product->id);
|
||||
$this->view->plan = $plan;
|
||||
$this->view->bugs = $bugs;
|
||||
$this->view->fromBug = $fromBug;
|
||||
@@ -607,7 +616,7 @@ class story extends control
|
||||
if($story->status == 'changed') unset($this->lang->story->reviewResultList['reject']);
|
||||
|
||||
$this->view->title = $this->lang->story->review . "STORY" . $this->lang->colon . $story->title;
|
||||
$this->view->position[] = html::a($this->createLink('product', 'browse', "product=$product->id"), $product->name);
|
||||
$this->view->position[] = html::a($this->createLink('product', 'browse', "product=$product->id&branch=$story->branch"), $product->name);
|
||||
$this->view->position[] = $this->lang->story->common;
|
||||
$this->view->position[] = $this->lang->story->review;
|
||||
|
||||
@@ -675,7 +684,7 @@ class story extends control
|
||||
if($story->status == 'draft') unset($this->lang->story->reasonList['cancel']);
|
||||
|
||||
$this->view->title = $this->lang->story->close . "STORY" . $this->lang->colon . $story->title;
|
||||
$this->view->position[] = html::a($this->createLink('product', 'browse', "product=$product->id"), $product->name);
|
||||
$this->view->position[] = html::a($this->createLink('product', 'browse', "product=$product->id&branch=$story->branch"), $product->name);
|
||||
$this->view->position[] = $this->lang->story->common;
|
||||
$this->view->position[] = $this->lang->story->close;
|
||||
|
||||
@@ -911,7 +920,7 @@ class story extends control
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function ajaxGetProductStories($productID, $moduleID = 0, $storyID = 0, $onlyOption = 'false', $status = '', $limit = 0)
|
||||
public function ajaxGetProductStories($productID, $branch = 0, $moduleID = 0, $storyID = 0, $onlyOption = 'false', $status = '', $limit = 0)
|
||||
{
|
||||
if($moduleID)
|
||||
{
|
||||
@@ -927,7 +936,7 @@ class story extends control
|
||||
$storyStatus = array_keys($storyStatus);
|
||||
}
|
||||
|
||||
$stories = $this->story->getProductStoryPairs($productID, $moduleID, $storyStatus, 'id_desc', $limit);
|
||||
$stories = $this->story->getProductStoryPairs($productID, $branch, $moduleID, $storyStatus, 'id_desc', $limit);
|
||||
$select = html::select('story', empty($stories) ? array('' => '') : $stories, $storyID, "class='form-control'");
|
||||
|
||||
/* If only need options, remove select wrap. */
|
||||
@@ -947,7 +956,7 @@ class story extends control
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function ajaxSearchProductStories($key, $productID, $moduleID = 0, $storyID = 0, $status = 'noclosed', $limit = 50)
|
||||
public function ajaxSearchProductStories($key, $productID, $branch = 0, $moduleID = 0, $storyID = 0, $status = 'noclosed', $limit = 50)
|
||||
{
|
||||
if($moduleID)
|
||||
{
|
||||
@@ -963,7 +972,7 @@ class story extends control
|
||||
$storyStatus = array_keys($storyStatus);
|
||||
}
|
||||
|
||||
$stories = $this->story->getProductStoryPairs($productID, $moduleID, $storyStatus, 'id_desc');
|
||||
$stories = $this->story->getProductStoryPairs($productID, $branch, $moduleID, $storyStatus, 'id_desc');
|
||||
$result = array();
|
||||
$i = 0;
|
||||
foreach ($stories as $id => $story)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#mailto {width:90.3%}
|
||||
select {border:1px solid #ccc}
|
||||
#module_chosen.chosen-container .chosen-drop {min-width: 400px; border-top: 1px solid #ddd!important}
|
||||
#branch_chosen.chosen-container .chosen-choices{width:100px;}
|
||||
|
||||
.row .col-sm-8{width:76%}
|
||||
.row .col-sm-2{padding-left:0px; padding-right:0px; width:12%}
|
||||
|
||||
@@ -2,7 +2,7 @@ $(function()
|
||||
{
|
||||
if(canCreate)
|
||||
{
|
||||
link = createLink('story', 'create', 'productID=' + productID + '&moduleID=' + moduleID);
|
||||
link = createLink('story', 'create', 'productID=' + productID + "&branch=" + branch + '&moduleID=' + moduleID);
|
||||
$('#modulemenu ul.nav li.right:first').before("<li class='right'><a href='" + link + "'><i class='icon-story-create icon-plus'></i> " + createStory + "</a></li>");
|
||||
}
|
||||
});
|
||||
|
||||
@@ -39,6 +39,7 @@ $lang->story->batchAssignTo = "批量指派";
|
||||
$lang->story->common = '需求';
|
||||
$lang->story->id = '编号';
|
||||
$lang->story->product = "所属{$lang->productCommon}";
|
||||
$lang->story->branch = "所属分支";
|
||||
$lang->story->module = '所属模块';
|
||||
$lang->story->source = '来源';
|
||||
$lang->story->fromBug = '来源Bug';
|
||||
|
||||
+26
-18
@@ -209,7 +209,7 @@ class storyModel extends model
|
||||
* @access public
|
||||
* @return int|bool the id of the created story or false when error.
|
||||
*/
|
||||
public function batchCreate($productID = 0)
|
||||
public function batchCreate($productID = 0, $branch = 0)
|
||||
{
|
||||
$now = helper::now();
|
||||
$stories = fixer::input('post')->get();
|
||||
@@ -221,14 +221,17 @@ class storyModel extends model
|
||||
$module = 0;
|
||||
$plan = 0;
|
||||
$pri = 0;
|
||||
$branch = 0;
|
||||
for($i = 0; $i < $batchNum; $i++)
|
||||
{
|
||||
$module = $stories->module[$i] == 'same' ? $module : $stories->module[$i];
|
||||
$plan = $stories->plan[$i] == 'same' ? $plan : $stories->plan[$i];
|
||||
$pri = $stories->pri[$i] == 'same' ? $pri : $stories->pri[$i];
|
||||
$branch = $stories->pri[$i] == 'same' ? $branch : $stories->branch[$i];
|
||||
$stories->module[$i] = (int)$module;
|
||||
$stories->plan[$i] = (int)$plan;
|
||||
$stories->pri[$i] = (int)$pri;
|
||||
$stories->branch[$i] = (int)$branch;
|
||||
}
|
||||
|
||||
if(isset($stories->uploadImage)) $this->loadModel('file');
|
||||
@@ -241,9 +244,11 @@ class storyModel extends model
|
||||
$data->plan = $stories->plan[$i];
|
||||
$data->title = $stories->title[$i];
|
||||
$data->pri = $stories->pri[$i] != '' ? $stories->pri[$i] : 0;
|
||||
$data->branch = $stories->branch[$i];
|
||||
$data->estimate = $stories->estimate[$i] != '' ? $stories->estimate[$i] : 0;
|
||||
$data->status = $stories->needReview[$i] == 0 ? 'active' : 'draft';
|
||||
$data->product = $productID;
|
||||
$data->branch = $branch;
|
||||
$data->openedBy = $this->app->user->account;
|
||||
$data->openedDate = $now;
|
||||
$data->version = 1;
|
||||
@@ -926,14 +931,15 @@ class storyModel extends model
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getProductStories($productID = 0, $moduleIds = 0, $status = 'all', $orderBy = 'id_desc', $pager = null)
|
||||
public function getProductStories($productID = 0, $branch = 0, $moduleIds = 0, $status = 'all', $orderBy = 'id_desc', $pager = null)
|
||||
{
|
||||
return $this->dao->select('t1.*, t2.title as planTitle')
|
||||
->from(TABLE_STORY)->alias('t1')
|
||||
->leftJoin(TABLE_PRODUCTPLAN)->alias('t2')->on('t1.plan = t2.id')
|
||||
->where('t1.product')->in($productID)
|
||||
->beginIF(!empty($moduleIds))->andWhere('module')->in($moduleIds)->fi()
|
||||
->beginIF($status and $status != 'all')->andWhere('status')->in($status)->fi()
|
||||
->beginIF(!empty($branch))->andWhere("t1.branch")->eq($branch)->fi()
|
||||
->beginIF(!empty($moduleIds))->andWhere('t1.module')->in($moduleIds)->fi()
|
||||
->beginIF($status and $status != 'all')->andWhere('t1.status')->in($status)->fi()
|
||||
->andWhere('t1.deleted')->eq(0)
|
||||
->orderBy($orderBy)->page($pager)->fetchAll();
|
||||
}
|
||||
@@ -949,13 +955,14 @@ class storyModel extends model
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getProductStoryPairs($productID = 0, $moduleIds = 0, $status = 'all', $order = 'id_desc', $limit = 0)
|
||||
public function getProductStoryPairs($productID = 0, $branch = 0, $moduleIds = 0, $status = 'all', $order = 'id_desc', $limit = 0)
|
||||
{
|
||||
$stories = $this->dao->select('t1.id, t1.title, t1.module, t1.pri, t1.estimate, t2.name AS product')
|
||||
->from(TABLE_STORY)->alias('t1')->leftJoin(TABLE_PRODUCT)->alias('t2')->on('t1.product = t2.id')
|
||||
->where('1=1')
|
||||
->beginIF($productID)->andWhere('t1.product')->in($productID)->fi()
|
||||
->beginIF($moduleIds)->andWhere('t1.module')->in($moduleIds)->fi()
|
||||
->beginIF($branch)->andWhere('t1.branch')->eq($branch)->fi()
|
||||
->beginIF($status and $status != 'all')->andWhere('t1.status')->in($status)->fi()
|
||||
->andWhere('t1.deleted')->eq(0)
|
||||
->orderBy($order)
|
||||
@@ -974,9 +981,9 @@ class storyModel extends model
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getByAssignedTo($productID, $account, $orderBy, $pager)
|
||||
public function getByAssignedTo($productID, $branch, $account, $orderBy, $pager)
|
||||
{
|
||||
return $this->getByField($productID, 'assignedTo', $account, $orderBy, $pager);
|
||||
return $this->getByField($productID, $branch, 'assignedTo', $account, $orderBy, $pager);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -989,9 +996,9 @@ class storyModel extends model
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getByOpenedBy($productID, $account, $orderBy, $pager)
|
||||
public function getByOpenedBy($productID, $branch, $account, $orderBy, $pager)
|
||||
{
|
||||
return $this->getByField($productID, 'openedBy', $account, $orderBy, $pager);
|
||||
return $this->getByField($productID, $branch, 'openedBy', $account, $orderBy, $pager);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1004,9 +1011,9 @@ class storyModel extends model
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getByReviewedBy($productID, $account, $orderBy, $pager)
|
||||
public function getByReviewedBy($productID, $branch, $account, $orderBy, $pager)
|
||||
{
|
||||
return $this->getByField($productID, 'reviewedBy', $account, $orderBy, $pager, 'include');
|
||||
return $this->getByField($productID, $branch, 'reviewedBy', $account, $orderBy, $pager, 'include');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1018,9 +1025,9 @@ class storyModel extends model
|
||||
* @param object $pager
|
||||
* @return array
|
||||
*/
|
||||
public function getByClosedBy($productID, $account, $orderBy, $pager)
|
||||
public function getByClosedBy($productID, $branch, $account, $orderBy, $pager)
|
||||
{
|
||||
return $this->getByField($productID, 'closedBy', $account, $orderBy, $pager);
|
||||
return $this->getByField($productID, $branch, 'closedBy', $account, $orderBy, $pager);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1033,9 +1040,9 @@ class storyModel extends model
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getByStatus($productID, $status, $orderBy, $pager)
|
||||
public function getByStatus($productID, $branch, $status, $orderBy, $pager)
|
||||
{
|
||||
return $this->getByField($productID, 'status', $status, $orderBy, $pager);
|
||||
return $this->getByField($productID, $branch, 'status', $status, $orderBy, $pager);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1050,13 +1057,14 @@ class storyModel extends model
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getByField($productID, $fieldName, $fieldValue, $orderBy, $pager, $operator = 'equal')
|
||||
public function getByField($productID, $branch, $fieldName, $fieldValue, $orderBy, $pager, $operator = 'equal')
|
||||
{
|
||||
return $this->dao->select('t1.*, t2.title as planTitle')
|
||||
->from(TABLE_STORY)->alias('t1')
|
||||
->leftJoin(TABLE_PRODUCTPLAN)->alias('t2')->on('t1.plan = t2.id')
|
||||
->where('t1.product')->in($productID)
|
||||
->andWhere('t1.deleted')->eq(0)
|
||||
->beginIF(!empty($branch))->andWhere("CONCAT(',', t1.branch, ',')")->like("%,$branch,%")->fi()
|
||||
->beginIF($operator == 'equal')->andWhere($fieldName)->eq($fieldValue)->fi()
|
||||
->beginIF($operator == 'include')->andWhere($fieldName)->like("%$fieldValue%")->fi()
|
||||
->orderBy($orderBy)
|
||||
@@ -1073,7 +1081,7 @@ class storyModel extends model
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getWillClose($productID, $orderBy, $pager)
|
||||
public function getWillClose($productID, $branch, $orderBy, $pager)
|
||||
{
|
||||
return $this->dao->select('t1.*, t2.title as planTitle')
|
||||
->from(TABLE_STORY)->alias('t1')
|
||||
@@ -1367,7 +1375,7 @@ class storyModel extends model
|
||||
*/
|
||||
public function getZeroCase($productID, $orderBy = 'id_desc')
|
||||
{
|
||||
$allStories = $this->getProductStories($productID, 0, 'all', $orderBy);
|
||||
$allStories = $this->getProductStories($productID, 0, 0, 'all', $orderBy);
|
||||
$casedStories = $this->dao->select('DISTINCT story')->from(TABLE_CASE)->where('product')->eq($productID)->andWhere('story')->ne(0)->andWhere('deleted')->eq(0)->fetchAll('story');
|
||||
|
||||
foreach($allStories as $key => $story)
|
||||
|
||||
@@ -25,7 +25,10 @@
|
||||
<tr>
|
||||
<th class='w-80px'><?php echo $lang->story->product;?></th>
|
||||
<td class='w-p25-f'>
|
||||
<?php echo html::select('product', $products, $productID, "onchange='loadProduct(this.value);' class='form-control chosen'");?>
|
||||
<div class='input-group'>
|
||||
<?php echo html::select('product', $products, $productID, "onchange='loadProduct(this.value);' class='form-control chosen'");?>
|
||||
<?php if($product->type != 'normal') echo html::select('branch', $branches, $branch, "onchange='loadBranch();' class='form-control' style='width:65px'");?>
|
||||
</div>
|
||||
</td>
|
||||
<td class='w-p25-f'>
|
||||
<div class='input-group' id='moduleIdBox'>
|
||||
@@ -53,7 +56,7 @@
|
||||
if(count($plans) == 1)
|
||||
{
|
||||
echo "<span class='input-group-addon'>";
|
||||
echo html::a($this->createLink('productplan', 'create', "productID=$productID"), $lang->productplan->create, '_blank');
|
||||
echo html::a($this->createLink('productplan', 'create', "productID=$productID&branch=$branch"), $lang->productplan->create, '_blank');
|
||||
echo ' ';
|
||||
echo html::a("javascript:loadProductPlans($productID)", $lang->refresh);
|
||||
echo '</span>';
|
||||
|
||||
@@ -55,7 +55,12 @@
|
||||
<table class='table table-form'>
|
||||
<tr>
|
||||
<th class='w-80px'><?php echo $lang->story->product;?></th>
|
||||
<td><?php echo html::select('product', $products, $story->product, 'class="form-control chosen" onchange="loadProduct(this.value)";');?></td>
|
||||
<td>
|
||||
<div class='input-group'>
|
||||
<?php echo html::select('product', $products, $story->product, "onchange='loadProduct(this.value);' class='form-control chosen'");?>
|
||||
<?php if($product->type != 'normal') echo html::select('branch', $branches, $story->branch, "onchange='loadBranch();' class='form-control' style='width:65px'");?>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->story->module;?></th>
|
||||
@@ -82,7 +87,7 @@
|
||||
if(count($plans) == 1)
|
||||
{
|
||||
echo "<span class='input-group-addon'>";
|
||||
echo html::a($this->createLink('productplan', 'create', "productID=$story->product"), $lang->productplan->create, '_blank');
|
||||
echo html::a($this->createLink('productplan', 'create', "productID=$story->product&branch=$story->branch"), $lang->productplan->create, '_blank');
|
||||
echo html::a("javascript:loadProductPlans($story->product)", $lang->refresh);
|
||||
echo '</span>';
|
||||
}
|
||||
|
||||
@@ -3,13 +3,37 @@
|
||||
<script language='Javascript'>
|
||||
function loadProduct(productID)
|
||||
{
|
||||
loadProductBranches(productID)
|
||||
loadProductModules(productID);
|
||||
loadProductPlans(productID);
|
||||
}
|
||||
|
||||
function loadProductModules(productID)
|
||||
function loadBranch()
|
||||
{
|
||||
moduleLink = createLink('tree', 'ajaxGetOptionMenu', 'productID=' + productID + '&viewtype=story&rootModuleID=0&returnType=html&needManage=true');
|
||||
var branch = $('#branch').val();
|
||||
if(typeof(branch) == 'undefined') branch = 0;
|
||||
loadProductModules($('#product').val(), branch);
|
||||
loadProductPlans($('#product').val(), branch);
|
||||
}
|
||||
|
||||
function loadProductBranches(productID)
|
||||
{
|
||||
$('#branch').remove();
|
||||
$.get(createLink('branch', 'ajaxGetBranches', "productID=" + productID), function(data)
|
||||
{
|
||||
if(data)
|
||||
{
|
||||
$('#product').closest('.input-group').append(data);
|
||||
$('#branch').css('width', '65px');
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function loadProductModules(productID, branch)
|
||||
{
|
||||
if(typeof(branch) == 'undefined') branch = 0;
|
||||
if(!branch) branch = 0;
|
||||
moduleLink = createLink('tree', 'ajaxGetOptionMenu', 'productID=' + productID + '&viewtype=story&branch=' + branch + '&rootModuleID=0&returnType=html&needManage=true');
|
||||
$('#moduleIdBox').load(moduleLink, function()
|
||||
{
|
||||
$('#moduleIdBox #module').chosen(defaultChosenOptions);
|
||||
@@ -17,9 +41,11 @@ function loadProductModules(productID)
|
||||
});
|
||||
}
|
||||
|
||||
function loadProductPlans(productID)
|
||||
function loadProductPlans(productID, branch)
|
||||
{
|
||||
planLink = createLink('product', 'ajaxGetPlans', 'productID=' + productID + '&planID=' + $('#plan').val() + '&needCreate=true');
|
||||
if(typeof(branch) == 'undefined') branch = 0;
|
||||
if(!branch) branch = 0;
|
||||
planLink = createLink('product', 'ajaxGetPlans', 'productID=' + productID + '&branch=' + branch + '&planID=' + $('#plan').val() + '&needCreate=true');
|
||||
$('#planIdBox').load(planLink, function(){$('#planIdBox #plan').chosen(defaultChosenOptions);});
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
</div>
|
||||
<div class='actions'>
|
||||
<?php
|
||||
$browseLink = $app->session->storyList != false ? $app->session->storyList : $this->createLink('product', 'browse', "productID=$story->product&moduleID=$story->module");
|
||||
$browseLink = $app->session->storyList != false ? $app->session->storyList : $this->createLink('product', 'browse', "productID=$story->product&branch=$story->branch&moduleID=$story->module");
|
||||
$actionLinks = '';
|
||||
|
||||
if(!$story->deleted)
|
||||
@@ -45,14 +45,14 @@
|
||||
common::printIcon('story', 'review', "storyID=$story->id", $story);
|
||||
common::printIcon('story', 'close', "storyID=$story->id", $story, 'button', '', '', 'iframe text-danger', true);
|
||||
common::printIcon('story', 'activate', "storyID=$story->id", $story, 'button', '', '', 'iframe text-success', true);
|
||||
common::printIcon('story', 'createCase', "productID=$story->product&moduleID=0&from=¶m=0&storyID=$story->id", '', 'button', 'sitemap');
|
||||
common::printIcon('story', 'createCase', "productID=$story->product&branch=$story->branch&moduleID=0&from=¶m=0&storyID=$story->id", '', 'button', 'sitemap');
|
||||
if($from == 'project') common::printIcon('task', 'create', "project=$param&storyID=$story->id", '', 'button', 'smile');
|
||||
echo '</div>';
|
||||
|
||||
echo "<div class='btn-group'>";
|
||||
common::printIcon('story', 'edit', "storyID=$story->id");
|
||||
common::printCommentIcon('story');
|
||||
common::printIcon('story', 'create', "productID=$story->product&moduleID=$story->module&storyID=$story->id", '', 'button', 'copy');
|
||||
common::printIcon('story', 'create', "productID=$story->product&branch=$story->branch&moduleID=$story->module&storyID=$story->id", '', 'button', 'copy');
|
||||
common::printIcon('story', 'delete', "storyID=$story->id", '', 'button', '', 'hiddenwin');
|
||||
echo '</div>';
|
||||
|
||||
@@ -111,6 +111,12 @@
|
||||
<th class='w-70px'><?php echo $lang->story->product;?></th>
|
||||
<td><?php common::printLink('product', 'view', "productID=$story->product", $product->name);?></td>
|
||||
</tr>
|
||||
<?php if($product->type != 'normal'):?>
|
||||
<tr>
|
||||
<th><?php echo $lang->story->branch;?></th>
|
||||
<td><?php common::printLink('product', 'browse', "productID=$story->product&branch=$story->branch", $branches[$story->branch]);?></td>
|
||||
</tr>
|
||||
<?php endif;?>
|
||||
<tr>
|
||||
<th><?php echo $lang->story->module;?></th>
|
||||
<?php
|
||||
@@ -126,7 +132,7 @@
|
||||
foreach($modulePath as $key => $module)
|
||||
{
|
||||
$moduleTitle .= $module->name;
|
||||
if(!common::printLink('product', 'browse', "productID=$story->product&browseType=byModule¶m=$module->id", $module->name)) echo $module->name;
|
||||
if(!common::printLink('product', 'browse', "productID=$story->product&branch=$story->branch&browseType=byModule¶m=$module->id", $module->name)) echo $module->name;
|
||||
if(isset($modulePath[$key + 1]))
|
||||
{
|
||||
$moduleTitle .= '/';
|
||||
@@ -300,6 +306,7 @@
|
||||
js::set('canCreate', common::hasPriv('story', 'story'));
|
||||
js::set('createStory', $lang->story->create);
|
||||
js::set('productID', $story->product);
|
||||
js::set('branch', $story->branch);
|
||||
js::set('moduleID', $story->module);
|
||||
?>
|
||||
<?php include '../../common/view/syntaxhighlighter.html.php';?>
|
||||
|
||||
@@ -219,7 +219,7 @@ class testcase extends control
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function create($productID, $moduleID = 0, $from = '', $param = 0, $storyID = 0)
|
||||
public function create($productID, $branch = 0, $moduleID = 0, $from = '', $param = 0, $storyID = 0)
|
||||
{
|
||||
$testcaseID = $from == 'testcase' ? $param : 0;
|
||||
$bugID = $from == 'bug' ? $param : 0;
|
||||
@@ -325,7 +325,7 @@ class testcase extends control
|
||||
$modules = $this->loadModel('tree')->getStoryModule($currentModuleID);
|
||||
$modules = $this->tree->getAllChildID($modules);
|
||||
}
|
||||
$stories = $this->story->getProductStoryPairs($productID, $modules, array_keys($storyStatus), 'id_desc', 50);
|
||||
$stories = $this->story->getProductStoryPairs($productID, $branch, $modules, array_keys($storyStatus), 'id_desc', 50);
|
||||
|
||||
$this->view->title = $title;
|
||||
$this->view->caseTitle = $caseTitle;
|
||||
@@ -357,7 +357,7 @@ class testcase extends control
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function batchCreate($productID, $moduleID = 0, $storyID = 0)
|
||||
public function batchCreate($productID, $branch = 0, $moduleID = 0, $storyID = 0)
|
||||
{
|
||||
$this->loadModel('story');
|
||||
if(!empty($_POST))
|
||||
@@ -398,10 +398,11 @@ class testcase extends control
|
||||
$this->view->story = $story;
|
||||
$this->view->storyList = $storyList;
|
||||
$this->view->productName = $this->products[$productID];
|
||||
$this->view->moduleOptionMenu = $this->tree->getOptionMenu($productID, $viewType = 'case', $startModuleID = 0);
|
||||
$this->view->moduleOptionMenu = $this->tree->getOptionMenu($productID, $viewType = 'case', $startModuleID = 0, $branch);
|
||||
$this->view->currentModuleID = $currentModuleID;
|
||||
$this->view->type = $type;
|
||||
$this->view->title = $title;
|
||||
$this->view->branch = $branch;
|
||||
|
||||
$this->display();
|
||||
}
|
||||
@@ -538,7 +539,7 @@ class testcase extends control
|
||||
$this->view->moduleOptionMenu = $this->tree->getOptionMenu($productID, $viewType = 'case', $startModuleID = 0);
|
||||
$this->view->currentModuleID = $currentModuleID;
|
||||
$this->view->users = $this->user->getPairs('noletter');
|
||||
$this->view->stories = $this->story->getProductStoryPairs($productID);
|
||||
$this->view->stories = $this->story->getProductStoryPairs($productID, $case->branch);
|
||||
$this->view->case = $case;
|
||||
$this->view->actions = $this->loadModel('action')->getList('case', $caseID);
|
||||
|
||||
@@ -969,7 +970,7 @@ class testcase extends control
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function showImport($productID)
|
||||
public function showImport($productID, $branch = 0)
|
||||
{
|
||||
if($_POST)
|
||||
{
|
||||
@@ -977,13 +978,13 @@ class testcase extends control
|
||||
die(js::locate(inlink('browse', "productID=$productID"), 'parent'));
|
||||
}
|
||||
|
||||
$this->testcase->setMenu($this->products, $productID);
|
||||
$this->testcase->setMenu($this->products, $productID, $branch);
|
||||
|
||||
$file = $this->session->importFile;
|
||||
$caseLang = $this->lang->testcase;
|
||||
$caseConfig = $this->config->testcase;
|
||||
$modules = $this->loadModel('tree')->getOptionMenu($productID, 'case');
|
||||
$stories = $this->loadModel('story')->getProductStoryPairs($productID);
|
||||
$modules = $this->loadModel('tree')->getOptionMenu($productID, 'case', 0, $branch);
|
||||
$stories = $this->loadModel('story')->getProductStoryPairs($productID, $branch);
|
||||
$fields = $this->testcase->getImportFields();
|
||||
|
||||
$rows = $this->loadModel('file')->parseCSV($file);
|
||||
|
||||
@@ -5,11 +5,6 @@ $(document).ready(function()
|
||||
var select = $(this).prev('select');
|
||||
var id = $(select).attr('id');
|
||||
if(id.indexOf('story') != -1)
|
||||
{
|
||||
index = id.substring(5);
|
||||
module = $('#module' + index).val();
|
||||
if(module == 'same')
|
||||
{
|
||||
for(var i = index - 1; i >=0; i--)
|
||||
{
|
||||
if($('#module' + i).val() != 'same')
|
||||
@@ -19,7 +14,7 @@ $(document).ready(function()
|
||||
}
|
||||
}
|
||||
}
|
||||
link = createLink('story', 'ajaxGetProductStories', 'productID=' + productID + '&moduleID=' + module + '&storyID='+ $(select).val() + '&onlyOption=true&status=noclosed');
|
||||
link = createLink('story', 'ajaxGetProductStories', 'productID=' + productID + '&branch=' + branch + '&moduleID=' + module + '&storyID='+ $(select).val() + '&onlyOption=true&status=noclosed');
|
||||
$('#story' + index).load(link, function(){$(this).trigger("chosen:updated");});
|
||||
}
|
||||
if($(select).val() == 'same')
|
||||
|
||||
@@ -47,7 +47,9 @@ function setStories()
|
||||
{
|
||||
moduleID = $('#module').val();
|
||||
productID = $('#product').val();
|
||||
link = createLink('story', 'ajaxGetProductStories', 'productID=' + productID + '&moduleID=' + moduleID + '&storyID=0&onlyOption=false&status=noclosed&limit=50');
|
||||
branch = $('#branch').val();
|
||||
if(typeof(branch) == 'undefined') branch = 0;
|
||||
link = createLink('story', 'ajaxGetProductStories', 'productID=' + productID + '&branch=' + branch + '&moduleID=' + moduleID + '&storyID=0&onlyOption=false&status=noclosed&limit=50');
|
||||
$.get(link, function(stories)
|
||||
{
|
||||
var value = $('#story').val();
|
||||
|
||||
@@ -97,7 +97,9 @@ $(function()
|
||||
if(key && key != $searchInput.data('lastkey'))
|
||||
{
|
||||
$searchResult.empty().append('<li class="loading"><i class="icon-spin icon-spinner icon-2x"></i></li>');
|
||||
var link = createLink('story', 'ajaxSearchProductStories', 'key=' + key + '&productID=' + $('#product').val() + '&moduleID=' + $('#module').val() + '&storyID=0&status=noclosed&limit=50');
|
||||
var branch = $('#branch').val();
|
||||
if(typeof(branch) == 'undefined') branch = 0;
|
||||
var link = createLink('story', 'ajaxSearchProductStories', 'key=' + key + '&productID=' + $('#product').val() + '&branch=' + branch + '&moduleID=' + $('#module').val() + '&storyID=0&status=noclosed&limit=50');
|
||||
$.getJSON(link, function(result)
|
||||
{
|
||||
$searchResult.empty();
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
<?php include '../../common/view/header.html.php';?>
|
||||
<?php js::set('testcaseBatchCreateNum', $config->testcase->batchCreate);?>
|
||||
<?php js::set('productID', $productID);?>
|
||||
<?php js::set('branch', $branch);?>
|
||||
<div id='titlebar'>
|
||||
<div class='heading'>
|
||||
<span class='prefix'><?php echo html::icon($lang->icons['testcase']);?></span>
|
||||
|
||||
+11
-9
@@ -11,7 +11,7 @@
|
||||
*/
|
||||
class tree extends control
|
||||
{
|
||||
const NEW_CHILD_COUNT = 10;
|
||||
const NEW_CHILD_COUNT = 5;
|
||||
|
||||
/**
|
||||
* Module browse.
|
||||
@@ -22,12 +22,13 @@ class tree extends control
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function browse($rootID, $viewType, $currentModuleID = 0)
|
||||
public function browse($rootID, $viewType, $currentModuleID = 0, $branch = 0)
|
||||
{
|
||||
/* According to the type, set the module root and modules. */
|
||||
if(strpos('story|bug|case', $viewType) !== false)
|
||||
{
|
||||
$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');
|
||||
}
|
||||
@@ -64,7 +65,6 @@ 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);
|
||||
@@ -110,9 +110,10 @@ class tree extends control
|
||||
$this->view->rootID = $rootID;
|
||||
$this->view->viewType = $viewType;
|
||||
$this->view->modules = $this->tree->getTreeMenu($rootID, $viewType, $rooteModuleID = 0, array('treeModel', 'createManageLink'));
|
||||
$this->view->sons = $this->tree->getSons($rootID, $currentModuleID, $viewType);
|
||||
$this->view->sons = $this->tree->getSons($rootID, $currentModuleID, $viewType, $branch);
|
||||
$this->view->currentModuleID = $currentModuleID;
|
||||
$this->view->parentModules = $parentModules;
|
||||
$this->view->branch = $branch;
|
||||
$this->display();
|
||||
}
|
||||
|
||||
@@ -170,7 +171,7 @@ class tree extends control
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function edit($moduleID, $type)
|
||||
public function edit($moduleID, $type, $branch = 0)
|
||||
{
|
||||
if(!empty($_POST))
|
||||
{
|
||||
@@ -192,11 +193,12 @@ class tree extends control
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->view->optionMenu = $this->tree->getOptionMenu($module->root, $module->type);
|
||||
$this->view->optionMenu = $this->tree->getOptionMenu($module->root, $module->type, 0, $branch);
|
||||
}
|
||||
|
||||
$this->view->module = $module;
|
||||
$this->view->type = $type;
|
||||
$this->view->branch = $branch;
|
||||
$this->view->users = $this->loadModel('user')->getPairs('noclosed|nodeleted', $module->owner);
|
||||
|
||||
$showProduct = strpos('story|bug|case', $type) !== false ? true : false;
|
||||
@@ -291,7 +293,7 @@ class tree extends control
|
||||
* @access public
|
||||
* @return string the html select string.
|
||||
*/
|
||||
public function ajaxGetOptionMenu($rootID, $viewType = 'story', $rootModuleID = 0, $returnType = 'html', $needManage = false)
|
||||
public function ajaxGetOptionMenu($rootID, $viewType = 'story', $branch = 0, $rootModuleID = 0, $returnType = 'html', $needManage = false)
|
||||
{
|
||||
if($viewType == 'task')
|
||||
{
|
||||
@@ -299,7 +301,7 @@ class tree extends control
|
||||
}
|
||||
else
|
||||
{
|
||||
$optionMenu = $this->tree->getOptionMenu($rootID, $viewType, $rootModuleID);
|
||||
$optionMenu = $this->tree->getOptionMenu($rootID, $viewType, $rootModuleID, $branch);
|
||||
}
|
||||
if($returnType == 'html')
|
||||
{
|
||||
@@ -309,7 +311,7 @@ class tree extends control
|
||||
if(count($optionMenu) == 1 and $needManage)
|
||||
{
|
||||
$output .= "<span class='input-group-addon'>";
|
||||
$output .= html::a($this->createLink('tree', 'browse', "rootID=$rootID&view=$viewType"), $this->lang->tree->manage, '_blank');
|
||||
$output .= html::a($this->createLink('tree', 'browse', "rootID=$rootID&view=$viewType¤tModuleID=0&branch=$branch"), $this->lang->tree->manage, '_blank');
|
||||
$output .= ' ';
|
||||
$output .= html::a("javascript:loadProductModules($rootID)", $this->lang->refresh);
|
||||
$output .= '</span>';
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
.outer .row .col-md-8 .table-form {max-width: 600px}
|
||||
|
||||
#sonModule {max-width: 240px}
|
||||
#sonModule {max-width: 330px}
|
||||
#moduleBox span > .form-control {margin-bottom: 5px;}
|
||||
|
||||
.w-260px {width: 260px!important}
|
||||
|
||||
@@ -7,8 +7,9 @@ function syncModule(rootID, type)
|
||||
$.getJSON(link, function(modules)
|
||||
{
|
||||
$('.helplink').addClass('hidden');
|
||||
var $inputgroup = $('<div></div>').append($('.input-group .icon-remove:first').closest('.input-group').clone()).html();
|
||||
$.each(modules, function(key, value)
|
||||
{
|
||||
{
|
||||
moduleName = value;
|
||||
$('.form-control').each(function()
|
||||
{
|
||||
@@ -18,8 +19,12 @@ function syncModule(rootID, type)
|
||||
});
|
||||
|
||||
$.each(modules, function(key, value)
|
||||
{
|
||||
if(value) $('#sonModule').append("<span><input type='text' name='modules[]' value='" + value + "' style='margin-bottom:5px' class='form-control' /><span>");
|
||||
{
|
||||
if(value)
|
||||
{
|
||||
$('#sonModule .input-group:last').after($inputgroup);
|
||||
$('#sonModule .input-group:last input').val(value);
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -28,7 +33,7 @@ function syncProductOrProject(obj, type)
|
||||
{
|
||||
if(type == 'product') viewType = 'story';
|
||||
if(type == 'project') viewType = 'task';
|
||||
link = createLink('tree', 'ajaxGetOptionMenu', 'rootID=' + obj.value + "&viewType=" + viewType + "&rootModuleID=0&returnType=json");
|
||||
link = createLink('tree', 'ajaxGetOptionMenu', 'rootID=' + obj.value + "&viewType=" + viewType + "&branch=0&rootModuleID=0&returnType=json");
|
||||
$.getJSON(link, function(modules)
|
||||
{
|
||||
$('.helplink').addClass('hidden');
|
||||
@@ -50,6 +55,18 @@ function toggleCopy()
|
||||
$copy.toggle();
|
||||
}
|
||||
|
||||
function addItem(obj)
|
||||
{
|
||||
var $inputgroup = $(obj).closest('.input-group');
|
||||
$inputgroup.after($inputgroup.clone()).next('.input-group').find('input').val('');
|
||||
}
|
||||
|
||||
function deleteItem(obj)
|
||||
{
|
||||
if($(obj).closest('.input-group').parent().find('i.icon-remove').size() <= 1) return;
|
||||
$(obj).closest('.input-group').remove();
|
||||
}
|
||||
|
||||
$(document).ready(function()
|
||||
{
|
||||
toggleCopy();
|
||||
|
||||
+186
-197
@@ -34,7 +34,7 @@ class treeModel extends model
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function buildMenuQuery($rootID, $type, $startModule)
|
||||
public function buildMenuQuery($rootID, $type, $startModule, $branch = 0)
|
||||
{
|
||||
/* Set the start module. */
|
||||
$startModulePath = '';
|
||||
@@ -57,6 +57,8 @@ class treeModel extends model
|
||||
->where('root')->eq((int)$rootID)
|
||||
->andWhere('type')->in("story,$type")
|
||||
->beginIF($startModulePath)->andWhere('path')->like($startModulePath)->fi()
|
||||
->beginIF($branch === 'null')->andWhere('branch')->eq(0)->fi()
|
||||
->beginIF((!empty($branch) and $branch != 'null'))->andWhere("branch")->eq($branch)->fi()
|
||||
->orderBy('grade desc, type desc, `order`')
|
||||
->get();
|
||||
}
|
||||
@@ -67,6 +69,8 @@ class treeModel extends model
|
||||
->where('root')->eq((int)$rootID)
|
||||
->andWhere('type')->eq($type)
|
||||
->beginIF($startModulePath)->andWhere('path')->like($startModulePath)->fi()
|
||||
->beginIF($branch === 'null')->andWhere('branch')->eq(0)->fi()
|
||||
->beginIF((!empty($branch) and $branch != 'null'))->andWhere("branch")->eq($branch)->fi()
|
||||
->orderBy('grade desc, `order`')
|
||||
->get();
|
||||
}
|
||||
@@ -80,51 +84,36 @@ class treeModel extends model
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getOptionMenu($rootID, $type = 'story', $startModule = 0)
|
||||
public function getOptionMenu($rootID, $type = 'story', $startModule = 0, $branch = 0)
|
||||
{
|
||||
$treeMenu = array();
|
||||
$stmt = $this->dbh->query($this->buildMenuQuery($rootID, $type, $startModule));
|
||||
$modules = array();
|
||||
while($module = $stmt->fetch()) $modules[$module->id] = $module;
|
||||
|
||||
foreach($modules as $module)
|
||||
$branches = array($branch => '');
|
||||
if(strpos('story|bug|case', $type) !== false)
|
||||
{
|
||||
$parentModules = explode(',', $module->path);
|
||||
$moduleName = '/';
|
||||
foreach($parentModules as $parentModuleID)
|
||||
$product = $this->loadModel('product')->getById($rootID);
|
||||
if($product->type != 'normal')
|
||||
{
|
||||
if(empty($parentModuleID)) continue;
|
||||
$moduleName .= $modules[$parentModuleID]->name . '/';
|
||||
}
|
||||
$moduleName = rtrim($moduleName, '/');
|
||||
$moduleName .= "|$module->id\n";
|
||||
|
||||
if(isset($treeMenu[$module->id]) and !empty($treeMenu[$module->id]))
|
||||
{
|
||||
if(isset($treeMenu[$module->parent]))
|
||||
$branches = array('null' => '') + $this->loadModel('branch')->getPairs($rootID, 'noempty');
|
||||
if($branch)
|
||||
{
|
||||
$treeMenu[$module->parent] .= $moduleName;
|
||||
$newBranches['null'] = '';
|
||||
$newBranches[$branch] = $branches[$branch];
|
||||
$branches = $newBranches;
|
||||
}
|
||||
else
|
||||
{
|
||||
$treeMenu[$module->parent] = $moduleName;;
|
||||
}
|
||||
$treeMenu[$module->parent] .= $treeMenu[$module->id];
|
||||
}
|
||||
else
|
||||
{
|
||||
if(isset($treeMenu[$module->parent]) and !empty($treeMenu[$module->parent]))
|
||||
{
|
||||
$treeMenu[$module->parent] .= $moduleName;
|
||||
}
|
||||
else
|
||||
{
|
||||
$treeMenu[$module->parent] = $moduleName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$topMenu = @array_pop($treeMenu);
|
||||
$treeMenu = array();
|
||||
foreach($branches as $branchID => $branch)
|
||||
{
|
||||
$stmt = $this->dbh->query($this->buildMenuQuery($rootID, $type, $startModule, $branchID));
|
||||
$modules = array();
|
||||
while($module = $stmt->fetch()) $modules[$module->id] = $module;
|
||||
|
||||
foreach($modules as $module) $this->buildTreeArray($treeMenu, $modules, $module, (empty($branch) or $branch == 'null') ? '/' : "/$branch/");
|
||||
}
|
||||
|
||||
ksort($treeMenu);
|
||||
$topMenu = @array_shift($treeMenu);
|
||||
$topMenu = explode("\n", trim($topMenu));
|
||||
$lastMenu[] = '/';
|
||||
foreach($topMenu as $menu)
|
||||
@@ -133,6 +122,7 @@ class treeModel extends model
|
||||
list($label, $moduleID) = explode('|', $menu);
|
||||
$lastMenu[$moduleID] = $label;
|
||||
}
|
||||
|
||||
return $lastMenu;
|
||||
}
|
||||
|
||||
@@ -171,22 +161,21 @@ class treeModel extends model
|
||||
$noProductModules = $this->dao->select('*')->from(TABLE_MODULE)->where("root = $rootID and type = 'task' and parent = 0")->fetchPairs('id', 'name');
|
||||
|
||||
/* Fix for not in product modules. */
|
||||
$productNum = count($products);
|
||||
foreach(array('product' => $products, 'noProduct' => $noProductModules) as $type => $rootModules)
|
||||
{
|
||||
foreach($rootModules as $id => $rootModule)
|
||||
{
|
||||
if($type == 'product')
|
||||
{
|
||||
$modules = $this->dao->select('*')->from(TABLE_MODULE)
|
||||
->where("((root = $rootID and type = 'task') OR (root = $id and type = 'story'))")
|
||||
$modules = $this->dao->select('*')->from(TABLE_MODULE)->where("((root = $rootID and type = 'task') OR (root = $id and type = 'story'))")
|
||||
->beginIF($startModulePath)->andWhere('path')->like($startModulePath)->fi()
|
||||
->orderBy('grade desc, type, `order`')
|
||||
->fetchAll('id');
|
||||
}
|
||||
else
|
||||
{
|
||||
$modules = $this->dao->select('*')->from(TABLE_MODULE)
|
||||
->where("root = $rootID and type = 'task' and path like '%,$id,%'")
|
||||
$modules = $this->dao->select('*')->from(TABLE_MODULE)->where("root = $rootID and type = 'task' and path like '%,$id,%'")
|
||||
->beginIF($startModulePath)->andWhere('path')->like($startModulePath)->fi()
|
||||
->orderBy('grade desc, type, `order`')
|
||||
->fetchAll('id');
|
||||
@@ -196,41 +185,11 @@ class treeModel extends model
|
||||
{
|
||||
$parentModules = explode(',', trim($module->path, ','));
|
||||
if($type == 'product' and isset($noProductModules[$parentModules[0]])) continue;
|
||||
|
||||
$moduleName = $type == 'product' ? '/' . $rootModule : '';
|
||||
foreach($parentModules as $parentModuleID)
|
||||
{
|
||||
if(empty($parentModuleID) or !isset($modules[$parentModuleID])) continue;
|
||||
$moduleName .= '/' . $modules[$parentModuleID]->name;
|
||||
}
|
||||
$moduleName = rtrim($moduleName, '/');
|
||||
$moduleName .= "|$module->id\n";
|
||||
|
||||
if(isset($treeMenu[$module->id]) and !empty($treeMenu[$module->id]))
|
||||
{
|
||||
if(isset($treeMenu[$module->parent]))
|
||||
{
|
||||
$treeMenu[$module->parent] .= $moduleName;
|
||||
}
|
||||
else
|
||||
{
|
||||
$treeMenu[$module->parent] = $moduleName;;
|
||||
}
|
||||
$treeMenu[$module->parent] .= $treeMenu[$module->id];
|
||||
}
|
||||
else
|
||||
{
|
||||
if(isset($treeMenu[$module->parent]) and !empty($treeMenu[$module->parent]))
|
||||
{
|
||||
$treeMenu[$module->parent] .= $moduleName;
|
||||
}
|
||||
else
|
||||
{
|
||||
$treeMenu[$module->parent] = $moduleName;
|
||||
}
|
||||
}
|
||||
$this->buildTreeArray($treeMenu, $modules, $module, $productNum > 1 ? "/$rootModule/" : '/');
|
||||
}
|
||||
$topMenu = @array_pop($treeMenu);
|
||||
|
||||
ksort($treeMenu);
|
||||
$topMenu = @array_shift($treeMenu);
|
||||
$topMenu = explode("\n", trim($topMenu));
|
||||
foreach($topMenu as $menu)
|
||||
{
|
||||
@@ -247,6 +206,52 @@ class treeModel extends model
|
||||
return $lastMenu;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build tree array.
|
||||
*
|
||||
* @param $&treeMenu
|
||||
* @param array $modules
|
||||
* @param object $module
|
||||
* @param string $moduleName
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function buildTreeArray(& $treeMenu, $modules, $module, $moduleName = '/')
|
||||
{
|
||||
$parentModules = explode(',', $module->path);
|
||||
foreach($parentModules as $parentModuleID)
|
||||
{
|
||||
if(empty($parentModuleID)) continue;
|
||||
$moduleName .= $modules[$parentModuleID]->name . '/';
|
||||
}
|
||||
$moduleName = rtrim($moduleName, '/');
|
||||
$moduleName .= "|$module->id\n";
|
||||
|
||||
if(isset($treeMenu[$module->id]) and !empty($treeMenu[$module->id]))
|
||||
{
|
||||
if(isset($treeMenu[$module->parent]))
|
||||
{
|
||||
$treeMenu[$module->parent] .= $moduleName;
|
||||
}
|
||||
else
|
||||
{
|
||||
$treeMenu[$module->parent] = $moduleName;;
|
||||
}
|
||||
$treeMenu[$module->parent] .= $treeMenu[$module->id];
|
||||
}
|
||||
else
|
||||
{
|
||||
if(isset($treeMenu[$module->parent]) and !empty($treeMenu[$module->parent]))
|
||||
{
|
||||
$treeMenu[$module->parent] .= $moduleName;
|
||||
}
|
||||
else
|
||||
{
|
||||
$treeMenu[$module->parent] = $moduleName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the tree menu in html.
|
||||
*
|
||||
@@ -258,46 +263,37 @@ class treeModel extends model
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getTreeMenu($rootID, $type = 'root', $startModule = 0, $userFunc, $extra = '')
|
||||
public function getTreeMenu($rootID, $type = 'root', $startModule = 0, $userFunc, $extra = '', $branch = 0)
|
||||
{
|
||||
$treeMenu = array();
|
||||
$stmt = $this->dbh->query($this->buildMenuQuery($rootID, $type, $startModule));
|
||||
$branches = array($branch => '');
|
||||
$manage = $userFunc[1] == 'createManageLink' ? true : false;
|
||||
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');
|
||||
while($module = $stmt->fetch())
|
||||
$lastMenu = '';
|
||||
foreach($branches as $branchID => $branch)
|
||||
{
|
||||
/* Add for task #1945. check the module has case or no. */
|
||||
if($type == 'case' and !empty($extra))
|
||||
$treeMenu = array();
|
||||
$stmt = $this->dbh->query($this->buildMenuQuery($rootID, $type, $startModule, $branchID));
|
||||
while($module = $stmt->fetch()) $this->buildTree($treeMenu, $module, $type, $userFunc, $extra, $branchID);
|
||||
ksort($treeMenu);
|
||||
if(!empty($branchID) and $branchID != 'null')
|
||||
{
|
||||
$modules = $this->getAllChildID($module->id);
|
||||
$runs = $this->testtask->getRuns($extra, $modules, 'id');
|
||||
if(empty($runs)) continue;
|
||||
}
|
||||
|
||||
$linkHtml = call_user_func($userFunc, $type, $module, $extra);
|
||||
|
||||
if(isset($treeMenu[$module->id]) and !empty($treeMenu[$module->id]))
|
||||
{
|
||||
if(!isset($treeMenu[$module->parent])) $treeMenu[$module->parent] = '';
|
||||
$treeMenu[$module->parent] .= "<li class='closed'>$linkHtml";
|
||||
$treeMenu[$module->parent] .= "<ul>" . $treeMenu[$module->id] . "</ul>\n";
|
||||
$linkHtml = $manage ? html::a(inlink('browse', "root=$rootID&viewType=$type¤tModuleID=0&branch=$branchID"), $branch) : $this->createBranchLink($type, $rootID, $branchID, $branch);
|
||||
$lastMenu .= "<li>$linkHtml<ul>" . @array_shift($treeMenu) . "</ul></li>\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
if(isset($treeMenu[$module->parent]) and !empty($treeMenu[$module->parent]))
|
||||
{
|
||||
$treeMenu[$module->parent] .= "<li>$linkHtml\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
$treeMenu[$module->parent] = "<li>$linkHtml\n";
|
||||
}
|
||||
$lastMenu .= array_shift($treeMenu);
|
||||
}
|
||||
$treeMenu[$module->parent] .= "</li>\n";
|
||||
}
|
||||
|
||||
$lastMenu = "<ul class='tree'>" . @array_pop($treeMenu) . "</ul>\n";
|
||||
$lastMenu = "<ul class='tree'>$lastMenu</ul>\n";
|
||||
return $lastMenu;
|
||||
}
|
||||
|
||||
@@ -360,8 +356,7 @@ class treeModel extends model
|
||||
|
||||
/* tree menu. */
|
||||
$treeMenu = array();
|
||||
$query = $this->dao->select('*')->from(TABLE_MODULE)
|
||||
->where("((root = $rootID and type = 'task' and parent != 0) OR (root = $id and type = 'story'))")
|
||||
$query = $this->dao->select('*')->from(TABLE_MODULE)->where("((root = $rootID and type = 'task' and parent != 0) OR (root = $id and type = 'story'))")
|
||||
->beginIF($startModulePath)->andWhere('path')->like($startModulePath)->fi()
|
||||
->orderBy('grade desc, type, `order`')
|
||||
->get();
|
||||
@@ -370,27 +365,7 @@ class treeModel extends model
|
||||
{
|
||||
/* if not manage, ignore unused modules. */
|
||||
if(!$manage and !isset($projectModules[$module->id])) continue;
|
||||
|
||||
$linkHtml = call_user_func($userFunc, 'task', $module, $extra);
|
||||
|
||||
if(isset($treeMenu[$module->id]) and !empty($treeMenu[$module->id]))
|
||||
{
|
||||
if(!isset($treeMenu[$module->parent])) $treeMenu[$module->parent] = '';
|
||||
$treeMenu[$module->parent] .= "<li class='closed'>$linkHtml";
|
||||
$treeMenu[$module->parent] .= "<ul>" . $treeMenu[$module->id] . "</ul>\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
if(isset($treeMenu[$module->parent]) and !empty($treeMenu[$module->parent]))
|
||||
{
|
||||
$treeMenu[$module->parent] .= "<li>$linkHtml\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
$treeMenu[$module->parent] = "<li>$linkHtml\n";
|
||||
}
|
||||
}
|
||||
$treeMenu[$module->parent] .= "</li>\n";
|
||||
$this->buildTree($treeMenu, $module, 'task', $userFunc, $extra);
|
||||
}
|
||||
|
||||
$tree = isset($treeMenu[0]) ? $treeMenu[0] : '';
|
||||
@@ -403,36 +378,13 @@ class treeModel extends model
|
||||
{
|
||||
/* tree menu. */
|
||||
$treeMenu = array();
|
||||
$query = $this->dao->select('*')->from(TABLE_MODULE)
|
||||
->where("root = $rootID and type = 'task'")
|
||||
->orderBy('grade desc, type, `order`')
|
||||
->get();
|
||||
$stmt = $this->dbh->query($query);
|
||||
$query = $this->dao->select('*')->from(TABLE_MODULE)->where("root = $rootID and type = 'task'")->orderBy('grade desc, type, `order`')->get();
|
||||
$stmt = $this->dbh->query($query);
|
||||
while($module = $stmt->fetch())
|
||||
{
|
||||
/* if not manage, ignore unused modules. */
|
||||
if(!$manage and !isset($projectModules[$module->id])) continue;
|
||||
|
||||
$linkHtml = call_user_func($userFunc, 'task', $module, $extra);
|
||||
|
||||
if(isset($treeMenu[$module->id]) and !empty($treeMenu[$module->id]))
|
||||
{
|
||||
if(!isset($treeMenu[$module->parent])) $treeMenu[$module->parent] = '';
|
||||
$treeMenu[$module->parent] .= "<li class='closed'>$linkHtml";
|
||||
$treeMenu[$module->parent] .= "<ul>" . $treeMenu[$module->id] . "</ul>\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
if(isset($treeMenu[$module->parent]) and !empty($treeMenu[$module->parent]))
|
||||
{
|
||||
$treeMenu[$module->parent] .= "<li>$linkHtml\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
$treeMenu[$module->parent] = "<li>$linkHtml\n";
|
||||
}
|
||||
}
|
||||
$treeMenu[$module->parent] .= "</li>\n";
|
||||
$this->buildTree($treeMenu, $module, 'task', $userFunc, $extra);
|
||||
}
|
||||
|
||||
$tree = isset($treeMenu[0]) ? $treeMenu[0] : '';
|
||||
@@ -475,8 +427,7 @@ class treeModel extends model
|
||||
|
||||
/* tree menu. */
|
||||
$treeMenu = array();
|
||||
$query = $this->dao->select('*')->from(TABLE_MODULE)
|
||||
->where("(root = $id and type = 'story')")
|
||||
$query = $this->dao->select('*')->from(TABLE_MODULE)->where("(root = $id and type = 'story')")
|
||||
->beginIF($startModulePath)->andWhere('path')->like($startModulePath)->fi()
|
||||
->orderBy('grade desc, type, `order`')
|
||||
->get();
|
||||
@@ -485,27 +436,7 @@ class treeModel extends model
|
||||
{
|
||||
/* if not manage, ignore unused modules. */
|
||||
if(!isset($projectModules[$module->id])) continue;
|
||||
|
||||
$linkHtml = call_user_func($userFunc, 'task', $module, $extra);
|
||||
|
||||
if(isset($treeMenu[$module->id]) and !empty($treeMenu[$module->id]))
|
||||
{
|
||||
if(!isset($treeMenu[$module->parent])) $treeMenu[$module->parent] = '';
|
||||
$treeMenu[$module->parent] .= "<li class='closed'>$linkHtml";
|
||||
$treeMenu[$module->parent] .= "<ul>" . $treeMenu[$module->id] . "</ul>\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
if(isset($treeMenu[$module->parent]) and !empty($treeMenu[$module->parent]))
|
||||
{
|
||||
$treeMenu[$module->parent] .= "<li>$linkHtml\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
$treeMenu[$module->parent] = "<li>$linkHtml\n";
|
||||
}
|
||||
}
|
||||
$treeMenu[$module->parent] .= "</li>\n";
|
||||
$this->buildTree($treeMenu, $module, 'task', $userFunc, $extra);
|
||||
}
|
||||
|
||||
$tree = isset($treeMenu[0]) ? $treeMenu[0] : '';
|
||||
@@ -517,6 +448,51 @@ class treeModel extends model
|
||||
return $menu;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build tree.
|
||||
*
|
||||
* @param & $&treeMenu
|
||||
* @param object $module
|
||||
* @param string $type
|
||||
* @param array $userFunc
|
||||
* @param array $extra
|
||||
* @param int $branch
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function buildTree(& $treeMenu, $module, $type, $userFunc, $extra, $branch = 0)
|
||||
{
|
||||
/* Add for task #1945. check the module has case or no. */
|
||||
if($type == 'case' and !empty($extra))
|
||||
{
|
||||
$modules = $this->getAllChildID($module->id);
|
||||
$runs = $this->testtask->getRuns($extra, $modules, 'id');
|
||||
if(empty($runs)) continue;
|
||||
}
|
||||
|
||||
$extra['branchID'] = $branch;
|
||||
$linkHtml = call_user_func($userFunc, $type, $module, $extra);
|
||||
|
||||
if(isset($treeMenu[$module->id]) and !empty($treeMenu[$module->id]))
|
||||
{
|
||||
if(!isset($treeMenu[$module->parent])) $treeMenu[$module->parent] = '';
|
||||
$treeMenu[$module->parent] .= "<li class='closed'>$linkHtml";
|
||||
$treeMenu[$module->parent] .= "<ul>" . $treeMenu[$module->id] . "</ul>\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
if(isset($treeMenu[$module->parent]) and !empty($treeMenu[$module->parent]))
|
||||
{
|
||||
$treeMenu[$module->parent] .= "<li>$linkHtml\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
$treeMenu[$module->parent] = "<li>$linkHtml\n";
|
||||
}
|
||||
}
|
||||
$treeMenu[$module->parent] .= "</li>\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get project modules.
|
||||
*
|
||||
@@ -568,10 +544,7 @@ class treeModel extends model
|
||||
foreach($paths as $path)
|
||||
{
|
||||
$modules = explode(',', $path);
|
||||
foreach($modules as $module)
|
||||
{
|
||||
$projectModules[$module] = $module;
|
||||
}
|
||||
foreach($modules as $module) $projectModules[$module] = $module;
|
||||
}
|
||||
return $projectModules;
|
||||
}
|
||||
@@ -680,7 +653,7 @@ class treeModel extends model
|
||||
*/
|
||||
public function createStoryLink($type, $module)
|
||||
{
|
||||
$linkHtml = html::a(helper::createLink('product', 'browse', "root={$module->root}&type=byModule¶m={$module->id}"), $module->name, '_self', "id='module{$module->id}'");
|
||||
$linkHtml = html::a(helper::createLink('product', 'browse', "root={$module->root}&branch=&type=byModule¶m={$module->id}"), $module->name, '_self', "id='module{$module->id}'");
|
||||
return $linkHtml;
|
||||
}
|
||||
|
||||
@@ -749,8 +722,9 @@ class treeModel extends model
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function createManageLink($type, $module)
|
||||
public function createManageLink($type, $module, $extra)
|
||||
{
|
||||
$branchID = $extra['branchID'];
|
||||
$tip = strpos('bug,case', $type) === false ? '' : ' <span style="font-size:smaller;">[' . strtoupper(substr($type, 0, 1)) . ']</span>';
|
||||
static $users;
|
||||
if(empty($users)) $users = $this->loadModel('user')->getPairs('noletter');
|
||||
@@ -759,13 +733,13 @@ class treeModel extends model
|
||||
if($type == 'bug' and $module->owner) $linkHtml .= '<span class="owner">[' . $users[$module->owner] . ']</span>';
|
||||
if($type != 'story' and $module->type == 'story')
|
||||
{
|
||||
if(common::hasPriv('tree', 'edit') and $type == 'bug') $linkHtml .= ' ' . html::a(helper::createLink('tree', 'edit', "module={$module->id}&type=$type"), $this->lang->tree->edit, '', 'data-toggle="modal" data-type="ajax"');
|
||||
if(common::hasPriv('tree', 'browse')) $linkHtml .= ' ' . html::a(helper::createLink('tree', 'browse', "root={$module->root}&type=$type&module={$module->id}"), $this->lang->tree->child);
|
||||
if(common::hasPriv('tree', 'edit') and $type == 'bug') $linkHtml .= ' ' . html::a(helper::createLink('tree', 'edit', "module={$module->id}&type=$type&branch=$branchID"), $this->lang->tree->edit, '', 'data-toggle="modal" data-type="ajax"');
|
||||
if(common::hasPriv('tree', 'browse')) $linkHtml .= ' ' . html::a(helper::createLink('tree', 'browse', "root={$module->root}&type=$type&module={$module->id}&branch=$branchID"), $this->lang->tree->child);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(common::hasPriv('tree', 'edit')) $linkHtml .= ' ' . html::a(helper::createLink('tree', 'edit', "module={$module->id}&type=$type"), $this->lang->tree->edit, '', 'data-toggle="modal" data-type="ajax" data-width="500"');
|
||||
if(common::hasPriv('tree', 'browse') and strpos($this->config->tree->noBrowse, ",$module->type,") === false) $linkHtml .= ' ' . html::a(helper::createLink('tree', 'browse', "root={$module->root}&type=$type&module={$module->id}"), $this->lang->tree->child);
|
||||
if(common::hasPriv('tree', 'edit')) $linkHtml .= ' ' . html::a(helper::createLink('tree', 'edit', "module={$module->id}&type=$type&branch=$branchID"), $this->lang->tree->edit, '', 'data-toggle="modal" data-type="ajax" data-width="500"');
|
||||
if(common::hasPriv('tree', 'browse') and strpos($this->config->tree->noBrowse, ",$module->type,") === false) $linkHtml .= ' ' . html::a(helper::createLink('tree', 'browse', "root={$module->root}&type=$type&module={$module->id}&branch=$branchID"), $this->lang->tree->child);
|
||||
if(common::hasPriv('tree', 'delete')) $linkHtml .= ' ' . html::a(helper::createLink('tree', 'delete', "root={$module->root}&module={$module->id}"), $this->lang->delete, 'hiddenwin');
|
||||
if(common::hasPriv('tree', 'updateorder')) $linkHtml .= ' ' . html::input("orders[$module->id]", $module->order, 'class="text-center w-30px form-control inline input-sm"');
|
||||
}
|
||||
@@ -810,7 +784,7 @@ class treeModel extends model
|
||||
*/
|
||||
public function createBugLink($type, $module)
|
||||
{
|
||||
$linkHtml = html::a(helper::createLink('bug', 'browse', "root={$module->root}&type=byModule¶m={$module->id}"), $module->name, '_self', "id='module{$module->id}'");
|
||||
$linkHtml = html::a(helper::createLink('bug', 'browse', "root={$module->root}&branch=&type=byModule¶m={$module->id}"), $module->name, '_self', "id='module{$module->id}'");
|
||||
return $linkHtml;
|
||||
}
|
||||
|
||||
@@ -823,7 +797,7 @@ class treeModel extends model
|
||||
*/
|
||||
public function createCaseLink($type, $module)
|
||||
{
|
||||
$linkHtml = html::a(helper::createLink('testcase', 'browse', "root={$module->root}&type=byModule¶m={$module->id}"), $module->name, '_self', "id='module{$module->id}'");
|
||||
$linkHtml = html::a(helper::createLink('testcase', 'browse', "root={$module->root}&branch=&type=byModule¶m={$module->id}"), $module->name, '_self', "id='module{$module->id}'");
|
||||
return $linkHtml;
|
||||
}
|
||||
|
||||
@@ -840,6 +814,13 @@ class treeModel extends model
|
||||
return $linkHtml;
|
||||
}
|
||||
|
||||
public function createBranchLink($type, $rootID, $branchID, $branch)
|
||||
{
|
||||
if($type == 'story') return html::a(helper::createLink('product', 'browse', "productID={$rootID}&branch=$branchID"), $branch, '_self', "id='branch{$branchID}'");
|
||||
if($type == 'bug') return html::a(helper::createLink('bug', 'browse', "productID={$rootID}&branch=$branchID"), $branch, '_self', "id='branch{$branchID}'");
|
||||
if($type == 'case') return html::a(helper::createLink('testcase', 'browse', "productID={$rootID}&branch=$branchID"), $branch, '_self', "id='branch{$branchID}'");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get sons of a module.
|
||||
*
|
||||
@@ -849,7 +830,7 @@ class treeModel extends model
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getSons($rootID, $moduleID, $type = 'root')
|
||||
public function getSons($rootID, $moduleID, $type = 'root', $branch = 0)
|
||||
{
|
||||
$createdVersion = $this->dao->select('createdVersion')->from(TABLE_PRODUCT)
|
||||
->where('id')->eq($rootID)
|
||||
@@ -862,6 +843,8 @@ class treeModel extends model
|
||||
->where('root')->eq((int)$rootID)
|
||||
->andWhere('parent')->eq((int)$moduleID)
|
||||
->andWhere('type')->eq($type)
|
||||
->beginIF(empty($branch))->andWhere("branch")->eq(0)->fi()
|
||||
->beginIF(!empty($branch))->andWhere("branch")->eq($branch)->fi()
|
||||
->orderBy('`order`')
|
||||
->fetchAll();
|
||||
}
|
||||
@@ -872,6 +855,8 @@ class treeModel extends model
|
||||
->where('root')->eq((int)$rootID)
|
||||
->andWhere('parent')->eq((int)$moduleID)
|
||||
->andWhere('type')->in($type)
|
||||
->beginIF(empty($branch))->andWhere("branch")->eq(0)->fi()
|
||||
->beginIF(!empty($branch))->andWhere("branch")->eq($branch)->fi()
|
||||
->orderBy('type desc,`order`')
|
||||
->fetchAll();
|
||||
}
|
||||
@@ -1014,23 +999,24 @@ class treeModel extends model
|
||||
public function updateOrder($orders)
|
||||
{
|
||||
asort($orders);
|
||||
$orderInfo = $this->dao->select('id,grade, parent')->from(TABLE_MODULE)->where('id')->in(array_keys($orders))->fetchAll('id');
|
||||
$orderInfo = $this->dao->select('id,grade, parent, branch')->from(TABLE_MODULE)->where('id')->in(array_keys($orders))->fetchAll('id');
|
||||
$newOrders = array();
|
||||
foreach($orders as $moduleID => $order)
|
||||
{
|
||||
$parent = $orderInfo[$moduleID]->parent;
|
||||
$grade = $orderInfo[$moduleID]->grade;
|
||||
$branch = $orderInfo[$moduleID]->branch;
|
||||
|
||||
if(!isset($newOrders[$parent][$grade]))
|
||||
if(!isset($newOrders[$parent][$grade][$branch]))
|
||||
{
|
||||
$newOrders[$parent][$grade] = 1;
|
||||
$newOrders[$parent][$grade][$branch] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$newOrders[$parent][$grade] ++;
|
||||
$newOrders[$parent][$grade][$branch] ++;
|
||||
}
|
||||
|
||||
$newOrder = $newOrders[$parent][$grade] * 10;
|
||||
$newOrder = $newOrders[$parent][$grade][$branch] * 10;
|
||||
$this->dao->update(TABLE_MODULE)->set('`order`')->eq($newOrder)->where('id')->eq((int)$moduleID)->limit(1)->exec();
|
||||
}
|
||||
}
|
||||
@@ -1048,6 +1034,7 @@ class treeModel extends model
|
||||
public function manageChild($rootID, $type, $parentModuleID, $childs)
|
||||
{
|
||||
$parentModule = $this->getByID($parentModuleID);
|
||||
$branches = $this->post->branch;
|
||||
if($parentModule)
|
||||
{
|
||||
$grade = $parentModule->grade + 1;
|
||||
@@ -1070,6 +1057,7 @@ class treeModel extends model
|
||||
$module->root = $rootID;
|
||||
$module->name = strip_tags($moduleName);
|
||||
$module->parent = $parentModuleID;
|
||||
$module->branch = $branches[$moduleID];
|
||||
$module->grade = $grade;
|
||||
$module->type = $type;
|
||||
$module->order = $this->post->maxOrder + $i * 10;
|
||||
@@ -1213,7 +1201,7 @@ class treeModel extends model
|
||||
{
|
||||
/* Get all modules grouped by parent. */
|
||||
if($type == 'bug' or $type == 'case') $type = 'story,' . $type;
|
||||
$groupModules = $this->dao->select('id, parent')->from(TABLE_MODULE)->where('root')->eq($root)->andWhere('type')->in($type)->fetchGroup('parent', 'id');
|
||||
$groupModules = $this->dao->select('id, parent, branch')->from(TABLE_MODULE)->where('root')->eq($root)->andWhere('type')->in($type)->fetchGroup('parent', 'id');
|
||||
$modules = array();
|
||||
|
||||
/* Cycle the groupModules until it has no item any more. */
|
||||
@@ -1238,8 +1226,9 @@ class treeModel extends model
|
||||
/* Compute it's child modules. */
|
||||
foreach($childModules as $childModuleID => $childModule)
|
||||
{
|
||||
$childModule->grade = $parentModule->grade + 1;
|
||||
$childModule->path = $parentModule->path . $childModule->id . ',';
|
||||
$childModule->grade = $parentModule->grade + 1;
|
||||
$childModule->path = $parentModule->path . $childModule->id . ',';
|
||||
if(isset($parentModule->branch))$childModule->branch = $parentModule->branch;
|
||||
$modules[$childModuleID] = $childModule; // Save child module to modules, thus the child of child can compute it's grade and path.
|
||||
}
|
||||
unset($groupModules[$parentModuleID]); // Remove it from the groupModules.
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
?>
|
||||
<?php include '../../common/view/header.html.php';?>
|
||||
<?php include '../../common/view/treeview.html.php';?>
|
||||
<?php $hasBranch = (strpos('story|bug|case', $viewType) !== false and $root->type != 'normal') ? true : false;?>
|
||||
<div id='titlebar'>
|
||||
<div class='heading'><i class='icon-cogs'></i> <?php echo $lang->tree->common;?> </div>
|
||||
</div>
|
||||
@@ -74,9 +75,20 @@
|
||||
{
|
||||
if($sonModule->order > $maxOrder) $maxOrder = $sonModule->order;
|
||||
$disabled = $sonModule->type == $viewType ? '' : 'disabled="true"';
|
||||
echo '<span>' . html::input("modules[id$sonModule->id]", $sonModule->name, 'class=form-control style="margin-bottom:5px" ' . $disabled) . '</span>';
|
||||
echo $hasBranch ? "<div class='input-group' style='margin-bottom:5px'>" : "<div style='margin-bottom:5px'>";
|
||||
echo html::input("modules[id$sonModule->id]", $sonModule->name, 'class="form-control"' . $disabled);
|
||||
if($hasBranch) echo '<span class="input-group-addon" style="padding:0px"></span>' . html::select("branch[id$sonModule->id]", $branches, $sonModule->branch, 'class="form-control" disabled');
|
||||
echo '</div>';
|
||||
}
|
||||
for($i = 0; $i < TREE::NEW_CHILD_COUNT ; $i ++)
|
||||
{
|
||||
echo "<div class='input-group' style='margin-bottom:5px'>";
|
||||
echo html::input("modules[]", '', 'class="form-control"');
|
||||
if($hasBranch) echo '<span class="input-group-addon" style="padding:0px"></span>' . html::select("branch[]", $branches, $branch, 'class="form-control"');
|
||||
echo "<span class='input-group-addon'><a href='javascript:;' onclick='addItem(this)'><i class='icon icon-plus'></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>';
|
||||
}
|
||||
for($i = 0; $i < TREE::NEW_CHILD_COUNT ; $i ++) echo '<span>' . html::input("modules[]", '', 'class=form-control style="margin-bottom:5px"') . '</span>';
|
||||
?>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
+19
-12
@@ -93,10 +93,11 @@ function shortcut()
|
||||
*/
|
||||
function showDropMenu(objectType, objectID, module, method, extra)
|
||||
{
|
||||
var li = $('#currentItem').closest('li');
|
||||
var itemID = objectType == 'branch' ? '#currentBranch' : '#currentItem';
|
||||
var li = $(itemID).closest('li');
|
||||
if(li.hasClass('show')) {li.removeClass('show'); return;}
|
||||
|
||||
var $dropMenu = $('#dropMenu');
|
||||
var $dropMenu = li.find('#dropMenu');
|
||||
if(!li.data('showagain'))
|
||||
{
|
||||
li.data('showagain', true);
|
||||
@@ -105,7 +106,7 @@ function showDropMenu(objectType, objectID, module, method, extra)
|
||||
|
||||
$dropMenu.on('keydown', '#search', function(e){
|
||||
var code = e.which;
|
||||
var $this = $('#searchResult > .search-list > ul > li.active');
|
||||
var $this = $dropMenu.find('#searchResult > .search-list > ul > li.active');
|
||||
if(code === 38) // up
|
||||
{
|
||||
$this.removeClass('active');
|
||||
@@ -122,7 +123,7 @@ function showDropMenu(objectType, objectID, module, method, extra)
|
||||
return;
|
||||
}
|
||||
}
|
||||
$('#searchResult > .search-list > ul > li:not(.heading):last').addClass('active');
|
||||
$dropMenu.find('#searchResult > .search-list > ul > li:not(.heading):last').addClass('active');
|
||||
}
|
||||
else if(code === 40) // down
|
||||
{
|
||||
@@ -140,7 +141,7 @@ function showDropMenu(objectType, objectID, module, method, extra)
|
||||
return;
|
||||
}
|
||||
}
|
||||
$('#searchResult > .search-list > ul > li:not(.heading):first').addClass('active');
|
||||
$dropMenu.find('#searchResult > .search-list > ul > li:not(.heading):first').addClass('active');
|
||||
}
|
||||
else if(code === 13) // enter
|
||||
{
|
||||
@@ -158,14 +159,14 @@ function showDropMenu(objectType, objectID, module, method, extra)
|
||||
searchItems(searchKey, objectType, objectID, module, method, extra);
|
||||
}, 200));
|
||||
}).on('mouseenter', '#searchResult .search-list > ul > li', function(){
|
||||
$('#searchResult > .search-list > ul > li.active').removeClass('active');
|
||||
$dropMenu.find('#searchResult > .search-list > ul > li.active').removeClass('active');
|
||||
$(this).addClass('active');
|
||||
});
|
||||
}
|
||||
$.get(createLink(objectType, 'ajaxGetDropMenu', "objectID=" + objectID + "&module=" + module + "&method=" + method + "&extra=" + extra), function(data)
|
||||
{
|
||||
$dropMenu.html(data).find('#search').focus();
|
||||
$('#searchResult > .search-list > ul > li:not(.heading)').removeClass('active').first().addClass('active');
|
||||
$dropMenu.find('#searchResult > .search-list > ul > li:not(.heading)').removeClass('active').first().addClass('active');
|
||||
});
|
||||
|
||||
li.addClass('show');
|
||||
@@ -184,11 +185,14 @@ function showDropMenu(objectType, objectID, module, method, extra)
|
||||
*/
|
||||
function showDropResult(objectType, objectID, module, method, extra)
|
||||
{
|
||||
var itemID = objectType == 'branch' ? '#currentBranch' : '#currentItem';
|
||||
var li = $(itemID).closest('li');
|
||||
var $dropMenu = li.find('#dropMenu');
|
||||
$.get(createLink(objectType, 'ajaxGetDropMenu', "objectID=" + objectID + "&module=" + module + "&method=" + method + "&extra=" + extra), function(data)
|
||||
{
|
||||
$('#dropMenu').html(data);
|
||||
setTimeout(function(){$("#dropMenu #search").focus();}, 200);
|
||||
$('#searchResult > .search-list > ul > li:not(.heading)').removeClass('active').first().addClass('active');
|
||||
$dropMenu.html(data);
|
||||
setTimeout(function(){$dropMenu.find("#search").focus();}, 200);
|
||||
$dropMenu.find('#searchResult > .search-list > ul > li:not(.heading)').removeClass('active').first().addClass('active');
|
||||
});
|
||||
}
|
||||
|
||||
@@ -213,10 +217,13 @@ function searchItems(keywords, objectType, objectID, module, method, extra)
|
||||
}
|
||||
else
|
||||
{
|
||||
var itemID = objectType == 'branch' ? '#currentBranch' : '#currentItem';
|
||||
var li = $(itemID).closest('li');
|
||||
var $dropMenu = li.find('#dropMenu');
|
||||
keywords = encodeURI(keywords);
|
||||
if(keywords != '-') $.get(createLink(objectType, 'ajaxGetMatchedItems', "keywords=" + keywords + "&module=" + module + "&method=" + method + "&extra=" + extra), function(data)
|
||||
if(keywords != '-') $.get(createLink(objectType, 'ajaxGetMatchedItems', "keywords=" + keywords + "&module=" + module + "&method=" + method + "&extra=" + extra + "&objectID=" + objectID), function(data)
|
||||
{
|
||||
$('#searchResult').html(data).find('.search-list > ul > li:not(.heading)').removeClass('active').first().addClass('active');
|
||||
$dropMenu.find('#searchResult').html(data).find('.search-list > ul > li:not(.heading)').removeClass('active').first().addClass('active');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user