16 KiB
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 | 6643 | 供应商编辑页地址营业执照与备注回显 | admin | lc(GIT) | 修改接口 | deployed | verified | pending | PR #6645 已合并 dev-v3;hl-resource-service 已通过 Deploy Panel 任务 954419f9 部署提交 d206d1d577a3e3f8cec228e73e139fcb36c00fd5。真实 TEST Gateway 已验证 address、licenseImageUrl、remark 原值回显、更新后回读、空地址保留、营业执照顶层字段权威读取、395014 零写入及测试草稿清理。 | 2026-08-29 | dev-v3 |
🔧 供应商编辑页地址、营业执照与备注回显
供应商编辑页应直接使用详情根对象的 address、licenseImageUrl、remark 初始化表单。其中 licenseImageUrl 是营业执照上传控件的权威字段,不得再从 qualifications[].imageUrl 推导或覆盖。
本次没有新增接口路径、请求必填项、权限点或业务错误码。
一、关键变化
| 字段 | 修改前 | 修改后 |
|---|---|---|
data.address |
已有详情字段,但编辑和空值保留规则缺少本次回归锁定 | 返回已保存地址;提交非空新值后可回读,更新时留空保持原值 |
data.licenseImageUrl |
详情根对象没有稳定的营业执照权威回显,调用方可能从资质数组取值 | 详情根对象稳定返回营业执照;只读取顶层权威值,不再从资质数组反向派生 |
data.remark |
已有详情字段,但编辑回显和更新规则缺少本次回归锁定 | 返回已保存内部备注;提交非空新值后可回读 |
二、变更接口清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|---|---|---|---|---|
| 1 | 查询供应商基本信息 | GET | /admin/supplier/items/{supplierId}/basic-info/view |
响应修改 | 根对象稳定返回 address、licenseImageUrl、remark |
| 2 | 更新供应商资料 | PUT | /admin/supplier/items/{supplierId}/update |
行为修改 | 三字段按增量更新和并发版本规则保存;写后重新查询可得到新值 |
三、接口详情
1. 查询供应商基本信息 GET /admin/supplier/items/{supplierId}/basic-info/view
VO: SupplierBasicInfoRespVO
使用场景
管理端进入供应商详情或编辑页时获取完整表单快照。营业执照上传控件必须绑定根对象 data.licenseImageUrl;qualifications[] 继续用于独立资质列表,不是该控件的取值来源。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
supplierId |
Path | String | 是 | 正整数 ID 字符串 | 目标供应商;不得转为 JavaScript Number |
无 Query 参数,无请求体。
出参 Result<SupplierBasicInfoRespVO>
| 字段 | 类型 | 说明 |
|---|---|---|
data.address |
String/null | 注册地址或经营地址;未填写时为 null |
data.licenseImageUrl |
String/null | 营业执照影像权威地址;未填写时为 null |
data.remark |
String/null | 供应商主体内部备注;不等同于审批意见或变更原因 |
data.qualifications[].imageUrl |
String/null | 单项资质影像;与根对象营业执照字段分别读取 |
data.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",
"supplierNo": "SUP2092800000000000001",
"fullName": "示例旅行服务有限公司",
"shortName": "示例旅行",
"tax_no": "91350211M000100Y46",
"legalRepresentative": "示例法人",
"legalRepresentativeIdNo": "11010519491231002X",
"legalRepresentativeIdNoMask": "11010519491231002X",
"legalRepresentativeIdCardFrontUrl": null,
"legalRepresentativeIdCardBackUrl": null,
"contactPhone": "13800138000",
"contactPhoneMask": "13800138000",
"establishDate": "2020-01-01",
"registeredCapital": "100万元",
"businessScope": "境内旅游服务",
"address": "福建省厦门市示例路 2 号",
"staffScale": "LT50",
"mainCooperation": "酒店与景区资源合作",
"licenseImageUrl": "https://files.example.com/supplier/business-license-new.jpg",
"remark": "地址与营业执照已复核",
"status": "DRAFT",
"creditLevel": "B",
"totalScore": null,
"types": [],
"primaryTypeCode": null,
"primaryTypeName": null,
"contacts": [],
"qualifications": [
{
"qualificationId": "2092800000000000011",
"qualType": "BUSINESS_LICENSE",
"qualTypeName": "营业执照",
"certNo": null,
"certNoMask": null,
"imageUrl": "https://files.example.com/supplier/business-license-new.jpg",
"expiryDate": null,
"permanentValid": true,
"daysUntilExpiry": null,
"validityStatus": "VALID",
"validityStatusName": "有效",
"isRequired": false,
"expired": false,
"updateTime": "2026-08-29 14:40:01"
}
],
"contracts": [],
"updateTime": "2026-08-29 14:40:02"
}
}
空数据 / 降级响应
未填写三字段时返回明确的 null,前端显示空控件即可,不要用资质数组补写营业执照:
{
"code": 200,
"message": "成功",
"success": true,
"data": {
"supplierId": "2092800000000000001",
"address": null,
"licenseImageUrl": null,
"remark": null,
"qualifications": [],
"updateTime": "2026-08-29 14:40:02"
}
}
错误响应
供应商不存在、已删除或超出可见范围:
{
"code": 395001,
"message": "供应商不存在",
"success": false,
"data": null
}
业务边界
- 要求可信管理身份、可读角色、
supplier:view平台权限和既有数据范围。 - 根对象
licenseImageUrl是编辑页营业执照的唯一权威回显;即使qualifications[]中同类型影像不同,也不得覆盖根对象值。 - 历史记录没有可用营业执照时返回
null,不猜测默认图片。 - 本接口只读,不推进版本、不触发审批或其他业务副作用。
2. 更新供应商资料 PUT /admin/supplier/items/{supplierId}/update
VO: SupplierUpdateReqVO / SupplierWriteRespVO
使用场景
管理端保存供应商编辑表单。请求只发送实际修改字段,并携带详情中的最新 updateTime 和本次 changeReason。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
supplierId |
Path | String | 是 | 正整数 ID 字符串 | 目标供应商 |
address |
Body | String | 否 | 最长 500 字符 | 非空时更新;省略、null、空串或纯空格时保留原值 |
licenseImageUrl |
Body | String | 否 | 最长 500 字符 | 省略时保留;传非空值时更新权威营业执照;传空串时清空 |
remark |
Body | String | 否 | - | 非空时更新;省略、null、空串或纯空格时保留原值 |
changeReason |
Body | String | 是 | 去空白后非空,最长 500 字符 | 本次资料变更原因 |
expectedUpdateTime |
Body | String | 是 | yyyy-MM-dd HH:mm:ss |
详情最新主体并发版本 |
其他既有可选字段和集合快照规则保持不变。
出参 Result<SupplierWriteRespVO>
| 字段 | 类型 | 说明 |
|---|---|---|
data.supplierId |
String | 供应商 ID |
data.supplierNo |
String | 供应商业务编号 |
data.status |
String | 当前生命周期状态 |
data.onboardingStage |
String | 当前注册阶段 |
data.initialAccounts |
Array | 初始收款账户摘要 |
data.updateTime |
String | 写入后的新主体并发版本 |
请求示例
PUT /admin/supplier/items/2092800000000000001/update
Authorization: Bearer <admin-token>
Content-Type: application/json
{
"address": "福建省厦门市示例路 2 号",
"licenseImageUrl": "https://files.example.com/supplier/business-license-new.jpg",
"remark": "地址与营业执照已复核",
"changeReason": "更新供应商编辑资料",
"expectedUpdateTime": "2026-08-29 14:40:00"
}
响应示例
{
"code": 200,
"message": "成功",
"success": true,
"data": {
"supplierId": "2092800000000000001",
"supplierNo": "SUP2092800000000000001",
"status": "DRAFT",
"onboardingStage": "PROFILE_DRAFT",
"initialAccounts": [],
"updateTime": "2026-08-29 14:40:02"
}
}
写响应不重复返回 address、licenseImageUrl、remark。前端需要完整表单时,应使用新 updateTime 重新查询详情。
空数据 / 降级响应
成功更新时 data 恒为写入结果对象,不返回 null。当前请求没有实际变化时不会伪造成功或推进版本,而是返回业务失败:
{
"code": 400,
"message": "未检测到实际变化",
"success": false,
"data": null
}
错误响应
{
"code": 395014,
"message": "数据已被他人修改,请刷新后重试",
"success": false,
"data": null
}
收到 395014 后先重新获取详情,由用户确认后再提交;不得用旧表单自动覆盖。
业务边界
- 要求可信管理身份、
FINANCE或SUPER_ADMIN写角色及supplier:update平台权限。 - 成功写入后推进主体
updateTime;权限、参数、状态或并发失败时三字段及版本均不变化。 - 顶层
licenseImageUrl更新时会继续兼容同步营业执照资质影像;反向只修改qualifications[].imageUrl不会改写顶层权威字段。 remark是主体内部备注;changeReason是本次变更审计原因,两者不得互相替代。- 统一响应可能以 HTTP 200 承载业务失败,调用方必须同时判断
code、success、message和data。
四、契约约束与正确调用方式
编辑页初始化
地址输入框 ← data.address
营业执照上传控件 ← data.licenseImageUrl
内部备注输入框 ← data.remark
并发版本 ← data.updateTime
不得把 qualifications.find(item => item.qualType === "BUSINESS_LICENSE").imageUrl 作为营业执照上传控件的回显值或顶层字段兜底。
更新规则对照
| 场景 | 请求 | 结果 |
|---|---|---|
| 更新三个字段 | 发送三个非空新值 + 原因 + 最新版本 | 更新成功;重新查询返回三个新值 |
| 地址留空,修改备注 | address: " ",remark 为新值 |
地址保持原值,备注更新 |
| 省略营业执照 | 不发送 licenseImageUrl |
顶层营业执照保持原值 |
| 清空营业执照 | licenseImageUrl: "" |
顶层营业执照清空,兼容影像同步清空 |
| 只改资质数组影像 | 发送 qualifications[],不发送顶层字段 |
资质影像独立变化,顶层营业执照保持原值 |
| 使用旧版本 | 发送过期 expectedUpdateTime |
返回 395014,零写入 |
五、数据库行为
本节只描述接口可观察结果,不要求前端感知存储结构:
- 三字段更新成功后,再次查询详情返回新值,且主体
updateTime推进。 address或remark留空时保存其他字段,重新查询仍返回原地址或原备注。- 顶层
licenseImageUrl更新成功后,详情根对象与兼容营业执照资质影像均返回新值。 - 只更新资质数组影像时,详情根对象
licenseImageUrl保持原值。 - 权限、参数、状态或
395014并发失败时,三字段和主体版本均不变化。 - 部署时已对可识别的历史营业执照影像完成一次性兼容初始化;之后详情根对象不再从资质数组动态派生。
六、边界行为
- 未登录或 Token 无效由 Gateway 拒绝,不产生业务写入。
- 无
supplier:view时详情读取失败;无supplier:update或不属于允许写角色时更新返回395002,零写入。 - 供应商不存在、已删除或不可见时返回
395001。 address或licenseImageUrl超过各自长度上限时返回400,零写入。- 缺少
changeReason、缺少expectedUpdateTime或没有实际变化时返回400,零写入。 - 版本过期返回
395014;客户端必须刷新详情,不能自动覆盖。 ARCHIVED等不可修改状态继续由既有状态门禁拒绝。- 业务失败可能仍使用 HTTP 200,客户端必须检查统一响应体。
六.6、修改前后对比
字段级对比
| 字段 | 改前 | 改后 |
|---|---|---|
data.address |
字段已存在,但本次编辑回归未锁定 | 原值、更新值及留空保留规则均已锁定 |
data.licenseImageUrl |
根对象没有稳定权威回显 | 根对象返回可空权威值,不从 qualifications[] 反向派生 |
data.remark |
字段已存在,但本次编辑回归未锁定 | 原值和更新值均可稳定回读 |
行为级对比
| 行为 | 改前 | 改后 |
|---|---|---|
| 编辑页初始化营业执照 | 可能从资质数组搜索影像 | 固定读取根对象 licenseImageUrl |
| 更新营业执照 | 根对象回读来源不稳定 | 提交顶层字段后,写后查询返回同一新值 |
| 单独修改资质影像 | 可能被误当成主体营业执照 | 不改变根对象营业执照权威值 |
六.7、影响评估
- 是否破坏向后兼容:否。详情根对象增加可空字段并固定既有字段行为;旧客户端可忽略未知字段。
- 前端是否必须同步上线:需要。营业执照上传控件必须改为读取并提交顶层
licenseImageUrl;地址和备注继续直接绑定根对象字段。 - 前端 workaround 清理点:删除从
qualifications[]搜索营业执照影像并覆盖表单值的逻辑。 - QA 重点:已有值回显、三字段更新后刷新、地址留空保留、资质影像与顶层营业执照相互独立、旧版本失败零写入。
七、不影响范围
- 仅影响:管理后台供应商详情与编辑表单的地址、营业执照和内部备注。
- 零影响:
- 接口路径、Gateway 路由和认证级别。
- 供应商既有角色、平台权限和数据范围。
- 生命周期状态机、审批、合同、收款账户和资源关系。
- 既有业务错误码、Redis、MQ、Feign 和其他服务。
- 小程序、C 端、Web、H5 和桌面端接口。
八、测试环境已验证
- 本地:供应商定向 62 项通过;
hl-resource-serviceReactor 全量 2,186 项通过,0 失败、0 错误,38 项既有条件跳过。 - 合并:后端 PR #6645 已合并,合并提交为
d206d1d577a3e3f8cec228e73e139fcb36c00fd5。 - 部署:Deploy Panel API 任务
954419f9成功,TEST 目标与实际提交均为上述合并提交;任务期 6 个采样均至少保持 2 个进程与 2 个健康启用实例匹配,0 个不可用采样。 - 真实 Gateway:唯一测试草稿依次验证原值回显、资质影像独立变化时顶层营业执照不变、三字段更新后回读、空地址保留、旧版本
395014零写入及未认证拒绝。 - 清理:测试草稿已通过业务删除接口软删除并确认详情不可查询;仅保留系统规定的脱敏业务审计事实。
九、撤回
如后端撤回本次契约,前端在回退部署前停止依赖顶层 licenseImageUrl,并以同步发布的撤回 Changelog 为准;不得自行恢复未冻结的资质数组反向覆盖逻辑。地址与备注仍按既有 #6476 契约处理。
十、相关文档
关联 / 联系人
链接
联系人
- 后端负责人: @lc
- 管理端负责人: 待认领(
frontend_status: pending)