From 52435ab8cd207814b05170b1276d4131d8924bb7 Mon Sep 17 00:00:00 2001 From: ssss <111@qq.com> Date: Mon, 6 Jul 2026 10:23:41 +0800 Subject: [PATCH] =?UTF-8?q?feat(wpf):=20=E5=AE=9E=E7=8E=B0=E5=9C=BA?= =?UTF-8?q?=E6=99=AF=E5=88=97=E8=A1=A8=E5=8A=A0=E8=BD=BD=E3=80=81=E7=AD=9B?= =?UTF-8?q?=E9=80=89=E4=B8=8E=E6=B6=88=E6=81=AF=E5=AF=BC=E8=88=AA=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ScenarioService新增筛选查询方法和动态筛选选项 - 使用WeakReferenceMessenger实现导入完成通知和导航消息 - ViewModel改为Singleton生命周期确保消息订阅正确工作 - 场景列表支持数据库加载和按维度筛选 - ScenarioId类型从int改为Guid Co-Authored-By: Claude Opus 4.8 --- .../Services/ScenarioService.cs | 146 ++++++++++++++++- src/WCTDataMiner.Wpf/App.xaml.cs | 26 ++- .../Messages/DataImportedMessage.cs | 19 +++ .../ViewModels/ImportViewModel.cs | 8 + .../ViewModels/MainViewModel.cs | 98 +++++++++-- .../ViewModels/PlossChartViewModel.cs | 47 ++++-- .../ViewModels/QfodChartViewModel.cs | 47 ++++-- .../ViewModels/ScenarioListViewModel.cs | 155 +++++++++++++++++- .../Views/ScenarioListView.xaml.cs | 13 +- 9 files changed, 498 insertions(+), 61 deletions(-) create mode 100644 src/WCTDataMiner.Wpf/Messages/DataImportedMessage.cs diff --git a/src/WCTDataMiner.Core/Services/ScenarioService.cs b/src/WCTDataMiner.Core/Services/ScenarioService.cs index c1b4b10..b070ed9 100644 --- a/src/WCTDataMiner.Core/Services/ScenarioService.cs +++ b/src/WCTDataMiner.Core/Services/ScenarioService.cs @@ -6,6 +6,17 @@ using WCTDataMiner.Core.Parsers; namespace WCTDataMiner.Core.Services; +/// +/// 篮选条件常量 +/// +public static class FilterConstants +{ + /// + /// 表示"全部"选项的常量值 + /// + public const string AllOption = "全部"; +} + /// /// 测试场景服务 - 负责测试场景的创建和查询(并发安全版本) /// @@ -129,6 +140,130 @@ public class ScenarioService .FirstOrDefaultAsync(s => s.Id == scenarioId); } + /// + /// 获取所有测试场景(含维度属性) + /// + /// 每页数量,默认50,传0表示不分页 + /// 页码,从0开始 + public async Task> GetAllScenariosAsync(int pageSize = 50, int pageIndex = 0) + { + var query = _context.TestScenarios + .Include(s => s.TxPanel) + .Include(s => s.TxHardware) + .Include(s => s.TxSoftware) + .Include(s => s.RxType) + .OrderByDescending(s => s.TestDate) + .ThenByDescending(s => s.TestSequence) + .AsNoTracking(); + + if (pageSize > 0) + { + query = query.Skip(pageIndex * pageSize).Take(pageSize); + } + + return await query.ToListAsync(); + } + + /// + /// 获取场景总数 + /// + public async Task GetScenariosCountAsync() + { + return await _context.TestScenarios.CountAsync(); + } + + /// + /// 获取可用的筛选选项 + /// + public async Task GetFilterOptionsAsync() + { + var txPanels = await _context.TxPanels + .Select(p => p.Name) + .Distinct() + .OrderBy(n => n) + .ToListAsync(); + + var txHardwares = await _context.TxHardwares + .Select(h => h.Version) + .Distinct() + .OrderBy(v => v) + .ToListAsync(); + + var txSoftwares = await _context.TxSoftwares + .Select(s => s.Version) + .Distinct() + .OrderBy(v => v) + .ToListAsync(); + + var rxTypes = await _context.RxTypes + .Select(r => r.Name) + .Distinct() + .OrderBy(n => n) + .ToListAsync(); + + return new FilterOptions( + txPanels.Prepend(FilterConstants.AllOption).ToList(), + txHardwares.Prepend(FilterConstants.AllOption).ToList(), + txSoftwares.Prepend(FilterConstants.AllOption).ToList(), + rxTypes.Prepend(FilterConstants.AllOption).ToList()); + } + + /// + /// 根据筛选条件获取测试场景 + /// + /// TxPanel 名称,null 或 "全部" 表示不过滤 + /// TxHardware 版本,null 或 "全部" 表示不过滤 + /// TxSoftware 版本,null 或 "全部" 表示不过滤 + /// RxType 名称,null 或 "全部" 表示不过滤 + /// 每页数量,默认50,传0表示不分页 + /// 页码,从0开始 + public async Task> GetScenariosByFilterAsync( + string? txPanel = null, + string? txHardware = null, + string? txSoftware = null, + string? rxType = null, + int pageSize = 50, + int pageIndex = 0) + { + var query = _context.TestScenarios + .Include(s => s.TxPanel) + .Include(s => s.TxHardware) + .Include(s => s.TxSoftware) + .Include(s => s.RxType) + .AsNoTracking(); + + if (!string.IsNullOrEmpty(txPanel) && txPanel != FilterConstants.AllOption) + { + query = query.Where(s => s.TxPanel.Name == txPanel); + } + + if (!string.IsNullOrEmpty(txHardware) && txHardware != FilterConstants.AllOption) + { + query = query.Where(s => s.TxHardware.Version == txHardware); + } + + if (!string.IsNullOrEmpty(txSoftware) && txSoftware != FilterConstants.AllOption) + { + query = query.Where(s => s.TxSoftware.Version == txSoftware); + } + + if (!string.IsNullOrEmpty(rxType) && rxType != FilterConstants.AllOption) + { + query = query.Where(s => s.RxType.Name == rxType); + } + + query = query + .OrderByDescending(s => s.TestDate) + .ThenByDescending(s => s.TestSequence); + + if (pageSize > 0) + { + query = query.Skip(pageIndex * pageSize).Take(pageSize); + } + + return await query.ToListAsync(); + } + /// /// 检测 SQLite 唯一约束违反错误 /// @@ -137,4 +272,13 @@ public class ScenarioService return ex.InnerException is Microsoft.Data.Sqlite.SqliteException sqliteEx && sqliteEx.SqliteErrorCode == 19; // SQLITE_CONSTRAINT } -} \ No newline at end of file +} + +/// +/// 筛选选项数据 +/// +public record FilterOptions( + List TxPanels, + List TxHardwares, + List TxSoftwares, + List RxTypes); \ No newline at end of file diff --git a/src/WCTDataMiner.Wpf/App.xaml.cs b/src/WCTDataMiner.Wpf/App.xaml.cs index 400efe9..884a4d9 100644 --- a/src/WCTDataMiner.Wpf/App.xaml.cs +++ b/src/WCTDataMiner.Wpf/App.xaml.cs @@ -68,12 +68,13 @@ public partial class App : Application services.AddDatabaseServices(context.Configuration); services.AddApplicationServices(); - // 注册 ViewModels - services.AddTransient(); - services.AddTransient(); + // 注册 ViewModels(使用 Singleton 确保消息订阅正确工作) + services.AddSingleton(); + services.AddSingleton(); + // Chart ViewModels 使用 Transient,每次导航创建新实例 services.AddTransient(); services.AddTransient(); - services.AddTransient(); + services.AddSingleton(); // 注册 Views services.AddTransient(); @@ -85,6 +86,23 @@ public partial class App : Application .Build(); var mainWindow = _host.Services.GetRequiredService(); + + // 初始化加载场景数据 + var mainViewModel = _host.Services.GetRequiredService(); + mainWindow.Loaded += async (s, e) => + { + try + { + await mainViewModel.InitializeAsync(); + } + catch (Exception ex) + { + _logger?.Error(ex, "主窗口初始化失败"); + MessageBox.Show($"应用初始化失败: {ex.Message}", "错误", + MessageBoxButton.OK, MessageBoxImage.Error); + } + }; + mainWindow.Show(); base.OnStartup(e); diff --git a/src/WCTDataMiner.Wpf/Messages/DataImportedMessage.cs b/src/WCTDataMiner.Wpf/Messages/DataImportedMessage.cs new file mode 100644 index 0000000..5f1e8b0 --- /dev/null +++ b/src/WCTDataMiner.Wpf/Messages/DataImportedMessage.cs @@ -0,0 +1,19 @@ +namespace WCTDataMiner.Wpf.Messages; + +/// +/// 数据导入完成消息 +/// +/// 导入的文件数量 +public record DataImportedMessage(int ImportedCount); + +/// +/// 导航到 Ploss 图表消息 +/// +/// 场景 ID +public record NavigateToPlossChartMessage(Guid ScenarioId); + +/// +/// 导航到 Qfod 图表消息 +/// +/// 场景 ID +public record NavigateToQfodChartMessage(Guid ScenarioId); \ No newline at end of file diff --git a/src/WCTDataMiner.Wpf/ViewModels/ImportViewModel.cs b/src/WCTDataMiner.Wpf/ViewModels/ImportViewModel.cs index 3aeca9d..5510465 100644 --- a/src/WCTDataMiner.Wpf/ViewModels/ImportViewModel.cs +++ b/src/WCTDataMiner.Wpf/ViewModels/ImportViewModel.cs @@ -1,9 +1,11 @@ using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; +using CommunityToolkit.Mvvm.Messaging; using Microsoft.Extensions.Logging; using Microsoft.Win32; using System.Collections.ObjectModel; using WCTDataMiner.Core.Services; +using WCTDataMiner.Wpf.Messages; namespace WCTDataMiner.Wpf.ViewModels; @@ -99,6 +101,9 @@ public partial class ImportViewModel : ObservableObject StatusMessage = $"导入完成: Qfod={report.QfodCount}, Ploss={report.PlossCount}, 错误={report.ErrorCount}"; _logger.LogInformation("单文件导入完成: {FileName}, Qfod={Qfod}, Ploss={Ploss}, 错误={Errors}", report.FileName, report.QfodCount, report.PlossCount, report.ErrorCount); + + // 发送导入完成消息,通知其他 ViewModel 刷新数据 + WeakReferenceMessenger.Default.Send(new DataImportedMessage(1)); } else if (System.IO.Directory.Exists(SelectedPath)) { @@ -118,6 +123,9 @@ public partial class ImportViewModel : ObservableObject StatusMessage = $"导入完成: {reports.Count} 个文件, Qfod={totalQfod}, Ploss={totalPloss}, 错误={totalErrors}"; _logger.LogInformation("目录导入完成: {FileCount} 个文件, Qfod={Qfod}, Ploss={Ploss}, 错误={Errors}", reports.Count, totalQfod, totalPloss, totalErrors); + + // 发送导入完成消息,通知其他 ViewModel 刷新数据 + WeakReferenceMessenger.Default.Send(new DataImportedMessage(reports.Count)); } else { diff --git a/src/WCTDataMiner.Wpf/ViewModels/MainViewModel.cs b/src/WCTDataMiner.Wpf/ViewModels/MainViewModel.cs index aa19288..6d28e74 100644 --- a/src/WCTDataMiner.Wpf/ViewModels/MainViewModel.cs +++ b/src/WCTDataMiner.Wpf/ViewModels/MainViewModel.cs @@ -1,15 +1,22 @@ using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; +using CommunityToolkit.Mvvm.Messaging; +using Microsoft.Extensions.DependencyInjection; +using WCTDataMiner.Core.Services; +using WCTDataMiner.Wpf.Messages; namespace WCTDataMiner.Wpf.ViewModels; /// /// 主窗口 ViewModel - 导航控制 /// -public partial class MainViewModel : ObservableObject +public partial class MainViewModel : ObservableObject, + IRecipient, + IRecipient { private readonly ImportViewModel _importViewModel; private readonly ScenarioListViewModel _scenarioListViewModel; + private readonly IServiceProvider _serviceProvider; [ObservableProperty] private ObservableObject _currentView = null!; @@ -26,17 +33,48 @@ public partial class MainViewModel : ObservableObject [ObservableProperty] private string? _selectedRxType; - // 筛选选项列表 - public List TxPanels { get; } = new() { "全部", "singleMold", "dualMold" }; - public List TxHardwares { get; } = new() { "全部", "v1.0", "v2.0" }; - public List TxSoftwares { get; } = new() { "全部", "hex2_1", "hex2_2" }; - public List RxTypes { get; } = new() { "全部", "iPhone15", "iPhone16", "Android" }; + // 筛选选项列表(动态加载) + [ObservableProperty] + private List _txPanels = new() { FilterConstants.AllOption }; - public MainViewModel(ImportViewModel importViewModel, ScenarioListViewModel scenarioListViewModel) + [ObservableProperty] + private List _txHardwares = new() { FilterConstants.AllOption }; + + [ObservableProperty] + private List _txSoftwares = new() { FilterConstants.AllOption }; + + [ObservableProperty] + private List _rxTypes = new() { FilterConstants.AllOption }; + + public MainViewModel( + ImportViewModel importViewModel, + ScenarioListViewModel scenarioListViewModel, + IServiceProvider serviceProvider) { _importViewModel = importViewModel; _scenarioListViewModel = scenarioListViewModel; + _serviceProvider = serviceProvider; _currentView = _scenarioListViewModel; + + // 注册导航消息订阅 + WeakReferenceMessenger.Default.Register(this); + WeakReferenceMessenger.Default.Register(this); + } + + /// + /// 初始化加载场景数据和筛选选项 + /// + public async Task InitializeAsync() + { + // 加载筛选选项 + var filterOptions = await _scenarioListViewModel.GetFilterOptionsAsync(); + TxPanels = filterOptions.TxPanels; + TxHardwares = filterOptions.TxHardwares; + TxSoftwares = filterOptions.TxSoftwares; + RxTypes = filterOptions.RxTypes; + + // 加载场景列表 + await _scenarioListViewModel.LoadScenariosAsync(); } [RelayCommand] @@ -46,20 +84,54 @@ public partial class MainViewModel : ObservableObject } [RelayCommand] - private void NavigateToScenarios() + private async Task NavigateToScenarios() { CurrentView = _scenarioListViewModel; + await _scenarioListViewModel.LoadScenariosAsync(); } [RelayCommand] - private void NavigateToPlossChart(int scenarioId) + private void NavigateToPlossChart(Guid scenarioId) { - CurrentView = new PlossChartViewModel { ScenarioId = scenarioId }; + var vm = _serviceProvider.GetRequiredService(); + vm.ScenarioId = scenarioId; + CurrentView = vm; } [RelayCommand] - private void NavigateToQfodChart(int scenarioId) + private void NavigateToQfodChart(Guid scenarioId) { - CurrentView = new QfodChartViewModel { ScenarioId = scenarioId }; + var vm = _serviceProvider.GetRequiredService(); + vm.ScenarioId = scenarioId; + CurrentView = vm; } -} \ No newline at end of file + + /// + /// 应用筛选条件并刷新场景列表 + /// + public async Task ApplyFilterAsync() + { + await _scenarioListViewModel.LoadScenariosByFilterAsync( + SelectedTxPanel, SelectedTxHardware, SelectedTxSoftware, SelectedRxType); + } + + /// + /// 接收导航到 Ploss 图表消息 + /// + public void Receive(NavigateToPlossChartMessage message) + { + var vm = _serviceProvider.GetRequiredService(); + vm.ScenarioId = message.ScenarioId; + CurrentView = vm; + } + + /// + /// 接收导航到 Qfod 图表消息 + /// + public void Receive(NavigateToQfodChartMessage message) + { + var vm = _serviceProvider.GetRequiredService(); + vm.ScenarioId = message.ScenarioId; + CurrentView = vm; + } +} diff --git a/src/WCTDataMiner.Wpf/ViewModels/PlossChartViewModel.cs b/src/WCTDataMiner.Wpf/ViewModels/PlossChartViewModel.cs index cd822a6..7b744fb 100644 --- a/src/WCTDataMiner.Wpf/ViewModels/PlossChartViewModel.cs +++ b/src/WCTDataMiner.Wpf/ViewModels/PlossChartViewModel.cs @@ -1,6 +1,8 @@ using CommunityToolkit.Mvvm.ComponentModel; using LiveChartsCore; using LiveChartsCore.SkiaSharpView; +using Microsoft.Extensions.Logging; +using WCTDataMiner.Core.Services; namespace WCTDataMiner.Wpf.ViewModels; @@ -9,8 +11,11 @@ namespace WCTDataMiner.Wpf.ViewModels; /// public partial class PlossChartViewModel : ObservableObject { + private readonly ScenarioService _scenarioService; + private readonly ILogger _logger; + [ObservableProperty] - private int _scenarioId; + private Guid _scenarioId; [ObservableProperty] private ISeries[] _series; @@ -21,8 +26,13 @@ public partial class PlossChartViewModel : ObservableObject [ObservableProperty] private Axis[] _yAxes; - public PlossChartViewModel() + public PlossChartViewModel( + ScenarioService scenarioService, + ILogger logger) { + _scenarioService = scenarioService; + _logger = logger; + // 初始化图表配置 Series = Array.Empty(); XAxes = new Axis[] { new Axis { Name = "Trigger Count" } }; @@ -31,19 +41,26 @@ public partial class PlossChartViewModel : ObservableObject public async Task LoadDataAsync() { - // TODO: 从数据库加载 Ploss 数据并构建图表 - Series = new ISeries[] + try { - new LineSeries + // TODO: 从数据库加载 Ploss 数据并构建图表 + Series = new ISeries[] { - Name = "Ploss", - Values = new double[] { -2882, -3500, -4200, -3800, -4500 } - }, - new LineSeries - { - Name = "Threshold", - Values = new double[] { -3000, -3000, -3000, -3000, -3000 } - } - }; + new LineSeries + { + Name = "Ploss", + Values = new double[] { -2882, -3500, -4200, -3800, -4500 } + }, + new LineSeries + { + Name = "Threshold", + Values = new double[] { -3000, -3000, -3000, -3000, -3000 } + } + }; + } + catch (Exception ex) + { + _logger.LogError(ex, "加载 Ploss 图表数据失败: ScenarioId={ScenarioId}", ScenarioId); + } } -} \ No newline at end of file +} diff --git a/src/WCTDataMiner.Wpf/ViewModels/QfodChartViewModel.cs b/src/WCTDataMiner.Wpf/ViewModels/QfodChartViewModel.cs index 91e9b30..c61ef20 100644 --- a/src/WCTDataMiner.Wpf/ViewModels/QfodChartViewModel.cs +++ b/src/WCTDataMiner.Wpf/ViewModels/QfodChartViewModel.cs @@ -1,6 +1,8 @@ using CommunityToolkit.Mvvm.ComponentModel; using LiveChartsCore; using LiveChartsCore.SkiaSharpView; +using Microsoft.Extensions.Logging; +using WCTDataMiner.Core.Services; namespace WCTDataMiner.Wpf.ViewModels; @@ -9,8 +11,11 @@ namespace WCTDataMiner.Wpf.ViewModels; /// public partial class QfodChartViewModel : ObservableObject { + private readonly ScenarioService _scenarioService; + private readonly ILogger _logger; + [ObservableProperty] - private int _scenarioId; + private Guid _scenarioId; [ObservableProperty] private ISeries[] _series; @@ -21,8 +26,13 @@ public partial class QfodChartViewModel : ObservableObject [ObservableProperty] private Axis[] _yAxes; - public QfodChartViewModel() + public QfodChartViewModel( + ScenarioService scenarioService, + ILogger logger) { + _scenarioService = scenarioService; + _logger = logger; + // 初始化图表配置 Series = Array.Empty(); XAxes = new Axis[] { new Axis { Name = "Coil Index" } }; @@ -31,19 +41,26 @@ public partial class QfodChartViewModel : ObservableObject public async Task LoadDataAsync() { - // TODO: 从数据库加载 Qfod 数据并构建图表 - Series = new ISeries[] + try { - new LineSeries + // TODO: 从数据库加载 Qfod 数据并构建图表 + Series = new ISeries[] { - Name = "DeltaQ", - Values = new double[] { 25, 30, 28 } - }, - new LineSeries - { - Name = "CurrentQ", - Values = new double[] { 45.5, 50.2, 48.8 } - } - }; + new LineSeries + { + Name = "DeltaQ", + Values = new double[] { 25, 30, 28 } + }, + new LineSeries + { + Name = "CurrentQ", + Values = new double[] { 45.5, 50.2, 48.8 } + } + }; + } + catch (Exception ex) + { + _logger.LogError(ex, "加载 Qfod 图表数据失败: ScenarioId={ScenarioId}", ScenarioId); + } } -} \ No newline at end of file +} diff --git a/src/WCTDataMiner.Wpf/ViewModels/ScenarioListViewModel.cs b/src/WCTDataMiner.Wpf/ViewModels/ScenarioListViewModel.cs index fbc0cd1..6b3f5b2 100644 --- a/src/WCTDataMiner.Wpf/ViewModels/ScenarioListViewModel.cs +++ b/src/WCTDataMiner.Wpf/ViewModels/ScenarioListViewModel.cs @@ -1,22 +1,163 @@ using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Messaging; +using Microsoft.Extensions.Logging; +using System.Collections.ObjectModel; +using WCTDataMiner.Core.Services; +using WCTDataMiner.Wpf.Messages; namespace WCTDataMiner.Wpf.ViewModels; /// /// 场景列表 ViewModel /// -public partial class ScenarioListViewModel : ObservableObject +public partial class ScenarioListViewModel : ObservableObject, IRecipient { + private readonly ScenarioService _scenarioService; + private readonly ILogger _logger; + [ObservableProperty] - private List _scenarios; + private ObservableCollection _scenarios = new(); [ObservableProperty] private ScenarioItem? _selectedScenario; - public ScenarioListViewModel() + [ObservableProperty] + private bool _isLoading; + + [ObservableProperty] + private string _loadingMessage = ""; + + public ScenarioListViewModel( + ScenarioService scenarioService, + ILogger logger) { - // TODO: 从数据库加载场景列表 - _scenarios = new List(); + _scenarioService = scenarioService; + _logger = logger; + + // 注册消息订阅,接收导入完成通知 + WeakReferenceMessenger.Default.Register(this); + } + + /// + /// 从数据库加载场景列表 + /// + public async Task LoadScenariosAsync() + { + // 避免并发加载 + if (IsLoading) + { + _logger.LogWarning("跳过重复加载请求:当前正在加载"); + return; + } + + IsLoading = true; + LoadingMessage = "正在加载场景列表..."; + + try + { + var scenarios = await _scenarioService.GetAllScenariosAsync(); + + // 批量更新,避免逐项 Add 导致频繁 UI 刷新 + var items = scenarios.Select(s => new ScenarioItem + { + Id = s.Id, + TxPanel = s.TxPanel?.Name ?? "", + TxHardware = s.TxHardware?.Version ?? "", + TxSoftware = s.TxSoftware?.Version ?? "", + RxType = s.RxType?.Name ?? "", + TestDate = s.TestDate.ToString("yyyy-MM-dd"), + QfodCount = s.QfodCount, + PlossCount = s.PlossCount + }).ToList(); + + Scenarios = new ObservableCollection(items); + } + catch (Exception ex) + { + _logger.LogError(ex, "加载场景列表失败"); + LoadingMessage = $"加载失败: {ex.Message}"; + return; + } + finally + { + IsLoading = false; + LoadingMessage = ""; + } + } + + /// + /// 根据筛选条件加载场景 + /// + public async Task LoadScenariosByFilterAsync( + string? txPanel = null, + string? txHardware = null, + string? txSoftware = null, + string? rxType = null) + { + // 避免并发加载 + if (IsLoading) + { + _logger.LogWarning("跳过重复筛选请求:当前正在加载"); + return; + } + + IsLoading = true; + LoadingMessage = "正在筛选场景..."; + + try + { + var scenarios = await _scenarioService.GetScenariosByFilterAsync( + txPanel, txHardware, txSoftware, rxType); + + // 批量更新,避免逐项 Add 导致频繁 UI 刷新 + var items = scenarios.Select(s => new ScenarioItem + { + Id = s.Id, + TxPanel = s.TxPanel?.Name ?? "", + TxHardware = s.TxHardware?.Version ?? "", + TxSoftware = s.TxSoftware?.Version ?? "", + RxType = s.RxType?.Name ?? "", + TestDate = s.TestDate.ToString("yyyy-MM-dd"), + QfodCount = s.QfodCount, + PlossCount = s.PlossCount + }).ToList(); + + Scenarios = new ObservableCollection(items); + } + catch (Exception ex) + { + _logger.LogError(ex, "筛选场景失败"); + LoadingMessage = $"筛选失败: {ex.Message}"; + return; + } + finally + { + IsLoading = false; + LoadingMessage = ""; + } + } + + /// + /// 接收数据导入完成消息,自动刷新列表 + /// + public async void Receive(DataImportedMessage message) + { + try + { + await LoadScenariosAsync(); + } + catch (Exception ex) + { + _logger.LogError(ex, "接收数据导入消息后刷新场景列表失败"); + } + } + + /// + /// 获取可用的筛选选项 + /// + public async Task GetFilterOptionsAsync() + { + return await _scenarioService.GetFilterOptionsAsync(); } } @@ -25,7 +166,7 @@ public partial class ScenarioListViewModel : ObservableObject /// public class ScenarioItem { - public int Id { get; set; } + public Guid Id { get; set; } public string TxPanel { get; set; } = ""; public string TxHardware { get; set; } = ""; public string TxSoftware { get; set; } = ""; @@ -33,4 +174,4 @@ public class ScenarioItem public string TestDate { get; set; } = ""; public int QfodCount { get; set; } public int PlossCount { get; set; } -} \ No newline at end of file +} diff --git a/src/WCTDataMiner.Wpf/Views/ScenarioListView.xaml.cs b/src/WCTDataMiner.Wpf/Views/ScenarioListView.xaml.cs index 95662b6..336d03e 100644 --- a/src/WCTDataMiner.Wpf/Views/ScenarioListView.xaml.cs +++ b/src/WCTDataMiner.Wpf/Views/ScenarioListView.xaml.cs @@ -1,5 +1,8 @@ +using CommunityToolkit.Mvvm.Messaging; using System.Windows; using System.Windows.Controls; +using WCTDataMiner.Wpf.Messages; +using WCTDataMiner.Wpf.ViewModels; namespace WCTDataMiner.Wpf.Views; @@ -12,19 +15,17 @@ public partial class ScenarioListView : UserControl private void OnViewPlossChart(object sender, RoutedEventArgs e) { - // TODO: 导航到 Ploss 图表页面 - if (DataContext is ViewModels.ScenarioListViewModel vm && vm.SelectedScenario != null) + if (DataContext is ScenarioListViewModel vm && vm.SelectedScenario != null) { - // Navigation logic + WeakReferenceMessenger.Default.Send(new NavigateToPlossChartMessage(vm.SelectedScenario.Id)); } } private void OnViewQfodChart(object sender, RoutedEventArgs e) { - // TODO: 导航到 Qfod 图表页面 - if (DataContext is ViewModels.ScenarioListViewModel vm && vm.SelectedScenario != null) + if (DataContext is ScenarioListViewModel vm && vm.SelectedScenario != null) { - // Navigation logic + WeakReferenceMessenger.Default.Send(new NavigateToQfodChartMessage(vm.SelectedScenario.Id)); } } } \ No newline at end of file