refactor: simplify today progress summary
ci / gitleaks (push) Successful in 39s
ci / docker (push) Successful in 5m24s

This commit is contained in:
2026-09-08 18:27:33 +08:00
parent ba08a2fd34
commit bbb797c411
3 changed files with 15 additions and 19 deletions
+3 -14
View File
@@ -241,14 +241,10 @@ const activeName = computed(() => {
if (activeView.value === 'settings') return '设置与数据' if (activeView.value === 'settings') return '设置与数据'
return lists.value.find((item) => item.id === activeList.value)?.name || '收集箱' return lists.value.find((item) => item.id === activeList.value)?.name || '收集箱'
}) })
const todayCompletedTasks = computed(() => activeView.value === 'today' ? tasks.value.filter((task) => task.completed).length : 0)
const todayOpenTasks = computed(() => activeView.value === 'today' ? Math.max(todayTaskTotal.value - todayTaskCompleted.value, 0) : 0)
const todayHabitProgress = computed(() => `${todayHabitCompleted.value} / ${todayHabitTotal.value}`) const todayHabitProgress = computed(() => `${todayHabitCompleted.value} / ${todayHabitTotal.value}`)
const progressWidth = (completed: number, total: number) => `${total > 0 ? Math.min(100, Math.round(completed / total * 100)) : 0}%` const progressWidth = (completed: number, total: number) => `${total > 0 ? Math.min(100, Math.round(completed / total * 100)) : 0}%`
const todayTaskProgressPercent = computed(() => progressWidth(todayTaskCompleted.value, todayTaskTotal.value)) const todayTaskProgressPercent = computed(() => progressWidth(todayTaskCompleted.value, todayTaskTotal.value))
const todayHabitProgressPercent = computed(() => progressWidth(todayHabitCompleted.value, todayHabitTotal.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)} 项未完成` : '今天暂无习惯')
function scrollTodaySection(id: 'today-tasks' | 'today-habits') { function scrollTodaySection(id: 'today-tasks' | 'today-habits') {
document.getElementById(id)?.scrollIntoView({ behavior: 'smooth', block: 'start' }) document.getElementById(id)?.scrollIntoView({ behavior: 'smooth', block: 'start' })
} }
@@ -256,12 +252,6 @@ function updateTodayHabitSummary(value: { total: number; completed: number }) {
todayHabitTotal.value = value.total todayHabitTotal.value = value.total
todayHabitCompleted.value = value.completed todayHabitCompleted.value = value.completed
} }
const todayProgressText = computed(() => {
if (activeView.value !== 'today') return ''
if (!todayTaskTotal.value) return '今天还没有任务'
if (!todayOpenTasks.value) return '今天任务都清掉了'
return `还有 ${todayOpenTasks.value} 件事要处理`
})
const sourceTasks = computed(() => activeView.value === 'trash' ? trash.value : tasks.value) const sourceTasks = computed(() => activeView.value === 'trash' ? trash.value : tasks.value)
const visibleTasks = computed(() => { const visibleTasks = computed(() => {
const now = new Date() const now = new Date()
@@ -810,7 +800,7 @@ onMounted(bootstrap)
<main> <main>
<header class="topbar" :class="{ 'today-topbar': activeView==='today' }"> <header class="topbar" :class="{ 'today-topbar': activeView==='today' }">
<button class="icon" :aria-label="(sidebarCollapsed ? '展开' : '收起') + '菜单'" :aria-expanded="sidebarCollapsed ? 'false' : 'true'" @click="toggleSidebar"><Menu /></button> <button class="icon" :aria-label="(sidebarCollapsed ? '展开' : '收起') + '菜单'" :aria-expanded="sidebarCollapsed ? 'false' : 'true'" @click="toggleSidebar"><Menu /></button>
<div><h1>{{ activeName }}</h1><p v-if="activeView==='today'">{{ todayProgressText }}慢慢来</p></div> <div><h1>{{ activeName }}</h1></div>
<label v-if="['tasks','today','upcoming','trash'].includes(activeView)" class="search"><Search/><input v-model="query" placeholder="搜索任务…" aria-label="搜索任务"><kbd> K</kbd></label> <label v-if="['tasks','today','upcoming','trash'].includes(activeView)" class="search"><Search/><input v-model="query" placeholder="搜索任务…" aria-label="搜索任务"><kbd> K</kbd></label>
</header> </header>
<template v-if="['habits','settings'].includes(activeView)"> <template v-if="['habits','settings'].includes(activeView)">
@@ -820,11 +810,11 @@ onMounted(bootstrap)
<template v-else> <template v-else>
<section v-if="activeView==='today'" class="today-board" aria-label="今日进度"> <section v-if="activeView==='today'" class="today-board" aria-label="今日进度">
<button class="today-track today-task-track" type="button" aria-controls="today-tasks" @click="scrollTodaySection('today-tasks')"> <button class="today-track today-task-track" type="button" aria-controls="today-tasks" @click="scrollTodaySection('today-tasks')">
<span class="today-track-head"><strong>任务 {{ todayTaskCompleted }} / {{ todayTaskTotal }}</strong><small>{{ todayTaskProgressHint }}</small></span> <span class="today-track-head"><strong>任务 {{ todayTaskCompleted }} / {{ todayTaskTotal }}</strong></span>
<span class="today-track-rail" role="progressbar" aria-label="今日任务进度" aria-valuemin="0" :aria-valuemax="todayTaskTotal" :aria-valuenow="todayTaskCompleted"><i class="today-track-fill" :style="{ width: todayTaskProgressPercent }" /></span> <span class="today-track-rail" role="progressbar" aria-label="今日任务进度" aria-valuemin="0" :aria-valuemax="todayTaskTotal" :aria-valuenow="todayTaskCompleted"><i class="today-track-fill" :style="{ width: todayTaskProgressPercent }" /></span>
</button> </button>
<button class="today-track today-habit-track" type="button" aria-controls="today-habits" @click="scrollTodaySection('today-habits')"> <button class="today-track today-habit-track" type="button" aria-controls="today-habits" @click="scrollTodaySection('today-habits')">
<span class="today-track-head"><strong>习惯 {{ todayHabitProgress }}</strong><small>{{ todayHabitProgressHint }}</small></span> <span class="today-track-head"><strong>习惯 {{ todayHabitProgress }}</strong></span>
<span class="today-track-rail" role="progressbar" aria-label="今日习惯进度" aria-valuemin="0" :aria-valuemax="todayHabitTotal" :aria-valuenow="todayHabitCompleted"><i class="today-track-fill" :style="{ width: todayHabitProgressPercent }" /></span> <span class="today-track-rail" role="progressbar" aria-label="今日习惯进度" aria-valuemin="0" :aria-valuemax="todayHabitTotal" :aria-valuenow="todayHabitCompleted"><i class="today-track-fill" :style="{ width: todayHabitProgressPercent }" /></span>
</button> </button>
</section> </section>
@@ -878,7 +868,6 @@ onMounted(bootstrap)
</div></details> </div></details>
<div class="detail-actions"><button class="secondary" @click="saveTask">保存更改</button><button class="danger-text" @click="removeTask(selectedTask)"><Trash2/>移到回收站</button></div> <div class="detail-actions"><button class="secondary" @click="saveTask">保存更改</button><button class="danger-text" @click="removeTask(selectedTask)"><Trash2/>移到回收站</button></div>
</div> </div>
<div v-else-if="activeView==='today'" class="paper today-summary"><ListTodo/><b>{{ todayProgressText }}</b><p>点左侧任务看详情;没任务时就从今天加一件小事开始。</p><div class="today-summary-grid"><span><strong>{{ todayOpenTasks }}</strong>待处理</span><span><strong>{{ todayCompletedTasks }}</strong>已完成</span></div></div>
<div v-else class="paper"><ListChecks/><b>选中一个任务</b><p>日期优先级子任务和 Markdown 备注会出现在这里</p></div> <div v-else class="paper"><ListChecks/><b>选中一个任务</b><p>日期优先级子任务和 Markdown 备注会出现在这里</p></div>
</aside> </aside>
File diff suppressed because one or more lines are too long
+9 -2
View File
@@ -197,9 +197,14 @@ describe('task and habit row decoration', () => {
expect(app).toContain('role="progressbar"') expect(app).toContain('role="progressbar"')
expect(app).toContain(':aria-valuemax="todayTaskTotal"') expect(app).toContain(':aria-valuemax="todayTaskTotal"')
expect(app).toContain(':aria-valuenow="todayHabitCompleted"') expect(app).toContain(':aria-valuenow="todayHabitCompleted"')
expect(app).toContain('还有 ${Math.max(todayHabitTotal.value - todayHabitCompleted.value, 0)} 项未完成')
expect(app).toContain('任务 {{ todayTaskCompleted }} / {{ todayTaskTotal }}') expect(app).toContain('任务 {{ todayTaskCompleted }} / {{ todayTaskTotal }}')
expect(app).toContain('习惯 {{ todayHabitProgress }}') expect(app).toContain('习惯 {{ todayHabitProgress }}')
expect(app).not.toContain('const todayProgressText = computed')
expect(app).not.toContain('const todayTaskProgressHint = computed')
expect(app).not.toContain('const todayHabitProgressHint = computed')
expect(app).not.toContain('<p v-if="activeView===\'today\'">')
expect(app).not.toContain('class="paper today-summary"')
expect(app).not.toContain('today-summary-grid')
expect(app).toContain("scrollTodaySection('today-tasks')") expect(app).toContain("scrollTodaySection('today-tasks')")
expect(app).toContain("scrollTodaySection('today-habits')") expect(app).toContain("scrollTodaySection('today-habits')")
expect(app).not.toContain('<div class="today-stat"') expect(app).not.toContain('<div class="today-stat"')
@@ -217,7 +222,9 @@ describe('task and habit row decoration', () => {
expect(css).toContain('.today-track-fill{') expect(css).toContain('.today-track-fill{')
expect(css).toContain('.today-habit-track .today-track-fill{') expect(css).toContain('.today-habit-track .today-track-fill{')
expect(css).not.toContain('.today-stat{') expect(css).not.toContain('.today-stat{')
expect(css).toContain('.today-summary-grid{') expect(css).not.toContain('.today-summary{')
expect(css).not.toContain('.today-summary-grid{')
expect(css).not.toContain('.today-track-head small{')
expect(css).toContain('.empty-action{') expect(css).toContain('.empty-action{')
}) })