docs: 交付供应商法人证件接口(#6391)
changelog-filename-gate / validate (push) Successful in 2s

这个提交包含在:
lc
2026-08-26 11:57:09 +08:00
父节点 42a16b78c6
当前提交 6831ec3128
@@ -0,0 +1,369 @@
---
schema: "hl-changelog/v2"
ticket: "6391"
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: "PR #6401 已合并 dev-v3 并部署 TEST;供应商创建、更新、提交新增法人身份证号及正反面永久地址,详情仅返回脱敏证件号。旧客户端省略三字段时保持兼容,前端待接入输入与双面上传。"
updated_at: "2026-08-26"
base: "dev-v3"
---
# 🔧 供应商法人证件号与身份证正反面
供应商“基本信息-法定代表人”新增身份证号、人像面和国徽面三个字段。身份证图片继续使用既有文件上传能力,本次接口只接收上传完成后的永久 HTTPS 地址,不新增上传或 OCR 接口。
## 变更接口
| 方法 | 路径 | 权限 | 变化 |
|---|---|---|---|
| POST | `/admin/supplier/items/add` | `supplier:create` | 创建草稿可保存三个法人证件字段 |
| PUT | `/admin/supplier/items/{supplierId}/update` | `supplier:update` | 增量更新三个法人证件字段 |
| POST | `/admin/supplier/items/{supplierId}/submit` | `supplier:update`、`supplier:approval:submit` | 完整注册表单可提交三个法人证件字段 |
| GET | `/admin/supplier/items/{supplierId}/basic-info/view` | `supplier:view` | 返回脱敏证件号及身份证正反面地址 |
## 通用字段与校验
| 字段 | 类型 | 必填 | 规则 |
|---|---|---|---|
| `legalRepresentativeIdNo` | string | 条件必填 | 18 位中国大陆居民身份证号;校验长度、出生日期、顺序码及校验位;末位小写 `x` 会规范为大写 `X` |
| `legalRepresentativeIdCardFrontUrl` | string | 条件必填 | 身份证人像面永久地址,最长 1000 字符;必须为公网 HTTPS 地址,且不能含账号密码、查询串或片段 |
| `legalRepresentativeIdCardBackUrl` | string | 条件必填 | 身份证国徽面永久地址,规则同人像面 |
三个字段必须“全部省略”或“同时提供”:
- 全部省略:兼容旧客户端和没有法人证件数据的存量供应商。
- 任意一个有值:三个字段必须同时有值,不能只保存证件号或单面图片。
- 法定代表人可能对应多个供应商,证件号不作为供应商之间的唯一键。
- 写接口的成功响应不回传证件号;需要展示时调用详情接口。
- 统一响应可能以 HTTP 200 承载业务失败,必须同时判断 `code`、`success` 和 `data`。
## 1. 创建供应商草稿
### 使用场景
在新建供应商基本信息时,同时保存法定代表人身份证号及正反面扫描件地址。
### 请求
```http
POST /admin/supplier/items/add
Authorization: Bearer <管理员令牌>
Content-Type: application/json
```
本次新增的三个字段遵循上方通用规则;创建草稿的既有最低必填字段仍为 `fullName`、`taxNo`、`mainCooperation`。
典型成功请求:
```json
{
"fullName": "法人证件联调示例供应商",
"taxNo": "L6391EXAMPLE001",
"legalRepresentative": "示例法人",
"legalRepresentativeIdNo": "11010519491231002x",
"legalRepresentativeIdCardFrontUrl": "https://files.example.com/supplier/id/front.jpg",
"legalRepresentativeIdCardBackUrl": "https://files.example.com/supplier/id/back.jpg",
"mainCooperation": "旅游资源供应"
}
```
典型成功响应:
```json
{
"code": 200,
"message": "成功",
"success": true,
"data": {
"supplierId": "1900000000000000001",
"supplierNo": null,
"status": "DRAFT",
"onboardingStage": "PROFILE_DRAFT",
"initialAccounts": [],
"updateTime": "2026-08-26 11:40:00"
}
}
```
兼容边界:旧客户端可完全省略三个新字段,其余请求保持原样。
异常请求(仅传人像面):
```json
{
"fullName": "法人证件联调示例供应商",
"taxNo": "L6391EXAMPLE001",
"legalRepresentativeIdCardFrontUrl": "https://files.example.com/supplier/id/front.jpg",
"mainCooperation": "旅游资源供应"
}
```
```json
{
"code": 400,
"message": "法定代表人证件号、人像面和国徽面必须同时提供",
"success": false,
"data": null
}
```
失败不会创建供应商草稿。
## 2. 更新供应商
### 使用场景
在供应商基本信息编辑页补录或替换完整的法人证件三字段。
### 请求
```http
PUT /admin/supplier/items/1900000000000000001/update
Authorization: Bearer <管理员令牌>
Content-Type: application/json
```
`changeReason` 和 `expectedUpdateTime` 沿用原接口必填约束;三个法人证件字段作为一组增量字段处理。典型成功请求:
```json
{
"legalRepresentative": "示例法人",
"legalRepresentativeIdNo": "11010519491231002X",
"legalRepresentativeIdCardFrontUrl": "https://files.example.com/supplier/id/front-v2.jpg",
"legalRepresentativeIdCardBackUrl": "https://files.example.com/supplier/id/back-v2.jpg",
"changeReason": "补录法人身份证扫描件",
"expectedUpdateTime": "2026-08-26 11:40:00"
}
```
典型成功响应:
```json
{
"code": 200,
"message": "成功",
"success": true,
"data": {
"supplierId": "1900000000000000001",
"supplierNo": null,
"status": "DRAFT",
"onboardingStage": "PROFILE_DRAFT",
"initialAccounts": [],
"updateTime": "2026-08-26 11:42:00"
}
}
```
兼容边界:三个新字段全部省略时,不修改现有法人证件数据。若请求中出现任一新字段,服务端会与当前值合并后再次检查三字段是否完整。
异常请求(身份证校验位错误):
```json
{
"legalRepresentativeIdNo": "110105194912310021",
"legalRepresentativeIdCardFrontUrl": "https://files.example.com/supplier/id/front-v2.jpg",
"legalRepresentativeIdCardBackUrl": "https://files.example.com/supplier/id/back-v2.jpg",
"changeReason": "补录法人身份证扫描件",
"expectedUpdateTime": "2026-08-26 11:40:00"
}
```
```json
{
"code": 400,
"message": "法定代表人证件号的日期或校验位不合法",
"success": false,
"data": null
}
```
失败时主体版本、法人证件数据和变更记录均保持原状。
## 3. 提交供应商注册审批
### 使用场景
提交草稿的完整注册表单时,将法人证件三字段一并纳入审批内容。
### 请求
```http
POST /admin/supplier/items/1900000000000000001/submit
Authorization: Bearer <管理员令牌>
Content-Type: application/json
```
本接口继续要求完整注册表单和当前 `expectedUpdateTime`。典型成功请求:
```json
{
"fullName": "法人证件联调示例供应商",
"taxNo": "L6391EXAMPLE001",
"legalRepresentative": "示例法人",
"legalRepresentativeIdNo": "11010519491231002X",
"legalRepresentativeIdCardFrontUrl": "https://files.example.com/supplier/id/front.jpg",
"legalRepresentativeIdCardBackUrl": "https://files.example.com/supplier/id/back.jpg",
"mainCooperation": "旅游资源供应",
"expectedUpdateTime": "2026-08-26 11:42:00"
}
```
典型成功响应:
```json
{
"code": 200,
"message": "成功",
"success": true,
"data": {
"approvalLogId": "1900000000000000101",
"requestNo": "SUP-REQ-20260826-0001",
"provider": "LOCAL_AUTO",
"approvalStatus": "APPROVED",
"spNo": null,
"spStatus": null,
"syncStatus": "APPLIED",
"submittedAt": "2026-08-26 11:43:00",
"finishedAt": "2026-08-26 11:43:00"
}
}
```
兼容边界:没有法人证件数据的旧草稿仍可按旧请求提交;若提交法人证件,则三字段必须完整。
异常请求(图片地址带查询串):
```json
{
"fullName": "法人证件联调示例供应商",
"taxNo": "L6391EXAMPLE001",
"legalRepresentativeIdNo": "11010519491231002X",
"legalRepresentativeIdCardFrontUrl": "https://files.example.com/supplier/id/front.jpg?token=temporary",
"legalRepresentativeIdCardBackUrl": "https://files.example.com/supplier/id/back.jpg",
"mainCooperation": "旅游资源供应",
"expectedUpdateTime": "2026-08-26 11:42:00"
}
```
```json
{
"code": 400,
"message": "法人证件人像面地址不在允许范围",
"success": false,
"data": null
}
```
失败时不会创建审批或改变供应商状态。
## 4. 查询供应商基本信息
### 使用场景
编辑页回显法人证件信息。证件号只返回掩码,不能用于恢复原文或再次提交;图片地址可用于有权限页面的预览。
### 请求
```http
GET /admin/supplier/items/1900000000000000001/basic-info/view
Authorization: Bearer <管理员令牌>
```
无请求体。
典型成功响应:
```json
{
"code": 200,
"message": "成功",
"success": true,
"data": {
"supplierId": "1900000000000000001",
"supplierNo": null,
"fullName": "法人证件联调示例供应商",
"shortName": null,
"tax_no": "L639****E001",
"legalRepresentative": "示例法人",
"legalRepresentativeIdNoMask": "110105********002X",
"legalRepresentativeIdCardFrontUrl": "https://files.example.com/supplier/id/front.jpg",
"legalRepresentativeIdCardBackUrl": "https://files.example.com/supplier/id/back.jpg",
"contactPhoneMask": null,
"establishDate": null,
"registeredCapital": null,
"businessScope": null,
"staffScale": null,
"mainCooperation": "旅游资源供应",
"status": "DRAFT",
"creditLevel": "B",
"totalScore": null,
"types": [],
"contacts": [],
"qualifications": [],
"updateTime": "2026-08-26 11:42:00"
}
}
```
兼容边界:存量供应商没有法人证件数据时,三个响应字段均为 `null`。响应中不存在 `legalRepresentativeIdNo` 明文字段。
未认证示例:
```json
{
"code": 401,
"message": "未认证或登录已失效",
"success": false,
"data": null
}
```
## 错误与前端处理
| 响应码 | 触发条件 | 前端处理 |
|---:|---|---|
| `400` | 身份证不是 18 位、出生日期/顺序码/校验位错误、三字段不完整、图片地址不符合规则 | 保留表单并定位到法人证件区域;不要自动重试 |
| `401` | 未登录或 Gateway 认证失效 | 进入统一重新登录流程 |
| `403` | 角色、功能权限或数据范围不足 | 隐藏无权操作并展示统一无权限提示 |
| `395014` | `expectedUpdateTime` 已过期 | 重新读取详情,提示用户确认后再提交 |
本次不新增业务错误码;参数失败继续使用统一 `400`。
## 前端改造清单
- 在“新建/编辑供应商-基本信息-法定代表人”后增加身份证号输入框、人像面上传和国徽面上传。
- 上传完成后提交永久 HTTPS 地址;不要提交临时签名 URL、查询参数 URL、Base64 或文件二进制。
- 前端可做 18 位长度和末位 `X/x` 预校验,但最终以服务端日期及校验位结果为准。
- 三字段联动必填;旧数据三个字段均为空时允许继续按原流程操作。
- 详情只展示 `legalRepresentativeIdNoMask`;不得寻找或缓存身份证号明文。
- 写成功后如需回显,重新调用详情接口,不要从写响应读取新字段。
## 验证证据
- 自动化:最新 `dev-v3` 的 Resource 全量测试 2111 项通过、0 失败、0 错误,38 项既有条件跳过;法人证件聚焦测试 89 项通过。
- TEST:Deploy Panel 任务 `118fcff1` 将目标提交 `de615b49e3ecef4be13bd6bc78b3100d08ef0bd2` 部署到双实例;该提交包含 #6391 合并提交 `b909c8f7dfd73712886a33b574c72030dde89d4f`,服务与 Nacos 健康检查通过。
- 真实 Gateway:7 组场景通过,覆盖合法创建、错误校验位零写入、详情脱敏与图片回显、未认证拒绝、非法更新零写入、旧客户端省略字段兼容和迁移状态。
- 清理:本轮验收草稿已通过业务删除接口软删除并保留正常删除审计,不遗留可用测试供应商。
## 撤回
1. 从最新 `dev-v3` 创建回退分支,revert #6401 合并提交并经独立 PR 合入。
2. 重新部署 `hl-resource-service`;新增的可空数据结构保留,不执行破坏性删除。
3. 旧客户端、存量供应商和已保存的安全数据保持兼容;无需恢复配置、Redis 或 MQ。
4. 经 Gateway 重跑旧请求、合法/非法证件号、三字段完整性、详情脱敏和失败零写入检查。
## 关联 / 联系人
- **Issue**: [#6391](https://git.1814.love:8443/wx/HL/issues/6391)
- **PR**: [#6401](https://git.1814.love:8443/wx/HL/pulls/6401)
- **合并提交**: [b909c8f7d](https://git.1814.love:8443/wx/HL/commit/b909c8f7dfd73712886a33b574c72030dde89d4f)
- **后端负责人**: @lc