Files
mp-pilates/docs/teaching-cases.md
2026-09-18 18:26:47 +08:00

7.5 KiB
Raw Blame History

教学案例展示

功能与入口

  • 管理中心 → 教学案例展示 → 新建 / 编辑。填写标题、学员化名、经历课时(节)、练习背景、变化与收获。
  • 每个案例支持 1–9 组图片:每组可以是练习前 / 后两张照片,也可以是一张已拼好的对比图;共最多 18 张原图。第一组为封面,可前后调整顺序。每张 JPG / PNG / WebP 不超过 10 MB。
  • 双图在同一画面并排展示,保留完整比例。手动滑动及左右按钮切换,提供张数、文字说明和点击放大;不自动轮播。
  • 编辑页可预览,并可把任意一组生成一张带标题、化名、课时和前后标签的对比图,通过图片预览保存。生成动作只在本地进行,不自动发布。
  • 管理员可保存草稿、发布、保存并下架、撤回授权并下架。排序数字越大越靠前,同序按创建时间和 ID 倒序。
  • 未登录访客:首页品牌区域之后,第一个内容模块展示最多 3 个已发布案例;无案例则不占位。登录用户仍优先显示快捷入口和即将开始的预约,随后展示案例。
  • 更多案例分页浏览;详情无需登录,支持分享及跳转至首页课程与体验区。下架案例的旧分享链接返回不可用状态。

数据与权限

新增 TeachingCase 和 TeachingCaseAsset 两张独立表。不关联或引用私密 ProgressPhoto,管理员不能利用成长档案授权直接公开照片。

公开接口:

  • GET /api/teaching-cases?page=1&limit=3
  • GET /api/teaching-cases/:id

管理接口均通过 JWT 及 ADMIN 角色校验:

  • GET/POST /api/admin/teaching-cases
  • GET/PUT /api/admin/teaching-cases/:id
  • POST /api/admin/teaching-cases/:id/withdraw
  • POST /api/admin/teaching-cases/assets/credentials
  • POST /api/admin/teaching-cases/assets/:id/complete

公开查询同时限制 published 与 consentConfirmed;白名单输出案例内容,不输出授权备注、授权时间及编辑版本。公开响应使用 no-store。分页最大 20 条。

图片流程为申请资产 → 上传私有 COS 对象 → HEAD 校验 → 标记完成 → 保存案例。对象固定在 teaching-cases/ 前缀下,保存时只接受资产表中已完成的 ID,不接受外部 URL、私密成长档案对象或未完成上传。

编辑版本通过条件更新递增;旧编辑页不能覆盖较新的修改或授权撤回。撤回操作同时取消发布、清除有效授权状态并增加版本;授权备注保留为管理记录,重新发布需再次确认。授权备注在请求日志中脱敏。

授权与内容约定

发布前管理员确认已取得学员单独的公开宣传授权,并记录日期、方式与凭证位置。这是线下授权记录,不是小程序替学员签署电子授权。照片、文字或用途变化后,应确认原授权覆盖新的内容。仅填写化名,不写身份证、诊断等无关信息;建议上传前遮挡面部和身份信息。系统不会自动识别面部、打码或移除 EXIF。

案例展示真实个人经历,不保证相同课时获得相同效果。照片建议保持相同视角、距离和光线,避免夸大变化。

COS 与缓存边界

沿用 COS_BUCKET、COS_REGION、COS_SECRET_ID、COS_SECRET_KEY,不新增环境变量。服务凭证须能上传私有对象并执行 HEAD / GET。确认桶策略没有给 teaching-cases/ 前缀额外开放匿名读取权限;对象 private ACL 不能抵消更宽泛的桶策略。

  • 上传签名有效 5 分钟;展示链接有效 15 分钟,重新进入页面或图片加载失败后刷新可获取新链接。
  • 下架立即阻止新查询,但已经签发的链接可能继续有效最多 15 分钟,已被下载的图片不能远程撤回。紧急移除需同时处理对应 COS 对象和任何独立缓存。
  • 微信合法域名需包含桶域名的 uploadFile / downloadFile;现有 API 域名继续用于 request。合成已有照片需要从 COS 下载,必须真机核对。
  • 中断上传及未保存编辑可能留下未引用资产。清理需先导出案例全部 frames 中的资产引用,核对后仅删除长期未引用资产,建议至少保留 7 天。不要给整个前缀配置自动过期规则,否则会删除有效案例图片。

发布与回退

按项目既有发布流程部署后端及小程序,发布前备份数据库并核对目标环境:

  1. 在后端环境执行 prisma migrate deploy,应用 20260918000000_teaching_cases,再生成客户端、部署后端。
  2. 验证匿名列表为空时正常返回、管理员权限、真实图片上传和读取。
  3. 发布小程序新版本,完成下方真机验收。

迁移仅增表,不修改原有业务数据。应用回退时保留两表及 COS 对象,避免丢失案例和授权记录;旧前端不使用新入口。不要自动执行 DROP TABLE 或批量删除照片。

验证

已完成共享包和后端构建、Prisma schema 校验、前端 vue-tsc、微信小程序生产构建、差异空白检查。新增服务/存储/HTTP 测试覆盖权限、草稿隔离、授权条件、上传完成性、多组图、分页参数及并发编辑。全量回归的普通测试在沙箱通过,HTTP 测试需要本机回环监听权限并已单独通过;身份在 HTTP 测试中模拟,角色守卫及 DTO 校验为真实实现。

仓库 pnpm lint 当前无法执行:server 声明了 eslint 命令,但未安装 eslint(command not found);本次未修改依赖来扩大范围。

真机 / 实际存储验收仍需完成:

  • 游客有 / 无案例、登录切换及首页刷新;已登录预约模块优先级。
  • 多组双图与合成图、长标题、小屏幕、滑动/按钮翻页与全屏预览。
  • 上传取消、断网重试、超大图、缺少半组照片、保存时重复点击。
  • 真机 Canvas 合成图正确、前后图不裁切、图片预览可保存。
  • 草稿不公开、授权撤回、旧分享链接失效、旧编辑页并发冲突。
  • 同一页面停留超过 15 分钟后图片刷新;确认 COS 前缀匿名访问被拒绝。

设计参考:移动端轮播可用性;个人信息保护法。

2026-09-18 生产发布记录

  • 部署前发现生产已上线商城、当前工作区落后一个提交;已快进同步 95b9f65 并恢复教学案例改动,保留商城模型、接口及前端入口。没有提交或推送教学案例改动。
  • 合并后共享包/后端构建、前端类型检查通过;29 个测试套件、455 项测试全部通过。
  • 服务器本地备份:/usr/local/backups/mp-pilates/2026-09-18T10-20-50-357Z-teaching-cases/。包含 database.sql.gz 与 backend.tar.gz,已检查压缩包完整性;权限限制为服务器管理员访问。
  • 使用 pnpm deploy:server 完成上传。部署脚本补充排除整个 logs 目录,避免上传本地日志轮转索引覆盖生产索引;生产 .env 保持不变。
  • 生产数据库 db_mp_focus 于北京时间 18:22:18 应用 20260918000000_teaching_cases,新增两张表可查询,暂为 0 条记录;商城现有商品记录保留。
  • 服务器本地及公网 HTTPS:health 200、teaching-cases 200(空列表)、未登录 admin/teaching-cases 401;不存在的案例 404。商城 products 接口 200。
  • PM2 服务 mp-pilates-server online,部署后检查无异常重启。
  • 本次完成生产数据库迁移及后端发布;未发布微信小程序,未替代真实照片上传、Canvas 合成和真机界面验收。