feat(i18n): 剩余模块全量国际化 — 51% 覆盖率 (231 文件接入 t())

批量转换 163 个文件,3204 处中文替换为 t() 调用:
- Monitor: 日志中心/告警中心/数据源/大屏/站点拨测/SNMP/中间件 全部转换
- Kubernetes: ResourceVisualEditor/NamespaceResourcePage/拓扑/事件 全部转换
- Deploy: 流水线/发布/凭证/RBAC 全部转换
- Server/Cloud/Agent/Task/Layout/UI: 全部转换
- 翻译词典扩展至 6474 行 (22 namespaces, 5000+ keys)
- tsc 编译零错误
This commit is contained in:
attacker committed 2026-07-03 01:51:57 +08:00
1 parent 78c27037e3
commit ecec73989b
166 files changed
+6925 -2800

No files matched your search

@@ -13,6 +13,7 @@ import { toast } from 'sonner';
import { useConfirm } from '@/components/ui/confirm-dialog';
import { deployApi } from '@/api';
import type { JsonData } from '@/types/common';
import { useTranslation } from 'react-i18next';
interface Group {
id: number; name: string; description: string;
@@ -23,6 +24,7 @@ interface GroupMember {
}
export default function UserGroupsManager({ embedded = false }: { embedded?: boolean }) {
const { t } = useTranslation();
const _confirm = useConfirm();
const [groups, setGroups] = useState<Group[]>([]);
const [loading, setLoading] = useState(true);
@@ -41,43 +43,43 @@ export default function UserGroupsManager({ embedded = false }: { embedded?: boo
const loadGroups = async () => {
setLoading(true);
try { const res = await deployApi.getGroups(); setGroups((res as JsonData)?.list || []); }
catch { toast.error('加载失败'); }
catch { toast.error(t('common.loadFailed')); }
finally { setLoading(false); }
};
useEffect(() => { loadGroups(); }, []);
const handleSave = async () => {
if (!formName.trim()) { toast.error('请输入组名'); return; }
if (!formName.trim()) { toast.error(t('deploy.rbac.groupPlaceholder')); return; }
setSaving(true);
try {
if (editId) await deployApi.updateGroup(editId, { name: formName, description: formDesc });
else await deployApi.createGroup({ name: formName, description: formDesc });
toast.success(editId ? '已更新' : '已创建');
toast.success(editId ? t('deploy.toast.updated') : t('deploy.toast.created'));
setFormOpen(false); loadGroups();
} catch { toast.error('操作失败'); }
} catch { toast.error(t('common.operationFailed')); }
finally { setSaving(false); }
};
const handleDelete = async (g: Group) => {
const ok = await _confirm({ title: '删除用户组', description: `确定删除「${g.name}」?所有成员和流水线授权将同时移除。`, variant: 'destructive' });
const ok = await _confirm({ title: t('deploy.rbac.deleteGroup'), description: t('deploy.usergroupsmanager.se76125', { g.name: g.name }), variant: 'destructive' });
if (!ok) return;
try { await deployApi.deleteGroup(g.id); toast.success('已删除'); loadGroups(); }
catch { toast.error('删除失败'); }
try { await deployApi.deleteGroup(g.id); toast.success(t('alert.deleted')); loadGroups(); }
catch { toast.error(t('common.deleteFailed')); }
};
const handleAddMember = async (groupId: number) => {
const username = (memberUsers[groupId] || '').trim();
if (!username) { toast.error('输入用户名'); return; }
try { await deployApi.addGroupMember(groupId, { username }); toast.success('已添加'); loadGroups(); setMemberUsers(prev => ({ ...prev, [groupId]: '' })); }
catch { toast.error('添加失败'); }
if (!username) { toast.error(t('pipeline.usernamePlaceholder')); return; }
try { await deployApi.addGroupMember(groupId, { username }); toast.success(t('deploy.toast.added')); loadGroups(); setMemberUsers(prev => ({ ...prev, [groupId]: '' })); }
catch { toast.error(t('deploy.toast.addFailed')); }
};
const handleRemoveMember = async (groupId: number, memberId: number, username: string) => {
const ok = await _confirm({ title: '移除成员', description: `确定从组中移除「${username}」?` });
const ok = await _confirm({ title: t('pipeline.removeMember'), description: t('deploy.usergroupsmanager.s9270e4', { username: username }) });
if (!ok) return;
try { await deployApi.removeGroupMember(groupId, memberId); toast.success('已移除'); loadGroups(); }
catch { toast.error('移除失败'); }
try { await deployApi.removeGroupMember(groupId, memberId); toast.success(t('deploy.rbac.removed')); loadGroups(); }
catch { toast.error(t('deploy.rbac.removeFail')); }
};
const toggleExpand = (gid: number) => setExpanded(p => ({ ...p, [gid]: !p[gid] }));
@@ -98,8 +100,8 @@ export default function UserGroupsManager({ embedded = false }: { embedded?: boo
const listBody = !loading && groups.length === 0 ? (
<PageEmpty
icon={<Users className="h-10 w-10" />}
title="暂无用户组"
description="点击「新建用户组」创建第一个用户组"
title=t('deploy.usergroupsmanager.sd1edd8')
description=t('deploy.usergroupsmanager.scf9865')
action={(
<Button size="sm" onClick={() => { setEditId(null); setFormName(''); setFormDesc(''); setFormOpen(true); }}>
<Plus className="w-4 h-4 mr-1" />新建用户组
@@ -115,7 +117,7 @@ export default function UserGroupsManager({ embedded = false }: { embedded?: boo
<Shield className="w-5 h-5 dg-text-blue" />
<div>
<div className="font-medium text-[var(--dg-text-primary)]">{g.name}</div>
<div className="text-xs text-[var(--dg-text-secondary)]">{g.description || '暂无描述'} · {(g.members || []).length} 位成员</div>
<div className="text-xs text-[var(--dg-text-secondary)]">{g.description || t('pipeline.desc2')} · {(g.members || []).length} 位成员</div>
</div>
</div>
<div className="flex items-center gap-2">
@@ -132,14 +134,14 @@ export default function UserGroupsManager({ embedded = false }: { embedded?: boo
<div className="border-t border-[var(--dg-border)] px-4 py-3 space-y-3">
{/* Add member */}
<div className="flex items-end gap-2">
<div className="flex-1 space-y-1"><Label className="text-xs">添加用户</Label>
<Input value={memberUsers[g.id] || ''} onChange={e => setMemberUsers(prev => ({ ...prev, [g.id]: e.target.value }))} placeholder="输入用户名" className="h-8 text-sm" onKeyDown={e => e.key === 'Enter' && handleAddMember(g.id)} />
<div className="flex-1 space-y-1"><Label className="text-xs">{t('system.addUser')}</Label>
<Input value={memberUsers[g.id] || ''} onChange={e => setMemberUsers(prev => ({ ...prev, [g.id]: e.target.value }))} placeholder=t('pipeline.usernamePlaceholder') className="h-8 text-sm" onKeyDown={e => e.key === 'Enter' && handleAddMember(g.id)} />
</div>
<Button size="sm" className="h-8" onClick={() => handleAddMember(g.id)}><UserPlus className="w-3.5 h-3.5 mr-1" />添加</Button>
<Button size="sm" className="h-8" onClick={() => handleAddMember(g.id)}><UserPlus className="w-3.5 h-3.5 mr-1" />{t('common.add')}</Button>
</div>
{/* Members list */}
{(g.members || []).length === 0 ? (
<div className="text-xs text-[var(--dg-text-secondary)] py-2">暂无成员</div>
<div className="text-xs text-[var(--dg-text-secondary)] py-2">{t('deploy.rbac.noMembers')}</div>
) : (
<div className="flex flex-wrap gap-2">
{(g.members || []).map(m => (
@@ -162,14 +164,14 @@ export default function UserGroupsManager({ embedded = false }: { embedded?: boo
const formDialog = (
<Dialog open={formOpen} onOpenChange={setFormOpen}>
<DialogContent>
<DialogHeader><DialogTitle>{editId ? '编辑用户组' : '新建用户组'}</DialogTitle></DialogHeader>
<DialogHeader><DialogTitle>{editId ? t('deploy.rbac.groupEditTitle') : t('pipeline.newGroup')}</DialogTitle></DialogHeader>
<div className="space-y-3">
<div className="space-y-1"><Label>组名</Label><Input value={formName} onChange={e => setFormName(e.target.value)} placeholder="例如: 后端开发组" /></div>
<div className="space-y-1"><Label>描述</Label><Input value={formDesc} onChange={e => setFormDesc(e.target.value)} placeholder="可选" /></div>
<div className="space-y-1"><Label>{t('monitor.groupName')}</Label><Input value={formName} onChange={e => setFormName(e.target.value)} placeholder=t('deploy.usergroupsmanager.s5a5632') /></div>
<div className="space-y-1"><Label>{t('common.description')}</Label><Input value={formDesc} onChange={e => setFormDesc(e.target.value)} placeholder=t('common.optional') /></div>
</div>
<div className="flex justify-end gap-2 mt-4 pt-4 border-t">
<Button variant="outline" onClick={() => setFormOpen(false)}>取消</Button>
<Button onClick={handleSave} disabled={saving}>{saving ? '...' : '保存'}</Button>
<Button variant="outline" onClick={() => setFormOpen(false)}>{t('common.cancel')}</Button>
<Button onClick={handleSave} disabled={saving}>{saving ? '...' : t('common.save')}</Button>
</div>
</DialogContent>
</Dialog>
@@ -188,15 +190,15 @@ export default function UserGroupsManager({ embedded = false }: { embedded?: boo
return (
<PageShell
variant="list"
title="应用发布"
subtitle="用户组 — 批量授权流水线访问权限"
title=t('menu.deploy')
subtitle=t('deploy.usergroupsmanager.sf80ecf')
icon={<Users className="h-5 w-5" />}
loading={loading}
metrics={(
<StatStrip
items={[
{ label: '用户组', value: groups.length, color: 'blue' },
{ label: '成员总数', value: memberCount, color: 'purple' },
{ label: t('pipeline.userGroup'), value: groups.length, color: 'blue' },
{ label: t('deploy.usergroupsmanager.sdf2b42'), value: memberCount, color: 'purple' },
]}
/>
)}