diff --git a/DMS.Application/DTOs/Events/NlogChangedEventArgs.cs b/DMS.Application/DTOs/Events/NlogChangedEventArgs.cs new file mode 100644 index 0000000..2f03f2c --- /dev/null +++ b/DMS.Application/DTOs/Events/NlogChangedEventArgs.cs @@ -0,0 +1,25 @@ +using System; + +namespace DMS.Application.DTOs.Events +{ + /// + /// Nlog日志变更事件参数 + /// + public class NlogChangedEventArgs : DataChangedEventArgs + { + /// + /// 变更的日志DTO + /// + public NlogDto Nlog { get; } + + /// + /// 构造函数 + /// + /// 变更类型 + /// 变更的日志DTO + public NlogChangedEventArgs(DataChangeType changeType, NlogDto nlog) : base(changeType) + { + Nlog = nlog; + } + } +} \ No newline at end of file diff --git a/DMS.Application/Interfaces/IDataCenterService.cs b/DMS.Application/Interfaces/IDataCenterService.cs index 3feceef..459117f 100644 --- a/DMS.Application/Interfaces/IDataCenterService.cs +++ b/DMS.Application/Interfaces/IDataCenterService.cs @@ -261,6 +261,45 @@ public interface IDataCenterService #endregion + #region 日志管理 + + /// + /// 异步根据ID获取日志DTO。 + /// + Task GetNlogByIdAsync(int id); + + /// + /// 异步获取所有日志DTO列表。 + /// + Task> GetAllNlogsAsync(); + + /// + /// 异步获取指定数量的最新日志DTO列表。 + /// + Task> GetLatestNlogsAsync(int count); + + /// + /// 异步清空所有日志。 + /// + Task ClearAllNlogsAsync(); + + /// + /// 在内存中添加日志 + /// + void AddNlogToMemory(NlogDto nlogDto); + + /// + /// 在内存中更新日志 + /// + void UpdateNlogInMemory(NlogDto nlogDto); + + /// + /// 在内存中删除日志 + /// + void RemoveNlogFromMemory(int nlogId); + + #endregion + #region 数据存储访问 /// @@ -291,6 +330,11 @@ public interface IDataCenterService /// 获取所有MQTT服务器的安全字典。 /// ConcurrentDictionary MqttServers { get; } + + /// + /// 获取所有日志的安全字典。 + /// + ConcurrentDictionary Nlogs { get; } #endregion @@ -325,6 +369,11 @@ public interface IDataCenterService /// 异步加载所有MQTT服务器数据。 /// Task> LoadAllMqttServersAsync(); + + /// + /// 异步加载所有日志数据。 + /// + Task> LoadAllNlogsAsync(); #endregion @@ -360,6 +409,10 @@ public interface IDataCenterService /// event EventHandler MqttServerChanged; + /// + /// 当日志数据发生变化时触发 + /// + event EventHandler NlogChanged; /// /// 当变量值发生变化时触发 diff --git a/DMS.Application/Services/DataCenterService.cs b/DMS.Application/Services/DataCenterService.cs index 0ab3d79..4fd66df 100644 --- a/DMS.Application/Services/DataCenterService.cs +++ b/DMS.Application/Services/DataCenterService.cs @@ -15,7 +15,7 @@ using System.Linq; namespace DMS.Application.Services; /// -/// 数据中心服务,负责管理所有的数据,包括设备、变量表、变量和菜单。 +/// 数据中心服务,负责管理所有的数据,包括设备、变量表、变量、菜单和日志。 /// 实现 接口。 /// public class DataCenterService : IDataCenterService @@ -27,6 +27,7 @@ public class DataCenterService : IDataCenterService private readonly IVariableAppService _variableAppService; private readonly IMenuService _menuService; private readonly IMqttAppService _mqttAppService; + private readonly INlogAppService _nlogAppService; /// /// 安全字典,用于存储所有设备数据 @@ -58,6 +59,11 @@ public class DataCenterService : IDataCenterService /// public ConcurrentDictionary MqttServers { get; } = new(); + /// + /// 安全字典,用于存储所有日志数据 + /// + public ConcurrentDictionary Nlogs { get; } = new(); + #region 事件定义 /// @@ -90,6 +96,10 @@ public class DataCenterService : IDataCenterService /// public event EventHandler MqttServerChanged; + /// + /// 当日志数据发生变化时触发 + /// + public event EventHandler NlogChanged; /// /// 当变量值发生变化时触发 @@ -108,6 +118,7 @@ public class DataCenterService : IDataCenterService /// 变量应用服务实例。 /// 菜单服务实例。 /// MQTT应用服务实例。 + /// Nlog应用服务实例。 public DataCenterService( IRepositoryManager repositoryManager, IMapper mapper, @@ -115,7 +126,8 @@ public class DataCenterService : IDataCenterService IVariableTableAppService variableTableAppService, IVariableAppService variableAppService, IMenuService menuService, - IMqttAppService mqttAppService) + IMqttAppService mqttAppService, + INlogAppService nlogAppService) { _repositoryManager = repositoryManager; _mapper = mapper; @@ -124,6 +136,7 @@ public class DataCenterService : IDataCenterService _variableAppService = variableAppService; _menuService = menuService; _mqttAppService = mqttAppService; + _nlogAppService = nlogAppService; } #region 设备管理 @@ -644,6 +657,7 @@ public class DataCenterService : IDataCenterService Menus.Clear(); MenuTrees.Clear(); MqttServers.Clear(); + Nlogs.Clear(); // 加载所有设备 var devices = await _repositoryManager.Devices.GetAllAsync(); @@ -662,6 +676,9 @@ public class DataCenterService : IDataCenterService var menuDtos = _mapper.Map>(menus); var mqttServers = await LoadAllMqttServersAsync(); + + // 加载所有日志 + var nlogs = await LoadAllNlogsAsync(); var variableMqttAliases = await _repositoryManager.VariableMqttAliases.GetAllAsync(); @@ -696,6 +713,12 @@ public class DataCenterService : IDataCenterService { MqttServers.TryAdd(mqttServer.Id, mqttServer); } + + // 加载日志数据到内存 + foreach (var nlog in nlogs) + { + Nlogs.TryAdd(nlog.Id, nlog); + } // 将变量添加到安全字典 foreach (var variableDto in variableDtos) @@ -783,6 +806,14 @@ public class DataCenterService : IDataCenterService { return await _mqttAppService.GetAllMqttServersAsync(); } + + /// + /// 异步加载所有日志数据。 + /// + public async Task> LoadAllNlogsAsync() + { + return await _nlogAppService.GetAllLogsAsync(); + } #endregion @@ -836,6 +867,14 @@ public class DataCenterService : IDataCenterService MqttServerChanged?.Invoke(this, e); } + /// + /// 触发日志变更事件 + /// + protected virtual void OnNlogChanged(NlogChangedEventArgs e) + { + NlogChanged?.Invoke(this, e); + } + /// /// 触发变量值变更事件 @@ -846,7 +885,7 @@ public class DataCenterService : IDataCenterService } #endregion - + #region 私有辅助方法 /// @@ -868,4 +907,71 @@ public class DataCenterService : IDataCenterService } #endregion + + #region 日志管理 + + /// + /// 异步根据ID获取日志DTO。 + /// + public async Task GetNlogByIdAsync(int id) + { + return await _nlogAppService.GetLogByIdAsync(id); + } + + /// + /// 异步获取所有日志DTO列表。 + /// + public async Task> GetAllNlogsAsync() + { + return await _nlogAppService.GetAllLogsAsync(); + } + + /// + /// 异步获取指定数量的最新日志DTO列表。 + /// + public async Task> GetLatestNlogsAsync(int count) + { + return await _nlogAppService.GetLatestLogsAsync(count); + } + + /// + /// 异步清空所有日志。 + /// + public async Task ClearAllNlogsAsync() + { + await _nlogAppService.ClearAllLogsAsync(); + } + + /// + /// 在内存中添加日志 + /// + public void AddNlogToMemory(NlogDto nlogDto) + { + if (Nlogs.TryAdd(nlogDto.Id, nlogDto)) + { + OnNlogChanged(new NlogChangedEventArgs(DataChangeType.Added, nlogDto)); + } + } + + /// + /// 在内存中更新日志 + /// + public void UpdateNlogInMemory(NlogDto nlogDto) + { + Nlogs.AddOrUpdate(nlogDto.Id, nlogDto, (key, oldValue) => nlogDto); + OnNlogChanged(new NlogChangedEventArgs(DataChangeType.Updated, nlogDto)); + } + + /// + /// 在内存中删除日志 + /// + public void RemoveNlogFromMemory(int nlogId) + { + if (Nlogs.TryRemove(nlogId, out var nlogDto)) + { + OnNlogChanged(new NlogChangedEventArgs(DataChangeType.Deleted, nlogDto)); + } + } + + #endregion } \ No newline at end of file diff --git a/DMS.Core/Enums/LoadTypes.cs b/DMS.Core/Enums/LoadTypes.cs index 45a3d85..808dd8a 100644 --- a/DMS.Core/Enums/LoadTypes.cs +++ b/DMS.Core/Enums/LoadTypes.cs @@ -5,5 +5,6 @@ public enum LoadTypes Devices, Menu, Mqtts, + Logs, All } \ No newline at end of file diff --git a/DMS.WPF/App.xaml.cs b/DMS.WPF/App.xaml.cs index b3fc0b4..0002c7e 100644 --- a/DMS.WPF/App.xaml.cs +++ b/DMS.WPF/App.xaml.cs @@ -277,7 +277,9 @@ public partial class App : System.Windows.Application provider.GetRequiredService(), provider.GetRequiredService(), provider.GetRequiredService(), - provider.GetRequiredService() + provider.GetRequiredService(), + provider.GetRequiredService(), + provider.GetRequiredService() ) ); services.AddScoped(); diff --git a/DMS.WPF/Services/DataServices.cs b/DMS.WPF/Services/DataServices.cs index 84fca33..6081a17 100644 --- a/DMS.WPF/Services/DataServices.cs +++ b/DMS.WPF/Services/DataServices.cs @@ -12,6 +12,7 @@ using DMS.Core.Models; using DMS.Message; using DMS.WPF.ViewModels.Items; using Microsoft.IdentityModel.Protocols.OpenIdConnect; +using ObservableCollections; namespace DMS.WPF.Services; @@ -50,6 +51,10 @@ public partial class DataServices : ObservableObject, IRecipient, I [ObservableProperty] private ObservableCollection _mqttServers; + // 日志列表。 + [ObservableProperty] + private ObservableCollection _nlogs; + // 设备列表变更事件,当设备列表数据更新时触发。 public event Action> OnDeviceListChanged; @@ -79,6 +84,37 @@ public partial class DataServices : ObservableObject, IRecipient, I })); } + /// + /// 处理日志变更事件 + /// + private void OnNlogChanged(object sender, NlogChangedEventArgs e) + { + // 在UI线程上更新日志 + App.Current.Dispatcher.BeginInvoke(new Action(() => + { + switch (e.ChangeType) + { + case DataChangeType.Added: + Nlogs.Add(_mapper.Map(e.Nlog)); + break; + case DataChangeType.Updated: + var existingLog = Nlogs.FirstOrDefault(l => l.Id == e.Nlog.Id); + if (existingLog != null) + { + _mapper.Map(e.Nlog, existingLog); + } + break; + case DataChangeType.Deleted: + var logToRemove = Nlogs.FirstOrDefault(l => l.Id == e.Nlog.Id); + if (logToRemove != null) + { + Nlogs.Remove(logToRemove); + } + break; + } + })); + } + /// /// DataServices类的构造函数。 @@ -98,10 +134,13 @@ public partial class DataServices : ObservableObject, IRecipient, I Menus = new ObservableCollection(); MenuTrees = new ObservableCollection(); MqttServers = new ObservableCollection(); + Nlogs = new ObservableCollection(); // 监听变量值变更事件 _dataCenterService.VariableValueChanged += OnVariableValueChanged; _dataCenterService.OnLoadDataCompleted += OnLoadDataCompleted; + // 监听日志变更事件 + _dataCenterService.NlogChanged += OnNlogChanged; // 注册消息接收 // WeakReferenceMessenger.Register(this, (r, m) => r.Receive(m)); @@ -144,6 +183,9 @@ public partial class DataServices : ObservableObject, IRecipient, I // 加载MQTT服务器数据 MqttServers = _mapper.Map>(_dataCenterService.MqttServers.Values); + + // 加载日志数据 + Nlogs = _mapper.Map>(_dataCenterService.Nlogs.Values); BuildMenuTrees(); } @@ -477,6 +519,9 @@ public partial class DataServices : ObservableObject, IRecipient, I case LoadTypes.Mqtts: _ = Task.Run(async () => await LoadMqttServers(_mqttAppService)); break; + case LoadTypes.Logs: + // 日志数据已在IDataCenterService中处理 + break; case LoadTypes.All: // 加载所有数据 LoadAllDatas(); diff --git a/DMS.WPF/ViewModels/Items/NlogItemViewModel.cs b/DMS.WPF/ViewModels/Items/NlogItemViewModel.cs index 32d34c4..6fc76cb 100644 --- a/DMS.WPF/ViewModels/Items/NlogItemViewModel.cs +++ b/DMS.WPF/ViewModels/Items/NlogItemViewModel.cs @@ -7,6 +7,11 @@ public class NlogItemViewModel : ObservableObject { private Nlog _nlog; + public NlogItemViewModel() + { + _nlog = new Nlog(); + } + public NlogItemViewModel(Nlog nlog) { _nlog = nlog; diff --git a/DMS.WPF/ViewModels/LogHistoryViewModel.cs b/DMS.WPF/ViewModels/LogHistoryViewModel.cs index 4fb9aeb..fb2f4da 100644 --- a/DMS.WPF/ViewModels/LogHistoryViewModel.cs +++ b/DMS.WPF/ViewModels/LogHistoryViewModel.cs @@ -15,15 +15,19 @@ using DMS.WPF.ViewModels.Dialogs; using Microsoft.Extensions.DependencyInjection; using System.Collections.ObjectModel; using System; +using DMS.WPF.Services; +using DMS.Application.DTOs.Events; namespace DMS.WPF.ViewModels; -partial class LogHistoryViewModel : ViewModelBase +partial class LogHistoryViewModel : ViewModelBase,IDisposable { + public DataServices DataServices { get; } private readonly IMapper _mapper; private readonly INlogAppService _nlogAppService; private readonly IDialogService _dialogService; private readonly INotificationService _notificationService; + private readonly IDataCenterService _dataCenterService; [ObservableProperty] private NlogItemViewModel _selectedLog; @@ -43,16 +47,85 @@ partial class LogHistoryViewModel : ViewModelBase public ObservableCollection LogLevels { get; } = new ObservableCollection { "Trace", "Debug", "Info", "Warn", "Error", "Fatal" }; - public LogHistoryViewModel(IMapper mapper, INlogAppService nlogAppService, IDialogService dialogService, INotificationService notificationService) + public LogHistoryViewModel(IMapper mapper, INlogAppService nlogAppService, IDialogService dialogService, + INotificationService notificationService, DataServices dataServices, IDataCenterService dataCenterService) { _mapper = mapper; _nlogAppService = nlogAppService; _dialogService = dialogService; _notificationService = notificationService; + DataServices = dataServices; + _dataCenterService = dataCenterService; - _logItemList = new ObservableList(); + _logItemList = new ObservableList(DataServices.Nlogs); + _synchronizedView = _logItemList.CreateView(v => v); LogItemListView = _synchronizedView.ToNotifyCollectionChanged(); + + // 订阅日志变更事件 + _dataCenterService.NlogChanged += OnNlogChanged; + } + + /// + /// 处理日志变更事件 + /// + private void OnNlogChanged(object sender, NlogChangedEventArgs e) + { + // 在UI线程上更新日志 + App.Current.Dispatcher.BeginInvoke(new Action(() => + { + switch (e.ChangeType) + { + case DataChangeType.Added: + var newLogItem = new NlogItemViewModel(new Nlog + { + Id = e.Nlog.Id, + LogTime = e.Nlog.LogTime, + Level = e.Nlog.Level, + ThreadId = e.Nlog.ThreadId, + ThreadName = e.Nlog.ThreadName, + Callsite = e.Nlog.Callsite, + CallsiteLineNumber = e.Nlog.CallsiteLineNumber, + Message = e.Nlog.Message, + Logger = e.Nlog.Logger, + Exception = e.Nlog.Exception, + CallerFilePath = e.Nlog.CallerFilePath, + CallerLineNumber = e.Nlog.CallerLineNumber, + CallerMember = e.Nlog.CallerMember + }); + _logItemList.Add(newLogItem); + break; + case DataChangeType.Updated: + var existingLog = _logItemList.FirstOrDefault(l => l.Id == e.Nlog.Id); + if (existingLog != null) + { + existingLog = new NlogItemViewModel(new Nlog + { + Id = e.Nlog.Id, + LogTime = e.Nlog.LogTime, + Level = e.Nlog.Level, + ThreadId = e.Nlog.ThreadId, + ThreadName = e.Nlog.ThreadName, + Callsite = e.Nlog.Callsite, + CallsiteLineNumber = e.Nlog.CallsiteLineNumber, + Message = e.Nlog.Message, + Logger = e.Nlog.Logger, + Exception = e.Nlog.Exception, + CallerFilePath = e.Nlog.CallerFilePath, + CallerLineNumber = e.Nlog.CallerLineNumber, + CallerMember = e.Nlog.CallerMember + }); + } + break; + case DataChangeType.Deleted: + var logToRemove = _logItemList.FirstOrDefault(l => l.Id == e.Nlog.Id); + if (logToRemove != null) + { + _logItemList.Remove(logToRemove); + } + break; + } + })); } private bool FilterLogs(NlogItemViewModel item) @@ -165,4 +238,11 @@ partial class LogHistoryViewModel : ViewModelBase _notificationService.ShowError($"加载日志时发生错误: {ex.Message}", ex); } } + + public void Dispose() + { + // 取消订阅事件 + _dataCenterService.NlogChanged -= OnNlogChanged; + + } } \ No newline at end of file