411 lines
14 KiB
C#
411 lines
14 KiB
C#
|
|
|
|||
|
|
using PdfSharpCore.Drawing;
|
|||
|
|
using PdfSharpCore.Pdf;
|
|||
|
|
using PdfSharpCore.Utils;
|
|||
|
|
using System;
|
|||
|
|
using System.Collections.ObjectModel;
|
|||
|
|
using System.ComponentModel;
|
|||
|
|
using System.Globalization;
|
|||
|
|
using System.IO;
|
|||
|
|
using System.Windows;
|
|||
|
|
using System.Windows.Controls;
|
|||
|
|
using System.Windows.Data;
|
|||
|
|
using System.Windows.Media;
|
|||
|
|
|
|||
|
|
namespace EmptyLoadTest
|
|||
|
|
{
|
|||
|
|
// 数据模型
|
|||
|
|
public class ReportItem
|
|||
|
|
{
|
|||
|
|
public int Index { get; set; }
|
|||
|
|
public DateTime Time { get; set; }
|
|||
|
|
public double Torque { get; set; }
|
|||
|
|
public int Speed { get; set; }
|
|||
|
|
public double Pressure { get; set; }
|
|||
|
|
public string Status { get; set; }
|
|||
|
|
public string Notes { get; set; }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 状态到颜色的转换器
|
|||
|
|
public class StatusToColorConverter : IValueConverter
|
|||
|
|
{
|
|||
|
|
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
|||
|
|
{
|
|||
|
|
if (value is string status)
|
|||
|
|
{
|
|||
|
|
return status switch
|
|||
|
|
{
|
|||
|
|
//"正常" => new SolidColorBrush(Color.FromRgb(39, 174, 96)), // 绿色
|
|||
|
|
//"警告" => new SolidColorBrush(Color.FromRgb(230, 126, 34)), // 橙色
|
|||
|
|
//"错误" => new SolidColorBrush(Color.FromRgb(231, 76, 60)), // 红色
|
|||
|
|
_ => new SolidColorBrush(Color.FromRgb(52, 73, 94)) // 默认深蓝色
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
return new SolidColorBrush(Color.FromRgb(52, 73, 94));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
|||
|
|
{
|
|||
|
|
throw new NotImplementedException();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 视图模型
|
|||
|
|
public class ReportViewModel : INotifyPropertyChanged
|
|||
|
|
{
|
|||
|
|
private ObservableCollection<ReportItem> _reportData;
|
|||
|
|
public ObservableCollection<ReportItem> ReportData
|
|||
|
|
{
|
|||
|
|
get => _reportData;
|
|||
|
|
set
|
|||
|
|
{
|
|||
|
|
_reportData = value;
|
|||
|
|
OnPropertyChanged(nameof(ReportData));
|
|||
|
|
UpdateStatistics();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private int _dataCount;
|
|||
|
|
public int DataCount
|
|||
|
|
{
|
|||
|
|
get => _dataCount;
|
|||
|
|
set
|
|||
|
|
{
|
|||
|
|
_dataCount = value;
|
|||
|
|
OnPropertyChanged(nameof(DataCount));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private int _normalCount;
|
|||
|
|
public int NormalCount
|
|||
|
|
{
|
|||
|
|
get => _normalCount;
|
|||
|
|
set
|
|||
|
|
{
|
|||
|
|
_normalCount = value;
|
|||
|
|
OnPropertyChanged(nameof(NormalCount));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private int _warningCount;
|
|||
|
|
public int WarningCount
|
|||
|
|
{
|
|||
|
|
get => _warningCount;
|
|||
|
|
set
|
|||
|
|
{
|
|||
|
|
_warningCount = value;
|
|||
|
|
OnPropertyChanged(nameof(WarningCount));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private int _errorCount;
|
|||
|
|
public int ErrorCount
|
|||
|
|
{
|
|||
|
|
get => _errorCount;
|
|||
|
|
set
|
|||
|
|
{
|
|||
|
|
_errorCount = value;
|
|||
|
|
OnPropertyChanged(nameof(ErrorCount));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public ReportViewModel(ObservableCollection<ReportItem> realData = null)
|
|||
|
|
{
|
|||
|
|
if (realData != null && realData.Count > 0)
|
|||
|
|
{
|
|||
|
|
// 使用传入的真实数据
|
|||
|
|
ReportData = realData;
|
|||
|
|
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
UpdateStatistics();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void UpdateStatistics()
|
|||
|
|
{
|
|||
|
|
if (ReportData == null) return;
|
|||
|
|
|
|||
|
|
DataCount = ReportData.Count;
|
|||
|
|
//NormalCount = ReportData.Count(item => item.Status == "正常");
|
|||
|
|
//WarningCount = ReportData.Count(item => item.Status == "警告");
|
|||
|
|
//ErrorCount = ReportData.Count(item => item.Status == "错误");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public event PropertyChangedEventHandler PropertyChanged;
|
|||
|
|
protected virtual void OnPropertyChanged(string propertyName)
|
|||
|
|
{
|
|||
|
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 在 ReportViewModel 类中添加这个方法
|
|||
|
|
public void ExportData()
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
var saveDialog = new Microsoft.Win32.SaveFileDialog
|
|||
|
|
{
|
|||
|
|
Filter = "CSV文件|*.csv",
|
|||
|
|
FileName = $"过程报表_{DateTime.Now:yyyyMMdd_HHmmss}.csv",
|
|||
|
|
Title = "导出报表"
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
if (saveDialog.ShowDialog() == true)
|
|||
|
|
{
|
|||
|
|
using (var writer = new StreamWriter(saveDialog.FileName, false, System.Text.Encoding.UTF8))
|
|||
|
|
{
|
|||
|
|
writer.WriteLine("序号,时间,实时扭矩(N.cm),实时转速(Rad/Min)");
|
|||
|
|
|
|||
|
|
foreach (var item in ReportData)
|
|||
|
|
{
|
|||
|
|
writer.WriteLine($"{item.Index},{item.Time:HH:mm:ss},{item.Torque:F1},{item.Speed}");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
MessageBox.Show($"报表已导出到:{saveDialog.FileName}", "导出成功");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
MessageBox.Show($"导出失败:{ex.Message}", "错误");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void Clear()
|
|||
|
|
{
|
|||
|
|
ReportData = new ObservableCollection<ReportItem>();
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
public void ExportToPdfUsingPdfSharp()
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
var saveDialog = new Microsoft.Win32.SaveFileDialog
|
|||
|
|
{
|
|||
|
|
Filter = "PDF文件|*.pdf",
|
|||
|
|
FileName = $"过程报表_{DateTime.Now:yyyyMMdd_HHmmss}.pdf"
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
if (saveDialog.ShowDialog() == true)
|
|||
|
|
{
|
|||
|
|
// 创建PDF文档
|
|||
|
|
PdfDocument document = new PdfDocument();
|
|||
|
|
document.Info.Title = "医用刨削器过程测试报表";
|
|||
|
|
document.Info.Author = "测试系统";
|
|||
|
|
document.Info.CreationDate = DateTime.Now;
|
|||
|
|
|
|||
|
|
// 添加页面
|
|||
|
|
PdfPage page = document.AddPage();
|
|||
|
|
XGraphics gfx = XGraphics.FromPdfPage(page);
|
|||
|
|
|
|||
|
|
// 直接使用系统中文字体名称(Windows系统)
|
|||
|
|
// 常见的系统中文字体:
|
|||
|
|
// "Microsoft YaHei" - 微软雅黑 (Windows 7+)
|
|||
|
|
// "SimSun" - 宋体
|
|||
|
|
// "SimHei" - 黑体
|
|||
|
|
// "KaiTi" - 楷体
|
|||
|
|
string fontName = "Microsoft YaHei"; // 使用微软雅黑
|
|||
|
|
|
|||
|
|
XFont titleFont = new XFont(fontName, 20, PdfSharpCore.Drawing.XFontStyle.Bold);
|
|||
|
|
XFont headerFont = new XFont(fontName, 12, PdfSharpCore.Drawing.XFontStyle.Bold);
|
|||
|
|
XFont normalFont = new XFont(fontName, 10, PdfSharpCore.Drawing.XFontStyle.Regular);
|
|||
|
|
|
|||
|
|
// 页面尺寸
|
|||
|
|
double pageWidth = page.Width;
|
|||
|
|
double margin = 50;
|
|||
|
|
double yPos = margin;
|
|||
|
|
|
|||
|
|
// 1. 标题
|
|||
|
|
gfx.DrawString("医用刨削器过程测试报表", titleFont, XBrushes.Black,
|
|||
|
|
new XRect(0, yPos, pageWidth, 30), XStringFormats.TopCenter);
|
|||
|
|
yPos += 40;
|
|||
|
|
|
|||
|
|
// 2. 生成时间
|
|||
|
|
gfx.DrawString($"生成时间:{DateTime.Now:yyyy年MM月dd日 HH:mm:ss}", headerFont, XBrushes.Black,
|
|||
|
|
new XRect(0, yPos, pageWidth, 20), XStringFormats.TopCenter);
|
|||
|
|
yPos += 30;
|
|||
|
|
|
|||
|
|
// 3. 统计信息
|
|||
|
|
string stats = $"数据总数:{DataCount} | 正常:{NormalCount} | 警告:{WarningCount} | 错误:{ErrorCount}";
|
|||
|
|
gfx.DrawString(stats, headerFont, XBrushes.DarkBlue,
|
|||
|
|
new XRect(margin, yPos, pageWidth - 2 * margin, 20), XStringFormats.TopLeft);
|
|||
|
|
yPos += 30;
|
|||
|
|
|
|||
|
|
// 4. 表格标题
|
|||
|
|
gfx.DrawString("测试过程数据明细", headerFont, XBrushes.Black,
|
|||
|
|
new XRect(margin, yPos, pageWidth - 2 * margin, 20), XStringFormats.TopLeft);
|
|||
|
|
yPos += 25;
|
|||
|
|
|
|||
|
|
// 5. 绘制表格
|
|||
|
|
double columnWidth = (pageWidth - 2 * margin) / 4;
|
|||
|
|
double rowHeight = 20;
|
|||
|
|
|
|||
|
|
// 表头
|
|||
|
|
gfx.DrawString("序号", headerFont, XBrushes.Black, margin, yPos);
|
|||
|
|
gfx.DrawString("时间", headerFont, XBrushes.Black, margin + columnWidth, yPos);
|
|||
|
|
gfx.DrawString("扭矩(N.cm)", headerFont, XBrushes.Black, margin + columnWidth * 2, yPos);
|
|||
|
|
gfx.DrawString("转速(rad/min)", headerFont, XBrushes.Black, margin + columnWidth * 3, yPos);
|
|||
|
|
|
|||
|
|
yPos += rowHeight;
|
|||
|
|
|
|||
|
|
// 数据行
|
|||
|
|
int rowCount = 0;
|
|||
|
|
foreach (var item in ReportData)
|
|||
|
|
{
|
|||
|
|
// 检查是否需要换页
|
|||
|
|
if (yPos + rowHeight > page.Height - margin && rowCount > 0)
|
|||
|
|
{
|
|||
|
|
// 添加新页面
|
|||
|
|
page = document.AddPage();
|
|||
|
|
gfx = XGraphics.FromPdfPage(page);
|
|||
|
|
yPos = margin;
|
|||
|
|
|
|||
|
|
// 在新页面绘制表头
|
|||
|
|
gfx.DrawString("序号", headerFont, XBrushes.Black, margin, yPos);
|
|||
|
|
gfx.DrawString("时间", headerFont, XBrushes.Black, margin + columnWidth, yPos);
|
|||
|
|
gfx.DrawString("扭矩(N.cm)", headerFont, XBrushes.Black, margin + columnWidth * 2, yPos);
|
|||
|
|
gfx.DrawString("转速(rad/min)", headerFont, XBrushes.Black, margin + columnWidth * 3, yPos);
|
|||
|
|
yPos += rowHeight;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
gfx.DrawString(item.Index.ToString(), normalFont, XBrushes.Black, margin, yPos);
|
|||
|
|
gfx.DrawString(item.Time.ToString("HH:mm:ss"), normalFont, XBrushes.Black, margin + columnWidth, yPos);
|
|||
|
|
gfx.DrawString(item.Torque.ToString("F1"), normalFont, XBrushes.Black, margin + columnWidth * 2, yPos);
|
|||
|
|
gfx.DrawString(item.Speed.ToString(), normalFont, XBrushes.Black, margin + columnWidth * 3, yPos);
|
|||
|
|
|
|||
|
|
yPos += rowHeight;
|
|||
|
|
rowCount++;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 保存PDF
|
|||
|
|
document.Save(saveDialog.FileName);
|
|||
|
|
|
|||
|
|
MessageBox.Show($"PDF已导出到:{saveDialog.FileName}", "导出成功");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
MessageBox.Show($"PDF导出失败:{ex.Message}", "错误");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 在窗口的代码后台设置DataContext
|
|||
|
|
public partial class ProcessReportWindow : Window
|
|||
|
|
{
|
|||
|
|
public ProcessReportWindow()
|
|||
|
|
{
|
|||
|
|
InitializeComponent();
|
|||
|
|
|
|||
|
|
var emergencyWindow = EmergencyStopWindow.Instance;
|
|||
|
|
var realData = emergencyWindow?.GetReportData();
|
|||
|
|
|
|||
|
|
if (realData != null && realData.Count > 0)
|
|||
|
|
{
|
|||
|
|
// 使用真实数据
|
|||
|
|
DataContext = new ReportViewModel(realData);
|
|||
|
|
var masx = realData.Select(s => s.Torque).ToList();
|
|||
|
|
var lasttime_ = realData.Max(s => s.Time);
|
|||
|
|
if (realData.Count > 0)
|
|||
|
|
{
|
|||
|
|
maxForce.Text = masx.Max().ToString("F3");
|
|||
|
|
lasttime.Text = "最后刷新:" + lasttime_.ToString("yyyy-MM-dd HH:mm:ss");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
// 如果没有真实数据,使用示例数据
|
|||
|
|
DataContext = new ReportViewModel();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 3. 修正单例逻辑:确保单例的 ReportData 可被外部修改,不丢失数据
|
|||
|
|
private static ProcessReportWindow _instance;
|
|||
|
|
// 加锁保证线程安全
|
|||
|
|
private static readonly object _lock = new object();
|
|||
|
|
public static ProcessReportWindow Instance
|
|||
|
|
{
|
|||
|
|
get
|
|||
|
|
{
|
|||
|
|
lock (_lock)
|
|||
|
|
{
|
|||
|
|
if (_instance == null || !_instance.IsLoaded)
|
|||
|
|
{
|
|||
|
|
_instance = new ProcessReportWindow(); // 使用无参构造,初始化空数据
|
|||
|
|
}
|
|||
|
|
return _instance;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void Button_Click(object sender, RoutedEventArgs e)
|
|||
|
|
{
|
|||
|
|
var mainWindow = EmergencyStopWindow.Instance;
|
|||
|
|
|
|||
|
|
if (!mainWindow.IsVisible)
|
|||
|
|
{
|
|||
|
|
mainWindow.Show();
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
mainWindow.Activate();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Close();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void Button_Click_1(object sender, RoutedEventArgs e)
|
|||
|
|
{
|
|||
|
|
if (DataContext is ReportViewModel viewModel)
|
|||
|
|
{
|
|||
|
|
viewModel.ExportData();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void Button_Click_2(object sender, RoutedEventArgs e)
|
|||
|
|
{
|
|||
|
|
if (DataContext is ReportViewModel viewModel)
|
|||
|
|
{
|
|||
|
|
viewModel.ExportToPdfUsingPdfSharp();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void Button_Click_3(object sender, RoutedEventArgs e)
|
|||
|
|
{
|
|||
|
|
var mainWindow = MainWindow.Instance;
|
|||
|
|
|
|||
|
|
if (!mainWindow.IsVisible)
|
|||
|
|
{
|
|||
|
|
mainWindow.Show();
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
mainWindow.Activate();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Close();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void Button_Click_4(object sender, RoutedEventArgs e)
|
|||
|
|
{
|
|||
|
|
if (DataContext is ReportViewModel viewModel)
|
|||
|
|
{
|
|||
|
|
var emergencyWindow = EmergencyStopWindow.Instance;
|
|||
|
|
emergencyWindow?.ClearReportData();
|
|||
|
|
viewModel.Clear();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void Window_Loaded(object sender, RoutedEventArgs e)
|
|||
|
|
{
|
|||
|
|
if (DataContext is ReportViewModel viewModel)
|
|||
|
|
{
|
|||
|
|
viewModel.ExportData();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|