From 18fce82f90606aa59921af8cedb2a455b1182677 Mon Sep 17 00:00:00 2001 From: guoyuqi Date: Tue, 12 Dec 2023 11:13:18 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E7=94=A8=E4=BE=8B=E8=AF=84=E5=AE=A1):=20?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=8D=95=E7=8B=AC=E5=8F=96=E6=B6=88=E5=85=B3?= =?UTF-8?q?=E8=81=94=E5=8A=9F=E8=83=BD=E7=94=A8=E4=BE=8B=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E8=AF=84=E5=AE=A1=E6=A8=A1=E5=9D=97=E6=95=B0=E9=87=8F=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/CaseReviewController.java | 20 +++- .../mapper/ExtCaseReviewMapper.java | 7 ++ .../functional/mapper/ExtCaseReviewMapper.xml | 51 ++++++++++ .../request/CaseReviewPageRequest.java | 8 ++ .../service/CaseReviewLogService.java | 25 +++++ .../functional/service/CaseReviewService.java | 48 +++++++++ .../controller/CaseReviewControllerTests.java | 97 +++++++++++++++++++ 7 files changed, 254 insertions(+), 2 deletions(-) diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/controller/CaseReviewController.java b/backend/services/case-management/src/main/java/io/metersphere/functional/controller/CaseReviewController.java index 9ebb5f6fd9..2991e851a4 100644 --- a/backend/services/case-management/src/main/java/io/metersphere/functional/controller/CaseReviewController.java +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/controller/CaseReviewController.java @@ -29,6 +29,7 @@ import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import java.util.List; +import java.util.Map; @Tag(name = "用例管理-用例评审") @RestController @@ -39,14 +40,21 @@ public class CaseReviewController { private CaseReviewService caseReviewService; @PostMapping("/page") - @Operation(summary = "用例管理-功能用例-用例列表查询") - @RequiresPermissions(PermissionConstants.FUNCTIONAL_CASE_READ) + @Operation(summary = "用例管理-用例评审-用例列表查询") + @RequiresPermissions(PermissionConstants.CASE_REVIEW_READ) public Pager> getFunctionalCasePage(@Validated @RequestBody CaseReviewPageRequest request) { Page page = PageHelper.startPage(request.getCurrent(), request.getPageSize(), StringUtils.isNotBlank(request.getSortString()) ? request.getSortString() : "pos desc"); return PageUtils.setPageInfo(page, caseReviewService.getCaseReviewPage(request)); } + @PostMapping("/module/count") + @Operation(summary = "用例管理-用例评审-表格分页查询文件") + @RequiresPermissions(PermissionConstants.CASE_REVIEW_READ) + public Map moduleCount(@Validated @RequestBody CaseReviewPageRequest request) { + return caseReviewService.moduleCount(request); + } + @PostMapping("/add") @Operation(summary = "用例管理-用例评审-创建用例评审") @Log(type = OperationLogType.ADD, expression = "#msClass.addCaseReviewLog(#request)", msClass = CaseReviewLogService.class) @@ -97,6 +105,14 @@ public class CaseReviewController { caseReviewService.associateCase(request, SessionUtils.getUserId()); } + @GetMapping("disassociate/{reviewId}/{caseId}") + @Operation(summary = "用例管理-用例评审-取消关联用例") + @Log(type = OperationLogType.DISASSOCIATE, expression = "#msClass.disAssociateCaseLog(#reviewId, #caseId)", msClass = CaseReviewLogService.class) + @RequiresPermissions(PermissionConstants.CASE_REVIEW_RELEVANCE) + public void disassociate(@PathVariable String reviewId, @PathVariable String caseId) { + caseReviewService.disassociate(reviewId, caseId); + } + @PostMapping("/edit/pos") @Operation(summary = "用例管理-用例评审-拖拽排序") @RequiresPermissions(PermissionConstants.CASE_REVIEW_READ_UPDATE) diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/mapper/ExtCaseReviewMapper.java b/backend/services/case-management/src/main/java/io/metersphere/functional/mapper/ExtCaseReviewMapper.java index 1409e71195..a21c9e2d74 100644 --- a/backend/services/case-management/src/main/java/io/metersphere/functional/mapper/ExtCaseReviewMapper.java +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/mapper/ExtCaseReviewMapper.java @@ -4,6 +4,7 @@ import io.metersphere.functional.domain.CaseReview; import io.metersphere.functional.dto.CaseReviewDTO; import io.metersphere.functional.request.CaseReviewBatchRequest; import io.metersphere.functional.request.CaseReviewPageRequest; +import io.metersphere.project.dto.ModuleCountDTO; import org.apache.ibatis.annotations.Param; import java.util.List; @@ -26,4 +27,10 @@ public interface ExtCaseReviewMapper { List getIds(@Param("request") CaseReviewBatchRequest request, @Param("projectId") String projectId); void batchMoveModule(@Param("request") CaseReviewBatchRequest request, @Param("ids") List ids, @Param("userId") String userId); + + List countModuleIdByKeywordAndFileType(@Param("request") CaseReviewPageRequest request); + + long caseCount(@Param("request") CaseReviewPageRequest request); + + } diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/mapper/ExtCaseReviewMapper.xml b/backend/services/case-management/src/main/java/io/metersphere/functional/mapper/ExtCaseReviewMapper.xml index 61c8a6ad56..6c013c3adc 100644 --- a/backend/services/case-management/src/main/java/io/metersphere/functional/mapper/ExtCaseReviewMapper.xml +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/mapper/ExtCaseReviewMapper.xml @@ -116,6 +116,21 @@ + + case_review.create_user = #{request.createByMe} + + + + + + case_review.id in + ( + select case_review_user.review_id from case_review_user where case_review_user.user_id = #{request.reviewByMe} + ) + + + + @@ -373,4 +388,40 @@ + + + + \ No newline at end of file diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/request/CaseReviewPageRequest.java b/backend/services/case-management/src/main/java/io/metersphere/functional/request/CaseReviewPageRequest.java index 3b7abbe090..7a1a287604 100644 --- a/backend/services/case-management/src/main/java/io/metersphere/functional/request/CaseReviewPageRequest.java +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/request/CaseReviewPageRequest.java @@ -22,4 +22,12 @@ public class CaseReviewPageRequest extends BasePageRequest implements Serializab @Schema(description = "模块id") private List moduleIds; + @Schema(description = "我评审的") + private String reviewByMe; + + @Schema(description = "我创建的") + private String createByMe; + + + } diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/service/CaseReviewLogService.java b/backend/services/case-management/src/main/java/io/metersphere/functional/service/CaseReviewLogService.java index 45a49c14a7..08d2d8e419 100644 --- a/backend/services/case-management/src/main/java/io/metersphere/functional/service/CaseReviewLogService.java +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/service/CaseReviewLogService.java @@ -164,11 +164,36 @@ public class CaseReviewLogService { dto.setPath("/case/review/associate"); dto.setMethod(HttpMethodConstants.POST.name()); dto.setOriginalValue(JSON.toJSONBytes(functionalCase)); + dtoList.add(dto); } return dtoList; } + public LogDTO disAssociateCaseLog(String reviewId, String caseId) { + CaseReview caseReview = caseReviewMapper.selectByPrimaryKey(reviewId); + if (caseReview == null) { + return null; + } + FunctionalCase functionalCase = functionalCaseMapper.selectByPrimaryKey(caseId); + if (functionalCase == null) { + return null; + } + LogDTO dto = new LogDTO( + caseReview.getProjectId(), + null, + caseReview.getId(), + null, + OperationLogType.DISASSOCIATE.name(), + OperationLogModule.CASE_REVIEW, + functionalCase.getName()); + + dto.setPath("/case/review/disassociate"); + dto.setMethod(HttpMethodConstants.GET.name()); + dto.setOriginalValue(JSON.toJSONBytes(functionalCase)); + return dto; + } + public List batchDisassociateCaseLog(BaseReviewCaseBatchRequest request) { List ids = caseReviewFunctionalCaseService.doSelectIds(request); diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/service/CaseReviewService.java b/backend/services/case-management/src/main/java/io/metersphere/functional/service/CaseReviewService.java index 5c88bc0df5..388c5d7f88 100644 --- a/backend/services/case-management/src/main/java/io/metersphere/functional/service/CaseReviewService.java +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/service/CaseReviewService.java @@ -12,6 +12,7 @@ import io.metersphere.functional.request.CaseReviewBatchRequest; import io.metersphere.functional.request.CaseReviewPageRequest; import io.metersphere.functional.request.CaseReviewRequest; import io.metersphere.functional.result.CaseManagementResultCode; +import io.metersphere.project.dto.ModuleCountDTO; import io.metersphere.sdk.constants.ApplicationNumScope; import io.metersphere.sdk.constants.PermissionConstants; import io.metersphere.sdk.exception.MSException; @@ -71,8 +72,14 @@ public class CaseReviewService { private FunctionalCaseMapper functionalCaseMapper; @Resource private DeleteCaseReviewService deleteCaseReviewService; + @Resource + private CaseReviewFunctionalCaseUserMapper caseReviewFunctionalCaseUserMapper; + @Resource + private CaseReviewModuleService caseReviewModuleService; + private static final String CASE_MODULE_COUNT_ALL = "all"; + /** * 获取用例评审列表 * @@ -523,4 +530,45 @@ public class CaseReviewService { deleteCaseReviewService.deleteCaseReviewResource(List.of(reviewId), projectId, false); } + + public void disassociate(String reviewId, String caseId) { + //1.刪除评审与功能用例关联关系 + CaseReviewFunctionalCaseExample caseReviewFunctionalCaseExample = new CaseReviewFunctionalCaseExample(); + caseReviewFunctionalCaseExample.createCriteria().andReviewIdEqualTo(reviewId).andCaseIdEqualTo(caseId); + caseReviewFunctionalCaseMapper.deleteByExample(caseReviewFunctionalCaseExample); + //2.删除用例和用例评审人的关系 + CaseReviewFunctionalCaseUserExample caseReviewFunctionalCaseUserExample = new CaseReviewFunctionalCaseUserExample(); + caseReviewFunctionalCaseUserExample.createCriteria().andCaseIdEqualTo(caseId).andReviewIdEqualTo(reviewId); + caseReviewFunctionalCaseUserMapper.deleteByExample(caseReviewFunctionalCaseUserExample); + + caseReviewFunctionalCaseExample = new CaseReviewFunctionalCaseExample(); + caseReviewFunctionalCaseExample.createCriteria().andReviewIdEqualTo(reviewId); + List caseReviewFunctionalCases = caseReviewFunctionalCaseMapper.selectByExample(caseReviewFunctionalCaseExample); + List passList = caseReviewFunctionalCases.stream().filter(t -> StringUtils.equalsIgnoreCase(t.getStatus(), FunctionalCaseReviewStatus.PASS.toString())).toList(); + CaseReview caseReview = new CaseReview(); + caseReview.setId(reviewId); + //更新用例数量 + caseReview.setCaseCount(caseReviewFunctionalCases.size()); + //通过率 + BigDecimal passCount = BigDecimal.valueOf(passList.size()); + BigDecimal totalCount = BigDecimal.valueOf(caseReview.getCaseCount()); + BigDecimal passRate; + if (totalCount.compareTo(BigDecimal.ZERO)==0) { + passRate = BigDecimal.ZERO; + } else { + passRate = passCount.divide(totalCount, 2, RoundingMode.HALF_UP); + } + caseReview.setPassRate(passRate); + caseReviewMapper.updateByPrimaryKeySelective(caseReview); + } + + public Map moduleCount(CaseReviewPageRequest request) { + //查出每个模块节点下的资源数量。 不需要按照模块进行筛选 + List moduleCountDTOList = extCaseReviewMapper.countModuleIdByKeywordAndFileType(request); + Map moduleCountMap = caseReviewModuleService.getModuleCountMap(request.getProjectId(), moduleCountDTOList); + //查出全部用例数量 + long allCount = extCaseReviewMapper.caseCount(request); + moduleCountMap.put(CASE_MODULE_COUNT_ALL, allCount); + return moduleCountMap; + } } \ No newline at end of file diff --git a/backend/services/case-management/src/test/java/io/metersphere/functional/controller/CaseReviewControllerTests.java b/backend/services/case-management/src/test/java/io/metersphere/functional/controller/CaseReviewControllerTests.java index 4464c99dff..78acf3a3be 100644 --- a/backend/services/case-management/src/test/java/io/metersphere/functional/controller/CaseReviewControllerTests.java +++ b/backend/services/case-management/src/test/java/io/metersphere/functional/controller/CaseReviewControllerTests.java @@ -32,6 +32,7 @@ import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.testcontainers.shaded.org.apache.commons.lang3.StringUtils; +import java.math.BigDecimal; import java.nio.charset.StandardCharsets; import java.util.*; import java.util.stream.Collectors; @@ -54,7 +55,9 @@ public class CaseReviewControllerTests extends BaseTest { private static final String BATCH_MOVE_CASE_REVIEW = "/case/review/batch/move"; private static final String EDIT_CASE_REVIEW = "/case/review/edit"; private static final String PAGE_CASE_REVIEW = "/case/review/page"; + private static final String MODULE_COUNT_CASE_REVIEW = "/case/review/module/count"; private static final String ASSOCIATE_CASE_REVIEW = "/case/review/associate"; + private static final String DISASSOCIATE_CASE_REVIEW = "/case/review/disassociate/"; private static final String EDIT_POS_CASE_REVIEW_URL = "/case/review/edit/pos"; private static final String FOLLOW_CASE_REVIEW = "/case/review/edit/follower"; private static final String CASE_REVIEWER_LIST = "/case/review/user-option/"; @@ -339,9 +342,19 @@ public class CaseReviewControllerTests extends BaseTest { request.setCombine(caseReviewCombine); request.setProjectId(projectId); request.setKeyword("评审更新"); + request.setReviewByMe("admin"); request.setCurrent(1); request.setPageSize(10); MvcResult mvcResult = this.requestPostWithOkAndReturn(PAGE_CASE_REVIEW, request); + Pager> tableData = JSON.parseObject(JSON.toJSONString( + JSON.parseObject(mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8), ResultHolder.class).getData()), + Pager.class); + + MvcResult moduleCountMvcResult = this.requestPostWithOkAndReturn(MODULE_COUNT_CASE_REVIEW, request); + Map moduleCount = JSON.parseObject(JSON.toJSONString( + JSON.parseObject(moduleCountMvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8), ResultHolder.class).getData()), + Map.class); + // 获取返回值 String returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8); ResultHolder resultHolder = JSON.parseObject(returnData, ResultHolder.class); @@ -355,6 +368,21 @@ public class CaseReviewControllerTests extends BaseTest { // 返回的数据量不超过规定要返回的数据量相同 Assertions.assertTrue(JSON.parseArray(JSON.toJSONString(pageData.getList())).size() <= request.getPageSize()); + //如果没有数据,则返回的模块节点也不应该有数据 + boolean moduleHaveResource = false; + for (int countByModuleId : moduleCount.values()) { + if (countByModuleId > 0) { + moduleHaveResource = true; + break; + } + } + Assertions.assertEquals(request.getPageSize(), tableData.getPageSize()); + if (tableData.getTotal() > 0) { + Assertions.assertTrue(moduleHaveResource); + } + + Assertions.assertTrue(moduleCount.containsKey("all")); + CaseReviewFunctionalCaseExample caseReviewFunctionalCaseExample = new CaseReviewFunctionalCaseExample(); caseReviewFunctionalCaseExample.createCriteria().andReviewIdEqualTo(caseReviews.get(0).getId()); List caseReviewFunctionalCases = caseReviewFunctionalCaseMapper.selectByExample(caseReviewFunctionalCaseExample); @@ -507,6 +535,75 @@ public class CaseReviewControllerTests extends BaseTest { Assertions.assertEquals(1, notifications.size()); } + + @Test + @Order(17) + public void testDisassociate() throws Exception { + List caseReviews = getCaseReviews("创建评审更新1"); + Assertions.assertEquals(1, caseReviews.size()); + String caseReviewId = caseReviews.get(0).getId(); + CaseReviewFunctionalCaseExample caseReviewFunctionalCaseExample = new CaseReviewFunctionalCaseExample(); + caseReviewFunctionalCaseExample.createCriteria().andReviewIdEqualTo(caseReviewId).andCaseIdEqualTo("CASE_REVIEW_TEST_GYQ_ID6"); + List caseReviewFunctionalCases = caseReviewFunctionalCaseMapper.selectByExample(caseReviewFunctionalCaseExample); + Assertions.assertEquals(1, caseReviewFunctionalCases.size()); + mockMvc.perform(MockMvcRequestBuilders.get(DISASSOCIATE_CASE_REVIEW+caseReviewId+"/CASE_REVIEW_TEST_GYQ_ID6").header(SessionConstants.HEADER_TOKEN, sessionId) + .header(SessionConstants.CSRF_TOKEN, csrfToken) + .header(SessionConstants.CURRENT_PROJECT, projectId) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)).andReturn(); + caseReviewFunctionalCaseExample = new CaseReviewFunctionalCaseExample(); + caseReviewFunctionalCaseExample.createCriteria().andReviewIdEqualTo(caseReviewId).andCaseIdEqualTo("CASE_REVIEW_TEST_GYQ_ID6"); + caseReviewFunctionalCases = caseReviewFunctionalCaseMapper.selectByExample(caseReviewFunctionalCaseExample); + Assertions.assertEquals(0, caseReviewFunctionalCases.size()); + + caseReviews = getCaseReviews("创建评审3"); + Assertions.assertEquals(1, caseReviews.size()); + caseReviewId = caseReviews.get(0).getId(); + CaseReviewAssociateRequest caseReviewAssociateRequest = new CaseReviewAssociateRequest(); + caseReviewAssociateRequest.setProjectId(projectId); + caseReviewAssociateRequest.setReviewId(caseReviewId); + List caseIds = new ArrayList<>(); + caseIds.add("CASE_REVIEW_TEST_GYQ_ID2"); + caseReviewAssociateRequest.setCaseIds(caseIds); + List userIds = new ArrayList<>(); + userIds.add("gyq_review_test"); + userIds.add("gyq_review_test2"); + caseReviewAssociateRequest.setReviewers(userIds); + this.requestPostWithOk(ASSOCIATE_CASE_REVIEW, caseReviewAssociateRequest); + + mockMvc.perform(MockMvcRequestBuilders.get(DISASSOCIATE_CASE_REVIEW+caseReviewId+"/CASE_REVIEW_TEST_GYQ_ID2").header(SessionConstants.HEADER_TOKEN, sessionId) + .header(SessionConstants.CSRF_TOKEN, csrfToken) + .header(SessionConstants.CURRENT_PROJECT, projectId) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)).andReturn(); + CaseReview caseReview = caseReviewMapper.selectByPrimaryKey(caseReviewId); + Assertions.assertEquals(0, caseReview.getPassRate().compareTo(BigDecimal.ZERO)); + + } + + @Test + @Order(18) + public void testDisassociateFalse() throws Exception { + List caseReviews = getCaseReviews("创建评审更新1"); + mockMvc.perform(MockMvcRequestBuilders.get(DISASSOCIATE_CASE_REVIEW+"caseReviewIdX"+"/CASE_REVIEW_TEST_GYQ_ID6").header(SessionConstants.HEADER_TOKEN, sessionId) + .header(SessionConstants.CSRF_TOKEN, csrfToken) + .header(SessionConstants.CURRENT_PROJECT, projectId) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)).andReturn(); + + String caseReviewId = caseReviews.get(0).getId(); + mockMvc.perform(MockMvcRequestBuilders.get(DISASSOCIATE_CASE_REVIEW+caseReviewId+"/CASE_REVIEW_TEST_GYQ_IDXX").header(SessionConstants.HEADER_TOKEN, sessionId) + .header(SessionConstants.CSRF_TOKEN, csrfToken) + .header(SessionConstants.CURRENT_PROJECT, projectId) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)).andReturn(); + + } + /** * 生成高级搜索参数 *