692 lines
25 KiB
C#
692 lines
25 KiB
C#
|
|
using Mapster;
|
|||
|
|
using Microsoft.Extensions.Configuration;
|
|||
|
|
using Newtonsoft.Json;
|
|||
|
|
using SqlSugar;
|
|||
|
|
using System.Collections.ObjectModel;
|
|||
|
|
using System.IO;
|
|||
|
|
using System.Net.Http;
|
|||
|
|
using System.Windows;
|
|||
|
|
using System.Windows.Input;
|
|||
|
|
using System.Windows.Media;
|
|||
|
|
using System.Windows.Threading;
|
|||
|
|
using YY.Admin.Core;
|
|||
|
|
using YY.Admin.Core.Const;
|
|||
|
|
using YY.Admin.Core.Model;
|
|||
|
|
using YY.Admin.Core.Session;
|
|||
|
|
using YY.Admin.Core.Util;
|
|||
|
|
using YY.Admin.Event;
|
|||
|
|
using YY.Admin.Module;
|
|||
|
|
using YY.Admin.Services.Service.Auth;
|
|||
|
|
using YY.Admin.Services.Service.Jeecg;
|
|||
|
|
using YY.Admin.Services.Service.Menu;
|
|||
|
|
using YY.Admin.ViewModels.Control;
|
|||
|
|
|
|||
|
|
namespace YY.Admin.ViewModels
|
|||
|
|
{
|
|||
|
|
public class MainWindowViewModel : BaseViewModel
|
|||
|
|
{
|
|||
|
|
private readonly ISysAuthService _authService;
|
|||
|
|
private readonly IDialogService _dialogService;
|
|||
|
|
private readonly IJeecgLoginLogReportService _loginLogReportService;
|
|||
|
|
private readonly IJeecgUserSyncCoordinator _jeecgUserSyncCoordinator;
|
|||
|
|
private readonly IConfiguration _configuration;
|
|||
|
|
private readonly HttpClient _httpClient = new();
|
|||
|
|
private readonly CancellationTokenSource _backendConnectivityCts = new();
|
|||
|
|
private const int ConnectivityCheckIntervalSeconds = 5;
|
|||
|
|
private SysUser? _currentUser;
|
|||
|
|
private bool _isBackendConnected;
|
|||
|
|
|
|||
|
|
#region 标签集合
|
|||
|
|
public ObservableCollection<TabItemModel> OpenTabs { get; } = new ObservableCollection<TabItemModel>();
|
|||
|
|
private CancellationTokenSource? _navigateCts;
|
|||
|
|
private bool _isTabClosing;
|
|||
|
|
private TabItemModel? _selectedTab;
|
|||
|
|
public TabItemModel? SelectedTab
|
|||
|
|
{
|
|||
|
|
get => _selectedTab;
|
|||
|
|
set
|
|||
|
|
{
|
|||
|
|
if (SetProperty(ref _selectedTab, value) && value != null)
|
|||
|
|
{
|
|||
|
|
// 发布事件
|
|||
|
|
_eventAggregator.GetEvent<TabSelectedEvent>().Publish(value);
|
|||
|
|
|
|||
|
|
bool isNotMenuTreeView = _regionManager.Regions[CommonConst.MenuRegion].ActiveViews.Where(it => it.GetType().Name != "MenuTreeView").Any();
|
|||
|
|
if (value.TabSource is MenuItem menuItem && !isNotMenuTreeView)
|
|||
|
|
{
|
|||
|
|
var navItem = NavItems?.Where(it => it.ViewName == "MenuTreeView").FirstOrDefault();
|
|||
|
|
if (navItem != null)
|
|||
|
|
{
|
|||
|
|
if (navItem.AlignBottom)
|
|||
|
|
{
|
|||
|
|
SelectedBottomNavItem = navItem;
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
SelectedTopNavItem = navItem;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
} else if (value.TabSource is NavItem navItem)
|
|||
|
|
{
|
|||
|
|
if (navItem.AlignBottom)
|
|||
|
|
{
|
|||
|
|
SelectedBottomNavItem = navItem;
|
|||
|
|
} else
|
|||
|
|
{
|
|||
|
|
SelectedTopNavItem = navItem;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 取消上一次延迟导航
|
|||
|
|
// 防止拖拽Tab时由于两次导航出现视觉上闪烁问题
|
|||
|
|
// TabA拖动到TabB过程:TabA -> TabB -> TabA
|
|||
|
|
_navigateCts?.Cancel();
|
|||
|
|
_navigateCts = new CancellationTokenSource();
|
|||
|
|
|
|||
|
|
// 延迟 100ms 执行导航(过滤临时选中)
|
|||
|
|
_ = Task.Delay(100, _navigateCts.Token)
|
|||
|
|
.ContinueWith(_ =>
|
|||
|
|
{
|
|||
|
|
Application.Current.Dispatcher.Invoke(() =>
|
|||
|
|
{
|
|||
|
|
_ = NavigateToViewAsync(CommonConst.ContentRegion, value.ViewName, value.TabSource?.NavigationParameter);
|
|||
|
|
});
|
|||
|
|
},
|
|||
|
|
TaskContinuationOptions.OnlyOnRanToCompletion
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
# region 侧边栏
|
|||
|
|
public ObservableCollection<NavItem>? NavItems { get; set; }
|
|||
|
|
public ObservableCollection<NavItem>? TopNavItems { get; set; }
|
|||
|
|
public ObservableCollection<NavItem>? BottomNavItems { get; set; }
|
|||
|
|
|
|||
|
|
private NavItem? _selectedNavItem;
|
|||
|
|
public NavItem? SelectedNavItem
|
|||
|
|
{
|
|||
|
|
get => _selectedNavItem;
|
|||
|
|
set {
|
|||
|
|
if (SetProperty(ref _selectedNavItem, value) && value != null)
|
|||
|
|
{
|
|||
|
|
// 执行命令(如果有)
|
|||
|
|
if (value.Command?.CanExecute(value) == true)
|
|||
|
|
{
|
|||
|
|
value.Command.Execute(value);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private NavItem? _selectedTopNavItem;
|
|||
|
|
public NavItem? SelectedTopNavItem
|
|||
|
|
{
|
|||
|
|
get => _selectedTopNavItem;
|
|||
|
|
set
|
|||
|
|
{
|
|||
|
|
if (SetProperty(ref _selectedTopNavItem, value) && value != null)
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
// 取消底部选中 互斥
|
|||
|
|
SelectedBottomNavItem = null;
|
|||
|
|
|
|||
|
|
SelectedNavItem = value;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private NavItem? _selectedBottomNavItem;
|
|||
|
|
public NavItem? SelectedBottomNavItem
|
|||
|
|
{
|
|||
|
|
get => _selectedBottomNavItem;
|
|||
|
|
set
|
|||
|
|
{
|
|||
|
|
if (SetProperty(ref _selectedBottomNavItem, value) && value != null)
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
// 取消顶部选中 互斥
|
|||
|
|
SelectedTopNavItem = null;
|
|||
|
|
|
|||
|
|
SelectedNavItem = value;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region 系统设置
|
|||
|
|
private bool _isAppSettingsOpen;
|
|||
|
|
public bool IsAppSettingsOpen
|
|||
|
|
{
|
|||
|
|
get => _isAppSettingsOpen;
|
|||
|
|
set => SetProperty(ref _isAppSettingsOpen, value);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private AppSettingsViewModel? _appSettingsViewModel;
|
|||
|
|
public AppSettingsViewModel? AppSettingsViewModel {
|
|||
|
|
get => _appSettingsViewModel;
|
|||
|
|
set => SetProperty(ref _appSettingsViewModel, value);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 系统设置命令
|
|||
|
|
public ICommand ResetAppSettingsCommand { get; }
|
|||
|
|
public ICommand OpenAppSettingsCommand { get; }
|
|||
|
|
public ICommand OpenServerSettingsCommand { get; }
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
private SubscriptionToken? _openOrActivateTabToken;
|
|||
|
|
private SubscriptionToken? _tabClosedToken;
|
|||
|
|
private SubscriptionToken? _refreshTabToken;
|
|||
|
|
private SubscriptionToken? _loginOutToken;
|
|||
|
|
|
|||
|
|
public MainWindowViewModel(
|
|||
|
|
ISysAuthService authService,
|
|||
|
|
IDialogService dialogService,
|
|||
|
|
IJeecgLoginLogReportService loginLogReportService,
|
|||
|
|
IJeecgUserSyncCoordinator jeecgUserSyncCoordinator,
|
|||
|
|
ISysMenuService sysMenuService,
|
|||
|
|
IContainerExtension _container,
|
|||
|
|
IRegionManager regionManager
|
|||
|
|
) : base(_container, regionManager)
|
|||
|
|
{
|
|||
|
|
// 加载系统设置
|
|||
|
|
LoadAppSettings();
|
|||
|
|
|
|||
|
|
_authService = authService;
|
|||
|
|
_dialogService = dialogService;
|
|||
|
|
_loginLogReportService = loginLogReportService;
|
|||
|
|
_jeecgUserSyncCoordinator = jeecgUserSyncCoordinator;
|
|||
|
|
_configuration = _container.Resolve<IConfiguration>();
|
|||
|
|
_loginLogReportService.StartBackgroundSync();
|
|||
|
|
// 订阅用户变更事件
|
|||
|
|
_currentUser = _authService.CurrentUser;
|
|||
|
|
_authService.UserChanged += OnUserChanged;
|
|||
|
|
|
|||
|
|
// 登出命令
|
|||
|
|
LogoutCommand = new DelegateCommand(LogoutAsync);
|
|||
|
|
// 系统设置命令
|
|||
|
|
OpenAppSettingsCommand = new DelegateCommand(OpenAppSettings);
|
|||
|
|
ResetAppSettingsCommand = new DelegateCommand(ResetAppSettings);
|
|||
|
|
OpenServerSettingsCommand = new DelegateCommand(OpenServerSettings);
|
|||
|
|
|
|||
|
|
// 初始化Sidebar数据
|
|||
|
|
InitNavItems();
|
|||
|
|
|
|||
|
|
// 订阅事件
|
|||
|
|
_openOrActivateTabToken = _eventAggregator.GetEvent<TabSourceSelectedEvent>().Subscribe(OnOpenOrActivateTab);
|
|||
|
|
_tabClosedToken = _eventAggregator.GetEvent<TabClosedEvent>().Subscribe(OnTabClosed);
|
|||
|
|
_refreshTabToken = _eventAggregator.GetEvent<TabRefreshEvent>().Subscribe(OnRefreshTab);
|
|||
|
|
_loginOutToken = _eventAggregator.GetEvent<SysUserEvents.LoginOutEvent>().Subscribe(Destroy);
|
|||
|
|
|
|||
|
|
// Jeecg 用户增量同步:定时 + 可选 WebSocket(工控机断网续传)
|
|||
|
|
_jeecgUserSyncCoordinator.Start();
|
|||
|
|
|
|||
|
|
// 主窗口底部连接状态圆点
|
|||
|
|
_ = StartBackendConnectivityLoopAsync(_backendConnectivityCts.Token);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
public SysUser? CurrentUser
|
|||
|
|
{
|
|||
|
|
get => _currentUser;
|
|||
|
|
set => SetProperty(ref _currentUser, value);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 后端连接状态:true=连接中,false=已断开
|
|||
|
|
/// </summary>
|
|||
|
|
public bool IsBackendConnected
|
|||
|
|
{
|
|||
|
|
get => _isBackendConnected;
|
|||
|
|
set
|
|||
|
|
{
|
|||
|
|
if (SetProperty(ref _isBackendConnected, value))
|
|||
|
|
{
|
|||
|
|
RaisePropertyChanged(nameof(BackendConnectionStatusBrush));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public Brush BackendConnectionStatusBrush => IsBackendConnected ? Brushes.LimeGreen : Brushes.Red;
|
|||
|
|
|
|||
|
|
public DelegateCommand LogoutCommand { get; }
|
|||
|
|
|
|||
|
|
private void InitNavItems()
|
|||
|
|
{
|
|||
|
|
NavItems = new ObservableCollection<NavItem>
|
|||
|
|
{
|
|||
|
|
new NavItem {
|
|||
|
|
Icon = "FileTreeOutline",
|
|||
|
|
Name = "功能菜单",
|
|||
|
|
ViewName = "MenuTreeView",
|
|||
|
|
Command = new DelegateCommand<NavItem>(it => _ = NavigateToViewAsync(CommonConst.MenuRegion, it.ViewName))
|
|||
|
|
},
|
|||
|
|
new NavItem {
|
|||
|
|
Icon = "GamepadVariantOutline",
|
|||
|
|
Name = "菜单区域",
|
|||
|
|
Command = new DelegateCommand<NavItem>(it => _ = NavigateToViewAsync(CommonConst.MenuRegion, it.ViewName))
|
|||
|
|
},
|
|||
|
|
new NavItem {
|
|||
|
|
Icon = "FoodAppleOutline",
|
|||
|
|
Name = "Tab区域",
|
|||
|
|
Command = new DelegateCommand<NavItem>(OnOpenOrActivateTab)
|
|||
|
|
},
|
|||
|
|
new NavItem {
|
|||
|
|
Icon = "Server",
|
|||
|
|
Name = "服务器设置",
|
|||
|
|
AlignBottom = true,
|
|||
|
|
IsActive = false,
|
|||
|
|
Command = OpenServerSettingsCommand
|
|||
|
|
},
|
|||
|
|
new NavItem {
|
|||
|
|
Icon = "AccountCircleOutline",
|
|||
|
|
Name = "个人中心",
|
|||
|
|
AlignBottom = true,
|
|||
|
|
Command = new DelegateCommand<NavItem>(OnOpenOrActivateTab)
|
|||
|
|
},
|
|||
|
|
new NavItem {
|
|||
|
|
Icon = StringUtil.ConvertHtmlEntityToUnicode(""),
|
|||
|
|
IconType = IconTypeEnum.AntDesign,
|
|||
|
|
Name = "系统设置",
|
|||
|
|
AlignBottom = true,
|
|||
|
|
IsActive = false,
|
|||
|
|
Command = OpenAppSettingsCommand
|
|||
|
|
},
|
|||
|
|
new NavItem {
|
|||
|
|
Icon = "Power",
|
|||
|
|
Name = "退出登录",
|
|||
|
|
AlignBottom = true,
|
|||
|
|
IsActive = false,
|
|||
|
|
Command = LogoutCommand
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
TopNavItems = new(NavItems.Where(t => !t.AlignBottom));
|
|||
|
|
BottomNavItems = new(NavItems.Where(t => t.AlignBottom));
|
|||
|
|
|
|||
|
|
SelectedTopNavItem = TopNavItems.FirstOrDefault();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void OnUserChanged(object? sender, SysUser? user)
|
|||
|
|
{
|
|||
|
|
CurrentUser = user;
|
|||
|
|
//// 用户变更时刷新菜单
|
|||
|
|
//LoadMenuAsync();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 导航
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="regionName">区域名称</param>
|
|||
|
|
/// <param name="viewName">视图名称</param>
|
|||
|
|
/// <returns></returns>
|
|||
|
|
private async Task NavigateToViewAsync(string regionName, string? viewName, INavigationParameters? parameters = null)
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
if (string.IsNullOrEmpty(regionName))
|
|||
|
|
return;
|
|||
|
|
|
|||
|
|
var tcs = new TaskCompletionSource<bool>();
|
|||
|
|
|
|||
|
|
// 视图为空 或者 视图未在容器中注册
|
|||
|
|
if (string.IsNullOrEmpty(viewName) || !(_container as IContainerProvider).IsRegistered<object>(viewName))
|
|||
|
|
{
|
|||
|
|
_logger.Error($"视图未注册: {viewName}");
|
|||
|
|
_regionManager.RequestNavigate(regionName, "NotFoundView");
|
|||
|
|
tcs.SetResult(false);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
_logger.Debug($"开始后台异步导航到: {viewName}");
|
|||
|
|
|
|||
|
|
|
|||
|
|
// 在UI线程执行导航(但不在属性设置的调用栈中)
|
|||
|
|
await Application.Current.Dispatcher.InvokeAsync(() =>
|
|||
|
|
{
|
|||
|
|
_regionManager.RequestNavigate(regionName, viewName,
|
|||
|
|
result =>
|
|||
|
|
{
|
|||
|
|
if (result.Success)
|
|||
|
|
{
|
|||
|
|
_logger.Debug($"导航成功: {viewName}");
|
|||
|
|
tcs.SetResult(true);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
_logger.Error($"导航失败: {viewName}");
|
|||
|
|
tcs.SetResult(false);
|
|||
|
|
}
|
|||
|
|
}, parameters);
|
|||
|
|
}, DispatcherPriority.Background); // 使用较低优先级
|
|||
|
|
|
|||
|
|
await tcs.Task;
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
_logger.Error($"导航异常: {ex.Message}");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 打开或激活一个标签页(若已打开则激活,否则新建)
|
|||
|
|
/// </summary>
|
|||
|
|
private void OnOpenOrActivateTab(TabSource tabSource)
|
|||
|
|
{
|
|||
|
|
if (tabSource == null) {
|
|||
|
|
_logger.Debug("tabSource为空");
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (tabSource is MenuItem menuItem)
|
|||
|
|
{
|
|||
|
|
// 检查是否是父级菜单(有子菜单)
|
|||
|
|
if (menuItem.Children?.Count > 0)
|
|||
|
|
{
|
|||
|
|
_logger.Debug($"跳过父级菜单: {menuItem.Name},它有 {menuItem.Children.Count} 个子菜单");
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 检查是否有有效的 ViewName
|
|||
|
|
//if (string.IsNullOrEmpty(menuItem.ViewName))
|
|||
|
|
//{
|
|||
|
|
// _logger.Debug($"菜单没有 ViewName: {menuItem.Name}");
|
|||
|
|
// return;
|
|||
|
|
//}
|
|||
|
|
|
|||
|
|
_logger.Debug($"点击菜单: {menuItem.Name}, ViewName: {menuItem.ViewName}");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 检查标签是否已打开
|
|||
|
|
var existingTab = OpenTabs.FirstOrDefault(t => t.TabSource == tabSource);
|
|||
|
|
if (existingTab != null)
|
|||
|
|
{
|
|||
|
|
_logger.Debug($"切换到已存在标签: {tabSource.ViewName}");
|
|||
|
|
SelectedTab = existingTab;
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 创建新标签
|
|||
|
|
var newTab = new TabItemModel
|
|||
|
|
{
|
|||
|
|
Header = tabSource.Name,
|
|||
|
|
Icon = tabSource.Icon,
|
|||
|
|
IconType = tabSource.IconType,
|
|||
|
|
ViewName = tabSource.ViewName,
|
|||
|
|
IsClosable = tabSource.IsClosable,
|
|||
|
|
TabSource = tabSource,
|
|||
|
|
OpenTabs = OpenTabs,
|
|||
|
|
EventAggregator = _eventAggregator
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
_logger.Debug($"创建新标签: {tabSource.ViewName}");
|
|||
|
|
OpenTabs.Add(newTab);
|
|||
|
|
SelectedTab = newTab;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 刷新Tab
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="tabItemModel"></param>
|
|||
|
|
private void OnRefreshTab(TabItemModel tabItemModel)
|
|||
|
|
{
|
|||
|
|
if (tabItemModel?.TabSource == null)
|
|||
|
|
{
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 当前Tab选中
|
|||
|
|
SelectedTab = tabItemModel;
|
|||
|
|
|
|||
|
|
// 从Region中移除现有视图(避免缓存问题)
|
|||
|
|
RemoveContentRegionView(tabItemModel.ViewName);
|
|||
|
|
|
|||
|
|
// 重新导航,确保加载新的视图
|
|||
|
|
_ = NavigateToViewAsync(CommonConst.ContentRegion, tabItemModel.ViewName, tabItemModel.TabSource.NavigationParameter);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// TabItem关闭回调
|
|||
|
|
/// </summary>
|
|||
|
|
private void OnTabClosed(TabItemModel tabModel)
|
|||
|
|
{
|
|||
|
|
if (tabModel != null)
|
|||
|
|
{
|
|||
|
|
_logger.Debug($"标签已关闭: {tabModel.Header}");
|
|||
|
|
|
|||
|
|
//var viewName = OpenTabs.Count <= 1 ? null : tabModel.ViewName;
|
|||
|
|
var viewName = tabModel.ViewName;
|
|||
|
|
|
|||
|
|
RemoveContentRegionView(viewName);
|
|||
|
|
|
|||
|
|
// 当前Tab是最后一个
|
|||
|
|
if (OpenTabs.Count <= 1)
|
|||
|
|
{
|
|||
|
|
var region = _regionManager.Regions[CommonConst.MenuRegion];
|
|||
|
|
var activeView = region.ActiveViews.FirstOrDefault();
|
|||
|
|
if (activeView != null)
|
|||
|
|
{
|
|||
|
|
var navItem = NavItems?.Where(it => it.ViewName == activeView.GetType().Name).FirstOrDefault();
|
|||
|
|
if (navItem != null)
|
|||
|
|
{
|
|||
|
|
if (navItem.AlignBottom)
|
|||
|
|
{
|
|||
|
|
SelectedBottomNavItem = navItem;
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
SelectedTopNavItem = navItem;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
} else if (tabModel.TabSource is NavItem navItem)
|
|||
|
|
{
|
|||
|
|
if (navItem == SelectedTopNavItem)
|
|||
|
|
{
|
|||
|
|
SelectedTopNavItem = null;
|
|||
|
|
SelectedNavItem = null;
|
|||
|
|
}
|
|||
|
|
else if (navItem == SelectedBottomNavItem)
|
|||
|
|
{
|
|||
|
|
SelectedBottomNavItem = null;
|
|||
|
|
SelectedNavItem = null;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 如果关闭的不是当前选中的Tab
|
|||
|
|
if (SelectedTab != null && SelectedTab != tabModel)
|
|||
|
|
{
|
|||
|
|
// 发布事件:强制刷新当前选中(因为右键关闭未切换,不会触发SelectedTab属性setter方法)
|
|||
|
|
_eventAggregator.GetEvent<TabSelectedEvent>().Publish(SelectedTab);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private async void LogoutAsync()
|
|||
|
|
{
|
|||
|
|
// 使用异步版本
|
|||
|
|
var confirmed = await ConfirmAsync("确定退出登录吗?");
|
|||
|
|
if (confirmed)
|
|||
|
|
{
|
|||
|
|
var account = AppSession.CurrentUser?.Account ?? CurrentUser?.Account ?? string.Empty;
|
|||
|
|
_ = _loginLogReportService.ReportLogAsync("LOGIN", "退出登录", account, true);
|
|||
|
|
// 发布登出事件
|
|||
|
|
_eventAggregator.GetEvent<SysUserEvents.LoginOutEvent>().Publish(AppSession.CurrentUser!);
|
|||
|
|
Logout();
|
|||
|
|
}
|
|||
|
|
// var messageBoxResult = HandyControl.Controls.MessageBox.Show(
|
|||
|
|
// $"确定退出登录吗?",
|
|||
|
|
// "确认登出",
|
|||
|
|
//MessageBoxButton.OKCancel,
|
|||
|
|
//MessageBoxImage.Warning);
|
|||
|
|
|
|||
|
|
// if (messageBoxResult != MessageBoxResult.OK) return;
|
|||
|
|
|
|||
|
|
// // 发布登出事件
|
|||
|
|
// _eventAggregator.GetEvent<SysUserEvents.LoginOutEvent>().Publish(AppSession.CurrentUser!);
|
|||
|
|
|
|||
|
|
// Logout();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#region 主题
|
|||
|
|
/// <summary>
|
|||
|
|
/// 打开系统设置
|
|||
|
|
/// </summary>
|
|||
|
|
private void OpenAppSettings()
|
|||
|
|
{
|
|||
|
|
IsAppSettingsOpen = true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 重置系统设置
|
|||
|
|
/// </summary>
|
|||
|
|
private void ResetAppSettings()
|
|||
|
|
{
|
|||
|
|
// 重置为默认值
|
|||
|
|
// new AppSettingsViewModel().Adapt(AppSettingsViewModel);
|
|||
|
|
|
|||
|
|
AppSettingsViewModel = new AppSettingsViewModel();
|
|||
|
|
AppSettingsViewModel.UpdateSkin(AppSettingsViewModel.SkinType!.Value);
|
|||
|
|
AppSettingsViewModel.UpdateAppSettings();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 加载系统设置
|
|||
|
|
/// </summary>
|
|||
|
|
private void LoadAppSettings()
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
var filePath = AppSettingsViewModel.GetFilePath();
|
|||
|
|
if (!File.Exists(filePath))
|
|||
|
|
{
|
|||
|
|
AppSettingsViewModel = new AppSettingsViewModel();
|
|||
|
|
AppSettingsViewModel.UpdateSkin(AppSettingsViewModel.SkinType!.Value);
|
|||
|
|
AppSettingsViewModel.SaveAppSettings();
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
var json = File.ReadAllText(filePath);
|
|||
|
|
var appSettings = JsonConvert.DeserializeObject<AppSettings>(json);
|
|||
|
|
AppSettingsViewModel = appSettings.Adapt<AppSettingsViewModel>();
|
|||
|
|
AppSettingsViewModel.SkinType = AppSettingsViewModel.SyncWithSystem ? AppSettingsViewModel.GetSkinTypeBySystem() : AppSettingsViewModel.SkinType;
|
|||
|
|
AppSettingsViewModel.UpdateSkin(AppSettingsViewModel.SkinType!.Value);
|
|||
|
|
AppSettingsViewModel.UpdateAppSettings();
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
_logger.Error($"加载系统设置失败: {ex.Message}", ex);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
private async Task StartBackendConnectivityLoopAsync(CancellationToken cancellationToken)
|
|||
|
|
{
|
|||
|
|
while (!cancellationToken.IsCancellationRequested)
|
|||
|
|
{
|
|||
|
|
bool connected = false;
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
// 每轮都重新读取配置,保存服务器设置后可即时生效
|
|||
|
|
var baseUrl = _configuration.GetValue<string>("JeecgIntegration:BaseUrl")?.TrimEnd('/');
|
|||
|
|
var userListPath = _configuration.GetValue<string>("JeecgIntegration:UserListPath") ?? "/sys/user/scada/queryUser";
|
|||
|
|
var probeUrl = string.IsNullOrWhiteSpace(baseUrl)
|
|||
|
|
? string.Empty
|
|||
|
|
: $"{baseUrl}{userListPath}?pageNo=1&pageSize=1&includeDetail=false";
|
|||
|
|
if (!string.IsNullOrWhiteSpace(probeUrl))
|
|||
|
|
{
|
|||
|
|
using var req = new HttpRequestMessage(HttpMethod.Get, probeUrl);
|
|||
|
|
using var resp = await _httpClient.SendAsync(req, cancellationToken);
|
|||
|
|
connected = resp.IsSuccessStatusCode;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
catch
|
|||
|
|
{
|
|||
|
|
connected = false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
await Application.Current.Dispatcher.InvokeAsync(() =>
|
|||
|
|
{
|
|||
|
|
IsBackendConnected = connected;
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
catch
|
|||
|
|
{
|
|||
|
|
// 忽略窗口关闭后的调度异常
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
await Task.Delay(TimeSpan.FromSeconds(ConnectivityCheckIntervalSeconds), cancellationToken);
|
|||
|
|
}
|
|||
|
|
catch (OperationCanceledException)
|
|||
|
|
{
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void OpenServerSettings()
|
|||
|
|
{
|
|||
|
|
_dialogService.ShowDialog("ServerSettingsDialog", r => { });
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 清空资源
|
|||
|
|
/// </summary>
|
|||
|
|
private void Destroy(SysUser? sysUser = null)
|
|||
|
|
{
|
|||
|
|
if (_openOrActivateTabToken != null)
|
|||
|
|
{
|
|||
|
|
_eventAggregator
|
|||
|
|
.GetEvent<TabSourceSelectedEvent>()
|
|||
|
|
.Unsubscribe(_openOrActivateTabToken);
|
|||
|
|
|
|||
|
|
_openOrActivateTabToken = null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (_tabClosedToken != null)
|
|||
|
|
{
|
|||
|
|
_eventAggregator
|
|||
|
|
.GetEvent<TabClosedEvent>()
|
|||
|
|
.Unsubscribe(_tabClosedToken);
|
|||
|
|
|
|||
|
|
_tabClosedToken = null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (_refreshTabToken != null)
|
|||
|
|
{
|
|||
|
|
_eventAggregator
|
|||
|
|
.GetEvent<TabRefreshEvent>()
|
|||
|
|
.Unsubscribe(_refreshTabToken);
|
|||
|
|
|
|||
|
|
_refreshTabToken = null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (_loginOutToken != null)
|
|||
|
|
{
|
|||
|
|
_eventAggregator
|
|||
|
|
.GetEvent<SysUserEvents.LoginOutEvent>()
|
|||
|
|
.Unsubscribe(_loginOutToken);
|
|||
|
|
|
|||
|
|
_loginOutToken = null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (_authService != null)
|
|||
|
|
{
|
|||
|
|
_authService.UserChanged -= OnUserChanged;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!_backendConnectivityCts.IsCancellationRequested)
|
|||
|
|
{
|
|||
|
|
_backendConnectivityCts.Cancel();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
_jeecgUserSyncCoordinator.Stop();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|