diff --git a/module/common/lang/zh-cn.php b/module/common/lang/zh-cn.php index 7469bf1b5f..6a8645c4ab 100755 --- a/module/common/lang/zh-cn.php +++ b/module/common/lang/zh-cn.php @@ -134,11 +134,12 @@ $lang->mainNav->program = ' 项目集|pro $lang->mainNav->product = ' 产品|product|index|'; $lang->mainNav->project = ' 项目|program|prjbrowse|'; $lang->mainNav->repo = ' 代码|repo|browse|'; +$lang->mainNav->doc = ' 文档|doc|index|'; $lang->mainNav->system = ' 组织|subject|browse|'; $lang->mainNav->admin = ' 后台|admin|index|'; $lang->reporting = new stdclass(); -$lang->dividerMenu = ',admin,project,repo,'; +$lang->dividerMenu = ',admin,project,doc,'; /* Program set menu. */ $lang->program = new stdclass(); diff --git a/module/doc/control.php b/module/doc/control.php index dea7e65e23..5aaea8446f 100644 --- a/module/doc/control.php +++ b/module/doc/control.php @@ -27,6 +27,8 @@ class doc extends control $this->loadModel('project'); $this->from = $this->cookie->from ? $this->cookie->from : 'doc'; $this->productID = $this->cookie->product ? $this->cookie->product : '0'; + $this->projectID = $this->session->PRJ; + if(!$this->projectID) $this->lang->navGroup->doc = 'doc'; } /** @@ -60,7 +62,7 @@ class doc extends control $this->view->myDocs = $this->doc->getDocsByBrowseType(0, 'openedbyme', 0, 0, 'addedDate_desc', $pager); $this->view->statisticInfo = $this->doc->getStatisticInfo(); $this->view->users = $this->loadModel('user')->getPairs('noletter'); - $this->view->doingProjects = $this->loadModel('project')->getExecutionsByProject($this->session->PRJ, 'undone', 5); + $this->view->doingProjects = $this->loadModel('project')->getExecutionsByProject($this->projectID, 'undone', 5); $this->display(); } diff --git a/module/doc/model.php b/module/doc/model.php index 5b7fd9a36f..147bed3fcd 100644 --- a/module/doc/model.php +++ b/module/doc/model.php @@ -524,13 +524,13 @@ class docModel extends model * @access public * @return void */ - public function getPrivDocs($libID = 0, $module = 0, $mode = 'normal') + public function getPrivDocs($libIdList = array(), $module = 0, $mode = 'normal') { $stmt = $this->dao->select('*')->from(TABLE_DOC) ->where('1=1') ->beginIF($mode == 'normal')->andWhere('deleted')->eq(0)->fi() ->beginIF($this->config->doc->notArticleType)->andWhere('type')->notIN($this->config->doc->notArticleType)->fi() - ->beginIF($libID)->andWhere('lib')->in($libID)->fi() + ->beginIF($libIdList)->andWhere('lib')->in($libIdList)->fi() ->beginIF(strpos($this->config->doc->custom->showLibs, 'children') === false)->andWhere('module')->in($module)->fi() ->beginIF(!empty($module) and strpos($this->config->doc->custom->showLibs, 'children') !== false)->andWhere('module')->in($module)->fi() ->query(); @@ -621,7 +621,6 @@ class docModel extends model ->add('editedDate', $now) ->add('version', 1) ->setDefault('product,project,module', 0) - ->setDefault('PRJ', $this->session->PRJ) ->stripTags($this->config->doc->editor->create['id'], $this->config->allowedTags) ->cleanInt('product,project,module,lib') ->join('groups', ',') @@ -999,7 +998,7 @@ class docModel extends model if($type == 'project') { $project = $this->loadModel('program')->getPRJByID($this->session->PRJ); - $orderBy = $project->model == 'waterfall' ? 'begin_asc,id_asc' : 'begin_desc,id_desc'; + $orderBy = (isset($project->model) and $project->model) == 'waterfall' ? 'begin_asc,id_asc' : 'begin_desc,id_desc'; } $table = $type == 'product' ? TABLE_PRODUCT : TABLE_PROJECT; @@ -1137,16 +1136,7 @@ class docModel extends model ->where('deleted')->eq(0) ->andWhere("$type")->in(array_keys($objectList)) ->orderBy("`order` asc, id asc") - ->fetchAll('project'); - - if($type == 'project') - { - foreach(array_keys($objectList) as $objectID) - { - $docLibs[] = $docLibs[$objectID]; - unset($docLibs[$objectID]); - } - } + ->fetchAll(); } else { @@ -1532,9 +1522,9 @@ class docModel extends model */ public function getStatisticInfo() { - $libID = 0; - if($this->session->PRJ) $libID = $this->getLibIdListByProject($this->session->PRJ); - $docIdList = $this->getPrivDocs($libID); + $libIdList = array(); + $libIdList = $this->getLibIdListByProject($this->session->PRJ); + $docIdList = $this->getPrivDocs($libIdList); $today = date('Y-m-d'); $lately = date('Y-m-d', strtotime('-3 day')); diff --git a/module/index/js/index.js b/module/index/js/index.js index ea37e07025..b79947b6d9 100644 --- a/module/index/js/index.js +++ b/module/index/js/index.js @@ -120,7 +120,11 @@ /* Update tab state */ tab.show = true; - lastOpenedGroup = group; + if(lastOpenedGroup !== group) + { + lastOpenedGroup = group; + updateTabUrl(group); + } } /** @@ -225,6 +229,30 @@ } } + /** + * Update browser url and title for the given tab + * @param {string} group The group of target tab to update url + * @param {string|boolean} [url] The new url of the tab + * @param {string|boolean} [title] The new title of the tab + * @return {void} + */ + function updateTabUrl(group, url, title) + { + var tab = openedTabs[group]; + if(!tab) return; + + if(url) tab.pageUrl = url; + else url = tab.pageUrl; + if(title) tab.pageTitle = title; + else title = tab.pageTitle || tab.text; + + if(lastOpenedGroup === group) + { + if(location.url !== url) history.replaceState({}, title, url); + document.title = title; + } + } + /* Bind helper methods to global object "$.tabs" */ $.tabs = window.tabs = { @@ -234,6 +262,7 @@ toggle: toggleTab, close: closeTab, reload: reloadTab, + updateUrl: updateTabUrl, openedTabs: openedTabs, groupsMap: groupsMap }; diff --git a/module/my/control.php b/module/my/control.php index b2beb421bb..dec792de13 100644 --- a/module/my/control.php +++ b/module/my/control.php @@ -269,6 +269,7 @@ class my extends control * My tasks * * @param string $type + * @param string $orderBy * @param int $recTotal * @param int $recPerPage * @param int $pageID @@ -458,7 +459,6 @@ class my extends control * My projects. * * @param string $status doing|wait|suspended|closed|openedbyme - * @param string $orderBy * @param int $recTotal * @param int $recPerPage * @param int $pageID @@ -519,7 +519,12 @@ class my extends control * My issues. * * @access public - * @return void + * @param string $type + * @param string $orderBy + * @param int $recTotal + * @param int $recPerPage + * @param int $pageID + * @return void */ public function issue($type = 'assignedTo', $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1) { @@ -542,6 +547,11 @@ class my extends control * My risks. * * @access public + * @param string $type + * @param string $orderBy + * @param int $recTotal + * @param int $recPerPage + * @param int $pageID * @return void */ public function risk($type = 'assignedTo', $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1) diff --git a/module/personnel/control.php b/module/personnel/control.php index 149a4af298..38fbf1247b 100644 --- a/module/personnel/control.php +++ b/module/personnel/control.php @@ -86,7 +86,8 @@ class personnel extends control * Get white list personnel. * * @param int $objectID - * @param string $browsetype + * @param string $module personnel|program + * @param string $objectType program|project|product|sprint * @param string $orderby * @param int $recTotal * @param int $recPerPage @@ -97,14 +98,16 @@ class personnel extends control public function whitelist($objectID = 0, $module = 'personnel', $objectType = 'program', $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1) { if($module == 'personnel') $this->setProgramNavMenu($objectID); + + /* Load lang and set session. */ $this->app->loadLang('user'); $this->app->session->set('whitelistBrowse', $this->app->getURI(true)); + /* Load pager. */ $this->app->loadClass('pager', true); $pager = pager::init($recTotal, $recPerPage, $pageID); - $whitelist = $this->personnel->getWhitelist($objectID, $objectType, $orderBy, $pager); - + /* Set back link. */ if($module == 'program') { $goback = $this->session->PRJBrowse ? $this->session->PRJBrowse : $this->createLink('program', 'PRJBrowse'); @@ -113,9 +116,10 @@ class personnel extends control $this->view->title = $this->lang->personnel->whitelist; $this->view->position[] = $this->lang->personnel->whitelist; + $this->view->pager = $pager; $this->view->objectID = $objectID; - $this->view->whitelist = $whitelist; + $this->view->whitelist = $this->personnel->getWhitelist($objectID, $objectType, $orderBy, $pager); $this->view->depts = $this->loadModel('dept')->getOptionMenu(); $this->view->module = $module; @@ -128,6 +132,7 @@ class personnel extends control * @param int $objectID * @param int $deptID * @param string $objectType program|project|product|sprint + * @param string $module * @access public * @return void */ diff --git a/module/product/css/all.css b/module/product/css/all.css index 5a8b1d48bb..5cf509133d 100644 --- a/module/product/css/all.css +++ b/module/product/css/all.css @@ -37,5 +37,5 @@ .main-table thead>tr:first-of-type>th {border-left: 1px solid #ddd;} th.table-nest-title .table-nest-toggle {margin-top: 15px; margin-left: 6px;} th.table-nest-title .header {margin-left: 5px;} -th.table-nest-title .sort-up {padding-left: 10px;} -th.table-nest-title .sort-down {padding-left: 10px;} +th.table-nest-title .sort-up {padding-left: 5px;} +th.table-nest-title .sort-down {padding-left: 5px;} diff --git a/module/product/js/all.js b/module/product/js/all.js index 8cdfe4b64e..23468a62d9 100644 --- a/module/product/js/all.js +++ b/module/product/js/all.js @@ -1,13 +1,17 @@ $("#" + browseType + "Tab").addClass('btn-active-text'); $(function() { + /* Init table sort. */ var $list = $('#productTableList'); $list.addClass('sortable').sortable( { + /* Init vars. */ reverse: orderBy === 'order_desc', selector: 'tr', dragCssClass: 'drag-row', trigger: $list.find('.sort-handler').length ? '.sort-handler' : null, + + /* Set movable conditions. */ canMoveHere: function($ele, $target) { return $ele.data('parent') === $target.data('parent'); @@ -16,6 +20,8 @@ $(function() { e.targets.filter('[data-parent!="' + e.element.attr('data-parent') + '"]').addClass('drop-not-allowed'); }, + + /* Update order sort. */ finish: function(e) { var products = ''; diff --git a/module/product/model.php b/module/product/model.php index 0810279b68..71240a2c9c 100644 --- a/module/product/model.php +++ b/module/product/model.php @@ -337,9 +337,9 @@ class productModel extends model ->from(TABLE_PROJECTPRODUCT)->alias('t1') ->leftJoin(TABLE_PRODUCT)->alias('t2') ->on('t1.product = t2.id') - ->where('t1.project')->eq($projectID) + ->where('t2.deleted')->eq(0) + ->beginIF($projectID)->andWhere('t1.project')->eq($projectID)->fi() ->beginIF(strpos($status, 'noclosed') !== false)->andWhere('status')->ne('closed')->fi() - ->andWhere('t2.deleted')->eq(0) ->orderBy('t2.order desc') ->fetchAll('id'); } @@ -354,7 +354,10 @@ class productModel extends model */ public function getProductIDByProject($projectID, $isFirst = true) { - $products = $this->dao->select('product')->from(TABLE_PROJECTPRODUCT)->where('project')->eq($projectID)->fetchPairs(); + $products = $this->dao->select('product')->from(TABLE_PROJECTPRODUCT) + ->beginIF($projectID)->where('project')->eq($projectID)->fi() + ->fetchPairs(); + if($isFirst === false) return $products; return empty($products) ? 0 : current($products); } diff --git a/module/program/control.php b/module/program/control.php index f6d2b67087..9ece2e61df 100644 --- a/module/program/control.php +++ b/module/program/control.php @@ -221,9 +221,14 @@ class program extends control { $this->lang->navGroup->program = 'program'; $this->loadModel('action'); + $program = $this->program->getPGMByID($programID); if(!empty($_POST)) { + /* Only when all subprograms and subprojects are closed can the program be closed. */ + $hasUnfinished = $this->program->hasUnfinished($program); + if($hasUnfinished) die(js::error($this->lang->program->PGMCloseErrorMessage)); + $changes = $this->project->close($programID); if(dao::isError()) die(js::error(dao::getError())); @@ -232,12 +237,14 @@ class program extends control $actionID = $this->action->create('program', $programID, 'Closed', $this->post->comment); $this->action->logHistory($actionID, $changes); } + + $this->executeHooks($programID); die(js::reload('parent.parent')); } $this->view->title = $this->lang->program->PGMClose; $this->view->position[] = $this->lang->program->PGMClose; - $this->view->project = $this->program->getPGMByID($programID); + $this->view->project = $program; $this->view->users = $this->loadModel('user')->getPairs('noletter'); $this->view->actions = $this->action->getList('program', $programID); @@ -356,8 +363,8 @@ class program extends control /** * Delete a program. * - * @param int $projectID - * @param varchar $confirm + * @param int $projectID + * @param string $confirm yes|no * @access public * @return void */ @@ -1257,6 +1264,7 @@ class program extends control { $this->lang->navGroup->program = 'project'; $this->loadModel('action'); + $project = $this->program->getPRJByID($projectID); if(!empty($_POST)) { @@ -1268,13 +1276,37 @@ class program extends control $actionID = $this->action->create('project', $projectID, 'Started', $this->post->comment); $this->action->logHistory($actionID, $changes); } + + /* Start all superior programs. */ + if($project->parent) + { + $path = explode(',', $project->path); + $path = array_filter($path); + foreach($path as $programID) + { + if($programID == $projectID) continue; + $program = $this->program->getPGMByID($programID); + if($program->status == 'wait' || $program->status == 'suspended') + { + $changes = $this->project->start($programID); + if(dao::isError()) die(js::error(dao::getError())); + + if($this->post->comment != '' or !empty($changes)) + { + $actionID = $this->action->create('program', $programID, 'Started', $this->post->comment); + $this->action->logHistory($actionID, $changes); + } + } + } + } + $this->executeHooks($projectID); die(js::reload('parent.parent')); } $this->view->title = $this->lang->project->start; $this->view->position[] = $this->lang->project->start; - $this->view->project = $this->program->getPRJByID($projectID); + $this->view->project = $project; $this->view->users = $this->loadModel('user')->getPairs('noletter'); $this->view->actions = $this->action->getList('project', $projectID); $this->display(); diff --git a/module/program/lang/de.php b/module/program/lang/de.php index d846d84031..7afc677441 100644 --- a/module/program/lang/de.php +++ b/module/program/lang/de.php @@ -205,6 +205,7 @@ $lang->program->PGMBeginLetterParent = "Parent begin date: %s, begin date should $lang->program->PGMEndGreaterParent = "Parent end date: %s, end date should be <= parent end date."; $lang->program->PGMBeginGreateChild = "Child earliest begin: %s, parent begin date <= child earliest begin date."; $lang->program->PGMEndLetterChild = "Child latest end: %s, parent end date >= child latest end date."; +$lang->program->PGMCloseErrorMessage = 'There are subprograms or projects that are not closed'; $lang->program->stakeholderTypeList['inside'] = 'Inside'; $lang->program->stakeholderTypeList['outside'] = 'Outside'; diff --git a/module/program/lang/en.php b/module/program/lang/en.php index a690b4331f..fd8a597979 100644 --- a/module/program/lang/en.php +++ b/module/program/lang/en.php @@ -205,6 +205,7 @@ $lang->program->PGMBeginLetterParent = "Parent begin date: %s, begin date should $lang->program->PGMEndGreaterParent = "Parent end date: %s, end date should be <= parent end date."; $lang->program->PGMBeginGreateChild = "Child earliest begin: %s, parent begin date <= child earliest begin date."; $lang->program->PGMEndLetterChild = "Child latest end: %s, parent end date >= child latest end date."; +$lang->program->PGMCloseErrorMessage = 'There are subprograms or projects that are not closed'; $lang->program->stakeholderTypeList['inside'] = 'Inside'; $lang->program->stakeholderTypeList['outside'] = 'Outside'; diff --git a/module/program/lang/fr.php b/module/program/lang/fr.php index d846d84031..7afc677441 100644 --- a/module/program/lang/fr.php +++ b/module/program/lang/fr.php @@ -205,6 +205,7 @@ $lang->program->PGMBeginLetterParent = "Parent begin date: %s, begin date should $lang->program->PGMEndGreaterParent = "Parent end date: %s, end date should be <= parent end date."; $lang->program->PGMBeginGreateChild = "Child earliest begin: %s, parent begin date <= child earliest begin date."; $lang->program->PGMEndLetterChild = "Child latest end: %s, parent end date >= child latest end date."; +$lang->program->PGMCloseErrorMessage = 'There are subprograms or projects that are not closed'; $lang->program->stakeholderTypeList['inside'] = 'Inside'; $lang->program->stakeholderTypeList['outside'] = 'Outside'; diff --git a/module/program/lang/vi.php b/module/program/lang/vi.php index d846d84031..7afc677441 100644 --- a/module/program/lang/vi.php +++ b/module/program/lang/vi.php @@ -205,6 +205,7 @@ $lang->program->PGMBeginLetterParent = "Parent begin date: %s, begin date should $lang->program->PGMEndGreaterParent = "Parent end date: %s, end date should be <= parent end date."; $lang->program->PGMBeginGreateChild = "Child earliest begin: %s, parent begin date <= child earliest begin date."; $lang->program->PGMEndLetterChild = "Child latest end: %s, parent end date >= child latest end date."; +$lang->program->PGMCloseErrorMessage = 'There are subprograms or projects that are not closed'; $lang->program->stakeholderTypeList['inside'] = 'Inside'; $lang->program->stakeholderTypeList['outside'] = 'Outside'; diff --git a/module/program/lang/zh-cn.php b/module/program/lang/zh-cn.php index a0fa3fd641..da1aa24333 100644 --- a/module/program/lang/zh-cn.php +++ b/module/program/lang/zh-cn.php @@ -205,6 +205,7 @@ $lang->program->PGMBeginLetterParent = "父项目集的开始日期:%s,开 $lang->program->PGMEndGreaterParent = "父项目集的完成日期:%s,完成日期不能大于父项目集的完成日期"; $lang->program->PGMBeginGreateChild = "子项目集的最小开始日期:%s,父项目集的开始日期不能大于子项目集的最小开始日期"; $lang->program->PGMEndLetterChild = "子项目的最大完成日期:%s,父项目的完成日期不能小于子项目的最大完成日期"; +$lang->program->PGMCloseErrorMessage = '存在子项目集或项目为未关闭状态'; $lang->program->stakeholderTypeList['inside'] = '内部'; $lang->program->stakeholderTypeList['outside'] = '外部'; diff --git a/module/program/lang/zh-tw.php b/module/program/lang/zh-tw.php index f0a0471ac2..d12ede9ca6 100644 --- a/module/program/lang/zh-tw.php +++ b/module/program/lang/zh-tw.php @@ -22,6 +22,7 @@ $lang->program->PRJManageView = '項目維護視野'; $lang->program->PRJManagePriv = '項目維護權限'; $lang->program->PRJManageMembers = '項目團隊'; $lang->program->export = '導出'; +$lang->program->addProduct = '新建產品'; $lang->program->PRJManageGroupMember = '維護分組用戶'; $lang->program->PRJModuleSetting = '列表設置'; $lang->program->PRJModuleOpen = '顯示項目集名'; @@ -29,18 +30,15 @@ $lang->program->PRJUpdateOrder = '排序'; $lang->program->PRJSort = '項目排序'; $lang->program->PRJWhitelist = '項目白名單'; $lang->program->PRJAddWhitelist = '項目添加白名單'; +$lang->program->PRJStoryConcept = '需求概念組合'; $lang->program->unbindWhielist = '項目刪除白名單'; $lang->program->PRJManageProducts = '關聯產品'; $lang->program->view = '項目集詳情'; -$lang->program->copyTitle = '請選擇一個項目來複制'; +$lang->program->copyTitle = '請選擇要複製的項目'; $lang->program->errorSameProducts = '項目不能關聯多個相同的產品。'; $lang->program->errorNoProducts = '最少關聯一個產品'; $lang->program->copyNoProject = '沒有可用的項目來複制'; -$lang->program->PRJSource = '項目來源:'; -$lang->program->PRJStandalone = '沒有所屬項目集的項目'; -$lang->program->tips = '提示'; -$lang->program->setTeam = '設置團隊'; -$lang->program->goback = '返回項目列表'; +$lang->project->searchByName = '輸入項目名稱進行檢索'; /* Fields. */ $lang->program->common = '項目集'; @@ -148,7 +146,7 @@ $lang->program->scrum = 'Scrum'; $lang->program->waterfall = '瀑布'; $lang->program->waterfallTitle = '瀑布式項目管理'; $lang->program->cannotCreateChild = '該項目已經有實際的內容,無法直接添加子項目。您可以為當前項目創建一個父項目,然後在新的父項目下面添加子項目。'; -$lang->program->hasChildren = '該項目集有子項目集或子項目存在,不能刪除。'; +$lang->program->hasChildren = '該項目集有子項目集或項目存在,不能刪除。'; $lang->program->confirmDelete = "您確定要刪除嗎?"; $lang->program->emptyPM = '暫無'; $lang->program->cannotChangeToCat = "該項目已經有實際的內容,無法修改為父項目"; @@ -156,7 +154,6 @@ $lang->program->cannotCancelCat = "該項目下已經有子項目,無法取 $lang->program->parentBeginEnd = "父項目起止時間:%s ~ %s"; $lang->program->childLongTime = "子項目中有長期項目,父項目也應該是長期項目"; $lang->program->readjustTime = '重新調整項目起止時間'; -$lang->program->afterInfo = "項目添加成功,您現在可以進行以下操作:"; $lang->program->PRJProgramTitle['0'] = '不顯示'; $lang->program->PRJProgramTitle['base'] = '只顯示一級項目集'; @@ -208,8 +205,9 @@ $lang->program->PGMBeginLetterParent = "父項目集的開始日期:%s,開 $lang->program->PGMEndGreaterParent = "父項目集的完成日期:%s,完成日期不能大於父項目集的完成日期"; $lang->program->PGMBeginGreateChild = "子項目集的最小開始日期:%s,父項目集的開始日期不能大於子項目集的最小開始日期"; $lang->program->PGMEndLetterChild = "子項目的最大完成日期:%s,父項目的完成日期不能小於子項目的最大完成日期"; +$lang->program->PGMCloseErrorMessage = '存在子項目集或項目為未關閉狀態'; -$lang->program->stakeholderTypeList['inside'] = '内部'; +$lang->program->stakeholderTypeList['inside'] = '內部'; $lang->program->stakeholderTypeList['outside'] = '外部'; /* Fields. */ @@ -230,7 +228,7 @@ $lang->program->PGMLongTime = '長期項目'; $lang->program->noPGM = '暫時沒有項目集'; $lang->program->PGMShowClosed = '顯示已關閉'; -$lang->program->PGMTips = '修改父項目集,可關聯產品也會發生變化,並且變為必填,如果未選擇任何項目集,則系統會預設創建一個和該項目同名的產品並關聯到該項目。'; +$lang->program->PGMTips = '選擇了父項目集,則可關聯該父項目集下的產品。如果項目未選擇任何項目集,則系統會預設創建一個和該項目同名的產品並關聯該項目。'; $lang->program->PGMChangeTips = '修改父項目集後,項目已關聯的產品會被清空,並且項目下的需求、bug等數據也會受影響,是否修改?'; $lang->program->PGMAclList['private'] = "私有(項目集負責人和干係人可訪問,干係人可後續維護)"; diff --git a/module/program/model.php b/module/program/model.php index 1d3b02faad..de04dff541 100644 --- a/module/program/model.php +++ b/module/program/model.php @@ -445,13 +445,32 @@ class programModel extends model * * @param int $programID * @access public - * @return void + * @return int */ public function getChildren($programID = 0) { return $this->dao->select('count(*) as count')->from(TABLE_PROGRAM)->where('parent')->eq($programID)->fetch('count'); } + /** + * Judge whether there is an unclosed programs or projects. + * + * @param object $program + * @access public + * @return int + */ + public function hasUnfinished($program) + { + $unfinished = $this->dao->select("count(IF(id != {$program->id}, true, null)) as count")->from(TABLE_PROJECT) + ->where('type')->in('program,project') + ->andWhere('path')->like($program->path . '%') + ->andWhere('status')->ne('closed') + ->andWhere('deleted')->eq('0') + ->fetch('count'); + + return $unfinished; + } + /** * Get stakeholders by program id. * @@ -792,7 +811,7 @@ class programModel extends model $path = ''; if($programID) { - $program = $this->getPRJByID($programID); + $program = $this->getPGMByID($programID); $path = $program->path; } diff --git a/module/project/control.php b/module/project/control.php index 31892ce0c2..c998a7a4fa 100644 --- a/module/project/control.php +++ b/module/project/control.php @@ -21,7 +21,7 @@ class project extends control public function __construct($moduleName = '', $methodName = '') { parent::__construct($moduleName, $methodName); - if(!in_array($this->methodName, array('computeburn', 'ajaxgetrecentexecutions')) && $this->session->PRJ) + if(!in_array($this->methodName, array('computeburn', 'ajaxgetrecentexecutions'))) { $this->projects = $this->project->getExecutionPairs($this->session->PRJ, 'all', 'nocode'); if(!$this->projects and $this->methodName != 'index' and $this->methodName != 'create' and $this->app->getViewType() != 'mhtml') $this->locate($this->createLink('project', 'create')); diff --git a/module/project/model.php b/module/project/model.php index c03e4df448..dcba2891c3 100644 --- a/module/project/model.php +++ b/module/project/model.php @@ -1005,10 +1005,11 @@ class projectModel extends model public function getExecutionIdList($projectID, $status = 'all') { return $this->dao->select('id')->from(TABLE_EXECUTION) - ->where('project')->eq($projectID) + ->where('deleted')->eq('0') + ->beginIF($projectID)->andWhere('project')->eq($projectID)->fi() ->beginIF($status == 'undone')->andWhere('status')->notIN('done,closed')->fi() ->beginIF($status != 'all' and $status != 'undone')->andWhere('status')->in($status)->fi() - ->andWhere('deleted')->eq('0') + ->andWhere('type')->in('sprint,stage') ->fetchPairs('id', 'id'); } @@ -1024,22 +1025,21 @@ class projectModel extends model */ public function getExecutionsByProject($projectID, $status = 'all', $limit = 0, $pairs = false) { - if(!$projectID) return array(); - $project = $this->loadModel('program')->getPRJByID($projectID); - $orderBy = $project->model == 'waterfall' ? 'begin_asc,id_asc' : 'begin_desc,id_desc'; + $orderBy = (isset($project->model) and $project->model == 'waterfall') ? 'begin_asc,id_asc' : 'begin_desc,id_desc'; $executions = $this->dao->select('*')->from(TABLE_EXECUTION) - ->where('project')->eq((int)$projectID) + ->where('deleted')->eq('0') + ->beginIF($projectID)->andWhere('project')->eq((int)$projectID)->fi() ->beginIF(!$this->app->user->admin)->andWhere('id')->in($this->app->user->view->sprints)->fi() ->beginIF($status == 'undone')->andWhere('status')->notIN('done,closed')->fi() ->beginIF($status != 'all' and $status != 'undone')->andWhere('status')->in($status)->fi() - ->andWhere('deleted')->eq('0') + ->andWhere('type')->in('stage,sprint') ->orderBy($orderBy) ->beginIF($limit)->limit($limit)->fi() ->fetchAll('id'); - if($project->model == 'waterfall') + if(isset($project->model) and $project->model == 'waterfall') { $executionList = array(); $executionProducts = $this->dao->select('t1.project,t1.product')->from(TABLE_PROJECTPRODUCT)->alias('t1') diff --git a/module/stakeholder/model.php b/module/stakeholder/model.php index cee7827f57..a13f97368e 100644 --- a/module/stakeholder/model.php +++ b/module/stakeholder/model.php @@ -102,18 +102,18 @@ class stakeholderModel extends model return false; } - /** + /** * Batch create stakeholders for a project. * * @access public * @return void */ public function batchCreate() - { + { $this->loadModel('action'); $data = (array)fixer::input('post')->get(); - $members = $this->loadModel('project')->getTeamMemberPairs($this->session->PRJ); + $members = $this->loadModel('project')->getTeamMemberPairs($this->session->PRJ); $accounts = array_unique($data['accounts']); $oldJoin = $this->dao->select('`user`, createdDate')->from(TABLE_STAKEHOLDER)->where('objectID')->eq((int)$this->session->PRJ)->andWhere('objectType')->eq('project')->fetchPairs(); $this->dao->delete()->from(TABLE_STAKEHOLDER)->where('objectID')->eq((int)$this->session->PRJ)->andWhere('objectType')->eq('project')->exec(); diff --git a/www/js/zui/min.js b/www/js/zui/min.js index 24f7739cd5..6abf988e02 100644 --- a/www/js/zui/min.js +++ b/www/js/zui/min.js @@ -76,4 +76,4 @@ function(t){"function"==typeof define&&define.amd?define(["jquery"],t):"object"= */ function(t){function e(e){if("string"==typeof e.data){var i=e.handler,n=e.data.toLowerCase().split(" ");e.handler=function(e){if(this===e.target||!/textarea|select/i.test(e.target.nodeName)&&"text"!==e.target.type){var o="keypress"!==e.type&&t.hotkeys.specialKeys[e.which],a=String.fromCharCode(e.which).toLowerCase(),s="",r={};e.altKey&&"alt"!==o&&(s+="alt+"),e.ctrlKey&&"ctrl"!==o&&(s+="ctrl+"),e.metaKey&&!e.ctrlKey&&"meta"!==o&&(s+="meta+"),e.shiftKey&&"shift"!==o&&(s+="shift+"),o?r[s+o]=!0:(r[s+a]=!0,r[s+t.hotkeys.shiftNums[a]]=!0,"shift+"===s&&(r[t.hotkeys.shiftNums[a]]=!0));for(var l=0,h=n.length;l","/":"?","\\":"|"}},t.each(["keydown","keyup","keypress"],function(){t.event.special[this]={add:e}})}(jQuery),function(t){"use strict";function e(e,i){if(e===!1)return e;if(!e)return i;e===!0?e={add:!0,"delete":!0,edit:!0,sort:!0}:"string"==typeof e&&(e=e.split(","));var n;return Array.isArray(e)&&(n={},t.each(e,function(e,i){t.isPlainObject(i)?n[i.action]=i:n[i]=!0}),e=n),t.isPlainObject(e)&&(n={},t.each(e,function(e,i){i?n[e]=t.extend({type:e},s[e],t.isPlainObject(i)?i:null):n[e]=!1}),e=n),i?t.extend(!0,{},i,e):e}function i(e,i,n){return i=i||e.type,t(n||e.template).addClass("tree-action").attr(t.extend({"data-type":i,title:e.title||""},e.attr)).data("action",e)}var n="zui.tree",o=0,a=function(e,i){this.name=n,this.$=t(e),this.getOptions(i),this._init()},s={sort:{template:''},add:{template:''},edit:{template:''},"delete":{template:''}};a.DEFAULTS={animate:null,initialState:"normal",toggleTemplate:''},a.prototype.add=function(e,i,n,o,a){var s,r=t(e),l=this.options;if(r.is("li")?(s=r.children("ul"),s.length||(s=t("