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)与接口清单
This commit is contained in:
cheney
2026-10-22 11:37:16 +08:00
parent 54a3224f00
commit 004f8c262d
32 changed files with 11030 additions and 63 deletions
+47 -8
View File
@@ -1,6 +1,6 @@
# iBoard V0.2 需求文档 — 打卡 / 日历 / 清单
> 版本:V0.2 · 分支:`dev-0.2` · 状态:待评审 · 日期:2026-10-22
> 版本:V0.2 · 分支:`dev-0.2` · 日期:2026-10-22
> 目标项目:iboard(Tauri 2 + React 18 + antd-mobile + Express + Prisma/MariaDB,移动端优先)
> 基线版本:V0.1(`dev-0.1`)
@@ -8,16 +8,16 @@
## 1. 总体描述
在 iBoard 移动端新增一个「打卡」模块,用**一个页面、三个视图**解决两类日常需求:
在 iBoard 移动端新增一个「打卡」模块一个「清单」模块,满足两类日常需求:
### 打卡
1. **周期性打卡**(习惯养成):用户定义"每天 n 次 / 每周 n 次 / 每月 n 次 / 每年 n 次"的目标,
每次打卡后卡片上的**环形进度**按 `已完成次数 / 目标次数` 增长,达标时环形闭合并播放完成特效;
2. **日历回看**:以日历为载体,快速查看**今天**(要做什么)、**昨天**(做得怎样)、
**明天**(计划做什么),日期上以圆点/实心标记完成情况;
3. **检查清单**(场景化一次性事项):面向**出差、回老家**等临时场景,逐条勾选确认,
避免遗漏;清单可复用为模板,下次一键生成。
一句话:**用环形进度做周期性打卡,用日历做时间维度的回看与计划,用清单覆盖临时性的检查场景。**
### 清单
1. **清单**(场景化一次性事项):面向**出差、回老家**等临时场景,逐条勾选确认,
避免遗漏;清单可复用为模板,下次一键生成。
### 1.1 本期范围
@@ -117,8 +117,8 @@
| 编号 | 需求描述 | 验收要点 | 优先级 |
| --- | --- | --- | --- |
| F-SY-01 | 底部 TabBar 新增**「打卡」页**(现有 4 个 Tab → 5 个),作为本模块唯一入口 | 图标风格与现有 TabIcon 一致 | P0 |
| F-SY-02 | 「打卡」页内以子 Tab(Segmented / SwipeTabs)切换 **打卡 / 日历 / 清单** 三个视图 | 复用现有 `SwipeTabs` 组件 | P0 |
| 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 |
@@ -293,3 +293,42 @@ model CheckListTemplate {
```
> 说明:周期进度由 `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` | 删除自定义模板 |