1
0
Files
nex/frontend/src/pages/Stats/StatsTable.tsx

117 lines
3.1 KiB
TypeScript

import { useMemo } from 'react'
import { Table, Select, Input, DateRangePicker, Space, Card } from 'tdesign-react'
import type { UsageStats, Provider } from '@/types'
import type { PrimaryTableCol } from 'tdesign-react/es/table/type'
interface StatsTableProps {
providers: Provider[]
stats: UsageStats[]
loading: boolean
providerId?: string
modelName?: string
dateRange: [Date | null, Date | null] | null
onProviderIdChange: (value: string | undefined) => void
onModelNameChange: (value: string | undefined) => void
onDateRangeChange: (dates: [Date | null, Date | null] | null) => void
}
export function StatsTable({
providers,
stats,
loading,
providerId,
modelName,
dateRange,
onProviderIdChange,
onModelNameChange,
onDateRangeChange,
}: StatsTableProps) {
const providerMap = useMemo(() => {
const map = new Map<string, string>()
for (const p of providers) {
map.set(p.id, p.name)
}
return map
}, [providers])
const columns: PrimaryTableCol<UsageStats>[] = [
{
title: '供应商',
colKey: 'providerId',
width: 180,
ellipsis: true,
cell: ({ row }) => providerMap.get(row.providerId) ?? row.providerId,
},
{
title: '模型',
colKey: 'modelName',
width: 250,
ellipsis: true,
cell: ({ row }) => {
// 如果后端返回统一 ID 格式(包含 /),直接显示
// 否则显示原始 model_name
return row.modelName
},
},
{
title: '日期',
colKey: 'date',
width: 120,
},
{
title: '请求数',
colKey: 'requestCount',
width: 100,
align: 'right',
},
]
const handleDateChange = (value: unknown) => {
if (Array.isArray(value) && value.length === 2) {
// 将值转换为Date对象
const startDate = value[0] ? new Date(value[0] as string | number | Date) : null
const endDate = value[1] ? new Date(value[1] as string | number | Date) : null
onDateRangeChange([startDate, endDate])
} else {
onDateRangeChange(null)
}
}
return (
<Card title='统计数据' headerBordered hoverShadow>
<Space style={{ marginBottom: 16 }} size='medium' breakLine>
<Select
clearable
placeholder='所有供应商'
style={{ width: 200 }}
value={providerId}
onChange={(value) => onProviderIdChange(value as string | undefined)}
options={providers.map((p) => ({ label: p.name, value: p.id }))}
/>
<Input
clearable
placeholder='模型名称'
style={{ width: 200 }}
value={modelName ?? ''}
onChange={(value) => onModelNameChange((value as string) || undefined)}
/>
<DateRangePicker
mode='date'
value={dateRange && dateRange[0] && dateRange[1] ? [dateRange[0], dateRange[1]] : []}
onChange={handleDateChange}
/>
</Space>
<Table<UsageStats>
columns={columns}
data={stats}
rowKey='id'
loading={loading}
stripe
pagination={{ pageSize: 20 }}
empty='暂无统计数据'
/>
</Card>
)
}