文件
hl-api-changelog/changelogs-v2/2026-09/24_8235_团车整段接管标记与虚拟待派卡抑制-修改接口-管理后台.md
T
2026-09-24 04:02:49 +08:00

26 KiB
原始文件 Blame 文件历史

schema, ticket, title, consumer, author, change_type, backend_status, gateway_status, frontend_status, frontend_owner, frontend_ref, target_release, verified_at, status_note, updated_at, base
schema ticket title consumer author change_type backend_status gateway_status frontend_status frontend_owner frontend_ref target_release verified_at status_note updated_at base
hl-changelog/v2 8235 看板订单记录新增团车整段接管标记;已接管且零派车行的行程用车在看板与矩阵不再生成虚拟待派卡 admin wx(GIT) 修改接口 deployed verified verified mmg 3f3f14b3cddf5a07e09730173f896084af3f5832 v2.1 2026-09-24 前端已交付:normalizeBoardOrder 显式归一布尔;isGroupVehicleCovered 只认 === true;卡片状态区「团车接管·可释放」badge+表格配车列 chip/popover 说明行;矩阵抑制与计数减少纯后端,前端无本地对比旧计数逻辑;spec 18 例全绿+fleet/board 557 例全绿,checkpoint 7 项过 2026-09-24 dev-v3

fleet: 团车整段接管标记透出 + 虚拟待派卡抑制

存放目录: changelogs-v2/{YYYY-MM}/

服务: hl-fleet-service (端口 8087) PR: #8300 Issue: #8235 日期: 2026-09-24 影响范围: 管理后台「车务看板」订单列表/网格视图、「车辆矩阵」未派清单与网格/月度统计


⚠️ 关键变化

团车已整段接管、且在 fleet 侧零派车行的行程用车(TRAVEL)需求,不再在看板与矩阵里生成虚拟待派卡,也不计入矩阵未派计数。这是主动抑制,不是数据丢失:该需求的车已经由团车统一安排,逐单侧没有活儿可派。若该户在团确认前已经被逐单单独派了车(真实派车行仍存在),这行照常出卡,并在看板订单记录上新增 groupVehicleCovered=true 标记,提示车务这行属冗余、可释放;只在这种"有真实派车行"的场景下才会看到该标记为 true,其余情况(未接管、接送机卡、虚拟待派卡)一律为 null,不会出现 false。


二、变更接口清单

# 接口 方法 路径 变更类型 说明
1 看板订单列表 GET /admin/fleet/board/orders 响应新增字段+行为变更 新增 groupVehicleCovered;团车已接管的零派车行 TRAVEL 不再生成虚拟待派卡
2 矩阵未派订单清单 GET /admin/fleet/matrix/unassigned-orders 行为变更 同上抑制逻辑,命中的订单不再出现在未派清单
3 矩阵网格主数据 GET /admin/fleet/matrix/grid 行为变更 statusCounts 未派/总量计数不再计入被抑制的虚拟条目

GET /admin/fleet/matrix/month-counts 与本清单第 3 项共用完全相同的 statusCounts 计算口径(MatrixController 自身 javadoc 明确"每月 statusCounts 与相同筛选下 grid.statusCounts 同口径"),受同一行为变更影响,不单列小节,详情参照第 3 项。


三、接口详情

1. 看板订单列表 GET /admin/fleet/board/orders

VO: BoardOrderPageReqVO → BoardOrderPageRespVO(records: BoardOrderRecordVO[])

使用场景

管理后台「车务看板」订单列表/网格视图(variant=list|grid),车务人员按状态、日期、团号、车型等筛选待派/已派订单卡片,逐卡执行改派、派车、查看行程等操作。

入参字段表

字段 位置 类型 必填 约束 说明
statuses Query String[] ❌ 枚举:unassigned/unassigned_urgent/holding/holding_urgent/assigned/canceled/completed,可多选 状态多选筛选
status Query String ❌ 同上枚举,兼容单值 statuses 兼容别名
startDayFrom Query LocalDate ❌ yyyy-MM-dd 行程日期区间起
startDayTo Query LocalDate ❌ yyyy-MM-dd 行程日期区间止
startDate Query LocalDate ❌ yyyy-MM-dd startDayFrom 兼容别名
endDate Query LocalDate ❌ yyyy-MM-dd startDayTo 兼容别名
vehicleTypeKeys Query String[] ❌ 车型大类字典值 车型多选筛选
typeKeys Query String[] ❌ 同上 vehicleTypeKeys 兼容别名
driverName Query String ❌ - 司机姓名模糊搜索
keyword Query String ❌ - 统一关键字搜索
contactName Query String ❌ - 联系人姓名模糊搜索
contactKeyword Query String ❌ - contactName 兼容别名
teamNo Query String ❌ - 团号模糊搜索
groupBatchId Query Long ❌ 等值匹配,只认派车行建行时刻快照(#7443) 运营团期 ID 筛选
consultantId Query Long ❌ - 定制师 ID 精确筛选
plannerName Query String ❌ - 定制师姓名模糊搜索
consultantName Query String ❌ - plannerName 兼容别名
variant Query String ❌ list/grid,其余值走缺省 100001 视图 视图口径
page(或 pageNo) Query Integer ❌ ≥1,缺省 1 页码
pageSize Query Integer ❌ 1-100 每页条数

出参字段表

字段 类型 说明
id Long 派车行/虚拟条目主键(虚拟条目为合成 ID)
orderId Long 子订单 ID
orderNo String 订单编号
teamNo String 团号
groupBatchId Long 运营团期 ID(#7443;非团期订单为 null)
customerName String 客户姓名
assignmentId Long 派车行 ID;虚拟条目恒为 null
assignmentGroupId Long 派车分组 ID
requirementId Long 当前用车需求 ID
assignmentStatus String 派单状态码
virtualPending Boolean 真实记录恒显式 false(非 null);虚拟待派卡为 true
groupVehicleCovered Boolean 新增(#8235)。仅真实记录且该需求已被团车整段接管时为 true;未接管、接送机卡、虚拟待派卡一律为 null,永不出现 false
urgentBadge String 紧急标签
canAssign Boolean 是否可派车
dispatchReadOnly Boolean 是否只读(不可操作)
startDate / endDate LocalDate 行程起止日期
currentVehiclePlate / currentDriverName String 当前车辆车牌/司机姓名

请求示例

GET /admin/fleet/board/orders?statuses=unassigned&variant=list&page=1&pageSize=20

响应示例

{
  "code": 200,
  "message": "成功",
  "data": {
    "records": [
      {
        "id": 9900000000000101,
        "orderId": 9900000000000201,
        "orderNo": "HL20261001000001",
        "teamNo": "26-9901",
        "groupBatchId": 9900000000000301,
        "customerName": "示例客户A",
        "assignmentId": 9900000000000401,
        "assignmentGroupId": 9900000000000501,
        "requirementId": 9900000000000601,
        "assignmentStatus": "PROCESSING",
        "virtualPending": false,
        "groupVehicleCovered": true,
        "urgentBadge": null,
        "canAssign": true,
        "dispatchReadOnly": false,
        "startDate": "2026-11-01",
        "endDate": "2026-11-05",
        "currentVehiclePlate": "蒙K·A0001",
        "currentDriverName": "示例司机"
      },
      {
        "id": -9900000000000701,
        "orderId": 9900000000000801,
        "orderNo": "HL20261001000002",
        "teamNo": null,
        "groupBatchId": null,
        "customerName": "示例客户B",
        "assignmentId": null,
        "assignmentGroupId": null,
        "requirementId": 9900000000000901,
        "assignmentStatus": "unassigned",
        "virtualPending": true,
        "groupVehicleCovered": null,
        "urgentBadge": null,
        "canAssign": true,
        "dispatchReadOnly": false,
        "startDate": "2026-11-02",
        "endDate": "2026-11-06",
        "currentVehiclePlate": null,
        "currentDriverName": null
      }
    ],
    "total": 2,
    "page": 1,
    "pageSize": 20
  },
  "success": true
}

空数据 / 降级响应

{
  "code": 200,
  "message": "成功",
  "data": { "records": [], "total": 0, "page": 1, "pageSize": 20 },
  "success": true
}

无匹配记录时返回空 records 数组,total=0,不报错。虚拟待派卡取数失败(Nacos fleet.board.virtual-candidates-enabled=false 或 order-v3 虚拟候选不可用)时只丢虚拟条目,真实派车行照常返回——这一条与矩阵未派清单口径一致。

带日期筛选时另有一条既有 fail-closed 口径(非本次引入,本次未改):看板按日期筛选走单独的日期候选扫描,该扫描取 order-v3 日期候选页失败,或候选行数据不完整(派车行 requirement_id 为空、订单 ID 为空、候选键为空或重复)时,本页整体返回空 records、total=0、code=200,不报错。因此带日期筛选时的空列表不能等同于「该日期窗确实无单」;不带日期筛选的查询与矩阵接口不走这条分支,不受影响。测试服当前就有一条命中该口径的夹具数据,见「八、测试环境已验证」末段与 #8301。

错误响应

{
  "code": 401,
  "message": "未登录或登录已过期",
  "success": false,
  "data": null
}

业务边界

  • groupVehicleCovered 只在真实记录(virtualPending=false)且该需求已被团车整段接管时为 true;虚拟待派卡(virtualPending=true)恒为 null。判断"是否已接管"请只用 === true,不要用 !== true 当作"未接管"的充分条件去做业务分支——null 同时覆盖"未接管"与"该卡不适用本标记"两种情况。
  • 团车已接管但零派车行的 TRAVEL 需求:本接口不再返回该需求的虚拟待派卡(该记录会从列表里消失)。
  • 团车已接管但存在存量真实派车行的 TRAVEL 需求(团确认前已逐单派出的部分):该行照常出卡,groupVehicleCovered=true,车务应据此判断该行属冗余可释放;车辆矩阵占用与行归属不受影响。
  • 非团期订单、以及团期内的接送机(TRANSFER)需求不受本次改动影响,出卡逻辑与计数均不变。
  • 鉴权:未登录 401(网关拦截)。

2. 矩阵未派订单清单 GET /admin/fleet/matrix/unassigned-orders

VO: MatrixUnassignedReqVO → List<MatrixUnassignedOrderVO>

使用场景

管理后台「车辆矩阵」未派窗口,车务人员按年月查看当月全部未派/待派订单,从中选取虚拟待派卡发起整单派车。

入参字段表

字段 位置 类型 必填 约束 说明
year Query Integer ✅ 1970-9999 年份
month Query Integer ✅ 1-12 月份
typeKeys Query String[] ❌ 车型大类字典值 车型多选筛选

出参字段表

字段 类型 说明
orderId String 订单 ID(订单号)
orderNumericId Long 订单数字 ID
orderNo String 订单编号
teamNo String 团号
virtualPending Boolean true=零派车行的虚拟待派卡(assignmentId 为 null,走 requirementId 整单派车入口)
assignmentId Long 派车行 ID;虚拟条目为 null
requirementId Long 用车需求 ID
vehicleCategory / categoryLabel String 车型大类编码/中文名
customerName String 客户姓名
productName String 产品名
headcountLabel String 人数摘要文案
startDate / endDate LocalDate 行程起止日期(未裁剪)
assignmentStatus String 派单状态码
urgentBadge String 紧急标签
vehicleAdvice Object 车辆建议;M2 暂返 null
parallelAssignments Array 并行派车条目;虚拟待派条目恒为空数组

请求示例

GET /admin/fleet/matrix/unassigned-orders?year=2026&month=11&typeKeys=suv

响应示例

{
  "code": 200,
  "message": "成功",
  "data": [
    {
      "orderId": "9900000000000801",
      "orderNumericId": 9900000000000801,
      "orderNo": "HL20261001000002",
      "teamNo": null,
      "virtualPending": true,
      "assignmentId": null,
      "requirementId": 9900000000000901,
      "vehicleCategory": "suv",
      "categoryLabel": "SUV",
      "customerName": "示例客户B",
      "productName": "示例产品",
      "headcountLabel": "2大1小",
      "startDate": "2026-11-02",
      "endDate": "2026-11-06",
      "assignmentStatus": "unassigned",
      "urgentBadge": null,
      "vehicleAdvice": null,
      "parallelAssignments": []
    }
  ],
  "success": true
}

空数据 / 降级响应

{ "code": 200, "message": "成功", "data": [], "success": true }

vehicleAdvice 暂返 null(数据源未建);Nacos fleet.board.virtual-candidates-enabled=false 或 order-v3 候选不可用时只丢虚拟条目,真实条目原样返回(fail-open,不让未派窗口整体打不开)——此为既有降级契约,本次未改。

错误响应

{
  "code": 400,
  "message": "month: 月份必须在 1-12 之间",
  "success": false,
  "data": null
}

业务边界

  • 团车已整段接管且零派车行的 TRAVEL 需求不再出现在本清单(原本会以一条 virtualPending=true 的条目出现,现在整条消失)。
  • 该需求若存在存量真实派车行,本清单不受影响——本清单只承载"待派"的虚拟条目,真实已派条目不在本接口的返回范围内(走看板订单列表接口查看)。
  • 非团期订单、接送机(TRANSFER)需求不受影响。
  • 鉴权:需 AdminContextUtil 权限检查。

3. 矩阵网格主数据 GET /admin/fleet/matrix/grid

VO: MatrixGridReqVO → MatrixGridRespVO

使用场景

管理后台「车辆矩阵」主视图,按年月+车队/车型/状态筛选渲染车辆甘特图与顶部统计条。statusCounts 驱动顶部"未派/已派/合计"计数徽标。

入参字段表

字段 位置 类型 必填 约束 说明
year Query Integer ✅ - 年份
month Query Integer ✅ 1-12(越界由 Service 返 605010,非 400) 月份
season Query String ❌ active/pending/archived/blacklist,缺省 active 车辆季节状态
fleetTeamIds Query Long[] ❌ - 车队 ID 多选
typeKeys Query String[] ❌ 车型大类字典值 车型多选
status Query String ❌ all/unassigned/assigned 状态口径(粗粒度)
statuses Query String[] ❌ unassigned/unassigned_urgent/holding/holding_urgent/assigned/completed;非空时优先于 status 状态口径(细粒度)

出参字段表

字段 类型 说明
year / month Integer 回显查询年月
daysInMonth Integer 当月天数(28-31)
todayDay Integer 今日是第几天;非当月查询为 null
weekendDays Integer[] 周末日序号列表
vehicles Array 车辆行数组(每辆车含其派车段/衔接/重叠子数组,本次未变更)
fleetTeamCounts Array 车队维度计数,本次未变更
statusCounts.totalAssignments Integer 有效派车行总数
statusCounts.unassignedAssignments Integer 未派派车行数(含虚拟条目)——本次改动后计数减少:被团车整段接管且零派车行的虚拟条目不再计入
statusCounts.assignedAssignments Integer 已派派车行数
statusCounts.totalOrders Integer 去重订单总数
statusCounts.unassignedOrders Integer 含至少一个未派项的去重订单数——同上,计数口径同步减少
statusCounts.partialOrders Integer 部分派车的去重订单数
statusCounts.assignedOrders Integer 全部派车完成的去重订单数
statusCounts.effectiveStatusCounts Object 固定五键(unassigned/unassigned_urgent/holding/holding_urgent/assigned)分面计数
unassignedWindowCount Integer 未派窗口角标计数,口径与 unassignedOrders 一致

请求示例

GET /admin/fleet/matrix/grid?year=2026&month=11&season=active

响应示例

{
  "code": 200,
  "message": "成功",
  "data": {
    "year": 2026,
    "month": 11,
    "daysInMonth": 30,
    "todayDay": null,
    "weekendDays": [1, 7, 8, 14, 15, 21, 22, 28, 29],
    "vehicles": [],
    "fleetTeamCounts": [],
    "statusCounts": {
      "totalAssignments": 118,
      "unassignedAssignments": 6,
      "assignedAssignments": 112,
      "totalOrders": 95,
      "unassignedOrders": 5,
      "partialOrders": 2,
      "assignedOrders": 88,
      "effectiveStatusCounts": {
        "unassigned": 4,
        "unassigned_urgent": 1,
        "holding": 3,
        "holding_urgent": 0,
        "assigned": 112,
        "completed": 40
      }
    },
    "unassignedWindowCount": 5
  },
  "success": true
}

空数据 / 降级响应

{
  "code": 200,
  "message": "成功",
  "data": {
    "year": 2026, "month": 11, "daysInMonth": 30, "todayDay": null,
    "weekendDays": [], "vehicles": [], "fleetTeamCounts": [],
    "statusCounts": {
      "totalAssignments": 0, "unassignedAssignments": 0, "assignedAssignments": 0,
      "totalOrders": 0, "unassignedOrders": 0, "partialOrders": 0, "assignedOrders": 0,
      "effectiveStatusCounts": {"unassigned":0,"unassigned_urgent":0,"holding":0,"holding_urgent":0,"assigned":0,"completed":0}
    },
    "unassignedWindowCount": 0
  },
  "success": true
}

虚拟候选源不可用时按同一 BoardCandidateSource 降级契约 fail-open:只丢虚拟条目对 statusCounts 未派计数的贡献,真实派车行的统计不受影响。

错误响应

{
  "code": 605010,
  "message": "月份必须在 1-12 之间",
  "success": false,
  "data": null
}

业务边界

  • statusCounts 的未派相关计数(unassignedAssignments/unassignedOrders/unassignedWindowCount,以及 effectiveStatusCounts.unassigned/unassigned_urgent)在本次改动后会同步减少:被团车整段接管且零派车行的虚拟条目不再参与统计。这不是数据异常,前端若有本地缓存/对比旧计数的逻辑需知悉此变化。
  • assignedAssignments/assignedOrders 等已派计数不受影响;vehicles[] 车辆行的段位数据与占用计算不受影响。
  • GET /admin/fleet/matrix/month-counts 与本接口共用完全相同的 statusCounts 计算口径,受同一行为变更影响。
  • 鉴权:需 AdminContextUtil 权限检查。

四、契约约束与正确调用方式

✅ 正确 / ❌ 错误用法对照

场景 说明
✅ 判断是否显示"可释放"提示 record.groupVehicleCovered === true
✅ 判断"不显示提示" record.groupVehicleCovered !== true(覆盖 null 与字段不存在两种情况)
❌ 用 groupVehicleCovered === false 做判断分支 该值永不出现 false,只会是 true 或 null,这样写的分支永远走不到
❌ 把矩阵未派计数的减少当作接口故障 团车已接管、零派车行的订单不再计入未派计数,是预期行为,不是数据丢失

切换状态时的必要动作

无。三个接口均为只读 GET,groupVehicleCovered 与虚拟待派卡的抑制均由后端在读取时实时计算,不接受前端传参覆盖,也无需前端在请求前做任何字段置空等准备动作。


五、数据库行为

三个接口均为只读查询,无新增或变更的写库行为。groupVehicleCovered 由 hl-fleet-service 在读取时实时计算:按看板卡片当前用车需求 ID 匹配该订单从 hl-order-service-v3 经 Feign 聚合拿到的需求身份集合,取其"是否已被团车整段接管"标记;不产生新表,也不改变既有列的语义。


六、边界行为

  • 未登录 → 401(网关拦截)
  • 无匹配记录 → 200 + 空数组/空列表,不报错
  • 矩阵网格 month 越界(不在 1-12)→ 605010 业务错误码,非 400
  • 虚拟候选源(order-v3 侧)不可用或 Nacos 开关关闭 → fail-open,只丢虚拟条目,真实记录与真实计数原样返回
  • 看板带日期筛选时,日期候选扫描取数失败或候选行不完整 → 200 + 整页空(既有 fail-closed,非本次引入,见接口 1「空数据 / 降级响应」;矩阵接口不走该分支)
  • 老数据兼容:历史已生成的虚拟待派卡在下次读取时按新逻辑重新计算,不残留旧结果;groupVehicleCovered 对改动前的历史真实记录同样实时计算,无需迁移

六.5、枚举 / 数据字典

groupVehicleCovered(团车整段接管标记)

所属字段: BoardOrderRecordVO.groupVehicleCovered | 类型: Boolean

本次不新增字典枚举类;该字段是只会取两种取值的标记位(不是完整的三态布尔):

值 说明
true 仅真实记录:该需求已被团车整段接管,此行属冗余可释放
null 未接管 / 接送机卡 / 虚拟待派卡 / 不适用;false 永不出现

六.6、修改前后对比

字段级对比

字段 改前 改后 变化说明
BoardOrderRecordVO.groupVehicleCovered 字段不存在 新增,true/null 两态 仅真实记录且被团车整段接管时为 true

行为级对比

行为 改前 改后 影响
团车已接管、零派车行的 TRAVEL 需求 在看板订单列表 / 矩阵未派清单里生成一张虚拟待派卡 不再生成虚拟待派卡,该条目从列表中消失 影响 3 个接口的记录集合与矩阵计数
团车已接管、存在存量真实派车行的 TRAVEL 需求 照常出卡,无标记区分冗余 照常出卡,新增 groupVehicleCovered=true 标记 仅看板订单列表新增标记,出卡数量不变
矩阵 statusCounts 未派相关计数 含上述被抑制的虚拟条目 不含 unassignedAssignments/unassignedOrders/unassignedWindowCount/effectiveStatusCounts.unassigned* 同步减少
非团期订单 / 接送机需求 不受影响 不受影响 无

六.7、影响评估

  • 是否破坏向后兼容: 否。groupVehicleCovered 是新增字段,旧前端未读取该字段不受影响;虚拟卡抑制导致的记录/计数减少是数据层面的行为变化,不改变接口结构或错误码。
  • 前端是否必须同步上线: 是(针对希望展示"可释放"提示的场景)。若前端有基于虚拟待派卡数量做的本地校验或缓存对比逻辑,需知悉计数会因本次改动而减少。
  • 前端 workaround 清理点: 无——这是新增能力,此前前端没有对应的字段或逻辑需要清理。

七、不影响范围

  • 仅影响:

    • 管理后台「车务看板」订单列表/网格视图(/admin/fleet/board/orders)
    • 管理后台「车辆矩阵」未派窗口(/admin/fleet/matrix/unassigned-orders)
    • 管理后台「车辆矩阵」网格与月度统计条(/admin/fleet/matrix/grid、/admin/fleet/matrix/month-counts)
  • 零影响:

    • 团期本身的团级配车流程与团级基线计算
    • 车辆矩阵的车辆占用/甘特图段位计算(vehicles[] 结构与数据不变)
    • 接送机(TRANSFER)需求的看板/矩阵可见性与计数
    • 非团期订单的看板/矩阵可见性与计数
    • 看板订单详情(/admin/fleet/board/orders/{orderId})、出行人列表、操作时间线等其余看板接口
    • C 端与定制师端相关接口

八、测试环境已验证

测试服部署:hl-order-service-v3 2026-09-24 02:52:37 / hl-fleet-service 2026-09-24 02:53:43,均部署到 commit ea9cd0d33(deploy-status 均为 ok;两服务必须同批部署,fleet 侧的接管判定依赖 order-v3 的打标)。

GET /admin/fleet/board/orders(不带日期筛选,全量翻页,共 243 条记录)
  → groupVehicleCovered 键在全部 243 条记录中均存在(0 条缺失)
  → 取值只有 true(5 条,均为真实派车行)与 null(205 条真实卡 + 33 条虚拟待派卡)
  → 0 条记录取值为 false ✓
GET /admin/fleet/matrix/unassigned-orders?year=Y&month=M(2026-09-24 03:50~03:51,2026-08 至 2027-08 逐月 13 次调用)
  → 13 次均 HTTP 200 / code=200
  → 12 张被团车整段接管、fleet 侧零派车行的订单(出行日期落在 2026-10、2026-11、2027-03,均在查询月份内)
    在 13 个月的响应原文中出现 0 次 ✓
  → 对照组 4 张未被接管的零派车行订单(出行 2026-11-15~11-17)全部出现在 2026-11 的未派清单中 ✓
GET /admin/fleet/matrix/grid?year=2026&month=11
  → HTTP 200 / code=200,statusCounts 正常下发(unassignedOrders=23,与同月未派清单 23 条一致)✓

矩阵接口不走看板的日期候选扫描分支,下方 #8301 的限定对矩阵不适用。

已知测试环境限定(与本次改动无关,独立跟踪于 #8301):看板按日期筛选查询,筛选窗口与 2026-11-05~2026-11-07 有交集时,因测试夹具数据缺陷(某条派车行的 requirement_id 为 null)导致该日期筛选分支整体返回 0 条;不带日期筛选的查询不受影响,本次改动的验证结论(上方 243 条全量核对)不依赖该日期区间。


十、相关文档

关联 / 联系人

链接

联系人

  • 后端负责人: @wx
  • 前端负责人: @mmg