Files
paoxiaoqi/ProcessReportWindow.xaml.cs
2026-01-16 20:55:07 +08:00

411 lines
14 KiB
C#
Raw Permalink 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 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();
}
}
}
}