wanshenmean
2026-02-28 c3de7bb2097aa347a1f92c2f640d18753aff633a
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/StackerCraneJob/CommonStackerCraneJob.cs
@@ -30,6 +30,7 @@
        private readonly ITaskExecuteDetailService _taskExecuteDetailService;
        private readonly ITaskRepository _taskRepository;
        private readonly IRouterService _routerService;
        private readonly StackerCraneCommandConfig _config;
        public CommonStackerCraneJob(ITaskService taskService, ITaskExecuteDetailService taskExecuteDetailService, ITaskRepository taskRepository, IRouterService routerService)
        {
@@ -37,6 +38,28 @@
            _taskExecuteDetailService = taskExecuteDetailService;
            _taskRepository = taskRepository;
            _routerService = routerService;
            _config = LoadConfig();
        }
        /// <summary>
        /// 加载配置(优先级:配置文件 > 默认配置)
        /// </summary>
        private static StackerCraneCommandConfig LoadConfig()
        {
            try
            {
                string configPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "StackerCraneJob", "stackercrane-command-config.json");
                if (File.Exists(configPath))
                {
                    string json = File.ReadAllText(configPath);
                    return System.Text.Json.JsonSerializer.Deserialize<StackerCraneCommandConfig>(json) ?? new StackerCraneCommandConfig();
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"配置加载失败: {ex.Message},使用默认配置");
            }
            return new StackerCraneCommandConfig();
        }
        public Task Execute(IJobExecutionContext context)
@@ -46,7 +69,7 @@
                Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " CommonStackerCraneJob Start");
                bool flag = context.JobDetail.JobDataMap.TryGetValue("JobParams", out object? value);
                if (!flag || value is not CommonStackerCrane commonStackerCrane)
                if (!flag || value is not IStackerCrane commonStackerCrane)
                {
                    return Task.CompletedTask;
                }
@@ -56,23 +79,17 @@
                    commonStackerCrane.StackerCraneTaskCompletedEventHandler += CommonStackerCrane_StackerCraneTaskCompletedEventHandler;
                }
                if (commonStackerCrane.StackerCraneAutoStatusValue != StackerCraneAutoStatus.Automatic
                    || commonStackerCrane.StackerCraneStatusValue != StackerCraneStatus.Normal)
                if (commonStackerCrane.IsCanSendTask(commonStackerCrane.Communicator, commonStackerCrane.DeviceProDTOs, commonStackerCrane.DeviceProtocolDetailDTOs))
                {
                    return Task.CompletedTask;
                }
                    commonStackerCrane.CheckStackerCraneTaskCompleted();
                commonStackerCrane.CheckStackerCraneTaskCompleted();
                if (commonStackerCrane.StackerCraneWorkStatusValue == StackerCraneWorkStatus.Standby)
                {
                    Dt_Task? task = GetTask(commonStackerCrane);
                    if (task != null)
                    {
                        StackerCraneTaskCommand? stackerCraneTaskCommand = ConvertToStackerCraneTaskCommand(task);
                        object? stackerCraneTaskCommand = ConvertToStackerCraneTaskCommand(task);
                        if (stackerCraneTaskCommand != null)
                        {
                            bool sendFlag = commonStackerCrane.SendCommand(stackerCraneTaskCommand);
                            bool sendFlag = SendStackerCraneCommand(commonStackerCrane, stackerCraneTaskCommand);
                            if (sendFlag)
                            {
                                commonStackerCrane.LastTaskType = task.TaskType;
@@ -99,12 +116,12 @@
            CommonStackerCrane? commonStackerCrane = sender as CommonStackerCrane;
            if (commonStackerCrane != null)
            {
                if (commonStackerCrane.GetValue<StackerCraneDBName, short>(StackerCraneDBName.WorkType) != 5)
                {
                //if (commonStackerCrane.GetValue<StackerCraneDBName, short>(StackerCraneDBName.WorkType) != 5)
                //{
                    Console.Out.WriteLine("TaskCompleted" + e.TaskNum);
                    _taskService.StackCraneTaskCompleted(e.TaskNum);
                    commonStackerCrane.SetValue(StackerCraneDBName.WorkType, 5);
                }
                //}
            }
        }
@@ -113,7 +130,7 @@
        /// </summary>
        /// <param name="commonStackerCrane">堆垛机对象</param>
        /// <returns></returns>
        private Dt_Task? GetTask(CommonStackerCrane commonStackerCrane)
        private Dt_Task? GetTask(IStackerCrane commonStackerCrane)
        {
            Dt_Task? task = null;
            if (commonStackerCrane.LastTaskType == null)
@@ -135,10 +152,10 @@
            if (task != null && task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.OutbondGroup)
            {
                if (IsOutTaskStationAvailable(task))
                {
                //if (IsOutTaskStationAvailable(task))
                //{
                    return task;
                }
                //}
                List<string> otherOutStationCodes = _routerService.QueryNextRoutes(commonStackerCrane.DeviceCode, task.NextAddress, task.TaskType)
                    .Select(x => x.ChildPosi).ToList();
@@ -184,32 +201,95 @@
        /// <summary>
        /// 任务实体转换成命令Model
        /// </summary>
        /// <param name="task">任务实体</param>
        /// <returns></returns>
        public StackerCraneTaskCommand? ConvertToStackerCraneTaskCommand([NotNull] Dt_Task task)
        public object? ConvertToStackerCraneTaskCommand([NotNull] Dt_Task task)
        {
            StackerCraneTaskCommand stackerCraneTaskCommand = new StackerCraneTaskCommand
            {
                Barcode = task.PalletCode,
                TaskNum = task.TaskNum,
                WorkType = 1,
                TrayType = 0
            };
            // 根据配置判断命令类型
            string commandType = GetCommandType(task.Roadway);
            TaskTypeGroup taskTypeGroup = task.TaskType.GetTaskTypeGroup();
            return taskTypeGroup switch
            // 创建并构建命令
            return commandType switch
            {
                TaskTypeGroup.InboundGroup => BuildInboundCommand(task, stackerCraneTaskCommand),
                TaskTypeGroup.OutbondGroup => BuildOutboundCommand(task, stackerCraneTaskCommand),
                TaskTypeGroup.RelocationGroup => BuildRelocationCommand(task, stackerCraneTaskCommand),
                _ => stackerCraneTaskCommand
                "Formation" => BuildCommand(task, CreateFormationCommand(task)),
                _ => BuildCommand(task, CreateStandardCommand(task))
            };
        }
        private static bool SendStackerCraneCommand(IStackerCrane commonStackerCrane, object command)
        {
            return command switch
            {
                FormationStackerCraneTaskCommand formationCommand => commonStackerCrane.SendCommand(formationCommand),
                StackerCraneTaskCommand standardCommand => commonStackerCrane.SendCommand(standardCommand),
                _ => false
            };
        }
        /// <summary>
        /// 构建入库命令
        /// 根据 Roadway 获取命令类型
        /// </summary>
        private StackerCraneTaskCommand? BuildInboundCommand(Dt_Task task, StackerCraneTaskCommand command)
        private string GetCommandType(string roadway)
        {
            foreach (var mapping in _config.RoadwayCommandMapping)
            {
                if (roadway.Contains(mapping.Key))
                {
                    return mapping.Value;
                }
            }
            return _config.DefaultCommandType;
        }
        /// <summary>
        /// 创建标准堆垛机命令
        /// </summary>
        private static StackerCraneTaskCommand CreateStandardCommand(Dt_Task task)
        {
            return new StackerCraneTaskCommand
            {
                //Barcode = task.PalletCode,
                TaskNum = task.TaskNum,
                WorkType = 1,
                WorkAction = 1
            };
        }
        /// <summary>
        /// 创建分容堆垛机命令
        /// </summary>
        private static FormationStackerCraneTaskCommand CreateFormationCommand(Dt_Task task)
        {
            return new FormationStackerCraneTaskCommand
            {
                Barcode = task.PalletCode,
                TaskNum = task.TaskNum,
                WorkType = 1,
                WorkAction = 1,
                FireAlarm = 0,
                HeartBeat = 0,
                FieldName = string.Empty
            };
        }
        /// <summary>
        /// 通用命令构建方法
        /// </summary>
        private T? BuildCommand<T>(Dt_Task task, T command) where T : class
        {
            TaskTypeGroup taskTypeGroup = task.TaskType.GetTaskTypeGroup();
            return taskTypeGroup switch
            {
                TaskTypeGroup.InboundGroup => BuildInboundCommand(task, command),
                TaskTypeGroup.OutbondGroup => BuildOutboundCommand(task, command),
                TaskTypeGroup.RelocationGroup => BuildRelocationCommand(task, command),
                _ => command
            };
        }
        /// <summary>
        /// 通用入库命令构建
        /// </summary>
        private T? BuildInboundCommand<T>(Dt_Task task, T command) where T : class
        {
            Dt_Router? router = _routerService.QueryNextRoute(task.CurrentAddress, task.Roadway, task.TaskType);
            if (router == null)
@@ -218,9 +298,9 @@
                return null;
            }
            command.StartRow = Convert.ToInt16(router.SrmRow);
            command.StartColumn = Convert.ToInt16(router.SrmColumn);
            command.StartLayer = Convert.ToInt16(router.SrmLayer);
            SetCommandProperty(command, "StartRow", Convert.ToInt16(router.SrmRow));
            SetCommandProperty(command, "StartColumn", Convert.ToInt16(router.SrmColumn));
            SetCommandProperty(command, "StartLayer", Convert.ToInt16(router.SrmLayer));
            if (!TryParseAddress(task.NextAddress, out short endRow, out short endColumn, out short endLayer))
            {
@@ -228,17 +308,17 @@
                return null;
            }
            command.EndRow = endRow;
            command.EndColumn = endColumn;
            command.EndLayer = endLayer;
            SetCommandProperty(command, "EndRow", endRow);
            SetCommandProperty(command, "EndColumn", endColumn);
            SetCommandProperty(command, "EndLayer", endLayer);
            return command;
        }
        /// <summary>
        /// 构建出库命令
        /// 通用出库命令构建
        /// </summary>
        private StackerCraneTaskCommand? BuildOutboundCommand(Dt_Task task, StackerCraneTaskCommand command)
        private T? BuildOutboundCommand<T>(Dt_Task task, T command) where T : class
        {
            Dt_Router? router = _routerService.QueryNextRoute(task.Roadway, task.TargetAddress, task.TaskType);
            if (router == null)
@@ -247,9 +327,9 @@
                return null;
            }
            command.EndRow = Convert.ToInt16(router.SrmRow);
            command.EndColumn = Convert.ToInt16(router.SrmColumn);
            command.EndLayer = Convert.ToInt16(router.SrmLayer);
            SetCommandProperty(command, "EndRow", Convert.ToInt16(router.SrmRow));
            SetCommandProperty(command, "EndColumn", Convert.ToInt16(router.SrmColumn));
            SetCommandProperty(command, "EndLayer", Convert.ToInt16(router.SrmLayer));
            if (!TryParseAddress(task.CurrentAddress, out short startRow, out short startColumn, out short startLayer))
            {
@@ -257,17 +337,17 @@
                return null;
            }
            command.StartRow = startRow;
            command.StartColumn = startColumn;
            command.StartLayer = startLayer;
            SetCommandProperty(command, "StartRow", startRow);
            SetCommandProperty(command, "StartColumn", startColumn);
            SetCommandProperty(command, "StartLayer", startLayer);
            return command;
        }
        /// <summary>
        /// 构建移库命令
        /// 通用移库命令构建
        /// </summary>
        private StackerCraneTaskCommand? BuildRelocationCommand(Dt_Task task, StackerCraneTaskCommand command)
        private T? BuildRelocationCommand<T>(Dt_Task task, T command) where T : class
        {
            if (!TryParseAddress(task.NextAddress, out short endRow, out short endColumn, out short endLayer))
            {
@@ -275,9 +355,9 @@
                return null;
            }
            command.EndRow = endRow;
            command.EndColumn = endColumn;
            command.EndLayer = endLayer;
            SetCommandProperty(command, "EndRow", endRow);
            SetCommandProperty(command, "EndColumn", endColumn);
            SetCommandProperty(command, "EndLayer", endLayer);
            if (!TryParseAddress(task.CurrentAddress, out short startRow, out short startColumn, out short startLayer))
            {
@@ -285,11 +365,20 @@
                return null;
            }
            command.StartRow = startRow;
            command.StartColumn = startColumn;
            command.StartLayer = startLayer;
            SetCommandProperty(command, "StartRow", startRow);
            SetCommandProperty(command, "StartColumn", startColumn);
            SetCommandProperty(command, "StartLayer", startLayer);
            return command;
        }
        /// <summary>
        /// 使用反射设置命令属性
        /// </summary>
        private static void SetCommandProperty<T>(T command, string propertyName, object value) where T : class
        {
            var property = typeof(T).GetProperty(propertyName);
            property?.SetValue(command, value);
        }
        /// <summary>
@@ -310,4 +399,4 @@
                && short.TryParse(parts[2], out layer);
        }
    }
}
}