using Masuit.Tools.Systems; 
 | 
using Newtonsoft.Json; 
 | 
using Quartz; 
 | 
using System.Diagnostics.CodeAnalysis; 
 | 
using System.Text; 
 | 
using System.Threading.Tasks; 
 | 
using WIDESEAWCS_BasicInfoRepository; 
 | 
using WIDESEAWCS_Common.TaskEnum; 
 | 
using WIDESEAWCS_Core.Caches; 
 | 
using WIDESEAWCS_Core.Helper; 
 | 
using WIDESEAWCS_Core.HttpContextUser; 
 | 
using WIDESEAWCS_IProcessRepository; 
 | 
using WIDESEAWCS_ITaskInfoRepository; 
 | 
using WIDESEAWCS_ITaskInfoService; 
 | 
using WIDESEAWCS_Model.Models; 
 | 
using WIDESEAWCS_QuartzJob; 
 | 
using WIDESEAWCS_QuartzJob.DeviceBase; 
 | 
using WIDESEAWCS_QuartzJob.Service; 
 | 
using WIDESEAWCS_QuartzJob.StackerCrane.Enum; 
 | 
using WIDESEAWCS_SignalR; 
 | 
using WIDESEAWCS_Tasks.ConveyorLineJob; 
 | 
using WIDESEAWCS_Tasks.StackerCraneJob; 
 | 
  
 | 
namespace WIDESEAWCS_Tasks 
 | 
{ 
 | 
    [DisallowConcurrentExecution] 
 | 
    public class CommonStackerStationCraneJob : JobBase, IJob 
 | 
    { 
 | 
        private readonly ITaskService _taskService; 
 | 
        private readonly ITaskExecuteDetailService _taskExecuteDetailService; 
 | 
        private readonly ITaskRepository _taskRepository; 
 | 
        private readonly IProcessRepository _processRepository; 
 | 
        private readonly IDt_StationManagerRepository _stationManagerRepository; 
 | 
        private readonly ICacheService _cacheService; 
 | 
        private readonly INoticeService _noticeService; 
 | 
  
 | 
        public CommonStackerStationCraneJob(ITaskService taskService, ITaskExecuteDetailService taskExecuteDetailService, ITaskRepository taskRepository, IRouterService routerService, IProcessRepository processRepository, IDt_StationManagerRepository stationManagerRepository, ICacheService cacheService, INoticeService noticeService) 
 | 
        { 
 | 
            _taskService = taskService; 
 | 
            _taskExecuteDetailService = taskExecuteDetailService; 
 | 
            _taskRepository = taskRepository; 
 | 
            _processRepository = processRepository; 
 | 
            _stationManagerRepository = stationManagerRepository; 
 | 
            _cacheService = cacheService; 
 | 
            _noticeService = noticeService; 
 | 
        } 
 | 
  
 | 
        public Task Execute(IJobExecutionContext context) 
 | 
        { 
 | 
            try 
 | 
            { 
 | 
                CommonStackerStationCrane commonStackerCrane = (CommonStackerStationCrane)context.JobDetail.JobDataMap.Get("JobParams"); 
 | 
                if (commonStackerCrane != null) 
 | 
                { 
 | 
                    if (!commonStackerCrane.IsEventSubscribed) 
 | 
                    { 
 | 
                        commonStackerCrane.StackerCraneTaskCompletedEventHandler += CommonStackerCrane_StackerCraneTaskCompletedEventHandler;//订阅任务完成事件 
 | 
                    } 
 | 
  
 | 
                    if (commonStackerCrane.StackerCraneAutoStatusValue == StackerCraneAutoStatus.Automatic && commonStackerCrane.StackerCraneStatusValue == StackerCraneStatus.Normal) 
 | 
                    { 
 | 
                        commonStackerCrane.CheckStackerCraneTaskCompleted();//防止任务完成事件监测超时,再手动触发一次 
 | 
  
 | 
                        if (commonStackerCrane.StackerCraneWorkStatusValue == StackerCraneWorkStatus.Standby) 
 | 
                        { 
 | 
                            Dt_Task? task = GetTask(commonStackerCrane); 
 | 
                            if (task != null) 
 | 
                            { 
 | 
                                StackerCraneTaskCommand? stackerCraneTaskCommand = ConvertToStackerCraneTaskCommand(task); 
 | 
                                if (stackerCraneTaskCommand != null) 
 | 
                                { 
 | 
                                    Thread.Sleep(1000); 
 | 
                                    bool sendFlag = commonStackerCrane.SendCommand(stackerCraneTaskCommand); 
 | 
                                    if (sendFlag) 
 | 
                                    { 
 | 
                                        //StringBuilder builder = new StringBuilder(); 
 | 
                                        //builder.AppendLine(); 
 | 
                                        //builder.AppendLine($"【{commonStackerCrane.DeviceName}】堆垛机状态:【{commonStackerCrane.StackerCraneStatusDes}】,时间:【{DateTime.Now}】"); 
 | 
                                        //builder.AppendLine($"【{commonStackerCrane.DeviceName}】手自动状态:【{commonStackerCrane.StackerCraneAutoStatusDes}】,时间:【{DateTime.Now}】"); 
 | 
                                        //builder.AppendLine($"【{commonStackerCrane.DeviceName}】作业状态:【{commonStackerCrane.StackerCraneWorkStatusDes}】,时间:【{DateTime.Now}】"); 
 | 
                                        //builder.AppendLine($"【{commonStackerCrane.DeviceName}】下发任务成功,【{JsonConvert.SerializeObject(stackerCraneTaskCommand, Formatting.Indented)}】"); 
 | 
                                        //builder.AppendLine($"时间:【{DateTime.Now}】"); 
 | 
                                        //builder.AppendLine(); 
 | 
                                        //ConsoleHelper.WriteColorLine(builder, ConsoleColor.Blue); 
 | 
                                        commonStackerCrane.LastTaskType = task.TaskType; 
 | 
                                        _taskService.UpdateTaskStatusToNext(task.TaskNum); 
 | 
                                    } 
 | 
                                } 
 | 
                            } 
 | 
                        } 
 | 
                    } 
 | 
  
 | 
                    #region 调用事件总线通知前端 
 | 
  
 | 
                    var tokenInfos = _cacheService.Get<List<UserInfo>>("Cache_UserToken"); 
 | 
                    if (tokenInfos == null || !tokenInfos.Any()) 
 | 
                    { 
 | 
                        //throw new Exception(commonStackerCrane.DeviceName + "缓存中未找到Token缓存"); 
 | 
                        return Task.CompletedTask; 
 | 
                    } 
 | 
                    var userTokenIds = tokenInfos?.Select(x => x.Token_ID).ToList(); 
 | 
                    var userIds = tokenInfos?.Select(x => x.UserId).ToList(); 
 | 
  
 | 
                    object obj = new 
 | 
                    { 
 | 
                        commonStackerCrane.StackerCraneStatusDes, 
 | 
                        commonStackerCrane.StackerCraneAutoStatusDes, 
 | 
                        commonStackerCrane.StackerCraneWorkStatusDes, 
 | 
                        commonStackerCrane.DeviceCode, 
 | 
                        commonStackerCrane.DeviceName, 
 | 
                        commonStackerCrane.CurrentTaskNum, 
 | 
                        commonStackerCrane.LastTaskNum, 
 | 
                    }; 
 | 
                    _noticeService.StackerData(userIds?.FirstOrDefault(), userTokenIds, new { commonStackerCrane.DeviceName, data = obj }); 
 | 
  
 | 
                    #endregion 调用事件总线通知前端 
 | 
                } 
 | 
            } 
 | 
            catch (Exception ex) 
 | 
            { 
 | 
                WriteError("CommonStackerStationCraneJob", "test", ex); 
 | 
            } 
 | 
            return Task.CompletedTask; 
 | 
        } 
 | 
  
 | 
        /// <summary> 
 | 
        /// 任务完成事件订阅的方法 
 | 
        /// </summary> 
 | 
        /// <param name="sender"></param> 
 | 
        /// <param name="e"></param> 
 | 
        private void CommonStackerCrane_StackerCraneTaskCompletedEventHandler(object? sender, WIDESEAWCS_QuartzJob.StackerCrane.StackerCraneTaskCompletedEventArgs e) 
 | 
        { 
 | 
            CommonStackerStationCrane? commonStackerCrane = sender as CommonStackerStationCrane; 
 | 
            if (commonStackerCrane != null) 
 | 
            { 
 | 
                if (commonStackerCrane.GetValue<StackerCraneDBName, short>(StackerCraneDBName.WorkType) != 5) 
 | 
                { 
 | 
                    ConsoleHelper.WriteColorLine($"【{commonStackerCrane.DeviceName}】堆垛机作业状态:【{(int)commonStackerCrane.StackerCraneWorkStatusValue}】时间【{DateTime.Now}】", ConsoleColor.Magenta); 
 | 
  
 | 
                    string str = $"【{commonStackerCrane.DeviceName}】任务完成,任务号:【{e.TaskNum}】时间【{DateTime.Now}】"; 
 | 
                    WriteInfo(commonStackerCrane.DeviceName, str); 
 | 
                    ConsoleHelper.WriteColorLine(str, ConsoleColor.Blue); 
 | 
  
 | 
                    var content = _taskService.StackCraneTaskCompletedByStation(e.TaskNum); 
 | 
                    commonStackerCrane.SetValue(StackerCraneDBName.WorkType, 5); 
 | 
  
 | 
                    var isWorkType = commonStackerCrane.SetValue(StackerCraneDBName.WorkType, 5); 
 | 
                    str = $"{commonStackerCrane.DeviceName}】WMS|WCS任务完成:【{content.Status}】,堆垛机完成信号写入:【{isWorkType}】,任务号:【{e.TaskNum}】时间【{DateTime.Now}】"; 
 | 
                    WriteInfo(commonStackerCrane.DeviceName, str); 
 | 
                    ConsoleHelper.WriteColorLine(str, ConsoleColor.Blue); 
 | 
  
 | 
                    if (content.Status) 
 | 
                    { 
 | 
                        var task = content.Data as Dt_Task; 
 | 
                        if (task.TaskType == (int)TaskOutboundTypeEnum.Outbound && task.TargetAddress == "001-000-001") 
 | 
                        { 
 | 
                            Dt_StationManager stationManager = _stationManagerRepository.QueryFirst(x => x.Roadway == task.Roadway && x.stationLocation == task.TargetAddress); 
 | 
                            IDevice? device = Storage.Devices.FirstOrDefault(x => x.DeviceCode == stationManager.stationPLC); 
 | 
                            if (device != null) 
 | 
                            { 
 | 
                                str = $"写入完成,给线体写入下降信号"; 
 | 
                                WriteInfo(commonStackerCrane.DeviceName, str); 
 | 
                                ConsoleHelper.WriteColorLine(str, ConsoleColor.Blue); 
 | 
  
 | 
                                // 获取输送线对象 
 | 
                                CommonConveyorLine_After conveyorLine = (CommonConveyorLine_After)device; 
 | 
  
 | 
                                // 获取协议地址 
 | 
                                var proAddress = conveyorLine.DeviceProDTOs 
 | 
                                    .FirstOrDefault(x => x.DeviceChildCode == stationManager.stationChildCode && x.DeviceProParamName == ConveyorLineDBName_After.InteractiveSignal.ToString()) 
 | 
                                    ?.DeviceProAddress; 
 | 
  
 | 
                                if (proAddress == null) 
 | 
                                { 
 | 
                                    str = "未找到协议地址"; 
 | 
                                    WriteInfo(commonStackerCrane.DeviceName, str); 
 | 
                                    ConsoleHelper.WriteColorLine(str, ConsoleColor.Red); 
 | 
                                    return; 
 | 
                                } 
 | 
  
 | 
                                string address = proAddress.Contains(".0") ? proAddress : proAddress + ".0"; 
 | 
  
 | 
                                // 写入 false 信号 
 | 
                                WriteSignal(conveyorLine, address, false, commonStackerCrane.DeviceName); 
 | 
                            } 
 | 
                            else 
 | 
                            { 
 | 
                                _taskService.UpdateTaskExceptionMessage(task.TaskNum, $"未找到出库站台【{task.NextAddress}】对应的通讯对象,无法清除出库站台顶升状态"); 
 | 
                            } 
 | 
                        } 
 | 
                    } 
 | 
                } 
 | 
            } 
 | 
        } 
 | 
  
 | 
        /// <summary> 
 | 
        /// 获取任务 
 | 
        /// </summary> 
 | 
        /// <param name="commonStackerCrane">堆垛机对象</param> 
 | 
        /// <returns></returns> 
 | 
        private Dt_Task? GetTask(CommonStackerStationCrane commonStackerCrane) 
 | 
        { 
 | 
            Dt_Task task; 
 | 
  
 | 
            task = _taskService.QueryOutFireAlarmTask(commonStackerCrane.DeviceCode); 
 | 
            if (task != null) 
 | 
            { 
 | 
                return task; 
 | 
            } 
 | 
  
 | 
            task = _taskService.QueryRelocationTask(commonStackerCrane.DeviceCode); 
 | 
            if (task != null) 
 | 
            { 
 | 
                return task; 
 | 
            } 
 | 
  
 | 
            if (commonStackerCrane.LastTaskType == null) 
 | 
            { 
 | 
                task = _taskService.QueryStackerCraneTask(commonStackerCrane.DeviceCode); 
 | 
            } 
 | 
            else 
 | 
            { 
 | 
                if (commonStackerCrane.LastTaskType.GetValueOrDefault().GetTaskTypeGroup() == TaskTypeGroup.OutbondGroup) 
 | 
                { 
 | 
                    task = _taskService.QueryStackerCraneInTask(commonStackerCrane.DeviceCode); 
 | 
                    if (task == null) 
 | 
                    { 
 | 
                        task = _taskService.QueryStackerCraneOutTask(commonStackerCrane.DeviceCode); 
 | 
                    } 
 | 
                } 
 | 
                else 
 | 
                { 
 | 
                    task = _taskService.QueryStackerCraneOutTask(commonStackerCrane.DeviceCode); 
 | 
                } 
 | 
            } 
 | 
  
 | 
            if (task != null && task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.OutbondGroup) 
 | 
            { 
 | 
                if (task.TaskType == (int)TaskOutboundTypeEnum.Outbound && task.TargetAddress == "001-000-001") 
 | 
                { 
 | 
                    Dt_StationManager stationManager = _stationManagerRepository.QueryFirst(x => x.Roadway == task.Roadway && x.stationLocation == task.TargetAddress); 
 | 
                    IDevice? device = Storage.Devices.FirstOrDefault(x => x.DeviceCode == stationManager.stationPLC); 
 | 
                    if (device != null) 
 | 
                    { 
 | 
                        CommonConveyorLine_After conveyorLine = (CommonConveyorLine_After)device; 
 | 
                        var proAddress = conveyorLine.DeviceProDTOs.Where(x => x.DeviceChildCode == stationManager.stationChildCode).Where(x => x.DeviceProParamName == ConveyorLineDBName_After.InteractiveSignal.ToString()).FirstOrDefault().DeviceProAddress; 
 | 
                        string? str = proAddress; 
 | 
                        if (!proAddress.Contains(".0")) 
 | 
                        { 
 | 
                            str = proAddress + ".0"; 
 | 
                        } 
 | 
                        conveyorLine.Communicator.Write(str, true); 
 | 
                    } 
 | 
                    else 
 | 
                    { 
 | 
                        _taskService.UpdateTaskExceptionMessage(task.TaskNum, $"未找到出库站台【{task.NextAddress}】对应的通讯对象,无法判断出库站台是否被占用"); 
 | 
                        return null; 
 | 
                    } 
 | 
                } 
 | 
                // 检查当前出库任务站台是否允许放货 
 | 
                var occupiedStation = OutTaskStationIsOccupied(task); 
 | 
                if (occupiedStation == null) 
 | 
                { 
 | 
                    // 如果当前出库任务站台不允许放货,排除当前任务,查找其他出库任务 
 | 
                    ConsoleHelper.WriteErrorLine($"任务号:【{task.TaskNum}】出库地址:【{task.NextAddress}】不允许放货"); 
 | 
                    task = FindAnotherOutboundTask(commonStackerCrane.DeviceCode, task); 
 | 
                } 
 | 
                else 
 | 
                { 
 | 
                    return task; 
 | 
                } 
 | 
  
 | 
                if (task == null) 
 | 
                { 
 | 
                    task = _taskService.QueryStackerCraneInTask(commonStackerCrane.DeviceCode); 
 | 
                } 
 | 
            } 
 | 
            else if (task == null) 
 | 
            { 
 | 
                task = _taskService.QueryStackerCraneInTask(commonStackerCrane.DeviceCode); 
 | 
            } 
 | 
  
 | 
            return task; 
 | 
        } 
 | 
  
 | 
        /// <summary> 
 | 
        /// 出库任务判断出库站台是否被占用 
 | 
        /// </summary> 
 | 
        /// <param name="task">任务实体</param> 
 | 
        /// <returns>如果未被占用,返回传入的任务信息,否则,返回null</returns> 
 | 
        private Dt_Task? OutTaskStationIsOccupied([NotNull] Dt_Task task) 
 | 
        { 
 | 
            var stationinfo = _stationManagerRepository.QueryFirst(x => x.stationLocation == task.TargetAddress && x.Roadway == task.Roadway); 
 | 
            IDevice? device = Storage.Devices.FirstOrDefault(x => x.DeviceCode == stationinfo.stationPLC); 
 | 
            if (device != null) 
 | 
            { 
 | 
                CommonConveyorLine_After conveyorLine = (CommonConveyorLine_After)device; 
 | 
                if (conveyorLine.IsOccupied(stationinfo.stationChildCode))//出库站台未被占用 
 | 
                { 
 | 
                    return task; 
 | 
                } 
 | 
            } 
 | 
            else 
 | 
            { 
 | 
                _taskService.UpdateTaskExceptionMessage(task.TaskNum, $"未找到出库站台【{task.NextAddress}】对应的通讯对象,无法判断出库站台是否被占用"); 
 | 
            } 
 | 
            return null; 
 | 
        } 
 | 
  
 | 
        /// <summary> 
 | 
        /// 查找其他出库任务的辅助方法(排除不可出的出库口任务) 
 | 
        /// </summary> 
 | 
        /// <param name="deviceCode">设备代码</param> 
 | 
        /// <param name="excludedTaskId">要排除的任务ID</param> 
 | 
        /// <returns></returns> 
 | 
        private Dt_Task? FindAnotherOutboundTask(string deviceCode, Dt_Task task) 
 | 
        { 
 | 
            // 先获取所有符合条件(排除不可出的)的出库任务列表 
 | 
            var allOutboundTasks = _taskService.QueryAllOutboundTasks(deviceCode); 
 | 
            Console.WriteLine(allOutboundTasks.Count); 
 | 
            var availableTasks = allOutboundTasks?.Where(t => t.TargetAddress != task.TargetAddress && t.TaskType.GetTaskTypeGroup() == TaskTypeGroup.OutbondGroup).ToList(); 
 | 
  
 | 
            Console.WriteLine("其他出库口任务:" + availableTasks?.Count); 
 | 
  
 | 
            if (availableTasks == null || availableTasks.Count == 0) 
 | 
            { 
 | 
                return null; 
 | 
            } 
 | 
  
 | 
            // 遍历可用任务列表,检查任务站台是否允许放货,找到第一个允许放货的任务就返回 
 | 
            foreach (var candidateTask in availableTasks) 
 | 
            { 
 | 
                var occupiedStation = OutTaskStationIsOccupied(candidateTask); 
 | 
                if (occupiedStation != null) 
 | 
                { 
 | 
                    return candidateTask; 
 | 
                } 
 | 
                ConsoleHelper.WriteErrorLine($"任务号:【{candidateTask.TaskNum}】出库地址:【{candidateTask.NextAddress}】不允许放货"); 
 | 
            } 
 | 
  
 | 
            return null; 
 | 
        } 
 | 
  
 | 
        /// <summary> 
 | 
        /// 任务实体转换成命令Model 
 | 
        /// </summary> 
 | 
        /// <param name="task">任务实体</param> 
 | 
        /// <returns></returns> 
 | 
        /// <exception cref="Exception"></exception> 
 | 
        public StackerCraneTaskCommand? ConvertToStackerCraneTaskCommand([NotNull] Dt_Task task) 
 | 
        { 
 | 
            StackerCraneTaskCommand stackerCraneTaskCommand = new StackerCraneTaskCommand(); 
 | 
  
 | 
            stackerCraneTaskCommand.Barcode = task.PalletCode; 
 | 
            stackerCraneTaskCommand.TaskNum = task.TaskNum; 
 | 
            stackerCraneTaskCommand.WorkType = 1; 
 | 
            stackerCraneTaskCommand.TrayType = 0; 
 | 
            stackerCraneTaskCommand.StartCommand = 1; 
 | 
            stackerCraneTaskCommand.FireCommand = Convert.ToInt16(task.TaskType == (int)TaskOutboundTypeEnum.OutFireAlarm ? 2 : 0); 
 | 
  
 | 
            string[] sourceCodes = task.SourceAddress.Split("-"); 
 | 
            if (sourceCodes.Length == 3) 
 | 
            { 
 | 
                stackerCraneTaskCommand.StartRow = (short)(Convert.ToInt16(sourceCodes[0]) % 2 == 0 ? 2 : 1); 
 | 
                stackerCraneTaskCommand.StartColumn = Convert.ToInt16(sourceCodes[1]); 
 | 
                stackerCraneTaskCommand.StartLayer = Convert.ToInt16(sourceCodes[2]); 
 | 
            } 
 | 
            else 
 | 
            { 
 | 
                //数据配置错误 
 | 
                _taskService.UpdateTaskExceptionMessage(task.TaskNum, $"移库任务起点错误,起点:【{task.CurrentAddress}】"); 
 | 
                return null; 
 | 
            } 
 | 
            string[] targetCodes = task.TargetAddress.Split("-"); 
 | 
            if (targetCodes.Length == 3) 
 | 
            { 
 | 
                stackerCraneTaskCommand.EndRow = (short)(Convert.ToInt16(targetCodes[0]) % 2 == 0 ? 2 : 1); 
 | 
                stackerCraneTaskCommand.EndColumn = Convert.ToInt16(targetCodes[1]); 
 | 
                stackerCraneTaskCommand.EndLayer = Convert.ToInt16(targetCodes[2]); 
 | 
            } 
 | 
            else 
 | 
            { 
 | 
                //数据配置错误 
 | 
                _taskService.UpdateTaskExceptionMessage(task.TaskNum, $"任务终点错误,起点:【{task.NextAddress}】"); 
 | 
                return null; 
 | 
            } 
 | 
  
 | 
            return stackerCraneTaskCommand; 
 | 
        } 
 | 
  
 | 
        /// <summary> 
 | 
        /// 写入信号并验证写入结果 
 | 
        /// </summary> 
 | 
        /// <param name="conveyorLine">输送线对象</param> 
 | 
        /// <param name="address">协议地址</param> 
 | 
        /// <param name="signal">信号值</param> 
 | 
        /// <param name="deviceName">设备名称</param> 
 | 
        void WriteSignal(CommonConveyorLine_After conveyorLine, string address, bool signal, string deviceName) 
 | 
        { 
 | 
            string str = string.Empty; 
 | 
  
 | 
            // 写入信号 
 | 
            conveyorLine.Communicator.Write(address, signal); 
 | 
  
 | 
            // 验证写入结果,最多重试5次 
 | 
            for (int i = 0; i < 5; i++) 
 | 
            { 
 | 
                var isWrite = conveyorLine.Communicator.Read<bool>(address); 
 | 
                if (isWrite == signal) 
 | 
                { 
 | 
                    break; 
 | 
                } 
 | 
                conveyorLine.Communicator.Write(address, signal); 
 | 
            } 
 | 
  
 | 
            // 最终验证写入结果 
 | 
            var finalWrite = conveyorLine.Communicator.Read<bool>(address); 
 | 
            if (finalWrite == signal) 
 | 
            { 
 | 
                str = $"{address}-写入{signal}成功"; 
 | 
                ConsoleHelper.WriteColorLine(str, ConsoleColor.Blue); 
 | 
                WriteInfo(deviceName, str); 
 | 
            } 
 | 
            else 
 | 
            { 
 | 
                str = $"{address}-写入{signal}失败"; 
 | 
                ConsoleHelper.WriteColorLine(str, ConsoleColor.Red); 
 | 
                WriteInfo(deviceName, str); 
 | 
            } 
 | 
        } 
 | 
    } 
 | 
} 
 |