--- schema: "hl-changelog/v2" ticket: "5374" title: "保险任务与派单候选补齐真实团号契约" consumer: "admin" change_type: "修改接口" backend_status: "deployed" gateway_status: "verified" frontend_status: "implemented" frontend_owner: "Pi" frontend_ref: "v2.1@193575171d817f1042040baf8e0d9d28e7206048" target_release: "" verified_at: "2026-08-03" status_note: "后端 PR #5415 已合并为 dev-v3@ee7ad816b;测试部署任务 23928056 双实例健康,保险任务与派单候选经网关真登录验证,Flyway 001/002、nullable VARCHAR(32)、回填收敛和普通 EXPLAIN 均通过;管理后台已由 Pi 领取,正在适配。" updated_at: "2026-08-03" base: "dev-v3" --- # Fleet:保险任务与派单候选补齐真实团号契约 > **服务**: hl-fleet-service (端口 8087) > **PR**: [wx/HL#5415](https://git.1814.love:8443/wx/HL/pulls/5415) > **Issue**: [wx/HL#5374](https://git.1814.love:8443/wx/HL/issues/5374) > **日期**: 2026-08-02 > **影响范围**: 管理后台车务保险任务列表与派单候选冲突提示 --- ## 一、关键变化 - 保险任务列表新增独立 `teamNo` 团号 contains 查询,并在任务项返回真实 `teamNo`。 - 派单候选的车辆、司机冲突快照新增真实 `teamNo`。 - 无团号统一返回 `null`,**禁止回退或伪装为 `orderNo`**;现有订单号和雪花 ID 字符串序列化契约不变。 --- ## 变更接口 | # | 接口 | 方法 | 路径 | 变更类型 | 说明 | |---|---|---|---|---|---| | 1 | 司机险任务/流水分页 | GET | `/admin/fleet/insurance/tasks` | 请求与响应字段新增 | 新增 `teamNo` 查询及任务团号 | | 2 | 派单车辆/司机候选 | POST | `/admin/fleet/assignments/candidates` | 嵌套响应字段新增 | 两类 `conflicts[]` 新增真实团号 | --- ## 三、接口详情 ### 1. 司机险任务/流水分页 `GET /admin/fleet/insurance/tasks` **请求 VO**: `FleetInsuranceTaskPageReqVO` #### 新增入参 | 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | |---|---|---|---|---|---| | `teamNo` | Query | String | 否 | contains 模糊匹配 | 只搜索团号;不会 OR 匹配订单号;过滤在分页前完成 | #### 新增出参 `Result>` | 字段 | 类型 | 说明 | |---|---|---| | `data.records[].teamNo` | `String|null` | 保险任务冻结的真实团号快照;无团号返回 `null` | 请求示例: ```http GET /admin/fleet/insurance/tasks?teamNo=2607&page=1&pageSize=20 ``` 响应字段示例: ```json { "code": 200, "data": { "records": [ { "taskId": "9007199254740993", "orderId": "9007199254740995", "orderNo": "26-0701", "teamNo": "HL-2607-001" } ], "total": 1, "page": 1, "pageSize": 20 }, "success": true } ``` ### 2. 派单车辆/司机候选 `POST /admin/fleet/assignments/candidates` **响应 VO**: `AssignmentCandidateRespVO.ConflictVO` #### 新增出参 | 字段 | 类型 | 说明 | |---|---|---| | `data.vehicles.records[].conflicts[].teamNo` | `String|null` | 冲突派单的 Fleet 本地真实团号快照 | | `data.vehicles.list[].conflicts[].teamNo` | `String|null` | `records` 的兼容序列化别名,字段一致 | | `data.drivers.records[].conflicts[].teamNo` | `String|null` | 冲突派单的 Fleet 本地真实团号快照 | | `data.drivers.list[].conflicts[].teamNo` | `String|null` | `records` 的兼容序列化别名,字段一致 | 响应片段: ```json { "vehicles": { "records": [ { "vehicleId": "101", "conflicts": [ { "assignmentId": "9001", "assignmentGroupId": "9101", "orderNo": "26-0701", "teamNo": "HL-2607-001", "blocking": true, "reasonCode": "ASSIGNMENT_CONFLICT" } ] } ] }, "drivers": { "records": [ { "driverId": "201", "conflicts": [ { "assignmentId": "9001", "assignmentGroupId": "9101", "orderNo": "26-0701", "teamNo": null, "blocking": true, "reasonCode": "ASSIGNMENT_CONFLICT" } ] } ] } } ``` --- ## 四、契约约束与正确调用方式 - 前端展示团号必须读取 `teamNo`;值为 `null` 时展示 `-`。 - 不得把 `orderNo` 当作团号回退值。 - `orderNo`、`orderId`、`assignmentId`、`assignmentGroupId` 继续保留;雪花 ID 继续按 JSON String 返回,用于路由和动作。 - `teamNo` 只增加展示与查询能力,不改变候选 `available`、`blocking`、同城首尾衔接、可用窗口或派单写侧锁内复核。 - 保险任务查询的 `teamNo` 是独立参数,不沿用派车看板兼容匹配订单号的既有语义。 --- ## 五、数据库行为 - `fleet_insurance_task.team_no VARCHAR(32) NULL` 与 `fleet_assignment.team_no` 对齐。 - nullable DDL 与历史回填 DML 使用两个独立 Flyway 版本。 - 历史数据仅按 `assignment_id` 从 `fleet_assignment.team_no` 回填。 - 无匹配派单、来源团号为空或任务已有非空团号时保持原值;不跨服务查询、不按订单号猜测。 ### 生产两阶段迁移门禁(本单未授权、未执行生产) 1. 第一阶段必须设置 `SPRING_FLYWAY_TARGET=20260802.001`,只允许 nullable DDL 落库;禁止携带默认 `latest` 直接滚动发布。 2. 完成 Fleet Java 全量滚动并确认所有旧实例退出;此时新写入已冻结 `teamNo`,不会再产生旧代码造成的新增空快照。 3. 重新只读统计待回填数、可匹配数并执行普通 `EXPLAIN`;影响行数 ≤ 50k、扫描行数 ≤ 200k、staging 单事务 ≤ 5s、锁等待 ≤ 1s、复制延迟增量 ≤ 2s 才可继续。 4. 第二阶段才移除 target 或设置 `SPRING_FLYWAY_TARGET=20260802.002`,由受控单实例执行幂等 DML,再核验 Flyway history 与剩余空值。 5. 任一阈值超限或证据缺失即停止第二阶段,改用 1k–5k 行受控分批;生产禁止 `EXPLAIN ANALYZE UPDATE`。 --- ## 六、边界行为 - `teamNo` 完整或部分关键词均按 contains 命中。 - 只有 `orderNo` 含关键词而 `teamNo` 不含时,不命中保险任务列表。 - 历史任务或冲突派单没有团号时,响应字段为 `null`,接口不异常。 - 空 `teamNo` 等同不启用该筛选;其他现有筛选条件与其按 AND 组合。 --- ## 七、不影响范围 - 不修改派车矩阵、甘特、车务工作台或派车看板字段与搜索语义。 - 不修改司机档案 `relatedOrders`。 - 不新增 order-v3 Feign,不修改 `hl-common-feign`、内部接口或共享 Java DTO。 - 不修改 `hl-ui`。 --- ## 验证证据 - 定向测试:226 项通过,0 failures、0 errors、0 skipped。 - Fleet Spotless:通过。 - JaCoCo changed executable lines:9/9(100%)。 - 独立 Reviewer(max):无 P0–P2。 - oasdiff:项目缺少可复现 Swagger 2 → OAS3 转换链,标记 `not_configured`;已完成源码级手工契约对比。 - MySQL 8.0.33 隔离实例:`FleetInsuranceTaskTeamNoMysqlTest` 3/3 通过,0 skipped;H2 全迁移回归 `FleetInsuranceTaskMigrationTest` 8/8 通过。 - Fleet 全模块 `verify` 已执行 2764 项;接入本单隔离 Redis 后相关 4 项通过且无 key 残留,当前仅余 3 项基线失败(Release E Windows 时序 2 项、保险并发夹具 1 项,后者已在未含本单改动的 `dev-v3@a999a3df7` 同样复现),未将该次命令记为通过。 - 测试部署及网关真实 round-trip 结果将在后端完成后更新本文件元数据与本节。 --- ## 九、前端消费动作 1. 保险任务列表筛选增加 `teamNo` 参数,并按 `data.records[].teamNo` 展示团号。 2. 派单候选的车辆/司机冲突提示改用各自 `conflicts[].teamNo` 展示团号。 3. `teamNo === null` 时展示 `-`,不得显示 `orderNo` 作为替代团号。 4. 保留现有 ID 与订单号用于路由、动作及兼容逻辑。 ## 关联 / 联系人 ### 联系人 - **后端负责人**: @wx