- #8659:候选页 inventoryStatus 按日历状态取值;控房表新增 calendarStatus / calendarStatusName(前端加一列展示);扣减拒绝分 808906 / 808907 / 808901。
- #8662:删除 PUT /v3/admin/order/{id}/hotel-requirement;询房预览补房务读守卫,非房务角色返回 808090。
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
9.6 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 | 8662 | 询房预览接口补房务读守卫 | admin | wx(GIT) | 修改接口 | deployed | not_required | not_required | 2026-10-02 | dev-v3 |
询房预览接口补房务读守卫
存放目录: 二期 →
changelogs-v2/2026-10/服务: hl-order-service-v3 Issue: #8662 日期: 2026-10-02 影响范围: 管理后台房务询房话术预览功能
⚠️ 关键变化
- 接口
POST /v3/admin/order/inquiry/preview新增房务读守卫。 - 非房务角色(定制师、管理员、其他后台角色)调用返回 808090「未登录或非房务角色,无权操作」。
- 房务角色(房务管理员、超管)放行,功能无改动。
一、背景
二期房务功能收口中,#8390 统一给 16 个旧只读端点(日历 / 房务详情 / 酒店视图 / 转单候选 / 待办 / 月度对账 / 旧抢单池 / 订单房间)挂上房务读守卫,唯独询房话术预览这一个接口漏过,导致定制师、运营等非房务角色能调通,拿到酒店联系人与微信(源码:HouseReadGuard.java 类 javadoc)。本次补上后,受此守卫覆盖的端点共 17 个。
二、变更接口清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|---|---|---|---|---|
| 1 | 询房话术预览 | POST | /v3/admin/order/inquiry/preview |
修改 | 新增房务读守卫,非房务角色返回 808090 |
三、接口详情
1. 询房话术预览 POST /v3/admin/order/inquiry/preview
VO: InquiryPreviewReqVO → InquiryPreviewRespVO
使用场景
房务在配房弹窗点击「询房」时预览即将发往酒店的话术(所见即所发),确认无误后复制到企业微信。本次修改:非房务角色被拒。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| hotelId | Body | Long | ✅ | - | 酒店 ID;按此取 resource 联系人渲染文案 |
| orderId | Body | Long | ❌ | - | 订单 ID(取团号);assignmentId 有效时以其所属订单为准 |
| assignmentId | Body | Long | ❌ | - | 配房 ID;存在且与 hotelId 匹配时,日期/房型/间数/支付方式优先取该配房快照 |
| stayDate | Body | LocalDate | ❌ | - | 入住日期;assignmentId 命中时被快照值覆盖 |
| roomCount | Body | Integer | ❌ | ≥1 | 房间数;assignmentId 命中时被快照值覆盖;都缺省时按 1 间渲染 |
| roomCategory | Body | String | ❌ | 字典 room_category | 房型类别;assignmentId 未命中时用于查房型中文名,查不到则原样回退为传入的 code |
出参 Result<InquiryPreviewRespVO>
| 字段 | 类型 | 说明 |
|---|---|---|
| messageBody | String | 渲染后的固定格式订房确认话术(模板见下) |
| contactName | String | 联系人姓名,resource 按 hotelId 带出,前端只读回显 |
| contactWechat | String | 联系人微信号,resource 按 hotelId 带出,前端只读回显 |
话术固定模板(InquiryMessageTemplate.SEND_BASE,占位符按 Map 渲染,缺失值替换为空串):
呼籁旅行 - 订房确认书:
团号:${teamNo}
日期:${stayDate}
房型:${roomTypeName}${roomCount}间
备注:${tags}
1.${paymentText},价格保密。
2.${breakfastText}${invoiceText}
3.核房电话:${phone}
辛苦确认后回复 @${replyContacts}
请求示例
{
"hotelId": 1900000001,
"orderId": 1900000000,
"stayDate": "2026-04-28",
"roomCount": 1
}
响应示例
{
"code": 200,
"message": "成功",
"data": {
"messageBody": "呼籁旅行 - 订房确认书:\n团号:HL20261001A\n日期:4.28\n房型:待补充1间\n备注:协议酒店\n1.领队前台现付,价格保密。\n2.含早含发票\n3.核房电话:0470-8888888\n辛苦确认后回复 @王前台",
"contactName": "王前台",
"contactWechat": "hailar_holiday"
},
"success": true
}
上例未传 roomCategory、也未传 assignmentId,roomTypeName 按规则取不到任何来源,渲染为空缺省文案(源码常量 EMPTY_VALUE_TEXT)——${roomTypeName}${roomCount}间 模板不插空格,故渲染结果是该空缺省文案与 1间 的无分隔拼接(见上方 JSON 示例的 messageBody),前端如需展示分隔需自行处理,后端不改模板。日期按 M.d 格式渲染(无补零),2026-04-28 → 4.28。ID、团号、酒店联系人等取值均为说明用的构造值。
空数据 / 降级响应
- 酒店联系信息查询抛异常(
loadHotelExtended捕获全部RuntimeException):静默降级,contactName/contactWechat返回空字符串""(不是 NULL),messageBody仍正常渲染,缺省字段分别落空值常量(EMPTY_VALUE_TEXT)/空标签常量(EMPTY_TAG_TEXT)/现付默认文案。 assignmentId传了但查不到记录、或与hotelId不匹配:静默降级为按请求参数 + 资源数据重新生成(不报错,仅记一条log.warn),不是 assignment 快照。assignmentId命中但与请求里的orderId不一致:忽略请求orderId,改用该配房记录的真实orderId(同样静默降级,仅记日志)。- 不落库,房务可反复调用,无状态。
错误响应
{
"code": 808090,
"message": "未登录或非房务角色,无权操作",
"data": null,
"success": false
}
其他错误:
| code | message | 触发 |
|---|---|---|
| 400 | hotelId 不能为空 | hotelId 未传 |
| 400 | 房间数最小为 1 | roomCount 传了但 < 1 |
业务边界
- 只校验角色(房务管理员/超管放行),不校验订单归属:房务可预览任意订单的询房话术,与 #8390 覆盖的其余 16 个只读端点行为一致。
- 该守卫只拦「有角色但非房务」;零角色账号(网关未透传
X-Admin-Role)按既有口径仍放行,不受本次改动影响(HouseReadGuard.java类 javadoc,#7609 G-2 定案)。 - 预览不落库,无副作用,可反复调用。
contactWechat仅供复制,前端不做交互(不拨电话、不主动跳转)。
四、契约约束与正确调用方式
权限对照
| 角色 | 改前 | 改后 | 说明 |
|---|---|---|---|
| 房务管理员 | 200 放行 | 200 放行 | 无改动 |
| 超管 | 200 放行 | 200 放行 | 无改动 |
| 定制师(CUSTOMIZER) | 200 放行(缺陷) | 808090 拒绝 | 新增限制 |
| 其他后台角色(如 ADMIN) | 200 放行(缺陷) | 808090 拒绝 | 新增限制 |
零角色账号(网关未透传 X-Admin-Role) |
放行 | 放行 | 无改动(#7609 G-2 口径,本次刻意不收) |
五、数据库行为
不落库,本接口无数据写入。
六、边界行为
- 错误码 808090 与所有同域房务读端点保持一致,可统一处理。
- 权限守卫受 Nacos 开关
group-batch.acl.enforce.house-read-role控制。测试服 2026-09-30~10-02 期间该开关为开启状态(实测 ADMIN/CUSTOMIZER 均返回 808090,见「八、测试环境已验证」);生产环境以当时的配置为准,前端按本文档的错误码契约接即可,无需关心开关本身的开关状态。
六.5 枚举
不适用(接口无新增枚举)。
六.6、修改前后对比
| 项 | 改前 | 改后 |
|---|---|---|
| 权限校验 | ❌ 无房务守卫,任何角色可调 | ✅ 新增房务读守卫,非房务返回 808090 |
| 功能逻辑 | 预览话术、返回联系人 | 不变(仅权限改动) |
六.7、影响评估
- 前端无需改动:经 hl-ui v2.1 核实,该接口的封装函数(
src/api/housekeeper/inquiry.js的previewInquiry)仅有一处调用——src/views/housekeeper/components/useHousekeeperInquiryCopy.js,位于房务专属视图目录下,本就只在房务角色登录后的界面里被触达。非房务角色(定制师等)侧没有调用这个接口的代码,本次收紧权限不会让任何现有页面报错。
七、不影响范围
- 房务配房流程(使用此接口的场景)功能不变。
- 小程序端、H5 端接口无改动。
- #8390 已覆盖的其余 16 个旧只读端点本身无行为变化,本次只是把本端点补入同一套守卫。
八、测试环境已验证
测试服环境,2026-09-30~10-02,经网关实测,与修前基线逐字段比对(基线快照:p50_ac3_room_manager.json/p50_ac3_super_admin.json;本轮:p6_ac3_roommanager.json/p6_ac3_superadmin.json/p6_ac3_admin.json/p6_ac3_consultant.json)。
POST /v3/admin/order/inquiry/preview
房务管理员(ROOM_MANAGER):200,messageBody/contactName/contactWechat 与修前基线逐字节相同 ✓
超管(SUPER_ADMIN):200,messageBody/contactName/contactWechat 与修前基线逐字节相同 ✓
管理员(ADMIN):808090 未登录或非房务角色,无权操作 ✓
定制师(CUSTOMIZER):808090 未登录或非房务角色,无权操作 ✓
十、相关文档
关联 / 联系人
关联工单: #8662
同批删除: 旧住宿需求提交接口
后端负责人: @wx