diff --git a/backend/src/main/java/io/metersphere/api/controller/APITestController.java b/backend/src/main/java/io/metersphere/api/controller/APITestController.java index 229d0f7fdf..5589a4cd67 100644 --- a/backend/src/main/java/io/metersphere/api/controller/APITestController.java +++ b/backend/src/main/java/io/metersphere/api/controller/APITestController.java @@ -3,6 +3,12 @@ package io.metersphere.api.controller; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import io.metersphere.api.dto.*; +import io.metersphere.api.dto.dataCount.ApiDataCountResult; +import io.metersphere.api.dto.dataCount.ExecutedCaseInfoResult; +import io.metersphere.api.dto.dataCount.request.ScheduleInfoRequest; +import io.metersphere.api.dto.dataCount.response.ApiDataCountDTO; +import io.metersphere.api.dto.dataCount.response.ExecutedCaseInfoDTO; +import io.metersphere.api.dto.dataCount.response.TaskInfoResult; import io.metersphere.api.dto.scenario.request.dubbo.RegistryCenter; import io.metersphere.api.service.*; import io.metersphere.base.domain.ApiTest; @@ -166,4 +172,126 @@ public class APITestController { public List getJsonPaths(@RequestBody QueryJsonPathRequest request) { return getListJson(request.getJsonPath()); } + + @GetMapping("/apiCount/{projectId}") + public ApiDataCountDTO apiCount(@PathVariable String projectId) { + + ApiDataCountDTO apiCountResult = new ApiDataCountDTO(); + + List countResultList = apiDefinitionService.countProtocolByProjectID(projectId); + apiCountResult.countByApiDefinitionCountResult(countResultList); + + long dateCountByCreateInThisWeek = apiDefinitionService.countByProjectIDAndCreateInThisWeek(projectId); + apiCountResult.setThisWeekAddedCount(dateCountByCreateInThisWeek); + + return apiCountResult; + } + + @GetMapping("/testCaseInfoCount/{projectId}") + public ApiDataCountDTO testCaseInfoCount(@PathVariable String projectId) { + ApiDataCountDTO apiCountResult = new ApiDataCountDTO(); + + List countResultList = apiTestCaseService.countProtocolByProjectID(projectId); + apiCountResult.countByApiDefinitionCountResult(countResultList); + + long dateCountByCreateInThisWeek = apiTestCaseService.countByProjectIDAndCreateInThisWeek(projectId); + apiCountResult.setThisWeekAddedCount(dateCountByCreateInThisWeek); + + long executedInThisWeekCountNumber = apiDefinitionExecResultService.countByTestCaseIDInProjectAndExecutedInThisWeek(projectId); + apiCountResult.setThisWeekExecutedCount(executedInThisWeekCountNumber); + long executedCountNumber = apiDefinitionExecResultService.countByTestCaseIDInProject(projectId); + apiCountResult.setExecutedCount(executedCountNumber); + + return apiCountResult; + } + + @GetMapping("/testSceneInfoCount/{projectId}") + public ApiDataCountDTO testSceneInfoCount(@PathVariable String projectId) { + + ApiDataCountDTO apiCountResult = new ApiDataCountDTO(); + + long scenarioCountNumber = apiAutomationService.countScenarioByProjectID(projectId); + apiCountResult.setAllApiDataCountNumber(scenarioCountNumber); + + /** + * 本周新增:通过测试场景的createTime + * 本周执行: 查询(本周)生成的测试报告 + * 历史总执行:查询所有的测试报告 + * */ + long dateCountByCreateInThisWeek = apiAutomationService.countScenarioByProjectIDAndCreatInThisWeek(projectId); + apiCountResult.setThisWeekAddedCount(dateCountByCreateInThisWeek); + long executedInThisWeekCountNumber = apiScenarioReportService.countByProjectIDAndCreateInThisWeek(projectId); + apiCountResult.setThisWeekExecutedCount(executedInThisWeekCountNumber); + long executedCountNumber = apiScenarioReportService.countByProjectID(projectId); + apiCountResult.setExecutedCount(executedCountNumber); + + return apiCountResult; + + } + + @GetMapping("/scheduleTaskInfoCount/{workSpaceID}") + public ApiDataCountDTO scheduleTaskInfoCount(@PathVariable String workSpaceID) { + ApiDataCountDTO apiCountResult = new ApiDataCountDTO(); + + long allTaskCount = scheduleService.countTaskByWorkspaceIdAndGroup(workSpaceID,ScheduleGroup.API_TEST.name()); + + apiCountResult.setAllApiDataCountNumber(allTaskCount); + + long taskCountInThisWeek = scheduleService.countTaskByWorkspaceIdAndGroupInThisWeek(workSpaceID,ScheduleGroup.API_TEST.name()); + apiCountResult.setThisWeekAddedCount(taskCountInThisWeek); + long executedInThisWeekCountNumber = apiReportService.countByWorkspaceIdAndGroupAndCreateInThisWeek(workSpaceID,ScheduleGroup.API_TEST.name()); + apiCountResult.setThisWeekExecutedCount(executedInThisWeekCountNumber); + long executedCountNumber = apiReportService.countByWorkspaceIdAndGroup(workSpaceID,ScheduleGroup.API_TEST.name()); + apiCountResult.setExecutedCount(executedCountNumber); + + return apiCountResult; + } + + @GetMapping("/faliureCaseAboutTestPlan/{projectId}/{limitNumber}") + public List faliureCaseAboutTestPlan(@PathVariable String projectId, @PathVariable int limitNumber) { + + List selectDataList = apiDefinitionExecResultService.findFaliureCaseInfoByProjectIDAndLimitNumberInSevenDays(projectId,limitNumber); + + List returnList = new ArrayList<>(limitNumber); + + for(int dataIndex = 0;dataIndex < limitNumber;dataIndex ++){ + + ExecutedCaseInfoDTO dataDTO = new ExecutedCaseInfoDTO(); + dataDTO.setSortIndex(dataIndex+1); + + if(dataIndex runningTask(@PathVariable String workspaceID) { + + List resultList = scheduleService.findRunningTaskInfoByWorkspaceID(workspaceID); + for (TaskInfoResult taskInfo : + resultList) { + Date nextExecutionTime = CronUtils.getNextTriggerTime(taskInfo.getRule()); + if(nextExecutionTime!=null){ + taskInfo.setNextExecutionTime(nextExecutionTime.getTime()); + } + } + return resultList; + } + + @PostMapping(value = "/schedule/updateEnableByPrimyKey") + public void updateScheduleEnableByPrimyKey(@RequestBody ScheduleInfoRequest request) { + Schedule schedule = scheduleService.getSchedule(request.getTaskID()); + schedule.setEnable(request.isEnable()); + apiTestService.updateSchedule(schedule); + } } diff --git a/backend/src/main/java/io/metersphere/api/dto/dataCount/ApiDataCountResult.java b/backend/src/main/java/io/metersphere/api/dto/dataCount/ApiDataCountResult.java new file mode 100644 index 0000000000..7a1307bbc9 --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dto/dataCount/ApiDataCountResult.java @@ -0,0 +1,16 @@ +package io.metersphere.api.dto.dataCount; + +import lombok.Getter; +import lombok.Setter; + +/** + * API数据统计查询结果类 + */ +@Getter +@Setter +public class ApiDataCountResult { + //分组统计字段 + private String groupField; + //数据统计 + private long countNumber; +} diff --git a/backend/src/main/java/io/metersphere/api/dto/dataCount/response/ApiDataCountDTO.java b/backend/src/main/java/io/metersphere/api/dto/dataCount/response/ApiDataCountDTO.java new file mode 100644 index 0000000000..657f03f4aa --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dto/dataCount/response/ApiDataCountDTO.java @@ -0,0 +1,65 @@ +package io.metersphere.api.dto.dataCount.response; + +import io.metersphere.api.dto.dataCount.ApiDataCountResult; +import io.metersphere.api.dto.scenario.request.RequestType; +import io.metersphere.base.domain.ApiDefinition; +import lombok.Getter; +import lombok.Setter; + +import java.util.List; +import java.util.Locale; + +/** + * 接口数据统计返回 + */ +@Getter +@Setter +public class ApiDataCountDTO { + + //接口统计 + private long allApiDataCountNumber = 0; + //http接口统计 + private long httpApiDataCountNumber = 0; + //rpc接口统计 + private long rpcApiDataCountNumber = 0; + //tcp接口统计 + private long tcpApiDataCountNumber = 0; + //sql接口统计 + private long sqlApiDataCountNumber = 0; + + //本周新增数量 + private long thisWeekAddedCount = 0; + //本周执行数量 + private long thisWeekExecutedCount = 0; + //历史总执行数量 + private long executedCount = 0; + + public ApiDataCountDTO(){} + + /** + * 通过ApiDefinitionCountResult统计查询结果进行数据合计 + * @param countResultList + */ + public void countByApiDefinitionCountResult(List countResultList){ + for (ApiDataCountResult countResult : + countResultList) { + switch (countResult.getGroupField().toUpperCase()){ + case RequestType.DUBBO: + this.rpcApiDataCountNumber += countResult.getCountNumber(); + break; + case RequestType.HTTP: + this.httpApiDataCountNumber += countResult.getCountNumber(); + break; + case RequestType.SQL: + this.sqlApiDataCountNumber += countResult.getCountNumber(); + break; + case RequestType.TCP: + this.tcpApiDataCountNumber += countResult.getCountNumber(); + break; + default: + break; + } + allApiDataCountNumber += countResult.getCountNumber(); + } + } +} diff --git a/backend/src/main/java/io/metersphere/api/dto/dataCount/response/TaskInfoResult.java b/backend/src/main/java/io/metersphere/api/dto/dataCount/response/TaskInfoResult.java new file mode 100644 index 0000000000..d1a8d0fa36 --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dto/dataCount/response/TaskInfoResult.java @@ -0,0 +1,30 @@ +package io.metersphere.api.dto.dataCount.response; + +import lombok.Getter; +import lombok.Setter; +import org.python.antlr.ast.Str; + +/** + * 任务信息 返回DTO + */ +@Getter +@Setter +public class TaskInfoResult { + //序号 + private int index; + //任务ID + private String taskID; + //场景名称 + private String scenario; + //规则 + private String rule; + //任务状态 + private boolean taskStatus; + //下次执行时间 + private Long nextExecutionTime; + //创建人 + private String creator; + //更新时间 + private Long updateTime; + +} diff --git a/backend/src/main/java/io/metersphere/api/service/APITestService.java b/backend/src/main/java/io/metersphere/api/service/APITestService.java index 23ae3400e9..de4c878c17 100644 --- a/backend/src/main/java/io/metersphere/api/service/APITestService.java +++ b/backend/src/main/java/io/metersphere/api/service/APITestService.java @@ -4,6 +4,7 @@ import com.alibaba.fastjson.JSONObject; import com.alibaba.nacos.client.utils.StringUtils; import io.github.ningyu.jmeter.plugin.dubbo.sample.ProviderService; import io.metersphere.api.dto.*; +import io.metersphere.api.dto.dataCount.ApiDataCountResult; import io.metersphere.api.dto.parse.ApiImport; import io.metersphere.api.dto.scenario.request.dubbo.RegistryCenter; import io.metersphere.api.jmeter.JMeterService; diff --git a/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java b/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java index ad04dbc5fd..6754ff285a 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java @@ -22,6 +22,7 @@ import io.metersphere.commons.constants.APITestStatus; import io.metersphere.commons.constants.ApiRunMode; import io.metersphere.commons.constants.ReportTriggerMode; import io.metersphere.commons.exception.MSException; +import io.metersphere.commons.utils.DateUtils; import io.metersphere.commons.utils.ServiceUtils; import io.metersphere.commons.utils.SessionUtils; import io.metersphere.i18n.Translator; @@ -355,4 +356,20 @@ public class ApiAutomationService { return "success"; } + public long countScenarioByProjectID(String projectId) { + return apiScenarioMapper.countByProjectID(projectId); + } + + public long countScenarioByProjectIDAndCreatInThisWeek(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 apiScenarioMapper.countByProjectIDAndCreatInThisWeek(projectId,firstTime.getTime(),lastTime.getTime()); + } + } } diff --git a/backend/src/main/java/io/metersphere/api/service/ApiDefinitionExecResultService.java b/backend/src/main/java/io/metersphere/api/service/ApiDefinitionExecResultService.java index 0df58b52ea..2319ed60c7 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiDefinitionExecResultService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiDefinitionExecResultService.java @@ -1,6 +1,7 @@ package io.metersphere.api.service; import com.alibaba.fastjson.JSON; +import io.metersphere.api.dto.dataCount.ExecutedCaseInfoResult; import io.metersphere.api.jmeter.TestResult; import io.metersphere.base.domain.ApiDefinitionExecResult; import io.metersphere.base.mapper.ApiDefinitionExecResultMapper; @@ -11,8 +12,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; -import java.util.Objects; -import java.util.UUID; +import java.util.*; @Service @Transactional(rollbackFor = Exception.class) @@ -39,4 +39,40 @@ public class ApiDefinitionExecResultService { apiDefinitionExecResultMapper.insert(saveResult); }); } + + public long countByTestCaseIDInProjectAndExecutedInThisWeek(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 apiDefinitionExecResultMapper.countByProjectIDAndCreateInThisWeek(projectId,firstTime.getTime(),lastTime.getTime()); + } + } + + public long countByTestCaseIDInProject(String projectId) { + return apiDefinitionExecResultMapper.countByTestCaseIDInProject(projectId); + + } + + public List findFaliureCaseInfoByProjectIDAndLimitNumberInSevenDays(String projectId, int limitNumber) { + + //获取7天之前的日期 + Date startDay = DateUtils.dateSum(new Date(),-6); + //将日期转化为 00:00:00 的时间戳 + Date startTime = null; + try{ + startTime = DateUtils.getDayStartTime(startDay); + }catch (Exception e){ + } + + if(startTime==null){ + return new ArrayList<>(0); + }else { + return apiDefinitionExecResultMapper.findFaliureCaseInfoByProjectIDAndExecuteTimeAndLimitNumber(projectId,startTime.getTime(),limitNumber); + } + } } diff --git a/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java b/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java index 6b1fa87426..9cf994d6a7 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java @@ -6,6 +6,7 @@ import io.metersphere.api.dto.APIReportResult; import io.metersphere.api.dto.ApiTestImportRequest; import io.metersphere.api.dto.automation.ApiScenarioRequest; import io.metersphere.api.dto.automation.ReferenceDTO; +import io.metersphere.api.dto.dataCount.ApiDataCountResult; import io.metersphere.api.dto.definition.*; import io.metersphere.api.dto.definition.parse.ApiDefinitionImport; import io.metersphere.api.dto.scenario.request.RequestType; @@ -23,10 +24,7 @@ import io.metersphere.base.mapper.ext.ExtTestPlanMapper; import io.metersphere.commons.constants.APITestStatus; import io.metersphere.commons.constants.ApiRunMode; import io.metersphere.commons.exception.MSException; -import io.metersphere.commons.utils.BeanUtils; -import io.metersphere.commons.utils.LogUtil; -import io.metersphere.commons.utils.ServiceUtils; -import io.metersphere.commons.utils.SessionUtils; +import io.metersphere.commons.utils.*; import io.metersphere.i18n.Translator; import io.metersphere.service.FileService; import io.metersphere.track.request.testcase.QueryTestPlanRequest; @@ -43,10 +41,7 @@ import sun.security.util.Cache; import javax.annotation.Resource; import java.io.*; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Objects; +import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; @@ -388,4 +383,30 @@ public class ApiDefinitionService { apiDefinitionMapper.updateByExampleSelective(definitionWithBLOBs, definitionExample); } + /** + * 数据统计-接口类型 + * @param projectId 项目ID + * @return + */ + public List countProtocolByProjectID(String projectId) { + return apiDefinitionMapper.countProtocolByProjectID(projectId); + } + + /** + * 统计本周创建的数据总量 + * @param projectId + * @return + */ + public long countByProjectIDAndCreateInThisWeek(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 apiDefinitionMapper.countByProjectIDAndCreateInThisWeek(projectId,firstTime.getTime(),lastTime.getTime()); + } + } } diff --git a/backend/src/main/java/io/metersphere/api/service/ApiScenarioReportService.java b/backend/src/main/java/io/metersphere/api/service/ApiScenarioReportService.java index ee3fc6b221..a54b737d53 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiScenarioReportService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiScenarioReportService.java @@ -14,6 +14,7 @@ import io.metersphere.base.mapper.ApiScenarioReportMapper; import io.metersphere.base.mapper.ext.ExtApiScenarioReportMapper; import io.metersphere.commons.constants.APITestStatus; import io.metersphere.commons.exception.MSException; +import io.metersphere.commons.utils.DateUtils; import io.metersphere.commons.utils.ServiceUtils; import io.metersphere.i18n.Translator; import org.apache.commons.lang3.StringUtils; @@ -24,7 +25,9 @@ import sun.security.util.Cache; import javax.annotation.Resource; import java.nio.charset.StandardCharsets; import java.text.DecimalFormat; +import java.util.Date; import java.util.List; +import java.util.Map; import java.util.UUID; @Service @@ -205,4 +208,20 @@ public class ApiScenarioReportService { apiScenarioReportMapper.deleteByExample(apiTestReportExample); } + public long countByProjectID(String projectId) { + return apiScenarioReportMapper.countByProjectID(projectId); + } + + public long countByProjectIDAndCreateInThisWeek(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 apiScenarioReportMapper.countByProjectIDAndCreateInThisWeek(projectId,firstTime.getTime(),lastTime.getTime()); + } + } } diff --git a/backend/src/main/java/io/metersphere/api/service/ApiTestCaseService.java b/backend/src/main/java/io/metersphere/api/service/ApiTestCaseService.java index 09cb797a07..c3a9cca804 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiTestCaseService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiTestCaseService.java @@ -1,6 +1,10 @@ package io.metersphere.api.service; import com.alibaba.fastjson.JSONObject; +import io.metersphere.api.dto.dataCount.ApiDataCountResult; +import io.metersphere.api.dto.definition.ApiTestCaseRequest; +import io.metersphere.api.dto.definition.ApiTestCaseResult; +import io.metersphere.api.dto.definition.SaveApiTestCaseRequest; import io.metersphere.api.dto.ApiCaseBatchRequest; import io.metersphere.api.dto.definition.*; import io.metersphere.base.domain.*; @@ -243,4 +247,22 @@ public class ApiTestCaseService { example.createCriteria().andIdIn(ids); apiTestCaseMapper.deleteByExample(example); } + + public List countProtocolByProjectID(String projectId) { + return apiTestCaseMapper.countProtocolByProjectID(projectId); + } + + public long countByProjectIDAndCreateInThisWeek(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 apiTestCaseMapper.countByProjectIDAndCreateInThisWeek(projectId,firstTime.getTime(),lastTime.getTime()); + } + } + } diff --git a/backend/src/main/java/io/metersphere/base/mapper/ApiDefinitionExecResultMapper.java b/backend/src/main/java/io/metersphere/base/mapper/ApiDefinitionExecResultMapper.java index 7e4d7c5a93..d29f447b44 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ApiDefinitionExecResultMapper.java +++ b/backend/src/main/java/io/metersphere/base/mapper/ApiDefinitionExecResultMapper.java @@ -1,8 +1,10 @@ package io.metersphere.base.mapper; +import io.metersphere.api.dto.dataCount.ExecutedCaseInfoResult; import io.metersphere.base.domain.ApiDefinitionExecResult; import io.metersphere.base.domain.ApiDefinitionExecResultExample; import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; import java.util.List; @@ -34,4 +36,42 @@ public interface ApiDefinitionExecResultMapper { int updateByPrimaryKeyWithBLOBs(ApiDefinitionExecResult record); int updateByPrimaryKey(ApiDefinitionExecResult record); + + @Select({ + "SELECT count(id) AS countNumber FROM api_definition_exec_result ", + "WHERE resource_id IN ( ", + "SELECT testCase.id FROM api_test_case testCase ", + "WHERE testCase.project_id = #{projectId}) ", + "and start_time BETWEEN #{firstDayTimestamp} AND #{lastDayTimestamp} " + }) + long countByProjectIDAndCreateInThisWeek(@Param("projectId") String projectId, @Param("firstDayTimestamp") long firstDayTimestamp, @Param("lastDayTimestamp") long lastDayTimestamp); + + @Select({ + "SELECT count(id) AS countNumber FROM api_definition_exec_result ", + "WHERE resource_id IN ( ", + "SELECT testCase.id FROM api_test_case testCase ", + "WHERE testCase.project_id = #{projectId}) ", + }) + long countByTestCaseIDInProject(String projectId); + +// AS testPlan FROM ( SELECT apiCase.id AS testCaseID,apiCase.`name` AS testCaseNa' at line 1 + + @Select({ + "SELECT testCase.testCaseName AS caseName,testCase.testPlanName AS testPlan ,caseErrorCountData.dataCountNumber AS failureTimes FROM ( ", + "SELECT apiCase.id AS testCaseID,apiCase.`name` AS testCaseName,group_concat(testPlan.`name`) AS testPlanName FROM api_test_case apiCase ", + "LEFT JOIN test_plan testPlan ON testPlan.api_ids like concat('%\"',apiCase.id,'\"%') ", + "GROUP BY apiCase.id ", + "ORDER BY apiCase.create_time DESC ", + ")testCase ", + "INNER JOIN ( ", + "SELECT resource_id AS testCaseID,COUNT(id) AS dataCountNumber,start_time AS executeTime FROM api_definition_exec_result ", + "WHERE resource_id IN ( ", + "SELECT id FROM api_test_case WHERE project_id = #{projectId} ", + ") and `status` = 'error' GROUP BY resource_id ", + ") caseErrorCountData ON caseErrorCountData.testCaseID =testCase.testCaseID ", + "WHERE caseErrorCountData.executeTime >= #{startTimestamp} ", + "ORDER BY caseErrorCountData.dataCountNumber DESC ", + "limit #{limitNumber} " + }) + List findFaliureCaseInfoByProjectIDAndExecuteTimeAndLimitNumber(@Param("projectId") String projectId, @Param("startTimestamp") long startTimestamp, @Param("limitNumber") int limitNumber); } \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/base/mapper/ApiDefinitionMapper.java b/backend/src/main/java/io/metersphere/base/mapper/ApiDefinitionMapper.java index 39ffaa1c22..76d0976d58 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ApiDefinitionMapper.java +++ b/backend/src/main/java/io/metersphere/base/mapper/ApiDefinitionMapper.java @@ -1,9 +1,12 @@ package io.metersphere.base.mapper; +import io.metersphere.api.dto.dataCount.ApiDataCountResult; +import io.metersphere.api.dto.dataCount.response.ApiDataCountDTO; import io.metersphere.base.domain.ApiDefinition; import io.metersphere.base.domain.ApiDefinitionExample; import io.metersphere.base.domain.ApiDefinitionWithBLOBs; import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; import java.util.List; @@ -35,4 +38,14 @@ public interface ApiDefinitionMapper { int updateByPrimaryKeyWithBLOBs(ApiDefinitionWithBLOBs record); int updateByPrimaryKey(ApiDefinition record); + + @Select("SELECT protocol AS groupField,count(id) AS countNumber FROM api_definition WHERE project_id = #{0} GROUP BY protocol;") + List countProtocolByProjectID(String projectId); + + @Select({ + "SELECT count(id) AS countNumber FROM api_definition ", + "WHERE project_id = #{projectId} ", + "AND create_time BETWEEN #{firstDayTimestamp} AND #{lastDayTimestamp} " + }) + long countByProjectIDAndCreateInThisWeek(@Param("projectId") String projectId, @Param("firstDayTimestamp") long firstDayTimestamp, @Param("lastDayTimestamp") long lastDayTimestamp); } \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/base/mapper/ApiScenarioMapper.java b/backend/src/main/java/io/metersphere/base/mapper/ApiScenarioMapper.java index 340b205de8..feb0626eb3 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ApiScenarioMapper.java +++ b/backend/src/main/java/io/metersphere/base/mapper/ApiScenarioMapper.java @@ -4,6 +4,7 @@ import io.metersphere.base.domain.ApiScenario; import io.metersphere.base.domain.ApiScenarioExample; import java.util.List; import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; public interface ApiScenarioMapper { long countByExample(ApiScenarioExample example); @@ -33,4 +34,14 @@ public interface ApiScenarioMapper { int updateByPrimaryKeyWithBLOBs(ApiScenario record); int updateByPrimaryKey(ApiScenario record); + + @Select("SELECT COUNT(id) AS countNumber FROM api_scenario WHERE project_id = #{0} ") + long countByProjectID(String projectId); + + @Select({ + "SELECT count(id) AS countNumber FROM api_scenario ", + "WHERE project_id = #{projectId} ", + "AND create_time BETWEEN #{firstDayTimestamp} AND #{lastDayTimestamp} " + }) + long countByProjectIDAndCreatInThisWeek(@Param("projectId") String projectId, @Param("firstDayTimestamp") long firstDayTimestamp, @Param("lastDayTimestamp") long lastDayTimestamp); } \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/base/mapper/ApiScenarioReportMapper.java b/backend/src/main/java/io/metersphere/base/mapper/ApiScenarioReportMapper.java index b8315a5d3a..ff97d54230 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ApiScenarioReportMapper.java +++ b/backend/src/main/java/io/metersphere/base/mapper/ApiScenarioReportMapper.java @@ -4,6 +4,7 @@ import io.metersphere.base.domain.ApiScenarioReport; import io.metersphere.base.domain.ApiScenarioReportExample; import java.util.List; import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; public interface ApiScenarioReportMapper { long countByExample(ApiScenarioReportExample example); @@ -27,4 +28,14 @@ public interface ApiScenarioReportMapper { int updateByPrimaryKeySelective(ApiScenarioReport record); int updateByPrimaryKey(ApiScenarioReport record); + + @Select("SELECT count(id) AS countNumber FROM api_scenario_report WHERE project_id = #{0} ") + long countByProjectID(String projectId); + + @Select({ + "SELECT count(id) AS countNumber FROM api_scenario_report ", + "WHERE project_id = #{projectId} ", + "AND create_time BETWEEN #{firstDayTimestamp} AND #{lastDayTimestamp} " + }) + long countByProjectIDAndCreateInThisWeek(@Param("projectId") String projectId, @Param("firstDayTimestamp") long firstDayTimestamp, @Param("lastDayTimestamp") long lastDayTimestamp); } \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/base/mapper/ApiTestCaseMapper.java b/backend/src/main/java/io/metersphere/base/mapper/ApiTestCaseMapper.java index a4935f22a7..56a7c31802 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ApiTestCaseMapper.java +++ b/backend/src/main/java/io/metersphere/base/mapper/ApiTestCaseMapper.java @@ -1,9 +1,11 @@ package io.metersphere.base.mapper; +import io.metersphere.api.dto.dataCount.ApiDataCountResult; import io.metersphere.base.domain.ApiTestCase; import io.metersphere.base.domain.ApiTestCaseExample; import io.metersphere.base.domain.ApiTestCaseWithBLOBs; import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; import java.util.List; @@ -35,4 +37,20 @@ public interface ApiTestCaseMapper { int updateByPrimaryKeyWithBLOBs(ApiTestCaseWithBLOBs record); int updateByPrimaryKey(ApiTestCase record); + + @Select({ + "SELECT apiDef.protocol AS groupField,COUNT(testCase.id) AS countNumber FROM api_test_case testCase ", + "INNER JOIN api_definition apiDef ON testCase.api_definition_id = apiDef.id ", + "WHERE testCase.project_id = #{0} ", + "GROUP BY apiDef.protocol " + }) + List countProtocolByProjectID(String projectId); + + @Select({ + "SELECT count(testCase.id) AS countNumber FROM api_test_case testCase ", + "INNER JOIN api_definition apiDef ON testCase.api_definition_id = apiDef.id ", + "WHERE testCase.project_id = #{projectId} ", + "AND testCase.create_time BETWEEN #{firstDayTimestamp} AND #{lastDayTimestamp} " + }) + long countByProjectIDAndCreateInThisWeek(@Param("projectId") String projectId, @Param("firstDayTimestamp") long firstDayTimestamp, @Param("lastDayTimestamp") long lastDayTimestamp); } \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/commons/utils/DateUtils.java b/backend/src/main/java/io/metersphere/commons/utils/DateUtils.java new file mode 100644 index 0000000000..1b09b18f24 --- /dev/null +++ b/backend/src/main/java/io/metersphere/commons/utils/DateUtils.java @@ -0,0 +1,121 @@ +package io.metersphere.commons.utils; + +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + + +public class DateUtils { + public static final String DATE_PATTERM = "yyyy-MM-dd"; + public static final String TIME_PATTERN = "yyyy-MM-dd HH:mm:ss"; + + + public static Date getDate(String dateString) throws Exception { + SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_PATTERM); + return dateFormat.parse(dateString); + } + public static Date getTime(String timeString) throws Exception { + SimpleDateFormat dateFormat = new SimpleDateFormat(TIME_PATTERN); + return dateFormat.parse(timeString); + } + + public static String getDateString(Date date) throws Exception { + SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_PATTERM); + return dateFormat.format(date); + } + + public static String getDateString(long timeStamp) throws Exception { + SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_PATTERM); + return dateFormat.format(timeStamp); + } + + public static String getTimeString(Date date) throws Exception { + SimpleDateFormat dateFormat = new SimpleDateFormat(TIME_PATTERN); + return dateFormat.format(date); + } + + public static String getTimeString(long timeStamp) throws Exception { + SimpleDateFormat dateFormat = new SimpleDateFormat(TIME_PATTERN); + return dateFormat.format(timeStamp); + } + + + + public static Date dateSum (Date date,int countDays){ + Calendar calendar = Calendar.getInstance(); + calendar.setTime(date); + calendar.add(Calendar.DAY_OF_MONTH,countDays); + + return calendar.getTime(); + } + + /** + * 获取入参日期所在周的周一周末日期。 日期对应的时间为当日的零点 + * + * @return Map(2); key取值范围:firstTime/lastTime + */ + public static Map getWeedFirstTimeAndLastTime(Date date) { + Map returnMap = new HashMap<>(); + Calendar calendar = Calendar.getInstance(); + + //Calendar默认一周的开始是周日。业务需求从周一开始算,所以要"+1" + int weekDayAdd = 1; + + try { + calendar.setTime(date); + calendar.set(Calendar.DAY_OF_WEEK, calendar.getActualMinimum(Calendar.DAY_OF_WEEK)); + calendar.add(Calendar.DAY_OF_MONTH,weekDayAdd); + + //第一天的时分秒是 00:00:00 这里直接取日期,默认就是零点零分 + Date thisWeekFirstTime = getDate(getDateString(calendar.getTime())); + + calendar.clear(); + calendar.setTime(date); + calendar.set(Calendar.DAY_OF_WEEK, calendar.getActualMaximum(Calendar.DAY_OF_WEEK)); + calendar.add(Calendar.DAY_OF_MONTH,weekDayAdd); + + //最后一天的时分秒应当是23:59:59。 处理方式是增加一天计算日期再-1 + calendar.add(Calendar.DAY_OF_MONTH,1); + Date nextWeekFirstDay = getDate(getDateString(calendar.getTime())); + Date thisWeekLastTime = getTime(getTimeString(nextWeekFirstDay.getTime()-1)); + + returnMap.put("firstTime", thisWeekFirstTime); + returnMap.put("lastTime", thisWeekLastTime); + } catch (Exception e) { + e.printStackTrace(); + } + return returnMap; + + } + + + public static void main(String[] args) throws Exception { + System.out.println("start:"); + Date paramTime = getTime(getTimeString(new Long("1607672440731"))); + + Map weekDate = getWeedFirstTimeAndLastTime(paramTime); + + for (Map.Entry entry : + weekDate.entrySet()) { + System.out.println(entry.getKey() + ":" + getTimeString(entry.getValue())+":"+entry.getValue().getTime()); + } + + long countTimeLong = new Long("1607672440731"); + + System.out.println(getTimeString(--countTimeLong)); + + } + + + /** + * 获取当天的起始时间Date + * @param time 指定日期 例: 2020-12-13 06:12:42 + * @return 当天起始时间 例: 2020-12-13 00:00:00 + * @throws Exception + */ + public static Date getDayStartTime(Date time) throws Exception { + return getDate(getDateString(time)); + } +} diff --git a/frontend/src/business/components/api/homepage/ApiTestHomePage.vue b/frontend/src/business/components/api/homepage/ApiTestHomePage.vue new file mode 100644 index 0000000000..a5d08b6ab9 --- /dev/null +++ b/frontend/src/business/components/api/homepage/ApiTestHomePage.vue @@ -0,0 +1,127 @@ + + + + + diff --git a/frontend/src/business/components/api/homepage/components/ApiDetailCard.vue b/frontend/src/business/components/api/homepage/components/ApiDetailCard.vue new file mode 100644 index 0000000000..b2b433b0d2 --- /dev/null +++ b/frontend/src/business/components/api/homepage/components/ApiDetailCard.vue @@ -0,0 +1,62 @@ + + + + diff --git a/frontend/src/business/components/api/homepage/components/ApiInfoCard.vue b/frontend/src/business/components/api/homepage/components/ApiInfoCard.vue new file mode 100644 index 0000000000..9c75236e1e --- /dev/null +++ b/frontend/src/business/components/api/homepage/components/ApiInfoCard.vue @@ -0,0 +1,63 @@ + + + + diff --git a/frontend/src/business/components/api/homepage/components/FailureTestCaseList.vue b/frontend/src/business/components/api/homepage/components/FailureTestCaseList.vue new file mode 100644 index 0000000000..4edee720cd --- /dev/null +++ b/frontend/src/business/components/api/homepage/components/FailureTestCaseList.vue @@ -0,0 +1,57 @@ + + + + + diff --git a/frontend/src/business/components/api/homepage/components/RunningTaskList.vue b/frontend/src/business/components/api/homepage/components/RunningTaskList.vue new file mode 100644 index 0000000000..254ae3cba1 --- /dev/null +++ b/frontend/src/business/components/api/homepage/components/RunningTaskList.vue @@ -0,0 +1,79 @@ + + + + + diff --git a/frontend/src/business/components/api/homepage/components/SceneDetailCard.vue b/frontend/src/business/components/api/homepage/components/SceneDetailCard.vue new file mode 100644 index 0000000000..16cd97d608 --- /dev/null +++ b/frontend/src/business/components/api/homepage/components/SceneDetailCard.vue @@ -0,0 +1,52 @@ + + + + diff --git a/frontend/src/business/components/api/homepage/components/SceneInfoCard.vue b/frontend/src/business/components/api/homepage/components/SceneInfoCard.vue new file mode 100644 index 0000000000..78a46f3179 --- /dev/null +++ b/frontend/src/business/components/api/homepage/components/SceneInfoCard.vue @@ -0,0 +1,64 @@ + + + + diff --git a/frontend/src/business/components/api/homepage/components/ScheduleTaskDetailCard.vue b/frontend/src/business/components/api/homepage/components/ScheduleTaskDetailCard.vue new file mode 100644 index 0000000000..1d25af566c --- /dev/null +++ b/frontend/src/business/components/api/homepage/components/ScheduleTaskDetailCard.vue @@ -0,0 +1,58 @@ + + + + diff --git a/frontend/src/business/components/api/homepage/components/ScheduleTaskInfoCard.vue b/frontend/src/business/components/api/homepage/components/ScheduleTaskInfoCard.vue new file mode 100644 index 0000000000..983d025b87 --- /dev/null +++ b/frontend/src/business/components/api/homepage/components/ScheduleTaskInfoCard.vue @@ -0,0 +1,72 @@ + + + + diff --git a/frontend/src/business/components/api/homepage/components/TestCaseDetailCard.vue b/frontend/src/business/components/api/homepage/components/TestCaseDetailCard.vue new file mode 100644 index 0000000000..e08fb9b92b --- /dev/null +++ b/frontend/src/business/components/api/homepage/components/TestCaseDetailCard.vue @@ -0,0 +1,58 @@ + + + + diff --git a/frontend/src/business/components/api/homepage/components/TestCaseInfoCard.vue b/frontend/src/business/components/api/homepage/components/TestCaseInfoCard.vue new file mode 100644 index 0000000000..1f3f43c384 --- /dev/null +++ b/frontend/src/business/components/api/homepage/components/TestCaseInfoCard.vue @@ -0,0 +1,71 @@ + + + + diff --git a/frontend/src/business/components/api/router.js b/frontend/src/business/components/api/router.js index 0a297fcdb5..0016bdb474 100644 --- a/frontend/src/business/components/api/router.js +++ b/frontend/src/business/components/api/router.js @@ -11,7 +11,8 @@ export default { { path: 'home', name: 'fucHome', - component: () => import('@/business/components/api/home/ApiTestHome'), + // component: () => import('@/business/components/api/home/ApiTestHome'), + component: () => import('@/business/components/api/homepage/ApiTestHomePage'), }, { path: "test/:type", @@ -53,7 +54,7 @@ export default { path: "automation/report", name: "ApiReportList", component: () => import('@/business/components/api/automation/report/ApiReportList'), - }, + }, { path: 'monitor/view', name: 'ApiMonitor', diff --git a/frontend/src/i18n/en-US.js b/frontend/src/i18n/en-US.js index 98741015f5..98297db031 100644 --- a/frontend/src/i18n/en-US.js +++ b/frontend/src/i18n/en-US.js @@ -791,6 +791,64 @@ export default { swagger_export_tip: "Export jSON-formatted files via Swagger website", suffixFormatErr: "The file format does not meet the requirements", swagger_url_import: "Import using URL", + }, + home_page:{ + unit_of_measurement:"", + api_count_card:{ + title: "API count", + }, + test_case_count_card:{ + title: "Test case count", + }, + test_scene_count_card:{ + title: "Scene count", + }, + schedule_task_count_card:{ + title: "Schedule task count", + }, + api_details_card:{ + title: "API", + this_week_add:"Added {0} this week", + }, + test_case_details_card:{ + title: "Test case", + this_week_add:"Added {0} this week", + this_week_execute:"Executed {0} this week", + executed:"Executed {0} in history", + }, + test_scene_details_card:{ + title: "Scene", + this_week_add:"Added {0} this week", + this_week_execute:"Executed {0} this week", + executed:"Executed {0} in history", + }, + schedule_task_details_card:{ + title: "Schedule task", + this_week_add:"Added {0} this week", + this_week_execute:"Executed {0} this week", + executed:"Executed {0} in history", + }, + failed_case_list:{ + title: "Top 10 failure process set cases in the past 7 days", + table_coloum:{ + index: "Ranking", + case_name: "Case name", + test_plan: "Test plan", + failure_times: "Failure times", + }, + }, + running_task_list:{ + title: "Running task", + table_coloum:{ + index: "Index", + scenario: "Scene", + run_rule: "Rule", + task_status: "Status", + next_execution_time: "Next Execution Time", + create_user: "Creator", + update_time: "Update time", + }, + } } }, api_report: { diff --git a/frontend/src/i18n/zh-CN.js b/frontend/src/i18n/zh-CN.js index 5f979021f3..e9bde643d8 100644 --- a/frontend/src/i18n/zh-CN.js +++ b/frontend/src/i18n/zh-CN.js @@ -792,6 +792,64 @@ export default { swagger_export_tip: "通过 Swagger 页面导出", suffixFormatErr: "文件格式不符合要求", swagger_url_import: "使用URL导入", + }, + home_page:{ + unit_of_measurement:"个", + api_count_card:{ + title: "接口总数", + }, + test_case_count_card:{ + title: "用例总数", + }, + test_scene_count_card:{ + title: "场景总数", + }, + schedule_task_count_card:{ + title: "定时任务总数", + }, + api_details_card:{ + title: "接口", + this_week_add:"本周新增{0}个", + }, + test_case_details_card:{ + title: "用例", + this_week_add:"本周新增: {0}个", + this_week_execute:"本周执行: {0}次", + executed:"历史总执行: {0}次", + }, + test_scene_details_card:{ + title: "场景", + this_week_add:"本周新增: {0}个", + this_week_execute:"本周执行: {0}次", + executed:"历史总执行: {0}次", + }, + schedule_task_details_card:{ + title: "定时任务", + this_week_add:"本周新增: {0}个", + this_week_execute:"本周执行: {0}次", + executed:"历史总执行: {0}次", + }, + failed_case_list:{ + title: "过去7天流程集失败用例TOP 10", + table_coloum:{ + index: "排名", + case_name: "用例名称", + test_plan: "所属测试计划", + failure_times: "失败次数", + }, + }, + running_task_list:{ + title: "运行中的任务", + table_coloum:{ + index: "序号", + scenario: "场景名称", + run_rule: "运行规则", + task_status: "任务状态", + next_execution_time: "下次执行时间", + create_user: "创建人", + update_time: "更新时间", + }, + } } }, api_report: { diff --git a/frontend/src/i18n/zh-TW.js b/frontend/src/i18n/zh-TW.js index d63f348547..70711b87c7 100644 --- a/frontend/src/i18n/zh-TW.js +++ b/frontend/src/i18n/zh-TW.js @@ -791,6 +791,64 @@ export default { swagger_export_tip: "通過 Swagger 頁面導出", suffixFormatErr: "文件格式不符合要求", swagger_url_import: "使用URL導入", + }, + home_page:{ + unit_of_measurement:"個", + api_count_card:{ + title: "接口總數", + }, + test_case_count_card:{ + title: "用例總數", + }, + test_scene_count_card:{ + title: "場景總數", + }, + schedule_task_count_card:{ + title: "定時任務總數", + }, + api_details_card:{ + title: "接口", + this_week_add:"本週新增{0}个", + }, + test_case_details_card:{ + title: "用例", + this_week_add:"本週新增: {0}个", + this_week_execute:"本週執行: {0}次", + executed:"歷史總執行: {0}次", + }, + test_scene_details_card:{ + title: "場景", + this_week_add:"本週新增: {0}个", + this_week_execute:"本週執行: {0}次", + executed:"歷史總執行: {0}次", + }, + schedule_task_details_card:{ + title: "定時任務", + this_week_add:"本週新增: {0}个", + this_week_execute:"本週執行: {0}次", + executed:"歷史總執行: {0}次", + }, + failed_case_list:{ + title: "過去7天流程集失敗用例TOP 10", + table_coloum:{ + index: "排名", + case_name: "用例名稱", + test_plan: "所屬測試計畫", + failure_times: "失敗次數", + }, + }, + running_task_list:{ + title: "運行中的任務", + table_coloum:{ + index: "序號", + scenario: "場景名稱", + run_rule: "運行規則", + task_status: "任務狀態", + next_execution_time: "下次執行時間", + create_user: "創建人", + update_time: "更新時間", + }, + } } }, api_report: {