From d60bb6116c698269d405fce3040bdc75128c6820 Mon Sep 17 00:00:00 2001
From: chenluhua1980 <Chenluhua@qq.com>
Date: 星期二, 18 十一月 2025 10:57:21 +0800
Subject: [PATCH] 1.用户管理相关;
---
SourceCode/Bond/Servo/LoginDlg2.cpp | 98 +++++++++
SourceCode/Bond/Servo/Servo.vcxproj | 6
.gitignore | 1
SourceCode/Bond/Servo/resource.h | 0
SourceCode/Bond/Servo/CUserManager2Dlg.h | 26 ++
SourceCode/Bond/Servo/CUserManager2.cpp | 100 ++++++++++
SourceCode/Bond/Servo/Servo.cpp | 8
SourceCode/Bond/Servo/stdafx.h | 2
SourceCode/Bond/Servo/ServoDlg.cpp | 55 +++--
SourceCode/Bond/Servo/Servo.vcxproj.filters | 8
SourceCode/Bond/Servo/CUserManager2Dlg.cpp | 53 +++++
SourceCode/Bond/Servo/LoginDlg2.h | 30 +++
SourceCode/Bond/Servo/ToolUnits.cpp | 40 ++++
SourceCode/Bond/Servo/Servo.rc | 0
SourceCode/Bond/USERXLibrary/UserXAPI.h | 136 +++++++++++++
SourceCode/Bond/Servo/CUserManager2.h | 20 ++
SourceCode/Bond/Servo/ToolUnits.h | 2
17 files changed, 564 insertions(+), 21 deletions(-)
diff --git a/.gitignore b/.gitignore
index e97c776..b3c6aac 100644
--- a/.gitignore
+++ b/.gitignore
@@ -63,3 +63,4 @@
SourceCode/Bond/x64/Debug/HsmsPassive.cache
SourceCode/Bond/x64/Debug/MasterState.dat
SourceCode/Bond/x64/Debug/Recipe/EQ10_Unit0.recipelist
+SourceCode/Bond/UserX/
diff --git a/SourceCode/Bond/Servo/CUserManager2.cpp b/SourceCode/Bond/Servo/CUserManager2.cpp
new file mode 100644
index 0000000..e06165f
--- /dev/null
+++ b/SourceCode/Bond/Servo/CUserManager2.cpp
@@ -0,0 +1,100 @@
+#include "stdafx.h"
+#include "CUserManager2.h"
+#include "ToolUnits.h"
+#include <sstream>
+#include <cwchar>
+
+std::vector<std::wstring> SplitLines(const std::wstring& text)
+{
+ std::wstringstream ss(text); std::vector<std::wstring> v; std::wstring line; while (std::getline(ss, line)) v.push_back(line); return v;
+}
+
+template<typename Fn>
+std::wstring ReadBufferVia(Fn fn)
+{
+ int need = fn(nullptr, 0); if (need <= 0) return L"";
+ std::wstring buf; buf.resize((size_t)need);
+ int rc = fn(buf.data(), need);
+ if (rc == 0) { if (!buf.empty() && buf.back() == L'\0') buf.pop_back(); return buf; }
+ return L"";
+}
+
+// 获取单例实例
+CUserManager2& CUserManager2::getInstance() {
+ static CUserManager2 instance;
+ return instance;
+}
+
+CUserManager2::CUserManager2()
+{
+
+}
+
+CUserManager2::~CUserManager2()
+{
+
+}
+
+void CUserManager2::init(const char* pszDir)
+{
+ std::wstring dir = CToolUnits::AnsiToWString(std::string(pszDir));
+ UX_Init(dir.c_str());
+
+ wchar_t buffer[1024];
+ UX_GetUsers(buffer, 1024);
+ bool hasAny = false;
+ for (auto& ln : SplitLines(buffer)) { if (!ln.empty()) { hasAny = true; break; } }
+ if (!hasAny) {
+ const wchar_t* roles = L"Admin:100\nEngineer:50\nOperator:10\n";
+ (void)UX_SetRoleDefinitions(roles);
+ (void)UX_AddUser(L"admin", L"Administrator", L"admin123", L"Admin");
+ }
+}
+
+bool CUserManager2::login(const char* pszAccount, const char* pszPwd)
+{
+ std::wstring strUser, strPwd;
+ strUser = CToolUnits::AnsiToWString(std::string(pszAccount));
+ strPwd = CToolUnits::AnsiToWString(std::string(pszPwd));
+ int rc = UX_Login(strUser.c_str(), strPwd.c_str());
+ return rc == UX_OK;
+}
+
+bool CUserManager2::isLoggedIn()
+{
+ return UX_IsLoggedIn();
+}
+
+std::string CUserManager2::getCurrentUserName()
+{
+ std::string strName;
+
+ int need = UX_GetCurrentUser(nullptr, 0);
+ std::wstring buf; buf.resize((size_t)need);
+ if (UX_GetCurrentUser(buf.data(), need) == UX_OK) {
+ if (!buf.empty() && buf.back() == L'\0')
+ buf.pop_back();
+
+ strName = CToolUnits::WStringToAnsi(buf);
+ }
+
+ return strName;
+}
+
+bool CUserManager2::IsAdminCurrent()
+{
+ if (UX_IsLoggedIn() != 1) return false;
+ int need = UX_GetCurrentUser(nullptr, 0); if (need <= 0) return false;
+ std::wstring user; user.resize((size_t)need);
+ if (UX_GetCurrentUser(user.data(), need) != 0) return false;
+ if (!user.empty() && user.back() == L'\0') user.pop_back();
+ int maxLvl = 0; auto rolesTxt = ReadBufferVia([](wchar_t* b, int n) { return UX_GetRoles(b, n); });
+ for (auto& ln : SplitLines(rolesTxt)) { size_t p = ln.find(L':'); if (p != std::wstring::npos) { int lvl = _wtoi(ln.substr(p + 1).c_str()); if (lvl > maxLvl) maxLvl = lvl; } }
+ int myLvl = 0; auto usersTxt = ReadBufferVia([](wchar_t* b, int n) { return UX_GetUsers(b, n); });
+ for (auto& ln : SplitLines(usersTxt)) {
+ if (ln.empty()) continue; size_t p1 = ln.find(L','), p2 = ln.find(L',', p1 == std::wstring::npos ? 0 : p1 + 1), p3 = ln.find(L',', p2 == std::wstring::npos ? 0 : p2 + 1);
+ std::wstring name = (p1 == std::wstring::npos ? ln : ln.substr(0, p1)); if (name == user) { if (p2 != std::wstring::npos) { std::wstring lvlS = ln.substr(p2 + 1, (p3 == std::wstring::npos ? ln.size() : p3) - (p2 + 1)); myLvl = _wtoi(lvlS.c_str()); } break; }
+ }
+
+ return (maxLvl > 0) && (myLvl >= maxLvl);
+}
diff --git a/SourceCode/Bond/Servo/CUserManager2.h b/SourceCode/Bond/Servo/CUserManager2.h
new file mode 100644
index 0000000..7430b00
--- /dev/null
+++ b/SourceCode/Bond/Servo/CUserManager2.h
@@ -0,0 +1,20 @@
+#pragma once
+class CUserManager2
+{
+public:
+ static CUserManager2& getInstance();
+ CUserManager2(const CUserManager2&) = delete;
+ CUserManager2& operator=(const CUserManager2&) = delete;
+
+public:
+ void init(const char* pszDir);
+ bool login(const char* pszAccount, const char* pszPwd);
+ bool isLoggedIn();
+ std::string getCurrentUserName();
+ bool IsAdminCurrent();
+
+private:
+ CUserManager2();
+ ~CUserManager2();
+};
+
diff --git a/SourceCode/Bond/Servo/CUserManager2Dlg.cpp b/SourceCode/Bond/Servo/CUserManager2Dlg.cpp
new file mode 100644
index 0000000..7d47ecd
--- /dev/null
+++ b/SourceCode/Bond/Servo/CUserManager2Dlg.cpp
@@ -0,0 +1,53 @@
+锘�// CUserManager2Dlg.cpp: 瀹炵幇鏂囦欢
+//
+
+#include "stdafx.h"
+#include "Servo.h"
+#include "CUserManager2Dlg.h"
+#include "afxdialogex.h"
+
+
+// CUserManager2Dlg 瀵硅瘽妗�
+
+IMPLEMENT_DYNAMIC(CUserManager2Dlg, CDialogEx)
+
+CUserManager2Dlg::CUserManager2Dlg(CWnd* pParent /*=nullptr*/)
+ : CDialogEx(IDD_DIALOG_USER_MANAGER2, pParent)
+{
+
+}
+
+CUserManager2Dlg::~CUserManager2Dlg()
+{
+}
+
+void CUserManager2Dlg::DoDataExchange(CDataExchange* pDX)
+{
+ CDialogEx::DoDataExchange(pDX);
+}
+
+
+BEGIN_MESSAGE_MAP(CUserManager2Dlg, CDialogEx)
+ ON_WM_SIZE()
+END_MESSAGE_MAP()
+
+
+// CUserManager2Dlg 娑堟伅澶勭悊绋嬪簭
+
+
+BOOL CUserManager2Dlg::OnInitDialog()
+{
+ CDialogEx::OnInitDialog();
+
+ // TODO: 鍦ㄦ娣诲姞棰濆鐨勫垵濮嬪寲
+
+ return TRUE; // return TRUE unless you set the focus to a control
+ // 寮傚父: OCX 灞炴�ч〉搴旇繑鍥� FALSE
+}
+
+void CUserManager2Dlg::OnSize(UINT nType, int cx, int cy)
+{
+ CDialogEx::OnSize(nType, cx, cy);
+
+ // TODO: 鍦ㄦ澶勬坊鍔犳秷鎭鐞嗙▼搴忎唬鐮�
+}
diff --git a/SourceCode/Bond/Servo/CUserManager2Dlg.h b/SourceCode/Bond/Servo/CUserManager2Dlg.h
new file mode 100644
index 0000000..5085a9e
--- /dev/null
+++ b/SourceCode/Bond/Servo/CUserManager2Dlg.h
@@ -0,0 +1,26 @@
+锘�#pragma once
+
+
+// CUserManager2Dlg 瀵硅瘽妗�
+
+class CUserManager2Dlg : public CDialogEx
+{
+ DECLARE_DYNAMIC(CUserManager2Dlg)
+
+public:
+ CUserManager2Dlg(CWnd* pParent = nullptr); // 鏍囧噯鏋勯�犲嚱鏁�
+ virtual ~CUserManager2Dlg();
+
+// 瀵硅瘽妗嗘暟鎹�
+#ifdef AFX_DESIGN_TIME
+ enum { IDD = IDD_DIALOG_USER_MANAGER2 };
+#endif
+
+protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 鏀寔
+
+ DECLARE_MESSAGE_MAP()
+public:
+ virtual BOOL OnInitDialog();
+ afx_msg void OnSize(UINT nType, int cx, int cy);
+};
diff --git a/SourceCode/Bond/Servo/LoginDlg2.cpp b/SourceCode/Bond/Servo/LoginDlg2.cpp
new file mode 100644
index 0000000..ad613a9
--- /dev/null
+++ b/SourceCode/Bond/Servo/LoginDlg2.cpp
@@ -0,0 +1,98 @@
+锘�// LoginDlg.cpp: 瀹炵幇鏂囦欢
+//
+
+#include "stdafx.h"
+#include "Servo.h"
+#include "afxdialogex.h"
+#include "LoginDlg2.h"
+
+
+// CLoginDlg 瀵硅瘽妗�
+
+IMPLEMENT_DYNAMIC(CLoginDlg2, CDialogEx)
+
+CLoginDlg2::CLoginDlg2(CWnd* pParent /*=nullptr*/)
+ : CDialogEx(IDD_DIALOG_LOGIN, pParent)
+{
+}
+
+CLoginDlg2::~CLoginDlg2()
+{
+}
+
+void CLoginDlg2::DoDataExchange(CDataExchange* pDX)
+{
+ CDialogEx::DoDataExchange(pDX);
+}
+
+
+BEGIN_MESSAGE_MAP(CLoginDlg2, CDialogEx)
+ ON_BN_CLICKED(IDC_BUTTON_LOGIN, &CLoginDlg2::OnBnClickedLogin)
+ ON_STN_CLICKED(IDC_STATIC_CHANGE_PASSWORD, &CLoginDlg2::OnBnClickedChangePassword)
+END_MESSAGE_MAP()
+
+
+// CLoginDlg 娑堟伅澶勭悊绋嬪簭
+
+
+BOOL CLoginDlg2::OnInitDialog()
+{
+ CDialog::OnInitDialog();
+
+ // 璁剧疆绐楀彛鏍囬鍜屽垵濮嬪��
+ SetWindowText(_T("鐧诲綍"));
+
+
+ CStatic* pStaticImage = (CStatic*)GetDlgItem(IDC_STATIC_IMAGE);
+ ASSERT(pStaticImage);
+
+ CString strIconPath;
+ strIconPath.Format(_T("%s\\Res\\Operator_High_32.ico"), (LPTSTR)(LPCTSTR)theApp.m_strAppDir);
+ HICON hIcon = (HICON)::LoadImage(
+ nullptr,
+ strIconPath,
+ IMAGE_ICON,
+ 32, // 鍥炬爣瀹藉害
+ 32, // 鍥炬爣楂樺害
+ LR_LOADFROMFILE);
+ if (hIcon) {
+ // 璁剧疆 CStatic 鎺т欢涓哄浘鏍囨牱寮�
+ pStaticImage->ModifyStyle(0xF, SS_ICON);
+ pStaticImage->SetIcon(hIcon);
+ }
+
+ // 娣诲姞SS_NOTIFY鏍峰紡
+ CStatic* pStatic = (CStatic*)GetDlgItem(IDC_STATIC_CHANGE_PASSWORD);
+ if (pStatic != nullptr) {
+ pStatic->ModifyStyle(0, SS_NOTIFY);
+ }
+
+ GetDlgItem(IDC_CHECK_REMEMBER_PASSWORD)->ShowWindow(SW_HIDE);
+
+ return TRUE;
+}
+
+void CLoginDlg2::OnBnClickedLogin()
+{
+ GetDlgItemText(IDC_EDIT_USERNAME, m_strUsername);
+ GetDlgItemText(IDC_EDIT_PASSWORD, m_strPassword);
+
+ if (m_strUsername.IsEmpty()) {
+ AfxMessageBox(_T("璇疯緭鍏ョ敤鎴峰悕"));
+ GetDlgItem(IDC_EDIT_USERNAME)->SetFocus();
+ return;
+ }
+ if (m_strPassword.IsEmpty()) {
+ AfxMessageBox(_T("璇疯緭鍏ュ瘑鐮�"));
+ GetDlgItem(IDC_EDIT_PASSWORD)->SetFocus();
+ return;
+}
+
+
+ EndDialog(IDOK);
+}
+
+void CLoginDlg2::OnBnClickedChangePassword()
+{
+
+}
\ No newline at end of file
diff --git a/SourceCode/Bond/Servo/LoginDlg2.h b/SourceCode/Bond/Servo/LoginDlg2.h
new file mode 100644
index 0000000..335037d
--- /dev/null
+++ b/SourceCode/Bond/Servo/LoginDlg2.h
@@ -0,0 +1,30 @@
+锘�#pragma once
+#include "afxdialogex.h"
+
+
+// CLoginDlg 瀵硅瘽妗�
+
+class CLoginDlg2 : public CDialogEx
+{
+ DECLARE_DYNAMIC(CLoginDlg2)
+
+public:
+ CLoginDlg2(CWnd* pParent = nullptr); // 鏍囧噯鏋勯�犲嚱鏁�
+ virtual ~CLoginDlg2();
+
+// 瀵硅瘽妗嗘暟鎹�
+#ifdef AFX_DESIGN_TIME
+ enum { IDD = IDD_DIALOG_LOGIN };
+#endif
+
+public:
+ CString m_strUsername;
+ CString m_strPassword;
+
+protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 鏀寔
+ virtual BOOL OnInitDialog();
+ afx_msg void OnBnClickedLogin();
+ afx_msg void OnBnClickedChangePassword();
+ DECLARE_MESSAGE_MAP()
+};
diff --git a/SourceCode/Bond/Servo/Servo.cpp b/SourceCode/Bond/Servo/Servo.cpp
index 60c2b8a..f4f67b4 100644
--- a/SourceCode/Bond/Servo/Servo.cpp
+++ b/SourceCode/Bond/Servo/Servo.cpp
@@ -17,6 +17,8 @@
#include "MapPosWnd.h"
#include "HmTab.h"
#include "CControlJobManagerDlg.h"
+#include "ToolUnits.h"
+#include "CUserManager2.h"
// 澹版槑鍏ㄥ眬鍙橀噺锛岀敤浜庣鐞� GDI+ 鍒濆鍖�
@@ -100,6 +102,11 @@
m_strAppDir = CString(sDrive) + CString(sDir);
m_strAppFile = CString(sFilename);
m_model.setWorkDir((LPTSTR)(LPCTSTR)m_strAppDir);
+
+
+ // 鐢ㄦ埛鏁版嵁搴撶鐞�
+ CString strDir = m_strAppDir + _T("\\DB");
+ CUserManager2::getInstance().init((LPTSTR)(LPCTSTR)strDir);
// 娉ㄥ唽鎺т欢
@@ -233,6 +240,7 @@
m_model.term();
HSMS_Term();
RX_Term();
+ UX_Shutdown();
// 娓呯悊 GDI+
TermGDIPlus();
diff --git a/SourceCode/Bond/Servo/Servo.rc b/SourceCode/Bond/Servo/Servo.rc
index 5188bbb..aadc145 100644
--- a/SourceCode/Bond/Servo/Servo.rc
+++ b/SourceCode/Bond/Servo/Servo.rc
Binary files differ
diff --git a/SourceCode/Bond/Servo/Servo.vcxproj b/SourceCode/Bond/Servo/Servo.vcxproj
index 2e09825..31c7ea3 100644
--- a/SourceCode/Bond/Servo/Servo.vcxproj
+++ b/SourceCode/Bond/Servo/Servo.vcxproj
@@ -255,6 +255,8 @@
<ClInclude Include="CRobotTaskDlg.h" />
<ClInclude Include="CSVData.h" />
<ClInclude Include="CServoUtilsTool.h" />
+ <ClInclude Include="CUserManager2.h" />
+ <ClInclude Include="CUserManager2Dlg.h" />
<ClInclude Include="CVariable.h" />
<ClInclude Include="DeviceRecipeParamDlg.h" />
<ClInclude Include="GlassJson.h" />
@@ -280,6 +282,7 @@
<ClInclude Include="InputDialog.h" />
<ClInclude Include="JobSlotGrid.h" />
<ClInclude Include="LoginDlg.h" />
+ <ClInclude Include="LoginDlg2.h" />
<ClInclude Include="MsgDlg.h" />
<ClInclude Include="PageRecipe.h" />
<ClInclude Include="CDoubleGlass.h" />
@@ -468,6 +471,8 @@
<ClCompile Include="CRobotTaskDlg.cpp" />
<ClCompile Include="CSVData.cpp" />
<ClCompile Include="CServoUtilsTool.cpp" />
+ <ClCompile Include="CUserManager2.cpp" />
+ <ClCompile Include="CUserManager2Dlg.cpp" />
<ClCompile Include="CVariable.cpp" />
<ClCompile Include="DeviceRecipeParamDlg.cpp" />
<ClCompile Include="GlassJson.cpp" />
@@ -491,6 +496,7 @@
<ClCompile Include="InputDialog.cpp" />
<ClCompile Include="JobSlotGrid.cpp" />
<ClCompile Include="LoginDlg.cpp" />
+ <ClCompile Include="LoginDlg2.cpp" />
<ClCompile Include="MsgDlg.cpp" />
<ClCompile Include="PageRecipe.cpp" />
<ClCompile Include="CDoubleGlass.cpp" />
diff --git a/SourceCode/Bond/Servo/Servo.vcxproj.filters b/SourceCode/Bond/Servo/Servo.vcxproj.filters
index 8c439f7..a0fd9b9 100644
--- a/SourceCode/Bond/Servo/Servo.vcxproj.filters
+++ b/SourceCode/Bond/Servo/Servo.vcxproj.filters
@@ -227,6 +227,10 @@
<ClCompile Include="..\DAQBridge\proto\ProtocolCodec.cpp">
<Filter>DAQBridge</Filter>
</ClCompile>
+ <ClCompile Include="ClientListDlg.cpp" />
+ <ClCompile Include="LoginDlg2.cpp" />
+ <ClCompile Include="CUserManager2.cpp" />
+ <ClCompile Include="CUserManager2Dlg.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="AlarmManager.h" />
@@ -497,6 +501,10 @@
<ClInclude Include="..\DAQBridge\DAQConfig.h">
<Filter>DAQBridge</Filter>
</ClInclude>
+ <ClInclude Include="ClientListDlg.h" />
+ <ClInclude Include="LoginDlg2.h" />
+ <ClInclude Include="CUserManager2.h" />
+ <ClInclude Include="CUserManager2Dlg.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="Servo.rc" />
diff --git a/SourceCode/Bond/Servo/ServoDlg.cpp b/SourceCode/Bond/Servo/ServoDlg.cpp
index 8eaf56f..dd3206c 100644
--- a/SourceCode/Bond/Servo/ServoDlg.cpp
+++ b/SourceCode/Bond/Servo/ServoDlg.cpp
@@ -16,6 +16,7 @@
#include "CRobotCmdContainerDlg.h"
#include "CRobotCmdTestDlg.h"
#include "LoginDlg.h"
+#include "LoginDlg2.h"
#include "ChangePasswordDlg.h"
#include "UserManagerDlg.h"
#include "SystemLogManagerDlg.h"
@@ -30,6 +31,8 @@
#include "InputDialog.h"
#include "ClientListDlg.h"
#include "CControlJobManagerDlg.h"
+#include "CUserManager2.h"
+#include "CUserManager2Dlg.h"
#ifdef _DEBUG
@@ -44,7 +47,7 @@
#define TIMER_ID_UPDATE_RUMTIME 2
/* Test */
-#define TIMER_ID_TEST 3
+#define TIMER_ID_LOGIN 3
// 鐢ㄤ簬搴旂敤绋嬪簭鈥滃叧浜庘�濊彍鍗曢」鐨� CAboutDlg 瀵硅瘽妗�
@@ -197,7 +200,7 @@
else if (RX_CODE_MASTER_STATE_CHANGED == code) {
SERVO::MASTERSTATE state = theApp.m_model.getMaster().getState();
if (state == SERVO::MASTERSTATE::READY) {
- m_pTopToolbar->GetBtn(IDC_BUTTON_RUN)->EnableWindow(TRUE);
+ m_pTopToolbar ->GetBtn(IDC_BUTTON_RUN)->EnableWindow(TRUE);
m_pTopToolbar->GetBtn(IDC_BUTTON_RUN_BATCH)->EnableWindow(TRUE);
m_pTopToolbar->GetBtn(IDC_BUTTON_RUN_CT)->EnableWindow(TRUE);
m_pTopToolbar->GetBtn(IDC_BUTTON_STOP)->EnableWindow(FALSE);
@@ -368,7 +371,7 @@
// model init
theApp.m_model.init();
- SetTimer(TIMER_ID_TEST, 1000, nullptr);
+ SetTimer(TIMER_ID_LOGIN, 1000, nullptr);
// 鑿滃崟
CMenu menu;
@@ -935,11 +938,23 @@
m_pMyStatusbar->setRunTimeText((LPTSTR)(LPCTSTR)strText);
}
- else if(TIMER_ID_TEST == nIDEvent){
- static __int64 tttt = 0;
- tttt++;
- theApp.m_model.m_hsmsPassive.setVariableValue("CJobSpace", tttt % 10);
- theApp.m_model.m_hsmsPassive.setVariableValue("PJobSpace", tttt % 5);
+ else if(TIMER_ID_LOGIN == nIDEvent){
+ KillTimer(TIMER_ID_LOGIN);
+ if (!CUserManager2::getInstance().isLoggedIn()) {
+ CLoginDlg2 dlg;
+ if (dlg.DoModal() != IDOK) {
+ PostMessage(WM_CLOSE);
+ }
+ else {
+ bool bRet = CUserManager2::getInstance().login((LPTSTR)(LPCTSTR)dlg.m_strUsername,
+ (LPTSTR)(LPCTSTR)dlg.m_strPassword);
+ if (!bRet) {
+ AfxMessageBox("鐧诲綍澶辫触锛岃妫�鏌ョ敤鎴峰悕鎴栧瘑鐮佹槸鍚︽纭紒");
+ PostMessage(WM_CLOSE);
+ }
+ UpdateLoginStatus();
+ }
+ }
}
@@ -977,32 +992,24 @@
void CServoDlg::UpdateLoginStatus()
{
HMENU hMenu = m_pTopToolbar->GetOperatorMenu();
- UserManager& userManager = UserManager::getInstance();
- if (userManager.isLoggedIn())
- {
- ::EnableMenuItem(hMenu, ID_OPEATOR_LOGIN, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
- ::EnableMenuItem(hMenu, ID_OPERATOR_CHANGE_PASSWORD, MF_BYCOMMAND | MF_ENABLED);
+ CUserManager2& userManager = CUserManager2::getInstance();
+ if (userManager.isLoggedIn()) {
::EnableMenuItem(hMenu, ID_OPERATOR_SYSTEM_LOG, MF_BYCOMMAND | MF_ENABLED);
::EnableMenuItem(hMenu, ID_OPEATOR_SWITCH, MF_BYCOMMAND | MF_ENABLED);
- ::EnableMenuItem(hMenu, ID_OPERATOR_LOGOUT, MF_BYCOMMAND | MF_ENABLED);
- if (userManager.getCurrentUserRole() == UserRole::SuperAdmin) {
+ if (userManager.IsAdminCurrent()) {
::EnableMenuItem(hMenu, ID_OPEATOR_USER_MANAGER, MF_BYCOMMAND | MF_ENABLED);
}
else {
::EnableMenuItem(hMenu, ID_OPEATOR_USER_MANAGER, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
}
- m_pTopToolbar->SetOperatorBtnText(userManager.getCurrentUser().c_str());
+ m_pTopToolbar->SetOperatorBtnText(userManager.getCurrentUserName().c_str());
}
else {
- ::EnableMenuItem(hMenu, ID_OPEATOR_LOGIN, MF_BYCOMMAND | MF_ENABLED);
- ::EnableMenuItem(hMenu, ID_OPERATOR_CHANGE_PASSWORD, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
::EnableMenuItem(hMenu, ID_OPEATOR_USER_MANAGER, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
::EnableMenuItem(hMenu, ID_OPERATOR_SYSTEM_LOG, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
::EnableMenuItem(hMenu, ID_OPEATOR_SWITCH, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
- ::EnableMenuItem(hMenu, ID_OPERATOR_LOGOUT, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
-
m_pTopToolbar->SetOperatorBtnText(_T("鏈櫥褰�"));
}
}
@@ -1090,6 +1097,13 @@
}
else if (id == IDC_BUTTON_OPERATOR) {
int menuId = (int)wParam;
+ if (menuId == 0) {
+ CUserManager2Dlg dlg;
+ dlg.DoModal();
+ }
+
+
+ /*
SystemLogManager& logManager = SystemLogManager::getInstance();
UserManager& userManager = UserManager::getInstance();
if (menuId == 0) {
@@ -1138,6 +1152,7 @@
}
UpdateLoginStatus();
+ */
}
return 0;
diff --git a/SourceCode/Bond/Servo/ToolUnits.cpp b/SourceCode/Bond/Servo/ToolUnits.cpp
index 6d5df0d..974121c 100644
--- a/SourceCode/Bond/Servo/ToolUnits.cpp
+++ b/SourceCode/Bond/Servo/ToolUnits.cpp
@@ -574,4 +574,44 @@
std::ostringstream oss;
oss << std::put_time(&tm, "%Y%m%d%H%M%S"); // 例:2025-09-15 08:23:07
return oss.str();
+}
+
+std::wstring CToolUnits::AnsiToWString(const std::string& str)
+{
+ if (str.empty()) return std::wstring();
+
+ int len = ::MultiByteToWideChar(CP_ACP, 0,
+ str.c_str(), -1,
+ nullptr, 0);
+ if (len <= 0) return std::wstring();
+
+ std::wstring ws;
+ ws.resize(len - 1);
+
+ ::MultiByteToWideChar(CP_ACP, 0,
+ str.c_str(), -1,
+ &ws[0], len);
+
+ return ws;
+}
+
+std::string CToolUnits::WStringToAnsi(const std::wstring& wstr)
+{
+ if (wstr.empty()) return std::string();
+
+ int len = ::WideCharToMultiByte(CP_ACP, 0,
+ wstr.c_str(), -1,
+ nullptr, 0,
+ nullptr, nullptr);
+ if (len <= 0) return std::string();
+
+ std::string str;
+ str.resize(len - 1);
+
+ ::WideCharToMultiByte(CP_ACP, 0,
+ wstr.c_str(), -1,
+ &str[0], len,
+ nullptr, nullptr);
+
+ return str;
}
\ No newline at end of file
diff --git a/SourceCode/Bond/Servo/ToolUnits.h b/SourceCode/Bond/Servo/ToolUnits.h
index f88788d..7314ea8 100644
--- a/SourceCode/Bond/Servo/ToolUnits.h
+++ b/SourceCode/Bond/Servo/ToolUnits.h
@@ -60,5 +60,7 @@
const char* fmt = "%Y-%m-%d %H:%M:%S");
static std::string TimePointToLocalStringMs(const std::optional<TP>& tp);
static std::string NowStrSec();
+ static std::wstring AnsiToWString(const std::string& str);
+ static std::string WStringToAnsi(const std::wstring& wstr);
};
diff --git a/SourceCode/Bond/Servo/resource.h b/SourceCode/Bond/Servo/resource.h
index 0a875a6..4cf1ef2 100644
--- a/SourceCode/Bond/Servo/resource.h
+++ b/SourceCode/Bond/Servo/resource.h
Binary files differ
diff --git a/SourceCode/Bond/Servo/stdafx.h b/SourceCode/Bond/Servo/stdafx.h
index 8e4739a..36ba555 100644
--- a/SourceCode/Bond/Servo/stdafx.h
+++ b/SourceCode/Bond/Servo/stdafx.h
@@ -75,7 +75,7 @@
#include "..\RxWindows1.0\include\RxWindowsLib.h"
#include "..\HSMSSDK\Include\HSMSSDK.h"
-
+#include "..\UserXLibrary\UserXAPI.h"
#ifdef _UNICODE
diff --git a/SourceCode/Bond/USERXLibrary/UserXAPI.h b/SourceCode/Bond/USERXLibrary/UserXAPI.h
new file mode 100644
index 0000000..94e141a
--- /dev/null
+++ b/SourceCode/Bond/USERXLibrary/UserXAPI.h
@@ -0,0 +1,136 @@
+// UserX 用户管理库(C 接口)/ UserX user management library (C API)
+// 覆盖功能 / Features: users, roles, actions, auth, logs(固定 SQLite3 持久化 / SQLite3 persistence)
+
+#pragma once
+
+#if defined(_WIN32)
+# ifdef USERXLIBRARY_EXPORTS
+# define UX_API extern "C" __declspec(dllexport)
+# else
+# define UX_API extern "C" __declspec(dllimport)
+# endif
+#else
+# define UX_API extern "C"
+#endif
+
+#include <wchar.h>
+
+
+#ifdef _COMPILE_AS_LIB
+#warning "compiling as lib!"
+#else
+#ifdef _DEBUG
+#ifndef _WIN64
+#pragma comment(lib, "../USERXLibrary/lib/Win32/Debug/UserXLibrary.lib")
+#else
+#pragma comment(lib, "../USERXLibrary/lib/x64/Debug/UserXLibrary.lib")
+#endif
+#else
+#ifndef _WIN64
+#pragma comment(lib, "../USERXLibrary/lib/Win32/Release/UserXLibrary.lib")
+#else
+#pragma comment(lib, "../USERXLibrary/lib/x64/Release/UserXLibrary.lib")
+#endif
+#endif
+#endif // !BUILD_AS_LIB
+
+
+// 额外错误码 / Extra error code
+#ifndef UX_ERR_BAD_PASSWORD
+#define UX_ERR_BAD_PASSWORD -10 // 密码错误 / bad password
+#endif
+
+// 错误码宏定义 / Error code macros
+#define UX_OK 0 // 成功 / success
+#define UX_ERR_INVALID_ARGS -1 // 参数错误 / invalid arguments
+#define UX_ERR_NOT_FOUND -2 // 未找到 / not found
+#define UX_ERR_EXISTS -3 // 已存在 / already exists
+#define UX_ERR_PERMISSION -4 // 权限不足 / permission denied
+#define UX_ERR_NOT_LOGGED_IN -5 // 未登录 / not logged in
+#define UX_ERR_BUFFER_TOO_SMALL -6 // 缓冲区不足 / buffer too small
+#define UX_ERR_DB -7 // I/O 或数据库错误 / I/O or database error
+#define UX_ERR_NOT_DEFINED -8 // 未定义(如动作不存在)/ not defined
+#define UX_ERR_DB_NOT_EMPTY -9 // 数据库非空(已初始化)/ database not empty
+
+// 返回码 / Return codes(详见上方宏)
+// UX_OK, UX_ERR_INVALID_ARGS, UX_ERR_NOT_FOUND, UX_ERR_EXISTS,
+// UX_ERR_PERMISSION, UX_ERR_NOT_LOGGED_IN, UX_ERR_BUFFER_TOO_SMALL,
+// UX_ERR_DB, UX_ERR_NOT_DEFINED, UX_ERR_DB_NOT_EMPTY
+
+// 初始化:指定数据目录,内部将打开/创建 SQLite 数据库文件 UserX.db
+// Init: provide data directory; opens/creates SQLite DB file UserX.db
+UX_API int UX_Init(const wchar_t* storage_dir);
+
+// 可选:覆盖数据库路径(仅使用第一个参数作为 .db 文件路径,其他忽略)
+// Optional: override DB path (use first arg as .db path; others ignored)
+UX_API int UX_SetStorage(const wchar_t* users_db_path,
+ const wchar_t* /*unused_logs*/,
+ const wchar_t* /*unused_roles*/,
+ const wchar_t* /*unused_actions*/);
+
+// 配置角色(name:level 按行)/ Configure roles from lines "name:level"
+// 仅允许在“空数据库”(roles/users/actions/logs 四表均无数据)时调用;否则返回 -9。
+// Only allowed when DB is empty (roles/users/actions/logs all zero rows); otherwise returns -9.
+// e.g. L"Admin:100\nEngineer:50\nOperator:10\n"
+UX_API int UX_SetRoleDefinitions(const wchar_t* roles_text);
+
+// 获取角色列表(name:level 按行);buffer 为空或不足时返回所需大小
+// Get roles list as lines; returns required size if buffer is null/too small
+UX_API int UX_GetRoles(wchar_t* buffer, int buffer_chars);
+
+// 用户管理 / User management
+UX_API int UX_AddUser(const wchar_t* username,
+ const wchar_t* display_name,
+ const wchar_t* password,
+ const wchar_t* role_name);
+
+UX_API int UX_DeleteUser(const wchar_t* username);
+
+// 更新任意字段(传 nullptr 表示保持不变)/ Update subset; nullptr keeps field
+UX_API int UX_UpdateUser(const wchar_t* username,
+ const wchar_t* new_display_name,
+ const wchar_t* new_password,
+ const wchar_t* new_role_name,
+ int enabled /* -1 keep, 0 disable, 1 enable */);
+
+UX_API int UX_EnableUser(const wchar_t* username, int enabled /*0/1*/);
+UX_API int UX_ResetPassword(const wchar_t* username, const wchar_t* new_password);
+UX_API int UX_RenameUser(const wchar_t* username, const wchar_t* new_display_name);
+
+// 管理员权限:删除所有用户 / Admin-only
+UX_API int UX_DeleteAllUsers();
+
+// 获取用户列表(每行:username,display,level,enabled)/ Query users
+UX_API int UX_GetUsers(wchar_t* buffer, int buffer_chars);
+
+// 认证 / Authentication
+UX_API int UX_Login(const wchar_t* username, const wchar_t* password);
+UX_API void UX_Logout();
+UX_API int UX_IsLoggedIn();
+UX_API void UX_Shutdown(); // 释放资源 / shutdown and free resources
+UX_API int UX_GetCurrentUser(wchar_t* buffer, int buffer_chars);
+
+// 动作与权限 / Actions & permissions
+// 定义/覆盖动作(名称、描述、最低角色)/ Define/overwrite action
+UX_API int UX_DefineAction(const wchar_t* action_name,
+ const wchar_t* description,
+ const wchar_t* min_role_name);
+
+// 可执行返回1,不可执行返回0;负数为错误 / 1 allowed, 0 denied
+UX_API int UX_CanExecute(const wchar_t* action_name);
+
+// 记录动作到日志(时间、用户、动作、描述)/ Record action to logs
+UX_API int UX_RecordAction(const wchar_t* action_name);
+
+// 获取动作列表(每行:name,desc,minlevel)/ Get actions list
+UX_API int UX_GetActions(wchar_t* buffer, int buffer_chars);
+
+// 记录尝试(允许/拒绝)/ record an attempt with allowed flag (1 allowed, 0 denied)
+UX_API int UX_RecordAttempt(const wchar_t* action_name, int allowed /*1/0*/);
+
+// 查询最近 N 条日志(每行:ISO8601时间,用户名,动作,描述)/ Query logs
+UX_API int UX_QueryLogs(int last_n, wchar_t* buffer, int buffer_chars);
+
+// 根据错误码返回文字描述(中文/English)
+// Return a human-readable message for an error code
+UX_API const wchar_t* UX_ErrorMessage(int code);
--
Gitblit v1.9.3