feat: 接口测试模块-首页页面展示以及后台接口适配
接口测试模块-首页开发,包含接口、用例、场景、定时任务、失败案例和运行中任务等功能的开发
This commit is contained in:
parent
7707f9902d
commit
66c01949af
|
@ -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<HashMap> getJsonPaths(@RequestBody QueryJsonPathRequest request) {
|
||||
return getListJson(request.getJsonPath());
|
||||
}
|
||||
|
||||
@GetMapping("/apiCount/{projectId}")
|
||||
public ApiDataCountDTO apiCount(@PathVariable String projectId) {
|
||||
|
||||
ApiDataCountDTO apiCountResult = new ApiDataCountDTO();
|
||||
|
||||
List<ApiDataCountResult> 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<ApiDataCountResult> 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<ExecutedCaseInfoDTO> faliureCaseAboutTestPlan(@PathVariable String projectId, @PathVariable int limitNumber) {
|
||||
|
||||
List<ExecutedCaseInfoResult> selectDataList = apiDefinitionExecResultService.findFaliureCaseInfoByProjectIDAndLimitNumberInSevenDays(projectId,limitNumber);
|
||||
|
||||
List<ExecutedCaseInfoDTO> returnList = new ArrayList<>(limitNumber);
|
||||
|
||||
for(int dataIndex = 0;dataIndex < limitNumber;dataIndex ++){
|
||||
|
||||
ExecutedCaseInfoDTO dataDTO = new ExecutedCaseInfoDTO();
|
||||
dataDTO.setSortIndex(dataIndex+1);
|
||||
|
||||
if(dataIndex<selectDataList.size()){
|
||||
ExecutedCaseInfoResult selectData = selectDataList.get(dataIndex);
|
||||
|
||||
dataDTO.setCaseName(selectData.getCaseName());
|
||||
dataDTO.setTestPlan(selectData.getTestPlan());
|
||||
dataDTO.setFailureTimes(selectData.getFailureTimes());
|
||||
}else {
|
||||
dataDTO.setCaseName("");
|
||||
dataDTO.setTestPlan("");
|
||||
}
|
||||
returnList.add(dataDTO);
|
||||
}
|
||||
return returnList;
|
||||
}
|
||||
|
||||
@GetMapping("/runningTask/{workspaceID}")
|
||||
public List<TaskInfoResult> runningTask(@PathVariable String workspaceID) {
|
||||
|
||||
List<TaskInfoResult> 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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<ApiDataCountResult> 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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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<String, Date> 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<String, Date> 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<ExecutedCaseInfoResult> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<ApiDataCountResult> countProtocolByProjectID(String projectId) {
|
||||
return apiDefinitionMapper.countProtocolByProjectID(projectId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计本周创建的数据总量
|
||||
* @param projectId
|
||||
* @return
|
||||
*/
|
||||
public long countByProjectIDAndCreateInThisWeek(String projectId) {
|
||||
Map<String, Date> 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<String, Date> 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<ApiDataCountResult> countProtocolByProjectID(String projectId) {
|
||||
return apiTestCaseMapper.countProtocolByProjectID(projectId);
|
||||
}
|
||||
|
||||
public long countByProjectIDAndCreateInThisWeek(String projectId) {
|
||||
Map<String, Date> 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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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<ExecutedCaseInfoResult> findFaliureCaseInfoByProjectIDAndExecuteTimeAndLimitNumber(@Param("projectId") String projectId, @Param("startTimestamp") long startTimestamp, @Param("limitNumber") int limitNumber);
|
||||
}
|
|
@ -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<ApiDataCountResult> 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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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<ApiDataCountResult> 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);
|
||||
}
|
|
@ -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<String, String>(2); key取值范围:firstTime/lastTime
|
||||
*/
|
||||
public static Map<String, Date> getWeedFirstTimeAndLastTime(Date date) {
|
||||
Map<String, Date> 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<String, Date> weekDate = getWeedFirstTimeAndLastTime(paramTime);
|
||||
|
||||
for (Map.Entry<String, Date> 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));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
<template>
|
||||
<ms-container>
|
||||
<ms-main-container v-loading="result.loading">
|
||||
<el-row :gutter="0"></el-row>
|
||||
<el-row :gutter="0">
|
||||
<el-col :span="4" >
|
||||
<ms-api-info-card :api-count-data="apiCountData"/>
|
||||
</el-col>
|
||||
<el-col :span="4" :offset="2">
|
||||
<ms-test-case-info-card :test-case-count-data="testCaseCountData"/>
|
||||
</el-col>
|
||||
<el-col :span="4" :offset="2">
|
||||
<ms-scene-info-card :scene-count-data="sceneCountData"/>
|
||||
</el-col>
|
||||
<el-col :span="4" :offset="2">
|
||||
<ms-schedule-task-info-card :schedule-task-count-data="scheduleTaskCountData"/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row>
|
||||
<el-col :span="4" >
|
||||
<ms-api-detail-card :api-count-data="apiCountData"/>
|
||||
</el-col>
|
||||
<el-col :span="4" :offset="2">
|
||||
<ms-test-case-detail-card :test-case-count-data="testCaseCountData"/>
|
||||
</el-col>
|
||||
<el-col :span="4" :offset="2">
|
||||
<ms-scene-detail-card :scene-count-data="sceneCountData"/>
|
||||
</el-col>
|
||||
<el-col :span="4" :offset="2">
|
||||
<ms-schedule-task-detail-card :schedule-task-count-data="scheduleTaskCountData"/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20" >
|
||||
<el-col :span="11" >
|
||||
<ms-failure-test-case-list/>
|
||||
</el-col>
|
||||
<el-col :span="13" >
|
||||
<ms-running-task-list/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
</ms-main-container>
|
||||
</ms-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MsContainer from "@/business/components/common/components/MsContainer";
|
||||
import MsMainContainer from "@/business/components/common/components/MsMainContainer";
|
||||
import MsApiInfoCard from "./components/ApiInfoCard";
|
||||
import MsSceneInfoCard from "./components/SceneInfoCard";
|
||||
import MsScheduleTaskInfoCard from "./components/ScheduleTaskInfoCard";
|
||||
import MsTestCaseInfoCard from "./components/TestCaseInfoCard";
|
||||
|
||||
import MsApiDetailCard from "./components/ApiDetailCard";
|
||||
import MsSceneDetailCard from "./components/SceneDetailCard";
|
||||
import MsScheduleTaskDetailCard from "./components/ScheduleTaskDetailCard";
|
||||
import MsTestCaseDetailCard from "./components/TestCaseDetailCard";
|
||||
|
||||
import MsFailureTestCaseList from "./components/FailureTestCaseList";
|
||||
import MsRunningTaskList from "./components/RunningTaskList"
|
||||
import {getCurrentProjectID,getCurrentWorkspaceId} from "@/common/js/utils";
|
||||
|
||||
export default {
|
||||
name: "ApiTestHome",
|
||||
|
||||
components: {
|
||||
MsApiInfoCard, MsSceneInfoCard, MsScheduleTaskInfoCard, MsTestCaseInfoCard,
|
||||
MsApiDetailCard, MsSceneDetailCard, MsScheduleTaskDetailCard, MsTestCaseDetailCard,
|
||||
MsFailureTestCaseList,MsRunningTaskList,
|
||||
MsMainContainer, MsContainer
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
values: [],
|
||||
apiCountData:{},
|
||||
sceneCountData:{},
|
||||
testCaseCountData:{},
|
||||
scheduleTaskCountData:{},
|
||||
result: {},
|
||||
}
|
||||
},
|
||||
// activated() {
|
||||
// this.getValues();
|
||||
// },
|
||||
// mounted() {
|
||||
// this.getValues();
|
||||
// },
|
||||
created() {
|
||||
this.search();
|
||||
},
|
||||
methods: {
|
||||
|
||||
search() {
|
||||
let selectProjectId = getCurrentProjectID();
|
||||
this.$get("/api/apiCount/"+selectProjectId, response => {
|
||||
this.apiCountData = response.data;
|
||||
});
|
||||
|
||||
this.$get("/api/testSceneInfoCount/"+selectProjectId, response => {
|
||||
this.sceneCountData = response.data;
|
||||
});
|
||||
|
||||
this.$get("/api/testCaseInfoCount/"+selectProjectId, response => {
|
||||
this.testCaseCountData = response.data;
|
||||
});
|
||||
|
||||
|
||||
let workSpaceID = getCurrentWorkspaceId();
|
||||
this.$get("/api/scheduleTaskInfoCount/"+workSpaceID, response => {
|
||||
this.scheduleTaskCountData = response.data;
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.el-row {
|
||||
margin-bottom: 20px;
|
||||
margin-left: 20px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
</style>
|
|
@ -0,0 +1,62 @@
|
|||
<template>
|
||||
<el-card class="table-card" v-loading="result.loading">
|
||||
<template v-slot:header>
|
||||
<span class="title">
|
||||
{{$t('api_test.home_page.api_details_card.title')}}
|
||||
</span>
|
||||
</template>
|
||||
<el-container>
|
||||
<el-main>
|
||||
<div class="text item">
|
||||
{{$t('api_test.home_page.api_details_card.this_week_add',[apiCountData.thisWeekAddedCount])}}
|
||||
</div>
|
||||
</el-main>
|
||||
</el-container>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: "MsApiDetailCard",
|
||||
components: {},
|
||||
|
||||
data() {
|
||||
return {
|
||||
result: {},
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
props:{
|
||||
apiCountData:{},
|
||||
},
|
||||
|
||||
methods: {
|
||||
search() {
|
||||
// this.result = this.$get("/api/apiCount/5", response => {
|
||||
// this.apiCountData = response.data;
|
||||
// });
|
||||
},
|
||||
// link(row) {
|
||||
// this.$router.push({
|
||||
// path: '/api/report/view/' + row.id,
|
||||
// })
|
||||
// }
|
||||
},
|
||||
|
||||
created() {
|
||||
this.search();
|
||||
},
|
||||
activated() {
|
||||
this.search();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.el-aside {
|
||||
/*background-color: #D3DCE6;*/
|
||||
/*color: #333;*/
|
||||
text-align: center;
|
||||
/*line-height: 20;*/
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,63 @@
|
|||
<template>
|
||||
<el-card class="table-card" v-loading="result.loading">
|
||||
<template v-slot:header>
|
||||
<span class="title">
|
||||
{{$t('api_test.home_page.api_count_card.title')}}
|
||||
</span>
|
||||
</template>
|
||||
<el-container>
|
||||
<el-aside width="40%">
|
||||
<span class="countNumber">
|
||||
{{apiCountData.allApiDataCountNumber}}
|
||||
</span>
|
||||
{{$t('api_test.home_page.unit_of_measurement')}}
|
||||
</el-aside>
|
||||
<el-container>
|
||||
<el-main>
|
||||
<div class="text item">
|
||||
{{'HTTP: '+apiCountData.httpApiDataCountNumber}}
|
||||
</div>
|
||||
<div class="text item">
|
||||
{{'RPC:'+apiCountData.rpcApiDataCountNumber}}
|
||||
</div>
|
||||
<div class="text item">
|
||||
{{'TCP:'+apiCountData.tcpApiDataCountNumber}}
|
||||
</div>
|
||||
<div class="text item">
|
||||
{{'SQL:'+apiCountData.sqlApiDataCountNumber}}
|
||||
</div>
|
||||
</el-main>
|
||||
</el-container>
|
||||
</el-container>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: "MsApiInfoCard",
|
||||
|
||||
components: {},
|
||||
|
||||
data() {
|
||||
return {
|
||||
result: {},
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
props:{
|
||||
apiCountData:{},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.el-aside {
|
||||
/*background-color: #D3DCE6;*/
|
||||
/*color: #333;*/
|
||||
text-align: center;
|
||||
/*line-height: 20;*/
|
||||
}
|
||||
.countNumber{
|
||||
font-size: 40px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,57 @@
|
|||
<template>
|
||||
<el-card class="table-card" v-loading="result.loading">
|
||||
<template v-slot:header>
|
||||
<span class="title">
|
||||
{{$t('api_test.home_page.failed_case_list.title')}}
|
||||
</span>
|
||||
</template>
|
||||
<el-table border :data="tableData" class="adjust-table table-content" height="300px">
|
||||
<el-table-column prop="sortIndex" :label="$t('api_test.home_page.failed_case_list.table_coloum.index')" width="100" show-overflow-tooltip/>
|
||||
<el-table-column prop="caseName" :label="$t('api_test.home_page.failed_case_list.table_coloum.case_name')" width="250" show-overflow-tooltip/>
|
||||
<el-table-column prop="testPlan" :label="$t('api_test.home_page.failed_case_list.table_coloum.test_plan')" show-overflow-tooltip/>
|
||||
<el-table-column prop="failureTimes" :label="$t('api_test.home_page.failed_case_list.table_coloum.failure_times')" width="100" show-overflow-tooltip/>
|
||||
</el-table>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {getCurrentProjectID} from "@/common/js/utils";
|
||||
|
||||
export default {
|
||||
name: "MsFailureTestCaseList",
|
||||
|
||||
|
||||
data() {
|
||||
return {
|
||||
result: {},
|
||||
tableData: [],
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
search() {
|
||||
let projectID = getCurrentProjectID();
|
||||
this.result = this.$get("/api/faliureCaseAboutTestPlan/"+projectID+"/10", response => {
|
||||
this.tableData = response.data;
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
created() {
|
||||
this.search();
|
||||
},
|
||||
activated() {
|
||||
this.search();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.el-table {
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
</style>
|
|
@ -0,0 +1,79 @@
|
|||
<template>
|
||||
<el-card class="table-card" v-loading="result.loading">
|
||||
<template v-slot:header>
|
||||
<span class="title">
|
||||
{{$t('api_test.home_page.running_task_list.title')}}
|
||||
</span>
|
||||
</template>
|
||||
<el-table border :data="tableData" class="adjust-table table-content" height="300px">
|
||||
<el-table-column prop="index" :label="$t('api_test.home_page.running_task_list.table_coloum.index')" width="80" show-overflow-tooltip/>
|
||||
<el-table-column prop="scenario" :label="$t('api_test.home_page.running_task_list.table_coloum.scenario')" width="200" show-overflow-tooltip/>
|
||||
<el-table-column prop="rule" :label="$t('api_test.home_page.running_task_list.table_coloum.run_rule')" width="120" show-overflow-tooltip/>
|
||||
<el-table-column width="100" :label="$t('api_test.home_page.running_task_list.table_coloum.task_status')">
|
||||
<template v-slot:default="scope">
|
||||
<el-switch @click.stop.native v-model="scope.row.taskStatus" @change="updateTask(scope.row)"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column width="200" :label="$t('api_test.home_page.running_task_list.table_coloum.next_execution_time')">
|
||||
<template v-slot:default="scope">
|
||||
<span>{{ scope.row.nextExecutionTime | timestampFormatDate }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="creator" :label="$t('api_test.home_page.running_task_list.table_coloum.create_user')" width="150" show-overflow-tooltip/>
|
||||
<el-table-column width="200" :label="$t('api_test.home_page.running_task_list.table_coloum.update_time')">
|
||||
<template v-slot:default="scope">
|
||||
<span>{{ scope.row.updateTime | timestampFormatDate }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
</el-table>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {getCurrentProjectID,getCurrentWorkspaceId} from "@/common/js/utils";
|
||||
export default {
|
||||
name: "MsRunningTaskList",
|
||||
|
||||
|
||||
data() {
|
||||
return {
|
||||
value: '100',
|
||||
result: {},
|
||||
tableData: [],
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
search() {
|
||||
let workSpaceID = getCurrentWorkspaceId();
|
||||
this.result = this.$get("/api/runningTask/"+workSpaceID, response => {
|
||||
this.tableData = response.data;
|
||||
});
|
||||
},
|
||||
|
||||
updateTask(taskRow){
|
||||
|
||||
this.result = this.$post('/api/schedule/updateEnableByPrimyKey', taskRow, response => {
|
||||
this.search();
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
this.search();
|
||||
},
|
||||
activated() {
|
||||
this.search();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.el-table {
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
</style>
|
|
@ -0,0 +1,52 @@
|
|||
<template>
|
||||
<el-card class="table-card" v-loading="result.loading">
|
||||
<template v-slot:header>
|
||||
<span class="title">
|
||||
{{$t('api_test.home_page.test_scene_details_card.title')}}
|
||||
</span>
|
||||
</template>
|
||||
<el-container>
|
||||
<el-main>
|
||||
<div class="text item">
|
||||
{{$t('api_test.home_page.test_scene_details_card.this_week_add',[sceneCountData.thisWeekAddedCount])}}
|
||||
</div>
|
||||
<div class="text item">
|
||||
{{$t('api_test.home_page.test_scene_details_card.this_week_execute',[sceneCountData.thisWeekExecutedCount])}}
|
||||
</div>
|
||||
<div class="text item">
|
||||
{{$t('api_test.home_page.test_scene_details_card.executed',[sceneCountData.executedCount])}}
|
||||
</div>
|
||||
</el-main>
|
||||
</el-container>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: "MsSceneDetailCard",
|
||||
components: {},
|
||||
|
||||
data() {
|
||||
return {
|
||||
result: {},
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
},
|
||||
props:{
|
||||
sceneCountData:{},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.el-aside {
|
||||
/*background-color: #D3DCE6;*/
|
||||
/*color: #333;*/
|
||||
text-align: center;
|
||||
line-height: 100px;
|
||||
}
|
||||
|
||||
</style>
|
|
@ -0,0 +1,64 @@
|
|||
<template>
|
||||
<el-card class="table-card" v-loading="result.loading">
|
||||
<template v-slot:header>
|
||||
<span class="title">
|
||||
{{$t('api_test.home_page.test_scene_count_card.title')}}
|
||||
</span>
|
||||
</template>
|
||||
<el-container>
|
||||
<el-aside width="40%">
|
||||
<span class="countNumber">
|
||||
{{sceneCountData.allApiDataCountNumber}}
|
||||
</span>
|
||||
{{$t('api_test.home_page.unit_of_measurement')}}
|
||||
</el-aside>
|
||||
<el-container>
|
||||
<el-main>
|
||||
<div class="text item">
|
||||
</div>
|
||||
<div class="text item">
|
||||
</div>
|
||||
<div class="text item">
|
||||
</div>
|
||||
<div class="text item">
|
||||
</div>
|
||||
</el-main>
|
||||
</el-container>
|
||||
</el-container>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: "MsSceneInfoCard",
|
||||
|
||||
components: {},
|
||||
|
||||
data() {
|
||||
return {
|
||||
result: {},
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
|
||||
props:{
|
||||
sceneCountData:{},
|
||||
},
|
||||
|
||||
methods: {
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.el-aside {
|
||||
/*background-color: #D3DCE6;*/
|
||||
/*color: #333;*/
|
||||
text-align: center;
|
||||
line-height: 100px;
|
||||
}
|
||||
|
||||
.countNumber{
|
||||
font-size: 40px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,58 @@
|
|||
<template>
|
||||
<el-card class="table-card" v-loading="result.loading">
|
||||
<template v-slot:header>
|
||||
<span class="title">
|
||||
{{$t('api_test.home_page.schedule_task_details_card.title')}}
|
||||
</span>
|
||||
</template>
|
||||
<el-container>
|
||||
<el-main>
|
||||
<div class="text item">
|
||||
{{$t('api_test.home_page.schedule_task_details_card.this_week_add',[scheduleTaskCountData.thisWeekAddedCount])}}
|
||||
</div>
|
||||
<div class="text item">
|
||||
{{$t('api_test.home_page.schedule_task_details_card.this_week_execute',[scheduleTaskCountData.thisWeekExecutedCount])}}
|
||||
</div>
|
||||
<div class="text item">
|
||||
{{$t('api_test.home_page.schedule_task_details_card.executed',[scheduleTaskCountData.executedCount])}}
|
||||
</div>
|
||||
</el-main>
|
||||
</el-container>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: "MsTestCaseDetailCard",
|
||||
|
||||
components: {},
|
||||
|
||||
data() {
|
||||
return {
|
||||
result: {},
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
|
||||
props:{
|
||||
scheduleTaskCountData:{},
|
||||
},
|
||||
|
||||
methods: {
|
||||
},
|
||||
|
||||
created() {
|
||||
},
|
||||
activated() {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.el-aside {
|
||||
/*background-color: #D3DCE6;*/
|
||||
/*color: #333;*/
|
||||
text-align: center;
|
||||
/*line-height: 200px;*/
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,72 @@
|
|||
<template>
|
||||
<el-card class="table-card" v-loading="result.loading">
|
||||
<template v-slot:header>
|
||||
<span class="title">
|
||||
{{$t('api_test.home_page.schedule_task_count_card.title')}}
|
||||
</span>
|
||||
</template>
|
||||
<el-container>
|
||||
<el-aside width="40%">
|
||||
<span class="countNumber">
|
||||
{{scheduleTaskCountData.allApiDataCountNumber}}
|
||||
</span>
|
||||
{{$t('api_test.home_page.unit_of_measurement')}}
|
||||
</el-aside>
|
||||
<el-container>
|
||||
<el-main>
|
||||
<div class="text item">
|
||||
|
||||
</div>
|
||||
<div class="text item">
|
||||
|
||||
</div>
|
||||
<div class="text item">
|
||||
|
||||
</div>
|
||||
<div class="text item">
|
||||
|
||||
</div>
|
||||
</el-main>
|
||||
</el-container>
|
||||
</el-container>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: "MsScheduleTaskInfoCard",
|
||||
|
||||
components: {},
|
||||
|
||||
data() {
|
||||
return {
|
||||
result: {},
|
||||
apiCountData: {},
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
props:{
|
||||
scheduleTaskCountData:{},
|
||||
},
|
||||
methods: {
|
||||
},
|
||||
|
||||
created() {
|
||||
},
|
||||
activated() {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.el-aside {
|
||||
/*background-color: #D3DCE6;*/
|
||||
/*color: #333;*/
|
||||
text-align: center;
|
||||
/*line-height: 200px;*/
|
||||
}
|
||||
|
||||
.countNumber{
|
||||
font-size: 40px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,58 @@
|
|||
<template>
|
||||
<el-card class="table-card" v-loading="result.loading">
|
||||
<template v-slot:header>
|
||||
<span class="title">
|
||||
{{$t('api_test.home_page.test_case_details_card.title')}}
|
||||
</span>
|
||||
</template>
|
||||
<el-container>
|
||||
<el-main>
|
||||
<div class="text item">
|
||||
{{$t('api_test.home_page.test_case_details_card.this_week_add',[testCaseCountData.thisWeekAddedCount])}}
|
||||
</div>
|
||||
<div class="text item">
|
||||
{{$t('api_test.home_page.test_case_details_card.this_week_execute',[testCaseCountData.thisWeekExecutedCount])}}
|
||||
</div>
|
||||
<div class="text item">
|
||||
{{$t('api_test.home_page.test_case_details_card.executed',[testCaseCountData.executedCount])}}
|
||||
</div>
|
||||
</el-main>
|
||||
</el-container>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: "MsTestCaseDetailCard",
|
||||
|
||||
components: {},
|
||||
|
||||
data() {
|
||||
return {
|
||||
result: {},
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
|
||||
props:{
|
||||
testCaseCountData:{},
|
||||
},
|
||||
|
||||
methods: {
|
||||
},
|
||||
|
||||
created() {
|
||||
},
|
||||
activated() {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.el-aside {
|
||||
/*background-color: #D3DCE6;*/
|
||||
/*color: #333;*/
|
||||
text-align: center;
|
||||
/*line-height: 200px;*/
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,71 @@
|
|||
<template>
|
||||
<el-card class="table-card" v-loading="result.loading">
|
||||
<template v-slot:header>
|
||||
<span class="title">
|
||||
{{$t('api_test.home_page.test_case_count_card.title')}}
|
||||
</span>
|
||||
</template>
|
||||
<el-container>
|
||||
<el-aside width="40%">
|
||||
<span class="countNumber">
|
||||
{{testCaseCountData.allApiDataCountNumber}}
|
||||
</span>
|
||||
{{$t('api_test.home_page.unit_of_measurement')}}
|
||||
</el-aside>
|
||||
<el-container>
|
||||
<el-main>
|
||||
<div class="text item">
|
||||
{{'HTTP: '+testCaseCountData.httpApiDataCountNumber}}
|
||||
</div>
|
||||
<div class="text item">
|
||||
{{'RPC:'+testCaseCountData.rpcApiDataCountNumber}}
|
||||
</div>
|
||||
<div class="text item">
|
||||
{{'TCP:'+testCaseCountData.tcpApiDataCountNumber}}
|
||||
</div>
|
||||
<div class="text item">
|
||||
{{'SQL:'+testCaseCountData.sqlApiDataCountNumber}}
|
||||
</div>
|
||||
</el-main>
|
||||
</el-container>
|
||||
</el-container>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: "MsTestCaseInfoCard",
|
||||
|
||||
components: {},
|
||||
|
||||
data() {
|
||||
return {
|
||||
result: {},
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
props:{
|
||||
testCaseCountData:{},
|
||||
},
|
||||
methods: {
|
||||
},
|
||||
|
||||
created() {
|
||||
},
|
||||
activated() {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.el-aside {
|
||||
/*background-color: #D3DCE6;*/
|
||||
/*color: #333;*/
|
||||
text-align: center;
|
||||
/*line-height: 200px;*/
|
||||
}
|
||||
|
||||
.countNumber{
|
||||
font-size: 40px;
|
||||
}
|
||||
</style>
|
|
@ -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",
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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: {
|
||||
|
|
Loading…
Reference in New Issue