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; /// /// 正在从 Jeecg 同步用户到本地库 /// 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 用户"; /// 登录与同步互斥,用于禁用登录按钮 public bool CanInteractWithLogin => !IsLoading && !IsSyncingJeecgUsers; private bool _isBackendConnected; /// /// 后端连接状态:true=连接中,false=已断开 /// 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(); _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(); 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("JeecgIntegration:BaseUrl")?.TrimEnd('/'); var userListPath = _configuration.GetValue("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 = "服务器配置已保存"; } }); } } }