From d9c16908e94bb53fd790e985baf85ae75991db61 Mon Sep 17 00:00:00 2001 From: bboysoul Date: Tue, 8 Sep 2026 14:58:09 +0800 Subject: [PATCH] fix: harden today progress summary --- frontend/src/App.vue | 50 ++++++++++++++++++++------------------ frontend/src/style.test.ts | 8 +++++- 2 files changed, 34 insertions(+), 24 deletions(-) diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 23f70fa..150d593 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -174,7 +174,7 @@ async function submitTaskCompose() { tasks.value.push(task) totalTasks.value = nextTotalAfterLocalTaskAdd(totalTasks.value) } - if (activeView.value === 'today') await loadTodayTaskSummary() + if (activeView.value === 'today') void loadTodayTaskSummary() taskComposeOpen.value = false toast('任务已添加') } catch (reason) { fail(reason) } @@ -229,7 +229,7 @@ const progressWidth = (completed: number, total: number) => `${total > 0 ? Math. const todayTaskProgressPercent = computed(() => progressWidth(todayTaskCompleted.value, todayTaskTotal.value)) const todayHabitProgressPercent = computed(() => progressWidth(todayHabitCompleted.value, todayHabitTotal.value)) const todayTaskProgressHint = computed(() => todayTaskTotal.value ? `还剩 ${todayOpenTasks.value} 件` : '今天暂无任务') -const todayHabitProgressHint = computed(() => todayHabitTotal.value ? `还差 ${Math.max(todayHabitTotal.value - todayHabitCompleted.value, 0)} 次` : '今天暂无习惯') +const todayHabitProgressHint = computed(() => todayHabitTotal.value ? `还有 ${Math.max(todayHabitTotal.value - todayHabitCompleted.value, 0)} 项未完成` : '今天暂无习惯') function scrollTodaySection(id: 'today-tasks' | 'today-habits') { document.getElementById(id)?.scrollIntoView({ behavior: 'smooth', block: 'start' }) } @@ -368,18 +368,20 @@ function isoAtLocalDayOffset(offset: number) { } async function loadTodayTaskSummary() { const token = ++todaySummaryLoadToken - const summaryTotal = async (completed: boolean) => { - const params = new URLSearchParams({ page: '1', page_size: '1' }) - params.set('due_from', isoAtLocalDayOffset(0)) - params.set('due_to', isoAtLocalDayOffset(1)) - params.set('completed', String(completed)) - const data = await api(`/tasks?${params}`) - return Number(data.total ?? data.items?.length ?? 0) - } - const [open, completed] = await Promise.all([summaryTotal(false), summaryTotal(true)]) - if (token !== todaySummaryLoadToken || activeView.value !== 'today') return - todayTaskCompleted.value = completed - todayTaskTotal.value = open + completed + try { + const summaryTotal = async (completed: boolean) => { + const params = new URLSearchParams({ page: '1', page_size: '1' }) + params.set('due_from', isoAtLocalDayOffset(0)) + params.set('due_to', isoAtLocalDayOffset(1)) + params.set('completed', String(completed)) + const data = await api(`/tasks?${params}`) + return Number(data.total ?? data.items?.length ?? 0) + } + const [open, completed] = await Promise.all([summaryTotal(false), summaryTotal(true)]) + if (token !== todaySummaryLoadToken || activeView.value !== 'today') return + todayTaskCompleted.value = completed + todayTaskTotal.value = open + completed + } catch { /* 概览统计失败不阻断今天页 */ } } async function loadOverdueTasks() { const params = new URLSearchParams() @@ -422,8 +424,10 @@ async function loadAll() { try { if (!navigationLoaded.value) await loadNavigation() await loadTasksPage() - if (activeView.value === 'today') await Promise.all([loadOverdueTasks(), loadTodayTaskSummary()]) - else overdueTasks.value = [] + if (activeView.value === 'today') { + await loadOverdueTasks() + void loadTodayTaskSummary() + } else overdueTasks.value = [] if (page.value > totalPages.value) { page.value = totalPages.value; await loadTasksPage() } } catch (reason) { fail(reason) } finally { loading.value = false } } @@ -469,7 +473,7 @@ async function patchTask(task: Task, patch: Partial) { async function toggle(task: Task) { try { await patchTask(task, { completed: !task.completed }) - if (activeView.value === 'today') await loadTodayTaskSummary() + if (activeView.value === 'today') void loadTodayTaskSummary() toast(task.completed ? '已重新打开' : '完成啦') } catch (reason) { fail(reason) } } @@ -642,7 +646,7 @@ async function saveTask() { } } if (selectedTask.value) selectedTask.value = { ...selectedTask.value, ...updated } - if (activeView.value === 'today') await loadTodayTaskSummary() + if (activeView.value === 'today') void loadTodayTaskSummary() toast('已保存') } catch (reason) { fail(reason) } } @@ -653,7 +657,7 @@ async function removeTask(task: Task) { tasks.value = tasks.value.filter((item) => item.id !== task.id && item.parent_id !== task.id) selectedTask.value = null mobileDetail.value = false - if (activeView.value === 'today') await loadTodayTaskSummary() + if (activeView.value === 'today') void loadTodayTaskSummary() toast('已移到回收站') } catch (reason) { fail(reason) } } @@ -776,13 +780,13 @@ onMounted(bootstrap)