You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
197 lines
6.0 KiB
197 lines
6.0 KiB
using AuroraDesk.Core.Interfaces;
|
|
using AuroraDesk.Core.Entities;
|
|
using Microsoft.Extensions.Logging;
|
|
using ReactiveUI;
|
|
using System;
|
|
using System.Collections.ObjectModel;
|
|
using System.Linq;
|
|
using System.Reactive.Linq;
|
|
using System.Reactive.Subjects;
|
|
|
|
namespace AuroraDesk.Infrastructure.Services;
|
|
|
|
/// <summary>
|
|
/// 标签页管理服务实现
|
|
/// 分离标签页管理职责,使用字典缓存优化查找性能
|
|
/// </summary>
|
|
public class TabManagementService : ITabManagementService, IDisposable
|
|
{
|
|
private readonly ILogger<TabManagementService>? _logger;
|
|
private readonly ObservableCollection<TabItem> _tabs = new();
|
|
private readonly BehaviorSubject<TabItem?> _selectedTabSubject;
|
|
|
|
// 使用字典缓存加速查找(O(1) 时间复杂度)
|
|
private readonly System.Collections.Generic.Dictionary<string, TabItem> _tabByIdMap = new();
|
|
private readonly System.Collections.Generic.Dictionary<IRoutableViewModel, TabItem> _tabByViewModelMap = new();
|
|
|
|
private TabItem? _selectedTab;
|
|
|
|
public TabManagementService(ILogger<TabManagementService>? logger = null)
|
|
{
|
|
_logger = logger;
|
|
_selectedTabSubject = new BehaviorSubject<TabItem?>(null);
|
|
SelectedTabChanged = _selectedTabSubject.AsObservable();
|
|
}
|
|
|
|
public ObservableCollection<TabItem> Tabs => _tabs;
|
|
|
|
public TabItem? SelectedTab
|
|
{
|
|
get => _selectedTab;
|
|
set
|
|
{
|
|
if (_selectedTab == value) return;
|
|
|
|
// 更新旧标签页的选中状态
|
|
if (_selectedTab != null)
|
|
{
|
|
_selectedTab.IsSelected = false;
|
|
}
|
|
|
|
_selectedTab = value;
|
|
|
|
// 更新新标签页的选中状态
|
|
if (_selectedTab != null)
|
|
{
|
|
_selectedTab.IsSelected = true;
|
|
}
|
|
|
|
_selectedTabSubject.OnNext(_selectedTab);
|
|
_logger?.LogDebug("已切换到标签页: {Title}", _selectedTab?.Title ?? "null");
|
|
}
|
|
}
|
|
|
|
public System.IObservable<TabItem?> SelectedTabChanged { get; }
|
|
|
|
public void CreateOrUpdateTab(NavigationItem navigationItem, IRoutableViewModel viewModel)
|
|
{
|
|
if (navigationItem == null || viewModel == null) return;
|
|
|
|
// 使用字典查找,时间复杂度 O(1)
|
|
var existingTab = _tabByIdMap.TryGetValue(navigationItem.Id, out var tab) ? tab : null;
|
|
|
|
if (existingTab != null)
|
|
{
|
|
// 更新现有标签页
|
|
if (existingTab.ViewModel != viewModel)
|
|
{
|
|
// 移除旧的 ViewModel 映射
|
|
if (existingTab.ViewModel != null)
|
|
{
|
|
_tabByViewModelMap.Remove(existingTab.ViewModel);
|
|
}
|
|
|
|
existingTab.ViewModel = viewModel;
|
|
|
|
// 添加新的 ViewModel 映射
|
|
_tabByViewModelMap[viewModel] = existingTab;
|
|
}
|
|
|
|
// 选中这个标签页
|
|
SelectTab(existingTab);
|
|
}
|
|
else
|
|
{
|
|
// 创建新标签页
|
|
var newTab = new TabItem
|
|
{
|
|
Id = navigationItem.Id,
|
|
Title = navigationItem.Title,
|
|
IconType = navigationItem.IconType,
|
|
ViewModel = viewModel,
|
|
IsSelected = false,
|
|
CanClose = navigationItem.Id != "dashboard"
|
|
};
|
|
|
|
_tabs.Add(newTab);
|
|
|
|
// 更新缓存
|
|
_tabByIdMap[navigationItem.Id] = newTab;
|
|
_tabByViewModelMap[viewModel] = newTab;
|
|
|
|
// 重置所有标签页的选中状态,然后选中新标签页
|
|
foreach (var t in _tabs)
|
|
{
|
|
if (t.IsSelected && t != newTab)
|
|
{
|
|
t.IsSelected = false;
|
|
}
|
|
}
|
|
|
|
newTab.IsSelected = true;
|
|
SelectedTab = newTab;
|
|
|
|
_logger?.LogInformation("已创建新标签页: {Title}", newTab.Title);
|
|
}
|
|
}
|
|
|
|
public void SelectTab(TabItem tab)
|
|
{
|
|
if (tab == null) return;
|
|
|
|
// 如果已经是选中状态,直接返回
|
|
if (tab.IsSelected && SelectedTab == tab) return;
|
|
|
|
// 只更新需要改变的标签页状态(优化性能)
|
|
if (SelectedTab != null && SelectedTab != tab)
|
|
{
|
|
SelectedTab.IsSelected = false;
|
|
}
|
|
|
|
SelectedTab = tab;
|
|
|
|
_logger?.LogDebug("已选择标签页: {Title}", tab.Title);
|
|
}
|
|
|
|
public void CloseTab(TabItem tab)
|
|
{
|
|
if (tab == null || !tab.CanClose) return;
|
|
|
|
var tabId = tab.Id;
|
|
var tabIndex = _tabs.IndexOf(tab);
|
|
|
|
// 移除缓存
|
|
_tabByIdMap.Remove(tabId);
|
|
if (tab.ViewModel != null)
|
|
{
|
|
_tabByViewModelMap.Remove(tab.ViewModel);
|
|
}
|
|
|
|
// 从集合中移除
|
|
_tabs.Remove(tab);
|
|
|
|
// 如果关闭的是当前选中的标签页,需要选择另一个标签页
|
|
if (tab.IsSelected && _tabs.Count > 0)
|
|
{
|
|
var newSelectedIndex = Math.Min(tabIndex, _tabs.Count - 1);
|
|
var newSelectedTab = _tabs[newSelectedIndex];
|
|
SelectedTab = newSelectedTab;
|
|
}
|
|
else if (_tabs.Count == 0)
|
|
{
|
|
SelectedTab = null;
|
|
}
|
|
|
|
_logger?.LogInformation("已关闭标签页: {Title}", tab.Title);
|
|
}
|
|
|
|
public TabItem? FindTabByViewModel(IRoutableViewModel viewModel)
|
|
{
|
|
// 使用字典查找,时间复杂度 O(1)
|
|
return _tabByViewModelMap.TryGetValue(viewModel, out var tab) ? tab : null;
|
|
}
|
|
|
|
public TabItem? FindTabById(string tabId)
|
|
{
|
|
// 使用字典查找,时间复杂度 O(1)
|
|
return _tabByIdMap.TryGetValue(tabId, out var tab) ? tab : null;
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
_selectedTabSubject?.Dispose();
|
|
_tabByIdMap.Clear();
|
|
_tabByViewModelMap.Clear();
|
|
}
|
|
}
|
|
|
|
|