Files
VacuumPressureMembranePoreS…/Helpers/ReportGenerator.cs
2026-04-07 14:47:36 +08:00

444 lines
16 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 MembranePoreTester.Models;
using OxyPlot;
using OxyPlot.Legends;
using OxyPlot.Wpf;
using System;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using FontWeights = System.Windows.FontWeights;
using HorizontalAlignment = System.Windows.HorizontalAlignment;
namespace MembranePoreTester.Helpers
{
/// <summary>
/// 膜测试报告生成器(泡点法 + 孔分布)
/// 排版规范A4自适应、居中对齐、表格规整、图表清晰、数据准确
/// </summary>
public static class ReportGenerator
{
#region
/// <summary>
/// 生成泡点法测试报告
/// </summary>
public static void GenerateBubblePointReport(BubblePointRecord record)
{
if (record == null)
{
MessageBox.Show("无测试数据,无法生成报告");
return;
}
var doc = new FlowDocument();
SetA4PageSettings(doc);
AddReportTitle(doc, "泡点法测试报告");
AddTestInfo(doc, record);
AddBubblePointDataTable(doc, record);
AddStandardRemark(doc);
ShowPrintPreview(doc, "泡点法测试报告");
}
/// <summary>
/// 生成孔分布测试报告
/// </summary>
public static void GeneratePoreDistributionReport(PoreDistributionRecord record, PlotModel plotModel)
{
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);
ShowPrintPreview(doc, "孔分布测试报告");
}
#endregion
#region
/// <summary>
/// 设置A4标准打印页面
/// </summary>
private static void SetA4PageSettings(FlowDocument doc)
{
doc.PageWidth = 793; // A4宽度
doc.PageHeight = 1122; // A4高度
doc.PagePadding = new Thickness(40);
doc.ColumnWidth = 793;
}
/// <summary>
/// 添加报告标题(居中、加粗、大字体)
/// </summary>
private static void AddReportTitle(FlowDocument doc, string title)
{
var titlePara = new Paragraph(new Run(title))
{
FontSize = 26,
FontWeight = FontWeights.Bold,
TextAlignment = TextAlignment.Center,
Margin = new Thickness(0, 0, 0, 25)
};
doc.Blocks.Add(titlePara);
}
/// <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}"))
{
FontSize = 13,
Margin = new Thickness(0, 0, 0, 20)
};
doc.Blocks.Add(infoPara);
}
/// <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);
}
/// <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");
table.RowGroups.Add(group);
doc.Blocks.Add(table);
}
#endregion
#region
private static void AddPoreDistributionResult(FlowDocument doc, PoreDistributionRecord record)
{
var title = new Paragraph(new Run("测试计算结果"))
{
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");
table.RowGroups.Add(group);
doc.Blocks.Add(table);
}
/// <summary>
/// 添加压力-流量曲线图(带图例:红线=干膜,蓝线=湿膜)
/// </summary>
private static void AddPressureFlowChart(FlowDocument doc, PlotModel plotModel)
{
if (plotModel == null) return;
var title = new Paragraph(new Run("压力 - 流量曲线图"))
{
FontSize = 16,
FontWeight = FontWeights.Bold,
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
{
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);
var legend = new Paragraph(new Run("■ 红色线:干膜流量 ■ 蓝色线:湿膜流量"))
{
FontSize = 14,
FontWeight = FontWeights.Bold,
TextAlignment = TextAlignment.Center,
Margin = new Thickness(0, 0, 0, 20)
};
doc.Blocks.Add(legend);
}
/// <summary>
/// 添加湿膜/干膜数据表(有效数据、排序、排版规整)
/// </summary>
private static void AddTestDataTables(FlowDocument doc, PoreDistributionRecord record)
{
// 湿膜数据
var wetPoints = record.DataPoints
.Where(x => x.WetFlow > 0)
.OrderBy(x => x.Pressure)
.ToList();
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);
}
// 干膜数据
var dryPoints = record.DataPoints
.Where(x => x.DryFlow > 0)
.OrderBy(x => x.Pressure)
.ToList();
if (dryPoints.Any())
{
AddDataTableTitle(doc, "干膜测试数据");
var dryTable = CreateTwoColumnDataTable("压力", "干膜流量 (L/min)");
var dryGroup = new TableRowGroup();
foreach (var p in dryPoints)
{
var row = new TableRow();
row.Cells.Add(CreateDataCell(p.Pressure.ToString("F2")));
row.Cells.Add(CreateDataCell(p.DryFlow.ToString("F3")));
dryGroup.Rows.Add(row);
}
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;
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);
}
table.RowGroups.Add(group);
doc.Blocks.Add(table);
}
// 辅助:表格标题
private static void AddDataTableTitle(FlowDocument doc, string title)
{
var para = new Paragraph(new Run(title))
{
FontSize = 15,
FontWeight = FontWeights.Bold,
Margin = new Thickness(0, 20, 0, 8)
};
doc.Blocks.Add(para);
}
// 辅助:创建双列数据表格
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;
}
// 辅助:数据单元格
private static TableCell CreateDataCell(string text, bool isHeader = false)
{
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);
}
#endregion
#region
/// <summary>
/// 显示打印对话框并打印
/// </summary>
private static void ShowPrintPreview(FlowDocument document, string title)
{
try
{
var dialog = new PrintDialog();
if (dialog.ShowDialog() == true)
{
document.PageWidth = dialog.PrintableAreaWidth;
document.PageHeight = dialog.PrintableAreaHeight;
document.PagePadding = new Thickness(40);
// 修复:正确获取分页器
IDocumentPaginatorSource paginatorSource = document;
dialog.PrintDocument(paginatorSource.DocumentPaginator, title);
}
}
catch (Exception ex)
{
MessageBox.Show($"打印失败:{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
#endregion
}
}