- 自动归档改为 doneAt + autoArchive 到期,只判定顶层任务,到期整树归档 - 手动归档/恢复提升到根父任务,子任务完全跟随父任务 - 新增 normalizeArchiveTree 修复历史父子归档不一致 - 移除按列保留窗口的显示过滤(前后端实现删除,T-FL-01~15 废止) - 列 retention 字段仅兼容旧数据保留,不再参与判定 - 已归档查询返回归档子任务,删除提示可正确显示连带条数
This commit is contained in:
+32
-40
@@ -23,7 +23,7 @@
|
||||
| --- | --- | --- |
|
||||
| 状态枚举 | `todo` / `doing` / `done` | 未开始 / 执行中 / 完成 |
|
||||
| 列 | `BoardColumn` 实体,按 `sortOrder` 升序 | 默认 `Plan/Doing/Action/Done` |
|
||||
| 保留选项 | `never` / `today` / `3d` / `week` / `month` / `forever` | 永不显示 / 当天 / 3 天 / 本周 / 本月 / 永久显示 |
|
||||
| 自动归档档位 | `3d` / `1w` / `1m` / `never` | 完成后 3 天 / 一周 / 一月 / 永不 |
|
||||
| 视图 | `list` / `board` | 设备端记忆 |
|
||||
| 设备端键 | `iboard_task_prefs` | `{ lastProjectId, viewMode: { [projectId]: 'list'\|'board' } }` |
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
| POST | `/api/projects/:id/members` | 加成员(个人项目 400) |
|
||||
| DELETE | `/api/projects/:id/members/:uid` | 移成员 / 自己退出 |
|
||||
| GET/POST | `/api/projects/:id/columns` | 列列表 / 新增列 |
|
||||
| PUT | `/api/columns/:id` | 改名 / 改绑定 / 改保留选项 |
|
||||
| PUT | `/api/columns/:id` | 改名 / 改绑定 |
|
||||
| DELETE | `/api/columns/:id` | 删列(需 `moveToColumnId`,最后列 400) |
|
||||
| PUT | `/api/projects/:id/columns/order` | 列排序 |
|
||||
| GET | `/api/projects/:id/tasks` | 任务列表(含子任务与列信息) |
|
||||
@@ -60,7 +60,7 @@
|
||||
| T-VW-03 | `prefs.js` → `viewMode[projectId]` | 按项目 id 分键存储,A/B 项目互不影响 |
|
||||
| T-VW-04 | `ProjectView` 挂载时读 `prefs.getViewMode(projectId)` | 有值用之;无值走 T-VW-05 默认 |
|
||||
| T-VW-05 | 默认值 `'list'` | 新项目首次进入为列表 |
|
||||
| T-VW-06 | `localStorage.iboard_task_prefs` | **不落库、不同步**;换设备不继承(与 T-FL-15 的项目级配置区分) |
|
||||
| T-VW-06 | `localStorage.iboard_task_prefs` | **不落库、不同步**;换设备不继承 |
|
||||
| T-VW-07 | `prefs.getLastProjectId()` / `setLastProjectId()` | 进入 `/task` 时读取;无记录或记录的项目已不可见 ⇒ 回落个人默认项目 |
|
||||
| T-VW-08 | `TaskPage` 首屏上部 `RecentProjects` 条 | 取最近访问的 3 个项目(按设备端访问时间倒序),末尾「更多项目」入口 → `/task/list`(完整项目列表 `ProjectList`,从「更多」进入) |
|
||||
| T-VW-09 | `TaskPage` 首屏下部直接内嵌 `ProjectView` | 当前项目 = 上次访问项目(无记录 ⇒ 个人默认项目);点首屏项目卡片切换当前项目,下部整体切换,不跳转页面 |
|
||||
@@ -109,32 +109,22 @@
|
||||
| T-BD-09 | 初始化默认值 | `Plan=todo`、`Doing=doing`、`Done=done`、`Action=null` |
|
||||
| T-BD-10 | 项目级配置 | 任一成员可改;不同项目独立 |
|
||||
| T-BD-11 | 配置变更不回溯 | 保存配置时**不触发**任何任务更新语句 |
|
||||
| T-BD-12 | 保存后返回最新列列表 | 前端整体替换 + 重算可见集合,无需刷新 |
|
||||
| T-BD-12 | 保存后返回最新列列表 | 前端整体替换,无需刷新 |
|
||||
| T-BD-13 | `resolveStatus()` 首行判 `parentId` | 子任务直接跳过全部联动 |
|
||||
|
||||
---
|
||||
|
||||
## 4. 已完成任务显示控制(T-FL)
|
||||
## 4. 已完成任务显示控制(T-FL,已移除)
|
||||
|
||||
| 编号 | 设计落点 | 实现要点 |
|
||||
| --- | --- | --- |
|
||||
| T-FL-01 | `BoardColumn.retention` | 每列独立字段 |
|
||||
| T-FL-02 | `ColumnSettings` 下拉 6 项 | 固定枚举,无自由输入 |
|
||||
| T-FL-03 | `retention='forever'` | 判定恒为可见 |
|
||||
| T-FL-04 | `retention='never'` | 已完成任务恒不可见 |
|
||||
| T-FL-05 | `retention='today'` | `doneAt >= 今天 00:00` |
|
||||
| T-FL-06 | `retention='3d'` | `doneAt >= 今天-2天 00:00` |
|
||||
| T-FL-07 | `retention='week'` | `doneAt >= 本周一 00:00` |
|
||||
| T-FL-08 | `retention='month'` | `doneAt >= 本月1日 00:00` |
|
||||
| T-FL-09 | `task-domain/retention.js` + 前端定时重算 | 超出窗口自动隐藏,无需操作 |
|
||||
| T-FL-10 | 判定字段 `Task.doneAt` | 与当前列无关;取消完成时 `doneAt=null` |
|
||||
| T-FL-11 | 前端可见性统一走同一函数 | 列表与看板共用 `isTaskVisible(task, column)`;列表不分组但归属不变 |
|
||||
| T-FL-12 | 判定前置 `status !== 'done'` | 未完成任务恒可见 |
|
||||
| T-FL-13 | 纯展示层过滤 | 不修改任何字段;接口返回全量,前端过滤(或服务端按需过滤但不改数据) |
|
||||
| T-FL-14 | 列计数取过滤后集合长度 | 列头计数与卡片数同源,杜绝不一致 |
|
||||
| T-FL-15 | 存在 `BoardColumn` 上 | 项目级共享,非个人偏好(对比 T-VW-06 设备端) |
|
||||
|
||||
> **实现细节**:保留判定在前后端各有一份实现(服务端用于分页/统计,前端用于即时过滤),但**必须共用同一口径常量**,跨度边界由 `date.js` 单测覆盖。
|
||||
> **2026-11-10 变更**:取消「隐藏」这一中间状态。任务只有两种状态:
|
||||
> **显示**(在主列表/看板中)或**归档**(在已归档列表中)。
|
||||
>
|
||||
> - 不再按看板列的保留窗口隐藏已完成任务;
|
||||
> - `BoardColumn.retention` 字段仅为兼容旧数据保留,**不再参与任何显示或归档判定**;
|
||||
> - 已完成任务在手动归档或项目自动归档到期前,始终留在主列表/看板;
|
||||
> - 原 T-FL-01 ~ 15 全部废止,不再有前后端保留窗口过滤实现。
|
||||
>
|
||||
> 归档规则见 §15。子任务完全跟随父任务:要么一起显示,要么一起归档。
|
||||
|
||||
---
|
||||
|
||||
@@ -314,21 +304,21 @@
|
||||
| T-EX-15 | 拖到自身或后代 | 拒绝 + Toast |
|
||||
| T-EX-16 | 删除有任务的列 | 二次确认 + 迁移到指定列(默认相邻)+ 重新裁决 |
|
||||
| T-EX-17 | 删除最后一列 | 400「至少保留一列」 |
|
||||
| T-EX-18 | 跨周期当场消失 | 定时重算 + 退场动画 + 重排 |
|
||||
| T-EX-18 | 跨周期不再隐藏(原保留窗口需求已移除) | 已完成任务保持显示,直到手动归档或自动归档到期 |
|
||||
| T-EX-19 | 达到列数上限 | 拒绝新增 + 提示 |
|
||||
|
||||
---
|
||||
|
||||
## 15. 任务归档(T-ARC)
|
||||
|
||||
> 归档与 T-FL 显示控制的分层:**隐藏 = 展示过滤(可逆、不落库)**;**归档 = 移出主工作集(落库、可恢复)**。
|
||||
> 自动归档的倒计时起点是任务**被隐藏的时刻**(由 `doneAt + 列保留窗口` 推导,不新增 hiddenAt 字段)。
|
||||
> 任务只有「显示」与「归档」两种状态,不再存在「隐藏」中间态。
|
||||
> 自动归档倒计时起点是任务的**完成时刻** `doneAt`,到期后整棵任务树一起归档。
|
||||
|
||||
### 15.1 数据
|
||||
|
||||
| 落点 | 说明 |
|
||||
| --- | --- |
|
||||
| `Project.autoArchive VARCHAR(8) NOT NULL DEFAULT 'never'` | 自动归档档位:`3d` / `1w` / `1m` / `never`;项目级共享(同 T-FL-12 口径) |
|
||||
| `Project.autoArchive VARCHAR(8) NOT NULL DEFAULT 'never'` | 自动归档档位:`3d` / `1w` / `1m` / `never`;项目级共享 |
|
||||
| `Task.archived BOOLEAN NOT NULL DEFAULT false` | 归档标记;归档**不迁移表**,主查询统一追加 `archived = false` |
|
||||
| `Task.archivedAt DATETIME(3) NULL` | 归档时刻(查询过滤与排序键) |
|
||||
| `Task.archiveSource VARCHAR(8) NULL` | `'manual'` / `'auto'`,溯源用 |
|
||||
@@ -339,7 +329,7 @@
|
||||
|
||||
| 接口 | 说明 |
|
||||
| --- | --- |
|
||||
| `POST /api/tasks/:id/archive` | 手动归档:父任务连带全部后代置 `archived/archivedAt/archiveSource='manual'`;幂等(已归档直接返回当前态) |
|
||||
| `POST /api/tasks/:id/archive` | 手动归档:以整棵树为单位置 `archived/archivedAt/archiveSource='manual'`;传子任务 id 也提升到根父任务;幂等 |
|
||||
| `POST /api/tasks/:id/unarchive` | 恢复:父任务连带后代清除归档三字段;原列因 `ON DELETE RESTRICT` 必存在,状态保持不变 |
|
||||
| `GET /api/projects/:id/tasks/archived?keyword&kind&columnId&from&to&cursor&limit` | 归档查询:`keyword` 标题 LIKE、`kind`、`columnId`、`from/to`(归档日期,含边界);`limit` 默认 20、≤100;游标 = `archivedAt+id` 复合降序,返回 `{ items, nextCursor }`,`nextCursor` 为空即到底 |
|
||||
| `PUT /api/projects/:id` | 增接受 `autoArchive`,枚举校验(非法 400) |
|
||||
@@ -347,19 +337,20 @@
|
||||
|
||||
### 15.3 自动归档执行
|
||||
|
||||
- **归档到期判定**:`due = 隐藏时刻 + autoArchive 档位`;隐藏时刻 = `doneAt + 列保留窗口`(复用 `retentionStart` 口径,含 `today/3d/week/month`;`forever` 列任务永不隐藏、不进入自动归档)。
|
||||
- **归档到期判定**:`due = doneAt + autoArchive 档位`(`3d` = 72 小时、`1w` = 7 天、`1m` = 上海日历月 +1;`never` = 不自动归档)。
|
||||
- **判定范围**:只看**顶层任务**(`parentId IS NULL`)且 `status = 'done'` / `doneAt` 非空 / 未归档。子任务不单独判定。
|
||||
- **整树归档**:顶层任务到期后,该任务与其全部子任务一起置 `archived/archivedAt/archiveSource='auto'`,不会出现父任务归档而子任务仍显示的情况。
|
||||
- **执行时机(双保险)**:
|
||||
1. **读时惰性**:加载项目任务时对该项目先执行一轮到期归档(保证用户看到的数据与判定一致,刚到期的任务当场消失);
|
||||
2. **每小时 cron 兜底**:扫描全部 `autoArchive != 'never'` 项目的到期 done 任务批量归档(`archiveSource='auto'`)。
|
||||
- **幂等**:`archived = false` 且 `status = 'done'` 且 `doneAt` 非空才进入判定;重复执行无副作用。
|
||||
- **批量写**:cron 用 `updateMany`(按到期集合),读时惰性用单项目范围 `updateMany`。
|
||||
1. **读时惰性**:加载项目任务时对该项目先执行一轮到期归档;
|
||||
2. **每小时 cron 兜底**:扫描全部项目的到期顶层任务批量归档,并修复历史父子归档状态不一致。
|
||||
- **幂等**:重复执行无副作用;批量写使用 `updateMany`。
|
||||
|
||||
### 15.4 前端
|
||||
|
||||
| 落点 | 说明 |
|
||||
| --- | --- |
|
||||
| 任务 `⋯` 菜单 | 新增「归档」(`Dialog.confirm`,含子任务时提示连带条数);成功后列表/看板乐观移除 |
|
||||
| 项目管理 | 「归档设置」分区:`Selector` 四档(3 天后/一周后/一月后/永不),保存即生效 |
|
||||
| 任务 `⋯` 菜单 | 新增「归档」(`Dialog.confirm`,含子任务时提示连带条数);子任务上点归档会提升到根父任务,整棵树一起处理 |
|
||||
| 项目管理 | 「归档设置」分区:完成后自动归档四档(3 天后/一周后/一月后/永不),保存即生效 |
|
||||
| 项目视图头部 | 项目栏新增「已归档」入口 → 全屏弹层:过滤条(**关键词 / 看板列 / 归档时段**;时段含「本周 / 本月 / 本季度」快捷项与自定义区间;条件编辑后点「筛选」统一提交,另有「重置」;**不提供类型过滤**)+ 已应用条件标签(可单独撤销)与命中条数 + 分页「加载更多」+ 行内「恢复 / 删除」 |
|
||||
| 主视图 | 列表/看板无需感知归档(数据源已排除);恢复后经 `load()` 回到原位 |
|
||||
|
||||
@@ -367,9 +358,10 @@
|
||||
|
||||
| 场景 | 处理 |
|
||||
| --- | --- |
|
||||
| 归档父任务时新增/恢复子任务 | 子任务随父判定:父 archived 则子不单独出现在主列表(查询按父排除) |
|
||||
| 子任务单独归档/恢复 | 不允许单独变化:接口与前端都会提升到根父任务,整棵树一起归档或恢复 |
|
||||
| 历史数据父子不一致 | 服务端归档扫描时执行 `normalizeArchiveTree`,子任务归档态强制跟随父任务 |
|
||||
| 自动归档期间用户正在编辑该任务 | 详情弹层保存正常(归档不锁写);保存后任务仍在归档集 |
|
||||
| 恢复后任务再次到期隐藏 | 重新进入自动归档倒计时(`doneAt` 未变则可能立即再次到期,属预期) |
|
||||
| 恢复后任务再次到期 | 重新进入自动归档倒计时(`doneAt` 未变则可能立即再次到期,属预期) |
|
||||
| 「永不」档位 | 不做任何自动归档;手动归档不受影响 |
|
||||
| 拷贝任务 | 拷贝件不继承归档态(`copyTask` 不复制 archived 三字段) |
|
||||
|
||||
@@ -382,7 +374,7 @@
|
||||
| 视图体系 | T-VW-01 ~ 10 | 10 | §1 |
|
||||
| 看板列管理 | T-COL-01 ~ 10 | 10 | §2 |
|
||||
| 列-状态绑定 | T-BD-01 ~ 16 | 16 | §3 |
|
||||
| 已完成显示控制 | T-FL-01 ~ 15 | 15 | §4 |
|
||||
| 已完成显示控制(已移除) | T-FL-01 ~ 15 | 15(废止) | §4 |
|
||||
| 任务字段体系 | T-TK-01 ~ 13 | 13 | §5 |
|
||||
| 负责人 & 成员 | T-AS-01 ~ 07 | 7 | §6 |
|
||||
| 子任务体系 | T-ST-01 ~ 15 | 15 | §7 |
|
||||
@@ -396,4 +388,4 @@
|
||||
| 任务归档 | T-ARC-01 ~ 08 | 8 | §15 |
|
||||
| **合计** | — | **157** | — |
|
||||
|
||||
> 需求文档共 **157 条**需求点,本文逐条给出设计落点,覆盖率 **157/157**。(其中 `T-BD-14~16`、`T-COL-*`、`T-EX-18~19`、`T-VW-08~10`、`T-PJ-11/12`、`T-UI-11`、`T-ARC-*` 为评审后新增,编号不连续,非笔误。)
|
||||
> 需求文档共 **157 条**需求点(其中 `T-FL-01~15` 已于 2026-11-10 废止,不再有隐藏中间态),本文逐条给出设计落点。(其中 `T-BD-14~16`、`T-COL-*`、`T-EX-18~19`、`T-VW-08~10`、`T-PJ-11/12`、`T-UI-11`、`T-ARC-*` 为评审后新增,编号不连续,非笔误。)
|
||||
|
||||
Reference in New Issue
Block a user