#pragma once #include #include #include #include #include #include #include #include struct AlarmRecord { int64_t id; std::string timestamp; // ISO format: "2025-01-15 14:30:22" int channel; std::string fence_name; std::string class_name; float confidence; std::string screenshot_path; // relative path like "data/screenshots/1234567890.jpg" }; // 姿态报警记录 struct PoseAlarmRecord { int64_t id; std::string timestamp; int channel; std::string action; // 跌倒/倒地/举手呼救/异常蹲坐 float score; std::string screenshot_path; }; struct RelayAction { int64_t id; std::string timestamp; std::string source; // fence=围栏报警 / di=输入联动 / manual=手动 std::string detail; // 触发说明 std::string channels; // 动作的输出通道, 逗号分隔, 如 "y01,y03" }; class AlarmHistory { public: AlarmHistory(); ~AlarmHistory(); bool init(const std::string& db_path = "data/alarms.db", const std::string& screenshot_dir = "data/screenshots"); // 非阻塞: 仅入队, 由后台线程写盘入库 void record(int channel, const std::string& fence_name, const std::string& class_name, float confidence, const cv::Mat& frame); std::vector getAlarms(int limit = 100, int offset = 0, int channel = -1, const std::string& start = "", const std::string& end = ""); int getAlarmCount(int channel = -1, const std::string& start = "", const std::string& end = ""); bool deleteAlarm(int64_t id); void clearAll(); std::string getScreenshotPath(int64_t id); // ---- 继电器动作历史(与报警共享保留周期) ---- void recordAction(const std::string& source, const std::string& detail, const std::string& channels); std::vector getActions(int limit = 200); void clearActions(); // ---- 姿态报警历史 ---- void recordPoseAlarm(int channel, const std::string& action, float score, const cv::Mat& frame); std::vector getPoseAlarms(int limit = 100, int offset = 0, int channel = -1, const std::string& action = "", const std::string& start = "", const std::string& end = ""); int getPoseAlarmCount(int channel = -1, const std::string& action = "", const std::string& start = "", const std::string& end = ""); bool deletePoseAlarm(int64_t id); void clearPoseAlarms(); void cleanup(int keep_days = 30); private: void createTable(); void insertRow(const std::string& timestamp, int channel, const std::string& fence_name, const std::string& class_name, float confidence, const std::string& rel_path); void insertActionRow(const std::string& timestamp, const std::string& source, const std::string& detail, const std::string& channels); void insertPoseRow(const std::string& timestamp, int channel, const std::string& action, float score, const std::string& rel_path); void workerLoop(); struct Pending { std::string timestamp; int channel; std::string fence_name; std::string class_name; float confidence; std::string rel_path; cv::Mat frame; int kind = 0; // 0=围栏报警 1=姿态报警 std::string action; // 姿态动作 float score = 0.0f; // 姿态得分 }; std::mutex mtx_; std::string db_path_; std::string screenshot_dir_; void* db_ = nullptr; // sqlite3* std::queue pending_; std::condition_variable pending_cv_; std::thread worker_; std::atomic worker_run_{false}; };