// ============================================================
// 仪表盘页面
// ============================================================
import { useQuery } from '@tanstack/react-query'
import { Card, Col, Row, Statistic, Table, Tag, Spin } from 'antd'
import {
TeamOutlined,
CloudServerOutlined,
ApiOutlined,
ThunderboltOutlined,
ColumnWidthOutlined,
} from '@ant-design/icons'
import { statsService } from '@/services/stats'
import { logService } from '@/services/logs'
import { PageHeader } from '@/components/PageHeader'
import { ErrorState } from '@/components/ErrorState'
import { actionLabels, actionColors } from '@/constants/status'
import type { OperationLog } from '@/types'
export default function Dashboard() {
const {
data: stats,
isLoading: statsLoading,
error: statsError,
refetch: refetchStats,
} = useQuery({
queryKey: ['dashboard-stats'],
queryFn: ({ signal }) => statsService.dashboard(signal),
})
const { data: logsData, isLoading: logsLoading } = useQuery({
queryKey: ['recent-logs'],
queryFn: ({ signal }) => logService.list({ page: 1, page_size: 10 }, signal),
})
if (statsError) {
return (
<>
refetchStats()}
/>
>
)
}
const statCards = [
{ title: '总账号', value: stats?.total_accounts ?? 0, icon: , color: '#863bff' },
{ title: '活跃服务商', value: stats?.active_providers ?? 0, icon: , color: '#47bfff' },
{ title: '活跃模型', value: stats?.active_models ?? 0, icon: , color: '#22c55e' },
{ title: '今日请求', value: stats?.tasks_today ?? 0, icon: , color: '#f59e0b' },
{
title: '今日 Token',
value: (stats?.tokens_today_input ?? 0) + (stats?.tokens_today_output ?? 0),
icon: ,
color: '#ef4444',
},
]
const logColumns = [
{
title: '操作类型',
dataIndex: 'action',
key: 'action',
width: 140,
render: (action: string) => (
{actionLabels[action] || action}
),
},
{
title: '目标类型',
dataIndex: 'target_type',
key: 'target_type',
width: 100,
render: (v: string | null) => v || '-',
},
{
title: '时间',
dataIndex: 'created_at',
key: 'created_at',
width: 180,
render: (v: string) => new Date(v).toLocaleString('zh-CN'),
},
]
return (
{/* Stat Cards */}
{statsLoading ? (
) : (
statCards.map((card) => (
{card.title}
}
value={card.value}
valueStyle={{ fontSize: 28, fontWeight: 600, color: card.color }}
prefix={
{card.icon}
}
/>
))
)}
{/* Recent Logs */}
最近操作日志
}
size="small"
styles={{ body: { padding: 0 } }}
>
columns={logColumns}
dataSource={logsData?.items ?? []}
loading={logsLoading}
rowKey="id"
pagination={false}
size="small"
/>
)
}