diff --git a/changelogs-v2/2026-08/31_6842_供应商补充合同字段与附件-修改接口-管理后台.md b/changelogs-v2/2026-08/31_6842_供应商补充合同字段与附件-修改接口-管理后台.md new file mode 100644 index 00000000..eb232e74 --- /dev/null +++ b/changelogs-v2/2026-08/31_6842_供应商补充合同字段与附件-修改接口-管理后台.md @@ -0,0 +1,373 @@ +--- +schema: "hl-changelog/v2" +ticket: "6842" +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 #6858 已合并 dev-v3,hl-resource-service 已部署提交 5546d7907c6eda9b372b4639094f84e568de6496。TEST Gateway 已验证完整字段与全空业务字段合同的新增、更新、详情回读,以及单个 PDF 上传、预览、下载和清理。当前状态:后端已就绪,前端待处理。" +updated_at: "2026-08-31" +base: "dev-v3" +--- + +# 供应商补充合同字段与附件 + +供应商补充合同新增 `businessLine`、`relatedMainContract`、`autoRenew`,并允许写入 `SIGNED`(已签约)。所有合同业务字段均可为空,只有 `changeReason` 继续必填。 + +管理端登记页仅展示补合同编号、状态、合同名称、业务线、有效期、签署日期、关联主合同、自动续约和单个 Word/PDF 附件;其他兼容字段隐藏。 + +## 二、变更接口清单 + +| # | 接口 | 方法 | 路径 | 变更类型 | 说明 | +|---:|---|---|---|---|---| +| 1 | 独立登记供应商合同 | POST | `/admin/supplier/items/{supplierId}/contracts/add` | 扩展请求与响应 | 增加三个字段,状态支持 `SIGNED` | +| 2 | 独立更新供应商合同 | PUT | `/admin/supplier/items/{supplierId}/contracts/{contractId}/update` | 扩展请求与响应 | 新字段支持补录、清空和 `false` | +| 3 | 查询供应商基本信息 | GET | `/admin/supplier/items/{supplierId}/basic-info/view` | 扩展响应 | `contracts[]` 完整回读补充合同字段 | + +## 三、接口详情 + +### 1. 独立登记供应商合同 `POST /admin/supplier/items/{supplierId}/contracts/add` + +**VO**: `SupplierContractCreateReqVO / SupplierContractRespVO` + +#### 使用场景 + +供应商已创建后登记一份补充合同;业务资料未齐时也可只提交审计原因,稍后再补录。 + +#### 入参 + +| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | +|---|---|---|---:|---|---| +| `supplierId` | Path | String | 是 | 正整数 ID 字符串 | 目标供应商 | +| `contractNo` | Body | String/null | 否 | 最长 100 | 补合同编号 | +| `status` | Body | String/null | 否 | `DRAFT` / `ACTIVE` / `SIGNED` / `EXPIRED` | `SIGNED` 显示为“已签约” | +| `contractName` | Body | String/null | 否 | 最长 500 | 合同名称 | +| `businessLine` | Body | String/null | 否 | 最长 100 | 业务线,自由文本 | +| `startDate` | Body | String/null | 否 | `yyyy-MM-dd` | 有效期开始日 | +| `endDate` | Body | String/null | 否 | `yyyy-MM-dd` | 有效期结束日;两端都有值时不得早于开始日 | +| `signDate` | Body | String/null | 否 | `yyyy-MM-dd` | 合同签署日期 | +| `relatedMainContract` | Body | String/null | 否 | 最长 100 | 关联主合同外部引用 | +| `autoRenew` | Body | Boolean/null | 否 | `true` / `false` / `null` | 是 / 否 / 未登记 | +| `scanFileUrl` | Body | String/null | 否 | 最长 1000 | 文件中心确认上传后返回的永久 `ossUrl` | +| `changeReason` | Body | String | 是 | 去空白后非空,最长 500 | 登记原因,写入审计 | + +`contractType`、`amount`、`pricingMode`、`settleCycle`、`remark` 仍兼容但本页面隐藏,也均可为空。 + +#### 出参 + +| 字段 | 类型 | 说明 | +|---|---|---| +| `data.contractId` | String | 合同 ID | +| `data.contractNo` | String/null | 补合同编号 | +| `data.status` | String/null | 包含新增可写值 `SIGNED` | +| `data.contractName` | String/null | 合同名称 | +| `data.businessLine` | String/null | 业务线 | +| `data.startDate` / `data.endDate` | String/null | 有效期日期 | +| `data.signDate` | String/null | 签署日期 | +| `data.relatedMainContract` | String/null | 关联主合同 | +| `data.autoRenew` | Boolean/null | 自动续约三态值 | +| `data.scanFileUrl` | String/null | 合同附件永久地址 | +| `data.updateTime` | String | 当前合同版本,格式 `yyyy-MM-dd HH:mm:ss` | + +#### 请求示例 + +```json +{ + "contractNo": "SHCT2025070102599446", + "status": "SIGNED", + "contractName": "内蒙古牵手草原国际旅行社有限公司额外后返", + "businessLine": null, + "startDate": "2010-01-01", + "endDate": "2099-12-31", + "signDate": "2025-07-01", + "relatedMainContract": "2185933", + "autoRenew": true, + "scanFileUrl": "https://files.example.com/supplier-contract/example.pdf", + "changeReason": "补录已签约合同" +} +``` + +#### 响应示例 + +```json +{ + "code": 200, + "message": "成功", + "success": true, + "data": { + "contractId": "2095000000000000001", + "contractNo": "SHCT2025070102599446", + "status": "SIGNED", + "contractName": "内蒙古牵手草原国际旅行社有限公司额外后返", + "businessLine": null, + "startDate": "2010-01-01", + "endDate": "2099-12-31", + "signDate": "2025-07-01", + "relatedMainContract": "2185933", + "autoRenew": true, + "scanFileUrl": "https://files.example.com/supplier-contract/example.pdf", + "updateTime": "2026-08-31 12:00:00" + } +} +``` + +#### 空数据 / 降级响应 + +仅提交 `changeReason` 也可成功;所有合同业务字段返回 `null`,前端不得补默认状态或日期。 + +#### 错误响应 + +```json +{ + "code": 400, + "message": "变更原因不能为空", + "success": false, + "data": null +} +``` + +#### 业务边界 + +- 所有合同业务字段可空;`changeReason` 不属于业务展示字段,继续必填。 +- `startDate`、`endDate` 同时有值时才校验日期先后。 +- `scanFileUrl` 只保存一个附件永久地址;上传、预览、下载复用文件中心。 + +### 2. 独立更新供应商合同 `PUT /admin/supplier/items/{supplierId}/contracts/{contractId}/update` + +**VO**: `SupplierContractUpdateReqVO / SupplierContractRespVO` + +#### 使用场景 + +补齐、修改或清空已登记合同。该接口为完整替换,省略或传 `null` 会清空对应字段。 + +#### 入参 + +| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | +|---|---|---|---:|---|---| +| `supplierId` | Path | String | 是 | 正整数 ID 字符串 | 目标供应商 | +| `contractId` | Path | String | 是 | 正整数 ID 字符串 | 目标合同 | +| 新增接口全部业务字段 | Body | 对应类型/null | 否 | 与新增一致 | 完整替换;`autoRenew=false` 会保留为否 | +| `expectedUpdateTime` | Body | String/null | 否 | `yyyy-MM-dd HH:mm:ss` | 提供时必须匹配当前版本 | +| `changeReason` | Body | String | 是 | 去空白后非空,最长 500 | 更新原因 | + +#### 出参 + +| 字段 | 类型 | 说明 | +|---|---|---| +| `data.contractId` | String | 原合同 ID | +| `data.businessLine` | String/null | 更新后的业务线,空白规范为 `null` | +| `data.relatedMainContract` | String/null | 更新后的关联主合同 | +| `data.autoRenew` | Boolean/null | 精确保留 `true`、`false` 或 `null` | +| `data.status` | String/null | 可返回 `SIGNED` | +| 其余合同业务字段 | 对应类型/null | 完整替换后的值 | +| `data.updateTime` | String | 更新后的合同版本 | + +#### 请求示例 + +```json +{ + "contractNo": "SHCT2025070102599446", + "status": "SIGNED", + "contractName": "内蒙古牵手草原国际旅行社有限公司额外后返", + "businessLine": null, + "startDate": "2010-01-01", + "endDate": "2099-12-31", + "signDate": "2025-07-01", + "relatedMainContract": null, + "autoRenew": false, + "scanFileUrl": "https://files.example.com/supplier-contract/example.pdf", + "changeReason": "调整自动续约信息" +} +``` + +#### 响应示例 + +```json +{ + "code": 200, + "message": "成功", + "success": true, + "data": { + "contractId": "2095000000000000001", + "contractNo": "SHCT2025070102599446", + "status": "SIGNED", + "businessLine": null, + "relatedMainContract": null, + "autoRenew": false, + "updateTime": "2026-08-31 12:00:01" + } +} +``` + +#### 空数据 / 降级响应 + +仅提交 `changeReason` 可把全部业务字段清空;与当前内容完全相同时拒绝空更新,不生成新版本。 + +#### 错误响应 + +```json +{ + "code": 395054, + "message": "合同有效期开始日期不能晚于结束日期", + "success": false, + "data": null +} +``` + +#### 业务边界 + +- 页面隐藏兼容字段时,编辑既有合同应从详情原样回传其 `contractType`、`amount`、`pricingMode`、`settleCycle`、`remark`,避免完整替换误清历史值。 +- `autoRenew=false` 是有效业务值,不能按空值过滤。 +- `expectedUpdateTime` 可省略;提供过期值时返回 `395014`,合同保持不变。 + +### 3. 查询供应商基本信息 `GET /admin/supplier/items/{supplierId}/basic-info/view` + +**VO**: `SupplierBasicInfoRespVO / SupplierContractRespVO` + +#### 使用场景 + +进入供应商编辑或详情页时,从 `data.contracts[]` 回显合同表格和附件操作。 + +#### 入参 + +| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | +|---|---|---|---:|---|---| +| `supplierId` | Path | String | 是 | 正整数 ID 字符串 | 目标供应商 | + +#### 出参 + +| 字段 | 类型 | 说明 | +|---|---|---| +| `data.contracts` | Array | 当前有效合同,按合同 ID 升序 | +| `data.contracts[].businessLine` | String/null | 业务线 | +| `data.contracts[].relatedMainContract` | String/null | 关联主合同 | +| `data.contracts[].autoRenew` | Boolean/null | 自动续约三态值 | +| `data.contracts[].status` | String/null | `SIGNED` 显示为“已签约” | +| `data.contracts[].scanFileUrl` | String/null | 单个合同附件永久地址 | +| 其余合同字段 | 对应类型/null | 与新增、更新响应一致 | + +#### 请求示例 + +```http +GET /admin/supplier/items/2095000000000000000/basic-info/view +Authorization: Bearer +``` + +#### 响应示例 + +```json +{ + "code": 200, + "message": "成功", + "success": true, + "data": { + "supplierId": "2095000000000000000", + "contracts": [ + { + "contractId": "2095000000000000001", + "contractNo": "SHCT2025070102599446", + "status": "SIGNED", + "contractName": "内蒙古牵手草原国际旅行社有限公司额外后返", + "businessLine": null, + "startDate": "2010-01-01", + "endDate": "2099-12-31", + "signDate": "2025-07-01", + "relatedMainContract": "2185933", + "autoRenew": true, + "scanFileUrl": "https://files.example.com/supplier-contract/example.pdf" + } + ] + } +} +``` + +#### 空数据 / 降级响应 + +没有合同记录时 `contracts=[]`;合同存在但某项未登记时,对应字段为 `null`。 + +#### 错误响应 + +```json +{ + "code": 395001, + "message": "供应商不存在", + "success": false, + "data": null +} +``` + +#### 业务边界 + +- 日期均为上海业务日字符串,前端按 `yyyy-MM-dd` 原样展示,不做 UTC 日期转换。 +- 查询只返回未删除合同;附件为空时隐藏预览、下载操作。 +- 未登录请求由 Gateway 返回业务码 `401`。 + +## 四、契约约束与正确调用方式 + +1. 表格列固定映射为 `contractNo`、`status`、`contractName`、`businessLine`、`startDate/endDate`、`signDate`、`relatedMainContract`、`autoRenew`、`scanFileUrl`;`SIGNED` 展示“已签约”。 +2. `startDate/endDate` 直接按上海日历日拼成有效期;`autoRenew=true` 可显示“到期自动续约”,`false` 显示“否”,`null` 显示未登记占位。 +3. 附件复用文件中心:申请上传凭证 `POST /admin/file/upload/token`,按返回模式上传后调用 `POST /admin/file/upload/confirm`,把确认响应的 `data.ossUrl` 写入 `scanFileUrl`。组件仅保留一个 `.doc`、`.docx` 或 `.pdf` 文件。 +4. 预览使用带登录态的 `GET /admin/file/preview-by-url?url={encodeURIComponent(scanFileUrl)}`;下载直接访问 `scanFileUrl`。 +5. 本页面隐藏 `contractType`、`amount`、`pricingMode`、`settleCycle`、`remark`;编辑历史合同时仍从详情原样回传,避免完整替换清空旧值。 + +## 五、数据库行为 + +这里只约定外部可观察结果:新增或更新成功后,再次请求基本信息详情可读到相同字段;未填写值返回 `null`,`autoRenew=false` 不会丢失。失败响应不产生部分合同变更。 + +## 六、边界行为 + +- 所有合同业务字段可空,只有新增、更新、删除操作的 `changeReason` 必填。 +- `SIGNED` 仅是新增可写状态,不改变既有 `DRAFT`、`ACTIVE`、`EXPIRED` 和历史 `TERMINATED` 的兼容读取。 +- 日期两端都有值且开始日晚于结束日时返回 `395054`,整次更新零写入。 +- 附件字段为单值;前端负责限制为一个 Word/PDF,并在替换附件后提交新的永久地址。 +- 写接口沿用既有角色、权限、幂等、锁和审计规则,无新增错误码。 + +## 六.6、修改前后对比 + +| 项目 | 修改前 | 修改后 | +|---|---|---| +| 业务线、关联主合同、自动续约 | 无字段 | 新增 `businessLine`、`relatedMainContract`、`autoRenew`,均可空 | +| 合同状态 | 可写 `DRAFT` / `ACTIVE` / `EXPIRED` | 追加可写 `SIGNED`(已签约) | +| 详情回读 | 无新增三字段 | `contracts[]` 完整回读新增三字段 | +| 其他合同业务字段 | 可空 | 继续可空,语义不变 | + +## 六.7、影响评估 + +- **是否破坏向后兼容**:否,均为可选字段和状态枚举扩展。 +- **前端是否必须同步上线**:是,需要新增列、附件控件和 `SIGNED` 中文映射,并隐藏非目标字段。 +- **前端 workaround 清理点**:不要在本地拼装缺失字段;以详情 `contracts[]` 为回显真相。 + +## 七、不影响范围 + +- 不修改供应商主体、联系人、资质、结算账户、审批和归档接口。 +- 不把合同并回供应商注册聚合;仍先取得 `supplierId`,再调用独立合同接口。 +- 不新增 Gateway 路由、权限点、配置、Redis 或 MQ 契约。 + +## 八、测试环境已验证 + +- 已在 TEST Gateway 验证完整字段和仅含 `changeReason` 的合同均可新增并跨请求回读;`SIGNED`、`null`、`false`、日期错误零写入均符合本契约。 +- 已验证一个 PDF 经文件中心上传后可预览、下载,验收产生的合同、附件和会话均已清理。 + +## 当前状态 + +- 后端:已部署并已验证。 +- 前端:待处理。 + +## 十、相关文档 + +- Issue:[#6842](https://git.1814.love:8443/wx/HL/issues/6842) +- 后端 PR:[#6858](https://git.1814.love:8443/wx/HL/pulls/6858) +- 合并提交:[5546d790](https://git.1814.love:8443/wx/HL/commit/5546d7907c6eda9b372b4639094f84e568de6496) + +## 关联 / 联系人 + +- **Issue**: [#6842](https://git.1814.love:8443/wx/HL/issues/6842) +- **PR**: [#6858](https://git.1814.love:8443/wx/HL/pulls/6858) +- **后端负责人**: @lc