# 堆垛机出库任务 TargetAddress 不可用时继续搜索 设计文档 ## 1. 背景与目标 在 `StackerCraneTaskSelector.SelectTask` 方法中,当 `TrySelectOutboundTask` 因 `TargetAddress` 输送线站台不空闲(`CV_State != 2`)而返回 null 时,需要继续搜索其他可选的出库任务,而不是直接返回 null 或仅尝试不同 NextAddress 的任务。 ## 2. 设计方案 ### 2.1 搜索顺序 当 TargetAddress 不可用时,按以下顺序搜索备选任务: 1. **同 NextAddress 的其他任务** - 查询与当前任务 NextAddress 相同的其他出库任务,尝试其 TargetAddress 是否可用 2. **不同 NextAddress 的任务** - 查询其他站台(N extAddress 不同)的出库任务(现有逻辑) ### 2.2 代码修改 在 `SelectTask` 方法中,`TrySelectOutboundTask(candidateTask)` 返回 null 之后、现有备选任务循环之前,插入同 NextAddress 任务搜索逻辑: ```csharp // 尝试选择出库任务 Dt_Task? selectedTask = TrySelectOutboundTask(candidateTask); if (selectedTask != null) { return selectedTask; } // ===== TargetAddress 不可用时,先尝试同 NextAddress 的其他任务 ===== // 查询与当前任务 NextAddress 相同的其他出库任务 var sameStationTasks = _taskService .QueryStackerCraneOutTasks(deviceCode, new List { candidateTask.NextAddress }) .Where(x => x.TaskId != candidateTask.TaskId) .ToList(); foreach (var sameStationTask in sameStationTasks) { selectedTask = TrySelectOutboundTask(sameStationTask); if (selectedTask != null) { QuartzLogHelper.LogDebug(_logger, $"选中同站台备选出库任务,任务号: {selectedTask.TaskNum}", commonStackerCrane.DeviceName); return selectedTask; } } // ===== 同 NextAddress 无可用任务,尝试不同 NextAddress 的任务(现有逻辑)===== var otherOutStationCodes = _routerService .QueryNextRoutes(deviceCode, candidateTask.NextAddress, candidateTask.TaskType) .Select(x => x.ChildPosi) .ToList(); var tasks = _taskService.QueryStackerCraneOutTasks(deviceCode, otherOutStationCodes); foreach (var alternativeTask in tasks) { selectedTask = TrySelectOutboundTask(alternativeTask); if (selectedTask != null) { QuartzLogHelper.LogDebug(_logger, $"选中备选出库任务,任务号: {selectedTask.TaskNum}", commonStackerCrane.DeviceName); return selectedTask; } } ``` ### 2.3 无需新增方法 利用现有的 `QueryStackerCraneOutTasks(deviceCode, stationCodes)` 方法,传入单站台列表即可查询同 NextAddress 的任务。过滤掉当前任务(`TaskId` 不同)避免重复尝试。 ### 2.4 流程图 ``` SelectTask ↓ TrySelectOutboundTask(candidateTask) ↓ TargetAddress 可用?否 → 返回 null ↓ 查询同 NextAddress 的其他出库任务 ↓ 遍历同站台任务 → TrySelectOutboundTask(task) → 可用 → 返回任务 → 不可用 → 继续下一个 ↓ 同 NextAddress 无可用任务 ↓ 查询不同 NextAddress 的出库任务(现有逻辑) ↓ 遍历 → 返回可用任务 / 无可用 → 返回 null ``` ## 3. 涉及的命名空间 无需新增 using,现有方法签名已满足。 ## 4. 风险与约束 - `TaskId` 作为唯一标识用于过滤已尝试任务,假设任务表中无重复 TaskId - `QueryStackerCraneOutTasks` 返回的任务列表需要考虑排序(如果有业务规则决定优先级) - 如果同 NextAddress 有大量任务,可能增加选择延迟