Files
admin-web/src/modules/self-operated/collectionPresentation.ts
T

59 lines
3.8 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.
import type { Task } from './types'
import { label, phaseText, quantityText, unitText } from './state'
export interface CollectionControlEvidence {
collectionMode?: string | null
accountPaused?: boolean
blockingReason?: string | null
}
export function collectionControlState(task: Task | null | undefined, evidence: CollectionControlEvidence = {}) {
if (task && ['SUCCEEDED', 'FAILED', 'DEAD', 'ABORTED'].includes(task.taskStatus)) return null
const reasons = [task?.blockingReason, evidence.blockingReason]
const text = evidence.collectionMode === 'OFF' || reasons.includes('COLLECTION_OFF') ? '采集已关闭'
: evidence.accountPaused || reasons.includes('ACCOUNT_PAUSED') ? '已暂停'
: reasons.includes('EXECUTION_DISABLED') ? '执行未启用' : null
if (!text) return null
// A control switch alone cannot establish that an already running attempt has stopped.
const running = Boolean(task && ['RUNNING', 'APPLYING'].includes(task.taskStatus))
return { text, running, summary: running ? `${text === '采集已关闭' ? '已关闭' : text} · 执行中` : text }
}
export function isNormalContinuation(task: Task | null | undefined) {
const attempt = task?.latestAttempt
return task?.taskStatus === 'RETRY_WAIT' && attempt?.status === 'YIELDED'
&& task.latestAttemptNo != null && task.latestAttemptNo > 0
&& attempt.attemptNo === task.latestAttemptNo && task.attemptCount === task.latestAttemptNo
&& !attempt.errorCode && !attempt.failureSummary
}
export function taskStateText(task: Task | null | undefined, evidence: CollectionControlEvidence = {}) {
if (!task) return '尚无任务'
const control = collectionControlState(task, evidence)
if (control) return control.summary
if (isNormalContinuation(task)) return '本批已完成,等待续采'
const states: Record<string, string> = { WAITING_SOURCE: '等待数据准备', WAITING_UPSTREAM: '等待数据准备', READY: '等待执行', QUEUED: '等待执行', WAITING: '等待执行', RUNNING: '正在执行', RETRY_WAIT: '等待重试', YIELDED: '本批已完成,等待续采', DEAD: '已停止,需处理', SUCCEEDED: '执行完成', FAILED: '执行失败' }
return states[task.taskStatus] ?? label(task.taskStatus)
}
export function taskProgressText(task: Task | null | undefined) {
if (!task) return '尚无任务'
if (['WAITING_SOURCE', 'WAITING_UPSTREAM'].includes(task.taskStatus)) return '尚未开始,等待数据准备'
if (task.attemptCount === 0 && ['READY', 'QUEUED', 'WAITING'].includes(task.taskStatus)) return '尚未开始,等待执行'
const progress = task.progress
if (!progress?.phase) return task.taskStatus === 'SUCCEEDED' ? '本任务执行完成' : '当前进度尚未提供'
const phase = phaseText(progress.phase)
if (progress.completed == null || !progress.unit || progress.unit === 'NONE') return phase
const amount = `${quantityText(progress.completed)}${unitText(progress.unit)}`
if (!progress.totalKnown || progress.total == null) return `${phase},已处理 ${amount},总量尚未确定`
const total = Number(progress.total), completed = Number(progress.completed)
const percent = Number.isFinite(total) && Number.isFinite(completed) && total > 0 && completed >= 0 && completed <= total ? `(${Math.floor(completed / total * 1000) / 10}%,当前阶段)` : ''
return `${phase},已处理 ${quantityText(progress.completed)} / ${quantityText(progress.total)}${unitText(progress.unit)}${percent}`
}
export function taskCompletionText(task: Task | null | undefined) {
if (!task) return '—'
if (task.resultPublicationState === 'PUBLISHED' || task.resultPublicationState === 'REUSED') return '结果已可用'
if (task.taskStatus === 'SUCCEEDED') return '执行完成,结果尚未发布'
if (['DEAD', 'FAILED', 'ABORTED'].includes(task.taskStatus)) return '已停止,需先处理异常'
return '完成时间暂无法预计'
}