diff --git a/web/frontend/src/pages/AutomationPage.tsx b/web/frontend/src/pages/AutomationPage.tsx index 4024b43..7224cb3 100644 --- a/web/frontend/src/pages/AutomationPage.tsx +++ b/web/frontend/src/pages/AutomationPage.tsx @@ -1,3 +1,4 @@ +import type { ReactNode } from "react"; import { useCallback, useEffect, useState } from "react"; import { Alert, @@ -34,6 +35,28 @@ const STATUS_TAG: Record = { skipped: { color: "default", text: "已跳过" }, }; +/** + * 下次运行时间:两个作业串行跑在同一个调度线程里,前一个作业耗时长时, + * 后一个会排队等待 —— 于是 next_run_at 会停在「已经过了」的时刻。 + * 直接显示一个过去时间看起来像故障,这里标明「排队中」。 + */ +function nextRunLabel(job: AutomationJobItem): ReactNode { + if (!job.next_run_at) { + return 未启用; + } + const next = new Date(job.next_run_at).getTime(); + if (!Number.isFinite(next)) return formatTime(job.next_run_at); + if (next > Date.now()) return formatTime(job.next_run_at); + return ( + + 排队中{" "} + + ({formatTime(job.next_run_at)} 到期,等待前序作业让出线程) + + + ); +} + function secondsToHours(seconds: number): number { return Math.round((seconds / 3600) * 10) / 10; } @@ -191,7 +214,13 @@ export default function AutomationPage() { { title: "耗时", width: 90, - render: (_, row) => formatDuration(row.started_at, row.finished_at), + render: (_, row) => + // 没实际扫描过的轮次没有真实耗时:被中断的记录 finished_at 是重启后 + // 补上的(见 cleanup_orphan_runs),差值里混入了停机时间,是个假数字; + // 一轮就报错的(如 SQL 语法错误)同理。 + row.scanned > 0 && row.finished_at + ? formatDuration(row.started_at, row.finished_at) + : "-", }, { title: "说明", dataIndex: "message", ellipsis: true }, ]; @@ -256,7 +285,7 @@ export default function AutomationPage() { {formatTime(job.last_run_at)} - {formatTime(job.next_run_at)} + {nextRunLabel(job)} {job.last_status ? (