酒店模块小程序化改造汇总
文档定位:本轮改造的进展汇总 + 理解导读,回答「这一轮到底改了什么、为什么改、解决了哪些问题、还有什么待办」。
本文档不是实现权威。具体实现细节请查同目录四份权威文档(用指针引用,不复制正文):
- 代码地图 / 实现进度 →
酒店模块迁移跟踪.md
- 需求缺口 / 补齐排期(第 0~6 批,排期唯一权威)→
酒店模块需求缺口清单.md
- 二维码与开放接口实现 →
酒店二维码模块开发文档.md
- 支付实现(协议 / 回调 / 幂等 / Mock 红线代码)→
酒店订单支付系统开发文档.md
核实基线:本文所有文件清单、改动性质均以工作区未提交改动的 git diff 逐一核实为准,非凭印象。
0. 元信息
| 项 |
内容 |
| 汇总时间 |
2026-09-07 |
| 覆盖范围 |
工作区当前全部未提交改动(26 个文件,+1366 / -702)+ 2 个新增变更目录 |
| 关联变更目录 |
code-copilot/changes/hotel-pay-mock-hardening/、code-copilot/changes/hotel-alipay-secret-externalize/ |
| 改造主线 |
酒店点餐系统由「H5 开发态」走向「支付宝小程序上线态」 |
| 硬约束 |
全程不破坏现有 H5 开发测试(详见第 2.2 节) |
1. 一句话总纲
本轮所有改动,本质上只服务一个目标:让酒店点餐系统能从「H5 开发态」平滑走向「支付宝小程序上线态」,且全程不破坏现在的 H5 开发测试。
改动之所以看起来横跨很多层面,是因为它同时触及了后端 / 前端 / 构建 / 配置 / 文档五层,但内在逻辑是统一的:
一条主线(小程序载体适配)
+ 一条安全支线(Mock 支付生产加固)
+ 两个核实过程中挖出的待决策问题(P0 启动崩溃、密钥明文入库)
+ 文档同步
2. 改造背景与约束
2.1 业务方向
- 首发只做支付宝小程序;微信小程序因商户号未申请,已决策暂缓上架,但后端三端共用,WECHAT 渠道仍须显式阻断。
- 非支付宝 / 微信的扫码器一律不可访问(两层拦截:入口层 + 接口层)。
- 资质问题后期补充,本轮只判定并落地技术可行性。
2.2 硬约束:不影响 H5 开发测试
所有改动只能归入以下三类手法,禁止直接替换现有实现:
| 手法 |
说明 |
本轮用例 |
| 条件编译 |
#ifdef H5 保留原实现,#ifndef H5 走小程序分支 |
前端页面、TabBar、首页入口 |
| 配置开关 |
生产 application.yml 默认严格,开发 application-dev.yml 覆盖宽松 |
hotel.qr.path、hotel.pay.mock-enabled |
| 纯增量 |
新增类 / 方法 / 重载 / 分支,旧签名委托保留 |
QrCodeUtils 重载、HotelPayConfig、resolveScanParams |
2.3 载体差异(为什么必须适配)
| 能力 |
H5 载体 |
小程序载体 |
| 扫码落地 |
hash 路由 /#/pages/hotel/scan-bind |
专属前缀 /r/(平台规则按 path 前缀匹配拉起) |
| 员工扫码绑定 |
支持(html5-qrcode + 相机) |
不支持(无 navigator.mediaDevices) |
| 图标渲染 |
CSS mask 引用本地 SVG 可换色 |
WXSS/ACSS 不支持 mask,需 <image> |
| 扫码入参 |
页面直接拿 c/t/s |
平台把整条 URL 塞进 q(微信)/qrCode(支付宝) |
3. 主线:H5 → 支付宝小程序「载体适配」
3.1 后端二维码:扫码落地路径可配置
- 解决的问题:扫码落地路径原来硬编码成 H5 的 hash 路由常量,但小程序拉起规则要求专属前缀
/r/,两者冲突。
- 手法:抽成配置项
hotel.qr.path;QrCodeUtils.buildQrCodeUrl 新增带 basePath 的重载,旧签名委托保留;空值回退默认常量。
- 关键设计:二维码 URL 不落库(
hotel_qr_code 只存 short_code + sign,URL 运行时拼接),因此改格式零数据迁移成本。
- 对 H5 影响:零。dev 环境
hotel.qr.path 锁定旧值 /#/pages/hotel/scan-bind,既有二维码与扫码流程完全不变。
| 文件 |
改动 |
QrCodeUtils.java |
新增带 basePath 重载(+35),旧签名委托 |
HotelQrCodeServiceImpl.java |
注入 qrBasePath,2 处调用改用重载(+14) |
HotelQrConstants.java |
QR_BASE_PATH 补注释说明其为回退值(+8,值不变) |
3.2 前端:双载体条件编译
- 解决的问题:小程序不支持 H5 的相机扫码页、CSS mask SVG 换色、员工扫码绑定页。
- 手法:用
#ifdef H5 / #ifndef H5 把仅 H5 的能力裁掉,H5 分支原样保留。
- 对 H5 影响:零。H5 构建走原分支,行为不变;小程序构建裁掉不适用部分。
| 文件 |
改动 |
pages.json |
scan-bind / qr-scanner 两页包进 #ifdef H5(+7),小程序不注册 |
index/index.vue |
扫码绑定入口、权限常量、路由白名单、快捷跳转全部 #ifdef H5(+25) |
HotelTabBar.vue |
图标渲染 #ifndef H5 改用 <image> + opacity 区分激活态(+17) |
3.3 前端:小程序扫码入参解析
- 解决的问题:小程序扫「普通链接二维码」时,平台不拆 query,而是把整条 URL 塞进
q(微信,已 encodeURIComponent)/qrCode(支付宝) 字段,原解析逻辑取不到 c/s。
- 手法:
room-confirm.vue 新增 resolveScanParams(),优先级「显式 c/s > 微信 q > 支付宝 qrCode」,用与 scan-bind.vue 一致的正则口径解析。
- 对 H5 影响:零。H5 仍走「显式 c/s 透传」分支,
resolveScanParams 对 H5 是恒等返回。
| 文件 |
改动 |
room-confirm.vue |
新增 resolveScanParams(),onMounted 改用它解析(+51) |
3.4 构建:支付宝小程序可打包
- 解决的问题:支付宝小程序无法打包——
dev/build:mp-alipay 命令缺 --mode,manifest.json 缺 appid 占位。
- 手法:补构建参数 + appid 空占位(待企业资质下来再填)+ 新增专属环境变量文件。
- 对 H5 影响:零。仅新增 mp-alipay 相关脚本与配置,H5 构建链不受影响。
| 文件 |
改动 |
package.json |
dev:mp-alipay / build:mp-alipay 补 --mode mp-alipay(+4) |
manifest.json |
mp-alipay.appid 空占位 + 说明注释(+4) |
.env.mp-alipay |
新增,支付宝小程序构建环境变量 |
4. 安全支线:MOCK 模拟支付「生产加固」
- 背景:AGENTS.md 5.9 资金红线。开发调试靠 MOCK 模拟支付(点一下就「支付成功」),若该通道在生产也能走,等于任何人不用真付钱就能把订单置为已支付。
- 原隐患:
/hotel/open/pay/mockSuccess 落在 Sa-Token 白名单 /hotel/open/** 内完全免登录,且 createPay 的 paySource 默认值就是 "MOCK",加上 resolvePayChannel 两处静默降级——构造请求即可免付款。
| 加固点 |
手法 |
| 单一收口 |
抽 mockOrReject():mock-enabled=true 返回 MOCK,否则抛 BusinessException |
| 开关控制 |
新增 HotelPayConfig 读 hotel.pay.mock-enabled(生产 false 严格、dev true 宽松) |
| 接口层拦截 |
mockSuccess 首行拦截;createPay 的 paySource 去掉 defaultValue |
| 渠道显式判定 |
WECHAT / 未知渠道显式抛异常,不再降级为 MOCK |
| 退款加固 |
refundOrder 改显式判 "MOCK".equals(payChannel),非 ALIPAY 非 MOCK 抛异常要求人工介入 |
| 前端兜底禁止 |
pay.vue 的 else MOCK 分支「拆分」而非「删除」:else if (payChannel==='MOCK') 保留 dev 调试逻辑,新增 else 显式 showModal 报错,禁止兜底调 mockSuccess |
| 日志脱敏 |
AlipayAuthController.maskPhone、AlipayAuthServiceImpl 只记 responseLength |
- 对 H5 影响:零。dev 环境
mock-enabled: true,现有模拟支付调试行为完全不变。
| 文件 |
改动 |
HotelPayConfig.java |
新增,读 hotel.pay.mock-enabled |
HotelPayServiceImpl.java |
mockOrReject 收口 + resolvePayChannel + refundOrder 渠道判定(+80) |
HotelPayController.java |
paySource 去默认值 + mockSuccess 首行拦截(+19) |
AlipayAuthController.java |
手机号脱敏 maskPhone(+16) |
AlipayAuthServiceImpl.java |
日志只记 responseLength(+3) |
pay.vue |
else MOCK 分支拆分(+20) |
5. 配置层设计(「不影响 H5」的关键)
同一段 hotel: 配置,在生产和开发两份文件里故意不同:
| 配置项 |
生产 application.yml |
开发 application-dev.yml |
qr.path |
${FORGE_HOTEL_QR_PATH:/r/}(小程序前缀) |
/#/pages/hotel/scan-bind(H5 旧值不变) |
qr.base-url |
${FORGE_HOTEL_QR_BASE_URL:}(空串,靠环境变量注入) |
http://192.168.10.4:3001(局域网 IP 不变) |
pay.mock-enabled |
${FORGE_HOTEL_PAY_MOCK_ENABLED:false}(严格禁止) |
true(模拟支付调试不变) |
- 结论:生产收紧、开发保持原样。现在 H5 怎么测,改完之后还怎么测,一模一样。
- 涉及 6 份 yml:admin-server 与 app-server 各 3 份(
application.yml / application-dev.yml / application-dev.example.yml)。
- 环境变量名易错点:是
FORGE_HOTEL_PAY_MOCK_ENABLED,不是 FORGE_HOTEL_PAY_MOCK(写错不报错,只静默退回 false)。
6. 核实过程中的两个观察(已更正)
6.1 【已撤销】生产 profile 启动崩溃 — 判断错误,当前不会崩
- 原判断:
AlipayConfig 5 个 @Value 无默认值 + 生产 application.yml 无 hotel.alipay 块 → 生产启动崩溃(P0)。
- 更正:
application.yml L42-43 spring.profiles.active: dev,且 docker-compose.yml / .env.example 无任何 profile 覆盖,项目也没有 application-prod.yml。因此当前启动(包括 docker 部署)都会加载 application-dev.yml,hotel.alipay.* 全部有值,不会崩。
- 我错在哪:把
application.yml 当成「生产专用配置」,忽略了它 L43 默认激活 dev profile,application-dev.yml 会被合并加载。
- 连带更正:我上一批往
application.yml 加 hotel: 块时写的注释「缺此项会导致生产 profile 启动失败」(L227)也是基于同样的错误前提。实际效果:因为 dev.yml 覆盖,application.yml 里的 hotel 块当前不生效(无害,但也无「修复崩溃」的作用)。
- 真正的配置架构观察:本项目没有独立的生产 profile 配置,所有环境(含 docker 部署)都用 dev profile,
application-dev.yml 承载了全部实际连接配置(数据库、Redis、支付宝沙箱)。若未来要建立独立生产 profile,需要同步建立 application-prod.yml 并提供所有必要配置。
6.2 【已决策接受】支付宝沙箱密钥明文入库
- 现象:
application-dev.yml 里的支付宝私钥 / 公钥是明文,且已随 commit 65508d9 推送到远端 origin/master。
- 用户决策:git 是内网私有仓库(192.168.8.4),不在外网;密钥是沙箱密钥;后期如有必要,会直接不提交生产的密钥。
- 处置:本变更关闭(
hotel-alipay-secret-externalize 不再推进)。后续生产密钥不入库由用户把控。
- 注意:本汇总文档不含任何真实密钥字符,避免二次扩散。
7. 文档同步与变更目录
| 动作 |
对象 |
说明 |
| 删除 |
forge-hotel/酒店AGENTS.md(-420)、forge-h5-ui/AGENTS.md(-19) |
废弃版本,用户确认删除 |
| 移动 |
酒店订单支付系统开发文档.md |
由仓库根 git mv 移入 forge-hotel/ 目录 |
| 同步 |
迁移跟踪 / 二维码开发文档 / 需求缺口清单 / 支付系统文档 |
回填本轮改动、行号纠错、新发现登记 |
| 新建变更 |
code-copilot/changes/hotel-pay-mock-hardening/ |
spec.md + tasks.md,HARD-GATE 留空待签 |
| 新建变更 |
code-copilot/changes/hotel-alipay-secret-externalize/ |
spec.md,status: propose,只写方案 |
8. 全量文件改动清单
后端代码(8)
| 文件 |
主题 |
性质 |
QrCodeUtils.java |
二维码路径可配置 |
增量重载 |
HotelQrCodeServiceImpl.java |
二维码路径可配置 |
注入 + 调用改重载 |
HotelQrConstants.java |
二维码路径可配置 |
注释补充(值不变) |
HotelPayConfig.java |
Mock 支付加固 |
新增类 |
HotelPayServiceImpl.java |
Mock 支付加固 |
收口 + 渠道判定 |
HotelPayController.java |
Mock 支付加固 |
接口层拦截 |
AlipayAuthController.java |
日志脱敏 |
手机号掩码 |
AlipayAuthServiceImpl.java |
日志脱敏 |
只记长度 |
配置(6)
| 文件 |
主题 |
性质 |
admin/app application.yml |
主配置 hotel 块 |
新增(qr + pay),当前被 dev.yml 覆盖不生效 |
admin/app application-dev.yml |
开发宽松值 |
新增 qr.path 旧值 + mock-enabled=true |
admin/app application-dev.example.yml |
模板同步 |
补齐 path + pay 块 |
前端 H5(8)
| 文件 |
主题 |
性质 |
package.json |
小程序构建 |
补 --mode mp-alipay |
manifest.json |
小程序构建 |
appid 空占位 |
.env.mp-alipay |
小程序构建 |
新增 |
pages.json |
载体裁剪 |
#ifdef H5 |
index/index.vue |
载体裁剪 |
#ifdef H5 入口 |
HotelTabBar.vue |
图标适配 |
#ifndef H5 用 image |
room-confirm.vue |
扫码入参 |
新增 resolveScanParams |
pay.vue |
Mock 加固 |
else 分支拆分 |
文档(5 + 2 目录)
见第 7 节。
9. 对 H5 开发测试的影响评估
总结论:零影响。 逐项核对:
| 你现在的 H5 行为 |
改造后 |
保证手法 |
| 扫二维码进员工绑定页 |
不变 |
dev qr.path 锁旧值 |
| 局域网 IP + 端口访问 |
不变 |
dev qr.base-url 保持 http://192.168.10.4:3001 |
| 点「模拟支付」调试下单 |
不变 |
dev mock-enabled: true |
| 首页扫码绑定入口 |
不变 |
#ifdef H5 保留 |
| TabBar 图标换色 |
不变 |
#ifdef H5 走 mask 原实现 |
| 员工相机扫码 |
不变 |
两页仅 H5 注册 |
10. 待办事项(需要用户决策)
- 签 HARD-GATE:读
hotel-pay-mock-hardening/spec.md 第 8.1 节(3 个资金审查点)+ 第 9 节 Q1~Q3,手填第 13 节确认时间 / 确认人(AI 不代签)。
- 生产部署方式确认:当前项目所有环境(含 docker)都用 dev profile,
application-dev.yml 的 mock-enabled: true 会覆盖 application.yml 的 false。若直接拿 dev 配置上生产,mock 支付是开着的。请确认上生产前是否会建独立 prod profile / 改 dev 值 / 设环境变量覆盖。
⚠ hotel-alipay-secret-externalize 变更已关闭(用户已决策接受,后期生产密钥不提交)。
附:本文档维护说明
- 本文档是小程序化改造这一持续任务的阶段性进展汇总,后续批次(第 3~6 批:MP 身份体系、支付宝
trade.create、图片绝对路径、上线资质切换)落地后可继续更新。
- 具体实现以四份权威文档为准;本文只负责「整体视图 + 问题-解决对照 + 待办跟踪」。
- 排期与缺口的唯一权威是
酒店模块需求缺口清单.md 第 0~6 批,本文不重复维护排期。