diff --git a/module/story/control.php b/module/story/control.php index f499cc2126..ce6f57b782 100755 --- a/module/story/control.php +++ b/module/story/control.php @@ -2016,32 +2016,6 @@ class story extends control } - /** - * AJAX: Get user requirements. - * - * @param int $productID - * @param int $branchID - * @param int $moduleID - * @param string $requirementList - * @access public - * @return void - */ - public function ajaxGetURS(int $productID, string $branchID = '0', int $moduleID = 0, string $requirementList = '0') - { - $moduleIdList = $this->loadModel('tree')->getAllChildId($moduleID); - - $URS = $this->story->getProductStoryPairs($productID, $branchID, $moduleIdList, 'active', 'id_desc', 0, '', 'requirement'); - - $items = array(); - foreach($URS as $URID => $URTitle) - { - if(empty($URID)) continue; - $items[] = array('text' => $URTitle, 'value' => $URID); - } - - return print(json_encode(array('name' => 'URS[]', 'multiple' => true, 'defaultValue' => $requirementList, 'items' => $items))); - } - /** * 移除需求的孪生需求。 * AJAX: Deleted story twin. diff --git a/module/story/js/common.ui.js b/module/story/js/common.ui.js index 60372b240a..72dd5b9253 100644 --- a/module/story/js/common.ui.js +++ b/module/story/js/common.ui.js @@ -44,43 +44,6 @@ window.toggleFeedback = function(obj) $('.feedbackBox').toggleClass('hidden', !feedbackSource.includes(source)); } -window.loadURS = function(e) -{ - const eventType = typeof e == 'undefined' ? '' : e.type; - const productID = $('[name=product]').val(); - - let requirementList = $('[name=URS]').val(); - requirementList = requirementList ? encodeURIComponent(requirementList.join(',')) : ''; - - let moduleID = 0; - if(eventType == 'change') moduleID = $('[name=module]').val(); - if(eventType == 'click' && !$(e.target).prop('checked')) moduleID = $('[name=module]').val(); - if($('#loadURS').prop('checked')) moduleID = 0; - - let branchID = 0; - let $branches = $('input[name^=branches]'); - if($branches.length > 0) - { - branchIdList = []; - $branches.each(function() - { - var currentBranch = $(this).val(); - if(currentBranch == '') currentBranch = 0; - if(!branchIdList.includes(currentBranch)) branchIdList.push(currentBranch); - }) - branchID = branchIdList.join(','); - } - - var link = $.createLink('story', 'ajaxGetURS', 'productID=' + productID + '&branchID=' + branchID + '&moduleID=' + moduleID + '&requirementList=' + requirementList); - $.get(link, function(data) - { - data = JSON.parse(data); - $URS = $('#URS').zui('picker'); - $URS.render({items: data.items}); - $URS.$.setValue($URS.$.value); - }) -}; - window.loadGrade = function(e) { const parent = e.target.value; @@ -144,5 +107,4 @@ window.loadBranch = function() if(typeof(branch) == 'undefined') branch = 0; window.loadProductPlans(productID, branch); - window.loadURS(); }; diff --git a/module/story/js/edit.ui.js b/module/story/js/edit.ui.js index 6e60b397e4..66259a6fdc 100644 --- a/module/story/js/edit.ui.js +++ b/module/story/js/edit.ui.js @@ -13,38 +13,19 @@ window.loadProduct = function() } } - if(productID != oldProductID) + if(isParent == '1') { - if(!confirm(changeProductTips)) - { - $product.$.setValue(oldProductID.toString()); - return false; - } - } - - if(parentStory) - { - confirmLoadProduct = confirm(moveChildrenTips); - if(!confirmLoadProduct) - { - $product.$.setValue(oldProductID.toString()); - return false; - } + zui.Modal.confirm(moveChildrenTips).then((result) => { + if(!result) + { + $product.$.setValue(oldProductID.toString(), true); + return false; + } + }); } loadProductBranches(productID); loadProductReviewers(productID); - loadURS(); - - if(storyType == 'story') - { - var storyLink = $.createLink('story', 'ajaxGetParentStory', 'productID=' + productID); - var $parent = $('#parent').zui('picker'); - $.get(storyLink, function(data) - { - $parent.render({items: JSON.parse(data)}); - }); - } } window.linkStories = function(e) diff --git a/module/story/lang/de.php b/module/story/lang/de.php index 1436e57dbf..d4a85bb564 100644 --- a/module/story/lang/de.php +++ b/module/story/lang/de.php @@ -344,7 +344,7 @@ $lang->story->noStory = 'Keine Stories. '; $lang->story->noRequirement = 'No Requirements.'; $lang->story->ignoreChangeStage = 'The status of %s is Draft or Closed. This operation has been filtered.'; $lang->story->cannotDeleteParent = "Can not delete parent {$lang->SRCommon}"; -$lang->story->moveChildrenTips = "Its Child {$lang->SRCommon} will be moved to the selected {$lang->productCommon} when editing the linked {$lang->productCommon} of Parent {$lang->SRCommon}."; +$lang->story->moveChildrenTips = "Are you sure to modify the product? After modification, all sub-level requirements of the requirement will also be changed accordingly."; $lang->story->changeTips = 'The story associated with the requirements to change, click "Cancel" ignore this change, click "Confirm" to change the story.'; $lang->story->estimateMustBeNumber = 'Estimate value must be number.'; $lang->story->estimateMustBePlus = 'Estimated value cannot be negative'; diff --git a/module/story/lang/en.php b/module/story/lang/en.php index d80a02abae..4c8f8f70f3 100644 --- a/module/story/lang/en.php +++ b/module/story/lang/en.php @@ -344,7 +344,7 @@ $lang->story->noStory = 'No stories yet. '; $lang->story->noRequirement = 'No requirements yet. '; $lang->story->ignoreChangeStage = 'The status of %s is Draft or Closed. This operation has been filtered.'; $lang->story->cannotDeleteParent = "Can not delete parent {$lang->SRCommon}"; -$lang->story->moveChildrenTips = "Its Child {$lang->SRCommon} will be moved to the selected {$lang->productCommon} when editing the linked {$lang->productCommon} of Parent {$lang->SRCommon}."; +$lang->story->moveChildrenTips = "Are you sure to modify the product? After modification, all sub-level requirements of the requirement will also be changed accordingly."; $lang->story->changeTips = 'The story associated with the requirements to change, click "Cancel" ignore this change, click "Confirm" to change the story.'; $lang->story->estimateMustBeNumber = 'Estimate value must be number.'; $lang->story->estimateMustBePlus = 'Estimated value cannot be negative'; diff --git a/module/story/lang/fr.php b/module/story/lang/fr.php index c5f7d279a1..c5b63c02f5 100644 --- a/module/story/lang/fr.php +++ b/module/story/lang/fr.php @@ -344,7 +344,7 @@ $lang->story->noStory = "Aucune story pour l'instant. "; $lang->story->noRequirement = 'No Requirements'; $lang->story->ignoreChangeStage = 'The status of %s is Draft or Closed. This operation has been filtered.'; $lang->story->cannotDeleteParent = "Impossible de supprimer {$lang->SRCommon} parent"; -$lang->story->moveChildrenTips = "Its Child {$lang->SRCommon} will be moved to the selected {$lang->productCommon} when editing the linked {$lang->productCommon} of Parent {$lang->SRCommon}."; +$lang->story->moveChildrenTips = "Are you sure to modify the product? After modification, all sub-level requirements of the requirement will also be changed accordingly."; $lang->story->changeTips = 'The story associated with the requirements to change, click "Cancel" ignore this change, click "Confirm" to change the story.'; $lang->story->estimateMustBeNumber = 'Estimate value must be number.'; $lang->story->estimateMustBePlus = 'Estimated value cannot be negative'; diff --git a/module/story/lang/zh-cn.php b/module/story/lang/zh-cn.php index ff2ce62bd6..c3f5e694f8 100644 --- a/module/story/lang/zh-cn.php +++ b/module/story/lang/zh-cn.php @@ -344,7 +344,7 @@ $lang->story->noStory = "暂时没有{$lang->SRCommon}。"; $lang->story->noRequirement = "暂时没有{$lang->URCommon}。"; $lang->story->ignoreChangeStage = "{$lang->SRCommon} %s 状态为草稿或已关闭,本次操作已被过滤。"; $lang->story->cannotDeleteParent = "不能删除父{$lang->SRCommon}"; -$lang->story->moveChildrenTips = "修改父{$lang->SRCommon}的所属{$lang->productCommon}会将其下的子{$lang->SRCommon}也移动到所选{$lang->productCommon}下。"; +$lang->story->moveChildrenTips = "确认修改所属产品吗,修改后,需求的所有子级需求也会跟随变更。"; $lang->story->changeTips = '该软件需求关联的用户需求有变更,点击“不变更”忽略此条变更,点击“变更”来进行该软件需求的变更。'; $lang->story->estimateMustBeNumber = '估算值必须是数字'; $lang->story->estimateMustBePlus = '估算值不能是负数'; diff --git a/module/story/model.php b/module/story/model.php index fb4d74f899..6cc7556657 100644 --- a/module/story/model.php +++ b/module/story/model.php @@ -788,7 +788,11 @@ class storyModel extends model if($story->product != $oldStory->product) { $childStories = $this->getAllChildId($storyID, false); - foreach($childStories as $childStoryID) $this->updateStoryProduct($childStoryID, $story->product); + $story->id = $storyID; + foreach($childStories as $childStoryID) + { + $this->updateStoryProduct($childStoryID, $story, $story->product); + } } if($story->grade != $oldStory->grade) $this->syncGrade($oldStory, $story); $parentChanged = $story->parent != $oldStory->parent; @@ -843,13 +847,30 @@ class storyModel extends model * Update story product. * * @param int $storyID + * @param object $parentID * @param int $productID * @access public * @return void */ - public function updateStoryProduct(int $storyID, int $productID): void + public function updateStoryProduct(int $storyID, object $parent, int $productID): void { - $this->dao->update(TABLE_STORY)->set('product')->eq($productID)->where('id')->eq($storyID)->exec(); + if($parent->id != $storyID) + { + $childPath = $this->dao->select('path')->from(TABLE_STORY)->where('id')->eq($storyID)->fetch('path'); + $childPath = strstr($childPath, ",{$parent->id},"); + $this->dao->update(TABLE_STORY) + ->set('product')->eq($parent->product) + ->set('module')->eq(0) + ->set('root')->eq($parent->root) + ->set('path')->eq($childPath) + ->where('id')->eq($storyID) + ->exec(); + } + else + { + $this->dao->update(TABLE_STORY)->set('path')->eq(",{$storyID},")->where('id')->eq($storyID)->exec(); + } + $this->dao->update(TABLE_PROJECTSTORY)->set('product')->eq($productID)->where('story')->eq($storyID)->exec(); $storyProjects = $this->dao->select('project')->from(TABLE_PROJECTSTORY)->where('story')->eq($storyID)->orderBy('project')->fetchPairs('project', 'project'); $linkedProjects = $this->dao->select('project')->from(TABLE_PROJECTPRODUCT)->where('project')->in($storyProjects)->andWhere('product')->eq($productID)->orderBy('project')->fetchPairs('project','project'); diff --git a/module/story/ui/edit.html.php b/module/story/ui/edit.html.php index cfea9bb0fc..0505374cc2 100644 --- a/module/story/ui/edit.html.php +++ b/module/story/ui/edit.html.php @@ -42,14 +42,14 @@ data('activeMenuID', $story->type); jsVar('storyType', $story->type); jsVar('storyID', $story->id); jsVar('storyStatus', $story->status); +jsVar('isParent', $story->isParent); +jsVar('oldProductID', $story->product); jsVar('lastReviewer', explode(',', $lastReviewer)); jsVar('storyReviewers', $storyReviewers); jsVar('reviewerNotEmpty', $lang->story->notice->reviewerNotEmpty); -jsVar('oldProductID', $story->product); jsVar('twins', $story->twins); jsVar('relievedTwinsTip', $lang->story->relievedTwinsTip); jsVar('changeProductTips', $lang->story->changeProductTips); -jsVar('parentStory', !empty($story->children)); jsVar('moveChildrenTips', $lang->story->moveChildrenTips); jsVar('executionID', isset($objectID) ? $objectID : 0); jsVar('langTreeManage', $lang->tree->manage); @@ -200,7 +200,7 @@ detailBody ( setClass('mt-5'), set::title($lang->story->legendBasicInfo), - $story->parent <= 0 ? item + item ( set::trClass(zget($fields['product'], 'className', '')), set::name($lang->story->product), @@ -228,7 +228,7 @@ detailBody ) : null ) ) - ) : null, + ), $story->parent > 0 && $product->type != 'normal' ? item ( set::name(sprintf($lang->product->branch, $lang->product->branchName[$product->type])), diff --git a/module/story/zen.php b/module/story/zen.php index 01eb0af628..16d9ac5474 100644 --- a/module/story/zen.php +++ b/module/story/zen.php @@ -1259,6 +1259,13 @@ class storyZen extends story if($this->post->linkStories) $storyData->linkStories = implode(',', array_unique($this->post->linkStories)); if($this->post->linkRequirements) $storyData->linkRequirements = implode(',', array_unique($this->post->linkRequirements)); + if($oldStory->product != $storyData->product) + { + $storyData->root = $storyID; + $storyData->parent = 0; + $storyData->module = 0; + } + return $this->loadModel('file')->processImgURL($storyData, $editorFields, $this->post->uid); }