docs(admin-ui): 配房差价弹窗 upgradePrice 未传给后端前端修复指引 (后端零改动)
这个提交包含在:
父节点
487f0a9c1a
当前提交
2429097e34
@ -0,0 +1,103 @@
|
|||||||
|
# 配房差价弹窗用户输入的差价未传给后端(前端 BUG,后端零改动)
|
||||||
|
|
||||||
|
**日期**: 2026-04-24
|
||||||
|
**类型**: 前端缺字段 BUG 指引
|
||||||
|
**受众**: hl-ui 管理后台
|
||||||
|
**对应界面**: 订单详情 → 行程安排 → 编辑房间 → 弹出「配房差价确认」
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 现场
|
||||||
|
|
||||||
|
订单 `HL20260423175303-5448`:
|
||||||
|
1. 第一次配房(4 天都是便宜房型),系统算 totalDiff=-280 → 生成「房间优惠 ¥280」
|
||||||
|
2. 用户把第 3 天改为大床房,弹窗「配房差价确认」显示 **差价 +200 / 合计 +200 元**
|
||||||
|
3. 点「确认提交」后,财务页仍显示「房间优惠 ¥280」,**没有 +200 升级房型**
|
||||||
|
|
||||||
|
## 后端自检结论:无问题
|
||||||
|
|
||||||
|
### 实测 DB 当前 hotel_assignment 数据
|
||||||
|
|
||||||
|
```
|
||||||
|
day=1 普通标间 upgradePrice=null
|
||||||
|
day=2 俄式标准房 upgradePrice=null
|
||||||
|
day=3 大床房 upgradePrice=null ← 用户在弹窗输入 +200
|
||||||
|
day=4 俄式标准房 upgradePrice=null
|
||||||
|
```
|
||||||
|
|
||||||
|
**4 条 assignment 的 `upgradePrice` 全部为 null** — 用户在弹窗里输入的 +200 **根本没传到后端**。
|
||||||
|
|
||||||
|
### 实测服务端日志(每次提交都命中)
|
||||||
|
|
||||||
|
```
|
||||||
|
配房升级差价记录已创建: orderId=2047252402389598209, count=1, totalDiff=-280.00, isCustomizer=true
|
||||||
|
系统写入分配副作用优惠: amount=280.00
|
||||||
|
```
|
||||||
|
|
||||||
|
后端 `calcDayUpgrade` 逻辑:`assignment.upgradePrice != null ? upgradePrice : systemDiff`。上游没传,必然走 systemDiff,其它 3 天按产品默认对比算出 -480 左右,第 3 天大床房 +200,合计 -280。
|
||||||
|
|
||||||
|
## 契约:后端已经预留字段(OrderAssignmentService 早就支持)
|
||||||
|
|
||||||
|
`HotelAssignmentRequest.HotelAssignmentItem` 字段(`hl-order-service-v2/src/main/java/com/hulalv/order/assignment/dto/HotelAssignmentRequest.java`):
|
||||||
|
|
||||||
|
```java
|
||||||
|
@ApiModelProperty(value = "手动覆盖升级差价(null=使用系统计算)")
|
||||||
|
private BigDecimal upgradePrice;
|
||||||
|
```
|
||||||
|
|
||||||
|
这个字段在 `PUT /admin/order/{orderId}/hotel-assignment`(保存配房)**和** `POST /admin/order/{orderId}/hotel-assignment/preview`(预览)**两个接口都接收**。
|
||||||
|
|
||||||
|
## 前端修复方案
|
||||||
|
|
||||||
|
### 方案(必做)
|
||||||
|
|
||||||
|
「配房差价确认」弹窗里,每一行**用户可编辑的差价输入框**,应该:
|
||||||
|
|
||||||
|
1. **保存时**:把用户输入值赋给对应 `assignment.upgradePrice`,通过 `PUT /hotel-assignment` 传给后端
|
||||||
|
2. **预览时**:同样赋值后调 `POST /hotel-assignment/preview`,保证 preview 和 execute 看到的是同一份 payload
|
||||||
|
|
||||||
|
伪代码:
|
||||||
|
|
||||||
|
```js
|
||||||
|
function submitHotelAssignment(dayEditedItems) {
|
||||||
|
const payload = {
|
||||||
|
assignments: dayEditedItems.map(d => ({
|
||||||
|
familyIndex: d.familyIndex,
|
||||||
|
hotelId: d.hotelId,
|
||||||
|
hotelName: d.hotelName,
|
||||||
|
roomTypeId: d.roomTypeId,
|
||||||
|
roomType: d.roomType,
|
||||||
|
dayNumber: d.dayNumber,
|
||||||
|
remark: d.remark,
|
||||||
|
upgradePrice: d.dayDiffEdited, // ← 本次要补的字段,null 也要显式传
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
await http.put(`/admin/order/${orderId}/hotel-assignment`, payload);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 关键点
|
||||||
|
|
||||||
|
- **全量替换语义**:`PUT /hotel-assignment` 是全量替换(内部 `deleteByOrderId + insertBatch`)。前端必须**全量**把所有天的 assignment 都传过来,不能只传改动的那一天。
|
||||||
|
- **未编辑的天**:`upgradePrice=null`(或省略字段,Jackson 会当 null),后端按系统价计算该天差价。
|
||||||
|
- **用户编辑过的天**:把用户输入的数字放到 `upgradePrice`。哪怕只编辑 1 天,其它 3 天也要按原值回填并带上 upgradePrice 处理策略(保持 null 让后端算,或显式传 0 意味"本天按产品默认不算差价")。
|
||||||
|
|
||||||
|
## 验证步骤
|
||||||
|
|
||||||
|
1. 用户编辑第 3 天差价 +200 → 提交
|
||||||
|
2. 检查请求 body,`assignments[day=3].upgradePrice == 200`
|
||||||
|
3. 后端日志应出现 `totalDiff=+200`(或其它符合预期的合计)
|
||||||
|
4. 财务页优惠记录消失,出现「升级房型 ¥200」
|
||||||
|
|
||||||
|
## 为什么不建 Gitea 工单
|
||||||
|
|
||||||
|
后端契约早就就绪(字段 `upgradePrice` 在 VO 里,calcDayUpgrade 里的 override 逻辑也在),纯前端保存时漏传。按约定不占 Gitea 待办通道,直接给前端指引。
|
||||||
|
|
||||||
|
## 同类预防
|
||||||
|
|
||||||
|
「前后端字段对齐问题」在本仓库历次踩坑里很常见:
|
||||||
|
- PR #691 GET 分页字段别名双通道
|
||||||
|
- PR #819 MyBatis-Plus NOT_NULL 策略 setXxx(null) 写不进 DB
|
||||||
|
- 本次 `upgradePrice` 契约早就在,但前端漏用
|
||||||
|
|
||||||
|
建议前端**新字段发布到后端 changelog 后,第一时间在关键提交路径加上该字段**,不要等到用户报错才发现。
|
||||||
正在加载...
x
在新工单中引用
屏蔽一个用户