Bladeren bron

刷卡登录与多用户支持重构,优化配置与语言切换

重构刷卡登录流程,支持刷卡器参数配置、记住用户、用户名下拉选择等功能。统一系统语言切换逻辑,优化依赖注入与启动流程。提升登录安全性与易用性,完善界面细节,移除重复初始化代码。
孝锋 徐 7 maanden geleden
bovenliggende
commit
e114f7152a

+ 28 - 4
TeamAAS-VM/App.xaml.cs

@@ -33,6 +33,7 @@ using TeamAAS_VP.ViewModels.Calibration;
 using TeamAAS_VP.ViewModels.DebugMod;
 using TeamAAS_VP.ViewModels.Home;
 using TeamAAS_VP.ViewModels.Product;
+using TeamAAS_VP.ViewModels.User;
 using TeamAAS_VP.Views;
 using TeamAAS_VP.Views.Calibration;
 using TeamAAS_VP.Views.DebugMod;
@@ -54,7 +55,29 @@ namespace TeamAAS_VP
         protected override Window CreateShell()
         {
             Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
-            return base.Container.Resolve<MainWindowView>();
+            var mainWindow = this.Container.Resolve<MainWindowView>();
+            var _configService = this.Container.Resolve<IConfigService>();
+            var _databaseInitializer = this.Container.Resolve<IDatabaseInitializer>();
+            // 1. 读取配置参数
+            _configService.LoadAll();
+            try
+            {
+                _databaseInitializer.InitializeDatabase();
+            }
+            catch (Exception ex)
+            {
+                LogHelper.WriteLogError("Database initialization failed during application startup", ex);
+            }
+            // 设置语言
+            var currentlanguage = _configService.GetSystemConfiguration().CurrentLanguage;
+            _configService.SetCurrentLanguage(currentlanguage);
+            var cardLogin = this.Container.Resolve<CardLoginWindow>();
+            var result = cardLogin.ShowDialog();
+            if (result is bool st1 && !st1)
+            {
+                this.Shutdown();
+            }
+            return mainWindow;
         }
 
         protected override void RegisterTypes(IContainerRegistry containerRegistry)
@@ -94,7 +117,7 @@ namespace TeamAAS_VP
             containerRegistry.RegisterForNavigation<ProductParams>();
             containerRegistry.RegisterForNavigation<ProcedureParams>();
             containerRegistry.RegisterForNavigation<AfagFeederParams>();
-            
+
             //校准
             containerRegistry.RegisterForNavigation<CalibrationAuto>();
             containerRegistry.RegisterForNavigation<CalibrationBasics>();
@@ -121,6 +144,7 @@ namespace TeamAAS_VP
             containerRegistry.RegisterSingleton<ICameraCalibrationService, CameraCalibrationService>();
             containerRegistry.RegisterSingleton<IMesService, MesService>();
             containerRegistry.RegisterSingleton<Management>();
+            containerRegistry.RegisterSingleton<CardLoginWindowViewModel>();
 
             // Register system database service and initializer
             containerRegistry.RegisterSingleton<ISystemDatabaseService, TeamAAS_VP.Data.SystemDatabaseService>();
@@ -274,7 +298,7 @@ namespace TeamAAS_VP
             }
             else
             {
-                MessageBox.Show(Lang.程序已经在运行, "AAS",MessageBoxButton.OK,MessageBoxImage.Asterisk);
+                MessageBox.Show(Lang.程序已经在运行, "AAS", MessageBoxButton.OK, MessageBoxImage.Asterisk);
                 this.Shutdown();
             }
         }
@@ -290,7 +314,7 @@ namespace TeamAAS_VP
             //可以记录日志并转向错误bug窗口友好提示用户
             e.Handled = true;
             LogHelper.WriteLogFatal("Application has crashed", e.Exception);
-            MessageBox.Show("Error:" + e.Exception.Message + " " + e.Exception.StackTrace,"AAS",MessageBoxButton.OK,MessageBoxImage.Asterisk);
+            MessageBox.Show("Error:" + e.Exception.Message + " " + e.Exception.StackTrace, "AAS", MessageBoxButton.OK, MessageBoxImage.Asterisk);
         }
 
         private static void UnhandledExceptionOccured(object sender, UnhandledExceptionEventArgs args)

+ 19 - 0
TeamAAS-VM/Data/SystemDatabaseService.cs

@@ -135,6 +135,25 @@ namespace TeamAAS_VP.Data
             await RecordUserLoginAsync(rec);
         }
 
+        /// <summary>
+        /// 将指定用户设为当前用户(会写入一条登录记录,标记为成功)
+        /// </summary>
+        /// <param name="user"></param>
+        /// <returns></returns>
+        public async Task SetCurrentUserAsync(User user)
+        {
+            CurrentUser = user;
+            // 记录一条成功的登录记录
+            var rec = new UserLoginRecord
+            {
+                UserId = user.Id,
+                Success = true,
+                Time = DateTime.UtcNow,
+                Message = user.UserName
+            };
+            await RecordUserLoginAsync(rec);
+        }
+
         /// <summary>
         /// 获取最近一次成功登录的用户(视为当前用户)。
         /// </summary>

+ 13 - 0
TeamAAS-VM/Interfaces/IConfigService.cs

@@ -2,6 +2,7 @@ using System;
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using System.Threading.Tasks;
+using TeamAAS_VP.Enums;
 using TeamAAS_VP.Models;
 using TeamAAS_VP.Models.Calibration;
 using TeamAAS_VP.Models.Feeder;
@@ -268,6 +269,18 @@ namespace TeamAAS_VP.Interfaces
         /// </summary>
         void SaveSystemConfiguration(SystemConfiguration systemConfiguration);
 
+        /// <summary>
+        /// 삿혤뎠품刀喇
+        /// </summary>
+        /// <returns></returns>
+        Language GetCurrentLanguage();
+
+        /// <summary>
+        /// �零뎠품刀喇
+        /// </summary>
+        /// <param name="language"></param>
+        void SetCurrentLanguage(Language language);
+
         //헌죕훨蛟
 
         /// <summary>

+ 7 - 0
TeamAAS-VM/Interfaces/ISystemDatabaseService.cs

@@ -123,6 +123,13 @@ namespace TeamAAS_VP.Interfaces
         /// </remarks>
         Task SetCurrentUserAsync(int userId);
 
+        /// <summary>
+        /// 将指定用户设为当前用户(会写入一条登录记录,标记为成功)
+        /// </summary>
+        /// <param name="user"></param>
+        /// <returns></returns>
+        Task SetCurrentUserAsync(User user);
+
         /// <summary>
         /// 获取当前(最近一次成功登录的)用户。
         /// </summary>

+ 69 - 2
TeamAAS-VM/Services/ConfigService.cs

@@ -4,10 +4,14 @@ using SqlSugar;
 using System;
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
+using System.Globalization;
 using System.IO;
 using System.Linq;
+using System.Threading;
 using System.Threading.Tasks;
 using TeamAAS_VP.Core;
+using TeamAAS_VP.Data; // for ISystemDatabaseService (if used)
+using TeamAAS_VP.Enums;
 using TeamAAS_VP.Interfaces;
 using TeamAAS_VP.Models;
 using TeamAAS_VP.Models.Calibration;
@@ -15,8 +19,8 @@ using TeamAAS_VP.Models.Feeder;
 using TeamAAS_VP.Models.Lights;
 using TeamAAS_VP.Models.PLC;
 using TeamAAS_VP.Models.ScrewDriver;
-using TeamAAS_VP.Data; // for ISystemDatabaseService (if used)
-using System.Threading;
+using TeamAAS_VP.Resources.Languages;
+using WPFLocalizeExtension.Engine;
 
 namespace TeamAAS_VP.Services
 {
@@ -761,6 +765,69 @@ namespace TeamAAS_VP.Services
                 FileHelper.WriteJsonFile(systemConfiguration, ConfigPaths.SystemConfigurationPath);
             }
         }
+
+        /// <summary>
+        /// 삿혤뎠품刀喇
+        /// </summary>
+        /// <returns></returns>
+        public Language GetCurrentLanguage()
+        {
+            lock (_sync)
+            {
+                var config = GetSystemConfiguration();
+                return config.CurrentLanguage;
+            }
+        }
+
+        /// <summary>
+        /// �零뎠품刀喇
+        /// </summary>
+        /// <param name="language"></param>
+        public void SetCurrentLanguage(Language language)
+        {
+            lock (_sync)
+            {
+                var config = GetSystemConfiguration();
+                config.CurrentLanguage = language;
+                if (language == Enums.Language.ChineseSimplified)
+                {
+                    var culture = new CultureInfo("zh-CN");
+                    App.Current.Dispatcher.Thread.CurrentCulture = culture;
+                    App.Current.Dispatcher.Thread.CurrentUICulture = culture;
+                    LocalizeDictionary.Instance.Culture = culture;
+                    Lang.Culture = culture;
+                    System.Windows.Application.Current.Resources["DefaultFont"] = new System.Windows.Media.FontFamily("Microsoft YaHei");
+                }
+                else if (language == Enums.Language.ChineseTraditional)
+                {
+                    var culture = new CultureInfo("zh-TW");
+                    App.Current.Dispatcher.Thread.CurrentCulture = culture;
+                    App.Current.Dispatcher.Thread.CurrentUICulture = culture;
+                    LocalizeDictionary.Instance.Culture = culture;
+                    Lang.Culture = culture;
+                    System.Windows.Application.Current.Resources["DefaultFont"] = new System.Windows.Media.FontFamily("Microsoft YaHei");
+                }
+                else if (language == Enums.Language.English)
+                {
+                    var culture = new CultureInfo("en");
+                    App.Current.Dispatcher.Thread.CurrentCulture = culture;
+                    App.Current.Dispatcher.Thread.CurrentUICulture = culture;
+                    LocalizeDictionary.Instance.Culture = culture;
+                    Lang.Culture = culture;
+                    System.Windows.Application.Current.Resources["DefaultFont"] = new System.Windows.Media.FontFamily("Segoe UI");
+                }
+                else if (language == Enums.Language.Japanese)
+                {
+                    var culture = new CultureInfo("ja-JP");
+                    App.Current.Dispatcher.Thread.CurrentCulture = culture;
+                    App.Current.Dispatcher.Thread.CurrentUICulture = culture;
+                    LocalizeDictionary.Instance.Culture = culture;
+                    Lang.Culture = culture;
+                    System.Windows.Application.Current.Resources["DefaultFont"] = new System.Windows.Media.FontFamily("Segoe UI");
+                }
+                SaveSystemConfiguration(config);
+            }
+        }
         #endregion
 
         #region Feeder헌죕훨蛟

+ 8 - 52
TeamAAS-VM/ViewModels/MainWindowViewModel.cs

@@ -150,14 +150,7 @@ namespace TeamAAS_VP.ViewModels
             LoadedCommand = new DelegateCommand(OnLoad);
             ClosedCommand = new DelegateCommand(OnClose);
             Status = management.Status;
-            try
-            {
-                _databaseInitializer.InitializeDatabase();
-            }
-            catch (Exception ex)
-            {
-                LogHelper.WriteLogError("Database initialization failed during application startup", ex);
-            }
+            
 
 
         }
@@ -220,11 +213,6 @@ namespace TeamAAS_VP.ViewModels
 
         private async void OnLoad()
         {
-            // 1. 读取配置参数
-            _configService.LoadAll();
-            // 2. 加载校准
-            _calibrationService.LoadAll();
-
             // 设置标题和版本号
             var systemconfig = _configService.GetSystemConfiguration();
             MyTitle = systemconfig.Title;
@@ -235,45 +223,10 @@ namespace TeamAAS_VP.ViewModels
 
 
             // 设置语言
-            #region 设置语言
-            var currentlanguage = _configService.GetSystemConfiguration().CurrentLanguage;
-            if (currentlanguage == Enums.Language.ChineseSimplified)
-            {
-                var culture = new CultureInfo("zh-CN");
-                App.Current.Dispatcher.Thread.CurrentCulture = culture;
-                App.Current.Dispatcher.Thread.CurrentUICulture = culture;
-                LocalizeDictionary.Instance.Culture = culture;
-                Lang.Culture = culture;
-                Application.Current.Resources["DefaultFont"] = new System.Windows.Media.FontFamily("Microsoft YaHei");
-            }
-            else if (currentlanguage == Enums.Language.ChineseTraditional)
-            {
-                var culture = new CultureInfo("zh-TW");
-                App.Current.Dispatcher.Thread.CurrentCulture = culture;
-                App.Current.Dispatcher.Thread.CurrentUICulture = culture;
-                LocalizeDictionary.Instance.Culture = culture;
-                Lang.Culture = culture;
-                Application.Current.Resources["DefaultFont"] = new System.Windows.Media.FontFamily("Microsoft YaHei");
-            }
-            else if (currentlanguage == Enums.Language.English)
-            {
-                var culture = new CultureInfo("en");
-                App.Current.Dispatcher.Thread.CurrentCulture = culture;
-                App.Current.Dispatcher.Thread.CurrentUICulture = culture;
-                LocalizeDictionary.Instance.Culture = culture;
-                Lang.Culture = culture;
-                Application.Current.Resources["DefaultFont"] = new System.Windows.Media.FontFamily("Segoe UI");
-            }
-            else if (currentlanguage == Enums.Language.Japanese)
-            {
-                var culture = new CultureInfo("ja-JP");
-                App.Current.Dispatcher.Thread.CurrentCulture = culture;
-                App.Current.Dispatcher.Thread.CurrentUICulture = culture;
-                LocalizeDictionary.Instance.Culture = culture;
-                Lang.Culture = culture;
-                Application.Current.Resources["DefaultFont"] = new System.Windows.Media.FontFamily("Segoe UI");
-            }
-            #endregion
+            //#region 设置语言
+            //var currentlanguage = _configService.GetSystemConfiguration().CurrentLanguage;
+            //_configService.SetCurrentLanguage(currentlanguage);
+            //#endregion
 
             SendTaskMessage(Lang.软件启动, MessageLevel.Info);
             StartTime = DateTime.Now;
@@ -290,6 +243,9 @@ namespace TeamAAS_VP.ViewModels
                 _eventAggregator.GetEvent<ProgressNotification>().Publish(new UProgressBar.ProgressParameter { Maximum = max, Minimum = 0, SubTitle = $"{Lang.初始化中}...", Message = $"{Lang.初始化数据库}...", Value = curvalue });
             }));
 
+            // 2. 加载校准
+            _calibrationService.LoadAll();
+
             //-------------------SETP 1: 初始化数据库-----------------------------------------------------------------------
             await Task.Delay(200);
             //初始化数据库

+ 37 - 36
TeamAAS-VM/ViewModels/SettingViewModel.cs

@@ -332,6 +332,14 @@ namespace TeamAAS_VP.ViewModels
             get { return _DeviceInfo; }
             set { SetProperty(ref _DeviceInfo, value); }
         }
+
+        private SerialPortConfig _CardReaderConfig;
+        public SerialPortConfig CardReaderConfig
+        {
+            get { return _CardReaderConfig; }
+            set { SetProperty(ref _CardReaderConfig, value); }
+        }
+
         #endregion
 
         #region 命令
@@ -430,6 +438,10 @@ namespace TeamAAS_VP.ViewModels
         public DelegateCommand<object> LightModelChangedCommand =>
             _LightModelChangedCommand ?? (_LightModelChangedCommand = new DelegateCommand<object>(ExecuteLightModelChangedCommand));
 
+        private DelegateCommand _SaveCardReaderConfigCommand;
+        public DelegateCommand SaveCardReaderConfigCommand =>
+            _SaveCardReaderConfigCommand ?? (_SaveCardReaderConfigCommand = new DelegateCommand(ExecuteSaveCardReaderConfigCommand));
+
         
         #endregion
 
@@ -1148,57 +1160,25 @@ namespace TeamAAS_VP.ViewModels
             if (string.Equals(language, "ChineseSimplified"))
             {
                 CurrentLanguage = Enums.Language.ChineseSimplified;
-                var sysConfig = _configService.GetSystemConfiguration();
-                sysConfig.CurrentLanguage = CurrentLanguage;
-                _configService.SaveSystemConfiguration(sysConfig);
-                var culture = new CultureInfo("zh-CN");
-                App.Current.Dispatcher.Thread.CurrentCulture = culture;
-                App.Current.Dispatcher.Thread.CurrentUICulture = culture;
-                LocalizeDictionary.Instance.Culture = culture;
-                Lang.Culture = culture;
-                Application.Current.Resources["DefaultFont"] = new System.Windows.Media.FontFamily("Microsoft YaHei");
+                _configService.SetCurrentLanguage(CurrentLanguage);
                 _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = Lang.完成, Duration = 0.5 });
             }
             else if (string.Equals(language, "ChineseTraditional"))
             {
                 CurrentLanguage = Enums.Language.ChineseTraditional;
-                var sysConfig = _configService.GetSystemConfiguration();
-                sysConfig.CurrentLanguage = CurrentLanguage;
-                _configService.SaveSystemConfiguration(sysConfig);
-                var culture = new CultureInfo("zh-TW");
-                App.Current.Dispatcher.Thread.CurrentCulture = culture;
-                App.Current.Dispatcher.Thread.CurrentUICulture = culture;
-                LocalizeDictionary.Instance.Culture = culture;
-                Lang.Culture = culture;
-                Application.Current.Resources["DefaultFont"] = new System.Windows.Media.FontFamily("Microsoft YaHei");
+                _configService.SetCurrentLanguage(CurrentLanguage);
                 _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = Lang.完成, Duration = 0.5 });
             }
             else if (string.Equals(language, "English"))
             {
                 CurrentLanguage = Enums.Language.English;
-                var sysConfig = _configService.GetSystemConfiguration();
-                sysConfig.CurrentLanguage = CurrentLanguage;
-                _configService.SaveSystemConfiguration(sysConfig);
-                var culture = new CultureInfo("en");
-                App.Current.Dispatcher.Thread.CurrentCulture = culture;
-                App.Current.Dispatcher.Thread.CurrentUICulture = culture;
-                LocalizeDictionary.Instance.Culture = culture;
-                Lang.Culture = culture;
-                Application.Current.Resources["DefaultFont"] = new System.Windows.Media.FontFamily("Segoe UI");
+                _configService.SetCurrentLanguage(CurrentLanguage);
                 _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = Lang.完成, Duration = 0.5 });
             }
             else if (string.Equals(language, "Japanese"))
             {
                 CurrentLanguage = Enums.Language.Japanese;
-                var sysConfig = _configService.GetSystemConfiguration();
-                sysConfig.CurrentLanguage = CurrentLanguage;
-                _configService.SaveSystemConfiguration(sysConfig);
-                var culture = new CultureInfo("ja-JP");
-                App.Current.Dispatcher.Thread.CurrentCulture = culture;
-                App.Current.Dispatcher.Thread.CurrentUICulture = culture;
-                LocalizeDictionary.Instance.Culture = culture;
-                Lang.Culture = culture;
-                Application.Current.Resources["DefaultFont"] = new System.Windows.Media.FontFamily("Segoe UI");
+                _configService.SetCurrentLanguage(CurrentLanguage);
                 _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = Lang.完成, Duration = 0.5 });
             }
         }
@@ -1355,6 +1335,12 @@ namespace TeamAAS_VP.ViewModels
                 ScrewFeederList = new ObservableCollection<ScrewFeederInfo>(screwFeeders);
             }
 
+            if (CardReaderConfig == null)
+            {
+                // load card reader config
+                CardReaderConfig = _configService.GetCardReaderConfig();
+            }
+
             CurrentLanguage = _configService.GetSystemConfiguration().CurrentLanguage;
 
             // load system parameters into UI
@@ -1618,6 +1604,21 @@ namespace TeamAAS_VP.ViewModels
                 }
             }
         }
+
+        /// <summary>
+        /// 保存读卡器配置
+        /// </summary>
+        void ExecuteSaveCardReaderConfigCommand()
+        {
+            try
+            {
+                _configService.SaveCardReaderConfig(CardReaderConfig);
+            }
+            catch (Exception ex)
+            {
+                _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = ex.Message, Duration = 1 });
+            }
+        }
         #endregion
 
         #region 设备信息

+ 119 - 26
TeamAAS-VM/ViewModels/User/CardLoginWindowViewModel.cs

@@ -1,5 +1,6 @@
 using Newtonsoft.Json;
 using Newtonsoft.Json.Linq;
+using OpenCvSharp;
 using Prism.Commands;
 using Prism.Events;
 using Prism.Ioc;
@@ -8,13 +9,20 @@ using Prism.Regions;
 using Prism.Services.Dialogs;
 using System;
 using System.Collections.Generic;
+using System.Collections.ObjectModel;
 using System.Linq;
 using System.Net.Http;
 using System.Text;
+using System.Threading.Tasks;
 using System.Windows;
 using TeamAAS_VP.Core;
 using TeamAAS_VP.Core.Lights;
+using TeamAAS_VP.Data;
+using TeamAAS_VP.Enums;
+using TeamAAS_VP.Events;
 using TeamAAS_VP.Interfaces;
+using TeamAAS_VP.Models;
+using TeamAAS_VP.Resources.Languages;
 using TeamAAS_VP.Views;
 using TeamAAS_VP.Views.User;
 
@@ -23,22 +31,29 @@ namespace TeamAAS_VP.ViewModels.User
     public class CardLoginWindowViewModel : BindableBase
     {
         #region 字段
-        IRegionManager _regionManager;
-        IRegionNavigationService _regionNavigationService;
-        IContainerProvider _container;
-        IDialogService _dialogService;
-        IEventAggregator _eventAggregator;
         IConfigService _configService;
-        System.Net.Http.HttpClient httpClient;
+        private readonly ISystemDatabaseService _systemDatabaseService;
+        private List<TeamAAS_VP.Models.User> Users;
         #endregion
 
         #region 属性
 
-        private string _Name;
-        public string Name
+        private ObservableCollection<string> _UserNameList = new ObservableCollection<string>();
+
+        /// <summary>
+        /// 用户列表
+        /// </summary>
+        public ObservableCollection<string> UserNameList
+        {
+            get { return _UserNameList; }
+            set { _UserNameList = value; }
+        }
+
+        private string _SelectedUserName;
+        public string SelectedUserName
         {
-            get { return _Name; }
-            set { SetProperty(ref _Name, value); }
+            get { return _SelectedUserName; }
+            set { SetProperty(ref _SelectedUserName, value); }
         }
 
         private string _Password;
@@ -48,6 +63,8 @@ namespace TeamAAS_VP.ViewModels.User
             set { SetProperty(ref _Password, value); }
         }
 
+        public bool IsRemember { get; set; }
+
         public bool IsLocal { get; private set; }
         public CardLoginWindow View { get; set; }
 
@@ -79,7 +96,7 @@ namespace TeamAAS_VP.ViewModels.User
         #region 命令
         private DelegateCommand _LoginCommand;
         public DelegateCommand LoginCommand =>
-            _LoginCommand ?? (_LoginCommand = new DelegateCommand(ExecuteLoginCommand, CanExecuteLoginCommand).ObservesProperty(() => Name).ObservesProperty(() => Password).ObservesProperty(() => IsLogining));
+            _LoginCommand ?? (_LoginCommand = new DelegateCommand(ExecuteLoginCommand, CanExecuteLoginCommand).ObservesProperty(() => SelectedUserName).ObservesProperty(() => Password).ObservesProperty(() => IsLogining));
 
         private DelegateCommand _CloseCommand;
         public DelegateCommand CloseCommand =>
@@ -98,18 +115,10 @@ namespace TeamAAS_VP.ViewModels.User
 
         #endregion
 
-        public CardLoginWindowViewModel(IRegionManager regionManager, IEventAggregator ea, IRegionNavigationService regionNavigationService, IContainerProvider container, IDialogService dialogService, IConfigService configService)
+        public CardLoginWindowViewModel(IConfigService configService, ISystemDatabaseService systemDatabaseService)
         {
-            _regionManager = regionManager;
-            _regionNavigationService = regionNavigationService;
-            _container = container;
-            _dialogService = dialogService;
             _configService = configService;
-            _eventAggregator = ea;
-            if (httpClient == null)
-            {
-                httpClient = new System.Net.Http.HttpClient();
-            }
+            _systemDatabaseService = systemDatabaseService;
         }
 
 
@@ -121,10 +130,44 @@ namespace TeamAAS_VP.ViewModels.User
         {
             //获取刷卡器配置
             var cardConfig = _configService.GetCardReaderConfig();
+            try
+            {
+                Users = _systemDatabaseService.GetAllUsersAsync().GetAwaiter().GetResult()?.ToList();
+            }
+            catch
+            {
+                Users = new List<TeamAAS_VP.Models.User>();
+            }
+            TeamAAS_VP.Models.User rememberUser = null;
+            if (Users != null)
+            {
+                UserNameList.Clear();
+                foreach (var user in Users)
+                {
+                    UserNameList.Add(user.UserName);
+                    if (user.IsRemember)
+                    {
+                        rememberUser = user;
+                    }
+                }
+            }
+
+            //对记住的用户界面绑定
+            if (rememberUser != null)
+            {
+                SelectedUserName = UserNameList.FirstOrDefault(p => p == rememberUser.UserName);
+                Password = rememberUser.UserPassword;
+                IsRemember = true;
+            }
+
             //创建刷卡器通讯
             serialPortProtocol = new SerialPortProtocol(cardConfig);
             serialPortProtocol.DataReceived += CardSerial_DataReceived;
-            await serialPortProtocol.ConnectAsync();
+            bool isConnected = await serialPortProtocol.ConnectAsync();
+            if (!isConnected)
+            {
+                MessageBox.Show("刷卡器连接失败,请检查连接!");
+            }
         }
 
         private async void CardSerial_DataReceived(object sender, string code)
@@ -135,21 +178,71 @@ namespace TeamAAS_VP.ViewModels.User
                 {
                     return;
                 }
-               
+                Models.User user = new Models.User();
+                user.UserName = code;
+                user.userPart = UserPart.Engineer;
+                user.UserPassword = code; //刷卡密码默认为卡号
+                user.CreateTime = DateTime.Now;
+                user.Id = -1;
+
+                await _systemDatabaseService.SetCurrentUserAsync(user);
+
+                View.DialogResult = true;
             }
         }
 
-        public void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
+        public async void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
         {
+            if (serialPortProtocol!=null)
+            {
+                serialPortProtocol.DataReceived -= CardSerial_DataReceived;
+            }
+            await serialPortProtocol?.DisconnectAsync();
+            
             serialPortProtocol?.Dispose();
+            serialPortProtocol = null;
         }
 
         async void ExecuteLoginCommand()
         {
+            if (Users == null || string.IsNullOrEmpty(SelectedUserName))
+                return;
+
             IsLogining = true;
             try
             {
-                
+                if (_systemDatabaseService.GetCurrentUser() != null)
+                {
+                    if (_systemDatabaseService.GetCurrentUser().UserName == SelectedUserName)
+                    {
+                        View.DialogResult = true;
+                        return;
+                    }
+                }
+
+                // authenticate via system database service
+                var user = await _systemDatabaseService.AuthenticateUserAsync(SelectedUserName, Password);
+                if (user != null)
+                {
+                    // set remember flag via system database service
+                    try
+                    {
+                        if (IsRemember)
+                            await _systemDatabaseService.SetRememberUserAsync(SelectedUserName);
+                        else
+                            await _systemDatabaseService.ClearRememberUserAsync();
+                    }
+                    catch
+                    {
+
+                    }
+
+                    // mark current user in system DB and record login
+                    await _systemDatabaseService.SetCurrentUserAsync(user.Id);
+                    await _systemDatabaseService.RecordUserLoginAsync(new UserLoginRecord { UserId = user.Id, Success = true, Time = DateTime.UtcNow, Message = "Login success" });
+                    View.DialogResult = true;
+                }
+
             }
             catch (Exception ex)
             {
@@ -163,7 +256,7 @@ namespace TeamAAS_VP.ViewModels.User
 
         bool CanExecuteLoginCommand()
         {
-            return !string.IsNullOrEmpty(Name) && !string.IsNullOrEmpty(Password) && !IsLogining;
+            return !string.IsNullOrEmpty(SelectedUserName) && !IsLogining;
         }
 
         void ExecuteCloseCommand()

+ 32 - 14
TeamAAS-VM/ViewModels/User/LoginViewModel.cs

@@ -11,12 +11,13 @@ using System.Collections.ObjectModel;
 using System.Data.Entity;
 using System.Linq;
 using System.Threading.Tasks;
+using TeamAAS_VP.Core;
 using TeamAAS_VP.Data;
 using TeamAAS_VP.Events;
-using TeamAAS_VP.Core;
+using TeamAAS_VP.Interfaces;
 using TeamAAS_VP.Models;
 using TeamAAS_VP.Resources.Languages;
-using TeamAAS_VP.Interfaces;
+using TeamAAS_VP.Views.User;
 
 namespace TeamAAS_VP.ViewModels.User
 {
@@ -25,8 +26,7 @@ namespace TeamAAS_VP.ViewModels.User
         private readonly IRegionManager _regionManager;
         private readonly IEventAggregator _eventAggregator;
         private readonly IContainerProvider _container;
-        private readonly ISystemDatabaseService _systemDb;
-		ISystemDatabaseService _systemDatabaseService;
+        private readonly ISystemDatabaseService _systemDatabaseService;
 
 		private List<TeamAAS_VP.Models.User> Users;
         #region 属性
@@ -59,18 +59,23 @@ namespace TeamAAS_VP.ViewModels.User
         /// </summary>
         public DelegateCommand LoginCommand { get; set; }
         public DelegateCommand LoadedCommand { get; set; }
+
+        private DelegateCommand _CardLoginCommand;
+        public DelegateCommand CardLoginCommand =>
+            _CardLoginCommand ?? (_CardLoginCommand = new DelegateCommand(ExecuteCardLoginCommand));
+
+        
         #endregion
 
         #region 事件
 
         #endregion
 
-        public LoginViewModel(IRegionManager regionManager, IEventAggregator ea, IContainerProvider container, ISystemDatabaseService systemDb,ISystemDatabaseService systemDatabaseService)
+        public LoginViewModel(IRegionManager regionManager, IEventAggregator ea, IContainerProvider container, ISystemDatabaseService systemDatabaseService)
         {
             _regionManager = regionManager;
             _eventAggregator = ea;
             _container = container;
-            _systemDb = systemDb;
             _systemDatabaseService = systemDatabaseService;
 
 			LoadedCommand = new DelegateCommand(OnLoad);
@@ -82,7 +87,7 @@ namespace TeamAAS_VP.ViewModels.User
             // load users from system database (sync-block safe call)
             try
             {
-                Users = _systemDb.GetAllUsersAsync().GetAwaiter().GetResult()?.ToList();
+                Users = _systemDatabaseService.GetAllUsersAsync().GetAwaiter().GetResult()?.ToList();
             }
             catch
             {
@@ -128,16 +133,16 @@ namespace TeamAAS_VP.ViewModels.User
             try
             {
                 // authenticate via system database service
-                var user = await _systemDb.AuthenticateUserAsync(SelectedUserName, UserPassword);
+                var user = await _systemDatabaseService.AuthenticateUserAsync(SelectedUserName, UserPassword);
                 if (user != null)
                 {
                     // set remember flag via system database service
                     try
                     {
                         if (IsRemember)
-                            await _systemDb.SetRememberUserAsync(SelectedUserName);
+                            await _systemDatabaseService.SetRememberUserAsync(SelectedUserName);
                         else
-                            await _systemDb.ClearRememberUserAsync();
+                            await _systemDatabaseService.ClearRememberUserAsync();
                     }
                     catch
                     {
@@ -145,8 +150,8 @@ namespace TeamAAS_VP.ViewModels.User
                     }
 
                     // mark current user in system DB and record login
-                    await _systemDb.SetCurrentUserAsync(user.Id);
-                    await _systemDb.RecordUserLoginAsync(new UserLoginRecord { UserId = user.Id, Success = true, Time = DateTime.UtcNow, Message = "Login success" });
+                    await _systemDatabaseService.SetCurrentUserAsync(user.Id);
+                    //await _systemDatabaseService.RecordUserLoginAsync(new UserLoginRecord { UserId = user.Id, Success = true, Time = DateTime.UtcNow, Message = "Login success" });
 
                     _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = $"{Lang.登录成功}!", Duration = 1 });
                     _eventAggregator.GetEvent<UserLoginNotification>().Publish(user);
@@ -155,7 +160,7 @@ namespace TeamAAS_VP.ViewModels.User
             catch (Exception ex)
             {
                 // authentication failed or error
-                await _systemDb.RecordUserLoginAsync(new UserLoginRecord { UserId = 0, Success = false, Time = DateTime.UtcNow, Message = $"Login failed for {SelectedUserName}: {ex.Message}" });
+                await _systemDatabaseService.RecordUserLoginAsync(new UserLoginRecord { UserId = 0, Success = false, Time = DateTime.UtcNow, Message = $"Login failed for {SelectedUserName}: {ex.Message}" });
                 _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = Lang.密码错误, Duration = 1 });
             }
         }
@@ -186,7 +191,7 @@ namespace TeamAAS_VP.ViewModels.User
             //获取所有用户
             try
             {
-                Users = _systemDb.GetAllUsersAsync().GetAwaiter().GetResult()?.ToList();
+                Users = _systemDatabaseService.GetAllUsersAsync().GetAwaiter().GetResult()?.ToList();
             }
             catch
             {
@@ -213,6 +218,19 @@ namespace TeamAAS_VP.ViewModels.User
                 IsRemember = true;
             }
         }
+
+        /// <summary>
+        /// 刷卡登录命令
+        /// </summary>
+        void ExecuteCardLoginCommand()
+        {
+            var cardLogin = _container.Resolve<CardLoginWindow>();
+            var result = cardLogin.ShowDialog();
+            if (result is bool st1 && !st1)
+            {
+                
+            }
+        }
         #endregion
     }
 }

+ 80 - 2
TeamAAS-VM/Views/SettingView.xaml

@@ -2176,8 +2176,7 @@
                                    HorizontalAlignment="Stretch" />
                     </StackPanel>
                 </TabItem.Header>
-                <StackPanel Orientation="Vertical"
-                            Margin="20">
+                <StackPanel Orientation="Vertical" Margin="20">
                     <Grid>
                         <Grid.ColumnDefinitions>
                             <ColumnDefinition Width="auto" />
@@ -2405,6 +2404,85 @@
                             </StackPanel>
                         </Button>
                     </Grid>
+                    
+                    <!--刷卡参数配置-->
+                    <GroupBox Grid.Row="5"
+                              Grid.ColumnSpan="2"
+                              Header="刷卡器配置"
+                              HorizontalAlignment="Left"
+                              MinWidth="400"
+                              Margin="0,12,0,0">
+                        <Grid Margin="10">
+                            <Grid.ColumnDefinitions>
+                                <ColumnDefinition Width="auto" />
+                                <ColumnDefinition Width="*" />
+                            </Grid.ColumnDefinitions>
+                            <Grid.RowDefinitions>
+                                <RowDefinition Height="Auto" />
+                                <RowDefinition Height="Auto" />
+                                <RowDefinition Height="Auto" />
+                                <RowDefinition Height="Auto" />
+                                <RowDefinition Height="Auto" />
+                                <RowDefinition Height="Auto" />
+                            </Grid.RowDefinitions>
+                            <TextBlock Text="PortName:"
+                                       Grid.Row="0"
+                                       Grid.Column="0"
+                                       HorizontalAlignment="Right" />
+                            <TextBox Text="{Binding CardReaderConfig.PortName,Mode=TwoWay}"
+                                     Grid.Row="0"
+                                     Grid.Column="1"
+                                     Margin="6,0" />
+                            <TextBlock Text="BaudRate:"
+                                       Grid.Row="1"
+                                       Grid.Column="0"
+                                       HorizontalAlignment="Right" />
+                            <TextBox Text="{Binding CardReaderConfig.BaudRate,Mode=TwoWay}"
+                                     Grid.Row="1"
+                                     Grid.Column="1"
+                                     Margin="6,0" />
+                            <TextBlock Text="Parity:"
+                                       Grid.Row="2"
+                                       Grid.Column="0"
+                                       HorizontalAlignment="Right" />
+                            <ComboBox Grid.Row="2"
+                                      Grid.Column="1"
+                                      SelectedItem="{Binding CardReaderConfig.Parity,Mode=TwoWay}"
+                                      ItemsSource="{Binding Source={StaticResource Parity}}" />
+                            <TextBlock Text="StopBits:"
+                                       Grid.Row="3"
+                                       Grid.Column="0"
+                                       HorizontalAlignment="Right" />
+                            <ComboBox Grid.Row="3"
+                                      Grid.Column="1"
+                                      SelectedItem="{Binding CardReaderConfig.StopBits,Mode=TwoWay}"
+                                      ItemsSource="{Binding Source={StaticResource StopBits}}" />
+                            <TextBlock Text="DataBits:"
+                                       Grid.Row="4"
+                                       Grid.Column="0"
+                                       HorizontalAlignment="Right" />
+                            <TextBox Text="{Binding CardReaderConfig.DataBits,Mode=TwoWay}"
+                                     Grid.Row="4"
+                                     Grid.Column="1"
+                                     Margin="6,0" />
+
+                            <Button Grid.Row="5"
+                                    Grid.Column="1"
+                                    Margin="0,6"
+                                    Style="{StaticResource MaterialDesignRaisedButton}"
+                                    materialDesign:ButtonAssist.CornerRadius="10"
+                                    MinWidth="120"
+                                    Command="{Binding SaveCardReaderConfigCommand}">
+                                <StackPanel Orientation="Horizontal"
+                                            HorizontalAlignment="Center">
+                                    <materialDesign:PackIcon Kind="ContentSaveCheck"
+                                                             Margin="0,0,6,0" />
+                                    <TextBlock VerticalAlignment="Center"
+                                               Text="保存刷卡器配置" />
+                                </StackPanel>
+                            </Button>
+                        </Grid>
+                    </GroupBox>
                 </StackPanel>
             </TabItem>
 

+ 25 - 20
TeamAAS-VM/Views/User/CardLoginWindow.xaml

@@ -1,6 +1,6 @@
 <Window x:Class="TeamAAS_VP.Views.User.CardLoginWindow"
-             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
         xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
@@ -15,6 +15,7 @@
         lex:ResxLocalizationProvider.DefaultDictionary="Lang"
         mc:Ignorable="d"
         d:DataContext="{d:DesignInstance Type=vm:CardLoginWindowViewModel}"
+        prism:ViewModelLocator.AutoWireViewModel="True"
         Background="Transparent"
         WindowState="Normal"
         WindowStyle="None"
@@ -51,6 +52,7 @@
                     FontWeight="Bold"
                     Width="32"
                     Height="32"
+                    Padding="0"
                     HorizontalAlignment="Right"
                     VerticalAlignment="Top"
                     Margin="0,20,18,0"
@@ -66,7 +68,7 @@
                        FontWeight="Bold" />
             <materialDesign:Transitioner Margin="20,110,20,20"
                                          AutoApplyTransitionOrigins="True"
-                                         d:SelectedIndex="0"
+                                         d:SelectedIndex="1"
                                          SelectedIndex="{Binding PageIndex}">
                 <materialDesign:TransitionerSlide OpeningEffect="{materialDesign:TransitionEffect FadeIn}">
                     <Grid Background="Transparent">
@@ -247,7 +249,8 @@
                                        Foreground="#2c3e50"
                                        FontWeight="SemiBold" />
                         </Grid>
-                        <Button Height="50"
+                        <Button x:Name="NameLoginButton"
+                                Height="50"
                                 Width="50"
                                 materialDesign:ButtonAssist.CornerRadius="5"
                                 HorizontalAlignment="Center"
@@ -287,16 +290,19 @@
                                FontSize="18"
                                FontWeight="Bold"
                                Text="用户名:" />
-                    <TextBox Grid.Row="0"
-                             Grid.Column="1"
-                             HorizontalAlignment="Left"
-                             VerticalAlignment="Center"
-                             Margin="20"
-                             Width="200"
-                             BorderThickness="1,1,1,1"
-                             FontSize="16"
-                             TextAlignment="Center"
-                             Text="{Binding Name}" />
+                    <ComboBox Grid.Row="0"
+                              Grid.Column="1"
+                              HorizontalAlignment="Left"
+                              VerticalAlignment="Center"
+                              Margin="20"
+                              Width="200"
+                              FontSize="16"
+                              materialDesign:HintAssist.Hint="{lex:Loc 用户}"
+                              HorizontalContentAlignment="Left"
+                              Style="{StaticResource MaterialDesignFloatingHintComboBox}"
+                              ItemsSource="{Binding UserNameList,Mode=TwoWay}"
+                              SelectedItem="{Binding SelectedUserName,Mode=TwoWay}">
+                    </ComboBox>
                     <TextBlock Grid.Row="1"
                                Grid.Column="0"
                                HorizontalAlignment="Left"
@@ -311,13 +317,12 @@
                                  VerticalAlignment="Center"
                                  Margin="20"
                                  Width="200"
-                                 HorizontalContentAlignment="Center"
+                                 HorizontalContentAlignment="Left"
                                  VerticalContentAlignment="Center"
-                                 BorderThickness="1,1,1,1"
                                  PasswordChar="*"
-                                 FontSize="16"
-                                 Padding="0,4,0,4"
-                                 materialDesign:HintAssist.HelperText="请输入用户登录密码"
+                                 Style="{StaticResource MaterialDesignFloatingHintPasswordBox}"
+                                 materialDesign:HintAssist.HelperText="{lex:Loc 请输入用户登录密码}"
+                                 materialDesign:HintAssist.Hint="{lex:Loc 密码}"
                                  materialDesign:TextFieldAssist.HasClearButton="True"
                                  materialDesign:PasswordBoxAssist.Password="{Binding Path=Password, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnExceptions=True}" />
                     <Button Grid.Row="2"
@@ -362,7 +367,7 @@
                     </Button>
                 </Grid>
             </materialDesign:Transitioner>
-
+            
         </Grid>
     </Border>
 </Window>

+ 14 - 0
TeamAAS-VM/Views/User/CardLoginWindow.xaml.cs

@@ -16,5 +16,19 @@ namespace TeamAAS_VP.Views.User
                 vm.View = this;
             };
         }
+
+        public CardLoginWindow(bool isCard)
+        {
+            InitializeComponent();
+            Loaded += (sender, e) =>
+            {
+                var vm = DataContext as ViewModels.User.CardLoginWindowViewModel;
+                vm.View = this;
+            };
+            if (isCard)
+            {
+                this.NameLoginButton.Visibility = Visibility.Collapsed;
+            }
+        }
     }
 }

+ 16 - 0
TeamAAS-VM/Views/User/LoginView.xaml

@@ -88,6 +88,22 @@
                                        Margin="20,0,0,0" />
                         </StackPanel>
                     </Button>
+                    <Button Grid.Row="4"
+                            Margin="0,55,0,0"
+                            Height="50"
+                            Width="50"
+                            materialDesign:ButtonAssist.CornerRadius="5"
+                            HorizontalAlignment="Center"
+                            VerticalAlignment="Center"
+                            ToolTip="刷卡登录"
+                            Padding="0"
+                            Command="{Binding CardLoginCommand}"
+                            Visibility="{Binding CardBtnVisibility}"
+                            IsEnabled="{Binding IsLogining,Converter={StaticResource InvertBooleanConverter}}">
+                        <Button.Content>
+                            <materialDesign:PackIcon Kind="CreditCardScanOutline" />
+                        </Button.Content>
+                    </Button>
                 </Grid>
             </materialDesign:Card>
         </Grid>