feat(i18n): U46 残余UI硬编码中文清零 — 6文件12处→0 (UserFormDialog/CredentialManager/RdpAuditViewer/LiveMonitorDialog/ServerFileBrowser/context-loaders) +17翻译键 zh/en 8085→8102对齐
This commit is contained in:
1 parent
6288fa0071
commit
21728be445
10 files changed
+118
-25
No files matched your search
@@ -8,27 +8,49 @@ export async function loadAlertsContext(): Promise<string> {
|
||||
const alerts: JsonData[] = (res as JsonData)?.list || [];
|
||||
if (!alerts.length) return i18n.t('aiops.noAlertsNow');
|
||||
const lines = alerts.slice(0, 15).map((a, i) =>
|
||||
`${i + 1}. [${a.severity || i18n.t('common.unknown')}|${a.status || '-'}] ${a.rule_name || i18n.t('dashboard.stat.alerts')} → 目标:${a.target || '-'} 值:${a.value ?? '-'} 时间:${(a.started_at || '').slice(0, 16)}`,
|
||||
i18n.t('aiops.ctx.alertLine', {
|
||||
i: i + 1,
|
||||
severity: a.severity || i18n.t('common.unknown'),
|
||||
status: a.status || '-',
|
||||
name: a.rule_name || i18n.t('dashboard.stat.alerts'),
|
||||
target: a.target || '-',
|
||||
value: a.value ?? '-',
|
||||
time: (a.started_at || '').slice(0, 16),
|
||||
}),
|
||||
);
|
||||
const firing = alerts.filter((a) => a.status === 'firing').length;
|
||||
return `共 ${alerts.length} 条告警(firing ${firing} 条),前 ${Math.min(15, alerts.length)} 条:\n${lines.join('\n')}`;
|
||||
return i18n.t('aiops.ctx.alertSummary', {
|
||||
total: alerts.length,
|
||||
firing,
|
||||
shown: Math.min(15, alerts.length),
|
||||
}) + '\n' + lines.join('\n');
|
||||
}
|
||||
|
||||
/** 拉取 Agent 实时主机指标,识别高负载主机 */
|
||||
export async function loadMetricsContext(): Promise<string> {
|
||||
const res = await agentApi.getLatest();
|
||||
const hosts: JsonData[] = Array.isArray(res) ? res : (res as JsonData)?.list || [];
|
||||
if (!hosts.length) return i18n.t('aiops.noAgentData');
|
||||
const lines = hosts.slice(0, 20).map((h, i) => {
|
||||
const cpu = h.cpu_usage ?? '-';
|
||||
const mem = h.mem_usage ?? '-';
|
||||
return `${i + 1}. ${h.hostname || '-'} | CPU:${cpu}% | 内存:${mem}% (${h.mem_used ?? '-'}/${h.mem_total ?? '-'}GB) | 核数:${h.cpu_cores ?? '-'} | 上报:${(h.report_time || '').slice(0, 16)}`;
|
||||
});
|
||||
if (!hosts.length) return i18n.t('aiops.ctx.noAgentData');
|
||||
const lines = hosts.slice(0, 20).map((h, i) =>
|
||||
i18n.t('aiops.ctx.metricLine', {
|
||||
i: i + 1,
|
||||
host: h.hostname || '-',
|
||||
cpu: h.cpu_usage ?? '-',
|
||||
mem: h.mem_usage ?? '-',
|
||||
used: h.mem_used ?? '-',
|
||||
total: h.mem_total ?? '-',
|
||||
cores: h.cpu_cores ?? '-',
|
||||
time: (h.report_time || '').slice(0, 16),
|
||||
}),
|
||||
);
|
||||
const hot = hosts.filter((h) => (h.cpu_usage ?? 0) >= 80 || (h.mem_usage ?? 0) >= 80);
|
||||
const note = hot.length
|
||||
? `\n⚠️ 高负载主机 ${hot.length} 台:${hot.map((h) => `${h.hostname}(CPU${h.cpu_usage}%/MEM${h.mem_usage}%)`).join('、')}`
|
||||
? '\n' + i18n.t('aiops.ctx.highLoadHosts', {
|
||||
count: hot.length,
|
||||
hosts: hot.map((h) => `${h.hostname}(CPU${h.cpu_usage}%/MEM${h.mem_usage}%)`).join('、'),
|
||||
})
|
||||
: '';
|
||||
return `Agent 监控的 ${hosts.length} 台主机实时指标:\n${lines.join('\n')}${note}`;
|
||||
return i18n.t('aiops.ctx.agentMetricsSummary', { count: hosts.length }) + '\n' + lines.join('\n') + note;
|
||||
}
|
||||
|
||||
/** 拉取仪表盘综合数据,生成运维报告上下文 */
|
||||
@@ -42,12 +64,18 @@ export async function loadReportContext(): Promise<string> {
|
||||
`${i + 1}.${h.hostname || h.ip} CPU:${h.cpu_usage}% MEM:${h.memory_usage}% DISK:${h.disk_usage}% Agent:${h.agent_status}`,
|
||||
);
|
||||
return [
|
||||
`平台概览:服务器:${summary.server_total}(在线${summary.server_online}) | Kubernetes集群:${summary.cluster_total} | 平台告警:${summary.firing_alerts} | Agent未恢复告警:${summary.unresolved_alerts}`,
|
||||
i18n.t('aiops.ctx.platformOverview', {
|
||||
servers: summary.server_total,
|
||||
online: summary.server_online,
|
||||
clusters: summary.cluster_total,
|
||||
alerts: summary.firing_alerts,
|
||||
unresolved: summary.unresolved_alerts,
|
||||
}),
|
||||
'',
|
||||
'高负载资产:',
|
||||
i18n.t('aiops.ctx.highLoadAssets'),
|
||||
highLoadLines.join('\n') || i18n.t('aiops.noneFallback'),
|
||||
'',
|
||||
'最近告警:',
|
||||
i18n.t('aiops.ctx.recentAlerts'),
|
||||
alertLines.join('\n') || i18n.t('aiops.noneFallback'),
|
||||
].join('\n');
|
||||
}
|
||||
@@ -60,10 +88,21 @@ export async function loadReportContext(): Promise<string> {
|
||||
|
||||
const s: JsonData = stats || {};
|
||||
const ss = s.server_stats || {}, ks = s.kubernetes_stats || {}, as = s.alert_stats || {}, ps = s.pipeline_stats || {}, cs = s.cost_stats || {};
|
||||
const overview = `服务器:${ss.total ?? 0}(运行${ss.running ?? 0}) | Kubernetes集群:${ks.total ?? 0} 节点:${ks.total_nodes ?? 0} Pod:${ks.total_pods ?? 0} | 告警:${as.total ?? 0}(firing ${as.firing ?? 0}) | 流水线:${ps.total ?? 0}(成功率${ps.success_rate ?? 0}%) | 本月成本:¥${cs.month_cost ?? 0}`;
|
||||
const overview = i18n.t('aiops.ctx.overviewFallback', {
|
||||
servers: ss.total ?? 0,
|
||||
running: ss.running ?? 0,
|
||||
clusters: ks.total ?? 0,
|
||||
nodes: ks.total_nodes ?? 0,
|
||||
pods: ks.total_pods ?? 0,
|
||||
alerts: as.total ?? 0,
|
||||
firing: as.firing ?? 0,
|
||||
pipelines: ps.total ?? 0,
|
||||
rate: ps.success_rate ?? 0,
|
||||
cost: cs.month_cost ?? 0,
|
||||
});
|
||||
const alertList: JsonData[] = Array.isArray(alerts) ? alerts : (alerts as JsonData)?.list || [];
|
||||
const releaseList: JsonData[] = Array.isArray(releases) ? releases : (releases as JsonData)?.list || [];
|
||||
const alertLines = alertList.slice(0, 10).map((a: JsonData, i: number) => `${i + 1}.[${a.severity || '?'}|${a.status || '?'}] ${a.rule_name || '-'} → ${a.target || '-'}`);
|
||||
const releaseLines = releaseList.slice(0, 10).map((r: JsonData, i: number) => `${i + 1}.${r.app_name || '-'} ${r.version || ''} [${r.environment || '-'}/${r.status || '-'}] by ${r.author || '-'}`);
|
||||
return `平台概览:${overview}\n\n最近告警:\n${alertLines.join('\n') || i18n.t('aiops.noneFallback')}\n\n最近发布:\n${releaseLines.join('\n') || i18n.t('aiops.noneFallback')}`;
|
||||
return `${overview}\n\n${i18n.t('aiops.ctx.recentAlerts')}\n${alertLines.join('\n') || i18n.t('aiops.noneFallback')}\n\n${i18n.t('aiops.ctx.recentReleases')}\n${releaseLines.join('\n') || i18n.t('aiops.noneFallback')}`;
|
||||
}
|
||||
@@ -127,7 +127,7 @@ export function ServerFileBrowser({ open, onOpenChange, serverId, serverName }:
|
||||
};
|
||||
|
||||
const handleMkdir = async () => {
|
||||
const name = prompt('输入目录名:');
|
||||
const name = prompt(i18n.t('common.dirNamePrompt'));
|
||||
if (!name || !serverId) return;
|
||||
const newPath = currentPath === '/' ? `/${name}` : `${currentPath}/${name}`;
|
||||
try {
|
||||
|
||||
@@ -349,7 +349,7 @@ export function CredentialManager() {
|
||||
size="icon"
|
||||
className="absolute top-2 right-2 h-7 w-7 text-[var(--dg-text-muted)] hover:text-[var(--dg-text-primary)]"
|
||||
onClick={() => setShowContent(!showContent)}
|
||||
title={showContent ? t('common.hidden') : '显示'}
|
||||
title={showContent ? t('common.hidden') : t('common.show')}
|
||||
>
|
||||
{showContent ? <EyeOff className="h-4 w-4" /> : <Eye className="h-4 w-4" />}
|
||||
</Button>
|
||||
|
||||
@@ -139,7 +139,7 @@ export function LiveMonitorDialog({ open, onOpenChange, sessionId, sessionInfo }
|
||||
|
||||
const timeout = setTimeout(() => {
|
||||
if (!didOpen) {
|
||||
setConnectError('连接超时 — 请确认已登录且有活跃会话');
|
||||
setConnectError(t('system.connectTimeoutActive'));
|
||||
ws.close();
|
||||
}
|
||||
}, 5000);
|
||||
|
||||
@@ -70,7 +70,7 @@ async function drawImageFrame(ctx: CanvasRenderingContext2D, frame: RdpFrame) {
|
||||
ctx.drawImage(img, frame.x || 0, frame.y || 0, frame.width || img.width, frame.height || img.height);
|
||||
resolve();
|
||||
};
|
||||
img.onerror = () => reject(new Error('RDP 录屏帧解码失败'));
|
||||
img.onerror = () => reject(new Error(i18n.t('system.rdpFrameError')));
|
||||
img.src = frame.image || '';
|
||||
});
|
||||
}
|
||||
@@ -242,7 +242,7 @@ export function RdpAuditViewer({ open, onOpenChange, sessionId, mode }: RdpAudit
|
||||
<DialogDescription className="sr-only">{i18n.t("system.rdpAuditDesc")}</DialogDescription>
|
||||
<div className="flex items-center justify-between px-4 py-2 border-b border-[var(--dg-border)]">
|
||||
<div className="text-sm font-medium text-[var(--dg-text-primary)]">
|
||||
{mode === 'live' ? 'RDP 实时审计' : `RDP 历史回放 #${sessionId || ''}`}
|
||||
{mode === 'live' ? i18n.t('system.rdpLiveAudit') : i18n.t('system.rdpHistoryReplayId', { id: sessionId || '' })}
|
||||
</div>
|
||||
<div className="flex items-center gap-1">
|
||||
<button type="button" onClick={() => setFullscreen(!fullscreen)} className="p-1.5 rounded hover:bg-[var(--dg-bg-hover)] text-[var(--dg-text-secondary)]">
|
||||
|
||||
@@ -83,7 +83,7 @@ export function UserFormDialog({
|
||||
<DialogHeader>
|
||||
<DialogTitle className="text-[var(--dg-text-primary)] flex items-center gap-2">
|
||||
<User className="h-5 w-5 dg-text-blue" />
|
||||
{editingUser ? t('system.editUser') : '新建用户'}
|
||||
{editingUser ? t('system.editUser') : t('system.createUser')}
|
||||
</DialogTitle>
|
||||
<DialogDescription className="dg-text-muted">
|
||||
{editingUser ? t('system.editUserDesc') : t('system.createUserDesc')}
|
||||
|
||||
Reference in new issue
Block a user