chenluhua1980
2025-11-18 fcc340fc812ee692f72fa1774c114e6f4d788f5c
1.实现用户管理。
已添加2个文件
已修改10个文件
649 ■■■■■ 文件已修改
SourceCode/Bond/BLControlsSDK/include/BLLabel.h 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CUserEdit2Dlg.cpp 125 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CUserEdit2Dlg.h 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CUserManager2.cpp 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CUserManager2.h 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CUserManager2Dlg.cpp 299 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CUserManager2Dlg.h 29 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Servo.rc 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Servo.vcxproj 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Servo.vcxproj.filters 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/ServoDlg.cpp 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/resource.h 补丁 | 查看 | 原始文档 | blame | 历史
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
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();
}
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()
};
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());
}
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();
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;
}
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;
};
SourceCode/Bond/Servo/Servo.rc
Binary files differ
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>
</Project>
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>
</Project>
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();
SourceCode/Bond/Servo/resource.h
Binary files differ