diff --git a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestCaseMapper.java b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestCaseMapper.java index 7181b1fb24..5ed9e3a7fa 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestCaseMapper.java +++ b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestCaseMapper.java @@ -60,4 +60,16 @@ public interface ExtTestCaseMapper { long countCreatedThisWeek(@Param("projectId") String projectId, @Param("firstDayTimestamp") long firstDayTimestamp, @Param("lastDayTimestamp") long lastDayTimestamp); List countStatus(@Param("projectId") String projectId); + + List countRelevance(@Param("projectId") String projectId); + + long countRelevanceCreatedThisWeek(@Param("projectId") String projectId,@Param("firstDayTimestamp") long firstDayTimestamp, @Param("lastDayTimestamp") long lastDayTimestamp); + + List countCoverage(@Param("projectId") String projectId); + + List countFuncMaintainer(@Param("projectId") String projectId); + + List countRelevanceMaintainer(@Param("projectId") String projectId); + + } diff --git a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestCaseMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestCaseMapper.xml index ed890ad122..17d5c37a6e 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestCaseMapper.xml +++ b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestCaseMapper.xml @@ -328,9 +328,33 @@ SELECT count(id) AS countNumber FROM test_case WHERE test_case.project_id = #{projectId} AND create_time BETWEEN #{firstDayTimestamp} AND #{lastDayTimestamp} - + + + + + + + + + \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/track/controller/TrackController.java b/backend/src/main/java/io/metersphere/track/controller/TrackController.java index c3d2981b78..2b0d66bfb0 100644 --- a/backend/src/main/java/io/metersphere/track/controller/TrackController.java +++ b/backend/src/main/java/io/metersphere/track/controller/TrackController.java @@ -2,6 +2,8 @@ package io.metersphere.track.controller; import io.metersphere.commons.constants.RoleConstants; +import io.metersphere.performance.base.ChartsData; +import io.metersphere.track.response.BugStatustics; import io.metersphere.track.response.TrackCountResult; import io.metersphere.track.response.TrackStatisticsDTO; import io.metersphere.track.service.TrackService; @@ -50,4 +52,42 @@ public class TrackController { statistics.setP3CountStr("P3  

" + statistics.getP3CaseCountNumber()); return statistics; } + + @GetMapping("/relevance/count/{projectId}") + public TrackStatisticsDTO getRelevanceCount(@PathVariable String projectId) { + TrackStatisticsDTO statistics = new TrackStatisticsDTO(); + + List relevanceResults = trackService.countRelevance(projectId); + statistics.countRelevance(relevanceResults); + + long size = trackService.countRelevanceCreatedThisWeek(projectId); + statistics.setThisWeekAddedCount(size); + + List coverageResults = trackService.countCoverage(projectId); + statistics.countCoverage(coverageResults); + + long total = statistics.getUncoverageCount() + statistics.getCoverageCount(); + + if (total != 0) { + float coverageRageNumber = (float) statistics.getCoverageCount() * 100 / total; + DecimalFormat df = new DecimalFormat("0.0"); + statistics.setCoverageRage(df.format(coverageRageNumber) + "%"); + } + + statistics.setApiCaseCountStr("接口用例  

" + statistics.getApiCaseCount()); + statistics.setPerformanceCaseCountStr("性能用例  

" + statistics.getPerformanceCaseCount()); + statistics.setScenarioCaseStr("场景用例  

" + statistics.getScenarioCaseCount()); + + return statistics; + } + + @GetMapping("/case/bar/{projectId}") + public List getCaseMaintenanceBar(@PathVariable String projectId) { + return trackService.getCaseMaintenanceBar(projectId); + } + + @GetMapping("/bug/count/{projectId}") + public BugStatustics getBugStatustics(@PathVariable String projectId) { + return trackService.getBugStatustics(projectId); + } } diff --git a/backend/src/main/java/io/metersphere/track/request/testcase/CasePriority.java b/backend/src/main/java/io/metersphere/track/request/testcase/TrackCount.java similarity index 53% rename from backend/src/main/java/io/metersphere/track/request/testcase/CasePriority.java rename to backend/src/main/java/io/metersphere/track/request/testcase/TrackCount.java index e450b44945..b795deb9da 100644 --- a/backend/src/main/java/io/metersphere/track/request/testcase/CasePriority.java +++ b/backend/src/main/java/io/metersphere/track/request/testcase/TrackCount.java @@ -1,8 +1,12 @@ package io.metersphere.track.request.testcase; -public class CasePriority { +public class TrackCount { public static final String P0 = "P0"; public static final String P1 = "P1"; public static final String P2 = "P2"; public static final String P3 = "P3"; + + public static final String API = "api"; + public static final String PERFORMANCE = "performance"; + public static final String AUTOMATION = "automation"; } diff --git a/backend/src/main/java/io/metersphere/track/response/BugStatustics.java b/backend/src/main/java/io/metersphere/track/response/BugStatustics.java new file mode 100644 index 0000000000..863fa5f0fe --- /dev/null +++ b/backend/src/main/java/io/metersphere/track/response/BugStatustics.java @@ -0,0 +1,16 @@ +package io.metersphere.track.response; + +import lombok.Getter; +import lombok.Setter; + +import java.util.ArrayList; +import java.util.List; + +@Getter +@Setter +public class BugStatustics { + + private long bugTotalSize; + private String rage; + private List list = new ArrayList<>(); +} diff --git a/backend/src/main/java/io/metersphere/track/response/TestPlanBugCount.java b/backend/src/main/java/io/metersphere/track/response/TestPlanBugCount.java new file mode 100644 index 0000000000..4c8a75b272 --- /dev/null +++ b/backend/src/main/java/io/metersphere/track/response/TestPlanBugCount.java @@ -0,0 +1,16 @@ +package io.metersphere.track.response; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class TestPlanBugCount { + private int index; + private String planName; + private long creatTime; + private String status; + private int caseSize; + private int bugSize; + private String passRage; +} diff --git a/backend/src/main/java/io/metersphere/track/response/TrackStatisticsDTO.java b/backend/src/main/java/io/metersphere/track/response/TrackStatisticsDTO.java index 6b58ecd8b7..cb3aeffc88 100644 --- a/backend/src/main/java/io/metersphere/track/response/TrackStatisticsDTO.java +++ b/backend/src/main/java/io/metersphere/track/response/TrackStatisticsDTO.java @@ -1,7 +1,8 @@ package io.metersphere.track.response; +import io.metersphere.api.dto.datacount.ApiDataCountResult; import io.metersphere.commons.constants.TestReviewCaseStatus; -import io.metersphere.track.request.testcase.CasePriority; +import io.metersphere.track.request.testcase.TrackCount; import lombok.Getter; import lombok.Setter; @@ -47,7 +48,7 @@ public class TrackStatisticsDTO { /** * 关联用例数量统计 */ - private long relevanceCaseCount = 0; + private long allRelevanceCaseCount = 0; /** * 接口用例数量统计 @@ -110,16 +111,16 @@ public class TrackStatisticsDTO { public void countPriority(List trackCountResults) { for (TrackCountResult countResult : trackCountResults) { switch (countResult.getGroupField().toUpperCase()){ - case CasePriority.P0: + case TrackCount.P0: this.p0CaseCountNumber += countResult.getCountNumber(); break; - case CasePriority.P1: + case TrackCount.P1: this.p1CaseCountNumber += countResult.getCountNumber(); break; - case CasePriority.P2: + case TrackCount.P2: this.p2CaseCountNumber += countResult.getCountNumber(); break; - case CasePriority.P3: + case TrackCount.P3: this.p3CaseCountNumber += countResult.getCountNumber(); break; default: @@ -140,4 +141,33 @@ public class TrackStatisticsDTO { } } } + + public void countRelevance(List relevanceResults) { + for (TrackCountResult countResult : relevanceResults) { + switch (countResult.getGroupField().toUpperCase()){ + case TrackCount.API: + this.apiCaseCount += countResult.getCountNumber(); + break; + case TrackCount.PERFORMANCE: + this.performanceCaseCount += countResult.getCountNumber(); + break; + case TrackCount.AUTOMATION: + this.scenarioCaseCount += countResult.getCountNumber(); + break; + default: + break; + } + this.allRelevanceCaseCount += countResult.getCountNumber(); + } + } + + public void countCoverage(List coverageResults) { + for (TrackCountResult countResult : coverageResults) { + if("coverage".equals(countResult.getGroupField())){ + this.coverageCount+= countResult.getCountNumber(); + }else if("uncoverage".equals(countResult.getGroupField())){ + this.uncoverageCount+= countResult.getCountNumber(); + } + } + } } diff --git a/backend/src/main/java/io/metersphere/track/service/TrackService.java b/backend/src/main/java/io/metersphere/track/service/TrackService.java index 6cf219ec8b..b2a01371bd 100644 --- a/backend/src/main/java/io/metersphere/track/service/TrackService.java +++ b/backend/src/main/java/io/metersphere/track/service/TrackService.java @@ -1,14 +1,22 @@ package io.metersphere.track.service; +import io.metersphere.base.domain.*; +import io.metersphere.base.mapper.*; import io.metersphere.base.mapper.ext.ExtTestCaseMapper; import io.metersphere.commons.utils.DateUtils; +import io.metersphere.performance.base.ChartsData; +import io.metersphere.track.response.BugStatustics; +import io.metersphere.track.response.TestPlanBugCount; import io.metersphere.track.response.TrackCountResult; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; +import java.math.BigDecimal; +import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; @Service @Transactional(rollbackFor = Exception.class) @@ -16,6 +24,16 @@ public class TrackService { @Resource private ExtTestCaseMapper extTestCaseMapper; + @Resource + private TestPlanMapper testPlanMapper; + @Resource + private TestPlanTestCaseMapper testPlanTestCaseMapper; + @Resource + private TestPlanLoadCaseMapper testPlanLoadCaseMapper; + @Resource + private TestPlanApiCaseMapper testPlanApiCaseMapper; + @Resource + private TestPlanApiScenarioMapper testPlanApiScenarioMapper; public List countPriority(String projectId) { return extTestCaseMapper.countPriority(projectId); @@ -37,4 +55,114 @@ public class TrackService { public List countStatus(String projectId) { return extTestCaseMapper.countStatus(projectId); } + + public List countRelevance(String projectId) { + return extTestCaseMapper.countRelevance(projectId); + } + + public long countRelevanceCreatedThisWeek(String projectId) { + Map startAndEndDateInWeek = DateUtils.getWeedFirstTimeAndLastTime(new Date()); + + Date firstTime = startAndEndDateInWeek.get("firstTime"); + Date lastTime = startAndEndDateInWeek.get("lastTime"); + + if (firstTime == null || lastTime == null) { + return 0; + } else { + return extTestCaseMapper.countRelevanceCreatedThisWeek(projectId, firstTime.getTime(), lastTime.getTime()); + } + } + + public List countCoverage(String projectId) { + return extTestCaseMapper.countCoverage(projectId); + } + + public List getCaseMaintenanceBar(String projectId) { + List funcMaintainer = extTestCaseMapper.countFuncMaintainer(projectId); + List relevanceMaintainer = extTestCaseMapper.countRelevanceMaintainer(projectId); + List list = relevanceMaintainer.stream().map(TrackCountResult::getGroupField).collect(Collectors.toList()); + + List charts = new ArrayList<>(); + for (TrackCountResult result : funcMaintainer) { + String groupField = result.getGroupField(); + if (!list.contains(groupField)) { + // 创建了功能用例,但是未关联测试 + TrackCountResult trackCount = new TrackCountResult(); + trackCount.setCountNumber(0); + trackCount.setGroupField(groupField); + relevanceMaintainer.add(trackCount); + } + ChartsData chartsData = new ChartsData(); + chartsData.setxAxis(groupField); + chartsData.setyAxis(BigDecimal.valueOf(result.getCountNumber())); + chartsData.setGroupName("FUNCTIONCASE"); + charts.add(chartsData); + } + + for (TrackCountResult result : relevanceMaintainer) { + ChartsData chartsData = new ChartsData(); + chartsData.setxAxis(result.getGroupField()); + chartsData.setyAxis(BigDecimal.valueOf(result.getCountNumber())); + chartsData.setGroupName("RELEVANCECASE"); + charts.add(chartsData); + } + + return charts; + } + + public BugStatustics getBugStatustics(String projectId) { + TestPlanExample example = new TestPlanExample(); + example.createCriteria().andProjectIdEqualTo(projectId); + List plans = testPlanMapper.selectByExample(example); + List list = new ArrayList<>(); + BugStatustics bugStatustics = new BugStatustics(); + int index = 1; + for (TestPlan plan : plans) { + TestPlanBugCount testPlanBug = new TestPlanBugCount(); + testPlanBug.setIndex(index++); + testPlanBug.setPlanName(plan.getName()); + testPlanBug.setCreatTime(plan.getCreateTime()); + testPlanBug.setStatus(plan.getStatus()); + testPlanBug.setCaseSize(getPlanCaseSize(plan.getId())); + testPlanBug.setBugSize(getPlanBugSize(plan.getId())); + testPlanBug.setPassRage(getPlanPassRage(plan.getId())); + list.add(testPlanBug); + } + + // todo + bugStatustics.setList(list); + bugStatustics.setRage("1"); + bugStatustics.setBugTotalSize(2); + return bugStatustics; + } + + private int getPlanCaseSize(String planId) { + TestPlanTestCaseExample testPlanTestCaseExample = new TestPlanTestCaseExample(); + testPlanTestCaseExample.createCriteria().andPlanIdEqualTo(planId); + List testPlanTestCases = testPlanTestCaseMapper.selectByExample(testPlanTestCaseExample); + + TestPlanApiCaseExample testPlanApiCaseExample = new TestPlanApiCaseExample(); + testPlanApiCaseExample.createCriteria().andTestPlanIdEqualTo(planId); + List testPlanApiCases = testPlanApiCaseMapper.selectByExample(testPlanApiCaseExample); + + TestPlanLoadCaseExample example = new TestPlanLoadCaseExample(); + example.createCriteria().andTestPlanIdEqualTo(planId); + List testPlanLoadCases = testPlanLoadCaseMapper.selectByExample(example); + + TestPlanApiScenarioExample testPlanApiScenarioExample = new TestPlanApiScenarioExample(); + testPlanApiCaseExample.createCriteria().andTestPlanIdEqualTo(planId); + List testPlanApiScenarios = testPlanApiScenarioMapper.selectByExample(testPlanApiScenarioExample); + + + return testPlanTestCases.size() + testPlanApiCases.size() + testPlanLoadCases.size() + testPlanApiScenarios.size(); + + } + + private int getPlanBugSize(String planId) { + return 1; + } + + private String getPlanPassRage(String planId) { + return "10%"; + } } diff --git a/frontend/src/business/components/track/home/TrackHome.vue b/frontend/src/business/components/track/home/TrackHome.vue index dfb5f4aaee..1f0b14b7e8 100644 --- a/frontend/src/business/components/track/home/TrackHome.vue +++ b/frontend/src/business/components/track/home/TrackHome.vue @@ -34,13 +34,35 @@
- +
-
3
+
+ +
+ + + + + + + + + + + + + + + + + + + + @@ -52,20 +74,34 @@ import MsContainer from "@/business/components/common/components/MsContainer"; import CaseCountCard from "@/business/components/track/home/components/CaseCountCard"; import RelevanceCaseCard from "@/business/components/track/home/components/RelevanceCaseCard"; import {getCurrentProjectID} from "@/common/js/utils"; +import CaseMaintenance from "@/business/components/track/home/components/CaseMaintenance"; +import {COUNT_NUMBER, COUNT_NUMBER_SHALLOW} from "@/common/js/constants"; +import BugCountCard from "@/business/components/track/home/components/BugCountCard"; +import ReviewList from "@/business/components/track/home/components/ReviewList"; +import MsRunningTaskList from "@/business/components/api/homepage/components/RunningTaskList"; +import MsFailureTestCaseList from "@/business/components/api/homepage/components/FailureTestCaseList"; +require('echarts/lib/component/legend'); export default { name: "TrackHome", components: { + ReviewList, + BugCountCard, RelevanceCaseCard, CaseCountCard, MsMainContainer, - MsContainer + MsContainer, + CaseMaintenance, + MsRunningTaskList, + MsFailureTestCaseList }, data() { return { tipsType: "1", result: {}, - trackCountData: {} + trackCountData: {}, + relevanceCountData: {}, + caseOption: {} } }, activated() { @@ -79,9 +115,76 @@ export default { }, init() { let selectProjectId = getCurrentProjectID(); + this.$get("/track/count/" + selectProjectId, response => { this.trackCountData = response.data; }); + + this.$get("/track/relevance/count/" + selectProjectId, response => { + this.relevanceCountData = response.data; + }); + + this.$get("/track/case/bar/" + selectProjectId, response => { + let data = response.data; + this.setBarOption(data); + }) + }, + setBarOption(data) { + let xAxis = []; + data.map(d => { + if (!xAxis.includes(d.xAxis)) { + xAxis.push(d.xAxis); + } + }); + let yAxis1 = data.filter(d => d.groupName === 'FUNCTIONCASE').map(d => d.yAxis); + let yAxis2 = data.filter(d => d.groupName === 'RELEVANCECASE').map(d => d.yAxis); + let option = { + tooltip: { + trigger: 'axis', + axisPointer: { + type: 'shadow' + } + }, + xAxis: { + type: 'category', + data: xAxis + }, + yAxis: { + type: 'value', + axisLine: { + show: false + }, + axisTick: { + show: false + } + }, + legend: { + data: ["功能用例数", "关联用例数"], + orient: 'vertical', + right: '80', + }, + series: [{ + name: "功能用例数", + data: yAxis1, + type: 'bar', + itemStyle: { + normal: { + color: COUNT_NUMBER + } + } + }, + { + name: "关联用例数", + data: yAxis2, + type: 'bar', + itemStyle: { + normal: { + color: COUNT_NUMBER_SHALLOW + } + } + }] + }; + this.caseOption = option; } } @@ -90,13 +193,11 @@ export default { diff --git a/frontend/src/business/components/track/home/components/CaseCountCard.vue b/frontend/src/business/components/track/home/components/CaseCountCard.vue index b70cf1c8f2..b1caeed243 100644 --- a/frontend/src/business/components/track/home/components/CaseCountCard.vue +++ b/frontend/src/business/components/track/home/components/CaseCountCard.vue @@ -68,7 +68,7 @@ - {{$t('api_test.home_page.detail_card.rate.completion')+":"}} + 评审率: diff --git a/frontend/src/business/components/track/home/components/CaseMaintenance.vue b/frontend/src/business/components/track/home/components/CaseMaintenance.vue new file mode 100644 index 0000000000..8cbb6f1121 --- /dev/null +++ b/frontend/src/business/components/track/home/components/CaseMaintenance.vue @@ -0,0 +1,41 @@ + + + + + diff --git a/frontend/src/business/components/track/home/components/RelevanceCaseCard.vue b/frontend/src/business/components/track/home/components/RelevanceCaseCard.vue index ec437a0472..d82ef603af 100644 --- a/frontend/src/business/components/track/home/components/RelevanceCaseCard.vue +++ b/frontend/src/business/components/track/home/components/RelevanceCaseCard.vue @@ -2,7 +2,7 @@
- 用例数量统计 + 关联用例数量统计
@@ -10,7 +10,7 @@
- {{caseCountData}} + {{relevanceCountData.allRelevanceCaseCount}} {{$t('api_test.home_page.unit_of_measurement')}} @@ -18,34 +18,17 @@
-
+
- - -
+ + +
- -
+ +
- -
-
- -
-
-
- - -
-
- -
-
- -
-
- -
+ +
@@ -57,7 +40,7 @@ {{$t('api_test.home_page.api_details_card.this_week_add')}} - {{caseCountData}} + {{relevanceCountData.thisWeekAddedCount}} {{$t('api_test.home_page.unit_of_measurement')}} @@ -68,11 +51,11 @@ - {{$t('api_test.home_page.detail_card.rate.completion')+":"}} + 覆盖率: - {{caseCountData}} + {{relevanceCountData.coverageRage}} @@ -83,28 +66,19 @@ - {{$t('api_test.home_page.detail_card.running')}} + 未覆盖 {{"\xa0\xa0"}} - {{caseCountData}} - - - - - - {{$t('api_test.home_page.detail_card.not_started')}} - {{"\xa0\xa0"}} - - {{caseCountData}} + {{relevanceCountData.uncoverageCount}} - {{$t('api_test.home_page.detail_card.finished')}} + 已覆盖 {{"\xa0\xa0"}} - - {{caseCountData}} + + {{relevanceCountData.coverageCount}} @@ -122,7 +96,7 @@ export default { name: "RelevanceCaseCard", props:{ - caseCountData:{}, + relevanceCountData:{}, }, data() { return { diff --git a/frontend/src/business/components/track/home/components/ReviewList.vue b/frontend/src/business/components/track/home/components/ReviewList.vue index 5ec3b49d47..b46bb93d01 100644 --- a/frontend/src/business/components/track/home/components/ReviewList.vue +++ b/frontend/src/business/components/track/home/components/ReviewList.vue @@ -1,14 +1,14 @@