feat(plan): 计划自动化执行、结果列表与鉴权请求优化

- 新增 automationApi、PlanAutomationRun、PlanAutomationExecutionList
- 计划构建/列表/执行/进度等接入自动化与路由
- request 与 authToken 处理 token 刷新与错误码

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
qiaoxinjiu
2026-05-11 14:27:55 +08:00
parent 33753361b0
commit 6e9673f7dd
14 changed files with 1587 additions and 48 deletions

View File

@@ -74,7 +74,9 @@
</el-form>
<el-table v-loading="loading" :data="tableData" border style="margin-top: 16px;">
<el-table-column prop="name" label="计划名称" min-width="180"></el-table-column>
<el-table-column prop="version" label="版本" width="120"></el-table-column>
<el-table-column label="是否自动化测试" width="140">
<template slot-scope="scope">{{ formatPlanIsAuto(scope.row) }}</template>
</el-table-column>
<el-table-column label="开始时间" min-width="170">
<template slot-scope="scope">{{ formatDateTime(getStartTimeValue(scope.row)) }}</template>
</el-table-column>
@@ -90,19 +92,20 @@
<el-table-column label="状态" width="110">
<template slot-scope="scope">{{ formatStatus(scope.row.status) }}</template>
</el-table-column>
<el-table-column label="操作" width="600">
<el-table-column label="操作" width="660">
<template slot-scope="scope">
<el-button type="text" @click="goEdit(scope.row)">编辑</el-button>
<el-button type="text" @click="goAssociateCases(scope.row)">关联用例</el-button>
<el-button type="text" @click="goExecute(scope.row)">执行</el-button>
<el-button v-if="!isPlanAutomation(scope.row)" type="text" @click="goExecute(scope.row)">执行</el-button>
<el-button type="text" @click="goProgress(scope.row)">进度</el-button>
<el-button type="text" @click="openHookSendDialog(scope.row)">机器人消息</el-button>
<el-button type="text" @click="runAutoCases(scope.row)">执行自动化用例</el-button>
<el-button type="text" @click="openHookSendDialog(scope.row)">发送消息</el-button>
<el-button v-if="isPlanAutomation(scope.row)" type="text" @click="runAutoCases(scope.row)">执行自动化用例</el-button>
<el-button type="text" class="danger-text" @click="confirmDeletePlan(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-dialog
title="发送机器人消息"
title="发送消息"
:visible.sync="hookSendDialogVisible"
width="600px"
append-to-body
@@ -180,7 +183,7 @@
<script>
import PageSection from '@/components/TestPlatform/common/PageSection'
import { getPlanList } from '@/api/planApi'
import { deletePlan, getPlanList } from '@/api/planApi'
import { getProductList } from '@/api/productApi'
import {
getProjectDetail,
@@ -535,6 +538,28 @@ export default {
}
})
},
confirmDeletePlan(row) {
if (!row || row.id == null) {
this.$message.warning('缺少计划信息')
return
}
if (!this.projectId) {
this.$message.warning('请先选择项目')
return
}
const name = (row.name || '').trim() || `计划 #${row.id}`
this.$confirm(`确定删除计划「${name}」吗?删除后不可恢复。`, '删除确认', {
confirmButtonText: '删除',
cancelButtonText: '取消',
type: 'warning'
})
.then(() => deletePlan(row.id))
.then(() => {
this.$message.success('删除成功')
this.fetchList()
})
.catch(() => {})
},
goAssociateCases(row) {
const project = (this.projectOptions || []).find(item => String(item.id) === String(this.projectId))
const product = (this.productOptions || []).find(item => String(item.id) === String(this.selectedProductId))
@@ -769,8 +794,31 @@ export default {
this.hookSendSubmitting = false
})
},
runAutoCases() {
this.$message.info('执行自动化用例功能开发中')
runAutoCases(row) {
if (!row || row.id == null) {
this.$message.warning('缺少计划信息')
return
}
if (!this.projectId) {
this.$message.warning('请先选择项目')
return
}
const project = (this.projectOptions || []).find(item => String(item.id) === String(this.projectId))
const product = (this.productOptions || []).find(item => String(item.id) === String(this.selectedProductId))
const jenkinsUrl = (row.jenkins_url || row.jenkinsUrl || '').trim()
this.$router.push({
path: '/test-platform/plan/automation',
query: {
productId: this.selectedProductId || undefined,
productName: (product && product.name) || '',
projectId: this.projectId,
projectName: (project && project.name) || '',
planId: row.id,
planName: row.name || '',
environmentId: row.environment_id != null ? row.environment_id : row.environmentId,
jenkinsUrl: jenkinsUrl || undefined
}
})
},
goProgress(row) {
const project = (this.projectOptions || []).find(item => String(item.id) === String(this.projectId))
@@ -787,6 +835,19 @@ export default {
}
})
},
formatPlanIsAuto(row) {
if (!row) return '-'
const v = row.isAuto !== undefined && row.isAuto !== null ? row.isAuto : row.is_auto
if (v === 1 || v === true || v === '1') return '是'
if (v === 0 || v === false || v === '0') return '否'
return '-'
},
/** 列表 is_auto === 1自动化测试计划只展示「执行自动化用例」 */
isPlanAutomation(row) {
if (!row) return false
const v = row.isAuto !== undefined && row.isAuto !== null ? row.isAuto : row.is_auto
return v === 1 || v === true || v === '1'
},
formatStatus(value) {
const map = { 0: '草稿', 1: '进行中', 2: '已完成', 3: '已归档', 4: '已通过' }
return map[value] || value
@@ -872,6 +933,14 @@ export default {
padding: 20px;
}
.danger-text {
color: #f56c6c;
}
.danger-text:hover {
color: #f78989;
}
.hook-send-result {
margin-top: 12px;
padding: 10px 12px;