refactor(i18n): U28 多模块 phantom key 清零 — theme/middleware-monitor/site-monitor/analytics/cost-predict/predict-types/agentAlertHelper/export-audit/AgentCLIMessages/copy-button 10 文件 74 phantom key → 语义化键, 新增 4 命名空间 (theme/agent.alerts.metric*/audit.*) + 扩展 3 命名空间 (monitor.lbl.mw*/site*/aiops.predict*), zh/en 7294→7358 +64 键对齐, phantom key 103→29 (残留全为 JSX 模板表达式/ANSI 转义码误匹配), tsc -b=0, npm build✓ (17.40s), ESLint=0/53/0, go build=0, 17/17 测试通过
This commit is contained in:
1 parent
b812b3b20c
commit
b2715ca3bd
12 files changed
+206
-74
No files matched your search
@@ -13,12 +13,12 @@ export const METRIC_OPTIONS = [
|
|||||||
{ value: 'cpu_iowait', label: i18n.t('agent.alertHelper.netInBps'), icon: Cpu },
|
{ value: 'cpu_iowait', label: i18n.t('agent.alertHelper.netInBps'), icon: Cpu },
|
||||||
{ value: 'mem', label: i18n.t('kubernetes.cluster.memoryUsage'), icon: MemoryStick },
|
{ value: 'mem', label: i18n.t('kubernetes.cluster.memoryUsage'), icon: MemoryStick },
|
||||||
{ value: 'mem_available', label: i18n.t('agent.alertHelper.memAvailable'), icon: MemoryStick },
|
{ value: 'mem_available', label: i18n.t('agent.alertHelper.memAvailable'), icon: MemoryStick },
|
||||||
{ value: 'swap', label: i18n.t('Swap 使用率'), icon: MemoryStick },
|
{ value: 'swap', label: i18n.t('agent.alerts.metricSwap'), icon: MemoryStick },
|
||||||
{ value: 'load1', label: i18n.t('1分钟负载'), icon: Gauge },
|
{ value: 'load1', label: i18n.t('agent.alerts.metricLoad1'), icon: Gauge },
|
||||||
{ value: 'disk', label: i18n.t('monitor.hostDisk'), icon: HardDrive },
|
{ 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: '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_time_wait', label: 'TCP TIME_WAIT', icon: Network },
|
||||||
{ value: 'tcp_close_wait', label: 'TCP CLOSE_WAIT', icon: Network },
|
{ value: 'tcp_close_wait', label: 'TCP CLOSE_WAIT', icon: Network },
|
||||||
{ value: 'net_rx_bps', label: i18n.t('monitor.hostNetIn'), icon: Network },
|
{ value: 'net_rx_bps', label: i18n.t('monitor.hostNetIn'), icon: Network },
|
||||||
|
|||||||
@@ -253,7 +253,7 @@ export function MessageView({ item, inRoundGroup = false }: { item: ChatItem; in
|
|||||||
return (
|
return (
|
||||||
<div className="flex gap-2 rounded-lg bg-red-500/10 border border-red-500/30 p-3">
|
<div className="flex gap-2 rounded-lg bg-red-500/10 border border-red-500/30 p-3">
|
||||||
<AlertTriangle className="w-5 h-5 dg-text-red shrink-0 mt-0.5" />
|
<AlertTriangle className="w-5 h-5 dg-text-red shrink-0 mt-0.5" />
|
||||||
<div className="text-sm text-[var(--dg-text-primary)] whitespace-pre-wrap">{item.content || i18n.t('发生错误')}</div>
|
<div className="text-sm text-[var(--dg-text-primary)] whitespace-pre-wrap">{item.content || i18n.t('aiops.agentCliErrorOccurred')}</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -309,10 +309,10 @@ function ToolBlock({ item, inRoundGroup }: { item: ChatItem; inRoundGroup?: bool
|
|||||||
{item.duration && <div className="text-[10px] dg-text-muted">{i18n.t('aiops.durationLabel', { duration: item.duration })}</div>}
|
{item.duration && <div className="text-[10px] dg-text-muted">{i18n.t('aiops.durationLabel', { duration: item.duration })}</div>}
|
||||||
{(item.toolName === 'analyze_output' || looksLikeMarkdown(item.output)) ? (
|
{(item.toolName === 'analyze_output' || looksLikeMarkdown(item.output)) ? (
|
||||||
<div className="bg-[var(--dg-bg-primary)]/40 rounded px-2 py-1.5 max-h-80 overflow-y-auto">
|
<div className="bg-[var(--dg-bg-primary)]/40 rounded px-2 py-1.5 max-h-80 overflow-y-auto">
|
||||||
<AgentMarkdown content={item.output || i18n.t('(无输出)')} />
|
<AgentMarkdown content={item.output || i18n.t('aiops.agentCliNoOutput')} />
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<pre className="text-xs text-[var(--dg-text-secondary)] bg-[var(--dg-bg-primary)]/40 rounded px-2 py-1.5 overflow-x-auto max-h-80 whitespace-pre-wrap">{item.output || i18n.t('(无输出)')}</pre>
|
<pre className="text-xs text-[var(--dg-text-secondary)] bg-[var(--dg-bg-primary)]/40 rounded px-2 py-1.5 overflow-x-auto max-h-80 whitespace-pre-wrap">{item.output || i18n.t('aiops.agentCliNoOutput')}</pre>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -83,15 +83,15 @@ function costTrendFromSlope(slope: number): 'up' | 'down' | 'stable' {
|
|||||||
/** 成本优化建议 */
|
/** 成本优化建议 */
|
||||||
export function costRecommendation(trend: 'up' | 'down' | 'stable', ratio: number): string {
|
export function costRecommendation(trend: 'up' | 'down' | 'stable', ratio: number): string {
|
||||||
if (trend === 'up' && ratio >= 0.85) {
|
if (trend === 'up' && ratio >= 0.85) {
|
||||||
return i18n.t('排查内存泄漏,优化进程内存配置,考虑增加节点');
|
return i18n.t('aiops.predictMemLeak');
|
||||||
}
|
}
|
||||||
if (trend === 'up') {
|
if (trend === 'up') {
|
||||||
return i18n.t('排查内存泄漏,优化进程内存配置,考虑增加节点');
|
return i18n.t('aiops.predictMemLeak');
|
||||||
}
|
}
|
||||||
if (trend === 'down') {
|
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 =
|
const allRatio =
|
||||||
summary.predictedMonthEnd > 0 ? summary.monthCost / summary.predictedMonthEnd : 0;
|
summary.predictedMonthEnd > 0 ? summary.monthCost / summary.predictedMonthEnd : 0;
|
||||||
dimensionForecasts.push({
|
dimensionForecasts.push({
|
||||||
dimension: i18n.t('清理历史数据和日志,实施数据归档策略,扩容磁盘'),
|
dimension: i18n.t('aiops.predictDiskFull'),
|
||||||
currentMonth: summary.monthCost,
|
currentMonth: summary.monthCost,
|
||||||
predictedMonthEnd: summary.predictedMonthEnd,
|
predictedMonthEnd: summary.predictedMonthEnd,
|
||||||
dailyAvg: summary.dailyAvg,
|
dailyAvg: summary.dailyAvg,
|
||||||
@@ -302,7 +302,7 @@ export function computeCostPredictions(input: ComputeCostPredictionsInput): Comp
|
|||||||
|
|
||||||
const metric = (rule.metric === 'daily' ? 'daily' : 'monthly') as 'daily' | 'monthly';
|
const metric = (rule.metric === 'daily' ? 'daily' : 'monthly') as 'daily' | 'monthly';
|
||||||
const ruleProvider = String(rule.provider || '');
|
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 current = 0;
|
||||||
let predicted = 0;
|
let predicted = 0;
|
||||||
@@ -339,7 +339,7 @@ export function computeCostPredictions(input: ComputeCostPredictionsInput): Comp
|
|||||||
if (current >= threshold) probability += 25;
|
if (current >= threshold) probability += 25;
|
||||||
probability = Math.max(5, Math.min(92, probability));
|
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) {
|
if (slope > 0.01 && threshold > current) {
|
||||||
const days = (threshold - current) / slope;
|
const days = (threshold - current) / slope;
|
||||||
if (days < 1) timeframe = metric === 'daily' ? i18n.t('aiops.predictutilsts.se5f6g7h8') : i18n.t('aiops.predictutilsts.sf6g7h8i9');
|
if (days < 1) timeframe = metric === 'daily' ? i18n.t('aiops.predictutilsts.se5f6g7h8') : i18n.t('aiops.predictutilsts.sf6g7h8i9');
|
||||||
|
|||||||
@@ -120,16 +120,16 @@ export interface ComputeCostPredictionsInput {
|
|||||||
|
|
||||||
/** 指标定义:后端 metric name → 展示标签 / 告警表达式前缀 / 阈值 */
|
/** 指标定义:后端 metric name → 展示标签 / 告警表达式前缀 / 阈值 */
|
||||||
export const METRIC_DEFS = [
|
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: '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 },
|
{ key: 'disk', label: i18n.t('aiops.predictTypes.diskUsage'), exprKey: 'disk_usage', threshold: 90 },
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
export const TIME_RANGE_LABELS: Record<string, string> = {
|
export const TIME_RANGE_LABELS: Record<string, string> = {
|
||||||
'1h': i18n.t('1小时后'),
|
'1h': i18n.t('aiops.predictIn1h'),
|
||||||
'24h': i18n.t('24小时后'),
|
'24h': i18n.t('aiops.predictIn24h'),
|
||||||
'7d': i18n.t('7天后'),
|
'7d': i18n.t('aiops.predictIn7d'),
|
||||||
'30d': i18n.t('30天后'),
|
'30d': i18n.t('aiops.predictIn30d'),
|
||||||
};
|
};
|
||||||
|
|
||||||
export const TIME_RANGE_HOURS: Record<string, number> = {
|
export const TIME_RANGE_HOURS: Record<string, number> = {
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ function escapeCsv(s: string): string {
|
|||||||
// exportAuditReportCsv 导出会话审计报告 CSV // Logan.Li
|
// exportAuditReportCsv 导出会话审计报告 CSV // Logan.Li
|
||||||
export function exportAuditReportCsv(meta: ReplaySessionMeta, commands: CommandBookmark[]) {
|
export function exportAuditReportCsv(meta: ReplaySessionMeta, commands: CommandBookmark[]) {
|
||||||
const lines: string[] = [
|
const lines: string[] = [
|
||||||
i18n.t('# 终端会话审计报告'),
|
i18n.t('audit.reportTitle'),
|
||||||
`会话ID,${meta.id}`,
|
`会话ID,${meta.id}`,
|
||||||
`用户,${escapeCsv(meta.username || '')}`,
|
`用户,${escapeCsv(meta.username || '')}`,
|
||||||
`目标主机,${escapeCsv(meta.server_name || '')}`,
|
`目标主机,${escapeCsv(meta.server_name || '')}`,
|
||||||
@@ -33,7 +33,7 @@ export function exportAuditReportCsv(meta: ReplaySessionMeta, commands: CommandB
|
|||||||
`时长(秒),${meta.duration || 0}`,
|
`时长(秒),${meta.duration || 0}`,
|
||||||
`录制大小,${meta.record_size || 0}`,
|
`录制大小,${meta.record_size || 0}`,
|
||||||
'',
|
'',
|
||||||
i18n.t('# 终端会话审计报告'),
|
i18n.t('audit.reportTitle'),
|
||||||
];
|
];
|
||||||
for (const c of commands) {
|
for (const c of commands) {
|
||||||
lines.push(`${c.label},${escapeCsv(c.command)},${c.highRisk ? '是' : '否'}`);
|
lines.push(`${c.label},${escapeCsv(c.command)},${c.highRisk ? '是' : '否'}`);
|
||||||
@@ -55,7 +55,7 @@ export interface CommandExportRow {
|
|||||||
|
|
||||||
// exportCommandsListCsv 导出命令列表 CSV // Logan.Li
|
// exportCommandsListCsv 导出命令列表 CSV // Logan.Li
|
||||||
export function exportCommandsListCsv(commands: CommandExportRow[]) {
|
export function exportCommandsListCsv(commands: CommandExportRow[]) {
|
||||||
const lines: string[] = [i18n.t('时间,用户,命令,输出大小,会话ID,高危')];
|
const lines: string[] = [i18n.t('audit.csvHeader')];
|
||||||
for (const c of commands) {
|
for (const c of commands) {
|
||||||
const ts = c.timestamp || c.created_at || '';
|
const ts = c.timestamp || c.created_at || '';
|
||||||
const highRisk = isHighRiskCommand(c.command || '');
|
const highRisk = isHighRiskCommand(c.command || '');
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ export function CopyButton({
|
|||||||
} else {
|
} else {
|
||||||
toast({
|
toast({
|
||||||
title: i18n.t('monitor.logPanel.copyFailed'),
|
title: i18n.t('monitor.logPanel.copyFailed'),
|
||||||
description: i18n.t('请手动选中内容后复制'),
|
description: i18n.t('common.copyManually'),
|
||||||
variant: 'destructive',
|
variant: 'destructive',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -513,7 +513,8 @@
|
|||||||
"critical": "Critical",
|
"critical": "Critical",
|
||||||
"request.tokenExpired": "Session expired, please log in again",
|
"request.tokenExpired": "Session expired, please log in again",
|
||||||
"days": "days",
|
"days": "days",
|
||||||
"seconds": "sec"
|
"seconds": "sec",
|
||||||
|
"copyManually": "Please manually select and copy"
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"dashboard": "Dashboard",
|
"dashboard": "Dashboard",
|
||||||
@@ -1505,7 +1506,9 @@
|
|||||||
"failed": "Failed",
|
"failed": "Failed",
|
||||||
"closed": "Closed"
|
"closed": "Closed"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"reportTitle": "Terminal Session Audit Report",
|
||||||
|
"csvHeader": "Time,User,Command,Output Size,Session ID,Critical"
|
||||||
},
|
},
|
||||||
"deploy": {
|
"deploy": {
|
||||||
"pipeline": {
|
"pipeline": {
|
||||||
@@ -4865,7 +4868,44 @@
|
|||||||
"selectMetricsHint": "Please check metrics from the left panel",
|
"selectMetricsHint": "Please check metrics from the left panel",
|
||||||
"probeName": "Probe Name",
|
"probeName": "Probe Name",
|
||||||
"execCommand": "Execute Command",
|
"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": {
|
"alertRuleDialog2": {
|
||||||
"editRule": "Edit Alert Rule",
|
"editRule": "Edit Alert Rule",
|
||||||
@@ -6806,7 +6846,11 @@
|
|||||||
"deleteRule": "Delete Rule",
|
"deleteRule": "Delete Rule",
|
||||||
"thresholdTriggered": "Alert threshold triggered",
|
"thresholdTriggered": "Alert threshold triggered",
|
||||||
"noResolved": "No resolved alerts",
|
"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": {
|
"monitor": {
|
||||||
"loadHostFailed": "Failed to load host list",
|
"loadHostFailed": "Failed to load host list",
|
||||||
@@ -7809,7 +7853,17 @@
|
|||||||
"predictTypes": {
|
"predictTypes": {
|
||||||
"memUsage": "Memory Usage",
|
"memUsage": "Memory Usage",
|
||||||
"diskUsage": "Disk 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": {
|
"breadcrumb": {
|
||||||
"dashboard": "Dashboard",
|
"dashboard": "Dashboard",
|
||||||
@@ -7936,5 +7990,17 @@
|
|||||||
"quickQuery": "Quick Query",
|
"quickQuery": "Quick Query",
|
||||||
"quickQueryHint": "{{engine}} common query templates, click to fill",
|
"quickQueryHint": "{{engine}} common query templates, click to fill",
|
||||||
"entries": "entries"
|
"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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -513,7 +513,8 @@
|
|||||||
"critical": "严重",
|
"critical": "严重",
|
||||||
"request.tokenExpired": "登录已过期,请重新登录",
|
"request.tokenExpired": "登录已过期,请重新登录",
|
||||||
"days": "天",
|
"days": "天",
|
||||||
"seconds": "秒"
|
"seconds": "秒",
|
||||||
|
"copyManually": "请手动选中内容后复制"
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"dashboard": "仪表盘",
|
"dashboard": "仪表盘",
|
||||||
@@ -1505,7 +1506,9 @@
|
|||||||
"failed": "失败",
|
"failed": "失败",
|
||||||
"closed": "已关闭"
|
"closed": "已关闭"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"reportTitle": "终端会话审计报告",
|
||||||
|
"csvHeader": "时间,用户,命令,输出大小,会话ID,高危"
|
||||||
},
|
},
|
||||||
"deploy": {
|
"deploy": {
|
||||||
"pipeline": {
|
"pipeline": {
|
||||||
@@ -4865,7 +4868,44 @@
|
|||||||
"selectMetricsHint": "请从左侧勾选指标",
|
"selectMetricsHint": "请从左侧勾选指标",
|
||||||
"probeName": "探针名称",
|
"probeName": "探针名称",
|
||||||
"execCommand": "执行命令",
|
"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": {
|
"alertRuleDialog2": {
|
||||||
"editRule": "编辑告警规则",
|
"editRule": "编辑告警规则",
|
||||||
@@ -6806,7 +6846,11 @@
|
|||||||
"deleteRule": "删除规则",
|
"deleteRule": "删除规则",
|
||||||
"thresholdTriggered": "触发告警阈值",
|
"thresholdTriggered": "触发告警阈值",
|
||||||
"noResolved": "暂无已恢复的告警",
|
"noResolved": "暂无已恢复的告警",
|
||||||
"noActive": "当前无活动告警,一切正常"
|
"noActive": "当前无活动告警,一切正常",
|
||||||
|
"metricSwap": "Swap 使用率",
|
||||||
|
"metricLoad1": "1分钟负载",
|
||||||
|
"metricInode": "Inode 使用率",
|
||||||
|
"metricTcpEst": "TCP 已建立"
|
||||||
},
|
},
|
||||||
"monitor": {
|
"monitor": {
|
||||||
"loadHostFailed": "加载主机列表失败",
|
"loadHostFailed": "加载主机列表失败",
|
||||||
@@ -7809,7 +7853,17 @@
|
|||||||
"predictTypes": {
|
"predictTypes": {
|
||||||
"memUsage": "内存使用率",
|
"memUsage": "内存使用率",
|
||||||
"diskUsage": "磁盘使用率"
|
"diskUsage": "磁盘使用率"
|
||||||
}
|
},
|
||||||
|
"predictMemLeak": "排查内存泄漏,优化进程内存配置,考虑增加节点",
|
||||||
|
"predictDiskFull": "清理历史数据和日志,实施数据归档策略,扩容磁盘",
|
||||||
|
"predictIn24h": "24小时后",
|
||||||
|
"predictNext24h": "未来24小时",
|
||||||
|
"predictCpuUsage": "CPU使用率",
|
||||||
|
"predictIn1h": "1小时后",
|
||||||
|
"predictIn7d": "7天后",
|
||||||
|
"predictIn30d": "30天后",
|
||||||
|
"agentCliErrorOccurred": "发生错误",
|
||||||
|
"agentCliNoOutput": "(无输出)"
|
||||||
},
|
},
|
||||||
"breadcrumb": {
|
"breadcrumb": {
|
||||||
"dashboard": "仪表盘",
|
"dashboard": "仪表盘",
|
||||||
@@ -7936,5 +7990,17 @@
|
|||||||
"quickQuery": "快捷查询",
|
"quickQuery": "快捷查询",
|
||||||
"quickQueryHint": "{{engine}} 常用查询模板,点击快速填充",
|
"quickQueryHint": "{{engine}} 常用查询模板,点击快速填充",
|
||||||
"entries": "条"
|
"entries": "条"
|
||||||
|
},
|
||||||
|
"theme": {
|
||||||
|
"system": "跟随系统",
|
||||||
|
"deepBlue": "深海蓝",
|
||||||
|
"brightWhite": "明亮白",
|
||||||
|
"brightWhiteDesc": "企业控制台清爽浅色",
|
||||||
|
"oneDarkDesc": "Atom 暖灰 IDE,紫绿语法渐变",
|
||||||
|
"draculaDesc": "经典紫粉暗色,极高辨识度",
|
||||||
|
"tokyoNightDesc": "东京霓虹深蓝紫,VS Code 热门",
|
||||||
|
"catppuccinDesc": "马卡龙柔和暗色,护眼",
|
||||||
|
"mainstream": "主流",
|
||||||
|
"developer": "开发者"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -59,20 +59,20 @@ export const MYSQL_PRIMARY_KEYS = ['mysql_qps', 'mysql_connections', 'mysql_buff
|
|||||||
|
|
||||||
export const REDIS_CHARTS: MwChartDef[] = [
|
export const REDIS_CHARTS: MwChartDef[] = [
|
||||||
{ key: 'redis_qps', label: 'QPS', color: 'var(--dg-blue)', unit: 'ops/s' },
|
{ 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_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_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_db_size', label: i18n.t('monitor.lbl.mwSlowQueryRate'), color: 'var(--dg-purple)' },
|
||||||
{ key: 'redis_blocked_clients', label: i18n.t('阻塞客户端'), color: 'var(--dg-orange)' },
|
{ key: 'redis_blocked_clients', label: i18n.t('monitor.lbl.mwBlockedClients'), color: 'var(--dg-orange)' },
|
||||||
];
|
];
|
||||||
|
|
||||||
export const MYSQL_CHARTS: MwChartDef[] = [
|
export const MYSQL_CHARTS: MwChartDef[] = [
|
||||||
{ key: 'mysql_qps', label: 'QPS', color: 'var(--dg-blue)', unit: 'q/s' },
|
{ 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_connections', label: i18n.t('kubernetes.topology.connections'), color: 'var(--dg-cyan)' },
|
||||||
{ key: 'mysql_threads_running', label: i18n.t('活跃线程'), color: 'var(--dg-purple)' },
|
{ key: 'mysql_threads_running', label: i18n.t('monitor.lbl.mwActiveThreads'), color: 'var(--dg-purple)' },
|
||||||
{ key: 'mysql_buffer_hit_rate', label: i18n.t('缓冲池命中率'), color: 'var(--dg-green)', percent: true },
|
{ key: 'mysql_buffer_hit_rate', label: i18n.t('monitor.lbl.mwBufferHitRate'), color: 'var(--dg-green)', percent: true },
|
||||||
{ key: 'mysql_slow_queries', label: i18n.t('慢查询速率'), color: 'var(--dg-orange)', unit: i18n.t('次/周期'), counterDelta: 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('缓冲池命中率'), color: 'var(--dg-amber)', formatter: fmtMemory },
|
{ key: 'mysql_bytes_sent', label: i18n.t('monitor.lbl.mwBufferHitRate'), color: 'var(--dg-amber)', formatter: fmtMemory },
|
||||||
];
|
];
|
||||||
|
|
||||||
export function fmtMemory(bytes: number): string {
|
export function fmtMemory(bytes: number): string {
|
||||||
@@ -139,7 +139,7 @@ export function statusBg(status: string): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function redisModeLabel(mode?: 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<string, number>): number | null {
|
export function redisMemoryPct(metrics: Record<string, number>): number | null {
|
||||||
@@ -209,27 +209,27 @@ export function evalMwHealth(target: MwTarget): MwHealthIssue[] {
|
|||||||
const m = target.latest_metrics || {};
|
const m = target.latest_metrics || {};
|
||||||
const issues: MwHealthIssue[] = [];
|
const issues: MwHealthIssue[] = [];
|
||||||
if (target.status !== 'online') {
|
if (target.status !== 'online') {
|
||||||
issues.push({ level: 'crit', message: i18n.t('实例离线') });
|
issues.push({ level: 'crit', message: i18n.t('monitor.lbl.mwInstanceOffline') });
|
||||||
return issues;
|
return issues;
|
||||||
}
|
}
|
||||||
if (target.description === 'redis') {
|
if (target.description === 'redis') {
|
||||||
if (m.redis_hit_rate > 0 && m.redis_hit_rate < 0.8) issues.push({ level: 'crit', message: i18n.t('命中率 < 80%') });
|
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('命中率 < 90%') });
|
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);
|
const memPct = redisMemoryPct(m);
|
||||||
if (memPct != null && memPct > 90) issues.push({ level: 'crit', message: i18n.t('内存 > 90%') });
|
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('内存 > 80%') });
|
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('阻塞客户端') });
|
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('Key 逐出') });
|
if (m.redis_evicted_keys > 0) issues.push({ level: 'warn', message: i18n.t('monitor.lbl.mwKeyEviction') });
|
||||||
} else if (target.description === 'mysql') {
|
} else if (target.description === 'mysql') {
|
||||||
if (m.mysql_buffer_hit_rate > 0 && m.mysql_buffer_hit_rate < 0.9) {
|
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) {
|
} 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);
|
const connPct = mysqlConnPct(m);
|
||||||
if (connPct != null && connPct > 90) issues.push({ level: 'crit', message: i18n.t('连接 > 90% 上限') });
|
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('连接 > 80% 上限') });
|
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('活跃线程偏多') });
|
if (m.mysql_threads_running > 20) issues.push({ level: 'warn', message: i18n.t('monitor.lbl.mwTooManyThreads') });
|
||||||
}
|
}
|
||||||
return issues;
|
return issues;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,10 +57,10 @@ export const SITE_TIME_RANGE_HOURS: Record<SiteTimeRange, number> = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const SITE_TIME_RANGE_LABELS: Record<SiteTimeRange, string> = {
|
export const SITE_TIME_RANGE_LABELS: Record<SiteTimeRange, string> = {
|
||||||
'1h': i18n.t('近 1 小时'),
|
'1h': i18n.t('monitor.lbl.siteRecentHour'),
|
||||||
'6h': i18n.t('monitor.siteProtocol.rangeDefault'),
|
'6h': i18n.t('monitor.siteProtocol.rangeDefault'),
|
||||||
'24h': i18n.t('近 24 小时'),
|
'24h': i18n.t('monitor.lbl.siteRecent24h'),
|
||||||
'7d': i18n.t('近 7 天'),
|
'7d': i18n.t('monitor.lbl.siteRecent7d'),
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 各协议推荐默认拨测间隔(秒)// Logan.Li */
|
/** 各协议推荐默认拨测间隔(秒)// Logan.Li */
|
||||||
@@ -86,11 +86,11 @@ export function defaultProbeFrequency(type: ProbeType): number {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const probeTypeMeta: Record<ProbeType, { label: string; placeholder: string; hint: string }> = {
|
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),检测状态码与响应时间') },
|
HTTP: { label: i18n.t('monitor.lbl.siteTargetUrl'), placeholder: 'https://example.com/health', hint: i18n.t('monitor.lbl.siteHttpHint') },
|
||||||
SSL: { label: i18n.t('SSL 地址'), placeholder: i18n.t('example.com:443 或 https://example.com'), hint: i18n.t('TLS 握手检测证书(支持 host:port / https:// 域名,不发起 HTTP 请求)') },
|
SSL: { label: i18n.t('monitor.lbl.siteSslAddr'), placeholder: i18n.t('monitor.lbl.siteSslPlaceholder'), hint: i18n.t('monitor.lbl.siteSslHint') },
|
||||||
TCP: { label: i18n.t('主机:端口'), placeholder: i18n.t('192.168.1.1:8080 或 example.com:443'), hint: i18n.t('TCP 端口连通性') },
|
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') },
|
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 {
|
export function probeFrequencyHint(type: ProbeType): string {
|
||||||
|
|||||||
@@ -93,16 +93,16 @@ export function analyzeHttpResults(results: SiteResult[], task: SiteTask): HttpO
|
|||||||
}
|
}
|
||||||
if (code >= 500) {
|
if (code >= 500) {
|
||||||
err5xx++;
|
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) {
|
} else if (code >= 400) {
|
||||||
err4xx++;
|
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') {
|
} else if (r.status === 'timeout') {
|
||||||
otherErr++;
|
otherErr++;
|
||||||
pushEvent(events, r, i18n.t('common.timeoutError'), 'error', r.error_message);
|
pushEvent(events, r, i18n.t('common.timeoutError'), 'error', r.error_message);
|
||||||
} else {
|
} else {
|
||||||
otherErr++;
|
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];
|
const latest = results[0];
|
||||||
@@ -128,7 +128,7 @@ export function analyzeSslResults(results: SiteResult[], task: SiteTask): SslObs
|
|||||||
const events: ProbeEvent[] = [];
|
const events: ProbeEvent[] = [];
|
||||||
for (const r of results) {
|
for (const r of results) {
|
||||||
if (r.status !== 'success') {
|
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) {
|
} 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);
|
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';
|
const failed = r.status !== 'success';
|
||||||
if (failed) {
|
if (failed) {
|
||||||
lastFailAt = r.checked_at;
|
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 };
|
return { time: fmtTime(r.checked_at).slice(-5), up: failed ? 0 : 100, failed };
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -32,22 +32,22 @@ export interface ThemeGroup {
|
|||||||
|
|
||||||
/** 主流主题 — 默认推荐 */
|
/** 主流主题 — 默认推荐 */
|
||||||
const MAINSTREAM_THEMES: ThemeOption[] = [
|
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: '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('深海蓝'), description: i18n.t('深海蓝'), isDark: true, primaryColor: '#0d1117' },
|
{ id: 'ocean-deep', name: i18n.t('theme.deepBlue'), description: i18n.t('theme.deepBlue'), isDark: true, primaryColor: '#0d1117' },
|
||||||
{ id: 'light-professional', name: i18n.t('明亮白'), description: i18n.t('企业控制台清爽浅色'), isDark: false, primaryColor: '#2563eb' },
|
{ id: 'light-professional', name: i18n.t('theme.brightWhite'), description: i18n.t('theme.brightWhiteDesc'), isDark: false, primaryColor: '#2563eb' },
|
||||||
];
|
];
|
||||||
|
|
||||||
/** 开发者主题 — 高辨识度扩展 */
|
/** 开发者主题 — 高辨识度扩展 */
|
||||||
const DEVELOPER_THEMES: ThemeOption[] = [
|
const DEVELOPER_THEMES: ThemeOption[] = [
|
||||||
{ id: 'one-dark', name: 'One Dark', description: i18n.t('Atom 暖灰 IDE,紫绿语法渐变'), isDark: true, primaryColor: '#c678dd' },
|
{ id: 'one-dark', name: 'One Dark', description: i18n.t('theme.oneDarkDesc'), isDark: true, primaryColor: '#c678dd' },
|
||||||
{ id: 'dracula', name: 'Dracula', description: i18n.t('经典紫粉暗色,极高辨识度'), isDark: true, primaryColor: '#bd93f9' },
|
{ id: 'dracula', name: 'Dracula', description: i18n.t('theme.draculaDesc'), isDark: true, primaryColor: '#bd93f9' },
|
||||||
{ id: 'tokyo-night', name: 'Tokyo Night', description: i18n.t('东京霓虹深蓝紫,VS Code 热门'), isDark: true, primaryColor: '#7aa2f7' },
|
{ id: 'tokyo-night', name: 'Tokyo Night', description: i18n.t('theme.tokyoNightDesc'), isDark: true, primaryColor: '#7aa2f7' },
|
||||||
{ id: 'catppuccin', name: 'Catppuccin', description: i18n.t('马卡龙柔和暗色,护眼'), isDark: true, primaryColor: '#89b4fa' },
|
{ id: 'catppuccin', name: 'Catppuccin', description: i18n.t('theme.catppuccinDesc'), isDark: true, primaryColor: '#89b4fa' },
|
||||||
];
|
];
|
||||||
|
|
||||||
export const THEME_GROUPS: ThemeGroup[] = [
|
export const THEME_GROUPS: ThemeGroup[] = [
|
||||||
{ label: i18n.t('主流'), options: MAINSTREAM_THEMES },
|
{ label: i18n.t('theme.mainstream'), options: MAINSTREAM_THEMES },
|
||||||
{ label: i18n.t('开发者'), options: DEVELOPER_THEMES },
|
{ label: i18n.t('theme.developer'), options: DEVELOPER_THEMES },
|
||||||
];
|
];
|
||||||
|
|
||||||
export const THEME_OPTIONS: ThemeOption[] = [
|
export const THEME_OPTIONS: ThemeOption[] = [
|
||||||
|
|||||||
Reference in new issue
Block a user