From 78218b47d01a44462f586ff7dd7814356964bd99 Mon Sep 17 00:00:00 2001 From: wangyidong Date: Tue, 20 Oct 2015 10:10:17 +0800 Subject: [PATCH 1/5] * fix a bug for safe. --- module/file/lang/zh-cn.php | 2 +- module/file/model.php | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/module/file/lang/zh-cn.php b/module/file/lang/zh-cn.php index 4de4e922ed..bd81b1a8ee 100644 --- a/module/file/lang/zh-cn.php +++ b/module/file/lang/zh-cn.php @@ -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 = <<1、上传文件为包含图片的zip压缩包,程序会以文件名作为标题,以图片作为内容。

2、如果文件名可以开头含有 数字+下划线,以方便排序,程序会将他们忽略。

diff --git a/module/file/model.php b/module/file/model.php index 5956bb2460..3cb1d13679 100644 --- a/module/file/model.php +++ b/module/file/model.php @@ -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; } From 9ad38472fc36ee805741c569fa28de4e8cde7886 Mon Sep 17 00:00:00 2001 From: wangyidong Date: Tue, 20 Oct 2015 10:11:46 +0800 Subject: [PATCH 2/5] * finish task #2336,2337,2338,2339. --- config/config.php | 1 + db/update7.3.sql | 17 +++++++ module/branch/control.php | 51 +++++++++++++++++++ module/branch/lang/zh-cn.php | 4 ++ module/branch/model.php | 41 +++++++++++++++ module/branch/view/ajaxgetdropmenu.html.php | 17 +++++++ .../branch/view/ajaxgetmatcheditems.html.php | 11 ++++ module/branch/view/manage.html.php | 42 +++++++++++++++ module/common/lang/menuOrder.php | 11 ++-- module/common/lang/zh-cn.php | 3 ++ module/product/control.php | 36 ++++++------- module/product/lang/zh-cn.php | 6 +++ module/product/model.php | 29 ++++++++--- module/product/view/browse.html.php | 24 ++++----- module/product/view/create.html.php | 4 ++ module/product/view/edit.html.php | 4 ++ module/product/view/view.html.php | 4 ++ module/productplan/control.php | 2 +- module/project/model.php | 7 +-- module/story/model.php | 36 ++++++------- www/js/my.full.js | 31 ++++++----- 21 files changed, 306 insertions(+), 75 deletions(-) create mode 100644 module/branch/control.php create mode 100644 module/branch/lang/zh-cn.php create mode 100644 module/branch/model.php create mode 100644 module/branch/view/ajaxgetdropmenu.html.php create mode 100644 module/branch/view/ajaxgetmatcheditems.html.php create mode 100644 module/branch/view/manage.html.php diff --git a/config/config.php b/config/config.php index f8a7993985..fef6e3bc31 100644 --- a/config/config.php +++ b/config/config.php @@ -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`'); diff --git a/db/update7.3.sql b/db/update7.3.sql index e99585ea65..9c80ac0ff4 100644 --- a/db/update7.3.sql +++ b/db/update7.3.sql @@ -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' +); diff --git a/module/branch/control.php b/module/branch/control.php new file mode 100644 index 0000000000..243754caae --- /dev/null +++ b/module/branch/control.php @@ -0,0 +1,51 @@ + + * @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(); + } +} + diff --git a/module/branch/lang/zh-cn.php b/module/branch/lang/zh-cn.php new file mode 100644 index 0000000000..180dd612a0 --- /dev/null +++ b/module/branch/lang/zh-cn.php @@ -0,0 +1,4 @@ +branch->manage = '分支管理'; + +$lang->branch->all = '所有'; diff --git a/module/branch/model.php b/module/branch/model.php new file mode 100644 index 0000000000..08d6c74f04 --- /dev/null +++ b/module/branch/model.php @@ -0,0 +1,41 @@ + + * @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(); + } +} + diff --git a/module/branch/view/ajaxgetdropmenu.html.php b/module/branch/view/ajaxgetdropmenu.html.php new file mode 100644 index 0000000000..8a270cd345 --- /dev/null +++ b/module/branch/view/ajaxgetdropmenu.html.php @@ -0,0 +1,17 @@ + + + + +search->common;?>'/> +
+
+
    + $branch) + { + echo "
  • " . html::a(sprintf($link, $productID, $branchID), " " . $branch, '', "class='text-important'"). "
  • "; + } + ?> +
+
+
diff --git a/module/branch/view/ajaxgetmatcheditems.html.php b/module/branch/view/ajaxgetmatcheditems.html.php new file mode 100644 index 0000000000..e35a6c00ab --- /dev/null +++ b/module/branch/view/ajaxgetmatcheditems.html.php @@ -0,0 +1,11 @@ +
+
    + " . sprintf($lang->product->noMatched, $keywords) . '';?> + $branch) + { + echo "
  • " . html::a(sprintf($link, $productID, $branchID), " " . $branch). "
  • "; + } + ?> +
+
diff --git a/module/branch/view/manage.html.php b/module/branch/view/manage.html.php new file mode 100644 index 0000000000..da4dc294eb --- /dev/null +++ b/module/branch/view/manage.html.php @@ -0,0 +1,42 @@ + + * @package branch + * @version $Id$ + * @link http://www.zentao.net + */ +?> + +
+
+
branch->manage?>
+
+
+ + $branch):?> + + + + + + + + + + + + + + + + + +
+
+
+ + diff --git a/module/common/lang/menuOrder.php b/module/common/lang/menuOrder.php index c9c0088771..b263388432 100644 --- a/module/common/lang/menuOrder.php +++ b/module/common/lang/menuOrder.php @@ -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; diff --git a/module/common/lang/zh-cn.php b/module/common/lang/zh-cn.php index af76deac50..1916a19737 100644 --- a/module/common/lang/zh-cn.php +++ b/module/common/lang/zh-cn.php @@ -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' => "  $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; diff --git a/module/product/control.php b/module/product/control.php index eddbee8c29..f63e692f93 100644 --- a/module/product/control.php +++ b/module/product/control.php @@ -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(); } diff --git a/module/product/lang/zh-cn.php b/module/product/lang/zh-cn.php index 2e93bad680..82a375b6c3 100644 --- a/module/product/lang/zh-cn.php +++ b/module/product/lang/zh-cn.php @@ -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'] = '结束'; diff --git a/module/product/model.php b/module/product/model.php index d2b851e951..aee245a32c 100644 --- a/module/product/model.php +++ b/module/product/model.php @@ -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 = "{$currentProduct->name}
"; + $output = "{$currentProduct->name}
"; + if($currentProduct->type != 'normal') + { + $branches = $this->loadModel('branch')->getPairs($productID); + $branchName = isset($branches[$branch]) ? $branches[$branch] : $branches[0]; + $output .= '
  • '; + $output .= "{$branchName}
    "; + } 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; } diff --git a/module/product/view/browse.html.php b/module/product/view/browse.html.php index 2be2cb6fff..85210b309e 100644 --- a/module/product/view/browse.html.php +++ b/module/product/view/browse.html.php @@ -15,17 +15,17 @@
    @@ -74,7 +74,7 @@ - recTotal}&recPerPage={$pager->recPerPage}";?> + recTotal}&recPerPage={$pager->recPerPage}";?> diff --git a/module/product/view/create.html.php b/module/product/view/create.html.php index 04cb35cbfe..59dc8c93da 100644 --- a/module/product/view/create.html.php +++ b/module/product/view/create.html.php @@ -41,6 +41,10 @@ + + + + diff --git a/module/product/view/edit.html.php b/module/product/view/edit.html.php index 201494a4bf..d665866660 100644 --- a/module/product/view/edit.html.php +++ b/module/product/view/edit.html.php @@ -42,6 +42,10 @@ + + + + diff --git a/module/product/view/view.html.php b/module/product/view/view.html.php index ca66c7814c..21a25cfe5f 100644 --- a/module/product/view/view.html.php +++ b/module/product/view/view.html.php @@ -81,6 +81,10 @@ + + + + diff --git a/module/productplan/control.php b/module/productplan/control.php index 1fe52294b5..4f0b3a7115 100644 --- a/module/productplan/control.php +++ b/module/productplan/control.php @@ -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; diff --git a/module/project/model.php b/module/project/model.php index a5b16ad328..fb7d5ed343 100644 --- a/module/project/model.php +++ b/module/project/model.php @@ -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]); diff --git a/module/story/model.php b/module/story/model.php index 771b3467eb..1f8502f1e1 100644 --- a/module/story/model.php +++ b/module/story/model.php @@ -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) diff --git a/www/js/my.full.js b/www/js/my.full.js index b651f1ff01..3fc58f0412 100644 --- a/www/js/my.full.js +++ b/www/js/my.full.js @@ -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'); }); } } From 333b0be157ac15717e7a7b39b53ccef49ec4a707 Mon Sep 17 00:00:00 2001 From: wangyidong Date: Thu, 22 Oct 2015 09:03:37 +0800 Subject: [PATCH 3/5] * finish task #2323,2340. --- module/tree/control.php | 20 +- module/tree/css/common.css | 2 +- module/tree/js/browse.js | 25 +- module/tree/model.php | 382 +++++++++++++++---------------- module/tree/view/browse.html.php | 16 +- 5 files changed, 228 insertions(+), 217 deletions(-) diff --git a/module/tree/control.php b/module/tree/control.php index ec506ad59e..e85a9de756 100644 --- a/module/tree/control.php +++ b/module/tree/control.php @@ -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 .= ""; - $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 .= ''; diff --git a/module/tree/css/common.css b/module/tree/css/common.css index 5d2f25501d..d919ec95de 100644 --- a/module/tree/css/common.css +++ b/module/tree/css/common.css @@ -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} diff --git a/module/tree/js/browse.js b/module/tree/js/browse.js index 5870f3a8b2..9a9e395070 100644 --- a/module/tree/js/browse.js +++ b/module/tree/js/browse.js @@ -7,8 +7,9 @@ function syncModule(rootID, type) $.getJSON(link, function(modules) { $('.helplink').addClass('hidden'); + var $inputgroup = $('
    ').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(""); + { + 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(); diff --git a/module/tree/model.php b/module/tree/model.php index f69d14549a..0b5a78907c 100644 --- a/module/tree/model.php +++ b/module/tree/model.php @@ -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,27 @@ 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 and empty($branch)) { - $parentModules = explode(',', $module->path); - $moduleName = '/'; - 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; - } - } + $product = $this->loadModel('product')->getById($rootID); + if($product->type != 'normal') $branches = array('null' => '') + $this->loadModel('branch')->getPairs($rootID, 'noempty'); } - $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 +113,7 @@ class treeModel extends model list($label, $moduleID) = explode('|', $menu); $lastMenu[$moduleID] = $label; } + return $lastMenu; } @@ -171,22 +152,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 +176,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 +197,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 +254,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] .= "
  • $linkHtml"; - $treeMenu[$module->parent] .= "
      " . $treeMenu[$module->id] . "
    \n"; + $linkHtml = $manage ? html::a(inlink('browse', "root=$rootID&viewType=$type¤tModuleID=0&branch=$branchID"), $branch) : $this->createBranchLink($type, $rootID, $branchID, $branch); + $lastMenu .= "
  • $linkHtml
      " . @array_shift($treeMenu) . "
  • \n"; } else { - if(isset($treeMenu[$module->parent]) and !empty($treeMenu[$module->parent])) - { - $treeMenu[$module->parent] .= "
  • $linkHtml\n"; - } - else - { - $treeMenu[$module->parent] = "
  • $linkHtml\n"; - } + $lastMenu .= array_shift($treeMenu); } - $treeMenu[$module->parent] .= "
  • \n"; } - $lastMenu = "
      " . @array_pop($treeMenu) . "
    \n"; + $lastMenu = "
      $lastMenu
    \n"; return $lastMenu; } @@ -360,8 +347,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 +356,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] .= "
  • $linkHtml"; - $treeMenu[$module->parent] .= "
      " . $treeMenu[$module->id] . "
    \n"; - } - else - { - if(isset($treeMenu[$module->parent]) and !empty($treeMenu[$module->parent])) - { - $treeMenu[$module->parent] .= "
  • $linkHtml\n"; - } - else - { - $treeMenu[$module->parent] = "
  • $linkHtml\n"; - } - } - $treeMenu[$module->parent] .= "
  • \n"; + $this->buildTree($treeMenu, $module, 'task', $userFunc, $extra); } $tree = isset($treeMenu[0]) ? $treeMenu[0] : ''; @@ -403,36 +369,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] .= "
  • $linkHtml"; - $treeMenu[$module->parent] .= "
      " . $treeMenu[$module->id] . "
    \n"; - } - else - { - if(isset($treeMenu[$module->parent]) and !empty($treeMenu[$module->parent])) - { - $treeMenu[$module->parent] .= "
  • $linkHtml\n"; - } - else - { - $treeMenu[$module->parent] = "
  • $linkHtml\n"; - } - } - $treeMenu[$module->parent] .= "
  • \n"; + $this->buildTree($treeMenu, $module, 'task', $userFunc, $extra); } $tree = isset($treeMenu[0]) ? $treeMenu[0] : ''; @@ -475,8 +418,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 +427,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] .= "
  • $linkHtml"; - $treeMenu[$module->parent] .= "
      " . $treeMenu[$module->id] . "
    \n"; - } - else - { - if(isset($treeMenu[$module->parent]) and !empty($treeMenu[$module->parent])) - { - $treeMenu[$module->parent] .= "
  • $linkHtml\n"; - } - else - { - $treeMenu[$module->parent] = "
  • $linkHtml\n"; - } - } - $treeMenu[$module->parent] .= "
  • \n"; + $this->buildTree($treeMenu, $module, 'task', $userFunc, $extra); } $tree = isset($treeMenu[0]) ? $treeMenu[0] : ''; @@ -517,6 +439,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] .= "
  • $linkHtml"; + $treeMenu[$module->parent] .= "
      " . $treeMenu[$module->id] . "
    \n"; + } + else + { + if(isset($treeMenu[$module->parent]) and !empty($treeMenu[$module->parent])) + { + $treeMenu[$module->parent] .= "
  • $linkHtml\n"; + } + else + { + $treeMenu[$module->parent] = "
  • $linkHtml\n"; + } + } + $treeMenu[$module->parent] .= "
  • \n"; + } + /** * Get project modules. * @@ -568,10 +535,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 +644,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 +713,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 ? '' : ' [' . strtoupper(substr($type, 0, 1)) . ']'; static $users; if(empty($users)) $users = $this->loadModel('user')->getPairs('noletter'); @@ -759,13 +724,13 @@ class treeModel extends model if($type == 'bug' and $module->owner) $linkHtml .= '[' . $users[$module->owner] . ']'; 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 +775,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 +788,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 +805,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 +821,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 +834,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 +846,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 +990,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 +1025,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 +1048,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 +1192,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 +1217,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. diff --git a/module/tree/view/browse.html.php b/module/tree/view/browse.html.php index e4535386f6..8689014f17 100644 --- a/module/tree/view/browse.html.php +++ b/module/tree/view/browse.html.php @@ -12,6 +12,7 @@ ?> +type != 'normal') ? true : false;?>
    tree->common;?>
    @@ -74,9 +75,20 @@ { if($sonModule->order > $maxOrder) $maxOrder = $sonModule->order; $disabled = $sonModule->type == $viewType ? '' : 'disabled="true"'; - echo '' . html::input("modules[id$sonModule->id]", $sonModule->name, 'class=form-control style="margin-bottom:5px" ' . $disabled) . ''; + echo $hasBranch ? "
    " : "
    "; + echo html::input("modules[id$sonModule->id]", $sonModule->name, 'class="form-control"' . $disabled); + if($hasBranch) echo '' . html::select("branch[id$sonModule->id]", $branches, $sonModule->branch, 'class="form-control" disabled'); + echo '
    '; + } + for($i = 0; $i < TREE::NEW_CHILD_COUNT ; $i ++) + { + echo "
    "; + echo html::input("modules[]", '', 'class="form-control"'); + if($hasBranch) echo '' . html::select("branch[]", $branches, $branch, 'class="form-control"'); + echo ""; + echo ""; + echo '
    '; } - for($i = 0; $i < TREE::NEW_CHILD_COUNT ; $i ++) echo '' . html::input("modules[]", '', 'class=form-control style="margin-bottom:5px"') . ''; ?>
    From df23f3b43e151ab81909f55dc6e45fd4b4b1f79c Mon Sep 17 00:00:00 2001 From: wangyidong Date: Thu, 22 Oct 2015 16:38:39 +0800 Subject: [PATCH 4/5] * finish task #2341. --- module/branch/control.php | 9 +++ module/bug/control.php | 17 ++++-- module/bug/js/common.js | 5 +- module/build/control.php | 10 ++++ module/product/config.php | 2 + module/product/control.php | 20 +++++-- module/product/model.php | 19 +++++-- module/product/view/browse.html.php | 6 +- module/project/control.php | 4 +- module/project/view/linkstory.html.php | 2 +- module/project/view/story.html.php | 2 +- module/release/control.php | 19 ++++++- module/story/control.php | 67 +++++++++++++---------- module/story/css/create.css | 1 + module/story/js/view.js | 2 +- module/story/lang/zh-cn.php | 1 + module/story/model.php | 14 +++-- module/story/view/create.html.php | 5 +- module/story/view/edit.html.php | 7 ++- module/story/view/header.html.php | 32 +++++++++-- module/story/view/view.html.php | 15 +++-- module/testcase/control.php | 19 ++++--- module/testcase/js/batchcreate.js | 7 +-- module/testcase/js/common.js | 3 +- module/testcase/js/create.js | 2 +- module/testcase/view/batchcreate.html.php | 1 + module/tree/model.php | 13 ++++- 27 files changed, 213 insertions(+), 91 deletions(-) diff --git a/module/branch/control.php b/module/branch/control.php index 243754caae..1e105daac2 100644 --- a/module/branch/control.php +++ b/module/branch/control.php @@ -47,5 +47,14 @@ class branch extends control $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'")); + } } diff --git a/module/bug/control.php b/module/bug/control.php index cf7613ad98..73e915c78f 100644 --- a/module/bug/control.php +++ b/module/bug/control.php @@ -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'); - $stories = $this->story->getProductStoryPairs($productID); + $stories = $this->story->getProductStoryPairs($productID, $branch); } $this->view->title = $this->products[$productID] . $this->lang->colon . $this->lang->bug->create; @@ -346,6 +348,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(); } @@ -359,7 +364,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)) { @@ -381,7 +386,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) @@ -538,7 +543,7 @@ class bug extends control $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->resolvedBuilds = array('' => '') + $this->view->openedBuilds; diff --git a/module/bug/js/common.js b/module/bug/js/common.js index efe0107e35..c2f8e3a927 100644 --- a/module/bug/js/common.js +++ b/module/bug/js/common.js @@ -73,7 +73,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);}); } @@ -213,7 +213,8 @@ function loadProjectBuilds(projectID) */ function setStories(moduleID, productID) { - link = createLink('story', 'ajaxGetProductStories', 'productID=' + productID + '&moduleID=' + moduleID); + branch = $('#branch').val(); + link = createLink('story', 'ajaxGetProductStories', 'productID=' + productID + '&branch=' + branch + '&moduleID=' + moduleID); $.get(link, function(stories) { if(!stories) stories = ''; diff --git a/module/build/control.php b/module/build/control.php index f868cddfac..08b160b847 100644 --- a/module/build/control.php +++ b/module/build/control.php @@ -245,6 +245,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']); @@ -254,6 +255,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') diff --git a/module/product/config.php b/module/product/config.php index 2c7c88ff47..75877e96da 100644 --- a/module/product/config.php +++ b/module/product/config.php @@ -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' => ''); diff --git a/module/product/control.php b/module/product/control.php index f63e692f93..dbd11f3e87 100644 --- a/module/product/control.php +++ b/module/product/control.php @@ -106,7 +106,7 @@ class product extends control * @access public * @return void */ - public function browse($productID = 0, $branch = 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,7 +117,8 @@ class product extends control /* Set product, module and query. */ $productID = $this->product->saveState($productID, $this->products); - if(empty($branch)) $branch = $this->session->branch; + $product = $this->product->getById($productID); + if($branch === '') $branch = $this->session->branch; $moduleID = ($browseType == 'bymodule') ? (int)$param : 0; $queryID = ($browseType == 'bysearch') ? (int)$param : 0; @@ -171,13 +172,22 @@ class product extends control $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); @@ -507,9 +517,9 @@ 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) { diff --git a/module/product/model.php b/module/product/model.php index aee245a32c..e4c3f0bb0a 100644 --- a/module/product/model.php +++ b/module/product/model.php @@ -22,7 +22,7 @@ class productModel extends model * @access public * @return void */ - public function setMenu($products, $productID, $branch = '', $extra = '') + public function setMenu($products, $productID, $branch = 0, $extra = '') { /* Has access privilege?. */ if($products and !isset($products[$productID]) and !$this->checkPriv($this->getById($productID))) @@ -57,12 +57,12 @@ class productModel extends model * @access public * @return string */ - public function select($products, $productID, $currentModule, $currentMethod, $extra = '', $branch = '') + public function select($products, $productID, $currentModule, $currentMethod, $extra = '', $branch = 0) { if(!$productID) return; setCookie("lastProduct", $productID, $this->config->cookieLife, $this->config->webRoot); - setCookie("lastBranch", $branch, $this->config->cookieLife, $this->config->webRoot); + setCookie("lastBranch", "$productID-$branch", $this->config->cookieLife, $this->config->webRoot); $currentProduct = $this->getById($productID); $output = "{$currentProduct->name}
    "; if($currentProduct->type != 'normal') @@ -88,8 +88,15 @@ 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)); + + 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; } @@ -690,7 +697,7 @@ class productModel extends model } else { - $link = helper::createLink($module, $method, "productID=%s"); + $link = helper::createLink($module, $method, "productID=%s&branch=%s"); } } else if($module == 'productplan' || $module == 'release') @@ -700,7 +707,7 @@ class productModel extends model } else if($module == 'tree') { - $link = helper::createLink($module, $method, "productID=%s&type=$extra" . ($branch ? "&branch=%s" : '')); + $link = helper::createLink($module, $method, "productID=%s&type=$extra"); } return $link; } diff --git a/module/product/view/browse.html.php b/module/product/view/browse.html.php index 85210b309e..e1bc979f21 100644 --- a/module/product/view/browse.html.php +++ b/module/product/view/browse.html.php @@ -47,8 +47,8 @@
    @@ -130,7 +130,7 @@ createLink('story', 'batchEdit', "productID=$productID&projectID=0"); + $actionLink = $this->createLink('story', 'batchEdit', "productID=$productID&projectID=0&branch=$branch"); ?>
    edit, "onclick=\"setFormAction('$actionLink')\" $disabled");?> diff --git a/module/project/control.php b/module/project/control.php index 7315fefcaf..981c20e997 100644 --- a/module/project/control.php +++ b/module/project/control.php @@ -1516,6 +1516,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; @@ -1528,7 +1530,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); diff --git a/module/project/view/linkstory.html.php b/module/project/view/linkstory.html.php index ed31e99f3d..700679590d 100644 --- a/module/project/view/linkstory.html.php +++ b/module/project/view/linkstory.html.php @@ -45,7 +45,7 @@ id));?>
    - + diff --git a/module/project/view/story.html.php b/module/project/view/story.html.php index 9c2e873d8e..3aa370c06c 100644 --- a/module/project/view/story.html.php +++ b/module/project/view/story.html.php @@ -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'); ?> diff --git a/module/release/control.php b/module/release/control.php index bbf0c2db38..96c8c94507 100644 --- a/module/release/control.php +++ b/module/release/control.php @@ -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') diff --git a/module/story/control.php b/module/story/control.php index f862f887d8..fb533d0515 100644 --- a/module/story/control.php +++ b/module/story/control.php @@ -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) diff --git a/module/story/css/create.css b/module/story/css/create.css index 73c283b6c5..03216bd698 100644 --- a/module/story/css/create.css +++ b/module/story/css/create.css @@ -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%} diff --git a/module/story/js/view.js b/module/story/js/view.js index c7329b89bb..180672d6e5 100644 --- a/module/story/js/view.js +++ b/module/story/js/view.js @@ -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("
  • " + createStory + "
  • "); } }); diff --git a/module/story/lang/zh-cn.php b/module/story/lang/zh-cn.php index 70ff48f550..f666910bc6 100644 --- a/module/story/lang/zh-cn.php +++ b/module/story/lang/zh-cn.php @@ -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'; diff --git a/module/story/model.php b/module/story/model.php index 1f8502f1e1..e80bc04394 100644 --- a/module/story/model.php +++ b/module/story/model.php @@ -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; @@ -932,7 +937,7 @@ class storyModel extends model ->from(TABLE_STORY)->alias('t1') ->leftJoin(TABLE_PRODUCTPLAN)->alias('t2')->on('t1.plan = t2.id') ->where('t1.product')->in($productID) - ->beginIF(!empty($branch))->andWhere("CONCAT(',', t1.branch, ',')")->like("%,$branch,%")->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) @@ -950,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) @@ -1101,7 +1107,7 @@ class storyModel extends model * @access public * @return array */ - public function getBySearch($productID, $branch, $queryID, $orderBy, $pager = null, $projectID = '') + public function getBySearch($productID, $queryID, $orderBy, $pager = null, $projectID = '') { if($projectID != '') { diff --git a/module/story/view/create.html.php b/module/story/view/create.html.php index d70be860d4..a982264f73 100644 --- a/module/story/view/create.html.php +++ b/module/story/view/create.html.php @@ -25,7 +25,10 @@
    idAB);?> priAB);?> story->title);?>product->RD;?>
    product->type;?>product->typeList, 'normal', "class='form-control'");?>
    product->desc;?> product->RD;?> RD, "class='form-control chosen'");?>
    product->type;?>product->typeList, $product->type, "class='form-control'");?>
    product->status;?> product->statusList, $product->status, "class='form-control'");?>product->RD;?> RD];?>
    product->type;?>product->typeList[$product->type];?>
    product->status;?> product->statusList[$product->status];?>story->priList, $story->pri, $story->pri)?>'>story->priList, $story->pri, $story->pri);?>createLink('product', 'browse', "productID=$story->product"), $products[$story->product], '_blank');?>createLink('product', 'browse', "productID=$story->product&branch=$story->branch"), $products[$story->product], '_blank');?> title);?> planTitle;?> openedBy];?>
    story->product;?> - +
    + + type != 'normal') echo html::select('branch', $branches, $branch, "onchange='loadBranch();' class='form-control' style='width:65px'");?> +
    diff --git a/module/story/view/edit.html.php b/module/story/view/edit.html.php index c995045f2f..5e5874d9e1 100644 --- a/module/story/view/edit.html.php +++ b/module/story/view/edit.html.php @@ -55,7 +55,12 @@ - + diff --git a/module/story/view/header.html.php b/module/story/view/header.html.php index 64872306ff..f90d1c949b 100644 --- a/module/story/view/header.html.php +++ b/module/story/view/header.html.php @@ -3,13 +3,35 @@
    story->product;?>product, 'class="form-control chosen" onchange="loadProduct(this.value)";');?> +
    + product, "onchange='loadProduct(this.value);' class='form-control chosen'");?> + type != 'normal') echo html::select('branch', $branches, $story->branch, "onchange='loadBranch();' class='form-control' style='width:65px'");?> +
    +
    story->module;?>