310 lines
13 KiB
C#
310 lines
13 KiB
C#
using OfficeOpenXml;
|
|
using OfficeOpenXml.Drawing.Chart;
|
|
using OfficeOpenXml.Style;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using TabletTester2025.Models;
|
|
|
|
namespace TabletTester2025.Services
|
|
{
|
|
public class ExcelExportService
|
|
{
|
|
public void ExportToExcel(IEnumerable<TestBatch> batches, string filePath)
|
|
{
|
|
using var package = new ExcelPackage(new FileInfo(filePath));
|
|
|
|
var hardnessData = batches.Where(b => b.TestType == "硬度").ToList();
|
|
var friabilityData = batches.Where(b => b.TestType == "脆碎度").ToList();
|
|
var disintegrationData = batches.Where(b => b.TestType == "崩解").ToList();
|
|
var dissolutionData = batches.Where(b => b.TestType == "溶出").ToList();
|
|
|
|
AddHardnessSheet(package, hardnessData);
|
|
AddFriabilitySheet(package, friabilityData);
|
|
AddDisintegrationSheet(package, disintegrationData);
|
|
AddDissolutionSheet(package, dissolutionData);
|
|
|
|
package.Save();
|
|
}
|
|
|
|
public void ExportHardnessToExcel(IEnumerable<TestBatch> batches, string filePath)
|
|
{
|
|
using var package = new ExcelPackage(new FileInfo(filePath));
|
|
AddHardnessSheet(package, batches);
|
|
package.Save();
|
|
}
|
|
|
|
public void ExportFriabilityToExcel(IEnumerable<TestBatch> batches, string filePath)
|
|
{
|
|
using var package = new ExcelPackage(new FileInfo(filePath));
|
|
AddFriabilitySheet(package, batches);
|
|
package.Save();
|
|
}
|
|
|
|
public void ExportDisintegrationToExcel(IEnumerable<TestBatch> batches, string filePath)
|
|
{
|
|
using var package = new ExcelPackage(new FileInfo(filePath));
|
|
AddDisintegrationSheet(package, batches);
|
|
package.Save();
|
|
}
|
|
|
|
public void ExportDissolutionToExcel(IEnumerable<TestBatch> batches, string filePath)
|
|
{
|
|
using var package = new ExcelPackage(new FileInfo(filePath));
|
|
AddDissolutionSheet(package, batches);
|
|
package.Save();
|
|
}
|
|
|
|
private static void AddHardnessSheet(ExcelPackage package, IEnumerable<TestBatch> batches)
|
|
{
|
|
var data = batches.ToList();
|
|
var sheet = package.Workbook.Worksheets.Add("硬度报表");
|
|
WriteHeader(sheet, "检测时间", "样品名称", "平均值(N)", "RSD(%)", "最大值(N)", "最小值(N)", "测试次数", "内控下限(N)", "内控上限(N)", "判定");
|
|
|
|
if (data.Count == 0)
|
|
{
|
|
sheet.Cells[2, 1].Value = "无硬度测试数据";
|
|
sheet.Cells.AutoFitColumns();
|
|
return;
|
|
}
|
|
|
|
int row = 2;
|
|
foreach (var b in data)
|
|
{
|
|
sheet.Cells[row, 1].Value = b.TestTime.ToString("yyyy-MM-dd HH:mm:ss");
|
|
sheet.Cells[row, 2].Value = b.SampleName;
|
|
sheet.Cells[row, 3].Value = b.HardnessAvg;
|
|
sheet.Cells[row, 4].Value = b.HardnessRSD;
|
|
sheet.Cells[row, 5].Value = b.HardnessMax;
|
|
sheet.Cells[row, 6].Value = b.HardnessMin;
|
|
sheet.Cells[row, 7].Value = b.HardnessTestCount;
|
|
sheet.Cells[row, 8].Value = b.HardnessInternalMin;
|
|
sheet.Cells[row, 9].Value = b.HardnessInternalMax;
|
|
sheet.Cells[row, 10].Value = b.HardnessPassText;
|
|
row++;
|
|
}
|
|
|
|
sheet.Cells.AutoFitColumns();
|
|
}
|
|
|
|
private static void AddFriabilitySheet(ExcelPackage package, IEnumerable<TestBatch> batches)
|
|
{
|
|
var data = batches.ToList();
|
|
var sheet = package.Workbook.Worksheets.Add("脆碎度报表");
|
|
WriteHeader(sheet, "检测时间", "样品名称", "失重率(%)", "设定转速(r/min)", "试验转数", "前重(g)", "后重(g)", "判定");
|
|
|
|
if (data.Count == 0)
|
|
{
|
|
sheet.Cells[2, 1].Value = "无脆碎度测试数据";
|
|
sheet.Cells.AutoFitColumns();
|
|
return;
|
|
}
|
|
|
|
int row = 2;
|
|
foreach (var b in data)
|
|
{
|
|
sheet.Cells[row, 1].Value = b.TestTime.ToString("yyyy-MM-dd HH:mm:ss");
|
|
sheet.Cells[row, 2].Value = b.SampleName;
|
|
sheet.Cells[row, 3].Value = b.FriabilityLoss;
|
|
sheet.Cells[row, 4].Value = b.FriabilityTargetRpm;
|
|
sheet.Cells[row, 5].Value = b.FriabilityTargetRounds;
|
|
sheet.Cells[row, 6].Value = b.WeightBefore;
|
|
sheet.Cells[row, 7].Value = b.WeightAfter;
|
|
sheet.Cells[row, 8].Value = b.FriabilityPassText;
|
|
row++;
|
|
}
|
|
|
|
sheet.Cells.AutoFitColumns();
|
|
}
|
|
|
|
private static void AddDisintegrationSheet(ExcelPackage package, IEnumerable<TestBatch> batches)
|
|
{
|
|
var data = batches.ToList();
|
|
var sheet = package.Workbook.Worksheets.Add("崩解报表");
|
|
WriteHeader(sheet, "检测时间", "样品名称", "剂型规则", "时限(秒)", "崩解时间(秒)", "剩余未崩解管", "水浴温度(℃)", "判定");
|
|
|
|
if (data.Count == 0)
|
|
{
|
|
sheet.Cells[2, 1].Value = "无崩解测试数据";
|
|
sheet.Cells.AutoFitColumns();
|
|
return;
|
|
}
|
|
|
|
int row = 2;
|
|
foreach (var b in data)
|
|
{
|
|
sheet.Cells[row, 1].Value = b.TestTime.ToString("yyyy-MM-dd HH:mm:ss");
|
|
sheet.Cells[row, 2].Value = b.SampleName;
|
|
sheet.Cells[row, 3].Value = b.DisintegrationDosageForm;
|
|
sheet.Cells[row, 4].Value = b.DisintegrationLimitSeconds;
|
|
sheet.Cells[row, 5].Value = b.DisintegrationTimeSec;
|
|
sheet.Cells[row, 6].Value = b.RemainingTubesAtEnd;
|
|
sheet.Cells[row, 7].Value = b.DisintegrationTemp;
|
|
sheet.Cells[row, 8].Value = b.DisintegrationPassText;
|
|
row++;
|
|
}
|
|
|
|
sheet.Cells.AutoFitColumns();
|
|
}
|
|
|
|
private static void AddDissolutionSheet(ExcelPackage package, IEnumerable<TestBatch> batches)
|
|
{
|
|
var data = batches.ToList();
|
|
var sheet = package.Workbook.Worksheets.Add("溶出报表");
|
|
WriteHeader(sheet, "检测时间", "样品名称", "通道", "30min溶出度(%)", "R²", "取样明细", "判定");
|
|
|
|
if (data.Count == 0)
|
|
{
|
|
sheet.Cells[2, 1].Value = "无溶出测试数据";
|
|
sheet.Cells.AutoFitColumns();
|
|
return;
|
|
}
|
|
|
|
int row = 2;
|
|
foreach (var b in data)
|
|
{
|
|
sheet.Cells[row, 1].Value = b.TestTime.ToString("yyyy-MM-dd HH:mm:ss");
|
|
sheet.Cells[row, 2].Value = b.SampleName;
|
|
sheet.Cells[row, 3].Value = b.DissolutionChannel;
|
|
sheet.Cells[row, 4].Value = b.DissolutionRate30Min;
|
|
sheet.Cells[row, 5].Value = b.DissolutionRSquared;
|
|
sheet.Cells[row, 6].Value = b.DissolutionSampleSummary;
|
|
sheet.Cells[row, 7].Value = b.DissolutionPassText;
|
|
row++;
|
|
}
|
|
|
|
sheet.Cells.AutoFitColumns();
|
|
AddDissolutionSamplesSheet(package, data);
|
|
AddDissolutionChartSheet(package, data);
|
|
}
|
|
|
|
private static void AddDissolutionSamplesSheet(ExcelPackage package, IEnumerable<TestBatch> batches)
|
|
{
|
|
var samples = GetDissolutionSampleRows(batches).ToList();
|
|
if (samples.Count == 0)
|
|
return;
|
|
|
|
var sheet = package.Workbook.Worksheets.Add("溶出取样明细");
|
|
WriteHeader(sheet, "检测时间", "样品名称", "通道", "计划时间(min)", "实际时间(min)", "溶出度(%)", "记录时间");
|
|
|
|
int row = 2;
|
|
foreach (var item in samples)
|
|
{
|
|
sheet.Cells[row, 1].Value = item.Batch.TestTime.ToString("yyyy-MM-dd HH:mm:ss");
|
|
sheet.Cells[row, 2].Value = item.Batch.SampleName;
|
|
sheet.Cells[row, 3].Value = item.Sample.ChannelName;
|
|
sheet.Cells[row, 4].Value = item.Sample.ScheduledTimeMin;
|
|
sheet.Cells[row, 5].Value = item.Sample.ActualTimeMin;
|
|
sheet.Cells[row, 6].Value = item.Sample.Percent;
|
|
sheet.Cells[row, 7].Value = item.Sample.RecordedAt?.ToString("yyyy-MM-dd HH:mm:ss");
|
|
row++;
|
|
}
|
|
|
|
sheet.Cells.AutoFitColumns();
|
|
}
|
|
|
|
private static void AddDissolutionChartSheet(ExcelPackage package, IEnumerable<TestBatch> batches)
|
|
{
|
|
var seriesGroups = GetDissolutionSampleRows(batches)
|
|
.Where(x => x.Sample.Percent.HasValue
|
|
&& double.IsFinite(x.Sample.ScheduledTimeMin)
|
|
&& x.Sample.ScheduledTimeMin >= 0
|
|
&& double.IsFinite(x.Sample.Percent.Value))
|
|
.GroupBy(x => new
|
|
{
|
|
x.Batch.Id,
|
|
x.Batch.TestTime,
|
|
x.Batch.SampleName,
|
|
x.Sample.ChannelName
|
|
})
|
|
.Select(group => new
|
|
{
|
|
Name = $"{group.Key.TestTime:MM-dd HH:mm} {group.Key.SampleName} {group.Key.ChannelName}",
|
|
Points = group
|
|
.OrderBy(x => x.Sample.ScheduledTimeMin)
|
|
.Select(x => new { Time = x.Sample.ScheduledTimeMin, Percent = x.Sample.Percent!.Value })
|
|
.ToList()
|
|
})
|
|
.Where(group => group.Points.Count > 0)
|
|
.ToList();
|
|
|
|
var sheet = package.Workbook.Worksheets.Add("溶出曲线");
|
|
if (seriesGroups.Count == 0)
|
|
{
|
|
sheet.Cells[1, 1].Value = "无可绘制溶出曲线数据";
|
|
sheet.Cells.AutoFitColumns();
|
|
return;
|
|
}
|
|
|
|
int column = 1;
|
|
foreach (var group in seriesGroups)
|
|
{
|
|
sheet.Cells[1, column].Value = $"{group.Name} 时间(min)";
|
|
sheet.Cells[1, column + 1].Value = $"{group.Name} 溶出度(%)";
|
|
|
|
int row = 2;
|
|
foreach (var point in group.Points)
|
|
{
|
|
sheet.Cells[row, column].Value = point.Time;
|
|
sheet.Cells[row, column + 1].Value = point.Percent;
|
|
row++;
|
|
}
|
|
|
|
column += 3;
|
|
}
|
|
|
|
using (var header = sheet.Cells[1, 1, 1, Math.Max(1, column - 2)])
|
|
{
|
|
header.Style.Font.Bold = true;
|
|
}
|
|
|
|
int dataEndRow = seriesGroups.Max(group => group.Points.Count) + 1;
|
|
int chartStartRow = dataEndRow + 2;
|
|
|
|
var chart = sheet.Drawings.AddChart("DissolutionCurve", eChartType.LineMarkers);
|
|
chart.Title.Text = "溶出曲线";
|
|
chart.SetPosition(chartStartRow - 1, 0, 0, 0);
|
|
chart.SetSize(900, 420);
|
|
chart.XAxis.Title.Text = "计划时间(min)";
|
|
chart.YAxis.Title.Text = "溶出度(%)";
|
|
chart.YAxis.MinValue = 0;
|
|
chart.YAxis.MaxValue = 150;
|
|
chart.Legend.Position = eLegendPosition.Bottom;
|
|
|
|
column = 1;
|
|
foreach (var group in seriesGroups)
|
|
{
|
|
int endRow = group.Points.Count + 1;
|
|
var series = chart.Series.Add(
|
|
sheet.Cells[2, column + 1, endRow, column + 1],
|
|
sheet.Cells[2, column, endRow, column]);
|
|
series.Header = group.Name;
|
|
column += 3;
|
|
}
|
|
|
|
sheet.Cells.AutoFitColumns();
|
|
}
|
|
|
|
private static IEnumerable<(TestBatch Batch, DissolutionSamplePoint Sample)> GetDissolutionSampleRows(IEnumerable<TestBatch> batches)
|
|
{
|
|
return batches
|
|
.SelectMany(batch => (batch.DissolutionSamples ?? Enumerable.Empty<DissolutionSamplePoint>())
|
|
.Select(sample => (Batch: batch, Sample: sample)))
|
|
.OrderBy(x => x.Batch.TestTime)
|
|
.ThenBy(x => x.Sample.Channel)
|
|
.ThenBy(x => x.Sample.ScheduledTimeMin);
|
|
}
|
|
|
|
private static void WriteHeader(ExcelWorksheet sheet, params string[] headers)
|
|
{
|
|
for (int i = 0; i < headers.Length; i++)
|
|
sheet.Cells[1, i + 1].Value = headers[i];
|
|
|
|
using var range = sheet.Cells[1, 1, 1, headers.Length];
|
|
range.Style.Font.Bold = true;
|
|
range.Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
|
|
}
|
|
}
|
|
}
|