feat_接口定义_首页卡片可配置 --story=1003343 --user=王孝刚 首页展示卡片可配置 https://www.tapd.cn/55049933/s/1057199
This commit is contained in:
parent
2bd9f512da
commit
0a1e1c0914
|
@ -62,6 +62,12 @@ public class ApiDefinitionController {
|
|||
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
|
||||
return PageUtils.setPageInfo(page, apiDefinitionService.list(request));
|
||||
}
|
||||
@PostMapping("/week/list/{goPage}/{pageSize}")
|
||||
@RequiresPermissions("PROJECT_API_DEFINITION:READ")
|
||||
public Pager<List<ApiDefinitionResult>> weekList(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody ApiDefinitionRequest request) {
|
||||
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
|
||||
return PageUtils.setPageInfo(page, apiDefinitionService.weekList(request));
|
||||
}
|
||||
|
||||
@PostMapping("/list/relevance/{goPage}/{pageSize}")
|
||||
public Pager<List<ApiDefinitionResult>> listRelevance(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody ApiDefinitionRequest request) {
|
||||
|
|
|
@ -16,7 +16,15 @@ public class ApiDefinitionResult extends ApiDefinitionWithBLOBs {
|
|||
|
||||
private String caseStatus;
|
||||
|
||||
private String scenarioTotal;
|
||||
|
||||
private String casePassingRate;
|
||||
|
||||
private String deleteUser;
|
||||
|
||||
private String[] ids;
|
||||
|
||||
private String caseType;
|
||||
|
||||
private String scenarioType;
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy;
|
|||
import io.metersphere.api.dto.definition.request.sampler.MsTCPSampler;
|
||||
import io.metersphere.api.dto.mockconfig.MockConfigImportDTO;
|
||||
import io.metersphere.api.dto.scenario.Body;
|
||||
import io.metersphere.api.dto.scenario.Scenario;
|
||||
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
|
||||
import io.metersphere.api.dto.scenario.request.RequestType;
|
||||
import io.metersphere.api.dto.swaggerurl.SwaggerTaskResult;
|
||||
|
@ -132,6 +133,26 @@ public class ApiDefinitionService {
|
|||
return resList;
|
||||
}
|
||||
|
||||
public List<ApiDefinitionResult> weekList(ApiDefinitionRequest request) {
|
||||
//获取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 {
|
||||
request = this.initRequest(request, true, true);
|
||||
List<ApiDefinitionResult> resList = extApiDefinitionMapper.weekList(request, startTime.getTime());
|
||||
calculateResult(resList, request.getProjectId());
|
||||
calculateResultSce(resList);
|
||||
return resList;
|
||||
}
|
||||
}
|
||||
|
||||
public void initDefaultModuleId() {
|
||||
ApiDefinitionExample example = new ApiDefinitionExample();
|
||||
example.createCriteria().andModuleIdIsNull();
|
||||
|
@ -1198,6 +1219,20 @@ public class ApiDefinitionService {
|
|||
return resList;
|
||||
}
|
||||
|
||||
public void calculateResultSce(List<ApiDefinitionResult> resList) {
|
||||
if (!resList.isEmpty()) {
|
||||
resList.stream().forEach(res -> {
|
||||
List<Scenario> scenarioList = extApiDefinitionMapper.scenarioList(res.getId());
|
||||
String count = String.valueOf(scenarioList.size());
|
||||
res.setScenarioTotal(count);
|
||||
String[] strings = new String[scenarioList.size()];
|
||||
String[] ids2 = scenarioList.stream().map(Scenario::getId).collect(Collectors.toList()).toArray(strings);
|
||||
res.setIds(ids2);
|
||||
res.setScenarioType("scenario");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void calculateResult(List<ApiDefinitionResult> resList, String projectId) {
|
||||
if (!resList.isEmpty()) {
|
||||
List<String> ids = resList.stream().map(ApiDefinitionResult::getId).collect(Collectors.toList());
|
||||
|
@ -1206,6 +1241,7 @@ public class ApiDefinitionService {
|
|||
for (ApiDefinitionResult res : resList) {
|
||||
ApiComputeResult compRes = resultMap.get(res.getId());
|
||||
if (compRes != null) {
|
||||
res.setCaseType("apiCase");
|
||||
res.setCaseTotal(String.valueOf(compRes.getCaseTotal()));
|
||||
res.setCasePassingRate(compRes.getPassRate());
|
||||
// 状态优先级 未执行,未通过,通过
|
||||
|
@ -1217,6 +1253,7 @@ public class ApiDefinitionService {
|
|||
res.setCaseStatus(Translator.get("execute_pass"));
|
||||
}
|
||||
} else {
|
||||
res.setCaseType("apiCase");
|
||||
res.setCaseTotal("-");
|
||||
res.setCasePassingRate("-");
|
||||
res.setCaseStatus("-");
|
||||
|
|
|
@ -5,6 +5,7 @@ import io.metersphere.api.dto.definition.ApiComputeResult;
|
|||
import io.metersphere.api.dto.definition.ApiDefinitionRequest;
|
||||
import io.metersphere.api.dto.definition.ApiDefinitionResult;
|
||||
import io.metersphere.api.dto.definition.ApiSwaggerUrlDTO;
|
||||
import io.metersphere.api.dto.scenario.Scenario;
|
||||
import io.metersphere.base.domain.ApiDefinition;
|
||||
import io.metersphere.base.domain.ApiDefinitionExampleWithOperation;
|
||||
import io.metersphere.controller.request.BaseQueryRequest;
|
||||
|
@ -20,6 +21,10 @@ public interface ExtApiDefinitionMapper {
|
|||
|
||||
List<ApiDefinitionResult> list(@Param("request") ApiDefinitionRequest request);
|
||||
|
||||
List<ApiDefinitionResult> weekList(@Param("request") ApiDefinitionRequest request , @Param("startTimestamp") long startTimestamp );
|
||||
|
||||
List<Scenario> scenarioList(@Param("apiDefinitionId") String apiDefinitionId);
|
||||
|
||||
int moduleCount(@Param("request") ApiDefinitionRequest request);
|
||||
|
||||
//List<ApiComputeResult> selectByIds(@Param("ids") List<String> ids);
|
||||
|
|
|
@ -263,6 +263,30 @@
|
|||
</if>
|
||||
</select>
|
||||
|
||||
<select id="weekList" resultType="io.metersphere.api.dto.definition.ApiDefinitionResult">
|
||||
select api_definition.id, api_definition.project_id, api_definition.num, api_definition.tags,api_definition.follow_people,api_definition.original_state,
|
||||
api_definition.name,api_definition.protocol,api_definition.path,api_definition.module_id,api_definition.module_path,api_definition.method,
|
||||
api_definition.description,api_definition.environment_id,
|
||||
api_definition.status, api_definition.user_id, api_definition.create_time, api_definition.update_time, project.name as
|
||||
project_name, user.name as user_name,deleteUser.name AS delete_user,api_definition.delete_time, api_definition.remark
|
||||
from (select * from api_definition where update_time >= #{startTimestamp} order by update_time desc)api_definition
|
||||
left join project on api_definition.project_id = project.id
|
||||
left join user on api_definition.user_id = user.id
|
||||
left join user deleteUser on api_definition.delete_user_id = deleteUser.id
|
||||
<include refid="queryWhereCondition"/>
|
||||
<if test="request.orders != null and request.orders.size() > 0">
|
||||
order by
|
||||
<foreach collection="request.orders" separator="," item="order">
|
||||
<if test="order.name == 'user_name'">
|
||||
user_name ${order.type}
|
||||
</if>
|
||||
<if test="order.name != 'user_name'">
|
||||
api_definition.${order.name} ${order.type}
|
||||
</if>
|
||||
</foreach>
|
||||
</if>
|
||||
</select>
|
||||
|
||||
<select id="listByIds" resultType="io.metersphere.api.dto.definition.ApiDefinitionResult">
|
||||
select api_definition.id, api_definition.project_id, api_definition.num, api_definition.tags,api_definition.follow_people,
|
||||
api_definition.name,api_definition.protocol,api_definition.path,api_definition.module_id,api_definition.module_path,api_definition.method,
|
||||
|
@ -688,5 +712,13 @@
|
|||
</foreach>
|
||||
and api_definition.status != 'Trash';
|
||||
</select>
|
||||
<select id="scenarioList" resultType="io.metersphere.api.dto.scenario.Scenario">
|
||||
select DISTINCT t1.id
|
||||
from api_scenario t1
|
||||
join api_scenario_reference_id t2 on t1.id = t2.api_scenario_id
|
||||
join api_test_case t3 on t2.reference_id = t3.id and t2.reference_type = 'REF'
|
||||
where t3.api_definition_id = #{apiDefinitionId}
|
||||
and t3.`status`!='Trash'
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
|
|
|
@ -220,7 +220,8 @@
|
|||
<el-drawer :visible.sync="showReportVisible" :destroy-on-close="true" direction="ltr" :withHeader="true"
|
||||
:modal="false"
|
||||
size="90%">
|
||||
<ms-api-report-detail @invisible="showReportVisible = false" @refresh="search" :infoDb="infoDb" :report-id="showReportId" :currentProjectId="projectId"/>
|
||||
<ms-api-report-detail @invisible="showReportVisible = false" @refresh="search" :infoDb="infoDb"
|
||||
:report-id="showReportId" :currentProjectId="projectId"/>
|
||||
</el-drawer>
|
||||
<!--测试计划-->
|
||||
<el-drawer :visible.sync="planVisible" :destroy-on-close="true" direction="ltr" :withHeader="false"
|
||||
|
@ -248,7 +249,12 @@ import {downloadFile, getCurrentProjectID, getUUID, setDefaultTheme, strMapToObj
|
|||
import {API_SCENARIO_CONFIGS} from "@/business/components/common/components/search/search-components";
|
||||
import {API_SCENARIO_LIST, ORIGIN_COLOR} from "../../../../../common/js/constants";
|
||||
|
||||
import {buildBatchParam, getCustomTableHeader, getCustomTableWidth, getLastTableSortField} from "@/common/js/tableUtils";
|
||||
import {
|
||||
buildBatchParam,
|
||||
getCustomTableHeader,
|
||||
getCustomTableWidth,
|
||||
getLastTableSortField
|
||||
} from "@/common/js/tableUtils";
|
||||
import {API_SCENARIO_FILTERS} from "@/common/js/table-constants";
|
||||
import {scenario} from "@/business/components/track/plan/event-bus";
|
||||
import MsTable from "@/business/components/common/components/table/MsTable";
|
||||
|
@ -638,6 +644,15 @@ export default {
|
|||
this.condition.executeStatus = 'executePass';
|
||||
break;
|
||||
}
|
||||
if (this.selectDataRange != null) {
|
||||
let selectParamArr = this.selectDataRange.split(":");
|
||||
if (selectParamArr.length === 2) {
|
||||
if (selectParamArr[0] === "list") {
|
||||
let ids = selectParamArr[1].split(",");
|
||||
this.condition.ids = ids;
|
||||
}
|
||||
}
|
||||
}
|
||||
let url = "/api/automation/list/" + this.currentPage + "/" + this.pageSize;
|
||||
if (this.condition.projectId) {
|
||||
this.result = this.$post(url, this.condition, response => {
|
||||
|
|
|
@ -637,9 +637,13 @@ export default {
|
|||
if (this.selectDataRange == 'thisWeekCount') {
|
||||
this.condition.selectThisWeedData = true;
|
||||
} else if (this.selectDataRange != null) {
|
||||
let selectParamArr = this.selectDataRange.split("single:");
|
||||
let selectParamArr = this.selectDataRange.split(":");
|
||||
if (selectParamArr.length === 2) {
|
||||
if(selectParamArr[0] === "single") {
|
||||
this.condition.id = selectParamArr[1];
|
||||
}else {
|
||||
this.condition.apiDefinitionId = selectParamArr[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -3,25 +3,114 @@
|
|||
<ms-main-container v-loading="result.loading">
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="6">
|
||||
<ms-api-info-card @redirectPage="redirectPage" :api-count-data="apiCountData" :interface-coverage="apiCoverage"/>
|
||||
<ms-api-info-card @redirectPage="redirectPage" :api-count-data="apiCountData"
|
||||
:interface-coverage="apiCoverage"/>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<ms-test-case-info-card @redirectPage="redirectPage" :test-case-count-data="testCaseCountData"/>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<ms-scene-info-card @redirectPage="redirectPage" :scene-count-data="sceneCountData" :interface-coverage="interfaceCoverage"/>
|
||||
<ms-scene-info-card @redirectPage="redirectPage" :scene-count-data="sceneCountData"
|
||||
:interface-coverage="interfaceCoverage"/>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<ms-schedule-task-info-card :schedule-task-count-data="scheduleTaskCountData"/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
|
||||
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="12">
|
||||
<ms-failure-test-case-list @redirectPage="redirectPage"/>
|
||||
<el-card class="table-card" v-loading="result.loading" body-style="padding:10px;">
|
||||
<template v-slot:header>
|
||||
<el-col :span="22">
|
||||
<span class="title">
|
||||
{{ cardTitle.name }}
|
||||
</span>
|
||||
</el-col>
|
||||
<el-dropdown @command="handleCommand">
|
||||
<el-col :span="2" :offset="22">
|
||||
<el-link type="primary" :underline="false">
|
||||
<el-icon class="el-icon-more"></el-icon>
|
||||
</el-link>
|
||||
</el-col>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item command="caseTitle">
|
||||
<el-radio v-model="testTitleFirst" label="caseTitle">{{
|
||||
$t('api_test.home_page.failed_case_list.title')}}
|
||||
</el-radio>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item command="taskTitle">
|
||||
<el-radio v-model="testTitleFirst" label="taskTitle">
|
||||
{{ $t('api_test.home_page.running_task_list.title') }}
|
||||
</el-radio>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item command="newApiTitle">
|
||||
<el-radio v-model="testTitleFirst" label="newApiTitle">
|
||||
{{ $t('api_test.home_page.new_case_list.title') }}
|
||||
</el-radio>
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</template>
|
||||
<div v-if="testTitleFirst === 'caseTitle'">
|
||||
<ms-api-failure-test-case-list @redirectPage="redirectPage"/>
|
||||
</div>
|
||||
<div v-if="testTitleFirst === 'taskTitle'">
|
||||
<ms-api-running-task-list :call-from="'api_test'" @redirectPage="redirectPage"/>
|
||||
</div>
|
||||
<div v-if="testTitleFirst === 'newApiTitle'">
|
||||
<ms-api-new-test-case-list @redirectPage="redirectPage"/>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12">
|
||||
<ms-running-task-list :call-from="'api_test'" @redirectPage="redirectPage"/>
|
||||
<el-card class="table-card" v-loading="result.loading" body-style="padding:10px;">
|
||||
<div v-if="testTitleSecond === 'caseTitle'">
|
||||
<ms-api-failure-test-case-list @redirectPage="redirectPage" />
|
||||
</div>
|
||||
<div v-if="testTitleSecond === 'taskTitle'">
|
||||
<ms-api-running-task-list :call-from="'api_test'" @redirectPage="redirectPage"/>
|
||||
</div>
|
||||
<div v-if="testTitleSecond === 'newApiTitle'">
|
||||
<ms-api-new-test-case-list @redirectPage="redirectPage"/>
|
||||
</div>
|
||||
<template v-slot:header>
|
||||
<el-col :span="22">
|
||||
<span class="title">
|
||||
{{ cardTitleSecond.name }}
|
||||
</span>
|
||||
</el-col>
|
||||
<el-dropdown @command="handleCommandSecond">
|
||||
<el-col :span="2" :offset="22">
|
||||
<el-link type="primary" :underline="false">
|
||||
<el-icon class="el-icon-more"></el-icon>
|
||||
</el-link>
|
||||
</el-col>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item command="caseTitle">
|
||||
<el-radio v-model="testTitleSecond" label="caseTitle">{{
|
||||
$t('api_test.home_page.failed_case_list.title')
|
||||
}}
|
||||
</el-radio>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item command="taskTitle">
|
||||
<el-radio v-model="testTitleSecond" label="taskTitle">
|
||||
{{ $t('api_test.home_page.running_task_list.title') }}
|
||||
</el-radio>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item command="newApiTitle">
|
||||
<el-radio v-model="testTitleSecond" label="newApiTitle">
|
||||
{{ $t('api_test.home_page.new_case_list.title') }}
|
||||
</el-radio>
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</template>
|
||||
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
|
@ -37,17 +126,20 @@ import MsSceneInfoCard from "./components/SceneInfoCard";
|
|||
import MsScheduleTaskInfoCard from "./components/ScheduleTaskInfoCard";
|
||||
import MsTestCaseInfoCard from "./components/TestCaseInfoCard";
|
||||
|
||||
import MsApiFailureTestCaseList from "./components/ApiFailureTestCaseList";
|
||||
import MsFailureTestCaseList from "./components/FailureTestCaseList";
|
||||
import MsRunningTaskList from "./components/RunningTaskList"
|
||||
import MsRunningTaskList from "./components/RunningTaskList";
|
||||
import MsApiRunningTaskList from "./components/ApiRunningTaskList";
|
||||
import {getCurrentProjectID, getUUID} from "@/common/js/utils";
|
||||
import MsApiNewTestCaseList from "./components/ApiNewTestCaseList";
|
||||
|
||||
export default {
|
||||
name: "ApiTestHomePage",
|
||||
|
||||
components: {
|
||||
MsApiInfoCard, MsSceneInfoCard, MsScheduleTaskInfoCard, MsTestCaseInfoCard,
|
||||
MsFailureTestCaseList, MsRunningTaskList,
|
||||
MsMainContainer, MsContainer
|
||||
MsApiFailureTestCaseList, MsRunningTaskList,
|
||||
MsMainContainer, MsContainer,MsFailureTestCaseList,MsApiRunningTaskList,MsApiNewTestCaseList
|
||||
},
|
||||
|
||||
data() {
|
||||
|
@ -60,14 +152,85 @@ export default {
|
|||
interfaceCoverage: "waitting...",
|
||||
apiCoverage: "waitting...",
|
||||
result: {},
|
||||
testTitleFirst: " ",
|
||||
testTitleSecond: " ",
|
||||
cardTitle: {},
|
||||
cardTitleSecond: {},
|
||||
}
|
||||
},
|
||||
activated() {
|
||||
this.search();
|
||||
},
|
||||
created() {
|
||||
this.testTitleFirst = "caseTitle";
|
||||
if (localStorage.getItem("cardTitle")) {
|
||||
if (localStorage.getItem("titleFirst")) {
|
||||
this.testTitleFirst = localStorage.getItem("titleFirst");
|
||||
}
|
||||
this.cardTitle.name = localStorage.getItem("cardTitle");
|
||||
} else{
|
||||
this.cardTitle.name=this.$t('api_test.home_page.failed_case_list.title');
|
||||
}
|
||||
this.testTitleSecond = "taskTitle";
|
||||
if (localStorage.getItem("cardTitleSecond")) {
|
||||
if (localStorage.getItem("titleSecond")) {
|
||||
this.testTitleSecond = localStorage.getItem("titleSecond");
|
||||
}
|
||||
this.cardTitleSecond.name = localStorage.getItem("cardTitleSecond");
|
||||
} else{
|
||||
this.cardTitleSecond.name=this.$t('api_test.home_page.running_task_list.title');
|
||||
}
|
||||
|
||||
},
|
||||
methods: {
|
||||
handleCommand(cmd) {
|
||||
if(cmd){
|
||||
switch (cmd) {
|
||||
case "caseTitle":
|
||||
this.cardTitle.name=this.$t('api_test.home_page.failed_case_list.title');
|
||||
localStorage.setItem("cardTitle" , this.cardTitle.name);
|
||||
localStorage.setItem("titleFirst" , "caseTitle");
|
||||
break;
|
||||
case "taskTitle":
|
||||
this.cardTitle.name = this.$t('api_test.home_page.running_task_list.title');
|
||||
localStorage.setItem("cardTitle" , this.cardTitle.name);
|
||||
localStorage.setItem("titleFirst" , "taskTitle");
|
||||
break;
|
||||
case "newApiTitle":
|
||||
this.cardTitle.name = this.$t('api_test.home_page.new_case_list.title');
|
||||
localStorage.setItem("cardTitle" , this.cardTitle.name);
|
||||
localStorage.setItem("titleFirst" , "newApiTitle");
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
handleCommandSecond(cmd) {
|
||||
if(cmd){
|
||||
switch (cmd) {
|
||||
case "caseTitle":
|
||||
this.cardTitleSecond.name=this.$t('api_test.home_page.failed_case_list.title');
|
||||
localStorage.setItem("cardTitleSecond" , this.cardTitleSecond.name);
|
||||
localStorage.setItem("titleSecond" , "caseTitle");
|
||||
break;
|
||||
case "taskTitle":
|
||||
this.cardTitleSecond.name = this.$t('api_test.home_page.running_task_list.title');
|
||||
localStorage.setItem("cardTitleSecond" , this.cardTitleSecond.name);
|
||||
localStorage.setItem("titleSecond" , "taskTitle");
|
||||
break;
|
||||
case "newApiTitle":
|
||||
this.cardTitleSecond.name = this.$t('api_test.home_page.new_case_list.title');
|
||||
localStorage.setItem("cardTitleSecond" , this.cardTitleSecond.name);
|
||||
localStorage.setItem("titleSecond" , "newApiTitle");
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
reload() {
|
||||
this.loading = true
|
||||
this.$nextTick(() => {
|
||||
this.loading = false
|
||||
});
|
||||
},
|
||||
search() {
|
||||
let selectProjectId = getCurrentProjectID();
|
||||
debugger
|
||||
|
@ -96,16 +259,22 @@ export default {
|
|||
this.scheduleTaskCountData = response.data;
|
||||
});
|
||||
},
|
||||
redirectPage(page,dataType,selectType){
|
||||
redirectPage(page, dataType, selectType, title) {
|
||||
//api页面跳转
|
||||
//传入UUID是为了进行页面重新加载判断
|
||||
let uuid = getUUID();
|
||||
switch (page) {
|
||||
case "api":
|
||||
this.$router.push({name:'ApiDefinition',params:{redirectID:uuid,dataType:dataType,dataSelectRange:selectType}});
|
||||
this.$router.push({
|
||||
name: 'ApiDefinition',
|
||||
params: {redirectID: uuid, dataType: dataType, dataSelectRange: selectType}
|
||||
});
|
||||
break;
|
||||
case "scenario":
|
||||
this.$router.push({name:'ApiAutomation',params:{redirectID:uuid,dataType:dataType,dataSelectRange:selectType}});
|
||||
this.$router.push({
|
||||
name: 'ApiAutomation',
|
||||
params: {redirectID: uuid, dataType: dataType, dataSelectRange: selectType}
|
||||
});
|
||||
break;
|
||||
case "testPlanEdit":
|
||||
this.$router.push('/track/plan/view/' + selectType)
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
<template>
|
||||
<div class="table-card" v-loading="result.loading" body-style="padding:10px;">
|
||||
<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="150">
|
||||
<template v-slot:default="{row}">
|
||||
<el-link type="info" @click="redirect(row.caseType,row.id)">
|
||||
{{ row.caseName }}
|
||||
</el-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="caseType"
|
||||
column-key="caseType"
|
||||
:label="$t('api_test.home_page.failed_case_list.table_coloum.case_type')"
|
||||
width="150"
|
||||
show-overflow-tooltip>
|
||||
<template v-slot:default="scope">
|
||||
<ms-tag v-if="scope.row.caseType == 'apiCase'" type="success" effect="plain" :content="$t('api_test.home_page.failed_case_list.table_value.case_type.api')"/>
|
||||
<ms-tag v-if="scope.row.caseType == 'scenario'" type="warning" effect="plain" :content="$t('api_test.home_page.failed_case_list.table_value.case_type.scene')"/>
|
||||
<ms-tag v-if="scope.row.caseType == 'load'" type="danger" effect="plain" :content="$t('api_test.home_page.failed_case_list.table_value.case_type.load')"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="testPlan" :label="$t('api_test.home_page.failed_case_list.table_coloum.test_plan')">
|
||||
<template v-slot:default="{row}">
|
||||
<div v-for="(testPlan, index) in row.testPlanDTOList" :key="index">
|
||||
<el-link type="info" @click="redirect('testPlanEdit',testPlan.id)">
|
||||
{{ testPlan.name }};
|
||||
</el-link>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<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>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MsTag from "@/business/components/common/components/MsTag";
|
||||
import {getCurrentProjectID} from "@/common/js/utils";
|
||||
|
||||
export default {
|
||||
name: "MsApiFailureTestCaseList",
|
||||
|
||||
components: {
|
||||
MsTag
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
result: {},
|
||||
tableData: [],
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
projectId() {
|
||||
return getCurrentProjectID();
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
search() {
|
||||
if (this.projectId) {
|
||||
this.result = this.$get("/api/faliureCaseAboutTestPlan/"+ this.projectId +"/10", response => {
|
||||
this.tableData = response.data;
|
||||
});
|
||||
}
|
||||
},
|
||||
redirect(pageType,param){
|
||||
switch (pageType){
|
||||
case "testPlanEdit":
|
||||
this.$emit('redirectPage','testPlanEdit',null, param);
|
||||
break;
|
||||
case "apiCase":
|
||||
this.$emit('redirectPage','api','apiTestCase', 'single:'+param);
|
||||
break;
|
||||
case "scenario":
|
||||
this.$emit('redirectPage','scenario','scenario', 'edit:'+param);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
created() {
|
||||
this.search();
|
||||
},
|
||||
activated() {
|
||||
this.search();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.el-table {
|
||||
cursor:pointer;
|
||||
}
|
||||
.el-card /deep/ .el-card__header {
|
||||
border-bottom: 0px solid #EBEEF5;
|
||||
}
|
||||
|
||||
</style>
|
|
@ -0,0 +1,217 @@
|
|||
<template>
|
||||
<div class="table-card" v-loading="result.loading" body-style="padding:10px;">
|
||||
<el-table border :data="tableData" class="adjust-table table-content" height="300px">
|
||||
<el-table-column prop="num" :label="$t('api_test.home_page.new_case_list.table_coloum.index')" width="100"
|
||||
show-overflow-tooltip/>
|
||||
<el-table-column prop="name" :label="$t('api_test.home_page.new_case_list.table_coloum.api_name')" width="150">
|
||||
</el-table-column>
|
||||
<el-table-column prop="path" :label="$t('api_test.home_page.new_case_list.table_coloum.path')" width="150">
|
||||
|
||||
</el-table-column>
|
||||
<el-table-column prop="status" :label="$t('api_test.home_page.new_case_list.table_coloum.api_status')">
|
||||
<template v-slot:default="scope">
|
||||
<span class="el-dropdown-link">
|
||||
<api-status :value="scope.row.status"/>
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('api_test.home_page.new_case_list.table_coloum.update_time')" width="170">
|
||||
<template v-slot:default="scope">
|
||||
<span>{{ scope.row.updateTime | timestampFormatDate }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="caseTotal" :label="$t('api_test.home_page.new_case_list.table_coloum.relation_case')"
|
||||
width="150">
|
||||
<template v-slot:default="{row}">
|
||||
<el-link type="info" @click="redirect(row.caseType,row.id)">
|
||||
{{ row.caseTotal }}
|
||||
</el-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="scenarioTotal"
|
||||
:label="$t('api_test.home_page.new_case_list.table_coloum.relation_scenario')">
|
||||
<template v-slot:default="{row}">
|
||||
<el-link type="info" @click="redirect(row.scenarioType,row.ids)">
|
||||
{{ row.scenarioTotal }}
|
||||
</el-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
</el-table>
|
||||
<ms-table-pagination :change="search" :current-page.sync="currentPage" :page-size.sync="pageSize"
|
||||
:total="total"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MsTag from "@/business/components/common/components/MsTag";
|
||||
import {getCurrentProjectID} from "@/common/js/utils";
|
||||
import {API_DEFINITION_CONFIGS} from "@/business/components/common/components/search/search-components";
|
||||
import {API_STATUS} from "@/business/components/api/definition/model/JsonData";
|
||||
import ApiStatus from "@/business/components/api/definition/components/list/ApiStatus";
|
||||
import MsTablePagination from "../../../common/pagination/TablePagination";
|
||||
import {initCondition} from "@/common/js/tableUtils";
|
||||
|
||||
export default {
|
||||
name: "MsApiNewTestCaseList",
|
||||
|
||||
components: {
|
||||
MsTag, ApiStatus, MsTablePagination
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
result: {},
|
||||
tableData: [],
|
||||
loading: false,
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
condition: {
|
||||
components: API_DEFINITION_CONFIGS,
|
||||
},
|
||||
status: API_STATUS,
|
||||
currentProtocol: "HTTP",
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
projectId() {
|
||||
return getCurrentProjectID();
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
search(currentProtocol) {
|
||||
if (this.$refs.table) {
|
||||
this.$refs.table.clear();
|
||||
}
|
||||
initCondition(this.condition, this.condition.selectAll);
|
||||
this.selectDataCounts = 0;
|
||||
if (!this.trashEnable) {
|
||||
this.condition.moduleIds = this.selectNodeIds;
|
||||
}
|
||||
this.condition.projectId = this.projectId;
|
||||
if (this.currentProtocol != null) {
|
||||
this.condition.protocol = this.currentProtocol;
|
||||
}
|
||||
|
||||
this.enableOrderDrag = (this.condition.orders && this.condition.orders.length) > 0 ? false : true;
|
||||
|
||||
//检查是否只查询本周数据
|
||||
this.getSelectDataRange();
|
||||
this.condition.selectThisWeedData = false;
|
||||
this.condition.apiCaseCoverage = null;
|
||||
switch (this.selectDataRange) {
|
||||
case 'thisWeekCount':
|
||||
this.condition.selectThisWeedData = true;
|
||||
break;
|
||||
case 'uncoverage':
|
||||
this.condition.apiCaseCoverage = 'uncoverage';
|
||||
break;
|
||||
case 'coverage':
|
||||
this.condition.apiCaseCoverage = 'coverage';
|
||||
break;
|
||||
case 'Prepare':
|
||||
this.condition.filters.status = [this.selectDataRange];
|
||||
break;
|
||||
case 'Completed':
|
||||
this.condition.filters.status = [this.selectDataRange];
|
||||
break;
|
||||
case 'Underway':
|
||||
this.condition.filters.status = [this.selectDataRange];
|
||||
break;
|
||||
}
|
||||
if (currentProtocol) {
|
||||
this.condition.moduleIds = [];
|
||||
}
|
||||
if (this.condition.projectId) {
|
||||
this.result = this.$post("/api/definition/week/list/" + this.currentPage + "/" + this.pageSize, this.condition, response => {
|
||||
this.total = response.data.itemCount;
|
||||
this.tableData = response.data.listObject;
|
||||
});
|
||||
}
|
||||
},
|
||||
genProtocalFilter(protocalType) {
|
||||
if (protocalType === "HTTP") {
|
||||
this.methodFilters = [
|
||||
{text: 'GET', value: 'GET'},
|
||||
{text: 'POST', value: 'POST'},
|
||||
{text: 'PUT', value: 'PUT'},
|
||||
{text: 'PATCH', value: 'PATCH'},
|
||||
{text: 'DELETE', value: 'DELETE'},
|
||||
{text: 'OPTIONS', value: 'OPTIONS'},
|
||||
{text: 'HEAD', value: 'HEAD'},
|
||||
{text: 'CONNECT', value: 'CONNECT'},
|
||||
];
|
||||
} else if (protocalType === "TCP") {
|
||||
this.methodFilters = [
|
||||
{text: 'TCP', value: 'TCP'},
|
||||
];
|
||||
} else if (protocalType === "SQL") {
|
||||
this.methodFilters = [
|
||||
{text: 'SQL', value: 'SQL'},
|
||||
];
|
||||
} else if (protocalType === "DUBBO") {
|
||||
this.methodFilters = [
|
||||
{text: 'DUBBO', value: 'DUBBO'},
|
||||
{text: 'dubbo://', value: 'dubbo://'},
|
||||
];
|
||||
} else {
|
||||
this.methodFilters = [
|
||||
{text: 'GET', value: 'GET'},
|
||||
{text: 'POST', value: 'POST'},
|
||||
{text: 'PUT', value: 'PUT'},
|
||||
{text: 'PATCH', value: 'PATCH'},
|
||||
{text: 'DELETE', value: 'DELETE'},
|
||||
{text: 'OPTIONS', value: 'OPTIONS'},
|
||||
{text: 'HEAD', value: 'HEAD'},
|
||||
{text: 'CONNECT', value: 'CONNECT'},
|
||||
{text: 'DUBBO', value: 'DUBBO'},
|
||||
{text: 'dubbo://', value: 'dubbo://'},
|
||||
{text: 'SQL', value: 'SQL'},
|
||||
{text: 'TCP', value: 'TCP'},
|
||||
];
|
||||
}
|
||||
},
|
||||
//判断是否只显示本周的数据。 从首页跳转过来的请求会带有相关参数
|
||||
getSelectDataRange() {
|
||||
let dataRange = this.$route.params.dataSelectRange;
|
||||
let dataType = this.$route.params.dataType;
|
||||
if (dataType === 'api') {
|
||||
this.selectDataRange = dataRange;
|
||||
} else {
|
||||
this.selectDataRange = 'all';
|
||||
}
|
||||
},
|
||||
redirect(pageType, param) {
|
||||
switch (pageType) {
|
||||
case "apiCase":
|
||||
this.$emit('redirectPage', 'api', 'apiTestCase', 'singleList:' + param);
|
||||
break;
|
||||
case "scenario":
|
||||
if(param) {
|
||||
this.$emit('redirectPage', 'scenario', 'scenario', 'list:' + param);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.search();
|
||||
},
|
||||
activated() {
|
||||
this.search();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.el-table {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.el-card /deep/ .el-card__header {
|
||||
border-bottom: 0px solid #EBEEF5;
|
||||
}
|
||||
|
||||
</style>
|
|
@ -0,0 +1,181 @@
|
|||
<template>
|
||||
<div class="table-card" v-loading="result.loading" body-style="padding:10px;">
|
||||
|
||||
<ms-table
|
||||
:enable-selection="false"
|
||||
:condition="condition"
|
||||
:data="tableData"
|
||||
@refresh="search"
|
||||
screen-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="name" :label="$t('commons.name')" width="200" >
|
||||
<template v-slot:default="{row}">
|
||||
<!-- 若为只读用户不可点击之后跳转-->
|
||||
<span v-if="isReadOnly">
|
||||
{{ row.name }}
|
||||
</span>
|
||||
<el-link v-else type="info" @click="redirect(row)">
|
||||
{{ row.name }}
|
||||
</el-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<ms-table-column
|
||||
prop="taskType"
|
||||
:filters="typeFilters"
|
||||
:label="$t('api_test.home_page.running_task_list.table_coloum.task_type')" width="120">
|
||||
<template v-slot:default="scope">
|
||||
<ms-tag v-if="scope.row.taskGroup == 'API_SCENARIO_TEST'" type="success" effect="plain" :content="$t('api_test.home_page.running_task_list.scenario_schedule')"/>
|
||||
<ms-tag v-if="scope.row.taskGroup == 'TEST_PLAN_TEST'" type="warning" effect="plain" :content="$t('api_test.home_page.running_task_list.test_plan_schedule')"/>
|
||||
<ms-tag v-if="scope.row.taskGroup == 'SWAGGER_IMPORT'" type="danger" effect="plain" :content="$t('api_test.home_page.running_task_list.swagger_schedule')"/>
|
||||
</template>
|
||||
</ms-table-column>
|
||||
<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">
|
||||
<div>
|
||||
<el-switch
|
||||
:disabled="isReadOnly"
|
||||
v-model="scope.row.taskStatus"
|
||||
class="captcha-img"
|
||||
@change="closeTaskConfirm(scope.row)"
|
||||
></el-switch>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
</el-table-column>
|
||||
<el-table-column width="170" :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="100" show-overflow-tooltip/>
|
||||
<el-table-column width="170" :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>
|
||||
|
||||
</ms-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MsTag from "@/business/components/common/components/MsTag";
|
||||
import {getCurrentProjectID} from "@/common/js/utils";
|
||||
import MsTable from "@/business/components/common/components/table/MsTable";
|
||||
import MsTableColumn from "@/business/components/common/components/table/MsTableColumn";
|
||||
export default {
|
||||
name: "MsApiRunningTaskList",
|
||||
components: {
|
||||
MsTableColumn,
|
||||
MsTable,
|
||||
MsTag
|
||||
},
|
||||
props: {
|
||||
callFrom: String,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
value: '100',
|
||||
result: {},
|
||||
tableData: [],
|
||||
visible: false,
|
||||
loading: false,
|
||||
typeFilters: [],
|
||||
condition: {
|
||||
filters: {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
computed:{
|
||||
isReadOnly(){
|
||||
return false;
|
||||
},
|
||||
projectId() {
|
||||
return getCurrentProjectID();
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
if (this.callFrom === 'api_test') {
|
||||
this.typeFilters = [
|
||||
{text: this.$t('api_test.home_page.running_task_list.scenario_schedule'), value: 'API_SCENARIO_TEST'},
|
||||
{text: this.$t('api_test.home_page.running_task_list.swagger_schedule'), value: 'SWAGGER_IMPORT'},
|
||||
];
|
||||
} else {
|
||||
this.typeFilters = [
|
||||
{text: this.$t('api_test.home_page.running_task_list.test_plan_schedule'), value: 'TEST_PLAN_TEST'}
|
||||
];
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
search() {
|
||||
if (!this.condition.filters.task_type) {
|
||||
if (this.callFrom === 'api_test') {
|
||||
this.condition.filters.task_type = ['SWAGGER_IMPORT', 'API_SCENARIO_TEST'];
|
||||
} else {
|
||||
this.condition.filters.task_type = ['TEST_PLAN_TEST'];
|
||||
}
|
||||
}
|
||||
if (this.projectId) {
|
||||
this.result = this.$post('/api/runningTask/' + this.projectId, this.condition, response => {
|
||||
this.tableData = response.data;
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
closeTaskConfirm(row){
|
||||
let flag = row.taskStatus;
|
||||
row.taskStatus = !flag; //保持switch点击前的状态
|
||||
this.$confirm(this.$t('api_test.home_page.running_task_list.confirm.close_title'), this.$t('commons.prompt'), {
|
||||
confirmButtonText: this.$t('commons.confirm'),
|
||||
cancelButtonText: this.$t('commons.cancel'),
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.updateTask(row);
|
||||
}).catch(() => {
|
||||
});
|
||||
},
|
||||
|
||||
updateTask(taskRow){
|
||||
|
||||
this.result = this.$post('/api/schedule/updateEnableByPrimyKey/disable', taskRow, response => {
|
||||
this.search();
|
||||
});
|
||||
},
|
||||
redirect(param){
|
||||
if(param.taskGroup === 'TEST_PLAN_TEST'){
|
||||
this.$emit('redirectPage','testPlanEdit','', param.scenarioId);
|
||||
}else if (param.taskGroup === 'API_SCENARIO_TEST') {
|
||||
this.$emit('redirectPage', 'scenario', 'scenario', 'edit:' + param.scenarioId);
|
||||
} else if (param.taskGroup === 'SWAGGER_IMPORT') {
|
||||
this.$emit('redirectPage', 'api', 'api', {param});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
this.search();
|
||||
},
|
||||
activated() {
|
||||
this.search();
|
||||
},
|
||||
handleStatus(scope) {
|
||||
// console.log(scope.row.userId)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.el-table {
|
||||
cursor:pointer;
|
||||
}
|
||||
.el-card /deep/ .el-card__header {
|
||||
border-bottom: 0px solid #EBEEF5;
|
||||
}
|
||||
|
||||
</style>
|
|
@ -1277,6 +1277,7 @@ export default {
|
|||
pool_max: "Max Number of Configuration",
|
||||
query_timeout: "Max Wait(ms)",
|
||||
name_cannot_be_empty: "SQL request name cannot be empty",
|
||||
tips: "Tips: Allowmultiqueries = true should be configured to execute multiple SQL statements",
|
||||
dataSource_cannot_be_empty: "SQL request datasource cannot be empty",
|
||||
result_variable: "Result variable",
|
||||
variable_names: "Variable names",
|
||||
|
@ -1423,6 +1424,18 @@ export default {
|
|||
}
|
||||
}
|
||||
},
|
||||
new_case_list: {
|
||||
title: "Updated interfaces in the past 7 days",
|
||||
table_coloum: {
|
||||
index: "ID",
|
||||
api_name: "Api name",
|
||||
path: "path",
|
||||
api_status: "Api status",
|
||||
update_time: "Update time",
|
||||
relation_case: "Relation CASE",
|
||||
relation_scenario: "Relation Scenario"
|
||||
},
|
||||
},
|
||||
running_task_list: {
|
||||
title: "Running schedule task",
|
||||
table_coloum: {
|
||||
|
|
|
@ -1432,6 +1432,18 @@ export default {
|
|||
}
|
||||
}
|
||||
},
|
||||
new_case_list: {
|
||||
title: "过去7天有更新的接口",
|
||||
table_coloum: {
|
||||
index: "ID",
|
||||
api_name: "接口名称",
|
||||
path: "路径",
|
||||
api_status: "状态",
|
||||
update_time: "更新时间",
|
||||
relation_case: "关联CASE",
|
||||
relation_scenario: "关联场景"
|
||||
},
|
||||
},
|
||||
running_task_list: {
|
||||
title: "运行中的定时任务",
|
||||
table_coloum: {
|
||||
|
|
|
@ -1121,6 +1121,7 @@ export default {
|
|||
common_config: "通用配置",
|
||||
http_config: "HTTP配置",
|
||||
database_config: "數據庫配置",
|
||||
tips: "Tips: 執行多條SQL語句需配寘allowMultiQueries=true",
|
||||
tcp_config: "TCP配置",
|
||||
import: "導入環境",
|
||||
request_timeout: "鏈接超時",
|
||||
|
@ -1432,6 +1433,18 @@ export default {
|
|||
}
|
||||
}
|
||||
},
|
||||
new_case_list: {
|
||||
title: "過去7天有更新的接口",
|
||||
table_coloum: {
|
||||
index: "ID",
|
||||
api_name: "接口名稱",
|
||||
path: "路徑",
|
||||
api_status: "狀態",
|
||||
update_time: "更新時間",
|
||||
relation_case: "關聯CASE",
|
||||
relation_scenario: "關聯場景"
|
||||
},
|
||||
},
|
||||
running_task_list: {
|
||||
title: "運行中的定時任務",
|
||||
table_coloum: {
|
||||
|
|
Loading…
Reference in New Issue