From 303ce022e2c817560a16e3f7fdb4cccbea964982 Mon Sep 17 00:00:00 2001 From: wx Date: Tue, 12 May 2026 17:38:23 +0800 Subject: [PATCH] =?UTF-8?q?add:=20=E8=B5=84=E6=BA=90=E4=B8=8B=E6=9E=B6?= =?UTF-8?q?=E6=94=BE=E5=BC=80=E8=A2=AB=E4=BA=A7=E5=93=81=E5=BC=95=E7=94=A8?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C=20+=20in-use=20=E9=A2=84=E8=A7=88=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=20(Issue=20#2115)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...rove_resource_disable_allow_when_in_use.md | 193 ++++++++++++++++++ 1 file changed, 193 insertions(+) create mode 100644 changelogs/2026-05/12_improve_resource_disable_allow_when_in_use.md diff --git a/changelogs/2026-05/12_improve_resource_disable_allow_when_in_use.md b/changelogs/2026-05/12_improve_resource_disable_allow_when_in_use.md new file mode 100644 index 0000000..565f5d0 --- /dev/null +++ b/changelogs/2026-05/12_improve_resource_disable_allow_when_in_use.md @@ -0,0 +1,193 @@ +--- +date: 2026-05-12 +type: backend-improvement +service: hl-resource-service +priority: high +notify: ["@mmg"] +status: verified +--- + +# 资源下架放开"被产品引用"硬拦, 新增 /admin/resource-reference/in-use 预览接口 (已测试服验证) + +> **PR**: [#2120](https://git.1814.love:8443/wx/HL/pulls/2120) — 已合并 dev + 部署测试服 +> **Issue**: [#2115](https://git.1814.love:8443/wx/HL/issues/2115) +> **状态**: ✅ **测试服已验证** (api.test.1814.love:9443) — 6/6 case 端到端通过 + +--- + +## 一、背景 + +之前所有资源 (景区/活动/酒店/房型/餐厅/服务/人员/备品/备品组合/费用项/车型) 下架时, 后端会调 ProductFeignClient.checkResourceInUse 校验"是否被上架产品引用", 被引用就抛 `*_DISABLE_IN_USE` 错误码 (300103/310103/310206/320103/340103/350103/360103/380103/390103) 硬拦. + +实际运营场景中, 资源被产品使用是常态, 强制要求"先解除产品绑定才能下架"把管理员锁死. 现改为: **后端放行下架, 由前端调预览接口拿到引用产品 list 弹二次确认**. + +**删除/审批工作流逻辑不动** — 删除被引用资源仍硬拦, 审批模板/状态机/企微推送全部保留. + +--- + +## 二、测试服已验证 (硬性凭证) + +景区 `scenicId=3001000000000000019` (中俄边境公路) 被 **8 个上架产品**引用. + +``` +A. GET /admin/resource-reference/in-use?type=SCENIC&id=3001000000000000019 + → 200 code=200 data=["结婚不回家", "发的是干啥地方", "冻干粉发短信给", + "有今天放假n", "游牧的森林-短途版", + "呼伦贝尔草原深度定制·3天2晚家庭私享团", + "呼伦贝尔周边摄影季", "游牧的森林-短途版(来自wx的分享)"] + +B. PUT /admin/scenic/spot/3001000000000000019/status body={"status":0} + → 200 code=200 success (历史 410103) ✓ 关键验收 + +C. PUT /admin/scenic/spot/3001000000000000019/status body={"status":1} (上架还原) + → 200 code=200 success + +D. PUT /admin/scenic/spots/batch/status body={"scenicIds":[3 个含 in-use],"status":0} + → 200 code=200 全部下架成功 ✓ (历史会静默跳过 in-use 的) + PUT 同上 status=1 上架还原 → 200 success + +E. GET /admin/resource-reference/in-use 边界: + - type=SCENIC&id=99999999 → 200 data=[] + - type=RESTAURANT&id=1 → 200 data=[] + - type=HOTEL&id=1 → 200 data=[] + - type=ROOM_TYPE&id=1 → 200 data=[] + - type=ACTIVITY&id=1 → 200 data=[] + +F. DELETE /admin/scenic/spots/batch body={"scenicIds":[3001000000000000019]} + → 200 deniedIds=["3001000000000000019"] + → deniedReasons=["被产品使用: 结婚不回家、发的是干啥地方、冻干粉发短信给、…"] + ✓ 删除逻辑保留, 仍硬拦 +``` + +--- + +## 三、变更接口清单 + +### 新接口 + +| # | 接口 | 方法 | 说明 | +|---|------|------|------| +| 1 | `GET /admin/resource-reference/in-use` | GET | **新增**. 查询资源被哪些上架产品使用. 入参 `type` + `id`. 返回 `Result>` 引用产品名 list. fail-closed: Feign 失败返 500 FEIGN_RPC_FAIL | + +**type 取值**: `SCENIC` / `ACTIVITY` / `HOTEL` / `ROOM_TYPE` / `RESTAURANT` / `SERVICE` / `STAFF` / `SUPPLIES` / `SUPPLIES_COMBO` / `COST` / `VEHICLE` + +### 行为变更接口 (响应结构不变, 只是不再返 410xxx) + +所有资源下架/禁用相关接口 **不再返** `*_DISABLE_IN_USE` 错误码: + +| 资源类型 | 单条下架 | 批量下架 | 提审批下架 | 已删的错误码 | +|----------|----------|----------|-----------|--------------| +| 景区 | `PUT /admin/scenic/spot/{id}/status` | `PUT /admin/scenic/spots/batch/status` | `POST /admin/scenic/spot/{id}/approval` | **300103** | +| 活动 | (同模式) | (同模式) | (同模式) | **320103** | +| 酒店 | `PUT /admin/hotel/...` | | | **310103** | +| 房型 | (同模式) | | | **310206** | +| 餐厅 | | | | (本就没此校验) | +| 服务 | (同模式) | | | **350103** | +| 人员 | (同模式) | | | **360103** | +| 备品 | (同模式) | | | **380103** | +| 备品组合 | (同模式) | | | **380103 (SUPPLIES_DISABLE_IN_USE 复用)** | +| 费用项 | (同模式) | | | **390103** | +| 车型 | (同模式) | | | **340103** | + +前端原有针对这些 code 的特殊错误提示可以删掉. + +### 删除/审批保留不动 + +- 删除被引用 (4 个 *_DELETE_IN_USE) 保留 ✓ +- "已启用不能删除请先下架" (3 个 STATUS_ON_CANT_DELETE) 保留 ✓ +- 审批模板/状态机/企微推送 全部保留 ✓ + +--- + +## 四、需要前端做的事 (@mmg) + +### 1) 所有资源下架按钮加二次确认弹窗 + +**通用模板** (景区为例): + +```vue + +``` + +### 2) 删掉对 *_DISABLE_IN_USE 错误码的特殊处理 + +前端如有 `if (code === 410103 || code === 320103 || ...)` 弹特定提示的逻辑, **删掉**. 服务端不会再返这些 code. + +### 3) type 参数映射 (前端各模块按需用) + +| 资源类型 | type 值 | +|----------|---------| +| 景区 | `SCENIC` | +| 活动 | `ACTIVITY` | +| 酒店 | `HOTEL` | +| 房型 | `ROOM_TYPE` | +| 餐厅 | `RESTAURANT` | +| 服务 | `SERVICE` | +| 人员 | `STAFF` | +| 备品 | `SUPPLIES` | +| 备品组合 | `SUPPLIES_COMBO` | +| 费用项 | `COST` | +| 车型 | `VEHICLE` | + +### 4) (可选) 列表页"被X个产品使用"角标 + +资源列表页可以批量调 `/admin/resource-reference/in-use` 给每个资源加角标"被N个产品使用", 但**不必须** — 二次确认弹窗已经足够. + +--- + +## 五、风险/兼容性 + +- **下架后产品端不变**: 产品行程节点拿的是资源的名字/概要快照, 不实时查 status. 下架仅影响"资源列表筛选可见性"和"管理员新建产品时能选哪些资源". +- **历史脏数据**: 没有. +- **fail-closed**: 新接口 Feign 失败 (product-service 挂了) 抛 500 FEIGN_RPC_FAIL, 前端弹"无法确认引用情况, 请稍后再试" 即可. +- **删除路径仍硬拦**: 数据不会因为允许下架而丢失. + +--- + +## 六、技术债清理 (跟改动一起完成) + +- 删 9 个 0 调用的 `*_DISABLE_IN_USE` 错误码常量 (`ScenicErrorCode` / `HotelErrorCode` / `ActivityErrorCode` 等) +- 7 个 Service 删 `referenceCheckHelper` 字段 (Activity/Cost/Vehicle/Hotel/RoomType/Service/SuppliesCombo) — 这些 Service 不再有引用校验 +- 4 个 Service 保留字段 (Scenic/Restaurant/Staff/Supplies — 它们 batchDelete 还在用) +- `ResourceReferenceCheckHelper` javadoc 更新, 标注只服务删除路径 +- 13 个 test 文件同步: 5 个删 in-use 测试, 7 个 Service 测试构造器去 helper 参数, 1 个清字段 mock + +**mvn test: Tests run: 1148, Failures: 0, Errors: 0, Skipped: 41 — 全绿** + +--- + +@mmg 看到先弹窗模板, 改完通知我闭环.