feat(frontend): 控制台 next-intl 中英双语

接入无 URL 前缀的 zh-CN/en,顶栏与外观设置可切换语言;选择写入 cookie 后刷新生效。
This commit is contained in:
ryan
2026-08-16 16:49:16 +08:00
parent 64fbaa7ef1
commit 5a8722ff07
219 changed files with 21437 additions and 5212 deletions
@@ -4,6 +4,7 @@
'use client';
import * as React from 'react';
import { useTranslations } from 'next-intl';
import { Code, Edit, ListFilter, Plus, Search, Trash2 } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
@@ -19,27 +20,28 @@ import { Badge } from '@/components/ui/badge';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
export function TableTab() {
const t = useTranslations('admin.demo.table');
const mockTableData = [
{
id: 'TX-1002',
name: '用户信息批量同步导出',
type: '数据同步',
name: t('mockData.syncExport'),
type: t('mockType.dataSync'),
status: 'success',
duration: '1.2s',
time: '2026-06-15 14:22',
},
{
id: 'TX-1003',
name: '系统数据库每周自动备份归档',
type: '数据库运维',
name: t('mockData.dbBackup'),
type: t('mockType.dbOps'),
status: 'running',
duration: '在执行中',
duration: t('mockDuration.running'),
time: '2026-06-15 15:00',
},
{
id: 'TX-1004',
name: '远端S3过期缓存对象自动清理任务',
type: '磁盘清理',
name: t('mockData.s3Cleanup'),
type: t('mockType.diskCleanup'),
status: 'failed',
duration: '0.4s',
time: '2026-06-15 10:05',
@@ -54,7 +56,7 @@ export function TableTab() {
<div className='relative w-64'>
<Search className='absolute left-2.5 top-2.5 size-3 text-muted-foreground' />
<Input
placeholder='输入任务名称搜索...'
placeholder={t('searchPlaceholder')}
className='h-8 pl-8 text-xs w-full shadow-none border-dashed bg-background'
/>
</div>
@@ -64,12 +66,12 @@ export function TableTab() {
className='h-8 border-dashed text-xs shadow-none'
>
<ListFilter className='size-3 mr-1' />
过滤
{t('filter')}
</Button>
</div>
<Button size='sm' className='h-8 text-xs shadow-none'>
<Plus className='size-3.5 mr-1' />
新建任务
{t('newTask')}
</Button>
</div>
@@ -79,25 +81,25 @@ export function TableTab() {
<TableHeader className='bg-muted/40'>
<TableRow className='border-dashed hover:bg-transparent'>
<TableHead className='w-[100px] text-xs font-semibold'>
任务编号
{t('columns.taskId')}
</TableHead>
<TableHead className='text-xs font-semibold'>
执行任务名称
{t('columns.taskName')}
</TableHead>
<TableHead className='w-[120px] text-xs font-semibold'>
任务类型
{t('columns.taskType')}
</TableHead>
<TableHead className='w-[100px] text-xs font-semibold'>
状态
{t('columns.status')}
</TableHead>
<TableHead className='w-[100px] text-xs font-semibold'>
执行耗时
{t('columns.duration')}
</TableHead>
<TableHead className='w-[150px] text-xs font-semibold'>
触发时间
{t('columns.triggerTime')}
</TableHead>
<TableHead className='w-[80px] text-xs font-semibold text-right'>
操作
{t('columns.actions')}
</TableHead>
</TableRow>
</TableHeader>
@@ -123,7 +125,7 @@ export function TableTab() {
className='text-[10px] bg-emerald-500/10 border-emerald-500/20 text-emerald-600 rounded-full py-0 px-2 font-medium'
>
<span className='size-1 bg-emerald-500 rounded-full mr-1.5 shrink-0' />
成功
{t('status.success')}
</Badge>
)}
{row.status === 'running' && (
@@ -132,7 +134,7 @@ export function TableTab() {
className='text-[10px] bg-blue-500/10 border-blue-500/20 text-blue-600 rounded-full py-0 px-2 font-medium'
>
<span className='size-1 bg-blue-500 rounded-full mr-1.5 shrink-0 animate-pulse' />
运行中
{t('status.running')}
</Badge>
)}
{row.status === 'failed' && (
@@ -141,7 +143,7 @@ export function TableTab() {
className='text-[10px] bg-destructive/10 border-destructive/20 text-destructive rounded-full py-0 px-2 font-medium'
>
<span className='size-1 bg-destructive rounded-full mr-1.5 shrink-0' />
失败
{t('status.failed')}
</Badge>
)}
</TableCell>
@@ -180,13 +182,13 @@ export function TableTab() {
<CardHeader className='pb-3'>
<CardTitle className='text-sm font-semibold flex items-center gap-1.5'>
<Code className='size-4 text-primary' />
表格设计规范与代码模板
{t('tableDesignSpec')}
</CardTitle>
</CardHeader>
<CardContent className='space-y-4'>
<ul className='list-disc pl-4 text-xs text-muted-foreground space-y-1.5'>
<li>
表格容器必须统一使用带有虚线边框的容器,即类名:
{t('spec.container')}
<code className='bg-muted px-1 py-0.5 rounded font-mono'>
border border-dashed shadow-none rounded-lg overflow-hidden
bg-background
@@ -194,40 +196,40 @@ export function TableTab() {
。
</li>
<li>
表头背景设为{' '}
{t('spec.headerBg')}
<code className='bg-muted px-1 py-0.5 rounded font-mono'>
bg-muted/40
</code>
。表头表项字号统一为小字粗体{' '}
{t('spec.headerStyle')}
<code className='bg-muted px-1 py-0.5 rounded font-mono'>
text-xs font-semibold
</code>
。
</li>
<li>
单元格行与列之间使用虚线分割(
{t('spec.cellDivider')}
<code className='bg-muted px-1 py-0.5 rounded font-mono'>
border-dashed
</code>
)。表格行悬浮交互采用温和过渡色{' '}
{t('spec.rowHover')}
<code className='bg-muted px-1 py-0.5 rounded font-mono'>
hover:bg-muted/10 transition-colors
</code>
。
</li>
<li>
编码、主键或唯一 ID 类字段一律采用等宽字体呈现:
{t('spec.monoFont')}
<code className='bg-muted px-1 py-0.5 rounded font-mono'>
font-mono text-xs
</code>
。
</li>
<li>
状态标签(Badge)尽量圆角化(
{t('spec.badgeStyle')}
<code className='bg-muted px-1 py-0.5 rounded font-mono'>
rounded-full py-0 px-2
</code>
),并以浅背景配以各自对应的图标圆点,以实现现代、高对比度的视觉质感。
{t('spec.badgeStyle2')}
</li>
</ul>
<pre className='text-[11px] font-mono text-muted-foreground overflow-x-auto p-3 bg-background rounded border border-border/40 leading-relaxed'>