【前端对接·管理后台】车务司机险自动投退保闭环与保险菜单契约
Issue: wx/HL#4760
服务: hl-fleet-service + hl-order-service-v3 insurance Feign
日期: 2026-07-06
影响范围: 车务管理 / 保险菜单 / 派单确认 / 取消 / 提前完结 / 车队对账
1. 结论
- 车务保险菜单只展示司机险任务,不展示游客保险、订单保险、客户退款保险明细。
insurance.type=perTrip 的司机在派单确认进入 assigned 后,后端按 driverId + serviceDate 自动一日一保投保。
insurance.type=annual 的司机不会自动按单买险,但派单确认时后端会逐服务日校验年保覆盖;年保到期或覆盖不足会生成车务保险待办。
- 同一司机同一服务日只能有一份司机险;前后订单相接同日不重复买。
- 取消/提前完结后,只退该司机该服务日已无其它 active 派单占用的单日险。
- 司机险只进入车队/司机成本,不进入客户退款、订单收款、游客保险或合同保险。
- 自动投退保失败不阻断派单主流程,但必须进入车务保险任务待处理。
2. 角色与菜单
| 角色 |
行为 |
VEHICLE_MANAGER / 车务角色 |
可访问 /admin/fleet/insurance/**,可查看任务、重试、标记线下完成、忽略。测试服独立账号:fleet_mgr_4760 |
CUSTOMIZER / 定制师 |
不应展示车务保险菜单;若访问 /admin/fleet/** 按角色守卫返回 403。测试服独立账号:designer_4760 |
前端不要复用订单保险页面的数据源。车务保险菜单只调本文件接口。
3. 接口一:司机险任务/流水分页
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 请求例子
GET /admin/fleet/insurance/tasks?pendingOnly=true&taskType=PURCHASE&serviceDateFrom=2026-07-01&serviceDateTo=2026-07-31&page=1&pageSize=20
Authorization: Bearer <admin-token>
3.3 响应例子
{
"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. 接口二:重试任务
POST /admin/fleet/insurance/tasks/{taskId}/retry
4.1 请求例子
POST /admin/fleet/insurance/tasks/194100000000000001/retry
Authorization: Bearer <admin-token>
无 body。
4.2 响应例子
{
"code": 200,
"message": "成功",
"success": true,
"data": {
"taskId": "194100000000000001",
"taskStatus": "SUCCESS",
"taskStatusLabel": "已成功"
}
}
4.3 前端处理
- 点击后按钮加 loading,接口有幂等保护,不要连续提交。
- 成功后刷新分页列表。
- 如果仍返回
PENDING,说明重试失败但已更新错误信息和 retryCount,前端展示最新 errorMessage/suggestedAction。
5. 接口三:标记线下完成
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 请求例子
{
"policyNo": "OFFLINE-20260701001",
"premiumAmount": "18.00",
"proofUrls": [
"https://oss.test.1814.love/fleet/insurance/OFFLINE-20260701001.jpg"
],
"remark": "保司后台线下补投,截图已上传"
}
5.3 响应例子
{
"code": 200,
"message": "成功",
"success": true,
"data": {
"taskId": "194100000000000001",
"taskStatus": "RESOLVED",
"taskStatusLabel": "已解决"
}
}
5.4 校验
policyNo 为空:参数校验失败。
premiumAmount 为空或负数:参数校验失败。
proofUrls 为空数组或不传:返回 code=400,message=线下凭证不能为空。
6. 接口四:忽略任务
POST /admin/fleet/insurance/tasks/{taskId}/ignore
6.1 请求例子
{
"remark": "重复人工记录,保单已由另一任务处理"
}
6.2 响应例子
{
"code": 200,
"message": "成功",
"success": true,
"data": {
"taskId": "194100000000000001",
"taskStatus": "IGNORED",
"taskStatusLabel": "已忽略"
}
}
7. 自动触发场景
| 场景 |
后端行为 |
前端关注 |
派单确认 holding -> assigned |
perTrip 司机按服务日逐日投保 |
确认派单成功不代表保险一定成功,需看保险任务 |
派单确认时司机配置年保且服务日全部被 annualStart~annualEnd 覆盖 |
不买按单险,不生成待办 |
保险成本按年保摊销进车队成本 |
| 派单确认时司机配置年保但部分服务日不被覆盖 |
对未覆盖服务日生成 PENDING 投保待办,错误码 540033 |
提示车务续保/修正年保起止,或改按行程险后重试 |
| 司机年保为手工/线下来源且与线上保单不一致 |
生成 PENDING 核对待办,错误码 540034 |
提示上传线下凭证或修正保单信息 |
| 已有线上保单覆盖同司机同日 |
不重复购买,写 SUCCESS 幂等流水 |
不要提示重复投保 |
| 已有手工/年保覆盖同司机同日 |
不买按单险,写 PENDING 提醒核对 |
展示 suggestedAction |
| 派单取消 |
只退该司机该服务日无其它 active 派单占用的单日险 |
同日仍有其它订单时不会退 |
| 提前完结 |
退新 endDate 之后不再使用的单日险 |
定时完结通常无动作 |
| 撤销取消恢复为 assigned |
如果之前已退险,恢复后补买 |
前端刷新任务列表 |
8. 前端不要做的事
- 不要用大交通日期推导司机险保障日期;司机险保障日期以派单服务日为准。
- 不要把司机险退保结果参与客户退款计算。
- 不要把
premiumAmount 转成 JS number 再计算。
- 不要在前端拼重试业务参数,重试只传
taskId。
- 不要在车务保险菜单展示订单游客险。
- 不要把
SUCCESS 自动流水当成待办提示;待办只看 PENDING/PROCESSING。
- 不要只看司机保险类型是
annual 就认为无需处理;必须以后端任务状态为准。年保到期、行程增加一天、换司机后都会重新按服务日校验。
9. 错误码提示
| code |
场景 |
前端文案建议 |
100001 |
参数非法、任务缺上下文、服务日区间反了 |
展示后端 message |
100502 |
幂等保护,重复提交 |
“正在处理,请勿重复提交” |
540007 |
保险计划缺费率 |
“请维护保险计划费率后重试” |
540032 |
同司机服务日已有保单覆盖 |
“已有保单覆盖,请核对后处理” |
540033 |
司机配置年保但服务日不在年保起止内 |
“司机年保未覆盖当前服务日,请续保/修正年保后重试,或改按行程险处理” |
540034 |
手工年保/线下保单与线上覆盖信息不一致 |
“请核对线下保单并上传凭证,确认后标记线下完成” |
605601 |
保险服务不可用 |
“保险服务暂不可用,请稍后重试或线下处理” |
10. 测试要求
前端联调不要只测接口 200。至少覆盖:
- 新建订单 -> 补出行人 -> 补大交通 -> 提用车需求 -> 车务派单确认 -> 保险任务生成。
- 同一司机同一服务日多订单,不重复买保险。
- 取消派单时,同司机同日还有其它 active 派单则不退保。
- 年保司机在服务期内不买按单险;服务日超过年保到期日时生成
540033 待办。
- 年保续保后重试
540033 任务,应变为 SUCCESS,且不能产生重复按单险。
- 投保失败后重试成功。
- 线下完成必须上传凭证。
- 定制师角色不可见车务保险菜单。