docs: 交接 Fleet 逐日逐车派车契约 (#5292) (#48)
所有检测均成功
changelog-filename-gate / validate (push) Successful in 2s
所有检测均成功
changelog-filename-gate / validate (push) Successful in 2s
这个提交包含在:
父节点
170d3b6208
当前提交
ea83186570
@ -0,0 +1,244 @@
|
||||
---
|
||||
schema: "hl-changelog/v2"
|
||||
ticket: "5292"
|
||||
title: "车务按服务日逐车配置用车、接机与价格"
|
||||
consumer: "admin"
|
||||
change_type: "修改接口"
|
||||
backend_status: "deployed"
|
||||
gateway_status: "verified"
|
||||
frontend_status: "pending"
|
||||
frontend_owner: ""
|
||||
frontend_ref: ""
|
||||
target_release: ""
|
||||
verified_at: "2026-07-27T19:10:14+08:00"
|
||||
status_note: "后端 PR #5296 已合并并部署测试环境;Fleet 详情与新旧字段互斥校验经真实网关验证,等待前端认领"
|
||||
updated_at: "2026-07-27"
|
||||
base: "dev-v3"
|
||||
---
|
||||
|
||||
# Fleet:按服务日逐车配置用车、接机与价格
|
||||
|
||||
> **服务**:`hl-fleet-service`
|
||||
> **后端 PR**:[wx/HL#5296](https://git.1814.love:8443/wx/HL/pulls/5296)
|
||||
> **Issue**:#5292
|
||||
> **日期**:2026-07-27
|
||||
> **影响范围**:管理后台车务看板派车弹窗和订单派车详情
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 关键变化
|
||||
|
||||
新派车页面不再提交“收取车费日期”。派车保存改为提交完整的“服务日期 × 稳定车辆槽位”矩阵,每个单元格独立说明是否用车、车辆、司机、ARRIVAL 接机参与和当天实际价格。
|
||||
|
||||
旧 `items` 输入暂时保留用于滚动发布兼容;旧收费日期字段只能随旧 `items` 使用,`dailyPlan` 模式提交这些字段会被拒绝。
|
||||
|
||||
## 变更接口
|
||||
|
||||
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|
||||
|---|---|---|---|---|---|
|
||||
| 1 | 原子提交最终派车方案 | POST | `/admin/fleet/assignments/batch` | 请求体扩展与校验调整 | 新增完整 `dailyPlan`,保留旧 `items` 兼容 |
|
||||
| 2 | 车务看板订单详情 | GET | `/admin/fleet/board/orders/<orderId>` | 响应字段新增 | 返回逐日逐车计划、每车小计和订单车辆总计 |
|
||||
|
||||
## 二、原子提交最终派车方案
|
||||
|
||||
### `POST /admin/fleet/assignments/batch`
|
||||
|
||||
**请求 VO**:`BatchCreateAssignmentReqVO`
|
||||
|
||||
### 新增顶层字段
|
||||
|
||||
| 字段 | 类型 | 必填 | 约束 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| `dailyPlan` | `DailyPlanItem[]` | 新页面必填 | 与旧 `items` 二选一;最多 4000 项 | 完整“服务日期 × 稳定车辆槽位”矩阵 |
|
||||
| `confirmNoVehicleServiceDates` | `Boolean` | 条件必填 | 某日全部槽位 `used=false` 时必须为 `true` | 全天无需用车二次确认 |
|
||||
|
||||
`orderId`、`requirementId` 和所有 Long ID 继续按 JSON 字符串传输。
|
||||
|
||||
### `DailyPlanItem`
|
||||
|
||||
| 字段 | 类型 | 必填 | 约束 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| `fleetItemIndex` | `Integer` | 是 | `>= 0` | 稳定车辆槽位序号 |
|
||||
| `serviceDate` | `String(date)` | 是 | `yyyy-MM-dd`,必须属于当前需求服务日 | 服务日期 |
|
||||
| `used` | `Boolean` | 是 | - | 当天是否实际用车 |
|
||||
| `vehicleId` | `String(Long)` | 条件必填 | `used=true` 必填;不用车必须为空 | 当天车辆 |
|
||||
| `driverId` | `String(Long)` | 条件必填 | `used=true` 必填;不用车必须为空 | 当天司机 |
|
||||
| `pickupParticipant` | `Boolean` | 否 | 仅表示 ARRIVAL 接机/接站;不用车不得为 `true` | 当天是否参与接机 |
|
||||
| `assignmentPrice` | `String(decimal)` | 条件必填 | `used=true` 必填;非负、整数最多 10 位、小数最多 2 位 | 本车当天实际价格,可为 `0.00` |
|
||||
| `priceAdjustmentReason` | `String` | 条件必填 | 最多 256 字;实际价偏离价格日历时必填 | 改价原因 |
|
||||
| `confirmCrossResident` | `Boolean` | 否 | 跨常驻车时按既有规则确认 | 跨常驻车确认 |
|
||||
|
||||
### 正确请求示例
|
||||
|
||||
```json
|
||||
{
|
||||
"orderId": "789",
|
||||
"orderNo": "26-4165",
|
||||
"requirementId": "790",
|
||||
"startDate": "2026-08-04",
|
||||
"endDate": "2026-08-05",
|
||||
"headcount": 3,
|
||||
"holdMode": 0,
|
||||
"fromEntry": "from-board",
|
||||
"requestId": "daily-plan-26-4165-v1",
|
||||
"confirmNoVehicleServiceDates": false,
|
||||
"dailyPlan": [
|
||||
{
|
||||
"fleetItemIndex": 0,
|
||||
"serviceDate": "2026-08-04",
|
||||
"used": true,
|
||||
"vehicleId": "701",
|
||||
"driverId": "801",
|
||||
"pickupParticipant": true,
|
||||
"assignmentPrice": "800.00",
|
||||
"priceAdjustmentReason": "首日短途优惠"
|
||||
},
|
||||
{
|
||||
"fleetItemIndex": 1,
|
||||
"serviceDate": "2026-08-04",
|
||||
"used": true,
|
||||
"vehicleId": "702",
|
||||
"driverId": "802",
|
||||
"pickupParticipant": false,
|
||||
"assignmentPrice": "900.00",
|
||||
"priceAdjustmentReason": null
|
||||
},
|
||||
{
|
||||
"fleetItemIndex": 0,
|
||||
"serviceDate": "2026-08-05",
|
||||
"used": false,
|
||||
"vehicleId": null,
|
||||
"driverId": null,
|
||||
"pickupParticipant": false,
|
||||
"assignmentPrice": null,
|
||||
"priceAdjustmentReason": null
|
||||
},
|
||||
{
|
||||
"fleetItemIndex": 1,
|
||||
"serviceDate": "2026-08-05",
|
||||
"used": true,
|
||||
"vehicleId": "702",
|
||||
"driverId": "802",
|
||||
"pickupParticipant": false,
|
||||
"assignmentPrice": "900.00",
|
||||
"priceAdjustmentReason": null
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 提交规则
|
||||
|
||||
- 每个保留槽位必须覆盖当前需求的全部服务日;同一 `fleetItemIndex + serviceDate` 不能重复。
|
||||
- 同一服务日不能重复使用同一车辆或同一司机。
|
||||
- `used=false` 不占用车辆/司机、不投保、不计费;车辆、司机、接机和价格必须为空或 false。
|
||||
- 某日所有槽位均不用车时允许提交,但必须设置 `confirmNoVehicleServiceDates=true`。
|
||||
- 大交通 ARRIVAL 要求平台接机时,当日至少一辆 `used=true` 的车辆必须 `pickupParticipant=true`。
|
||||
- 大交通未要求接机时,仍允许人工标记一辆或多辆使用中的车辆参与接机。
|
||||
- 连续日期使用相同车辆和司机时后端自动合并派车组;逐日价格仍分别冻结。
|
||||
- 过去日期、已完结日期或已关账对账期不能修改。
|
||||
- 新 `dailyPlan` 不得提交 `chargeableServiceDates`、`vehicleFeeWaiverReason`、`confirmAllServiceDatesFree`。
|
||||
|
||||
### 参数错误响应
|
||||
|
||||
本项目参数校验失败沿用 HTTP 200 + 业务 `code=400`:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 400,
|
||||
"message": "dailyPlan 与旧 items 必须二选一,dailyPlan 不得提交旧收费日期字段",
|
||||
"data": null,
|
||||
"success": false
|
||||
}
|
||||
```
|
||||
|
||||
## 三、车务看板订单详情
|
||||
|
||||
### `GET /admin/fleet/board/orders/<orderId>`
|
||||
|
||||
**响应 VO**:`Result<BoardOrderDetailVO>`
|
||||
|
||||
### 新增响应字段
|
||||
|
||||
| 字段 | 类型 | 空值规则 | 说明 |
|
||||
|---|---|---|---|
|
||||
| `dailyVehiclePlan` | `DailyVehiclePlanVO[]` | 无记录返回 `[]` | 按服务日期、槽位序号稳定排序 |
|
||||
| `vehicleFeeSummaries` | `VehicleFeeSummaryVO[]` | 无实际用车返回 `[]` | 按实际车辆汇总小计 |
|
||||
| `vehicleFeeTotal` | `String(decimal)` | 无费用返回 `"0.00"` | 当前需求全部实际用车日总计 |
|
||||
|
||||
### `DailyVehiclePlanVO`
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| `serviceDate` | `String(date)` | 服务日期 |
|
||||
| `fleetItemIndex` | `Integer` | 稳定槽位序号 |
|
||||
| `assignmentSlotId` | `String(Long)` | 稳定槽位 ID |
|
||||
| `assignmentId` | `String(Long)` | 每日切片 ID;显式不用车也返回占位 ID |
|
||||
| `assignmentGroupId` | `String(Long)` | 当前连续派车组 ID |
|
||||
| `planFinalized` | `Boolean` | 该日格是否已经业务最终确认 |
|
||||
| `planState` | `String` | `UNPLANNED`(建议占位)/ `NOT_USED`(明确不用车)/ `USED`(实际用车) |
|
||||
| `used` | `Boolean` | 当天是否实际用车;必须结合 `planFinalized/planState` 区分未规划与明确不用车 |
|
||||
| `pickupParticipant` | `Boolean` | 当天车辆是否参与 ARRIVAL 接机 |
|
||||
| `pickupRequired` | `Boolean` | 大交通当天是否要求接机 |
|
||||
| `vehicleId` / `driverId` | `String(Long)` | 不用车时为 `null` |
|
||||
| `vehiclePlate` / `vehicleModel` / `driverName` | `String` | 不用车时为 `null` |
|
||||
| `driverPhone` | `String` | 脱敏手机号;不用车时为 `null` |
|
||||
| `calendarPrice` | `String(decimal)` | 价格日历参考价;缺价或不用车时为 `null` |
|
||||
| `assignmentPrice` | `String(decimal)` | 本车当天实际价;不用车时为 `null` |
|
||||
| `priceSource` | `String` | `CALENDAR` / `OVERRIDE` / `MISSING` / `NOT_USED` |
|
||||
| `priceAdjustmentReason` | `String` | 改价原因,无则 `null` |
|
||||
| `assignmentStatus` | `String` | 基础派单状态;显式不用车为 `unassigned` |
|
||||
| `readOnly` | `Boolean` | 过去、已完结或已关账日期为 `true` |
|
||||
| `readOnlyReason` | `String` | `服务日期已过去` / `派单已完结` / `对账期已关账`,可编辑时为 `null` |
|
||||
|
||||
### `VehicleFeeSummaryVO`
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| `vehicleId` | `String(Long)` | 实际车辆 ID |
|
||||
| `vehiclePlate` | `String` | 车牌 |
|
||||
| `vehicleModel` | `String` | 车型 |
|
||||
| `amount` | `String(decimal)` | 该车辆全部实际用车日小计 |
|
||||
|
||||
金额守恒:`vehicleFeeTotal = sum(vehicleFeeSummaries[].amount) = sum(dailyVehiclePlan[used=true].assignmentPrice)`。
|
||||
|
||||
## 四、前端改造清单
|
||||
|
||||
1. 删除派车弹窗中的“收取车费日期”和免费日期提交逻辑。
|
||||
2. 按服务日渲染稳定车辆槽位矩阵;每格维护 `used`、车辆、司机、ARRIVAL 接机参与和当天实际价格。
|
||||
3. 某日全不用车时显示二次确认,并提交 `confirmNoVehicleServiceDates=true`。
|
||||
4. 默认价格使用详情/报价返回的日历价;修改价格时强制填写原因,允许 `0.00`。
|
||||
5. 详情展示每辆车小计和订单车辆总计;金额以字符串解析,不能用浮点累计。
|
||||
6. `readOnly=true` 的日格禁止编辑,并展示 `readOnlyReason`。
|
||||
7. 新页面只提交 `dailyPlan`,不得同时提交旧 `items` 或收费日期字段。
|
||||
|
||||
## 五、数据库和历史数据
|
||||
|
||||
- `fleet_assignment.daily_vehicle_used`:`1` 表示当天实际用车,`0` 表示明确不用车;滚动发布期间允许 `NULL`,读取侧按车辆/司机事实回退,避免旧节点新写入被误判。
|
||||
- `fleet_assignment.pickup_participant`:`1` 表示当天该车参与 ARRIVAL 接机/接站;滚动发布期间允许 `NULL` 并按 `false` 兼容。
|
||||
- 历史已派日迁移为实际用车;原免费日实际价格迁为 `0.00`;未派占位迁为不用车;历史接机参与默认 `false`。
|
||||
- 全程明确不用车可由 Fleet 以 `vehicleCount=0` 完成需求;Order 端车辆和司机快照均为空。
|
||||
|
||||
## 六、不影响范围
|
||||
|
||||
- 不修改 `hl-ui` 仓库,由本 changelog 交接前端。
|
||||
- 不改变单派接口及旧 `items` 滚动兼容输入。
|
||||
- 不把 DEPARTURE 送机/送站映射到 `pickupParticipant`。
|
||||
- 不改变订单或产品价格日历接口。
|
||||
|
||||
## 验证证据
|
||||
|
||||
- 后端 PR #5296 已 squash 合并至 `dev-v3`,`hl-order-service-v3` 与 `hl-fleet-service` 已滚动部署测试环境,双实例健康检查通过。
|
||||
- Fleet 最新 `dev-v3` reactor verify:2452 项测试,0 failures,0 errors,1 skipped;Spotless、Jar、JaCoCo 均成功。
|
||||
- Order 全量:6759 项测试,0 failures,0 errors,29 skipped;零车辆回调生产者/消费者及迁移定向回归通过。
|
||||
- 真实测试网关 `GET /admin/fleet/board/orders/<orderId>`:HTTP 200、业务 code 200;返回 3 条 `dailyVehiclePlan`,包含 `planFinalized`、`planState`、`used`、接机、价格和只读字段;逐车汇总数组及字符串总计存在。
|
||||
- 真实测试网关 `POST /admin/fleet/assignments/batch` 安全负例:`dailyPlan` 携带旧收费日期字段时 HTTP 200、业务 code 400,确认新旧模式互斥;该探针不产生业务写入。
|
||||
- OpenAPI diff 与 Spring Cloud Contract 未配置;已通过源码字段对比、Controller/Service 及 Fleet → Order 双端普通测试提供人工回退证据,未冒充工具通过。
|
||||
|
||||
当前状态:
|
||||
|
||||
- `backend_status: deployed`
|
||||
- `gateway_status: verified`
|
||||
- `frontend_status: pending`
|
||||
|
||||
关联 Issue:[wx/HL#5292](https://git.1814.love:8443/wx/HL/issues/5292)
|
||||
正在加载...
x
在新工单中引用
屏蔽一个用户