refactor(session): expose WPF-compatible legacy state

This commit is contained in:
2026-07-29 14:09:00 +08:00
parent 4d907cf1dd
commit 6df28462be
4 changed files with 352 additions and 179 deletions
@@ -16,6 +16,10 @@ namespace Lskj.Main.Hosting
void RequestRelogin(); void RequestRelogin();
void RequestLock();
void RequestSubscriptRefresh();
void RequestExit(string message); void RequestExit(string message);
} }
} }
@@ -92,16 +92,58 @@ namespace Lskj.Main.Hosting
try try
{ {
Program.ShutdownMainProcess(); Manager.EndExternalSessionServices();
Manager.ExitSystem();
} }
finally finally
{ {
_mainProcessInitialized = false; try
_mainProcessShutdown = true; {
Manager.ExternalMainShell = null; 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();
}
} }
/// <summary> /// <summary>
@@ -111,6 +153,7 @@ namespace Lskj.Main.Hosting
public sealed partial class LegacyLoginRuntime public sealed partial class LegacyLoginRuntime
{ {
private DataTable _ledgerTable; private DataTable _ledgerTable;
private bool _connectionInitialized;
public LegacyLoginRuntime() public LegacyLoginRuntime()
{ {
@@ -175,11 +218,69 @@ namespace Lskj.Main.Hosting
public DataTable LoadLedgers() public DataTable LoadLedgers()
{ {
EnsureInitialConnection();
_ledgerTable = MainImpl.GetLedgerList() ?? new DataTable("Ledgers"); _ledgerTable = MainImpl.GetLedgerList() ?? new DataTable("Ledgers");
SelectedLedgerName = ResolveSelectedLedgerName(_ledgerTable); SelectedLedgerName = ResolveSelectedLedgerName(_ledgerTable);
return _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() public DataTable LoadUsers()
{ {
DataTable users = SystemInfo.Instance.DisplayUserCode DataTable users = SystemInfo.Instance.DisplayUserCode
@@ -220,6 +321,7 @@ namespace Lskj.Main.Hosting
string oldDataBook = DBConfig.Instance.DataBook; string oldDataBook = DBConfig.Instance.DataBook;
string oldSelectedLedgerName = SelectedLedgerName; string oldSelectedLedgerName = SelectedLedgerName;
string oldAccountBook = ERPInfo.Instance.AccountBook; string oldAccountBook = ERPInfo.Instance.AccountBook;
bool oldConnectionInitialized = _connectionInitialized;
try try
{ {
DBConfig.Instance.ServerName = serverName; DBConfig.Instance.ServerName = serverName;
@@ -238,10 +340,12 @@ namespace Lskj.Main.Hosting
} }
SystemInfo.RefreshSystemParam(); SystemInfo.RefreshSystemParam();
BaseResources.Localization(LocalizationType.CHS);
DataTable users = LoadUsers(); DataTable users = LoadUsers();
SelectedLedgerName = dataBook; SelectedLedgerName = dataBook;
ERPInfo.Instance.AccountBook = dataBook; ERPInfo.Instance.AccountBook = dataBook;
_connectionInitialized = true;
return users; return users;
} }
catch (Exception switchException) catch (Exception switchException)
@@ -251,6 +355,7 @@ namespace Lskj.Main.Hosting
DBConfig.Instance.DataBook = oldDataBook; DBConfig.Instance.DataBook = oldDataBook;
SelectedLedgerName = oldSelectedLedgerName; SelectedLedgerName = oldSelectedLedgerName;
ERPInfo.Instance.AccountBook = oldAccountBook; ERPInfo.Instance.AccountBook = oldAccountBook;
_connectionInitialized = oldConnectionInitialized;
try try
{ {
DBConfig.Instance.CreateConnection(DBConfig.Instance.Connection); DBConfig.Instance.CreateConnection(DBConfig.Instance.Connection);
@@ -488,11 +593,11 @@ namespace Lskj.Main.Hosting
ERPInfo.Instance.LanguageName = "中文"; ERPInfo.Instance.LanguageName = "中文";
LanguageTranslation.GetLanguageComparisonTable(); LanguageTranslation.GetLanguageComparisonTable();
TrySetDelphiParameters(); RefreshDelphiParameters();
PubUtil.ClearFilesInDirectory(PubUtil.ImageDownloadPath); PubUtil.ClearFilesInDirectory(PubUtil.ImageDownloadPath);
} }
private static void TrySetDelphiParameters() internal static void RefreshDelphiParameters()
{ {
try try
{ {
@@ -9,6 +9,7 @@ using Lskj.Business;
using Lskj.Business.Impl; using Lskj.Business.Impl;
using Lskj.Control.Model; using Lskj.Control.Model;
using Lskj.Core; using Lskj.Core;
using Lskj.Data;
using Lskj.Main.Model; using Lskj.Main.Model;
using Lskj.Model; using Lskj.Model;
using Lskj.Util; using Lskj.Util;
@@ -150,11 +151,13 @@ namespace Lskj.Main.Hosting
ValidateDatabase(candidate); ValidateDatabase(candidate);
ValidateDelphi(candidate); ValidateDelphi(candidate);
SystemInfo.RefreshSystemParam(); SystemInfo.RefreshSystemParam();
BaseResources.Localization(LocalizationType.CHS);
commit(); commit();
_ledgerTable = null; _ledgerTable = null;
SelectedLedgerName = candidate.AccountBookName; SelectedLedgerName = candidate.AccountBookName;
ERPInfo.Instance.AccountBook = candidate.AccountBookName; ERPInfo.Instance.AccountBook = candidate.AccountBookName;
_connectionInitialized = true;
return string.Empty; return string.Empty;
} }
catch (Exception exception) catch (Exception exception)
@@ -525,6 +528,7 @@ namespace Lskj.Main.Hosting
private string _delphiConnectionTemplate; private string _delphiConnectionTemplate;
private string _selectedLedgerName; private string _selectedLedgerName;
private string _accountBook; private string _accountBook;
private bool _connectionInitialized;
public static LegacyConnectionStateSnapshot Capture( public static LegacyConnectionStateSnapshot Capture(
LegacyLoginRuntime runtime) LegacyLoginRuntime runtime)
@@ -540,7 +544,8 @@ namespace Lskj.Main.Hosting
_delphiConnectionTemplate = _delphiConnectionTemplate =
DBConfig.Instance.dephiConnection, DBConfig.Instance.dephiConnection,
_selectedLedgerName = runtime.SelectedLedgerName, _selectedLedgerName = runtime.SelectedLedgerName,
_accountBook = ERPInfo.Instance.AccountBook _accountBook = ERPInfo.Instance.AccountBook,
_connectionInitialized = runtime._connectionInitialized
}; };
} }
@@ -556,6 +561,7 @@ namespace Lskj.Main.Hosting
_delphiConnectionTemplate; _delphiConnectionTemplate;
runtime.SelectedLedgerName = _selectedLedgerName; runtime.SelectedLedgerName = _selectedLedgerName;
runtime._ledgerTable = null; runtime._ledgerTable = null;
runtime._connectionInitialized = _connectionInitialized;
ERPInfo.Instance.AccountBook = _accountBook; ERPInfo.Instance.AccountBook = _accountBook;
try try
+230 -172
View File
@@ -59,6 +59,10 @@ namespace Lskj.Main.Model
/// 由外部启动程序提供的可选主界面。默认为 null,旧 Ls_ERP.exe 仍打开 FrmMain。 /// 由外部启动程序提供的可选主界面。默认为 null,旧 Ls_ERP.exe 仍打开 FrmMain。
/// </summary> /// </summary>
public static IExternalMainShell ExternalMainShell { get; internal set; } public static IExternalMainShell ExternalMainShell { get; internal set; }
private static readonly object SessionMonitorSync = new object();
private static CancellationTokenSource _sessionMonitorCancellation;
private static readonly List<Thread> SessionMonitorThreads =
new List<Thread>();
/// <summary> /// <summary>
/// 默认下载地址 /// 默认下载地址
/// </summary> /// </summary>
@@ -182,9 +186,7 @@ namespace Lskj.Main.Model
/// <param name="skipMenu">是否跳过子系统选择(适用于切换用户).</param> /// <param name="skipMenu">是否跳过子系统选择(适用于切换用户).</param>
public static void ReStartMain(bool skipMenu = false) public static void ReStartMain(bool skipMenu = false)
{ {
WhenConstraintLogin(); StartSessionMonitors();
LockApplication();
if (SystemInfo.Instance.SubscriptRefreshTime > 0 && !SystemInfo.Instance.RefreshNotify) RefreshSubscript();
if (_frmMain != null) if (_frmMain != null)
{ {
if (ERPInfo.Instance.WatermarkForm != null) if (ERPInfo.Instance.WatermarkForm != null)
@@ -205,7 +207,7 @@ namespace Lskj.Main.Model
{ {
// WPF 主框架已经提供顶部子系统导航,不再打开旧 FrmSubSystem。 // WPF 主框架已经提供顶部子系统导航,不再打开旧 FrmSubSystem。
// 优先保留当前仍有权限的子系统,否则选择第一个可用子系统。 // 优先保留当前仍有权限的子系统,否则选择第一个可用子系统。
isStart = SelectExternalMainShellSubSystem(); isStart = TrySelectExternalMainShellSubSystem();
} }
else if (ERPInfo.Instance.SubMenuCount > 1 && !skipMenu) else if (ERPInfo.Instance.SubMenuCount > 1 && !skipMenu)
{ {
@@ -634,8 +636,9 @@ namespace Lskj.Main.Model
} }
return dllName; return dllName;
} }
private static void ExitSystem() internal static void ExitSystem()
{ {
StopSessionMonitors();
try try
{ {
// 退出系统 // 退出系统
@@ -720,7 +723,7 @@ namespace Lskj.Main.Model
/// 为外部 WPF 主框架选择登录后的初始子系统。 /// 为外部 WPF 主框架选择登录后的初始子系统。
/// 旧 WinForms 入口仍由 FrmSubSystem 完成人工选择。 /// 旧 WinForms 入口仍由 FrmSubSystem 完成人工选择。
/// </summary> /// </summary>
private static bool SelectExternalMainShellSubSystem() internal static bool TrySelectExternalMainShellSubSystem()
{ {
string where = string.IsNullOrEmpty(ERPInfo.Instance.SeriesId) string where = string.IsNullOrEmpty(ERPInfo.Instance.SeriesId)
? string.Empty ? string.Empty
@@ -951,192 +954,247 @@ namespace Lskj.Main.Model
return isSuccess; return isSuccess;
} }
#endregion #endregion
/// <summary> internal static void BeginExternalSessionServices()
/// <para>说明:强制登录下线</para>
/// <para>创建人:唐德馨</para>
/// <para>创建日期:2023-10-16 </para>
/// <para>修改人:</para>
/// <para>修改日期:</para>
/// <para>修改备注:</para>
/// <para>版本:1.0</para>
/// </summary>
private static void WhenConstraintLogin()
{ {
Thread thread = new Thread(() => StartSessionMonitors();
}
internal static void EndExternalSessionServices()
{
StopSessionMonitors();
}
private static void StartSessionMonitors()
{
StopSessionMonitors();
CancellationTokenSource cancellation =
new CancellationTokenSource();
var threads = new List<Thread>();
if (SystemInfo.Instance.IsConstraintExit)
{ {
bool isClose = false; threads.Add(CreateSessionMonitor(
while (SystemInfo.Instance.IsConstraintExit) "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 = ""; if (!thread.Join(2000))
string clientip = ""; allStopped = false;
string loginMacAdress = ""; }
DataTable loginTable = new DataTable(); }
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 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')"); IExternalMainShell externalMainShell = ExternalMainShell;
hostName = SqlHelper.ExecuteScalar(string.Format("select hostname from p_LoginHostInfotab where OperatorId = '{0}' and Tagid = 1", ERPInfo.Instance.UserId)) + ""; if (externalMainShell != null &&
clientip = SqlHelper.ExecuteScalar(string.Format("select clientip from p_employeetab where employeeid = '{0}'", ERPInfo.Instance.UserId)) + ""; externalMainShell.IsOpen)
loginMacAdress = SqlHelper.ExecuteScalar(string.Format("select macAdress from p_employeetab where employeeid = '{0}'", ERPInfo.Instance.UserId)) + ""; {
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) 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(); if (token.WaitHandle.WaitOne(1000))
} return;
/// <summary> }
/// 锁定程序
/// </summary>
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();
} }
private static void MonitorApplicationLock(CancellationToken token)
/// <summary>
/// 刷新数量角标
/// </summary>
private static void RefreshSubscript()
{ {
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; externalMainShell.RequestLock();
if (_frmMain != null && _frmMain.Visible == true) return;
}
if (_frmMain != null && _frmMain.Visible)
{
_frmMain.Invoke(new Action(delegate
{ {
XtraTabPage tabPage = _frmMain.mainPanelControlEx.tabMain.SelectedTabPage; _frmMain.mainPanelControlEx.AwaitControl.BringToFront();
if (tabPage.TabIndex == 0) _frmMain.mainPanelControlEx.AwaitControl.Visible = true;
{ _frmMain.mainPanelControlEx.AwaitControl.OnFrmAwaitScreenLoad();
if (!SystemInfo.Instance.RefreshNotify) }));
{ }
Thread threadnew = new Thread(_frmMain.mainPanelControlEx.RefreshSubscript); }
threadnew.IsBackground = true; isAwaitTime += 1;
threadnew.Start(); 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);
} }
}); RefreshTime += 1;
thread.Start(); if (token.WaitHandle.WaitOne(60000))
return;
}
} }