wanshenmean
15 小时以前 c96b149557eb570ec3ae28e0d0c03adef734766a
feat: 添加机械手选择功能并优化MES请求处理

refactor: 重构堆垛机任务选择器的日志记录方式

fix: 修复HTTP头设置使用Add方法的问题

feat(WMS): 在绑定/解绑请求中添加设备名称字段

perf: 更新Swashbuckle.AspNetCore至8.0.0版本

style: 移除QuartzLogger中的控制台输出

feat: 在MES请求中添加HTTP配置信息

fix: 修复容器NG报告接口的返回值处理

feat: 添加合并JSON对象的工具方法

docs: 更新IMesUploadHelper接口定义

test: 添加QuartzLogHelper的新测试方法
已添加1个文件
已修改20个文件
300 ■■■■ 文件已修改
Code/.omc/state/subagent-tracking.json 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Filter/ApiAuthorizeFilter.cs 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/LogHelper/QuartzLogger.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Middlewares/HttpRequestMiddleware.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Server.csproj 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/QuartzLogHelper.cs 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/StackerCraneJob/CommonStackerCraneJob.cs 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/StackerCraneJob/StackerCraneTaskSelector.cs 19 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSClient/src/extension/stock/extend/RobotSelect.vue 125 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSClient/src/extension/stock/stockInfo.jsx 53 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSServer/WIDESEA_BasicService/MesService.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSServer/WIDESEA_DTO/MES/BindContainerRequestDto.cs 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSServer/WIDESEA_DTO/MES/UnbindContainerRequestDto.cs 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSServer/WIDESEA_IBasicService/IMesService.cs 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSServer/WIDESEA_IBasicService/IMesUploadHelper.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSServer/WIDESEA_StockService/MesUploadHelper.cs 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSServer/WIDESEA_StockService/StockSerivce.cs 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/WCS/TaskService_Inbound.cs 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/WCS/TaskService_Outbound.cs 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Stock/StockInfoController.cs 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Stock/StockInfoDetailController.cs 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/.omc/state/subagent-tracking.json
@@ -1459,5 +1459,5 @@
  "total_spawned": 135,
  "total_completed": 157,
  "total_failed": 0,
  "last_updated": "2026-04-20T17:02:18.739Z"
  "last_updated": "2026-04-21T06:46:41.255Z"
}
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Filter/ApiAuthorizeFilter.cs
@@ -7,6 +7,7 @@
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Hosting;
using WIDESEAWCS_Core.Authorization;
@@ -112,7 +113,7 @@
                int ExpMinutes = AppSettings.Get("ExpMinutes").ObjToInt();
                if ((expDate.GetValueOrDefault() - DateTime.Now).TotalMinutes < ExpMinutes / 3 && context.HttpContext.Request.Path != replaceTokenPath)
                {
                    context.HttpContext.Response.Headers.Add("wideseawcs_exp", "1");
                    context.HttpContext.Response.Headers.Append("wideseawcs_exp", "1");
                }
            }
        }
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/LogHelper/QuartzLogger.cs
@@ -166,7 +166,7 @@
                    string fileName = GetLogFileName(entry.Source);
                    string filePath = Path.Combine(_logFolder, fileName);
                    string content = entry.ToFormattedString() + Environment.NewLine;
                    ConsoleHelper.WriteInfoLine(content);
                    //ConsoleHelper.WriteInfoLine(content);
                    File.AppendAllText(filePath, content);
                }
            }
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Middlewares/HttpRequestMiddleware.cs
@@ -25,7 +25,7 @@
        public async Task InvokeAsync(HttpContext context)
        {
            
            context.Response.Headers.Add("Access-Control-Expose-Headers", "wideseawcs_exp");
            context.Response.Headers.Append("Access-Control-Expose-Headers", "wideseawcs_exp");
            await _next(context);
        }
    }
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Server.csproj
@@ -65,7 +65,7 @@
    </ItemGroup>
    <ItemGroup>
        <PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
        <PackageReference Include="Swashbuckle.AspNetCore" Version="8.0.0" />
    </ItemGroup>
    <ItemGroup>
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/QuartzLogHelper.cs
@@ -95,4 +95,18 @@
        logger.Debug(loggerMessage, args);
        QuartzLogger.Debug(quartzMessage, deviceCode);
    }
    /// <summary>
    /// è®°å½•调试日志
    /// </summary>
    /// <param name="logger">ILogger å®žä¾‹</param>
    /// <param name="loggerMessage">ILogger çš„结构化日志模板(支持占位符)</param>
    /// <param name="quartzMessage">QuartzLogger çš„æ—¥å¿—消息</param>
    /// <param name="deviceCode">设备编码</param>
    /// <param name="args">ILogger ç»“构化日志的参数</param>
    public static void LogDebug(ILogger logger, string loggerMessage, string deviceCode)
    {
        logger.Debug(loggerMessage);
        QuartzLogger.Debug(loggerMessage, deviceCode);
    }
}
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/StackerCraneJob/CommonStackerCraneJob.cs
@@ -210,6 +210,8 @@
                    return Task.CompletedTask;
                }
                // ========== æž„建命令 ==========
                // å‘½ä»¤æž„建下沉到专用构建器
                object? stackerCraneTaskCommand = _commandBuilder.ConvertToStackerCraneTaskCommand(task);
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/StackerCraneJob/StackerCraneTaskSelector.cs
@@ -100,15 +100,14 @@
            Dt_Task? candidateTask;
            var deviceCode = commonStackerCrane.DeviceCode;
            //_logger.LogInformation("SelectTask:开始选择任务,设备: {DeviceCode},上一任务类型: {LastTaskType}", deviceCode, commonStackerCrane.LastTaskType);
            //QuartzLogger.Info($"开始选择任务,设备: {deviceCode},上一任务类型: {commonStackerCrane.LastTaskType}", deviceCode);
            QuartzLogHelper.LogDebug(_logger, $"开始选择任务,设备: {deviceCode},上一任务类型: {commonStackerCrane.LastTaskType}",commonStackerCrane.DeviceName);
            // æ ¹æ®ä¸Šä¸€ä»»åŠ¡ç±»åž‹å†³å®šæŸ¥è¯¢ç­–ç•¥
            if (commonStackerCrane.LastTaskType == null || commonStackerCrane.LastTaskType == TaskRelocationTypeEnum.Relocation.GetHashCode())
            {
                // æ²¡æœ‰ä¸Šä¸€ä»»åŠ¡ç±»åž‹ï¼ŒæŸ¥è¯¢æ™®é€šä»»åŠ¡
                candidateTask = _taskService.QueryStackerCraneTask(deviceCode);
                //QuartzLogHelper.LogDebug(_logger, "SelectTask:查询普通任务,设备: {DeviceCode},结果: {TaskNum}", $"查询普通任务,设备: {deviceCode},结果: {candidateTask?.TaskNum}", deviceCode, deviceCode, candidateTask?.TaskNum);
                QuartzLogHelper.LogDebug(_logger, $"查询普通任务,设备: {deviceCode},结果: {candidateTask?.TaskNum}", commonStackerCrane.DeviceName);
            }
            else if (commonStackerCrane.LastTaskType.GetValueOrDefault().GetTaskTypeGroup() == TaskTypeGroup.OutbondGroup)
            {
@@ -116,26 +115,26 @@
                candidateTask = _taskService.QueryStackerCraneInTask(deviceCode);
                // å¦‚果没有入库任务,再查一下出库任务
                candidateTask ??= _taskService.QueryStackerCraneOutTask(deviceCode);
                //QuartzLogHelper.LogDebug(_logger, "SelectTask:出库后优先查入库,设备: {DeviceCode},结果: {TaskNum}", $"出库后优先查入库,设备: {deviceCode},结果: {candidateTask?.TaskNum}", deviceCode, deviceCode, candidateTask?.TaskNum);
                QuartzLogHelper.LogDebug(_logger, $"出库后优先查入库,设备: {deviceCode},结果: {candidateTask?.TaskNum}", commonStackerCrane.DeviceName);
            }
            else
            {
                // ä¸Šä¸€ä»»åŠ¡æ˜¯å…¥åº“ï¼ˆéžå‡ºåº“ï¼‰ï¼Œä¼˜å…ˆæŸ¥å‡ºåº“ä»»åŠ¡
                candidateTask = _taskService.QueryStackerCraneOutTask(deviceCode);
                //QuartzLogHelper.LogDebug(_logger, "SelectTask:入库后优先查出库,设备: {DeviceCode},结果: {TaskNum}", $"入库后优先查出库,设备: {deviceCode},结果: {candidateTask?.TaskNum}", deviceCode, deviceCode, candidateTask?.TaskNum);
                QuartzLogHelper.LogDebug(_logger, $"入库后优先查出库,设备: {deviceCode},结果: {candidateTask?.TaskNum}", commonStackerCrane.DeviceName);
            }
            // å¦‚果没有候选任务,返回 null
            if (candidateTask == null)
            {
                //QuartzLogHelper.LogDebug(_logger, "SelectTask:没有候选任务,设备: {DeviceCode}", $"没有候选任务,设备: {deviceCode}", deviceCode, deviceCode);
                QuartzLogHelper.LogDebug(_logger, $"没有候选任务,设备: {deviceCode}", commonStackerCrane.DeviceName);
                return null;
            }
            // å¦‚果不是出库任务,直接返回
            if (candidateTask.TaskType.GetTaskTypeGroup() != TaskTypeGroup.OutbondGroup)
            {
                QuartzLogHelper.LogInfo(_logger, "SelectTask:选中非出库任务,设备: {DeviceCode},任务号: {TaskNum},任务类型: {TaskType}", $"选中非出库任务,任务号: {candidateTask.TaskNum},任务类型: {candidateTask.TaskType}", deviceCode, deviceCode, candidateTask.TaskNum, candidateTask.TaskType);
                QuartzLogHelper.LogDebug(_logger, $"选中非出库任务,任务号: {candidateTask.TaskNum},任务类型: {candidateTask.TaskType}", commonStackerCrane.DeviceName);
                return candidateTask;
            }
@@ -143,7 +142,7 @@
            Dt_Task? selectedTask = TrySelectOutboundTask(candidateTask);
            if (selectedTask != null)
            {
                QuartzLogHelper.LogInfo(_logger, "SelectTask:选中出库任务,设备: {DeviceCode},任务号: {TaskNum}", $"选中出库任务,任务号: {selectedTask.TaskNum}", deviceCode, deviceCode, selectedTask.TaskNum);
                QuartzLogHelper.LogDebug(_logger, $"选中出库任务,任务号: {selectedTask.TaskNum}", commonStackerCrane.DeviceName);
                return selectedTask;
            }
@@ -160,14 +159,14 @@
                selectedTask = TrySelectOutboundTask(alternativeTask);
                if (selectedTask != null)
                {
                    QuartzLogHelper.LogInfo(_logger, "SelectTask:选中备选出库任务,设备: {DeviceCode},任务号: {TaskNum}", $"选中备选出库任务,任务号: {selectedTask.TaskNum}", deviceCode, deviceCode, selectedTask.TaskNum);
                    QuartzLogHelper.LogDebug(_logger, $"选中备选出库任务,任务号: {selectedTask.TaskNum}", commonStackerCrane.DeviceName);
                    return selectedTask;
                }
            }
            // æ²¡æœ‰å¯ç”¨å‡ºåº“任务,尝试返回入库任务
            var inboundTask = _taskService.QueryStackerCraneInTask(deviceCode);
            QuartzLogHelper.LogInfo(_logger, "SelectTask:返回入库任务,设备: {DeviceCode},任务号: {TaskNum}", $"返回入库任务,任务号: {inboundTask?.TaskNum}", deviceCode, deviceCode, inboundTask?.TaskNum);
            QuartzLogHelper.LogDebug(_logger, $"返回入库任务,任务号: {inboundTask?.TaskNum}", commonStackerCrane.DeviceName);
            return inboundTask;
        }
Code/WMS/WIDESEA_WMSClient/src/extension/stock/extend/RobotSelect.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,125 @@
<template>
  <div>
    <vol-box
      v-model="showDetialBox"
      :lazy="true"
      width="400px"
      :padding="15"
      title="选择机械手"
    >
      <div>
        <el-form>
          <el-form-item required label="机械手:">
            <el-select v-model="selectedRobot" placeholder="请选择机械手" style="width: 100%">
              <el-option
                v-for="item in robotList"
                :key="item.robotCode"
                :label="item.robotName"
                :value="item.robotCode"
              >
              </el-option>
            </el-select>
          </el-form-item>
        </el-form>
      </div>
      <template #footer>
        <el-button type="primary" size="small" @click="submit">确认</el-button>
        <el-button type="danger" size="small" @click="close">关闭</el-button>
      </template>
    </vol-box>
  </div>
</template>
<script>
import VolBox from "@/components/basic/VolBox.vue";
export default {
  components: { VolBox },
  data() {
    return {
      showDetialBox: false,
      robotList: [
        { robotCode: '注液组盘机械手', robotName: '注液组盘机械手' },
        { robotCode: '高温换盘机械手', robotName: '高温换盘机械手' },
        { robotCode: '化成换盘机械手', robotName: '化成换盘机械手' },
        { robotCode: '拆盘机械手', robotName: '拆盘机械手' },
        { robotCode: '成品组盘机械手', robotName: '成品组盘机械手' }
      ],
      selectedRobot: '',
      currentRow: null,
      actionType: null // 'bind' or 'unbind'
    };
  },
  methods: {
    open(action, row) {
      this.actionType = action;
      this.currentRow = row;
      this.selectedRobot = '';
      this.showDetialBox = true;
    },
    close() {
      this.showDetialBox = false;
    },
    async submit() {
      if (!this.selectedRobot) {
        return this.$message.error("请选择机械手");
      }
      this.showDetialBox = false;
      try {
        if (this.actionType === 'bind') {
          // ç»„盘确认
          await this.$confirm(
            `确认执行托盘组盘操作?\n托盘编号:${this.currentRow.palletCode}\n机械手:${this.selectedRobot}`,
            "组盘确认",
            {
              confirmButtonText: "确认",
              cancelButtonText: "取消",
              type: "warning"
            }
          );
          const result = await this.http.post("/api/StockInfoDetail/BindContainer", {
            palletCode: this.currentRow.palletCode,
            robotCode: this.selectedRobot
          }, "正在调用MES接口...");
          if (result.status) {
            this.$Message.success(result.message || "托盘组盘成功");
            this.$parent.$refs.table.load();
          } else {
            this.$error(result.message || "托盘组盘失败");
          }
        } else if (this.actionType === 'unbind') {
          // æ‹†ç›˜ç¡®è®¤
          await this.$confirm(
            `确认执行托盘拆盘操作?\n托盘编号:${this.currentRow.palletCode}\n机械手:${this.selectedRobot}`,
            "拆盘确认",
            {
              confirmButtonText: "确认",
              cancelButtonText: "取消",
              type: "warning"
            }
          );
          const result = await this.http.post("/api/StockInfoDetail/UnbindContainer", {
            palletCode: this.currentRow.palletCode,
            robotCode: this.selectedRobot
          }, "正在调用MES接口...");
          if (result.status) {
            this.$Message.success(result.message || "托盘拆盘成功");
            this.$parent.$refs.table.load();
          } else {
            this.$error(result.message || "托盘拆盘失败");
          }
        }
      } catch (error) {
        if (error !== "cancel") {
          this.$error(error.message || "网络错误,请稍后重试");
        }
      }
    }
  }
};
</script>
Code/WMS/WIDESEA_WMSClient/src/extension/stock/stockInfo.jsx
@@ -1,10 +1,11 @@
//此js文件是用来自定义扩展业务代码,可以扩展一些自定义页面或者重新配置生成的代码
import RobotSelect from './extend/RobotSelect.vue';
let extension = {
  components: {
    //查询界面扩展组件
    gridHeader: '',
    gridBody: '',
    gridBody: RobotSelect,
    gridFooter: '',
    //新建、编辑弹出框扩展组件
    modelHeader: '',
@@ -54,29 +55,8 @@
    },
    // æ‰˜ç›˜ç»„盘操作
    async handleBind(row) {
      try {
        await this.$confirm(`确认执行托盘组盘操作?\n托盘编号:${row.palletCode}`, "组盘确认", {
          confirmButtonText: "确认",
          cancelButtonText: "取消",
          type: "warning"
        });
        const result = await this.http.post("/api/StockInfoDetail/BindContainer", {
          palletCode: row.palletCode
        }, "正在调用MES接口...");
        if (result.status) {
          this.$Message.success(result.message || "托盘组盘成功");
          this.$refs.table.load();
        } else {
          this.$error(result.message || "托盘组盘失败");
        }
      } catch (error) {
        if (error !== "cancel") {
          this.$error(error.message || "网络错误,请稍后重试");
        }
      }
    handleBind(row) {
      this.$refs.gridBody.open('bind', row);
    },
    // æ‰˜ç›˜è¿›ç«™æ“ä½œ
@@ -134,29 +114,8 @@
    },
    // æ‰˜ç›˜æ‹†ç›˜æ“ä½œ
    async handleUnbind(row) {
      try {
        await this.$confirm(`确认执行托盘拆盘操作?\n托盘编号:${row.palletCode}`, "拆盘确认", {
          confirmButtonText: "确认",
          cancelButtonText: "取消",
          type: "warning"
        });
        const result = await this.http.post("/api/StockInfoDetail/UnbindContainer", {
          palletCode: row.palletCode,
        }, "正在调用MES接口...");
        if (result.status) {
          this.$Message.success(result.message || "托盘拆盘成功");
          this.$refs.table.load();
        } else {
          this.$error(result.message || "托盘拆盘失败");
        }
      } catch (error) {
        if (error !== "cancel") {
          this.$error(error.message || "网络错误,请稍后重试");
        }
      }
    handleUnbind(row) {
      this.$refs.gridBody.open('unbind', row);
    },
    onInited() {
Code/WMS/WIDESEA_WMSServer/WIDESEA_BasicService/MesService.cs
@@ -43,7 +43,7 @@
            };
        }
        private HttpRequestConfig BuildConfig(string token)
        public HttpRequestConfig BuildConfig(string token)
        {
            return new HttpRequestConfig
            {
Code/WMS/WIDESEA_WMSServer/WIDESEA_DTO/MES/BindContainerRequestDto.cs
@@ -18,6 +18,11 @@
        public List<string> SfcList { get; set; }
        /// <summary>
        /// è®¾å¤‡åç§°
        /// </summary>
        public string DeviceName { get; set; }
        /// <summary>
        /// ä½ç½®ä¿¡æ¯
        /// </summary>
        public string Location { get; set; }
Code/WMS/WIDESEA_WMSServer/WIDESEA_DTO/MES/UnbindContainerRequestDto.cs
@@ -13,6 +13,11 @@
        public string PalletCode { get; set; }
        /// <summary>
        /// è®¾å¤‡åç§°
        /// </summary>
        public string DeviceName { get; set; }
        /// <summary>
        /// ç”µèŠ¯ç åˆ—è¡¨
        /// </summary>
        public List<string> SfcList { get; set; }
Code/WMS/WIDESEA_WMSServer/WIDESEA_IBasicService/IMesService.cs
@@ -53,5 +53,12 @@
        /// æ‰˜ç›˜å‡ºç«™ï¼ˆæ”¯æŒåŠ¨æ€Token)
        /// </summary>
        HttpResponseResult<MesResponse> OutboundInContainer(OutboundInContainerRequest request, string token);
        /// <summary>
        ///  è¯·æ±‚头配置
        /// </summary>
        /// <param name="token"> è¯·æ±‚Token</param>
        /// <returns></returns>
        HttpRequestConfig BuildConfig(string token);
    }
}
Code/WMS/WIDESEA_WMSServer/WIDESEA_IBasicService/IMesUploadHelper.cs
@@ -22,7 +22,7 @@
            MesUploadStatusEnum successStatus,
            string apiType,
            string requestJson,
            Func<(bool isSuccess, string responseJson, string errorMessage)> mesCall,
            Func<(bool isSuccess, string responseJson, string errorMessage, string httpRequest)> mesCall,
            string creator = "System");
    }
}
Code/WMS/WIDESEA_WMSServer/WIDESEA_StockService/MesUploadHelper.cs
@@ -1,9 +1,10 @@
using Newtonsoft.Json.Linq;
using System.Diagnostics;
using WIDESEA_Common.StockEnum;
using WIDESEA_Core;
using WIDESEA_DTO.MES;
using WIDESEA_IStockService;
using WIDESEA_IBasicService;
using WIDESEA_IStockService;
namespace WIDESEA_StockService
{
@@ -34,7 +35,7 @@
            MesUploadStatusEnum successStatus,
            string apiType,
            string requestJson,
            Func<(bool isSuccess, string responseJson, string errorMessage)> mesCall,
            Func<(bool isSuccess, string responseJson, string errorMessage, string httpRequest)> mesCall,
            string creator = "System")
        {
            _ = Task.Run(async () =>
@@ -42,12 +43,14 @@
                var stopwatch = Stopwatch.StartNew();
                try
                {
                    var (isSuccess, responseJson, errorMessage) = mesCall();
                    var (isSuccess, responseJson, errorMessage, httpRequest) = mesCall();
                    stopwatch.Stop();
                    // å¥‡æ•°=成功,偶数=失败
                    int status = isSuccess ? (int)successStatus : (int)successStatus + 1;
                    await _stockInfoService.UpdateMesUploadStatusAsync(palletCode, status);
                    requestJson = MergeJsonObjects(requestJson, httpRequest);
                    await LogAsync(palletCode, apiType, requestJson, responseJson,
                        stopwatch.ElapsedMilliseconds, isSuccess, errorMessage, creator);
@@ -89,5 +92,16 @@
                // æ—¥å¿—记录失败不影响主流程
            }
        }
        public static string MergeJsonObjects(string json1, string json2)
        {
            var obj1 = JObject.Parse(json1);
            var obj2 = JObject.Parse(json2);
            obj1.Merge(obj2, new JsonMergeSettings
            {
                MergeArrayHandling = MergeArrayHandling.Union   // æ•°ç»„合并方式,可按需修改
            });
            return obj1.ToString();
        }
    }
}
Code/WMS/WIDESEA_WMSServer/WIDESEA_StockService/StockSerivce.cs
@@ -463,7 +463,8 @@
                        return (
                            result?.Data?.IsSuccess ?? false,
                            System.Text.Json.JsonSerializer.Serialize(result),
                            result?.Data?.Msg ?? result?.ErrorMessage ?? "未知错误"
                            result?.Data?.Msg ?? result?.ErrorMessage ?? "未知错误",
                            _mesService.BuildConfig(token ?? string.Empty).ToJson()
                        );
                    });
@@ -548,7 +549,8 @@
                        return (
                            result?.Data?.IsSuccess ?? false,
                            System.Text.Json.JsonSerializer.Serialize(result),
                            result?.Data?.Msg ?? result?.ErrorMessage ?? "未知错误"
                            result?.Data?.Msg ?? result?.ErrorMessage ?? "未知错误",
                            _mesService.BuildConfig(token ?? string.Empty).ToJson()
                        );
                    });
Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/WCS/TaskService_Inbound.cs
@@ -206,7 +206,8 @@
                                return (
                                    result?.Data?.IsSuccess ?? false,
                                    JsonConvert.SerializeObject(result),
                                    result?.Data?.Msg ?? result?.ErrorMessage ?? "未知错误"
                                    result?.Data?.Msg ?? result?.ErrorMessage ?? "未知错误",
                                    _mesService.BuildConfig(token ?? string.Empty).ToJson()
                                );
                            });
Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/WCS/TaskService_Outbound.cs
@@ -153,7 +153,8 @@
                            return (
                                result?.Data?.IsSuccess ?? false,
                                Newtonsoft.Json.JsonConvert.SerializeObject(result),
                                result?.Data?.Msg ?? result?.ErrorMessage ?? "未知错误"
                                result?.Data?.Msg ?? result?.ErrorMessage ?? "未知错误",
                                _mesService.BuildConfig(token ?? string.Empty).ToJson()
                            );
                        });
Code/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Stock/StockInfoController.cs
@@ -11,6 +11,7 @@
using WIDESEA_Model.Models;
using WIDESEA_Common.Constants;
using WIDESEA_Common.StockEnum;
using WIDESEA_Core.Helper;
namespace WIDESEA_WMSServer.Controllers.Stock
{
@@ -115,7 +116,8 @@
                        return (
                            result.Data?.IsSuccess ?? false,
                            System.Text.Json.JsonSerializer.Serialize(result),
                            result?.Data?.Msg ?? result?.ErrorMessage ?? "未知错误"
                            result?.Data?.Msg ?? result?.ErrorMessage ?? "未知错误",
                            _mesService.BuildConfig(token ?? string.Empty).ToJson()
                        );
                    },
                    App.User.UserName);
@@ -205,7 +207,8 @@
                        return (
                            result?.Data?.IsSuccess ?? false,
                            System.Text.Json.JsonSerializer.Serialize(result),
                            result?.Data?.Msg ?? result?.ErrorMessage ?? "未知错误"
                            result?.Data?.Msg ?? result?.ErrorMessage ?? "未知错误",
                            _mesService.BuildConfig(token ?? string.Empty).ToJson()
                        );
                    },
                    App.User.UserName);
Code/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Stock/StockInfoDetailController.cs
@@ -3,6 +3,7 @@
using WIDESEA_Common.StockEnum;
using WIDESEA_Core;
using WIDESEA_Core.BaseController;
using WIDESEA_Core.Helper;
using WIDESEA_DTO.MES;
using WIDESEA_IBasicService;
using WIDESEA_IStockService;
@@ -66,7 +67,7 @@
                var stockInfo = await _stockInfoService.Repository.QueryDataNavFirstAsync(x => x.PalletCode == dto.PalletCode);
                // 3. åŠ¨æ€èŽ·å–MES凭证
                var mesConfig = _mesDeviceConfigService.GetByDeviceName("组盘机械手");
                var mesConfig = _mesDeviceConfigService.GetByDeviceName(dto.DeviceName);
                string equipmentCode = mesConfig?.EquipmentCode ?? StockConstants.MES_EQUIPMENT_CODE;
                string resourceCode = mesConfig?.ResourceCode ?? StockConstants.MES_RESOURCE_CODE;
                string token = mesConfig?.Token;
@@ -102,7 +103,8 @@
                        return (
                            result?.Data?.IsSuccess ?? false,
                            System.Text.Json.JsonSerializer.Serialize(result),
                            result?.Data?.Msg ?? result?.ErrorMessage ?? "未知错误"
                            result?.Data?.Msg ?? result?.ErrorMessage ?? "未知错误",
                            _mesService.BuildConfig(token ?? string.Empty).ToJson()
                        );
                    },
                    App.User.UserName);
@@ -143,7 +145,7 @@
                var stockInfo = await _stockInfoService.Repository.QueryDataNavFirstAsync(x => dto.PalletCode == x.PalletCode);
                // 3. åŠ¨æ€èŽ·å–MES凭证
                var mesConfig = _mesDeviceConfigService.GetByDeviceName("组盘机械手");
                var mesConfig = _mesDeviceConfigService.GetByDeviceName(dto.DeviceName);
                string equipmentCode = mesConfig?.EquipmentCode ?? StockConstants.MES_EQUIPMENT_CODE;
                string resourceCode = mesConfig?.ResourceCode ?? StockConstants.MES_RESOURCE_CODE;
                string token = mesConfig?.Token;
@@ -174,7 +176,8 @@
                        return (
                            result?.Data?.IsSuccess ?? false,
                            System.Text.Json.JsonSerializer.Serialize(result),
                            result?.Data?.Msg ?? result?.ErrorMessage ?? "未知错误"
                            result?.Data?.Msg ?? result?.ErrorMessage ?? "未知错误",
                            _mesService.BuildConfig(token ?? string.Empty).ToJson()
                        );
                    },
                    App.User.UserName);
@@ -253,9 +256,10 @@
                    {
                        var result = _mesService.ContainerNgReport(mesRequest);
                        return (
                            result?.IsSuccess ?? false,
                            result?.Data?.IsSuccess ?? false,
                            System.Text.Json.JsonSerializer.Serialize(result),
                            result?.ErrorMessage ?? "未知错误"
                            result?.Data?.Msg ?? result?.ErrorMessage ?? "未知错误",
                            _mesService.BuildConfig(mesConfig?.Token ?? string.Empty).ToJson()
                        );
                    },
                    App.User.UserName);