5.6 KiB
小程序填写返程信息: 校验前置 mp 端 + 错误信息友好化(前端有 BUG 待排查)
服务: hl-mp-service (端口 8085) PR: #1830 (已合并 dev, 待部署 prod) Issue: #1828 (P0-紧急, 正式环境) 日期: 2026-05-07 影响范围: 小程序「填写返程信息」页(自驾/飞机/火车 × 一起返程/分批返程 全部场景) @ 前端: mmg
⚠️ 关键信息
正式环境用户在小程序「填写返程信息」点「确认提交」后弹 toast:
batchReplace.reqs[0].travelerIds: 出行人列表不能为空
用户 UI 上已经勾选了「蒋桂龙」乘坐人员,但后端收到的 travelerIds 是空 — 这是一个双重 BUG:
- 前端 BUG(mmg 必修):hl-mini 小程序
_buildTogetherPlan把勾选的 traveler 的id装进请求 body 时,因 ID 字段名漂移导致最终装入的是占位符order-N被过滤,致 travelerIds 空数组 - 后端友好化(本 PR 修):
MpArrivalController.batchReplace用@Valid List<...>不递归到元素,校验穿透到 internal controller 才被@Validated触发,错误信息暴露内部参数名batchReplace.reqs[0]
一、后端变更(本 PR 已合 dev)
1.1 接口契约
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|---|---|---|---|---|
| 1 | 全量替换返程批次 | POST | /mp/order/{orderId}/arrival/batch |
错误信息变更(不破坏契约) | body 形状不变;mp 端前置校验,错误信息中文友好 |
1.2 新错误码
| Code | Message | 触发条件 |
|---|---|---|
620001 |
请添加至少一批返程信息 | body 是空 List 或 null |
620002 |
第 N 批返程信息:请选择至少一位乘坐人员 | body[N-1].travelerIds 为 null 或空 List |
1.3 旧错误信息(部署前)vs 新错误信息(部署后)
| 场景 | 部署前 | 部署后 |
|---|---|---|
| body 空 | batchReplace.reqs: 不能为空 |
请添加至少一批返程信息 |
| 首批空 travelerIds | batchReplace.reqs[0].travelerIds: 出行人列表不能为空 |
第 1 批返程信息:请选择至少一位乘坐人员 |
| 第二批空 travelerIds | batchReplace.reqs[1].travelerIds: 出行人列表不能为空 |
第 2 批返程信息:请选择至少一位乘坐人员 |
1.4 服务端日志增强
mp controller 抛出校验失败前会 log.warn:
mp/arrival/batch 校验失败 orderId={} userId={} bodySize={} 元素摘要={}
(元素摘要含 direction / transportType / travelerIds.size 协助排查前端实际发出 body)
部署后 mmg 可以让运维拉 hl-mp-service WARN 日志看真实 body 形状(每元素含 direction/transportType/travelerIds 是否为空)。
二、前端待处理(mmg 必修)
2.1 嫌疑代码位置
hl-mini/packages/trip/arrival/arrival.js:
行 88(_loadPassengers):
id: String(t.orderTravelerId || t.travelerId || t.id || `order-${idx}`)
行 681-686(_buildTogetherPlan):
const selected = this.data.passengers.filter(p => p.checked && !p._isLocal);
const travelerIds = selected
.map(p => String(p.id || ''))
.filter(id => id && !id.startsWith('order-') && !id.startsWith('local-'));
2.2 排查步骤(建议)
- 在
_buildTogetherPlan进入时打日志:console.log('[arrival] passengers=', this.data.passengers, 'selected=', selected, 'travelerIds=', travelerIds); - 复现「蒋桂龙」场景(正式订单),观察 passenger 对象的
id字段真实值:- 如果是
order-0这种占位符 →_loadPassengers三个候选字段名(orderTravelerId / travelerId / id)都没拿到值,对照后端getOrderDetail接口返回的travelers[]元素真实字段名与三候选是否对齐 - 如果是雪花 ID →
_buildTogetherPlan的 filter 逻辑是否有别的过滤条件把它排掉
- 如果是
- 对照后端 VO(
hl-mp-service的MpOrderTravelerVO)确认实际字段名 — 必要时让我贴出来
2.3 separate 模式(多批次返程)
arrival.js L711 _buildSeparatePlans 取 b.travelerIds || [],L717 已有"第 N 批缺少出行人"前置 toast 拦截 — 理论上不会发到后端。但若有路径绕过此 toast,本次后端校验是兜底。
三、数据库行为
只读校验,不写库。校验失败立即抛 BusinessException 不进入 Feign 调 order-v2。
四、边界行为
- body=null → 620001 "请添加至少一批返程信息"
- body=[] → 620001
- body=[{travelerIds:null}] → 620002 "第 1 批..."
- body=[{travelerIds:[]}] → 620002
- body=[{travelerIds:[10001]}, {travelerIds:[]}] → 620002 "第 2 批..."
- body=[{travelerIds:[10001]}, {travelerIds:[10002]}] → 走 Feign 到 internal,正常处理
五、不影响范围
- 仅
POST /mp/order/{orderId}/arrival/batch一个接口 - mp create / update / delete / list 接口 0 改动
- internal controller
@Validated兜底仍在,admin / 其他客户端调 internal 仍受校验 - API 契约(body 形状)不变,前端无需改请求结构
六、测试
- 单测:
MpArrivalControllerTest9/9 全绿 (5 原有 + 4 新增反例:空 body / null body / 首批空 travelerIds / 第二批空 travelerIds) - 测试服 round-trip: 待 dev 部署测试服后由 QA 验证
- prod 部署: 由运维管理员排期 (本 PR 不动 prod)
七、相关文档
- 关联 Issue: wx/HL#1828
- 关联 PR: wx/HL#1830