using Modbus.Device; using OfficeOpenXml; using OfficeOpenXml.Style; using Sunny.UI; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.IO; using System.Linq; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using 薄膜气体透过率测试仪.Data; using static 薄膜气体透过率测试仪.TestScreen; namespace 薄膜气体透过率测试仪 { public partial class MiopahReport : UIForm { #region 私有字段 private TcpClient _tcpClient => ModbusResourceManager.Instance.TcpClient; private IModbusMaster _modbusMaster => ModbusResourceManager.Instance.ModbusMaster; #endregion private TestScreen _testScreen; Timer Timer; Function ma; private List reports; public MiopahReport(List reports) { InitializeComponent(); this.reports = reports; Timer = new Timer(); Timer.Tick += Timer_Tick; Timer.Interval = 500; Timer.Start(); } private void MiopahReport_Load(object sender, EventArgs e) { string plcIp = "192.168.1.10"; bool initSuccess = Data.ModbusResourceManager.Instance.Init(plcIp, 502); if (!initSuccess) { MessageBox.Show("连接Modbus服务器失败!", "错误"); this.Close(); return; } // 检查连接状态 if (_tcpClient == null || !_tcpClient.Connected) { MessageBox.Show("Modbus连接异常!", "错误"); this.Close(); return; } ma = new Function(_modbusMaster); uiDataGridView1.DataSource = reports; uiDataGridView1.AllowUserToAddRows = false; AdjustDataGridViewStyle(); } private void Timer_Tick(object sender, EventArgs e) { uiLabel2.Text = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); } private void SwitchWindow(ref T windowInstance, Func createFunc) where T : UIForm { //1.停止当前窗口的定时器(不释放资源) Timer?.Stop(); // 2. 检查资源是否可用(添加重连机制) if (_tcpClient == null || !_tcpClient.Connected || _modbusMaster == null) { //尝试重新连接 bool reconnectSuccess = TryReconnect(); if (!reconnectSuccess) { MessageBox.Show("TCP连接已断开,请重新连接!", "提示"); return; } } // 3. 复用窗口实例:不存在则创建,存在则激活 if (windowInstance == null) { windowInstance = createFunc(); // 添加窗口关闭事件处理 windowInstance.Closed += (s, args) => { // 窗口关闭时重新启动定时器并显示当前窗口 //_readtimer?.Start(); //this.Show(); this.Activate(); }; } else { // 激活已存在的窗口(前置显示) windowInstance.Activate(); return; } // 4. 切换窗口:隐藏当前窗口,显示目标窗口(非模态) this.Hide(); windowInstance.Show(); // 使用 Show() 而不是 ShowDialog() } private bool TryReconnect() { try { string plcIp = "192.168.1.10"; bool initSuccess = Data.ModbusResourceManager.Instance.Init(plcIp, 502); if (initSuccess) { ma = new Function(_modbusMaster); return true; } } catch (Exception ex) { ShowError($"重新连接失败:{ex.Message}"); } return false; } private void ShowError(string msg) => MessageBox.Show(msg, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); private void AdjustDataGridViewStyle() { foreach (DataGridViewColumn column in uiDataGridView1.Columns) { // 自动调整列宽(适配内容) column.AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells; // 列宽最小值(防止过窄) if (column.Width < 120) column.Width = 120; // 单元格内容居中 column.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter; column.HeaderCell.Style.Alignment = DataGridViewContentAlignment.MiddleCenter; } } private void ExportToExcel(string filePath) { try { string extension = Path.GetExtension(filePath).ToLower(); // 根据文件后缀分支处理 switch (extension) { case ".xlsx": ExportToXlsx(filePath); // Excel格式(支持样式) break; case ".csv": ExportToCsv(filePath); // CSV格式(基础导出) break; case ".pdf": ShowMessage("提示", "PDF导出暂未实现,已自动切换为Excel格式", UIMessageBoxIcon.Info); ExportToXlsx(Path.ChangeExtension(filePath, ".xlsx")); filePath = Path.ChangeExtension(filePath, ".xlsx"); break; default: throw new NotSupportedException("不支持的文件格式!"); } ShowMessage("导出成功", $"报表已成功导出到:{filePath}", UIMessageBoxIcon.Success); } catch (Exception ex) { ShowMessage("导出错误", $"导出失败:{ex.Message}", UIMessageBoxIcon.Error); } } /// /// 导出为Excel(.xlsx),支持列宽调整+居中样式 /// private void ExportToXlsx(string filePath) { // 授权EPPlus使用(非商业用途) //ExcelPackage.LicenseContext = OfficeOpenXml.LicenseContext.NonCommercial; using (var package = new ExcelPackage()) { var worksheet = package.Workbook.Worksheets.Add("秒帕记录报告"); // 找到化验编号输入文本框 //var labNumberInput = this.Controls.OfType() // .FirstOrDefault(tb => tb.Location.X == uiDataGridView1.Width - 130 && tb.ReadOnly == false); //string labNumberValue = labNumberInput?.Text?.Trim() ?? "未填写"; // 1. 写入化验编号(第1行) //worksheet.Cells["A1"].Value = "化验编号"; //worksheet.Cells["B1"].Value = labNumberValue; // 合并单元格(美化) //worksheet.Cells["A1:B1"].Style.Font.Bold = true; //worksheet.Cells["A1:B1"].Style.HorizontalAlignment = ExcelHorizontalAlignment.Center; // 2. 写入表头(第3行,空出第2行分隔) int headerRow = 1; for (int i = 0; i < uiDataGridView1.Columns.Count; i++) { worksheet.Cells[headerRow, i + 1].Value = uiDataGridView1.Columns[i].HeaderText; // 表头样式:加粗+居中 worksheet.Cells[headerRow, i + 1].Style.Font.Bold = true; worksheet.Cells[headerRow, i + 1].Style.HorizontalAlignment = ExcelHorizontalAlignment.Center; worksheet.Cells[headerRow, i + 1].Style.VerticalAlignment = ExcelVerticalAlignment.Center; } // 3. 写入数据行 int dataRow = headerRow + 1; foreach (DataGridViewRow row in uiDataGridView1.Rows) { if (!row.IsNewRow) { for (int i = 0; i < row.Cells.Count; i++) { string cellValue = row.Cells[i].Value?.ToString() ?? ""; cellValue = cellValue.Replace("\n", " ").Replace("\r", " ").Trim(); worksheet.Cells[dataRow, i + 1].Value = cellValue; // 数据居中 worksheet.Cells[dataRow, i + 1].Style.HorizontalAlignment = ExcelHorizontalAlignment.Center; worksheet.Cells[dataRow, i + 1].Style.VerticalAlignment = ExcelVerticalAlignment.Center; // 日期列特殊处理(确保格式完整) if (uiDataGridView1.Columns[i].HeaderText.Contains("时间") || uiDataGridView1.Columns[i].HeaderText.Contains("日期")) { worksheet.Cells[dataRow, i + 1].Style.Numberformat.Format = "yyyy-MM-dd HH:mm:ss"; } } dataRow++; } } // 4. 自动调整列宽(关键:解决日期显示不完整) for (int i = 1; i <= uiDataGridView1.Columns.Count; i++) { // 自动适配内容宽度,最小值15(Excel列宽单位) worksheet.Column(i).AutoFit(); if (worksheet.Column(i).Width < 15) { worksheet.Column(i).Width = 15; } // 日期列强制加宽(避免仍截断) if (worksheet.Cells[headerRow, i].Value?.ToString().Contains("时间") == true || worksheet.Cells[headerRow, i].Value?.ToString().Contains("日期") == true) { worksheet.Column(i).Width = 25; } } // 5. 保存文件 package.SaveAs(new FileInfo(filePath)); } } private void ExportToCsv(string filePath) { var labNumberInput = this.Controls.OfType() .FirstOrDefault(tb => tb.Location.X == uiDataGridView1.Width - 130 && tb.ReadOnly == false); string labNumberValue = labNumberInput?.Text?.Trim() ?? "未填写"; using (var writer = new StreamWriter(filePath, false, System.Text.Encoding.UTF8)) { writer.Write('\uFEFF'); writer.WriteLine(); // 空行分隔 // 写入表头 var headerCells = new List(); foreach (DataGridViewColumn column in uiDataGridView1.Columns) { headerCells.Add(EscapeCsv(column.HeaderText)); } writer.WriteLine(string.Join(",", headerCells)); // 写入数据 foreach (DataGridViewRow row in uiDataGridView1.Rows) { if (!row.IsNewRow) { var cells = new List(); foreach (DataGridViewCell cell in row.Cells) { string cellValue = cell.Value?.ToString() ?? ""; cellValue = cellValue.Replace("\n", " ").Replace("\r", " ").Trim(); cells.Add(EscapeCsv(cellValue)); } writer.WriteLine(string.Join(",", cells)); } } } // 提示CSV样式调整方法 ShowMessage("提示", "CSV文件导出成功!打开后可手动设置:\n1. 选中列 → 右键 → 列宽(建议日期列设为20)\n2. 选中单元格 → 开始 → 居中对齐", UIMessageBoxIcon.Info); } private string EscapeCsv(string value) { if (string.IsNullOrEmpty(value)) return ""; if (value.Contains(",") || value.Contains("\"") || value.Contains("\n") || value.Contains("\r")) { value = value.Replace("\"", "\"\""); return $"\"{value}\""; } return value; } private void ShowMessage(string title, string message, UIMessageBoxIcon icon) { switch (icon) { case UIMessageBoxIcon.Success: UIMessageTip.ShowOk(message); break; case UIMessageBoxIcon.Error: UIMessageTip.ShowError(message); break; case UIMessageBoxIcon.Info: UIMessageTip.ShowWarning(message); // 此处可根据实际控件调整为Info样式 break; default: UIMessageBox.Show(message, title); break; } } //导出 private void uiButton2_Click(object sender, EventArgs e) { try { using (SaveFileDialog saveDialog = new SaveFileDialog()) { saveDialog.Filter = "Excel文件|*.xlsx|CSV文件|*.csv|PDF文件|*.pdf"; saveDialog.Title = "导出报表"; saveDialog.FileName = $"秒帕记录报告_{DateTime.Now:yyyyMMdd_HHmmss}"; if (saveDialog.ShowDialog() == DialogResult.OK) { string filePath = saveDialog.FileName; ExportToExcel(filePath); } } } catch (Exception ex) { ShowMessage("导出错误", $"导出失败:{ex.Message}", UIMessageBoxIcon.Error); } } //打印 private void uiButton1_Click(object sender, EventArgs e) { ma?.BtnClickFunctionForNew(Function.ButtonType.切换型, 15); } //返回 private void uiButton3_Click(object sender, EventArgs e) { SwitchWindow(ref _testScreen, () => new TestScreen()); } private void MiopahReport_FormClosing(object sender, FormClosingEventArgs e) { Timer?.Stop(); Timer?.Dispose(); // 仅用户主动关闭时退出应用 if (e.CloseReason == CloseReason.UserClosing) { ModbusResourceManager.Instance?.Dispose(); Application.Exit(); } } } public enum UIMessageBoxIcon { Success, Error, Info, Warning } }