Add force rerun recovery and polish CLI startup

This commit is contained in:
rayd1o
2026-04-08 02:49:29 +08:00
parent 981617ee80
commit f5308340af
6 changed files with 546 additions and 137 deletions

View File

@@ -1,6 +1,6 @@
import { useCallback, useEffect, useRef, useState } from 'react'
import {
Table, Tag, Space, Button, Form, Input, Select, Progress, Checkbox, message,
Table, Tag, Space, Button, Form, Input, Select, Progress, Checkbox, message, Modal,
Drawer, Tabs, Empty, Tooltip, Popconfirm, Collapse, InputNumber, Row, Col, Card
} from 'antd'
import {
@@ -382,30 +382,92 @@ function DataSources() {
return () => clearInterval(interval)
}, [builtInSources, taskProgress, taskSocketConnected, fetchData])
const triggerDatasource = async (id: number, options?: { force?: boolean }) => {
const force = options?.force ?? false
const res = await axios.post(`/api/v1/datasources/${id}/trigger`, null, {
params: { force },
})
if (res.data.task_id) {
setTaskProgress(prev => ({
...prev,
[id]: {
task_id: res.data.task_id,
progress: 0,
is_running: true,
phase: 'queued',
status: 'running',
},
}))
} else {
window.setTimeout(() => {
fetchData()
}, 800)
}
fetchData()
return res
}
const confirmForceTrigger = (id: number, taskInfo?: {
progress?: number | null
phase?: string | null
records_processed?: number | null
total_records?: number | null
message?: string
}) => {
const progressText = typeof taskInfo?.progress === 'number' ? `${Math.round(taskInfo.progress)}%` : '未知'
const phaseText = taskInfo?.phase || 'running'
const processedText = typeof taskInfo?.records_processed === 'number'
? `${taskInfo.records_processed}${typeof taskInfo?.total_records === 'number' && taskInfo.total_records > 0 ? ` / ${taskInfo.total_records}` : ''}`
: '未知'
Modal.confirm({
title: '当前任务未完成',
content: (
<div>
<p>{taskInfo?.message || '当前采集任务仍在运行,重新触发会丢失本次未完成进度。'}</p>
<p>: {phaseText}</p>
<p>: {progressText}</p>
<p>: {processedText}</p>
<p></p>
</div>
),
okText: '强制重新采集',
cancelText: '取消',
okButtonProps: { danger: true },
onOk: async () => {
try {
await triggerDatasource(id, { force: true })
messageApi.success('已强制重新触发,未完成采集将回滚')
} catch (error: unknown) {
const err = error as { response?: { data?: { detail?: string | { message?: string } } } }
const detail = err.response?.data?.detail
messageApi.error(typeof detail === 'string' ? detail : detail?.message || '强制重新采集失败')
}
},
})
}
const handleTrigger = async (id: number) => {
try {
const res = await axios.post(`/api/v1/datasources/${id}/trigger`)
await triggerDatasource(id)
messageApi.success('任务已触发')
if (res.data.task_id) {
setTaskProgress(prev => ({
...prev,
[id]: {
task_id: res.data.task_id,
progress: 0,
is_running: true,
phase: 'queued',
status: 'running',
},
}))
} else {
window.setTimeout(() => {
fetchData()
}, 800)
}
fetchData()
} catch (error: unknown) {
const err = error as { response?: { data?: { detail?: string } } }
messageApi.error(err.response?.data?.detail || '触发失败')
const err = error as { response?: { status?: number; data?: { detail?: string | {
reason?: string
message?: string
progress?: number | null
phase?: string | null
records_processed?: number | null
total_records?: number | null
} } } }
const detail = err.response?.data?.detail
if (err.response?.status === 409 && typeof detail === 'object' && detail?.reason === 'running_task_in_progress') {
confirmForceTrigger(id, detail)
return
}
messageApi.error(typeof detail === 'string' ? detail : detail?.message || '触发失败')
}
}
@@ -527,12 +589,24 @@ function DataSources() {
const handleUpdateSource = async () => {
if (!viewingSource) return
try {
await axios.post(`/api/v1/datasources/${viewingSource.id}/trigger`)
await triggerDatasource(viewingSource.id)
messageApi.success('已触发更新')
setViewDrawerVisible(false)
} catch (error: unknown) {
const err = error as { response?: { data?: { detail?: string } } }
messageApi.error(err.response?.data?.detail || '更新失败')
const err = error as { response?: { status?: number; data?: { detail?: string | {
reason?: string
message?: string
progress?: number | null
phase?: string | null
records_processed?: number | null
total_records?: number | null
} } } }
const detail = err.response?.data?.detail
if (err.response?.status === 409 && typeof detail === 'object' && detail?.reason === 'running_task_in_progress') {
confirmForceTrigger(viewingSource.id, detail)
return
}
messageApi.error(typeof detail === 'string' ? detail : detail?.message || '更新失败')
}
}