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

314 lines
12 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Windows;
using System.Windows.Media;
using System.Net.Http;
using Microsoft.Extensions.Configuration;
using Prism.Dialogs;
using YY.Admin;
using YY.Admin.Core.Helper;
using YY.Admin.Core.Session;
using YY.Admin.FluentValidation;
using YY.Admin.Helper;
using YY.Admin.Services;
using YY.Admin.Services.Service.Auth;
using YY.Admin.Services.Service.Jeecg;
using YY.Admin.Views;
namespace YY.Admin.ViewModels
{
// ViewModels/LoginViewModel.cs
public class LoginWindowViewModel : BaseViewModel
{
private readonly ISysAuthService _authService;
private readonly IDialogService _dialogService;
private readonly IJeecgLoginLogReportService _loginLogReportService;
private readonly IConfiguration _configuration;
private readonly HttpClient _httpClient = new();
private readonly CancellationTokenSource _connectivityCts = new();
private const int ConnectivityCheckIntervalSeconds = 5;
public LoginInput LoginInput { get; set; }
private string _loginMessage = string.Empty;
public DelegateCommand LoginCommand { get; }
public DelegateCommand SyncJeecgUsersCommand { get; }
public DelegateCommand OpenServerSettingsCommand { get; }
public LoginInputValidator LoginInputValidator { get; private set; }
private bool _isSyncingJeecgUsers;
/// <summary>
/// 正在从 Jeecg 同步用户到本地库
/// </summary>
public bool IsSyncingJeecgUsers
{
get => _isSyncingJeecgUsers;
set
{
if (SetProperty(ref _isSyncingJeecgUsers, value))
{
SyncJeecgUsersCommand.RaiseCanExecuteChanged();
LoginCommand.RaiseCanExecuteChanged();
RaisePropertyChanged(nameof(SyncJeecgUsersButtonText));
RaisePropertyChanged(nameof(CanInteractWithLogin));
}
}
}
public string SyncJeecgUsersButtonText => IsSyncingJeecgUsers ? "同步中..." : "同步 Jeecg 用户";
/// <summary>登录与同步互斥,用于禁用登录按钮</summary>
public bool CanInteractWithLogin => !IsLoading && !IsSyncingJeecgUsers;
private bool _isBackendConnected;
/// <summary>
/// 后端连接状态true=连接中false=已断开
/// </summary>
public bool IsBackendConnected
{
get => _isBackendConnected;
set
{
if (SetProperty(ref _isBackendConnected, value))
{
RaisePropertyChanged(nameof(BackendConnectionStatusText));
RaisePropertyChanged(nameof(BackendConnectionStatusBrush));
}
}
}
public string BackendConnectionStatusText => IsBackendConnected ? "后端连接中" : "后端已断开";
public Brush BackendConnectionStatusBrush => IsBackendConnected ? Brushes.LimeGreen : Brushes.Red;
public LoginWindowViewModel(
ISysAuthService authService,
IDialogService dialogService,
IJeecgLoginLogReportService loginLogReportService,
IContainerExtension _container,
IRegionManager regionManager
) : base(_container, regionManager)
{
_authService = authService;
_dialogService = dialogService;
_loginLogReportService = loginLogReportService;
_configuration = _container.Resolve<IConfiguration>();
_loginLogReportService.StartBackgroundSync();
Title = "系统登录";
LoginInput = new LoginInput()
{
Username = "admin",
Password = "123456"
};
LoginInputValidator = new LoginInputValidator();
LoginCommand = new DelegateCommand(async () => await LoginAsync(), CanLogin)
.ObservesProperty(() => IsLoading)
.ObservesProperty(() => IsSyncingJeecgUsers);
SyncJeecgUsersCommand = new DelegateCommand(async () => await SyncJeecgUsersAsync(), CanSyncJeecgUsers)
.ObservesProperty(() => IsLoading)
.ObservesProperty(() => IsSyncingJeecgUsers);
OpenServerSettingsCommand = new DelegateCommand(OpenServerSettings);
_ = StartBackendConnectivityLoopAsync(_connectivityCts.Token);
}
public string LoginMessage
{
get => _loginMessage;
set => SetProperty(ref _loginMessage, value);
}
public string LoginButtonText => IsLoading ? "登录中..." : "登录";
protected override void OnIsLoadingChanged()
{
base.OnIsLoadingChanged();
RaisePropertyChanged(nameof(LoginButtonText));
RaisePropertyChanged(nameof(CanInteractWithLogin));
LoginCommand.RaiseCanExecuteChanged();
SyncJeecgUsersCommand.RaiseCanExecuteChanged();
}
private bool CanLogin()
{
return !IsLoading && !IsSyncingJeecgUsers;
}
private bool CanSyncJeecgUsers()
{
return !IsLoading && !IsSyncingJeecgUsers;
}
private async Task SyncJeecgUsersAsync()
{
LoginMessage = string.Empty;
IsSyncingJeecgUsers = true;
try
{
await UIHelper.WaitForRenderAsync();
var (success, message) = await _authService.SyncJeecgUsersToLocalFromLoginScreenAsync();
LoginMessage = message;
if (success)
{
_logger?.Information("登录页一键同步 Jeecg 用户成功");
}
else
{
_logger?.Warning($"登录页一键同步 Jeecg 用户:{message}");
}
}
catch (Exception ex)
{
LoginMessage = $"同步出错:{ex.Message}";
}
finally
{
IsSyncingJeecgUsers = false;
}
}
private async Task LoginAsync()
{
IsLoading = true;
//LoginMessage = string.Empty;
try
{
// 让出线程让UI先渲染
await UIHelper.WaitForRenderAsync();
var response = await _authService.LoginAsync(LoginInput);
if (response.Success)
{
_ = _loginLogReportService.ReportLoginAsync(LoginInput.Username, true, "登录成功");
_connectivityCts.Cancel();
//设置会话
AppSession.CurrentUser = response.User;
// 设置用户上下文
SetUserContext(response.User!, response.Token);
// 启动定时器
StartTokenCheckTimer();
// 登录成功,打开主窗口
var loginWindow = Application.Current.MainWindow;
var mainWindow = _container.Resolve<MainWindow>();
Application.Current.MainWindow = mainWindow;
//把窗口和RegionManager 绑定一下即可
SetRegionManager(mainWindow);
mainWindow.Show();
loginWindow.Close();
// 不等待异步更新用户登录信息,不阻塞主窗口打开
_ = _authService.UpdateUserLoginInfoAsync(response.User!);
}
else
{
LoginMessage = response.Message;
_ = _loginLogReportService.ReportLoginAsync(LoginInput.Username, false, response.Message);
}
}
catch (Exception ex)
{
LoginMessage = $"登录出错:{ex.Message}";
_ = _loginLogReportService.ReportLoginAsync(LoginInput.Username, false, ex.Message);
}
finally
{
IsLoading = false;
}
}
private async Task StartBackendConnectivityLoopAsync(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
bool connected = false;
var settings = ServerSettingsStore.Load();
if (settings.DisconnectConnection)
{
try
{
await Application.Current.Dispatcher.InvokeAsync(() =>
{
IsBackendConnected = false;
});
}
catch
{
// 忽略窗口关闭后的调度异常
}
try
{
await Task.Delay(TimeSpan.FromSeconds(ConnectivityCheckIntervalSeconds), cancellationToken);
}
catch (OperationCanceledException)
{
break;
}
continue;
}
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()
{
var parameters = new DialogParameters
{
{ KnownDialogParameters.WindowName, DialogWindowNames.ChromeDialogWindow },
};
_dialogService.ShowDialog("ServerSettingsDialog", parameters, r =>
{
if (r.Result == ButtonResult.OK)
{
var settings = ServerSettingsStore.Load();
if (settings.DisconnectConnection)
{
IsBackendConnected = false;
}
LoginMessage = "服务器配置已保存";
}
});
}
}
}