# 【前端对接·管理后台】车务司机险自动投退保闭环与保险菜单契约 > **Issue**: [wx/HL#4760](https://git.1814.love:8443/wx/HL/issues/4760) > **服务**: hl-fleet-service + hl-order-service-v3 insurance Feign > **日期**: 2026-07-06 > **影响范围**: 车务管理 / 保险菜单 / 派单确认 / 取消 / 提前完结 / 车队对账 --- ## 1. 结论 - 车务保险菜单只展示司机险任务,不展示游客保险、订单保险、客户退款保险明细。 - `insurance.type=perTrip` 的司机在派单确认进入 `assigned` 后,后端按 `driverId + serviceDate` 自动一日一保投保。 - 同一司机同一服务日只能有一份司机险;前后订单相接同日不重复买。 - 取消/提前完结后,只退该司机该服务日已无其它 active 派单占用的单日险。 - 司机险只进入车队/司机成本,不进入客户退款、订单收款、游客保险或合同保险。 - 自动投退保失败不阻断派单主流程,但必须进入车务保险任务待处理。 --- ## 2. 角色与菜单 | 角色 | 行为 | |------|------| | `admin` / 车务角色 | 可访问 `/admin/fleet/insurance/**`,可查看任务、重试、标记线下完成、忽略 | | `wx` / 定制师 | 不应展示车务保险菜单;若访问 `/admin/fleet/**` 按角色守卫返回 `403` | 前端不要复用订单保险页面的数据源。车务保险菜单只调本文件接口。 --- ## 3. 接口一:司机险任务/流水分页 ```http GET /admin/fleet/insurance/tasks ``` ### 3.1 Query 参数 | 参数 | 类型 | 必填 | 示例 | 说明 | |------|------|------|------|------| | `page` | number | 否 | `1` | 页码 | | `pageSize` | number | 否 | `20` | 每页条数 | | `pendingOnly` | boolean | 否 | `true` | `true` 只查 `PENDING/PROCESSING`;不传查全部 | | `taskType` | string | 否 | `PURCHASE` | `PURCHASE` 投保 / `REFUND` 退保 | | `taskStatus` | string | 否 | `PENDING` | `PENDING/PROCESSING/SUCCESS/RESOLVED/IGNORED` | | `driverId` | string | 否 | `188800000000000001` | 司机 ID | | `assignmentId` | string | 否 | `194000000000000001` | 派单 ID | | `orderId` | string | 否 | `193900000000000001` | 订单 ID | | `serviceDateFrom` | string | 否 | `2026-07-01` | 服务日起,`yyyy-MM-dd` | | `serviceDateTo` | string | 否 | `2026-07-31` | 服务日止,不能早于起始日 | ### 3.2 请求例子 ```http GET /admin/fleet/insurance/tasks?pendingOnly=true&taskType=PURCHASE&serviceDateFrom=2026-07-01&serviceDateTo=2026-07-31&page=1&pageSize=20 Authorization: Bearer ``` ### 3.3 响应例子 ```json { "code": 200, "message": "成功", "success": true, "data": { "page": 1, "pageSize": 20, "total": 2, "records": [ { "taskId": "194100000000000001", "bizKey": "PURCHASE:188800000000000001:2026-07-06", "taskType": "PURCHASE", "taskTypeLabel": "投保", "taskStatus": "PENDING", "taskStatusLabel": "待处理", "driverId": "188800000000000001", "driverName": "王师傅", "assignmentId": "194000000000000001", "orderId": "193900000000000001", "orderNo": "HL20260705001", "insuranceOrderId": null, "policyNo": "", "serviceDate": "2026-07-06", "coverageStartDate": "2026-07-06", "coverageEndDate": "2026-07-06", "premiumAmount": "0.00", "source": "BAOYOU", "sourceLabel": "保游网", "errorCode": "540007", "errorMessage": "保险计划没有匹配该保障天数的费率", "suggestedAction": "保险计划没有匹配该保障天数的费率,请维护费率后重试", "retryCount": 1, "proofUrls": [], "handledBy": null, "handledAt": null, "handleRemark": "", "createTime": "2026-07-06T09:10:00", "updateTime": "2026-07-06T09:12:00" }, { "taskId": "194100000000000002", "bizKey": "PURCHASE:188800000000000001:2026-07-07", "taskType": "PURCHASE", "taskTypeLabel": "投保", "taskStatus": "SUCCESS", "taskStatusLabel": "已成功", "driverId": "188800000000000001", "driverName": "王师傅", "assignmentId": "194000000000000002", "orderId": "193900000000000002", "orderNo": "HL20260705002", "insuranceOrderId": "194200000000000001", "policyNo": "BY-20260707001", "serviceDate": "2026-07-07", "coverageStartDate": "2026-07-07", "coverageEndDate": "2026-07-07", "premiumAmount": "18.00", "source": "BAOYOU", "sourceLabel": "保游网", "errorCode": "", "errorMessage": "", "suggestedAction": "", "retryCount": 0, "proofUrls": [], "handledBy": "0", "handledAt": "2026-07-06T09:10:05", "handleRemark": "", "createTime": "2026-07-06T09:10:05", "updateTime": "2026-07-06T09:10:05" } ] } } ``` ### 3.4 字段说明 | 字段 | 说明 | |------|------| | `bizKey` | 后端幂等键,前端只展示/排查,不要拼业务逻辑 | | `taskType` | `PURCHASE` 投保,`REFUND` 退保 | | `taskStatus` | `PENDING` 待处理,`PROCESSING` 处理中,`SUCCESS` 线上成功,`RESOLVED` 线下解决,`IGNORED` 已忽略 | | `premiumAmount` | 真实保费/退回金额,字符串;前端不要转 number 做精度运算 | | `source` | `BAOYOU` 保游网,`OFFLINE` 线下处理 | | `proofUrls` | 线下处理凭证 URL;线上成功通常为空数组 | | `handledBy=0` | 后端自动成功流水,不是人工账号 | --- ## 4. 接口二:重试任务 ```http POST /admin/fleet/insurance/tasks/{taskId}/retry ``` ### 4.1 请求例子 ```http POST /admin/fleet/insurance/tasks/194100000000000001/retry Authorization: Bearer ``` 无 body。 ### 4.2 响应例子 ```json { "code": 200, "message": "成功", "success": true, "data": { "taskId": "194100000000000001", "taskStatus": "SUCCESS", "taskStatusLabel": "已成功" } } ``` ### 4.3 前端处理 - 点击后按钮加 loading,接口有幂等保护,不要连续提交。 - 成功后刷新分页列表。 - 如果仍返回 `PENDING`,说明重试失败但已更新错误信息和 `retryCount`,前端展示最新 `errorMessage/suggestedAction`。 --- ## 5. 接口三:标记线下完成 ```http POST /admin/fleet/insurance/tasks/{taskId}/offline-done ``` ### 5.1 请求参数 | 字段 | 类型 | 必填 | 示例 | 说明 | |------|------|------|------|------| | `policyNo` | string | 是 | `OFFLINE-20260701001` | 真实保单号 / 退保凭证号 | | `premiumAmount` | decimal string | 是 | `"18.00"` | 真实保费金额;退保填实际退回/冲减金额 | | `proofUrls` | string[] | 是 | `["https://...jpg"]` | 至少 1 个凭证 URL | | `remark` | string | 否 | `保司后台线下补投` | 处理备注 | ### 5.2 请求例子 ```json { "policyNo": "OFFLINE-20260701001", "premiumAmount": "18.00", "proofUrls": [ "https://oss.test.1814.love/fleet/insurance/OFFLINE-20260701001.jpg" ], "remark": "保司后台线下补投,截图已上传" } ``` ### 5.3 响应例子 ```json { "code": 200, "message": "成功", "success": true, "data": { "taskId": "194100000000000001", "taskStatus": "RESOLVED", "taskStatusLabel": "已解决" } } ``` ### 5.4 校验 - `policyNo` 为空:参数校验失败。 - `premiumAmount` 为空或负数:参数校验失败。 - `proofUrls` 为空数组或不传:返回 `100001` / 参数校验失败。 --- ## 6. 接口四:忽略任务 ```http POST /admin/fleet/insurance/tasks/{taskId}/ignore ``` ### 6.1 请求例子 ```json { "remark": "重复人工记录,保单已由另一任务处理" } ``` ### 6.2 响应例子 ```json { "code": 200, "message": "成功", "success": true, "data": { "taskId": "194100000000000001", "taskStatus": "IGNORED", "taskStatusLabel": "已忽略" } } ``` --- ## 7. 自动触发场景 | 场景 | 后端行为 | 前端关注 | |------|----------|----------| | 派单确认 `holding -> assigned` | perTrip 司机按服务日逐日投保 | 确认派单成功不代表保险一定成功,需看保险任务 | | 已有线上保单覆盖同司机同日 | 不重复购买,写 `SUCCESS` 幂等流水 | 不要提示重复投保 | | 已有手工/年保覆盖同司机同日 | 不买按单险,写 `PENDING` 提醒核对 | 展示 `suggestedAction` | | 派单取消 | 只退该司机该服务日无其它 active 派单占用的单日险 | 同日仍有其它订单时不会退 | | 提前完结 | 退新 `endDate` 之后不再使用的单日险 | 定时完结通常无动作 | | 撤销取消恢复为 assigned | 如果之前已退险,恢复后补买 | 前端刷新任务列表 | --- ## 8. 前端不要做的事 - 不要用大交通日期推导司机险保障日期;司机险保障日期以派单服务日为准。 - 不要把司机险退保结果参与客户退款计算。 - 不要把 `premiumAmount` 转成 JS number 再计算。 - 不要在前端拼重试业务参数,重试只传 `taskId`。 - 不要在车务保险菜单展示订单游客险。 - 不要把 `SUCCESS` 自动流水当成待办提示;待办只看 `PENDING/PROCESSING`。 --- ## 9. 错误码提示 | code | 场景 | 前端文案建议 | |------|------|--------------| | `100001` | 参数非法、任务缺上下文、服务日区间反了 | 展示后端 message | | `100502` | 幂等保护,重复提交 | “正在处理,请勿重复提交” | | `540007` | 保险计划缺费率 | “请维护保险计划费率后重试” | | `540032` | 同司机服务日已有保单覆盖 | “已有保单覆盖,请核对后处理” | | `605601` | 保险服务不可用 | “保险服务暂不可用,请稍后重试或线下处理” | --- ## 10. 测试要求 前端联调不要只测接口 200。至少覆盖: - 新建订单 -> 补出行人 -> 补大交通 -> 提用车需求 -> 车务派单确认 -> 保险任务生成。 - 同一司机同一服务日多订单,不重复买保险。 - 取消派单时,同司机同日还有其它 active 派单则不退保。 - 投保失败后重试成功。 - 线下完成必须上传凭证。 - 定制师角色不可见车务保险菜单。