mirror of
https://gitee.com/fit2cloud-feizhiyun/MeterSphere.git
synced 2024-12-02 03:58:33 +08:00
feat(工作台): 增加用例数与关联用例接口
This commit is contained in:
parent
40b9fbdc6a
commit
822bb5b664
@ -1 +1,13 @@
|
||||
# dashboard
|
||||
functional_case.reviewRate=评审率
|
||||
functional_case.hasReview=已评审
|
||||
functional_case.unReview=未评审
|
||||
functional_case.passRate=通过率
|
||||
functional_case.hasPass=已通过
|
||||
functional_case.unPass=未通过
|
||||
functional_case.coverRate=覆盖率
|
||||
functional_case.hasCover=已覆盖
|
||||
functional_case.unCover=未覆盖
|
||||
|
||||
|
||||
|
||||
|
@ -1 +1,10 @@
|
||||
# dashboard
|
||||
functional_case.reviewRate=Review rate
|
||||
functional_case.hasReview=Reviewed
|
||||
functional_case.unReview=Not reviewed
|
||||
functional_case.passRate=Pass rate
|
||||
functional_case.hasPass=Passed
|
||||
functional_case.unPass=Un Pass
|
||||
functional_case.coverRate=Coverage
|
||||
functional_case.hasCover=Covered
|
||||
functional_case.unCover=Not covered
|
||||
|
@ -1 +1,10 @@
|
||||
# dashboard
|
||||
functional_case.reviewRate=评审率
|
||||
functional_case.hasReview=已评审
|
||||
functional_case.unReview=未评审
|
||||
functional_case.passRate=通过率
|
||||
functional_case.hasPass=已通过
|
||||
functional_case.unPass=未通过
|
||||
functional_case.coverRate=覆盖率
|
||||
functional_case.hasCover=已覆盖
|
||||
functional_case.unCover=未覆盖
|
@ -7,6 +7,7 @@ import io.metersphere.bug.dto.response.BugTagEditDTO;
|
||||
import io.metersphere.dto.BugProviderDTO;
|
||||
import io.metersphere.project.dto.ProjectCountDTO;
|
||||
import io.metersphere.project.dto.ProjectUserCreateCount;
|
||||
import io.metersphere.project.dto.ProjectUserStatusCountDTO;
|
||||
import io.metersphere.request.AssociateBugRequest;
|
||||
import io.metersphere.request.BugPageProviderRequest;
|
||||
import io.metersphere.system.interceptor.BaseConditionFilter;
|
||||
@ -116,4 +117,6 @@ public interface ExtBugMapper {
|
||||
List<ProjectCountDTO> projectBugCount(@Param("projectIds") Set<String> projectIds, @Param("startTime") long startTime, @Param("endTime") long endTime, @Param("userId") String userId);
|
||||
List<ProjectUserCreateCount> userCreateBugCount(@Param("projectId") String projectId, @Param("startTime") long startTime, @Param("endTime") long endTime, @Param("userIds") Set<String> userIds);
|
||||
|
||||
List<ProjectUserStatusCountDTO> projectUserBugStatusCount(@Param("projectId") String projectId, @Param("startTime") long startTime, @Param("endTime") long endTime, @Param("userIds") Set<String> userIds, @Param("platforms") Set<String> platforms);
|
||||
|
||||
}
|
||||
|
@ -393,5 +393,26 @@
|
||||
group by bug.create_user;
|
||||
</select>
|
||||
|
||||
<select id="projectUserBugStatusCount"
|
||||
resultType="io.metersphere.project.dto.ProjectUserStatusCountDTO">
|
||||
SELECT bug.create_user as userId, bug.status, count(bug.id) as count
|
||||
FROM bug
|
||||
WHERE bug.deleted = false
|
||||
AND bug.project_id = #{projectId}
|
||||
AND bug.create_time BETWEEN #{startTime} AND #{endTime}
|
||||
AND bug.handle_user != ''
|
||||
<if test="userIds != null and userIds.size() > 0">
|
||||
AND bug.handle_user IN
|
||||
<foreach collection="userIds" item="userId" separator="," open="(" close=")">
|
||||
#{userId}
|
||||
</foreach>
|
||||
</if>
|
||||
AND bug.platform IN
|
||||
<foreach collection="platforms" item="platform" separator="," open="(" close=")">
|
||||
#{platform}
|
||||
</foreach>
|
||||
group by bug.handle_user, bug.status;
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
|
||||
|
@ -0,0 +1,24 @@
|
||||
package io.metersphere.functional.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class FunctionalCaseStatisticDTO {
|
||||
|
||||
@Schema(description = "caseID")
|
||||
private String caseId;
|
||||
|
||||
@Schema(description = "fieldId")
|
||||
private String fieldId;
|
||||
|
||||
@Schema(description = "评审结果:未评审(UN_REVIEWED)/评审中(UNDER_REVIEWED)/PASS(通过)/UN_PASS(未通过)/RE_REVIEWED(重新提审)")
|
||||
private String reviewStatus;
|
||||
|
||||
@Schema(description = "用例等级")
|
||||
private String priority;
|
||||
}
|
@ -3,10 +3,7 @@ package io.metersphere.functional.mapper;
|
||||
import io.metersphere.dto.TestCaseProviderDTO;
|
||||
import io.metersphere.functional.domain.FunctionalCase;
|
||||
import io.metersphere.functional.domain.FunctionalCaseCustomField;
|
||||
import io.metersphere.functional.dto.BaseFunctionalCaseBatchDTO;
|
||||
import io.metersphere.functional.dto.FunctionalCaseMindDTO;
|
||||
import io.metersphere.functional.dto.FunctionalCasePageDTO;
|
||||
import io.metersphere.functional.dto.FunctionalCaseVersionDTO;
|
||||
import io.metersphere.functional.dto.*;
|
||||
import io.metersphere.functional.request.*;
|
||||
import io.metersphere.project.dto.ModuleCountDTO;
|
||||
import io.metersphere.project.dto.ProjectCountDTO;
|
||||
@ -124,4 +121,10 @@ public interface ExtFunctionalCaseMapper {
|
||||
|
||||
List<ProjectUserCreateCount> userCreateCaseCount(@Param("projectId") String projectId, @Param("startTime") long startTime, @Param("endTime") long endTime, @Param("userIds") Set<String> userIds);
|
||||
|
||||
List<FunctionalCaseStatisticDTO> getStatisticListByProjectId(@Param("projectId") String projectId, @Param("startTime") long startTime, @Param("endTime") long endTime);
|
||||
|
||||
long caseTestCount(@Param("projectId") String projectId, @Param("startTime") long startTime, @Param("endTime") long endTime);
|
||||
|
||||
long simpleCaseCount(@Param("projectId") String projectId, @Param("startTime") long startTime, @Param("endTime") long endTime);
|
||||
|
||||
}
|
||||
|
@ -893,6 +893,45 @@
|
||||
</foreach>
|
||||
</select>
|
||||
|
||||
<select id="getStatisticListByProjectId" resultType="io.metersphere.functional.dto.FunctionalCaseStatisticDTO">
|
||||
SELECT
|
||||
fc.id as caseId,
|
||||
fc.review_status as reviewStatus,
|
||||
fccf.field_id as fieldId,
|
||||
fccf.value as priority
|
||||
FROM functional_case fc
|
||||
LEFT JOIN functional_case_custom_field fccf ON fccf.case_id = fc.id
|
||||
LEFT JOIN custom_field cf ON cf.id = fccf.field_id
|
||||
WHERE fc.deleted = false
|
||||
AND fc.create_time BETWEEN #{startTime} AND #{endTime}
|
||||
AND fc.project_id = #{projectId}
|
||||
AND cf.name = 'functional_priority'
|
||||
AND cf.scene = 'FUNCTIONAL'
|
||||
AND cf.internal= true
|
||||
</select>
|
||||
|
||||
<select id="caseTestCount"
|
||||
resultType="java.lang.Long">
|
||||
select
|
||||
count(distinct fct.case_id)
|
||||
from functional_case_test fct
|
||||
LEFT JOIN functional_case fc ON fc.id = fct.case_id
|
||||
where fct.project_id = #{projectId}
|
||||
and fc.project_id = #{projectId}
|
||||
and fc.deleted = false
|
||||
and fc.create_time between #{startTime} and #{endTime}
|
||||
</select>
|
||||
|
||||
<select id="simpleCaseCount"
|
||||
resultType="java.lang.Long">
|
||||
select
|
||||
count(functional_case.id)
|
||||
from functional_case
|
||||
where functional_case.deleted = false
|
||||
and functional_case.project_id = #{projectId}
|
||||
and functional_case.create_time between #{startTime} and #{endTime}
|
||||
</select>
|
||||
|
||||
<select id="getProjectIdByIds" resultType="io.metersphere.functional.domain.FunctionalCase">
|
||||
select id, project_id from functional_case where id in
|
||||
<foreach collection="ids" item="id" open="(" separator="," close=")">
|
||||
|
@ -3,6 +3,7 @@ package io.metersphere.dashboard.controller;
|
||||
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.system.security.CheckOwner;
|
||||
import io.metersphere.system.utils.SessionUtils;
|
||||
@ -60,4 +61,18 @@ public class DashboardController {
|
||||
|
||||
|
||||
|
||||
@PostMapping("/case_count")
|
||||
@Operation(summary = "用例数")
|
||||
@CheckOwner(resourceId = "#request.getOrganizationId()", resourceType = "organization")
|
||||
public StatisticsDTO projectCaseCount(@Validated @RequestBody DashboardFrontPageRequest request) {
|
||||
return dashboardService.projectCaseCount(request);
|
||||
}
|
||||
|
||||
@PostMapping("/associate_case_count")
|
||||
@Operation(summary = "关联用例统计")
|
||||
@CheckOwner(resourceId = "#request.getOrganizationId()", resourceType = "organization")
|
||||
public StatisticsDTO projectAssociateCaseCount(@Validated @RequestBody DashboardFrontPageRequest request) {
|
||||
return dashboardService.projectAssociateCaseCount(request);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,18 @@
|
||||
package io.metersphere.dashboard.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class NameCountDTO {
|
||||
|
||||
@Schema(description = "名称")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "数量")
|
||||
private Integer count;
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package io.metersphere.dashboard.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class StatusPercentDTO {
|
||||
|
||||
@Schema(description = "状态")
|
||||
private String status;
|
||||
|
||||
@Schema(description = "数量")
|
||||
private Integer count;
|
||||
|
||||
@Schema(description = "百分比")
|
||||
private String percentValue;
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package io.metersphere.dashboard.response;
|
||||
|
||||
import io.metersphere.dashboard.dto.NameCountDTO;
|
||||
import io.metersphere.dashboard.dto.StatusPercentDTO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class StatisticsDTO {
|
||||
|
||||
@Schema(description = "指标DTO")
|
||||
private Map<String, List<NameCountDTO>> statusStatisticsMap;
|
||||
|
||||
@Schema(description = "百分比集合")
|
||||
private List<StatusPercentDTO>statusPercentList;
|
||||
}
|
@ -4,11 +4,18 @@ import io.metersphere.api.mapper.ExtApiDefinitionMapper;
|
||||
import io.metersphere.api.mapper.ExtApiScenarioMapper;
|
||||
import io.metersphere.api.mapper.ExtApiTestCaseMapper;
|
||||
import io.metersphere.bug.mapper.ExtBugMapper;
|
||||
import io.metersphere.bug.service.BugCommonService;
|
||||
import io.metersphere.bug.service.BugStatusService;
|
||||
import io.metersphere.dashboard.constants.DashboardUserLayoutKeys;
|
||||
import io.metersphere.dashboard.dto.LayoutDTO;
|
||||
import io.metersphere.dashboard.dto.NameArrayDTO;
|
||||
import io.metersphere.dashboard.dto.NameCountDTO;
|
||||
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.FunctionalCaseReviewStatus;
|
||||
import io.metersphere.functional.dto.FunctionalCaseStatisticDTO;
|
||||
import io.metersphere.functional.mapper.ExtCaseReviewMapper;
|
||||
import io.metersphere.functional.mapper.ExtFunctionalCaseMapper;
|
||||
import io.metersphere.plan.mapper.ExtTestPlanMapper;
|
||||
@ -18,9 +25,11 @@ import io.metersphere.project.dto.ProjectUserCreateCount;
|
||||
import io.metersphere.project.mapper.ExtProjectMapper;
|
||||
import io.metersphere.project.mapper.ExtProjectMemberMapper;
|
||||
import io.metersphere.project.mapper.ProjectMapper;
|
||||
import io.metersphere.project.service.ProjectApplicationService;
|
||||
import io.metersphere.project.service.ProjectService;
|
||||
import io.metersphere.sdk.constants.PermissionConstants;
|
||||
import io.metersphere.sdk.util.JSON;
|
||||
import io.metersphere.sdk.util.Translator;
|
||||
import io.metersphere.system.domain.UserLayout;
|
||||
import io.metersphere.system.domain.UserLayoutExample;
|
||||
import io.metersphere.system.dto.user.ProjectUserMemberDTO;
|
||||
@ -33,6 +42,8 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ -69,6 +80,12 @@ public class DashboardService {
|
||||
private ProjectMapper projectMapper;
|
||||
@Resource
|
||||
private UserLayoutMapper userLayoutMapper;
|
||||
@Resource
|
||||
private BugCommonService bugCommonService;
|
||||
@Resource
|
||||
private BugStatusService bugStatusService;
|
||||
@Resource
|
||||
private ProjectApplicationService projectApplicationService;
|
||||
|
||||
|
||||
public static final String FUNCTIONAL = "FUNCTIONAL"; // 功能用例
|
||||
@ -298,11 +315,11 @@ public class DashboardService {
|
||||
allHandleUsers.addAll(layoutDTO.getHandleUsers());
|
||||
}
|
||||
List<Project> getUserProjectIdName;
|
||||
if(CollectionUtils.isEmpty(allProjectIds)) {
|
||||
getUserProjectIdName =extProjectMapper.getUserProjectIdName(organizationId, null, userId);
|
||||
if (CollectionUtils.isEmpty(allProjectIds)) {
|
||||
getUserProjectIdName = extProjectMapper.getUserProjectIdName(organizationId, null, userId);
|
||||
} else {
|
||||
List<String> projectIds = allProjectIds.stream().distinct().toList();
|
||||
getUserProjectIdName =extProjectMapper.getUserProjectIdName(null, projectIds, userId);
|
||||
getUserProjectIdName = extProjectMapper.getUserProjectIdName(null, projectIds, userId);
|
||||
}
|
||||
Map<String, Project> projectMap = getUserProjectIdName.stream().collect(Collectors.toMap(Project::getId, t -> t));
|
||||
List<String> handleUsers = allHandleUsers.stream().distinct().toList();
|
||||
@ -396,7 +413,7 @@ public class DashboardService {
|
||||
Map<String, Integer> userApiScenarioCountMap;
|
||||
Map<String, Integer> userApiCaseCountMap;
|
||||
Map<String, Integer> userPlanCountMap;
|
||||
Map<String, Integer> userBugCountMap ;
|
||||
Map<String, Integer> userBugCountMap;
|
||||
|
||||
if (moduleIds.contains(FUNCTIONAL_CASE_MODULE)) {
|
||||
List<ProjectUserCreateCount> userCreateCaseCount = extFunctionalCaseMapper.userCreateCaseCount(projectId, toStartTime, toEndTime, userIds);
|
||||
@ -408,7 +425,7 @@ public class DashboardService {
|
||||
userCaseCountMap = new HashMap<>();
|
||||
}
|
||||
if (moduleIds.contains(API_TEST_MODULE)) {
|
||||
List<ProjectUserCreateCount> userCreateApiCount = extApiDefinitionMapper.userCreateApiCount(projectId, toStartTime, toEndTime, userIds);
|
||||
List<ProjectUserCreateCount> userCreateApiCount = extApiDefinitionMapper.userCreateApiCount(projectId, toStartTime, toEndTime, userIds);
|
||||
userApiCountMap = userCreateApiCount.stream().collect(Collectors.toMap(ProjectUserCreateCount::getUserId, ProjectUserCreateCount::getCount));
|
||||
List<ProjectUserCreateCount> userCreateApiScenarioCount = extApiScenarioMapper.userCreateApiScenarioCount(projectId, toStartTime, toEndTime, userIds);
|
||||
userApiScenarioCountMap = userCreateApiScenarioCount.stream().collect(Collectors.toMap(ProjectUserCreateCount::getUserId, ProjectUserCreateCount::getCount));
|
||||
@ -440,38 +457,38 @@ public class DashboardService {
|
||||
List<Integer> userPlanCount = new ArrayList<>();
|
||||
List<Integer> userBugCount = new ArrayList<>();
|
||||
|
||||
userNameMap.forEach((id, userName)->{
|
||||
if (userCaseCountMap.get(id)!=null) {
|
||||
userNameMap.forEach((id, userName) -> {
|
||||
if (userCaseCountMap.get(id) != null) {
|
||||
userCaseCount.add(userCaseCountMap.get(id));
|
||||
} else {
|
||||
userCaseCount.add(0);
|
||||
}
|
||||
if (userReviewCountMap.get(id)!=null) {
|
||||
if (userReviewCountMap.get(id) != null) {
|
||||
userReviewCount.add(userCaseCountMap.get(id));
|
||||
} else {
|
||||
userReviewCount.add(0);
|
||||
}
|
||||
if (userApiCountMap.get(id)!=null) {
|
||||
if (userApiCountMap.get(id) != null) {
|
||||
userApiCount.add(userApiCountMap.get(id));
|
||||
} else {
|
||||
userApiCount.add(0);
|
||||
}
|
||||
if (userApiCaseCountMap.get(id)!=null) {
|
||||
if (userApiCaseCountMap.get(id) != null) {
|
||||
userApiCaseCount.add(userApiCaseCountMap.get(id));
|
||||
} else {
|
||||
userApiCaseCount.add(0);
|
||||
}
|
||||
if (userApiScenarioCountMap.get(id)!=null) {
|
||||
if (userApiScenarioCountMap.get(id) != null) {
|
||||
userApiScenarioCount.add(userApiScenarioCountMap.get(id));
|
||||
} else {
|
||||
userApiScenarioCount.add(0);
|
||||
}
|
||||
if (userPlanCountMap.get(id)!=null) {
|
||||
if (userPlanCountMap.get(id) != null) {
|
||||
userPlanCount.add(userPlanCountMap.get(id));
|
||||
} else {
|
||||
userPlanCount.add(0);
|
||||
}
|
||||
if (userBugCountMap.get(id)!=null) {
|
||||
if (userBugCountMap.get(id) != null) {
|
||||
userBugCount.add(userBugCountMap.get(id));
|
||||
} else {
|
||||
userBugCount.add(0);
|
||||
@ -511,4 +528,139 @@ public class DashboardService {
|
||||
overViewCountDTO.setProjectCountList(nameArrayDTOList);
|
||||
return overViewCountDTO;
|
||||
}
|
||||
|
||||
|
||||
public StatisticsDTO projectCaseCount(DashboardFrontPageRequest request) {
|
||||
String projectId = request.getProjectIds().getFirst();
|
||||
StatisticsDTO statisticsDTO = new StatisticsDTO();
|
||||
if (Boolean.FALSE.equals(checkModule(projectId, FUNCTIONAL_CASE_MODULE))) return statisticsDTO;
|
||||
List<StatusPercentDTO>statusPercentList = new ArrayList<>();
|
||||
Long toStartTime = request.getToStartTime();
|
||||
Long toEndTime = request.getToEndTime();
|
||||
List<FunctionalCaseStatisticDTO> statisticListByProjectId = extFunctionalCaseMapper.getStatisticListByProjectId(projectId, toStartTime, toEndTime);
|
||||
buildStatusPercentList(statisticListByProjectId, statusPercentList);
|
||||
statisticsDTO.setStatusPercentList(statusPercentList);
|
||||
Map<String, List<FunctionalCaseStatisticDTO>> reviewStatusMap = statisticListByProjectId.stream().collect(Collectors.groupingBy(FunctionalCaseStatisticDTO::getReviewStatus));
|
||||
Map<String, List<NameCountDTO>> statusStatisticsMap = new HashMap<>();
|
||||
List<NameCountDTO> reviewList = getReviewList(reviewStatusMap, statisticListByProjectId);
|
||||
statusStatisticsMap.put("review", reviewList);
|
||||
List<NameCountDTO> passList = getPassList(reviewStatusMap, statisticListByProjectId);
|
||||
statusStatisticsMap.put("pass", passList);
|
||||
statisticsDTO.setStatusStatisticsMap(statusStatisticsMap);
|
||||
return statisticsDTO;
|
||||
}
|
||||
|
||||
private Boolean checkModule(String projectId, String module) {
|
||||
Project project = projectMapper.selectByPrimaryKey(projectId);
|
||||
List<String> moduleIds = JSON.parseArray(project.getModuleSetting(), String.class);
|
||||
return moduleIds.contains(module);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static List<NameCountDTO> getPassList(Map<String, List<FunctionalCaseStatisticDTO>> reviewStatusMap, List<FunctionalCaseStatisticDTO> statisticListByProjectId) {
|
||||
List<NameCountDTO> passList = new ArrayList<>();
|
||||
List<FunctionalCaseStatisticDTO> hasPassList = reviewStatusMap.get(FunctionalCaseReviewStatus.PASS.toString());
|
||||
if (CollectionUtils.isEmpty(hasPassList)) {
|
||||
hasPassList = new ArrayList<>();
|
||||
}
|
||||
NameCountDTO passRate = new NameCountDTO();
|
||||
passRate.setName(Translator.get("functional_case.passRate"));
|
||||
if (CollectionUtils.isNotEmpty(statisticListByProjectId)) {
|
||||
BigDecimal divide = BigDecimal.valueOf(hasPassList.size()).divide(BigDecimal.valueOf(statisticListByProjectId.size()), 0, RoundingMode.HALF_UP);
|
||||
passRate.setCount(Integer.valueOf(String.valueOf(divide.multiply(BigDecimal.valueOf(100)))));
|
||||
} else {
|
||||
passRate.setCount(0);
|
||||
}
|
||||
passList.add(passRate);
|
||||
NameCountDTO hasPass = new NameCountDTO();
|
||||
hasPass.setName(Translator.get("functional_case.hasPass"));
|
||||
hasPass.setCount(hasPassList.size());
|
||||
passList.add(hasPass);
|
||||
NameCountDTO unPass = new NameCountDTO();
|
||||
unPass.setName(Translator.get("functional_case.unPass"));
|
||||
unPass.setCount(statisticListByProjectId.size()-hasPassList.size());
|
||||
passList.add(unPass);
|
||||
return passList;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static List<NameCountDTO> getReviewList(Map<String, List<FunctionalCaseStatisticDTO>> reviewStatusMap, List<FunctionalCaseStatisticDTO> statisticListByProjectId) {
|
||||
List<NameCountDTO>reviewList = new ArrayList<>();
|
||||
List<FunctionalCaseStatisticDTO> unReviewList = reviewStatusMap.get(FunctionalCaseReviewStatus.UN_REVIEWED.toString());
|
||||
if (CollectionUtils.isEmpty(unReviewList)) {
|
||||
unReviewList = new ArrayList<>();
|
||||
}
|
||||
NameCountDTO reviewRate = new NameCountDTO();
|
||||
reviewRate.setName(Translator.get("functional_case.reviewRate"));
|
||||
if (CollectionUtils.isEmpty(statisticListByProjectId)) {
|
||||
reviewRate.setCount(0);
|
||||
} else {
|
||||
BigDecimal divide = BigDecimal.valueOf(statisticListByProjectId.size()-unReviewList.size()).divide(BigDecimal.valueOf(statisticListByProjectId.size()), 0, RoundingMode.HALF_UP);
|
||||
reviewRate.setCount(Integer.valueOf(String.valueOf(divide.multiply(BigDecimal.valueOf(100)))));
|
||||
}
|
||||
reviewList.add(reviewRate);
|
||||
NameCountDTO hasReview = new NameCountDTO();
|
||||
hasReview.setName(Translator.get("functional_case.hasReview"));
|
||||
hasReview.setCount(statisticListByProjectId.size()-unReviewList.size());
|
||||
reviewList.add(hasReview);
|
||||
NameCountDTO unReview = new NameCountDTO();
|
||||
unReview.setName(Translator.get("functional_case.unReview"));
|
||||
unReview.setCount(unReviewList.size());
|
||||
reviewList.add(unReview);
|
||||
return reviewList;
|
||||
}
|
||||
|
||||
private static void buildStatusPercentList(List<FunctionalCaseStatisticDTO> statisticListByProjectId, List<StatusPercentDTO> statusPercentList) {
|
||||
Map<String, List<FunctionalCaseStatisticDTO>> priorityMap = statisticListByProjectId.stream().collect(Collectors.groupingBy(FunctionalCaseStatisticDTO::getPriority));
|
||||
for (int i = 0; i < 4; i++) {
|
||||
String priority = "P" + i;
|
||||
StatusPercentDTO statusPercentDTO = new StatusPercentDTO();
|
||||
statusPercentDTO.setStatus(priority);
|
||||
List<FunctionalCaseStatisticDTO> functionalCaseStatisticDTOS = priorityMap.get(priority);
|
||||
if (CollectionUtils.isNotEmpty(functionalCaseStatisticDTOS)) {
|
||||
int size = functionalCaseStatisticDTOS.size();
|
||||
statusPercentDTO.setCount(size);
|
||||
BigDecimal divide = BigDecimal.valueOf(size).divide(BigDecimal.valueOf(statisticListByProjectId.size()), 2, RoundingMode.HALF_UP);
|
||||
statusPercentDTO.setPercentValue(divide.multiply(BigDecimal.valueOf(100))+"%");
|
||||
} else {
|
||||
statusPercentDTO.setCount(0);
|
||||
statusPercentDTO.setPercentValue("0%");
|
||||
}
|
||||
statusPercentList.add(statusPercentDTO);
|
||||
}
|
||||
}
|
||||
|
||||
public StatisticsDTO projectAssociateCaseCount(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();
|
||||
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);
|
||||
Map<String, List<NameCountDTO>> statusStatisticsMap = new HashMap<>();
|
||||
statusStatisticsMap.put("cover", coverList);
|
||||
statisticsDTO.setStatusStatisticsMap(statusStatisticsMap);
|
||||
return statisticsDTO;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -5,6 +5,7 @@ import io.metersphere.dashboard.constants.DashboardUserLayoutKeys;
|
||||
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.project.domain.Project;
|
||||
import io.metersphere.project.domain.ProjectExample;
|
||||
@ -49,6 +50,8 @@ public class DashboardFrontPageControllerTests extends BaseTest {
|
||||
private static final String CREATE_BY_ME = "/dashboard/create_by_me";
|
||||
private static final String PROJECT_VIEW = "/dashboard/project_view";
|
||||
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";
|
||||
|
||||
|
||||
@Test
|
||||
@ -108,12 +111,7 @@ public class DashboardFrontPageControllerTests extends BaseTest {
|
||||
projectMapper.updateByPrimaryKeySelective(project);
|
||||
OverViewCountDTO gyq4 = dashboardService.projectViewCount(dashboardFrontPageRequest, "default-dashboard-member-user-gyq");
|
||||
Assertions.assertTrue(gyq4.getXAxis().isEmpty());
|
||||
List<String> moduleIds = new ArrayList<>();
|
||||
moduleIds.add("apiTest");
|
||||
moduleIds.add("testPlan");
|
||||
moduleIds.add("caseManagement");
|
||||
moduleIds.add("bugManagement");
|
||||
project.setModuleSetting(moduleIds.toString());
|
||||
project.setModuleSetting("[\"apiTest\",\"testPlan\",\"caseManagement\",\"bugManagement\"]");
|
||||
project.setId(DEFAULT_PROJECT_ID);
|
||||
projectMapper.updateByPrimaryKeySelective(project);
|
||||
}
|
||||
@ -121,7 +119,7 @@ public class DashboardFrontPageControllerTests extends BaseTest {
|
||||
@Test
|
||||
@Order(2)
|
||||
public void testLayout() throws Exception {
|
||||
MvcResult mvcResultGrt = this.requestGetWithOkAndReturn(GET_LAYOUT+"DEFAULT_ORGANIZATION_ID");
|
||||
MvcResult mvcResultGrt = this.requestGetWithOkAndReturn(GET_LAYOUT + "DEFAULT_ORGANIZATION_ID");
|
||||
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);
|
||||
@ -131,7 +129,7 @@ public class DashboardFrontPageControllerTests extends BaseTest {
|
||||
projectExample.createCriteria().andOrganizationIdEqualTo(DEFAULT_ORGANIZATION_ID);
|
||||
List<Project> projects = projectMapper.selectByExample(projectExample);
|
||||
|
||||
ProjectMemberRequest projectMemberRequest = new ProjectMemberRequest();
|
||||
ProjectMemberRequest projectMemberRequest = new ProjectMemberRequest();
|
||||
projectMemberRequest.setProjectId(DEFAULT_PROJECT_ID);
|
||||
projectMemberRequest.setCurrent(1);
|
||||
projectMemberRequest.setPageSize(5);
|
||||
@ -179,13 +177,13 @@ public class DashboardFrontPageControllerTests extends BaseTest {
|
||||
layoutDTO1.setHandleUsers(new ArrayList<>());
|
||||
layoutDTO1.setFullScreen(false);
|
||||
layoutDTO.add(layoutDTO1);
|
||||
MvcResult mvcResult = this.requestPostWithOkAndReturn(EDIT_LAYOUT+DEFAULT_ORGANIZATION_ID, layoutDTO);
|
||||
MvcResult mvcResult = this.requestPostWithOkAndReturn(EDIT_LAYOUT + DEFAULT_ORGANIZATION_ID, layoutDTO);
|
||||
contentAsString = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
||||
resultHolder = JSON.parseObject(contentAsString, ResultHolder.class);
|
||||
layoutDTOS = JSON.parseArray(JSON.toJSONString(resultHolder.getData()), LayoutDTO.class);
|
||||
Assertions.assertNotNull(layoutDTOS);
|
||||
|
||||
mvcResultGrt = this.requestGetWithOkAndReturn(GET_LAYOUT+DEFAULT_ORGANIZATION_ID);
|
||||
mvcResultGrt = this.requestGetWithOkAndReturn(GET_LAYOUT + DEFAULT_ORGANIZATION_ID);
|
||||
contentAsString = mvcResultGrt.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
||||
resultHolder = JSON.parseObject(contentAsString, ResultHolder.class);
|
||||
layoutDTOS = JSON.parseArray(JSON.toJSONString(resultHolder.getData()), LayoutDTO.class);
|
||||
@ -200,15 +198,66 @@ public class DashboardFrontPageControllerTests extends BaseTest {
|
||||
layoutDTO2.setHandleUsers(new ArrayList<>());
|
||||
layoutDTO2.setFullScreen(false);
|
||||
layoutDTO.add(layoutDTO1);
|
||||
mvcResult = this.requestPostWithOkAndReturn(EDIT_LAYOUT+DEFAULT_ORGANIZATION_ID, layoutDTO);
|
||||
mvcResult = this.requestPostWithOkAndReturn(EDIT_LAYOUT + DEFAULT_ORGANIZATION_ID, layoutDTO);
|
||||
contentAsString = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
||||
resultHolder = JSON.parseObject(contentAsString, ResultHolder.class);
|
||||
layoutDTOS = JSON.parseArray(JSON.toJSONString(resultHolder.getData()), LayoutDTO.class);
|
||||
Assertions.assertNotNull(layoutDTOS);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(3)
|
||||
public void testOther() throws Exception {
|
||||
DashboardFrontPageRequest dashboardFrontPageRequest = new DashboardFrontPageRequest();
|
||||
dashboardFrontPageRequest.setOrganizationId(DEFAULT_ORGANIZATION_ID);
|
||||
dashboardFrontPageRequest.setDayNumber(null);
|
||||
dashboardFrontPageRequest.setStartTime(1697971947000L);
|
||||
dashboardFrontPageRequest.setEndTime(1700650347000L);
|
||||
dashboardFrontPageRequest.setCurrent(1);
|
||||
dashboardFrontPageRequest.setPageSize(5);
|
||||
dashboardFrontPageRequest.setProjectIds(List.of(DEFAULT_PROJECT_ID));
|
||||
MvcResult mvcResult = this.requestPostWithOkAndReturn(CASE_COUNT, dashboardFrontPageRequest);
|
||||
String contentAsString = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
||||
ResultHolder resultHolder = JSON.parseObject(contentAsString, ResultHolder.class);
|
||||
StatisticsDTO moduleCount = JSON.parseObject(JSON.toJSONString(resultHolder.getData()), StatisticsDTO.class);
|
||||
Assertions.assertNotNull(moduleCount);
|
||||
MvcResult associateMvcResult = this.requestPostWithOkAndReturn(ASSOCIATE_CASE_COUNT, dashboardFrontPageRequest);
|
||||
String associateContent = associateMvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
||||
ResultHolder associateResultHolder = JSON.parseObject(associateContent, ResultHolder.class);
|
||||
StatisticsDTO associateCount = JSON.parseObject(JSON.toJSONString(associateResultHolder.getData()), StatisticsDTO.class);
|
||||
Assertions.assertNotNull(associateCount);
|
||||
Project project = new Project();
|
||||
project.setModuleSetting("[]");
|
||||
project.setId(DEFAULT_PROJECT_ID);
|
||||
projectMapper.updateByPrimaryKeySelective(project);
|
||||
mvcResult = this.requestPostWithOkAndReturn(CASE_COUNT, dashboardFrontPageRequest);
|
||||
contentAsString = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
||||
resultHolder = JSON.parseObject(contentAsString, ResultHolder.class);
|
||||
moduleCount = JSON.parseObject(JSON.toJSONString(resultHolder.getData()), StatisticsDTO.class);
|
||||
Assertions.assertNotNull(moduleCount);
|
||||
associateMvcResult = this.requestPostWithOkAndReturn(ASSOCIATE_CASE_COUNT, dashboardFrontPageRequest);
|
||||
associateContent = associateMvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
||||
associateResultHolder = JSON.parseObject(associateContent, ResultHolder.class);
|
||||
associateCount = JSON.parseObject(JSON.toJSONString(associateResultHolder.getData()), StatisticsDTO.class);
|
||||
Assertions.assertNotNull(associateCount);
|
||||
project.setModuleSetting("[\"apiTest\",\"testPlan\",\"caseManagement\",\"bugManagement\"]");
|
||||
project.setId(DEFAULT_PROJECT_ID);
|
||||
projectMapper.updateByPrimaryKeySelective(project);
|
||||
dashboardFrontPageRequest.setDayNumber(3);
|
||||
dashboardFrontPageRequest.setStartTime(null);
|
||||
dashboardFrontPageRequest.setEndTime(null);
|
||||
mvcResult = this.requestPostWithOkAndReturn(CASE_COUNT, dashboardFrontPageRequest);
|
||||
contentAsString = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
||||
resultHolder = JSON.parseObject(contentAsString, ResultHolder.class);
|
||||
moduleCount = JSON.parseObject(JSON.toJSONString(resultHolder.getData()), StatisticsDTO.class);
|
||||
Assertions.assertNotNull(moduleCount);
|
||||
associateMvcResult = this.requestPostWithOkAndReturn(ASSOCIATE_CASE_COUNT, dashboardFrontPageRequest);
|
||||
associateContent = associateMvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
||||
associateResultHolder = JSON.parseObject(associateContent, ResultHolder.class);
|
||||
associateCount = JSON.parseObject(JSON.toJSONString(associateResultHolder.getData()), StatisticsDTO.class);
|
||||
Assertions.assertNotNull(associateCount);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -22,5 +22,44 @@ VALUES (UUID(), 'default-dashboard-member-user-gyq', 'project_admin', 'project-r
|
||||
INSERT INTO user_role_permission(id, role_id, permission_id)
|
||||
VALUES ('user_role_gyq_permission1', 'project_admin', 'FUNCTIONAL_CASE:READ+COMMENT');
|
||||
|
||||
INSERT INTO functional_case(id, num, module_id, project_id, template_id, name, review_status, tags, case_edit_type, pos, version_id, ref_id, last_execute_result, deleted, public_case, latest, create_user, update_user, delete_user, create_time, update_time, delete_time)
|
||||
VALUES ('dashboard_TEST_FUNCTIONAL_CASE_ID_g', 8, 'Trash_TEST_MOUDLE_ID_1', '100001100001', '100001', 'copy_测试多版本g', 'UN_REVIEWED', NULL, 'STEP', 0, 'v3.0.0', 'Trash_TEST_FUNCTIONAL_CASE_ID_f', 'UN_EXECUTED',false, b'0', b'1', 'gyq', 'gyq', '', 1698058347559, 1698058347559, NULL);
|
||||
|
||||
INSERT INTO functional_case(id, num, module_id, project_id, template_id, name, review_status, tags, case_edit_type, pos, version_id, ref_id, last_execute_result, deleted, public_case, latest, create_user, update_user, delete_user, create_time, update_time, delete_time)
|
||||
VALUES ('dashboard_TEST_FUNCTIONAL_CASE_ID_GYQ', 10, 'Trash_TEST_MOUDLE_ID', '100001100001', '100001', '回收站测信', 'UNDER_REVIEWED', NULL, 'STEP', 0, 'v1.0.0', 'Trash_TEST_FUNCTIONAL_CASE_ID_GYQ', 'UN_EXECUTED', false, b'0', b'0', 'gyq', 'gyq', '', 1698058347559, 1698058347559, NULL);
|
||||
|
||||
INSERT INTO functional_case(id, num, module_id, project_id, template_id, name, review_status, tags, case_edit_type, pos, version_id, ref_id, last_execute_result, deleted, public_case, latest, create_user, update_user, delete_user, create_time, update_time, delete_time)
|
||||
VALUES ('dashboard_TEST_FUNCTIONAL_CASE_ID', 20, 'Trash_TEST_MOUDLE_ID', '100001100001', '100001', '回收站测信', 'PASS', NULL, 'STEP', 0, 'v1.0.0', 'unTrash_TEST_FUNCTIONAL_CASE_ID', 'UN_EXECUTED', false, b'0', b'0', 'gyq', 'gyq', '', 1698058347559, 1698058347559, NULL);
|
||||
|
||||
INSERT INTO functional_case(id, num, module_id, project_id, template_id, name, review_status, tags, case_edit_type, pos, version_id, ref_id, last_execute_result, deleted, public_case, latest, create_user, update_user, delete_user, create_time, update_time, delete_time)
|
||||
VALUES ('dashboard_TEST_FUNCTIONAL_CASE_ID5', 30, 'Trash_TEST_MOUDLE_ID', '100001100001', '100001', '回收站测信', 'RE_REVIEWED', NULL, 'STEP', 0, 'v1.0.0', 'unTrash_TEST_FUNCTIONAL_CASE_ID', 'UN_EXECUTED', false, b'0', b'0', 'gyq', 'gyq', '', 1698058347559, 1698058347559, NULL);
|
||||
|
||||
INSERT INTO case_review(id, num, name, module_id, project_id, status, review_pass_rule, pos, start_time, end_time, case_count, pass_rate, tags, description, create_time, create_user, update_time, update_user)
|
||||
VALUES ('dashboardGyq_review_id', 10001, '用例评审1', 'Trash_TEST_MOUDLE_ID_1', 'project-case-trash-test', 'COMPLETE' , 'SINGLE', 0, 1698058347559, 1698058347559, 1, 100.00, null, null, 1698058347559, 'admin', 1698058347559, 'admin');
|
||||
|
||||
INSERT INTO case_review(id, num, name, module_id, project_id, status, review_pass_rule, pos, start_time, end_time, case_count, pass_rate, tags, description, create_time, create_user, update_time, update_user)
|
||||
VALUES ('dashboardGyq_review_id1', 10001, '用例评审2', 'Trash_TEST_MOUDLE_ID_1', 'project-case-trash-test', 'COMPLETE' , 'SINGLE', 0, 1698058347559, 1698058347559, 1, 100.00, null, null, 1698058347559, 'admin', 1698058347559, 'admin');
|
||||
|
||||
INSERT INTO case_review_functional_case(id, review_id, case_id, status, create_time, create_user, update_time, pos)
|
||||
VALUES ('dashboardGyq_Review_Case_Id','dashboardGyq_review_id', 'dashboard_TEST_FUNCTIONAL_CASE_ID_GYQ', 'UNDER_REVIEWED', 1698058347559, 'admin',1698058347559, 0);
|
||||
|
||||
INSERT INTO case_review_functional_case(id, review_id, case_id, status, create_time, create_user, update_time, pos)
|
||||
VALUES ('dashboardGyq_Review_Case_Id2','dashboardGyq_review_id1', 'dashboard_TEST_FUNCTIONAL_CASE_ID5', 'RE_REVIEWED', 1698058347559, 'admin',1698058347559, 0);
|
||||
|
||||
INSERT INTO case_review_functional_case(id, review_id, case_id, status, create_time, create_user, update_time, pos)
|
||||
VALUES ('dashboardGyq_Review_Case_Id3','dashboardGyq_review_id', 'dashboard_TEST_FUNCTIONAL_CASE_ID_g', 'UN_REVIEWED', 1698058347559, 'admin',1698058347559, 0);
|
||||
|
||||
|
||||
INSERT INTO case_review_functional_case(id, review_id, case_id, status, create_time, create_user, update_time, pos)
|
||||
VALUES ('dashboardGyq_Review_Case_Id4','dashboardGyq_review_id', 'dashboard_TEST_FUNCTIONAL_CASE_ID', 'PASS', 1698058347559, 'admin',1698058347559, 0);
|
||||
|
||||
INSERT INTO functional_case_custom_field(case_id, field_id, value) VALUES ('dashboard_TEST_FUNCTIONAL_CASE_ID_g', 'gyq_custom_id1', 'P0');
|
||||
INSERT INTO functional_case_custom_field(case_id, field_id, value) VALUES ('dashboard_TEST_FUNCTIONAL_CASE_ID', 'gyq_custom_id1', 'P2');
|
||||
INSERT INTO functional_case_custom_field(case_id, field_id, value) VALUES ('dashboard_TEST_FUNCTIONAL_CASE_ID5', 'gyq_custom_id1', 'P3');
|
||||
INSERT INTO functional_case_custom_field(case_id, field_id, value) VALUES ('dashboard_TEST_FUNCTIONAL_CASE_ID_GYQ', 'gyq_custom_id1', 'P1');
|
||||
|
||||
INSERT INTO custom_field(id, name, scene, `type`, remark, internal, scope_type, create_time, update_time, create_user, scope_id)
|
||||
VALUES('gyq_custom_id1', 'functional_priority', 'FUNCTIONAL', 'SELECT', '', 1, 'ORGANIZATION', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'test_template_case_trash_id');
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,19 @@
|
||||
package io.metersphere.project.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ProjectUserStatusCountDTO {
|
||||
|
||||
@Schema(description = "用户ID")
|
||||
private String userId;
|
||||
@Schema(description = "用户ID")
|
||||
private String status;
|
||||
@Schema(description = "数量")
|
||||
private int count;
|
||||
}
|
Loading…
Reference in New Issue
Block a user