新增供应商三级地址保存与回显契约(#6739)
changelog-filename-gate / validate (push) Successful in 3s

这个提交包含在:
lc
2026-08-30 15:44:39 +08:00
父节点 5c52926269
当前提交 17bb0ef2bf
@@ -0,0 +1,288 @@
---
schema: "hl-changelog/v2"
ticket: "6739"
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: ""
status_note: "供应商写接口现接收最下级 countyId;基本信息详情返回 provinceId、prefectureId、countyId 和 address。当前状态:待前端接入三级联动并按字段回显。"
updated_at: "2026-08-30"
base: "dev-v3"
---
# 供应商三级地址保存与回显
`countyId` 保存三级联动的最下级区县 ID,`address` 只保存详细地址,例如“某某路 1 号”。前端不要再使用 `addressId`。
## 二、变更接口清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---:|---|---|---|---|---|
| 1 | 新增供应商草稿 | POST | `/admin/supplier/items/add` | 请求字段 | 可传 `countyId`、`address` |
| 2 | 修改供应商 | PUT | `/admin/supplier/items/{supplierId}/update` | 请求字段 | 可更新 `countyId`、`address` |
| 3 | 提交供应商 | POST | `/admin/supplier/items/{supplierId}/submit` | 请求字段 | 完整表单可传 `countyId`、`address` |
| 4 | 查询供应商基本信息 | GET | `/admin/supplier/items/{supplierId}/basic-info/view` | 响应字段 | 顶层返回三级 ID 与 `address` |
## 三、接口详情
### 1. 新增供应商草稿 `POST /admin/supplier/items/add`
**VO**: `SupplierDraftSaveReqVO / SupplierWriteRespVO`
#### 使用场景
新增草稿时同时保存区县选择和详细地址。
#### 入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| `countyId` | Body | String | 否 | 正整数 | 三级联动最后一级区县 ID |
| `address` | Body | String | 否 | 最长 500 字符 | 详细地址,不拼接省市区名称 |
| `fullName` / `taxNo` / `mainCooperation` | Body | String | 是 | 沿用既有规则 | 其他新增必填字段 |
#### 出参
| 字段 | 类型 | 说明 |
|---|---|---|
| `data.supplierId` | String | 新供应商 ID |
| `data.updateTime` | String | 后续修改使用的并发版本 |
#### 请求示例
```json
{"fullName":"示例旅行服务有限公司","taxNo":"91350211M000100Y46","countyId":"376","address":"某某路1号","mainCooperation":"景区合作"}
```
#### 响应示例
```json
{"code":200,"message":"成功","success":true,"data":{"supplierId":"2093966831894056961","status":"DRAFT","updateTime":"2026-08-30 15:39:31"}}
```
#### 空数据 / 降级响应
省略 `countyId` 或 `address` 时按 `null` 保存;依赖或业务校验失败时不产生部分写入。
#### 错误响应
```json
{"code":400,"message":"区县ID必须为正数","success":false,"data":null}
```
#### 业务边界
- 有三级联动选择结果时只传最后一级 `countyId`。
- `addressId` 不是本接口字段。
### 2. 修改供应商 `PUT /admin/supplier/items/{supplierId}/update`
**VO**: `SupplierUpdateReqVO / SupplierWriteRespVO`
#### 使用场景
编辑页修改区县或详细地址。
#### 入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| `supplierId` | Path | String | 是 | 正整数 | 供应商 ID |
| `countyId` | Body | String | 否 | 正整数 | 新的最下级区县 ID |
| `address` | Body | String | 否 | 最长 500 字符 | 新的详细地址 |
| `expectedUpdateTime` | Body | String | 是 | `yyyy-MM-dd HH:mm:ss` | 详情最新并发版本 |
#### 出参
| 字段 | 类型 | 说明 |
|---|---|---|
| `data.supplierId` | String | 供应商 ID |
| `data.updateTime` | String | 保存后的新并发版本 |
#### 请求示例
```json
{"countyId":"377","address":"某某路2号","expectedUpdateTime":"2026-08-30 15:39:31"}
```
#### 响应示例
```json
{"code":200,"message":"成功","success":true,"data":{"supplierId":"2093966831894056961","status":"DRAFT","updateTime":"2026-08-30 15:39:42"}}
```
#### 空数据 / 降级响应
省略 `countyId` 或 `address` 表示该字段不修改;失败时原值和版本保持不变。
#### 错误响应
```json
{"code":400,"message":"区县ID必须为正数","success":false,"data":null}
```
#### 业务边界
- 修改成功后使用响应中的新 `updateTime` 重新查询详情。
- 非正数 `countyId` 在写入前拒绝。
### 3. 提交供应商 `POST /admin/supplier/items/{supplierId}/submit`
**VO**: `SupplierSubmitReqVO / SupplierApprovalCommandRespVO`
#### 使用场景
提交完整供应商表单进入审批时一并保存区县和详细地址。
#### 入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| `supplierId` | Path | String | 是 | 正整数 | 草稿供应商 ID |
| `countyId` | Body | String | 否 | 正整数 | 最下级区县 ID |
| `address` | Body | String | 否 | 最长 500 字符 | 详细地址 |
| `expectedUpdateTime` | Body | String | 是 | `yyyy-MM-dd HH:mm:ss` | 当前并发版本 |
#### 出参
| 字段 | 类型 | 说明 |
|---|---|---|
| `data.approvalLogId` | String | 审批记录 ID |
| `data.approvalStatus` | String | 审批状态 |
#### 请求示例
```json
{"fullName":"示例旅行服务有限公司","taxNo":"91350211M000100Y46","countyId":"377","address":"某某路2号","mainCooperation":"景区合作","expectedUpdateTime":"2026-08-30 15:39:42"}
```
#### 响应示例
```json
{"code":200,"message":"成功","success":true,"data":{"approvalLogId":"2093967000000000001","approvalStatus":"APPROVED"}}
```
#### 空数据 / 降级响应
`countyId`、`address` 为空时按完整表单既有规则处理;提交失败不推进审批状态。
#### 错误响应
```json
{"code":400,"message":"区县ID必须为正数","success":false,"data":null}
```
#### 业务边界
- 仍须提交完整表单和最新 `expectedUpdateTime`。
- 本次不改变既有审批、幂等和状态门禁。
### 4. 查询供应商基本信息 `GET /admin/supplier/items/{supplierId}/basic-info/view`
**VO**: `SupplierBasicInfoRespVO`
#### 使用场景
编辑页读取三级联动默认值和详细地址。
#### 入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| `supplierId` | Path | String | 是 | 正整数 | 供应商 ID |
#### 出参
| 字段 | 类型 | 说明 |
|---|---|---|
| `data.provinceId` | String/null | 省级 ID |
| `data.prefectureId` | String/null | 市级 ID |
| `data.countyId` | String/null | 已保存的最下级区县 ID |
| `data.address` | String/null | 已保存的详细地址原值 |
#### 请求示例
```http
GET /admin/supplier/items/2093966831894056961/basic-info/view
Authorization: Bearer <admin-token>
```
#### 响应示例
```json
{"code":200,"message":"成功","success":true,"data":{"supplierId":"2093966831894056961","provinceId":"1","prefectureId":"35","countyId":"377","address":"某某路2号","updateTime":"2026-08-30 15:39:42"}}
```
#### 空数据 / 降级响应
历史供应商没有 `countyId` 时三个行政区划 ID 均为 `null`,`address` 仍按历史值返回。
#### 错误响应
```json
{"code":395001,"message":"供应商不存在","success":false,"data":null}
```
#### 业务边界
- 三个行政区划 ID 均按 JSON 字符串返回。
- 行政区划父链不可用或不完整时失败关闭,不伪造 ID。
## 四、契约约束与正确调用方式
1. 用 `/admin/region/children` 逐级选择,将最后一级 ID 作为 `countyId`,门牌内容单独放入 `address`。
2. 编辑页按 `provinceId → prefectureId → countyId` 设置默认选中,并用 `address` 初始化详细地址输入框。
3. 前端字段统一命名为 `countyId`;保存后使用新版本重新查询详情。
## 五、数据库行为
- 写接口成功后,后续详情查询返回已保存的 `countyId` 和 `address`。
- 非正数 `countyId` 校验失败时不修改原值或并发版本。
- 历史供应商不自动补行政区划 ID。
## 六、边界行为
- 未认证返回业务码 `401`;供应商不存在或已删除返回 `395001`。
- 业务失败可能仍使用 HTTP 200,前端须同时判断 `code` 与 `success`。
- `address` 不包含省市区中文文本;省市区展示由三级 ID 对应的选项生成。
## 六.6、修改前后对比
| 项目 | 修改前 | 修改后 |
|---|---|---|
| 写请求 | 仅保存详细地址 | 可同时保存最下级 `countyId` 与详细地址 |
| 详情回显 | 仅有 `address` | 顶层增加三个行政区划 ID,继续返回 `address` |
## 六.7、影响评估
- **是否破坏向后兼容**:否,历史空值继续返回 `null`。
- **前端是否必须同步上线**:是,需要传 `countyId` 并消费三级回显字段。
- **前端 workaround 清理点**:移除 `addressId` 映射和自行解析完整中文地址的逻辑。
## 七、不影响范围
- 不改变供应商权限、状态机、审批、并发和错误码。
- 不改变行政区划联动接口契约,也不影响其他资源模块。
## 八、测试环境已验证
- 新增与修改后可回读对应 `countyId`、`address`,详情三个行政区划 ID 均为字符串。
- 非正数 `countyId` 返回 `400` 且原数据不变;未认证返回 `401`;验收草稿已清理。
## 十、相关文档
- [Issue #6739](https://git.1814.love:8443/wx/HL/issues/6739)
- [PR #6744](https://git.1814.love:8443/wx/HL/pulls/6744)
## 关联 / 联系人
- **合并提交**: [2d24b3290](https://git.1814.love:8443/wx/HL/commit/2d24b32908bffb0e7ac95fd31b33cdfe56ae69f5)
- **后端负责人**: @lc
- **当前状态**: 待前端接入