171 lines
6.3 KiB
TypeScript
171 lines
6.3 KiB
TypeScript
'use client';
|
|
|
|
import Link from 'next/link';
|
|
import {
|
|
Table,
|
|
TableBody,
|
|
TableCell,
|
|
TableHead,
|
|
TableHeader,
|
|
TableRow,
|
|
} from '@/components/ui/table';
|
|
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
|
import { Badge } from '@/components/ui/badge';
|
|
import { Skeleton } from '@/components/ui/skeleton';
|
|
import { Button } from '@/components/ui/button';
|
|
import { formatDecimal } from '@/lib/utils/format';
|
|
import { getAccountDisplayInfo, type SystemAccount } from '@/types/system-account';
|
|
import { getRegionDisplayName } from '@/lib/constants/region-codes';
|
|
import { formatDistanceToNow } from 'date-fns';
|
|
import { zhCN } from 'date-fns/locale';
|
|
import { FileText } from 'lucide-react';
|
|
|
|
interface AccountsTableProps {
|
|
title: string;
|
|
accounts: SystemAccount[];
|
|
isLoading?: boolean;
|
|
showSyncInfo?: boolean;
|
|
showMiningData?: boolean;
|
|
}
|
|
|
|
export function AccountsTable({
|
|
title,
|
|
accounts,
|
|
isLoading = false,
|
|
showSyncInfo = false,
|
|
showMiningData = true,
|
|
}: AccountsTableProps) {
|
|
// 计算列数
|
|
const getColumnCount = () => {
|
|
let count = 5; // 基础列: 类型, 名称, 算力, 来源, 操作
|
|
if (showMiningData) count += 1; // 已挖积分股
|
|
if (showSyncInfo) count += 1; // 同步时间
|
|
return count;
|
|
};
|
|
|
|
return (
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle className="text-lg flex items-center gap-2">
|
|
{title}
|
|
{accounts.length > 0 && (
|
|
<Badge variant="secondary" className="text-xs">
|
|
{accounts.length} 个账户
|
|
</Badge>
|
|
)}
|
|
</CardTitle>
|
|
</CardHeader>
|
|
<CardContent className="p-0">
|
|
<Table>
|
|
<TableHeader>
|
|
<TableRow>
|
|
<TableHead className="w-[180px]">账户类型</TableHead>
|
|
<TableHead>账户名称</TableHead>
|
|
<TableHead className="text-right">算力</TableHead>
|
|
{showMiningData && (
|
|
<TableHead className="text-right">已挖积分股</TableHead>
|
|
)}
|
|
<TableHead>来源</TableHead>
|
|
{showSyncInfo && <TableHead>同步时间</TableHead>}
|
|
<TableHead className="w-[100px]">操作</TableHead>
|
|
</TableRow>
|
|
</TableHeader>
|
|
<TableBody>
|
|
{isLoading ? (
|
|
[...Array(3)].map((_, i) => (
|
|
<TableRow key={i}>
|
|
{[...Array(getColumnCount())].map((_, j) => (
|
|
<TableCell key={j}>
|
|
<Skeleton className="h-4 w-full" />
|
|
</TableCell>
|
|
))}
|
|
</TableRow>
|
|
))
|
|
) : accounts.length === 0 ? (
|
|
<TableRow>
|
|
<TableCell
|
|
colSpan={getColumnCount()}
|
|
className="text-center text-muted-foreground py-8"
|
|
>
|
|
暂无数据
|
|
</TableCell>
|
|
</TableRow>
|
|
) : (
|
|
accounts.map((account) => {
|
|
const displayInfo = getAccountDisplayInfo(account.accountType);
|
|
const contribution = account.contributionBalance || account.totalContribution || '0';
|
|
const totalMined = account.totalMined || '0';
|
|
|
|
// 使用前端区域代码映射获取显示名称
|
|
const displayName = account.regionCode
|
|
? getRegionDisplayName(account.regionCode, account.accountType)
|
|
: (account.name || displayInfo.label);
|
|
|
|
return (
|
|
<TableRow key={account.accountType + (account.regionCode || '')}>
|
|
<TableCell>
|
|
<div className="flex items-center gap-2">
|
|
<span
|
|
className={`inline-block w-2 h-2 rounded-full ${displayInfo.color.replace('text-', 'bg-')}`}
|
|
/>
|
|
<code className="text-xs bg-muted px-1.5 py-0.5 rounded">
|
|
{account.accountType}
|
|
{account.regionCode && `_${account.regionCode}`}
|
|
</code>
|
|
</div>
|
|
</TableCell>
|
|
<TableCell className="font-medium">
|
|
{displayName}
|
|
</TableCell>
|
|
<TableCell className="text-right font-mono">
|
|
{formatDecimal(contribution, 8)}
|
|
{account.contributionNeverExpires && (
|
|
<Badge variant="outline" className="ml-2 text-xs">
|
|
永久
|
|
</Badge>
|
|
)}
|
|
</TableCell>
|
|
{showMiningData && (
|
|
<TableCell className="text-right font-mono">
|
|
<span className={Number(totalMined) > 0 ? 'text-green-600' : 'text-muted-foreground'}>
|
|
{formatDecimal(totalMined, 8)}
|
|
</span>
|
|
</TableCell>
|
|
)}
|
|
<TableCell>
|
|
<Badge
|
|
variant={account.source === 'synced' ? 'default' : 'secondary'}
|
|
className="text-xs"
|
|
>
|
|
{account.source === 'synced' ? 'CDC同步' : '本地'}
|
|
</Badge>
|
|
</TableCell>
|
|
{showSyncInfo && (
|
|
<TableCell className="text-muted-foreground text-sm">
|
|
{account.syncedAt
|
|
? formatDistanceToNow(new Date(account.syncedAt), {
|
|
addSuffix: true,
|
|
locale: zhCN,
|
|
})
|
|
: '-'}
|
|
</TableCell>
|
|
)}
|
|
<TableCell>
|
|
<Link href={`/system-accounts/${account.accountType}`}>
|
|
<Button variant="ghost" size="sm" className="h-8 px-2">
|
|
<FileText className="h-4 w-4 mr-1" />
|
|
分类账
|
|
</Button>
|
|
</Link>
|
|
</TableCell>
|
|
</TableRow>
|
|
);
|
|
})
|
|
)}
|
|
</TableBody>
|
|
</Table>
|
|
</CardContent>
|
|
</Card>
|
|
);
|
|
}
|