diff --git a/framework/sdk-parent/frontend/src/components/new-ui/MsNodeTree.vue b/framework/sdk-parent/frontend/src/components/new-ui/MsNodeTree.vue index 37a5157691..d0fdf33d5a 100644 --- a/framework/sdk-parent/frontend/src/components/new-ui/MsNodeTree.vue +++ b/framework/sdk-parent/frontend/src/components/new-ui/MsNodeTree.vue @@ -292,10 +292,7 @@ export default { return hasPermissions(permission[0]); }, init() { - let num = 0; - this.treeNodes.forEach(t => { - num += t.caseNum; - }); + let num = this.getTotalCount(); this.extendTreeNodes = []; this.extendTreeNodes.unshift({ "id": "root", @@ -308,6 +305,31 @@ export default { this.expandedNode.push("root"); } }, + getTotalCount() { + let num = 0; + this.treeNodes.forEach(t => { + num += t.caseNum; + }); + return num; + }, + updateNodeCount(countMap) { + // countMap 是对应模块下的用例数,这里根据模块的层级结构,计算模块及其子模块的用例数 + this.doUpdateNodeCount(this.treeNodes, countMap); + // 更新 root 节点,用例数量 + this.$refs.tree.root.childNodes[0].data.caseNum = this.getTotalCount(); + }, + doUpdateNodeCount(treeNodes, countMap) { + treeNodes.forEach(item => { + let children = item.children; + if (children && children.length > 0) { + this.doUpdateNodeCount(children, countMap); + item.caseNum = countMap[item.id] + children.map(i => i.caseNum) + .reduce((pre, curr) => pre + curr, 0); + } else { + item.caseNum = countMap[item.id]; + } + }); + }, handleNodeSelect(node) { let nodeIds = []; let pNodes = []; diff --git a/test-track/backend/src/main/java/io/metersphere/controller/TestCaseNodeController.java b/test-track/backend/src/main/java/io/metersphere/controller/TestCaseNodeController.java index 50c651cc65..b222fde09e 100644 --- a/test-track/backend/src/main/java/io/metersphere/controller/TestCaseNodeController.java +++ b/test-track/backend/src/main/java/io/metersphere/controller/TestCaseNodeController.java @@ -44,7 +44,15 @@ public class TestCaseNodeController { projectId = request.getProjectId(); } baseCheckPermissionService.checkProjectOwner(projectId); - return testCaseNodeService.getNodeTreeByProjectId(projectId, Optional.ofNullable(request).orElse(new QueryTestCaseRequest())); + return testCaseNodeService.getNodeTreeByProjectId(projectId, + Optional.ofNullable(request).orElse(new QueryTestCaseRequest())); + } + + @PostMapping("/count/{projectId}") + public Map getNodeCountMapByProjectId(@PathVariable String projectId, @RequestBody(required = false) QueryTestCaseRequest request) { + baseCheckPermissionService.checkProjectOwner(projectId); + return testCaseNodeService.getNodeCountMapByProjectId(projectId, + Optional.ofNullable(request).orElse(new QueryTestCaseRequest())); } @PostMapping("/minder/extraNode/count") diff --git a/test-track/backend/src/main/java/io/metersphere/service/TestCaseNodeService.java b/test-track/backend/src/main/java/io/metersphere/service/TestCaseNodeService.java index 5ea7f52852..52f97b0c50 100644 --- a/test-track/backend/src/main/java/io/metersphere/service/TestCaseNodeService.java +++ b/test-track/backend/src/main/java/io/metersphere/service/TestCaseNodeService.java @@ -18,7 +18,6 @@ import io.metersphere.commons.utils.CommonBeanFactory; import io.metersphere.commons.utils.JSON; import io.metersphere.commons.utils.SessionUtils; import io.metersphere.dto.NodeNumDTO; -import io.metersphere.dto.TestCaseDTO; import io.metersphere.dto.TestCaseNodeDTO; import io.metersphere.dto.TestPlanCaseDTO; import io.metersphere.exception.ExcelException; @@ -225,11 +224,27 @@ public class TestCaseNodeService extends NodeTreeService { request.setProjectId(projectId); request.setUserId(SessionUtils.getUserId()); request.setNodeIds(null); + request.setOrders(null); ServiceUtils.buildCombineTagsToSupportMultiple(request); ServiceUtils.setBaseQueryRequestCustomMultipleFields(request); - List countMNodes = extTestCaseMapper.getCountNodes(request); + List countNodes = extTestCaseMapper.getCountNodes(request); List testCaseNodes = extTestCaseNodeMapper.getNodeTreeByProjectId(projectId); - return getNodeTrees(testCaseNodes, getCountMap(countMNodes)); + return getNodeTrees(testCaseNodes, getCountMap(countNodes)); + } + + + + public Map getNodeCountMapByProjectId(String projectId, QueryTestCaseRequest request) { + request.setProjectId(projectId); + request.setUserId(SessionUtils.getUserId()); + request.setNodeIds(null); + request.setOrders(null); + ServiceUtils.buildCombineTagsToSupportMultiple(request); + ServiceUtils.setBaseQueryRequestCustomMultipleFields(request); + List countNodes = extTestCaseMapper.getCountNodes(request); + Map countMap = getCountMap(countNodes); + countMap.remove(null); // 脏数据,没有模块 ID 的会有 null 的清空 + return countMap; } /** diff --git a/test-track/frontend/src/api/testCase.js b/test-track/frontend/src/api/testCase.js index 0d90c90083..79dcc9f46e 100644 --- a/test-track/frontend/src/api/testCase.js +++ b/test-track/frontend/src/api/testCase.js @@ -193,6 +193,10 @@ export function getTestCaseNodesByCaseFilter(projectId, param) { return post('/case/node/list/' + projectId, param); } +export function getTestCaseNodesCountMap(projectId, param) { + return post('/case/node/count/' + projectId, param); +} + export function getTestPlanCaseNodesByCaseFilter(planId, param) { return post('/case/node/list/plan/' + planId, param); } diff --git a/test-track/frontend/src/business/case/components/TestCaseList.vue b/test-track/frontend/src/business/case/components/TestCaseList.vue index 45ee8410c2..06460de93c 100644 --- a/test-track/frontend/src/business/case/components/TestCaseList.vue +++ b/test-track/frontend/src/business/case/components/TestCaseList.vue @@ -840,29 +840,11 @@ export default { item.customFields = JSON.parse(item.customFields); } }); - this.updateTestCaseNodeCount(); }); this.$emit("getTrashList"); this.$emit("getPublicList") } }, - // 如果在其他tab页创建用例,会导致模块数量显示和列表不一致,这里重新更新下模块的用例数 - updateTestCaseNodeCount() { - if (this.selectNode && this.treeNodes && this.selectNode.data - && this.selectNode.data.caseNum !== this.page.total) { - - let updateCount = this.page.total - this.selectNode.data.caseNum; - let node = this.selectNode; - this.selectNode.data.caseNum = this.page.total; - while (node) { - node = node.parent; - if (node && node.data) { - node.data.caseNum += updateCount; - } - } - - } - }, search() { this.refreshBySearch = true; // 添加搜索条件时,当前页设置成第一页 diff --git a/test-track/frontend/src/business/module/TestCaseNodeTree.vue b/test-track/frontend/src/business/module/TestCaseNodeTree.vue index 746a320c85..6e15b3fea2 100644 --- a/test-track/frontend/src/business/module/TestCaseNodeTree.vue +++ b/test-track/frontend/src/business/module/TestCaseNodeTree.vue @@ -50,7 +50,7 @@ import MsSearchBar from "metersphere-frontend/src/components/new-ui/MsSearchBar" import {buildTree, buildNodePath} from "metersphere-frontend/src/model/NodeTree"; import {getCurrentProjectID} from "metersphere-frontend/src/utils/token"; import ModuleTrashButton from "metersphere-frontend/src/components/ModuleTrashButton"; -import {getTestCaseNodesByCaseFilter} from "@/api/testCase"; +import {getTestCaseNodesByCaseFilter, getTestCaseNodesCountMap} from "@/api/testCase"; import IsChangeConfirm from "metersphere-frontend/src/components/IsChangeConfirm"; import ModulePublicButton from "metersphere-frontend/src/components/module/ModulePublicButton"; import {useStore} from "@/store"; @@ -296,8 +296,16 @@ export default { this.currentNode = node; this.$emit("nodeSelectEvent", node, node.data.id === 'root' ? [] : nodeIds, pNodes); - // 只在TAB页切换时才刷新树 - // this.nohupReloadTree(node.data.id); + // 刷新模块用例数 + this.updateNodeCount(); + }, + updateNodeCount() { + getTestCaseNodesCountMap(this.projectId, this.caseCondition) + .then((r) => { + if (this.$refs.nodeTree) { + this.$refs.nodeTree.updateNodeCount(r.data); + } + }); }, nohupReloadTree(selectNodeId) { if (this.projectId) {