From 139882d7a13f253f471b7efefd48a05711d2d0bd Mon Sep 17 00:00:00 2001 From: richarjiang Date: Wed, 9 Sep 2026 15:55:48 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E8=AF=BE=E5=90=8E?= =?UTF-8?q?=E8=AF=84=E4=BB=B7=E4=B8=8E=E6=88=90=E9=95=BF=E6=A1=A3=E6=A1=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 完成后即可评价并订阅提醒,馆主可记录体测、笔记与成长照片,首页展示匿名星级均分。 Co-authored-by: Cursor --- CLAUDE.md | 10 + docs/member-care.md | 41 +++++ .../app/src/components/ClassReviewForm.vue | 76 ++++++++ .../app/src/components/MemberProgress.vue | 172 ++++++++++++++++++ packages/app/src/components/ProfileMenu.vue | 1 + .../app/src/components/ReviewSummaryCard.vue | 9 + packages/app/src/pages.json | 18 ++ packages/app/src/pages/admin/index.vue | 1 + .../app/src/pages/admin/member-detail.vue | 13 +- .../app/src/pages/admin/member-progress.vue | 13 ++ packages/app/src/pages/admin/reviews.vue | 53 ++++++ packages/app/src/pages/admin/stores/admin.ts | 5 + packages/app/src/pages/booking/detail.vue | 26 ++- packages/app/src/pages/home/index.vue | 2 + packages/app/src/pages/profile/bookings.vue | 4 +- packages/app/src/pages/profile/progress.vue | 12 ++ packages/app/src/utils/format.ts | 7 + packages/server/.env.example | 3 + .../20260909120000_member_care/migration.sql | 85 +++++++++ packages/server/prisma/schema.prisma | 68 +++++++ .../src/auth/__tests__/auth.service.spec.ts | 2 +- packages/server/src/auth/auth.service.ts | 1 + .../booking/__tests__/booking.service.spec.ts | 6 + .../booking/__tests__/review.service.spec.ts | 69 +++++++ packages/server/src/booking/booking.module.ts | 6 +- .../server/src/booking/booking.service.ts | 8 + .../src/booking/dto/create-review.dto.ts | 8 + .../server/src/booking/review.controller.ts | 27 +++ packages/server/src/booking/review.service.ts | 61 +++++++ .../__tests__/review-reminder.service.spec.ts | 29 +++ .../__tests__/scheduler.service.spec.ts | 2 + .../src/scheduler/review-reminder.service.ts | 25 +++ .../server/src/scheduler/scheduler.module.ts | 6 +- .../src/studio/studio-upload.service.ts | 9 +- .../__tests__/slot-generator.service.spec.ts | 2 +- .../src/time-slot/slot-generator.service.ts | 2 +- .../__tests__/member-progress.service.spec.ts | 102 +++++++++++ .../progress-photo-storage.service.spec.ts | 59 ++++++ .../subscription-message.service.spec.ts | 27 +++ .../src/user/dto/member-progress.dto.ts | 21 +++ .../src/user/member-progress.controller.ts | 27 +++ .../src/user/member-progress.service.ts | 87 +++++++++ .../user/progress-photo-storage.service.ts | 45 +++++ .../src/user/subscription-message.service.ts | 37 ++++ packages/server/src/user/user.module.ts | 7 +- packages/server/src/user/user.service.ts | 1 + packages/shared/src/enums.ts | 1 + packages/shared/src/index.ts | 2 + packages/shared/src/types/booking.ts | 1 + packages/shared/src/types/member-care.ts | 23 +++ 50 files changed, 1307 insertions(+), 15 deletions(-) create mode 100644 docs/member-care.md create mode 100644 packages/app/src/components/ClassReviewForm.vue create mode 100644 packages/app/src/components/MemberProgress.vue create mode 100644 packages/app/src/components/ReviewSummaryCard.vue create mode 100644 packages/app/src/pages/admin/member-progress.vue create mode 100644 packages/app/src/pages/admin/reviews.vue create mode 100644 packages/app/src/pages/profile/progress.vue create mode 100644 packages/server/prisma/migrations/20260909120000_member_care/migration.sql create mode 100644 packages/server/src/booking/__tests__/review.service.spec.ts create mode 100644 packages/server/src/booking/dto/create-review.dto.ts create mode 100644 packages/server/src/booking/review.controller.ts create mode 100644 packages/server/src/booking/review.service.ts create mode 100644 packages/server/src/scheduler/__tests__/review-reminder.service.spec.ts create mode 100644 packages/server/src/scheduler/review-reminder.service.ts create mode 100644 packages/server/src/user/__tests__/member-progress.service.spec.ts create mode 100644 packages/server/src/user/__tests__/progress-photo-storage.service.spec.ts create mode 100644 packages/server/src/user/__tests__/subscription-message.service.spec.ts create mode 100644 packages/server/src/user/dto/member-progress.dto.ts create mode 100644 packages/server/src/user/member-progress.controller.ts create mode 100644 packages/server/src/user/member-progress.service.ts create mode 100644 packages/server/src/user/progress-photo-storage.service.ts create mode 100644 packages/shared/src/types/member-care.ts diff --git a/CLAUDE.md b/CLAUDE.md index de83cb8..ca270c0 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -104,3 +104,13 @@ pnpm deploy:server # 部署后端到生产环境 - 累计上课、本月上课、剩余课时集中在我的会员卡页面,个人资料卡不重复展示汇总。 - 次数限制以 remainingTimes 是否为 null 判断,不能按卡种推断。次数进度表示已用占总次数,已用包括预约占用;不限次卡不伪造耗课数。 - 会员卡加载失败显示重试,不当作无卡;会话变化时丢弃旧请求结果。 + +### 课后评价与成长档案 +- 评价归属 booking 模块,档案归属 user 模块;共享契约放 shared/src/types/member-care.ts,页面沿用 booking/profile/admin 目录,不新增顶层业务目录。 +- COMPLETED 后立即可评价,无 24 小时截止;完成后 24 小时仅提醒未评价预约。唯一 bookingId 防重复,提醒状态保存在 Booking 上,定时任务原子领取,未知发送结果不自动重发。 +- 星级均分与 NPS 分开:NPS 仅使用可选 0–10 推荐意愿(9–10 推荐者、0–6 贬损者),按中国自然月聚合并展示样本数。 +- 教练私密笔记必须在服务端过滤;课程批注必须属于该学员的已完成预约。体测允许缺项,不以缺项当 0;累计课时包含有效补录,里程碑为 10/30/50 节。 +- 照片仅用于学员与馆主之间的档案展示,不能用于公开宣传。学员本人按照片授权/撤回,馆主不能代授权。与馆图共用 COS 桶,对象前缀 `progress/`,上传为私有 ACL,读取用短时签名,禁止落库公共链接;上传凭证绑定学员及照片记录。 +- 新增迁移目录只放 migration.sql,测试沿用各模块 __tests__;部署配置与验收清单放 docs/member-care.md。 + +- 成长档案的两端共用 `components/MemberProgress.vue`,仅此跨端组件直接请求 progress API,避免主包引用 admin 分包 Store;馆主评价页面仍通过 admin Store 访问。 diff --git a/docs/member-care.md b/docs/member-care.md new file mode 100644 index 0000000..e79bcbd --- /dev/null +++ b/docs/member-care.md @@ -0,0 +1,41 @@ +# 课后评价与成长档案 + +入口:预约详情评价、个人中心「我的成长档案」、管理中心「课后评价」与会员档案「成长档案」。评价归属 booking 模块,档案归属 user 模块。共享契约在 `packages/shared/src/types/member-care.ts`。 + +## 产品口径 + +- 课程变为 COMPLETED 后即可评价,没有 24 小时截止。完成后 24 小时只提醒仍未评价的预约。 +- 同一预约只能评价一次。提醒状态写在 Booking 上,定时任务原子领取;发送结果未知或失败不自动重发。 +- 星级均分与 NPS 分开。NPS 只用可选的 0–10 推荐意愿(9–10 推荐者、0–6 贬损者),按中国自然月聚合并展示样本数。 +- 教练私密笔记只在服务端过滤。课程批注必须属于该学员的已完成预约。 +- 体测允许缺项,缺项不按 0 计算。累计课时含有效补录,里程碑为 10 / 30 / 50 节。 +- 成长照片仅用于学员与馆主之间的档案,不用于公开宣传。学员本人授权或撤回,馆主不能代授权。误传或学员主动删除会同时删除数据库记录和 COS 对象。 + +## 部署配置 + +新增环境变量(见 `packages/server/.env.example`): + +| 变量 | 作用 | +| --- | --- | +| `WX_SUBSCRIBE_TEMPLATE_CLASS_REVIEW` | 课后评价订阅消息模板 ID | + +成长照片与馆图共用 `COS_BUCKET`、`COS_SECRET_ID`、`COS_SECRET_KEY`、`COS_REGION`。对象写在 `progress/{userId}/` 下,上传带私有 ACL,读取用约 60 秒签名 URL,不落库公共链接。小程序合法域名沿用现有 COS 域名即可。 + +评价提醒模板字段由服务端按预约填充:`thing1` 课程名称(工作室名)、`thing2` 课程教练(Iris)、`time3` 课程时间、`thing4` 温馨提示。未配置模板 ID 时定时任务不领取预约。 + +回退:先回退应用代码。新增表可保留;`progress/` 下对象不会被旧代码读取。不要在生产直接 `DROP TABLE`。 + +## 迁移 + +目录 `packages/server/prisma/migrations/20260909120000_member_care/migration.sql`。发布时先 `prisma migrate deploy`,再发布后端,最后发布小程序。 + +## 验收清单 + +- 学员在 CONFIRMED 或 COMPLETED 且未评价时都可以订阅提醒;核销后仍能订阅。 +- 完成后可立即评价;重复提交返回已评价。 +- 首页匿名均分不含评论文案;管理端趋势按中国自然月,NPS 与星级分开展示。 +- 私密笔记学员不可见;馆主在学员授权前不能读取照片,授权后可看,撤回后不能再签发。 +- 误传照片可删除,删除后档案和 COS 对象都不再保留。 +- 体测可只填一项,柔韧度允许负值;累计课时含未撤销补录。 +- 未配置评价模板时,定时任务不领取预约。 +- 小程序真机确认可上传、可用签名链接预览成长照片。 diff --git a/packages/app/src/components/ClassReviewForm.vue b/packages/app/src/components/ClassReviewForm.vue new file mode 100644 index 0000000..5f8e563 --- /dev/null +++ b/packages/app/src/components/ClassReviewForm.vue @@ -0,0 +1,76 @@ +