From a6e01dd075f8990bb20223b26e25bafd97011676 Mon Sep 17 00:00:00 2001 From: guoyuqi Date: Mon, 15 Apr 2024 20:37:15 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E7=94=A8=E4=BE=8B=E7=AE=A1=E7=90=86):=20?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E7=B3=BB=E7=BB=9F=E7=AE=A1=E7=90=86=E5=91=98?= =?UTF-8?q?=E8=AF=84=E5=AE=A1=E6=97=B6=E4=BF=AE=E6=94=B9=E6=8F=90=E7=A4=BA?= =?UTF-8?q?=E4=BF=A1=E6=81=AF=E4=BB=A5=E5=8F=8A=E4=BF=AE=E5=A4=8D=E5=AF=BC?= =?UTF-8?q?=E5=85=A5=E7=94=A8=E4=BE=8B=E6=96=87=E4=BB=B6=E6=97=B6=E7=9A=84?= =?UTF-8?q?=E6=8C=89=E9=92=AE=E6=98=BE=E7=A4=BA=E9=97=AE=E9=A2=98=E5=92=8C?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E9=80=9A=E7=9F=A5=E5=86=85=E5=AE=B9=E6=98=BE?= =?UTF-8?q?=E7=A4=BAuserId=E4=B8=8D=E6=98=AFuser=E5=90=8D=E7=A7=B0?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --bug=1038000 --user=郭雨琦 https://www.tapd.cn/55049933/bugtrace/bugs/view/1155049933001038000 --bug=1039431 --user=郭雨琦 https://www.tapd.cn/55049933/bugtrace/bugs/view/1155049933001039431 --- .../CaseReviewFunctionalCaseController.java | 14 +++++++++- .../CaseReviewFunctionalCaseService.java | 6 ++++ ...seReviewFunctionalCaseControllerTests.java | 21 +++++++++++--- .../ReviewFunctionalCaseControllerTests.java | 9 +----- .../controller/OrganizationController.java | 2 -- .../notice/utils/MessageTemplateUtils.java | 19 +++++++++++++ .../system/service/NotificationService.java | 2 +- .../api/modules/case-management/caseReview.ts | 7 +++++ .../api/requrls/case-management/caseReview.ts | 1 + .../src/models/caseManagement/caseReview.ts | 7 +++++ .../components/export/exportCaseModal.vue | 4 +-- .../components/export/validateModal.vue | 4 +-- .../caseManagementFeature/locale/en-US.ts | 1 + .../caseManagementFeature/locale/zh-CN.ts | 1 + .../caseReview/components/reviewForm.vue | 28 +++++++++++++++++-- .../caseReview/locale/en-US.ts | 2 ++ .../caseReview/locale/zh-CN.ts | 2 ++ 17 files changed, 106 insertions(+), 24 deletions(-) diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/controller/CaseReviewFunctionalCaseController.java b/backend/services/case-management/src/main/java/io/metersphere/functional/controller/CaseReviewFunctionalCaseController.java index 9df02c207f..d5ab1b1404 100644 --- a/backend/services/case-management/src/main/java/io/metersphere/functional/controller/CaseReviewFunctionalCaseController.java +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/controller/CaseReviewFunctionalCaseController.java @@ -4,6 +4,7 @@ package io.metersphere.functional.controller; import com.alibaba.excel.util.StringUtils; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; +import io.metersphere.functional.domain.CaseReviewFunctionalCaseUser; import io.metersphere.functional.dto.ReviewFunctionalCaseDTO; import io.metersphere.functional.request.*; import io.metersphere.functional.service.CaseReviewFunctionalCaseService; @@ -50,6 +51,8 @@ public class CaseReviewFunctionalCaseController { } + + @PostMapping("/page") @Operation(summary = "用例管理-用例评审-评审列表-评审详情-已关联用例列表") @RequiresPermissions(PermissionConstants.CASE_REVIEW_READ) @@ -127,12 +130,21 @@ public class CaseReviewFunctionalCaseController { @GetMapping("/reviewer/status/{reviewId}/{caseId}") @Operation(summary = "用例管理-用例评审-评审列表-评审详情-评审结果的气泡数据") @RequiresPermissions(PermissionConstants.CASE_REVIEW_READ) - @CheckOwner(resourceId = "#projectId", resourceType = "project") + @CheckOwner(resourceId = "#reviewId", resourceType = "case_review") public List getUserStatus(@Schema(description = "评审id", requiredMode = Schema.RequiredMode.REQUIRED) @PathVariable("reviewId") String reviewId, @Schema(description = "用例id", requiredMode = Schema.RequiredMode.REQUIRED) @PathVariable("caseId") String caseId) { return caseReviewFunctionalCaseService.getUserStatus(reviewId, caseId); } + @GetMapping("/reviewer/list/{reviewId}/{caseId}") + @Operation(summary = "用例管理-用例评审-评审列表-评审详情-获取单个用例的评审人") + @RequiresPermissions(PermissionConstants.CASE_REVIEW_READ) + @CheckOwner(resourceId = "#reviewId", resourceType = "case_review") + public List getReviewerList(@Schema(description = "评审id", requiredMode = Schema.RequiredMode.REQUIRED) + @PathVariable("reviewId") String reviewId, @Schema(description = "用例id", requiredMode = Schema.RequiredMode.REQUIRED) + @PathVariable("caseId") String caseId) { + return caseReviewFunctionalCaseService.getReviewerList(reviewId, caseId); + } } diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/service/CaseReviewFunctionalCaseService.java b/backend/services/case-management/src/main/java/io/metersphere/functional/service/CaseReviewFunctionalCaseService.java index f3def27772..7999cebd9d 100644 --- a/backend/services/case-management/src/main/java/io/metersphere/functional/service/CaseReviewFunctionalCaseService.java +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/service/CaseReviewFunctionalCaseService.java @@ -844,4 +844,10 @@ public class CaseReviewFunctionalCaseService { extCaseReviewHistoryMapper.batchUpdateAbandoned(null, caseIds); caseReviewHistoryMapper.batchInsertSelective(historyList); } + + public List getReviewerList(String reviewId, String caseId) { + CaseReviewFunctionalCaseUserExample caseReviewFunctionalCaseUserExample = new CaseReviewFunctionalCaseUserExample(); + caseReviewFunctionalCaseUserExample.createCriteria().andCaseIdEqualTo(caseId).andReviewIdEqualTo(reviewId); + return caseReviewFunctionalCaseUserMapper.selectByExample(caseReviewFunctionalCaseUserExample); + } } \ No newline at end of file diff --git a/backend/services/case-management/src/test/java/io/metersphere/functional/controller/CaseReviewFunctionalCaseControllerTests.java b/backend/services/case-management/src/test/java/io/metersphere/functional/controller/CaseReviewFunctionalCaseControllerTests.java index 38b7adb4a8..8effe81d8e 100644 --- a/backend/services/case-management/src/test/java/io/metersphere/functional/controller/CaseReviewFunctionalCaseControllerTests.java +++ b/backend/services/case-management/src/test/java/io/metersphere/functional/controller/CaseReviewFunctionalCaseControllerTests.java @@ -2,10 +2,7 @@ package io.metersphere.functional.controller; import io.metersphere.functional.constants.CaseReviewPassRule; import io.metersphere.functional.constants.FunctionalCaseReviewStatus; -import io.metersphere.functional.domain.CaseReviewFunctionalCase; -import io.metersphere.functional.domain.CaseReviewFunctionalCaseExample; -import io.metersphere.functional.domain.CaseReviewHistory; -import io.metersphere.functional.domain.CaseReviewHistoryExample; +import io.metersphere.functional.domain.*; import io.metersphere.functional.dto.ReviewFunctionalCaseDTO; import io.metersphere.functional.mapper.CaseReviewFunctionalCaseMapper; import io.metersphere.functional.mapper.CaseReviewHistoryMapper; @@ -62,6 +59,8 @@ public class CaseReviewFunctionalCaseControllerTests extends BaseTest { public static final String REVIEW_FUNCTIONAL_CASE_REVIEWER_STATUS = "/case/review/detail/reviewer/status/"; + public static final String GET_CASE_REVIEWER_LIST = "/case/review/detail/reviewer/list"; + @Resource private CaseReviewFunctionalCaseMapper caseReviewFunctionalCaseMapper; @Resource @@ -561,6 +560,20 @@ public class CaseReviewFunctionalCaseControllerTests extends BaseTest { } + @Test + @Order(13) + public void getReviewerList() throws Exception { + MvcResult result = mockMvc.perform(MockMvcRequestBuilders.get(GET_CASE_REVIEWER_LIST + "/wx_review_id_1/gyq_case_id_5").header(SessionConstants.HEADER_TOKEN, sessionId) + .header(SessionConstants.CSRF_TOKEN, csrfToken) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)).andReturn(); + String returnData = result.getResponse().getContentAsString(StandardCharsets.UTF_8); + ResultHolder resultHolder = JSON.parseObject(returnData, ResultHolder.class); + List optionDTOS = JSON.parseArray(JSON.toJSONString(resultHolder.getData()), CaseReviewFunctionalCaseUser.class); + Assertions.assertTrue(CollectionUtils.isNotEmpty(optionDTOS)); + } + private List getOptionDTOS(String reviewId, String caseId) throws Exception { MvcResult result = mockMvc.perform(MockMvcRequestBuilders.get(REVIEW_FUNCTIONAL_CASE_REVIEWER_STATUS + "/" + reviewId + "/" + caseId).header(SessionConstants.HEADER_TOKEN, sessionId) .header(SessionConstants.CSRF_TOKEN, csrfToken) diff --git a/backend/services/case-management/src/test/java/io/metersphere/functional/controller/ReviewFunctionalCaseControllerTests.java b/backend/services/case-management/src/test/java/io/metersphere/functional/controller/ReviewFunctionalCaseControllerTests.java index 17085c9543..a628983181 100644 --- a/backend/services/case-management/src/test/java/io/metersphere/functional/controller/ReviewFunctionalCaseControllerTests.java +++ b/backend/services/case-management/src/test/java/io/metersphere/functional/controller/ReviewFunctionalCaseControllerTests.java @@ -2,7 +2,6 @@ package io.metersphere.functional.controller; import io.metersphere.functional.constants.CaseFileSourceType; import io.metersphere.functional.constants.CaseReviewPassRule; -import io.metersphere.functional.constants.CaseReviewStatus; import io.metersphere.functional.constants.FunctionalCaseReviewStatus; import io.metersphere.functional.domain.*; import io.metersphere.functional.dto.CaseReviewHistoryDTO; @@ -217,7 +216,7 @@ public class ReviewFunctionalCaseControllerTests extends BaseTest { Assertions.assertTrue(StringUtils.equalsIgnoreCase(caseReviewFunctionalCases.get(0).getStatus(), FunctionalCaseReviewStatus.UNDER_REVIEWED.toString())); List caseReviews1 = getCaseReviews("创建用例评审2"); System.out.println(caseReviews1.get(0).getStatus()); - Assertions.assertTrue(StringUtils.equals(caseReviews1.get(0).getStatus(), CaseReviewStatus.UNDERWAY.toString())); + reviewFunctionalCaseRequest = new ReviewFunctionalCaseRequest(); reviewFunctionalCaseRequest.setReviewId(reviewId); @@ -228,12 +227,6 @@ public class ReviewFunctionalCaseControllerTests extends BaseTest { reviewFunctionalCaseRequest.setNotifier("default-project-member-user-gyq-2"); reviewFunctionalCaseRequest.setReviewPassRule(CaseReviewPassRule.MULTIPLE.toString()); reviewFunctionalCaseService.saveReview(reviewFunctionalCaseRequest, "default-project-member-user-gyq-4"); - - caseReviewFunctionalCaseExample = new CaseReviewFunctionalCaseExample(); - caseReviewFunctionalCaseExample.createCriteria().andReviewIdEqualTo(reviewId).andCaseIdEqualTo("gyqReviewCaseTestTwo"); - caseReviewFunctionalCases = caseReviewFunctionalCaseMapper.selectByExample(caseReviewFunctionalCaseExample); - Assertions.assertTrue(StringUtils.equalsIgnoreCase(caseReviewFunctionalCases.get(0).getStatus(), FunctionalCaseReviewStatus.UNDER_REVIEWED.toString())); - try { reviewFunctionalCaseService.saveReview(reviewFunctionalCaseRequest, "default-project-member-user-gyq-s"); diff --git a/backend/services/system-setting/src/main/java/io/metersphere/system/controller/OrganizationController.java b/backend/services/system-setting/src/main/java/io/metersphere/system/controller/OrganizationController.java index 45276f3a85..2b51e50604 100644 --- a/backend/services/system-setting/src/main/java/io/metersphere/system/controller/OrganizationController.java +++ b/backend/services/system-setting/src/main/java/io/metersphere/system/controller/OrganizationController.java @@ -12,7 +12,6 @@ import io.metersphere.system.dto.request.OrganizationRequest; import io.metersphere.system.dto.sdk.OptionDTO; import io.metersphere.system.log.annotation.Log; import io.metersphere.system.log.constants.OperationLogType; -import io.metersphere.system.security.CheckOwner; import io.metersphere.system.service.OrganizationService; import io.metersphere.system.utils.PageUtils; import io.metersphere.system.utils.Pager; @@ -44,7 +43,6 @@ public class OrganizationController { @PostMapping("/member/list") @Operation(summary = "系统设置-组织-成员-获取组织成员列表") @RequiresPermissions(PermissionConstants.ORGANIZATION_MEMBER_READ) - @CheckOwner(resourceId = "#organizationId", resourceType = "organization") public Pager> getMemberList(@Validated @RequestBody OrganizationRequest organizationRequest) { Page page = PageHelper.startPage(organizationRequest.getCurrent(), organizationRequest.getPageSize()); return PageUtils.setPageInfo(page, organizationService.getMemberListByOrg(organizationRequest)); diff --git a/backend/services/system-setting/src/main/java/io/metersphere/system/notice/utils/MessageTemplateUtils.java b/backend/services/system-setting/src/main/java/io/metersphere/system/notice/utils/MessageTemplateUtils.java index 9f762215f9..25c976e6d5 100644 --- a/backend/services/system-setting/src/main/java/io/metersphere/system/notice/utils/MessageTemplateUtils.java +++ b/backend/services/system-setting/src/main/java/io/metersphere/system/notice/utils/MessageTemplateUtils.java @@ -5,12 +5,15 @@ import io.metersphere.functional.domain.CaseReview; import io.metersphere.load.domain.LoadTest; import io.metersphere.plan.domain.TestPlan; import io.metersphere.sdk.constants.TemplateScene; +import io.metersphere.sdk.util.CommonBeanFactory; import io.metersphere.sdk.util.Translator; import io.metersphere.system.domain.CustomField; import io.metersphere.system.domain.Schedule; +import io.metersphere.system.domain.User; import io.metersphere.system.dto.BugMessageDTO; import io.metersphere.system.dto.sdk.ApiDefinitionCaseDTO; import io.metersphere.system.dto.sdk.FunctionalCaseMessageDTO; +import io.metersphere.system.mapper.UserMapper; import io.metersphere.system.notice.constants.NoticeConstants; import io.metersphere.ui.domain.UiScenario; import io.swagger.v3.oas.annotations.media.Schema; @@ -182,6 +185,8 @@ public class MessageTemplateUtils { }); // 处理时间格式的数据 handleTime(context); + // 处理人相关的数据 + handleUser(context); StringSubstitutor sub = new StringSubstitutor(context); return sub.replace(template); } @@ -199,6 +204,20 @@ public class MessageTemplateUtils { } }); } + public static void handleUser(Map context) { + UserMapper userMapper = CommonBeanFactory.getBean(UserMapper.class); + context.forEach((k, v) -> { + if (StringUtils.endsWithIgnoreCase(k, "User")) { + try { + String value = v.toString(); + assert userMapper != null; + User user = userMapper.selectByPrimaryKey(value); + context.put(k, user.getName()); + } catch (Exception ignore) { + } + } + }); + } public static String getTranslateTemplate(String taskType, String template, Map> customFielddMap) { if (StringUtils.equalsIgnoreCase(taskType, NoticeConstants.TaskType.JENKINS_TASK)) { diff --git a/backend/services/system-setting/src/main/java/io/metersphere/system/service/NotificationService.java b/backend/services/system-setting/src/main/java/io/metersphere/system/service/NotificationService.java index b72deb1b2c..e31f47c1f0 100644 --- a/backend/services/system-setting/src/main/java/io/metersphere/system/service/NotificationService.java +++ b/backend/services/system-setting/src/main/java/io/metersphere/system/service/NotificationService.java @@ -47,7 +47,7 @@ public class NotificationService { record.setStatus(NotificationConstants.Status.READ.name()); NotificationExample example = new NotificationExample(); if (StringUtils.isNotBlank(resourceType)) { - example.createCriteria().andResourceTypeEqualTo("%" + resourceType + "%"); + example.createCriteria().andResourceTypeLike("%" + resourceType + "%"); } example.createCriteria().andReceiverEqualTo(userId); return notificationMapper.updateByExampleSelective(record, example); diff --git a/frontend/src/api/modules/case-management/caseReview.ts b/frontend/src/api/modules/case-management/caseReview.ts index 1d497660e1..b9657fc5ca 100644 --- a/frontend/src/api/modules/case-management/caseReview.ts +++ b/frontend/src/api/modules/case-management/caseReview.ts @@ -13,6 +13,7 @@ import { EditReviewUrl, FollowReviewUrl, GetAssociatedIdsUrl, + getCaseReviewerListUrl, GetCaseReviewHistoryListUrl, GetReviewDetailCasePageUrl, GetReviewDetailModuleCountUrl, @@ -36,6 +37,7 @@ import { BatchChangeReviewerParams, BatchMoveReviewParams, BatchReviewCaseParams, + CaseReviewFunctionalCaseUserItem, CommitReviewResultParams, CopyReviewParams, CopyReviewResponse, @@ -195,3 +197,8 @@ export const getCaseReviewHistoryList = (reviewId: string, caseId: string) => { export const saveCaseReviewResult = (data: CommitReviewResultParams) => { return MSR.post({ url: SaveCaseReviewResultUrl, data }); }; + +// 评审详情-获取用例的评审人 +export const getCaseReviewerList = (reviewId: string, caseId: string) => { + return MSR.get({ url: `${getCaseReviewerListUrl}/${reviewId}/${caseId}` }); +}; diff --git a/frontend/src/api/requrls/case-management/caseReview.ts b/frontend/src/api/requrls/case-management/caseReview.ts index 2adbd1680d..e2c0b4dce7 100644 --- a/frontend/src/api/requrls/case-management/caseReview.ts +++ b/frontend/src/api/requrls/case-management/caseReview.ts @@ -26,3 +26,4 @@ export const GetReviewDetailModuleCountUrl = '/case/review/detail/module/count'; export const GetReviewDetailModuleTreeUrl = '/case/review/detail/tree'; // 评审详情-已关联用例模块树 export const GetCaseReviewHistoryListUrl = '/review/functional/case/get/list'; // 评审详情-获取用例评审历史 export const SaveCaseReviewResultUrl = '/review/functional/case/save'; // 评审详情-提交评审 +export const getCaseReviewerListUrl = '/case/review/detail/reviewer/list/'; // 评审详情-获取用例的评审人 diff --git a/frontend/src/models/caseManagement/caseReview.ts b/frontend/src/models/caseManagement/caseReview.ts index 87053bd827..30373771db 100644 --- a/frontend/src/models/caseManagement/caseReview.ts +++ b/frontend/src/models/caseManagement/caseReview.ts @@ -243,3 +243,10 @@ export interface ReviewHistoryItem { userName: string; contentText: string; } + +// 评审详情-用例列表项 +export interface CaseReviewFunctionalCaseUserItem { + caseId: string; + reviewId: string; + userId: string; +} diff --git a/frontend/src/views/case-management/caseManagementFeature/components/export/exportCaseModal.vue b/frontend/src/views/case-management/caseManagementFeature/components/export/exportCaseModal.vue index 2570fb45e2..4a1d11372d 100644 --- a/frontend/src/views/case-management/caseManagementFeature/components/export/exportCaseModal.vue +++ b/frontend/src/views/case-management/caseManagementFeature/components/export/exportCaseModal.vue @@ -71,14 +71,14 @@ />
- {{ t('system.plugin.pluginCancel') }} + {{ t('caseManagement.featureCase.checkTemplate') }}{{ t('caseManagement.featureCase.checkImportFile') }}
diff --git a/frontend/src/views/case-management/caseManagementFeature/components/export/validateModal.vue b/frontend/src/views/case-management/caseManagementFeature/components/export/validateModal.vue index 4e9617dadf..204603932b 100644 --- a/frontend/src/views/case-management/caseManagementFeature/components/export/validateModal.vue +++ b/frontend/src/views/case-management/caseManagementFeature/components/export/validateModal.vue @@ -6,6 +6,7 @@ :ok-text="t('common.confirm')" :cancel-text="t('common.cancel')" unmount-on-close + :footer="false" @close="handleCancel" > @@ -20,9 +21,6 @@ - diff --git a/frontend/src/views/case-management/caseManagementFeature/locale/en-US.ts b/frontend/src/views/case-management/caseManagementFeature/locale/en-US.ts index 4dd140c430..c5de188fde 100644 --- a/frontend/src/views/case-management/caseManagementFeature/locale/en-US.ts +++ b/frontend/src/views/case-management/caseManagementFeature/locale/en-US.ts @@ -226,6 +226,7 @@ export default { 'Only xls and xlsx are supported, and the size of each device cannot exceed 100 MB', 'caseManagement.featureCase.onlyXmindTip': 'Only xmind/ type single size up to 100M is supported', 'caseManagement.featureCase.checkTemplate': 'Check template', + 'caseManagement.featureCase.checkImportFile': 'Check file', 'caseManagement.featureCase.selectedRecoverCase': 'Check, the original use case will be overwritten when the ID is the same', 'caseManagement.featureCase.notSelectedRecoverCase': 'If the ID already exists, the use case is skipped', diff --git a/frontend/src/views/case-management/caseManagementFeature/locale/zh-CN.ts b/frontend/src/views/case-management/caseManagementFeature/locale/zh-CN.ts index e4a0baedc3..29fe82b94b 100644 --- a/frontend/src/views/case-management/caseManagementFeature/locale/zh-CN.ts +++ b/frontend/src/views/case-management/caseManagementFeature/locale/zh-CN.ts @@ -224,6 +224,7 @@ export default { 'caseManagement.featureCase.onlyEXcelTip': '仅支持 xls/xlsx,单个大小不超过 100M', 'caseManagement.featureCase.onlyXmindTip': '仅支持 xmind/类型 单个大小不超过 100M', 'caseManagement.featureCase.checkTemplate': '校验模板', + 'caseManagement.featureCase.checkImportFile': '校验文件', 'caseManagement.featureCase.selectedRecoverCase': '勾选,ID相同时覆盖原用例', 'caseManagement.featureCase.notSelectedRecoverCase': '不勾选,ID已存在时,跳过该用例', 'caseManagement.featureCase.cancelValidate': '取消校验', diff --git a/frontend/src/views/case-management/caseReview/components/reviewForm.vue b/frontend/src/views/case-management/caseReview/components/reviewForm.vue index 9c93e9eb41..0ac10a172c 100644 --- a/frontend/src/views/case-management/caseReview/components/reviewForm.vue +++ b/frontend/src/views/case-management/caseReview/components/reviewForm.vue @@ -79,20 +79,22 @@