diff --git a/changelogs-v2/2026-07/25_4756_车务菜单全接口验收与前端契约收口-管理后台.md b/changelogs-v2/2026-07/25_4756_车务菜单全接口验收与前端契约收口-管理后台.md index a4fac82..6d936ce 100644 --- a/changelogs-v2/2026-07/25_4756_车务菜单全接口验收与前端契约收口-管理后台.md +++ b/changelogs-v2/2026-07/25_4756_车务菜单全接口验收与前端契约收口-管理后台.md @@ -22,7 +22,7 @@ | 场景 | 前端处理 | |------|----------| | 当前角色 | 车务菜单只能由 `VEHICLE_MANAGER` 或 `SUPER_ADMIN` 访问;`wx/CUSTOMIZER` 访问 `/admin/fleet/**` 返回 `403`,提示切换车务角色。 | -| 司机结算方式 | 司机新增/编辑/导入使用字典 `driver_settlement_mode`:`direct`=直接结算,`fleet_leader`=车队长结算。 | +| 司机结算方式 | 司机新增/编辑/导入使用字典 `driver_settlement_mode`:`direct`=直接结算,`captain`=车队长结算。 | | 待审核详情 ID | `GET /admin/fleet/drivers/pending/{pendingId}` 响应主键字段是 `id`,不是 `pendingId`;路径变量仍叫 `pendingId`。 | | 派单重复确认 | `POST /admin/fleet/assignments/{assignmentId}/confirm` 只允许 `holding -> assigned`;非 `holding` 返回 `605020`。 | | 取消重复操作 | 终态派单再次取消也返回 `605020`。 | @@ -737,7 +737,7 @@ PUT /admin/fleet/drivers/{driverId} "preferredTypeKey": "suv", "preferredModel": "SUV", "vehicleSource": "company", - "settlementMode": "fleet_leader", + "settlementMode": "captain", "license": { "no": "L6966520260705", "type": "C1", @@ -762,7 +762,7 @@ PUT /admin/fleet/drivers/{driverId} "phone": "199****9999", "driverStatus": "idle", "season": "active", - "settlementMode": "fleet_leader", + "settlementMode": "captain", "license": { "no": "L6966520260705", "type": "C1", "expire": "2035-12-31" }, "insurance": { "type": "none" }, "tags": ["API_TEST_FLEET_FULL"] @@ -775,7 +775,7 @@ PUT /admin/fleet/drivers/{driverId} | 值 | 展示 | |----|------| | `direct` | 直接结算 | -| `fleet_leader` | 车队长结算 | +| `captain` | 车队长结算 | 非法值响应: diff --git a/changelogs-v2/2026-07/26_4760_车务司机险自动投退保闭环与保险菜单契约-管理后台.md b/changelogs-v2/2026-07/26_4760_车务司机险自动投退保闭环与保险菜单契约-管理后台.md new file mode 100644 index 0000000..a100400 --- /dev/null +++ b/changelogs-v2/2026-07/26_4760_车务司机险自动投退保闭环与保险菜单契约-管理后台.md @@ -0,0 +1,318 @@ +# 【前端对接·管理后台】车务司机险自动投退保闭环与保险菜单契约 + +> **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 派单则不退保。 +- 投保失败后重试成功。 +- 线下完成必须上传凭证。 +- 定制师角色不可见车务保险菜单。