Files
VacuumPressureMembranePoreS…/Helpers/ReportGenerator.cs

444 lines
16 KiB
C#
Raw Normal View History

2026-02-27 16:03:49 +08:00
using MembranePoreTester.Models;
2026-04-07 14:47:36 +08:00
using OxyPlot;
using OxyPlot.Legends;
using OxyPlot.Wpf;
2026-02-27 16:03:49 +08:00
using System;
using System.IO;
2026-04-07 14:47:36 +08:00
using System.Linq;
2026-02-27 16:03:49 +08:00
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
2026-04-07 14:47:36 +08:00
using System.Windows.Media;
using System.Windows.Media.Imaging;
using FontWeights = System.Windows.FontWeights;
using HorizontalAlignment = System.Windows.HorizontalAlignment;
2026-02-27 16:03:49 +08:00
namespace MembranePoreTester.Helpers
{
2026-04-07 14:47:36 +08:00
/// <summary>
/// 膜测试报告生成器(泡点法 + 孔分布)
/// 排版规范A4自适应、居中对齐、表格规整、图表清晰、数据准确
/// </summary>
2026-02-27 16:03:49 +08:00
public static class ReportGenerator
{
2026-04-07 14:47:36 +08:00
#region
/// <summary>
/// 生成泡点法测试报告
/// </summary>
2026-02-27 16:03:49 +08:00
public static void GenerateBubblePointReport(BubblePointRecord record)
{
2026-04-07 14:47:36 +08:00
if (record == null)
{
MessageBox.Show("无测试数据,无法生成报告");
return;
}
var doc = new FlowDocument();
SetA4PageSettings(doc);
AddReportTitle(doc, "泡点法测试报告");
AddTestInfo(doc, record);
AddBubblePointDataTable(doc, record);
AddStandardRemark(doc);
2026-02-27 16:03:49 +08:00
ShowPrintPreview(doc, "泡点法测试报告");
}
2026-04-07 14:47:36 +08:00
/// <summary>
/// 生成孔分布测试报告
/// </summary>
public static void GeneratePoreDistributionReport(PoreDistributionRecord record, PlotModel plotModel)
2026-02-27 16:03:49 +08:00
{
2026-04-07 14:47:36 +08:00
if (record == null || record.DataPoints == null || !record.DataPoints.Any())
{
MessageBox.Show("无测试数据,无法生成报告");
return;
}
var doc = new FlowDocument();
SetA4PageSettings(doc);
AddReportTitle(doc, "孔分布测试报告");
AddTestInfo(doc, record);
AddPoreDistributionResult(doc, record);
AddPressureFlowChart(doc, plotModel);
AddTestDataTables(doc, record);
AddPoreDistributionTable(doc, record);
AddStandardRemark(doc);
2026-02-27 16:03:49 +08:00
ShowPrintPreview(doc, "孔分布测试报告");
}
2026-04-07 14:47:36 +08:00
#endregion
2026-02-27 16:03:49 +08:00
2026-04-07 14:47:36 +08:00
#region
/// <summary>
/// 设置A4标准打印页面
/// </summary>
private static void SetA4PageSettings(FlowDocument doc)
2026-02-27 16:03:49 +08:00
{
2026-04-07 14:47:36 +08:00
doc.PageWidth = 793; // A4宽度
doc.PageHeight = 1122; // A4高度
doc.PagePadding = new Thickness(40);
doc.ColumnWidth = 793;
}
2026-02-27 16:03:49 +08:00
2026-04-07 14:47:36 +08:00
/// <summary>
/// 添加报告标题(居中、加粗、大字体)
/// </summary>
private static void AddReportTitle(FlowDocument doc, string title)
{
var titlePara = new Paragraph(new Run(title))
2026-02-27 16:03:49 +08:00
{
2026-04-07 14:47:36 +08:00
FontSize = 26,
2026-02-27 16:03:49 +08:00
FontWeight = FontWeights.Bold,
2026-04-07 14:47:36 +08:00
TextAlignment = TextAlignment.Center,
Margin = new Thickness(0, 0, 0, 25)
};
doc.Blocks.Add(titlePara);
}
2026-02-27 16:03:49 +08:00
2026-04-07 14:47:36 +08:00
/// <summary>
/// 添加测试基础信息(日期、测试人)
/// </summary>
private static void AddTestInfo(FlowDocument doc, dynamic record)
{
var infoPara = new Paragraph(new Run(
$"测试日期:{record.TestDate:yyyy-MM-dd HH:mm} 测试人员:{record.Tester}"))
2026-02-27 16:03:49 +08:00
{
2026-04-07 14:47:36 +08:00
FontSize = 13,
Margin = new Thickness(0, 0, 0, 20)
};
doc.Blocks.Add(infoPara);
}
2026-02-27 16:03:49 +08:00
2026-04-07 14:47:36 +08:00
/// <summary>
/// 添加标准备注(依据国标)
/// </summary>
private static void AddStandardRemark(FlowDocument doc)
{
var remark = new Paragraph(new Run("本报告依据 GB/T 32361-2015《膜材料孔径测试 泡点法》生成"))
{
FontSize = 12,
FontStyle = FontStyles.Italic,
TextAlignment = TextAlignment.Center,
Margin = new Thickness(0, 30, 0, 0)
};
doc.Blocks.Add(remark);
}
2026-02-27 16:03:49 +08:00
2026-04-07 14:47:36 +08:00
/// <summary>
/// 创建标准两列表格
/// </summary>
private static Table CreateStandardTable()
{
var table = new Table
{
CellSpacing = 0,
Margin = new Thickness(0, 10, 0, 20),
BorderThickness = new Thickness(1)
};
table.Columns.Add(new TableColumn { Width = new GridLength(180) });
table.Columns.Add(new TableColumn { Width = new GridLength(500) });
table.BorderBrush = Brushes.Black;
return table;
}
/// <summary>
/// 向表格添加一行(名称 + 值)
/// </summary>
private static void AddTableRow(TableRowGroup group, string label, string value)
{
var row = new TableRow();
row.Cells.Add(CreateTableCell(label, true));
row.Cells.Add(CreateTableCell(value ?? "-", false));
group.Rows.Add(row);
}
/// <summary>
/// 创建表格单元格
/// </summary>
private static TableCell CreateTableCell(string text, bool isBold)
{
var para = new Paragraph(new Run(text))
{
FontSize = 13,
Padding = new Thickness(8, 6, 8, 6),
Margin = new Thickness(0)
};
if (isBold) para.FontWeight = FontWeights.Bold;
return new TableCell(para);
}
#endregion
#region
private static void AddBubblePointDataTable(FlowDocument doc, BubblePointRecord record)
{
var table = CreateStandardTable();
var group = new TableRowGroup();
AddTableRow(group, "膜类型", record.SampleType);
AddTableRow(group, "样品规格", record.SampleSpec);
AddTableRow(group, "测试温度", $"{record.RoomTemperature:F1} ℃");
AddTableRow(group, "浸润时间", $"{record.SoakingTime:F1} h");
AddTableRow(group, "测试液体", record.Liquid?.Name);
AddTableRow(group, "液体厂家", record.LiquidManufacturer);
AddTableRow(group, "泡点压力", $"{record.BubblePointPressure} {record.PressureUnit}");
AddTableRow(group, "最大孔径", $"{record.MaxPoreSize:F3} μm");
2026-02-27 16:03:49 +08:00
table.RowGroups.Add(group);
doc.Blocks.Add(table);
2026-04-07 14:47:36 +08:00
}
#endregion
2026-02-27 16:03:49 +08:00
2026-04-07 14:47:36 +08:00
#region
private static void AddPoreDistributionResult(FlowDocument doc, PoreDistributionRecord record)
{
var title = new Paragraph(new Run("测试计算结果"))
2026-02-27 16:03:49 +08:00
{
2026-04-07 14:47:36 +08:00
FontSize = 18,
FontWeight = FontWeights.Bold,
Margin = new Thickness(0, 15, 0, 10)
};
doc.Blocks.Add(title);
var table = CreateStandardTable();
var group = new TableRowGroup();
AddTableRow(group, "泡点压力", $"{record.BubblePointPressure} {record.PressureUnit}");
AddTableRow(group, "平均孔径", $"{record.AveragePoreSize:F3} μm");
AddTableRow(group, "测试液体", record.Liquid?.Name ?? "-");
AddTableRow(group, "液体表面张力", record.Liquid?.SurfaceTension.ToString() ?? "-");
AddTableRow(group, "液体厂家", record.LiquidManufacturer ?? "-");
AddTableRow(group, "测试温度", $"{record.RoomTemperature:F1} ℃");
AddTableRow(group, "浸润时间", $"{record.SoakingTime:F1} h");
AddTableRow(group, "压力单位", record.PressureUnit);
AddTableRow(group, "数据点数", record.DataPoints?.Count.ToString() ?? "0");
2026-02-27 16:03:49 +08:00
2026-04-07 14:47:36 +08:00
table.RowGroups.Add(group);
doc.Blocks.Add(table);
2026-02-27 16:03:49 +08:00
}
2026-04-07 14:47:36 +08:00
/// <summary>
/// 添加压力-流量曲线图(带图例:红线=干膜,蓝线=湿膜)
/// </summary>
private static void AddPressureFlowChart(FlowDocument doc, PlotModel plotModel)
2026-02-27 16:03:49 +08:00
{
2026-04-07 14:47:36 +08:00
if (plotModel == null) return;
2026-02-27 16:03:49 +08:00
2026-04-07 14:47:36 +08:00
var title = new Paragraph(new Run("压力 - 流量曲线图"))
2026-02-27 16:03:49 +08:00
{
2026-04-07 14:47:36 +08:00
FontSize = 16,
2026-02-27 16:03:49 +08:00
FontWeight = FontWeights.Bold,
2026-04-07 14:47:36 +08:00
Margin = new Thickness(0, 20, 0, 15)
};
doc.Blocks.Add(title);
// 确保图表显示图例(红线=干膜,蓝线=湿膜)
plotModel.IsLegendVisible = true;
//plotModel.LegendPosition = LegendPosition.RightTop;
using var stream = new MemoryStream();
var exporter = new PngExporter { Width = 700, Height = 400, Resolution = 96 };
exporter.Export(plotModel, stream);
stream.Position = 0;
var bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.StreamSource = stream;
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.EndInit();
bitmap.Freeze();
var image = new Image
2026-02-27 16:03:49 +08:00
{
2026-04-07 14:47:36 +08:00
Source = bitmap,
Width = 700,
Height = 400,
Stretch = Stretch.Uniform,
HorizontalAlignment = HorizontalAlignment.Center
};
var container = new BlockUIContainer(image)
{
Margin = new Thickness(0, 0, 0, 20)
};
doc.Blocks.Add(container);
2026-02-27 16:03:49 +08:00
2026-04-07 14:47:36 +08:00
var legend = new Paragraph(new Run("■ 红色线:干膜流量 ■ 蓝色线:湿膜流量"))
2026-02-27 16:03:49 +08:00
{
FontSize = 14,
FontWeight = FontWeights.Bold,
2026-04-07 14:47:36 +08:00
TextAlignment = TextAlignment.Center,
Margin = new Thickness(0, 0, 0, 20)
};
doc.Blocks.Add(legend);
}
2026-02-27 16:03:49 +08:00
2026-04-07 14:47:36 +08:00
/// <summary>
/// 添加湿膜/干膜数据表(有效数据、排序、排版规整)
/// </summary>
private static void AddTestDataTables(FlowDocument doc, PoreDistributionRecord record)
{
// 湿膜数据
var wetPoints = record.DataPoints
.Where(x => x.WetFlow > 0)
.OrderBy(x => x.Pressure)
.ToList();
2026-02-27 16:03:49 +08:00
2026-04-07 14:47:36 +08:00
if (wetPoints.Any())
{
AddDataTableTitle(doc, "湿膜测试数据");
var wetTable = CreateTwoColumnDataTable("压力", "湿膜流量 (L/min)");
var wetGroup = new TableRowGroup();
foreach (var p in wetPoints)
{
var row = new TableRow();
row.Cells.Add(CreateDataCell(p.Pressure.ToString("F2")));
row.Cells.Add(CreateDataCell(p.WetFlow.ToString("F3")));
wetGroup.Rows.Add(row);
}
wetTable.RowGroups.Add(wetGroup);
doc.Blocks.Add(wetTable);
2026-02-27 16:03:49 +08:00
}
2026-04-07 14:47:36 +08:00
// 干膜数据
var dryPoints = record.DataPoints
.Where(x => x.DryFlow > 0)
.OrderBy(x => x.Pressure)
.ToList();
2026-02-27 16:03:49 +08:00
2026-04-07 14:47:36 +08:00
if (dryPoints.Any())
2026-02-27 16:03:49 +08:00
{
2026-04-07 14:47:36 +08:00
AddDataTableTitle(doc, "干膜测试数据");
var dryTable = CreateTwoColumnDataTable("压力", "干膜流量 (L/min)");
var dryGroup = new TableRowGroup();
foreach (var p in dryPoints)
2026-02-27 16:03:49 +08:00
{
2026-04-07 14:47:36 +08:00
var row = new TableRow();
row.Cells.Add(CreateDataCell(p.Pressure.ToString("F2")));
row.Cells.Add(CreateDataCell(p.DryFlow.ToString("F3")));
dryGroup.Rows.Add(row);
2026-02-27 16:03:49 +08:00
}
2026-04-07 14:47:36 +08:00
dryTable.RowGroups.Add(dryGroup);
doc.Blocks.Add(dryTable);
}
}
/// <summary>
/// 添加孔分布表格
/// </summary>
private static void AddPoreDistributionTable(FlowDocument doc, PoreDistributionRecord record)
{
if (record.PoreDistributions == null || !record.PoreDistributions.Any()) return;
2026-02-27 16:03:49 +08:00
2026-04-07 14:47:36 +08:00
AddDataTableTitle(doc, "孔径分布结果");
var table = new Table
{
CellSpacing = 0,
Margin = new Thickness(0, 10, 0, 20),
BorderThickness = new Thickness(1),
BorderBrush = Brushes.Black
};
table.Columns.Add(new TableColumn { Width = new GridLength(220) });
table.Columns.Add(new TableColumn { Width = new GridLength(220) });
table.Columns.Add(new TableColumn { Width = new GridLength(220) });
var group = new TableRowGroup();
// 表头
var header = new TableRow();
header.Cells.Add(CreateDataCell("孔径下限 (μm)", true));
header.Cells.Add(CreateDataCell("孔径上限 (μm)", true));
header.Cells.Add(CreateDataCell("分布百分比 (%)", true));
group.Rows.Add(header);
// 数据行
foreach (var item in record.PoreDistributions.OrderBy(x => x.LowerPore))
{
var row = new TableRow();
row.Cells.Add(CreateDataCell(item.LowerPore.ToString("F3")));
row.Cells.Add(CreateDataCell(item.UpperPore.ToString("F3")));
row.Cells.Add(CreateDataCell(item.Percentage.ToString("F1")));
group.Rows.Add(row);
2026-02-27 16:03:49 +08:00
}
2026-04-07 14:47:36 +08:00
table.RowGroups.Add(group);
doc.Blocks.Add(table);
}
// 辅助:表格标题
private static void AddDataTableTitle(FlowDocument doc, string title)
{
var para = new Paragraph(new Run(title))
2026-02-27 16:03:49 +08:00
{
2026-04-07 14:47:36 +08:00
FontSize = 15,
FontWeight = FontWeights.Bold,
Margin = new Thickness(0, 20, 0, 8)
};
doc.Blocks.Add(para);
}
2026-02-27 16:03:49 +08:00
2026-04-07 14:47:36 +08:00
// 辅助:创建双列数据表格
private static Table CreateTwoColumnDataTable(string col1, string col2)
{
var table = new Table
{
CellSpacing = 0,
Margin = new Thickness(0, 0, 0, 15),
BorderThickness = new Thickness(1),
BorderBrush = Brushes.Black
};
table.Columns.Add(new TableColumn { Width = new GridLength(330) });
table.Columns.Add(new TableColumn { Width = new GridLength(330) });
var headerGroup = new TableRowGroup();
var header = new TableRow();
header.Cells.Add(CreateDataCell(col1, true));
header.Cells.Add(CreateDataCell(col2, true));
headerGroup.Rows.Add(header);
table.RowGroups.Add(headerGroup);
return table;
2026-02-27 16:03:49 +08:00
}
2026-04-07 14:47:36 +08:00
// 辅助:数据单元格
private static TableCell CreateDataCell(string text, bool isHeader = false)
2026-02-27 16:03:49 +08:00
{
2026-04-07 14:47:36 +08:00
var para = new Paragraph(new Run(text))
{
FontSize = 12,
Padding = new Thickness(6),
Margin = new Thickness(0),
TextAlignment = TextAlignment.Center
};
if (isHeader) para.FontWeight = FontWeights.Bold;
return new TableCell(para);
2026-02-27 16:03:49 +08:00
}
2026-04-07 14:47:36 +08:00
#endregion
2026-02-27 16:03:49 +08:00
2026-04-07 14:47:36 +08:00
#region
/// <summary>
/// 显示打印对话框并打印
/// </summary>
2026-02-27 16:03:49 +08:00
private static void ShowPrintPreview(FlowDocument document, string title)
{
2026-04-07 14:47:36 +08:00
try
2026-02-27 16:03:49 +08:00
{
2026-04-07 14:47:36 +08:00
var dialog = new PrintDialog();
if (dialog.ShowDialog() == true)
{
document.PageWidth = dialog.PrintableAreaWidth;
document.PageHeight = dialog.PrintableAreaHeight;
document.PagePadding = new Thickness(40);
2026-02-27 16:03:49 +08:00
2026-04-07 14:47:36 +08:00
// 修复:正确获取分页器
IDocumentPaginatorSource paginatorSource = document;
dialog.PrintDocument(paginatorSource.DocumentPaginator, title);
}
}
catch (Exception ex)
{
MessageBox.Show($"打印失败:{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
2026-02-27 16:03:49 +08:00
}
}
2026-04-07 14:47:36 +08:00
#endregion
2026-02-27 16:03:49 +08:00
}
}