feat(board): 展示任务时间,并修正已完成任务的逾期基准
CI / verify (push) Successful in 1m43s
CI / 部署到服务器 (push) Successful in 26s

时间展示(ADR-008):
- 详情抽屉新增只读「时间」区块:创建 / 更新常驻,完成时间缺失时标注「未完成」,归档任务追加归档时间;时间不进入草稿与 dirty 判定
- 已完成卡片在元信息行右侧显示「完成于 M月D日」,卡片根元素 title 汇总创建 / 完成 / 归档时间(精确到分钟)
- 回收站条目补创建时间,删掉内联 formatTime,统一走 @/utils/date
- date.ts 新增 formatDateTime(YYYY-MM-DD HH:mm)与 formatCompactDate(同年 M月D日 / 跨年带年份),空值与非法时间戳返回 null

逾期基准修复:
- 新增 formatDueDateForTask:未完成任务仍以「今天」推算;已完成任务改以「完成日」推算,19 号截止、19 号当天完成的任务不会在 20 号显示「逾期 1 天」,完成时确实超期则定格为「逾期 N 天完成」,不再随日期增长
- 新增 localDateOf:completedAt 存 UTC 时间戳,按本地时区取日期,避免跨日偏差
- TaskCard 改用 dueLabel computed 取代模板内直接调用 formatDueDate;颜色仍由 isOverdue 决定,已完成卡片保持中性色

测试:date / TaskCard 补时间格式化与逾期基准用例(当天完成、提前完成、完成时超期定格、缺 completedAt、跨年),全量 728 单测通过;vue-tsc 与 eslint 干净。
This commit is contained in:
chenshoulin
2026-10-20 09:23:29 +08:00
parent a269694834
commit b39267fba7
10 changed files with 392 additions and 11 deletions
+39
View File
@@ -203,3 +203,42 @@ MVP 有「启动快照 + 手动导出」两道保护,但两个整份覆盖的
泄漏到 UI;可见性矩阵已写进测试(列、统计、标签、今日视图、归档候选)。
- 迁移链新增 `2 → 3`,且 `parsePersistedState` / 快照恢复共用同一套解析,旧备份仍可读。
- 详情抽屉的编辑对象改为在 `activeTasks` 里查找,删除后抽屉会立即关闭,而不是停留在一条已删除的任务上。
---
## ADR-008 · 任务时间只读展示,不参与排序与筛选
**背景**
`Task` 从 T03 起就有 `createdAt` / `updatedAt` / `completedAt`,后者还承担「本周完成」统计与归档候选的判断,
但界面上没有任何入口能把它们读出来 —— 想知道任务哪天创建、哪天完成,只能导出 JSON 自己找。
时间字段是只写不读的,等于白存。
**结论**
1. 详情抽屉底部新增只读「时间」区块:创建 / 更新常驻,完成时间在 `completedAt` 为空时显示「未完成」,
归档任务追加一行归档时间。时间不属于可编辑字段,不进入草稿与 dirty 判定。
2. 已完成卡片在元信息行右侧显示 `完成于 M月D日`(跨年补年份);未完成卡片不渲染该行,避免给待办增加噪音。
3. 卡片根元素带 `title`,汇总创建 / 完成 / 归档时间(精确到分钟)。悬停即得,不占版面;
移动端与键盘用户由详情抽屉兜底。
4. 回收站条目同时显示创建时间与删除时间,原先内联的 `formatTime` 被 `@/utils/date` 的 `formatDateTime` 取代。
5. 格式化统一收敛到 `src/utils/date.ts`:`formatDateTime` 输出 `YYYY-MM-DD HH:mm`,`formatCompactDate`
按是否跨年输出 `M月D日` / `YYYY年M月D日`。两者对空值与非法时间戳返回 `null`,由调用方决定占位符
—— 界面上永远不会出现 `Invalid Date`。
**被否决的方案**
- _卡片同时显示创建时间_:待办卡片的元信息行已有优先级、截止日期与标签,再加一行会挤掉真正的决策信息。
创建时间对「先做哪件」几乎没有影响,放进 `title` 与详情抽屉足够。
- _增加「按创建 / 完成时间排序」开关_:完成列的顺序由手动 `sortOrder` 表达,再引入第二种排序会让
「看到的顺序」与「拖拽写回的顺序」产生两个真相;当前也没有对应使用场景。
- _用相对时间(「3 天前」)_:文案依赖渲染时刻,页面开一整天就会和实际完成日对不上;
复盘场景下具体日期更有用。
- _提升 `schemaVersion` 做迁移_:字段早已存在,且 `coerceTask` 已把它们收敛为字符串或 `null`,无需迁移。
**影响**
- 时间展示纯只读;`completedAt` 的写入仍收敛在状态流转处 —— 单条 / 批量编辑走 `applyTaskPatch`,
拖拽换列走 `moveTask`,两者规则一致(进入「已完成」写时间、离开即清空),展示值与状态不会互相矛盾。
- 新增两个纯函数与对应单测;`TrashPanel` 少了一个私有格式化函数。
- 卡片 `title` 是纯提示信息,不参与可访问性命名(`aria-label` 仅在多选态给出),读屏语义不变。