diff --git a/admin/dashboard/templates/index.html b/admin/dashboard/templates/index.html
index 1244618..ca637f0 100644
--- a/admin/dashboard/templates/index.html
+++ b/admin/dashboard/templates/index.html
@@ -676,6 +676,29 @@
levelClass: level.className || ''
};
},
+ buildLatencyMeter(label, latencyMs, warningThreshold = 1200, dangerThreshold = 3000) {
+ // 耗时不是天然百分比,这里映射成一个“压力条”视图:
+ // 1. 低于 warningThreshold 视为较平稳;
+ // 2. 接近 dangerThreshold 时让条形接近满格;
+ // 3. 超过 dangerThreshold 直接按 100% 展示,首页一眼就能看出慢调用风险。
+ const latency = Number(latencyMs || 0);
+ const safeLatency = Number.isNaN(latency) ? 0 : Math.max(0, latency);
+ const percent = Math.max(0, Math.min(100, (safeLatency / dangerThreshold) * 100));
+ return this.buildMeter(
+ label,
+ percent,
+ `${this.formatMetricNumber(safeLatency, 2)} ms`,
+ () => this.buildRiskLevel(percent, (warningThreshold / dangerThreshold) * 100, 100)
+ );
+ },
+ buildRatioPercent(numerator, denominator) {
+ const num = Number(numerator || 0);
+ const den = Number(denominator || 0);
+ if (Number.isNaN(num) || Number.isNaN(den) || den <= 0) {
+ return 0;
+ }
+ return this.normalizePercent((num / den) * 100);
+ },
countHealthyInfrastructureServices(infrastructure) {
const mysql = infrastructure.mysql || {};
const redis = infrastructure.redis || {};
@@ -774,11 +797,66 @@
},
buildAiRuntimeServiceBlocks(aiRuntime) {
return [
+ {
+ key: 'ai-overview',
+ title: '运行总览',
+ status: aiRuntime.status || 'warning',
+ summary: aiRuntime.summary || '暂无状态',
+ highlights: [
+ {
+ label: '最近调用',
+ value: this.formatMetricNumber(aiRuntime.total_calls),
+ tone: 'neutral'
+ },
+ {
+ label: '失败次数',
+ value: this.formatMetricNumber(aiRuntime.failed_calls),
+ tone: Number(aiRuntime.failed_calls || 0) > 0 ? 'warning' : 'healthy'
+ },
+ {
+ label: '最近记录',
+ value: aiRuntime.last_timestamp || '-',
+ tone: aiRuntime.last_timestamp ? 'info' : 'neutral'
+ }
+ ],
+ meters: [
+ this.buildMeter(
+ '成功率',
+ aiRuntime.success_rate,
+ `${this.formatMetricNumber(aiRuntime.success_rate, 2)}%`,
+ (percent) => this.buildPositiveLevel(percent, 70, 95)
+ ),
+ this.buildLatencyMeter(
+ '平均耗时',
+ aiRuntime.avg_latency_ms,
+ 1200,
+ 3000
+ )
+ ],
+ metrics: [
+ { label: '最近场景', value: aiRuntime.last_scene || '-' },
+ { label: '最近后端', value: aiRuntime.last_backend || '-' },
+ { label: '最近模型', value: aiRuntime.last_model || '-' },
+ { label: '最近错误', value: aiRuntime.last_error || '无' }
+ ]
+ },
{
key: 'ai-routing',
title: '路由配置',
status: aiRuntime.has_routing ? 'healthy' : 'warning',
summary: aiRuntime.default_scene ? `默认场景:${aiRuntime.default_scene}` : '当前未设置默认场景',
+ highlights: [
+ {
+ label: '默认场景',
+ value: aiRuntime.default_scene || '-',
+ tone: aiRuntime.default_scene ? 'healthy' : 'warning'
+ },
+ {
+ label: '默认后端',
+ value: aiRuntime.default_backend || '-',
+ tone: aiRuntime.default_backend ? 'healthy' : 'warning'
+ }
+ ],
metrics: [
{ label: '场景数量', value: this.formatMetricNumber(aiRuntime.scene_count) },
{ label: '目标数量', value: this.formatMetricNumber(aiRuntime.target_count) },
@@ -791,12 +869,33 @@
title: '最近调用',
status: (aiRuntime.failed_calls || 0) > 0 ? 'warning' : ((aiRuntime.total_calls || 0) > 0 ? 'healthy' : 'warning'),
summary: aiRuntime.last_timestamp ? `最近一次记录时间:${aiRuntime.last_timestamp}` : '当前窗口内暂无调用记录',
+ highlights: [
+ {
+ label: 'Provider',
+ value: aiRuntime.last_provider || '-',
+ tone: 'neutral'
+ },
+ {
+ label: 'Backend',
+ value: aiRuntime.last_backend || '-',
+ tone: 'neutral'
+ },
+ {
+ label: 'Scene',
+ value: aiRuntime.last_scene || '-',
+ tone: 'neutral'
+ }
+ ],
+ meters: [
+ this.buildLatencyMeter(
+ '最近耗时',
+ aiRuntime.last_latency_ms,
+ 1200,
+ 3000
+ )
+ ],
metrics: [
- { label: 'Provider', value: aiRuntime.last_provider || '-' },
- { label: 'Backend', value: aiRuntime.last_backend || '-' },
- { label: 'Scene', value: aiRuntime.last_scene || '-' },
{ label: '模型', value: aiRuntime.last_model || '-' },
- { label: '最近耗时', value: `${this.formatMetricNumber(aiRuntime.last_latency_ms, 2)} ms` },
{ label: '最近错误', value: aiRuntime.last_error || '无' }
]
}
@@ -812,6 +911,31 @@
title: '任务装载',
status: scheduler.enabled_jobs > 0 ? 'healthy' : 'warning',
summary: scheduler.next_run_at ? `下一次执行:${scheduler.next_run_at}` : '当前没有可计算的下一次执行时间',
+ highlights: [
+ {
+ label: '总任务',
+ value: this.formatMetricNumber(scheduler.total_jobs),
+ tone: 'neutral'
+ },
+ {
+ label: '启用任务',
+ value: this.formatMetricNumber(scheduler.enabled_jobs),
+ tone: Number(scheduler.enabled_jobs || 0) > 0 ? 'healthy' : 'warning'
+ },
+ {
+ label: '下次执行',
+ value: scheduler.next_run_at || '-',
+ tone: scheduler.next_run_at ? 'info' : 'warning'
+ }
+ ],
+ meters: [
+ this.buildMeter(
+ '启用率',
+ this.buildRatioPercent(scheduler.enabled_jobs, scheduler.total_jobs),
+ `${this.formatMetricNumber(this.buildRatioPercent(scheduler.enabled_jobs, scheduler.total_jobs), 1)}%`,
+ (percent) => this.buildPositiveLevel(percent, 50, 80)
+ )
+ ],
metrics: [
{ label: '启用任务', value: this.formatMetricNumber(scheduler.enabled_jobs) },
{ label: '暂停任务', value: this.formatMetricNumber(scheduler.paused_jobs) },
@@ -824,12 +948,66 @@
title: '执行状态',
status: scheduler.status || 'warning',
summary: scheduler.latest_failed_job_name ? `最近失败任务:${scheduler.latest_failed_job_name}` : '当前未发现最近失败任务',
+ highlights: [
+ {
+ label: '执行中',
+ value: this.formatMetricNumber(scheduler.running_jobs),
+ tone: Number(scheduler.running_jobs || 0) > 0 ? 'info' : 'neutral'
+ },
+ {
+ label: '失败任务',
+ value: this.formatMetricNumber(scheduler.failed_jobs),
+ tone: Number(scheduler.failed_jobs || 0) > 0 ? 'warning' : 'healthy'
+ },
+ {
+ label: '非法调度',
+ value: this.formatMetricNumber(scheduler.invalid_jobs),
+ tone: Number(scheduler.invalid_jobs || 0) > 0 ? 'danger' : 'healthy'
+ }
+ ],
+ meters: [
+ this.buildMeter(
+ '失败占比',
+ this.buildRatioPercent(scheduler.failed_jobs, scheduler.total_jobs),
+ `${this.formatMetricNumber(this.buildRatioPercent(scheduler.failed_jobs, scheduler.total_jobs), 1)}%`,
+ (percent) => this.buildRiskLevel(percent, 10, 30)
+ ),
+ this.buildMeter(
+ '未运行占比',
+ this.buildRatioPercent(scheduler.never_run_jobs, scheduler.total_jobs),
+ `${this.formatMetricNumber(this.buildRatioPercent(scheduler.never_run_jobs, scheduler.total_jobs), 1)}%`,
+ (percent) => this.buildRiskLevel(percent, 20, 50)
+ )
+ ],
metrics: [
{ label: '执行中', value: this.formatMetricNumber(scheduler.running_jobs) },
{ label: '失败任务', value: this.formatMetricNumber(scheduler.failed_jobs) },
{ label: '非法调度', value: this.formatMetricNumber(scheduler.invalid_jobs) },
{ label: '未执行过', value: this.formatMetricNumber(scheduler.never_run_jobs) }
]
+ },
+ {
+ key: 'scheduler-last-failure',
+ title: '失败与恢复',
+ status: scheduler.latest_failed_error ? 'warning' : (scheduler.status || 'healthy'),
+ summary: scheduler.latest_failed_error ? '当前存在最近失败原因摘要' : '最近未记录到失败原因',
+ highlights: [
+ {
+ label: '最近失败任务',
+ value: scheduler.latest_failed_job_name || '无',
+ tone: scheduler.latest_failed_job_name ? 'warning' : 'healthy'
+ },
+ {
+ label: '最近失败原因',
+ value: scheduler.latest_failed_error || '无',
+ tone: scheduler.latest_failed_error ? 'warning' : 'healthy'
+ }
+ ],
+ metrics: [
+ { label: '下次执行', value: scheduler.next_run_at || '-' },
+ { label: '系统任务', value: this.formatMetricNumber(scheduler.system_job_count) },
+ { label: '插件任务', value: this.formatMetricNumber(scheduler.plugin_job_count) }
+ ]
}
];
},