--- schema: "hl-changelog/v2" ticket: "8597" title: "退团房清空免费退改期限:截止时刻与提醒天数保留原值(订正 #8491 交接件三处表述),异常检查补回源单已取消的退团房待办" consumer: "admin" author: "wx(GIT)" change_type: "修改接口" backend_status: "deployed" gateway_status: "not_required" frontend_status: "not_required" frontend_owner: "" frontend_ref: "" target_release: "" verified_at: "" status_note: "PR #8599(提交 ff68637542)已合入 dev-v3;测试服 hl-order-service-v3 运行提交 d57498d38、BEHIND 0/N、STATE ok、2026-09-30 05:32:57,ff68637542 是 d57498d381 的祖先。两个端点的路径与方法均未变,网关 /v3/admin/** 路由块已通配,零网关改动。【frontend_status 取 not_required 的依据与限定,2026-09-30 对 hl-ui origin/v2.1 查证】「房务控制台」整个功能域目前在前端**不存在任何代码**:house-console / houseConsole / 退团房 / room-transfer 等 9 个中英文关键词在 src/ 下全部 0 命中(阳性对照:同为房务域的 house-allocation 在 src/api/housekeeper/ 与 src/views/housekeeper/ 均有活跃文件,故检索有分辨力)。因此这里的 not_required 含义是「没有可改的前端代码」,不是「改动对现有页面透明」——本条是 #8491『房务控制台接口』(frontend_status: pending,17 个新增端点)的后续订正,待该模块被前端认领落地时,本条的口径需与它一并核对,勿据本条认为这块功能已可用。" updated_at: "2026-09-30" base: "dev-v3" --- # 房务控制台: 退团房期限清空口径订正 + 异常检查退团房待办补全 > **存放目录**: 二期 → `changelogs-v2/2026-09/` > > **服务**: hl-order-service-v3 > **Issue**: #8597 > **PR**: #8599 > **日期**: 2026-09-30 > **影响范围**: 管理后台「房务控制台」的「退团房」页签(设期限弹窗)与「异常检查」页签(待办列表) --- ## ⚠️ 关键变化(非必须,本版与上版行为不同 / 纠错 / 撤销时必写) - 🔴 **订正 #8491 交接件的三处表述**:`PUT .../room-transfers/{id}/deadline` 传 `cancelDays: null` 清除期限时,**只有 `cancelDays` 变成 `null`,`cancelCutoff` 与 `remindDays` 保留该行原值,不会被置空**。`changelogs-v2/2026-09/30_8491_房务控制台接口-新增接口-管理后台.md` 的第 746、747 行(入参表)、第 787 行(空数据 / 降级响应)、第 1623 行(显式 SET NULL 说明)写的「三列一并清空 / 本字段被忽略、一并清空」与实际行为不符,以本条为准;该文件第 1847 行的测试环境读数(`cancel_cutoff / remind_days 保留原值`)才是正确的那一条。 - 🔴 **判「这一行有没有设免费退改期限」只能看 `cancelDays === null` 或 `risk === "NO_DEADLINE"`**,不能看 `cancelCutoff` / `remindDays` 是否为 `null`——清空后这两个字段仍有值(该行从未设过期限时是建表默认的 `"18:00"` 与 `1`)。 - **清除期限从「必定失败」改为成功**:本次改动前,`cancelDays: null` 的请求 100% 返回 **808932**「房务状态已被并发修改,请刷新后重试」(并非真的并发冲突),现在返回 `code=200` 并给出更新后的整行。 - **异常检查 `tasks[]` 的 `TRANSFER_PENDING` 条目不再漏行**:待处理退团房行的窗口归属改为只看源团期 / 源订单的**出发日**,**不看源单状态**;源单查不到、或源单出发日为空时同样列出。取消订单恰恰是产生退团房最常见的原因,订正前这些待办在控制台唯一的待办载体上看不到。**同一窗口下本端点返回的 `tasks` 行数会比订正前多。** --- ## 一、背景(选填) 退团房行有两处独立缺陷,都发生在「房务控制台」已交付的端点上: 1. 清期限走的乐观锁写口,其入参守卫要求截止时刻与提醒天数非空(两列在库中是 NOT NULL);旧代码在 `cancelDays` 为 `null` 时把这两项也一起传 `null`,守卫直接返回「影响行数 0」,上层把 0 当成版本冲突抛 808932。表现是「清除期限」按钮永远失败,而错误文案指向刷新重试,看不出是入参问题。 2. 异常检查的退团房待办原先用「窗口内的团期集合 / 散单集合」判归属,这两个集合按占用口径排除了已取消的单,于是「订单取消 → 释放房间 → 待转出」这条最常见的链路产出的待办从不出现。 --- ## 二、变更接口清单 | # | 接口 | 方法 | 路径 | 变更类型 | 说明 | |---|------|------|------|----------|------| | 1 | 设置 / 清除退团房免费退改期限 | PUT | `/v3/admin/order/house-console/room-transfers/{id}/deadline` | 修改 | 清除期限由必定失败改为成功;`cancelCutoff` / `remindDays` 保留原值(订正交接件表述) | | 2 | 房务异常检查 | GET | `/v3/admin/order/house-console/audit` | 修改 | `tasks[]` 的 `TRANSFER_PENDING` 按源单出发日归属、不看源单状态,补回源单已取消的行 | --- ## 三、接口详情 ### 1. 设置 / 清除退团房免费退改期限 `PUT /v3/admin/order/house-console/room-transfers/{id}/deadline` **VO**: `HouseRoomTransferDeadlineSaveReqVO → HouseRoomTransferRespVO` #### 使用场景 「退团房」页签某一行点「设期限」,录入酒店给的免费取消规则(入住前几天、当天几点前)与提前几天提醒;也用于把已设的期限清掉。清掉后该行的风险分档变为 `NO_DEADLINE`,前端应按 `cancelDays` 是否为 `null` 渲染「未设免费取消期」,而不是按 `cancelCutoff` / `remindDays` 是否有值判断。 #### 入参 | 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | |------|------|------|------|------|------| | id | Path | Long | ✅ | 必须是退团房**父行**(子行是转出明细,不可改期限);不存在或已删返 808320 | 退团房行 ID | | cancelDays | Body | Integer | ❌ | 0~60,越界返 808328;传 `null` 表示清除期限 | 入住前几天可免费取消 | | cancelCutoff | Body | String | ❌ | `HH:mm` 24 小时制(`00:00`~`23:59`),格式不符返 808328;`cancelDays` 非空而本字段为空 / 空白时取 `18:00`;**`cancelDays` 为 `null` 时本字段被忽略,该行原值保留** | 截止当天的时刻 | | remindDays | Body | Integer | ❌ | 0~30,越界返 808328;`cancelDays` 非空而本字段为空时取 `1`;**`cancelDays` 为 `null` 时本字段被忽略,该行原值保留** | 提前几天提醒 | #### 出参 `Result` | 字段 | 类型 | 说明 | |------|------|------| | (整行) | HouseRoomTransferRespVO | 更新后的该退团房父行,字段与退团房分页 `records[]` 同构 | | cancelDays | Integer | 入住前几天免费取消;**清除期限后为 `null`** | | cancelCutoff | String | 截止当天的时刻 `HH:mm`;**清除期限后仍是该行原值(从未设过则是 `"18:00"`),不会变成 `null`** | | remindDays | Integer | 提前几天提醒;**清除期限后仍是该行原值(从未设过则是 `1`),不会变成 `null`** | | deadlineAt | LocalDateTime | 免费取消截止时刻 = 入住晚 − `cancelDays` 天的 `cancelCutoff`;`cancelDays` 为 `null` 或缺入住晚时为 `null` | | risk | String | 风险码 `OVERDUE` / `NEAR` / `NO_DEADLINE` / `NORMAL`;仅 `PENDING` 行有值,其余为 `null` | | riskLabel | String | 风险中文;`NO_DEADLINE` 对应「未设免费取消期」 | | status / statusLabel | String | 行状态 `PENDING` / `TRANSFERRED` / `CANCELLED` 与中文;本端点只对 `PENDING` 行成功 | | id / sourceOrderId / sourceGroupBatchId / hotelId / roomTypeId | Long(String) | 雪花 ID,JSON 中为字符串 | | teamNo | String | 源订单团号(批量读订单主表团号);取不到为 `null` | | stayDate | LocalDate | 入住晚 | | roomCount / remainingCount | Integer | 原始间数 / 剩余待处理间数 | | readOnly / readOnlyReason | Boolean / String | 对当前操作人是否只读(源单由他人处理)与理由 | #### 请求示例 ```json PUT /v3/admin/order/house-console/room-transfers/1950000000000000001/deadline { "cancelDays": null } ``` #### 响应示例 ```json { "code": 200, "message": "成功", "data": { "id": "1950000000000000001", "sourceType": "ORDER", "sourceOrderId": "1930000000000000001", "teamNo": "HL20261001A", "sourceGroupBatchId": null, "sourceBatchNo": null, "stayDate": "2026-10-02", "cityName": "海拉尔", "hotelId": "100001", "hotelName": "海拉尔草原酒店", "roomTypeId": "300001", "roomTypeName": "豪华双床房", "roomCount": 2, "remainingCount": 2, "status": "PENDING", "statusLabel": "待处理", "cancelDays": null, "cancelCutoff": "18:00", "remindDays": 1, "deadlineAt": null, "risk": "NO_DEADLINE", "riskLabel": "未设免费取消期", "readOnly": false, "readOnlyReason": null }, "success": true } ``` #### 空数据 / 降级响应 - 本端点恒返回整行,没有空响应形态。 - 清除期限(`cancelDays: null`)是正常成功路径:`data.cancelDays = null`、`data.deadlineAt = null`、`data.risk = "NO_DEADLINE"`、`data.riskLabel = "未设免费取消期"`,而 `data.cancelCutoff` 与 `data.remindDays` 仍是该行原值。 - 源单(订单需求 / 团期)读不到时,只影响「谁是源单处理人」的判定,不影响本端点的写入结果;非源单处理人且非超管一律返 808326。 #### 错误响应 ```json { "code": 808328, "message": "退改期限参数不合法", "data": null, "success": false } ``` | code | message | 触发 | |------|---------|------| | 808090 | 未登录或非房务角色,无权操作 | 非房务角色 | | 808320 | 转房记录不存在 | `id` 不存在、已删、或不是父行 | | 808321 | 该房间已处理 | 行已不是 `PENDING`(已转出 / 已取消) | | 808326 | 只有原单处理人可以处理退团房间 | 非源单处理人且非超管 | | 808328 | 退改期限参数不合法 | `cancelDays` 超 0~60、`remindDays` 超 0~30、`cancelCutoff` 不是 `HH:mm` | | 808932 | 房务状态已被并发修改,请刷新后重试 | 真并发写冲突(行版本在锁定读与写之间被改)。**订正前 `cancelDays: null` 会恒定命中这一条,订正后不再出现这种假冲突** | | 100502 | 修改处理中,请勿重复提交 | 3 秒幂等窗口内重复提交同一请求 | #### 业务边界 - 入参不走 Bean Validation,范围与格式错误统一以 **808328** 返回,HTTP 状态仍是 200,不是 400。 - 清除期限只清 `cancelDays` 这一项语义;`cancelCutoff` / `remindDays` 是「下次设期限时的默认值」,保留它们不影响「有没有期限」的判定,因为 `deadlineAt` 与 `risk` 都只在 `cancelDays` 非空时才成立。 - 该行处于 `PENDING` 才可改期限;`TRANSFERRED` / `CANCELLED` 返 808321。 - 只有源单处理人或超管可改;源订单来源看该需求的持有人,团期来源看该团期的房务认领人。 - 同一行的改期限、转房、向酒店取消共用一把行级锁,前端不必自己串行化。 ### 2. 房务异常检查 `GET /v3/admin/order/house-console/audit` **VO**: `HouseConsoleAuditReqVO → HouseConsoleAuditRespVO` #### 使用场景 「异常检查」页签:按出发日期区间一次列出数据对不上的问题(`issues`)和还没办完的事(`tasks`)。本次订正只影响 `tasks` 里 `TRANSFER_PENDING`(退团房未结清)这一类条目的**取行范围**,字段结构未变;前端按 `refId` 跳转退团房处理页的逻辑不变。 #### 入参 | 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | |------|------|------|------|------|------| | scope | Query | String | ❌ | `mine` / `all`,默认 `mine`;其他取值返 400 | 只作用于 `tasks`:`mine` 只留当前登录人是处理人的条目;`issues` 不受它影响 | | departDateFrom | Query | LocalDate | ❌ | `yyyy-MM-dd`,默认今天 | 出发日期区间起(含) | | departDateTo | Query | LocalDate | ❌ | `yyyy-MM-dd`,默认起始日 +30 天;早于起始日或跨度超 92 天返 808313 | 出发日期区间止(含) | #### 出参 `Result` | 字段 | 类型 | 说明 | |------|------|------| | issues | Array | 数据不一致问题,不归属处理人,不受 `scope` 影响;无则空数组 | | tasks | Array | 待处理事项,受 `scope` 过滤;无则空数组 | | issues[].code / tasks[].code | String | 问题码 / 待办码,取值见「六.5、枚举」 | | tasks[].taskCode | String | 待办码(仅 `tasks` 有值),与 `code` 同值 | | issues[].codeLabel / tasks[].codeLabel | String | 中文标签,后端给出直接展示;`TRANSFER_PENDING` 为「退团房未结清」 | | tasks[].orderId | Long(String) | 源订单 ID;退团房条目取该行的源订单 | | tasks[].teamNo | String | 源订单团号;取不到为 `null` | | tasks[].groupBatchId / tasks[].batchNo | Long(String) / String | 源团期 ID 与批次号;散单来源为 `null` | | tasks[].stayDate | LocalDate | 入住晚 | | tasks[].hotelId / hotelName / roomTypeId / roomTypeName | Long(String) / String | 酒店与房型 | | tasks[].refId | Long(String) | 关联单据 ID,`TRANSFER_PENDING` 为退团房父行 ID,前端据此跳转 | | tasks[].detail | String | 说明文案,`TRANSFER_PENDING` 为「剩余 N 间待转出或向酒店取消」 | #### 请求示例 ```http GET /v3/admin/order/house-console/audit?scope=mine&departDateFrom=2026-10-01&departDateTo=2026-10-31 ``` #### 响应示例 ```json { "code": 200, "message": "成功", "data": { "issues": [], "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 } ``` #### 空数据 / 降级响应 ```json { "code": 200, "message": "成功", "data": { "issues": [], "tasks": [] }, "success": true } ``` - `issues` 与 `tasks` 恒为数组,不会是 `null`。 - 退团房条目的源单读不到(源订单或源团期查不到、或出发日为空)时,该条目**仍然列出**,`teamNo` / `batchNo` 可能为 `null`;口径是「宁可多报一条,也不让待办从唯一载体上消失」。 - `STOCK_LEDGER_MISMATCH`(库存账不平)只在资源侧全局库存追踪开关打开时检查,开关关闭时不产出该问题码。 #### 错误响应 ```json { "code": 808313, "message": "日期跨度不能超过 92 天", "data": null, "success": false } ``` | code | message | 触发 | |------|---------|------| | 400 | scope 取值非法 | `scope` 不是 `mine` / `all` | | 808090 | 未登录或非房务角色,无权操作 | 非房务角色 | | 808313 | 日期跨度不能超过 {0} 天 | 出发日期区间跨度超 92 天,或止日早于起日 | #### 业务边界 - `TRANSFER_PENDING` 的归属判据是**源团期 / 源订单的出发日落在窗口内**,与源单当前状态(含已取消)无关;这是本次订正的点。 - 只列 `PENDING` 的退团房父行;已转出、已取消的行不是待办。 - `scope=mine` 的「我的」按源单处理人判:散单来源看该需求持有人,团期来源看该团期房务认领人;源单读不到时该条目在 `mine` 下不会出现(无法判定处理人)。 - 窗口跨度上限 92 天,与控房表查询的 62 天不是同一个上限,别复用。 - 纯读接口,不写数据。 --- ## 四、契约约束与正确调用方式(接口类必写) ### ✅ 正确 / ❌ 错误 payload 对照 | 场景 | payload / 判断 | |------|----------------| | ✅ 设期限 | `{ "cancelDays": 3, "cancelCutoff": "18:00", "remindDays": 1 }` | | ✅ 设期限只给天数 | `{ "cancelDays": 3 }` → 截止时刻取 `18:00`、提醒天数取 `1` | | ✅ 清除期限 | `{ "cancelDays": null }`(或整个 body 只有 `{}`)→ 200,`cancelCutoff` / `remindDays` 保留原值 | | ✅ 判「未设期限」 | `data.cancelDays === null`,或 `data.risk === "NO_DEADLINE"` | | ❌ 判「未设期限」 | `data.cancelCutoff === null && data.remindDays === null`——清除期限后这两项仍有值,该判断恒为 false | | ❌ 清除期限时显式传空 | `{ "cancelDays": null, "cancelCutoff": "", "remindDays": null }` 能成功,但 `cancelCutoff` / `remindDays` 一样被忽略,不要指望用它们清值 | | ❌ 期限天数越界 | `{ "cancelDays": 61 }` → 808328(不是 400) | ### 切换状态时的必要动作 - 清除期限成功后,前端应以返回的整行直接替换列表行,不要只把 `cancelDays` 置空——`risk` / `riskLabel` / `deadlineAt` 都由后端重算,本地推算会与「退团房分页」的汇总读数对不上。 - 「异常检查」页签的待办条数在订正后可能增加;若页面上有与之对照的徽标计数,改为直接用本端点返回的 `tasks.length`,不要沿用按订单状态自行过滤后的口径。 --- ## 五、数据库行为(涉及写操作时必写) | 写操作 | 外部可观察行为 | |--------|----------------| | 设期限(`cancelDays` 非空) | 该行的免费退改天数、截止时刻、提醒天数三项按入参(含默认值)整体更新;行版本 +1;写一条订单级操作日志「退团房 {入住晚} {酒店名} 免费退改期限改为入住前 N 天 HH:mm」 | | 清除期限(`cancelDays` 为 `null`) | **只有免费退改天数被清空**;截止时刻与提醒天数保持该行原值;行版本 +1;写一条订单级操作日志「…免费退改期限改为未设」 | | 并发保护 | 行级分布式锁 + 行版本比对;版本在锁定读与写之间被改则整笔回滚并返 808932 | - 两个写路径都不产生跨服务调用,不发消息。 - 「异常检查」端点是纯读,不写任何数据。 --- ## 六、边界行为 - 清除期限后再次设期限,若只传 `cancelDays`,截止时刻与提醒天数会被**重新按默认值 `18:00` / `1` 覆盖**(不是沿用清除前保留下来的那两个值);要沿用旧值必须显式回传。 - 从未设过期限的新行,其截止时刻与提醒天数是建表默认的 `"18:00"` 与 `1`,所以「一行从没设过期限」与「设过又被清掉」在这两个字段上不可区分;唯一区分点是操作日志。 - 风险分档 `NEAR` 按「日」比较(今天 ≥ 截止日 − 提醒天数),同一天上午和下午不会给出不同分档。 - 退团房待办的取行只设窗口下限(入住晚不早于窗口起日),不设上限:待处理池量级小,多读回的行由源单出发日过滤掉。 - `scope=all` 时任何房务都能看到全部待办条目,但看得见不等于能写;改期限仍按源单处理人校验(808326)。 --- ## 六.5、枚举 / 数据字典(接口出现枚举时必写) ### risk(退团房风险分档) | 值 | 中文(`riskLabel`) | 判据 | |----|--------------------|------| | `OVERDUE` | 已过免费取消期 | 现在已过截止时刻 | | `NEAR` | 临近免费取消期 | 今天 ≥ 截止日 − 提醒天数 | | `NO_DEADLINE` | 未设免费取消期 | `cancelDays` 为空(或该行缺入住晚) | | `NORMAL` | 正常 | 其余 | > 仅 `status = PENDING` 的行有值,其余行 `risk` / `riskLabel` 均为 `null`。 ### status(退团房行状态) | 值 | 中文(`statusLabel`) | 说明 | |----|----------------------|------| | `PENDING` | 待处理 | 还有剩余间数待转出或向酒店取消;只有这一状态能改期限 | | `TRANSFERRED` | 已转出 | 全部间数已转给别的订单 / 团期 | | `CANCELLED` | 已取消 | 已向酒店取消 | ### taskCode / code(异常检查待办码,`tasks[]`) | 值 | 中文(`codeLabel`) | 说明 | |----|--------------------|------| | `TRANSFER_PENDING` | 退团房未结清 | 本次订正影响的就是这一类的取行范围 | | `HOTEL_CANCEL_PENDING` | 原酒店待取消 | 改配留下的原订尚未确认取消 | | `INQUIRY_PENDING` | 新订 / 变更待确认 | — | | `STAY_UNARRANGED` | 住宿待落实 | — | > `issues[]` 的 `code` 取值域是另一组(`STOCK_OVERBOOKED` / `STOCK_LEDGER_MISMATCH` / `STOCK_ROW_MISSING` / `TRANSFER_TARGET_GONE` / `PLAN_COUNT_MISMATCH`),本次未变。 --- ## 六.6、修改前后对比(修改/删除类接口必写,新增跳过) ### 字段级对比 | 字段 | 之前交接件写的 | 现在的实际行为 | |------|----------------|----------------| | `data.cancelCutoff`(清除期限后) | 被一并置空为 `null` | **保留该行原值**(从未设过则为 `"18:00"`) | | `data.remindDays`(清除期限后) | 被一并置空为 `null` | **保留该行原值**(从未设过则为 `1`) | | `data.cancelDays`(清除期限后) | `null` | `null`(不变) | | `data.deadlineAt`(清除期限后) | `null` | `null`(不变) | | `data.risk` / `riskLabel`(清除期限后) | `NO_DEADLINE` / 「未设免费取消期」 | 同(不变) | | 异常检查 `tasks[]` 结构 | — | 字段与类型均未变 | ### 行为级对比 | 行为 | 之前 | 现在 | |------|------|------| | `PUT .../deadline` 传 `cancelDays: null` | 恒定返回 808932「房务状态已被并发修改,请刷新后重试」,期限清不掉 | 返回 200 并给出更新后的整行 | | `PUT .../deadline` 传 `cancelDays` 非空 | 成功 | 成功(口径不变) | | `GET .../audit` 的 `TRANSFER_PENDING` | 源订单 / 源团期已取消的退团房行不出现在 `tasks` 里 | 按源单出发日归属、不看源单状态,这些行会出现 | | `GET .../audit` 的 `TRANSFER_PENDING`(源单查不到 / 出发日为空) | 不出现 | 出现(宁可多报一条) | | `GET .../audit` 的 `issues[]` | — | 口径不变 | --- ## 六.7、影响评估(修改/删除类必写) | 项 | 评估 | |----|------| | 需要前端改代码 | **是(1 处必改)**:凡按 `cancelCutoff` / `remindDays` 是否为 `null` 判「有没有设期限」的地方,改为按 `cancelDays === null` 或 `risk === "NO_DEADLINE"` 判。 | | 需要前端改代码 | **可能(1 处)**:「异常检查」页签若自行按订单状态过滤过待办条目,去掉该过滤,直接用后端返回的 `tasks`。 | | 兼容性 | 无字段增删、无类型变化、无路径与方法变化;只有取值与取行范围变化。 | | 「清除期限」功能 | 从不可用变为可用,前端原有的 808932 报错提示分支在该场景不再触发(真并发冲突仍会返回它,不要删该分支)。 | | 读数变化 | 同一出发日窗口下「异常检查」的待办行数只会增加或不变,不会减少。 | | 其他消费方 | 退团房分页、转房、向酒店取消三个端点的契约未变;本次不涉及小程序端。 | --- ## 七、不影响范围(显式声明, 帮前端/QA 缩小排查面) - 退团房分页 `GET /v3/admin/order/house-console/room-transfers`、转入候选 `GET .../room-transfers/{id}/candidates`、转房 `POST .../room-transfers/{id}/transfer`、向酒店取消 `POST .../room-transfers/{id}/cancel-hotel`:字段与口径均未变。 - 控房表(查询 / 调房量 / 调价 / 导出)、住宿模板、批量认领、改配取消确认、团期转交:未触及。 - `issues[]` 的五类问题码及其判据未变。 - 房务只读标识 `readOnly` / `readOnlyReason` 的口径未变(其口径见 #8491 的两份交接件)。 - 通知、消息模板、跳转链接未变。 - 无数据库结构变更,无新增 Flyway 脚本,无网关路由改动。 --- ## 八、测试环境已验证 | 项 | 读数 | 依据 | |----|------|------| | hl-order-service-v3 运行的提交 | `d57498d38`,BEHIND `0/N`,STATE `ok`,时间 2026-09-30 05:32:57 | 测试服部署登记脚本 `/opt/hulalv/scripts/deploy-status.sh`,2026-09-30 本次读取 | | 本次改动在运行的字节里 | 是 | `git merge-base --is-ancestor ff68637542 origin/dev-v3` 返回 0;`origin/dev-v3` 头为 `d57498d381` | | 清除期限 | `cancelDays=null` → `code=200`;库里免费退改天数为 NULL,截止时刻 / 提醒天数保留原值;`risk=NO_DEADLINE` | 取证提交 `ff6863754`,读数原文记在 `changelogs-v2/2026-09/30_8491_房务控制台接口-新增接口-管理后台.md` 第 1847 行 | | 设期限(回归) | `cancelDays=3` → `code=200`、该行 `risk=OVERDUE`;`cancelDays=0` + `remindDays=1` → `code=200`、`risk=NEAR` | 同上文件第 1845、1846 行,复测提交 `ff6863754` | | 退团房待办含源单已取消的行 | 源订单已取消 + 退团房行 `PENDING` + 窗口覆盖出发日 → `code=200`,`tasks` 含 `TRANSFER_PENDING`「退团房未结清」 | 同上文件第 1861 行,取证提交 `ff6863754` | | 用例覆盖 | `HouseRoomTransferManagerTest#updateDeadline_nullCancelDays_keepsRowCutoffAndRemind`;`HouseRoomTransferMapperMysqlTest#casUpdateDeadline_nullCancelDaysWithRowValues_writesNullAndKeepsCutoffRemind`;`HouseConsoleAuditManagerTest#audit_pendingTransferSourceOrderCancelledInWindow_listed` / `#audit_pendingTransferSourceBatchCancelledInWindow_listed` / `#audit_pendingTransferSourceOrderMissing_listed` / `#audit_pendingTransferSourceOrderDepartOutsideWindow_notListed` | 随 `ff68637542` 新增 | --- ## 九、相关历史 PR(纠错 / 功能演进时必写) | PR / 提交 | 内容 | 与本条的关系 | |-----------|------|--------------| | PR #8564(`7c21cf0e40`) | 房务控制台整套(#8491),首次引入本文两个端点 | 被订正的表述出自它的交接件 | | PR #8599(`ff68637542`) | 本条的两处修复(#8597) | 本条正文描述的就是它合入后的行为 | --- ## 十、相关文档 - 本条 Issue:#8597(PR #8599) - 被订正的交接件:`changelogs-v2/2026-09/30_8491_房务控制台接口-新增接口-管理后台.md`(接口 8 与接口 12) - 只读标识口径:`changelogs-v2/2026-09/30_8491_房务配房接口字段与口径调整-修改接口-管理后台.md` --- ## 关联 / 联系人 ### 链接 - Issue: #8597 - PR: #8599 - 分支基线: `dev-v3` ### 联系人 - 后端: wx - 前端: mmg(管理后台)