diff --git a/DMS.Application/DTOs/Events/MenuChangedEventArgs.cs b/DMS.Application/DTOs/Events/MenuChangedEventArgs.cs
new file mode 100644
index 0000000..17aa32c
--- /dev/null
+++ b/DMS.Application/DTOs/Events/MenuChangedEventArgs.cs
@@ -0,0 +1,44 @@
+using System;
+
+namespace DMS.Application.DTOs.Events
+{
+ ///
+ /// 菜单变更事件参数
+ ///
+ public class MenuChangedEventArgs : System.EventArgs
+ {
+ ///
+ /// 变更类型
+ ///
+ public DataChangeType ChangeType { get; }
+
+ ///
+ /// 菜单DTO
+ ///
+ public MenuBeanDto Menu { get; }
+
+ ///
+ /// 父级菜单DTO
+ ///
+ public MenuBeanDto ParentMenu { get; }
+
+ ///
+ /// 变更时间
+ ///
+ public DateTime ChangeTime { get; }
+
+ ///
+ /// 构造函数
+ ///
+ /// 变更类型
+ /// 菜单DTO
+ /// 父级菜单DTO
+ public MenuChangedEventArgs(DataChangeType changeType, MenuBeanDto menu, MenuBeanDto parentMenu)
+ {
+ ChangeType = changeType;
+ Menu = menu;
+ ParentMenu = parentMenu;
+ ChangeTime = DateTime.Now;
+ }
+ }
+}
\ No newline at end of file
diff --git a/DMS.Application/DTOs/MenuBeanDto.cs b/DMS.Application/DTOs/MenuBeanDto.cs
index 9e08565..25c4d10 100644
--- a/DMS.Application/DTOs/MenuBeanDto.cs
+++ b/DMS.Application/DTOs/MenuBeanDto.cs
@@ -3,27 +3,62 @@ using DMS.Core.Enums;
namespace DMS.Application.DTOs;
///
-/// 用于在UI上显示菜单项的DTO。
+/// 菜单数据传输对象(DTO)
+/// 用于在应用程序层和表示层之间传输菜单数据,特别是在UI上显示菜单项时使用。
///
public class MenuBeanDto
{
+ ///
+ /// 菜单项的唯一标识符
+ ///
public int Id { get; set; }
- public int? ParentId { get; set; }
+
+ ///
+ /// 父级菜单项的ID,用于构建层级菜单结构
+ /// 如果为0表示为顶级菜单项
+ ///
+ public int ParentId { get; set; }
+
+ ///
+ /// 菜单项显示的标题文本
+ ///
public string Header { get; set; }
+
+ ///
+ /// 菜单项显示的图标资源路径或标识符
+ ///
public string Icon { get; set; }
+
///
/// 菜单的类型,例如菜单关联的是设备,还是变量表,或者是MQTT
+ /// 用于区分不同类型的菜单项,决定点击菜单项时的行为
///
public MenuType MenuType { get; set; }
///
/// 菜单关联的数据ID,例如设备Id,变量表Id
+ /// 根据MenuType的不同,此ID可以指向不同的数据实体
///
public int TargetId { get; set; }
+
///
- /// 菜单关联的数据ID,例如设备Id,变量表Id
+ /// 目标视图的键值,用于导航到特定的视图页面
///
public string TargetViewKey { get; set; }
+
+ ///
+ /// 导航参数,传递给目标视图的额外参数信息
+ ///
public string NavigationParameter { get; set; }
+
+ ///
+ /// 菜单项在同级菜单中的显示顺序
+ /// 数值越小显示越靠前
+ ///
public int DisplayOrder { get; set; }
+
+ ///
+ /// 子菜单项集合,用于构建层级菜单结构
+ ///
+ public List Children { get; set; } = new List();
}
\ No newline at end of file
diff --git a/DMS.Application/Interfaces/IDataCenterService.cs b/DMS.Application/Interfaces/IDataCenterService.cs
index 860d75d..f039f1a 100644
--- a/DMS.Application/Interfaces/IDataCenterService.cs
+++ b/DMS.Application/Interfaces/IDataCenterService.cs
@@ -13,34 +13,6 @@ namespace DMS.Application.Interfaces;
///
public interface IDataCenterService
{
- #region 事件定义
-
- ///
- /// 当数据加载完成时触发
- ///
- event EventHandler DataLoadCompleted;
-
- ///
- /// 当设备数据发生变化时触发
- ///
- event EventHandler DeviceChanged;
-
- ///
- /// 当变量表数据发生变化时触发
- ///
- event EventHandler VariableTableChanged;
-
- ///
- /// 当变量数据发生变化时触发
- ///
- event EventHandler VariableChanged;
-
- ///
- /// 当数据发生任何变化时触发
- ///
- event EventHandler DataChanged;
-
- #endregion
#region 设备管理
///
@@ -138,91 +110,59 @@ public interface IDataCenterService
#endregion
- #region 变量管理
+ #region 菜单管理
///
- /// 异步根据ID获取变量DTO。
+ /// 异步获取所有菜单DTO列表。
///
- Task GetVariableByIdAsync(int id);
+ Task> GetAllMenusAsync();
///
- /// 异步获取所有变量DTO列表。
+ /// 异步根据ID获取菜单DTO。
///
- Task> GetAllVariablesAsync();
+ Task GetMenuByIdAsync(int id);
///
- /// 异步创建一个新变量(事务性操作)。
+ /// 异步创建一个新菜单。
///
- Task CreateVariableAsync(VariableDto variableDto);
+ Task CreateMenuAsync(MenuBeanDto menuDto);
///
- /// 异步更新一个已存在的变量(事务性操作)。
+ /// 异步更新一个已存在的菜单。
///
- Task UpdateVariableAsync(VariableDto variableDto);
+ Task UpdateMenuAsync(MenuBeanDto menuDto);
///
- /// 异步批量更新变量(事务性操作)。
+ /// 异步删除一个菜单。
///
- Task UpdateVariablesAsync(List variableDtos);
+ Task DeleteMenuAsync(int id);
///
- /// 异步删除一个变量(事务性操作)。
+ /// 在内存中添加菜单
///
- Task DeleteVariableAsync(int id);
+ void AddMenuToMemory(MenuBeanDto menuDto);
///
- /// 异步批量删除变量(事务性操作)。
+ /// 在内存中更新菜单
///
- Task DeleteVariablesAsync(List ids);
+ void UpdateMenuInMemory(MenuBeanDto menuDto);
///
- /// 异步批量导入变量。
+ /// 在内存中删除菜单
///
- Task BatchImportVariablesAsync(List variables);
+ void RemoveMenuFromMemory(int menuId);
///
- /// 检测一组变量是否已存在。
+ /// 获取根菜单列表
///
- /// 要检查的变量列表。
- /// 返回输入列表中已存在的变量。
- Task> FindExistingVariablesAsync(IEnumerable variablesToCheck);
+ List GetRootMenus();
///
- /// 检测单个变量是否已存在。
+ /// 根据父级ID获取子菜单列表
///
- /// 要检查的变量。
- /// 如果变量已存在则返回该变量,否则返回null。
- Task FindExistingVariableAsync(VariableDto variableToCheck);
-
- ///
- /// 在内存中添加变量
- ///
- void AddVariableToMemory(VariableDto variableDto);
-
- ///
- /// 在内存中更新变量
- ///
- void UpdateVariableInMemory(VariableDto variableDto);
-
- ///
- /// 在内存中删除变量
- ///
- void RemoveVariableFromMemory(int variableId);
-
- ///
- /// 批量在内存中添加变量
- ///
- void AddVariablesToMemory(List variables);
-
- ///
- /// 批量在内存中更新变量
- ///
- void UpdateVariablesInMemory(List variables);
-
- ///
- /// 批量在内存中删除变量
- ///
- void RemoveVariablesFromMemory(List variableIds);
+ /// 父级菜单ID
+ /// 子菜单列表
+ List GetChildMenus(int parentId);
#endregion
@@ -243,6 +183,11 @@ public interface IDataCenterService
///
ConcurrentDictionary Variables { get; }
+ ///
+ /// 获取所有菜单的安全字典。
+ ///
+ ConcurrentDictionary Menus { get; }
+
#endregion
#region 数据加载和初始化
@@ -267,5 +212,44 @@ public interface IDataCenterService
///
Task> LoadAllVariablesAsync();
+ ///
+ /// 异步加载所有菜单数据。
+ ///
+ Task> LoadAllMenusAsync();
+
+ #endregion
+
+ #region 事件定义
+
+ ///
+ /// 当数据加载完成时触发
+ ///
+ event EventHandler DataLoadCompleted;
+
+ ///
+ /// 当设备数据发生变化时触发
+ ///
+ event EventHandler DeviceChanged;
+
+ ///
+ /// 当变量表数据发生变化时触发
+ ///
+ event EventHandler VariableTableChanged;
+
+ ///
+ /// 当变量数据发生变化时触发
+ ///
+ event EventHandler VariableChanged;
+
+ ///
+ /// 当菜单数据发生变化时触发
+ ///
+ event EventHandler MenuChanged;
+
+ ///
+ /// 当数据发生任何变化时触发
+ ///
+ event EventHandler DataChanged;
+
#endregion
}
\ No newline at end of file
diff --git a/DMS.Application/Services/DataCenterService.cs b/DMS.Application/Services/DataCenterService.cs
index 8129f75..72df6cc 100644
--- a/DMS.Application/Services/DataCenterService.cs
+++ b/DMS.Application/Services/DataCenterService.cs
@@ -14,11 +14,38 @@ using System.Linq;
namespace DMS.Application.Services;
///
-/// 数据中心服务,负责管理所有的数据,包括设备、变量表和变量。
+/// 数据中心服务,负责管理所有的数据,包括设备、变量表、变量和菜单。
/// 实现 接口。
///
public class DataCenterService : IDataCenterService
{
+ private readonly IRepositoryManager _repositoryManager;
+ private readonly IMapper _mapper;
+ private readonly IDeviceAppService _deviceAppService;
+ private readonly IVariableTableAppService _variableTableAppService;
+ private readonly IVariableAppService _variableAppService;
+ private readonly IMenuService _menuService;
+
+ ///
+ /// 安全字典,用于存储所有设备数据
+ ///
+ public ConcurrentDictionary Devices { get; } = new();
+
+ ///
+ /// 安全字典,用于存储所有变量表数据
+ ///
+ public ConcurrentDictionary VariableTables { get; } = new();
+
+ ///
+ /// 安全字典,用于存储所有变量数据
+ ///
+ public ConcurrentDictionary Variables { get; } = new();
+
+ ///
+ /// 安全字典,用于存储所有菜单数据
+ ///
+ public ConcurrentDictionary Menus { get; } = new();
+
#region 事件定义
///
@@ -41,32 +68,17 @@ public class DataCenterService : IDataCenterService
///
public event EventHandler VariableChanged;
+ ///
+ /// 当菜单数据发生变化时触发
+ ///
+ public event EventHandler MenuChanged;
+
///
/// 当数据发生任何变化时触发
///
public event EventHandler DataChanged;
#endregion
- private readonly IRepositoryManager _repositoryManager;
- private readonly IMapper _mapper;
- private readonly IDeviceAppService _deviceAppService;
- private readonly IVariableTableAppService _variableTableAppService;
- private readonly IVariableAppService _variableAppService;
-
- ///
- /// 安全字典,用于存储所有设备数据
- ///
- public ConcurrentDictionary Devices { get; } = new();
-
- ///
- /// 安全字典,用于存储所有变量表数据
- ///
- public ConcurrentDictionary VariableTables { get; } = new();
-
- ///
- /// 安全字典,用于存储所有变量数据
- ///
- public ConcurrentDictionary Variables { get; } = new();
///
/// 构造函数,通过依赖注入获取仓储管理器和相关服务实例。
@@ -76,18 +88,21 @@ public class DataCenterService : IDataCenterService
/// 设备应用服务实例。
/// 变量表应用服务实例。
/// 变量应用服务实例。
+ /// 菜单服务实例。
public DataCenterService(
IRepositoryManager repositoryManager,
IMapper mapper,
IDeviceAppService deviceAppService,
IVariableTableAppService variableTableAppService,
- IVariableAppService variableAppService)
+ IVariableAppService variableAppService,
+ IMenuService menuService)
{
_repositoryManager = repositoryManager;
_mapper = mapper;
_deviceAppService = deviceAppService;
_variableTableAppService = variableTableAppService;
_variableAppService = variableAppService;
+ _menuService = menuService;
}
#region 设备管理
@@ -224,6 +239,7 @@ public class DataCenterService : IDataCenterService
if (Devices.TryGetValue(variableTableDto.DeviceId, out var device))
{
deviceDto = device;
+ variableTableDto.Device = deviceDto;
}
if (VariableTables.TryAdd(variableTableDto.Id, variableTableDto))
@@ -275,214 +291,117 @@ public class DataCenterService : IDataCenterService
#endregion
- #region 变量管理
+ #region 菜单管理
///
- /// 异步根据ID获取变量DTO。
+ /// 异步获取所有菜单DTO列表。
///
- public async Task GetVariableByIdAsync(int id)
+ public async Task> GetAllMenusAsync()
{
- return await _variableAppService.GetVariableByIdAsync(id);
+ return await _menuService.GetAllMenusAsync();
}
///
- /// 异步获取所有变量DTO列表。
+ /// 异步根据ID获取菜单DTO。
///
- public async Task> GetAllVariablesAsync()
+ public async Task GetMenuByIdAsync(int id)
{
- return await _variableAppService.GetAllVariablesAsync();
+ return await _menuService.GetMenuByIdAsync(id);
}
///
- /// 异步创建一个新变量(事务性操作)。
+ /// 异步创建一个新菜单。
///
- public async Task CreateVariableAsync(VariableDto variableDto)
+ public async Task CreateMenuAsync(MenuBeanDto menuDto)
{
- return await _variableAppService.CreateVariableAsync(variableDto);
+ return await _menuService.CreateMenuAsync(menuDto);
}
///
- /// 异步更新一个已存在的变量(事务性操作)。
+ /// 异步更新一个已存在的菜单。
///
- public async Task UpdateVariableAsync(VariableDto variableDto)
+ public async Task UpdateMenuAsync(MenuBeanDto menuDto)
{
- return await _variableAppService.UpdateVariableAsync(variableDto);
+ await _menuService.UpdateMenuAsync(menuDto);
}
///
- /// 异步批量更新变量(事务性操作)。
+ /// 异步删除一个菜单。
///
- public async Task UpdateVariablesAsync(List variableDtos)
+ public async Task DeleteMenuAsync(int id)
{
- return await _variableAppService.UpdateVariablesAsync(variableDtos);
+ await _menuService.DeleteMenuAsync(id);
}
///
- /// 异步删除一个变量(事务性操作)。
+ /// 在内存中添加菜单
///
- public async Task DeleteVariableAsync(int id)
+ public void AddMenuToMemory(MenuBeanDto menuDto)
{
- return await _variableAppService.DeleteVariableAsync(id);
- }
-
- ///
- /// 异步批量删除变量(事务性操作)。
- ///
- public async Task DeleteVariablesAsync(List ids)
- {
- return await _variableAppService.DeleteVariablesAsync(ids);
- }
-
- ///
- /// 异步批量导入变量。
- ///
- public async Task BatchImportVariablesAsync(List variables)
- {
- return await _variableAppService.BatchImportVariablesAsync(variables);
- }
-
- ///
- /// 检测一组变量是否已存在。
- ///
- public async Task> FindExistingVariablesAsync(IEnumerable variablesToCheck)
- {
- return await _variableAppService.FindExistingVariablesAsync(variablesToCheck);
- }
-
- ///
- /// 检测单个变量是否已存在。
- ///
- public async Task FindExistingVariableAsync(VariableDto variableToCheck)
- {
- return await _variableAppService.FindExistingVariableAsync(variableToCheck);
- }
-
- ///
- /// 在内存中添加变量
- ///
- public void AddVariableToMemory(VariableDto variableDto)
- {
- VariableTableDto variableTableDto = null;
- if (VariableTables.TryGetValue(variableDto.VariableTableId, out var variableTable))
+ if (Menus.TryAdd(menuDto.Id, menuDto))
{
- variableTableDto = variableTable;
- }
-
- if (Variables.TryAdd(variableDto.Id, variableDto))
- {
- OnVariableChanged(new VariableChangedEventArgs(
- DataChangeType.Added,
- variableDto,
- variableTableDto));
- }
- }
-
- ///
- /// 在内存中更新变量
- ///
- public void UpdateVariableInMemory(VariableDto variableDto)
- {
- VariableTableDto variableTableDto = null;
- if (VariableTables.TryGetValue(variableDto.VariableTableId, out var variableTable))
- {
- variableTableDto = variableTable;
- }
-
- Variables.AddOrUpdate(variableDto.Id, variableDto, (key, oldValue) => variableDto);
- OnVariableChanged(new VariableChangedEventArgs(
- DataChangeType.Updated,
- variableDto,
- variableTableDto));
- }
-
- ///
- /// 在内存中删除变量
- ///
- public void RemoveVariableFromMemory(int variableId)
- {
- if (Variables.TryRemove(variableId, out var variableDto))
- {
- VariableTableDto variableTableDto = null;
- if (variableDto != null && VariableTables.TryGetValue(variableDto.VariableTableId, out var variableTable))
+ MenuBeanDto parentMenu = null;
+ if (menuDto.ParentId > 0 && Menus.TryGetValue(menuDto.ParentId, out var parent))
{
- variableTableDto = variableTable;
+ parentMenu = parent;
+ parent.Children.Add(menuDto);
+
+
}
- OnVariableChanged(new VariableChangedEventArgs(
- DataChangeType.Deleted,
- variableDto,
- variableTableDto));
+ OnMenuChanged(new MenuChangedEventArgs(DataChangeType.Added, menuDto, parentMenu));
}
}
///
- /// 批量在内存中添加变量
+ /// 在内存中更新菜单
///
- public void AddVariablesToMemory(List variables)
+ public void UpdateMenuInMemory(MenuBeanDto menuDto)
{
- foreach (var variable in variables)
- {
- VariableTableDto variableTableDto = null;
- if (VariableTables.TryGetValue(variable.VariableTableId, out var variableTable))
- {
- variableTableDto = variableTable;
- }
+ Menus.AddOrUpdate(menuDto.Id, menuDto, (key, oldValue) => menuDto);
- if (Variables.TryAdd(variable.Id, variable))
- {
- OnVariableChanged(new VariableChangedEventArgs(
- DataChangeType.Added,
- variable,
- variableTableDto));
- }
+ MenuBeanDto parentMenu = null;
+ if (menuDto.ParentId > 0 && Menus.TryGetValue(menuDto.ParentId, out var parent))
+ {
+ parentMenu = parent;
}
- OnDataChanged(new DataChangedEventArgs(DataChangeType.BatchOperation));
+
+ OnMenuChanged(new MenuChangedEventArgs(DataChangeType.Updated, menuDto, parentMenu));
}
///
- /// 批量在内存中更新变量
+ /// 在内存中删除菜单
///
- public void UpdateVariablesInMemory(List variables)
+ public void RemoveMenuFromMemory(int menuId)
{
- foreach (var variable in variables)
+ if (Menus.TryRemove(menuId, out var menuDto))
{
- VariableTableDto variableTableDto = null;
- if (VariableTables.TryGetValue(variable.VariableTableId, out var variableTable))
+ MenuBeanDto parentMenu = null;
+ if (menuDto.ParentId > 0 && Menus.TryGetValue(menuDto.ParentId, out var parent))
{
- variableTableDto = variableTable;
+ parentMenu = parent;
}
- Variables.AddOrUpdate(variable.Id, variable, (key, oldValue) => variable);
- OnVariableChanged(new VariableChangedEventArgs(
- DataChangeType.Updated,
- variable,
- variableTableDto));
+ OnMenuChanged(new MenuChangedEventArgs(DataChangeType.Deleted, menuDto, parentMenu));
}
- OnDataChanged(new DataChangedEventArgs(DataChangeType.BatchOperation));
}
///
- /// 批量在内存中删除变量
+ /// 获取根菜单列表
///
- public void RemoveVariablesFromMemory(List variableIds)
+ public List GetRootMenus()
{
- foreach (var variableId in variableIds)
- {
- if (Variables.TryRemove(variableId, out var variableDto))
- {
- VariableTableDto variableTableDto = null;
- if (variableDto != null && VariableTables.TryGetValue(variableDto.VariableTableId, out var variableTable))
- {
- variableTableDto = variableTable;
- }
+ return Menus.Values.Where(m => m.ParentId == 0).ToList();
+ }
- OnVariableChanged(new VariableChangedEventArgs(
- DataChangeType.Deleted,
- variableDto,
- variableTableDto));
- }
- }
- OnDataChanged(new DataChangedEventArgs(DataChangeType.BatchOperation));
+ ///
+ /// 根据父级ID获取子菜单列表
+ ///
+ /// 父级菜单ID
+ /// 子菜单列表
+ public List GetChildMenus(int parentId)
+ {
+ return Menus.Values.Where(m => m.ParentId == parentId).ToList();
}
#endregion
@@ -529,6 +448,16 @@ public class DataCenterService : IDataCenterService
OnDataChanged(new DataChangedEventArgs(e.ChangeType));
}
+ ///
+ /// 触发菜单变更事件
+ ///
+ /// 事件参数
+ protected virtual void OnMenuChanged(MenuChangedEventArgs e)
+ {
+ MenuChanged?.Invoke(this, e);
+ OnDataChanged(new DataChangedEventArgs(e.ChangeType));
+ }
+
///
/// 触发数据变更事件
///
@@ -553,6 +482,7 @@ public class DataCenterService : IDataCenterService
Devices.Clear();
VariableTables.Clear();
Variables.Clear();
+ Menus.Clear();
// 加载所有设备
var devices = await _repositoryManager.Devices.GetAllAsync();
@@ -566,6 +496,10 @@ public class DataCenterService : IDataCenterService
var variables = await _repositoryManager.Variables.GetAllAsync();
var variableDtos = _mapper.Map>(variables);
+ // 加载所有菜单
+ var menus = await _repositoryManager.Menus.GetAllAsync();
+ var menuDtos = _mapper.Map>(menus);
+
// 建立设备与变量表的关联
foreach (var deviceDto in deviceDtos)
{
@@ -594,6 +528,12 @@ public class DataCenterService : IDataCenterService
Variables.TryAdd(variableDto.Id, variableDto);
}
+ // 将菜单添加到安全字典
+ foreach (var menuDto in menuDtos)
+ {
+ Menus.TryAdd(menuDto.Id, menuDto);
+ }
+
// 触发数据加载完成事件
OnDataLoadCompleted(new DataLoadCompletedEventArgs(
deviceDtos,
@@ -614,6 +554,23 @@ public class DataCenterService : IDataCenterService
}
}
+ ///
+ /// 异步加载所有菜单数据。
+ ///
+ public async Task> LoadAllMenusAsync()
+ {
+ try
+ {
+ // 获取所有菜单
+ var menus = await _repositoryManager.Menus.GetAllAsync();
+ return _mapper.Map>(menus);
+ }
+ catch (Exception ex)
+ {
+ throw new ApplicationException($"加载所有菜单数据时发生错误,错误信息:{ex.Message}", ex);
+ }
+ }
+
///
/// 异步加载所有设备及其关联数据。
///
diff --git a/DMS.Core/Models/MenuBean.cs b/DMS.Core/Models/MenuBean.cs
index f61b85c..25bd3b3 100644
--- a/DMS.Core/Models/MenuBean.cs
+++ b/DMS.Core/Models/MenuBean.cs
@@ -3,27 +3,58 @@ using DMS.Core.Enums;
namespace DMS.Core.Models;
///
-/// 领域模型:代表一个菜单项。
+/// 菜单项领域模型
+/// 代表系统中的一个菜单项,包含菜单的基本信息和导航相关信息
+/// 作为领域模型,它在核心业务逻辑中使用,与数据库实体对应
///
public class MenuBean
{
+ ///
+ /// 菜单项的唯一标识符
+ ///
public int Id { get; set; }
+
+ ///
+ /// 父级菜单项的ID,用于构建层级菜单结构
+ /// 如果为null表示为顶级菜单项
+ ///
public int? ParentId { get; set; }
+
+ ///
+ /// 菜单项显示的标题文本
+ ///
public string Header { get; set; }
+
+ ///
+ /// 菜单项显示的图标资源路径或标识符
+ ///
public string Icon { get; set; }
+
///
/// 菜单的类型,例如菜单关联的是设备,还是变量表,或者是MQTT
+ /// 用于区分不同类型的菜单项,决定点击菜单项时的行为
///
public MenuType MenuType { get; set; }
///
/// 菜单关联的数据ID,例如设备Id,变量表Id
+ /// 根据MenuType的不同,此ID可以指向不同的数据实体
///
public int TargetId { get; set; }
+
///
- /// 菜单关联的数据ID,例如设备Id,变量表Id
+ /// 目标视图的键值,用于导航到特定的视图页面
///
public string TargetViewKey { get; set; }
+
+ ///
+ /// 导航参数,传递给目标视图的额外参数信息
+ ///
public string NavigationParameter { get; set; }
+
+ ///
+ /// 菜单项在同级菜单中的显示顺序
+ /// 数值越小显示越靠前
+ ///
public int DisplayOrder { get; set; }
}
\ No newline at end of file
diff --git a/DMS.Infrastructure.UnitTests/DataCenterServiceTests.cs b/DMS.Infrastructure.UnitTests/DataCenterServiceTests.cs
deleted file mode 100644
index 0c29b6d..0000000
--- a/DMS.Infrastructure.UnitTests/DataCenterServiceTests.cs
+++ /dev/null
@@ -1,173 +0,0 @@
-using DMS.Application.DTOs;
-using DMS.Application.DTOs.Events;
-using DMS.Application.Interfaces;
-using DMS.Application.Services;
-using DMS.Core.Interfaces;
-using Moq;
-using System;
-using System.Collections.Concurrent;
-using Xunit;
-
-namespace DMS.Infrastructure.UnitTests
-{
- public class DataCenterServiceTests
- {
- [Fact]
- public void DataCenterService_Should_Implement_All_Required_Methods()
- {
- // Arrange
- var mockRepositoryManager = new Mock();
- var mockDeviceAppService = new Mock();
- var mockVariableTableAppService = new Mock();
- var mockVariableAppService = new Mock();
-
- // Act
- var dataCenterService = new DataCenterService(
- mockRepositoryManager.Object,
- null, // 在测试中不会使用到mapper
- mockDeviceAppService.Object,
- mockVariableTableAppService.Object,
- mockVariableAppService.Object);
-
- // Assert - Verify that service implements the interface
- Assert.IsAssignableFrom(dataCenterService);
- }
-
- [Fact]
- public void DataCenterService_Should_Have_ConcurrentDictionary_Properties()
- {
- // Arrange
- var mockRepositoryManager = new Mock();
- var mockDeviceAppService = new Mock();
- var mockVariableTableAppService = new Mock();
- var mockVariableAppService = new Mock();
-
- // Act
- var dataCenterService = new DataCenterService(
- mockRepositoryManager.Object,
- null, // 在测试中不会使用到mapper
- mockDeviceAppService.Object,
- mockVariableTableAppService.Object,
- mockVariableAppService.Object);
-
- // Assert
- Assert.NotNull(dataCenterService.Devices);
- Assert.NotNull(dataCenterService.VariableTables);
- Assert.NotNull(dataCenterService.Variables);
- Assert.IsType>(dataCenterService.Devices);
- Assert.IsType>(dataCenterService.VariableTables);
- Assert.IsType>(dataCenterService.Variables);
- }
-
- [Fact]
- public void DataCenterService_AddDeviceToMemory_Should_Add_Device_To_Dictionary()
- {
- // Arrange
- var mockRepositoryManager = new Mock();
- var mockMapper = new Mock();
- var mockDeviceAppService = new Mock();
- var mockVariableTableAppService = new Mock();
- var mockVariableAppService = new Mock();
- var dataCenterService = new DataCenterService(
- mockRepositoryManager.Object,
- mockMapper.Object,
- mockDeviceAppService.Object,
- mockVariableTableAppService.Object,
- mockVariableAppService.Object);
-
- var deviceDto = new DeviceDto { Id = 1, Name = "Test Device" };
-
- // Act
- dataCenterService.AddDeviceToMemory(deviceDto);
-
- // Assert
- Assert.True(dataCenterService.Devices.ContainsKey(1));
- Assert.Equal(deviceDto, dataCenterService.Devices[1]);
- }
-
- [Fact]
- public void DataCenterService_UpdateDeviceInMemory_Should_Update_Device_In_Dictionary()
- {
- // Arrange
- var mockRepositoryManager = new Mock();
- var mockMapper = new Mock();
- var mockDeviceAppService = new Mock();
- var mockVariableTableAppService = new Mock();
- var mockVariableAppService = new Mock();
- var dataCenterService = new DataCenterService(
- mockRepositoryManager.Object,
- mockMapper.Object,
- mockDeviceAppService.Object,
- mockVariableTableAppService.Object,
- mockVariableAppService.Object);
-
- var deviceDto = new DeviceDto { Id = 1, Name = "Test Device" };
- var updatedDeviceDto = new DeviceDto { Id = 1, Name = "Updated Device" };
-
- // Act
- dataCenterService.AddDeviceToMemory(deviceDto);
- dataCenterService.UpdateDeviceInMemory(updatedDeviceDto);
-
- // Assert
- Assert.True(dataCenterService.Devices.ContainsKey(1));
- Assert.Equal(updatedDeviceDto, dataCenterService.Devices[1]);
- Assert.Equal("Updated Device", dataCenterService.Devices[1].Name);
- }
-
- [Fact]
- public void DataCenterService_RemoveDeviceFromMemory_Should_Remove_Device_From_Dictionary()
- {
- // Arrange
- var mockRepositoryManager = new Mock();
- var mockMapper = new Mock();
- var mockDeviceAppService = new Mock();
- var mockVariableTableAppService = new Mock();
- var mockVariableAppService = new Mock();
- var dataCenterService = new DataCenterService(
- mockRepositoryManager.Object,
- mockMapper.Object,
- mockDeviceAppService.Object,
- mockVariableTableAppService.Object,
- mockVariableAppService.Object);
-
- var deviceDto = new DeviceDto { Id = 1, Name = "Test Device" };
-
- // Act
- dataCenterService.AddDeviceToMemory(deviceDto);
- dataCenterService.RemoveDeviceFromMemory(1);
-
- // Assert
- Assert.False(dataCenterService.Devices.ContainsKey(1));
- }
-
- [Fact]
- public void DataCenterService_Should_Raise_DeviceChanged_Event_On_Add()
- {
- // Arrange
- var mockRepositoryManager = new Mock();
- var mockMapper = new Mock();
- var mockDeviceAppService = new Mock();
- var mockVariableTableAppService = new Mock();
- var mockVariableAppService = new Mock();
- var dataCenterService = new DataCenterService(
- mockRepositoryManager.Object,
- mockMapper.Object,
- mockDeviceAppService.Object,
- mockVariableTableAppService.Object,
- mockVariableAppService.Object);
-
- DeviceChangedEventArgs eventArgs = null;
- dataCenterService.DeviceChanged += (sender, args) => eventArgs = args;
-
- var deviceDto = new DeviceDto { Id = 1, Name = "Test Device" };
-
- // Act
- dataCenterService.AddDeviceToMemory(deviceDto);
-
- // Assert
- Assert.NotNull(eventArgs);
- Assert.Equal(DataChangeType.Added, eventArgs.ChangeType);
- Assert.Equal(deviceDto, eventArgs.Device);
- }
- }
-}
\ No newline at end of file
diff --git a/DMS.Infrastructure.UnitTests/Services/OpcUaServiceTest.cs b/DMS.Infrastructure.UnitTests/Services/OpcUaServiceTest.cs
deleted file mode 100644
index 603b779..0000000
--- a/DMS.Infrastructure.UnitTests/Services/OpcUaServiceTest.cs
+++ /dev/null
@@ -1,159 +0,0 @@
-using DMS.Infrastructure.Interfaces.Services;
-using DMS.Infrastructure.Services;
-using Opc.Ua;
-using System;
-using System.Threading.Tasks;
-using Xunit;
-
-namespace DMS.Infrastructure.UnitTests.Services
-{
- public class OpcUaServiceTest
- {
- [Fact]
- public async Task TestOpcUaService_CreateSession_WithValidUrl_ShouldCreateSession()
- {
- // Arrange
- var service = new OpcUaService();
- var opcUaServerUrl = "opc.tcp://localhost:4840"; // 示例URL,实际测试时需要真实的OPC UA服务器
-
- // Act & Assert
- // 注意:这个测试需要真实的OPC UA服务器才能通过
- // 在实际测试环境中,您需要启动一个OPC UA服务器
- try
- {
- await service.CreateSession(opcUaServerUrl);
- // 如果没有异常,则认为会话创建成功
- Assert.True(true);
- }
- catch (Exception ex)
- {
- // 在没有真实服务器的情况下,我们期望出现连接异常
- Assert.NotNull(ex);
- }
- }
-
- [Fact]
- public async Task TestOpcUaService_CreateSession_WithNullUrl_ShouldThrowException()
- {
- // Arrange
- var service = new OpcUaService();
- string opcUaServerUrl = null;
-
- // Act & Assert
- await Assert.ThrowsAsync(async () =>
- {
- await service.CreateSession(opcUaServerUrl);
- });
- }
-
- [Fact]
- public async Task TestOpcUaService_CreateSession_WithEmptyUrl_ShouldThrowException()
- {
- // Arrange
- var service = new OpcUaService();
- var opcUaServerUrl = "";
-
- // Act & Assert
- await Assert.ThrowsAsync(async () =>
- {
- await service.CreateSession(opcUaServerUrl);
- });
- }
-
- [Fact]
- public void TestOpcUaService_IsConnected_WithoutSession_ShouldReturnFalse()
- {
- // Arrange
- var service = new OpcUaService();
-
- // Act
- var isConnected = service.IsConnected();
-
- // Assert
- Assert.False(isConnected);
- }
-
- [Fact]
- public async Task TestOpcUaService_ConnectAsync_WithoutSession_ShouldThrowException()
- {
- // Arrange
- var service = new OpcUaService();
-
- // Act & Assert
- await Assert.ThrowsAsync(async () =>
- {
- await service.ConnectAsync("opc.tcp://localhost:4840");
- });
- }
-
- [Fact]
- public void TestOpcUaService_Connect_WithoutSession_ShouldThrowException()
- {
- // Arrange
- var service = new OpcUaService();
-
- // Act & Assert
- Assert.Throws(() =>
- {
- service.Connect();
- });
- }
-
- [Fact]
- public void TestOpcUaService_AddSubscription_WithoutSession_ShouldThrowException()
- {
- // Arrange
- var service = new OpcUaService();
- var subscriptionName = "TestSubscription";
-
- // Act & Assert
- Assert.Throws(() =>
- {
- service.AddSubscription(subscriptionName);
- });
- }
-
- [Fact]
- public void TestOpcUaService_BrowseNodes_WithoutSession_ShouldThrowException()
- {
- // Arrange
- var service = new OpcUaService();
- var nodeId = NodeId.Null;
-
- // Act & Assert
- Assert.Throws(() =>
- {
- service.BrowseNodes(nodeId);
- });
- }
-
- [Fact]
- public void TestOpcUaService_ReadValue_WithoutSession_ShouldThrowException()
- {
- // Arrange
- var service = new OpcUaService();
- var nodeId = NodeId.Null;
-
- // Act & Assert
- Assert.Throws(() =>
- {
- service.ReadValue(nodeId);
- });
- }
-
- [Fact]
- public void TestOpcUaService_WriteValue_WithoutSession_ShouldThrowException()
- {
- // Arrange
- var service = new OpcUaService();
- var nodeId = NodeId.Null;
- var value = "test";
-
- // Act & Assert
- Assert.Throws(() =>
- {
- service.WriteValue(nodeId, value);
- });
- }
- }
-}
\ No newline at end of file
diff --git a/DMS.WPF/App.xaml.cs b/DMS.WPF/App.xaml.cs
index 1bceb16..d4b0e37 100644
--- a/DMS.WPF/App.xaml.cs
+++ b/DMS.WPF/App.xaml.cs
@@ -167,9 +167,9 @@ public partial class App : System.Windows.Application
services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
+ services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
- services.AddSingleton();
services.AddSingleton();
//注册WPF中的服务
services.AddSingleton();
diff --git a/DMS.WPF/ViewModels/Items/MenuItemViewModel.cs b/DMS.WPF/ViewModels/Items/MenuItemViewModel.cs
index 42ee7e6..e673088 100644
--- a/DMS.WPF/ViewModels/Items/MenuItemViewModel.cs
+++ b/DMS.WPF/ViewModels/Items/MenuItemViewModel.cs
@@ -8,34 +8,74 @@ using DMS.WPF.Services;
namespace DMS.WPF.ViewModels.Items;
+///
+/// 菜单项视图模型
+/// 用于在WPF界面中绑定和显示菜单项数据,实现MVVM模式
+/// 继承自ObservableObject以支持属性更改通知
+///
public partial class MenuItemViewModel : ObservableObject
{
+ ///
+ /// 菜单项的唯一标识符
+ ///
public int Id { get; set; }
+ ///
+ /// 父级菜单项的ID,用于构建层级菜单结构
+ /// 如果为null表示为顶级菜单项
+ ///
[ObservableProperty]
private int? _parentId;
+ ///
+ /// 菜单项显示的标题文本
+ ///
[ObservableProperty]
private string _header;
+ ///
+ /// 菜单项显示的图标资源路径或标识符
+ ///
[ObservableProperty]
private string _icon;
+ ///
+ /// 菜单的类型,例如菜单关联的是设备,还是变量表,或者是MQTT
+ /// 用于区分不同类型的菜单项,决定点击菜单项时的行为
+ ///
[ObservableProperty]
private MenuType _menuType;
+ ///
+ /// 菜单关联的数据ID,例如设备Id,变量表Id
+ /// 根据MenuType的不同,此ID可以指向不同的数据实体
+ ///
[ObservableProperty]
private int _targetId;
+
+ ///
+ /// 目标视图的键值,用于导航到特定的视图页面
+ ///
[ObservableProperty]
private string _targetViewKey;
+ ///
+ /// 导航参数,传递给目标视图的额外参数信息
+ ///
[ObservableProperty]
private string _navigationParameter;
+ ///
+ /// 菜单项在同级菜单中的显示顺序
+ /// 数值越小显示越靠前
+ ///
[ObservableProperty]
private int _displayOrder;
- [ObservableProperty]
- private ObservableCollection _children=new ();
-
-}
+ ///
+ /// 子菜单项集合,用于构建层级菜单结构
+ /// 使用ObservableCollection以支持动态添加和删除子项并自动更新UI
+ ///
+ [ObservableProperty]
+ private ObservableCollection _children = new();
+}
\ No newline at end of file