Files
zijiuqizonghejianyanyi/ReportWindow.xaml.cs
2026-03-11 15:21:27 +08:00

300 lines
13 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 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<TestRecord> _records;
// 添加静态集合来保持数据
private static ObservableCollection<TestRecord> _staticRecords = new ObservableCollection<TestRecord>();
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<TestRecord>();
_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("<html><body>");
// 表格整体样式:带边框、边框合并、统一字体(微软雅黑)
htmlBuilder.AppendLine("<table border='1' style='border-collapse:collapse; font-family:微软雅黑; font-size:11px;'>");
// 1. 表头行:居中+加粗+加宽列宽(重点优化长内容列)
htmlBuilder.AppendLine("<tr style='background-color:#f0f0f0;'>");
htmlBuilder.AppendLine("<th style='width:100px; text-align:center; font-weight:bold; padding:6px;'>编号</th>");
htmlBuilder.AppendLine("<th style='width:140px; text-align:center; font-weight:bold; padding:6px;'>日期</th>"); // 加宽
htmlBuilder.AppendLine("<th style='width:100px; text-align:center; font-weight:bold; padding:6px;'>时间</th>");
htmlBuilder.AppendLine("<th style='width:160px; text-align:center; font-weight:bold; padding:6px;'>定量供氧流量(L/min)</th>"); // 加宽(字段名较长)
htmlBuilder.AppendLine("<th style='width:160px; text-align:center; font-weight:bold; padding:6px;'>自动/手动补给供氧量(L/min)</th>");
htmlBuilder.AppendLine("<th style='width:90px; text-align:center; font-weight:bold; padding:6px;'>样品编号</th>");
htmlBuilder.AppendLine("<th style='width:140px; text-align:center; font-weight:bold; padding:6px;'>测试时长</th>"); // 加宽(支持时长格式)
htmlBuilder.AppendLine("<th style='width:160px; text-align:center; font-weight:bold; padding:6px;'>记录时间</th>"); // 加宽
htmlBuilder.AppendLine("</tr>");
// 2. 数据行:居中对齐+数值格式化供氧流量保留2位小数
foreach (var record in _records)
{
htmlBuilder.AppendLine("<tr>");
// 每个单元格强制居中,添加内边距避免拥挤
htmlBuilder.AppendLine($"<td style='text-align:center; padding:6px;'>{record.Id.ToString() ?? ""}</td>");
htmlBuilder.AppendLine($"<td style='text-align:center; padding:6px;'>{record.Date?.ToString() ?? ""}</td>");
htmlBuilder.AppendLine($"<td style='text-align:center; padding:6px;'>{record.Time?.ToString() ?? ""}</td>");
htmlBuilder.AppendLine($"<td style='text-align:center; padding:6px;'>{record.FlowRate:F2}</td>"); // 供氧流量2位小数匹配单位
htmlBuilder.AppendLine($"<td style='text-align:center; padding:6px;'>{record.FlowRate2:F2}</td>"); // 供氧流量2位小数匹配单位
htmlBuilder.AppendLine($"<td style='text-align:center; padding:6px;'>{record.No?.ToString() ?? ""}</td>"); // 样品编号
htmlBuilder.AppendLine($"<td style='text-align:center; padding:6px;'>{record.Duration?.ToString() ?? ""}</td>"); // 测试时长
htmlBuilder.AppendLine($"<td style='text-align:center; padding:6px;'>{record.CreateTime:yyyy/MM/dd HH:mm:ss}</td>"); // 记录时间
htmlBuilder.AppendLine("</tr>");
}
// 闭合HTML标签确保格式正确
htmlBuilder.AppendLine("</table></body></html>");
// 保存文件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();
// 确保应用程序完全退出
Application.Current.Shutdown();
}
private void Window_Closed(object sender, EventArgs e)
{
//_mainWindow4?.Close();
_mainWindow?.Close();
}
private void BtnPrint_Click(object sender, RoutedEventArgs e)
{
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<T>(ref T windowInstance, Func<T> 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) =>
{
// 窗口关闭时重新启动定时器并显示当前窗口
this.Show();
this.Activate();
};
}
else
{
// 激活已存在的窗口(前置显示)
windowInstance.Activate();
return;
}
// 4. 切换窗口:隐藏当前窗口,显示目标窗口(非模态)
this.Hide();
windowInstance.Show(); // 使用 Show() 而不是 ShowDialog()
}
private void BtnClose_Click(object sender, RoutedEventArgs e)
{
SwitchWindow(ref _mainWindow, () => new MainWindow());
}
}
}