扫码体测 · 用户端原型 + 管理后台 + 技术方案

对接广州海迪 HOWBODY 体成分分析仪(API V2.4.1,二维码对接 + 报告推送)。按真实产品流程组织——用户端(C 端):入口 → 扫码「确认开始体测」→ 购买体测次数 → 绑定与上秤测量 → 体成分报告 → 记录/次数/订单;管理后台(B 端):体测仪-门店序列号绑定;技术:交互时序图、接口契约与关键考量、开发文档。资料补全与次数配额均落到练二既有体系。
海迪 V2.4.1 · 二维码对接 + 推送 资料复用 user/info(性别·生日现成 + 身高补全) 体测次数 = 复用次卡权益体系 归属 thirdUid · 幂等 dataKey

0概述 · 端到端动线

到店 → 体测仪出码(注 equipmentNo+scanId)→ 会员小程序扫一扫 → 打开「确认开始体测」页(确认资料·缺身高则补 + 校体测次数)→ 点「确认并开始」核销 1 次并调海迪绑定 → 设备关码 → 会员上秤测量 → 海迪 push 报告 到练二 → 「我的」最近体测卡 / 体测记录 查看。

1信息架构 · 页面地图

用户端(C 端) 6 个产品段 + 管理后台(B 端) 设备绑定;下表列出每段包含的页面/状态屏,便于导航定位。

流程段包含的页面 / 状态屏
入口我的页含「最近体测」卡 · 空态(未测过)
扫码 → 开始体测未登录拦截 · 确认开始(有次数)· 确认开始(无次数 → 购买)· 资料编辑弹窗 · 健康数据授权 · 监护人同意 · 授权被拒 / 撤回
购买体测次数购买次数半屏 · 次数包下单确认 · 支付失败回流 · 购买成功回流
绑定与测量绑定处理中 · 请上秤引导 · 测量进行中 · 测量未出数 · 绑定失败 · 会话过期 · 设备未注册 / 离线
报告报告生成中 · 报告超时 + 订阅 · 体成分报告 · 体成分报告补全 · 首测无对比 · 报告错误兜底 · 指标解读弹层 · 删除报告确认 · 分享海报
记录 · 次数 · 订单体测记录(趋势 + 历次)· 次数明细 / 流水 · 体测次数订单 · 体测次数订单详情
管理后台(B 端)体测仪-门店绑定:列表 + 筛选 + 新增/编辑 + 删除 + 启停(路由 /store/bodyDevice

2入口 ·「我的」页最近体测卡

单独一张卡,挂在「我的」页(pages/user/index.vue)私教卡区与三宫格之间,承载最近一次结论,点击进入体测记录;未测过时显示空态引导。

9:415G
练二会员
1280 积分 ›
我的会员卡 (武汉店)
有效期 2026-05-22 至 2027-05-21
私教次卡
私教时长卡
最近体测体成分
06-05 · 查看记录 ›
74健康分
体重
65.7kg ▼0.1
体脂率
20.0% ▼0.3
骨骼肌
29.4kg ▲0.0
内脏脂肪
5 正常
BMI 22.6 · 基代 1501 kcal完整报告 ›
我的页含「最近体测」卡
  • 健康分环 + 4 指标,每项带与上次对比箭头
  • 整卡点击 → pages/user/bodyTest
9:415G
练二会员
1280 积分 ›
还没有体测记录
到店扫描体测仪二维码,1 分钟生成专业体成分报告
了解体测 ›
我的课程
我的订单
优惠卡券
空态(未测过)
  • 无记录 → 引导到店体测,不强推

卡片字段(海迪体成分字典)

元素字段说明
健康分(环)healthScore0–100 + 颜色分级
体重weight/weight2kg + ▲▼
体脂率pbf/pbf2% 越低越好
骨骼肌smm/smm2kg 越高越好
内脏脂肪vfr级 1–9
副文案bmi/bmrBMI·基代
箭头方向:体重/体脂率/内脏脂肪「↓绿↑红」;骨骼肌/基代「↑绿↓红」;无上次值不显示。

3扫码 → 开始体测

扫码后小程序打开「确认开始体测」页(带 equipmentNo+scanId,新页 pages/fitness/bodyTestConfirm):先校登录,再确认会员资料(性别/生日来自档案、身高首次补全)、健康数据授权(PIPL 单独同意,未成年须监护人同意),再校体测次数。

9:415G
已与体测仪配对
海迪体测仪 HD11012511
练二健身(武汉店)
登录后开始体测
登录后将原地继续,不丢失本次配对
微信一键登录
未登录拦截
9:415G
已与体测仪配对
海迪体测仪 HD11012511
练二健身(武汉店)· 会话 5 分钟有效
确认体测资料 去修改
姓名练二会员
性别
出生日期1998-05 · 28 岁
身高 需补全175 cm
3 次
剩余体测次数
本次预占 1 次 · 测完才扣
性别/生日来自会员档案;身高补全后写回档案(下次免填)。资料用于海迪计算,仅本次体测。
确认资料并开始体测
确认开始(有次数)
  • 资料确认:性别/生日现成,身高 inline 补填
  • 剩余次数 + 「本次核销 1 次」
  • 点按钮 → 扣次 + 海迪绑定 → 设备解锁
9:415G
已与体测仪配对
海迪体测仪 HD11012511
练二健身(武汉店)
确认体测资料 去修改
性别 / 年龄男 · 28 岁
身高175 cm
0 次
暂无体测次数
购买后即可开始
体测次数包
单次体测¥39
5 次卡 省 36¥159
购买体测次数
确认开始(无次数 → 购买)
  • 0 次 → 底部转「购买体测次数」
  • 购买复用现有下单 + 支付(次数包商品)
9:415G
完善体测资料
性别
出生日期1998-05-12 ›
身高 必填175 cm
范围 80–250cm,请按厘米填写(如 175 而非 1.75)
保存
资料编辑弹窗(身高校验)
9:415G
已与体测仪配对
海迪体测仪 HD11012511
确认体测资料
性别 / 年龄男 · 28 岁
体测数据授权
为完成体测,需向第三方·广州海迪提供你的性别 / 身高 / 年龄 / 手机号,用于体成分计算。数据保留期 X 个月,可在「我的-体测」随时删除/撤回授权。详见《健康数据授权协议》。
我已阅读并同意《健康数据授权协议》
不同意
同意并开始
健康数据授权(PIPL 单独同意)
9:415G
需监护人同意
检测到你未满 14 周岁,体测须监护人同意(PIPL §31)。请监护人确认授权:
监护人手机号请输入 ›
暂不体测
监护人已同意
未满 4 周岁不支持体测
监护人同意(<14 岁)
9:415G
未授权,无法体测
需同意《健康数据授权协议》
方可开始体测
重新授权
你已于 06-01 撤回授权
授权被拒 / 撤回

资料补全 · 落到练二既有字段

复用 pages/user/info.vue 的字段与接口,不另起一套。海迪 setUserInfo 需 性别/身高/年龄。

海迪需要练二既有字段状态
sex 性别gender(1男/2女)✅ 现成
age 年龄birthday 推算✅ 现成
height 身高—(无)⚠️ 唯一需新增
tel 手机号phone✅ 现成
加载/保存接口(复用)
载入 getUserInfo/user/front/getUserInfo
保存 setUserInfo/user/front/setUserInfouserStore.saveAppUserInfo
后端待办(先改不提交):练二 /user/front/setUserInfo 增加 height 字段持久化;会员档案表加身高列。区分两个同名接口:练二 setUserInfo = 存档案海迪 setUserInfo = 体测绑定

4购买体测次数

次数为 0 时引导购买(复用现有下单 + 支付,次数包商品),购买在守会话时效下闭环:半屏选包 → 下单确认 → 支付(失败可回流重试)→ 到账回流继续本次体测。

9:415G
购买体测次数
会话剩余 00:48,购买后将自动续期本次体测
单次体测¥39
5 次卡 省 36¥159
10 次卡 省 91¥299
合计¥159
微信支付
购买次数半屏(守时效)
9:415G
体测次数 · 5 次卡¥159
优惠券自动选最优−¥10
商品金额¥159
优惠−¥10
实付¥149
已阅读《体测次数购买与退款须知》
确认支付 ¥149
次数包下单确认
9:415G
支付未完成
会话剩余 00:42,请尽快完成,超时需重新出码
放弃
重新支付
支付失败回流(守时效)
9:415G
已到账 5 次
本次会话仍有效,可直接开始
继续开始体测
若已超时 → 请在设备重新出码
购买成功回流

5绑定与测量

点「确认并开始」后:冻结 1 次 → 调海迪绑定(成功才落实,失败退冻)→ 设备解锁 → 会员上秤测量。覆盖绑定中/上秤/测量中/未出数/绑定失败/会话过期/设备异常等走通必需的状态。

9:415G
正在为你开通体测…
占用 1 次体测次数(预占)
校验设备 HD11012511
绑定体测仪 / 解锁中
请勿退出,约 3 秒
绑定处理中(禁返回)
9:415G
绑定成功,请上秤测量
HD11012511 设备上:
赤脚站上踏板 · 双手握住电极 · 保持不动
赤脚
握电极
站直
已预占 1 次 · 取消本次(退回次数)
请上秤引导
9:415G
正在测量…请保持站姿
赤脚握住电极 · 约 30 秒
测量进行中
9:415G
本次未测出数据
· 是否赤脚踩在金属电极上?
· 双手是否握住手柄电极?
· 测量中是否移动了身体?
重新测量
本次未消耗次数
测量未出数 · 重测
9:415G
设备绑定失败
设备被占用或网络异常。
已退回次数,未扣费
返回
重试
绑定失败(已退冻)
9:415G
二维码已过期
会话有效期为 5 分钟,已超时。
本次未扣次数(已退回)。
在设备上重新出码并扫码
会话过期(scanId 超时)
9:415G
设备暂时不可用
该体测仪未启用或当前离线。
本次未扣次数,请联系前台协助。
联系门店
重新扫码
设备未注册 / 离线

6报告

海迪 push 报告到练二后,会员在报告页查看体成分结论。覆盖生成中/超时订阅触达、正式报告与补全(节段/目标/更多指标)、首测降级、加载兜底、指标解读与免责、删除、脱敏分享。

9:415G
报告生成中…
体成分数据已回传
体成分报告解析中
报告生成需要一点时间,可先离开,稍后在「我的 - 体测」查看,或开启提醒到账即通知。
开启「报告生成」提醒
报告生成中(订阅触达)
9:415G
报告生成较长
设备繁忙,报告稍后生成。
开启提醒,到账即通知你。
开启到账提醒
可先离开,「我的-体测」随时查看
报告超时 + 订阅
9:415G
74健康分
身体状况 · 良好
2026-06-05 14:30 · HD11012511
代谢年龄 27 岁(实际 28)
体重65.7kg 标准
53.5标准 53.5–7272
体脂率 PBF20.0% 标准
10标准 10–2020
骨骼肌 SMM29.4kg 偏低
27.1标准 27.1–33.133.1
内脏脂肪
5 正常
基础代谢
1501kcal
保存/分享
据此约私教
体成分报告
  • 每项:值 + 单位 + 正常范围条 + 达标色 + 偏离
9:415G
节段分析肌肉 · 脂肪
左臂 2.8kg右臂 2.6kg 躯干 22.7kg 左腿 8.2kg右腿 8.3kg
体重管理目标
目标体重63.7 kg
脂肪控制−3.6 kg
肌肉控制+1.6 kg
据此约私教解读
更多指标 展开 ›
去脂体重 · 蛋白质 · 无机盐 · 身体水分 · 腰臀比 · 细胞内外液 · 代谢年龄 27
体成分报告补全(节段/目标/指标)
9:415G
74健康分
首次体测 · 良好
2026-06-05 14:30
这是你的首份报告,下次体测即可看到变化趋势
体重65.7kg
体脂率20.0%
趋势图:仅 1 个数据点,再测一次即可成线
首测无对比 · 降级
9:415G
报告加载失败
网络异常或报告暂不可用,
请稍后重试。
重试
仍有问题?联系门店
报告错误兜底
9:415G
体脂率 PBF
你的数值20.0% 标准
正常范围(海迪口径)10 – 20%
体脂率指脂肪占体重的比例。偏高建议增加有氧运动、控制精制糖摄入;偏低需关注营养与激素水平。
仅供健身参考,非医疗诊断。孕妇、植入起搏器等人群不建议使用生物电阻抗(BIA)测量。
指标解读弹层(含免责)
9:415G
删除这份报告?
删除后不可恢复,该体测报告将永久移除。
取消
删除
删除报告确认
9:415G
练二健身 · 体测报告
74健康分
20.0%
体脂率
29.4
骨骼肌
22.6
BMI
长按识别 · 到店体测
隐藏手机号已开(默认)
保存图片
分享给好友
分享海报(脱敏)

7记录 · 次数 · 订单

沉淀页:体测记录(趋势 + 历次列表)、体测次数明细/流水,以及购买次数生成的订单(落进「我的订单」新增「体测」tab,接 V0510 退款体系,详见开发文档 11.10)。

9:415G
体脂率趋势体重 · 体脂率 · 骨骼肌
3-023-304-285-206-05 20.0%
74健康分
2026-06-05 14:30 最新
体重 65.7kg · 体脂率 20.0% · 骨骼肌 29.4kg
72健康分
2026-05-20 10:12
体重 65.8kg · 体脂率 20.3% · 骨骼肌 29.4kg
68健康分
2026-04-28 19:40
体重 66.4kg · 体脂率 21.1% · 骨骼肌 29.1kg
66健康分
2026-03-30 18:02
体重 67.0kg · 体脂率 21.8% · 骨骼肌 28.9kg
体测记录(趋势 + 历次)
  • 趋势曲线(指标可切换),用海迪每条报告的值聚合
  • 列表每条:健康分 + 日期 + 三项核心;点进详情
  • 同日多次取最近;下拉分页(signs.vue 范式)
9:415G
剩余可用
3
适用 练二(武汉店)· 最近 1 次 12-31 到期
购买 5 次卡
06-05 14:20
+5
会员卡附赠
05-22
+2
体测核销
06-05 14:31
−1
绑定失败退回
06-03
+1
次数明细 / 流水
9:415G
私教订单场地卡团课积分体测
全部待支付已支付已退款已关闭
订单号 1786…3012已支付
体测次数 · 5 次卡
练二健身(武汉店)
下单 2026-06-05 14:20
总计¥149
订单号 1779…6088已退款
体测次数 · 单次
练二健身(汉口店)
退款金额¥39 ›
体测次数订单(订单中心新增 tab)
9:415G
购买商品体测次数 · 5 次卡
订单金额¥159.00
优惠金额−¥10.00
实付金额¥149.00
门店练二(武汉店)
订单编号1786…3012
创建时间06-05 14:20
次数使用已核销 1 / 共 5 次
已核销不退,未核销 4 次按单价折算退款(接 V0510 退款体系)
申请退款
体测次数订单详情

8管理后台 · 体测仪-门店序列号绑定 已落地

B 端(管理后台 lianer-backend-ui)功能:门店把体测仪序列号(SN)登记并绑定到门店,列表 / 新增 / 编辑 / 删除 / 启停。一台序列号全表唯一绑定一个门店(反向唯一),一个门店可多台。此表是扫码体测链路「序列号 → 门店」的权威映射 + 白名单来源。

功能定位:体测仪到店后,运营在管理后台录入设备序列号并绑定门店;扫码体测时后端据此反查门店、做白名单校验(未注册 / 停用直接拒绝)。归在「门店管理」下,镜像现有门禁设备(FaceDevice)管理,零新范式。

管理页原型(路由 /store/bodyDevice · ElementUI)

练二管理后台 · 门店管理 / 体测仪绑定
门店 ▾ 全部 序列号:________ 状态 ▾ 全部 搜索重置 + 添加体测仪
#序列号 equipmentNo绑定门店状态备注创建时间操作
1HD11012511练二(武汉店)启用前台06-05 14:20编辑 · 删除 · 停用
2HD11012512练二(武汉店)启用二楼器械区06-05 14:22编辑 · 删除 · 停用
3HD22033100练二(汉口店)停用维修中05-30 09:10编辑 · 删除 · 启用
共 3 条   ‹ 1 ›
+ 添加 / 编辑体测仪(抽屉)
绑定门店 *武汉店 ▾
序列号 *HD11012511
状态● 启用 ○ 停用
备注选填
取消确定
序列号唯一校验:已被别店绑定 → 「该序列号已绑定门店 X」

接口(/user/back/* · 已建)

功能接口
分页列表POST /user/back/getBodyDeviceList
新增 / 编辑POST /user/back/addOrUpdateBodyDevice(唯一校验 + 反填门店名)
删除POST /user/back/delBodyDevice
启用 / 停用POST /user/back/changeBodyDeviceStatus
门店下拉复用 /ground/back/getStoreList

字段与校验

字段说明 / 校验
equipmentNo 序列号必填;全表唯一(DB uk_equipment_no + 保存前 selectByEquipmentNo 排重)
storeId 门店必填;据此反查 lianer_store 反填 storeName(不信任前端传名)
deviceStatus 状态1 启用 / 0 停用,默认 1
remark 备注选填 ≤255
与扫码体测衔接:扫码解析到 equipmentNoselectByEquipmentNo 反查 → 查不到(未注册)/ deviceStatus=0(停用)拒绝;命中且启用 → 取 storeId 继续(创建会话 / 归属门店 / 匹配本店次数)。封装 resolveStoreByEquipmentNo 供 scanPrepare 与 webhook 共用。
落地状态:后端 lianer-backLianerBodyDevice + Mapper + BodyDeviceBackApi/Impl + 表 lianer_body_device已编译通过、未提交(先改不提交,建表 SQL 待执行);前端 lianer-backend-uiviews/store/bodyDevice.vue + api/bodyDevice.js + 路由)已提交推送

9交互时序图 · 会员 / 小程序 / 练二后端 / 海迪云 / 体测仪

蓝实线=接口调用,灰虚线=返回/推送,橙虚线=物理动作(扫码 / 上秤)。注意区分练二 setUserInfo(存档案)与海迪 setUserInfo(体测绑定)。

会员 练二小程序 练二后端 海迪云 体测仪(海迪) ① 前置配置 + 鉴权 + 设备出码 ② 扫码 →「确认开始体测」页(资料确认 + 次数) ③ 核销 + 海迪绑定 + 测量 ④ 报告推送 + 查看 配置:练二申请 appKey/userName;提供 登入URL + 推送 webhook 给海迪 POST /openApi/getToken token(24h 缓存) 请求登录二维码 用练二登入URL生码(注 equipmentNo+scanId·5min) 设备显示二维码 点「扫一扫」 扫描设备二维码(读 equipmentNo + scanId) 打开「确认开始体测」页 getUserInfo 载入会员资料 资料(gender/birthday/height?) 缺身高?会员补填 练二 setUserInfo 存档案(身高落库) getRightsList 查体测次数 剩余次数 次数=0 → 购买体测次数(复用下单+支付),购买后返回本页 点「确认并开始体测」 冻结 1 次(预占) + 请求绑定 海迪 /setUserInfo {thirdUid,scanId,sex,height,age,tel} 绑定成功 200 关闭二维码 · 允许测量 绑定成功,请上秤开始测量 会员上秤测量(体成分) 上传测量结果 推送【体成分】(appkey){thirdUid,dataKey,…} 校 appkey + dataKey 幂等 · scanId 反查归属落库 + 真扣次(SETTLED) 200 推送成功 我的 → 最近体测/记录 拉取列表 / 详情 报告数据(体成分)→ 展示

10接口契约与关键考量

接口一览

接口方向关键参数 / 说明
POST /openApi/getToken练二后端 → 海迪userName,appKey,timeStamp → token(24h 缓存)
登入鉴权 URL练二 → 海迪后台配置海迪注入 equipmentNo+scanId 生成二维码
GET /user/front/getUserInfo小程序 → 练二后端载入会员资料(gender/birthday/height)复用现有
POST /user/front/setUserInfo小程序 → 练二后端存练二档案(补身高)复用现有,后端加 height
POST /payment/front/getRightsList小程序 → 练二后端查体测次数(新增一种次数权益)
核销体测次数小程序 → 练二后端仿 setPrivateAppointBySchedule 扣 1 次(新接口)
POST /openApi/setUserInfo练二后端 → 海迪体测绑定{equipmentNo,thirdUid,scanId,tel,sex,height,age};header token/appkey
推送【体成分】webhook海迪 → 练二后端练二提供;含 thirdUid,dataKey + 全指标
报告列表 / 详情小程序 → 练二后端练二自建,复用 XHR+token

关键考量(三视角完整性批判 · P0/P1/P2 分级)

业务/技术/合规三视角去重分级:P0 不解决必出事故/资损/违规;P1 上线前必须有方案;P2 体验运营完善。

P0 · 上线前必须闭环(否则必出事)
1. 核销=「预占冻结」,不是点确认即扣:硬扣遇绑定失败/会员离场/报告永不到达就白扣无回滚(资损客诉)。→ 三态 FROZEN(确认时冻结) → SETTLED(收到合格报告才真扣) → RELEASE(失败/超时自动退);后端建 measure_session 表 + 超时兜底任务。
2. 扣次与海迪绑定的事务顺序 + 失败回滚:先扣后绑、绑定失败 = 次数没了还测不了。→ 绑定成功才落实扣减;已冻结则绑定失败幂等回滚释放;确认按钮防抖 + 后端按 (userId,scanId) 幂等,杜绝重复扣/重复绑。
3. 报告归属以 scanId 为锚,严防挂错人:按 equipmentNo 归属 → 同设备前后两会员的数据挂错人(隐私事故)。→ 用 scanId 反查「未关闭 session 且 thirdUid 一致」才落库,否则进异常隔离表人工核对;同设备会话串行化
4. 报告触达闭环(订阅消息基建从零搭):异步推送时会员多已离店,全仓requestSubscribeMessage,只靠主动打开会大量丢失,丢掉体测核心价值。→ 确认页申请一次性订阅,webhook 落库即推「报告已生成」直达报告页(需单独立项排期)。
5. 健康 + 未成年人数据的单独同意 + 第三方告知:体成分属敏感个人信息须「单独同意」(PIPL §28);向海迪传 tel/性别/身高/年龄属对外提供须单独告知(§23);年龄下限 4 岁,<14 岁须监护人同意(§31)。沿用注册总协议 = 违规可被下架整改。→ 确认页独立健康数据授权弹窗(列明第三方=海迪/字段/用途/期限/可撤回),存带时间戳+版本的同意记录;按生日分级;与海迪签 DPA。
P1 · 上线前需明确方案
类别考量 → 处理
计费 / 权益体测次数做独立权益(勿复用私教次卡,会员会反弹):会员卡附赠 / 单售次数包 / 活动赠送,扣减只动该池。退款:已核销不退、未核销按单价退、附赠不折现,接现有退款引擎。
设备 / 门店 已建lianer_body_device(已建):确认页/扫码链路 selectByEquipmentNo 反查门店再匹配本店次数,跨店策略写死;服务端白名单校验(未注册/停用直接拒绝、不冻结)。管理后台 store/bodyDevice 维护绑定。
异常容错海迪错误码映射人话(「设备离线,请联系前台」)+ 一键联系门店(复用企微客服弹窗);scanId 过期给「重新出码」;后台留「已核销未收到报告」对账表。
扫码契约home.vue 扫码用无 try-catch 的 JSON.parse,海迪码会 parse 抛错进不了页 → 入口格式嗅探(try-catch + 海迪码特征)再分发;先与海迪确认 payload 确切格式。
首测降级落库带 isFirst 标记,首测隐藏对比箭头改正向引导文案,趋势单点给空态(防 NaN)。
合规细则身高 80–250cm / 年龄 4–99 范围+单位校验(防 1.75 当米);报告固定医疗免责 + BIA 禁忌人群(孕妇/起搏器)提示;正常范围只透传海迪口径不自算数据保留期 + 删除权(「我的-体测」删单条,注销清理/解绑 thirdUid)。
技术健壮dataKey 幂等存 (dataKey,bodyHash):同 hash 返 200、不同 hash 版本覆盖留痕;报告先于 session 到 → pending 待认领补挂。getToken 单飞+锁防击穿,遇「会话无效」作废重取。scanId 拆两个时钟:5min 只覆盖「扫码→绑定」,测量时效在设备侧;确认页倒计时剩 <60s 禁用按钮。
P2 · 体验与运营完善

11开发文档(前端 / 后端 / 数据 / 接口 / 排期)

落到练二真实工程:用户端 lianer-user-app(UniApp Vue3 + TS + Pinia)、后端 lianer-back(Spring Boot / Dubbo / Shenyu)。约定:后端「先改不提交」,前端每步 commit+push。新建一个 fitness(体测)业务域承载。

11.1 核心数据流

设备出码(海迪注 equipmentNo+scanId) → 小程序扫码进 bodyTestConfirm → 后端 scanPrepare(解析门店+校设备+读资料+查次数) → 用户补身高/确认 → 点开始 → 后端 confirmStart(冻结1次 + 调海迪 setUserInfo 绑定,失败即退冻) → 海迪关码、上秤测量 → 海迪 push 报告到练二 webhook(dataKey 幂等 / scanId 反查归属) → 后端落库 + 真扣次(SETTLED) + 订阅消息推达 → 小程序「我的」最近体测卡 / 记录查看。

11.2 核销状态机(measure_session)

FROZEN 冻结(点「确认开始」时占用 1 次) — 绑定成功 + 收到合格报告 → SETTLED 真扣(终态)
FROZEN — 绑定失败 / scanId 超时 / 超时窗口内无报告 → RELEASED 退回次数(终态)
超时兜底定时任务扫 FROZENexpire_time 已过的会话:收到过合格报告 → 转 SETTLED;否则 RELEASED 退冻。真扣只发生在收到合格体成分报告时

11.3 前端任务(lianer-user-app)

页面 / 文件改动复用
pages/user/index.vue加「最近体测」卡(健康分环 + 4 指标 + 对比箭头),点击跳 bodyTest;空态卡现有卡片样式
pages/index/home.vue openPromotion扫码分发加格式嗅探(try-catch 包 JSON.parse)+ 海迪登入码分支 → 跳 bodyTestConfirm;未知码兜底 toast现有扫一扫
pages/fitness/bodyTestConfirm确认开始体测:设备卡 + 资料确认(性别/生日现成、身高 inline 补填)+ 次数(核销/购买)+ 倒计时 + 健康授权弹窗 + 「确认并开始」getUserInfo/setUserInfogetRightsList
pages/user/bodyTest体测记录:趋势(Canvas/uCharts)+ 历次列表(下拉分页)signs.vue 分页范式
pages/user/bodyTestDetail报告详情:体成分报告(范围条/达标色/对比),保存/分享/删除orderDetail 范式、Poster.vue
api/fitness.tsscanPrepare / confirmStart / quota / buyQuota / reportList / reportDetail / deleteReportXHR + token
订阅消息首次引入 uni.requestSubscribeMessage(在确认页申请「报告生成」模板)
身高/单位校验height 80–250cm、单位提示、异常二次确认;首测 isFirst 隐藏对比箭头

11.4 后端任务(lianer-back · 先改不提交)

模块职责
海迪客户端 HaidiClient封装 getToken单飞+分布式锁缓存 24h,遇「会话无效」作废重取)、setUserInfo(绑定,header token/appkey/timestamp)
登入 URL 提供提供小程序 scheme / H5 中转页模板,海迪注入 equipmentNo+scanId → 唤起 bodyTestConfirm(形态待与海迪确认
会话/核销 BodyTestSessionServicescanPrepare(解析门店+校设备+资料+次数)、confirmStart(冻结→绑定→失败退冻,按 (userId,scanId) 幂等)、超时兜底定时任务
推送 webhook BodyTestPushApi接体成分接口:校 appkey + dataKey 幂等(存 bodyHash) + scanId 反查归属 + 落库 + 真扣(SETTLED) + 推订阅消息;找不到 session 进 pending 待认领
体测次数权益新增独立「体测次数」权益类型(不碰私教次卡),来源 会员卡附赠/单售/赠送;核销扣该池;退款规则接入 RefundBusiness
设备-门店绑定 已建已落地BodyDeviceBackApi/Impl(lianer-user,/user/back/getBodyDeviceList·addOrUpdateBodyDevice·delBodyDevice·changeBodyDeviceStatus)+ 表 lianer_body_deviceuk_equipment_no 反向唯一、新增唯一校验+反填门店名);扫码链路用 selectByEquipmentNo 反查 + 白名单校验(未注册/停用拒绝)。管理后台见前端 views/store/bodyDevice
会员档案 /user/front/setUserInfo新增 height 字段持久化;会员表加身高列
报告读接口 + 合规reportList/Detail/delete;数据保留期 + 删除权(删库 + 解绑 thirdUid);健康授权记录

11.5 数据库表设计(新增)

关键字段
lianer_body_test_session 会话/核销id, user_id, scan_id, equipment_no, store_id, quota_id, status(FROZEN/SETTLED/RELEASED), bind_time, settle_time, expire_time, fail_reason;唯一键 (scan_id)
lianer_body_test_report 报告id, user_id, scan_id, data_key(唯一), body_hash, equipment_no, store_id, test_time, health_score, raw_json, 提取的核心指标列(weight/pbf/smm/vfr/bmi/bmr…), created_at
lianer_body_test_quota 次数(或并入 rights 体系)id, user_id, total, remain, source(buy/gift/card), order_no, store_scope, expire_time
lianer_body_device 设备↔门店 已建id, equipment_no(唯一 uk_equipment_no), store_id, store_name(冗余), device_status(1启/0停), remark, created_time, updated_time
lianer_health_consent 健康授权user_id, version, scope, third_party(haidi), agreed_at, revoked_at
会员表 ALTERheight(cm) 列

11.6 练二自建接口清单

接口方向入参 → 出参
POST /fitness/front/scanPrepare小程序 → 后端{equipmentNo,scanId} → {storeName, needHeight, profile{gender,age,height}, quota{remain}, expireIn}
POST /fitness/front/confirmStart小程序 → 后端{equipmentNo,scanId} → 冻结+绑定结果(成功/失败原因)
GET /fitness/front/quota小程序 → 后端→ {remain, items}
POST /fitness/front/buyQuota小程序 → 后端{skuId} → 复用下单+支付
GET /fitness/front/reportList小程序 → 后端分页 → 历次(体成分)
GET /fitness/front/reportDetail小程序 → 后端{dataKey/sessionId} → 体成分详情
POST /fitness/front/deleteReport小程序 → 后端{id} → 删库
POST /fitness/openapi/push/body海迪 → 后端体成分 webhook(header appkey)
复用现有
/user/front/getUserInfo · setUserInfo小程序 → 后端载入/保存资料(setUserInfo 加 height)
/payment/front/getRightsList小程序 → 后端权益/下单/支付/退款复用

11.7 海迪字段 → 练二库 映射(节选)

海迪练二落库用途
thirdUiduser_id(绑定时传练二 userId)归属
dataKeydata_key(唯一 + bodyHash)幂等
scanIdscan_id会话反查归属
healthScore/weight/pbf/smm/vfr/bmi/bmr/...提取为列 + raw_json 全量卡片/报告/趋势
weight2/pbf2/...不依赖,趋势以练二历史自算环比对比(降耦合)

11.8 里程碑与排期

M1 · MVP(跑通闭环)
M2 · 进阶

11.9 依赖与待确认(找海迪 / 内部拍板)

11.10 订单与退款(体测次数包 · 接入既有订单体系)

体测次数是付费商品,购买即生成订单,必须落进「我的订单」并接 V0510 退款体系。订单 ↔ 次数解耦:订单负责支付与退款,次数(quota)负责核销;支付成功发次数、退款扣未核销次数。

① 订单中心新增一类「体测」

pages/order/index.vue 现有 4 个一级 tab(私教订单 / 场地卡 / 团课 / 积分订单)→ 新增第 5 类「体测次数」orderType 新值),新建组件 order/component/fitnessItem.vue复用 memberItem.vue 范式:二级 tab(全部 / 待支付 / 已支付 / 已退款 / 待退款 / 已关闭),卡片含 订单号 / 商品(体测 5 次卡) / 门店 / 下单时间 / 总计 / 状态 / 退款金额。订单详情复用 card/orderDetail.vue 范式(van-cell + 底部按钮)。

② 下单 → 支付 → 发次数

buyQuota复用的下单(memberOrderInfo 同构) + 支付(createPayOrder / trCreateMemberOrder);支付成功回调发放次数到 lianer_body_test_quota(source=buy, order_no 关联),并写订单记录;订单与次数通过 order_no 双向关联。

③ 退款(接 V0510 RefundBusiness)

规则处理
退款渠道原路退 refundType=1(微信 / 泰荣在线支付);走 V0510 RefundBusiness 既有审批/打款流
可退金额已核销次数不退、未核销按单价退(残值 = 单价 × 未核销次数);附赠/赠送次数不折现
权益扣减退款完成(pay)时扣减该订单未核销的剩余次数;若有 FROZEN 占用中的次数,先结算/释放再退
区分来源quota 流水按 source(buy/gift/card) 分池结算,退款只动 buy 池,对账可自证
入口订单详情「申请退款」/「退款详情」复用退款重做设计(order/applyorder/refundDetail

④ 数据与接口补充

练二 · 扫码体测(海迪 HOWBODY V2.4.1)· 设计稿 + 交互时序图 + 接口契约 + 开发文档