From a63d9e811acabe250f259c35fa490d3e41cea2af Mon Sep 17 00:00:00 2001 From: WangXu10 Date: Thu, 29 Aug 2024 15:28:37 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E6=B5=8B=E8=AF=95=E8=AE=A1=E5=88=92):=20?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E8=AE=A1=E5=88=92=E8=AF=A6=E6=83=85=E7=94=A8?= =?UTF-8?q?=E4=BE=8B=E8=84=91=E5=9B=BE=E6=89=B9=E9=87=8F=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E7=BC=BA=E9=99=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../FunctionalCaseExportConverter.java | 11 +- ...estPlanFunctionalCaseMinderController.java | 46 +++++++ .../TestPlanCaseMinderBatchAddBugRequest.java | 22 +++ .../ExtTestPlanFunctionalCaseMapper.java | 9 ++ .../ExtTestPlanFunctionalCaseMapper.xml | 49 +++++++ .../TestPlanFunctionalCaseMinderService.java | 127 ++++++++++++++++++ .../TestPlanFunctionalCaseService.java | 2 +- .../TestPlanCaseControllerTests.java | 31 +++++ .../dml/init_test_plan_case_relate_bug.sql | 5 + 9 files changed, 297 insertions(+), 5 deletions(-) create mode 100644 backend/services/test-plan/src/main/java/io/metersphere/plan/controller/TestPlanFunctionalCaseMinderController.java create mode 100644 backend/services/test-plan/src/main/java/io/metersphere/plan/dto/request/TestPlanCaseMinderBatchAddBugRequest.java create mode 100644 backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanFunctionalCaseMinderService.java diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/excel/converter/FunctionalCaseExportConverter.java b/backend/services/case-management/src/main/java/io/metersphere/functional/excel/converter/FunctionalCaseExportConverter.java index 06f0b466c2..8c2f78f31d 100644 --- a/backend/services/case-management/src/main/java/io/metersphere/functional/excel/converter/FunctionalCaseExportConverter.java +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/excel/converter/FunctionalCaseExportConverter.java @@ -4,9 +4,11 @@ import io.metersphere.functional.domain.CaseReviewHistory; import io.metersphere.functional.domain.FunctionalCase; import io.metersphere.functional.domain.FunctionalCaseComment; import io.metersphere.plan.domain.TestPlanCaseExecuteHistory; +import io.metersphere.sdk.util.JSON; import io.metersphere.sdk.util.Translator; import org.apache.commons.lang3.StringUtils; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.regex.Matcher; @@ -39,10 +41,11 @@ public interface FunctionalCaseExportConverter { default String parseHtml(String html) { Pattern pattern = Pattern.compile("]*>(.*?)

"); Matcher matcher = pattern.matcher(html); - if (matcher.find()) { - String content = matcher.group(1); - return content; + List contents = new ArrayList<>(); + while (matcher.find()) { + contents.add(matcher.group(1)); } - return StringUtils.EMPTY; + String join = String.join(StringUtils.SPACE, contents); + return join; } } diff --git a/backend/services/test-plan/src/main/java/io/metersphere/plan/controller/TestPlanFunctionalCaseMinderController.java b/backend/services/test-plan/src/main/java/io/metersphere/plan/controller/TestPlanFunctionalCaseMinderController.java new file mode 100644 index 0000000000..86b1fe0aa6 --- /dev/null +++ b/backend/services/test-plan/src/main/java/io/metersphere/plan/controller/TestPlanFunctionalCaseMinderController.java @@ -0,0 +1,46 @@ +package io.metersphere.plan.controller; + +import io.metersphere.bug.domain.Bug; +import io.metersphere.bug.dto.request.BugEditRequest; +import io.metersphere.bug.service.BugService; +import io.metersphere.plan.dto.request.TestPlanCaseMinderBatchAddBugRequest; +import io.metersphere.plan.service.TestPlanFunctionalCaseMinderService; +import io.metersphere.sdk.constants.PermissionConstants; +import io.metersphere.sdk.util.BeanUtils; +import io.metersphere.system.security.CheckOwner; +import io.metersphere.system.utils.SessionUtils; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import org.apache.shiro.authz.annotation.RequiresPermissions; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +import java.util.List; + +@Tag(name = "测试计划-功能用例-脑图-操作") +@RestController +@RequestMapping("/test-plan/functional/case/minder") +public class TestPlanFunctionalCaseMinderController { + + @Resource + private BugService bugService; + @Resource + private TestPlanFunctionalCaseMinderService testPlanFunctionalCaseMinderService; + + @PostMapping("/batch/add-bug") + @Operation(summary = "测试计划-功能用例-脑图-批量添加缺陷") + @RequiresPermissions(PermissionConstants.TEST_PLAN_READ_EXECUTE) + @CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project") + public void minderBatchAddBug(@Validated @RequestPart("request") TestPlanCaseMinderBatchAddBugRequest request, + @RequestPart(value = "files", required = false) List files) { + BugEditRequest bugEditRequest = new BugEditRequest(); + BeanUtils.copyBean(bugEditRequest, request); + Bug bug = bugService.addOrUpdate(bugEditRequest, files, SessionUtils.getUserId(), SessionUtils.getCurrentOrganizationId(), false); + testPlanFunctionalCaseMinderService.minderBatchAssociateBug(request, bug.getId(), SessionUtils.getUserId()); + } +} diff --git a/backend/services/test-plan/src/main/java/io/metersphere/plan/dto/request/TestPlanCaseMinderBatchAddBugRequest.java b/backend/services/test-plan/src/main/java/io/metersphere/plan/dto/request/TestPlanCaseMinderBatchAddBugRequest.java new file mode 100644 index 0000000000..7059ea2286 --- /dev/null +++ b/backend/services/test-plan/src/main/java/io/metersphere/plan/dto/request/TestPlanCaseMinderBatchAddBugRequest.java @@ -0,0 +1,22 @@ +package io.metersphere.plan.dto.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +/** + * @author wx + */ +@Data +public class TestPlanCaseMinderBatchAddBugRequest extends TestPlanCaseBatchAddBugRequest { + + @Schema(description = "脑图选中的模块id集合") + private List minderModuleIds; + + @Schema(description = "脑图选中的用例id集合") + private List minderCaseIds; + + @Schema(description = "脑图选中的项目id集合") + private List minderProjectIds; +} 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 102ffaac19..e81db2e868 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.domain.FunctionalCaseModule; import io.metersphere.functional.dto.FunctionalCaseModuleCountDTO; import io.metersphere.functional.dto.FunctionalCaseModuleDTO; import io.metersphere.functional.dto.ProjectOptionDTO; @@ -8,6 +9,7 @@ import io.metersphere.plan.dto.ResourceSelectParam; import io.metersphere.plan.dto.TestPlanCaseRunResultCount; import io.metersphere.plan.dto.TestPlanResourceExecResultDTO; import io.metersphere.plan.dto.request.BasePlanCaseBatchRequest; +import io.metersphere.plan.dto.request.TestPlanCaseMinderBatchAddBugRequest; import io.metersphere.plan.dto.request.TestPlanCaseModuleRequest; import io.metersphere.plan.dto.request.TestPlanCaseRequest; import io.metersphere.plan.dto.response.TestPlanCasePageResponse; @@ -16,6 +18,7 @@ import io.metersphere.project.dto.ModuleCountDTO; import io.metersphere.project.dto.NodeSortQueryParam; import org.apache.ibatis.annotations.Param; +import java.util.Collection; import java.util.List; public interface ExtTestPlanFunctionalCaseMapper { @@ -73,4 +76,10 @@ public interface ExtTestPlanFunctionalCaseMapper { List selectTestPlanIdByFunctionCaseId(String functionalCaseId); List selectDistinctExecResultByTestPlanIds(@Param("testPlanIds") List testPlanIds); + + Collection selectIdsByProjectIds(@Param("request") TestPlanCaseMinderBatchAddBugRequest request); + + List selectProjectByModuleIds(@Param("moduleIds") List moduleIds); + + Collection selectIdsByModuleIds(@Param("request") TestPlanCaseMinderBatchAddBugRequest request, @Param("minderModuleIds") List minderModuleIds); } 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 90c892ccfc..d9042b1ab3 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 @@ -666,4 +666,53 @@ AND test_plan.status != 'ARCHIVED' + + + + + + + \ No newline at end of file diff --git a/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanFunctionalCaseMinderService.java b/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanFunctionalCaseMinderService.java new file mode 100644 index 0000000000..03c8e33245 --- /dev/null +++ b/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanFunctionalCaseMinderService.java @@ -0,0 +1,127 @@ +package io.metersphere.plan.service; + +import io.metersphere.bug.domain.BugRelationCase; +import io.metersphere.bug.mapper.BugRelationCaseMapper; +import io.metersphere.functional.domain.FunctionalCaseModule; +import io.metersphere.functional.service.FunctionalCaseModuleService; +import io.metersphere.plan.dto.request.TestPlanCaseMinderBatchAddBugRequest; +import io.metersphere.plan.mapper.ExtTestPlanFunctionalCaseMapper; +import io.metersphere.sdk.constants.CaseType; +import io.metersphere.sdk.util.SubListUtils; +import io.metersphere.system.dto.sdk.BaseTreeNode; +import io.metersphere.system.uid.IDGenerator; +import jakarta.annotation.Resource; +import org.apache.commons.collections.CollectionUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Service +@Transactional(rollbackFor = Exception.class) +public class TestPlanFunctionalCaseMinderService { + + @Resource + private ExtTestPlanFunctionalCaseMapper extTestPlanFunctionalCaseMapper; + @Resource + private FunctionalCaseModuleService functionalCaseModuleService; + @Resource + private TestPlanFunctionalCaseService testPlanFunctionalCaseService; + @Resource + private BugRelationCaseMapper bugRelationCaseMapper; + + public void minderBatchAssociateBug(TestPlanCaseMinderBatchAddBugRequest request, String bugId, String userId) { + //获取脑图选中的用例id集合 + List ids = getMinderSelectIds(request); + if (CollectionUtils.isNotEmpty(ids)) { + SubListUtils.dealForSubList(ids, 500, (subList) -> { + Map caseMap = testPlanFunctionalCaseService.getCaseMap(subList); + List list = new ArrayList<>(); + subList.forEach(id -> { + BugRelationCase bugRelationCase = new BugRelationCase(); + bugRelationCase.setId(IDGenerator.nextStr()); + bugRelationCase.setBugId(bugId); + bugRelationCase.setCaseId(caseMap.get(id)); + bugRelationCase.setCaseType(CaseType.FUNCTIONAL_CASE.getKey()); + bugRelationCase.setCreateUser(userId); + bugRelationCase.setCreateTime(System.currentTimeMillis()); + bugRelationCase.setUpdateTime(System.currentTimeMillis()); + bugRelationCase.setTestPlanCaseId(id); + bugRelationCase.setTestPlanId(request.getTestPlanId()); + list.add(bugRelationCase); + }); + bugRelationCaseMapper.batchInsert(list); + }); + } + + } + + private List getMinderSelectIds(TestPlanCaseMinderBatchAddBugRequest request) { + if (request.isSelectAll()) { + //全选 + List ids = extTestPlanFunctionalCaseMapper.getIds(request, false); + if (CollectionUtils.isNotEmpty(request.getExcludeIds())) { + ids.removeAll(request.getExcludeIds()); + } + return ids; + } else { + List ids = new ArrayList<>(); + //项目 + if (CollectionUtils.isNotEmpty(request.getMinderProjectIds())) { + ids.addAll(extTestPlanFunctionalCaseMapper.selectIdsByProjectIds(request)); + } + //模块 + if (CollectionUtils.isNotEmpty(request.getMinderModuleIds())) { + //获取模块及子模块 + List modules = extTestPlanFunctionalCaseMapper.selectProjectByModuleIds(request.getMinderModuleIds()); + Map> moduleMaps = modules.stream().collect(Collectors.groupingBy(FunctionalCaseModule::getProjectId)); + List minderModuleIds = new LinkedList<>(); + moduleMaps.forEach((k, v) -> { + buildIdsByModule(k, v, minderModuleIds); + }); + + ids.addAll(extTestPlanFunctionalCaseMapper.selectIdsByModuleIds(request, minderModuleIds)); + } + //用例 + if (CollectionUtils.isNotEmpty(request.getMinderCaseIds())) { + ids.addAll(request.getMinderCaseIds()); + } + return ids; + } + } + + private void buildIdsByModule(String projectId, List modules, List moduleIds) { + List tree = functionalCaseModuleService.getTree(projectId); + modules.forEach(module -> { + moduleIds.addAll(getModuleId(tree, module.getId())); + }); + } + + private List getModuleId(List tree, String moduleId) { + List nodeIds = new ArrayList<>(); + for (BaseTreeNode node : tree) { + if (node.getId().equals(moduleId)) { + nodeIds.add(node.getId()); + getChildrenModuleId(node.getChildren(), nodeIds); + } else { + getModuleId(node.getChildren(), moduleId); + } + } + return nodeIds; + } + + private void getChildrenModuleId(List children, List nodeIds) { + if (CollectionUtils.isNotEmpty(children)) { + for (BaseTreeNode child : children) { + nodeIds.add(child.getId()); + getChildrenModuleId(child.getChildren(), nodeIds); + } + } + } + + +} 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 8c8e87346b..a0e46481ab 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 @@ -969,7 +969,7 @@ public class TestPlanFunctionalCaseService extends TestPlanResourceService { } } - private Map getCaseMap(List ids) { + public Map getCaseMap(List ids) { TestPlanFunctionalCaseExample example = new TestPlanFunctionalCaseExample(); example.createCriteria().andIdIn(ids); List caseList = testPlanFunctionalCaseMapper.selectByExample(example); 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 b2a7992d6f..3fbff241c3 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 @@ -22,6 +22,7 @@ import io.metersphere.plan.service.TestPlanFunctionalCaseService; import io.metersphere.provider.BaseAssociateBugProvider; import io.metersphere.request.AssociateBugPageRequest; import io.metersphere.request.BugPageProviderRequest; +import io.metersphere.sdk.util.BeanUtils; import io.metersphere.sdk.util.JSON; import io.metersphere.system.base.BaseTest; import io.metersphere.system.controller.handler.ResultHolder; @@ -68,6 +69,8 @@ public class TestPlanCaseControllerTests extends BaseTest { public static final String FUNCTIONAL_CASE_BATCH_MOVE_URL = "/test-plan/functional/case/batch/move"; public static final String FUNCTIONAL_CASE_BATCH_ADD_BUG_URL = "/test-plan/functional/case/batch/add-bug"; public static final String FUNCTIONAL_CASE_BATCH_ASSOCIATE_BUG_URL = "/test-plan/functional/case/batch/associate-bug"; + + public static final String FUNCTIONAL_CASE_MINDER_BATCH_ADD_BUG = "/test-plan/functional/case/minder/batch/add-bug"; @Resource private TestPlanFunctionalCaseMapper testPlanFunctionalCaseMapper; @Resource @@ -504,4 +507,32 @@ public class TestPlanCaseControllerTests extends BaseTest { this.requestPostWithOk(FUNCTIONAL_CASE_BATCH_ASSOCIATE_BUG_URL, request); } + @Test + @Order(20) + public void testMinderBatchAddBug() throws Exception { + TestPlanCaseMinderBatchAddBugRequest request = new TestPlanCaseMinderBatchAddBugRequest(); + TestPlanCaseBatchAddBugRequest bugRequest = buildRequest(false); + BeanUtils.copyBean(request, bugRequest); + request.setSelectAll(true); + List files = new ArrayList<>(); + LinkedMultiValueMap paramMap = new LinkedMultiValueMap<>(); + paramMap.add("request", JSON.toJSONString(request)); + paramMap.add("files", files); + this.requestMultipartWithOkAndReturn(FUNCTIONAL_CASE_MINDER_BATCH_ADD_BUG, paramMap); + + request.setSelectAll(false); + paramMap = new LinkedMultiValueMap<>(); + paramMap.add("request", JSON.toJSONString(request)); + paramMap.add("files", files); + this.requestMultipartWithOkAndReturn(FUNCTIONAL_CASE_MINDER_BATCH_ADD_BUG, paramMap); + + request.setMinderProjectIds(List.of("123")); + request.setMinderModuleIds(List.of("t_1")); + request.setMinderCaseIds(List.of("fc_1")); + paramMap = new LinkedMultiValueMap<>(); + paramMap.add("request", JSON.toJSONString(request)); + paramMap.add("files", files); + this.requestMultipartWithOkAndReturn(FUNCTIONAL_CASE_MINDER_BATCH_ADD_BUG, paramMap); + } + } diff --git a/backend/services/test-plan/src/test/resources/dml/init_test_plan_case_relate_bug.sql b/backend/services/test-plan/src/test/resources/dml/init_test_plan_case_relate_bug.sql index 428d6579b0..afd5243cca 100644 --- a/backend/services/test-plan/src/test/resources/dml/init_test_plan_case_relate_bug.sql +++ b/backend/services/test-plan/src/test/resources/dml/init_test_plan_case_relate_bug.sql @@ -96,3 +96,8 @@ INSERT INTO service_integration(`id`, `plugin_id`, `enable`, `configuration`, `o INSERT INTO bug_relation_case (id, case_id, bug_id, case_type, test_plan_id, test_plan_case_id, create_user, create_time, update_time) VALUES ('bug_relate_1', 'fc_1', 'bug_1', 'FUNCTIONAL', 'plan_1', 'relate_case_1', 'admin', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), ('bug_relate_2', 'fc_1', 'bug_2', 'FUNCTIONAL', 'plan_1', 'relate_case_1', 'admin', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); + +INSERT INTO functional_case_module(id, project_id, name, parent_id, pos, create_time, create_user, update_time, update_user) +VALUES + ('t_1', '123', '测试模块', 'NONE', '1', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'admin'), + ('t_1_1', '123', '测试模块_1', 't_1', '2', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'admin');