Files
knowledge-governance/web/src/monitorTasks.ts
T
姚章浩 1b09f7d35b
build / build (push) Successful in 1m17s
feat(monitor): 卡片概况与统一文件处理表
2026-10-27 12:14:19 +08:00

130 lines
3.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
export interface MonitorTask {
history?: { at: string; kind: string; detail: string }[]
id: string
title: string
path: string
source_id: string
source_name: string
target_scope: string
target_kb: string
action: string
stage: string
status: string
detail: string
updated_at: string
retry_kind: string
failure_id: string
retry_count: number
version_id: string
}
export interface MonitorTaskPage {
items: MonitorTask[]
total: number
limit: number
offset: number
sources: { id: string; name: string }[]
targets: { id: string; name: string }[]
retryable: number
}
export interface MonitorFilters {
q: string
source: string
scope: string
target: string
action: string
status: string
stage: string
since: string
until: string
}
export const defaultMonitorFilters: MonitorFilters = {
q: '',
source: '',
scope: '',
target: '',
action: '',
status: 'active',
stage: '',
since: '',
until: '',
}
export const actionLabels: Record<string, string> = { add: '新增', update: '更新', remove: '移除' }
export const stageLabels: Record<string, string> = {
waiting: '等待调度',
fetch: '取件',
upload: '上传',
parsing: '解析',
indexing: '索引增强',
removal: '测试库移除',
finished: '结束',
}
export const taskStatusLabels: Record<string, string> = {
waiting: '等待中',
running: '执行中',
retrying: '重试中',
attention: '需人工处理',
completed: '已完成',
cancelled: '已取消',
}
export const canRetryTask = (item: MonitorTask) =>
item.status === 'attention' && ['upload', 'fetch', 'remove'].includes(item.retry_kind)
const record = (v: unknown): v is Record<string, unknown> => typeof v === 'object' && v !== null
export async function fetchMonitorTasks(
filters: Partial<MonitorFilters> & { id?: string },
offset = 0,
limit = 20,
signal?: AbortSignal
): Promise<MonitorTaskPage> {
const query = new URLSearchParams({ limit: String(limit), offset: String(offset) })
Object.entries(filters).forEach(([k, v]) => {
if (v) query.set(k, v)
})
const response = await fetch(`/api/v1/monitor/tasks?${query}`, { headers: { Accept: 'application/json' }, signal })
if (!response.ok) throw new Error(`加载文件处理状态失败(HTTP ${response.status})`)
const value: unknown = await response.json()
if (!record(value) || !record(value.data)) throw new Error('文件处理响应无效')
const d = value.data
const count = (v: unknown) => Number.isInteger(v) && Number(v) >= 0
if (
!Array.isArray(d.items) ||
!count(d.total) ||
!count(d.limit) ||
!count(d.offset) ||
!count(d.retryable) ||
!Array.isArray(d.sources) ||
!Array.isArray(d.targets)
)
throw new Error('文件处理分页响应无效')
for (const item of d.items) {
if (
!record(item) ||
![
'id',
'title',
'path',
'source_id',
'source_name',
'target_scope',
'target_kb',
'action',
'stage',
'status',
'detail',
'updated_at',
'retry_kind',
'failure_id',
'version_id',
].every((k) => typeof item[k] === 'string') ||
!count(item.retry_count) ||
!Object.hasOwn(actionLabels, String(item.action)) ||
!Object.hasOwn(stageLabels, String(item.stage)) ||
!Object.hasOwn(taskStatusLabels, String(item.status))
)
throw new Error('文件处理条目无效')
}
for (const option of [...d.sources, ...d.targets])
if (!record(option) || typeof option.id !== 'string' || typeof option.name !== 'string')
throw new Error('文件处理筛选项无效')
return d as unknown as MonitorTaskPage
}