refactor(品牌工具页): 历史轮询抽为 useHistoryPolling

QueryAsin / Withdraw / PatrolDelete 三页逐字相同的 startHistoryPolling /
stopHistoryPolling 收敛为 shared/composables/useHistoryPolling:定时器走各页
categorized-timers(category 固定 history-poll),间隔默认主轮询的 2 倍。
categorized-timers 补 CategorizedTimers 类型导出;补注入式假定时器单测 5 例。

净减约 40 行;vue-tsc 构建与 695 个前端单测通过。
This commit is contained in:
2026-09-13 23:22:49 +08:00
parent 882ccdac12
commit dc6e8924a9
13 changed files with 685 additions and 84 deletions
@@ -0,0 +1,50 @@
import { getTaskPollIntervalMs } from '../task-progress-config.ts'
import type { CategorizedTimers } from '../utils/categorized-timers.ts'
export interface HistoryPollingOptions {
/** 页面自己的 categorized-timers 实例(决定定时器清理 scope)。 */
timers: CategorizedTimers
/** 组件是否已卸载。 */
isDisposed: () => boolean
/** 是否还有队列工作需要跟踪。 */
shouldPoll: () => boolean
/** 每轮拉取活动任务进度(返回值被忽略,允许各页返回不同结果)。 */
refresh: () => Promise<unknown>
/** 轮询间隔;默认 getTaskPollIntervalMs() 的 2 倍(历史刷新不需要主任务那么勤)。 */
intervalMs?: () => number
}
/**
* 历史任务进度轮询:队列有工作时按较慢的固定间隔拉取活动任务进度。
* 与主任务轮询(useTaskProgressLoop)并存,但节奏更慢、只管历史列表刷新。
*
* 定时器统一注册到传入的 categorized-timerscategory 固定为 'history-poll'),
* 由页面在卸载时 clearScope 兜底清理。
*/
export function useHistoryPolling(options: HistoryPollingOptions) {
const intervalMs = options.intervalMs ?? (() => getTaskPollIntervalMs() * 2)
let timer: number | null = null
function stop() {
if (timer != null) {
options.timers.clearTimer('history-poll', timer)
timer = null
}
}
function start() {
stop()
if (options.isDisposed() || !options.shouldPoll()) return
const run = async () => {
timer = null
if (options.isDisposed() || !options.shouldPoll()) return
await options.refresh()
if (!options.isDisposed() && options.shouldPoll()) {
timer = options.timers.setTimeout('history-poll', run, intervalMs())
}
}
timer = options.timers.setTimeout('history-poll', run, intervalMs())
}
return { start, stop }
}
@@ -105,6 +105,8 @@ export function createCategorizedTimers(scope: string) {
}
}
export type CategorizedTimers = ReturnType<typeof createCategorizedTimers>
export function getCategorizedTimerStats() {
return Array.from(timerBuckets.entries()).map(([category, bucket]) => ({
category,