文件
hl-api-changelog/changelogs-v2/2026-08/27_6476_供应商详情补齐地址备注并统一表单校验-修改接口-管理后台.md
T
2026-08-27 16:03:03 +08:00

18 KiB
原始文件 Blame 文件历史

schema, ticket, title, consumer, author, change_type, backend_status, gateway_status, frontend_status, frontend_owner, frontend_ref, target_release, verified_at, status_note, updated_at, base
schema ticket title consumer author change_type backend_status gateway_status frontend_status frontend_owner frontend_ref target_release verified_at status_note updated_at base
hl-changelog/v2 6476 供应商详情补齐地址备注并统一表单校验 admin lc(GIT) 修改接口 deployed verified verified mmg 6635a2ae v2.1 2026-08-27 PR #6517 已合并 dev-v3(合并提交 a952a04c);hl-resource-service 已随 dev-v3 精确提交 b269e5fd 由 Deploy Panel 任务 938ca09e 发布 TEST。真实 TEST 身份已验证 address/remark 创建、详情、更新回显,创建/更新同口径校验、权限失败零写入及测试数据清理。 2026-08-27 dev-v3

供应商管理:详情补齐地址备注并统一表单校验

供应商详情接口现在完整返回主体的 address 和 remark,管理端可用同一份详情快照初始化查看页与编辑表单。创建、提交和更新原本已有的业务字段与校验未增加新的必填项;本工单用契约测试和真实 TEST 验收固定三条写链路的一致口径。

本次没有新增接口路径、权限点或业务错误码。

一、背景

创建和更新请求已经接受地址、备注等主体字段,但基础信息详情此前没有回传 address、remark,导致管理端打开编辑页时无法完整还原已保存表单。同时,创建、提交和更新分属不同请求模型,消费方需要一个明确、可验证的共同校验口径。

本次处理后:

  • 详情响应补齐主体地址与内部备注。
  • 创建、提交、更新对共同主体字段、类型、联系人、资质和合同继续执行同一业务规则。
  • 更新只额外要求变更原因、主体并发版本,以及被修改子项的 ID/版本。
  • #6436/#6499 已交付的授权完整值语义保持不变,不重新引入脱敏值或“留空表示保留旧敏感值”的旧约定。

二、变更接口清单

# 接口 方法 路径 变更类型 说明
1 查询供应商基本信息 GET /admin/supplier/items/{supplierId}/basic-info/view 响应新增字段 根对象新增 address、remark,用于完整初始化查看与编辑表单

创建草稿、提交注册和更新资料的路径、请求字段及错误码没有结构性变化,因此不作为新增接口列入上表;其稳定调用规则在第四节集中说明。

三、接口详情

1. 查询供应商基本信息 GET /admin/supplier/items/{supplierId}/basic-info/view

VO: SupplierBasicInfoRespVO

使用场景

管理端进入供应商详情或编辑页时调用。响应是主体、类型、联系人、资质、合同及并发版本的完整快照;编辑页应直接使用其中的 address、remark 和 updateTime,不得用本地空值覆盖。

入参

字段 位置 类型 必填 约束 说明
supplierId Path String 是 正整数 ID 字符串 目标供应商;不得转为 JavaScript Number

出参 Result<SupplierBasicInfoRespVO>

字段 类型 说明
supplierId String 供应商 ID
fullName / shortName String/null 供应商全称与简称
tax_no String 完整主体证件号;JSON 字段名保持 tax_no
legalRepresentative String/null 法定代表人姓名
legalRepresentativeIdNo String/null 完整法人居民身份证号
legalRepresentativeIdCardFrontUrl / legalRepresentativeIdCardBackUrl String/null 法人证件正反面永久文件地址
contactPhone String/null 完整公司联系电话
establishDate String/null 成立日期,格式 yyyy-MM-dd
registeredCapital / businessScope String/null 注册资本与经营范围
address String/null 本次新增回显:注册地址或经营地址
staffScale String/null 人员规模字典值
mainCooperation String 主要合作内容
remark String/null 本次新增回显:供应商主体内部备注
types Array 类型完整集合;每项包含 isPrimary
primaryTypeCode / primaryTypeName String/null 当前主类型
contacts / qualifications / contracts Array 联系人、资质和合同完整集合;现有项包含字符串 ID 与 updateTime
status String 当前供应商状态
updateTime String 主体并发版本,格式 yyyy-MM-dd HH:mm:ss

请求示例

GET /admin/supplier/items/2092800000000000001/basic-info/view
Authorization: Bearer <admin-token>

响应示例

{
  "code": 200,
  "message": "成功",
  "success": true,
  "data": {
    "supplierId": "2092800000000000001",
    "fullName": "示例旅行服务有限公司",
    "shortName": "示例旅行",
    "tax_no": "91350211M000100Y46",
    "legalRepresentative": "示例法人",
    "legalRepresentativeIdNo": "11010519491231002X",
    "legalRepresentativeIdNoMask": "11010519491231002X",
    "legalRepresentativeIdCardFrontUrl": "https://files.example.com/supplier/id-front.jpg",
    "legalRepresentativeIdCardBackUrl": "https://files.example.com/supplier/id-back.jpg",
    "contactPhone": "13800138000",
    "contactPhoneMask": "13800138000",
    "establishDate": "2020-01-01",
    "registeredCapital": "100万元",
    "businessScope": "境内旅游服务",
    "address": "福建省厦门市示例路 1 号",
    "staffScale": "LT50",
    "mainCooperation": "酒店与景区资源合作",
    "remark": "重点合作供应商",
    "types": [{"typeCode": "HOTEL", "typeName": "酒店", "isPrimary": true}],
    "primaryTypeCode": "HOTEL",
    "primaryTypeName": "酒店",
    "contacts": [],
    "qualifications": [],
    "contracts": [],
    "status": "DRAFT",
    "updateTime": "2026-08-27 15:30:00"
  }
}

空数据 / 降级响应

历史供应商未填写地址或备注时,字段明确返回 null;无类型、联系人、资质或合同时,相应集合返回空数组,不把缺失数据当成接口异常:

{
  "code": 200,
  "message": "成功",
  "success": true,
  "data": {
    "supplierId": "2092800000000000001",
    "address": null,
    "remark": null,
    "types": [],
    "primaryTypeCode": null,
    "primaryTypeName": null,
    "contacts": [],
    "qualifications": [],
    "contracts": [],
    "updateTime": "2026-08-27 15:30:00"
  }
}

错误响应

供应商不存在、已删除或超出数据范围时不返回空详情:

{
  "code": 395001,
  "message": "供应商不存在",
  "success": false,
  "data": null
}

业务边界

  • 要求可信管理身份、supplier:view 平台权限和供应商数据范围;登录态不能代替业务权限。
  • address、remark 属于响应的向后兼容增加;旧客户端忽略未知字段即可继续运行。
  • legalRepresentativeIdNoMask、contactPhoneMask 等废弃兼容别名继续与完整值字段同值;新代码使用无 Mask 字段。
  • Long ID 一律按字符串保存、比较和传输。
  • 本接口只读,不修改主体版本、缓存或审批状态。

四、契约约束与正确调用方式

以下三个既有写接口没有新增路径或字段,但共同业务口径由本工单固定:

  • 创建草稿:POST /admin/supplier/items/add
  • 提交注册:POST /admin/supplier/items/{supplierId}/submit
  • 更新资料:PUT /admin/supplier/items/{supplierId}/update

共同主体字段规则

字段 创建/提交 更新 统一约束
fullName 必填 可选 最长 500 字符
shortName 可选 可选 最长 300 字符
taxNo 必填 可选,且仅允许在状态规则内修改 6 至 64 位字母、数字或展示分隔符;身份证/统一社会信用代码还校验日期或校验位
legalRepresentative 可选 可选 最长 500 字符
legalRepresentativeIdNo 可选 可选 18 位合法居民身份证号;与正反面地址按完整三字段组合校验
legalRepresentativeIdCardFrontUrl / legalRepresentativeIdCardBackUrl 可选 可选 公网 HTTPS 永久文件地址,单项最长 1000 字符
contactPhone 可选 可选 7 至 20 位合法电话字符
establishDate 可选 可选 yyyy-MM-dd,不得晚于当前日期
registeredCapital 可选 可选 最长 50 字符
businessScope 可选 可选 最长 500 字符
address 可选 可选 最长 500 字符;创建和更新同口径
staffScale 可选 可选 LT50、R50_200、R200_500、GT500
mainCooperation 必填 可选 创建/提交不能为空白;更新传值时按同一业务含义保存
licenseImageUrl 可选 可选 最长 500 字符,并与营业执照资质归一化
remark 可选 可选 供应商主体内部备注,不等同于审批意见或 changeReason

集合上限与语义保持不变:types 最多 15 项;contacts、qualifications、contracts 各最多 100 项;initialAccounts 最多 1 项。非空类型必须来自生效字典且不得重复,非空联系人集合必须形成唯一默认联系人,资质和合同继续执行类型、日期、金额、归属和完整快照校验。

更新场景额外要求:

  • changeReason 必填、非空白、最长 500 字符,并进入业务审计。
  • expectedUpdateTime 必须等于详情最新 updateTime。
  • 已有联系人、资质、合同随完整快照更新时,必须带回对应字符串 ID 和子项 updateTime。

✅ 正确 / ❌ 错误 payload 对照

场景 payload / 结果
✅ 更新地址和备注 {"address":"福建省厦门市示例路 2 号","remark":"地址已确认","changeReason":"更新地址和备注","expectedUpdateTime":"2026-08-27 15:30:00"}
✅ 只更新备注 {"remark":"新的内部备注","changeReason":"补充内部备注","expectedUpdateTime":"2026-08-27 15:30:00"}
❌ 地址超过 500 字符 创建、更新均返回 400,零写入
❌ 成立日期晚于当前日期 创建、更新均返回 400,零写入
❌ 更新缺少 changeReason 返回 400,零写入
❌ 使用旧 expectedUpdateTime 返回 395014,零写入;必须刷新详情后由用户确认

正确更新顺序

  1. 先查询详情,保存字符串 ID、子项版本和根对象 updateTime。
  2. 用户提交时只发送实际变更字段,并附非空 changeReason、最新 expectedUpdateTime。
  3. 更新成功后采用响应里的新版本;需要完整表单时重新查询详情。
  4. 遇到 395014 先刷新,不得自动用旧表单覆盖他人修改。

五、数据库行为

  • 成功创建、提交或更新时,主体与本次携带的类型、联系人、资质、合同及业务审计按聚合事务一起成功。
  • 地址和备注保存后,详情读取与变更审计使用同一业务值;remark 不会被提升为审批意见或变更原因。
  • 请求校验、权限、状态、归属或并发版本失败时零写入,主体 updateTime 不变化。
  • 本次没有数据库结构变更、Flyway migration 或历史数据回填;旧记录的地址/备注原值保持不变。
  • 不新增 Redis、MQ、Feign 或跨服务副作用。

六、边界行为

  • 未登录或 Token 失效:401,不把无认证响应当作正向验收。
  • ADMIN 等无写权限角色调用创建、提交或更新:395002,零写入;已有详情仍按读取权限返回。
  • 供应商不存在或已删除:395001。
  • 并发版本过期:395014,调用方刷新详情后重提。
  • 地址超过 500 字符、未来成立日期、必填字段缺失或组合不完整:400,零写入。
  • 历史 address、remark 为空:详情返回 null,不报错、不猜测默认值。
  • ARCHIVED 等不可修改状态继续由既有状态门禁拒绝更新。
  • 业务失败可能仍使用 HTTP 200,调用方必须同时判断响应体 code、success、data。

六.5、枚举 / 数据字典

staffScale(供应商人员规模稳定值)

所属字段: SupplierDraftSaveReqVO.staffScale / SupplierUpdateReqVO.staffScale / SupplierBasicInfoRespVO.staffScale | 类型: String

值 中文 说明
LT50 50 人以下 小于 50 人
R50_200 50 至 200 人 50 至 200 人档
R200_500 200 至 500 人 200 至 500 人档
GT500 500 人以上 大于 500 人

types[].typeCode、contacts[].contactRole、qualifications[].qualType 继续从对应生效数据字典读取,不在客户端硬编码展示名。

六.6、修改前后对比

字段级对比

字段 改前 改后
详情根对象 address 未返回,已保存值无法用于表单回填 返回保存的地址;未填写为 null
详情根对象 remark 未返回,已保存值无法用于表单回填 返回主体内部备注;未填写为 null
创建/提交/更新请求字段 已存在 无新增字段、无新增必填项

行为级对比

行为 改前 改后
打开编辑页 详情缺少地址和备注,表单初始化不完整 一次详情调用可完整初始化主体字段
共同字段校验 实现存在,但缺少跨创建/更新契约锁定 自动化和 TEST 验收固定创建/更新同口径
完整敏感值回显 按 #6436/#6499 返回授权完整值 保持不变

六.7、影响评估

  • 是否破坏向后兼容: 否。响应新增两个可空字段,旧客户端可忽略;请求无新增必填项。
  • 前端是否必须同步上线: 为闭合编辑体验需要接入 address、remark,但不构成旧客户端继续运行的硬门禁。
  • 前端 workaround 清理点: 删除编辑页对地址、备注的本地空值兜底,改为使用详情真实值。
  • QA 重点: 新建后打开详情、更新后刷新详情、地址长度 500/501、今天/未来成立日期、ADMIN 越权、旧版本并发冲突。

七、不影响范围

  • 仅影响: 管理后台供应商详情/编辑表单的主体地址、内部备注回填,以及已有写接口校验口径的契约固定。
  • 零影响:
    • Gateway 路由和认证级别。
    • 供应商生命周期状态机、审批、收款账户、证明附件、资源关系及归档语义。
    • 数据库结构、历史数据、Nacos 配置、Redis、MQ、Feign 和其他服务。
    • 小程序、C 端、Web、H5、桌面端接口。
    • #6436/#6499 的授权完整值和废弃 *Mask 兼容语义。

八、测试环境已验证

  • 本地自动化:供应商定向测试 49 项通过;最新 dev-v3 上 hl-resource-service Reactor 全量 2,153 项,0 失败、0 错误、38 项条件跳过。
  • 部署:Deploy Panel API 任务 938ca09e 终态 success;目标与实际提交均为 b269e5fdca2e1d29e0336314a909885e9d1f9d16,包含本工单合并提交 a952a04c。
  • 采样:部署任务期 8 个有效采样;每个采样至少 2 个运行进程、2 个健康启用 Nacos 实例,零观测不可用采样。该证据只证明采样点,不代表采样间绝对连续。
  • 真实 Gateway:SUPER_ADMIN 创建完整表单后,详情精确回显 address、remark、完整授权字段、主类型及联系人/资质/合同 ID 和版本;更新后 API、数据库主体与更新审计一致。
  • 失败路径:创建/更新的地址超长均返回 400;创建/更新的未来成立日期均返回 400;ADMIN 更新返回 395002;所有失败均验证零写入、版本不变。
  • 清理:临时供应商先经业务删除接口软删除,确认主体已删除且活动子项为 0;随后按本次唯一标记精确清理 8 行测试数据,17 张关联表回读,剩余供应商 0 行;测试会话已注销并验证失效。

九、相关历史 PR

PR Issue 说明 是否仍有效
#6478 / #6483 / #6486 #6436 供应商授权完整值、主类型及同日修正 ✅ 有效,本次保持
#6517 #6476 详情补齐地址备注并固定表单校验契约 ✅ 最新

十、相关文档

  • 关联 Issue:#6476
  • 关联 PR:#6517
  • 相关完整值契约:changelogs-v2/2026-08/27_6436_供应商敏感字段完整回显与主类型-修改接口-管理后台.md
  • 管理端接入:读取详情 address、remark,更新时保留最新 expectedUpdateTime;前端引用待回填。

撤回

  1. 从最新 dev-v3 创建独立回退分支,执行:

    git revert -m 1 --no-edit a952a04cf80f24d6c50cbec4b992c82f8580beba
    
  2. 运行供应商定向测试、hl-resource-service 全量测试和差异检查,经独立 PR 合入。

  3. 使用同一 Deploy Panel 两阶段客户端,仅滚动部署 hl-resource-service,并绑定批准回退分支的精确提交。

  4. 管理端停止依赖详情响应中的 address、remark,再撤回本 Changelog;既有请求字段和完整值契约保持不变。

  5. 无数据库、配置、Redis 或 MQ 恢复步骤;已保存的地址和备注数据保留,不做破坏性回填或删除。

  6. 撤回后经 Gateway 复测详情、创建、更新、未认证、越权、并发冲突和失败零写入,并确认 Resource 双实例与 Nacos 健康。

关联 / 联系人

链接

联系人

  • 后端负责人: @lc
  • 管理端负责人: @mmg(frontend_status: pending)