编辑 | blame | 历史 | 原始文档

MES 上传状态跟踪与异步上传设计

Date: 2026-04-20
Author: Claude

1. 目标

在库存表添加 MES 上传状态字段,通过异步方式上传 MES 数据,不干扰主业务逻辑,所有 MES 调用均记录详细日志。

2. 数据库变更

2.1 Dt_StockInfo 表新增字段

ALTER TABLE [dbo].[Dt_StockInfo] ADD [MesUploadStatus] TINYINT NOT NULL DEFAULT 0;
GO

2.2 枚举定义

含义
0 未上传(从未调用过MES)
1 组盘上传成功
2 组盘上传失败
3 拆盘上传成功
4 拆盘上传失败
5 进站上传成功
6 进站上传失败
7 出站上传成功
8 出站上传失败
9 NG上报成功
10 NG上报失败

WIDESEA_Common 项目新增枚举类 MesUploadStatusEnum

3. 后端设计

3.1 核心异步方法

WIDESEA_TaskInfoService/TaskService.cs 中新增 MesUploadAsync 私有异步方法:

/// <summary>
/// 异步执行MES上传 - 不阻塞主业务逻辑
/// </summary>
/// <param name="palletCode">托盘号</param>
/// <param name="mesType">MES操作类型枚举</param>
/// <param name="uploadFunc">具体的MES调用函数</param>
private async Task MesUploadAsync(string palletCode, MesUploadStatusEnum mesType, Func<Task<HttpResponseResult<MesResponse>>> uploadFunc)
{
    var stopwatch = Stopwatch.StartNew();
    string requestJson = "";
    string responseJson = "";
    bool isSuccess = false;
    string errorMessage = "";

    try
    {
        // 记录请求日志
        var mesLog = new MesApiLogDto
        {
            PalletCode = palletCode,
            ApiType = mesType.ToString(),
            RequestTime = DateTime.Now
        };

        // 调用MES
        var result = await uploadFunc();

        stopwatch.Stop();
        isSuccess = result?.Data?.IsSuccess ?? false;
        errorMessage = result?.Data?.Msg ?? result?.ErrorMessage ?? "未知错误";
        responseJson = JsonConvert.SerializeObject(result);

        // 更新库存表状态
        var uploadStatus = isSuccess ? (int)mesType : (int)mesType + 1; // 奇数=成功,偶数=失败
        await _stockInfoService.UpdateMesUploadStatusAsync(palletCode, uploadStatus);

        // 记录日志
        mesLog.ResponseTime = DateTime.Now;
        mesLog.Duration = stopwatch.ElapsedMilliseconds;
        mesLog.RequestParams = requestJson;
        mesLog.ResponseResult = responseJson;
        mesLog.Status = isSuccess ? "成功" : "失败";
        mesLog.ErrorMessage = errorMessage;
        mesLog.CreateTime = DateTime.Now;

        _ = _mesLogService.LogAsync(mesLog); // 不等待
    }
    catch (Exception ex)
    {
        stopwatch.Stop();
        errorMessage = ex.Message;

        // 更新状态为失败
        var uploadStatus = (int)mesType + 1;
        _stockInfoService.UpdateMesUploadStatusAsync(palletCode, uploadStatus).ConfigureAwait(false);

        // 记录异常日志
        var mesLog = new MesApiLogDto
        {
            PalletCode = palletCode,
            ApiType = mesType.ToString(),
            RequestTime = DateTime.Now,
            ResponseTime = DateTime.Now,
            Duration = stopwatch.ElapsedMilliseconds,
            RequestParams = requestJson,
            ResponseResult = responseJson,
            Status = "失败",
            ErrorMessage = errorMessage,
            CreateTime = DateTime.Now
        };
        _ = _mesLogService.LogAsync(mesLog); // 不等待
    }
}

3.2 调用方式

在各个 MES 操作处统一使用 Task.Run + MesUploadAsync

// 组盘确认
public async Task<WebResponseContent> GroupPalletConfirmAsync(string palletCode, string deviceName)
{
    // ... 业务逻辑 ...
    
    // 异步MES上传,不阻塞主逻辑
    _ = Task.Run(() => MesUploadAsync(palletCode, MesUploadStatusEnum.GroupPalletSuccess, async () =>
    {
        return await _mesService.BindContainerAsync(bindRequest, token);
    }));

    return content.OK("组盘成功");
}

// 拆盘确认
public async Task<WebResponseContent> SplitPalletConfirmAsync(string palletCode, string deviceName)
{
    // ... 业务逻辑 ...

    _ = Task.Run(() => MesUploadAsync(palletCode, MesUploadStatusEnum.SplitPalletSuccess, async () =>
    {
        return await _mesService.UnBindContainerAsync(unbindRequest, token);
    }));

    return content.OK("拆盘成功");
}

3.3 IStockInfoService 新增方法

IStockInfoService 接口新增:

/// <summary>
/// 更新MES上传状态
/// </summary>
/// <param name="palletCode">托盘号</param>
/// <param name="status">状态值</param>
Task<bool> UpdateMesUploadStatusAsync(string palletCode, int status);

StockInfoService 中实现该方法。

3.4 日志记录规范

所有 MES 调用统一记录以下字段:

字段 说明
PalletCode 托盘号
ApiType 接口类型(组盘/拆盘/进站/出站/NG上报)
RequestTime 请求时间
ResponseTime 响应时间
Duration 耗时(ms)
RequestParams 请求JSON
ResponseResult 响应JSON
Status 成功/失败
ErrorMessage 失败原因

4. 前端变更

4.1 库存页面操作列新增按钮

WMS/WIDESEA_WMSClient/src/extension/stock/stock.jsx 中扩展操作列:

let extension = {
  components: {
    gridHeader: "",
    gridBody: "",
    gridFooter: "",
    modelHeader: "",
    modelBody: "",
    modelFooter: "",
  },
  tableAction: "stock",
  buttons: {
    view: ["Export"],
    box: []
  },
  methods: {
    onInit() {
      return true;
    },
    onInited() {
      // 注入组盘/拆盘按钮
      this.editTableButtons = [
        { name: "组盘", onClick: this.onGroupPallet },
        { name: "拆盘", onClick: this.onSplitPallet }
      ];
      return true;
    },
    async onGroupPallet({ row }) {
      // 调用组盘接口
      let result = await this.$api.post("/Stock/GroupPalletConfirm", { palletCode: row.palletCode });
      if (result.status) {
        this.$Message.success("组盘成功");
        this.$refs.grid.search();
      } else {
        this.$Message.error(result.message || "组盘失败");
      }
    },
    async onSplitPallet({ row }) {
      // 调用拆盘接口
      let result = await this.$api.post("/Stock/SplitPalletConfirm", { palletCode: row.palletCode });
      if (result.status) {
        this.$Message.success("拆盘成功");
        this.$refs.grid.search();
      } else {
        this.$Message.error(result.message || "拆盘失败");
      }
    }
  },
};

export default extension;

4.2 库存列表新增状态列

WMS/WIDESEA_WMSClient/src/views/stock/stock.vuecolumns 中新增:

{ field: "mesUploadStatus", title: "MES状态", type: "int", width: 120, bind: { key: "mesUploadStatusEnum", data: [] } }

4.3 字典配置

mesUploadStatusEnum 字典中添加:

value label
0 未上传
1 组盘成功
2 组盘失败
3 拆盘成功
4 拆盘失败
5 进站成功
6 进站失败
7 出站成功
8 出站失败
9 NG上报成功
10 NG上报失败

5. 文件变更清单

操作 文件
新增 WMS/WIDESEA_WMSServer/WIDESEA_Common/StockEnum/MesUploadStatusEnum.cs
修改 WMS/WIDESEA_WMSServer/WIDESEA_Model/Models/Stock/Dt_StockInfo.cs - 新增 MesUploadStatus 字段
修改 WMS/WIDESEA_WMSServer/WIDESEA_IStockService/IStockInfoService.cs - 新增 UpdateMesUploadStatusAsync
修改 WMS/WIDESEA_WMSServer/WIDESEA_StockService/StockInfoService.cs - 实现 UpdateMesUploadStatusAsync
修改 WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService.cs - 新增 MesUploadAsync + 各处调用
修改 WMS/WIDESEA_WMSClient/src/extension/stock/stock.jsx - 新增组盘/拆盘按钮
修改 WMS/WIDESEA_WMSClient/src/views/stock/stock.vue - 新增MES状态列
新增 数据库变更脚本

6. 自检清单

  • [ ] MesUploadStatusEnum 枚举值奇数为成功,偶数为失败,+1运算正确
  • [ ] MesUploadAsync 方法内所有 MES 调用记录详细日志(请求JSON、响应JSON、耗时、错误原因)
  • [ ] 组盘/拆盘/进站/出站/NG上报均通过 Task.Run 异步执行,不阻塞主逻辑
  • [ ] 前端组盘/拆盘按钮调用 GroupPalletConfirmAsync / SplitPalletConfirmAsync
  • [ ] 库存列表正确显示 mesUploadStatus 字段
  • [ ] 所有 public 方法均有 XML 文档注释