LAPTOP-T815PCOQ\25526
2024-11-20 f56f083a7e59e58dd44913b11ce4e959fb0475cc
1. 添加运行日志界面2.运行日志基本功能已经完成
已重命名2个文件
已添加2个文件
已修改12个文件
634 ■■■■■ 文件已修改
SourceCode/Bond/BondEq/BondEq.rc 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BondEq/BondEq.vcxproj 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BondEq/BondEqDlg.cpp 44 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BondEq/DBManager/SystemLogManager.cpp 162 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BondEq/DBManager/SystemLogManager.h 35 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BondEq/DBManager/UserManager.cpp 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BondEq/DBManager/UserManager.h 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BondEq/Resource.h 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BondEq/View/ChangePasswordDlg.cpp 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BondEq/View/LoginDlg.cpp 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BondEq/View/SystemLogManagerDlg.cpp 266 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BondEq/View/SystemLogManagerDlg.h 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BondEq/View/UserManagerDlg.cpp 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BondEq/View/UserManagerDlg.h 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BondEq/stdafx.h 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/x64/Debug/Config/BondEq.db 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BondEq/BondEq.rc
Binary files differ
SourceCode/Bond/BondEq/BondEq.vcxproj
@@ -244,10 +244,11 @@
    <ClInclude Include="targetver.h" />
    <ClInclude Include="ToolUnits.h" />
    <ClInclude Include="TopToolbar.h" />
    <ClInclude Include="UserManagerDlg.h" />
    <ClInclude Include="VerticalLine.h" />
    <ClInclude Include="View\ChangePasswordDlg.h" />
    <ClInclude Include="View\LoginDlg.h" />
    <ClInclude Include="View\SystemLogManagerDlg.h" />
    <ClInclude Include="View\UserManagerDlg.h" />
  </ItemGroup>
  <ItemGroup>
    <ClCompile Include="CPLC.cpp" />
@@ -305,10 +306,11 @@
    </ClCompile>
    <ClCompile Include="ToolUnits.cpp" />
    <ClCompile Include="TopToolbar.cpp" />
    <ClCompile Include="UserManagerDlg.cpp" />
    <ClCompile Include="VerticalLine.cpp" />
    <ClCompile Include="View\ChangePasswordDlg.cpp" />
    <ClCompile Include="View\LoginDlg.cpp" />
    <ClCompile Include="View\SystemLogManagerDlg.cpp" />
    <ClCompile Include="View\UserManagerDlg.cpp" />
  </ItemGroup>
  <ItemGroup>
    <ResourceCompile Include="BondEq.rc" />
SourceCode/Bond/BondEq/BondEqDlg.cpp
@@ -9,13 +9,13 @@
#include "Common.h"
#include "CBonder.h"
#include "SettingsDlg.h"
#include "UserManager.h"
#include "SystemLogManager.h"
#include "LoginDlg.h"
#include "ChangePasswordDlg.h"
#include "InputDialog.h"
#include "UserManagerDlg.h"
// test
#include "SystemLogManagerDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
@@ -184,21 +184,15 @@
    userManager.loadSession();
    std::unique_ptr<BL::Database>& db = userManager.getDatabaseInstance();
    // è®¾ç½®æ—¥å¿—模块的数据库连接
    // è®¾ç½®è¿è¡Œæ—¥å¿—模块的数据库连接
    SystemLogManager& logManager = SystemLogManager::getInstance();
    logManager.setDatabase(db);
    // åˆå§‹åŒ–日志表
    // åˆå§‹åŒ–运行日志表
    if (!logManager.initializeLogTable()) {
        AfxMessageBox("初始化系统日志表失败!");
        return FALSE;
    }
    std::string strUsername = userManager.getCurrentUser();
    if (strUsername.empty()) {
        strUsername = "SYSTEM";
    }
    logManager.log(SystemLogManager::LogType::Info, _T("BondEq启动..."), strUsername);
    // èœå•
@@ -243,6 +237,7 @@
    // æ›´æ–°ç™»å½•状态
    UpdateLoginStatus();
    logManager.log(SystemLogManager::LogType::Info, _T("BondEq启动..."));
    return TRUE;  // é™¤éžå°†ç„¦ç‚¹è®¾ç½®åˆ°æŽ§ä»¶ï¼Œå¦åˆ™è¿”回 TRUE
@@ -368,11 +363,7 @@
    KillTimer(1);
#endif
    std::string strUsername = UserManager::getInstance().getCurrentUser();
    if (strUsername.empty()) {
        strUsername = "SYSTEM";
    }
    SystemLogManager::getInstance().log(SystemLogManager::LogType::Info, _T("BondEq关闭..."), strUsername);
    SystemLogManager::getInstance().log(SystemLogManager::LogType::Info, _T("BondEq关闭..."));
}
void CBondEqDlg::OnSize(UINT nType, int cx, int cy)
@@ -533,6 +524,7 @@
LRESULT CBondEqDlg::OnToolbarBtnClicked(WPARAM wParam, LPARAM lParam)
{
    int id = (int)lParam;
    SystemLogManager& logManager = SystemLogManager::getInstance();
    if (id == IDC_BUTTON_RUN || id == IDC_BUTTON_STOP || id == IDC_BUTTON_SETTINGS)
    {
        CInputDialog inputDialog(_T("验证用户"), _T("请输入用户密码:"));
@@ -545,6 +537,7 @@
        std::string strPass = UserManager::getInstance().getCurrentPass();
        if (inputText.Compare(strPass.c_str()) != 0) {
            AfxMessageBox(_T("密码错误!"));
            logManager.log(SystemLogManager::LogType::Info, _T("验证时,密码错误!"));
            return 0;
        }
    }
@@ -552,10 +545,12 @@
    if (id == IDC_BUTTON_RUN) {
        m_pTopToolbar->GetBtn(IDC_BUTTON_RUN)->EnableWindow(FALSE);
        m_pTopToolbar->GetBtn(IDC_BUTTON_STOP)->EnableWindow(TRUE);
        logManager.log(SystemLogManager::LogType::Operation, _T("运行..."));
    }
    else if (id == IDC_BUTTON_STOP) {
        m_pTopToolbar->GetBtn(IDC_BUTTON_RUN)->EnableWindow(TRUE);
        m_pTopToolbar->GetBtn(IDC_BUTTON_STOP)->EnableWindow(FALSE);
        logManager.log(SystemLogManager::LogType::Operation, _T("Í£Ö¹..."));
    }
    else if (id == IDC_BUTTON_SETTINGS) {
        CSettingsDlg dlg;
@@ -569,20 +564,28 @@
            loginDlg.DoModal();
        }
        else if (1 == menuId) {
            // test
            CSystemLogManagerDlg dlg;
            dlg.DoModal();
            CChangePasswordDlg changePasswordDlg;
            changePasswordDlg.DoModal();
        }
        else if (2 == menuId) {
            CUserManagerDlg dlg;
            dlg.DoModal();
            if (dlg.DoModal()!= IDOK) {
                logManager.log(SystemLogManager::LogType::Operation, _T("用户管理的预操作被取消!"));
            }
        }
        else if (3 == menuId) {
            int ret = AfxMessageBox(_T("是否切换用户?切换用户会退出当前账号!"), MB_OK | MB_ICONEXCLAMATION);
            if (ret != MB_OK) {
            int ret = AfxMessageBox(_T("是否切换用户?切换用户会退出当前账号!"), MB_OKCANCEL | MB_ICONEXCLAMATION);
            if (ret != IDOK) {
                return 0;
            }
            logManager.log(SystemLogManager::LogType::Operation, _T("确认切换角色!"));
            if (userManager.isLoggedIn()) {
                logManager.log(SystemLogManager::LogType::Info, _T("退出登录!"));
                userManager.logout();
            }
@@ -592,11 +595,12 @@
        else {
            CString cstrMessage;
            cstrMessage.Format(_T("是否退出用户 [%s]?"), userManager.getCurrentUser().c_str());
            int ret = AfxMessageBox(_T(cstrMessage), MB_OK | MB_ICONEXCLAMATION);
            if (ret != MB_OK) {
            int ret = AfxMessageBox(_T(cstrMessage), MB_OKCANCEL | MB_ICONEXCLAMATION);
            if (ret != IDOK) {
                return 0;
            }
            logManager.log(SystemLogManager::LogType::Info, _T("退出登录!"));
            userManager.logout();
        }
SourceCode/Bond/BondEq/DBManager/SystemLogManager.cpp
@@ -1,5 +1,4 @@
#include "stdafx.h"
#include "SystemLogManager.h"
#include <iostream>
#include <sstream>
#include <stdexcept>
@@ -41,18 +40,49 @@
            log_type TEXT NOT NULL,
            event TEXT NOT NULL,
            username TEXT NOT NULL,
            timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
            timestamp DATETIME DEFAULT (datetime('now', 'localtime'))
        )
    )";
    return (*m_pDB)->executeQuery(createTableQuery);
}
// æ·»åŠ æ—¥å¿—
bool SystemLogManager::log(LogType logType, const std::string& event) {
    if (!m_pDB || !(*m_pDB)) {
        std::cerr << "Database connection is not set." << std::endl;
        return false;
    }
    // æ¸…理旧日志
    cleanOldLogs(30);
    std::string strUsername = UserManager::getInstance().getCurrentUser();
    if (strUsername.empty()) {
        strUsername = "SYSTEM";
    }
    std::ostringstream query;
    query << "INSERT INTO system_logs (log_type, event, username) VALUES ("
        << "'" << logTypeToString(logType) << "', "
        << "'" << event << "', "
        << "'" << strUsername << "')";
    return (*m_pDB)->executeQuery(query.str());
}
bool SystemLogManager::log(LogType logType, const std::string& event, const std::string& username) {
    if (!m_pDB || !(*m_pDB)) {
        std::cerr << "Database connection is not set." << std::endl;
        return false;
    }
    std::vector<std::string> vecUserInfo = UserManager::getInstance().getUserInfo(username);
    if (username.empty() || vecUserInfo.empty()) {
        std::cerr << "Username empty." << std::endl;
        return false;
    }
    // æ¸…理旧日志
    cleanOldLogs(30);
    std::ostringstream query;
    query << "INSERT INTO system_logs (log_type, event, username) VALUES ("
@@ -90,6 +120,132 @@
    return logs;
}
// èŽ·å–ç­›é€‰åŽçš„æ—¥å¿—æ•°æ®
std::vector<std::vector<std::string>> SystemLogManager::getFilteredLogs(
    const std::string& logType,
    const std::string& username,
    const std::string& description,
    const std::string& startTime,
    const std::string& endTime,
    int pageNumber,
    int pageSize)
{
    if (!m_pDB || !(*m_pDB)) {
        throw std::runtime_error("Database connection is not set.");
    }
    // æž„建基础 SQL æŸ¥è¯¢
    std::ostringstream query;
    query << "SELECT id, log_type, event, username, timestamp FROM system_logs WHERE 1=1";
    // æŒ‰æ—¥å¿—类型筛选
    if (logType != "ALL") {
        query << " AND log_type = '" << logType << "'";
    }
    // æŒ‰ç”¨æˆ·åç­›é€‰
    if (username != "ALL") {
        query << " AND username = '" << username << "'";
    }
    // æŒ‰æè¿°å…³é”®è¯ç­›é€‰
    if (!description.empty()) {
        query << " AND event LIKE '%" << description << "%'";
    }
    // æŒ‰æ—¶é—´èŒƒå›´ç­›é€‰
    if (!startTime.empty()) {
        query << " AND timestamp >= '" << startTime << "'";
    }
    if (!endTime.empty()) {
        query << " AND timestamp <= '" << endTime << "'";
    }
    // åˆ†é¡µé€»è¾‘:设置 LIMIT å’Œ OFFSET
    int offset = (pageNumber - 1) * pageSize;
    query << " ORDER BY timestamp DESC"; // æŒ‰æ—¶é—´é™åºæŽ’列
    query << " LIMIT " << pageSize << " OFFSET " << offset;
    // æ‰§è¡ŒæŸ¥è¯¢
    return (*m_pDB)->fetchResults(query.str());
}
// èŽ·å–ç¬¦åˆæ¡ä»¶çš„æ—¥å¿—æ€»æ•°
int SystemLogManager::getTotalLogCount(
    const std::string& logType,
    const std::string& username,
    const std::string& description,
    const std::string& startTime,
    const std::string& endTime)
{
    // æ£€æŸ¥æ•°æ®åº“连接是否可用
    if (!m_pDB || !(*m_pDB)) {
        throw std::runtime_error("Database connection is not set.");
    }
    // æž„建基础 SQL æŸ¥è¯¢
    std::ostringstream query;
    query << "SELECT COUNT(*) FROM system_logs WHERE 1=1";
    // æŒ‰æ—¥å¿—类型筛选
    if (logType != "ALL") {
        query << " AND log_type = '" << logType << "'";
    }
    // æŒ‰ç”¨æˆ·åç­›é€‰
    if (username != "ALL") {
        query << " AND username = '" << username << "'";
    }
    // æŒ‰æè¿°å…³é”®è¯ç­›é€‰
    if (!description.empty()) {
        query << " AND event LIKE '%" << description << "%'";
    }
    // æŒ‰æ—¶é—´èŒƒå›´ç­›é€‰
    if (!startTime.empty()) {
        query << " AND timestamp >= '" << startTime << "'";
    }
    if (!endTime.empty()) {
        query << " AND timestamp <= '" << endTime << "'";
    }
    // æ‰§è¡ŒæŸ¥è¯¢
    auto results = (*m_pDB)->fetchResults(query.str());
    // è¿”回记录总数
    if (!results.empty() && !results[0].empty()) {
        return std::stoi(results[0][0]); // ç¬¬ä¸€è¡Œç¬¬ä¸€åˆ—是计数值
    }
    return 0; // å¦‚果没有结果,返回 0
}
void SystemLogManager::cleanOldLogs(int daysToKeep)
{
    if (!m_pDB || !(*m_pDB)) {
        throw std::runtime_error("Database connection is not set.");
    }
    // èŽ·å–å½“å‰æ—¥æœŸå¹¶è®¡ç®—æˆªæ–­æ—¥æœŸ
    time_t now = time(nullptr);
    tm timeInfo;
    localtime_s(&timeInfo, &now);
    timeInfo.tm_mday -= daysToKeep; // è®¡ç®—指定天数之前的日期
    mktime(&timeInfo);              // è§„范化日期
    char buffer[20];
    strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", &timeInfo);
    std::string cutoffDate(buffer);
    std::ostringstream query;
    query << "DELETE FROM system_logs WHERE timestamp < '" << cutoffDate << "'";
    bool ret = (*m_pDB)->executeQuery(query.str());
    if (!ret) {
        throw std::runtime_error("System Log cleanup operation failed.");
    }
}
// è½¬æ¢æ—¥å¿—类型为字符串
std::string SystemLogManager::logTypeToString(LogType logType) const {
    switch (logType) {
@@ -102,4 +258,4 @@
    default:
        return _T("δ֪");
    }
}
}
SourceCode/Bond/BondEq/DBManager/SystemLogManager.h
@@ -10,9 +10,10 @@
class SystemLogManager {
public:
    enum class LogType {
        Info,     // ä¿¡æ¯æ—¥å¿—
        Error,    // é”™è¯¯æ—¥å¿—
        Operation // æ“ä½œæ—¥å¿—
        Info,
        Error,
        Operation,
        Unknown
    };
    // èŽ·å–å•ä¾‹å®žä¾‹
@@ -21,14 +22,36 @@
    // è®¾ç½®æ•°æ®åº“连接
    void setDatabase(std::unique_ptr<BL::Database>& db);
    // åˆå§‹åŒ–日志表
    bool initializeLogTable();
    // æ·»åŠ æ—¥å¿—
    bool log(LogType logType, const std::string& event, const std::string& username = "SYSTEM");
    bool log(LogType logType, const std::string& event);
    bool log(LogType logType, const std::string& event, const std::string& username);
    // èŽ·å–æ—¥å¿—
    std::vector<std::vector<std::string>> SystemLogManager::getLogs(int startPosition = -1, int count = -1);
    // åˆå§‹åŒ–日志表
    bool initializeLogTable();
    // èŽ·å–ç­›é€‰åŽçš„æ—¥å¿—æ•°æ®
    std::vector<std::vector<std::string>> getFilteredLogs(
        const std::string& logType,
        const std::string& username,
        const std::string& description,
        const std::string& startTime,
        const std::string& endTime,
        int pageNumber,
        int pageSize);
    // èŽ·å–ç¬¦åˆæ¡ä»¶çš„æ—¥å¿—æ€»æ•°
    int getTotalLogCount(
        const std::string& logType,
        const std::string& username,
        const std::string& description,
        const std::string& startTime,
        const std::string& endTime);
    // æ¸…理超过指定天数的旧日志
    void cleanOldLogs(int daysToKeep = 30);
private:
    // æž„造函数(私有化)
SourceCode/Bond/BondEq/DBManager/UserManager.cpp
@@ -48,7 +48,7 @@
            role INT NOT NULL,
            session_timeout INT DEFAULT 30,
            session_expiration INT DEFAULT 72,
            last_login TIMESTAMP
            last_login DATETIME DEFAULT (datetime('now', 'localtime'))
        )
    )";
    m_pDB->executeQuery(createTableQuery);
@@ -411,6 +411,39 @@
    return success;
}
// èŽ·å–æ‰€æœ‰ç”¨æˆ·åç§°
std::vector<std::string> UserManager::getUsernames() {
    std::vector<std::string> usernames;
    std::string query = "SELECT username FROM users";
    auto results = m_pDB->fetchResults(query);
    for (const auto& row : results) {
        if (!row.empty()) {
            usernames.push_back(row[0]); // èŽ·å–ç”¨æˆ·ååˆ—çš„å€¼
        }
    }
    return usernames;
}
// èŽ·å–æŒ‡å®šç”¨æˆ·åçš„ç”¨æˆ·ä¿¡æ¯
std::vector<std::string> UserManager::getUserInfo(const std::string& username)
{
    // æž„建查询语句
    std::ostringstream query;
    query << "SELECT username, password, role, session_timeout, session_expiration, last_login "
        << "FROM users WHERE username = '" << username << "'";
    // æ‰§è¡ŒæŸ¥è¯¢å¹¶èŽ·å–ç»“æžœ
    auto results = m_pDB->fetchResults(query.str());
    if (results.empty()) {
        return {};
    }
    // è¿”回查询到的第一行数据
    return results[0];
}
// æ›´æ–°æœ€åŽæ´»åŠ¨æ—¶é—´ï¼Œç”¨äºŽæ— æ“ä½œè¶…æ—¶æ£€æµ‹
void UserManager::updateActivityTime() {
    m_tpLastActivity = std::chrono::system_clock::now();
SourceCode/Bond/BondEq/DBManager/UserManager.h
@@ -41,6 +41,8 @@
    bool changeUserRole(const std::string& username, UserRole newRole);
    bool changeUserSessionTimeout(const std::string& username, int newTimeoutMinutes);
    bool changeUserSessionExpiration(const std::string& username, int newExpirationHours);
    std::vector<std::string> getUsernames();
    std::vector<std::string> getUserInfo(const std::string& username);
    // ä¼šè¯æ–‡ä»¶æ“ä½œ
    bool loadSession();     // ä»Žä¼šè¯æ–‡ä»¶åŠ è½½ä¼šè¯ä¿¡æ¯
SourceCode/Bond/BondEq/Resource.h
Binary files differ
SourceCode/Bond/BondEq/View/ChangePasswordDlg.cpp
@@ -5,7 +5,6 @@
#include "BondEq.h"
#include "afxdialogex.h"
#include "ChangePasswordDlg.h"
#include "UserManager.h"
// CChangePasswordDlg å¯¹è¯æ¡†
@@ -82,6 +81,7 @@
        return;
    }
    SystemLogManager& logManager = SystemLogManager::getInstance();
    if (newPassword.Compare(currentPassword) == 0) {
        EndDialog(IDCANCEL);
        return;
@@ -101,12 +101,14 @@
    if (userManager.isLoggedIn() && strCurrentPassword.compare(userManager.getCurrentPass()) == 0) {
        if (changeUserPassword(userManager, strUsername, strNewPassword)) {
            EndDialog(IDOK);
            logManager.log(SystemLogManager::LogType::Info, "修改密码成功!", strUsername);
        }
    }
    else {
        if (userManager.login(strUsername, strCurrentPassword)) {
            if (changeUserPassword(userManager, strUsername, strNewPassword)) {
                EndDialog(IDOK);
                logManager.log(SystemLogManager::LogType::Info, "修改密码成功!", strUsername);
            }
            else {
                userManager.logout();
SourceCode/Bond/BondEq/View/LoginDlg.cpp
@@ -5,7 +5,6 @@
#include "BondEq.h"
#include "afxdialogex.h"
#include "LoginDlg.h"
#include "UserManager.h"
#include "ChangePasswordDlg.h"
@@ -98,12 +97,14 @@
#endif
    UserManager& userManager = UserManager::getInstance();
    SystemLogManager& logManager = SystemLogManager::getInstance();
    if (!userManager.login(strUsername, strPassword, (m_checkRememberPassword.GetCheck() == BST_CHECKED))) {
        AfxMessageBox(_T("登录失败。"));
        return;
    }
    EndDialog(IDOK);
    logManager.log(SystemLogManager::LogType::Info, _T("登录成功..."));
}
void CLoginDlg::OnBnClickedChangePassword()
SourceCode/Bond/BondEq/View/SystemLogManagerDlg.cpp
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,266 @@
// SystemLogManagerDlg.cpp: å®žçŽ°æ–‡ä»¶
//
#include "stdafx.h"
#include "BondEq.h"
#include "afxdialogex.h"
#include "SystemLogManagerDlg.h"
#include "UserManager.h"
#include "SystemLogManager.h"
// CSystemLogManagerDlg å¯¹è¯æ¡†
IMPLEMENT_DYNAMIC(CSystemLogManagerDlg, CDialogEx)
CSystemLogManagerDlg::CSystemLogManagerDlg(CWnd* pParent /*=nullptr*/)
    : CDialogEx(IDD_DIALOG_SYSTEM_LOG_MANAGER, pParent)
{
}
CSystemLogManagerDlg::~CSystemLogManagerDlg()
{
}
void CSystemLogManagerDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_COMBO_TYPE, m_comboType);
    DDX_Control(pDX, IDC_COMBO_USER, m_comboUser);
    DDX_Control(pDX, IDC_DATETIMEPICKER_START, m_dateTimeStart);
    DDX_Control(pDX, IDC_DATETIMEPICKER_END, m_dateTimeEnd);
    DDX_Control(pDX, IDC_EDIT_DESCRIPTION, m_editDescription);
    DDX_Control(pDX, IDC_CUSTOM_LIST_LOGS, m_listLogs);
    DDX_Control(pDX, IDC_STATIC_PAGE_NUMBER, m_staticPageNum);
}
void CSystemLogManagerDlg::InitSystemLogManager()
{
    if (m_listLogs.GetSafeHwnd() == NULL)
        return;
    int nRows = 21; // åŒ…括表头(1 è¡Œï¼‰å’Œæ•°æ®ï¼ˆ20 è¡Œï¼‰
    int nCols = 5;
    int nFixRows = 1;
    int nFixCols = 0;
    int nRowIdx = 0;
    int nColIdx = 0;
    m_listLogs.DeleteAllItems();
    m_listLogs.SetVirtualMode(FALSE);
    m_listLogs.GetDefaultCell(TRUE, FALSE)->SetBackClr(g_nGridFixCellColor); // è®¾ç½®å›ºå®šè¡ŒèƒŒæ™¯è‰²
    m_listLogs.GetDefaultCell(FALSE, TRUE)->SetBackClr(g_nGridFixCellColor); // è®¾ç½®å›ºå®šåˆ—背景色
    m_listLogs.GetDefaultCell(FALSE, FALSE)->SetBackClr(g_nGridCellColor);    // è®¾ç½®å•元格背景色
    m_listLogs.SetFixedTextColor(g_nGridFixFontColor); // è®¾ç½®å›ºå®šè¡Œåˆ—字体颜色
    m_listLogs.SetRowCount(nRows);
    m_listLogs.SetColumnCount(nCols);
    m_listLogs.SetFixedRowCount(nFixRows);
    m_listLogs.SetFixedColumnCount(nFixCols);
    // Col
    m_listLogs.SetColumnWidth(nColIdx, 20);
    m_listLogs.SetItemText(nRowIdx, nColIdx++, _T("No."));
    m_listLogs.SetColumnWidth(nColIdx, 70);
    m_listLogs.SetItemText(nRowIdx, nColIdx++, _T("类型"));
    m_listLogs.SetColumnWidth(nColIdx, 150);
    m_listLogs.SetItemText(nRowIdx, nColIdx++, _T("事件"));
    m_listLogs.SetColumnWidth(nColIdx, 70);
    m_listLogs.SetItemText(nRowIdx, nColIdx++, _T("用户"));
    m_listLogs.SetColumnWidth(nColIdx, 70);
    m_listLogs.SetItemText(nRowIdx, nColIdx++, _T("时间"));
    // åˆ›å»º 20 è¡Œç©ºç™½æ•°æ®è¡Œ
    for (int i = 1; i < nRows; ++i) {
        for (int j = 0; j < nCols; ++j) {
            m_listLogs.SetItemText(i, j, _T("")); // åˆå§‹åŒ–为空字符串
        }
    }
    m_listLogs.SetFixedRowSelection(FALSE);
    m_listLogs.SetFixedColumnSelection(FALSE);
    m_listLogs.SetEditable(FALSE);
    m_listLogs.SetRowResize(FALSE);
    m_listLogs.SetColumnResize(TRUE);
    m_listLogs.ExpandColumnsToFit(TRUE);
    m_listLogs.SetListMode(TRUE);                // å¯ç”¨åˆ—表模式
    m_listLogs.EnableSelection(TRUE);            // å¯ç”¨é€‰æ‹©
    m_listLogs.SetSingleRowSelection(TRUE);        // è‡ªåŠ¨æ•´è¡Œé«˜äº®ï¼ˆé™åˆ¶ä¸ºå•è¡Œé€‰æ‹©ï¼‰
    m_listLogs.ExpandLastColumn();                // æœ€åŽä¸€åˆ—填充网格
    try {
        FillSystemLogManager();
    }
    catch (const std::exception& ex) {
        CString errorMsg;
        errorMsg.Format(_T("初始化运行日志失败:%s"), CString(ex.what()));
        AfxMessageBox(errorMsg, MB_ICONERROR);
    }
}
void CSystemLogManagerDlg::FillSystemLogManager()
{
    // èŽ·å–ç­›é€‰æ¡ä»¶
    CString selectedType, selectedUser, description;
    m_comboType.GetLBText(m_comboType.GetCurSel(), selectedType);
    m_comboUser.GetLBText(m_comboUser.GetCurSel(), selectedUser);
    m_editDescription.GetWindowText(description);
    COleDateTime startTime, endTime;
    m_dateTimeStart.GetTime(startTime);
    m_dateTimeEnd.GetTime(endTime);
    CString strStartTime = startTime.Format(_T("%Y-%m-%d %H:%M:%S"));
    CString strEndTime = endTime.Format(_T("%Y-%m-%d %H:%M:%S"));
    std::string type = CT2A(selectedType);
    std::string user = CT2A(selectedUser);
    std::string desc = CT2A(description);
    std::string start = CT2A(strStartTime);
    std::string end = CT2A(strEndTime);
    // èŽ·å–æ—¥å¿—ç®¡ç†å®žä¾‹
    SystemLogManager& logManager = SystemLogManager::getInstance();
    int pageSize = 20; // æ¯é¡µæ˜¾ç¤º 20 æ¡è®°å½•
    int totalRecords = logManager.getTotalLogCount(type, user, desc, start, end);
    m_nTotalPages = (totalRecords + pageSize - 1) / pageSize;
    auto logs = logManager.getFilteredLogs(type, user, desc, start, end, m_nCurrentPage, pageSize);
    // æ›´æ–°è¡¨æ ¼æ•°æ®
    int rowIdx = 1;
    for (const auto& log : logs) {
        m_listLogs.SetItemText(rowIdx, 0, CString(std::to_string(rowIdx).c_str())); // åºå·
        m_listLogs.SetItemText(rowIdx, 1, CString(log[1].c_str()));                 // ç±»åž‹
        m_listLogs.SetItemText(rowIdx, 2, CString(log[2].c_str()));                 // äº‹ä»¶
        m_listLogs.SetItemText(rowIdx, 3, CString(log[3].c_str()));                 // ç”¨æˆ·
        m_listLogs.SetItemText(rowIdx, 4, CString(log[4].c_str()));                 // æ—¶é—´
        ++rowIdx;
    }
    // æ¸…空多余行
    for (; rowIdx <= 20; ++rowIdx) {
        m_listLogs.SetItemText(rowIdx, 0, CString(std::to_string(rowIdx).c_str())); // åºå·åˆ—
        for (int colIdx = 1; colIdx < m_listLogs.GetColumnCount(); ++colIdx) {
            m_listLogs.SetItemText(rowIdx, colIdx, _T(""));
        }
    }
    m_listLogs.Invalidate();
    m_listLogs.UpdateWindow();
    m_listLogs.ExpandColumnsToFit(FALSE);
    m_listLogs.ExpandLastColumn();
    UpdatePageInfo();
}
void CSystemLogManagerDlg::UpdatePageInfo()
{
    // æ ¼å¼åŒ–页码信息为 "当前页/总页数"
    CString pageInfo;
    pageInfo.Format(_T("%d/%d é¡µ"), m_nCurrentPage, m_nTotalPages);
    m_staticPageNum.SetWindowText(pageInfo);
}
BEGIN_MESSAGE_MAP(CSystemLogManagerDlg, CDialogEx)
    ON_BN_CLICKED(IDC_BUTTON_SEARCH, &CSystemLogManagerDlg::OnBnClickedButtonSearch)
    ON_BN_CLICKED(IDC_BUTTON_PREV_PAGE, &CSystemLogManagerDlg::OnBnClickedButtonPrevPage)
    ON_BN_CLICKED(IDC_BUTTON_NEXT_PAGE, &CSystemLogManagerDlg::OnBnClickedButtonNextPage)
END_MESSAGE_MAP()
// CSystemLogManagerDlg æ¶ˆæ¯å¤„理程序
BOOL CSystemLogManagerDlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();
    // TODO:  åœ¨æ­¤æ·»åŠ é¢å¤–çš„åˆå§‹åŒ–
    m_nCurrentPage = 1;  // ä»Žç¬¬ä¸€é¡µå¼€å§‹
    m_nTotalPages = 1;   // é»˜è®¤æ€»é¡µæ•°ä¸º 1
    m_comboType.AddString(_T("ALL"));
    m_comboType.AddString(_T("信息"));
    m_comboType.AddString(_T("操作"));
    m_comboType.AddString(_T("错误"));
    m_comboType.AddString(_T("未知"));
    m_comboType.SetCurSel(0);
    m_comboUser.AddString(_T("ALL"));
    m_comboUser.AddString(_T("SYSTEM"));
    auto usernames = UserManager::getInstance().getUsernames();
    for (const auto& username : usernames) {
        CString cstrUsername(username.c_str());
        m_comboUser.AddString(cstrUsername);
    }
    m_comboUser.SetCurSel(0);
    // è®¾ç½®ä¸º 30 å¤©å‰
    COleDateTime currentTime = COleDateTime::GetCurrentTime();
    COleDateTime defaultStartTime = currentTime - COleDateTimeSpan(30, 0, 0, 0);
    m_dateTimeStart.SetTime(defaultStartTime);
    InitSystemLogManager();
    return TRUE;  // return TRUE unless you set the focus to a control
    // å¼‚常: OCX å±žæ€§é¡µåº”返回 FALSE
}
void CSystemLogManagerDlg::OnBnClickedButtonSearch()
{
    // TODO: åœ¨æ­¤æ·»åŠ æŽ§ä»¶é€šçŸ¥å¤„ç†ç¨‹åºä»£ç 
    try {
        m_nCurrentPage = 1;
        FillSystemLogManager();
    }
    catch (const std::exception& ex) {
        CString errorMsg;
        errorMsg.Format(_T("搜索失败:%s"), CString(ex.what()));
        AfxMessageBox(errorMsg, MB_ICONERROR);
    }
}
void CSystemLogManagerDlg::OnBnClickedButtonPrevPage()
{
    // TODO: åœ¨æ­¤æ·»åŠ æŽ§ä»¶é€šçŸ¥å¤„ç†ç¨‹åºä»£ç 
    try {
        if (m_nCurrentPage > 1) {
            m_nCurrentPage--;
            FillSystemLogManager();
        }
        else {
            AfxMessageBox(_T("已经是第一页!"));
        }
    }
    catch (const std::exception& ex) {
        CString errorMsg;
        errorMsg.Format(_T("切换到上一页失败:%s"), CString(ex.what()));
        AfxMessageBox(errorMsg, MB_ICONERROR);
    }
}
void CSystemLogManagerDlg::OnBnClickedButtonNextPage()
{
    // TODO: åœ¨æ­¤æ·»åŠ æŽ§ä»¶é€šçŸ¥å¤„ç†ç¨‹åºä»£ç 
    try {
        if (m_nCurrentPage < m_nTotalPages) {
            m_nCurrentPage++;
            FillSystemLogManager();
        }
        else {
            AfxMessageBox(_T("已经是最后一页!"));
        }
    }
    catch (const std::exception& ex) {
        CString errorMsg;
        errorMsg.Format(_T("切换到下一页失败:%s"), CString(ex.what()));
        AfxMessageBox(errorMsg, MB_ICONERROR);
    }
}
SourceCode/Bond/BondEq/View/SystemLogManagerDlg.h
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,48 @@
#pragma once
#include "afxdialogex.h"
#include "GridCtrl.h"
// CSystemLogManagerDlg å¯¹è¯æ¡†
class CSystemLogManagerDlg : public CDialogEx
{
    DECLARE_DYNAMIC(CSystemLogManagerDlg)
public:
    CSystemLogManagerDlg(CWnd* pParent = nullptr);   // æ ‡å‡†æž„造函数
    virtual ~CSystemLogManagerDlg();
// å¯¹è¯æ¡†æ•°æ®
#ifdef AFX_DESIGN_TIME
    enum { IDD = IDD_DIALOG_SYSTEM_LOG_MANAGER };
#endif
private:
    void InitSystemLogManager();
    void FillSystemLogManager();
    void UpdatePageInfo();
private:
    int m_nCurrentPage;    // å½“前页码
    int m_nTotalPages;     // æ€»é¡µæ•°
private:
    CComboBox m_comboType;
    CComboBox m_comboUser;
    CDateTimeCtrl m_dateTimeStart;
    CDateTimeCtrl m_dateTimeEnd;
    CEdit m_editDescription;
    CGridCtrl m_listLogs;
    CStatic m_staticPageNum;
protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV æ”¯æŒ
    DECLARE_MESSAGE_MAP()
public:
    virtual BOOL OnInitDialog();
    afx_msg void OnBnClickedButtonSearch();
    afx_msg void OnBnClickedButtonPrevPage();
    afx_msg void OnBnClickedButtonNextPage();
};
SourceCode/Bond/BondEq/View/UserManagerDlg.cpp
ÎļþÃû´Ó SourceCode/Bond/BondEq/UserManagerDlg.cpp ÐÞ¸Ä
@@ -6,7 +6,6 @@
#include "afxdialogex.h"
#include "UserManagerDlg.h"
#include "InputDialog.h"
#include "UserManager.h"
#include "NewCellTypes/GridCellCombo.h"
#include "NewCellTypes/GridCellNumeric.h"
@@ -202,12 +201,12 @@
    CString inputText = inputDialog.GetInputText();
    if (inputText.IsEmpty()) {
        AfxMessageBox(_T("用户名不能为空!"), MB_OK | MB_ICONEXCLAMATION);
        AfxMessageBox(_T("用户名不能为空!"));
        return;
    }
    if (IsUsernameDuplicate(inputText)) {
        AfxMessageBox(_T("用户名重复!"), MB_OK | MB_ICONEXCLAMATION);
        AfxMessageBox(_T("用户名重复!"));
        return;
    }
@@ -259,6 +258,11 @@
    pGridCtrl->ExpandLastColumn();
    pGridCtrl->Invalidate();
    pGridCtrl->UpdateWindow();
    CString cstrMessage;
    cstrMessage.Format(_T("预添加用户 [%s]!"), inputText);
    std::string strMessage = CT2A(cstrMessage);
    SystemLogManager::getInstance().log(SystemLogManager::LogType::Operation, strMessage);
}
void CUserManagerDlg::DeleteSelectedRow(CGridCtrl* pGridCtrl)
@@ -286,7 +290,7 @@
            if (selectedUser == currentUser) {
                CString message;
                message.Format(_T("用户 [%s] æ˜¯å½“前登录用户,不能删除!"), currentUser);
                AfxMessageBox(message, MB_OK | MB_ICONEXCLAMATION);
                AfxMessageBox(message);
                return;
            }
@@ -294,7 +298,7 @@
        }
        if (rowsToDelete.empty()) {
            AfxMessageBox(_T("请先选择要删除的行!"), MB_OK | MB_ICONINFORMATION);
            AfxMessageBox(_T("请先选择要删除的行!"));
            return;
        }
@@ -302,6 +306,11 @@
        if (rowsToDelete.size() == 1) {
            CString selectedUser = pGridCtrl->GetItemText(rowsToDelete[0], 1);
            message.Format(_T("确定要删除选中用户 [%s] å—?"), selectedUser);
            CString cstrMessage;
            cstrMessage.Format(_T("预删除用户 [%s]!"), selectedUser);
            std::string strMessage = CT2A(cstrMessage);
            SystemLogManager::getInstance().log(SystemLogManager::LogType::Operation, strMessage);
        }
        else {
            message.Format(_T("确定要删除选中的 %d ä¸ªç”¨æˆ·å—?"), rowsToDelete.size());
@@ -319,7 +328,7 @@
        }
    }
    else {
        AfxMessageBox(_T("请先选择要删除的用户!"), MB_OK | MB_ICONINFORMATION);
        AfxMessageBox(_T("请先选择要删除的用户!"));
    }
}
@@ -498,14 +507,14 @@
    CCellRange selectedRange = m_gridUserManager.GetSelectedCellRange();
    if (!selectedRange.IsValid()) {
        AfxMessageBox(_T("请先选择要插入的位置!"), MB_OK | MB_ICONINFORMATION);
        AfxMessageBox(_T("请先选择要插入的位置!"));
        return;
    }
    int minRow = selectedRange.GetMinRow();
    int maxRow = selectedRange.GetMaxRow();
    if (minRow < 1) {
        AfxMessageBox(_T("请选择有效的行!"), MB_OK | MB_ICONEXCLAMATION);
        AfxMessageBox(_T("请选择有效的行!"));
        return;
    }
SourceCode/Bond/BondEq/View/UserManagerDlg.h
SourceCode/Bond/BondEq/stdafx.h
@@ -47,6 +47,10 @@
#include "..\DatabaseSDK\include\MySQLDatabase.h"
#include "..\DatabaseSDK\include\SQLiteDatabase.h"
// å•例模式的数据库管理类
#include "UserManager.h"
#include "SystemLogManager.h"
// æŽ§ä»¶æ ·å¼
static UINT g_nGridFixCellColor = RGB(144, 200, 246);
static UINT g_nGridFixFontColor = RGB(0, 0, 0);
SourceCode/Bond/x64/Debug/Config/BondEq.db
Binary files differ