--- schema: "hl-changelog/v2" ticket: "7442" title: "团期配车分组写口 reconfigure(PR-A 补登)" 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: "本文档是补登,不是新上线通知。PR-A(#7844,merge commit 8eb8e13cdfd4a8cc004f95cfb53f7e4b81904461,2026-09-16 合入 dev-v3)首次交付本端点时漏写了交接件,导致 #7442 AC-22(要求『5 个新增接口 + 4 个改造接口的完整契约』)按字面一直不可能达成;本单是对这个缺口的补登。backend_status=deployed 的依据:8eb8e13cd 已在 dev-v3,测试服 2026-09-19 01:15 已滚动部署到 4cbccc26b(晚于 8eb8e13cd 与后续 c6aa1224f,均已实测回读 commit 确认在链上)。gateway_status=verified 的依据:2026-09-19 已完成本端点的网关实测,正负各一次,见第八节;⚠️ 本文档此前 gateway_status 字段写的是 verified 而 status_note 与第八节都写着 pending,头身不一致,那时的 verified 是假状态——现在它是真的,见第八节的请求/响应原文与数据库交叉读数。本文档按端点当前(2026-09-19)的完整契约撰写,其中 requirementId/requirementVersion/demands[].assignments[].groupId 等分组相关字段是 PR-A 首次引入的核心内容;reconfigureWindowToken 字段与 602011/602012/602013 三个错误码是随后 PR-C2(#7957)追加到同一端点的字段,本文档一并如实标注,避免把 PR-C2 之后的完整契约错当 PR-A 原状描述。" updated_at: "2026-09-19" base: "dev-v3" --- # fleet: 团期配车分组写口 reconfigure(PR-A 补登) > **存放目录**: changelogs-v2/{YYYY-MM}/ > > **服务**: hl-fleet-service (端口 8082) > **PR**: [#7844](https://git.1814.love:8443/wx/HL/pulls/7844)(PR-A,2026-09-16 已合入;本端点此后又被 [#7957](https://git.1814.love:8443/wx/HL/pulls/7957) PR-C2 追加一个字段,详见下方标注) > **Issue**: #7442(AC-22) > **日期**: 2026-09-19(补登;端点实际上线于 2026-09-16) > **影响范围**: 团期配车页——车务提交整团逐日配车计划的核心写口 --- ## ⚠️ 关键变化 1. **这是补登,不是新功能上线通知**:本端点已在测试服跑了 3 天(2026-09-16 起),**mmg 可能已经在对接它**—— 本文档只是把此前漏写的交接件补齐,不代表这是新上线的东西,请勿据此重新走一遍"新接口接入"流程。 2. **本单是团级配车从"零调用方"到"有真实写口"的分水岭**:改前,`GroupDispatchStatus` 相关的团级配车引擎 虽已存在,但生产调用方为零,车务只能靠车管手工建单兜底;改后,车务可在团期配车页把整团逐日计划直接提交。 3. **`reconfigureWindowToken` 字段与 602011/602012/602013 三个错误码不属于 PR-A**:它们是随后 PR-C2 (2026-09-18 合入)追加到本端点的,服务「受控重开窗口」流程(见 `19_7442_团期配车受控重开窗口计划刷新状态收口-新增接口-管理后台.md`)。本文档按端点**当前**的完整契约 撰写(两次改动都已部署),但在字段表/错误码表里标注了各自的来源批次,避免误以为这是 PR-A 一次性交付的。 4. **`missingGroupCodes` 字段恒为空列表,不要依赖它判断缺组**:响应 `coverage.missingGroupCodes` 在任何路径上都只能是 `[]`——真的缺组时走的是抛 602002 异常的路径,根本不产生响应体,「缺组」这个结论 永远不会通过这个字段表达出来。前端如果要展示"缺哪些组",请用捕获到的 602002 错误消息(点名到组), 或改查 `GET /internal/fleet/dispatch/group-batch/{id}/coverage`(内部接口,见 `19_7442_团期配车受控重开窗口计划刷新状态收口-新增接口-管理后台.md` 第 4 条,那个端点的同名字段才有 非空的可能)。 --- ## 二、变更接口清单 | # | 接口 | 方法 | 路径 | 变更类型 | 说明 | |---|------|------|------|----------|------| | 1 | 整团逐日配车提交 | POST | `/admin/fleet/group-dispatch/batches/{groupBatchId}/reconfigure` | 新增(补登;PR-A 已部署 3 天) | 车务按乘车分组提交整团逐日配车计划,服务端与现状差量比对 | --- ## 三、接口详情 ### 1. 整团逐日配车提交 `POST /admin/fleet/group-dispatch/batches/{groupBatchId}/reconfigure` **VO**: `GroupDispatchReconfigureReqVO → GroupDispatchReconfigureRespVO` #### 使用场景 车务在团期配车页提交整团逐日配车计划(差量重配:多删少补,旧记录软删留痕,新需求新写,不整团作废重配)。 服务端以 order-v3 提供的权威团期基线(服务日、生命周期、权威乘车分组清单)校验:完整覆盖、无越界、无重复 且团期可配才允许提交。 #### 入参字段表 | 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | |------|------|------|------|------|------| | groupBatchId | Path | Long | 是 | - | 团期主订单 ID | | requirementId | Body | Long | 是 | - | 本次计划照着哪一份正式团级用车需求排;与基线不一致抛 602005 | | requirementVersion | Body | Integer | 是 | - | 本次计划照着需求的哪一版排;落后于基线当前版本抛 602005(fail-closed,不接受"反正车没变") | | clearAll | Body | Boolean | 否 | 默认 `false` | true=显式整团清零,软删该团全部活跃配车并释放车辆/司机占用,`demands` 可为空 | | reconfigureWindowToken | Body | String | 条件必填 | - | 【**PR-C2 追加**】受控重开窗口令牌,团期仍在 `RESOURCE_PREPARING` 时可不传;团期过了资源准备阶段后必填,且必须与 order-v3 下发的窗口令牌一致,否则 602012 | | demands | Body | Array | 条件必填 | `clearAll=false` 时非空 | 逐日配车需求;行程日期不可重复(600003) | | demands[].tripDate | Body | LocalDate | 是 | - | 行程日期 | | demands[].assignments | Body | Array | 是 | 至少一条 | 当日全部车/司机组合,非空(600004) | | demands[].assignments[].groupId | Body | String | 是 | ≤64 字符 | 乘车分组键(=需求侧 `group_code`,如 `BUS`);空抛 602000,不在基线清单抛 602001 | | demands[].assignments[].vehicleId | Body | Long | 是 | - | 派出车辆 ID;同日重复抛 600006(车辆被占) | | demands[].assignments[].driverId | Body | Long | 否 | - | 派出司机 ID;可空=仅排车未排司机;同日重复抛 600007(司机被占) | | demands[].assignments[].remark | Body | String | 否 | ≤200 字符 | 备注 | | survivorPolicy | Body | String | **条件必填** | - | 🔴 **【#7444 追加,2026-09-19 补列】** `clearAll=true` 且该团存在 active 车辆共用关系时**必填**,缺失抛 **602110**。完整取值与语义见 `19_7444_团期配车就绪门禁与车辆共用关系-修改接口-管理后台.md` | > 🔴 **2026-09-19 订正:本文档此前漏列了 5 个字段(入参 1 + 出参 4)。** > 它们由 **#7444** 追加到**同一个端点**上,源码里也标注为 #7444 > (`GroupDispatchReconfigureReqVO` / `GroupDispatchReconfigureRespVO`)。 > ⚠️ **漏列的后果是具体的**:本文档开头自称按端点**「当前的完整契约」**撰写, > 只读这一份的人会以为契约就这些,而 `clearAll=true` 时不传 `survivorPolicy` 会**直接被 602110 拒**。 > ⇒ 这 5 个字段的**完整语义在 #7444 那份文档里**,本文档只补列字段名与出处,不重复其内容。 > **教训**:「本端点的完整契约」这种自述,会在**别的工单往同一个端点加字段**时静默失效—— > 而加字段的人写的是他自己那份 changelog,不会回头改这一份。 #### 出参字段表 | 字段 | 类型 | 说明 | |------|------|------| | groupBatchId | String(雪花 ID) | 团期主订单 ID | | requirementId | String(雪花 ID) | 本次计划所依据的正式团级用车需求 ID | | requirementVersion | Integer | 本次计划所依据的需求版本 | | planVersion | Long | 本次落库后的团期计划版本;幂等短路时为当前版本,不递增 | | addedCount | Integer | 新增派车记录数 | | removedCount | Integer | 软删派车记录数(减员) | | keptCount | Integer | 保留未变派车记录数 | | updatedCount | Integer | 就地更新(换组/换司机/改备注)派车记录数 | | aliveCount | Integer | 提交后整团存活派车记录总数 | | addedDispatchIds | Array\(雪花 ID) | 新增派车记录主键列表 | | idempotentShortCircuit | Boolean | 本次是否被计划去重短路;`true`=计划与上次完全一致、本次未落库——**这是幂等成功,不是失败**,前端不要按错误提示 | | coverage | Object | 按乘车分组的覆盖明细,见下 | | coverage.groups[] | Array | 按组的覆盖明细 | | coverage.groups[].groupCode | String | 分组键 | | coverage.groups[].vehicleType | String | 车型文本/字典值 | | coverage.groups[].requiredDates | Array\ | 本组权威服务日 | | coverage.groups[].coveredDates | Array\ | 本次计划为本组实际排车的日期 | | coverage.groups[].missingDates | Array\ | 本组缺失的服务日 | | coverage.groups[].outOfRangeDates | Array\ | 本组越界的日期 | | coverage.groups[].satisfied | Boolean | 本组是否已满足 | | coverage.missingGroupCodes | Array\ | **恒为空列表**(见「⚠️ 关键变化」第 4 条),不要依赖它判断缺组 | | coverage.wholeBatchSatisfied | Boolean | 全团行程日整体覆盖是否成立 | | legacyGroupRowCount | Integer | 本团存活派车行里无分组键的历史行数(非错误,仅留痕,见 #7442 AC-32) | | releasedShareGroupIds | Array\ | 🔴 **【#7444 追加,2026-09-19 补列】** 本次被解除的车辆共用关系 ID | | keptSourceIds | Array\ | 🔴 **【#7444 追加】** 按 `survivorPolicy` 判定为保留的幸存派单 `sourceId` | | releasedSourceIds | Array\ | 🔴 **【#7444 追加】** 按 `survivorPolicy` 判定为释放的派单 `sourceId` | | pendingReassignSourceIds | Array\ | 🔴 **【#7444 追加】** 待重新改派的派单 `sourceId` | > ⚠️ 上面 4 个出参字段同 `survivorPolicy`,由 #7444 追加,**完整语义见 > `19_7444_团期配车就绪门禁与车辆共用关系-修改接口-管理后台.md`**,本文档只补列字段名与出处。 #### 请求示例 ```json POST /admin/fleet/group-dispatch/batches/1934567890123456800/reconfigure { "requirementId": 1934567890123456789, "requirementVersion": 3, "clearAll": false, "demands": [ { "tripDate": "2026-09-12", "assignments": [ {"groupId": "BUS", "vehicleId": 1001, "driverId": 2001, "remark": "大巴组"}, {"groupId": "SUV", "vehicleId": 1002, "driverId": 2002} ] } ] } ``` #### 响应示例 ```json { "code": 200, "message": "成功", "data": { "groupBatchId": "1934567890123456800", "requirementId": "1934567890123456789", "requirementVersion": 3, "planVersion": 7, "addedCount": 2, "removedCount": 0, "keptCount": 0, "updatedCount": 0, "aliveCount": 2, "addedDispatchIds": ["99011", "99012"], "idempotentShortCircuit": false, "coverage": { "groups": [ { "groupCode": "BUS", "vehicleType": "宇通33座大巴", "requiredDates": ["2026-09-12"], "coveredDates": ["2026-09-12"], "missingDates": [], "outOfRangeDates": [], "satisfied": true } ], "missingGroupCodes": [], "wholeBatchSatisfied": true }, "legacyGroupRowCount": 0 }, "success": true } ``` #### 空数据 / 降级响应 `clearAll=true` 时 `demands` 可为空数组,属正常请求形态(整团清零),响应仍返回完整对象, `removedCount` 反映本次软删的行数、`aliveCount=0`: ```json { "code": 200, "message": "成功", "data": { "groupBatchId": "1934567890123456800", "requirementId": "1934567890123456789", "requirementVersion": 3, "planVersion": 8, "addedCount": 0, "removedCount": 2, "keptCount": 0, "updatedCount": 0, "aliveCount": 0, "addedDispatchIds": [], "idempotentShortCircuit": false, "coverage": { "groups": [], "missingGroupCodes": [], "wholeBatchSatisfied": false }, "legacyGroupRowCount": 0 }, "success": true } ``` #### 错误响应 ```json { "code": 602002, "message": "以下乘车分组整组未排车: SUV", "data": null, "success": false } ``` 可能的错误码: - `600001` - 团期批次 ID 不能为空 - `600002` - 逐日配车需求不能为空 - `600003` - 逐日需求存在重复行程日期 - `600004` - 单日排车列表不能为空 - `600005` - 排车车辆 ID 不能为空 - `600006` - 车辆已被占用 - `600007` - 司机已被占用 - `600008` - 团期配车已被并发修改,请刷新后重试 - `600009` - 团期配车权威基线不可用,请稍后重试或检查团期状态 - `600010` - 团期当前状态不可配车 - `600011` - 配车计划未完整覆盖团期服务日 - `602000` - 排车项缺少乘车分组(PR-A) - `602001` - 乘车分组不存在于本团正式需求(PR-A) - `602002` - 以下乘车分组整组未排车(PR-A,**点名到组**,不是笼统的"缺日") - `602003` - 乘车分组的服务日未排满(PR-A) - `602004` - 乘车分组排了本组服务范围外的日期(PR-A) - `602005` - 用车需求已更新,请刷新后重新配车(PR-A) - `602006` - 正式用车需求当前状态不允许配车(PR-A) - `602009` - 无法取得本团的权威乘车分组清单(PR-A,**失败关闭**,两种成因:该团从没提交过正式用车需求,或需求存在但声明了整团免车) - `602010` - 配车入参非法(PR-A) - `602011` - 受控重开窗口内不允许整团清零配车(**PR-C2 追加**) - `602012` - 受控重开窗口校验不通过(**PR-C2 追加**,缺/错/过期令牌) - `602013` - 本次配车改动越出重开窗口授权范围(**PR-C2 追加**) - `809100` / `809101` - order-v3 经 Feign 解包透出(无活跃需求 / 需求状态不允许) #### 业务边界 - **鉴权**: `X-Admin-Role` 须为 `VEHICLE_MANAGER` 或 `SUPER_ADMIN`(`FleetAdminRoleGuardInterceptor` 角色门禁,**不是权限点**——工单原文与部分源码 javadoc 写的"权限点 `fleet:group-dispatch:write`"在数据库层从未注册,全仓 `*.sql` 搜不到这个字符串,见 #7444 的交接件(`changelogs-v2/2026-09/` 下按 `*_7444_*` 检索;本仓文件名带**提交日前缀**,会随提交日变,所以这里不写死文件名。⚠️ 起草期曾以 `…同团车辆共用关系-新增接口…` 为名,该稿已并入前者、名字不再存在) 的「关键变化」第 2 条详细核实过程) - **防重与幂等是两件事,不要混读**:①10 秒内对同一份计划重复提交会被 `@Idempotent` 防重窗口**拒绝** (返 100502「团期配车重配处理中,请勿重复提交」),前端按"稍后重试"处理;②窗口**之外**重复提交同一份 计划会正常受理并返回 `idempotentShortCircuit=true`——**那是成功**(计划未变、未落库、未产生新意图), 不要按错误提示。这两条机制彼此独立:前者按 10 秒时间窗判重,后者按计划内容摘要(`planDigest`)判重, 没有时间窗限制 - **各组服务日范围可以不同**:A 组走全程、B 组只用三天车时,B 组在第四、五天没有排车行是**正确的**, 不报缺日——这条既有口径未被 602003 削弱 - **不校验"是否能确认"**:本端点只管排车,"确认整团配车"是另一个独立端点 (`POST .../confirm`,见 `17_7442_团级确认态-需求已发车务回写-新增接口-管理后台.md`) --- ## 四、契约约束与正确调用方式 > 本节只写后端接受/拒绝 payload 的规则,不写 UI 渲染建议。 | 场景 | 做法 | |------|------| | 提交计划前需要拿团期权威分组清单 | 该清单在基线里,本端点自己不暴露一个单独的查询口;前端通常从团期需求/配车总览页拿到 | | 团期在 `RESOURCE_PREPARING` 阶段提交 | `reconfigureWindowToken` 可不传 | | 团期已过 `RESOURCE_PREPARING`(`MATERIAL_PREPARING`/`PENDING_DEPARTURE`)提交 | 必须先经受控重开端点(`POST .../vehicle-requirement/reopen`)拿到 `windowToken` 并原样带回,否则 602012 | | 需要整团清零 | 传 `clearAll=true`,`demands` 可省略 | | 判断"提交成功但计划没变" | 看 `idempotentShortCircuit`,为 `true` 时是成功,不是失败 | --- ## 五、数据库行为 | 操作 | 数据库影响 | |------|----------| | 正常提交(有增/删/改) | `fleet_group_dispatch` 差量写入:新增行 INSERT、软删行 `status` 置软删并留痕、就地更新行按需变更;`fleet_group_dispatch_plan.plan_version` CAS +1 | | `clearAll=true` | 该团全部活跃 `fleet_group_dispatch` 行软删,释放车辆/司机占用,`vehicle_ready` 重置为 false | | 幂等短路(`idempotentShortCircuit=true`) | 零写入,`plan_version` 不变 | --- ## 六、边界行为 - **无权威分组清单时失败关闭**(602009):不会因为拿不到分组就放行一份没有分母的计划 - **同日重复车辆/司机拒绝**(600006/600007):同一天同一辆车/同一名司机出现在两条排车项里直接拒绝,不做去重合并 - **服务日部分覆盖不是缺陷**:各组服务日范围可以不同,短组在超出自己范围的日子没有排车行是合法的 --- ## 部署清单(本单改了 hl-common-core,CODE_RULES §16.6) 本单在 `hl-common-core` 的 `GroupBatchDispatchBaselineDTO`(团期配车权威基线)新增 `requirementId`/ `requirementVersion`/`requirementStatus`/`groups` 四个字段,并新增 `GroupBatchVehicleGroupBaselineDTO` (乘车分组基线)全新类;order-v3 是这份基线的提供方,fleet 是消费方。 ### 滚动顺序分析:本单与 #7957(PR-C2)的"fleet 必须先滚"不同——本单两个方向都不会静默出错 - **order-v3 先滚**:order-v3 开始下发新字段(`groups[]` 等),此时 fleet 还是旧版——**旧版 fleet 压根没有 本单新增的 `POST /admin/fleet/group-dispatch/batches/{groupBatchId}/reconfigure` 端点**(该端点是本单 才新增的),不存在任何消费方读取这些新字段,**零风险**。 - **fleet 先滚**:fleet 的新端点已经存在,但调用旧版 order-v3 的基线接口时**拿不到 `groups` 字段** (Jackson 反序列化为 `null`)——fleet 侧的按组覆盖校验属于**失败关闭**设计(602009「无法取得本团的权威 乘车分组清单」),**这是本单与 PR-C2 最大的不同**:PR-C2 的 `dispatchable` 放宽会被旧 fleet 静默忽略、 放行了本不该放行的请求;本单缺 `groups[]` 则是**整个新端点在这段时间内全部请求都报 602009**——响应是 **明确的错误码,不是静默放行**,运营/车务会立刻发现"这功能用不了"而不是"这功能用了但结果不对"。 - **结论(⚠️ 只对本单这一次改动成立,不要拿它指导今天的部署)**:**单看本单**,两个方向都不会产生 数据错乱,区别只是"功能完全不可用一段时间"(fleet 先滚)还是"零影响"(order-v3 先滚)。 > 🔴 **2026-09-19 订正:上面那句"order-v3 先滚风险更低"是按本单单独算的,拿它指导实际部署会出事。** > PR-C2(#7957,2026-09-18 合入)**后来在同一个 `GroupBatchDispatchBaselineDTO` 上又加了 > `reconfigureWindow`**,而今天要部署的人面对的是**两次改动的并集**,不是本单。 > 对并集而言正确答案是 **fleet 必须先于 order-v3**:order-v3 先滚 ⇒ 旧 fleet 收到 `dispatchable=true` > 直接放行重配,它不读 `reconfigureWindow`、不校验令牌与范围 ⇒ **「受控重开」当场退化成「不受控重开」, > 而两端日志都正常、没有任何报错**(详见 `19_7442_团期配车受控重开窗口计划刷新状态收口…md`「部署清单」 > 与 PR [#7957](https://git.1814.love:8443/wx/HL/pulls/7957) 正文「⚠️ 部署:fleet 必须先于 order-v3」)。 > > ⚠️ 上面那段按单分析**本身没错、也标了范围**(见本节标题与开头那句「本单与 #7957 的『fleet 必须先滚』 > 不同」)——错的是**结论句把限定丢了**,读起来像是对这次部署的建议。 > **按单写的部署结论会在下一次改动落到同一个 DTO 上时变成陷阱**,而它不会报错、也没有人会回来改它。 > ⇒ 今后写部署顺序结论,一律带上「**截至 <日期/commit>,本 DTO 上还有哪些已合入的改动**」这个限定。 **⇒ 今天的实操答案:同批滚;必须分批时 `fleet` 先、`order-v3` 后。** ### 消费方清单不能按 `pom.xml` 直接依赖关系查 理由与判据同 `19_7442_团期配车受控重开窗口计划刷新状态收口-新增接口-管理后台.md`「部署清单」节—— `grep -rl 'hl-common-core' */pom.xml` 只命中 `hl-gateway`/`hl-finance`,order-v3 与 fleet 都经 `hl-common-web` 传递引入,不在直接依赖清单里,但正是本单真正改了代码的两个服务。 ⇒ **实际部署单位共 7 个**:gateway / user / resource / product-v2 / order-v3 / mp / fleet。 **同批滚**;必须分批时 **`fleet` 先、`order-v3` 后**(理由见上方 2026-09-19 订正框—— 本单自身不强制顺序,但同一个 DTO 上的 PR-C2 强制了,今天部署的是两者的并集)。 --- ## 七、不影响范围 - **仅影响**: 团期配车页的整团逐日提交动作 - **零影响**: - 确认整团配车 `POST .../confirm`(见 `17_7442_团级确认态-需求已发车务回写-新增接口-管理后台.md`) - 受控重开/计划刷新流程的其余 4 个端点(见 `19_7442_团期配车受控重开窗口计划刷新状态收口-新增接口-管理后台.md`) - 团期配车就绪判定、车辆共用关系(见 #7444 的交接件(`changelogs-v2/2026-09/` 下按 `*_7444_*` 检索;本仓文件名带**提交日前缀**,会随提交日变,所以这里不写死文件名。⚠️ 起草期曾以 `…同团车辆共用关系-新增接口…` 为名,该稿已并入前者、名字不再存在)) --- ## 八、测试环境已验证 ✅ **2026-09-19 已完成网关实测**(走网关,非直连)。部署基线:order-v3 与 fleet 均在 `31fd5b5e6`。 本文档只覆盖一个端点,**正负各测一次**,两次都达到「HTTP 200 + `success`/预先点名的错误码 + 至少一个本次改动相关字段并经数据库交叉核实」。 ### 1. 正常路径 夹具 `groupBatchId=2099951310525673474`。 ``` POST /admin/fleet/group-dispatch/batches/2099951310525673474/reconfigure → HTTP 200,success=true ``` | 断言字段 | 读数 | 说明 | |---|---|---| | `planVersion` | **2 → 3** | 真实递增,非固定值 | | `idempotentShortCircuit` | `false` | 本次确实走了写路径,不是幂等短路 | | `coverage.wholeBatchSatisfied` | `true` | 覆盖判定通过 | 落库交叉核实:`fleet_group_dispatch` 该团 **3 条**活跃行。 ### 2. 负向路径(**调用前即写明期望 602002**) 夹具 `groupBatchId=2100667751600148481`(BUS + SUV 双组团),故意只提交 BUS 组、漏掉 SUV 组。 ``` POST /admin/fleet/group-dispatch/batches/2100667751600148481/reconfigure → HTTP 200,code=602002 message="以下乘车分组整组未排车: SUV" ``` **消息点名了具体漏掉的组**,不是笼统失败。数据库交叉核实:调用前后 `fleet_group_dispatch` 行数**不变**(纯校验失败,**零写入**)。 > 🔴 **给下一个要复现 602002 的人**:**单组需求下 602002 在语法上不可达**。只要 `demands` 非空就必然映中至少一个组码;而若该组码不在权威清单里,会**先**触发 602001(`unknownGroupCodes` 的检查排在 `missingGroupCodes` 之前)。⇒ 复现 602002 必须用**双组及以上**的夹具。 > 🔴 **另一个坑**:旧夹具里遗留的 `vehicle_id=1001` 是 `fleet_vehicle` 表里**不存在的占位 ID**,拿它重提会被 **600006**(车辆被占,源头在 `fleet_assignment`)拦下。换成库里真实存在且当日空闲的车/司机才走得通。 **副作用**:主夹具全程经真实写口驱动、**零 SQL 直改**,终态与起始态结构等价,无需复位。 --- ## 十、相关文档 - 关联 Issue: [wx/HL#7442](https://git.1814.love:8443/wx/HL/issues/7442) - 关联 PR: [wx/HL#7844](https://git.1814.love:8443/wx/HL/pulls/7844)(PR-A,本端点首次交付); [wx/HL#7957](https://git.1814.love:8443/wx/HL/pulls/7957)(PR-C2,追加 `reconfigureWindowToken` 字段) - 相关文档: - `changelogs-v2/2026-09/17_7442_团级确认态-需求已发车务回写-新增接口-管理后台.md` - `changelogs-v2/2026-09/19_7442_团期配车受控重开窗口计划刷新状态收口-新增接口-管理后台.md` ## 关联 / 联系人 ### 链接 - **Issue**: [#7442](https://git.1814.love:8443/wx/HL/issues/7442) - **PR**: [#7844](https://git.1814.love:8443/wx/HL/pulls/7844) - **Merge commit**: [8eb8e13cdfd4a8cc004f95cfb53f7e4b81904461](https://git.1814.love:8443/wx/HL/commit/8eb8e13cdfd4a8cc004f95cfb53f7e4b81904461) ### 联系人 - **后端负责人**: @wx