88caa74 房务接口审计批次:#8385 订房计划守卫/#8386 住宿驳回加门+删车务口/#8387 旧房间分配三口下线/#8388 回执认领校验+读门/#8389 家庭维度写口下线/#8390 16 读端点补门+菜单撤授。前端按钮后端字段驱动+错误码拦截器透 message+被删端点零调用/入口仅房务角色页,6 条均 not_required;#8387/#8389 后端已标,余 4 条翻 not_required,owner/ref 留空,status_note 引号内追充实证。
15 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 | 8388 | 回执接口守卫:上传加认领人校验(808110/808186,超管不豁免)、列表加房务读门(808090)、缺分片改 808184 | admin | wx(GIT) | 修改接口 | deployed | verified | not_required | 房务回执上传新增认领人校验(超管不豁免)与可选分片处理;列表新增房务读权限门(不受灰度开关控制,常开);错误码 808184 消息补五种原因的具体文案。测试环境网关已实测各分支,含缺分片 808184 新文案。前端实证(mmg 2026-09-27):uploadReceipt 走 http.upload 同一拦截器统一弹 message,808184 原因入 message 无需按 code 分支;回执入口仅房务角色页,零改动 not_required。 | 2026-09-26 | dev-v3 |
order-v3:房务最终确认回执接口守卫加固(管理后台)
服务: hl-order-service-v3
PR: #8394(原始改动) + #8399(808184 补 {0} 占位追加)
Issue: #8388
⚠️ 关键变化
-
上传回执
POST /admin/house/assignments/requirements/{requirementId}/receipts:- 新增认领人校验:需求必须被当前操作人认领,否则返回 808110(非本人);SUPER_ADMIN 在本端点不豁免,与 #8386 驳回需求口径相反。
- 需求处于
PENDING_CLAIM(未认领)时先被状态闸口拦下,返回 808186;错误码 808116 仅作理论防御(正常调用路径不可达)。 - 缺 file 分片 / 0 字节 file 分片改返 808184「回执上传失败:上传文件为空或缺少 file 分片」(改前返 HTTP 500),共 5 种原因文案。
- 顺序:角色门(808090/808091)→ 需求存在(808100)→ 状态闸口(808186)→ 认领人校验(808110)→ 文件校验(808184)。
-
回执列表
GET /admin/house/assignments/requirements/{requirementId}/receipts:- 新增房务读权限门:非房务角色(定制师、车控等)返回 808090。房务全角色(含组长)可见;超管可见。
- 无认领限制(组长可看全部、他人接手前查历史回执)。
一、背景
回执两个端点(上传、列表)无任何权限校验,导致:
- 非认领人房务可为他人上传回执,破坏追责链。
- 定制师、车控等非房务角色可读回执列表含 OSS 直链与酒店联系信息。
同一配房模块的 10 个写操作都带认领人校验;回执缺失属遗漏。缺 file 分片时返回 500 属参数处理缺陷(hl-common-log 共性坑,本单仅止血)。
二、变更接口清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|---|---|---|---|---|
| 1 | 上传最终确认回执 | POST | /admin/house/assignments/requirements/{requirementId}/receipts |
修改接口 | 加认领人校验、缺分片改 808184 |
| 2 | 回执列表 | GET | /admin/house/assignments/requirements/{requirementId}/receipts |
修改接口 | 加房务读权限门(808090) |
三、接口详情
1. 上传最终确认回执 POST /admin/house/assignments/requirements/{requirementId}/receipts
VO: multipart/form-data: file → Result<HouseFinalizeReceiptRespVO>
使用场景
房务在配房面板「最终确认」区上传回执照片/PDF,证明已与酒店确认房间。仅该需求的认领人本人可上传;非房务角色、房务组长、非认领人(含 SUPER_ADMIN)均返回权限错误——超管在本端点不豁免认领归属校验,这一点与 #8386(驳回需求超管豁免)口径不同。
入参字段表
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| requirementId | Path | Long | 是 | — | 酒店需求 ID |
| file | Form | MultipartFile | 是(业务校验) | ≤50MB,类型自动识别 | 回执文件;缺失返 808184 |
出参字段表
| 字段 | 类型 | 说明 |
|---|---|---|
| receiptId | String | 回执 ID(雪花 ID,序列化为字符串) |
| requirementId | String | 需求 ID(雪花 ID,序列化为字符串) |
| orderId | String | 订单 ID(雪花 ID,序列化为字符串) |
| fileName | String | 原始文件名 |
| ossUrl | String | OSS 公网 URL,domain + "/" + ossKey 拼接,不签名 |
| ossKey | String | OSS Object Key |
| fileSize | Long | 文件大小(字节) |
| fileType | String | 附件类型:PDF / IMAGE / OTHER(按扩展名识别) |
| createTime | LocalDateTime | 上传时间,序列化格式 yyyy-MM-dd HH:mm:ss |
请求示例
POST /admin/house/assignments/requirements/2103126783048245250/receipts HTTP/1.1
Host: api.test.1814.love:9443
Authorization: Bearer <room_manager token>
Content-Type: multipart/form-data; boundary=----Boundary
------Boundary
Content-Disposition: form-data; name="file"; filename="receipt.jpg"
Content-Type: image/jpeg
[binary jpeg data]
------Boundary--
响应示例
成功:
{
"code": 200,
"message": "成功",
"success": true,
"data": {
"receiptId": "2103801203844689921",
"requirementId": "2103126783048245250",
"orderId": "2100542287908892650",
"fileName": "receipt.jpg",
"ossUrl": "https://hlgl-test.oss-cn-beijing.aliyuncs.com/house/finalize-receipt/...",
"ossKey": "house/finalize-receipt/2026-09/2103126783048245250_receipt.jpg",
"fileSize": 512000,
"fileType": "IMAGE",
"createTime": "2026-09-26 14:30:00"
}
}
失败(非认领人):
{
"code": 808110,
"message": "需求不属于当前用户",
"success": false,
"data": null
}
失败(缺分片,实测):
{
"code": 808184,
"message": "回执上传失败:上传文件为空或缺少 file 分片",
"success": false,
"data": null
}
空数据 / 降级响应
- 文件为空或缺
file分片:code=808184,message「回执上传失败:上传文件为空或缺少 file 分片」(改前返 HTTP 500)。
错误响应
{
"code": 808110,
"message": "需求不属于当前用户",
"success": false,
"data": null
}
其他错误码:
- 808090:未登录或非房务角色,无权操作。
- 808091:房务组长为只读监督角色,无权执行该操作。
- 808100:需求不存在。
- 808186:当前状态不允许上传回执(仅 CLAIMING/PENDING_FINALIZE 可传;PENDING_CLAIM 等其他状态走这个码,不是 808116)。
- 808116:订单未抢单, 请先抢单再配房(状态闸口之后理论不可达,作纵深防护保留)。
- 808184:回执上传失败:{0},
{0}按触发原因取以下固定文案之一——「上传文件为空或缺少 file 分片」/「文件大小超过 50MB」/「OSS 未配置」/「读取上传文件失败」/「文件存储服务暂不可用,请稍后重试」;异常原文只进服务端日志,不回显给客户端。
业务边界
- 认领校验:需求
claimer_id必须等于当前操作人;超管不豁免,对他人认领的需求上传同样返回 808110。与 #8386(驳回需求,超管豁免)口径不同,前端不要套同一套按钮逻辑。 - 校验顺序:写门(808090/808091)→ 需求存在(808100)→ 状态闸口(808186)→ 认领归属(808116/808110)→ 文件校验(808184)。
- 文件分片:
file分片改为可选(required=false),缺失走 Service 内已有的空文件分支报业务码 808184(改前是 HTML form 漏填触发MissingServletRequestPartException,落到兜底Exception处理器返 HTTP 200+code 500「系统繁忙」并打 ERROR 日志)。 - 状态限制:仅 CLAIMING(配房中)与 PENDING_FINALIZE(待确认)两个阶段可上传;PENDING_CLAIM(未抢单)等其他状态返 808186,不是 808116。
- 无事务:
upload()不加@Transactional;OSSputObject成功后才insert,insert失败可能残留孤儿 OSS 对象(由清理 job 兜底);OSS 失败(putObject抛异常)返 808184 且不落库。
2. 回执列表 GET /admin/house/assignments/requirements/{requirementId}/receipts
VO: → Result<List<HouseFinalizeReceiptRespVO>>
使用场景
房务或超管查看某需求的全部回执列表(谁上传的、何时、文件链接)。非房务角色返回 808090;房务全角色可见无限制。
入参字段表
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| requirementId | Path | Long | 是 | — | 酒店需求 ID |
出参字段表
| 字段 | 类型 | 说明 |
|---|---|---|
| receiptId | String | 回执 ID(雪花 ID,序列化为字符串) |
| requirementId | String | 需求 ID(雪花 ID,序列化为字符串) |
| orderId | String | 订单 ID(雪花 ID,序列化为字符串) |
| fileName | String | 原始文件名 |
| ossUrl | String | OSS 公网 URL,不签名 |
| ossKey | String | OSS Object Key |
| fileSize | Long | 文件大小(字节) |
| fileType | String | 附件类型:PDF / IMAGE / OTHER |
| createTime | LocalDateTime | 上传时间,序列化格式 yyyy-MM-dd HH:mm:ss |
请求示例
GET /admin/house/assignments/requirements/2103126783048245250/receipts HTTP/1.1
Host: api.test.1814.love:9443
Authorization: Bearer <room_manager token>
响应示例
成功(房务):
{
"code": 200,
"message": "成功",
"success": true,
"data": [
{
"receiptId": "2103801203844689921",
"requirementId": "2103126783048245250",
"orderId": "2100542287908892650",
"fileName": "receipt_1.jpg",
"ossUrl": "https://hlgl-test.oss-cn-beijing.aliyuncs.com/house/finalize-receipt/...",
"ossKey": "house/finalize-receipt/2026-09/2103126783048245250_receipt_1.jpg",
"fileSize": 512000,
"fileType": "IMAGE",
"createTime": "2026-09-26 14:30:00"
}
]
}
失败(定制师):
{
"code": 808090,
"message": "未登录或非房务角色,无权操作",
"success": false,
"data": null
}
空数据 / 降级响应
- 无回执:
code=200,data=[]。
错误响应
{
"code": 808090,
"message": "未登录或非房务角色,无权操作",
"success": false,
"data": null
}
说明:
- 808090(新增):非房务角色返回;该读门调
HouseReadGuard.assertHouseReadPermission(),不受 #8390 引入的灰度开关group-batch.acl.enforce.house-read-role控制,是常开的角色门。
业务边界
- 角色放行:ROOM_MANAGER / house_keeper_lead / SUPER_ADMIN 均可读;零角色(#7609 G-2 保留项)亦放行。
- 无认领限制:组长可看全部需求回执(监督权),他人接手后也可查历史。
- 直链有效期:测试桶直链公共可读(无签名);生产桶读策略未定,前端不得缓存直链。
四、契约约束与正确调用方式
| 场景 | 调用方法 | 说明 |
|---|---|---|
| ✅ 认领人上传 | POST /admin/house/assignments/requirements/{id}/receipts,multipart: file=@... |
该需求的当前认领人上传,返回 200 |
| ✅ 房务查列表 | GET /admin/house/assignments/requirements/{id}/receipts |
返回 200 + 全部回执 |
| ✅ 组长查列表 | 同上(house_keeper_lead 身份) | 无限制,200 返回 |
| ❌ 非认领人上传(含 SUPER_ADMIN) | — | 返回 808110,不落库;超管在本端点不豁免认领归属校验 |
| ❌ 未认领需求(PENDING_CLAIM)上传 | — | 返回 808186(先过状态闸口) |
| ❌ 定制师查列表 | — | 返回 808090 |
| ❌ 缺 file 分片 | 空 multipart 或无 file 字段 | 返回 808184 |
五、数据库行为
无变更、无 Flyway。house_finalize_receipt 表与逻辑保留;认领人校验在内存判断,无新增存储。
六、边界行为
| 场景 | 行为 |
|---|---|
| 认领人上传 | 返回 200,回执入库入 OSS |
| 非认领人上传(含 SUPER_ADMIN) | 返回 808110,无新行 |
| 转单后原人上传 | 返回 808110(新人成认领人,原人失去权限) |
| PENDING_CLAIM 需求上传 | 返回 808186(状态闸口先于认领校验) |
| 组长列表查询 | 返回 200,全列表 |
| 定制师列表查询 | 返回 808090,无数据 |
| 缺 file 分片 / 0 字节 file 分片 | 返回 808184(HTTP 200、code 业务码,5 种原因文案) |
六.6、修改前后对比
| 维度 | 改前 | 改后 |
|---|---|---|
| 非认领人上传(含超管) | 返回 200,入库 | 返回 808110 |
| 缺 file 分片 | HTTP 500、ERROR 日志 | HTTP 200、code 808184,仅 WARN 日志 |
| 定制师查列表 | 返回 200 + 列表 | 返回 808090 |
六.7、影响评估
- 兼容性:hl-ui 回执上传与列表操作收新错误码(808090/808091/808110/808186/808184);需处理新文案提示。
- 前端要动的:
- 上传失败按错误码区分:「权限不足」(808090/808091)、「非本人(含超管)」(808110)、「需求未认领」(808186)、「文件」(808184,5 种原因文案,需在
message里判断具体原因而非只判 code)。 - 定制师等非房务角色不再能查回执列表,改改导航或隐藏入口。
- 上传失败按错误码区分:「权限不足」(808090/808091)、「非本人(含超管)」(808110)、「需求未认领」(808186)、「文件」(808184,5 种原因文案,需在
- 数据影响:无;仅加校验,不改历史回执。
- 其它服务:hl-mp-service、fleet 无直接调用。
七、不影响范围
- 房务订单详情页回执展示逻辑(虽然定制师不再能查全列表,已登录进详情页的现有回执链接仍有效)。
- 回执删除接口(无,但实体带
@TableLogic支持软删)。 - 其他配房写操作(转单、释放、分房等),无改动。
八、测试环境已验证
部署:测试环境 order-v3 1f65d7894(含 e2313790b)。网关 api.test.1814.love:9443。
| # | 场景 | 实测结果 |
|---|---|---|
| 1 | 认领人上传 | code 200,新行 uploader_id = 认领人;已软删清理 |
| 2 | 非认领人上传 | code 808110,无新行 |
| 3 | PENDING_CLAIM 需求上传 | code 808186 |
| 4 | SUPER_ADMIN 对他人认领的需求上传 | code 808110(不豁免) |
| 5 | 缺 file 分片(multipart 只带无关字段)×2 | HTTP 200 + {"code":808184,"message":"回执上传失败:上传文件为空或缺少 file 分片"} |
| 6 | 0 字节 file 分片 | 同 #5,同码同文案 |
| 7 | 房务(认领人本人)查列表 | code 200,全部回执 |
| 8 | 定制师 / VEHICLE_MANAGER 查列表 | code 808090,无数据 |
| 9 | house_keeper_lead / 非认领 ROOM_MANAGER / SUPER_ADMIN 查列表 | code 200,全部回执 |
#5、#6 场景 order-v3 日志对应 3 条 WARN Business error [order.808184],无 Unexpected error ERROR 行。
十、相关文档
- Issue:wx/HL#8388
- PR:wx/HL#8399(808184 补
{0}占位追加) - 相关单号:#8386(认领人校验,超管在该单有豁免,口径与本单相反)、#8390(读权限门同配方)
关联 / 联系人
联系人
- 后端负责人: @wx