From cf2abcb5729135d950311e4386918fce32934f56 Mon Sep 17 00:00:00 2001 From: richjohnrambo Date: Sat, 24 Oct 2026 18:33:07 +0800 Subject: [PATCH] fix: improve task matching progress feedback --- web/src/mobile/views/ClaimView.vue | 75 +++++++++--------------------- 1 file changed, 23 insertions(+), 52 deletions(-) diff --git a/web/src/mobile/views/ClaimView.vue b/web/src/mobile/views/ClaimView.vue index a0d791c..3c755f3 100644 --- a/web/src/mobile/views/ClaimView.vue +++ b/web/src/mobile/views/ClaimView.vue @@ -52,8 +52,8 @@ -
- {{ matchProgress }}% +
+ {{ matchProgress }}%
  1. ✓正在匹配订单
@@ -117,12 +117,11 @@ const resultState = ref('matching'); const failureMessage = ref('当前任务库存未分配成功,请稍后重试'); const matchProgress = ref(18); - const matchRemainingSeconds = ref(0); - const matchTotalSeconds = ref(0); const pollFinished = ref(false); + const matchProgressDurationSeconds = 15 * 60; let pollTimer: number | undefined; let countdownTimer: number | undefined; - let pollCount = 0; + let pollFailureCount = 0; const statCards = computed(() => [ { label: '总资产', value: money(stats.value?.total_asset_amount), icon: mobileAssets.claimTotal }, @@ -139,11 +138,10 @@ Number(item?.available_amount || 0) < Number(item.minimum_amount) ) ); - const isAutoMatching = computed(() => order.value?.dispatch_mode !== 'manual'); const matchingHint = computed(() => { - if (order.value?.dispatch_mode === 'manual') return '订单已领取,正在等待后台匹配...'; - if (matchRemainingSeconds.value > 0) return `系统正在派单... ${formatCountdown(matchRemainingSeconds.value)}`; - return pollFinished.value ? '订单仍在匹配,可稍后前往记录查看' : '系统正在为您匹配订单,请稍等...'; + return pollFinished.value + ? '订单仍在匹配,可稍后前往记录查看' + : '订单已领取,正在等待后台匹配...'; }); const resultIcon = computed(() => resultState.value === 'success' ? mobileAssets.claimSuccess : resultState.value === 'failed' ? mobileAssets.claimFailed : mobileAssets.claimCancelled); const resultTitle = computed(() => resultState.value === 'success' ? '任务获取成功' : resultState.value === 'failed' ? '领取失败' : '已取消任务'); @@ -247,23 +245,13 @@ resultState.value = 'matching'; showResult.value = true; matchProgress.value = 18; - matchRemainingSeconds.value = 0; - matchTotalSeconds.value = 0; - pollCount = 0; + pollFailureCount = 0; } function handleOrder(value: any) { order.value = value; if (value?.status === 'matching') { - if (value?.dispatch_mode === 'manual') { - if (countdownTimer) window.clearInterval(countdownTimer); - countdownTimer = undefined; - matchRemainingSeconds.value = 0; - matchTotalSeconds.value = 0; - matchProgress.value = 18; - } else { - startCountdown(value); - } + startMatchingProgress(value); schedulePoll(); } else if (['pending', 'processing', 'completed'].includes(value?.status)) { matchProgress.value = 100; @@ -282,55 +270,38 @@ function schedulePoll() { if (!order.value?.id) return; if (pollTimer) window.clearTimeout(pollTimer); - const scheduledAt = Date.parse(String(order.value?.scheduled_match_at || '')); - const wait = order.value?.dispatch_mode === 'manual' - ? 10000 - : Number.isFinite(scheduledAt) && scheduledAt > Date.now() - ? scheduledAt - Date.now() + 300 - : 1200; + const wait = order.value?.dispatch_mode === 'manual' ? 5000 : 3000; pollTimer = window.setTimeout(async () => { - pollCount += 1; try { + pollFailureCount = 0; handleOrder(await request({ url: `/v1/task-orders/${order.value.id}` })); } catch (err) { - if (pollCount >= 10) { + pollFailureCount += 1; + if (pollFailureCount >= 10) { pollFinished.value = true; stopPolling(); } else schedulePoll(); } - if (resultState.value === 'matching' && pollCount >= 10) { - pollFinished.value = true; - stopPolling(); - } }, wait); } - function startCountdown(value: any) { + function startMatchingProgress(value: any) { if (countdownTimer) window.clearInterval(countdownTimer); - if (value?.dispatch_mode === 'manual') return; - const scheduledAt = Date.parse(String(value?.scheduled_match_at || '')); - if (!Number.isFinite(scheduledAt)) return; - matchTotalSeconds.value = Math.max(1, Number(value?.dispatch_delay_seconds || 0)); + const createdAt = Date.parse(String(value?.created_at || '')); + const startedAt = Number.isFinite(createdAt) ? createdAt : Date.now(); const update = () => { - matchRemainingSeconds.value = Math.max(0, Math.ceil((scheduledAt - Date.now()) / 1000)); - const elapsed = Math.max(0, matchTotalSeconds.value - matchRemainingSeconds.value); - matchProgress.value = Math.min(88, Math.round(18 + elapsed / matchTotalSeconds.value * 70)); - if (matchRemainingSeconds.value === 0 && countdownTimer) { + const elapsedSeconds = Math.max(0, Math.floor((Date.now() - startedAt) / 1000)); + matchProgress.value = Math.min( + 88, + Math.round(18 + elapsedSeconds / matchProgressDurationSeconds * 70) + ); + if (matchProgress.value >= 88 && countdownTimer) { window.clearInterval(countdownTimer); countdownTimer = undefined; } }; update(); - if (matchRemainingSeconds.value > 0) countdownTimer = window.setInterval(update, 1000); - } - - function formatCountdown(totalSeconds: number) { - const hours = Math.floor(totalSeconds / 3600); - const minutes = Math.floor(totalSeconds % 3600 / 60); - const seconds = totalSeconds % 60; - return hours > 0 - ? [hours, minutes, seconds].map((item) => String(item).padStart(2, '0')).join(':') - : [minutes, seconds].map((item) => String(item).padStart(2, '0')).join(':'); + if (matchProgress.value < 88) countdownTimer = window.setInterval(update, 1000); } function stopPolling(clearProgress = true) {