feat(i18n): Approval 审批模块全量国际化 — 11 文件硬编码中文改翻译键 + approval 命名空间(136 键)

迁移文件:
- pages/approval/: ApprovalWorkflowPage + ApprovalCategoryPage + 3 子页面(Resource/App/Permission)
- components/approval/: ApprovalFlow + ApprovalProcessTab + ApprovalCreateDialog + ApprovalDetailDialog + ApprovalTemplateTab + helpers

翻译键: approval 命名空间 136 键 (8 子组: category/step/status/col/editor/detail/flow/type/msg)
复用 common.* 通用键 (approve/reject/cancel/save/create/delete/edit/detail/close/loading 等)
zh-CN/en-US 完全对齐, 8 命名空间 (common/menu/header/login/dashboard/server/alert/approval)

模式: 组件内 useTranslation() + t(); 模块级常量/helpers 用 i18n.t()
labelKey 模式: STATUS_TABS/statusMap 从 label:string 改为 labelKey:string + i18n.t(config.labelKey)
This commit is contained in:
attacker committed 2026-06-29 18:25:29 +08:00
1 parent 61a1f32e64
commit fef4997391
13 files changed
+649 -292

No files matched your search

@@ -19,42 +19,44 @@ import {
getApprovalTypeIcon,
getInstanceType,
} from './helpers';
import i18n from 'i18next';
import { useTranslation } from 'react-i18next';
import type { JsonData } from '@/types/common';
// 状态标签页定义
const STATUS_TABS = [
{ key: 'all', label: '全部', value: '' },
{ key: 'pending', label: '待审批', value: 'pending' },
{ key: 'approved', label: '已通过', value: 'approved' },
{ key: 'rejected', label: '已拒绝', value: 'rejected' },
{ key: 'processing', label: '进行中', value: 'processing' },
{ key: 'completed', label: '已完成', value: 'completed' },
{ key: 'all', labelKey: 'common.all', value: '' },
{ key: 'pending', labelKey: 'approval.status.pending', value: 'pending' },
{ key: 'approved', labelKey: 'approval.status.approved', value: 'approved' },
{ key: 'rejected', labelKey: 'approval.status.rejected', value: 'rejected' },
{ key: 'processing', labelKey: 'approval.status.pending', value: 'processing' },
{ key: 'completed', labelKey: 'common.completed', value: 'completed' },
];
function getStatusBadge(status: string) {
const statusMap: Record<string, { label: string; className: string; dot: string }> = {
const statusMap: Record<string, { labelKey: string; className: string; dot: string }> = {
pending: {
label: '待审批',
labelKey: 'approval.status.pending',
className: 'border-amber-500/30 text-amber-400 bg-amber-500/10',
dot: 'bg-amber-400',
},
approved: {
label: '已通过',
labelKey: 'approval.status.approved',
className: 'border-emerald-500/30 text-emerald-400 bg-emerald-500/10',
dot: 'bg-emerald-400',
},
rejected: {
label: '已拒绝',
labelKey: 'approval.status.rejected',
className: 'border-red-500/30 text-red-400 bg-red-500/10',
dot: 'bg-red-400',
},
processing: {
label: '进行中',
labelKey: 'approval.status.pending',
className: 'border-[var(--dg-blue)]/30 text-[var(--dg-blue)] bg-[var(--dg-blue)]/10',
dot: 'bg-[var(--dg-blue)]',
},
completed: {
label: '已完成',
labelKey: 'common.completed',
className: 'border-[var(--dg-border)] text-[var(--dg-text-secondary)] bg-[var(--dg-bg-tertiary)]',
dot: 'bg-[var(--dg-text-secondary)]',
},
@@ -64,7 +66,7 @@ function getStatusBadge(status: string) {
return (
<Badge variant="outline" className={config.className}>
<div className={cn('w-1.5 h-1.5 rounded-full mr-1.5', config.dot)} />
{config.label}
{i18n.t(config.labelKey)}
</Badge>
);
}
@@ -93,6 +95,7 @@ export function ApprovalProcessTab({
onApprove,
onReject,
}: ApprovalProcessTabProps) {
const { t } = useTranslation();
return (
<>
{/* 搜索 + 状态筛选 */}
@@ -100,7 +103,7 @@ export function ApprovalProcessTab({
<div className="relative w-72">
<Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-[var(--dg-text-muted)]" />
<Input
placeholder="搜索标题/申请人..."
placeholder={t('approval.flow.searchPlaceholder')}
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="pl-9 h-9 bg-[var(--dg-bg-tertiary)] border-[var(--dg-border)] text-[var(--dg-text-primary)] placeholder:text-[var(--dg-text-muted)]"
@@ -118,7 +121,7 @@ export function ApprovalProcessTab({
: 'text-[var(--dg-text-secondary)] hover:text-[var(--dg-text-primary)]'
)}
>
{tab.label}
{t(tab.labelKey)}
</button>
))}
</div>
@@ -130,7 +133,7 @@ export function ApprovalProcessTab({
<CardContent className="p-12">
<div className="flex items-center justify-center text-[var(--dg-text-muted)]">
<Loader2 className="h-6 w-6 animate-spin mr-2" />
加载中...
{t('common.loading')}
</div>
</CardContent>
</Card>
@@ -139,8 +142,8 @@ export function ApprovalProcessTab({
<CardContent className="p-12">
<div className="text-center">
<FileText className="h-12 w-12 mx-auto text-[var(--dg-text-muted)] mb-4" />
<h3 className="text-lg font-medium text-[var(--dg-text-secondary)] mb-2">暂无审批流程</h3>
<p className="text-sm text-[var(--dg-text-muted)]">当前筛选条件下没有匹配的流程实例</p>
<h3 className="text-lg font-medium text-[var(--dg-text-secondary)] mb-2">{t('approval.noInstances')}</h3>
<p className="text-sm text-[var(--dg-text-muted)]">{t('approval.noInstancesDesc')}</p>
</div>
</CardContent>
</Card>
@@ -168,15 +171,15 @@ export function ApprovalProcessTab({
{getApprovalTypeLabel(getInstanceType(instance))}
</Badge>
</span>
<span>申请人:{instance.applicant_name || instance.applicant || '--'}</span>
<span>提交于 {instance.created_at ? new Date(instance.created_at).toLocaleString() : '--'}</span>
<span>{t('approval.detail.applicant')}: {instance.applicant_name || instance.applicant || '--'}</span>
<span>{t('approval.detail.submittedAt')} {instance.created_at ? new Date(instance.created_at).toLocaleString() : '--'}</span>
</div>
</div>
</div>
<div className="flex items-center gap-2">
<Button variant="ghost" size="sm" className="text-[var(--dg-text-secondary)] hover:text-[var(--dg-text-primary)]" onClick={() => onView(instance)}>
<Eye className="h-4 w-4 mr-1" />
详情
{t('common.detail')}
</Button>
{instance.status === 'pending' && (
<>
@@ -187,7 +190,7 @@ export function ApprovalProcessTab({
onClick={() => onApprove(instance)}
>
<CheckCircle2 className="h-4 w-4 mr-1" />
通过
{t('common.approve')}
</Button>
<Button
variant="outline"
@@ -196,16 +199,16 @@ export function ApprovalProcessTab({
onClick={() => onReject(instance)}
>
<XCircle className="h-4 w-4 mr-1" />
拒绝
{t('common.reject')}
</Button>
</>
)}
</div>
</div>
{/* 审批进度条 */}
{/* {t('approval.detail.approvalProgress')}条 */}
<div className="mb-3">
<div className="flex items-center justify-between text-xs text-[var(--dg-text-muted)] mb-1.5">
<span>审批进度</span>
<span>{t('approval.detail.approvalProgress')}</span>
<span>{percentage}%</span>
</div>
<div className="w-full h-1.5 bg-[var(--dg-bg-tertiary)] rounded-full overflow-hidden">