using JinYuan.Helper; using JinYuan.Models; using JinYuan.VirtualDataLibrary; using Language; using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Text; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using System.Windows.Forms.DataVisualization.Charting; namespace LargeSquareOne { public partial class FrmMonitor : MultiLanguageForm { private static readonly object uiLock = new object(); private static FrmMonitor _instance; private readonly CancellationTokenSource _cts = new CancellationTokenSource(); private readonly PrivateFontCollection _font = new PrivateFontCollection(); private Font _myFont; public static FrmMonitor Instance { get { lock (uiLock) { return _instance ??= new FrmMonitor(); } } } public FrmMonitor() { InitializeComponent(); InitializeFormSettings(); //LoadCustomFont(); this.FormClosing += FrmMonitor_FormClosing; } private void InitializeFormSettings() { this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.DoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.Selectable | ControlStyles.SupportsTransparentBackColor, true); } private void LoadCustomFont() { try { var fontPath = Path.Combine(Environment.CurrentDirectory, "Assts", "Fonts", "FZY4JW.ttf"); _font.AddFontFile(fontPath); var myFontFamily = new FontFamily(_font.Families[0].Name, _font); _myFont = new Font(myFontFamily, 20, FontStyle.Bold); } catch (Exception ex) { CommonMethods.AddLog(true, "加载字体异常".Translated() + $":{ex.Message}"); } } private void FrmMonitor_FormClosing(object sender, FormClosingEventArgs e) { _cts.Cancel(); _font?.Dispose(); _myFont?.Dispose(); } protected override void WndProc(ref Message m) { if (m.Msg == 0x0014) return; // 禁掉清除背景消息 base.WndProc(ref m); } private async void FrmMonitor_Load(object sender, EventArgs e) { try { SetChart(); await RefreshAllDataAsync(); await StartPeriodicRefreshAsync(_cts.Token); } catch (Exception ex) { CommonMethods.AddLog(true, "窗体加载异常".Translated() + $":{ex.Message}"); } } private void SetChart() { try { #region 24小时统计 Chart12HourTotal.Series.Clear(); Chart12HourTotal.ChartAreas[0].AxisY.Minimum = 0; Chart12HourTotal.ChartAreas[0].AxisY.Maximum = 2000; ChartHelper.AddSeries(Chart12HourTotal, "投入".Translated(), SeriesChartType.Column, ChartValueType.Auto, MarkerStyle.Diamond, 8, Color.DarkTurquoise, Color.Aqua, "", false, true); ChartHelper.AddSeries(Chart12HourTotal, "产出".Translated(), SeriesChartType.Column, ChartValueType.Auto, MarkerStyle.Diamond, 8, Color.PaleGoldenrod, Color.PaleGoldenrod, "", false, true); ChartHelper.AddSeries(Chart12HourTotal, "优率".Translated(), SeriesChartType.Spline, ChartValueType.String, MarkerStyle.Circle, 8, Color.Lime, Color.Lime, "#VAL{P}", true, true); ChartHelper.SetStyle(Chart12HourTotal, Color.Transparent, Color.White); ChartHelper.SetLegend(Chart12HourTotal, Docking.Left, StringAlignment.Center, Color.Transparent, Color.White); ChartHelper.SetXY(Chart12HourTotal, "时间".Translated(), "数值".Translated(), -45, StringAlignment.Center, Color.White, Color.White, AxisArrowStyle.None, 1, true); ChartHelper.SetMajorGrid(Chart12HourTotal, Color.Transparent, 20, 2); #endregion } catch (Exception ex) { CommonMethods.AddLog(true, "图表初始化异常".Translated() + $":{ex.Message}"); } } private async Task StartPeriodicRefreshAsync(CancellationToken ct) { while (!ct.IsCancellationRequested) { try { await RefreshAllDataAsync(); await Task.Delay(2000, ct); } catch (OperationCanceledException) { break; } catch (Exception ex) { CommonMethods.AddLog(true, "定时刷新异常".Translated() + $":{ex.Message}"); await Task.Delay(1000, ct); } } } private async Task RefreshAllDataAsync() { var tasks = new[] { Refresh12ProdQtyAsync(), RefreshXiaoLvDataAsync(), RefreshChatTop10AlarmDataAsync(), RefreshChatNGDataAsync() }; await Task.WhenAll(tasks); } private async Task Refresh12ProdQtyAsync() { await Task.Run(() => { if (IsDisposed) return; this.InvokeIfRequired(() => { var data = CommonMethods.Lst_Prod12HourData?.Count > 0 ? CommonMethods.Lst_Prod12HourData : MockDataGenerator.Generate12HourData(); UpdateChart12HourData(data); }); }); } private void UpdateChart12HourData(List data) { try { var maxValue = data.Max(x => x.ProdIn); Chart12HourTotal.ChartAreas[0].AxisY.Minimum = 0; Chart12HourTotal.ChartAreas[0].AxisY.Maximum = (int)maxValue + 1500; // 直接使用数据,不需要额外排序 var x1 = data.Select(c => c.DisplayTime).ToList(); var y1 = data.Select(c => c.ProdIn).ToList(); var y2 = data.Select(c => c.ProdOut).ToList(); var y3 = data.Select(c => c.OKRatio).ToList(); Chart12HourTotal.Series[0].Points.DataBindXY(x1, y1); Chart12HourTotal.Series[1].Points.DataBindXY(x1, y2); Chart12HourTotal.Series[2].Points.DataBindXY(x1, y3); // 设置X轴标签的角度,提高可读性 Chart12HourTotal.ChartAreas[0].AxisX.LabelStyle.Angle = 0; // 确保显示所有标签 Chart12HourTotal.ChartAreas[0].AxisX.Interval = 1; } catch (Exception ex) { CommonMethods.AddLog(true, "更新12小时数据异常".Translated() + $":{ex.Message}"); } } // 效率数据也可以添加模拟数据 private async Task RefreshXiaoLvDataAsync() { await Task.Run(() => { if (IsDisposed) return; // 使用实际数据或模拟数据 var utilizationRate = CommonMethods.JiaDL >= 0 ? Convert.ToDouble(CommonMethods.JiaDL) * 100 : MockDataGenerator._random.Next(60, 95); var totalQty = CommonMethods.TotalQty >= 0 ? CommonMethods.TotalQty : MockDataGenerator._random.Next(1000, 5000); var okQty = CommonMethods.ProOKQty >= 0 ? CommonMethods.ProOKQty : MockDataGenerator._random.Next(900, (int)totalQty); var yieldRate = totalQty == 0 ? 0 : Convert.ToDouble((Convert.ToDouble(okQty) / Convert.ToDouble(totalQty) * 100.0) .ToString("f2")); this.InvokeIfRequired(() => { UpdateEfficiencyControls(utilizationRate, yieldRate, (int)totalQty, (int)okQty); UpdateTimeDisplay(); UpdateEnergyDisplay(); }); }); } private double CalculateYieldRate() { if (CommonMethods.TotalQty == 0) return 0; return Convert.ToDouble((Convert.ToDouble(CommonMethods.ProOKQty) / Convert.ToDouble(CommonMethods.TotalQty) * 100.0) .ToString("f2")); } private void UpdateEfficiencyControls(double utilizationRate, double yieldRate, int totalQty, int okQty) { try { titleModeName.Title = CommonMethods.mesConfig.ModelName ?? "测试型号"; titleFactory_code.Title = CommonMethods.mesConfig.siteCode ?? "TEST001"; titleLine_No.Title = CommonMethods.mesConfig.lineCode ?? "LINE01"; titleEqp_code.Title = CommonMethods.mesConfig.equipNum ?? "EQP001"; proUtilizationRate.FloatValue = (float)utilizationRate; proPPM.IntValue = (int)(CommonMethods.Ppm > 0 ? CommonMethods.Ppm : MockDataGenerator._random.Next(100, 1000)); proOKQty.IntValue = okQty; proOKRatio.Value = yieldRate; proTotalQty.TotalValue = totalQty; } catch (Exception ex) { CommonMethods.AddLog(true, "更新效率控件异常".Translated() + $":{ex.Message}"); } } private void UpdateTimeDisplay() { try { if (CommonMethods.PlcOpenAndRunTime?.Count > 0) { titleStartTime.Title = $"{CommonMethods.PlcOpenAndRunTime[0]}:" + $"{CommonMethods.PlcOpenAndRunTime[1]}:" + $"{CommonMethods.PlcOpenAndRunTime[2]}"; titleRunTime.Title = $"{CommonMethods.PlcOpenAndRunTime[3]}:" + $"{CommonMethods.PlcOpenAndRunTime[4]}:" + $"{CommonMethods.PlcOpenAndRunTime[5]}"; } } catch (Exception ex) { CommonMethods.AddLog(true, "更新时间显示异常".Translated() + $":{ex.Message}"); } } private void UpdateEnergyDisplay() { try { if (CommonMethods.listElectricEnergy?.Count > 0) { EyMaterH1.ElectricEnergy = CommonMethods.listElectricEnergy[0]; } } catch (Exception ex) { CommonMethods.AddLog(true, "更新能源显示异常".Translated() + $":{ex.Message}"); } } private async Task RefreshChatTop10AlarmDataAsync() { await Task.Run(() => { if (IsDisposed) return; this.InvokeIfRequired(() => { UpdateAlarmChart(); }); }); } private void UpdateAlarmChart() { try { var alarmData = CommonMethods.Lst_AlarmTop10_Qty?.Count > 0 ? CommonMethods.Lst_AlarmTop10_Qty : MockDataGenerator.GenerateAlarmTop10Data(); if (alarmData?.Count > 0) { chartAlarmData.Series.Clear(); chartAlarmData.Titles.Clear(); var maxValue = alarmData.Max(x => x.DataCount); chartAlarmData.ChartAreas[0].AxisY.Minimum = 0; chartAlarmData.ChartAreas[0].AxisY.Maximum = (int)maxValue + 20; foreach (var item in alarmData) { ChartHelper.AddSeries(chartAlarmData, item.DataType, SeriesChartType.Column, ChartValueType.Auto, MarkerStyle.Diamond, 4, Color.DarkTurquoise, Color.White, "", false, true); } ConfigureAlarmChart(); var xData = alarmData.Select(c => c.DataType).ToList(); var yData = alarmData.Select(c => c.DataCount).ToList(); chartAlarmData.Series[0].Points.DataBindXY(xData, yData); } } catch (Exception ex) { CommonMethods.AddLog(true, "更新报警图表异常".Translated() + $":{ex.Message}"); } } private void ConfigureAlarmChart() { ChartHelper.SetTitle(chartAlarmData, "告警TOP10".Translated(), new Font("微软雅黑", 12), Docking.Top, Color.White); ChartHelper.SetStyle(chartAlarmData, Color.Transparent, Color.White); ChartHelper.SetLegend(chartAlarmData, Docking.Top, StringAlignment.Center, Color.Transparent, Color.White); ChartHelper.SetXY(chartAlarmData, "报警项".Translated(), "次数".Translated(), -45, StringAlignment.Center, Color.White, Color.White, AxisArrowStyle.None, 1, false); ChartHelper.SetMajorGrid(chartAlarmData, Color.Transparent, 20, 2); } private void BindAlarmChartData() { var xData = CommonMethods.Lst_AlarmTop10_Qty.Select(c => c.DataType).ToList(); var yData = CommonMethods.Lst_AlarmTop10_Qty.Select(c => c.DataCount).ToList(); chartAlarmData.Series[0].Points.DataBindXY(xData, yData); } private async Task RefreshChatNGDataAsync() { await Task.Run(() => { if (IsDisposed) return; this.InvokeIfRequired(() => { UpdateNGChart(); }); }); } private void UpdateNGChart() { try { var ngData = CommonMethods.Lst_DefectTypeQty?.Count > 0 ? CommonMethods.Lst_DefectTypeQty : MockDataGenerator.GenerateNGData(); if (ngData?.Count > 0) { chartNgShow.Series.Clear(); chartNgShow.Titles.Clear(); var maxValue = ngData.Max(x => x.DataCount); chartNgShow.ChartAreas[0].AxisY.Minimum = 0; chartNgShow.ChartAreas[0].AxisY.Maximum = (int)maxValue + 100; foreach (var item in ngData) { ChartHelper.AddSeries(chartNgShow, item.DataType, SeriesChartType.Column, ChartValueType.Auto, MarkerStyle.Diamond, 4, Color.Red, Color.White, "", false, true); } ConfigureNGChart(); var xData = ngData.Select(c => c.DataType).ToList(); var yData = ngData.Select(c => c.DataCount).ToList(); chartNgShow.Series[0].Points.DataBindXY(xData, yData); } } catch (Exception ex) { CommonMethods.AddLog(true, "更新不良图表异常".Translated() + $":{ex.Message}"); } } private void ConfigureNGChart() { ChartHelper.SetTitle(chartNgShow, "各不良项".Translated(), new Font("微软雅黑", 12), Docking.Top, Color.White); ChartHelper.SetStyle(chartNgShow, Color.Transparent, Color.White); ChartHelper.SetLegend(chartNgShow, Docking.Top, StringAlignment.Center, Color.Transparent, Color.White); ChartHelper.SetXY(chartNgShow, "项名".Translated(), "数值".Translated(), 0, StringAlignment.Center, Color.White, Color.White, AxisArrowStyle.None, 1, false); ChartHelper.SetMajorGrid(chartNgShow, Color.Transparent, 1, 1); } private void BindNGChartData() { var xData = CommonMethods.Lst_DefectTypeQty.Select(c => c.DataType).ToList(); var yData = CommonMethods.Lst_DefectTypeQty.Select(c => c.DataCount).ToList(); chartNgShow.Series[0].Points.DataBindXY(xData, yData); } } // 扩展方法 public static class ControlExtensions { public static void InvokeIfRequired(this Control control, Action action) { if (control.IsDisposed) return; if (control.InvokeRequired) control.BeginInvoke(action); else action(); } } }