- 新增批量导出功能,支持text模式导出账户数据 - 添加导出弹窗,支持文本全选和文件下载 - 移动刷新按钮到全局位置,统一刷新账户和统计数据 - 在统计卡片中将已导出状态计入可用账户 - 创建自定义确认对话框替换系统confirm弹窗 - 统一按钮尺寸,修复刷新和上传按钮大小不一致 - 添加已导出状态的中文映射和样式 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
		
			
				
	
	
		
			97 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			97 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| "use client";
 | |
| 
 | |
| import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
 | |
| import { Database, TrendingUp, Users, Activity } from 'lucide-react';
 | |
| import { StatsOverview } from '@/lib/types';
 | |
| 
 | |
| interface StatsCardsProps {
 | |
|   stats: StatsOverview | null;
 | |
|   loading?: boolean;
 | |
| }
 | |
| 
 | |
| export function StatsCards({ stats, loading }: StatsCardsProps) {
 | |
|   if (loading) {
 | |
|     return (
 | |
|       <div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
 | |
|         {Array.from({ length: 4 }).map((_, i) => (
 | |
|           <Card key={i}>
 | |
|             <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
 | |
|               <CardTitle className="text-sm font-medium">加载中...</CardTitle>
 | |
|             </CardHeader>
 | |
|             <CardContent>
 | |
|               <div className="text-2xl font-bold">--</div>
 | |
|             </CardContent>
 | |
|           </Card>
 | |
|         ))}
 | |
|       </div>
 | |
|     );
 | |
|   }
 | |
| 
 | |
|   if (!stats) {
 | |
|     return null;
 | |
|   }
 | |
| 
 | |
|   return (
 | |
|     <div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
 | |
|       <Card>
 | |
|         <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
 | |
|           <CardTitle className="text-sm font-medium">总账户数</CardTitle>
 | |
|           <Database className="h-4 w-4 text-muted-foreground" />
 | |
|         </CardHeader>
 | |
|         <CardContent>
 | |
|           <div className="text-2xl font-bold">{stats.totalAccounts}</div>
 | |
|         </CardContent>
 | |
|       </Card>
 | |
|       
 | |
|       <Card>
 | |
|         <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
 | |
|           <CardTitle className="text-sm font-medium">平台数量</CardTitle>
 | |
|           <TrendingUp className="h-4 w-4 text-muted-foreground" />
 | |
|         </CardHeader>
 | |
|         <CardContent>
 | |
|           <div className="text-2xl font-bold">{Object.keys(stats.platformSummary).length}</div>
 | |
|           <p className="text-xs text-muted-foreground">
 | |
|             {Object.entries(stats.platformSummary).slice(0, 3).map(([platform, count]) => (
 | |
|               `${platform}: ${count}`
 | |
|             )).join(', ')}
 | |
|           </p>
 | |
|         </CardContent>
 | |
|       </Card>
 | |
|       
 | |
|       <Card>
 | |
|         <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
 | |
|           <CardTitle className="text-sm font-medium">所有者数量</CardTitle>
 | |
|           <Users className="h-4 w-4 text-muted-foreground" />
 | |
|         </CardHeader>
 | |
|         <CardContent>
 | |
|           <div className="text-2xl font-bold">{Object.keys(stats.ownerSummary).length}</div>
 | |
|           <p className="text-xs text-muted-foreground">
 | |
|             {Object.entries(stats.ownerSummary).slice(0, 3).map(([owner, count]) => (
 | |
|               `${owner}: ${count}`
 | |
|             )).join(', ')}
 | |
|           </p>
 | |
|         </CardContent>
 | |
|       </Card>
 | |
|       
 | |
|       <Card>
 | |
|         <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
 | |
|           <CardTitle className="text-sm font-medium">可用账户</CardTitle>
 | |
|           <Activity className="h-4 w-4 text-muted-foreground" />
 | |
|         </CardHeader>
 | |
|         <CardContent>
 | |
|           <div className="text-2xl font-bold text-green-600">
 | |
|             {(stats.statusSummary.available || 0) + (stats.statusSummary.exported || 0)}
 | |
|           </div>
 | |
|           <p className="text-xs text-muted-foreground">
 | |
|             可用: {stats.statusSummary.available || 0} | 
 | |
|             已导出: {stats.statusSummary.exported || 0}
 | |
|           </p>
 | |
|           <p className="text-xs text-muted-foreground">
 | |
|             已锁定: {stats.statusSummary.locked || 0} | 
 | |
|             已封禁: {stats.statusSummary.banned || 0}
 | |
|           </p>
 | |
|         </CardContent>
 | |
|       </Card>
 | |
|     </div>
 | |
|   );
 | |
| } |