From 6df28462bedcf7bad200df26391267bb6a9456e8 Mon Sep 17 00:00:00 2001 From: SugarChes Date: Wed, 29 Jul 2026 14:09:00 +0800 Subject: [PATCH] refactor(session): expose WPF-compatible legacy state --- .../Lskj.Main/Hosting/IExternalMainShell.cs | 4 + .../Hosting/LegacyApplicationHost.cs | 117 ++++- .../LegacyLoginRuntime.ConnectionSettings.cs | 8 +- 插件库/Lskj.Main/Model/Manager.cs | 402 ++++++++++-------- 4 files changed, 352 insertions(+), 179 deletions(-) diff --git a/插件库/Lskj.Main/Hosting/IExternalMainShell.cs b/插件库/Lskj.Main/Hosting/IExternalMainShell.cs index 16864f7..6544f3a 100644 --- a/插件库/Lskj.Main/Hosting/IExternalMainShell.cs +++ b/插件库/Lskj.Main/Hosting/IExternalMainShell.cs @@ -16,6 +16,10 @@ namespace Lskj.Main.Hosting void RequestRelogin(); + void RequestLock(); + + void RequestSubscriptRefresh(); + void RequestExit(string message); } } diff --git a/插件库/Lskj.Main/Hosting/LegacyApplicationHost.cs b/插件库/Lskj.Main/Hosting/LegacyApplicationHost.cs index b920ab1..4282b22 100644 --- a/插件库/Lskj.Main/Hosting/LegacyApplicationHost.cs +++ b/插件库/Lskj.Main/Hosting/LegacyApplicationHost.cs @@ -92,16 +92,58 @@ namespace Lskj.Main.Hosting try { - Program.ShutdownMainProcess(); + Manager.EndExternalSessionServices(); + Manager.ExitSystem(); } finally { - _mainProcessInitialized = false; - _mainProcessShutdown = true; - Manager.ExternalMainShell = null; + try + { + Program.ShutdownMainProcess(); + } + finally + { + _mainProcessInitialized = false; + _mainProcessShutdown = true; + Manager.ExternalMainShell = null; + } } } } + + public static object CreateLoginRuntime() + { + return new LegacyLoginRuntime(); + } + + public static string PrepareAuthenticatedSession() + { + if (!ERPInfo.Instance.LoginResult) + return ResourceKeys.LoginFault; + + DataTable enabled = MainImpl.EnableSubSystem(); + ERPInfo.Instance.SubMenuCount = enabled == null + ? 0 + : enabled.Rows.Count; + if (!Manager.TrySelectExternalMainShellSubSystem()) + return ResourceKeys.SubSystemUnEnabled; + + LegacyLoginRuntime.RefreshDelphiParameters(); + Manager.BeginExternalSessionServices(); + return string.Empty; + } + + public static void CompleteAuthenticatedSession() + { + Manager.EndExternalSessionServices(); + } + + public static void ActivateSubSystem(string id, string caption) + { + ERPInfo.Instance.SubSysId = id ?? string.Empty; + ERPInfo.Instance.SubSysName = caption ?? string.Empty; + LegacyLoginRuntime.RefreshDelphiParameters(); + } } /// @@ -111,6 +153,7 @@ namespace Lskj.Main.Hosting public sealed partial class LegacyLoginRuntime { private DataTable _ledgerTable; + private bool _connectionInitialized; public LegacyLoginRuntime() { @@ -175,11 +218,69 @@ namespace Lskj.Main.Hosting public DataTable LoadLedgers() { + EnsureInitialConnection(); _ledgerTable = MainImpl.GetLedgerList() ?? new DataTable("Ledgers"); SelectedLedgerName = ResolveSelectedLedgerName(_ledgerTable); return _ledgerTable; } + private void EnsureInitialConnection() + { + if (_connectionInitialized) + return; + + if (string.Equals( + IniHelper.Read(SystemResourcesIniName, ConnectionModeKey), + "1", + StringComparison.Ordinal)) + { + int port; + string host = IniHelper.Read( + SystemResourcesIniName, + DirectLastHostKey); + string name = IniHelper.Read( + SystemResourcesIniName, + DirectLastNameKey); + if (!int.TryParse( + IniHelper.Read( + SystemResourcesIniName, + DirectLastPortKey), + out port)) + { + throw new InvalidOperationException( + "保存的直连端口无效,请重新设置连接。"); + } + + string error = ApplyDirectConnection(host, port, name); + if (!string.IsNullOrWhiteSpace(error)) + throw new InvalidOperationException(error); + } + else + { + if (!DBConfig.Instance.CreateConnection( + DBConfig.Instance.Connection)) + { + throw new InvalidOperationException( + ResourceKeys.UnConnectServer); + } + if (!string.Equals( + DBConfig.Instance.ServerType, + "达梦数据库", + StringComparison.Ordinal) && + DelphiHelper.Delphi_Init(new StringBuilder( + DBConfig.Instance.GetDelphiConnection( + DBConfig.Instance.dephiConnection))) == 0) + { + throw new InvalidOperationException( + ResourceKeys.UnConnectServer + "[By Delphi]"); + } + SystemInfo.RefreshSystemParam(); + } + + BaseResources.Localization(LocalizationType.CHS); + _connectionInitialized = true; + } + public DataTable LoadUsers() { DataTable users = SystemInfo.Instance.DisplayUserCode @@ -220,6 +321,7 @@ namespace Lskj.Main.Hosting string oldDataBook = DBConfig.Instance.DataBook; string oldSelectedLedgerName = SelectedLedgerName; string oldAccountBook = ERPInfo.Instance.AccountBook; + bool oldConnectionInitialized = _connectionInitialized; try { DBConfig.Instance.ServerName = serverName; @@ -238,10 +340,12 @@ namespace Lskj.Main.Hosting } SystemInfo.RefreshSystemParam(); + BaseResources.Localization(LocalizationType.CHS); DataTable users = LoadUsers(); SelectedLedgerName = dataBook; ERPInfo.Instance.AccountBook = dataBook; + _connectionInitialized = true; return users; } catch (Exception switchException) @@ -251,6 +355,7 @@ namespace Lskj.Main.Hosting DBConfig.Instance.DataBook = oldDataBook; SelectedLedgerName = oldSelectedLedgerName; ERPInfo.Instance.AccountBook = oldAccountBook; + _connectionInitialized = oldConnectionInitialized; try { DBConfig.Instance.CreateConnection(DBConfig.Instance.Connection); @@ -488,11 +593,11 @@ namespace Lskj.Main.Hosting ERPInfo.Instance.LanguageName = "中文"; LanguageTranslation.GetLanguageComparisonTable(); - TrySetDelphiParameters(); + RefreshDelphiParameters(); PubUtil.ClearFilesInDirectory(PubUtil.ImageDownloadPath); } - private static void TrySetDelphiParameters() + internal static void RefreshDelphiParameters() { try { diff --git a/插件库/Lskj.Main/Hosting/LegacyLoginRuntime.ConnectionSettings.cs b/插件库/Lskj.Main/Hosting/LegacyLoginRuntime.ConnectionSettings.cs index 8856719..4acf479 100644 --- a/插件库/Lskj.Main/Hosting/LegacyLoginRuntime.ConnectionSettings.cs +++ b/插件库/Lskj.Main/Hosting/LegacyLoginRuntime.ConnectionSettings.cs @@ -9,6 +9,7 @@ using Lskj.Business; using Lskj.Business.Impl; using Lskj.Control.Model; using Lskj.Core; +using Lskj.Data; using Lskj.Main.Model; using Lskj.Model; using Lskj.Util; @@ -150,11 +151,13 @@ namespace Lskj.Main.Hosting ValidateDatabase(candidate); ValidateDelphi(candidate); SystemInfo.RefreshSystemParam(); + BaseResources.Localization(LocalizationType.CHS); commit(); _ledgerTable = null; SelectedLedgerName = candidate.AccountBookName; ERPInfo.Instance.AccountBook = candidate.AccountBookName; + _connectionInitialized = true; return string.Empty; } catch (Exception exception) @@ -525,6 +528,7 @@ namespace Lskj.Main.Hosting private string _delphiConnectionTemplate; private string _selectedLedgerName; private string _accountBook; + private bool _connectionInitialized; public static LegacyConnectionStateSnapshot Capture( LegacyLoginRuntime runtime) @@ -540,7 +544,8 @@ namespace Lskj.Main.Hosting _delphiConnectionTemplate = DBConfig.Instance.dephiConnection, _selectedLedgerName = runtime.SelectedLedgerName, - _accountBook = ERPInfo.Instance.AccountBook + _accountBook = ERPInfo.Instance.AccountBook, + _connectionInitialized = runtime._connectionInitialized }; } @@ -556,6 +561,7 @@ namespace Lskj.Main.Hosting _delphiConnectionTemplate; runtime.SelectedLedgerName = _selectedLedgerName; runtime._ledgerTable = null; + runtime._connectionInitialized = _connectionInitialized; ERPInfo.Instance.AccountBook = _accountBook; try diff --git a/插件库/Lskj.Main/Model/Manager.cs b/插件库/Lskj.Main/Model/Manager.cs index 99e2fd5..2a81be4 100644 --- a/插件库/Lskj.Main/Model/Manager.cs +++ b/插件库/Lskj.Main/Model/Manager.cs @@ -59,6 +59,10 @@ namespace Lskj.Main.Model /// 由外部启动程序提供的可选主界面。默认为 null,旧 Ls_ERP.exe 仍打开 FrmMain。 /// public static IExternalMainShell ExternalMainShell { get; internal set; } + private static readonly object SessionMonitorSync = new object(); + private static CancellationTokenSource _sessionMonitorCancellation; + private static readonly List SessionMonitorThreads = + new List(); /// /// 默认下载地址 /// @@ -182,9 +186,7 @@ namespace Lskj.Main.Model /// 是否跳过子系统选择(适用于切换用户). public static void ReStartMain(bool skipMenu = false) { - WhenConstraintLogin(); - LockApplication(); - if (SystemInfo.Instance.SubscriptRefreshTime > 0 && !SystemInfo.Instance.RefreshNotify) RefreshSubscript(); + StartSessionMonitors(); if (_frmMain != null) { if (ERPInfo.Instance.WatermarkForm != null) @@ -205,7 +207,7 @@ namespace Lskj.Main.Model { // WPF 主框架已经提供顶部子系统导航,不再打开旧 FrmSubSystem。 // 优先保留当前仍有权限的子系统,否则选择第一个可用子系统。 - isStart = SelectExternalMainShellSubSystem(); + isStart = TrySelectExternalMainShellSubSystem(); } else if (ERPInfo.Instance.SubMenuCount > 1 && !skipMenu) { @@ -634,8 +636,9 @@ namespace Lskj.Main.Model } return dllName; } - private static void ExitSystem() + internal static void ExitSystem() { + StopSessionMonitors(); try { // 退出系统 @@ -720,7 +723,7 @@ namespace Lskj.Main.Model /// 为外部 WPF 主框架选择登录后的初始子系统。 /// 旧 WinForms 入口仍由 FrmSubSystem 完成人工选择。 /// - private static bool SelectExternalMainShellSubSystem() + internal static bool TrySelectExternalMainShellSubSystem() { string where = string.IsNullOrEmpty(ERPInfo.Instance.SeriesId) ? string.Empty @@ -951,192 +954,247 @@ namespace Lskj.Main.Model return isSuccess; } #endregion - /// - /// 说明:强制登录下线 - /// 创建人:唐德馨 - /// 创建日期:2023-10-16 - /// 修改人: - /// 修改日期: - /// 修改备注: - /// 版本:1.0 - /// - private static void WhenConstraintLogin() + internal static void BeginExternalSessionServices() { - Thread thread = new Thread(() => + StartSessionMonitors(); + } + + internal static void EndExternalSessionServices() + { + StopSessionMonitors(); + } + + private static void StartSessionMonitors() + { + StopSessionMonitors(); + + CancellationTokenSource cancellation = + new CancellationTokenSource(); + var threads = new List(); + if (SystemInfo.Instance.IsConstraintExit) { - bool isClose = false; - while (SystemInfo.Instance.IsConstraintExit) + threads.Add(CreateSessionMonitor( + "ConstraintLoginMonitor", + delegate { MonitorConstraintLogin(cancellation.Token); })); + } + if (SystemInfo.Instance.AwaitTime > 10) + { + threads.Add(CreateSessionMonitor( + "ApplicationLockMonitor", + delegate { MonitorApplicationLock(cancellation.Token); })); + } + if (SystemInfo.Instance.SubscriptRefreshTime > 0 && + !SystemInfo.Instance.RefreshNotify) + { + threads.Add(CreateSessionMonitor( + "SubscriptRefreshMonitor", + delegate { MonitorSubscriptRefresh(cancellation.Token); })); + } + + lock (SessionMonitorSync) + { + _sessionMonitorCancellation = cancellation; + SessionMonitorThreads.AddRange(threads); + isAwaitTime = 10; + RefreshTime = 0; + } + foreach (Thread thread in threads) + thread.Start(); + } + + internal static void StopSessionMonitors() + { + CancellationTokenSource cancellation; + Thread[] threads; + lock (SessionMonitorSync) + { + cancellation = _sessionMonitorCancellation; + _sessionMonitorCancellation = null; + threads = SessionMonitorThreads.ToArray(); + SessionMonitorThreads.Clear(); + } + + if (cancellation == null) + return; + + cancellation.Cancel(); + bool allStopped = true; + foreach (Thread thread in threads) + { + if (thread != null && + thread != Thread.CurrentThread && + thread.IsAlive) { - string hostName = ""; - string clientip = ""; - string loginMacAdress = ""; - DataTable loginTable = new DataTable(); + if (!thread.Join(2000)) + allStopped = false; + } + } + if (allStopped) + cancellation.Dispose(); + } + + private static Thread CreateSessionMonitor( + string name, + ThreadStart monitor) + { + return new Thread(monitor) + { + Name = name, + IsBackground = true + }; + } + + private static void MonitorConstraintLogin(CancellationToken token) + { + while (SystemInfo.Instance.IsConstraintExit && + !token.IsCancellationRequested) + { + string clientip = string.Empty; + string loginMacAdress = string.Empty; + try + { + clientip = SqlHelper.ExecuteScalar(string.Format( + "select clientip from p_employeetab where employeeid = '{0}'", + ERPInfo.Instance.UserId)) + string.Empty; + loginMacAdress = SqlHelper.ExecuteScalar(string.Format( + "select macAdress from p_employeetab where employeeid = '{0}'", + ERPInfo.Instance.UserId)) + string.Empty; + } + catch (Exception) + { + } + + if (!string.IsNullOrWhiteSpace(loginMacAdress) && + !loginMacAdress.Equals(ERPInfo.Instance.MacAddress)) + { + string message = string.Format( + "当前用户在另一电脑登录\r\nClientIp:{0}\r\nMacAdress:{1}\r\n当前系统即将关闭", + clientip, + loginMacAdress); try { - loginTable = SqlHelper.ExecuteDataTable("select rtrim(ltrim(substring(hostname,1,100))) as hostname from master.dbo.sysprocesses where loginame = 'lserpAdmin' and (program_name = '' or program_name = '.Net SqlClient Data Provider')"); - hostName = SqlHelper.ExecuteScalar(string.Format("select hostname from p_LoginHostInfotab where OperatorId = '{0}' and Tagid = 1", ERPInfo.Instance.UserId)) + ""; - clientip = SqlHelper.ExecuteScalar(string.Format("select clientip from p_employeetab where employeeid = '{0}'", ERPInfo.Instance.UserId)) + ""; - loginMacAdress = SqlHelper.ExecuteScalar(string.Format("select macAdress from p_employeetab where employeeid = '{0}'", ERPInfo.Instance.UserId)) + ""; + IExternalMainShell externalMainShell = ExternalMainShell; + if (externalMainShell != null && + externalMainShell.IsOpen) + { + externalMainShell.RequestExit(message); + return; + } + + bool isClose = false; + if (_frmSubSystem != null && _frmSubSystem.Visible) + { + _frmSubSystem.Invoke(new Action(delegate + { + _frmSubSystem.Opacity = 0; + MessageUtil.Show(message); + isClose = true; + })); + } + else if (_frmMain != null && _frmMain.Visible) + { + _frmMain.Invoke(new Action(delegate + { + _frmMain.Opacity = 0; + MessageUtil.Show(message); + isClose = true; + })); + } + + if (isClose) + { + ExitSystem(); + LogUtil.WriteDebug( + string.Empty, + "退出软件", + "软件退出", + "系统登录"); + foreach (Process item in GetApplicationProcesses()) + { + try + { + item.Kill(); + } + catch (Exception) + { + } + } + Application.Exit(); + return; + } } catch (Exception) { } - //!string.IsNullOrEmpty(hostName) && loginTable.Select().Where(n => n["hostname"].Equals(hostName)).Count() > 0 && !loginMacAdress.Equals(ERPInfo.Instance.MacAddress) - if (!loginMacAdress.Equals(ERPInfo.Instance.MacAddress)) - { - try - { - if (_frmSubSystem != null && _frmSubSystem.Visible == true) - { - _frmSubSystem.Invoke(new Action(() => - { - if (!isClose) - { - _frmSubSystem.Opacity = 0; - MessageUtil.Show($"当前用户在另一电脑登录\r\nClientIp:{clientip}\r\nMacAdress:{loginMacAdress}\r\n当前系统即将关闭"); - isClose = true; - } - })); - } - else if (ExternalMainShell != null && ExternalMainShell.IsOpen) - { - ExternalMainShell.RequestExit($"当前用户在另一电脑登录\r\nClientIp:{clientip}\r\nMacAdress:{loginMacAdress}\r\n当前系统即将关闭"); - isClose = true; - } - else if (_frmMain != null && _frmMain.Visible == true) - { - _frmMain.Invoke(new Action(() => - { - if (!isClose) - { - _frmMain.Opacity = 0; - MessageUtil.Show($"当前用户在另一电脑登录\r\nClientIp:{clientip}\r\nMacAdress:{loginMacAdress}\r\n当前系统即将关闭"); - isClose = true; - } - })); - } - if (isClose) - { - if (DBConfig.Instance.NoticeExit) - { - Process[] p1 = Process.GetProcessesByName("Ls_Notice"); - foreach (Process item in p1) - { - try - { - item.Kill(); - } - catch (Exception) - { - } - } - if (!string.IsNullOrWhiteSpace(SystemInfo.Instance.QuickMenuId)) - { - Process[] p2 = Process.GetProcessesByName("Lskj.QuickModule"); - foreach (Process item in p2) - { - try - { - item.Kill(); - } - catch (Exception) - { - } - } - } - } - //记录登出日志 - LogUtil.WriteDebug("", "退出软件", "软件退出", "系统登录"); - Process[] p = GetApplicationProcesses(); - foreach (Process item in p) - { - try - { - item.Kill(); - } - catch (Exception) - { - } - } - //Environment.Exit(0); - Application.Exit(); - break; - } - } - catch (Exception) - { - } - } - Thread.Sleep(1000); } - }); - thread.Start(); - } - /// - /// 锁定程序 - /// - private static void LockApplication() - { - Thread thread = new Thread(() => - { - while (SystemInfo.Instance.AwaitTime > 10) - { - if (isAwaitTime == SystemInfo.Instance.AwaitTime) - { - isAwaitTime = 0; - if (_frmMain != null && _frmMain.Visible == true) - { - _frmMain.Invoke(new Action(() => - { - _frmMain.mainPanelControlEx.AwaitControl.BringToFront(); - _frmMain.mainPanelControlEx.AwaitControl.Visible = true; - _frmMain.mainPanelControlEx.AwaitControl.OnFrmAwaitScreenLoad(); - })); - } - } - isAwaitTime += 1; - Thread.Sleep(1000); - } - }); - thread.Start(); + + if (token.WaitHandle.WaitOne(1000)) + return; + } } - - - - - - /// - /// 刷新数量角标 - /// - private static void RefreshSubscript() + private static void MonitorApplicationLock(CancellationToken token) { - Thread thread = new Thread(() => + while (SystemInfo.Instance.AwaitTime > 10 && + !token.IsCancellationRequested) { - while (SystemInfo.Instance.SubscriptRefreshTime > 0) + if (isAwaitTime >= SystemInfo.Instance.AwaitTime) { - if (RefreshTime >= SystemInfo.Instance.SubscriptRefreshTime) + isAwaitTime = 0; + IExternalMainShell externalMainShell = ExternalMainShell; + if (externalMainShell != null && externalMainShell.IsOpen) { - RefreshTime = 0; - if (_frmMain != null && _frmMain.Visible == true) + externalMainShell.RequestLock(); + return; + } + if (_frmMain != null && _frmMain.Visible) + { + _frmMain.Invoke(new Action(delegate { - XtraTabPage tabPage = _frmMain.mainPanelControlEx.tabMain.SelectedTabPage; - if (tabPage.TabIndex == 0) - { - if (!SystemInfo.Instance.RefreshNotify) - { - Thread threadnew = new Thread(_frmMain.mainPanelControlEx.RefreshSubscript); - threadnew.IsBackground = true; - threadnew.Start(); - } - } + _frmMain.mainPanelControlEx.AwaitControl.BringToFront(); + _frmMain.mainPanelControlEx.AwaitControl.Visible = true; + _frmMain.mainPanelControlEx.AwaitControl.OnFrmAwaitScreenLoad(); + })); + } + } + isAwaitTime += 1; + if (token.WaitHandle.WaitOne(1000)) + return; + } + } + + private static void MonitorSubscriptRefresh(CancellationToken token) + { + while (SystemInfo.Instance.SubscriptRefreshTime > 0 && + !token.IsCancellationRequested) + { + if (RefreshTime >= SystemInfo.Instance.SubscriptRefreshTime) + { + RefreshTime = 0; + IExternalMainShell externalMainShell = ExternalMainShell; + if (externalMainShell != null && externalMainShell.IsOpen) + { + externalMainShell.RequestSubscriptRefresh(); + } + else if (_frmMain != null && _frmMain.Visible) + { + XtraTabPage tabPage = + _frmMain.mainPanelControlEx.tabMain.SelectedTabPage; + if (tabPage != null && + tabPage.TabIndex == 0 && + !SystemInfo.Instance.RefreshNotify) + { + Thread refreshThread = new Thread( + _frmMain.mainPanelControlEx.RefreshSubscript); + refreshThread.IsBackground = true; + refreshThread.Start(); } } - RefreshTime += 1; - Thread.Sleep(60000); } - }); - thread.Start(); + RefreshTime += 1; + if (token.WaitHandle.WaitOne(60000)) + return; + } }