Files
iboard/docs/V0.2/需求文档.md
T
cheney 004f8c262d feat(V0.2): 打卡 / 日历 / 清单模块
- 数据: Habit/CheckIn/CheckList/CheckListItem/CheckListTemplate + 迁移 + 重新生成 client
- 后端: server/checkin/period.js 周期计算(日/周/月/年, 周一起始, Asia/Shanghai)
        /api/checkin/* 打卡项CRUD/打卡/撤销/补打/某日详情/月历
        /api/checklists/* 清单与检查项CRUD/勾选/全选/复制/模板(系统预置出差·回老家)
- 前端: 底部新增「打卡」Tab -> /checkin, 页内三视图
        环形进度 RingProgress + 完成特效(粒子/光晕/触感, 可关闭)
        打卡视图: 待办列表/乐观更新/撤销/新建编辑
        日历视图: 月历网格 + 今天·昨天·明天 + 日期标记/完成率
        清单视图: 场景清单/勾选进度条/模板生成/另存模板/归档
- 文档: docs/V0.2/需求文档.md 补充实现约定(附录B)与接口清单
2026-10-22 11:37:16 +08:00

21 KiB
Raw Blame History

iBoard V0.2 需求文档 — 打卡 / 日历 / 清单

版本:V0.2 · 分支:dev-0.2 · 日期:2026-10-22 目标项目:iboard(Tauri 2 + React 18 + antd-mobile + Express + Prisma/MariaDB,移动端优先) 基线版本:V0.1(dev-0.1)


1. 总体描述

在 iBoard 移动端新增一个「打卡」模块一个「清单」模块,满足两类日常需求:

打卡

  1. 周期性打卡(习惯养成):用户定义"每天 n 次 / 每周 n 次 / 每月 n 次 / 每年 n 次"的目标, 每次打卡后卡片上的环形进度按 已完成次数 / 目标次数 增长,达标时环形闭合并播放完成特效;
  2. 日历回看:以日历为载体,快速查看今天(要做什么)、昨天(做得怎样)、 明天(计划做什么),日期上以圆点/实心标记完成情况;

清单

  1. 清单(场景化一次性事项):面向出差、回老家等临时场景,逐条勾选确认, 避免遗漏;清单可复用为模板,下次一键生成。

1.1 本期范围

  • 单用户使用,数据按登录用户隔离(复用现有 JWT 鉴权)。
  • 移动端优先(MobileShell + 底部 TabBar 体系),桌面浏览器兼容可用即可。
  • 数据落库 MariaDB,通过现有 Express /api/* 提供接口。

1.2 不在本期范围(明确排除)

  • 多人协作 / 共享打卡 / 打卡排行榜。
  • 系统通知、推送提醒、定时提醒(V0.2 不引入通知能力)。
  • 复杂统计报表(周报/月报/趋势图),本期只提供完成率概览。
  • 桌面端专用布局、横屏适配。
  • 清单的周期性重复(如"每次出差都生成"),本期只做临时清单 + 模板手动复用。

2. 术语与概念定义

术语 定义
打卡项(Habit) 一个被跟踪的周期性目标,如"喝水 每天 8 次""健身 每周 3 次"
周期类型 day / week / month / year,决定进度统计窗口
目标次数 n 一个周期内需要完成的打卡次数,n ≥ 1
周期窗口 日=自然日;周=自然周(周一 00:00 至周日 23:59);月=自然月;年=自然年。时区统一 Asia/Shanghai
打卡记录(CheckIn) 一次打卡动作,归属到某个本地日历日(可补打到过去日期)
环形进度 卡片上的圆环组件,进度 = min(已完成次数 / n, 1);达标=闭合
清单(CheckList) 一次性检查清单,如"出差 · 10月杭州",含若干检查项
检查项(CheckItem) 清单中的单条待检查事项,勾选即完成
模板(Template) 可被复用的清单结构(一组检查项标题),用于一键生成新清单
日期状态 某日的打卡完成情况:全部完成 / 部分完成 / 未开始 / 超额完成

3. 需求点

编号规则:类型-模块-序号。类型:F=功能需求、U=交互与体验、D=数据、N=非功能、E=异常与边界。 模块:CK=打卡、CL=日历、LS=清单、SY=通用。

优先级:P0 = 本期必须有;P1 = 本期应该有;P2 = 有则更好(可延后)。

3.1 功能需求 — 打卡(F-CK)

编号 需求描述 验收要点 优先级
F-CK-01 支持新建打卡项:名称、周期类型、目标次数 n、颜色、图标、备注 表单校验:名称必填且 ≤ 20 字;n 为 ≥1 的整数 P0
F-CK-02 周期类型支持每天 n 次 / 每周 n 次 / 每月 n 次 / 每年 n 次四种 四种类型均可创建并正确统计 P0
F-CK-03 卡片以环形进度展示当前周期完成情况,环中心显示 已完成/n 进度 = 已完成次数 / n,上限 100% P0
F-CK-04 每天 1 次的打卡项:打卡后环形直接闭合(100%),卡片进入"已完成"态 一次点击即闭合,不出现 50% 之类的中间态 P0
F-CK-05 每周 n 次(及月/年):每打卡一次环形闭合对应百分比(如 n=3,打 1 次=33.3%、2 次=66.7%、3 次=100% 闭合) 进度随每次打卡实时刷新,带过渡动画 P0
F-CK-06 打卡主操作:点击卡片上的打卡按钮即完成一次打卡 单击即生效,响应 < 300ms(乐观更新) P0
F-CK-07 打卡完成特效:达标(进度达 100%)时播放特效——环形闭合动画 + 光晕/粒子扩散 + 轻量触感反馈 特效时长 ≤ 800ms,不阻塞后续操作 P0
F-CK-08 打卡记录需记录发生日期(本地日历日)与时间戳 支持按日回看,跨零点归属正确 P0
F-CK-09 支持撤销:可撤销本周期内最近一次打卡(主要是误触场景) 撤销后进度回退,记录物理删除或标记撤销 P1
F-CK-10 支持补打卡:对过去日期补记一次打卡,默认允许回溯 7 天 补打后对应日期的状态与进度同步更新 P1
F-CK-11 不允许提前打卡(未来日期不可打卡) 明天的项只展示为"计划",按钮置灰 P0
F-CK-12 展示连续完成天数/周期数(streak) 如"已连续 5 天",断签归零 P1
F-CK-13 打卡项可编辑(改名/改 n/改颜色/改周期)与停用(归档) 归档后不出现在今日待办,历史保留 P1
F-CK-14 修改目标次数 n 后,当前周期进度按新 n 重算展示,不改写历史记录 例如 n 由 3 改 5,已完成 3 次 → 显示 3/5(60%) P1
F-CK-15 超额打卡:周期内超过 n 仍可继续打卡,环形保持闭合,中心显示 n+k(如 3+1) 不清零、不报错 P2
F-CK-16 打卡项支持排序(拖动或置顶)与分组展示 今日列表按"未完成在前、已完成在后"默认排序 P2
F-CK-17 打卡时可附带备注(可选,纯文本) 列表详情中可查看 P2

3.2 功能需求 — 日历(F-CL)

编号 需求描述 验收要点 优先级
F-CL-01 提供月历视图:当月日历网格,可切换上/下月,点击日期查看当日详情 周一起始,周一~周日七列 P0
F-CL-02 今天视图(默认):列出今天应打卡的项及完成状态,可直接打卡 打开页面默认定位今天 P0
F-CL-03 昨天视图:展示昨天各打卡项的已完成结果(完成/未完成/超额),未完成项可进行补打 以回看为主,标记为"已完成的历史" P0
F-CL-04 明天视图:展示明天计划要打卡的项(按周期规则推算),只读,不可打卡 明确标注"计划",打卡按钮不可用 P0
F-CL-05 今天/昨天/明天快捷切换(顶部 Segmented 或左右滑动) 一键切换,切换有过渡动画 P0
F-CL-06 日期标记:月历中每个日期按完成情况标记——全部完成(实心)、部分完成(半填充)、未开始(空心/无标记)、超额完成(特殊标记) 一眼能看出当月坚持情况 P0
F-CL-07 日期详情:点击某日期,展示当天每个打卡项的"目标次数 / 已完成次数 / 状态" 过去日期可补打,未来日期只读 P0
F-CL-08 日历与打卡数据同源:打卡操作在日历视图与打卡列表视图中即时一致 任一处打卡,另一处刷新 P0
F-CL-09 月历顶部展示当月完成率(完成次数 / 应完成次数) 百分比展示 P1
F-CL-10 支持左右滑动手势切换月份 与按钮切换等价 P2
F-CL-11 月视图支持简单的完成热力(按完成率深浅着色) 可选展示,默认关闭 P2

3.3 功能需求 — 清单(F-LS)

编号 需求描述 验收要点 优先级
F-LS-01 支持新建检查清单:名称、场景标签(出差 / 回老家 / 自定义)、备注 名称必填,场景标签可空 P0
F-LS-02 清单内可增删改检查项,支持排序 单条 ≤ 40 字 P0
F-LS-03 勾选完成:点击检查项前的复选框即打勾,已完成项置灰 + 删除线;可取消勾选 单击切换,状态即时保存 P0
F-LS-04 清单头部显示进度:已完成 / 总数 + 进度条;全部完成时显示完成态 全部勾完触发完成提示 P0
F-LS-05 清单全部完成时播放完成特效(与 F-CK-07 同一套特效组件) 复用,风格统一 P1
F-LS-06 模板:系统预置常用模板(出差、回老家),一键基于模板生成新清单 至少 2 个预置模板 P1
F-LS-07 另存为模板:用户可将自己的清单保存为自定义模板,后续复用 自定义模板可删除 P1
F-LS-08 复用历史清单:从历史清单复制生成一份新清单(勾选状态重置) 原清单保持不变 P1
F-LS-09 清单归档/删除:完成的清单可归档(不出现在进行中列表),可查看历史 删除需二次确认 P1
F-LS-10 清单项支持备注/数量说明(如"充电器 ×1") 展示在标题下方,弱色小字 P2
F-LS-11 清单支持一键全部勾选 / 全部取消 批量操作入口 P2

3.4 功能需求 — 通用(F-SY)

编号 需求描述 验收要点 优先级
F-SY-01 底部 TabBar 新增**「打卡」页** 和 「清单」页 图标风格与现有 TabIcon 一致 P0
F-SY-02 「打卡」页内集成 打卡/日历 两个功能,日历放在上半截,默认显示一行为周视图,下拉显示为月视图。 日历中选择时间与下部打卡任务联动 P0
F-SY-03 所有接口复用现有鉴权(authRequired,JWT),数据按 userId 隔离 未登录跳转 /login P0
F-SY-04 后端新增 REST 路由(建议 /api/checkin/*、/api/checklist/*),挂载到 server/index.js 与现有路由风格一致 P0
F-SY-05 时间处理统一 Asia/Shanghai,前端与后端对"日历日"的判定一致 跨零点打卡归属当天 P0
F-SY-06 打卡/勾选操作采用乐观更新,接口失败时回滚并 Toast 提示 失败可见、状态不失真 P1
F-SY-07 写接口幂等/防抖:同一打卡项 1 秒内重复点击只记一次 前端防抖 + 后端唯一约束双保险 P1
F-SY-08 页面可见性变化时刷新数据(复用 useRefreshOnVisible) 从后台切回自动同步 P1

3.5 交互与体验需求(U)

编号 需求描述 验收要点 优先级
U-01 环形进度组件:SVG 圆环,背景环 + 进度环,进度变化带 400ms ease-out 动画 组件可复用(打卡卡片、清单进度共用) P0
U-02 完成特效:达标瞬间环形闭合 + 光晕/粒子扩散,约 600ms;可重复观看不烦扰 不阻塞操作,动画结束自动清理 P0
U-03 触感反馈:完成打卡时轻量震动(Web Vibration API / Tauri),可在设置中关闭 默认开启,关闭后仅视觉反馈 P1
U-04 移动端适配:375~430px 视口,复用 globals.css 的 .card 体系,安全区与底部 TabBar 不遮挡内容 真机无横向滚动、无遮挡 P0
U-05 空态 / 加载态 / 错误态三态齐全(首次使用引导"创建第一个打卡项") 空态有明确 CTA P0
U-06 打卡按钮足够大(点击热区 ≥ 44×44),符合移动端触控规范 误触率低 P1
U-07 动效性能降级:低端设备或 prefers-reduced-motion 时关闭粒子特效,仅保留进度动画 不卡顿 P1
U-08 深浅色:跟随现有浅色主题,卡片/分割线风格与首页、监控页一致 视觉统一 P1
U-09 清单勾选有明确的勾选动画(勾形描边动画) 反馈即时 P2

3.6 数据需求(D)

编号 需求描述 验收要点 优先级
D-01 新增 Prisma 模型:Habit(打卡项)、CheckIn(打卡记录) 字段见附录 A P0
D-02 新增 Prisma 模型:CheckList(清单)、CheckListItem(检查项)、CheckListTemplate(模板,P1) 字段见附录 A P0
D-03 Habit / CheckList 均带 userId 外键,删除用户级联删除 数据隔离 P0
D-04 CheckIn 建立 (habitId, date) 索引,支持按日期范围查询 日历月查询走索引 P0
D-05 提供迁移 SQL 并纳入 prisma migrate deploy 流程 与 V0.1 迁移流程一致 P0
D-06 软删除语义:Habit.archived、CheckList.archived,历史记录保留 不物理删除历史 P1

3.7 非功能需求(N)

编号 需求描述 验收要点 优先级
N-01 页面首屏数据加载 < 1.5s(内网/正常网络),交互响应 < 300ms(乐观更新) 真机可感知流畅 P0
N-02 兼容 Android WebView(Tauri 打包)与移动端浏览器,不依赖桌面专有 API 真机验证 P0
N-03 单用户数据量按"千级记录/年"设计,无需分表;月查询一次请求返回 日历切月无等待感 P1
N-04 所有接口 authRequired,越权访问返回 401 安全基线 P0
N-05 前端代码组织遵循现有约定:src/pages/checkin/* + src/components/* + server/routes/* 结构一致 P0

3.8 异常与边界需求(E)

编号 需求描述 处理约定 优先级
E-01 重复点击打卡 前端防抖 + 后端唯一约束,只记一次 P0
E-02 接口失败 / 断网 乐观更新回滚 + Toast 提示,可重试 P0
E-03 周期中途新建打卡项(如周三创建"每周 3 次") 本期按完整目标 n 计算,不按剩余天数折算 P1
E-04 每月 n 次在天数不同的月份 按自然月窗口,不折算 P0
E-05 每年 n 次跨年 按自然年窗口,年末清零 P0
E-06 删除打卡项 归档(软删除)为主;硬删除需二次确认并提示"历史记录将一并删除" P1
E-07 清单项全部删除后清单进度为 0/0 显示空清单,不显示 100% P1
E-08 跨零点打卡(23:59 → 00:00) 以提交时刻的本地日历日归属 P0

4. 优先级汇总(本期交付范围)

  • P0(必须):F-CK-0108、F-CK-11;F-CL-0108;F-LS-0104;F-SY-0105;U-01、U-02、U-04、U-05;D-01~05;N-01、N-02、N-04、N-05;E-01、E-02、E-04、E-05、E-08。
  • P1(应该):F-CK-09、10、1214;F-CL-09;F-LS-0509;F-SY-0608;U-03、U-0608;D-06;N-03;E-03、E-06、E-07。
  • P2(可选/延后):F-CK-15~17;F-CL-10、11;F-LS-10、11;U-09。

5. 里程碑建议

里程碑 内容
M1 数据与接口 Prisma 模型 + 迁移;server/routes/checkin.js、checklist.js;周期进度计算与日期查询
M2 打卡视图 环形进度组件 + 打卡卡片列表 + 打卡/撤销/补打 + 完成特效
M3 日历视图 月历网格 + 今天/昨天/明天三视图 + 日期标记 + 日期详情
M4 清单视图 清单 CRUD + 勾选交互 + 进度条 + 模板与复用
M5 联调打磨 真机验证、动效降级、空态/错误态、性能与跨天边界

6. 待确认问题(评审时决策)

# 问题 建议
1 是否新增第 5 个底部 Tab「打卡」,还是放在首页入口? 建议新增 Tab,入口最清晰
2 周起始日是周一还是周日? 建议周一(国内习惯)
3 是否允许"明天提前打卡"? 建议不允许(F-CK-11),保持统计口径干净
4 删除打卡项时历史是否保留? 建议默认归档保留,硬删除才清历史
5 预置模板具体包含哪些项? 评审时列出"出差/回老家"各 8~12 条初始项
6 完成特效是否可全局关闭? 建议在"我"页提供开关(默认开)

附录 A:核心实体草案(供设计阶段参考,非最终表结构)

// 打卡项
model Habit {
  id        Int      @id @default(autoincrement())
  userId    Int
  name      String
  period    String   // day | week | month | year
  target    Int      @default(1)      // 周期内目标次数 n
  color     String   @default("#1677ff")
  icon      String   @default("")
  note      String   @default("")
  archived  Boolean  @default(false)
  sortOrder Int      @default(0)
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  records   CheckIn[]

  @@index([userId, archived])
}

// 打卡记录(一次打卡 = 一条;同日多次为多条)
model CheckIn {
  id        Int      @id @default(autoincrement())
  habitId   Int
  habit     Habit    @relation(fields: [habitId], references: [id], onDelete: Cascade)
  userId    Int
  date      String                    // 本地日历日 "YYYY-MM-DD" (Asia/Shanghai)
  seq       Int      @default(1)      // 当日第几次 (1..n, 超额继续累加)
  note      String   @default("")
  source    String   @default("user") // user | backfill(补打)
  createdAt DateTime @default(now())

  @@unique([habitId, date, seq])
  @@index([userId, date])
  @@index([habitId, date])
}

// 检查清单
model CheckList {
  id        Int             @id @default(autoincrement())
  userId    Int
  title     String
  scene     String   @default("")     // 出差 | 回老家 | 自定义
  note      String   @default("")
  archived  Boolean  @default(false)
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  items     CheckListItem[]

  @@index([userId, archived])
}

// 检查项
model CheckListItem {
  id        Int       @id @default(autoincrement())
  listId    Int
  list      CheckList @relation(fields: [listId], references: [id], onDelete: Cascade)
  title     String
  note      String    @default("")
  done      Boolean   @default(false)
  doneAt    DateTime?
  sortOrder Int       @default(0)
  createdAt DateTime  @default(now())
  updatedAt DateTime @updatedAt

  @@index([listId, sortOrder])
}

// 清单模板(P1)
model CheckListTemplate {
  id        Int      @id @default(autoincrement())
  userId    Int?                      // null = 系统预置
  name      String
  scene     String   @default("")
  items     Json                      // [{ title, note }]
  builtin   Boolean  @default(false)
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}

说明:周期进度由 CheckIn 按周期窗口现场聚合(不冗余计数字段),避免并发与修改 n 后的一致性问题。


附录 B:实现约定(开发期补充,用于消除口径歧义)

# 约定 说明
B-1 周期窗口 日=自然日;周=周一 00:00 ~ 周日 23:59;月=自然月;年=自然年;时区 Asia/Shanghai
B-2 环形进度 周期完成度 = 周期内累计打卡次数 / n(每周 n 次:打 1 次=1/n 环;每天 1 次:打 1 次直接闭合)
B-3 日历日期标记 用"当日完成度":当日次数 / 日均期望次数(每天 n 次→n;每周 n 次→ceil(n/7);每月→ceil(n/当月天数);每年→ceil(n/365))。全完成=实心绿点,部分=黄点,超额=紫点,无记录=不显示
B-4 streak 从当前周期往回数连续达标的周期数;当前周期未结束且未达标不算断签(跳过继续往前数)
B-5 补打限制 只能补打最近 7 天(BACKFILL_DAYS),未来日期禁止打卡
B-6 撤销语义 撤销删除本周期内"最近一次"打卡(按 date desc、seq desc 取第一条)
B-7 删除打卡项 默认归档(archived=true,历史保留);?hard=1 才物理删除并清记录
B-8 接口前缀 打卡 /api/checkin/*、清单 /api/checklists/*,全部 authRequired,数据按 userId 隔离
B-9 前端入口 底部新增第 5 个 Tab「打卡」→ /checkin,页内三视图:打卡 / 日历 / 清单
B-10 特效开关 完成特效 + 触感反馈受 localStorage iboard_celebrate 控制(默认开),系统开启"减弱动效"时自动降级

接口清单

方法 路径 说明
GET /api/checkin/habits?date= 打卡项列表 + 当前周期进度 + streak
POST /api/checkin/habits 新建打卡项
PUT /api/checkin/habits/:id 编辑(改 n / 周期 / 归档)
DELETE /api/checkin/habits/:id?hard=1 归档(默认)/ 物理删除
POST /api/checkin/habits/:id/check 打卡一次(可带 date 补打、note)
DELETE /api/checkin/habits/:id/check?date= 撤销本周期最近一次
GET /api/checkin/day?date= 某日详情(今天可打卡 / 昨天可补打 / 明天只读)
GET /api/checkin/calendar?month=YYYY-MM 月历:每日状态 + 当月完成率
GET /api/checklists?archived=0|1 清单列表(含进度)
POST /api/checklists 新建清单(可带 templateId 从模板生成)
GET/PUT/DELETE /api/checklists/:id 详情 / 编辑 / 删除
POST /api/checklists/:id/duplicate 复制为新清单(勾选重置)
POST /api/checklists/:id/items 新增检查项
PUT/DELETE /api/checklists/items/:id 改标题 / 勾选(done) / 删除
POST /api/checklists/:id/check-all 一键全选 / 全不选
GET/POST /api/checklists/templates 模板列表(含系统预置)/ 另存为模板
DELETE /api/checklists/templates/:id 删除自定义模板