diff --git a/ExportModule/ExportModule.csproj b/ExportModule/ExportModule.csproj
index 82c07f7..c6c067e 100644
--- a/ExportModule/ExportModule.csproj
+++ b/ExportModule/ExportModule.csproj
@@ -7,6 +7,10 @@
enable
+
+
+
+
diff --git a/ExportModule/ViewModels/ExportViewModel.cs b/ExportModule/ViewModels/ExportViewModel.cs
index 5885d49..10524d8 100644
--- a/ExportModule/ViewModels/ExportViewModel.cs
+++ b/ExportModule/ViewModels/ExportViewModel.cs
@@ -1,24 +1,16 @@
-using Logger;
-using MahApps.Metro.Controls;
+using ClosedXML.Excel;
+using Logger;
+using Microsoft.Win32;
using Model;
using Model.Entity;
using Model.Models;
-using NLog.Targets;
-using OxyPlot;
using Service.Interface;
using System;
-using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
-using System.Data;
-using System.Diagnostics;
using System.Linq;
-using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
-using System.Windows.Threading;
-using UIShare.GlobalVariable;
-using UIShare.UIViewModel;
using UIShare.ViewModelBase;
namespace ExportModule.ViewModels
@@ -36,56 +28,231 @@ namespace ExportModule.ViewModels
set { SetProperty(ref _testReportModelList, value); }
}
+ private DateTime? _startTime;
+ public DateTime? StartTime
+ {
+ get => _startTime;
+ set => SetProperty(ref _startTime, value);
+ }
+
+ private DateTime? _endTime;
+ public DateTime? EndTime
+ {
+ get => _endTime;
+ set => SetProperty(ref _endTime, value);
+ }
+
+ private string _selectedScope = "全部";
+ public string SelectedScope
+ {
+ get => _selectedScope;
+ set => SetProperty(ref _selectedScope, value);
+ }
+
+ public ObservableCollection ScopeOptions { get; } = new()
+ {
+ "全部",
+ "TestCell1", "TestCell2", "TestCell3", "TestCell4",
+ "TestCell5", "TestCell6", "TestCell7", "TestCell8"
+ };
+
+ private string _statusMessage = "就绪";
+ public string StatusMessage
+ {
+ get => _statusMessage;
+ set => SetProperty(ref _statusMessage, value);
+ }
+
+ private int _totalCount;
+ public int TotalCount
+ {
+ get => _totalCount;
+ set => SetProperty(ref _totalCount, value);
+ }
#endregion
#region 命令
+ public ICommand LoadedCommand { get; }
+ public ICommand QueryCommand { get; }
+ public ICommand ExportCommand { get; }
+ #endregion
- #endregion
- public ICommand LoadedCommand { get; set; }
#region 私有字段
- ITestReportService _testReportService { get; set; }
+ private readonly ITestReportService _testReportService;
#endregion
+
public ExportViewModel(IContainerProvider containerProvider) : base(containerProvider)
{
_testReportService = containerProvider.Resolve();
+
LoadedCommand = new AsyncDelegateCommand(OnLoad);
+ QueryCommand = new AsyncDelegateCommand(OnQuery);
+ ExportCommand = new AsyncDelegateCommand(OnExport);
}
-
-
#region 命令处理
+
+ ///
+ /// 加载全部(无筛选条件)
+ ///
private async Task OnLoad()
{
- var result=await _testReportService.GetFilterList();
+ var result = await _testReportService.GetFilterList();
if (result.IsSuccess)
{
- IList reportList = result.Data;
- TestReportModelList = new ObservableCollection(reportList);
+ TestReportModelList = new ObservableCollection(result.Data ?? new List());
+ TotalCount = TestReportModelList.Count;
+ ShowInfoMessageBox($"加载完成,共 {TotalCount} 条记录", () => { });
}
else
{
- TestReportModelList = new();
+ TestReportModelList = new ObservableCollection();
+ TotalCount = 0;
+ ShowErrorMessageBox($"加载失败:{result.Msg}", () => { });
+ LoggerHelper.Error(result.Msg);
}
}
+
+ ///
+ /// 查询(根据开始日期、结束日期、台架名称筛选)
+ ///
+ private async Task OnQuery()
+ {
+ // 处理结束日期:若用户只选了日期没选时间,默认到当天末尾
+ DateTime? queryEnd = EndTime;
+ if (queryEnd.HasValue)
+ {
+ queryEnd = queryEnd.Value.Date.AddDays(1).AddSeconds(-1);
+ }
+
+ string? scope = SelectedScope == "全部" ? null : SelectedScope;
+
+ var result = await _testReportService.GetFilterList(StartTime, queryEnd, scope);
+ if (result.IsSuccess)
+ {
+ TestReportModelList = new ObservableCollection(result.Data ?? new List());
+ TotalCount = TestReportModelList.Count;
+ ShowInfoMessageBox($"查询完成,共 {TotalCount} 条记录", () => { });
+ }
+ else
+ {
+ TestReportModelList = new ObservableCollection();
+ TotalCount = 0;
+ ShowErrorMessageBox($"查询失败:{result.Msg}", () => { });
+ LoggerHelper.Error(result.Msg);
+ }
+ }
+
+ ///
+ /// 导出 Excel(根据当前筛选条件导出完整实体数据)
+ ///
+ private async Task OnExport()
+ {
+ DateTime? queryEnd = EndTime;
+ if (queryEnd.HasValue)
+ {
+ queryEnd = queryEnd.Value.Date.AddDays(1).AddSeconds(-1);
+ }
+
+ string? scope = SelectedScope == "全部" ? null : SelectedScope;
+
+ // 查询全量实体数据
+ StatusMessage = "正在查询导出数据...";
+ var entityResult = await _testReportService.GetEntitiesByFilter(StartTime, queryEnd, scope);
+ if (!entityResult.IsSuccess || entityResult.Data == null || entityResult.Data.Count == 0)
+ {
+ ShowErrorMessageBox("没有数据可导出,请先查询或调整筛选条件。", () => { });
+ return;
+ }
+
+ var dialog = new SaveFileDialog
+ {
+ Filter = "Excel 工作簿 (*.xlsx)|*.xlsx|所有文件 (*.*)|*.*",
+ DefaultExt = ".xlsx",
+ FileName = $"测试报告_{DateTime.Now:yyyyMMdd_HHmmss}.xlsx"
+ };
+
+ if (dialog.ShowDialog() != true) return;
+
+ var entities = entityResult.Data;
+ StatusMessage = $"正在导出 {entities.Count} 条记录...";
+ await Task.Run(() => ExportToExcel(dialog.FileName, entities));
+ ShowInfoMessageBox($"导出完成,共 {entities.Count} 条记录,已保存至:{dialog.FileName}", () => { });
+ }
+
#endregion
#region 辅助方法
+ private static void ExportToExcel(string filePath, List entities)
+ {
+ using var workbook = new XLWorkbook();
+ var ws = workbook.Worksheets.Add("测试报告");
+
+ // 表头
+ string[] headers = {
+ "Id", "CreateTime", "TestRoundId", "Scope", "FileName",
+ "StepIndex", "StepName", "StepType", "MethodName", "MethodFullName",
+ "Result", "RunTimeMs", "OutputValue", "Depth", "IsErrorStep", "LoopRemaining"
+ };
+
+ for (int c = 0; c < headers.Length; c++)
+ {
+ ws.Cell(1, c + 1).Value = headers[c];
+ }
+
+ // 标题行样式
+ var headerRange = ws.Range(1, 1, 1, headers.Length);
+ headerRange.Style.Font.Bold = true;
+ headerRange.Style.Fill.BackgroundColor = XLColor.FromArgb(0xECEFF4);
+ headerRange.Style.Border.OutsideBorder = XLBorderStyleValues.Thin;
+ headerRange.Style.Border.InsideBorder = XLBorderStyleValues.Thin;
+
+ // 填充数据
+ for (int i = 0; i < entities.Count; i++)
+ {
+ var e = entities[i];
+ int row = i + 2;
+
+ ws.Cell(row, 1).Value = e.Id;
+ ws.Cell(row, 2).Value = e.CreateTime.ToString("yyyy-MM-dd HH:mm:ss");
+ ws.Cell(row, 3).Value = e.TestRoundId.ToString();
+ ws.Cell(row, 4).Value = e.Scope ?? "";
+ ws.Cell(row, 5).Value = e.FileName ?? "";
+ ws.Cell(row, 6).Value = e.StepIndex;
+ ws.Cell(row, 7).Value = e.StepName ?? "";
+ ws.Cell(row, 8).Value = e.StepType ?? "";
+ ws.Cell(row, 9).Value = e.MethodName ?? "";
+ ws.Cell(row, 10).Value = e.MethodFullName ?? "";
+ ws.Cell(row, 11).Value = e.Result;
+ ws.Cell(row, 12).Value = e.RunTimeMs;
+ ws.Cell(row, 13).Value = e.OutputValue ?? "";
+ ws.Cell(row, 14).Value = e.Depth;
+ ws.Cell(row, 15).Value = e.IsErrorStep ? "是" : "否";
+ ws.Cell(row, 16).Value = e.LoopRemaining;
+
+ // 数据行边框
+ var dataRange = ws.Range(row, 1, row, headers.Length);
+ dataRange.Style.Border.OutsideBorder = XLBorderStyleValues.Thin;
+ dataRange.Style.Border.InsideBorder = XLBorderStyleValues.Thin;
+ }
+
+ ws.Columns().AdjustToContents();
+ workbook.SaveAs(filePath);
+ }
#endregion
+
#region 生命周期
public override void OnNavigatedTo(NavigationContext navigationContext)
{
-
}
public void Dispose()
{
-
}
#endregion
-
}
}
diff --git a/ExportModule/Views/ExportView.xaml b/ExportModule/Views/ExportView.xaml
index 827caf2..023fcd6 100644
--- a/ExportModule/Views/ExportView.xaml
+++ b/ExportModule/Views/ExportView.xaml
@@ -1,20 +1,203 @@
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Service/Implement/TestReportService.cs b/Service/Implement/TestReportService.cs
index 599ea7d..5d91f8c 100644
--- a/Service/Implement/TestReportService.cs
+++ b/Service/Implement/TestReportService.cs
@@ -38,22 +38,35 @@ namespace Service.Implement
}
///
- /// 根据 TestRoundId 分组,获取唯一记录并按分组统计最大与最小时间
+ /// 根据 TestRoundId 分组,获取唯一记录并按分组统计最大与最小时间,
+ /// 支持按日期范围与台架名称筛选。
///
- public async Task>> GetFilterList()
+ public async Task>> GetFilterList(DateTime? startTime = null, DateTime? endTime = null, string? scope = null)
{
try
{
// 使用 SqlSugar 的 GroupBy 查询,聚合最大/最小时间
// 推荐采用这种按组投影的方式,将分组计算交由数据库处理,性能最佳
- var list = await _repository.Context.Queryable()
+ var query = _repository.Context.Queryable();
+
+ // 日期范围筛选
+ if (startTime.HasValue)
+ query = query.Where(x => x.CreateTime >= startTime.Value);
+ if (endTime.HasValue)
+ query = query.Where(x => x.CreateTime <= endTime.Value);
+
+ // 台架名称筛选
+ if (!string.IsNullOrEmpty(scope))
+ query = query.Where(x => x.Scope == scope);
+
+ var list = await query
.GroupBy(x => x.TestRoundId)
.Select(x => new TestReportModel
{
TestRoundId = x.TestRoundId,
StartTime = SqlFunc.AggregateMin(x.CreateTime),
EndTime = SqlFunc.AggregateMax(x.CreateTime),
- Scope=x.Scope,
+ Scope = x.Scope,
FileName = x.FileName,
})
.ToListAsync();
@@ -65,5 +78,32 @@ namespace Service.Implement
return Result>.Error("获取分组过滤列表失败", ex);
}
}
+ ///
+ /// 根据日期和台架名称筛选获取完整的测试步骤实体列表(无分组,用于导出)
+ ///
+ public async Task>> GetEntitiesByFilter(DateTime? startTime = null, DateTime? endTime = null, string? scope = null)
+ {
+ try
+ {
+ var query = _repository.Context.Queryable();
+
+ if (startTime.HasValue)
+ query = query.Where(x => x.CreateTime >= startTime.Value);
+ if (endTime.HasValue)
+ query = query.Where(x => x.CreateTime <= endTime.Value);
+ if (!string.IsNullOrEmpty(scope))
+ query = query.Where(x => x.Scope == scope);
+
+ var list = await query
+ .OrderBy(x => x.CreateTime)
+ .ToListAsync();
+
+ return Result>.Success(list);
+ }
+ catch (Exception ex)
+ {
+ return Result>.Error("获取导出数据失败", ex);
+ }
+ }
}
}
\ No newline at end of file
diff --git a/Service/Interface/ITestReportService.cs b/Service/Interface/ITestReportService.cs
index 2190217..a2270c4 100644
--- a/Service/Interface/ITestReportService.cs
+++ b/Service/Interface/ITestReportService.cs
@@ -21,6 +21,17 @@ namespace Service.Interface
///
/// 根据 TestRoundId 分组,获取唯一记录并按分组统计最大与最小时间
///
- Task>> GetFilterList();
+ /// 开始日期筛选(可选)
+ /// 结束日期筛选(可选)
+ /// 台架名称筛选(可选)
+ Task>> GetFilterList(DateTime? startTime = null, DateTime? endTime = null, string? scope = null);
+
+ ///
+ /// 根据日期和台架名称筛选获取完整的测试步骤实体列表(无分组,用于导出)
+ ///
+ /// 开始日期筛选(可选)
+ /// 结束日期筛选(可选)
+ /// 台架名称筛选(可选)
+ Task>> GetEntitiesByFilter(DateTime? startTime = null, DateTime? endTime = null, string? scope = null);
}
}