- 受影响接口: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
11 KiB
合同/保险镜像状态"无记录"时从 "NONE" 改为 null
- 变更类型:修改接口
- 端类型:管理后台
- 日期:2026-06-18
- Issue:#3953
- PR:#3956
- Commit:dc21950a9(feature)/ 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 典型成功——订单已签约并已投保
请求
GET /v3/admin/order/2000000001
Authorization: Bearer <token>
响应(main 节点节选)
{
"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)
{
"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 节点节选)
{
"code": 200,
"data": {
"main": {
"id": "2000000002",
"orderNo": "HL20260602001",
"orderStatus": "CUSTOMIZING",
"contractStatus": null,
"insuranceStatus": null,
"hasRefund": false
}
}
}
合同保险 Tab
{
"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,无合同无保险的子订单项节选)
{
"code": 200,
"data": [
{
"orderId": "2000000002",
"orderNo": "HL20260602001",
"contractStatus": null,
"insuranceStatus": null,
"payStatus": "UNPAID"
}
]
}
8.3 业务失败——订单 ID 不存在
请求
GET /v3/admin/order/9999999999
响应
{
"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),否则判断会失效。
前端同步要求
前端需在本次后端上线前(或同时)完成如下改动:
- 所有判断
contractStatus === "NONE"的地方改为contractStatus == null(或!contractStatus) - 所有判断
insuranceStatus === "NONE"的地方改为insuranceStatus == null(或!insuranceStatus) - 合同 Tab 徽标逻辑:判断是否显示「无合同」状态从
=== "NONE"改为=== null - 保险 Tab 徽标逻辑:同上
回滚方案
后端可在镜像写入层回退 null → "NONE" 兜底逻辑,重新发布即生效,无需 DDL。
⑫ 注意事项
- 三个接口同时生效:
GET /v3/admin/order/{id}、GET /v3/admin/order/{id}/contract-insurance、GET /v3/admin/order/group-batch/{groupBatchId}/orders同批上线,需一次性适配,不存在分步过渡。 - 历史数据已处理:后端上线时同步处理库中存量
"NONE"值,前端永远不会收到字符串"NONE",无需做兼容两个值的过渡逻辑。 - 列表接口不受影响:
GET /v3/admin/order/list返回的列表项 VO 不含contractStatus/insuranceStatus,无需处理。 - 枚举值语义不变:除
"NONE"变为null外,其余枚举值含义和拼写完全不变。
⑬ 关联 / 联系人
| 项 | 链接 |
|---|---|
| Issue | #3953 合同/保险镜像状态统一 NONE→null |
| PR | #3956 refactor(order-v3): 合同/保险镜像状态统一 NONE→null |
| Feature Commit | dc21950a9 |
| Merge Commit | 41cfd5ad8 |
| 后端负责人 | 腰苏图(yaosutu) |