hl-api-changelog/changelogs-v2/2026-07/62_4938_车务最终确认订单调整基线差异-修改接口-管理后台.md
2026-07-19 02:20:37 +08:00

18 KiB

【#4938 前端对接·管理后台】车务创建、修改与最终确认返回订单调整基线差异

Issue: wx/HL#4938

PR: wx/HL#5065

服务: hl-fleet-service

日期: 2026-07-18

影响范围: 车务直接派车、直接改派、holding → assigned 最终确认,以及订单调整后的日期、人数、车辆容量差异处理

状态: 后端已合并并部署测试环境;待管理后台按本文完成页面联调

一、前端对接结论

以下三个既有管理后台接口现在共用业务码 605041 返回结构化逐日差异:

操作 接口 触发 605041 的条件
创建派单 POST /admin/fleet/assignments holdMode=0 直接派车时最终基线不一致
修改派单 POST /admin/fleet/assignments/{assignmentId}/change holdMode=0 直接改派时最终基线不一致
最终确认 POST /admin/fleet/assignments/{assignmentId}/confirm 订单、需求、行程、逐日派单、人数或容量基线不一致

前端必须遵守以下判断:

  1. 三个接口的 605041 当前均返回 HTTP 200,但统一响应体为 code=605041success=false,不能只判断 HTTP 状态。
  2. 605041data 不为空:
    • create 返回 AssignmentWriteRespVO,保证 data.dailyDifferences 可读;
    • change 返回 ChangeAssignmentRespVO,保证 data.dailyDifferences 可读;
    • confirm 返回 ConfirmRespVO,保证 data.confirmed=falsedata.dailyDifferences 可读。
  3. 605041 不会提交派单及其关联业务状态写入:
    • create 不会新增或激活派单;
    • change 不会取消旧派单,也不会生成可用的新派车版本;
    • confirm 不会推进派单状态或确认时间;
    • 三者都不会触发车辆/司机占用、保险、对账或订单派定结果变化。
    • change 仍会按既有设计在独立事务保留一条 CHANGE_FAILED 操作审计;它不是有效派单版本,也不表示业务写入成功。
  4. 收到 605041 后保持操作前页面状态,展示逐日差异,并重新拉取最新订单和车务详情。
  5. 所有派单、车辆槽位、派车组、订单、车辆和司机雪花 ID 均按 JSON String 发送和读取,禁止转为 JavaScript Number。金额字段也按 String 读取。

二、605041 公共响应契约

2.1 统一响应外层

{
  "code": 605041,
  "message": "订单行程或用车派单已变化,请按逐日差异处理后重试",
  "data": {
    "dailyDifferences": [
      {
        "serviceDate": "2026-07-22",
        "differenceType": "CAPACITY_INSUFFICIENT",
        "assignmentId": null,
        "assignmentSlotId": null,
        "passengerCount": 8,
        "passengerCapacity": 5,
        "capacityGap": 3,
        "message": "车辆载客量不足,已按每车司机占一座计算"
      }
    ]
  },
  "traceId": "7db459fd-0b8e-4f29-9c46-4938f09a001",
  "success": false
}

注意:

  • data 的完整类型取决于调用的是 create、change 还是 confirm,不能跨接口复用成功响应模型。
  • 除本文件明确保证的失败字段外,其余成功态字段在 605041 时为空,前端不得用它们推断写入结果。
  • traceId 用于反馈和日志定位,不参与业务判断。

2.2 dailyDifferences[]

字段 类型 说明
serviceDate String/null 发生差异的服务日,格式 yyyy-MM-dd;无法定位到单日时为空
differenceType String 差异类型,取值见下表
assignmentId String/null 可定位到具体派单时返回;仅用于定位差异,不代表本次写入成功
assignmentSlotId String/null 可定位到稳定车辆槽位时返回
passengerCount Integer/null 当前比对使用的乘客人数,不含司机
passengerCapacity Integer/null 当日车辆合计可载客人数,每辆车已扣除司机一座
capacityGap Integer/null 缺少座位数,等于 passengerCount - passengerCapacity
message String 后端生成的差异说明,可直接辅助展示

差异类型:

differenceType 含义
REQUIREMENT_VERSION_MISMATCH 当前生效用车需求已变化,或订单/需求已不可继续派单
ORDER_DATE_MISMATCH 订单当前日期与用车需求冻结日期不一致
ITINERARY_DATE_MISMATCH 逐日行程日期与用车需求冻结日期不一致,或缺少逐日行程
ASSIGNMENT_DATE_MISSING 某服务日缺少有效派单或车辆槽位
ASSIGNMENT_DATE_EXTRA 派单仍包含已不属于当前需求的服务日
HEADCOUNT_BASELINE_MISMATCH 订单当前人数、需求冻结人数或派单人数快照不一致
CAPACITY_INSUFFICIENT 当日所有车辆合计载客量不足

dailyDifferences 可能同时包含多种类型、多条服务日记录。前端应遍历数组展示,不得只取第一条,也不得自行重算人数或车辆容量。

三、创建派单 create

3.1 请求

POST /admin/fleet/assignments
Authorization: Bearer <admin-token>
Content-Type: application/json
{
  "orderId": "2078001000000000101",
  "orderNo": "26-0719",
  "requirementId": "2078001000000000201",
  "fleetItemIndex": 1,
  "vehicleId": "2078001000000000301",
  "driverId": "2078001000000000401",
  "startDate": "2026-07-21",
  "endDate": "2026-07-23",
  "pickupAt": "海拉尔",
  "dropoffAt": "满洲里",
  "headcount": 8,
  "protocolPrice": "1300.00",
  "holdMode": 0,
  "fromEntry": "from-board",
  "skipCityJunctionException": false,
  "strictSeats": true,
  "confirmCrossResident": false,
  "requestId": "fleet-create-4938-20260719-001"
}

605041 只适用于 holdMode=0。原有 holdMode=1 排车锁定流程不执行本次最终基线门禁。

3.2 holdMode=0 成功响应

{
  "code": 200,
  "message": "成功",
  "data": {
    "id": "2078001000000000501",
    "assignmentGroupId": "2078001000000000601",
    "assignmentSlotId": "2078001000000000701",
    "assignmentStatus": "assigned",
    "stageCode": "assigned",
    "stageLabel": "已派车",
    "currentStep": 4,
    "skippedStepCodes": [
      "DRIVER_CONFIRMATION",
      "DRIVER_CONFIRMATION_EVIDENCE"
    ],
    "protocolPrice": "1300.00",
    "holdSentAt": null,
    "confirmedAt": "2026-07-19 14:20:00",
    "sideEffects": {
      "vehicleStatusUpdated": "busy",
      "driverStatusUpdated": "busy",
      "reconPrepRowsCreated": 0,
      "reconPrepMarkedCanceled": null
    },
    "dailyDifferences": null
  },
  "traceId": "7db459fd-0b8e-4f29-9c46-4938c200001",
  "success": true
}

仅在 code=200 时把新派单加入页面;idassignmentGroupIdassignmentSlotId 均按 String 保存。

3.3 605041 失败响应

{
  "code": 605041,
  "message": "订单行程或用车派单已变化,请按逐日差异处理后重试",
  "data": {
    "id": null,
    "assignmentGroupId": null,
    "assignmentSlotId": null,
    "assignmentStatus": null,
    "stageCode": null,
    "stageLabel": null,
    "currentStep": null,
    "skippedStepCodes": null,
    "protocolPrice": null,
    "holdSentAt": null,
    "confirmedAt": null,
    "sideEffects": null,
    "dailyDifferences": [
      {
        "serviceDate": "2026-07-22",
        "differenceType": "CAPACITY_INSUFFICIENT",
        "assignmentId": null,
        "assignmentSlotId": null,
        "passengerCount": 8,
        "passengerCapacity": 5,
        "capacityGap": 3,
        "message": "车辆载客量不足,已按每车司机占一座计算"
      }
    ]
  },
  "traceId": "7db459fd-0b8e-4f29-9c46-4938c605041",
  "success": false
}

此时不得把临时响应内容加入派单列表,不得本地占用车辆/司机;刷新后仍以服务端最新详情为准。

四、修改派单 change

4.1 请求

POST /admin/fleet/assignments/2078001000000000501/change
Authorization: Bearer <admin-token>
Content-Type: application/json
{
  "effectiveDate": "2026-07-22",
  "newVehicleId": "2078001000000000302",
  "newDriverId": "2078001000000000402",
  "holdMode": 0,
  "protocolPrice": "1688.00",
  "confirmCrossResident": false,
  "reason": "订单调整后更换车辆和司机",
  "requestId": "fleet-change-4938-20260719-001"
}

newVehicleIdnewDriverId 至少传一个。605041 只适用于 holdMode=0holdMode=1 仍按排车待司机确认流程处理。

4.2 holdMode=0 成功响应

{
  "code": 200,
  "message": "成功",
  "data": {
    "assignmentId": "2078001000000000502",
    "assignmentSlotId": "2078001000000000701",
    "previousAssignmentGroupId": "2078001000000000601",
    "newAssignmentGroupId": "2078001000000000602",
    "assignmentStatus": "assigned",
    "effectiveDate": "2026-07-22",
    "affectedDays": 2,
    "protocolPrice": "1688.00",
    "otherVehicleCount": 1,
    "warningCode": "ORDER_HAS_OTHER_VEHICLES",
    "warningMessage": "该订单另有1个车辆槽位,当前仅修改本车辆,请核对其它车辆安排",
    "otherVehicles": [
      {
        "assignmentSlotId": "2078001000000000702",
        "vehiclePlate": "蒙B-66666",
        "driverName": "李师傅",
        "startDate": "2026-07-21",
        "endDate": "2026-07-23"
      }
    ],
    "dailyDifferences": null
  },
  "traceId": "7db459fd-0b8e-4f29-9c46-4938a200001",
  "success": true
}

change 成功响应没有 confirmedsideEffects 字段。只有 code=200 时才能用新派车组替换页面中的旧版本;warningCode=ORDER_HAS_OTHER_VEHICLES 时继续保留既有强提示。

4.3 605041 失败响应

{
  "code": 605041,
  "message": "订单行程或用车派单已变化,请按逐日差异处理后重试",
  "data": {
    "assignmentId": null,
    "assignmentSlotId": null,
    "previousAssignmentGroupId": null,
    "newAssignmentGroupId": null,
    "assignmentStatus": null,
    "effectiveDate": null,
    "affectedDays": null,
    "protocolPrice": null,
    "otherVehicleCount": null,
    "warningCode": null,
    "warningMessage": null,
    "otherVehicles": null,
    "dailyDifferences": [
      {
        "serviceDate": null,
        "differenceType": "HEADCOUNT_BASELINE_MISMATCH",
        "assignmentId": null,
        "assignmentSlotId": null,
        "passengerCount": 8,
        "passengerCapacity": null,
        "capacityGap": null,
        "message": "订单当前人数与用车需求冻结人数不一致"
      },
      {
        "serviceDate": "2026-07-22",
        "differenceType": "CAPACITY_INSUFFICIENT",
        "assignmentId": null,
        "assignmentSlotId": null,
        "passengerCount": 8,
        "passengerCapacity": 5,
        "capacityGap": 3,
        "message": "车辆载客量不足,已按每车司机占一座计算"
      }
    ]
  },
  "traceId": "7db459fd-0b8e-4f29-9c46-4938a605041",
  "success": false
}

此时旧派单和原派车组仍是有效业务状态。后端可能新增一条 CHANGE_FAILED 操作审计,但不会生成可用的新派车版本。不得用 dailyDifferences[].assignmentId 替换页面主键,也不得本地切换车辆、司机或状态。

五、最终确认 confirm

5.1 请求

POST /admin/fleet/assignments/2078001000000000501/confirm
Authorization: Bearer <admin-token>
Content-Type: application/json
{
  "requestId": "fleet-final-confirm-4938-20260719-001"
}
字段 位置 类型 必填 约束 说明
assignmentId Path String 有效派单 ID 当前派车组中的任一派单 ID
requestId Body String 非空,最长 64 最终确认幂等标识

5.2 成功响应

{
  "code": 200,
  "message": "成功",
  "data": {
    "confirmed": true,
    "assignmentStatus": "assigned",
    "stageCode": "assigned",
    "stageLabel": "已派车",
    "currentStep": 4,
    "assignmentGroupId": "2078001000000000601",
    "confirmedAt": "2026-07-19 14:30:00",
    "itineraryUrl": "https://h5.example.com/#/itinerary/<signed-token>",
    "sideEffects": {
      "vehicleStatusUpdated": "busy",
      "driverStatusUpdated": "busy",
      "reconPrepRowsCreated": 0,
      "reconPrepMarkedCanceled": null
    },
    "dailyDifferences": null
  },
  "traceId": "7db459fd-0b8e-4f29-9c46-4938f200001",
  "success": true
}

itineraryUrl 签发配置不可用时允许为空,不影响确认成功。前端只有在 code=200 && data.confirmed===true 时展示最终确认成功,并刷新派单详情、看板列表和汇总。

5.3 日期、人数与容量同时存在差异

{
  "code": 605041,
  "message": "订单行程或用车派单已变化,请按逐日差异处理后重试",
  "data": {
    "confirmed": false,
    "assignmentStatus": null,
    "stageCode": null,
    "stageLabel": null,
    "currentStep": null,
    "assignmentGroupId": null,
    "confirmedAt": null,
    "itineraryUrl": null,
    "sideEffects": null,
    "dailyDifferences": [
      {
        "serviceDate": "2026-07-21",
        "differenceType": "ORDER_DATE_MISMATCH",
        "assignmentId": null,
        "assignmentSlotId": null,
        "passengerCount": null,
        "passengerCapacity": null,
        "capacityGap": null,
        "message": "订单当前日期与用车需求冻结日期不一致"
      },
      {
        "serviceDate": null,
        "differenceType": "HEADCOUNT_BASELINE_MISMATCH",
        "assignmentId": null,
        "assignmentSlotId": null,
        "passengerCount": 8,
        "passengerCapacity": null,
        "capacityGap": null,
        "message": "订单当前人数与用车需求冻结人数不一致"
      },
      {
        "serviceDate": "2026-07-22",
        "differenceType": "CAPACITY_INSUFFICIENT",
        "assignmentId": null,
        "assignmentSlotId": null,
        "passengerCount": 8,
        "passengerCapacity": 5,
        "capacityGap": 3,
        "message": "车辆载客量不足,已按每车司机占一座计算"
      }
    ]
  },
  "traceId": "7db459fd-0b8e-4f29-9c46-4938f605041",
  "success": false
}

5.4 缺少某日车辆槽位

{
  "code": 605041,
  "message": "订单行程或用车派单已变化,请按逐日差异处理后重试",
  "data": {
    "confirmed": false,
    "assignmentStatus": null,
    "stageCode": null,
    "stageLabel": null,
    "currentStep": null,
    "assignmentGroupId": null,
    "confirmedAt": null,
    "itineraryUrl": null,
    "sideEffects": null,
    "dailyDifferences": [
      {
        "serviceDate": "2026-07-23",
        "differenceType": "ASSIGNMENT_DATE_MISSING",
        "assignmentId": null,
        "assignmentSlotId": null,
        "passengerCount": null,
        "passengerCapacity": null,
        "capacityGap": null,
        "message": "该服务日缺少第2个车辆槽位派单"
      }
    ]
  },
  "traceId": "7db459fd-0b8e-4f29-9c46-4938f605042",
  "success": false
}

六、前端统一处理顺序

  1. 先判断业务 code,再读取端点自己的 data
    • code=200:按对应成功模型处理;
    • code=605041:按对应失败模型读取 dailyDifferences
    • 其他业务码:继续走既有错误处理。
  2. 605041 时不要乐观更新:
    • create 不新增本地派单;
    • change 不替换旧派单;
    • confirm 不改为 assigned 或“已确认”。
  3. 展示顶层 message,并按 dailyDifferences 列出服务日、差异类型、人数、容量和缺口;字段为空时隐藏对应展示项。
  4. 重新请求最新订单和车务详情,避免继续使用操作前缓存。
  5. 用户修正订单日期、行程、人数或派单后,生成新的 requestId 再提交新动作;仅在同一次动作网络结果不确定时复用原 requestId

七、其他直接错误分支

业务码 常见场景 前端处理
605009 派单不存在 刷新详情和看板,停止操作旧记录
605020 当前状态不允许操作 刷新最新生命周期与操作能力
605025 最终确认前缺少司机确认或有效凭证 引导先完成司机确认与凭证登记
605001 / 605003 车辆或司机档期冲突 展示后端错误并重新选车/司机
605036 跨常驻车未显式确认 二次提示后携带 confirmCrossResident=true 重试
605041 订单、需求、行程、逐日派单、人数或容量基线不一致 使用当前端点的 data.dailyDifferences 展示并处理

请求字段为空、格式不正确或超过长度限制时走统一参数校验错误,前端应在发请求前完成同样约束。

八、不影响范围

  • 不新增管理后台接口,三个接口的请求字段结构保持不变。
  • holdMode=1 的排车锁定、司机确认与凭证登记流程保持不变。
  • 不改变取消、司机拒接、驳回需求、撤销取消和提前完结的前端调用契约。
  • 不要求前端计算订单人数、逐日服务日期或车辆载客量,这些均由后端权威校验并返回差异。
  • 本文件只描述管理后台直接消费的 HTTP 契约,不包含服务间调用或发布实现细节。

九、验收状态与待补证据

已完成:

  • 当前 worktree 中 create、change、confirm Controller 的 605041 强类型 data 静态核对。
  • AssignmentWriteRespVOChangeAssignmentRespVOConfirmRespVOdailyDifferences 字段静态核对。
  • 三条失败路径不提交派单及其关联业务状态变化的源码顺序核对。
  • 后端 PR #5065 已合并至 dev-v3;Fleet 双实例 8087/8187 已完成滚动部署并通过健康/Nacos 验证。
  • 最终源码指纹下 Fleet verify 1909/1909、Order-v3 受影响回归 438/438、User Quartz 桥接 5/5 均通过。

前端联调仍需补充:

  • 三个接口在测试环境 OpenAPI 中的请求/响应模型截图或导出差异。
  • 经网关分别取得 create、change、confirm 的成功响应和 605041 真实响应,记录 HTTP 状态、业务码、traceId 与完整 data
  • 605041 前后做测试业务数据对照,确认派单版本/状态、车辆司机占用、保险、对账和订单派定结果未发生变化。
  • 管理后台页面联调证据:差异列表展示、空字段处理、刷新行为、禁止乐观更新,以及修正后重新提交成功。