From 7707f9902d92604b425e695de93a93cdd2959ca0 Mon Sep 17 00:00:00 2001 From: "song.tianyang" Date: Thu, 17 Dec 2020 17:35:27 +0800 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=E6=8E=A5=E5=8F=A3=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E6=A8=A1=E5=9D=97-=E9=A6=96=E9=A1=B5=E5=BC=80?= =?UTF-8?q?=E5=8F=91Service=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 接口测试模块-首页开发,包含接口、用例、场景、定时任务、失败案例和运行中任务等功能的开发 --- .../api/controller/APITestController.java | 322 +++++++++--------- .../dto/dataCount/ExecutedCaseInfoResult.java | 18 + .../request/ScheduleInfoRequest.java | 16 + .../response/ExecutedCaseInfoDTO.java | 20 ++ .../api/service/APIReportService.java | 23 +- .../ApiDefinitionExecResultService.java | 7 + .../base/mapper/ApiTestReportMapper.java | 18 + .../base/mapper/ScheduleMapper.java | 25 ++ .../metersphere/commons/utils/CronUtils.java | 62 ++++ .../metersphere/service/ScheduleService.java | 25 ++ 10 files changed, 379 insertions(+), 157 deletions(-) create mode 100644 backend/src/main/java/io/metersphere/api/dto/dataCount/ExecutedCaseInfoResult.java create mode 100644 backend/src/main/java/io/metersphere/api/dto/dataCount/request/ScheduleInfoRequest.java create mode 100644 backend/src/main/java/io/metersphere/api/dto/dataCount/response/ExecutedCaseInfoDTO.java create mode 100644 backend/src/main/java/io/metersphere/commons/utils/CronUtils.java 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 5a58efb37e..229d0f7fdf 100644 --- a/backend/src/main/java/io/metersphere/api/controller/APITestController.java +++ b/backend/src/main/java/io/metersphere/api/controller/APITestController.java @@ -1,153 +1,169 @@ -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.scenario.request.dubbo.RegistryCenter; -import io.metersphere.api.service.APITestService; -import io.metersphere.base.domain.ApiTest; -import io.metersphere.base.domain.Schedule; -import io.metersphere.commons.constants.RoleConstants; -import io.metersphere.commons.utils.PageUtils; -import io.metersphere.commons.utils.Pager; -import io.metersphere.commons.utils.SessionUtils; -import io.metersphere.controller.request.QueryScheduleRequest; -import io.metersphere.dto.ScheduleDao; -import io.metersphere.service.CheckOwnerService; - -import org.apache.shiro.authz.annotation.Logical; -import org.apache.shiro.authz.annotation.RequiresRoles; -import org.springframework.web.bind.annotation.*; -import org.springframework.web.multipart.MultipartFile; - -import javax.annotation.Resource; - -import java.util.HashMap; -import java.util.List; - -import static io.metersphere.commons.utils.JsonPathUtils.getListJson; - - -@RestController -@RequestMapping(value = "/api") -@RequiresRoles(value = {RoleConstants.TEST_MANAGER, RoleConstants.TEST_USER, RoleConstants.TEST_VIEWER}, logical = Logical.OR) -public class APITestController { - @Resource - private APITestService apiTestService; - @Resource - private CheckOwnerService checkownerService; - - @GetMapping("recent/{count}") - public List recentTest(@PathVariable int count) { - String currentWorkspaceId = SessionUtils.getCurrentWorkspaceId(); - QueryAPITestRequest request = new QueryAPITestRequest(); - request.setWorkspaceId(currentWorkspaceId); - request.setUserId(SessionUtils.getUserId()); - PageHelper.startPage(1, count, true); - return apiTestService.recentTest(request); - } - - @PostMapping("/list/{goPage}/{pageSize}") - public Pager> list(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody QueryAPITestRequest request) { - Page page = PageHelper.startPage(goPage, pageSize, true); - request.setWorkspaceId(SessionUtils.getCurrentWorkspaceId()); - request.setProjectId(SessionUtils.getCurrentProjectId()); - return PageUtils.setPageInfo(page, apiTestService.list(request)); - } - - @PostMapping("/list/ids") - public List listByIds(@RequestBody QueryAPITestRequest request) { - return apiTestService.listByIds(request); - } - - @GetMapping("/list/{projectId}") - public List list(@PathVariable String projectId) { - checkownerService.checkProjectOwner(projectId); - return apiTestService.getApiTestByProjectId(projectId); - } - - @PostMapping(value = "/schedule/update") - public void updateSchedule(@RequestBody Schedule request) { - apiTestService.updateSchedule(request); - } - - @PostMapping(value = "/schedule/create") - public void createSchedule(@RequestBody Schedule request) { - apiTestService.createSchedule(request); - } - - @PostMapping(value = "/create", consumes = {"multipart/form-data"}) - public void create(@RequestPart("request") SaveAPITestRequest request, @RequestPart(value = "file") MultipartFile file, @RequestPart(value = "files") List bodyFiles) { - apiTestService.create(request, file, bodyFiles); - } - - @PostMapping(value = "/create/merge", consumes = {"multipart/form-data"}) - public void mergeCreate(@RequestPart("request") SaveAPITestRequest request, @RequestPart(value = "file") MultipartFile file, @RequestPart(value = "selectIds") List selectIds) { - apiTestService.mergeCreate(request, file, selectIds); - } - @PostMapping(value = "/update", consumes = {"multipart/form-data"}) - public void update(@RequestPart("request") SaveAPITestRequest request, @RequestPart(value = "file") MultipartFile file, @RequestPart(value = "files") List bodyFiles) { - checkownerService.checkApiTestOwner(request.getId()); - apiTestService.update(request, file, bodyFiles); - } - - @PostMapping(value = "/copy") - public void copy(@RequestBody SaveAPITestRequest request) { - apiTestService.copy(request); - } - - @GetMapping("/get/{testId}") - public APITestResult get(@PathVariable String testId) { - checkownerService.checkApiTestOwner(testId); - return apiTestService.get(testId); - } - - - @PostMapping("/delete") - public void delete(@RequestBody DeleteAPITestRequest request) { - checkownerService.checkApiTestOwner(request.getId()); - apiTestService.delete(request); - } - - @PostMapping(value = "/run") - public String run(@RequestBody SaveAPITestRequest request) { - return apiTestService.run(request); - } - - @PostMapping(value = "/run/debug", consumes = {"multipart/form-data"}) - public String runDebug(@RequestPart("request") SaveAPITestRequest request, @RequestPart(value = "file") MultipartFile file, @RequestPart(value = "files") List bodyFiles) { - return apiTestService.runDebug(request, file, bodyFiles); - } - - @PostMapping(value = "/checkName") - public void checkName(@RequestBody SaveAPITestRequest request) { - apiTestService.checkName(request); - } - - @PostMapping(value = "/import", consumes = {"multipart/form-data"}) - @RequiresRoles(value = {RoleConstants.TEST_USER, RoleConstants.TEST_MANAGER}, logical = Logical.OR) - public ApiTest testCaseImport(@RequestPart(value = "file", required = false) MultipartFile file, @RequestPart("request") ApiTestImportRequest request) { - return apiTestService.apiTestImport(file, request); - } - - @PostMapping("/dubbo/providers") - public List getProviders(@RequestBody RegistryCenter registry) { - return apiTestService.getProviders(registry); - } - - @PostMapping("/list/schedule/{goPage}/{pageSize}") - public List listSchedule(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody QueryScheduleRequest request) { - Page page = PageHelper.startPage(goPage, pageSize, true); - return apiTestService.listSchedule(request); - } - - @PostMapping("/list/schedule") - public List listSchedule(@RequestBody QueryScheduleRequest request) { - return apiTestService.listSchedule(request); - } - - @PostMapping("/getJsonPaths") - public List getJsonPaths(@RequestBody QueryJsonPathRequest request) { - return getListJson(request.getJsonPath()); - } -} +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.scenario.request.dubbo.RegistryCenter; +import io.metersphere.api.service.*; +import io.metersphere.base.domain.ApiTest; +import io.metersphere.base.domain.Schedule; +import io.metersphere.commons.constants.RoleConstants; +import io.metersphere.commons.constants.ScheduleGroup; +import io.metersphere.commons.utils.*; +import io.metersphere.controller.request.QueryScheduleRequest; +import io.metersphere.dto.ScheduleDao; +import io.metersphere.service.CheckOwnerService; + +import io.metersphere.service.ScheduleService; +import org.apache.shiro.authz.annotation.Logical; +import org.apache.shiro.authz.annotation.RequiresRoles; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; + +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; + +import static io.metersphere.commons.utils.JsonPathUtils.getListJson; + + +@RestController +@RequestMapping(value = "/api") +@RequiresRoles(value = {RoleConstants.TEST_MANAGER, RoleConstants.TEST_USER, RoleConstants.TEST_VIEWER}, logical = Logical.OR) +public class APITestController { + @Resource + private APITestService apiTestService; + @Resource + private ApiDefinitionService apiDefinitionService; + @Resource + private CheckOwnerService checkownerService; + @Resource + private ApiTestCaseService apiTestCaseService; + @Resource + private ApiDefinitionExecResultService apiDefinitionExecResultService; + @Resource + private ApiAutomationService apiAutomationService; + @Resource + private ApiScenarioReportService apiScenarioReportService; + @Resource + private ScheduleService scheduleService; + @Resource + private APIReportService apiReportService; + + @GetMapping("recent/{count}") + public List recentTest(@PathVariable int count) { + String currentWorkspaceId = SessionUtils.getCurrentWorkspaceId(); + QueryAPITestRequest request = new QueryAPITestRequest(); + request.setWorkspaceId(currentWorkspaceId); + request.setUserId(SessionUtils.getUserId()); + PageHelper.startPage(1, count, true); + return apiTestService.recentTest(request); + } + + @PostMapping("/list/{goPage}/{pageSize}") + public Pager> list(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody QueryAPITestRequest request) { + Page page = PageHelper.startPage(goPage, pageSize, true); + request.setWorkspaceId(SessionUtils.getCurrentWorkspaceId()); + request.setProjectId(SessionUtils.getCurrentProjectId()); + return PageUtils.setPageInfo(page, apiTestService.list(request)); + } + + @PostMapping("/list/ids") + public List listByIds(@RequestBody QueryAPITestRequest request) { + return apiTestService.listByIds(request); + } + + @GetMapping("/list/{projectId}") + public List list(@PathVariable String projectId) { + checkownerService.checkProjectOwner(projectId); + return apiTestService.getApiTestByProjectId(projectId); + } + + @PostMapping(value = "/schedule/update") + public void updateSchedule(@RequestBody Schedule request) { + apiTestService.updateSchedule(request); + } + + @PostMapping(value = "/schedule/create") + public void createSchedule(@RequestBody Schedule request) { + apiTestService.createSchedule(request); + } + + @PostMapping(value = "/create", consumes = {"multipart/form-data"}) + public void create(@RequestPart("request") SaveAPITestRequest request, @RequestPart(value = "file") MultipartFile file, @RequestPart(value = "files") List bodyFiles) { + apiTestService.create(request, file, bodyFiles); + } + + @PostMapping(value = "/create/merge", consumes = {"multipart/form-data"}) + public void mergeCreate(@RequestPart("request") SaveAPITestRequest request, @RequestPart(value = "file") MultipartFile file, @RequestPart(value = "selectIds") List selectIds) { + apiTestService.mergeCreate(request, file, selectIds); + } + @PostMapping(value = "/update", consumes = {"multipart/form-data"}) + public void update(@RequestPart("request") SaveAPITestRequest request, @RequestPart(value = "file") MultipartFile file, @RequestPart(value = "files") List bodyFiles) { + checkownerService.checkApiTestOwner(request.getId()); + apiTestService.update(request, file, bodyFiles); + } + + @PostMapping(value = "/copy") + public void copy(@RequestBody SaveAPITestRequest request) { + apiTestService.copy(request); + } + + @GetMapping("/get/{testId}") + public APITestResult get(@PathVariable String testId) { + checkownerService.checkApiTestOwner(testId); + return apiTestService.get(testId); + } + + + @PostMapping("/delete") + public void delete(@RequestBody DeleteAPITestRequest request) { + checkownerService.checkApiTestOwner(request.getId()); + apiTestService.delete(request); + } + + @PostMapping(value = "/run") + public String run(@RequestBody SaveAPITestRequest request) { + return apiTestService.run(request); + } + + @PostMapping(value = "/run/debug", consumes = {"multipart/form-data"}) + public String runDebug(@RequestPart("request") SaveAPITestRequest request, @RequestPart(value = "file") MultipartFile file, @RequestPart(value = "files") List bodyFiles) { + return apiTestService.runDebug(request, file, bodyFiles); + } + + @PostMapping(value = "/checkName") + public void checkName(@RequestBody SaveAPITestRequest request) { + apiTestService.checkName(request); + } + + @PostMapping(value = "/import", consumes = {"multipart/form-data"}) + @RequiresRoles(value = {RoleConstants.TEST_USER, RoleConstants.TEST_MANAGER}, logical = Logical.OR) + public ApiTest testCaseImport(@RequestPart(value = "file", required = false) MultipartFile file, @RequestPart("request") ApiTestImportRequest request) { + return apiTestService.apiTestImport(file, request); + } + + @PostMapping("/dubbo/providers") + public List getProviders(@RequestBody RegistryCenter registry) { + return apiTestService.getProviders(registry); + } + + @PostMapping("/list/schedule/{goPage}/{pageSize}") + public List listSchedule(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody QueryScheduleRequest request) { + Page page = PageHelper.startPage(goPage, pageSize, true); + return apiTestService.listSchedule(request); + } + + @PostMapping("/list/schedule") + public List listSchedule(@RequestBody QueryScheduleRequest request) { + return apiTestService.listSchedule(request); + } + + @PostMapping("/getJsonPaths") + public List getJsonPaths(@RequestBody QueryJsonPathRequest request) { + return getListJson(request.getJsonPath()); + } +} diff --git a/backend/src/main/java/io/metersphere/api/dto/dataCount/ExecutedCaseInfoResult.java b/backend/src/main/java/io/metersphere/api/dto/dataCount/ExecutedCaseInfoResult.java new file mode 100644 index 0000000000..2a499dc49f --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dto/dataCount/ExecutedCaseInfoResult.java @@ -0,0 +1,18 @@ +package io.metersphere.api.dto.dataCount; + +import lombok.Getter; +import lombok.Setter; + +/** + * 已执行的案例 + */ +@Getter +@Setter +public class ExecutedCaseInfoResult { + //案例名称 + private String caseName; + //所属测试计划 + private String testPlan; + //失败次数 + private Long failureTimes; +} diff --git a/backend/src/main/java/io/metersphere/api/dto/dataCount/request/ScheduleInfoRequest.java b/backend/src/main/java/io/metersphere/api/dto/dataCount/request/ScheduleInfoRequest.java new file mode 100644 index 0000000000..df66955556 --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dto/dataCount/request/ScheduleInfoRequest.java @@ -0,0 +1,16 @@ +package io.metersphere.api.dto.dataCount.request; + +import lombok.Getter; +import lombok.Setter; + +/** + * @author song.tianyang + * @Date 2020/12/17 5:04 下午 + * @Description + */ +@Getter +@Setter +public class ScheduleInfoRequest { + private String taskID; + private boolean enable; +} diff --git a/backend/src/main/java/io/metersphere/api/dto/dataCount/response/ExecutedCaseInfoDTO.java b/backend/src/main/java/io/metersphere/api/dto/dataCount/response/ExecutedCaseInfoDTO.java new file mode 100644 index 0000000000..bdd267efed --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dto/dataCount/response/ExecutedCaseInfoDTO.java @@ -0,0 +1,20 @@ +package io.metersphere.api.dto.dataCount.response; + +import lombok.Getter; +import lombok.Setter; + +/** + * 已执行的案例 + */ +@Getter +@Setter +public class ExecutedCaseInfoDTO { + //排名 + private int sortIndex; + //案例名称 + private String caseName; + //所属测试计划 + private String testPlan; + //失败次数 + private Long failureTimes; +} diff --git a/backend/src/main/java/io/metersphere/api/service/APIReportService.java b/backend/src/main/java/io/metersphere/api/service/APIReportService.java index 20fd1834db..38db544c3b 100644 --- a/backend/src/main/java/io/metersphere/api/service/APIReportService.java +++ b/backend/src/main/java/io/metersphere/api/service/APIReportService.java @@ -15,6 +15,7 @@ import io.metersphere.base.mapper.ext.ExtApiTestReportMapper; import io.metersphere.commons.constants.APITestStatus; import io.metersphere.commons.constants.ReportTriggerMode; import io.metersphere.commons.exception.MSException; +import io.metersphere.commons.utils.DateUtils; import io.metersphere.commons.utils.LogUtil; import io.metersphere.commons.utils.ServiceUtils; import io.metersphere.commons.utils.SessionUtils; @@ -30,10 +31,7 @@ import java.nio.charset.StandardCharsets; import java.text.SimpleDateFormat; import java.time.Instant; import java.time.temporal.ChronoUnit; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.UUID; +import java.util.*; @Service @Transactional(rollbackFor = Exception.class) @@ -212,4 +210,21 @@ public class APIReportService { apiTestReportExample.createCriteria().andIdIn(reportRequest.getIds()); apiTestReportMapper.deleteByExample(apiTestReportExample); } + + public long countByWorkspaceIdAndGroupAndCreateInThisWeek(String workspaceID, String group) { + 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 apiTestReportMapper.countByProjectIDAndCreateInThisWeek(workspaceID,group,firstTime.getTime(),lastTime.getTime()); + } + } + + public long countByWorkspaceIdAndGroup(String workspaceID, String group) { + return apiTestReportMapper.countByWorkspaceIdAndGroup(workspaceID,group); + } } 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 f5a175d62e..0df58b52ea 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiDefinitionExecResultService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiDefinitionExecResultService.java @@ -4,6 +4,8 @@ import com.alibaba.fastjson.JSON; import io.metersphere.api.jmeter.TestResult; import io.metersphere.base.domain.ApiDefinitionExecResult; import io.metersphere.base.mapper.ApiDefinitionExecResultMapper; +import io.metersphere.base.mapper.ext.ExtApiDefinitionExecResultMapper; +import io.metersphere.commons.utils.DateUtils; import io.metersphere.commons.utils.SessionUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -17,9 +19,14 @@ import java.util.UUID; public class ApiDefinitionExecResultService { @Resource private ApiDefinitionExecResultMapper apiDefinitionExecResultMapper; + @Resource + private ExtApiDefinitionExecResultMapper extApiDefinitionExecResultMapper; + public void saveApiResult(TestResult result) { result.getScenarios().get(0).getRequestResults().forEach(item -> { + // 清理原始资源,每个执行 保留一条结果 + extApiDefinitionExecResultMapper.deleteByResourceId(item.getName()); ApiDefinitionExecResult saveResult = new ApiDefinitionExecResult(); saveResult.setId(UUID.randomUUID().toString()); saveResult.setUserId(Objects.requireNonNull(SessionUtils.getUser()).getId()); diff --git a/backend/src/main/java/io/metersphere/base/mapper/ApiTestReportMapper.java b/backend/src/main/java/io/metersphere/base/mapper/ApiTestReportMapper.java index 6888e61a55..a736d54ecb 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ApiTestReportMapper.java +++ b/backend/src/main/java/io/metersphere/base/mapper/ApiTestReportMapper.java @@ -4,6 +4,7 @@ import io.metersphere.base.domain.ApiTestReport; import io.metersphere.base.domain.ApiTestReportExample; import java.util.List; import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; public interface ApiTestReportMapper { long countByExample(ApiTestReportExample example); @@ -27,4 +28,21 @@ public interface ApiTestReportMapper { int updateByPrimaryKeySelective(ApiTestReport record); int updateByPrimaryKey(ApiTestReport record); + + @Select({ + "SELECT COUNT(testReportDetail.report_id) AS countNumber FROM api_test_report_detail testReportDetail ", + "INNER JOIN `schedule` sch ON sch.resource_id = testReportDetail.test_id ", + "INNER JOIN api_test_report testReport ON testReportDetail.report_id = testReport.id ", + "WHERE workspace_id = #{workspaceID} AND `group` = #{group} ", + }) + long countByWorkspaceIdAndGroup(@Param("workspaceID") String workspaceID, @Param("group")String group); + + @Select({ + "SELECT COUNT(testReportDetail.report_id) AS countNumber FROM api_test_report_detail testReportDetail ", + "INNER JOIN `schedule` sch ON sch.resource_id = testReportDetail.test_id ", + "INNER JOIN api_test_report testReport ON testReportDetail.report_id = testReport.id ", + "WHERE workspace_id = #{workspaceID} AND `group` = #{group} ", + "AND testReport.create_time BETWEEN #{startTime} and #{endTime} ", + }) + long countByProjectIDAndCreateInThisWeek(@Param("workspaceID") String workspaceID, @Param("group")String group, @Param("startTime") long startTime, @Param("endTime")long endTime); } \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/base/mapper/ScheduleMapper.java b/backend/src/main/java/io/metersphere/base/mapper/ScheduleMapper.java index 264e2f2e58..ee050eeccd 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ScheduleMapper.java +++ b/backend/src/main/java/io/metersphere/base/mapper/ScheduleMapper.java @@ -1,9 +1,13 @@ package io.metersphere.base.mapper; +import io.metersphere.api.dto.dataCount.response.TaskInfoResult; import io.metersphere.base.domain.Schedule; import io.metersphere.base.domain.ScheduleExample; import java.util.List; import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; +import org.apache.ibatis.annotations.Update; +import org.python.antlr.ast.Str; public interface ScheduleMapper { long countByExample(ScheduleExample example); @@ -33,4 +37,25 @@ public interface ScheduleMapper { int updateByPrimaryKeyWithBLOBs(Schedule record); int updateByPrimaryKey(Schedule record); + + @Select("SELECT COUNT(id) AS countNumber FROM `schedule` WHERE `workspace_id` = #{workspaceId} AND `group` = #{group} ") + long countTaskByWorkspaceIdAndGroup(@Param("workspaceId") String workspaceId,@Param("group") String group); + + @Select({ + "SELECT COUNT(id) AS countNumber FROM `schedule` ", + "WHERE workspace_id = #{workspaceId} ", + "AND `group` = #{group} ", + "AND create_time BETWEEN #{startTime} and #{endTime}; " + }) + long countTaskByWorkspaceIdAndGroupAndCreateTimeRange(@Param("workspaceId")String workspaceId,@Param("group") String group, @Param("startTime") long startTime, @Param("endTime") long endTime); + + @Select({ + "SELECT apiTest.`name` AS scenario,sch.id AS taskID,sch.`value` AS rule,sch.`enable` AS `taskStatus`,u.`name` AS creator,sch.update_time AS updateTime ", + "FROM api_test apiTest ", + "INNER JOIN `schedule` sch ON apiTest.id = sch.resource_id ", + "INNER JOIN `user` u ON u.id = sch.user_id ", + "WHERE sch.`enable` = true AND sch.workspace_id = #{0,jdbcType=VARCHAR}" + }) + List findRunningTaskInfoByWorkspaceID(String workspaceID); + } \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/commons/utils/CronUtils.java b/backend/src/main/java/io/metersphere/commons/utils/CronUtils.java new file mode 100644 index 0000000000..2d03a1de56 --- /dev/null +++ b/backend/src/main/java/io/metersphere/commons/utils/CronUtils.java @@ -0,0 +1,62 @@ +package io.metersphere.commons.utils; + +import org.quartz.CronExpression; +import org.quartz.CronScheduleBuilder; +import org.quartz.CronTrigger; +import org.quartz.TriggerBuilder; + +import java.util.Date; + +/** + * @author song.tianyang + * @Date 2020/12/17 4:06 下午 + * @Description CRON解析类 + */ +public class CronUtils { + + /** + * 解析表达式,获取CronTrigger + * @param cron + * @return + */ + public static CronTrigger getCronTrigger(String cron) { + if (!CronExpression.isValidExpression(cron)) { + throw new RuntimeException("cron :" + cron + "表达式解析错误"); + } + return TriggerBuilder.newTrigger().withIdentity("Caclulate Date").withSchedule(CronScheduleBuilder.cronSchedule(cron)).build(); + } + + /** + * 获取以指定时间为开始时间的下一次执行时间 + * @param cron + * @param start + * @return + */ + public static Date getNextTriggerTime(String cron, Date start) { + if (start == null) { + return getNextTriggerTime(cron); + }else{ + CronTrigger trigger = getCronTrigger(cron); + return trigger.getFireTimeAfter(start); + } + } + + /** + * 获取以当前日期为准的下一次执行时间 + * @param cron + * @return + */ + public static Date getNextTriggerTime(String cron) { + Date date = null; + try{ + CronTrigger trigger = getCronTrigger(cron); + Date startDate = trigger.getStartTime(); + date = trigger.getFireTimeAfter(startDate); + }catch (Exception e){ + + } + return date; + } + + +} diff --git a/backend/src/main/java/io/metersphere/service/ScheduleService.java b/backend/src/main/java/io/metersphere/service/ScheduleService.java index 6ba14f21db..7db0a4fd79 100644 --- a/backend/src/main/java/io/metersphere/service/ScheduleService.java +++ b/backend/src/main/java/io/metersphere/service/ScheduleService.java @@ -1,6 +1,7 @@ package io.metersphere.service; import com.alibaba.fastjson.JSON; +import io.metersphere.api.dto.dataCount.response.TaskInfoResult; import io.metersphere.base.domain.Schedule; import io.metersphere.base.domain.ScheduleExample; import io.metersphere.base.domain.User; @@ -9,6 +10,7 @@ import io.metersphere.base.mapper.ScheduleMapper; import io.metersphere.base.mapper.UserMapper; import io.metersphere.base.mapper.ext.ExtScheduleMapper; import io.metersphere.commons.exception.MSException; +import io.metersphere.commons.utils.DateUtils; import io.metersphere.commons.utils.LogUtil; import io.metersphere.commons.utils.ServiceUtils; import io.metersphere.commons.utils.SessionUtils; @@ -25,6 +27,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; +import java.util.Date; import java.util.List; import java.util.Map; import java.util.UUID; @@ -162,4 +165,26 @@ public class ScheduleService { schedule.setUserName(userMap.get(schedule.getUserId())); }); } + + public long countTaskByWorkspaceIdAndGroup(String workspaceId,String group) { + return scheduleMapper.countTaskByWorkspaceIdAndGroup(workspaceId,group); + } + + public long countTaskByWorkspaceIdAndGroupInThisWeek(String workspaceID, String group) { + 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 scheduleMapper.countTaskByWorkspaceIdAndGroupAndCreateTimeRange(workspaceID,group,firstTime.getTime(),lastTime.getTime()); + } + } + + public List findRunningTaskInfoByWorkspaceID(String workspaceID) { + List runningTaskInfoList = scheduleMapper.findRunningTaskInfoByWorkspaceID(workspaceID); + return runningTaskInfoList; + } } From 66c01949af33734aa478ccbc795b7fcf553195ec Mon Sep 17 00:00:00 2001 From: "song.tianyang" Date: Thu, 17 Dec 2020 17:37:19 +0800 Subject: [PATCH 2/2] =?UTF-8?q?feat:=20=E6=8E=A5=E5=8F=A3=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E6=A8=A1=E5=9D=97-=E9=A6=96=E9=A1=B5=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2=E5=B1=95=E7=A4=BA=E4=BB=A5=E5=8F=8A=E5=90=8E=E5=8F=B0?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E9=80=82=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 接口测试模块-首页开发,包含接口、用例、场景、定时任务、失败案例和运行中任务等功能的开发 --- .../api/controller/APITestController.java | 128 ++++++++++++++++++ .../api/dto/dataCount/ApiDataCountResult.java | 16 +++ .../dataCount/response/ApiDataCountDTO.java | 65 +++++++++ .../dataCount/response/TaskInfoResult.java | 30 ++++ .../api/service/APITestService.java | 1 + .../api/service/ApiAutomationService.java | 17 +++ .../ApiDefinitionExecResultService.java | 40 +++++- .../api/service/ApiDefinitionService.java | 37 +++-- .../api/service/ApiScenarioReportService.java | 19 +++ .../api/service/ApiTestCaseService.java | 22 +++ .../mapper/ApiDefinitionExecResultMapper.java | 40 ++++++ .../base/mapper/ApiDefinitionMapper.java | 13 ++ .../base/mapper/ApiScenarioMapper.java | 11 ++ .../base/mapper/ApiScenarioReportMapper.java | 11 ++ .../base/mapper/ApiTestCaseMapper.java | 18 +++ .../metersphere/commons/utils/DateUtils.java | 121 +++++++++++++++++ .../api/homepage/ApiTestHomePage.vue | 127 +++++++++++++++++ .../api/homepage/components/ApiDetailCard.vue | 62 +++++++++ .../api/homepage/components/ApiInfoCard.vue | 63 +++++++++ .../components/FailureTestCaseList.vue | 57 ++++++++ .../homepage/components/RunningTaskList.vue | 79 +++++++++++ .../homepage/components/SceneDetailCard.vue | 52 +++++++ .../api/homepage/components/SceneInfoCard.vue | 64 +++++++++ .../components/ScheduleTaskDetailCard.vue | 58 ++++++++ .../components/ScheduleTaskInfoCard.vue | 72 ++++++++++ .../components/TestCaseDetailCard.vue | 58 ++++++++ .../homepage/components/TestCaseInfoCard.vue | 71 ++++++++++ .../src/business/components/api/router.js | 5 +- frontend/src/i18n/en-US.js | 58 ++++++++ frontend/src/i18n/zh-CN.js | 58 ++++++++ frontend/src/i18n/zh-TW.js | 58 ++++++++ 31 files changed, 1519 insertions(+), 12 deletions(-) create mode 100644 backend/src/main/java/io/metersphere/api/dto/dataCount/ApiDataCountResult.java create mode 100644 backend/src/main/java/io/metersphere/api/dto/dataCount/response/ApiDataCountDTO.java create mode 100644 backend/src/main/java/io/metersphere/api/dto/dataCount/response/TaskInfoResult.java create mode 100644 backend/src/main/java/io/metersphere/commons/utils/DateUtils.java create mode 100644 frontend/src/business/components/api/homepage/ApiTestHomePage.vue create mode 100644 frontend/src/business/components/api/homepage/components/ApiDetailCard.vue create mode 100644 frontend/src/business/components/api/homepage/components/ApiInfoCard.vue create mode 100644 frontend/src/business/components/api/homepage/components/FailureTestCaseList.vue create mode 100644 frontend/src/business/components/api/homepage/components/RunningTaskList.vue create mode 100644 frontend/src/business/components/api/homepage/components/SceneDetailCard.vue create mode 100644 frontend/src/business/components/api/homepage/components/SceneInfoCard.vue create mode 100644 frontend/src/business/components/api/homepage/components/ScheduleTaskDetailCard.vue create mode 100644 frontend/src/business/components/api/homepage/components/ScheduleTaskInfoCard.vue create mode 100644 frontend/src/business/components/api/homepage/components/TestCaseDetailCard.vue create mode 100644 frontend/src/business/components/api/homepage/components/TestCaseInfoCard.vue 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: {