#pragma once #include #include #include #include #include // 历史活动记录: // 每条格式:[YYYY-MM-DD HH:MM:SS] [窗口标题] <时长> // 倒序存储(最新在前)。后台线程每 1 秒采样一次前台窗口。 #define ACTIVITY_MIN_DWELL_SEC 5 // 一闪而过阈值(秒):驻留低于此值不记录 #define ACTIVITY_IDLE_BREAK_SEC 300 // 空闲打断阈值(秒):空闲超过此值才结账当前窗口 // 注意:与心跳“活动窗口”列的 6s 判定不同,这里要远大于 MIN_DWELL, // 否则“停在一个窗口上看 10 秒”会被 6s 空闲判定过早结账/漏记 #define ACTIVITY_HISTORY_MAX 500 // 内存保留的最大记录条数 class ActivityHistory { public: static ActivityHistory& Instance(); // 启动常驻采样线程(幂等,重复调用无副作用) void Start(); // 停止采样线程 void Stop(); // 返回全部历史记录(最新在前,多行文本,每行一条) std::string Dump() const; private: ActivityHistory() = default; ~ActivityHistory() { Stop(); } ActivityHistory(const ActivityHistory&) = delete; ActivityHistory& operator=(const ActivityHistory&) = delete; void Loop(); // 拼一条记录字符串 static std::string FormatRecord(const std::string& startTime, const std::string& title, int dwellSec); // 时长格式化:Ns / Nm / NmNs / NhNm static std::string FormatDuration(int sec); // 当前时间戳 "YYYY-MM-DD HH:MM:SS" static std::string NowStr(); mutable std::mutex m_mutex; std::deque m_records; // 已完成记录,最新在前 std::string m_curTitle; // 当前进行中的窗口标题 std::string m_curStartTime; // 当前窗口的起始时间 int m_curDwellSec = 0; // 当前窗口已连续活跃秒数 std::atomic m_running{ false }; std::atomic m_started{ false }; std::thread m_thread; };