feat(工作台): 增加计划遗留缺陷统计

This commit is contained in:
guoyuqi 2024-11-14 14:16:27 +08:00 committed by Craftsman
parent 0d35aaf821
commit 622cc8c814
8 changed files with 252 additions and 131 deletions

View File

@ -72,6 +72,9 @@ CREATE INDEX idx_project_id_delete_create_time
CREATE INDEX idx_project_id_delete_create_time_create_user
ON bug (project_id, deleted, create_time, create_user);
create index idx_test_plan_id_bug_id
on bug_relation_case (test_plan_id, bug_id);
ALTER TABLE exec_task ADD COLUMN deleted bit(1) NOT NULL DEFAULT b'0' COMMENT '删除标识';
ALTER TABLE exec_task_item ADD COLUMN deleted bit(1) NOT NULL DEFAULT b'0' COMMENT '删除标识';
ALTER TABLE exec_task_item ADD COLUMN case_id VARCHAR(50) COMMENT '用例表id';

View File

@ -144,12 +144,19 @@ public class DashboardController {
}
@PostMapping("/handle_bug_by_me")
@Operation(summary = "我创建的缺陷")
@Operation(summary = "待我处理的缺陷")
@CheckOwner(resourceId = "#request.getOrganizationId()", resourceType = "organization")
public StatisticsDTO projectBugCountHandleByMe(@Validated @RequestBody DashboardFrontPageRequest request) {
return dashboardService.projectBugCountHandleByMe(request, SessionUtils.getUserId());
}
@PostMapping("/plan_legacy_bug")
@Operation(summary = "计划遗留bug统计")
@CheckOwner(resourceId = "#request.getOrganizationId()", resourceType = "organization")
public StatisticsDTO projectPlanLegacyBug(@Validated @RequestBody DashboardFrontPageRequest request) {
return dashboardService.projectPlanLegacyBug(request, SessionUtils.getUserId());
}
@PostMapping("/reviewing_by_me")
@Operation(summary = "待我评审")

View File

@ -48,6 +48,7 @@ import io.metersphere.project.service.ProjectService;
import io.metersphere.sdk.constants.ExecStatus;
import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.sdk.constants.ResultStatus;
import io.metersphere.sdk.constants.TestPlanConstants;
import io.metersphere.sdk.dto.CombineCondition;
import io.metersphere.sdk.dto.CombineSearch;
import io.metersphere.sdk.util.JSON;
@ -335,40 +336,91 @@ public class DashboardService {
UserLayoutExample userLayoutExample = new UserLayoutExample();
userLayoutExample.createCriteria().andUserIdEqualTo(userId).andOrgIdEqualTo(organizationId);
List<UserLayout> userLayouts = userLayoutMapper.selectByExampleWithBLOBs(userLayoutExample);
if (CollectionUtils.isEmpty(userLayouts)) {
return getDefaultLayoutDTOS(organizationId);
List<Project> allPermissionProjects = extProjectMapper.getUserProjectIdName(organizationId, null, userId);
if (CollectionUtils.isEmpty(allPermissionProjects)) {
return new ArrayList<>();
}
if (CollectionUtils.isEmpty(userLayouts)) {
return getDefaultLayoutDTOS(allPermissionProjects.getFirst().getId());
}
UserLayout userLayout = userLayouts.getFirst();
byte[] configuration = userLayout.getConfiguration();
String layoutDTOStr = new String(configuration);
List<LayoutDTO> layoutDTOS = JSON.parseArray(layoutDTOStr, LayoutDTO.class);
//重新查询排除项目禁用的或者用户已经移除某个项目的项目或者成员
List<String> oldAllProjectIds = new ArrayList<>();
List<String> oldHallHandleUsers = new ArrayList<>();
for (LayoutDTO layoutDTO : layoutDTOS) {
oldAllProjectIds.addAll(layoutDTO.getProjectIds());
oldHallHandleUsers.addAll(layoutDTO.getHandleUsers());
}
List<Project> hasPermissionProjectList;
if (CollectionUtils.isEmpty(oldAllProjectIds)) {
hasPermissionProjectList = extProjectMapper.getUserProjectIdName(organizationId, null, userId);
} else {
List<String> projectIds = oldAllProjectIds.stream().distinct().toList();
hasPermissionProjectList = extProjectMapper.getUserProjectIdName(null, projectIds, userId);
if (CollectionUtils.isEmpty(hasPermissionProjectList)) {
hasPermissionProjectList = extProjectMapper.getUserProjectIdName(organizationId, null, userId);
}
}
Map<String, Project> projectMap = hasPermissionProjectList.stream().collect(Collectors.toMap(Project::getId, t -> t));
List<String> handleUsers = oldHallHandleUsers.stream().distinct().toList();
List<ProjectUserMemberDTO> orgProjectMemberList = extProjectMemberMapper.getOrgProjectMemberList(organizationId, handleUsers);
//重新填充填充返回的项目id 用户id
rebuildProjectOrUser(layoutDTOS, hasPermissionProjectList, projectMap, orgProjectMemberList);
Map<String, Set<String>> permissionModuleProjectIdMap = dashboardProjectService.getPermissionModuleProjectIds(allPermissionProjects, userId);
List<ProjectUserMemberDTO> orgProjectMemberList = extProjectMemberMapper.getOrgProjectMemberList(organizationId, null);
rebuildLayouts(layoutDTOS, allPermissionProjects, orgProjectMemberList, permissionModuleProjectIdMap);
return layoutDTOS;
}
/**
* 过滤用户在当前项目是否有移除或者项目是否被禁用以及用户是否被删除禁用
* @param layoutDTOS 用户保存的布局
* @param allPermissionProjects 用户有任意权限的所有在役项目
* @param orgProjectMemberList 当前组织下所有有项目权限的成员
* @param permissionModuleProjectIdMap 只读权限对应的开启模块的项目ids
*/
private void rebuildLayouts(List<LayoutDTO> layoutDTOS, List<Project> allPermissionProjects, List<ProjectUserMemberDTO> orgProjectMemberList, Map<String, Set<String>> permissionModuleProjectIdMap) {
for (LayoutDTO layoutDTO : layoutDTOS) {
if (StringUtils.equalsIgnoreCase(layoutDTO.getKey(), DashboardUserLayoutKeys.PROJECT_VIEW.toString()) || StringUtils.equalsIgnoreCase(layoutDTO.getKey(), DashboardUserLayoutKeys.CREATE_BY_ME.toString())) {
List<Project> list = allPermissionProjects.stream().filter(t -> layoutDTO.getProjectIds().contains(t.getId())).toList();
if (CollectionUtils.isNotEmpty(list)) {
layoutDTO.setProjectIds(list.stream().map(Project::getId).toList());
} else {
layoutDTO.setProjectIds(allPermissionProjects.stream().map(Project::getId).toList());
}
} else if (StringUtils.equalsIgnoreCase(layoutDTO.getKey(), DashboardUserLayoutKeys.PROJECT_MEMBER_VIEW.toString())) {
List<ProjectUserMemberDTO> list = orgProjectMemberList.stream().filter(t -> layoutDTO.getHandleUsers().contains(t.getId())).toList();
layoutDTO.setHandleUsers(list.stream().map(ProjectUserMemberDTO::getId).toList());
List<Project> projectList = allPermissionProjects.stream().filter(t -> layoutDTO.getProjectIds().contains(t.getId())).toList();
if (CollectionUtils.isEmpty(projectList)) {
layoutDTO.setProjectIds(List.of(allPermissionProjects.getFirst().getId()));
} else {
layoutDTO.setProjectIds(List.of(projectList.getFirst().getId()));
}
} else if(StringUtils.equalsIgnoreCase(layoutDTO.getKey(), DashboardUserLayoutKeys.CASE_COUNT.toString())
|| StringUtils.equalsIgnoreCase(layoutDTO.getKey(), DashboardUserLayoutKeys.ASSOCIATE_CASE_COUNT.toString())
||StringUtils.equalsIgnoreCase(layoutDTO.getKey(), DashboardUserLayoutKeys.REVIEW_CASE_COUNT.toString())
|| StringUtils.equalsIgnoreCase(layoutDTO.getKey(), DashboardUserLayoutKeys.REVIEWING_BY_ME.toString())) {
Set<String> hasReadProjectIds = permissionModuleProjectIdMap.get(PermissionConstants.FUNCTIONAL_CASE_READ);
checkHasPermissionProject(layoutDTO, hasReadProjectIds);
} else if (StringUtils.equalsIgnoreCase(layoutDTO.getKey(), DashboardUserLayoutKeys.API_COUNT.toString())
|| StringUtils.equalsIgnoreCase(layoutDTO.getKey(), DashboardUserLayoutKeys.API_CHANGE.toString())) {
Set<String> hasReadProjectIds = permissionModuleProjectIdMap.get(PermissionConstants.PROJECT_API_DEFINITION_READ);
checkHasPermissionProject(layoutDTO, hasReadProjectIds);
} else if (StringUtils.equalsIgnoreCase(layoutDTO.getKey(), DashboardUserLayoutKeys.API_CASE_COUNT.toString())){
Set<String> hasReadProjectIds = permissionModuleProjectIdMap.get(PermissionConstants.PROJECT_API_DEFINITION_CASE_READ);
checkHasPermissionProject(layoutDTO, hasReadProjectIds);
}else if (StringUtils.equalsIgnoreCase(layoutDTO.getKey(), DashboardUserLayoutKeys.SCENARIO_COUNT.toString())){
Set<String> hasReadProjectIds = permissionModuleProjectIdMap.get(PermissionConstants.PROJECT_API_SCENARIO_READ);
checkHasPermissionProject(layoutDTO, hasReadProjectIds);
}
else if (StringUtils.equalsIgnoreCase(layoutDTO.getKey(), DashboardUserLayoutKeys.TEST_PLAN_COUNT.toString())
|| StringUtils.equalsIgnoreCase(layoutDTO.getKey(), DashboardUserLayoutKeys.PLAN_LEGACY_BUG.toString())) {
Set<String> hasReadProjectIds = permissionModuleProjectIdMap.get(PermissionConstants.TEST_PLAN_READ);
checkHasPermissionProject(layoutDTO, hasReadProjectIds);
}else if (StringUtils.equalsIgnoreCase(layoutDTO.getKey(), DashboardUserLayoutKeys.BUG_COUNT.toString())
|| StringUtils.equalsIgnoreCase(layoutDTO.getKey(), DashboardUserLayoutKeys.CREATE_BUG_BY_ME.toString())
||StringUtils.equalsIgnoreCase(layoutDTO.getKey(), DashboardUserLayoutKeys.HANDLE_BUG_BY_ME.toString())
|| StringUtils.equalsIgnoreCase(layoutDTO.getKey(), DashboardUserLayoutKeys.BUG_HANDLE_USER.toString())) {
Set<String> hasReadProjectIds = permissionModuleProjectIdMap.get(PermissionConstants.PROJECT_BUG_READ);
checkHasPermissionProject(layoutDTO, hasReadProjectIds);
}
}
}
private void checkHasPermissionProject(LayoutDTO layoutDTO, Set<String> hasReadProjectIds) {
if (CollectionUtils.isEmpty(hasReadProjectIds)) {
return;
}
List<String> projectIds = hasReadProjectIds.stream().filter(t -> layoutDTO.getProjectIds().contains(t)).toList();
if (CollectionUtils.isEmpty(projectIds)) {
layoutDTO.setProjectIds(List.of(new ArrayList<>(hasReadProjectIds).getFirst()));
} else {
layoutDTO.setProjectIds(List.of(projectIds.getFirst()));
}
}
/**
* 获取默认布局
*
@ -379,9 +431,9 @@ public class DashboardService {
List<LayoutDTO> layoutDTOS = new ArrayList<>();
LayoutDTO projectLayoutDTO = buildDefaultLayoutDTO(DashboardUserLayoutKeys.PROJECT_VIEW, "workbench.homePage.projectOverview", 0, new ArrayList<>());
layoutDTOS.add(projectLayoutDTO);
LayoutDTO createByMeLayoutDTO = buildDefaultLayoutDTO(DashboardUserLayoutKeys.CREATE_BY_ME, "workbench,homePage.createdByMe", 1, new ArrayList<>());
LayoutDTO createByMeLayoutDTO = buildDefaultLayoutDTO(DashboardUserLayoutKeys.CREATE_BY_ME, "workbench.homePage.createdByMe", 1, new ArrayList<>());
layoutDTOS.add(createByMeLayoutDTO);
LayoutDTO projectMemberLayoutDTO = buildDefaultLayoutDTO(DashboardUserLayoutKeys.PROJECT_MEMBER_VIEW, "workbench,homePage.staffOverview", 2, List.of(organizationId));
LayoutDTO projectMemberLayoutDTO = buildDefaultLayoutDTO(DashboardUserLayoutKeys.PROJECT_MEMBER_VIEW, "workbench.homePage.staffOverview", 2, List.of(organizationId));
layoutDTOS.add(projectMemberLayoutDTO);
return layoutDTOS;
}
@ -407,30 +459,6 @@ public class DashboardService {
return layoutDTO;
}
/**
* 过滤用户在当前项目是否有移除或者项目是否被禁用以及用户是否被删除禁用
*
* @param layoutDTOS 获取的所有布局卡片
* @param hasPermissionProjectList 用户有任意权限的项目
* @param projectMap 用户有任意权限的项目Map
* @param orgProjectMemberList 组织下所有的项目人员
*/
private static void rebuildProjectOrUser(List<LayoutDTO> layoutDTOS, List<Project> hasPermissionProjectList, Map<String, Project> projectMap, List<ProjectUserMemberDTO> orgProjectMemberList) {
for (LayoutDTO layoutDTO : layoutDTOS) {
if (StringUtils.equalsIgnoreCase(layoutDTO.getKey(), DashboardUserLayoutKeys.PROJECT_VIEW.toString()) || StringUtils.equalsIgnoreCase(layoutDTO.getKey(), DashboardUserLayoutKeys.CREATE_BY_ME.toString())) {
List<Project> list = hasPermissionProjectList.stream().filter(t -> layoutDTO.getProjectIds().contains(t.getId())).toList();
layoutDTO.setProjectIds(list.stream().map(Project::getId).toList());
} else if (StringUtils.equalsIgnoreCase(layoutDTO.getKey(), DashboardUserLayoutKeys.PROJECT_MEMBER_VIEW.toString())) {
List<ProjectUserMemberDTO> list = orgProjectMemberList.stream().filter(t -> layoutDTO.getHandleUsers().contains(t.getId())).toList();
layoutDTO.setHandleUsers(list.stream().map(ProjectUserMemberDTO::getId).toList());
} else {
if (CollectionUtils.isNotEmpty(layoutDTO.getProjectIds()) && projectMap.get(layoutDTO.getProjectIds().getFirst()) == null) {
layoutDTO.setProjectIds(List.of(hasPermissionProjectList.get(0).getId()));
}
}
}
}
public OverViewCountDTO projectMemberViewCount(DashboardFrontPageRequest request) {
String projectId = request.getProjectIds().getFirst();
Project project = projectMapper.selectByPrimaryKey(projectId);
@ -577,13 +605,10 @@ public class DashboardService {
statisticsDTO.setErrorCode(NO_PROJECT_PERMISSION.getCode());
return statisticsDTO;
}
Long toStartTime = request.getToStartTime();
Long toEndTime = request.getToEndTime();
List<FunctionalCaseStatisticDTO> statisticListByProjectId = extFunctionalCaseMapper.getStatisticListByProjectId(projectId, toStartTime, toEndTime);
List<StatusPercentDTO> statusPercentList = new ArrayList<>();
buildStatusPercentList(statisticListByProjectId, statusPercentList);
statisticsDTO.setStatusPercentList(statusPercentList);
List<FunctionalCaseStatisticDTO> allStatisticListByProjectId = extFunctionalCaseMapper.getStatisticListByProjectId(projectId, null, null);
buildStatusPercentList(allStatisticListByProjectId, statusPercentList);
statisticsDTO.setStatusPercentList(statusPercentList);
Map<String, List<FunctionalCaseStatisticDTO>> reviewStatusMap = allStatisticListByProjectId.stream().collect(Collectors.groupingBy(FunctionalCaseStatisticDTO::getReviewStatus));
Map<String, List<NameCountDTO>> statusStatisticsMap = new HashMap<>();
List<NameCountDTO> reviewList = getReviewList(reviewStatusMap, allStatisticListByProjectId);
@ -836,8 +861,6 @@ public class DashboardService {
statisticsDTO.setErrorCode(NO_PROJECT_PERMISSION.getCode());
return statisticsDTO;
}
Long toStartTime = request.getToStartTime();
Long toEndTime = request.getToEndTime();
List<FunctionalCaseStatisticDTO> statisticListByProjectId = extFunctionalCaseMapper.getStatisticListByProjectId(projectId, null, null);
List<FunctionalCaseStatisticDTO> unReviewCaseList = statisticListByProjectId.stream().filter(t -> StringUtils.equalsIgnoreCase(t.getReviewStatus(), FunctionalCaseReviewStatus.UN_REVIEWED.toString())).toList();
int reviewCount = statisticListByProjectId.size() - unReviewCaseList.size();
@ -845,7 +868,7 @@ public class DashboardService {
Map<String, List<NameCountDTO>> statusStatisticsMap = new HashMap<>();
statusStatisticsMap.put("cover", coverList);
statisticsDTO.setStatusStatisticsMap(statusStatisticsMap);
List<StatusPercentDTO> statusPercentList = getStatusPercentList(projectId, toStartTime, toEndTime);
List<StatusPercentDTO> statusPercentList = getStatusPercentList(statisticListByProjectId);
statisticsDTO.setStatusPercentList(statusPercentList);
return statisticsDTO;
}
@ -857,29 +880,28 @@ public class DashboardService {
statisticsDTO.setErrorCode(NO_PROJECT_PERMISSION.getCode());
return statisticsDTO;
}
Long toStartTime = request.getToStartTime();
Long toEndTime = request.getToEndTime();
List<ApiDefinition> createApiList = extApiDefinitionMapper.getCreateApiList(projectId, toStartTime, toEndTime);
Map<String, List<ApiDefinition>> protocolMap = createApiList.stream().collect(Collectors.groupingBy(ApiDefinition::getProtocol));
List<ApiDefinition> createAllApiList = extApiDefinitionMapper.getCreateApiList(projectId, null, null);
Map<String, List<ApiDefinition>> protocolMap = createAllApiList.stream().collect(Collectors.groupingBy(ApiDefinition::getProtocol));
List<StatusPercentDTO> statusPercentList = new ArrayList<>();
List<ProtocolDTO> protocols = apiTestService.getProtocols(request.getOrganizationId());
int totalCount = CollectionUtils.isEmpty(createAllApiList) ? 0 : createAllApiList.size();
for (ProtocolDTO protocol : protocols) {
String protocolName = protocol.getProtocol();
StatusPercentDTO statusPercentDTO = new StatusPercentDTO();
statusPercentDTO.setStatus(protocolName);
List<ApiDefinition> apiDefinitionList = protocolMap.get(protocolName);
if (CollectionUtils.isEmpty(apiDefinitionList)) {
int size = CollectionUtils.isEmpty(apiDefinitionList) ? 0 : apiDefinitionList.size();
if (totalCount == 0) {
statusPercentDTO.setCount(0);
statusPercentDTO.setPercentValue("0%");
} else {
int size = apiDefinitionList.size();
statusPercentDTO.setCount(size);
BigDecimal divide = BigDecimal.valueOf(size).divide(BigDecimal.valueOf(createApiList.size()), 2, RoundingMode.HALF_UP);
BigDecimal divide = BigDecimal.valueOf(size).divide(BigDecimal.valueOf(totalCount), 2, RoundingMode.HALF_UP);
statusPercentDTO.setPercentValue(divide.multiply(BigDecimal.valueOf(100)) + "%");
}
statusPercentList.add(statusPercentDTO);
}
List<ApiDefinition> createAllApiList = extApiDefinitionMapper.getCreateApiList(projectId, null, null);
Map<String, List<ApiDefinition>> statusMap = createAllApiList.stream().collect(Collectors.groupingBy(ApiDefinition::getStatus));
List<ApiDefinition> doneList = statusMap.get(ApiDefinitionStatus.DONE.toString());
List<ApiDefinition> processList = statusMap.get(ApiDefinitionStatus.PROCESSING.toString());
@ -890,12 +912,14 @@ public class DashboardService {
doneDTO.setName(Translator.get("api_definition.status.completed"));
NameCountDTO completionRate = new NameCountDTO();
completionRate.setName(Translator.get("api_definition.completionRate"));
if (CollectionUtils.isEmpty(doneList)) {
int doneSize = CollectionUtils.isEmpty(doneList) ? 0 : doneList.size();
if (totalCount == 0) {
completionRate.setCount(0);
doneDTO.setCount(0);
} else {
doneDTO.setCount(doneList.size());
BigDecimal divide = BigDecimal.valueOf(doneList.size()).divide(BigDecimal.valueOf(createAllApiList.size()), 2, RoundingMode.HALF_UP);
doneDTO.setCount(doneSize);
BigDecimal divide = BigDecimal.valueOf(doneSize).divide(BigDecimal.valueOf(totalCount), 2, RoundingMode.HALF_UP);
completionRate.setCount(getTurnCount(divide));
}
NameCountDTO processDTO = getNameCountDTO(CollectionUtils.isEmpty(processList) ? 0 : processList.size(), Translator.get("api_definition.status.ongoing"));
@ -922,23 +946,19 @@ public class DashboardService {
}
@NotNull
private List<StatusPercentDTO> getStatusPercentList(String projectId, Long toStartTime, Long toEndTime) {
private List<StatusPercentDTO> getStatusPercentList(List<FunctionalCaseStatisticDTO> statisticListByProjectId) {
List<StatusPercentDTO> statusPercentList = new ArrayList<>();
Map<String, String> statusNameMap = buildStatusNameMap();
List<ProjectUserStatusCountDTO> projectUserStatusCountDTOS = extCaseReviewMapper.statusReviewCount(projectId, toStartTime, toEndTime);
Map<String, Integer> statusCountMap = projectUserStatusCountDTOS.stream().collect(Collectors.toMap(ProjectUserStatusCountDTO::getStatus, ProjectUserStatusCountDTO::getCount));
int totalCount = CollectionUtils.isEmpty(statisticListByProjectId) ? 0 : statisticListByProjectId.size();
Map<String, List<FunctionalCaseStatisticDTO>> reviewStatusMap = statisticListByProjectId.stream().collect(Collectors.groupingBy(FunctionalCaseStatisticDTO::getReviewStatus));
statusNameMap.forEach((k, v) -> {
StatusPercentDTO statusPercentDTO = new StatusPercentDTO();
Integer count = statusCountMap.get(k);
List<FunctionalCaseStatisticDTO> functionalCaseStatisticDTOS = reviewStatusMap.get(k);
int count = CollectionUtils.isEmpty(functionalCaseStatisticDTOS) ? 0 : functionalCaseStatisticDTOS.size();
statusPercentDTO.setStatus(v);
if (count != null) {
statusPercentDTO.setCount(count);
} else {
count = 0;
statusPercentDTO.setCount(0);
}
if (CollectionUtils.isNotEmpty(projectUserStatusCountDTOS)) {
BigDecimal divide = BigDecimal.valueOf(count).divide(BigDecimal.valueOf(projectUserStatusCountDTOS.size()), 2, RoundingMode.HALF_UP);
if (totalCount > 0) {
BigDecimal divide = BigDecimal.valueOf(count).divide(BigDecimal.valueOf(totalCount), 2, RoundingMode.HALF_UP);
statusPercentDTO.setPercentValue(divide.multiply(BigDecimal.valueOf(100)) + "%");
} else {
statusPercentDTO.setPercentValue("0%");
@ -971,9 +991,11 @@ public class DashboardService {
private static Map<String, String> buildStatusNameMap() {
Map<String, String> statusNameMap = new HashMap<>();
statusNameMap.put(CaseReviewStatus.PREPARED.toString(), Translator.get("case_review.prepared"));
statusNameMap.put(CaseReviewStatus.UNDERWAY.toString(), Translator.get("case_review.underway"));
statusNameMap.put(CaseReviewStatus.COMPLETED.toString(), Translator.get("case_review.completed"));
statusNameMap.put(FunctionalCaseReviewStatus.UN_REVIEWED.toString(), Translator.get("case.review.status.un_reviewed"));
statusNameMap.put(FunctionalCaseReviewStatus.UNDER_REVIEWED.toString(), Translator.get("case.review.status.under_reviewed"));
statusNameMap.put(FunctionalCaseReviewStatus.PASS.toString(), Translator.get("case.review.status.pass"));
statusNameMap.put(FunctionalCaseReviewStatus.UN_PASS.toString(), Translator.get("case.review.status.un_pass"));
statusNameMap.put(FunctionalCaseReviewStatus.RE_REVIEWED.toString(), Translator.get("case.review.status.re_reviewed"));
return statusNameMap;
}
@ -1068,10 +1090,8 @@ public class DashboardService {
statisticsDTO.setErrorCode(NO_PROJECT_PERMISSION.getCode());
return statisticsDTO;
}
Long toStartTime = request.getToStartTime();
Long toEndTime = request.getToEndTime();
Map<String, List<NameCountDTO>> statusStatisticsMap = new HashMap<>();
long unDeleteCaseExecCount = extExecTaskItemMapper.getUnDeleteCaseExecCount(projectId, toStartTime, toEndTime, List.of("PLAN_RUN_API_CASE", "API_CASE"));
long unDeleteCaseExecCount = extExecTaskItemMapper.getUnDeleteCaseExecCount(projectId, null, null, List.of("PLAN_RUN_API_CASE", "API_CASE"));
List<ApiTestCase> simpleAllApiCaseList = extApiTestCaseMapper.getSimpleApiCaseList(projectId, null, null);
int simpleAllApiCaseSize = 0;
@ -1086,9 +1106,7 @@ public class DashboardService {
List<ApiTestCase> errorList = simpleAllApiCaseList.stream().filter(t -> StringUtils.equalsIgnoreCase(t.getLastReportStatus(), ResultStatus.ERROR.name())).toList();
int errorSize = CollectionUtils.isNotEmpty(errorList) ? errorList.size() : 0;
List<ApiTestCase> simpleApiCaseList = extApiTestCaseMapper.getSimpleApiCaseList(projectId, toStartTime, toEndTime);
List<ApiTestCase> fakeList = simpleApiCaseList.stream().filter(t -> StringUtils.equalsIgnoreCase(t.getLastReportStatus(), ResultStatus.FAKE_ERROR.name())).toList();
int simpleApiCaseSize = CollectionUtils.isNotEmpty(simpleApiCaseList) ? simpleApiCaseList.size() : 0;
List<ApiTestCase> fakeList = simpleAllApiCaseList.stream().filter(t -> StringUtils.equalsIgnoreCase(t.getLastReportStatus(), ResultStatus.FAKE_ERROR.name())).toList();
int fakeSize = CollectionUtils.isNotEmpty(fakeList) ? fakeList.size() : 0;
List<NameCountDTO> execDTOS = getExecDTOS((int) unDeleteCaseExecCount);
@ -1097,7 +1115,7 @@ public class DashboardService {
statusStatisticsMap.put("execRate", execRateDTOS);
List<NameCountDTO> passRateDTOS = getPassRateDTOS(successSize, errorSize, simpleAllApiCaseSize, Translator.get("api_management.apiCasePassRate"));
statusStatisticsMap.put("passRate", passRateDTOS);
List<NameCountDTO> apiCaseDTOS = getApiCaseDTOS(fakeSize, simpleApiCaseSize, Translator.get("api_management.apiCaseCount"));
List<NameCountDTO> apiCaseDTOS = getApiCaseDTOS(fakeSize, simpleAllApiCaseSize, Translator.get("api_management.apiCaseCount"));
statusStatisticsMap.put("apiCaseCount", apiCaseDTOS);
statisticsDTO.setStatusStatisticsMap(statusStatisticsMap);
return statisticsDTO;
@ -1169,10 +1187,9 @@ public class DashboardService {
statisticsDTO.setErrorCode(NO_PROJECT_PERMISSION.getCode());
return statisticsDTO;
}
Long toStartTime = request.getToStartTime();
Long toEndTime = request.getToEndTime();
Map<String, List<NameCountDTO>> statusStatisticsMap = new HashMap<>();
long unDeleteCaseExecCount = extExecTaskItemMapper.getUnDeleteScenarioExecCount(projectId, toStartTime, toEndTime, List.of("PLAN_RUN_API_SCENARIO", "API_SCENARIO"));
long unDeleteCaseExecCount = extExecTaskItemMapper.getUnDeleteScenarioExecCount(projectId, null, null, List.of("PLAN_RUN_API_SCENARIO", "API_SCENARIO"));
List<ApiScenario> simpleAllApiScenarioList = extApiScenarioMapper.getSimpleApiScenarioList(projectId, null, null);
int simpleAllApiScenarioSize = 0;
@ -1187,9 +1204,7 @@ public class DashboardService {
List<ApiScenario> errorList = simpleAllApiScenarioList.stream().filter(t -> StringUtils.equalsIgnoreCase(t.getLastReportStatus(), ResultStatus.ERROR.name())).toList();
int errorSize = CollectionUtils.isNotEmpty(errorList) ? errorList.size() : 0;
List<ApiScenario> simpleApiScenarioList = extApiScenarioMapper.getSimpleApiScenarioList(projectId, toStartTime, toEndTime);
List<ApiScenario> fakeList = simpleApiScenarioList.stream().filter(t -> StringUtils.equalsIgnoreCase(t.getLastReportStatus(), ResultStatus.FAKE_ERROR.name())).toList();
int simpleApiCaseSize = CollectionUtils.isNotEmpty(simpleApiScenarioList) ? simpleApiScenarioList.size() : 0;
List<ApiScenario> fakeList = simpleAllApiScenarioList.stream().filter(t -> StringUtils.equalsIgnoreCase(t.getLastReportStatus(), ResultStatus.FAKE_ERROR.name())).toList();
int fakeSize = CollectionUtils.isNotEmpty(fakeList) ? fakeList.size() : 0;
List<NameCountDTO> execDTOS = getExecDTOS((int) unDeleteCaseExecCount);
@ -1198,7 +1213,7 @@ public class DashboardService {
statusStatisticsMap.put("execRate", execRateDTOS);
List<NameCountDTO> passRateDTOS = getPassRateDTOS(successSize, errorSize, simpleAllApiScenarioSize, Translator.get("api_management.scenarioPassRate"));
statusStatisticsMap.put("passRate", passRateDTOS);
List<NameCountDTO> apiCaseDTOS = getApiCaseDTOS(fakeSize, simpleApiCaseSize, Translator.get("api_management.apiScenarioCount")) ;
List<NameCountDTO> apiCaseDTOS = getApiCaseDTOS(fakeSize, simpleAllApiScenarioSize, Translator.get("api_management.apiScenarioCount"));
statusStatisticsMap.put("apiScenarioCount", apiCaseDTOS);
statisticsDTO.setStatusStatisticsMap(statusStatisticsMap);
return statisticsDTO;
@ -1211,12 +1226,27 @@ public class DashboardService {
statisticsDTO.setErrorCode(NO_PROJECT_PERMISSION.getCode());
return statisticsDTO;
}
Long toStartTime = request.getToStartTime();
Long toEndTime = request.getToEndTime();
String handleUser = hasHandleUser ? userId : null;
String createUser = hasCreateUser ? userId : null;
Set<String> platforms = getPlatforms(projectId);
List<Bug> allSimpleList = extBugMapper.getSimpleList(projectId, null, null, handleUser, createUser, platforms);
List<String> localLastStepStatus = getBugEndStatus(projectId);
List<Bug> statusList = allSimpleList.stream().filter(t -> !localLastStepStatus.contains(t.getStatus())).toList();
int statusSize = CollectionUtils.isEmpty(statusList) ? 0 : statusList.size();
int totalSize = CollectionUtils.isEmpty(allSimpleList) ? 0 : allSimpleList.size();
List<NameCountDTO> nameCountDTOS = buildBugRetentionRateList(totalSize, statusSize);
Map<String, List<NameCountDTO>> statusStatisticsMap = new HashMap<>();
statusStatisticsMap.put("retentionRate", nameCountDTOS);
List<SelectOption> headerStatusOption = bugStatusService.getHeaderStatusOption(projectId);
Map<String, List<Bug>> bugMap = allSimpleList.stream().collect(Collectors.groupingBy(Bug::getStatus));
List<StatusPercentDTO> bugPercentList = bulidBugPercentList(headerStatusOption, bugMap, totalSize);
statisticsDTO.setStatusStatisticsMap(statusStatisticsMap);
statisticsDTO.setStatusPercentList(bugPercentList);
return statisticsDTO;
}
@NotNull
private List<String> getBugEndStatus(String projectId) {
List<String> localLastStepStatus = bugCommonService.getLocalLastStepStatus(projectId);
List<String> platformLastStepStatus = new ArrayList<>();
try {
@ -1225,24 +1255,10 @@ public class DashboardService {
throw new RuntimeException(e);
}
localLastStepStatus.addAll(platformLastStepStatus);
List<Bug> statusList = allSimpleList.stream().filter(t -> !localLastStepStatus.contains(t.getStatus())).toList();
int statusSize = CollectionUtils.isEmpty(statusList) ? 0 : statusList.size();
int totalSize = CollectionUtils.isEmpty(allSimpleList) ? 0 : allSimpleList.size();
List<NameCountDTO> nameCountDTOS = buildBugRetentionRateList(totalSize, statusSize);
Map<String, List<NameCountDTO>> statusStatisticsMap = new HashMap<>();
statusStatisticsMap.put("retentionRate",nameCountDTOS);
List<SelectOption> headerStatusOption = bugStatusService.getHeaderStatusOption(projectId);
List<Bug> simpleList = extBugMapper.getSimpleList(projectId, toStartTime, toEndTime,handleUser, createUser, platforms);
Map<String, List<Bug>> bugMap = simpleList.stream().collect(Collectors.groupingBy(Bug::getStatus));
List<StatusPercentDTO> bugPercentList = bulidBugPercentList(headerStatusOption, bugMap, simpleList);
statisticsDTO.setStatusStatisticsMap(statusStatisticsMap);
statisticsDTO.setStatusPercentList(bugPercentList);
return statisticsDTO;
return localLastStepStatus;
}
private static List<NameCountDTO> buildBugRetentionRateList(int totalSize, int statusSize) {
List<NameCountDTO> retentionRates = new ArrayList<>();
NameCountDTO retentionRate = new NameCountDTO();
@ -1261,9 +1277,8 @@ public class DashboardService {
return retentionRates;
}
private static List<StatusPercentDTO> bulidBugPercentList(List<SelectOption> headerStatusOption, Map<String, List<Bug>> bugMap, List<Bug> simpleList) {
private static List<StatusPercentDTO> bulidBugPercentList(List<SelectOption> headerStatusOption, Map<String, List<Bug>> bugMap, int simpleSize) {
List<StatusPercentDTO> statusPercentList = new ArrayList<>();
int simpleSize = CollectionUtils.isEmpty(simpleList) ? 0 : simpleList.size();
for (SelectOption selectOption : headerStatusOption) {
StatusPercentDTO statusPercentDTO = new StatusPercentDTO();
statusPercentDTO.setStatus(selectOption.getText());
@ -1293,6 +1308,45 @@ public class DashboardService {
public StatisticsDTO projectBugCountHandleByMe(DashboardFrontPageRequest request, String userId) {
return baseProjectBugCount(request, userId, true, false);
}
public StatisticsDTO projectPlanLegacyBug(DashboardFrontPageRequest request, String userId) {
String projectId = request.getProjectIds().getFirst();
StatisticsDTO statisticsDTO = new StatisticsDTO();
if (Boolean.FALSE.equals(permissionCheckService.checkModule(projectId, TEST_PLAN_MODULE, userId, PermissionConstants.TEST_PLAN_READ))) {
statisticsDTO.setErrorCode(NO_PROJECT_PERMISSION.getCode());
return statisticsDTO;
}
Set<String> platforms = getPlatforms(projectId);
List<SelectOption> planBugList = extTestPlanMapper.getPlanBugList(projectId, TestPlanConstants.TEST_PLAN_TYPE_PLAN, new ArrayList<>(platforms), null);
List<String> localLastStepStatus = getBugEndStatus(projectId);
List<SelectOption> legacyBugList = planBugList.stream().filter(t -> !localLastStepStatus.contains(t.getText())).toList();
List<SelectOption> headerStatusOption = bugStatusService.getHeaderStatusOption(projectId);
int statusSize = CollectionUtils.isEmpty(legacyBugList) ? 0 : legacyBugList.size();
int totalSize = CollectionUtils.isEmpty(planBugList) ? 0 : planBugList.size();
List<NameCountDTO> nameCountDTOS = buildBugRetentionRateList(totalSize, statusSize);
Map<String, List<NameCountDTO>> statusStatisticsMap = new HashMap<>();
statusStatisticsMap.put("retentionRate", nameCountDTOS);
Map<String, List<SelectOption>> bugMap = legacyBugList.stream().collect(Collectors.groupingBy(SelectOption::getValue));
List<StatusPercentDTO> statusPercentList = new ArrayList<>();
for (SelectOption selectOption : headerStatusOption) {
StatusPercentDTO statusPercentDTO = new StatusPercentDTO();
statusPercentDTO.setStatus(selectOption.getText());
List<SelectOption> bugs = bugMap.get(selectOption.getValue());
int bugSize = CollectionUtils.isEmpty(bugs) ? 0 : bugs.size();
if (statusSize == 0) {
statusPercentDTO.setPercentValue("0%");
statusPercentDTO.setCount(0);
} else {
BigDecimal divide = BigDecimal.valueOf(bugSize).divide(BigDecimal.valueOf(statusSize), 2, RoundingMode.HALF_UP);
statusPercentDTO.setPercentValue(divide.multiply(BigDecimal.valueOf(100)) + "%");
statusPercentDTO.setCount(bugSize);
}
statusPercentList.add(statusPercentDTO);
}
statisticsDTO.setStatusStatisticsMap(statusStatisticsMap);
statisticsDTO.setStatusPercentList(statusPercentList);
return statisticsDTO;
}
}

View File

@ -93,6 +93,7 @@ public class DashboardFrontPageControllerTests extends BaseTest {
private static final String BUG_COUNT = "/dashboard/bug_count";
private static final String CREATE_BUG_BY_ME = "/dashboard/create_bug_by_me";
private static final String HANDLE_BUG_BY_ME = "/dashboard/handle_bug_by_me";
private static final String PLAN_LEGACY_BUG = "/dashboard/plan_legacy_bug";
@ -195,7 +196,7 @@ public class DashboardFrontPageControllerTests extends BaseTest {
String contentAsString = mvcResultGrt.getResponse().getContentAsString(StandardCharsets.UTF_8);
ResultHolder resultHolder = JSON.parseObject(contentAsString, ResultHolder.class);
List<LayoutDTO> layoutDTOS = JSON.parseArray(JSON.toJSONString(resultHolder.getData()), LayoutDTO.class);
Assertions.assertEquals(3, layoutDTOS.size());
Assertions.assertEquals(0, layoutDTOS.size());
ProjectExample projectExample = new ProjectExample();
projectExample.createCriteria().andOrganizationIdEqualTo(DEFAULT_ORGANIZATION_ID);
@ -304,8 +305,7 @@ public class DashboardFrontPageControllerTests extends BaseTest {
dashboardFrontPageRequest.setCurrent(1);
dashboardFrontPageRequest.setPageSize(5);
dashboardFrontPageRequest.setProjectIds(List.of(DEFAULT_PROJECT_ID));
List<SelectOption> headerStatusOption = bugStatusService.getHeaderStatusOption(DEFAULT_PROJECT_ID);
buildBug(headerStatusOption);
MvcResult mvcResult = this.requestPostWithOkAndReturn(CASE_COUNT, dashboardFrontPageRequest);
String contentAsString = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
ResultHolder resultHolder = JSON.parseObject(contentAsString, ResultHolder.class);
@ -352,6 +352,11 @@ public class DashboardFrontPageControllerTests extends BaseTest {
ResultHolder handleBugResultHolder = JSON.parseObject(handleBugContentAsString, ResultHolder.class);
StatisticsDTO handleBugCount = JSON.parseObject(JSON.toJSONString(handleBugResultHolder.getData()), StatisticsDTO.class);
Assertions.assertNotNull(handleBugCount);
MvcResult planBugMvcResult = this.requestPostWithOkAndReturn(PLAN_LEGACY_BUG, dashboardFrontPageRequest);
String planBugContentAsString = planBugMvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
ResultHolder planBugResultHolder = JSON.parseObject(planBugContentAsString, ResultHolder.class);
StatisticsDTO planBugCount = JSON.parseObject(JSON.toJSONString(planBugResultHolder.getData()), StatisticsDTO.class);
Assertions.assertNotNull(planBugCount);
Project project = new Project();
project.setModuleSetting("[]");
@ -406,6 +411,11 @@ public class DashboardFrontPageControllerTests extends BaseTest {
handleBugCount = JSON.parseObject(JSON.toJSONString(handleBugResultHolder.getData()), StatisticsDTO.class);
Assertions.assertNotNull(handleBugCount);
planBugMvcResult = this.requestPostWithOkAndReturn(PLAN_LEGACY_BUG, dashboardFrontPageRequest);
planBugContentAsString = planBugMvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
planBugResultHolder = JSON.parseObject(planBugContentAsString, ResultHolder.class);
planBugCount = JSON.parseObject(JSON.toJSONString(planBugResultHolder.getData()), StatisticsDTO.class);
Assertions.assertNotNull(planBugCount);
project.setModuleSetting("[\"apiTest\",\"testPlan\",\"caseManagement\",\"bugManagement\"]");
project.setId(DEFAULT_PROJECT_ID);
@ -462,6 +472,12 @@ public class DashboardFrontPageControllerTests extends BaseTest {
handleBugCount = JSON.parseObject(JSON.toJSONString(handleBugResultHolder.getData()), StatisticsDTO.class);
Assertions.assertNotNull(handleBugCount);
planBugMvcResult = this.requestPostWithOkAndReturn(PLAN_LEGACY_BUG, dashboardFrontPageRequest);
planBugContentAsString = planBugMvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
planBugResultHolder = JSON.parseObject(planBugContentAsString, ResultHolder.class);
planBugCount = JSON.parseObject(JSON.toJSONString(planBugResultHolder.getData()), StatisticsDTO.class);
Assertions.assertNotNull(planBugCount);
}
@Test

View File

@ -110,6 +110,17 @@ VALUES ('dashboard_scenario_four', 'api_scenario', 'p1', 'test-api-status', 'ER
INSERT INTO api_scenario_step(id, scenario_id, name, sort, enable, resource_id, resource_num, step_type, project_id, parent_id, version_id, ref_type, origin_project_id, config)
VALUE ('dashboard_act_1', 'dashboard_sc_1', 'dd', 1, true, 'dashboard_api_definition_id_1', '1000', 'API', '100001100001', null, 'oasis_ac_version_id', 'REF', '100001100001', null);
INSERT INTO bug_relation_case(id, case_id, bug_id, case_type, test_plan_id, test_plan_case_id, create_user, create_time, update_time)
VALUES ('dashboard_bug-relate-case-default-id', 'bug_relate_case', 'dashboard_bug1', 'FUNCTIONAL', 'dashboard_test-plan-id', null, 'admin', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000),
('dashboard_bug-relate-case-default-id-1', 'bug_relate_case', 'dashboard_bug2', 'FUNCTIONAL', 'dashboard_test-plan-id', 'bug_relate_case', 'admin', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000),
('dashboard_bug-relate-case-default-id-2', 'bug_relate_case-1', 'dashboard_bug3', 'FUNCTIONAL', 'dashboard_test-plan-id', 'bug_relate_case-1', 'admin', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000),
('dashboard_bug-relate-case-default-id-3', null, 'dashboard_bug1', 'FUNCTIONAL', 'dashboard_test-plan-id', 'bug_relate_case-3', 'admin', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000);
INSERT INTO test_plan(id, num, project_id, group_id, module_id, name, status, type, tags, create_time, create_user, update_time, update_user, planned_start_time, planned_end_time, actual_start_time, actual_end_time, description)
VALUE ('dashboard_test-plan-id', 500, '100001100001', 'NONE', 'case_plan_module', 'test_plan_associate_case_name_three', 'NOT_ARCHIVED', 'TEST_PLAN', null, UNIX_TIMESTAMP() * 1000,'admin',
UNIX_TIMESTAMP() * 1000,'admin',UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, null);
INSERT INTO project_application (project_id, type, type_value) VALUES
('100001100001', 'BUG_SYNC_BUG_PLATFORM_CONFIG', '{"jiraKey":"TES","jiraBugTypeId":"10009"}'),
('100001100001', 'BUG_SYNC_PLATFORM_KEY', 'jira'),

View File

@ -134,7 +134,7 @@
</select>
<select id="getUserProjectIdName" resultType="io.metersphere.project.domain.Project">
SELECT DISTINCT p.id, p.name
SELECT DISTINCT p.id, p.name, p.module_setting
FROM user_role u
JOIN user_role_relation urr ON u.id = urr.role_id
JOIN project p ON p.id = urr.source_id

View File

@ -8,6 +8,7 @@ import io.metersphere.plan.dto.request.TestPlanBatchProcessRequest;
import io.metersphere.plan.dto.request.TestPlanExecuteHisPageRequest;
import io.metersphere.plan.dto.request.TestPlanTableRequest;
import io.metersphere.plan.dto.response.TestPlanResponse;
import io.metersphere.plugin.platform.dto.SelectOption;
import io.metersphere.project.dto.*;
import io.metersphere.system.interceptor.BaseConditionFilter;
import org.apache.ibatis.annotations.Param;
@ -83,5 +84,13 @@ public interface ExtTestPlanMapper {
List<TestPlan> getSimpleTestPlanList(@Param("projectId") String projectId, @Param("startTime") Long startTime, @Param("endTime") Long endTime);
/**
* 获取项目下的计划关联缺陷
* @param projectId 项目
* @param type 计划类型
* @param platform 缺陷平台集合
* @param statusList 缺陷状态
* @return List<SelectOption>
*/
List<SelectOption> getPlanBugList(@Param("projectId") String projectId, @Param("type") String type, @Param("platforms") List<String> platform, @Param("statusList") List<String> statusList);
}

View File

@ -852,8 +852,29 @@
AND test_plan.create_time BETWEEN #{startTime} AND #{endTime}
</if>
</select>
<select id="getPlanBugList" resultType="io.metersphere.plugin.platform.dto.SelectOption">
select distinct bug.id as `value`, bug.status as `text`
from test_plan
left join bug_relation_case on test_plan.id = bug_relation_case.test_plan_id
left join bug on bug_relation_case.bug_id = bug.id
where test_plan.status = 'NOT_ARCHIVED'
<if test="type != null and type != ''">
and test_plan.type= #{type}
</if>
and test_plan.project_id = #{projectId}
<if test="statusList != null and statusList.size() > 0">
and bug.status in
<foreach collection="statusList" item="status" separator="," open="(" close=")">
#{status}
</foreach>
</if>
<if test="platforms != null and platforms.size() > 0">
and bug.platform in
<foreach collection="platforms" item="platform" separator="," open="(" close=")">
#{platform}
</foreach>
</if>
</select>
<sql id="queryMyFollowGroupByTableRequest">