| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179 |
- <template>
- <div class="page-container">
- <el-card>
- <div slot="header">
- <span>执行详情</span>
- <el-button size="small" style="float:right" @click="$router.push('/orchestration')">返回列表</el-button>
- </div>
- <el-descriptions v-if="execution" :column="3" border size="medium" style="margin-bottom:20px">
- <el-descriptions-item label="执行ID">{{ execution.id }}</el-descriptions-item>
- <el-descriptions-item label="流ID">{{ execution.flowId }}</el-descriptions-item>
- <el-descriptions-item label="版本">{{ execution.flowVersion }}</el-descriptions-item>
- <el-descriptions-item label="状态">
- <el-tag :type="statusType(execution.status)">{{ statusLabel(execution.status) }}</el-tag>
- </el-descriptions-item>
- <el-descriptions-item label="触发来源">{{ triggerLabel(execution.triggerSource) }}</el-descriptions-item>
- <el-descriptions-item label="启动时间">{{ formatTime(execution.startedAt) }}</el-descriptions-item>
- <el-descriptions-item label="完成时间">{{ formatTime(execution.finishedAt) }}</el-descriptions-item>
- <el-descriptions-item label="错误原因">{{ execution.errorReason || '-' }}</el-descriptions-item>
- </el-descriptions>
- <!-- 手动干预 -->
- <div style="margin-bottom:15px">
- <el-button type="warning" size="small" v-if="execution && execution.status==='running'" @click="handleTerminate">终止流</el-button>
- <el-button type="primary" size="small" v-if="execution && execution.status==='running'" @click="handlePause">暂停</el-button>
- <el-button type="success" size="small" v-if="execution && execution.status==='paused'" @click="handleResume">恢复</el-button>
- </div>
- <!-- 节点树 -->
- <div class="adm-table-wrap">
- <el-table :data="nodes" border v-loading="loading" row-key="id" default-expand-all height="100%">
- <el-table-column prop="nodeId" label="节点ID" width="160"></el-table-column>
- <el-table-column prop="status" label="状态" width="120">
- <template slot-scope="scope">
- <el-tag :type="statusType(scope.row.status)" size="small">{{ statusLabel(scope.row.status) }}</el-tag>
- </template>
- </el-table-column>
- <el-table-column prop="generation" label="循环次数" width="100"></el-table-column>
- <el-table-column prop="taskId" label="关联任务ID" width="120">
- <template slot-scope="scope">{{ scope.row.taskId || '-' }}</template>
- </el-table-column>
- <el-table-column prop="conditionMetAt" label="条件达成时间" width="180">
- <template slot-scope="scope">{{ formatTime(scope.row.conditionMetAt) }}</template>
- </el-table-column>
- <el-table-column prop="loopTerminationReason" label="循环终止原因" width="150">
- <template slot-scope="scope">{{ scope.row.loopTerminationReason || '-' }}</template>
- </el-table-column>
- <el-table-column prop="errorReason" label="错误原因" min-width="150">
- <template slot-scope="scope">{{ scope.row.errorReason || '-' }}</template>
- </el-table-column>
- <el-table-column prop="createdAt" label="创建时间" width="170">
- <template slot-scope="scope">{{ formatTime(scope.row.createdAt) }}</template>
- </el-table-column>
- <el-table-column label="操作" width="180" fixed="right">
- <template slot-scope="scope">
- <el-button size="mini" type="danger" v-if="scope.row.status==='in_progress'||scope.row.status==='pending'" @click="handleNodeFail(scope.row)">标记失败</el-button>
- <el-button size="mini" type="warning" v-if="scope.row.status==='failed'||scope.row.status==='timeout'" @click="handleNodeRestart(scope.row)">重启节点</el-button>
- <el-button size="mini" type="success" v-if="scope.row.status==='in_progress'||scope.row.status==='pending'" @click="handleConditionMet(scope.row)">条件达成</el-button>
- </template>
- </el-table-column>
- </el-table>
- </div>
- </el-card>
- </div>
- </template>
- <script>
- import { getExecutionDetail, terminateExecution, pauseExecution, resumeExecution, failNode, restartNode, markConditionMet } from '@/api/orchestration'
- export default {
- name: 'ExecutionDetail',
- data() {
- return {
- executionId: Number(this.$route.params.id),
- execution: null,
- nodes: [],
- loading: false
- }
- },
- created() {
- this.loadDetail()
- },
- methods: {
- async loadDetail() {
- this.loading = true
- try {
- const res = await getExecutionDetail(this.executionId)
- this.execution = res.data.execution || null
- this.nodes = res.data.nodes || []
- } catch (e) {
- console.error(e)
- } finally {
- this.loading = false
- }
- },
- async handleTerminate() {
- this.$confirm('确认终止整个执行流?运行中的任务不会被删除。', '提示', { type: 'warning' }).then(async () => {
- try {
- await terminateExecution({ executionId: this.executionId, reason: '管理员手动终止' })
- this.$message.success('已终止')
- this.loadDetail()
- } catch (e) {
- this.$message.error(e.message || '操作失败')
- }
- }).catch(() => {})
- },
- async handlePause() {
- try {
- await pauseExecution(this.executionId)
- this.$message.success('已暂停')
- this.loadDetail()
- } catch (e) {
- this.$message.error(e.message || '操作失败')
- }
- },
- async handleResume() {
- try {
- await resumeExecution(this.executionId)
- this.$message.success('已恢复')
- this.loadDetail()
- } catch (e) {
- this.$message.error(e.message || '操作失败')
- }
- },
- async handleNodeFail(row) {
- try {
- await failNode(row.id, '管理员手动标记失败')
- this.$message.success('已标记失败')
- this.loadDetail()
- } catch (e) {
- this.$message.error(e.message || '操作失败')
- }
- },
- async handleNodeRestart(row) {
- try {
- await restartNode(row.id)
- this.$message.success('已重启节点')
- this.loadDetail()
- } catch (e) {
- this.$message.error(e.message || '操作失败')
- }
- },
- async handleConditionMet(row) {
- try {
- await markConditionMet(row.id)
- this.$message.success('已通知条件达成')
- this.loadDetail()
- } catch (e) {
- this.$message.error(e.message || '操作失败')
- }
- },
- statusType(s) {
- const map = {
- running: 'primary', paused: 'warning', terminated: 'danger', completed: 'success',
- pending: 'info', in_progress: 'primary', completed: 'success',
- failed: 'danger', timeout: 'warning', terminated: 'danger', skipped: 'info'
- }
- return map[s] || 'info'
- },
- statusLabel(s) {
- const map = {
- running: '运行中', paused: '已暂停', terminated: '已终止', completed: '已完成',
- pending: '等待中', in_progress: '进行中',
- failed: '失败', timeout: '超时', skipped: '跳过'
- }
- return map[s] || s
- },
- triggerLabel(s) {
- const map = { manual: '手动', cron: '定时', callback: '回调' }
- return map[s] || s
- },
- }
- }
- </script>
- <style scoped>
- .page-container { padding: 20px; }
- </style>
|