changelog-filename-gate / validate (push) Failing after 2s
修改原因:6 条 changelog 前端已落地并交付(sync-log 已记 done),但 frontmatter 仍为 pending, 导致发布门禁的前端核验状态与真实交付不符。 修改内容:按 hl-changelog/v2 口径回写 frontend_status=verified、frontend_owner=mmg、 frontend_ref=对应业务 commit 短哈希、verified_at=2026-09-04;target_release 与 status_note 保持原值。 - #6926 导出补 opsStage 筛选 -> ea1b9803 - #7059 设置供应商候选按资源上下文过滤 -> a1a78906 - #7069 供应商企微在途状态统一审核中 -> f6ddd94c - #7070 房务列表/详情补产品类型标签 productType -> 7476250d - #7078 供应商企微审核中冻结资料修改 -> f4d3e1c9 - #7087 供应商新建修改必填资料校验 -> 72d63c8e 实际验证:逐条 diff 核对仅改 frontmatter 5 字段,status_note/target_release/正文未动。
11 KiB
11 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 | 7087 | 供应商新建修改必填资料校验 | admin | lc(GIT) | 修改接口 | deployed | verified | verified | mmg | 72d63c8e | 2026-09-04 | 后端已部署并通过 TEST;前端需为供应商新建和编辑表单补齐主体资料、联系人及结算账户必填校验。 | 2026-09-04 | dev-v3 |
供应商模块:新建与修改补齐必填资料校验
POST /admin/supplier/items/add 新建时必须一次提交完整资料;PUT /admin/supplier/items/{supplierId}/update 仍是增量接口,但保存后的供应商聚合必须完整。前端需同步补齐表单必填标识和提交前校验。
二、变更接口清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|---|---|---|---|---|
| 1 | 新建供应商草稿 | POST | /admin/supplier/items/add |
必填校验收紧 | 主体资料完整,且至少一名联系人、一个初始账户 |
| 2 | 修改供应商资料 | PUT | /admin/supplier/items/{supplierId}/update |
聚合完整性校验 | 省略字段保留现值;显式空类型、联系人或账户拒绝 |
三、接口详情
1. 新建供应商草稿 POST /admin/supplier/items/add
VO: SupplierDraftSaveReqVO → SupplierWriteRespVO
使用场景
管理端完成供应商新建表单后保存草稿。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
fullName |
Body | String | 是 | 非空,最长 500 | 供应商全称 |
taxNo |
Body | String | 是 | 合法主体证件号 | 统一社会信用代码 |
types |
Body | Array | 是 | 至少 1 项,最多 15 项 | typeCode 取 supplier_type 生效字典值 |
legalRepresentative |
Body | String | 是 | 非空 | 法定代表人 |
legalRepresentativeIdNo |
Body | String | 是 | 合法 18 位居民身份证号 | 法人身份证号 |
legalRepresentativeIdCardFrontUrl |
Body | String | 是 | 公网 HTTPS 永久地址 | 身份证人像面 |
legalRepresentativeIdCardBackUrl |
Body | String | 是 | 公网 HTTPS 永久地址 | 身份证国徽面 |
contactPhone |
Body | String | 是 | 合法手机号、座机或 400/800 号码 | 法人联系电话 |
establishDate |
Body | String | 是 | yyyy-MM-dd,不得晚于当天 |
成立日期 |
balance |
Body | Number | 是 | 最多 16 位整数、2 位小数 | 余额,可为正数、0 或负数 |
paymentType |
Body | String | 是 | supplier_payment_type 生效字典值 |
支付类型 |
mainCooperation |
Body | String | 是 | 非空 | 主要合作内容 |
licenseImageUrl |
Body | String | 是 | 非空 | 营业执照影像地址 |
address |
Body | String | 是 | 非空,最长 500 | 注册地址 |
contacts |
Body | Array | 是 | 至少 1 项,最多 100 项 | 每项填写姓名、电话及 sup_content_role 角色 |
initialAccounts |
Body | Array | 是 | 当前必须且只能 1 项 | 每项填写账户类型、银行和账号 |
出参
| 字段 | 类型 | 说明 |
|---|---|---|
data.supplierId |
String | 供应商 ID |
data.supplierNo |
String | 供应商编号 |
data.status |
String | 新建成功为 DRAFT |
data.initialAccounts |
Array | 初始账户摘要 |
data.updateTime |
String | 后续修改使用的并发版本 |
请求示例
{
"fullName": "示例供应商有限公司",
"taxNo": "91350211M000100Y46",
"types": [{"typeCode": "HOTEL"}],
"legalRepresentative": "张三",
"legalRepresentativeIdNo": "11010519491231002X",
"legalRepresentativeIdCardFrontUrl": "https://example.com/supplier/id-front.jpg",
"legalRepresentativeIdCardBackUrl": "https://example.com/supplier/id-back.jpg",
"contactPhone": "13800138000",
"establishDate": "2020-01-02",
"balance": 0,
"paymentType": "1",
"mainCooperation": "酒店资源合作",
"licenseImageUrl": "https://example.com/supplier/license.jpg",
"address": "厦门市思明区示例路 1 号",
"contacts": [{"contactName": "李四", "contactPhone": "13800138001", "contactRole": "contentBus", "isPrimary": true}],
"initialAccounts": [{"accountType": "CORPORATE", "bankName": "示例银行", "accountNo": "6222000012345678"}]
}
响应示例
{
"code": 200,
"message": "成功",
"success": true,
"data": {
"supplierId": "2095000000000000001",
"supplierNo": "SUP2095000000000000001",
"status": "DRAFT",
"initialAccounts": [{"accountId": "2095000000000000002", "status": "DRAFT"}],
"updateTime": "2026-09-04 16:48:49"
}
}
空数据 / 降级响应
写接口没有空数据成功或降级成功;任一必填项缺失时返回失败响应。
错误响应
{"code":400,"message":"联系人不能为空","data":null,"success":false}
业务边界
- 未登录返回业务码
401;写入仍要求FINANCE或SUPER_ADMIN及supplier:create权限。 types、contacts、initialAccounts传null、省略或空数组均视为缺失。- 校验失败不创建供应商或子项;响应可能使用 HTTP 200,必须同时检查
code与success。
2. 修改供应商资料 PUT /admin/supplier/items/{supplierId}/update
VO: SupplierUpdateReqVO → SupplierWriteRespVO
使用场景
管理端编辑既有供应商资料并按最新版本保存。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
supplierId |
Path | String | 是 | 正整数 ID | 目标供应商 |
expectedUpdateTime |
Body | String | 是 | yyyy-MM-dd HH:mm:ss |
取详情最新 updateTime |
| 主体必填资料 | Body | 原类型 | 条件必填 | 与新建接口相同 | 省略表示保留现值;保存后的有效值必须完整 |
types |
Body | Array | 条件必填 | 显式提交时至少 1 项 | 省略保留存量,[] 拒绝 |
contacts |
Body | Array | 条件必填 | 显式提交时至少 1 项 | 省略保留存量,[] 拒绝 |
initialAccounts |
Body | Array | 条件必填 | 显式提交时当前必须且只能 1 项 | 省略保留存量,[] 拒绝 |
changeReason |
Body | String | 条件必填 | 最长 500 | DRAFT 可省略,其他可修改状态沿用既有规则 |
主体必填资料指:fullName、taxNo、legalRepresentative、legalRepresentativeIdNo、legalRepresentativeIdCardFrontUrl、legalRepresentativeIdCardBackUrl、contactPhone、establishDate、balance、paymentType、mainCooperation、licenseImageUrl、address。
出参
| 字段 | 类型 | 说明 |
|---|---|---|
data.supplierId |
String | 供应商 ID |
data.status |
String | 保存后的状态 |
data.initialAccounts |
Array | 当前初始账户摘要 |
data.updateTime |
String | 保存后的新并发版本 |
请求示例
{
"shortName": "示例供应商",
"expectedUpdateTime": "2026-09-04 16:48:49"
}
响应示例
{
"code": 200,
"message": "成功",
"success": true,
"data": {
"supplierId": "2095000000000000001",
"status": "DRAFT",
"initialAccounts": [{"accountId": "2095000000000000002", "status": "DRAFT"}],
"updateTime": "2026-09-04 16:49:16"
}
}
空数据 / 降级响应
省略未修改字段会保留已存值;接口没有空数据成功或降级成功。
错误响应
{"code":400,"message":"供应商类型不能为空","data":null,"success":false}
业务边界
- 写入仍要求
FINANCE或SUPER_ADMIN及supplier:update权限。 - 保存前按“请求值 + 已存值”校验完整聚合;存量资料缺项时,必须补齐后才能保存其他修改。
- 非草稿账户继续走独立账户审批;本次不改变状态、并发、审批、幂等或审计规则。
expectedUpdateTime过期返回既有业务码395014,失败不更新任何聚合数据。
四、契约约束与正确调用方式(接口类必写)
| 场景 | 正确调用 |
|---|---|
| 新建 | 一次提交全部主体必填资料、非空 types、非空 contacts 和一个 initialAccounts |
| 修改普通字段 | 先查询详情;已存聚合完整时,只提交变化字段和最新 expectedUpdateTime |
| 修改关系快照 | 提交完整非空快照;不修改关系时省略对应字段 |
| 字典字段 | 提交字典接口返回的 dictValue,不要提交中文标签或前端硬编码默认值 |
支付类型当前字典值为 1(现付)、2(签单)、3(月付);供应商类型和联系人角色分别从 supplier_type、sup_content_role 动态字典读取。
五、数据库行为
- 校验失败不新增或更新供应商聚合数据。
- 本次没有表结构、字段非空约束、数据迁移或历史数据回填。
六、边界行为
- 业务失败可能仍为 HTTP 200;前端必须检查
success=false和业务code/message。 - 必填文本为空白、必填值为
null、必填集合为空时均拒绝。 - 更新省略字段表示保留,不等于清空;完整性按保存后的有效聚合判断。
- 超过列表上限、字典值失效、身份证/电话/URL 格式不合法时继续使用既有校验错误。
六.6、修改前后对比
| 行为 | 改前 | 改后 |
|---|---|---|
| 新建缺主体资料 | 部分字段可缺失并保存草稿 | 任一约定主体必填资料缺失即拒绝 |
| 新建缺关系资料 | 类型、联系人或账户可能为空 | 三类均必须非空 |
| 修改显式空关系快照 | 可清空部分关系 | types: []、contacts: []、initialAccounts: [] 均拒绝 |
| 修改省略未变化字段 | 保留现值 | 仍保留现值,并校验最终聚合完整性 |
六.7、影响评估
- 是否破坏向后兼容: 是。依赖不完整草稿或显式清空类型、联系人、初始账户的旧请求会被拒绝。
- 前端是否必须同步上线: 是。新建和编辑表单均需补齐必填标识、校验提示和提交数据。
- 前端 workaround 清理点: 不再允许以空数组清空供应商类型、联系人或初始账户。
七、不影响范围
- 响应结构和字段名不变。
- 不改变供应商注册提交接口、权限矩阵、状态机、审批流、并发版本、幂等与审计语义。
- 不改变非草稿账户独立审批入口,也不修改数据库约束。
八、测试环境已验证
- 新建缺注册地址、联系人或账户分别返回业务码
400,且无业务数据写入;完整资料创建成功。 - 修改显式空类型、联系人、账户或清空营业执照分别返回业务码
400,资料与版本不变;完整存量上的增量修改成功。 - 匿名新建返回业务码
401;验收草稿已通过应用删除接口清理,有效聚合数据为零。
十、相关文档
- 后端 Issue #7087
- 后端 PR #7093
- 历史契约 #6343:其中“新建可空类型、修改可显式清空类型”已被本工单取代。
关联 / 联系人
链接
联系人
- 后端负责人: @lc