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:
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">
|
||||
|
||||
Reference in new issue
Block a user