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
@@ -255,6 +255,7 @@ import { passGuard } from "@/shared/dispatch-guard-ui";
import ZiniaoVersionSetting from "@/shared/components/ZiniaoVersionSetting.vue";
import { useZiniaoVersion } from "@/shared/utils/ziniao-version";
import { formatDateTime } from '@/shared/utils/datetime'
import { useHistoryPolling } from '@/shared/composables/useHistoryPolling'
const MAX_TRANSIENT_ERRORS = 30;
const ziniaoVersion = useZiniaoVersion();
@@ -292,7 +293,6 @@ const activeQueueItem = ref<WithdrawTaskBatchQueueItem | null>(null);
const queueWorkerRunning = ref(false);
const autoQueueEnabled = ref(false);
const taskStartTimes = ref<Record<number, string>>({});
let historyPollTimer: number | null = null;
const timers = createCategorizedTimers("withdraw");
const matchedRunnableItems = computed(() =>
@@ -458,6 +458,13 @@ function mergeQueueBatches(
let disposed = false;
const historyPolling = useHistoryPolling({
timers,
isDisposed: () => disposed,
shouldPoll: () => hasQueueWork.value,
refresh: () => refreshActiveTaskProgress(),
})
function sleep(ms: number) {
if (disposed) return Promise.resolve();
return timers.sleep("queue-wait", ms);
@@ -741,7 +748,7 @@ function resetQueueWorkerIfIdle() {
queueWorkerRunning.value = false;
pushing.value = false;
autoQueueEnabled.value = false;
stopHistoryPolling();
historyPolling.stop();
saveQueueState();
}
@@ -838,27 +845,6 @@ async function refreshActiveTaskProgress(taskIds?: number[]) {
}
}
function startHistoryPolling() {
stopHistoryPolling();
if (disposed || !hasQueueWork.value) return;
const run = async () => {
historyPollTimer = null;
if (disposed || !hasQueueWork.value) return;
await refreshActiveTaskProgress();
if (!disposed && hasQueueWork.value) {
historyPollTimer = timers.setTimeout("history-poll", run, getTaskPollIntervalMs() * 2);
}
};
historyPollTimer = timers.setTimeout("history-poll", run, getTaskPollIntervalMs() * 2);
}
function stopHistoryPolling() {
if (historyPollTimer) {
timers.clearTimer("history-poll", historyPollTimer);
historyPollTimer = null;
}
}
function onSelectionChange(rows: WithdrawCandidateVo[]) {
selectedCandidates.value = rows;
}
@@ -1033,7 +1019,7 @@ async function processQueue() {
if (disposed || queueWorkerRunning.value) return;
queueWorkerRunning.value = true;
pushing.value = true;
startHistoryPolling();
historyPolling.start();
try {
const api = getPywebviewApi();
@@ -1136,7 +1122,7 @@ async function processQueue() {
} finally {
queueWorkerRunning.value = false;
pushing.value = false;
stopHistoryPolling();
historyPolling.stop();
saveQueueState();
}
}
@@ -1220,7 +1206,7 @@ onMounted(async () => {
onUnmounted(() => {
disposed = true;
stopHistoryPolling();
historyPolling.stop();
clearSleepTimers();
timers.clearScope();
});