using iWareCommon; using iWareCommon.Utils; using iWareSql; using System; using System.Collections.Generic; using System.Threading; using iWareCC.SrmService; using System.Linq; using iWareSql.Orm; using System.Threading.Tasks; using iWareSql.DataAccess; using iWareSql.Entity.ParamModel; using Newtonsoft.Json; using iWareCC.BLL; using iWareCC.Common; using iWareModel; using iWareSql.DBModel; using iWareCommon.Common.Globle; using XiGang.Core.Model; using iWareCC.Common.Helper; namespace iWareCC { /// /// 堆垛机任务服务线程类 /// public class SrmTaskThreadService : DeviceThreadServiceHandle { private static string _namespace = "iWareCC.SrmTaskThreadService"; private SrmTaskThreadService() { } public SrmTaskThreadService(iWareCommon.Utils.LogType logType) { base.currentLogType = logType; } public override void StartService() { Task.Run(() => { try { //自动执行堆垛机任务线程 Log4NetHelper.WriteInfoLog(base.currentLogType, "自动执行堆垛机任务线程启动了"); //var srmList = new SrmService.SrmServiceClient().GetSrm_CacheEntity(); var srmList = FormCC.SrmDeviceList; foreach (var x in srmList) { IssueTaskThread(x); ConfirmFinishTaskThread(x); } } catch (Exception ex) { Log4NetHelper.WriteErrorLog(base.currentLogType, "SrmTaskThreadService线程启动出现异常", ex); } }); } #region 线程处理 #region 自动执行堆垛机任务线程 /// /// 自动执行堆垛机任务 /// /// public override void IssueTask(object deviceId) { string errMsg1 = "", errMsg2 = "", errMsg3 = "", errMsg4 = ""; int i_deviceId = (int)deviceId; while (true) { if ((int)deviceId == (int)EDevice.一号堆垛机 && SystemValue.isAllowRuning_SrmTaskThreadService_1 && SystemValue.isStartedModel) { IssueTaskHandle(i_deviceId, out errMsg1); } else if ((int)deviceId == (int)EDevice.二号堆垛机 && SystemValue.isAllowRuning_SrmTaskThreadService_2 && SystemValue.isStartedModel) { IssueTaskHandle(i_deviceId, out errMsg2); } else if ((int)deviceId == (int)EDevice.三号堆垛机 && SystemValue.isAllowRuning_SrmTaskThreadService_3 && SystemValue.isStartedModel) { IssueTaskHandle(i_deviceId, out errMsg3); } else if ((int)deviceId == (int)EDevice.四号堆垛机 && SystemValue.isAllowRuning_SrmTaskThreadService_4 && SystemValue.isStartedModel) { IssueTaskHandle(i_deviceId, out errMsg4); } SystemWarningMsg._lbl_Alert_DataProcess_BZ39_IssueInboundTask = errMsg1; SystemWarningMsg._lbl_Alert_Srm2Release = errMsg2; SystemWarningMsg._lbl_Alert_Srm4Release = errMsg4; Thread.Sleep(2000);//2秒一次 } } /// /// 自动执行堆垛机任务(线程) /// /// public override void IssueTaskHandle(int deviceId, out string errMsg) { errMsg = ""; string logHeader = "方法:DoSrmTaskByThead,参数deviceId:" + deviceId.ToString() + "==="; #region 新增异常信息表 【EditBy shaocx,2020-01-20】 IDictionary logDict = new Dictionary(); logDict.Add("deviceId", deviceId); Base_SysExceptionInfo exception = SysExceptionInfoHandler.GetExceptionInfo>(base.currentLogType, _namespace, "DoSrmTaskByThead", logDict); #endregion try { /* * 执行发送给堆垛机的指令任务 * 1、验证根据设备号是否找到堆垛机 * 2、判断设备是否属于任务完成,如果属于任务完成,就继续走3 * 3、判断数据库中是否有可要下发的任务,如果有就下发+验证起始点和目标点是否正确 * 4、下发成功后,更新任务状态 */ errMsg = ""; int int_deviceId = (int)deviceId; //2、判断堆垛机是否可以下发新任务 bool isOk = ValidateDeviceIsAllowSendTask(int_deviceId, out errMsg); if (!isOk) { errMsg = "不允许下发新任务," + errMsg; return; } using (DbModel dbModel = new DbModel()) { //var srmTask = ValidateIsExistTaskToDispose(dbModel, int_deviceId, out errMsg, TaskExcuteTypeEnum.执行任务); //if (srmTask == null) //{//表示DB中没有任务要发送给堆垛机 // return; //} var srmTaskList = ValidateIsExistTaskToDisposeForIssued(dbModel, int_deviceId, out errMsg); if (srmTaskList == null || srmTaskList.Count == 0) {//表示DB中没有任务要发送给堆垛机 return; } foreach (var item in srmTaskList) { SingleIssueTaskHandle(item, exception, dbModel, int_deviceId, out errMsg); if (!string.IsNullOrEmpty(errMsg)) {//说明报错了,继续走下一个循环 continue; } else {//说明执行成功了,跳出循环 break; } } } } catch (Exception ex) { errMsg = "异常,请联系管理员:" + ex.Message; SysExceptionInfoHandler.GetExceptionInfoForError("自动执行堆垛机任务(线程)出现异常,deviceId:" + deviceId + ",异常:" + ex.Message, ex, ref exception); SysExceptionInfoHandler.InsertExceptionInfo(exception, true); } } /// /// 单个堆垛机任务下发处理 /// /// /// /// /// /// private void SingleIssueTaskHandle(Task_Part srmTask, Base_SysExceptionInfo exception, DbModel dbModel, int int_deviceId, out string errMsg) { #region //3、判断数据库中是否有可要下发的任务,如果有就下发 DeviceTaskTypeEnum _DeviceTaskTypeEnum = (DeviceTaskTypeEnum)Enum.Parse(typeof(DeviceTaskTypeEnum), srmTask.TaskType.ToString()); //验证起始点和目标点是否正确 RealPlaceEntity realPlaceEntity = null; if (!ValdiatePalceIsRight(dbModel, (int)srmTask.SourcePlace, (int)srmTask.ToPlace, ref realPlaceEntity)) { errMsg = "验证起始点和目标点是否正确失败"; PartTaskHandler.WriteOperationRemarkForPartTask(srmTask.Id, errMsg); return; } //验证目标点是否已经有库存 【EditBy shaocx,2022-04-15】 var isOk = ValidateIsHasStoreForToPlace(int_deviceId, srmTask.ToPlace, srmTask.RealToPlace, out errMsg); if (!isOk) { errMsg = "不允许下发新任务," + errMsg; PartTaskHandler.WriteOperationRemarkForPartTask(srmTask.Id, errMsg); return; } #region 增加校验 [EditBy shaocx,2022-05-15] //去掉这个验证 【EditBy shaocx,2022-05-19】 /* Base_Station toPlaceObject = dbModel.Base_Station.Where(o => o.Id == (int)srmTask.ToPlace).FirstOrDefault(); if (toPlaceObject == null) { throw new Exception(string.Format("根据目标库位ID {0},{1}没有找到库位信息!", srmTask.ToPlace, srmTask.RealToPlace)); } //*/ var sourcePlace = dbModel.Base_Station.Where(o => o.Id == srmTask.SourcePlace).FirstOrDefault(); if (sourcePlace == null) { throw new Exception(string.Format("根据库位号{0},{1}没有找到堆垛机的来源库位信息!", srmTask.SourcePlace.ToString(), srmTask.RealSourcePlace)); } //要判断起点是否有库存,如果起点没有库存,则报错 var sourcePlaceStore = dbModel.V_AllStore.Where(x => x.StationId == sourcePlace.Id).FirstOrDefault(); if (sourcePlaceStore == null) { throw new Exception(string.Format("起点{0},{1}没有找到库存信息,无法下发堆垛机任务!任务号{2}", srmTask.SourcePlace.ToString(), srmTask.RealSourcePlace, srmTask.Id)); } #endregion //同一个关联任务的其他设备任务 var queryTaskState1 = (int)DeviceTaskStatusEnum.未开始; //var queryTaskState2 = (int)DeviceTaskStatusEnum.已下发; var relevanceTask = dbModel.Task_Part.Where(x => x.MainTaskId == srmTask.MainTaskId && x.TaskSequence < srmTask.TaskSequence && (x.TaskState == queryTaskState1) ).FirstOrDefault(); if (relevanceTask != null) { errMsg = string.Format("关联{0}任务未开始,所以堆垛机任务不允许下发!关联任务号:{1}", relevanceTask.DeviceName, relevanceTask.PlcTaskId); PartTaskHandler.WriteOperationRemarkForPartTask(srmTask.Id, errMsg); return; } //去掉验证 【EditBy shaocx,2022-05-19】 /* var validateIsAllowNewTaskForRgvStattion = ValidateIsAllowNewTaskForRgvStattion(dbModel, _DeviceTaskTypeEnum, srmTask.RealToPlace, ref errMsg); if (!validateIsAllowNewTaskForRgvStattion) { PartTaskHandler.WriteOperationRemarkForPartTask(srmTask.Id, errMsg); return; } //*/ var log = TaskRequestLogHandler.GetTask(srmTask.Id, int_deviceId, srmTask.PlcTaskId, srmTask.RealSourcePlace, srmTask.RealToPlace, "给堆垛机发送任务指令", "sys"); SdaResEntity sdaResult = new SdaResEntity(); try { if (MyExtendHelper.IsAllowSimulatorHandle(srmTask)) { sdaResult.result = true; } else { if (Convert.ToInt32(srmTask.PlcTaskId) <= 0) { throw new Exception("任务号不能小于等于0,PlcTaskId:" + srmTask.PlcTaskId); } sdaResult = new SrmService.SrmServiceClient().SendSrmTask(int_deviceId, Convert.ToInt32(srmTask.PlcTaskId), srmTask.RealSourcePlace, srmTask.RealToPlace, (short)ESrmCmd.库内搬运); } if (sdaResult.result == false) {//给堆垛机下发指令失败 exception.exceptionMsg = string.Format("发送指令给堆垛机失败,设备号{0},任务ID{1},起始位{2},目标位{3},ContainerId{4}", int_deviceId, Convert.ToInt32(srmTask.PlcTaskId), srmTask.RealSourcePlace, srmTask.RealToPlace, srmTask.SalverId); SysExceptionInfoHandler.InsertExceptionInfo(exception, true); TaskRequestLogHandler.InsertTask(base.currentLogType, RequestStatusEnum.请求失败, JsonConvert.SerializeObject(sdaResult).ToString(), log, null); return; } else { TaskRequestLogHandler.InsertTask(base.currentLogType, RequestStatusEnum.请求成功, JsonConvert.SerializeObject(sdaResult).ToString(), log, null); SystemValueUtil.DelayExcuteForSrmTaskThreadService(int_deviceId, ThreadDirectionEnum.任务开始下发线程); } } catch (Exception ex) { TaskRequestLogHandler.InsertTask(base.currentLogType, RequestStatusEnum.请求失败, JsonConvert.SerializeObject(sdaResult).ToString(), log, ex); throw ex; } #endregion //只更新着三个字段! //任务完成后的库存转移工作 isOk = DealWithCurrentTaskWhenFinished(srmTask, dbModel); if (isOk == false) { throw new Exception("DealWithCurrentTaskWhenFinished处理失败"); } } /// /// 当前任务完成后进行状态修改 /// /// 当前任务 /// private bool DealWithCurrentTaskWhenFinished(Task_Part currentTask, DbModel dbModel) { #region 新增异常信息表 【EditBy shaocx,2020-01-20】 IDictionary logDict = new Dictionary(); logDict.Add("currentTask.tackId", currentTask.Id); logDict.Add("currentTask.plcTaskId", currentTask.PlcTaskId); Base_SysExceptionInfo exception = SysExceptionInfoHandler.GetExceptionInfo>(base.currentLogType, _namespace, "DealWithCurrentTask", logDict); #endregion try { bool rtn = false; var taskType = (DeviceTaskTypeEnum)Enum.Parse(typeof(DeviceTaskTypeEnum), currentTask.TaskType.ToString()); switch (taskType) { case DeviceTaskTypeEnum.组盘入库: case DeviceTaskTypeEnum.空托转运到立体库: rtn = DealFor_Srm_Store_In(currentTask, dbModel, taskType);//入库执行后增加库存 break; case DeviceTaskTypeEnum.出库: case DeviceTaskTypeEnum.立库空托到拆盘机入口: rtn = DealFor_Srm_Store_Out(currentTask, dbModel, taskType);//出库 break; default: break; } //库存发生变化时,发送库存给MES //switch (taskType) //{ // case DeviceTaskTypeEnum22.配板原料入库: // case DeviceTaskTypeEnum22.线下配板原料入库: // case DeviceTaskTypeEnum22.配板余料回库: // case DeviceTaskTypeEnum22.配板原料出库: // case DeviceTaskTypeEnum22.人工出库: // //MesBLL.SendSysnStockToMes(); // break; // default: // break; //} return rtn; } catch (Exception ex) { SysExceptionInfoHandler.GetExceptionInfoForError("当前任务完成后进行状态修改出现异常:" + ex.Message, ex, ref exception); SysExceptionInfoHandler.InsertExceptionInfo(exception); throw ex; } } /// /// 入库任务处理 /// /// /// private bool DealFor_Srm_Store_In(Task_Part currentTask, DbModel dbModel, DeviceTaskTypeEnum taskType) { #region 新增异常信息表 【EditBy shaocx,2020-01-20】 IDictionary logDict = new Dictionary(); logDict.Add("currentTask.tackId", currentTask.Id); logDict.Add("currentTask.plcTaskId", currentTask.PlcTaskId); Base_SysExceptionInfo exception = SysExceptionInfoHandler.GetExceptionInfo>(base.currentLogType, _namespace, "DealFor_Srm_Store_In", logDict); #endregion try { /** * 1、当前任务状态修改为已完成 * 2、添加托盘和库位的绑定关系 * 3、变更库位状态 */ #region 准备数据 #region 增加校验 [EditBy shaocx,2022-05-15] Base_Station toPlaceObject = dbModel.Base_Station.Where(o => o.Id == (int)currentTask.ToPlace).FirstOrDefault(); if (toPlaceObject == null) { throw new Exception(string.Format("根据目标库位ID {0},{1}没有找到库位信息!", currentTask.ToPlace, currentTask.RealToPlace)); } var sourcePlace = dbModel.Base_Station.Where(o => o.Id == currentTask.SourcePlace).FirstOrDefault(); if (sourcePlace == null) { throw new Exception(string.Format("根据库位号{0},{1}没有找到堆垛机的来源库位信息!", currentTask.SourcePlace.ToString(), currentTask.RealSourcePlace)); } //要判断起点是否有库存,如果起点没有库存,则报错 var sourcePlaceStore = dbModel.V_AllStore.Where(x => x.StationId == sourcePlace.Id).FirstOrDefault(); if (sourcePlaceStore == null) { throw new Exception(string.Format("起点{0},{1}没有找到库存信息,无法下发堆垛机任务!这里任务号{2}", currentTask.SourcePlace.ToString(), currentTask.RealSourcePlace, currentTask.Id)); } #endregion toPlaceObject.IsHasTaskDoing = false; toPlaceObject.IsFull = true; StationHandler.SetPlaceLockStatus(false, SysGloble.WCSSystem, ref toPlaceObject, "堆垛机任务完成,入库任务处理,任务类型:" + taskType.ToString()); StationHandler.SetPlaceLockStatus(false, SysGloble.WCSSystem, ref sourcePlace, "堆垛机任务完成,入库任务处理,任务类型:" + taskType.ToString()); #endregion return CommonTransForThreadFinish(dbModel, currentTask, "入库任务完成处理成功,任务类型:" + taskType.ToString(), sourcePlace, toPlaceObject, taskType); } catch (Exception ex) { SysExceptionInfoHandler.GetExceptionInfoForError("入库任务处理出现异常:" + ex.Message, ex, ref exception); SysExceptionInfoHandler.InsertExceptionInfo(exception); throw ex; } } /// /// 出库任务处理 /// /// /// private bool DealFor_Srm_Store_Out(Task_Part currentTask, DbModel dbModel, DeviceTaskTypeEnum taskType) { #region 新增异常信息表 【EditBy shaocx,2020-01-20】 IDictionary logDict = new Dictionary(); logDict.Add("currentTask.tackId", currentTask.Id); logDict.Add("currentTask.plcTaskId", currentTask.PlcTaskId); Base_SysExceptionInfo exception = SysExceptionInfoHandler.GetExceptionInfo>(base.currentLogType, _namespace, "DealFor_Srm_Store_Out", logDict); #endregion try { /** * 1、当前任务状态修改为已完成 * 2、解除来源位置的托盘和库位的绑定关系 * 3、变更库位状态 */ #region 准备数据 Base_Station toPlaceObject = dbModel.Base_Station.Where(o => o.Id == (int)currentTask.ToPlace).FirstOrDefault(); if (toPlaceObject == null) { throw new Exception(string.Format("根据库位ID {0}没有找到库位信息!", currentTask.ToPlace)); } #region 3、变更库位状态 //目标的库位状态 toPlaceObject.IsHasTaskDoing = false; toPlaceObject.IsFull = true; StationHandler.SetPlaceLockStatus(false, SysGloble.WCSSystem, ref toPlaceObject, "堆垛机任务完成,出库任务处理"); //来源位置的库位状态 var sourcePlace = dbModel.Base_Station.Where(o => o.Id == currentTask.SourcePlace).FirstOrDefault(); if (sourcePlace == null) { throw new Exception(string.Format("根据库位号{0}没有找到库位信息!", currentTask.SourcePlace.ToString())); } sourcePlace.IsHasTaskDoing = false; sourcePlace.IsFull = false; StationHandler.SetPlaceLockStatus(false, SysGloble.WCSSystem, ref sourcePlace, "堆垛机任务完成,出库任务处理"); #endregion #endregion return CommonTransForThreadFinish(dbModel, currentTask, "出库任务处理成功", sourcePlace, toPlaceObject, taskType); } catch (Exception ex) { SysExceptionInfoHandler.GetExceptionInfoForError("出库任务处理出现异常:" + ex.Message, ex, ref exception); SysExceptionInfoHandler.InsertExceptionInfo(exception); return false; } } private bool CommonTransForThreadFinish(DbModel dbModel, Task_Part currentTask, string business, Base_Station sourcePlace, Base_Station toPlaceObject, DeviceTaskTypeEnum taskType) { #region 新增异常信息表 【EditBy shaocx,2020-01-20】 IDictionary logDict = new Dictionary(); logDict.Add("currentTask.tackId", currentTask.Id); logDict.Add("currentTask.plcTaskId", currentTask.PlcTaskId); Base_SysExceptionInfo exception = SysExceptionInfoHandler.GetExceptionInfo>(base.currentLogType, _namespace, "CommonTransForThreadFinish", logDict); #endregion try { try { #region 当设备任务完成后,转移库存(注意:一定要在最后面执行!!) try { TransferStoreWhenFinished(currentTask, dbModel, currentTask.SalverId, toPlaceObject, business, taskType, EDeviceType.堆垛机); } catch (Exception ex) { throw new Exception("转移库存时抛出异常,方法(TransferStoreWhenFinished),message:" + ex.Message, ex); } #endregion UpdateMainTaskStatus(dbModel, currentTask.MainTaskId, currentTask.TaskType, "堆垛机任务完成时"); //4、下发成功后,更新任务状态 currentTask.IsReleased = true; currentTask.ModifyBy = SysGloble.WCSSystem; currentTask.ModifyTime = DateTime.Now; currentTask.TaskState = (int)DeviceTaskStatusEnum.已下发; currentTask.TaskStateName = DeviceTaskStatusEnum.已下发.ToString(); currentTask.OperationRemark = "任务已下发给设备"; currentTask.IssueTime = DateTime.Now;//下发时间 //注意:一定是先要保存数据库,才再跟plc交互!!!!! int i = dbModel.SaveChanges(); if (i <= 0) { throw new Exception("更新的条数为" + i); } } catch (Exception ex) { throw ex; } return true; } catch (Exception) { throw; } } #endregion #region 自动结束堆垛机任务线程 /// /// 自动结束堆垛机任务线程 /// /// public override void ConfirmFinishTask(object deviceId) { string errMsg1 = "", errMsg2 = "", errMsg3 = "", errMsg4 = ""; int i_deviceId = (int)deviceId; while (true) { if ((int)deviceId == (int)EDevice.一号堆垛机 && SystemValue.isAllowRuning_SrmTaskThreadService_1_Finish && SystemValue.isStartedModel) { ConfirmFinishTaskHandle(i_deviceId, out errMsg1); } else if ((int)deviceId == (int)EDevice.二号堆垛机 && SystemValue.isAllowRuning_SrmTaskThreadService_2_Finish && SystemValue.isStartedModel) { ConfirmFinishTaskHandle(i_deviceId, out errMsg2); } else if ((int)deviceId == (int)EDevice.三号堆垛机 && SystemValue.isAllowRuning_SrmTaskThreadService_3_Finish && SystemValue.isStartedModel) { ConfirmFinishTaskHandle(i_deviceId, out errMsg3); } else if ((int)deviceId == (int)EDevice.四号堆垛机 && SystemValue.isAllowRuning_SrmTaskThreadService_4_Finish && SystemValue.isStartedModel) { ConfirmFinishTaskHandle(i_deviceId, out errMsg4); } SystemWarningMsg._lbl_Alert_Srm1ReleaseFinish = errMsg1; SystemWarningMsg._lbl_Alert_DataProcess_BZ12_FinishTask = errMsg2; SystemWarningMsg._lbl_Alert_DataProcess_BZ21_FinishTask = errMsg3; SystemWarningMsg._lbl_Alert_DataProcess_BZ21 = errMsg4; Thread.Sleep(2000);//设置2秒一次 } } /// /// 自动结束堆垛机任务线程(线程) /// /// public override void ConfirmFinishTaskHandle(int deviceId, out string errMsg) { errMsg = ""; string logHeader = "自动结束堆垛机任务线程(线程),设备号:" + deviceId; #region 新增异常信息表 【EditBy shaocx,2020-01-20】 IDictionary logDict = new Dictionary(); logDict.Add("deviceId", deviceId); Base_SysExceptionInfo exception = SysExceptionInfoHandler.GetExceptionInfo>(base.currentLogType, _namespace, "FinishSrmTaskByThead", logDict); #endregion try { /* * 执行发送给堆垛机的指令任务 * 1、验证根据设备号是否找到堆垛机 * 2、判断设备是否属于任务完成,如果属于任务完成,就继续走3 * 3、判断数据库中是否有可要完成的任务,如果有判断是否跟堆垛机中的完成任务相符,如果相符就处理 * 4、更新任务状态 */ int int_deviceId = (int)deviceId; //SystemValueUtil.DelayExcuteForSrmTaskThreadService((int)deviceId, ThreadDirectionEnum.任务完成线程); using (DbModel dbModel = new DbModel()) { #region //3、判断数据库中是否有可要完成的任务,如果有判断是否跟堆垛机中的完成任务相符,如果相符就处理 var currentTask = ValidateIsExistTaskToDispose(dbModel, int_deviceId, out errMsg, TaskExcuteTypeEnum.结束任务); if (currentTask == null) {//表示DB中没有任务要发送给堆垛机 //注释以下代码,手动发的任务,不要自动确认 ////可以完成 非系统发送的自动任务 [EditBy shaocx,2022-04-04] //if (FormCC.IsSimulationPLC == false && FormCC.srmViewDict[int_deviceId].R_TaskFinish == 1 && FormCC.srmViewDict[int_deviceId].R_TaskNo > 0) //{//只有当堆垛机是任务完成的时候 // ConfirmTaskFinishToSda(deviceId, FormCC.srmViewDict[int_deviceId].R_TaskNo); //} errMsg = "没有堆垛机任务数据要处理"; return; } #endregion //2、判断设备是否任务完成 var isFinished = ValidateDeviceTaskIsFinsished(int_deviceId, currentTask, Convert.ToInt32(currentTask.PlcTaskId), (DeviceTaskTypeEnum)Enum.Parse(typeof(DeviceTaskTypeEnum), currentTask.TaskType.ToString()), currentTask.IsAllowSimulateExecute, out errMsg); if (!isFinished) return; ////判断和堆垛机(或RGV)的连接任务是不是已经完成了 var queryTaskState1 = (int)DeviceTaskStatusEnum.未开始; var queryTaskState2 = (int)DeviceTaskStatusEnum.已下发; /* //注释以下方法,因为出现了 某个任务MainTaskSequence 比他小,但是某个任务还未执行的问题 【EditBy shaocx,2022-04-28】 //同一个堆垛机的前面未结束的任务,且同种类型 var otherSrmTask = dbModel.Task_Part.Where(x => x.DeviceId == int_deviceId && x.Id != currentTask.Id && (x.TaskState == queryTaskState1 || x.TaskState == queryTaskState2) && x.CreateTime < currentTask.CreateTime ).FirstOrDefault(); if (otherSrmTask != null) { errMsg = "上一个堆垛机任务未完成,所以堆垛机任务不允许完成!上一个堆垛机任务号:" + otherSrmTask.PlcTaskId + ",本次堆垛机任务号:" + currentTask.PlcTaskId; return; } //*/ //同一个关联任务的其他设备任务 var relevanceTask = dbModel.Task_Part.Where(x => x.MainTaskId == currentTask.MainTaskId && x.TaskSequence < currentTask.TaskSequence && (x.TaskState == queryTaskState1 || x.TaskState == queryTaskState2)).FirstOrDefault(); if (relevanceTask != null) { errMsg = string.Format("关联{0}任务未完成,所以堆垛机任务不允许完成!关联任务号:{1}", relevanceTask.DeviceName, relevanceTask.PlcTaskId); return; } //4、处理任务完成状态 var isOk = ConfirmTaskFinishToSrm(currentTask, "堆垛机任务完成", exception); if (isOk) { //堆垛机完成了当前任务后进行任务状态的修改 ChangeTaskStateWhenTaskFinish(currentTask); dbModel.SaveChanges(); } } } catch (Exception ex) { errMsg = "出现异常:" + ex.Message; SysExceptionInfoHandler.GetExceptionInfoForError("自动结束堆垛机任务线程(线程)出现异常,deviceId:" + deviceId + ",异常:" + ex.Message, ex, ref exception); SysExceptionInfoHandler.InsertExceptionInfo(exception, true); } } /// /// 判断是人工发送给任务,单独给堆垛机发送任务完成信号 /// /// /// /// private bool ConfirmTaskFinishToSda(int deviceId, int taskId) { //任务完成处理成功,需要再给堆垛机发送任务完成确认信号 SdaResEntity sdaResult = new SdaResEntity(); try { sdaResult = new SrmService.SrmServiceClient().ConfirmTaskFinish(deviceId, taskId); if (!sdaResult.result) { Log4NetHelper.WriteInfoLog(iWareCommon.Utils.LogType.DataProcess_BZ39_IssueInboundTask, "判断是人工发送的任务,单独给堆垛机发送任务完成信号,【失败】,设备号:" + deviceId + ",任务号:" + taskId); return false; } else { Log4NetHelper.WriteInfoLog(iWareCommon.Utils.LogType.DataProcess_BZ39_IssueInboundTask, "判断是人工发送的任务,单独给堆垛机发送任务完成信号,【成功】,设备号:" + deviceId + ",任务号:" + taskId); return true; } } catch (Exception ex) { Log4NetHelper.WriteErrorLog(iWareCommon.Utils.LogType.DataProcess_BZ39_IssueInboundTask, "判断是人工发送的任务,单独给堆垛机发送任务完成信号,【异常】,设备号:" + deviceId + ",任务号:" + taskId + ",ex:" + ex.Message, ex); throw ex; } } #region 向堆垛机发送任务完成确认信号 /// /// 向堆垛机发送任务完成确认信号 /// /// /// /// /// private bool ConfirmTaskFinishToSrm(Task_Part currentTask, string business, Base_SysExceptionInfo exception) { //任务完成处理成功,需要再给堆垛机发送任务完成确认信号 SdaResEntity sdaResult = new SdaResEntity(); var log = TaskRequestLogHandler.GetTask(currentTask.Id, (int)currentTask.DeviceId, currentTask.PlcTaskId, currentTask.RealSourcePlace.ToString(), currentTask.RealToPlace.ToString(), "给堆垛机发送任务完成确信指令", "sys"); try { if (MyExtendHelper.IsAllowSimulatorHandle(currentTask)) { sdaResult.result = true; } else { sdaResult = new SrmService.SrmServiceClient().ConfirmTaskFinish((int)currentTask.DeviceId, Convert.ToInt32(currentTask.PlcTaskId)); } if (!sdaResult.result) { TaskRequestLogHandler.InsertTask(base.currentLogType, RequestStatusEnum.请求失败, JsonConvert.SerializeObject(sdaResult), log, null); exception.exceptionMsg = string.Format(business + ",需要再给堆垛机发送任务完成确认信号失败,设备号{0} 任务号{1}", (int)currentTask.DeviceId, currentTask.PlcTaskId); SysExceptionInfoHandler.InsertExceptionInfo(exception, true); return false; } else { TaskRequestLogHandler.InsertTask(base.currentLogType, RequestStatusEnum.请求成功, JsonConvert.SerializeObject(sdaResult), log, null); Log4NetHelper.WriteInfoLog(base.currentLogType, string.Format(business + ",再给堆垛机发送任务完成确认信号成功,设备号{0} 任务号{1}", (int)currentTask.DeviceId, currentTask.PlcTaskId)); return true; } } catch (Exception ex) { TaskRequestLogHandler.InsertTask(base.currentLogType, RequestStatusEnum.请求失败, JsonConvert.SerializeObject(sdaResult), log, ex); throw ex; } } #endregion #endregion #endregion #region 公共处理 /// /// 验证RGV站点上是否允许下发堆垛机新任务 /// /// /// /// /// /// true:允许,false:不允许 private bool ValidateIsAllowNewTaskForRgvStattion(DbModel model, DeviceTaskTypeEnum _DeviceTaskTypeEnum, string realToPlace, ref string errMsg) { MainInOutFlagEnum _MainInOutFlagEnum = GetMainInOutFlagForSrm(_DeviceTaskTypeEnum); if (_MainInOutFlagEnum == MainInOutFlagEnum.出库) { //判断目标点是否有光电占用 var rgv_stationCode = model.Base_Station.Where(x => x.SrmStationCode == realToPlace).First(); var isGD_HasCatogryForRgvStattion = MyExtendHelper.IsGD_HasCatogryForRgvStattion(rgv_stationCode.RgvStationCode); if (isGD_HasCatogryForRgvStattion) { errMsg = "RGV出库口站点" + rgv_stationCode.RgvStationCode + "上面光电显示有货,不允许下发堆垛机的出库任务"; return false; } } return true; } /// /// 根据堆垛机任务类型判断出是出库还是入库 /// /// /// private MainInOutFlagEnum GetMainInOutFlagForSrm(DeviceTaskTypeEnum _DeviceTaskTypeEnum) { switch (_DeviceTaskTypeEnum) { case DeviceTaskTypeEnum.组盘入库: case DeviceTaskTypeEnum.空托转运到立体库: return MainInOutFlagEnum.入库; case DeviceTaskTypeEnum.立库空托到拆盘机入口: case DeviceTaskTypeEnum.出库: return MainInOutFlagEnum.出库; } throw new Exception("堆垛机不支持的任务类型" + _DeviceTaskTypeEnum.ToString()); } /// /// 更新主任务的状态 /// /// /// /// /// private void UpdateMainTaskStatus(DbModel edm, int mainTaskId, int srmTaskTypeValue, string remark) { DeviceTaskTypeEnum srmTaskTypeEnum = (DeviceTaskTypeEnum)Enum.Parse(typeof(DeviceTaskTypeEnum), srmTaskTypeValue.ToString()); MainTaskStatusEnum changeTaskStatus = default(MainTaskStatusEnum); switch (srmTaskTypeEnum) { case DeviceTaskTypeEnum.组盘入库: case DeviceTaskTypeEnum.空托转运到立体库: changeTaskStatus = MainTaskStatusEnum.已完成; MainTaskHandler.UpdateTaskStatus(edm, mainTaskId, changeTaskStatus, remark); break; } } /// /// 堆垛机任务完成后修改任务状态 /// /// private void ChangeTaskStateWhenTaskFinish(Task_Part currentTask) { //堆垛机完成了当前任务后进行任务状态的修改 currentTask.FinishTime = DateTime.Now;//完成时间 currentTask.IsFinished = true; currentTask.TaskState = (int)DeviceTaskStatusEnum.已完成; currentTask.TaskStateName = DeviceTaskStatusEnum.已完成.ToString(); currentTask.OperationRemark = "已完成"; currentTask.ModifyTime = DateTime.Now; currentTask.ModifyBy = SysGloble.WCSSystem; //currentTask.IsLastTask = (int)EYesOrNo.否;//设置不是最新的任务 } /// /// 堆垛机任务完成后,根据堆垛机的任务类型去判断Base_Salver_V_Station 的State /// /// 堆垛机任务类型 /// 原先的Base_Salver_V_Station 的State /// private Salver_V_Station_StateEnum DeviceTaskTypeEnumToC_V_P_StateEnumWhenTaskFinish(DeviceTaskTypeEnum _DeviceTaskTypeEnum, int old_int_C_V_P_StateEnum) { Salver_V_Station_StateEnum old_C_V_P_StateEnum = (Salver_V_Station_StateEnum)Enum.Parse(typeof(Salver_V_Station_StateEnum), old_int_C_V_P_StateEnum.ToString()); Salver_V_Station_StateEnum _C_V_P_StateEnum = old_C_V_P_StateEnum; switch (_DeviceTaskTypeEnum) { case DeviceTaskTypeEnum.组盘入库: _C_V_P_StateEnum = Salver_V_Station_StateEnum.在库物料; break; //case DeviceTaskTypeEnum22.线下其他垛入库: // _C_V_P_StateEnum = C_V_P_StateEnum.在库其他料; // break; //case DeviceTaskTypeEnum22.线下垫板垛入库: // _C_V_P_StateEnum = C_V_P_StateEnum.在库垫板; // break; //case DeviceTaskTypeEnum22.成品料配板完成回库: // _C_V_P_StateEnum = C_V_P_StateEnum.在库成品料; // break; //case DeviceTaskTypeEnum22.待拆垛回库: // _C_V_P_StateEnum = C_V_P_StateEnum.在库待拆垛; // break; //case DeviceTaskTypeEnum22.桁架垫板垛入立库垫板库位: //case DeviceTaskTypeEnum22.锯切垫板垛入立体库: // _C_V_P_StateEnum = C_V_P_StateEnum.在库垫板; // break; //case DeviceTaskTypeEnum22.移库://移库,状态不变 //case DeviceTaskTypeEnum22.成品料上锯切线出库://成品料出库,状态不变 //case DeviceTaskTypeEnum22.垫板上料出库://垫板出库,状态不变 // _C_V_P_StateEnum = old_C_V_P_StateEnum; // break; //case DeviceTaskTypeEnum22.配板原料出库: // _C_V_P_StateEnum = C_V_P_StateEnum.原料配板中; // break; //case DeviceTaskTypeEnum22.人工出库://出库后会将表Base_Salver_V_Station 清掉 // break; } return _C_V_P_StateEnum; } public override bool ValidateDeviceIsAllowSendTask(int int_deviceId, out string errMsg) { errMsg = ""; if (!base.ValidateDeviceIsAllowSendTask(int_deviceId, out errMsg)) { return false; } if (FormCC.IsSimulationPLC) { return true; } using (var srmService = new SrmService.SrmServiceClient()) { SdaResEntity sdaResult = srmService.IsAllowSendTask(int_deviceId, out errMsg); if (sdaResult.result == false) { errMsg = "非自动、有任务未确认或有报警," + sdaResult.resMsg; Log4NetHelper.WriteErrorLog(currentLogType, "验证堆垛机不可以下发新任务,int_deviceId:" + int_deviceId + ",sdaResultStr:" + JsonConvert.SerializeObject(sdaResult)); } return sdaResult.result; } } /// /// 验证堆垛机是否自动 /// /// /// public override bool ValidateDeviceIsOK(int int_deviceId, Task_Part _task, int taskId, out string errMsg) { errMsg = ""; if (Wms_EquipmentSituationHandler.IsEquipmentBreakdown(int_deviceId).result) {//如果设备已经设定为 故障状态,不允许下发任务!!! [EditBy shaocx,2020-12-07] errMsg = "设备被设为故障"; return false; } if (MyExtendHelper.IsAllowSimulatorHandle(_task)) { errMsg = "模拟PLC"; return true; } using (var srmService = new SrmService.SrmServiceClient()) { SdaResEntity sdaResult = srmService.IsReady(int_deviceId, out errMsg); errMsg = sdaResult.resMsg; return sdaResult.result; } } /// /// 验证堆垛机是否任务完成 /// /// /// public override bool ValidateDeviceTaskIsFinsished(int int_deviceId, Task_Part _task, int taskId, out string errMsg) { errMsg = ""; if (MyExtendHelper.IsAllowSimulatorHandle(_task)) {//模拟代码!发布时移除该代码 errMsg = "任务要求强制模拟完成"; return true; } SdaResEntity sdaResult = new SrmService.SrmServiceClient().IsTaskFinish(int_deviceId, taskId); if (sdaResult.result == false) { errMsg = sdaResult.resMsg; } return sdaResult.result; } /// /// 验证堆垛机是否任务完成 /// /// /// private bool ValidateDeviceTaskIsFinsished(int int_deviceId, Task_Part _task, int taskId, DeviceTaskTypeEnum _DeviceTaskTypeEnum, bool? isAllowSimulateExecute, out string errMsg) { errMsg = ""; if (MyExtendHelper.IsAllowSimulatorHandle(_task)) { errMsg = "模拟PLC完成或任务要求强制模拟完成"; return true; } SdaResEntity sdaResult = new SrmService.SrmServiceClient().IsTaskFinish(int_deviceId, taskId); if (sdaResult.result == false) { errMsg = "验证堆垛机是否任务完成 失败:" + JsonConvert.SerializeObject(sdaResult); //Log4NetHelper.WriteErrorLog(currentLogType, "验证堆垛机是否任务完成 失败:" + JsonConvert.SerializeObject(sdaResult)); } switch (_DeviceTaskTypeEnum) { //涉及到最后到输送线的任务,都要再加上输送线的任务是否完成 case DeviceTaskTypeEnum.组盘入库: //using (var srmConveyorService = new SrmConveyorService.SrmConveyorServiceClient()) //{ // sdaResultStr = srmConveyorService.IsTaskFinish(taskId); // sdaResult = JsonConvert.DeserializeObject(sdaResultStr); // if (sdaResult.result == false) // { // errMsg = "验证输送线是否任务完成 失败:" + sdaResultStr; // Log4NetHelper.WriteErrorLog(currentLogType, "验证输送线是否任务完成 失败:" + sdaResultStr); // } //} break; } return sdaResult.result; } #endregion #region 私有方法 /// /// 验证数据库中是否有任务要处理 /// /// /// /// Rgv设备号 /// /// /// private List ValidateIsExistTaskToDisposeForIssued(DbModel dbModel, int int_deviceId, out string errMsg) { errMsg = ""; List partList = new List(); //看同一个设备,是否还有其他正在执行的任务! var partTask = dbModel.Task_Part.Where(x => x.DeviceId == int_deviceId && x.TaskState == (int)DeviceTaskStatusEnum.已下发). OrderBy(x => x.CreateTime).FirstOrDefault();//按照主任务的顺序升序 if (partTask != null) { errMsg = string.Format("deviceId={0}的正在执行任务,任务ID:" + partTask.Id + ",主任务:" + partTask.MainTaskNo + ",PLC任务号:" + partTask.PlcTaskId, int_deviceId); return null; } //1、查询 var currTaskList = dbModel.Task_Part.Where(x => x.DeviceId == int_deviceId && x.TaskState == (int)DeviceTaskStatusEnum.未开始).ToList().OrderBy(x => x.CreateTime).ToList();//按照主任务优先级的升序排序 if (currTaskList == null || currTaskList.Count == 0) { errMsg = "没有需要处理的任务"; return null; } var firstTask = currTaskList.First();//第一个待执行的任务 partList.Add(firstTask); //判断如果这个任务是出库任务的话,就再查询第一个待执行的入库任务 DeviceTaskTypeEnum _DeviceTaskTypeEnum = (DeviceTaskTypeEnum)Enum.Parse(typeof(DeviceTaskTypeEnum), firstTask.TaskType.ToString()); //查询 出库和入库的两个任务,优先执行出库任务 【EditBy shaocx,2022-05-09】 MainInOutFlagEnum _MainInOutFlagEnum = GetMainInOutFlagForSrm(_DeviceTaskTypeEnum); if (_MainInOutFlagEnum == MainInOutFlagEnum.出库) { //查询第一个待执行的入库任务 var queryInOutFlag = (int)MainInOutFlagEnum.入库; var fisrtTaskForIn = currTaskList.Where(x => x.InOutFlag == queryInOutFlag).ToList().OrderBy(x => x.CreateTime).FirstOrDefault(); if (fisrtTaskForIn != null) { partList.Add(fisrtTaskForIn); } } return partList; } #endregion } }