From fcc340fc812ee692f72fa1774c114e6f4d788f5c Mon Sep 17 00:00:00 2001
From: chenluhua1980 <Chenluhua@qq.com>
Date: 星期二, 18 十一月 2025 14:33:14 +0800
Subject: [PATCH] 1.实现用户管理。

---
 SourceCode/Bond/Servo/Servo.vcxproj             |    4 
 SourceCode/Bond/Servo/Servo.vcxproj.filters     |    4 
 SourceCode/Bond/Servo/CUserManager2Dlg.cpp      |  299 +++++++++++++++++++++++++-
 SourceCode/Bond/Servo/resource.h                |    0 
 SourceCode/Bond/Servo/CUserManager2Dlg.h        |   29 ++
 SourceCode/Bond/BLControlsSDK/include/BLLabel.h |    2 
 SourceCode/Bond/Servo/CUserManager2.cpp         |  120 ++++++++++
 SourceCode/Bond/Servo/Servo.rc                  |    0 
 SourceCode/Bond/Servo/ServoDlg.cpp              |   15 +
 SourceCode/Bond/Servo/CUserEdit2Dlg.cpp         |  125 +++++++++++
 SourceCode/Bond/Servo/CUserManager2.h           |   28 ++
 SourceCode/Bond/Servo/CUserEdit2Dlg.h           |   23 ++
 12 files changed, 625 insertions(+), 24 deletions(-)

diff --git a/SourceCode/Bond/BLControlsSDK/include/BLLabel.h b/SourceCode/Bond/BLControlsSDK/include/BLLabel.h
index 88ff5d0..5089fa8 100644
--- a/SourceCode/Bond/BLControlsSDK/include/BLLabel.h
+++ b/SourceCode/Bond/BLControlsSDK/include/BLLabel.h
@@ -1,4 +1,4 @@
-#if !defined(AFX_BLLABEL_H__A4EABEC5_2E8C_11D1_B79F_00805F9ECE10__INCLUDED_)
+锘�#if !defined(AFX_BLLABEL_H__A4EABEC5_2E8C_11D1_B79F_00805F9ECE10__INCLUDED_)
 #define AFX_BLLABEL_H__A4EABEC5_2E8C_11D1_B79F_00805F9ECE10__INCLUDED_
 
 #if _MSC_VER >= 1000
diff --git a/SourceCode/Bond/Servo/CUserEdit2Dlg.cpp b/SourceCode/Bond/Servo/CUserEdit2Dlg.cpp
new file mode 100644
index 0000000..7237f5d
--- /dev/null
+++ b/SourceCode/Bond/Servo/CUserEdit2Dlg.cpp
@@ -0,0 +1,125 @@
+锘�#include "stdafx.h"
+#include "CUserEdit2Dlg.h"
+#include "CUserManager2.h"
+#include "resource.h"
+
+IMPLEMENT_DYNAMIC(CUserEdit2Dlg, CDialogEx)
+
+CUserEdit2Dlg::CUserEdit2Dlg(bool editMode, CWnd* pParent /*=nullptr*/)
+	: CDialogEx(IDD_DIALOG_USER_EDIT2, pParent)
+{
+	m_bEditMode = editMode;
+}
+
+CUserEdit2Dlg::~CUserEdit2Dlg()
+{
+}
+
+void CUserEdit2Dlg::DoDataExchange(CDataExchange* pDX)
+{
+	CDialogEx::DoDataExchange(pDX);
+	DDX_Text(pDX, IDC_EDIT_USER_ACCOUNT, m_strUsername);
+	DDX_Text(pDX, IDC_EDIT_USER_DISPLAY, m_strDisplayName);
+	DDX_Text(pDX, IDC_EDIT_USER_PASSWORD, m_strPassword);
+	DDX_CBString(pDX, IDC_COMBO_USER_ROLE, m_strRole);
+	DDX_Check(pDX, IDC_CHECK_USER_ENABLED, m_bEnabled);
+}
+
+BEGIN_MESSAGE_MAP(CUserEdit2Dlg, CDialogEx)
+END_MESSAGE_MAP()
+
+BOOL CUserEdit2Dlg::OnInitDialog()
+{
+	CDialogEx::OnInitDialog();
+
+	if (m_bEditMode) {
+		if (auto pEdit = GetDlgItem(IDC_EDIT_USER_ACCOUNT)) {
+			pEdit->EnableWindow(FALSE);
+		}
+	}
+
+	UpdateData(FALSE);
+
+	auto roles = CUserManager2::getInstance().getRoles();
+	CComboBox* pCombo = (CComboBox*)GetDlgItem(IDC_COMBO_USER_ROLE);
+	if (pCombo) {
+		int selected = -1;
+		for (const auto& role : roles) {
+			CString text(role.name.c_str());
+			int idx = pCombo->AddString(text);
+			if (selected == -1 && m_strRole.CompareNoCase(text) == 0) {
+				selected = idx;
+			}
+		}
+
+		if (selected >= 0) {
+			pCombo->SetCurSel(selected);
+		}
+		else if (pCombo->GetCount() > 0) {
+			pCombo->SetCurSel(0);
+			CString text;
+			pCombo->GetLBText(0, text);
+			if (m_strRole.IsEmpty()) {
+				m_strRole = text;
+			}
+		}
+	}
+
+	if (auto pPwd = GetDlgItem(IDC_EDIT_USER_PASSWORD)) {
+		pPwd->EnableWindow(!m_bEditMode);
+		if (m_bEditMode) {
+			pPwd->SetWindowText(_T(""));
+		}
+	}
+
+	return TRUE;
+}
+
+void CUserEdit2Dlg::OnOK()
+{
+	UpdateData(TRUE);
+
+	CString user = m_strUsername;
+	user.Trim();
+	CString role = m_strRole;
+	role.Trim();
+
+	CString password = m_strPassword;
+	password.Trim();
+
+	if (m_bEditMode) {
+		password.Empty();
+	}
+
+	if (!m_bEditMode) {
+		if (user.IsEmpty()) {
+			AfxMessageBox(_T("璇疯緭鍏ヨ处鍙�"));
+			return;
+		}
+
+		if (password.IsEmpty()) {
+			AfxMessageBox(_T("璇疯緭鍏ュ瘑鐮�"));
+			return;
+		}
+	}
+
+	if (role.IsEmpty()) {
+		AfxMessageBox(_T("璇烽�夋嫨瑙掕壊"));
+		return;
+	}
+
+	if (auto pCombo = (CComboBox*)GetDlgItem(IDC_COMBO_USER_ROLE)) {
+		int sel = pCombo->GetCurSel();
+		if (sel != CB_ERR) {
+			CString text;
+			pCombo->GetLBText(sel, text);
+			if (!text.IsEmpty()) {
+				m_strRole = text;
+			}
+		}
+	}
+
+	m_strUsername = user;
+	m_strPassword = password;
+	CDialogEx::OnOK();
+}
diff --git a/SourceCode/Bond/Servo/CUserEdit2Dlg.h b/SourceCode/Bond/Servo/CUserEdit2Dlg.h
new file mode 100644
index 0000000..e61e745
--- /dev/null
+++ b/SourceCode/Bond/Servo/CUserEdit2Dlg.h
@@ -0,0 +1,23 @@
+#pragma once
+
+class CUserEdit2Dlg : public CDialogEx
+{
+	DECLARE_DYNAMIC(CUserEdit2Dlg)
+
+public:
+	CUserEdit2Dlg(bool editMode = false, CWnd* pParent = nullptr);
+	virtual ~CUserEdit2Dlg();
+
+	CString m_strUsername;
+	CString m_strDisplayName;
+	CString m_strPassword;
+	CString m_strRole;
+	BOOL m_bEnabled = TRUE;
+	bool m_bEditMode = false;
+
+protected:
+	virtual void DoDataExchange(CDataExchange* pDX);
+	virtual BOOL OnInitDialog();
+	afx_msg void OnOK();
+	DECLARE_MESSAGE_MAP()
+};
diff --git a/SourceCode/Bond/Servo/CUserManager2.cpp b/SourceCode/Bond/Servo/CUserManager2.cpp
index e06165f..25912eb 100644
--- a/SourceCode/Bond/Servo/CUserManager2.cpp
+++ b/SourceCode/Bond/Servo/CUserManager2.cpp
@@ -1,12 +1,33 @@
 #include "stdafx.h"
 #include "CUserManager2.h"
 #include "ToolUnits.h"
+#include <vector>
+#include <map>
+#include <utility>
 #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;
+}
+
+std::vector<std::wstring> SplitByDelimiter(const std::wstring& text, wchar_t delimiter)
+{
+	std::vector<std::wstring> parts;
+	size_t start = 0;
+	while (start <= text.length()) {
+		size_t pos = text.find(delimiter, start);
+		if (pos == std::wstring::npos) {
+			parts.push_back(text.substr(start));
+			break;
+		}
+
+		parts.push_back(text.substr(start, pos - start));
+		start = pos + 1;
+	}
+
+	return parts;
 }
 
 template<typename Fn>
@@ -98,3 +119,102 @@
 
 	return (maxLvl > 0) && (myLvl >= maxLvl);
 }
+
+std::vector<CUserManager2::RoleInfo> CUserManager2::getRoles()
+{
+	std::vector<RoleInfo> roles;
+	auto txt = ReadBufferVia([](wchar_t* b, int n) { return UX_GetRoles(b, n); });
+	if (txt.empty()) {
+		return roles;
+	}
+
+	for (auto& line : SplitLines(txt)) {
+		if (line.empty()) continue;
+		size_t pos = line.find(L':');
+		RoleInfo info;
+		info.name = (pos == std::wstring::npos) ? line : line.substr(0, pos);
+		if (pos != std::wstring::npos) {
+			info.level = _wtoi(line.substr(pos + 1).c_str());
+		}
+
+		if (!info.name.empty()) {
+			roles.push_back(std::move(info));
+		}
+	}
+
+	return roles;
+}
+
+std::vector<CUserManager2::UserInfo> CUserManager2::getUsers()
+{
+	std::vector<UserInfo> users;
+	auto txt = ReadBufferVia([](wchar_t* b, int n) { return UX_GetUsers(b, n); });
+	if (txt.empty()) {
+		return users;
+	}
+
+	std::map<int, std::wstring> roleMap;
+	for (auto& role : getRoles()) {
+		roleMap[role.level] = role.name;
+	}
+
+	for (auto& line : SplitLines(txt)) {
+		if (line.empty()) continue;
+		auto parts = SplitByDelimiter(line, L',');
+		UserInfo info;
+		if (!parts.empty()) info.userName = parts[0];
+		if (parts.size() > 1) info.displayName = parts[1];
+		if (parts.size() > 2) info.roleLevel = _wtoi(parts[2].c_str());
+		if (parts.size() > 3) info.enabled = (_wtoi(parts[3].c_str()) != 0);
+		auto it = roleMap.find(info.roleLevel);
+		if (it != roleMap.end()) {
+			info.roleName = it->second;
+		}
+		users.push_back(std::move(info));
+	}
+
+	return users;
+}
+
+int CUserManager2::addUser(const std::wstring& userName, const std::wstring& displayName,
+	const std::wstring& password, const std::wstring& roleName, bool enabled)
+{
+	int rc = UX_AddUser(userName.c_str(), displayName.c_str(), password.c_str(), roleName.c_str());
+	if (rc == UX_OK && !enabled) {
+		UX_EnableUser(userName.c_str(), 0);
+	}
+
+	return rc;
+}
+
+int CUserManager2::updateUser(const std::wstring& userName, const std::wstring& displayName,
+	const std::wstring& password, const std::wstring& roleName, bool enabled)
+{
+	const wchar_t* disp = displayName.empty() ? nullptr : displayName.c_str();
+	const wchar_t* pwd = password.empty() ? nullptr : password.c_str();
+	const wchar_t* role = roleName.empty() ? nullptr : roleName.c_str();
+	return UX_UpdateUser(userName.c_str(), disp, pwd, role, enabled ? 1 : 0);
+}
+
+int CUserManager2::deleteUser(const std::wstring& userName)
+{
+	return UX_DeleteUser(userName.c_str());
+}
+
+int CUserManager2::setUserEnabled(const std::wstring& userName, bool enabled)
+{
+	return UX_EnableUser(userName.c_str(), enabled ? 1 : 0);
+}
+
+int CUserManager2::resetPassword(const std::wstring& userName, const std::wstring& password)
+{
+	return UX_ResetPassword(userName.c_str(), password.c_str());
+}
+
+
+
+
+
+
+
+
diff --git a/SourceCode/Bond/Servo/CUserManager2.h b/SourceCode/Bond/Servo/CUserManager2.h
index 7430b00..794f454 100644
--- a/SourceCode/Bond/Servo/CUserManager2.h
+++ b/SourceCode/Bond/Servo/CUserManager2.h
@@ -1,4 +1,8 @@
 #pragma once
+
+#include <string>
+#include <vector>
+
 class CUserManager2
 {
 public:
@@ -6,12 +10,36 @@
 	CUserManager2(const CUserManager2&) = delete;
 	CUserManager2& operator=(const CUserManager2&) = delete;
 
+	struct RoleInfo
+	{
+		std::wstring name;
+		int level = 0;
+	};
+
+	struct UserInfo
+	{
+		std::wstring userName;
+		std::wstring displayName;
+		std::wstring roleName;
+		int roleLevel = 0;
+		bool enabled = false;
+	};
+
 public:
 	void init(const char* pszDir);
 	bool login(const char* pszAccount, const char* pszPwd);
 	bool isLoggedIn();
 	std::string getCurrentUserName();
 	bool IsAdminCurrent();
+	std::vector<RoleInfo> getRoles();
+	std::vector<UserInfo> getUsers();
+	int addUser(const std::wstring& userName, const std::wstring& displayName,
+		const std::wstring& password, const std::wstring& roleName, bool enabled);
+	int updateUser(const std::wstring& userName, const std::wstring& displayName,
+		const std::wstring& password, const std::wstring& roleName, bool enabled);
+	int deleteUser(const std::wstring& userName);
+	int setUserEnabled(const std::wstring& userName, bool enabled);
+	int resetPassword(const std::wstring& userName, const std::wstring& password);
 
 private:
 	CUserManager2();
diff --git a/SourceCode/Bond/Servo/CUserManager2Dlg.cpp b/SourceCode/Bond/Servo/CUserManager2Dlg.cpp
index 7d47ecd..84be473 100644
--- a/SourceCode/Bond/Servo/CUserManager2Dlg.cpp
+++ b/SourceCode/Bond/Servo/CUserManager2Dlg.cpp
@@ -1,20 +1,20 @@
-锘�// CUserManager2Dlg.cpp: 瀹炵幇鏂囦欢
+锘�// CUserManager2Dlg.cpp
 //
 
 #include "stdafx.h"
 #include "Servo.h"
 #include "CUserManager2Dlg.h"
 #include "afxdialogex.h"
-
-
-// CUserManager2Dlg 瀵硅瘽妗�
+#include "CUserEdit2Dlg.h"
+#include "InputDialog.h"
+#include "resource.h"
+#include "ToolUnits.h"
 
 IMPLEMENT_DYNAMIC(CUserManager2Dlg, CDialogEx)
 
-CUserManager2Dlg::CUserManager2Dlg(CWnd* pParent /*=nullptr*/)
+CUserManager2Dlg::CUserManager2Dlg(CWnd* pParent)
 	: CDialogEx(IDD_DIALOG_USER_MANAGER2, pParent)
 {
-
 }
 
 CUserManager2Dlg::~CUserManager2Dlg()
@@ -24,30 +24,299 @@
 void CUserManager2Dlg::DoDataExchange(CDataExchange* pDX)
 {
 	CDialogEx::DoDataExchange(pDX);
+	DDX_Control(pDX, IDC_LIST1, m_listUsers);
 }
-
 
 BEGIN_MESSAGE_MAP(CUserManager2Dlg, CDialogEx)
 	ON_WM_SIZE()
+	ON_BN_CLICKED(IDC_BUTTON_ADD, &CUserManager2Dlg::OnBnClickedButtonAdd)
+	ON_BN_CLICKED(IDC_BUTTON_EDIT, &CUserManager2Dlg::OnBnClickedButtonEdit)
+	ON_BN_CLICKED(IDC_BUTTON_DEL, &CUserManager2Dlg::OnBnClickedButtonDel)
+	ON_BN_CLICKED(IDC_BUTTON_RESET_PWD, &CUserManager2Dlg::OnBnClickedButtonResetPwd)
+	ON_BN_CLICKED(IDC_BUTTON_ENABLE, &CUserManager2Dlg::OnBnClickedButtonEnable)
+	ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST1, &CUserManager2Dlg::OnLvnItemchangedUsers)
 END_MESSAGE_MAP()
-
-
-// CUserManager2Dlg 娑堟伅澶勭悊绋嬪簭
-
 
 BOOL CUserManager2Dlg::OnInitDialog()
 {
 	CDialogEx::OnInitDialog();
 
-	// TODO:  鍦ㄦ娣诲姞棰濆鐨勫垵濮嬪寲
+	InitList();
+	RefreshUserList();
+	UpdateButtonState();
 
-	return TRUE;  // return TRUE unless you set the focus to a control
-				  // 寮傚父: OCX 灞炴�ч〉搴旇繑鍥� FALSE
+	return TRUE;
 }
 
 void CUserManager2Dlg::OnSize(UINT nType, int cx, int cy)
 {
 	CDialogEx::OnSize(nType, cx, cy);
+}
 
-	// TODO: 鍦ㄦ澶勬坊鍔犳秷鎭鐞嗙▼搴忎唬鐮�
+void CUserManager2Dlg::InitList()
+{
+	DWORD dwStyle = m_listUsers.GetExtendedStyle();
+	m_listUsers.SetExtendedStyle(dwStyle | LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);
+	m_listUsers.InsertColumn(0, _T("璐﹀彿"), LVCFMT_LEFT, 90);
+	m_listUsers.InsertColumn(1, _T("鏄剧ず鍚�"), LVCFMT_LEFT, 100);
+	m_listUsers.InsertColumn(2, _T("瑙掕壊"), LVCFMT_LEFT, 80);
+	m_listUsers.InsertColumn(3, _T("绾у埆"), LVCFMT_LEFT, 60);
+	m_listUsers.InsertColumn(4, _T("鐘舵��"), LVCFMT_LEFT, 70);
+}
+
+void CUserManager2Dlg::RefreshUserList()
+{
+	CString selectedName;
+	int currentIndex = GetSelectedIndex();
+	if (currentIndex >= 0 && currentIndex < static_cast<int>(m_users.size())) {
+		selectedName = m_users[currentIndex].userName.c_str();
+	}
+
+	m_users = CUserManager2::getInstance().getUsers();
+	m_listUsers.DeleteAllItems();
+
+	for (size_t i = 0; i < m_users.size(); ++i) {
+		const auto& user = m_users[i];
+		CString account(user.userName.c_str());
+		CString display(user.displayName.c_str());
+		CString role(user.roleName.empty() ? L"-" : user.roleName.c_str());
+		CString level;
+		level.Format(_T("%d"), user.roleLevel);
+		CString state = user.enabled ? _T("鍚敤") : _T("绂佺敤");
+
+		int row = m_listUsers.InsertItem(static_cast<int>(i), account);
+		m_listUsers.SetItemText(row, 1, display);
+		m_listUsers.SetItemText(row, 2, role);
+		m_listUsers.SetItemText(row, 3, level);
+		m_listUsers.SetItemText(row, 4, state);
+	}
+
+	if (!selectedName.IsEmpty()) {
+		for (int i = 0; i < m_listUsers.GetItemCount(); ++i) {
+			if (selectedName.CompareNoCase(m_listUsers.GetItemText(i, 0)) == 0) {
+				m_listUsers.SetItemState(i, LVIS_SELECTED, LVIS_SELECTED);
+				m_listUsers.EnsureVisible(i, FALSE);
+				break;
+			}
+		}
+	}
+	UpdateButtonState();
+}
+
+void CUserManager2Dlg::UpdateButtonState()
+{
+	int index = GetSelectedIndex();
+	BOOL hasSelection = (index >= 0);
+
+	auto enable = [&](int id, BOOL enableFlag) {
+		if (CWnd* p = GetDlgItem(id)) {
+			p->EnableWindow(enableFlag);
+		}
+	};
+
+	enable(IDC_BUTTON_EDIT, hasSelection);
+	enable(IDC_BUTTON_DEL, hasSelection);
+	enable(IDC_BUTTON_RESET_PWD, hasSelection);
+	enable(IDC_BUTTON_ENABLE, hasSelection);
+
+	CString toggleText = _T("绂佺敤/鍚敤");
+	if (const auto* user = GetSelectedUser()) {
+		toggleText = user->enabled ? _T("绂佺敤") : _T("鍚敤");
+		if (IsCurrentUser(*user)) {
+			enable(IDC_BUTTON_DEL, FALSE);
+			enable(IDC_BUTTON_ENABLE, FALSE);
+		}
+	}
+
+	SetDlgItemText(IDC_BUTTON_ENABLE, toggleText);
+}
+
+int CUserManager2Dlg::GetSelectedIndex() const
+{
+	if (!::IsWindow(m_listUsers.GetSafeHwnd())) {
+		return -1;
+	}
+	return m_listUsers.GetNextItem(-1, LVNI_SELECTED);
+}
+
+const CUserManager2::UserInfo* CUserManager2Dlg::GetSelectedUser() const
+{
+	int index = GetSelectedIndex();
+	if (index < 0 || index >= static_cast<int>(m_users.size())) {
+		return nullptr;
+	}
+	return &m_users[index];
+}
+
+std::wstring CUserManager2Dlg::ToWString(const CString& text) const
+{
+	CString trimmed(text);
+	trimmed.Trim();
+
+	std::string str((LPTSTR)(LPCTSTR)trimmed);
+	return CToolUnits::AnsiToWString(str);
+}
+
+void CUserManager2Dlg::ShowErrorMessage(const CString& action, int code)
+{
+	const wchar_t* detail = UX_ErrorMessage(code);
+	CString msg;
+	msg.Format(_T("%s: %s"), action.GetString(), detail ? detail : L"Unknown");
+	AfxMessageBox(msg, MB_ICONERROR);
+}
+
+bool CUserManager2Dlg::IsCurrentUser(const CUserManager2::UserInfo& info) const
+{
+	CString current(CUserManager2::getInstance().getCurrentUserName().c_str());
+	CString account(info.userName.c_str());
+	current.Trim();
+	account.Trim();
+	return !current.IsEmpty() && current.CompareNoCase(account) == 0;
+}
+
+void CUserManager2Dlg::OnBnClickedButtonAdd()
+{
+	CUserEdit2Dlg dlg(false, this);
+	if (dlg.DoModal() != IDOK) {
+		return;
+	}
+
+	CString account = dlg.m_strUsername;
+	account.Trim();
+	CString display = dlg.m_strDisplayName;
+	display.Trim();
+	if (display.IsEmpty()) {
+		display = account;
+	}
+	CString role = dlg.m_strRole;
+	role.Trim();
+	CString password = dlg.m_strPassword;
+	password.Trim();
+
+	int rc = CUserManager2::getInstance().addUser(ToWString(account), ToWString(display), ToWString(password), ToWString(role), dlg.m_bEnabled == TRUE);
+	if (rc == UX_OK) {
+		RefreshUserList();
+		AfxMessageBox(_T("鏂板鐢ㄦ埛鎴愬姛"));
+	}
+	else {
+		ShowErrorMessage(_T("鏂板鐢ㄦ埛澶辫触"), rc);
+	}
+}
+
+void CUserManager2Dlg::OnBnClickedButtonEdit()
+{
+	const auto* user = GetSelectedUser();
+	if (!user) {
+		AfxMessageBox(_T("璇烽�夋嫨鐢ㄦ埛"));
+		return;
+	}
+
+	CUserEdit2Dlg dlg(true, this);
+	dlg.m_strUsername = user->userName.c_str();
+	dlg.m_strDisplayName = user->displayName.c_str();
+	dlg.m_strRole = user->roleName.c_str();
+	dlg.m_bEnabled = user->enabled ? TRUE : FALSE;
+	if (dlg.DoModal() != IDOK) {
+		return;
+	}
+
+	CString display = dlg.m_strDisplayName;
+	display.Trim();
+	CString password = dlg.m_strPassword;
+	password.Trim();
+	CString role = dlg.m_strRole;
+	role.Trim();
+
+	int rc = CUserManager2::getInstance().updateUser(user->userName, ToWString(display), ToWString(password), ToWString(role), dlg.m_bEnabled == TRUE);
+	if (rc == UX_OK) {
+		RefreshUserList();
+		AfxMessageBox(_T("淇濆瓨鎴愬姛"));
+	}
+	else {
+		ShowErrorMessage(_T("淇濆瓨澶辫触"), rc);
+	}
+}
+
+void CUserManager2Dlg::OnBnClickedButtonDel()
+{
+	const auto* user = GetSelectedUser();
+	if (!user) {
+		AfxMessageBox(_T("璇烽�夋嫨鐢ㄦ埛"));
+		return;
+	}
+
+	if (IsCurrentUser(*user)) {
+		AfxMessageBox(_T("涓嶈兘鍒犻櫎褰撳墠鐧诲綍鐢ㄦ埛"));
+		return;
+	}
+
+	CString prompt;
+	prompt.Format(_T("纭畾鍒犻櫎鐢ㄦ埛 %s ?"), CString(user->userName.c_str()));
+	if (AfxMessageBox(prompt, MB_ICONQUESTION | MB_YESNO) != IDYES) {
+		return;
+	}
+
+	int rc = CUserManager2::getInstance().deleteUser(user->userName);
+	if (rc == UX_OK) {
+		RefreshUserList();
+		AfxMessageBox(_T("鍒犻櫎鎴愬姛"));
+	}
+	else {
+		ShowErrorMessage(_T("鍒犻櫎澶辫触"), rc);
+	}
+}
+
+void CUserManager2Dlg::OnBnClickedButtonResetPwd()
+{
+	const auto* user = GetSelectedUser();
+	if (!user) {
+		AfxMessageBox(_T("璇烽�夋嫨鐢ㄦ埛"));
+		return;
+	}
+
+	CInputDialog dlg(_T("閲嶇疆瀵嗙爜"), _T("璇疯緭鍏ユ柊瀵嗙爜:"), this);
+	if (dlg.DoModal() != IDOK) {
+		return;
+	}
+
+	CString password = dlg.GetInputText();
+	password.Trim();
+	if (password.IsEmpty()) {
+		AfxMessageBox(_T("瀵嗙爜涓嶈兘涓虹┖"));
+		return;
+	}
+
+	int rc = CUserManager2::getInstance().resetPassword(user->userName, ToWString(password));
+	if (rc == UX_OK) {
+		AfxMessageBox(_T("瀵嗙爜宸查噸缃�"));
+	}
+	else {
+		ShowErrorMessage(_T("閲嶇疆澶辫触"), rc);
+	}
+}
+
+void CUserManager2Dlg::OnBnClickedButtonEnable()
+{
+	const auto* user = GetSelectedUser();
+	if (!user) {
+		AfxMessageBox(_T("璇烽�夋嫨鐢ㄦ埛"));
+		return;
+	}
+
+	bool enable = !user->enabled;
+	int rc = CUserManager2::getInstance().setUserEnabled(user->userName, enable);
+	if (rc == UX_OK) {
+		RefreshUserList();
+		CString msg = enable ? _T("鐢ㄦ埛宸插惎鐢�") : _T("鐢ㄦ埛宸茬鐢�");
+		AfxMessageBox(msg);
+	}
+	else {
+		ShowErrorMessage(_T("鎿嶄綔澶辫触"), rc);
+	}
+}
+
+void CUserManager2Dlg::OnLvnItemchangedUsers(NMHDR* /*pNMHDR*/, LRESULT* pResult)
+{
+	UpdateButtonState();
+	*pResult = 0;
 }
diff --git a/SourceCode/Bond/Servo/CUserManager2Dlg.h b/SourceCode/Bond/Servo/CUserManager2Dlg.h
index 5085a9e..2a2507c 100644
--- a/SourceCode/Bond/Servo/CUserManager2Dlg.h
+++ b/SourceCode/Bond/Servo/CUserManager2Dlg.h
@@ -1,26 +1,45 @@
 锘�#pragma once
 
-
-// CUserManager2Dlg 瀵硅瘽妗�
+#include "CUserManager2.h"
+#include <string>
+#include <vector>
 
 class CUserManager2Dlg : public CDialogEx
 {
 	DECLARE_DYNAMIC(CUserManager2Dlg)
 
 public:
-	CUserManager2Dlg(CWnd* pParent = nullptr);   // 鏍囧噯鏋勯�犲嚱鏁�
+	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 鏀寔
+	virtual void DoDataExchange(CDataExchange* pDX);
 
 	DECLARE_MESSAGE_MAP()
 public:
 	virtual BOOL OnInitDialog();
 	afx_msg void OnSize(UINT nType, int cx, int cy);
+	afx_msg void OnBnClickedButtonAdd();
+	afx_msg void OnBnClickedButtonEdit();
+	afx_msg void OnBnClickedButtonDel();
+	afx_msg void OnBnClickedButtonResetPwd();
+	afx_msg void OnBnClickedButtonEnable();
+	afx_msg void OnLvnItemchangedUsers(NMHDR* pNMHDR, LRESULT* pResult);
+
+private:
+	CListCtrl m_listUsers;
+	std::vector<CUserManager2::UserInfo> m_users;
+
+	void InitList();
+	void RefreshUserList();
+	void UpdateButtonState();
+	int GetSelectedIndex() const;
+	const CUserManager2::UserInfo* GetSelectedUser() const;
+	std::wstring ToWString(const CString& text) const;
+	void ShowErrorMessage(const CString& action, int code);
+	bool IsCurrentUser(const CUserManager2::UserInfo& info) const;
 };
diff --git a/SourceCode/Bond/Servo/Servo.rc b/SourceCode/Bond/Servo/Servo.rc
index aadc145..88ccd82 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 31c7ea3..f3e94f1 100644
--- a/SourceCode/Bond/Servo/Servo.vcxproj
+++ b/SourceCode/Bond/Servo/Servo.vcxproj
@@ -257,6 +257,7 @@
     <ClInclude Include="CServoUtilsTool.h" />
     <ClInclude Include="CUserManager2.h" />
     <ClInclude Include="CUserManager2Dlg.h" />
+    <ClInclude Include="CUserEdit2Dlg.h" />
     <ClInclude Include="CVariable.h" />
     <ClInclude Include="DeviceRecipeParamDlg.h" />
     <ClInclude Include="GlassJson.h" />
@@ -473,6 +474,7 @@
     <ClCompile Include="CServoUtilsTool.cpp" />
     <ClCompile Include="CUserManager2.cpp" />
     <ClCompile Include="CUserManager2Dlg.cpp" />
+    <ClCompile Include="CUserEdit2Dlg.cpp" />
     <ClCompile Include="CVariable.cpp" />
     <ClCompile Include="DeviceRecipeParamDlg.cpp" />
     <ClCompile Include="GlassJson.cpp" />
@@ -647,4 +649,4 @@
     <Error Condition="!Exists('..\packages\Microsoft.Web.WebView2.1.0.2903.40\build\native\Microsoft.Web.WebView2.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Web.WebView2.1.0.2903.40\build\native\Microsoft.Web.WebView2.targets'))" />
     <Error Condition="!Exists('..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240803.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240803.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
   </Target>
-</Project>
\ No newline at end of file
+</Project>
diff --git a/SourceCode/Bond/Servo/Servo.vcxproj.filters b/SourceCode/Bond/Servo/Servo.vcxproj.filters
index a0fd9b9..ef7e8a6 100644
--- a/SourceCode/Bond/Servo/Servo.vcxproj.filters
+++ b/SourceCode/Bond/Servo/Servo.vcxproj.filters
@@ -231,6 +231,7 @@
     <ClCompile Include="LoginDlg2.cpp" />
     <ClCompile Include="CUserManager2.cpp" />
     <ClCompile Include="CUserManager2Dlg.cpp" />
+    <ClCompile Include="CUserEdit2Dlg.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="AlarmManager.h" />
@@ -505,6 +506,7 @@
     <ClInclude Include="LoginDlg2.h" />
     <ClInclude Include="CUserManager2.h" />
     <ClInclude Include="CUserManager2Dlg.h" />
+    <ClInclude Include="CUserEdit2Dlg.h" />
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="Servo.rc" />
@@ -548,4 +550,4 @@
       <UniqueIdentifier>{885738f6-3122-4bb9-8308-46b7f692fb13}</UniqueIdentifier>
     </Filter>
   </ItemGroup>
-</Project>
\ No newline at end of file
+</Project>
diff --git a/SourceCode/Bond/Servo/ServoDlg.cpp b/SourceCode/Bond/Servo/ServoDlg.cpp
index dd3206c..5705532 100644
--- a/SourceCode/Bond/Servo/ServoDlg.cpp
+++ b/SourceCode/Bond/Servo/ServoDlg.cpp
@@ -1101,7 +1101,20 @@
 			CUserManager2Dlg dlg;
 			dlg.DoModal();
 		}
-
+		else if (menuId == 2) {
+			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("鐧诲綍澶辫触锛岃妫�鏌ョ敤鎴峰悕鎴栧瘑鐮佹槸鍚︽纭紒");
+				}
+				UpdateLoginStatus();
+			}
+		}
 
 		/*
 		SystemLogManager& logManager = SystemLogManager::getInstance();
diff --git a/SourceCode/Bond/Servo/resource.h b/SourceCode/Bond/Servo/resource.h
index 4cf1ef2..6992734 100644
--- a/SourceCode/Bond/Servo/resource.h
+++ b/SourceCode/Bond/Servo/resource.h
Binary files differ

--
Gitblit v1.9.3