import { useEffect, useState } from 'react' import { Table, Tag, Card, Row, Col, Statistic, Button, Tooltip } from 'antd' import { ReloadOutlined, CheckCircleOutlined, CloseCircleOutlined, SyncOutlined } from '@ant-design/icons' import { useAuthStore } from '../../stores/auth' import AppLayout from '../../components/AppLayout/AppLayout' import TableScrollRegion from '../../components/Scrollbar/TableScrollRegion' import { formatDateTimeZhCN } from '../../utils/datetime' import { getPhaseDisplay, getPhaseSummary } from '../../utils/phaseProgress' interface Task { id: number collector?: string datasource_name?: string status: 'success' | 'failed' | 'running' | 'pending' phase?: string | null phase_progress?: number | null phase_message?: string | null phase_current?: number | null phase_total?: number | null phase_unit?: string | null records_processed: number total_records?: number | null progress?: number | null started_at: string completed_at: string duration_seconds: number } function Tasks() { const { token } = useAuthStore() const [tasks, setTasks] = useState([]) const [loading, setLoading] = useState(false) const [stats, setStats] = useState({ total_today: 0, success: 0, failed: 0, running: 0, }) const fetchTasks = async () => { setLoading(true) try { const res = await fetch('/api/v1/tasks', { headers: { Authorization: `Bearer ${token}` }, }) const data = await res.json() setTasks(data.data || []) setStats(data.stats || stats) } catch (error) { console.error('Failed to fetch tasks:', error) } finally { setLoading(false) } } useEffect(() => { fetchTasks() }, [token]) const columns = [ { title: 'ID', dataIndex: 'id', key: 'id', width: 80 }, { title: '收集器', dataIndex: 'collector', key: 'collector', render: (_: string, task: Task) => {task.collector || task.datasource_name || '-'}, }, { title: '阶段', dataIndex: 'phase', key: 'phase', render: (_: string, task: Task) => { const detail = task.phase ? getPhaseDisplay(task) : null return detail ? ( {getPhaseSummary(task)} ) : '-' }, }, { title: '状态', dataIndex: 'status', key: 'status', render: (status: string) => { const colors: Record = { success: 'success', failed: 'error', running: 'processing', pending: 'default', } const icons: Record = { success: , failed: , running: , pending: , } return ( {status === 'success' ? '成功' : status === 'failed' ? '失败' : status === 'running' ? '运行中' : '等待中'} ) }, }, { title: '处理记录', dataIndex: 'records_processed', key: 'records_processed', render: (n: number) => n.toLocaleString(), }, { title: '耗时', dataIndex: 'duration_seconds', key: 'duration_seconds', render: (s: number) => s ? `${s.toFixed(2)}s` : '-', }, { title: '开始时间', dataIndex: 'started_at', key: 'started_at', render: (t: string) => formatDateTimeZhCN(t), }, ] const statusCounts = tasks.reduce( (acc, task) => { acc[task.status]++ return acc }, { success: 0, failed: 0, running: 0, pending: 0 } as Record ) const successRate = tasks.length > 0 ? (statusCounts.success / tasks.length) * 100 : 0 return (
} /> = 90 ? '#52c41a' : '#faad14' }} /> } onClick={fetchTasks}> 刷新 } > ) } export default Tasks