1.对系统运行日志管理类优化,比如获取单例模式的方式。unique_ptr必须通过析构函数结束
已修改6个文件
416 ■■■■■ 文件已修改
SourceCode/Bond/BondEq/BondEqDlg.cpp 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BondEq/DBManager/SystemLogManager.cpp 188 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BondEq/DBManager/SystemLogManager.h 25 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BondEq/View/SystemLogManagerDlg.cpp 183 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BondEq/View/SystemLogManagerDlg.h 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/x64/Debug/Config/BondEq.db 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BondEq/BondEqDlg.cpp
@@ -186,13 +186,21 @@
    // 设置运行日志模块的数据库连接
    SystemLogManager& logManager = SystemLogManager::getInstance();
    logManager.setDatabase(db);
    logManager.setDatabase(db.get());
    // 初始化运行日志表
    try {
    if (!logManager.initializeLogTable()) {
        AfxMessageBox("初始化系统日志表失败!");
        return FALSE;
    }
    }
    catch (const std::exception& ex) {
        CString errorMsg;
        errorMsg.Format(_T("初始化系统日志表失败:%s"), CString(ex.what()));
        AfxMessageBox(errorMsg, MB_ICONERROR);
        return FALSE;
    }
    // 菜单
SourceCode/Bond/BondEq/DBManager/SystemLogManager.cpp
@@ -1,37 +1,36 @@
#include "stdafx.h"
#include <iostream>
#include <sstream>
#include <iostream>
#include <stdexcept>
#include <ctime>
// 静态成员变量初始化
std::unique_ptr<SystemLogManager> SystemLogManager::m_instance = nullptr;
// 静态成员初始化
std::mutex SystemLogManager::m_mutex;
// 获取单例实例
SystemLogManager& SystemLogManager::getInstance() {
    if (m_instance == nullptr) {
        std::lock_guard<std::mutex> lock(m_mutex);
        if (m_instance == nullptr) {
            m_instance = std::unique_ptr<SystemLogManager>(new SystemLogManager());
        }
    }
    return *m_instance;
    static SystemLogManager instance;
    return instance;
}
// 构造函数
SystemLogManager::SystemLogManager() : m_pDB(nullptr) {}
// 析构函数
SystemLogManager::~SystemLogManager() {
    m_pDB = nullptr; // 清除指针引用
}
// 设置数据库连接
void SystemLogManager::setDatabase(std::unique_ptr<BL::Database>& db) {
void SystemLogManager::setDatabase(BL::Database* db) {
    std::lock_guard<std::mutex> lock(m_mutex);
    m_pDB = &db;
    m_pDB = db;
}
// 初始化日志表
bool SystemLogManager::initializeLogTable() {
    if (!m_pDB || !(*m_pDB)) {
        std::cerr << "Database connection is not set." << std::endl;
        return false;
    if (!m_pDB) {
        throw std::runtime_error("Database connection is not set.");
    }
    const std::string createTableQuery = R"(
@@ -43,81 +42,67 @@
            timestamp DATETIME DEFAULT (datetime('now', 'localtime'))
        )
    )";
    return (*m_pDB)->executeQuery(createTableQuery);
    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;
    if (!m_pDB) {
        throw std::runtime_error("Database connection is not set.");
    }
    // 清理旧日志
    cleanOldLogs(30);
    cleanOldLogs();
    std::string strUsername = UserManager::getInstance().getCurrentUser();
    if (strUsername.empty()) {
        strUsername = "SYSTEM";
    std::string username = UserManager::getInstance().getCurrentUser();
    if (username.empty()) {
        username = "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 ("
        << "'" << logTypeToString(logType) << "', "
        << "'" << event << "', "
        << "'" << username << "')";
    return (*m_pDB)->executeQuery(query.str());
    std::lock_guard<std::mutex> lock(m_mutex);
    return m_pDB->executeQuery(query.str());
}
// 添加日志(指定用户)
bool SystemLogManager::log(LogType logType, const std::string& event, const std::string& username) {
    if (!m_pDB) {
        throw std::runtime_error("Database connection is not set.");
    }
    cleanOldLogs();
    std::ostringstream query;
    query << "INSERT INTO system_logs (log_type, event, username) VALUES ("
        << "'" << logTypeToString(logType) << "', "
        << "'" << event << "', "
        << "'" << username << "')";
    std::lock_guard<std::mutex> lock(m_mutex);
    return m_pDB->executeQuery(query.str());
}
// 获取日志内容
std::vector<std::vector<std::string>> SystemLogManager::getLogs(int startPosition, int count) {
    std::vector<std::vector<std::string>> logs;
    if (!m_pDB || !(*m_pDB)) {
        std::cerr << "Database connection is not set." << std::endl;
        return logs;
    if (!m_pDB) {
        throw std::runtime_error("Database connection is not set.");
    }
    std::ostringstream query;
    // 如果 startPosition 和 count 都是 -1,获取全部数据
    if (startPosition == -1 && count == -1) {
        query << "SELECT id, log_type, event, username, timestamp FROM system_logs";
        query << "SELECT id, log_type, event, username, datetime(timestamp, 'localtime') FROM system_logs";
    }
    else {
        query << "SELECT id, log_type, event, username, timestamp FROM system_logs "
        query << "SELECT id, log_type, event, username, datetime(timestamp, 'localtime') FROM system_logs "
            << "LIMIT " << count << " OFFSET " << startPosition;
    }
    auto results = (*m_pDB)->fetchResults(query.str());
    for (const auto& row : results) {
        logs.push_back(row);
    }
    return logs;
    return m_pDB->fetchResults(query.str());
}
// 获取筛选后的日志数据
@@ -130,30 +115,22 @@
    int pageNumber,
    int pageSize)
{
    if (!m_pDB || !(*m_pDB)) {
    if (!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";
    query << "SELECT id, log_type, event, username, datetime(timestamp, 'localtime') 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 << "'";
    }
@@ -161,13 +138,10 @@
        query << " AND timestamp <= '" << endTime << "'";
    }
    // 分页逻辑:设置 LIMIT 和 OFFSET
    int offset = (pageNumber - 1) * pageSize;
    query << " ORDER BY timestamp DESC"; // 按时间降序排列
    query << " LIMIT " << pageSize << " OFFSET " << offset;
    query << " ORDER BY timestamp DESC LIMIT " << pageSize << " OFFSET " << offset;
    // 执行查询
    return (*m_pDB)->fetchResults(query.str());
    return m_pDB->fetchResults(query.str());
}
// 获取符合条件的日志总数
@@ -178,31 +152,22 @@
    const std::string& startTime,
    const std::string& endTime)
{
    // 检查数据库连接是否可用
    if (!m_pDB || !(*m_pDB)) {
    if (!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 << "'";
    }
@@ -210,52 +175,31 @@
        query << " AND timestamp <= '" << endTime << "'";
    }
    // 执行查询
    auto results = (*m_pDB)->fetchResults(query.str());
    // 返回记录总数
    if (!results.empty() && !results[0].empty()) {
        return std::stoi(results[0][0]); // 第一行第一列是计数值
    auto results = m_pDB->fetchResults(query.str());
    return (!results.empty() && !results[0].empty()) ? std::stoi(results[0][0]) : 0;
    }
    return 0; // 如果没有结果,返回 0
}
void SystemLogManager::cleanOldLogs(int daysToKeep)
{
    if (!m_pDB || !(*m_pDB)) {
// 清理超过指定天数的旧日志
void SystemLogManager::cleanOldLogs(int daysToKeep) {
    if (!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.");
    }
    query << "DELETE FROM system_logs WHERE timestamp < datetime('now', '-" << daysToKeep << " days')";
    m_pDB->executeQuery(query.str());
}
// 转换日志类型为字符串
std::string SystemLogManager::logTypeToString(LogType logType) const {
std::string SystemLogManager::logTypeToString(LogType logType) {
    switch (logType) {
    case LogType::Info:
        return _T("信息");
        return "信息";
    case LogType::Error:
        return _T("错误");
        return "错误";
    case LogType::Operation:
        return _T("操作");
        return "操作";
    default:
        return _T("δ֪");
        return "δ֪";
    }
}
SourceCode/Bond/BondEq/DBManager/SystemLogManager.h
@@ -2,13 +2,14 @@
#define SYSTEM_LOG_MANAGER_H
#include <string>
#include <memory>
#include <vector>
#include <mutex>
#include <chrono>
#include "Database.h"
// 系统日志管理类
class SystemLogManager {
public:
    // 日志类型定义
    enum class LogType {
        Info,
        Error,
@@ -20,7 +21,7 @@
    static SystemLogManager& getInstance();
    // 设置数据库连接
    void setDatabase(std::unique_ptr<BL::Database>& db);
    void setDatabase(BL::Database* db);
    // 初始化日志表
    bool initializeLogTable();
@@ -29,8 +30,8 @@
    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);
    // 获取日志内容
    std::vector<std::vector<std::string>> getLogs(int startPosition = -1, int count = -1);
    // 获取筛选后的日志数据
    std::vector<std::vector<std::string>> getFilteredLogs(
@@ -53,22 +54,20 @@
    // 清理超过指定天数的旧日志
    void cleanOldLogs(int daysToKeep = 30);
    // 转换日志类型为字符串
    static std::string logTypeToString(LogType logType);
private:
    // 构造函数(私有化)
    // 构造函数和析构函数
    SystemLogManager();
    ~SystemLogManager();
    // 禁止拷贝和赋值
    SystemLogManager(const SystemLogManager&) = delete;
    SystemLogManager& operator=(const SystemLogManager&) = delete;
    // 转换日志类型为字符串
    std::string logTypeToString(LogType logType) const;
    // 数据库连接
    std::unique_ptr<BL::Database>* m_pDB;
    // 单例实例
    static std::unique_ptr<SystemLogManager> m_instance;
    BL::Database* m_pDB = nullptr;
    // 线程安全锁
    static std::mutex m_mutex;
SourceCode/Bond/BondEq/View/SystemLogManagerDlg.cpp
@@ -162,11 +162,129 @@
    m_staticPageNum.SetWindowText(pageInfo);
}
void CSystemLogManagerDlg::SetDefaultFont()
{
    CFont* pFont = new CFont();
    LOGFONT logFont = { 0 };
    // 设置字体属性
    _tcscpy_s(logFont.lfFaceName, _T("Segoe UI")); // 使用清晰字体
    logFont.lfHeight = -12; // 字体高度
    logFont.lfWeight = FW_NORMAL;
    logFont.lfQuality = CLEARTYPE_QUALITY; // 启用 ClearType 抗锯齿
    pFont->CreateFontIndirect(&logFont);
    // 遍历所有控件,应用字体
    CWnd* pWnd = GetWindow(GW_CHILD);
    while (pWnd) {
        TCHAR szClassName[256];
        GetClassName(pWnd->m_hWnd, szClassName, sizeof(szClassName));
        if (_tcsicmp(szClassName, _T("MFCGridCtrl")) == 0
            || _tcsicmp(szClassName, _T("ComboBoxs")) == 0) {
            pWnd = pWnd->GetNextWindow();
            continue;
        }
        pWnd->SetFont(pFont, TRUE);
        pWnd = pWnd->GetNextWindow();
    }
}
void CSystemLogManagerDlg::AdjustControls(int nWidth, int nHeight)
{
    CWnd* pWnd = GetWindow(GW_CHILD);
    while (pWnd) {
        UINT nCtrlID = pWnd->GetDlgCtrlID();
        CRect ctrlRect;
        pWnd->GetWindowRect(&ctrlRect);
        ScreenToClient(&ctrlRect);
        // 计算控件的新位置和大小,按比例调整
        int newX = (int)(ctrlRect.left * (nWidth / (float)m_nInitialWidth));
        int newY = (int)(ctrlRect.top * (nHeight / (float)m_nInitialHeight));
        int newWidth = (int)(ctrlRect.Width() * (nWidth / (float)m_nInitialWidth));
        int newHeight = (int)(ctrlRect.Height() * (nHeight / (float)m_nInitialHeight));
        TCHAR szClassName[256];
        GetClassName(pWnd->m_hWnd, szClassName, sizeof(szClassName));
        if (_tcsicmp(szClassName, _T("MFCGridCtrl")) == 0) {
            CGridCtrl* pGridCtrl = (CGridCtrl*)pWnd;
            pGridCtrl->SetDefCellHeight(newHeight / 21);
            pGridCtrl->ExpandColumnsToFit(TRUE);
            pGridCtrl->Invalidate();
        }
        pWnd->MoveWindow(newX, newY, newWidth, newHeight);
        AdjustControlFont(pWnd, newWidth, newHeight);
        // 获取下一个控件
        pWnd = pWnd->GetNextWindow();
    }
}
void CSystemLogManagerDlg::AdjustControlFont(CWnd* pWnd, int nWidth, int nHeight)
{
    TCHAR szClassName[256];
    GetClassName(pWnd->m_hWnd, szClassName, sizeof(szClassName));
    if (_tcsicmp(szClassName, _T("Static")) == 0) {
        CStatic* pStatic = (CStatic*)pWnd;
        pStatic->ModifyStyle(SS_CENTER | SS_RIGHT | SS_CENTERIMAGE, SS_LEFT | SS_CENTERIMAGE);
        return;
    }
    if (_tcsicmp(szClassName, _T("ComboBox")) == 0) {
        CComboBox* pComboBox = (CComboBox*)pWnd;
        pComboBox->SetItemHeight(-1, nHeight);  // -1 表示所有项的高度
    }
    if (_tcsicmp(szClassName, _T("MFCGridCtrl")) == 0) {
        return;
    }
    int fontSize = nHeight - 10;
    CFont* pCurrentFont = pWnd->GetFont();
    LOGFONT logFont;
    pCurrentFont->GetLogFont(&logFont);
    logFont.lfHeight = -fontSize;
    CFont newFont;
    newFont.CreateFontIndirect(&logFont);
    pWnd->SetFont(&newFont);
    pWnd->Invalidate();
}
void CSystemLogManagerDlg::AdjustComboBoxStyle(CComboBox& comboBox)
{
    DWORD dwStyle = comboBox.GetStyle();
    comboBox.ModifyStyle(0, CBS_DROPDOWNLIST | CBS_HASSTRINGS | CBS_OWNERDRAWFIXED);
    comboBox.Invalidate();
    comboBox.UpdateWindow();
}
void CSystemLogManagerDlg::AdjustDateTimeCtrlStyle(CDateTimeCtrl& dateTimeCtrl)
{
    dateTimeCtrl.ModifyStyle(0, DTS_RIGHTALIGN);
    dateTimeCtrl.Invalidate();
    dateTimeCtrl.UpdateWindow();
}
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)
    ON_CBN_SELCHANGE(IDC_COMBO_TYPE, &CSystemLogManagerDlg::OnSelchangeComboType)
    ON_CBN_SELCHANGE(IDC_COMBO_USER, &CSystemLogManagerDlg::OnSelchangeComboUser)
    ON_WM_SIZE()
END_MESSAGE_MAP()
@@ -178,6 +296,8 @@
    CDialogEx::OnInitDialog();
    // TODO:  在此添加额外的初始化
    SetWindowText(_T("系统运行日志"));
    m_nCurrentPage = 1;  // 从第一页开始
    m_nTotalPages = 1;   // 默认总页数为 1
@@ -202,12 +322,46 @@
    COleDateTime defaultStartTime = currentTime - COleDateTimeSpan(30, 0, 0, 0);
    m_dateTimeStart.SetTime(defaultStartTime);
    CRect screenRect, dlgRect, clientRect;
    GetClientRect(&clientRect);
    m_nInitialWidth = clientRect.Width();
    m_nInitialHeight = clientRect.Height();
    GetWindowRect(&dlgRect);
    int dlgWidth = dlgRect.Width() * 2;
    int dlgHeight = dlgRect.Height() * 2;
    SystemParametersInfo(SPI_GETWORKAREA, 0, &screenRect, 0);
    if (dlgWidth > screenRect.Width()) {
        dlgWidth = screenRect.Width();
    }
    if (dlgHeight > screenRect.Height()) {
        dlgHeight = screenRect.Height();
    }
    int centerX = screenRect.left + (screenRect.Width() - dlgWidth) / 2;
    int centerY = screenRect.top + (screenRect.Height() - dlgHeight) / 2;
    MoveWindow(centerX, centerY, dlgWidth, dlgHeight);
    InitSystemLogManager();
    return TRUE;  // return TRUE unless you set the focus to a control
    // 异常: OCX 属性页应返回 FALSE
}
void CSystemLogManagerDlg::OnSize(UINT nType, int cx, int cy)
{
    CDialogEx::OnSize(nType, cx, cy);
    // TODO: 在此处添加消息处理程序代码
    CRect rect;
    GetClientRect(&rect);
    // 遍历对话框中的所有控件
    AdjustControls(rect.Width(), rect.Height());
    //SetDefaultFont();
}
void CSystemLogManagerDlg::OnBnClickedButtonSearch()
@@ -264,3 +418,32 @@
    }
}
void CSystemLogManagerDlg::OnSelchangeComboType()
{
    // 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::OnSelchangeComboUser()
{
    // TODO: 在此添加控件通知处理程序代码
    try {
        m_nCurrentPage = 1;
        FillSystemLogManager();
    }
    catch (const std::exception& ex) {
        CString errorMsg;
        errorMsg.Format(_T("切换角色失败:%s"), CString(ex.what()));
        AfxMessageBox(errorMsg, MB_ICONERROR);
    }
}
SourceCode/Bond/BondEq/View/SystemLogManagerDlg.h
@@ -22,8 +22,15 @@
    void InitSystemLogManager();
    void FillSystemLogManager();
    void UpdatePageInfo();
    void SetDefaultFont();
    void AdjustControls(int nWidth, int nHeight);
    void AdjustControlFont(CWnd* pWnd, int nWidth, int nHeight);
    void AdjustComboBoxStyle(CComboBox& comboBox);
    void AdjustDateTimeCtrlStyle(CDateTimeCtrl& dateTimeCtrl);
private:
    int m_nInitialWidth;   // 初始宽度
    int m_nInitialHeight;  // 初始高度
    int m_nCurrentPage;    // 当前页码
    int m_nTotalPages;     // 总页数
@@ -42,7 +49,10 @@
    DECLARE_MESSAGE_MAP()
public:
    virtual BOOL OnInitDialog();
    afx_msg void OnSize(UINT nType, int cx, int cy);
    afx_msg void OnBnClickedButtonSearch();
    afx_msg void OnBnClickedButtonPrevPage();
    afx_msg void OnBnClickedButtonNextPage();
    afx_msg void OnSelchangeComboType();
    afx_msg void OnSelchangeComboUser();
};
SourceCode/Bond/x64/Debug/Config/BondEq.db
Binary files differ