# 资源服务接口契约审计修复（状态校验收紧 + 关联字段回填 + 错误码补全）— 修改接口 — 管理后台

> 变更类型：⚠️ 行为收紧（非法状态拒绝 + 校验新增）+ 响应字段回填，无破坏性删除
> 端类型：管理后台（景区/活动/酒店/餐厅/服务/人员/车型/备品/费用/攻略/素材）
> 日期：2026-06-17
> 服务：hl-resource-service
> PR：https://git.1814.love:8443/wx/HL/pulls/3948

---

## ⚠️ 关键说明

用接口契约语义审计工作流全量扫描资源服务全部 63 个 Controller（355 条原始发现），对抗复核后修复高置信 P0/P1 共 64 项。已合并 dev-v3、部署测试服双实例（totalCodes=238）、网关 9443 + 真 admin token 实测（状态非法值已拒、修复端点正常）、本地全量 1545 单测零新增回归。

最影响前端的是第 1 节（状态端点对非法值的拒绝）和第 2 节（详情/列表的关联中文字段现在会回填）。

---

## 1. 状态/审批端点收紧：非法状态值被拒绝（前端只能传字典内值）

此前一批 `status` / `submit-approval` 端点的状态入参只有 `@Max(2)` 或无白名单，能把字典外的 `status=2` 静默落库。本次统一收紧：**状态字典只有 `0=下架 / 1=上架`，传 `2` 等非法值会被拒绝**（`@Valid` 层返 400 文案「状态值无效，仅支持0=下架/1=上架」+ Service 层业务错误码双重防御），不再静默写入。

涉及端点（admin，传非法 status 会被拒）：

| 域 | 端点 |
|---|---|
| 活动 | PUT `/admin/activity/item/{id}/status`、POST `/admin/activity/item/{id}/submit-approval` |
| 酒店 | POST `/admin/hotel/item/{id}/submit-approval` |
| 餐厅 | PUT `/admin/restaurant/item/{id}/status`、POST `.../submit-approval` |
| 服务 | POST `/admin/service/item/{id}/submit-approval`、PUT `/admin/service/items/batch/status` |
| 人员 | PUT `/admin/staff/{id}/status`、POST `.../submit-approval` |
| 车型 | PUT `/admin/vehicle/model/{id}/status`、POST `.../submit-approval` |
| 备品 | POST `/admin/supplies/item/{id}/submit-approval` |
| 费用 | POST `/admin/cost/item/{id}/submit-approval` |
| 攻略分类 | PUT `/admin/guide/category/{id}/status` |
| 价格日历(批量改状态) | 活动/服务/人员/景区/房型 `.../prices/batch-status`（状态字典白名单校验） |

> 前端处理：以上端点 status / targetStatus 只传字典内值（一般 `0`/`1`，价格日历用 `AVAILABLE/SOLD_OUT/CLOSED`）。原先误传 `2` 能成功的，现在会收到 400/业务错误码。

---

## 2. 详情/列表关联中文字段回填（原先恒 null，现在返回）

以下 VO 声明了关联中文字段但 Service 从不回填、恒为 null，本次在 Service 回填：

| 端点 | 现在会回填的字段 |
|---|---|
| GET `/admin/restaurant/items`、`/admin/restaurant/item/{id}` | categoryName、cuisineTypeName |
| GET `/admin/scenic/spot/{id}` | facilityNames |
| GET `/admin/hotel/item/{id}` | roomTypes（房型列表，原先只有 roomTypeCount） |
| GET `/internal/material/by-ids` 等 | categoryName（Feign 消费方原先拿到 null） |

> 前端处理：这些字段从「恒 null」变为「有值」，按需展示即可，无破坏性。

---

## 3. 新增/规范化错误码（前端按 Result.code 处理）

新增 15 个业务错误码（resource 段 3xxxxx）替代原裸字符串/裸 404/400。前端常见：

| 接口 | 错误码 | 触发场景 |
|---|---|---|
| 各状态端点 | 330303/340403/360303 等 | 状态值非法（仅 0/1） |
| 价格日历批量改状态 | 300402/350304/360304 | 日历状态非法（AVAILABLE/SOLD_OUT/CLOSED） |
| 攻略分类创建 | 370704 | 分类名称重复 |
| 攻略分类状态 | 370705 | 状态非法（仅 0/1） |
| 内部房务扣库存 | 310403-310406 | 库存不足/参数空/qty 非法/hotelId 不一致 |
| 素材删除 | 370703 | 素材存在引用无法删除 |
| 费用审批 | 390902 | 目标状态非法 |

---

## 4. 其它对齐（前端基本无感）

- 金额字段补 `@JsonSerialize(ToStringSerializer)` 输出字符串（7 个价格日历 VO + 退费明细 + 备品组合 basePrice）
- tagType 注解 `0/1` 标反修正（酒店/景区/车型标签：`0=系统预设 1=自定义`，与数据一致；数据本身不变）
- adhoc 标签并发建重名兜底；多写补事务；价格变更 MQ 改事务提交后异步；删房型/季节级联清理孤儿数据

---

## ⚠️ 待产品确认（本次未改，留作后续）

- 内部酒店 `status` 类型（resource 返 Integer 0/1）与下游 `HotelBriefDTO`（String ACTIVE/INACTIVE）跨服务不一致
- 素材分类权限校验当前恒放行（`hasPermission` 恒 true），按角色分类权限未真正生效；权限表 schema 有 role_id/role_code 两套矛盾定义
- 小程序景区详情未返季节内容（resource + mp 两侧都未加载）
- 车型 `GROUP` 字典是否保留

---

## 备注

P2/P3 与中等置信发现暂未处理（后续批次）。本次为高置信 P0/P1。
