Files
qhmes/yy-admin-master/YY.Admin/ViewModels/Base/BaseViewModel.cs

593 lines
19 KiB
C#
Raw Normal View History

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.Views;
namespace YY.Admin.ViewModels
{
public class BaseViewModel : BindableBase, IDestructible
{
protected bool _isLoading;
private string _title = string.Empty;
// 添加Token检查定时器
private static DispatcherTimer? _tokenCheckTimer;
/// <summary>
///加载
/// </summary>
public bool IsLoading
{
get => _isLoading;
set
{
if (SetProperty(ref _isLoading, value))
{
// 触发一个虚拟方法,让派生类可以响应
OnIsLoadingChanged();
}
}
}
public bool IsNotLoading => !IsLoading;
/// <summary>
///标题
/// </summary>
public string Title
{
get => _title;
set => SetProperty(ref _title, value);
}
private readonly IDialogService _dialogService;
protected readonly IRegionManager _regionManager;
/// <summary>
/// 日志对象
/// </summary>
protected ILoggerService _logger;
/// <summary>
/// 依赖注入容器
/// </summary>
protected IContainerExtension _container { get; }
/// <summary>
/// 事件汇总器,用于发布或订阅事件
/// </summary>
protected IEventAggregator _eventAggregator;
/// <summary>
/// 当前已登录用户信息
/// </summary>
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<ILoggerService>();
_eventAggregator = container.Resolve<IEventAggregator>();
this._dialogService = container.Resolve<IDialogService>();
this._regionManager = regionManager;
_themeChangedEventToken = _eventAggregator.GetEvent<ThemeChangedEvent>().Subscribe(skinType => SkinType = skinType);
}
#region
// 启动定时器的方法
public static void StartTokenCheckTimer()
{
if (_tokenCheckTimer == null)
{
_tokenCheckTimer = new DispatcherTimer
{
Interval = TimeSpan.FromMinutes(1)
};
_tokenCheckTimer.Tick += CheckTokenExpiration;
// 捕获全局用户输入事件
EventManager.RegisterClassHandler(typeof(Window),
UIElement.PreviewMouseDownEvent,
new MouseButtonEventHandler(OnUserActivity));
EventManager.RegisterClassHandler(typeof(Window),
UIElement.PreviewKeyDownEvent,
new KeyEventHandler(OnUserActivity));
}
if (!_tokenCheckTimer.IsEnabled)
{
_tokenCheckTimer.Start();
}
}
// 停止定时器的方法
public static void StopTokenCheckTimer()
{
if (_tokenCheckTimer != null && _tokenCheckTimer.IsEnabled)
{
_tokenCheckTimer.Stop();
}
}
private static void OnUserActivity(object sender, EventArgs e)
{
var authService = ContainerLocator.Current.Resolve<ISysAuthService>();
authService.RefreshToken(UserContext?.Token?.AccessToken);
}
/// <summary>
///定时器检查方法
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void CheckTokenExpiration(object? sender, EventArgs e)
{
// 确保在主线程执行
Application.Current.Dispatcher.Invoke(() =>
{
if (UserContext == null || UserContext.Token == null)
{
// 如果没有用户信息,停止定时器
StopTokenCheckTimer();
return;
}
var authService = ContainerLocator.Current.Resolve<ISysAuthService>();
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("您的登录已过期,请重新登录");
}
});
}
});
}
/// <summary>
/// 强制退出方法
/// </summary>
/// <param name="message"></param>
public async void ForceLogout(string message)
{
// 先显示对话框
await ShowAlertAsync(message);
// 发布登出事件
_eventAggregator.GetEvent<SysUserEvents.LoginOutEvent>().Publish(AppSession.CurrentUser!);
Logout();
}
/// <summary>
/// 登出
/// </summary>
public void Logout()
{
// 停止定时器
StopTokenCheckTimer();
// 清除用户上下文
ClearUserContext();
// 再执行退出操作
var authService = _container.Resolve<ISysAuthService>();
authService.LogoutAsync();
// 当前窗口
var mainWindow = Application.Current.MainWindow;
// 跳转到登录页
var loginWindow = _container.Resolve<LoginWindow>();
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<PropertyChangedEventArgs>? StaticPropertyChanged;
/// <summary>
/// 设置用户上下文
/// </summary>
/// <param name="user"></param>
/// <param name="token"></param>
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
};
}
/// <summary>
/// 清除用户上下文
/// </summary>
public static void ClearUserContext()
{
UserContext = null;
}
#endregion
#region
/// <summary>
/// 导航到指定Page
/// </summary>
/// <param name="regionName">区域名称</param>
/// <param name="target">目标Page名称</param>
/// <param name="navigationCallback">导航回调函数</param>
protected void RequestNavigate(string regionName, string target, Action<NavigationResult> 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);
}
/// <summary>
/// 安全导航到指定视图
/// </summary>
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
/// <summary>
/// 弹框提示
/// </summary>
/// <param name="message">消息内容</param>
/// <param name="callback">回调函数</param>
protected void Alert(string message, Action<IDialogResult>? callback = null)
{
_dialogService.ShowDialog("AlertDialog", new DialogParameters($"message={message}"), callback);
}
protected Task ShowAlertAsync(string message)
{
var tcs = new TaskCompletionSource<bool>();
Alert(message,result => tcs.SetResult(true));
return tcs.Task;
}
/// <summary>
/// 弹出消息提示框1秒钟自动关闭
/// </summary>
/// <param name="message">消息内容</param>
/// <param name="messageType">消息类型</param>
/// <param name="callback">回调函数</param>
protected void AlertPopup(string message, MessageTypeEnum messageType = MessageTypeEnum.Success, Action<IDialogResult> 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;
}
}
/// <summary>
/// 确认框提示
/// </summary>
/// <param name="message">确认框消息</param>
/// <param name="callback">回调函数</param>
protected void Confirm(string message, Action<IDialogResult>? callback = null)
{
_dialogService.ShowDialog("ConfirmDialog", new DialogParameters($"message={message}"), callback);
}
/// <summary>
/// 异步确认框
/// </summary>
/// <param name="message">确认消息</param>
/// <returns>用户是否确认</returns>
protected Task<bool> ConfirmAsync(string message)
{
var tcs = new TaskCompletionSource<bool>();
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
/// <summary>
/// 异常处理封装
/// </summary>
/// <param name="asyncAction"></param>
/// <param name="onFinally"></param>
/// <returns></returns>
protected async Task ExecuteAsync(Func<Task> asyncAction, Action? onFinally = null)
{
try
{
IsLoading = true;
await asyncAction();
}
catch (Exception ex)
{
HandleException(ex);
}
finally
{
IsLoading = false;
onFinally?.Invoke();
}
}
/// <summary>
/// 窗口管理
/// </summary>
/// <typeparam name="T"></typeparam>
protected void SwitchMainWindow<T>() where T : Window
{
ExecuteWithExceptionHandling(() =>
{
var currentWindow = Application.Current.MainWindow;
var newWindow = _container.Resolve<T>();
Application.Current.MainWindow?.Hide();
Application.Current.MainWindow = newWindow;
newWindow.Show();
currentWindow?.Close();
});
}
/// <summary>
/// 资源管理
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="resourceKey"></param>
/// <returns></returns>
/// <exception cref="ResourceNotFoundException"></exception>
protected T GetResource<T>(string resourceKey)
{
if (Application.Current.TryFindResource(resourceKey) is T resource)
{
return resource;
}
throw new ResourceNotFoundException($"资源未找到: {resourceKey}");
}
/// <summary>
/// 移除区域,包括清空区域内的内容,导航日志
/// </summary>
/// <param name="regionName">区域名称</param>
protected void RemoveRegion(string regionName)
{
if (string.IsNullOrEmpty(regionName))
{
return;
}
if (!_regionManager.Regions.ContainsRegionWithName(regionName))
{
return;
}
var region = _regionManager.Regions[regionName];
RemoveRegion(region);
}
/// <summary>
/// 移除区域,包括清空区域内的内容,导航日志
/// </summary>
/// <param name="region"></param>
protected void RemoveRegion(IRegion region)
{
if (region == null)
{
return;
}
// 清空区域内容
region.RemoveAll();
// 清空导航历史
region.NavigationService?.Journal?.Clear();
// 从区域管理器中移除区域
_regionManager.Regions.Remove(region.Name);
_logger.Debug($"移除区域{region.Name}");
}
/// <summary>
/// 移除所有区域
/// </summary>
protected void RemoveAllRegion()
{
foreach (var region in _regionManager.Regions.ToList())
{
RemoveRegion(region);
}
_logger.Debug($"移除所有区域");
}
/// <summary>
/// 移除区域视图
/// </summary>
/// <param name="regionName">区域名称</param>
/// <param name="viewName">视图名称</param>
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}");
}
}
/// <summary>
/// 移除区域ContentRegion视图
/// </summary>
/// <param name="viewName"></param>
protected void RemoveContentRegionView(string? viewName)
{
RemoveView(CommonConst.ContentRegion, viewName);
}
/// <summary>
/// 移除区域所有视图
/// </summary>
/// <param name="regionName">区域名称</param>
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}所有视图");
}
/// <summary>
/// 当 IsLoading 变化时的回调方法
/// </summary>
protected virtual void OnIsLoadingChanged()
{
RaisePropertyChanged(nameof(IsNotLoading));
}
/// <summary>
/// 清理资源
/// </summary>
protected virtual void CleanUp()
{
}
/// <summary>
/// 清空资源
/// 执行时机从Region移除View 或 导航到另一个View时
/// </summary>
public void Destroy()
{
if (_themeChangedEventToken != null)
{
_eventAggregator.GetEvent<ThemeChangedEvent>().Unsubscribe(_themeChangedEventToken);
_themeChangedEventToken = null;
}
// 清理派生类的资源
CleanUp();
}
}
// 自定义异常类型
public class ResourceNotFoundException : Exception
{
public ResourceNotFoundException(string message) : base(message) { }
}
}