diff --git a/插件库/Lskj.Main/Hosting/IExternalMainShell.cs b/插件库/Lskj.Main/Hosting/IExternalMainShell.cs
new file mode 100644
index 0000000..16864f7
--- /dev/null
+++ b/插件库/Lskj.Main/Hosting/IExternalMainShell.cs
@@ -0,0 +1,21 @@
+using System.Windows.Forms;
+
+namespace Lskj.Main.Hosting
+{
+ ///
+ /// 旧启动流程与可选新主界面之间的中立扩展点。
+ /// 此接口只使用 .NET Framework 4.0/WinForms 基础类型,不引用 WPF 或 DevExpress 25.2。
+ ///
+ public interface IExternalMainShell
+ {
+ bool IsOpen { get; }
+
+ DialogResult ShowLoginDialog(object loginRuntime);
+
+ DialogResult ShowDialog();
+
+ void RequestRelogin();
+
+ void RequestExit(string message);
+ }
+}
diff --git a/插件库/Lskj.Main/Hosting/LegacyApplicationHost.cs b/插件库/Lskj.Main/Hosting/LegacyApplicationHost.cs
new file mode 100644
index 0000000..3bc8d05
--- /dev/null
+++ b/插件库/Lskj.Main/Hosting/LegacyApplicationHost.cs
@@ -0,0 +1,439 @@
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.Linq;
+using System.Text;
+using DevExpress.LookAndFeel;
+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;
+
+namespace Lskj.Main.Hosting
+{
+ ///
+ /// 为独立的新启动程序公开原 Ls_ERP 初始化和登录流程。
+ ///
+ public static class LegacyApplicationHost
+ {
+ public static void Run(string[] args, IExternalMainShell externalMainShell)
+ {
+ if (externalMainShell == null)
+ throw new ArgumentNullException("externalMainShell");
+ if (Manager.ExternalMainShell != null)
+ throw new InvalidOperationException("旧程序已经由另一个外部主界面托管。");
+
+ Manager.ExternalMainShell = externalMainShell;
+ try
+ {
+ Program.RunFromExternalHost(args);
+ }
+ finally
+ {
+ Manager.ExternalMainShell = null;
+ }
+ }
+ }
+
+ ///
+ /// 向外部 WPF 登录页提供旧账套、用户、认证和会话状态写入能力。
+ /// 该类型不创建 WinForms 控件,也不引用 WPF。
+ ///
+ public sealed class LegacyLoginRuntime
+ {
+ private DataTable _ledgerTable;
+
+ public LegacyLoginRuntime()
+ {
+ ERPInfo.Instance.LoginResult = false;
+ }
+
+ public string SelectedLedgerName { get; private set; }
+
+ public string LoginName
+ {
+ get { return DBConfig.Instance.LoginName ?? string.Empty; }
+ }
+
+ public bool RememberPasswordEnabled
+ {
+ get { return !SystemInfo.Instance.DisableRememberPassword; }
+ }
+
+ public DataTable LoadLedgers()
+ {
+ _ledgerTable = MainImpl.GetLedgerList() ?? new DataTable("Ledgers");
+ SelectedLedgerName = ResolveSelectedLedgerName(_ledgerTable);
+ return _ledgerTable;
+ }
+
+ public DataTable LoadUsers()
+ {
+ DataTable users = SystemInfo.Instance.DisplayUserCode
+ ? MainImpl.GetEmployeeListNew()
+ : MainImpl.GetEmployeeList();
+ return users ?? new DataTable("Users");
+ }
+
+ public DataTable SelectLedger(string ledgerName)
+ {
+ if (string.IsNullOrWhiteSpace(ledgerName))
+ throw new InvalidOperationException("请选择账套。");
+ if (_ledgerTable == null)
+ LoadLedgers();
+
+ DataRow ledger = _ledgerTable.Rows.Cast().FirstOrDefault(
+ row => string.Equals(
+ Value(row, "ShowName"),
+ ledgerName,
+ StringComparison.OrdinalIgnoreCase));
+ if (ledger == null)
+ throw new InvalidOperationException("未找到所选账套,请重新选择。");
+
+ string serverName = Value(ledger, "IP");
+ string database = Value(ledger, "DBName");
+ string dataBook = Value(ledger, "ShowName");
+ if (string.IsNullOrWhiteSpace(serverName) ||
+ string.IsNullOrWhiteSpace(database))
+ {
+ throw new InvalidOperationException(ResourceKeys.UnSetServerAddress);
+ }
+
+ string oldServerName = DBConfig.Instance.ServerName;
+ string oldDatabase = DBConfig.Instance.DataBase;
+ string oldDataBook = DBConfig.Instance.DataBook;
+ string oldSelectedLedgerName = SelectedLedgerName;
+ string oldAccountBook = ERPInfo.Instance.AccountBook;
+ try
+ {
+ DBConfig.Instance.ServerName = serverName;
+ DBConfig.Instance.DataBase = database;
+ DBConfig.Instance.DataBook = dataBook;
+
+ if (!DBConfig.Instance.CreateConnection(DBConfig.Instance.Connection))
+ throw new InvalidOperationException(ResourceKeys.ServerAddressFault);
+ if (!DBConfig.Instance.ServerType.Equals("达梦数据库") &&
+ DelphiHelper.Delphi_Init(new StringBuilder(
+ DBConfig.Instance.GetDelphiConnection(
+ DBConfig.Instance.dephiConnection))) == 0)
+ {
+ throw new InvalidOperationException(
+ ResourceKeys.UnConnectServer + "[By Delphi]");
+ }
+
+ SystemInfo.RefreshSystemParam();
+ DataTable users = LoadUsers();
+
+ SelectedLedgerName = dataBook;
+ ERPInfo.Instance.AccountBook = dataBook;
+ return users;
+ }
+ catch (Exception switchException)
+ {
+ DBConfig.Instance.ServerName = oldServerName;
+ DBConfig.Instance.DataBase = oldDatabase;
+ DBConfig.Instance.DataBook = oldDataBook;
+ SelectedLedgerName = oldSelectedLedgerName;
+ ERPInfo.Instance.AccountBook = oldAccountBook;
+ try
+ {
+ DBConfig.Instance.CreateConnection(DBConfig.Instance.Connection);
+ if (!DBConfig.Instance.ServerType.Equals("达梦数据库"))
+ {
+ DelphiHelper.Delphi_Init(new StringBuilder(
+ DBConfig.Instance.GetDelphiConnection(
+ DBConfig.Instance.dephiConnection)));
+ }
+ SystemInfo.RefreshSystemParam();
+ }
+ catch (Exception restoreException)
+ {
+ LogHelper.Instance.WriteError(restoreException);
+ }
+
+ LogHelper.Instance.WriteError(switchException);
+ throw;
+ }
+ }
+
+ public string LoadRememberedPassword(string loginName)
+ {
+ if (!RememberPasswordEnabled || string.IsNullOrWhiteSpace(loginName))
+ return null;
+
+ try
+ {
+ string encrypted = IniHelper.Read(
+ DBConfig.Instance.ServerName + loginName);
+ if (string.IsNullOrWhiteSpace(encrypted))
+ return null;
+
+ string[] parts = AESUtil.Decrypt(encrypted).Split('^');
+ bool remember;
+ if (parts.Length < 2 ||
+ !bool.TryParse(parts[0], out remember) ||
+ !remember)
+ {
+ return null;
+ }
+
+ return string.Join("^", parts.Skip(1).ToArray());
+ }
+ catch
+ {
+ return null;
+ }
+ }
+
+ public string Login(
+ string loginName,
+ string password,
+ bool rememberPassword)
+ {
+ ERPInfo.Instance.LoginResult = false;
+ if (string.IsNullOrWhiteSpace(loginName))
+ return ResourceKeys.UserNameNotNull;
+ if (password == null)
+ password = string.Empty;
+
+ try
+ {
+ DataTable users = MainImpl.GetEmployeeList();
+ string displayColumn = ResolveDisplayColumn(users);
+ List matches = users.Rows.Cast()
+ .Where(row =>
+ string.Equals(
+ Value(row, displayColumn),
+ loginName,
+ StringComparison.OrdinalIgnoreCase) ||
+ string.Equals(
+ Value(row, "UserCode"),
+ loginName,
+ StringComparison.OrdinalIgnoreCase))
+ .ToList();
+ if (matches.Count == 0)
+ return ResourceKeys.NameOrPasswordError;
+ if (matches.Count > 1)
+ return ResourceKeys.DuplicatedNameError;
+
+ DataRow user = matches[0];
+ string userId = Value(user, "UserId");
+ string userName = Value(user, "UserName");
+ string loginAccount = Value(user, "UserCode");
+ if (string.IsNullOrWhiteSpace(userId))
+ return ResourceKeys.UserNotFound;
+
+ ERPInfo.Instance.LoginResult = false;
+ if (SystemInfo.Instance.MacEnabled)
+ {
+ int macResult = MainImpl.CheckMacAddress(
+ ERPInfo.Instance.MacAddress,
+ userId);
+ MainImpl.LoginAfterRegister(
+ ERPInfo.Instance.MacAddress,
+ userId);
+ if (macResult == 0)
+ return ResourceKeys.LoginFault + ResourceKeys.UnKownMacAddress;
+ if (macResult == -1)
+ return ResourceKeys.LoginFault + ResourceKeys.UnKownMacAddressTable;
+ }
+
+ string keyError = VerifyEncryptionKey();
+ if (!string.IsNullOrEmpty(keyError))
+ return keyError;
+
+ if (!MainImpl.CheckingMacAddress(userId))
+ return ResourceKeys.MacAddressError +
+ ",当前地址:" + ERPInfo.Instance.MacAddress;
+
+ int loginResult = MainImpl.Login(userId, password, false);
+ if (loginResult != 0)
+ return LoginError(loginResult);
+
+ CompleteLogin(
+ userId,
+ userName,
+ loginAccount,
+ loginName,
+ password,
+ rememberPassword);
+ ERPInfo.Instance.LoginResult = true;
+ LogUtil.WriteDebug("", "登录软件", "进入操作", "系统登录");
+ return string.Empty;
+ }
+ catch (Exception exception)
+ {
+ ERPInfo.Instance.LoginResult = false;
+ LogUtil.WriteError(ResourceKeys.UserLogin, exception);
+ return ResourceKeys.LoginFault;
+ }
+ }
+
+ private static string VerifyEncryptionKey()
+ {
+ if (!SystemInfo.Instance.IsEncrypt)
+ return string.Empty;
+
+ int[] keyHandles = ERPInfo.Instance.keyHandles = new int[8];
+ int[] keyNumbers = ERPInfo.Instance.keyNumber = new int[8];
+ SmartX1Api.SmartX1Find(DBConfig.Instance.ServerName, keyHandles, keyNumbers);
+
+ int keyHandle = keyHandles[0];
+ int pin1 = Convert.ToInt32("0x987F6BCD", 16);
+ int pin2 = Convert.ToInt32("0xE193C5B2", 16);
+ int pin3 = Convert.ToInt32("0xD507CC28", 16);
+ int pin4 = Convert.ToInt32("0x4B125AF6", 16);
+ return SmartX1Api.SmartX1Open(keyHandle, pin1, pin2, pin3, pin4) == 0
+ ? string.Empty
+ : "U盾数据获取失败,请重试或联系管理员";
+ }
+
+ private void CompleteLogin(
+ string userId,
+ string userName,
+ string loginAccount,
+ string enteredLoginName,
+ string password,
+ bool rememberPassword)
+ {
+ if (!MainImpl.HasExistsColumn("p_employeetab", "MacAdress"))
+ BaseImpl.ExecSqlValue("alter table p_employeetab add MacAdress varchar(100)");
+ BaseImpl.ExecSqlValue(string.Format(
+ "update p_employeetab set MacAdress = '{0}' where employeeid='{1}'",
+ (ERPInfo.Instance.MacAddress ?? string.Empty).Replace("'", "''"),
+ userId.Replace("'", "''")));
+
+ if (!MainImpl.HasExistsColumn("p_employeetab", "ClientIp"))
+ BaseImpl.ExecSqlValue("alter table p_employeetab add ClientIp varchar(100)");
+ BaseImpl.ExecSqlValue(string.Format(
+ "update p_employeetab set ClientIp = '{0}' where employeeid='{1}'",
+ (ERPInfo.Instance.LoginIPV4 ?? string.Empty).Replace("'", "''"),
+ userId.Replace("'", "''")));
+
+ if (SystemInfo.Instance.AutoSystemDataFormat)
+ {
+ FormatSystemDatetime formatter = new FormatSystemDatetime();
+ formatter.SetDateTimeFormat();
+ }
+
+ string skinName = MainImpl.GetUserSkin(userId);
+ skinName = string.IsNullOrEmpty(skinName)
+ ? ERPInfo.Instance.SkinName
+ : skinName;
+ UserLookAndFeel.Default.SetSkinStyle(skinName);
+
+ IniHelper.Write(
+ DBConfig.Instance.ServerName + enteredLoginName,
+ AESUtil.Encrypt(rememberPassword + "^" + password));
+
+ ERPInfo.Instance.SeriesId = SystemInfo.Instance.seriesid;
+ ERPInfo.Instance.UserLinkPhone = MainImpl.GetUserPhone(userId);
+ ERPInfo.Instance.UserId = userId;
+ ERPInfo.Instance.UserName = userName;
+ ERPInfo.Instance.Password = SHAHelper.EncryptPassword(password);
+ ERPInfo.Instance.SkinName = skinName;
+ string accountBook = string.IsNullOrWhiteSpace(SelectedLedgerName)
+ ? DBConfig.Instance.DataBook
+ : SelectedLedgerName;
+ ERPInfo.Instance.AccountBook = accountBook;
+ ERPInfo.Instance.LoginAccount = loginAccount;
+ ERPInfo.Instance.InPassWord = password;
+ ERPInfo.Instance.PrimitiveBrowser = SystemInfo.Instance.PrimitiveBrowser;
+
+ DBConfig.Instance.LoginName = enteredLoginName;
+ DBConfig.Instance.NoticeUserID = userId;
+ DBConfig.Instance.NoticeUserName = userName;
+ DBConfig.Instance.DataBook = accountBook;
+ DBConfig.Instance.WriteConfig();
+
+ if (userName.Equals("管理员") &&
+ !string.IsNullOrWhiteSpace(loginAccount))
+ {
+ ERPInfo.Instance.Password = SqlHelper.ExecuteString(
+ "Password",
+ "select Password from P_EmployeeTab where LoginAccount='" +
+ loginAccount.Replace("'", "''") + "'");
+ }
+
+ ERPInfo.Instance.LanguageName = "中文";
+ LanguageTranslation.GetLanguageComparisonTable();
+ TrySetDelphiParameters();
+ PubUtil.ClearFilesInDirectory(PubUtil.ImageDownloadPath);
+ }
+
+ private static void TrySetDelphiParameters()
+ {
+ try
+ {
+ DelphiHelper.Delphi_SetParams(
+ Convert.ToInt32(ERPInfo.Instance.UserId),
+ string.IsNullOrWhiteSpace(ERPInfo.Instance.SubSysId)
+ ? 0
+ : Convert.ToInt32(ERPInfo.Instance.SubSysId),
+ new StringBuilder(ERPInfo.Instance.UserName),
+ new StringBuilder(ERPInfo.Instance.WindowName),
+ new StringBuilder(ERPInfo.Instance.SkinName));
+ }
+ catch (Exception exception)
+ {
+ LogHelper.Instance.WriteError(exception);
+ }
+ }
+
+ private static string LoginError(int loginResult)
+ {
+ switch (loginResult)
+ {
+ case 1:
+ return ResourceKeys.NameOrPasswordError;
+ case 2:
+ return ResourceKeys.AlreadyLogin;
+ case -2:
+ return ResourceKeys.MultiFailedLogin;
+ default:
+ return ResourceKeys.LoginFault;
+ }
+ }
+
+ private static string ResolveSelectedLedgerName(DataTable ledgers)
+ {
+ DataRow selected = ledgers.Rows.Cast().FirstOrDefault(
+ row => string.Equals(
+ Value(row, "DBName"),
+ DBConfig.Instance.DataBase,
+ StringComparison.OrdinalIgnoreCase));
+ if (selected == null && !string.IsNullOrWhiteSpace(DBConfig.Instance.DataBook))
+ {
+ selected = ledgers.Rows.Cast().FirstOrDefault(
+ row => string.Equals(
+ Value(row, "ShowName"),
+ DBConfig.Instance.DataBook,
+ StringComparison.OrdinalIgnoreCase));
+ }
+ if (selected == null)
+ selected = ledgers.Rows.Cast().FirstOrDefault();
+
+ return selected == null ? string.Empty : Value(selected, "ShowName");
+ }
+
+ private static string ResolveDisplayColumn(DataTable users)
+ {
+ string configured = SystemInfo.Instance.LoginUsername;
+ return !string.IsNullOrWhiteSpace(configured) &&
+ users.Columns.Contains(configured)
+ ? configured
+ : "UserName";
+ }
+
+ private static string Value(DataRow row, string columnName)
+ {
+ return row != null && row.Table.Columns.Contains(columnName)
+ ? row[columnName] + string.Empty
+ : string.Empty;
+ }
+ }
+}
diff --git a/插件库/Lskj.Main/Lskj.Main.csproj b/插件库/Lskj.Main/Lskj.Main.csproj
index 1bc8efc..355288c 100644
--- a/插件库/Lskj.Main/Lskj.Main.csproj
+++ b/插件库/Lskj.Main/Lskj.Main.csproj
@@ -276,6 +276,8 @@
+
+
diff --git a/插件库/Lskj.Main/Model/Manager.cs b/插件库/Lskj.Main/Model/Manager.cs
index de4de7b..2faece4 100644
--- a/插件库/Lskj.Main/Model/Manager.cs
+++ b/插件库/Lskj.Main/Model/Manager.cs
@@ -15,6 +15,7 @@ using Lskj.Control;
using Lskj.Control.Model;
using Lskj.Core;
using Lskj.Data;
+using Lskj.Main.Hosting;
using Lskj.Model;
using Lskj.Util;
using Lskj.Web.Core.Util;
@@ -55,6 +56,10 @@ namespace Lskj.Main.Model
public static int isAwaitTime = 10;
public static int RefreshTime = 0;
///
+ /// 由外部启动程序提供的可选主界面。默认为 null,旧 Ls_ERP.exe 仍打开 FrmMain。
+ ///
+ public static IExternalMainShell ExternalMainShell { get; internal set; }
+ ///
/// 默认下载地址
///
private static string filePath = string.Empty;
@@ -180,7 +185,13 @@ namespace Lskj.Main.Model
bool isOpenBs = false;
DialogResult result;
- if (ERPInfo.Instance.SubMenuCount > 1 && !skipMenu)
+ if (ExternalMainShell != null)
+ {
+ // WPF 主框架已经提供顶部子系统导航,不再打开旧 FrmSubSystem。
+ // 优先保留当前仍有权限的子系统,否则选择第一个可用子系统。
+ isStart = SelectExternalMainShellSubSystem();
+ }
+ else if (ERPInfo.Instance.SubMenuCount > 1 && !skipMenu)
{
// 进入子系统界面
result = RunSubSystemForm();
@@ -190,8 +201,19 @@ namespace Lskj.Main.Model
if (isStart)
{
// 直接进入主界面
- RunMainForm();
- if (ERPInfo.Instance.SubMenuCount > 1)
+ result = RunMainForm();
+ if (result == DialogResult.Retry)
+ {
+ StartForm();
+ return;
+ }
+ if (ExternalMainShell != null)
+ {
+ // 外部主界面关闭即结束本次 WPF 入口,不返回旧子系统选择页。
+ ExitSystem();
+ return;
+ }
+ else if (ERPInfo.Instance.SubMenuCount > 1)
{
ReStartMain();
}
@@ -653,6 +675,9 @@ namespace Lskj.Main.Model
/// DialogResult.
private static DialogResult RunLoginForm()
{
+ if (ExternalMainShell != null)
+ return ExternalMainShell.ShowLoginDialog(new LegacyLoginRuntime());
+
FrmLogin frmLogin = new FrmLogin();
return frmLogin.ShowDialog();
}
@@ -674,6 +699,50 @@ namespace Lskj.Main.Model
BsUrl = _frmSubSystem.BsUrl;
return dialogResult;
}
+
+ ///
+ /// 为外部 WPF 主框架选择登录后的初始子系统。
+ /// 旧 WinForms 入口仍由 FrmSubSystem 完成人工选择。
+ ///
+ private static bool SelectExternalMainShellSubSystem()
+ {
+ string where = string.IsNullOrEmpty(ERPInfo.Instance.SeriesId)
+ ? string.Empty
+ : string.Format("and SeriesId={0}", ERPInfo.Instance.SeriesId);
+ DataTable subSystems = MainImpl.GetSubSystems(where);
+ if (subSystems == null || subSystems.Rows.Count == 0)
+ {
+ MessageUtil.Show(ResourceKeys.SubSystemUnEnabled);
+ return false;
+ }
+
+ DataRow selectedRow = subSystems.AsEnumerable().FirstOrDefault(row =>
+ IsEnabledSubSystem(row) &&
+ string.Equals(
+ row["SubSysId"] + string.Empty,
+ ERPInfo.Instance.SubSysId,
+ StringComparison.OrdinalIgnoreCase));
+ if (selectedRow == null)
+ selectedRow = subSystems.AsEnumerable().FirstOrDefault(IsEnabledSubSystem);
+ if (selectedRow == null)
+ {
+ MessageUtil.Show(ResourceKeys.SubSystemUnEnabled);
+ return false;
+ }
+
+ ERPInfo.Instance.SubMenuCount = subSystems.AsEnumerable().Count(IsEnabledSubSystem);
+ ERPInfo.Instance.SubSysId = selectedRow["SubSysId"] + string.Empty;
+ ERPInfo.Instance.SubSysName = selectedRow["SubSysName"] + string.Empty;
+ return true;
+ }
+
+ private static bool IsEnabledSubSystem(DataRow row)
+ {
+ return row != null &&
+ row.Table.Columns.Contains("UseEd") &&
+ row["UseEd"] != DBNull.Value &&
+ Convert.ToBoolean(row["UseEd"]);
+ }
///
/// 说明:打开主程序
/// 创建人:龚宇超
@@ -686,6 +755,10 @@ namespace Lskj.Main.Model
/// DialogResult.
private static DialogResult RunMainForm()
{
+ IExternalMainShell externalMainShell = ExternalMainShell;
+ if (externalMainShell != null)
+ return externalMainShell.ShowDialog();
+
_frmMain = new FrmMain();
return _frmMain.ShowDialog();
}
@@ -909,6 +982,11 @@ namespace Lskj.Main.Model
}
}));
}
+ 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(() =>
@@ -953,7 +1031,7 @@ namespace Lskj.Main.Model
}
//记录登出日志
LogUtil.WriteDebug("", "退出软件", "软件退出", "系统登录");
- Process[] p = Process.GetProcessesByName("Ls_ERP");
+ Process[] p = GetApplicationProcesses();
foreach (Process item in p)
{
try
@@ -1107,6 +1185,12 @@ namespace Lskj.Main.Model
///
public static void ReLogin()
{
+ IExternalMainShell externalMainShell = ExternalMainShell;
+ if (externalMainShell != null && externalMainShell.IsOpen)
+ {
+ externalMainShell.RequestRelogin();
+ return;
+ }
if (_frmMain != null)
{
if (ERPInfo.Instance.WatermarkForm != null)
@@ -1121,5 +1205,16 @@ namespace Lskj.Main.Model
StartForm();
}
+ ///
+ /// 返回当前启动路线需要退出的主进程。
+ /// 旧入口保持原有 Ls_ERP 进程名语义,外部宿主只退出当前 WPF 进程。
+ ///
+ internal static Process[] GetApplicationProcesses()
+ {
+ return ExternalMainShell == null
+ ? Process.GetProcessesByName("Ls_ERP")
+ : new[] { Process.GetCurrentProcess() };
+ }
+
}
-}
\ No newline at end of file
+}