Files
1258/LargeSquareOne/FrmBatteryStatus.cs
T
2026-08-04 18:36:40 +08:00

2764 lines
103 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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");
}
}
}
}