using Admin.Core.Common; using Admin.Core.IService; using Admin.Core.Model; using Aucma.Core.HwPLc; using Aucma.Core.Scanner; using log4net; using Microsoft.Extensions.DependencyInjection; using StackExchange.Profiling.Internal; using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace Aucma.Core.Palletiz.Business { /// ///分垛入库业务处理 /// public class InstoreBusiness { #region 单例实现 private static readonly InstoreBusiness lazy = new InstoreBusiness(); public static InstoreBusiness Instance { get { return lazy; } } #endregion #region 初始化对象 private static readonly log4net.ILog logHelper = LogManager.GetLogger(typeof(InstoreBusiness)); private readonly IBaseSpaceInfoServices? _baseSpaceInfoServices; private readonly ICodeBindingRecordServices? _codeBindingServices; private readonly IRecordInStoreServices? _recordInstoreServices; #endregion #region 构造函数 public InstoreBusiness() { _baseSpaceInfoServices = App.ServiceProvider.GetService(); _codeBindingServices = App.ServiceProvider.GetService(); _recordInstoreServices = App.ServiceProvider.GetService(); MvCodeHelper.HandlePalletizDelegateEvent += ScannerInStore;//注册扫码器扫码后业务处理事件 } #endregion #region 变量定义 public readonly List allScanners = Appsettings.app("ScannerServer").ToList(); public readonly string storeCodeA = Appsettings.app("StoreInfo", "PalletizStoreCodeA");//分垛库A public readonly string storeCodeB = Appsettings.app("StoreInfo", "PalletizStoreCodeB");//分垛库B private static bool flagA = true; private static bool flagB = true; #endregion #region 事件 #region 更新提醒信息 /// /// 日志事件 /// public delegate void LogInStoreInfoDelegate(string message, string color); public static event LogInStoreInfoDelegate LogInStoreInfoDelegateEvent; #endregion #region 更新扫码信息 /// /// 刷新扫码信息——图表和表格 /// public delegate void ResherStoreInfoDelegate(); public static event ResherStoreInfoDelegate ResherStoreInfoDelegateEvent; #endregion #endregion #region Test [Obsolete("正式环境下使用ScannerInStore(string SNCode,string IP)")] public void test() { // B240101 8302501416 0001 SN:16160030000000910999 Task.Run(async () => { Thread.Sleep(3000); await InStore("16160030000000910999", "192.168.1.19"); }); } #endregion #region 扫码入库 /// /// 扫码入库 /// /// 成品码 /// 扫码器IP public void ScannerInStore(string SNCode,string IP) { Task.Run(async () => { Thread.Sleep(3000); await InStore(SNCode, IP); }); } #endregion #region 扫码入库处理 /// /// 扫码入库处理 /// /// 成品码 /// 扫码器ip /// public async Task InStore(string SNCode, string scannerIp) { Console.WriteLine($"上位机接收到扫码器传入的成品码:{SNCode};扫码器IP:{scannerIp}"); LogInStoreInfoDelegateEvent?.Invoke($"上位机接收到扫码器传入的成品码:{SNCode};扫码器IP:{scannerIp}","White"); bool plcResult = false;// plc下发结果 List spaceNumList = new List();// 下发plc的货道号 RecordInStore recordInstore = new RecordInStore();// 入库记录 try { // 刷新页面 List allScanners = Appsettings.app("ScannerServer").ToList(); ScannerModel model = allScanners.First(x => x.Ip == scannerIp); Console.WriteLine($"上位机获取配置的扫码器【IP:{model.ToJson()}》名称:{model.Name}】"); LogInStoreInfoDelegateEvent?.Invoke($"上位机获取配置的扫码器【IP:{model.ToJson()}》名称:{model.Name}】","White"); //1.根据成品码找货道 List? spaceList = GetSpaceBySNCode(SNCode, recordInstore); Console.WriteLine($"上位机获取配置的货道数量【{spaceList.Count}】"); // 根据货道信息判断下发plc信号 if (spaceList == null || spaceList.Count == 0) { logHelper.Error("未找到匹配货道,请手动入库!"); // 刷新页面提示信息 Console.WriteLine("未找到匹配货道,请手动入库!"); LogInStoreInfoDelegateEvent?.Invoke("未找到匹配货道,请手动入库!", "White"); return; } // 过滤货道,找到最终需要下发的货道 BaseSpaceInfo finalSpace = FilterSpace(spaceList); Console.WriteLine($"上位机获取需要下发的货道【货道名称:{finalSpace.SpaceName}》货道库存:{finalSpace.SpaceStock}》货道状态:{finalSpace.SpaceStatus}》货道类型:{finalSpace.SpaceType}》所属仓库:{finalSpace.StoreCode}】"); LogInStoreInfoDelegateEvent?.Invoke($"是否为大产品:【{finalSpace.IsTwoSpace}】", "White"); Console.WriteLine($"是否为大产品:【{finalSpace.IsTwoSpace}】"); LogInStoreInfoDelegateEvent?.Invoke($"下发的货道:【货道名称:{finalSpace.SpaceName}", "White"); // 大产品占两道 if (finalSpace.IsTwoSpace == 1) { spaceNumList.Add(int.Parse(finalSpace.SpaceCode.Substring(5, 3))); spaceNumList.Add(int.Parse(GetOtherSpace(finalSpace, spaceList).SpaceCode.Substring(5, 3))); plcResult = SendAndAnswerPlc(scannerIp, spaceList[0].RotationRange, spaceNumList); recordInstore.SpaceCode = finalSpace.SpaceCode; recordInstore.StoreCode = finalSpace.StoreCode; // 更新货道信息,大产品last存objId大的,储存上一个货道的主键 如货道7,8存8 BaseSpaceInfo otherSpace = GetOtherSpace(finalSpace, spaceList); Console.WriteLine($"大产品入库信息:【{finalSpace.ToJson()}】【{spaceList.ToJson()}】"); if (otherSpace != null) { UpdateSapceList(otherSpace.ObjId, spaceList); Console.WriteLine("更新货道信息成功!"); LogInStoreInfoDelegateEvent?.Invoke("更新货道信息成功!", "White"); } } else { // last不等于自己,可以先入自己,否则入另一条货道 if (IsOddNumber(finalSpace)) { spaceNumList.Add(int.Parse(finalSpace.SpaceCode.Substring(5, 3))); spaceNumList.Add(0); plcResult = SendAndAnswerPlc(scannerIp, finalSpace.RotationRange, spaceNumList); UpdateSapceList(finalSpace.ObjId, spaceList); Console.WriteLine("更新货道信息成功!"); LogInStoreInfoDelegateEvent?.Invoke("更新货道信息成功!", "White"); } else { spaceNumList.Add(0); spaceNumList.Add(int.Parse(finalSpace.SpaceCode.Substring(5, 3))); plcResult = SendAndAnswerPlc(scannerIp, finalSpace.RotationRange, spaceNumList);//给PLC下传入库信号 UpdateSapceList(finalSpace.ObjId, spaceList); Console.WriteLine("更新货道信息成功!"); LogInStoreInfoDelegateEvent?.Invoke("更新货道信息成功!", "White"); } } if (plcResult == true) { // 更新入库记录,刷新界面 #region 添加入库记录 recordInstore.SpaceCode = finalSpace.SpaceCode; recordInstore.StoreCode = finalSpace.StoreCode; recordInstore.InStoreAmount = 1; recordInstore.InStoreTime = DateTime.Now; recordInstore.CreatedTime = DateTime.Now; recordInstore.UpdateTime = DateTime.Now; await _recordInstoreServices.AddAsync(recordInstore); #endregion } else { // 界面提示手动入库 LogInStoreInfoDelegateEvent?.Invoke("界面提示手动入库!", "Red"); } } catch (Exception ex) { logHelper.Error(ex.Message.ToString()); return; } } #region 根据成品码找货道 /// /// 根据成品码找货道 /// /// /// private List? GetSpaceBySNCode(string SNCode, RecordInStore recordInstore) { try { CodeBindingRecord bindingRecord = _codeBindingServices.FirstAsync(c => c.ProductCode.Equals(SNCode)).Result; if (bindingRecord == null) return null; recordInstore.BarCodeCode = bindingRecord.BoxCode; recordInstore.MaterialCode = bindingRecord.BoxCode; recordInstore.MaterialType = bindingRecord.BoxCode.Substring(7, 10); recordInstore.MaterialName = bindingRecord.BoxName; string mType = bindingRecord.BoxCode.Substring(7, 10); List bsInfo = _baseSpaceInfoServices.Query(s => (s.MaterialType.Equals(mType) && (s.StoreCode.Equals(storeCodeA)) || s.StoreCode.Equals(storeCodeB))); if (bsInfo.Count > 0) return bsInfo.OrderBy(x => x.ObjId).ToList(); else return null; } catch (Exception ex) { logHelper.Error(ex.Message.ToString()); Console.WriteLine(ex.Message.ToString()); return null; } } #endregion private BaseSpaceInfo FilterSpace(List spaceInfos) { BaseSpaceInfo spaceInfo = spaceInfos.First(); if (spaceInfos.Count == 1 || string.IsNullOrEmpty(spaceInfo.LastSpace)) { return spaceInfo; } List spaceList = spaceInfos.Where(s => s.ObjId > int.Parse(spaceInfo.LastSpace)).ToList(); if (spaceList == null || spaceList.Count == 0) { return spaceInfo; } else { return spaceInfo; } } /// /// 大产品占据两条货道,根据一条货道找到另一条货道 /// /// private BaseSpaceInfo GetOtherSpace(BaseSpaceInfo spaceInfo, List spaceList) { try { // 找到当前货道匹配的另一条货道 int num = int.Parse(spaceInfo.SpaceCode.Substring(5, 3)); string otherSpaceCode = string.Empty; if (num % 2 == 0) // 偶数,如7,8,当前8找7 { otherSpaceCode = spaceInfo.SpaceCode.Substring(0, 5) + (num - 1).ToString("D3"); } else { otherSpaceCode = spaceInfo.SpaceCode.Substring(0, 5) + (num + 1).ToString("D3"); } spaceList = spaceList.Where(s => s.SpaceCode.Equals(otherSpaceCode)).ToList(); if (spaceList.Count > 0) { return spaceList[0]; } else { return null; } } catch (Exception ex) { logHelper.Error(ex.Message.ToString()); Console.WriteLine($"大产品根据一条货道找到另一条货道异常:{ex.Message}"); return null; } } /// /// 判断货道编号是否为奇数 /// /// /// private bool IsOddNumber(BaseSpaceInfo space) { int num = int.Parse(space.SpaceCode.Substring(5, 3)); if (num % 2 == 0) { return false; } else { return true; } } /// /// 将该物料的所有货道列表的last修改为上次入库货道objId /// /// /// /// private bool UpdateSapceList(int objId, List spaceList) { foreach (BaseSpaceInfo space in spaceList) { space.LastSpace = objId.ToString(); } return _baseSpaceInfoServices.UpdateAsync(spaceList).Result; } #endregion #region plc信号下发 #region 下发plc入库信号 /// /// 下发plc入库信号 /// /// 扫码器ip /// 转向角度 /// 货道号int集合 /// private bool SendAndAnswerPlc(string scannerIp, int range, List spaceNum) { bool result = false; try { PlcModel obj = GetPlcByScanner(scannerIp); if (obj != null) { if (SendPlc(obj, range, spaceNum)) { result = WaitAnswerPlc(obj); } } else { logHelper.Error("plc未连接"); return false; } return result; } catch (Exception ex) { logHelper.Error(ex.Message.ToString()); return result; } } #endregion #region 下发plc信号 /// /// 下发plc信号 /// /// /// /// /// private bool SendPlc(PlcModel obj, int range, List spaceNum) { try { bool result = false; DateTime targetTime = DateTime.Now.AddSeconds(8); while (true) { if (DateTime.Now > targetTime) // plc超最大时限无反馈 { logHelper.Error("等待plc放行反馈信号超时"); Console.WriteLine("等待plc放行反馈信号超时"); return false; } // 应答字允许下发 Console.WriteLine($"读取应答字是否下传成功!【{obj.plc.ReadInt32("D102")}】"); if (obj.plc.ReadInt32("D102") == 1) { //obj.plc.WriteInt32("D110", range);//旋转角度暂时不赋值由PLC转向 obj.plc.WriteInt32("D112", spaceNum[0]); //货道号 obj.plc.WriteInt32("D114", spaceNum[1]); //货道号 Console.WriteLine($"plc信号货道信号下发成功!【D112:{spaceNum[0]}】D114:{spaceNum[1]}"); result = true; break; } Thread.Sleep(500); } return result; } catch (Exception ex) { logHelper.Error(ex.Message); return false; } } #endregion #region 等待plc信号反馈 /// /// 等待plc信号反馈 /// /// /// private bool WaitAnswerPlc(PlcModel obj) { try { bool result = false; DateTime targetTime = DateTime.Now.AddSeconds(8); while (true) { if (DateTime.Now > targetTime) // plc超最大时限无反馈 { logHelper.Error("等待plc放行反馈信号超时"); Console.WriteLine("等待plc放行反馈信号超时"); return false; } // 应答字允许下发 if (obj.plc.ReadInt32("D102") == 2) { result = true; Console.WriteLine("下发成功!"); break; } Thread.Sleep(500); } return result; } catch (Exception ex) { logHelper.Error(ex.Message.ToString()); return false; } } #endregion #region 根据扫码器ip确定是属于哪个plc /// /// 根据扫码器ip确定是属于哪个plc /// /// /// private PlcModel GetPlcByScanner(string scannerIp) { PlcModel obj = null; ScannerModel model = allScanners.FirstOrDefault(x => x.Ip == scannerIp); if (model.Id < 3) { obj = PlcHelper.melsecList.FirstOrDefault(d => d.EquipName.Equals("InStoreAPlc")); } else { obj = PlcHelper.melsecList.FirstOrDefault(d => d.EquipName.Equals("InStoreBPlc")); } return obj; } #endregion #endregion #region 手动写入货道号给PLC数据 /// /// 手动写入PLC数据 /// /// public static bool WritePlc(Models.StackInfoModel tempStackInfo) { var obj = PlcHelper.melsecList.FirstOrDefault(d => d.EquipName.Equals("InStorePlc")); //写入PLC if (obj.plc.IsConnected) { //1、判断是否为大产品、占用两个货道 上位机两条道设置为相同型号 if (tempStackInfo.IsLargeProducts) { obj.plc.WriteInt16("D7000", tempStackInfo.BinNo.ToString());//写入货道 obj.plc.WriteInt16("D7100", tempStackInfo.BinNo.ToString());//写入货道 } else { //判断入库货道 if (tempStackInfo.BinNo / 2 == 0) { obj.plc.WriteInt16("D7000", tempStackInfo.BinNo.ToString());//写入货道 obj.plc.WriteInt16("D7100", "0");//写入货道 } else { obj.plc.WriteInt16("D7000", "0");//写入货道 obj.plc.WriteInt16("D7100", tempStackInfo.BinNo.ToString());//写入货道 } } obj.plc.WriteInt16("D7020", "1");//同时写入应答字 Console.WriteLine("手动写入PLC成功!"); do { #region 1号区域码垛——A int responseWord1 = obj.plc.ReadInt16("D7020");//读取1号区域码垛 等待应答字回去 Console.WriteLine($"获取应答信号:{responseWord1}"); if (responseWord1 == 2) { //清空货道 obj.plc.WriteInt16("D7000", "0"); obj.plc.WriteInt16("D7100", "0"); flagA = false; } #endregion } while (flagA); } //更新货道 return false; } private static void GetResposeB() { var obj = PlcHelper.melsecList.FirstOrDefault(d => d.EquipName.Equals("InStorePlc")); //写入PLC if (obj.plc.IsConnected) { do { #region 2号区域码垛——B int responseWord2 = obj.plc.ReadInt16("D7120");//读取1号区域码垛 等待应答字回去 Console.WriteLine("手动写入PLC成功!"); if (responseWord2 == 2) { obj.plc.WriteInt16("D7000", "0");//清空 } #endregion } while (flagA); } } #endregion } }