using System.Collections.ObjectModel; using System.Windows; using System.Windows.Threading; using YY.Admin.Core; using YY.Admin.Core.Util; using YY.Admin.Event; using Prism.Events; using YY.Admin.Module; using YY.Admin.Services; using YY.Admin.Services.Service.Menu; namespace YY.Admin.ViewModels.Control { /// /// 菜单选项 /// public class MenuItem : TabSource { public MenuItem? Parent { get; set; } // 父节点引用 public ObservableCollection Children { get; set; } = []; private bool _isExpanded; public bool IsExpanded { get => _isExpanded; set => SetProperty(ref _isExpanded, value); } } public class MenuTreeViewModel : BaseViewModel { private static readonly Dictionary RouteToViewMap = new(StringComparer.OrdinalIgnoreCase) { // 已实现页面:仪表盘 ["DashboardView"] = "DashboardView", ["/dashboard"] = "DashboardView", ["/dashboard/index"] = "DashboardView", ["/home/index"] = "DashboardView", ["dashboard"] = "DashboardView", ["home"] = "DashboardView", // 已实现页面:账号管理 ["UserManagementView"] = "UserManagementView", ["/system/user"] = "UserManagementView", ["/system/user/index"] = "UserManagementView", ["sysUser"] = "UserManagementView", // 已实现页面:数据字典 ["DataDictionaryManagementView"] = "DataDictionaryManagementView", ["/system/dict"] = "DataDictionaryManagementView", ["/system/dict/index"] = "DataDictionaryManagementView", ["/platform/dict"] = "DataDictionaryManagementView", ["sysDict"] = "DataDictionaryManagementView", // 已实现页面:分类字典 ["CategoryDictionaryManagementView"] = "CategoryDictionaryManagementView", ["/system/category"] = "CategoryDictionaryManagementView", ["/system/category/index"] = "CategoryDictionaryManagementView", ["/platform/category"] = "CategoryDictionaryManagementView", ["sysCategory"] = "CategoryDictionaryManagementView", // 已实现页面:角色管理 ["RoleManagementView"] = "RoleManagementView", ["/system/role"] = "RoleManagementView", ["/system/role/index"] = "RoleManagementView", ["sysRole"] = "RoleManagementView", // 已实现页面:租户管理 ["TenantManagementView"] = "TenantManagementView", ["/system/tenant"] = "TenantManagementView", ["/system/tenant/index"] = "TenantManagementView", ["/platform/tenant"] = "TenantManagementView", ["sysTenant"] = "TenantManagementView", // 已实现页面:菜单管理 ["MenuManagementView"] = "MenuManagementView", ["/platform/menu"] = "MenuManagementView", ["/system/menu/index"] = "MenuManagementView", ["sysMenu"] = "MenuManagementView", // 已实现页面:登录设置 ["LoginSettingsView"] = "LoginSettingsView", ["/system/loginSettings"] = "LoginSettingsView", ["/system/login-setting"] = "LoginSettingsView", ["/system/login-settings"] = "LoginSettingsView", ["loginSettings"] = "LoginSettingsView", ["登录设置"] = "LoginSettingsView", ["登陆设置"] = "LoginSettingsView", // 已实现页面:车辆管理 ["VehicleListView"] = "VehicleListView", ["/xslmes/mesXslVehicle"] = "VehicleListView", ["/xslmes/vehicle"] = "VehicleListView", ["mesXslVehicle"] = "VehicleListView", // 已实现页面:客户管理 ["CustomerListView"] = "CustomerListView", ["/xslmes/mesXslCustomer"] = "CustomerListView", ["/xslmes/customer"] = "CustomerListView", ["mesXslCustomer"] = "CustomerListView", // 已实现页面:供应商管理 ["SupplierListView"] = "SupplierListView", ["/xslmes/mesXslSupplier"] = "SupplierListView", ["/xslmes/supplier"] = "SupplierListView", ["mesXslSupplier"] = "SupplierListView", // 已实现页面:磅单记录管理 ["WeightRecordListView"] = "WeightRecordListView", ["/xslmes/mesXslWeightRecord"] = "WeightRecordListView", ["mesXslWeightRecord"] = "WeightRecordListView", // 已实现页面:地磅称重操作 ["WeightRecordOperationView"] = "WeightRecordOperationView", ["/xslmes/weightRecordOperation"] = "WeightRecordOperationView", ["weightRecordOperation"] = "WeightRecordOperationView", // 已实现页面:密炼物料信息 ["MixerMaterialListView"] = "MixerMaterialListView", ["/xslmes/mesMixerMaterial"] = "MixerMaterialListView", ["mesMixerMaterial"] = "MixerMaterialListView", // 已实现页面:原料入场记录 ["RawMaterialEntryListView"] = "RawMaterialEntryListView", ["/xslmes/mesXslRawMaterialEntry"] = "RawMaterialEntryListView", ["mesXslRawMaterialEntry"] = "RawMaterialEntryListView" }; private MenuItem? _selectedMenuItem; public MenuItem? SelectedMenuItem { get => _selectedMenuItem; set => SetProperty(ref _selectedMenuItem, value); } private readonly ISysMenuService _sysMenuService; public ObservableCollection MenuItems { get; } = []; public DelegateCommand NavigateCommand { get; } private SubscriptionToken? tabSelectedToken; private SubscriptionToken? tabClosedToken; private SubscriptionToken? _menuStructureToken; public MenuTreeViewModel( ISysMenuService sysMenuService, IContainerExtension _container, IRegionManager regionManager) : base(_container, regionManager) { _sysMenuService = sysMenuService; // 异步初始化菜单 LoadMenuAsync(); NavigateCommand = new DelegateCommand(OpenOrActivateTab); // 订阅事件 tabSelectedToken = _eventAggregator.GetEvent().Subscribe(OnTabSelected); tabClosedToken = _eventAggregator.GetEvent().Subscribe(OnTabClosed); _menuStructureToken = _eventAggregator.GetEvent() .Subscribe(async _ => await ReloadMenusAsync(), ThreadOption.UIThread); } /// /// 菜单数据变更后刷新左侧树(不重复执行默认页签导航) /// private async Task ReloadMenusAsync() { try { var menuTree = await _sysMenuService.GetLoginMenuTree(); MenuItems.Clear(); ConvertMenuTreeToViewModel(menuTree); } catch (Exception ex) { _logger.Error($"菜单重新加载失败: {ex.Message}", ex); } } public void OpenOrActivateTab(MenuItem menuItem) { _logger.Debug($"菜单点击触发: Name={menuItem?.Name}, ViewName={menuItem?.ViewName}, ChildrenCount={menuItem?.Children?.Count ?? 0}"); // 发布事件 _eventAggregator.GetEvent().Publish(menuItem); } private void OnTabSelected(TabItemModel tab) { if (tab.TabSource is MenuItem menuItem) { // 取消上一个选中菜单选中状态 SelectedMenuItem?.IsSelected = false; SelectedMenuItem = menuItem; // 设置菜单选中 SelectedMenuItem.IsSelected = true; // 展开父节点 ToggleParents(SelectedMenuItem, true); } } private void OnTabClosed(TabItemModel tab) { if (tab.TabSource is MenuItem menuItem) { // 折叠父节点 ToggleParents(menuItem, false); // 取消菜单选中 menuItem?.IsSelected = false; } } /// /// 异步加载菜单【后续使用缓存以及权限管理】 /// private async void LoadMenuAsync() { try { // 异步获取菜单数据 var menuTree = await _sysMenuService.GetLoginMenuTree(); // 转换菜单数据 ConvertMenuTreeToViewModel(menuTree); // 默认导航 ScheduleDefaultNavigation(); } catch (Exception ex) { _logger.Error($"菜单加载失败: {ex.Message}", ex); // 显示错误菜单项 MenuItems.Add(new MenuItem { Name = "菜单加载失败", Icon = "ErrorOutline", ViewName = "ErrorView", Children = { new MenuItem { Name = "点击重试", Icon = "Refresh" } } }); } } /// /// 将服务层菜单树转换为视图模型 /// private void ConvertMenuTreeToViewModel(List menuTree) { MenuItems.Clear(); // 过滤并排序菜单项:只包含目录和菜单类型,排除按钮类型,并按排序号排序 var rootMenus = menuTree .Where(m => m.Type == MenuTypeEnum.Dir || m.Type == MenuTypeEnum.Menu) .Where(m => m.Status == StatusEnum.Enable) // 只包含启用状态的菜单 .Where(m => !(m?.IsHide ?? false)) // 排除隐藏的菜单 .OrderBy(m => m.OrderNo) .ToList(); // 递归转换菜单项 void ConvertMenu(MenuOutput source, MenuItem target, MenuItem? parent = null) { target.Name = source?.Title ?? source?.Name; target.Icon = ConvertHtmlEntityToUnicode(source?.Icon ?? ""); target.ViewName = ResolveViewName(source); // 将菜单路由映射到已注册的WPF视图 target.Parent = parent; // 设置父节点 // 添加子菜单(如果有) if (source.Children != null && source.Children.Any()) { // 过滤并排序子菜单 var childMenus = source.Children .Where(c => c.Type == MenuTypeEnum.Dir || c.Type == MenuTypeEnum.Menu) // 子菜单支持目录和菜单两种类型 .Where(c => c.Status == StatusEnum.Enable) .Where(c => !(c?.IsHide ?? false)) .OrderBy(c => c.OrderNo) .ToList(); foreach (var child in childMenus) { var childItem = new MenuItem(); ConvertMenu(child, childItem, target); target.Children.Add(childItem); } } } // 处理每个根菜单 foreach (var root in rootMenus) { var rootItem = new MenuItem(); ConvertMenu(root, rootItem); // 如果根菜单是目录但没有子菜单,则不显示 if (root.Type == MenuTypeEnum.Dir && !rootItem.Children.Any()) continue; MenuItems.Add(rootItem); } } /// /// 解析菜单对应的视图名称 /// private string? ResolveViewName(MenuOutput? menu) { if (menu == null) return null; // 目录节点不参与内容区导航 if (menu.Type == MenuTypeEnum.Dir) return null; // 依次尝试 Path / Component / Name / Title,兼容不同来源的菜单数据 var candidates = new[] { menu.Path, menu.Component, menu.Name, menu.Title }; foreach (var candidate in candidates) { if (string.IsNullOrWhiteSpace(candidate)) continue; if (RouteToViewMap.TryGetValue(candidate.Trim(), out var viewName)) { _logger.Debug($"菜单路由命中: Title={menu.Title}, Candidate={candidate}, View={viewName}"); return viewName; } } // 保留原始Path,若未注册将统一展示NotFoundView _logger.Warning($"菜单路由未命中映射: Title={menu.Title}, Path={menu.Path}, Component={menu.Component}, Name={menu.Name}"); return menu.Path; } private string ConvertHtmlEntityToUnicode(string htmlEntity) { if (string.IsNullOrEmpty(htmlEntity)) return "\ue7c6"; // 默认图标 return StringUtil.ConvertHtmlEntityToUnicode(htmlEntity); } /// /// 安排默认导航 /// private void ScheduleDefaultNavigation() { Application.Current.Dispatcher.BeginInvoke(new Action(() => { try { // 默认菜单 var defaultMenuItem = GetFirstLeaf(MenuItems.FirstOrDefault()); if (defaultMenuItem != null) { // Tab不允许关闭 defaultMenuItem.IsClosable = false; // 导航菜单 OpenOrActivateTab(defaultMenuItem); } } catch (Exception ex) { _logger.Error($"默认导航失败: {ex.Message}", ex); } }), DispatcherPriority.ApplicationIdle); } private MenuItem? GetFirstLeaf(MenuItem? menu) { if (menu == null) return null; if (menu.Children == null || menu.Children.Count == 0) return menu; // 自己就是叶子节点 // 递归向下找第一个叶子 return GetFirstLeaf(menu.Children.FirstOrDefault()); } public void ToggleParents(MenuItem? item, bool IsExpanded) { if (item == null) { return; } var parent = item.Parent; while (parent != null) { parent.IsExpanded = IsExpanded; // 展开父节点 if (!IsExpanded) { parent.IsSelected = IsExpanded; } parent = parent.Parent; } } /// /// 清空资源 /// protected override void CleanUp() { if (tabSelectedToken != null) { _eventAggregator .GetEvent() .Unsubscribe(tabSelectedToken); tabSelectedToken = null; } if (tabClosedToken != null) { _eventAggregator .GetEvent() .Unsubscribe(tabClosedToken); tabClosedToken = null; } if (_menuStructureToken != null) { _eventAggregator.GetEvent().Unsubscribe(_menuStructureToken); _menuStructureToken = null; } } /// /// 根据ViewName同步选中对应的菜单项 /// //private MenuItem? GetSelectedMenuItem(string? viewName) //{ // if (string.IsNullOrEmpty(viewName)) // return null; // // 递归查找匹配的菜单项 // return FindMenuItemByViewName(MenuItems, viewName); //} /// /// 递归查找匹配ViewName的菜单项 /// //private MenuItem? FindMenuItemByViewName(ObservableCollection menuItems, string viewName) //{ // foreach (var menuItem in menuItems) // { // // 如果当前菜单项匹配 // if (menuItem.ViewName == viewName) // return menuItem; // // 递归查找子菜单 // if (menuItem.Children?.Count > 0) // { // var found = FindMenuItemByViewName(menuItem.Children, viewName); // if (found != null) // return found; // } // } // return null; //} } }