Files
aiops/frontend/src/pages/monitor/site-monitor/helpers.ts
T
attacker 4c4aaf60f6 fix(i18n): U18 幻影 i18n hash 键治理 — 从 git 历史恢复 1540/1696 处原始中文文本 (91%)
问题: i18n 批量转换 (commit 55f216c) 生成了 813 个 hash 键引用但翻译从未写入 JSON,
导致用户在受影响模块看到 hash 键路径(如 monitor.quickquerybarts.s64559524)而非实际文本.
影响范围: 126 个文件、1696 处引用、monitor/kubernetes/aiops/pipeline/task/agent/cloud 11 个命名空间.

修复策略: 用 git 历史中 pre-i18n 版本(commit 7e1c8f5)的原始中文文本,
通过结构相似度匹配(difflib SequenceMatcher)将 hash 键引用替换为实际字符串.
对于组件拆分后产生的新文件,映射到其原始源文件查找中文文本.

修复明细:
- monitor 命名空间: 335 键修复(站点拨测/日志中心/中间件监控/告警规则/SNMP/主机监控)
- kubernetes 命名空间: 195 键修复(资源编辑器/Deployment编辑器/事件/命名空间/Pod日志)
- aiops 命名空间: 70 键修复(容量预测/成本预测/告警分析)
- pipeline/task/agent/cloud/common 命名空间: 其余键修复

验证: tsc -b=0, npm build✓ (16.87s), ESLint=0/0/0, go build=0, 17/17 测试通过, Docker healthy
2026-07-11 05:49:23 +08:00

172 lines
5.7 KiB
TypeScript

import i18n from '@/i18n';
// 站点拨测辅助函数 // Logan.Li
export const PROBE_TYPE_OPTIONS = ['HTTP', 'SSL', 'TCP', 'DNS', 'PING'] as const;
export type ProbeType = (typeof PROBE_TYPE_OPTIONS)[number];
export interface SiteTask {
id: number;
name: string;
url: string;
type: string;
frequency_sec: number;
timeout_sec: number;
expected_status_code: number;
enabled: boolean;
last_status?: string;
last_response_time_ms?: number;
last_checked_at?: string;
success_rate?: number;
alert_status?: 'normal' | 'alerting';
created_at: string;
ssl_days_remaining?: number;
ssl_cert_expiry?: string;
}
export interface SiteResult {
id: number;
task_id: number;
status: string;
http_status_code?: number;
response_time?: number;
total_time: number;
remote_ip?: string;
error_message?: string;
checked_at: string;
ssl_days_remaining?: number;
ssl_cert_expiry?: string;
ssl_cert_issuer?: string;
}
export interface SiteStats {
total_tasks: number;
enabled_tasks: number;
up_count: number;
down_count: number;
availability: number;
probe_count: number;
}
export type SiteTimeRange = '1h' | '6h' | '24h' | '7d';
export const SITE_TIME_RANGE_HOURS: Record<SiteTimeRange, number> = {
'1h': 1,
'6h': 6,
'24h': 24,
'7d': 168,
};
export const SITE_TIME_RANGE_LABELS: Record<SiteTimeRange, string> = {
'1h': i18n.t('近 1 小时'),
'6h': i18n.t('monitor.siteProtocol.rangeDefault'),
'24h': i18n.t('近 24 小时'),
'7d': i18n.t('近 7 天'),
};
/** 各协议推荐默认拨测间隔(秒)// Logan.Li */
export const DEFAULT_PROBE_FREQUENCY: Record<ProbeType, number> = {
HTTP: 60,
SSL: 3600,
TCP: 120,
DNS: 300,
PING: 120,
};
/** 各协议最小拨测间隔(秒)// Logan.Li */
export const MIN_PROBE_FREQUENCY: Record<ProbeType, number> = {
HTTP: 30,
SSL: 600,
TCP: 30,
DNS: 60,
PING: 30,
};
export function defaultProbeFrequency(type: ProbeType): number {
return DEFAULT_PROBE_FREQUENCY[type] ?? 60;
}
export const probeTypeMeta: Record<ProbeType, { label: string; placeholder: string; hint: string }> = {
HTTP: { label: i18n.t('目标 URL'), placeholder: 'https://example.com/health', hint: i18n.t('Web 请求(支持 http/https),检测状态码与响应时间') },
SSL: { label: i18n.t('SSL 地址'), placeholder: i18n.t('example.com:443 或 https://example.com'), hint: i18n.t('TLS 握手检测证书(支持 host:port / https:// 域名,不发起 HTTP 请求)') },
TCP: { label: i18n.t('主机:端口'), placeholder: i18n.t('192.168.1.1:8080 或 example.com:443'), hint: i18n.t('TCP 端口连通性') },
DNS: { label: i18n.t('cloud.domainName'), placeholder: 'example.com', hint: i18n.t('monitor.helpersts.sd3fd8f1d') },
PING: { label: i18n.t('主机地址'), placeholder: i18n.t('192.168.1.1 或 example.com'), hint: i18n.t('ICMP 连通性与延迟(默认 2 分钟/次)') },
};
export function probeFrequencyHint(type: ProbeType): string {
const sec = defaultProbeFrequency(type);
return `推荐 ${fmtFrequency(sec)},最小 ${fmtFrequency(MIN_PROBE_FREQUENCY[type])}`;
}
/** 拨测频率展示 // Logan.Li */
export function fmtFrequency(sec?: number): string {
if (!sec) return '--';
if (sec < 60) return `${sec}秒`;
if (sec < 3600) return `${Math.round(sec / 60)}分钟`;
return `${(sec / 3600).toFixed(1)}小时`;
}
/** 可用率 / 响应时间组合展示 // Logan.Li */
export function fmtAvailResponse(task: Pick<SiteTask, 'success_rate' | 'last_response_time_ms'>): string {
const avail = task.success_rate != null && task.success_rate >= 0
? `${task.success_rate.toFixed(1)}%`
: '--';
return `${avail} / ${fmtMs(task.last_response_time_ms)}`;
}
export function fmtMs(ms?: number): string {
if (ms == null) return '--';
if (ms < 1) return '0ms';
if (ms < 1000) return `${Math.round(ms)}ms`;
return `${(ms / 1000).toFixed(2)}s`;
}
/** 列表时间:MM-DD HH:mm // Logan.Li */
export function fmtTime(iso?: string): string {
if (!iso) return '--';
const d = new Date(iso);
const pad = (n: number) => String(n).padStart(2, '0');
return `${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`;
}
/** SSL 证书预警阈值(天)// Logan.Li */
export const SSL_EXPIRY_WARN_DAYS = 30;
/** 是否为 SSL 证书拨测任务 // Logan.Li */
export function isSslProbeTask(task: Pick<SiteTask, 'type'>): boolean {
const t = task.type?.toUpperCase();
return t === 'SSL' || t === 'HTTPS';
}
/** 证书是否进入预警期(默认 < 30 天)// Logan.Li */
export function isSslExpiringSoon(days?: number, threshold = SSL_EXPIRY_WARN_DAYS): boolean {
return days != null && days < threshold;
}
/** SSL 证书剩余天数展示 // Logan.Li */
export function fmtSslDays(days?: number): { text: string; tone: string } {
if (days == null) return { text: '--', tone: 'text-[var(--dg-text-muted)]' };
if (days < 0) return { text: i18n.t('system.expired2'), tone: 'dg-text-red' };
if (days <= 7) return { text: `${days}天`, tone: 'dg-text-red' };
if (days <= 30) return { text: `${days}天`, tone: 'dg-text-yellow' };
return { text: `${days}天`, tone: 'dg-text-green' };
}
/** 归一化拨测协议类型 // Logan.Li */
export function normalizeProbeType(raw?: string): ProbeType {
const upper = (raw || 'HTTP').toUpperCase();
if (upper === 'HTTPS') return 'HTTP';
if (PROBE_TYPE_OPTIONS.includes(upper as ProbeType)) return upper as ProbeType;
return 'HTTP';
}
export function isHttpProbeTask(task: Pick<SiteTask, 'type'>): boolean {
return normalizeProbeType(task.type) === 'HTTP';
}
export function fmtChartTime(iso?: string): string {
if (!iso) return '';
const d = new Date(iso);
const pad = (n: number) => String(n).padStart(2, '0');
return `${pad(d.getHours())}:${pad(d.getMinutes())}`;
}