--- schema: "hl-changelog/v2" ticket: "7059" title: "设置供应商候选按资源上下文过滤" consumer: "admin" author: "lc(GIT)" change_type: "修改接口" backend_status: "deployed" gateway_status: "verified" frontend_status: "verified" frontend_owner: "mmg" frontend_ref: "a1a78906" target_release: "" verified_at: "2026-09-04" status_note: "后端已部署并验证;待前端删除本地映射,仅透传资源上下文。" updated_at: "2026-09-04" base: "dev-v3" --- # 资源管理:设置供应商候选按资源上下文过滤 > **服务**: hl-resource-service (8082) > **PR**: #7064 > **Issue**: #7059 > **日期**: 2026-09-04 > **影响范围**: 管理后台资源管理、车务管理的“设置供应商”候选与绑定 --- ## ⚠️ 关键变化 前端不再维护“资源分类 → 供应商类型”映射;候选查询传 `resourceModule`、`resourceId`,后端解析类型并只返回 `ACTIVE` 且匹配的供应商。 ## 一、背景 #7042 要求前端传 `typeCode` 的结论已撤销。本次由后端统一解析资源上下文,避免景区混入车队供应商,并修正组合备品误用 `SUPPLIES` 的问题。 ## 二、变更接口清单 | # | 接口 | 方法 | 路径 | 变更类型 | 说明 | |---|------|------|------|----------|------| | 1 | 有界查询供应商 | GET | `/admin/supplier/items/list` | 新增可选查询参数 | 完整资源上下文下由后端过滤候选 | | 2 | 设置或改绑资源供应商 | PUT | `/admin/supplier/resource-relations/{resourceModule}/{resourceId}/update` | 调整类型解析 | 固定映射模块可省略 `requiredTypeCode` | ## 三、接口详情 ### 1. 有界查询供应商 `GET /admin/supplier/items/list` **VO**: `SupplierListReqVO / SupplierListItemRespVO` #### 使用场景 资源管理或车务管理打开“设置供应商”候选列表时调用;搜索时沿用 `keyword`。 #### 入参 | 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | |------|------|------|------|------|------| | `resourceModule` | Query | String | 场景必填 | 与 `resourceId` 同传 | 当前资源模块,不是供应商类型 | | `resourceId` | Query | String | 场景必填 | 正整数,与 `resourceModule` 同传 | 当前资源 ID | | `keyword` | Query | String | 否 | 最长 500 | 搜索关键字 | | `limit` | Query | Integer | 否 | 1~200,默认 50 | 候选列表建议传 200 | | `typeCode` | Query | String | 否 | 通用列表兼容参数 | 设置供应商场景不要传;资源上下文存在时后端忽略调用方值 | | `status` | Query | String | 否 | 通用列表兼容参数 | 设置供应商场景不要传;资源上下文存在时后端固定 `ACTIVE` | #### 出参 `Result>` | 字段 | 类型 | 说明 | |------|------|------| | `data[].supplierId` | String | 供应商 ID | | `data[].supplierNo` | String | 供应商编号 | | `data[].fullName` | String | 供应商全称 | | `data[].shortName` | String | 供应商简称 | | `data[].types` | Array | 类型列表;元素含 `typeCode`、`typeName`、`isPrimary` | | `data[].status` | String | 资源上下文场景恒为 `ACTIVE` | | 其他既有字段 | - | 响应结构未变化 | #### 请求示例 ```http GET /admin/supplier/items/list?resourceModule=SCENIC&resourceId=3001000000000000019&limit=200 ``` #### 响应示例 ```json { "code": 200, "message": "成功", "data": [ { "supplierId": "2091381643661983746", "supplierNo": "SUP2091381643661983746", "fullName": "示例景区供应商", "types": [{ "typeCode": "SCENIC", "typeName": "景区", "isPrimary": true }], "status": "ACTIVE" } ], "success": true } ``` #### 空数据 / 降级响应 没有符合条件的供应商时返回 `data: []`;资源不存在、上下文不完整或映射不可用时失败关闭,不降级为全量列表。 ```json { "code": 200, "message": "成功", "data": [], "success": true } ``` #### 错误响应 ```json { "code": 400, "message": "resourceModule与resourceId必须同时提供或同时省略", "data": null, "success": false } ``` #### 业务边界 - 完整资源上下文下,后端校验供应商列表权限、资源关系查看权限、资源存在性和数据范围。 - 后端只返回状态为 `ACTIVE` 且包含映射类型的供应商;调用方传入的 `typeCode`、`status` 不会覆盖该规则。 - 不传资源上下文时,原有 `typeCode`、`status`、`keyword`、`limit` 通用查询行为保持不变。 ### 2. 设置或改绑资源供应商 `PUT /admin/supplier/resource-relations/{resourceModule}/{resourceId}/update` **VO**: `SupplierResourceReassignReqVO / SupplierResourceRelationRespVO` #### 使用场景 用户确认候选供应商后首次设置或改绑当前资源的供应商。 #### 入参 | 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | |------|------|------|------|------|------| | `resourceModule` | Path | String | 是 | 见映射表 | 当前资源模块 | | `resourceId` | Path | String | 是 | 正整数 | 当前资源 ID | | `supplierId` | Body | String | 是 | 正整数 | 候选供应商 ID | | `requiredTypeCode` | Body | String | 否 | 最长 64 | 七个固定映射模块应省略,由后端解析 | | `remark` | Body | String | 否 | 最长 500 | 关系备注 | | `changeReason` | Body | String | 是 | 非空,最长 500 | 设置或改绑原因 | | `expectedCurrentSupplierId` | Body | String | 改绑时必填 | 与版本时间同传 | 当前关系供应商 ID | | `expectedRelationUpdateTime` | Body | String | 改绑时必填 | 与当前供应商 ID 同传 | 当前关系并发版本 | #### 出参 `Result` | 字段 | 类型 | 说明 | |------|------|------| | `data.supplierId` | String | 生效供应商 ID | | `data.resourceModule` | String | 资源模块 | | `data.resourceId` | String | 资源 ID | | `data.requiredTypeCode` | String | 后端解析并冻结的供应商类型 | | `data.updateTime` | String | 后续改绑或解绑使用的并发版本 | | 其他既有字段 | - | 响应结构未变化 | #### 请求示例 ```json { "supplierId": "2091381643661983746", "changeReason": "设置资源供应商" } ``` #### 响应示例 ```json { "code": 200, "message": "成功", "data": { "supplierId": "2091381643661983746", "resourceModule": "SUPPLIES_COMBO", "resourceId": "2046122595429806082", "requiredTypeCode": "SUPPLIES_COMBO", "updateTime": "2026-09-04 12:00:00" }, "success": true } ``` #### 空数据 / 降级响应 写接口成功时返回完整关系;校验失败时返回业务错误和 `data: null`,不会创建或改写关系。 #### 错误响应 ```json { "code": 395037, "message": "供应商类型不满足资源关联要求", "data": null, "success": false } ``` #### 业务边界 - 七个固定映射模块由后端确定 `requiredTypeCode`;前端不要提交本地映射值。 - 供应商必须处于 `ACTIVE` 且包含所需类型;失败时关系保持不变。 - 已有关系改绑仍必须传成对的并发版本字段,既有审计、权限和数据范围规则不变。 ## 四、契约约束与正确调用方式 | 场景 | 正确调用 | 错误调用 | |------|----------|----------| | 打开候选列表 | `resourceModule=SCENIC&resourceId={id}&limit=200` | 前端把 `SCENIC` 映射为 `typeCode` 后只按类型查询 | | 搜索候选 | 上述参数继续加 `keyword` | 搜索时丢失资源上下文 | | 设置/改绑 | Path 传资源上下文,Body 省略 `requiredTypeCode` | 前端根据字典或资源分类拼 `requiredTypeCode` | 前端应删除资源分类与供应商类型的本地映射。`supplier_type` 在“系统管理 → 字典管理”维护供应商类型的名称、状态和排序;它不是资源模块映射配置。资源模块映射由后端统一维护。 ## 五、数据库行为 设置或改绑时,关系中冻结后端解析出的 `requiredTypeCode`;本次无表结构、存量数据迁移或跨库写入变化,原有关系审计行为保持不变。 ## 六、边界行为 - `resourceModule` 与 `resourceId` 只传一个 → `400`,`resourceModule与resourceId必须同时提供或同时省略`。 - 未知模块 → `395034`,`不支持的资源模块`;资源不存在或已删除 → `395035`。 - `ACTIVITY`、`COST_ITEM`、`STAFF` 本工单没有默认映射,按资源上下文查询会以 `400 requiredTypeCode不能为空` 失败关闭。 - 映射类型在 `supplier_type` 字典缺失或停用 → `400`,`供应商类型不合法或已停用`。 - 未登录 → 应用响应 `401`;无权限或超出资源数据范围 → 拒绝访问。 ## 六.5、枚举 / 数据字典 ### resourceModule 与 supplier_type **所属字段**: `SupplierListReqVO.resourceModule / SupplierResourceRelationRespVO.requiredTypeCode` | **类型**: `String` | `resourceModule` | 后端要求的 `supplier_type` | 页面 | |------------------|-------------------------------|------| | `SCENIC` | `SCENIC` | 景区管理 | | `RESTAURANT` | `RESTAURANT` | 餐厅管理 | | `SUPPLIES` | `SUPPLIES` | 备品管理 | | `SUPPLIES_COMBO` | `SUPPLIES_COMBO` | 组合配品 | | `HOTEL` | `HOTEL` | 酒店管理 | | `SERVICE` | `SERVICE` | 服务管理 | | `VEHICLE` | `FLEET` | 车务管理-车队管理 | ## 六.6、修改前后对比 ### 字段级对比 | 字段 | 改前 | 改后 | |------|------|------| | 候选查询资源上下文 | 无 | 新增可选 `resourceModule`、`resourceId`,必须成对传入 | | `requiredTypeCode` | 组合备品可能由调用方误传 `SUPPLIES` | 固定映射模块可省略,组合备品由后端解析为 `SUPPLIES_COMBO` | ### 行为级对比 | 行为 | 改前 | 改后 | |------|------|------| | 设置供应商候选 | 依赖前端映射 `typeCode`,可能展示不对应类型 | 后端按真实资源上下文过滤 `ACTIVE` 且匹配的供应商 | | 无资源上下文的通用列表 | 按调用方筛选 | 保持不变 | ## 六.7、影响评估 - **是否破坏向后兼容**: 否;无资源上下文的原调用保持兼容。 - **前端是否必须同步上线**: 是。 - **前端 workaround 清理点**: 删除资源分类与供应商类型本地映射;候选查询改传 `resourceModule`、`resourceId`,绑定请求不再拼 `requiredTypeCode`。 ## 七、不影响范围 - **仅影响**: 管理后台资源管理、车务管理的供应商候选和设置/改绑类型解析。 - **零影响**: 供应商分页管理、供应商注册审批、既有响应字段、数据库结构、Redis、MQ 和其他前端源码。 ## 八、测试环境已验证 ```text SCENIC 候选:忽略错误 typeCode/status,只返回 ACTIVE + SCENIC,FLEET-only 为 0 ✓ SUPPLIES_COMBO 候选及绑定:返回/冻结 SUPPLIES_COMBO,绑定后已解绑恢复原关系状态 ✓ VEHICLE 候选:忽略错误 typeCode/status,只返回 ACTIVE + FLEET ✓ 通用列表 typeCode/status/keyword/limit:保持兼容 ✓ 上下文不完整、无默认映射、失效类型、资源不存在:均失败关闭 ✓ ``` ## 九、相关历史 PR | PR / 提交 | Issue | 说明 | 是否仍有效 | |-----------|-------|------|------------| | changelog `5046bce` | #7042 | 原要求前端维护映射 | ❌ 已更正 | | changelog `a0daab2` | #7042 | 撤销前端映射要求,转后端工单 | ✅ 有效 | | **PR #7064** | **#7059** | 后端按资源上下文解析、过滤并修正组合备品映射 | ✅ 最新 | ## 十、相关文档 - 关联 Issue: [wx/HL#7059](https://git.1814.love:8443/wx/HL/issues/7059) - 关联 PR: [wx/HL#7064](https://git.1814.love:8443/wx/HL/pulls/7064) - 被更正记录: [#7042 Changelog](./03_7042_设置供应商列表按资源类型过滤-前端缺陷-管理后台.md) ## 关联 / 联系人 ### 链接 - **Issue**: [#7059](https://git.1814.love:8443/wx/HL/issues/7059) - **PR**: [#7064](https://git.1814.love:8443/wx/HL/pulls/7064) - **Merge commit**: [5999b532e9f9725ac3b36f859ee48f6f0b8aa43c](https://git.1814.love:8443/wx/HL/commit/5999b532e9f9725ac3b36f859ee48f6f0b8aa43c) ### 联系人 - **后端负责人**: @lc