From bfffbdb8a6d7a3b4805c45583f8bf2101e7b2ad4 Mon Sep 17 00:00:00 2001
From: chenluhua1980 <Chenluhua@qq.com>
Date: 星期三, 21 一月 2026 11:34:38 +0800
Subject: [PATCH] 1.警告信息对话框显示;

---
 SourceCode/Bond/Servo/Servo.vcxproj         |    2 
 SourceCode/Bond/Servo/AlarmManager.cpp      |  420 ++++++++++------
 SourceCode/Bond/Servo/Servo.vcxproj.filters |    2 
 SourceCode/Bond/Servo/resource.h            |   23 
 SourceCode/Bond/Servo/AlarmManager.h        |  205 ++++----
 SourceCode/Bond/Servo/Servo.rc              |   33 +
 SourceCode/Bond/Servo/CMaster.cpp           |  252 +++++-----
 SourceCode/Bond/Servo/AlarmPopupDlg.cpp     |  278 +++++++++++
 SourceCode/Bond/Servo/ServoDlg.cpp          |  130 +++++
 SourceCode/Bond/Servo/AlarmPopupDlg.h       |   53 ++
 SourceCode/Bond/Servo/Common.h              |   21 
 SourceCode/Bond/Servo/ServoDlg.h            |   14 
 12 files changed, 1,034 insertions(+), 399 deletions(-)

diff --git a/SourceCode/Bond/Servo/AlarmManager.cpp b/SourceCode/Bond/Servo/AlarmManager.cpp
index 56d6cbb..8cd9acb 100644
--- a/SourceCode/Bond/Servo/AlarmManager.cpp
+++ b/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鍜屽崟鍏僆D缁勫悎浣滀负涓婚敭
     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是主键
+    // 鍒涘缓鎶ヨ琛紝鎶ヨ璁板綍鐨刟larm_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;
 }
 
-// 筛选报警数据
+// 鑾峰彇褰撳墠鏈粨鏉熺殑鎶ヨ锛坋nd_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鍜屽崟鍏僆D鑾峰彇鍗曞厓鍚嶇О
 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 瑙i櫎鎶ヨ锛堟洿鏂扮粨鏉熸椂闂达級
 bool AlarmManager::clearAlarmByEventId(int alarmEventId, const std::string& endTime) {
     if (!m_pDB) {
         return false;
@@ -745,7 +827,7 @@
     return result;
 }
 
-// 通过多个属性查找并解除报警(更新结束时间)
+// 閫氳繃澶氫釜灞炴�ф煡鎵惧苟瑙i櫎鎶ヨ锛堟洿鏂扮粨鏉熸椂闂达級
 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;
         }
     }
 
diff --git a/SourceCode/Bond/Servo/AlarmManager.h b/SourceCode/Bond/Servo/AlarmManager.h
index d98fce9..1cd55a9 100644
--- a/SourceCode/Bond/Servo/AlarmManager.h
+++ b/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锛屽け璐ヨ繑鍥瀎alse
      */
     bool initAlarmTable();
 
 	/**
-	 * 销毁报警表
+	 * 閿�姣佹姤璀﹁〃
 	 */
     void termAlarmTable();
 
 	/**
-	 * 销毁报警表
-	 * @return 成功返回true,失败返回false
+	 * 閿�姣佹姤璀﹁〃
+	 * @return 鎴愬姛杩斿洖true锛屽け璐ヨ繑鍥瀎alse
 	 */
     bool destroyAlarmTable();
 
     /**
-    * 插入模拟数据
+    * 鎻掑叆妯℃嫙鏁版嵁
     */
     void insertMockData();
 
     /**
-     * 添加报警
-     * @param alarmData 报警数据的结构体
-     * @param alarmEventId 最近插入的 alarm_event_id
-     * @return 成功返回true,失败返回false
+     * 娣诲姞鎶ヨ
+     * @param alarmData 鎶ヨ鏁版嵁鐨勭粨鏋勪綋
+     * @param alarmEventId 鏈�杩戞彃鍏ョ殑 alarm_event_id
+     * @return 鎴愬姛杩斿洖true锛屽け璐ヨ繑鍥瀎alse
      */
     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锛屽け璐ヨ繑鍥瀎alse
 	 */
     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鍜屽崟鍏僆D鑾峰彇鍗曞厓鍚嶇О
+    * @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瑙i櫎鎶ヨ锛堟洿鏂扮粨鏉熸椂闂达級
+    * @param alarmEventId 浜嬩欢ID
+    * @param endTime 缁撴潫鏃堕棿
+    * @return 鎴愬姛杩斿洖true锛屽け璐ヨ繑鍥瀎alse
     */
     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
+    * 閫氳繃澶氫釜灞炴�ф煡鎵惧苟瑙i櫎鎶ヨ锛堟洿鏂扮粨鏉熸椂闂达級
+    * @param nId 鎶ヨID
+    * @param nSeverityLevel 鎶ヨ绛夌骇
+    * @param nDeviceId 璁惧ID
+    * @param nUnitId 鍗曞厓ID
+    * @param strDescription 鎻忚堪
+    * @param endTime 缁撴潫鏃堕棿
+    * @return 鎴愬姛杩斿洖true锛屽け璐ヨ繑鍥瀎alse
     */
     bool clearAlarmByAttributes(int nId, int nDeviceId, int nUnitId, const std::string& endTime);
 
 	/**
-	 * 读取报警文件
-	 * @param filename 文件名
-	 * @return 成功返回true,失败返回false
+	 * 璇诲彇鎶ヨ鏂囦欢
+	 * @param filename 鏂囦欢鍚�
+	 * @return 鎴愬姛杩斿洖true锛屽け璐ヨ繑鍥瀎alse
 	 */
     bool readAlarmFile(const std::string& filename);
 
     /**
-     * 保存报警文件
-     * @param filename 文件名
-     * @return 成功返回true,失败返回false
+     * 淇濆瓨鎶ヨ鏂囦欢
+     * @param filename 鏂囦欢鍚�
+     * @return 鎴愬姛杩斿洖true锛屽け璐ヨ繑鍥瀎alse
      */
     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;
 
diff --git a/SourceCode/Bond/Servo/AlarmPopupDlg.cpp b/SourceCode/Bond/Servo/AlarmPopupDlg.cpp
new file mode 100644
index 0000000..cc2a48d
--- /dev/null
+++ b/SourceCode/Bond/Servo/AlarmPopupDlg.cpp
@@ -0,0 +1,278 @@
+锘�#include "stdafx.h"
+#include "Servo.h"
+#include "AlarmPopupDlg.h"
+#include "afxdialogex.h"
+#include "Log.h"
+#include "Common.h"
+#include "HorizontalLine.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_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);
+
+
+	// 瑙i櫎璀﹀憡鎸夐挳
+	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, IDC_POPUP_BTN_CLOSE };
+	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()
+{
+	auto actives = AlarmManager::getInstance().getActiveAlarms();
+	if (!actives.empty()) {
+		m_activeAlarm = actives.front();
+		m_hasActive = true;
+
+		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);
+		ShowAlarmControls(true);
+		ShowNoAlarmControls(false);
+		ShowWindow(SW_SHOW);
+	}
+	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();
+}
+
+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();
+	}
+}
diff --git a/SourceCode/Bond/Servo/AlarmPopupDlg.h b/SourceCode/Bond/Servo/AlarmPopupDlg.h
new file mode 100644
index 0000000..5ca49a0
--- /dev/null
+++ b/SourceCode/Bond/Servo/AlarmPopupDlg.h
@@ -0,0 +1,53 @@
+锘�#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();
+
+private:
+	bool m_hasActive;
+	AlarmData m_activeAlarm;
+	void SetButtonBackgroundColors(bool bMute);
+	void ShowNoAlarmControls(bool bShow);
+	void ShowAlarmControls(bool bShow);
+};
diff --git a/SourceCode/Bond/Servo/CMaster.cpp b/SourceCode/Bond/Servo/CMaster.cpp
index 80ce726..df536fb 100644
--- a/SourceCode/Bond/Servo/CMaster.cpp
+++ b/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];
diff --git a/SourceCode/Bond/Servo/Common.h b/SourceCode/Bond/Servo/Common.h
index b207bfd..41b56e7 100644
--- a/SourceCode/Bond/Servo/Common.h
+++ b/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)
+
diff --git a/SourceCode/Bond/Servo/Servo.rc b/SourceCode/Bond/Servo/Servo.rc
index 1c07a27..98fa6fd 100644
--- a/SourceCode/Bond/Servo/Servo.rc
+++ b/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,67,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,118,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
+    LTEXT           "当前没有警告", IDC_LABEL_NO_ALARM, 18, 98, 329, 89, 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
+
 
 /////////////////////////////////////////////////////////////////////////////
 //
diff --git a/SourceCode/Bond/Servo/Servo.vcxproj b/SourceCode/Bond/Servo/Servo.vcxproj
index 3f876a1..f1eff4a 100644
--- a/SourceCode/Bond/Servo/Servo.vcxproj
+++ b/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" />
diff --git a/SourceCode/Bond/Servo/Servo.vcxproj.filters b/SourceCode/Bond/Servo/Servo.vcxproj.filters
index dd0ee29..09bb6e1 100644
--- a/SourceCode/Bond/Servo/Servo.vcxproj.filters
+++ b/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" />
diff --git a/SourceCode/Bond/Servo/ServoDlg.cpp b/SourceCode/Bond/Servo/ServoDlg.cpp
index 7c6641f..f8a74b8 100644
--- a/SourceCode/Bond/Servo/ServoDlg.cpp
+++ b/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)
@@ -264,7 +267,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]");
 					}
@@ -326,6 +329,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 +363,77 @@
 
 		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::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 +543,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);
@@ -531,13 +608,13 @@
 		}
 		LOGI("[BOOT][UI] before master.init, elapsed=%llu ms", (unsigned long long)(GetTickCount64() - boot_ui_begin));
 
-	// 鐩稿綋浜庡欢鏃惰皟鐢╩aster鐨勫垵濮嬪寲
-	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();
+		// 鐩稿綋浜庡欢鏃惰皟鐢╩aster鐨勫垵濮嬪寲
+		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();
 	}
 
 
@@ -547,6 +624,8 @@
 
 	// 鏇存柊鐧诲綍鐘舵��
 	UpdateLoginStatus();
+	// 鍒濆鍖栨姤璀﹁鏍�
+	RefreshAlarmBadge();
 	//SystemLogManager::getInstance.log(SystemLogManager::LogType::Info, _T("BondEq鍚姩..."));
 	//SystemLogManager::getInstance.
 
@@ -848,6 +927,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 +1341,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 +1462,23 @@
 	return 0;
 }
 
+BOOL CServoDlg::PreTranslateMessage(MSG* pMsg)
+{
+	if (pMsg->message == WM_KEYDOWN) {
+		const bool ctrl = (GetKeyState(VK_CONTROL) & 0x8000) != 0;
+		const bool alt = (GetKeyState(VK_MENU) & 0x8000) != 0;
+		if (ctrl && alt && pMsg->wParam == 'T') {
+			RaiseTestAlarm();
+			return TRUE;
+		}
+		if (ctrl && alt && pMsg->wParam == 'Y') {
+			ClearTestAlarm();
+			return TRUE;
+		}
+	}
+	return CDialogEx::PreTranslateMessage(pMsg);
+}
+
 CString& CServoDlg::GetRuntimeFormatText(CString& strText, const char* pszSuffix)
 {
 	ULONGLONG ullRunTime = (ULONGLONG)(theApp.m_model.getMaster().getRunTime() * 0.001);
diff --git a/SourceCode/Bond/Servo/ServoDlg.h b/SourceCode/Bond/Servo/ServoDlg.h
index df4b01d..ec0cba7 100644
--- a/SourceCode/Bond/Servo/ServoDlg.h
+++ b/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 瀵硅瘽妗�
@@ -36,6 +41,10 @@
 
 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 +62,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
@@ -116,4 +129,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);
 };
diff --git a/SourceCode/Bond/Servo/resource.h b/SourceCode/Bond/Servo/resource.h
index 52ee640..5eacbaf 100644
--- a/SourceCode/Bond/Servo/resource.h
+++ b/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,23 @@
 #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 ID_MENU_HELP_ABOUT              32771
 #define ID_MENU_FILE_EXIT               32772
 #define ID_MENU_FILE_SECSTEST           32773
@@ -369,9 +386,9 @@
 // 
 #ifdef APSTUDIO_INVOKED
 #ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE        191
+#define _APS_NEXT_RESOURCE_VALUE        192
 #define _APS_NEXT_COMMAND_VALUE         32804
-#define _APS_NEXT_CONTROL_VALUE         1255
+#define _APS_NEXT_CONTROL_VALUE         1273
 #define _APS_NEXT_SYMED_VALUE           101
 #endif
 #endif

--
Gitblit v1.9.3