From b452de379de3e00b7e40b65058ce503a06b7efbe Mon Sep 17 00:00:00 2001 From: richarjiang Date: Sun, 18 Oct 2026 14:59:48 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E6=96=B0=E7=89=88?= =?UTF-8?q?=E4=BC=9A=E5=91=98=E6=A1=A3=E6=A1=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/posture-assessment.md | 63 ++++++ docs/studio-shop.md | 6 + .../src/components/BodyAssessmentRecords.vue | 37 ++++ packages/app/src/components/CustomNavBar.vue | 6 +- .../app/src/components/MemberProgress.vue | 49 +---- .../app/src/components/PostureChecklist.vue | 33 +++ packages/app/src/pages.json | 6 + .../app/src/pages/profile/body-assessment.vue | 196 ++++++++++++++++++ .../migration.sql | 3 + packages/server/prisma/schema.prisma | 2 + .../shop-compatibility.controller.spec.ts | 44 ++++ ...op-order-compatibility.interceptor.spec.ts | 25 +++ .../shop-order-compatibility.interceptor.ts | 24 +++ packages/server/src/shop/shop.controller.ts | 4 + packages/server/src/shop/shop.module.ts | 3 +- .../__tests__/member-progress.service.spec.ts | 109 +++++++++- .../src/user/dto/member-progress.dto.ts | 15 +- .../src/user/member-progress.controller.ts | 5 +- .../src/user/member-progress.service.ts | 24 ++- packages/shared/src/index.ts | 1 + packages/shared/src/posture-assessment.ts | 125 +++++++++++ packages/shared/src/types/member-care.ts | 3 +- packages/shared/src/types/shop.ts | 2 + 23 files changed, 731 insertions(+), 54 deletions(-) create mode 100644 docs/posture-assessment.md create mode 100644 packages/app/src/components/BodyAssessmentRecords.vue create mode 100644 packages/app/src/components/PostureChecklist.vue create mode 100644 packages/app/src/pages/profile/body-assessment.vue create mode 100644 packages/server/prisma/migrations/20261018070000_posture_assessment/migration.sql create mode 100644 packages/server/src/shop/__tests__/shop-compatibility.controller.spec.ts create mode 100644 packages/server/src/shop/__tests__/shop-order-compatibility.interceptor.spec.ts create mode 100644 packages/server/src/shop/shop-order-compatibility.interceptor.ts create mode 100644 packages/shared/src/posture-assessment.ts diff --git a/docs/posture-assessment.md b/docs/posture-assessment.md new file mode 100644 index 0000000..211eb5c --- /dev/null +++ b/docs/posture-assessment.md @@ -0,0 +1,63 @@ +# 会员体测与体态检查表 + +会员档案 → 成长档案 → 体测 → 新建记录 / 查看 / 编辑。会员自己的成长档案可查看完整记录;新增、修改和删除沿用馆主权限。 + +## 纸质内容对应 + +检查项目按用户提供的《体态分析指南 检查表》照片逐项录入。共同定义位于 `packages/shared/src/posture-assessment.ts`,前端与服务端共用,避免选项漂移。 + +| 分区 | 内容 | +| --- | --- | +| 铅垂线 | 身体各部分与铅垂线相符;头部、胸部和骨盆排列对齐 | +| 侧视图(两侧均需检查) | 踝关节、膝部、髋关节、骨盆、腰椎、下胸椎、上胸椎、颈椎、头部 | +| 正面视图(两侧均需检查) | 足部、膝部、骨盆、肋骨架、肩部、头部;保留「如有必要,可参照后视图加以确认」提示 | +| 后视图(两侧均需检查) | 足部、股骨、骨盆、肩胛骨、肱骨 | +| 循序检查脊柱 | 从侧面观察是否有平直部位及位置;从背后观察并触碰检查是否有失衡部位及位置 | + +保留纸上每一行的右/左栏;无左右栏的项目按整体记录。左右始终指会员自身。不同解剖平面的观察可以并存,同一侧中立位与异常、同一平面的相反观察互斥。铅垂线和脊柱问题区分「是」「否」「未检查」,没有自动勾选正常项。脊柱选项从「是」改为「否」或未检查时会清空相应位置。 + +## 数据与兼容性 + +- 沿用 `body_metrics`、现有记录 ID、日期、体重、体脂率、腰围、臀围、柔韧度和备注,不删除或重建历史记录。 +- 仅新增可空的 `height DOUBLE NULL` 和 `assessment JSON NULL`。历史行无需回填,体态内容为空时显示原始测量,并允许打开详情、编辑和补充检查项。 +- `assessment` 使用 `version: 1`、检查行 ID、左右标记、铅垂线和脊柱观察保存。未选项目不推定为正常。 +- 所有数值字段及检查项目均可选。至少需要一项测量、检查结果或非空备注,防止误存完全空白的记录。 +- 保留 `POST /admin/members/:userId/progress/metrics`;旧客户端无需提交新增字段,仍可保存原有数据。 +- 新增 `GET .../metrics/:id`(馆主与会员各自的 progress 路径)和 `PUT /admin/members/:userId/progress/metrics/:id`。读取和修改均限定记录所属会员,会员端仅有读取权限。 +- PUT 为整份记录保存:未填写的数值写入 NULL、取消的检查项清空,修改原记录而非新增一条。服务端校验日期、数值范围、检查行、左右标记及互斥约束。 + +## 发布顺序 + +1. 使用现有发布流程备份数据库,并在服务端执行 `pnpm --filter @mp-pilates/server exec prisma migrate deploy`,应用 `20261018070000_posture_assessment`。这是仅新增可空列的迁移,原服务仍能使用原字段。 +2. 生成 Prisma Client、构建 shared/server 后发布服务端。 +3. 构建并发布小程序。旧版小程序在过渡期仍可通过原 POST 接口保存测量,新版可查看和编辑所有历史记录。 + +没有新环境变量。本地开发不会自动连接生产数据库或执行生产迁移。 + +## 验证重点 + +已有会员的旧测量原值展示、旧版请求无需新字段、新增仅体态检查、空数值清除、编辑后不新增副本、左右侧独立、多平面并存、相反结果互斥、记录归属校验、未保存离开提醒、保存失败保留表单,以及返回档案后刷新。 + +## 生产发布记录(2026-10-18) + +按用户授权,将体测功能与此前遗漏的商城「取消取货码、管理员直接完成交付」服务端改动一并发布。商城增加了旧版小程序响应兼容层,避免旧页面缺少取货码而无法提交交付。 + +- 服务器:沿用 `/usr/local/web/mp-pilates-server`、`/usr/local/web/mp-pilates-shared` 和 PM2 `mp-pilates-server`,Node 22.16.0、Prisma 5.22.0;保留现有环境配置、支付证书和依赖。 +- 成功应用 `20260925111500_drop_product_order_pickup_code` 与 `20261018070000_posture_assessment`,生产数据库的 13 个迁移均已完成。 +- 采用短暂停服的同步切换,更新 server/shared 构建、schema 和原生 Prisma Client 后重启;PM2 正常在线,没有异常重启,内网和公网健康检查均为 200。 +- 对迁移前后记录按 ID 排序并校验完整字段摘要:3 条历史体测原值完全一致;3 条商品订单除被移除的取货码外,其余原值完全一致。历史体测新增字段为 NULL,且数据库列允许 NULL。 +- 13 项线上接口检查通过:体测档案和详情读取、会员归属隔离、商城订单列表的旧版兼容码、管理汇总、匿名访问限制、会员管理权限限制和非法分页校验。 +- 发布前完整服务端测试为 31 个套件、480 项全部通过;shared/server 构建与小程序类型检查通过。没有创建真实测试订单、扣款或修改历史体测来做验证。 +- 发布包 SHA-256:`ad993fe92dd06b43eb4f33963dd3a72642debb5e9c501880c953e05643d1dd4c`。 + +备份和验证报告仅保存在服务器受限目录 `/usr/local/web/releases/posture-20261018-1792305938060/`: + +- `database-before.sql.gz`:完整逻辑备份,gzip 完整性检查通过。 +- `previous-build.tgz`、`prisma-client-before/`:旧运行文件、共享包、schema/迁移和生成的 Client。 +- `pickup-codes-at-switch.json`:切换时的旧取货码,供必要时精确恢复旧商城版本使用。 +- `data-baseline-at-switch.json`、`verification.json`:切换前的数据摘要及发布后的验证报告,不包含访问令牌。 +- `release.tgz`、`stage/`:本次发布包及解压后的暂存文件。 + +回滚旧商城版本时,需要同时恢复旧 `pickup_code` 列及对应值、旧运行文件和 Prisma Client,并核对迁移元数据,不能仅重启旧构建。体测新增的可空列可保留。完整数据库恢复用于灾难恢复,正常回滚不得覆盖上线后产生的新数据。 + +本次仅发布服务端。新的体测界面与商城发货界面仍需随小程序新版发布;已发布的小程序通过服务端兼容层继续使用。 diff --git a/docs/studio-shop.md b/docs/studio-shop.md index 10d8d2c..c69f87a 100644 --- a/docs/studio-shop.md +++ b/docs/studio-shop.md @@ -40,6 +40,12 @@ 状态:`PENDING → PAID → COMPLETED`;`PENDING → CANCELLED`。商品可下架但不删除,保证历史订单有效。 +### 已发布小程序的过渡兼容(2026-10-18) + +数据库删除 `pickup_code` 后,商城订单响应暂时保留可选的 `pickupCode` 字段,由订单 ID 派生为稳定的 12 位大写十六进制展示值。旧版小程序仍可展示、输入并提交这个值;新版小程序不使用它。它不落库,也不作为交付凭证或鉴权依据。完成订单仍必须通过馆主权限及 PAID 状态检查,新旧请求体均可接受。待旧版小程序退出使用后可移除此响应兼容层。 + +此兼容层及删列迁移已于 2026-10-18 与体测服务一并上线。旧订单除取货码外的原始字段摘要保持一致,线上订单列表、兼容字段和权限验证通过;详见 [本次生产发布记录](posture-assessment.md#生产发布记录2026-10-18)。 + ## 接口 公开:`GET /shop/products`、`GET /shop/products/:id`。 diff --git a/packages/app/src/components/BodyAssessmentRecords.vue b/packages/app/src/components/BodyAssessmentRecords.vue new file mode 100644 index 0000000..00ca103 --- /dev/null +++ b/packages/app/src/components/BodyAssessmentRecords.vue @@ -0,0 +1,37 @@ + + + + + diff --git a/packages/app/src/components/CustomNavBar.vue b/packages/app/src/components/CustomNavBar.vue index f79c247..5473495 100644 --- a/packages/app/src/components/CustomNavBar.vue +++ b/packages/app/src/components/CustomNavBar.vue @@ -23,12 +23,13 @@ diff --git a/packages/app/src/components/PostureChecklist.vue b/packages/app/src/components/PostureChecklist.vue new file mode 100644 index 0000000..58b6a48 --- /dev/null +++ b/packages/app/src/components/PostureChecklist.vue @@ -0,0 +1,33 @@ + + + + + diff --git a/packages/app/src/pages.json b/packages/app/src/pages.json index 9414e9f..74ffeca 100644 --- a/packages/app/src/pages.json +++ b/packages/app/src/pages.json @@ -75,6 +75,12 @@ "navigationStyle": "custom" } }, + { + "path": "pages/profile/body-assessment", + "style": { + "navigationStyle": "custom" + } + }, { "path": "pages/profile/progress", "style": { diff --git a/packages/app/src/pages/profile/body-assessment.vue b/packages/app/src/pages/profile/body-assessment.vue new file mode 100644 index 0000000..cd7c7b6 --- /dev/null +++ b/packages/app/src/pages/profile/body-assessment.vue @@ -0,0 +1,196 @@ +