Files
Kanban/README.md
T
chenshoulin 8721e8ab0b feat: 补齐今日视图待办组、卡片键盘操作、深色模式
今日视图
- 补上「待办」组。此前只收 逾期 / 今天到期 / 进行中,导致待办列里没设
  截止日期的任务在今日视图里完全消失 —— 用户明明有一堆事没做,却看到
  「今天没有待办事项」。现在只要任务未完成且未归档,就必定出现在某个
  分组里(归属优先级:逾期 > 今天到期 > 进行中 > 待办)。
- 统计卡片改为与分组一一对应(逾期 / 今天到期 / 进行中 / 本周完成),
  不再用「今日待办」这种把四组混在一起、与列表长度对不上的指标。

键盘操作(可访问性)
- 卡片可聚焦(Tab / 点击),← → 换列、↑ ↓ 列内调序、Enter 打开详情。
- 换列时追加到目标列末尾:用全量长度而不是可见下标,筛选态下也安全;
  列内调序要求该列渲染的是全量,否则禁用(与拖拽的规则一致)。
- 移动后手动恢复焦点 —— 卡片跨列会被重建,不恢复的话连续按键会失效。

深色模式
- 三态:跟随系统 / 浅色 / 深色,选择持久化到 localStorage。
- index.html 内联脚本在首帧之前应用主题,避免深色下闪白。
- 用 @custom-variant dark 做 class 控制(而不是纯 media query),
  才能支持「强制浅色」;html 的 color-scheme 让原生控件与滚动条跟随。

验证:单元测试 480 个、端到端测试 25 个全部通过,lint 与构建无错误。
截图脚本新增深色与移动端深色两组,便于后续对照。
2026-10-18 17:48:55 +08:00

9.1 KiB
Raw Blame History

看板 · 个人任务管理

一个轻量的个人看板工具:打开即用、数据存在本地、不依赖后端。

  • 固定三列:待办 / 进行中 / 已完成
  • 快速新增、拖拽排序、详情编辑、删除撤销
  • 搜索与筛选(关键词 / 优先级 / 标签 / 今日到期 / 逾期)
  • 今日视图:按紧急度分组汇总(逾期 / 今天到期 / 进行中 / 待办),含本周完成等统计
  • 键盘快捷键;任务卡片可用方向键换列与调序
  • 深色模式:跟随系统 / 浅色 / 深色三态
  • 导出导入 JSON + 启动自动备份
  • 可安装为 PWA,支持离线使用

快速开始

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)
node scripts/screenshot.mjs 生成界面截图(需先起 dev server),产物在 .screenshots/
npm run lint / npm run format 代码检查与格式化

快捷键

按键 作用
N 聚焦「待办」列的快速新增输入框
/ 聚焦搜索框
? 打开快捷键帮助
Esc 关闭当前面板

卡片获得焦点(Tab 或点击)后:

按键 作用
← → 把卡片移到上一列 / 下一列
↑ ↓ 在列内上移 / 下移
Enter 打开任务详情

在输入框内输入时不会触发全局快捷键。方向键移动在筛选态下只允许跨列(列内排序需要看到完整列表才有意义)。


两个视图

顶部导航可在两个视图之间切换:

视图 路径 组织方式
看板 / 按状态:待办 / 进行中 / 已完成
今日 /today 按紧急度:已逾期 → 今天到期 → 进行中 → 待办

今日视图顶部有四张统计卡片(逾期 / 今天到期 / 进行中 / 本周完成),下方是可直接勾选完成的待办列表。

分组是互斥的:一张卡片只会出现在一组里,归属优先级为「逾期 > 今天到期 > 进行中 > 待办」,所以你能一眼数清今天到底有几件事。已完成和已归档的任务不会出现在今日视图。

只要任务未完成且未归档,就一定会出现在某个分组里 —— 包括没设截止日期的待办(归入「待办」组)。


安装与离线(PWA)

应用可以像原生应用一样安装到桌面或手机主屏,安装后支持完全离线使用 —— Service Worker 会预缓存页面与静态资源,断网后照常打开,数据本来就在本地。

  • 桌面 Chrome / Edge:地址栏右侧会出现安装图标
  • 手机:浏览器菜单 →「添加到主屏幕」
  • 安装后长按图标有「今日」快捷方式,直达 /today

更新策略是 prompt:检测到新版本时会在底部弹出提示,由你决定何时刷新,不会打断正在进行的编辑。

图标由 scripts/generate-icons.py(Pillow)生成,需要改图标时运行:

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 等)。

npm run build
# 将 dist/ 上传或指向静态服务器

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。

测试

  • 单元测试:480 个用例,覆盖 src/ 下的纯逻辑与组件行为,行覆盖率约 96%。
  • 端到端测试:25 个用例,分两组运行 —— 交互类跑 dev server,PWA 类跑生产构建(Service Worker 只在构建产物中生成)。覆盖「新增 → 拖拽 → 完成 → 刷新保持」「导出 → 清空 → 导入还原」「删除撤销」「搜索筛选」「键盘快捷键与方向键移动」「深色模式切换」「今日视图」「离线打开」等主链路,每个用例使用独立的浏览器上下文。
npm run test:coverage
npm run test:e2e

关于 E2E 使用的浏览器

默认驱动系统已安装的 Chrome(channel: 'chrome'),不下载 Playwright 自带的 Chromium —— 后者约 197MB,在网络受限的环境下容易超时失败。

如需改用其它通道:

PLAYWRIGHT_CHANNEL=msedge npm run test:e2e    # 用系统 Edge
PLAYWRIGHT_CHANNEL=chromium npm run test:e2e  # 用自带 Chromium(需先 npx playwright install chromium)

已知限制

  • 单用户、单设备,无协作与同步能力(离线可用,但多设备之间不会同步)。
  • 标签是字符串数组,重命名标签需要逐个任务修改。
  • 看板列固定为三列,不支持自定义。
  • 归档阈值固定为「已完成超过 7 天」,暂不可配置。
  • 今日视图的分组规则固定(逾期 > 今天到期 > 进行中 > 待办),不可自定义。
  • 统计只覆盖本周完成数等基础指标,没有趋势图或历史留存。
  • 深色模式只跟随系统或手动三态切换,没有按时间段自动切换。