From cf4f24fde39673faae1cce7d171562f308172904 Mon Sep 17 00:00:00 2001 From: ssss <111@qq.com> Date: Mon, 6 Jul 2026 13:37:34 +0800 Subject: [PATCH] =?UTF-8?q?feat(wpf):=20=E6=B7=BB=E5=8A=A0Ploss=E5=92=8CQf?= =?UTF-8?q?od=E6=95=B0=E6=8D=AE=E8=A1=A8=E6=A0=BC=E8=A7=86=E5=9B=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/WCTDataMiner.Wpf/App.xaml.cs | 5 ++ src/WCTDataMiner.Wpf/MainWindow.xaml | 6 ++ .../Messages/DataImportedMessage.cs | 14 ++- .../ViewModels/MainViewModel.cs | 53 +++++++++-- .../ViewModels/PlossTableViewModel.cs | 87 +++++++++++++++++++ .../ViewModels/QfodTableViewModel.cs | 87 +++++++++++++++++++ .../Views/PlossTableView.xaml | 79 +++++++++++++++++ .../Views/PlossTableView.xaml.cs | 14 +++ src/WCTDataMiner.Wpf/Views/QfodTableView.xaml | 61 +++++++++++++ .../Views/QfodTableView.xaml.cs | 14 +++ 10 files changed, 411 insertions(+), 9 deletions(-) create mode 100644 src/WCTDataMiner.Wpf/ViewModels/PlossTableViewModel.cs create mode 100644 src/WCTDataMiner.Wpf/ViewModels/QfodTableViewModel.cs create mode 100644 src/WCTDataMiner.Wpf/Views/PlossTableView.xaml create mode 100644 src/WCTDataMiner.Wpf/Views/PlossTableView.xaml.cs create mode 100644 src/WCTDataMiner.Wpf/Views/QfodTableView.xaml create mode 100644 src/WCTDataMiner.Wpf/Views/QfodTableView.xaml.cs diff --git a/src/WCTDataMiner.Wpf/App.xaml.cs b/src/WCTDataMiner.Wpf/App.xaml.cs index 884a4d9..3b7ba0e 100644 --- a/src/WCTDataMiner.Wpf/App.xaml.cs +++ b/src/WCTDataMiner.Wpf/App.xaml.cs @@ -74,6 +74,9 @@ public partial class App : Application // Chart ViewModels 使用 Transient,每次导航创建新实例 services.AddTransient(); services.AddTransient(); + // Table ViewModels 使用 Transient,每次导航创建新实例 + services.AddTransient(); + services.AddTransient(); services.AddSingleton(); // 注册 Views @@ -81,6 +84,8 @@ public partial class App : Application services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); + services.AddTransient(); services.AddTransient(); }) .Build(); diff --git a/src/WCTDataMiner.Wpf/MainWindow.xaml b/src/WCTDataMiner.Wpf/MainWindow.xaml index 64e3b8b..097bb9c 100644 --- a/src/WCTDataMiner.Wpf/MainWindow.xaml +++ b/src/WCTDataMiner.Wpf/MainWindow.xaml @@ -62,6 +62,12 @@ + + + + + + diff --git a/src/WCTDataMiner.Wpf/Messages/DataImportedMessage.cs b/src/WCTDataMiner.Wpf/Messages/DataImportedMessage.cs index 5f1e8b0..eae684f 100644 --- a/src/WCTDataMiner.Wpf/Messages/DataImportedMessage.cs +++ b/src/WCTDataMiner.Wpf/Messages/DataImportedMessage.cs @@ -16,4 +16,16 @@ public record NavigateToPlossChartMessage(Guid ScenarioId); /// 导航到 Qfod 图表消息 /// /// 场景 ID -public record NavigateToQfodChartMessage(Guid ScenarioId); \ No newline at end of file +public record NavigateToQfodChartMessage(Guid ScenarioId); + +/// +/// 导航到 Ploss 表格消息 +/// +/// 场景 ID +public record NavigateToPlossTableMessage(Guid ScenarioId); + +/// +/// 导航到 Qfod 表格消息 +/// +/// 场景 ID +public record NavigateToQfodTableMessage(Guid ScenarioId); \ No newline at end of file diff --git a/src/WCTDataMiner.Wpf/ViewModels/MainViewModel.cs b/src/WCTDataMiner.Wpf/ViewModels/MainViewModel.cs index 6d28e74..e67e62a 100644 --- a/src/WCTDataMiner.Wpf/ViewModels/MainViewModel.cs +++ b/src/WCTDataMiner.Wpf/ViewModels/MainViewModel.cs @@ -2,6 +2,7 @@ using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using CommunityToolkit.Mvvm.Messaging; using Microsoft.Extensions.DependencyInjection; +using System.Windows; using WCTDataMiner.Core.Services; using WCTDataMiner.Wpf.Messages; @@ -12,7 +13,9 @@ namespace WCTDataMiner.Wpf.ViewModels; /// public partial class MainViewModel : ObservableObject, IRecipient, - IRecipient + IRecipient, + IRecipient, + IRecipient { private readonly ImportViewModel _importViewModel; private readonly ScenarioListViewModel _scenarioListViewModel; @@ -59,6 +62,8 @@ public partial class MainViewModel : ObservableObject, // 注册导航消息订阅 WeakReferenceMessenger.Default.Register(this); WeakReferenceMessenger.Default.Register(this); + WeakReferenceMessenger.Default.Register(this); + WeakReferenceMessenger.Default.Register(this); } /// @@ -120,9 +125,12 @@ public partial class MainViewModel : ObservableObject, /// public void Receive(NavigateToPlossChartMessage message) { - var vm = _serviceProvider.GetRequiredService(); - vm.ScenarioId = message.ScenarioId; - CurrentView = vm; + Application.Current.Dispatcher.InvokeAsync(() => + { + var vm = _serviceProvider.GetRequiredService(); + vm.ScenarioId = message.ScenarioId; + CurrentView = vm; + }); } /// @@ -130,8 +138,37 @@ public partial class MainViewModel : ObservableObject, /// public void Receive(NavigateToQfodChartMessage message) { - var vm = _serviceProvider.GetRequiredService(); - vm.ScenarioId = message.ScenarioId; - CurrentView = vm; + Application.Current.Dispatcher.InvokeAsync(() => + { + var vm = _serviceProvider.GetRequiredService(); + vm.ScenarioId = message.ScenarioId; + CurrentView = vm; + }); } -} + + /// + /// 接收导航到 Ploss 表格消息 + /// + public void Receive(NavigateToPlossTableMessage message) + { + Application.Current.Dispatcher.InvokeAsync(() => + { + var vm = _serviceProvider.GetRequiredService(); + vm.ScenarioId = message.ScenarioId; + CurrentView = vm; + }); + } + + /// + /// 接收导航到 Qfod 表格消息 + /// + public void Receive(NavigateToQfodTableMessage message) + { + Application.Current.Dispatcher.InvokeAsync(() => + { + var vm = _serviceProvider.GetRequiredService(); + vm.ScenarioId = message.ScenarioId; + CurrentView = vm; + }); + } +} \ No newline at end of file diff --git a/src/WCTDataMiner.Wpf/ViewModels/PlossTableViewModel.cs b/src/WCTDataMiner.Wpf/ViewModels/PlossTableViewModel.cs new file mode 100644 index 0000000..2b13068 --- /dev/null +++ b/src/WCTDataMiner.Wpf/ViewModels/PlossTableViewModel.cs @@ -0,0 +1,87 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using CommunityToolkit.Mvvm.Messaging; +using Microsoft.Extensions.Logging; +using System.Collections.ObjectModel; +using WCTDataMiner.Core.Models; +using WCTDataMiner.Core.Services; +using WCTDataMiner.Wpf.Messages; + +namespace WCTDataMiner.Wpf.ViewModels; + +/// +/// Ploss 数据表格 ViewModel +/// +public partial class PlossTableViewModel : ObservableObject +{ + private readonly ScenarioService _scenarioService; + private readonly ILogger _logger; + + [ObservableProperty] + private Guid _scenarioId; + + [ObservableProperty] + private ObservableCollection _records = new(); + + [ObservableProperty] + private bool _isLoading; + + [ObservableProperty] + private string _loadingMessage = ""; + + public PlossTableViewModel( + ScenarioService scenarioService, + ILogger logger) + { + _scenarioService = scenarioService; + _logger = logger; + } + + /// + /// ScenarioId 属性变更时自动触发数据加载 + /// + partial void OnScenarioIdChanged(Guid value) + { + if (value != Guid.Empty) + { + _ = LoadDataAsync().ContinueWith(t => + { + if (t.Exception != null) + { + _logger.LogError(t.Exception, "LoadDataAsync 失败: ScenarioId={ScenarioId}", value); + } + }, TaskContinuationOptions.OnlyOnFaulted); + } + } + + public async Task LoadDataAsync() + { + if (IsLoading) return; // 防并发 + + IsLoading = true; + LoadingMessage = "正在加载数据..."; + + try + { + var records = await _scenarioService.GetPlossRecordsByScenarioIdAsync(ScenarioId); + Records = new ObservableCollection(records); + _logger.LogInformation("加载 Ploss 表格数据成功: ScenarioId={ScenarioId}, 记录数={Count}", ScenarioId, records.Count); + LoadingMessage = ""; + } + catch (Exception ex) + { + _logger.LogError(ex, "加载 Ploss 表格数据失败: ScenarioId={ScenarioId}", ScenarioId); + LoadingMessage = $"加载失败: {ex.Message}"; + } + finally + { + IsLoading = false; + } + } + + [RelayCommand] + private void SwitchToChart() + { + WeakReferenceMessenger.Default.Send(new NavigateToPlossChartMessage(ScenarioId)); + } +} \ No newline at end of file diff --git a/src/WCTDataMiner.Wpf/ViewModels/QfodTableViewModel.cs b/src/WCTDataMiner.Wpf/ViewModels/QfodTableViewModel.cs new file mode 100644 index 0000000..53c0ab1 --- /dev/null +++ b/src/WCTDataMiner.Wpf/ViewModels/QfodTableViewModel.cs @@ -0,0 +1,87 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using CommunityToolkit.Mvvm.Messaging; +using Microsoft.Extensions.Logging; +using System.Collections.ObjectModel; +using WCTDataMiner.Core.Models; +using WCTDataMiner.Core.Services; +using WCTDataMiner.Wpf.Messages; + +namespace WCTDataMiner.Wpf.ViewModels; + +/// +/// Qfod 数据表格 ViewModel +/// +public partial class QfodTableViewModel : ObservableObject +{ + private readonly ScenarioService _scenarioService; + private readonly ILogger _logger; + + [ObservableProperty] + private Guid _scenarioId; + + [ObservableProperty] + private ObservableCollection _records = new(); + + [ObservableProperty] + private bool _isLoading; + + [ObservableProperty] + private string _loadingMessage = ""; + + public QfodTableViewModel( + ScenarioService scenarioService, + ILogger logger) + { + _scenarioService = scenarioService; + _logger = logger; + } + + /// + /// ScenarioId 属性变更时自动触发数据加载 + /// + partial void OnScenarioIdChanged(Guid value) + { + if (value != Guid.Empty) + { + _ = LoadDataAsync().ContinueWith(t => + { + if (t.Exception != null) + { + _logger.LogError(t.Exception, "LoadDataAsync 失败: ScenarioId={ScenarioId}", value); + } + }, TaskContinuationOptions.OnlyOnFaulted); + } + } + + public async Task LoadDataAsync() + { + if (IsLoading) return; // 防并发 + + IsLoading = true; + LoadingMessage = "正在加载数据..."; + + try + { + var records = await _scenarioService.GetQfodRecordsByScenarioIdAsync(ScenarioId); + Records = new ObservableCollection(records); + _logger.LogInformation("加载 Qfod 表格数据成功: ScenarioId={ScenarioId}, 记录数={Count}", ScenarioId, records.Count); + LoadingMessage = ""; + } + catch (Exception ex) + { + _logger.LogError(ex, "加载 Qfod 表格数据失败: ScenarioId={ScenarioId}", ScenarioId); + LoadingMessage = $"加载失败: {ex.Message}"; + } + finally + { + IsLoading = false; + } + } + + [RelayCommand] + private void SwitchToChart() + { + WeakReferenceMessenger.Default.Send(new NavigateToQfodChartMessage(ScenarioId)); + } +} \ No newline at end of file diff --git a/src/WCTDataMiner.Wpf/Views/PlossTableView.xaml b/src/WCTDataMiner.Wpf/Views/PlossTableView.xaml new file mode 100644 index 0000000..d183eb7 --- /dev/null +++ b/src/WCTDataMiner.Wpf/Views/PlossTableView.xaml @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + +