diff --git a/changelogs-v2/2026-07/25_4756_车务菜单全接口验收与前端契约收口-管理后台.md b/changelogs-v2/2026-07/25_4756_车务菜单全接口验收与前端契约收口-管理后台.md index 6d936ce..cf03a5c 100644 --- a/changelogs-v2/2026-07/25_4756_车务菜单全接口验收与前端契约收口-管理后台.md +++ b/changelogs-v2/2026-07/25_4756_车务菜单全接口验收与前端契约收口-管理后台.md @@ -22,6 +22,7 @@ | 场景 | 前端处理 | |------|----------| | 当前角色 | 车务菜单只能由 `VEHICLE_MANAGER` 或 `SUPER_ADMIN` 访问;`wx/CUSTOMIZER` 访问 `/admin/fleet/**` 返回 `403`,提示切换车务角色。 | +| 车务工作台 | `GET /admin/profile/dashboard?period=today` 在 `VEHICLE_MANAGER` 角色下由 user-service 代理 fleet 真实看板数据;不要再读旧订单统计或本地 mock。 | | 司机结算方式 | 司机新增/编辑/导入使用字典 `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`。 | @@ -41,6 +42,7 @@ | 菜单 | 关键接口 | |------|----------| +| 车务工作台 | `/admin/profile/dashboard?period=today` | | 派单看板 | `/admin/fleet/board/summary`, `/orders`, `/orders/{orderId}`, `/timeline`, `/expiry`, `/assignments/**` | | 矩阵派单 | `/admin/fleet/matrix/grid`, `/unassigned-orders`, `/day-orders` | | 车队对账 | `/admin/fleet/reconciliation/cars`, `/insurance`, `/periods`, `/actual`, `/close`, `/reopen`, `/pending-compensations/**`, `/export/cars` | @@ -94,6 +96,80 @@ Content-Type: application/json > 说明:下面示例来自本次测试服真实 API 回归结构,手机号、token、部分 ID 做了脱敏或占位。前端处理长整型 ID 时建议按字符串保存,避免 JS 精度问题。 +### 4.4 分页与全量接口约定 + +- 公共分页对象 `page/pageSize` 的上限仍为 `100`,车务模块不绕过公共上限。 +- 页面列表、弹窗选择、远程搜索列表继续调用分页接口,前端分页选项不要超过 `100`。 +- 下拉、筛选、树形选择等“需要全量选项”的场景不要用 `pageSize=200/1000` 拉分页接口,应改用对应的非分页轻量端点。 +- 当前可用非分页端点: + +```http +GET /admin/fleet/vehicle-types +GET /admin/fleet/vehicle-types/list +GET /admin/fleet/drivers/options?keyword=王&limit=20 +GET /admin/fleet/message-templates +GET /admin/fleet/reconciliation/periods?fromMonth=2026-01 +``` + +| 场景 | 正确接口 | 不要这么调 | +|------|----------|------------| +| 车辆列表页/车辆档案分页 | `GET /admin/fleet/vehicles/page?page=1&pageSize=24` | 不要 `pageSize>100` | +| 派单弹窗选择车辆 | `GET /admin/fleet/vehicles/page?page=1&pageSize=10&vehicleStatus=idle` | 不要用一个下拉一次拉全部车辆 | +| 车型大类筛选下拉 | `GET /admin/fleet/vehicle-types/list` | 不要 `/vehicle-types/page?pageSize=1000` | +| 大类+型号树选择 | `GET /admin/fleet/vehicle-types` | 不要按每个大类再批量扫 `/models/page` | +| 司机远程搜索下拉 | `GET /admin/fleet/drivers/options?keyword=王&limit=20` | 不要 `/drivers/page?pageSize=1000` | +| 车管模板列表 | `GET /admin/fleet/message-templates` | 该接口本身不分页,不要拼 page/pageSize | +| 车队对账主数据 | `GET /admin/fleet/reconciliation/cars` / `insurance` | 主数据不分页,不要自己从车辆/司机分页接口拼 mock | + +如果后续前端出现新的“确实需要全量车辆选项”的页面,不要扩大 `/vehicles/page` 上限;先提需求补一个窄字段的车辆 options 接口,限定字段和筛选条件。 + +### 4.5 车务工作台 + +车务首页入口仍走用户服务的角色分发接口;当前登录角色必须是 `VEHICLE_MANAGER`: + +```http +GET /admin/profile/dashboard?period=today +``` + +响应: + +```json +{ + "code": 200, + "message": "成功", + "success": true, + "data": { + "pendingArrangeVehicle": 3, + "upcomingTrips": [ + { + "orderId": "70123456789", + "assignmentId": "80123456789", + "orderNo": "HL202607010001", + "productName": "呼伦贝尔 6 日", + "customerName": "张先生", + "departureDate": "2026-07-10", + "endDate": "2026-07-15", + "headcount": 4, + "status": "unassigned_urgent", + "statusLabel": "待派", + "urgentBadge": "T-1" + } + ] + } +} +``` + +字段口径: + +| 字段 | 说明 | +|------|------| +| `pendingArrangeVehicle` | 来源 fleet 派单看板 `pendingCount`,即当前待派单数,含紧急待派。 | +| `upcomingTrips` | 来源 fleet 派单看板列表,近 7 天游程,最多 5 条。 | +| `status` | 车务派单态:`unassigned`、`unassigned_urgent`、`holding`、`holding_urgent`、`assigned`。 | +| `orderId` / `assignmentId` | 长整型按字符串处理,前端不要转 JS Number。 | + +这不是分页不足问题;工作台不应从 `/admin/fleet/vehicles/page` 或旧 `DashboardStats` 拼数据,也不应使用本地 `useFleetStore` mock。 + --- ## 5. 订单前置:新建订单、出行人、大交通、用车需求 @@ -1405,6 +1481,8 @@ POST /admin/fleet/drivers/pending/{pendingId}/reject ## 13. 车队对账 +前端当前若仍用本地 `useFleetStore` / mock 计算车队对账,需要切到本节接口;后端主数据不是分页接口,返回结构也不是旧的 `records/total`。 + ### 13.1 查询车费、保险、对账期 ```http @@ -1419,24 +1497,152 @@ GET /admin/fleet/reconciliation/export/cars?periodStart=2026-07-01&periodEnd=202 ```json { "code": 200, + "message": "成功", "success": true, "data": { - "records": [ + "periodLabel": "2026-07", + "periodStart": "2026-07-01", + "periodEnd": "2026-07-31", + "fleets": [ { "fleet": "own", "fleetName": "自有车队", - "assignmentCount": 1, - "estimated": "888.00", - "payableEstimated": "888.00", - "actualAmount": "123.45", - "diff": "-764.55" + "orderCount": 3, + "estimatedTotal": "27000.00", + "payableTotal": "27000.00", + "actualTotal": "26000.00", + "settleMode": "OWN_COST", + "diff": "-1000.00", + "closed": false, + "vehicles": [ + { + "vehicleId": "2064991856994758657", + "plate": "蒙A-88888", + "modelName": "丰田汉兰达", + "seats": 7, + "orderCount": 3, + "days": 18, + "avgPerDay": "1500.00", + "amount": "27000.00", + "payableAmount": "27000.00" + } + ] } ], - "total": 1 + "grandTotal": { + "estimated": "27000.00", + "payable": "27000.00", + "actual": "26000.00", + "diff": "-1000.00", + "totalDays": 18, + "totalOrderCount": 3 + } } } ``` +字段口径: + +| 字段 | 说明 | +|------|------| +| `fleets[].orderCount` | 车队内订单数,后端已按 `orderNo` 去重 | +| `fleets[].estimatedTotal` | 对客报价合计,利润分析用 | +| `fleets[].payableTotal` | 对车队应付合计,车队成本基准 | +| `fleets[].actualTotal` | 车务/财务手工录入实付,未录为 `null` | +| `fleets[].diff` | `actualTotal - payableTotal`,未录实付为 `null` | +| `fleets[].closed` | 整月关账状态;非自然月查询恒为 `false` | +| `vehicles[].days` | 车天,来自 active prep 行数 | +| `vehicles[].avgPerDay` | `payableAmount / days` | +| `grandTotal.totalOrderCount` | 全车队订单数,后端跨车队全局去重,前端不要用明细求和 | + +保险响应: + +```json +{ + "code": 200, + "message": "成功", + "success": true, + "data": { + "periodLabel": "2026-07", + "grandTotal": "250.00", + "fleets": [ + { + "fleet": "own", + "sourceSubtotals": { + "manual": "120.00", + "baoyou": "130.00" + }, + "typeCounts": { + "annual": 1, + "perTrip": 1, + "none": 0 + }, + "drivers": [ + { + "driverId": "188800000000000001", + "name": "王师傅", + "phone": "138****1234", + "insuranceType": "annual", + "insuranceSource": "MANUAL", + "billingMethod": "年保险按日摊销", + "annualPremium": "3650.00", + "perDayRate": null, + "totalPremium": null, + "orderCount": 2, + "days": 12, + "insuranceAmount": "120.00" + }, + { + "driverId": "188800000000000002", + "name": "李师傅", + "phone": "139****5678", + "insuranceType": "", + "insuranceSource": "BAOYOU", + "billingMethod": "保游网实际出单", + "annualPremium": null, + "perDayRate": null, + "totalPremium": "130.00", + "orderCount": 1, + "days": 3, + "insuranceAmount": "130.00" + } + ] + } + ] + } +} +``` + +保险字段口径: + +| 字段 | 说明 | +|------|------| +| `insuranceSource` | 分组主键,取 `MANUAL/BAOYOU/NONE`;不要用 `insuranceType` 分组 | +| `insuranceType` | 司机配置类型,`annual/perTrip/none`;保游实际出单行可能为空字符串 | +| `sourceSubtotals.manual` | 手填年保费/行程险摊销小计 | +| `sourceSubtotals.baoyou` | 保游实际出单摊销小计 | +| `typeCounts` | 车队内司机保险类型计数 | +| `grandTotal` | 全车队保险成本合计,不含 `NONE` | + +对账期响应: + +```json +{ + "code": 200, + "message": "成功", + "success": true, + "data": [ + { + "label": "2026-07", + "periodStart": "2026-07-01", + "periodEnd": "2026-07-31", + "closed": false, + "reopened": false + } + ] +} +``` + ### 13.2 录入实付、关账、重开、补偿 ```http @@ -1454,7 +1660,7 @@ POST /admin/fleet/reconciliation/pending-compensations/{id}/resolve "periodStart": "2026-07-01", "periodEnd": "2026-07-31", "fleet": "own", - "actualAmount": 123.45, + "actualAmount": "26000.00", "note": "菜单验收录入" } ``` @@ -1464,13 +1670,70 @@ POST /admin/fleet/reconciliation/pending-compensations/{id}/resolve ```json { "code": 200, + "message": "成功", "success": true, "data": { - "id": "2026-07-own", - "estimated": "888.00", - "payableEstimated": "888.00", - "actualAmount": "123.45", - "diff": "-764.55" + "id": "2073749573041356801", + "diff": "-1000.00", + "payableEstimated": "27000.00", + "estimated": "27000.00" + } +} +``` + +清空实付:`actualAmount` 传 `null` 或省略,后端软删该 `(periodStart, fleet)` 实付行,响应中 `diff` 返 `null`。 + +补偿列表响应: + +```json +{ + "code": 200, + "message": "成功", + "success": true, + "data": { + "page": 1, + "pageSize": 5, + "total": 1, + "records": [ + { + "compId": "2073749573041356802", + "assignmentId": "2073749573041356803", + "orderId": "2073749536638992386", + "periodLabel": "2026-07", + "opType": "TRUNCATE", + "serviceDateFrom": "2026-07-20", + "reason": "提前完结截断触及已关账期 2026-07", + "status": "PENDING", + "createTime": "2026-07-06T10:00:00", + "resolvedAt": null, + "resolvedBy": null, + "resolveRemark": null + } + ] + } +} +``` + +处置补偿请求: + +```json +{ + "remark": "已线下补对账,差额计入 2026-08 调整" +} +``` + +处置补偿响应: + +```json +{ + "code": 200, + "message": "成功", + "success": true, + "data": { + "compId": "2073749573041356802", + "status": "RESOLVED", + "resolvedAt": "2026-07-06T10:30:00", + "resolvedBy": "1001" } } ``` @@ -1509,6 +1772,8 @@ POST /admin/fleet/reconciliation/pending-compensations/{id}/resolve ## 14. 车管模板 +模板列表是非分页接口;前端页面不要传 `page/pageSize`。测试服如果返回空数组,表示当前库没有配置模板,不是分页问题。 + ```http GET /admin/fleet/message-templates GET /admin/fleet/message-templates?templateType=hold_notify @@ -1552,9 +1817,9 @@ DELETE /admin/fleet/message-templates/{templateId} ```json { - "orderNo": "HL20260705204312543", - "driverName": "API师傅", - "vehiclePlate": "蒙A-69665" + "orderId": "2073749536638992386", + "driverId": "2073749573041356803", + "vehicleId": "2073749573041356804" } ``` @@ -1565,12 +1830,14 @@ DELETE /admin/fleet/message-templates/{templateId} "code": 200, "success": true, "data": { - "renderedBody": "您好 API师傅,订单 HL20260705204312543 已派车,车牌 蒙A-69665", + "renderedBody": "您好 API师傅,订单 已派车,车牌 蒙A-69665", "variablesUsed": ["driver.name", "order.no", "vehicle.plate"] } } ``` +说明:当前 `driver.*`、`vehicle.*` 可按 ID 渲染;`order.*` / `itinerary.*` 本期仍走占位端口,缺值会替换为空串,不报错。前端不要传 `orderNo/driverName/vehiclePlate`,这些不是该接口入参字段。 + 变量缺失: ```json diff --git a/changelogs-v2/2026-07/26_4760_车务司机险自动投退保闭环与保险菜单契约-管理后台.md b/changelogs-v2/2026-07/26_4760_车务司机险自动投退保闭环与保险菜单契约-管理后台.md index a100400..4375193 100644 --- a/changelogs-v2/2026-07/26_4760_车务司机险自动投退保闭环与保险菜单契约-管理后台.md +++ b/changelogs-v2/2026-07/26_4760_车务司机险自动投退保闭环与保险菜单契约-管理后台.md @@ -11,6 +11,7 @@ - 车务保险菜单只展示司机险任务,不展示游客保险、订单保险、客户退款保险明细。 - `insurance.type=perTrip` 的司机在派单确认进入 `assigned` 后,后端按 `driverId + serviceDate` 自动一日一保投保。 +- `insurance.type=annual` 的司机不会自动按单买险,但派单确认时后端会逐服务日校验年保覆盖;年保到期或覆盖不足会生成车务保险待办。 - 同一司机同一服务日只能有一份司机险;前后订单相接同日不重复买。 - 取消/提前完结后,只退该司机该服务日已无其它 active 派单占用的单日险。 - 司机险只进入车队/司机成本,不进入客户退款、订单收款、游客保险或合同保险。 @@ -275,6 +276,9 @@ POST /admin/fleet/insurance/tasks/{taskId}/ignore | 场景 | 后端行为 | 前端关注 | |------|----------|----------| | 派单确认 `holding -> assigned` | perTrip 司机按服务日逐日投保 | 确认派单成功不代表保险一定成功,需看保险任务 | +| 派单确认时司机配置年保且服务日全部被 `annualStart~annualEnd` 覆盖 | 不买按单险,不生成待办 | 保险成本按年保摊销进车队成本 | +| 派单确认时司机配置年保但部分服务日不被覆盖 | 对未覆盖服务日生成 `PENDING` 投保待办,错误码 `540033` | 提示车务续保/修正年保起止,或改按行程险后重试 | +| 司机年保为手工/线下来源且与线上保单不一致 | 生成 `PENDING` 核对待办,错误码 `540034` | 提示上传线下凭证或修正保单信息 | | 已有线上保单覆盖同司机同日 | 不重复购买,写 `SUCCESS` 幂等流水 | 不要提示重复投保 | | 已有手工/年保覆盖同司机同日 | 不买按单险,写 `PENDING` 提醒核对 | 展示 `suggestedAction` | | 派单取消 | 只退该司机该服务日无其它 active 派单占用的单日险 | 同日仍有其它订单时不会退 | @@ -291,6 +295,7 @@ POST /admin/fleet/insurance/tasks/{taskId}/ignore - 不要在前端拼重试业务参数,重试只传 `taskId`。 - 不要在车务保险菜单展示订单游客险。 - 不要把 `SUCCESS` 自动流水当成待办提示;待办只看 `PENDING/PROCESSING`。 +- 不要只看司机保险类型是 `annual` 就认为无需处理;必须以后端任务状态为准。年保到期、行程增加一天、换司机后都会重新按服务日校验。 --- @@ -302,6 +307,8 @@ POST /admin/fleet/insurance/tasks/{taskId}/ignore | `100502` | 幂等保护,重复提交 | “正在处理,请勿重复提交” | | `540007` | 保险计划缺费率 | “请维护保险计划费率后重试” | | `540032` | 同司机服务日已有保单覆盖 | “已有保单覆盖,请核对后处理” | +| `540033` | 司机配置年保但服务日不在年保起止内 | “司机年保未覆盖当前服务日,请续保/修正年保后重试,或改按行程险处理” | +| `540034` | 手工年保/线下保单与线上覆盖信息不一致 | “请核对线下保单并上传凭证,确认后标记线下完成” | | `605601` | 保险服务不可用 | “保险服务暂不可用,请稍后重试或线下处理” | --- @@ -313,6 +320,8 @@ POST /admin/fleet/insurance/tasks/{taskId}/ignore - 新建订单 -> 补出行人 -> 补大交通 -> 提用车需求 -> 车务派单确认 -> 保险任务生成。 - 同一司机同一服务日多订单,不重复买保险。 - 取消派单时,同司机同日还有其它 active 派单则不退保。 +- 年保司机在服务期内不买按单险;服务日超过年保到期日时生成 `540033` 待办。 +- 年保续保后重试 `540033` 任务,应变为 `SUCCESS`,且不能产生重复按单险。 - 投保失败后重试成功。 - 线下完成必须上传凭证。 - 定制师角色不可见车务保险菜单。