From 958593b35d4a1f59c2ae56af02df2eecf52a0450 Mon Sep 17 00:00:00 2001 From: "David P.G" Date: Sun, 19 Oct 2025 20:34:20 +0800 Subject: [PATCH] =?UTF-8?q?=20=20=20=201=20feat:=20=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E8=A7=A6=E5=8F=91=E5=99=A8-=E8=8F=9C=E5=8D=95=E8=81=94?= =?UTF-8?q?=E5=8A=A8=E5=8A=9F=E8=83=BD=E5=92=8C=E4=BA=8B=E4=BB=B6=E7=B3=BB?= =?UTF-8?q?=E7=BB=9F=20=20=20=20=202=20=20=20=20=203=20-=20=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0=E8=A7=A6=E5=8F=91=E5=99=A8=E4=B8=8E=E8=8F=9C=E5=8D=95?= =?UTF-8?q?=E8=81=94=E5=8A=A8=E5=8A=9F=E8=83=BD=EF=BC=8C=E7=8E=B0=E5=9C=A8?= =?UTF-8?q?=E5=8F=AF=E4=BB=A5=E5=90=8C=E6=97=B6=E5=88=9B=E5=BB=BA=E8=A7=A6?= =?UTF-8?q?=E5=8F=91=E5=99=A8=E5=8F=8A=E5=85=B6=E5=85=B3=E8=81=94=E7=9A=84?= =?UTF-8?q?=E8=8F=9C=E5=8D=95=E9=A1=B9=20=20=20=20=204=20-=20=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E8=A7=A6=E5=8F=91=E5=99=A8=E6=9B=B4=E6=94=B9=E4=BA=8B?= =?UTF-8?q?=E4=BB=B6=E7=B3=BB=E7=BB=9F=EF=BC=8C=E7=94=A8=E4=BA=8E=E9=80=9A?= =?UTF-8?q?=E7=9F=A5UI=E5=92=8C=E5=85=B6=E4=BB=96=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E8=A7=A6=E5=8F=91=E5=99=A8=E7=8A=B6=E6=80=81=E7=9A=84=E5=8F=98?= =?UTF-8?q?=E5=8C=96=20=20=20=20=205=20-=20=E4=BC=98=E5=8C=96=E8=A7=A6?= =?UTF-8?q?=E5=8F=91=E5=99=A8=E7=AE=A1=E7=90=86=E6=9C=8D=E5=8A=A1=EF=BC=8C?= =?UTF-8?q?=E6=94=B9=E8=BF=9B=E4=BA=86=E6=B7=BB=E5=8A=A0=E3=80=81=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E5=92=8C=E5=88=A0=E9=99=A4=E8=A7=A6=E5=8F=91=E5=99=A8?= =?UTF-8?q?=E7=9A=84=E9=80=BB=E8=BE=91=20=20=20=20=206=20-=20=E5=B0=86Crea?= =?UTF-8?q?teTriggerAsync=E6=96=B9=E6=B3=95=E9=87=8D=E5=91=BD=E5=90=8D?= =?UTF-8?q?=E4=B8=BAAddTriggerAsync=EF=BC=8C=E4=BD=BF=E5=85=B6=E8=AF=AD?= =?UTF-8?q?=E4=B9=89=E6=9B=B4=E5=87=86=E7=A1=AE=20=20=20=20=207=20-=20?= =?UTF-8?q?=E4=BF=AE=E6=94=B9UpdateTriggerAsync=E6=96=B9=E6=B3=95=E7=9A=84?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E5=92=8C=E8=BF=94=E5=9B=9E=E5=80=BC=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=EF=BC=8C=E6=8F=90=E9=AB=98=E4=B8=80=E8=87=B4=E6=80=A7?= =?UTF-8?q?=20=20=20=20=208=20-=20=E6=B7=BB=E5=8A=A0CreateTriggerWithMenuA?= =?UTF-8?q?sync=E6=96=B9=E6=B3=95=E7=94=A8=E4=BA=8E=E5=90=8C=E6=97=B6?= =?UTF-8?q?=E5=88=9B=E5=BB=BA=E8=A7=A6=E5=8F=91=E5=99=A8=E5=92=8C=E8=8F=9C?= =?UTF-8?q?=E5=8D=95=20=20=20=20=209=20-=20=E5=9C=A8=E5=BA=94=E7=94=A8?= =?UTF-8?q?=E5=B1=82=E9=87=8D=E6=9E=84=E8=A7=A6=E5=8F=91=E5=99=A8=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E9=80=BB=E8=BE=91=EF=BC=8C=E5=A2=9E=E5=8A=A0=E4=BA=8B?= =?UTF-8?q?=E5=8A=A1=E6=94=AF=E6=8C=81=E7=A1=AE=E4=BF=9D=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E4=B8=80=E8=87=B4=E6=80=A7=20=20=20=2010=20-=20=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E8=8F=9C=E5=8D=95=E7=AE=A1=E7=90=86=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=EF=BC=8C=E6=94=B9=E8=BF=9B=E5=B9=B6=E5=8F=91=E5=AE=89=E5=85=A8?= =?UTF-8?q?=E5=A4=84=E7=90=86=20=20=20=2011=20-=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=AD=98=E5=82=A8=E6=9C=8D=E5=8A=A1=EF=BC=8C?= =?UTF-8?q?=E4=BD=BF=E5=85=B6=E5=90=8C=E6=AD=A5=E8=A7=A6=E5=8F=91=E5=99=A8?= =?UTF-8?q?=E5=92=8C=E8=8F=9C=E5=8D=95=E6=9B=B4=E6=96=B0=20=20=20=2012=20-?= =?UTF-8?q?=20=E6=9B=B4=E6=96=B0=E8=A7=A6=E5=8F=91=E5=99=A8=E5=AF=B9?= =?UTF-8?q?=E8=AF=9D=E6=A1=86=E5=92=8C=E5=88=97=E8=A1=A8=E8=A7=86=E5=9B=BE?= =?UTF-8?q?=E6=A8=A1=E5=9E=8B=EF=BC=8C=E6=8F=90=E5=8D=87=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E4=BD=93=E9=AA=8C=20=20=20=2013=20-=20=E5=9C=A8=E4=BE=9D?= =?UTF-8?q?=E8=B5=96=E6=B3=A8=E5=85=A5=E5=AE=B9=E5=99=A8=E4=B8=AD=E6=B3=A8?= =?UTF-8?q?=E5=86=8C=E8=A7=A6=E5=8F=91=E5=99=A8=E6=9C=8D=E5=8A=A1=20=20=20?= =?UTF-8?q?=2014=20-=20=E4=BF=AE=E5=A4=8D=E8=AE=BE=E5=A4=87=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E6=9C=8D=E5=8A=A1=E4=B8=AD=E7=9A=84=E5=BC=82=E6=AD=A5?= =?UTF-8?q?=E8=B0=83=E7=94=A8=E9=97=AE=E9=A2=98=EF=BC=8C=E7=A1=AE=E4=BF=9D?= =?UTF-8?q?=E8=8F=9C=E5=8D=95=E9=A1=B9=E7=9A=84=E6=AD=A3=E7=A1=AE=E5=A4=84?= =?UTF-8?q?=E7=90=86=20=20=20=2015=20-=20=E6=B7=BB=E5=8A=A0=E7=BC=BA?= =?UTF-8?q?=E5=A4=B1=E7=9A=84=E8=A7=A6=E5=8F=91=E5=99=A8=E9=A1=B9=E6=98=A0?= =?UTF-8?q?=E5=B0=84=E9=85=8D=E7=BD=AE=20=20=20=2016=20-=20=E5=88=9B?= =?UTF-8?q?=E5=BB=BATriggerChangedEventArgs=E7=B1=BB=E5=A4=84=E7=90=86?= =?UTF-8?q?=E8=A7=A6=E5=8F=91=E5=99=A8=E6=9B=B4=E6=94=B9=E4=BA=8B=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Events/TriggerChangedEventArgs.cs | 26 ++++ .../Interfaces/Database/ITriggerAppService.cs | 10 +- DMS.Application/Interfaces/IEventService.cs | 16 +++ .../Management/ITriggerManagementService.cs | 11 +- .../Services/Database/TriggerAppService.cs | 94 ++++++++----- DMS.Application/Services/EventService.cs | 19 +++ .../Management/MenuManagementService.cs | 8 +- .../Management/TriggerManagementService.cs | 124 +++++++++++------- DMS.WPF/App.xaml.cs | 1 + DMS.WPF/Interfaces/IMenuDataService.cs | 2 +- DMS.WPF/Interfaces/ITriggerDataService.cs | 2 +- DMS.WPF/Profiles/MappingProfile.cs | 1 + DMS.WPF/Services/DeviceDataService.cs | 6 +- DMS.WPF/Services/MenuDataService.cs | 32 ++++- DMS.WPF/Services/TriggerDataService.cs | 119 +++++++++++------ .../Dialogs/TriggerDialogViewModel.cs | 4 +- DMS.WPF/ViewModels/TriggersViewModel.cs | 86 +++++------- 17 files changed, 362 insertions(+), 199 deletions(-) create mode 100644 DMS.Application/Events/TriggerChangedEventArgs.cs diff --git a/DMS.Application/Events/TriggerChangedEventArgs.cs b/DMS.Application/Events/TriggerChangedEventArgs.cs new file mode 100644 index 0000000..17785f6 --- /dev/null +++ b/DMS.Application/Events/TriggerChangedEventArgs.cs @@ -0,0 +1,26 @@ +using DMS.Core.Enums; +using DMS.Core.Models.Triggers; + +namespace DMS.Application.Events +{ + /// + /// 触发器更改事件参数 + /// + public class TriggerChangedEventArgs : DataChangedEventArgs + { + /// + /// 更改的触发器 + /// + public Trigger Trigger { get; } + + /// + /// 构造函数 + /// + /// 更改类型 + /// 触发器 + public TriggerChangedEventArgs(DataChangeType changeType, Trigger trigger) : base(changeType) + { + Trigger = trigger; + } + } +} \ No newline at end of file diff --git a/DMS.Application/Interfaces/Database/ITriggerAppService.cs b/DMS.Application/Interfaces/Database/ITriggerAppService.cs index 3b2c7f9..abc81c2 100644 --- a/DMS.Application/Interfaces/Database/ITriggerAppService.cs +++ b/DMS.Application/Interfaces/Database/ITriggerAppService.cs @@ -1,3 +1,4 @@ +using DMS.Application.DTOs; using DMS.Core.Models.Triggers; using System.Collections.Generic; using System.Threading.Tasks; @@ -27,7 +28,14 @@ namespace DMS.Application.Interfaces.Database /// /// 要创建的触发器定义。 /// 新创建的触发器定义。 - Task CreateTriggerAsync(Trigger trigger); + Task AddTriggerAsync(Trigger trigger); + + /// + /// 异步创建触发器及其关联菜单。 + /// + /// 包含触发器和菜单信息的数据传输对象。 + /// 包含新创建触发器和菜单信息的数据传输对象。 + Task CreateTriggerWithMenuAsync(CreateTriggerWithMenuDto dto); /// /// 异步更新一个已存在的触发器定义及其关联的变量ID。 diff --git a/DMS.Application/Interfaces/IEventService.cs b/DMS.Application/Interfaces/IEventService.cs index a2eeba2..d43ba08 100644 --- a/DMS.Application/Interfaces/IEventService.cs +++ b/DMS.Application/Interfaces/IEventService.cs @@ -164,4 +164,20 @@ public interface IEventService void RaiseTriggerVariableChanged(object sender, TriggerVariableChangedEventArgs e); #endregion + + #region 触发器事件 + + /// + /// 触发器改变事件 + /// + event EventHandler OnTriggerChanged; + + /// + /// 触发触发器改变事件 + /// + /// 事件发送者 + /// 触发器改变事件参数 + void RaiseTriggerChanged(object sender, TriggerChangedEventArgs e); + + #endregion } \ No newline at end of file diff --git a/DMS.Application/Interfaces/Management/ITriggerManagementService.cs b/DMS.Application/Interfaces/Management/ITriggerManagementService.cs index c820276..c75b04d 100644 --- a/DMS.Application/Interfaces/Management/ITriggerManagementService.cs +++ b/DMS.Application/Interfaces/Management/ITriggerManagementService.cs @@ -26,7 +26,14 @@ namespace DMS.Application.Interfaces.Management /// /// 要创建的触发器定义 DTO /// 创建成功的触发器定义 DTO - Task CreateTriggerAsync(Trigger triggerDto); + Task AddTriggerAsync(Trigger triggerDto); + + /// + /// 创建触发器及其关联菜单 + /// + /// 包含触发器和菜单信息的数据传输对象 + /// 包含新创建触发器和菜单信息的数据传输对象 + Task CreateTriggerWithMenuAsync(CreateTriggerWithMenuDto dto); /// /// 更新一个已存在的触发器定义 @@ -34,7 +41,7 @@ namespace DMS.Application.Interfaces.Management /// 要更新的触发器 ID /// 包含更新信息的触发器定义 DTO /// 更新后的触发器定义 DTO,如果未找到则返回 null - Task UpdateTriggerAsync(int id, Trigger triggerDto); + Task UpdateTriggerAsync( Trigger trigger); /// /// 删除一个触发器定义 diff --git a/DMS.Application/Services/Database/TriggerAppService.cs b/DMS.Application/Services/Database/TriggerAppService.cs index b285ad9..32a3bbb 100644 --- a/DMS.Application/Services/Database/TriggerAppService.cs +++ b/DMS.Application/Services/Database/TriggerAppService.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using System.Linq; using System.Diagnostics; using DMS.Application.Interfaces; +using DMS.Application.DTOs; namespace DMS.Application.Services.Database { @@ -62,7 +63,7 @@ namespace DMS.Application.Services.Database /// /// 要创建的触发器定义。 /// 新创建的触发器定义。 - public async Task CreateTriggerAsync(Trigger trigger) + public async Task AddTriggerAsync(Trigger trigger) { try { @@ -71,19 +72,6 @@ namespace DMS.Application.Services.Database // 添加触发器定义 var addedTrigger = await _repositoryManager.Triggers.AddAsync(trigger); - // // 添加关联的变量ID - // if (trigger.Variables != null && trigger.Variables.Any()) - // { - // var triggerVariables = trigger.Variables.Select(variableId => new DbTriggerVariable - // { - // TriggerDefinitionId = addedTrigger.Id, - // VariableId = variableId - // }) - // .ToList(); - // - // await _repositoryManager.AddTriggerVariablesAsync(triggerVariables); - // } - await _repositoryManager.CommitAsync(); return addedTrigger; } @@ -94,6 +82,62 @@ namespace DMS.Application.Services.Database } } + /// + /// 异步创建触发器及其关联菜单。 + /// + /// 包含触发器和菜单信息的数据传输对象。 + /// 包含新创建触发器和菜单信息的数据传输对象。 + public async Task CreateTriggerWithMenuAsync(CreateTriggerWithMenuDto dto) + { + try + { + await _repositoryManager.BeginTranAsync(); + + // 创建触发器 + var createdTrigger = await _repositoryManager.Triggers.AddAsync(dto.Trigger); + if (createdTrigger == null || createdTrigger.Id == 0) + { + throw new InvalidOperationException($"添加触发器失败:{createdTrigger}"); + } + + // 确保DTO中的触发器对象也更新为新创建的触发器 + dto.Trigger = createdTrigger; + + // 创建菜单 + if (dto.TriggerMenu != null) + { + // 使用现有的菜单查找逻辑来获取父菜单 + var parentMenu = await _repositoryManager.Menus.GetMenuByTargetIdAsync(Core.Enums.MenuType.TriggerMenu, 0); + if (parentMenu != null) + { + // 设置菜单的关联信息 + dto.TriggerMenu.ParentId = parentMenu.Id; + dto.TriggerMenu.MenuType = Core.Enums.MenuType.TriggerMenu; + dto.TriggerMenu.TargetId = createdTrigger.Id; + + // 添加菜单到数据库 + var addMenu = await _repositoryManager.Menus.AddAsync(dto.TriggerMenu); + if (addMenu == null || addMenu.Id == 0) + { + throw new InvalidOperationException($"添加触发器菜单失败:{addMenu}"); + } + + // 更新dto中的菜单对象 + dto.TriggerMenu = addMenu; + } + } + + await _repositoryManager.CommitAsync(); + + return dto; + } + catch (Exception ex) + { + await _repositoryManager.RollbackAsync(); + throw new ApplicationException($"创建触发器及其菜单时发生错误,操作已回滚,错误信息:{ex.Message}", ex); + } + } + /// /// 异步更新一个已存在的触发器定义及其关联的变量ID。 /// @@ -108,25 +152,6 @@ namespace DMS.Application.Services.Database // 更新触发器定义 var rowsAffected = await _repositoryManager.Triggers.UpdateAsync(trigger); - // if (rowsAffected > 0) - // { - // // 删除旧的关联关系 - // await _repositoryManager.DeleteTriggerVariablesByTriggerIdAsync(trigger.Id); - // - // // 插入新的关联关系 - // if (trigger.Variables != null && trigger.Variables.Any()) - // { - // var triggerVariables = trigger.Variables.Select(variableId => new DbTriggerVariable - // { - // TriggerDefinitionId = trigger.Id, - // VariableId = variableId - // }) - // .ToList(); - // - // await _repositoryManager.AddTriggerVariablesAsync(triggerVariables); - // } - // } - await _repositoryManager.CommitAsync(); return rowsAffected; } @@ -148,9 +173,6 @@ namespace DMS.Application.Services.Database { await _repositoryManager.BeginTranAsync(); - // // 删除关联的变量关系 - // await _repositoryManager.DeleteTriggerVariablesByTriggerIdAsync(id); - // 删除触发器本身 var rowsAffected = await _repositoryManager.Triggers.DeleteByIdAsync(id); diff --git a/DMS.Application/Services/EventService.cs b/DMS.Application/Services/EventService.cs index 3d7a544..5bc0d12 100644 --- a/DMS.Application/Services/EventService.cs +++ b/DMS.Application/Services/EventService.cs @@ -207,4 +207,23 @@ public class EventService : IEventService } #endregion + + #region 触发器事件 + + /// + /// 触发器改变事件 + /// + public event EventHandler OnTriggerChanged; + + /// + /// 触发触发器改变事件 + /// + /// 事件发送者 + /// 触发器改变事件参数 + public void RaiseTriggerChanged(object sender, TriggerChangedEventArgs e) + { + OnTriggerChanged?.Invoke(sender, e); + } + + #endregion } \ No newline at end of file diff --git a/DMS.Application/Services/Management/MenuManagementService.cs b/DMS.Application/Services/Management/MenuManagementService.cs index 4e7d54f..e97bcc1 100644 --- a/DMS.Application/Services/Management/MenuManagementService.cs +++ b/DMS.Application/Services/Management/MenuManagementService.cs @@ -78,10 +78,12 @@ public class MenuManagementService : IMenuManagementService var result = await _menuService.UpdateMenuAsync(menu); // 更新成功后,更新内存中的菜单 - if (result > 0 && menu != null) + if (result > 0) { - _appStorageService.Menus.AddOrUpdate(menu.Id, menu, (key, oldValue) => menu); - + if (_appStorageService.Menus.TryGetValue(menu.Id,out var mMenu)) + { + mMenu.Header = menu.Header; + } _eventService.RaiseMenuChanged(this, new MenuChangedEventArgs(DataChangeType.Updated, menu)); } diff --git a/DMS.Application/Services/Management/TriggerManagementService.cs b/DMS.Application/Services/Management/TriggerManagementService.cs index ceea41b..4ef842b 100644 --- a/DMS.Application/Services/Management/TriggerManagementService.cs +++ b/DMS.Application/Services/Management/TriggerManagementService.cs @@ -1,8 +1,12 @@ using AutoMapper; using DMS.Application.DTOs; +using DMS.Application.Events; using DMS.Application.Interfaces; +using DMS.Application.Interfaces.Database; using DMS.Application.Interfaces.Management; using DMS.Application.Services.Triggers; +using DMS.Core.Enums; +using DMS.Core.Events; using DMS.Core.Interfaces; using DMS.Core.Models.Triggers; @@ -14,22 +18,24 @@ namespace DMS.Application.Services.Management public class TriggerManagementService : ITriggerManagementService { private readonly IAppStorageService _appStorageService; - private readonly IRepositoryManager _repositoryManager; + private readonly ITriggerAppService _triggerAppService; private readonly IMapper _mapper; + private readonly IEventService _eventService; - public TriggerManagementService(IAppStorageService appStorageService,IRepositoryManager repositoryManager, IMapper mapper) + public TriggerManagementService(IAppStorageService appStorageService, ITriggerAppService triggerAppService, IMapper mapper, IEventService eventService) { _appStorageService = appStorageService; - _repositoryManager = repositoryManager; + _triggerAppService = triggerAppService; _mapper = mapper ?? throw new ArgumentNullException(nameof(mapper)); + _eventService = eventService; } /// /// 获取所有触发器定义 /// - public List GetAllTriggersAsync() + public List GetAllTriggersAsync() { - var triggers = _appStorageService.Triggers.Values.ToList(); + var triggers = _appStorageService.Triggers.Values.ToList(); return _mapper.Map>(triggers); } @@ -41,76 +47,92 @@ namespace DMS.Application.Services.Management _appStorageService.Triggers.TryGetValue(id, out var trigger); return trigger; } - - + + /// /// 创建一个新的触发器定义 /// - public async Task CreateTriggerAsync(Trigger triggerDto) + public async Task AddTriggerAsync(Trigger trigger) { - // 1. 验证 DTO (可以在应用层或领域层做) - // ValidateTriggerDto(triggerDto); + var createdTrigger = await _triggerAppService.AddTriggerAsync(trigger); - // 2. 转换 DTO 到实体 - var triggerEntity = _mapper.Map(triggerDto); - triggerEntity.CreatedAt = DateTime.UtcNow; - triggerEntity.UpdatedAt = DateTime.UtcNow; - - // 3. 调用仓储保存实体 - var createdTrigger = await _repositoryManager.Triggers.AddAsync(triggerEntity); - - // 5. 同步更新AppDataStorageService中的Triggers字典 - _appStorageService.Triggers[createdTrigger.Id] = createdTrigger; + // 创建成功后,将触发器添加到内存中 + if (createdTrigger != null) + { + if (_appStorageService.Triggers.TryAdd(createdTrigger.Id, createdTrigger)) + { + _eventService.RaiseTriggerChanged(this, new TriggerChangedEventArgs(DataChangeType.Added, createdTrigger)); + } + } return createdTrigger; } /// - /// 更新一个已存在的触发器定义 + /// 创建触发器及其关联菜单 /// - public async Task UpdateTriggerAsync(int id, Trigger triggerDto) + public async Task CreateTriggerWithMenuAsync(CreateTriggerWithMenuDto dto) { - // 1. 获取现有实体 - var existingTrigger = await _repositoryManager.Triggers.GetByIdAsync(id); - if (existingTrigger == null) + var result = await _triggerAppService.CreateTriggerWithMenuAsync(dto); + + // 创建成功后,将触发器添加到内存中 + if (result is null || result.Trigger is null) + { return null; + } - // 2. 验证 DTO - ValidateTriggerDto(triggerDto); + if (_appStorageService.Triggers.TryAdd(result.Trigger.Id, result.Trigger)) + { + _eventService.RaiseTriggerChanged(this, new TriggerChangedEventArgs(DataChangeType.Added, result.Trigger)); + } - // 3. 将 DTO 映射到现有实体 (排除不可变字段如 Id, CreatedAt) - _mapper.Map(triggerDto, existingTrigger, opts => opts.Items["IgnoreIdAndCreatedAt"] = true); - existingTrigger.UpdatedAt = DateTime.UtcNow; + if (_appStorageService.Menus.TryAdd(result.TriggerMenu.Id, result.TriggerMenu)) + { + _eventService.RaiseMenuChanged(this, new MenuChangedEventArgs(DataChangeType.Added, result.TriggerMenu)); + } - // 4. 调用仓储更新实体 - var updatedTrigger = await _repositoryManager.Triggers.UpdateAsync(existingTrigger); - if (updatedTrigger == null) - return null; - - // 5. 转换回 DTO 并返回 - var result = _mapper.Map(updatedTrigger); - - // 6. 同步更新AppDataStorageService中的Triggers字典 - _appStorageService.Triggers[result.Id] = result; return result; } + /// + /// 更新一个已存在的触发器定义 + /// + public async Task UpdateTriggerAsync(Trigger trigger) + { + + // 4. 调用仓储更新实体 + var res = await _triggerAppService.UpdateTriggerAsync(trigger); + if (res == 0) + return res; + + // 6. 同步更新AppDataStorageService中的Triggers字典 + if (_appStorageService.Triggers.TryGetValue(trigger.Id, out var memTrigger)) + { + _mapper.Map(trigger, memTrigger); + } + + + return res; + } + /// /// 删除一个触发器定义 /// public async Task DeleteTriggerAsync(int id) { - // var result = await _repositoryManager.Triggers.DeleteAsync(id); - // - // // 如果删除成功,也从AppDataStorageService中的Triggers字典中移除 - // if (result) - // { - // _appStorageService.Triggers.TryRemove(id, out _); - // } - // - // return result; - return false; + + // 如果删除成功,也从AppDataStorageService中的Triggers字典中移除 + if (await _triggerAppService.DeleteTriggerByIdAsync(id)) + { + _appStorageService.Triggers.TryRemove(id, out _); + return true; + } + else + { + return false; + } + } /// @@ -129,7 +151,7 @@ namespace DMS.Application.Services.Management public async Task LoadAllTriggersAsync() { _appStorageService.Triggers.Clear(); - var triggerDefinitions = await _repositoryManager.Triggers.GetAllAsync(); + var triggerDefinitions = await _triggerAppService.GetAllTriggersAsync(); foreach (var triggerDefinition in triggerDefinitions) { _appStorageService.Triggers.TryAdd(triggerDefinition.Id, triggerDefinition); diff --git a/DMS.WPF/App.xaml.cs b/DMS.WPF/App.xaml.cs index b81638e..a3157bd 100644 --- a/DMS.WPF/App.xaml.cs +++ b/DMS.WPF/App.xaml.cs @@ -268,6 +268,7 @@ public partial class App : System.Windows.Application services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); // 注册触发器应用服务 services.AddSingleton(); // 注册触发器管理服务 services.AddSingleton(); // 注册触发器评估服务 services.AddSingleton(); // 注册触发器动作执行器 diff --git a/DMS.WPF/Interfaces/IMenuDataService.cs b/DMS.WPF/Interfaces/IMenuDataService.cs index 2d5a3d7..cdc9b6d 100644 --- a/DMS.WPF/Interfaces/IMenuDataService.cs +++ b/DMS.WPF/Interfaces/IMenuDataService.cs @@ -21,5 +21,5 @@ public interface IMenuDataService Task DeleteMenuItem(MenuItem? MenuItem); void LoadAllMenus(); - + Task UpdateMenuItem(MenuItem MenuItem); } \ No newline at end of file diff --git a/DMS.WPF/Interfaces/ITriggerDataService.cs b/DMS.WPF/Interfaces/ITriggerDataService.cs index 39f57d3..784fe6b 100644 --- a/DMS.WPF/Interfaces/ITriggerDataService.cs +++ b/DMS.WPF/Interfaces/ITriggerDataService.cs @@ -22,7 +22,7 @@ public interface ITriggerDataService /// /// 添加触发器及其关联菜单。 /// - Task AddTriggerWithMenu(CreateTriggerWithMenuDto dto); + Task CreateTriggerWithMenu(CreateTriggerWithMenuDto dto); /// /// 删除触发器。 diff --git a/DMS.WPF/Profiles/MappingProfile.cs b/DMS.WPF/Profiles/MappingProfile.cs index 82d1157..c485556 100644 --- a/DMS.WPF/Profiles/MappingProfile.cs +++ b/DMS.WPF/Profiles/MappingProfile.cs @@ -38,6 +38,7 @@ namespace DMS.WPF.Profiles CreateMap() .ReverseMap(); CreateMap().ReverseMap(); + CreateMap().ReverseMap(); // 添加触发器相关映射 CreateMap() diff --git a/DMS.WPF/Services/DeviceDataService.cs b/DMS.WPF/Services/DeviceDataService.cs index ef35f76..fc611d8 100644 --- a/DMS.WPF/Services/DeviceDataService.cs +++ b/DMS.WPF/Services/DeviceDataService.cs @@ -111,7 +111,7 @@ public class DeviceDataService : IDeviceDataService // 给界面添加设备菜单 if (addDto.DeviceMenu != null) { - _menuDataService.AddMenuItem(_mapper.Map(addDto.DeviceMenu)); + await _menuDataService.AddMenuItem(_mapper.Map(addDto.DeviceMenu)); } @@ -124,7 +124,7 @@ public class DeviceDataService : IDeviceDataService if (addDto.VariableTable != null && addDto.VariableTableMenu != null) { - _menuDataService.AddMenuItem(_mapper.Map(addDto.VariableTableMenu)); + await _menuDataService.AddMenuItem(_mapper.Map(addDto.VariableTableMenu)); } @@ -158,7 +158,7 @@ public class DeviceDataService : IDeviceDataService var deviceMenu= _dataStorageService.Menus.FirstOrDefault(m => m.MenuType == MenuType.DeviceMenu && m.TargetId == device.Id); if (deviceMenu != null) { - _menuDataService.DeleteMenuItem(deviceMenu); + await _menuDataService.DeleteMenuItem(deviceMenu); } _dataStorageService.Devices.Remove(device.Id); diff --git a/DMS.WPF/Services/MenuDataService.cs b/DMS.WPF/Services/MenuDataService.cs index 6c00ed0..7430f1c 100644 --- a/DMS.WPF/Services/MenuDataService.cs +++ b/DMS.WPF/Services/MenuDataService.cs @@ -27,7 +27,7 @@ public class MenuDataService : IMenuDataService /// /// AutoMapper 实例。 /// 数据服务中心实例。 - public MenuDataService(IMapper mapper,IDataStorageService dataStorageService, IAppStorageService appStorageService,IMenuManagementService menuManagementService) + public MenuDataService(IMapper mapper, IDataStorageService dataStorageService, IAppStorageService appStorageService, IMenuManagementService menuManagementService) { _mapper = mapper; _dataStorageService = dataStorageService; @@ -79,15 +79,35 @@ public class MenuDataService : IMenuDataService if (deviceMenu is not null) { - var menuId= await _menuManagementService.CreateMenuAsync(_mapper.Map(MenuItem)); - if (menuId>0) + var menuId = await _menuManagementService.CreateMenuAsync(_mapper.Map(MenuItem)); + if (menuId > 0) { MenuItem.Id = menuId; deviceMenu.Children.Add(MenuItem); _dataStorageService.Menus.Add(MenuItem); BuildMenuTrees(); } - + + } + } + + /// + /// 更新菜单项。 + /// + public async Task UpdateMenuItem(MenuItem MenuItem) + { + if (MenuItem is null) return; + + var menu = _dataStorageService.Menus.FirstOrDefault(m => m.Id == MenuItem.Id); + if (menu is not null) + { + + var res = await _menuManagementService.UpdateMenuAsync(_mapper.Map(MenuItem)); + if (res > 0) + { + menu.Header = MenuItem.Header; + } + } } @@ -99,8 +119,8 @@ public class MenuDataService : IMenuDataService { if (MenuItem is null) return; - await _menuManagementService.DeleteMenuAsync(MenuItem.Id); - + await _menuManagementService.DeleteMenuAsync(MenuItem.Id); + // 从扁平菜单列表中移除 _dataStorageService.Menus.Remove(MenuItem); diff --git a/DMS.WPF/Services/TriggerDataService.cs b/DMS.WPF/Services/TriggerDataService.cs index b256e5e..813311b 100644 --- a/DMS.WPF/Services/TriggerDataService.cs +++ b/DMS.WPF/Services/TriggerDataService.cs @@ -4,10 +4,15 @@ using DMS.Application.Interfaces; using DMS.Application.Services; using DMS.Core.Enums; using DMS.Core.Events; +using DMS.Core.Models; using DMS.Core.Models.Triggers; using DMS.WPF.Interfaces; using DMS.WPF.ItemViewModel; +using DMS.WPF.ViewModels; +using HandyControl.Data; using Opc.Ua; +using System.Windows; +using System.Windows.Controls; using System.Windows.Threading; namespace DMS.WPF.Services; @@ -19,6 +24,7 @@ public class TriggerDataService : ITriggerDataService { private readonly IMapper _mapper; private readonly IAppCenterService _appCenterService; + private readonly IMenuDataService _menuDataService; private readonly IAppStorageService _appStorageService; private readonly IDataStorageService _dataStorageService; private readonly IEventService _eventService; @@ -35,11 +41,13 @@ public class TriggerDataService : ITriggerDataService /// 事件服务实例。 /// 通知服务实例。 public TriggerDataService(IMapper mapper, IAppCenterService appCenterService, + IMenuDataService menuDataService, IAppStorageService appStorageService, IDataStorageService dataStorageService, IEventService eventService, INotificationService notificationService) { _mapper = mapper; _appCenterService = appCenterService; + _menuDataService = menuDataService; _appStorageService = appStorageService; _dataStorageService = dataStorageService; _eventService = eventService; @@ -65,22 +73,39 @@ public class TriggerDataService : ITriggerDataService public async Task AddTrigger(TriggerItem triggerItem) { // 添加null检查 - if (triggerItem == null) - return null; + if (triggerItem is null) return null; var addDto - = await _appCenterService.TriggerManagementService.CreateTriggerAsync( - _mapper.Map(triggerItem)); + = await _appCenterService.TriggerManagementService.AddTriggerAsync( + _mapper.Map(triggerItem)); // 添加null检查 - if (addDto == null) - { - return null; - } + if (addDto is null) return null; // 给界面添加触发器 - var addItem = _mapper.Map(addDto); - _dataStorageService.Triggers.Add(addDto.Id, addItem); + var addItem = _mapper.Map(addDto, triggerItem); + + _dataStorageService.Triggers.Add(triggerItem.Id, triggerItem); + + //添加菜单 + + var parentMenu=_dataStorageService.Menus.FirstOrDefault(m => m.TargetViewKey == nameof(TriggersViewModel) && m.TargetId == 0); + if (parentMenu is not null) + { + var menuItem = new ItemViewModel.MenuItem() + { + Header = triggerItem.Name, + ParentId=parentMenu.Id, + MenuType=MenuType.TriggerMenu, + TargetId=addItem.Id, + Icon = "\uE945", // 使用触发器图标 + TargetViewKey = nameof(TriggerDetailViewModel), + }; + await _menuDataService.AddMenuItem(menuItem); + + } + + return addItem; } @@ -91,21 +116,27 @@ public class TriggerDataService : ITriggerDataService public async Task DeleteTrigger(TriggerItem trigger) { // 从数据库删除触发器数据 - if (!await _appCenterService.TriggerManagementService.DeleteTriggerAsync(trigger.Id)) + if (await _appCenterService.TriggerManagementService.DeleteTriggerAsync(trigger.Id)) { - return false; + //删除菜单 + var menu=_dataStorageService.Menus.FirstOrDefault(m => m.MenuType == MenuType.TriggerMenu && m.TargetId == trigger.Id); + if (menu is not null) + { + await _menuDataService.DeleteMenuItem(menu); + } + + // 从界面删除触发器 + _dataStorageService.Triggers.Remove(trigger.Id); + + return true; } - - // 从界面删除触发器 - _dataStorageService.Triggers.Remove(trigger.Id); - - return true; + return false; } /// /// 添加触发器及其关联菜单。 /// - public async Task AddTriggerWithMenu(CreateTriggerWithMenuDto dto) + public async Task CreateTriggerWithMenu(CreateTriggerWithMenuDto dto) { // 添加null检查 if (dto == null || dto.Trigger == null) @@ -114,26 +145,16 @@ public class TriggerDataService : ITriggerDataService try { // 首先添加触发器 - var createdTrigger = await _appCenterService.TriggerManagementService.CreateTriggerAsync(dto.Trigger); + var createdTrigger = await _appCenterService.TriggerManagementService.CreateTriggerWithMenuAsync(dto); if (createdTrigger == null) return null; - - var parentMenu=_appStorageService.Menus.Values.OrderBy(m=>m.Id).FirstOrDefault(m=>m.MenuType==MenuType.TriggerMenu); - if (parentMenu is not null) - { - // 将菜单关联到触发器 - dto.TriggerMenu.TargetId = createdTrigger.Id; - dto.TriggerMenu.MenuType = MenuType.TriggerMenu; - } - - - - // 添加到UI数据存储 - var addItem = _mapper.Map(createdTrigger); - _dataStorageService.Triggers.Add(createdTrigger.Id, addItem); + var addItem = _mapper.Map(createdTrigger.Trigger); + _dataStorageService.Triggers.Add(addItem.Id, addItem); + + return dto; } @@ -147,18 +168,34 @@ public class TriggerDataService : ITriggerDataService /// /// 更新触发器。 /// - public async Task UpdateTrigger(TriggerItem trigger) + public async Task UpdateTrigger(TriggerItem triggerItem) { - if (!_appStorageService.Triggers.TryGetValue(trigger.Id, out var triggerDto)) + if (_appStorageService.Triggers.TryGetValue(triggerItem.Id, out var triggerDto)) { - return false; + _mapper.Map(triggerItem, triggerDto); + if (await _appCenterService.TriggerManagementService.UpdateTriggerAsync(triggerDto) > 0) + { + if (_dataStorageService.Triggers.TryGetValue(triggerItem.Id,out var mTrigger)) + { + _mapper.Map(triggerItem,mTrigger); + + //菜单 + var menuItem = _dataStorageService.Menus.FirstOrDefault(m => m.MenuType == MenuType.TriggerMenu && m.TargetId == triggerItem.Id); + if (menuItem is not null) + { + menuItem.Header = triggerItem.Name; + await _menuDataService.UpdateMenuItem(menuItem); + } + + return true; + } + + + } } - _mapper.Map(trigger, triggerDto); - if (await _appCenterService.TriggerManagementService.UpdateTriggerAsync(trigger.Id, triggerDto) != null) - { - return true; - } + + return false; } diff --git a/DMS.WPF/ViewModels/Dialogs/TriggerDialogViewModel.cs b/DMS.WPF/ViewModels/Dialogs/TriggerDialogViewModel.cs index 7ecad9a..2d5365b 100644 --- a/DMS.WPF/ViewModels/Dialogs/TriggerDialogViewModel.cs +++ b/DMS.WPF/ViewModels/Dialogs/TriggerDialogViewModel.cs @@ -145,10 +145,10 @@ namespace DMS.WPF.ViewModels.Dialogs } // Set timestamps - Trigger.UpdatedAt = DateTime.UtcNow; + Trigger.UpdatedAt = DateTime.Now; if (Trigger.Id == default(int)) { - Trigger.CreatedAt = DateTime.UtcNow; + Trigger.CreatedAt = DateTime.Now; Trigger.Id = 0; // 对于自增ID,设置为0让数据库自动生成 } diff --git a/DMS.WPF/ViewModels/TriggersViewModel.cs b/DMS.WPF/ViewModels/TriggersViewModel.cs index 9e84720..c115761 100644 --- a/DMS.WPF/ViewModels/TriggersViewModel.cs +++ b/DMS.WPF/ViewModels/TriggersViewModel.cs @@ -30,7 +30,7 @@ namespace DMS.WPF.ViewModels public NotifyCollectionChangedSynchronizedViewList TriggerItemListView { get; } [ObservableProperty] - private ObservableDictionary _triggers ; + private ObservableDictionary _triggers; [ObservableProperty] private TriggerItem? _selectedTrigger; @@ -51,14 +51,14 @@ namespace DMS.WPF.ViewModels _navigationService = navigationService ?? throw new ArgumentNullException(nameof(navigationService)); // 初始化时加载触发器数据 - _synchronizedView = _dataStorageService.Triggers.CreateView(v=>v.Value); - TriggerItemListView= _synchronizedView.ToNotifyCollectionChanged(); - + _synchronizedView = _dataStorageService.Triggers.CreateView(v => v.Value); + TriggerItemListView = _synchronizedView.ToNotifyCollectionChanged(); + } - + /// /// 添加新触发器 @@ -67,59 +67,40 @@ namespace DMS.WPF.ViewModels private async Task AddTriggerAsync() { var newTrigger = new TriggerItem() - { - IsActive = true, - Action = Core.Models.Triggers.ActionType.SendEmail, - Description = "新建触发器", - CreatedAt = DateTime.Now, - UpdatedAt = DateTime.Now + { + IsActive = true, + Action = Core.Models.Triggers.ActionType.SendEmail, + Name = "新建触发器", + Description = "新建触发器", + CreatedAt = DateTime.Now, + UpdatedAt = DateTime.Now }; TriggerDialogViewModel viewModel = App.Current.Services.GetRequiredService(); await viewModel.OnInitializedAsync(newTrigger); var result = await _dialogService.ShowDialogAsync(viewModel); - if (result != null) + if (result is null) return; + + try { - try - { - // 创建包含菜单信息的 DTO - CreateTriggerWithMenuDto dto = new CreateTriggerWithMenuDto(); - if (_mapper != null) - { - dto.Trigger = _mapper.Map(result); - } - else - { - _notificationService?.ShowError("映射服务未初始化"); - return; - } - // 创建菜单项 - dto.TriggerMenu = new MenuBean() - { - Header = result.Name ?? result.Description, - Icon = "\uE945", // 使用触发器图标 - TargetViewKey = nameof(TriggerDetailViewModel), - }; + // 使用TriggerDataService添加触发器和菜单 + var resTriggerItem = await _triggerDataService.AddTrigger(result); - // 使用TriggerDataService添加触发器和菜单 - var createdTriggerDto = await _triggerDataService.AddTriggerWithMenu(dto); - - if (createdTriggerDto != null && createdTriggerDto.Trigger != null) - { - // 更新UI显示 - _notificationService.ShowSuccess($"触发器创建成功:{createdTriggerDto.Trigger.Name ?? createdTriggerDto.Trigger.Description}"); - } - else - { - _notificationService.ShowError("触发器创建失败"); - } - } - catch (Exception ex) + if (resTriggerItem is not null) { - _notificationService.ShowError($"创建触发器失败: {ex.Message}"); + // 更新UI显示 + _notificationService.ShowSuccess($"触发器创建成功:{resTriggerItem.Name}"); } + else + { + _notificationService.ShowError("触发器创建失败"); + } + } + catch (Exception ex) + { + _notificationService.ShowError($"创建触发器失败: {ex.Message},"); } } @@ -136,10 +117,11 @@ namespace DMS.WPF.ViewModels } // 传递副本以避免直接修改原始对象 - var triggerToEdit = _mapper.Map(SelectedTrigger); - + TriggerItem triggerItemToEdit = new TriggerItem(); + _mapper.Map(SelectedTrigger, triggerItemToEdit); + TriggerDialogViewModel viewModel = App.Current.Services.GetRequiredService(); - await viewModel.OnInitializedAsync(triggerToEdit); + await viewModel.OnInitializedAsync(triggerItemToEdit); var result = await _dialogService.ShowDialogAsync(viewModel); if (result != null) @@ -147,7 +129,7 @@ namespace DMS.WPF.ViewModels try { // 使用TriggerDataService更新触发器 - var updatedTrigger = await _triggerDataService.UpdateTrigger(SelectedTrigger); + var updatedTrigger = await _triggerDataService.UpdateTrigger(result); if (updatedTrigger) { _notificationService.ShowSuccess("触发器更新成功"); @@ -176,7 +158,7 @@ namespace DMS.WPF.ViewModels return; } - var confirm = await _dialogService.ShowDialogAsync(new ConfirmDialogViewModel("确认删除", $"确定要删除触发器 '{SelectedTrigger.Description}' 吗?","删除")); + var confirm = await _dialogService.ShowDialogAsync(new ConfirmDialogViewModel("确认删除", $"确定要删除触发器 '{SelectedTrigger.Description}' 吗?", "删除")); if (confirm) { try