Files
OpenFlare/frontend/app/(main)/admin/demo/tabs/table-tab.tsx
T
ryan 5a8722ff07 feat(frontend): 控制台 next-intl 中英双语
接入无 URL 前缀的 zh-CN/en,顶栏与外观设置可切换语言;选择写入 cookie 后刷新生效。
2026-08-16 16:49:16 +08:00

263 lines
9.7 KiB
TypeScript

// Copyright 2026 Arctel.net
// SPDX-License-Identifier: Apache-2.0
'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';
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '@/components/ui/table';
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: t('mockData.syncExport'),
type: t('mockType.dataSync'),
status: 'success',
duration: '1.2s',
time: '2026-06-15 14:22',
},
{
id: 'TX-1003',
name: t('mockData.dbBackup'),
type: t('mockType.dbOps'),
status: 'running',
duration: t('mockDuration.running'),
time: '2026-06-15 15:00',
},
{
id: 'TX-1004',
name: t('mockData.s3Cleanup'),
type: t('mockType.diskCleanup'),
status: 'failed',
duration: '0.4s',
time: '2026-06-15 10:05',
},
];
return (
<div className='space-y-6'>
{/* 表格控制工具栏 */}
<div className='flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3'>
<div className='flex items-center gap-2'>
<div className='relative w-64'>
<Search className='absolute left-2.5 top-2.5 size-3 text-muted-foreground' />
<Input
placeholder={t('searchPlaceholder')}
className='h-8 pl-8 text-xs w-full shadow-none border-dashed bg-background'
/>
</div>
<Button
variant='outline'
size='sm'
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>
{/* 数据表格本身 */}
<div className='border border-dashed shadow-none rounded-lg overflow-hidden bg-background'>
<Table className='w-full caption-bottom text-sm min-w-full'>
<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>
<TableBody>
{mockTableData.map((row) => (
<TableRow
key={row.id}
className='border-dashed hover:bg-muted/10 transition-colors'
>
<TableCell className='font-mono text-xs font-semibold'>
{row.id}
</TableCell>
<TableCell className='text-xs font-medium text-foreground'>
{row.name}
</TableCell>
<TableCell className='text-xs text-muted-foreground'>
{row.type}
</TableCell>
<TableCell>
{row.status === 'success' && (
<Badge
variant='outline'
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' && (
<Badge
variant='outline'
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' && (
<Badge
variant='outline'
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>
<TableCell className='text-xs text-muted-foreground font-mono'>
{row.duration}
</TableCell>
<TableCell className='text-xs text-muted-foreground'>
{row.time}
</TableCell>
<TableCell className='text-right'>
<div className='flex items-center justify-end gap-1.5'>
<Button
variant='ghost'
size='icon'
className='h-6 w-6 rounded hover:bg-muted text-muted-foreground'
>
<Edit className='size-3' />
</Button>
<Button
variant='ghost'
size='icon'
className='h-6 w-6 rounded hover:bg-destructive/10 text-destructive'
>
<Trash2 className='size-3' />
</Button>
</div>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
{/* 表格规范指引 */}
<Card className='border-dashed shadow-none bg-muted/20'>
<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
</code>
。
</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>
{t('spec.monoFont')}
<code className='bg-muted px-1 py-0.5 rounded font-mono'>
font-mono text-xs
</code>
。
</li>
<li>
{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'>
{`<div className="border border-dashed shadow-none rounded-lg overflow-hidden bg-background">
<Table>
<TableHeader className="bg-muted/40">
<TableRow className="border-dashed hover:bg-transparent">
<TableHead className="text-xs font-semibold">编号</TableHead>
<TableHead className="text-xs font-semibold">状态</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow className="border-dashed hover:bg-muted/10 transition-colors">
<TableCell className="font-mono text-xs">ID-1001</TableCell>
<TableCell>
<Badge variant="outline" className="text-[10px] bg-emerald-500/10 border-emerald-500/20 text-emerald-600 rounded-full py-0 px-2">
<span className="size-1 bg-emerald-500 rounded-full mr-1.5 shrink-0" />
成功
</Badge>
</TableCell>
</TableRow>
</TableBody>
</Table>
</div>`}
</pre>
</CardContent>
</Card>
</div>
);
}