新增 changelog:合同·保险 Tab 无合同/无保险时子对象返 null(订单详情接口 #4460/PR #4461)
这个提交包含在:
父节点
c88cc66ffd
当前提交
558425c4f8
@ -0,0 +1,250 @@
|
||||
# 【修改接口·管理后台】订单详情「合同·保险」Tab:无合同/无保险时子对象返 null (#4460)
|
||||
|
||||
> **PR**: #4461 | **服务**: hl-order-service-v3 | **更新时间**: 2026-06-26
|
||||
|
||||
## 1. 接口背景
|
||||
|
||||
订单详情「合同·保险」Tab 懒加载接口,在订单**从未签约 / 从未投保**时,原本仍返回一个字段全为 `null` 的 `contract` / `insurance` 壳对象,前端要判断"这单到底有没有合同/保险"只能逐字段判空,体验差且容易误判。
|
||||
|
||||
本次改为:合同、保险**各自独立**判断是否存在,不存在则整个子对象直接返 `null`,前端一层判断即可。
|
||||
|
||||
## 2. 变更清单
|
||||
|
||||
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|
||||
|---|------|------|------|----------|------|
|
||||
| 1 | 合同·保险 Tab | GET | `/v3/admin/order/{id}/contract-insurance` | 修改接口 | 无合同时 `contract` 返 null、无保险时 `insurance` 返 null(原为字段全 null 的壳对象) |
|
||||
|
||||
## 3. 接口详情
|
||||
|
||||
### 3.1 获取订单合同·保险 Tab 数据
|
||||
|
||||
- **使用场景**:管理后台订单详情页,点开「合同·保险」Tab 时懒加载
|
||||
- **认证**:需要 JWT(管理后台登录态)
|
||||
- **幂等性**:是(纯查询)
|
||||
- **限流**:无
|
||||
|
||||
## 4. 接口入参
|
||||
|
||||
### 4.1 路径参数
|
||||
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `id` | String | ✅ | 订单 ID(雪花 ID,字符串传递) |
|
||||
|
||||
### 4.2 请求体字段
|
||||
|
||||
无(GET 请求)。
|
||||
|
||||
## 5. 出参(响应)
|
||||
|
||||
### 5.1 顶层结构
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `contract` | Object \| null | 合同信息;该订单**从未签约**时为 `null` |
|
||||
| `insurance` | Object \| null | 保险信息;该订单**从未投保**时为 `null` |
|
||||
|
||||
> **判定口径**:
|
||||
> - `contract` 为 null:合同状态为空 **且** 无合同方案头 **且** 无合同事件
|
||||
> - `insurance` 为 null:保险聚合状态为空 **且** 无保单
|
||||
> 三者/两者任一非空即视为"存在",照常返回完整对象。
|
||||
|
||||
### 5.2 `contract` 对象字段(存在时)
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `contractStatus` | String | 合同状态,见 §6.1 |
|
||||
| `contractSignedAt` | String | 签署时间(`yyyy-MM-dd HH:mm:ss`),未签为 null |
|
||||
| `contractFileUrl` | String | 合同文件地址,未生成为 null |
|
||||
| `contractSchemeName` | String | 合同方案名 |
|
||||
| `signerName` | String | 签署人 |
|
||||
| `signMethod` | String | 签署方式 |
|
||||
| `events` | Array | 合同流程事件(固定 5 步模板),见 §5.4 |
|
||||
|
||||
### 5.3 `insurance` 对象字段(存在时)
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `insuranceStatus` | String | 保险聚合状态,见 §6.2 |
|
||||
| `insuranceStatusName` | String | 保险状态中文名 |
|
||||
| `totalPremium` | Number | 总保费 |
|
||||
| `policyCount` | Number | 保单数量 |
|
||||
| `policies` | Array | 逐张保单列表(存在时;可能为空数组) |
|
||||
|
||||
### 5.4 `events` / `policies[].events` 事件字段
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `eventType` / `stepCode` | String | 步骤码 |
|
||||
| `eventName` | String | 步骤名 |
|
||||
| `actorType` | String | 操作方类型,见 §6.3 |
|
||||
| `actorTypeName` | String | 操作方中文名 |
|
||||
| `actorLabel` | String | 操作方标签 |
|
||||
| `statusLabel` | String | 状态标签(如 已完成/进行中/待处理) |
|
||||
| `description` | String | 描述 |
|
||||
| `occurredAt` | String | 发生时间 |
|
||||
|
||||
## 6. 枚举 / 数据字典
|
||||
|
||||
### 6.1 contractStatus(合同状态)
|
||||
|
||||
**所属字段**:`contract.contractStatus` | **类型**:`String`
|
||||
|
||||
| 值 | 中文 | 说明 |
|
||||
|----|------|------|
|
||||
| `SIGNED` | 已签约 | 合同已签署完成 |
|
||||
| 其他业务态 | — | 按合同流程取值(生成/报备/作废等) |
|
||||
|
||||
### 6.2 insuranceStatus(保险聚合状态)
|
||||
|
||||
**所属字段**:`insurance.insuranceStatus` | **类型**:`String`
|
||||
|
||||
| 值 | 中文(insuranceStatusName) | 说明 |
|
||||
|----|------|------|
|
||||
| `INSURED` | 已出单 | — |
|
||||
| `INSURING` | 出单中 | — |
|
||||
| `CANCELLED` | 已取消 | — |
|
||||
| `FAILED` | 出单失败 | — |
|
||||
|
||||
### 6.3 actorType(操作方类型)
|
||||
|
||||
**所属字段**:`events[].actorType` / `policies[].events[].actorType` | **类型**:`String`
|
||||
|
||||
| 值 | 中文(actorTypeName) | 说明 |
|
||||
|----|------|------|
|
||||
| `SYSTEM` | 系统 | — |
|
||||
| `THIRD_PARTY` | 第三方 | 如电子合同平台 / 保险公司 |
|
||||
| `CUSTOMER` | 客户 | — |
|
||||
|
||||
## 7. 错误码
|
||||
|
||||
| code | 含义 | 触发场景 |
|
||||
|------|------|----------|
|
||||
| `581007` | 订单不存在 | 路径 `id` 对应订单不存在 |
|
||||
|
||||
## 8. 示例
|
||||
|
||||
### 8.1 典型成功(无合同无保险订单)
|
||||
|
||||
**请求**:
|
||||
```
|
||||
GET /v3/admin/order/2070039058075017217/contract-insurance
|
||||
Authorization: Bearer <token>
|
||||
无请求体
|
||||
```
|
||||
|
||||
**响应**:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "成功",
|
||||
"data": {
|
||||
"contract": null,
|
||||
"insurance": null
|
||||
},
|
||||
"success": true
|
||||
}
|
||||
```
|
||||
|
||||
### 8.2 边界(有合同·有保险订单)
|
||||
|
||||
**场景说明**:订单已签约(SIGNED)且已投保,两子对象照常返回完整结构。
|
||||
|
||||
**响应**:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "成功",
|
||||
"data": {
|
||||
"contract": {
|
||||
"contractStatus": "SIGNED",
|
||||
"contractSignedAt": "2026-04-18 17:12:00",
|
||||
"contractFileUrl": "https://oss.example.com/contract/xxx.pdf",
|
||||
"contractSchemeName": "标准国内单团签约方案",
|
||||
"signerName": "张三",
|
||||
"signMethod": "电子签约",
|
||||
"events": [
|
||||
{ "stepCode": "GENERATE", "eventName": "生成合同", "actorType": "SYSTEM", "actorTypeName": "系统", "statusLabel": "已完成", "occurredAt": "2026-04-18 17:10:00" }
|
||||
]
|
||||
},
|
||||
"insurance": {
|
||||
"insuranceStatus": "INSURED",
|
||||
"insuranceStatusName": "已出单",
|
||||
"totalPremium": 88.00,
|
||||
"policyCount": 1,
|
||||
"policies": [
|
||||
{ "policyNo": "PICC-001", "status": "INSURED", "statusName": "已出单", "events": [] }
|
||||
]
|
||||
}
|
||||
},
|
||||
"success": true
|
||||
}
|
||||
```
|
||||
|
||||
### 8.3 业务失败(订单不存在)
|
||||
|
||||
**请求**:
|
||||
```
|
||||
GET /v3/admin/order/88888888/contract-insurance
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
**响应**:
|
||||
```json
|
||||
{
|
||||
"code": 581007,
|
||||
"message": "订单不存在",
|
||||
"success": false
|
||||
}
|
||||
```
|
||||
|
||||
## 9. 业务边界
|
||||
|
||||
- ✅ **返完整对象**:合同侧状态/方案头/事件任一存在 → `contract` 完整返回;保险侧聚合状态或保单任一存在 → `insurance` 完整返回
|
||||
- ⚠️ **返 null**:从未签约 → `contract` 整体为 `null`;从未投保 → `insurance` 整体为 `null`
|
||||
- 两者相互独立:可能出现「有合同无保险」(`contract` 非 null、`insurance` 为 null)或反之
|
||||
|
||||
## 10. 修改前后对比
|
||||
|
||||
### 10.1 字段级对比
|
||||
|
||||
| 字段 | 改前 | 改后 |
|
||||
|------|------|------|
|
||||
| `data.contract`(无合同时) | 字段全为 null 的对象 `{contractStatus:null, ..., events:[]}` | `null` |
|
||||
| `data.insurance`(无保险时) | 字段全为 null 的对象 `{insuranceStatus:null, ..., policyCount:0, policies:[]}` | `null` |
|
||||
|
||||
### 10.2 行为级对比
|
||||
|
||||
| 行为 | 改前 | 改后 |
|
||||
|------|------|------|
|
||||
| 前端判断有无合同/保险 | 逐字段判空(如 `contract.contractStatus == null && ...`) | 一层判断 `if (data.contract)` / `if (data.insurance)` |
|
||||
|
||||
## 11. 影响评估 / 回滚
|
||||
|
||||
### 11.1 影响评估
|
||||
|
||||
- **是否破坏向后兼容**:是(无合同/无保险订单的 `contract`/`insurance` 由对象变为 null,前端需调整判空逻辑)
|
||||
- **前端是否必须同步上线**:是(原逐字段判空逻辑需改为判子对象是否为 null)
|
||||
|
||||
### 11.2 回滚方案
|
||||
|
||||
- **回滚方式**:revert PR #4461
|
||||
- **回滚耗时**:预计 5 分钟(重新部署)
|
||||
|
||||
## 12. 注意事项
|
||||
|
||||
- 前端 workaround 清理点:原先「逐字段判空来识别是否有合同/保险」的逻辑可改为「判 `data.contract` / `data.insurance` 是否为 null」
|
||||
- 「有合同·有保险」「有合同·无保险」「无合同·有保险」「无合同·无保险」四种组合均需正确处理
|
||||
|
||||
## 13. 关联 / 联系人
|
||||
|
||||
### 13.1 链接
|
||||
|
||||
- **Issue**: [#4460](https://git.1814.love:8443/wx/HL/issues/4460)
|
||||
- **PR**: [#4461](https://git.1814.love:8443/wx/HL/pulls/4461)
|
||||
- **Merge commit**: [8ae5d58](https://git.1814.love:8443/wx/HL/commit/8ae5d5819268a01910a8ec93908489d728ad7005)
|
||||
|
||||
### 13.2 联系人
|
||||
|
||||
- **后端负责人**: @yst
|
||||
- **前端对接(管理后台)**: —
|
||||
正在加载...
x
在新工单中引用
屏蔽一个用户