# OutboundTaskFlowService.MoveToNextStatus TODO 设计方案
## 背景
`OutboundTaskFlowService.MoveToNextStatus` 方法中存在一个 TODO:
```csharp
if (task.TaskStatus == (int)TaskOutStatusEnum.Line_OutFinish && task.TaskType == (int)TaskOutboundTypeEnum.Outbound)
{
return WebResponseContent.Instance.OK();
// Todo:获取对向线体是否有托盘号,如果有托盘号直接生成机械手任务
return GetWMSOutboundTrayTask(task);
}
```
该 TODO 需要在出库任务到达 `Line_OutFinish` 状态时,检查对向线体是否有托盘号,以决定后续机械手任务的创建方式。
## 业务逻辑
出库任务流程中,当物料通过输送线到达目标位置后:
- **对向线体有托盘号** → 托盘上有货,直接在本地创建机械手任务执行换盘/组盘/拆盘
- **对向线体无托盘号** → 需要从 WMS 获取空托盘出库任务
## 方案选择
**采用方案 B**:在 `RobotTaskService` 中封装检查逻辑,复用已有的 `BuildRobotTaskStock` 基础设施。
### 原因
- `RobotTaskService.BuildRobotTaskStock` 已实现通过 `AddressSourceLineNoMap` 解析源线体编号,并通过设备通信读取 `Barcode` 的完整逻辑
- 新增方法职责单一:检查 → 决策,仅做判断不执行副作用
- `OutboundTaskFlowService` 保持简洁,只需调用即可
## 实现设计
### 1. RobotTaskService 新增方法
```csharp
///
/// 检查源线体是否有托盘号,并根据结果创建机械手任务。
///
/// 出库任务实体
///
/// 有托盘号时返回 CreateLocalRobotTask 结果;
/// 无托盘号时返回 GetWMSOutboundTrayTask 结果。
///
public WebResponseContent CheckSourceLineAndCreateRobotTask(Dt_Task task)
{
// 1. 获取源线体编号(复用已有逻辑)
string configKey = ResolveRobotTaskConfigKey(task.TargetAddress);
StockDTO stock = BuildRobotTaskStock(task, configKey);
string sourceLineNo = stock.SourceLineNo;
if (string.IsNullOrWhiteSpace(sourceLineNo))
{
return GetWMSOutboundTrayTask(task);
}
// 2. 通过设备通信读取线体托盘号
string? palletCode = ReadLineBarcode(sourceLineNo);
if (!string.IsNullOrWhiteSpace(palletCode))
{
// 有托盘号,本地创建机械手任务
return CreateLocalRobotTask(task);
}
// 无托盘号,从 WMS 获取任务
return GetWMSOutboundTrayTask(task);
}
///
/// 读取指定线体的托盘号。
///
private string? ReadLineBarcode(string sourceLineNo)
{
try
{
IDevice? device = Storage.Devices.FirstOrDefault(x =>
x.DeviceProDTOs.Any(d => d.DeviceChildCode == sourceLineNo));
if (device == null)
return null;
CommonConveyorLine conveyorLine = (CommonConveyorLine)device;
return conveyorLine.GetValue(
ConveyorLineDBNameNew.Barcode, sourceLineNo);
}
catch
{
return null;
}
}
```
### 2. OutboundTaskFlowService 修改
```csharp
if (task.TaskStatus == (int)TaskOutStatusEnum.Line_OutFinish && task.TaskType == (int)TaskOutboundTypeEnum.Outbound)
{
// 获取对向线体是否有托盘号,如果有托盘号直接生成机械手任务
return _robotTaskService.CheckSourceLineAndCreateRobotTask(task);
}
```
## 数据流
```
MoveToNextStatus (OutboundTaskFlowService)
│
▼
CheckSourceLineAndCreateRobotTask (RobotTaskService)
│
├───► BuildRobotTaskStock ──► ResolveRobotTaskConfigKey
│ └──► AddressSourceLineNoMap 获取 sourceLineNo
│
▼
ReadLineBarcode(sourceLineNo)
│
├───► Storage.Devices 查找设备
└───► CommonConveyorLine.GetValue(Barcode)
│
▼
┌───────┴───────┐
│ 托盘号有值 │ 托盘号为空
▼ ▼
CreateLocalRobotTask GetWMSOutboundTrayTask
```
## 错误处理
- 设备查找失败或读取异常 → 降级为调用 `GetWMSOutboundTrayTask`(从 WMS 获取任务)
- 不阻塞主流程,异常仅记录日志
## 涉及文件
| 文件 | 改动 |
|------|------|
| `WIDESEAWCS_TaskInfoService/RobotTaskService.cs` | 新增 `CheckSourceLineAndCreateRobotTask` 和 `ReadLineBarcode` 方法 |
| `WIDESEAWCS_TaskInfoService/Flows/OutboundTaskFlowService.cs` | 替换 TODO 代码段为委托调用 |
## 验证要点
1. 当输送线有料时,机械手任务直接本地创建,不调用 WMS 接口
2. 当输送线无料时,降级调用 WMS 获取空托盘任务
3. 异常场景不阻塞主流程,降级到 WMS 获取