diff --git a/changelogs/2026-03/2026-03-22_insurance_module_guide.md b/changelogs/2026-03/2026-03-22_insurance_module_guide.md new file mode 100644 index 0000000..8641ef1 --- /dev/null +++ b/changelogs/2026-03/2026-03-22_insurance_module_guide.md @@ -0,0 +1,399 @@ +# 保险模块前端对接完整指南 + +**日期**: 2026-03-22 +**模块**: 保险管理(hl-insurance-service) +**类型**: 前端对接指南 + +--- + +## 一、核心概念(必须理解) + +保险模块有 **两层** 概念,搞混会导致字段传错: + +### 第一层:第三方保险目录(只读,不可编辑) + +来自保游网 API 同步,管理员只能查看,不能修改。 + +``` +InsuranceProduct(保险产品) ← 比如"保游未来星研学旅行保险" + └── InsurancePlan(保险计划) ← 比如"20万计划""30万计划""50万计划" + └── InsuranceRate(费率) ← 比如"1天=5元""4-7天=15元" +``` + +**前端使用场景**: +- "保险产品"页面展示产品列表 +- 编辑方案时,选择"保险产品"下拉 → 联动加载该产品的"保险计划"下拉 + +### 第二层:自定义方案模板(可编辑) + +管理员创建的投保模板,关联到订单上使用。 + +``` +InsuranceScheme(保险方案) ← 比如"6日行程保险方案" + └── InsuranceSchemeSegment(保险段) ← 比如"第1-3天低风险段""第4-6天高风险段" + ├── productId → 引用哪个保险产品 + └── planId → 引用哪个保险计划 +``` + +**关键区别**: +- **Product/Plan** = 保险公司提供的产品目录(同步来的,不能改) +- **Scheme/Segment** = 我们自己组装的方案模板(可以自由创建/编辑) +- 一个方案可以有多个段,每段可以用不同的产品和计划 + +--- + +## 二、方案编辑页面字段说明 + +### 方案基本信息 + +| 字段 | API字段名 | 类型 | 必填 | 说明 | +|------|----------|------|------|------| +| 方案名称 | `name` | String | ✅ | 最长100字符 | +| 产品类型 | `isOverseas` | Boolean | ✅ | `false`=境内,`true`=境外 | +| 方案描述 | `description` | String | ❌ | 最长500字符 | +| 排序 | `sortOrder` | Integer | ❌ | `>= 0` | + +### 保险段配置(segments 数组) + +| 字段 | API字段名 | 类型 | 必填 | 说明 | +|------|----------|------|------|------| +| 段名称 | `segmentName` | String | ❌ | 如"低风险段""高风险段" | +| **保险产品** | `productId` | **Long** | ✅ | 选择哪个保险产品(下拉选) | +| **保险计划** | `planId` | **Long** | ✅ | 选择该产品下的哪个计划(联动下拉) | +| 起始天 | `dayOffsetStart` | Integer | ✅ | **从1开始**,1=出发当天 | +| 结束天 | `dayOffsetEnd` | Integer | ✅ | **必须 >= 起始天**,如6日行程最后一段填6 | +| 排序 | `sortOrder` | Integer | ❌ | `>= 0`,段内排序 | + +### ⚠️ 重点:dayOffsetEnd 不要传 -1 + +之前代码中 `-1` 表示"到行程最后一天",但前端编辑时请直接填实际天数。例如: + +``` +6日行程保险方案: + 第1段:起始天=1,结束天=3(覆盖第1-3天) + 第2段:起始天=4,结束天=6(覆盖第4-6天)← 填6,不要填-1 +``` + +### ⚠️ 重点:productId 和 planId 的联动 + +1. 用户选择"保险产品"下拉时 → 调用 `GET /admin/insurance/products/{productId}/plans` 获取该产品的计划列表 +2. 用户再从计划列表中选择"保险计划" +3. 保存时传 `productId` + `planId`(都是 Long 类型的 ID,不是名称字符串) + +**常见错误**:把 productName 当 productId 传了,或者没有联动清空 planId + +--- + +## 三、接口清单 + +### 3.1 保险产品(只读) + +#### 产品列表 +``` +GET /admin/insurance/products?page=1&pageSize=20&isOverseas=false +``` +响应: +```json +{ + "code": 200, + "data": { + "list": [ + { + "productId": 2026279733947334657, + "productName": "保游未来星研学旅行保险", + "companyName": "中国人寿", + "isOverseas": false, + "minDays": 1, + "maxDays": 365, + "status": "ON_SALE" + } + ], + "total": 10, "page": 1, "pageSize": 20 + } +} +``` + +#### 产品计划及费率(联动下拉用) +``` +GET /admin/insurance/products/{productId}/plans +``` +响应: +```json +{ + "code": 200, + "data": [ + { + "planId": 2026295680158437378, + "planName": "20万计划", + "securityList": "...
", + "rates": [ + { "rateId": 1, "dayRange": "1", "premium": 5.00 }, + { "rateId": 2, "dayRange": "2-3", "premium": 8.00 }, + { "rateId": 3, "dayRange": "4-7", "premium": 15.00 } + ] + }, + { + "planId": 2026295681706135562, + "planName": "30万计划", + "rates": [...] + } + ] +} +``` + +#### 同步产品数据(手动触发) +``` +POST /admin/insurance/sync-products +``` + +### 3.2 保险方案 CRUD + +#### 方案列表(管理页面用) +``` +GET /admin/insurance/scheme/list-all +``` +响应: +```json +{ + "code": 200, + "data": [ + { + "schemeId": 100001, + "name": "6日行程保险方案", + "description": "6天行程全覆盖:第1-3天低风险+第4-6天高风险", + "isOverseas": false, + "sortOrder": 15, + "totalDays": 6, + "status": "ACTIVE", + "segmentCount": 2, + "segments": [ + { + "segmentId": 200011, + "segmentName": "低风险段", + "dayOffsetStart": 1, + "dayOffsetEnd": 3, + "productId": 2026279733947334657, + "productName": "保游未来星研学旅行保险", + "planId": 2026295680158437378, + "planName": "20万计划", + "sortOrder": 0 + }, + { + "segmentId": 200012, + "segmentName": "高风险段", + "dayOffsetStart": 4, + "dayOffsetEnd": 6, + "productId": 2026279733947334657, + "productName": "保游未来星研学旅行保险", + "planId": 2026295681706135562, + "planName": "30万计划", + "sortOrder": 1 + } + ] + } + ] +} +``` + +#### 活跃方案列表(下拉选择用,如订单页选方案) +``` +GET /admin/insurance/scheme/list +``` +仅返回 `status=ACTIVE` 的方案。 + +#### 方案详情 +``` +GET /admin/insurance/scheme/{schemeId} +``` + +#### 创建方案 +``` +POST /admin/insurance/scheme +Content-Type: application/json + +{ + "name": "6日行程保险方案", + "description": "6天行程全覆盖:第1-3天低风险+第4-6天高风险", + "isOverseas": false, + "sortOrder": 15, + "segments": [ + { + "segmentName": "低风险段", + "dayOffsetStart": 1, + "dayOffsetEnd": 3, + "productId": 2026279733947334657, + "planId": 2026295680158437378, + "sortOrder": 0 + }, + { + "segmentName": "高风险段", + "dayOffsetStart": 4, + "dayOffsetEnd": 6, + "productId": 2026279733947334657, + "planId": 2026295681706135562, + "sortOrder": 1 + } + ] +} +``` + +#### 更新方案(全量替换 segments) +``` +PUT /admin/insurance/scheme/{schemeId} +``` +请求体同创建。**注意:segments 是全量替换,不是增量。前端保存时要把所有段都传回去。** + +#### 切换启用/停用 +``` +PUT /admin/insurance/scheme/{schemeId}/toggle-status +``` + +#### 删除方案 +``` +DELETE /admin/insurance/scheme/{schemeId} +``` + +### 3.3 保险订单 + +#### 订单列表 +``` +GET /admin/insurance/orders?page=1&pageSize=20&orderId=xxx&status=INSURED +``` +status 可选值:`PENDING`(待出单) / `INSURED`(已承保) / `CANCELLED`(已退保) / `FAILED`(投保失败) + +#### 订单详情(含被保人列表) +``` +GET /admin/insurance/orders/{insuranceOrderId} +``` + +#### 按旅行订单查询保险单 +``` +GET /admin/insurance/orders/by-order/{orderId} +``` + +#### 查询订单保险保障全貌 +``` +GET /admin/insurance/coverage/{orderId} +``` + +### 3.4 投保操作 + +#### 保费试算 +``` +POST /admin/insurance/trial-price +{ + "planId": 2026295680158437378, + "startDate": "2026-04-01", + "endDate": "2026-04-06", + "insuredCount": 5 +} +``` +响应: +```json +{ + "code": 200, + "data": { + "totalPremium": 75.00, + "unitPremium": 15.00, + "tripDays": 6, + "insuredCount": 5 + } +} +``` + +#### 按方案自动投保(推荐) +``` +POST /admin/insurance/purchase-by-scheme +{ + "orderId": 123456, + "schemeId": 100001 +} +``` + +#### 预览方案应用效果(投保前先看) +``` +POST /admin/insurance/scheme/preview-apply +{ + "schemeId": 100001, + "orderId": 123456 +} +``` +响应包含每段的实际日期、预估保费、是否跳过及原因。 + +#### 手动投保(指定计划) +``` +POST /admin/insurance/purchase +{ + "orderId": 123456, + "planId": 2026295680158437378, + "entityCode": "hh_nmg" +} +``` +传了 orderId 会自动从订单获取出行人和日期,不需要再传 insuredPersons。 + +#### 退保 +``` +POST /admin/insurance/cancel/{insuranceOrderId} +``` + +### 3.5 其他 + +#### 账户余额 +``` +GET /admin/insurance/balance +``` + +#### 在线充值 +``` +POST /admin/insurance/recharge +{ "money": 1000, "payType": 33 } +``` +payType: 11=支付宝扫码, 33=微信扫码 + +#### 下载保单PDF +``` +GET /admin/insurance/policy/{insuranceOrderId}/download +``` +返回 Base64 编码的 PDF 字符串。 + +--- + +## 四、页面交互建议 + +### 方案编辑页 + +``` +┌─────────────────────────────────────────────┐ +│ 方案名称 * [____________] │ +│ 产品类型 * ○ 境内 ○ 境外 │ +│ 方案描述 [________________________] │ +│ 排序 [0] ─ + │ +│ │ +│ 保险段配置 [+ 添加保险段] │ +│ ┌──────────────────────────────────────┐ │ +│ │ 第1段 ↑ ↓ 移除 │ │ +│ │ 段名称 [低风险段] │ │ +│ │ 保险产品* [保游未来星研学旅行保险 ▼] │ ← 下拉,数据来自 GET /products │ +│ │ 保险计划* [20万计划 ▼] │ ← 联动下拉,数据来自 GET /products/{id}/plans │ +│ │ 起始天* [1] ─ + 结束天* [3] ─ + │ │ +│ │ 排序 [0] ─ + │ │ +│ └──────────────────────────────────────┘ │ +│ ┌──────────────────────────────────────┐ │ +│ │ 第2段 ↑ ↓ 移除 │ │ +│ │ 段名称 [高风险段] │ │ +│ │ 保险产品* [保游未来星研学旅行保险 ▼] │ │ +│ │ 保险计划* [30万计划 ▼] │ │ +│ │ 起始天* [4] ─ + 结束天* [6] ─ + │ │ +│ │ 排序 [1] ─ + │ │ +│ └──────────────────────────────────────┘ │ +│ [取消] [保存] │ +└─────────────────────────────────────────────┘ +``` + +### 交互要点 + +1. **保险产品下拉**:页面加载时调 `GET /admin/insurance/products?pageSize=100` 一次性加载 +2. **保险计划联动**:选择产品后调 `GET /admin/insurance/products/{productId}/plans`,清空已选的计划 +3. **编辑回显**:从 `GET /admin/insurance/scheme/{id}` 拿到 segments,每段的 `productId` 和 `planId` 用于回显下拉选中状态,`productName` 和 `planName` 用于显示文字 +4. **起始天/结束天**:``,结束天 `:min` 动态绑定为该段起始天 +5. **保存提交**:segments 全量提交,每段必须包含 `productId`(Long) 和 `planId`(Long)