wanshenmean
9 小时以前 c9a1df9c19a64844d05d120ff171f523d77e7823
Merge branch 'xiaoyang' into dev
已删除3个文件
已修改26个文件
2807 ■■■■ 文件已修改
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Common/HttpEnum/ConfigKey.cs 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Communicator/Siemens/SiemensS7Communicator.cs 64 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/RobotTaskService.cs 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/TaskService/TaskService.Receive.cs 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/TaskService/TaskService.Status.cs 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/CommonConveyorLineNewJob.cs 65 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/ConstraintMachine/ConstraintMachineDBName.cs 81 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/ConveyorLineDispatchHandler.cs 35 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/ConveyorLineTargetAddressSelector.cs 382 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/ManualInbound/ManualInboundTaskHandler.cs 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/PinMachine/PinMachineCommand.cs 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/PinMachine/PinMachineDBName.cs 83 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Abstractions/ISocketClientGateway.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotClientManager.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotTaskProcessor.cs 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/SocketServer/SocketClientGateway.cs 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/SocketServer/TcpSocketServer.Messaging.cs 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/SocketServer/TcpSocketServer.Server.cs 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/SocketServer/TcpSocketServer.cs 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/StackerCraneJob/StackerCraneTaskSelector.cs 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSServer/WIDESEA_IStockService/IStockService.cs 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSServer/WIDESEA_StockService/StockSerivce.cs 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService_GradingMachine.cs 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/WCS/TaskService_AutoOutbound.cs 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/WCS/TaskService_Tray.cs 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Stock/StockController.cs 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/测试工具/WIDESEAWCS_S7Simulator/WIDESEAWCS_S7Simulator.Server/Data/instance-1001/config.json 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/测试工具/WIDESEAWCS_S7Simulator/WIDESEAWCS_S7Simulator.Server/Data/instance-1002/config.json 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/测试工具/WIDESEAWCS_S7Simulator/WIDESEAWCS_S7Simulator.Server/Data/protocol-templates.json 1789 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
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_Communicator/Siemens/SiemensS7Communicator.cs
@@ -1,4 +1,5 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_Communicator
 * åˆ›å»ºè€…:胡童庆
@@ -13,6 +14,7 @@
 * ä¿®æ”¹è¯´æ˜Žï¼š
 * 
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using HslCommunication;
@@ -20,19 +22,12 @@
using HslCommunication.LogNet;
using HslCommunication.Profinet.Siemens;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace WIDESEAWCS_Communicator
{
@@ -43,6 +38,7 @@
    public class SiemensS7 : BaseCommunicator
    {
        #region Private Member
        /// <summary>
        /// HSLCommunication的西门子的S7协议的通讯类
        /// </summary>
@@ -71,9 +67,11 @@
        private ILogNet _logNet;
        private bool _isPing = true;
        #endregion Private Member
        #region Public Member
        /// <summary>  
        /// èŽ·å–å½“å‰é€šè®¯å™¨æ˜¯å¦å·²è¿žæŽ¥åˆ°PLC。  
        /// </summary>
@@ -92,10 +90,12 @@
        /// <summary>
        /// æ˜¯å¦åœ¨å†™å…¥æ•°æ®åŽè¯»å–数据确认。
        /// </summary>
        public override bool IsReadAfterWrite { get; set; } = false;
        public override bool IsReadAfterWrite { get; set; } = true;
        #endregion Public Member
        #region Constructor Function
        /// <summary>
        /// æž„造函数
        /// </summary>
@@ -118,9 +118,11 @@
            _port = port;//通过构造函数赋值连接使用的端口号
            _name = name;
        }
        #endregion
        #region Private Method
        /// <summary>
        /// ä»ŽOperateResult对象中获取读取的数据。
        /// </summary>
@@ -221,25 +223,32 @@
            try
            {
                Type type = value.GetType();
                switch (Type.GetTypeCode(type))
                {
                    case TypeCode.Int32:
                        return plc.Write(address, Convert.ToInt32(value));
                    case TypeCode.UInt32:
                        return plc.Write(address, Convert.ToUInt32(value));
                    case TypeCode.Int16:
                        return plc.Write(address, Convert.ToInt16(value));
                    case TypeCode.UInt16:
                        return plc.Write(address, Convert.ToUInt16(value));
                    case TypeCode.Single:
                        return plc.Write(address, Convert.ToSingle(value));
                    case TypeCode.Boolean:
                        return plc.Write(address, Convert.ToBoolean(value));
                    case TypeCode.Byte:
                        return plc.Write(address, Convert.ToByte(value));
                    case TypeCode.String:
                        return plc.Write(address, Convert.ToString(value));
                    case TypeCode.Char:
                        return plc.Write(address, Convert.ToChar(value));
                    //case TypeCode.arr:
@@ -302,44 +311,53 @@
                            return (int[])GetContent(plc.ReadInt32(address, length), address);
                        else
                            return (int)GetContent(plc.ReadInt32(address), address);
                    case TypeCode.UInt32:
                        if (length > 1)
                            return (uint[])GetContent(plc.ReadUInt32(address, length), address);
                        else
                            return (uint)GetContent(plc.ReadUInt32(address), address);
                    case TypeCode.Int16:
                        if (length > 1)
                            return (short[])GetContent(plc.ReadInt16(address, length), address);
                        else
                            return (short)GetContent(plc.ReadInt16(address), address);
                    case TypeCode.UInt16:
                        if (length > 1)
                            return (ushort[])GetContent(plc.ReadUInt16(address, length), address);
                        else
                            return (ushort)GetContent(plc.ReadUInt16(address), address);
                    case TypeCode.Single:
                        if (length > 1)
                            return (float[])GetContent(plc.ReadFloat(address, length), address);
                        else
                            return (float)GetContent(plc.ReadFloat(address), address);
                    case TypeCode.Boolean:
                        if (length > 1)
                            return (bool[])GetContent(plc.ReadBool(address, length), address);
                        else
                            return (bool)GetContent(plc.ReadBool(address), address);
                    case TypeCode.Byte:
                        if (length > 1)
                            return (byte)GetContent(plc.Read(address, length), address);
                        return (byte)GetContent(plc.ReadByte(address), address);
                    case TypeCode.String:
                        if (length > 1)
                            return (string)GetContent(plc.ReadString(address, length), address);
                        else
                            return (string)GetContent(plc.ReadString(address), address);
                    case TypeCode.Char:
                        if (length > 1)
                            return Encoding.Default.GetString((byte[])GetContent(plc.Read(address, length), address)).ToArray();
                        return (char)GetContent(plc.ReadByte(address), address);
                    default:
                        throw new CommunicationException(string.Format(CommunicationExceptionMessage.DataTypeErrorException, typeCode.ToString(), address), CommunicationErrorType.TypeError);
                }
@@ -376,11 +394,12 @@
                    }
                }
            });
        }
        #endregion
        #region Public Method
        /// <summary>  
        /// è¿žæŽ¥åˆ°PLC。
        /// </summary>  
@@ -442,6 +461,7 @@
        }
        #region Read
        /// <summary>  
        /// ä»ŽPLC读取数据。  
        /// </summary>  
@@ -495,9 +515,11 @@
            else
                return Read(address, SiemensDBDataType.GetTypeCode(dataType));
        }
        #endregion
        #region Write
        /// <summary>
        /// å‘PLC写入数据。
        /// </summary>
@@ -540,7 +562,6 @@
            return GetResult(Write(address, value), address, value);
        }
        public override bool Write<T>(string address, T[] values)
        {
            return GetResult(Write(address, values), address, values);
@@ -573,6 +594,7 @@
                        obj = GetResult(Write(address, writeVal), address, writeVal);
                    }
                    break;
                case SiemensDBDataType.DataType_DW:
                    {
                        uint writeVal;
@@ -587,6 +609,7 @@
                        obj = GetResult(Write(address, writeVal), address, writeVal);
                    }
                    break;
                case SiemensDBDataType.DataType_Int:
                    {
                        short writeVal;
@@ -601,6 +624,7 @@
                        obj = GetResult(Write(address, writeVal), address, writeVal);
                    }
                    break;
                case SiemensDBDataType.DataType_W:
                    {
                        ushort writeVal;
@@ -615,6 +639,7 @@
                        obj = GetResult(Write(address, writeVal), address, writeVal);
                    }
                    break;
                case SiemensDBDataType.DataType_Float:
                    {
                        float writeVal;
@@ -629,6 +654,7 @@
                        obj = GetResult(Write(address, writeVal), address, writeVal);
                    }
                    break;
                case SiemensDBDataType.DataType_Bool:
                    {
                        bool writeVal;
@@ -643,6 +669,7 @@
                        obj = GetResult(Write(address, writeVal), address, writeVal);
                    }
                    break;
                case SiemensDBDataType.DataType_Byte:
                    {
                        byte writeVal;
@@ -657,6 +684,7 @@
                        obj = GetResult(Write(address, writeVal), address, writeVal);
                    }
                    break;
                case SiemensDBDataType.DataType_String:
                    {
                        string writeVal;
@@ -672,6 +700,7 @@
                    }
                    break;
                case SiemensDBDataType.DataType_Char:
                    break;
@@ -690,14 +719,17 @@
                        obj = GetResult(Write(address, writeVal), address, writeVal);
                    }
                    break;
                default:
                    throw new CommunicationException(string.Format(CommunicationExceptionMessage.DataTypeErrorException, dataType, address), CommunicationErrorType.TypeError);
            }
            return obj;
        }
        #endregion
        #region ReadCustomer
        /// <summary>
        /// è¯»å–自定义的数据类型,需要继承自IDataTransfer接口,返回一个新的类型的实例对象。
        /// </summary>
@@ -716,9 +748,11 @@
                throw new CommunicationException(ex.Message, CommunicationErrorType.ReadException, innerException: ex);
            }
        }
        #endregion
        #region WriteCustomer
        /// <summary>
        /// å†™å…¥è‡ªå®šä¹‰ç±»åž‹çš„æ•°æ®ï¼Œè¯¥ç±»åž‹å¿…须继承自IDataTransfer接口。
        /// </summary>
@@ -785,6 +819,7 @@
                LogNet.WriteInfo(Name, stringBuilder.ToString());
            }
        }
        #endregion
        /// <summary>
@@ -829,22 +864,28 @@
                case TypeCode.Int16:
                    OperateResult<TimeSpan> operateResultShort = plc.Wait(address, Convert.ToInt16(value), readInterval, waitTimeout);
                    return operateResultShort;
                case TypeCode.Int32:
                    OperateResult<TimeSpan> operateResultInt = plc.Wait(address, Convert.ToInt16(value), readInterval, waitTimeout);
                    return operateResultInt;
                case TypeCode.UInt16:
                    OperateResult<TimeSpan> operateResultUShort = plc.Wait(address, Convert.ToInt16(value), readInterval, waitTimeout);
                    return operateResultUShort;
                case TypeCode.UInt32:
                    OperateResult<TimeSpan> operateResultUInt = plc.Wait(address, Convert.ToInt16(value), readInterval, waitTimeout);
                    return operateResultUInt;
                default:
                    throw new NotSupportedException();
            }
        }
        #endregion
        #region Destruction Function
        /// <summary>
        /// æžæž„函数,确保在不再需要时关闭连接  
        /// </summary>
@@ -852,6 +893,7 @@
        {
            Dispose();
        }
        #endregion
    }
}
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_TaskInfoService/TaskService/TaskService.Receive.cs
@@ -1,13 +1,8 @@
using MapsterMapper;
using System.Diagnostics.CodeAnalysis;
using WIDESEA_Core;
using WIDESEAWCS_Common.TaskEnum;
using WIDESEAWCS_Core;
using WIDESEAWCS_Core.Enums;
using WIDESEAWCS_DTO.TaskInfo;
using WIDESEAWCS_Model.Models;
using WIDESEAWCS_QuartzJob;
using WIDESEAWCS_QuartzJob.Models;
namespace WIDESEAWCS_TaskInfoService;
@@ -104,12 +99,16 @@
        {
            case TaskTypeGroup.OutbondGroup:
                return _outboundTaskFlowService.InitializeOnReceive(task, source);
            case TaskTypeGroup.InboundGroup:
                return _inboundTaskFlowService.InitializeOnReceive(task, source);
            case TaskTypeGroup.RelocationGroup:
                return _relocationTaskFlowService.InitializeOnReceive(task, source);
            case TaskTypeGroup.OtherGroup:
                return _robotTaskFlowService.InitializeOnReceive(task, source);
            default:
                return WebResponseContent.Instance.Error("WCS不存在当前任务的任务类型");
        }
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/TaskService/TaskService.Status.cs
@@ -1,3 +1,4 @@
using Serilog.Core;
using System.Diagnostics.CodeAnalysis;
using WIDESEAWCS_Common.TaskEnum;
using WIDESEAWCS_Core;
@@ -5,6 +6,7 @@
using WIDESEAWCS_DTO.TaskInfo;
using WIDESEAWCS_Model.Models;
using WIDESEAWCS_QuartzJob.Models;
using WIDESEAWCS_Tasks;
namespace WIDESEAWCS_TaskInfoService;
@@ -92,6 +94,9 @@
    /// <returns></returns>
    public WebResponseContent UpdateTaskStatusToNext([NotNull] Dt_Task task)
    {
        WebResponseContent content = new WebResponseContent();
        try
        {
        int oldState = task.TaskStatus;
        var result = task.TaskType.GetTaskTypeGroup() switch
@@ -100,7 +105,7 @@
            TaskTypeGroup.InboundGroup => _inboundTaskFlowService.MoveToNextStatus(task),
            TaskTypeGroup.RelocationGroup => _relocationTaskFlowService.MoveToNextStatus(task),
            TaskTypeGroup.OtherGroup => _robotTaskFlowService.MoveToNextStatus(task),
            _ => WebResponseContent.Instance.Error($"任务类型错误,未找到该任务类型,任务号:【{task.TaskNum}】,任务类型:【{task.TaskType}】")
                _ => content.Error($"任务类型错误,未找到该任务类型,任务号:【{task.TaskNum}】,任务类型:【{task.TaskType}】")
        };
        if (!result.Status)
@@ -111,7 +116,7 @@
            && result.Data is List<WMSTaskDTO> wmsTasks
            && wmsTasks.Count > 0)
        {
            WebResponseContent content = ReceiveWMSTask(wmsTasks);
                content = ReceiveWMSTask(wmsTasks);
            if (!content.Status)
                return content;
        }
@@ -134,7 +139,13 @@
            : $"系统自动流程,任务状态从【{oldState}】转到【{task.TaskStatus}】";
        _taskExecuteDetailService.AddTaskExecuteDetail(task.TaskId, logMessage);
        return WebResponseContent.Instance.OK();
            return content.OK();
        }
        catch (Exception ex)
        {
            QuartzLogHelper.LogError(Logger.None, $"UpdateTaskStatusToNext æ›´æ–°å°†ä»»åŠ¡çŠ¶æ€ä¿®æ”¹ä¸ºä¸‹ä¸€ä¸ªçŠ¶æ€å¤±è´¥,任务号:【{task.TaskNum}】,错误信息:【{ex.Message}】", "UpdateTaskStatusToNext");
            return content.Error(ex.Message);
        }
    }
    /// <summary>
@@ -171,7 +182,8 @@
        }
        catch (Exception ex)
        {
            Console.WriteLine($"UpdatePosition æ›´æ–°ä»»åŠ¡ä½ç½®å¤±è´¥,任务号:【{taskNum}】,错误信息:【{ex.Message}】");
            QuartzLogHelper.LogError(Logger.None, $"UpdatePosition æ›´æ–°ä»»åŠ¡ä½ç½®å¤±è´¥,任务号:【{taskNum}】,错误信息:【{ex.Message}】", "UpdatePosition");
            //Console.WriteLine($"UpdatePosition æ›´æ–°ä»»åŠ¡ä½ç½®å¤±è´¥,任务号:【{taskNum}】,错误信息:【{ex.Message}】");
        }
        return null;
    }
@@ -208,7 +220,7 @@
        }
        catch (Exception ex)
        {
            Console.WriteLine($"UpdatePosition æ›´æ–°ä»»åŠ¡ä½ç½®å¤±è´¥,任务号:【{taskNum}】,错误信息:【{ex.Message}】");
            QuartzLogHelper.LogError(Logger.None, $"UpdatePosition æ›´æ–°ä»»åŠ¡ä½ç½®å¤±è´¥,任务号:【{taskNum}】,错误信息:【{ex.Message}】", "UpdatePosition");
        }
        return null;
    }
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];
@@ -193,8 +185,8 @@
                                if (command.CV_State == 2)
                                {
                                    // æ£€æŸ¥è¯¥ä½ç½®æ˜¯å¦å·²æœ‰ä»»åŠ¡
                                    var existingTask = _taskService.Db.Queryable<Dt_Task>().First(x => x.TargetAddress == childDeviceCode);
                                    if (existingTask.IsNullOrEmpty())
                                    var existingTask = _taskService.Db.Queryable<Dt_Task>().Count(x => x.TargetAddress == childDeviceCode);
                                    if (existingTask < 5)
                                    {
                                        // æ²¡æœ‰ä»»åŠ¡ï¼Œå‘ WMS è¯·æ±‚出库托盘任务
                                        var position = checkPalletPositions.FirstOrDefault(x => x.Code == childDeviceCode);
@@ -274,15 +266,16 @@
                                    QuartzLogHelper.LogInfo(_logger, $"处理任务 {task.TaskNum},状态: {task.TaskStatus}", conveyorLine.DeviceCode);
                                    // å¤„理任务状态(根据状态分发到不同方法)
                                    ProcessTaskState(conveyorLine, command, task, childDeviceCode);
                                    return Task.CompletedTask;
                                    continue;
                                }
                                // Todo: ä¸‹é¢çš„逻辑主要处理没有查询到任务但有条码的情况,可能是需要生成机械手任务或者调用 WMS åˆ›å»ºå…¥åº“任务 ï¼ˆä¸´æ—¶ä½¿ç”¨ï¼‰
                                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 +299,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/ConveyorLineNewJob/ConstraintMachine/ConstraintMachineDBName.cs
ÎļþÒÑɾ³ý
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/ConveyorLineDispatchHandler.cs
@@ -266,23 +266,46 @@
            }
            // è®¾ç½®ä»»åŠ¡å·ã€æ‰˜ç›˜æ¡ç ã€ç›®æ ‡åœ°å€ã€WCS_ACK
            conveyorLine.SetValue(ConveyorLineDBNameNew.TaskNo, task.TaskNum, childDeviceCode);
            conveyorLine.SetValue(ConveyorLineDBNameNew.Barcode, task.PalletCode, childDeviceCode);
            conveyorLine.SetValue(ConveyorLineDBNameNew.Target, targetAddress, childDeviceCode);
            conveyorLine.SetValue(ConveyorLineDBNameNew.WCS_ACK, (short)1, childDeviceCode);
            var isTaskNoSet = conveyorLine.SetValue(ConveyorLineDBNameNew.TaskNo, task.TaskNum, childDeviceCode);
            Thread.Sleep(100); // ç¡®ä¿ PLC èƒ½æ­£ç¡®è¯»å–任务号后再写入条码
            var isPalletSet = conveyorLine.SetValue(ConveyorLineDBNameNew.Barcode, task.PalletCode, childDeviceCode);
            bool isTargetSet = true;
            if (targetAddress == "2217" && !isEmptyTask)
            {
                QuartzLogHelper.LogDebug(_logger, $"子设备: {childDeviceCode},出库目标地址: {targetAddress}", conveyorLine.DeviceCode);
                Thread.Sleep(100); // ç¡®ä¿ PLC èƒ½æ­£ç¡®è¯»å–任务号后再写入条码
                isTargetSet = conveyorLine.SetValue(ConveyorLineDBNameNew.Target, targetAddress, childDeviceCode);
            }
            if (!isTargetSet || !isTaskNoSet || !isPalletSet)
            {
                QuartzLogHelper.LogError(_logger, $"RequestOutbound:下发出库任务失败,任务号: {task.TaskNum},子设备: {childDeviceCode}", conveyorLine.DeviceCode);
                return Task.CompletedTask;
            }
            bool isWmsResult = false;
            // æ›´æ–°ä»»åŠ¡çŠ¶æ€æˆ–ä½ç½®
            if (isEmptyTask && task.NextAddress == "2217")
            {
                task.TaskStatus = task.TaskStatus.GetNextNotCompletedStatus<TaskOutStatusEnum>();
                task.NextAddress = "2201";
                _taskService.Repository.UpdateData(task);
                isWmsResult = _taskService.Repository.UpdateData(task);
            }
            else
            {
                _taskService.UpdateTaskStatusToNext(task);
                isWmsResult = _taskService.UpdateTaskStatusToNext(task).Status;
            }
            if(!isWmsResult)
            {
                QuartzLogHelper.LogError(_logger, $"RequestOutbound:更新任务状态失败,任务号: {task.TaskNum},子设备: {childDeviceCode}", conveyorLine.DeviceCode);
                return Task.CompletedTask;
            }
            Thread.Sleep(100); // ç¡®ä¿ PLC èƒ½æ­£ç¡®è¯»å–任务号后再写入条码
            conveyorLine.SetValue(ConveyorLineDBNameNew.WCS_ACK, (short)1, childDeviceCode);
            QuartzLogHelper.LogInfo(_logger, "RequestOutbound:出库任务已下发,任务号: {TaskNum},子设备: {ChildDeviceCode}", $"出库任务已下发,任务号: {task.TaskNum}", conveyorLine.DeviceCode, task.TaskNum, childDeviceCode);
            return Task.CompletedTask;
        }
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/ConveyorLineTargetAddressSelector.cs
@@ -4,105 +4,12 @@
namespace WIDESEAWCS_Tasks
{
    /// <summary>
    /// è¾“送线目标地址选择器 - å¤„理拘束机/插拔钉机的上下层请求
    /// è¾“送线目标地址选择器
    /// </summary>
    /// <remarks>
    /// æ ¸å¿ƒèŒè´£ï¼š
    /// 1. å¤„理入库场景的目标地址选择
    /// 2. å¤„理出库场景的目标地址选择
    /// 3. åˆ¤æ–­æ‹˜æŸæœºå’Œæ’拔钉机的物料请求状态
    /// 4. åè°ƒè¾“送线与上下层设备之间的物料流转
    ///
    /// æ‹˜æŸæœºå’Œæ’拔钉机都有上下两层结构,
    /// æ¯å±‚都有独立的物料请求和出料信号,需要分别处理。
    /// </remarks>
    public class ConveyorLineTargetAddressSelector
    {
        /// <summary>
        /// è®¾å¤‡å±‚级(上层/下层)
        /// </summary>
        /// <remarks>
        /// ç”¨äºŽåŒºåˆ†æ‹˜æŸæœºå’Œæ’拔钉机的上层工位和下层工位。
        /// å…¥åº“任务对应上层(MaterialRequestUpper),出库任务对应下层(MaterialRequestLower)。
        /// </remarks>
        private enum Layer
        {
            /// <summary>
            /// ä¸Šå±‚工位
            /// </summary>
            Upper,
            /// <summary>
            /// ä¸‹å±‚工位
            /// </summary>
            Lower
        }
        /// <summary>
        /// ç›®æ ‡è®¾å¤‡ç±»åž‹æžšä¸¾
        /// </summary>
        /// <remarks>
        /// ç”¨äºŽæ ¹æ®ç›®æ ‡åœ°å€ç¼–码识别需要对接的设备类型。
        /// </remarks>
        private enum TargetDeviceType
        {
            /// <summary>
            /// æ— æœ‰æ•ˆè®¾å¤‡ï¼ˆåœ°å€ä¸åœ¨å·²çŸ¥èŒƒå›´å†…)
            /// </summary>
            None,
            /// <summary>
            /// æ‹˜æŸæœº
            /// </summary>
            /// <remarks>
            /// è´Ÿè´£å›ºå®š/约束电池托盘的设备,有上下两层。
            /// </remarks>
            ConstraintMachine,
            /// <summary>
            /// æ’拔钉机
            /// </summary>
            /// <remarks>
            /// è´Ÿè´£æ’针和拔针操作的设备,有上下两层。
            /// </remarks>
            PinMachine
        }
        /// <summary>
        /// æ‹˜æŸæœºå¯¹åº”的点位编码集合
        /// </summary>
        /// <remarks>
        /// å½“目标地址在这些编码中时,表示需要与拘束机交互。
        /// ä½¿ç”¨ HashSet ä¿è¯ O(1) çš„ Contains æŸ¥æ‰¾æ€§èƒ½ã€‚
        /// </remarks>
        private static readonly HashSet<string> ConstraintMachineCodes = new HashSet<string> { "10180", "20090" };
        /// <summary>
        /// æ’拔钉机对应的点位编码集合
        /// </summary>
        /// <remarks>
        /// å½“目标地址在这些编码中时,表示需要与插拔钉机交互。
        /// ä½¿ç”¨ HashSet ä¿è¯ O(1) çš„ Contains æŸ¥æ‰¾æ€§èƒ½ã€‚
        /// </remarks>
        private static readonly HashSet<string> PinMachineCodes = new HashSet<string> { "10190", "20100" };
        /// <summary>
        /// ç›®æ ‡åœ°å€åˆ°è®¾å¤‡ç±»åž‹çš„æ˜ å°„
        /// </summary>
        /// <remarks>
        /// é€šè¿‡å•一字典实现 O(1) æŸ¥æ‰¾ï¼Œæ›¿ä»£åŽŸå…ˆåˆ†åˆ«ç”¨ä¸¤ä¸ª List + Contains + if/else if çš„写法。
        /// Key: ç›®æ ‡åœ°å€ç¼–码,Value: å¯¹åº”的设备类型。
        /// </remarks>
        private static readonly Dictionary<string, TargetDeviceType> AddressToDeviceType = new Dictionary<string, TargetDeviceType>
        {
            // æ‹˜æŸæœºçš„两个点位编码都映射到 ConstraintMachine ç±»åž‹
            { "10180", TargetDeviceType.ConstraintMachine },
            { "20090", TargetDeviceType.ConstraintMachine },
            // æ’拔钉机的两个点位编码都映射到 PinMachine ç±»åž‹
            { "10190", TargetDeviceType.PinMachine },
            { "20100", TargetDeviceType.PinMachine }
        };
        /// <summary>
        /// æ—¥å¿—记录器
        /// </summary>
@@ -134,8 +41,6 @@
        {
            // è®°å½•入库场景的调试日志,包含子设备和目标地址信息
            WriteDebug(conveyorLine, "入库下一地址", childDeviceCode, nextAddress);
            // å§”托通用处理方法,入库对应上层(isUpper: true)
            //HandleDeviceRequest(conveyorLine, nextAddress, childDeviceCode, Layer.Upper);
            var cvState = conveyorLine.GetValue<ConveyorLineDBNameNew, byte>(ConveyorLineDBNameNew.CV_State, nextAddress);
            bool isAvailable = cvState == 2;
@@ -160,8 +65,6 @@
        {
            // è®°å½•出库场景的调试日志,包含子设备和目标地址信息
            WriteDebug(conveyorLine, "出库下一地址", childDeviceCode, nextAddress);
            // å§”托通用处理方法,出库对应下层(isUpper: false)
            //HandleDeviceRequest(conveyorLine, nextAddress, childDeviceCode, Layer.Lower);
            var cvState = conveyorLine.GetValue<ConveyorLineDBNameNew, byte>(ConveyorLineDBNameNew.CV_State, nextAddress);
            bool isAvailable = cvState == 2;
@@ -171,289 +74,6 @@
            }
            return false;
        }
        /// <summary>
        /// æ ¹æ®ç›®æ ‡åœ°å€ç±»åž‹åˆ†å‘到对应设备处理
        /// </summary>
        /// <remarks>
        /// é€šè¿‡ AddressToDeviceType å­—典将目标地址映射到设备类型,
        /// ç„¶åŽåˆ†å‘到对应的专用处理方法(HandleConstraintMachine / HandlePinMachine)。
        /// å¦‚果目标地址不在已知映射表中,直接返回,不做任何处理。
        /// </remarks>
        /// <param name="conveyorLine">输送线设备对象,传递到具体设备处理方法</param>
        /// <param name="nextAddress">目标设备编码,通过字典查找识别设备类型</param>
        /// <param name="childDeviceCode">子设备编码,传递到具体设备处理方法</param>
        /// <param name="layer">设备层级(上层或下层),决定读取哪组请求标志</param>
        private void HandleDeviceRequest(CommonConveyorLine conveyorLine, string nextAddress, string childDeviceCode, Layer layer)
        {
            // é€šè¿‡å­—典查找目标地址对应的设备类型,如果找不到则 deviceType ä¸º None
            if (!AddressToDeviceType.TryGetValue(nextAddress, out var deviceType) || deviceType == TargetDeviceType.None)
            {
                // ç›®æ ‡åœ°å€ä¸åœ¨å·²çŸ¥æ˜ å°„表中,直接返回(可能是其他类型设备)
                return;
            }
            // æ ¹æ®è¯†åˆ«å‡ºçš„设备类型分发到对应的处理方法
            switch (deviceType)
            {
                case TargetDeviceType.ConstraintMachine:
                    // æ‹˜æŸæœºå¤„理分支:获取拘束机实例并处理其上下层请求
                    HandleConstraintMachine(conveyorLine, childDeviceCode, layer);
                    break; // å¤„理完毕,跳出 switch
                case TargetDeviceType.PinMachine:
                    // æ’拔钉机处理分支:获取插拔钉机实例并处理其上下层请求
                    HandlePinMachine(conveyorLine, childDeviceCode, layer);
                    break; // å¤„理完毕,跳出 switch
            }
        }
        /// <summary>
        /// å¤„理拘束机的物料/出料请求
        /// </summary>
        /// <remarks>
        /// æŸ¥æ‰¾æ‹˜æŸæœºè®¾å¤‡ï¼ŒèŽ·å–å½“å‰å±‚çº§çš„ç‰©æ–™è¯·æ±‚å’Œå‡ºæ–™è¯·æ±‚çŠ¶æ€ï¼Œ
        /// ç„¶åŽè°ƒç”¨é€šç”¨å¤„理逻辑 ProcessDeviceRequest。
        /// </remarks>
        /// <param name="conveyorLine">输送线设备对象,用于通知目标地址和 ACK</param>
        /// <param name="childDeviceCode">子设备编码,用于精确定位</param>
        /// <param name="layer">设备层级,决定读取上层还是下层的请求标志</param>
        private void HandleConstraintMachine(CommonConveyorLine conveyorLine, string childDeviceCode, Layer layer)
        {
            // ä»Žå…¨å±€è®¾å¤‡åˆ—表中查找名为"拘束机"的拘束机设备实例
            var constraint = FindDevice<ConstraintMachine>("拘束机");
            if (constraint == null)
            {
                // æœªæ‰¾åˆ°æ‹˜æŸæœºè®¾å¤‡ï¼Œå·²åœ¨ FindDevice ä¸­è®°å½•日志,此处直接返回
                return;
            }
            // èŽ·å–å½“å‰å±‚çº§ï¼ˆä¸Šå±‚/下层)的物料请求标志,非零表示设备需要物料
            bool materialRequest = GetConstraintFlag(constraint, layer, isMaterial: true);
            // èŽ·å–å½“å‰å±‚çº§ï¼ˆä¸Šå±‚/下层)的出料请求标志,非零表示设备有货要出
            bool outputRequest = GetConstraintFlag(constraint, layer, isMaterial: false);
            // æž„造设置输出就绪标志的委托(根据层级写入 Upper æˆ– Lower å¯¹åº”的寄存器)
            Action<bool> setOutputReady = outputReady =>
                SetConstraintOutputReady(constraint, layer, outputReady);
            // è°ƒç”¨é€šç”¨è¯·æ±‚处理逻辑,传入设备类型描述用于日志记录
            ProcessDeviceRequest(conveyorLine, childDeviceCode, materialRequest, outputRequest, setOutputReady, "拘束机");
        }
        /// <summary>
        /// å¤„理插拔钉机的物料/出料请求
        /// </summary>
        /// <remarks>
        /// æŸ¥æ‰¾æ’拔钉机设备,获取当前层级的物料请求和出料请求状态,
        /// ç„¶åŽè°ƒç”¨é€šç”¨å¤„理逻辑 ProcessDeviceRequest。
        /// </remarks>
        /// <param name="conveyorLine">输送线设备对象,用于通知目标地址和 ACK</param>
        /// <param name="childDeviceCode">子设备编码,用于精确定位</param>
        /// <param name="layer">设备层级,决定读取上层还是下层的请求标志</param>
        private void HandlePinMachine(CommonConveyorLine conveyorLine, string childDeviceCode, Layer layer)
        {
            // ä»Žå…¨å±€è®¾å¤‡åˆ—表中查找名为"插拔钉机"的插拔钉机设备实例
            var pinMachine = FindDevice<PinMachine>("插拔钉机");
            if (pinMachine == null)
            {
                // æœªæ‰¾åˆ°æ’拔钉机设备,已在 FindDevice ä¸­è®°å½•日志,此处直接返回
                return;
            }
            // èŽ·å–å½“å‰å±‚çº§ï¼ˆä¸Šå±‚/下层)的物料请求标志,非零表示设备需要物料
            bool materialRequest = GetPinMachineFlag(pinMachine, layer, isMaterial: true);
            // èŽ·å–å½“å‰å±‚çº§ï¼ˆä¸Šå±‚/下层)的出料请求标志,非零表示设备有货要出
            bool outputRequest = GetPinMachineFlag(pinMachine, layer, isMaterial: false);
            // æž„造设置输出就绪标志的委托(根据层级写入 Upper æˆ– Lower å¯¹åº”的寄存器)
            Action<bool> setOutputReady = outputReady =>
                SetPinMachineOutputReady(pinMachine, layer, outputReady);
            // è°ƒç”¨é€šç”¨è¯·æ±‚处理逻辑,传入设备类型描述用于日志记录
            ProcessDeviceRequest(conveyorLine, childDeviceCode, materialRequest, outputRequest, setOutputReady, "插拔钉机");
        }
        /// <summary>
        /// æŸ¥æ‰¾æŒ‡å®šåç§°çš„设备
        /// </summary>
        /// <remarks>
        /// ä»Žå…¨å±€è®¾å¤‡åˆ—表 Storage.Devices ä¸­é€šè¿‡è®¾å¤‡ç±»åž‹å’Œåç§°æŸ¥æ‰¾è®¾å¤‡å®žä¾‹ã€‚
        /// è¿™æ˜¯ä¸€ä¸ªæ³›åž‹æ–¹æ³•,可以适用于 ConstraintMachine、PinMachine ç­‰å¤šç§è®¾å¤‡ç±»åž‹ã€‚
        /// </remarks>
        /// <typeparam name="T">设备类型,必须是引用类型(如 ConstraintMachine、PinMachine)</typeparam>
        /// <param name="deviceName">设备名称,用于精确匹配设备的 DeviceName å±žæ€§</param>
        /// <returns>找到的设备实例,未找到则返回 null</returns>
        private T? FindDevice<T>(string deviceName) where T : class
        {
            // OfType<T>() ç­›é€‰å‡ºæŒ‡å®šç±»åž‹çš„设备,FirstOrDefault æŒ‰åç§°ç²¾ç¡®åŒ¹é…
            var device = Storage.Devices.OfType<T>().FirstOrDefault(d => GetDeviceName(d) == deviceName);
            if (device == null)
            {
                // è®¾å¤‡æœªæ‰¾åˆ°æ—¶è®°å½•调试日志,方便排查配置问题
                _logger.Debug("FindDevice:未找到 {DeviceName}", deviceName);
            }
            return device; // å¯èƒ½ä¸º null,由调用方负责 null æ£€æŸ¥
        }
        /// <summary>
        /// é€šè¿‡å¤šæ€èŽ·å–ä»»æ„è®¾å¤‡çš„åç§°
        /// </summary>
        /// <remarks>
        /// ä½¿ç”¨ switch è¡¨è¾¾å¼æ ¹æ®è®¾å¤‡çš„具体类型获取其 DeviceName å±žæ€§ï¼Œ
        /// é¿å…ä¸ºæ¯ç§è®¾å¤‡ç±»åž‹ç¼–写独立的反射或属性访问代码。
        /// å½“前支持 ConstraintMachine å’Œ PinMachine ä¸¤ç§ç±»åž‹ã€‚
        /// </remarks>
        /// <typeparam name="T">设备类型</typeparam>
        /// <param name="device">设备实例,非空</param>
        /// <returns>设备的名称字符串,如果类型不匹配则返回空字符串</returns>
        private static string GetDeviceName<T>(T device) where T : class
        {
            // æ¨¡å¼åŒ¹é…ï¼šæ ¹æ®è®¾å¤‡çš„具体运行时类型返回对应的 DeviceName
            return device switch
            {
                ConstraintMachine cm => cm.DeviceName, // æ‹˜æŸæœºè¿”回其设备名称
                PinMachine pm => pm.DeviceName,       // æ’拔钉机返回其设备名称
                _ => string.Empty                     // æœªçŸ¥ç±»åž‹è¿”回空字符串(理论上不会走到这里)
            };
        }
        /// <summary>
        /// èŽ·å–æ‹˜æŸæœºçš„è¯·æ±‚æ ‡å¿—ï¼ˆç‰©æ–™è¯·æ±‚æˆ–å‡ºæ–™è¯·æ±‚ï¼‰
        /// </summary>
        /// <remarks>
        /// æ ¹æ® isMaterial å‚数决定读取物料请求还是出料请求寄存器,
        /// å†æ ¹æ® layer å‚数决定读取上层(Upper)还是下层(Lower)寄存器。
        /// è¿”回值表示请求是否有效(非零为有效)。
        /// </remarks>
        /// <param name="constraint">拘束机设备实例,用于读取 PLC å¯„存器值</param>
        /// <param name="layer">设备层级,决定读取 Upper è¿˜æ˜¯ Lower å¯„存器</param>
        /// <param name="isMaterial">true=读取物料请求标志,false=读取出料请求标志</param>
        /// <returns>请求标志是否有效(true=有请求,false=无请求)</returns>
        private bool GetConstraintFlag(ConstraintMachine constraint, Layer layer, bool isMaterial)
        {
            // æ ¹æ® isMaterial é€‰æ‹©å¯¹åº”的寄存器名称对(物料请求或出料请求)
            var (materialKey, outputKey) = isMaterial
                ? (ConstraintMachineDBName.MaterialRequestUpper, ConstraintMachineDBName.MaterialRequestLower)   // ç‰©æ–™è¯·æ±‚
                : (ConstraintMachineDBName.OutputRequestUpper, ConstraintMachineDBName.OutputRequestLower);        // å‡ºæ–™è¯·æ±‚
            // æ ¹æ® layer é€‰æ‹©å…·ä½“使用 Upper è¿˜æ˜¯ Lower ç‰ˆæœ¬çš„寄存器
            var key = layer == Layer.Upper ? materialKey : outputKey;
            // è¯»å–寄存器值,非零表示有请求,返回布尔值
            return constraint.GetValue<ConstraintMachineDBName, short>(key) != 0;
        }
        /// <summary>
        /// èŽ·å–æ’æ‹”é’‰æœºçš„è¯·æ±‚æ ‡å¿—ï¼ˆç‰©æ–™è¯·æ±‚æˆ–å‡ºæ–™è¯·æ±‚ï¼‰
        /// </summary>
        /// <remarks>
        /// ä¸Ž GetConstraintFlag é€»è¾‘相同,但操作对象是插拔钉机(PinMachine)。
        /// æ ¹æ® isMaterial å‚数决定读取物料请求还是出料请求寄存器,
        /// å†æ ¹æ® layer å‚数决定读取上层(Upper)还是下层(Lower)寄存器。
        /// </remarks>
        /// <param name="pinMachine">插拔钉机设备实例,用于读取 PLC å¯„存器值</param>
        /// <param name="layer">设备层级,决定读取 Upper è¿˜æ˜¯ Lower å¯„存器</param>
        /// <param name="isMaterial">true=读取物料请求标志,false=读取出料请求标志</param>
        /// <returns>请求标志是否有效(true=有请求,false=无请求)</returns>
        private bool GetPinMachineFlag(PinMachine pinMachine, Layer layer, bool isMaterial)
        {
            // æ ¹æ® isMaterial é€‰æ‹©å¯¹åº”的寄存器名称对(物料请求或出料请求)
            var (materialKey, outputKey) = isMaterial
                ? (PinMachineDBName.MaterialRequestUpper, PinMachineDBName.MaterialRequestLower)   // ç‰©æ–™è¯·æ±‚
                : (PinMachineDBName.OutputRequestUpper, PinMachineDBName.OutputRequestLower);       // å‡ºæ–™è¯·æ±‚
            // æ ¹æ® layer é€‰æ‹©å…·ä½“使用 Upper è¿˜æ˜¯ Lower ç‰ˆæœ¬çš„寄存器
            var key = layer == Layer.Upper ? materialKey : outputKey;
            // è¯»å–寄存器值,非零表示有请求,返回布尔值
            return pinMachine.GetValue<PinMachineDBName, short>(key) != 0;
        }
        /// <summary>
        /// è®¾ç½®æ‹˜æŸæœºçš„输出就绪标志
        /// </summary>
        /// <remarks>
        /// å‘拘束机的 PLC å¯„存器写入输出就绪状态,告知拘束机可以继续出料。
        /// æ ¹æ® layer å‚数决定写入上层(ConstraintTrayOutputReadyUpper)还是下层(ConstraintTrayOutputReadyLower)寄存器。
        /// </remarks>
        /// <param name="constraint">拘束机设备实例,用于写入 PLC å¯„存器</param>
        /// <param name="layer">设备层级,决定写入 Upper è¿˜æ˜¯ Lower å¯„存器</param>
        /// <param name="outputReady">输出就绪状态,true=可以出料,false=不能出料</param>
        private void SetConstraintOutputReady(ConstraintMachine constraint, Layer layer, bool outputReady)
        {
            // æ ¹æ® layer é€‰æ‹©å¯¹åº”的输出就绪寄存器(Upper æˆ– Lower)
            var key = layer == Layer.Upper
                ? ConstraintMachineDBName.ConstraintTrayOutputReadyUpper   // ä¸Šå±‚输出就绪寄存器
                : ConstraintMachineDBName.ConstraintTrayOutputReadyLower;  // ä¸‹å±‚输出就绪寄存器
            // å‘ PLC å†™å…¥å€¼ï¼ŒoutputReady ä¸º true æ—¶å†™å…¥ 1,否则写入 0
            constraint.SetValue(key, outputReady ? true : false);
        }
        /// <summary>
        /// è®¾ç½®æ’拔钉机的输出就绪标志
        /// </summary>
        /// <remarks>
        /// å‘插拔钉机的 PLC å¯„存器写入输出就绪状态,告知插拔钉机可以继续出料。
        /// æ ¹æ® layer å‚数决定写入上层(PlugPinTrayOutputReadyUpper)还是下层(PlugPinTrayOutputReadyLower)寄存器。
        /// </remarks>
        /// <param name="pinMachine">插拔钉机设备实例,用于写入 PLC å¯„存器</param>
        /// <param name="layer">设备层级,决定写入 Upper è¿˜æ˜¯ Lower å¯„存器</param>
        /// <param name="outputReady">输出就绪状态,true=可以出料,false=不能出料</param>
        private void SetPinMachineOutputReady(PinMachine pinMachine, Layer layer, bool outputReady)
        {
            // æ ¹æ® layer é€‰æ‹©å¯¹åº”的输出就绪寄存器(Upper æˆ– Lower)
            var key = layer == Layer.Upper
                ? PinMachineDBName.PlugPinTrayOutputReadyUpper   // ä¸Šå±‚输出就绪寄存器
                : PinMachineDBName.PlugPinTrayOutputReadyLower; // ä¸‹å±‚输出就绪寄存器
            // å‘ PLC å†™å…¥å€¼ï¼ŒoutputReady ä¸º true æ—¶å†™å…¥ 1,否则写入 0
            pinMachine.SetValue(key, outputReady ? true : false);
        }
        /// <summary>
        /// å¤„理设备请求的核心逻辑
        /// </summary>
        /// <remarks>
        /// æ ¹æ®ç‰©æ–™è¯·æ±‚和出料请求的状态决定行为:
        /// - å¦‚果设备需要物料(materialRequest=true),设置输送线的目标地址为 1(有料进来)并回复 ACK ç¡®è®¤ä¿¡å·
        /// - å¦‚果设备不需要物料(materialRequest=false),则通知设备可以继续出料(setOutputReady)
        ///
        /// è¿™æ˜¯æ‹˜æŸæœºå’Œæ’拔钉机共用的处理逻辑,设备特有的部分已在此方法外封装。
        /// </remarks>
        /// <param name="conveyorLine">输送线设备对象,用于写入目标地址(Target)和 ACK ä¿¡å·</param>
        /// <param name="childDeviceCode">子设备编码,用于精确定位写入哪个子设备</param>
        /// <param name="materialRequest">物料请求标志,true=设备当前需要补充物料</param>
        /// <param name="outputRequest">出料请求标志,true=设备当前有物料需要输出(配合 materialRequest=false æ—¶ä½¿ç”¨ï¼‰</param>
        /// <param name="setOutputReady">设置设备输出就绪标志的委托,根据层级写入 Upper æˆ– Lower å¯„存器</param>
        /// <param name="deviceType">设备类型描述字符串,用于日志输出</param>
        private void ProcessDeviceRequest(
            CommonConveyorLine conveyorLine,
            string childDeviceCode,
            bool materialRequest,
            bool outputRequest,
            Action<bool> setOutputReady,
            string deviceType)
        {
            // è®°å½•当前请求状态的调试日志,供排查问题使用
            QuartzLogHelper.LogDebug(_logger, "ProcessDeviceRequest:{DeviceType},子设备: {ChildDeviceCode},物料请求: {MaterialReq},出料请求: {OutputReq}", $"ProcessDeviceRequest:{deviceType},子设备: {childDeviceCode},物料请求: {materialRequest},出料请求: {outputRequest}", conveyorLine.DeviceCode, deviceType, childDeviceCode, materialRequest, outputRequest);
            // åˆ†æ”¯åˆ¤æ–­ï¼šè®¾å¤‡æ˜¯éœ€è¦ç‰©æ–™è¿˜æ˜¯éœ€è¦å‡ºæ–™
            if (materialRequest)
            {
                // è®¾å¤‡éœ€è¦ç‰©æ–™ -> é€šçŸ¥è¾“送线有料过来
                // 1. è®¾ç½®ç›®æ ‡åœ°å€ä¸º 1,表示"有料进入"
                conveyorLine.SetValue(ConveyorLineDBNameNew.Target, 1, childDeviceCode);
                // 2. å›žå¤ ACK ç¡®è®¤ä¿¡å·ï¼Œå‘ŠçŸ¥è®¾å¤‡å·²æ”¶åˆ°è¯·æ±‚
                conveyorLine.SetValue(ConveyorLineDBNameNew.WCS_ACK, 1, childDeviceCode);
                // 3. è®°å½•信息日志,表明已完成目标地址设置和 ACK å›žå¤
                QuartzLogHelper.LogInfo(_logger, "ProcessDeviceRequest:{DeviceType} éœ€è¦ç‰©æ–™ï¼Œå·²è®¾ç½®ç›®æ ‡åœ°å€å’ŒACK", $"ProcessDeviceRequest:{deviceType} éœ€è¦ç‰©æ–™ï¼Œå·²è®¾ç½®ç›®æ ‡åœ°å€å’ŒACK", conveyorLine.DeviceCode, deviceType);
            }
            else
            {
                // è®¾å¤‡ä¸éœ€è¦ç‰©æ–™ -> é€šçŸ¥è®¾å¤‡å¯ä»¥ç»§ç»­å‡ºæ–™ï¼ˆæ— è®ºå½“前是否有货要出,都要通知)
                // outputRequest è¡¨ç¤ºè®¾å¤‡å½“前是否确实有货,如果没有货则 outputReady=false,设备收到后等待
                setOutputReady(outputRequest);
            }
        }
        /// <summary>
        /// å†™å…¥è°ƒè¯•日志(同时输出到两个日志系统)
        /// </summary>
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/ManualInbound/ManualInboundTaskHandler.cs
@@ -56,21 +56,13 @@
                var isTaskNum = conveyorLine.SetValue(ConveyorLineDBNameNew.TaskNo, (short)task.TaskNum, childDeviceCode);
                if (!isTaskNum) return;
                QuartzLogHelper.LogInfo(_logger, $"任务号写入PLC成功,任务号【{task.TaskNum}】", conveyorLine.DeviceCode);
                Thread.Sleep(500);
                //// å†™å…¥èµ·å§‹åœ°å€
                //conveyorLine.SetValue(ConveyorLineDBNameNew.Source, short.Parse(task.SourceAddress ?? "0"), childDeviceCode);
                //QuartzLogHelper.LogInfo(_logger, $"任务号写入PLC成功,任务号【{task.TaskNum}】", conveyorLine.DeviceCode);
                //Thread.Sleep(500);
                Thread.Sleep(100);
                // å†™å…¥ç›®æ ‡åœ°å€
                var isTarget = conveyorLine.SetValue(ConveyorLineDBNameNew.Target, short.Parse(task.NextAddress ?? "0"), childDeviceCode);
                if (!isTarget) return;
                QuartzLogHelper.LogInfo(_logger, $"目标地址写入PLC成功,目标地址【{task.NextAddress}】", conveyorLine.DeviceCode);
                Thread.Sleep(500);
                // å†™å…¥æ‰˜ç›˜å·
                //conveyorLine.SetValue(ConveyorLineDBNameNew.Barcode, task.PalletCode, childDeviceCode);
                Thread.Sleep(100);
                // æ›´æ–°ä»»åŠ¡çŠ¶æ€åˆ°ä¸‹ä¸€é˜¶æ®µ
                var updateResult = _taskService.UpdateTaskStatusToNext(task);
@@ -83,7 +75,7 @@
                // å†™å…¥ACK标志
                conveyorLine.SetValue(ConveyorLineDBNameNew.WCS_ACK, (short)1, childDeviceCode);
                QuartzLogHelper.LogInfo(_logger, $"ManualInboundTaskHandler: æ‰‹åŠ¨ä»»åŠ¡å†™å…¥PLC成功,任务号【{task.TaskNum}】,源地址【{task.SourceAddress}】,目标地址【{task.NextAddress}】", conveyorLine.DeviceCode);
                QuartzLogHelper.LogInfo(_logger, $"ManualInboundTaskHandler: ä»»åС写入PLC成功,任务号【{task.TaskNum}】,源地址【{task.SourceAddress}】,目标地址【{task.NextAddress}】", conveyorLine.DeviceCode);
            }
            catch (Exception ex)
            {
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/PinMachine/PinMachineCommand.cs
ÎļþÒÑɾ³ý
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/PinMachine/PinMachineDBName.cs
ÎļþÒÑɾ³ý
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Abstractions/ISocketClientGateway.cs
@@ -50,6 +50,6 @@
        /// <param name="clientId">客户端标识(通常是 IP åœ°å€ï¼‰</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <param name="robotCrane">机器人状态对象</param>
        Task HandleClientAsync(TcpClient client, string clientId, CancellationToken cancellationToken, RobotSocketState robotCrane);
        Task HandleClientAsync(TcpClient client, string clientId, CancellationToken cancellationToken);
    }
}
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotClientManager.cs
@@ -146,7 +146,7 @@
                    // å¼‚步启动客户端消息处理循环
                    // ä½¿ç”¨ TaskContinuationOptions.OnlyOnFaulted æ•获异常情况
                    _ = _tcpSocket.HandleClientAsync(tcpClient, robotCrane.IPAddress, _tcpSocket._cts.Token, latestStateForSubscribe)
                    _ = _tcpSocket.HandleClientAsync(tcpClient, robotCrane.IPAddress, _tcpSocket._cts.Token)
                        .ContinueWith(t =>
                        {
                            // å¦‚果处理出现异常
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotTaskProcessor.cs
@@ -590,39 +590,6 @@
                return false;
            }
            // è§£æžè¿”回的任务信息
            //var taskInfos = JsonConvert.DeserializeObject<List<Dt_Task>>(content.Data.ToJson() ?? string.Empty) ?? new List<Dt_Task>();
            //var taskInfo = taskInfos.FirstOrDefault();
            //// èŽ·å–æºåœ°å€
            //string sourceAddress = taskDTO.SourceAddress;
            //// æŸ¥æ‰¾æºåœ°å€å¯¹åº”的输送线设备
            //IDevice? device = Storage.Devices.FirstOrDefault(x => x.DeviceProDTOs.Any(d => d.DeviceChildCode == sourceAddress));
            //if (device != null)
            //{
            //    // å°†è®¾å¤‡è½¬æ¢ä¸ºè¾“送线类型
            //    CommonConveyorLine conveyorLine = (CommonConveyorLine)device;
            //    // è®¾ç½®è¾“送线的目标地址
            //    conveyorLine.SetValue(ConveyorLineDBNameNew.Target, taskInfo.NextAddress, sourceAddress);
            //    // è®¾ç½®è¾“送线的任务号
            //    conveyorLine.SetValue(ConveyorLineDBNameNew.TaskNo, taskInfo.TaskNum, sourceAddress);
            //    // è§¦å‘输送线开始执行(写入 WCS_ACK = 1)
            //    conveyorLine.SetValue(ConveyorLineDBNameNew.WCS_ACK, (short)1, sourceAddress);
            //    // æ›´æ–°ä»»åŠ¡çŠ¶æ€åˆ°ä¸‹ä¸€é˜¶æ®µ
            //    if (_taskService.UpdateTaskStatusToNext(taskInfo).Status)
            //    {
            //        _logger.LogInformation("HandleInboundTaskAsync:入库任务处理成功,任务号: {TaskNum}", taskInfo.TaskNum);
            //        QuartzLogger.Info($"HandleInboundTaskAsync:入库任务处理成功,任务号: {taskInfo.TaskNum}", state.RobotCrane?.DeviceName ?? "Unknown");
            //        return true;
            //    }
            //}
            return true;
        }
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/SocketServer/SocketClientGateway.cs
@@ -66,9 +66,9 @@
        /// <param name="cancellationToken">取消令牌</param>
        /// <param name="robotCrane">机器人状态</param>
        /// <returns>任务</returns>
        public Task HandleClientAsync(TcpClient client, string clientId, CancellationToken cancellationToken, RobotSocketState robotCrane)
        public Task HandleClientAsync(TcpClient client, string clientId, CancellationToken cancellationToken)
        {
            return _tcpSocket.HandleClientAsync(client, clientId, cancellationToken, robotCrane);
            return _tcpSocket.HandleClientAsync(client, clientId, cancellationToken);
        }
    }
}
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/SocketServer/TcpSocketServer.Messaging.cs
@@ -23,8 +23,7 @@
        /// <param name="client">TCP å®¢æˆ·ç«¯è¿žæŽ¥</param>
        /// <param name="clientId">客户端唯一标识</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <param name="robotCrane">机器人状态</param>
        public async Task HandleClientAsync(TcpClient client, string clientId, CancellationToken cancellationToken, RobotSocketState robotCrane)
        public async Task HandleClientAsync(TcpClient client, string clientId, CancellationToken cancellationToken)
        {
            using (client)
            using (NetworkStream networkStream = client.GetStream())
@@ -60,11 +59,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/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/StackerCraneJob/StackerCraneTaskSelector.cs
@@ -203,11 +203,14 @@
        {
            // å…ˆè¿›è¡Œæœ¬åœ°ç«™å°æ£€æŸ¥ï¼ˆPLC è¯»å–,快速),避免不必要的 WMS HTTP è°ƒç”¨
            if (outboundTask.TaskType != (int)TaskOutboundTypeEnum.OutEmpty)
            {
            // åˆ¤æ–­ TargetAddress è¾“送线站台是否空闲
            if (!IsTargetAddressConveyorStationAvailable(outboundTask))
            {
                return null;
            }
            }
            // åˆ¤æ–­ NextAddress å‡ºåº“站台是否可用
            if (!IsOutTaskStationAvailable(outboundTask))
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_TaskInfoService/TaskService_GradingMachine.cs
@@ -144,7 +144,7 @@
                    PalletType = stock.PalletType,
                    SourceAddress = stock.LocationCode,
                    CurrentAddress = stock.LocationCode,
                    NextAddress = TaskAddressConstants.DEFAULT_ADDRESS,
                    NextAddress = TaskAddressConstants.GRADING_OUTBOUND_ADDRESS,
                    TargetAddress = TaskAddressConstants.GRADING_OUTBOUND_ADDRESS,
                    Roadway = stock.LocationDetails.RoadwayNo,
                    TaskType = TaskOutboundTypeEnum.Outbound.GetHashCode(),
@@ -158,8 +158,8 @@
                {
                    var result = await BaseDal.AddDataAsync(taskList) > 0;
                    var wmstaskDto = result ? _mapper.Map<WMSTaskDTO>(taskList) : null;
                    var httpResponse = _httpClientHelper.Post<WebResponseContent>("http://logistics-service/api/logistics/notifyoutbound", JsonSerializer.Serialize(wmstaskDto)).Data;
                    var wmsTaskDtos = new List<WMSTaskDTO> { wmstaskDto };
                    var httpResponse = _httpClientHelper.Post<WebResponseContent>("http://localhost:9292/api/Task/ReceiveTask", JsonSerializer.Serialize(wmsTaskDtos)).Data;
                    if (result && httpResponse != null)
                    {
                        return content.OK("出库请求成功");
Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/WCS/TaskService_AutoOutbound.cs
@@ -33,7 +33,8 @@
                // è¿‡æ»¤æœ‰ä½ç½®ä¸”位置有库存的记录
                expiredStocks = expiredStocks
                    .Where(s => s.LocationDetails != null
                        && s.LocationDetails.LocationStatus == LocationStatusEnum.InStock.GetHashCode())
                        && s.LocationDetails.LocationStatus == LocationStatusEnum.InStock.GetHashCode()
                        && s.LocationDetails.EnableStatus != EnableStatusEnum.Disable.GetHashCode())
                    .ToList();
                if (!expiredStocks.Any())
Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/WCS/TaskService_Tray.cs
@@ -51,14 +51,14 @@
                var stockInfo = await _stockInfoService.GetStockInfoAsync(taskDto.PalletCode);
                if (stockInfo == null) return WebResponseContent.Instance.Error("未找到对应库存信息");
                return await _unitOfWorkManage.BeginTranAsync(async () =>
                {
                    stockInfo.LocationCode = location.LocationCode;
                    stockInfo.LocationId = location.Id;
                    stockInfo.StockStatus = StockStatusEmun.空托盘库存.GetHashCode();
                    location.LocationStatus = LocationStatusEnum.InStock.GetHashCode();
                return await _unitOfWorkManage.BeginTranAsync(async () =>
                {
                    var updateLocationResult = await _locationInfoService.UpdateLocationInfoAsync(location);
                    var updateStockResult = await _stockInfoService.UpdateStockAsync(stockInfo);
                    if (!updateLocationResult || !updateStockResult)
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);
        }
    }
}
Code/²âÊÔ¹¤¾ß/WIDESEAWCS_S7Simulator/WIDESEAWCS_S7Simulator.Server/Data/instance-1001/config.json
@@ -2,7 +2,7 @@
  "id": "1001",
  "name": "A\u533A_\u4E00\u6CE8\u8F93\u9001\u7EBF",
  "plcType": "S71500",
  "port": 103,
  "port": 102,
  "activationKey": "",
  "autoStart": false,
  "protocolTemplateId": "protocol-1001",
Code/²âÊÔ¹¤¾ß/WIDESEAWCS_S7Simulator/WIDESEAWCS_S7Simulator.Server/Data/instance-1002/config.json
@@ -2,7 +2,7 @@
  "id": "1002",
  "name": "A\u533A_\u6362\u76D8\u8F93\u9001\u7EBF",
  "plcType": "S71500",
  "port": 104,
  "port": 102,
  "activationKey": "",
  "autoStart": false,
  "protocolTemplateId": "protocol-1002",
Code/²âÊÔ¹¤¾ß/WIDESEAWCS_S7Simulator/WIDESEAWCS_S7Simulator.Server/Data/protocol-templates.json
@@ -2225,5 +2225,1794 @@
        "direction": 2
      }
    ]
  },
  {
    "id": "protocol-1004",
    "name": "B\u533A_\u5E38\u6E29\u5316\u6210\u8F93\u9001\u7EBF \u534F\u8BAE\u6A21\u677F",
    "version": "1.0",
    "fields": [
      {
        "fieldKey": "2125_TaskNo",
        "dbNumber": 50,
        "offset": 960,
        "bit": 1,
        "dataType": 1,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2125_Source",
        "dbNumber": 50,
        "offset": 962,
        "bit": 1,
        "dataType": 1,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2125_Target",
        "dbNumber": 50,
        "offset": 964,
        "bit": 1,
        "dataType": 1,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2125_BoxType",
        "dbNumber": 50,
        "offset": 966,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2125_CV_State",
        "dbNumber": 50,
        "offset": 967,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2125_CV_ERRCode",
        "dbNumber": 50,
        "offset": 968,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2125_WCS_STB",
        "dbNumber": 50,
        "offset": 969,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2125_WCS_ACK",
        "dbNumber": 50,
        "offset": 970,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2125_PLC_STB",
        "dbNumber": 50,
        "offset": 971,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2125_PLC_ACK",
        "dbNumber": 50,
        "offset": 972,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2125_PLC_REQ",
        "dbNumber": 50,
        "offset": 973,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2125_WCS_ERRCode",
        "dbNumber": 50,
        "offset": 974,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2125_WCS_Special",
        "dbNumber": 50,
        "offset": 975,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2125_Equ_Auto",
        "dbNumber": 50,
        "offset": 976,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2125_Last_pallet",
        "dbNumber": 50,
        "offset": 977,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2125_Barcode",
        "dbNumber": 50,
        "offset": 978,
        "bit": 1,
        "dataType": 0,
        "length": 20,
        "direction": 2
      },
      {
        "fieldKey": "2125_Spare_1",
        "dbNumber": 50,
        "offset": 998,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2125_Spare_2",
        "dbNumber": 50,
        "offset": 999,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2217_TaskNo",
        "dbNumber": 50,
        "offset": 4640,
        "bit": 1,
        "dataType": 1,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2217_Source",
        "dbNumber": 50,
        "offset": 4642,
        "bit": 1,
        "dataType": 1,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2217_Target",
        "dbNumber": 50,
        "offset": 4644,
        "bit": 1,
        "dataType": 1,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2217_BoxType",
        "dbNumber": 50,
        "offset": 4646,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2217_CV_State",
        "dbNumber": 50,
        "offset": 4647,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2217_CV_ERRCode",
        "dbNumber": 50,
        "offset": 4648,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2217_WCS_STB",
        "dbNumber": 50,
        "offset": 4649,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2217_WCS_ACK",
        "dbNumber": 50,
        "offset": 4650,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2217_PLC_STB",
        "dbNumber": 50,
        "offset": 4651,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2217_PLC_ACK",
        "dbNumber": 50,
        "offset": 4652,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2217_PLC_REQ",
        "dbNumber": 50,
        "offset": 4653,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2217_WCS_ERRCode",
        "dbNumber": 50,
        "offset": 4654,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2217_WCS_Special",
        "dbNumber": 50,
        "offset": 4655,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2217_Equ_Auto",
        "dbNumber": 50,
        "offset": 4656,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2217_Last_pallet",
        "dbNumber": 50,
        "offset": 4657,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2217_Barcode",
        "dbNumber": 50,
        "offset": 4658,
        "bit": 1,
        "dataType": 0,
        "length": 20,
        "direction": 2
      },
      {
        "fieldKey": "2217_Spare_1",
        "dbNumber": 50,
        "offset": 4678,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2217_Spare_2",
        "dbNumber": 50,
        "offset": 4679,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2101_TaskNo",
        "dbNumber": 50,
        "offset": 0,
        "bit": 1,
        "dataType": 1,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2101_Source",
        "dbNumber": 50,
        "offset": 2,
        "bit": 1,
        "dataType": 1,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2101_Target",
        "dbNumber": 50,
        "offset": 4,
        "bit": 1,
        "dataType": 1,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2101_BoxType",
        "dbNumber": 50,
        "offset": 6,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2101_CV_State",
        "dbNumber": 50,
        "offset": 7,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2101_CV_ERRCode",
        "dbNumber": 50,
        "offset": 8,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2101_WCS_STB",
        "dbNumber": 50,
        "offset": 9,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2101_WCS_ACK",
        "dbNumber": 50,
        "offset": 10,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2101_PLC_STB",
        "dbNumber": 50,
        "offset": 11,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2101_PLC_ACK",
        "dbNumber": 50,
        "offset": 12,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2101_PLC_REQ",
        "dbNumber": 50,
        "offset": 13,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2101_WCS_ERRCode",
        "dbNumber": 50,
        "offset": 14,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2101_WCS_Special",
        "dbNumber": 50,
        "offset": 15,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2101_Equ_Auto",
        "dbNumber": 50,
        "offset": 16,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2101_Last_pallet",
        "dbNumber": 50,
        "offset": 17,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2101_Barcode",
        "dbNumber": 50,
        "offset": 18,
        "bit": 1,
        "dataType": 0,
        "length": 20,
        "direction": 2
      },
      {
        "fieldKey": "2101_Spare_1",
        "dbNumber": 50,
        "offset": 38,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2101_Spare_2",
        "dbNumber": 50,
        "offset": 39,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2103_TaskNo",
        "dbNumber": 50,
        "offset": 80,
        "bit": 1,
        "dataType": 1,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2103_Source",
        "dbNumber": 50,
        "offset": 82,
        "bit": 1,
        "dataType": 1,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2103_Target",
        "dbNumber": 50,
        "offset": 84,
        "bit": 1,
        "dataType": 1,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2103_BoxType",
        "dbNumber": 50,
        "offset": 86,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2103_CV_State",
        "dbNumber": 50,
        "offset": 87,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2103_CV_ERRCode",
        "dbNumber": 50,
        "offset": 88,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2103_WCS_STB",
        "dbNumber": 50,
        "offset": 89,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2103_WCS_ACK",
        "dbNumber": 50,
        "offset": 90,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2103_PLC_STB",
        "dbNumber": 50,
        "offset": 91,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2103_PLC_ACK",
        "dbNumber": 50,
        "offset": 92,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2103_PLC_REQ",
        "dbNumber": 50,
        "offset": 93,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2103_WCS_ERRCode",
        "dbNumber": 50,
        "offset": 94,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2103_WCS_Special",
        "dbNumber": 50,
        "offset": 95,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2103_Equ_Auto",
        "dbNumber": 50,
        "offset": 96,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2103_Last_pallet",
        "dbNumber": 50,
        "offset": 97,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2103_Barcode",
        "dbNumber": 50,
        "offset": 98,
        "bit": 1,
        "dataType": 0,
        "length": 20,
        "direction": 2
      },
      {
        "fieldKey": "2103_Spare_1",
        "dbNumber": 50,
        "offset": 118,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2103_Spare_2",
        "dbNumber": 50,
        "offset": 119,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2118_TaskNo",
        "dbNumber": 50,
        "offset": 680,
        "bit": 1,
        "dataType": 1,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2118_Source",
        "dbNumber": 50,
        "offset": 682,
        "bit": 1,
        "dataType": 1,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2118_Target",
        "dbNumber": 50,
        "offset": 684,
        "bit": 1,
        "dataType": 1,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2118_BoxType",
        "dbNumber": 50,
        "offset": 686,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2118_CV_State",
        "dbNumber": 50,
        "offset": 687,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2118_CV_ERRCode",
        "dbNumber": 50,
        "offset": 688,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2118_WCS_STB",
        "dbNumber": 50,
        "offset": 689,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2118_WCS_ACK",
        "dbNumber": 50,
        "offset": 690,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2118_PLC_STB",
        "dbNumber": 50,
        "offset": 691,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2118_PLC_ACK",
        "dbNumber": 50,
        "offset": 692,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2118_PLC_REQ",
        "dbNumber": 50,
        "offset": 693,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2118_WCS_ERRCode",
        "dbNumber": 50,
        "offset": 694,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2118_WCS_Special",
        "dbNumber": 50,
        "offset": 695,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2118_Equ_Auto",
        "dbNumber": 50,
        "offset": 696,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2118_Last_pallet",
        "dbNumber": 50,
        "offset": 697,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2118_Barcode",
        "dbNumber": 50,
        "offset": 698,
        "bit": 1,
        "dataType": 0,
        "length": 20,
        "direction": 2
      },
      {
        "fieldKey": "2118_Spare_1",
        "dbNumber": 50,
        "offset": 718,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2118_Spare_2",
        "dbNumber": 50,
        "offset": 719,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2117_TaskNo",
        "dbNumber": 50,
        "offset": 640,
        "bit": 1,
        "dataType": 1,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2117_Source",
        "dbNumber": 50,
        "offset": 642,
        "bit": 1,
        "dataType": 1,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2117_Target",
        "dbNumber": 50,
        "offset": 644,
        "bit": 1,
        "dataType": 1,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2117_BoxType",
        "dbNumber": 50,
        "offset": 646,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2117_CV_State",
        "dbNumber": 50,
        "offset": 647,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2117_CV_ERRCode",
        "dbNumber": 50,
        "offset": 648,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2117_WCS_STB",
        "dbNumber": 50,
        "offset": 649,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2117_WCS_ACK",
        "dbNumber": 50,
        "offset": 650,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2117_PLC_STB",
        "dbNumber": 50,
        "offset": 651,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2117_PLC_ACK",
        "dbNumber": 50,
        "offset": 652,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2117_PLC_REQ",
        "dbNumber": 50,
        "offset": 653,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2117_WCS_ERRCode",
        "dbNumber": 50,
        "offset": 654,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2117_WCS_Special",
        "dbNumber": 50,
        "offset": 655,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2117_Equ_Auto",
        "dbNumber": 50,
        "offset": 656,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2117_Last_pallet",
        "dbNumber": 50,
        "offset": 657,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2117_Barcode",
        "dbNumber": 50,
        "offset": 658,
        "bit": 1,
        "dataType": 0,
        "length": 20,
        "direction": 2
      },
      {
        "fieldKey": "2117_Spare_1",
        "dbNumber": 50,
        "offset": 678,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2117_Spare_2",
        "dbNumber": 50,
        "offset": 679,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2209_TaskNo",
        "dbNumber": 50,
        "offset": 4320,
        "bit": 1,
        "dataType": 1,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2209_Source",
        "dbNumber": 50,
        "offset": 4322,
        "bit": 1,
        "dataType": 1,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2209_Target",
        "dbNumber": 50,
        "offset": 4324,
        "bit": 1,
        "dataType": 1,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2209_BoxType",
        "dbNumber": 50,
        "offset": 4326,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2209_CV_State",
        "dbNumber": 50,
        "offset": 4327,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2209_CV_ERRCode",
        "dbNumber": 50,
        "offset": 4328,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2209_WCS_STB",
        "dbNumber": 50,
        "offset": 4329,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2209_WCS_ACK",
        "dbNumber": 50,
        "offset": 4330,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2209_PLC_STB",
        "dbNumber": 50,
        "offset": 4331,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2209_PLC_ACK",
        "dbNumber": 50,
        "offset": 4332,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2209_PLC_REQ",
        "dbNumber": 50,
        "offset": 4333,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2209_WCS_ERRCode",
        "dbNumber": 50,
        "offset": 4334,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2209_WCS_Special",
        "dbNumber": 50,
        "offset": 4335,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2209_Equ_Auto",
        "dbNumber": 50,
        "offset": 4336,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2209_Last_pallet",
        "dbNumber": 50,
        "offset": 4337,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2209_Barcode",
        "dbNumber": 50,
        "offset": 4338,
        "bit": 1,
        "dataType": 0,
        "length": 20,
        "direction": 2
      },
      {
        "fieldKey": "2209_Spare_1",
        "dbNumber": 50,
        "offset": 4358,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2209_Spare_2",
        "dbNumber": 50,
        "offset": 4359,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2210_TaskNo",
        "dbNumber": 50,
        "offset": 4360,
        "bit": 1,
        "dataType": 1,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2210_Source",
        "dbNumber": 50,
        "offset": 4362,
        "bit": 1,
        "dataType": 1,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2210_Target",
        "dbNumber": 50,
        "offset": 4364,
        "bit": 1,
        "dataType": 1,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2210_BoxType",
        "dbNumber": 50,
        "offset": 4366,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2210_CV_State",
        "dbNumber": 50,
        "offset": 4367,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2210_CV_ERRCode",
        "dbNumber": 50,
        "offset": 4368,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2210_WCS_STB",
        "dbNumber": 50,
        "offset": 4369,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2210_WCS_ACK",
        "dbNumber": 50,
        "offset": 4370,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2210_PLC_STB",
        "dbNumber": 50,
        "offset": 4371,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2210_PLC_ACK",
        "dbNumber": 50,
        "offset": 4372,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2210_PLC_REQ",
        "dbNumber": 50,
        "offset": 4373,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2210_WCS_ERRCode",
        "dbNumber": 50,
        "offset": 4374,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2210_WCS_Special",
        "dbNumber": 50,
        "offset": 4375,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2210_Equ_Auto",
        "dbNumber": 50,
        "offset": 4376,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2210_Last_pallet",
        "dbNumber": 50,
        "offset": 4377,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2210_Barcode",
        "dbNumber": 50,
        "offset": 4378,
        "bit": 1,
        "dataType": 0,
        "length": 20,
        "direction": 2
      },
      {
        "fieldKey": "2210_Spare_1",
        "dbNumber": 50,
        "offset": 4398,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2210_Spare_2",
        "dbNumber": 50,
        "offset": 4399,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2120_TaskNo",
        "dbNumber": 50,
        "offset": 760,
        "bit": 1,
        "dataType": 1,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2120_Source",
        "dbNumber": 50,
        "offset": 762,
        "bit": 1,
        "dataType": 1,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2120_Target",
        "dbNumber": 50,
        "offset": 764,
        "bit": 1,
        "dataType": 1,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2120_BoxType",
        "dbNumber": 50,
        "offset": 766,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2120_CV_State",
        "dbNumber": 50,
        "offset": 767,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2120_CV_ERRCode",
        "dbNumber": 50,
        "offset": 768,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2120_WCS_STB",
        "dbNumber": 50,
        "offset": 769,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2120_WCS_ACK",
        "dbNumber": 50,
        "offset": 770,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2120_PLC_STB",
        "dbNumber": 50,
        "offset": 771,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2120_PLC_ACK",
        "dbNumber": 50,
        "offset": 772,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2120_PLC_REQ",
        "dbNumber": 50,
        "offset": 773,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2120_WCS_ERRCode",
        "dbNumber": 50,
        "offset": 774,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2120_WCS_Special",
        "dbNumber": 50,
        "offset": 775,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2120_Equ_Auto",
        "dbNumber": 50,
        "offset": 776,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2120_Last_pallet",
        "dbNumber": 50,
        "offset": 777,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2120_Barcode",
        "dbNumber": 50,
        "offset": 778,
        "bit": 1,
        "dataType": 0,
        "length": 20,
        "direction": 2
      },
      {
        "fieldKey": "2120_Spare_1",
        "dbNumber": 50,
        "offset": 798,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2120_Spare_2",
        "dbNumber": 50,
        "offset": 799,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2211_TaskNo",
        "dbNumber": 50,
        "offset": 4400,
        "bit": 1,
        "dataType": 1,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2211_Source",
        "dbNumber": 50,
        "offset": 4402,
        "bit": 1,
        "dataType": 1,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2211_Target",
        "dbNumber": 50,
        "offset": 4404,
        "bit": 1,
        "dataType": 1,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2211_BoxType",
        "dbNumber": 50,
        "offset": 4406,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2211_CV_State",
        "dbNumber": 50,
        "offset": 4407,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2211_CV_ERRCode",
        "dbNumber": 50,
        "offset": 4408,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2211_WCS_STB",
        "dbNumber": 50,
        "offset": 4409,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2211_WCS_ACK",
        "dbNumber": 50,
        "offset": 4410,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2211_PLC_STB",
        "dbNumber": 50,
        "offset": 4411,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2211_PLC_ACK",
        "dbNumber": 50,
        "offset": 4412,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2211_PLC_REQ",
        "dbNumber": 50,
        "offset": 4413,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2211_WCS_ERRCode",
        "dbNumber": 50,
        "offset": 4414,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2211_WCS_Special",
        "dbNumber": 50,
        "offset": 4415,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2211_Equ_Auto",
        "dbNumber": 50,
        "offset": 4416,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2211_Last_pallet",
        "dbNumber": 50,
        "offset": 4417,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2211_Barcode",
        "dbNumber": 50,
        "offset": 4418,
        "bit": 1,
        "dataType": 0,
        "length": 20,
        "direction": 2
      },
      {
        "fieldKey": "2211_Spare_1",
        "dbNumber": 50,
        "offset": 4438,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2211_Spare_2",
        "dbNumber": 50,
        "offset": 4439,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2213_TaskNo",
        "dbNumber": 50,
        "offset": 4480,
        "bit": 1,
        "dataType": 1,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2213_Source",
        "dbNumber": 50,
        "offset": 4482,
        "bit": 1,
        "dataType": 1,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2213_Target",
        "dbNumber": 50,
        "offset": 4484,
        "bit": 1,
        "dataType": 1,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2213_BoxType",
        "dbNumber": 50,
        "offset": 4486,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2213_CV_State",
        "dbNumber": 50,
        "offset": 4487,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2213_CV_ERRCode",
        "dbNumber": 50,
        "offset": 4488,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2213_WCS_STB",
        "dbNumber": 50,
        "offset": 4489,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2213_WCS_ACK",
        "dbNumber": 50,
        "offset": 4490,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2213_PLC_STB",
        "dbNumber": 50,
        "offset": 4491,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2213_PLC_ACK",
        "dbNumber": 50,
        "offset": 4492,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2213_PLC_REQ",
        "dbNumber": 50,
        "offset": 4493,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2213_WCS_ERRCode",
        "dbNumber": 50,
        "offset": 4494,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2213_WCS_Special",
        "dbNumber": 50,
        "offset": 4495,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2213_Equ_Auto",
        "dbNumber": 50,
        "offset": 4496,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2213_Last_pallet",
        "dbNumber": 50,
        "offset": 4497,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2213_Barcode",
        "dbNumber": 50,
        "offset": 4498,
        "bit": 1,
        "dataType": 0,
        "length": 20,
        "direction": 2
      },
      {
        "fieldKey": "2213_Spare_1",
        "dbNumber": 50,
        "offset": 4518,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      },
      {
        "fieldKey": "2213_Spare_2",
        "dbNumber": 50,
        "offset": 4519,
        "bit": 1,
        "dataType": 0,
        "length": 1,
        "direction": 2
      }
    ]
  }
]