---
date: 2026-05-07
type: frontend-bug
module: contract-generate
priority: high
notify: ["@mmg"]
status: pending
source: 测试用例汇总.xlsx (2026-05-07) + /@bug 实测
related_cases: [HT-001]
gitea_issue_closed: 1788
---

# 合同生成显示"网络错误" — 实为前端 axios 误判 + 雪花 ID 精度丢失

## 原始现象

测试用例 HT-001：合同生成报"网络错误"。

## /@bug 实测结论（admin 真 token round-trip）

后端 `POST /admin/contract/create-by-scheme` HTTP **全部 200**，5 个 case 测试结果：

| Case | 入参 | 业务 code | 含义 |
|------|------|-----------|------|
| A | DEPOSIT_PAID 订单+schemeId=3 | 510208 | 出行人未补全（业务校验，正确） |
| B | 订单+schemeId=`2046840448906940417`（19 位 Long） | 510205 | **前端把雪花 ID 序列化为 JS Number，后 4 位精度丢失** |
| C | CONFIRMED 订单+schemeId=3 | **200** | **生成成功**，contractId=2052278173260824577 |
| D | 不存在 orderId | 510207 | 订单不存在（正确） |

**结论**：后端纯净，根因在前端两处。

## 根因 1：axios interceptor 误把业务码当 HTTP 5xx

本项目 P0 铁律：**HTTP 始终 200，业务码在 `Result.code`**。

前端 axios interceptor 看到 `code:5xxxxx`（业务码格式 `xxxxxx` 6 位），可能误判为 HTTP 5xx 异常，统一显示"网络错误"，**用户根本看不到 body.message** 提示的真实业务原因（如"出行人未补全"）。

### 修复方向

```js
// 错误（推断）：
axios.interceptors.response.use(resp => {
  if (String(resp.data.code).startsWith('5')) {
    showToast('网络错误')  // ❌ 业务码 510208 被误判为 5xx
    throw new Error()
  }
  return resp.data
})

// 正确：
axios.interceptors.response.use(resp => {
  const { code, message, data } = resp.data
  if (code !== 200) {
    showToast(message || `操作失败 (${code})`)  // ✅ 显示后端真实 message
    throw new BizError(code, message)
  }
  return data
})
```

## 根因 2：雪花 ID schemeId 没字符串化

后端 schemeId 是 19 位 Long（雪花算法），最大值 `2^63-1 ≈ 9.22e18`。
JS Number 精度上限 `Number.MAX_SAFE_INTEGER = 2^53-1 ≈ 9.007e15`。

19 位 Long 直接被 JS Number 接收会**丢失后 3-4 位精度**，发回后端的 ID 已经不是原值。

### 实测证据（case B）

```
原值:    2046840448906940417
JS 后:   2046840448906940000  ← 后 4 位变 0
后端:    schemeId 不存在 → code:510205
```

### 修复方向

```js
// 1. axios 配置 transformResponse 用 json-bigint 解析
import JSONbig from 'json-bigint'
axios.defaults.transformResponse = [data => JSONbig.parse(data)]

// 2. 或后端 Long 字段 @JsonSerialize(using = ToStringSerializer.class)
//    → 但本项目历史决定，前端处理更省事

// 3. 或前端拿到 ID 后立即转 String，传回时也按 String 传
const schemeId = String(resp.schemeId)  // 显式字符串化
```

类似已知坑：memory `feedback_http-200-check-business-code.md`、项目其他列表用雪花 ID 的地方都需要复检。

## 影响

- 合同生成完全无法触发（用户看到"网络错误"放弃）
- 间接影响所有调用合同接口的页面

## 验收（前端）

- [ ] 合同生成失败时 toast 显示后端真实 message（如"出行人未补全"）
- [ ] CONFIRMED 订单 + 真实 schemeId → 合同生成成功（HTTP 200 + code:200）
- [ ] axios 全局检查：所有调用涉及雪花 ID 的接口（订单 ID/产品 ID/方案 ID/合同 ID）都按 String 处理
- [ ] 业务码 5xxxxx 不再被误判为网络错误

## 关联工单

Gitea #1788 已关闭并留 closing comment（项目规则前端 BUG 不建工单）。
完整分析报告：`docs/tasks/20260507_bug_contract_analysis.md`
