From 4bfa0002acd61a5d952089394607533e28f08d29 Mon Sep 17 00:00:00 2001 From: API Changelog Bot Date: Thu, 24 Sep 2026 03:54:16 +0800 Subject: [PATCH] =?UTF-8?q?docs(changelog):=20#8235=20=E7=9C=8B=E6=9D=BF?= =?UTF-8?q?=E8=AE=A2=E5=8D=95=E8=AE=B0=E5=BD=95=E6=96=B0=E5=A2=9E=E5=9B=A2?= =?UTF-8?q?=E8=BD=A6=E6=95=B4=E6=AE=B5=E6=8E=A5=E7=AE=A1=E6=A0=87=E8=AE=B0?= =?UTF-8?q?=EF=BC=8C=E5=B7=B2=E6=8E=A5=E7=AE=A1=E9=9B=B6=E6=B4=BE=E8=BD=A6?= =?UTF-8?q?=E8=A1=8C=20TRAVEL=20=E4=B8=8D=E5=86=8D=E7=94=9F=E6=88=90?= =?UTF-8?q?=E8=99=9A=E6=8B=9F=E5=BE=85=E6=B4=BE=E5=8D=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refs wx/HL#8235 Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01Cfipfut7pN3pLCRibrYygP --- ...µ接管标记与虚拟待派卡抑制-修改接口-管理后台.md | 571 ++++++++++++++++++ 1 file changed, 571 insertions(+) create mode 100644 changelogs-v2/2026-09/24_8235_团车整段接管标记与虚拟待派卡抑制-修改接口-管理后台.md diff --git a/changelogs-v2/2026-09/24_8235_团车整段接管标记与虚拟待派卡抑制-修改接口-管理后台.md b/changelogs-v2/2026-09/24_8235_团车整段接管标记与虚拟待派卡抑制-修改接口-管理后台.md new file mode 100644 index 00000000..848d6b83 --- /dev/null +++ b/changelogs-v2/2026-09/24_8235_团车整段接管标记与虚拟待派卡抑制-修改接口-管理后台.md @@ -0,0 +1,571 @@ +--- +schema: "hl-changelog/v2" +ticket: "8235" +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: "" +status_note: "" +updated_at: "2026-09-24" +base: "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 | 当前车辆车牌/司机姓名 | + +#### 请求示例 + +```json +GET /admin/fleet/board/orders?statuses=unassigned&variant=list&page=1&pageSize=20 +``` + +#### 响应示例 + +```json +{ + "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 +} +``` + +#### 空数据 / 降级响应 + +```json +{ + "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。 + +#### 错误响应 + +```json +{ + "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` + +#### 使用场景 + +管理后台「车辆矩阵」未派窗口,车务人员按年月查看当月全部未派/待派订单,从中选取虚拟待派卡发起整单派车。 + +#### 入参字段表 + +| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | +|------|------|------|------|------|------| +| 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 | 并行派车条目;虚拟待派条目恒为空数组 | + +#### 请求示例 + +```json +GET /admin/fleet/matrix/unassigned-orders?year=2026&month=11&typeKeys=suv +``` + +#### 响应示例 + +```json +{ + "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 +} +``` + +#### 空数据 / 降级响应 + +```json +{ "code": 200, "message": "成功", "data": [], "success": true } +``` + +`vehicleAdvice` 暂返 null(数据源未建);Nacos `fleet.board.virtual-candidates-enabled=false` 或 order-v3 候选不可用时只丢虚拟条目,真实条目原样返回(fail-open,不让未派窗口整体打不开)——此为既有降级契约,本次未改。 + +#### 错误响应 + +```json +{ + "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 一致 | + +#### 请求示例 + +```json +GET /admin/fleet/matrix/grid?year=2026&month=11&season=active +``` + +#### 响应示例 + +```json +{ + "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 +} +``` + +#### 空数据 / 降级响应 + +```json +{ + "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` 未派计数的贡献,真实派车行的统计不受影响。 + +#### 错误响应 + +```json +{ + "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 条全量核对)不依赖该日期区间。 + +--- + +## 十、相关文档 + +- 关联 Issue: [wx/HL#8235](https://git.1814.love/wx/HL/issues/8235) +- 关联 Issue(测试环境已知缺口,独立跟踪): [wx/HL#8301](https://git.1814.love/wx/HL/issues/8301) + +## 关联 / 联系人 + +### 链接 + +- **Issue**: [#8235](https://git.1814.love/wx/HL/issues/8235) +- **PR**: [#8300](https://git.1814.love/wx/HL/pulls/8300) +- **Merge commit**: [ea9cd0d33](https://git.1814.love/wx/HL/commit/ea9cd0d33) + +### 联系人 + +- **后端负责人**: @wx +- **前端负责人**: @mmg