using HandyControl.Data;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Threading;
using YY.Admin.Core;
using YY.Admin.Core.Const;
using YY.Admin.Core.EventBus;
using YY.Admin.Core.Session;
using YY.Admin.Services.Service.Auth;
using YY.Admin.Services.Service.Config;
using YY.Admin.Views;
namespace YY.Admin.ViewModels
{
public class BaseViewModel : BindableBase, IDestructible
{
protected bool _isLoading;
private string _title = string.Empty;
// 添加Token检查定时器
private static DispatcherTimer? _tokenCheckTimer;
///
///加载
///
public bool IsLoading
{
get => _isLoading;
set
{
if (SetProperty(ref _isLoading, value))
{
// 触发一个虚拟方法,让派生类可以响应
OnIsLoadingChanged();
}
}
}
public bool IsNotLoading => !IsLoading;
///
///标题
///
public string Title
{
get => _title;
set => SetProperty(ref _title, value);
}
private readonly IDialogService _dialogService;
protected readonly IRegionManager _regionManager;
///
/// 日志对象
///
protected ILoggerService _logger;
///
/// 依赖注入容器
///
protected IContainerExtension _container { get; }
///
/// 事件汇总器,用于发布或订阅事件
///
protected IEventAggregator _eventAggregator;
///
/// 当前已登录用户信息
///
protected static UserContext? _userContext { get; set; }
private SkinType _skinType;
public SkinType SkinType { get => _skinType; set => SetProperty(ref _skinType, value); }
private SubscriptionToken? _themeChangedEventToken;
protected BaseViewModel(IContainerExtension container, IRegionManager regionManager)
{
_container = container;
_logger = container.Resolve();
_eventAggregator = container.Resolve();
this._dialogService = container.Resolve();
this._regionManager = regionManager;
_themeChangedEventToken = _eventAggregator.GetEvent().Subscribe(skinType => SkinType = skinType);
}
#region 用户操作
///
/// 从系统配置应用登录状态检查间隔(分钟)
///
private static void ApplyTokenCheckIntervalFromConfig()
{
var minutes = 1;
try
{
var cfg = Prism.Ioc.ContainerLocator.Current.Resolve();
var v = cfg.GetConfigValue(ConfigConst.SysTokenCheckIntervalMinutes).GetAwaiter().GetResult();
if (v >= 1 && v <= 120)
minutes = v;
}
catch
{
// 使用默认 1 分钟
}
if (_tokenCheckTimer != null)
_tokenCheckTimer.Interval = TimeSpan.FromMinutes(minutes);
}
///
/// 是否开启登录永不过期
///
private static bool IsTokenNeverExpireEnabled()
{
try
{
var cfg = Prism.Ioc.ContainerLocator.Current.Resolve();
return cfg.GetConfigValue(ConfigConst.SysTokenNeverExpire).GetAwaiter().GetResult();
}
catch
{
return false;
}
}
///
/// 登录设置保存后刷新检查间隔(已启动定时器时立即生效)
///
public static void RefreshTokenCheckIntervalFromConfig()
{
ApplyTokenCheckIntervalFromConfig();
}
// 启动定时器的方法
public static void StartTokenCheckTimer()
{
if (_tokenCheckTimer == null)
{
_tokenCheckTimer = new DispatcherTimer();
_tokenCheckTimer.Tick += CheckTokenExpiration;
// 捕获全局用户输入事件
EventManager.RegisterClassHandler(typeof(Window),
UIElement.PreviewMouseDownEvent,
new MouseButtonEventHandler(OnUserActivity));
EventManager.RegisterClassHandler(typeof(Window),
UIElement.PreviewKeyDownEvent,
new KeyEventHandler(OnUserActivity));
}
ApplyTokenCheckIntervalFromConfig();
if (!_tokenCheckTimer.IsEnabled)
{
_tokenCheckTimer.Start();
}
}
// 停止定时器的方法
public static void StopTokenCheckTimer()
{
if (_tokenCheckTimer != null && _tokenCheckTimer.IsEnabled)
{
_tokenCheckTimer.Stop();
}
}
private static void OnUserActivity(object sender, EventArgs e)
{
if (IsTokenNeverExpireEnabled())
return;
var authService = ContainerLocator.Current.Resolve();
authService.RefreshToken(UserContext?.Token?.AccessToken);
}
///
///定时器检查方法
///
///
///
private static void CheckTokenExpiration(object? sender, EventArgs e)
{
// 确保在主线程执行
Application.Current.Dispatcher.Invoke(() =>
{
if (UserContext == null || UserContext.Token == null)
{
// 如果没有用户信息,停止定时器
StopTokenCheckTimer();
return;
}
if (IsTokenNeverExpireEnabled())
return;
var authService = ContainerLocator.Current.Resolve();
if (!authService.ValidateToken(UserContext.Token.AccessToken))
{
// 停止定时器防止重复触发
StopTokenCheckTimer();
// 显示过期提示
Application.Current.Dispatcher.Invoke(() =>
{
var currentWindow = Application.Current.MainWindow;
if (currentWindow != null)
{
var viewModel = currentWindow.DataContext as BaseViewModel;
viewModel?.ForceLogout("您的登录已过期,请重新登录");
}
});
}
});
}
///
/// 强制退出方法
///
///
public async void ForceLogout(string message)
{
// 先显示对话框
await ShowAlertAsync(message);
// 发布登出事件
_eventAggregator.GetEvent().Publish(AppSession.CurrentUser!);
Logout();
}
///
/// 登出
///
public void Logout()
{
// 停止定时器
StopTokenCheckTimer();
// 清除用户上下文
ClearUserContext();
// 再执行退出操作
var authService = _container.Resolve();
authService.LogoutAsync();
// 当前窗口
var mainWindow = Application.Current.MainWindow;
// 跳转到登录页
var loginWindow = _container.Resolve();
Application.Current.MainWindow = loginWindow;
loginWindow.Show();
mainWindow.Close();
// 移除所有区域
RemoveAllRegion();
}
public static UserContext? UserContext
{
get => _userContext;
private set
{
if (_userContext != value)
{
_userContext = value;
// 通知静态属性变化(需要额外实现)
StaticPropertyChanged?.Invoke(null, new PropertyChangedEventArgs(nameof(UserContext)));
}
}
}
// 静态属性变更通知事件
public static event EventHandler? StaticPropertyChanged;
///
/// 设置用户上下文
///
///
///
public static void SetUserContext(SysUser user, UserToken token)
{
UserContext = new UserContext
{
UserId = user.Id,
TenantId = user.TenantId!.Value,
Account = user.Account,
AccountType = user.AccountType,
RealName = user.RealName,
IsSuperAdmin = user.AccountType == AccountTypeEnum.SuperAdmin,
OrgId = user.OrgId,
Token = token
};
}
///
/// 清除用户上下文
///
public static void ClearUserContext()
{
UserContext = null;
}
#endregion
#region 导航
///
/// 导航到指定Page
///
/// 区域名称
/// 目标Page名称
/// 导航回调函数
protected void RequestNavigate(string regionName, string target, Action navigationCallback = null)
{
IRegion region = _regionManager.Regions[regionName];
if (region == null) return;
region.RemoveAll();
if (navigationCallback != null)
region.RequestNavigate(target, navigationCallback);
else
region.RequestNavigate(target);
}
protected void SetRegionManager(DependencyObject target)
{
RegionManager.SetRegionManager(target, _regionManager);
}
///
/// 安全导航到指定视图
///
protected void SafeNavigate(string regionName, string targetView, NavigationParameters parameters = null)
{
ExecuteWithExceptionHandling(() =>
{
// 导航页面
_regionManager.RequestNavigate(regionName, targetView, parameters);
});
}
protected void ExecuteWithExceptionHandling(Action action)
{
try
{
action();
}
catch (Exception ex)
{
HandleException(ex);
}
}
private void HandleException(Exception ex)
{
LogError("操作发生异常", ex);
// ShowErrorDialog($"操作异常: {ex.Message}");
}
#endregion
#region 弹出框
///
/// 弹框提示
///
/// 消息内容
/// 回调函数
protected void Alert(string message, Action? callback = null)
{
_dialogService.ShowDialog("AlertDialog", new DialogParameters($"message={message}"), callback);
}
protected Task ShowAlertAsync(string message)
{
var tcs = new TaskCompletionSource();
Alert(message,result => tcs.SetResult(true));
return tcs.Task;
}
///
/// 弹出消息提示框,1秒钟自动关闭
///
/// 消息内容
/// 消息类型
/// 回调函数
protected void AlertPopup(string message, MessageTypeEnum messageType = MessageTypeEnum.Success, Action callback = null)
{
switch (messageType)
{
case MessageTypeEnum.Success:
_dialogService.ShowDialog("SuccessDialog", new DialogParameters($"message={message}"), callback);
break;
case MessageTypeEnum.Error:
_dialogService.ShowDialog("ErrorDialog", new DialogParameters($"message={message}"), callback);
break;
case MessageTypeEnum.Warning:
_dialogService.ShowDialog("WarningDialog", new DialogParameters($"message={message}"), callback);
break;
default:
_dialogService.ShowDialog("SuccessDialog", new DialogParameters($"message={message}"), callback);
break;
}
}
///
/// 确认框提示
///
/// 确认框消息
/// 回调函数
protected void Confirm(string message, Action? callback = null)
{
_dialogService.ShowDialog("ConfirmDialog", new DialogParameters($"message={message}"), callback);
}
///
/// 异步确认框
///
/// 确认消息
/// 用户是否确认
protected Task ConfirmAsync(string message)
{
var tcs = new TaskCompletionSource();
Confirm(message, result =>
{
// 从 IDialogResult 中提取用户选择
var userConfirmed = result.Result == ButtonResult.Yes;
tcs.SetResult(userConfirmed);
});
return tcs.Task;
}
#endregion
#region 日志功能封装
protected void LogInfo(string message, [CallerMemberName] string caller = "")
=> _logger.Information($"[{GetType().Name}.{caller}] {message}");
protected void LogWarning(string message, [CallerMemberName] string caller = "")
=> _logger.Warning($"[{GetType().Name}.{caller}] {message}");
protected void LogError(string message, Exception ex = null, [CallerMemberName] string caller = "")
=> _logger.Error($"[{GetType().Name}.{caller}] {message}", ex);
#endregion
///
/// 异常处理封装
///
///
///
///
protected async Task ExecuteAsync(Func asyncAction, Action? onFinally = null)
{
try
{
IsLoading = true;
await asyncAction();
}
catch (Exception ex)
{
HandleException(ex);
}
finally
{
IsLoading = false;
onFinally?.Invoke();
}
}
///
/// 窗口管理
///
///
protected void SwitchMainWindow() where T : Window
{
ExecuteWithExceptionHandling(() =>
{
var currentWindow = Application.Current.MainWindow;
var newWindow = _container.Resolve();
Application.Current.MainWindow?.Hide();
Application.Current.MainWindow = newWindow;
newWindow.Show();
currentWindow?.Close();
});
}
///
/// 资源管理
///
///
///
///
///
protected T GetResource(string resourceKey)
{
if (Application.Current.TryFindResource(resourceKey) is T resource)
{
return resource;
}
throw new ResourceNotFoundException($"资源未找到: {resourceKey}");
}
///
/// 移除区域,包括清空区域内的内容,导航日志
///
/// 区域名称
protected void RemoveRegion(string regionName)
{
if (string.IsNullOrEmpty(regionName))
{
return;
}
if (!_regionManager.Regions.ContainsRegionWithName(regionName))
{
return;
}
var region = _regionManager.Regions[regionName];
RemoveRegion(region);
}
///
/// 移除区域,包括清空区域内的内容,导航日志
///
///
protected void RemoveRegion(IRegion region)
{
if (region == null)
{
return;
}
// 清空区域内容
region.RemoveAll();
// 清空导航历史
region.NavigationService?.Journal?.Clear();
// 从区域管理器中移除区域
_regionManager.Regions.Remove(region.Name);
_logger.Debug($"移除区域{region.Name}");
}
///
/// 移除所有区域
///
protected void RemoveAllRegion()
{
foreach (var region in _regionManager.Regions.ToList())
{
RemoveRegion(region);
}
_logger.Debug($"移除所有区域");
}
///
/// 移除区域视图
///
/// 区域名称
/// 视图名称
protected void RemoveView(string regionName, string? viewName)
{
if (string.IsNullOrEmpty(regionName) || string.IsNullOrEmpty(viewName))
{
return;
}
if (!_regionManager.Regions.ContainsRegionWithName(regionName))
{
return;
}
var region = _regionManager.Regions[regionName];
// 查找并移除指定的视图
var viewToRemove = region.Views.FirstOrDefault(v =>
{
// 根据视图名称或类型来匹配
var viewType = v.GetType();
return viewType.Name == viewName || viewType.Name == viewName + "View";
});
if (viewToRemove != null)
{
region.Remove(viewToRemove);
_logger.Debug($"从区域{regionName}移除视图{viewName}");
}
}
///
/// 移除区域ContentRegion视图
///
///
protected void RemoveContentRegionView(string? viewName)
{
RemoveView(CommonConst.ContentRegion, viewName);
}
///
/// 移除区域所有视图
///
/// 区域名称
protected void RemoveAllView(string regionName)
{
if (string.IsNullOrEmpty(regionName))
{
return;
}
if (!_regionManager.Regions.ContainsRegionWithName(regionName))
{
return;
}
var region = _regionManager.Regions[regionName];
region.RemoveAll();
_logger.Debug($"移除区域{regionName}所有视图");
}
///
/// 当 IsLoading 变化时的回调方法
///
protected virtual void OnIsLoadingChanged()
{
RaisePropertyChanged(nameof(IsNotLoading));
}
///
/// 清理资源
///
protected virtual void CleanUp()
{
}
///
/// 清空资源
/// 执行时机:从Region移除View 或 导航到另一个View时
///
public void Destroy()
{
if (_themeChangedEventToken != null)
{
_eventAggregator.GetEvent().Unsubscribe(_themeChangedEventToken);
_themeChangedEventToken = null;
}
// 清理派生类的资源
CleanUp();
}
}
// 自定义异常类型
public class ResourceNotFoundException : Exception
{
public ResourceNotFoundException(string message) : base(message) { }
}
}