* finish task #2336,2337,2338,2339.

This commit is contained in:
wangyidong
2015-10-20 10:11:46 +08:00
parent 78218b47d0
commit 9ad38472fc
21 changed files with 306 additions and 75 deletions

View File

@@ -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`');

View File

@@ -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'
);

51
module/branch/control.php Normal file
View File

@@ -0,0 +1,51 @@
<?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();
}
}

View File

@@ -0,0 +1,4 @@
<?php
$lang->branch->manage = '分支管理';
$lang->branch->all = '所有';

41
module/branch/model.php Normal file
View File

@@ -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();
}
}

View File

@@ -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>

View File

@@ -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>

View File

@@ -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';?>

View File

@@ -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;

View File

@@ -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>&nbsp
$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;

View File

@@ -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 = 0, $browseType = 'unclosed', $param = 0, $orderBy = '', $recTotal = 0, $recPerPage = 20, $pageID = 1)
{
/* Lower browse type. */
$browseType = strtolower($browseType);
@@ -117,11 +117,12 @@ class product extends control
/* Set product, module and query. */
$productID = $this->product->saveState($productID, $this->products);
if(empty($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,26 +147,26 @@ 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);
@@ -185,6 +186,7 @@ class product extends control
$this->view->orderBy = $orderBy;
$this->view->browseType = $browseType;
$this->view->moduleID = $moduleID;
$this->view->branch = $branch;
$this->display();
}

View File

@@ -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'] = '结束';

View File

@@ -22,7 +22,7 @@ class productModel extends model
* @access public
* @return void
*/
public function setMenu($products, $productID, $extra = '')
public function setMenu($products, $productID, $branch = '', $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 = '')
{
if(!$productID) return;
setCookie("lastProduct", $productID, $this->config->cookieLife, $this->config->webRoot);
setCookie("lastBranch", $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;
}
@@ -80,6 +88,7 @@ class productModel extends model
if($productID > 0) $this->session->set('product', (int)$productID);
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($this->cookie->lastBranch) $this->session->set('branch', (int)$this->cookie->lastBranch);
if(!isset($products[$this->session->product])) $this->session->set('product', key($products));
return $this->session->product;
}
@@ -662,19 +671,23 @@ 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");
@@ -683,11 +696,11 @@ class productModel extends model
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')
{
$link = helper::createLink($module, $method, "productID=%s&type=$extra");
$link = helper::createLink($module, $method, "productID=%s&type=$extra" . ($branch ? "&branch=%s" : ''));
}
return $link;
}

View File

@@ -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'>
@@ -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&param=$moduleID&orderBy=%s&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}";?>
<?php $vars = "productID=$productID&branch=$branch&browseType=$browseType&param=$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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -290,7 +290,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;

View File

@@ -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]);

View File

@@ -926,14 +926,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("CONCAT(',', t1.branch, ',')")->like("%,$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();
}
@@ -974,9 +975,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 +990,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 +1005,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 +1019,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 +1034,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 +1051,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 +1075,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')
@@ -1099,7 +1101,7 @@ class storyModel extends model
* @access public
* @return array
*/
public function getBySearch($productID, $queryID, $orderBy, $pager = null, $projectID = '')
public function getBySearch($productID, $branch, $queryID, $orderBy, $pager = null, $projectID = '')
{
if($projectID != '')
{
@@ -1367,7 +1369,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)

View File

@@ -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');
});
}
}