Date: 2026-04-20
Author: Claude
在库存表添加 MES 上传状态字段,通过异步方式上传 MES 数据,不干扰主业务逻辑,所有 MES 调用均记录详细日志。
ALTER TABLE [dbo].[Dt_StockInfo] ADD [MesUploadStatus] TINYINT NOT NULL DEFAULT 0;
GO
| 值 | 含义 |
|---|---|
| 0 | 未上传(从未调用过MES) |
| 1 | 组盘上传成功 |
| 2 | 组盘上传失败 |
| 3 | 拆盘上传成功 |
| 4 | 拆盘上传失败 |
| 5 | 进站上传成功 |
| 6 | 进站上传失败 |
| 7 | 出站上传成功 |
| 8 | 出站上传失败 |
| 9 | NG上报成功 |
| 10 | NG上报失败 |
在 WIDESEA_Common 项目新增枚举类 MesUploadStatusEnum。
在 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); // 不等待
}
}
在各个 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("拆盘成功");
}
在 IStockInfoService 接口新增:
/// <summary>
/// 更新MES上传状态
/// </summary>
/// <param name="palletCode">托盘号</param>
/// <param name="status">状态值</param>
Task<bool> UpdateMesUploadStatusAsync(string palletCode, int status);
在 StockInfoService 中实现该方法。
所有 MES 调用统一记录以下字段:
| 字段 | 说明 |
|---|---|
| PalletCode | 托盘号 |
| ApiType | 接口类型(组盘/拆盘/进站/出站/NG上报) |
| RequestTime | 请求时间 |
| ResponseTime | 响应时间 |
| Duration | 耗时(ms) |
| RequestParams | 请求JSON |
| ResponseResult | 响应JSON |
| Status | 成功/失败 |
| ErrorMessage | 失败原因 |
在 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;
在 WMS/WIDESEA_WMSClient/src/views/stock/stock.vue 的 columns 中新增:
{ field: "mesUploadStatus", title: "MES状态", type: "int", width: 120, bind: { key: "mesUploadStatusEnum", data: [] } }
在 mesUploadStatusEnum 字典中添加:
| value | label |
|---|---|
| 0 | 未上传 |
| 1 | 组盘成功 |
| 2 | 组盘失败 |
| 3 | 拆盘成功 |
| 4 | 拆盘失败 |
| 5 | 进站成功 |
| 6 | 进站失败 |
| 7 | 出站成功 |
| 8 | 出站失败 |
| 9 | NG上报成功 |
| 10 | NG上报失败 |
| 操作 | 文件 |
|---|---|
| 新增 | 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状态列 |
| 新增 | 数据库变更脚本 |
MesUploadStatusEnum 枚举值奇数为成功,偶数为失败,+1运算正确MesUploadAsync 方法内所有 MES 调用记录详细日志(请求JSON、响应JSON、耗时、错误原因)Task.Run 异步执行,不阻塞主逻辑GroupPalletConfirmAsync / SplitPalletConfirmAsyncmesUploadStatus 字段