|
|
@@ -242,7 +242,8 @@ function parseRuleBizFields(row: S8WatchRuleConfigRow): { objectLabel: string; m
|
|
|
}
|
|
|
try {
|
|
|
const p = JSON.parse(row.paramsJson) as Record<string, unknown>;
|
|
|
- const explicitThr = typeof p.thresholdDisplay === 'string' && p.thresholdDisplay ? p.thresholdDisplay : '';
|
|
|
+ const rawThr = typeof p.thresholdDisplay === 'string' && p.thresholdDisplay ? p.thresholdDisplay : '';
|
|
|
+ const explicitThr = rawThr.replace(/[((]\s*演示\s*[))]/g, '').replace(/演示/g, '').replace(/\s+/g, ' ').trim();
|
|
|
return {
|
|
|
objectLabel: deriveObjectLabel(row, p),
|
|
|
metricLabel: deriveMetricLabel(p),
|
|
|
@@ -282,6 +283,15 @@ function isSeedRule(row: S8WatchRuleConfigRow): boolean {
|
|
|
return code.startsWith('DEMO_') || /^RULE_S[1-7]_/.test(code);
|
|
|
}
|
|
|
|
|
|
+// 当前租户缺少该阶段业务源数据,对应自动规则未纳入运行范围;用于在列表中清楚标识,避免与已可运行规则混淆。
|
|
|
+const STAGE_DATA_UNAVAILABLE: Readonly<Record<string, string>> = {
|
|
|
+ S5: '当前租户库存源数据未就绪',
|
|
|
+};
|
|
|
+function stageDataUnavailableNote(row: S8WatchRuleConfigRow): string | null {
|
|
|
+ const stage = row.stageCode || '';
|
|
|
+ return STAGE_DATA_UNAVAILABLE[stage] ?? null;
|
|
|
+}
|
|
|
+
|
|
|
// CONFIG-RULE-EDIT-BIZ-VIEW-MVP-1:从 paramsJson 推导业务判定标准的中文展示(编辑抽屉摘要使用)。
|
|
|
function summarizeBizCondition(row: S8WatchRuleConfigRow | null): string {
|
|
|
if (!row) return '—';
|
|
|
@@ -682,7 +692,7 @@ async function loadMonitorOptions() {
|
|
|
monitorObjects.value = res?.objects ?? [];
|
|
|
} catch (e: any) {
|
|
|
monitorObjects.value = [];
|
|
|
- ElMessage.warning('监控对象/指标字典加载失败,已回退本地默认(不影响演示)');
|
|
|
+ ElMessage.warning('监控对象/指标字典加载失败,已回退本地默认,不影响当前页面已加载数据');
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -1057,6 +1067,12 @@ function isRunning(row: S8WatchRuleConfigRow) {
|
|
|
if (!row.lockUntil) return false;
|
|
|
return new Date(row.lockUntil).getTime() > Date.now();
|
|
|
}
|
|
|
+function runNowDisabledReason(row: S8WatchRuleConfigRow): string | null {
|
|
|
+ if (!row.enabled) return '规则停用后不会自动执行,请先启用';
|
|
|
+ if (isPaused(row)) return '规则已暂停,请先恢复';
|
|
|
+ if (isRunning(row)) return '当前规则正在执行,请稍后再试';
|
|
|
+ return null;
|
|
|
+}
|
|
|
function pollIntervalLabel(seconds: number | null | undefined) {
|
|
|
if (!seconds || seconds <= 0) return '—';
|
|
|
const preset = POLL_INTERVAL_PRESETS.find((p) => p.value === seconds);
|
|
|
@@ -1066,20 +1082,30 @@ function pollIntervalLabel(seconds: number | null | undefined) {
|
|
|
return `${Math.round(seconds / 3600)} 小时`;
|
|
|
}
|
|
|
function lastStatusTagType(status: string | null | undefined): 'success' | 'danger' | 'info' | '' {
|
|
|
- switch ((status ?? '').toUpperCase()) {
|
|
|
+ const key = (status ?? '').toUpperCase();
|
|
|
+ if (!key) return 'info';
|
|
|
+ switch (key) {
|
|
|
case 'SUCCESS': return 'success';
|
|
|
- case 'FAILED': return 'danger';
|
|
|
- case 'SKIPPED': return 'info';
|
|
|
+ case 'FAILED':
|
|
|
+ case 'EVALUATE_FAILED':
|
|
|
+ case 'QUERY_FAILED': return 'danger';
|
|
|
+ case 'SKIPPED':
|
|
|
+ case 'NO_HIT': return 'info';
|
|
|
default: return '';
|
|
|
}
|
|
|
}
|
|
|
// S8-CONFIG-UI-LABEL-CLEANUP-1:状态枚举中文化(仅展示层;DB 字段值不变)。
|
|
|
function lastStatusLabel(status: string | null | undefined): string {
|
|
|
- switch ((status ?? '').toUpperCase()) {
|
|
|
+ const key = (status ?? '').toUpperCase();
|
|
|
+ if (!key) return '未运行';
|
|
|
+ switch (key) {
|
|
|
case 'SUCCESS': return '成功';
|
|
|
- case 'FAILED': return '失败';
|
|
|
+ case 'FAILED':
|
|
|
+ case 'EVALUATE_FAILED':
|
|
|
+ case 'QUERY_FAILED': return '失败';
|
|
|
case 'SKIPPED': return '跳过';
|
|
|
- default: return status ?? '—';
|
|
|
+ case 'NO_HIT': return '无命中';
|
|
|
+ default: return status ?? '未运行';
|
|
|
}
|
|
|
}
|
|
|
function nextRunDisplay(row: S8WatchRuleConfigRow) {
|
|
|
@@ -1199,7 +1225,7 @@ onDeactivated(() => stopAutoRefresh());
|
|
|
</script>
|
|
|
|
|
|
<template>
|
|
|
- <AidopDemoShell title="规则配置中心" subtitle="配置异常监控规则、报警机制、监控对象与判定标准。新建后默认停用,演示前由人工启用。">
|
|
|
+ <AidopDemoShell title="规则配置中心" subtitle="配置异常监控规则、报警机制、监控对象与判定标准。新建后默认停用,确认配置后启用自动运行。">
|
|
|
<!-- S8-WATCH-RULE-CONFIG-CONSISTENCY-FIX-1:演示语义说明,避免用户把"已配规则"误解为"已在运行" -->
|
|
|
<el-alert
|
|
|
v-if="centerStats.disabled > 0"
|
|
|
@@ -1207,14 +1233,14 @@ onDeactivated(() => stopAutoRefresh());
|
|
|
:closable="false"
|
|
|
show-icon
|
|
|
style="margin-bottom: 8px"
|
|
|
- :title="`当前 ${centerStats.disabled} 条规则处于停用状态,调度器不会执行;大盘异常数据来自演示种子,不由本页规则实时产生。`"
|
|
|
+ :title="`当前 ${centerStats.disabled} 条规则处于停用状态,调度器不会执行;页面数据来自当前已入库异常记录,不由本页规则实时产生。`"
|
|
|
/>
|
|
|
<!-- CONFIG-RULE-CENTER-SHELL-MVP-1:主操作 + 统计 chip + 业务化筛选 + 前端分页 -->
|
|
|
<div class="rule-toolbar">
|
|
|
<el-button size="small" type="primary" @click="openWizard">新建监控配置</el-button>
|
|
|
<el-button size="small" @click="openDraftDrawer">草稿配置 ({{ draftCount }})</el-button>
|
|
|
<el-button size="small" @click="loadRows" :loading="loading">手动刷新</el-button>
|
|
|
- <el-checkbox v-model="showAdvancedColumns" size="small" style="margin-left: 8px">显示运行态</el-checkbox>
|
|
|
+ <el-checkbox v-model="showAdvancedColumns" size="small" style="margin-left: 8px">显示技术列</el-checkbox>
|
|
|
<span class="rule-toolbar__hint">每 30 秒自动刷新;编辑抽屉打开期间暂停刷新</span>
|
|
|
</div>
|
|
|
|
|
|
@@ -1321,11 +1347,19 @@ onDeactivated(() => stopAutoRefresh());
|
|
|
<span :class="{ 'rule-biz-empty': parseRuleBizFields(row).thresholdDisplay === '未配置' }">{{ parseRuleBizFields(row).thresholdDisplay }}</span>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column label="状态" width="120">
|
|
|
+ <el-table-column label="状态" width="180">
|
|
|
<template #default="{ row }">
|
|
|
<el-tag :type="row.enabled ? 'success' : 'info'" size="small">{{ row.enabled ? '启用' : '停用' }}</el-tag>
|
|
|
<!-- S8-WATCH-RULE-CONFIG-CONSISTENCY-FIX-1:SeedData / DEMO 规则标记,避免被误读为生产运行规则 -->
|
|
|
- <el-tag v-if="isSeedRule(row)" size="small" type="warning" effect="plain" style="margin-left: 4px">演示</el-tag>
|
|
|
+ <el-tag v-if="isSeedRule(row)" size="small" type="warning" effect="plain" style="margin-left: 4px">系统预置</el-tag>
|
|
|
+ <!-- 当前租户业务源数据未就绪的阶段,明确标识其规则未纳入自动运行范围 -->
|
|
|
+ <el-tooltip
|
|
|
+ v-if="stageDataUnavailableNote(row)"
|
|
|
+ :content="`${stageDataUnavailableNote(row)},需补齐后启用`"
|
|
|
+ placement="top"
|
|
|
+ >
|
|
|
+ <el-tag size="small" type="warning" effect="dark" style="margin-left: 4px">未纳入自动运行</el-tag>
|
|
|
+ </el-tooltip>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
<el-table-column label="严重度" width="80">
|
|
|
@@ -1340,10 +1374,10 @@ onDeactivated(() => stopAutoRefresh());
|
|
|
</template>
|
|
|
<template #default="{ row }">{{ pollIntervalLabel(row.pollIntervalSeconds) }}</template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column prop="ruleCode" label="内部编码" width="200" show-overflow-tooltip>
|
|
|
+ <el-table-column v-if="showAdvancedColumns" prop="ruleCode" label="内部编码" width="200" show-overflow-tooltip>
|
|
|
<template #default="{ row }"><span class="rule-code-mono">{{ row.ruleCode }}</span></template>
|
|
|
</el-table-column>
|
|
|
- <!-- 运行态高级列:默认隐藏,由"显示运行态"开关控制 -->
|
|
|
+ <!-- 技术列:默认隐藏,由"显示技术列"开关控制 -->
|
|
|
<el-table-column v-if="showAdvancedColumns" label="规则类型" width="100">
|
|
|
<template #default="{ row }">
|
|
|
<el-tag :type="row.ruleType ? 'success' : 'info'" size="small">{{ ruleTypeLabel(row.ruleType) }}</el-tag>
|
|
|
@@ -1356,7 +1390,7 @@ onDeactivated(() => stopAutoRefresh());
|
|
|
<el-table-column v-if="showAdvancedColumns" label="持续正常次数" width="115">
|
|
|
<template #default="{ row }">连续 {{ row.recoverCountRequired ?? 1 }} 次</template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column v-if="showAdvancedColumns" label="上次执行" width="160">
|
|
|
+ <el-table-column label="上次执行" width="160">
|
|
|
<template #default="{ row }">
|
|
|
<el-tooltip v-if="row.lastRunAt" :content="String(row.lastRunAt)" placement="top">
|
|
|
<span>{{ row.lastRunAt }}</span>
|
|
|
@@ -1364,17 +1398,16 @@ onDeactivated(() => stopAutoRefresh());
|
|
|
<span v-else>—</span>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column v-if="showAdvancedColumns" label="下次执行" width="160">
|
|
|
+ <el-table-column label="下次执行" width="160">
|
|
|
<template #default="{ row }">
|
|
|
<el-tag v-if="isPaused(row)" type="warning" size="small">已暂停</el-tag>
|
|
|
<el-tag v-else-if="isRunning(row)" type="info" size="small">执行中</el-tag>
|
|
|
<span v-else>{{ nextRunDisplay(row) }}</span>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column v-if="showAdvancedColumns" label="上次状态" width="100">
|
|
|
+ <el-table-column label="上次状态" width="100">
|
|
|
<template #default="{ row }">
|
|
|
- <el-tag v-if="row.lastStatus" :type="lastStatusTagType(row.lastStatus)" size="small">{{ lastStatusLabel(row.lastStatus) }}</el-tag>
|
|
|
- <span v-else>—</span>
|
|
|
+ <el-tag :type="lastStatusTagType(row.lastStatus)" size="small">{{ lastStatusLabel(row.lastStatus) }}</el-tag>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
<el-table-column v-if="showAdvancedColumns" label="失败次数" width="90">
|
|
|
@@ -1386,7 +1419,7 @@ onDeactivated(() => stopAutoRefresh());
|
|
|
<el-table-column v-if="showAdvancedColumns" label="耗时" width="80">
|
|
|
<template #default="{ row }">{{ row.lastDurationMs != null ? `${row.lastDurationMs}ms` : '—' }}</template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column v-if="showAdvancedColumns" label="错误摘要" min-width="180" show-overflow-tooltip>
|
|
|
+ <el-table-column label="错误摘要" min-width="180" show-overflow-tooltip>
|
|
|
<template #default="{ row }">
|
|
|
<el-tooltip v-if="row.lastError" :content="String(row.lastError)" placement="top">
|
|
|
<span class="rule-error">{{ mapLastError(row.lastError) }}</span>
|
|
|
@@ -1397,7 +1430,11 @@ onDeactivated(() => stopAutoRefresh());
|
|
|
<el-table-column label="操作" width="320" fixed="right">
|
|
|
<template #default="{ row }">
|
|
|
<el-button size="small" type="primary" link @click="openEdit(row)">编辑</el-button>
|
|
|
- <el-button size="small" type="success" link :disabled="!row.enabled || isPaused(row) || isRunning(row)" @click="runNow(row)">立即执行</el-button>
|
|
|
+ <el-tooltip :disabled="!runNowDisabledReason(row)" :content="runNowDisabledReason(row) ?? ''" placement="top">
|
|
|
+ <span>
|
|
|
+ <el-button size="small" type="success" link :disabled="!!runNowDisabledReason(row)" @click="runNow(row)">立即执行</el-button>
|
|
|
+ </span>
|
|
|
+ </el-tooltip>
|
|
|
<el-button v-if="!isPaused(row)" size="small" type="warning" link @click="pauseRule(row)">暂停</el-button>
|
|
|
<el-button v-else size="small" type="success" link @click="resumeRule(row)">恢复</el-button>
|
|
|
<el-button v-if="!isPaused(row) && (row.consecutiveFailureCount ?? 0) > 0" size="small" type="success" link @click="resumeRule(row)">重置失败</el-button>
|