hl-api-changelog/changelogs-v2/2026-07/25_5237_酒店候选补齐房型结算价-修改接口-管理后台.md
Mimingguang bd7f5a5e19
一些检查失败了
changelog-filename-gate / validate (push) Has been cancelled
chore(changelog): 标记前端已实现 #5237
修改原因:hl-ui changelog loop 需要把前端消费进度回写到契约源,避免领取、实现状态与实际交付脱节。

修改内容:将 frontend_status 与已有 legacy frontend 同步为 implemented,记录负责人 hl-ui-codex,并关联 mmg/hl-ui@adff10ea74198f4e89a1488e631463bedbcd4eea;发布和验收字段保持不变。

实际验证:回写器已校验目标文件、状态单调性、提交范围和 Front Matter 内容,提交只包含当前 changelog。

Frontend-Status: tools/mcp-api-sync/.changelog-repo/changelogs-v2/2026-07/25_5237_酒店候选补齐房型结算价-修改接口-管理后台.md
2026-07-25 11:37:11 +08:00

17 KiB

frontend_status, frontend_owner, frontend_ref, updated_at
frontend_status frontend_owner frontend_ref updated_at
implemented hl-ui-codex mmg/hl-ui@adff10ea74 2026-07-25T03:37:10.934Z

【修改接口·管理后台】酒店候选补齐房型结算价 (#5237)

PR: #5240 | 服务: hl-order-service-v3 | 更新时间: 2026-07-25 10:58

1. 接口背景

管理后台酒店候选列表原来只在候选酒店顶层返回 protoPrice,前端无法确认这个价格来自哪个真实房型,也拿不到同一房型同一天的结算价。配房时如果只看房型列表或自行匹配最低价,容易把协议价和结算价口径拆到不同房型。

本次在候选酒店顶层补齐:

  • protoPriceRoomTypeId:产生顶层 protoPrice 的真实房型 ID。
  • settlementPrice:与 protoPriceRoomTypeId 同一房型、同一天的结算价。

顶层 protoPriceprotoPriceRoomTypeIdsettlementPrice 是同一代表房型口径。未维护结算价时 settlementPrice = null,不会用协议价兜底。

2. 变更清单

# 接口 方法 路径 变更类型 说明
1 查询酒店候选4 场景统一入口) GET /v3/admin/hotel-candidates 修改接口 候选酒店项新增 protoPriceRoomTypeIdsettlementPrice 两个出参字段;入参不变。

3. 接口详情

3.1 查询酒店候选4 场景统一入口)

  • 使用场景:管理后台在订单维度查询某一晚的候选酒店,用于配房选酒店、回显当前已配酒店、按产品池/定制师点名/资源库候选排序。
  • 认证:需要管理后台 JWT。
  • 幂等性:只读查询,幂等。
  • 限流:无接口级特殊限流;受网关与服务通用限流策略约束。

4. 接口入参

4.1 路径参数 / Query 参数

字段 类型 必填 说明
orderId String 订单 ID。后端 Long,JSON/Query 建议按字符串传,避免长 ID 精度问题。
dayNumber Integer 第几天,从 1 开始;用于推算 stayDate = departDate + dayNumber - 1。最小值 1。
stayDate String 入住日期,格式 yyyy-MM-dd;直接指定时优先于 dayNumber 推算。
city String 城市代码或城市名;未传且非关键词模式时默认不按城市限制。
keyword String 关键词;非空时跨城/省匹配酒店名、城市、省份、地址,此时 city 可不传。
limit Integer 返回候选条数上限,默认 30,最小 1,最大 50。
roomCategory String 房型字典 code。
roomCount Integer 需要的房间数;最小 1。
preferredHotelId String 定制师指定的优先酒店 ID。后端 Long,建议字符串传。
requirementId String 用房需求 ID;传入后将该需求 days JSON 中当前天的酒店候选作为定制师指定候选。后端 Long,建议字符串传。

4.2 请求体字段

GET 接口无请求体。

5. 出参字段

统一响应结构:

字段 类型 说明
code Integer 业务状态码,成功为 200
message String 响应消息,成功为 成功
data Object 酒店候选查询出参。
traceId String 链路追踪 ID,可能为空。
success Boolean code == 200 时为 true

data 字段:

字段 类型 说明
stayDate String 入住日期,格式 yyyy-MM-dd
city String / null 本次查询使用的城市;关键词模式或默认不限城市时可为 null
productType String 产品类型:CORE / GROUP / CUSTOM
candidates Array 候选酒店列表,已按产品类型分流排序。

data.candidates[] 字段:

字段 类型 说明
hotelId String 酒店 ID。
hotelName String 酒店名称。
level String / null 酒店等级。
form String / null 住宿形态。
address String / null 地址。
tags Array 运营标签;无标签时为空数组或 null
contactPerson String / null 联系人。
contactWechat String / null 联系微信。
settleType String / null 结算类型,取值见 §6.1。
city String / null 酒店所在城市。
district String / null 酒店所在区/县。
roomTypes Array 该酒店当日真实房型列表;无房型数据时为空数组。
protoPrice String / null 代表房型协议价。与 protoPriceRoomTypeId、顶层 settlementPrice 同一房型同一天。
protoPriceRoomTypeId String / null 产生顶层 protoPrice 的真实房型 ID。无有效可售协议价时为 null
settlementPrice String / null protoPriceRoomTypeId 同一房型、同一天的结算价。未维护时为 null,不会用 protoPrice 兜底。
todayAvailable Integer / null 今日全房型可用房数合计。
availFreshness String / null 可用数数据时效:fresh / stale / never_checked
lastCheckedAt String / null 最近一次核房时间,格式 yyyy-MM-dd'T'HH:mm:ss
matchedRoomTypeAvailable Integer / null 匹配房型今日可用数。
matchedRoomTypeId String / null 匹配的房型 ID。
matchedRoomTypeLabel String / null 匹配的房型中文。
quickPickEnabled Boolean / null 是否支持快速配房。
quickPickDisabledReason String / null 置灰原因。
isPoolMatch Boolean / null 是否产品池内。
poolMatchBadge Object / null 产品池内徽章。
isConsultantRecommended Boolean / null 是否被定制师点名。
consultantRecommendBadge Object / null 定制师点名徽章。
historyMatchScore Number / null 历史匹配度,范围 0-1。
score Number / null 排序分数。
recommendation String / null 推荐理由。
recommended Boolean / null 是否为推荐候选。
recommendSource String / null 推荐来源,见 §6.4。
historyScoreStub Boolean / null 历史命中分数是否为 stub。
isCurrentlyAssigned Boolean / null 是否为本天当前已配酒店。
assignedRoomTypeId String / null 本天当前已配的房型 ID;isCurrentlyAssigned=true 时可用于预填原房型。

data.candidates[].roomTypes[] 字段:

字段 类型 说明
roomTypeId String 房型 ID。
name String / null 房型名称。
roomCategory String / null 房型分类字典值。
bedType String / null 床型,已按字典尽量翻译;字典缺失时可回退为 code。
maxOccupancy Integer / null 最大入住人数。
available Integer / null 今日可用房数;unlimited=true 时为 null,语义为不限。
unlimited Boolean 是否不限库存。
stock Integer / null 当前可用房;unlimited=true 时为 null
protocolPrice String / null 该房型当日协议价。
settlementPrice String / null 该房型当日结算价。
basePrice String / null 标价/挂牌价。
inventoryStatus String 库存状态,见 §6.2。

徽章对象字段:

字段 类型 说明
label String 中文徽章文字。
color String 徽章色,见 §6.5。
tooltip String 悬浮提示。

6. 枚举 / 数据字典

6.1 settleType

所属字段data.candidates[].settleType | 类型String | 必填:否

中文 说明
cash 现付 到店或线下现金类结算。
sign 签单 供应商签单结算。
company 公司付 公司统一付款结算。

6.2 inventoryStatus

所属字段data.candidates[].roomTypes[].inventoryStatus | 类型String | 必填:是

中文 说明
AVAILABLE 可售 有余量,或 unlimited=true 不限库存。
FULL 满房 有日历记录,但库存为 0。
CLOSED 未开放 无该日价格日历记录。

6.3 availFreshness

所属字段data.candidates[].availFreshness | 类型String | 必填:否

中文 说明
fresh 最新 可用于快速配房判断。
stale 过期 核房数据过期。
never_checked 从未核房 无可用核房数据。

6.4 recommendSource

所属字段data.candidates[].recommendSource | 类型String | 必填:否

中文 说明
PRODUCT_POOL 产品池 来自产品池候选。
CONSULTANT 定制师点名 来自定制师指定候选。
RESOURCE_LIB 资源库 来自资源库候选。

6.5 Badge.color

所属字段poolMatchBadge.color / consultantRecommendBadge.color | 类型String | 必填:否

中文 说明
blue 蓝色 普通推荐或池内标识。
gold 金色 高优先级推荐标识。
gray 灰色 弱提示标识。

7. 错误码

code 含义 触发场景
200 成功 查询成功。
400 参数错误 orderId 为空、dayNumber < 1limit 超出 1-50、roomCount < 1、日期格式不是 yyyy-MM-dd 等参数绑定或校验失败。
401 未认证 JWT 缺失或无效。
403 无权限 当前账号无权访问该管理后台接口或订单数据。
581007 订单不存在 orderId 对应订单不存在。
500 服务内部错误 非预期异常。

8. 示例3 组:典型 / 边界 / 异常)

8.1 典型成功

请求

GET /v3/admin/hotel-candidates?orderId=100001&dayNumber=1&stayDate=2026-07-25&limit=30&roomCount=2 HTTP/1.1
Authorization: Bearer <admin-jwt>

无请求体。

响应

{
  "code": 200,
  "message": "成功",
  "data": {
    "stayDate": "2026-07-25",
    "city": null,
    "productType": "CORE",
    "candidates": [
      {
        "hotelId": "2023714929877450753",
        "hotelName": "测试酒店",
        "level": "舒适型",
        "form": "HOTEL",
        "address": "呼伦贝尔市海拉尔区测试路 1 号",
        "tags": ["协议酒店"],
        "contactPerson": "张经理",
        "contactWechat": "hotel_mgr",
        "settleType": "sign",
        "city": "呼伦贝尔市",
        "district": "海拉尔区",
        "protoPrice": "280.00",
        "protoPriceRoomTypeId": "2023727403196502017",
        "settlementPrice": "279.00",
        "todayAvailable": 7,
        "availFreshness": "fresh",
        "lastCheckedAt": null,
        "matchedRoomTypeAvailable": 7,
        "matchedRoomTypeId": "2023727403196502017",
        "matchedRoomTypeLabel": "豪华大床房",
        "quickPickEnabled": true,
        "quickPickDisabledReason": null,
        "isPoolMatch": true,
        "poolMatchBadge": {
          "label": "产品池内",
          "color": "blue",
          "tooltip": "本酒店在产品池内,优先推荐"
        },
        "isConsultantRecommended": false,
        "consultantRecommendBadge": null,
        "historyMatchScore": 0.85,
        "score": 1185.0,
        "recommendation": "池内 · 历史合作 8 单成功率 95%",
        "recommended": true,
        "recommendSource": "PRODUCT_POOL",
        "historyScoreStub": true,
        "isCurrentlyAssigned": false,
        "assignedRoomTypeId": null,
        "roomTypes": [
          {
            "roomTypeId": "2023727403196502017",
            "name": "豪华大床房",
            "roomCategory": "KING",
            "bedType": "大床",
            "maxOccupancy": 2,
            "available": 7,
            "unlimited": false,
            "stock": 7,
            "protocolPrice": "280.00",
            "settlementPrice": "279.00",
            "basePrice": "568.00",
            "inventoryStatus": "AVAILABLE"
          }
        ]
      }
    ]
  },
  "traceId": "trace-20260725-0001",
  "success": true
}

8.2 边界情况

场景说明:代表房型有协议价但未维护结算价,顶层 settlementPrice 返回 null,不使用 protoPrice 兜底。

请求

GET /v3/admin/hotel-candidates?orderId=100001&stayDate=2026-07-25&keyword=%E6%B5%B7%E6%8B%89%E5%B0%94&limit=1 HTTP/1.1
Authorization: Bearer <admin-jwt>

无请求体。

响应

{
  "code": 200,
  "message": "成功",
  "data": {
    "stayDate": "2026-07-25",
    "city": null,
    "productType": "CUSTOM",
    "candidates": [
      {
        "hotelId": "2023714929877450753",
        "hotelName": "测试酒店",
        "settleType": "cash",
        "protoPrice": "280.00",
        "protoPriceRoomTypeId": "2023727403196502017",
        "settlementPrice": null,
        "roomTypes": [
          {
            "roomTypeId": "2023727403196502017",
            "name": "豪华大床房",
            "available": 7,
            "unlimited": false,
            "protocolPrice": "280.00",
            "settlementPrice": null,
            "basePrice": "568.00",
            "inventoryStatus": "AVAILABLE"
          }
        ],
        "quickPickEnabled": true,
        "recommended": true,
        "recommendSource": "RESOURCE_LIB"
      }
    ]
  },
  "traceId": "trace-20260725-0002",
  "success": true
}

8.3 业务失败(异常)

场景说明orderId 未传,触发参数校验失败。

请求

GET /v3/admin/hotel-candidates?stayDate=2026-07-25 HTTP/1.1
Authorization: Bearer <admin-jwt>

无请求体。

响应

{
  "code": 400,
  "message": "orderId 不能为空",
  "data": null,
  "traceId": "trace-20260725-0003",
  "success": false
}

9. 业务边界

  • 适用场景:管理后台按订单和入住日查询酒店候选;stayDate 可直接传,也可通过 dayNumber 和订单出发日推算。
  • 不适用场景:不用于前端直接查询内部资源服务;本文只描述管理后台 /v3/admin/hotel-candidates
  • 特殊边界:顶层 protoPriceprotoPriceRoomTypeIdsettlementPrice 必须按同一代表房型理解;settlementPrice = null 表示该代表房型当天未维护结算价。
  • 特殊边界roomTypes[].settlementPrice 是每个房型自己的当日结算价;顶层 settlementPrice 只对应 protoPriceRoomTypeId 指向的代表房型。

10. 修改前后对比

10.1 字段级对比

字段 改前 改后
data.candidates[].protoPriceRoomTypeId 不返回 返回产生顶层 protoPrice 的真实房型 ID;无有效可售协议价为 null
data.candidates[].settlementPrice 不返回 返回与 protoPriceRoomTypeId 同一房型、同一天的结算价;未维护为 null
data.candidates[].protoPrice 已返回,但无法判断来自哪个房型 仍返回原字段,并与新增的 protoPriceRoomTypeId、顶层 settlementPrice 组成同一代表房型口径。

10.2 行为级对比

行为 改前 改后
候选酒店顶层价格展示 只能拿到代表协议价 protoPrice 可同时拿到代表协议价、代表房型 ID、该代表房型结算价。
结算价为空 顶层没有结算价字段。 顶层 settlementPrice 返回 null;不使用 protoPrice 兜底。

11. 影响评估 / 回滚

11.1 影响评估

  • 是否破坏向后兼容:否。只新增出参字段,已有字段名、类型、入参不变。
  • 前端是否必须同步上线:否。老前端可忽略新增字段;需要展示或回填结算价的页面可读取新增字段。
  • 影响已有数据:无数据迁移要求;历史未维护结算价的房型按 settlementPrice = null 返回。

11.2 回滚方案

  • 回滚方式:回滚 PR #5240 后,顶层新增字段不再返回。
  • 回滚后清理:无前端数据清理要求。
  • 回滚耗时:按常规服务回滚流程处理。

12. 注意事项

  • 前端读取顶层 settlementPrice 时,不要把 null 当作 protoPricenull 表示未维护结算价。
  • 如需定位价格来自哪个房型,使用顶层 protoPriceRoomTypeId 去匹配 roomTypes[].roomTypeId
  • 金额和长 ID 在响应 JSON 中按字符串处理,例如 "280.00""2023727403196502017"

13. 关联 / 联系人

13.1 链接

13.2 联系人

  • 后端负责人: @yst