From 84c1d113e1506d59de8f34ce2c2d3ff831aab0d2 Mon Sep 17 00:00:00 2001 From: API Changelog Bot Date: Thu, 19 Mar 2026 19:02:55 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E9=85=8D=E6=88=BF=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E6=8C=87=E5=8D=97=20=E2=80=94=20=E7=BB=93?= =?UTF-8?q?=E6=9E=84=E5=8C=96=E5=88=86=E9=85=8D=E6=8C=89=E5=AE=B6=E5=BA=AD?= =?UTF-8?q?=E7=BB=B4=E5=BA=A6+=E9=85=92=E5=BA=97=E6=88=BF=E5=9E=8B?= =?UTF-8?q?=E8=81=94=E5=8A=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../2026-03/2026-03-19_room_assignment_fix.md | 484 ++++++++++++++++++ 1 file changed, 484 insertions(+) create mode 100644 changelogs/2026-03/2026-03-19_room_assignment_fix.md diff --git a/changelogs/2026-03/2026-03-19_room_assignment_fix.md b/changelogs/2026-03/2026-03-19_room_assignment_fix.md new file mode 100644 index 0000000..3be7f36 --- /dev/null +++ b/changelogs/2026-03/2026-03-19_room_assignment_fix.md @@ -0,0 +1,484 @@ +# 配房页面修正指南(紧急) + +> **日期**: 2026-03-19 +> **后端状态**: ✅ 已完成,无需后端修改 +> **问题**: 当前配房弹窗结构化分配 tab 与后端接口不匹配,缺少关键功能 + +--- + +## 当前问题 + +当前"结构化分配"tab 只有一组酒店/房型/数量/日期,**但后端是按家庭维度批量分配的**,需要支持多行。 +另外缺少"配房可选酒店列表"接口调用,以及选择酒店后联动加载房型列表。 + +--- + +## 正确的页面布局 + +### 配房信息弹窗(el-dialog) + +``` +┌──────────────────────────────────────────────────────┐ +│ 配房信息 [×] │ +├──────────────────────────────────────────────────────┤ +│ │ +│ [ 文本录入 ] [ 结构化分配 ] │ +│ │ +│ 订单号 HL202603111457027786 │ +│ 出发日期 2026-03-11 │ +│ 行程天数 6天5晚 │ +│ │ +│ ┌── 家庭 1 ──────────────────────────────── [删除] ┐│ +│ │ 选择酒店 * [ 下拉选择(调接口9) ▼] ││ +│ │ 选择房型 * [ 联动下拉(调接口10) ▼] ││ +│ │ 入住日期 * [2026-03-11] 退房日期 * [2026-03-16]││ +│ └──────────────────────────────────────────────────┘│ +│ ┌── 家庭 2 ──────────────────────────────── [删除] ┐│ +│ │ 选择酒店 * [ 下拉选择 ▼] ││ +│ │ 选择房型 * [ 联动下拉 ▼] ││ +│ │ 入住日期 * [2026-03-11] 退房日期 * [2026-03-16]││ +│ └──────────────────────────────────────────────────┘│ +│ │ +│ [+ 添加家庭] │ +│ │ +│ [ 取消 ] [ 确定 ] │ +└──────────────────────────────────────────────────────┘ +``` + +### 关键交互 + +1. **点击"配房"按钮** → 调用接口 9 获取可选酒店列表 +2. **选择酒店** → 用酒店ID调用接口 10 获取该酒店的房型列表 +3. **点击"+ 添加家庭"** → 动态添加一组分配表单 +4. **入住/退房日期** → 默认为订单出发日期~结束日期 +5. **点击"确定"** → 调用接口 2(`PUT /admin/order/{orderId}/hotel-assignment`)提交 + +--- + +## 接口清单 + +| # | 接口 | 方法 | 路径 | 说明 | +|---|------|------|------|------| +| 1 | 更新房间信息(文本) | PUT | `/api/order/admin/order/{orderId}/room-info` | 文本录入 tab 使用 | +| 2 | 分配酒店(结构化) | PUT | `/api/order/admin/order/{orderId}/hotel-assignment` | 结构化分配 tab 使用 | +| 3 | 检测房型一致性 | POST | `/api/order/admin/order/{orderId}/room-info/check-diff` | 提交后检查 | +| 9 | **配房可选酒店列表** | GET | `/api/order/admin/order/{orderId}/available-hotels` | **新增关键接口** | +| 10 | **酒店房型列表** | GET | `/api/resource/admin/hotel/{hotelId}/room-types` | **联动加载房型** | + +--- + +## 接口 9:配房可选酒店列表(当前页面缺失) + +**使用场景**:打开配房弹窗时调用,获取酒店下拉列表。产品快照中的酒店排在最前面并标注"产品快照"。 + +``` +GET /api/order/admin/order/{orderId}/available-hotels +``` + +### 响应示例 + +```json +{ + "code": 200, + "message": "成功", + "data": [ + { + "hotelId": "2028730814273536001", + "hotelName": "阿尔善国际维景度假温泉酒店", + "inSnapshot": true + }, + { + "hotelId": "2028730814273536002", + "hotelName": "呼和浩特香格里拉大酒店", + "inSnapshot": false + } + ] +} +``` + +### 响应字段 + +| 字段 | 类型 | 说明 | +|------|------|------| +| hotelId | String | 酒店ID | +| hotelName | String | 酒店名称 | +| inSnapshot | Boolean | 是否在产品快照中(true=行程已安排的酒店,应优先选择) | + +### 前端实现 + +```js +// 打开配房弹窗时调用 +const loadAvailableHotels = async (orderId) => { + const res = await request.get(`/api/order/admin/order/${orderId}/available-hotels`) + // 快照酒店已自动排在前面 + hotelOptions.value = res.data.map(h => ({ + value: h.hotelId, + label: h.inSnapshot ? `${h.hotelName}(产品快照)` : h.hotelName, + hotelId: h.hotelId, + hotelName: h.hotelName + })) +} +``` + +--- + +## 接口 10:酒店房型列表(当前页面缺失) + +**使用场景**:选择酒店后联动加载该酒店的可用房型。 + +``` +GET /api/resource/admin/hotel/{hotelId}/room-types +``` + +### 响应示例 + +```json +{ + "code": 200, + "message": "成功", + "data": [ + { + "roomTypeId": "2029001234567890001", + "name": "豪华大床房", + "maxOccupancy": 2, + "basePrice": 680.00, + "category": "DELUXE", + "bedType": "KING", + "windowType": "WITH_WINDOW", + "status": 1, + "coverUrl": "https://oss.example.com/room1.jpg" + }, + { + "roomTypeId": "2029001234567890002", + "name": "标准双人间", + "maxOccupancy": 2, + "basePrice": 480.00, + "category": "STANDARD", + "bedType": "TWIN", + "windowType": "WITH_WINDOW", + "status": 1, + "coverUrl": "https://oss.example.com/room2.jpg" + } + ] +} +``` + +### 响应字段 + +| 字段 | 类型 | 说明 | +|------|------|------| +| roomTypeId | String | 房型ID | +| name | String | 房型名称(用于展示和提交) | +| maxOccupancy | Integer | 最大入住人数 | +| basePrice | BigDecimal | 参考价(门市价) | +| category | String | 房型分类(字典:room_category) | +| bedType | String | 床型(字典:bed_type) | +| windowType | String | 窗户类型(字典:window_type) | +| status | Integer | 状态(1=启用) | +| coverUrl | String | 房型封面图 | + +### 前端实现 + +```js +// 选择酒店后联动加载房型 +const onHotelChange = async (hotelId, assignmentIndex) => { + const res = await request.get(`/api/resource/admin/hotel/${hotelId}/room-types`) + // 将房型选项绑定到对应的家庭行 + roomTypeOptions.value[assignmentIndex] = res.data.map(rt => ({ + value: rt.name, // 提交时用 name 字段 + label: `${rt.name}(最多${rt.maxOccupancy}人,¥${rt.basePrice})` + })) +} +``` + +--- + +## 接口 2:分配酒店(结构化模式) - 提交 + +**使用场景**:点击"确定"按钮提交配房数据。 + +``` +PUT /api/order/admin/order/{orderId}/hotel-assignment +``` + +### 请求体 + +```json +{ + "assignments": [ + { + "familyIndex": 1, + "hotelName": "阿尔善国际维景度假温泉酒店", + "roomType": "豪华大床房", + "checkInDate": "2026-03-11", + "checkOutDate": "2026-03-16" + }, + { + "familyIndex": 2, + "hotelName": "阿尔善国际维景度假温泉酒店", + "roomType": "标准双人间", + "checkInDate": "2026-03-11", + "checkOutDate": "2026-03-16" + } + ] +} +``` + +### 请求字段 + +| 字段 | 类型 | 必填 | 说明 | +|------|------|------|------| +| assignments | Array | ✅ | 酒店分配列表,不能为空 | +| assignments[].familyIndex | Integer | ✅ | 家庭序号(从1开始,每行递增) | +| assignments[].hotelName | String | ✅ | 酒店名称(从接口9的返回中取 hotelName) | +| assignments[].roomType | String | ✅ | 房型名称(从接口10的返回中取 name) | +| assignments[].checkInDate | String | ✅ | 入住日期(yyyy-MM-dd) | +| assignments[].checkOutDate | String | ✅ | 退房日期(yyyy-MM-dd) | + +### 校验规则 + +- `assignments` 不能为空数组 +- 每个 assignment 的所有字段都必填 +- 日期格式 `yyyy-MM-dd` +- `checkOutDate` 必须晚于 `checkInDate` + +--- + +## 接口 1:更新房间信息(文本模式) + +**使用场景**:文本录入 tab 使用,简单填写文字描述。 + +``` +PUT /api/order/admin/order/{orderId}/room-info +``` + +### 请求体 + +```json +{ + "roomInfo": "标准双人间2间,大床房1间" +} +``` + +### 业务规则 +- 仅限 **ROOM_MANAGER** 或 **SUPER_ADMIN** 角色 +- 保存成功后自动完成 `ARRANGE_ROOM` 待办,流程自动推进到"待配车" + +--- + +## 接口 3:检测房型一致性 + +**使用场景**:配房提交后自动调用,检测当前配置与产品快照是否一致。 + +``` +POST /api/order/admin/order/{orderId}/room-info/check-diff +``` + +### 响应 + +- `data` 为 `null` → 一致,无需提示 +- `data` 为字符串 → 不一致描述,用 `ElMessageBox.confirm` 弹窗提示 + +--- + +## 完整代码示例 + +```vue + + + +``` + +--- + +## 关联字典 + +| 字典类型 | 说明 | 用途 | +|---------|------|------| +| room_category | 房型分类:STANDARD-标准间, DELUXE-豪华间, SUITE-套房, FAMILY-家庭房 | 房型列表展示 | +| bed_type | 床型:KING-大床, TWIN-双床, TATAMI-榻榻米 | 房型列表展示 | +| window_type | 窗户:WITH_WINDOW-有窗, NO_WINDOW-无窗, SKYLIGHT-天窗 | 房型列表展示 | + +--- + +## 删掉的字段 + +当前弹窗中的"房间数量"字段应该**删除**——后端按家庭分配,每个家庭一间房,不需要单独设置数量。如果一个家庭需要2间房,就添加2行同样的家庭。 + +--- + +🤖 Generated with [Claude Code](https://claude.com/claude-code)