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) } + ] } ]; },