hl-api-changelog/changelogs-v2/2026-07/53_4871_车务提需求派单看板闭环契约-管理后台.md
2026-07-09 17:40:40 +08:00

14 KiB

【前端对接·管理后台】车务提需求与派单看板闭环契约

Issue: wx/HL#4871
服务: hl-order-service-v3 / hl-fleet-service / hl-user-service
日期: 2026-07-09
影响范围: 订单详情车辆需求、车务工作台、派单看板、车务聊天、派单操作

1. 结论

  • 用车需求只选车型大类,不选具体车型型号;fleet[].vehicleType 传大类 key,fleet[].seats 传该大类 seatOptions 中的座位数。
  • 司机占 1 个座位:后端新增并返回 passengerSeatCapacityremainingPassengerSeats 等字段,前端余座展示以这些字段为准。
  • 派单看板状态枚举以后读 GET /admin/fleet/board/summarystatusOptions,前端不要再独立维护状态文案映射。
  • holding 的业务含义是“排车中”:车务已经派给司机,但司机还没有确认。
  • 派单看板列表/工作台补齐联系人、团号、定制师展示名、操作能力字段,支持按联系人/团号/定制师筛选。
  • 车务聊天在线态按“是否有任一车务管理员角色在线”聚合,不再绑定单个 admin。
  • 派单取消和司机拒接/退回待派已补后端接口。已告知司机也允许取消,但前端必须做强提示确认。

2. 提交用车需求

PUT /v3/admin/order/2074746808742928386/vehicle-requirement
Authorization: Bearer <admin-token>
Content-Type: application/json

请求示例:

{
  "fleet": [
    {
      "vehicleType": "suv2",
      "seats": 5,
      "count": 1
    }
  ],
  "specialTags": ["大行李空间", "中文司机"],
  "remark": "接机后直接去酒店"
}

成功响应新增座位字段:

{
  "code": 200,
  "message": "成功",
  "success": true,
  "data": {
    "id": "2075000000000000001",
    "orderId": "2074746808742928386",
    "version": 1,
    "status": "PENDING",
    "fleet": [
      { "vehicleType": "suv", "seats": 5, "count": 1 }
    ],
    "specialTags": ["大行李空间", "中文司机"],
    "remark": "接机后直接去酒店",
    "passengerCount": 3,
    "vehicleCount": 1,
    "totalSeatCount": 5,
    "driverSeatCount": 1,
    "passengerSeatCapacity": 4,
    "remainingPassengerSeats": 1
  }
}

座位公式:

vehicleCount = sum(fleet[].count)
totalSeatCount = sum(fleet[].seats * fleet[].count)
driverSeatCount = vehicleCount
passengerSeatCapacity = totalSeatCount - driverSeatCount
remainingPassengerSeats = passengerSeatCapacity - passengerCount

示例1 台 5 座车只能坐 4 名乘客,司机占 1 座。订单 5 名乘客提交 1 台 5 座车会失败:

{
  "code": 582027,
  "message": "车辆载客座位不足每辆车需扣除1个司机座",
  "success": false,
  "data": null
}

前端处理:

  • “余 X 座”展示请读 remainingPassengerSeats,不要用 seats * count - passengerCount 自行计算。
  • 仍然从 GET /admin/fleet/vehicle-types/list 读取车型大类和 seatOptions
  • fleet[].vehicleTypetypeKeyfleet[].seats 只能从该大类 seatOptions 里选。
  • specialTags 继续来自字典 vehicle_special_demand

3. 订单详情行程 Tab

GET /v3/admin/order/2074746808742928386/itinerary
Authorization: Bearer <admin-token>

vehicleGroup.requirement 同步新增座位字段:

{
  "code": 200,
  "message": "成功",
  "success": true,
  "data": {
    "canContactFleet": true,
    "contactFleetDisabledReason": null,
    "vehicleGroup": {
      "requirement": {
        "requirementId": "2075000000000000001",
        "status": "PENDING",
        "vehicleTypeSummary": "suv×1",
        "specialTags": ["大行李空间", "中文司机"],
        "remark": "接机后直接去酒店",
        "passengerCount": 3,
        "vehicleCount": 1,
        "totalSeatCount": 5,
        "driverSeatCount": 1,
        "passengerSeatCapacity": 4,
        "remainingPassengerSeats": 1
      },
      "assignments": []
    }
  }
}

4. 派单看板汇总与状态选项

GET /admin/fleet/board/summary
Authorization: Bearer <fleet-admin-token>

响应示例:

{
  "code": 200,
  "message": "成功",
  "success": true,
  "data": {
    "totalOrders": 132,
    "unassigned": 111,
    "holding": 2,
    "assigned": 8,
    "changeRequested": 3,
    "completed": 3,
    "canceled": 2,
    "statusOptions": [
      {
        "value": "unassigned",
        "label": "待派车",
        "description": "未派车,可派车/可驳回用车需求",
        "count": 111,
        "urgentCount": 2
      },
      {
        "value": "holding",
        "label": "排车中",
        "description": "车务已派给司机,司机未确认",
        "count": 2,
        "urgentCount": 2
      },
      {
        "value": "assigned",
        "label": "已派车",
        "description": "司机已确认执行",
        "count": 8,
        "urgentCount": 0
      },
      {
        "value": "change_requested",
        "label": "换车请求",
        "description": "客户或定制师提出换车",
        "count": 3,
        "urgentCount": 0
      },
      {
        "value": "completed",
        "label": "已完结",
        "description": "派车已完结",
        "count": 3,
        "urgentCount": 0
      },
      {
        "value": "canceled",
        "label": "已取消",
        "description": "派车已取消",
        "count": 2,
        "urgentCount": 0
      }
    ]
  }
}

前端处理:

  • 筛选下拉和状态文案读 statusOptions[].value/label/count/urgentCount
  • 前端不要把 holding 显示成“待派车”或“已派车”;它固定显示为“排车中”。
  • 红色急单角标可读 urgentCount;列表行是否急单仍读行内 assignmentStatus 派生态。

5. 派单看板列表

GET /admin/fleet/board/orders?page=1&pageSize=10&statuses=unassigned&contactName=乐瑶&teamNo=26-7218&consultantName=阿如娜
Authorization: Bearer <fleet-admin-token>

新增/强化查询参数:

参数 类型 说明
contactName string 联系人/客户名模糊筛选。
contactKeyword string contactName 别名,二者任选其一。
teamNo string 团号模糊筛选,例如 26-7218
plannerName string 定制师模糊筛选,旧字段保留。
consultantName string 定制师模糊筛选,plannerName 别名。
statuses string[] 状态多选,值来自 statusOptions[].value
status string 单状态或逗号分隔状态。
typeKeys string[] 车型大类筛选。
startDate/endDate date 行程日期区间。
keyword string 司机姓名搜索,兼容旧页面。

响应示例:

{
  "code": 200,
  "message": "成功",
  "success": true,
  "data": {
    "page": 1,
    "pageSize": 10,
    "total": 27,
    "records": [
      {
        "id": "HL20260708144557879",
        "orderId": "2074746808742928386",
        "orderNo": "HL20260708144557879",
        "teamNo": "26-7218",
        "customerName": "何子墨",
        "contactName": "何子墨",
        "productName": "测试核心产品-单档-固定订金",
        "headcount": 2,
        "startDate": "2026-07-20",
        "endDate": "2026-07-22",
        "tripDays": 3,
        "assignmentStatus": "unassigned_urgent",
        "assignmentStatusLabel": "待派车",
        "urgentBadge": "待派即将超时",
        "consultantName": "阿如娜",
        "consultantDisplayName": "阿如娜",
        "plannerName": "阿如娜",
        "customerNote": "需要接送机",
        "requiredVehicles": [
          {
            "vehicleType": "suv",
            "categoryLabel": "SUV系列",
            "seats": 5,
            "count": 1
          }
        ],
        "canAssign": true,
        "canRejectRequirement": true,
        "unreadMessageCount": 0
      }
    ]
  }
}

前端处理:

  • 列表卡片至少展示联系人/人数/定制师/团号;字段优先级:
    • 联系人:contactName || customerName
    • 定制师:consultantDisplayName || consultantName || plannerName
    • 团号:teamNo
  • 派车按钮展示条件:canAssign === true
  • 驳回用车需求按钮展示条件:canRejectRequirement === true
  • 红色即将超时订单也必须显示派车/驳回按钮,不能因为急单样式隐藏操作区。
  • 当前接口仍是分页接口;前端不要改成不分页一次性全拉。

6. 车务工作台

GET /admin/fleet/dashboard/summary
Authorization: Bearer <fleet-admin-token>

upcomingTrips[] 与派单看板列表同步字段:

{
  "code": 200,
  "message": "成功",
  "success": true,
  "data": {
    "pendingAssignmentCount": 111,
    "upcomingTrips": [
      {
        "orderId": "2074746808742928386",
        "orderNo": "HL20260708144557879",
        "teamNo": "26-7218",
        "contactName": "何子墨",
        "customerName": "何子墨",
        "productName": "测试核心产品-单档-固定订金",
        "startDate": "2026-07-20",
        "headcount": 2,
        "assignmentStatus": "unassigned",
        "assignmentStatusLabel": "待派车",
        "consultantName": "阿如娜",
        "consultantDisplayName": "阿如娜",
        "canAssign": true,
        "canRejectRequirement": true
      }
    ]
  }
}

前端处理同派单看板列表:工作台快捷入口可直接根据 canAssign/canRejectRequirement 展示派车/驳回入口。

7. 取消派单

DELETE /admin/fleet/assignments/2075001000000000001
Authorization: Bearer <fleet-admin-token>
Content-Type: application/json

{
  "cancelReason": "客户调整接送时间,原司机无法执行",
  "driverNotified": true
}

响应示例:

{
  "code": 200,
  "message": "成功",
  "success": true,
  "data": {
    "assignmentStatus": "canceled",
    "sideEffects": {
      "vehicleReleased": true,
      "driverReleased": true
    }
  }
}

前端处理:

  • driverNotified=false:可直接二次确认后取消。
  • driverNotified=true:仍可取消,但必须用强提示,例如“已告知司机,取消后需线下同步司机,确认取消?”。
  • 不要因为已告知司机就禁用取消按钮;后端已经允许并记录该标记。

8. 司机拒接/退回待派

司机拒接或车务确认本次排车无效时调用。只允许 holding 状态。

POST /admin/fleet/assignments/2075001000000000001/driver-reject
Authorization: Bearer <fleet-admin-token>
Content-Type: application/json

{
  "rejectReason": "司机临时无法出车"
}

响应示例:

{
  "code": 200,
  "message": "成功",
  "success": true,
  "data": {
    "assignmentStatus": "unassigned",
    "assignmentGroupId": "2075001000000000001",
    "sideEffects": {
      "vehicleReleased": true,
      "driverReleased": true
    }
  }
}

错误响应示例:

{
  "code": 605020,
  "message": "当前状态不允许退回待派",
  "success": false,
  "data": null
}

前端处理:

  • 司机未确认前的 holding 行可展示“司机拒接/退回待派”。
  • 调用成功后该行回到 unassigned,可重新派车。
  • assigned 的行不走本接口,如需取消用 §7 取消派单。

9. 车务聊天在线态

POST /admin/message/chat/open-fleet
Authorization: Bearer <admin-token>
Content-Type: application/json

{
  "orderId": "2074746808742928386",
  "peerAdminId": null
}

响应中的对端在线态现在按“车务管理员角色是否有人在线”聚合:

{
  "code": 200,
  "message": "成功",
  "success": true,
  "data": {
    "conversationKey": "FLEET:2074746808742928386",
    "peer": {
      "peerAdminId": "0",
      "peerRole": "FLEET",
      "peerRoleLabel": "车务",
      "peerOnline": true
    },
    "order": {
      "orderId": "2074746808742928386",
      "orderNo": "HL20260708144557879",
      "customerName": "何子墨",
      "teamNo": "26-7218"
    }
  }
}

前端处理:

  • peerRole=FLEETpeerAdminId=0 表示车务团队,不是某一个 admin。
  • 只要任一车务管理员在线,peerOnline=true
  • 管理员必须以车务角色登录系统,才会被计入车务团队在线态。

10. 前端对接清单

页面/弹窗 必做
调整订单车辆页 车型选大类,座位选 seatOptions;余座读后端 remainingPassengerSeats
订单详情行程 Tab vehicleGroup.requirement 新增座位字段直接展示,不要前端自算司机座。
派单看板 状态下拉读 summary.statusOptions;列表保持分页;卡片展示联系人/人数/定制师/团号。
派单看板操作 canAssign 控制派车按钮,canRejectRequirement 控制驳回需求按钮。
派单取消 driverNotified=true 时强提示,但不能禁用取消。
排车中 holding 显示为“排车中”,含义是司机未确认。
车务聊天 peerOnline 按车务团队聚合显示在线/离线。

11. 后端本地验证

mvn -pl hl-order-service-v3 -am "-Dtest=RequirementServiceTest,OrderDetailServiceTest,OrderDetailConverterTest" "-DfailIfNoTests=false" test
mvn -pl hl-fleet-service -am "-Dtest=BoardOrderServiceTest,BoardSummaryServiceTest,FleetDashboardSummaryServiceTest,AssignmentControllerTest,AssignmentServiceTest,AssignmentStateMachineHelperTest" "-DfailIfNoTests=false" test
mvn -pl hl-user-service -am "-Dtest=ChatManagerTest,ConversationMemberServiceTest,AdminPresenceServiceTest,AdminSseServiceTest" "-DfailIfNoTests=false" test

覆盖点:

  • 5 座车只允许 4 名乘客;5 名乘客提交 1 台 5 座车返回 582027
  • 订单详情 vehicleGroup.requirement 返回 passengerSeatCapacity/remainingPassengerSeats
  • 派车 strictSeats 对 5 座车 + 5 名乘客返回 605002
  • 派单看板返回联系人/团号/定制师/操作能力/状态文案。
  • statusOptions 由后端返回,含 holding=排车中
  • 车务团队在线态按车务角色聚合。