| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120 |
- #pragma once
- #include <string>
- #include <vector>
- #include <queue>
- #include <mutex>
- #include <thread>
- #include <atomic>
- #include <condition_variable>
- #include <opencv2/opencv.hpp>
- 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<AlarmRecord> 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<RelayAction> getActions(int limit = 200);
- void clearActions();
- // ---- 姿态报警历史 ----
- void recordPoseAlarm(int channel, const std::string& action, float score,
- const cv::Mat& frame);
- std::vector<PoseAlarmRecord> 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> pending_;
- std::condition_variable pending_cv_;
- std::thread worker_;
- std::atomic<bool> worker_run_{false};
- };
|