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 = { '1h': 1, '6h': 6, '24h': 24, '7d': 168, }; export const SITE_TIME_RANGE_LABELS: Record = { '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 = { HTTP: 60, SSL: 3600, TCP: 120, DNS: 300, PING: 120, }; /** 各协议最小拨测间隔(秒)// Logan.Li */ export const MIN_PROBE_FREQUENCY: Record = { 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 = { 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): 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): 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): 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())}`; }