- README 补充回收站、批量编辑、合并导入、标签管理与 schema v3 说明 - 新增 ADR-007,记录软删除、可见性矩阵与合并冲突策略的取舍
This commit is contained in:
@@ -5,12 +5,14 @@
|
||||
- 固定三列:**待办 / 进行中 / 已完成**
|
||||
- 快速新增、拖拽排序、详情编辑、删除撤销;详情里可直接切换状态
|
||||
- **批量添加**:一次录入多行清单,整批共用目标列 / 优先级 / 标签 / 截止日期
|
||||
- **批量删除**:多选后整批删除,可一键撤销
|
||||
- **批量编辑**:多选后可统一移动列、改优先级、加/减标签、设截止日期、归档
|
||||
- **回收站**:删除是软删除,30 天内可随时恢复;也可永久删除或清空
|
||||
- 搜索与筛选(关键词 / 优先级 / 标签 / 今日到期 / 逾期)
|
||||
- **标签管理**:全局重命名、合并、删除标签,不必逐个任务改
|
||||
- **今日视图**:按紧急度分组汇总(逾期 / 今天到期 / 进行中 / 待办),含本周完成等统计
|
||||
- 键盘快捷键;任务卡片可用方向键换列与调序
|
||||
- **深色模式**:跟随系统 / 浅色 / 深色三态
|
||||
- 导出导入 JSON + 启动自动备份;**覆盖式导入或恢复快照前会自动留档**
|
||||
- 导出导入 JSON(**覆盖 / 合并**两种模式)+ 启动自动备份;覆盖或合并前都会自动留档
|
||||
- 已完成任务可批量归档,归档任务可在详情里随时恢复
|
||||
- **可安装为 PWA,支持离线使用**
|
||||
|
||||
@@ -25,7 +27,7 @@ npm run dev
|
||||
|
||||
打开终端提示的地址即可。首次进入是空看板,在任意列顶部的输入框里输入标题、回车即可创建任务。
|
||||
|
||||
## 批量添加与批量删除
|
||||
## 批量添加、批量编辑与回收站
|
||||
|
||||
工具栏的「批量添加」可以一次录入多条任务:清单里**一行一条**,整段粘贴即可;行首的 `-`、`*`、`1.` 这类列表符号会自动去掉,空行会被忽略。
|
||||
|
||||
@@ -33,9 +35,30 @@ npm run dev
|
||||
|
||||
不打开面板也行:在任意列的快速新增输入框里**粘贴多行文本**,会按行直接拆成多条任务(插入该列列首);单行粘贴仍是常规输入,不会被拦截。
|
||||
|
||||
要清理一批任务,点工具栏的「多选」:卡片变成可勾选的方框,点哪张选哪张,操作条上可以「全选 N 个」(只覆盖**当前筛选后可见**的任务)或「清空选择」,然后「删除 N 个」整批删掉。
|
||||
要批量处理,点工具栏的「多选」:卡片变成可勾选的方框,点哪张选哪张,操作条上可以「全选 N 个」(只覆盖**当前筛选后可见**的任务)或「清空选择」。第二行是批量编辑器:
|
||||
|
||||
批量添加与批量删除都会弹出带「撤销」的提示,误操作可以整批撤回(删除撤销会连原顺序一起还原)。多选期间拖拽会停用,避免顺手拖乱了顺序;筛选条件一变也会清空选择,保证「删掉的都是眼前看得见的」。
|
||||
- **移动到**:统一换到目标列,追加到该列末尾
|
||||
- **优先级**:低 / 中 / 高
|
||||
- **标签**:输入后「添加」或「移除」—— 是增删,不会覆盖每条任务原有的其它标签
|
||||
- **截止日**:可设置,也可清空
|
||||
- **归档**:批量归档,保留撤销入口
|
||||
|
||||
批量删除与批量归档仍提供 Toast 撤销;批量改属性不做撤销(与详情编辑一致),只提示「已更新 N 个任务」。
|
||||
|
||||
删除是**软删除**:任务进入顶部导航的「回收站」,保留 30 天后在下次打开时自动清理。回收站里可以逐条「恢复」或「永久删除」,也可以「清空回收站」(二次确认)。恢复会回到原列、原顺序,已归档的任务恢复后仍保持归档态。
|
||||
|
||||
多选期间拖拽会停用,避免顺手拖乱了顺序;筛选条件一变也会清空选择,保证「改掉的都是眼前看得见的」。
|
||||
|
||||
## 标签管理
|
||||
|
||||
标签下拉面板底部有「管理标签…」,打开后可以:
|
||||
|
||||
- 查看每个标签被多少任务使用(只统计未归档、未删除的任务)
|
||||
- **重命名**:所有任务上的该标签一次性替换,其它标签不受影响
|
||||
- **合并**:把两个标签并成一个,任务上的标签自动去重
|
||||
- **删除**:只从任务上移除标签,不删除任务
|
||||
|
||||
操作后会提示影响了多少个任务。回收站里的任务不参与这些改写。
|
||||
|
||||
## 脚本
|
||||
|
||||
@@ -124,7 +147,12 @@ python scripts/generate-icons.py
|
||||
2. **覆盖前自动留档**:导入 JSON 或从快照恢复会整份替换数据,执行前会先把当前数据写一份快照,选错文件或选错备份也能退回去。
|
||||
3. **手动导出**:「备份」面板 → 导出为 JSON,文件名形如 `kanban-2026-10-18.json`。
|
||||
|
||||
导入是**覆盖式**的:选中文件后会先校验,再显示将被覆盖的任务数量,需要二次确认才会执行。确认覆盖前会自动备份当前数据;文件不合法时不会改动任何现有数据。
|
||||
导入支持两种模式,选中文件后会先校验并显示预览,需要二次确认才会执行:
|
||||
|
||||
- **覆盖导入**:替换当前全部数据,并显示将被覆盖的任务数量
|
||||
- **合并导入**:按 `id` 合并,同一条任务以 `updatedAt` 较新的一方为准;文件里新增的任务追加到对应列末尾,本地独有的任务保留(合并不是同步,不会删本地数据)。预览会显示「新增 X 个 / 更新 Y 个 / 保持 Z 个」
|
||||
|
||||
两种模式在确认前都会自动把当前数据写一份快照;文件不合法时不会改动任何现有数据。导出默认包含回收站里的任务,这样换设备后回收站也能一并带走。
|
||||
|
||||
任务详情里的「状态」可以直接切换待办 / 进行中 / 已完成,不必回到看板拖拽。编辑后如果没保存就关闭,抽屉会先提醒,不会静默丢弃草稿。
|
||||
|
||||
@@ -184,7 +212,7 @@ src/
|
||||
├── router/ # 路由定义(看板 / 今日)
|
||||
├── stores/ # Pinia:任务、筛选、提示
|
||||
├── types/ # 领域类型与常量
|
||||
├── utils/ # 纯函数:排序、筛选、日期、归档、拖拽解析、今日分组、统计
|
||||
├── utils/ # 纯函数:排序、筛选、日期、归档、拖拽解析、今日分组、统计、任务补丁、合并、标签
|
||||
└── views/ # 页面级组件(BoardView / TodayView)
|
||||
docs/
|
||||
├── adr.md # 架构决策记录
|
||||
@@ -205,7 +233,8 @@ E2E 需要真实浏览器,默认不放进 CI(要求 runner 预装 Chrome)
|
||||
|
||||
- **单一数据源**:Pinia store 是内存态的唯一来源,所有变更经由 `TaskRepository` 落盘;拖拽也只消费事件,不接管数据。看板与今日视图共享同一份数据。
|
||||
- **持久化端口**:`TaskRepository` 采用「整份快照读写」(`load` / `save`),而非细粒度 CRUD。要换成 IndexedDB 或后端 API,只需实现同一接口。
|
||||
- **显式迁移**:落盘结构带 `schemaVersion`,升级规则登记在 `MIGRATIONS` 表中。当前版本为 2(v1 → v2 为归档功能补 `archivedAt`)。
|
||||
- **显式迁移**:落盘结构带 `schemaVersion`,升级规则登记在 `MIGRATIONS` 表中。当前版本为 3(v1 → v2 补 `archivedAt`,v2 → v3 补 `deletedAt` 以支持回收站)。
|
||||
- **软删除是数据状态,不是筛选维度**:`deletedAt` 在 `activeTasks` 层统一剔除,列、计数、统计、今日视图、标签下拉都消费它;回收站单独由 `trashTasks` 提供。
|
||||
- **损坏数据先备份再报错**:读取失败时把原始内容另存到 `kanban.tasks.corrupt.<时间戳>`,不覆盖用户数据。
|
||||
- **视图与数据解耦**:今日视图只做「分组 + 排序」,全部逻辑在 `src/utils/today.ts` 与 `stats.ts` 的纯函数里,组件不持有业务规则。
|
||||
|
||||
@@ -213,7 +242,7 @@ E2E 需要真实浏览器,默认不放进 CI(要求 runner 预装 Chrome)
|
||||
|
||||
## 测试
|
||||
|
||||
- 单元测试:605 个用例,覆盖 `src/` 下的纯逻辑与组件行为,行覆盖率约 96%。
|
||||
- 单元测试:705 个用例,覆盖 `src/` 下的纯逻辑与组件行为。
|
||||
- 端到端测试:28 个用例,分两组运行 —— 交互类跑 dev server,PWA 类跑生产构建(Service Worker 只在构建产物中生成)。覆盖「新增 → 拖拽 → 完成 → 刷新保持」「批量添加」「多选批量删除 + 撤销」「导出 → 清空 → 导入还原」「删除撤销」「搜索筛选」「键盘快捷键与方向键移动」「深色模式切换」「今日视图」「离线打开」等主链路,每个用例使用独立的浏览器上下文。
|
||||
|
||||
```bash
|
||||
@@ -235,10 +264,11 @@ PLAYWRIGHT_CHANNEL=chromium npm run test:e2e # 用自带 Chromium(需先 npx
|
||||
## 已知限制
|
||||
|
||||
- 单用户、单设备,无协作与同步能力(离线可用,但多设备之间不会同步)。
|
||||
- 标签是字符串数组,重命名标签需要逐个任务修改。
|
||||
- 看板列固定为三列,不支持自定义。
|
||||
- 归档阈值固定为「已完成超过 7 天」,暂不可配置。
|
||||
- 今日视图的分组规则固定(逾期 > 今天到期 > 进行中 > 待办),不可自定义。
|
||||
- 统计只覆盖本周完成数等基础指标,没有趋势图或历史留存。
|
||||
- 深色模式只跟随系统或手动三态切换,没有按时间段自动切换。
|
||||
- 删除只提供 5 秒内的 Toast 撤销,还没有回收站;误删超过窗口后只能从自动备份里找。
|
||||
- 回收站固定保留 30 天,没有搜索 / 筛选,只有「按删除时间」一种顺序。
|
||||
- 批量改属性不提供撤销(标签是增删语义,误改可以再改回来);导入冲突策略固定为「`updatedAt` 新者胜」,不可配置。
|
||||
- 标签还没有颜色,重命名 / 合并会同步落盘但不会保留旧名映射。
|
||||
|
||||
+48
@@ -155,3 +155,51 @@ MVP 有「启动快照 + 手动导出」两道保护,但两个整份覆盖的
|
||||
- `persistent` 现在会随写入成功/失败翻转,UI 可据此判断「改动是否真的落盘」。
|
||||
- 关闭详情抽屉的默认行为从「直接关闭」变为「有改动先确认」,相关组件测试已同步调整。
|
||||
- 新增 `.gitea/workflows/ci.yml`,把 lint / typecheck / test / build 纳入推送与合并请求检查。
|
||||
|
||||
---
|
||||
|
||||
## ADR-007 · 删除改为软删除,导入提供覆盖 / 合并两种模式
|
||||
|
||||
**背景**
|
||||
|
||||
删除此前只有 5 秒内的 Toast 撤销,超过窗口后只能去自动备份里碰运气;而多设备、多次导出之后,
|
||||
覆盖式导入又只能二选一,「把两份数据拼起来」需要手工处理。本批同时解决这两件事,并顺带把多选
|
||||
从「批量删除工具」升级为「批量编辑器」。
|
||||
|
||||
**结论**
|
||||
|
||||
1. `Task` 增加 `deletedAt`,`schemaVersion` 升到 3;删除写 `deletedAt`(软删除),任务进入回收站,
|
||||
30 天后在启动时自动清理。永久删除只允许作用于回收站里的任务,且需要二次确认。
|
||||
2. 软删除是**数据状态**而不是筛选维度:store 提供 `activeTasks`,列、计数、统计、今日视图、
|
||||
标签下拉、归档候选全部消费它;`matchesFilter` 仍然只负责归档可见性。回收站数据由 `trashTasks`
|
||||
单独提供,按删除时间倒序。
|
||||
3. 恢复只清除 `deletedAt`,保留原 `sortOrder` 与 `archivedAt`,因此位置和归档态都会还原。
|
||||
导出仍包含已删除任务,保证换设备后回收站也能带走。
|
||||
4. 批量编辑与单条编辑共用 `applyTaskPatch`(`src/utils/taskPatch.ts`),状态进出「已完成」、
|
||||
`updatedAt` 刷新、标签去重、标题回退只有一份规则。批量标签采用**增 / 删**语义,
|
||||
避免统一加标签时把每条任务原有的其它标签抹掉。
|
||||
5. 导入增加合并模式:按 `id` 匹配,同 id 以 `updatedAt` 较新的一方为准;文件新增项追加到对应列末尾
|
||||
并重算 `sortOrder`;本地独有任务保留;两种模式执行前都调用同一套快照逻辑。
|
||||
6. 标签治理(重命名 / 合并 / 删除)放在 `src/utils/tags.ts` 的纯函数里,store 只负责找出真正变化的
|
||||
任务、刷新 `updatedAt` 并一次落盘。回收站里的任务不参与改写。
|
||||
|
||||
**被否决的方案**
|
||||
|
||||
- _把 `deletedAt` 塞进 `TaskFilter`_:回收站不是「筛掉一部分」,而是一条独立的数据状态。
|
||||
放进筛选会让每个调用点都要记得带上「排除已删除」,漏一处就会把删除项泄漏到看板或统计里。
|
||||
改为在 `activeTasks` 层统一剔除,失败模式从「N 处可能漏」收敛为「一处必须对」。
|
||||
- _给删除加二次确认_:删除是高频操作,弹窗会拖慢节奏;软删除 + 回收站已经提供了比确认框更好的退路。
|
||||
- _批量改属性做 `[{id, before}]` 快照式撤销_:需要额外的内存态与 UI 语义,收益低于成本;
|
||||
标签是增删语义,改错了再改回来即可。批量删除 / 归档仍有 Toast 撤销。
|
||||
- _合并时对整列 `sortOrder` 做 normalize_:会悄悄重排用户已有数据。新增项追加列尾已经足够,
|
||||
既有冲突留给后续显式整理。
|
||||
- _给回收站做搜索 / 筛选_:列表按删除时间倒序已经能覆盖「刚删错」这个主场景,先不加。
|
||||
|
||||
**影响**
|
||||
|
||||
- 数据面变大:回收站会占用 localStorage 配额,靠 30 天自动清理与手动清空兜底;导出文件也会包含
|
||||
已删除任务,体积略增。
|
||||
- 所有「看板语义」的读取点必须走 `activeTasks`。新增读取点时若直接用 `tasks`,会把已删除任务
|
||||
泄漏到 UI;可见性矩阵已写进测试(列、统计、标签、今日视图、归档候选)。
|
||||
- 迁移链新增 `2 → 3`,且 `parsePersistedState` / 快照恢复共用同一套解析,旧备份仍可读。
|
||||
- 详情抽屉的编辑对象改为在 `activeTasks` 里查找,删除后抽屉会立即关闭,而不是停留在一条已删除的任务上。
|
||||
|
||||
Reference in New Issue
Block a user