wanshenmean
2026-03-30 cff279ab12d8d3d77bae12cfb0438ecbafada6b1
docs: 添加 MES 托盘进站出站集成实现计划

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
已添加1个文件
297 ■■■■■ 文件已修改
Code/WMS/docs/superpowers/plans/2026-03-30-MES托盘进站出站集成实现计划.md 297 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/docs/superpowers/plans/2026-03-30-MESÍÐÅ̽øÕ¾³öÕ¾¼¯³ÉʵÏּƻ®.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,297 @@
# MES æ‰˜ç›˜è¿›ç«™å‡ºç«™é›†æˆå®žçŽ°è®¡åˆ’
> **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:** åœ¨ TaskService çš„入库完成/出库完成方法中集成 MES è¿›ç«™/出站调用,新增空托盘入库/出库完成方法。
**Architecture:** åœ¨ `ExecuteWithinTransactionAsync` äº‹åŠ¡å†…æ·»åŠ  MES è°ƒç”¨ï¼ŒMES å¤±è´¥åˆ™äº‹åŠ¡å›žæ»šã€‚
**Tech Stack:** ASP.NET Core 6.0, IMesService, ExecuteWithinTransactionAsync
---
## ä»»åŠ¡æ€»è§ˆ
| ä»»åŠ¡ | æ–¹æ³• | æ“ä½œ |
|------|------|------|
| Task 1 | `InboundFinishTaskAsync` | æ·»åŠ  `InboundInContainer` è°ƒç”¨ |
| Task 2 | `OutboundFinishTaskAsync` | æ·»åŠ  `OutboundInContainer` è°ƒç”¨ |
| Task 3 | `InboundFinishTaskTrayAsync`(新增) | ç©ºæ‰˜ç›˜å…¥åº“完成,无需 MES |
| Task 4 | `OutboundFinishTaskTrayAsync`(新增) | ç©ºæ‰˜ç›˜å‡ºåº“完成,无需 MES |
---
## ä»»åŠ¡å‰ç½®æ¡ä»¶
`TaskService` éœ€æ³¨å…¥ `IMesService`。检查现有构造函数是否已有:
```csharp
private readonly IMesService _mesService;
```
如果不存在,需添加。
---
## Task 1: ä¿®æ”¹ InboundFinishTaskAsync æ·»åŠ  MES è¿›ç«™è°ƒç”¨
**Files:**
- Modify: `WIDESEA_TaskInfoService/TaskService.cs`(`InboundFinishTaskAsync` æ–¹æ³•,约第 215 è¡Œï¼‰
- [ ] **Step 1: æŸ¥çœ‹å½“前代码确认上下文**
读取 `TaskService.cs` ç¬¬ 199-240 è¡Œï¼Œç¡®è®¤ `CompleteTaskAsync` è°ƒç”¨çš„位置。
- [ ] **Step 2: åœ¨ CompleteTaskAsync ä¹‹å‰æ·»åŠ  MES InboundInContainer è°ƒç”¨**
在 `return await CompleteTaskAsync(task);` ä¹‹å‰æ·»åŠ ï¼š
```csharp
// è°ƒç”¨MES托盘进站
var inboundRequest = new InboundInContainerRequest
{
    EquipmentCode = "STK-GROUP-001",
    ResourceCode = "STK-GROUP-001",
    LocalTime = DateTime.Now,
    ContainerCode = taskDto.PalletCode
};
var inboundResult = _mesService.InboundInContainer(inboundRequest);
if (inboundResult == null || inboundResult.Data == null || !inboundResult.Data.IsSuccess)
{
    return content.Error($"任务完成失败:MES进站失败: {inboundResult?.Data?.Msg ?? inboundResult?.ErrorMessage ?? "未知错误"}");
}
```
- [ ] **Step 3: æ·»åŠ  using å¼•用(如果需要)**
确认文件顶部已有 `using WIDESEA_IBasicService;` å’Œ `using WIDESEA_DTO.MES;`。如果没有,添加。
- [ ] **Step 4: æž„建验证**
```bash
cd WIDESEA_WMSServer && dotnet build WIDESEA_TaskInfoService/WIDESEA_TaskInfoService.csproj
```
确认无编译错误。
- [ ] **Step 5: æäº¤**
```bash
git add WIDESEA_TaskInfoService/TaskService.cs
git commit -m "feat(TaskService): InboundFinishTaskAsync添加MES进站调用"
```
---
## Task 2: ä¿®æ”¹ OutboundFinishTaskAsync æ·»åŠ  MES å‡ºç«™è°ƒç”¨
**Files:**
- Modify: `WIDESEA_TaskInfoService/TaskService.cs`(`OutboundFinishTaskAsync` æ–¹æ³•,约第 258 è¡Œï¼‰
- [ ] **Step 1: æŸ¥çœ‹å½“前代码确认上下文**
读取 `TaskService.cs` ç¬¬ 258-280 è¡Œï¼Œç¡®è®¤ `CompleteTaskAsync` è°ƒç”¨çš„位置。
- [ ] **Step 2: åœ¨ CompleteTaskAsync ä¹‹å‰æ·»åŠ  MES OutboundInContainer è°ƒç”¨**
在 `return await CompleteTaskAsync(task);` ä¹‹å‰æ·»åŠ ï¼š
```csharp
// è°ƒç”¨MES托盘出站
var outboundRequest = new OutboundInContainerRequest
{
    EquipmentCode = "STK-GROUP-001",
    ResourceCode = "STK-GROUP-001",
    LocalTime = DateTime.Now,
    ContainerCode = taskDto.PalletCode,
    ParamList = new List<ParamItem>()
};
var outboundResult = _mesService.OutboundInContainer(outboundRequest);
if (outboundResult == null || outboundResult.Data == null || !outboundResult.Data.IsSuccess)
{
    return content.Error($"任务完成失败:MES出站失败: {outboundResult?.Data?.Msg ?? outboundResult?.ErrorMessage ?? "未知错误"}");
}
```
- [ ] **Step 3: æž„建验证**
```bash
cd WIDESEA_WMSServer && dotnet build WIDESEA_TaskInfoService/WIDESEA_TaskInfoService.csproj
```
确认无编译错误。
- [ ] **Step 4: æäº¤**
```bash
git add WIDESEA_TaskInfoService/TaskService.cs
git commit -m "feat(TaskService): OutboundFinishTaskAsync添加MES出站调用"
```
---
## Task 3: æ–°å¢ž InboundFinishTaskTrayAsync ç©ºæ‰˜ç›˜å…¥åº“完成方法
**Files:**
- Modify: `WIDESEA_TaskInfoService/TaskService.cs`(在 `InboundFinishTaskTrayAsync` æ–¹æ³•之后添加新方法)
- [ ] **Step 1: æŸ¥çœ‹çŽ°æœ‰ InboundFinishTaskTrayAsync æ–¹æ³•位置**
读取 `TaskService.cs` ç¬¬ 330-350 è¡Œï¼Œç¡®è®¤ `CreateTaskInboundTrayAsync` ä¹‹åŽçš„位置。
- [ ] **Step 2: æ·»åŠ æ–°æ–¹æ³• InboundFinishTaskTrayAsync**
在 `CreateTaskInboundTrayAsync` æ–¹æ³•之后添加:
```csharp
/// <summary>
/// ç©ºæ‰˜ç›˜å…¥åº“完成
/// </summary>
public async Task<WebResponseContent> InboundFinishTaskTrayAsync(CreateTaskDto taskDto)
{
    try
    {
        var task = await BaseDal.QueryFirstAsync(s => s.PalletCode == taskDto.PalletCode);
        if (task == null) return WebResponseContent.Instance.Error("未找到对应的任务");
        var location = await _locationInfoService.GetLocationInfo(task.Roadway, task.TargetAddress);
        if (location == null) return WebResponseContent.Instance.Error("未找到对应的货位");
        var stockInfo = await _stockInfoService.GetStockInfoAsync(taskDto.PalletCode);
        if (stockInfo == null) return WebResponseContent.Instance.Error("未找到对应库存信息");
        return await ExecuteWithinTransactionAsync(async () =>
        {
            stockInfo.LocationCode = location.LocationCode;
            stockInfo.LocationId = location.Id;
            stockInfo.StockStatus = StockStatusEmun.空托盘库存.GetHashCode();
            location.LocationStatus = LocationStatusEnum.InStock.GetHashCode();
            var updateLocationResult = await _locationInfoService.UpdateLocationInfoAsync(location);
            var updateStockResult = await _stockInfoService.UpdateStockAsync(stockInfo);
            if (!updateLocationResult || !updateStockResult)
                return WebResponseContent.Instance.Error("任务完成失败");
            var deleteResult = await BaseDal.DeleteDataAsync(task);
            if (!deleteResult) return WebResponseContent.Instance.Error("任务完成失败");
            return WebResponseContent.Instance.OK("任务完成");
        });
    }
    catch (Exception ex)
    {
        return WebResponseContent.Instance.Error($"完成任务失败: {ex.Message}");
    }
}
```
- [ ] **Step 3: æž„建验证**
```bash
cd WIDESEA_WMSServer && dotnet build WIDESEA_TaskInfoService/WIDESEA_TaskInfoService.csproj
```
确认无编译错误。
- [ ] **Step 4: æäº¤**
```bash
git add WIDESEA_TaskInfoService/TaskService.cs
git commit -m "feat(TaskService): æ–°å¢žInboundFinishTaskTrayAsync空托盘入库完成方法"
```
---
## Task 4: æ–°å¢ž OutboundFinishTaskTrayAsync ç©ºæ‰˜ç›˜å‡ºåº“完成方法
**Files:**
- Modify: `WIDESEA_TaskInfoService/TaskService.cs`(在 `OutboundFinishTaskTrayAsync` æ–¹æ³•之后添加新方法)
- [ ] **Step 1: æŸ¥çœ‹çŽ°æœ‰ GetOutBoundTrayTaskAsync æ–¹æ³•位置**
读取 `TaskService.cs` ç¬¬ 357-393 è¡Œï¼Œç¡®è®¤ `GetOutBoundTrayTaskAsync` ä¹‹åŽçš„位置。
- [ ] **Step 2: æ·»åŠ æ–°æ–¹æ³• OutboundFinishTaskTrayAsync**
在 `GetOutBoundTrayTaskAsync` æ–¹æ³•之后添加:
```csharp
/// <summary>
/// ç©ºæ‰˜ç›˜å‡ºåº“完成
/// </summary>
public async Task<WebResponseContent> OutboundFinishTaskTrayAsync(CreateTaskDto taskDto)
{
    try
    {
        var task = await BaseDal.QueryFirstAsync(s => s.PalletCode == taskDto.PalletCode);
        if (task == null) return WebResponseContent.Instance.Error("未找到对应的任务");
        var location = await _locationInfoService.GetLocationInfo(task.Roadway, task.SourceAddress);
        if (location == null) return WebResponseContent.Instance.Error("未找到对应的货位");
        var stockInfo = await _stockInfoService.GetStockInfoAsync(taskDto.PalletCode);
        if (stockInfo == null) return WebResponseContent.Instance.Error("未找到对应库存信息");
        return await ExecuteWithinTransactionAsync(async () =>
        {
            stockInfo.LocationId = 0;
            stockInfo.LocationCode = null;
            stockInfo.StockStatus = StockStatusEmun.出库完成.GetHashCode();
            location.LocationStatus = LocationStatusEnum.Free.GetHashCode();
            var updateLocationResult = await _locationInfoService.UpdateLocationInfoAsync(location);
            var updateStockResult = await _stockInfoService.UpdateStockAsync(stockInfo);
            if (!updateLocationResult || !updateStockResult)
                return WebResponseContent.Instance.Error("任务完成失败");
            var deleteResult = await BaseDal.DeleteDataAsync(task);
            if (!deleteResult) return WebResponseContent.Instance.Error("任务完成失败");
            return WebResponseContent.Instance.OK("任务完成");
        });
    }
    catch (Exception ex)
    {
        return WebResponseContent.Instance.Error($"完成任务失败: {ex.Message}");
    }
}
```
- [ ] **Step 3: æž„建验证**
```bash
cd WIDESEA_WMSServer && dotnet build WIDESEA_TaskInfoService/WIDESEA_TaskInfoService.csproj
```
确认无编译错误。
- [ ] **Step 4: æäº¤**
```bash
git add WIDESEA_TaskInfoService/TaskService.cs
git commit -m "feat(TaskService): æ–°å¢žOutboundFinishTaskTrayAsync空托盘出库完成方法"
```
---
## Task 5: æ•´ä½“构建验证
- [ ] **Step 1: æž„建整个解决方案**
```bash
cd WIDESEA_WMSServer && dotnet build WIDESEA_WMSServer.sln
```
确认无编译错误、无警告。
---
## éªŒè¯æ£€æŸ¥æ¸…单
- [ ] `InboundFinishTaskAsync` ä¸­ `InboundInContainer` åœ¨ `CompleteTaskAsync` ä¹‹å‰
- [ ] `OutboundFinishTaskAsync` ä¸­ `OutboundInContainer` åœ¨ `CompleteTaskAsync` ä¹‹å‰
- [ ] æ‰€æœ‰ MES è°ƒç”¨æ£€æŸ¥ `mesResult.Data?.IsSuccess`
- [ ] é”™è¯¯ä¿¡æ¯æ ¼å¼ï¼š`"任务完成失败:MES{操作}失败: {错误信息}"`
- [ ] `InboundFinishTaskTrayAsync` å’Œ `OutboundFinishTaskTrayAsync` æ–°å¢žæ–¹æ³•签名正确
- [ ] è§£å†³æ–¹æ¡ˆæž„建无错误