From 5a6f8675b672596233a692ccc92e2363466724d0 Mon Sep 17 00:00:00 2001 From: yaosutu <770858045@qq.com> Date: Thu, 18 Jun 2026 10:15:07 +0800 Subject: [PATCH] =?UTF-8?q?docs(changelog):=20order-v3=20=E5=90=88?= =?UTF-8?q?=E5=90=8C/=E4=BF=9D=E9=99=A9=E9=95=9C=E5=83=8F=E7=8A=B6?= =?UTF-8?q?=E6=80=81=20NONE=E2=86=92null=20=E5=89=8D=E7=AB=AF=E5=8F=98?= =?UTF-8?q?=E6=9B=B4=E8=AF=B4=E6=98=8E=20(#3956)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 受影响接口:GET /v3/admin/order/{id}、GET /v3/admin/order/{id}/contract-insurance、GET /v3/admin/order/group-batch/{groupBatchId}/orders - 无合同/无保险时 contractStatus/insuranceStatus 由 "NONE" 改为 null - Issue #3953 / PR #3956 --- ...同保险状态NONE改null-修改接口-管理后台.md | 342 ++++++++++++++++++ 1 file changed, 342 insertions(+) create mode 100644 changelogs-v2/2026-06/18_3953_合同保险状态NONE改null-修改接口-管理后台.md diff --git a/changelogs-v2/2026-06/18_3953_合同保险状态NONE改null-修改接口-管理后台.md b/changelogs-v2/2026-06/18_3953_合同保险状态NONE改null-修改接口-管理后台.md new file mode 100644 index 0000000..c136e02 --- /dev/null +++ b/changelogs-v2/2026-06/18_3953_合同保险状态NONE改null-修改接口-管理后台.md @@ -0,0 +1,342 @@ +# 合同/保险镜像状态"无记录"时从 `"NONE"` 改为 `null` + +- **变更类型**:修改接口 +- **端类型**:管理后台 +- **日期**:2026-06-18 +- **Issue**:[#3953](https://git.1814.love:8443/wx/HL/issues/3953) +- **PR**:[#3956](https://git.1814.love:8443/wx/HL/pulls/3956) +- **Commit**:[dc21950a9](https://git.1814.love:8443/wx/HL/commit/dc21950a9)(feature)/ [41cfd5ad8](https://git.1814.love:8443/wx/HL/commit/41cfd5ad8)(merge) +- **后端负责人**:腰苏图 + +--- +## ① 接口背景 + +order-v3 主表 `order_main` 中有两个镜像状态列:`contract_status`(合同状态)和 `insurance_status`(保险状态)。 + +以往在订单**尚无合同**或**尚无保险**时,这两列的值以字符串 `"NONE"` 写入并通过接口返回给前端。此次统一语义:「无记录」状态改为返回 `null`,不再返回字符串 `"NONE"`。 + +涉及枚举值(有进展时不变): +- 合同:`GENERATING` / `GENERATED` / `SIGNED` / `VOIDED` / `RESIGNING` +- 保险:`INSURING` / `INSURED` / `CANCELLED` / `FAILED` + +--- +## ② 变更清单 + +| # | 接口 | 字段路径 | 变更 | +|---|------|----------|------| +| 1 | `GET /v3/admin/order/{id}` | `main.contractStatus` | 无合同时:`"NONE"` → `null` | +| 2 | `GET /v3/admin/order/{id}` | `main.insuranceStatus` | 无保险时:`"NONE"` → `null` | +| 3 | `GET /v3/admin/order/{id}/contract-insurance` | `contract.contractStatus` | 无合同时:`"NONE"` → `null` | +| 4 | `GET /v3/admin/order/{id}/contract-insurance` | `insurance.insuranceStatus` | 无保险时:`"NONE"` → `null` | +| 5 | `GET /v3/admin/order/group-batch/{groupBatchId}/orders` | `[*].contractStatus` | 无合同时:`"NONE"` → `null` | +| 6 | `GET /v3/admin/order/group-batch/{groupBatchId}/orders` | `[*].insuranceStatus` | 无保险时:`"NONE"` → `null` | + +> 订单列表 `GET /v3/admin/order/list` 返回的 `OrderListItemRespVO` **不含**这两个字段,不受影响。 + +--- +## ③ 接口详情 + +### 接口一:订单详情(9 Tab 聚合) + +| 项 | 值 | +|---|---| +| 方法 + 路径 | `GET /v3/admin/order/{id}` | +| 接口名 | 订单详情(9 Tab 聚合) | +| 认证 | 需要 JWT(管理后台 token) | +| 幂等性 | 只读,天然幂等 | +| 限流 | 无特殊限流 | + +### 接口二:合同保险 Tab + +| 项 | 值 | +|---|---| +| 方法 + 路径 | `GET /v3/admin/order/{id}/contract-insurance` | +| 接口名 | 订单合同保险 Tab | +| 认证 | 需要 JWT(管理后台 token) | +| 幂等性 | 只读,天然幂等 | +| 限流 | 无特殊限流 | + +### 接口三:团期子订单列表 + +| 项 | 值 | +|---|---| +| 方法 + 路径 | `GET /v3/admin/order/group-batch/{groupBatchId}/orders` | +| 接口名 | 团期子订单列表 | +| 认证 | 需要 JWT(管理后台 token) | +| 幂等性 | 只读,天然幂等 | +| 限流 | 无特殊限流 | + +--- +## ④ 接口入参 + +三个接口均为路径参数,本次变更不影响入参。 + +| 参数 | 位置 | 类型 | 必填 | 说明 | +|------|------|------|------|------| +| `id` | Path | Long | 是 | 订单 ID(接口一、二) | +| `groupBatchId` | Path | Long | 是 | 团期 ID(接口三) | + +--- + +## ⑤ 出参字段(受影响字段) + +### 接口一 `GET /v3/admin/order/{id}` — `main` 节点 + +| 字段路径 | 类型 | 说明 | +|----------|------|------| +| `main.contractStatus` | `String \| null` | 合同状态。**无合同时返回 `null`**(原来返回 `"NONE"`);有合同时为枚举值,见 § ⑥ | +| `main.insuranceStatus` | `String \| null` | 保险状态。**无保险时返回 `null`**(原来返回 `"NONE"`);有保险时为枚举值,见 § ⑥ | + +### 接口二 `GET /v3/admin/order/{id}/contract-insurance` + +| 字段路径 | 类型 | 说明 | +|----------|------|------| +| `contract.contractStatus` | `String \| null` | 合同状态。**无合同时返回 `null`** | +| `insurance.insuranceStatus` | `String \| null` | 保险状态。**无保险时返回 `null`** | + +其余字段(`contractSignedAt`、`contractFileUrl`、`events`、`insurancePolicyNo`、`insurancePremium` 等)在无合同/无保险时仍返回 `null`,无变化。 + +### 接口三 `GET /v3/admin/order/group-batch/{groupBatchId}/orders` — 列表项 + +| 字段路径 | 类型 | 说明 | +|----------|------|------| +| `[*].contractStatus` | `String \| null` | 合同状态。**无合同时返回 `null`** | +| `[*].insuranceStatus` | `String \| null` | 保险状态。**无保险时返回 `null`** | + +--- +## ⑥ 枚举 / 数据字典 + +### contractStatus 合同状态 + +| 枚举值 | 含义 | 备注 | +|--------|------|------| +| `null` | 无合同记录 | **本次新值**(原来是 `"NONE"`) | +| `GENERATING` | 合同生成中 | | +| `GENERATED` | 合同已生成(待签署) | | +| `SIGNED` | 已签署 | | +| `VOIDED` | 已作废 | | +| `RESIGNING` | 重新签署中 | | + +### insuranceStatus 保险状态 + +| 枚举值 | 含义 | 备注 | +|--------|------|------| +| `null` | 无保险记录 | **本次新值**(原来是 `"NONE"`) | +| `INSURING` | 出单中 | | +| `INSURED` | 已投保 | | +| `CANCELLED` | 已取消 | | +| `FAILED` | 出单失败 | | + +--- +## ⑦ 错误码 + +本次变更不新增错误码。以下为接口既有错误码: + +| 错误码 | HTTP 状态 | 说明 | +|--------|-----------|------| +| `587000` | 400 | 订单不存在 | + +--- + +## ⑧ 示例 + +### 8.1 典型成功——订单已签约并已投保 + +**请求** +```http +GET /v3/admin/order/2000000001 +Authorization: Bearer +``` + +**响应(main 节点节选)** +```json +{ + "code": 200, + "data": { + "main": { + "id": "2000000001", + "orderNo": "HL20260601001", + "orderStatus": "ON_TRIP", + "contractStatus": "SIGNED", + "insuranceStatus": "INSURED", + "refundStatus": null, + "hasRefund": false + } + } +} +``` + +**合同保险 Tab(`GET /v3/admin/order/2000000001/contract-insurance`)** +```json +{ + "code": 200, + "data": { + "contract": { + "contractStatus": "SIGNED", + "contractSignedAt": "2026-06-01T10:30:00", + "contractFileUrl": "https://oss.hulalv.com/contract/HL20260601001.pdf", + "events": [ + { "eventType": "GENERATE", "occurredAt": "2026-06-01T10:00:00" }, + { "eventType": "SIGN", "occurredAt": "2026-06-01T10:30:00" } + ] + }, + "insurance": { + "insuranceStatus": "INSURED", + "insurancePolicyNo": "PICC2026060100123", + "insurancePremium": 88.00, + "events": [ + { "eventType": "ISSUE", "occurredAt": "2026-06-01T10:35:00" } + ] + } + } +} +``` + +--- +### 8.2 边界情况——订单刚创建,尚无合同和保险 + +**响应(main 节点节选)** +```json +{ + "code": 200, + "data": { + "main": { + "id": "2000000002", + "orderNo": "HL20260602001", + "orderStatus": "CUSTOMIZING", + "contractStatus": null, + "insuranceStatus": null, + "hasRefund": false + } + } +} +``` + +**合同保险 Tab** +```json +{ + "code": 200, + "data": { + "contract": { + "contractStatus": null, + "contractSignedAt": null, + "contractFileUrl": null, + "events": [] + }, + "insurance": { + "insuranceStatus": null, + "insurancePolicyNo": null, + "insurancePremium": null, + "events": [] + } + } +} +``` + +**团期子订单列表(`GET /v3/admin/order/group-batch/3000000001/orders`,无合同无保险的子订单项节选)** +```json +{ + "code": 200, + "data": [ + { + "orderId": "2000000002", + "orderNo": "HL20260602001", + "contractStatus": null, + "insuranceStatus": null, + "payStatus": "UNPAID" + } + ] +} +``` + +### 8.3 业务失败——订单 ID 不存在 + +**请求** +```http +GET /v3/admin/order/9999999999 +``` + +**响应** +```json +{ + "code": 587000, + "msg": "订单不存在" +} +``` + +--- +## ⑨ 业务边界 + +**适用**: +- 创建后尚未触发签约的订单:`contractStatus` 返回 `null` +- 创建后尚未触发投保的订单:`insuranceStatus` 返回 `null` +- 合同被作废后重新签署流程未开始的中间态仍走枚举值(`VOIDED` → `RESIGNING`),不返回 `null` + +**不适用(不返回 null)**: +- 合同/保险流程一旦触发(任意枚举值),即使中途失败(`FAILED`)也返回枚举值而非 `null` + +**特殊边界**: +- 若历史订单数据库列值为 `"NONE"`(迁移前旧数据),后端读取时统一转换为 `null` 再返回,前端不会收到字符串 `"NONE"` + +--- + +## ⑩ 修改前后对比 + +### 字段级对比 + +| 字段 | 无合同/无保险时修改前 | 无合同/无保险时修改后 | +|------|---------------------|---------------------| +| `contractStatus` | `"NONE"` | `null` | +| `insuranceStatus` | `"NONE"` | `null` | + +三个接口均适用此对比。有合同/有保险时枚举值**不变**。 + +### 行为级对比 + +| 场景 | 修改前 | 修改后 | +|------|--------|--------| +| 新建订单查详情 | `contractStatus: "NONE"` | `contractStatus: null` | +| 查合同保险 Tab | `contract.contractStatus: "NONE"` | `contract.contractStatus: null` | +| 团期子订单列表 | `contractStatus: "NONE"` | `contractStatus: null` | + +--- + +## ⑪ 影响评估 / 回滚 + +### 破坏兼容 + +**破坏性变更**。若前端代码以 `contractStatus === "NONE"` 或 `insuranceStatus === "NONE"` 判断「无状态」,**需改为 `contractStatus == null`**(或 `!contractStatus`),否则判断会失效。 + +### 前端同步要求 + +前端需在本次后端上线前(或同时)完成如下改动: + +1. 所有判断 `contractStatus === "NONE"` 的地方改为 `contractStatus == null`(或 `!contractStatus`) +2. 所有判断 `insuranceStatus === "NONE"` 的地方改为 `insuranceStatus == null`(或 `!insuranceStatus`) +3. 合同 Tab 徽标逻辑:判断是否显示「无合同」状态从 `=== "NONE"` 改为 `=== null` +4. 保险 Tab 徽标逻辑:同上 + +### 回滚方案 + +后端可在镜像写入层回退 `null → "NONE"` 兜底逻辑,重新发布即生效,无需 DDL。 + +--- + +## ⑫ 注意事项 + +1. **三个接口同时生效**:`GET /v3/admin/order/{id}`、`GET /v3/admin/order/{id}/contract-insurance`、`GET /v3/admin/order/group-batch/{groupBatchId}/orders` 同批上线,需一次性适配,不存在分步过渡。 +2. **历史数据已处理**:后端上线时同步处理库中存量 `"NONE"` 值,前端永远不会收到字符串 `"NONE"`,无需做兼容两个值的过渡逻辑。 +3. **列表接口不受影响**:`GET /v3/admin/order/list` 返回的列表项 VO 不含 `contractStatus` / `insuranceStatus`,无需处理。 +4. **枚举值语义不变**:除 `"NONE"` 变为 `null` 外,其余枚举值含义和拼写完全不变。 + +--- + +## ⑬ 关联 / 联系人 + +| 项 | 链接 | +|---|------| +| Issue | [#3953 合同/保险镜像状态统一 NONE→null](https://git.1814.love:8443/wx/HL/issues/3953) | +| PR | [#3956 refactor(order-v3): 合同/保险镜像状态统一 NONE→null](https://git.1814.love:8443/wx/HL/pulls/3956) | +| Feature Commit | [dc21950a9](https://git.1814.love:8443/wx/HL/commit/dc21950a9) | +| Merge Commit | [41cfd5ad8](https://git.1814.love:8443/wx/HL/commit/41cfd5ad8) | +| 后端负责人 | 腰苏图(yaosutu) |