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 RequestLock();
void RequestSubscriptRefresh();
void RequestExit(string message);
}
}
@@ -90,6 +90,13 @@ namespace Lskj.Main.Hosting
return;
}
try
{
Manager.EndExternalSessionServices();
Manager.ExitSystem();
}
finally
{
try
{
Program.ShutdownMainProcess();
@@ -104,6 +111,41 @@ namespace Lskj.Main.Hosting
}
}
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>
/// 向外部 WPF 登录页提供旧账套、用户、认证和会话状态写入能力。
/// 该类型不创建 WinForms 控件,也不引用 WPF。
@@ -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
{
@@ -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
+207 -149
View File
@@ -59,6 +59,10 @@ namespace Lskj.Main.Model
/// 由外部启动程序提供的可选主界面。默认为 null,旧 Ls_ERP.exe 仍打开 FrmMain。
/// </summary>
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>
@@ -182,9 +186,7 @@ namespace Lskj.Main.Model
/// <param name="skipMenu">是否跳过子系统选择(适用于切换用户).</param>
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 完成人工选择。
/// </summary>
private static bool SelectExternalMainShellSubSystem()
internal static bool TrySelectExternalMainShellSubSystem()
{
string where = string.IsNullOrEmpty(ERPInfo.Instance.SeriesId)
? string.Empty
@@ -951,142 +954,202 @@ namespace Lskj.Main.Model
return isSuccess;
}
#endregion
/// <summary>
/// <para>说明:强制登录下线</para>
/// <para>创建人:唐德馨</para>
/// <para>创建日期:2023-10-16 </para>
/// <para>修改人:</para>
/// <para>修改日期:</para>
/// <para>修改备注:</para>
/// <para>版本:1.0</para>
/// </summary>
private static void WhenConstraintLogin()
internal static void BeginExternalSessionServices()
{
Thread thread = new Thread(() =>
{
bool isClose = false;
while (SystemInfo.Instance.IsConstraintExit)
{
string hostName = "";
string clientip = "";
string loginMacAdress = "";
DataTable loginTable = new DataTable();
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)) + "";
StartSessionMonitors();
}
catch (Exception)
internal static void EndExternalSessionServices()
{
StopSessionMonitors();
}
//!string.IsNullOrEmpty(hostName) && loginTable.Select().Where(n => n["hostname"].Equals(hostName)).Count() > 0 && !loginMacAdress.Equals(ERPInfo.Instance.MacAddress)
if (!loginMacAdress.Equals(ERPInfo.Instance.MacAddress))
private static void StartSessionMonitors()
{
try
StopSessionMonitors();
CancellationTokenSource cancellation =
new CancellationTokenSource();
var threads = new List<Thread>();
if (SystemInfo.Instance.IsConstraintExit)
{
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;
threads.Add(CreateSessionMonitor(
"ConstraintLoginMonitor",
delegate { MonitorConstraintLogin(cancellation.Token); }));
}
}));
}
else if (ExternalMainShell != null && ExternalMainShell.IsOpen)
if (SystemInfo.Instance.AwaitTime > 10)
{
ExternalMainShell.RequestExit($"当前用户在另一电脑登录\r\nClientIp:{clientip}\r\nMacAdress:{loginMacAdress}\r\n当前系统即将关闭");
isClose = true;
threads.Add(CreateSessionMonitor(
"ApplicationLockMonitor",
delegate { MonitorApplicationLock(cancellation.Token); }));
}
else if (_frmMain != null && _frmMain.Visible == true)
if (SystemInfo.Instance.SubscriptRefreshTime > 0 &&
!SystemInfo.Instance.RefreshNotify)
{
_frmMain.Invoke(new Action(() =>
threads.Add(CreateSessionMonitor(
"SubscriptRefreshMonitor",
delegate { MonitorSubscriptRefresh(cancellation.Token); }));
}
lock (SessionMonitorSync)
{
if (!isClose)
{
_frmMain.Opacity = 0;
MessageUtil.Show($"当前用户在另一电脑登录\r\nClientIp:{clientip}\r\nMacAdress:{loginMacAdress}\r\n当前系统即将关闭");
isClose = true;
_sessionMonitorCancellation = cancellation;
SessionMonitorThreads.AddRange(threads);
isAwaitTime = 10;
RefreshTime = 0;
}
}));
}
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);
}
});
foreach (Thread thread in threads)
thread.Start();
}
/// <summary>
/// 锁定程序
/// </summary>
private static void LockApplication()
internal static void StopSessionMonitors()
{
Thread thread = new Thread(() =>
CancellationTokenSource cancellation;
Thread[] threads;
lock (SessionMonitorSync)
{
while (SystemInfo.Instance.AwaitTime > 10)
cancellation = _sessionMonitorCancellation;
_sessionMonitorCancellation = null;
threads = SessionMonitorThreads.ToArray();
SessionMonitorThreads.Clear();
}
if (cancellation == null)
return;
cancellation.Cancel();
bool allStopped = true;
foreach (Thread thread in threads)
{
if (isAwaitTime == SystemInfo.Instance.AwaitTime)
if (thread != null &&
thread != Thread.CurrentThread &&
thread.IsAlive)
{
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
{
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)
{
}
}
if (token.WaitHandle.WaitOne(1000))
return;
}
}
private static void MonitorApplicationLock(CancellationToken token)
{
while (SystemInfo.Instance.AwaitTime > 10 &&
!token.IsCancellationRequested)
{
if (isAwaitTime >= SystemInfo.Instance.AwaitTime)
{
isAwaitTime = 0;
if (_frmMain != null && _frmMain.Visible == true)
IExternalMainShell externalMainShell = ExternalMainShell;
if (externalMainShell != null && externalMainShell.IsOpen)
{
_frmMain.Invoke(new Action(() =>
externalMainShell.RequestLock();
return;
}
if (_frmMain != null && _frmMain.Visible)
{
_frmMain.Invoke(new Action(delegate
{
_frmMain.mainPanelControlEx.AwaitControl.BringToFront();
_frmMain.mainPanelControlEx.AwaitControl.Visible = true;
@@ -1095,48 +1158,43 @@ namespace Lskj.Main.Model
}
}
isAwaitTime += 1;
Thread.Sleep(1000);
if (token.WaitHandle.WaitOne(1000))
return;
}
});
thread.Start();
}
/// <summary>
/// 刷新数量角标
/// </summary>
private static void RefreshSubscript()
private static void MonitorSubscriptRefresh(CancellationToken token)
{
Thread thread = new Thread(() =>
{
while (SystemInfo.Instance.SubscriptRefreshTime > 0)
while (SystemInfo.Instance.SubscriptRefreshTime > 0 &&
!token.IsCancellationRequested)
{
if (RefreshTime >= SystemInfo.Instance.SubscriptRefreshTime)
{
RefreshTime = 0;
if (_frmMain != null && _frmMain.Visible == true)
IExternalMainShell externalMainShell = ExternalMainShell;
if (externalMainShell != null && externalMainShell.IsOpen)
{
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();
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);
if (token.WaitHandle.WaitOne(60000))
return;
}
});
thread.Start();
}