更新
This commit is contained in:
@@ -47,6 +47,7 @@ public sealed class RunExportService
|
|||||||
throw new InvalidOperationException("未找到可导出的有效历史数据。");
|
throw new InvalidOperationException("未找到可导出的有效历史数据。");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var exportStatistics = BuildExportStatistics(runs.Count, exportRuns);
|
||||||
var outputDirectory = Path.GetDirectoryName(outputPath);
|
var outputDirectory = Path.GetDirectoryName(outputPath);
|
||||||
if (!string.IsNullOrWhiteSpace(outputDirectory))
|
if (!string.IsNullOrWhiteSpace(outputDirectory))
|
||||||
{
|
{
|
||||||
@@ -56,13 +57,17 @@ public sealed class RunExportService
|
|||||||
WorksheetChartLayout chartLayout;
|
WorksheetChartLayout chartLayout;
|
||||||
using (var workbook = new XLWorkbook())
|
using (var workbook = new XLWorkbook())
|
||||||
{
|
{
|
||||||
BuildSummarySheet(workbook.Worksheets.Add("报表汇总"), exportRuns);
|
BuildSummarySheet(workbook.Worksheets.Add("报表汇总"), exportRuns, exportStatistics);
|
||||||
BuildRawDataSheet(workbook.Worksheets.Add("原始数据"), exportRuns);
|
BuildRawDataSheet(workbook.Worksheets.Add("原始数据"), exportRuns);
|
||||||
chartLayout = BuildChartSheet(workbook.Worksheets.Add("曲线图"), exportRuns);
|
chartLayout = BuildChartSheet(workbook.Worksheets.Add("曲线图"), exportRuns);
|
||||||
workbook.SaveAs(outputPath);
|
workbook.SaveAs(outputPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (chartLayout.Charts.Count > 0)
|
||||||
|
{
|
||||||
InsertNativeCharts(outputPath, chartLayout);
|
InsertNativeCharts(outputPath, chartLayout);
|
||||||
|
}
|
||||||
|
|
||||||
return outputPath;
|
return outputPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,7 +101,17 @@ public sealed class RunExportService
|
|||||||
.ToArray();
|
.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsValidSample(RawSampleRecord sample)
|
private static ExportReportStatistics BuildExportStatistics(int sourceRunCount, IReadOnlyList<ExportCurveData> exportRuns)
|
||||||
|
{
|
||||||
|
return new ExportReportStatistics(
|
||||||
|
sourceRunCount,
|
||||||
|
exportRuns.Count,
|
||||||
|
exportRuns.Count(IsChartableRun),
|
||||||
|
Math.Max(0, sourceRunCount - exportRuns.Count),
|
||||||
|
exportRuns.Sum(item => item.ValidSamples.Count));
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static bool IsValidSample(RawSampleRecord sample)
|
||||||
{
|
{
|
||||||
return sample.SampleIndex > 0
|
return sample.SampleIndex > 0
|
||||||
&& IsFinite(sample.DisplacementMm)
|
&& IsFinite(sample.DisplacementMm)
|
||||||
@@ -109,7 +124,10 @@ public sealed class RunExportService
|
|||||||
return !double.IsNaN(value) && !double.IsInfinity(value);
|
return !double.IsNaN(value) && !double.IsInfinity(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void BuildSummarySheet(IXLWorksheet worksheet, IReadOnlyList<ExportCurveData> runs)
|
private static void BuildSummarySheet(
|
||||||
|
IXLWorksheet worksheet,
|
||||||
|
IReadOnlyList<ExportCurveData> runs,
|
||||||
|
ExportReportStatistics exportStatistics)
|
||||||
{
|
{
|
||||||
ApplyDefaultWorksheetStyle(worksheet);
|
ApplyDefaultWorksheetStyle(worksheet);
|
||||||
|
|
||||||
@@ -122,11 +140,19 @@ public sealed class RunExportService
|
|||||||
worksheet.Cell("A3").Value = "导出时间";
|
worksheet.Cell("A3").Value = "导出时间";
|
||||||
worksheet.Cell("B3").Value = DateTime.Now;
|
worksheet.Cell("B3").Value = DateTime.Now;
|
||||||
worksheet.Cell("B3").Style.DateFormat.Format = "yyyy-mm-dd hh:mm:ss";
|
worksheet.Cell("B3").Style.DateFormat.Format = "yyyy-mm-dd hh:mm:ss";
|
||||||
worksheet.Cell("A4").Value = "有效历史数量";
|
worksheet.Cell("A4").Value = "历史记录总数";
|
||||||
worksheet.Cell("B4").Value = runs.Count;
|
worksheet.Cell("B4").Value = exportStatistics.SourceRunCount;
|
||||||
worksheet.Cell("A5").Value = "汇总说明";
|
worksheet.Cell("A5").Value = "有效导出记录数";
|
||||||
worksheet.Cell("B5").Value = "本表仅统计含有效采样点的试验记录,包含结果汇总、标准差统计和原始力值统计。";
|
worksheet.Cell("B5").Value = exportStatistics.ExportRunCount;
|
||||||
worksheet.Range("B5:F5").Merge();
|
worksheet.Cell("A6").Value = "曲线图数量";
|
||||||
|
worksheet.Cell("B6").Value = exportStatistics.ChartRunCount;
|
||||||
|
worksheet.Cell("A7").Value = "排除记录数";
|
||||||
|
worksheet.Cell("B7").Value = exportStatistics.ExcludedRunCount;
|
||||||
|
worksheet.Cell("A8").Value = "有效采样点总数";
|
||||||
|
worksheet.Cell("B8").Value = exportStatistics.ValidSampleCount;
|
||||||
|
worksheet.Cell("A9").Value = "汇总说明";
|
||||||
|
worksheet.Cell("B9").Value = "本表仅统计含有效采样点的试验记录;单点记录保留数据但不生成曲线图。";
|
||||||
|
worksheet.Range("B9:F9").Merge();
|
||||||
|
|
||||||
BuildStatisticsPanel(worksheet, runs);
|
BuildStatisticsPanel(worksheet, runs);
|
||||||
|
|
||||||
@@ -309,14 +335,14 @@ public sealed class RunExportService
|
|||||||
worksheet.Cell("A1").Style.Font.FontColor = XLColor.FromHtml("#21313D");
|
worksheet.Cell("A1").Style.Font.FontColor = XLColor.FromHtml("#21313D");
|
||||||
|
|
||||||
worksheet.Cell("A3").Value = "图表说明";
|
worksheet.Cell("A3").Value = "图表说明";
|
||||||
worksheet.Cell("B3").Value = "包含历史总览曲线、静动摩擦趋势图,以及每轮有效数据的单独曲线图。";
|
worksheet.Cell("B3").Value = "每条含至少 2 个有效采样点的历史试验记录对应一个独立曲线图,横轴按真实位移数值比例绘制。";
|
||||||
worksheet.Range("B3:H3").Merge();
|
worksheet.Range("B3:H3").Merge();
|
||||||
|
|
||||||
worksheet.Cell("A5").Value = "曲线清单";
|
worksheet.Cell("A5").Value = "曲线清单";
|
||||||
worksheet.Cell("A5").Style.Font.Bold = true;
|
worksheet.Cell("A5").Style.Font.Bold = true;
|
||||||
worksheet.Cell("A5").Style.Font.FontSize = 12;
|
worksheet.Cell("A5").Style.Font.FontSize = 12;
|
||||||
|
|
||||||
WriteHeaderRow(worksheet, 6, ["曲线标识", "图例标签", "颜色", "有效采样点数"]);
|
WriteHeaderRow(worksheet, 6, ["曲线标识", "图例标签", "颜色", "有效采样点数", "曲线状态"]);
|
||||||
|
|
||||||
for (var index = 0; index < runs.Count; index++)
|
for (var index = 0; index < runs.Count; index++)
|
||||||
{
|
{
|
||||||
@@ -325,13 +351,16 @@ public sealed class RunExportService
|
|||||||
worksheet.Cell(row, 2).Value = BuildLegendLabel(runs[index]);
|
worksheet.Cell(row, 2).Value = BuildLegendLabel(runs[index]);
|
||||||
worksheet.Cell(row, 3).Value = runs[index].CurveColorHex;
|
worksheet.Cell(row, 3).Value = runs[index].CurveColorHex;
|
||||||
worksheet.Cell(row, 4).Value = runs[index].ValidSamples.Count;
|
worksheet.Cell(row, 4).Value = runs[index].ValidSamples.Count;
|
||||||
|
worksheet.Cell(row, 5).Value = IsChartableRun(runs[index])
|
||||||
|
? "已绘制"
|
||||||
|
: "采样点不足,未绘制曲线";
|
||||||
worksheet.Cell(row, 3).Style.Fill.BackgroundColor = ToXlColor(runs[index].CurveColorHex);
|
worksheet.Cell(row, 3).Style.Fill.BackgroundColor = ToXlColor(runs[index].CurveColorHex);
|
||||||
worksheet.Cell(row, 3).Style.Font.FontColor = XLColor.White;
|
worksheet.Cell(row, 3).Style.Font.FontColor = XLColor.White;
|
||||||
}
|
}
|
||||||
|
|
||||||
ApplyChartColumnWidths(worksheet);
|
ApplyChartColumnWidths(worksheet);
|
||||||
var chartLayout = BuildChartDataArea(worksheet, runs);
|
var chartLayout = BuildChartDataArea(worksheet, runs);
|
||||||
ApplyPageLayout(worksheet, Math.Max(40, 25 + ((runs.Count + 1) / 2) * 14), "$A$1:$T$");
|
ApplyPageLayout(worksheet, CalculateChartSheetLastRow(runs), "$A$1:$T$");
|
||||||
worksheet.SheetView.FreezeRows(1);
|
worksheet.SheetView.FreezeRows(1);
|
||||||
return chartLayout;
|
return chartLayout;
|
||||||
}
|
}
|
||||||
@@ -371,8 +400,9 @@ public sealed class RunExportService
|
|||||||
{
|
{
|
||||||
var row = 4 + index;
|
var row = 4 + index;
|
||||||
worksheet.Cell(row, 8).Value = rows[index].Label;
|
worksheet.Cell(row, 8).Value = rows[index].Label;
|
||||||
worksheet.Cell(row, 8).Style.Fill.BackgroundColor = XLColor.FromHtml("#EEF3F7");
|
worksheet.Cell(row, 8).Style.Fill.BackgroundColor = XLColor.FromHtml("#2F4A5C");
|
||||||
worksheet.Cell(row, 8).Style.Font.Bold = true;
|
worksheet.Cell(row, 8).Style.Font.Bold = true;
|
||||||
|
worksheet.Cell(row, 8).Style.Font.FontColor = XLColor.White;
|
||||||
worksheet.Cell(row, 9).Value = rows[index].Value;
|
worksheet.Cell(row, 9).Value = rows[index].Value;
|
||||||
worksheet.Cell(row, 9).Style.Border.BottomBorder = XLBorderStyleValues.Thin;
|
worksheet.Cell(row, 9).Style.Border.BottomBorder = XLBorderStyleValues.Thin;
|
||||||
worksheet.Cell(row, 9).Style.Border.BottomBorderColor = XLColor.FromHtml("#D3DDE5");
|
worksheet.Cell(row, 9).Style.Border.BottomBorderColor = XLColor.FromHtml("#D3DDE5");
|
||||||
@@ -384,7 +414,6 @@ public sealed class RunExportService
|
|||||||
const int startColumn = 30;
|
const int startColumn = 30;
|
||||||
const int startRow = 1;
|
const int startRow = 1;
|
||||||
|
|
||||||
var seriesLayouts = new List<SeriesLayout>();
|
|
||||||
var perRunSeries = new List<PerRunSeriesLayout>();
|
var perRunSeries = new List<PerRunSeriesLayout>();
|
||||||
var currentColumn = startColumn;
|
var currentColumn = startColumn;
|
||||||
var sheetName = worksheet.Name;
|
var sheetName = worksheet.Name;
|
||||||
@@ -420,74 +449,14 @@ public sealed class RunExportService
|
|||||||
BuildRangeReference(sheetName, startDataRow, yColumn, endDataRow, yColumn),
|
BuildRangeReference(sheetName, startDataRow, yColumn, endDataRow, yColumn),
|
||||||
item.CurveColorHex);
|
item.CurveColorHex);
|
||||||
|
|
||||||
seriesLayouts.Add(layout);
|
if (IsChartableRun(item))
|
||||||
|
{
|
||||||
perRunSeries.Add(new PerRunSeriesLayout(item, layout));
|
perRunSeries.Add(new PerRunSeriesLayout(item, layout));
|
||||||
}
|
}
|
||||||
|
|
||||||
var trendHeaderRow = startRow;
|
|
||||||
var trendDataStartRow = startRow + 1;
|
|
||||||
var runIndexColumn = currentColumn;
|
|
||||||
var staticColumn = runIndexColumn + 1;
|
|
||||||
var kineticColumn = runIndexColumn + 2;
|
|
||||||
|
|
||||||
worksheet.Cell(trendHeaderRow, runIndexColumn).Value = "试验轮次";
|
|
||||||
worksheet.Cell(trendHeaderRow, staticColumn).Value = "静摩擦系数 μs";
|
|
||||||
worksheet.Cell(trendHeaderRow, kineticColumn).Value = "动摩擦系数 μk";
|
|
||||||
|
|
||||||
for (var index = 0; index < runs.Count; index++)
|
|
||||||
{
|
|
||||||
var row = trendDataStartRow + index;
|
|
||||||
worksheet.Cell(row, runIndexColumn).Value = runs[index].Data.Run.RunIndex;
|
|
||||||
worksheet.Cell(row, staticColumn).Value = runs[index].Data.Run.StaticCoefficient;
|
|
||||||
worksheet.Cell(row, kineticColumn).Value = runs[index].Data.Run.KineticCoefficient;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
worksheet.Column(runIndexColumn).Hide();
|
var charts = new List<ChartDefinition>();
|
||||||
worksheet.Column(staticColumn).Hide();
|
var perRunStartRow = Math.Max(10, runs.Count + 8);
|
||||||
worksheet.Column(kineticColumn).Hide();
|
|
||||||
|
|
||||||
var trendEndRow = Math.Max(trendDataStartRow, trendDataStartRow + runs.Count - 1);
|
|
||||||
var charts = new List<ChartDefinition>
|
|
||||||
{
|
|
||||||
new(
|
|
||||||
"历史曲线总览",
|
|
||||||
"位移 (mm)",
|
|
||||||
"力值 (N)",
|
|
||||||
true,
|
|
||||||
seriesLayouts,
|
|
||||||
new ChartAnchor(0, 20, 11, 36),
|
|
||||||
"历史曲线总览"),
|
|
||||||
new(
|
|
||||||
"静摩擦系数趋势",
|
|
||||||
"试验轮次",
|
|
||||||
"μs",
|
|
||||||
true,
|
|
||||||
[
|
|
||||||
new SeriesLayout(
|
|
||||||
BuildCellReference(sheetName, trendHeaderRow, staticColumn),
|
|
||||||
BuildRangeReference(sheetName, trendDataStartRow, runIndexColumn, trendEndRow, runIndexColumn),
|
|
||||||
BuildRangeReference(sheetName, trendDataStartRow, staticColumn, trendEndRow, staticColumn),
|
|
||||||
"#5E7DA0")
|
|
||||||
],
|
|
||||||
new ChartAnchor(12, 20, 19, 28),
|
|
||||||
"静摩擦趋势图"),
|
|
||||||
new(
|
|
||||||
"动摩擦系数趋势",
|
|
||||||
"试验轮次",
|
|
||||||
"μk",
|
|
||||||
true,
|
|
||||||
[
|
|
||||||
new SeriesLayout(
|
|
||||||
BuildCellReference(sheetName, trendHeaderRow, kineticColumn),
|
|
||||||
BuildRangeReference(sheetName, trendDataStartRow, runIndexColumn, trendEndRow, runIndexColumn),
|
|
||||||
BuildRangeReference(sheetName, trendDataStartRow, kineticColumn, trendEndRow, kineticColumn),
|
|
||||||
"#00839A")
|
|
||||||
],
|
|
||||||
new ChartAnchor(12, 29, 19, 37),
|
|
||||||
"动摩擦趋势图")
|
|
||||||
};
|
|
||||||
|
|
||||||
const int perRunStartRow = 39;
|
|
||||||
const int chartHeight = 11;
|
const int chartHeight = 11;
|
||||||
const int chartWidth = 9;
|
const int chartWidth = 9;
|
||||||
const int rowGap = 2;
|
const int rowGap = 2;
|
||||||
@@ -515,6 +484,17 @@ public sealed class RunExportService
|
|||||||
return new WorksheetChartLayout(worksheet.Name, charts);
|
return new WorksheetChartLayout(worksheet.Name, charts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool IsChartableRun(ExportCurveData item)
|
||||||
|
{
|
||||||
|
return item.ValidSamples.Count >= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int CalculateChartSheetLastRow(IReadOnlyList<ExportCurveData> runs)
|
||||||
|
{
|
||||||
|
var chartCount = runs.Count(IsChartableRun);
|
||||||
|
return Math.Max(24, runs.Count + 22 + ((chartCount + 1) / 2) * 13);
|
||||||
|
}
|
||||||
|
|
||||||
private static void ApplyDefaultWorksheetStyle(IXLWorksheet worksheet)
|
private static void ApplyDefaultWorksheetStyle(IXLWorksheet worksheet)
|
||||||
{
|
{
|
||||||
worksheet.Style.Font.FontName = "Microsoft YaHei UI";
|
worksheet.Style.Font.FontName = "Microsoft YaHei UI";
|
||||||
@@ -530,9 +510,10 @@ public sealed class RunExportService
|
|||||||
var cell = worksheet.Cell(row, index + 1);
|
var cell = worksheet.Cell(row, index + 1);
|
||||||
cell.Value = headers[index];
|
cell.Value = headers[index];
|
||||||
cell.Style.Font.Bold = true;
|
cell.Style.Font.Bold = true;
|
||||||
cell.Style.Fill.BackgroundColor = XLColor.FromHtml("#E1EAF1");
|
cell.Style.Font.FontColor = XLColor.White;
|
||||||
|
cell.Style.Fill.BackgroundColor = XLColor.FromHtml("#2F4A5C");
|
||||||
cell.Style.Border.BottomBorder = XLBorderStyleValues.Thin;
|
cell.Style.Border.BottomBorder = XLBorderStyleValues.Thin;
|
||||||
cell.Style.Border.BottomBorderColor = XLColor.FromHtml("#B7C4CE");
|
cell.Style.Border.BottomBorderColor = XLColor.FromHtml("#1F3342");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -595,6 +576,7 @@ public sealed class RunExportService
|
|||||||
2 => 28,
|
2 => 28,
|
||||||
3 => 12,
|
3 => 12,
|
||||||
4 => 12,
|
4 => 12,
|
||||||
|
5 => 22,
|
||||||
_ => 14
|
_ => 14
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -681,7 +663,7 @@ public sealed class RunExportService
|
|||||||
|
|
||||||
private static void BuildChartPart(ChartPart chartPart, ChartDefinition chartDefinition)
|
private static void BuildChartPart(ChartPart chartPart, ChartDefinition chartDefinition)
|
||||||
{
|
{
|
||||||
const uint categoryAxisId = 48650112U;
|
const uint xAxisId = 48650112U;
|
||||||
const uint valueAxisId = 48672768U;
|
const uint valueAxisId = 48672768U;
|
||||||
|
|
||||||
var chartSpace = new C.ChartSpace();
|
var chartSpace = new C.ChartSpace();
|
||||||
@@ -694,8 +676,8 @@ public sealed class RunExportService
|
|||||||
var plotArea = new C.PlotArea();
|
var plotArea = new C.PlotArea();
|
||||||
plotArea.Append(new C.Layout());
|
plotArea.Append(new C.Layout());
|
||||||
|
|
||||||
var lineChart = new C.LineChart(
|
var scatterChart = new C.ScatterChart(
|
||||||
new C.Grouping { Val = C.GroupingValues.Standard },
|
new C.ScatterStyle { Val = C.ScatterStyleValues.Line },
|
||||||
new C.VaryColors { Val = false });
|
new C.VaryColors { Val = false });
|
||||||
|
|
||||||
for (var index = 0; index < chartDefinition.Series.Count; index++)
|
for (var index = 0; index < chartDefinition.Series.Count; index++)
|
||||||
@@ -710,25 +692,25 @@ public sealed class RunExportService
|
|||||||
Width = 19050
|
Width = 19050
|
||||||
});
|
});
|
||||||
|
|
||||||
var lineSeries = new C.LineChartSeries(
|
var scatterSeries = new C.ScatterChartSeries(
|
||||||
new C.Index { Val = (uint)index },
|
new C.Index { Val = (uint)index },
|
||||||
new C.Order { Val = (uint)index },
|
new C.Order { Val = (uint)index },
|
||||||
new C.SeriesText(new C.StringReference(new C.Formula(series.TitleReference))),
|
new C.SeriesText(new C.StringReference(new C.Formula(series.TitleReference))),
|
||||||
chartShape,
|
chartShape,
|
||||||
new C.Marker(new C.Symbol { Val = C.MarkerStyleValues.None }),
|
new C.Marker(new C.Symbol { Val = C.MarkerStyleValues.None }),
|
||||||
new C.CategoryAxisData(new C.NumberReference(new C.Formula(series.XValuesReference))),
|
new C.XValues(new C.NumberReference(new C.Formula(series.XValuesReference))),
|
||||||
new C.Values(new C.NumberReference(new C.Formula(series.YValuesReference))),
|
new C.YValues(new C.NumberReference(new C.Formula(series.YValuesReference))),
|
||||||
new C.Smooth { Val = false });
|
new C.Smooth { Val = false });
|
||||||
|
|
||||||
lineChart.Append(lineSeries);
|
scatterChart.Append(scatterSeries);
|
||||||
}
|
}
|
||||||
|
|
||||||
lineChart.Append(new C.AxisId { Val = categoryAxisId });
|
scatterChart.Append(new C.AxisId { Val = xAxisId });
|
||||||
lineChart.Append(new C.AxisId { Val = valueAxisId });
|
scatterChart.Append(new C.AxisId { Val = valueAxisId });
|
||||||
plotArea.Append(lineChart);
|
plotArea.Append(scatterChart);
|
||||||
|
|
||||||
var categoryAxis = new C.CategoryAxis(
|
var xAxis = new C.ValueAxis(
|
||||||
new C.AxisId { Val = categoryAxisId },
|
new C.AxisId { Val = xAxisId },
|
||||||
new C.Scaling(new C.Orientation { Val = C.OrientationValues.MinMax }),
|
new C.Scaling(new C.Orientation { Val = C.OrientationValues.MinMax }),
|
||||||
new C.Delete { Val = false },
|
new C.Delete { Val = false },
|
||||||
new C.AxisPosition { Val = C.AxisPositionValues.Bottom },
|
new C.AxisPosition { Val = C.AxisPositionValues.Bottom },
|
||||||
@@ -737,9 +719,7 @@ public sealed class RunExportService
|
|||||||
new C.TickLabelPosition { Val = C.TickLabelPositionValues.NextTo },
|
new C.TickLabelPosition { Val = C.TickLabelPositionValues.NextTo },
|
||||||
new C.CrossingAxis { Val = valueAxisId },
|
new C.CrossingAxis { Val = valueAxisId },
|
||||||
new C.Crosses { Val = C.CrossesValues.AutoZero },
|
new C.Crosses { Val = C.CrossesValues.AutoZero },
|
||||||
new C.AutoLabeled { Val = true },
|
new C.CrossBetween { Val = C.CrossBetweenValues.Between });
|
||||||
new C.LabelAlignment { Val = C.LabelAlignmentValues.Center },
|
|
||||||
new C.LabelOffset { Val = 100 });
|
|
||||||
|
|
||||||
var valueAxis = new C.ValueAxis(
|
var valueAxis = new C.ValueAxis(
|
||||||
new C.AxisId { Val = valueAxisId },
|
new C.AxisId { Val = valueAxisId },
|
||||||
@@ -750,11 +730,11 @@ public sealed class RunExportService
|
|||||||
new C.NumberingFormat { FormatCode = "0.000", SourceLinked = true },
|
new C.NumberingFormat { FormatCode = "0.000", SourceLinked = true },
|
||||||
CreateAxisTitle(chartDefinition.YAxisTitle),
|
CreateAxisTitle(chartDefinition.YAxisTitle),
|
||||||
new C.TickLabelPosition { Val = C.TickLabelPositionValues.NextTo },
|
new C.TickLabelPosition { Val = C.TickLabelPositionValues.NextTo },
|
||||||
new C.CrossingAxis { Val = categoryAxisId },
|
new C.CrossingAxis { Val = xAxisId },
|
||||||
new C.Crosses { Val = C.CrossesValues.AutoZero },
|
new C.Crosses { Val = C.CrossesValues.AutoZero },
|
||||||
new C.CrossBetween { Val = C.CrossBetweenValues.Between });
|
new C.CrossBetween { Val = C.CrossBetweenValues.Between });
|
||||||
|
|
||||||
plotArea.Append(categoryAxis);
|
plotArea.Append(xAxis);
|
||||||
plotArea.Append(valueAxis);
|
plotArea.Append(valueAxis);
|
||||||
|
|
||||||
chart.Append(plotArea);
|
chart.Append(plotArea);
|
||||||
@@ -965,6 +945,13 @@ public sealed class RunExportService
|
|||||||
|
|
||||||
private sealed record ExportCurveData(PersistedRunData Data, IReadOnlyList<RawSampleRecord> ValidSamples, int Sequence, string CurveColorHex);
|
private sealed record ExportCurveData(PersistedRunData Data, IReadOnlyList<RawSampleRecord> ValidSamples, int Sequence, string CurveColorHex);
|
||||||
|
|
||||||
|
private sealed record ExportReportStatistics(
|
||||||
|
int SourceRunCount,
|
||||||
|
int ExportRunCount,
|
||||||
|
int ChartRunCount,
|
||||||
|
int ExcludedRunCount,
|
||||||
|
int ValidSampleCount);
|
||||||
|
|
||||||
private sealed record SeriesLayout(string TitleReference, string XValuesReference, string YValuesReference, string ColorHex);
|
private sealed record SeriesLayout(string TitleReference, string XValuesReference, string YValuesReference, string ColorHex);
|
||||||
|
|
||||||
private sealed record PerRunSeriesLayout(ExportCurveData Data, SeriesLayout Series);
|
private sealed record PerRunSeriesLayout(ExportCurveData Data, SeriesLayout Series);
|
||||||
|
|||||||
@@ -1663,19 +1663,21 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
|||||||
private bool TryResolveHistoryExportData(out IReadOnlyList<PersistedRunData> exportData)
|
private bool TryResolveHistoryExportData(out IReadOnlyList<PersistedRunData> exportData)
|
||||||
{
|
{
|
||||||
var historyData = new List<PersistedRunData>();
|
var historyData = new List<PersistedRunData>();
|
||||||
|
var hasExportableSamples = false;
|
||||||
foreach (var run in RunHistory.OrderBy(item => item.CompletedAt))
|
foreach (var run in RunHistory.OrderBy(item => item.CompletedAt))
|
||||||
{
|
{
|
||||||
var data = LoadRunData(run);
|
var data = LoadRunData(run);
|
||||||
if (data is not null && data.Samples.Count > 0)
|
if (data is not null)
|
||||||
{
|
{
|
||||||
historyData.Add(data);
|
historyData.Add(data);
|
||||||
|
hasExportableSamples |= data.Samples.Any(RunExportService.IsValidSample);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exportData = historyData;
|
exportData = historyData;
|
||||||
if (historyData.Count == 0)
|
if (!hasExportableSamples)
|
||||||
{
|
{
|
||||||
AddWarningEvent("未找到可导出的历史采样数据。");
|
AddWarningEvent("未找到可导出的有效历史采样数据。");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1710,7 +1712,7 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
|||||||
}
|
}
|
||||||
|
|
||||||
var workbookPath = _runExportService.ExportHistoricalComparisonReport(exportData, saveFileDialog.FileName);
|
var workbookPath = _runExportService.ExportHistoricalComparisonReport(exportData, saveFileDialog.FileName);
|
||||||
foreach (var item in exportData)
|
foreach (var item in exportData.Where(data => data.Samples.Any(RunExportService.IsValidSample)))
|
||||||
{
|
{
|
||||||
_dataRepository.UpdateExportPaths(item.Run.RunId, null, workbookPath);
|
_dataRepository.UpdateExportPaths(item.Run.RunId, null, workbookPath);
|
||||||
item.Run.ReportExportPath = workbookPath;
|
item.Run.ReportExportPath = workbookPath;
|
||||||
|
|||||||
Reference in New Issue
Block a user