# [修改接口·管理后台] 订单详情枚举统一 + service-standard 修复 (#2867 #2868)

> **PR**: #2869 #2874 | **服务**: hl-order-service-v3 | **更新时间**: 2026-05-22

## 1. 接口背景

本次修复合并两个 PR，均针对订单详情页管理后台接口的静默 bug：

- **PR #2869（Issue #2868）枚举统一 + null 兑底**：contractStatus / insuranceStatus 两个字段历史上枚举値定义不完整（少了中间过渡态和 NONE 初始态），且在订单还未进入合同/保险流程时后端直接返回 null，前端字典无法匹配导致显示空白或"未知"。本次统一枚举値集并将 null 兑底为 "NONE"。

- **PR #2874（Issue #2867）service-standard Tab 修复**：hasServiceStandard 字段原来只判断快照记录是否存在（行存在即返回 true），未校验反序列化是否成功、itinerary 是否非空，导致前端收到 hasServiceStandard=true 后调 GET /service-standard 接口却收到 data=null 的矛盾。根因是快照 itinerary 字段类型 List<String> 与源头 List<DayItem> 不匹配，反序列化失败被静默吞掉。

## 2. 变更清单

| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|------|------|------|----------|------|
| 1 | 订单详情 | GET | `/v3/admin/order/{id}` | 修改接口 | contractStatus/insuranceStatus 枚举统一；hasServiceStandard 判定逻辑修复 |
| 2 | 合同&保险 Tab | GET | `/v3/admin/order/{id}/contract-insurance` | 修改接口 | contractStatus/insuranceStatus 枚举统一，null 兑底为 NONE |
| 3 | 服务标准 Tab | GET | `/v3/admin/order/{id}/service-standard` | 修改接口（行为修复） | 原来 data 永远 null；现在能正常返回完整数据 |

## 3. 接口详情

### 3.1 GET /v3/admin/order/{id} —— 订单详情

- **使用场景**：管理后台订单详情页首次加载，获取订单主信息
- **认证**：需要管理后台 JWT（Bearer token），role=ADMIN
- **幂等性**：是（只读）
- **限流**：无

**本次变更字段**：
- `data.main.contractStatus`：枚举値扩展（4→6 値），null → `"NONE"`
- `data.main.insuranceStatus`：枚举値扩展（4→5 値），null → `"NONE"`
- `data.main.hasServiceStandard`：判定逻辑修复（见 §9）

### 3.2 GET /v3/admin/order/{id}/contract-insurance —— 合同&保险 Tab

- **使用场景**：管理后台订单详情页切换到 "合同&保险" Tab 时调用
- **认证**：需要管理后台 JWT（Bearer token），role=ADMIN
- **幂等性**：是（只读）
- **限流**：无

**本次变更字段**：
- `data.contract.contractStatus`：枚举値扩展（4→6 値），null → `"NONE"`
- `data.insurance.insuranceStatus`：枚举値扩展（4→5 値），null → `"NONE"`

### 3.3 GET /v3/admin/order/{id}/service-standard —— 服务标准 Tab

- **使用场景**：管理后台订单详情页切换到 "服务标准" Tab 时调用；应在 `hasServiceStandard=true` 时才调此接口
- **认证**：需要管理后台 JWT（Bearer token），role=ADMIN
- **幂等性**：是（只读）
- **限流**：无

**本次变更**：行为修复。修复前 data 永远为 null；修复后在有效快照时返回完整结构。

## 4. 接口入参

### 4.1 路径参数

三个接口入参相同，无变化。

| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `id` | Long（String） | 是 | 订单 ID（snowflake，JSON 传 String 防精度丢失） |

### 4.2 请求体字段

三个接口均为 GET，无请求体。

## 5. 出参（响应）

### 5.1 GET /v3/admin/order/{id} —— 变更字段

| 字段路径 | 类型 | 说明 |
|----------|------|------|
| `data.main.contractStatus` | String（枚举） | 合同状态，见 §6.1。**本次扩展枚举値 + null 兑底** |
| `data.main.insuranceStatus` | String（枚举） | 保险状态，见 §6.2。**本次扩展枚举値 + null 兑底** |
| `data.main.hasServiceStandard` | Boolean | 是否有服务标准快照。**本次修复判定逻辑** |

### 5.2 GET /v3/admin/order/{id}/contract-insurance —— 变更字段

| 字段路径 | 类型 | 说明 |
|----------|------|------|
| `data.contract.contractStatus` | String（枚举） | 合同状态，见 §6.1。**本次扩展枚举値 + null 兑底** |
| `data.insurance.insuranceStatus` | String（枚举） | 保险状态，见 §6.2。**本次扩展枚举値 + null 兑底** |

### 5.3 GET /v3/admin/order/{id}/service-standard —— ServiceStandardVO（完整）

| 字段 | 类型 | 说明 |
|------|------|------|
| `data.itinerary` | List<String> | 行程列表，元素格式："Day{n} {title}"，如 "Day1 抵达成都"。**修复前恒为 null，修复后正常返回** |
| `data.notice` | String | 出行须知。可为 null |
| `data.refundPolicy` | String | 退款政策说明。可为 null |

当订单无服务标准快照时（`hasServiceStandard=false`），整个 `data` 为 null。

## 6. 枚举 / 数据字典

### 6.1 contractStatus（合同状态）

**所属字段**：`data.main.contractStatus`（OrderMainVO）、`data.contract.contractStatus`（ContractInsuranceVO）| **类型**：`String`

| 値 | 中文 | 说明 |
|----|------|------|
| `NONE` | 无合同 | 订单尚未进入签约流程（修复前此状态返回 null） |
| `GENERATING` | 生成中 | 合同正在后台生成 |
| `GENERATED` | 已生成 | 合同已生成，待客户签署 |
| `SIGNED` | 已签署 | 客户已完成签署 |
| `VOIDED` | 已作废 | 合同已作废 |
| `RESIGNING` | 重签中 | 合同正在重新发起签署 |

**修复前仅有4 値**：PENDING / GENERATED / SIGNED / VOIDED（PENDING 已废弃，NONE / GENERATING / RESIGNING 为本次新增枚举値）

### 6.2 insuranceStatus（保险状态）

**所属字段**：`data.main.insuranceStatus`（OrderMainVO）、`data.insurance.insuranceStatus`（ContractInsuranceVO）| **类型**：`String`

| 値 | 中文 | 说明 |
|----|------|------|
| `NONE` | 无保险 | 订单尚未进入投保流程（修复前此状态返回 null） |
| `ISSUING` | 投保中 | 保险正在后台出单 |
| `ISSUED` | 已出单 | 保险已成功出单 |
| `CANCELLED` | 已取消 | 保险已取消 |
| `FAILED` | 出单失败 | 保险出单失败 |

**修复前仅有4 値**：PENDING / ACTIVE / FAILED / CANCELLED（旧値已废弃重命名，全部替换为上表5 値）

## 7. 错误码

本次修复无新增错误码。

| code | 含义 | 触发场景 |
|------|------|----------|
| `200` | 成功 | 正常响应 |
| `1000400` | 参数异常 | 路径参数 `id` 格式错误 |
| `1000404` | 订单不存在 | 指定 id 的订单不存在或已删除 |
| `1000403` | 无权限 | 非管理员 token 访问 |

## 8. 示例

### 8.1 典型成功 —— 新建订单 contractStatus 返 NONE（修复前返 null）

**请求**：

```
GET /v3/admin/order/1921234567890123456
Authorization: Bearer <admin-jwt-token>
```

**响应**：

```json
{
  "code": 200,
  "data": {
    "main": {
      "orderId": "1921234567890123456",
      "orderNo": "ORD20260522001",
      "contractStatus": "NONE",
      "insuranceStatus": "NONE",
      "hasServiceStandard": false
    }
  },
  "message": "ok",
  "success": true
}
```

> 修复前：contractStatus: null，insuranceStatus: null，前端字典无法匹配显示空白。

### 8.2 边界情况 —— service-standard 接口有快照时返完整数据（修复前永远 null）

**请求**：

```
GET /v3/admin/order/1921234567890123456/service-standard
Authorization: Bearer <admin-jwt-token>
```

**响应（修复后）**：

```json
{
  "code": 200,
  "data": {
    "itinerary": [
      "Day1 抵达成都，入住民宿",
      "Day2 前往峨眉山景区",
      "Day3 返程"
    ],
    "notice": "请携带身份证原件，到达后联系导游",
    "refundPolicy": "出发7天以上全额退款，7天内收取50%手续费"
  },
  "message": "ok",
  "success": true
}
```

**响应（修复前）**：

```json
{
  "code": 200,
  "data": null,
  "message": "ok",
  "success": true
}
```

### 8.3 业务失败 —— hasServiceStandard=false 时 service-standard 返 data=null（正常行为）

**场景说明**：订单未绑定产品行程快照，调 service-standard 接口返 data=null 是正常行为。

**请求**：

```
GET /v3/admin/order/1921111111111111111/service-standard
Authorization: Bearer <admin-jwt-token>
```

**响应**：

```json
{
  "code": 200,
  "data": null,
  "message": "ok",
  "success": true
}
```

## 9. 业务边界

**hasServiceStandard 判定逻辑（修复后）**：

同时满足以下三个条件，`hasServiceStandard` 才返回 `true`：
1. 订单关联的产品行程快照记录存在
2. 快照 JSON 反序列化成功（无类型错误）
3. 快照中 `itinerary` 字段非空（至少有1天行程）

任意一个条件不满足，`hasServiceStandard` 返回 `false`，此时调 `GET /service-standard` 将返回 `data=null`。

**contractStatus / insuranceStatus 兑底规则**：
- 订单刚创建、尚未发起签约/投保时，两个字段返回 "NONE"（修复前返回 null）
- 字段値随后端状态机流转更新，不需要前端轮询，刷新页面即可获取最新値

## 10. 修改前后对比

### 10.1 字段级对比

| 字段 | 修复前 | 修复后 |
|------|--------|--------|
| `contractStatus`（初始态） | null | "NONE" |
| `contractStatus`（枚举集合） | PENDING / GENERATED / SIGNED / VOIDED（4 値，含PENDING已废弃） | NONE / GENERATING / GENERATED / SIGNED / VOIDED / RESIGNING（6 値） |
| `insuranceStatus`（初始态） | null | "NONE" |
| `insuranceStatus`（枚举集合） | PENDING / ACTIVE / FAILED / CANCELLED（4 値，均已废弃重命名） | NONE / ISSUING / ISSUED / CANCELLED / FAILED（5 値） |
| `hasServiceStandard` | 只判断快照行存在，partial 快照也返 true | 快照存在 + 反序列化成功 + itinerary 非空，三条件全满足才返 true |
| GET /service-standard data | 永远为 null（反序列化失败被吐） | 有效快照时返回完整 {itinerary, notice, refundPolicy} |

### 10.2 行为级对比

| 行为 | 修复前 | 修复后 |
|------|--------|--------|
| 新建订单合同/保险状态 | 返回 null，前端字典无法匹配 | 返回 "NONE"，字典正常匹配显示"无合同"/"无保险" |
| hasServiceStandard=true 但 Tab 内容空 | 会出现（快照反序列化失败时） | 不再出现；hasServiceStandard=true 一定能拿到有效数据 |
| insuranceStatus 枚举 ACTIVE / PENDING | 后端可能返回这两个値 | 后端不再返回，统一替换为新枚举値集合 |

## 11. 影响评估 / 回滚

### 11.1 影响评估

- **是否破坏向后兼容**：是（枚举値重命名）。旧字典如只有 PENDING / ACTIVE（保险）或 PENDING（合同）等旧値，遇到新値会显示 "未知"。
- **前端是否必须同步上线**：建议同步更新枚举字典（§6.1 和 §6.2 完整値表）再上线；若前端能容忍旧値显示 "未知" 可先不同步。

### 11.2 回滚方案

- **回滚方式**：revert PR #2869 / PR #2874，重新打包部署 hl-order-service-v3
- **回滚后影响**：contractStatus / insuranceStatus 恢复返回 null 和旧枚举値；service-standard Tab 恢复返回 null

## 12. 注意事项

- **枚举字典必须更新**：旧前端字典仅有4 値/4 値（含已废弃的 PENDING / ACTIVE），遇到新枚举値（如 NONE / GENERATING / RESIGNING / ISSUING / ISSUED）会显示 "未知"。请按 §6.1 和 §6.2 完整値表更新本地枚举字典。
- **旧枚举値已废弃**：contractStatus 的 PENDING、insuranceStatus 的 PENDING 和 ACTIVE 后端不再返回，前端字典保留无害但不会再出现。
- **service-standard workaround 清理**：如果前端之前针对 hasServiceStandard=true 但 data=null 的矛盾做过兑底处理（如显示固定占位文案、屏蔽Tab），修复后可以移除该 workaround。

## 13. 关联 / 联系人

### 13.1 链接

- **Issue（枚举统一）**: [#2868](https://git.1814.love:8443/wx/HL/issues/2868)
- **Issue（service-standard 修复）**: [#2867](https://git.1814.love:8443/wx/HL/issues/2867)
- **PR（枚举统一）**: [#2869](https://git.1814.love:8443/wx/HL/pulls/2869)
- **PR（service-standard 修复）**: [#2874](https://git.1814.love:8443/wx/HL/pulls/2874)
- **Merge commit（枚举统一）**: [bb4c41969](https://git.1814.love:8443/wx/HL/commit/bb4c41969)
- **Merge commit（service-standard 修复）**: [442fdf089](https://git.1814.love:8443/wx/HL/commit/442fdf089)

### 13.2 联系人

- **后端负责人**: @yst
