diff --git a/changelogs-v2/2026-08/30_6710_供应商联系人快照版本字段兼容-修改接口-管理后台.md b/changelogs-v2/2026-08/30_6710_供应商联系人快照版本字段兼容-修改接口-管理后台.md new file mode 100644 index 00000000..f0862ef9 --- /dev/null +++ b/changelogs-v2/2026-08/30_6710_供应商联系人快照版本字段兼容-修改接口-管理后台.md @@ -0,0 +1,227 @@ +--- +schema: "hl-changelog/v2" +ticket: "6710" +title: "供应商联系人快照版本字段兼容" +consumer: "admin" +author: "lc(GIT)" +change_type: "修改接口" +backend_status: "deployed" +gateway_status: "verified" +frontend_status: "pending" +frontend_owner: "" +frontend_ref: "" +target_release: "" +verified_at: "2026-08-30" +status_note: "PR #6712 已合并 dev-v3,合并提交 7f3f944bf361b7ae41424c43b29262fb634fe791 已精确部署 TEST。真实 Gateway 已验证联系人详情返回的 updateTime 可直接作为条目级并发版本回传,并能一次新增多个姓名、联系电话重复的联系人;验收草稿已清理。当前状态:待前端处理。" +updated_at: "2026-08-30" +base: "dev-v3" +--- + +# 供应商联系人快照版本字段兼容 + +供应商编辑接口现已兼容详情响应中的 `contacts[].updateTime`:管理端保留已有联系人并新增多个联系人时,可以将详情联系人对象原样回传,不再因版本字段名不一致收到“联系人快照项不合法”。联系人姓名和联系电话允许重复。 + +## 二、变更接口清单 + +| # | 接口 | 方法 | 路径 | 变更类型 | 说明 | +|---:|---|---|---|---|---| +| 1 | 编辑供应商 | PUT | `/admin/supplier/items/{supplierId}/update` | 请求字段兼容 | 已有联系人条目同时接受 `expectedUpdateTime` 和详情字段 `updateTime` 作为并发版本 | + +详情接口路径和响应结构未修改: + +| 接口 | 方法 | 路径 | 本次用途 | +|---|---|---|---| +| 查询供应商基本信息 | GET | `/admin/supplier/items/{supplierId}/basic-info/view` | 返回主体 `updateTime`、联系人 `contactId` 和联系人 `updateTime` | + +业务失败可能仍返回 HTTP 200,调用方必须同时判断统一响应中的 `code`、`success`、`message` 和 `data`。 + +## 三、接口详情 + +### 1. 编辑供应商 `PUT /admin/supplier/items/{supplierId}/update` + +**VO**: `SupplierUpdateReqVO / SupplierContactMergeReqVO / SupplierWriteRespVO` + +#### 使用场景 + +管理端编辑供应商时,需要保留详情中的已有联系人并在同一次保存中新增一个或多个联系人。调用方可以直接使用详情返回的联系人 `updateTime` 作为该条目的并发版本。 + +#### 入参 + +| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | +|---|---|---|---:|---|---| +| `supplierId` | Path | String | 是 | 正整数 ID 字符串 | 目标供应商 | +| `expectedUpdateTime` | Body | String | 是 | `yyyy-MM-dd HH:mm:ss` | 供应商主体并发版本,取详情顶层 `updateTime` | +| `contacts` | Body | Array | 否 | 最多 100 项 | 完整联系人快照;省略表示不修改,空数组表示清空 | +| `contacts[].contactId` | Body | String | 已有项是 | 正整数 ID 字符串 | 为空表示新增联系人 | +| `contacts[].expectedUpdateTime` | Body | String | 已有项二选一 | `yyyy-MM-dd HH:mm:ss` | 规范的联系人条目级并发版本字段 | +| `contacts[].updateTime` | Body | String | 已有项二选一 | `yyyy-MM-dd HH:mm:ss` | 本次新增兼容名,可直接使用详情响应值 | +| `contacts[].contactName` | Body | String | 新增项按既有规则 | 最长 500 字符 | 允许与已有或同批新增联系人重复 | +| `contacts[].contactPhone` | Body | String | 新增项按既有规则 | 7~20 位合法电话格式 | 允许与已有或同批新增联系人重复 | +| `contacts[].contactRole` | Body | String | 新增项是 | 当前生效的 `sup_content_role.dictValue` | 沿用既有角色字典校验 | +| `contacts[].isPrimary` | Body | Boolean | 否 | 非空快照最终恰好一个默认联系人 | 沿用既有默认联系人规则 | + +已有联系人仍必须提供 `contactId`,并通过 `expectedUpdateTime` 或 `updateTime` 携带条目级并发版本;本次只兼容字段名,没有取消并发校验。新增联系人不发送 `contactId` 和版本字段。 + +#### 出参 `Result` + +| 字段 | 类型 | 说明 | +|---|---|---| +| `code` | Number | 业务码;成功为 `200` | +| `success` | Boolean | 业务是否成功 | +| `data.supplierId` | String | 供应商 ID | +| `data.supplierNo` | String | 供应商业务编号 | +| `data.status` | String | 保存后的供应商状态 | +| `data.onboardingStage` | String | 当前建档阶段 | +| `data.initialAccounts` | Array | 当前初始结算账户摘要 | +| `data.updateTime` | String | 保存后的主体并发版本 | + +#### 请求示例 + +以下请求保留一名已有联系人,并新增两名姓名、电话相同的联系人: + +```json +{ + "expectedUpdateTime": "2026-08-30 10:04:18", + "contacts": [ + { + "contactId": "2093000000000000001", + "contactName": "张三", + "contactPhone": "18501941408", + "contactRole": "contentBus", + "isPrimary": true, + "updateTime": "2026-08-30 10:04:19" + }, + { + "contactName": "张三", + "contactPhone": "18501941408", + "contactRole": "contentMoney", + "isPrimary": false + }, + { + "contactName": "张三", + "contactPhone": "18501941408", + "contactRole": "contentMoney", + "isPrimary": false + } + ] +} +``` + +#### 响应示例 + +```json +{ + "code": 200, + "message": "成功", + "success": true, + "data": { + "supplierId": "2093000000000000000", + "supplierNo": "SUP2093000000000000000", + "status": "DRAFT", + "onboardingStage": "PROFILE_DRAFT", + "initialAccounts": [], + "updateTime": "2026-08-30 10:04:29" + } +} +``` + +#### 空数据 / 降级响应 + +- 省略 `contacts` 或传 `null` 表示本次不修改联系人;传空数组表示按既有快照语义清空联系人。 +- 本次不新增降级返回;联系人角色字典等既有依赖异常时继续失败关闭,不产生部分写入。 + +#### 错误响应 + +已有联系人缺少两种版本字段时,继续返回既有快照校验错误: + +```json +{ + "code": 400, + "message": "联系人快照项不合法", + "success": false, + "data": null +} +``` + +联系人版本已过期时,继续返回既有并发错误: + +```json +{ + "code": 395014, + "message": "数据已被他人修改,请刷新后重试", + "success": false, + "data": null +} +``` + +#### 业务边界 + +- 快照字段和版本均有效时返回 `code=200`、`success=true`,并返回新的主体 `data.updateTime`。 +- 已有联系人缺少两种版本字段时,继续返回业务码 `400`、消息“联系人快照项不合法”。 +- 联系人版本已过期时,继续返回业务码 `395014`、消息“数据已被他人修改,请刷新后重试”,整次请求零写入。 +- 姓名或联系电话重复本身不是拒绝条件,不新增重复值错误码。 +- 接口继续要求有效管理端身份、既有可信角色和服务端供应商写权限。 +- 本次不改变供应商状态门禁、聚合锁、幂等、审计或事务边界。 + +## 四、契约约束与正确调用方式 + +1. 进入编辑页先读取供应商详情,保留顶层 `updateTime` 及每个已有联系人的 `contactId`、`updateTime`。 +2. 提交时把顶层 `updateTime` 放入请求的 `expectedUpdateTime`。 +3. 已有联系人可以保留详情对象的 `updateTime` 字段原样提交;新增联系人不要伪造 `contactId` 或版本。 +4. 保存成功后重新读取详情,以新的主体和联系人版本作为下一次编辑的并发基线。 + +## 五、数据库行为 + +- 本次不新增或修改数据库 migration、索引及唯一约束。 +- 姓名和联系电话继续按既有方式存储;没有按这两个字段新增去重或唯一性限制。 +- 联系人新增、更新、软删除、默认项归一、审计及主体版本推进仍在既有供应商聚合事务内完成。 +- 参数、权限或并发校验失败时不产生联系人部分写入。 + +## 六、边界行为 + +- 未登录请求继续由 Gateway 拒绝;本次不改变认证级别。 +- 无供应商写权限、供应商不存在、状态不允许或主体并发版本过期时继续按既有错误语义失败。 +- 联系人 `contactId` 必须属于当前供应商;重复 ID、无效 ID 或已软删除 ID 继续被拒绝。 +- 新增联系人仍需满足姓名、电话格式、角色字典和默认联系人等既有规则;只允许姓名或电话的业务值重复。 +- 成功保存后应重新读取详情,使用服务端返回的新版本继续编辑。 + +## 六.6、修改前后对比 + +| 项目 | 修改前 | 修改后 | +|---|---|---| +| 已有联系人版本字段 | 请求只识别 `contacts[].expectedUpdateTime`;详情对象原样回传的 `updateTime` 未被识别 | 同时识别规范字段 `expectedUpdateTime` 和详情字段 `updateTime` | +| 条目级乐观并发 | 已有联系人必须携带有效版本 | 保持不变 | +| 姓名、电话重复 | 无重复值限制 | 保持不变;重复值不会被拒绝 | +| 响应字段 | 详情返回 `contacts[].updateTime` | 保持不变 | + +## 六.7、影响评估 + +- **是否破坏向后兼容**:否;继续发送 `contacts[].expectedUpdateTime` 的调用方不受影响。 +- **前端是否必须同步上线**:是;管理端应保留详情联系人 `updateTime` 并随已有联系人回传,或显式映射为 `expectedUpdateTime`。 +- **前端 workaround 清理点**:无需为联系人姓名或电话重复做前置拦截;不得删除联系人条目级并发版本。 +- **响应与错误码影响**:响应结构和错误码不变,仅扩展请求字段兼容名。 + +## 七、不影响范围 + +- 不修改供应商创建、提交审批、合同、账户、状态机或资源关系接口。 +- 不修改 Gateway 路由、认证策略、角色、权限点、幂等、聚合锁或事务边界。 +- 不修改数据库结构、历史数据、配置、Redis 或 MQ 契约。 +- 本工单仅交付后端和接口 Changelog,不修改任何前端源码或资源。 + +## 八、测试环境已验证 + +- 合并提交 `7f3f944bf361b7ae41424c43b29262fb634fe791` 已精确部署到 TEST。 +- 通过真实 TEST Gateway 将详情返回的已有联系人 `updateTime` 原样放入编辑快照,并在同一请求新增两名姓名、联系电话均与已有联系人相同的联系人;返回 `code=200`,详情回读为 3 名联系人。 +- 使用过期联系人 `updateTime` 再次提交返回 `395014`;随后回读主体版本及 3 名联系人均未变化。 +- 未认证详情请求返回业务码 `401`;验收草稿已通过正式删除接口清理,删除后详情返回 `395001`。 + +## 十、相关文档 + +- Issue [#6710](https://git.1814.love:8443/wx/HL/issues/6710) +- PR [#6712](https://git.1814.love:8443/wx/HL/pulls/6712) +- 合并提交 [7f3f944bf361b7ae41424c43b29262fb634fe791](https://git.1814.love:8443/wx/HL/commit/7f3f944bf361b7ae41424c43b29262fb634fe791) + +## 关联 / 联系人 + +- **后端负责人**:@lc +- **当前状态**:待前端处理