| | |
| | | 查看详情 |
| | | </el-button> |
| | | <el-button |
| | | v-if="row.status === 'RUNNING'" |
| | | v-if="row.status === 'RUNNING' || row.status === 'FAILED'" |
| | | link |
| | | type="danger" |
| | | size="small" |
| | |
| | | <div class="step-desc">耗时:{{ formatDuration(step.durationMs) }}</div> |
| | | <div class="step-desc" v-if="step.retryCount > 0"> |
| | | 重试次数:{{ step.retryCount }} |
| | | </div> |
| | | <div class="step-desc" v-if="step.successMessage"> |
| | | 提示:{{ step.successMessage }} |
| | | </div> |
| | | <div class="step-desc error-message" v-if="step.errorMessage"> |
| | | <el-icon><Warning /></el-icon> |
| | |
| | | const sseConnecting = ref(false) |
| | | let eventSource = null |
| | | const baseURL = import.meta.env.VITE_API_BASE_URL || '' |
| | | |
| | | // 统一的ID比较,避免数字/字符串不一致导致SSE更新被忽略 |
| | | const isSameId = (a, b) => { |
| | | if (a == null || b == null) return false |
| | | return String(a) === String(b) |
| | | } |
| | | |
| | | const fetchTasks = async () => { |
| | | try { |
| | |
| | | // 监听步骤更新 |
| | | eventSource.addEventListener('stepUpdate', (event) => { |
| | | try { |
| | | const data = JSON.parse(event.data) |
| | | const raw = JSON.parse(event.data) |
| | | // 后端全量监听时的数据结构为 { taskId, step: { ... } },需要展开 step |
| | | const data = raw?.step ? { ...raw.step, taskId: raw.taskId || raw.step.taskId } : raw |
| | | // 如果数据中包含 taskId,检查是否匹配当前查看的任务 |
| | | if (data.taskId && data.taskId === currentTaskId.value) { |
| | | if (data.taskId && isSameId(data.taskId, currentTaskId.value)) { |
| | | updateStepFromSSE(data) |
| | | } else if (!data.taskId) { |
| | | // 如果没有 taskId,可能是步骤数据直接传递 |
| | |
| | | return |
| | | } |
| | | |
| | | const taskIndex = tasks.value.findIndex(t => t.taskId === data.taskId) |
| | | const taskIndex = tasks.value.findIndex(t => isSameId(t.taskId, data.taskId)) |
| | | if (taskIndex >= 0) { |
| | | // 更新任务 - 保留原有字段,只更新SSE传来的字段 |
| | | const existingTask = tasks.value[taskIndex] |
| | |
| | | if (!data) return |
| | | |
| | | // 如果数据中包含 taskId,检查是否匹配当前查看的任务 |
| | | if (data.taskId && data.taskId !== currentTaskId.value) { |
| | | if (data.taskId && !isSameId(data.taskId, currentTaskId.value)) { |
| | | return |
| | | } |
| | | |
| | |
| | | endTime: data.endTime ? new Date(data.endTime) : existingStep.endTime, |
| | | durationMs: data.durationMs !== undefined ? data.durationMs : existingStep.durationMs, |
| | | retryCount: data.retryCount !== undefined ? data.retryCount : existingStep.retryCount, |
| | | successMessage: data.successMessage !== undefined ? data.successMessage : existingStep.successMessage, |
| | | errorMessage: data.errorMessage || existingStep.errorMessage |
| | | } |
| | | } else if (data.stepOrder !== undefined) { |
| | |
| | | } finally { |
| | | stepsLoading.value = false |
| | | } |
| | | } |
| | | |
| | | // 根据taskId打开任务详情抽屉(供父组件调用) |
| | | const openTaskDrawer = async (taskId) => { |
| | | if (!taskId) return |
| | | // 如果任务列表为空,先加载一次 |
| | | if (!tasks.value || tasks.value.length === 0) { |
| | | await fetchTasks() |
| | | } |
| | | const task = tasks.value.find(t => t.taskId === taskId) |
| | | if (!task) { |
| | | return |
| | | } |
| | | await handleRowClick(task) |
| | | } |
| | | |
| | | const statusType = (status) => { |
| | |
| | | defineExpose({ |
| | | fetchTasks, |
| | | connectSSE, |
| | | disconnectSSE |
| | | disconnectSSE, |
| | | openTaskDrawer |
| | | }) |
| | | </script> |
| | | |