diff --git a/db/update20.0.sql b/db/update20.0.sql index e8bbe6fb8a..f52dc6224d 100644 --- a/db/update20.0.sql +++ b/db/update20.0.sql @@ -24,10 +24,10 @@ CREATE TABLE `zt_storygrade` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8; ALTER TABLE `zt_story` ADD `grade` smallint(6) NOT NULL AFTER `parent`; -ALTER TABLE `zt_story` ADD `path` varchar(255) NULL AFTER `grade`; -update zt_story set grade = 1, path = concat(',', id, ',') where type != 'story'; -update zt_story set grade = 1, path = concat(',', id, ',') where type = 'story' and parent <= 0; -update zt_story set grade = 2, path = concat(',', parent, ',', id, ',') where type = 'story' and parent > 0; +ALTER TABLE `zt_story` ADD `top` mediumint NOT NULL DEFAULT '0' AFTER `parent`; +update zt_story set grade = 1, parent = 0, top = id where type != 'story'; +update zt_story set grade = 1, parent = 0, top = id where type = 'story' and parent <= 0; +update zt_story set grade = 2, top = parent where type = 'story' and parent > 0; INSERT INTO `zt_config` (`owner`, `module`, `section`, `key`, `value`) VALUES ('system', 'story', '', 'gradeRule', 'stepwise'); INSERT INTO `zt_config` (`owner`, `module`, `section`, `key`, `value`) VALUES ('system', 'requirement', '', 'gradeRule', 'stepwise'); diff --git a/module/product/js/browse.ui.js b/module/product/js/browse.ui.js index 08a5e55e03..6c260f7c6f 100644 --- a/module/product/js/browse.ui.js +++ b/module/product/js/browse.ui.js @@ -63,11 +63,11 @@ window.renderCell = function(result, info) const story = info.row.data; let html = ''; if(typeof modulePairs[story.rawModule] != 'undefined') html += "" + modulePairs[story.rawModule] + " "; - if(story.parent > 0) - { - if($.cookie.get('tab') == 'project') html += story.parentName + ' / '; - html += "" + (storyType == 'requirement' ? 'SR' : childrenAB) + " "; - } + if(story.parent > 0) if($.cookie.get('tab') == 'project') html += story.parentName + ' / '; + + let gradeLabel = gradeGroup[story.type][story.grade]; + if(!showGrade && story.grade < 2) gradeLabel = ''; + if(gradeLabel) html += "" + gradeLabel + " "; if(story.color) result[0].props.style = 'color: ' + story.color; if(html) result.unshift({html}); } diff --git a/module/product/ui/browse.html.php b/module/product/ui/browse.html.php index f68c60bc42..6092400bb5 100644 --- a/module/product/ui/browse.html.php +++ b/module/product/ui/browse.html.php @@ -15,6 +15,8 @@ namespace zin; data('storyType', $storyType); data('activeMenuID', $storyType); jsVar('URChanged', $this->lang->story->URChanged); +jsVar('gradeGroup', $gradeGroup); +jsVar('showGrade', $showGrade); $storyCommon = $storyType == 'requirement' ? $lang->URCommon : $lang->SRCommon; $isProjectStory = $this->app->rawModule == 'projectstory'; diff --git a/module/product/zen.php b/module/product/zen.php index 78bc0c5027..9dc85c39fc 100644 --- a/module/product/zen.php +++ b/module/product/zen.php @@ -1451,6 +1451,10 @@ class productZen extends product $projectProducts = $this->getProjectProductList($projectID, $storyType, $isProjectStory); list($branchOpt, $branchTagOpt) = $this->getBranchAndTagOption($projectID, $product, $isProjectStory); + $gradeList = $this->loadModel('story')->getGradeList(''); + $gradeGroup = array(); + foreach($gradeList as $grade) $gradeGroup[$grade->type][$grade->grade] = $grade->name; + /* Set show module by config. */ $showModule = empty($this->config->product->browse->showModule) ? 0 : $this->config->product->browse->showModule; if($isProjectStory) $showModule = empty($this->config->projectstory->story->showModule) ? 0 : $this->config->projectstory->story->showModule; @@ -1461,6 +1465,8 @@ class productZen extends product $this->view->projectID = $projectID; $this->view->project = $project; $this->view->stories = $stories; + $this->view->gradeGroup = $gradeGroup; + $this->view->showGrade = $storyType == 'story' ? count($gradeGroup[$storyType]) > 2 : count($gradeGroup[$storyType]) > 1; $this->view->storyType = $storyType; $this->view->browseType = $browseType; $this->view->isProjectStory = $isProjectStory; diff --git a/module/story/model.php b/module/story/model.php index 41cc961d1f..1bbf860cfb 100644 --- a/module/story/model.php +++ b/module/story/model.php @@ -447,8 +447,6 @@ class storyModel extends model $storyID = $this->storyTao->doCreateStory($story); if(!$storyID) return false; - $this->dao->update(TABLE_STORY)->set('path')->eq(",{$storyID},")->where('id')->eq($storyID)->exec(); - /* Upload files. */ $this->loadModel('action'); $this->loadModel('file')->updateObjectID($this->post->uid, $storyID, $story->type); @@ -466,7 +464,14 @@ class storyModel extends model if($bugID) $this->storyTao->closeBugWhenToStory($bugID, $storyID); if(!empty($story->reviewer)) $this->storyTao->doCreateReviewer($storyID, $story->reviewer); if(!empty($story->URS)) $this->storyTao->doCreateURRelations($storyID, $story->URS); - if(!empty($story->parent)) $this->subdivide($story->parent, array($storyID)); + if(!empty($story->parent)) + { + $this->subdivide($story->parent, array($storyID)); + } + else + { + $this->dao->update(TABLE_STORY)->set('top')->eq($storyID)->where('id')->eq($storyID)->exec(); + } if(!empty($story->plan)) { $this->updateStoryOrderOfPlan($storyID, (string)$story->plan); // Set story order in this plan. @@ -586,7 +591,14 @@ class storyModel extends model if(!$storyID) return array(); $this->storyTao->doCreateSpec($storyID, $story); - if($story->parent > 0) $this->subdivide($story->parent, array($storyID)); + if(!empty($story->parent)) + { + $this->subdivide($story->parent, array($storyID)); + } + else + { + $this->dao->update(TABLE_STORY)->set('top')->eq($storyID)->where('id')->eq($storyID)->exec(); + } /* Update product plan stories order. */ if(!empty($story->reviewer)) $this->storyTao->doCreateReviewer($storyID, $story->reviewer); @@ -748,10 +760,15 @@ class storyModel extends model if($story->grade != $oldStory->grade) { $gradeDiff = (int)$story->grade - (int)$oldStory->grade; - $this->dao->update(TABLE_STORY)->set("grade = grade + $gradeDiff")->where('path')->like($oldStory->path . '%')->andWhere('id')->ne($storyID)->exec(); + $this->dao->update(TABLE_STORY) + ->set("grade = grade + $gradeDiff") + ->where('top')->eq($oldStory->top) + ->andWhere('grade')->gt($oldStory->grade) + ->andWhere('id')->ne($storyID) + ->exec(); } $parentChanged = $story->parent != $oldStory->parent; - if($parentChanged) $this->doChangeParent($storyID, $story, $oldStory->parent, $oldStory->path); + if($parentChanged) $this->doChangeParent($storyID, $story, $oldStory->parent); if($oldStory->parent > 0) $this->updateParentStatus($storyID, $oldStory->parent, !$parentChanged); if($story->parent > 0) $this->updateParentStatus($storyID, $story->parent, !$parentChanged); @@ -1004,12 +1021,11 @@ class storyModel extends model } $this->loadModel('action'); - $changeGradeList = array(); foreach($stories as $storyID => $story) { $oldStory = $oldStories[$storyID]; if(!$story->grade) $story->grade = $oldStory->grade; - $this->dao->update(TABLE_STORY)->data($story) + $this->dao->update(TABLE_STORY)->data($story, 'grade') ->autoCheck() ->checkIF($story->closedBy, 'closedReason', 'notempty') ->checkIF($story->closedReason == 'done', 'stage', 'notempty') @@ -1020,14 +1036,20 @@ class storyModel extends model if(dao::isError()) return false; /* Update story sort of plan when story plan has changed. */ - if($oldStory->plan != $story->plan) $this->updateStoryOrderOfPlan($storyID, (string)$story->plan, $oldStory->plan); if($story->grade != $oldStory->grade) { - $changeGradeList[$storyID]['oldGrade'] = $oldStory->grade; - $changeGradeList[$storyID]['newGrade'] = $story->grade; + $gradeDiff = (int)$story->grade - (int)$oldStory->grade; + $this->dao->update(TABLE_STORY) + ->set("grade = grade + $gradeDiff") + ->where('top')->eq($oldStory->top) + ->andWhere('grade')->gt($oldStory->grade) + ->andWhere('id')->ne($storyID) + ->exec(); + $this->dao->update(TABLE_STORY)->set('grade')->eq($story->grade)->where('id')->eq($storyID)->exec(); } + if($oldStory->plan != $story->plan) $this->updateStoryOrderOfPlan($storyID, (string)$story->plan, $oldStory->plan); $parentChanged = $story->parent != $oldStory->parent; - if($parentChanged) $this->doChangeParent($storyID, $story, $oldStory->parent, $oldStory->path); + if($parentChanged) $this->doChangeParent($storyID, $story, $oldStory->parent); if($oldStory->parent > 0) $this->updateParentStatus($storyID, $oldStory->parent, !$parentChanged); if($story->parent > 0) $this->updateParentStatus($storyID, $story->parent, !$parentChanged); @@ -1049,12 +1071,6 @@ class storyModel extends model } } - foreach($changeGradeList as $storyID => $oldStory) - { - $gradeDiff = $oldStory['newGrade'] - $oldStory['oldGrade']; - $this->dao->update(TABLE_STORY)->set("grade = grade + $gradeDiff")->where('path')->like("%,{$storyID},%")->andWhere('id')->ne($storyID)->exec(); - } - $this->loadModel('score')->create('ajax', 'batchEdit'); foreach($unlinkPlans as $planID => $stories) $this->action->create('productplan', $planID, 'unlinkstory', '', $stories); foreach($link2Plans as $planID => $stories) $this->action->create('productplan', $planID, 'linkstory', '', $stories); @@ -1334,10 +1350,9 @@ class storyModel extends model /* Set parent to child story. */ foreach($SRList as $childStoryID) { - $path = rtrim($oldStory->path, ',') . ",$childStoryID,"; $this->dao->update(TABLE_STORY) ->set('parent')->eq($storyID) - ->set('path')->eq($path) + ->set('top')->eq($oldStory->top) ->where('id')->eq($childStoryID) ->exec(); } @@ -2043,11 +2058,10 @@ class storyModel extends model * 获取需求的所有子需求ID。 * * @param int $storyID - * @param bool $includeSelf * @access public * @return array */ - public function getAllChildId(int $storyID, bool $includeSelf = true): array + public function getAllChildId(int $storyID): array { if($storyID == 0) return array(); @@ -2055,9 +2069,9 @@ class storyModel extends model if(empty($story)) return array(); $children = $this->dao->select('id')->from(TABLE_STORY) - ->where('path')->like($story->path . '%') - ->andWhere('deleted')->eq(0) - ->beginIF(!$includeSelf)->andWhere('id')->ne($storyID)->fi() + ->where('deleted')->eq(0) + ->andWhere('top')->eq($story->top) + ->andWhere('grade')->gt($story->grade) ->fetchPairs(); return array_keys($children); @@ -2214,10 +2228,10 @@ class storyModel extends model * @param string|array $modules * @param string $fieldName * @param string $fieldValue - * @param string $type requirement|story + * @param string $type requirement|story * @param string $orderBy * @param object $pager - * @param string $operator equal|include + * @param string $operator equal|include * @access public * @return array */ @@ -4636,7 +4650,11 @@ class storyModel extends model */ public function getGradeList($type = 'story'): array { - return $this->dao->select('*')->from(TABLE_STORYGRADE)->where('type')->eq($type)->orderBy('grade_asc')->fetchAll(); + return $this->dao->select('*')->from(TABLE_STORYGRADE) + ->where('1=1') + ->beginIF($type)->andWhere('type')->eq($type)->fi() + ->orderBy('grade_asc') + ->fetchAll(); } /** @@ -4719,7 +4737,7 @@ class storyModel extends model public function checkGrade(object $story, object $oldStory, string $method = 'edit') { $maxGrade = $this->dao->select('max(grade) as maxGrade')->from(TABLE_STORY) - ->where('path')->like("{$oldStory->path}%") + ->where('top')->eq($oldStory->top) ->andWhere('deleted')->eq('0') ->fetch('maxGrade'); diff --git a/module/story/tao.php b/module/story/tao.php index a91b75a560..03062a0229 100644 --- a/module/story/tao.php +++ b/module/story/tao.php @@ -817,14 +817,11 @@ class storyTao extends storyModel * @param int $storyID * @param object $story * @param int $oldStoryParent - * @param string $oldStoryPath * @access protected * @return void */ - protected function doChangeParent(int $storyID, object $story, int $oldStoryParent, string $oldStoryPath) + protected function doChangeParent(int $storyID, object $story, int $oldStoryParent) { - if($story->parent == $oldStoryParent) return; - $this->loadModel('action'); if($oldStoryParent > 0) { @@ -841,9 +838,9 @@ class storyTao extends storyModel if($story->parent > 0) { - $parentStory = $this->dao->select('*')->from(TABLE_STORY)->where('id')->eq($story->parent)->fetch(); - $story->path = rtrim($parentStory->path, ',') . ',' . $storyID . ','; - $children = $this->dao->select('id')->from(TABLE_STORY)->where('parent')->eq($story->parent)->andWhere('deleted')->eq(0)->fetchPairs('id', 'id'); + $parentStory = $this->dao->select('*')->from(TABLE_STORY)->where('id')->eq($story->parent)->fetch(); + $newTop = $parentStory->top; + $children = $this->dao->select('id')->from(TABLE_STORY)->where('parent')->eq($story->parent)->andWhere('deleted')->eq(0)->fetchPairs('id', 'id'); $this->dao->update(TABLE_STORY) ->set('childStories')->eq(implode(',', $children)) ->set('lastEditedBy')->eq($this->app->user->account) @@ -859,16 +856,12 @@ class storyTao extends storyModel } else { - $story->path = ",$storyID,"; + $newTop = $storyID; } $childStories = $this->getAllChildId($storyID); - foreach($childStories as $childStoryID) - { - $oldChildPath = $this->dao->select('path')->from(TABLE_STORY)->where('id')->eq($childStoryID)->fetch('path'); - $newChildPath = str_replace($oldStoryPath, $story->path, $oldChildPath); - $this->dao->update(TABLE_STORY)->set('path')->eq($newChildPath)->where('id')->eq($childStoryID)->exec(); - } + if($childStories) $this->dao->update(TABLE_STORY)->set('top')->eq($newTop)->where('id')->in($childStories)->exec(); + $this->dao->update(TABLE_STORY)->set('top')->eq($newTop)->where('id')->eq($storyID)->exec(); } /**