using Microsoft.Extensions.Logging; using AuroraDesk.Core.Interfaces; using AuroraDesk.Presentation.ViewModels.Base; using AuroraDesk.Core.Entities; using ReactiveUI; using System; using System.Collections.ObjectModel; using System.Linq; using System.Reactive; using System.Reactive.Disposables; using System.Reactive.Linq; namespace AuroraDesk.Presentation.ViewModels; /// /// 主窗口的 ViewModel,使用完整的 ReactiveUI 路由系统 /// 重构后遵循整洁架构原则: /// - 职责分离:导航状态管理委托给 INavigationStateService /// - 标签页管理委托给 ITabManagementService /// - 使用字典缓存优化查找性能(O(1) 时间复杂度) /// - 减少不必要的状态重置循环 /// public class MainWindowViewModel : ReactiveObject { private string _title = "My Avalonia App - ReactiveUI 路由"; private string _headerTitle = "系统管理平台"; private string _headerSubtitle = "欢迎使用现代化管理界面"; private ObservableCollection _navigationItems = new(); private NavigationItem? _selectedNavigationItem; private readonly ILogger? _logger; private readonly INavigationService _navigationService; private readonly INavigationStateService _navigationStateService; private readonly ITabManagementService _tabManagementService; private readonly IScreen _screen; // 使用 CompositeDisposable 管理订阅,确保资源释放 private readonly System.Reactive.Disposables.CompositeDisposable _disposables = new(); public string Title { get => _title; set => this.RaiseAndSetIfChanged(ref _title, value); } public string HeaderTitle { get => _headerTitle; set => this.RaiseAndSetIfChanged(ref _headerTitle, value); } public string HeaderSubtitle { get => _headerSubtitle; set => this.RaiseAndSetIfChanged(ref _headerSubtitle, value); } public ObservableCollection NavigationItems { get => _navigationItems; set => this.RaiseAndSetIfChanged(ref _navigationItems, value); } /// /// 标签页集合(委托给 TabManagementService) /// public ObservableCollection Tabs => _tabManagementService.Tabs; public NavigationItem? SelectedNavigationItem { get => _selectedNavigationItem; set => this.RaiseAndSetIfChanged(ref _selectedNavigationItem, value); } /// /// 当前选中的标签页(委托给 TabManagementService) /// public TabItem? SelectedTab { get => _tabManagementService.SelectedTab; set => _tabManagementService.SelectedTab = value; } /// /// 路由状态(暴露给 UI 使用) /// public RoutingState Router => _screen.Router; // 响应式命令 public ReactiveCommand NavigateCommand { get; } public ReactiveCommand CloseTabCommand { get; } public ReactiveCommand SelectTabCommand { get; } // 关闭确认对话框 Interaction public Interaction CloseConfirmInteraction { get; } /// /// 请求关闭确认 /// public async System.Threading.Tasks.Task RequestCloseConfirmAsync() { var viewModel = new CloseConfirmViewModel(); var result = await CloseConfirmInteraction.Handle(viewModel); _logger?.LogInformation("用户选择: {Result}", result ? "确认关闭" : "取消关闭"); return result; } public MainWindowViewModel( IScreen screen, INavigationService navigationService, INavigationStateService navigationStateService, ITabManagementService tabManagementService, ILogger? logger = null) { _screen = screen; _navigationService = navigationService; _navigationStateService = navigationStateService; _tabManagementService = tabManagementService; _logger = logger; _logger?.LogInformation("MainWindowViewModel 已创建(重构版本 - 整洁架构)"); // 从导航服务获取导航项 NavigationItems = _navigationService.GetNavigationItems(_screen); // 初始化导航状态服务(建立字典缓存,优化查找性能) _navigationStateService.InitializeStateMap(NavigationItems); // 创建导航命令 NavigateCommand = ReactiveCommand.Create(NavigateToPage); // 创建关闭标签页命令(委托给 TabManagementService,并在关闭后同步导航) CloseTabCommand = ReactiveCommand.Create(CloseTab); // 创建选择标签页命令(委托给 TabManagementService) SelectTabCommand = ReactiveCommand.Create(tab => SelectTab(tab)); // 创建关闭确认对话框 Interaction CloseConfirmInteraction = new Interaction(); // 监听导航项选择变化 _disposables.Add( this.WhenAnyValue(x => x.SelectedNavigationItem) .Where(item => item != null) .Subscribe(item => _logger?.LogInformation("导航到: {Title}", item!.Title))); // 监听标签页选择变化(通过服务的事件流) _disposables.Add( _tabManagementService.SelectedTabChanged .Where(tab => tab != null) .Subscribe(tab => { this.RaisePropertyChanged(nameof(SelectedTab)); _logger?.LogInformation("切换到标签页: {Title}", tab!.Title); })); // 监听 Router.CurrentViewModel 变化,同步标签页 _disposables.Add( _screen.Router .CurrentViewModel .Subscribe(viewModel => OnRouterViewModelChanged(viewModel))); // 初始化导航:自动导航到仪表板页面 _disposables.Add( Observable.Start(() => { var dashboardItem = NavigationItems.FirstOrDefault(item => item.Id == "dashboard"); if (dashboardItem != null && dashboardItem.ViewModel != null) { // 使用状态服务选中导航项 _navigationStateService.SelectItem(dashboardItem); SelectedNavigationItem = dashboardItem; // 导航到仪表板 _navigationService.NavigateToPage(dashboardItem); _logger?.LogInformation("自动导航到仪表板页面"); } }, RxApp.MainThreadScheduler) .Subscribe()); } // 以下状态管理方法已移除,现在委托给 INavigationStateService // - ResetAllNavigationItemsState() -> _navigationStateService.ResetAllStates() // - ResetAllNavigationItemsSelectionOnly() -> _navigationStateService.ResetSelectionOnly() // - ResetOtherNavigationItemsState() -> _navigationStateService.ResetOtherStates() // 这样可以分离职责,并且使用字典缓存优化性能(O(1) vs O(n*m)) /// /// 导航到指定页面 /// 重构后:使用 INavigationStateService 管理状态,减少耦合 /// private void NavigateToPage(NavigationItem navigationItem) { if (navigationItem == null) return; // 使用状态服务查找父项(使用字典缓存,O(1) 时间复杂度) var parentItem = _navigationStateService.FindParentItem(navigationItem); bool isChildItem = parentItem != null; if (isChildItem) { // 子级菜单项:处理导航 if (navigationItem.ViewModel == null) return; // 如果已经选中,直接返回,避免重复操作 if (navigationItem.IsSelected && SelectedNavigationItem == navigationItem) return; // 使用状态服务重置选中状态(保持展开状态) _navigationStateService.ResetSelectionOnly(); // 确保父项保持展开状态 if (parentItem != null && !parentItem.IsExpanded) { parentItem.IsExpanded = true; } // 使用状态服务选中当前子项 _navigationStateService.SelectItem(navigationItem); SelectedNavigationItem = navigationItem; // 使用导航服务进行导航 _navigationService.NavigateToPage(navigationItem); _logger?.LogInformation("导航到子页面: {Title}", navigationItem.Title); } else if (navigationItem.HasChildren) { // 父级菜单项:处理展开/收起逻辑 if (navigationItem.IsExpanded) { // 如果已经展开,则收起 _navigationStateService.ToggleExpand(navigationItem); _navigationStateService.ResetAllStates(); SelectedNavigationItem = null; _logger?.LogInformation("收起导航项: {Title}", navigationItem.Title); } else { // 如果未展开,则展开并选中第一个子项 _navigationStateService.ResetOtherStates(navigationItem); _navigationStateService.ToggleExpand(navigationItem); // 选中第一个子项并导航 if (navigationItem.Children.Count > 0) { var firstChild = navigationItem.Children[0]; if (firstChild.ViewModel != null) { _navigationStateService.SelectItem(firstChild); SelectedNavigationItem = firstChild; _navigationService.NavigateToPage(firstChild); } } _logger?.LogInformation("展开导航项: {Title}", navigationItem.Title); } } else { // 无子项的父级导航项,直接选中并导航 // 如果已经选中,直接返回,避免重复操作 if (navigationItem.IsSelected && SelectedNavigationItem == navigationItem) return; // 优化:检查是否已经有对应的 Tab 存在,如果有就直接切换到那个 Tab // 使用字典查找,时间复杂度 O(1) var existingTab = _tabManagementService.FindTabById(navigationItem.Id); if (existingTab != null) { // 直接切换到已存在的 Tab,避免重新创建和导航 _navigationStateService.ResetAllStates(); _navigationStateService.SelectItem(navigationItem); SelectedNavigationItem = navigationItem; SelectTab(existingTab); _logger?.LogInformation("切换到已存在的标签页: {Title}", navigationItem.Title); return; } // 使用状态服务重置所有状态并选中当前项 _navigationStateService.ResetAllStates(); _navigationStateService.SelectItem(navigationItem); SelectedNavigationItem = navigationItem; // 使用导航服务进行导航 if (navigationItem.ViewModel != null) { _navigationService.NavigateToPage(navigationItem); } _logger?.LogInformation("导航到页面: {Title}", navigationItem.Title); } } /// /// Router.CurrentViewModel 变化时的处理 /// 重构后:委托给 TabManagementService 管理标签页 /// private void OnRouterViewModelChanged(IRoutableViewModel? viewModel) { if (viewModel == null) return; // 使用状态服务查找导航项(使用字典缓存,O(1) 时间复杂度) var navigationItem = _navigationStateService.FindNavigationItemByViewModel(viewModel); if (navigationItem == null) return; // 委托给 TabManagementService 创建或更新标签页 _tabManagementService.CreateOrUpdateTab(navigationItem, viewModel); _logger?.LogInformation("Router 导航到: {Title}", navigationItem.Title); } /// /// 选择标签页 /// 重构后:委托给 TabManagementService,并同步 Router /// 优化:如果当前已经是目标 ViewModel,跳过导航避免重复渲染 /// private void SelectTab(TabItem tab) { if (tab == null) return; // 如果当前 Router 已经显示的是这个 ViewModel,跳过导航避免重复渲染 if (tab.ViewModel != null && _screen.Router.CurrentViewModel == tab.ViewModel) { // 只更新标签页状态,不触发 Router 导航 _tabManagementService.SelectTab(tab); _logger?.LogDebug("标签页已处于当前视图,跳过导航: {Title}", tab.Title); return; } // 委托给 TabManagementService 选择标签页 _tabManagementService.SelectTab(tab); // 使用 Router 导航到对应的 ViewModel if (tab.ViewModel != null) { _screen.Router.Navigate.Execute(tab.ViewModel); } _logger?.LogInformation("选择标签页: {Title}", tab.Title); } /// /// 关闭标签页 /// 重构后:委托给 TabManagementService,并在关闭后同步 Router 导航 /// private void CloseTab(TabItem tab) { if (tab == null || !tab.CanClose) return; var wasSelected = tab.IsSelected; var tabIndex = _tabManagementService.Tabs.IndexOf(tab); // 委托给 TabManagementService 关闭标签页 _tabManagementService.CloseTab(tab); // 如果关闭的是当前选中的标签页,且还有其他标签页,需要导航到新选中的标签页 if (wasSelected && _tabManagementService.Tabs.Count > 0) { var newSelectedTab = _tabManagementService.SelectedTab; if (newSelectedTab?.ViewModel != null) { _screen.Router.Navigate.Execute(newSelectedTab.ViewModel); } } // 如果没有标签页了,可能需要导航到默认页面(如仪表板) else if (_tabManagementService.Tabs.Count == 0) { var dashboardItem = NavigationItems.FirstOrDefault(item => item.Id == "dashboard"); if (dashboardItem?.ViewModel != null) { _screen.Router.Navigate.Execute(dashboardItem.ViewModel); } } _logger?.LogInformation("关闭标签页: {Title}", tab.Title); } /// /// 释放资源 /// public void Dispose() { _disposables?.Dispose(); if (_tabManagementService is IDisposable disposable) { disposable.Dispose(); } } }