using Dapper; using Modbus.Device; using MySql.Data.MySqlClient; using System; using System.Collections.ObjectModel; using System.Configuration; using System.IO; using System.Net.Sockets; using System.Text; using System.Windows; using System.Windows.Controls; using 自救器呼吸器综合检验仪.Data; namespace 自救器呼吸器综合检验仪 { public partial class ReportWindow : Window { private MainWindow _mainWindow; private ReportWindow _reportWindow; public ObservableCollection _records; // 添加静态集合来保持数据 private static ObservableCollection _staticRecords = new ObservableCollection(); private static readonly string ReportFilePath = System.IO.Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "氧气自救器检验报表.csv"); Function ma; private TcpClient _tcpClient => ModbusResourceManager.Instance.TcpClient; private IModbusMaster _modbusMaster => ModbusResourceManager.Instance.ModbusMaster; public ReportWindow() { InitializeComponent(); _records = new ObservableCollection(); _records = _staticRecords; dataGrid.ItemsSource = _records; } // 添加新记录 public void AddRecord(string time, string date, double flowRate, string duration, double flowRate2, string no) { var record = new TestRecord { Id = _records.Count + 1, Time = time, Date = date, FlowRate = flowRate, Duration = duration, CreateTime = DateTime.Now, FlowRate2 = flowRate2, No = no }; _records.Insert(0, record); // 新记录插入到最前面 SaveRecords(time, date, flowRate, duration, flowRate2, no); } // 保存记录到文件 private void SaveRecords(string time, string date, double flowRate, string duration, double flowRate2, string No) { try { using (var connection = new MySqlConnection(DatabaseConfig.ConnectionString)) { connection.Open(); var sql = @"INSERT INTO test_records (Time, Date, FlowRate, Duration, CreateTime,FlowRate2,No,Type) VALUES (@Time, @Date, @FlowRate, @Duration, @CreateTime,@FlowRate2,@No,0)"; var record = new TestRecord { Time = time, Date = date, FlowRate = flowRate, Duration = duration, CreateTime = DateTime.Now, FlowRate2 = flowRate2, No = No }; connection.Execute(sql, record); } } catch (Exception ex) { MessageBox.Show($"保存记录失败:{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error); } } private void BtnExport_Click(object sender, RoutedEventArgs e) { try { // 数据校验:无数据时给出友好提示 if (_records == null || _records.Count == 0) { MessageBox.Show("没有数据可导出", "提示", MessageBoxButton.OK, MessageBoxImage.Information); return; } // 保存文件对话框:后缀改为.xls,支持Excel直接打开 var saveDialog = new Microsoft.Win32.SaveFileDialog { FileName = $"氧气自救器_供养量检验报表_{DateTime.Now:yyyyMMdd_HHmmss}.xls", Filter = "Excel文件 (*.xls)|*.xls|所有文件 (*.*)|*.*", Title = "导出供氧量检验报表" }; if (saveDialog.ShowDialog() == true) { // 构建HTML表格(核心:通过CSS定义居中、列宽、样式,Excel可识别) var htmlBuilder = new System.Text.StringBuilder(); htmlBuilder.AppendLine(""); // 表格整体样式:带边框、边框合并、统一字体(微软雅黑) htmlBuilder.AppendLine(""); // 1. 表头行:居中+加粗+加宽列宽(重点优化长内容列) htmlBuilder.AppendLine(""); htmlBuilder.AppendLine(""); htmlBuilder.AppendLine(""); // 加宽 htmlBuilder.AppendLine(""); htmlBuilder.AppendLine(""); // 加宽(字段名较长) htmlBuilder.AppendLine(""); htmlBuilder.AppendLine(""); htmlBuilder.AppendLine(""); // 加宽(支持时长格式) htmlBuilder.AppendLine(""); // 加宽 htmlBuilder.AppendLine(""); // 2. 数据行:居中对齐+数值格式化(供氧流量保留2位小数) foreach (var record in _records) { htmlBuilder.AppendLine(""); // 每个单元格强制居中,添加内边距避免拥挤 htmlBuilder.AppendLine($""); htmlBuilder.AppendLine($""); htmlBuilder.AppendLine($""); htmlBuilder.AppendLine($""); // 供氧流量(2位小数,匹配单位) htmlBuilder.AppendLine($""); // 供氧流量(2位小数,匹配单位) htmlBuilder.AppendLine($""); // 样品编号 htmlBuilder.AppendLine($""); // 测试时长 htmlBuilder.AppendLine($""); // 记录时间 htmlBuilder.AppendLine(""); } // 闭合HTML标签,确保格式正确 htmlBuilder.AppendLine("
编号日期时间定量供氧流量(L/min)自动/手动补给供氧量(L/min)样品编号测试时长记录时间
{record.Id.ToString() ?? ""}{record.Date?.ToString() ?? ""}{record.Time?.ToString() ?? ""}{record.FlowRate:F2}{record.FlowRate2:F2}{record.No?.ToString() ?? ""}{record.Duration?.ToString() ?? ""}{record.CreateTime:yyyy/MM/dd HH:mm:ss}
"); // 保存文件(UTF-8编码,彻底避免中文乱码) System.IO.File.WriteAllText(saveDialog.FileName, htmlBuilder.ToString(), Encoding.UTF8); // 导出成功提示:明确告知用户格式已自动设置 MessageBox.Show( $"报表已成功导出到:\n{saveDialog.FileName}\n\n", "导出成功(格式已自动设置)", MessageBoxButton.OK, MessageBoxImage.Information); } } catch (Exception ex) { // 异常捕获:给出具体错误信息,便于排查 MessageBox.Show($"导出失败:{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error); } } private void BtnClear_Click(object sender, RoutedEventArgs e) { var result = MessageBox.Show("确定要清空所有记录吗?此操作不可恢复!", "确认清空", MessageBoxButton.YesNo, MessageBoxImage.Warning); if (result == MessageBoxResult.Yes) { _records.Clear(); MessageBox.Show("记录已清空", "提示", MessageBoxButton.OK, MessageBoxImage.Information); } } private void Window_Loaded(object sender, RoutedEventArgs 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); } private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) { // 停止ViewModel的定时器 if (DataContext is MainViewModel viewModel) { viewModel.StopTimer(); } // 释放Modbus资源 ModbusResourceManager.Instance?.Dispose(); // 延后到当前窗口完成关闭后再统一关停,避免关闭重入。 AppShutdownCoordinator.RequestShutdown(); } private void Window_Closed(object sender, EventArgs e) { // 由应用级关停统一处理其他窗口,避免关闭链路重入。 } private void BtnPrint_Click(object sender, RoutedEventArgs e) { if (_records == null || _records.Count == 0) { MessageBox.Show("无数据,不可打印", "提示", MessageBoxButton.OK, MessageBoxImage.Information); return; } ma.BtnClickFunctionForNew(Function.ButtonType.切换型, 15); } 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) { //ShowErrorMsg($"重新连接失败:{ex.Message}"); } return false; } private void SwitchWindow(ref T windowInstance, Func createFunc) where T : Window, new() { // 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) => { WindowNavigationHelper.RestoreWindow(this); }; } else { WindowNavigationHelper.ShowWithoutWhiteFlash(this, windowInstance); return; } WindowNavigationHelper.ShowWithoutWhiteFlash(this, windowInstance); } private void BtnClose_Click(object sender, RoutedEventArgs e) { SwitchWindow(ref _mainWindow, () => new MainWindow()); } } }