// 第三方服务巡检(svc_health)的前端共享类型与展示辅助。 // 巡检页(pages/svcinspect.vue) 与仪表盘告警条(components/SvcAlertBanner.vue) 共用, // 保证两处对「状态怎么叫、原因怎么写、区域怎么显示」的口径完全一致。 // 与后端 comm/svchealth.go 的 SvcHealth 字段一一对应。 export interface SvcHealth { app_name: string svc_id: string region: number // 0=服务默认配置,>0=该区域的覆盖配置 name: string provider: string categories: string enable: boolean status: 'ok' | 'warn' | 'error' | 'skip' config_issues: string[] | null probe_kind: 'none' | 'reachable' | 'credential' probe_ok: boolean probe_msg: string latency_ms: number fail_streak: number last_ok_at: number checked_at: number duration_ms: number } // 区域枚举(与 pb.Region、serviceconfig.vue 的 REGIONS 一致)。 export const REGION_LABEL: Record = { 1: '中国', 2: '美国', 3: '东亚', 4: '东南亚', 5: '南亚', 6: '中东', 7: '欧洲', 8: '俄罗斯', 9: '非洲', 10: '南美', 11: '北美', 12: '大洋洲', 13: '巴西', 14: '印度', } // 服务类别(与后端 svcCatXxx、serviceconfig.vue 的 SCAT 一致)。 export const CAT_LABEL: Record = { 1: 'STT', 2: 'TTS', 3: 'MT', 4: 'AST', 5: '文本LLM', 6: '存储', 7: 'STS', 8: '录音识别', 9: '多媒体LLM', 10: 'MCP', } export const STATUS_META: Record = { error: { label: '不可用', color: '#be123c', bg: '#ffe4e6' }, warn: { label: '有隐患', color: '#b45309', bg: '#fef3c7' }, ok: { label: '正常', color: '#047857', bg: '#d1fae5' }, skip: { label: '已停用', color: '#64748b', bg: '#f1f5f9' }, } // 探测方式的人话说明。核心是让「未探测」不被误读成「已验证通过」。 export const PROBE_META: Record = { credential: { label: '凭据已验证', hint: '已用真实凭据调通服务商接口' }, reachable: { label: '仅连通性', hint: '地址可达,但未验证凭据是否有效' }, none: { label: '未探测', hint: '暂无该服务商的探针,可用性未经验证' }, } // healthReason 一句话说清「为什么是这个状态」,供告警条与表格摘要列使用。 // 优先级:致命配置问题 > 探测失败原因 > 非致命隐患 > 探测结论。 export function healthReason(h: SvcHealth): string { const issues = h.config_issues || [] const fatal = issues.filter((s) => s.startsWith('[致命] ')) if (fatal.length) return fatal.map((s) => s.replace('[致命] ', '')).join(';') if (h.status === 'error') return h.probe_msg || '巡检失败' if (issues.length) return issues.join(';') if (h.probe_kind === 'none') return h.probe_msg || '未验证可用性' return h.probe_msg || '' } // healthLastRunText 把巡检时间戳渲染成「刚刚 / N 分钟前 / N 小时前 / 日期」。 export function healthLastRunText(ms: number): string { if (!ms) return '尚未执行' const diff = Date.now() - ms if (diff < 60_000) return '刚刚' if (diff < 3_600_000) return `${Math.floor(diff / 60_000)} 分钟前` if (diff < 86_400_000) return `${Math.floor(diff / 3_600_000)} 小时前` return new Date(ms).toLocaleString('zh-CN', { hour12: false }) } // parseCats 把逗号分隔的 categories 解析成类别数值数组。 export function parseCats(categories: string): number[] { return (categories || '') .split(',') .map((s) => Number(s.trim())) .filter((n) => !Number.isNaN(n) && n > 0) }