| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154 |
- import { useEffect, useState, useCallback } from 'react'
- import { Table, Tag, Button, message, Badge } from 'antd'
- import { StopOutlined } from '@ant-design/icons'
- import { getTasks, stopTask, type Task } from '../api'
- import { useAppStore } from '../store'
- import TaskControl from '../components/TaskControl'
- const taskTypeColor: Record<string, string> = {
- full: 'purple',
- discover: 'blue',
- search: 'cyan',
- github: 'geekblue',
- scrape: 'orange',
- crawl: 'green',
- clean: 'lime',
- score: 'gold',
- }
- const taskStatusBadge: Record<string, 'processing' | 'success' | 'error' | 'warning' | 'default'> = {
- running: 'processing',
- completed: 'success',
- failed: 'error',
- stopped: 'warning',
- pending: 'default',
- }
- function formatDateTime(dateStr: string | null) {
- if (!dateStr) return '-'
- const d = new Date(dateStr)
- return d.toLocaleString('zh-CN')
- }
- export default function Tasks() {
- const [tasks, setTasks] = useState<Task[]>([])
- const [total, setTotal] = useState(0)
- const [page, setPage] = useState(1)
- const [loading, setLoading] = useState(false)
- const [stoppingId, setStoppingId] = useState<number | null>(null)
- const { runningTask, setRunningTask } = useAppStore()
- const fetchTasks = useCallback(async (currentPage = page) => {
- setLoading(true)
- try {
- const res = await getTasks({ page: currentPage, page_size: 20 })
- setTasks(res.data.items)
- setTotal(res.data.total)
- } catch {
- message.error('获取任务列表失败')
- } finally {
- setLoading(false)
- }
- }, [page])
- useEffect(() => {
- fetchTasks(page)
- }, [page, fetchTasks])
- useEffect(() => {
- if (!runningTask) return
- const timer = setInterval(() => fetchTasks(page), 3000)
- return () => clearInterval(timer)
- }, [runningTask, fetchTasks, page])
- const handleStop = async (id: number) => {
- setStoppingId(id)
- try {
- await stopTask(id)
- setRunningTask(null)
- message.success('任务已停止')
- fetchTasks(page)
- } catch {
- message.error('停止任务失败')
- } finally {
- setStoppingId(null)
- }
- }
- const columns = [
- { title: 'ID', dataIndex: 'id', key: 'id', width: 70 },
- {
- title: '任务类型',
- dataIndex: 'task_type',
- key: 'task_type',
- render: (type: string) => <Tag color={taskTypeColor[type] ?? 'default'}>{type}</Tag>,
- },
- {
- title: '状态',
- dataIndex: 'status',
- key: 'status',
- render: (status: string) => (
- <Badge status={taskStatusBadge[status] ?? 'default'} text={status} />
- ),
- },
- {
- title: '参数预览',
- dataIndex: 'params',
- key: 'params',
- render: (params: Record<string, unknown>) => (
- <span style={{ fontSize: 12, color: '#666' }}>
- {JSON.stringify(params).slice(0, 60)}
- {JSON.stringify(params).length > 60 ? '...' : ''}
- </span>
- ),
- ellipsis: true,
- },
- {
- title: '创建时间',
- dataIndex: 'created_at',
- key: 'created_at',
- render: (t: string) => formatDateTime(t),
- },
- {
- title: '完成时间',
- dataIndex: 'completed_at',
- key: 'completed_at',
- render: (t: string | null) => formatDateTime(t),
- },
- {
- title: '操作',
- key: 'action',
- render: (_: unknown, record: Task) =>
- record.status === 'running' ? (
- <Button
- danger
- size="small"
- icon={<StopOutlined />}
- loading={stoppingId === record.id}
- onClick={() => handleStop(record.id)}
- >
- 停止
- </Button>
- ) : null,
- },
- ]
- return (
- <div>
- <TaskControl onTaskStarted={() => fetchTasks(1)} />
- <Table
- dataSource={tasks}
- columns={columns}
- rowKey="id"
- loading={loading}
- pagination={{
- current: page,
- pageSize: 20,
- total,
- onChange: (p) => setPage(p),
- showTotal: (t) => `共 ${t} 条`,
- }}
- />
- </div>
- )
- }
|