diff --git a/changelogs-v2/2026-09/27_8408_车务响应补团号-修改接口-管理后台.md b/changelogs-v2/2026-09/27_8408_车务响应补团号-修改接口-管理后台.md new file mode 100644 index 00000000..3a21cd8c --- /dev/null +++ b/changelogs-v2/2026-09/27_8408_车务响应补团号-修改接口-管理后台.md @@ -0,0 +1,1517 @@ +--- +schema: "hl-changelog/v2" +ticket: "8408" +title: "车务派单响应体补团号字段" +consumer: "admin" +author: "wx(GIT)" +change_type: "修改接口" +backend_status: "deployed" +gateway_status: "verified" +frontend_status: "pending" +frontend_owner: "" +frontend_ref: "" +target_release: "" +verified_at: "2026-09-27" +status_note: "PR #8419 已合入 dev-v3(合并提交 c5027d809);2026-09-27 fleet 与 order-v3 同批部署测试环境,网关实测接口 4/5/7/9/11/12 通过" +updated_at: "2026-09-27" +base: "dev-v3" +--- + +# 车务派单响应体补团号字段 + +> **服务**: hl-fleet-service + hl-common-core +> **PR**: #8419 | **Issue**: #8408 | **合并提交**: `c5027d809` +> **影响范围**: 管理后台车务 13 个接口,含派单预检、需求驳回、自动推荐、分组派车总览、共用关系(查询/确认)、共用成员候选、司机险保单(分页/旧路径/详情)、关账后变更补偿列表、矩阵主数据(网格)、司机 H5 行程 + +--- + +## ⚠️ 关键变化 + +**车务派单链路响应的 VO(含嵌套内部类)新增团号字段,表示订单的团号。** 字段类型均为 String,无团号时为 null;多数接口取自派单表 `fleet_assignment.team_no` 的建行快照(写一次不刷新),接口 4/12/13 优先取订单实时值、为空才回落快照。 + +涉及 10 个 fleet VO + hl-common-core 共用 DTO `OrderVehicleCoverageItemDTO`: +- 派单预检冲突项(`conflictTeamNo`) +- 需求驳回响应、槽位自动推荐响应(`teamNo`) +- 分组派车总览订单行(`teamNo`,订单实时优先) +- 共用关系承担方与成员(`costBearerTeamNo` / `teamNo`)、共用成员候选(`teamNo`,并订正 `groupCode` 注解) +- 司机险保单关联派单(`teamNo`) +- 关账后变更补偿列表(`teamNo`) +- 矩阵主数据连线(`fromTeamNo` / `toTeamNo`,订单实时优先) +- 司机 H5 行程(`teamNo`,订单实时优先) + +--- + +## 二、变更接口清单 + +| # | 接口 | 方法 | 路径 | 变更类型 | 说明 | +|---|------|------|------|----------|------| +| 1 | 派单预检 | POST | `/admin/fleet/assignments/precheck` | 字段新增 | 冲突项新增 `conflictTeamNo` | +| 2 | 需求驳回 | POST | `/admin/fleet/assignments/{assignmentId}/requirement-reject` | 字段新增 | 响应新增 `teamNo` | +| 3 | 槽位自动推荐 | POST | `/admin/fleet/assignments/{assignmentId}/auto-recommend` | 字段新增 | 响应新增 `teamNo` | +| 4 | 分组派车总览 | GET | `/admin/fleet/group-dispatch/batches/{groupBatchId}/overview` | 字段新增 | 订单行新增 `teamNo` | +| 5 | 共用关系查询 | GET | `/admin/fleet/group-dispatch/batches/{groupBatchId}/share-groups` | 字段新增 | 响应新增 `costBearerTeamNo` 与成员 `teamNo` | +| 6 | 共用关系确认 | POST | `/admin/fleet/group-dispatch/batches/{groupBatchId}/share-groups` | 字段新增 | 同上 | +| 7 | 共用成员候选 | GET | `/admin/fleet/group-dispatch/batches/{groupBatchId}/share-member-candidates` | 字段新增/改注解 | 候选新增 `teamNo`;`groupCode` 注解订正为「车务分组编码」 | +| 8 | 司机险保单分页(新路径) | POST | `/admin/fleet/insurance/driver-policies/page` | 字段新增 | 关联派单新增 `teamNo` | +| 9 | 司机险保单分页(旧路径,已弃用) | GET | `/admin/fleet/insurance/policies` | 字段新增 | 关联派单新增 `teamNo`,响应结构与接口 8 相同 | +| 10 | 司机险保单详情 | GET | `/admin/fleet/insurance/driver-policies/{insuranceOrderId}` | 字段新增 | 关联派单新增 `teamNo` | +| 11 | 关账后变更补偿列表 | GET | `/admin/fleet/reconciliation/pending-compensations` | 字段新增 | 响应新增 `teamNo` | +| 12 | 矩阵主数据(网格) | GET | `/admin/fleet/matrix/grid` | 字段新增 | 连线新增 `fromTeamNo` / `toTeamNo` | +| 13 | H5 行程 | GET | `/app/h5/itinerary/{token}` | 字段新增 | 响应新增 `teamNo` | + +--- + +## 三、接口详情 + +### 1. 派单预检 `POST /admin/fleet/assignments/precheck` + +**VO**: `PrecheckReqVO → PrecheckRespVO` + +#### 使用场景 + +车务选定车辆和司机、保存派单前调用,只读校验该车/该司机在给定日期区间是否与既有派单冲突;冲突项新增 `conflictTeamNo`,车务按团号快速辨认冲突单,无需再跳转查订单。 + +#### 入参 + +| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | +|------|------|------|------|------|------| +| `orderId` | Body | Long(字符串) | ❌ | — | 拟派单订单 ID,仅用于日志/上下文 | +| `vehicleId` | Body | Long(字符串) | ✅ | 非空 | 拟派车辆 ID | +| `driverId` | Body | Long(字符串) | ✅ | 非空 | 拟派司机 ID | +| `startDate` | Body | LocalDate | ✅ | 非空 | 用车开始日 | +| `endDate` | Body | LocalDate | ✅ | 非空 | 用车结束日 | +| `pickupAt` | Body | String | ❌ | — | 接客地点 | +| `dropoffAt` | Body | String | ❌ | — | 送客地点 | +| `headcount` | Body | Integer | ❌ | — | 人数 | +| `excludeAssignmentId` | Body | Long(字符串) | ❌ | — | 改派预校验时排除自身派单 ID | + +#### 出参 + +| 字段 | 类型 | 说明 | +|------|------|------| +| `conflict` | boolean | 是否存在冲突 | +| `conflicts[]` | List | 冲突明细数组 | +| `conflicts[].type` | String | 冲突维度(vehicle=车冲突/driver=司机冲突/vehicle_not_found=车辆不存在/driver_not_found=司机不存在) | +| `conflicts[].conflictAssignmentId` | String(Long) | 冲突的已有派单 ID | +| `conflicts[].conflictOrderNo` | String | 冲突派单所属订单号 | +| `conflicts[].conflictTeamNo` | String | **【新增】** 冲突派单的团号,无团号为 null | +| `conflicts[].conflictDateRange` | String | 冲突日期区间 | +| `conflicts[].blocking` | Boolean | 是否阻断性冲突 | +| `conflicts[].msg` | String | 冲突提示文案 | +| `warnings[]` | List | 非阻断提示数组 | +| `warnings[].type` | String | 提示类型(seats_short/vehicle_unavailable/driver_unavailable/cross_resident/license_expired/veh_inspect_expired/veh_insure_expired) | +| `warnings[].msg` | String | 提示文案 | + +#### 请求示例 + +```json +{ + "vehicleId": "1934567890123456701", + "driverId": "1934567890123456801", + "startDate": "2026-10-01", + "endDate": "2026-10-02" +} +``` + +#### 响应示例 + +有冲突时: + +```json +{ + "code": 200, + "message": "成功", + "success": true, + "data": { + "conflict": true, + "conflicts": [ + { + "type": "vehicle", + "conflictAssignmentId": "1934567890123456901", + "conflictOrderNo": "26-0501", + "conflictTeamNo": "26-0480", + "conflictDateRange": "2026-10-01~2026-10-02", + "blocking": true, + "msg": "车 蒙A-88888 10/1-10/2 已派" + } + ], + "warnings": [] + } +} +``` + +#### 空数据 / 降级响应 + +无冲突时 `conflict=false`,`conflicts[]` 与 `warnings[]` 均为空列表: + +```json +{ + "code": 200, + "message": "成功", + "success": true, + "data": { + "conflict": false, + "conflicts": [], + "warnings": [] + } +} +``` + +#### 错误响应 + +本接口是只读咨询,恒 `code=200` 不抛业务异常;车辆/司机不存在也走 `conflicts[].type=vehicle_not_found`/`driver_not_found`,不是异常。仅 `@Valid` 校验失败(如缺 `vehicleId`)走通用参数错误: + +```json +{ + "code": 100001, + "message": "车辆 ID 不能为空", + "success": false, + "data": null +} +``` + +#### 业务边界 + +- `conflictTeamNo` 来自冲突派单表 `fleet_assignment.team_no` 的建行快照(`trimToNull` 后取值),不回落订单号,也不给空串。 +- 快照为 null 的三类情形:建行时订单还没有团号(含 #8408 A 修复前被 transition 强推付款态的订单);本字段上线前的存量派单;车务在管理端手工新建的派单(建行时未关联到已有团号的订单)。 +- 团号一旦写入即不再刷新,不会出现「团号与订单不符」的错号,只会是 null 或旧值。 + +--- + +### 2. 需求驳回 `POST /admin/fleet/assignments/{assignmentId}/requirement-reject` + +**VO**: `RequirementRejectReqVO → RequirementRejectRespVO` + +#### 使用场景 + +车务在某条未派占位对应的用车需求确定无法安排车辆时驳回该需求;响应新增 `teamNo` 便于调度员核对被驳回需求所属订单的团号。 + +#### 入参 + +| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | +|------|------|------|------|------|------| +| `assignmentId` | Path | Long | ✅ | 正整数 | 未派占位对应的派单 ID | +| `returnRemark` | Body | String | ✅ | 非空,≤500 字 | 驳回原因 | + +#### 出参 + +| 字段 | 类型 | 说明 | +|------|------|------| +| `orderId` | String(Long) | 订单 ID | +| `teamNo` | String | **【新增】** 订单的团号,无团号为 null | +| `requirementId` | String(Long) | 被驳回的用车需求 ID | +| `canceledUnassignedCount` | Integer | 联动作废的未派单槽位数 | +| `remainingInFlightCount` | Integer | 该需求下仍在途(已派未完成)的槽位数 | +| `processingStatus` | String | 处理状态(PENDING/PROCESSING/SUCCESS) | + +#### 请求示例 + +```json +{ + "returnRemark": "当地无满足条件车辆,请调整车型或用车时间" +} +``` + +#### 响应示例 + +```json +{ + "code": 200, + "message": "成功", + "success": true, + "data": { + "orderId": "1934567890123456701", + "teamNo": "26-0480", + "requirementId": "1934567890123456850", + "canceledUnassignedCount": 2, + "remainingInFlightCount": 0, + "processingStatus": "SUCCESS" + } +} +``` + +#### 空数据 / 降级响应 + +该 requirementId 下已存在 holding/assigned 的派单时,须先取消派单并完成司机告知存证,否则拒绝: + +```json +{ + "code": 605018, + "message": "已派单不可驳回", + "success": false, + "data": null +} +``` + +#### 错误响应 + +```json +{ + "code": 605009, + "message": "派单不存在", + "success": false, + "data": null +} +``` + +其余业务码:582080 用车需求不存在或已失效 / 582083 需求状态不允许此操作。 + +#### 业务边界 + +- `teamNo` 来自派单表 `team_no` 建行快照,无团号为 null,不回落订单号,也不给空串。 +- 快照为 null 的三类情形:建行时订单还没有团号;本字段上线前的存量派单;车务在管理端手工新建的派单(建行时未关联到已有团号的订单)。 +- 驳回不改变派单/需求的团号值,仅改状态。 + +--- + +### 3. 槽位自动推荐 `POST /admin/fleet/assignments/{assignmentId}/auto-recommend` + +**VO**: `SlotAutoRecommendRespVO` + +#### 使用场景 + +需求变更后车务删除旧派车、对空缺派车行调用本接口;接口只读、不产生写操作,仅按新需求推荐候选车辆与司机,车务确认后仍需走既有派车接口手动提交。响应新增 `teamNo` 标识该空缺派车行所属订单的团号。 + +#### 入参 + +| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | +|------|------|------|------|------|------| +| `assignmentId` | Path | Long | ✅ | 正整数 | 空缺待派的派单行 ID | + +(无请求体。) + +#### 出参 + +| 字段 | 类型 | 说明 | +|------|------|------| +| `assignmentId` | String(Long) | 派单行 ID(回显路径参数) | +| `requirementId` | String(Long) | 所属用车需求 ID | +| `orderId` | String(Long) | 所属订单 ID | +| `teamNo` | String | **【新增】** 所属订单的团号,无团号为 null | +| `recommendedVehicle` | Object | 推荐车辆(可为 null,见 `noRecommendation`) | +| `recommendedDriver` | Object | 推荐司机(可为 null) | +| `recommendNote` | String | 推荐说明文案 | +| `vehicleAlternatives[]` | List | 候选车辆备选列表 | +| `driverAlternatives[]` | List | 候选司机备选列表 | +| `noRecommendation` | Boolean | 是否无合适推荐 | + +#### 请求示例 + +```http +POST /admin/fleet/assignments/1934567890123456901/auto-recommend +``` + +#### 响应示例 + +```json +{ + "code": 200, + "message": "成功", + "success": true, + "data": { + "assignmentId": "1934567890123456901", + "requirementId": "1934567890123456850", + "orderId": "1934567890123456701", + "teamNo": "26-0480", + "recommendedVehicle": { + "vehicleId": "1934567890123456702", + "plate": "蒙A-88888" + }, + "recommendedDriver": { + "driverId": "1934567890123456802", + "name": "王师傅" + }, + "recommendNote": "常驻匹配优先", + "vehicleAlternatives": [], + "driverAlternatives": [], + "noRecommendation": false + } +} +``` + +#### 空数据 / 降级响应 + +无合适推荐时 `noRecommendation=true`,`recommendedVehicle`/`recommendedDriver` 为 null: + +```json +{ + "code": 200, + "message": "成功", + "success": true, + "data": { + "assignmentId": "1934567890123456901", + "requirementId": "1934567890123456850", + "orderId": "1934567890123456701", + "teamNo": "26-0480", + "recommendedVehicle": null, + "recommendedDriver": null, + "recommendNote": "当前无满足条件的车辆或司机", + "vehicleAlternatives": [], + "driverAlternatives": [], + "noRecommendation": true + } +} +``` + +#### 错误响应 + +```json +{ + "code": 605009, + "message": "派单不存在", + "success": false, + "data": null +} +``` + +#### 业务边界 + +- `teamNo` 来自该派单行所属订单的派单表快照,无团号为 null。 +- 本接口只读、不产生写操作,也不会生成新派单;车务确认推荐后需另调派车接口手动提交。 +- 快照为 null 的三类情形:建行时订单还没有团号;本字段上线前的存量派单;车务在管理端手工新建的派单(建行时未关联到已有团号的订单)。 + +--- + +### 4. 分组派车总览 `GET /admin/fleet/group-dispatch/batches/{groupBatchId}/overview` + +**VO**: `GroupDispatchOverviewRespVO`(逐户行 `GroupDispatchOverviewOrderVO`) + +#### 使用场景 + +车务查看团期配车总览页,按权威服务日逐日铺开已排车、空洞日与逐户接送机缺口;逐户行新增 `teamNo`,车务按团号识别订单。 + +#### 入参 + +| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | +|------|------|------|------|------|------| +| `groupBatchId` | Path | Long | ✅ | 正整数 | 团期主订单 ID | + +(无 Query 参数,也无 `pageIndex`/`pageSize`。) + +#### 出参 + +| 字段 | 类型 | 说明 | +|------|------|------| +| `groupBatchId` | String(Long) | 团期主订单 ID | +| `batchNo` | String | 团期批次号(如 `GB-26-0912-01`,非订单团号) | +| `serviceDates[]` | List<LocalDate> | 权威服务日集合(order-v3 下发) | +| `orders[]` | List | 逐户行数组 | +| `orders[].orderId` | String(Long) | 子订单 ID | +| `orders[].orderNo` | String | 订单号 | +| `orders[].teamNo` | String | **【新增】** 订单团号,无团号为 null(经 order-v3 覆盖口透传,优先取订单当前值) | +| `orders[].customerName` | String | 客户姓名 | +| `orders[].headcount` | Integer | 出行人数 | +| `transferPendingTotal` | Integer | 全团接送机未配计数 | + +#### 请求示例 + +```http +GET /admin/fleet/group-dispatch/batches/1934567890123456789/overview +``` + +#### 响应示例 + +```json +{ + "code": 200, + "message": "成功", + "success": true, + "data": { + "groupBatchId": "1934567890123456789", + "batchNo": "GB-26-0912-01", + "serviceDates": ["2026-09-12", "2026-09-13"], + "orders": [ + { + "orderId": "1934567890123456790", + "orderNo": "26-0503", + "teamNo": "26-0480", + "customerName": "赵先生", + "headcount": 3 + } + ], + "transferPendingTotal": 1 + } +} +``` + +#### 空数据 / 降级响应 + +团期下无订单时 `orders` 为空列表,其余骨架字段(`serviceDates`/`days`)仍正常返回: + +```json +{ + "code": 200, + "message": "成功", + "success": true, + "data": { + "groupBatchId": "1934567890123456789", + "batchNo": "GB-26-0912-01", + "serviceDates": [], + "orders": [], + "transferPendingTotal": 0 + } +} +``` + +#### 错误响应 + +```json +{ + "code": 600012, + "message": "团期配车基线不可达,请稍后重试", + "success": false, + "data": null +} +``` + +该码同时覆盖「order-v3 降级」与「团期不存在」两种情形,前端不应把它渲染成「该团没有需求」。 + +#### 业务边界 + +- `orders[].teamNo` 取自 order-v3 单团覆盖口透传的订单当前团号(`order_main.team_no`),不是派单快照,故本接口不受「建行时订单还没有团号」这一类快照边界影响。 +- 该字段仍可能为 null:团号尚未生成(订单未收款/未确认)时,透传值本身就是 null。 +- 团号一旦生成不会改号,故不存在「团号回退」的情况。 + +--- + +### 5. 共用关系查询 `GET /admin/fleet/group-dispatch/batches/{groupBatchId}/share-groups` + +**VO**: `ShareGroupQueryReqVO → List`(成员 `ShareGroupMemberRespVO`) + +#### 使用场景 + +车务查看本团期的车辆/司机共用关系列表,确认成本承担方及成员派单;响应新增 `costBearerTeamNo` 与成员 `teamNo`,财务按团号核对。 + +#### 入参 + +| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | +|------|------|------|------|------|------| +| `groupBatchId` | Path | Long | ✅ | 正整数 | 团期主订单 ID | +| `serviceDate` | Query | LocalDate | ❌ | — | 筛选服务日,不传=全部服务日 | +| `resourceType` | Query | String | ❌ | VEHICLE / DRIVER | 筛选资源维度,不传=两者;非法枚举按入参非法拒绝 | +| `includeReleased` | Query | Boolean | ❌ | 默认 false | 是否一并返回已解除的关系与变更历史 | + +#### 出参 + +响应是**裸数组**(`data` 直接是数组,不包一层 `shareGroups`): + +| 字段 | 类型 | 说明 | +|------|------|------| +| `[].shareGroupId` | String(Long) | 共用关系 ID | +| `[].groupBatchId` | String(Long) | 团期主订单 ID | +| `[].resourceType` | String | 资源维度(VEHICLE / DRIVER) | +| `[].status` | String | 关系状态(ACTIVE / RELEASED) | +| `[].costBearer` | String | 成本承担方(GROUP / ORDER) | +| `[].costBearerOrderId` | String(Long) | `costBearer=ORDER` 时的承担订单 ID | +| `[].costBearerTeamNo` | String | **【新增】** 承担订单的团号,取不到为 null | +| `[].members[]` | List | 成员全集 | +| `[].members[].sourceType` | String | 成员来源(ASSIGNMENT / GROUP_DISPATCH) | +| `[].members[].orderId` | String(Long) | 成员订单 ID(ASSIGNMENT 成员) | +| `[].members[].teamNo` | String | **【新增】** 成员派单的团号,无团号为 null | + +#### 请求示例 + +```http +GET /admin/fleet/group-dispatch/batches/8801/share-groups?serviceDate=2026-09-12&resourceType=VEHICLE +``` + +#### 响应示例 + +```json +{ + "code": 200, + "message": "成功", + "success": true, + "data": [ + { + "shareGroupId": "77001", + "groupBatchId": "8801", + "serviceDate": "2026-09-12", + "resourceType": "VEHICLE", + "resourceId": "1", + "status": "ACTIVE", + "costBearer": "ORDER", + "costBearerOrderId": "70123", + "costBearerTeamNo": "26-0480", + "costSourceRefNo": "SHARE-77001", + "members": [ + { + "sourceType": "ASSIGNMENT", + "sourceId": "88001", + "requirementId": "5501", + "orderId": "70123", + "teamNo": "26-0480" + } + ] + } + ] +} +``` + +#### 空数据 / 降级响应 + +无共用关系时返回空数组: + +```json +{ + "code": 200, + "message": "成功", + "success": true, + "data": [] +} +``` + +#### 错误响应 + +无专属业务错误码;`resourceType` 传非法字面量按参数非法拒绝: + +```json +{ + "code": 100001, + "message": "参数非法", + "success": false, + "data": null +} +``` + +#### 业务边界 + +- `costBearerTeamNo` 取成员里同 `costBearerOrderId` 的 ASSIGNMENT 成员派单快照团号,取不到为 null。 +- `members[].teamNo` 只对 `sourceType=ASSIGNMENT` 的成员有意义;`GROUP_DISPATCH` 成员恒为 null(团级配车行不挂订单)。 +- 两者都来自派单表快照,写一次不刷新;快照为 null 的三类情形同接口 1。 + +--- + +### 6. 共用关系确认 `POST /admin/fleet/group-dispatch/batches/{groupBatchId}/share-groups` + +**VO**: `ShareGroupConfirmReqVO → ShareGroupRespVO` + +#### 使用场景 + +车务在团期配车页确认「本团这一个服务日、这一辆车(或一名司机),由下列几方共用」;本端点是「授权+派单+准入」的复合原子操作,同一事务内完成。响应新增 `costBearerTeamNo` 与成员 `teamNo`。 + +#### 入参 + +| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | +|------|------|------|------|------|------| +| `groupBatchId` | Path | Long | ✅ | 正整数 | 团期主订单 ID | +| `serviceDate` | Body | LocalDate | ✅ | 非空 | 共用发生的服务日 | +| `resourceType` | Body | String | ✅ | VEHICLE / DRIVER | 资源维度 | +| `resourceId` | Body | Long | ✅ | 非空 | 车辆或司机 ID | +| `members` | Body | List<Object> | ✅ | 2-20 个,**成员全集非增量** | 成员数组 | +| `members[].sourceType` | Body | String | ✅ | ASSIGNMENT / GROUP_DISPATCH | 成员来源 | +| `members[].sourceId` | Body | Long | ✅ | 非空 | 成员来源 ID | +| `members[].admissionIntent` | Body | String | ❌ | — | 纯前端提示,服务端不读不校验不落库 | +| `costBearer` | Body | String | ✅ | GROUP / ORDER | 成本承担方 | +| `costBearerOrderId` | Body | Long | ❌ | `costBearer=ORDER` 时必填 | 承担订单 ID | +| `remark` | Body | String | ❌ | ≤200 字 | 备注 | +| `confirmCrossResident` | Body | Boolean | ❌ | 不传/false=不确认 | 跨常驻车派单人工确认位,见错误响应 605036 | + +#### 出参 + +(同接口 5 单条关系形状,非数组) + +| 字段 | 类型 | 说明 | +|------|------|------| +| `shareGroupId` | String(Long) | 共用关系 ID(同 (团,日,维度,资源) 重复提交返回同一个值) | +| `costBearer` | String | 成本承担方 | +| `costBearerOrderId` | String(Long) | 承担订单 ID | +| `costBearerTeamNo` | String | **【新增】** 承担订单的团号,无团号为 null | +| `costSourceRefNo` | String | 车费来源引用,格式 `SHARE-{shareGroupId}`,关系生命周期内恒定 | +| `members[]` | List | 成员全集(回显) | +| `members[].teamNo` | String | **【新增】** 成员派单的团号,无团号为 null | + +#### 请求示例 + +```json +{ + "serviceDate": "2026-09-12", + "resourceType": "VEHICLE", + "resourceId": 1, + "members": [ + { "sourceType": "ASSIGNMENT", "sourceId": 88001 }, + { "sourceType": "ASSIGNMENT", "sourceId": 88002 } + ], + "costBearer": "ORDER", + "costBearerOrderId": 70123 +} +``` + +#### 响应示例 + +```json +{ + "code": 200, + "message": "成功", + "success": true, + "data": { + "shareGroupId": "77001", + "costBearer": "ORDER", + "costBearerOrderId": "70123", + "costBearerTeamNo": "26-0480", + "costSourceRefNo": "SHARE-77001", + "members": [ + { "sourceType": "ASSIGNMENT", "sourceId": "88001", "orderId": "70123", "teamNo": "26-0480" }, + { "sourceType": "ASSIGNMENT", "sourceId": "88002", "orderId": "70124", "teamNo": "26-0481" } + ] + } +} +``` + +#### 空数据 / 降级响应 + +10 秒内重复提交同一份成员全集会被防重窗口拒绝(前端按「请勿重复提交」提示,不是失败): + +```json +{ + "code": 429, + "message": "请勿重复提交", + "success": false, + "data": null +} +``` + +#### 错误响应 + +```json +{ + "code": 605036, + "message": "该车已设常驻司机,与成员当前司机不是同一人,请确认跨常驻车派单", + "success": false, + "data": null +} +``` + +其余业务码:602100 成员不能少于 2 个 / 602101 成员不能超过 20 个 / 602103 成员派单不属本团或团期身份未知 / 602104 服务日不在团期服务日窗内 / 602105 团级配车成员不属本团或当日非活跃 / 602106 成员已属于另一个共用关系 / 602107 成本承担方缺失或非法 / 602109 共用关系已被并发修改。 + +#### 业务边界 + +- `costBearerTeamNo` / `members[].teamNo` 取自成员派单表快照,无团号为 null,不回落订单号。 +- `members` 是成员全集不是增量:同一 (团,日,维度,资源) 重复提交按新全集覆盖,不抛错,返回同一个 `shareGroupId`。 +- `confirmCrossResident` 不传或传 false 都表示不确认,真跨常驻仍抛 605036;确认后带 `confirmCrossResident=true` 原样重发即可,失败路径会释放防重窗口。 + +--- + +### 7. 共用成员候选 `GET /admin/fleet/group-dispatch/batches/{groupBatchId}/share-member-candidates` + +**VO**: `ShareMemberCandidateQueryReqVO → List` + +#### 使用场景 + +车务在建立共用关系前查询可纳入的成员候选,`sourceType`+`sourceId` 直接透传进接口 6 的 `members[]`;响应新增 `teamNo`,同时把 `groupCode` 的注解从「团号」订正为「车务分组编码」(不是团号)。 + +#### 入参 + +| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | +|------|------|------|------|------|------| +| `groupBatchId` | Path | Long | ✅ | 正整数 | 团期主订单 ID | +| `serviceDate` | Query | LocalDate | ✅ | 非空,须落在团期基线服务日内 | 服务日,窗外抛 602104 | +| `resourceType` | Query | String | ✅ | VEHICLE / DRIVER | 资源维度,非法字面量抛参数非法 | +| `resourceId` | Query | Long | ❌ | — | 车辆或司机 ID;不传=浏览态,`occupying`/`selectable` 返 null | + +#### 出参 + +响应是**裸数组**: + +| 字段 | 类型 | 说明 | +|------|------|------| +| `[].sourceType` | String | 成员来源(ASSIGNMENT / GROUP_DISPATCH) | +| `[].sourceId` | String(Long) | 成员来源 ID | +| `[].orderId` | String(Long) | 订单 ID(ASSIGNMENT 行;团级配车行为空) | +| `[].orderNo` | String | 订单号(ASSIGNMENT 行展示用) | +| `[].teamNo` | String | **【新增】** 团号,GROUP_DISPATCH 行与无团号均为 null | +| `[].groupCode` | String | **【注解订正】** 车务分组编码(如 G1),**不是团号**;如前端曾展示为「团号」,请改用 `teamNo` | +| `[].occupying` | Boolean | 三态:true/false=已判定,**null=未判定**(`resourceId` 未传时恒 null,不是 false) | +| `[].selectable` | Boolean | 三态:true=可勾选,false=不可选(见 `unselectableReason`),null=未判定 | +| `[].unselectableReason` | String | 不可选原因(CROSS_BATCH/NOT_OCCUPYING/ALREADY_IN_ANOTHER_GROUP/GROUP_DISPATCH_INVALID) | + +#### 请求示例 + +```http +GET /admin/fleet/group-dispatch/batches/8801/share-member-candidates?serviceDate=2026-09-12&resourceType=VEHICLE&resourceId=1 +``` + +#### 响应示例 + +```json +{ + "code": 200, + "message": "成功", + "success": true, + "data": [ + { + "sourceType": "ASSIGNMENT", + "sourceId": "88001", + "orderId": "70123", + "orderNo": "26-0503", + "teamNo": "26-0480", + "groupCode": "G1", + "occupying": true, + "selectable": true, + "unselectableReason": null + } + ] +} +``` + +#### 空数据 / 降级响应 + +无候选时返回空数组: + +```json +{ + "code": 200, + "message": "成功", + "success": true, + "data": [] +} +``` + +#### 错误响应 + +```json +{ + "code": 602104, + "message": "服务日不在团期服务日窗内", + "success": false, + "data": null +} +``` + +#### 业务边界 + +- `teamNo` 来自派单表快照,无团号为 null;`groupCode` 是车务内部分组编码,与团号是两个不同字段。 +- `resourceId` 未传时 `occupying`/`selectable` 恒为 null(未判定),不得当作 false 处理。 +- `selectable=true` 不是提交必成功的承诺:候选清单是时点快照不加锁,提交时仍可能撞 602106,应提示「有人先一步占了,请刷新候选清单重选」而非当系统故障重试。 + +--- + +### 8. 司机险保单分页(新路径) `POST /admin/fleet/insurance/driver-policies/page` + +**VO**: `FleetInsurancePolicyPageReqVO → FleetDriverInsurancePolicyPageRespVO` + +#### 使用场景 + +车队保险菜单「保单」Tab 主链,查询司机险保单(`insurance_order.bizType=DRIVER`,含手动投保);保单关联派单新增 `teamNo`,车队按团号索引。 + +#### 入参 + +| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | +|------|------|------|------|------|------| +| `page` | Body | Integer | ❌ | 默认 1,≥1 | 页码 | +| `pageSize` | Body | Integer | ❌ | 默认 20,1-100 | 每页行数 | +| `keyword` | Body | String | ❌ | — | 司机姓名/订单号模糊 | +| `driverId` | Body | Long(字符串) | ❌ | — | 司机 ID,精确 | +| `policyNo` | Body | String | ❌ | — | 保单号,精确 | +| `status` | Body | String | ❌ | PENDING/INSURING/INSURED/CANCELLED/FAILED | 保单状态 | +| `source` | Body | String | ❌ | BAOYOU/MANUAL | 投保来源 | +| `planId` | Body | Long(字符串) | ❌ | — | 保险计划 ID | +| `coverageStartDate` | Body | LocalDate | ❌ | 不可与 `coverageStartDateFrom` 混传 | 保障起期下界(新字段) | +| `coverageEndDate` | Body | LocalDate | ❌ | 同上 | 保障止期上界(新字段) | +| `serviceDate` | Body | LocalDate | ❌ | — | 覆盖某服务日 | +| `orderId` | Body | Long(字符串) | ❌ | — | 订单 ID,精确 | +| `assignmentId` | Body | Long(字符串) | ❌ | — | 派单 ID,经派单表关联 | +| `pendingOnly` | Body | Boolean | ❌ | — | 只看存在 PENDING/PROCESSING 异常任务的保单 | + +#### 出参 + +| 字段 | 类型 | 说明 | +|------|------|------| +| `page` / `pageSize` / `total` | Integer / Integer / long | 分页信息 | +| `records[]` | List | 保单行数组 | +| `records[].insuranceOrderId` | String(Long) | 保险单 ID | +| `records[].policyNo` | String | 保单号 | +| `records[].linkedAssignments[]` | List | 关联派单列表 | +| `records[].linkedAssignments[].assignmentId` | String(Long) | 派单 ID | +| `records[].linkedAssignments[].orderNo` | String | 关联派单所属订单号 | +| `records[].linkedAssignments[].teamNo` | String | **【新增】** 关联派单的团号,无团号为 null | + +#### 请求示例 + +```json +{ + "page": 1, + "pageSize": 20, + "status": "INSURED" +} +``` + +#### 响应示例 + +```json +{ + "code": 200, + "message": "成功", + "success": true, + "data": { + "page": 1, + "pageSize": 20, + "total": 1, + "records": [ + { + "insuranceOrderId": "1934567890123456999", + "policyNo": "POL20260901001", + "linkedAssignments": [ + { + "assignmentId": "1934567890123456901", + "orderNo": "HL20260705001", + "teamNo": "26-0480" + } + ] + } + ] + } +} +``` + +#### 空数据 / 降级响应 + +无保单时返回空 `records`: + +```json +{ + "code": 200, + "message": "成功", + "success": true, + "data": { + "page": 1, + "pageSize": 20, + "total": 0, + "records": [] + } +} +``` + +#### 错误响应 + +`coverageStartDate`/`coverageEndDate` 与旧字段 `coverageStartDateFrom`/`coverageStartDateTo` 混传: + +```json +{ + "code": 100001, + "message": "参数非法", + "success": false, + "data": null +} +``` + +#### 业务边界 + +- `teamNo` 只在有关联派单时才有意义;保单可能无关联派单,此时 `linkedAssignments` 为空列表。 +- `teamNo` 来自派单表快照,无团号为 null,不回落订单号。 +- 本路径**只接受**新字段 `coverageStartDate`/`coverageEndDate`;旧字段仅接口 9 的旧路径接受,两套混传返 100001。 +- 同路径 `GET /admin/fleet/insurance/driver-policies/page` 恒返回 405 Method Not Allowed(内部路由守卫,防止与详情模板 `/driver-policies/{insuranceOrderId}` 冲突),本接口必须用 POST。 + +--- + +### 9. 司机险保单分页(旧路径,已弃用) `GET /admin/fleet/insurance/policies` + +**VO**: `FleetInsurancePolicyPageReqVO → FleetDriverInsurancePolicyPageRespVO` + +#### 使用场景 + +`@Deprecated` 旧兼容路径(#4760 时代偏离路径,仅存量调用使用,后续下线),响应结构与接口 8 完全相同;关联派单新增 `teamNo`。新对接一律使用接口 8。 + +#### 入参 + +| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | +|------|------|------|------|------|------| +| `page` | Query | Integer | ❌ | 默认 1,≥1 | 页码 | +| `pageSize` | Query | Integer | ❌ | 默认 20,1-100 | 每页行数 | +| `coverageStartDateFrom` | Query | LocalDate | ❌ | 仅本路径接受,不可与 `coverageStartDate` 混传 | 保障起期下界(旧字段,按 startDate 过滤) | +| `coverageStartDateTo` | Query | LocalDate | ❌ | 同上 | 保障起期上界(旧字段) | +| 其余筛选字段 | Query | — | ❌ | — | 与接口 8 同语义(keyword/driverId/policyNo/status/source/planId/orderId/assignmentId/pendingOnly 等) | + +#### 出参 + +(结构与接口 8 完全相同) + +| 字段 | 类型 | 说明 | +|------|------|------| +| `records[].linkedAssignments[].teamNo` | String | **【新增】** 关联派单的团号,无团号为 null | + +#### 请求示例 + +```http +GET /admin/fleet/insurance/policies?page=1&pageSize=20&coverageStartDateFrom=2026-09-01&coverageStartDateTo=2026-09-30 +``` + +#### 响应示例 + +```json +{ + "code": 200, + "message": "成功", + "success": true, + "data": { + "page": 1, + "pageSize": 20, + "total": 1, + "records": [ + { + "insuranceOrderId": "1934567890123456999", + "linkedAssignments": [ + { "assignmentId": "1934567890123456901", "teamNo": "26-0480" } + ] + } + ] + } +} +``` + +#### 空数据 / 降级响应 + +无保单时返回空 `records`(结构与接口 8 相同): + +```json +{ + "code": 200, + "message": "成功", + "success": true, + "data": { "page": 1, "pageSize": 20, "total": 0, "records": [] } +} +``` + +#### 错误响应 + +本路径只接受旧字段 `coverageStartDateFrom`/`coverageStartDateTo`;传入新字段 `coverageStartDate`/`coverageEndDate` 混传: + +```json +{ + "code": 100001, + "message": "参数非法", + "success": false, + "data": null +} +``` + +#### 业务边界 + +- `teamNo` 来自派单表快照,无团号为 null;语义与接口 8 完全一致。 +- 本路径已 `@Deprecated`,仅存量调用使用;新对接请用接口 8 的 POST 路径。 + +--- + +### 10. 保险单详情 `GET /admin/fleet/insurance/driver-policies/{insuranceOrderId}` + +**VO**: `FleetDriverInsurancePolicyDetailRespVO` + +#### 使用场景 + +查询司机险保单详情页;关联派单新增 `teamNo`。旧路径 `GET /admin/fleet/insurance/policies/{insuranceOrderId}` 是同一方法的兼容别名,行为完全相同。 + +#### 入参 + +| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | +|------|------|------|------|------|------| +| `insuranceOrderId` | Path | Long | ✅ | 正整数 | 保险单 ID | + +#### 出参 + +| 字段 | 类型 | 说明 | +|------|------|------| +| `insuranceOrderId` | String(Long) | 保险单 ID | +| `policyNo` | String | 保单号 | +| `status` | String | 保单状态 | +| `linkedAssignments[]` | List | 关联派单列表 | +| `linkedAssignments[].assignmentId` | String(Long) | 派单 ID | +| `linkedAssignments[].orderNo` | String | 关联派单所属订单号 | +| `linkedAssignments[].teamNo` | String | **【新增】** 关联派单的团号,无团号为 null | + +#### 请求示例 + +```http +GET /admin/fleet/insurance/driver-policies/1934567890123456999 +``` + +#### 响应示例 + +```json +{ + "code": 200, + "message": "成功", + "success": true, + "data": { + "insuranceOrderId": "1934567890123456999", + "policyNo": "POL20260901001", + "status": "INSURED", + "linkedAssignments": [ + { + "assignmentId": "1934567890123456901", + "orderNo": "HL20260705001", + "teamNo": "26-0480" + } + ] + } +} +``` + +#### 空数据 / 降级响应 + +保单无关联派单时 `linkedAssignments` 为空列表: + +```json +{ + "code": 200, + "message": "成功", + "success": true, + "data": { + "insuranceOrderId": "1934567890123456999", + "policyNo": "POL20260901001", + "status": "PENDING", + "linkedAssignments": [] + } +} +``` + +#### 错误响应 + +```json +{ + "code": 540501, + "message": "保单不存在或非司机险", + "success": false, + "data": null +} +``` + +其余业务码:100901 Feign 协议空数据(保险服务返回 success(null)) / 605601 保险服务不可用。 + +#### 业务边界 + +- `teamNo` 来自派单表快照,无团号为 null,不回落订单号。 +- `540501` 是保险服务(order)侧的权威码原样透传,不是 fleet 自定义码。 +- 快照为 null 的三类情形同接口 1。 + +--- + +### 11. 关账后变更补偿列表 `GET /admin/fleet/reconciliation/pending-compensations` + +**VO**: `ReconPendingCompPageReqVO → ReconPendingCompRespVO` + +#### 使用场景 + +财务查询「关账后 prep 变更待人工对账」列表:派单域在已关账期内发生变更(生成/反标/重激活/截断)时落下的补偿记录,人工核对补对账后 resolve 闭环。**不是应收对账**,本次同时订正命名。新增 `teamNo` 便于财务按团号核对。 + +#### 入参 + +| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | +|------|------|------|------|------|------| +| `page` | Query | Integer | ❌ | 默认 1,≥1 | 页码 | +| `pageSize` | Query | Integer | ❌ | 默认 20,1-100 | 每页行数 | +| `status` | Query | String | ❌ | PENDING/RESOLVED,默认 PENDING | 处置状态 | +| `periodLabel` | Query | String | ❌ | 自然月 YYYY-MM | 触及的已关账期 | +| `opType` | Query | String | ❌ | GENERATE/INVALIDATE/REACTIVATE/TRUNCATE/INSURANCE | 变更类型 | + +#### 出参 + +| 字段 | 类型 | 说明 | +|------|------|------| +| `page` / `pageSize` / `total` | int / int / int | 分页信息 | +| `records[]` | List | 补偿记录数组(按落账时间倒序) | +| `records[].compId` | String(Long) | 补偿记录 ID | +| `records[].assignmentId` | String(Long) | 触发变更的派单 ID | +| `records[].orderId` | String(Long) | 订单 ID,可空 | +| `records[].teamNo` | String | **【新增】** 团号,无团号为 null | +| `records[].periodLabel` | String | 触及的已关账期(自然月) | +| `records[].opType` | String | 变更类型(GENERATE=生成/INVALIDATE=反标/REACTIVATE=重激活/TRUNCATE=截断) | +| `records[].reason` | String | 补偿原因 | +| `records[].status` | String | 处置状态(PENDING=待人工对账/RESOLVED=已处置) | +| `records[].createTime` | LocalDateTime | 落账时间 | + +#### 请求示例 + +```http +GET /admin/fleet/reconciliation/pending-compensations?page=1&pageSize=20&status=PENDING +``` + +#### 响应示例 + +```json +{ + "code": 200, + "message": "成功", + "success": true, + "data": { + "page": 1, + "pageSize": 20, + "total": 1, + "records": [ + { + "compId": "1234567890123456789", + "assignmentId": "9001000000000000001", + "orderId": "5001000000000000001", + "teamNo": "26-0480", + "periodLabel": "2026-05", + "opType": "GENERATE", + "reason": "confirm 生成 prep 触及已关账期 2026-05,3 个服务日成本未落账", + "status": "PENDING", + "createTime": "2026-06-23 10:00:00" + } + ] + } +} +``` + +#### 空数据 / 降级响应 + +无待处置记录时返回空 `records`: + +```json +{ + "code": 200, + "message": "成功", + "success": true, + "data": { "page": 1, "pageSize": 20, "total": 0, "records": [] } +} +``` + +#### 错误响应 + +```json +{ + "code": 100001, + "message": "参数非法", + "success": false, + "data": null +} +``` + +#### 业务边界 + +- `teamNo` 按 `assignmentId` 批量取派单表快照,无团号为 null,不回落订单号,也不给空串。 +- 响应**没有金额字段**:本列表只记「触及哪期、何种变更、何时落账」,不是应收金额对账单。 +- 快照为 null 的三类情形同接口 1;订单尚无团号时该记录同样列入待处置,不会被过滤掉。 + +--- + +### 12. 矩阵主数据(网格) `GET /admin/fleet/matrix/grid` + +**VO**: `MatrixGridReqVO → MatrixGridRespVO`(连线 `MatrixConnectionVO`) + +#### 使用场景 + +车队月视图甘特排盘主战场:拉某月车辆×日期矩阵,含每辆车的常驻司机、本月派单段与衔接判断。连线新增 `fromTeamNo`/`toTeamNo`,调度按团号识别衔接的前后订单。 + +#### 入参 + +| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | +|------|------|------|------|------|------| +| `year` | Query | Integer | ✅ | 非空 | 年 | +| `month` | Query | Integer | ✅ | 非空,1-12 | 月,越界抛 605010 | +| `season` | Query | String | ❌ | active/pending/archived/blacklist,默认 active | 车辆状态筛选 | +| `fleetTeamIds` | Query | Long[] | ❌ | — | 车队 ID 筛选 | +| `typeKeys` | Query | String[] | ❌ | suv/mpv/bus/sedan | 车型筛选 | +| `statuses` | Query | String[] | ❌ | — | 精确多选派单状态,优先于 `status` | + +(无 `groupBatchId`/`serviceDate`;本接口按月拉取,不按团期或单日筛选。) + +#### 出参 + +| 字段 | 类型 | 说明 | +|------|------|------| +| `vehicles[]` | List | 行(车辆)数组 | +| `vehicles[].assignments[]` | List | 该车本月派单段 | +| `connections[]` | List | 相邻派单段的衔接连线数组 | +| `connections[].fromOrderNo` | String | 前一订单号 | +| `connections[].toOrderNo` | String | 后一订单号 | +| `connections[].fromTeamNo` | String | **【新增】** 前一订单团号,无团号为 null(优先取订单当前值,为空回落派单快照) | +| `connections[].toTeamNo` | String | **【新增】** 后一订单团号,无团号为 null(同上) | +| `connections[].connectionMinutes` | Long | 衔接间隔分钟数,可空 | +| `connections[].status` | String | 衔接状态 | + +#### 请求示例 + +```http +GET /admin/fleet/matrix/grid?year=2026&month=10&season=active +``` + +#### 响应示例 + +```json +{ + "code": 200, + "message": "成功", + "success": true, + "data": { + "vehicles": [ + { "vehicleId": "1934567890123456702", "plate": "蒙A-88888" } + ], + "connections": [ + { + "fromOrderNo": "26-0501", + "toOrderNo": "26-0502", + "fromTeamNo": "26-0480", + "toTeamNo": "26-0481", + "connectionMinutes": 90, + "status": "OK" + } + ] + } +} +``` + +#### 空数据 / 降级响应 + +该月无派单时 `vehicles`/`connections` 为空列表: + +```json +{ + "code": 200, + "message": "成功", + "success": true, + "data": { "vehicles": [], "connections": [] } +} +``` + +#### 错误响应 + +```json +{ + "code": 605010, + "message": "月份超出范围", + "success": false, + "data": null +} +``` + +该码是 `year`/`month` 越界,与接口 4「团期配车基线不可达」(600012) 不是同一个错误码,不要混用。 + +#### 业务边界 + +- `fromTeamNo`/`toTeamNo` 优先取订单服务实时值,为空回落派单表快照。 +- 本接口是排班/甘特视图,不是对账矩阵;连线的 `connectionMinutes` 是衔接时间判断,不是成本或应收字段。 +- 快照回落时为 null 的三类情形同接口 1;订单实时值同样可能为 null(团号尚未生成)。 + +--- + +### 13. H5 行程 `GET /app/h5/itinerary/{token}` + +**VO**: `ItineraryH5RespVO` + +#### 使用场景 + +司机通过 H5 短链查看电子行程单,公开端点、无 JWT(Gateway 已配免鉴权白名单),token 由服务端无状态验签+过期自校验。响应新增 `teamNo`,司机按团号与导游/计调对口。 + +#### 入参 + +| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | +|------|------|------|------|------|------| +| `token` | Path | String | ✅ | 非空 | 行程签名串 | + +#### 出参 + +| 字段 | 类型 | 说明 | +|------|------|------| +| `orderId` | String | 订单号字符串(取派单快照 `order_no`,非雪花 ID),示例 `HL20260516143052999` | +| `teamNo` | String | **【新增】** 团号,无团号为 null(优先取订单当前值,为空回落派单快照) | +| `theme` | String | 行程主题 | +| `dateRange` | String | 行程日期区间 | +| `days` | Integer | 行程天数 | +| `headcount` | Integer | 出行人数 | +| `customer` | String | 客户(团称化,非真实姓名) | +| `contactName` | String | 联系人真实姓名 | +| `contactPhone` | String | 联系人真实电话(非脱敏) | +| `vehicle` | Object | 车辆信息(`plate`/`model`/`seats`) | +| `driver` | Object | 司机信息(`name`/`phoneMasked`) | +| `daily[]` | List | 逐日行程 | +| `expireAt` | OffsetDateTime | 链接过期时间 | + +#### 请求示例 + +```http +GET /app/h5/itinerary/eyJhbGciOiJIUzI1NiJ9... +Accept: application/json +``` + +#### 响应示例 + +```json +{ + "code": 200, + "message": "成功", + "success": true, + "data": { + "orderId": "HL20260516143052999", + "teamNo": "26-0480", + "theme": "内蒙草原五日游", + "dateRange": "2026-10-01至2026-10-05", + "days": 5, + "headcount": 3, + "customer": "赵先生一行", + "contactName": "赵先生", + "contactPhone": "13800001234", + "vehicle": { "plate": "蒙A-88888", "model": "别克GL8", "seats": 7 }, + "driver": { "name": "王师傅", "phoneMasked": "138****1234" }, + "daily": [ + { "dayNumber": 1, "date": "2026-10-01", "title": "抵达", "detail": "接机后入住酒店" } + ], + "expireAt": "2026-10-06T00:00:00+08:00" + } +} +``` + +#### 空数据 / 降级响应 + +本接口 HTTP 恒 200,无「空数据」态;token 无效/过期/订单不存在按下方错误响应处理,`data` 为 null。 + +#### 错误响应 + +```json +{ + "code": 605306, + "message": "链接无效", + "success": false, + "data": null +} +``` + +其余业务码:605307 链接已过期 / 605308 订单不存在或未派车。 + +#### 业务边界 + +- `teamNo` 优先从订单服务实时查询当前值,为空才回落派单表快照 `team_no`;一旦生成不会改号。 +- `orderId` 字段本身是订单号字符串(非雪花 ID),不要与团号的 `NN-NNNN` 形态混淆——两者都可能是 `26-xxxx` 形态,只能按字段名区分。 +- 快照回落为 null 的三类情形同接口 1。 +- 司机 H5 的链接有效期受 token 签名控制,与团号生成时机无关。 +- 同一路径按 `Accept` 分流:请求头带 `Accept: application/json` 才返回本 JSON 契约;浏览器直接打开(`Accept: text/html`)返回 fleet 内置的只读页 `h5/itinerary.html`,该页加载后再以 `Accept: application/json` 同源请求本路径取数。 +- 内置只读页当前不展示 `teamNo`,本次只在 JSON 响应里新增字段。 + +--- + +## 四、契约约束与正确调用方式 + +所有 13 个接口的路径、请求参数、错误码、HTTP 方法均未变,仅响应体新增字段。 + +- **新增字段**: 类型均为 String,可为 null,无默认值。 +- **调用无需适配**: 现有调用方无需改变请求参数或处理逻辑。 +- **响应结构兼容**: 新字段为 additive,不影响既有字段的反序列化。 +- **入参校验规则不变**: 所有写接口的入参校验、业务规则、权限控制保持原样。 + +--- + +## 五、数据库行为 + +无数据库表结构变更。所有新增字段从现有表 `fleet_assignment.team_no`(派单快照)或订单服务实时值读取,不新增列。 + +--- + +## 六、边界行为 + +### 团号的两个来源 + +1. **派单快照** (`fleet_assignment.team_no`):建行时写入,代表派单创建那一刻订单的团号。之后不刷新,即使订单团号改变(实际上不会改变)快照仍保持原值。 + - 来源接口:预检冲突项、需求驳回、自动推荐、共用关系成员、H5 行程(回落)、保险任务、关账后变更补偿列表、矩阵网格(回落)。 +2. **订单实时值**:从订单服务查询订单的当前 `team_no`,反映订单的最新状态。 + - 来源接口:分组派车总览、H5 行程(优先)、矩阵网格(优先)。 + +### 何时为 null + +新增的 `teamNo` / `costBearerTeamNo` / `fromTeamNo` / `toTeamNo` 字段在以下情况为 null: + +- **建行时订单无团号**:派单创建之初,订单还未收款不生成团号,快照留 null;后续该订单若生成团号也不会自动更新快照。 +- **本字段上线前的存量派单**:库中已有的历史派单,未经本次更新,仍无此字段。 +- **车务在管理端手工新建的派单**:建行时未关联到已有团号的订单。 + +### 订单实时值与快照不一致时 + +对于优先级为「订单实时」的接口(分组派车总览、H5 行程、矩阵网格): + +- 若订单当前有团号,返回当前值(已生成的号永不改变)。 +- 若订单当前无团号,回落派单快照(可能为 null)。 +- **前端不需要处理两个值的转换**,返回的 `teamNo` 字段已是最终展示值。 + +### 快照只读,不会给出错号 + +派单表 `team_no` 列是建行时的一次性写入,之后被读取不被改写: + +- 不会出现「派单团号与订单不符」的情况(快照代表建行那一刻,之后订单不改号)。 +- 建行时订单无团号,快照就是 null;后来订单生成号了,快照仍是 null(不自动补)。 + +--- + +## 六.6、修改前后对比 + +| 维度 | 改前 | 改后 | 影响 | +|------|------|------|------| +| 派单预检冲突项 | `conflictAssignmentId` / `conflictOrderNo` | 新增 `conflictTeamNo` | 车务可按团号快速辨认冲突派单 | +| 共用关系响应 | 仅含 `members[].orderId` | 新增 `members[].teamNo` 与 `costBearerTeamNo` | 财务可按团号核对成本承担方及成员 | +| 矩阵主数据(网格) | 连线无订单身份 | 新增 `fromTeamNo` / `toTeamNo` | 调度按团号识别衔接的前后订单,不涉及成本 | +| H5 行程 | 仅含订单号 | 新增 `teamNo` | 司机行程页可显示团号 | +| 保险任务派单 | 无派单链接 | 新增 `linkedAssignments[].teamNo` | 车队按团号索引保单关联的派单 | + +--- + +## 六.7、影响评估 + +### 前端改动 + +1. **派单预检**(接口 1):冲突项新增 `conflictTeamNo` 展示列。 +2. **需求驳回**(接口 2):响应新增 `teamNo`,无需改交互。 +3. **槽位自动推荐**(接口 3):响应新增 `teamNo`;该接口只读,不产生写操作,车务确认后仍需另调派车接口手动提交,前端不要把它当成「一键生成派单」。 +4. **共用关系查询/确认**(接口 5/6):共用关系卡片新增 `costBearerTeamNo` 显示,成员表格新增 `teamNo` 列。 +5. **共用成员候选**(接口 7):新增 `teamNo` 列展示;**`groupCode` 注解订正**——前端若曾用此字段展示为「团号」,请改用 `teamNo`,`groupCode` 是车务分组编码(如 G1),与团号不同。 +6. **分组派车总览**(接口 4):订单行新增 `teamNo` 列。 +7. **司机险保单分页/详情**(接口 8/9/10):关联派单列表新增 `teamNo` 列。 +8. **关账后变更补偿列表**(接口 11,原「应收对账」入口更名):记录新增 `teamNo` 列;该列表不含金额字段。 +9. **矩阵主数据(网格)**(接口 12):连线新增起点/终点团号 `fromTeamNo`/`toTeamNo`。 +10. **H5 行程**(接口 13):行程新增团号显示。 + +### 后端改动 + +- hl-fleet-service 13 个 controller 接口响应的 VO 新增字段。 +- hl-common-core `OrderVehicleCoverageItemDTO` 新增字段,order-v3 的 `GroupBatchVehicleDispatchQueryService` 调用共用 DTO 时赋值。 +- `OrderVehicleCoverageItemDTO` 的消费方只有 fleet 与 order-v3,两者已同批部署。 + +### 部署顺序 + +- hl-common-core 新增字段后,order-v3 与 fleet 必须在同一批部署(CODE_RULES §16.6)。 + +--- + +## 七、不影响范围 + +- 团期导出、司机批量导入、车辆信息等不含派单主体的接口无改动。 +- `/admin/fleet/matrix/month-counts` 不含连线结构,无 `teamNo` 字段。 +- 派单 ID、订单 ID、订单号的业务逻辑及错误码均不变。 +- 新增字段无统一命名:具体为 `teamNo` / `conflictTeamNo` / `costBearerTeamNo` / `fromTeamNo` / `toTeamNo`,前端按 `*TeamNo`/`*teamNo` 模式搜索即可覆盖全部 13 个接口。 + +--- + +## 八、测试环境已验证 + +- hl-common-core 全量单测:546 run / 0 失败 / 0 错误。 +- hl-fleet-service 全量单测:4829 run / 0 失败 / 6 跳过(既有 MySQL 故障注入条件跳过,与本单无关)。 +- order-v3 定向单测(涉改动类及 ArchTest):87 run / 0 失败 / 0 错误。 +- fleet 定向单测(11 个改动类):851 run / 0 失败。 +- spotless:check 通过。 +- 网关实测(2026-09-27 12:20 前后,测试服 fleet 与 order-v3 均为 `c5027d809`,经 `https://api.test.1814.love`,非 admin 测试账号):6 个接口共 7 次请求,全部 HTTP 200 / 业务码 200,团号逐条对库一致。 + - 接口 4 分组派车总览:2 个订单的 `teamNo` 与 `order_main.team_no` 一致(26-9478、26-6601),验证了 order-v3 → common DTO → fleet 的跨服务链路。 + - 接口 5 共用关系查询(2 个批次,2 次请求):`costBearerTeamNo` 与成员 `teamNo` 共 4 个值与库一致。 + - 接口 7 共用成员候选:2 个候选的 `teamNo` 与派单行一致(26-4002、26-1125)。 + - 接口 9 司机险保单(旧路径):`linkedAssignments` 34 条去重后 7 个派单,`teamNo` 与 `fleet_assignment.team_no` 逐个一致;其中 1 个为 null,其订单在 `order_main` 里同样没有团号。 + - 接口 11 关账后变更补偿列表:抽 6 条对 `fleet_assignment.team_no` 全部一致;另有 2 条为 null,其引用的派单行与订单行在库里已不存在。 + - 接口 12 矩阵网格:48 条连线带团号,抽 7 条对 `order_main` 全部一致。 + - 「派单快照为 null、订单却已有团号」的覆盖边界本轮取样 0 例。 + - 接口 1/2/3/6/8/10/13 本轮未经网关实测,由 fleet 定向单测覆盖(每个装配点都有「有团号」与「null」两支)。 + +--- + +## 十、相关文档 + +- 工单 #8408:车务响应体补团号(PR-4 车务部分) +- 工单 #8401:房务配房台账联动(已合入,涉及派单预检回调 808188) +- PR #8419:车务派单响应补团号(本 PR) +- PR #8415:order-v3 transition 补团号(A 部分,已合入) + +--- + +## 关联 / 联系人 + +**工单**: [wx/HL#8408](https://git.1814.love:8443/wx/HL/issues/8408) + +**PR**: [wx/HL#8419](https://git.1814.love:8443/wx/HL/pulls/8419) + +**管理后台对接**: mmg (hl-ui) + +**H5 行程对接**: 页面是 fleet 内置静态页(`hl-fleet-service/src/main/resources/h5/itinerary.html`),没有独立的前端工程;JSON 契约供需要按团号展示行程的调用方使用