using Admin.Core.Common; using Admin.Core.IService; using Admin.Core.Model; using Admin.Core.Model.Model_New; using Admin.Core.Service; 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.Security.Cryptography.X509Certificates; 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 IOffLineInfoServices _offLineInfoServices; private readonly IRecordInStoreServices _recordInstoreServices; private readonly IBaseOrderInfoServices _baseOrderInfoServices; #endregion #region 构造函数 public InstoreBusiness() { _baseSpaceInfoServices = App.ServiceProvider.GetService(); _codeBindingServices = App.ServiceProvider.GetService(); _recordInstoreServices = App.ServiceProvider.GetService(); _offLineInfoServices = App.ServiceProvider.GetService(); _baseOrderInfoServices = App.ServiceProvider.GetService(); MvCodeHelper.RefreshPalletizDelegateEvent += 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("15100P000009E360795", "10.10.92.230"); }); } #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 = GetSpaceBySNCode2(SNCode, recordInstore);//2024 if (spaceList == null || spaceList.Count == 0) { logHelper.Error("未找到匹配货道,请手动入库!"); Console.WriteLine("未找到匹配货道,请手动入库!"); // 刷新页面提示信息 LogInStoreInfoDelegateEvent?.Invoke("未找到匹配货道,请手动入库!", "Red"); return; } Console.WriteLine($"上位机获取配置的货道数量【{spaceList.Count}】"); // 过滤货道,找到最终需要下发的货道 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, 1); // 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); int space =Convert.ToInt32(finalSpace.SpaceCode.Substring(finalSpace.SpaceCode.Length - 3, 3)); plcResult = SendAndAnswerPlc(scannerIp, finalSpace.RotationRange, space); UpdateSapceList(finalSpace.ObjId, finalSpace); Console.WriteLine("更新货道信息成功!"); LogInStoreInfoDelegateEvent?.Invoke("更新货道信息成功!", "White"); } else { spaceNumList.Add(0); spaceNumList.Add(int.Parse(finalSpace.SpaceCode.Substring(5, 3))); int space = Convert.ToInt32(finalSpace.SpaceCode.Substring(finalSpace.SpaceCode.Length - 3, 3)); plcResult = SendAndAnswerPlc(scannerIp, finalSpace.RotationRange, space);//给PLC下传入库信号 UpdateSapceList(finalSpace.ObjId, finalSpace); 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) { Console.WriteLine("成品下线库未有此成品下线记录!"); LogInStoreInfoDelegateEvent?.Invoke("成品下线库未有此成品下线记录!qin", "Red"); 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) { Console.WriteLine("成品下线库未有此成品下线记录!"); LogInStoreInfoDelegateEvent?.Invoke("成品下线库未有此成品下线记录!qin", "Red"); logHelper.Error(ex.Message.ToString()); Console.WriteLine(ex.Message.ToString()); return null; } } /// /// 根据成品码找货道_临时 2024-03-11 /// /// /// private List GetSpaceBySNCode2(string SNCode, RecordInStore recordInstore) { try { OffLineInfo record = _offLineInfoServices.FirstAsync(c => c.ProductSNCode.Equals(SNCode)).Result; if (record == null) { Console.WriteLine("成品下线库未有此成品下线记录!"); return null; } Console.WriteLine(record.ProductOrderNo); BaseOrderInfo baseOrderInfo =_baseOrderInfoServices.FirstAsync(d=>"0000"+d.OrderCode== record.ProductOrderNo).Result ; recordInstore.BarCodeCode = record.BoxCode; recordInstore.MaterialCode = baseOrderInfo.MaterialCode; recordInstore.MaterialType = baseOrderInfo.MaterialCode; recordInstore.MaterialName = baseOrderInfo.MaterialName; string mType = baseOrderInfo.MaterialCode; List bsInfo = _baseSpaceInfoServices.Query(s => (s.MaterialType.Equals(mType) && (s.StoreCode.Equals(storeCodeA)))); if (bsInfo.Count > 0) return bsInfo.OrderBy(x => x.ObjId).ToList(); else return null; } catch (Exception ex) { Console.WriteLine("成品下线库未有此成品下线记录!"); //LogInStoreInfoDelegateEvent?.Invoke("成品下线库查询成品下线记录异常!请联系当班负责人处理", "Red"); logHelper.Error(ex.Message.ToString()); Console.WriteLine($"成品下线库未有此成品下线记录!{ex.Message.ToString()}"); return null; } } #endregion private BaseSpaceInfo FilterSpace(List spaceInfos) { if (spaceInfos == null|| spaceInfos.Count==0) return null; List baseSpaceInfoList = spaceInfos.OrderBy(d => d.UpdatedTime).ToList(); BaseSpaceInfo spaceInfo = baseSpaceInfoList.First(); if (spaceInfo!=null || string.IsNullOrEmpty(spaceInfo.LastSpace)) { return spaceInfo; } return null; } /// /// 大产品占据两条货道,根据一条货道找到另一条货道 /// /// 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, BaseSpaceInfo spaceList) { //foreach (BaseSpaceInfo space in spaceList) //{ // space.LastSpace = objId.ToString(); // space.UpdatedTime =DateTime.Now; //} spaceList.LastSpace = objId.ToString(); spaceList.UpdatedTime = DateTime.Now; return _baseSpaceInfoServices.UpdateAsync(spaceList).Result; } #endregion #region plc信号下发 #region 下发plc入库信号 /// /// 下发plc入库信号 /// /// 扫码器ip /// 转向角度 /// 货道号 /// private bool SendAndAnswerPlc(string scannerIp, int range,int spaceNum) { bool result = false; try { PlcModel obj = GetPlcByScanner(scannerIp); if (obj != null&& obj.plc.IsConnected) { if (SendPlc(obj, range, spaceNum)) { return true; } } 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,int spaceNum) { try { bool result = false; DateTime targetTime = DateTime.Now.AddSeconds(8); int i= 0; while (i<3) { if (obj.plc.IsConnected) { Console.WriteLine($"是否可以下发:【{obj.plc.ReadBool("B1000")}】"); if (obj.plc.ReadBool("B1000"))//如果为true 则可以下发 任务 { // 应答字允许下发 int storeNum = GetStoreNum(obj, spaceNum); Console.WriteLine($"读取当前货道数量:【{storeNum}】"); //if (storeNum == 1) { //obj.plc.WriteInt16("D7010", range.ToString());//旋转角度1=》90 2=>反转90 D2 1正转 2反转 //obj.plc.WriteInt16("D29", spaceNum.ToString()); //货道号 //obj.plc.WriteInt16("B1001", "1");//发送完成信号 obj.plc.WriteInt16("D29", spaceNum.ToString());//货道号 if (range==0) { range = 3; } if (range == 90) { range = 1; } if (range == -90) { range = 2; } if (range == -180) { range = 4; } obj.plc.WriteInt16("D2", range.ToString());//角度 1正转90 2反转90 3不转 4 反转180 obj.plc.WriteInt16("B1001", "1");//发送完成信号 Console.WriteLine($"plc信号货道信号下发成功!【货道号:{spaceNum}"); result = true; break; } } } else { Console.WriteLine($"plc未连接"); } Thread.Sleep(100); i++; } return result; } catch (Exception ex) { logHelper.Error(ex.Message); return false; } } public int GetStoreNum(PlcModel obj, int spaceNum) { int storeNum = 0; switch (spaceNum) { case 1: storeNum = obj.plc.ReadInt16("D1001"); break; case 2: storeNum = obj.plc.ReadInt16("D1002"); break; case 3: storeNum = obj.plc.ReadInt16("D1003"); break; case 4: storeNum = obj.plc.ReadInt16("D1004"); break; case 5: storeNum = obj.plc.ReadInt16("D1005"); break; case 6: storeNum = obj.plc.ReadInt16("D1006"); break; case 7: storeNum = obj.plc.ReadInt16("D1007"); break; case 8: storeNum = obj.plc.ReadInt16("D1008"); break; case 9: storeNum = obj.plc.ReadInt16("D1009"); break; case 10: storeNum = obj.plc.ReadInt16("D1010"); break; case 11: storeNum = obj.plc.ReadInt16("D1011"); break; case 12: storeNum = obj.plc.ReadInt16("D1012"); break; case 13: storeNum = obj.plc.ReadInt16("D1013"); break; case 14: storeNum = obj.plc.ReadInt16("D1014"); break; default: break; } return storeNum; } #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")); //} PlcModel obj = PlcHelper.melsecList.FirstOrDefault(d => d.EquipName.Equals("InStoreAPlc")); 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());//写入货道 } 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 true; } else { LogInStoreInfoDelegateEvent?.Invoke("PLC未连接!", "Red"); return false; } //更新货道 } #endregion #region 人工操作入库 /// /// 临时写入入库 /// /// 货道号 /// 转向: 1正转 2反转,3不转 /// public static bool TempWritePlc(int freightLaneNumber, int range) { try { var obj = PlcHelper.melsecList.FirstOrDefault(d => d.EquipName.Equals("InStoreAPlc")); //写入PLC bool flag = true; do { if (obj == null) { return false; } if (obj.plc.IsConnected) { bool isDown = false; int i = 0; do { isDown = obj.plc.ReadBool("B1000"); if (isDown) { Console.WriteLine($"[{DateTime.Now}] 当前下发信号为:{isDown}"); LogInStoreInfoDelegateEvent?.Invoke($"[{DateTime.Now}] 当前下发信号为:{isDown}", "White"); break; } else { Console.WriteLine($"[{DateTime.Now}] 当前下发信号为:{isDown},不可以下发"); LogInStoreInfoDelegateEvent?.Invoke($"[{DateTime.Now}] 当前下发信号为:{isDown}", "Red"); } Console.WriteLine($"[{DateTime.Now}] 当前下发信号为:{isDown}"); Thread.Sleep(1000); i++; } while (i < 3); if (isDown == false) { Console.WriteLine($"[{DateTime.Now}] 下发失败,当前下发信号为:{isDown},请稍等后重试!"); LogInStoreInfoDelegateEvent?.Invoke($"[{DateTime.Now}] 下发失败,当前下发信号为:{isDown},请稍等后重试!", "Red"); return false; } LogInStoreInfoDelegateEvent?.Invoke($"[{DateTime.Now}] 开始下发PLC》货道号:{freightLaneNumber}》角度(1正转 2反转 3不转):{range}", "Red"); Console.WriteLine($"[{DateTime.Now}] 开始下发PLC》货道号:{freightLaneNumber}》角度(1正转 2反转 3不转):{range}"); if (isDown) { obj.plc.WriteInt16("D29", freightLaneNumber.ToString());//货道号 obj.plc.WriteInt16("D2", range.ToString());//角度 1正转90 2反转90 3不转 4 反转180 obj.plc.WriteInt16("B1001", "1");//发送完成信号 Console.WriteLine($"[{DateTime.Now}] 下发PLC成功"); LogInStoreInfoDelegateEvent?.Invoke($"[{DateTime.Now}] 下发PLC成功", "Red"); //将手动信息保存到库中,设置000000000未手动设置的成品码 Thread.Sleep(1000); isDown = obj.plc.ReadBool("B1000"); if (isDown) { Console.WriteLine($"[{DateTime.Now}] 当前下发信号为:{isDown}"); } else { Console.WriteLine($"[{DateTime.Now}] 当前下发信号为:{isDown}"); } return true; } flag = false; } else { flag = true; } } while (flag); return true; } catch (Exception ex) { Console.WriteLine($"[{DateTime.Now}] 手动下发任务异常:{ex.Message}"); LogInStoreInfoDelegateEvent?.Invoke($"[{DateTime.Now}] 手动下发任务异常:{ex.Message}", "Red"); return false; } } #endregion public bool WriteIF(PlcModel obj, string space) { bool flag = true; switch (space) { case "FD01_001": flag = obj.plc.ReadBool("D1001"); break; case "FD01_002": flag = obj.plc.ReadBool("D1001"); break; case "FD01_003": flag = obj.plc.ReadBool("D1001"); break; case "FD01_004": flag = obj.plc.ReadBool("D1001"); break; case "FD01_005": flag = obj.plc.ReadBool("D1001"); break; case "FD01_006": flag = obj.plc.ReadBool("D1001"); break; case "FD01_007": flag = obj.plc.ReadBool("D1001"); break; case "FD01_008": flag = obj.plc.ReadBool("D1001"); break; case "FD01_009": flag = obj.plc.ReadBool("D1001"); break; case "FD01_010": flag = obj.plc.ReadBool("D1001"); break; case "FD01_011": flag = obj.plc.ReadBool("D1001"); break; case "FD01_012": flag = obj.plc.ReadBool("D1001"); break; case "FD01_013": flag = obj.plc.ReadBool("D1001"); break; case "FD01_014": flag = obj.plc.ReadBool("D1001"); break; default: break; } return flag; } } }