refactor(i18n): U44 残余硬编码中文清零 — 终端审计状态+凭证类型+流水线阶段+时间格式+CSV导出
20 文件 ~70 处 UI 硬编码中文清零:
- credential-manager/constants.ts: 8 凭证类型 label/desc → labelKey/descKey + i18n.t()
- pipeline-run-detail/types.ts: 6 阶段 label → i18n.t('deploy.stage.*') + labelKey
- pipeline-manager/constants.ts + pipeline-editor/types.ts: 分秒 duration → i18n.t('common.duration.minSec')
- LiveMonitorDialog: 6 终端状态消息 → t()
- RdpAuditViewer: 6 RDP审计状态 → i18n.t('monitor.rdp.*')
- WorkspaceTermDialog: 2 终端连接状态 → t()
- TerminalSessionsTab: 4 时长格式+状态标签 → i18n.t()/t()
- k8s-event-utils + QueryHistoryPanel: 6 相对时间 → i18n.t('common.duration.*Ago')
- export-audit.ts: 9 CSV导出表头 → i18n.t('system.auditExport.*')
- useAuditSettings: 4 审计保留策略消息 → i18n.t('system.auditSettings.*')
- event-handler.ts: 4 AgentCLI事件消息 → i18n.t('aiops.cli.*')
- 其他 9 文件: NotifyPolicyTab/RoleFormDialog/CronJobViewDialog/TerminalOutput/shared-components/prometheus-ds/helpers/CloudServerImport/AdvancedSettingsPanel/releaseManagerHelpers
新增 75 翻译键, zh/en 7987→8059 对齐
tsc -b=0, npm build✓ (17.13s), ESLint=0/43/any=0, go build=0, 17/17 测试通过
This commit is contained in:
1 parent
bd1ccefa7f
commit
05ee051879
26 files changed
+307
-93
No files matched your search
@@ -39,7 +39,7 @@ export function createWsEventHandler(deps: WsEventHandlerDeps) {
|
||||
variant: 'destructive',
|
||||
});
|
||||
wsRef.current?.send(JSON.stringify({ type: ok ? 'confirm' : 'deny', confirm_id: ev.confirm_id }));
|
||||
if (!ok) push({ kind: 'info', content: `已拒绝执行:${ev.command || ev.tool_name}` });
|
||||
if (!ok) push({ kind: 'info', content: i18n.t('aiops.cli.eventRejected', { command: ev.command || ev.tool_name }) });
|
||||
}
|
||||
|
||||
// 处理后端事件
|
||||
@@ -49,7 +49,7 @@ export function createWsEventHandler(deps: WsEventHandlerDeps) {
|
||||
case 'session':
|
||||
push({ kind: 'info', content: ev.message || '' });
|
||||
// 仅「恢复历史会话」时进入可追问(新任务开始的 session 事件文案不同)
|
||||
if (ev.message?.includes('已恢复历史会话')) {
|
||||
if (ev.message?.includes(i18n.t('aiops.cli.eventRecovered'))) {
|
||||
setViewMode(false);
|
||||
setCanContinue(true);
|
||||
}
|
||||
@@ -127,7 +127,7 @@ export function createWsEventHandler(deps: WsEventHandlerDeps) {
|
||||
return [...next, {
|
||||
id: nextId(),
|
||||
kind: 'done',
|
||||
content: text || '任务已完成,请查看上方工具执行结果。',
|
||||
content: text || i18n.t('aiops.cli.eventCompleted'),
|
||||
round: ev.round,
|
||||
}];
|
||||
});
|
||||
@@ -138,7 +138,7 @@ export function createWsEventHandler(deps: WsEventHandlerDeps) {
|
||||
}
|
||||
case 'error':
|
||||
case 'aborted':
|
||||
push({ kind: type === 'aborted' ? 'info' : 'error', content: ev.message || (type === 'aborted' ? '任务已中断' : '发生错误') });
|
||||
push({ kind: type === 'aborted' ? 'info' : 'error', content: ev.message || (type === 'aborted' ? i18n.t('aiops.cli.eventAborted') : i18n.t('aiops.cli.eventFailed')) });
|
||||
setRunning(false);
|
||||
setCanContinue(type !== 'aborted');
|
||||
setHistoryRefresh((k) => k + 1);
|
||||
|
||||
@@ -106,12 +106,12 @@ export function WorkspaceTermDialog({
|
||||
ws.onclose = () => {
|
||||
setConnected(false);
|
||||
setHasOutput(true);
|
||||
term.write('\r\n\x1b[31m[连接已关闭]\x1b[0m\r\n');
|
||||
term.write(`\r\n\x1b[31m${t('deploy.terminal.connClosed')}\x1b[0m\r\n`);
|
||||
};
|
||||
|
||||
ws.onerror = () => {
|
||||
setHasOutput(true);
|
||||
term.write('\r\n\x1b[31m[连接发生错误]\x1b[0m\r\n');
|
||||
term.write(`\r\n\x1b[31m${t('deploy.terminal.connError')}\x1b[0m\r\n`);
|
||||
};
|
||||
|
||||
return () => {
|
||||
@@ -120,6 +120,7 @@ export function WorkspaceTermDialog({
|
||||
wsRef.current = null;
|
||||
setConnected(false);
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [open, runId]);
|
||||
|
||||
// 容器尺寸变化时 fit 并同步远端 PTY,避免缩放后黑边或铺不满。 // Logan.Li
|
||||
|
||||
@@ -3,17 +3,18 @@
|
||||
import {
|
||||
Key, Server, Container, Shield, Cloud, Database, FileText, Globe, Monitor,
|
||||
} from 'lucide-react';
|
||||
import i18n from '@/i18n';
|
||||
import type { SecretType } from './types';
|
||||
|
||||
export const TYPE_CONFIG: Record<SecretType, { label: string; icon: typeof Key; color: string; desc: string }> = {
|
||||
ssh: { label: 'SSH 密钥', icon: Server, color: 'dg-text-yellow', desc: 'SSH 私钥/公钥/密码' },
|
||||
rdp: { label: 'Windows RDP 密码', icon: Monitor, color: 'dg-text-blue', desc: 'Windows 远程桌面用户名/密码' },
|
||||
docker: { label: 'Docker 凭证', icon: Container, color: 'dg-text-cyan', desc: 'Docker Registry 登录凭据' },
|
||||
tls: { label: 'TLS 证书', icon: Shield, color: 'dg-text-green', desc: 'TLS/SSL 证书与私钥' },
|
||||
aksk: { label: 'AKSK 密钥', icon: Cloud, color: 'dg-text-purple', desc: '云服务 AccessKey/SecretKey' },
|
||||
database: { label: '数据库凭证', icon: Database, color: 'dg-text-blue', desc: '数据库连接信息' },
|
||||
api: { label: 'API 密钥', icon: Globe, color: 'dg-text-orange', desc: 'API Token/Key + 端点' },
|
||||
generic: { label: '通用凭证', icon: FileText, color: 'dg-text-secondary', desc: '自定义 Key/Value 键值对' },
|
||||
export const TYPE_CONFIG: Record<SecretType, { label: string; labelKey: string; icon: typeof Key; color: string; desc: string; descKey: string }> = {
|
||||
ssh: { label: i18n.t('deploy.credType.ssh'), labelKey: 'deploy.credType.ssh', icon: Server, color: 'dg-text-yellow', desc: i18n.t('deploy.credTypeDesc.ssh'), descKey: 'deploy.credTypeDesc.ssh' },
|
||||
rdp: { label: i18n.t('deploy.credType.rdp'), labelKey: 'deploy.credType.rdp', icon: Monitor, color: 'dg-text-blue', desc: i18n.t('deploy.credTypeDesc.rdp'), descKey: 'deploy.credTypeDesc.rdp' },
|
||||
docker: { label: i18n.t('deploy.credType.docker'), labelKey: 'deploy.credType.docker', icon: Container, color: 'dg-text-cyan', desc: i18n.t('deploy.credTypeDesc.docker'), descKey: 'deploy.credTypeDesc.docker' },
|
||||
tls: { label: i18n.t('deploy.credType.tls'), labelKey: 'deploy.credType.tls', icon: Shield, color: 'dg-text-green', desc: i18n.t('deploy.credTypeDesc.tls'), descKey: 'deploy.credTypeDesc.tls' },
|
||||
aksk: { label: i18n.t('deploy.credType.aksk'), labelKey: 'deploy.credType.aksk', icon: Cloud, color: 'dg-text-purple', desc: i18n.t('deploy.credTypeDesc.aksk'), descKey: 'deploy.credTypeDesc.aksk' },
|
||||
database: { label: i18n.t('deploy.credType.database'), labelKey: 'deploy.credType.database', icon: Database, color: 'dg-text-blue', desc: i18n.t('deploy.credTypeDesc.database'), descKey: 'deploy.credTypeDesc.database' },
|
||||
api: { label: i18n.t('deploy.credType.api'), labelKey: 'deploy.credType.api', icon: Globe, color: 'dg-text-orange', desc: i18n.t('deploy.credTypeDesc.api'), descKey: 'deploy.credTypeDesc.api' },
|
||||
generic: { label: i18n.t('deploy.credType.generic'), labelKey: 'deploy.credType.generic', icon: FileText, color: 'dg-text-secondary', desc: i18n.t('deploy.credTypeDesc.generic'), descKey: 'deploy.credTypeDesc.generic' },
|
||||
};
|
||||
|
||||
export const TYPE_BADGE_CLASS: Record<SecretType, string> = {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import i18n from '@/i18n';
|
||||
import {
|
||||
GitBranch,
|
||||
Wrench,
|
||||
@@ -62,5 +63,5 @@ export function fmtDuration(s: number | undefined): string {
|
||||
if (s < 60) return `${s}s`;
|
||||
const m = Math.floor(s / 60);
|
||||
const sec = s % 60;
|
||||
return sec > 0 ? `${m}分${sec}秒` : `${m}分`;
|
||||
return sec > 0 ? i18n.t('common.duration.minSec', { m, s: sec }) : i18n.t('common.duration.min', { m });
|
||||
}
|
||||
@@ -32,7 +32,7 @@ export function fmtDuration(s: number | undefined): string {
|
||||
if (s < 60) return `${s}s`;
|
||||
const m = Math.floor(s / 60);
|
||||
const sec = s % 60;
|
||||
return sec > 0 ? `${m}分${sec}秒` : `${m}分`;
|
||||
return sec > 0 ? i18n.t('common.duration.minSec', { m, s: sec }) : i18n.t('common.duration.min', { m });
|
||||
}
|
||||
|
||||
// 解析 stages 字段 // Logan.Li
|
||||
|
||||
+1
-1
@@ -80,7 +80,7 @@ export function AdvancedSettingsPanel({
|
||||
</div>
|
||||
<div className="space-y-1.5">
|
||||
<Label className="text-xs">
|
||||
Job 名称 <span className="text-[var(--dg-text-muted)]">(Webhook)</span>
|
||||
{t('deploy.jobName')} <span className="text-[var(--dg-text-muted)]">(Webhook)</span>
|
||||
</Label>
|
||||
<Input
|
||||
value={jobName}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import i18n from '@/i18n';
|
||||
import {
|
||||
CheckCircle2, Loader2, XCircle, Clock, AlertCircle,
|
||||
GitBranch, Box, Container, Rocket, ShieldCheck,
|
||||
@@ -9,12 +10,12 @@ export type { JsonData };
|
||||
|
||||
// ═══════════ 阶段定义 (与 PipelineManager 共用) ═══════════
|
||||
export const STAGE_DEFS = [
|
||||
{ key: 'checkout', label: '代码检出', icon: GitBranch, color: '#6366F1', order: 1 },
|
||||
{ key: 'build', label: '构建', icon: Box, color: '#F59E0B', order: 2 },
|
||||
{ key: 'test', label: '测试', icon: CheckCircle2, color: '#10B981', order: 3 },
|
||||
{ key: 'image', label: '镜像打包', icon: Container, color: '#06B6D4', order: 4 },
|
||||
{ key: 'deploy', label: '部署', icon: Rocket, color: '#EF4444', order: 5 },
|
||||
{ key: 'verify', label: '验证', icon: ShieldCheck, color: '#3B82F6', order: 6 },
|
||||
{ key: 'checkout', label: i18n.t('deploy.stage.checkout'), labelKey: 'deploy.stage.checkout', icon: GitBranch, color: '#6366F1', order: 1 },
|
||||
{ key: 'build', label: i18n.t('deploy.stage.build'), labelKey: 'deploy.stage.build', icon: Box, color: '#F59E0B', order: 2 },
|
||||
{ key: 'test', label: i18n.t('deploy.stage.test'), labelKey: 'deploy.stage.test', icon: CheckCircle2, color: '#10B981', order: 3 },
|
||||
{ key: 'image', label: i18n.t('deploy.stage.image'), labelKey: 'deploy.stage.image', icon: Container, color: '#06B6D4', order: 4 },
|
||||
{ key: 'deploy', label: i18n.t('deploy.stage.deploy'), labelKey: 'deploy.stage.deploy', icon: Rocket, color: '#EF4444', order: 5 },
|
||||
{ key: 'verify', label: i18n.t('deploy.stage.verify'), labelKey: 'deploy.stage.verify', icon: ShieldCheck, color: '#3B82F6', order: 6 },
|
||||
].sort((a, b) => a.order - b.order);
|
||||
|
||||
export interface PipelineRun {
|
||||
|
||||
@@ -14,10 +14,10 @@ import {
|
||||
|
||||
// 环境配置(值与后端 oneof=dev test staging prod 一致) // Logan.Li
|
||||
export const ENVIRONMENTS: Record<string, { label: string; color: string }> = {
|
||||
dev: { label: '开发环境', color: 'border-blue-500/30 dg-text-blue bg-blue-500/10' },
|
||||
test: { label: '测试环境', color: 'border-cyan-500/30 dg-text-cyan bg-cyan-500/10' },
|
||||
staging: { label: '预发环境', color: 'border-amber-500/30 dg-text-yellow bg-amber-500/10' },
|
||||
prod: { label: '生产环境', color: 'border-red-500/30 dg-text-red bg-red-500/10' },
|
||||
dev: { label: 'dev', color: 'border-blue-500/30 dg-text-blue bg-blue-500/10' },
|
||||
test: { label: 'test', color: 'border-cyan-500/30 dg-text-cyan bg-cyan-500/10' },
|
||||
staging: { label: 'staging', color: 'border-amber-500/30 dg-text-yellow bg-amber-500/10' },
|
||||
prod: { label: 'prod', color: 'border-red-500/30 dg-text-red bg-red-500/10' },
|
||||
};
|
||||
|
||||
const ENV_LABEL_KEY: Record<string, string> = {
|
||||
|
||||
@@ -61,10 +61,10 @@ export function formatEventRelative(ts: string): string {
|
||||
if (diff < 0) return '';
|
||||
const mins = Math.floor(diff / 60000);
|
||||
if (mins < 1) return i18n.t('task.cronJob.time.justNow');
|
||||
if (mins < 60) return `${mins}分钟前`;
|
||||
if (mins < 60) return i18n.t('common.duration.minAgo', { count: mins });
|
||||
const hrs = Math.floor(mins / 60);
|
||||
if (hrs < 24) return `${hrs}小时前`;
|
||||
return `${Math.floor(hrs / 24)}天前`;
|
||||
if (hrs < 24) return i18n.t('common.duration.hourAgo', { count: hrs });
|
||||
return i18n.t('common.duration.dayAgo', { count: Math.floor(hrs / 24) });
|
||||
}
|
||||
|
||||
/** 重复跨度:首次 → 最后 // Logan.Li */
|
||||
|
||||
@@ -54,7 +54,7 @@ export function ContainerInfo({ c }: { c: JsonData }) {
|
||||
CPU: <span className="text-[var(--dg-text-primary)] font-mono">{c.resources?.requests?.cpu || '-'}/{c.resources?.limits?.cpu || '-'}</span>
|
||||
</div>
|
||||
<div className="text-[var(--dg-text-secondary)]">
|
||||
内存: <span className="text-[var(--dg-text-primary)] font-mono">{c.resources?.requests?.memory || '-'}/{c.resources?.limits?.memory || '-'}</span>
|
||||
{i18n.t('k8s.workloadView.memoryLabel')}: <span className="text-[var(--dg-text-primary)] font-mono">{c.resources?.requests?.memory || '-'}/{c.resources?.limits?.memory || '-'}</span>
|
||||
</div>
|
||||
<div className="text-[var(--dg-text-secondary)]">
|
||||
{i18n.t('k8s.workload.portsLabel')}: <span className="text-[var(--dg-text-primary)] font-mono">
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// 告警集合通知策略 — 四类监控绑定联系组 + 消息模版 // Logan.Li
|
||||
import { useState, useEffect, useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import i18n from '@/i18n';
|
||||
import { Server, Database, Globe, Network, Bell, Zap, Loader2, Save, FileText } from 'lucide-react';
|
||||
import { SilenceRulesPanel } from './SilenceRulesPanel';
|
||||
import { toast } from 'sonner';
|
||||
@@ -41,7 +42,7 @@ const CATEGORIES = [
|
||||
|
||||
const DEFAULT_TITLE = '[{{severity_label}}] {{rule_name}} — {{hostname}} ({{metric}})';
|
||||
const DEFAULT_FOOTER = '{{time}} | {{platform}}';
|
||||
const DEFAULT_PLATFORM = 'AIOps 智能运维平台';
|
||||
const DEFAULT_PLATFORM = i18n.t('monitor.notify.defaultPlatform');
|
||||
|
||||
const TEMPLATE_VARS = [
|
||||
'{{time}}', '{{platform}}', '{{rule_name}}', '{{hostname}}',
|
||||
|
||||
@@ -105,7 +105,7 @@ export async function handleTestQuick(ds: PromDS): Promise<void> {
|
||||
skip_tls_verify: ds.skip_tls_verify,
|
||||
});
|
||||
if (data?.success) {
|
||||
toast.success(`连接成功 · ${data.target_count || 0} targets`);
|
||||
toast.success(i18n.t('monitor.prometheus.connSuccess', { count: data.target_count || 0 }));
|
||||
} else {
|
||||
toast.error(data?.message || i18n.t('aiops.llmTestFailed'));
|
||||
}
|
||||
|
||||
@@ -22,9 +22,9 @@ const ENGINE_ICONS: Record<string, { Icon: typeof Flame; color: string }> = {
|
||||
function relativeTime(ts: number): string {
|
||||
const diff = Date.now() - ts;
|
||||
if (diff < 60000) return i18n.t('task.cronJob.time.justNow');
|
||||
if (diff < 3600000) return `${Math.floor(diff / 60000)}分钟前`;
|
||||
if (diff < 86400000) return `${Math.floor(diff / 3600000)}小时前`;
|
||||
return `${Math.floor(diff / 86400000)}天前`;
|
||||
if (diff < 3600000) return i18n.t('common.duration.minAgo', { count: Math.floor(diff / 60000) });
|
||||
if (diff < 86400000) return i18n.t('common.duration.hourAgo', { count: Math.floor(diff / 3600000) });
|
||||
return i18n.t('common.duration.dayAgo', { count: Math.floor(diff / 86400000) });
|
||||
}
|
||||
|
||||
export function QueryHistoryPanel({ visible, onClose, onSelect, onCreateAlert }: Props) {
|
||||
|
||||
@@ -170,10 +170,11 @@ export function CloudServerImport({ open, onClose, initialAccountId }: CloudServ
|
||||
setDiscoverErrors((res?.errors as string[]) || []);
|
||||
} catch (e) {
|
||||
console.error('发现主机失败:', e);
|
||||
setDiscoverErrors([(e as Error)?.message || '发现主机失败']);
|
||||
setDiscoverErrors([(e as Error)?.message || t('server.import.discoverFailed')]);
|
||||
} finally {
|
||||
setIsDiscovering(false);
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [selectedAccount, selectedRegions]);
|
||||
|
||||
// ==================== 导入逻辑 ====================
|
||||
|
||||
@@ -325,7 +325,7 @@ export function CredentialManager() {
|
||||
{/* 内容 */}
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-[var(--dg-text-secondary)] mb-1">
|
||||
{formData.type === 'ssh_key' ? 'SSH 私钥' : formData.type === 'api_token' ? 'Token' : formData.type === 'access_key' ? 'AK/SK (每行一对,用空格或逗号分隔)' : '密码'}
|
||||
{formData.type === 'ssh_key' ? t('system.credTypeLabel.sshKey') : formData.type === 'api_token' ? t('system.credTypeLabel.apiToken') : formData.type === 'access_key' ? 'AK/SK (每行一对,用空格或逗号分隔)' : t('system.credTypeLabel.password')}
|
||||
{!editingId && <span className="dg-text-red"> *</span>}
|
||||
{editingId && <span className="text-xs text-[var(--dg-text-muted)] ml-1">{t('system.leaveBlankNoUpdate')}</span>}
|
||||
</label>
|
||||
|
||||
@@ -102,7 +102,7 @@ export function LiveMonitorDialog({ open, onOpenChange, sessionId, sessionInfo }
|
||||
setConnected(true);
|
||||
setConnectError('');
|
||||
mountXterm(term, fitAddon, () => containerRef.current);
|
||||
term.writeln('\x1b[36m[审计监控] 已连接到会话...\x1b[0m');
|
||||
term.writeln(`\x1b[36m${t('monitor.terminal.auditConnected')}\x1b[0m`);
|
||||
};
|
||||
|
||||
ws.onmessage = (event) => {
|
||||
@@ -112,7 +112,7 @@ export function LiveMonitorDialog({ open, onOpenChange, sessionId, sessionInfo }
|
||||
case 'session_info':
|
||||
setMeta(msg.payload);
|
||||
term.writeln(
|
||||
`\x1b[36m用户: ${msg.payload.username} 服务器: ${msg.payload.server_name} (${msg.payload.server_ip})\x1b[0m`,
|
||||
`\x1b[36m${t('monitor.terminal.userServer', { username: msg.payload.username, serverName: msg.payload.server_name, serverIp: msg.payload.server_ip })}\x1b[0m`,
|
||||
);
|
||||
break;
|
||||
case 'history':
|
||||
@@ -127,14 +127,14 @@ export function LiveMonitorDialog({ open, onOpenChange, sessionId, sessionInfo }
|
||||
}
|
||||
};
|
||||
|
||||
ws.onerror = () => setConnectError('WebSocket 连接失败');
|
||||
ws.onerror = () => setConnectError(t('monitor.terminal.wsConnFailed'));
|
||||
|
||||
ws.onclose = (e) => {
|
||||
if (!didOpen) {
|
||||
setConnectError(`连接失败 (code=${e.code}): ${e.reason || '认证失败或网络问题'}`);
|
||||
setConnectError(t('monitor.terminal.connFailedCode', { code: e.code, reason: e.reason || t('monitor.terminal.authOrNetwork') }));
|
||||
}
|
||||
setConnected(false);
|
||||
term.writeln('\r\n\x1b[33m[审计监控] 连接已断开\x1b[0m');
|
||||
term.writeln(`\r\n\x1b[33m${t('monitor.terminal.auditDisconnected')}\x1b[0m`);
|
||||
};
|
||||
|
||||
const timeout = setTimeout(() => {
|
||||
@@ -153,6 +153,7 @@ export function LiveMonitorDialog({ open, onOpenChange, sessionId, sessionInfo }
|
||||
wsRef.current = null;
|
||||
setConnected(false);
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [open, sessionId]);
|
||||
|
||||
// 容器尺寸变化时持续 fit // Logan.Li
|
||||
|
||||
@@ -126,7 +126,7 @@ export function RdpAuditViewer({ open, onOpenChange, sessionId, mode }: RdpAudit
|
||||
|
||||
useEffect(() => {
|
||||
if (!open || !sessionId) return;
|
||||
setStatus(mode === 'live' ? '正在连接 RDP 实时审计...' : '正在加载 RDP 录屏...');
|
||||
setStatus(mode === 'live' ? i18n.t('monitor.rdp.connectingLive') : i18n.t('monitor.rdp.loadingRecording'));
|
||||
setLoading(true);
|
||||
setFrames([]);
|
||||
setIndex(0);
|
||||
@@ -161,8 +161,8 @@ export function RdpAuditViewer({ open, onOpenChange, sessionId, mode }: RdpAudit
|
||||
/* ignore */
|
||||
}
|
||||
};
|
||||
ws.onerror = () => { setLoading(false); setStatus('RDP 实时审计连接失败'); };
|
||||
ws.onclose = () => setStatus((prev) => prev || 'RDP 实时审计已断开');
|
||||
ws.onerror = () => { setLoading(false); setStatus(i18n.t('monitor.rdp.liveConnFailed')); };
|
||||
ws.onclose = () => setStatus((prev) => prev || i18n.t('monitor.rdp.liveDisconnected'));
|
||||
return () => {
|
||||
ws.close();
|
||||
wsRef.current = null;
|
||||
@@ -182,13 +182,13 @@ export function RdpAuditViewer({ open, onOpenChange, sessionId, mode }: RdpAudit
|
||||
setCanvasSize({ width: sizeFrame.width, height: sizeFrame.height });
|
||||
}
|
||||
setFrames(list);
|
||||
setStatus(list.length ? '' : '该 RDP 会话没有可播放画面帧');
|
||||
setStatus(list.length ? '' : i18n.t('monitor.rdp.noFrames'));
|
||||
setPlaying(list.length > 0);
|
||||
setLoading(false);
|
||||
})
|
||||
.catch(() => {
|
||||
if (!cancelled) {
|
||||
setStatus('RDP 录屏加载失败');
|
||||
setStatus(i18n.t('monitor.rdp.loadFailed'));
|
||||
setLoading(false);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -45,7 +45,7 @@ const MODULE_GROUPS: { key: string; label: string; prefixes: string[] }[] = [
|
||||
{ key: 'deploy', label: i18n.t('common.menuApp'), prefixes: ['deploy:'] },
|
||||
{ key: 'monitor', label: i18n.t('common.menuMonitoring'), prefixes: ['monitor:', 'agent:'] },
|
||||
{ key: 'auto', label: i18n.t('common.menuAutomation'), prefixes: ['auto:'] },
|
||||
{ key: 'aiops', label: '🤖 AIOps智能', prefixes: ['aiops:'] },
|
||||
{ key: 'aiops', label: i18n.t('system.role.aiopsGroup'), prefixes: ['aiops:'] },
|
||||
{ key: 'approval', label: i18n.t('common.menuApproval'), prefixes: ['approval:'] },
|
||||
{ key: 'audit', label: i18n.t('common.menuAudit'), prefixes: ['audit:'] },
|
||||
{ key: 'system', label: i18n.t('common.menuSystem'), prefixes: ['system:'] },
|
||||
|
||||
@@ -17,16 +17,17 @@ import { useTerminalSessions, useTerminalSessionMutations } from '@/hooks/api/us
|
||||
import { useConfirm } from '@/components/ui/confirm-dialog';
|
||||
import { ReplayDialog } from './ReplayDialog';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import i18n from '@/i18n';
|
||||
|
||||
function formatDuration(sec: number): string {
|
||||
if (!sec || sec < 0) return '--';
|
||||
if (sec < 60) return `${sec}秒`;
|
||||
if (sec < 60) return i18n.t('common.duration.seconds', { count: sec });
|
||||
const m = Math.floor(sec / 60);
|
||||
const s = sec % 60;
|
||||
if (m < 60) return `${m}分${s > 0 ? `${s}秒` : ''}`;
|
||||
if (m < 60) return s > 0 ? i18n.t('common.duration.minSec', { m, s }) : i18n.t('common.duration.min', { m });
|
||||
const h = Math.floor(m / 60);
|
||||
const rm = m % 60;
|
||||
return `${h}时${rm > 0 ? `${rm}分` : ''}`;
|
||||
return rm > 0 ? i18n.t('common.duration.hoursMin', { h, m: rm }) : i18n.t('common.duration.hour', { count: h });
|
||||
}
|
||||
|
||||
function formatSize(bytes: number): string {
|
||||
@@ -170,7 +171,7 @@ export function TerminalSessionsTab() {
|
||||
}
|
||||
onClick={() => setStatusFilter(st)}
|
||||
>
|
||||
{st === '' ? '全部' : st === 'active' ? '活动中' : st === 'closed' ? '已关闭' : '失败'}
|
||||
{st === '' ? t('system.terminalSession.all') : st === 'active' ? t('system.terminalSession.active') : st === 'closed' ? t('system.terminalSession.closed') : t('system.terminalSession.failed')}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -24,14 +24,14 @@ function escapeCsv(s: string): string {
|
||||
export function exportAuditReportCsv(meta: ReplaySessionMeta, commands: CommandBookmark[]) {
|
||||
const lines: string[] = [
|
||||
i18n.t('audit.reportTitle'),
|
||||
`会话ID,${meta.id}`,
|
||||
`用户,${escapeCsv(meta.username || '')}`,
|
||||
`目标主机,${escapeCsv(meta.server_name || '')}`,
|
||||
`${i18n.t('system.auditExport.sessionId')},${meta.id}`,
|
||||
`${i18n.t('system.auditExport.user')},${escapeCsv(meta.username || '')}`,
|
||||
`${i18n.t('system.auditExport.targetHost')},${escapeCsv(meta.server_name || '')}`,
|
||||
`IP,${meta.server_ip}:${meta.server_port}`,
|
||||
`客户端IP,${meta.client_ip || ''}`,
|
||||
`开始时间,${meta.start_time || ''}`,
|
||||
`时长(秒),${meta.duration || 0}`,
|
||||
`录制大小,${meta.record_size || 0}`,
|
||||
`${i18n.t('system.auditExport.clientIp')},${meta.client_ip || ''}`,
|
||||
`${i18n.t('system.auditExport.startTime')},${meta.start_time || ''}`,
|
||||
`${i18n.t('system.auditExport.duration')},${meta.duration || 0}`,
|
||||
`${i18n.t('system.auditExport.status')},${meta.record_size || 0}`,
|
||||
'',
|
||||
i18n.t('audit.reportTitle'),
|
||||
];
|
||||
|
||||
@@ -107,8 +107,8 @@ export function useAuditSettings() {
|
||||
const total = res.cleanup?.total ?? 0;
|
||||
toast.success(
|
||||
total > 0
|
||||
? `已应用 ${days} 天保留策略,立即清理 ${total} 条超期记录`
|
||||
: `已应用 ${days} 天保留策略,暂无超期记录需清理`,
|
||||
? i18n.t('system.auditSettings.appliedWithCleanup', { days, total })
|
||||
: i18n.t('system.auditSettings.appliedNoCleanup', { days }),
|
||||
);
|
||||
} catch (e: unknown) {
|
||||
toast.error(
|
||||
@@ -131,16 +131,13 @@ export function useAuditSettings() {
|
||||
total?: number;
|
||||
};
|
||||
if (typeof s.total === "number") {
|
||||
detail =
|
||||
s.total > 0
|
||||
? `,清理 ${s.total} 条`
|
||||
: i18n.t("system.auditSetting.noExpiredRecords");
|
||||
detail = s.total > 0 ? i18n.t('system.auditSettings.cleanupCount', { count: s.total }) : i18n.t("system.auditSetting.noExpiredRecords");
|
||||
}
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
return `上次清理:${t}${detail}`;
|
||||
return i18n.t('system.auditSettings.lastCleanup', { time: t, detail });
|
||||
})();
|
||||
|
||||
return {
|
||||
|
||||
@@ -87,7 +87,7 @@ export function CronJobViewDialog({ open, onOpenChange, job }: Props) {
|
||||
|
||||
{job.script?.name && (
|
||||
<div className="text-xs dg-text-secondary">
|
||||
关联脚本: <span className="text-[var(--dg-text-primary)]">{job.script.name}</span>
|
||||
{t('task.cronJob.associatedScript')}: <span className="text-[var(--dg-text-primary)]">{job.script.name}</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -101,7 +101,7 @@ export function CronJobViewDialog({ open, onOpenChange, job }: Props) {
|
||||
/>
|
||||
) : (
|
||||
<pre className="rounded-lg border border-[var(--dg-border)] bg-[var(--dg-bg-tertiary)] p-4 text-xs font-mono text-[var(--dg-text-primary)] whitespace-pre-wrap break-all max-h-96 overflow-auto">
|
||||
{content || '(无命令内容)'}
|
||||
{content || t('task.cronJob.noCommand')}
|
||||
</pre>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -33,7 +33,7 @@ export function TerminalOutput({
|
||||
status,
|
||||
durationMs,
|
||||
startedAt,
|
||||
emptyText = '(无输出)',
|
||||
emptyText = i18n.t('task.terminal.noOutput'),
|
||||
className,
|
||||
maxHeight = 'min(28rem, 55vh)',
|
||||
variant = 'plain',
|
||||
|
||||
+115
-11
@@ -184,7 +184,9 @@
|
||||
"minAgo": "{{count}} min ago",
|
||||
"secAgo": "{{count}}s ago",
|
||||
"hourAgo": "{{count}}h ago",
|
||||
"dayAgo": "{{count}}d ago"
|
||||
"dayAgo": "{{count}}d ago",
|
||||
"seconds": "{{count}}s",
|
||||
"hoursMin": "{{h}}h {{m}}m"
|
||||
},
|
||||
"ebCaughtError": "[ErrorBoundary] Caught error:",
|
||||
"ebCopyError": "Copy Error",
|
||||
@@ -1290,7 +1292,10 @@
|
||||
"loggingIn": "Logging in..."
|
||||
},
|
||||
"webshellConnect": "Connect",
|
||||
"webshellLoggingIn": "Logging in..."
|
||||
"webshellLoggingIn": "Logging in...",
|
||||
"import": {
|
||||
"discoverFailed": "Failed to discover hosts"
|
||||
}
|
||||
},
|
||||
"alert": {
|
||||
"acknowledged": "Alert acknowledged",
|
||||
@@ -2538,7 +2543,8 @@
|
||||
"notInstalled": "Not installed",
|
||||
"installing": "Installing",
|
||||
"test": "Test",
|
||||
"install": "Install"
|
||||
"install": "Install",
|
||||
"recommended": "Recommended"
|
||||
},
|
||||
"trigger": {
|
||||
"manual": "Manual",
|
||||
@@ -2583,7 +2589,35 @@
|
||||
"envVar": "Environment Variables",
|
||||
"envVarOptional": "Environment Variables (optional)"
|
||||
},
|
||||
"workspaceTerminalTitle": "Workspace Terminal #{{num}}"
|
||||
"workspaceTerminalTitle": "Workspace Terminal #{{num}}",
|
||||
"credType": {
|
||||
"ssh": "SSH Key",
|
||||
"rdp": "Windows RDP Password",
|
||||
"docker": "Docker Credential",
|
||||
"tls": "TLS Certificate",
|
||||
"aksk": "AKSK Key",
|
||||
"database": "Database Credential",
|
||||
"api": "API Key",
|
||||
"generic": "Generic Credential"
|
||||
},
|
||||
"credTypeDesc": {
|
||||
"ssh": "SSH private/public key/password",
|
||||
"rdp": "Windows remote desktop username/password",
|
||||
"docker": "Docker Registry login credentials",
|
||||
"tls": "TLS/SSL certificate and private key",
|
||||
"aksk": "Cloud AccessKey/SecretKey",
|
||||
"database": "Database connection info",
|
||||
"api": "API Token/Key + endpoint",
|
||||
"generic": "Custom Key/Value pairs"
|
||||
},
|
||||
"fmtDuration": {
|
||||
"minSec": "{{m}}m {{s}}s"
|
||||
},
|
||||
"terminal": {
|
||||
"connClosed": "[Connection Closed]",
|
||||
"connError": "[Connection Error]"
|
||||
},
|
||||
"jobName": "Job Name"
|
||||
},
|
||||
"k8s": {
|
||||
"actionModal": {
|
||||
@@ -3708,7 +3742,8 @@
|
||||
"serviceName": "Service Name",
|
||||
"podCount": "Pod Count",
|
||||
"actualSchedule": "Actual Schedule",
|
||||
"restartSentDesc": "{{kind}} rolling restart triggered"
|
||||
"restartSentDesc": "{{kind}} rolling restart triggered",
|
||||
"memoryLabel": "Memory"
|
||||
},
|
||||
"workloads": {
|
||||
"scaleSuccess": "Scaling succeeded",
|
||||
@@ -4976,7 +5011,9 @@
|
||||
"noData": "No Prometheus datasources",
|
||||
"addHint": "Add datasources for metrics monitoring and dashboards"
|
||||
},
|
||||
"prometheus": "Prometheus",
|
||||
"prometheus": {
|
||||
"connSuccess": "Connection successful · {{count}} targets"
|
||||
},
|
||||
"prometheusDashb": {
|
||||
"connecting": "Connecting…"
|
||||
},
|
||||
@@ -5397,6 +5434,25 @@
|
||||
"durationMinutes": "{{count}} min",
|
||||
"queryHistory": {
|
||||
"count": "{{count}} entries"
|
||||
},
|
||||
"terminal": {
|
||||
"auditConnected": "[Audit Monitor] Connected to session...",
|
||||
"userServer": "User: {{username}} Server: {{serverName}} ({{serverIp}})",
|
||||
"wsConnFailed": "WebSocket connection failed",
|
||||
"connFailedCode": "Connection failed (code={{code}}): {{reason}}",
|
||||
"auditDisconnected": "[Audit Monitor] Disconnected",
|
||||
"authOrNetwork": "Authentication failed or network issue"
|
||||
},
|
||||
"rdp": {
|
||||
"connectingLive": "Connecting to RDP live audit...",
|
||||
"loadingRecording": "Loading RDP recording...",
|
||||
"liveConnFailed": "RDP live audit connection failed",
|
||||
"liveDisconnected": "RDP live audit disconnected",
|
||||
"noFrames": "No playable frames for this RDP session",
|
||||
"loadFailed": "RDP recording load failed"
|
||||
},
|
||||
"notify": {
|
||||
"defaultPlatform": "AIOps Platform"
|
||||
}
|
||||
},
|
||||
"task": {
|
||||
@@ -5476,7 +5532,9 @@
|
||||
"confirmDelete": "Delete \"{{name}}\"? This cannot be undone.",
|
||||
"execDuration": "Duration: {{ms}}ms"
|
||||
},
|
||||
"runCount": "{{count}} times"
|
||||
"runCount": "{{count}} times",
|
||||
"associatedScript": "Associated Script",
|
||||
"noCommand": "(No command content)"
|
||||
},
|
||||
"cronJobCol": {
|
||||
"task": "Task",
|
||||
@@ -5601,6 +5659,9 @@
|
||||
"noShell": "No shell interpreter detected. Scripts cannot run on this host. For Docker deployments, ensure bash is installed in the image.",
|
||||
"noPython": "Python is not installed. Python scripts will not be executable.",
|
||||
"partialUnavailable": "Some interpreters are unavailable; scripts of those types cannot run after creation."
|
||||
},
|
||||
"terminal": {
|
||||
"noOutput": "(No output)"
|
||||
}
|
||||
},
|
||||
"rbac": {
|
||||
@@ -7466,7 +7527,12 @@
|
||||
"invalidRetentionDays": "Please select valid retention days",
|
||||
"noExpiredRecords": ", no expired records"
|
||||
},
|
||||
"auditSettings": "Audit Settings",
|
||||
"auditSettings": {
|
||||
"appliedWithCleanup": "Applied {{days}}-day retention policy, cleaned {{total}} expired records",
|
||||
"appliedNoCleanup": "Applied {{days}}-day retention policy, no expired records to clean",
|
||||
"cleanupCount": ", cleaned {{count}} records",
|
||||
"lastCleanup": "Last cleanup: {{time}}{{detail}}"
|
||||
},
|
||||
"auditSettingsDesc": "Operation logs and audit policy",
|
||||
"auditStats": "Audit Statistics",
|
||||
"auditSuccess": "Success",
|
||||
@@ -7818,7 +7884,12 @@
|
||||
"terminalRecordSize": "Recording Size",
|
||||
"terminalReplay": "Replay",
|
||||
"terminalServer": "Server",
|
||||
"terminalSession": "Session",
|
||||
"terminalSession": {
|
||||
"all": "All",
|
||||
"active": "Active",
|
||||
"closed": "Closed",
|
||||
"failed": "Failed"
|
||||
},
|
||||
"terminalStartTime": "Start Time",
|
||||
"terminalStatus": "Status",
|
||||
"terminalUser": "User",
|
||||
@@ -7897,7 +7968,35 @@
|
||||
"credentialAkSk": "AK/SK (one pair per line, space or comma separated)",
|
||||
"credentialEncryptedHint": "Credentials are encrypted with AES-256-GCM, decrypted only on server side",
|
||||
"permissionAssign": "Permission Assignment",
|
||||
"adminPassword": "Admin Password"
|
||||
"adminPassword": "Admin Password",
|
||||
"csvHeader": {
|
||||
"username": "Username",
|
||||
"nickname": "Nickname",
|
||||
"displayName": "Display Name",
|
||||
"email": "Email",
|
||||
"phone": "Phone",
|
||||
"role": "Role",
|
||||
"department": "Department"
|
||||
},
|
||||
"auditExport": {
|
||||
"sessionId": "Session ID",
|
||||
"user": "User",
|
||||
"targetHost": "Target Host",
|
||||
"clientIp": "Client IP",
|
||||
"startTime": "Start Time",
|
||||
"endTime": "End Time",
|
||||
"duration": "Duration",
|
||||
"commandCount": "Command Count",
|
||||
"status": "Status"
|
||||
},
|
||||
"credTypeLabel": {
|
||||
"sshKey": "SSH Private Key",
|
||||
"apiToken": "Token",
|
||||
"password": "Password"
|
||||
},
|
||||
"role": {
|
||||
"aiopsGroup": "AIOps Intelligence"
|
||||
}
|
||||
},
|
||||
"aiops": {
|
||||
"activeCount": "{{count}} active",
|
||||
@@ -8255,7 +8354,12 @@
|
||||
"execute": "Run"
|
||||
},
|
||||
"confirmHighRiskTitle": "⚠️ Confirm High-Risk Operation",
|
||||
"confirmHighRiskDesc": "Tool: {{tool}}\nRisk: {{risk}}\nCommand: {{command}}"
|
||||
"confirmHighRiskDesc": "Tool: {{tool}}\nRisk: {{risk}}\nCommand: {{command}}",
|
||||
"eventRejected": "Execution rejected: {{command}}",
|
||||
"eventRecovered": "Session recovered",
|
||||
"eventCompleted": "Task completed. Please check the tool execution results above.",
|
||||
"eventAborted": "Task aborted",
|
||||
"eventFailed": "Task execution failed"
|
||||
},
|
||||
"cloudService": "Cloud Services",
|
||||
"codingPlan": "Coding Plan",
|
||||
|
||||
+115
-11
@@ -184,7 +184,9 @@
|
||||
"minAgo": "{{count}}分钟前",
|
||||
"secAgo": "{{count}}秒前",
|
||||
"hourAgo": "{{count}}小时前",
|
||||
"dayAgo": "{{count}}天前"
|
||||
"dayAgo": "{{count}}天前",
|
||||
"seconds": "{{count}}秒",
|
||||
"hoursMin": "{{h}}时{{m}}分"
|
||||
},
|
||||
"ebCaughtError": "[ErrorBoundary] 捕获到错误:",
|
||||
"ebCopyError": "复制错误",
|
||||
@@ -1290,7 +1292,10 @@
|
||||
"loggingIn": "正在登录..."
|
||||
},
|
||||
"webshellConnect": "连接",
|
||||
"webshellLoggingIn": "正在登录..."
|
||||
"webshellLoggingIn": "正在登录...",
|
||||
"import": {
|
||||
"discoverFailed": "发现主机失败"
|
||||
}
|
||||
},
|
||||
"alert": {
|
||||
"acknowledged": "告警已确认",
|
||||
@@ -2538,7 +2543,8 @@
|
||||
"notInstalled": "未安装",
|
||||
"installing": "安装中",
|
||||
"test": "测试",
|
||||
"install": "安装"
|
||||
"install": "安装",
|
||||
"recommended": "推荐"
|
||||
},
|
||||
"trigger": {
|
||||
"manual": "手动",
|
||||
@@ -2583,7 +2589,35 @@
|
||||
"envVar": "环境变量",
|
||||
"envVarOptional": "环境变量 (可选)"
|
||||
},
|
||||
"workspaceTerminalTitle": "Workspace 终端 #{{num}}"
|
||||
"workspaceTerminalTitle": "Workspace 终端 #{{num}}",
|
||||
"credType": {
|
||||
"ssh": "SSH 密钥",
|
||||
"rdp": "Windows RDP 密码",
|
||||
"docker": "Docker 凭证",
|
||||
"tls": "TLS 证书",
|
||||
"aksk": "AKSK 密钥",
|
||||
"database": "数据库凭证",
|
||||
"api": "API 密钥",
|
||||
"generic": "通用凭证"
|
||||
},
|
||||
"credTypeDesc": {
|
||||
"ssh": "SSH 私钥/公钥/密码",
|
||||
"rdp": "Windows 远程桌面用户名/密码",
|
||||
"docker": "Docker Registry 登录凭据",
|
||||
"tls": "TLS/SSL 证书与私钥",
|
||||
"aksk": "云服务 AccessKey/SecretKey",
|
||||
"database": "数据库连接信息",
|
||||
"api": "API Token/Key + 端点",
|
||||
"generic": "自定义 Key/Value 键值对"
|
||||
},
|
||||
"fmtDuration": {
|
||||
"minSec": "{{m}}分{{s}}秒"
|
||||
},
|
||||
"terminal": {
|
||||
"connClosed": "[连接已关闭]",
|
||||
"connError": "[连接发生错误]"
|
||||
},
|
||||
"jobName": "Job 名称"
|
||||
},
|
||||
"k8s": {
|
||||
"actionModal": {
|
||||
@@ -3708,7 +3742,8 @@
|
||||
"serviceName": "服务名",
|
||||
"podCount": "Pod 数量",
|
||||
"actualSchedule": "当前调度",
|
||||
"restartSentDesc": "{{kind}} 滚动重启已触发"
|
||||
"restartSentDesc": "{{kind}} 滚动重启已触发",
|
||||
"memoryLabel": "内存"
|
||||
},
|
||||
"workloads": {
|
||||
"scaleSuccess": "扩缩容成功",
|
||||
@@ -4976,7 +5011,9 @@
|
||||
"noData": "暂无 Prometheus 数据源",
|
||||
"addHint": "添加数据源后可用于指标监控与监控大屏"
|
||||
},
|
||||
"prometheus": "Prometheus",
|
||||
"prometheus": {
|
||||
"connSuccess": "连接成功 · {{count}} targets"
|
||||
},
|
||||
"prometheusDashb": {
|
||||
"connecting": "连接中…"
|
||||
},
|
||||
@@ -5397,6 +5434,25 @@
|
||||
"durationMinutes": "{{count}}分钟",
|
||||
"queryHistory": {
|
||||
"count": "{{count}} 条"
|
||||
},
|
||||
"terminal": {
|
||||
"auditConnected": "[审计监控] 已连接到会话...",
|
||||
"userServer": "用户: {{username}} 服务器: {{serverName}} ({{serverIp}})",
|
||||
"wsConnFailed": "WebSocket 连接失败",
|
||||
"connFailedCode": "连接失败 (code={{code}}): {{reason}}",
|
||||
"auditDisconnected": "[审计监控] 连接已断开",
|
||||
"authOrNetwork": "认证失败或网络问题"
|
||||
},
|
||||
"rdp": {
|
||||
"connectingLive": "正在连接 RDP 实时审计...",
|
||||
"loadingRecording": "正在加载 RDP 录屏...",
|
||||
"liveConnFailed": "RDP 实时审计连接失败",
|
||||
"liveDisconnected": "RDP 实时审计已断开",
|
||||
"noFrames": "该 RDP 会话没有可播放画面帧",
|
||||
"loadFailed": "RDP 录屏加载失败"
|
||||
},
|
||||
"notify": {
|
||||
"defaultPlatform": "AIOps 智能运维平台"
|
||||
}
|
||||
},
|
||||
"task": {
|
||||
@@ -5476,7 +5532,9 @@
|
||||
"confirmDelete": "确定删除「{{name}}」吗?此操作不可恢复。",
|
||||
"execDuration": "耗时 {{ms}}ms"
|
||||
},
|
||||
"runCount": "{{count}} 次"
|
||||
"runCount": "{{count}} 次",
|
||||
"associatedScript": "关联脚本",
|
||||
"noCommand": "(无命令内容)"
|
||||
},
|
||||
"cronJobCol": {
|
||||
"task": "任务",
|
||||
@@ -5601,6 +5659,9 @@
|
||||
"noShell": "未检测到 Shell 解释器,脚本无法在本机执行。Docker 部署请确认镜像已安装 bash。",
|
||||
"noPython": "Python 未安装,Python 类型脚本将无法执行。",
|
||||
"partialUnavailable": "部分解释器不可用,对应类型的脚本创建后无法执行。"
|
||||
},
|
||||
"terminal": {
|
||||
"noOutput": "(无输出)"
|
||||
}
|
||||
},
|
||||
"rbac": {
|
||||
@@ -7466,7 +7527,12 @@
|
||||
"invalidRetentionDays": "请选择有效的保留天数",
|
||||
"noExpiredRecords": ",无超期记录"
|
||||
},
|
||||
"auditSettings": "审计设置",
|
||||
"auditSettings": {
|
||||
"appliedWithCleanup": "已应用 {{days}} 天保留策略,立即清理 {{total}} 条超期记录",
|
||||
"appliedNoCleanup": "已应用 {{days}} 天保留策略,暂无超期记录需清理",
|
||||
"cleanupCount": ",清理 {{count}} 条",
|
||||
"lastCleanup": "上次清理:{{time}}{{detail}}"
|
||||
},
|
||||
"auditSettingsDesc": "操作日志与审计策略",
|
||||
"auditStats": "审计统计",
|
||||
"auditSuccess": "成功",
|
||||
@@ -7818,7 +7884,12 @@
|
||||
"terminalRecordSize": "录制大小",
|
||||
"terminalReplay": "回放",
|
||||
"terminalServer": "服务器",
|
||||
"terminalSession": "会话",
|
||||
"terminalSession": {
|
||||
"all": "全部",
|
||||
"active": "活动中",
|
||||
"closed": "已关闭",
|
||||
"failed": "失败"
|
||||
},
|
||||
"terminalStartTime": "开始时间",
|
||||
"terminalStatus": "状态",
|
||||
"terminalUser": "用户",
|
||||
@@ -7897,7 +7968,35 @@
|
||||
"credentialAkSk": "AK/SK (每行一对,用空格或逗号分隔)",
|
||||
"credentialEncryptedHint": "凭据内容使用 AES-256-GCM 加密存储,仅在服务器端解密使用",
|
||||
"permissionAssign": "权限分配",
|
||||
"adminPassword": "管理员密码"
|
||||
"adminPassword": "管理员密码",
|
||||
"csvHeader": {
|
||||
"username": "用户名",
|
||||
"nickname": "昵称",
|
||||
"displayName": "显示名",
|
||||
"email": "邮箱",
|
||||
"phone": "手机",
|
||||
"role": "角色",
|
||||
"department": "部门"
|
||||
},
|
||||
"auditExport": {
|
||||
"sessionId": "会话ID",
|
||||
"user": "用户",
|
||||
"targetHost": "目标主机",
|
||||
"clientIp": "客户端IP",
|
||||
"startTime": "开始时间",
|
||||
"endTime": "结束时间",
|
||||
"duration": "时长",
|
||||
"commandCount": "命令数",
|
||||
"status": "状态"
|
||||
},
|
||||
"credTypeLabel": {
|
||||
"sshKey": "SSH 私钥",
|
||||
"apiToken": "Token",
|
||||
"password": "密码"
|
||||
},
|
||||
"role": {
|
||||
"aiopsGroup": "AIOps智能"
|
||||
}
|
||||
},
|
||||
"aiops": {
|
||||
"activeCount": "{{count}} 个活跃",
|
||||
@@ -8255,7 +8354,12 @@
|
||||
"execute": "执行"
|
||||
},
|
||||
"confirmHighRiskTitle": "⚠️ 确认执行高危操作",
|
||||
"confirmHighRiskDesc": "工具:{{tool}}\n风险:{{risk}}\n命令:{{command}}"
|
||||
"confirmHighRiskDesc": "工具:{{tool}}\n风险:{{risk}}\n命令:{{command}}",
|
||||
"eventRejected": "已拒绝执行:{{command}}",
|
||||
"eventRecovered": "已恢复历史会话",
|
||||
"eventCompleted": "任务已完成,请查看上方工具执行结果。",
|
||||
"eventAborted": "任务已取消",
|
||||
"eventFailed": "任务执行失败"
|
||||
},
|
||||
"cloudService": "云服务",
|
||||
"codingPlan": "编码套餐 Coding Plan",
|
||||
|
||||
Reference in new issue
Block a user