diff --git a/Helpers/ExportHelper.cs b/Helpers/ExportHelper.cs
index a771ade..b105548 100644
--- a/Helpers/ExportHelper.cs
+++ b/Helpers/ExportHelper.cs
@@ -27,31 +27,84 @@ public static class ExportHelper
package.SaveAs(new FileInfo(filePath));
}
+ //public static void ExportPoreDistribution(PoreDistributionEntity entity, string filePath)
+ //{
+ // using var package = new ExcelPackage();
+ // var sheet = package.Workbook.Worksheets.Add("孔分布测试");
+ // sheet.Cells["A1"].Value = "工位"; sheet.Cells["B1"].Value = entity.StationId;
+ // sheet.Cells["A2"].Value = "测试日期"; sheet.Cells["B2"].Value = entity.TestDate.ToString("yyyy-MM-dd HH:mm:ss");
+ // sheet.Cells["A3"].Value = "测试者"; sheet.Cells["B3"].Value = entity.Tester;
+ // sheet.Cells["A4"].Value = "样品类型"; sheet.Cells["B4"].Value = entity.SampleType;
+ // sheet.Cells["A5"].Value = "规格"; sheet.Cells["B5"].Value = entity.SampleSpec;
+ // sheet.Cells["A6"].Value = "室温(°C)"; sheet.Cells["B6"].Value = entity.RoomTemperature;
+ // sheet.Cells["A7"].Value = "浸润时间(h)"; sheet.Cells["B7"].Value = entity.SoakingTime;
+ // sheet.Cells["A8"].Value = "测试液体"; sheet.Cells["B8"].Value = entity.LiquidName;
+ // sheet.Cells["A9"].Value = "液体生产厂家"; sheet.Cells["B9"].Value = entity.LiquidManufacturer;
+ // sheet.Cells["A10"].Value = "泡点压力"; sheet.Cells["B10"].Value = $"{entity.BubblePointPressure} {entity.PressureUnit}";
+ // sheet.Cells["A11"].Value = "平均孔径(μm)"; sheet.Cells["B11"].Value = entity.AveragePoreSize;
+
+ // // 数据点表格
+ // sheet.Cells["A13"].Value = "压力"; sheet.Cells["B13"].Value = "湿膜流量(L/min)"; sheet.Cells["C13"].Value = "干膜流量(L/min)";
+ // int row = 14;
+ // foreach (var dp in entity.DataPoints)
+ // {
+ // sheet.Cells[$"A{row}"].Value = dp.Pressure;
+ // sheet.Cells[$"B{row}"].Value = dp.WetFlow;
+ // sheet.Cells[$"C{row}"].Value = dp.DryFlow;
+ // row++;
+ // }
+
+ // package.SaveAs(new FileInfo(filePath));
+ //}
+
public static void ExportPoreDistribution(PoreDistributionEntity entity, string filePath)
{
using var package = new ExcelPackage();
- var sheet = package.Workbook.Worksheets.Add("孔分布测试");
- sheet.Cells["A1"].Value = "工位"; sheet.Cells["B1"].Value = entity.StationId;
- sheet.Cells["A2"].Value = "测试日期"; sheet.Cells["B2"].Value = entity.TestDate.ToString("yyyy-MM-dd HH:mm:ss");
- sheet.Cells["A3"].Value = "测试者"; sheet.Cells["B3"].Value = entity.Tester;
- sheet.Cells["A4"].Value = "样品类型"; sheet.Cells["B4"].Value = entity.SampleType;
- sheet.Cells["A5"].Value = "规格"; sheet.Cells["B5"].Value = entity.SampleSpec;
- sheet.Cells["A6"].Value = "室温(°C)"; sheet.Cells["B6"].Value = entity.RoomTemperature;
- sheet.Cells["A7"].Value = "浸润时间(h)"; sheet.Cells["B7"].Value = entity.SoakingTime;
- sheet.Cells["A8"].Value = "测试液体"; sheet.Cells["B8"].Value = entity.LiquidName;
- sheet.Cells["A9"].Value = "液体生产厂家"; sheet.Cells["B9"].Value = entity.LiquidManufacturer;
- sheet.Cells["A10"].Value = "泡点压力"; sheet.Cells["B10"].Value = $"{entity.BubblePointPressure} {entity.PressureUnit}";
- sheet.Cells["A11"].Value = "平均孔径(μm)"; sheet.Cells["B11"].Value = entity.AveragePoreSize;
- // 数据点表格
- sheet.Cells["A13"].Value = "压力"; sheet.Cells["B13"].Value = "湿膜流量(L/min)"; sheet.Cells["C13"].Value = "干膜流量(L/min)";
- int row = 14;
- foreach (var dp in entity.DataPoints)
+ // 公共信息工作表(可选)
+ var infoSheet = package.Workbook.Worksheets.Add("测试信息");
+ infoSheet.Cells["A1"].Value = "工位"; infoSheet.Cells["B1"].Value = entity.StationId;
+ infoSheet.Cells["A2"].Value = "测试日期"; infoSheet.Cells["B2"].Value = entity.TestDate.ToString("yyyy-MM-dd HH:mm:ss");
+ infoSheet.Cells["A3"].Value = "测试者"; infoSheet.Cells["B3"].Value = entity.Tester;
+ infoSheet.Cells["A4"].Value = "样品类型"; infoSheet.Cells["B4"].Value = entity.SampleType;
+ infoSheet.Cells["A5"].Value = "规格"; infoSheet.Cells["B5"].Value = entity.SampleSpec;
+ infoSheet.Cells["A6"].Value = "室温(°C)"; infoSheet.Cells["B6"].Value = entity.RoomTemperature;
+ infoSheet.Cells["A7"].Value = "浸润时间(h)"; infoSheet.Cells["B7"].Value = entity.SoakingTime;
+ infoSheet.Cells["A8"].Value = "测试液体"; infoSheet.Cells["B8"].Value = entity.LiquidName;
+ infoSheet.Cells["A9"].Value = "液体生产厂家"; infoSheet.Cells["B9"].Value = entity.LiquidManufacturer;
+ infoSheet.Cells["A10"].Value = "压力单位"; infoSheet.Cells["B10"].Value = entity.PressureUnit;
+ infoSheet.Cells["A11"].Value = "平均孔径(μm)"; infoSheet.Cells["B11"].Value = entity.AveragePoreSize;
+
+ // 湿膜数据表(仅保留湿膜流量 > 0 的点)
+ var wetPoints = entity.DataPoints.Where(dp => dp.WetFlow > 0).OrderBy(dp => dp.Pressure).ToList();
+ if (wetPoints.Any())
{
- sheet.Cells[$"A{row}"].Value = dp.Pressure;
- sheet.Cells[$"B{row}"].Value = dp.WetFlow;
- sheet.Cells[$"C{row}"].Value = dp.DryFlow;
- row++;
+ var wetSheet = package.Workbook.Worksheets.Add("湿膜数据");
+ wetSheet.Cells["A1"].Value = "压力";
+ wetSheet.Cells["B1"].Value = "湿膜流量(L/min)";
+ int row = 2;
+ foreach (var dp in wetPoints)
+ {
+ wetSheet.Cells[$"A{row}"].Value = dp.Pressure;
+ wetSheet.Cells[$"B{row}"].Value = dp.WetFlow;
+ row++;
+ }
+ }
+
+ // 干膜数据表(仅保留干膜流量 > 0 的点)
+ var dryPoints = entity.DataPoints.Where(dp => dp.DryFlow > 0).OrderBy(dp => dp.Pressure).ToList();
+ if (dryPoints.Any())
+ {
+ var drySheet = package.Workbook.Worksheets.Add("干膜数据");
+ drySheet.Cells["A1"].Value = "压力";
+ drySheet.Cells["B1"].Value = "干膜流量(L/min)";
+ int row = 2;
+ foreach (var dp in dryPoints)
+ {
+ drySheet.Cells[$"A{row}"].Value = dp.Pressure;
+ drySheet.Cells[$"B{row}"].Value = dp.DryFlow;
+ row++;
+ }
}
package.SaveAs(new FileInfo(filePath));
diff --git a/Helpers/ReportGenerator.cs b/Helpers/ReportGenerator.cs
index f52176c..457b7cf 100644
--- a/Helpers/ReportGenerator.cs
+++ b/Helpers/ReportGenerator.cs
@@ -1,227 +1,444 @@
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.Xps.Packaging;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using FontWeights = System.Windows.FontWeights;
+using HorizontalAlignment = System.Windows.HorizontalAlignment;
namespace MembranePoreTester.Helpers
{
+ ///
+ /// 膜测试报告生成器(泡点法 + 孔分布)
+ /// 排版规范:A4自适应、居中对齐、表格规整、图表清晰、数据准确
+ ///
public static class ReportGenerator
{
+ #region 公开调用方法
+ ///
+ /// 生成泡点法测试报告
+ ///
public static void GenerateBubblePointReport(BubblePointRecord record)
{
- FlowDocument doc = CreateBubblePointDocument(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, "泡点法测试报告");
}
- public static void GeneratePoreDistributionReport(PoreDistributionRecord record)
+ ///
+ /// 生成孔分布测试报告
+ ///
+ public static void GeneratePoreDistributionReport(PoreDistributionRecord record, PlotModel plotModel)
{
- FlowDocument doc = CreatePoreDistributionDocument(record);
+ 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
- private static FlowDocument CreateBubblePointDocument(BubblePointRecord record)
+ #region 通用排版模块
+ ///
+ /// 设置A4标准打印页面
+ ///
+ private static void SetA4PageSettings(FlowDocument doc)
{
- FlowDocument doc = new FlowDocument();
- doc.PageWidth = 800; // 适应打印
-
- // 标题
- doc.Blocks.Add(new Paragraph(new Run("泡点法测试报告"))
- {
- FontSize = 24,
- FontWeight = FontWeights.Bold,
- TextAlignment = TextAlignment.Center
- });
-
- // 日期/测试者
- doc.Blocks.Add(new Paragraph(new Run($"测试日期: {record.TestDate:yyyy-MM-dd} 测试者: {record.Tester}"))
- {
- TextAlignment = TextAlignment.Right
- });
-
- // 样品信息表格
- Table table = new Table();
- table.Columns.Add(new TableColumn { Width = new GridLength(150) });
- table.Columns.Add(new TableColumn { Width = new GridLength(200) });
-
- TableRowGroup group = new TableRowGroup();
- AddRow(group, "膜类型", record.SampleType);
- AddRow(group, "规格", record.SampleSpec);
- AddRow(group, "室温(°C)", record.RoomTemperature.ToString("F1"));
- AddRow(group, "浸润时间(h)", record.SoakingTime.ToString("F1"));
- AddRow(group, "测试液体", record.Liquid?.Name);
- AddRow(group, "液体生产厂家", record.LiquidManufacturer);
- AddRow(group, "泡点压力", $"{record.BubblePointPressure} {record.PressureUnit}");
- AddRow(group, "最大孔径(μm)", record.MaxPoreSize.ToString("F3"));
-
- table.RowGroups.Add(group);
- doc.Blocks.Add(table);
-
- doc.Blocks.Add(new Paragraph(new Run("本报告依据 GB/T 32361-2015 生成。"))
- {
- FontStyle = FontStyles.Italic,
- TextAlignment = TextAlignment.Center,
- Margin = new Thickness(0, 20, 0, 0)
- });
-
- return doc;
+ doc.PageWidth = 793; // A4宽度
+ doc.PageHeight = 1122; // A4高度
+ doc.PagePadding = new Thickness(40);
+ doc.ColumnWidth = 793;
}
- private static FlowDocument CreatePoreDistributionDocument(PoreDistributionRecord record)
+ ///
+ /// 添加报告标题(居中、加粗、大字体)
+ ///
+ private static void AddReportTitle(FlowDocument doc, string title)
{
- FlowDocument doc = new FlowDocument();
- doc.PageWidth = 800;
-
- // 标题
- doc.Blocks.Add(new Paragraph(new Run("孔分布测试报告"))
+ var titlePara = new Paragraph(new Run(title))
{
- FontSize = 24,
+ FontSize = 26,
FontWeight = FontWeights.Bold,
- TextAlignment = TextAlignment.Center
- });
-
- doc.Blocks.Add(new Paragraph(new Run($"测试日期: {record.TestDate:yyyy-MM-dd} 测试者: {record.Tester}"))
- {
- TextAlignment = TextAlignment.Right
- });
-
- // 样品信息表格
- Table infoTable = new Table();
- infoTable.Columns.Add(new TableColumn { Width = new GridLength(150) });
- infoTable.Columns.Add(new TableColumn { Width = new GridLength(200) });
- TableRowGroup group = new TableRowGroup();
- AddRow(group, "膜类型", record.SampleType);
- AddRow(group, "规格", record.SampleSpec);
- AddRow(group, "室温(°C)", record.RoomTemperature.ToString("F1"));
- AddRow(group, "浸润时间(h)", record.SoakingTime.ToString("F1"));
- AddRow(group, "测试液体", record.Liquid?.Name);
- AddRow(group, "液体生产厂家", record.LiquidManufacturer);
- infoTable.RowGroups.Add(group);
- doc.Blocks.Add(infoTable);
-
- // 计算结果
- doc.Blocks.Add(new Paragraph(new Run("测试结果"))
- {
- FontSize = 18,
- FontWeight = FontWeights.Bold,
- Margin = new Thickness(0, 10, 0, 5)
- });
-
- Table resultTable = new Table();
- resultTable.Columns.Add(new TableColumn { Width = new GridLength(150) });
- resultTable.Columns.Add(new TableColumn { Width = new GridLength(200) });
- TableRowGroup resultGroup = new TableRowGroup();
- AddRow(resultGroup, "泡点压力", $"{record.BubblePointPressure} {record.PressureUnit}");
- AddRow(resultGroup, "平均孔径(μm)", record.AveragePoreSize.ToString("F3"));
- resultTable.RowGroups.Add(resultGroup);
- doc.Blocks.Add(resultTable);
-
- // 数据点列表
- doc.Blocks.Add(new Paragraph(new Run("压力-流量数据"))
- {
- FontSize = 14,
- FontWeight = FontWeights.Bold,
- Margin = new Thickness(0, 10, 0, 5)
- });
-
- Table dataTable = new Table();
- dataTable.Columns.Add(new TableColumn { Width = new GridLength(80) });
- dataTable.Columns.Add(new TableColumn { Width = new GridLength(80) });
- dataTable.Columns.Add(new TableColumn { Width = new GridLength(80) });
- dataTable.CellSpacing = 2;
-
- TableRowGroup dataGroup = new TableRowGroup();
-
- // 表头
- TableRow headerRow = new TableRow();
- headerRow.Cells.Add(new TableCell(new Paragraph(new Run("压力"))));
- headerRow.Cells.Add(new TableCell(new Paragraph(new Run("湿膜流量(L/min)"))));
- headerRow.Cells.Add(new TableCell(new Paragraph(new Run("干膜流量(L/min)"))));
- headerRow.FontWeight = FontWeights.Bold;
- dataGroup.Rows.Add(headerRow);
-
- foreach (var dp in record.DataPoints)
- {
- TableRow row = new TableRow();
- row.Cells.Add(new TableCell(new Paragraph(new Run(dp.Pressure.ToString("F2")))));
- row.Cells.Add(new TableCell(new Paragraph(new Run(dp.WetFlow.ToString("F3")))));
- row.Cells.Add(new TableCell(new Paragraph(new Run(dp.DryFlow.ToString("F3")))));
- dataGroup.Rows.Add(row);
- }
-
- dataTable.RowGroups.Add(dataGroup);
- doc.Blocks.Add(dataTable);
-
- // 孔分布结果
- if (record.PoreDistributions != null && record.PoreDistributions.Any())
- {
- doc.Blocks.Add(new Paragraph(new Run("孔分布"))
- {
- FontSize = 14,
- FontWeight = FontWeights.Bold,
- Margin = new Thickness(0, 10, 0, 5)
- });
-
- Table distTable = new Table();
- distTable.Columns.Add(new TableColumn { Width = new GridLength(80) });
- distTable.Columns.Add(new TableColumn { Width = new GridLength(80) });
- distTable.Columns.Add(new TableColumn { Width = new GridLength(80) });
-
- TableRowGroup distGroup = new TableRowGroup();
-
- TableRow distHeader = new TableRow();
- distHeader.Cells.Add(new TableCell(new Paragraph(new Run("孔径下限(μm)"))));
- distHeader.Cells.Add(new TableCell(new Paragraph(new Run("孔径上限(μm)"))));
- distHeader.Cells.Add(new TableCell(new Paragraph(new Run("百分比(%)"))));
- distHeader.FontWeight = FontWeights.Bold;
- distGroup.Rows.Add(distHeader);
-
- foreach (var pd in record.PoreDistributions)
- {
- TableRow row = new TableRow();
- row.Cells.Add(new TableCell(new Paragraph(new Run(pd.LowerPore.ToString("F3")))));
- row.Cells.Add(new TableCell(new Paragraph(new Run(pd.UpperPore.ToString("F3")))));
- row.Cells.Add(new TableCell(new Paragraph(new Run(pd.Percentage.ToString("F1")))));
- distGroup.Rows.Add(row);
- }
-
- distTable.RowGroups.Add(distGroup);
- doc.Blocks.Add(distTable);
- }
-
- doc.Blocks.Add(new Paragraph(new Run("本报告依据 GB/T 32361-2015 生成。"))
- {
- FontStyle = FontStyles.Italic,
TextAlignment = TextAlignment.Center,
- Margin = new Thickness(0, 20, 0, 0)
- });
-
- return doc;
+ Margin = new Thickness(0, 0, 0, 25)
+ };
+ doc.Blocks.Add(titlePara);
}
- private static void AddRow(TableRowGroup group, string label, string value)
+ ///
+ /// 添加测试基础信息(日期、测试人)
+ ///
+ private static void AddTestInfo(FlowDocument doc, dynamic record)
{
- TableRow row = new TableRow();
- row.Cells.Add(new TableCell(new Paragraph(new Run(label))));
- row.Cells.Add(new TableCell(new Paragraph(new Run(value ?? ""))));
+ 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);
+ }
+
+ ///
+ /// 添加标准备注(依据国标)
+ ///
+ 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);
+ }
+
+ ///
+ /// 创建标准两列表格
+ ///
+ 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;
+ }
+
+ ///
+ /// 向表格添加一行(名称 + 值)
+ ///
+ 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);
}
- private static void ShowPrintPreview(FlowDocument document, string title)
+ ///
+ /// 创建表格单元格
+ ///
+ private static TableCell CreateTableCell(string text, bool isBold)
{
- PrintDialog printDialog = new PrintDialog();
- if (printDialog.ShowDialog() == true)
+ var para = new Paragraph(new Run(text))
{
- // 调整文档页面大小以匹配打印机
- document.PageHeight = printDialog.PrintableAreaHeight;
- document.PageWidth = printDialog.PrintableAreaWidth;
- document.PagePadding = new Thickness(50);
+ FontSize = 13,
+ Padding = new Thickness(8, 6, 8, 6),
+ Margin = new Thickness(0)
+ };
+ if (isBold) para.FontWeight = FontWeights.Bold;
+ return new TableCell(para);
+ }
+ #endregion
- IDocumentPaginatorSource dps = document;
- printDialog.PrintDocument(dps.DocumentPaginator, title);
+ #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);
+ }
+
+ ///
+ /// 添加压力-流量曲线图(带图例:红线=干膜,蓝线=湿膜)
+ ///
+ 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);
+ }
+
+ ///
+ /// 添加湿膜/干膜数据表(有效数据、排序、排版规整)
+ ///
+ 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);
}
}
+
+ ///
+ /// 添加孔分布表格
+ ///
+ 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 打印预览
+ ///
+ /// 显示打印对话框并打印
+ ///
+ 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
}
}
\ No newline at end of file
diff --git a/ViewModels/PoreDistributionViewModel.cs b/ViewModels/PoreDistributionViewModel.cs
index 40120e6..37314c2 100644
--- a/ViewModels/PoreDistributionViewModel.cs
+++ b/ViewModels/PoreDistributionViewModel.cs
@@ -106,12 +106,12 @@ namespace MembranePoreTester.ViewModels
if (TestMode.Contains("湿膜"))
{
float rawFlow = await _plcService.ReadWetFlowAsync();
- flow = Math.Round(ConvertFlowByMode(rawFlow), 2);
+ flow = Math.Round(ConvertFlowByMode(rawFlow), 3);
}
else
{
float rawFlow = await _plcService.ReadDryFlowAsync();
- flow = Math.Round(ConvertFlowByMode(rawFlow), 2);
+ flow = Math.Round(ConvertFlowByMode(rawFlow), 3);
}
if (pressure <= 0 || flow <= 0)
@@ -424,7 +424,7 @@ namespace MembranePoreTester.ViewModels
if (TestMode == "湿膜")
{
float rawWet = await _plcService.ReadWetFlowAsync();
- newPoint.WetFlow = ConvertFlowByMode(ConvertFlowByMode(rawWet));
+ newPoint.WetFlow = ConvertFlowByMode(rawWet);
}
else
{
@@ -577,9 +577,95 @@ namespace MembranePoreTester.ViewModels
.ToList();
}
+ //private void GenerateReport()
+ //{
+ // ReportGenerator.GeneratePoreDistributionReport(Record);
+ //}
+
private void GenerateReport()
{
- ReportGenerator.GeneratePoreDistributionReport(Record);
+ // 可选:先清洗数据再生成报告(但不改变原集合)
+ var cleanedPoints = CleanDataPoints(Record.DataPoints);
+ if (cleanedPoints.Count < 2)
+ {
+ MessageBox.Show("有效数据点不足,无法生成报告。");
+ return;
+ }
+ // 临时替换 Record 中的数据点用于报告(不影响界面)
+ var originalPoints = Record.DataPoints.ToList();
+ Record.DataPoints.Clear();
+ foreach (var p in cleanedPoints)
+ Record.DataPoints.Add(p);
+
+
+
+
+
+ ReportGenerator.GeneratePoreDistributionReport(Record, PlotModel);
+
+ // 恢复原始数据
+ Record.DataPoints.Clear();
+ foreach (var p in originalPoints)
+ Record.DataPoints.Add(p);
+
+
+
+
+
+
+
+
+ //// 清空现有数据
+ //Record.DataPoints.Clear();
+
+ //Random rand = new Random();
+
+ //// 生成湿膜数据(模拟压力从0到100,流量先增后减)
+ //for (double pressure = 0; pressure <= 100; pressure += 5)
+ //{
+ // // 模拟流量曲线:先上升后下降,峰值在40-60之间
+ // double wetFlow = 0;
+ // if (pressure < 30)
+ // wetFlow = pressure * 1.5; // 上升段
+ // else if (pressure < 60)
+ // wetFlow = 45 - (pressure - 30) * 0.5; // 下降段
+ // else
+ // wetFlow = 30 - (pressure - 60) * 0.8; // 继续下降
+
+ // // 添加随机波动 (±15%)
+ // wetFlow = wetFlow * (0.85 + rand.NextDouble() * 0.3);
+ // wetFlow = Math.Round(Math.Max(0, wetFlow), 2);
+
+ // // 干膜数据(稍低于湿膜)
+ // double dryFlow = wetFlow * (0.6 + rand.NextDouble() * 0.3);
+ // dryFlow = Math.Round(dryFlow, 2);
+
+ // Record.DataPoints.Add(new Models.DataPoint
+ // {
+ // Pressure = Math.Round(pressure, 2),
+ // WetFlow = wetFlow,
+ // DryFlow = dryFlow
+ // });
+ //}
+
+ //// 设置一些测试基本参数
+ //Record.SampleType = "平板膜";
+ //Record.SampleSpec = "φ47mm";
+ //Record.RoomTemperature = 22.5;
+ //Record.SoakingTime = 2.0;
+ //Record.Liquid = TestLiquid.Predefined.FirstOrDefault();
+ //Record.LiquidManufacturer = "测试厂家";
+ //Record.PressureUnit = "kPa";
+ //Record.BubblePointPressure = 45.6;
+ //Record.AveragePoreSize = 0.856;
+ //Record.TestDate = DateTime.Now;
+ //Record.Tester = "测试员";
+
+ //// 刷新曲线显示
+ //UpdatePlot();
+
+ //ReportGenerator.GeneratePoreDistributionReport(Record, PlotModel);
+
}
private void OpenFlowCalibration()
@@ -725,17 +811,45 @@ namespace MembranePoreTester.ViewModels
private void ExportToExcel()
{
+ // 使用当前数据点(已通过手动删除或自动清洗,保证有效性)
+ var dataPoints = Record.DataPoints.ToList();
+ if (dataPoints.Count == 0)
+ {
+ MessageBox.Show("没有数据可导出。", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
+ return;
+ }
+
var saveFileDialog = new SaveFileDialog
{
Filter = "Excel文件|*.xlsx",
- FileName = $"泡点法_工位{StationId}_{DateTime.Now:yyyyMMddHHmmss}.xlsx"
+ FileName = $"孔分布_工位{StationId}_{DateTime.Now:yyyyMMddHHmmss}.xlsx"
};
if (saveFileDialog.ShowDialog() == true)
{
- // 转换为Entity后导出
- var entity = new BubblePointEntity { /* 从Record复制 */ };
- ExportHelper.ExportBubblePoint(entity, saveFileDialog.FileName);
- MessageBox.Show("导出成功");
+ var entity = new PoreDistributionEntity
+ {
+ StationId = this.StationId,
+ TestDate = Record.TestDate,
+ Tester = Record.Tester ?? "系统操作员",
+ SampleType = Record.SampleType,
+ SampleSpec = Record.SampleSpec ?? "缺省值",
+ RoomTemperature = Record.RoomTemperature,
+ SoakingTime = Record.SoakingTime,
+ LiquidName = Record.Liquid?.Name,
+ LiquidSurfaceTension = Record.Liquid?.SurfaceTension ?? 0,
+ LiquidManufacturer = Record.LiquidManufacturer ?? "缺省值",
+ PressureUnit = Record.PressureUnit,
+ BubblePointPressure = Record.BubblePointPressure,
+ AveragePoreSize = AveragePoreSize, // 已计算的平均孔径
+ DataPoints = dataPoints.Select(dp => new DataPointEntity
+ {
+ Pressure = dp.Pressure,
+ WetFlow = dp.WetFlow,
+ DryFlow = dp.DryFlow
+ }).ToList()
+ };
+ ExportHelper.ExportPoreDistribution(entity, saveFileDialog.FileName);
+ MessageBox.Show("导出成功", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
}
}
diff --git a/Views/PoreDistributionView.xaml b/Views/PoreDistributionView.xaml
index a2eceaa..791b5ad 100644
--- a/Views/PoreDistributionView.xaml
+++ b/Views/PoreDistributionView.xaml
@@ -185,7 +185,7 @@
-
+