using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using Serilog; using System.ComponentModel; using YZWater.Core.Models; using YZWater.Core.Services; namespace YZWater.Core.ViewModels; /// /// 主窗口 ViewModel /// public partial class MainViewModel : ObservableObject, IDisposable { private readonly ViewAViewModel _viewAViewModel; private readonly ViewBViewModel _viewBViewModel; private readonly ViewCViewModel _viewCViewModel; private readonly ViewDViewModel _viewDViewModel; private readonly ViewEViewModel _viewEViewModel; private readonly ViewFViewModel _viewFViewModel; private ProjectViewModel? _projectViewModel; private readonly ThemeService _themeService = ThemeService.Instance; private readonly LanguageService _langService = LanguageService.Instance; private readonly SynchronizationContext? _uiContext = SynchronizationContext.Current; private System.Timers.Timer? _clockTimer; private bool _disposed; [ObservableProperty] private ObservableObject _currentView; [ObservableProperty] private string _title; [ObservableProperty] private string _currentTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); [ObservableProperty] private bool _isPlcConnected; [ObservableProperty] private int _selectedTabIndex; // 各 Tab 激活状态 [ObservableProperty] private bool _isTabAActive = true; [ObservableProperty] private bool _isTabBActive; [ObservableProperty] private bool _isTabCActive; [ObservableProperty] private bool _isTabDActive; [ObservableProperty] private bool _isTabEActive; [ObservableProperty] private bool _isTabFActive; // 当前 Tab 标题 [ObservableProperty] private string _tabTitle; // 主题/语言状态 [ObservableProperty] private bool _isDarkTheme = true; [ObservableProperty] private bool _isChinese = true; [ObservableProperty] private string _themeIcon = "🌙"; [ObservableProperty] private string _langIcon = "中"; // 导航标签 [ObservableProperty] private string _navProcess; [ObservableProperty] private string _navParams; [ObservableProperty] private string _navFlow; [ObservableProperty] private string _navAlarm; [ObservableProperty] private string _navAbout; [ObservableProperty] private string _navAudit; // ═══ 用户管理翻译 ═══ [ObservableProperty] private string _userManageText; [ObservableProperty] private string _createNewUserText; [ObservableProperty] private string _userNameLabel; [ObservableProperty] private string _passwordLabel; [ObservableProperty] private string _displayNameLabel; [ObservableProperty] private string _roleLabel; [ObservableProperty] private string _statusLabel; [ObservableProperty] private string _lastLoginLabel; [ObservableProperty] private string _actionLabel; [ObservableProperty] private string _createText; [ObservableProperty] private string _closeText; [ObservableProperty] private string _logoutText; // ═══ 运行模式与连接状态 ═══ [ObservableProperty] private string _runMode = "Direct"; [ObservableProperty] private string _hubStatusText = ""; [ObservableProperty] private string _plcStatusText = ""; [ObservableProperty] private string _plcStatusColor = "#E74C3C"; // ═══ 子 ViewModel(供 View 绑定 DataContext) ═══ public ViewAViewModel ViewA => _viewAViewModel; public ViewBViewModel ViewB => _viewBViewModel; public ViewCViewModel ViewC => _viewCViewModel; public ViewDViewModel ViewD => _viewDViewModel; public ViewEViewModel ViewE => _viewEViewModel; public ViewFViewModel ViewF => _viewFViewModel; /// 项目化 ViewModel(当加载了项目档案时可用) public ProjectViewModel? ProjectView => _projectViewModel; /// 是否加载了项目档案 [ObservableProperty] private bool _hasProject; // ═══ 用户与权限 ═══ [ObservableProperty] private string _currentUserName = string.Empty; [ObservableProperty] private string _currentUserRole = string.Empty; [ObservableProperty] private bool _canControl; [ObservableProperty] private bool _canModifyParams; [ObservableProperty] private bool _canManageUsers; [ObservableProperty] private bool _showUserDialog; public MainViewModel() { _viewAViewModel = new ViewAViewModel(); _viewBViewModel = new ViewBViewModel(); _viewCViewModel = new ViewCViewModel(); _viewDViewModel = new ViewDViewModel(); _viewEViewModel = new ViewEViewModel(); _viewFViewModel = new ViewFViewModel(); _currentView = _viewAViewModel; UpdateAllTexts(); RefreshUserInfo(); LoadRunMode(); _langService.LanguageChanged += OnLanguageChanged; _themeService.PropertyChanged += OnThemeServicePropertyChanged; // PLC 连接状态监听 PlcPollingService.Instance.ConnectionStateChanged += OnConnectionStateChanged; StartTimer(); // 项目档案初始化 InitializeProject(); } /// /// 根据当前配置初始化项目 ViewModel /// private void InitializeProject() { var profile = ProjectService.Current; if (profile != null) { _projectViewModel = new ProjectViewModel(profile); CurrentView = _projectViewModel; HasProject = true; Log.Information("已初始化项目视图: {Name}", profile.Name); } } private void OnLanguageChanged() { RunOnUi(() => { IsChinese = _langService.IsChinese; UpdateAllTexts(); RefreshUserInfo(); }); } private void OnThemeServicePropertyChanged(object? sender, PropertyChangedEventArgs e) { if (e.PropertyName != nameof(ThemeService.IsDarkTheme)) return; RunOnUi(() => { IsDarkTheme = _themeService.IsDarkTheme; ThemeIcon = IsDarkTheme ? "🌙" : "☀️"; }); } private void OnConnectionStateChanged(bool connected) { RunOnUi(() => { PlcStatusText = connected ? _langService.Get("PlcConnectedStatus") : _langService.Get("PlcDisconnected"); PlcStatusColor = connected ? "#27AE60" : "#E74C3C"; IsPlcConnected = connected; }); } private void RunOnUi(Action action) { if (_disposed) return; if (_uiContext != null && SynchronizationContext.Current != _uiContext) _uiContext.Post(_ => { if (!_disposed) action(); }, null); else action(); } private void UpdateAllTexts() { Title = _langService.Get("AppName"); TabTitle = _langService.Get("ProcessFlow"); NavProcess = _langService.Get("NavProcess"); NavParams = _langService.Get("NavParams"); NavFlow = _langService.Get("NavFlow"); NavAlarm = _langService.Get("NavAlarm"); NavAbout = _langService.Get("NavAbout"); NavAudit = _langService.Get("AuditLog"); UserManageText = _langService.Get("UserManage"); CreateNewUserText = _langService.Get("CreateNewUser"); UserNameLabel = _langService.Get("UserName"); PasswordLabel = _langService.Get("Password"); DisplayNameLabel = _langService.Get("DisplayName"); RoleLabel = _langService.Get("Role"); StatusLabel = _langService.Get("Status"); LastLoginLabel = _langService.Get("LastLogin"); ActionLabel = _langService.Get("Action"); CreateText = _langService.Get("Create"); CloseText = _langService.Get("Close"); LogoutText = _langService.Get("Logout"); IsChinese = _langService.IsChinese; LangIcon = IsChinese ? "中" : "EN"; IsDarkTheme = _themeService.IsDarkTheme; ThemeIcon = IsDarkTheme ? "🌙" : "☀️"; } /// /// 加载运行模式 /// private void LoadRunMode() { var config = ConfigService.GetConfig(); RunMode = config?.RunMode ?? "Direct"; HubStatusText = RunMode switch { "Server" => $"{_langService.Get("ServerMode")} :{config?.HubPort ?? 8765}", "Client" => $"{_langService.Get("ClientMode")} → {config?.HubServerUrl ?? "ws://localhost:8765"}", "Mock" => _langService.Get("MockMode"), _ => _langService.Get("DirectMode") }; } [RelayCommand] private void ToggleTheme() { _themeService.ToggleTheme(); } [RelayCommand] private void ToggleLanguage() { _langService.ToggleLanguage(); } [RelayCommand] private async Task ConnectPlcAsync() => await _viewAViewModel.ConnectPlcCommand.ExecuteAsync(null); [RelayCommand] private void DisconnectPlc() => _viewAViewModel.DisconnectPlcCommand.Execute(null); [RelayCommand] private async Task RefreshDataAsync() => await _viewAViewModel.RefreshDataCommand.ExecuteAsync(null); // ─── Tab 切换 ─── private readonly string[] _tabTitleKeys = { "ProcessFlow", "Parameters", "FlowRecords", "AlarmLog", "About", "AuditLog" }; private void SetActiveTab(int index) { IsTabAActive = index == 0; IsTabBActive = index == 1; IsTabCActive = index == 2; IsTabDActive = index == 3; IsTabEActive = index == 4; IsTabFActive = index == 5; TabTitle = _langService.Get(_tabTitleKeys[index]); } [RelayCommand] private void ShowViewA() { CurrentView = HasProject && _projectViewModel != null ? _projectViewModel : _viewAViewModel; SetActiveTab(0); } [RelayCommand] private void ShowViewB() { CurrentView = _viewBViewModel; SetActiveTab(1); } [RelayCommand] private void ShowViewC() { CurrentView = _viewCViewModel; SetActiveTab(2); } [RelayCommand] private void ShowViewD() { CurrentView = _viewDViewModel; SetActiveTab(3); } [RelayCommand] private void ShowViewE() { CurrentView = _viewEViewModel; SetActiveTab(4); } [RelayCommand] private void ShowViewF() { CurrentView = _viewFViewModel; SetActiveTab(5); } private void StartTimer() { _clockTimer = new System.Timers.Timer(1000); _clockTimer.Elapsed += (s, e) => { var time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); RunOnUi(() => CurrentTime = time); }; _clockTimer.Start(); } private void StopTimer() { _clockTimer?.Stop(); _clockTimer?.Dispose(); _clockTimer = null; } private void RefreshUserInfo() { var user = AuthService.CurrentUser; if (user != null) { // 管理员显示名跟随语言更新 if (user.UserName == "admin") { var adminDisplayName = _langService.Get("AdminName"); if (user.DisplayName != adminDisplayName) { user.DisplayName = adminDisplayName; DatabaseService.Db.Updateable(user).UpdateColumns(u => u.DisplayName).ExecuteCommand(); } } CurrentUserName = user.DisplayName; CurrentUserRole = user.Role switch { UserRole.Viewer => _langService.Get("Viewer"), UserRole.Operator => _langService.Get("OperatorRole"), UserRole.Engineer => _langService.Get("Engineer"), UserRole.Admin => _langService.Get("AdminRole"), _ => "Unknown" }; CanControl = AuthService.HasPermission(UserRole.Operator); CanModifyParams = AuthService.HasPermission(UserRole.Engineer); CanManageUsers = AuthService.HasPermission(UserRole.Admin); } } [RelayCommand] private void Logout() { AuthService.Logout(); } [RelayCommand] private void ToggleUserDialog() { ShowUserDialog = !ShowUserDialog; if (ShowUserDialog) { LoadUsers(); } } // ═══ 用户管理 ═══ [ObservableProperty] private List _userList = new(); [ObservableProperty] private string _newUserName = string.Empty; [ObservableProperty] private string _newUserPassword = string.Empty; [ObservableProperty] private string _newUserDisplayName = string.Empty; [ObservableProperty] private UserRole _newUserRole = UserRole.Operator; [ObservableProperty] private string _userManageMessage = string.Empty; private void LoadUsers() { UserList = AuthService.GetAllUsers(); } [RelayCommand] private void CreateUser() { if (string.IsNullOrWhiteSpace(NewUserName) || string.IsNullOrWhiteSpace(NewUserPassword)) { UserManageMessage = _langService.Get("UserNamePasswordRequired"); return; } var (success, message) = AuthService.CreateUser(NewUserName, NewUserPassword, NewUserDisplayName, NewUserRole); UserManageMessage = message; if (success) { NewUserName = string.Empty; NewUserPassword = string.Empty; NewUserDisplayName = string.Empty; NewUserRole = UserRole.Operator; LoadUsers(); } } [RelayCommand] private void ToggleUserActive(User? user) { if (user == null) return; AuthService.SetUserActive(user.UserName, !user.IsActive); LoadUsers(); } public void Dispose() { if (_disposed) return; _disposed = true; StopTimer(); _langService.LanguageChanged -= OnLanguageChanged; _themeService.PropertyChanged -= OnThemeServicePropertyChanged; PlcPollingService.Instance.ConnectionStateChanged -= OnConnectionStateChanged; _viewAViewModel.Dispose(); _viewBViewModel.Dispose(); _viewCViewModel.Dispose(); _viewDViewModel.Dispose(); _viewEViewModel.Dispose(); _viewFViewModel.Dispose(); _projectViewModel?.Dispose(); } }