已添加2个文件
已修改12个文件
1536 ■■■■ 文件已修改
SourceCode/Bond/Servo/AlarmManager.cpp 420 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/AlarmManager.h 205 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/AlarmPopupDlg.cpp 321 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/AlarmPopupDlg.h 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CMaster.cpp 252 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CMyStatusbar.cpp 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CMyStatusbar.h 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Common.h 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Servo.rc 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Servo.vcxproj 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Servo.vcxproj.filters 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/ServoDlg.cpp 158 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/ServoDlg.h 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/resource.h 28 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/AlarmManager.cpp
@@ -1,6 +1,7 @@
#include "stdafx.h"
#include "stdafx.h"
#include "Common.h"
#include "AlarmManager.h"
#include "Log.h"
#include <sstream>
#include <fstream>
#include <iostream>
@@ -8,25 +9,26 @@
#include <ctime>
#include <iomanip>
#include <random>
#include <chrono>
// å¸¸é‡
// å¸¸é‡
const std::string DATABASE_FILE = R"(AlarmManager.db)";
// é™æ€æˆå‘˜åˆå§‹åŒ–
// é™æ€æˆå‘˜åˆå§‹åŒ–
std::mutex AlarmManager::m_mutex;
// èŽ·å–å•ä¾‹å®žä¾‹
// èŽ·å–å•ä¾‹å®žä¾‹
AlarmManager& AlarmManager::getInstance() {
    static AlarmManager instance;
    return instance;
}
// æž„造函数
// æž„造函数
AlarmManager::AlarmManager() {
    m_pDB = new BL::SQLiteDatabase();
}
// æžæž„函数
// æžæž„函数
AlarmManager::~AlarmManager() {
    if (m_pDB != nullptr) {
        delete m_pDB;
@@ -34,7 +36,7 @@
    }
}
// åˆå§‹åŒ–报警表
// åˆå§‹åŒ–报警表
bool AlarmManager::initAlarmTable() {
    char path[MAX_PATH];
    GetModuleFileName(NULL, path, MAX_PATH);
@@ -49,7 +51,7 @@
        throw std::runtime_error("Failed to connect to database.");
    }
    // åˆ›å»ºè®¾å¤‡è¡¨
    // åˆ›å»ºè®¾å¤‡è¡¨
    const std::string createDevicesTableQuery = R"(
        CREATE TABLE IF NOT EXISTS devices (
            device_id TEXT PRIMARY KEY NOT NULL,
@@ -60,7 +62,7 @@
        return false;
    }
    // åˆ›å»ºå•元表,设备ID和单元ID组合作为主键
    // åˆ›å»ºå•元表,设备ID和单元ID组合作为主键
    const std::string createUnitsTableQuery = R"(
        CREATE TABLE IF NOT EXISTS units (
            device_id TEXT NOT NULL,
@@ -74,7 +76,7 @@
        return false;
    }
    // åˆ›å»ºæŠ¥è­¦è¡¨ï¼ŒæŠ¥è­¦è®°å½•çš„alarm_event_id是主键
    // åˆ›å»ºæŠ¥è­¦è¡¨ï¼ŒæŠ¥è­¦è®°å½•çš„alarm_event_id是主键
    const std::string createAlarmsTableQuery = R"(
        CREATE TABLE IF NOT EXISTS alarms (
            alarm_event_id INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -93,8 +95,9 @@
        return false;
    }
    // è®¾å¤‡åˆ—表 (ID -> åç§°)
    // è®¾å¤‡åˆ—表 (ID -> åç§°)
    std::vector<std::pair<int, std::string>> devices = {
        {0, "Software"},
        {EQ_ID_LOADPORT1, EQ_NAME_LOADPORT1},
        {EQ_ID_LOADPORT2, EQ_NAME_LOADPORT2},
        {EQ_ID_LOADPORT3, EQ_NAME_LOADPORT3},
@@ -113,12 +116,12 @@
        {EQ_ID_OPERATOR_REMOVE, EQ_NAME_OPERATOR_REMOVE}
    };
    // æ’å…¥ devices å’Œå¯¹åº”的默认 unit
    // æ’å…¥ devices å’Œå¯¹åº”的默认 unit
    for (const auto& dev : devices) {
        int nDeviceId = dev.first;
        const std::string& strDeviceName = dev.second;
        // æ’入设备
        // æ’入设备
        std::ostringstream ossDev;
        ossDev << "INSERT OR IGNORE INTO devices (device_id, device_name) VALUES("
            << nDeviceId << ", '" << strDeviceName << "')";
@@ -126,7 +129,7 @@
            return false;
        }
        // æ’入默认单元 (unit_id = 0, unit_name = device_name)
        // æ’入默认单元 (unit_id = 0, unit_name = device_name)
        std::ostringstream ossUnit;
        ossUnit << "INSERT OR IGNORE INTO units (device_id, unit_id, unit_name) VALUES("
            << nDeviceId << ", 0, '" << strDeviceName << "')";
@@ -138,14 +141,14 @@
    return true;
}
// é”€æ¯æŠ¥è­¦è¡¨
// é”€æ¯æŠ¥è­¦è¡¨
void AlarmManager::termAlarmTable() {
    if (m_pDB != nullptr) {
        m_pDB->disconnect();
    }
}
// é”€æ¯æŠ¥è­¦è¡¨
// é”€æ¯æŠ¥è­¦è¡¨
bool AlarmManager::destroyAlarmTable() {
    if (!m_pDB) {
        throw std::runtime_error("Database connection is not set.");
@@ -154,9 +157,9 @@
    return m_pDB->executeQuery(dropTableQuery);
}
// æ’入模拟数据
// æ’入模拟数据
void AlarmManager::insertMockData() {
    // æ’入设备数据
    // æ’入设备数据
    for (int i = 1; i <= 3; ++i) {
        std::string deviceName = "Device" + std::to_string(i);
        std::stringstream query;
@@ -166,7 +169,7 @@
        }
    }
    // æ’入单元数据
    // æ’入单元数据
    for (int i = 1; i <= 3; ++i) {
        for (int j = 0; j <= 3; ++j) {
            int unitId = j;
@@ -175,8 +178,8 @@
            std::stringstream query;
            query << "INSERT INTO units (device_id, unit_id, unit_name) VALUES ('"
                << deviceId << "', '"   // æ’入设备ID,确保是字符串
                << unitId << "', '"     // æ’入单元ID,确保是字符串
                << deviceId << "', '"   // æ’入设备ID,确保是字符串
                << unitId << "', '"     // æ’入单元ID,确保是字符串
                << unitName << "');";
            if (!m_pDB->executeQuery(query.str())) {
@@ -186,7 +189,7 @@
    }
    /*
    // åˆå§‹åŒ–随机数生成器
    // åˆå§‹åŒ–随机数生成器
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<> deviceDis(1, 3);
@@ -195,7 +198,7 @@
    std::uniform_int_distribution<> severityDis(0, 3);
    std::vector<std::string> descriptions = { "Overheat", "Sensor failure", "Power outage" };
    // æ—¶é—´ç›¸å…³
    // æ—¶é—´ç›¸å…³
    auto now = std::chrono::system_clock::now();
    auto start_time = std::chrono::system_clock::to_time_t(now);
    auto end_time = std::chrono::system_clock::to_time_t(now + std::chrono::minutes(10));
@@ -205,13 +208,13 @@
    localtime_s(&start_tm, &start_time);
    localtime_s(&end_tm, &end_time);
    // æ’入模拟数据
    // æ’入模拟数据
    for (int i = 0; i < 10; ++i) {
        int deviceId = deviceDis(gen);          // éšæœºè®¾å¤‡ID
        int unitId = unitDis(gen);              // éšæœºå•å…ƒID
        int errorCode = errorCodeDis(gen);      // éšæœºé”™è¯¯ç 
        int severityLevel = severityDis(gen);   // éšæœºç”ŸæˆæŠ¥è­¦ç­‰çº§
        std::string description = descriptions[errorCodeDis(gen) % descriptions.size()];  // éšæœºæŠ¥è­¦æè¿°
        int deviceId = deviceDis(gen);          // éšæœºè®¾å¤‡ID
        int unitId = unitDis(gen);              // éšæœºå•å…ƒID
        int errorCode = errorCodeDis(gen);      // éšæœºé”™è¯¯ç 
        int severityLevel = severityDis(gen);   // éšæœºç”ŸæˆæŠ¥è­¦ç­‰çº§
        std::string description = descriptions[errorCodeDis(gen) % descriptions.size()];  // éšæœºæŠ¥è­¦æè¿°
        std::stringstream query;
        query << "INSERT INTO alarms (id, severity_level, device_id, unit_id, description, start_time, end_time) "
@@ -226,38 +229,38 @@
    */
}
// æ·»åŠ æŠ¥è­¦ä¿¡æ¯
// æ·»åŠ æŠ¥è­¦ä¿¡æ¯
bool AlarmManager::addAlarm(const AlarmData& alarmData, int& alarmEventId) {
    if (!m_pDB) {
        return false;
    }
    #if 0
        // å¼€å§‹äº‹åŠ¡
        // å¼€å§‹äº‹åŠ¡
        m_pDB->executeQuery("BEGIN TRANSACTION;");
    
        // æž„建插入查询
        // æž„建插入查询
        std::ostringstream query;
        query << "INSERT INTO alarms (id, severity_level, device_id, unit_id, description, start_time, end_time) VALUES ("
            << alarmData.nId << ", "              // é”™è¯¯ç 
            << alarmData.nSeverityLevel << ", "   // æŠ¥è­¦ç­‰çº§
            << alarmData.nDeviceId << ", "        // è®¾å¤‡ID
            << alarmData.nUnitId << ", '"         // å•å…ƒID
            << alarmData.strDescription << "', '" // æè¿°
            << alarmData.strStartTime << "', '"   // å¼€å§‹æ—¶é—´
            << alarmData.strEndTime << "')";      // ç»“束时间
            << alarmData.nId << ", "              // é”™è¯¯ç 
            << alarmData.nSeverityLevel << ", "   // æŠ¥è­¦ç­‰çº§
            << alarmData.nDeviceId << ", "        // è®¾å¤‡ID
            << alarmData.nUnitId << ", '"         // å•å…ƒID
            << alarmData.strDescription << "', '" // æè¿°
            << alarmData.strStartTime << "', '"   // å¼€å§‹æ—¶é—´
            << alarmData.strEndTime << "')";      // ç»“束时间
    
        // ä½¿ç”¨é”ä¿æŠ¤å¤šçº¿ç¨‹å®‰å…¨
        // ä½¿ç”¨é”ä¿æŠ¤å¤šçº¿ç¨‹å®‰å…¨
        std::lock_guard<std::mutex> lock(m_mutex);
    
        // æ‰§è¡Œæ’入查询
        // æ‰§è¡Œæ’入查询
        bool result = m_pDB->executeQuery(query.str());
        if (result) {
            alarmEventId = getLastInsertId();
            m_alarmCache[alarmEventId] = alarmData;
        }
    
        // æäº¤äº‹åŠ¡
        // æäº¤äº‹åŠ¡
        m_pDB->executeQuery("COMMIT;");
    
        return result;
@@ -273,23 +276,23 @@
            }
        }
        // æž„建插入查询并使用 RETURNING èŽ·å–æ’å…¥åŽçš„ alarm_event_id
        // æž„建插入查询并使用 RETURNING èŽ·å–æ’å…¥åŽçš„ alarm_event_id
        std::ostringstream query;
        query << "INSERT INTO alarms (id, severity_level, device_id, unit_id, description, start_time, end_time) "
            << "VALUES (" << alarmData.nId << ", " << alarmData.nSeverityLevel << ", " << alarmData.nDeviceId << ", "
            << alarmData.nUnitId << ", '" << alarmData.strDescription << "', '" << alarmData.strStartTime << "', '"
            << alarmData.strEndTime << "') RETURNING alarm_event_id;";
    
        // ä½¿ç”¨é”ä¿æŠ¤å¤šçº¿ç¨‹å®‰å…¨
        // ä½¿ç”¨é”ä¿æŠ¤å¤šçº¿ç¨‹å®‰å…¨
        std::lock_guard<std::mutex> lock(m_mutex);
    
        // æ‰§è¡ŒæŸ¥è¯¢å¹¶èŽ·å–ç»“æžœ
        // æ‰§è¡ŒæŸ¥è¯¢å¹¶èŽ·å–ç»“æžœ
        auto results = m_pDB->fetchResults(query.str());
        if (!results.empty() && !results[0].empty()) {
            try {
                // æå–并转换 alarm_event_id
                // æå–并转换 alarm_event_id
                alarmEventId = std::stoi(results[0][0]);
                // å°†æ’入的报警数据添加到缓存
                // å°†æ’入的报警数据添加到缓存
                m_mapCache[alarmEventId] = alarmData;
                return true;
            }
@@ -303,13 +306,13 @@
    #endif
}
// æŸ¥è¯¢æ‰€æœ‰æŠ¥è­¦æ•°æ®
// æŸ¥è¯¢æ‰€æœ‰æŠ¥è­¦æ•°æ®
std::vector<AlarmData> AlarmManager::getAllAlarms() {
    if (!m_pDB) {
        return {};
    }
    // æŸ¥è¯¢æ‰€æœ‰æŠ¥è­¦æ•°æ®ï¼ˆåŒ…括设备名称和单元名称)
    // æŸ¥è¯¢æ‰€æœ‰æŠ¥è­¦æ•°æ®ï¼ˆåŒ…括设备名称和单元名称)
    const std::string query = R"(
        SELECT a.id, a.severity_level, a.device_id, a.unit_id, d.device_name, u.unit_name, a.description, a.start_time, a.end_time
        FROM alarms a
@@ -319,19 +322,19 @@
    auto results = m_pDB->fetchResults(query);
    // éåŽ†æŸ¥è¯¢ç»“æžœï¼Œå¡«å…… AlarmData ç»“构体
    // éåŽ†æŸ¥è¯¢ç»“æžœï¼Œå¡«å…… AlarmData ç»“构体
    std::vector<AlarmData> alarms;
    for (const auto& row : results) {
        AlarmData alarmData;
        alarmData.nId = std::stoi(row[0]);              // é”™è¯¯ç 
        alarmData.nSeverityLevel = std::stoi(row[1]);   // æŠ¥è­¦ç­‰çº§
        alarmData.nDeviceId = std::stoi(row[2]);        // è®¾å¤‡ID
        alarmData.nUnitId = std::stoi(row[3]);          // å•å…ƒID
        alarmData.strDeviceName = row[4];               // è®¾å¤‡åç§°
        alarmData.strUnitName = row[5];                 // å•元名称
        alarmData.strDescription = row[6];              // æè¿°
        alarmData.strStartTime = row[7];                // å¼€å§‹æ—¶é—´
        alarmData.strEndTime = row[8];                  // ç»“束时间
        alarmData.nId = std::stoi(row[0]);              // é”™è¯¯ç 
        alarmData.nSeverityLevel = std::stoi(row[1]);   // æŠ¥è­¦ç­‰çº§
        alarmData.nDeviceId = std::stoi(row[2]);        // è®¾å¤‡ID
        alarmData.nUnitId = std::stoi(row[3]);          // å•å…ƒID
        alarmData.strDeviceName = row[4];               // è®¾å¤‡åç§°
        alarmData.strUnitName = row[5];                 // å•元名称
        alarmData.strDescription = row[6];              // æè¿°
        alarmData.strStartTime = row[7];                // å¼€å§‹æ—¶é—´
        alarmData.strEndTime = row[8];                  // ç»“束时间
        alarms.push_back(alarmData);
    }
@@ -339,7 +342,7 @@
    return alarms;
}
// æ ¹æ®æŠ¥è­¦ID查询报警
// æ ¹æ®æŠ¥è­¦ID查询报警
std::vector<AlarmData> AlarmManager::getAlarmsById(const std::string& id) {
    if (!m_pDB) {
        return {};
@@ -355,19 +358,19 @@
    auto results = m_pDB->fetchResults(query.str());
    // éåŽ†æŸ¥è¯¢ç»“æžœï¼Œå¡«å…… AlarmData ç»“构体
    // éåŽ†æŸ¥è¯¢ç»“æžœï¼Œå¡«å…… AlarmData ç»“构体
    std::vector<AlarmData> alarms;
    for (const auto& row : results) {
        AlarmData alarmData;
        alarmData.nId = std::stoi(row[0]);              // é”™è¯¯ç 
        alarmData.nSeverityLevel = std::stoi(row[1]);   // æŠ¥è­¦ç­‰çº§
        alarmData.nDeviceId = std::stoi(row[2]);        // è®¾å¤‡ID
        alarmData.nUnitId = std::stoi(row[3]);          // å•å…ƒID
        alarmData.strDeviceName = row[4];               // è®¾å¤‡åç§°
        alarmData.strUnitName = row[5];                 // å•元名称
        alarmData.strDescription = row[6];              // æè¿°
        alarmData.strStartTime = row[7];                // å¼€å§‹æ—¶é—´
        alarmData.strEndTime = row[8];                  // ç»“束时间
        alarmData.nId = std::stoi(row[0]);              // é”™è¯¯ç 
        alarmData.nSeverityLevel = std::stoi(row[1]);   // æŠ¥è­¦ç­‰çº§
        alarmData.nDeviceId = std::stoi(row[2]);        // è®¾å¤‡ID
        alarmData.nUnitId = std::stoi(row[3]);          // å•å…ƒID
        alarmData.strDeviceName = row[4];               // è®¾å¤‡åç§°
        alarmData.strUnitName = row[5];                 // å•元名称
        alarmData.strDescription = row[6];              // æè¿°
        alarmData.strStartTime = row[7];                // å¼€å§‹æ—¶é—´
        alarmData.strEndTime = row[8];                  // ç»“束时间
        alarms.push_back(alarmData);
    }
@@ -375,7 +378,7 @@
    return alarms;
}
// æ ¹æ®æè¿°æŸ¥è¯¢æŠ¥è­¦
// æ ¹æ®æè¿°æŸ¥è¯¢æŠ¥è­¦
std::vector<AlarmData> AlarmManager::getAlarmsByDescription(const std::string& description) {
    if (!m_pDB) {
        return {};
@@ -391,19 +394,19 @@
    auto results = m_pDB->fetchResults(query.str());
    // éåŽ†æŸ¥è¯¢ç»“æžœï¼Œå¡«å…… AlarmData ç»“构体
    // éåŽ†æŸ¥è¯¢ç»“æžœï¼Œå¡«å…… AlarmData ç»“构体
    std::vector<AlarmData> alarms;
    for (const auto& row : results) {
        AlarmData alarmData;
        alarmData.nId = std::stoi(row[0]);              // é”™è¯¯ç 
        alarmData.nSeverityLevel = std::stoi(row[1]);   // æŠ¥è­¦ç­‰çº§
        alarmData.nDeviceId = std::stoi(row[2]);        // è®¾å¤‡ID
        alarmData.nUnitId = std::stoi(row[3]);          // å•å…ƒID
        alarmData.strDeviceName = row[4];               // è®¾å¤‡åç§°
        alarmData.strUnitName = row[5];                 // å•元名称
        alarmData.strDescription = row[6];              // æè¿°
        alarmData.strStartTime = row[7];                // å¼€å§‹æ—¶é—´
        alarmData.strEndTime = row[8];                  // ç»“束时间
        alarmData.nId = std::stoi(row[0]);              // é”™è¯¯ç 
        alarmData.nSeverityLevel = std::stoi(row[1]);   // æŠ¥è­¦ç­‰çº§
        alarmData.nDeviceId = std::stoi(row[2]);        // è®¾å¤‡ID
        alarmData.nUnitId = std::stoi(row[3]);          // å•å…ƒID
        alarmData.strDeviceName = row[4];               // è®¾å¤‡åç§°
        alarmData.strUnitName = row[5];                 // å•元名称
        alarmData.strDescription = row[6];              // æè¿°
        alarmData.strStartTime = row[7];                // å¼€å§‹æ—¶é—´
        alarmData.strEndTime = row[8];                  // ç»“束时间
        alarms.push_back(alarmData);
    }
@@ -411,7 +414,7 @@
    return alarms;
}
// æ ¹æ®æ—¶é—´èŒƒå›´æŸ¥è¯¢æŠ¥è­¦
// æ ¹æ®æ—¶é—´èŒƒå›´æŸ¥è¯¢æŠ¥è­¦
std::vector<AlarmData> AlarmManager::getAlarmsByTimeRange(const std::string& startTime, const std::string& endTime) {
    if (!m_pDB) {
        return {};
@@ -434,19 +437,19 @@
    auto results = m_pDB->fetchResults(query.str());
    // éåŽ†æŸ¥è¯¢ç»“æžœï¼Œå¡«å…… AlarmData ç»“构体
    // éåŽ†æŸ¥è¯¢ç»“æžœï¼Œå¡«å…… AlarmData ç»“构体
    std::vector<AlarmData> alarms;
    for (const auto& row : results) {
        AlarmData alarmData;
        alarmData.nId = std::stoi(row[0]);              // é”™è¯¯ç 
        alarmData.nSeverityLevel = std::stoi(row[1]);   // æŠ¥è­¦ç­‰çº§
        alarmData.nDeviceId = std::stoi(row[2]);        // è®¾å¤‡ID
        alarmData.nUnitId = std::stoi(row[3]);          // å•å…ƒID
        alarmData.strDeviceName = row[4];               // è®¾å¤‡åç§°
        alarmData.strUnitName = row[5];                 // å•元名称
        alarmData.strDescription = row[6];              // æè¿°
        alarmData.strStartTime = row[7];                // å¼€å§‹æ—¶é—´
        alarmData.strEndTime = row[8];                  // ç»“束时间
        alarmData.nId = std::stoi(row[0]);              // é”™è¯¯ç 
        alarmData.nSeverityLevel = std::stoi(row[1]);   // æŠ¥è­¦ç­‰çº§
        alarmData.nDeviceId = std::stoi(row[2]);        // è®¾å¤‡ID
        alarmData.nUnitId = std::stoi(row[3]);          // å•å…ƒID
        alarmData.strDeviceName = row[4];               // è®¾å¤‡åç§°
        alarmData.strUnitName = row[5];                 // å•元名称
        alarmData.strDescription = row[6];              // æè¿°
        alarmData.strStartTime = row[7];                // å¼€å§‹æ—¶é—´
        alarmData.strEndTime = row[8];                  // ç»“束时间
        alarms.push_back(alarmData);
    }
@@ -454,7 +457,7 @@
    return alarms;
}
// æ ¹æ®ID、开始时间和结束时间查询报警
// æ ¹æ®ID、开始时间和结束时间查询报警
std::vector<AlarmData> AlarmManager::getAlarmsByIdAndTimeRange(const std::string& id, const std::string& startTime, const std::string& endTime) {
    if (!m_pDB) {
        return {};
@@ -477,19 +480,19 @@
    auto results = m_pDB->fetchResults(query.str());
    // éåŽ†æŸ¥è¯¢ç»“æžœï¼Œå¡«å…… AlarmData ç»“构体
    // éåŽ†æŸ¥è¯¢ç»“æžœï¼Œå¡«å…… AlarmData ç»“构体
    std::vector<AlarmData> alarms;
    for (const auto& row : results) {
        AlarmData alarmData;
        alarmData.nId = std::stoi(row[0]);              // é”™è¯¯ç 
        alarmData.nSeverityLevel = std::stoi(row[1]);   // æŠ¥è­¦ç­‰çº§
        alarmData.nDeviceId = std::stoi(row[2]);        // è®¾å¤‡ID
        alarmData.nUnitId = std::stoi(row[3]);          // å•å…ƒID
        alarmData.strDeviceName = row[4];               // è®¾å¤‡åç§°
        alarmData.strUnitName = row[5];                 // å•元名称
        alarmData.strDescription = row[6];              // æè¿°
        alarmData.strStartTime = row[7];                // å¼€å§‹æ—¶é—´
        alarmData.strEndTime = row[8];                  // ç»“束时间
        alarmData.nId = std::stoi(row[0]);              // é”™è¯¯ç 
        alarmData.nSeverityLevel = std::stoi(row[1]);   // æŠ¥è­¦ç­‰çº§
        alarmData.nDeviceId = std::stoi(row[2]);        // è®¾å¤‡ID
        alarmData.nUnitId = std::stoi(row[3]);          // å•å…ƒID
        alarmData.strDeviceName = row[4];               // è®¾å¤‡åç§°
        alarmData.strUnitName = row[5];                 // å•元名称
        alarmData.strDescription = row[6];              // æè¿°
        alarmData.strStartTime = row[7];                // å¼€å§‹æ—¶é—´
        alarmData.strEndTime = row[8];                  // ç»“束时间
        alarms.push_back(alarmData);
    }
@@ -497,7 +500,7 @@
    return alarms;
}
// åˆ†é¡µæŸ¥è¯¢æŠ¥è­¦æ•°æ®
// åˆ†é¡µæŸ¥è¯¢æŠ¥è­¦æ•°æ®
std::vector<AlarmData> AlarmManager::getAlarms(int startPosition, int count) {
    if (!m_pDB) {
        return {};
@@ -513,19 +516,19 @@
    auto results = m_pDB->fetchResults(query.str());
    // éåŽ†æŸ¥è¯¢ç»“æžœï¼Œå¡«å…… AlarmData ç»“构体
    // éåŽ†æŸ¥è¯¢ç»“æžœï¼Œå¡«å…… AlarmData ç»“构体
    std::vector<AlarmData> alarms;
    for (const auto& row : results) {
        AlarmData alarmData;
        alarmData.nId = std::stoi(row[0]);              // é”™è¯¯ç 
        alarmData.nSeverityLevel = std::stoi(row[1]);   // æŠ¥è­¦ç­‰çº§
        alarmData.nDeviceId = std::stoi(row[2]);        // è®¾å¤‡ID
        alarmData.nUnitId = std::stoi(row[3]);          // å•å…ƒID
        alarmData.strDeviceName = row[4];               // è®¾å¤‡åç§°
        alarmData.strUnitName = row[5];                 // å•元名称
        alarmData.strDescription = row[6];              // æè¿°
        alarmData.strStartTime = row[7];                // å¼€å§‹æ—¶é—´
        alarmData.strEndTime = row[8];                  // ç»“束时间
        alarmData.nId = std::stoi(row[0]);              // é”™è¯¯ç 
        alarmData.nSeverityLevel = std::stoi(row[1]);   // æŠ¥è­¦ç­‰çº§
        alarmData.nDeviceId = std::stoi(row[2]);        // è®¾å¤‡ID
        alarmData.nUnitId = std::stoi(row[3]);          // å•å…ƒID
        alarmData.strDeviceName = row[4];               // è®¾å¤‡åç§°
        alarmData.strUnitName = row[5];                 // å•元名称
        alarmData.strDescription = row[6];              // æè¿°
        alarmData.strStartTime = row[7];                // å¼€å§‹æ—¶é—´
        alarmData.strEndTime = row[8];                  // ç»“束时间
        alarms.push_back(alarmData);
    }
@@ -533,7 +536,86 @@
    return alarms;
}
// ç­›é€‰æŠ¥è­¦æ•°æ®
// èŽ·å–å½“å‰æœªç»“æŸçš„æŠ¥è­¦ï¼ˆend_time ä¸ºç©ºï¼‰ï¼Œå¹¶å¯æŒ‰ start_time æœ€è¿‘ N å°æ—¶è¿‡æ»¤
std::vector<AlarmData> AlarmManager::getActiveAlarms(int recentHours /*=12*/) {
    if (!m_pDB) {
        return {};
    }
    // è®¡ç®—时间阈值:当前时间减 recentHours
    std::string cutoffTime;
    if (recentHours > 0) {
        using namespace std::chrono;
        auto cutoff = system_clock::now() - hours(recentHours);
        std::time_t t = system_clock::to_time_t(cutoff);
        std::tm tm {};
        localtime_s(&tm, &t);
        char buf[32] = { 0 };
        std::strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tm);
        cutoffTime = buf;
    }
    std::ostringstream query;
    query << R"(
        SELECT a.id, a.severity_level, a.device_id, a.unit_id, d.device_name, u.unit_name, a.description, a.start_time, a.end_time
        FROM alarms a
        JOIN devices d ON a.device_id = d.device_id
        JOIN units u ON a.device_id = u.device_id AND a.unit_id = u.unit_id
        WHERE a.end_time IS NULL OR a.end_time = ''
    )";
    if (!cutoffTime.empty()) {
        query << " AND a.start_time >= '" << cutoffTime << "'";
    }
    query << " ORDER BY a.start_time DESC";
    auto lastErrStr = []() -> std::string {
        DWORD gle = GetLastError();
        if (gle == 0) return {};
        LPSTR buf = nullptr;
        size_t len = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
            nullptr, gle, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&buf, 0, nullptr);
        std::string s = (buf && len > 0) ? std::string(buf, len) : "";
        if (buf) LocalFree(buf);
        return s;
    };
    std::vector<std::vector<std::string>> results;
    try {
        results = m_pDB->fetchResults(query.str());
    }
    catch (const std::exception& ex) {
        DWORD gle = GetLastError();
        auto errStr = lastErrStr();
        LOGE("<AlarmManager>getActiveAlarms failed: %s, GLE=%lu (%s)", ex.what(), gle, errStr.c_str());
        return {};
    }
    std::vector<AlarmData> alarms;
    auto toInt = [](const std::string& s) -> int {
        try {
            return std::stoi(s);
        }
        catch (...) {
            return 0;
        }
    };
    for (const auto& row : results) {
        if (row.size() < 9) continue;
        AlarmData alarmData;
        alarmData.nId = toInt(row[0]);
        alarmData.nSeverityLevel = toInt(row[1]);
        alarmData.nDeviceId = toInt(row[2]);
        alarmData.nUnitId = toInt(row[3]);
        alarmData.strDeviceName = row[4];
        alarmData.strUnitName = row[5];
        alarmData.strDescription = row[6];
        alarmData.strStartTime = row[7];
        alarmData.strEndTime = row[8];
        alarms.push_back(alarmData);
    }
    return alarms;
}
// ç­›é€‰æŠ¥è­¦æ•°æ®
std::vector<AlarmData> AlarmManager::getFilteredAlarms(const std::string& keyword, const std::string& startTime, const std::string& endTime, int pageNumber, int pageSize) {
    if (!m_pDB) {
        return {};
@@ -547,7 +629,7 @@
        JOIN units u   ON a.device_id = u.device_id AND a.unit_id = u.unit_id
        WHERE 1=1)";
    // ç»Ÿä¸€å…³é”®å­—模糊查询
    // ç»Ÿä¸€å…³é”®å­—模糊查询
    if (!keyword.empty()) {
        query << " AND ("
            << "a.id LIKE '%" << keyword << "%' OR "
@@ -557,7 +639,7 @@
            << "a.description LIKE '%" << keyword << "%')";
    }
    // æ—¶é—´æ¡ä»¶
    // æ—¶é—´æ¡ä»¶
    if (!startTime.empty()) {
        query << " AND a.start_time >= '" << startTime << "'";
    }
@@ -565,26 +647,26 @@
        query << " AND a.end_time <= '" << endTime << "'";
    }
    // åˆ†é¡µè®¾ç½®
    // åˆ†é¡µè®¾ç½®
    int nOffset = (pageNumber - 1) * pageSize;
    query << " ORDER BY a.start_time DESC LIMIT " << pageSize << " OFFSET " << nOffset;
    // æŸ¥è¯¢
    // æŸ¥è¯¢
    auto results = m_pDB->fetchResults(query.str());
    // éåŽ†æŸ¥è¯¢ç»“æžœï¼Œå¡«å…… AlarmData ç»“构体
    // éåŽ†æŸ¥è¯¢ç»“æžœï¼Œå¡«å…… AlarmData ç»“构体
    std::vector<AlarmData> alarms;
    for (const auto& row : results) {
        AlarmData alarmData;
        alarmData.nId = std::stoi(row[0]);             // é”™è¯¯ç 
        alarmData.nSeverityLevel = std::stoi(row[1]);  // æŠ¥è­¦ç­‰çº§ (字符串)
        alarmData.nDeviceId = std::stoi(row[2]);       // è®¾å¤‡ID
        alarmData.nUnitId = std::stoi(row[3]);         // å•å…ƒID
        alarmData.strDeviceName = row[4];              // è®¾å¤‡åç§°
        alarmData.strUnitName = row[5];                // å•元名称
        alarmData.strDescription = row[6];             // æè¿°
        alarmData.strStartTime = row[7];               // å¼€å§‹æ—¶é—´
        alarmData.strEndTime = row[8];                 // ç»“束时间
        alarmData.nId = std::stoi(row[0]);             // é”™è¯¯ç 
        alarmData.nSeverityLevel = std::stoi(row[1]);  // æŠ¥è­¦ç­‰çº§ (字符串)
        alarmData.nDeviceId = std::stoi(row[2]);       // è®¾å¤‡ID
        alarmData.nUnitId = std::stoi(row[3]);         // å•å…ƒID
        alarmData.strDeviceName = row[4];              // è®¾å¤‡åç§°
        alarmData.strUnitName = row[5];                // å•元名称
        alarmData.strDescription = row[6];             // æè¿°
        alarmData.strStartTime = row[7];               // å¼€å§‹æ—¶é—´
        alarmData.strEndTime = row[8];                 // ç»“束时间
        alarms.push_back(alarmData);
    }
@@ -592,7 +674,7 @@
    return alarms;
}
// èŽ·å–ç¬¦åˆæ¡ä»¶çš„æŠ¥è­¦æ€»æ•°
// èŽ·å–ç¬¦åˆæ¡ä»¶çš„æŠ¥è­¦æ€»æ•°
int AlarmManager::getTotalAlarmCount(const std::string& keyword, const std::string& startTime, const std::string& endTime) {
    if (!m_pDB) {
        return 0;
@@ -606,7 +688,7 @@
        JOIN units u   ON a.device_id = u.device_id AND a.unit_id = u.unit_id
        WHERE 1=1)";
    // ç»Ÿä¸€å…³é”®å­—模糊查询
    // ç»Ÿä¸€å…³é”®å­—模糊查询
    if (!keyword.empty()) {
        query << " AND ("
            << "a.id LIKE '%" << keyword << "%' OR "
@@ -616,7 +698,7 @@
            << "a.description LIKE '%" << keyword << "%')";
    }
    // æ—¶é—´æ¡ä»¶
    // æ—¶é—´æ¡ä»¶
    if (!startTime.empty()) {
        query << " AND a.start_time >= '" << startTime << "'";
    }
@@ -628,7 +710,7 @@
    return (!results.empty() && !results[0].empty()) ? std::stoi(results[0][0]) : 0;
}
// æ›´æ–°æŠ¥è­¦çš„结束时间
// æ›´æ–°æŠ¥è­¦çš„结束时间
bool AlarmManager::updateAlarmEndTime(
    const std::string& id,
    const std::string& severityLevel,
@@ -642,7 +724,7 @@
        return false;
    }
    // æ›´æ–°æŠ¥è­¦ç»“束时间
    // æ›´æ–°æŠ¥è­¦ç»“束时间
    std::ostringstream updateQuery;
    updateQuery << "UPDATE alarms SET end_time = '" << newEndTime << "'"
        << " WHERE id = '" << id << "'"
@@ -655,7 +737,7 @@
    return m_pDB->executeQuery(updateQuery.str());
}
// æ¸…理旧报警数据
// æ¸…理旧报警数据
void AlarmManager::cleanOldAlarms(int daysToKeep, const std::string& deviceId, const std::string& unitId) {
    if (!m_pDB) {
        return;
@@ -674,7 +756,7 @@
    m_pDB->executeQuery(query.str());
}
// é€šè¿‡è®¾å¤‡ID获取设备名称
// é€šè¿‡è®¾å¤‡ID获取设备名称
std::string AlarmManager::getDeviceNameById(int deviceId) {
    if (!m_pDB) {
        return "";
@@ -688,10 +770,10 @@
        return "";
    }
    return result[0][0];  // è¿”回查询到的设备名称
    return result[0][0];  // è¿”回查询到的设备名称
}
// é€šè¿‡è®¾å¤‡ID和单元ID获取单元名称
// é€šè¿‡è®¾å¤‡ID和单元ID获取单元名称
std::string AlarmManager::getUnitNameById(int deviceId, int unitId) {
    if (!m_pDB) {
        return "";
@@ -706,10 +788,10 @@
        return "";
    }
    return result[0][0];  // è¿”回查询到的单元名称
    return result[0][0];  // è¿”回查询到的单元名称
}
// èŽ·å–æœ€è¿‘æ’å…¥çš„ alarm_event_id
// èŽ·å–æœ€è¿‘æ’å…¥çš„ alarm_event_id
int AlarmManager::getLastInsertId() {
    std::string query = "SELECT last_insert_rowid();";
    auto results = m_pDB->fetchResults(query);
@@ -718,12 +800,12 @@
        return -1;
    }
    // ä»ŽæŸ¥è¯¢ç»“果中获取最后插入的 ID
    // ä»ŽæŸ¥è¯¢ç»“果中获取最后插入的 ID
    int lastInsertId = std::stoi(results[0][0]);
    return lastInsertId;
}
// é€šè¿‡ alarm_event_id è§£é™¤æŠ¥è­¦ï¼ˆæ›´æ–°ç»“束时间)
// é€šè¿‡ alarm_event_id è§£é™¤æŠ¥è­¦ï¼ˆæ›´æ–°ç»“束时间)
bool AlarmManager::clearAlarmByEventId(int alarmEventId, const std::string& endTime) {
    if (!m_pDB) {
        return false;
@@ -745,7 +827,7 @@
    return result;
}
// é€šè¿‡å¤šä¸ªå±žæ€§æŸ¥æ‰¾å¹¶è§£é™¤æŠ¥è­¦ï¼ˆæ›´æ–°ç»“束时间)
// é€šè¿‡å¤šä¸ªå±žæ€§æŸ¥æ‰¾å¹¶è§£é™¤æŠ¥è­¦ï¼ˆæ›´æ–°ç»“束时间)
bool AlarmManager::clearAlarmByAttributes(int nId, int nDeviceId, int nUnitId, const std::string& endTime) {
    if (!m_pDB) {
        return false;
@@ -753,7 +835,7 @@
    std::lock_guard<std::mutex> lock(m_mutex);
    // å…ˆåœ¨ç¼“存中查找匹配的 alarm_event_id
    // å…ˆåœ¨ç¼“存中查找匹配的 alarm_event_id
    int alarmEventId = -1;
    for (AlarmDataMap::const_iterator it = m_mapCache.begin(); it != m_mapCache.end(); ++it) {
        const AlarmData& alarm = it->second;
@@ -766,12 +848,32 @@
        }
    }
    // å¦‚果没找到匹配的记录,则直接返回 false
    if (alarmEventId == -1) {
        return false;
    }
    // ç¼“存未命中时,从数据库查找仍未结束的记录(取最新一条)
    if (alarmEventId == -1) {
        std::ostringstream querySel;
        querySel << "SELECT alarm_event_id FROM alarms WHERE "
            << "id = " << nId
            << " AND device_id = " << nDeviceId
            << " AND unit_id = " << nUnitId
            << " AND (end_time IS NULL OR end_time = '') "
            << "ORDER BY start_time DESC LIMIT 1;";
        auto results = m_pDB->fetchResults(querySel.str());
        if (!results.empty() && !results[0].empty()) {
            try {
                alarmEventId = std::stoi(results[0][0]);
            }
            catch (...) {
                alarmEventId = -1;
            }
        }
    }
    // æž„建 SQL è¯­å¥ï¼Œä½¿ç”¨æ‰¾åˆ°çš„ alarm_event_id æ¥æ›´æ–°ç»“束时间
    // å¦‚果没找到匹配的记录,则直接返回 false
    if (alarmEventId == -1) {
        return false;
    }
    // æž„建 SQL è¯­å¥ï¼Œä½¿ç”¨æ‰¾åˆ°çš„ alarm_event_id æ¥æ›´æ–°ç»“束时间
    std::ostringstream query;
    query << "UPDATE alarms SET end_time = '" << endTime << "' WHERE alarm_event_id = " << alarmEventId << ";";
    bool result = m_pDB->executeQuery(query.str());
@@ -782,7 +884,7 @@
    return result;
}
// è¯»å–报警文件
// è¯»å–报警文件
bool AlarmManager::readAlarmFile(const std::string& filename) {
    std::ifstream file(filename, std::ios::binary);
    if (!file.is_open()) {
@@ -795,7 +897,7 @@
        char ch;
        while (f.get(ch)) {
            if (ch == '\r') {
                // å¤„理 \r\n æˆ– å•独 \r
                // å¤„理 \r\n æˆ– å•独 \r
                if (f.peek() == '\n') f.get();
                break;
            }
@@ -850,19 +952,19 @@
    return true;
}
// å°†æŠ¥è­¦æ•°æ®ä¿å­˜åˆ°æ–‡ä»¶
// å°†æŠ¥è­¦æ•°æ®ä¿å­˜åˆ°æ–‡ä»¶
bool AlarmManager::saveAlarmFile(const std::string& filename) {
    std::ofstream file(filename);
    if (!file.is_open()) {
        std::cerr << "打开文件写入失败!" << std::endl;
        std::cerr << "打开文件写入失败!" << std::endl;
        return false;
    }
    // å†™å…¥æ ‡é¢˜è¡Œ
    // å†™å…¥æ ‡é¢˜è¡Œ
    file << "No,UNIT ID,UNIT NO,Alarm Level,Alarm Code,AlarmID,Alarm Text,Description\n";
    // å†™å…¥æŠ¥è­¦æ•°æ®
    // å†™å…¥æŠ¥è­¦æ•°æ®
    int nIndex = 1;
    for (const auto& pair : m_mapAlarm) {
        const AlarmInfo& alarm = pair.second;
@@ -880,19 +982,19 @@
    return true;
}
// é€šè¿‡ AlarmID æŸ¥è¯¢å¯¹åº”的报警信息
// é€šè¿‡ AlarmID æŸ¥è¯¢å¯¹åº”的报警信息
const AlarmInfo* AlarmManager::getAlarmInfoByID(int nAlarmID) const {
    auto it = m_mapAlarm.find(nAlarmID);
    if (it != m_mapAlarm.end()) {
        return &(it->second);
    }
    else {
        std::cerr << "未找到 AlarmID: " << nAlarmID << std::endl;
        std::cerr << "未找到 AlarmID: " << nAlarmID << std::endl;
        return nullptr;
    }
}
// é€šè¿‡å¤šä¸ª AlarmID æŸ¥è¯¢å¯¹åº”的报警信息
// é€šè¿‡å¤šä¸ª AlarmID æŸ¥è¯¢å¯¹åº”的报警信息
std::vector<AlarmInfo> AlarmManager::getAlarmsInfoByIDs(const std::vector<int>& alarmIDs) const {
    std::vector<AlarmInfo> alarms;
@@ -902,7 +1004,7 @@
            alarms.push_back(it->second);
        } 
        else {
            std::cerr << "未找到 AlarmID: " << alarmID << std::endl;
            std::cerr << "未找到 AlarmID: " << alarmID << std::endl;
        }
    }
SourceCode/Bond/Servo/AlarmManager.h
@@ -1,4 +1,4 @@
#ifndef ALARM_MANAGER_H
#ifndef ALARM_MANAGER_H
#define ALARM_MANAGER_H
#include <string>
@@ -18,15 +18,15 @@
};
struct AlarmData {
    int nId;                       // é”™è¯¯ç 
    int nSeverityLevel;            // æŠ¥è­¦ç­‰çº§
    int nDeviceId;                 // è®¾å¤‡ID
    int nUnitId;                   // å•å…ƒID
    std::string strDeviceName;     // è®¾å¤‡åç§°
    std::string strUnitName;       // å•元名称
    std::string strDescription;    // æè¿°
    std::string strStartTime;      // å¼€å§‹æ—¶é—´
    std::string strEndTime;        // ç»“束时间
    int nId;                       // é”™è¯¯ç 
    int nSeverityLevel;            // æŠ¥è­¦ç­‰çº§
    int nDeviceId;                 // è®¾å¤‡ID
    int nUnitId;                   // å•å…ƒID
    std::string strDeviceName;     // è®¾å¤‡åç§°
    std::string strUnitName;       // å•元名称
    std::string strDescription;    // æè¿°
    std::string strStartTime;      // å¼€å§‹æ—¶é—´
    std::string strEndTime;        // ç»“束时间
};
using AlarmInfoMap = std::unordered_map<int, AlarmInfo>;
@@ -35,116 +35,117 @@
class AlarmManager {
public:
    /**
     * èŽ·å–å•ä¾‹å®žä¾‹
     * @return AlarmManager实例的引用
     * èŽ·å–å•ä¾‹å®žä¾‹
     * @return AlarmManager实例的引用
     */
    static AlarmManager& getInstance();
    /**
     * åˆå§‹åŒ–报警表
     * @return æˆåŠŸè¿”å›žtrue,失败返回false
     * åˆå§‹åŒ–报警表
     * @return æˆåŠŸè¿”å›žtrue,失败返回false
     */
    bool initAlarmTable();
    /**
     * é”€æ¯æŠ¥è­¦è¡¨
     * é”€æ¯æŠ¥è­¦è¡¨
     */
    void termAlarmTable();
    /**
     * é”€æ¯æŠ¥è­¦è¡¨
     * @return æˆåŠŸè¿”å›žtrue,失败返回false
     * é”€æ¯æŠ¥è­¦è¡¨
     * @return æˆåŠŸè¿”å›žtrue,失败返回false
     */
    bool destroyAlarmTable();
    /**
    * æ’入模拟数据
    * æ’入模拟数据
    */
    void insertMockData();
    /**
     * æ·»åŠ æŠ¥è­¦
     * @param alarmData æŠ¥è­¦æ•°æ®çš„结构体
     * @param alarmEventId æœ€è¿‘插入的 alarm_event_id
     * @return æˆåŠŸè¿”å›žtrue,失败返回false
     * æ·»åŠ æŠ¥è­¦
     * @param alarmData æŠ¥è­¦æ•°æ®çš„结构体
     * @param alarmEventId æœ€è¿‘插入的 alarm_event_id
     * @return æˆåŠŸè¿”å›žtrue,失败返回false
     */
    bool addAlarm(const AlarmData& alarmData, int& alarmEventId);
    /**
     * æŸ¥è¯¢æ‰€æœ‰æŠ¥è­¦æ•°æ®
     * @return åŒ…含所有报警数据的结构体
     * æŸ¥è¯¢æ‰€æœ‰æŠ¥è­¦æ•°æ®
     * @return åŒ…含所有报警数据的结构体
     */
    std::vector<AlarmData> getAllAlarms();
    /**
     * æ ¹æ®æŠ¥è­¦ID查询报警
     * @param id æŠ¥è­¦ID
     * @return åŒ…含筛选后报警数据的结构体
     * æ ¹æ®æŠ¥è­¦ID查询报警
     * @param id æŠ¥è­¦ID
     * @return åŒ…含筛选后报警数据的结构体
     */
    std::vector<AlarmData> getAlarmsById(const std::string& id);
    /**
     * æ ¹æ®æè¿°æŸ¥è¯¢æŠ¥è­¦
     * @param description æŠ¥è­¦æè¿°çš„筛选条件
     * @return åŒ…含筛选后报警数据的结构体
     * æ ¹æ®æè¿°æŸ¥è¯¢æŠ¥è­¦
     * @param description æŠ¥è­¦æè¿°çš„筛选条件
     * @return åŒ…含筛选后报警数据的结构体
     */
    std::vector<AlarmData> getAlarmsByDescription(const std::string& description);
    /**
     * æ ¹æ®æ—¶é—´èŒƒå›´æŸ¥è¯¢æŠ¥è­¦
     * @param startTime èµ·å§‹æ—¶é—´
     * @param endTime ç»“束时间
     * @return åŒ…含查询结果的报警数据
     * æ ¹æ®æ—¶é—´èŒƒå›´æŸ¥è¯¢æŠ¥è­¦
     * @param startTime èµ·å§‹æ—¶é—´
     * @param endTime ç»“束时间
     * @return åŒ…含查询结果的报警数据
     */
    std::vector<AlarmData> getAlarmsByTimeRange(const std::string& startTime, const std::string& endTime);
    /**
    * æ ¹æ®ID和时间范围查询报警
     * @param id æŠ¥è­¦ID
     * @param startTime èµ·å§‹æ—¶é—´
     * @param endTime ç»“束时间
     * @return åŒ…含查询结果的报警数据
    * æ ¹æ®ID和时间范围查询报警
     * @param id æŠ¥è­¦ID
     * @param startTime èµ·å§‹æ—¶é—´
     * @param endTime ç»“束时间
     * @return åŒ…含查询结果的报警数据
     */
    std::vector<AlarmData> getAlarmsByIdAndTimeRange(const std::string& id, const std::string& startTime, const std::string& endTime);
    /**
     * èŽ·å–æŠ¥è­¦æ•°æ®
     * @param startPosition èµ·å§‹ä½ç½®
     * @param count èŽ·å–çš„è®°å½•æ•°é‡
     * @return åŒ…含查询结果的报警数据
     * èŽ·å–æŠ¥è­¦æ•°æ®
     * @param startPosition èµ·å§‹ä½ç½®
     * @param count èŽ·å–çš„è®°å½•æ•°é‡
     * @return åŒ…含查询结果的报警数据
     */
    std::vector<AlarmData> getAlarms(int startPosition, int count);
    std::vector<AlarmData> getActiveAlarms(int recentHours = 12);
    /**
     * ç­›é€‰æŠ¥è­¦æ•°æ®
     * @param keyword å…³é”®å­—筛选条件
     * @param startTime èµ·å§‹æ—¶é—´ç­›é€‰æ¡ä»¶
     * @param endTime ç»“束时间筛选条件
     * @param pageNumber é¡µç 
     * @param pageSize æ¯é¡µè®°å½•æ•°
     * @return åŒ…含筛选后报警数据的结构体
     * ç­›é€‰æŠ¥è­¦æ•°æ®
     * @param keyword å…³é”®å­—筛选条件
     * @param startTime èµ·å§‹æ—¶é—´ç­›é€‰æ¡ä»¶
     * @param endTime ç»“束时间筛选条件
     * @param pageNumber é¡µç 
     * @param pageSize æ¯é¡µè®°å½•æ•°
     * @return åŒ…含筛选后报警数据的结构体
     */
    std::vector<AlarmData> getFilteredAlarms(const std::string& keyword, const std::string& startTime, const std::string& endTime, int pageNumber, int pageSize);
    /**
     * èŽ·å–ç¬¦åˆæ¡ä»¶çš„æŠ¥è­¦æ€»æ•°
     * @param keyword å…³é”®å­—筛选条件
     * @param startTime èµ·å§‹æ—¶é—´ç­›é€‰æ¡ä»¶
     * @param endTime ç»“束时间筛选条件
     * @return ç¬¦åˆæ¡ä»¶çš„æŠ¥è­¦æ€»æ•°
     * èŽ·å–ç¬¦åˆæ¡ä»¶çš„æŠ¥è­¦æ€»æ•°
     * @param keyword å…³é”®å­—筛选条件
     * @param startTime èµ·å§‹æ—¶é—´ç­›é€‰æ¡ä»¶
     * @param endTime ç»“束时间筛选条件
     * @return ç¬¦åˆæ¡ä»¶çš„æŠ¥è­¦æ€»æ•°
     */
    int getTotalAlarmCount(const std::string& keyword, const std::string& startTime, const std::string& endTime);
    /**
     * æ›´æ–°æŠ¥è­¦ç»“束时间
     * @param id æŠ¥è­¦ID
     * @param severityLevel æŠ¥è­¦ç­‰çº§ç­›é€‰æ¡ä»¶
     * @param deviceId è®¾å¤‡ID
     * @param unitId å•å…ƒID
     * @param description æŠ¥è­¦æè¿°
     * @param startTime æŠ¥è­¦å¼€å§‹æ—¶é—´
     * @param newEndTime æ–°çš„æŠ¥è­¦ç»“束时间
     * @return æˆåŠŸè¿”å›žtrue,失败返回false
     * æ›´æ–°æŠ¥è­¦ç»“束时间
     * @param id æŠ¥è­¦ID
     * @param severityLevel æŠ¥è­¦ç­‰çº§ç­›é€‰æ¡ä»¶
     * @param deviceId è®¾å¤‡ID
     * @param unitId å•å…ƒID
     * @param description æŠ¥è­¦æè¿°
     * @param startTime æŠ¥è­¦å¼€å§‹æ—¶é—´
     * @param newEndTime æ–°çš„æŠ¥è­¦ç»“束时间
     * @return æˆåŠŸè¿”å›žtrue,失败返回false
     */
    bool updateAlarmEndTime(
        const std::string& id,
@@ -156,79 +157,79 @@
        const std::string& newEndTime);
    /**
     * æ¸…理旧报警
     * @param daysToKeep ä¿ç•™çš„天数
     * @param deviceId è®¾å¤‡ID
     * @param unitId å•å…ƒID
     * æ¸…理旧报警
     * @param daysToKeep ä¿ç•™çš„天数
     * @param deviceId è®¾å¤‡ID
     * @param unitId å•å…ƒID
     */
    void cleanOldAlarms(int daysToKeep = 30, const std::string& deviceId = "", const std::string& unitId = "");
    /**
    * é€šè¿‡è®¾å¤‡ID获取设备名称
    * @param deviceId è®¾å¤‡ID
    * @return æˆåŠŸè¿”å›žè®¾å¤‡åç§°ï¼Œå¤±è´¥è¿”å›žç©º
    * é€šè¿‡è®¾å¤‡ID获取设备名称
    * @param deviceId è®¾å¤‡ID
    * @return æˆåŠŸè¿”å›žè®¾å¤‡åç§°ï¼Œå¤±è´¥è¿”å›žç©º
    */
    std::string getDeviceNameById(int deviceId);
    /**
    * é€šè¿‡è®¾å¤‡ID和单元ID获取单元名称
    * @param deviceId è®¾å¤‡ID
    * @param unitId å•å…ƒID
    * @return æˆåŠŸè¿”å›žå•å…ƒåç§°ï¼Œå¤±è´¥è¿”å›žç©º
    * é€šè¿‡è®¾å¤‡ID和单元ID获取单元名称
    * @param deviceId è®¾å¤‡ID
    * @param unitId å•å…ƒID
    * @return æˆåŠŸè¿”å›žå•å…ƒåç§°ï¼Œå¤±è´¥è¿”å›žç©º
    */
    std::string getUnitNameById(int deviceId, int unitId);
    /**
    * èŽ·å–æœ€è¿‘æ’å…¥çš„ alarm_event_id
    * @return å¤±è´¥è¿”回-1,成功返回最近插入的 alarm_event_id
    * èŽ·å–æœ€è¿‘æ’å…¥çš„ alarm_event_id
    * @return å¤±è´¥è¿”回-1,成功返回最近插入的 alarm_event_id
    */
    int getLastInsertId();
    /**
    * é€šè¿‡äº‹ä»¶id解除报警(更新结束时间)
    * @param alarmEventId äº‹ä»¶ID
    * @param endTime ç»“束时间
    * @return æˆåŠŸè¿”å›žtrue,失败返回false
    * é€šè¿‡äº‹ä»¶id解除报警(更新结束时间)
    * @param alarmEventId äº‹ä»¶ID
    * @param endTime ç»“束时间
    * @return æˆåŠŸè¿”å›žtrue,失败返回false
    */
    bool clearAlarmByEventId(int alarmEventId, const std::string& endTime);
    /**
    * é€šè¿‡å¤šä¸ªå±žæ€§æŸ¥æ‰¾å¹¶è§£é™¤æŠ¥è­¦ï¼ˆæ›´æ–°ç»“束时间)
    * @param nId æŠ¥è­¦ID
    * @param nSeverityLevel æŠ¥è­¦ç­‰çº§
    * @param nDeviceId è®¾å¤‡ID
    * @param nUnitId å•å…ƒID
    * @param strDescription æè¿°
    * @param endTime ç»“束时间
    * @return æˆåŠŸè¿”å›žtrue,失败返回false
    * é€šè¿‡å¤šä¸ªå±žæ€§æŸ¥æ‰¾å¹¶è§£é™¤æŠ¥è­¦ï¼ˆæ›´æ–°ç»“束时间)
    * @param nId æŠ¥è­¦ID
    * @param nSeverityLevel æŠ¥è­¦ç­‰çº§
    * @param nDeviceId è®¾å¤‡ID
    * @param nUnitId å•å…ƒID
    * @param strDescription æè¿°
    * @param endTime ç»“束时间
    * @return æˆåŠŸè¿”å›žtrue,失败返回false
    */
    bool clearAlarmByAttributes(int nId, int nDeviceId, int nUnitId, const std::string& endTime);
    /**
     * è¯»å–报警文件
     * @param filename æ–‡ä»¶å
     * @return æˆåŠŸè¿”å›žtrue,失败返回false
     * è¯»å–报警文件
     * @param filename æ–‡ä»¶å
     * @return æˆåŠŸè¿”å›žtrue,失败返回false
     */
    bool readAlarmFile(const std::string& filename);
    /**
     * ä¿å­˜æŠ¥è­¦æ–‡ä»¶
     * @param filename æ–‡ä»¶å
     * @return æˆåŠŸè¿”å›žtrue,失败返回false
     * ä¿å­˜æŠ¥è­¦æ–‡ä»¶
     * @param filename æ–‡ä»¶å
     * @return æˆåŠŸè¿”å›žtrue,失败返回false
     */
    bool saveAlarmFile(const std::string& filename);
    /**
     * é€šè¿‡æŠ¥è­¦ID查询报警信息
     * @param nAlarmID æŠ¥è­¦ID
     * @return æŠ¥è­¦ä¿¡æ¯çš„æŒ‡é’ˆ
     * é€šè¿‡æŠ¥è­¦ID查询报警信息
     * @param nAlarmID æŠ¥è­¦ID
     * @return æŠ¥è­¦ä¿¡æ¯çš„æŒ‡é’ˆ
     */
    const AlarmInfo* getAlarmInfoByID(int nAlarmID) const;
    /**
    * é€šè¿‡å¤šä¸ªæŠ¥è­¦ID查询对应的报警信息
    * @param alarmIDs å¤šä¸ªæŠ¥è­¦ID
    * @return è¿”回多个报警信息
    * é€šè¿‡å¤šä¸ªæŠ¥è­¦ID查询对应的报警信息
    * @param alarmIDs å¤šä¸ªæŠ¥è­¦ID
    * @return è¿”回多个报警信息
    */
    std::vector<AlarmInfo> getAlarmsInfoByIDs(const std::vector<int>& alarmIDs) const;
@@ -236,7 +237,7 @@
    AlarmManager();
    ~AlarmManager();
    // ç¦æ­¢æ‹·è´å’Œèµ‹å€¼
    // ç¦æ­¢æ‹·è´å’Œèµ‹å€¼
    AlarmManager(const AlarmManager&) = delete;
    AlarmManager& operator=(const AlarmManager&) = delete;
SourceCode/Bond/Servo/AlarmPopupDlg.cpp
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,321 @@
#include "stdafx.h"
#include "Servo.h"
#include "AlarmPopupDlg.h"
#include "afxdialogex.h"
#include "Log.h"
#include "Common.h"
#include "HorizontalLine.h"
#include "ServoDlg.h"
IMPLEMENT_DYNAMIC(CAlarmPopupDlg, CDialogEx)
CAlarmPopupDlg::CAlarmPopupDlg(CWnd* pParent /*=NULL*/)
    : CDialogEx(IDD_DIALOG_POPUP_ALARM, pParent)
    , m_hasActive(false)
{
    memset(&m_activeAlarm, 0, sizeof(m_activeAlarm));
    m_crBkgnd = RGB(112, 146, 190);
    m_hbrBkgnd = nullptr;
}
CAlarmPopupDlg::~CAlarmPopupDlg()
{
}
void CAlarmPopupDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAlarmPopupDlg, CDialogEx)
    ON_BN_CLICKED(IDC_POPUP_BTN_CLOSE, &CAlarmPopupDlg::OnBnClickedClose)
    ON_BN_CLICKED(IDC_BUTTON_ALARM_OFF, &CAlarmPopupDlg::OnBnClickedAlarmOff)
    ON_BN_CLICKED(IDC_BUTTON_PREV, &CAlarmPopupDlg::OnBnClickedPrev)
    ON_BN_CLICKED(IDC_BUTTON_NEXT, &CAlarmPopupDlg::OnBnClickedNext)
    ON_WM_CTLCOLOR()
    ON_WM_DESTROY()
END_MESSAGE_MAP()
BOOL CAlarmPopupDlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();
    // èƒŒæ™¯åˆ·
    if (m_hbrBkgnd != nullptr) {
        ::DeleteObject(m_hbrBkgnd);
    }
    m_hbrBkgnd = CreateSolidBrush(m_crBkgnd);
    // å­—体
    HFONT hFontDefault = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
    LOGFONT lf;
    ::GetObject(hFontDefault, sizeof(LOGFONT), &lf);
    lf.lfHeight -= 8;
    lf.lfWeight = 700;
    m_fontTitle.CreateFontIndirect(&lf);
    ::GetObject(hFontDefault, sizeof(LOGFONT), &lf);
    lf.lfHeight -= 8;
    m_fontLevel.CreateFontIndirect(&lf);
    ::GetObject(hFontDefault, sizeof(LOGFONT), &lf);
    lf.lfHeight -= 16;
    m_fontName.CreateFontIndirect(&lf);
    ::GetObject(hFontDefault, sizeof(LOGFONT), &lf);
    lf.lfHeight -= 8;
    m_fontDescription.CreateFontIndirect(&lf);
    GetDlgItem(IDC_LABEL_TITLE)->SetFont(&m_fontTitle);
    GetDlgItem(IDC_LABEL_LEVEL)->SetFont(&m_fontLevel);
    GetDlgItem(IDC_LABEL_NAME)->SetFont(&m_fontName);
    GetDlgItem(IDC_LABEL_DESCRIPTION)->SetFont(&m_fontDescription);
    GetDlgItem(IDC_LABEL_NO_ALARM)->SetFont(&m_fontDescription);
    // å›¾æ ‡
    CString strIcon1;
    HICON hIcon;
    CStatic* pStatic;
    strIcon1.Format(_T("%s\\Res\\Alarm_o_24.ico"), theApp.m_strAppDir);
    pStatic = (CStatic*)GetDlgItem(IDC_ICON_TITLE);
    hIcon = (HICON)::LoadImage(AfxGetInstanceHandle(),
        strIcon1, IMAGE_ICON, 24, 24,
        LR_LOADFROMFILE | LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE);
    pStatic->SetIcon(hIcon);
    strIcon1.Format(_T("%s\\Res\\Alarm_o_64.ico"), theApp.m_strAppDir);
    pStatic = (CStatic*)GetDlgItem(IDC_ICON_ALARM);
    hIcon = (HICON)::LoadImage(AfxGetInstanceHandle(),
        strIcon1, IMAGE_ICON, 64, 64,
        LR_LOADFROMFILE | LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE);
    pStatic->SetIcon(hIcon);
    // å…³é—­æŒ‰é’®
    strIcon1.Format(_T("%s\\Res\\close_blcak_24.ico"), theApp.m_strAppDir);
    pStatic = (CStatic*)GetDlgItem(IDC_ICON_ALARM);
    hIcon = (HICON)::LoadImage(AfxGetInstanceHandle(),
        strIcon1, IMAGE_ICON, 128, 128,
        LR_LOADFROMFILE | LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE);
    m_btnClose.SubclassDlgItem(IDC_POPUP_BTN_CLOSE, this);
    m_btnClose.SetIcon(hIcon, hIcon, 24);
    m_btnClose.SetFaceColor(m_crBkgnd);
    m_btnClose.SetBkgndColor(BS_NORMAL, BTN_ALARM_OFF_BKGND_NORMAL);
    m_btnClose.SetBkgndColor(BS_HOVER, BTN_ALARM_OFF_BKGND_NORMAL);
    m_btnClose.SetBkgndColor(BS_PRESS, BTN_ALARM_OFF_BKGND_PRESS);
    m_btnClose.SetFrameColor(m_crBkgnd);
    // è§£é™¤è­¦å‘ŠæŒ‰é’®
    m_btnAlarmOff.SubclassDlgItem(IDC_BUTTON_ALARM_OFF, this);
    m_btnAlarmOff.SetFrameColor(BS_NORMAL, BTN_ALARM_OFF_FRAME_NORMAL);
    m_btnAlarmOff.SetFrameColor(BS_HOVER, BTN_ALARM_OFF_FRAME_HOVER);
    m_btnAlarmOff.SetFrameColor(BS_PRESS, BTN_ALARM_OFF_FRAME_PRESS);
    m_btnAlarmOff.SetBkgndColor(BS_NORMAL, BTN_ALARM_OFF_BKGND_NORMAL);
    m_btnAlarmOff.SetBkgndColor(BS_HOVER, BTN_ALARM_OFF_BKGND_HOVER);
    m_btnAlarmOff.SetBkgndColor(BS_PRESS, BTN_ALARM_OFF_BKGND_PRESS);
    // é™éŸ³æŒ‰é’®
    bool bMute = false;
    m_btnSoundOff.SubclassDlgItem(IDC_BUTTON_SOUND_OFF, this);
    m_btnSoundOff.SetFrameColor(BS_NORMAL, BTN_SOUND_OFF_FRAME_NORMAL);
    m_btnSoundOff.SetFrameColor(BS_HOVER, BTN_SOUND_OFF_FRAME_HOVER);
    m_btnSoundOff.SetFrameColor(BS_PRESS, BTN_SOUND_OFF_FRAME_PRESS);
    SetButtonBackgroundColors(bMute);
    // æ¨ªçº¿1
    CHorizontalLine* pLine = CHorizontalLine::Hook(GetDlgItem(IDC_LINE1)->m_hWnd);
    pLine->SetBkgndColor(m_crBkgnd);
    pLine->SetLineColor(RGB(168, 168, 168));
    pLine = CHorizontalLine::Hook(GetDlgItem(IDC_LINE2)->m_hWnd);
    pLine->SetBkgndColor(m_crBkgnd);
    pLine->SetLineColor(RGB(168, 168, 168));
    RefreshContent();
    return TRUE;
}
void CAlarmPopupDlg::ShowNoAlarmControls(bool bShow)
{
    const int ids[] = { IDC_LABEL_NO_ALARM };
    for (int id : ids) {
        if (auto* p = GetDlgItem(id)) {
            p->ShowWindow(bShow ? SW_SHOW : SW_HIDE);
        }
    }
}
void CAlarmPopupDlg::ShowAlarmControls(bool bShow)
{
    const int ids[] = {
        IDC_BUTTON_PREV, IDC_BUTTON_NEXT,
        IDC_LABEL_TITLE, IDC_ICON_ALARM, IDC_ICON_TITLE,
        IDC_LABEL_LEVEL, IDC_LABEL_NAME,
        IDC_LINE1, IDC_BUTTON_SOUND_OFF, IDC_BUTTON_ALARM_OFF,
        IDC_LINE2, IDC_LABEL_DESCRIPTION
    };
    for (int id : ids) {
        if (auto* p = GetDlgItem(id)) {
            p->ShowWindow(bShow ? SW_SHOW : SW_HIDE);
        }
    }
}
void CAlarmPopupDlg::RefreshContent()
{
    m_activeAlarms = AlarmManager::getInstance().getActiveAlarms();
    m_activeIndex = 0;
    if (!m_activeAlarms.empty()) {
        m_hasActive = true;
        DisplayActiveAt(m_activeIndex);
        ShowAlarmControls(true);
        ShowNoAlarmControls(false);
    }
    else {
        m_hasActive = false;
        SetDlgItemText(IDC_LABEL_NO_ALARM, _T("当前无报警"));
        SetDlgItemText(IDC_LABEL_NAME, _T(""));
        SetDlgItemText(IDC_LABEL_LEVEL, _T(""));
        SetDlgItemText(IDC_LABEL_DESCRIPTION, _T(""));
        ShowAlarmControls(false);
        ShowNoAlarmControls(true);
    }
}
void CAlarmPopupDlg::OnBnClickedClose()
{
    ShowWindow(SW_HIDE);
}
void CAlarmPopupDlg::OnBnClickedAlarmOff()
{
    if (!m_hasActive) return;
    AlarmManager& alarmManager = AlarmManager::getInstance();
    alarmManager.clearAlarmByAttributes(
        m_activeAlarm.nId,
        m_activeAlarm.nDeviceId,
        m_activeAlarm.nUnitId,
        CToolUnits::getCurrentTimeString());
    RefreshContent();
}
void CAlarmPopupDlg::OnBnClickedPrev()
{
    if (m_activeIndex > 0) {
        --m_activeIndex;
        DisplayActiveAt(m_activeIndex);
    }
}
void CAlarmPopupDlg::OnBnClickedNext()
{
    if (m_activeIndex + 1 < static_cast<int>(m_activeAlarms.size())) {
        ++m_activeIndex;
        DisplayActiveAt(m_activeIndex);
    }
}
void CAlarmPopupDlg::DisplayActiveAt(int idx)
{
    if (idx < 0 || idx >= static_cast<int>(m_activeAlarms.size())) return;
    m_activeAlarm = m_activeAlarms[idx];
    // æ ‡è®°å·²è¯»
    if (auto* pParent = dynamic_cast<CServoDlg*>(GetParent())) {
        pParent->AckAlarm(m_activeAlarm.nId);
    }
    AlarmManager& alarmManager = AlarmManager::getInstance();
    const AlarmInfo* info = alarmManager.getAlarmInfoByID(m_activeAlarm.nId);
    CString title, level, name, desc;
    level.Format(_T("等级: %d"), m_activeAlarm.nSeverityLevel);
    if (info != nullptr && !info->strAlarmText.empty()) {
        name = CString(info->strAlarmText.c_str());
    }
    else {
        name.Format(_T("ID:%d (%s)"), m_activeAlarm.nId, CString(m_activeAlarm.strDeviceName.c_str()));
    }
    if (!m_activeAlarm.strDescription.empty()) {
        desc = CString(m_activeAlarm.strDescription.c_str());
    }
    else if (info != nullptr && !info->strDescription.empty()) {
        desc = CString(info->strDescription.c_str());
    }
    else {
        desc = _T("暂无描述");
    }
    title.Format(_T("设备:%s å•å…ƒ:%s"),
        CString(m_activeAlarm.strDeviceName.c_str()),
        CString(m_activeAlarm.strUnitName.c_str()));
    SetDlgItemText(IDC_LABEL_TITLE, title);
    SetDlgItemText(IDC_LABEL_NAME, name);
    SetDlgItemText(IDC_LABEL_LEVEL, level);
    SetDlgItemText(IDC_LABEL_DESCRIPTION, desc);
    UpdateNavButtons();
    ShowWindow(SW_SHOW);
}
void CAlarmPopupDlg::UpdateNavButtons()
{
    auto* pPrev = GetDlgItem(IDC_BUTTON_PREV);
    auto* pNext = GetDlgItem(IDC_BUTTON_NEXT);
    if (pPrev) pPrev->EnableWindow(m_activeIndex > 0);
    if (pNext) pNext->EnableWindow(m_activeIndex + 1 < static_cast<int>(m_activeAlarms.size()));
}
HBRUSH CAlarmPopupDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
    HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);
    if (nCtlColor == CTLCOLOR_STATIC) {
        pDC->SetBkColor(m_crBkgnd);
        pDC->SetTextColor(RGB(30, 30, 30));
        hbr = m_hbrBkgnd;
    }
    else if (nCtlColor == CTLCOLOR_DLG) {
        hbr = m_hbrBkgnd;
    }
    return hbr;
}
void CAlarmPopupDlg::OnDestroy()
{
    CDialogEx::OnDestroy();
    if (m_hbrBkgnd != nullptr) {
        ::DeleteObject(m_hbrBkgnd);
        m_hbrBkgnd = nullptr;
    }
}
void CAlarmPopupDlg::SetButtonBackgroundColors(bool bMute)
{
    if (!bMute) {
        m_btnSoundOff.SetBkgndColor(BS_NORMAL, BTN_SOUND_OFF_BKGND_NORMAL);
        m_btnSoundOff.SetBkgndColor(BS_HOVER, BTN_SOUND_OFF_BKGND_HOVER);
        m_btnSoundOff.SetBkgndColor(BS_PRESS, BTN_SOUND_OFF_BKGND_PRESS);
        m_btnSoundOff.Invalidate();
    }
    else {
        m_btnSoundOff.SetBkgndColor(BS_NORMAL, BTN_SOUND_ON_BKGND_NORMAL);
        m_btnSoundOff.SetBkgndColor(BS_HOVER, BTN_SOUND_ON_BKGND_HOVER);
        m_btnSoundOff.SetBkgndColor(BS_PRESS, BTN_SOUND_ON_BKGND_PRESS);
        m_btnSoundOff.Invalidate();
    }
}
SourceCode/Bond/Servo/AlarmPopupDlg.h
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,59 @@
#pragma once
#include "afxwin.h"
#include "AlarmManager.h"
#include "Common.h"
#include "ToolUnits.h"
#include "BlButton.h"
// ç®€åŒ–版报警弹窗,对接 AlarmManager çš„æ´»è·ƒå‘Šè­¦
class CAlarmPopupDlg : public CDialogEx
{
    DECLARE_DYNAMIC(CAlarmPopupDlg)
public:
    CAlarmPopupDlg(CWnd* pParent = NULL);
    virtual ~CAlarmPopupDlg();
public:
    void RefreshContent(); // åˆ·æ–°å½“前告警显示
private:
    COLORREF m_crBkgnd;
    HBRUSH m_hbrBkgnd;
    CFont m_fontTitle;
    CFont m_fontLevel;
    CFont m_fontName;
    CFont m_fontDescription;
    CBlButton m_btnClose;
    CBlButton m_btnSoundOff;
    CBlButton m_btnAlarmOff;
// å¯¹è¯æ¡†æ•°æ®
#ifdef AFX_DESIGN_TIME
    enum { IDD = IDD_DIALOG_POPUP_ALARM };
#endif
protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV æ”¯æŒ
    DECLARE_MESSAGE_MAP()
public:
    virtual BOOL OnInitDialog();
    afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
    afx_msg void OnDestroy();
    afx_msg void OnBnClickedClose();
    afx_msg void OnBnClickedAlarmOff();
    afx_msg void OnBnClickedPrev();
    afx_msg void OnBnClickedNext();
private:
    bool m_hasActive;
    AlarmData m_activeAlarm;
    std::vector<AlarmData> m_activeAlarms;
    int m_activeIndex = 0;
    void SetButtonBackgroundColors(bool bMute);
    void ShowNoAlarmControls(bool bShow);
    void ShowAlarmControls(bool bShow);
    void UpdateNavButtons();
    void DisplayActiveAt(int idx);
};
SourceCode/Bond/Servo/CMaster.cpp
@@ -153,132 +153,132 @@
            LOGE("连接CC-Link失败.");
        }
        else {
                LOGI("连接CC-Link成功.");
                BoardVersion version{};
                int nRet = m_cclink.GetBoardVersion(version);
                if (nRet == 0) {
                    LOGD("版本信息:%s.", version.toString().c_str());
                }
                else {
                    LOGE("获取CC-Link版本信息失败.");
                }
                BoardStatus status;
                nRet = m_cclink.GetBoardStatus(status);
                if (nRet == 0) {
                    LOGD("状态:%s.", status.toString().c_str());
                }
                else {
                    LOGE("获取CC-Link状态失败.");
                }
            LOGI("连接CC-Link成功.");
            BoardVersion version{};
            int nRet = m_cclink.GetBoardVersion(version);
            if (nRet == 0) {
                LOGD("版本信息:%s.", version.toString().c_str());
            }
            else {
                LOGE("获取CC-Link版本信息失败.");
            }
            // åˆå§‹åŒ–添加各子设备
            CLoadPort* pPort1, * pPort2, * pPort3, * pPort4;
            CBonder* pBonder1, * pBonder2;
            CEFEM* pEfem;
            CArm* pArm;
            CArmTray* pArmTray1, * pArmTray2;
            CFliper* pFliper;
            CVacuumBake* pVacuumBake;
            CAligner* pAligner;
            CBakeCooling* pBakeCooling;
            CMeasurement* pMeasurement;
            pPort1 = addLoadPort(0);
            pPort2 = addLoadPort(1);
            pPort3 = addLoadPort(2);
            pPort4 = addLoadPort(3);
            pEfem = addEFEM();
            pArm = addArm();
            pArmTray1 = addArmTray(0);
            pArmTray2 = addArmTray(1);
            pFliper = addFliper();
            pVacuumBake = addVacuumBake();
            pAligner = addAligner();
            pBonder1 = addBonder(0);
            pBonder2 = addBonder(1);
            pBakeCooling = addBakeCooling();
            pMeasurement = addMeasurement();
            ASSERT(pEfem);
            ASSERT(pFliper);
            ASSERT(pVacuumBake);
            ASSERT(pAligner);
            ASSERT(pBonder1);
            ASSERT(pBonder2);
            ASSERT(pBakeCooling);
            ASSERT(pMeasurement);
            pEfem->setPort(0, pPort1);
            pEfem->setPort(1, pPort2);
            pEfem->setPort(2, pPort3);
            pEfem->setPort(3, pPort4);
            pEfem->setFliper(pFliper);
            pEfem->setAligner(pAligner);
            pEfem->setArmTray(0, pArmTray1);
            pEfem->setArmTray(1, pArmTray2);
            pPort1->setArm(pArm);
            pPort2->setArm(pArm);
            pPort3->setArm(pArm);
            pPort4->setArm(pArm);
            pArmTray1->setArm(pArm);
            pArmTray2->setArm(pArm);
            pFliper->setArm(pArm);
            pVacuumBake->setArm(pArm);
            pAligner->setArm(pArm);
            pBonder1->setArm(pArm);
            pBonder2->setArm(pArm);
            pBakeCooling->setArm(pArm);
            pMeasurement->setArm(pArm);
            connectEquipments();
            // è¯»ç¼“存数据
            const ULONGLONG boot_cache_begin = GetTickCount64();
            const ULONGLONG boot_read_begin = GetTickCount64();
            readCache();
            LOGI("[BOOT][MASTER] readCache finished, cost=%llu ms", (unsigned long long)(GetTickCount64() - boot_read_begin));
            const ULONGLONG boot_state_begin = GetTickCount64();
            loadState();
            LOGI("[BOOT][MASTER] loadState finished, cost=%llu ms", (unsigned long long)(GetTickCount64() - boot_state_begin));
            if (m_listener.onControlJobChanged) {
                notifyControlJobChanged();
            BoardStatus status;
            nRet = m_cclink.GetBoardStatus(status);
            if (nRet == 0) {
                LOGD("状态:%s.", status.toString().c_str());
            }
            LOGI("[BOOT][MASTER] cache/state loaded, cost=%llu ms (since init %llu ms)",
                (unsigned long long)(GetTickCount64() - boot_cache_begin),
                (unsigned long long)(GetTickCount64() - boot_master_begin));
            // å®šæ—¶å™¨
            g_pMaster = this;
            SetTimer(NULL, 1, 250, (TIMERPROC)MasterTimerProc);
            // è°ƒåº¦çº¿ç¨‹
            m_hDispatchThreadHandle = (HANDLE)_beginthreadex(NULL, 0, SERVO::DispatchThreadFunction, this,
                0, &m_nDispatchThreadAddr);
            // ç›‘控bit线程
            m_hReadBitsThreadHandle = (HANDLE)_beginthreadex(NULL, 0, SERVO::ReadBitsThreadFunction, this,
                0, &m_nReadBitsThreadAddr);
            // æ›²çº¿æœåŠ¡
            CreateDAQBridgeServer();
            LOGI("<Master>初始化完成.");
            LOGI("[BOOT][MASTER] init finished, total cost=%llu ms",
                (unsigned long long)(GetTickCount64() - boot_master_begin));
            return 0;
            else {
                LOGE("获取CC-Link状态失败.");
            }
        }
        // åˆå§‹åŒ–添加各子设备
        CLoadPort* pPort1, * pPort2, * pPort3, * pPort4;
        CBonder* pBonder1, * pBonder2;
        CEFEM* pEfem;
        CArm* pArm;
        CArmTray* pArmTray1, * pArmTray2;
        CFliper* pFliper;
        CVacuumBake* pVacuumBake;
        CAligner* pAligner;
        CBakeCooling* pBakeCooling;
        CMeasurement* pMeasurement;
        pPort1 = addLoadPort(0);
        pPort2 = addLoadPort(1);
        pPort3 = addLoadPort(2);
        pPort4 = addLoadPort(3);
        pEfem = addEFEM();
        pArm = addArm();
        pArmTray1 = addArmTray(0);
        pArmTray2 = addArmTray(1);
        pFliper = addFliper();
        pVacuumBake = addVacuumBake();
        pAligner = addAligner();
        pBonder1 = addBonder(0);
        pBonder2 = addBonder(1);
        pBakeCooling = addBakeCooling();
        pMeasurement = addMeasurement();
        ASSERT(pEfem);
        ASSERT(pFliper);
        ASSERT(pVacuumBake);
        ASSERT(pAligner);
        ASSERT(pBonder1);
        ASSERT(pBonder2);
        ASSERT(pBakeCooling);
        ASSERT(pMeasurement);
        pEfem->setPort(0, pPort1);
        pEfem->setPort(1, pPort2);
        pEfem->setPort(2, pPort3);
        pEfem->setPort(3, pPort4);
        pEfem->setFliper(pFliper);
        pEfem->setAligner(pAligner);
        pEfem->setArmTray(0, pArmTray1);
        pEfem->setArmTray(1, pArmTray2);
        pPort1->setArm(pArm);
        pPort2->setArm(pArm);
        pPort3->setArm(pArm);
        pPort4->setArm(pArm);
        pArmTray1->setArm(pArm);
        pArmTray2->setArm(pArm);
        pFliper->setArm(pArm);
        pVacuumBake->setArm(pArm);
        pAligner->setArm(pArm);
        pBonder1->setArm(pArm);
        pBonder2->setArm(pArm);
        pBakeCooling->setArm(pArm);
        pMeasurement->setArm(pArm);
        connectEquipments();
        // è¯»ç¼“存数据
        const ULONGLONG boot_cache_begin = GetTickCount64();
        const ULONGLONG boot_read_begin = GetTickCount64();
        readCache();
        LOGI("[BOOT][MASTER] readCache finished, cost=%llu ms", (unsigned long long)(GetTickCount64() - boot_read_begin));
        const ULONGLONG boot_state_begin = GetTickCount64();
        loadState();
        LOGI("[BOOT][MASTER] loadState finished, cost=%llu ms", (unsigned long long)(GetTickCount64() - boot_state_begin));
        if (m_listener.onControlJobChanged) {
            notifyControlJobChanged();
        }
        LOGI("[BOOT][MASTER] cache/state loaded, cost=%llu ms (since init %llu ms)",
            (unsigned long long)(GetTickCount64() - boot_cache_begin),
            (unsigned long long)(GetTickCount64() - boot_master_begin));
        // å®šæ—¶å™¨
        g_pMaster = this;
        SetTimer(NULL, 1, 250, (TIMERPROC)MasterTimerProc);
        // è°ƒåº¦çº¿ç¨‹
        m_hDispatchThreadHandle = (HANDLE)_beginthreadex(NULL, 0, SERVO::DispatchThreadFunction, this,
            0, &m_nDispatchThreadAddr);
        // ç›‘控bit线程
        m_hReadBitsThreadHandle = (HANDLE)_beginthreadex(NULL, 0, SERVO::ReadBitsThreadFunction, this,
            0, &m_nReadBitsThreadAddr);
        // æ›²çº¿æœåŠ¡
        CreateDAQBridgeServer();
        LOGI("<Master>初始化完成.");
        LOGI("[BOOT][MASTER] init finished, total cost=%llu ms",
            (unsigned long long)(GetTickCount64() - boot_master_begin));
        return 0;
    }
    int CMaster::term()
    {
@@ -3607,14 +3607,14 @@
            auto& dataTypes = CServoUtilsTool::getEqDataTypes();
            auto& bonderTypes = dataTypes[MID_Bonder1];
            for (size_t i = 0; i < bonderTypes.size(); ++i) {
                m_pCollector->buffersSetChannelName(MID_Bonder1, i + 1, bonderTypes[i].c_str());
                m_pCollector->buffersSetChannelName(MID_Bonder2, i + 1, bonderTypes[i].c_str());
                m_pCollector->buffersSetChannelName(MID_Bonder1, (UINT)i + 1, bonderTypes[(UINT)i].c_str());
                m_pCollector->buffersSetChannelName(MID_Bonder2, (UINT)i + 1, bonderTypes[(UINT)i].c_str());
            }
            auto& vacuumbakeTypes = dataTypes[MID_VacuumBakeA];
            for (size_t i = 0; i < vacuumbakeTypes.size(); ++i) {
                m_pCollector->buffersSetChannelName(MID_VacuumBakeA, i + 1, vacuumbakeTypes[i].c_str());
                m_pCollector->buffersSetChannelName(MID_VacuumBakeB, i + 1, vacuumbakeTypes[i].c_str());
                m_pCollector->buffersSetChannelName(MID_VacuumBakeA, (UINT)i + 1, vacuumbakeTypes[(UINT)i].c_str());
                m_pCollector->buffersSetChannelName(MID_VacuumBakeB, (UINT)i + 1, vacuumbakeTypes[(UINT)i].c_str());
            }
            auto& coolingTypes = dataTypes[MID_BakeCoolingA];
SourceCode/Bond/Servo/CMyStatusbar.cpp
@@ -70,6 +70,11 @@
    SetDlgItemText(IDC_LABEL_RUNTIME, pszText);
}
void CMyStatusbar::setJobText(const char* pszText)
{
    SetDlgItemText(IDC_LABEL_JOBSTATE, pszText);
}
void CMyStatusbar::setCurTaskBtnText(const char* pszText)
{
    SetDlgItemText(IDC_BUTTON_ROBOTTASK, pszText);
@@ -212,4 +217,12 @@
    pItem->GetClientRect(rcItem);
    pItem->MoveWindow(x, (rcClient.Height() - rcItem.Height()) / 2, rcItem.Width(), rcItem.Height());
    x += rcItem.Width();
    x += 8;
    pItem = GetDlgItem(IDC_LABEL_JOBSTATE);
    if (pItem != nullptr) {
        pItem->GetClientRect(rcItem);
        pItem->MoveWindow(x, (rcClient.Height() - rcItem.Height()) / 2, rcItem.Width(), rcItem.Height());
        x += rcItem.Width();
    }
}
SourceCode/Bond/Servo/CMyStatusbar.h
@@ -20,6 +20,7 @@
    void setBackgroundColor(COLORREF color);
    void setForegroundColor(COLORREF cr);
    void setRunTimeText(const char* pszText);
    void setJobText(const char* pszText);
    void setCurTaskBtnText(const char* pszText);
    void setCimBtnText(const char* pszText);
    void setCurTaskBtnColors(COLORREF face, COLORREF frame, COLORREF text);
SourceCode/Bond/Servo/Common.h
@@ -24,6 +24,7 @@
/* è½¯ä»¶ä¾§ ALID */
#define ALID_SOFTWARE_PAUSE_EVENT        9000
#define ALID_SOFTWARE_TEST_ALARM        9099
/* Channel Name */
#define MC_CHANNEL1_NAME        "McChannel1"
@@ -561,3 +562,23 @@
/* PPID名字最大长度 */
#define PPID_NAME_MAX            80
/* è§£é™¤è­¦å‘Š æŒ‰é’® */
#define BTN_ALARM_OFF_FRAME_NORMAL        RGB(88, 88, 88)
#define BTN_ALARM_OFF_FRAME_HOVER        RGB(88, 88, 88)
#define BTN_ALARM_OFF_FRAME_PRESS        RGB(88, 88, 88)
#define BTN_ALARM_OFF_BKGND_NORMAL        RGB(255, 127, 39)
#define BTN_ALARM_OFF_BKGND_HOVER        RGB(255, 157, 59)
#define BTN_ALARM_OFF_BKGND_PRESS        RGB(255, 100, 29)
/* é™éŸ³æŒ‰é’® */
#define BTN_SOUND_OFF_FRAME_NORMAL        RGB(88, 88, 88)
#define BTN_SOUND_OFF_FRAME_HOVER        RGB(88, 88, 88)
#define BTN_SOUND_OFF_FRAME_PRESS        RGB(88, 88, 88)
#define BTN_SOUND_OFF_BKGND_NORMAL        RGB(255, 127, 39)
#define BTN_SOUND_OFF_BKGND_HOVER        RGB(255, 157, 59)
#define BTN_SOUND_OFF_BKGND_PRESS        RGB(255, 100, 29)
#define BTN_SOUND_ON_BKGND_NORMAL        RGB(100, 200, 100)
#define BTN_SOUND_ON_BKGND_HOVER        RGB(150, 250, 150)
#define BTN_SOUND_ON_BKGND_PRESS        RGB(50, 150, 50)
SourceCode/Bond/Servo/Servo.rc
@@ -835,6 +835,26 @@
    PUSHBUTTON      "Online Remote",IDC_BUTTON_ONLINE_REMOTE,138,15,58,27
END
IDD_DIALOG_POPUP_ALARM DIALOGEX 0, 0, 379, 247
STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_SYSMENU
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
    PUSHBUTTON      "<< ä¸Šä¸€æ¡",IDC_BUTTON_PREV,8,224,50,14,NOT WS_VISIBLE
    PUSHBUTTON      "下一条 >>",IDC_BUTTON_NEXT,62,224,50,14,NOT WS_VISIBLE
    LTEXT           "警告",IDC_LABEL_TITLE,27,6,212,17,SS_CENTERIMAGE | NOT WS_VISIBLE
    ICON            "",IDC_ICON_ALARM,29,28,20,20
    ICON            "",IDC_ICON_TITLE,7,8,20,20,NOT WS_VISIBLE
    LTEXT           "等级:--",IDC_LABEL_LEVEL,75,26,161,18
    LTEXT           "警告名称",IDC_LABEL_NAME,120,45,251,24
    PUSHBUTTON      "",IDC_POPUP_BTN_CLOSE,354,0,24,22
    CONTROL         "Custom1",IDC_LINE1,"BYHorizontalLine",WS_TABSTOP,7,78,364,8
    PUSHBUTTON      "静音",IDC_BUTTON_SOUND_OFF,228,216,68,22,WS_DISABLED
    PUSHBUTTON      "异常解除",IDC_BUTTON_ALARM_OFF,304,216,68,22,WS_DISABLED
    CONTROL         "Custom1",IDC_LINE2,"BYHorizontalLine",WS_TABSTOP,7,202,364,8
    LTEXT           "警告描述:",IDC_LABEL_DESCRIPTION,18,98,329,89
    CTEXT           "当前没有警告",IDC_LABEL_NO_ALARM,18,98,329,89,SS_CENTERIMAGE | NOT WS_VISIBLE
END
/////////////////////////////////////////////////////////////////////////////
//
@@ -1288,6 +1308,14 @@
        TOPMARGIN, 7
        BOTTOMMARGIN, 90
    END
    IDD_DIALOG_POPUP_ALARM, DIALOG
    BEGIN
        LEFTMARGIN, 7
        RIGHTMARGIN, 371
        TOPMARGIN, 7
        BOTTOMMARGIN, 238
    END
END
#endif    // APSTUDIO_INVOKED
@@ -1552,6 +1580,11 @@
    0
END
IDD_DIALOG_POPUP_ALARM AFX_DIALOG_LAYOUT
BEGIN
    0
END
/////////////////////////////////////////////////////////////////////////////
//
@@ -1600,6 +1633,8 @@
    END
    POPUP "测试(&T)"
    BEGIN
        MENUITEM "Test1",                       ID_MENU_TEST_ALARM_ON
        MENUITEM "Test2",                       ID_MENU_TEST_ALARM_OFF
        MENUITEM "Message &Set",                ID_MENU_TEST_MESSAGE_SET
        MENUITEM "Message &Clear",              ID_MENU_TEST_MESSAGE_CLEAR
    END
SourceCode/Bond/Servo/Servo.vcxproj
@@ -223,6 +223,7 @@
    <ClInclude Include="..\jsoncpp\include\json\writer.h" />
    <ClInclude Include="..\jsoncpp\lib_json\json_batchallocator.h" />
    <ClInclude Include="AccordionWnd.h" />
    <ClInclude Include="AlarmPopupDlg.h" />
    <ClInclude Include="CBaseDlg.h" />
    <ClInclude Include="CCarrierSlotGrid.h" />
    <ClInclude Include="CCarrierSlotSelector.h" />
@@ -451,6 +452,7 @@
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
    </ClCompile>
    <ClCompile Include="AccordionWnd.cpp" />
    <ClCompile Include="AlarmPopupDlg.cpp" />
    <ClCompile Include="CBaseDlg.cpp" />
    <ClCompile Include="CCarrierSlotGrid.cpp" />
    <ClCompile Include="CCarrierSlotSelector.cpp" />
SourceCode/Bond/Servo/Servo.vcxproj.filters
@@ -244,6 +244,7 @@
    <ClCompile Include="CPageProdOverview.cpp" />
    <ClCompile Include="HmLabel.cpp" />
    <ClCompile Include="CPageCtrlState.cpp" />
    <ClCompile Include="AlarmPopupDlg.cpp" />
  </ItemGroup>
  <ItemGroup>
    <ClInclude Include="AlarmManager.h" />
@@ -530,6 +531,7 @@
    <ClInclude Include="CPageProdOverview.h" />
    <ClInclude Include="HmLabel.h" />
    <ClInclude Include="CPageCtrlState.h" />
    <ClInclude Include="AlarmPopupDlg.h" />
  </ItemGroup>
  <ItemGroup>
    <ResourceCompile Include="Servo.rc" />
SourceCode/Bond/Servo/ServoDlg.cpp
@@ -31,6 +31,7 @@
#include "InputDialog.h"
#include "ClientListDlg.h"
#include "CControlJobManagerDlg.h"
#include "AlarmManager.h"
#include "CUserManager2.h"
#include "CUserManager2Dlg.h"
#include "CUserXLogDlg.h"
@@ -110,6 +111,8 @@
    m_pTopToolbar = nullptr;
    m_pMyStatusbar = nullptr;
    m_pRobotTaskDlg = nullptr;
    m_pTab = nullptr;
    m_pAlarmPopupDlg = nullptr;
}
void CServoDlg::DoDataExchange(CDataExchange* pDX)
@@ -137,6 +140,10 @@
    ON_UPDATE_COMMAND_UI(ID_MENU_FILE_SECSTEST, &CServoDlg::OnUpdateMenuFileSecsTest)
    ON_COMMAND(ID_MENU_PROJECT_VARIABLE_LIST, &CServoDlg::OnMenuProjectVarialbleList)
    ON_UPDATE_COMMAND_UI(ID_MENU_PROJECT_VARIABLE_LIST, &CServoDlg::OnUpdateMenuProjectVarialbleList)
    ON_COMMAND(ID_MENU_TEST_ALARM_ON, &CServoDlg::OnMenuTestAlarmOn)
    ON_UPDATE_COMMAND_UI(ID_MENU_TEST_ALARM_ON, &CServoDlg::OnUpdateMenuTestAlarmOn)
    ON_COMMAND(ID_MENU_TEST_ALARM_OFF, &CServoDlg::OnMenuTestAlarmOff)
    ON_UPDATE_COMMAND_UI(ID_MENU_TEST_ALARM_OFF, &CServoDlg::OnUpdateMenuTestAlarmOff)
    ON_COMMAND(ID_MENU_TEST_MESSAGE_SET, &CServoDlg::OnMenuTestMessageSet)
    ON_UPDATE_COMMAND_UI(ID_MENU_TEST_MESSAGE_SET, &CServoDlg::OnUpdateMenuTestMessageSet)
    ON_COMMAND(ID_MENU_TEST_MESSAGE_CLEAR, &CServoDlg::OnMenuTestMessageClear)
@@ -264,7 +271,7 @@
                CString text;
                if (cj != nullptr) {
                    std::string st = cj->getStateText();
                    text.Format(_T("ControlJob: %S (%S)"), cj->id().c_str(), st.c_str());
                    text.Format(_T("ControlJob: %s (%s)"), cj->id().c_str(), st.c_str());
                    if (cj->state() == SERVO::CJState::Paused) {
                        text += _T(" [Paused]");
                    }
@@ -273,7 +280,7 @@
                    text = _T("ControlJob: None");
                }
                if (m_pMyStatusbar != nullptr) {
                    m_pMyStatusbar->setRunTimeText((LPTSTR)(LPCTSTR)text);
                    m_pMyStatusbar->setJobText((LPTSTR)(LPCTSTR)text);
                    if (cj != nullptr && cj->state() == SERVO::CJState::Paused) {
                        m_pMyStatusbar->setBackgroundColor(STATUSBAR_BK_ALARM);
                        m_pMyStatusbar->setForegroundColor(RGB(0, 0, 0));
@@ -326,6 +333,9 @@
                    //dlg.DoModal();
                }
            }
            else if (RX_CODE_ALARM_SET == code || RX_CODE_ALARM_CLEAR == code) {
                RefreshAlarmBadge();
            }
            if (RX_CODE_PASSIVE_STATUS_CHANGED == code) {
                int state = 0;
@@ -357,6 +367,83 @@
        theApp.m_model.getObservable()->observeOn(pRxWindows->mainThread())
            ->subscribe(m_pObserver);
    }
}
void CServoDlg::RefreshAlarmBadge()
{
    if (m_pTopToolbar == nullptr) return;
    auto activeAlarms = AlarmManager::getInstance().getActiveAlarms();
    // ç»´æŠ¤æœªè¯»åˆ—表:当前活跃且未在已读集合中的报警
    std::unordered_set<int> activeIds;
    m_unreadAlarms.clear();
    for (const auto& alarm : activeAlarms) {
        activeIds.insert(alarm.nId);
        if (m_ackAlarms.find(alarm.nId) == m_ackAlarms.end()) {
            m_unreadAlarms.push_back(alarm);
        }
    }
    // ç§»é™¤å·²è¯»é›†åˆä¸­å·²ä¸å†æ´»è·ƒçš„告警
    for (auto it = m_ackAlarms.begin(); it != m_ackAlarms.end(); ) {
        if (activeIds.find(*it) == activeIds.end()) {
            it = m_ackAlarms.erase(it);
        }
        else {
            ++it;
        }
    }
    int count = static_cast<int>(m_unreadAlarms.size());
    auto* pBtn = dynamic_cast<CBlButton*>(m_pTopToolbar->GetBtn(IDC_BUTTON_ALARM));
    if (pBtn != nullptr) {
        if (count <= 0) {
            pBtn->SetBadgeNumber(0);
            pBtn->ShowDotBadge(FALSE, RGB(255, 0, 0));
            pBtn->StopFlash();
        }
        else if (count <= 9) {
            pBtn->ShowDotBadge(FALSE, RGB(255, 0, 0));
            pBtn->SetBadgeNumber(count);
            if (!pBtn->IsFlash()) pBtn->Flash(600);
        }
        else {
            pBtn->SetBadgeNumber(0);
            pBtn->ShowDotBadge(TRUE, RGB(255, 0, 0));
            if (!pBtn->IsFlash()) pBtn->Flash(600);
        }
        pBtn->EnableWindow(TRUE);
    }
}
void CServoDlg::AckAlarm(int alarmId)
{
    m_ackAlarms.insert(alarmId);
    RefreshAlarmBadge();
}
void CServoDlg::RaiseTestAlarm()
{
    theApp.m_model.raiseSoftAlarm(ALID_SOFTWARE_TEST_ALARM, "Test Alarm (Ctrl+Alt+T)");
}
void CServoDlg::ClearTestAlarm()
{
    theApp.m_model.clearSoftAlarm(ALID_SOFTWARE_TEST_ALARM);
}
void CServoDlg::MarkAlarmsRead()
{
    auto* pBtn = dynamic_cast<CBlButton*>(m_pTopToolbar ? m_pTopToolbar->GetBtn(IDC_BUTTON_ALARM) : nullptr);
    for (const auto& alarm : m_unreadAlarms) {
        m_ackAlarms.insert(alarm.nId);
    }
    m_unreadAlarms.clear();
    if (pBtn != nullptr) {
        pBtn->SetBadgeNumber(0);
        pBtn->ShowDotBadge(FALSE, RGB(255, 0, 0));
        pBtn->StopFlash();
    }
}
@@ -466,7 +553,7 @@
        (unsigned long long)(GetTickCount64() - boot_pages_begin),
        (unsigned long long)(GetTickCount64() - boot_ui_begin));
    CHmTab* m_pTab = CHmTab::Hook(GetDlgItem(IDC_TAB1)->m_hWnd);
    m_pTab = CHmTab::Hook(GetDlgItem(IDC_TAB1)->m_hWnd);
    m_pTab->SetPaddingLeft(20);
    m_pTab->SetItemMarginLeft(18);
    m_pTab->AddItem("状态图", FALSE);
@@ -505,6 +592,7 @@
    m_pMyStatusbar = new CMyStatusbar();
    m_pMyStatusbar->Create(IDD_STATUSBAR, this);
    m_pMyStatusbar->ShowWindow(SW_SHOW);
    m_pMyStatusbar->setJobText("ControlJob: None");
    LOGI("[BOOT][UI] statusbar created, elapsed=%llu ms", (unsigned long long)(GetTickCount64() - boot_ui_begin));
@@ -531,13 +619,20 @@
        }
        LOGI("[BOOT][UI] before master.init, elapsed=%llu ms", (unsigned long long)(GetTickCount64() - boot_ui_begin));
    // ç›¸å½“于延时调用master的初始化
    const ULONGLONG boot_master_begin = GetTickCount64();
    theApp.m_model.m_master.init();
    LOGI("[BOOT][UI] m_master.init finished, cost=%llu ms (since OnInit start %llu ms)",
        (unsigned long long)(GetTickCount64() - boot_master_begin),
        (unsigned long long)(GetTickCount64() - boot_ui_begin));
    theApp.m_model.loadPortParams();
        // ç›¸å½“于延时调用master的初始化
        const ULONGLONG boot_master_begin = GetTickCount64();
        theApp.m_model.m_master.init();
        LOGI("[BOOT][UI] m_master.init finished, cost=%llu ms (since OnInit start %llu ms)",
            (unsigned long long)(GetTickCount64() - boot_master_begin),
            (unsigned long long)(GetTickCount64() - boot_ui_begin));
        theApp.m_model.loadPortParams();
    }
    // è¿˜åŽŸçŠ¶æ€æ è¿è¡Œæ—¶é—´æ˜¾ç¤ºï¼ˆé¿å…ä¸€ç›´åœç•™åœ¨â€œæ­£åœ¨åŠ è½½åŽ†å²ç¼“å­˜...”)
    if (m_pMyStatusbar != nullptr) {
        CString strText;
        GetRuntimeFormatText(strText, "");
        m_pMyStatusbar->setRunTimeText((LPTSTR)(LPCTSTR)strText);
    }
@@ -547,6 +642,8 @@
    // æ›´æ–°ç™»å½•状态
    UpdateLoginStatus();
    // åˆå§‹åŒ–报警角标
    RefreshAlarmBadge();
    //SystemLogManager::getInstance.log(SystemLogManager::LogType::Info, _T("BondEq启动..."));
    //SystemLogManager::getInstance.
@@ -736,6 +833,26 @@
    pCmdUI->Enable(TRUE);
}
void CServoDlg::OnMenuTestAlarmOn()
{
    RaiseTestAlarm();
}
void CServoDlg::OnUpdateMenuTestAlarmOn(CCmdUI* pCmdUI)
{
    pCmdUI->Enable(TRUE);
}
void CServoDlg::OnMenuTestAlarmOff()
{
    ClearTestAlarm();
}
void CServoDlg::OnUpdateMenuTestAlarmOff(CCmdUI* pCmdUI)
{
    pCmdUI->Enable(TRUE);
}
void CServoDlg::OnMenuTestMessageSet()
{
    SERVO::CEquipment* pEquipment = m_pPanelMaster->GetActiveEquipment();
@@ -848,6 +965,12 @@
        m_pMyStatusbar->DestroyWindow();
        delete m_pMyStatusbar;
        m_pMyStatusbar = nullptr;
    }
    if (m_pAlarmPopupDlg != nullptr) {
        m_pAlarmPopupDlg->DestroyWindow();
        delete m_pAlarmPopupDlg;
        m_pAlarmPopupDlg = nullptr;
    }
    if (m_pRobotTaskDlg != nullptr) {
@@ -1256,6 +1379,16 @@
        dlg.SetEFEM(pEFEM);
        dlg.DoModal();
    }
    else if (id == IDC_BUTTON_ALARM) {
        if (m_pAlarmPopupDlg == nullptr) {
            m_pAlarmPopupDlg = new CAlarmPopupDlg();
            m_pAlarmPopupDlg->Create(IDD_DIALOG_POPUP_ALARM, this);
            m_pAlarmPopupDlg->CenterWindow();
        }
        m_pAlarmPopupDlg->RefreshContent();
        m_pAlarmPopupDlg->ShowWindow(SW_SHOW);
        MarkAlarmsRead();
    }
    else if (id == IDC_BUTTON_SETTINGS) {
        SERVO::CEquipment* pEq = theApp.m_model.m_master.getEquipment(EQ_ID_EFEM);
        ((SERVO::CEFEM*)pEq)->printDebugRobotState();
@@ -1367,6 +1500,11 @@
    return 0;
}
BOOL CServoDlg::PreTranslateMessage(MSG* pMsg)
{
    return CDialogEx::PreTranslateMessage(pMsg);
}
CString& CServoDlg::GetRuntimeFormatText(CString& strText, const char* pszSuffix)
{
    ULONGLONG ullRunTime = (ULONGLONG)(theApp.m_model.getMaster().getRunTime() * 0.001);
SourceCode/Bond/Servo/ServoDlg.h
@@ -3,6 +3,8 @@
//
#pragma once
#include <vector>
#include <unordered_set>
#include "BlButton.h"
#include "PageLog.h"
#include "PageAlarm.h"
@@ -15,12 +17,15 @@
#include "CPanelProduction.h"
#include "CPageGraph1.h"
#include "CPageGraph2.h"
#include "HmTab.h"
#include "TopToolbar.h"
#include "CMyStatusbar.h"
#include "CRobotTaskDlg.h"
#include "CPageGlassList.h"
#include "CPageVarialbles.h"
#include "CPageDataVarialbles.h"
#include "AlarmPopupDlg.h"
#include "AlarmManager.h"
// CServoDlg å¯¹è¯æ¡†
@@ -33,9 +38,14 @@
public:
    void ShowTerminalText(const char* pszText, unsigned int duration = -1);
    void AckAlarm(int alarmId);
private:
    void InitRxWindows();
    void RefreshAlarmBadge();
    void MarkAlarmsRead();
    void RaiseTestAlarm();
    void ClearTestAlarm();
    void Resize();
    void SetLeftPanelType(int type, bool resize = true);
    void ShowChildPage(int index);
@@ -53,6 +63,10 @@
    CPageAlarm*     m_pPageAlarm;
    CPageLog*     m_pPageLog;
    CPageTransferLog* m_pPageTransferLog;
    CAlarmPopupDlg* m_pAlarmPopupDlg;
    CHmTab* m_pTab;
    std::vector<AlarmData> m_unreadAlarms;
    std::unordered_set<int> m_ackAlarms;
// å¯¹è¯æ¡†æ•°æ®
#ifdef AFX_DESIGN_TIME
@@ -100,6 +114,10 @@
    afx_msg void OnUpdateMenuFileExit(CCmdUI* pCmdUI);
    afx_msg void OnMenuProjectVarialbleList();
    afx_msg void OnUpdateMenuProjectVarialbleList(CCmdUI* pCmdUI);
    afx_msg void OnMenuTestAlarmOn();
    afx_msg void OnUpdateMenuTestAlarmOn(CCmdUI* pCmdUI);
    afx_msg void OnMenuTestAlarmOff();
    afx_msg void OnUpdateMenuTestAlarmOff(CCmdUI* pCmdUI);
    afx_msg void OnMenuTestMessageSet();
    afx_msg void OnUpdateMenuTestMessageSet(CCmdUI* pCmdUI);
    afx_msg void OnMenuTestMessageClear();
@@ -116,4 +134,5 @@
    afx_msg void OnTabSelChanged(NMHDR* nmhdr, LRESULT* result);
    LRESULT OnToolbarBtnClicked(WPARAM wParam, LPARAM lParam);
    LRESULT OnStatusbarBtnClicked(WPARAM wParam, LPARAM lParam);
    virtual BOOL PreTranslateMessage(MSG* pMsg);
};
SourceCode/Bond/Servo/resource.h
@@ -49,7 +49,6 @@
#define IDD_DIALOG_RECIPE_DEVICE_BIND   167
#define IDD_PAGE_VARIABLE               168
#define IDD_PAGE_REPORT                 169
#define IDD_PAGE_                       170
#define IDD_PAGE_COLLECTION_EVENT       171
#define IDD_DIALOG_CONTROL_JOB          172
#define IDD_PAGE_GLASS_LIST             173
@@ -68,6 +67,7 @@
#define IDD_DIALOG_EVENT_EDIT           188
#define IDD_PANEL_PRODUCTION            189
#define IDD_PROD_CTRL_STATE             190
#define IDD_DIALOG_POPUP_ALARM          191
#define IDC_SERVO_GRAPH1                1001
#define IDC_BUTTON_LOG                  1002
#define IDC_EDIT_LOG                    1003
@@ -332,6 +332,24 @@
#define IDC_BUTTON_OFFLINE              1252
#define IDC_BUTTON_ONLINE_LOCAL         1253
#define IDC_BUTTON_ONLINE_REMOTE        1254
#define IDC_POPUP_TITLE                 1255
#define IDC_POPUP_ALARM_ID              1256
#define IDC_POPUP_ALARM_LEVEL           1257
#define IDC_POPUP_ALARM_DESC            1258
#define IDC_POPUP_BTN_CLOSE             1259
#define IDC_POPUP_BTN_CLEAR             1260
#define IDC_BUTTON_PREV                 1261
#define IDC_BUTTON_NEXT                 1262
#define IDC_ICON_ALARM                  1263
#define IDC_ICON_TITLE                  1264
#define IDC_LABEL_LEVEL                 1265
#define IDC_LABEL_NAME                  1267
#define IDC_BUTTON_SOUND_OFF            1268
#define IDC_BUTTON_ALARM_OFF            1269
#define IDC_LINE2                       1270
#define IDC_LABEL_DESCRIPTION           1271
#define IDC_LABEL_NO_ALARM                1272
#define IDC_LABEL_JOBSTATE              1273
#define ID_MENU_HELP_ABOUT              32771
#define ID_MENU_FILE_EXIT               32772
#define ID_MENU_FILE_SECSTEST           32773
@@ -364,14 +382,16 @@
#define ID_MENU_TOOLS_CLIENT_LIST       32801
#define ID_MENU_WND_TEST_PANEL          32802
#define ID_MENU_WND_PRO_PANEL           32803
#define ID_MENU_TEST_ALARM_ON           32804
#define ID_MENU_TEST_ALARM_OFF          32805
// Next default values for new objects
// 
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE        191
#define _APS_NEXT_COMMAND_VALUE         32804
#define _APS_NEXT_CONTROL_VALUE         1255
#define _APS_NEXT_RESOURCE_VALUE        192
#define _APS_NEXT_COMMAND_VALUE         32806
#define _APS_NEXT_CONTROL_VALUE         1274
#define _APS_NEXT_SYMED_VALUE           101
#endif
#endif