diff --git a/backend/framework/sdk/src/main/resources/i18n/dashboard.properties b/backend/framework/sdk/src/main/resources/i18n/dashboard.properties index 82c9f5376b..f8e4579091 100644 --- a/backend/framework/sdk/src/main/resources/i18n/dashboard.properties +++ b/backend/framework/sdk/src/main/resources/i18n/dashboard.properties @@ -25,6 +25,7 @@ api_management.unPassCount=未通过 bug_management.retentionRate=遗留率 bug_management.totalCount=缺陷总数 bug_management.retentionCount=遗留缺陷数 +get_platform_end_status_error=获取平台结束状态失败 diff --git a/backend/framework/sdk/src/main/resources/i18n/dashboard_en_US.properties b/backend/framework/sdk/src/main/resources/i18n/dashboard_en_US.properties index 985fbf2035..04624e6cbe 100644 --- a/backend/framework/sdk/src/main/resources/i18n/dashboard_en_US.properties +++ b/backend/framework/sdk/src/main/resources/i18n/dashboard_en_US.properties @@ -25,3 +25,4 @@ api_management.unPassCount=Un pass bug_management.retentionRate=Retention rate bug_management.totalCount=Bug total count bug_management.retentionCount=Retention count +get_platform_end_status_error=Failed to get the end status of the platform diff --git a/backend/framework/sdk/src/main/resources/i18n/dashboard_zh_CN.properties b/backend/framework/sdk/src/main/resources/i18n/dashboard_zh_CN.properties index 8f50df24db..0ccde92878 100644 --- a/backend/framework/sdk/src/main/resources/i18n/dashboard_zh_CN.properties +++ b/backend/framework/sdk/src/main/resources/i18n/dashboard_zh_CN.properties @@ -25,4 +25,5 @@ api_management.unPassCount=未通过 bug_management.retentionRate=遗留率 bug_management.totalCount=缺陷总数 -bug_management.retentionCount=遗留缺陷数 \ No newline at end of file +bug_management.retentionCount=遗留缺陷数 +get_platform_end_status_error=获取平台结束状态失败 \ No newline at end of file diff --git a/backend/services/bug-management/src/main/java/io/metersphere/bug/mapper/ExtBugMapper.java b/backend/services/bug-management/src/main/java/io/metersphere/bug/mapper/ExtBugMapper.java index 5b273cb643..e545a1a725 100644 --- a/backend/services/bug-management/src/main/java/io/metersphere/bug/mapper/ExtBugMapper.java +++ b/backend/services/bug-management/src/main/java/io/metersphere/bug/mapper/ExtBugMapper.java @@ -136,5 +136,5 @@ public interface ExtBugMapper { */ List projectUserBugStatusCount(@Param("projectId") String projectId, @Param("startTime") Long startTime, @Param("endTime") Long endTime, @Param("userIds") List userIds, @Param("platforms") Set platforms); - ListgetSimpleList(@Param("projectId") String projectId, @Param("startTime") Long startTime, @Param("endTime") Long endTime,@Param("handleUser") String handleUser,@Param("createUser") String createUser, @Param("platforms") Set platforms); + ListgetSimpleList(@Param("projectId") String projectId, @Param("startTime") Long startTime, @Param("endTime") Long endTime,@Param("handleUser") String handleUser,@Param("createUser") String createUser, @Param("platforms") Set platforms, @Param("currentUser") String currentUser); } diff --git a/backend/services/bug-management/src/main/java/io/metersphere/bug/mapper/ExtBugMapper.xml b/backend/services/bug-management/src/main/java/io/metersphere/bug/mapper/ExtBugMapper.xml index 1f85d8cf5a..595745ed5d 100644 --- a/backend/services/bug-management/src/main/java/io/metersphere/bug/mapper/ExtBugMapper.xml +++ b/backend/services/bug-management/src/main/java/io/metersphere/bug/mapper/ExtBugMapper.xml @@ -457,8 +457,16 @@ AND bug.create_time BETWEEN #{startTime} AND #{endTime} - - AND bug.handle_user = #{handleUser} + + AND ( + FALSE + + OR bug.handle_user = #{handleUser} + + + OR bug.handle_user = #{currentUser} + + ) AND bug.create_user = #{createUser} diff --git a/backend/services/bug-management/src/main/java/io/metersphere/bug/service/BugCommonService.java b/backend/services/bug-management/src/main/java/io/metersphere/bug/service/BugCommonService.java index 1115c3663e..42dad2db11 100644 --- a/backend/services/bug-management/src/main/java/io/metersphere/bug/service/BugCommonService.java +++ b/backend/services/bug-management/src/main/java/io/metersphere/bug/service/BugCommonService.java @@ -25,6 +25,7 @@ import io.metersphere.system.domain.ServiceIntegration; import io.metersphere.system.service.FileService; import io.metersphere.system.service.PlatformPluginService; import io.metersphere.system.service.PluginLoadService; +import io.metersphere.system.service.UserPlatformAccountService; import jakarta.annotation.Resource; import org.apache.commons.collections4.ListUtils; import org.apache.commons.lang3.StringUtils; @@ -34,6 +35,7 @@ import org.springframework.transaction.annotation.Transactional; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.stream.Collectors; @Service @@ -68,6 +70,8 @@ public class BugCommonService { private BugLocalAttachmentMapper bugLocalAttachmentMapper; @Resource private ProjectApplicationService projectApplicationService; + @Resource + private UserPlatformAccountService userPlatformAccountService; /** * 获取表头处理人选项 @@ -211,4 +215,26 @@ public class BugCommonService { List platformLastSteps = platform.getStatusTransitionsLastSteps(projectApplicationService.getProjectBugThirdPartConfig(projectId)); return platformLastSteps.stream().map(SelectOption::getValue).toList(); } + + /** + * 获取登录用户平台处理人 + * @param projectId 项目ID + * @param currentUserId 当前用户ID + * @param currentOrgId 当前组织ID + * @return 平台处理人 + */ + public String getPlatformHandlerUser(String projectId, String currentUserId, String currentOrgId) { + ServiceIntegration serviceIntegration = projectApplicationService.getPlatformServiceIntegrationWithSyncOrDemand(projectId, true); + String platformUserName = userPlatformAccountService.getPlatformUserName(currentUserId, currentOrgId, serviceIntegration.getPluginId()); + List headerHandlerOption = getHeaderHandlerOption(projectId); + if (StringUtils.isNotBlank(platformUserName)) { + Optional handleOption = headerHandlerOption.stream().filter(option -> StringUtils.containsAnyIgnoreCase(option.getText(), platformUserName)) + .findFirst(); + if (handleOption.isPresent()) { + return handleOption.get().getValue(); + } + return platformUserName; + } + return null; + } } diff --git a/backend/services/dashboard/src/main/java/io/metersphere/dashboard/controller/DashboardController.java b/backend/services/dashboard/src/main/java/io/metersphere/dashboard/controller/DashboardController.java index 6033165919..f9950d4788 100644 --- a/backend/services/dashboard/src/main/java/io/metersphere/dashboard/controller/DashboardController.java +++ b/backend/services/dashboard/src/main/java/io/metersphere/dashboard/controller/DashboardController.java @@ -3,6 +3,7 @@ package io.metersphere.dashboard.controller; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import io.metersphere.api.dto.definition.ApiDefinitionUpdateDTO; +import io.metersphere.bug.service.BugCommonService; import io.metersphere.dashboard.dto.LayoutDTO; import io.metersphere.dashboard.request.DashboardFrontPageRequest; import io.metersphere.dashboard.response.OverViewCountDTO; @@ -35,6 +36,8 @@ public class DashboardController { @Resource private DashboardService dashboardService; @Resource + private BugCommonService bugCommonService; + @Resource private PermissionCheckService permissionCheckService; @PostMapping("/layout/edit/{organizationId}") @@ -133,21 +136,22 @@ public class DashboardController { @Operation(summary = "缺陷数量统计") @CheckOwner(resourceId = "#request.getOrganizationId()", resourceType = "organization") public StatisticsDTO projectBugCount(@Validated @RequestBody DashboardFrontPageRequest request) { - return dashboardService.projectBugCount(request, SessionUtils.getUserId()); + return dashboardService.projectBugCount(request, SessionUtils.getUserId(), null); } @PostMapping("/create_bug_by_me") @Operation(summary = "我创建的缺陷") @CheckOwner(resourceId = "#request.getOrganizationId()", resourceType = "organization") public StatisticsDTO projectBugCountCreateByMe(@Validated @RequestBody DashboardFrontPageRequest request) { - return dashboardService.projectBugCountCreateByMe(request, SessionUtils.getUserId()); + return dashboardService.projectBugCountCreateByMe(request, SessionUtils.getUserId(), null); } @PostMapping("/handle_bug_by_me") @Operation(summary = "待我处理的缺陷") @CheckOwner(resourceId = "#request.getOrganizationId()", resourceType = "organization") public StatisticsDTO projectBugCountHandleByMe(@Validated @RequestBody DashboardFrontPageRequest request) { - return dashboardService.projectBugCountHandleByMe(request, SessionUtils.getUserId()); + String platformHandlerUser = bugCommonService.getPlatformHandlerUser(request.getProjectIds().getFirst(), SessionUtils.getUserId(), SessionUtils.getCurrentOrganizationId()); + return dashboardService.projectBugCountHandleByMe(request, SessionUtils.getUserId(), platformHandlerUser); } @PostMapping("/plan_legacy_bug") diff --git a/backend/services/dashboard/src/main/java/io/metersphere/dashboard/controller/ToDoController.java b/backend/services/dashboard/src/main/java/io/metersphere/dashboard/controller/ToDoController.java index 912b44222d..de4aff349d 100644 --- a/backend/services/dashboard/src/main/java/io/metersphere/dashboard/controller/ToDoController.java +++ b/backend/services/dashboard/src/main/java/io/metersphere/dashboard/controller/ToDoController.java @@ -16,10 +16,8 @@ import io.metersphere.plan.dto.response.TestPlanResponse; import io.metersphere.plan.dto.response.TestPlanStatisticsResponse; import io.metersphere.plan.service.TestPlanManagementService; import io.metersphere.plan.service.TestPlanStatisticsService; -import io.metersphere.plugin.platform.dto.SelectOption; import io.metersphere.project.service.ProjectApplicationService; import io.metersphere.sdk.util.LogUtils; -import io.metersphere.system.domain.ServiceIntegration; import io.metersphere.system.security.CheckOwner; import io.metersphere.system.service.UserPlatformAccountService; import io.metersphere.system.utils.PageUtils; @@ -118,15 +116,8 @@ public class ToDoController { return todoParam; } todoParam.setCurrentPlatform(platformName); - List platformLastStepStatus = bugCommonService.getPlatformLastStepStatus(request.getProjectId()); - todoParam.setPlatformLastStatus(platformLastStepStatus); - ServiceIntegration serviceIntegration = projectApplicationService.getPlatformServiceIntegrationWithSyncOrDemand(request.getProjectId(), true); - String platformUserName = userPlatformAccountService.getPlatformUserName(currentUserId, currentOrgId, serviceIntegration.getPluginId()); - List headerHandlerOption = bugCommonService.getHeaderHandlerOption(request.getProjectId()); - if (StringUtils.isNotBlank(platformUserName)) { - headerHandlerOption.stream().filter(option -> StringUtils.containsAnyIgnoreCase(option.getText(), platformUserName)) - .findFirst().ifPresent(option -> todoParam.setPlatformUser(option.getValue())); - } + todoParam.setPlatformLastStatus(bugCommonService.getPlatformLastStepStatus(request.getProjectId())); + todoParam.setPlatformUser(bugCommonService.getPlatformHandlerUser(request.getProjectId(), currentUserId, currentOrgId)); } catch (Exception e) { // 设置平台参数异常时, 无法正常过滤平台非结束的缺陷 LogUtils.error(e.getMessage()); diff --git a/backend/services/dashboard/src/main/java/io/metersphere/dashboard/service/DashboardService.java b/backend/services/dashboard/src/main/java/io/metersphere/dashboard/service/DashboardService.java index ee8b23f973..cf28ff597f 100644 --- a/backend/services/dashboard/src/main/java/io/metersphere/dashboard/service/DashboardService.java +++ b/backend/services/dashboard/src/main/java/io/metersphere/dashboard/service/DashboardService.java @@ -52,6 +52,7 @@ import io.metersphere.sdk.constants.TestPlanConstants; import io.metersphere.sdk.dto.CombineCondition; import io.metersphere.sdk.dto.CombineSearch; import io.metersphere.sdk.util.JSON; +import io.metersphere.sdk.util.LogUtils; import io.metersphere.sdk.util.Translator; import io.metersphere.system.domain.UserLayout; import io.metersphere.system.domain.UserLayoutExample; @@ -1234,17 +1235,18 @@ public class DashboardService { return statisticsDTO; } - public StatisticsDTO baseProjectBugCount(DashboardFrontPageRequest request, String userId, Boolean hasHandleUser, Boolean hasCreateUser) { + public StatisticsDTO baseProjectBugCount(DashboardFrontPageRequest request, String userId, String handleUserId, Boolean hasHandleUser, Boolean hasCreateUser) { String projectId = request.getProjectIds().getFirst(); StatisticsDTO statisticsDTO = new StatisticsDTO(); if (Boolean.FALSE.equals(permissionCheckService.checkModule(projectId, BUG_MODULE, userId, PermissionConstants.PROJECT_BUG_READ))) { statisticsDTO.setErrorCode(NO_PROJECT_PERMISSION.getCode()); return statisticsDTO; } - String handleUser = hasHandleUser ? userId : null; + String localHandleUser = hasHandleUser ? userId : null; + String handleUser = hasHandleUser ? handleUserId : null; String createUser = hasCreateUser ? userId : null; Set platforms = getPlatforms(projectId); - List allSimpleList = extBugMapper.getSimpleList(projectId, null, null, handleUser, createUser, platforms); + List allSimpleList = extBugMapper.getSimpleList(projectId, null, null, handleUser, createUser, platforms, localHandleUser); List localLastStepStatus = getBugEndStatus(projectId); List statusList = allSimpleList.stream().filter(t -> !localLastStepStatus.contains(t.getStatus())).toList(); int statusSize = CollectionUtils.isEmpty(statusList) ? 0 : statusList.size(); @@ -1263,11 +1265,17 @@ public class DashboardService { @NotNull private List getBugEndStatus(String projectId) { List localLastStepStatus = bugCommonService.getLocalLastStepStatus(projectId); + String platformName = projectApplicationService.getPlatformName(projectId); + if (StringUtils.equalsIgnoreCase(platformName, BugPlatform.LOCAL.getName())) { + return localLastStepStatus; + } + // 项目对接三方平台 List platformLastStepStatus = new ArrayList<>(); try { platformLastStepStatus = bugCommonService.getPlatformLastStepStatus(projectId); } catch (Exception e) { - throw new RuntimeException(e); + // 获取三方平台结束状态失败, 只过滤本地结束状态 + LogUtils.error(Translator.get("get_platform_end_status_error")); } localLastStepStatus.addAll(platformLastStepStatus); return localLastStepStatus; @@ -1312,16 +1320,16 @@ public class DashboardService { return statusPercentList; } - public StatisticsDTO projectBugCount(DashboardFrontPageRequest request, String userId) { - return baseProjectBugCount(request, userId, false, false); + public StatisticsDTO projectBugCount(DashboardFrontPageRequest request, String userId, String handlerUser) { + return baseProjectBugCount(request, userId, handlerUser, false, false); } - public StatisticsDTO projectBugCountCreateByMe(DashboardFrontPageRequest request, String userId) { - return baseProjectBugCount(request, userId, false, true); + public StatisticsDTO projectBugCountCreateByMe(DashboardFrontPageRequest request, String userId, String handlerUser) { + return baseProjectBugCount(request, userId, handlerUser, false, true); } - public StatisticsDTO projectBugCountHandleByMe(DashboardFrontPageRequest request, String userId) { - return baseProjectBugCount(request, userId, true, false); + public StatisticsDTO projectBugCountHandleByMe(DashboardFrontPageRequest request, String userId, String handlerUser) { + return baseProjectBugCount(request, userId, handlerUser, true, false); } public StatisticsDTO projectPlanLegacyBug(DashboardFrontPageRequest request, String userId) { diff --git a/backend/services/test-plan/src/main/java/io/metersphere/plan/controller/TestPlanReportController.java b/backend/services/test-plan/src/main/java/io/metersphere/plan/controller/TestPlanReportController.java index 870540832c..0dca27ef5e 100644 --- a/backend/services/test-plan/src/main/java/io/metersphere/plan/controller/TestPlanReportController.java +++ b/backend/services/test-plan/src/main/java/io/metersphere/plan/controller/TestPlanReportController.java @@ -163,6 +163,7 @@ public class TestPlanReportController { @RequiresPermissions(value = {PermissionConstants.TEST_PLAN_REPORT_READ, PermissionConstants.TEST_PLAN_READ_EXECUTE}, logical = Logical.OR) @CheckOwner(resourceId = "#request.getReportId()", resourceType = "test_plan_report") public Pager> pageBug(@Validated @RequestBody TestPlanReportDetailPageRequest request) { + request.setDetailReportIds(testPlanReportService.getActualReportIds(request.getReportId())); Page page = PageHelper.startPage(request.getCurrent(), request.getPageSize(), StringUtils.isNotBlank(request.getSortString()) ? request.getSortString() : "tprb.bug_num, tprb.id desc"); if (!request.getStartPager()) { @@ -177,6 +178,7 @@ public class TestPlanReportController { @RequiresPermissions(value = {PermissionConstants.TEST_PLAN_REPORT_READ, PermissionConstants.TEST_PLAN_READ_EXECUTE}, logical = Logical.OR) @CheckOwner(resourceId = "#request.getReportId()", resourceType = "test_plan_report") public Pager> pageFunctionalCase(@Validated @RequestBody TestPlanReportDetailPageRequest request) { + request.setDetailReportIds(testPlanReportService.getActualReportIds(request.getReportId())); Page page = PageHelper.startPage(request.getCurrent(), request.getPageSize(), StringUtils.isNotBlank(request.getSortString()) ? request.getSortString() : "tprfc.pos desc"); if (!request.getStartPager()) { @@ -201,6 +203,7 @@ public class TestPlanReportController { @RequiresPermissions(value = {PermissionConstants.TEST_PLAN_REPORT_READ, PermissionConstants.TEST_PLAN_READ_EXECUTE}, logical = Logical.OR) @CheckOwner(resourceId = "#request.getReportId()", resourceType = "test_plan_report") public Pager> pageApiCase(@Validated @RequestBody TestPlanReportDetailPageRequest request) { + request.setDetailReportIds(testPlanReportService.getActualReportIds(request.getReportId())); Page page = PageHelper.startPage(request.getCurrent(), request.getPageSize(), StringUtils.isNotBlank(request.getSortString()) ? request.getSortString() : "tprac.pos desc"); if (!request.getStartPager()) { @@ -218,6 +221,7 @@ public class TestPlanReportController { @RequiresPermissions(value = {PermissionConstants.TEST_PLAN_REPORT_READ, PermissionConstants.TEST_PLAN_READ_EXECUTE}, logical = Logical.OR) @CheckOwner(resourceId = "#request.getReportId()", resourceType = "test_plan_report") public Pager> pageScenarioCase(@Validated @RequestBody TestPlanReportDetailPageRequest request) { + request.setDetailReportIds(testPlanReportService.getActualReportIds(request.getReportId())); Page page = PageHelper.startPage(request.getCurrent(), request.getPageSize(), StringUtils.isNotBlank(request.getSortString()) ? request.getSortString() : "tpras.pos desc"); if (!request.getStartPager()) { @@ -249,7 +253,6 @@ public class TestPlanReportController { return testPlanReportService.previewMd(projectId, fileId, compressed); } - @PostMapping("/export/{reportId}") @Operation(summary = "测试计划-报告-导出日志") @RequiresPermissions(PermissionConstants.TEST_PLAN_REPORT_READ_EXPORT) @@ -264,13 +267,13 @@ public class TestPlanReportController { testPlanReportService.batchExportLog(request, SessionUtils.getUserId(), SessionUtils.getCurrentProjectId()); } - @PostMapping("/detail/{type}/collection/page") @Operation(summary = "测试计划-报告-详情-测试集分页查询(不同用例类型)") @RequiresPermissions(value = {PermissionConstants.TEST_PLAN_REPORT_READ, PermissionConstants.TEST_PLAN_READ_EXECUTE}, logical = Logical.OR) @CheckOwner(resourceId = "#request.getReportId()", resourceType = "test_plan_report") @Parameter(name = "type", description = "用例类型", schema = @Schema(requiredMode = Schema.RequiredMode.REQUIRED), example = "functional, api, scenario") public Pager> collectionPage(@PathVariable String type, @Validated @RequestBody TestPlanReportDetailPageRequest request) { + request.setDetailReportIds(testPlanReportService.getActualReportIds(request.getReportId())); // 默认按照测试集的位序升序 Page page = PageHelper.startPage(request.getCurrent(), request.getPageSize(), "tpc.pos asc"); return PageUtils.setPageInfo(page, testPlanReportService.listReportCollection(request, type)); diff --git a/backend/services/test-plan/src/main/java/io/metersphere/plan/controller/TestPlanReportShareController.java b/backend/services/test-plan/src/main/java/io/metersphere/plan/controller/TestPlanReportShareController.java index 66c0095ff2..60b1283220 100644 --- a/backend/services/test-plan/src/main/java/io/metersphere/plan/controller/TestPlanReportShareController.java +++ b/backend/services/test-plan/src/main/java/io/metersphere/plan/controller/TestPlanReportShareController.java @@ -94,6 +94,7 @@ public class TestPlanReportShareController { @PostMapping("/detail/bug/page") @Operation(summary = "测试计划-报告-详情-缺陷分页查询") public Pager> pageBug(@Validated @RequestBody TestPlanShareReportDetailRequest request) { + request.setDetailReportIds(testPlanReportService.getActualReportIds(request.getReportId())); ShareInfo shareInfo = testPlanReportShareService.checkResource(request.getShareId()); testPlanReportShareService.validateExpired(shareInfo); Page page = PageHelper.startPage(request.getCurrent(), request.getPageSize(), @@ -104,6 +105,7 @@ public class TestPlanReportShareController { @PostMapping("/detail/functional/case/page") @Operation(summary = "测试计划-报告-详情-功能用例分页查询") public Pager> pageFunctionalCase(@Validated @RequestBody TestPlanShareReportDetailRequest request) { + request.setDetailReportIds(testPlanReportService.getActualReportIds(request.getReportId())); ShareInfo shareInfo = testPlanReportShareService.checkResource(request.getShareId()); testPlanReportShareService.validateExpired(shareInfo); Page page = PageHelper.startPage(request.getCurrent(), request.getPageSize(), @@ -114,6 +116,7 @@ public class TestPlanReportShareController { @PostMapping("/detail/api/case/page") @Operation(summary = "测试计划-报告-详情-接口用例分页查询") public Pager> pageApiCase(@Validated @RequestBody TestPlanShareReportDetailRequest request) { + request.setDetailReportIds(testPlanReportService.getActualReportIds(request.getReportId())); ShareInfo shareInfo = testPlanReportShareService.checkResource(request.getShareId()); testPlanReportShareService.validateExpired(shareInfo); Page page = PageHelper.startPage(request.getCurrent(), request.getPageSize(), @@ -124,6 +127,7 @@ public class TestPlanReportShareController { @PostMapping("/detail/scenario/case/page") @Operation(summary = "测试计划-报告-详情-场景用例分页查询") public Pager> pageScenarioCase(@Validated @RequestBody TestPlanShareReportDetailRequest request) { + request.setDetailReportIds(testPlanReportService.getActualReportIds(request.getReportId())); ShareInfo shareInfo = testPlanReportShareService.checkResource(request.getShareId()); testPlanReportShareService.validateExpired(shareInfo); Page page = PageHelper.startPage(request.getCurrent(), request.getPageSize(), @@ -189,6 +193,7 @@ public class TestPlanReportShareController { @Operation(summary = "测试计划-报告-详情-测试集分页查询(不同用例类型)") @Parameter(name = "type", description = "用例类型", schema = @Schema(requiredMode = Schema.RequiredMode.REQUIRED), example = "functional, api, scenario") public Pager> collectionPage(@PathVariable String type, @Validated @RequestBody TestPlanShareReportDetailRequest request) { + request.setDetailReportIds(testPlanReportService.getActualReportIds(request.getReportId())); ShareInfo shareInfo = testPlanReportShareService.checkResource(request.getShareId()); testPlanReportShareService.validateExpired(shareInfo); Page page = PageHelper.startPage(request.getCurrent(), request.getPageSize(), diff --git a/backend/services/test-plan/src/main/java/io/metersphere/plan/dto/request/TestPlanReportDetailPageRequest.java b/backend/services/test-plan/src/main/java/io/metersphere/plan/dto/request/TestPlanReportDetailPageRequest.java index ac72507b38..3abb4c15b8 100644 --- a/backend/services/test-plan/src/main/java/io/metersphere/plan/dto/request/TestPlanReportDetailPageRequest.java +++ b/backend/services/test-plan/src/main/java/io/metersphere/plan/dto/request/TestPlanReportDetailPageRequest.java @@ -6,6 +6,11 @@ import jakarta.validation.constraints.NotBlank; import lombok.Data; import lombok.EqualsAndHashCode; +import java.util.List; + +/** + * @author song-cc-rock + */ @Data @EqualsAndHashCode(callSuper = false) public class TestPlanReportDetailPageRequest extends BasePageRequest { @@ -19,4 +24,7 @@ public class TestPlanReportDetailPageRequest extends BasePageRequest { @Schema(description = "测试集ID") private String collectionId; + + @Schema(description = "报告ID集合") + private List detailReportIds; } diff --git a/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanReportApiCaseMapper.java b/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanReportApiCaseMapper.java index 1b8afad40a..4e060e16d0 100644 --- a/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanReportApiCaseMapper.java +++ b/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanReportApiCaseMapper.java @@ -14,10 +14,10 @@ public interface ExtTestPlanReportApiCaseMapper { /** * 统计报告中接口用例执行情况 - * @param reportId 报告ID + * @param reportIds 报告ID集合 * @return 用例数量 */ - List countExecuteResult(@Param("id") String reportId); + List countExecuteResult(@Param("ids") List reportIds); /** * 获取计划关联的接口用例 diff --git a/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanReportApiCaseMapper.xml b/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanReportApiCaseMapper.xml index df3c1ec786..06b15dec8b 100644 --- a/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanReportApiCaseMapper.xml +++ b/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanReportApiCaseMapper.xml @@ -3,7 +3,10 @@ @@ -38,7 +41,10 @@ ifnull(tprac.api_case_execute_result, 'PENDING') as executeResult, tprac.api_case_execute_user as executeUser, atc.project_id projectId from test_plan_report_api_case tprac left join api_test_case atc on tprac.api_case_id = atc.id left join test_plan_collection tpc on tprac.test_plan_collection_id = tpc.id - where tprac.test_plan_report_id = #{request.reportId} + where tprac.test_plan_report_id in + + #{id} + and (tprac.api_case_num like concat('%', #{request.keyword}, '%') or tprac.api_case_name like concat('%', #{request.keyword}, '%') @@ -55,7 +61,10 @@ from test_plan_report_api_case tprac right join test_plan_collection tpc on tprac.test_plan_collection_id = tpc.id and tpc.type = 'API' join test_plan tp on tpc.test_plan_id = tp.id - where tprac.test_plan_report_id = #{request.reportId} + where tprac.test_plan_report_id in + + #{id} + and (tprac.api_case_name like concat('%', #{request.keyword}, '%') or tprac.api_case_num like concat('%', #{request.keyword}, '%') diff --git a/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanReportApiScenarioMapper.java b/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanReportApiScenarioMapper.java index 21bbb7ba06..4086f6e6c4 100644 --- a/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanReportApiScenarioMapper.java +++ b/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanReportApiScenarioMapper.java @@ -14,10 +14,10 @@ public interface ExtTestPlanReportApiScenarioMapper { /** * 统计报告中场景用例执行情况 - * @param reportId 报告ID + * @param reportIds 报告ID集合 * @return 用例数量 */ - List countExecuteResult(@Param("id") String reportId); + List countExecuteResult(@Param("ids") List reportIds); /** * 获取计划关联的场景用例 diff --git a/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanReportApiScenarioMapper.xml b/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanReportApiScenarioMapper.xml index 70106409d9..ee13614491 100644 --- a/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanReportApiScenarioMapper.xml +++ b/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanReportApiScenarioMapper.xml @@ -3,7 +3,10 @@ @@ -37,7 +40,10 @@ ifnull(tpras.api_scenario_execute_result, 'PENDING') as executeResult, tpras.api_scenario_execute_user as executeUser, aso.project_id projectId from test_plan_report_api_scenario tpras left join api_scenario aso on tpras.api_scenario_id = aso.id left join test_plan_collection tpc on tpras.test_plan_collection_id = tpc.id - where tpras.test_plan_report_id = #{request.reportId} + where tpras.test_plan_report_id in + + #{id} + and (tpras.api_scenario_num like concat('%', #{request.keyword}, '%') or tpras.api_scenario_name like concat('%', #{request.keyword}, '%') @@ -54,7 +60,10 @@ from test_plan_report_api_scenario tpras right join test_plan_collection tpc on tpras.test_plan_collection_id = tpc.id and tpc.type = 'SCENARIO' join test_plan tp on tpc.test_plan_id = tp.id - where tpras.test_plan_report_id = #{request.reportId} + where tpras.test_plan_report_id in + + #{id} + and (tpras.api_scenario_name like concat('%', #{request.keyword}, '%') or tpras.api_scenario_num like concat('%', #{request.keyword}, '%') diff --git a/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanReportBugMapper.xml b/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanReportBugMapper.xml index 6310d7f5b5..e8260459c0 100644 --- a/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanReportBugMapper.xml +++ b/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanReportBugMapper.xml @@ -26,7 +26,10 @@ select distinct tprb.bug_id as id, tprb.bug_num as num, tprb.bug_title as title, tprb.bug_status as status, tprb.bug_status as statusName, tprb.bug_handle_user as handleUserName, ifnull(tprb.bug_case_count, 0) as relationCaseCount from test_plan_report_bug tprb - where tprb.test_plan_report_id = #{request.reportId} + where tprb.test_plan_report_id in + + #{id} + and (tprb.bug_num like concat('%', #{request.keyword}, '%') or tprb.bug_title like concat('%', #{request.keyword}, '%')) diff --git a/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanReportFunctionalCaseMapper.java b/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanReportFunctionalCaseMapper.java index 475426c95e..986cc3b3e6 100644 --- a/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanReportFunctionalCaseMapper.java +++ b/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanReportFunctionalCaseMapper.java @@ -43,10 +43,10 @@ public interface ExtTestPlanReportFunctionalCaseMapper { /** * 统计报告中功能用例执行情况 - * @param reportId 报告ID + * @param reportIds 报告ID集合 * @return 用例数量 */ - List countExecuteResult(@Param("id") String reportId); + List countExecuteResult(@Param("ids") List reportIds); /** * 分页查询报告关联的用例 diff --git a/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanReportFunctionalCaseMapper.xml b/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanReportFunctionalCaseMapper.xml index fd42f3d396..8b4a68fefa 100644 --- a/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanReportFunctionalCaseMapper.xml +++ b/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanReportFunctionalCaseMapper.xml @@ -45,7 +45,10 @@ @@ -58,7 +61,10 @@ from test_plan_report_function_case tprfc left join functional_case fc on fc.id = tprfc.function_case_id left join test_plan_collection tpc on tpc.id = tprfc.test_plan_collection_id - where tprfc.test_plan_report_id = #{request.reportId} + where tprfc.test_plan_report_id in + + #{id} + and (tprfc.function_case_num like concat('%', #{request.keyword}, '%') or tprfc.function_case_name like concat('%', #{request.keyword}, '%') @@ -75,7 +81,10 @@ from test_plan_report_function_case tprfc right join test_plan_collection tpc on tprfc.test_plan_collection_id = tpc.id and tpc.type = 'FUNCTIONAL' join test_plan tp on tpc.test_plan_id = tp.id - where tprfc.test_plan_report_id = #{request.reportId} + where tprfc.test_plan_report_id in + + #{id} + and (tprfc.function_case_num like concat('%', #{request.keyword}, '%') or tprfc.function_case_name like concat('%', #{request.keyword}, '%') diff --git a/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanReportMapper.java b/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanReportMapper.java index 752f3b2959..ca5b95ac12 100644 --- a/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanReportMapper.java +++ b/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanReportMapper.java @@ -75,4 +75,6 @@ public interface ExtTestPlanReportMapper { List getChildrenReport(@Param("reportId") String reportId); void resetRerunReport(@Param("reportId") String reportId); + + List getPlanChildrenTask(@Param("reportId") String reportId); } diff --git a/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanReportMapper.xml b/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanReportMapper.xml index caa4d9cf5b..2074c3a5b8 100644 --- a/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanReportMapper.xml +++ b/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanReportMapper.xml @@ -550,7 +550,12 @@ + + diff --git a/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanReportService.java b/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanReportService.java index 679c2e1eb7..c5db7e3c3b 100644 --- a/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanReportService.java +++ b/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanReportService.java @@ -60,6 +60,9 @@ import java.util.*; import java.util.concurrent.atomic.AtomicLong; import java.util.stream.Collectors; +/** + * @author song-cc-rock + */ @Service public class TestPlanReportService { @@ -126,8 +129,6 @@ public class TestPlanReportService { @Resource private ApiReportRelateTaskMapper apiReportRelateTaskMapper; @Resource - private TestPlanCollectionMapper testPlanCollectionMapper; - @Resource private ExecTaskMapper execTaskMapper; private static final int MAX_REPORT_NAME_LENGTH = 300; @@ -337,7 +338,6 @@ public class TestPlanReportService { return genReport(prepareReportId, taskId, request, false, currentUser, null); } - @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW) public Map genReport(String prepareReportId, TestPlanReportGenRequest request, boolean manual, String currentUser, String manualReportName) { return genReport(prepareReportId, null, request, manual, currentUser, manualReportName); } @@ -464,188 +464,216 @@ public class TestPlanReportService { */ private TestPlanReportDetailCaseDTO genReportDetail(TestPlanReportGenPreParam genParam, TestPlanReport report) { SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH); - // 缺陷数 List bugCountList = extTestPlanReportBugMapper.countPlanBug(genParam.getTestPlanId()); Map bugCountMap = bugCountList.stream().collect(Collectors.toMap(ReportBugCountDTO::getRefCaseId, ReportBugCountDTO::getBugCount)); - Project project = projectMapper.selectByPrimaryKey(genParam.getProjectId()); - - AtomicLong funcCaseCount = new AtomicLong(); - AtomicLong apiCaseCount = new AtomicLong(); - AtomicLong apiScenarioCount = new AtomicLong(); - AtomicLong bugCount = new AtomicLong(); - // 功能用例 - { - List funcCaseIdList = extTestPlanReportFunctionalCaseMapper.getPlanExecuteCasesId(genParam.getTestPlanId()); - if (CollectionUtils.isNotEmpty(funcCaseIdList)) { - SubListUtils.dealForSubList(funcCaseIdList, 200, (subList) -> { - if (CollectionUtils.isEmpty(subList)) { - return; - } - List reportFunctionCases = extTestPlanReportFunctionalCaseMapper.getPlanExecuteCases(genParam.getTestPlanId(), subList); - funcCaseCount.addAndGet(reportFunctionCases.size()); - // 用例等级 - List ids = reportFunctionCases.stream().map(TestPlanReportFunctionCase::getFunctionCaseId).distinct().toList(); - List options = extTestPlanReportFunctionalCaseMapper.getCasePriorityByIds(ids); - Map casePriorityMap = options.stream().collect(Collectors.toMap(SelectOption::getValue, SelectOption::getText)); - // 用例模块 - List moduleIds = reportFunctionCases.stream().map(TestPlanReportFunctionCase::getFunctionCaseModule).filter(Objects::nonNull).toList(); - Map moduleMap = getModuleMapByIds(moduleIds, CaseType.FUNCTIONAL_CASE.getKey()); - // 关联的功能用例最新一次执行历史 - List relateIds = reportFunctionCases.stream().map(TestPlanReportFunctionCase::getTestPlanFunctionCaseId).toList(); - TestPlanCaseExecuteHistoryExample example = new TestPlanCaseExecuteHistoryExample(); - example.createCriteria().andTestPlanCaseIdIn(relateIds); - List functionalExecHisList = testPlanCaseExecuteHistoryMapper.selectByExample(example); - Map> functionalExecMap = functionalExecHisList.stream().collect(Collectors.groupingBy(TestPlanCaseExecuteHistory::getTestPlanCaseId)); - - for (TestPlanReportFunctionCase reportFunctionalCase : reportFunctionCases) { - reportFunctionalCase.setId(IDGenerator.nextStr()); - reportFunctionalCase.setTestPlanReportId(report.getId()); - reportFunctionalCase.setTestPlanName(genParam.getTestPlanName()); - if (reportFunctionalCase.getFunctionCaseModule() != null) { - reportFunctionalCase.setFunctionCaseModule(moduleMap.getOrDefault(reportFunctionalCase.getFunctionCaseModule(), reportFunctionalCase.getFunctionCaseModule())); - } - reportFunctionalCase.setFunctionCasePriority(casePriorityMap.get(reportFunctionalCase.getFunctionCaseId())); - List hisList = functionalExecMap.get(reportFunctionalCase.getTestPlanFunctionCaseId()); - if (CollectionUtils.isNotEmpty(hisList)) { - Optional lastExecuteHisOpt = hisList.stream().sorted(Comparator.comparing(TestPlanCaseExecuteHistory::getCreateTime).reversed()).map(TestPlanCaseExecuteHistory::getId).findFirst(); - reportFunctionalCase.setFunctionCaseExecuteReportId(lastExecuteHisOpt.orElse(null)); - } else { - reportFunctionalCase.setFunctionCaseExecuteReportId(null); - } - reportFunctionalCase.setFunctionCaseBugCount(bugCountMap.containsKey(reportFunctionalCase.getTestPlanFunctionCaseId()) ? bugCountMap.get(reportFunctionalCase.getTestPlanFunctionCaseId()) : 0); - } - - // 插入计划功能用例关联数据 -> 报告内容 - TestPlanReportFunctionCaseMapper batchMapper = sqlSession.getMapper(TestPlanReportFunctionCaseMapper.class); - batchMapper.batchInsert(reportFunctionCases); - }); - } - funcCaseIdList = null; - } - - // 接口用例 - { - List testPlanReportApiCaseIdList = extTestPlanReportApiCaseMapper.getPlanExecuteCasesId(genParam.getTestPlanId()); - if (CollectionUtils.isNotEmpty(testPlanReportApiCaseIdList)) { - SubListUtils.dealForSubList(testPlanReportApiCaseIdList, 200, (subList) -> { - if (CollectionUtils.isEmpty(subList)) { - return; - } - List reportApiCases = extTestPlanReportApiCaseMapper.getPlanExecuteCases(genParam.getTestPlanId(), subList); - apiCaseCount.addAndGet(reportApiCases.size()); - List moduleIds = reportApiCases.stream().map(TestPlanReportApiCase::getApiCaseModule).filter(Objects::nonNull).distinct().toList(); - Map moduleMap = getModuleMapByIds(moduleIds, CaseType.API_CASE.getKey()); - - for (TestPlanReportApiCase reportApiCase : reportApiCases) { - reportApiCase.setId(IDGenerator.nextStr()); - reportApiCase.setTestPlanReportId(report.getId()); - reportApiCase.setTestPlanName(genParam.getTestPlanName()); - if (reportApiCase.getApiCaseModule() != null) { - reportApiCase.setApiCaseModule(moduleMap.getOrDefault(reportApiCase.getApiCaseModule(), reportApiCase.getApiCaseModule())); - } - // 根据不超过数据库字段最大长度压缩模块名 - reportApiCase.setApiCaseModule(ServiceUtils.compressName(reportApiCase.getApiCaseModule(), 450)); - if (!genParam.getUseManual()) { - // 接口执行时才更新结果 - reportApiCase.setApiCaseExecuteResult(null); - reportApiCase.setApiCaseExecuteUser(null); - } - reportApiCase.setApiCaseBugCount(bugCountMap.containsKey(reportApiCase.getTestPlanApiCaseId()) ? bugCountMap.get(reportApiCase.getTestPlanApiCaseId()) : 0); - } - // 插入计划接口用例关联数据 -> 报告内容 - TestPlanReportApiCaseMapper batchMapper = sqlSession.getMapper(TestPlanReportApiCaseMapper.class); - batchMapper.batchInsert(reportApiCases); - sqlSession.flushStatements(); - - if (StringUtils.isNotBlank(genParam.getTaskId())) { - reportApiCases.sort(Comparator.comparing(TestPlanReportApiCase::getPos).reversed()); - initApiCaseExecTaskItem(genParam.getTaskId(), genParam.getTestPlanId(), reportApiCases, report.getCreateUser(), project); - } - }); - } - testPlanReportApiCaseIdList = null; - } - - // 场景用例 - { - List reportApiScenarioIdList = extTestPlanReportApiScenarioMapper.getPlanExecuteCasesId(genParam.getTestPlanId()); - if (CollectionUtils.isNotEmpty(reportApiScenarioIdList)) { - SubListUtils.dealForSubList(reportApiScenarioIdList, 200, (subList) -> { - if (CollectionUtils.isEmpty(subList)) { - return; - } - List reportApiScenarios = extTestPlanReportApiScenarioMapper.getPlanExecuteCases(genParam.getTestPlanId(), subList); - apiScenarioCount.addAndGet(reportApiScenarios.size()); - List moduleIds = reportApiScenarios.stream().map(TestPlanReportApiScenario::getApiScenarioModule).filter(Objects::nonNull).distinct().toList(); - Map moduleMap = getModuleMapByIds(moduleIds, CaseType.SCENARIO_CASE.getKey()); - for (TestPlanReportApiScenario reportApiScenario : reportApiScenarios) { - reportApiScenario.setId(IDGenerator.nextStr()); - reportApiScenario.setTestPlanReportId(report.getId()); - reportApiScenario.setTestPlanName(genParam.getTestPlanName()); - if (reportApiScenario.getApiScenarioModule() != null) { - reportApiScenario.setApiScenarioModule(moduleMap.getOrDefault(reportApiScenario.getApiScenarioModule(), reportApiScenario.getApiScenarioModule())); - } - // 根据不超过数据库字段最大长度压缩模块名 - reportApiScenario.setApiScenarioModule(ServiceUtils.compressName(reportApiScenario.getApiScenarioModule(), 450)); - if (!genParam.getUseManual()) { - // 接口执行时才更新结果 - reportApiScenario.setApiScenarioExecuteResult(null); - reportApiScenario.setApiScenarioExecuteUser(null); - } - reportApiScenario.setApiScenarioBugCount(bugCountMap.containsKey(reportApiScenario.getTestPlanApiScenarioId()) ? bugCountMap.get(reportApiScenario.getTestPlanApiScenarioId()) : 0); - } - // 插入计划场景用例关联数据 -> 报告内容 - TestPlanReportApiScenarioMapper batchMapper = sqlSession.getMapper(TestPlanReportApiScenarioMapper.class); - batchMapper.batchInsert(reportApiScenarios); - sqlSession.flushStatements(); - - if (StringUtils.isNotBlank(genParam.getTaskId())) { - reportApiScenarios.sort(Comparator.comparing(TestPlanReportApiScenario::getPos).reversed()); - initScenarioExecTaskItem(genParam.getTaskId(), genParam.getTestPlanId(), reportApiScenarios, report.getCreateUser(), project); - } - }); - } - reportApiScenarioIdList = null; - } - - // 计划报告缺陷内容 - { - List reportBugIdList = extTestPlanReportBugMapper.getPlanBugsId(genParam.getTestPlanId()); - if (CollectionUtils.isNotEmpty(reportBugIdList)) { - SubListUtils.dealForSubList(reportBugIdList, 200, (subList) -> { - if (CollectionUtils.isEmpty(subList)) { - return; - } - List reportBugs = extTestPlanReportBugMapper.getPlanBugs(genParam.getTestPlanId(), subList); - bugCount.addAndGet(reportBugs.size()); - // MS处理人会与第三方的值冲突, 分开查询 - List headerOptions = bugCommonService.getHeaderHandlerOption(genParam.getProjectId()); - Map headerHandleUserMap = headerOptions.stream().collect(Collectors.toMap(SelectOption::getValue, SelectOption::getText)); - List localOptions = bugCommonService.getLocalHandlerOption(genParam.getProjectId()); - Map localHandleUserMap = localOptions.stream().collect(Collectors.toMap(SelectOption::getValue, SelectOption::getText)); - Map allStatusMap = bugCommonService.getAllStatusMap(genParam.getProjectId()); - reportBugs.forEach(reportBug -> { - reportBug.setId(IDGenerator.nextStr()); - reportBug.setTestPlanReportId(report.getId()); - reportBug.setBugHandleUser(headerHandleUserMap.containsKey(reportBug.getBugHandleUser()) ? - headerHandleUserMap.get(reportBug.getBugHandleUser()) : localHandleUserMap.get(reportBug.getBugHandleUser())); - reportBug.setBugStatus(allStatusMap.get(reportBug.getBugStatus())); - }); - // 插入计划关联用例缺陷数据(去重) -> 报告内容 - TestPlanReportBugMapper batchMapper = sqlSession.getMapper(TestPlanReportBugMapper.class); - batchMapper.batchInsert(reportBugs); - sqlSession.flushStatements(); - }); - } - } - - long beforeFlush = System.currentTimeMillis(); - sqlSession.flushStatements(); + long funcCount = initReportFunctionCase(sqlSession, genParam, report, bugCountMap); + long apiCount = initReportApiCase(sqlSession, genParam, report, project, bugCountMap); + long scenarioCount = initReportApiScenario(sqlSession, genParam, report, project, bugCountMap); + long bugCount = initReportBug(sqlSession, genParam, report); SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory); - return TestPlanReportDetailCaseDTO.builder() - .functionCaseCount(funcCaseCount.get()).apiCaseCount(apiCaseCount.get()).apiScenarioCount(apiScenarioCount.get()).bugCount(bugCount.get()).build(); + .functionCaseCount(funcCount).apiCaseCount(apiCount).apiScenarioCount(scenarioCount).bugCount(bugCount).build(); + } + + /** + * 批量初始化报告关联功能用例数据 + * @param sqlSession sql操作对象 + * @param genParam 报告生成参数 + * @param report 报告 + * @param bugCountMap 缺陷-用例 统计Map + * @return 执行条数 + */ + private long initReportFunctionCase(SqlSession sqlSession, TestPlanReportGenPreParam genParam, TestPlanReport report, Map bugCountMap) { + AtomicLong funcCaseCount = new AtomicLong(); + List funcCaseIdList = extTestPlanReportFunctionalCaseMapper.getPlanExecuteCasesId(genParam.getTestPlanId()); + if (CollectionUtils.isNotEmpty(funcCaseIdList)) { + SubListUtils.dealForSubList(funcCaseIdList, 200, (subList) -> { + if (CollectionUtils.isEmpty(subList)) { + return; + } + List reportFunctionCases = extTestPlanReportFunctionalCaseMapper.getPlanExecuteCases(genParam.getTestPlanId(), subList); + funcCaseCount.addAndGet(reportFunctionCases.size()); + // 用例等级 + List ids = reportFunctionCases.stream().map(TestPlanReportFunctionCase::getFunctionCaseId).distinct().toList(); + List options = extTestPlanReportFunctionalCaseMapper.getCasePriorityByIds(ids); + Map casePriorityMap = options.stream().collect(Collectors.toMap(SelectOption::getValue, SelectOption::getText)); + // 用例模块 + List moduleIds = reportFunctionCases.stream().map(TestPlanReportFunctionCase::getFunctionCaseModule).filter(Objects::nonNull).toList(); + Map moduleMap = getModuleMapByIds(moduleIds, CaseType.FUNCTIONAL_CASE.getKey()); + // 关联的功能用例最新一次执行历史 + List relateIds = reportFunctionCases.stream().map(TestPlanReportFunctionCase::getTestPlanFunctionCaseId).toList(); + TestPlanCaseExecuteHistoryExample example = new TestPlanCaseExecuteHistoryExample(); + example.createCriteria().andTestPlanCaseIdIn(relateIds); + List functionalExecHisList = testPlanCaseExecuteHistoryMapper.selectByExample(example); + Map> functionalExecMap = functionalExecHisList.stream().collect(Collectors.groupingBy(TestPlanCaseExecuteHistory::getTestPlanCaseId)); + + for (TestPlanReportFunctionCase reportFunctionalCase : reportFunctionCases) { + reportFunctionalCase.setId(IDGenerator.nextStr()); + reportFunctionalCase.setTestPlanReportId(report.getId()); + reportFunctionalCase.setTestPlanName(genParam.getTestPlanName()); + if (reportFunctionalCase.getFunctionCaseModule() != null) { + reportFunctionalCase.setFunctionCaseModule(moduleMap.getOrDefault(reportFunctionalCase.getFunctionCaseModule(), reportFunctionalCase.getFunctionCaseModule())); + } + reportFunctionalCase.setFunctionCasePriority(casePriorityMap.get(reportFunctionalCase.getFunctionCaseId())); + List hisList = functionalExecMap.get(reportFunctionalCase.getTestPlanFunctionCaseId()); + if (CollectionUtils.isNotEmpty(hisList)) { + Optional lastExecuteHisOpt = hisList.stream().sorted(Comparator.comparing(TestPlanCaseExecuteHistory::getCreateTime).reversed()).map(TestPlanCaseExecuteHistory::getId).findFirst(); + reportFunctionalCase.setFunctionCaseExecuteReportId(lastExecuteHisOpt.orElse(null)); + } else { + reportFunctionalCase.setFunctionCaseExecuteReportId(null); + } + reportFunctionalCase.setFunctionCaseBugCount(bugCountMap.containsKey(reportFunctionalCase.getTestPlanFunctionCaseId()) ? bugCountMap.get(reportFunctionalCase.getTestPlanFunctionCaseId()) : 0); + } + + // 插入计划功能用例关联数据 -> 报告内容 + TestPlanReportFunctionCaseMapper batchMapper = sqlSession.getMapper(TestPlanReportFunctionCaseMapper.class); + batchMapper.batchInsert(reportFunctionCases); + sqlSession.flushStatements(); + }); + } + return funcCaseCount.get(); + } + + /** + * 批量初始化报告关联接口用例数据 + * @param sqlSession sql操作对象 + * @param genParam 报告生成参数 + * @param report 报告 + * @param project 项目 + * @param bugCountMap 缺陷-用例 统计Map + * @return 执行条数 + */ + private long initReportApiCase(SqlSession sqlSession, TestPlanReportGenPreParam genParam, TestPlanReport report, Project project, Map bugCountMap) { + AtomicLong apiCaseCount = new AtomicLong(); + List testPlanReportApiCaseIdList = extTestPlanReportApiCaseMapper.getPlanExecuteCasesId(genParam.getTestPlanId()); + if (CollectionUtils.isNotEmpty(testPlanReportApiCaseIdList)) { + SubListUtils.dealForSubList(testPlanReportApiCaseIdList, 200, (subList) -> { + if (CollectionUtils.isEmpty(subList)) { + return; + } + List reportApiCases = extTestPlanReportApiCaseMapper.getPlanExecuteCases(genParam.getTestPlanId(), subList); + apiCaseCount.addAndGet(reportApiCases.size()); + List moduleIds = reportApiCases.stream().map(TestPlanReportApiCase::getApiCaseModule).filter(Objects::nonNull).distinct().toList(); + Map moduleMap = getModuleMapByIds(moduleIds, CaseType.API_CASE.getKey()); + for (TestPlanReportApiCase reportApiCase : reportApiCases) { + reportApiCase.setId(IDGenerator.nextStr()); + reportApiCase.setTestPlanReportId(report.getId()); + reportApiCase.setTestPlanName(genParam.getTestPlanName()); + if (reportApiCase.getApiCaseModule() != null) { + reportApiCase.setApiCaseModule(moduleMap.getOrDefault(reportApiCase.getApiCaseModule(), reportApiCase.getApiCaseModule())); + } + // 根据不超过数据库字段最大长度压缩模块名 + reportApiCase.setApiCaseModule(ServiceUtils.compressName(reportApiCase.getApiCaseModule(), 450)); + if (!genParam.getUseManual()) { + // 接口执行时才更新结果 + reportApiCase.setApiCaseExecuteResult(null); + reportApiCase.setApiCaseExecuteUser(null); + } + reportApiCase.setApiCaseBugCount(bugCountMap.containsKey(reportApiCase.getTestPlanApiCaseId()) ? bugCountMap.get(reportApiCase.getTestPlanApiCaseId()) : 0); + } + // 插入计划接口用例关联数据 -> 报告内容 + TestPlanReportApiCaseMapper batchMapper = sqlSession.getMapper(TestPlanReportApiCaseMapper.class); + batchMapper.batchInsert(reportApiCases); + sqlSession.flushStatements(); + + if (StringUtils.isNotBlank(genParam.getTaskId())) { + reportApiCases.sort(Comparator.comparing(TestPlanReportApiCase::getPos).reversed()); + initApiCaseExecTaskItem(genParam.getTaskId(), genParam.getTestPlanId(), reportApiCases, report.getCreateUser(), project); + } + }); + } + return apiCaseCount.get(); + } + + /** + * 批量初始化报告关联场景用例数据 + * @param sqlSession sql操作对象 + * @param genParam 报告生成参数 + * @param report 报告 + * @param project 项目 + * @param bugCountMap 缺陷-用例 统计Map + * @return 执行条数 + */ + private long initReportApiScenario(SqlSession sqlSession, TestPlanReportGenPreParam genParam, TestPlanReport report, Project project, Map bugCountMap) { + AtomicLong apiScenarioCount = new AtomicLong(); + List reportApiScenarioIdList = extTestPlanReportApiScenarioMapper.getPlanExecuteCasesId(genParam.getTestPlanId()); + if (CollectionUtils.isNotEmpty(reportApiScenarioIdList)) { + SubListUtils.dealForSubList(reportApiScenarioIdList, 200, (subList) -> { + if (CollectionUtils.isEmpty(subList)) { + return; + } + List reportApiScenarios = extTestPlanReportApiScenarioMapper.getPlanExecuteCases(genParam.getTestPlanId(), subList); + apiScenarioCount.addAndGet(reportApiScenarios.size()); + List moduleIds = reportApiScenarios.stream().map(TestPlanReportApiScenario::getApiScenarioModule).filter(Objects::nonNull).distinct().toList(); + Map moduleMap = getModuleMapByIds(moduleIds, CaseType.SCENARIO_CASE.getKey()); + for (TestPlanReportApiScenario reportApiScenario : reportApiScenarios) { + reportApiScenario.setId(IDGenerator.nextStr()); + reportApiScenario.setTestPlanReportId(report.getId()); + reportApiScenario.setTestPlanName(genParam.getTestPlanName()); + if (reportApiScenario.getApiScenarioModule() != null) { + reportApiScenario.setApiScenarioModule(moduleMap.getOrDefault(reportApiScenario.getApiScenarioModule(), reportApiScenario.getApiScenarioModule())); + } + // 根据不超过数据库字段最大长度压缩模块名 + reportApiScenario.setApiScenarioModule(ServiceUtils.compressName(reportApiScenario.getApiScenarioModule(), 450)); + if (!genParam.getUseManual()) { + // 接口执行时才更新结果 + reportApiScenario.setApiScenarioExecuteResult(null); + reportApiScenario.setApiScenarioExecuteUser(null); + } + reportApiScenario.setApiScenarioBugCount(bugCountMap.containsKey(reportApiScenario.getTestPlanApiScenarioId()) ? bugCountMap.get(reportApiScenario.getTestPlanApiScenarioId()) : 0); + } + // 插入计划场景用例关联数据 -> 报告内容 + TestPlanReportApiScenarioMapper batchMapper = sqlSession.getMapper(TestPlanReportApiScenarioMapper.class); + batchMapper.batchInsert(reportApiScenarios); + sqlSession.flushStatements(); + + if (StringUtils.isNotBlank(genParam.getTaskId())) { + reportApiScenarios.sort(Comparator.comparing(TestPlanReportApiScenario::getPos).reversed()); + initScenarioExecTaskItem(genParam.getTaskId(), genParam.getTestPlanId(), reportApiScenarios, report.getCreateUser(), project); + } + }); + } + return apiScenarioCount.get(); + } + + /** + * 批量初始化报告关联缺陷数据 + * @param sqlSession sql操作对象 + * @param genParam 报告生成参数 + * @param report 报告 + * @return 执行条数 + */ + private long initReportBug(SqlSession sqlSession, TestPlanReportGenPreParam genParam, TestPlanReport report) { + AtomicLong bugCount = new AtomicLong(); + List reportBugIdList = extTestPlanReportBugMapper.getPlanBugsId(genParam.getTestPlanId()); + if (CollectionUtils.isNotEmpty(reportBugIdList)) { + SubListUtils.dealForSubList(reportBugIdList, 200, (subList) -> { + if (CollectionUtils.isEmpty(subList)) { + return; + } + List reportBugs = extTestPlanReportBugMapper.getPlanBugs(genParam.getTestPlanId(), subList); + bugCount.addAndGet(reportBugs.size()); + // MS处理人会与第三方的值冲突, 分开查询 + List headerOptions = bugCommonService.getHeaderHandlerOption(genParam.getProjectId()); + Map headerHandleUserMap = headerOptions.stream().collect(Collectors.toMap(SelectOption::getValue, SelectOption::getText)); + List localOptions = bugCommonService.getLocalHandlerOption(genParam.getProjectId()); + Map localHandleUserMap = localOptions.stream().collect(Collectors.toMap(SelectOption::getValue, SelectOption::getText)); + Map allStatusMap = bugCommonService.getAllStatusMap(genParam.getProjectId()); + reportBugs.forEach(reportBug -> { + reportBug.setId(IDGenerator.nextStr()); + reportBug.setTestPlanReportId(report.getId()); + reportBug.setBugHandleUser(headerHandleUserMap.containsKey(reportBug.getBugHandleUser()) ? + headerHandleUserMap.get(reportBug.getBugHandleUser()) : localHandleUserMap.get(reportBug.getBugHandleUser())); + reportBug.setBugStatus(allStatusMap.get(reportBug.getBugStatus())); + }); + // 插入计划关联用例缺陷数据(去重) -> 报告内容 + TestPlanReportBugMapper batchMapper = sqlSession.getMapper(TestPlanReportBugMapper.class); + batchMapper.batchInsert(reportBugs); + sqlSession.flushStatements(); + }); + } + return bugCount.get(); } private void initApiCaseExecTaskItem(String taskId, String testPlanId, List apiTestCases, String userId, Project project) { @@ -793,20 +821,15 @@ public class TestPlanReportService { return planReportDetail; } + /** + * 获取计划任务执行结果 + * @param taskId 任务ID + * @return 计划执行结果 + */ public TestPlanTaskReportResponse getTaskDetail(String taskId) { TestPlanTaskReportResponse testPlanTaskReportResponse = new TestPlanTaskReportResponse(); ExecTask task = execTaskMapper.selectByPrimaryKey(taskId); BeanUtils.copyBean(testPlanTaskReportResponse, task); - TestPlanExample planExample = new TestPlanExample(); - planExample.createCriteria().andGroupIdEqualTo(task.getResourceId()); - List testPlans = testPlanMapper.selectByExample(planExample); - List childPlans = testPlans.stream().map(plan -> { - TestPlanTaskReportResponse.ChildPlan childPlan = new TestPlanTaskReportResponse.ChildPlan(); - childPlan.setId(plan.getId()); - childPlan.setName(plan.getName()); - return childPlan; - }).toList(); - testPlanTaskReportResponse.setChildPlans(childPlans); ApiReportRelateTaskExample example = new ApiReportRelateTaskExample(); example.createCriteria().andTaskResourceIdEqualTo(taskId); List taskReports = apiReportRelateTaskMapper.selectByExample(example); @@ -815,6 +838,14 @@ public class TestPlanReportService { return testPlanTaskReportResponse; } String reportId = taskReports.getFirst().getReportId(); + List planChildrenTask = extTestPlanReportMapper.getPlanChildrenTask(reportId); + List childPlans = planChildrenTask.stream().map(childTask -> { + TestPlanTaskReportResponse.ChildPlan childPlan = new TestPlanTaskReportResponse.ChildPlan(); + childPlan.setId(childTask.getId()); + childPlan.setName(childTask.getName()); + return childPlan; + }).toList(); + testPlanTaskReportResponse.setChildPlans(childPlans); return calcTaskExecActual(reportId, testPlanTaskReportResponse); } @@ -878,9 +909,7 @@ public class TestPlanReportService { List distinctUserIds = detailCases.stream().map(ReportDetailCasePageDTO::getExecuteUser).distinct().collect(Collectors.toList()); distinctUserIds.removeIf(StringUtils::isEmpty); Map userMap = getUserMap(distinctUserIds); - detailCases.forEach(detailCase -> { - detailCase.setExecuteUser(userMap.getOrDefault(detailCase.getExecuteUser(), detailCase.getExecuteUser())); - }); + detailCases.forEach(detailCase -> detailCase.setExecuteUser(userMap.getOrDefault(detailCase.getExecuteUser(), detailCase.getExecuteUser()))); return detailCases; } @@ -915,13 +944,13 @@ public class TestPlanReportService { return; } // 功能用例 - List functionalCountMapList = extTestPlanReportFunctionalCaseMapper.countExecuteResult(reportId); + List functionalCountMapList = extTestPlanReportFunctionalCaseMapper.countExecuteResult(List.of(reportId)); CaseCount functionalCaseCount = countMap(functionalCountMapList); // 接口用例 - List apiCountMapList = extTestPlanReportApiCaseMapper.countExecuteResult(reportId); + List apiCountMapList = extTestPlanReportApiCaseMapper.countExecuteResult(List.of(reportId)); CaseCount apiCaseCount = countMap(apiCountMapList); // 场景用例 - List scenarioCountMapList = extTestPlanReportApiScenarioMapper.countExecuteResult(reportId); + List scenarioCountMapList = extTestPlanReportApiScenarioMapper.countExecuteResult(List.of(reportId)); CaseCount scenarioCaseCount = countMap(scenarioCountMapList); // 规划整体的汇总数据 @@ -950,7 +979,7 @@ public class TestPlanReportService { summaryExample.createCriteria().andTestPlanReportIdEqualTo(reportId); List testPlanReportSummaries = testPlanReportSummaryMapper.selectByExample(summaryExample); if (CollectionUtils.isEmpty(testPlanReportSummaries)) { - // 报告详情不存在 + // 计划组报告详情不存在 return; } TestPlanReportSummary groupSummary = testPlanReportSummaries.getFirst(); @@ -963,69 +992,27 @@ public class TestPlanReportService { return; } - // 汇总子报告关联的数据并入库 - SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH); + // 汇总子报告关联的数据 (计划组的用例明细不入库) List ids = testPlanReports.stream().map(TestPlanReport::getId).toList(); - // 功能用例 + // 汇总功能用例 TestPlanReportFunctionCaseExample functionCaseExample = new TestPlanReportFunctionCaseExample(); functionCaseExample.createCriteria().andTestPlanReportIdIn(ids); - List reportFunctionCases = testPlanReportFunctionCaseMapper.selectByExample(functionCaseExample); - if (CollectionUtils.isNotEmpty(reportFunctionCases)) { - groupSummary.setFunctionalCaseCount((long) reportFunctionCases.size()); - reportFunctionCases.forEach(reportFunctionCase -> { - reportFunctionCase.setId(IDGenerator.nextStr()); - reportFunctionCase.setTestPlanReportId(reportId); - }); - // 插入计划组报告, 功能用例关联数据 - TestPlanReportFunctionCaseMapper batchMapper = sqlSession.getMapper(TestPlanReportFunctionCaseMapper.class); - batchMapper.batchInsert(reportFunctionCases); - } - // 接口用例 + groupSummary.setFunctionalCaseCount(testPlanReportFunctionCaseMapper.countByExample(functionCaseExample)); + // 汇总接口用例 TestPlanReportApiCaseExample apiCaseExample = new TestPlanReportApiCaseExample(); apiCaseExample.createCriteria().andTestPlanReportIdIn(ids); - List reportApiCases = testPlanReportApiCaseMapper.selectByExample(apiCaseExample); - if (CollectionUtils.isNotEmpty(reportApiCases)) { - groupSummary.setApiCaseCount((long) reportApiCases.size()); - reportApiCases.forEach(reportApiCase -> { - reportApiCase.setId(IDGenerator.nextStr()); - reportApiCase.setTestPlanReportId(reportId); - }); - // 插入计划组报告, 接口用例关联数据 - TestPlanReportApiCaseMapper batchMapper = sqlSession.getMapper(TestPlanReportApiCaseMapper.class); - batchMapper.batchInsert(reportApiCases); - } - // 场景用例 + groupSummary.setApiCaseCount(testPlanReportApiCaseMapper.countByExample(apiCaseExample)); + // 汇总场景用例 TestPlanReportApiScenarioExample scenarioExample = new TestPlanReportApiScenarioExample(); scenarioExample.createCriteria().andTestPlanReportIdIn(ids); - List reportApiScenarios = testPlanReportApiScenarioMapper.selectByExample(scenarioExample); - if (CollectionUtils.isNotEmpty(reportApiScenarios)) { - groupSummary.setApiScenarioCount((long) reportApiScenarios.size()); - reportApiScenarios.forEach(reportApiScenario -> { - reportApiScenario.setId(IDGenerator.nextStr()); - reportApiScenario.setTestPlanReportId(reportId); - }); - // 插入计划组报告, 场景用例关联数据 - TestPlanReportApiScenarioMapper batchMapper = sqlSession.getMapper(TestPlanReportApiScenarioMapper.class); - batchMapper.batchInsert(reportApiScenarios); - } - // 缺陷明细 + groupSummary.setApiScenarioCount(testPlanReportApiScenarioMapper.countByExample(scenarioExample)); + // 汇总缺陷明细 (子计划同一缺陷去重) TestPlanReportBugExample bugExample = new TestPlanReportBugExample(); bugExample.createCriteria().andTestPlanReportIdIn(ids); List reportBugs = testPlanReportBugMapper.selectByExample(bugExample); - if (CollectionUtils.isNotEmpty(reportBugs)) { - groupSummary.setBugCount((long) reportBugs.size()); - reportBugs.forEach(reportBug -> { - reportBug.setId(IDGenerator.nextStr()); - reportBug.setTestPlanReportId(reportId); - }); - // 插入计划组关联用例缺陷数据 - TestPlanReportBugMapper batchMapper = sqlSession.getMapper(TestPlanReportBugMapper.class); - batchMapper.batchInsert(reportBugs); - } - sqlSession.flushStatements(); - SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory); + groupSummary.setBugCount(reportBugs.stream().map(TestPlanReportBug::getBugId).distinct().count()); - // 汇总并计算子报告执行的数据 + // 汇总并计算子报告执行的用例数据 summaryExample.clear(); summaryExample.createCriteria().andTestPlanReportIdIn(ids); List summaryList = testPlanReportSummaryMapper.selectByExampleWithBLOBs(summaryExample); @@ -1281,22 +1268,6 @@ public class TestPlanReportService { return userOptions.stream().collect(Collectors.toMap(OptionDTO::getId, OptionDTO::getName)); } - /** - * 获取测试点集合 - * - * @param collectionIds 测试点ID集合 - * @return 测试点集合 - */ - private Map getCollectionMap(List collectionIds) { - if (CollectionUtils.isEmpty(collectionIds)) { - return new HashMap<>(16); - } - TestPlanCollectionExample example = new TestPlanCollectionExample(); - example.createCriteria().andIdIn(collectionIds); - List collections = testPlanCollectionMapper.selectByExample(example); - return collections.stream().collect(Collectors.toMap(TestPlanCollection::getId, TestPlanCollection::getName)); - } - /** * 计划报告列表 * @@ -1430,11 +1401,12 @@ public class TestPlanReportService { */ private TestPlanTaskReportResponse calcTaskExecActual(String reportId, TestPlanTaskReportResponse testPlanTaskReportResponse) { testPlanTaskReportResponse.setReportId(reportId); + List calcReportIds = getActualReportIds(reportId); // 计算接口用例 - List apiCountMapList = extTestPlanReportApiCaseMapper.countExecuteResult(reportId); + List apiCountMapList = extTestPlanReportApiCaseMapper.countExecuteResult(calcReportIds); CaseCount apiCaseCount = countMap(apiCountMapList); // 计算场景用例 - List scenarioCountMapList = extTestPlanReportApiScenarioMapper.countExecuteResult(reportId); + List scenarioCountMapList = extTestPlanReportApiScenarioMapper.countExecuteResult(calcReportIds); CaseCount scenarioCaseCount = countMap(scenarioCountMapList); // 汇总接口&&场景用例的执行情况 CaseCount caseCount = CountUtils.summarizeProperties(List.of(apiCaseCount, scenarioCaseCount)); @@ -1444,4 +1416,22 @@ public class TestPlanReportService { 0 : RateCalculateUtils.divWithPrecision(caseCount.sum() - caseCount.getPending(), caseCount.sum(), 2)); return testPlanTaskReportResponse; } + + /** + * 获取实际的报告ID集合 (计划组报告则会返回多个) + * @param reportId 报告ID + * @return 报告ID集合 + */ + public List getActualReportIds(String reportId) { + // 计划组任务结果, 取多个子计划的结果计算完成率 + TestPlanReport report = testPlanReportMapper.selectByPrimaryKey(reportId); + if (report.getIntegrated()) { + TestPlanReportExample example = new TestPlanReportExample(); + example.createCriteria().andParentIdEqualTo(reportId).andIntegratedEqualTo(false); + List testPlanReports = testPlanReportMapper.selectByExample(example); + return testPlanReports.stream().map(TestPlanReport::getId).toList(); + } else { + return List.of(reportId); + } + } }