2026-03-11 15:21:27 +08:00
|
|
|
|
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 static class DatabaseConfig
|
|
|
|
|
|
{
|
|
|
|
|
|
public static string ConnectionString => ConfigurationManager.ConnectionStrings["MySqlConnection"].ConnectionString;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public partial class ReportWindow2 : Window
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
private MainWindow2 _mainWindow2;
|
|
|
|
|
|
private ReportWindow2 _reportWindow2;
|
|
|
|
|
|
//private MainWindow2 _mainWindow2;
|
|
|
|
|
|
//private MainWindow3 _mainWindow3;
|
|
|
|
|
|
//private MainWindow4 _mainWindow4;
|
|
|
|
|
|
public ObservableCollection<TestRecordForNegativePressure> _records;
|
|
|
|
|
|
// 添加静态集合来保持数据
|
|
|
|
|
|
//private static ObservableCollection<TestRecord> _staticRecords = new ObservableCollection<TestRecord>();
|
|
|
|
|
|
|
|
|
|
|
|
private static ObservableCollection<TestRecordForNegativePressure> _staticRecords = new ObservableCollection<TestRecordForNegativePressure>();
|
|
|
|
|
|
|
|
|
|
|
|
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 ReportWindow2()
|
|
|
|
|
|
{
|
|
|
|
|
|
InitializeComponent();
|
|
|
|
|
|
_records = new ObservableCollection<TestRecordForNegativePressure>();
|
|
|
|
|
|
_records = _staticRecords;
|
|
|
|
|
|
dataGrid.ItemsSource = _records;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 添加新记录
|
|
|
|
|
|
public void AddRecord(string time, string date, double StartPress, double EndPress, double DiffPress, double ProtectTime,string no)
|
|
|
|
|
|
{
|
|
|
|
|
|
var record = new TestRecordForNegativePressure
|
|
|
|
|
|
{
|
|
|
|
|
|
Id = _records.Count + 1,
|
|
|
|
|
|
Time = time,
|
|
|
|
|
|
Date = date,
|
|
|
|
|
|
DiffPress = DiffPress,
|
|
|
|
|
|
EndPress = EndPress,
|
|
|
|
|
|
ProtectTime = ProtectTime,
|
|
|
|
|
|
StartPress = StartPress,
|
|
|
|
|
|
CreateTime = DateTime.Now,
|
|
|
|
|
|
No = no
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
_records.Insert(0, record); // 新记录插入到最前面
|
|
|
|
|
|
SaveRecords(time, date, StartPress, EndPress, DiffPress, ProtectTime,no);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 保存记录到文件
|
|
|
|
|
|
private void SaveRecords(string time, string date, double StartPress, double EndPress, double DiffPress, double ProtectTime,string no)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
using (var connection = new MySqlConnection(DatabaseConfig.ConnectionString))
|
|
|
|
|
|
{
|
|
|
|
|
|
connection.Open();
|
|
|
|
|
|
|
|
|
|
|
|
var sql = @"INSERT INTO test_recordsForNegativePressure (Time, Date,StartPress,EndPress,DiffPress,ProtectTime,No, CreateTime,Type)
|
|
|
|
|
|
VALUES (@Time, @Date, @StartPress, @EndPress,@DiffPress,@ProtectTime,@No, @CreateTime,0)";
|
|
|
|
|
|
|
|
|
|
|
|
var record = new TestRecordForNegativePressure
|
|
|
|
|
|
{
|
|
|
|
|
|
Time = time,
|
|
|
|
|
|
Date = date,
|
|
|
|
|
|
DiffPress = DiffPress,
|
|
|
|
|
|
EndPress = EndPress,
|
|
|
|
|
|
ProtectTime = ProtectTime,
|
|
|
|
|
|
StartPress = StartPress,
|
|
|
|
|
|
CreateTime = DateTime.Now,
|
|
|
|
|
|
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直接定义居中、列宽、样式)
|
|
|
|
|
|
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:130px; 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:100px; 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:100px; 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:130px; text-align:center; font-weight:bold; padding:6px;'>保压时间</th>"); // 加宽
|
|
|
|
|
|
htmlBuilder.AppendLine("<th style='width:180px; 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.StartPress:F2}</td>"); // 初始压力(2位小数)
|
|
|
|
|
|
htmlBuilder.AppendLine($"<td style='text-align:center; padding:6px;'>{record.EndPress:F2}</td>"); // 结束压力(2位小数)
|
|
|
|
|
|
htmlBuilder.AppendLine($"<td style='text-align:center; padding:6px;'>{record.DiffPress: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.ProtectTime:F2}</td>"); // 保压时间(2位小数)
|
|
|
|
|
|
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();
|
|
|
|
|
|
|
2026-03-16 19:10:33 +08:00
|
|
|
|
// 延后到当前窗口完成关闭后再统一关停,避免关闭重入。
|
|
|
|
|
|
AppShutdownCoordinator.RequestShutdown();
|
2026-03-11 15:21:27 +08:00
|
|
|
|
}
|
|
|
|
|
|
private void Window_Closed(object sender, EventArgs e)
|
|
|
|
|
|
{
|
2026-03-16 19:10:33 +08:00
|
|
|
|
// 由应用级关停统一处理其他窗口,避免关闭链路重入。
|
2026-03-11 15:21:27 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//private void BtnClose_Click(object sender, RoutedEventArgs e)
|
|
|
|
|
|
//{
|
|
|
|
|
|
// this.Close(); // 直接关闭当前窗口,不切换
|
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void BtnPrint_Click(object sender, RoutedEventArgs e)
|
|
|
|
|
|
{
|
2026-03-16 19:58:18 +08:00
|
|
|
|
if (_records == null || _records.Count == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show("无数据,不可打印", "提示",
|
|
|
|
|
|
MessageBoxButton.OK, MessageBoxImage.Information);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-11 15:21:27 +08:00
|
|
|
|
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) =>
|
|
|
|
|
|
{
|
2026-03-16 19:10:33 +08:00
|
|
|
|
WindowNavigationHelper.RestoreWindow(this);
|
2026-03-11 15:21:27 +08:00
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2026-03-16 19:10:33 +08:00
|
|
|
|
WindowNavigationHelper.ShowWithoutWhiteFlash(this, windowInstance);
|
2026-03-11 15:21:27 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-16 19:10:33 +08:00
|
|
|
|
WindowNavigationHelper.ShowWithoutWhiteFlash(this, windowInstance);
|
2026-03-11 15:21:27 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void BtnClose_Click(object sender, RoutedEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
SwitchWindow(ref _mainWindow2, () => new MainWindow2());
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-03-16 19:10:33 +08:00
|
|
|
|
}
|