74 lines
2.1 KiB
TypeScript
74 lines
2.1 KiB
TypeScript
import { Card, Timeline, Typography, Tag, Empty } from 'antd'
|
|
import { HistoryOutlined } from '@ant-design/icons'
|
|
import { formatTimestamp, quotaToUsd } from '@/utils/quota'
|
|
|
|
const { Text } = Typography
|
|
|
|
interface LogItem {
|
|
id: number
|
|
created_at: number
|
|
model_name: string
|
|
token_name: string
|
|
quota: number
|
|
type: number
|
|
}
|
|
|
|
interface Props {
|
|
logs: LogItem[]
|
|
loading: boolean
|
|
}
|
|
|
|
const logTypeMap: Record<number, { color: string; label: string }> = {
|
|
1: { color: '#7DB87D', label: '充值' },
|
|
2: { color: '#C8956C', label: '消费' },
|
|
3: { color: '#E8A850', label: '管理' },
|
|
4: { color: '#9B8EC2', label: '系统' },
|
|
5: { color: '#D4645C', label: '错误' },
|
|
6: { color: '#7BA4C8', label: '退款' },
|
|
}
|
|
|
|
export default function RecentLogs({ logs, loading }: Props) {
|
|
if (!loading && logs.length === 0) {
|
|
return (
|
|
<Card title={<><HistoryOutlined style={{ color: '#C8956C' }} /> 最近操作日志</>} className="stat-accent">
|
|
<Empty description="暂无日志" />
|
|
</Card>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<Card
|
|
title={<><HistoryOutlined style={{ color: '#C8956C' }} /> 最近操作日志</>}
|
|
loading={loading}
|
|
hoverable
|
|
className="stat-accent"
|
|
>
|
|
<Timeline
|
|
items={logs.slice(0, 10).map((log) => {
|
|
const typeInfo = logTypeMap[log.type] || { color: '#A69278', label: '未知' }
|
|
return {
|
|
color: typeInfo.color,
|
|
children: (
|
|
<div>
|
|
<div>
|
|
<Tag color={typeInfo.color} style={{ marginRight: 8 }}>{typeInfo.label}</Tag>
|
|
<Text strong>{log.model_name || '-'}</Text>
|
|
{log.quota > 0 && (
|
|
<Text type="secondary" style={{ marginLeft: 8 }}>
|
|
${quotaToUsd(log.quota)}
|
|
</Text>
|
|
)}
|
|
</div>
|
|
<Text type="secondary" style={{ fontSize: 12 }}>
|
|
{formatTimestamp(log.created_at)}
|
|
{log.token_name && ` · ${log.token_name}`}
|
|
</Text>
|
|
</div>
|
|
),
|
|
}
|
|
})}
|
|
/>
|
|
</Card>
|
|
)
|
|
}
|