import { useState, useEffect } from 'react'; import { useRouter } from 'next/router'; import { UserGroupIcon, PhoneIcon, DocumentTextIcon, CurrencyDollarIcon, ChartBarIcon, ClockIcon, CheckCircleIcon, ExclamationTriangleIcon, ArrowUpIcon, ArrowDownIcon, EyeIcon, PencilIcon, TrashIcon, PlayIcon, PauseIcon, StopIcon, MicrophoneIcon, VideoCameraIcon, GlobeAltIcon, BellIcon, CogIcon, UserIcon, BuildingOfficeIcon, CalendarDaysIcon, ChatBubbleLeftRightIcon, BanknotesIcon, UsersIcon, LanguageIcon, DocumentDuplicateIcon, InboxIcon, PhoneArrowUpRightIcon, PhoneArrowDownLeftIcon, TrophyIcon, StarIcon, HeartIcon, FireIcon, LightBulbIcon, ShieldCheckIcon, SparklesIcon, RocketLaunchIcon, MegaphoneIcon, GiftIcon, AcademicCapIcon, MapIcon, SunIcon, MoonIcon, ComputerDesktopIcon, } from '@heroicons/react/24/outline'; import { CheckCircleIcon as CheckCircleIconSolid, ExclamationTriangleIcon as ExclamationTriangleIconSolid, ClockIcon as ClockIconSolid, XCircleIcon as XCircleIconSolid, UserGroupIcon as UserGroupIconSolid, PhoneIcon as PhoneIconSolid, DocumentTextIcon as DocumentTextIconSolid, CurrencyDollarIcon as CurrencyDollarIconSolid, ChartBarIcon as ChartBarIconSolid, BellIcon as BellIconSolid, StarIcon as StarIconSolid, HeartIcon as HeartIconSolid, FireIcon as FireIconSolid, TrophyIcon as TrophyIconSolid, SparklesIcon as SparklesIconSolid, RocketLaunchIcon as RocketLaunchIconSolid, GiftIcon as GiftIconSolid, AcademicCapIcon as AcademicCapIconSolid, ShieldCheckIcon as ShieldCheckIconSolid, LightBulbIcon as LightBulbIconSolid, MegaphoneIcon as MegaphoneIconSolid, MapIcon as MapIconSolid, SunIcon as SunIconSolid, MoonIcon as MoonIconSolid, ComputerDesktopIcon as ComputerDesktopIconSolid, } from '@heroicons/react/24/solid'; import { toast } from 'react-hot-toast'; import { statsAPI } from '../../lib/api-service'; interface DashboardStats { totalUsers: number; totalInterpreters: number; totalOrders: number; totalCalls: number; activeUsers: number; activeCalls: number; recentOrders: any[]; recentCalls: any[]; } interface RecentActivity { id: string; type: 'order' | 'call' | 'user' | 'interpreter'; title: string; description: string; time: string; status: 'success' | 'warning' | 'error' | 'info'; icon: any; } export default function Dashboard() { const router = useRouter(); const [stats, setStats] = useState({ totalUsers: 0, totalInterpreters: 0, totalOrders: 0, totalCalls: 0, activeUsers: 0, activeCalls: 0, recentOrders: [], recentCalls: [] }); const [loading, setLoading] = useState(true); const [recentActivity, setRecentActivity] = useState([]); useEffect(() => { loadDashboardData(); }, []); const loadDashboardData = async () => { try { setLoading(true); const dashboardStats = await statsAPI.getDashboardStats(); setStats(dashboardStats); // 生成最近活动记录 const activities: RecentActivity[] = []; // 添加最近订单活动 dashboardStats.recentOrders.forEach((order: any) => { activities.push({ id: order.id, type: 'order', title: `订单 ${order.order_number}`, description: `${order.user_name} - ${order.service_name}`, time: formatTime(order.created_at), status: getOrderStatus(order.status), icon: getOrderIcon(order.service_type) }); }); // 添加最近通话活动 dashboardStats.recentCalls.forEach((call: any) => { activities.push({ id: call.id, type: 'call', title: `${call.service_type === 'phone' ? '电话' : '视频'}通话`, description: `${call.users?.name || '用户'} - ${call.interpreters?.name || '翻译员'}`, time: formatTime(call.created_at), status: getCallStatus(call.status), icon: call.service_type === 'phone' ? PhoneIcon : VideoCameraIcon }); }); // 按时间排序 activities.sort((a, b) => new Date(b.time).getTime() - new Date(a.time).getTime()); setRecentActivity(activities.slice(0, 10)); } catch (error) { console.error('加载仪表盘数据失败:', error); toast.error('加载仪表盘数据失败'); } finally { setLoading(false); } }; const getOrderStatus = (status: string) => { switch (status) { case 'completed': return 'success'; case 'cancelled': return 'error'; case 'in_progress': return 'warning'; default: return 'info'; } }; const getCallStatus = (status: string) => { switch (status) { case 'ended': return 'success'; case 'cancelled': return 'error'; case 'connected': return 'warning'; default: return 'info'; } }; const getOrderIcon = (serviceType: string) => { switch (serviceType) { case 'phone': return PhoneIcon; case 'video': return VideoCameraIcon; case 'document': return DocumentTextIcon; default: return LanguageIcon; } }; const formatTime = (dateString: string) => { const date = new Date(dateString); const now = new Date(); const diff = now.getTime() - date.getTime(); const minutes = Math.floor(diff / 60000); const hours = Math.floor(minutes / 60); const days = Math.floor(hours / 24); if (days > 0) return `${days}天前`; if (hours > 0) return `${hours}小时前`; if (minutes > 0) return `${minutes}分钟前`; return '刚刚'; }; const formatCurrency = (amount: number) => { return new Intl.NumberFormat('zh-CN', { style: 'currency', currency: 'CNY' }).format(amount); }; const getStatusColor = (status: string) => { switch (status) { case 'success': return 'text-green-600 bg-green-50'; case 'warning': return 'text-yellow-600 bg-yellow-50'; case 'error': return 'text-red-600 bg-red-50'; default: return 'text-blue-600 bg-blue-50'; } }; const getStatusIcon = (status: string) => { switch (status) { case 'success': return CheckCircleIconSolid; case 'warning': return ExclamationTriangleIconSolid; case 'error': return XCircleIconSolid; default: return ClockIconSolid; } }; if (loading) { return (

加载中...

); } return (
{/* Header */}

仪表盘

欢迎回来,管理员

{/* Stats Cards */}
总用户数
{stats.totalUsers.toLocaleString()}
{stats.activeUsers} 活跃用户
翻译员总数
{stats.totalInterpreters.toLocaleString()}
在线翻译员
总订单数
{stats.totalOrders.toLocaleString()}
本月新增
总通话数
{stats.totalCalls.toLocaleString()}
{stats.activeCalls} 进行中
{/* Main Content */}
{/* Recent Activity */}

最近活动

{recentActivity.length === 0 ? (

暂无活动记录

) : ( recentActivity.map((activity) => { const StatusIcon = getStatusIcon(activity.status); const ActivityIcon = activity.icon; return (

{activity.title}

{activity.time}

{activity.description}

); }) )}
{/* Quick Actions */}

快速操作

); }