Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Common/HttpEnum/ConfigKey.cs
@@ -92,7 +92,12 @@ /// <summary> /// 批量组盘确认 /// </summary> GroupPalletConfirm GroupPalletConfirm, /// <summary> /// 根据托盘号查询库存明细数量 /// </summary> GetStockDetailCount #endregion WMS接口 } Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/RobotTaskService.cs
@@ -25,6 +25,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using WIDESEA_Core; using WIDESEAWCS_Common; using WIDESEAWCS_Common.HttpEnum; using WIDESEAWCS_Common.TaskEnum; using WIDESEAWCS_Core; @@ -205,14 +206,20 @@ RobotTargetAddress = section[1]!, RobotSourceAddressLineCode = stock?.SourceLineNo ?? string.Empty, RobotTargetAddressLineCode = stock?.TargetLineNo ?? string.Empty, RobotRoadway = stock?.TargetLineNo == "11068" ? "注液组盘机械手" : "换盘机械手" ?? string.Empty, // todo RobotRoadway = stock?.TargetLineNo switch { "11068" => "注液组盘机械手", "1000" => "拆盘机械手", "2000" => "成品组盘机械手", _ => "换盘机械手" }, RobotSourceAddressPalletCode = stock?.SourcePalletNo ?? string.Empty, RobotTargetAddressPalletCode = stock?.TargetPalletNo ?? string.Empty, RobotTaskType = taskType, RobotTaskState = (int)TaskRobotStatusEnum.RobotNew, RobotGrade = task.Grade, Creater = "WCS_Local", RobotTaskTotalNum = taskType == (int)RobotTaskTypeEnum.GroupPallet ? 48 : 1, RobotTaskTotalNum = GetRobotTaskTotalNum(taskType, stock.SourcePalletNo), CreateDate = DateTime.Now }; @@ -233,6 +240,38 @@ } /// <summary> /// 获取机械手任务总数量。 /// 组盘任务固定48,换盘和拆盘任务通过托盘号查询WMS库存明细数量。 /// </summary> private int GetRobotTaskTotalNum(int taskType, string? palletCode) { if (taskType == (int)RobotTaskTypeEnum.GroupPallet) return 48; if (string.IsNullOrWhiteSpace(palletCode)) return 1; try { string url = $"{BaseAPI.WMSBaseUrl}Stock/GetStockDetailCount?palletCode={Uri.EscapeDataString(palletCode)}"; var result = _httpClientHelper.Get(url); if (!result.IsSuccess || string.IsNullOrEmpty(result.Content)) return 1; var response = JsonConvert.DeserializeObject<WebResponseContent>(result.Content); if (response == null || !response.Status) return 1; var detailCount = response.Data?.GetType().GetProperty("DetailCount")?.GetValue(response.Data); return detailCount is int count and > 0 ? count : 1; } catch { return 1; } } /// <summary> /// 将配置键映射到机械手任务类型枚举值。 /// </summary> /// <param name="configKey">配置键名称</param> Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/CommonConveyorLineNewJob.cs
@@ -6,6 +6,7 @@ using Serilog; using SqlSugar; using WIDESEA_Core; using WIDESEAWCS_Common.HttpEnum; using WIDESEAWCS_Common.TaskEnum; using WIDESEAWCS_Core; using WIDESEAWCS_Core.Helper; @@ -148,15 +149,6 @@ return Task.CompletedTask; } // 创建并行选项,限制最大并发数 //var parallelOptions = new ParallelOptions //{ // // 限制并发数:子设备数量和 CPU 核心数*2 的较小值 // MaxDegreeOfParallelism = Math.Min(childDeviceCodes.Count, Environment.ProcessorCount * 2), //}; // 并行处理每个子设备 //Parallel.For(0, childDeviceCodes.Count, parallelOptions, i => foreach (var childDeviceCode in childDeviceCodes) { //string childDeviceCode = childDeviceCodes[i]; @@ -274,15 +266,15 @@ QuartzLogHelper.LogInfo(_logger, $"处理任务 {task.TaskNum},状态: {task.TaskStatus}", conveyorLine.DeviceCode); // 处理任务状态(根据状态分发到不同方法) ProcessTaskState(conveyorLine, command, task, childDeviceCode); return Task.CompletedTask; continue; } else if (!command.Barcode.IsNullOrEmpty() && childDeviceCode == "11068") { var isWcsTask = _taskService.Db.Queryable<Dt_Task>().Any(x => x.PalletCode == command.Barcode && x.TaskStatus == (int)TaskOutStatusEnum.OutNew); var isRobotTask = _robotTaskService.Db.Queryable<Dt_RobotTask>().Any(x => x.RobotTargetAddressPalletCode == command.Barcode); var isWcsTask = _taskService.Db.Queryable<Dt_Task>().Any(x => x.PalletCode == command.Barcode && (x.TaskStatus == (int)TaskOutStatusEnum.OutNew || x.TaskStatus == (int)TaskInStatusEnum.InNew)); var isRobotTask = _robotTaskService.Db.Queryable<Dt_RobotTask>().Any(x => x.RobotTargetAddressPalletCode == command.Barcode || x.RobotRoadway == "注液组盘机械手"); if (isWcsTask || isRobotTask) { return Task.CompletedTask; continue; } // 直接添加机械手组盘任务 @@ -306,6 +298,48 @@ conveyorLine.SetValue(ConveyorLineDBNameNew.WCS_ACK, (short)1, childDeviceCode); } } else if (!command.Barcode.IsNullOrEmpty() && (childDeviceCode == "11001" || childDeviceCode == "11010")) { var isWcsTask = _taskService.Db.Queryable<Dt_Task>().Any(x => x.PalletCode == command.Barcode && (x.TaskStatus == (int)TaskOutStatusEnum.OutNew || x.TaskStatus == (int)TaskInStatusEnum.InNew)); var isRobotTask = _robotTaskService.Db.Queryable<Dt_RobotTask>().Any(x => x.RobotTargetAddressPalletCode == command.Barcode); if (isWcsTask || isRobotTask) { continue; } // 调用 WMS 创建空托盘入库任务 string configKey = nameof(ConfigKey.CreateTaskInboundAsync); string requestParam = new CreateTaskDto() { PalletCode = command.Barcode, SourceAddress = childDeviceCode, TargetAddress = "GWSC1", // 目标地址 Roadway = "GWSC1", // 巷道 WarehouseId = 1, // 仓库 ID PalletType = 1, // 托盘类型(默认为1) TaskType = TaskTypeEnum.InEmpty.GetHashCode() // 任务类型(入库/空托盘入库) }.Serialize(); DateTime startTime = DateTime.Now; var responseResult = _httpClientHelper.Post<WebResponseContent>(configKey, requestParam); if (responseResult.IsSuccess && responseResult.Data.Status) { QuartzLogHelper.LogInfo(_logger, $"调用WMS接口成功,接口:【{configKey}】,请求参数:【{requestParam}】,响应数据:【{responseResult.Data?.Data}】,耗时:{(DateTime.Now - startTime).TotalMilliseconds}ms", conveyorLine.DeviceCode); var wmsTask = JsonConvert.DeserializeObject<WMSTaskDTO>(responseResult?.Data?.Data?.ToString()); List<WMSTaskDTO> taskDTOs = new List<WMSTaskDTO> { wmsTask }; if (wmsTask == null) continue; if (_taskService.ReceiveWMSTask(taskDTOs).Status) { conveyorLine.SetValue(ConveyorLineDBNameNew.WCS_ACK, (short)1, childDeviceCode); } } else { QuartzLogHelper.LogError(_logger, $"调用WMS接口失败,接口:【{configKey}】,请求参数:【{requestParam}】,错误信息:【{responseResult.Data?.Message}】", conveyorLine.DeviceCode); } } } } catch (Exception innerEx) Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/SocketServer/TcpSocketServer.Messaging.cs
@@ -60,11 +60,15 @@ break; } if(message == lastMessage) // 按客户端去重:检查是否与该客户端上次消息相同 lock (_syncRoot) { // 重复消息,忽略 if (_clientLastMessage.TryGetValue(clientId, out var prev) && message == prev) { continue; } _clientLastMessage[clientId] = message; } // 更新客户端状态 UpdateClientStatus(clientId, message); Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/SocketServer/TcpSocketServer.Server.cs
@@ -161,6 +161,9 @@ // 移除活跃时间记录 _clientLastActive.Remove(clientId); // 移除上次消息记录 _clientLastMessage.Remove(clientId); // 移除编码记录 _clientEncodings.Remove(clientId); Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/SocketServer/TcpSocketServer.cs
@@ -1,13 +1,6 @@ using Microsoft.Extensions.Options; using System; using System.Collections.Generic; using System.IO; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; using WIDESEAWCS_Model.Models; using WIDESEAWCS_QuartzJob; namespace WIDESEAWCS_Tasks.SocketServer { @@ -137,9 +130,13 @@ public bool IsRunning { get; private set; } /// <summary> /// 上次接收消息源 /// 每个客户端上次接收的消息,用于去重 /// </summary> public string lastMessage; /// <remarks> /// Key: 客户端 ID /// Value: 上次接收的消息内容 /// </remarks> public readonly Dictionary<string, string> _clientLastMessage = new(); /// <summary> /// 消息接收事件 @@ -200,6 +197,7 @@ /// <param name="message">日志消息</param> private void Log(string message) { //Logger.None.Information(message); Console.WriteLine(message); try { File.AppendAllText(_logFile, message + Environment.NewLine); } catch { } } Code/WMS/WIDESEA_WMSServer/WIDESEA_IStockService/IStockService.cs
@@ -71,5 +71,12 @@ /// <param name="deviceName">设备名称(用于动态MES凭证查询)</param> /// <returns>操作结果</returns> Task<WebResponseContent> GroupPalletConfirmAsync(string palletCode, string deviceName); /// <summary> /// 根据托盘号查询库存明细数量 /// </summary> /// <param name="palletCode">托盘号</param> /// <returns>库存明细数量</returns> Task<WebResponseContent> GetStockDetailCountByPalletCodeAsync(string palletCode); } } Code/WMS/WIDESEA_WMSServer/WIDESEA_StockService/StockSerivce.cs
@@ -584,6 +584,26 @@ } /// <summary> /// 根据托盘号查询库存明细数量 /// </summary> /// <param name="palletCode">托盘号</param> /// <returns>库存明细数量</returns> public async Task<WebResponseContent> GetStockDetailCountByPalletCodeAsync(string palletCode) { WebResponseContent content = new WebResponseContent(); if (string.IsNullOrWhiteSpace(palletCode)) return content.Error("托盘号不能为空"); var stockInfo = StockInfoService.Repository.QueryFirst(s => s.PalletCode == palletCode); if (stockInfo == null) return content.Error("托盘不存在"); var count = await StockInfoDetailService.Repository.Db.Queryable<Dt_StockInfoDetail>() .CountAsync(d => d.StockId == stockInfo.Id); return content.OK("查询成功", new { PalletCode = palletCode, DetailCount = count }); } /// <summary> /// 根据设备名称和托盘号解析MES设备配置 /// </summary> /// <param name="deviceName">设备名称</param> Code/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Stock/StockController.cs
@@ -85,5 +85,16 @@ { return await Service.GroupPalletConfirmAsync(dto.PalletCode, dto.DeviceName); } /// <summary> /// 根据托盘号查询库存明细数量 /// </summary> /// <param name="palletCode">托盘号</param> /// <returns>库存明细数量</returns> [HttpGet("GetStockDetailCount"), AllowAnonymous] public async Task<WebResponseContent> GetStockDetailCount(string palletCode) { return await Service.GetStockDetailCountByPalletCodeAsync(palletCode); } } }