debug
This commit is contained in:
677
src/views/site/domainImportHealthWorkbenchDialog.vue
Normal file
677
src/views/site/domainImportHealthWorkbenchDialog.vue
Normal file
@@ -0,0 +1,677 @@
|
||||
<template>
|
||||
<el-dialog v-model="visible" title="导入健康台" width="1100px" draggable>
|
||||
<div class="import-health-workbench">
|
||||
<div class="import-health-workbench__toolbar">
|
||||
<el-button type="primary" plain @click="loadSummary">刷新</el-button>
|
||||
<el-button type="primary" plain :loading="workbenchRunLoading" @click="runWorkbenchSummaryAction">刷新并落盘健康台</el-button>
|
||||
<el-button type="success" plain :loading="selfHealingLoading" @click="runSelfHealingAction">执行自动修复</el-button>
|
||||
<el-button type="success" plain @click="openClosureOverview">闭环总览</el-button>
|
||||
<el-button type="info" plain @click="openImportRuns">最近导入记录</el-button>
|
||||
<el-button type="warning" plain @click="openFailedQueue">探测失败队列</el-button>
|
||||
<el-button type="info" plain @click="openRerunRuns">最近重跑记录</el-button>
|
||||
<el-button type="warning" plain @click="openRemediationRuns">最近补料记录</el-button>
|
||||
<el-button type="info" plain @click="openSelfHealingRuns">最近自动修复记录</el-button>
|
||||
<el-button type="danger" plain @click="openManualAttention">人工关注队列</el-button>
|
||||
<el-button type="primary" plain @click="openManualHandleRuns">最近人工处理记录</el-button>
|
||||
<el-button type="info" plain @click="openWorkbenchRuns">最近健康台记录</el-button>
|
||||
<el-button type="info" plain @click="openWorkbenchTrend">健康台趋势</el-button>
|
||||
</div>
|
||||
<div class="import-health-workbench__hero">
|
||||
<div class="import-health-workbench__hero-title">导入健康台</div>
|
||||
<div class="import-health-workbench__hero-desc">{{ healthLabelText() }}</div>
|
||||
<div v-if="summary.hero_summary" class="import-health-workbench__hero-note">
|
||||
{{ summary.hero_summary }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="import-health-workbench__stats">
|
||||
<span>导入记录:{{ summary.import_runs_count || 0 }}</span>
|
||||
<span>当前失败:{{ summary.active_count || summary.queue_count || 0 }}</span>
|
||||
<span>自动修复记录:{{ summary.self_healing_runs_count || 0 }}</span>
|
||||
<span>人工关注:{{ summary.manual_attention_count || 0 }}</span>
|
||||
<span>重跑恢复:{{ summary.resolved_by_rerun_count || 0 }}</span>
|
||||
<span>补料恢复:{{ summary.resolved_by_remediation_count || 0 }}</span>
|
||||
</div>
|
||||
<div class="import-health-workbench__blocks">
|
||||
<div class="import-health-workbench__block">
|
||||
<div class="import-health-workbench__block-title">最新导入</div>
|
||||
<div>{{ summary.latest_import_run?.run_id || "-" }}</div>
|
||||
<div>失败 {{ summary.latest_import_run?.failed_count || 0 }}</div>
|
||||
</div>
|
||||
<div class="import-health-workbench__block">
|
||||
<div class="import-health-workbench__block-title">最新失败 Host</div>
|
||||
<div>{{ summary.latest_failed_item?.host || "-" }}</div>
|
||||
<div>{{ summary.latest_failed_item?.failed_stage || "-" }}</div>
|
||||
</div>
|
||||
<div class="import-health-workbench__block">
|
||||
<div class="import-health-workbench__block-title">最新自动修复</div>
|
||||
<div>{{ summary.latest_self_healing_run?.run_id || "-" }}</div>
|
||||
<div>{{ summary.latest_self_healing_run?.status || "-" }}</div>
|
||||
</div>
|
||||
<div class="import-health-workbench__block">
|
||||
<div class="import-health-workbench__block-title">最新重跑</div>
|
||||
<div>{{ summary.latest_rerun_run?.run_id || "-" }}</div>
|
||||
<div>失败 {{ summary.latest_rerun_run?.failed_count || 0 }}</div>
|
||||
</div>
|
||||
<div class="import-health-workbench__block">
|
||||
<div class="import-health-workbench__block-title">最新补料</div>
|
||||
<div>{{ summary.latest_remediation_run?.run_id || "-" }}</div>
|
||||
<div>恢复 {{ summary.latest_remediation_run?.recovered_count || 0 }}</div>
|
||||
</div>
|
||||
<div class="import-health-workbench__block">
|
||||
<div class="import-health-workbench__block-title">失败趋势</div>
|
||||
<div>{{ failureTrendText() }}</div>
|
||||
</div>
|
||||
<div class="import-health-workbench__block">
|
||||
<div class="import-health-workbench__block-title">人工关注</div>
|
||||
<div>{{ summary.manual_attention_count || 0 }}</div>
|
||||
<div>{{ summary.latest_manual_attention_item?.host || "-" }}</div>
|
||||
</div>
|
||||
<div class="import-health-workbench__block">
|
||||
<div class="import-health-workbench__block-title">最新人工处理</div>
|
||||
<div>{{ summary.latest_manual_handle_run?.run_id || "-" }}</div>
|
||||
<div>{{ summary.latest_manual_handle_run?.status || "-" }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="(summary.resolved_hosts_preview || []).length" class="import-health-workbench__resolved">
|
||||
<span class="import-health-workbench__resolved-label">最近恢复:</span>
|
||||
<span>{{ (summary.resolved_hosts_preview || []).join(" / ") }}</span>
|
||||
</div>
|
||||
<div class="import-health-workbench__insights">
|
||||
<div class="import-health-workbench__insight-card">
|
||||
<div class="import-health-workbench__panel-title">当前失败阶段分布</div>
|
||||
<div
|
||||
v-for="item in (summary.top_failed_stages || []).slice(0, 5)"
|
||||
:key="item.stage"
|
||||
class="import-health-workbench__panel-row"
|
||||
>
|
||||
<span>{{ item.stage || "-" }}</span>
|
||||
<span>{{ item.count || 0 }}</span>
|
||||
</div>
|
||||
<div v-if="!(summary.top_failed_stages || []).length" class="import-health-workbench__empty">当前没有活跃失败阶段</div>
|
||||
</div>
|
||||
<div class="import-health-workbench__insight-card">
|
||||
<div class="import-health-workbench__panel-title">当前恢复主路径</div>
|
||||
<div class="import-health-workbench__mix-main">{{ recoveryMixText() }}</div>
|
||||
<div class="import-health-workbench__mix-sub">
|
||||
重跑恢复 {{ summary.recovery_mix?.resolved_by_rerun_count || 0 }} /
|
||||
补料恢复 {{ summary.recovery_mix?.resolved_by_remediation_count || 0 }}
|
||||
</div>
|
||||
<div class="import-health-workbench__mix-sub">
|
||||
自动修复记录 {{ summary.recovery_mix?.self_healing_runs_count || 0 }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="import-health-workbench__insights">
|
||||
<div class="import-health-workbench__insight-card">
|
||||
<div class="import-health-workbench__panel-title">人工关注分层</div>
|
||||
<div class="import-health-workbench__mix-main">{{ manualAttentionText() }}</div>
|
||||
<div class="import-health-workbench__mix-sub">
|
||||
高优先 {{ summary.manual_attention_buckets?.high || 0 }} /
|
||||
中优先 {{ summary.manual_attention_buckets?.medium || 0 }} /
|
||||
低优先 {{ summary.manual_attention_buckets?.low || 0 }}
|
||||
</div>
|
||||
<div
|
||||
v-for="item in (summary.recent_manual_attention_items || []).slice(0, 3)"
|
||||
:key="item.host"
|
||||
class="import-health-workbench__panel-row"
|
||||
>
|
||||
<span>{{ item.host || "-" }}</span>
|
||||
<span>{{ item.attention_reason || "-" }}</span>
|
||||
</div>
|
||||
<div v-if="!(summary.recent_manual_attention_items || []).length" class="import-health-workbench__empty">当前没有需要人工接管的 host</div>
|
||||
</div>
|
||||
<div class="import-health-workbench__insight-card">
|
||||
<div class="import-health-workbench__panel-title">最近人工处理</div>
|
||||
<div class="import-health-workbench__mix-main">{{ manualHandleText() }}</div>
|
||||
<div class="import-health-workbench__mix-sub">
|
||||
处理记录 {{ summary.manual_handle_runs_count || 0 }} / 最新复核 {{ summary.latest_manual_handle_run?.reprobe_status || "-" }}
|
||||
</div>
|
||||
<div
|
||||
v-for="item in (summary.recent_manual_handle_runs || []).slice(0, 3)"
|
||||
:key="item.run_id"
|
||||
class="import-health-workbench__panel-row"
|
||||
>
|
||||
<span>{{ item.host || "-" }}</span>
|
||||
<span>{{ item.action || "-" }} / {{ item.status || "-" }}</span>
|
||||
</div>
|
||||
<div v-if="!(summary.recent_manual_handle_runs || []).length" class="import-health-workbench__empty">当前还没有人工处理记录</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="import-health-workbench__insights">
|
||||
<div class="import-health-workbench__insight-card">
|
||||
<div class="import-health-workbench__panel-title">健康台记录告警</div>
|
||||
<div class="import-health-workbench__mix-main">{{ workbenchAlertText() }}</div>
|
||||
<div class="import-health-workbench__mix-sub">
|
||||
高优先 {{ workbenchRunsSummary.alert_buckets?.high || 0 }} /
|
||||
中优先 {{ workbenchRunsSummary.alert_buckets?.medium || 0 }} /
|
||||
低优先 {{ workbenchRunsSummary.alert_buckets?.low || 0 }}
|
||||
</div>
|
||||
<div
|
||||
v-for="item in (workbenchRunsSummary.top_attention_runs || []).slice(0, 3)"
|
||||
:key="item.run_id"
|
||||
class="import-health-workbench__panel-row"
|
||||
>
|
||||
<span>{{ item.run_id || "-" }}</span>
|
||||
<span>{{ item.alert_reason || "-" }}</span>
|
||||
</div>
|
||||
<div v-if="!(workbenchRunsSummary.top_attention_runs || []).length" class="import-health-workbench__empty">当前没有需要优先回看的健康台 run</div>
|
||||
</div>
|
||||
<div class="import-health-workbench__insight-card">
|
||||
<div class="import-health-workbench__panel-title">健康台趋势告警</div>
|
||||
<div class="import-health-workbench__mix-main">{{ trendAlertText() }}</div>
|
||||
<div class="import-health-workbench__mix-sub">
|
||||
当前趋势 {{ trendText() }}
|
||||
</div>
|
||||
<div class="import-health-workbench__mix-sub">
|
||||
{{ workbenchTrend.alert_reason || "当前健康台趋势平稳" }}
|
||||
</div>
|
||||
<div
|
||||
v-for="item in (workbenchTrend.stage_buckets || []).slice(0, 3)"
|
||||
:key="item.stage"
|
||||
class="import-health-workbench__panel-row"
|
||||
>
|
||||
<span>{{ item.stage || "-" }}</span>
|
||||
<span>{{ item.count || 0 }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="(summary.priority_actions || []).length" class="import-health-workbench__actions">
|
||||
<div
|
||||
v-for="item in summary.priority_actions || []"
|
||||
:key="item.key"
|
||||
class="import-health-workbench__action-card"
|
||||
>
|
||||
<div class="import-health-workbench__action-head">
|
||||
<div class="import-health-workbench__action-title">{{ item.label || "-" }}</div>
|
||||
<el-tag size="small" :type="item.tag_type || 'info'">{{ actionTagText(item.tag_type) }}</el-tag>
|
||||
</div>
|
||||
<div class="import-health-workbench__action-summary">{{ item.summary || "-" }}</div>
|
||||
<div class="import-health-workbench__action-foot">
|
||||
<el-button size="small" :type="buttonType(item.tag_type)" plain @click="handlePriorityAction(item.action_key)">
|
||||
{{ item.action_label || "执行" }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="import-health-workbench__panels">
|
||||
<div class="import-health-workbench__panel">
|
||||
<div class="import-health-workbench__panel-title">最近导入</div>
|
||||
<div
|
||||
v-for="item in (summary.recent_import_runs || []).slice(0, 5)"
|
||||
:key="item.run_id"
|
||||
class="import-health-workbench__panel-row"
|
||||
>
|
||||
<span>{{ item.run_id || "-" }}</span>
|
||||
<span>失败 {{ item.failed_count || 0 }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="import-health-workbench__panel">
|
||||
<div class="import-health-workbench__panel-title">最近自动修复</div>
|
||||
<div
|
||||
v-for="item in (summary.recent_self_healing_runs || []).slice(0, 5)"
|
||||
:key="item.run_id"
|
||||
class="import-health-workbench__panel-row"
|
||||
>
|
||||
<span>{{ item.run_id || "-" }}</span>
|
||||
<span>{{ item.status || "-" }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="import-health-workbench__panel">
|
||||
<div class="import-health-workbench__panel-title">最近重跑</div>
|
||||
<div
|
||||
v-for="item in (summary.recent_rerun_runs || []).slice(0, 5)"
|
||||
:key="item.run_id"
|
||||
class="import-health-workbench__panel-row"
|
||||
>
|
||||
<span>{{ item.run_id || "-" }}</span>
|
||||
<span>失败 {{ item.failed_count || 0 }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="import-health-workbench__panel">
|
||||
<div class="import-health-workbench__panel-title">最近补料</div>
|
||||
<div
|
||||
v-for="item in (summary.recent_remediation_runs || []).slice(0, 5)"
|
||||
:key="item.run_id"
|
||||
class="import-health-workbench__panel-row"
|
||||
>
|
||||
<span>{{ item.run_id || "-" }}</span>
|
||||
<span>恢复 {{ item.recovered_count || 0 }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<DomainImportRunDialog ref="importRunDialogRef" />
|
||||
<DomainImportFailedQueueDialog ref="failedQueueDialogRef" />
|
||||
<DomainImportRerunDialog ref="rerunDialogRef" />
|
||||
<DomainImportRemediationDialog ref="remediationDialogRef" />
|
||||
<DomainImportSelfHealingDialog ref="selfHealingDialogRef" />
|
||||
<DomainImportManualAttentionDialog ref="manualAttentionDialogRef" />
|
||||
<DomainImportManualAttentionHandleDialog ref="manualHandleDialogRef" />
|
||||
<DomainImportHealthWorkbenchSummaryDialog ref="workbenchSummaryDialogRef" />
|
||||
<DomainImportHealthWorkbenchTrendDialog ref="workbenchTrendDialogRef" />
|
||||
<DomainImportTaskConsoleDialog ref="taskConsoleDialogRef" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { SiteList } from "@/api/interface/site/list";
|
||||
import {
|
||||
getDomainImportHealthWorkbench,
|
||||
getDomainImportHealthWorkbenchSummary,
|
||||
getDomainImportHealthWorkbenchTrend,
|
||||
runDomainImportHealthWorkbenchSummary,
|
||||
runDomainImportSelfHealing
|
||||
} from "@/api/modules/site/list";
|
||||
import DomainImportRunDialog from "./domainImportRunDialog.vue";
|
||||
import DomainImportFailedQueueDialog from "./domainImportFailedQueueDialog.vue";
|
||||
import DomainImportRerunDialog from "./domainImportRerunDialog.vue";
|
||||
import DomainImportRemediationDialog from "./domainImportRemediationDialog.vue";
|
||||
import DomainImportSelfHealingDialog from "./domainImportSelfHealingDialog.vue";
|
||||
import DomainImportManualAttentionDialog from "./domainImportManualAttentionDialog.vue";
|
||||
import DomainImportManualAttentionHandleDialog from "./domainImportManualAttentionHandleDialog.vue";
|
||||
import DomainImportHealthWorkbenchSummaryDialog from "./domainImportHealthWorkbenchSummaryDialog.vue";
|
||||
import DomainImportHealthWorkbenchTrendDialog from "./domainImportHealthWorkbenchTrendDialog.vue";
|
||||
import DomainImportTaskConsoleDialog from "./domainImportTaskConsoleDialog.vue";
|
||||
|
||||
const visible = ref(false);
|
||||
const loading = ref(false);
|
||||
const workbenchRunLoading = ref(false);
|
||||
const selfHealingLoading = ref(false);
|
||||
const summary = ref<SiteList.DomainImportHealthWorkbenchData>({});
|
||||
const workbenchRunsSummary = ref<SiteList.DomainImportHealthWorkbenchSummaryData>({});
|
||||
const workbenchTrend = ref<SiteList.DomainImportHealthWorkbenchTrendData>({});
|
||||
const importRunDialogRef = ref();
|
||||
const failedQueueDialogRef = ref();
|
||||
const rerunDialogRef = ref();
|
||||
const remediationDialogRef = ref();
|
||||
const selfHealingDialogRef = ref();
|
||||
const manualAttentionDialogRef = ref();
|
||||
const manualHandleDialogRef = ref();
|
||||
const workbenchSummaryDialogRef = ref();
|
||||
const workbenchTrendDialogRef = ref();
|
||||
const taskConsoleDialogRef = ref();
|
||||
const requestGlobalDialogOpen = (key: string) => {
|
||||
window.dispatchEvent(new CustomEvent("site-dialog-open", { detail: { key } }));
|
||||
};
|
||||
|
||||
const healthLabelText = () => {
|
||||
const label = summary.value.health_label || "steady";
|
||||
if (label === "worsening") return "探测失败趋势上升,优先处理探测失败队列";
|
||||
if (label === "attention") return "当前仍有失败 host,建议关注自愈结果";
|
||||
if (label === "waiting_self_healing") return "存在失败 host,但还缺自动修复进展";
|
||||
return "导入链整体平稳";
|
||||
};
|
||||
|
||||
const actionTagText = (tagType?: string) => {
|
||||
if (tagType === "danger") return "高优先";
|
||||
if (tagType === "warning") return "先处理";
|
||||
if (tagType === "success") return "已接入";
|
||||
return "建议";
|
||||
};
|
||||
|
||||
const buttonType = (tagType?: string) => {
|
||||
if (tagType === "danger") return "danger";
|
||||
if (tagType === "warning") return "warning";
|
||||
if (tagType === "success") return "success";
|
||||
return "primary";
|
||||
};
|
||||
|
||||
const failureTrendText = () => {
|
||||
const label = summary.value.failure_trend?.label || "flat";
|
||||
if (label === "improving") return "改善中";
|
||||
if (label === "worsening") return "上升中";
|
||||
return "持平";
|
||||
};
|
||||
|
||||
const recoveryMixText = () => {
|
||||
const path = summary.value.recovery_mix?.primary_path || "none";
|
||||
if (path === "rerun") return "当前恢复主要靠重跑";
|
||||
if (path === "remediation") return "当前恢复主要靠补料";
|
||||
if (path === "balanced") return "当前恢复由重跑和补料共同承担";
|
||||
return "当前还没有明显恢复主路径";
|
||||
};
|
||||
|
||||
const manualAttentionText = () => {
|
||||
const count = summary.value.manual_attention_count || 0;
|
||||
if (count > 0) {
|
||||
return `当前有 ${count} 个 host 需要人工接管`;
|
||||
}
|
||||
return "当前没有需要人工接管的 host";
|
||||
};
|
||||
|
||||
const manualHandleText = () => {
|
||||
const latestRun = summary.value.latest_manual_handle_run || {};
|
||||
if (latestRun.run_id) {
|
||||
return `最新人工处理 ${latestRun.run_id},Host ${latestRun.host || "-"},状态 ${latestRun.status || "-"}`;
|
||||
}
|
||||
return "当前还没有人工处理记录";
|
||||
};
|
||||
|
||||
const workbenchAlertText = () => {
|
||||
const level = workbenchRunsSummary.value.latest_run?.alert_level || "none";
|
||||
if (level === "high") return "最近健康台 run 有高优先级告警";
|
||||
if (level === "medium") return "最近健康台 run 需要继续重点关注";
|
||||
if (level === "low") return "当前处于恢复观察态";
|
||||
return "最近健康台 run 整体平稳";
|
||||
};
|
||||
|
||||
const trendText = () => {
|
||||
const label = workbenchTrend.value.label || "flat";
|
||||
if (label === "improving") return "改善中";
|
||||
if (label === "worsening") return "上升中";
|
||||
return "持平";
|
||||
};
|
||||
|
||||
const trendAlertText = () => {
|
||||
const level = workbenchTrend.value.alert_level || "none";
|
||||
if (level === "high") return "趋势高优先级告警";
|
||||
if (level === "medium") return "趋势需要继续重点关注";
|
||||
if (level === "low") return "趋势进入低优先级观察态";
|
||||
return "趋势平稳";
|
||||
};
|
||||
|
||||
const openImportRuns = () => {
|
||||
importRunDialogRef.value?.open();
|
||||
};
|
||||
|
||||
const openFailedQueue = () => {
|
||||
failedQueueDialogRef.value?.open();
|
||||
};
|
||||
|
||||
const openSelfHealingRuns = () => {
|
||||
selfHealingDialogRef.value?.open();
|
||||
};
|
||||
|
||||
const openManualAttention = () => {
|
||||
manualAttentionDialogRef.value?.open();
|
||||
};
|
||||
|
||||
const openManualHandleRuns = () => {
|
||||
manualHandleDialogRef.value?.open();
|
||||
};
|
||||
|
||||
const openRerunRuns = () => {
|
||||
rerunDialogRef.value?.open();
|
||||
};
|
||||
|
||||
const openRemediationRuns = () => {
|
||||
remediationDialogRef.value?.open();
|
||||
};
|
||||
|
||||
const openWorkbenchRuns = () => {
|
||||
workbenchSummaryDialogRef.value?.open();
|
||||
};
|
||||
|
||||
const openWorkbenchTrend = () => {
|
||||
workbenchTrendDialogRef.value?.open();
|
||||
};
|
||||
|
||||
const openClosureOverview = () => {
|
||||
requestGlobalDialogOpen("domainImportExternalSeoClosureDialog");
|
||||
};
|
||||
|
||||
const handlePriorityAction = async (actionKey?: string) => {
|
||||
if (actionKey === "open_import_runs") {
|
||||
openImportRuns();
|
||||
return;
|
||||
}
|
||||
if (actionKey === "open_failed_queue") {
|
||||
openFailedQueue();
|
||||
return;
|
||||
}
|
||||
if (actionKey === "open_self_healing_runs") {
|
||||
openSelfHealingRuns();
|
||||
return;
|
||||
}
|
||||
if (actionKey === "open_manual_attention") {
|
||||
openManualAttention();
|
||||
return;
|
||||
}
|
||||
if (actionKey === "open_manual_handle_runs") {
|
||||
openManualHandleRuns();
|
||||
return;
|
||||
}
|
||||
if (actionKey === "open_rerun_runs") {
|
||||
openRerunRuns();
|
||||
return;
|
||||
}
|
||||
if (actionKey === "open_remediation_runs") {
|
||||
openRemediationRuns();
|
||||
return;
|
||||
}
|
||||
if (actionKey === "run_self_healing") {
|
||||
await runSelfHealingAction();
|
||||
}
|
||||
};
|
||||
|
||||
const runSelfHealingAction = async () => {
|
||||
selfHealingLoading.value = true;
|
||||
try {
|
||||
const res = await runDomainImportSelfHealing();
|
||||
const job = res.data.job;
|
||||
if (!job?.job_id) {
|
||||
throw new Error("job_id missing");
|
||||
}
|
||||
ElMessage.success("自动修复任务已创建");
|
||||
taskConsoleDialogRef.value?.open("自动修复任务", job.job_id, async () => {
|
||||
await loadSummary();
|
||||
openSelfHealingRuns();
|
||||
});
|
||||
} catch (_error) {
|
||||
ElMessage.error("执行自动修复失败");
|
||||
} finally {
|
||||
selfHealingLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const runWorkbenchSummaryAction = async () => {
|
||||
workbenchRunLoading.value = true;
|
||||
try {
|
||||
const res = await runDomainImportHealthWorkbenchSummary({ limit: 10 });
|
||||
const job = res.data.job;
|
||||
if (!job?.job_id) {
|
||||
throw new Error("job_id missing");
|
||||
}
|
||||
ElMessage.success("健康台刷新任务已创建");
|
||||
taskConsoleDialogRef.value?.open("健康台落盘任务", job.job_id, async () => {
|
||||
await loadSummary();
|
||||
openWorkbenchRuns();
|
||||
});
|
||||
} catch (_error) {
|
||||
ElMessage.error("刷新并落盘健康台失败");
|
||||
} finally {
|
||||
workbenchRunLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const loadSummary = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
const [workbenchRes, runsRes, trendRes] = await Promise.all([
|
||||
getDomainImportHealthWorkbench({ limit: 10 }),
|
||||
getDomainImportHealthWorkbenchSummary({ limit: 10 }),
|
||||
getDomainImportHealthWorkbenchTrend({ limit: 10 })
|
||||
]);
|
||||
summary.value = workbenchRes.data ?? {};
|
||||
workbenchRunsSummary.value = runsRes.data ?? {};
|
||||
workbenchTrend.value = trendRes.data ?? {};
|
||||
} catch (_error) {
|
||||
ElMessage.error("读取导入健康台失败");
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const open = async () => {
|
||||
visible.value = true;
|
||||
await loadSummary();
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
open
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.import-health-workbench__toolbar {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.import-health-workbench__hero {
|
||||
padding: 14px 16px;
|
||||
border-radius: 12px;
|
||||
background: linear-gradient(135deg, #f3f8ff 0%, #eefaf4 100%);
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.import-health-workbench__hero-title {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.import-health-workbench__hero-desc,
|
||||
.import-health-workbench__hero-note,
|
||||
.import-health-workbench__stats,
|
||||
.import-health-workbench__resolved {
|
||||
font-size: 13px;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
.import-health-workbench__hero-note {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.import-health-workbench__stats {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.import-health-workbench__blocks {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 12px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.import-health-workbench__block {
|
||||
border: 1px solid #ebeef5;
|
||||
border-radius: 12px;
|
||||
padding: 12px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.import-health-workbench__block-title {
|
||||
font-size: 13px;
|
||||
color: #909399;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.import-health-workbench__resolved-label {
|
||||
margin-right: 8px;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.import-health-workbench__insights {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 12px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.import-health-workbench__insight-card {
|
||||
border: 1px solid #ebeef5;
|
||||
border-radius: 12px;
|
||||
padding: 12px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.import-health-workbench__mix-main {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.import-health-workbench__mix-sub,
|
||||
.import-health-workbench__empty {
|
||||
font-size: 13px;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
.import-health-workbench__actions {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 12px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.import-health-workbench__action-card {
|
||||
border: 1px solid #ebeef5;
|
||||
border-radius: 12px;
|
||||
padding: 12px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.import-health-workbench__action-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.import-health-workbench__action-title {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.import-health-workbench__action-summary {
|
||||
font-size: 13px;
|
||||
color: #606266;
|
||||
line-height: 1.6;
|
||||
min-height: 42px;
|
||||
}
|
||||
|
||||
.import-health-workbench__action-foot {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.import-health-workbench__panels {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 12px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.import-health-workbench__panel {
|
||||
border: 1px solid #ebeef5;
|
||||
border-radius: 12px;
|
||||
padding: 12px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.import-health-workbench__panel-title {
|
||||
font-size: 13px;
|
||||
color: #909399;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.import-health-workbench__panel-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
padding: 6px 0;
|
||||
font-size: 13px;
|
||||
color: #606266;
|
||||
border-top: 1px dashed #f0f2f5;
|
||||
}
|
||||
|
||||
.import-health-workbench__panel-row:first-of-type {
|
||||
border-top: 0;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user