# 【修改·管理后台】配房/选酒店流程评审 11 点收口（候选房型富化 + 段×候选 + 池内快照 + 特殊诉求字典）

> 涉及 PR：#4126 / #4127 / #4135 / #4136 / #4148 / #4149（hl-order-service-v3，区县另涉 hl-resource-service）
> 影响页面：**订单详情 → 调整订单 → 酒店安排**（配房需求表单）+ 其中的**「选择酒店」弹窗**
> 状态：已合并 dev-v3、已部署测试服双实例、候选接口已网关 API 实测通过

---

## ⚠️ 关键说明（先读）

1. 这是定制师「提交配房需求」表单 +「选择酒店」弹窗的一轮产品评审收口，共 11 个点，前后端都要改。
2. 两处契约变化，前端必改：
   - **配房需求提交体** `HotelRequirementReqVO.days` 结构升级为「**段 × 候选**」（见 §三-2）。
   - **选酒店候选接口** `GET /v3/admin/hotel-candidates` 出参**富化**（真实房型/城市/区县/池内，见 §三-1）。
3. **房型下拉不再用通用字典**，改由「所选酒店的真实房型」驱动；**不选酒店不能选房型**。
4. 金额字段（协议价/标价/预算）均为 **String**（后端 @JsonSerialize），前端按字符串收。

---

## 一、配房需求表单改动

### 点1 删「当晚备注」
- 每晚的「当晚备注（当晚整体安排说明）」**整条去掉**（输入框删除）。
- 后端 `DayHotelReq.remark` 字段已移除；行程 Tab 的 `requirementDays[].remark` 也随之废弃（新单恒空，前端别再展示当晚备注）。
- **保留**「该酒店备注」（迁为每个候选酒店的备注，见点8 `CandidateHotel.remark`）。

### 点2 删「城市/区域」输入（纯前端）
- 每晚那个「城市/区域（如 拉萨市区）」输入框**删掉**——它本就没进后端，且与「选择酒店」弹窗自带的搜索框重复。

### 点3 特殊诉求改字典（多选 + 允许自定义）
- 「特殊诉求」从自由文本标签改为**绑定字典** `house_special_demand`，前端做**多选**，**仍允许回车加自定义**。
- 字典加载：`GET /admin/dict/data/house_special_demand` → `[{dictValue, dictLabel}]`（当前值：安静楼层/高楼层/景观房/无烟房/含早餐/含双早/可加床/可拆分双床/相邻房间/远离电梯，运营可在字典管理增删）。
- 提交字段不变，仍是 `specialTags: List<String>`（存字典 value，自定义则存原文）。

### 点8 酒店支持「段 × 候选」（提交体结构升级，重点）
两个**独立**维度（产品确认都要）：
- **分住**：同一晚住两家（房数相加）—— 一晚有多个 **段(segment)**。
- **候选**：定制师对某段提多家心仪酒店，**房控后台择一**回配 —— 一段有多个 **候选(candidate)**。

UI：
- 每晚可「+ 加一段不同酒店（同一晚分住）」= 加 segment（每段独立填 房数/房型/预算/段备注）。
- 每段的「酒店」框支持**多选**候选酒店（房控择一）；每个候选可填该酒店备注。
- 候选酒店会自动进候选接口的「定制师点名」高亮（`isConsultantRecommended`）。

---

## 二、选择酒店弹窗 + 房型

### 点4 协议价按真实房型 / 点6 可用房按真实房型 / 点7 房型按真实酒店
- 候选接口现返回每家酒店的**真实房型列表** `roomTypes[]`（来自 resource 价格日历/库存）。
- 前端：
  - **房型下拉**改由所选酒店的 `roomTypes[]` 驱动（`name`/`bedType`/`maxOccupancy`），**不选酒店则房型不可选**；不再用通用 `room_category` 字典。
  - **协议价**显示所选房型的 `roomTypes[].protocolPrice`（不是酒店级起步价 `protoPrice`）。
  - **可用房**显示所选房型的 `roomTypes[].available`（+ `inventoryStatus` AVAILABLE/FULL/CLOSED）。
- 注：测试酒店需 resource 侧配了价格日历+库存才有 `roomTypes` 数据（无则该酒店 roomTypes 为空/价 null）。

### 点5 城市 / 点10 区县
- 候选项新增 `city`（城市，如 呼伦贝尔市）+ `district`（区/县，如 满洲里市）。
- 选酒店列表/候选展示加「城市」「区/县」两列。

### 点9+11 池内徽章：按行程天数 + 从订单产品快照取
- 「池内」徽章 `isPoolMatch` 语义修正为：**该酒店在「订单产品快照」里当天当档（order.tierSeq）的产品酒店池中**。
  - 按**行程天数**：第1天只标第1天产品行程的酒店，第2天标第2天的。
  - 从**订单产品快照冻结值**取（非 live 产品配置）——产品下单后被改不影响已下单订单的池内判定。
- 前端无需改调用方式，照常按 `dayNumber` 查候选，`isPoolMatch`/`poolMatchBadge` 直接用。

---

## 三、接口契约

### 1. 候选接口出参（新增字段）
`GET /v3/admin/hotel-candidates?orderId=&dayNumber=&roomCategory=&roomCount=&keyword=&limit=`
出参 `data.candidates[]`（`HotelCandidateRespVO.Candidate`）**新增**：

| 字段 | 类型 | 说明 |
|------|------|------|
| `city` | String | 酒店所在城市（如 呼伦贝尔市） |
| `district` | String | 酒店所在区/县（如 满洲里市） |
| `roomTypes` | List | 该酒店当日真实房型列表（见下） |

`roomTypes[]`（`RoomTypeOption`）：

| 字段 | 类型 | 说明 |
|------|------|------|
| `roomTypeId` | String | 房型 ID |
| `name` | String | 房型名称（如 普通标间） |
| `bedType` | String | 床型（如 TWIN_BED） |
| `maxOccupancy` | Integer | 最大入住人数 |
| `available` | Integer | 今日可用房数 |
| `stock` | Integer | 总库存 |
| `protocolPrice` | String | 协议价（金额字符串） |
| `basePrice` | String | 标价 |
| `inventoryStatus` | String | AVAILABLE / FULL / CLOSED |

`isPoolMatch`（既有字段，语义改为按天+快照）、`protoPrice`/`matchedRoomType*`（既有，向后兼容保留）不变。

### 2. 配房需求提交体（结构升级）
`HotelRequirementReqVO`（提交配房需求 / 调整订单 hotelRequirement.days 同构）：
```
{
  "days": [
    {
      "dayNumber": 1,
      "segments": [                      // ← 原 hotels[] 改为 segments[]（分住段）
        {
          "roomCount": 2,
          "roomCategory": "TWIN",
          "budget": "600.00",            // 可空(后端反查协议价覆盖)
          "remark": "段备注",
          "candidates": [                // ← 候选酒店列表(房控择一)
            { "hotelId": 80001, "hotelName": "拉萨西藏宾馆", "remark": "靠湖一侧" },
            { "hotelId": 80002, "hotelName": "山景酒店", "remark": "含双早" }
          ]
        }
      ]
    }
  ],
  "specialTags": ["安静楼层", "含早餐"],   // 字典 house_special_demand 的 value(允许自定义)
  "remark": "整单备注"
}
```
- **去掉**：`days[].remark`（当晚备注）、`days[].hotels[].source`（死字段）。
- 后端兼容旧 `hotels[]` 结构读取（存量订单不报错），但**新提交请用 `segments[].candidates[]`**。

### 3. 特殊诉求字典
`GET /admin/dict/data/house_special_demand` → `data: [{dictValue, dictLabel, ...}]`。

---

## 四、curl 实测（候选接口，2026-06-20 测试服）
```
GET /v3/admin/hotel-candidates?orderId=2068235380959682562&dayNumber=1&limit=3
→ 200
data.candidates[0]:
  hotelName=呼伦贝尔香格里拉大酒店  city=呼伦贝尔市  district=满洲里市  isPoolMatch=true
  roomTypes=[{name:普通标间, bedType:TWIN_BED, available:20, protocolPrice:"280.00", inventoryStatus:AVAILABLE}, ...]
data.candidates[1]: 海拉尔嘉世豪酒店  district=海拉尔区  isPoolMatch=false
```

---

如对契约/字段有疑问随时找后端（王骁）。
