diff --git a/docs/superpowers/specs/2026-07-30-wcs-dispatch-traffic-demo-design.md b/docs/superpowers/specs/2026-07-30-wcs-dispatch-traffic-demo-design.md new file mode 100644 index 0000000..cd79313 --- /dev/null +++ b/docs/superpowers/specs/2026-07-30-wcs-dispatch-traffic-demo-design.md @@ -0,0 +1,258 @@ +# WCS 中心调度与交通管制 Demo 设计 + +## 1. 背景与目标 + +本设计依据 `01-P0-A现有链路稳固实施计划.md`,在 `FT546-WCS` 优化工作树根目录新增独立的 `javaTest` Maven 项目,用纯 Java 内存模型模拟 WCS 中心调度与交通管制。 + +Demo 的目标是: + +1. 建立一个可运行的调度中心,模拟每周期任务准入、车辆分配、路径规划、交通管制、任务下发和完成。 +2. 用真实 JUnit 5 测试覆盖关键调度规则,确保测试数量大于 0。 +3. 固化当前 LEGACY 链路的重要语义,为后续从 `BaseSRgvThread` 提取可测试边界提供参考。 +4. 输出可读的控制台事件,使开发人员能观察每个周期的决策原因和状态变化。 + +## 2. 范围与约束 + +### 2.1 范围内 + +- 独立 Maven 项目 `javaTest`。 +- Java 8 源码兼容。 +- JUnit 5 自动测试。 +- 内存车辆快照、业务任务、调度队列、地图和事件记录。 +- 每周期一次任务准入。 +- 确定性车辆选择。 +- 网格最短路径、路径占用和通道占用。 +- 避让任务生成。 +- 模拟协议下发与队列状态流转。 +- 命令行 Demo 场景。 + +### 2.2 范围外 + +- 不修改生产 `BaseSRgvThread`、`PlcSrgvRead` 或数据库表。 +- 不连接 SQL Server、PLC、WMS 或 Spring 容器。 +- 不发送真实 PLC 指令。 +- 不建立生产中央路权服务,不写交通运行表。 +- 不启用 SHADOW 或 ACTIVE 模式。 +- 不使用 `default02` 至 `default08` 保存新增交通状态。 +- 不猜测 PLC 寄存器偏移或载货字段布局。 + +Demo 中的“调度中心”只协调内存任务、车辆与路径,不改变 P0-A 的 LEGACY 生产控制边界。 + +## 3. 方案选择 + +采用独立 Maven 项目,而不是加入现有 Reactor 或直接放入 `ruoyi-admin/src/test`。 + +理由: + +- 可独立运行,不污染生产 Reactor 和依赖关系。 +- 不需要 Spring、MyBatis、HslCommunication 或数据库。 +- 能强制使用 JUnit 5 和现代 Surefire,避免现有工程“构建成功但测试数为 0”的假阳性。 +- 后续可把验证成熟的纯领域服务迁移到生产模块。 + +## 4. 目录结构 + +```text +javaTest/ +├── pom.xml +├── README.md +└── src/ + ├── main/java/com/ft546/wcs/demo/ + │ ├── DemoApplication.java + │ ├── center/ + │ ├── model/ + │ ├── repository/ + │ ├── traffic/ + │ └── simulation/ + └── test/java/com/ft546/wcs/demo/ +``` + +包边界如下: + +- `model`:不可变输入快照和明确的状态枚举。 +- `center`:调度周期、任务准入和车辆选择。 +- `traffic`:路径规划、资源占用与避让决策。 +- `repository`:内存任务、队列和历史。 +- `simulation`:场景构造、周期推进和事件输出。 + +## 5. 核心模型 + +### 5.1 车辆快照 + +`VehicleSnapshot` 至少包含: + +- `vehicleId` +- `floor` +- `currentSite` +- `workMode` +- `status` +- `battery` +- `connected` +- `allowSend` +- `cargo` + +快照不可变。车辆只有同时满足在线、自动模式 `workMode=5`、空闲 `status=1`、允许下发且电量大于 30 时才具备普通任务资格。 + +### 5.2 业务任务 + +`DispatchTask` 包含: + +- `taskId` +- `type` +- `sourceSite` +- `targetSite` +- `floor` +- `priority` +- `state` + +Demo 支持入库、出库和移库的统一调度输入,但不模拟真实 WMS 回调。 + +### 5.3 调度队列 + +`DispatchQueueEntry` 使用明确字段表达: + +- `taskId` +- `vehicleId` +- `queueType` +- `startSite` +- `endSite` +- `priority` +- `issued` +- `executionStatus` +- `path` + +状态语义与旧链路保持一致: + +- 新建:`issued=0`、`executionStatus=1` +- 下发成功:`issued=1`、`executionStatus=3` +- 完成:`executionStatus=4`,随后归档并从活动队列删除 + +避让任务使用 `queueType=AVOIDANCE` 和优先级 9,不把新增交通状态塞入旧扩展字段。 + +## 6. 调度中心 + +`LegacyDispatchCenter.runCycle()` 是每个模拟周期的唯一入口,固定顺序为: + +1. 冻结当轮车辆快照,并按 `vehicleId` 排序。 +2. 调用一次 `QueueAdmissionService.createPendingQueues()`。 +3. 对未分配业务任务调用 `VehicleAssignmentService.select()`。 +4. 对每辆车处理已有队列。 +5. 调用 `TrafficController.plan()` 获得路径、等待或避让决策。 +6. 通过 `SimulatedProtocolAdapter` 模拟指令下发。 +7. 根据车辆位置推进队列完成和历史归档。 + +无论车辆数是多少,每周期业务准入只能调用一次。 + +## 7. 确定性车辆选择 + +车辆选择采用稳定比较顺序: + +1. 不符合资格的车辆排除,并记录排除原因。 +2. 同楼层优先。 +3. 绝对楼层差更小者优先。 +4. 保留旧链路的 Y 距离优先、X 距离次优语义。 +5. 全部相同时,`vehicleId` 字典序更小者优先。 + +站点编码必须能解析为坐标。编码无效时返回 `REJECT_INVALID_SITE`,不得按坐标 0 静默参与比较。 + +`VehicleAssignmentDecision` 必须包含被选车辆和可读的选择理由;没有可用车辆时返回明确的 HOLD 决策。 + +## 8. 交通管制 + +### 8.1 地图与路径 + +`GridMap` 保存可通行点及站点坐标。`GridPathPlanner` 使用确定性最短路径算法,只允许通过可通行节点。 + +每次规划前,`TrafficController` 从当前内存状态构建占用视图: + +- 锁定其他车辆队列中从其当前位置开始的剩余路径。 +- 锁定离线车辆当前位置。 +- 锁定场景中声明不可用的提升机或障碍点。 + +占用视图只存在于当前模拟周期,不写数据库。 + +### 8.2 通道与路径冲突 + +如果目标通道存在同层阻挡车辆: + +- 阻挡车辆没有活动队列时,为其生成高优先级避让任务。 +- 当前业务任务返回 `HOLD_CHANNEL_BLOCKED`。 +- 避让任务完成并删除后,下一周期重新规划。 + +如果路径被其他车辆占用但存在替代路线,则规划绕行;没有替代路线时返回 `HOLD_NO_PATH`。 + +同一阻挡车辆在已有避让队列时不得重复创建避让任务。 + +## 9. 协议模拟与状态流转 + +`SimulatedProtocolAdapter` 只记录命令,不进行 I/O。它支持成功和可注入失败两种结果: + +- 成功时,队列更新为 `issued=1`、`executionStatus=3`。 +- 失败时,队列保持未下发状态,并记录 `HOLD_PROTOCOL_FAILURE` 及失败原因。 +- 同一队列已成功下发后不得重复发送。 + +模拟器把车辆移动到路径下一站。到达目标站后: + +- 普通任务归档业务历史并删除活动队列。 +- 避让任务只归档避让事件并删除活动队列。 +- 删除队列后,其路径占用在下一周期自然释放。 + +## 10. 错误处理 + +Demo 使用决策结果表达预期异常,不使用空值表示失败: + +- `HOLD_NO_ELIGIBLE_VEHICLE` +- `REJECT_INVALID_SITE` +- `HOLD_NO_PATH` +- `HOLD_CHANNEL_BLOCKED` +- `HOLD_PROTOCOL_FAILURE` + +构造时拒绝重复任务号、重复车辆号和缺失地图站点。不可恢复的模型错误抛出 `IllegalArgumentException`;调度等待条件作为正常决策返回。 + +## 11. 模拟场景 + +`DemoApplication` 至少运行以下场景: + +1. 三辆车、一个业务任务:证明每周期只准入一次,并稳定选出车辆。 +2. 同层与跨层车辆竞争:证明同层、楼层差、Y/X 距离和车辆编号裁决。 +3. 其他车辆剩余路径占用:证明绕行或等待。 +4. 同通道阻挡:生成优先级 9 的避让任务,当前车等待。 +5. 避让完成:删除避让队列,下一周期原任务重新规划并下发。 +6. 无可达路径:返回 `HOLD_NO_PATH`,不抛异常。 +7. 协议失败后重试:第一次保持未下发,下一周期成功进入执行中。 +8. 到达目标:队列完成、归档并释放路径。 + +控制台按周期输出任务、车辆、选车原因、路径、HOLD 原因、队列状态和历史结果。 + +## 12. 自动测试 + +JUnit 5 测试至少覆盖: + +- `LegacyDispatchCenterTest`:三车每周期只准入一次、稳定处理顺序。 +- `VehicleAssignmentServiceTest`:资格过滤、同层优先、楼层差、Y/X 距离、稳定裁决和无效站点。 +- `TrafficControllerTest`:路径锁、离线点、绕行、无路、通道阻挡、避让去重和释放。 +- `QueueLifecycleTest`:新建、下发、失败重试、完成归档和幂等。 +- `DemoScenarioTest`:端到端运行关键场景并验证真实事件结果。 + +验证命令: + +```bash +cd javaTest +mvn test +mvn exec:java +``` + +验收时必须从 Surefire 报告确认测试数量大于 0、失败数为 0、错误数为 0;不能只依据 Maven 退出码。 + +## 13. 验收标准 + +满足以下条件才认为 Demo 完成: + +1. 工作树根目录存在独立 `javaTest` Maven 项目。 +2. 源码编译目标为 Java 8。 +3. 调度中心真实执行每周期一次准入和逐车处理。 +4. 确定性选车规则及理由可测试。 +5. 交通管制能处理路径锁、通道阻挡、避让任务和占用释放。 +6. 队列状态按 LEGACY 语义流转。 +7. `DemoApplication` 可运行并打印完整模拟结果。 +8. JUnit 5 测试数量大于 0,全部通过。 +9. 项目不访问真实数据库、PLC 或 WMS,不修改生产控制代码。