新增 30_8597 覆盖两个端点:
- PUT /v3/admin/order/house-console/room-transfers/{id}/deadline
- GET /v3/admin/order/house-console/audit
同时就地订正已交付的 30_8491(4 行 / 3 处):原文写「cancelDays 传 null 时
cancelCutoff / remindDays 一并清空」,与源码相反。HouseRoomTransferManager#doUpdateDeadline
对 cancelDays == null 的分支是「cutoff / remind 沿用行上原值」——两列 NOT NULL,
传 null 会被 Mapper 守卫当失败返 0、进而被误报成并发修改(正是 #8597 的根因)。
30_8491 自己第 1847 行记录的实测读数也是「cancelCutoff 保留」,即该文件内部自相矛盾。
订正不是措辞问题:前端若按原文写 `cancelCutoff === null` 去判「有没有设期限」,
那个判断恒为 false。订正后同时写明正确判据是看 cancelDays 或 risk === "NO_DEADLINE"。
两文件 validate-changelog-frontmatter.mjs --files 全绿(校验 2 个对象,EXIT=0)。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
85 KiB
schema, ticket, title, consumer, author, change_type, backend_status, gateway_status, frontend_status, frontend_owner, frontend_ref, target_release, verified_at, status_note, updated_at, base
| schema | ticket | title | consumer | author | change_type | backend_status | gateway_status | frontend_status | frontend_owner | frontend_ref | target_release | verified_at | status_note | updated_at | base |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| hl-changelog/v2 | 8491 | 房务控制台新增接口:批量认领、改配取消确认、控房表、退团房转房、异常检查、住宿模板、团期转交 | admin | wx(GIT) | 新增接口 | deployed | not_required | pending | 2026-09-30 | dev-v3 |
房务控制台: 新增 17 个管理端接口(批量认领 / 改配取消确认 / 控房表 / 退团房转房 / 异常检查 / 住宿模板 / 团期转交)
存放目录: 二期 →
changelogs-v2/2026-09/服务: hl-order-service-v3 Issue: #8491 日期: 2026-09-29 影响范围: 管理后台新菜单「房务控制台」(
/housekeeper/console)及团期抢单池的「团期转交」
⚠️ 关键变化(非必须,本版与上版行为不同 / 纠错 / 撤销时必写)
- 新增菜单「房务控制台」,路由
/housekeeper/console;原菜单「待处理」(/housekeeper/todos)已删除。 - 房务通知里的跳转链接改指控制台:退团房为
/housekeeper/console?tab=transfer&id={transferId},团期为/housekeeper/console?groupBatchId={groupBatchId}。 - 本文 17 个接口全部为新增,路径前缀
/v3/admin/order/house-console/**(16 个)与/v3/admin/order/grab-pool/**(团期转交 1 个)。 - 房务人员名单取不到时,「团期转交」一律拒绝并返回 808343「房务人员名单暂不可用,请稍后重试」,不会像超管「整团接管」那样降级放行。
- 住宿模板的改 / 删只允许创建人本人或超管,否则返回 808352「只能修改或删除自己创建的模板」。
- 控房表是否可调房量由响应字段
stockTrackingEnabled决定(对应 resource 全局开关hotel.stock.enabled),前端按该字段控制「调房量」入口。
一、背景(选填)
#8491 把房务的日常操作收拢到一个控制台:批量认领待认领的常规单需求与团期;改配(换酒店 / 减间数)后对原酒店做取消确认;按酒店 × 房型 × 入住夜查看、调整控房总数与价格并导出;处理退团释放出来的房间(设免费取消期限、转给其他订单或团期、或向酒店取消);一屏查看数据不一致与未办完的事项;按「逐晚城市 / 酒店 / 房型」保存住宿模板复用;团期持有人把整团转交给其他房务。
二、变更接口清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|---|---|---|---|---|
| 1 | 改配原订取消确认 | PUT | /v3/admin/order/house-console/changes/{changeId}/cancel-confirm |
新增 | 上传原酒店取消凭证,HELD 转 CANCEL_CONFIRMED |
| 2 | 批量认领 | POST | /v3/admin/order/house-console/claims/batch |
新增 | 常规单需求与团期一次最多 50 条,逐条返回结果 |
| 3 | 控房表查询 | GET | /v3/admin/order/house-console/room-control |
新增 | 酒店 × 房型 × 入住夜的总数、已用、剩余、价格与团组用房 |
| 4 | 控房表调房量 | PUT | /v3/admin/order/house-console/room-control/stock |
新增 | 改单格控房总数,带已用间数 CAS |
| 5 | 控房表调价 | PUT | /v3/admin/order/house-console/room-control/price |
新增 | 按日期区间改控房价 / 结算价 |
| 6 | 控房表导出 | GET | /v3/admin/order/house-console/room-control/export |
新增 | xlsx,两个工作表,不含价格 |
| 7 | 退团房分页 | GET | /v3/admin/order/house-console/room-transfers |
新增 | 退团释放房间列表与待处理汇总 |
| 8 | 设置退团房免费取消期限 | PUT | /v3/admin/order/house-console/room-transfers/{id}/deadline |
新增 | 设 / 清免费取消期限与提醒天数 |
| 9 | 退团房转入候选 | GET | /v3/admin/order/house-console/room-transfers/{id}/candidates |
新增 | 同城同晚的订单 / 团期候选及不可转入原因 |
| 10 | 退团房转房 | POST | /v3/admin/order/house-console/room-transfers/{id}/transfer |
新增 | 把房间转给订单需求或团期 |
| 11 | 退团房向酒店取消 | POST | /v3/admin/order/house-console/room-transfers/{id}/cancel-hotel |
新增 | 上传取消凭证,行置为 CANCELLED |
| 12 | 房务异常检查 | GET | /v3/admin/order/house-console/audit |
新增 | issues 数据不一致 + tasks 待办 |
| 13 | 住宿模板列表 | GET | /v3/admin/order/house-console/stay-templates |
新增 | 全部创建人的模板,按创建时间倒序 |
| 14 | 住宿模板详情 | GET | /v3/admin/order/house-console/stay-templates/{id} |
新增 | 逐晚城市 / 酒店 / 房型明细 |
| 15 | 住宿模板保存 | POST | /v3/admin/order/house-console/stay-templates |
新增 | id 为空新建,否则修改 |
| 16 | 住宿模板删除 | DELETE | /v3/admin/order/house-console/stay-templates/{id} |
新增 | 软删,仅创建人或超管 |
| 17 | 团期转交 | POST | /v3/admin/order/grab-pool/group-batches/{groupBatchId}/transfer |
新增 | 团期持有人或超管把整团交给其他房务 |
三、接口详情
本节示例 JSON 的字段名、类型、错误码与文案逐一取自源码;ID、日期、金额、姓名等取值为说明用的构造值。所有接口统一返回 Result 信封(code / message / data / traceId / success),示例省略 traceId;业务失败与入参校验失败均为 HTTP 200,靠 code 区分。ID 与金额字段序列化为字符串。
1. 改配原订取消确认 PUT /v3/admin/order/house-console/changes/{changeId}/cancel-confirm
VO: HouseAssignmentChangeConfirmReqVO → Result<Void>
使用场景
订单房务详情(GET /admin/house/orders/{orderId})的 changes[] 里 oldStatus=HELD 的改配记录,房务向原酒店取消后,在该记录上点「确认取消」并上传取消凭证。changeId 取自 changes[].changeId。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| changeId | Path | Long | ✅ | - | 改配记录 ID |
| cancelProofFileIds | Body | List | ✅ | 1~9 个,元素非空 | 取消凭证文件 ID |
| cancelFee | Body | BigDecimal | ❌ | ≥0,最多 2 位小数 | 取消费用(元) |
| remark | Body | String | ❌ | ≤200 字 | 备注 |
出参 Result<Void>
| 字段 | 类型 | 说明 |
|---|---|---|
| data | null | 成功无返回体,前端成功后重新拉取订单房务详情 |
请求示例
{
"cancelProofFileIds": [1930000000000000501],
"cancelFee": "120.00",
"remark": "酒店已电话确认取消"
}
响应示例
{
"code": 200,
"message": "成功",
"data": null,
"success": true
}
空数据 / 降级响应
本接口无列表数据,成功时 data 恒为 null。无降级分支:任何失败都返回非 200 的 code,记录不变。
错误响应
{
"code": 808333,
"message": "原订已确认取消",
"data": null,
"success": false
}
其余错误:
| code | message | 触发 |
|---|---|---|
| 400 | 请上传取消凭证 / 取消凭证 1~9 个 / 凭证文件 ID 不能为空 / 取消费用不能为负 / 取消费用最多 2 位小数 / 备注不能超过 200 字 | 入参校验 |
| 808090 | 未登录或非房务角色,无权操作 | 非房务角色 |
| 808332 | 变更记录不存在 | changeId 不存在 |
| 808116 | 订单未抢单, 请先抢单再配房 | 该需求无人持有 |
| 808110 | 需求不属于当前用户 | 当前登录人不是需求持有人(超管同样拒绝) |
| 808333 | 原订已确认取消 | 记录已不是 HELD,或并发确认时落后的一方 |
| 100503 | 资源被占用,请稍后重试 | 同一 changeId 正在被另一请求处理 |
业务边界
- 只有该需求的当前持有人能确认;超管不豁免,超管要确认须先把需求「指派」或「转单」给自己。
- 只能从
HELD确认一次,成功后oldStatus=CANCEL_CONFIRMED;重复确认返回 808333。 - 成功时覆盖写该记录的取消费用、凭证与备注,操作人记为确认人;不改配房行,不发通知。
- 同一
changeId在服务端串行处理(锁 30 秒),并发请求其一返回 100503 或 808333。
2. 批量认领 POST /v3/admin/order/house-console/claims/batch
VO: HouseConsoleBatchClaimReqVO → HouseConsoleBatchClaimRespVO
使用场景
控房台待认领列表勾选多条常规单需求和 / 或团期,一次提交认领。结果逐条返回,前端按 items[] 标出成功与失败原因。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| requirementIds | Body | List | ❌ | 元素非空 | 常规单住宿需求 ID 列表 |
| groupBatchIds | Body | List | ❌ | 元素非空 | 团期 ID 列表 |
| (跨字段) | Body | - | ✅ | 两列表各自去重后合计 1~50 条 | 违反时返回 400「请选择 1~50 条待认领记录」 |
出参 Result<HouseConsoleBatchClaimRespVO>
| 字段 | 类型 | 说明 |
|---|---|---|
| successCount | Integer | 成功条数 |
| failCount | Integer | 失败条数 |
| items | List | 逐项结果,顺序:先需求后团期,各自按提交顺序去重 |
| items[].targetType | String | REQUIREMENT 常规单住宿需求 / GROUP_BATCH 团期 |
| items[].targetId | Long(String) | 需求 ID 或团期 ID |
| items[].orderId | Long(String) | 订单 ID,仅需求项有;团期项为空 |
| items[].teamNo | String | 团号;无团号为空 |
| items[].batchNo | String | 团期批次号,仅团期项有 |
| items[].success | Boolean | 是否认领成功 |
| items[].errorCode | Integer | 失败错误码;成功为空,系统异常也为空 |
| items[].errorMessage | String | 失败原因;成功为空 |
请求示例
{
"requirementIds": [1840000000000000001, 1840000000000000011],
"groupBatchIds": [1840000000000000002]
}
响应示例
{
"code": 200,
"message": "成功",
"data": {
"successCount": 2,
"failCount": 1,
"items": [
{ "targetType": "REQUIREMENT", "targetId": "1840000000000000001", "orderId": "1840000000000000003", "teamNo": "HL20261002A", "batchNo": null, "success": true, "errorCode": null, "errorMessage": null },
{ "targetType": "REQUIREMENT", "targetId": "1840000000000000011", "orderId": "1840000000000000013", "teamNo": "HL20261003B", "batchNo": null, "success": false, "errorCode": 808001, "errorMessage": "该需求已被其他房务认领或状态已变化,请刷新后重试" },
{ "targetType": "GROUP_BATCH", "targetId": "1840000000000000002", "orderId": null, "teamNo": null, "batchNo": "GB20261001-01", "success": true, "errorCode": null, "errorMessage": null }
]
},
"success": true
}
空数据 / 降级响应
- 订单号 / 团号 / 批次号等展示字段是一次批量查询补齐的;该查询失败时这些字段为空,认领结果不受影响。
- 单条出现非业务异常时该条
success=false、errorCode=null、errorMessage="系统繁忙,请稍后重试",其余条目照常处理。
错误响应
{
"code": 400,
"message": "请选择 1~50 条待认领记录",
"data": null,
"success": false
}
整体失败:
| code | message | 触发 |
|---|---|---|
| 400 | 请选择 1~50 条待认领记录 / 需求 ID 不能为空 / 团期 ID 不能为空 | 入参校验 |
| 808090 | 未登录或非房务角色,无权操作 | 非房务角色 |
| 100502 | 批量认领处理中,请勿重复提交 | 同一批 3 秒内重复提交 |
逐项失败(出现在 items[].errorCode)常见值:808001「该需求已被其他房务认领或状态已变化,请刷新后重试」、808002「需求已不存在」、808003「该需求已由您抢到,请勿重复抢单」、808004「需求所在订单已取消」,团期项沿用整团认领的既有错误码。
业务边界
- 每一条独立认领、独立成败,不整体回滚;HTTP 与
code为 200 只代表批次处理完,逐项看items[].success。 - 需求项走常规单抢单、团期项走整团认领,校验与单条认领一致。
- 同一 ID 重复提交只处理一次;
successCount + failCount等于去重后的条数。
3. 控房表查询 GET /v3/admin/order/house-console/room-control
VO: HouseRoomControlListReqVO → HouseRoomControlRespVO
使用场景
控制台「控房表」页签加载:按城市或酒店、入住夜区间列出每个酒店 × 房型 × 入住夜的控房总数、已用、剩余、已分配、价格,以及每格的团组用房明细。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| cityCode | Query | String | ❌ | ≤32 | 城市编码(如 hailar);与 hotelId 都不传则查全部酒店 |
| hotelId | Query | Long | ❌ | - | 传了只查这一家,优先于 cityCode |
| dateFrom | Query | LocalDate | ✅ | yyyy-MM-dd | 入住夜起(含) |
| dateTo | Query | LocalDate | ✅ | yyyy-MM-dd;跨度 ≤62 天(含首尾) | 入住夜止(含) |
| onlyWithRemain | Query | Boolean | ❌ | - | true 时只返回剩余为不限或 >0 的行 |
出参 Result<HouseRoomControlRespVO>
| 字段 | 类型 | 说明 |
|---|---|---|
| stockTrackingEnabled | Boolean | resource 全局库存追踪开关(hotel.stock.enabled);false 时行照常返回,但调房量会被拒(808312) |
| rows | List | 控房行,按(酒店, 入住夜, 房型)升序 |
| rows[].hotelId | Long(String) | 酒店 ID |
| rows[].hotelName | String | 酒店名称 |
| rows[].cityName | String | 城市中文名 |
| rows[].roomTypeId | Long(String) | 房型 ID |
| rows[].roomTypeName | String | 房型名称 |
| rows[].stayDate | LocalDate | 入住夜 |
| rows[].totalRooms | Integer | 控房总数 = 剩余 + 已用;null 表示不限量 |
| rows[].usedRooms | Integer | 已用(resource 当前值) |
| rows[].remainRooms | Integer | 剩余;null 表示不限量 |
| rows[].assignedRooms | Integer | 已分配:扣库存的配房行 + 已确认扣库存的团期计划行的间数合计 |
| rows[].protocolPrice | BigDecimal(String) | 控房价 |
| rows[].settlementPrice | BigDecimal(String) | 结算价 |
| rows[].usages | List | 团组用房明细 |
| rows[].usages[].orderId | Long(String) | 订单 ID;团期计划行为 null |
| rows[].usages[].teamNo | String | 团号;团期计划行或无团号为 null |
| rows[].usages[].batchNo | String | 团期批次号;散客订单为 null |
| rows[].usages[].roomCount | Integer | 用房间数 |
| rows[].usages[].roomSource | String | 恒为 STOCK(本表只列扣库存行) |
| rows[].usages[].roomSourceLabel | String | 控房 |
| rows[].usages[].confirmStatusLabel | String | 确认状态标签 |
请求示例
GET /v3/admin/order/house-console/room-control?cityCode=hailar&dateFrom=2026-10-01&dateTo=2026-10-07&onlyWithRemain=false
响应示例
{
"code": 200,
"message": "成功",
"data": {
"stockTrackingEnabled": true,
"rows": [
{
"hotelId": "100001",
"hotelName": "海拉尔草原酒店",
"cityName": "海拉尔",
"roomTypeId": "300001",
"roomTypeName": "豪华双床房",
"stayDate": "2026-10-01",
"totalRooms": 12,
"usedRooms": 5,
"remainRooms": 7,
"assignedRooms": 5,
"protocolPrice": "320.00",
"settlementPrice": "300.00",
"usages": [
{ "orderId": "1930000000000000001", "teamNo": "HL20261001A", "batchNo": null, "roomCount": 3, "roomSource": "STOCK", "roomSourceLabel": "控房", "confirmStatusLabel": "已确认" },
{ "orderId": null, "teamNo": null, "batchNo": "GB20261001", "roomCount": 2, "roomSource": "STOCK", "roomSourceLabel": "控房", "confirmStatusLabel": "已确认" }
]
}
]
},
"success": true
}
空数据 / 降级响应
{ "code": 200, "message": "成功", "data": { "stockTrackingEnabled": true, "rows": [] }, "success": true }
条件内无控房行时 rows 为空数组。resource 服务不可用时不降级为空表,返回 808900。
错误响应
{
"code": 808313,
"message": "日期跨度不能超过 62 天",
"data": null,
"success": false
}
| code | message | 触发 |
|---|---|---|
| 400 | dateFrom 不能为空 / dateTo 不能为空 | 入参校验 |
| 808090 | 未登录或非房务角色,无权操作 | 非房务角色 |
| 808313 | 日期跨度不能超过 62 天 | dateFrom 晚于 dateTo,或跨度超 62 天 |
| 808330 | 查询范围过大,请缩小酒店或日期范围 | 结果超过 2000 行 |
| 808900 | 资源服务暂不可用,请稍后重试 | resource 调用失败 |
业务边界
- 本接口的
cityCode是城市编码;退团房列表(接口 7)的cityCode是城市中文名,两处不要混用。 stockTrackingEnabled=false时行照常返回,已用 / 剩余取 resource 当前值,但此时配房不扣减库存,已用 / 剩余不随配房变化;前端应据此隐藏或禁用「调房量」。- 纯读接口,无幂等要求,不写任何数据。
4. 控房表调房量 PUT /v3/admin/order/house-console/room-control/stock
VO: HouseRoomControlStockSaveReqVO → HouseRoomControlRowRespVO
使用场景
控房表某一格(酒店 × 房型 × 入住夜)点「调房量」,修改控房总数。提交时带上页面读到的已用间数做并发校验。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| hotelId | Body | Long | ✅ | - | 酒店 ID |
| roomTypeId | Body | Long | ✅ | - | 房型 ID |
| stayDate | Body | LocalDate | ✅ | yyyy-MM-dd | 入住夜 |
| totalRooms | Body | Integer | ✅ | 0~500 | 新的控房总数 |
| expectedUsedRooms | Body | Integer | ✅ | ≥0 | 页面读到的已用间数(CAS 期望值) |
出参 Result<HouseRoomControlRowRespVO>
| 字段 | 类型 | 说明 |
|---|---|---|
| hotelId / hotelName / cityName | Long(String) / String / String | 酒店与城市 |
| roomTypeId / roomTypeName | Long(String) / String | 房型 |
| stayDate | LocalDate | 入住夜 |
| totalRooms | Integer | 调整后的控房总数;null 表示不限量 |
| usedRooms | Integer | 已用 |
| remainRooms | Integer | 剩余;null 表示不限量 |
| assignedRooms | Integer | 已分配间数 |
| protocolPrice / settlementPrice | BigDecimal(String) | 控房价 / 结算价 |
| usages | List | 团组用房明细,字段同接口 3 |
请求示例
{
"hotelId": 100001,
"roomTypeId": 300001,
"stayDate": "2026-10-01",
"totalRooms": 15,
"expectedUsedRooms": 5
}
响应示例
{
"code": 200,
"message": "成功",
"data": {
"hotelId": "100001", "hotelName": "海拉尔草原酒店", "cityName": "海拉尔",
"roomTypeId": "300001", "roomTypeName": "豪华双床房", "stayDate": "2026-10-01",
"totalRooms": 15, "usedRooms": 5, "remainRooms": 10, "assignedRooms": 5,
"protocolPrice": "320.00", "settlementPrice": "300.00",
"usages": [
{ "orderId": "1930000000000000001", "teamNo": "HL20261001A", "batchNo": null, "roomCount": 3, "roomSource": "STOCK", "roomSourceLabel": "控房", "confirmStatusLabel": "已确认" }
]
},
"success": true
}
空数据 / 降级响应
写入成功后服务端会重读这一行;重读失败时用写入结果拼出返回行,此时 assignedRooms=0、usages=[],前端可再调接口 3 刷新整表。
错误响应
{
"code": 808311,
"message": "已占用数已变化,请刷新后重试",
"data": null,
"success": false
}
| code | message | 触发 |
|---|---|---|
| 400 | hotelId 不能为空 / roomTypeId 不能为空 / stayDate 不能为空 / totalRooms 不能为空 / totalRooms 不能小于 0 / totalRooms 不能大于 500 / expectedUsedRooms 不能为空 / expectedUsedRooms 不能小于 0 | 入参校验 |
| 808090 | 未登录或非房务角色,无权操作 | 非房务角色 |
| 808312 | 库存追踪未开启,暂不能调整房量 | resource 全局开关关闭 |
| 808310 | 总房量不能小于已占用 {0} 间 | totalRooms 小于当前已用,{0} 为已用间数 |
| 808311 | 已占用数已变化,请刷新后重试 | expectedUsedRooms 与服务端当前已用不一致 |
| 100502 | 调房量处理中,请勿重复提交 | 同一操作人 3 秒内重复提交同一格 |
| 808900 | 资源服务暂不可用,请稍后重试 | resource 调用失败 |
业务边界
- 写守卫只要求房务角色,不校验认领人:控房是酒店级资源,不属于任何订单。
- 失败时控房总数不变。808311 后前端应重新查询该格再提交。
- 幂等键带操作人,两个房务 3 秒内改同一格不会被互判为重复提交,由 CAS 决定先后。
5. 控房表调价 PUT /v3/admin/order/house-console/room-control/price
VO: HouseRoomControlPriceSaveReqVO → Result<Integer>
使用场景
控房表选定酒店 × 房型,对一段入住夜批量修改控房价和 / 或结算价。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| hotelId | Body | Long | ✅ | - | 酒店 ID |
| roomTypeId | Body | Long | ✅ | - | 房型 ID |
| dateFrom | Body | LocalDate | ✅ | yyyy-MM-dd | 入住夜起(含) |
| dateTo | Body | LocalDate | ✅ | yyyy-MM-dd;跨度 ≤62 天 | 入住夜止(含) |
| protocolPrice | Body | BigDecimal | ❌ | >0,最多 2 位小数 | 控房价;不传则不改 |
| settlementPrice | Body | BigDecimal | ❌ | >0,最多 2 位小数 | 结算价;不传则不改 |
出参 Result<Integer>
| 字段 | 类型 | 说明 |
|---|---|---|
| data | Integer | 受影响的天数(更新已有价格日历行 + 补建缺失日历行) |
请求示例
{
"hotelId": 100001,
"roomTypeId": 300001,
"dateFrom": "2026-10-01",
"dateTo": "2026-10-07",
"protocolPrice": "320.00",
"settlementPrice": "300.00"
}
响应示例
{
"code": 200,
"message": "成功",
"data": 7,
"success": true
}
空数据 / 降级响应
本接口无列表型数据;区间内缺失的价格日历行会被补建并计入 data。
错误响应
{
"code": 808314,
"message": "协议价与结算价至少填写一项",
"data": null,
"success": false
}
| code | message | 触发 |
|---|---|---|
| 400 | hotelId 不能为空 / roomTypeId 不能为空 / dateFrom 不能为空 / dateTo 不能为空 / protocolPrice 必须大于 0 / protocolPrice 最多 2 位小数 / settlementPrice 必须大于 0 / settlementPrice 最多 2 位小数 | 入参校验 |
| 808090 | 未登录或非房务角色,无权操作 | 非房务角色 |
| 808313 | 日期跨度不能超过 62 天 | dateFrom 晚于 dateTo 或跨度超 62 天 |
| 808314 | 协议价与结算价至少填写一项 | 两个价格都没传 |
| 100502 | 调价处理中,请勿重复提交 | 3 秒内重复提交 |
| 808900 | 资源服务暂不可用,请稍后重试 | resource 调用失败 |
业务边界
- 只影响之后新生成的配房;已有配房行保存的是配房当时的价格快照,不回写。
- 不传的价格字段保持原值,不会被清空。
- 一次调用按区间整体写入,不需要前端逐日调用。
6. 控房表导出 GET /v3/admin/order/house-console/room-control/export
VO: HouseRoomControlListReqVO → xlsx 文件流
使用场景
控房表页签点「导出」,按与查询相同的条件下载 Excel。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| cityCode | Query | String | ❌ | ≤32 | 城市编码;与 hotelId 都不传则导出全部酒店 |
| hotelId | Query | Long | ❌ | - | 只导出这一家,优先于 cityCode |
| dateFrom | Query | LocalDate | ✅ | yyyy-MM-dd | 入住夜起(含) |
| dateTo | Query | LocalDate | ✅ | yyyy-MM-dd;跨度 ≤62 天 | 入住夜止(含) |
| onlyWithRemain | Query | Boolean | ❌ | - | 只导出有剩余的行 |
出参 xlsx 文件流(失败时为 Result JSON)
| 字段 | 类型 | 说明 |
|---|---|---|
| Content-Type | Header | application/vnd.openxmlformats-officedocument.spreadsheetml.sheet |
| Content-Disposition | Header | attachment; filename="<URL 编码文件名>"; filename*=UTF-8''<URL 编码文件名> |
| 文件名 | String | 控房表-{dateFrom}~{dateTo}.xlsx |
| 工作表「每日房量」 | Sheet | 每个酒店 × 房型 × 入住夜一行;列:酒店 / 入住夜日期 / 房型 / 控房总数 / 已用 / 剩余;不限量时总数与剩余显示「不限」 |
| 工作表「团组用房」 | Sheet | 一条占用一行;列:酒店 / 入住夜日期 / 房型 / 团号 / 房源 / 用房间数 / 确认状态;团期计划行没有团号,团号列填批次号 |
请求示例
GET /v3/admin/order/house-console/room-control/export?hotelId=100001&dateFrom=2026-10-01&dateTo=2026-10-07
响应示例
{
"Content-Type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"Content-Disposition": "attachment; filename=\"%E6%8E%A7%E6%88%BF%E8%A1%A8-2026-10-01~2026-10-07.xlsx\"; filename*=UTF-8''%E6%8E%A7%E6%88%BF%E8%A1%A8-2026-10-01~2026-10-07.xlsx"
}
以上为响应头,响应体是二进制 xlsx。
空数据 / 降级响应
条件内无数据时仍返回 xlsx,两个工作表只有表头。
错误响应
{
"code": 808330,
"message": "查询范围过大,请缩小酒店或日期范围",
"data": null,
"success": false
}
失败时响应体是 Result JSON 而不是文件,错误码同接口 3(400 / 808090 / 808313 / 808330 / 808900),另有 100502「导出处理中,请勿重复点击」。前端下载前需按 Content-Type 判断是文件还是 JSON。
业务边界
- 导出内容不含价格列。
- 与接口 3 同一查询条件与同一 2000 行上限。
- 同一条件 3 秒内重复点击返回 100502。
7. 退团房分页 GET /v3/admin/order/house-console/room-transfers
VO: HouseRoomTransferPageReqVO → HouseRoomTransferPageRespVO
使用场景
控制台「退团房」页签(通知链接 /housekeeper/console?tab=transfer&id={transferId}):列出退团释放出来、需要转给别人或向酒店取消的房间,并给出待处理的风险汇总。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| page | Query | Integer | ❌ | 默认 1 | 页码 |
| pageSize | Query | Integer | ❌ | 1~100,默认 20 | 每页条数 |
| status | Query | String | ❌ | PENDING / TRANSFERRED / CANCELLED,默认 PENDING | 状态 |
| risk | Query | String | ❌ | OVERDUE / NEAR / NO_DEADLINE / NORMAL | 风险筛选 |
| cityCode | Query | String | ❌ | ≤64 | 城市中文名(如 海拉尔) |
| keyword | Query | String | ❌ | ≤64 | 团号或酒店名 |
| stayDateFrom | Query | LocalDate | ❌ | yyyy-MM-dd | 入住晚起(含) |
| stayDateTo | Query | LocalDate | ❌ | yyyy-MM-dd | 入住晚止(含) |
出参 Result<HouseRoomTransferPageRespVO>
| 字段 | 类型 | 说明 |
|---|---|---|
| records | List | 当前页转房行 |
| records[].id | Long(String) | 转房行 ID |
| records[].sourceType | String | 来源类型 ORDER / GROUP_BATCH |
| records[].sourceOrderId | Long(String) | 源订单 ID(团期来源时为离团子单) |
| records[].teamNo | String | 源订单团号;空为 null |
| records[].sourceTeamNo | String | 源团号 / 批次号快照 |
| records[].sourceGroupBatchId | Long(String) | 源团期 ID |
| records[].sourceBatchNo | String | 源团期批次号 |
| records[].stayDate | LocalDate | 入住晚 |
| records[].cityName | String | 城市名 |
| records[].hotelId / hotelName | Long(String) / String | 酒店 |
| records[].roomTypeId / roomTypeName | Long(String) / String | 房型 |
| records[].roomCount | Integer | 原始间数 |
| records[].remainingCount | Integer | 剩余待处理间数 |
| records[].status / statusLabel | String | 状态及中文 |
| records[].cancelDays | Integer | 入住前几天免费取消;未设为 null |
| records[].cancelCutoff | String | 截止当天时刻 HH:mm |
| records[].remindDays | Integer | 提前几天提醒 |
| records[].deadlineAt | LocalDateTime | 免费取消截止时刻;未设期限为 null |
| records[].risk / riskLabel | String | 风险及中文;仅 PENDING 行有值 |
| records[].targetType | String | 最近一次转出的目标类型 ORDER / GROUP_BATCH |
| records[].targetOrderId / targetTeamNo | Long(String) / String | 目标订单与团号 |
| records[].targetRequirementId | Long(String) | 目标需求 ID |
| records[].targetGroupBatchId / targetBatchNo | Long(String) / String | 目标团期与批次号 |
| records[].hotelConfirmNo | String | 酒店确认号(转出时填写) |
| records[].proofFileIds | List | 凭证文件 ID |
| records[].cancelFee | BigDecimal(String) | 取消费用(元) |
| records[].cancelReason | String | 取消原因 HOTEL_CANCELLED |
| records[].handlerName / handledAt | String / LocalDateTime | 处理人与处理时间 |
| records[].remark | String | 备注 |
| records[].readOnly | Boolean | 对当前登录人是否只读(源单由他人处理) |
| records[].readOnlyReason | String | 「由 X 处理」;可写为 null |
| total | long | 总条数 |
| page / pageSize | int | 当前页 / 每页条数 |
| summary.pendingRooms | int | 全部 PENDING 行的待处理间数合计 |
| summary.overdueRooms | int | 其中已过免费取消期的间数 |
| summary.nearRooms | int | 其中临近免费取消期的间数 |
| summary.noDeadlineRooms | int | 其中未设免费取消期的间数 |
请求示例
GET /v3/admin/order/house-console/room-transfers?status=PENDING&cityCode=海拉尔&page=1&pageSize=20
响应示例
{
"code": 200,
"message": "成功",
"data": {
"records": [
{
"id": "1950000000000000001", "sourceType": "ORDER", "sourceOrderId": "1930000000000000001",
"teamNo": "HL20261001A", "sourceTeamNo": "HL20261001A", "sourceGroupBatchId": null, "sourceBatchNo": null,
"stayDate": "2026-10-02", "cityName": "海拉尔", "hotelId": "100001", "hotelName": "海拉尔草原酒店",
"roomTypeId": "300001", "roomTypeName": "豪华双床房", "roomCount": 2, "remainingCount": 2,
"status": "PENDING", "statusLabel": "待处理", "cancelDays": 3, "cancelCutoff": "18:00", "remindDays": 1,
"deadlineAt": "2026-09-29 18:00:00", "risk": "NEAR", "riskLabel": "临近免费取消期",
"targetType": null, "targetOrderId": null, "targetTeamNo": null, "targetRequirementId": null,
"targetGroupBatchId": null, "targetBatchNo": null, "hotelConfirmNo": null, "proofFileIds": [],
"cancelFee": null, "cancelReason": null, "handlerName": null, "handledAt": null, "remark": null,
"readOnly": false, "readOnlyReason": null
}
],
"total": 1,
"page": 1,
"pageSize": 20,
"summary": { "pendingRooms": 2, "overdueRooms": 0, "nearRooms": 2, "noDeadlineRooms": 0 }
},
"success": true
}
空数据 / 降级响应
{ "code": 200, "message": "成功", "data": { "records": [], "total": 0, "page": 1, "pageSize": 20, "summary": { "pendingRooms": 0, "overdueRooms": 0, "nearRooms": 0, "noDeadlineRooms": 0 } }, "success": true }
错误响应
{
"code": 400,
"message": "risk 取值非法",
"data": null,
"success": false
}
| code | message | 触发 |
|---|---|---|
| 400 | status 取值非法 / risk 取值非法 | 入参校验 |
| 808090 | 未登录或非房务角色,无权操作 | 非房务角色 |
业务边界
summary始终统计全部 PENDING 行,不受本次筛选条件影响;列表按筛选条件分页。risk只对 PENDING 行有意义,其他状态行risk/riskLabel为 null;带risk筛选时服务端在内存中分页,total仍是筛选后的总数。readOnly判据与写接口 8 / 10 / 11 的守卫一致:源单持有人本人为 false,超管豁免为 false,其余为 true 并给「由 X 处理」(持有人姓名取不到时为「由其他房务处理」)。
8. 设置退团房免费取消期限 PUT /v3/admin/order/house-console/room-transfers/{id}/deadline
VO: HouseRoomTransferDeadlineSaveReqVO → HouseRoomTransferRespVO
使用场景
退团房列表某一行点「设期限」,录入酒店给的免费取消规则(入住前几天、当天几点前)与提前几天提醒;也可清除期限。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| id | Path | Long | ✅ | - | 转房行 ID |
| cancelDays | Body | Integer | ❌ | 0~60;null 表示清除期限 | 入住前几天免费取消 |
| cancelCutoff | Body | String | ❌ | HH:mm;cancelDays 非空而本字段空时取 18:00;cancelDays 为 null 时本字段被忽略,该行原值保留、不置空(#8597 订正) | 截止当天的时刻 |
| remindDays | Body | Integer | ❌ | 0~30;cancelDays 非空而本字段空时取 1;cancelDays 为 null 时本字段被忽略,该行原值保留、不置空(#8597 订正) | 提前几天提醒 |
出参 Result<HouseRoomTransferRespVO>
| 字段 | 类型 | 说明 |
|---|---|---|
| (整行) | HouseRoomTransferRespVO | 更新后的该转房行,字段同接口 7 的 records[] |
| cancelDays / cancelCutoff / remindDays | Integer / String / Integer | 更新后的期限参数 |
| deadlineAt | LocalDateTime | 截止时刻 = 入住晚 − cancelDays 天的 cancelCutoff;清除期限后为 null |
| risk / riskLabel | String | 按新期限重算的风险 |
请求示例
{
"cancelDays": 3,
"cancelCutoff": "18:00",
"remindDays": 1
}
响应示例
{
"code": 200,
"message": "成功",
"data": {
"id": "1950000000000000001", "sourceType": "ORDER", "stayDate": "2026-10-02",
"hotelName": "海拉尔草原酒店", "roomTypeName": "豪华双床房", "remainingCount": 2,
"status": "PENDING", "statusLabel": "待处理", "cancelDays": 3, "cancelCutoff": "18:00", "remindDays": 1,
"deadlineAt": "2026-09-29 18:00:00", "risk": "NEAR", "riskLabel": "临近免费取消期",
"readOnly": false, "readOnlyReason": null
},
"success": true
}
空数据 / 降级响应
cancelDays 传 null 表示清除期限:只有 cancelDays 变成 null,cancelCutoff / remindDays 保留该行原值(从未设过期限时是默认的 "18:00" / 1);返回行的 deadlineAt=null、risk=NO_DEADLINE、riskLabel="未设免费取消期"。判「有没有设期限」只看 cancelDays === null 或 risk === "NO_DEADLINE",不要看 cancelCutoff / remindDays 是否为 null(#8597 订正)。
错误响应
{
"code": 808328,
"message": "退改期限参数不合法",
"data": null,
"success": false
}
| code | message | 触发 |
|---|---|---|
| 808090 | 未登录或非房务角色,无权操作 | 非房务角色 |
| 808320 | 转房记录不存在 | id 不存在 |
| 808326 | 只有原单处理人可以处理退团房间 | 非源单持有人且非超管 |
| 808328 | 退改期限参数不合法 | cancelDays 超 0 |
| 808321 | 该房间已处理 | 行已不是 PENDING |
| 808932 | 房务状态已被并发修改,请刷新后重试 | 并发写冲突 |
| 100502 | 修改处理中,请勿重复提交 | 3 秒内重复提交 |
业务边界
- 本接口的入参不走注解校验,范围与格式错误统一返回 808328(不是 400)。
- 只有 PENDING 行可改;源单持有人或超管可操作。
- 校验顺序:808320 → 808326 → 808328 → 808321 → 808932。
9. 退团房转入候选 GET /v3/admin/order/house-console/room-transfers/{id}/candidates
VO: Long id → List<HouseRoomTransferCandidateRespVO>
使用场景
退团房「转房」弹窗打开时加载:列出与该房间同城、同入住晚、非控房的常规单需求与团期,可转入的排在前面,不合格的带原因列出。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| id | Path | Long | ✅ | - | 转房行 ID |
出参 Result<List<HouseRoomTransferCandidateRespVO>>
| 字段 | 类型 | 说明 |
|---|---|---|
| targetType | String | ORDER / GROUP_BATCH |
| orderId | Long(String) | 目标订单 ID;团期目标为 null |
| teamNo | String | 目标订单团号 |
| requirementId | Long(String) | 目标需求 ID(targetType=ORDER 时转房入参用) |
| groupBatchId | Long(String) | 目标团期 ID(targetType=GROUP_BATCH 时转房入参用) |
| batchNo | String | 目标团期批次号 |
| guestName | String | 客人姓名 / 团期名称 |
| stayDate | LocalDate | 入住晚 |
| cityName | String | 城市名 |
| needRoomCount | Integer | 该晚还差几间没配 |
| eligible | Boolean | 是否可转入 |
| ineligibleReason | String | 不可转入原因 |
| holderName | String | 目标当前处理人姓名;待认领为 null |
| readOnly | Boolean | 目标是否由他人处理(仅展示,不影响转入) |
| readOnlyReason | String | 「由 X 处理」 |
请求示例
GET /v3/admin/order/house-console/room-transfers/1950000000000000001/candidates
响应示例
{
"code": 200,
"message": "成功",
"data": [
{ "targetType": "ORDER", "orderId": "1930000000000000009", "teamNo": "HL20261002C", "requirementId": "1940000000000000009", "groupBatchId": null, "batchNo": null, "guestName": "李女士", "stayDate": "2026-10-02", "cityName": "海拉尔", "needRoomCount": 2, "eligible": true, "ineligibleReason": null, "holderName": "张三", "readOnly": true, "readOnlyReason": "由 张三 处理" },
{ "targetType": "GROUP_BATCH", "orderId": null, "teamNo": null, "requirementId": null, "groupBatchId": "1960000000000000001", "batchNo": "GB20261001", "guestName": "呼伦贝尔秋季团", "stayDate": "2026-10-02", "cityName": "海拉尔", "needRoomCount": 3, "eligible": false, "ineligibleReason": "团期已确认", "holderName": null, "readOnly": false, "readOnlyReason": null }
],
"success": true
}
空数据 / 降级响应
{ "code": 200, "message": "成功", "data": [], "success": true }
该转房行已不是 PENDING(已转出 / 已取消)时同样返回空数组,不报错。
错误响应
{
"code": 808320,
"message": "转房记录不存在",
"data": null,
"success": false
}
| code | message | 触发 |
|---|---|---|
| 808090 | 未登录或非房务角色,无权操作 | 非房务角色 |
| 808320 | 转房记录不存在 | id 不存在 |
业务边界
readOnly只用于展示目标由谁处理,不影响能否转入;能否转入只看eligible。ineligibleReason取值见「六.5 枚举」;可转入的候选排在前面。- 纯读接口,不写数据。
10. 退团房转房 POST /v3/admin/order/house-console/room-transfers/{id}/transfer
VO: HouseRoomTransferSaveReqVO → HouseRoomTransferRespVO
使用场景
退团房「转房」弹窗选中一个候选后提交:把若干间房转给订单需求或团期,同时录入酒店确认号与凭证。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| id | Path | Long | ✅ | - | 转房行 ID |
| targetType | Body | String | ✅ | ORDER / GROUP_BATCH | 转入目标类型 |
| targetRequirementId | Body | Long | 条件 | targetType=ORDER 必填 | 目标需求 ID(取候选的 requirementId) |
| targetGroupBatchId | Body | Long | 条件 | targetType=GROUP_BATCH 必填 | 目标团期 ID(取候选的 groupBatchId) |
| roomCount | Body | Integer | ✅ | ≥1,且不超过剩余间数与目标缺口 | 转出间数 |
| hotelConfirmNo | Body | String | ✅ | 1~64 字 | 酒店确认号 |
| proofFileIds | Body | List | ✅ | 1~9 个,元素非空 | 凭证文件 ID |
| remark | Body | String | ❌ | ≤200 字 | 备注 |
出参 Result<HouseRoomTransferRespVO>
| 字段 | 类型 | 说明 |
|---|---|---|
| (整行) | HouseRoomTransferRespVO | 转房后的该行,字段同接口 7 的 records[] |
| remainingCount | Integer | 扣减后的剩余待处理间数 |
| status / statusLabel | String | 剩余为 0 时为 TRANSFERRED / 已转出,否则仍为 PENDING |
| targetType / targetOrderId / targetTeamNo / targetRequirementId / targetGroupBatchId / targetBatchNo | String / Long(String) / String / Long(String) / Long(String) / String | 最近一次转出的目标 |
| hotelConfirmNo / proofFileIds / handlerName / handledAt | String / List / String / LocalDateTime | 本次转出录入的信息 |
请求示例
{
"targetType": "ORDER",
"targetRequirementId": 1940000000000000009,
"roomCount": 2,
"hotelConfirmNo": "HX20261002001",
"proofFileIds": [1930000000000000601],
"remark": "酒店已同意换住客"
}
响应示例
{
"code": 200,
"message": "成功",
"data": {
"id": "1950000000000000001", "sourceType": "ORDER", "stayDate": "2026-10-02",
"hotelName": "海拉尔草原酒店", "roomTypeName": "豪华双床房", "roomCount": 2, "remainingCount": 0,
"status": "TRANSFERRED", "statusLabel": "已转出", "risk": null, "riskLabel": null,
"targetType": "ORDER", "targetOrderId": "1930000000000000009", "targetTeamNo": "HL20261002C",
"targetRequirementId": "1940000000000000009", "targetGroupBatchId": null, "targetBatchNo": null,
"hotelConfirmNo": "HX20261002001", "proofFileIds": ["1930000000000000601"],
"handlerName": "王房务", "handledAt": "2026-09-29 10:00:00", "remark": "酒店已同意换住客",
"readOnly": false, "readOnlyReason": null
},
"success": true
}
空数据 / 降级响应
本接口无列表数据;任何失败都返回非 200 的 code,源行、目标与配房均不变。
错误响应
{
"code": 808322,
"message": "目标不可转入:不同城",
"data": null,
"success": false
}
| code | message | 触发 |
|---|---|---|
| 400 | 请选择转入目标类型 / targetType 取值非法 / 请填写转出间数 / 转出间数至少 1 间 / 酒店确认号不能超过 64 字 / 凭证最多 9 个 / 凭证文件 ID 不能为空 / 备注不能超过 200 字 | 入参校验 |
| 808090 | 未登录或非房务角色,无权操作 | 非房务角色 |
| 808320 | 转房记录不存在 | id 不存在 |
| 808326 | 只有原单处理人可以处理退团房间 | 非源单持有人且非超管 |
| 808325 | 请填写酒店确认号并上传凭证 | 确认号为空或凭证为空 |
| 808322 | 目标不可转入:{0} | {0} 为具体原因,见「六.5 枚举」 |
| 808323 | 目标团期已确认,不能转入 | 目标团期已推进到确认;来源为团期(sourceType=GROUP_BATCH)且源团期已推进到确认时也返回本码,文案仍写「目标团期」 |
| 808321 | 该房间已处理 | 行已不是 PENDING |
| 808324 | 转出间数超过剩余 {0} 间 | roomCount 超过源剩余或目标缺口,{0} 为此刻可转间数 |
| 808608 | 订房计划已被其他操作修改,请刷新后重试 | 团期计划版本冲突 |
| 599602 | 应付款台账行已锁定 | 来源为 ORDER、源配房行对应的应付款台账行已有在途付款申请 |
| 808932 | 房务状态已被并发修改,请刷新后重试 | 并发写冲突 |
| 100502 | 转房处理中,请勿重复提交 | 3 秒内重复提交 |
| 100503 | 资源被占用,请稍后重试 | 源或目标正被另一写操作锁定 |
业务边界
- 只有源单持有人或超管可转;超管豁免持有人校验。目标由谁持有不影响转入。
hotelConfirmNo与proofFileIds在 Swagger 标为必填,但不是注解校验:缺失时返回业务码 808325,不是 400。- 校验顺序:808320 → 808326 → 808325 → 808322(未指定转入目标)→ 锁内复验(808323 / 808321 / 808324 / 808322 其余原因)→ 808932。
- 部分转出时该行保持 PENDING,
remainingCount减少;剩余为 0 时变为 TRANSFERRED。 - 来源为 ORDER 时,源配房行的应付款台账行若已有在途付款申请,返回 599602 且整笔不落库。
- 通知在事务提交后才发出、回滚时一条不发:目标处理人收
HOUSE_ROOM_TRANSFERRED(跳转/housekeeper/console?tab=transfer&id={transferId};目标待认领、没有处理人时不发),源单与目标单的定制师各收一条(同一人只发一次;团期目标只通知源单定制师)。
11. 退团房向酒店取消 POST /v3/admin/order/house-console/room-transfers/{id}/cancel-hotel
VO: HouseRoomTransferCancelReqVO → HouseRoomTransferRespVO
使用场景
退团房没有合适的转入对象时,房务向酒店取消该房间,上传取消凭证并录入取消费用。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| id | Path | Long | ✅ | - | 转房行 ID |
| proofFileIds | Body | List | ✅ | 1~9 个,元素非空 | 取消凭证文件 ID |
| cancelFee | Body | BigDecimal | ❌ | ≥0,最多 2 位小数 | 取消费用(元) |
| remark | Body | String | ❌ | ≤200 字 | 备注 |
出参 Result<HouseRoomTransferRespVO>
| 字段 | 类型 | 说明 |
|---|---|---|
| (整行) | HouseRoomTransferRespVO | 取消后的该行,字段同接口 7 的 records[] |
| status / statusLabel | String | CANCELLED / 已取消 |
| cancelReason | String | HOTEL_CANCELLED |
| cancelFee | BigDecimal(String) | 录入的取消费用 |
| proofFileIds | List | 取消凭证 |
请求示例
{
"proofFileIds": [1930000000000000701],
"cancelFee": "0.00",
"remark": "酒店已免费取消"
}
响应示例
{
"code": 200,
"message": "成功",
"data": {
"id": "1950000000000000001", "sourceType": "ORDER", "stayDate": "2026-10-02",
"hotelName": "海拉尔草原酒店", "roomTypeName": "豪华双床房", "roomCount": 2, "remainingCount": 2,
"status": "CANCELLED", "statusLabel": "已取消", "risk": null, "riskLabel": null,
"cancelFee": "0.00", "cancelReason": "HOTEL_CANCELLED", "proofFileIds": ["1930000000000000701"],
"handlerName": "王房务", "handledAt": "2026-09-29 10:00:00", "remark": "酒店已免费取消",
"readOnly": false, "readOnlyReason": null
},
"success": true
}
空数据 / 降级响应
本接口无列表数据;任何失败都返回非 200 的 code,该行不变。
错误响应
{
"code": 808325,
"message": "请填写酒店确认号并上传凭证",
"data": null,
"success": false
}
| code | message | 触发 |
|---|---|---|
| 400 | 凭证最多 9 个 / 凭证文件 ID 不能为空 / 取消费用不能为负 / 取消费用最多 2 位小数 / 备注不能超过 200 字 | 入参校验 |
| 808090 | 未登录或非房务角色,无权操作 | 非房务角色 |
| 808320 | 转房记录不存在 | id 不存在 |
| 808326 | 只有原单处理人可以处理退团房间 | 非源单持有人且非超管 |
| 808325 | 请填写酒店确认号并上传凭证 | 未上传凭证(本接口不要求确认号,文案沿用同一错误码) |
| 808321 | 该房间已处理 | 行已不是 PENDING |
| 808932 | 房务状态已被并发修改,请刷新后重试 | 并发写冲突 |
| 100502 | 取消处理中,请勿重复提交 | 3 秒内重复提交 |
业务边界
- 只有源单持有人或超管可操作。
- 凭证为空时返回 808325(业务码,不是 400)。
- 成功后该行整行变为 CANCELLED,不再出现在待处理汇总里;已部分转出的行取消的是剩余部分。
- 校验顺序:808320 → 808326 → 808325 → 808321 → 808932。
12. 房务异常检查 GET /v3/admin/order/house-console/audit
VO: HouseConsoleAuditReqVO → HouseConsoleAuditRespVO
使用场景
控制台「异常检查」页签:按出发日期区间一次列出数据对不上的问题(issues)和还没办完的事(tasks),每条可按 orderId / groupBatchId / refId 跳转处理。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| scope | Query | String | ❌ | mine / all,默认 mine | 待办范围 |
| departDateFrom | Query | LocalDate | ❌ | yyyy-MM-dd;默认今天 | 出发日期起(含) |
| departDateTo | Query | LocalDate | ❌ | yyyy-MM-dd;默认起始日 +30 天;跨度 ≤92 天 | 出发日期止(含) |
出参 Result<HouseConsoleAuditRespVO>
| 字段 | 类型 | 说明 |
|---|---|---|
| issues | List | 数据不一致问题 |
| tasks | List | 待处理事项 |
| (Item)code | String | 问题码或待办码,见「六.5 枚举」 |
| (Item)codeLabel | String | 问题中文,前端直接展示 |
| (Item)taskCode | String | 待办码,仅 tasks 有值(与 code 相同) |
| (Item)orderId | Long(String) | 订单 ID |
| (Item)teamNo | String | 订单团号 |
| (Item)groupBatchId | Long(String) | 团期 ID |
| (Item)batchNo | String | 团期批次号 |
| (Item)stayDate | LocalDate | 入住晚 |
| (Item)hotelId / hotelName | Long(String) / String | 酒店 |
| (Item)roomTypeId / roomTypeName | Long(String) / String | 房型 |
| (Item)refId | Long(String) | 关联单据 ID(转房行 / 改配记录),用于跳转 |
| (Item)detail | String | 说明文字 |
请求示例
GET /v3/admin/order/house-console/audit?scope=mine&departDateFrom=2026-10-01&departDateTo=2026-10-31
响应示例
{
"code": 200,
"message": "成功",
"data": {
"issues": [
{ "code": "STOCK_LEDGER_MISMATCH", "codeLabel": "库存账不平", "taskCode": null, "orderId": null, "teamNo": null, "groupBatchId": null, "batchNo": null, "stayDate": "2026-10-02", "hotelId": "100001", "hotelName": "海拉尔草原酒店", "roomTypeId": "300001", "roomTypeName": "豪华双床房", "refId": null, "detail": "本地已用 5 间,库存日历已用 3 间" }
],
"tasks": [
{ "code": "TRANSFER_PENDING", "codeLabel": "退团房未结清", "taskCode": "TRANSFER_PENDING", "orderId": "1930000000000000001", "teamNo": "HL20261001A", "groupBatchId": null, "batchNo": null, "stayDate": "2026-10-02", "hotelId": "100001", "hotelName": "海拉尔草原酒店", "roomTypeId": "300001", "roomTypeName": "豪华双床房", "refId": "1950000000000000001", "detail": "剩余 2 间待处理" }
]
},
"success": true
}
空数据 / 降级响应
{ "code": 200, "message": "成功", "data": { "issues": [], "tasks": [] }, "success": true }
错误响应
{
"code": 808313,
"message": "日期跨度不能超过 92 天",
"data": null,
"success": false
}
| code | message | 触发 |
|---|---|---|
| 400 | scope 取值非法 | scope 不是 mine / all |
| 808090 | 未登录或非房务角色,无权操作 | 非房务角色 |
| 808313 | 日期跨度不能超过 92 天 | 出发日期跨度超 92 天 |
业务边界
scope只作用于tasks:mine 只列当前登录人持有的订单 / 团期的待办;issues不受 scope 影响,始终是区间内全部。STOCK_LEDGER_MISMATCH(库存账不平)只在 resource 全局库存追踪开关打开时检查;开关关闭时不会产出该问题码。- 纯读接口,不写数据。
13. 住宿模板列表 GET /v3/admin/order/house-console/stay-templates
VO: String keyword → List<HouseStayTemplateSimpleRespVO>
使用场景
控制台「住宿模板」页签,以及配房时「从模板带入」的下拉列表。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| keyword | Query | String | ❌ | - | 模板名称模糊匹配 |
出参 Result<List<HouseStayTemplateSimpleRespVO>>
| 字段 | 类型 | 说明 |
|---|---|---|
| id | Long(String) | 模板 ID |
| name | String | 模板名称 |
| creatorName | String | 创建人姓名;房务名单里查不到时为 null |
| nightCount | Integer | 晚数 |
| createTime | LocalDateTime | 创建时间 |
请求示例
GET /v3/admin/order/house-console/stay-templates?keyword=海拉尔
响应示例
{
"code": 200,
"message": "成功",
"data": [
{ "id": "1839000000000000001", "name": "海拉尔 3 晚标准", "creatorName": "张三", "nightCount": 3, "createTime": "2026-09-28 10:00:00" }
],
"success": true
}
空数据 / 降级响应
{ "code": 200, "message": "成功", "data": [], "success": true }
房务名单取不到时列表照常返回,creatorName 为 null。
错误响应
{
"code": 808090,
"message": "未登录或非房务角色,无权操作",
"data": null,
"success": false
}
业务边界
- 返回全部创建人的模板(不是只看自己的),按创建时间倒序,不分页。
- 已删除的模板不返回。
- 纯读接口,不写数据。
14. 住宿模板详情 GET /v3/admin/order/house-console/stay-templates/{id}
VO: Long id → HouseStayTemplateRespVO
使用场景
打开模板编辑,或配房时选中模板后取出逐晚明细带入。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| id | Path | Long | ✅ | - | 模板 ID |
出参 Result<HouseStayTemplateRespVO>
| 字段 | 类型 | 说明 |
|---|---|---|
| id | Long(String) | 模板 ID |
| name | String | 模板名称 |
| creatorId | Long(String) | 创建人 ID(前端据此判断是否显示改 / 删) |
| creatorName | String | 创建人姓名 |
| createTime | LocalDateTime | 创建时间 |
| nights | List | 逐晚安排 |
| nights[].day | Integer | 第几晚,从 1 起 |
| nights[].cityName | String | 城市名 |
| nights[].hotelId / hotelName | Long(String) / String | 酒店 |
| nights[].settleType | String | 结算方式编码(字典 resource_settle_type),可空 |
| nights[].settleTypeLabel | String | ���算方式名称;为空时为「待确认」 |
| nights[].rooms | List | 房型明细 |
| nights[].rooms[].roomTypeId / roomTypeName | Long(String) / String | 房型 |
| nights[].rooms[].roomCount | Integer | 间数 |
| nights[].rooms[].price | String | 单价(元) |
| nights[].rooms[].breakfast | String | INCLUDED / EXCLUDED / PENDING |
| nights[].rooms[].breakfastLabel | String | 早餐显示名 |
请求示例
GET /v3/admin/order/house-console/stay-templates/1839000000000000001
响应示例
{
"code": 200,
"message": "成功",
"data": {
"id": "1839000000000000001",
"name": "海拉尔 3 晚标准",
"creatorId": "30001",
"creatorName": "张三",
"createTime": "2026-09-28 10:00:00",
"nights": [
{
"day": 1, "cityName": "海拉尔", "hotelId": "100001", "hotelName": "海拉尔草原酒店",
"settleType": null, "settleTypeLabel": "待确认",
"rooms": [
{ "roomTypeId": "300001", "roomTypeName": "豪华双床房", "roomCount": 5, "price": "320.00", "breakfast": "INCLUDED", "breakfastLabel": "含早餐" }
]
}
]
},
"success": true
}
空数据 / 降级响应
模板不存在或已删除时不返回空对象,返回 808351。
错误响应
{
"code": 808351,
"message": "模板不存在",
"data": null,
"success": false
}
| code | message | 触发 |
|---|---|---|
| 808090 | 未登录或非房务角色,无权操作 | 非房务角色 |
| 808351 | 模板不存在 | id 不存在或已删除 |
业务边界
- 任何房务都可查看任何人的模板;改 / 删权限见接口 15 / 16。
settleTypeLabel由服务端按字典翻译,字典查不到时回退为原编码。
15. 住宿模板保存 POST /v3/admin/order/house-console/stay-templates
VO: HouseStayTemplateSaveReqVO → Result<Long>
使用场景
「住宿模板」页签新建或编辑模板后保存。id 为空表示新建,有值表示修改该模板。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| id | Body | Long | ❌ | - | 模板 ID;为空表示新建 |
| name | Body | String | ✅ | 1~50 字,服务端去首尾空格 | 模板名称,未删除模板中唯一 |
| nights | Body | List | ✅ | 1~30 晚 | 逐晚安排 |
| nights[].day | Body | Integer | ✅ | 1~30 | 第几晚 |
| nights[].cityName | Body | String | ❌ | ≤32 字 | 城市名 |
| nights[].hotelId | Body | Long | ❌ | - | 酒店 ID |
| nights[].hotelName | Body | String | ❌ | ≤100 字 | 酒店名 |
| nights[].settleType | Body | String | ❌ | ≤32 字 | 结算方式编码(字典 resource_settle_type),空为待确认 |
| nights[].rooms | Body | List | ✅ | 每晚 1~10 行 | 房型明细 |
| nights[].rooms[].roomTypeId | Body | Long | ❌ | - | 房型 ID |
| nights[].rooms[].roomTypeName | Body | String | ❌ | ≤100 字 | 房型名 |
| nights[].rooms[].roomCount | Body | Integer | ✅ | 1~500 | 间数 |
| nights[].rooms[].price | Body | BigDecimal | ❌ | ≥0,最多 2 位小数 | 单价(元) |
| nights[].rooms[].breakfast | Body | String | ❌ | INCLUDED / EXCLUDED / PENDING | 早餐 |
出参 Result<Long>
| 字段 | 类型 | 说明 |
|---|---|---|
| data | Long | 模板 ID(新建时为新 ID,修改时为原 ID) |
请求示例
{
"id": null,
"name": "海拉尔 3 晚标准",
"nights": [
{
"day": 1,
"cityName": "海拉尔",
"hotelId": 100001,
"hotelName": "海拉尔草原酒店",
"settleType": null,
"rooms": [
{ "roomTypeId": 300001, "roomTypeName": "豪华双床房", "roomCount": 5, "price": "320.00", "breakfast": "INCLUDED" }
]
}
]
}
响应示例
{
"code": 200,
"message": "成功",
"data": "1839000000000000001",
"success": true
}
空数据 / 降级响应
本接口无列表数据;失败时模板不变(新建则不产生记录)。
错误响应
{
"code": 808352,
"message": "只能修改或删除自己创建的模板",
"data": null,
"success": false
}
| code | message | 触发 |
|---|---|---|
| 400 | name 不能为空 / name 不能超过 50 字 / nights 不能为空 / nights 不能超过 30 晚 / day 不能为空 / day 从 1 起 / day 不能超过 30 / cityName 不能超过 32 字 / hotelName 不能超过 100 字 / settleType 不能超过 32 字 / rooms 不能为空 / 每晚 rooms 不能超过 10 行 / roomTypeName 不能超过 100 字 / roomCount 不能为空 / roomCount 至少 1 / roomCount 不能超过 500 / price 不能小于 0 / price 最多 2 位小数 / breakfast 只能是 INCLUDED / EXCLUDED / PENDING | 入参校验 |
| 808090 | 未登录或非房务角色,无权操作 | 非房务角色 |
| 808350 | 模板名称已存在 | 与未删除模板重名(去首尾空格后比较) |
| 808351 | 模板不存在 | 修改时 id 不存在或已删除 |
| 808352 | 只能修改或删除自己创建的模板 | 修改他人创建的模板且当前登录人不是超管 |
| 100502 | 模板保存处理中,请勿重复提交 | 3 秒内重复提交 |
业务边界
- 修改只允许创建人本人或超管。
- 名称唯一只在未删除模板中判断,已删除模板的名称可以复用。
- 修改是整份覆盖:
nights以本次提交为准。
16. 住宿模板删除 DELETE /v3/admin/order/house-console/stay-templates/{id}
VO: Long id → Result<Void>
使用场景
「住宿模板」页签删除一个模板。前端可按详情里的 creatorId 与当前登录人比对决定是否展示删除按钮,服务端仍会校验。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| id | Path | Long | ✅ | - | 模板 ID |
出参 Result<Void>
| 字段 | 类型 | 说明 |
|---|---|---|
| data | null | 成功无返回体 |
请求示例
DELETE /v3/admin/order/house-console/stay-templates/1839000000000000001
响应示例
{
"code": 200,
"message": "成功",
"data": null,
"success": true
}
空数据 / 降级响应
成功时 data 恒为 null;删除的是软删,列表与详情不再返回该模板。
错误响应
{
"code": 808352,
"message": "只能修改或删除自己创建的模板",
"data": null,
"success": false
}
| code | message | 触发 |
|---|---|---|
| 808090 | 未登录或非房务角色,无权操作 | 非房务角色 |
| 808351 | 模板不存在 | id 不存在或已删除 |
| 808352 | 只能修改或删除自己创建的模板 | 删除他人创建的模板且当前登录人不是超管 |
业务边界
- 只允许创建人本人或超管删除。
- 软删;删除后该名称可被新模板复用。
- 已删除的模板再次删除返回 808351。
17. 团期转交 POST /v3/admin/order/grab-pool/group-batches/{groupBatchId}/transfer
VO: HouseGroupTransferReqVO → Result<Void>
使用场景
团期持有人(或超管)把已整团认领的团期交给另一名房务,例如持有人休假。控制台团期视图(通知链接 /housekeeper/console?groupBatchId={groupBatchId})上的「转交」按钮调用。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| groupBatchId | Path | Long | ✅ | - | 团期 ID |
| toUserId | Body | Long | ✅ | 须是在职房务 | 接收人 userId |
| reason | Body | String | ✅ | 1~200 字 | 转交原因,写入团期时间线 |
出参 Result<Void>
| 字段 | 类型 | 说明 |
|---|---|---|
| data | null | 成功无返回体 |
请求示例
{
"toUserId": 30002,
"reason": "本人休假,团期交给同组房务跟进"
}
响应示例
{
"code": 200,
"message": "成功",
"data": null,
"success": true
}
空数据 / 降级响应
房务人员名单取不到时不降级放行,直接返回 808343,团期持有人不变。
错误响应
{
"code": 808343,
"message": "房务人员名单暂不可用,请稍后重试",
"data": null,
"success": false
}
| code | message | 触发 |
|---|---|---|
| 400 | toUserId 不能为空 / reason 不能为空 / reason 长度不能超过 200 字 | 入参校验 |
| 808090 | 未登录或非房务角色,无权操作 | 非房务角色 |
| 589500 | 团期不存在 | groupBatchId 不存在 |
| 808340 | 只有团期当前处理人可以转交 | 团期未被认领;或当前登录人不是持有人且不是超管;或并发下持有人已变 |
| 808341 | 不能转交给自己 | toUserId 等于当前持有人或当前登录人 |
| 808343 | 房务人员名单暂不可用,请稍后重试 | 房务人员名单取不到(异常 / 空) |
| 808342 | 接收人不是房务 | 名单里没有 toUserId |
| 808659 | 该团有 {0} 户存在逐户配房(首个订单 {1}),请先删除配房后再操作 | 团内有户存在有效的逐户配房 |
| 100502 | 团期转交处理中,请勿重复提交 | 5 秒内重复提交 |
业务边界
- 持有人本人或超管可转交;超管可转交任何已被认领的团期。
reason必填,与户级转单(超管 ≥10 字、普通房务可选)规则不同。- 名单取不到一律拒绝(808343);只有超管「整团接管」(
POST /v3/admin/order/grab-pool/group-batches/{groupBatchId}/takeover)在名单取不到时仍放行,接收人姓名显示占位user-{id}。 - 名单里有接收人、但其姓名为空时,时间线里显示
user-{id}。 - 只换持有人:订房计划与分房不变。团期时间线记一条「团期转交:A → B(原因)」,事务提交后通知接收人。
四、契约约束与正确调用方式(接口类必写)
本节只写后端接受/拒绝 payload 的规则,不写 UI 渲染建议。
✅ 正确 / ❌ 错误 payload 对照
| 场景 | payload |
|---|---|
| ✅ 批量认领只认领需求 | { "requirementIds": [1840000000000000001] } |
| ❌ 批量认领两个列表都空 | { "requirementIds": [], "groupBatchIds": [] } → 400 请选择 1~50 条待认领记录 |
| ✅ 转入订单需求 | { "targetType": "ORDER", "targetRequirementId": 1940000000000000009, "roomCount": 1, "hotelConfirmNo": "HX1", "proofFileIds": [1] } |
| ❌ 转入团期却只给需求 ID | { "targetType": "GROUP_BATCH", "targetRequirementId": 1940000000000000009, "roomCount": 1, "hotelConfirmNo": "HX1", "proofFileIds": [1] } → 808322 目标不可转入:未指定转入目标 |
| ❌ 转房不带凭证 | { "targetType": "ORDER", "targetRequirementId": 1940000000000000009, "roomCount": 1, "hotelConfirmNo": "HX1" } → 808325 |
| ✅ 清除退团房期限 | { "cancelDays": null } |
| ❌ 期限天数越界 | { "cancelDays": 61 } → 808328(不是 400) |
| ✅ 只改结算价 | { "hotelId": 100001, "roomTypeId": 300001, "dateFrom": "2026-10-01", "dateTo": "2026-10-07", "settlementPrice": "300.00" } |
| ❌ 调价两个价格都不传 | { "hotelId": 100001, "roomTypeId": 300001, "dateFrom": "2026-10-01", "dateTo": "2026-10-07" } → 808314 |
| ❌ 调房量不带已用期望值 | { "hotelId": 100001, "roomTypeId": 300001, "stayDate": "2026-10-01", "totalRooms": 15 } → 400 expectedUsedRooms 不能为空 |
| ❌ 团期转交不写原因 | { "toUserId": 30002 } → 400 reason 不能为空 |
切换状态时的必要动作
- 转房
targetType切换时,把另一个目标 ID 字段置 null;服务端只读与targetType对应的那个字段。 - 调房量提交的
expectedUsedRooms必须取自最近一次查询该格的usedRooms;收到 808311 后先重新查询再提交。 - 控房表查询用城市编码,退团房列表用城市中文名,两个筛选框的取值来源不同。
- 下载导出文件前按响应
Content-Type判断:xlsx 为文件,application/json为错误Result。
五、数据库行为(涉及写操作时必写)
| 前端提交 | 写入位置 | 行为 |
|---|---|---|
| 改配原订取消确认 | house_assignment_change |
该记录 HELD → CANCEL_CONFIRMED,覆盖取消费用 / 凭证 / 备注 / 操作人 |
| 批量认领 | 需求与团期的认领字段 | 逐条独立写,失败的条目不写 |
| 调房量 | resource 价格日历的库存列 | 按已用间数 CAS 更新控房总数 |
| 调价 | resource 价格日历的价格列 | 一次区间写入:已有日历行更新、缺失的补建;未传的价格列不动 |
| 设置期限 | house_room_transfer |
更新 cancel_days / cancel_cutoff / remind_days |
| 转房 | house_room_transfer、目标配房或团期计划、源配房或源团期计划 |
同一事务:父行扣剩余、写目标、扣源、写子行与日志;任一步失败整笔回滚 |
| 向酒店取消 | house_room_transfer |
父行置 CANCELLED、cancel_reason=HOTEL_CANCELLED |
| 模板保存 / 删除 | house_stay_template |
新建 / 整份覆盖;删除为软删 |
| 团期转交 | 团期认领字段、团期时间线 | CAS 换持有人,写时间线;计划与分房不动 |
显式 SET NULL 说明: 设置期限时 cancelDays 传 null 只把免费退改天数清空,截止时刻与提醒天数保留该行原值(两列非空),deadlineAt 随之为 null(#8597 订正);其余写接口未传的可选字段保持原值,不会被写成 null。
六、边界行为
- 已登录但不是房务角色(ROOM_MANAGER / SUPER_ADMIN 以外)→ 808090「未登录或非房务角色,无权操作」;原「房务组长」角色已取消,该类账号同样返回 808090。
- 写接口统一经房务写守卫;只读接口经房务读守卫,两者都只认房务角色。
- 资源不存在 → 各接口的业务码(808320 / 808332 / 808351 / 589500),HTTP 200。
- resource 服务不可用 → 控房表相关接口返回 808900「资源服务暂不可用,请稍后重试」,不返回空表冒充无数据。
- 所有写接口带防重(3 秒,团期转交 5 秒);重复提交返回 100502 与各接口自己的提示文案。
- 并发写冲突 → 808932「房务状态已被并发修改,请刷新后重试」或 808311 / 808608(见各接口)。
六.5、枚举 / 数据字典(接口出现枚举时必写)
oldStatus(HouseAssignmentChangeConstants)
所属字段: HouseAssignmentChangeRespVO.oldStatus / 类型: String
| 值 | 中文 | 说明 |
|---|---|---|
HELD |
原酒店待取消 | 改配后原酒店还没取消,可调接口 1 确认 |
CANCEL_CONFIRMED |
已确认取消 | 已上传取消凭证 |
changeKind(HouseAssignmentChangeConstants)
所属字段: HouseAssignmentChangeRespVO.changeKind / 类型: String
| 值 | 中文 | 说明 |
|---|---|---|
HOTEL |
换酒店 | 配房行换了酒店 |
ROOM_COUNT |
减间数 | 配房行间数减少 |
status(退团房行状态)
所属字段: HouseRoomTransferRespVO.status、HouseRoomTransferPageReqVO.status / 类型: String
| 值 | 中文 | 说明 |
|---|---|---|
PENDING |
待处理 | 还有剩余间数没转出也没取消 |
TRANSFERRED |
已转出 | 剩余间数已全部转出 |
CANCELLED |
已取消 | 已向酒店取消 |
risk(退团房风险)
所属字段: HouseRoomTransferRespVO.risk、HouseRoomTransferPageReqVO.risk / 类型: String
| 值 | 中文 | 说明 |
|---|---|---|
OVERDUE |
已过免费取消期 | 现在已过截止时刻(入住晚 − cancelDays 天的 cancelCutoff) |
NEAR |
临近免费取消期 | 今天 ≥ 截止日 − remindDays 天(按日比较) |
NO_DEADLINE |
未设免费取消期 | cancelDays 为空 |
NORMAL |
正常 | 其余 |
cancelReason(HouseRoomTransferCancelReason)
所属字段: HouseRoomTransferRespVO.cancelReason / 类型: String
| 值 | 中文 | 说明 |
|---|---|---|
HOTEL_CANCELLED |
- | 接口 11 写入;该值在代码里没有对应的中文标签,展示时请用行上的 statusLabel(已取消) |
sourceType / targetType(退团房来源与目标类型)
所属字段: HouseRoomTransferRespVO.sourceType、targetType,HouseRoomTransferSaveReqVO.targetType,HouseRoomTransferCandidateRespVO.targetType / 类型: String
| 值 | 中文 | 说明 |
|---|---|---|
ORDER |
订单 | 常规单或团期户的订单需求 |
GROUP_BATCH |
团期 | 团期整团 |
ineligibleReason / 808322 参数(转入不可用原因)
所属字段: HouseRoomTransferCandidateRespVO.ineligibleReason、808322 文案 {0} / 类型: String
| 值 | 中文 | 说明 |
|---|---|---|
团期已确认 |
团期已确认 | 候选原因 |
需求已失效 |
需求已失效 | 候选原因 |
需求改版中 |
需求改版中 | 候选原因 |
该晚已配满 |
该晚已配满 | 候选原因 |
无团号 |
无团号 | 候选原因,也是 808322 参数 |
该晚已有同酒店同房型 |
该晚已有同酒店同房型 | 候选原因,也是 808322 参数 |
未指定转入目标 |
未指定转入目标 | 808322 参数 |
目标不存在 |
目标不存在 | 808322 参数 |
团期户请转入所在团期 |
团期户请转入所在团期 | 808322 参数 |
不同城 |
不同城 | 808322 参数 |
目标当晚无住宿 |
目标当晚无住宿 | 808322 参数 |
目标当晚已有控房 |
目标当晚已有控房 | 808322 参数 |
不能转回原团期/原需求 |
不能转回原团期/原需求 | 808322 参数 |
批量认领 targetType
所属字段: HouseConsoleBatchClaimRespVO.items[].targetType / 类型: String
| 值 | 中文 | 说明 |
|---|---|---|
REQUIREMENT |
常规单住宿需求 | 来自 requirementIds |
GROUP_BATCH |
团期 | 来自 groupBatchIds |
audit code(异常检查问题码与待办码)
所属字段: HouseConsoleAuditRespVO.Item.code / taskCode / 类型: String
| 值 | 中文 | 说明 |
|---|---|---|
STOCK_OVERBOOKED |
超分配 | issues;已分配超过库存 |
STOCK_LEDGER_MISMATCH |
库存账不平 | issues;本地已用与库存日历不一致,仅库存追踪开关打开时检查 |
STOCK_ROW_MISSING |
库存日历缺行 | issues |
TRANSFER_TARGET_GONE |
转房目标失效 | issues |
PLAN_COUNT_MISMATCH |
计划数量不符 | issues |
TRANSFER_PENDING |
退团房未结清 | tasks |
HOTEL_CANCEL_PENDING |
原酒店待取消 | tasks;对应 HELD 改配记录 |
INQUIRY_PENDING |
新订/变更待确认 | tasks |
STAY_UNARRANGED |
住宿待落实 | tasks |
breakfast(HouseBreakfast)
所属字段: HouseStayTemplateSaveReqVO.nights[].rooms[].breakfast、HouseStayTemplateRespVO.nights[].rooms[].breakfast / 类型: String
| 值 | 中文 | 说明 |
|---|---|---|
INCLUDED |
含早餐 | - |
EXCLUDED |
不含早餐 | - |
PENDING |
早餐待确认 | 未填时按此输出 |
roomSource(HouseRoomSource)
所属字段: HouseRoomControlRowRespVO.usages[].roomSource / 类型: String
| 值 | 中文 | 说明 |
|---|---|---|
STOCK |
控房 | 控房表只列扣库存的行,本表恒为此值 |
settleType(字典 resource_settle_type)
所属字段: HouseStayTemplateRespVO.nights[].settleType / 类型: String
| 值 | 中文 | 说明 |
|---|---|---|
| 空 | 待确认 | settleTypeLabel 输出「待确认」 |
| 字典编码 | 字典名称 | 字典查不到时 settleTypeLabel 回退为原编码 |
错误码段 808300~808399(HouseConsoleErrorCode)
所属字段: Result.code / 类型: Integer
| 值 | 中文 | 说明 |
|---|---|---|
808310 |
总房量不能小于已占用 {0} 间 | 调房量;{0} 为已用间数 |
808311 |
已占用数已变化,请刷新后重试 | 调房量 CAS 失败 |
808312 |
库存追踪未开启,暂不能调整房量 | 调房量;resource 全局开关关闭 |
808313 |
日期跨度不能超过 {0} 天 | 控房表 62 天;异常检查 92 天 |
808314 |
协议价与结算价至少填写一项 | 调价 |
808320 |
转房记录不存在 | 退团房 |
808321 |
该房间已处理 | 退团房行已不是 PENDING |
808322 |
目标不可转入:{0} | 转房;{0} 见上表 |
808323 |
目标团期已确认,不能转入 | 转房;源团期已确认时也返回本码 |
808324 |
转出间数超过剩余 {0} 间 | 转房;{0} 为此刻可转间数 |
808325 |
请填写酒店确认号并上传凭证 | 转房 / 向酒店取消 |
808326 |
只有原单处理人可以处理退团房间 | 退团房写操作 |
808328 |
退改期限参数不合法 | 设置期限 |
808330 |
查询范围过大,请缩小酒店或日期范围 | 控房表查询 / 导出 |
808332 |
变更记录不存在 | 改配取消确认 |
808333 |
原订已确认取消 | 改配取消确认 |
808340 |
只有团期当前处理人可以转交 | 团期转交 |
808341 |
不能转交给自己 | 团期转交 |
808342 |
接收人不是房务 | 团期转交 |
808343 |
房务人员名单暂不可用,请稍后重试 | 团期转交、户级转单、超管指派 |
808350 |
模板名称已存在 | 模板保存 |
808351 |
模板不存在 | 模板详情 / 保存 / 删除 |
808352 |
只能修改或删除自己创建的模板 | 模板保存 / 删除 |
808327、808331 未使用。
resource 错误码映射(HouseResourceErrorTranslator)
所属字段: Result.code / 类型: Integer
控房表接口调用 resource 时,resource 返回的 3104xx 在本服务翻译成 8083xx 后返回,前端只会看到右侧的码。
| 值 | 中文 | 说明 |
|---|---|---|
310421 |
映射为 808313 | 参数固定为 62 |
310422 |
映射为 808330 | - |
310423 |
映射为 808312 | - |
310424 |
映射为 808310 | 参数为已用间数,取不到时为「?」 |
310425 |
映射为 808311 | - |
| 其他 3104xx | 原样透传 | 例如 310426「房型 {0} 不属于酒店 {1}」 |
| 返回为空 | 映射为 808900 | 资源服务暂不可用,请稍后重试 |
七、不影响范围(显式声明, 帮前端/QA 缩小排查面)
- 仅影响: 管理后台「房务控制台」菜单各页签;团期抢单池新增「转交」动作。
- 零影响:
- 小程序与 H5
- 已有配房行的价格(调价只作用于之后新生成的配房)
八、测试环境已验证
所有接口都经测试服网关调用。HTTP 状态恒为 200,下面的 code 指响应 body 里的 code,带 ✓ 标记。行尾 @ 后面是当时测试服 order-v3 的部署提交。bdde64a3a、9c7ac9382、ff6863754、3ecf38797 四个提交都包含本单合并提交 7c21cf0e40。控房表相关接口另依赖 resource 部署提交 bdde64a3a,测试服已开 hotel.stock.enabled=true。
PUT /v3/admin/order/house-console/changes/{changeId}/cancel-confirm HELD 改配记录,带 1 个凭证 + cancelFee=200.00 → code=200,oldStatus HELD→CANCEL_CONFIRMED,cancelFee="200.00" ✓ @bdde64a3a
PUT /v3/admin/order/house-console/changes/{changeId}/cancel-confirm 同一条再确认一次 → code=808333「原订已确认取消」 ✓ @bdde64a3a
POST /v3/admin/order/house-console/claims/batch 2 条待认领 + 1 条已被他人认领 → code=200,successCount=2、failCount=1,失败项 errorCode=808001;成功两条的认领人为本人 ✓ @bdde64a3a
GET /v3/admin/order/house-console/room-control 某晚已有 2 间控房配房 → code=200,usedRooms=2、assignedRooms=2、totalRooms=15、remainRooms=13 ✓ @9c7ac9382
PUT /v3/admin/order/house-console/room-control/stock totalRooms=1(小于已占用 2) → code=808310 ✓ @9c7ac9382
PUT /v3/admin/order/house-console/room-control/stock expectedUsedRooms=1(实际已占用 2) → code=808311 ✓ @9c7ac9382
PUT /v3/admin/order/house-console/room-control/stock totalRooms=5 + expectedUsedRooms=2 → code=200;控房表该行 totalRooms 15→5、remainRooms 13→3 ✓ @9c7ac9382
PUT /v3/admin/order/house-console/room-control/price protocolPrice / settlementPrice 620.00 / 615.00 → 680.00 / 675.00 → code=200;之后新提交的同酒店同房型同晚配房行快照 680.00 / 675.00,调价前已有的行仍是 620.00 / 615.00 ✓ @9c7ac9382
GET /v3/admin/order/house-console/room-control/export 导出 → 响应为 xlsx 文件(非 JSON 包装);sheet「每日房量」表头 酒店 / 入住夜日期 / 房型 / 控房总数 / 已用 / 剩余,sheet「团组用房」表头 酒店 / 入住夜日期 / 房型 / 团号 / 房源 / 用房间数 / 确认状态,全文无价格列 ✓ @9c7ac9382
GET /v3/admin/order/house-console/room-transfers 取消一张已确认常规订单(1 行非控房 2 间 + 1 行控房) → code=200,新增 1 行 PENDING、roomCount=2,控房行不出现 ✓ @bdde64a3a,重建夹具复测同样读数 ✓ @ff6863754
GET /v3/admin/order/house-console/room-transfers 同一取消命令重放(返回 581017 订单已取消) → 行数仍为 1 ✓ @bdde64a3a
GET /v3/admin/order/house-console/room-transfers RESOURCE_PREPARING 团期里一户出行前取消 → code=200,新增 1 行 PENDING、sourceType=GROUP_BATCH、roomCount=2 ✓ @3ecf38797
GET /v3/admin/order/house-console/room-transfers 整行转出后 → 该行 status=TRANSFERRED、remainingCount=0、标签「已转出」 ✓ @3ecf38797
PUT /v3/admin/order/house-console/room-transfers/{id}/deadline cancelDays=3 → code=200,分页该行 risk=OVERDUE ✓ @9c7ac9382,复测 ✓ @ff6863754
PUT /v3/admin/order/house-console/room-transfers/{id}/deadline cancelDays=0、remindDays=1 → code=200,risk=NEAR ✓ @9c7ac9382,复测 ✓ @ff6863754
PUT /v3/admin/order/house-console/room-transfers/{id}/deadline cancelDays=null(清空) → code=200,库里 cancel_days 为 NULL(cancel_cutoff / remind_days 保留原值),risk=NO_DEADLINE ✓ @ff6863754
GET /v3/admin/order/house-console/room-transfers/{id}/candidates 同城同晚有 RESOURCE_PREPARING 团期 → code=200,该团 eligible=true、needRoomCount=4 ✓ @3ecf38797
GET /v3/admin/order/house-console/room-transfers/{id}/candidates 同城同晚有房务 B 处理的订单 → 该单 eligible=true,holderName 为房务 B 的姓名 ✓ @ff6863754
GET /v3/admin/order/house-console/room-transfers/{id}/candidates 团期该晚 needRoomCount=0 → eligible=false,ineligibleReason「该晚已配满」 ✓ @ff6863754
GET /v3/admin/order/house-console/room-transfers/{id}/candidates 已确认团期 → eligible=false、ineligibleReason「团期已确认」:测试服未单独调用,由 HouseRoomTransferQueryManagerTest#candidates_confirmedGroup_listedLastAsIneligibleWithReason 覆盖
POST /v3/admin/order/house-console/room-transfers/{id}/transfer 转入团期,不带 hotelConfirmNo → code=808325「请填写酒店确认号并上传凭证」 ✓ @3ecf38797
POST /v3/admin/order/house-console/room-transfers/{id}/transfer 转入 RESOURCE_PREPARING 团期,带齐确认号与凭证、整行 2 间 → code=200,源行 TRANSFERRED、remainingCount 2→0;该团该晚新增 1 行 2 间计划行(不扣控房、已确认);源订单该晚配房行被软删 ✓ @3ecf38797
POST /v3/admin/order/house-console/room-transfers/{id}/transfer 转入房务 B 处理的订单 → code=200,目标配房行 confirmStatus=CONFIRMED;房务 B 站内信新增 HOUSE_ROOM_TRANSFERRED「退团房间已转入:<目标团号>」 ✓ @ff6863754
POST /v3/admin/order/house-console/room-transfers/{id}/transfer 非源单处理人(房务 C)调用 → code=808326「只有原单处理人可以处理退团房间」 ✓ @ff6863754
POST /v3/admin/order/house-console/room-transfers/{id}/transfer 部分转入 roomCount=1 → code=200,源行 remainingCount 2→1,仍为 PENDING ✓ @ff6863754
POST /v3/admin/order/house-console/room-transfers/{id}/transfer 转入已确认团期 → 808323:测试服未单独调用,由 HouseRoomTransferManagerTest#transfer_recheck7GroupNoLongerWritable_throws808323 覆盖
POST /v3/admin/order/house-console/room-transfers/{id}/cancel-hotel 不带凭证 → code=808325 ✓ @9c7ac9382
POST /v3/admin/order/house-console/room-transfers/{id}/cancel-hotel 带凭证(真实 OSS 上传) → code=200,该行 PENDING→CANCELLED,cancel_fee=0.00 ✓ @9c7ac9382
GET /v3/admin/order/house-console/audit 有 HELD 改配记录、尚未确认取消 → code=200,tasks 含 HOTEL_CANCEL_PENDING「原酒店待取消」 ✓ @bdde64a3a
GET /v3/admin/order/house-console/audit 源订单已取消、退团房行 PENDING,窗口覆盖出发日 → code=200,tasks 含 TRANSFER_PENDING「退团房未结清」 ✓ @ff6863754
GET /v3/admin/order/house-console/audit issues 各类(超分配 / 账不平)正反例:开关打开时正常流程造不出超分配,测试服未单独造,由 HouseConsoleAuditManagerTest#audit_assignedAboveStockPlusUsed_reportsOverbooked 等逐类覆盖
GET /v3/admin/order/house-console/stay-templates 新建后按关键字查 → code=200,列表含新模板 ✓ @bdde64a3a,复测 ✓ @9c7ac9382
GET /v3/admin/order/house-console/stay-templates/{id} 测试服未单独调用,由 HouseStayTemplateServiceTest#get_roundTripNights_withLabelsAndPriceString 覆盖
POST /v3/admin/order/house-console/stay-templates 新建 → code=200 ✓;同名再建 → code=808350「模板名称已存在」 ✓ @bdde64a3a,复测 ✓ @9c7ac9382
DELETE /v3/admin/order/house-console/stay-templates/{id} 非创建人(房务 A)删除 → code=808352「只能修改或删除自己创建的模板」 ✓;创建人(超管测试账号)删除 → code=200 ✓ @bdde64a3a,复测 ✓ @9c7ac9382
POST /v3/admin/order/grab-pool/group-batches/{groupBatchId}/transfer 持有人转给另一房务(团里已有 1 行计划) → code=200;团期配房列表 houseClaimerName 变为接收人,计划行数 1→1 ✓ @9c7ac9382
POST /v3/admin/order/grab-pool/group-batches/{groupBatchId}/transfer 非持有人(房务 C)调用 → code=808340「只有团期当前处理人可以转交」 ✓ @9c7ac9382
验证身份:房务 A / B / C、测试定制师、超管测试账号,全部是测试专用账号。落库读数来自测试服只读 SQL。
十、相关文档
- 关联 Issue: wx/HL#8491
- 契约文档:
docs/order-v3/api/API-SPEC-HOUSE-V1.1.html§12 接口、§11.12 错误码 - 同批变更: 同目录
30_8491_房务配房接口字段与口径调整-修改接口-管理后台.md、30_8491_房务旧列表接口下线-删除接口-管理后台.md
关联 / 联系人
链接
- Issue: #8491
联系人
- 后端负责人: @wx