322 行
13 KiB
Markdown
322 行
13 KiB
Markdown
# mp-service: 保险/合同详情 5 个接口梳理 + 合同接口返回值强类型化
|
||
|
||
> **服务** hl-mp-service(端口 8085)→ 透传 hl-order-service-v2(端口 8094)
|
||
> **PR**: wx/HL#1314 · **Issue**: wx/HL#1312
|
||
> **日期**: 2026-04-23
|
||
> **影响范围**: C 端「订单详情页」保险详情弹窗、合同详情、保单 PDF 下载
|
||
|
||
---
|
||
|
||
## ⚠️ 关键变化
|
||
|
||
合同相关 3 个接口(`GET /mp/contract/list` / `GET /mp/contract/{id}` / `GET /mp/contract/by-order/{orderId}`)的返回值类型从后端弱类型 `Map<String, Object>` 改为具名 VO(`MpContractVO` / `MpContractDetailVO`)。**JSON 结构与字段名均未改变**,Swagger 上能看到具名 schema 了,前端无需改动;本 changelog 重点是一次性把这 5 个接口契约梳理清楚。
|
||
|
||
---
|
||
|
||
## 一、接口清单
|
||
|
||
| # | 接口 | 方法 | 路径 | 返回类型 |
|
||
|---|------|------|------|----------|
|
||
| 1 | 订单详情聚合(含保险详情) | GET | `/mp/order/{orderId}/dashboard` | `MpOrderDashboardVO`(取 `.insurance` 字段) |
|
||
| 2 | 合同详情(按订单) | GET | `/mp/contract/by-order/{orderId}` | `MpContractVO` |
|
||
| 3 | 合同详情(按合同 ID) | GET | `/mp/contract/{id}` | `MpContractDetailVO` |
|
||
| 4 | 订单保单合并 PDF | GET | `/mp/insurance/policy-pdf/{orderId}` | `Map<String,Object>`(透传 `PolicyShareVO`) |
|
||
| 5 | 单张保单下载 | GET | `/mp/insurance/policy/{insuranceOrderId}/download` | `String`(Base64) |
|
||
|
||
- 全部需要登录,`userId` 由 mp-service 从 token 中取出后透传给 order-v2
|
||
- 仅 5 号需要 `insuranceOrderId`,该 ID 来自订单详情出行人的 `insurancePolicies[].insuranceOrderId`
|
||
|
||
---
|
||
|
||
## 二、接口详情
|
||
|
||
### 1. 保险详情 `GET /mp/order/{orderId}/dashboard`
|
||
|
||
保险详情没有独立接口,走订单详情聚合 `MpOrderDashboardVO`,取 `.insurance` 字段(`MpInsuranceDetailVO`)。未投保或查询失败时该字段为 `null`(降级,不阻断页面)。
|
||
|
||
#### 入参
|
||
|
||
| 字段 | 位置 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|------|
|
||
| `orderId` | Path | Long | ✅ | 订单 ID |
|
||
|
||
#### 出参 `Result<MpOrderDashboardVO>` — 聚合 VO 全字段
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| `order` | `MpOrderDetailVO` | 订单主体(详见 2026-04-17 订单详情 changelog) |
|
||
| `preTripChecklist` | `MpPreTripChecklistVO` | 出发准备清单(降级时 null) |
|
||
| `files.contract` | `MpContractSummaryVO` | 合同摘要(无合同 null) |
|
||
| `files.invoice` | `MpInvoiceSummaryVO` | 发票摘要(未开票 null) |
|
||
| `files.insurancePolicyPdfUrl` | `String` | 保单合并 PDF 下载路径,固定为 `/mp/insurance/policy-pdf/{orderId}` |
|
||
| `insurance` | `MpInsuranceDetailVO` | **保险详情(本 changelog 重点字段)** |
|
||
| `refund` | `RefundVO` | 退款模块(仅取消/退款中状态有值) |
|
||
|
||
#### `insurance`(`MpInsuranceDetailVO`)字段
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| `schemeId` | Long | 方案 ID |
|
||
| `schemeName` | String | 方案名称 |
|
||
| `description` | String | 方案描述 |
|
||
| `isOverseas` | Boolean | 是否境外 |
|
||
| `totalDays` | Integer | 适用行程天数 |
|
||
| `notice` | String | 保险告知状态:`INCLUDED` / `OPTIONAL` / `EXCLUDED` |
|
||
| `segments` | `List<CoverageSegment>` | 保障分段列表 |
|
||
| `segments[].segmentName` | String | 分段名称 |
|
||
| `segments[].dayOffsetStart` | Integer | 起始天 |
|
||
| `segments[].dayOffsetEnd` | Integer | 结束天(`-1` = 最后一天) |
|
||
| `segments[].productName` | String | 保险产品名称 |
|
||
| `segments[].planName` | String | 保险计划名称 |
|
||
| `policies` | `List<PolicyItem>` | 投保记录列表(未投保为空数组) |
|
||
| `policies[].insuranceOrderId` | Long | 保险订单 ID(用于接口 5 下载) |
|
||
| `policies[].policyNo` | String | 保单号 |
|
||
| `policies[].productName` | String | 保险产品名称 |
|
||
| `policies[].planName` | String | 计划名称 |
|
||
| `policies[].premium` | BigDecimal | 保费(元) |
|
||
| `policies[].insuredCount` | Integer | 被保人数 |
|
||
| `policies[].coverageStartDate` | LocalDate | 保障开始日期 |
|
||
| `policies[].coverageEndDate` | LocalDate | 保障结束日期 |
|
||
| `policies[].status` | String | 保险状态:`PENDING` / `INSURING` / `INSURED` / `FAILED`(`CANCELLED` 已过滤不返回) |
|
||
| `policies[].statusLabel` | String | 状态中文标签 |
|
||
| `policies[].insuredPersons` | `List<InsuredPerson>` | 被保人列表 |
|
||
| `insuredPersons[].name` | String | 姓名(明文,脱敏由前端处理) |
|
||
| `insuredPersons[].idCardType` | String | 证件类型:`ID_CARD` / `PASSPORT` |
|
||
| `insuredPersons[].idCardNo` | String | 证件号码(明文) |
|
||
| `insuredPersons[].birthday` | LocalDate | 出生日期 |
|
||
| `insuredPersons[].gender` | String | `MALE` / `FEMALE` |
|
||
| `insuredPersons[].phone` | String | 手机号(明文) |
|
||
|
||
---
|
||
|
||
### 2. 合同详情(按订单) `GET /mp/contract/by-order/{orderId}`
|
||
|
||
返回订单关联的**最新**有效合同(非作废),一般用于订单详情页的"合同"入口。
|
||
|
||
#### 入参
|
||
|
||
| 字段 | 位置 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|------|
|
||
| `orderId` | Path | Long | ✅ | 订单 ID |
|
||
|
||
#### 出参 `Result<MpContractVO>`
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| `contractId` | Long | 合同 ID |
|
||
| `orderId` | Long | 订单 ID |
|
||
| `templateCode` | String | 模板编码 |
|
||
| `templateName` | String | 模板名称 |
|
||
| `contractNumber` | String | 合同编号 |
|
||
| `platform` | String | 签约平台 |
|
||
| `contractType` | String | 字典 `contract_type`:`TOUR` / `INSURANCE` |
|
||
| `contractTypeLabel` | String | 合同类型标签 |
|
||
| `mode` | String | 字典 `contract_mode`:`ONLINE` / `OFFLINE` |
|
||
| `modeLabel` | String | 签约模式标签 |
|
||
| `status` | String | 字典 `contract_status` |
|
||
| `statusLabel` | String | 合同状态标签 |
|
||
| `signUrl` | String | 签署 URL |
|
||
| `qrCodeUrl` | String | 签署二维码 URL |
|
||
| `fileUrl` | String | 合同文件 URL |
|
||
| `agencyCode` | String | 旅行社编号 |
|
||
| `travelAgencyName` | String | 旅行社名称 |
|
||
| `destination` | String | 目的地 |
|
||
| `departureDate` | LocalDate | 出发日期 |
|
||
| `returnDate` | LocalDate | 返回日期 |
|
||
| `totalAmount` | BigDecimal | 合同总金额 |
|
||
| `touristCount` | Integer | 出行人数 |
|
||
| `contactName` | String | 联系人姓名(明文,脱敏由前端处理) |
|
||
| `contactPhone` | String | 联系人电话(明文,脱敏由前端处理) |
|
||
| `createTime` | LocalDateTime | 创建时间 |
|
||
|
||
无合同时 `data` 为 `null`。
|
||
|
||
---
|
||
|
||
### 3. 合同详情(按合同 ID) `GET /mp/contract/{id}`
|
||
|
||
按合同 ID 查完整详情,返回合同基本信息 + 出行人签署详情 + 状态变更日志。
|
||
|
||
#### 入参
|
||
|
||
| 字段 | 位置 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|------|
|
||
| `id` | Path | Long | ✅ | 合同 ID |
|
||
|
||
#### 出参 `Result<MpContractDetailVO>`
|
||
|
||
`MpContractDetailVO` 继承 `MpContractVO`(字段见接口 2),额外字段:
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| `supplementaryClause` | String | 补充约定内容 |
|
||
| `travelers` | `List<TravelerInfo>` | 出行人列表 |
|
||
| `travelers[].travelerId` | Long | 出行人 ID |
|
||
| `travelers[].name` | String | 姓名(明文) |
|
||
| `travelers[].idCardType` | String | `ID_CARD` / `PASSPORT` |
|
||
| `travelers[].idCardNo` | String | 证件号码(明文) |
|
||
| `travelers[].phone` | String | 手机号(明文) |
|
||
| `travelers[].isSigner` | Boolean | 是否签署人 |
|
||
| `statusLogs` | `List<MpContractStatusLogVO>` | 状态变更日志 |
|
||
| `statusLogs[].logId` | Long | 日志 ID |
|
||
| `statusLogs[].contractId` | Long | 合同 ID |
|
||
| `statusLogs[].oldStatus` | String | 旧状态 |
|
||
| `statusLogs[].newStatus` | String | 新状态 |
|
||
| `statusLogs[].source` | String | 变更来源:`CALLBACK` / `POLLING` / `MANUAL` |
|
||
| `statusLogs[].rawPayload` | String | 原始载荷(仅调试用) |
|
||
| `statusLogs[].createTime` | LocalDateTime | 创建时间 |
|
||
|
||
权限:合同 `userId` 必须与登录用户一致,否则 403。
|
||
|
||
---
|
||
|
||
### 4. 订单保单合并 PDF `GET /mp/insurance/policy-pdf/{orderId}`
|
||
|
||
合并订单下所有出行人的有效保单为一个 PDF,返回 Base64。
|
||
|
||
#### 入参
|
||
|
||
| 字段 | 位置 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|------|
|
||
| `orderId` | Path | Long | ✅ | 订单 ID |
|
||
|
||
#### 出参 `Result<Map<String,Object>>`(BFF 当前透传 order-v2 `PolicyShareVO`)
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| `pdfBase64` | String | 合并后的保单 PDF(Base64 编码) |
|
||
| `personName` | String | 出行人姓名(订单范围分享时一般为空/null) |
|
||
| `policyCount` | Integer | 成功合并的保单数量 |
|
||
| `failedCount` | Integer | 下载失败的保单数量 |
|
||
|
||
---
|
||
|
||
### 5. 单张保单下载 `GET /mp/insurance/policy/{insuranceOrderId}/download`
|
||
|
||
下载指定保险订单的单张保单 PDF,返回 Base64 字符串。`insuranceOrderId` 从接口 1 的 `insurance.policies[].insuranceOrderId` 取。
|
||
|
||
#### 入参
|
||
|
||
| 字段 | 位置 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|------|
|
||
| `insuranceOrderId` | Path | Long | ✅ | 保险订单 ID(非订单 ID) |
|
||
|
||
#### 出参 `Result<String>`
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| `data` | String | 保单 PDF(Base64 编码) |
|
||
|
||
---
|
||
|
||
## 三、响应示例
|
||
|
||
### 接口 2 `GET /mp/contract/by-order/{orderId}`
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"message": "成功",
|
||
"data": {
|
||
"contractId": 9001,
|
||
"orderId": 20439,
|
||
"templateCode": "TOUR_STANDARD",
|
||
"templateName": "旅游服务合同(标准版)",
|
||
"contractNumber": "HL-2026-0423-0001",
|
||
"platform": "fadada",
|
||
"contractType": "TOUR",
|
||
"contractTypeLabel": "旅游合同",
|
||
"mode": "ONLINE",
|
||
"modeLabel": "线上签署",
|
||
"status": "SIGNED",
|
||
"statusLabel": "已签署",
|
||
"signUrl": "https://sign.fadada.com/xxx",
|
||
"qrCodeUrl": "https://cdn.1814.love/qr-9001.png",
|
||
"fileUrl": "https://cdn.1814.love/contract-9001.pdf",
|
||
"agencyCode": "HULAL001",
|
||
"travelAgencyName": "呼籁旅行",
|
||
"destination": "呼伦贝尔",
|
||
"departureDate": "2026-07-01",
|
||
"returnDate": "2026-07-07",
|
||
"totalAmount": "12600.00",
|
||
"touristCount": 4,
|
||
"contactName": "张三",
|
||
"contactPhone": "13800138000",
|
||
"createTime": "2026-04-20 10:30:00"
|
||
},
|
||
"success": true
|
||
}
|
||
```
|
||
|
||
### 接口 4 `GET /mp/insurance/policy-pdf/{orderId}`
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"message": "成功",
|
||
"data": {
|
||
"pdfBase64": "JVBERi0xLjQKJeLjz9MKMSAwIG9iago8PC9UeX...(截断)",
|
||
"personName": null,
|
||
"policyCount": 4,
|
||
"failedCount": 0
|
||
},
|
||
"success": true
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 四、边界行为
|
||
|
||
- 未登录 → 401(网关拦截)
|
||
- 订单/合同不属于当前 `userId` → 403
|
||
- 订单无合同(接口 2)→ `data: null`
|
||
- 订单未投保(接口 1 的 `insurance` 字段)→ `insurance: null`,不阻断页面
|
||
- 保单 PDF 下载失败(接口 4)→ `failedCount > 0`,`pdfBase64` 仍返回已合并部分;下游整体失败时 BFF 返 `500`
|
||
- 合同服务整体不可用(接口 2/3)→ BFF 返 `500 合同服务不可用,请稍后重试`
|
||
|
||
---
|
||
|
||
## 五、不影响范围
|
||
|
||
- **仅影响**:C 端订单详情页的保险详情弹窗 / 合同详情 / 保单 PDF 下载入口
|
||
- **零影响**:
|
||
- 下单、支付、退款、发票所有接口
|
||
- 合同列表 `GET /mp/contract/list`(未列出,字段同接口 2 `MpContractVO`)
|
||
- 管理后台合同/保险所有接口(不走 `/mp/` 前缀)
|
||
- JSON 字段名与取值逻辑(本次仅后端 VO 强类型化)
|
||
|
||
---
|
||
|
||
## 六、相关历史 PR
|
||
|
||
| PR | Issue | 说明 | 是否仍有效 |
|
||
|----|-------|------|------------|
|
||
| wx/HL#1314 | wx/HL#1312 | 合同接口返回值从 Map 改为强类型 VO(本 PR) | ✅ 最新 |
|
||
| 2026-04-17 `mp-order-detail-refactor` | - | 订单详情聚合 VO `MpOrderDashboardVO` | ✅ 有效 |
|
||
|
||
---
|
||
|
||
## 七、代码位置
|
||
|
||
- Controller
|
||
- `hl-mp-service` · `com.hulalv.mp.controller.MpOrderController#getOrderDashboard`
|
||
- `hl-mp-service` · `com.hulalv.mp.controller.MpContractController`
|
||
- `hl-mp-service` · `com.hulalv.mp.controller.MpInsuranceController`
|
||
- VO
|
||
- `hl-mp-service` · `com.hulalv.mp.vo.MpOrderDashboardVO`
|
||
- `hl-mp-service` · `com.hulalv.mp.vo.MpInsuranceDetailVO`
|
||
- `hl-mp-service` · `com.hulalv.mp.vo.MpContractVO` / `MpContractDetailVO` / `MpContractStatusLogVO`
|
||
- 下游
|
||
- `hl-order-service-v2` · `com.hulalv.contract.controller.internal.InternalMpContractController`
|
||
- `hl-order-service-v2` · `com.hulalv.insurance.controller.internal.InternalInsuranceController`
|
||
- `hl-order-service-v2` · `com.hulalv.insurance.vo.PolicyShareVO`
|
||
|
||
---
|
||
|
||
## 八、相关文档
|
||
|
||
- 关联 Issue: [wx/HL#1312](https://git.1814.love:8443/wx/HL/issues/1312)
|
||
- 关联 PR: [wx/HL#1314](https://git.1814.love:8443/wx/HL/pulls/1314)
|
||
- 订单详情聚合 VO 参考: `changelogs/2026-04/2026-04-17_order-v2_mp-order-detail-refactor.md`
|