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
@@ -273,6 +273,7 @@ import {
sanitizeCountryCodes,
} from "@/shared/country-options";
import { formatDateTime } from '@/shared/utils/datetime'
import { useHistoryPolling } from '@/shared/composables/useHistoryPolling'
const MAX_TRANSIENT_ERRORS = 30;
/** 任务终态后等待结果文件(Java 侧异步生成)的最大轮次,12 × 10s ≈ 2 分钟 */
@@ -302,7 +303,6 @@ const queuePushResult = ref("");
const queuePayloadText = ref("");
const activeTaskId = ref<number | null>(null);
const queueWorkerRunning = ref(false);
let historyPollTimer: number | null = null;
const timers = createCategorizedTimers("patrol-delete");
const matchedRunnableItems = computed(() =>
@@ -399,6 +399,13 @@ function taskGroupKey(item: PatrolDeleteHistoryItem) {
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);
@@ -793,27 +800,6 @@ async function refreshActiveTaskProgress(taskIds?: number[]) {
return batch.missingTaskIds || [];
}
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: PatrolDeleteCandidateVo[]) {
selectedCandidates.value = rows;
}
@@ -1060,7 +1046,7 @@ async function processQueue() {
if (disposed || queueWorkerRunning.value) return;
queueWorkerRunning.value = true;
pushing.value = true;
startHistoryPolling();
historyPolling.start();
try {
const api = getPywebviewApi();
@@ -1175,7 +1161,7 @@ async function processQueue() {
} finally {
queueWorkerRunning.value = false;
pushing.value = false;
stopHistoryPolling();
historyPolling.stop();
saveQueueState();
}
}
@@ -1260,7 +1246,7 @@ onMounted(async () => {
onUnmounted(() => {
disposed = true;
stopHistoryPolling();
historyPolling.stop();
clearSleepTimers();
timers.clearScope();
});