From b2715ca3bd79d4f25dd0b8754295a5714c4a9394 Mon Sep 17 00:00:00 2001 From: attacker Date: Sun, 12 Jul 2026 05:18:52 +0800 Subject: [PATCH] =?UTF-8?q?refactor(i18n):=20U28=20=E5=A4=9A=E6=A8=A1?= =?UTF-8?q?=E5=9D=97=20phantom=20key=20=E6=B8=85=E9=9B=B6=20=E2=80=94=20th?= =?UTF-8?q?eme/middleware-monitor/site-monitor/analytics/cost-predict/pred?= =?UTF-8?q?ict-types/agentAlertHelper/export-audit/AgentCLIMessages/copy-b?= =?UTF-8?q?utton=2010=20=E6=96=87=E4=BB=B6=2074=20phantom=20key=20?= =?UTF-8?q?=E2=86=92=20=E8=AF=AD=E4=B9=89=E5=8C=96=E9=94=AE,=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=204=20=E5=91=BD=E5=90=8D=E7=A9=BA=E9=97=B4=20(theme/a?= =?UTF-8?q?gent.alerts.metric*/audit.*)=20+=20=E6=89=A9=E5=B1=95=203=20?= =?UTF-8?q?=E5=91=BD=E5=90=8D=E7=A9=BA=E9=97=B4=20(monitor.lbl.mw*/site*/a?= =?UTF-8?q?iops.predict*),=20zh/en=207294=E2=86=927358=20+64=20=E9=94=AE?= =?UTF-8?q?=E5=AF=B9=E9=BD=90,=20phantom=20key=20103=E2=86=9229=20(?= =?UTF-8?q?=E6=AE=8B=E7=95=99=E5=85=A8=E4=B8=BA=20JSX=20=E6=A8=A1=E6=9D=BF?= =?UTF-8?q?=E8=A1=A8=E8=BE=BE=E5=BC=8F/ANSI=20=E8=BD=AC=E4=B9=89=E7=A0=81?= =?UTF-8?q?=E8=AF=AF=E5=8C=B9=E9=85=8D),=20tsc=20-b=3D0,=20npm=20build?= =?UTF-8?q?=E2=9C=93=20(17.40s),=20ESLint=3D0/53/0,=20go=20build=3D0,=2017?= =?UTF-8?q?/17=20=E6=B5=8B=E8=AF=95=E9=80=9A=E8=BF=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/agent/agentAlertHelper.tsx | 8 +- .../src/components/aiops/AgentCLIMessages.tsx | 6 +- frontend/src/components/aiops/cost-predict.ts | 14 ++-- .../src/components/aiops/predict-types.ts | 10 +-- .../components/system/replay/export-audit.ts | 6 +- frontend/src/components/ui/copy-button.tsx | 2 +- frontend/src/locales/en-US.json | 76 +++++++++++++++++-- frontend/src/locales/zh-CN.json | 76 +++++++++++++++++-- .../monitor/middleware-monitor/helpers.ts | 40 +++++----- .../src/pages/monitor/site-monitor/helpers.ts | 14 ++-- .../site-monitor/observability/analytics.ts | 10 +-- frontend/src/utils/theme.ts | 18 ++--- 12 files changed, 206 insertions(+), 74 deletions(-) diff --git a/frontend/src/components/agent/agentAlertHelper.tsx b/frontend/src/components/agent/agentAlertHelper.tsx index 8c402cf..563592a 100644 --- a/frontend/src/components/agent/agentAlertHelper.tsx +++ b/frontend/src/components/agent/agentAlertHelper.tsx @@ -13,12 +13,12 @@ export const METRIC_OPTIONS = [ { value: 'cpu_iowait', label: i18n.t('agent.alertHelper.netInBps'), icon: Cpu }, { value: 'mem', label: i18n.t('kubernetes.cluster.memoryUsage'), icon: MemoryStick }, { value: 'mem_available', label: i18n.t('agent.alertHelper.memAvailable'), icon: MemoryStick }, - { value: 'swap', label: i18n.t('Swap 使用率'), icon: MemoryStick }, - { value: 'load1', label: i18n.t('1分钟负载'), icon: Gauge }, + { value: 'swap', label: i18n.t('agent.alerts.metricSwap'), icon: MemoryStick }, + { value: 'load1', label: i18n.t('agent.alerts.metricLoad1'), icon: Gauge }, { value: 'disk', label: i18n.t('monitor.hostDisk'), icon: HardDrive }, - { value: 'disk_inode', label: i18n.t('Inode 使用率'), icon: HardDrive }, + { value: 'disk_inode', label: i18n.t('agent.alerts.metricInode'), icon: HardDrive }, { value: 'disk_io_util', label: i18n.t('agent.alertHelper.diskIOUtil'), icon: HardDrive }, - { value: 'tcp_established', label: i18n.t('TCP 已建立'), icon: Network }, + { value: 'tcp_established', label: i18n.t('agent.alerts.metricTcpEst'), icon: Network }, { value: 'tcp_time_wait', label: 'TCP TIME_WAIT', icon: Network }, { value: 'tcp_close_wait', label: 'TCP CLOSE_WAIT', icon: Network }, { value: 'net_rx_bps', label: i18n.t('monitor.hostNetIn'), icon: Network }, diff --git a/frontend/src/components/aiops/AgentCLIMessages.tsx b/frontend/src/components/aiops/AgentCLIMessages.tsx index 1c2c85e..02cedd0 100644 --- a/frontend/src/components/aiops/AgentCLIMessages.tsx +++ b/frontend/src/components/aiops/AgentCLIMessages.tsx @@ -253,7 +253,7 @@ export function MessageView({ item, inRoundGroup = false }: { item: ChatItem; in return (
-
{item.content || i18n.t('发生错误')}
+
{item.content || i18n.t('aiops.agentCliErrorOccurred')}
); } @@ -309,10 +309,10 @@ function ToolBlock({ item, inRoundGroup }: { item: ChatItem; inRoundGroup?: bool {item.duration &&
{i18n.t('aiops.durationLabel', { duration: item.duration })}
} {(item.toolName === 'analyze_output' || looksLikeMarkdown(item.output)) ? (
- +
) : ( -
{item.output || i18n.t('(无输出)')}
+
{item.output || i18n.t('aiops.agentCliNoOutput')}
)} )} diff --git a/frontend/src/components/aiops/cost-predict.ts b/frontend/src/components/aiops/cost-predict.ts index a5a052e..5151e55 100644 --- a/frontend/src/components/aiops/cost-predict.ts +++ b/frontend/src/components/aiops/cost-predict.ts @@ -83,15 +83,15 @@ function costTrendFromSlope(slope: number): 'up' | 'down' | 'stable' { /** 成本优化建议 */ export function costRecommendation(trend: 'up' | 'down' | 'stable', ratio: number): string { if (trend === 'up' && ratio >= 0.85) { - return i18n.t('排查内存泄漏,优化进程内存配置,考虑增加节点'); + return i18n.t('aiops.predictMemLeak'); } if (trend === 'up') { - return i18n.t('排查内存泄漏,优化进程内存配置,考虑增加节点'); + return i18n.t('aiops.predictMemLeak'); } if (trend === 'down') { - return i18n.t('排查内存泄漏,优化进程内存配置,考虑增加节点'); + return i18n.t('aiops.predictMemLeak'); } - return i18n.t('你是 AIOps 容量规划专家。基于以下服务器资源容量预测数据,给出综合风险评估与可执行的运维建议:'); + return i18n.t('aiops.predictutilsts.sa3b5c7d9'); } /** 预算风险建议 */ @@ -256,7 +256,7 @@ export function computeCostPredictions(input: ComputeCostPredictionsInput): Comp const allRatio = summary.predictedMonthEnd > 0 ? summary.monthCost / summary.predictedMonthEnd : 0; dimensionForecasts.push({ - dimension: i18n.t('清理历史数据和日志,实施数据归档策略,扩容磁盘'), + dimension: i18n.t('aiops.predictDiskFull'), currentMonth: summary.monthCost, predictedMonthEnd: summary.predictedMonthEnd, dailyAvg: summary.dailyAvg, @@ -302,7 +302,7 @@ export function computeCostPredictions(input: ComputeCostPredictionsInput): Comp const metric = (rule.metric === 'daily' ? 'daily' : 'monthly') as 'daily' | 'monthly'; const ruleProvider = String(rule.provider || ''); - const providerLabel = ruleProvider ? PROVIDER_LABELS[ruleProvider] || ruleProvider : i18n.t('24小时后'); + const providerLabel = ruleProvider ? PROVIDER_LABELS[ruleProvider] || ruleProvider : i18n.t('aiops.predictIn24h'); let current = 0; let predicted = 0; @@ -339,7 +339,7 @@ export function computeCostPredictions(input: ComputeCostPredictionsInput): Comp if (current >= threshold) probability += 25; probability = Math.max(5, Math.min(92, probability)); - let timeframe = metric === 'daily' ? i18n.t('未来24小时') : i18n.t('aiops.predictutilsts.sd4e5f6g7'); + let timeframe = metric === 'daily' ? i18n.t('aiops.predictNext24h') : i18n.t('aiops.predictutilsts.sd4e5f6g7'); if (slope > 0.01 && threshold > current) { const days = (threshold - current) / slope; if (days < 1) timeframe = metric === 'daily' ? i18n.t('aiops.predictutilsts.se5f6g7h8') : i18n.t('aiops.predictutilsts.sf6g7h8i9'); diff --git a/frontend/src/components/aiops/predict-types.ts b/frontend/src/components/aiops/predict-types.ts index 85e6deb..afbcb1f 100644 --- a/frontend/src/components/aiops/predict-types.ts +++ b/frontend/src/components/aiops/predict-types.ts @@ -120,16 +120,16 @@ export interface ComputeCostPredictionsInput { /** 指标定义:后端 metric name → 展示标签 / 告警表达式前缀 / 阈值 */ export const METRIC_DEFS = [ - { key: 'cpu', label: i18n.t('CPU使用率'), exprKey: 'cpu_usage', threshold: 85 }, + { key: 'cpu', label: i18n.t('aiops.predictCpuUsage'), exprKey: 'cpu_usage', threshold: 85 }, { key: 'memory', label: i18n.t('aiops.predictTypes.memUsage'), exprKey: 'memory_usage', threshold: 85 }, { key: 'disk', label: i18n.t('aiops.predictTypes.diskUsage'), exprKey: 'disk_usage', threshold: 90 }, ] as const; export const TIME_RANGE_LABELS: Record = { - '1h': i18n.t('1小时后'), - '24h': i18n.t('24小时后'), - '7d': i18n.t('7天后'), - '30d': i18n.t('30天后'), + '1h': i18n.t('aiops.predictIn1h'), + '24h': i18n.t('aiops.predictIn24h'), + '7d': i18n.t('aiops.predictIn7d'), + '30d': i18n.t('aiops.predictIn30d'), }; export const TIME_RANGE_HOURS: Record = { diff --git a/frontend/src/components/system/replay/export-audit.ts b/frontend/src/components/system/replay/export-audit.ts index b8fa739..d8b60ad 100644 --- a/frontend/src/components/system/replay/export-audit.ts +++ b/frontend/src/components/system/replay/export-audit.ts @@ -23,7 +23,7 @@ function escapeCsv(s: string): string { // exportAuditReportCsv 导出会话审计报告 CSV // Logan.Li export function exportAuditReportCsv(meta: ReplaySessionMeta, commands: CommandBookmark[]) { const lines: string[] = [ - i18n.t('# 终端会话审计报告'), + i18n.t('audit.reportTitle'), `会话ID,${meta.id}`, `用户,${escapeCsv(meta.username || '')}`, `目标主机,${escapeCsv(meta.server_name || '')}`, @@ -33,7 +33,7 @@ export function exportAuditReportCsv(meta: ReplaySessionMeta, commands: CommandB `时长(秒),${meta.duration || 0}`, `录制大小,${meta.record_size || 0}`, '', - i18n.t('# 终端会话审计报告'), + i18n.t('audit.reportTitle'), ]; for (const c of commands) { lines.push(`${c.label},${escapeCsv(c.command)},${c.highRisk ? '是' : '否'}`); @@ -55,7 +55,7 @@ export interface CommandExportRow { // exportCommandsListCsv 导出命令列表 CSV // Logan.Li export function exportCommandsListCsv(commands: CommandExportRow[]) { - const lines: string[] = [i18n.t('时间,用户,命令,输出大小,会话ID,高危')]; + const lines: string[] = [i18n.t('audit.csvHeader')]; for (const c of commands) { const ts = c.timestamp || c.created_at || ''; const highRisk = isHighRiskCommand(c.command || ''); diff --git a/frontend/src/components/ui/copy-button.tsx b/frontend/src/components/ui/copy-button.tsx index baf3c33..5b9256c 100644 --- a/frontend/src/components/ui/copy-button.tsx +++ b/frontend/src/components/ui/copy-button.tsx @@ -42,7 +42,7 @@ export function CopyButton({ } else { toast({ title: i18n.t('monitor.logPanel.copyFailed'), - description: i18n.t('请手动选中内容后复制'), + description: i18n.t('common.copyManually'), variant: 'destructive', }); } diff --git a/frontend/src/locales/en-US.json b/frontend/src/locales/en-US.json index 5572be7..3c85ead 100644 --- a/frontend/src/locales/en-US.json +++ b/frontend/src/locales/en-US.json @@ -513,7 +513,8 @@ "critical": "Critical", "request.tokenExpired": "Session expired, please log in again", "days": "days", - "seconds": "sec" + "seconds": "sec", + "copyManually": "Please manually select and copy" }, "menu": { "dashboard": "Dashboard", @@ -1505,7 +1506,9 @@ "failed": "Failed", "closed": "Closed" } - } + }, + "reportTitle": "Terminal Session Audit Report", + "csvHeader": "Time,User,Command,Output Size,Session ID,Critical" }, "deploy": { "pipeline": { @@ -4865,7 +4868,44 @@ "selectMetricsHint": "Please check metrics from the left panel", "probeName": "Probe Name", "execCommand": "Execute Command", - "refreshing": " · Refreshing..." + "refreshing": " · Refreshing...", + "mwMemUsage": "Memory Usage", + "mwSlowQueryRate": "Slow Query Rate", + "mwBlockedClients": "Blocked Clients", + "mwActiveThreads": "Active Threads", + "mwBufferHitRate": "Buffer Pool Hit Rate", + "mwPerCycle": "/cycle", + "mwCluster": "Cluster", + "mwInstanceOffline": "Instance Offline", + "mwHitRateBelow80": "Hit Rate < 80%", + "mwHitRateBelow90": "Hit Rate < 90%", + "mwMemAbove90": "Memory > 90%", + "mwMemAbove80": "Memory > 80%", + "mwKeyEviction": "Key Eviction", + "mwBufferHitBelow90": "Buffer Pool Hit < 90%", + "mwBufferHitBelow95": "Buffer Pool Hit < 95%", + "mwConnAbove90": "Connections > 90% Limit", + "mwConnAbove80": "Connections > 80% Limit", + "mwTooManyThreads": "Too Many Active Threads", + "siteRecentHour": "Last 1 hour", + "siteRecent24h": "Last 24 hours", + "siteRecent7d": "Last 7 days", + "siteTargetUrl": "Target URL", + "siteHttpHint": "Web request (supports http/https), detects status code and response time", + "siteSslAddr": "SSL Address", + "siteSslPlaceholder": "example.com:443 or https://example.com", + "siteSslHint": "TLS handshake certificate check (supports host:port / https:// domain, no HTTP request)", + "siteHostPort": "Host:Port", + "siteTcpPlaceholder": "192.168.1.1:8080 or example.com:443", + "siteTcpHint": "TCP Port Connectivity", + "siteHostAddr": "Host Address", + "sitePingPlaceholder": "192.168.1.1 or example.com", + "sitePingHint": "ICMP connectivity and latency (default 2 min/interval)", + "siteServerError": "Server Error", + "siteClientError": "Client/Auth Error", + "siteRequestFailed": "Request Failed", + "siteRequestTimeout": "Request Timeout", + "siteConnFailed": "Connection Failed" }, "alertRuleDialog2": { "editRule": "Edit Alert Rule", @@ -6806,7 +6846,11 @@ "deleteRule": "Delete Rule", "thresholdTriggered": "Alert threshold triggered", "noResolved": "No resolved alerts", - "noActive": "No active alerts, all clear" + "noActive": "No active alerts, all clear", + "metricSwap": "Swap Usage", + "metricLoad1": "1-min Load Average", + "metricInode": "Inode Usage", + "metricTcpEst": "TCP Established" }, "monitor": { "loadHostFailed": "Failed to load host list", @@ -7809,7 +7853,17 @@ "predictTypes": { "memUsage": "Memory Usage", "diskUsage": "Disk Usage" - } + }, + "predictMemLeak": "Investigate memory leaks, optimize process memory config, consider adding nodes", + "predictDiskFull": "Clean up historical data and logs, implement data archiving, expand disk", + "predictIn24h": "In 24 hours", + "predictNext24h": "Next 24 hours", + "predictCpuUsage": "CPU Usage", + "predictIn1h": "In 1 hour", + "predictIn7d": "In 7 days", + "predictIn30d": "In 30 days", + "agentCliErrorOccurred": "Error occurred", + "agentCliNoOutput": "(no output)" }, "breadcrumb": { "dashboard": "Dashboard", @@ -7936,5 +7990,17 @@ "quickQuery": "Quick Query", "quickQueryHint": "{{engine}} common query templates, click to fill", "entries": "entries" + }, + "theme": { + "system": "Follow System", + "deepBlue": "Deep Ocean Blue", + "brightWhite": "Bright White", + "brightWhiteDesc": "Enterprise console clean light theme", + "oneDarkDesc": "Atom warm gray IDE, purple-green syntax", + "draculaDesc": "Classic purple-pink dark, high contrast", + "tokyoNightDesc": "Tokyo neon deep blue-purple, VS Code popular", + "catppuccinDesc": "Macaron soft dark, eye-friendly", + "mainstream": "Mainstream", + "developer": "Developer" } } diff --git a/frontend/src/locales/zh-CN.json b/frontend/src/locales/zh-CN.json index 55b1818..febddac 100644 --- a/frontend/src/locales/zh-CN.json +++ b/frontend/src/locales/zh-CN.json @@ -513,7 +513,8 @@ "critical": "严重", "request.tokenExpired": "登录已过期,请重新登录", "days": "天", - "seconds": "秒" + "seconds": "秒", + "copyManually": "请手动选中内容后复制" }, "menu": { "dashboard": "仪表盘", @@ -1505,7 +1506,9 @@ "failed": "失败", "closed": "已关闭" } - } + }, + "reportTitle": "终端会话审计报告", + "csvHeader": "时间,用户,命令,输出大小,会话ID,高危" }, "deploy": { "pipeline": { @@ -4865,7 +4868,44 @@ "selectMetricsHint": "请从左侧勾选指标", "probeName": "探针名称", "execCommand": "执行命令", - "refreshing": " · 刷新中..." + "refreshing": " · 刷新中...", + "mwMemUsage": "内存占用", + "mwSlowQueryRate": "慢查询速率", + "mwBlockedClients": "阻塞客户端", + "mwActiveThreads": "活跃线程", + "mwBufferHitRate": "缓冲池命中率", + "mwPerCycle": "次/周期", + "mwCluster": "集群", + "mwInstanceOffline": "实例离线", + "mwHitRateBelow80": "命中率 < 80%", + "mwHitRateBelow90": "命中率 < 90%", + "mwMemAbove90": "内存 > 90%", + "mwMemAbove80": "内存 > 80%", + "mwKeyEviction": "Key 逐出", + "mwBufferHitBelow90": "缓冲池命中 < 90%", + "mwBufferHitBelow95": "缓冲池命中 < 95%", + "mwConnAbove90": "连接 > 90% 上限", + "mwConnAbove80": "连接 > 80% 上限", + "mwTooManyThreads": "活跃线程偏多", + "siteRecentHour": "近 1 小时", + "siteRecent24h": "近 24 小时", + "siteRecent7d": "近 7 天", + "siteTargetUrl": "目标 URL", + "siteHttpHint": "Web 请求(支持 http/https),检测状态码与响应时间", + "siteSslAddr": "SSL 地址", + "siteSslPlaceholder": "example.com:443 或 https://example.com", + "siteSslHint": "TLS 握手检测证书(支持 host:port / https:// 域名,不发起 HTTP 请求)", + "siteHostPort": "主机:端口", + "siteTcpPlaceholder": "192.168.1.1:8080 或 example.com:443", + "siteTcpHint": "TCP 端口连通性", + "siteHostAddr": "主机地址", + "sitePingPlaceholder": "192.168.1.1 或 example.com", + "sitePingHint": "ICMP 连通性与延迟(默认 2 分钟/次)", + "siteServerError": "服务端错误", + "siteClientError": "客户端/鉴权错误", + "siteRequestFailed": "请求失败", + "siteRequestTimeout": "请求超时", + "siteConnFailed": "连接失败" }, "alertRuleDialog2": { "editRule": "编辑告警规则", @@ -6806,7 +6846,11 @@ "deleteRule": "删除规则", "thresholdTriggered": "触发告警阈值", "noResolved": "暂无已恢复的告警", - "noActive": "当前无活动告警,一切正常" + "noActive": "当前无活动告警,一切正常", + "metricSwap": "Swap 使用率", + "metricLoad1": "1分钟负载", + "metricInode": "Inode 使用率", + "metricTcpEst": "TCP 已建立" }, "monitor": { "loadHostFailed": "加载主机列表失败", @@ -7809,7 +7853,17 @@ "predictTypes": { "memUsage": "内存使用率", "diskUsage": "磁盘使用率" - } + }, + "predictMemLeak": "排查内存泄漏,优化进程内存配置,考虑增加节点", + "predictDiskFull": "清理历史数据和日志,实施数据归档策略,扩容磁盘", + "predictIn24h": "24小时后", + "predictNext24h": "未来24小时", + "predictCpuUsage": "CPU使用率", + "predictIn1h": "1小时后", + "predictIn7d": "7天后", + "predictIn30d": "30天后", + "agentCliErrorOccurred": "发生错误", + "agentCliNoOutput": "(无输出)" }, "breadcrumb": { "dashboard": "仪表盘", @@ -7936,5 +7990,17 @@ "quickQuery": "快捷查询", "quickQueryHint": "{{engine}} 常用查询模板,点击快速填充", "entries": "条" + }, + "theme": { + "system": "跟随系统", + "deepBlue": "深海蓝", + "brightWhite": "明亮白", + "brightWhiteDesc": "企业控制台清爽浅色", + "oneDarkDesc": "Atom 暖灰 IDE,紫绿语法渐变", + "draculaDesc": "经典紫粉暗色,极高辨识度", + "tokyoNightDesc": "东京霓虹深蓝紫,VS Code 热门", + "catppuccinDesc": "马卡龙柔和暗色,护眼", + "mainstream": "主流", + "developer": "开发者" } } diff --git a/frontend/src/pages/monitor/middleware-monitor/helpers.ts b/frontend/src/pages/monitor/middleware-monitor/helpers.ts index 0d14238..da21c13 100644 --- a/frontend/src/pages/monitor/middleware-monitor/helpers.ts +++ b/frontend/src/pages/monitor/middleware-monitor/helpers.ts @@ -59,20 +59,20 @@ export const MYSQL_PRIMARY_KEYS = ['mysql_qps', 'mysql_connections', 'mysql_buff export const REDIS_CHARTS: MwChartDef[] = [ { key: 'redis_qps', label: 'QPS', color: 'var(--dg-blue)', unit: 'ops/s' }, - { key: 'redis_used_memory', label: i18n.t('内存占用'), color: 'var(--dg-red)', formatter: fmtMemory }, + { key: 'redis_used_memory', label: i18n.t('monitor.lbl.mwMemUsage'), color: 'var(--dg-red)', formatter: fmtMemory }, { key: 'redis_hit_rate', label: i18n.t('monitor.lbl.hitRate'), color: 'var(--dg-green)', percent: true }, { key: 'redis_connected_clients', label: i18n.t('kubernetes.topology.connections'), color: 'var(--dg-cyan)' }, - { key: 'redis_db_size', label: i18n.t('慢查询速率'), color: 'var(--dg-purple)' }, - { key: 'redis_blocked_clients', label: i18n.t('阻塞客户端'), color: 'var(--dg-orange)' }, + { key: 'redis_db_size', label: i18n.t('monitor.lbl.mwSlowQueryRate'), color: 'var(--dg-purple)' }, + { key: 'redis_blocked_clients', label: i18n.t('monitor.lbl.mwBlockedClients'), color: 'var(--dg-orange)' }, ]; export const MYSQL_CHARTS: MwChartDef[] = [ { key: 'mysql_qps', label: 'QPS', color: 'var(--dg-blue)', unit: 'q/s' }, { key: 'mysql_connections', label: i18n.t('kubernetes.topology.connections'), color: 'var(--dg-cyan)' }, - { key: 'mysql_threads_running', label: i18n.t('活跃线程'), color: 'var(--dg-purple)' }, - { key: 'mysql_buffer_hit_rate', label: i18n.t('缓冲池命中率'), color: 'var(--dg-green)', percent: true }, - { key: 'mysql_slow_queries', label: i18n.t('慢查询速率'), color: 'var(--dg-orange)', unit: i18n.t('次/周期'), counterDelta: true }, - { key: 'mysql_bytes_sent', label: i18n.t('缓冲池命中率'), color: 'var(--dg-amber)', formatter: fmtMemory }, + { key: 'mysql_threads_running', label: i18n.t('monitor.lbl.mwActiveThreads'), color: 'var(--dg-purple)' }, + { key: 'mysql_buffer_hit_rate', label: i18n.t('monitor.lbl.mwBufferHitRate'), color: 'var(--dg-green)', percent: true }, + { key: 'mysql_slow_queries', label: i18n.t('monitor.lbl.mwSlowQueryRate'), color: 'var(--dg-orange)', unit: i18n.t('monitor.lbl.mwPerCycle'), counterDelta: true }, + { key: 'mysql_bytes_sent', label: i18n.t('monitor.lbl.mwBufferHitRate'), color: 'var(--dg-amber)', formatter: fmtMemory }, ]; export function fmtMemory(bytes: number): string { @@ -139,7 +139,7 @@ export function statusBg(status: string): string { } export function redisModeLabel(mode?: string): string { - return mode === 'cluster' ? i18n.t('k8s.topology.typeCluster') : i18n.t('集群'); + return mode === 'cluster' ? i18n.t('k8s.topology.typeCluster') : i18n.t('monitor.lbl.mwCluster'); } export function redisMemoryPct(metrics: Record): number | null { @@ -209,27 +209,27 @@ export function evalMwHealth(target: MwTarget): MwHealthIssue[] { const m = target.latest_metrics || {}; const issues: MwHealthIssue[] = []; if (target.status !== 'online') { - issues.push({ level: 'crit', message: i18n.t('实例离线') }); + issues.push({ level: 'crit', message: i18n.t('monitor.lbl.mwInstanceOffline') }); return issues; } if (target.description === 'redis') { - if (m.redis_hit_rate > 0 && m.redis_hit_rate < 0.8) issues.push({ level: 'crit', message: i18n.t('命中率 < 80%') }); - else if (m.redis_hit_rate > 0 && m.redis_hit_rate < 0.9) issues.push({ level: 'warn', message: i18n.t('命中率 < 90%') }); + if (m.redis_hit_rate > 0 && m.redis_hit_rate < 0.8) issues.push({ level: 'crit', message: i18n.t('monitor.lbl.mwHitRateBelow80') }); + else if (m.redis_hit_rate > 0 && m.redis_hit_rate < 0.9) issues.push({ level: 'warn', message: i18n.t('monitor.lbl.mwHitRateBelow90') }); const memPct = redisMemoryPct(m); - if (memPct != null && memPct > 90) issues.push({ level: 'crit', message: i18n.t('内存 > 90%') }); - else if (memPct != null && memPct > 80) issues.push({ level: 'warn', message: i18n.t('内存 > 80%') }); - if (m.redis_blocked_clients > 0) issues.push({ level: 'warn', message: i18n.t('阻塞客户端') }); - if (m.redis_evicted_keys > 0) issues.push({ level: 'warn', message: i18n.t('Key 逐出') }); + if (memPct != null && memPct > 90) issues.push({ level: 'crit', message: i18n.t('monitor.lbl.mwMemAbove90') }); + else if (memPct != null && memPct > 80) issues.push({ level: 'warn', message: i18n.t('monitor.lbl.mwMemAbove80') }); + if (m.redis_blocked_clients > 0) issues.push({ level: 'warn', message: i18n.t('monitor.lbl.mwBlockedClients') }); + if (m.redis_evicted_keys > 0) issues.push({ level: 'warn', message: i18n.t('monitor.lbl.mwKeyEviction') }); } else if (target.description === 'mysql') { if (m.mysql_buffer_hit_rate > 0 && m.mysql_buffer_hit_rate < 0.9) { - issues.push({ level: 'crit', message: i18n.t('缓冲池命中 < 90%') }); + issues.push({ level: 'crit', message: i18n.t('monitor.lbl.mwBufferHitBelow90') }); } else if (m.mysql_buffer_hit_rate > 0 && m.mysql_buffer_hit_rate < 0.95) { - issues.push({ level: 'warn', message: i18n.t('缓冲池命中 < 95%') }); + issues.push({ level: 'warn', message: i18n.t('monitor.lbl.mwBufferHitBelow95') }); } const connPct = mysqlConnPct(m); - if (connPct != null && connPct > 90) issues.push({ level: 'crit', message: i18n.t('连接 > 90% 上限') }); - else if (connPct != null && connPct > 80) issues.push({ level: 'warn', message: i18n.t('连接 > 80% 上限') }); - if (m.mysql_threads_running > 20) issues.push({ level: 'warn', message: i18n.t('活跃线程偏多') }); + if (connPct != null && connPct > 90) issues.push({ level: 'crit', message: i18n.t('monitor.lbl.mwConnAbove90') }); + else if (connPct != null && connPct > 80) issues.push({ level: 'warn', message: i18n.t('monitor.lbl.mwConnAbove80') }); + if (m.mysql_threads_running > 20) issues.push({ level: 'warn', message: i18n.t('monitor.lbl.mwTooManyThreads') }); } return issues; } diff --git a/frontend/src/pages/monitor/site-monitor/helpers.ts b/frontend/src/pages/monitor/site-monitor/helpers.ts index 14b5319..2e6dac1 100644 --- a/frontend/src/pages/monitor/site-monitor/helpers.ts +++ b/frontend/src/pages/monitor/site-monitor/helpers.ts @@ -57,10 +57,10 @@ export const SITE_TIME_RANGE_HOURS: Record = { }; export const SITE_TIME_RANGE_LABELS: Record = { - '1h': i18n.t('近 1 小时'), + '1h': i18n.t('monitor.lbl.siteRecentHour'), '6h': i18n.t('monitor.siteProtocol.rangeDefault'), - '24h': i18n.t('近 24 小时'), - '7d': i18n.t('近 7 天'), + '24h': i18n.t('monitor.lbl.siteRecent24h'), + '7d': i18n.t('monitor.lbl.siteRecent7d'), }; /** 各协议推荐默认拨测间隔(秒)// Logan.Li */ @@ -86,11 +86,11 @@ export function defaultProbeFrequency(type: ProbeType): number { } 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 端口连通性') }, + HTTP: { label: i18n.t('monitor.lbl.siteTargetUrl'), placeholder: 'https://example.com/health', hint: i18n.t('monitor.lbl.siteHttpHint') }, + SSL: { label: i18n.t('monitor.lbl.siteSslAddr'), placeholder: i18n.t('monitor.lbl.siteSslPlaceholder'), hint: i18n.t('monitor.lbl.siteSslHint') }, + TCP: { label: i18n.t('monitor.lbl.siteHostPort'), placeholder: i18n.t('monitor.lbl.siteTcpPlaceholder'), hint: i18n.t('monitor.lbl.siteTcpHint') }, 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 分钟/次)') }, + PING: { label: i18n.t('monitor.lbl.siteHostAddr'), placeholder: i18n.t('monitor.lbl.sitePingPlaceholder'), hint: i18n.t('monitor.lbl.sitePingHint') }, }; export function probeFrequencyHint(type: ProbeType): string { diff --git a/frontend/src/pages/monitor/site-monitor/observability/analytics.ts b/frontend/src/pages/monitor/site-monitor/observability/analytics.ts index cc70f87..526d272 100644 --- a/frontend/src/pages/monitor/site-monitor/observability/analytics.ts +++ b/frontend/src/pages/monitor/site-monitor/observability/analytics.ts @@ -93,16 +93,16 @@ export function analyzeHttpResults(results: SiteResult[], task: SiteTask): HttpO } if (code >= 500) { err5xx++; - pushEvent(events, r, `HTTP ${code}`, 'error', r.error_message || i18n.t('服务端错误')); + pushEvent(events, r, `HTTP ${code}`, 'error', r.error_message || i18n.t('monitor.lbl.siteServerError')); } else if (code >= 400) { err4xx++; - pushEvent(events, r, `HTTP ${code}`, 'warn', r.error_message || i18n.t('客户端/鉴权错误')); + pushEvent(events, r, `HTTP ${code}`, 'warn', r.error_message || i18n.t('monitor.lbl.siteClientError')); } else if (r.status === 'timeout') { otherErr++; pushEvent(events, r, i18n.t('common.timeoutError'), 'error', r.error_message); } else { otherErr++; - pushEvent(events, r, code > 0 ? `HTTP ${code}` : i18n.t('请求失败'), 'error', r.error_message); + pushEvent(events, r, code > 0 ? `HTTP ${code}` : i18n.t('monitor.lbl.siteRequestFailed'), 'error', r.error_message); } } const latest = results[0]; @@ -128,7 +128,7 @@ export function analyzeSslResults(results: SiteResult[], task: SiteTask): SslObs const events: ProbeEvent[] = []; for (const r of results) { if (r.status !== 'success') { - pushEvent(events, r, i18n.t('请求超时'), 'error', r.error_message); + pushEvent(events, r, i18n.t('monitor.lbl.siteRequestTimeout'), 'error', r.error_message); } else if (r.ssl_days_remaining != null && r.ssl_days_remaining < 30) { pushEvent(events, r, `证书剩余 ${r.ssl_days_remaining} 天`, r.ssl_days_remaining <= 7 ? 'error' : 'warn', expiry); } @@ -186,7 +186,7 @@ export function analyzeTcpResults(results: SiteResult[]): ConnectivityObsSummary const failed = r.status !== 'success'; if (failed) { lastFailAt = r.checked_at; - pushEvent(events, r, i18n.t('连接失败'), 'error', r.error_message || i18n.t('aiops.llmTestFailed')); + pushEvent(events, r, i18n.t('monitor.lbl.siteConnFailed'), 'error', r.error_message || i18n.t('aiops.llmTestFailed')); } return { time: fmtTime(r.checked_at).slice(-5), up: failed ? 0 : 100, failed }; }); diff --git a/frontend/src/utils/theme.ts b/frontend/src/utils/theme.ts index 8777ee8..da0310b 100644 --- a/frontend/src/utils/theme.ts +++ b/frontend/src/utils/theme.ts @@ -32,22 +32,22 @@ export interface ThemeGroup { /** 主流主题 — 默认推荐 */ const MAINSTREAM_THEMES: ThemeOption[] = [ - { id: 'system', name: i18n.t('common.lightDark'), description: i18n.t('跟随系统'), isDark: false, primaryColor: 'linear-gradient(135deg, #2563eb 50%, #0d1117 50%)' }, - { id: 'ocean-deep', name: i18n.t('深海蓝'), description: i18n.t('深海蓝'), isDark: true, primaryColor: '#0d1117' }, - { id: 'light-professional', name: i18n.t('明亮白'), description: i18n.t('企业控制台清爽浅色'), isDark: false, primaryColor: '#2563eb' }, + { id: 'system', name: i18n.t('common.lightDark'), description: i18n.t('theme.system'), isDark: false, primaryColor: 'linear-gradient(135deg, #2563eb 50%, #0d1117 50%)' }, + { id: 'ocean-deep', name: i18n.t('theme.deepBlue'), description: i18n.t('theme.deepBlue'), isDark: true, primaryColor: '#0d1117' }, + { id: 'light-professional', name: i18n.t('theme.brightWhite'), description: i18n.t('theme.brightWhiteDesc'), isDark: false, primaryColor: '#2563eb' }, ]; /** 开发者主题 — 高辨识度扩展 */ const DEVELOPER_THEMES: ThemeOption[] = [ - { id: 'one-dark', name: 'One Dark', description: i18n.t('Atom 暖灰 IDE,紫绿语法渐变'), isDark: true, primaryColor: '#c678dd' }, - { id: 'dracula', name: 'Dracula', description: i18n.t('经典紫粉暗色,极高辨识度'), isDark: true, primaryColor: '#bd93f9' }, - { id: 'tokyo-night', name: 'Tokyo Night', description: i18n.t('东京霓虹深蓝紫,VS Code 热门'), isDark: true, primaryColor: '#7aa2f7' }, - { id: 'catppuccin', name: 'Catppuccin', description: i18n.t('马卡龙柔和暗色,护眼'), isDark: true, primaryColor: '#89b4fa' }, + { id: 'one-dark', name: 'One Dark', description: i18n.t('theme.oneDarkDesc'), isDark: true, primaryColor: '#c678dd' }, + { id: 'dracula', name: 'Dracula', description: i18n.t('theme.draculaDesc'), isDark: true, primaryColor: '#bd93f9' }, + { id: 'tokyo-night', name: 'Tokyo Night', description: i18n.t('theme.tokyoNightDesc'), isDark: true, primaryColor: '#7aa2f7' }, + { id: 'catppuccin', name: 'Catppuccin', description: i18n.t('theme.catppuccinDesc'), isDark: true, primaryColor: '#89b4fa' }, ]; export const THEME_GROUPS: ThemeGroup[] = [ - { label: i18n.t('主流'), options: MAINSTREAM_THEMES }, - { label: i18n.t('开发者'), options: DEVELOPER_THEMES }, + { label: i18n.t('theme.mainstream'), options: MAINSTREAM_THEMES }, + { label: i18n.t('theme.developer'), options: DEVELOPER_THEMES }, ]; export const THEME_OPTIONS: ThemeOption[] = [