feat(工作台): 用例统计完成
Some checks are pending
MeterSphere 覆盖率统计 / 覆盖率统计 (push) Waiting to run
MeterSphere 前端代码校验 / 前端代码校验 (push) Waiting to run
SonarCloud / Build and analyze (push) Waiting to run
Mirror GitHub Auto Queried Repos to Gitee / Sync-GitHub-to-Gitee (push) Waiting to run

This commit is contained in:
guoyuqi 2024-11-12 16:11:29 +08:00 committed by Craftsman
parent ab848b47a7
commit 344a933278
5 changed files with 221 additions and 22 deletions

View File

@ -7,6 +7,7 @@ import io.metersphere.functional.request.CaseReviewPageRequest;
import io.metersphere.project.dto.ModuleCountDTO;
import io.metersphere.project.dto.ProjectCountDTO;
import io.metersphere.project.dto.ProjectUserCreateCount;
import io.metersphere.project.dto.ProjectUserStatusCountDTO;
import io.metersphere.system.interceptor.BaseConditionFilter;
import org.apache.ibatis.annotations.Param;
@ -47,5 +48,13 @@ public interface ExtCaseReviewMapper {
List<ProjectUserCreateCount> userCreateReviewCount(@Param("projectId") String projectId, @Param("startTime") long startTime, @Param("endTime") long endTime, @Param("userIds") Set<String> userIds);
/**
* 获取各种状态总数量的评审
* @param projectId 项目ID
* @param startTime 时间过滤条件
* @param endTime 时间过滤条件
* @return ProjectUserStatusCountDTO userId 在这里不返回
*/
List<ProjectUserStatusCountDTO> statusReviewCount(@Param("projectId") String projectId, @Param("startTime") long startTime, @Param("endTime") long endTime);
}

View File

@ -211,6 +211,9 @@
<property name="condition" value="condition"/>
</include>
</if>
<include refid="io.metersphere.system.mapper.BaseMapper.queryType">
<property name="searchMode" value="${combineSearch}.searchMode"/>
</include>
</foreach>
<foreach collection="${combineSearch}.systemFieldConditions" item="condition">
<include refid="io.metersphere.system.mapper.BaseMapper.commonSystemFieldConditions">
@ -268,6 +271,9 @@
<property name="column" value="case_review.description"/>
</include>
</if>
<include refid="io.metersphere.system.mapper.BaseMapper.queryType">
<property name="searchMode" value="${combineSearch}.searchMode"/>
</include>
</foreach>
</if>
</trim>
@ -373,5 +379,13 @@
</if>
group by case_review.create_user;
</select>
<select id="statusReviewCount" resultType="io.metersphere.project.dto.ProjectUserStatusCountDTO">
SELECT case_review.status as status, count(case_review.id) as count
FROM case_review
WHERE case_review.project_id = #{projectId}
AND case_review.create_time BETWEEN #{startTime} AND #{endTime}
group by case_review.status;
</select>
</mapper>

View File

@ -1,19 +1,33 @@
package io.metersphere.dashboard.controller;
import com.alibaba.excel.util.StringUtils;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.metersphere.dashboard.dto.LayoutDTO;
import io.metersphere.dashboard.request.DashboardFrontPageRequest;
import io.metersphere.dashboard.response.OverViewCountDTO;
import io.metersphere.dashboard.response.StatisticsDTO;
import io.metersphere.dashboard.service.DashboardService;
import io.metersphere.functional.constants.CaseReviewStatus;
import io.metersphere.functional.dto.CaseReviewDTO;
import io.metersphere.functional.request.CaseReviewPageRequest;
import io.metersphere.functional.service.CaseReviewService;
import io.metersphere.sdk.dto.CombineCondition;
import io.metersphere.sdk.dto.CombineSearch;
import io.metersphere.system.security.CheckOwner;
import io.metersphere.system.utils.PageUtils;
import io.metersphere.system.utils.Pager;
import io.metersphere.system.utils.SessionUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import org.jetbrains.annotations.NotNull;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@Tag(name = "工作台-首页")
@RestController
@ -22,6 +36,8 @@ public class DashboardController {
@Resource
private DashboardService dashboardService;
@Resource
private CaseReviewService caseReviewService;
@PostMapping("/layout/edit/{organizationId}")
@Operation(summary = "编辑用户布局")
@ -65,7 +81,6 @@ public class DashboardController {
return dashboardService.projectBugHandleUser(request);
}
@PostMapping("/case_count")
@Operation(summary = "用例数")
@CheckOwner(resourceId = "#request.getOrganizationId()", resourceType = "organization")
@ -80,4 +95,60 @@ public class DashboardController {
return dashboardService.projectAssociateCaseCount(request);
}
@PostMapping("/review_case_count")
@Operation(summary = "用例评审数")
@CheckOwner(resourceId = "#request.getOrganizationId()", resourceType = "organization")
public StatisticsDTO projectReviewCaseCount(@Validated @RequestBody DashboardFrontPageRequest request) {
return dashboardService.projectReviewCaseCount(request);
}
@PostMapping("/reviewing_by_me")
@Operation(summary = "待我评审")
@CheckOwner(resourceId = "#request.getOrganizationId()", resourceType = "organization")
public Pager<List<CaseReviewDTO>> getFunctionalCasePage(@Validated @RequestBody DashboardFrontPageRequest request) {
CaseReviewPageRequest reviewRequest = getCaseReviewPageRequest(request);
Page<Object> page = PageHelper.startPage(reviewRequest.getCurrent(), reviewRequest.getPageSize(),
StringUtils.isNotBlank(reviewRequest.getSortString()) ? reviewRequest.getSortString() : "pos desc");
return PageUtils.setPageInfo(page, caseReviewService.getCaseReviewPage(reviewRequest));
}
@NotNull
private static CaseReviewPageRequest getCaseReviewPageRequest(DashboardFrontPageRequest request) {
String projectId = request.getProjectIds().getFirst();
CaseReviewPageRequest reviewRequest = new CaseReviewPageRequest();
reviewRequest.setProjectId(projectId);
reviewRequest.setPageSize(request.getPageSize());
reviewRequest.setCurrent(request.getCurrent());
reviewRequest.setSort(request.getSort());
CombineSearch combineSearch = getCombineSearch(request);
reviewRequest.setCombineSearch(combineSearch);
return reviewRequest;
}
@NotNull
private static CombineSearch getCombineSearch(DashboardFrontPageRequest request) {
CombineSearch combineSearch = new CombineSearch();
combineSearch.setSearchMode(CombineSearch.SearchMode.AND.name());
List<CombineCondition> conditions = new ArrayList<>();
CombineCondition userCombineCondition = getCombineCondition(List.of(Objects.requireNonNull(SessionUtils.getUserId())), "reviewers",CombineCondition.CombineConditionOperator.IN.toString());
conditions.add(userCombineCondition);
CombineCondition statusCombineCondition = getCombineCondition(List.of(CaseReviewStatus.PREPARED.toString(), CaseReviewStatus.UNDERWAY.toString()), "status",CombineCondition.CombineConditionOperator.IN.toString());
conditions.add(statusCombineCondition);
CombineCondition createTimeCombineCondition = getCombineCondition(List.of(request.getToStartTime(), request.getToEndTime()), "createTime",CombineCondition.CombineConditionOperator.BETWEEN.toString());
conditions.add(createTimeCombineCondition);
combineSearch.setConditions(conditions);
return combineSearch;
}
@NotNull
private static CombineCondition getCombineCondition(List<Object> value, String reviewers, String operator) {
CombineCondition userCombineCondition = new CombineCondition();
userCombineCondition.setValue(value);
userCombineCondition.setName(reviewers);
userCombineCondition.setOperator(operator);
userCombineCondition.setCustomField(false);
userCombineCondition.setCustomFieldType("");
return userCombineCondition;
}
}

View File

@ -15,6 +15,7 @@ import io.metersphere.dashboard.dto.StatusPercentDTO;
import io.metersphere.dashboard.request.DashboardFrontPageRequest;
import io.metersphere.dashboard.response.OverViewCountDTO;
import io.metersphere.dashboard.response.StatisticsDTO;
import io.metersphere.functional.constants.CaseReviewStatus;
import io.metersphere.functional.constants.FunctionalCaseReviewStatus;
import io.metersphere.functional.dto.FunctionalCaseStatisticDTO;
import io.metersphere.functional.mapper.ExtCaseReviewMapper;
@ -641,22 +642,7 @@ public class DashboardService {
Long toEndTime = request.getToEndTime();
long caseTestCount = extFunctionalCaseMapper.caseTestCount(projectId, toStartTime, toEndTime);
long simpleCaseCount = extFunctionalCaseMapper.simpleCaseCount(projectId, toStartTime, toEndTime);
List<NameCountDTO> coverList = new ArrayList<>();
NameCountDTO coverRate = new NameCountDTO();
if (simpleCaseCount > 0L) {
BigDecimal divide = BigDecimal.valueOf(caseTestCount).divide(BigDecimal.valueOf(simpleCaseCount), 0, RoundingMode.HALF_UP);
coverRate.setCount(Integer.valueOf(String.valueOf(divide.multiply(BigDecimal.valueOf(100)))));
}
coverRate.setName(Translator.get("functional_case.coverRate"));
coverList.add(coverRate);
NameCountDTO hasCover = new NameCountDTO();
hasCover.setCount((int) caseTestCount);
hasCover.setName(Translator.get("functional_case.hasCover"));
coverList.add(hasCover);
NameCountDTO unCover = new NameCountDTO();
unCover.setCount((int) (simpleCaseCount - caseTestCount));
unCover.setName(Translator.get("functional_case.unCover"));
coverList.add(unCover);
List<NameCountDTO> coverList = getCoverList((int) simpleCaseCount, (int) caseTestCount, (int) (simpleCaseCount - caseTestCount));
Map<String, List<NameCountDTO>> statusStatisticsMap = new HashMap<>();
statusStatisticsMap.put("cover", coverList);
statisticsDTO.setStatusStatisticsMap(statusStatisticsMap);
@ -665,7 +651,8 @@ public class DashboardService {
public OverViewCountDTO projectBugHandleUser(DashboardFrontPageRequest request) {
String projectId = request.getProjectIds().getFirst();
if (Boolean.FALSE.equals(checkModule(projectId, BUG_MODULE))) return new OverViewCountDTO(null, new ArrayList<>(), new ArrayList<>());
if (Boolean.FALSE.equals(checkModule(projectId, BUG_MODULE)))
return new OverViewCountDTO(null, new ArrayList<>(), new ArrayList<>());
Long toStartTime = request.getToStartTime();
Long toEndTime = request.getToEndTime();
List<SelectOption> headerHandlerOption = getHandlerOption(request.getHandleUsers(), projectId);
@ -746,10 +733,10 @@ public class DashboardService {
statusCountArrayMap.put(k, countArray);
} else {
for (int i = 0; i < handleUserIds.size(); i++) {
if (userIds.size()>i) {
if (!StringUtils.equalsIgnoreCase(userIds.get(i),handleUserIds.get(i))) {
userIds.add(i,handleUserIds.get(i));
handleUserCounts.add(i,0);
if (userIds.size() > i) {
if (!StringUtils.equalsIgnoreCase(userIds.get(i), handleUserIds.get(i))) {
userIds.add(i, handleUserIds.get(i));
handleUserCounts.add(i, 0);
}
} else {
handleUserCounts.add(0);
@ -793,6 +780,80 @@ public class DashboardService {
}
return platforms;
}
public StatisticsDTO projectReviewCaseCount(DashboardFrontPageRequest request) {
String projectId = request.getProjectIds().getFirst();
StatisticsDTO statisticsDTO = new StatisticsDTO();
if (Boolean.FALSE.equals(checkModule(projectId, FUNCTIONAL_CASE_MODULE))) return statisticsDTO;
Long toStartTime = request.getToStartTime();
Long toEndTime = request.getToEndTime();
List<FunctionalCaseStatisticDTO> statisticListByProjectId = extFunctionalCaseMapper.getStatisticListByProjectId(projectId, toStartTime, toEndTime);
List<FunctionalCaseStatisticDTO> unReviewCaseList = statisticListByProjectId.stream().filter(t -> StringUtils.equalsIgnoreCase(t.getReviewStatus(), FunctionalCaseReviewStatus.UN_REVIEWED.toString())).toList();
int reviewCount = statisticListByProjectId.size() - unReviewCaseList.size();
List<NameCountDTO> coverList = getCoverList(statisticListByProjectId.size(), reviewCount, unReviewCaseList.size());
Map<String, List<NameCountDTO>> statusStatisticsMap = new HashMap<>();
statusStatisticsMap.put("cover", coverList);
statisticsDTO.setStatusStatisticsMap(statusStatisticsMap);
List<StatusPercentDTO> statusPercentList = getStatusPercentList(projectId, toStartTime, toEndTime);
statisticsDTO.setStatusPercentList(statusPercentList);
return statisticsDTO;
}
@NotNull
private List<StatusPercentDTO> getStatusPercentList(String projectId, Long toStartTime, Long toEndTime) {
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));
statusNameMap.forEach((k, v) -> {
StatusPercentDTO statusPercentDTO = new StatusPercentDTO();
Integer count = statusCountMap.get(k);
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);
statusPercentDTO.setPercentValue(divide.multiply(BigDecimal.valueOf(100)) + "%");
} else {
statusPercentDTO.setPercentValue("0%");
}
statusPercentList.add(statusPercentDTO);
});
return statusPercentList;
}
@NotNull
private static List<NameCountDTO> getCoverList(int totalCount, int coverCount, int unCoverCount) {
List<NameCountDTO> coverList = new ArrayList<>();
NameCountDTO coverRate = new NameCountDTO();
if (totalCount>0) {
BigDecimal divide = BigDecimal.valueOf(coverCount).divide(BigDecimal.valueOf(totalCount), 0, RoundingMode.HALF_UP);
coverRate.setCount(Integer.valueOf(String.valueOf(divide.multiply(BigDecimal.valueOf(100)))));
}
coverRate.setName(Translator.get("functional_case.coverRate"));
coverList.add(coverRate);
NameCountDTO hasCover = new NameCountDTO();
hasCover.setCount(coverCount);
hasCover.setName(Translator.get("functional_case.hasCover"));
coverList.add(hasCover);
NameCountDTO unCover = new NameCountDTO();
unCover.setCount(unCoverCount);
unCover.setName(Translator.get("functional_case.unCover"));
coverList.add(unCover);
return coverList;
}
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"));
return statusNameMap;
}
}

View File

@ -11,6 +11,7 @@ import io.metersphere.dashboard.request.DashboardFrontPageRequest;
import io.metersphere.dashboard.response.OverViewCountDTO;
import io.metersphere.dashboard.response.StatisticsDTO;
import io.metersphere.dashboard.service.DashboardService;
import io.metersphere.functional.dto.CaseReviewDTO;
import io.metersphere.plugin.platform.dto.SelectOption;
import io.metersphere.project.domain.Project;
import io.metersphere.project.domain.ProjectExample;
@ -21,6 +22,7 @@ import io.metersphere.project.service.ProjectMemberService;
import io.metersphere.sdk.util.JSON;
import io.metersphere.system.base.BaseTest;
import io.metersphere.system.controller.handler.ResultHolder;
import io.metersphere.system.utils.Pager;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.*;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
@ -61,8 +63,10 @@ public class DashboardFrontPageControllerTests extends BaseTest {
private static final String PROJECT_MEMBER_VIEW = "/dashboard/project_member_view";
private static final String CASE_COUNT = "/dashboard/case_count";
private static final String ASSOCIATE_CASE_COUNT = "/dashboard/associate_case_count";
private static final String REVIEW_CASE_COUNT = "/dashboard/review_case_count";
private static final String BUG_HANDLE_USER = "/dashboard/bug_handle_user";
private static final String REVIEWING_BY_ME = "/dashboard/reviewing_by_me";
@Test
@ -263,6 +267,11 @@ public class DashboardFrontPageControllerTests extends BaseTest {
ResultHolder associateResultHolder = JSON.parseObject(associateContent, ResultHolder.class);
StatisticsDTO associateCount = JSON.parseObject(JSON.toJSONString(associateResultHolder.getData()), StatisticsDTO.class);
Assertions.assertNotNull(associateCount);
MvcResult reviewMvcResult = this.requestPostWithOkAndReturn(REVIEW_CASE_COUNT, dashboardFrontPageRequest);
String reviewContent = reviewMvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
ResultHolder reviewResultHolder = JSON.parseObject(reviewContent, ResultHolder.class);
StatisticsDTO reviewCount = JSON.parseObject(JSON.toJSONString(reviewResultHolder.getData()), StatisticsDTO.class);
Assertions.assertNotNull(reviewCount);
Project project = new Project();
project.setModuleSetting("[]");
project.setId(DEFAULT_PROJECT_ID);
@ -277,6 +286,11 @@ public class DashboardFrontPageControllerTests extends BaseTest {
associateResultHolder = JSON.parseObject(associateContent, ResultHolder.class);
associateCount = JSON.parseObject(JSON.toJSONString(associateResultHolder.getData()), StatisticsDTO.class);
Assertions.assertNotNull(associateCount);
reviewMvcResult = this.requestPostWithOkAndReturn(REVIEW_CASE_COUNT, dashboardFrontPageRequest);
reviewContent = reviewMvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
reviewResultHolder = JSON.parseObject(reviewContent, ResultHolder.class);
reviewCount = JSON.parseObject(JSON.toJSONString(reviewResultHolder.getData()), StatisticsDTO.class);
Assertions.assertNotNull(reviewCount);
project.setModuleSetting("[\"apiTest\",\"testPlan\",\"caseManagement\",\"bugManagement\"]");
project.setId(DEFAULT_PROJECT_ID);
projectMapper.updateByPrimaryKeySelective(project);
@ -293,8 +307,38 @@ public class DashboardFrontPageControllerTests extends BaseTest {
associateResultHolder = JSON.parseObject(associateContent, ResultHolder.class);
associateCount = JSON.parseObject(JSON.toJSONString(associateResultHolder.getData()), StatisticsDTO.class);
Assertions.assertNotNull(associateCount);
reviewMvcResult = this.requestPostWithOkAndReturn(REVIEW_CASE_COUNT, dashboardFrontPageRequest);
reviewContent = reviewMvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
reviewResultHolder = JSON.parseObject(reviewContent, ResultHolder.class);
reviewCount = JSON.parseObject(JSON.toJSONString(reviewResultHolder.getData()), StatisticsDTO.class);
Assertions.assertNotNull(reviewCount);
}
@Test
@Order(4)
public void testList() throws Exception {
DashboardFrontPageRequest dashboardFrontPageRequest = new DashboardFrontPageRequest();
dashboardFrontPageRequest.setOrganizationId(DEFAULT_ORGANIZATION_ID);
dashboardFrontPageRequest.setDayNumber(3);
dashboardFrontPageRequest.setCurrent(1);
dashboardFrontPageRequest.setPageSize(5);
dashboardFrontPageRequest.setProjectIds(List.of(DEFAULT_PROJECT_ID));
MvcResult mvcResult = this.requestPostWithOkAndReturn(REVIEWING_BY_ME, dashboardFrontPageRequest);
Pager<List<CaseReviewDTO>> tableData = JSON.parseObject(JSON.toJSONString(
JSON.parseObject(mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8), ResultHolder.class).getData()),
Pager.class);
List<CaseReviewDTO> list = tableData.getList();
Assertions.assertNotNull(list);
dashboardFrontPageRequest.setStartTime(1697971947000L);
dashboardFrontPageRequest.setEndTime(1700650347000L);
mvcResult = this.requestPostWithOkAndReturn(REVIEWING_BY_ME, dashboardFrontPageRequest);
tableData = JSON.parseObject(JSON.toJSONString(
JSON.parseObject(mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8), ResultHolder.class).getData()),
Pager.class);
list = tableData.getList();
Assertions.assertNotNull(list);
}
}