From 5cf923b55cd4c2997dcdbaa29e709e873b2c7362 Mon Sep 17 00:00:00 2001 From: WangXu10 Date: Sat, 11 May 2024 16:31:17 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E6=B5=8B=E8=AF=95=E8=AE=A1=E5=88=92):=20?= =?UTF-8?q?=E5=B7=B2=E5=85=B3=E8=81=94=E7=94=A8=E4=BE=8B=E6=A8=A1=E5=9D=97?= =?UTF-8?q?=E6=A0=91=E7=BB=9F=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TestPlanFunctionalCaseController.java | 12 +++- .../plan/dto/request/TestPlanCaseRequest.java | 4 ++ .../ExtTestPlanFunctionalCaseMapper.java | 5 ++ .../ExtTestPlanFunctionalCaseMapper.xml | 21 +++++++ .../plan/mapper/ExtTestPlanModuleMapper.java | 2 + .../plan/mapper/ExtTestPlanModuleMapper.xml | 7 +++ .../TestPlanFunctionalCaseService.java | 60 +++++++++++++++++-- .../TestPlanCaseControllerTests.java | 18 ++++++ 8 files changed, 124 insertions(+), 5 deletions(-) diff --git a/backend/services/test-plan/src/main/java/io/metersphere/plan/controller/TestPlanFunctionalCaseController.java b/backend/services/test-plan/src/main/java/io/metersphere/plan/controller/TestPlanFunctionalCaseController.java index 95efbae023..5cc616b50a 100644 --- a/backend/services/test-plan/src/main/java/io/metersphere/plan/controller/TestPlanFunctionalCaseController.java +++ b/backend/services/test-plan/src/main/java/io/metersphere/plan/controller/TestPlanFunctionalCaseController.java @@ -1,7 +1,9 @@ package io.metersphere.plan.controller; +import com.alibaba.excel.util.StringUtils; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; +import io.metersphere.functional.request.ReviewFunctionalCasePageRequest; import io.metersphere.plan.constants.TestPlanResourceConfig; import io.metersphere.plan.dto.request.ResourceSortRequest; import io.metersphere.plan.dto.request.TestPlanAssociationRequest; @@ -28,6 +30,7 @@ import org.springframework.web.bind.annotation.*; import java.util.Collections; import java.util.List; +import java.util.Map; @RestController @Tag(name = "测试计划功能用例") @@ -61,7 +64,7 @@ public class TestPlanFunctionalCaseController { @PostMapping("/page") @Operation(summary = "测试计划-已关联功能用例分页查询") @RequiresPermissions(PermissionConstants.FUNCTIONAL_CASE_READ) - @CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project") + @CheckOwner(resourceId = "#request.getTestPlanId()", resourceType = "test_plan") public Pager> page(@Validated @RequestBody TestPlanCaseRequest request) { Page page = PageHelper.startPage(request.getCurrent(), request.getPageSize()); return PageUtils.setPageInfo(page, testPlanFunctionalCaseService.getFunctionalCasePage(request, false)); @@ -76,4 +79,11 @@ public class TestPlanFunctionalCaseController { return testPlanFunctionalCaseService.getTree(testPlanId); } + @PostMapping("/module/count") + @Operation(summary = "测试计划-已关联功能用例模块数量") + @RequiresPermissions(PermissionConstants.CASE_REVIEW_READ) + @CheckOwner(resourceId = "#request.getTestPlanId()", resourceType = "test_plan") + public Map moduleCount(@Validated @RequestBody TestPlanCaseRequest request) { + return testPlanFunctionalCaseService.moduleCount(request); + } } diff --git a/backend/services/test-plan/src/main/java/io/metersphere/plan/dto/request/TestPlanCaseRequest.java b/backend/services/test-plan/src/main/java/io/metersphere/plan/dto/request/TestPlanCaseRequest.java index a835f8e57f..1aa14c053a 100644 --- a/backend/services/test-plan/src/main/java/io/metersphere/plan/dto/request/TestPlanCaseRequest.java +++ b/backend/services/test-plan/src/main/java/io/metersphere/plan/dto/request/TestPlanCaseRequest.java @@ -17,6 +17,10 @@ public class TestPlanCaseRequest extends BasePageRequest implements Serializable @Serial private static final long serialVersionUID = 1L; + @Schema(description = "测试计划id") + @NotBlank(message = "{test_plan.id.not_blank}") + private String testPlanId; + @Schema(description = "项目ID", requiredMode = Schema.RequiredMode.REQUIRED) @NotBlank(message = "{functional_case.project_id.not_blank}") private String projectId; diff --git a/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanFunctionalCaseMapper.java b/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanFunctionalCaseMapper.java index 65be10b992..383310e45f 100644 --- a/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanFunctionalCaseMapper.java +++ b/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanFunctionalCaseMapper.java @@ -1,5 +1,6 @@ package io.metersphere.plan.mapper; +import io.metersphere.functional.dto.FunctionalCaseModuleCountDTO; import io.metersphere.functional.dto.FunctionalCaseModuleDTO; import io.metersphere.functional.dto.ProjectOptionDTO; import io.metersphere.plan.dto.AssociationNode; @@ -30,4 +31,8 @@ public interface ExtTestPlanFunctionalCaseMapper { List selectRootIdByTestPlanId(@Param("testPlanId") String testPlanId); List selectBaseByProjectIdAndTestPlanId(@Param("testPlanId") String testPlanId); + + List countModuleIdByRequest(@Param("request") TestPlanCaseRequest request, @Param("deleted") boolean deleted); + + long caseCount(@Param("request") TestPlanCaseRequest request, @Param("deleted") boolean deleted); } diff --git a/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanFunctionalCaseMapper.xml b/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanFunctionalCaseMapper.xml index f19fab8bb3..9520d8dc84 100644 --- a/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanFunctionalCaseMapper.xml +++ b/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanFunctionalCaseMapper.xml @@ -94,6 +94,7 @@ LEFT JOIN project_version ON functional_case.version_id = project_version.id left join test_plan_functional_case on functional_case.id = test_plan_functional_case.functional_case_id where functional_case.deleted = #{deleted} + and test_plan_functional_case.test_plan_id = #{request.testPlanId} and functional_case.project_id = #{request.projectId} order by @@ -392,4 +393,24 @@ (SELECT fc.module_id FROM functional_case fc LEFT JOIN test_plan_functional_case tpfc ON tpfc.functional_case_id = fc.id WHERE tpfc.test_plan_id = #{testPlanId} AND fc.deleted = false) ORDER BY pos + + + + \ No newline at end of file diff --git a/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanModuleMapper.java b/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanModuleMapper.java index 2b6c6059d5..08fc6e606c 100644 --- a/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanModuleMapper.java +++ b/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanModuleMapper.java @@ -31,4 +31,6 @@ public interface ExtTestPlanModuleMapper { String selectProjectIdByModuleId(String id); List selectBaseByIds(@Param("ids") List ids); + + List selectIdByProjectIdAndTestPlanId(@Param("projectId") String projectId, @Param("testPlanId") String testPlanId); } diff --git a/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanModuleMapper.xml b/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanModuleMapper.xml index cb9be9ac14..4574eb865f 100644 --- a/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanModuleMapper.xml +++ b/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanModuleMapper.xml @@ -83,4 +83,11 @@ ORDER BY pos + + \ No newline at end of file diff --git a/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanFunctionalCaseService.java b/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanFunctionalCaseService.java index c5faf79821..c81597dcc8 100644 --- a/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanFunctionalCaseService.java +++ b/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanFunctionalCaseService.java @@ -4,6 +4,7 @@ import io.metersphere.bug.dto.CaseRelateBugDTO; import io.metersphere.bug.mapper.ExtBugRelateCaseMapper; import io.metersphere.functional.domain.FunctionalCaseModule; import io.metersphere.functional.dto.FunctionalCaseCustomFieldDTO; +import io.metersphere.functional.dto.FunctionalCaseModuleCountDTO; import io.metersphere.functional.dto.FunctionalCaseModuleDTO; import io.metersphere.functional.dto.ProjectOptionDTO; import io.metersphere.functional.service.FunctionalCaseService; @@ -19,11 +20,14 @@ import io.metersphere.plan.dto.response.TestPlanAssociationResponse; import io.metersphere.plan.dto.response.TestPlanCasePageResponse; import io.metersphere.plan.dto.response.TestPlanResourceSortResponse; import io.metersphere.plan.mapper.ExtTestPlanFunctionalCaseMapper; +import io.metersphere.plan.mapper.ExtTestPlanModuleMapper; import io.metersphere.plan.mapper.TestPlanFunctionalCaseMapper; import io.metersphere.plan.mapper.TestPlanMapper; import io.metersphere.project.domain.Project; +import io.metersphere.project.dto.ModuleCountDTO; import io.metersphere.sdk.constants.TestPlanResourceConstants; import io.metersphere.sdk.exception.MSException; +import io.metersphere.sdk.util.BeanUtils; import io.metersphere.sdk.util.Translator; import io.metersphere.system.dto.LogInsertModule; import io.metersphere.system.dto.sdk.BaseTreeNode; @@ -39,10 +43,7 @@ import org.mybatis.spring.SqlSessionUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -69,6 +70,10 @@ public class TestPlanFunctionalCaseService extends TestPlanResourceService { private TestPlanModuleService testPlanModuleService; @Resource private TestPlanCaseService testPlanCaseService; + @Resource + private ExtTestPlanModuleMapper extTestPlanModuleMapper; + + private static final String CASE_MODULE_COUNT_ALL = "all"; @Override public int deleteBatchByTestPlanId(List testPlanIdList) { @@ -203,4 +208,51 @@ public class TestPlanFunctionalCaseService extends TestPlanResourceService { }); return returnList; } + + + public Map moduleCount(TestPlanCaseRequest request) { + //查出每个模块节点下的资源数量。 不需要按照模块进行筛选 + request.setModuleIds(null); + List projectModuleCountDTOList = extTestPlanFunctionalCaseMapper.countModuleIdByRequest(request, false); + Map> projectCountMap = projectModuleCountDTOList.stream().collect(Collectors.groupingBy(FunctionalCaseModuleCountDTO::getProjectId)); + Map projectModuleCountMap = new HashMap<>(); + projectCountMap.forEach((projectId, moduleCountDTOList) -> { + List moduleCountDTOS = new ArrayList<>(); + for (FunctionalCaseModuleCountDTO functionalCaseModuleCountDTO : moduleCountDTOList) { + ModuleCountDTO moduleCountDTO = new ModuleCountDTO(); + BeanUtils.copyBean(moduleCountDTO, functionalCaseModuleCountDTO); + moduleCountDTOS.add(moduleCountDTO); + } + int sum = moduleCountDTOList.stream().mapToInt(FunctionalCaseModuleCountDTO::getDataCount).sum(); + Map moduleCountMap = getModuleCountMap(projectId, request.getTestPlanId(), moduleCountDTOS); + moduleCountMap.forEach((k, v) -> { + if (projectModuleCountMap.get(k) == null || projectModuleCountMap.get(k) == 0L) { + projectModuleCountMap.put(k, v); + } + }); + projectModuleCountMap.put(projectId, (long) sum); + }); + //查出全部用例数量 + long allCount = extTestPlanFunctionalCaseMapper.caseCount(request, false); + projectModuleCountMap.put(CASE_MODULE_COUNT_ALL, allCount); + return projectModuleCountMap; + } + + + public Map getModuleCountMap(String projectId, String testPlanId, List moduleCountDTOList) { + //构建模块树,并计算每个节点下的所有数量(包含子节点) + List treeNodeList = this.getTreeOnlyIdsAndResourceCount(projectId, testPlanId, moduleCountDTOList); + + //通过广度遍历的方式构建返回值 + return testPlanModuleService.getIdCountMapByBreadth(treeNodeList); + } + + public List getTreeOnlyIdsAndResourceCount(String projectId, String testPlanId, List moduleCountDTOList) { + //节点内容只有Id和parentId + List moduleIds = extTestPlanModuleMapper.selectIdByProjectIdAndTestPlanId(projectId, testPlanId); + List nodeByNodeIds = testPlanModuleService.getNodeByNodeIds(moduleIds); + return testPlanModuleService.buildTreeAndCountResource(nodeByNodeIds, moduleCountDTOList, true, Translator.get("functional_case.module.default.name")); + + + } } diff --git a/backend/services/test-plan/src/test/java/io/metersphere/plan/controller/TestPlanCaseControllerTests.java b/backend/services/test-plan/src/test/java/io/metersphere/plan/controller/TestPlanCaseControllerTests.java index 8db80808a9..f9d3647be6 100644 --- a/backend/services/test-plan/src/test/java/io/metersphere/plan/controller/TestPlanCaseControllerTests.java +++ b/backend/services/test-plan/src/test/java/io/metersphere/plan/controller/TestPlanCaseControllerTests.java @@ -21,6 +21,7 @@ public class TestPlanCaseControllerTests extends BaseTest { public static final String FUNCTIONAL_CASE_LIST_URL = "/test-plan/functional/case/page"; public static final String FUNCTIONAL_CASE_TREE_URL = "/test-plan/functional/case/tree/"; + public static final String FUNCTIONAL_CASE_TREE_COUNT_URL = "/test-plan/functional/case/module/count"; @Test @Order(1) @@ -30,6 +31,7 @@ public class TestPlanCaseControllerTests extends BaseTest { request.setProjectId("123"); request.setCurrent(1); request.setPageSize(10); + request.setTestPlanId("plan_1"); this.requestPost(FUNCTIONAL_CASE_LIST_URL, request); request.setSort(new HashMap<>() {{ put("createTime", "desc"); @@ -51,4 +53,20 @@ public class TestPlanCaseControllerTests extends BaseTest { this.requestGetWithOkAndReturn(FUNCTIONAL_CASE_TREE_URL + "plan_2"); } + + @Test + @Order(3) + public void testGetFunctionalCaseTreeCount() throws Exception { + TestPlanCaseRequest request = new TestPlanCaseRequest(); + request.setProjectId("123"); + request.setCurrent(1); + request.setPageSize(10); + request.setTestPlanId("plan_1"); + MvcResult mvcResult = this.requestPostWithOkAndReturn(FUNCTIONAL_CASE_TREE_COUNT_URL, request); + String returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8); + ResultHolder resultHolder = JSON.parseObject(returnData, ResultHolder.class); + Assertions.assertNotNull(resultHolder); + } + + }