Files
Kanban/README.md
T
chenshoulin 4e064e82ea feat: 个人轻量看板工具 MVP
从零实现一个 local-first 的个人任务看板,数据只存在浏览器本地,不依赖后端。

功能
- 固定三列看板(待办 / 进行中 / 已完成),支持拖拽改状态与列内排序
- 快速新增、详情编辑、删除撤销、已完成归档
- 搜索与筛选(关键词 / 优先级 / 标签 / 今日到期 / 逾期)
- 今日视图:按紧急度分组(逾期 > 今天到期 > 进行中)+ 统计卡片
- 导出导入 JSON;启动时自动留快照,保留最近 3 份
- 键盘快捷键(N / 「/」/ ? / Esc)
- PWA:可安装、离线可用、更新提示

技术要点
- 持久化采用 TaskRepository 端口 + 整份快照读写,schemaVersion 迁移表
  显式登记升级规则(当前 v2,v1 -> v2 为归档功能补 archivedAt)
- 同列排序用相邻中点插入,间距不足时按列 normalize,避免浮点精度耗尽
- 拖拽只消费 Sortable 的事件,store 保持唯一数据源,不接管数据
- 数据损坏时先备份到 *.corrupt.<时间戳> 再报错,不覆盖用户数据
- 引入 vue-router 拆分看板与今日两个视图(见 docs/adr.md ADR-005)

验证
- 单元测试 437 个(33 个文件),行覆盖率 96.8%
- 端到端测试 23 个(Playwright),含真实拖拽与断网离线场景
- npm run build 通过,产物可静态托管

注:部署时需配置 SPA 回落,否则直接访问 /today 会 404(详见 README)。
2026-10-18 11:59:49 +08:00

206 lines
8.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 看板 · 个人任务管理
一个轻量的个人看板工具:打开即用、数据存在本地、不依赖后端。
- 固定三列:**待办 / 进行中 / 已完成**
- 快速新增、拖拽排序、详情编辑、删除撤销
- 搜索与筛选(关键词 / 优先级 / 标签 / 今日到期 / 逾期)
- **今日视图**:按紧急度汇总今天要做的事,含本周完成等统计
- 键盘快捷键
- 导出导入 JSON + 启动自动备份
- **可安装为 PWA,支持离线使用**
---
## 快速开始
```bash
npm install
npm run dev
```
打开终端提示的地址即可。首次进入是空看板,在任意列顶部的输入框里输入标题、回车即可创建任务。
## 脚本
| 命令 | 说明 |
|---|---|
| `npm run dev` | 启动开发服务器 |
| `npm run build` | 类型检查 + 生产构建,产物在 `dist/` |
| `npm run preview` | 本地预览生产构建 |
| `npm run typecheck` | 只做类型检查 |
| `npm run test` | 单元测试(Vitest) |
| `npm run test:coverage` | 单元测试 + 覆盖率报告 |
| `npm run test:e2e` | 端到端测试(Playwright,默认驱动系统已安装的 Chrome) |
| `npm run lint` / `npm run format` | 代码检查与格式化 |
## 快捷键
| 按键 | 作用 |
|---|---|
| `N` | 聚焦「待办」列的快速新增输入框 |
| `/` | 聚焦搜索框 |
| `?` | 打开快捷键帮助 |
| `Esc` | 关闭当前面板 |
在输入框内输入时不会触发快捷键。
---
## 两个视图
顶部导航可在两个视图之间切换:
| 视图 | 路径 | 组织方式 |
|---|---|---|
| 看板 | `/` | 按**状态**:待办 / 进行中 / 已完成 |
| 今日 | `/today` | 按**紧急度**:已逾期 → 今天到期 → 进行中 |
今日视图顶部有四张统计卡片(今日待办 / 逾期 / 今天到期 / 本周完成),下方是可直接勾选完成的待办列表。
分组是**互斥**的:一张卡片只会出现在一组里,归属优先级为「逾期 > 今天到期 > 进行中」,所以你能一眼数清今天到底有几件事。已完成和已归档的任务不会出现在今日视图。
---
## 安装与离线(PWA)
应用可以像原生应用一样安装到桌面或手机主屏,安装后支持**完全离线**使用 —— Service Worker 会预缓存页面与静态资源,断网后照常打开,数据本来就在本地。
- 桌面 Chrome / Edge:地址栏右侧会出现安装图标
- 手机:浏览器菜单 →「添加到主屏幕」
- 安装后长按图标有「今日」快捷方式,直达 `/today`
更新策略是 **prompt**:检测到新版本时会在底部弹出提示,由你决定何时刷新,不会打断正在进行的编辑。
图标由 `scripts/generate-icons.py`(Pillow)生成,需要改图标时运行:
```bash
python scripts/generate-icons.py
```
---
## 数据与备份(重要)
**数据只保存在你这台设备的浏览器里**(localStorage,键名 `kanban.tasks`)。没有服务端,也不会自动同步到其它设备。
这意味着以下操作会导致数据丢失:
- 清理浏览器数据 / 缓存
- 使用隐私模式
- 换浏览器或换设备
- Safari 的 7 天未访问存储清理策略
因此工具内置了两道保护:
1. **启动自动备份**:每次打开看板时留一份快照,最多保留最近 3 份,可在「备份」面板中一键恢复。
2. **手动导出**:「备份」面板 → 导出为 JSON,文件名形如 `kanban-2026-10-18.json`。
导入是**覆盖式**的:选中文件后会先校验,再显示将被覆盖的任务数量,需要二次确认才会执行。文件不合法时不会改动任何现有数据。
> 如果需要在多设备间同步,需要自行接入后端;`TaskRepository` 接口就是为此预留的扩展点(见下)。
---
## 部署
产物是纯静态文件,把 `dist/` 目录交给任意静态托管即可(Nginx、Vercel、Netlify、GitHub Pages 等)。
```bash
npm run build
# 将 dist/ 上传或指向静态服务器
```
Nginx 示例:
```nginx
server {
listen 80;
root /var/www/kanban/dist;
index index.html;
location / {
# 必须配置:/today 是真实路径,刷新时文件不存在,需要回落到 index.html
try_files $uri $uri/ /index.html;
}
}
```
Netlify / Vercel 等平台,在 `dist/` 同级放一个 `_redirects` 或配置即可:
```
/* /index.html 200
```
> **注意**:应用使用前端路由(`/today`),因此**必须**配置 SPA 回落,否则直接访问或刷新 `/today` 会 404。
> 这不是可选项。若你的托管环境无法配置回落,可以改用 hash 路由(把 `src/router/index.ts` 里的
> `createWebHistory()` 换成 `createWebHashHistory()`),代价是 URL 变成 `/#/today`。
Service Worker 的 `navigateFallback` 已设为 `index.html`,因此**离线状态下**深链 `/today` 也能正常打开,
无需服务器参与。
---
## 技术栈
Vue 3 · TypeScript · Vite · Pinia · Vue Router · Tailwind CSS v4 · vue-draggable-plus (SortableJS) · dayjs · vite-plugin-pwa (Workbox) · Vitest · Playwright
## 目录结构
```
src/
├── components/ # 看板列、卡片、抽屉、工具栏、导航、PWA 提示等 UI 组件
├── composables/ # 可复用的组合式逻辑(键盘快捷键)
├── data/ # 持久化:schema 与迁移、仓库实现、快照
├── router/ # 路由定义(看板 / 今日)
├── stores/ # Pinia:任务、筛选、提示
├── types/ # 领域类型与常量
├── utils/ # 纯函数:排序、筛选、日期、归档、拖拽解析、今日分组、统计
└── views/ # 页面级组件(BoardView / TodayView)
docs/
├── adr.md # 架构决策记录
├── tasks.md # 开发任务卡(含验收标准)
└── tasks.json # 可导入看板的种子数据
e2e/ # Playwright 端到端测试
scripts/ # 图标生成等辅助脚本
```
## 架构要点
- **单一数据源**:Pinia store 是内存态的唯一来源,所有变更经由 `TaskRepository` 落盘;拖拽也只消费事件,不接管数据。看板与今日视图共享同一份数据。
- **持久化端口**:`TaskRepository` 采用「整份快照读写」(`load` / `save`),而非细粒度 CRUD。要换成 IndexedDB 或后端 API,只需实现同一接口。
- **显式迁移**:落盘结构带 `schemaVersion`,升级规则登记在 `MIGRATIONS` 表中。当前版本为 2(v1 → v2 为归档功能补 `archivedAt`)。
- **损坏数据先备份再报错**:读取失败时把原始内容另存到 `kanban.tasks.corrupt.<时间戳>`,不覆盖用户数据。
- **视图与数据解耦**:今日视图只做「分组 + 排序」,全部逻辑在 `src/utils/today.ts` 与 `stats.ts` 的纯函数里,组件不持有业务规则。
更多取舍与理由见 [docs/adr.md](docs/adr.md)。
## 测试
- 单元测试:437 个用例,覆盖 `src/` 下的纯逻辑与组件行为,行覆盖率约 97%。
- 端到端测试:23 个用例,分两组运行 —— 交互类跑 dev server,PWA 类跑生产构建(Service Worker 只在构建产物中生成)。覆盖「新增 → 拖拽 → 完成 → 刷新保持」「导出 → 清空 → 导入还原」「删除撤销」「搜索筛选」「键盘快捷键」「今日视图」「离线打开」等主链路,每个用例使用独立的浏览器上下文。
```bash
npm run test:coverage
npm run test:e2e
```
### 关于 E2E 使用的浏览器
默认驱动**系统已安装的 Chrome**(`channel: 'chrome'`),不下载 Playwright 自带的 Chromium —— 后者约 197MB,在网络受限的环境下容易超时失败。
如需改用其它通道:
```bash
PLAYWRIGHT_CHANNEL=msedge npm run test:e2e # 用系统 Edge
PLAYWRIGHT_CHANNEL=chromium npm run test:e2e # 用自带 Chromium(需先 npx playwright install chromium)
```
## 已知限制
- 单用户、单设备,无协作与同步能力(离线可用,但多设备之间不会同步)。
- 标签是字符串数组,重命名标签需要逐个任务修改。
- 看板列固定为三列,不支持自定义。
- 归档阈值固定为「已完成超过 7 天」,暂不可配置。
- 今日视图的分组规则固定(逾期 > 今天到期 > 进行中),不可自定义。
- 统计只覆盖本周完成数等基础指标,没有趋势图或历史留存。