For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: 在WMS界面上添加手动创建任务功能,支持入库/出库/移库三种类型,任务发送至WCS后,WCS判断起点为线体点位(11068/11010/11001)时写入输送线任务。
Architecture: WMS前端Vue页面 → WMS后端API → WCS ReceiveTask → WCS FlowService判断并写入输送线PLC
Tech Stack: .NET 6 (WMS/WCS Backend), Vue3 (WMS Frontend), MapsterMapper, SqlSugar
| 文件 | 职责 |
|---|---|
WMS/WIDESEA_WMSClient/src/extension/taskinfo/task.js |
添加手动创建任务按钮和处理逻辑 |
WMS/WIDESEA_WMSServer/WIDESEA_DTO/Task/CreateManualTaskDto.cs |
新建 - 手动创建任务请求DTO |
WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/TaskInfo/TaskController.cs |
添加 CreateManualTask 接口 |
WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService.cs |
添加 CreateManualTaskAsync 方法 |
WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/TaskService.cs |
ReceiveWMSTask 已有分发逻辑,确认入口正确 |
WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/Flows/InboundTaskFlowService.cs |
添加线体点位判断和输送线任务写入逻辑 |
文件:
- Modify: WMS/WIDESEA_WMSClient/src/extension/taskinfo/task.js:16
在 task.js 的 buttons: { view: [], box: [], detail: [] } 中添加:
buttons: {
view: [],
box: [
{
value: 'CreateManualTask',
label: '手动创建任务',
onClick: function () {
// 弹出手动创建任务对话框
this.$refs.grid.openModel('Add');
}
}
],
detail: []
},
在 components.modelFooter 添加 Vue 模板(如果框架支持自定义弹窗内容),或使用框架内置的 openModel 配合 addBefore 处理。
注意: 具体的弹窗实现取决于当前前端框架的扩展机制。若当前页面不支持自定义字段,则需要在
task.vue中添加新的页面组件,或通过modelBody扩展自定义表单。
git add WMS/WIDESEA_WMSClient/src/extension/taskinfo/task.js
git commit -m "feat(WMS): 添加手动创建任务按钮"
文件:
- Create: WMS/WIDESEA_WMSServer/WIDESEA_DTO/Task/CreateManualTaskDto.cs
using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;
using WIDESEA_Common.TaskEnum;
namespace WIDESEA_DTO.Task
{
/// <summary>
/// 手动创建任务请求DTO
/// </summary>
public class CreateManualTaskDto
{
/// <summary>
/// 任务类型:1=入库, 2=出库, 3=移库
/// </summary>
[JsonPropertyName("taskType")]
[Required(ErrorMessage = "任务类型不能为空")]
public TaskTypeEnum TaskType { get; set; }
/// <summary>
/// 起点地址
/// </summary>
[JsonPropertyName("sourceAddress")]
[Required(ErrorMessage = "起点地址不能为空")]
public string SourceAddress { get; set; }
/// <summary>
/// 终点地址
/// </summary>
[JsonPropertyName("targetAddress")]
[Required(ErrorMessage = "终点地址不能为空")]
public string TargetAddress { get; set; }
/// <summary>
/// 条码
/// </summary>
[JsonPropertyName("barcode")]
[Required(ErrorMessage = "条码不能为空")]
public string Barcode { get; set; }
/// <summary>
/// 仓库ID
/// </summary>
[JsonPropertyName("warehouseId")]
[Required(ErrorMessage = "仓库ID不能为空")]
public int WarehouseId { get; set; }
/// <summary>
/// 优先级,默认1
/// </summary>
[JsonPropertyName("grade")]
public int Grade { get; set; } = 1;
}
}
git add WMS/WIDESEA_WMSServer/WIDESEA_DTO/Task/CreateManualTaskDto.cs
git commit -m "feat(WMS): 新增CreateManualTaskDto"
文件:
- Modify: WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/TaskInfo/TaskController.cs
在 TaskController 类中添加:
/// <summary>
/// 手动创建任务
/// </summary>
/// <param name="dto">手动创建任务参数</param>
/// <returns></returns>
[HttpGet, HttpPost, Route("CreateManualTask"), AllowAnonymous]
public async Task<WebResponseContent?> CreateManualTaskAsync([FromBody] CreateManualTaskDto dto)
{
return await Service.CreateManualTaskAsync(dto);
}
git add WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/TaskInfo/TaskController.cs
git commit -m "feat(WMS): 添加手动创建任务接口 CreateManualTask"
文件:
- Modify: WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService.cs
首先查看现有 TaskService.cs 结构,确认方法签名格式。
在 TaskService 类中添加(参考 CreateAutoOutboundTasksAsync 的模式):
/// <summary>
/// 手动创建任务
/// </summary>
/// <param name="dto">手动创建任务参数</param>
/// <returns></returns>
public async Task<WebResponseContent> CreateManualTaskAsync(CreateManualTaskDto dto)
{
try
{
// 1. 生成任务号
int taskNum = await BaseDal.GetTaskNo();
// 2. 根据任务类型确定状态值
int taskStatus = dto.TaskType switch
{
TaskTypeEnum.Inbound => TaskInStatusEnum.InNew.GetHashCode(), // 200
TaskTypeEnum.Outbound => TaskOutStatusEnum.OutNew.GetHashCode(), // 100
TaskTypeEnum.Relocation => TaskRelocationStatusEnum.New.GetHashCode(), // 300
_ => TaskStatusEnum.New.GetHashCode()
};
// 3. 构建任务实体
var task = new Dt_Task
{
TaskNum = taskNum,
PalletCode = dto.Barcode,
SourceAddress = dto.SourceAddress,
TargetAddress = dto.TargetAddress,
TaskType = dto.TaskType.GetHashCode(),
TaskStatus = taskStatus,
Grade = dto.Grade,
WarehouseId = dto.WarehouseId,
Creater = "manual",
CreateDate = DateTime.Now,
ModifyDate = DateTime.Now
};
// 4. 保存到数据库
var result = await BaseDal.Add(task);
if (!result)
return WebResponseContent.Instance.Error("创建任务失败");
// 5. 发送任务到WCS
var wmsTaskDto = new WMSTaskDTO
{
TaskNum = task.TaskNum,
PalletCode = task.PalletCode,
SourceAddress = task.SourceAddress,
TargetAddress = task.TargetAddress,
TaskType = task.TaskType,
TaskStatus = task.TaskStatus,
WarehouseId = task.WarehouseId ?? 0
};
var wcsResult = await _httpClientHelper.PostAsync<WebResponseContent>(
"http://localhost:9292/api/Task/ReceiveTask",
wmsTaskDto.ToJson());
if (!wcsResult.IsSuccess || !wcsResult.Data.Status)
return WebResponseContent.Instance.Error($"任务已创建但发送给WCS失败: {wcsResult.Data?.Message}");
return WebResponseContent.Instance.OK($"手动创建任务成功,任务号: {taskNum}");
}
catch (Exception ex)
{
return WebResponseContent.Instance.Error($"手动创建任务异常: {ex.Message}");
}
}
注意: 需要确认
TaskRelocationStatusEnum是否存在,如不存在则使用TaskStatusEnum.New。
using WIDESEA_DTO.Task;
using WIDESEA_Common.TaskEnum;
using WIDESEAWCS_DTO;
git add WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService.cs
git commit -m "feat(WMS): 添加手动创建任务 CreateManualTaskAsync 方法"
文件:
- Modify: WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/TaskService.cs
确认 ReceiveWMSTask 接收 WMSTaskDTO 列表后路由到对应 FlowService。
public WebResponseContent ReceiveWMSTask([NotNull] List<WMSTaskDTO> taskDTOs)
{
// 遍历任务,根据 TaskType 分发到不同 FlowService
foreach (var item in taskDTOs)
{
// 根据 item.TaskType 判断路由到 Inbound/Outbound/Relocation
}
}
git add WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/TaskService.cs
git commit -m "feat(WCS): 确认 ReceiveWMSTask 入口正确"
文件:
- Modify: WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/Flows/InboundTaskFlowService.cs
首先查看现有的 InitializeOnReceive 方法完整实现。
在类中添加:
/// <summary>
/// 线体入库点位
/// </summary>
private static readonly string[] LINE_IN_POINTS = { "11068", "11010", "11001" };
在 InitializeOnReceive 方法中,判断如果 SourceAddress 是线体点位,则写入输送线任务:
public void InitializeOnReceive([NotNull] Dt_Task task, [NotNull] WMSTaskDTO source)
{
// 先执行原有的路由逻辑
Dt_Router routers = _routerService.QueryNextRoute(source.SourceAddress);
if (routers.IsNullOrEmpty())
{
return;
}
task.TaskStatus = (int)TaskInStatusEnum.InNew;
task.CurrentAddress = source.SourceAddress;
task.NextAddress = routers.ChildPosi;
// 如果起点是线体点位(11068/11010/11001),直接写入输送线任务
if (LINE_IN_POINTS.Contains(source.SourceAddress))
{
WriteConveyorLineTask(task, source.SourceAddress);
}
}
/// <summary>
/// 写入输送线任务到PLC
/// </summary>
private void WriteConveyorLineTask(Dt_Task task, string sourceAddress)
{
// 1. 通过 Storage.Devices 查找对应的输送线设备
IDevice? device = Storage.Devices
.FirstOrDefault(x => x.DeviceProDTOs.Any(d => d.DeviceChildCode == sourceAddress));
if (device == null)
{
// 记录日志:未找到对应的输送线设备
QuartzLogger.Error($"手动创建任务:未找到源地址【{sourceAddress}】对应的输送线设备", "InboundTaskFlowService");
return;
}
// 2. 转换为 CommonConveyorLine 类型
if (device is not CommonConveyorLine conveyorLine)
{
QuartzLogger.Error($"设备【{device.DeviceCode}】不是输送线类型", "InboundTaskFlowService");
return;
}
// 3. 获取子设备编码
string? childDeviceCode = device.DeviceProDTOs
.FirstOrDefault(d => d.DeviceChildCode == sourceAddress)?.DeviceChildCode;
if (string.IsNullOrEmpty(childDeviceCode))
{
QuartzLogger.Error($"源地址【{sourceAddress}】未找到对应的子设备编码", "InboundTaskFlowService");
return;
}
// 4. 构造 ConveyorLineTaskCommandNew
ConveyorLineTaskCommandNew command = new ConveyorLineTaskCommandNew
{
TaskNo = (short)task.TaskNum,
Source = short.Parse(sourceAddress),
Target = short.Parse(task.TargetAddress ?? "0"),
Barcode = task.PalletCode ?? string.Empty,
WCS_STB = 1, // WCS已发送标志
WCS_ACK = 0,
PLC_STB = 0,
PLC_ACK = 0
};
// 5. 写入PLC
bool success = conveyorLine.SendCommand(command, childDeviceCode);
if (success)
{
QuartzLogger.Info($"手动创建入库任务已写入输送线:任务号【{task.TaskNum}】,源地址【{sourceAddress}】", conveyorLine.DeviceCode);
}
else
{
QuartzLogger.Error($"手动创建入库任务写入输送线失败:任务号【{task.TaskNum}】,源地址【{sourceAddress}】", conveyorLine.DeviceCode);
}
}
using WIDESEAWCS_QuartzJob;
using WIDESEAWCS_QuartzJob.ConveyorLine;
using WIDESEAWCS_Tasks;
using WIDESEAWCS_Core.LogHelper;
git add WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/Flows/InboundTaskFlowService.cs
git commit -m "feat(WCS): 入库任务线体点位时写入输送线任务"