| | |
| | | #include "stdafx.h" |
| | | #include "stdafx.h" |
| | | #include "Common.h" |
| | | #include "AlarmManager.h" |
| | | #include "Log.h" |
| | | #include <sstream> |
| | | #include <fstream> |
| | | #include <iostream> |
| | |
| | | #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; |
| | |
| | | } |
| | | } |
| | | |
| | | // 初始化报警表 |
| | | // 初始化报警表 |
| | | bool AlarmManager::initAlarmTable() { |
| | | char path[MAX_PATH]; |
| | | GetModuleFileName(NULL, path, MAX_PATH); |
| | |
| | | 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, |
| | |
| | | return false; |
| | | } |
| | | |
| | | // 创建单元表,设备ID和单元ID组合作为主键 |
| | | // 创建单元表,设备ID和单元ID组合作为主键 |
| | | const std::string createUnitsTableQuery = R"( |
| | | CREATE TABLE IF NOT EXISTS units ( |
| | | device_id TEXT NOT NULL, |
| | |
| | | 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, |
| | |
| | | FOREIGN KEY (unit_id) REFERENCES units(unit_id) |
| | | ) |
| | | )"; |
| | | return m_pDB->executeQuery(createAlarmsTableQuery); |
| | | if (!m_pDB->executeQuery(createAlarmsTableQuery)) { |
| | | return false; |
| | | } |
| | | |
| | | // 设备列表 (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}, |
| | | {EQ_ID_LOADPORT4, EQ_NAME_LOADPORT4}, |
| | | {EQ_ID_ARM_TRAY1, EQ_NAME_ARM_TRAY1}, |
| | | {EQ_ID_ARM_TRAY2, EQ_NAME_ARM_TRAY2}, |
| | | {EQ_ID_ALIGNER, EQ_NAME_ALIGNER}, |
| | | {EQ_ID_FLIPER, EQ_NAME_FLIPER}, |
| | | {EQ_ID_VACUUMBAKE, EQ_NAME_VACUUMBAKE}, |
| | | {EQ_ID_Bonder1, EQ_NAME_BONDER1}, |
| | | {EQ_ID_Bonder2, EQ_NAME_BONDER2}, |
| | | {EQ_ID_BAKE_COOLING, EQ_NAME_BAKE_COOLING}, |
| | | {EQ_ID_MEASUREMENT, EQ_NAME_MEASUREMENT}, |
| | | {EQ_ID_EFEM, EQ_NAME_EFEM}, |
| | | {EQ_ID_ARM, EQ_NAME_ARM}, |
| | | {EQ_ID_OPERATOR_REMOVE, EQ_NAME_OPERATOR_REMOVE} |
| | | }; |
| | | |
| | | // 插入 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 << "')"; |
| | | if (!m_pDB->executeQuery(ossDev.str())) { |
| | | return false; |
| | | } |
| | | |
| | | // 插入默认单元 (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 << "')"; |
| | | if (!m_pDB->executeQuery(ossUnit.str())) { |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | 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."); |
| | |
| | | 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; |
| | |
| | | } |
| | | } |
| | | |
| | | // 插入单元数据 |
| | | // 插入单元数据 |
| | | for (int i = 1; i <= 3; ++i) { |
| | | for (int j = 0; j <= 3; ++j) { |
| | | int unitId = j; |
| | |
| | | |
| | | 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())) { |
| | |
| | | } |
| | | |
| | | /* |
| | | // 初始化随机数生成器 |
| | | // 初始化随机数生成器 |
| | | std::random_device rd; |
| | | std::mt19937 gen(rd()); |
| | | std::uniform_int_distribution<> deviceDis(1, 3); |
| | |
| | | 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)); |
| | |
| | | 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) " |
| | |
| | | */ |
| | | } |
| | | |
| | | // 添加报警信息 |
| | | // 添加报警信息 |
| | | 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; |
| | |
| | | } |
| | | } |
| | | |
| | | // 构建插入查询并使用 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; |
| | | } |
| | |
| | | #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 |
| | |
| | | |
| | | 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); |
| | | } |
| | |
| | | return alarms; |
| | | } |
| | | |
| | | // 根据报警ID查询报警 |
| | | // 根据报警ID查询报警 |
| | | std::vector<AlarmData> AlarmManager::getAlarmsById(const std::string& id) { |
| | | if (!m_pDB) { |
| | | return {}; |
| | |
| | | |
| | | 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); |
| | | } |
| | |
| | | return alarms; |
| | | } |
| | | |
| | | // 根据描述查询报警 |
| | | // 根据描述查询报警 |
| | | std::vector<AlarmData> AlarmManager::getAlarmsByDescription(const std::string& description) { |
| | | if (!m_pDB) { |
| | | return {}; |
| | |
| | | |
| | | 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); |
| | | } |
| | |
| | | return alarms; |
| | | } |
| | | |
| | | // 根据时间范围查询报警 |
| | | // 根据时间范围查询报警 |
| | | std::vector<AlarmData> AlarmManager::getAlarmsByTimeRange(const std::string& startTime, const std::string& endTime) { |
| | | if (!m_pDB) { |
| | | return {}; |
| | |
| | | |
| | | 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); |
| | | } |
| | |
| | | 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 {}; |
| | |
| | | |
| | | 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); |
| | | } |
| | |
| | | return alarms; |
| | | } |
| | | |
| | | // 分页查询报警数据 |
| | | // 分页查询报警数据 |
| | | std::vector<AlarmData> AlarmManager::getAlarms(int startPosition, int count) { |
| | | if (!m_pDB) { |
| | | return {}; |
| | |
| | | |
| | | 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); |
| | | } |
| | |
| | | return alarms; |
| | | } |
| | | |
| | | // 筛选报警数据 |
| | | std::vector<AlarmData> AlarmManager::getFilteredAlarms( |
| | | const std::string& id, |
| | | const std::string& severityLevel, |
| | | const std::string& deviceName, |
| | | const std::string& unitName, |
| | | const std::string& description, |
| | | const std::string& startTime, |
| | | const std::string& endTime, |
| | | int pageNumber, |
| | | int pageSize) { |
| | | // 获取当前未结束的报警(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 {}; |
| | | } |
| | |
| | | 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 |
| | | JOIN units u ON a.device_id = u.device_id AND a.unit_id = u.unit_id |
| | | WHERE 1=1)"; |
| | | |
| | | // 传入的过滤条件 |
| | | if (!id.empty()) { |
| | | query << " AND a.id = '" << id << "'"; |
| | | // 统一关键字模糊查询 |
| | | if (!keyword.empty()) { |
| | | query << " AND (" |
| | | << "a.id LIKE '%" << keyword << "%' OR " |
| | | << "a.severity_level LIKE '%" << keyword << "%' OR " |
| | | << "d.device_name LIKE '%" << keyword << "%' OR " |
| | | << "u.unit_name LIKE '%" << keyword << "%' OR " |
| | | << "a.description LIKE '%" << keyword << "%')"; |
| | | } |
| | | if (!severityLevel.empty()) { |
| | | query << " AND a.severity_level = '" << severityLevel << "'"; |
| | | } |
| | | if (!deviceName.empty()) { |
| | | query << " AND d.device_name LIKE '%" << deviceName << "%'"; |
| | | } |
| | | if (!unitName.empty()) { |
| | | query << " AND u.unit_name LIKE '%" << unitName << "%'"; |
| | | } |
| | | if (!description.empty()) { |
| | | query << " AND a.description LIKE '%" << description << "%'"; |
| | | } |
| | | |
| | | // 时间条件 |
| | | if (!startTime.empty()) { |
| | | query << " AND a.start_time >= '" << startTime << "'"; |
| | | } |
| | |
| | | query << " AND a.end_time <= '" << endTime << "'"; |
| | | } |
| | | |
| | | // 分页设置 |
| | | int offset = (pageNumber - 1) * pageSize; |
| | | query << " ORDER BY a.start_time DESC LIMIT " << pageSize << " OFFSET " << offset; |
| | | // 分页设置 |
| | | 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); |
| | | } |
| | |
| | | return alarms; |
| | | } |
| | | |
| | | // 获取符合条件的报警总数 |
| | | int AlarmManager::getTotalAlarmCount( |
| | | const std::string& id, |
| | | const std::string& severityLevel, |
| | | const std::string& deviceName, |
| | | const std::string& unitName, |
| | | const std::string& description, |
| | | const std::string& startTime, |
| | | const std::string& endTime) { |
| | | |
| | | // 获取符合条件的报警总数 |
| | | int AlarmManager::getTotalAlarmCount(const std::string& keyword, const std::string& startTime, const std::string& endTime) { |
| | | if (!m_pDB) { |
| | | return 0; |
| | | } |
| | | |
| | | std::ostringstream query; |
| | | query << "SELECT COUNT(*) 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 1=1"; |
| | | query << R"( |
| | | SELECT COUNT(*) |
| | | 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 1=1)"; |
| | | |
| | | // 添加过滤条件 |
| | | if (!id.empty()) { |
| | | query << " AND a.id = '" << id << "'"; |
| | | // 统一关键字模糊查询 |
| | | if (!keyword.empty()) { |
| | | query << " AND (" |
| | | << "a.id LIKE '%" << keyword << "%' OR " |
| | | << "a.severity_level LIKE '%" << keyword << "%' OR " |
| | | << "d.device_name LIKE '%" << keyword << "%' OR " |
| | | << "u.unit_name LIKE '%" << keyword << "%' OR " |
| | | << "a.description LIKE '%" << keyword << "%')"; |
| | | } |
| | | if (!severityLevel.empty()) { |
| | | query << " AND a.severity_level = '" << severityLevel << "'"; |
| | | } |
| | | if (!deviceName.empty()) { |
| | | query << " AND d.device_name LIKE '%" << deviceName << "%'"; |
| | | } |
| | | if (!unitName.empty()) { |
| | | query << " AND u.unit_name LIKE '%" << unitName << "%'"; |
| | | } |
| | | if (!description.empty()) { |
| | | query << " AND a.description LIKE '%" << description << "%'"; |
| | | } |
| | | |
| | | // 时间条件 |
| | | if (!startTime.empty()) { |
| | | query << " AND a.start_time >= '" << startTime << "'"; |
| | | } |
| | |
| | | return (!results.empty() && !results[0].empty()) ? std::stoi(results[0][0]) : 0; |
| | | } |
| | | |
| | | // 更新报警的结束时间 |
| | | // 更新报警的结束时间 |
| | | bool AlarmManager::updateAlarmEndTime( |
| | | const std::string& id, |
| | | const std::string& severityLevel, |
| | |
| | | return false; |
| | | } |
| | | |
| | | // 更新报警结束时间 |
| | | // 更新报警结束时间 |
| | | std::ostringstream updateQuery; |
| | | updateQuery << "UPDATE alarms SET end_time = '" << newEndTime << "'" |
| | | << " WHERE id = '" << id << "'" |
| | |
| | | return m_pDB->executeQuery(updateQuery.str()); |
| | | } |
| | | |
| | | // 清理旧报警数据 |
| | | // 清理旧报警数据 |
| | | void AlarmManager::cleanOldAlarms(int daysToKeep, const std::string& deviceId, const std::string& unitId) { |
| | | if (!m_pDB) { |
| | | return; |
| | |
| | | m_pDB->executeQuery(query.str()); |
| | | } |
| | | |
| | | // 通过设备ID获取设备名称 |
| | | // 通过设备ID获取设备名称 |
| | | std::string AlarmManager::getDeviceNameById(int deviceId) { |
| | | if (!m_pDB) { |
| | | return ""; |
| | |
| | | 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 ""; |
| | |
| | | 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); |
| | |
| | | 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; |
| | |
| | | return result; |
| | | } |
| | | |
| | | // 通过多个属性查找并解除报警(更新结束时间) |
| | | // 通过多个属性查找并解除报警(更新结束时间) |
| | | bool AlarmManager::clearAlarmByAttributes(int nId, int nDeviceId, int nUnitId, const std::string& endTime) { |
| | | if (!m_pDB) { |
| | | return false; |
| | |
| | | |
| | | 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; |
| | |
| | | } |
| | | } |
| | | |
| | | // 如果没找到匹配的记录,则直接返回 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()); |
| | |
| | | return result; |
| | | } |
| | | |
| | | // 读取报警文件 |
| | | // 读取报警文件 |
| | | bool AlarmManager::readAlarmFile(const std::string& filename) { |
| | | std::ifstream file(filename); |
| | | std::string line; |
| | | bool first_line = true; |
| | | |
| | | std::ifstream file(filename, std::ios::binary); |
| | | if (!file.is_open()) { |
| | | std::cerr << "Error opening file!" << std::endl; |
| | | return false; |
| | | } |
| | | |
| | | while (std::getline(file, line)) { |
| | | auto getline_cross = [](std::ifstream& f, std::string& out) -> bool { |
| | | out.clear(); |
| | | char ch; |
| | | while (f.get(ch)) { |
| | | if (ch == '\r') { |
| | | // 处理 \r\n 或 单独 \r |
| | | if (f.peek() == '\n') f.get(); |
| | | break; |
| | | } |
| | | else if (ch == '\n') { |
| | | break; |
| | | } |
| | | out.push_back(ch); |
| | | } |
| | | return !out.empty() || !f.eof(); |
| | | }; |
| | | |
| | | std::string line; |
| | | bool first_line = true; |
| | | |
| | | while (getline_cross(file, line)) { |
| | | if (first_line) { |
| | | first_line = false; |
| | | continue; |
| | |
| | | std::string cell; |
| | | AlarmInfo alarm; |
| | | |
| | | std::getline(ss, cell, ','); |
| | | std::getline(ss, alarm.strUnitID, ','); |
| | | std::getline(ss, alarm.strUnitNo, ','); |
| | | std::getline(ss, cell, ','); |
| | | alarm.nAlarmLevel = std::stoi(cell); |
| | | std::getline(ss, cell, ','); |
| | | alarm.nAlarmCode = std::stoi(cell); |
| | | std::getline(ss, cell, ','); |
| | | alarm.nAlarmID = std::stoi(cell); |
| | | std::getline(ss, alarm.strAlarmText, ','); |
| | | std::getline(ss, alarm.strDescription, ','); |
| | | try { |
| | | if (!std::getline(ss, cell, ',')) throw std::runtime_error("Missing field: No"); |
| | | if (!std::getline(ss, alarm.strUnitID, ',')) throw std::runtime_error("Missing field: UnitID"); |
| | | if (!std::getline(ss, alarm.strUnitNo, ',')) throw std::runtime_error("Missing field: UnitNo"); |
| | | if (!std::getline(ss, cell, ',')) throw std::runtime_error("Missing field: AlarmLevel"); |
| | | alarm.nAlarmLevel = std::stoi(cell); |
| | | if (!std::getline(ss, cell, ',')) throw std::runtime_error("Missing field: AlarmCode"); |
| | | alarm.nAlarmCode = std::stoi(cell); |
| | | if (!std::getline(ss, cell, ',')) throw std::runtime_error("Missing field: AlarmID"); |
| | | alarm.nAlarmID = std::stoi(cell); |
| | | if (!std::getline(ss, alarm.strAlarmText, ',')) throw std::runtime_error("Missing field: AlarmText"); |
| | | if (!std::getline(ss, alarm.strDescription, ',')) throw std::runtime_error("Missing field: Description"); |
| | | |
| | | if (m_mapAlarm.find(alarm.nAlarmID) == m_mapAlarm.end()) { |
| | | m_mapAlarm[alarm.nAlarmID] = alarm; |
| | | if (m_mapAlarm.find(alarm.nAlarmID) == m_mapAlarm.end()) { |
| | | m_mapAlarm[alarm.nAlarmID] = alarm; |
| | | } |
| | | else { |
| | | std::cerr << "Duplicate AlarmID: " << alarm.nAlarmID << std::endl; |
| | | } |
| | | } |
| | | else { |
| | | std::cerr << "Duplicate AlarmID: " << alarm.nAlarmID << std::endl; |
| | | catch (const std::exception& e) { |
| | | std::cerr << "Error parsing line: " << line << " - " << e.what() << std::endl; |
| | | continue; |
| | | } |
| | | } |
| | | |
| | |
| | | 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; |
| | |
| | | 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; |
| | | |
| | |
| | | alarms.push_back(it->second); |
| | | } |
| | | else { |
| | | std::cerr << "未找到 AlarmID: " << alarmID << std::endl; |
| | | std::cerr << "未找到 AlarmID: " << alarmID << std::endl; |
| | | } |
| | | } |
| | | |