using CommunityToolkit.Mvvm.ComponentModel; using System; using System.Collections.ObjectModel; using log4net; using Aucma.Core.CodeBinding.Common; using LiveCharts; using Admin.Core.Model; using Admin.Core.Service; using LiveCharts.Wpf; using Admin.Core.IService; using Microsoft.Extensions.DependencyInjection; using System.Threading.Tasks; using System.Windows.Controls; using System.Collections; using Aucma.Core.CodeBinding.Models; using System.Reflection.Emit; using NPOI.SS.Formula.Functions; using System.Threading; using System.Windows.Threading; using static Admin.Core.Service.CodeBindingRecordServices; using System.Windows.Data; using System.Windows; using System.Linq; using System.Collections.Generic; using NPOI.HSSF.Record; using SqlSugar; using Microsoft.AspNetCore.Mvc.ModelBinding; using Admin.Core.Model.ViewModels; using System.Windows.Media; using System.Drawing; using Brushes = System.Windows.Media.Brushes; using Admin.Core.Model.Model_New; using Microsoft.IdentityModel.Logging; using static Npgsql.Replication.PgOutput.Messages.RelationMessage; using Aucma.Core.HwPLc; using System.Windows.Documents; using Admin.Core.Common; using Aucma.Core.CodeBinding.Business; using Aucma.Core.Scanner; using LiveCharts.Defaults; using Admin.Core.Socket; using System.Runtime.ConstrainedExecution; /* * 首页信息 */ namespace Aucma.Core.CodeBinding.ViewModels { public partial class IndexPageViewModel : ObservableObject { private static readonly log4net.ILog log = LogManager.GetLogger(typeof(IndexPageViewModel)); private readonly ICodeBindingRecordServices? _codeBindingRecordServices; private readonly IBaseMaterialInfoServices? _baseMaterialInfoServices; private readonly IBaseBomInfoServices? _baseBomInfoServices; private readonly IPrintBarCodeServices? _printBarCodeServices; // 过点数据表,物料完成记录MaterialCompletion private readonly IMaterialCompletionServices? _iMaterialCompletionServices; // 静态变量存code1,mes条码 private static string code1Str = string.Empty; // 静态变量存code2,SN条码 private static string code2Str = string.Empty; //配置文件扫码器列表 private static List allScanners = Appsettings.app("ScannerServer").ToList(); // mes扫码器ip private static string MesScannerIp = allScanners.First(x => x.Name == "mes扫码器").Ip; // sn扫码器ip private static string SnScannerIp = allScanners.First(x => x.Name == "sn扫码器").Ip; private SpeechStr speechStr = SpeechStr.Instance; private string ProductLineCode = Appsettings.app("StationInfo", "ProductLineCode"); // 质检记录 private readonly IReportQualityInspectionServices? _reportQualityInspectionServices; //异常记录,记录质检失败情况 private readonly IExceptionRecordServices? exceptionRecordServices; public IndexPageViewModel() { try { _codeBindingRecordServices = App.ServiceProvider.GetService(); _baseBomInfoServices = App.ServiceProvider.GetService(); _baseMaterialInfoServices = App.ServiceProvider.GetService(); _reportQualityInspectionServices = App.ServiceProvider.GetService(); _printBarCodeServices = App.ServiceProvider.GetService(); _iMaterialCompletionServices = App.ServiceProvider.GetService(); exceptionRecordServices = App.ServiceProvider.GetService(); // Business.MvCodeHelper.ReceiveCodeEvent += ReceiveCode; // Business.MvCodeHelper.BindingCodeEvent += BindingCode; // Business.MvCodeHelper.NoReadEvent += ReceiveNoRead; TouchSocketService.ReceiveCodeDelegateEvent += ReceiveCode; TouchSocketService.NoReadReceiveEvent += ReceiveNoRead; GunBusiness.BindingReceiveCodeEvent += BindingCode; GunBusiness.RefreshMaterialCodeStrEvent += ReceiveCode; MsgUIColor = "White"; LoadData(); //实时绑定条码和实时下发plc放行信号 realBindingAndSendPlc(); LoadCharts(); } catch (Exception ex) { log.Error(ex); } } /// /// 实时绑定条码和实时下发plc放行信号 /// public void realBindingAndSendPlc() { string tempCode1; string tempCode2; // 实时绑定条码 //Task.Run(() => //{ // while (true) // { // try // { // if (!string.IsNullOrEmpty(code1Str) && !string.IsNullOrEmpty(code2Str)) // { // BindingCode(code1Str, code2Str); // code1Str = string.Empty; // code2Str = string.Empty; // } // } // catch (Exception ex) // { // code1Str = string.Empty; // code2Str = string.Empty; // Console.WriteLine(ex.ToString()); // } // Thread.Sleep(500); // } //}); // 心跳线程 Task.Run(() => { try { Thread.Sleep(3000); var obj = PlcHelper.melsecList.FirstOrDefault(d => d.EquipName.Equals("条码绑定Plc")); if (obj != null) { while (true) { SendHeart(obj, "0"); Thread.Sleep(1000); SendHeart(obj, "1"); Thread.Sleep(1000); } } } catch (Exception ex) { log.Error(ex.ToString()); } }); #region 暂未启用 // 实时下发plc放行信号 //Task.Run(() => //{ // try // { // while (true) // { // Thread.Sleep(3000); // var obj = PlcHelper.melsecList.FirstOrDefault(d => d.EquipName.Equals("条码绑定Plc")); // if (obj != null && obj.plc.IsConnected) // { // CodeBindingRecord record = _codeBindingRecordServices.FirstAsync(x => x.isPlcPass == 1 && x.RecordTime2 >= System.DateTime.Now.AddDays(-1)).Result; // if (record != null) // { // // 下发plc放行信号 // RefreshAndWriteLog($"条码[{record.BoxCode}]下发plc放行信号,等待plc反馈..."); // if (SendPlcPass(obj)) // { // RefreshAndWriteLog($"条码[{record.BoxCode}]放行成功"); // record.isPlcPass = 2; // _ = _codeBindingRecordServices.UpdateAsync(record).Result; // LoadData(); // } // else // { // RefreshAndWriteLog("等待Plc反馈信号5秒超时!"); // } // } // } // Thread.Sleep(1000); // } // } // catch (Exception ex) // { // log.Error(ex.ToString()); // } //}); #endregion } #region 加载DataGrid数据 private async void LoadData() { try { // LoadCharts(); List records = null; records = _codeBindingRecordServices.QueryAsync(x => x.BoxCode != null && x.RecordTime2 >= DateTime.Today && x.RecordTime2 < DateTime.Today.AddDays(1)).Result; if (records != null && records.Count > 0) { records = records.OrderBy(x => x.RecordTime2).ToList(); Application.Current.Dispatcher.Invoke(() => { ListItems.Clear(); foreach (CodeBindingRecord record in records) { ListItems.Insert(0, new ReaderInfo() { No = ListItems.Count + 1, BoxCode = record.BoxCode, ProductCode = record.ProductCode, BoxName = record.BoxName, BindingResult = record.BindingResult, IsPass = record.IsPass==1?"自动":"手动", RecordTime = record.RecordTime2.ToString() }); } }); } } catch (Exception) { } } // 修改为统计近一天白班或夜班 private async void LoadCharts() { try { List list = _codeBindingRecordServices.QueryCharts().Result; if (list == null || list.Count == 0) return; var result = from m in list group m by GetSubstringBetweenCommas(m.BoxName) into g select new CodeBindCharts() { BoxName = g.Key, Amount = g.Sum(m => m.Amount) }; App.Current.Dispatcher.Invoke(() => { ProductionHourList.Clear(); ModelStatistics.Clear(); // 图表赋值 ChartValues achievement = new ChartValues(); int i = 0; double total = 0; foreach (var item in result) { ProductionHourList.Add(item.BoxName); achievement.Add(new ObservablePoint(i, item.Amount)); total += item.Amount; i++; } //加一个汇总柱状图 ProductionHourList.Add("合计"); achievement.Add(new ObservablePoint(i, total)); var column = new ColumnSeries(); column.DataLabels = true; column.Title = "型号"; column.Values = achievement; column.Foreground = Brushes.White; ModelStatistics.Add(column); }); } catch (Exception) { throw; } } /// /// 截取两个逗号之间的字符串 /// /// /// static string GetSubstringBetweenCommas(string input) { if (input == null) return null; // 找到第一个逗号的位置 int firstCommaIndex = input.IndexOf(','); if (firstCommaIndex != -1) { // 找到第二个逗号的位置 int secondCommaIndex = input.IndexOf(',', firstCommaIndex + 1); if (secondCommaIndex != -1) { // 使用Substring截取第一个逗号和第二个逗号之间的字符 return input.Substring(firstCommaIndex + 1, secondCommaIndex - firstCommaIndex - 1); } else { return null; } } else { return null; } } #endregion #region 参数定义 /// /// 条码1 /// private string code1 = string.Empty; public string Code1 { get { return code1; } set { code1 = value; OnPropertyChanged(nameof(Code1)); } } /// /// 条码1扫描时间 /// private string code1Time = string.Empty; public string Code1Time { get { return code1Time; } set { code1Time = value; OnPropertyChanged(nameof(Code1Time)); } } /// /// 条码2 /// private string code2 = string.Empty; public string Code2 { get { return code2; } set { code2 = value; OnPropertyChanged(nameof(Code2)); } } ///// ///// 条码2扫描时间 ///// private string code2Time = string.Empty; public string Code2Time { get { return code2Time; } set { code2Time = value; OnPropertyChanged(nameof(Code2Time)); } } /// /// 绑定提示信息 /// private string bindingInfo = string.Empty; public string BindingInfo { get { return bindingInfo; } set { bindingInfo = value; OnPropertyChanged(nameof(BindingInfo)); } } #region 日产量柱状图X轴日期 /// /// 日产量柱状图X轴日期 /// private List productionHourList = new List(); public List ProductionHourList { get { return productionHourList; } set { productionHourList = value; } } #endregion #region 型号统计柱状图 /// /// 型号统计柱状图 /// private SeriesCollection modelStatistics = new SeriesCollection(); public SeriesCollection ModelStatistics { get { return modelStatistics; } set { modelStatistics = value; } } #endregion #endregion #region 初始化datagrid private ObservableCollection listItems = new ObservableCollection() { }; public ObservableCollection ListItems { get { return listItems; } set { listItems = value; OnPropertyChanged();//属性通知 } } #endregion /// /// NoRead处理 /// /// private async void ReceiveNoRead(string scannerIp) { // ScannerModel model = allScanners.FirstOrDefault(x => x.Ip == scannerIp); if (scannerIp == MesScannerIp) { // log.Info("MES条码NoRead:"); SendPlcStop(); Clear(); RefreshAndWriteLog("MES条码未扫描到,NoRead报警,线体停止,请重新扫描!",true); } else if (SnScannerIp == scannerIp) { SendPlcStop(); Clear(); RefreshAndWriteLog("SN条码未扫描到,NoRead报警,线体停止,请重新扫描!", true); } speechStr.SpeakAsync("扫码失败,请补扫"); } /// /// 页面扫码信息清空 /// public void Clear() { code1Str = string.Empty; code2Str = string.Empty; // 页面扫码信息清空 Code1 = string.Empty; Code2 = string.Empty; Code1Time = string.Empty; Code2Time = string.Empty; BindingInfo = string.Empty; } /// /// 接收扫码器传输的条码,扫码器ip /// /// /// private void ReceiveCode(string scannerIp, string codeStr) { // ScannerModel model = allScanners.FirstOrDefault(x => x.Ip == scannerIp); if (MesScannerIp == scannerIp) { log.Info("扫描到MES条码:" + codeStr); // 全局变量赋值,SN码扫描后使用 code1Str = codeStr; RefreshCode1(codeStr); if (!string.IsNullOrEmpty(code1Str) && !string.IsNullOrEmpty(code2Str)) { BindingCode(code1Str, code2Str); code1Str = string.Empty; code2Str = string.Empty; } } else if (SnScannerIp == scannerIp) { // Clear(); log.Info("扫描到成品条码:" + codeStr); // 1.刷新界面条码信息 // 全局变量赋值,mes条码扫描后使用 code2Str = codeStr; RefreshCode2(codeStr); if (!string.IsNullOrEmpty(code1Str) && !string.IsNullOrEmpty(code2Str)) { BindingCode(code1Str, code2Str); code1Str = string.Empty; code2Str = string.Empty; } } #region // 2.创建任务更新数据库条码1 // CodeBindingRecord codeRecord = new CodeBindingRecord(); // codeRecord.BoxCode = code1; // codeRecord.BoxName = "去别的数据库查询"; //List bomInfo = await _baseBomInfoServices.QueryAsync(x => x.MaterialCode == code); //string aa = bomInfo.FirstOrDefault().MaterialName; // codeRecord.RecordTime1 = time; // int a = await _codeBindingRecordServices.AddAsync(codeRecord); // 页面刷新ListItems //await Application.Current.Dispatcher.InvokeAsync(() => //{ // // 在 UI 线程上操作列表 // ListItems.Insert(0, new ReaderInfo() { No = codeRecord.ObjId, BoxCode = codeRecord.BoxCode, RecordTime = codeRecord.RecordTime1.ToString() }); //}); //log.Info("条码1记录更新"); #endregion } private void RefreshCode1(string code1) { DateTime time = System.DateTime.Now; Code1 = code1; Code1Time = time.ToString(); } private void RefreshCode2(string code2) { DateTime time = System.DateTime.Now; Code2 = code2; Code2Time = time.ToString(); } /// /// 提示信息刷新并且存日志 /// /// private void RefreshAndWriteLog(string logStr,bool warnflag=false) { TimeSpan currentTime = DateTime.Now.TimeOfDay; // DateTime time = System.DateTime.Now; string timeString = currentTime.ToString(@"hh\:mm\:ss"); BindingInfo = timeString + ":" + logStr; if(warnflag) { MsgUIColor = "Red"; } else { MsgUIColor = "White"; } log.Info(BindingInfo); } /// /// 提示信息-颜色 /// public string msgUIColor; public string MsgUIColor { get => msgUIColor; set => SetProperty(ref msgUIColor, value); } /// /// 条码绑定 /// /// MES码 /// SN码 /// 1为自动扫描,2为手动扫描 public void BindingCode(string code1, string code2,int flag =1) { try { if (code1.Substring(0, 1) != "B") { speechStr.SpeakAsync("扫码失败,请补扫"); RefreshAndWriteLog("MES码:" + code1 + ",扫描错误,请重新扫描!"); SendPlcStop(); return; } if (code2.Length != 20) { speechStr.SpeakAsync("扫码失败,请补扫"); RefreshAndWriteLog("SN码:" + code2 + ",扫描错误,请重新扫描!"); SendPlcStop(); return; } #region 终检校验-未查到终检合格记录即为质检不合格 ReportQualityInsPection qualityList = _reportQualityInspectionServices.JudgeIsQualified(code1); if (qualityList == null) { SendPlcStop(); RefreshAndWriteLog($"终检失败!! 箱体码{code1}未查询到终检合格记录,请重新终检!",true); speechStr.SpeakAsync("终检失败,请终检"); AddExceptionRecord(code1, $"终检失败!! 箱体码{code1}未查询到终检合格记录,请重新终检!", 4); return; } #endregion RefreshAndWriteLog("开始绑定MES条码:" + code1 + " SN条码:" + code2); // 1.数据库查询各个工序质检结果,不合格报警 //// 2.查询条码绑定记录表(内胆箱壳绑定处就应该插入记录),绑定SN码 int Repeatflag = 0; CodeBindingRecord record = _codeBindingRecordServices.FirstAsync(x => x.BoxCode == code1).Result; if (record == null) { RefreshAndWriteLog("未查询到MES条码记录,集存库未绑定箱壳内胆"); //return; // 没有记录重新插入一条 record = new CodeBindingRecord(); } else { Repeatflag = 1; } BaseMaterialInfo materialInfo = _baseMaterialInfoServices.FirstAsync(x => x.MaterialCode == code1.Substring(7, 10)).Result; if (materialInfo == null) { record.BoxName = ""; } else { record.BoxName = materialInfo.MaterialName; } record.BoxCode = code1; record.ProductCode = code2; //record.RecordTime1 = System.DateTime.Now; record.RecordTime2 = System.DateTime.Now; record.IsPass = flag; record.BindingResult = "成功"; bool result = false; if (Repeatflag == 0) { // 没有记录,新加 result = _codeBindingRecordServices.AddAsync(record).Result > 0 ? true : false; } else if (Repeatflag == 1) { result = _codeBindingRecordServices.UpdateAsync(record).Result; } if (result) { RefreshAndWriteLog("条码【" + record.BoxCode + "】与SN码【" + record.ProductCode + "】绑定成功"); #region 更新过点数据,插入记录到MATERIAL_COMPLETION表 PrintBarCode print = _printBarCodeServices.FirstAsync(x => x.MaterialBarcode == code1).Result; if (print == null) return; MaterialCompletion completion = new MaterialCompletion(); completion.OrderCode = print.OrderCode; completion.MaterialBarcode = code1; completion.MaterialCode = print.MaterialCode; completion.MaterialName = print.MaterialName; completion.StationName = "1008"; completion.CompleteDate = DateTime.Now; completion.isDownLine = 0; completion.ProductLineCode = "CX_02"; _ = _iMaterialCompletionServices.AddAsync(completion).Result; #endregion SendPlcPass(); //刷新页面 LoadData(); LoadCharts(); } else { RefreshAndWriteLog("条码【" + record.BoxCode + "】与SN码【" + record.ProductCode + "】绑定失败", true); if (SendPlcStop()) { RefreshAndWriteLog("条码绑定失败,线体停止"); } } } catch (Exception ex) { RefreshAndWriteLog(ex.Message.ToString()); SendPlcStop(); } finally { // code1Str = string.Empty; // code2Str = string.Empty; } } /// /// 往mes数据库添加异常记录 /// /// /// /// 1=69码校验;2=重复扫描;3=未绑条码;4=未终检 public async void AddExceptionRecord(string BoxCode, string Msg, int Type) { try { ExceptionRecord record = new ExceptionRecord(); record.ProductSnCode = BoxCode; record.ProductScanTime = DateTime.Now; record.ProductLineCode = ProductLineCode; record.ExceptionMsg = Msg; record.ExceptionType = Type; record.Position = "条码绑定"; await exceptionRecordServices.AddAsync(record); } catch (Exception ex) { log.Info("添加异常记录方法AddExceptionRecord异常:" + ex.Message.ToString()); } } #region plc交互 /// /// 下发plc停止信号 /// /// /// private bool SendPlcStop() { bool result = false; try { var obj = PlcHelper.melsecList.FirstOrDefault(d => d.EquipName.Equals("条码绑定Plc")); if (obj != null) { log.Info($"NoRead信号,下发停止信号成功,当前箱体码{code1Str},当前成品码{code2Str}"); // 往plc写入停止信号 obj.plc.WriteInt16("D7102", "1"); // 报警信号 obj.plc.WriteInt16("D7101", "1"); result = true; } else { log.Info($"NoRead信号,下发停止信号失败,plc未连接,当前箱体码{code1Str},当前成品码{code2Str}"); } } catch (Exception ex) { log.Info($"NoRead信号,下发停止信号异常,plc未连接,当前箱体码{code1Str},当前成品码{code2Str}"); } return result; } /// /// 下发plc放行信号 /// /// /// private bool SendPlcPass() { bool result = false; try { var obj = PlcHelper.melsecList.FirstOrDefault(d => d.EquipName.Equals("条码绑定Plc")); if (obj != null) { log.Info("下发放行,停止信号D7102写0"); // 停止信号复位 obj.plc.WriteInt16("D7102", "0"); // 报警信号复位 obj.plc.WriteInt16("D7101", "0"); result = true; } } catch (Exception ex) { log.Error("下发plc停止信号方法出现异常,ex:" + ex); } return result; } /// /// 发送心跳 /// /// /// private void SendHeart(PlcModel obj, string flag) { try { // log.Info("心跳D7100写:"+flag); // 往plc写入停止信号 obj.plc.WriteInt16("D7100", flag); // obj.plc.WriteInt32("D7102", 1); } catch (Exception ex) { log.Error("SendHeart异常,ex:" + ex); } } ///// ///// 下发plc放行信号 ///// ///// //private bool SendPlcPass(PlcModel obj) //{ // bool result = false; // try // { // log.Info("D7100写1"); // // 往plc写入放行信号 // obj.plc.WriteInt16("D7100", "1"); // // 等待plc反馈信号 // result = waitPlcSignal(obj); // } // catch (Exception ex) // { // log.Error("下发plc放行信号方法SendPlcPass()出现异常,ex:" + ex); // } // return result; //} ///// ///// 读取plc放行反馈 ///// ///// //private bool waitPlcSignal(PlcModel obj) //{ // bool result = false; // try // { // DateTime startTime = DateTime.Now; // bool isFlag = true; // do // { // if (obj.plc.ReadInt16("D7200") == 2) // { // log.Info("D7100读2"); // isFlag = false; // result = true; // } // TimeSpan elapsedTime = DateTime.Now - startTime; // if (elapsedTime.TotalSeconds >= 5) // { // isFlag = false; // } // Thread.Sleep(500); // } while (isFlag); // } // catch (Exception ex) // { // log.Error("读取plc放行反馈方法waitPlcSignal()出现异常,ex:" + ex); // } // return result; //} #endregion } }