From d7ea00e94de8dadba45040aa225b873cd3e5a640 Mon Sep 17 00:00:00 2001 From: "David P.G" Date: Sun, 19 Oct 2025 14:55:09 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=9E=E7=8E=B0=E8=A7=A6=E5=8F=91?= =?UTF-8?q?=E5=99=A8=E8=AF=A6=E6=83=85=E9=A1=B5=E9=9D=A2=E5=92=8C=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E8=A7=A6=E5=8F=91=E5=99=A8=E5=88=97=E8=A1=A8=E8=A7=86?= =?UTF-8?q?=E5=9B=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DMS.Core/Enums/NavigationType.cs | 1 + DMS.WPF/App.xaml.cs | 2 + DMS.WPF/Services/DataEventService.cs | 2 + DMS.WPF/Services/NavigationService.cs | 2 + DMS.WPF/Services/TriggerDataService.cs | 1 + DMS.WPF/ViewModels/TriggerDetailViewModel.cs | 188 +++++++++ DMS.WPF/ViewModels/TriggersViewModel.cs | 44 +- DMS.WPF/Views/MainView.xaml | 4 + DMS.WPF/Views/TriggerDetailView.xaml | 403 +++++++++++++++++++ DMS.WPF/Views/TriggerDetailView.xaml.cs | 15 + DMS.WPF/Views/TriggersView.xaml | 210 +++++----- 11 files changed, 768 insertions(+), 104 deletions(-) create mode 100644 DMS.WPF/ViewModels/TriggerDetailViewModel.cs create mode 100644 DMS.WPF/Views/TriggerDetailView.xaml create mode 100644 DMS.WPF/Views/TriggerDetailView.xaml.cs diff --git a/DMS.Core/Enums/NavigationType.cs b/DMS.Core/Enums/NavigationType.cs index dbf94ba..d2cb0d5 100644 --- a/DMS.Core/Enums/NavigationType.cs +++ b/DMS.Core/Enums/NavigationType.cs @@ -9,4 +9,5 @@ public enum NavigationType VariableTable, Variable, Mqtt, + Trigger, } \ No newline at end of file diff --git a/DMS.WPF/App.xaml.cs b/DMS.WPF/App.xaml.cs index f57e0ab..b81638e 100644 --- a/DMS.WPF/App.xaml.cs +++ b/DMS.WPF/App.xaml.cs @@ -332,6 +332,7 @@ public partial class App : System.Windows.Application services.AddSingleton(); services.AddSingleton(); services.AddScoped(); + services.AddScoped(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); // 注册 TriggersViewModel @@ -370,6 +371,7 @@ public partial class App : System.Windows.Application services.AddScoped(); services.AddSingleton(); services.AddSingleton(); // 注册 TriggersView + services.AddSingleton(); // 注册 TriggersView } diff --git a/DMS.WPF/Services/DataEventService.cs b/DMS.WPF/Services/DataEventService.cs index e6e3263..62b409b 100644 --- a/DMS.WPF/Services/DataEventService.cs +++ b/DMS.WPF/Services/DataEventService.cs @@ -144,6 +144,8 @@ public class DataEventService : IDataEventService _wpfDataService.MqttAliasDataService.LoadMqttAliases(); _logger?.LogDebug("MQTT别名加载完成"); + _wpfDataService.TriggerDataService.LoadAllTriggers(); + _logger?.LogDebug("触发器加载完成"); _wpfDataService.LogDataService.LoadAllLog(); _logger?.LogDebug("日志数据加载完成"); diff --git a/DMS.WPF/Services/NavigationService.cs b/DMS.WPF/Services/NavigationService.cs index 2188ff5..328e94f 100644 --- a/DMS.WPF/Services/NavigationService.cs +++ b/DMS.WPF/Services/NavigationService.cs @@ -86,6 +86,8 @@ public class NavigationService : INavigationService return App.Current.Services.GetRequiredService(); case nameof(TriggersViewModel): return App.Current.Services.GetRequiredService(); + case nameof(TriggerDetailViewModel): + return App.Current.Services.GetRequiredService(); default: return null; } diff --git a/DMS.WPF/Services/TriggerDataService.cs b/DMS.WPF/Services/TriggerDataService.cs index 53efa62..f3149cd 100644 --- a/DMS.WPF/Services/TriggerDataService.cs +++ b/DMS.WPF/Services/TriggerDataService.cs @@ -50,6 +50,7 @@ public class TriggerDataService : ITriggerDataService /// public void LoadAllTriggers() { + _dataStorageService.Triggers.Clear(); foreach (var triggerDto in _appStorageService.Triggers.Values) { _dataStorageService.Triggers.Add(triggerDto.Id, _mapper.Map(triggerDto)); diff --git a/DMS.WPF/ViewModels/TriggerDetailViewModel.cs b/DMS.WPF/ViewModels/TriggerDetailViewModel.cs new file mode 100644 index 0000000..9cf89b7 --- /dev/null +++ b/DMS.WPF/ViewModels/TriggerDetailViewModel.cs @@ -0,0 +1,188 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using DMS.Application.Interfaces; +using DMS.Application.Interfaces.Management; +using DMS.Core.Models.Triggers; +using DMS.WPF.Interfaces; +using DMS.WPF.ItemViewModel; +using DMS.WPF.ViewModels.Dialogs; +using Microsoft.Extensions.Logging; +using System.Collections; +using System.Collections.ObjectModel; +using DMS.Core.Models; + +namespace DMS.WPF.ViewModels +{ + /// + /// 触发器详情视图模型。 + /// 负责管理单个触发器的配置及其关联的变量数据。 + /// + public partial class TriggerDetailViewModel : ViewModelBase + { + private readonly ILogger _logger; + private readonly IDialogService _dialogService; + private readonly INotificationService _notificationService; + private readonly ITriggerManagementService _triggerManagementService; + private readonly ITriggerDataService _triggerDataService; + private readonly IDataStorageService _dataStorageService; + private readonly INavigationService _navigationService; + + /// + /// 当前正在查看的触发器对象。 + /// + [ObservableProperty] + private TriggerItem _currentTrigger; + + /// + /// 与当前触发器关联的变量数据集合。 + /// + [ObservableProperty] + private ObservableCollection _associatedVariables; + + [ObservableProperty] + private IList _selectedVariables = new ArrayList(); + + /// + /// 构造函数。 + /// + /// 日志服务。 + /// 对话框服务。 + /// 通知服务。 + /// 触发器管理服务 + /// 触发器数据服务 + /// 数据存储服务 + /// 导航服务 + public TriggerDetailViewModel(ILogger logger, + IDialogService dialogService, + INotificationService notificationService, + ITriggerManagementService triggerManagementService, + ITriggerDataService triggerDataService, + IDataStorageService dataStorageService, + INavigationService navigationService) + { + _logger = logger; + _dialogService = dialogService; + _notificationService = notificationService; + _triggerManagementService = triggerManagementService; + _triggerDataService = triggerDataService; + _dataStorageService = dataStorageService; + _navigationService = navigationService; + } + + /// + /// 编辑当前触发器 + /// + [RelayCommand] + private async Task EditTrigger() + { + try + { + if (CurrentTrigger == null) + { + _notificationService.ShowError("没有选中的触发器,无法编辑。"); + return; + } + + // 创建编辑对话框的视图模型 + TriggerDialogViewModel triggerDialogViewModel = new TriggerDialogViewModel(_dialogService, _dataStorageService, _notificationService); + await triggerDialogViewModel.OnInitializedAsync(CurrentTrigger); + + // 显示对话框 + var updatedTrigger = await _dialogService.ShowDialogAsync(triggerDialogViewModel); + + if (updatedTrigger == null) + { + return; // 用户取消了编辑 + } + + // 更新触发器 + var result = await _triggerDataService.UpdateTrigger(updatedTrigger); + + if (result) + { + // 更新当前视图模型的数据 + CurrentTrigger.Name = updatedTrigger.Name; + CurrentTrigger.Description = updatedTrigger.Description; + CurrentTrigger.IsActive = updatedTrigger.IsActive; + CurrentTrigger.Action = updatedTrigger.Action; + CurrentTrigger.ActionConfigurationJson = updatedTrigger.ActionConfigurationJson; + CurrentTrigger.SuppressionDuration = updatedTrigger.SuppressionDuration; + CurrentTrigger.UpdatedAt = updatedTrigger.UpdatedAt; + + _notificationService.ShowSuccess($"触发器编辑成功:{updatedTrigger.Name}"); + } + else + { + _notificationService.ShowError("更新触发器失败。"); + } + } + catch (Exception e) + { + _logger.LogError(e, "编辑触发器过程中发生错误"); + _notificationService.ShowError($"编辑触发器过程中发生错误:{e.Message}", e); + } + } + + /// + /// 重新加载当前触发器数据 + /// + [RelayCommand] + private async Task Reload() + { + if (CurrentTrigger?.Id > 0) + { + // 重新加载当前触发器数据 + var updatedTrigger = await _triggerManagementService.GetTriggerByIdAsync(CurrentTrigger.Id); + if (updatedTrigger != null) + { + // 更新CurrentTrigger的属性 + CurrentTrigger.Name = updatedTrigger.Name; + CurrentTrigger.Description = updatedTrigger.Description; + CurrentTrigger.IsActive = updatedTrigger.IsActive; + CurrentTrigger.Action = updatedTrigger.Action; + CurrentTrigger.ActionConfigurationJson = updatedTrigger.ActionConfigurationJson; + CurrentTrigger.SuppressionDuration = updatedTrigger.SuppressionDuration; + CurrentTrigger.LastTriggeredAt = updatedTrigger.LastTriggeredAt; + CurrentTrigger.UpdatedAt = updatedTrigger.UpdatedAt; + CurrentTrigger.CreatedAt = updatedTrigger.CreatedAt; + } + } + } + + /// + /// 导航回触发器列表页面 + /// + [RelayCommand] + private async Task NavigateToTriggers() + { + await _navigationService.NavigateToAsync(this, new NavigationParameter(nameof(TriggersViewModel))); + } + + public override Task OnNavigatedToAsync(NavigationParameter parameter) + { + if (parameter == null) return Task.CompletedTask; + + if (_dataStorageService.Triggers.TryGetValue(parameter.TargetId, out var triggerItem)) + { + CurrentTrigger = triggerItem; + + // 初始化关联变量列表 - 从VariableIds创建VariableItems列表 + AssociatedVariables = new ObservableCollection(); + foreach (var variableId in CurrentTrigger.VariableIds) + { + if (_dataStorageService.Variables.TryGetValue(variableId, out var variableItem)) + { + AssociatedVariables.Add(variableItem); + } + } + } + + return Task.CompletedTask; + } + + public override Task OnNavigatedFromAsync(NavigationParameter parameter) + { + return Task.CompletedTask; + } + } +} \ No newline at end of file diff --git a/DMS.WPF/ViewModels/TriggersViewModel.cs b/DMS.WPF/ViewModels/TriggersViewModel.cs index 9013883..0a85619 100644 --- a/DMS.WPF/ViewModels/TriggersViewModel.cs +++ b/DMS.WPF/ViewModels/TriggersViewModel.cs @@ -3,6 +3,8 @@ using AutoMapper; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using DMS.Application.DTOs; +using DMS.Core.Enums; +using DMS.Core.Models; using DMS.Core.Models.Triggers; using DMS.WPF.Interfaces; using DMS.WPF.ViewModels.Dialogs; @@ -22,6 +24,10 @@ namespace DMS.WPF.ViewModels private readonly IDataStorageService _dataStorageService; private readonly IDialogService _dialogService; private readonly INotificationService _notificationService; + private readonly INavigationService _navigationService; + + public ISynchronizedView, TriggerItem> _synchronizedView; + public NotifyCollectionChangedSynchronizedViewList TriggerItemListView { get; } [ObservableProperty] private ObservableDictionary _triggers ; @@ -34,16 +40,22 @@ namespace DMS.WPF.ViewModels ITriggerDataService triggerDataService, IDataStorageService dataStorageService, IDialogService dialogService, - INotificationService notificationService) + INotificationService notificationService, + INavigationService navigationService) { _mapper = mapper; _triggerDataService = triggerDataService ?? throw new ArgumentNullException(nameof(triggerDataService)); _dataStorageService = dataStorageService ?? throw new ArgumentNullException(nameof(dataStorageService)); _dialogService = dialogService ?? throw new ArgumentNullException(nameof(dialogService)); _notificationService = notificationService ?? throw new ArgumentNullException(nameof(notificationService)); - + _navigationService = navigationService ?? throw new ArgumentNullException(nameof(navigationService)); + // 初始化时加载触发器数据 - Triggers=_dataStorageService.Triggers; + _synchronizedView = _dataStorageService.Triggers.CreateView(v=>v.Value); + TriggerItemListView= _synchronizedView.ToNotifyCollectionChanged(); + + + } @@ -167,5 +179,31 @@ namespace DMS.WPF.ViewModels } } + /// + /// 刷新触发器列表 + /// + [RelayCommand] + private async Task RefreshAsync() + { + try + { + // 重新加载所有触发器数据 + _triggerDataService.LoadAllTriggers(); + _notificationService.ShowSuccess("触发器列表已刷新"); + } + catch (Exception ex) + { + _notificationService.ShowError($"刷新触发器列表失败: {ex.Message}"); + } + } + + [RelayCommand] + public void NavigateToTriggerDetail() + { + if (SelectedTrigger == null) return; + + _navigationService.NavigateToAsync(this, new NavigationParameter(nameof(TriggerDetailViewModel), SelectedTrigger.Id, NavigationType.Trigger)); + } + } } \ No newline at end of file diff --git a/DMS.WPF/Views/MainView.xaml b/DMS.WPF/Views/MainView.xaml index 5b1c5a4..7ca21aa 100644 --- a/DMS.WPF/Views/MainView.xaml +++ b/DMS.WPF/Views/MainView.xaml @@ -130,6 +130,10 @@ + + + + diff --git a/DMS.WPF/Views/TriggerDetailView.xaml b/DMS.WPF/Views/TriggerDetailView.xaml new file mode 100644 index 0000000..29fda90 --- /dev/null +++ b/DMS.WPF/Views/TriggerDetailView.xaml @@ -0,0 +1,403 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DMS.WPF/Views/TriggerDetailView.xaml.cs b/DMS.WPF/Views/TriggerDetailView.xaml.cs new file mode 100644 index 0000000..20adc39 --- /dev/null +++ b/DMS.WPF/Views/TriggerDetailView.xaml.cs @@ -0,0 +1,15 @@ +using System.Windows.Controls; + +namespace DMS.WPF.Views +{ + /// + /// TriggerDetailView.xaml 的交互逻辑 + /// + public partial class TriggerDetailView : UserControl + { + public TriggerDetailView() + { + InitializeComponent(); + } + } +} \ No newline at end of file diff --git a/DMS.WPF/Views/TriggersView.xaml b/DMS.WPF/Views/TriggersView.xaml index 158c381..dec2542 100644 --- a/DMS.WPF/Views/TriggersView.xaml +++ b/DMS.WPF/Views/TriggersView.xaml @@ -7,28 +7,23 @@ xmlns:hc="https://handyorg.github.io/handycontrol" xmlns:converters="clr-namespace:DMS.WPF.Converters" mc:Ignorable="d" + d:DesignHeight="450" d:DesignWidth="800"> - + - - - - - + Padding="15" + Effect="{DynamicResource SharedDropShadow}"> @@ -43,40 +38,39 @@ - + - - + + VerticalAlignment="Center" + Foreground="{DynamicResource SystemControlForegroundBaseHighBrush}"/> + + + + + - - - - - - @@ -88,16 +82,24 @@ + CornerRadius="20" + Width="12" + Height="12" + Margin="0,0,5,0"> + @@ -110,56 +112,47 @@ - + - - - - - - - - + - - @@ -167,47 +160,62 @@ + + + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - + + + + + + + + + + \ No newline at end of file