feat(工作台): 缺陷统计完成

This commit is contained in:
guoyuqi 2024-11-13 20:42:49 +08:00 committed by Craftsman
parent fced7b284f
commit 39246f217a
8 changed files with 244 additions and 5 deletions

View File

@ -1,5 +1,6 @@
package io.metersphere.bug.mapper;
import io.metersphere.bug.domain.Bug;
import io.metersphere.bug.dto.request.BugBatchUpdateRequest;
import io.metersphere.bug.dto.request.BugPageRequest;
import io.metersphere.bug.dto.response.BugDTO;
@ -135,4 +136,5 @@ public interface ExtBugMapper {
*/
List<ProjectUserStatusCountDTO> projectUserBugStatusCount(@Param("projectId") String projectId, @Param("startTime") Long startTime, @Param("endTime") Long endTime, @Param("userIds") List<String> userIds, @Param("platforms") Set<String> platforms);
List<Bug>getSimpleList(@Param("projectId") String projectId, @Param("startTime") Long startTime, @Param("endTime") Long endTime,@Param("handleUser") String handleUser,@Param("createUser") String createUser, @Param("platforms") Set<String> platforms);
}

View File

@ -449,5 +449,27 @@
group by bug.handle_user, bug.status order by bug.handle_user;
</select>
<select id="getSimpleList" resultType="io.metersphere.bug.domain.Bug">
SELECT bug.id, bug.status, bug.platform, bug.platform_bug_id
FROM bug
WHERE bug.deleted = false
AND bug.project_id = #{projectId}
<if test="startTime != null and endTime != null">
AND bug.create_time BETWEEN #{startTime} AND #{endTime}
</if>
<if test="handleUser != null and handleUser != ''">
AND bug.handle_user = #{handleUser}
</if>
<if test="createUser != null and createUser != ''">
AND bug.create_user = #{createUser}
</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>
</mapper>

View File

@ -121,7 +121,6 @@ public class DashboardController {
return dashboardService.projectApiCaseCount(request, SessionUtils.getUserId());
}
@PostMapping("/scenario_count")
@Operation(summary = "场景数量统计")
@CheckOwner(resourceId = "#request.getOrganizationId()", resourceType = "organization")
@ -130,6 +129,28 @@ public class DashboardController {
}
@PostMapping("/bug_count")
@Operation(summary = "缺陷数量统计")
@CheckOwner(resourceId = "#request.getOrganizationId()", resourceType = "organization")
public StatisticsDTO projectBugCount(@Validated @RequestBody DashboardFrontPageRequest request) {
return dashboardService.projectBugCount(request, SessionUtils.getUserId());
}
@PostMapping("/create_bug_by_me")
@Operation(summary = "我创建的缺陷")
@CheckOwner(resourceId = "#request.getOrganizationId()", resourceType = "organization")
public StatisticsDTO projectBugCountCreateByMe(@Validated @RequestBody DashboardFrontPageRequest request) {
return dashboardService.projectBugCountCreateByMe(request, SessionUtils.getUserId());
}
@PostMapping("/handle_bug_by_me")
@Operation(summary = "我创建的缺陷")
@CheckOwner(resourceId = "#request.getOrganizationId()", resourceType = "organization")
public StatisticsDTO projectBugCountHandleByMe(@Validated @RequestBody DashboardFrontPageRequest request) {
return dashboardService.projectBugCountHandleByMe(request, SessionUtils.getUserId());
}
@PostMapping("/reviewing_by_me")
@Operation(summary = "待我评审")
@CheckOwner(resourceId = "#request.getOrganizationId()", resourceType = "organization")

View File

@ -12,6 +12,7 @@ import io.metersphere.api.mapper.ExtApiDefinitionMapper;
import io.metersphere.api.mapper.ExtApiScenarioMapper;
import io.metersphere.api.mapper.ExtApiTestCaseMapper;
import io.metersphere.api.service.ApiTestService;
import io.metersphere.bug.domain.Bug;
import io.metersphere.bug.enums.BugPlatform;
import io.metersphere.bug.mapper.ExtBugMapper;
import io.metersphere.bug.service.BugCommonService;
@ -1135,7 +1136,6 @@ public class DashboardService {
@NotNull
private static List<NameCountDTO> getExecRateDTOS(int unExecSize, int simpleAllApiCaseSize, String name) {
List<NameCountDTO> execRateDTOS = new ArrayList<>();
NameCountDTO execRateDTO = new NameCountDTO();
execRateDTO.setName(name);
if (simpleAllApiCaseSize == 0) {
@ -1203,6 +1203,97 @@ public class DashboardService {
statisticsDTO.setStatusStatisticsMap(statusStatisticsMap);
return statisticsDTO;
}
public StatisticsDTO baseProjectBugCount(DashboardFrontPageRequest request, String userId, Boolean hasHandleUser, Boolean hasCreateUser){
String projectId = request.getProjectIds().getFirst();
StatisticsDTO statisticsDTO = new StatisticsDTO();
if (Boolean.FALSE.equals(permissionCheckService.checkModule(projectId, BUG_MODULE, userId, PermissionConstants.PROJECT_BUG_READ))) {
statisticsDTO.setErrorCode(NO_PROJECT_PERMISSION.getCode());
return statisticsDTO;
}
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 = bugCommonService.getLocalLastStepStatus(projectId);
List<String> platformLastStepStatus = new ArrayList<>();
//TODO: 第三方的单元测试没成功
/*try {
platformLastStepStatus = bugCommonService.getPlatformLastStepStatus(projectId);
} catch (Exception e) {
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;
}
private static List<NameCountDTO> buildBugRetentionRateList(int totalSize, int statusSize) {
List<NameCountDTO> retentionRates = new ArrayList<>();
NameCountDTO retentionRate = new NameCountDTO();
retentionRate.setName(Translator.get("bug_management.retentionRate"));
if (totalSize ==0) {
retentionRate.setCount(0);
} else {
BigDecimal divide = BigDecimal.valueOf(statusSize).divide(BigDecimal.valueOf(totalSize), 2, RoundingMode.HALF_UP);
retentionRate.setCount(getTurnCount(divide));
}
retentionRates.add(retentionRate);
NameCountDTO total = getNameCountDTO(totalSize, Translator.get("bug_management.totalCount"));
retentionRates.add(total);
NameCountDTO retentionDTO = getNameCountDTO(statusSize, Translator.get("bug_management.retentionCount"));
retentionRates.add(retentionDTO);
return retentionRates;
}
private static List<StatusPercentDTO> bulidBugPercentList(List<SelectOption> headerStatusOption, Map<String, List<Bug>> bugMap, List<Bug> simpleList) {
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());
List<Bug> bugs = bugMap.get(selectOption.getValue());
int bugSize = CollectionUtils.isEmpty(bugs) ? 0 : bugs.size();
if (simpleSize == 0) {
statusPercentDTO.setPercentValue("0%");
statusPercentDTO.setCount(0);
} else {
BigDecimal divide = BigDecimal.valueOf(bugSize).divide(BigDecimal.valueOf(simpleSize), 2, RoundingMode.HALF_UP);
statusPercentDTO.setPercentValue(divide.multiply(BigDecimal.valueOf(100)) + "%");
statusPercentDTO.setCount(bugSize);
}
statusPercentList.add(statusPercentDTO);
}
return statusPercentList;
}
public StatisticsDTO projectBugCount(DashboardFrontPageRequest request, String userId) {
return baseProjectBugCount(request,userId,false,false);
}
public StatisticsDTO projectBugCountCreateByMe(DashboardFrontPageRequest request, String userId) {
return baseProjectBugCount(request,userId,false,true);
}
public StatisticsDTO projectBugCountHandleByMe(DashboardFrontPageRequest request, String userId) {
return baseProjectBugCount(request,userId,true,false);
}
}

View File

@ -21,11 +21,15 @@ import io.metersphere.project.mapper.ProjectMapper;
import io.metersphere.project.request.ProjectMemberRequest;
import io.metersphere.project.service.ProjectMemberService;
import io.metersphere.sdk.util.JSON;
import io.metersphere.system.base.BasePluginTestService;
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.mockserver.client.MockServerClient;
import org.mockserver.model.Header;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.jdbc.Sql;
@ -37,6 +41,8 @@ import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import static org.mockserver.model.HttpRequest.request;
import static org.mockserver.model.HttpResponse.response;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@ -56,6 +62,14 @@ public class DashboardFrontPageControllerTests extends BaseTest {
private BugStatusService bugStatusService;
@Resource
private BugMapper bugMapper;
@Resource
private BasePluginTestService basePluginTestService;
@Resource
private MockServerClient mockServerClient;
@Value("${embedded.mockserver.host}")
private String mockServerHost;
@Value("${embedded.mockserver.port}")
private int mockServerHostPort;
private static final String EDIT_LAYOUT = "/dashboard/layout/edit/";
private static final String GET_LAYOUT = "/dashboard/layout/get/";
@ -71,6 +85,11 @@ public class DashboardFrontPageControllerTests extends BaseTest {
private static final String API_COUNT = "/dashboard/api_count";
private static final String API_CASE_COUNT = "/dashboard/api_case_count";
private static final String SCENARIO_COUNT = "/dashboard/scenario_count";
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 REVIEWING_BY_ME = "/dashboard/reviewing_by_me";
private static final String API_CHANGE = "/dashboard/api_change";
@ -256,6 +275,22 @@ public class DashboardFrontPageControllerTests extends BaseTest {
@Test
@Order(3)
public void testOther() throws Exception {
basePluginTestService.addJiraPlugin();
basePluginTestService.addServiceIntegration(DEFAULT_ORGANIZATION_ID);
mockServerClient
.when(
request()
.withMethod("GET")
.withPath("/rest/api/2/search"))
.respond(
response()
.withStatusCode(200)
.withHeaders(
new Header("Content-Type", "application/json; charset=utf-8"),
new Header("Cache-Control", "public, max-age=86400"))
.withBody("{\"id\":\"123456\",\"name\":\"test\", \"issues\": [{\"key\": \"TES-1\",\"fields\": {\"summary\": \"Test\"}}], \"total\": 1}")
);
DashboardFrontPageRequest dashboardFrontPageRequest = new DashboardFrontPageRequest();
dashboardFrontPageRequest.setOrganizationId(DEFAULT_ORGANIZATION_ID);
dashboardFrontPageRequest.setDayNumber(null);
@ -264,6 +299,8 @@ 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);
@ -294,6 +331,22 @@ public class DashboardFrontPageControllerTests extends BaseTest {
ResultHolder reviewResultHolder = JSON.parseObject(reviewContent, ResultHolder.class);
StatisticsDTO reviewCount = JSON.parseObject(JSON.toJSONString(reviewResultHolder.getData()), StatisticsDTO.class);
Assertions.assertNotNull(reviewCount);
MvcResult bugMvcResult = this.requestPostWithOkAndReturn(BUG_COUNT, dashboardFrontPageRequest);
String bugContentAsString = bugMvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
ResultHolder bugResultHolder = JSON.parseObject(bugContentAsString, ResultHolder.class);
StatisticsDTO bugCount = JSON.parseObject(JSON.toJSONString(bugResultHolder.getData()), StatisticsDTO.class);
Assertions.assertNotNull(bugCount);
MvcResult createBugMvcResult = this.requestPostWithOkAndReturn(CREATE_BUG_BY_ME, dashboardFrontPageRequest);
String createBugContentAsString = createBugMvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
ResultHolder createBugResultHolder = JSON.parseObject(createBugContentAsString, ResultHolder.class);
StatisticsDTO createBugCount = JSON.parseObject(JSON.toJSONString(createBugResultHolder.getData()), StatisticsDTO.class);
Assertions.assertNotNull(createBugCount);
MvcResult handleBugMvcResult = this.requestPostWithOkAndReturn(HANDLE_BUG_BY_ME, dashboardFrontPageRequest);
String handleBugContentAsString = handleBugMvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
ResultHolder handleBugResultHolder = JSON.parseObject(handleBugContentAsString, ResultHolder.class);
StatisticsDTO handleBugCount = JSON.parseObject(JSON.toJSONString(handleBugResultHolder.getData()), StatisticsDTO.class);
Assertions.assertNotNull(handleBugCount);
Project project = new Project();
project.setModuleSetting("[]");
project.setId(DEFAULT_PROJECT_ID);
@ -329,6 +382,25 @@ public class DashboardFrontPageControllerTests extends BaseTest {
reviewResultHolder = JSON.parseObject(reviewContent, ResultHolder.class);
reviewCount = JSON.parseObject(JSON.toJSONString(reviewResultHolder.getData()), StatisticsDTO.class);
Assertions.assertNotNull(reviewCount);
bugMvcResult = this.requestPostWithOkAndReturn(BUG_COUNT, dashboardFrontPageRequest);
bugContentAsString = bugMvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
bugResultHolder = JSON.parseObject(bugContentAsString, ResultHolder.class);
bugCount = JSON.parseObject(JSON.toJSONString(bugResultHolder.getData()), StatisticsDTO.class);
Assertions.assertNotNull(bugCount);
createBugMvcResult = this.requestPostWithOkAndReturn(CREATE_BUG_BY_ME, dashboardFrontPageRequest);
createBugContentAsString = createBugMvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
createBugResultHolder = JSON.parseObject(createBugContentAsString, ResultHolder.class);
createBugCount = JSON.parseObject(JSON.toJSONString(createBugResultHolder.getData()), StatisticsDTO.class);
Assertions.assertNotNull(createBugCount);
handleBugMvcResult = this.requestPostWithOkAndReturn(HANDLE_BUG_BY_ME, dashboardFrontPageRequest);
handleBugContentAsString = handleBugMvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
handleBugResultHolder = JSON.parseObject(handleBugContentAsString, ResultHolder.class);
handleBugCount = JSON.parseObject(JSON.toJSONString(handleBugResultHolder.getData()), StatisticsDTO.class);
Assertions.assertNotNull(handleBugCount);
project.setModuleSetting("[\"apiTest\",\"testPlan\",\"caseManagement\",\"bugManagement\"]");
project.setId(DEFAULT_PROJECT_ID);
projectMapper.updateByPrimaryKeySelective(project);
@ -366,6 +438,23 @@ public class DashboardFrontPageControllerTests extends BaseTest {
reviewResultHolder = JSON.parseObject(reviewContent, ResultHolder.class);
reviewCount = JSON.parseObject(JSON.toJSONString(reviewResultHolder.getData()), StatisticsDTO.class);
Assertions.assertNotNull(reviewCount);
bugMvcResult = this.requestPostWithOkAndReturn(BUG_COUNT, dashboardFrontPageRequest);
bugContentAsString = bugMvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
bugResultHolder = JSON.parseObject(bugContentAsString, ResultHolder.class);
bugCount = JSON.parseObject(JSON.toJSONString(bugResultHolder.getData()), StatisticsDTO.class);
Assertions.assertNotNull(bugCount);
createBugMvcResult = this.requestPostWithOkAndReturn(CREATE_BUG_BY_ME, dashboardFrontPageRequest);
createBugContentAsString = createBugMvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
createBugResultHolder = JSON.parseObject(createBugContentAsString, ResultHolder.class);
createBugCount = JSON.parseObject(JSON.toJSONString(createBugResultHolder.getData()), StatisticsDTO.class);
Assertions.assertNotNull(createBugCount);
handleBugMvcResult = this.requestPostWithOkAndReturn(HANDLE_BUG_BY_ME, dashboardFrontPageRequest);
handleBugContentAsString = handleBugMvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
handleBugResultHolder = JSON.parseObject(handleBugContentAsString, ResultHolder.class);
handleBugCount = JSON.parseObject(JSON.toJSONString(handleBugResultHolder.getData()), StatisticsDTO.class);
Assertions.assertNotNull(handleBugCount);
}

View File

@ -62,13 +62,13 @@ INSERT INTO custom_field(id, name, scene, `type`, remark, internal, scope_type,
VALUES('gyq_custom_id1', 'functional_priority', 'FUNCTIONAL', 'SELECT', '', 1, 'ORGANIZATION', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'test_template_case_trash_id');
INSERT INTO bug (id, num, title, handle_users, handle_user, create_user, create_time,update_user, update_time, delete_user, delete_time, project_id, template_id, platform, status, tags, platform_bug_id, deleted, pos)
VALUES ('dashboard_bug1', 100001, 'oasis', 'admin', 'admin', 'admin', 1716185577387, 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, '100001100001', 'bug-template-id', 'Local', 'open', '["default-tag"]', null, 0, 5000);
VALUES ('dashboard_bug1', 100001, 'oasis', 'admin', 'admin', 'admin', 1697971947000, 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, '100001100001', 'bug-template-id', 'Local', 'open', '["default-tag"]', null, 0, 5000);
INSERT INTO bug (id, num, title, handle_users, handle_user, create_user, create_time,update_user, update_time, delete_user, delete_time, project_id, template_id, platform, status, tags, platform_bug_id, deleted, pos)
VALUES ('dashboard_bug2', 100002, 'oasis2', 'PROJECT', 'PROJECT', 'admin', 1716185577387, 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, '100001100001', 'bug-template-id', 'Local', 'open', '["default-tag"]', null, 0, 5000);
VALUES ('dashboard_bug2', 100002, 'oasis2', 'PROJECT', 'PROJECT', 'admin', 1697971947000, 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, '100001100001', 'bug-template-id', 'Local', 'open', '["default-tag"]', null, 0, 5000);
INSERT INTO bug (id, num, title, handle_users, handle_user, create_user, create_time,update_user, update_time, delete_user, delete_time, project_id, template_id, platform, status, tags, platform_bug_id, deleted, pos)
VALUES ('dashboard_bug3', 100003, 'oasis3', 'admin', 'admin', 'admin', 1716185577387, 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, '100001100001', 'bug-template-id', 'Local', 'open', '["default-tag"]', null, 0, 5000);
VALUES ('dashboard_bug3', 100003, 'oasis3', 'admin', 'admin', 'admin', 1697971947000, 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, '100001100001', 'bug-template-id', 'Local', 'open', '["default-tag"]', null, 0, 5000);
INSERT INTO api_definition(id, name, protocol, method, path, status, num, tags, pos, project_id, module_id, latest, version_id, ref_id, description, create_time, create_user, update_time, update_user, delete_user, delete_time, deleted)
VALUES ('dashboard_api_definition_id_1', 'gyq_associate_api_definition_id_1', 'HTTP', 'POST','api/test','DONE', 1000001, null, 1, '100001100001' , 'gyq_associate_test_module', true, 'v1.10','gyq_associate_api_definition_id_1', null, 1697971947000,'admin', 1697971947000,'admin', null,null,false);

View File

@ -81,4 +81,7 @@ public interface ExtTestPlanMapper {
@BaseConditionFilter
List<TestPlanResponse> selectMyFollowByConditions(@Param("request") TestPlanTableRequest request);
List<TestPlan> getSimpleTestPlanList(@Param("projectId") String projectId, @Param("startTime") Long startTime, @Param("endTime") Long endTime);
}

View File

@ -823,6 +823,17 @@
) t
</select>
<select id="getSimpleTestPlanList" resultType="io.metersphere.plan.domain.TestPlan">
SELECT test_plan.id, test_plan.status
FROM test_plan
WHERE test_plan.project_id = #{projectId}
<if test="startTime != null and endTime != null">
AND test_plan.create_time BETWEEN #{startTime} AND #{endTime}
</if>
</select>
<sql id="queryMyFollowGroupByTableRequest">
<include refid="baseConditionQuery"/>