Files

2764 lines
103 KiB
C#
Raw Permalink Normal View History

2026-08-04 18:36:40 +08:00
using Google.Protobuf.WellKnownTypes;
using JinYuan.ControlLib;
using JinYuan.Helper;
using JinYuan.MES.Models;
using JinYuan.Models;
using JinYuan.Models.HelperAttribute;
using JinYuan.VirtualDataLibrary;
using Language;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Documents;
using System.Windows.Forms;
namespace LargeSquareOne
{
public partial class FrmBatteryStatus : MultiLanguageForm
{
#region 字段定义
// 电池控件字典:Key=stationNo(1/2/3),Value=控件字典(Key=layer-row-col)
private readonly Dictionary<int, Dictionary<string, BatteryControl>> _batteryControlsByStationNo = new Dictionary<int, Dictionary<string, BatteryControl>>();
// 条码到控件映射(加速查找)
private readonly Dictionary<string, (int stationNo, string controlKey)> _barcodeToControlMap = new Dictionary<string, (int, string)>();
// 数据绑定列表
private readonly BindingList<BatteryReplace> _replaceRecords = new BindingList<BatteryReplace>();
private readonly BindingList<BatteryEntity> _ngBatteryRecords = new BindingList<BatteryEntity>();
private readonly BindingList<BatteryEntity> _allBatteryRecords = new BindingList<BatteryEntity>();
// 统计标签字典
private readonly Dictionary<int, List<System.Windows.Forms.Label>> _statisticsLabelsByLoc = new Dictionary<int, List<System.Windows.Forms.Label>>();
// 并发控制
private readonly SemaphoreSlim _operationSemaphore = new SemaphoreSlim(1, 1);
private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
// 防抖控制
private DateTime _lastStatisticsUpdateTime = DateTime.MinValue;
private DateTime _lastBatteryClickTime = DateTime.MinValue;
// 状态标记
private bool _isControlsInitialized = false;
// 统计项显示名称
private readonly string[] _statusDisplayNames = new string[]
{
"电芯替换总数", // GradeNG
"电芯装箱NG总数", // PackNG
"电芯档位&装箱OK总数", // Normal
"满箱还缺总数" // Init
};
// 性能监控
private PerformanceCounter _cpuUsageCounter;
#endregion
#region 构造函数
public FrmBatteryStatus()
{
InitializeComponent();
// 基础窗体设置
ConfigureFormProperties();
// 性能优化设置
ApplyPerformanceOptimizations();
// 初始化控件
InitializeDataGridViews();
BindScannerEvents();
InitializeDataBindings();
// 事件绑定
Load += FrmBatteryStatus_Load;
// 性能监控初始化
InitializePerformanceMonitoring();
}
#endregion
#region 初始化方法
/// <summary>
/// 配置窗体基础属性
/// </summary>
private void ConfigureFormProperties()
{
Dock = DockStyle.Fill;
AutoSize = false;
FormBorderStyle = FormBorderStyle.None;
Padding = new Padding(0);
Margin = new Padding(0);
// 双缓冲设置
SetStyle(
ControlStyles.OptimizedDoubleBuffer |
ControlStyles.AllPaintingInWmPaint |
ControlStyles.UserPaint |
ControlStyles.ResizeRedraw, true);
DoubleBuffered = true;
SetStyle(ControlStyles.SupportsTransparentBackColor, false);
}
/// <summary>
/// 应用全局性能优化
/// </summary>
private void ApplyPerformanceOptimizations()
{
// 禁用不必要的动画
Application.EnableVisualStyles();
//Application.SetCompatibleTextRenderingDefault(false);
// 递归设置所有控件双缓冲
SetDoubleBufferingRecursive(this, true);
// 禁用自动滚动减少重绘
AutoScroll = false;
AutoScrollMinSize = new Size(0, 0);
// 优化TabControl
if (tabBattery != null)
{
SetDoubleBuffering(tabBattery, true);
}
if (_cpuUsageCounter != null)
{
_cpuUsageCounter.Dispose();
_cpuUsageCounter = null;
}
}
/// <summary>
/// 初始化DataGridView控件
/// </summary>
private void InitializeDataGridViews()
{
OptimizeDataGridView(dgv_ngRsn);
OptimizeDataGridView(dgvReplaceBattery);
}
/// <summary>
/// 绑定扫描枪输入事件
/// </summary>
private void BindScannerEvents()
{
// 回车切换焦点
txtBox_Barcode.KeyDown += (s, e) =>
{
if (e.KeyCode == Keys.Enter && !string.IsNullOrEmpty(txtBox_Barcode.Text.Trim()))
{
e.SuppressKeyPress = true;
txtBox_SubBarcode?.Focus();
txtBox_SubBarcode?.SelectAll();
}
};
// 焦点获取时全选文本
txtBox_Barcode.Enter += (s, e) => ((TextBox)s)?.SelectAll();
txtBox_SubBarcode.Enter += (s, e) => ((TextBox)s)?.SelectAll();
}
/// <summary>
/// 初始化数据绑定
/// </summary>
private void InitializeDataBindings()
{
dgvReplaceBattery.DataSource = _replaceRecords;
dgv_ngRsn.DataSource = _ngBatteryRecords;
// 验证绑定
Debug.WriteLine($"dgv_ngRsn数据源类型:{dgv_ngRsn.DataSource?.GetType().Name}");
Debug.WriteLine($"dgv_ngRsn列数:{dgv_ngRsn.Columns.Count}");
_ngBatteryRecords.ListChanged += (s, e) =>
{
if (dgv_ngRsn.IsHandleCreated)
dgv_ngRsn.BeginInvoke(() => dgv_ngRsn.Invalidate());
};
_replaceRecords.ListChanged += (s, e) =>
{
if (dgvReplaceBattery.IsHandleCreated)
dgvReplaceBattery.BeginInvoke(() => dgvReplaceBattery.Invalidate());
};
}
/// <summary>
/// 初始化性能监控
/// </summary>
private void InitializePerformanceMonitoring()
{
try
{
// 先释放旧的计数器
if (_cpuUsageCounter != null)
{
_cpuUsageCounter.Dispose();
_cpuUsageCounter = null;
}
_cpuUsageCounter = new PerformanceCounter(
"Process",
"% Processor Time",
Process.GetCurrentProcess().ProcessName);
}
catch (Exception ex)
{
LogHelper.Instance.WriteError($"性能监控初始化失败:{ex}", "BatteryStatusLog");
_cpuUsageCounter = null; // 确保置空
}
}
#endregion
#region 性能优化相关方法
/// <summary>
/// 优化DataGridView性能
/// </summary>
private void OptimizeDataGridView(DataGridView dgv)
{
if (dgv == null) return;
// 设置双缓冲
var doubleBufferProp = dgv.GetType().GetProperty(
"DoubleBuffered",
BindingFlags.Instance | BindingFlags.NonPublic);
doubleBufferProp?.SetValue(dgv, true);
dgv.EnableHeadersVisualStyles = false;
dgv.AutoGenerateColumns = false;
dgv.RowHeadersVisible = true;
dgv.AllowUserToAddRows = false;
dgv.AllowUserToDeleteRows = false;
dgv.AllowUserToOrderColumns = false;
dgv.AllowUserToResizeRows = false;
dgv.ReadOnly = true;
dgv.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
dgv.MultiSelect = false;
// 减少绘制开销
dgv.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing;
dgv.ColumnHeadersHeight = 25;
dgv.RowTemplate.Height = 22;
dgv.ScrollBars = ScrollBars.Vertical;
}
/// <summary>
/// 设置控件双缓冲
/// </summary>
/// <param name="control">目标控件</param>
/// <param name="enable">是否启用</param>
private void SetDoubleBuffering(Control control, bool enable)
{
if (control == null) return;
try
{
var prop = control.GetType().GetProperty(
"DoubleBuffered",
BindingFlags.Instance | BindingFlags.NonPublic);
prop?.SetValue(control, enable);
}
catch (Exception ex)
{
LogHelper.Instance.WriteLog($"设置双缓冲失败:{ex.Message}", "BatteryStatusLog");
}
}
/// <summary>
/// 递归设置控件双缓冲
/// </summary>
private void SetDoubleBufferingRecursive(Control control, bool enable)
{
if (control == null) return;
try
{
SetDoubleBuffering(control, enable);
foreach (Control child in control.Controls)
{
SetDoubleBufferingRecursive(child, enable);
}
}
catch
{
// 忽略设置失败
}
}
#endregion
#region 窗体加载与控件初始化
private async void FrmBatteryStatus_Load(object sender, EventArgs e)
{
try
{
if (_isControlsInitialized) return;
SafeUI(() =>
{
this.SuspendLayout();
SetPanelsVisibility(false);
});
await Task.Delay(100);
// 所有控件创建必须走 UI()
SafeUI(() =>
{
InitializeBatteryControls();
_isControlsInitialized = true;
panelExt_Grade1?.Invalidate();
panelExt_Grade2?.Invalidate();
panelExt_Grade3?.Invalidate();
tabBattery?.Invalidate();
this.ResumeLayout(false);
Invalidate();
SetPanelsVisibility(true);
});
}
catch (Exception ex)
{
LogHelper.Instance.WriteError($"加载电池界面异常:{ex}", "BatteryStatusLog");
}
}
/// <summary>
/// 异步初始化电池控件(避免UI阻塞)
/// </summary>
private async Task InitializeBatteryControlsAsync()
{
await Task.Run(() =>
{
if (InvokeRequired)
{
Invoke(new Action(InitializeBatteryControls));
}
else
{
InitializeBatteryControls();
}
}).ConfigureAwait(false);
}
/// <summary>
/// 初始化电池控件
/// </summary>
private void InitializeBatteryControls()
{
try
{
// 获取配置参数
var config = CommonMethods.mesConfig;
int layers = config?.packLayers ?? 4;
int rows = config?.rowsPerLayer ?? 5;
int cols = config?.colsPerLayer ?? 12;
Debug.WriteLine($"初始化电池控件:层={layers}, 行={rows}, 列={cols}");
// 暂停面板布局更新
SuspendPanelsLayout();
ClearPanelsControls();
// 获取FD配置
var fdConfig = CommonMethods.curFdConfig;
if (fdConfig == null) return;
// 初始化各档位控件
InitializeGradeControls(1, fdConfig.Grade1, panelExt_Grade1, layers, rows, cols);
InitializeGradeControls(2, fdConfig.Grade2, panelExt_Grade2, layers, rows, cols);
InitializeGradeControls(3, fdConfig.Grade3, panelExt_Grade3, layers, rows, cols);
// 恢复布局
ResumePanelsLayout();
// 统计控件数量
int totalControls = _batteryControlsByStationNo.Values.Sum(d => d.Count);
Debug.WriteLine($"电池控件初始化完成,总控件数:{totalControls}");
}
catch (Exception ex)
{
Debug.WriteLine($"控件初始化异常:{ex.Message}");
LogHelper.Instance.WriteError($"初始化电池控件异常:{ex}", "BatteryStatusLog");
}
}
// 窗体关闭时释放资源
protected override void OnFormClosing(FormClosingEventArgs e)
{
base.OnFormClosing(e);
//// 取消异步任务
//_cancellationTokenSource.Cancel();
_cancellationTokenSource.Token.UnregisterAll(); // 新增:移除所有注册的回调
// 安全取消
try
{
_cancellationTokenSource.Cancel(true); // true=允许回调抛异常但不终止程序
}
catch (AggregateException ex)
{
// 记录回调中的具体异常(关键:定位哪个回调出问题)
foreach (var innerEx in ex.InnerExceptions)
{
LogHelper.Instance.WriteError($"取消任务时回调异常:{innerEx}", "BatteryStatusLog");
}
}
catch (Exception ex)
{
LogHelper.Instance.WriteError($"取消CancellationTokenSource异常:{ex}", "BatteryStatusLog");
}
Task.Delay(100).Wait();
// 释放资源
_operationSemaphore.Dispose();
if (_cpuUsageCounter != null)
{
_cpuUsageCounter.Dispose();
_cpuUsageCounter = null;
}
lock (_batteryControlsByStationNo)
{
DisposeBatteryControls();
ClearAllPanels();
_batteryControlsByStationNo.Clear();
_statisticsLabelsByLoc.Clear();
_barcodeToControlMap.Clear();
}
_cancellationTokenSource.Dispose();
}
// 重写窗体显示方法,优化渲染
protected override void OnShown(EventArgs e)
{
base.OnShown(e);
// 恢复布局
foreach (Control control in this.Controls)
{
control.ResumeLayout(false);
}
}
/// <summary>
/// 重写CreateParams减少闪烁
/// </summary>
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x02000000; // WS_EX_COMPOSITED
return cp;
}
}
#endregion
#region 电池控件管理
/// <summary>
/// 初始化指定档位的电池控件
/// </summary>
/// <param name="stationNo">机架号(1/2/3)</param>
/// <param name="grade">档位名称</param>
/// <param name="container">容器面板</param>
/// <param name="layers">层数</param>
/// <param name="rows">行数</param>
/// <param name="cols">列数</param>
private void InitializeGradeControls(int stationNo, string grade, PanelExt container, int layers, int rows, int cols)
{
if (stationNo < 1 || stationNo > 3 || container == null || container.HasChildren)
{
Debug.WriteLine($"机架号{stationNo}错误或容器非空,跳过初始化");
return;
}
if (string.IsNullOrEmpty(grade) || grade == "不设置" || grade == "NG" )
{
// 设置标签页文本
SetTabPageText(stationNo, grade);
return;
}
try
{
// 设置标签页文本
SetTabPageText(stationNo, grade);
// 初始化容器面板
container.Controls.Clear();
//container.AutoScroll = true;
container.BackColor = Color.FromArgb(11, 20, 36);
container.SuspendLayout();
container.Visible = false;
container.Dock = DockStyle.Fill;
container.Padding = new Padding(0); // 增加容器内边距
// 创建层级面板
var layerPanel = CreateLayerPanel(stationNo, grade, layers, rows, cols);
// 创建统计区域
var statsGroup = CreateStatisticsGroupBox(stationNo, grade, out var statLabels);
_statisticsLabelsByLoc[stationNo] = statLabels;
statsGroup.Size = new Size(layerPanel.Width, 70);
statsGroup.Location = new System.Drawing.Point(0, layerPanel.Bottom + 5);
//statsGroup.Dock = DockStyle.Bottom;
// 添加控件到容器
container.Controls.Add(layerPanel);
container.Controls.Add(statsGroup);
//container.AutoScrollMinSize = new Size(layerPanel.Width, statsGroup.Bottom);
//container.ClientSize = new Size(layerPanel.Width + 10, statsGroup.Bottom + 10);
// 恢复布局
container.ResumeLayout(true);
container.Visible = true;
container.Invalidate();
Debug.WriteLine($"机架号{stationNo}控件创建完成,总数:{layers * rows * cols}");
}
catch (Exception ex)
{
Debug.WriteLine($"初始化机架号{stationNo}异常:{ex.Message}");
LogHelper.Instance.WriteError($"初始化机架号{stationNo}电池控件异常:{ex}", "BatteryStatusLog");
}
}
/// <summary>
/// 创建层级面板
/// </summary>
//创建分层的表格
private TableLayoutPanel CreateLayerPanel(int stationNo, string grade, int layers, int rows, int cols)
{
// 布局参数
int batterySize = 24;
int cellPadding = 2;
int cellSize = batterySize + cellPadding * 2;
int rowNumColWidth = 40; // 行号列宽度
int layerColWidth = 40; // 层数列宽度
int totalColWidth = rowNumColWidth + (cellSize * cols); // 电池区域总列宽
int totalPanelWidth = layerColWidth + totalColWidth + 10; // 整体总宽度(+10px余量)
int rowHeight = cellSize + cellPadding; // 每行高度 = 单元格高度
int layerHeight = (rowHeight * rows) + 2; // 每层高度 = 表头 + 电池行
int layerTotalHeight = rowHeight * rows + 6; // 每层总高度(+8px余量,确保最后一行显示)
//外层TableLayoutPanel:分层(包含表头+所有层)
TableLayoutPanel layerPanel = new TableLayoutPanel
{
RowCount = layers + 1,
ColumnCount = 2,
//Dock = DockStyle.Fill, // 顶部对齐,避免Fill压缩宽度
BackColor = Color.Transparent,
CellBorderStyle = TableLayoutPanelCellBorderStyle.Single, //TableLayoutPanelCellBorderStyle.None,
Margin = new Padding(0),
AutoSizeMode = AutoSizeMode.GrowAndShrink,
Size = new Size(totalPanelWidth, layerTotalHeight * layers + 35),
//Margin = new Padding(0, 0, 0, 10),
};
layerPanel.ColumnStyles.Clear();
layerPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, layerColWidth));
layerPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, totalColWidth));
// 设置行样式
layerPanel.RowStyles.Clear();
layerPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, 25F)); //第一行 显示列号
for (int i = 1; i <= layers; i++)
{
layerPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, layerTotalHeight));
}
// ========== 创建表头行 ==========
// 表头-第一列(文本:层数/列)
System.Windows.Forms.Label lblHeaderLayer = new System.Windows.Forms.Label
{
Text = "层",
TextAlign = ContentAlignment.MiddleCenter,
ForeColor = Color.White,
Dock = DockStyle.Fill,
Font = new Font("Microsoft YaHei", 9, FontStyle.Bold)
};
layerPanel.Controls.Add(lblHeaderLayer, 0, 0);
// 表头-第二列(列号容器)
TableLayoutPanel tblColHeader = new TableLayoutPanel
{
RowCount = 1,
ColumnCount = cols + 1, // 行号列 + 所有电池列
Dock = DockStyle.Fill,
Size = new Size(totalColWidth, 25),
//AutoSize = true,
//AutoSizeMode = AutoSizeMode.GrowAndShrink,
//BackColor = Color.Transparent,
BackColor = Color.FromArgb(18, 30, 50),
Margin = new Padding(0),
CellBorderStyle = TableLayoutPanelCellBorderStyle.None
};
tblColHeader.ColumnStyles.Clear();
tblColHeader.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, rowNumColWidth));
for (int col = 1; col <= cols; col++)
{
tblColHeader.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, cellSize));
}
System.Windows.Forms.Label lblheaderCol = new System.Windows.Forms.Label
{
Text = "行/列",
TextAlign = ContentAlignment.MiddleCenter,
ForeColor = Color.White,
Dock = DockStyle.Fill,
Margin = new Padding(0),
Font = new Font("Microsoft YaHei", 9, FontStyle.Bold),
BackColor = Color.FromArgb(18, 30, 50),
};
tblColHeader.Controls.Add(lblheaderCol, 0, 0);
for (int col = 1; col <= cols; col++)
{
System.Windows.Forms.Label lblCol = new System.Windows.Forms.Label
{
Text = col.ToString(),
TextAlign = ContentAlignment.MiddleCenter,
ForeColor = Color.White,
Dock = DockStyle.Fill,
Margin = new Padding(0),
Font = new Font("Microsoft YaHei", 9, FontStyle.Bold)
};
tblColHeader.Controls.Add(lblCol, col, 0);
}
layerPanel.Controls.Add(tblColHeader, 1, 0);
//CreateBatteryControls(stationNo, grade, layerPanel, layers, rows, cols);
// 初始化控件字典
if (!_batteryControlsByStationNo.ContainsKey(stationNo))
{
_batteryControlsByStationNo[stationNo] = new Dictionary<string, BatteryControl>();
}
// ========== 遍历每层,创建电池控件 ==========
for (int layer = 1; layer <= layers; layer++)
{
// 层数标签(第一列)
System.Windows.Forms.Label lblLayer = new System.Windows.Forms.Label
{
Text = $"第{layer}层",
TextAlign = ContentAlignment.MiddleCenter,
ForeColor = Color.White,
Dock = DockStyle.Fill,
BackColor = Color.FromArgb(18, 30, 50),
Font = new Font("Microsoft YaHei", 9, FontStyle.Bold),
Margin = new Padding(0),
Padding = new Padding(0)
};
layerPanel.Controls.Add(lblLayer, 0, layer);
System.Windows.Forms.Panel pnlBatteryContainer = new System.Windows.Forms.Panel
{
//Dock = DockStyle.Fill,
//BackColor = Color.FromArgb(18, 30, 50),
//BorderStyle = BorderStyle.FixedSingle, // 层边框
//Margin = new Padding(2), // 层之间的间距
//Padding = new Padding(3)
Size = new Size(totalColWidth, layerTotalHeight), // 固定尺寸,和层高度一致
BackColor = Color.FromArgb(18, 30, 50),
//BorderStyle = BorderStyle.FixedSingle, // 层边框
Margin = new Padding(3), // 层之间间距(统一)
Padding = new Padding(1)
};
// 内层TableLayoutPanel:当前层的行和列
TableLayoutPanel tblBattery = new TableLayoutPanel
{
//RowCount = totalRows,
//ColumnCount = totalCols + 1,
//Dock = DockStyle.Fill, // 填充容器
//AutoSize = true,
//AutoSizeMode = AutoSizeMode.GrowAndShrink,
//BackColor = Color.Transparent,
//CellBorderStyle = TableLayoutPanelCellBorderStyle.None,
//Margin = new Padding(0),
//Padding = new Padding(5)
RowCount = rows,
ColumnCount = cols + 1,
Size = new Size(totalColWidth, layerTotalHeight - 2),
//Dock = DockStyle.Fill,
BackColor = Color.Transparent,
CellBorderStyle = TableLayoutPanelCellBorderStyle.None,
Margin = new Padding(0),
Padding = new Padding(0)
};
tblBattery.RowStyles.Clear();
for (int r = 0; r < rows; r++)
{
tblBattery.RowStyles.Add(new RowStyle(SizeType.Absolute, rowHeight));
}
tblBattery.ColumnStyles.Clear();
tblBattery.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, rowNumColWidth));
for (int c = 1; c <= cols; c++)
{
tblBattery.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, cellSize));
}
// 遍历当前层的所有行和列,生成电池控件
for (int row = 1; row <= rows; row++)
{
System.Windows.Forms.Label lblrow = new System.Windows.Forms.Label
{
Text = row.ToString(),
TextAlign = ContentAlignment.MiddleCenter,
ForeColor = Color.White,
Dock = DockStyle.Fill,
Margin = new Padding(0),
Font = new Font("Microsoft YaHei", 9, FontStyle.Bold)
};
tblBattery.Controls.Add(lblrow, 0, row - 1);
}
for (int row = 1; row <= rows; row++)
{
for (int col = 1; col <= cols; col++)
{
BatteryControl battery = new BatteryControl(grade, layer, row, col, "")
{
Name = $"BatteryControl_{stationNo}_{location}",
Size = new Size(batterySize, batterySize),
Margin = new Padding(cellPadding),
Anchor = AnchorStyles.None,
//Dock = DockStyle.None,
Dock = DockStyle.None,
Tag = $"{stationNo}-{location}",
Style = SeeSharpTools.JY.GUI.LED.LedStyle.Circular
};
// 绑定点击事件
battery.OnBatteryClicked += OnBatteryControlClicked;
// 添加到行列表格
tblBattery.Controls.Add(battery, col, row - 1);
// 加入全局管理字典
string controlKey = $"{layer}-{row}-{col}";
_batteryControlsByStationNo[stationNo][controlKey] = battery;
}
}
pnlBatteryContainer.Controls.Add(tblBattery);
layerPanel.Controls.Add(pnlBatteryContainer, 1, layer);
}
return layerPanel;
}
//创建一个整体的表格
//private TableLayoutPanel CreateLayerPanel(int stationNo, string grade, int layers, int rows, int cols)
//{
// // 布局参数
// int batterySize = 24;
// int cellPadding = 2;
// int cellSize = batterySize + cellPadding * 2;
// int layerNumWidth = 50;
// int totalPanelWidth = layerNumWidth * 2 + (cellSize * cols) + 18;
// int totalPanelHeight = cellSize * rows * layers + 50; // 每层总高度(+8px余量,确保最后一行显示)
// // 创建外层面板
// var layerPanel = new TableLayoutPanel
// {
// RowCount = layers * rows + 1,
// ColumnCount = cols + 2,
// BackColor = Color.Transparent,
// CellBorderStyle = TableLayoutPanelCellBorderStyle.Single,
// Margin = new Padding(0),
// Size = new Size(totalPanelWidth, totalPanelHeight),
// Padding = new Padding(0)
// };
// // 设置列样式
// layerPanel.ColumnStyles.Clear();
// for (int i = 0; i < layerPanel.ColumnCount; i++)
// {
// if (i < 2)
// layerPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, layerNumWidth));
// else
// layerPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, cellSize));
// }
// // 设置行样式
// layerPanel.RowStyles.Clear();
// for (int i = 0; i < layerPanel.RowCount; i++)
// {
// layerPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, cellSize));
// }
// // 添加表头
// //AddPanelHeaders(layerPanel, cols, layerNumWidth, cellSize);
// // 层数标签
// var layerHeader = new Label
// {
// Text = "层",
// TextAlign = ContentAlignment.MiddleCenter,
// ForeColor = Color.White,
// BackColor = Color.FromArgb(18, 30, 50),
// Dock = DockStyle.Fill,
// Font = new Font("Microsoft YaHei", 9, FontStyle.Bold)
// };
// layerPanel.Controls.Add(layerHeader, 0, 0);
// // 行/列表头
// var rowColHeader = new Label
// {
// Text = "行/列",
// TextAlign = ContentAlignment.MiddleCenter,
// ForeColor = Color.White,
// Dock = DockStyle.Fill,
// Margin = new Padding(0),
// Font = new Font("Microsoft YaHei", 9, FontStyle.Bold),
// BackColor = Color.FromArgb(18, 30, 50)
// };
// layerPanel.Controls.Add(rowColHeader, 1, 0);
// // 列号标签
// for (int col = 1; col <= cols; col++)
// {
// var colLabel = new Label
// {
// Text = col.ToString(),
// TextAlign = ContentAlignment.MiddleCenter,
// ForeColor = Color.White,
// Dock = DockStyle.Fill,
// Margin = new Padding(0),
// Padding = new Padding(0),
// Font = new Font("Microsoft YaHei", 9, FontStyle.Bold),
// BackColor = Color.FromArgb(18, 30, 50)
// };
// layerPanel.Controls.Add(colLabel, col + 1, 0);
// }
// // 创建电池控件
// //CreateBatteryControls(stationNo, grade, layerPanel, layers, rows, cols);
// // 初始化控件字典
// if (!_batteryControlsByStationNo.ContainsKey(stationNo))
// {
// _batteryControlsByStationNo[stationNo] = new Dictionary<string, BatteryControl>();
// }
// for (int layer = 0; layer < layers; layer++)
// {
// // 添加层数标签
// var layerLabel = new Label
// {
// Text = $"第{layer + 1}层",
// TextAlign = ContentAlignment.MiddleCenter,
// ForeColor = Color.White,
// Dock = DockStyle.Fill,
// BackColor = Color.FromArgb(18, 30, 50),
// Font = new Font("Microsoft YaHei", 9, FontStyle.Bold),
// Margin = new Padding(0)
// };
// layerPanel.Controls.Add(layerLabel, 0, layer * rows + 1);
// layerPanel.SetRowSpan(layerLabel, rows);
// // 添加行号标签
// for (int row = 1; row <= rows; row++)
// {
// var rowLabel = new Label
// {
// Text = row.ToString(),
// TextAlign = ContentAlignment.MiddleCenter,
// ForeColor = Color.White,
// Dock = DockStyle.Fill,
// Margin = new Padding(0),
// Font = new Font("Microsoft YaHei", 9, FontStyle.Bold),
// BackColor = Color.FromArgb(18, 30, 50)
// };
// layerPanel.Controls.Add(rowLabel, 1, layer * rows + row);
// for (int col = 1; col <= cols; col++)
// {
// string location = $"{layer}-{row}-{col}";
// // 创建电池控件
// var batteryControl = new BatteryControl(grade, layer, row, col, "", JinYuan.ControlLib.BatteryStatus.Init)
// {
// Name = $"BatteryControl_{stationNo}_{location}",
// Size = new Size(batterySize, batterySize),
// Margin = new Padding(cellPadding),
// Anchor = AnchorStyles.None,
// //Dock = DockStyle.None,
// Dock = DockStyle.Fill,
// Tag = $"{stationNo}-{location}",
// Style = SeeSharpTools.JY.GUI.LED.LedStyle.Circular
// };
// // 绑定点击事件
// batteryControl.OnBatteryClicked += OnBatteryControlClicked;
// // 添加到面板
// layerPanel.Controls.Add(batteryControl, col + 1, row + layer * rows);
// // 加入管理字典
// string controlKey = $"{layer}-{row}-{col}";
// _batteryControlsByStationNo[stationNo][controlKey] = batteryControl;
// }
// }
// // 创建具体电池控件
// //AddBatteryControlCells(stationNo, grade, layerPanel, layer, rows, cols, batterySize, cellPadding);
// }
// return layerPanel;
//}
/// <summary>
/// 创建电池控件
/// </summary>
private void CreateBatteryControls(int stationNo, string grade, TableLayoutPanel layerPanel, int layers, int rows, int cols)
{
// 初始化控件字典
if (!_batteryControlsByStationNo.ContainsKey(stationNo))
{
_batteryControlsByStationNo[stationNo] = new Dictionary<string, BatteryControl>();
}
int cellPadding = 1;
int batterySize = 24;
int cellSize = batterySize + cellPadding * 2;
//int rowNumWidth = 40;
for (int layer = 0; layer < layers; layer++)
{
// 添加层数标签
var layerLabel = new Label
{
Text = $"第{layer + 1}层",
TextAlign = ContentAlignment.MiddleCenter,
ForeColor = Color.White,
Dock = DockStyle.Fill,
BackColor = Color.FromArgb(18, 30, 50),
Font = new Font("Microsoft YaHei", 9, FontStyle.Bold),
Margin = new Padding(0)
};
layerPanel.Controls.Add(layerLabel, 0, layer * rows + 1);
layerPanel.SetRowSpan(layerLabel, rows);
// 添加行号标签
AddRowNumberLabels(layerPanel, layer, rows);
// 创建具体电池控件
AddBatteryControlCells(stationNo, grade, layerPanel, layer, rows, cols, batterySize, cellPadding);
}
}
/// <summary>
/// 添加电池控件单元格
/// </summary>
private void AddBatteryControlCells(int stationNo, string grade, TableLayoutPanel layerPanel,
int layer, int rows, int cols, int batterySize, int cellPadding)
{
for (int row = 1; row <= rows; row++)
{
for (int col = 1; col <= cols; col++)
{
string location = $"{layer}-{row}-{col}";
// 创建电池控件
var batteryControl = new BatteryControl(grade, layer, row, col, "", JinYuan.ControlLib.BatteryStatus.Init)
{
Name = $"BatteryControl_{stationNo}_{location}",
Size = new Size(batterySize, batterySize),
Margin = new Padding(cellPadding),
Anchor = AnchorStyles.None,
//Dock = DockStyle.None,
Dock = DockStyle.Fill,
Tag = $"{stationNo}-{location}",
Style = SeeSharpTools.JY.GUI.LED.LedStyle.Circular
};
// 绑定点击事件
batteryControl.OnBatteryClicked += OnBatteryControlClicked;
// 添加到面板
layerPanel.Controls.Add(batteryControl, col+1, row + layer * rows);
// 加入管理字典
string controlKey = $"{layer}-{row}-{col}";
_batteryControlsByStationNo[stationNo][controlKey] = batteryControl;
}
}
}
/// <summary>
/// 创建统计信息GroupBox
/// </summary>
private GroupBoxEX CreateStatisticsGroupBox(int stationNo, string grade, out List<Label> statLabels)
{
statLabels = new List<Label>();
var groupBox = new GroupBoxEX
{
Height = 70,
Margin = new Padding(0, 5, 0, 0),
Font = new Font("微软雅黑", 9F),
ForeColor = Color.White,
BackColor = Color.FromArgb(14, 23, 38),
Text = $"叠盘位{stationNo}-{grade}等级统计",
AutoSize = true, // 自动适配内容
AutoSizeMode = AutoSizeMode.GrowOnly
};
// 创建表格布局
var tableLayout = new TableLayoutPanel
{
Dock = DockStyle.Fill,
ColumnCount = 2,
RowCount = 2,
CellBorderStyle = TableLayoutPanelCellBorderStyle.None,
BackColor = Color.Transparent,
Margin = new Padding(2),
AutoSize = true
};
// 设置行列样式
tableLayout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));
tableLayout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));
tableLayout.RowStyles.Add(new RowStyle(SizeType.Percent, 50F));
tableLayout.RowStyles.Add(new RowStyle(SizeType.Percent, 50F));
// 添加统计标签
for (int i = 0; i < _statusDisplayNames.Length; i++)
{
var label = new Label
{
Text = $"{_statusDisplayNames[i]}:0",
AutoSize = true,
TextAlign = ContentAlignment.MiddleLeft,
Font = new Font("微软雅黑", 9),
ForeColor = Color.White,
Margin = new Padding(5, 1, 0, 1)
};
int row = i / 2;
int col = i % 2;
tableLayout.Controls.Add(label, col, row);
statLabels.Add(label);
}
groupBox.Controls.Add(tableLayout);
return groupBox;
}
#endregion
#region 数据绑定与更新相关方法
/// <summary>
/// 批量绑定电池数据
/// </summary>
/// <param name="stationNo">机架号</param>
/// <param name="batteryList">电池数据列表</param>
public void BindBatteryData(int stationNo, List<BatteryEntity> batteryList)
{
if (batteryList == null || batteryList.Count == 0 || stationNo < 1 || stationNo > 3) return;
BeginInvoke(() =>
{
try
{
// 暂停列表事件触发
_allBatteryRecords.RaiseListChangedEvents = false;
_ngBatteryRecords.RaiseListChangedEvents = false;
foreach (var battery in batteryList)
{
_allBatteryRecords.Add(battery);
var (layer, row, col) = SplitLocation(battery.location);
string controlKey = $"{layer}-{row}-{col}";
// 更新控件状态
if (_batteryControlsByStationNo.TryGetValue(stationNo, out var locControls) &&
locControls.TryGetValue(controlKey, out var batteryControl) &&
IsControlValid(batteryControl))
{
var status = battery.packResult ? JinYuan.ControlLib.BatteryStatus.Normal : JinYuan.ControlLib.BatteryStatus.PackNG;
batteryControl.BindData(battery.identification, status, battery.containerCode);
//RefreshControl(batteryControl);
// 更新条码映射
if (!string.IsNullOrEmpty(battery.identification))
{
_barcodeToControlMap[battery.identification] = (stationNo, controlKey);
}
// 添加到NG列表(去重)
if (!battery.packResult && !_ngBatteryRecords.Any(b => b.identification == battery.identification))
{
_ngBatteryRecords.Add(battery);
}
}
}
// 恢复事件触发并刷新
_allBatteryRecords.RaiseListChangedEvents = true;
_ngBatteryRecords.RaiseListChangedEvents = true;
_allBatteryRecords.ResetBindings();
_ngBatteryRecords.ResetBindings();
// 更新统计信息
UpdateBatteryStatistics(stationNo);
}
catch (Exception ex)
{
LogHelper.Instance.WriteError($"批量绑定电池数据异常:{ex}", "BatteryStatusLog");
}
});
}
/// <summary>
/// 单个电池数据绑定
/// </summary>
//public void ModifyBindBatteryData(int stationNo, BatteryControl batteryControl,
// string barcode, JinYuan.ControlLib.BatteryStatus status, string containerCode = "")
//{
// if (stationNo < 1 || stationNo > 3) return;
// if (IsControlValid(batteryControl))
// {
// Invoke(() =>
// {
// batteryControl.BindData(barcode, status, containerCode);
// RefreshControlPartial(batteryControl);
// // 更新条码映射
// if (!string.IsNullOrEmpty(barcode))
// {
// string controlKey = $"{batteryControl.Layer}-{batteryControl.Row}-{batteryControl.Col}";
// _barcodeToControlMap[barcode] = (stationNo, controlKey);
// }
// });
// }
//}
public void ModifyBindBatteryData(int stationNo, BatteryControl batteryControl,
string barcode, JinYuan.ControlLib.BatteryStatus status, string containerCode = "")
{
if (stationNo < 1 || stationNo > 3 || batteryControl == null) return;
SafeUI(() =>
{
if (!batteryControl.IsDisposed)
{
batteryControl.BindData(barcode, status, containerCode);
RefreshControlPartial(batteryControl);
}
if (!string.IsNullOrEmpty(barcode))
{
string key = $"{batteryControl.Layer}-{batteryControl.Row}-{batteryControl.Col}";
_barcodeToControlMap[barcode] = (stationNo, key);
}
});
}
/// <summary>
/// 更新电池统计信息
/// </summary>
public void UpdateBatteryStatistics(int stationNo)
{
if (!Visible || IsDisposed || stationNo < 1 || stationNo > 3) return;
// 防抖:200ms内不重复更新
if (DateTime.Now - _lastStatisticsUpdateTime < TimeSpan.FromMilliseconds(200))
return;
_lastStatisticsUpdateTime = DateTime.Now;
SafeUI(() => UpdateStatisticsInternal(stationNo));
//if (InvokeRequired)
//{
// BeginInvoke(() => UpdateStatisticsInternal(stationNo));
//}
//else
//{
// UpdateStatisticsInternal(stationNo);
//}
}
/// <summary>
/// 统计信息更新内部逻辑
/// </summary>
private void UpdateStatisticsInternal(int stationNo)
{
if (!_statisticsLabelsByLoc.TryGetValue(stationNo, out var labels) || labels.Count < 4)
return;
// 初始化状态计数
var statusCounts = new Dictionary<JinYuan.ControlLib.BatteryStatus, int>
{
{ JinYuan.ControlLib.BatteryStatus.Replacing, 0 },
{ JinYuan.ControlLib.BatteryStatus.PackNG, 0 },
{ JinYuan.ControlLib.BatteryStatus.Normal, 0 },
{ JinYuan.ControlLib.BatteryStatus.Init, 0 }
};
lock (_batteryControlsByStationNo)
{
if (_batteryControlsByStationNo.TryGetValue(stationNo, out var controls))
{
foreach (var control in controls.Values)
{
if (IsControlValid(control) && statusCounts.ContainsKey(control.Status))
{
statusCounts[control.Status]++;
}
}
}
}
SafeUI(() =>
{
labels[0].Text = $"{_statusDisplayNames[0]}:{statusCounts[JinYuan.ControlLib.BatteryStatus.Replacing]}";
labels[1].Text = $"{_statusDisplayNames[1]}:{statusCounts[JinYuan.ControlLib.BatteryStatus.PackNG]}";
labels[2].Text = $"{_statusDisplayNames[2]}:{statusCounts[JinYuan.ControlLib.BatteryStatus.Normal]}";
labels[3].Text = $"{_statusDisplayNames[3]}:{statusCounts[JinYuan.ControlLib.BatteryStatus.Init]}";
});
}
/// <summary>
/// 清理电池数据
/// </summary>
/// <param name="stationNo">档位(0=全部)</param>
/// <param name="containerCode">容器码</param>
//public void ClearBatteryData(int stationNo = 0, string containerCode = null)
//{
// BeginInvoke(() =>
// {
// try
// {
// var controlsToClear = new List<BatteryControl>();
// // 筛选要清理的控件
// if (stationNo == 0 && string.IsNullOrEmpty(containerCode))
// {
// // 清空所有
// foreach (var locControls in _batteryControlsByStationNo.Values)
// {
// controlsToClear.AddRange(locControls.Values);
// }
// }
// else if (stationNo > 0 && stationNo <= 3)
// {
// // 清空指定档位
// if (_batteryControlsByStationNo.TryGetValue(stationNo, out var locControls))
// {
// controlsToClear = string.IsNullOrEmpty(containerCode)
// ? locControls.Values.ToList()
// : locControls.Values.Where(b => b.Container == containerCode).ToList();
// }
// }
// // 暂停DataGridView布局
// dgv_ngRsn?.SuspendLayout();
// // 清理控件和数据
// foreach (var battery in controlsToClear)
// {
// // 从NG列表移除
// RemoveBatteryFromNgList(battery.Barcode);
// // 清空控件
// battery.Clear();
// RefreshControlPartial(battery);
// // 从条码映射移除
// if (!string.IsNullOrEmpty(battery.Barcode) && _barcodeToControlMap.ContainsKey(battery.Barcode))
// {
// _barcodeToControlMap.Remove(battery.Barcode);
// }
// }
// // 恢复布局
// if (dgv_ngRsn != null && dgv_ngRsn.IsHandleCreated)
// {
// dgv_ngRsn.ResumeLayout(false);
// dgv_ngRsn.Invalidate();
// }
// }
// catch (Exception ex)
// {
// LogHelper.Instance.WriteError($"清理电池数据异常:{ex}", "BatteryStatusLog");
// }
// });
//}
public void ClearBatteryData(int stationNo = 0, string containerCode = null)
{
SafeUI(() =>
{
try
{
List<BatteryControl> clearList = new List<BatteryControl>();
if (stationNo == 0 && string.IsNullOrEmpty(containerCode))
{
foreach (var dic in _batteryControlsByStationNo.Values)
clearList.AddRange(dic.Values);
}
else if (stationNo >= 1 && stationNo <= 3)
{
if (_batteryControlsByStationNo.TryGetValue(stationNo, out var dic))
{
clearList = string.IsNullOrEmpty(containerCode)
? dic.Values.ToList()
: dic.Values.Where(b => b.Container == containerCode).ToList();
}
}
dgv_ngRsn?.SuspendLayout();
foreach (var b in clearList)
{
if (b == null || b.IsDisposed) continue;
RemoveBatteryFromNgList(b.Barcode);
b.Clear();
RefreshControlPartial(b);
if (!string.IsNullOrEmpty(b.Barcode))
_barcodeToControlMap.Remove(b.Barcode);
}
dgv_ngRsn?.ResumeLayout(true);
dgv_ngRsn?.Invalidate();
}
catch (Exception ex)
{
LogHelper.Instance.WriteError($"清理电池数据异常:{ex}", "BatteryStatusLog");
}
});
}
#endregion
#region 事件处理方法
/// <summary>
/// 电池控件点击事件
/// </summary>
private void OnBatteryControlClicked(BatteryControl battery)
{
// 防抖
if (DateTime.Now - _lastBatteryClickTime < TimeSpan.FromMilliseconds(200))
return;
_lastBatteryClickTime = DateTime.Now;
// 高亮表格行
if (!string.IsNullOrEmpty(battery.Barcode))
{
HighlightGridViewRow(battery.Barcode);
}
// 更新UI
UpdateBatteryInfoDisplay(battery);
}
/// <summary>
/// 条码搜索按钮点击事件
/// </summary>
private void btn_Search_Click(object sender, EventArgs e)
{
string barcode = FilterBarcodeChars(txtBox_Barcode?.Text?.Trim() ?? "");
if (string.IsNullOrEmpty(barcode))
{
txtBox_Barcode?.Focus();
MessageBox.Show("请输入待查询的电芯条码!");
return;
}
// 查找电池控件
var batteryControl = FindBatteryControlByBarcode(barcode);
if (batteryControl != null)
{
// 更新显示信息
UpdateBatteryInfoDisplay(batteryControl);
// 闪烁提示
batteryControl.BlinkOn = true;
batteryControl.BlinkInterval = 500;
// 2秒后停止闪烁
Task.Delay(2000, _cancellationTokenSource.Token).ContinueWith(t =>
{
if (t.IsCanceled || t.IsFaulted) return;
SafeUI(() =>
{
try
{
// 校验控件有效性
if (batteryControl != null && !batteryControl.IsDisposed)
{
batteryControl.BlinkOn = false;
}
}
catch (ObjectDisposedException)
{
// 预期异常:控件已释放,无需处理
}
catch (Exception ex)
{
LogHelper.Instance.WriteError($"停止电池闪烁异常:{ex}", "BatteryStatusLog");
}
}, true);
}, _cancellationTokenSource.Token);
}
else
{
MessageBox.Show($"未找到条码为{barcode}的电池!");
}
}
/// <summary>
/// 条码替换按钮点击事件
/// </summary>
private async void btn_SubBarcode_Click(object sender, EventArgs e)
{
if (!await _operationSemaphore.WaitAsync(0, _cancellationTokenSource.Token).ConfigureAwait(false))
{
MessageBox.Show("当前有操作正在执行,请稍候!");
return;
}
try
{
// 获取输入
string oldBarcode = FilterBarcodeChars(txtBox_Barcode?.Text?.Trim() ?? "");
string newBarcode = FilterBarcodeChars(txtBox_SubBarcode?.Text?.Trim() ?? "");
string containerCode = FilterBarcodeChars(txtBox_Carton?.Text?.Trim() ?? "");
// 输入验证
if (!ValidateBarcodeInput(oldBarcode, newBarcode))
{
return;
}
//// 查找原条码位置
int stationNo = 0;
if (_barcodeToControlMap.TryGetValue(oldBarcode, out var mapValue))
{
stationNo = mapValue.stationNo;
}
else
{
// 遍历查找
stationNo = FindBatteryLocByBarcode(oldBarcode);
if (stationNo == 0)
{
MessageBox.Show($"电池【{oldBarcode}】不在当前叠盘位内!");
return;
}
}
// 查找电池控件
var batteryControl = FindBatteryControlByBarcode(oldBarcode);
if (batteryControl == null)
{
MessageBox.Show($"电池【{oldBarcode}】不在当前叠盘位内!");
return;
}
//数据库验证
var oldBatteryList = await Task.Run(() =>
CommonMethods.db.QueryWhereList<BatteryEntity>(it => it.identification == oldBarcode)).ConfigureAwait(false);
if (oldBatteryList == null || oldBatteryList.Count == 0)
{
LogHelper.Instance.WriteError($"本地数据库无该电池条码{oldBarcode}", "SysErrorLog");
MessageBox.Show("电池未绑定过,不能替换");
return;
}
// 检查新条码是否存在
if (await IsBarcodeExistsAsync(newBarcode).ConfigureAwait(false))
{
MessageBox.Show($"新条码【{newBarcode}】已存在,无法替换!");
return;
}
BatteryEntity battery = new BatteryEntity()
{
identification = batteryControl.Barcode,
location = $"{batteryControl.Layer}-{batteryControl.Row}-{batteryControl.Col}",
grade = batteryControl.Grade,
containerCode = batteryControl.Container,
};
// 确认替换
if (MessageBox.Show($"确认将原条码【{oldBarcode}】替换为新条码【{newBarcode}】吗?", "确认", MessageBoxButtons.YesNo, MessageBoxIcon.Question) != DialogResult.Yes)
{
return;
}
// 执行数据库更新
bool replaceSuccess = true; //await UpdateBarcodeInDatabase(oldBatteryList, newBarcode);
// 更新UI
if (replaceSuccess)
{
//var (layer, row, col) = SplitLocation(location);
// 更新控件状态
ModifyBindBatteryData(stationNo, batteryControl, oldBarcode, JinYuan.ControlLib.BatteryStatus.Replacing, containerCode);
ModifyBindBatteryData(stationNo, batteryControl, newBarcode, JinYuan.ControlLib.BatteryStatus.Normal, containerCode);
// 记录替换信息
AddReplaceRecord(oldBarcode, newBarcode, battery, "替换成功");
// 从NG列表移除原条码
RemoveBatteryFromNgList(oldBarcode);
MessageBox.Show("条码替换成功!", "成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
// 清空输入框
ClearInputTextBoxes();
}
else
{
AddReplaceRecord(oldBarcode, newBarcode, battery, "数据库更新失败");
MessageBox.Show("条码替换失败,请检查条码是否存在!", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
catch (Exception ex)
{
LogHelper.Instance.WriteError($"条码替换异常:{ex}", "SysErrorLog");
MessageBox.Show($"替换失败:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
_operationSemaphore.Release();
}
}
/// <summary>
/// 清空按钮点击事件
/// </summary>
private async void btn_clear_Click(object sender, EventArgs e)
{
if (!await _operationSemaphore.WaitAsync(0, _cancellationTokenSource.Token).ConfigureAwait(false)) return;
try
{
ClearInputTextBoxes();
}
catch (Exception ex)
{
LogHelper.Instance.WriteError($"清空输入框异常:{ex}", "SysErrorLog");
MessageBox.Show($"清空失败:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
_operationSemaphore.Release();
}
}
/// <summary>
/// 强制放行按钮点击事件
/// </summary>
private async void btn_ForceOut_Click(object sender, EventArgs e)
{
if (!await _operationSemaphore.WaitAsync(0, _cancellationTokenSource.Token).ConfigureAwait(false))
return;
try
{
// 验证配置
if (!ValidatePlcConfiguration())
{
return;
}
// 获取容器码
string containerCode = GetSelectedContainerCode();
if (string.IsNullOrEmpty(containerCode))
{
MessageBox.Show("未获取到容器码,不能继续执行");
return;
}
// 确认操作
if (MessageBox.Show("确认执行强制放行吗?", "确认", MessageBoxButtons.YesNo, MessageBoxIcon.Question) != DialogResult.Yes)
return;
// 执行PLC操作
await Task.Run(() =>
{
if (CommonMethods.plcDevices.Count() > 0)
{
for (int i = 0; i < CommonMethods.plcDevices.Count(); i++)
{
if (CommonMethods.plcDevices[i].IsConnected && CommonMethods.plcDevices[i].Name == "PLC_1")
{
CommonMethods.plcDevices[i].WriteInt16("ForceOutStation", 1);
CommonMethods.AddDataMonitorLog(0, $"已触发强制放行信号,容器码:{containerCode}");
}
}
}
}, _cancellationTokenSource.Token).ConfigureAwait(false);
}
catch (Exception ex)
{
LogHelper.Instance.WriteError($"强制放行异常:{ex}", "SysErrorLog");
MessageBox.Show($"强制放行失败:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
_operationSemaphore.Release();
}
}
/// <summary>
/// 重新组盘按钮点击事件
/// </summary>
private async void btn_repacking_Click(object sender, EventArgs e)
{
if (!await _operationSemaphore.WaitAsync(0, _cancellationTokenSource.Token).ConfigureAwait(false))
return;
try
{
// 验证配置
if (!ValidatePlcConfiguration())
{
return;
}
// 确认操作
if (MessageBox.Show("确认执行组盘操作吗?", "确认", MessageBoxButtons.YesNo, MessageBoxIcon.Question) != DialogResult.Yes)
return;
// 执行操作
await Task.Run(() =>
{
CommonMethods.AddDataMonitorLog(0, "执行重新组盘操作");
}, _cancellationTokenSource.Token).ConfigureAwait(false);
}
catch (Exception ex)
{
LogHelper.Instance.WriteError($"组盘异常:{ex}", "SysErrorLog");
MessageBox.Show($"组盘失败:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
_operationSemaphore.Release();
}
}
#endregion
#region 辅助方法
/// <summary>
/// 拆分位置字符串
/// </summary>
public (int layer, int row, int col) SplitLocation(string location)
{
if (string.IsNullOrEmpty(location))
return (0, 0, 0);
var parts = location.Split('-');
int layer = parts.Length > 0 && int.TryParse(parts[0], out var l) ? l : 0;
int row = parts.Length > 1 && int.TryParse(parts[1], out var r) ? r : 0;
int col = parts.Length > 2 && int.TryParse(parts[2], out var c) ? c : 0;
return (layer, row, col);
}
/// <summary>
/// 解析位置编号
/// </summary>
public string ParseLocation(int layerNum, int number)
{
try
{
if (CommonMethods.mesConfig == null)
throw new InvalidOperationException("MES配置未初始化");
int row = number / CommonMethods.mesConfig.colsPerLayer + 1; // 行
int col = (number % CommonMethods.mesConfig.colsPerLayer) + 1; // 列
return $"{layerNum}-{row}-{col}";
}
catch (Exception ex)
{
throw new InvalidOperationException($"解析位置失败: {ex.Message}", ex);
}
}
/// <summary>
/// 过滤条码无效字符
/// </summary>
private string FilterBarcodeChars(string barcode)
{
if (string.IsNullOrEmpty(barcode)) return string.Empty;
return barcode.Replace("\r", "").Replace("\n", "").Replace("\t", "").Trim();
}
/// <summary>
/// 检查条码是否存在
/// </summary>
private async Task<bool> IsBarcodeExistsAsync(string barcode)
{
if (string.IsNullOrEmpty(barcode)) return false;
try
{
return await Task.Run(() =>
{
var batteryList = CommonMethods.db.QueryWhereList<BatteryEntity>(it => it.identification == barcode);
return batteryList != null && batteryList.Count > 0;
}).ConfigureAwait(false);
}
catch (Exception ex)
{
LogHelper.Instance.WriteError($"校验条码是否存在异常:{ex}", "SysErrorLog");
return false;
}
}
/// <summary>
/// 高亮表格行
/// </summary>
private void HighlightGridViewRow(string barcode)
{
if (string.IsNullOrEmpty(barcode) || dgv_ngRsn == null || !dgv_ngRsn.IsHandleCreated) return;
try
{
BeginInvoke(() =>
{
dgv_ngRsn.ClearSelection();
foreach (DataGridViewRow row in dgv_ngRsn.Rows)
{
if (!row.IsNewRow && row.Cells["identification"]?.Value?.ToString() == barcode)
{
row.Selected = true;
row.DefaultCellStyle.BackColor = Color.Yellow;
dgv_ngRsn.FirstDisplayedScrollingRowIndex = row.Index;
// 3秒后恢复颜色
Task.Delay(3000, _cancellationTokenSource.Token).ContinueWith(t =>
{
if (!t.IsCanceled && IsHandleCreated)
{
Invoke(() => row.DefaultCellStyle.BackColor = Color.Transparent);
}
}, _cancellationTokenSource.Token);
break;
}
}
});
}
catch (Exception ex)
{
LogHelper.Instance.WriteError($"高亮表格行异常:{ex}", "BatteryStatusLog");
}
}
/// <summary>
/// 验证控件是否有效
/// </summary>
private bool IsControlValid(Control control)
{
return control != null && !control.IsDisposed && control.IsHandleCreated;
}
/// <summary>
/// 添加替换记录
/// </summary>
private void AddReplaceRecord(string oldBarcode, string newBarcode, BatteryEntity battery, string remark)
{
try
{
BeginInvoke(() =>
{
var record = new BatteryReplace
{
OldBarCode = oldBarcode,
NewBarCode = newBarcode,
ReplaceTime = DateTime.Now,
GongWei = CommonMethods.sysConfig?.GongWei ?? "",
Location = battery.location,
VassoioID = battery.containerCode,
Grade = battery.grade,
Remark = remark
};
_replaceRecords.Add(record);
// 触发外部委托
CommonMethods.ShowBatteryReplaceDelegate?.Invoke(new List<BatteryReplace> { record });
});
}
catch (Exception ex)
{
LogHelper.Instance.WriteError($"添加替换记录异常:{ex}", "BatteryStatusLog");
}
}
/// <summary>
/// 从NG列表移除电池
/// </summary>
private void RemoveBatteryFromNgList(string barcode)
{
if (string.IsNullOrEmpty(barcode)) return;
for (int i = _ngBatteryRecords.Count - 1; i >= 0; i--)
{
if (_ngBatteryRecords[i].identification == barcode)
{
_ngBatteryRecords.RemoveAt(i);
break;
}
}
}
/// <summary>
/// 清空输入框
/// </summary>
private void ClearInputTextBoxes()
{
txtBox_Row?.Clear();
txtBox_Carton?.Clear();
txtBox_Barcode?.Clear();
txtBox_SubBarcode?.Clear();
}
/// <summary>
/// 验证PLC配置
/// </summary>
private bool ValidatePlcConfiguration()
{
if (CommonMethods.mesConfig == null || CommonMethods.plcDevices == null ||
CommonMethods.plcDevices.Count == 0 || !CommonMethods.mesConfig.isConnected)
{
MessageBox.Show("MES配置或PLC设备未初始化/未连接,无法执行操作!",
"提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return false;
}
return true;
}
/// <summary>
/// 获取选中的容器码
/// </summary>
private string GetSelectedContainerCode()
{
return dgv_ngRsn?.Rows.Count > 0
? dgv_ngRsn.Rows[0].Cells["containerCode"]?.Value?.ToString()?.Trim()
: string.Empty;
}
/// <summary>
/// 验证条码输入
/// </summary>
private bool ValidateBarcodeInput(string oldBarcode, string newBarcode)
{
if (string.IsNullOrEmpty(oldBarcode) || string.IsNullOrEmpty(newBarcode))
{
MessageBox.Show("原条码和新条码均不能为空!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
if (string.IsNullOrEmpty(oldBarcode))
txtBox_Barcode?.Focus();
else
{
txtBox_SubBarcode?.Focus();
txtBox_SubBarcode?.SelectAll();
}
return false;
}
if (oldBarcode == newBarcode)
{
MessageBox.Show("原条码和新条码不能一致!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
txtBox_SubBarcode?.Focus();
txtBox_SubBarcode?.SelectAll();
return false;
}
return true;
}
/// <summary>
/// 更新数据库中的条码
/// </summary>
private async Task<bool> UpdateBarcodeInDatabase(List<BatteryEntity> batteryList, string newBarcode)
{
return await Task.Run(() =>
{
try
{
foreach (var entity in batteryList)
{
entity.identification = newBarcode;
CommonMethods.db.Update(entity);
}
return true;
}
catch (Exception ex)
{
LogHelper.Instance.WriteError($"数据库替换条码异常:{ex}", "SysErrorLog");
return false;
}
}).ConfigureAwait(false);
}
/// <summary>
/// 根据条码查找电池位置
/// </summary>
private int FindBatteryLocByBarcode(string barcode)
{
for (int i = 1; i <= 3; i++)
{
if (_batteryControlsByStationNo.TryGetValue(i, out var controls))
{
if (controls.Values.Any(b => b.Barcode == barcode))
{
return i;
}
}
}
return 0;
}
/// <summary>
/// 根据条码查找电池控件
/// </summary>
private BatteryControl FindBatteryControlByBarcode(string barcode)
{
if (!string.IsNullOrEmpty(barcode) && _barcodeToControlMap.TryGetValue(barcode, out var mapValue))
{
if (_batteryControlsByStationNo.TryGetValue(mapValue.stationNo, out var locControls) &&
locControls.TryGetValue(mapValue.controlKey, out var batteryControl) &&
IsControlValid(batteryControl))
{
return batteryControl;
}
}
// 映射表未找到时,遍历所有控件(兜底)
foreach (var locControls in _batteryControlsByStationNo.Values)
{
var battery = locControls.Values.FirstOrDefault(b => b.Barcode == barcode);
if (battery != null)
{
return battery;
}
}
return null;
}
/// <summary>
/// 更新电池信息显示
/// </summary>
private void UpdateBatteryInfoDisplay(BatteryControl battery)
{
try
{
Invoke(() =>
{
string position = $"{battery.Layer}-{battery.Row}-{battery.Col}";
if (txtBox_Row != null && !txtBox_Row.IsDisposed)
txtBox_Row.Text = position;
if (txtBox_Barcode != null && !txtBox_Barcode.IsDisposed)
txtBox_Barcode.Text = battery.Barcode ?? "";
if (txtBox_Carton != null && !txtBox_Carton.IsDisposed)
txtBox_Carton.Text = battery.Container ?? "";
});
}
catch (Exception ex)
{
LogHelper.Instance.WriteError($"更新电池信息显示异常: {ex}", "BatteryStatusLog");
}
}
/// <summary>
/// 设置标签页文本
/// </summary>
private void SetTabPageText(int stationNo, string grade)
{
switch (stationNo)
{
case 1: tabPagePlus1.Text = $"1_{grade}"; break;
case 2: tabPagePlus2.Text = $"2_{grade}"; break;
case 3: tabPagePlus3.Text = $"3_{grade}"; break;
}
}
/// <summary>
/// 添加面板表头
/// </summary>
private void AddPanelHeaders(TableLayoutPanel panel, int cols, int rowNumWidth, int cellSize)
{
// 层数标签
var layerHeader = new Label
{
Text = "层",
TextAlign = ContentAlignment.MiddleCenter,
ForeColor = Color.White,
BackColor = Color.FromArgb(18, 30, 50),
Dock = DockStyle.Fill,
Font = new Font("Microsoft YaHei", 9, FontStyle.Bold)
};
panel.Controls.Add(layerHeader, 0, 0);
// 行/列表头
var rowColHeader = new Label
{
Text = "行/列",
TextAlign = ContentAlignment.MiddleCenter,
ForeColor = Color.White,
Dock = DockStyle.Fill,
Margin = new Padding(0),
Font = new Font("Microsoft YaHei", 9, FontStyle.Bold),
BackColor = Color.FromArgb(18, 30, 50)
};
panel.Controls.Add(rowColHeader, 1, 0);
// 列号标签
for (int col = 0; col < cols; col++)
{
var colLabel = new Label
{
Text = col.ToString(),
TextAlign = ContentAlignment.MiddleCenter,
ForeColor = Color.White,
Dock = DockStyle.Fill,
Margin = new Padding(0),
Padding = new Padding(0),
Font = new Font("Microsoft YaHei", 9, FontStyle.Bold),
BackColor = Color.FromArgb(18, 30, 50)
};
panel.Controls.Add(colLabel, col+2, 0);
}
//panel.Controls.Add(colHeaderPanel, 1, 0);
}
/// <summary>
/// 配置单元格面板样式
/// </summary>
private void ConfigureCellPanelStyles(TableLayoutPanel panel, int rows, int cols, int cellSize, int rowNumWidth)
{
// 行样式
panel.RowStyles.Clear();
for (int r = 0; r < rows; r++)
{
panel.RowStyles.Add(new RowStyle(SizeType.Absolute, cellSize));
}
// 列样式
panel.ColumnStyles.Clear();
panel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, rowNumWidth));
for (int c = 1; c <= cols; c++)
{
panel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, cellSize));
}
panel.CellBorderStyle = TableLayoutPanelCellBorderStyle.None;
panel.Margin = new Padding(0);
panel.Padding = new Padding(0);
}
/// <summary>
/// 添加行号标签
/// </summary>
private void AddRowNumberLabels(TableLayoutPanel panel, int layer, int rows)
{
for (int row = 0; row < rows; row++)
{
var rowLabel = new Label
{
Text = (row + 1).ToString(),
TextAlign = ContentAlignment.MiddleCenter,
ForeColor = Color.White,
Dock = DockStyle.Fill,
Margin = new Padding(0),
Font = new Font("Microsoft YaHei", 9, FontStyle.Bold),
BackColor = Color.FromArgb(18, 30, 50)
};
panel.Controls.Add(rowLabel, 1, layer * rows + row);
}
}
/// <summary>
/// 设置面板可见性
/// </summary>
private void SetPanelsVisibility(bool visible)
{
SafeUI(() =>
{
if (panelExt_Grade1 != null && !panelExt_Grade1.IsDisposed)
panelExt_Grade1.Visible = visible;
if (panelExt_Grade2 != null && !panelExt_Grade2.IsDisposed)
panelExt_Grade2.Visible = visible;
if (panelExt_Grade3 != null && !panelExt_Grade3.IsDisposed)
panelExt_Grade3.Visible = visible;
});
}
/// <summary>
/// 暂停面板布局
/// </summary>
private void SuspendPanelsLayout()
{
panelExt_Grade1?.SuspendLayout();
panelExt_Grade2?.SuspendLayout();
panelExt_Grade3?.SuspendLayout();
}
/// <summary>
/// 恢复面板布局
/// </summary>
private void ResumePanelsLayout()
{
panelExt_Grade1?.ResumeLayout(false);
panelExt_Grade2?.ResumeLayout(false);
panelExt_Grade3?.ResumeLayout(false);
}
/// <summary>
/// 清空面板控件
/// </summary>
private void ClearPanelsControls()
{
panelExt_Grade1?.Controls.Clear();
panelExt_Grade2?.Controls.Clear();
panelExt_Grade3?.Controls.Clear();
}
/// <summary>
/// 释放电池控件
/// </summary>
private void DisposeBatteryControls()
{
foreach (var locControls in _batteryControlsByStationNo.Values)
{
foreach (var battery in locControls.Values)
{
battery.Dispose();
}
}
}
/// <summary>
/// 清空所有面板
/// </summary>
private void ClearAllPanels()
{
panelExt_Grade1?.Controls.Clear();
panelExt_Grade2?.Controls.Clear();
panelExt_Grade3?.Controls.Clear();
}
#endregion
#region 公共显示方法(对外接口)
/// <summary>
/// 显示NG电池列表
/// </summary>
public void ShowBatteryNGRsn(List<BatteryEntity> list)
{
list ??= new List<BatteryEntity>();
//// 确保在UI线程执行
//if (InvokeRequired)
//{
// Invoke(new Action(() => ShowBatteryNGRsn(list)));
// return;
//}
//// 强制关闭自动生成列(避免列名混乱)
//dgv_ngRsn.AutoGenerateColumns = false;
//dgv_ngRsn?.SuspendLayout();
//try
//{
// // 筛选NG电池
// var ngItems = list.Where(b => !b.packResult).ToList();
// if (ngItems.Count == 0)
// {
// Debug.WriteLine("无NG数据");
// return;
// }
// // 暂停列表事件
// _ngBatteryRecords.RaiseListChangedEvents = false;
// foreach (var item in ngItems)
// {
// var existingItem = _ngBatteryRecords.FirstOrDefault(x => x.identification == item.identification);
// if (existingItem != null)
// {
// // 更新原有记录
// existingItem.location = item.location;
// existingItem.grade = item.grade;
// existingItem.packResult = item.packResult;
// existingItem.outStationType = item.outStationType;
// existingItem.packFalseReason = item.packFalseReason;
// existingItem.containerCode = item.containerCode;
// existingItem.packTime = item.packTime;
// }
// else
// {
// _ngBatteryRecords.Add(item);
// }
// }
// _ngBatteryRecords.RaiseListChangedEvents = true;
// _ngBatteryRecords.ResetBindings();
// if (_ngBatteryRecords.Count > 0)
// {
// dgv_ngRsn.ClearSelection();
// }
// dgv_ngRsn?.ResumeLayout(false);
// // 强制刷新表格单元格
// dgv_ngRsn.Invalidate();
// //dgv_ngRsn.Invalidate(true); // 强制重绘整个控件
//}
//catch (Exception ex)
//{
// LogHelper.Instance.WriteError($"显示NG电池异常:{ex}", "BatteryStatusLog");
//}
//finally
//{
// dgv_ngRsn?.ResumeLayout(true);
//}
SafeUI(() =>
{
dgv_ngRsn.AutoGenerateColumns = false;
dgv_ngRsn.SuspendLayout();
try
{
var ngItems = list.Where(b => !b.packResult).ToList();
_ngBatteryRecords.RaiseListChangedEvents = false;
foreach (var item in ngItems)
{
var exist = _ngBatteryRecords.FirstOrDefault(x => x.identification == item.identification);
if (exist != null)
{
exist.location = item.location;
exist.grade = item.grade;
exist.packResult = item.packResult;
exist.packFalseReason = item.packFalseReason;
exist.containerCode = item.containerCode;
}
else
{
_ngBatteryRecords.Add(item);
}
}
_ngBatteryRecords.RaiseListChangedEvents = true;
_ngBatteryRecords.ResetBindings();
dgv_ngRsn.ResumeLayout(true);
dgv_ngRsn.Invalidate();
}
catch
{
}
});
}
private void dgv_ngRsn_RowPostPaint(object sender, DataGridViewRowPostPaintEventArgs e)
{
//显示序列号
DataGridViewHelper.DgvRowPostPaint(this.dgv_ngRsn, e);
}
private void dgv_ngRsn_RowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e)
{
//指定列字体颜色
DataGridViewHelper.DgvRowPrePaint(this.dgv_ngRsn, "packResult", sender, e);
}
/// <summary>
/// 显示替换记录
/// </summary>
public void ShowBatteryReplace(List<BatteryReplace> list)
{
list ??= new List<BatteryReplace>();
try
{
BeginInvoke(() =>
{
dgvReplaceBattery?.SuspendLayout();
// 限制记录数量(最多500条)
if (_replaceRecords.Count > 500)
{
var tempList = _replaceRecords.Skip(_replaceRecords.Count - 500).ToList();
_replaceRecords.Clear();
foreach (var item in tempList)
{
_replaceRecords.Add(item);
}
}
// 添加新记录
foreach (var item in list)
{
if (!_replaceRecords.Any(x => x.OldBarCode == item.OldBarCode && x.NewBarCode == item.NewBarCode))
{
_replaceRecords.Add(item);
}
}
dgvReplaceBattery?.ResumeLayout(false);
dgvReplaceBattery?.Invalidate();
});
}
catch (Exception ex)
{
LogHelper.Instance.WriteError($"显示替换记录异常:{ex}", "BatteryStatusLog");
}
}
private void dgvReplaceBattery_RowPostPaint(object sender, DataGridViewRowPostPaintEventArgs e)
{
//显示序列号
DataGridViewHelper.DgvRowPostPaint(this.dgvReplaceBattery, e);
}
/// <summary>
/// 显示电池状态
/// </summary>
public void ShowBatteryStatus(int stationNo, List<BatteryEntity> list)
{
if (list == null || list.Count == 0) return;
try
{
BindBatteryData(stationNo, list);
}
catch (Exception ex)
{
LogHelper.Instance.WriteError($"显示电池状态失败:{ex}", "BatteryStatusLog");
}
}
/// <summary>
/// 局部刷新控件(仅重绘变化区域,避免全局卡顿)
/// </summary>
/// <param name="control">目标控件</param>
/// <param name="rect">需要重绘的区域(null则重绘控件本身)</param>
private void RefreshControlPartial(Control control, Rectangle? rect = null)
{
if (!IsControlValid(control)) return;
if (control.InvokeRequired)
{
control.Invoke(new Action(() => RefreshControlPartial(control, rect)));
return;
}
// 只重绘指定区域,而非整个控件
if (rect.HasValue)
{
control.Invalidate(rect.Value);
}
else
{
control.Invalidate(); // 仅重绘控件边界内区域
}
control.Update(); // 立即更新,不等待刷新队列
// 仅刷新直接父容器,而非递归刷新所有父级(减少卡顿)
var parent = control.Parent;
if (parent != null && !parent.IsDisposed)
{
parent.Invalidate(control.Bounds);
parent.Update();
}
}
#endregion
#region 测试方法
/// <summary>
/// 测试按钮点击事件
/// </summary>
private void button1_Click(object sender, EventArgs e)
{
//TestTrayStation();
TestStatusNG();
//TestBatteryStation();
}
private void TestStatusNG()
{
int stationNo = 1;
int layerNum = 1;
string grade = "A";
string GongWei = CommonMethods.sysConfig.GongWei;
string containerCode = "XM1111";
List<BatteryInfo> batteryInfos = null;
List<BGearEntity> bGearlist = new List<BGearEntity>();
int MAX_BATTERY_NUM = 60;
batteryInfos = Enumerable.Repeat(new BatteryInfo(), MAX_BATTERY_NUM).ToList();
BGearEntity m = new BGearEntity
{
TestTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
VassoioID = containerCode,
GongWei = GongWei,
};
List<MaterialPackInfo> packInfos = new List<MaterialPackInfo>(batteryInfos.Count);
for (int i = 0; i < batteryInfos.Count; i++)
{
bool packResult = true;
string packFalseReason = null;
if (i % 3 == 1)
{
packResult = false;
packFalseReason = "错误NG1";
}
else if (i % 3 == 2)
{
packResult = false;
packFalseReason = "错误NG2";
}
MaterialPackInfo materialPackInfo = new MaterialPackInfo
{
identification = "DC_" + i.ToString(),
locationRow = ParseLocation(layerNum, i),
packResult = packResult,
packFalseReason = packFalseReason
};
packInfos.Add(materialPackInfo);
}
List<BatteryEntity> batteryEntities = new List<BatteryEntity>(packInfos.Count);
for (int i = 0; i < packInfos.Count; i++)
{
var info = packInfos[i];
batteryEntities.Add(new BatteryEntity
{
identification = info.identification,
location = info.locationRow,
packResult = info.packResult,
packFalseReason = info.packFalseReason,
containerCode = containerCode,
grade = grade,
outStationType = 1,
packTime = m.TestTime
});
}
//if (batteryEntities.Count > 0)
//{
// CommonMethods.ShowBatteryNGRsnDelegate?.Invoke(batteryEntities);
// CommonMethods.ShowBatteryStatusDelegate?.Invoke(stationNo, batteryEntities);
// //CommonMethods.ShowBatteryQRCoderDelegate?.Invoke(batteryEntities);
//}
m.Result = "NG";
m.Remark = "电芯绑定失败";
m.OutSuccTotal = batteryEntities.Where(x => x.packResult == true).Count();
m.Qty = grade;
m.Total = batteryEntities.Count;
bGearlist.Add(m);
CommonMethods.ShowBlankingDelegate.Invoke(bGearlist);
}
private async Task TestTrayStation()
{
// 初始化业务层TrayInfo
TrayInfo mesTrayInfo = new TrayInfo();
int stationNo = 1;
string trayID = "1234567890";
mesTrayInfo.cellList = new List<Cell>
{
new Cell { cellNo = "11111111111", channel = 1 },
new Cell { cellNo = "22222222222", channel = 2 },
};
mesTrayInfo.trayNo = trayID;
mesTrayInfo.grade = MesConfig.GetLocGrade(stationNo, CommonMethods.curFdConfig);
mesTrayInfo.productCode = CommonMethods.mesConfig.ModelName;
//mesTrayInfo.lineNo = "Line01";
mesTrayInfo.moreGrade = "A1";
// 业务逻辑判断
List<string> grades = CommonMethods.GetValidGrades();
bool bModelSame = mesTrayInfo.productCode == CommonMethods.mesConfig.ModelName;
bool bGradeIn = grades.Contains(mesTrayInfo.grade);
int ret = (bModelSame && bGradeIn) ? 1 : 2;
// 完整赋值TrayEntity(数据库层)
TrayEntity mesTrayEntity = new TrayEntity();
// 映射TrayInfo的核心字段到TrayEntity
mesTrayEntity.trayID = mesTrayInfo.trayNo; // 关键:料框码必须赋值,否则更新/新增无标识
mesTrayEntity.model = mesTrayInfo.productCode;
mesTrayEntity.grade = mesTrayInfo.grade;
mesTrayEntity.moreGrade = mesTrayInfo.moreGrade;
//mesTrayEntity.lineNo = mesTrayInfo.lineNo;
// 补充数据库必需字段
mesTrayEntity.Count = mesTrayInfo.cellList?.Count ?? 0; // 电池个数=电芯条码数量
mesTrayEntity.GongWei = stationNo.ToString(); // 机架号=工位号
mesTrayEntity.Time = DateTime.Now; // 进站时间=当前时间
mesTrayEntity.Result = ret == 1 ? "本机架处理" : "非本机架处理";
mesTrayEntity.Remark = $"{mesTrayEntity.Result}:型号{bModelSame},等级{bGradeIn}";
// 封装为列表并保存
List<TrayEntity> mesTrayInfos = new List<TrayEntity>() { mesTrayEntity };
await SaveTrayDataAsync(mesTrayInfos).ConfigureAwait(false);
}
private async Task SaveTrayDataAsync(List<TrayEntity> list)
{
if (list == null || list.Count == 0)
return;
try
{
string strRes = "";
foreach (TrayEntity m in list)
{
int updateCount = await CommonMethods.db.UpdateSingleAsync<TrayEntity>(
m,
null,
it => it.trayID == m.trayID).ConfigureAwait(false);
if (updateCount > 0)
{
strRes = "更新Yes";
}
else
{
// SQLSugar会自动忽略[IsIgnore]字段,无需额外处理
bool addSuccess = await CommonMethods.db.AddReturnBoolAsync<TrayEntity>(m).ConfigureAwait(false);
strRes = addSuccess ? "新增Yes" : "新增No";
}
// 更新备注
m.Remark = $"{m.Remark} | {strRes}";
}
// 保留原有委托调用(兼容其他显示逻辑)
CommonMethods.ShowTrayDataDelegate?.Invoke(list);
}
catch (Exception ex)
{
LogHelper.Instance.WriteError($"物流线进站保存处理异常:{ex}", "SysErrorLog");
throw; // 重新抛出异常,让上层知道保存失败
}
}
private async Task TestBatteryStation()
{
TrayInfo mesTrayInfo = new TrayInfo();
List<AGearEntity> list = new List<AGearEntity>();//实体
string recordDate = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
var GongWei = CommonMethods.sysConfig.GongWei;
string trayID = "1234567890";
List<BatteryControl> batteryControls = new List<BatteryControl>();
mesTrayInfo.cellList = new List<Cell>
{
new Cell { cellNo = "11111111111", channel = 1 },
new Cell { cellNo = "22222222222", channel = 2 },
};
mesTrayInfo.trayNo = trayID;
mesTrayInfo.grade = "A";
mesTrayInfo.productCode = CommonMethods.mesConfig.ModelName;
//创建AGearEntity列表
for (int i = 0; i < mesTrayInfo.cellList.Count; i++)
{
var entity = new AGearEntity
{
Location = mesTrayInfo.cellList[i].channel.ToString(),
Time = DateTime.Now, //DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
BarCode = mesTrayInfo.cellList[i].cellNo,
TrayID = mesTrayInfo.trayNo,
Result = "OK",
Remark = "",
Grade = mesTrayInfo.grade ?? "",
Model = mesTrayInfo.productCode ?? "",
GongWei = GongWei,
};
list.Add(entity);
}
if (list.Count > 0)
{
await SaveFeedingDataAsync(list).ConfigureAwait(false);
CommonMethods.AddDataMonitorLog(0, $"{GongWei} 保存{list.Count}条数据到数据库");
}
}
private async Task SaveFeedingDataAsync(List<AGearEntity> list)
{
if (list == null || list.Count == 0)
return;
// 明确指定为异步 lambda
try
{
// 数据库操作
string strRes = "";
foreach (AGearEntity m in list)
{
//更新
int b = await CommonMethods.db.UpdateSingleAsync<AGearEntity>(m, null, it => it.BarCode == m.BarCode).ConfigureAwait(false);
if (b > 0)
{
strRes = "更新Yes";
}
else
{
//新增
bool b2 = await CommonMethods.db.AddReturnBoolAsync<AGearEntity>(m).ConfigureAwait(false);
strRes = b2 ? "新增Yes" : "新增No";
}
m.Remark = m.Remark + strRes;
}
//数据显示 - 在主线程执行
CommonMethods.ShowFeedingDelegate?.Invoke(list);
}
catch (Exception ex)
{
LogHelper.Instance.WriteError($"组盘工位保存处理异常:{ex}", "SysErrorLog");
throw; // 重新抛出异常,让上层知道保存失败
}
}
#endregion
private void SafeUI(Action action, bool forceAsync = false)
{
if (action == null || IsDisposed || !IsHandleCreated) return;
try
{
if (InvokeRequired)
{
if (forceAsync)
{
// 异步调用不等待,避免阻塞回调
BeginInvoke(new Action(() =>
{
try { action(); }
catch (Exception ex) { LogHelper.Instance.WriteError($"异步UI操作异常:{ex}", "BatteryStatusLog"); }
}));
}
else
{
// 同步调用捕获异常
Invoke(new Action(() =>
{
try { action(); }
catch (Exception ex) { LogHelper.Instance.WriteError($"同步UI操作异常:{ex}", "BatteryStatusLog"); }
}));
}
}
else
{
action();
}
}
catch (ObjectDisposedException)
{
// 窗体已释放,忽略
}
catch (InvalidAsynchronousStateException)
{
// 控件句柄无效,忽略
}
catch (Exception ex)
{
LogHelper.Instance.WriteError($"SafeUI执行异常:{ex}", "BatteryStatusLog");
}
}
}
public static class CancellationTokenExtensions
{
public static void UnregisterAll(this CancellationToken token)
{
// 通过反射清空回调
try
{
var registrationsField = token.GetType().GetField(
"_registrations",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
if (registrationsField != null)
{
var registrations = registrationsField.GetValue(token);
if (registrations != null)
{
var clearMethod = registrations.GetType().GetMethod(
"Clear",
System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
clearMethod?.Invoke(registrations, null);
}
}
}
catch (Exception ex)
{
LogHelper.Instance.WriteError($"移除CancellationToken回调失败:{ex}", "BatteryStatusLog");
}
}
}
}