feat(接口测试): 接口测试增加已开启的定时任务统计功能

接口测试增加已开启的定时任务统计功能
This commit is contained in:
song-tianyang 2022-11-17 18:22:12 +08:00 committed by 建国
parent 5d8f47f2eb
commit 3a1d5f562b
7 changed files with 256 additions and 63 deletions

View File

@ -26,11 +26,7 @@
<select id="countByProjectIDAndCreateInThisWeek" resultType="java.lang.Long"> <select id="countByProjectIDAndCreateInThisWeek" resultType="java.lang.Long">
SELECT count(id) AS countNumber SELECT count(id) AS countNumber
FROM api_case_execution_info FROM api_case_execution_info
WHERE source_id IN ( WHERE project_id = #{projectId}
SELECT testCase.id
FROM api_test_case testCase
WHERE testCase.project_id = #{projectId}
)
<if test="version != null"> <if test="version != null">
AND version = #{version} AND version = #{version}
</if> </if>

View File

@ -31,6 +31,9 @@ export function genPerformanceTestXml(file, files, params) {
return fileUpload(url, file, files, params); return fileUpload(url, file, files, params);
} }
export function getRunningTask(selectProjectId, currentPage, pageSize, param) {
return post("/task/center/runningTask/" + selectProjectId + "/" + currentPage + "/" + pageSize, param);
}
export function formatNumber(param) { export function formatNumber(param) {
let num = (param || 0).toString(), result = ''; let num = (param || 0).toString(), result = '';

View File

@ -282,7 +282,7 @@ import MsEnvironmentSelect from "./components/case/MsEnvironmentSelect";
import {PROJECT_ID, WORKSPACE_ID} from "metersphere-frontend/src/utils/constants"; import {PROJECT_ID, WORKSPACE_ID} from "metersphere-frontend/src/utils/constants";
import {useApiStore} from "@/store"; import {useApiStore} from "@/store";
import {buildTree} from "metersphere-frontend/src/model/NodeTree"; import {buildTree} from "metersphere-frontend/src/model/NodeTree";
import {createMockConfig, getMockApiParams, getTcpMockInfo, mockExpectConfig} from "@/api/api-mock"; import {createMockConfig, getMockApiParams, mockExpectConfig} from "@/api/api-mock";
import MockEditDrawer from "@/business/definition/components/mock/MockEditDrawer"; import MockEditDrawer from "@/business/definition/components/mock/MockEditDrawer";
const store = useApiStore(); const store = useApiStore();
@ -407,6 +407,9 @@ export default {
this.$nextTick(() => { this.$nextTick(() => {
let routeParamObj = this.$route.params; let routeParamObj = this.$route.params;
if (routeParamObj) { if (routeParamObj) {
if (routeParamObj.dataType === 'swagger') {
this.openSwaggerScheduleTab();
} else {
let dataRange = routeParamObj.dataSelectRange; let dataRange = routeParamObj.dataSelectRange;
if (dataRange && dataRange.length > 0) { if (dataRange && dataRange.length > 0) {
this.activeDom = 'middle'; this.activeDom = 'middle';
@ -420,25 +423,18 @@ export default {
} }
} }
this.selectNodeIds = []; this.selectNodeIds = [];
}
} else { } else {
let dataType = this.$route.params.dataType; let dataType = this.$route.params.dataType;
if (dataType) { if (dataType) {
if (dataType === "api") { if (dataType === 'swagger') {
this.openSwaggerScheduleTab();
} else if (dataType === "api") {
this.activeDom = 'left'; this.activeDom = 'left';
} else { } else {
this.activeDom = 'middle'; this.activeDom = 'middle';
} }
} }
if (this.$route.params.dataSelectRange) {
let item = JSON.parse(JSON.stringify(this.$route.params.dataSelectRange)).param;
if (item) {
let type = item.taskGroup.toString();
if (type === "SWAGGER_IMPORT") {
this.openSwaggerScheduleTab();
this.param = item;
}
}
}
} }
}); });
}, },
@ -453,10 +449,6 @@ export default {
this.handleCommand("CLOSE_ALL"); this.handleCommand("CLOSE_ALL");
}, },
selectNodeIds() { selectNodeIds() {
if (!this.trashEnable) {
this.apiDefaultTab = "default";
}
}, },
redirectID() { redirectID() {
this.renderComponent = false; this.renderComponent = false;
@ -464,7 +456,6 @@ export default {
// DOM my-component // DOM my-component
this.renderComponent = true; this.renderComponent = true;
}); });
}, },
'$route'(to, from) { // ctrl s '$route'(to, from) { // ctrl s
if (to.path.indexOf('/api/definition') === -1) { if (to.path.indexOf('/api/definition') === -1) {

View File

@ -20,10 +20,15 @@
</el-col> </el-col>
</el-row> </el-row>
<el-row style="margin-top: 16px"> <el-row style="margin-top: 16px">
<el-col style="height: 369px;background-color: #FFFFFF;"> <el-col style="background-color: #FFFFFF;">
<updated-api-list @redirectPage="redirectPage"/> <updated-api-list @redirectPage="redirectPage"/>
</el-col> </el-col>
</el-row> </el-row>
<el-row style="margin-top: 16px">
<el-col style="background-color: #FFFFFF;">
<schedule-task-list @redirectPage="redirectPage"/>
</el-col>
</el-row>
</div> </div>
</ms-main-container> </ms-main-container>
</ms-container> </ms-container>
@ -39,7 +44,8 @@ import ApiDashboard from "@/business/home/components/dashboard/ApiDashboard";
import ApiCaseDashboard from "@/business/home/components/dashboard/ApiCaseDashboard"; import ApiCaseDashboard from "@/business/home/components/dashboard/ApiCaseDashboard";
import ScenarioDashboard from "@/business/home/components/dashboard/ScenarioDashboard"; import ScenarioDashboard from "@/business/home/components/dashboard/ScenarioDashboard";
import ScenarioScheduleDashboard from "@/business/home/components/dashboard/ScenarioScheduleDashboard"; import ScenarioScheduleDashboard from "@/business/home/components/dashboard/ScenarioScheduleDashboard";
import updatedApiList from "@/business/home/components/table/UpdatedApiList"; import UpdatedApiList from "@/business/home/components/table/UpdatedApiList";
import ScheduleTaskList from "@/business/home/components/table/ScheduleTaskList";
export default { export default {
name: "ApiHome", name: "ApiHome",
@ -51,7 +57,8 @@ export default {
MsMainContainer, MsMainContainer,
ScenarioDashboard, ScenarioDashboard,
ScenarioScheduleDashboard, ScenarioScheduleDashboard,
updatedApiList UpdatedApiList,
ScheduleTaskList
}, },
data() { data() {
@ -190,4 +197,27 @@ export default {
.api-home-layout :deep(.el-card) { .api-home-layout :deep(.el-card) {
border: 0; border: 0;
} }
.api-home-layout :deep(.table-title) {
color: #1F2329;
font-weight: 500;
font-size: 18px;
line-height: 26px;
}
.api-home-layout :deep(.el-table__row), .adjust-table :deep(.el-table__row .el-link) {
font-size: 14px;
font-weight: 400;
line-height: 22px;
color: #1F2329;
}
.api-home-layout :deep(.el-table__body tr:hover ) {
cursor: pointer;
}
.api-home-layout :deep(.el-table .cell) {
padding-left: 12px;
padding-right: 12px;
}
</style> </style>

View File

@ -0,0 +1,179 @@
<template>
<div style="margin: 24px" class="update-api-table">
<span class="table-title">
{{ $t('api_test.home_page.running_task_list.title') }}
</span>
<div style="margin-top: 16px;" v-loading="loading" element-loading-background="#FFFFFF">
<div v-show="loadError"
style="width: 100%; height: 300px; display: flex; flex-direction: column; justify-content: center;align-items: center">
<img style="height: 100px;width: 100px;"
src="/assets/figma/icon_load_error.svg"/>
<span class="addition-info-title" style="color: #646A73">{{ $t("home.dashboard.public.load_error") }}</span>
</div>
<div v-show="!loadError">
<el-table border :data="tableData" class="adjust-table table-content" style="min-height: 228px"
@row-click="clickRow"
header-cell-class-name="home-table-cell"
element-loading-background="#FFFFFF">
<!--序号-->
<el-table-column prop="index" :label="$t('home.new_case.index')" width="50"
show-overflow-tooltip>
<template v-slot:default="{row}">
{{ row.index }}
</template>
</el-table-column>
<!--名称-->
<el-table-column prop="name" :label="$t('commons.name')"
show-overflow-tooltip min-width="200">
<template v-slot:default="{row}">
<span class="redirectColumn">
{{ row.name }}
</span>
</template>
</el-table-column>
<!--任务类型-->
<el-table-column prop="taskGroup" :label="$t('home.table.task_type')" min-width="100"
show-overflow-tooltip>
<template v-slot:default="scope">
<span class="el-dropdown-link">
<basic-status-label :value="scope.row.taskGroup"/>
</span>
</template>
</el-table-column>
<!--任务状态-->
<el-table-column prop="status" :label="$t('home.table.task_status')" width="100">
<template v-slot:default="scope">
<div>
<el-switch
v-model="scope.row.taskStatus"
class="captcha-img"
@change="closeTaskConfirm(scope.row)"
></el-switch>
</div>
</template>
</el-table-column>
<!--创建人-->
<el-table-column prop="creator" :label="$t('home.table.create_user')"
width="100" show-overflow-tooltip/>
<!--运行规则-->
<el-table-column prop="rule" :label="$t('home.table.run_rule')" min-width="150"
show-overflow-tooltip>
</el-table-column>
<!--下次更新时间-->
<el-table-column :label="$t('home.table.update_time')" width="170" align="right">
<template v-slot:default="scope">
{{ scope.row.updateTime | datetimeFormat }}
</template>
</el-table-column>
<!--更新时间-->
<el-table-column :label="$t('home.table.next_execution_time')" width="170" align="right">
<template v-slot:default="scope">
{{ scope.row.updateTime | datetimeFormat }}
</template>
</el-table-column>
<template #empty>
<div
style="width: 100%; height: 144px;display: flex; flex-direction: column; justify-content: center;align-items: center">
<img style="height: 100px;width: 100px;margin-bottom: 8px"
src="/assets/figma/icon_none.svg"/>
<span class="addition-info-title">{{ $t("home.dashboard.public.no_data") }}</span>
</div>
</template>
</el-table>
<home-table-pagination :change="search" :current-page.sync="currentPage" :page-size.sync="pageSize"
layout="prev, pager, next, sizes"
:total="total"/>
</div>
</div>
</div>
</template>
<script>
import {getCurrentProjectID} from "metersphere-frontend/src/utils/token";
import ApiStatus from "@/business/definition/components/list/ApiStatus";
import HomeTablePagination from "@/business/home/components/table/HomeTablePagination";
import BasicStatusLabel from "metersphere-frontend/src/components/BasicStatusLabel";
import {operationConfirm} from "metersphere-frontend/src/utils";
import {getRunningTask} from "@/api/home";
import {scheduleDisable} from "@/api/schedule";
export default {
name: "ScheduleTask",
components: {
BasicStatusLabel, ApiStatus, HomeTablePagination
},
data() {
return {
result: false,
loadError: false,
loading: false,
tableData: [],
currentPage: 1,
pageSize: 5,
total: 0,
condition: {
filters: {}
}
}
},
activated() {
this.search();
},
methods: {
clickRow(row, column) {
if (column.property !== 'status') {
if (row.taskGroup === 'API_SCENARIO_TEST') {
this.redirectPage('scenario', 'scenario', 'edit:' + row.scenarioId);
} else if (row.taskGroup === 'SWAGGER_IMPORT') {
this.redirectPage('api', 'swagger');
}
}
},
search() {
let projectId = getCurrentProjectID();
this.loading = true;
this.loadError = false;
this.condition.filters.task_type = ['SWAGGER_IMPORT', 'API_SCENARIO_TEST'];
this.result = getRunningTask(projectId, this.currentPage, this.pageSize, this.condition).then(response => {
this.total = response.data.itemCount;
this.tableData = response.data.listObject;
this.loading = false;
this.loadError = false;
}).catch(() => {
this.loading = false;
this.loadError = true;
});
},
redirectPage(redirectPage, dataType, selectRange) {
this.$emit('redirectPage', redirectPage, dataType, selectRange, null);
},
closeTaskConfirm(row) {
let flag = row.taskStatus;
row.taskStatus = !flag; //switch
operationConfirm(this, this.$t('api_test.home_page.running_task_list.confirm.close_title'), () => {
this.updateTask(row);
});
},
updateTask(taskRow) {
this.loading = true;
this.loadError = false;
this.result = scheduleDisable(taskRow).then(() => {
this.search();
});
},
}
}
</script>
<style scoped>
.update-api-table :deep(.el-link--inner) {
width: 100%;
float: left;
}
.update-api-table :deep(.status-label) {
width: 68px;
}
</style>

View File

@ -11,11 +11,9 @@
<span class="addition-info-title" style="color: #646A73">{{ $t("home.dashboard.public.load_error") }}</span> <span class="addition-info-title" style="color: #646A73">{{ $t("home.dashboard.public.load_error") }}</span>
</div> </div>
<div v-show="!loadError"> <div v-show="!loadError">
<el-table border :data="tableData" class="adjust-table table-content" height="233px" <el-table border :data="tableData" class="adjust-table table-content" style="min-height: 228px"
@row-click="clickRow" @row-click="clickRow"
header-cell-class-name="home-table-cell" header-cell-class-name="home-table-cell" element-loading-background="#FFFFFF">
v-loading="loading" element-loading-background="#FFFFFF">
<!--ID--> <!--ID-->
<el-table-column prop="num" :label="$t('home.new_case.index')" width="100" <el-table-column prop="num" :label="$t('home.new_case.index')" width="100"
show-overflow-tooltip> show-overflow-tooltip>
@ -150,31 +148,8 @@ export default {
</script> </script>
<style scoped> <style scoped>
.table-title { .update-api-table :deep(.el-link--inner) {
color: #1F2329;
font-weight: 500;
font-size: 18px;
line-height: 26px;
}
.adjust-table :deep(.el-table__row), .adjust-table :deep(.el-table__row .el-link) {
font-size: 14px;
font-weight: 400;
line-height: 22px;
color: #1F2329;
}
.adjust-table :deep(.el-link--inner) {
width: 100%; width: 100%;
float: left; float: left;
} }
.update-api-table :deep(.el-table__body tr:hover ) {
cursor: pointer;
}
.update-api-table :deep(.el-table .cell) {
padding-left: 12px;
padding-right: 12px;
}
</style> </style>

View File

@ -18,7 +18,16 @@
<el-tag v-if="value === 'Archived'" class="status-label archived"> <el-tag v-if="value === 'Archived'" class="status-label archived">
{{ $t('test_track.plan.plan_status_archived') }} {{ $t('test_track.plan.plan_status_archived') }}
</el-tag> </el-tag>
<!--Api首页中的两种定时任务-->
<el-tag v-if="value === 'API_SCENARIO_TEST'" class="status-label schedule-task-scenario">
{{ $t('commons.scenario_case') }}
</el-tag>
<el-tag v-if="value === 'SWAGGER_IMPORT'" class="status-label schedule-task-swagger">
{{ $t('api_test.home_page.running_task_list.swagger_schedule') }}
</el-tag>
</span> </span>
</template> </template>
<script> <script>
@ -73,4 +82,14 @@ export default {
background-color: rgba(255, 136, 0, 0.2); background-color: rgba(255, 136, 0, 0.2);
color: #DE7802; color: #DE7802;
} }
.schedule-task-scenario {
background: rgba(52, 199, 36, 0.2);
color: #2EA121;
}
.schedule-task-swagger {
background: rgba(0, 214, 185, 0.2);
color: #078372;
}
</style> </style>