feat: add monthly card periods and apparatus lesson feedback

This commit is contained in:
richarjiang
2026-10-18 15:47:29 +08:00
parent b452de379d
commit a3d58fa8f2
40 changed files with 968 additions and 170 deletions

View File

@@ -0,0 +1,24 @@
# 按器械填写课后评价
教练从已完成课程详情的「为这次课写评语」进入,评价继续关联该预约与学员。成长档案的「寄语 → 写评价」也可以记录不关联课程的教练笔记。
- 保留整体评价,新增 M、R、TT、Chair、ARC、SC、LB 七项自由文本,每项最多 1000 字。
- 所有字段均选填;整体评价或任意一项器械有非空白内容即可保存。空白器械不入库、不展示。
- 按器械展开填写,收起保留摘要;保存失败保留当前输入,可重试。主动关闭时会提醒放弃未保存内容。
- 继续沿用「分享给学员」开关,默认关闭。学员只可读取已共享笔记。历史笔记无需转换。
## 部署
新增可空 MySQL JSON 字段 `member_notes.apparatus_notes`,迁移为 `20261018100000_lesson_apparatus_notes`。先在目标环境执行 `pnpm --filter @mp-pilates/server exec prisma migrate deploy`,重新生成 Prisma Client 并部署后端,然后发布小程序。此命令会部署目标库中所有尚未执行的迁移,应按现有发布流程核对。
本次仅添加迁移文件,未对任何数据库执行迁移。
## 验收
1. 从一节已完成课程进入,仅填写 M、仅填写整体评价、填写多种器械,分别保存;检查关联课程、换行及各器械内容。
2. 所有输入为空或只有空格时不可保存。填满 1000 字,检查计数和输入上限。
3. 展开、收起、切换器械,检查内容摘要与填写数量;滚动至 LB,检查软键盘、输入框和底部按钮在微信 iOS / Android 的可见性。
4. 保存时连续点击不重复提交;断网保存后内容保留,恢复网络可重试;关闭未保存表单可选择继续填写。
5. 默认私密记录仅馆主可见,开启共享后学员端按器械分段展示;未填写的器械不显示,历史整体评价仍显示。
本地已验证共享包构建、前端类型检查、小程序构建、后端构建,以及完整 Jest 测试。本地浏览器组件预览用于验证展开、切换、填写计数、仅器械保存及分段展示;不替代微信真机验收。

View File

@@ -0,0 +1,51 @@
# 月卡周期与续费规则
## 已确认规则
- 月卡(DURATION)每次购买生成独立会员卡周期,不向旧周期累加课时,不覆盖旧卡、订单和预约关联。
- 旧周期尚未到期时,新周期从同款卡已购周期的最晚到期时间开始。连续购买按支付确认顺序排期,每期额度独立。
- 旧周期已结束时,新周期从支付确认时间开始。旧月卡即使账面还有 6 次,也不可继续使用,不会与新购 10 次合成 16 次。
- 次卡(TIMES)保留现有规则:有效期内续费累加次数、延长有效期;过期余次不结转。体验卡仍为独立新卡。
- 原有月卡沿用已经约定的有效期,不按开卡日倒推缩短,不批量改写历史余额。
## 状态与展示
新增 `SCHEDULED`(待生效)状态,数据库迁移只在原枚举末尾追加值,不改写现有记录。
读取会员权益时,依据服务端时间实时判断生效、到期和可用次数,不依赖凌晨任务。到期的限次月卡返回 0 次可用权益;原始账面余额留在旧记录中用于历史核对。待生效额度不会计入当前余额。
会员页分为「正在使用」「下期待生效」「历史记录」。续费页显示本期剩余与下期起止时间/独立额度,提前续费提示「支付后排期待生效」。页面打开期间在生效和到期边界刷新展示。
## 提前启用
接口:`POST /membership/:id/activate`,要求登录及 `{ "confirmed": true }`,仅操作登录用户自己的周期。
只能启用同款卡最早的待生效周期。本期必须已经用完次数;不限次月卡或仍有余次的周期不允许提前结束。
启用前先检查本期未完成预约;如仍有未来待确认/已确认课程,需上完或取消后再启用。新周期从启用时刻开始,保留完整已购时长,后续待生效周期连续重新衔接。已经预约到新周期或后续周期的课程必须仍在调整后的范围内,否则拒绝操作并提示调整预约,不自动取消课程。
购卡排期、提前启用及预约写入使用同一会员的数据库行锁串行处理。启用事务只修改周期日期与状态,不改变订单和预约所关联的周期 ID。
## 预约与扣次
月卡可提前预约已付款周期内的课程,但课程起止时间必须完全落在所选周期内。上课时间按场馆中国时区计算。学员预约、馆主代约及确认预约均验证周期,不能借用另一期额度。
仍由教练确认预约时扣次;未来周期被确认预约后保留待生效状态。取消后退回原周期,不转入其他新卡;已过期月卡的退回次数不会变为可用权益。
## 发布与兼容
1. 备份生产数据库和当前 server/shared 构建及 Prisma Client。
2. 应用 `20261018090000_scheduled_membership_periods`,生成对应 Prisma Client,再发布 shared/server。
3. 发布小程序新版本,才能显示独立周期、正确续卡预览及提前启用入口。旧版内置的续卡计算不会随服务端更新,应配套发布小程序。
没有新增环境变量,不需要清空或重建已有会员数据。新周期与历史记录共用原有 memberships、orders、bookings 关系,既有购买不会重新发卡。
验证包括月卡 6 + 新购 10 分期保存、过期与临界时刻、连续购买排期、提前启用确认与归属、已有预约保护、课程周期边界、支付确认发放新周期、次卡原逻辑,以及共享/服务端/小程序构建。
## 本次验证(2026-10-18)
- 当前工作区完整服务端测试通过:34 个套件、545 项测试。
- shared/server 构建、小程序类型检查和微信小程序生产构建通过。
- `pnpm lint` 无法执行:现有环境未安装脚本引用的 `eslint`;未为此调整依赖或锁文件。
- 使用真实 Vue 页面与模拟数据检查了 390px 宽度下的未过期续卡、已过期续卡、待生效周期列表、提前启用确认及成功后的日期/额度更新;未发起真实支付或修改真实会员权益。
- 本次月卡迁移及服务端改动尚未部署生产,新版小程序尚未上传或发布。