瀏覽代碼

V0.4.6
1、完成了大部分的在岗离岗报警功能

Apple 1 月之前
父節點
當前提交
d22a4e3941

+ 31 - 0
SQL/SecurePlay.sqlbook

@@ -102,12 +102,16 @@ INSERT INTO "tAlarmInfo" ("AlarmId","StartTime","CreateTime","EndTime","bBox","P
 VALUES(:AlarmID, :StartTime, :CreateTime, :EndTime, :bBox, :PicUrl, :AppID, :ActionID, :ActionDes, :CamerID, :RoomID, :chnID, :Stat, :FaceIDList, :FaceNameList, :OnWork);
 
 INSERT INTO "tAlarmInfo" ("AlarmId","StartTime","CreateTime","EndTime","bBox","PicUrl","Appid","ActionId","ActionDes","CamerId","RoomId","chnID","State","FaceIdList","FaceNameList","OnWork")
+OUTPUT INSERTED."PKID"
 VALUES(@AlarmID, @StartTime, @CreateTime, @EndTime, @bBox, @PicUrl, @AppID, @ActionID, @ActionDes, @CamerID, @RoomID, @chnID, @Stat, @FaceIDList, @FaceNameList, @OnWork);
 
 
+
 #插入报警信息示例
 INSERT INTO "tAlarmInfo" ("AlarmId","StartTime","CreateTime","EndTime","bBox","PicUrl","Appid","ActionId","ActionDes","CamerId","RoomId","chnID","State","FaceIdList","FaceNameList","OnWork")
 VALUES('0', '2024-10-08 14:00:00', '2024-10-08 14:00:00','','112,112,112,112','PicURL', '1', '2', '报警测试', '3', '4', '5', '6', 'FaceIDList','FaceNameList', '1');
+SELECT @@IDENTITY AS PKID;
+SELECT SCOPE_IDENTITY() AS PKID;
 
 #删除一行
 DELETE FROM "tAlarmInfo"
@@ -121,6 +125,24 @@ WHERE ("chnID" = :ChannelID AND "RoomId" = :RoomID AND "CamerId" = :CamerID AND
 UPDATE "tAlarmInfo"
 SET "EndTime" = @EndTime
 WHERE ("chnID" = @ChannelID AND "RoomId" = @RoomID AND "CamerId" = @CamerID AND "ActionId" = @ActionID);
+
+#更新结束时间,通过PKID
+UPDATE "tAlarmInfo"
+SET "EndTime" = :EndTime
+WHERE "PKID" = :pkid;
+
+
+#更新人员列表,通过PKDI
+UPDATE "tAlarmInfo"
+SET "FaceIdList" = @faceIDList, "FaceNameList" = @faceNameList, "ActionDes" = @actionDes, "CreateTime" = GetDate()
+WHERE "PKID" = @pkid;
+
+#更新人员列表,通过PKID
+UPDATE "tAlarmInfo"
+SET "FaceIdList" = :faceIDList, "FaceNameList" = :faceNameList, "ActionDes" = :actionDes, "CreateTime" = GetDate()
+WHERE "PKID" = :pkid;
+
+
 -- SQLBook: Code
 #报警规则表
 SELECT *
@@ -130,6 +152,15 @@ FROM "tRuleInfo";
 #时段详细信息表,从这里获取到开启了哪些检测功能
 SELECT *
 FROM "tPeriod";
+
+#获取功能信息,同时包含所在的频率信息
+SELECT "tPeriod".*, "tChannel"."ChnName"
+FROM "tPeriod"
+LEFT JOIN "tChannel"
+ON "tPeriod"."ChnId" = "tChannel"."chnId";
+
+SELECT *
+FROM "tChannel";
 -- SQLBook: Code
 #人员在岗信息表
 SELECT *

+ 11 - 11
SecurePlayAuxServer/Application/FuncBase.cpp

@@ -3,12 +3,12 @@
 #include "GlobalVariable.h"
 #include "GlobalConfig.h"
 #include "FromRedis.h"
-#include "ToEQMDataBase.h"
+#include "FromWebAPI.h"
 
 FuncBase::FuncBase()
 {
     m_fromRedis = std::make_shared<FromRedis>();
-    m_toEQMDataBase = std::make_shared<ToEQMDataBase>();
+    m_fromWebAPI = std::make_shared<FromWebAPI>();
 }
 
 FuncBase::~FuncBase()
@@ -30,36 +30,36 @@ void FuncBase::thread_task()
         }
     }
     /* 线程功能信息 */
-    if(m_funcAct.appFunction == AppFunction::APP_NONE)
+    if(m_funcThreadInfo.appFunction == AppFunction::APP_NONE)
     {
         SPDLOG_LOGGER_ERROR(m_logger, "未设置线程功能信息");
         return;
     }
-    SPDLOG_LOGGER_INFO(m_logger, "开启 {} 功能线程, ChannelID:{}",m_funcAct.strFunctionName, m_funcAct.ChannelID);
+    SPDLOG_LOGGER_INFO(m_logger, "开启 {} 功能线程, ChannelID:{}",m_funcThreadInfo.strFunctionName, m_funcThreadInfo.ChannelID);
     /* 设置线程运行状态 */
     m_bRunning = true;
     /* 执行线程功能,会一直阻塞,直到退出 */
     task();
     /* 设置线程退出的状态,设置成 RUN_STATE_EXITCOMPLET ,就会被管理线程回收 */
-    GThreadInfo.setThreadState(m_funcAct, RunTimeState::RUN_STATE_EXITCOMPLET);
-    SPDLOG_LOGGER_INFO(m_logger, "{} 功能线程退出,Channel:{}", m_funcAct.strFunctionName, m_funcAct.ChannelID);
+    GThreadInfo.setThreadState(m_funcThreadInfo, RunTimeState::RUN_STATE_EXITCOMPLET);
+    SPDLOG_LOGGER_INFO(m_logger, "{} 功能线程退出,Channel:{}", m_funcThreadInfo.strFunctionName, m_funcThreadInfo.ChannelID);
     m_bRunning = false;
 }
 
 /* 设置功能信息 */
-void FuncBase::setFuncActionInfo(FuncActionInfo* pFuncAct)
+void FuncBase::setFuncThreadInfo(FuncThreadInfo* pFuncAct)
 {
-    m_funcAct = *pFuncAct;
+    m_funcThreadInfo = *pFuncAct;
 }
-void FuncBase::setFuncActionInfo(FuncActionInfo& FuncAct)
+void FuncBase::setFuncThreadInfo(FuncThreadInfo& FuncAct)
 {
-    m_funcAct = FuncAct;
+    m_funcThreadInfo = FuncAct;
 }
 
 /* 获取该实例的功能 */
 AppFunction FuncBase::getApp()
 {
-    return m_funcAct.appFunction;
+    return m_funcThreadInfo.appFunction;
 }
 
 /* 获取线程运行状态 */

+ 9 - 6
SecurePlayAuxServer/Application/FuncBase.h

@@ -3,11 +3,14 @@
 
 #include <memory>
 #include "GlobalVariable.h"
+#include "GlobalFuncThread.h"
+
+
 #include "spdlog/spdlog.h"
 
 class FromRedis;
-class ToEQMDataBase;
-struct FuncActionInfo;
+class FromWebAPI;
+struct FuncThreadInfo;
 
 /**
  * @brief 功能基础类,包含读取Redis数据和写入EQM数据库的功能
@@ -24,8 +27,8 @@ public:
     void thread_task();
 
     /* 设置功能信息 */
-    void setFuncActionInfo(FuncActionInfo* pFuncAct);
-    void setFuncActionInfo(FuncActionInfo& FuncAct);
+    void setFuncThreadInfo(FuncThreadInfo* pFuncAct);
+    void setFuncThreadInfo(FuncThreadInfo& FuncAct);
     /* 获取该实例的功能 */
     AppFunction getApp();
     /* 获取线程运行状态 */
@@ -42,9 +45,9 @@ protected:
     /* 读取Redis的实例 */
     std::shared_ptr<FromRedis> m_fromRedis = nullptr;
     /* 写入EQM数据库的实例 */
-    std::shared_ptr<ToEQMDataBase> m_toEQMDataBase = nullptr;
+    std::shared_ptr<FromWebAPI> m_fromWebAPI = nullptr;
     /* 线程信息 */
-    FuncActionInfo m_funcAct;
+    FuncThreadInfo m_funcThreadInfo;
 
     std::atomic_bool m_bRunning = false;     /* 线程运行状态 */
 };

+ 41 - 38
SecurePlayAuxServer/Application/FuncIllegalInvasion.cpp

@@ -2,7 +2,7 @@
 #include "GlobalVariable.h"
 #include "GlobalConfig.h"
 #include "FromRedis.h"
-#include "ToEQMDataBase.h"
+#include "FromWebAPI.h"
 #include "UniversalFunc.h"
 
 
@@ -180,9 +180,9 @@ FuncIllegalInvasion::~FuncIllegalInvasion()
 }
 
 /* 是否报警 */
-bool FuncIllegalInvasion::isAlarm(const std::vector<PersonInfo>& vecPersion)
+bool FuncIllegalInvasion::isAlarm(const std::list<PersonInfo>& listPersion)
 {
-    for(const auto& it : vecPersion)
+    for(const auto& it : listPersion)
     {
         if(it.PersonID == "-1")
         {
@@ -201,14 +201,14 @@ void FuncIllegalInvasion::task()
     while (GThreadInfo.getRunning())
     {   
         /* 更新线程信息 */
-        GThreadInfo.updateFuncInfo(m_funcAct);
-        if(m_funcAct.RunState == RunTimeState::RUN_STATE_STOP)
+        GThreadInfo.updateFuncInfo(m_funcThreadInfo);
+        if(m_funcThreadInfo.RunState == RunTimeState::RUN_STATE_STOP)
         {
             break;
         }
 
         /* 判断是否在检测时间段内 */
-        if(!isInDetectTime(m_funcAct.StartTime, m_funcAct.EndTime))
+        if(!isInDetectTime(m_funcThreadInfo.StartTime, m_funcThreadInfo.EndTime))
         {
             std::this_thread::sleep_for(std::chrono::milliseconds(GConfig.ThreadSleepMS));
             continue;
@@ -224,37 +224,40 @@ void FuncIllegalInvasion::task()
 
         /* 读取Redis数据 */
         m_pListAlarm->clear();
-        for(const auto& RoomInfo : m_funcAct.listRoomCamActInfo)
+        for(const auto& RoomInfo : m_funcThreadInfo.listRoomCamActInfo)
         {
             for(const auto& it : RoomInfo.mapCameraAction)
             {
-                std::string strKey = std::to_string(it.first) + ":" + it.second;
-                std::string strRetValue;
-                if(!m_fromRedis->getRedisString(strKey, strRetValue))
+                for(const auto& act : it.second)
                 {
-                    SPDLOG_LOGGER_ERROR(m_logger, "读取Redis数据失败, Key:{}", strKey);
-                    std::this_thread::sleep_for(std::chrono::milliseconds(100));
-                    continue;
-                }
-                /* 解析数据 */
-                AlarmInfo alarmInfo;
-                // parseRedisData(strRetValue, alarmInfo);
-                parseRedisBaseData(strRetValue, alarmInfo);
-                parseRedisBBoxesData(strRetValue, alarmInfo);
-                /* 判断事件的时效性,超过多少秒不更新就可能是超脑挂了 */
-                if(isEventTimeVaild(alarmInfo.EventTime))
-                {
-                    SPDLOG_LOGGER_WARN(m_logger, "Redis Key:{} 数据长时间没有更新,EventTime:{}",strKey, alarmInfo.EventTime);
-                    std::this_thread::sleep_for(std::chrono::milliseconds(100));
-                    continue;
+                    std::string strKey = std::to_string(it.first) + ":" + act;
+                    std::string strRetValue;
+                    if(!m_fromRedis->getRedisString(strKey, strRetValue))
+                    {
+                        SPDLOG_LOGGER_ERROR(m_logger, "读取Redis数据失败, Key:{}", strKey);
+                        std::this_thread::sleep_for(std::chrono::milliseconds(100));
+                        continue;
+                    }
+                    /* 解析数据 */
+                    AlarmInfo alarmInfo;
+                    // parseRedisData(strRetValue, alarmInfo);
+                    parseRedisBaseData(strRetValue, alarmInfo);
+                    parseRedisBBoxesData(strRetValue, alarmInfo);
+                    /* 判断事件的时效性,超过多少秒不更新就可能是超脑挂了 */
+                    if(isEventTimeVaild(alarmInfo.EventTime))
+                    {
+                        SPDLOG_LOGGER_WARN(m_logger, "Redis Key:{} 数据长时间没有更新,EventTime:{}",strKey, alarmInfo.EventTime);
+                        std::this_thread::sleep_for(std::chrono::milliseconds(100));
+                        continue;
+                    }
+                    m_pListAlarm->push_back(alarmInfo);
                 }
-                m_pListAlarm->push_back(alarmInfo);
             }
         }
 
         /* 找出房间的个数,按照房间进行判断 */
         ListRoomIll listRoomIll;
-        for(auto& it : m_funcAct.listRoomCamActInfo)
+        for(auto& it : m_funcThreadInfo.listRoomCamActInfo)
         {
             listRoomIll.addRoom(it.RoomID, it.RoomType);
         }
@@ -271,16 +274,16 @@ void FuncIllegalInvasion::task()
                 /* 统计这个房间内《人脸算法》检测到的最大人员数 */
                 if(alarm.ActionID == strFaceActionID)
                 {
-                    if(alarm.vecPersonInfo.size() > room.numMaxFace)
+                    if(alarm.listPersonInfo.size() > room.numMaxFace)
                     {
-                        room.numMaxFace = alarm.vecPersonInfo.size();
+                        room.numMaxFace = alarm.listPersonInfo.size();
                         room.strBoxList = alarm.listBbox;
-                        room.vecPersonInfo = alarm.vecPersonInfo;
+                        room.listPersonInfo = alarm.listPersonInfo;
                     }
                 }
 
                 /* 判断有没有非法入侵人员 */
-                if(isAlarm(alarm.vecPersonInfo))
+                if(isAlarm(alarm.listPersonInfo))
                 {
                     room.isAlarm = true;
                     room.strMessage = "人员非法入侵(未知人员)";
@@ -312,9 +315,9 @@ void FuncIllegalInvasion::task()
                 if(alarm.ActionID == strCountActionID)
                 {
                     /* 统计这个房间内《人员计数算法》检测到的最大人员数 */
-                    if(alarm.vecPersonInfo.size() > room.numMaxPerson)
+                    if(alarm.listPersonInfo.size() > room.numMaxPerson)
                     {
-                        room.numMaxPerson = alarm.vecPersonInfo.size();
+                        room.numMaxPerson = alarm.listPersonInfo.size();
                         room.strBoxList = alarm.listBbox;
                         if(!alarm.ImageInfo.empty())
                         {
@@ -342,7 +345,7 @@ void FuncIllegalInvasion::task()
                 if(pIll == nullptr)
                 {
                     IllegalInvasionInfo info;
-                    info.ChannelID = m_funcAct.ChannelID;
+                    info.ChannelID = m_funcThreadInfo.ChannelID;
                     info.CameraID = room.CameraID;
                     info.RoomID = room.RoomID;
                     info.RoomType = room.RoomType;
@@ -363,7 +366,7 @@ void FuncIllegalInvasion::task()
                     {
                         /* 超过非法入侵的时间,写入数据库 */
                         AlarmInfo ai;
-                        ai.ChannelID = m_funcAct.ChannelID;
+                        ai.ChannelID = m_funcThreadInfo.ChannelID;
                         ai.RoomID = pIll->RoomID;
                         ai.ActionID = g_actionList.ActPersonNumber;
                         ai.ActionDes = pIll->strActionDec;
@@ -371,9 +374,9 @@ void FuncIllegalInvasion::task()
                         ai.StartTime = pIll->FirstTime.toString("yyyy-MM-dd hh:mm:ss").toStdString();
                         ai.EndTime = currTime.toString("yyyy-MM-dd hh:mm:ss").toStdString();
                         ai.EventTime = pIll->FirstTime.toString("yyyy-MM-dd hh:mm:ss").toStdString();
-                        ai.vecPersonInfo = room.vecPersonInfo;
+                        ai.listPersonInfo = room.listPersonInfo;
                         ai.listBbox = room.strBoxList;
-                        bool insertRet  = m_toEQMDataBase->insertAlarmInfo(ai);
+                        bool insertRet  = m_fromWebAPI->insertAlarmInfo(ai);
                         if(insertRet)
                         {
                             std::string actionName = g_actionList.getActionName(ai.ActionID);
@@ -383,7 +386,7 @@ void FuncIllegalInvasion::task()
                     }
                     else {
                         SPDLOG_LOGGER_WARN(m_logger, "× 取消新增报警信息,因为没有图片,频道[{}],房间[{}],摄像头[{}],{},{},有{}个区域,有{}个人脸",
-                            pIll->ChannelID, pIll->RoomID, pIll->CameraID, pIll->strActionDec, pIll->strImageInfo, room.strBoxList.size(), room.vecPersonInfo.size());
+                            pIll->ChannelID, pIll->RoomID, pIll->CameraID, pIll->strActionDec, pIll->strImageInfo, room.strBoxList.size(), room.listPersonInfo.size());
                     }
                     /* 删除这个非法入侵信息 */
                     m_pListIllInfo->deleteIllInfo(*pIll);

+ 2 - 2
SecurePlayAuxServer/Application/FuncIllegalInvasion.h

@@ -36,7 +36,7 @@ struct RoomIllegalInvasionInfo
     std::list<std::string> strBoxList;      /* box */
     std::string strMessage;                 /* 报警信息字符串 */
     std::string strImage;                   /* 报警图片 */
-    std::vector<PersonInfo> vecPersonInfo;  /* 人员信息 */
+    std::list<PersonInfo> listPersonInfo;  /* 人员信息 */
 
     RoomIllegalInvasionInfo() = default;
     RoomIllegalInvasionInfo(const RoomIllegalInvasionInfo& o);
@@ -113,7 +113,7 @@ public:
 
 private:
     /* 是否报警 */
-    bool isAlarm(const std::vector<PersonInfo>& vecPersion);
+    bool isAlarm(const std::list<PersonInfo>& listPersion);
 
 protected:
     /* 线程功能 */

+ 447 - 62
SecurePlayAuxServer/Application/FuncOnAndOffJob.cpp

@@ -4,7 +4,7 @@
 #include "UniversalFunc.h"
 
 #include "FromRedis.h"
-#include "ToEQMDataBase.h"
+#include "FromWebAPI.h"
 
 
 
@@ -39,18 +39,40 @@ DecCondition& DecCondition::operator=(const DecCondition& other)
 }
 
 
+RoomOnWorkInfo::RoomOnWorkInfo()
+{
+    bOnWork = false;
+    PKID = 0;
+    ChannelID = 0;
+    RoomID = 0;
+    CameraID = 0;
+    RoomType = 0;
+    strRoomName = "";
+    StartTime = QDateTime::fromString("1970-01-01 00:00:00", "yyyy-MM-dd hh:mm:ss");
+    EndTime = QDateTime::fromString("1970-01-01 00:00:00", "yyyy-MM-dd hh:mm:ss");
+    strImagePath = "";
+    listLeaveTime.clear();
+    listPersonInfo.clear();
+
+}
+
+
 RoomOnWorkInfo& RoomOnWorkInfo::operator=(const RoomOnWorkInfo& other)
 {
     if (this != &other)
     {
         bOnWork = other.bOnWork;
+        PKID = other.PKID;
+        ChannelID = other.ChannelID;
         RoomID = other.RoomID;
         CameraID = other.CameraID;
         RoomType = other.RoomType;
+        strRoomName = other.strRoomName;
         StartTime = other.StartTime;
         EndTime = other.EndTime;
         strImagePath = other.strImagePath;
         listPersonInfo = other.listPersonInfo;
+        listLeaveTime = other.listLeaveTime;
     }
     return *this;
 }
@@ -58,92 +80,200 @@ RoomOnWorkInfo& RoomOnWorkInfo::operator=(const RoomOnWorkInfo& other)
 RoomOnWorkInfo::RoomOnWorkInfo(const RoomOnWorkInfo& other)
 {
     bOnWork = other.bOnWork;
+    PKID = other.PKID;
+    ChannelID = other.ChannelID;
     RoomID = other.RoomID;
     CameraID = other.CameraID;
     RoomType = other.RoomType;
+    strRoomName = other.strRoomName;
     StartTime = other.StartTime;
     EndTime = other.EndTime;
     strImagePath = other.strImagePath;
     listPersonInfo = other.listPersonInfo;
+    listLeaveTime = other.listLeaveTime;
+    
 }
 
+void RoomOnWorkInfo::clear()
+{
+    bOnWork = false;
+    PKID = 0;
+    ChannelID = 0;
+    RoomID = 0;
+    CameraID = 0;
+    RoomType = 0;
+    strRoomName = "";
+    StartTime = QDateTime::fromString("1970-01-01 00:00:00", "yyyy-MM-dd hh:mm:ss");
+    EndTime = QDateTime::fromString("1970-01-01 00:00:00", "yyyy-MM-dd hh:mm:ss");
+    strImagePath = "";
+    listLeaveTime.clear();
+    listPersonInfo.clear();
+}
 
 
 
 
+/* 添加人员信息,进行查重 */
+void RoomOnWorkInfo::addPersonInfo(const std::list<PersonInfo>& vecInfo)
+{
+    for(auto& it : vecInfo)
+    {
+        /* 查重 */
+        bool bFind = false;
+        for(auto& it0 : listPersonInfo)
+        {
+            if(it0.PersonID == it.PersonID && it0.PersonName == it.PersonName)
+            {
+                bFind = true;
+                break;
+            }
+        }
+        if(!bFind)
+        {
+            listPersonInfo.push_back(it);
+        }
+    }
+}
 
-FuncOnAndOffJob::FuncOnAndOffJob()
+/* 更新在岗时间 */
+void RoomOnWorkInfo::updateOnWorkTime(const QDateTime& time)
 {
-    m_pListAlarm = new ListAlarmInfo();
-    m_logger = spdlog::get("SPAServer");
-    if(m_logger == nullptr)
+    for(auto& it : listPersonInfo)
     {
-        SPDLOG_ERROR("FuncOnAndOffJob logger is nullptr");
-        return;
+        it.lastOnWork = time;
     }
+}
 
+/* 获取人脸ID字符串 */
+std::string RoomOnWorkInfo::getFaceIDListString()
+{
+    std::string strFaceList;
+    for(const auto& it : listPersonInfo)
+    {
+        strFaceList += it.PersonID + ";" ;
+    }
+    /* 去掉最后的“;” */
+    strFaceList = strFaceList.substr(0, strFaceList.size() - 1);
+
+    return strFaceList;
 }
 
-FuncOnAndOffJob::~FuncOnAndOffJob()
+/* 获取人脸字符串 */
+std::string RoomOnWorkInfo::getFaceNameListString()
 {
+    std::string strFaceName;
+    for(const auto& it : listPersonInfo)
+    {
+        strFaceName += it.PersonName + ";";
+    }
+    /* 去掉最后的“;” */
+    strFaceName = strFaceName.substr(0, strFaceName.size() - 1);
 
+    return strFaceName;
 }
 
-/* 获取当前频率信息 */
-bool FuncOnAndOffJob::getCurrentFrequencyInfo(const int ChannelID, DecCondition& info)
+/* 获取离岗时间字符串 */
+std::string RoomOnWorkInfo::getLeaveTimeString()
 {
-    auto str = m_toEQMDataBase->getChannelName(ChannelID);
-    if(str == "")
+    std::string strLeaveTime;
+    for(const auto& it : listLeaveTime)
     {
-        SPDLOG_LOGGER_ERROR(m_logger, "获取通道信息失败, ChannelID:{}", ChannelID);
-        return false;
+        strLeaveTime += it.toString("yyyy-MM-dd hh:mm:ss").toStdString() + ";";
     }
-    /* 解析数据 */
-    try
+    /* 去掉最后的“;” */
+    strLeaveTime = strLeaveTime.substr(0, strLeaveTime.size() - 1);
+
+    return strLeaveTime;
+}
+
+/* 获取人员最后在岗时间字符串 */
+std::string RoomOnWorkInfo::getLastOnWorkTimeString()
+{
+    std::string strLastOnWorkTime;
+    for(const auto& it : listPersonInfo)
     {
-        nJson json1 = nJson::parse(str);
-        info.ChannelID = ChannelID;
-        info.leaveNum = json1["leaveNum"].is_null() ? 0 : json1["leaveNum"].get<int>();
-        info.leaveNumOnTime = json1["leaveNumTime"].is_null() ? 0 : json1["leaveNumTime"].get<int>();
-        info.leaveOneTime = json1["leaveLongTime"].is_null() ? 0 : json1["leaveLongTime"].get<int>();
+        strLastOnWorkTime += it.lastOnWork.toString("yyyy-MM-dd hh:mm:ss").toStdString() + ";";
     }
-    catch (const nJson::parse_error& e) {
-        SPDLOG_LOGGER_ERROR(m_logger,"解析 tChannel数据失败 数据失败:{}, 错误ID:{}",e.what(), e.id);
-        return false;
+    /* 去掉最后的“;” */
+    strLastOnWorkTime = strLastOnWorkTime.substr(0, strLastOnWorkTime.size() - 1);
+
+    return strLastOnWorkTime;
+}
+
+
+/* 添加一次离岗时间 */
+void RoomOnWorkInfo::addOneLeaveTime(const QDateTime& time, int maxLeaveTime)
+{
+    if(isLeaveTimeExist(time))
+    {
+        return;
     }
-    catch (const nJson::type_error& e) {
-        SPDLOG_LOGGER_ERROR(m_logger,"解析 tChannel数据失败 数据失败:{}, 错误ID:{}",e.what(), e.id);
-        return false;
+    /* 对时间个数进行限制,不能太多 */
+    if(listLeaveTime.size() > maxLeaveTime)
+    {
+        listLeaveTime.pop_front();
     }
-    catch(...) {
-        SPDLOG_LOGGER_ERROR(m_logger,"解析 tChannel数据失败 数据失败");
-        return false;
+    listLeaveTime.push_back(time);
+}
+
+/* 对离岗时间进行查重 */
+bool RoomOnWorkInfo::isLeaveTimeExist(const QDateTime& time)
+{
+    for(auto& it : listLeaveTime)
+    {
+        if(it == time)
+        {
+            return true;
+        }
     }
+    return false;
+}
+
+
+
+
+
+
+FuncOnAndOffJob::FuncOnAndOffJob()
+{
+    m_pListAlarm = new ListAlarmInfo();
+    m_logger = spdlog::get("SPAServer");
+    if(m_logger == nullptr)
+    {
+        SPDLOG_ERROR("FuncOnAndOffJob logger is nullptr");
+        return;
+    }
+
+}
+
+FuncOnAndOffJob::~FuncOnAndOffJob()
+{
 
-    return true;
 }
 
+
 void FuncOnAndOffJob::task()
 {
     while(GThreadInfo.getRunning())
     {
         /* 判断是否需要退出 */
-        if(m_funcAct.RunState == RunTimeState::RUN_STATE_STOP)
+        if(m_funcThreadInfo.RunState == RunTimeState::RUN_STATE_STOP)
         {
             break;
         }
 
         /* 判断是否在检测时间段内 */
-        if(!isInDetectTime(m_funcAct.StartTime, m_funcAct.EndTime))
+        if(!isInDetectTime(m_funcThreadInfo.StartTime, m_funcThreadInfo.EndTime))
         {
             /* 休眠一段时间 */
             std::this_thread::sleep_for(std::chrono::milliseconds(GConfig.ThreadSleepMS));
             continue;
         }
 
-        /* 先获取所有的直播间,这里不需要读取所有的房间数据 */
+        /* 先获取所有的直播间,这里不需要读取所有的房间数据
+         * 理论上一个频率只有一个直播间 */
         std::map<int, RoomCamActInfo> mapRoomCamActInfo;
-        for(auto& it : m_funcAct.listRoomCamActInfo)
+        for(auto& it : m_funcThreadInfo.listRoomCamActInfo)
         {
             /* 判断是不是直播间 */
             if(it.RoomType == GConfig.liveRoomType)
@@ -153,10 +283,9 @@ void FuncOnAndOffJob::task()
         }
 
         /* 获取当前频率的在岗离岗信息,在表格“tChannel”中 */
-        DecCondition decCondition;
-        if(!getCurrentFrequencyInfo(m_funcAct.ChannelID, decCondition))
+        if(!getCurrentFrequencyInfo(m_funcThreadInfo.ChannelID, m_nowChnDecCondition))
         {
-            SPDLOG_LOGGER_ERROR(m_logger, "获取当前频率信息失败, ChannelID:{}", m_funcAct.ChannelID);
+            SPDLOG_LOGGER_ERROR(m_logger, "获取当前频率信息失败, ChannelID:{}", m_funcThreadInfo.ChannelID);
             std::this_thread::sleep_for(std::chrono::milliseconds(GConfig.ThreadSleepMS));
             continue;
         }
@@ -165,36 +294,45 @@ void FuncOnAndOffJob::task()
         /* 读取Redis数据 */
         for(const auto& RoomInfo : mapRoomCamActInfo)
         {
+            /* it是摄像机信息,it.first是摄像机ID */
             for(const auto& it : RoomInfo.second.mapCameraAction)
             {
-                std::string strKey = std::to_string(it.first) + ":" + it.second;
-                std::string strRetValue;
-                if(!m_fromRedis->getRedisString(strKey, strRetValue))
-                {
-                    SPDLOG_LOGGER_ERROR(m_logger, "读取Redis数据失败, Key:{}", strKey);
-                    std::this_thread::sleep_for(std::chrono::milliseconds(100));
-                    continue;
-                }
-                /* 解析数据 */
-                AlarmInfo alarmInfo;
-                parseRedisBaseData(strRetValue, alarmInfo);
-                parseRedisBBoxesData(strRetValue, alarmInfo);
-                /* 判断事件的时效性,超过多少秒不更新就可能是超脑挂了 */
-                if(isEventTimeVaild(alarmInfo.EventTime))
+                for(const auto& act : it.second)
                 {
-                    SPDLOG_LOGGER_WARN(m_logger, "Redis Key:{} 数据长时间没有更新,EventTime:{}",strKey, alarmInfo.EventTime);
-                    std::this_thread::sleep_for(std::chrono::milliseconds(100));
-                    continue;
+                    std::string strKey = std::to_string(it.first) + ":" + act;
+                    std::string strRetValue;
+                    if(!m_fromRedis->getRedisString(strKey, strRetValue))
+                    {
+                        SPDLOG_LOGGER_ERROR(m_logger, "读取Redis数据失败, Key:{}", strKey);
+                        std::this_thread::sleep_for(std::chrono::milliseconds(100));
+                        continue;
+                    }
+                    /* 解析数据 */
+                    AlarmInfo alarmInfo;
+                    parseRedisBaseData(strRetValue, alarmInfo);
+                    parseRedisBBoxesData(strRetValue, alarmInfo);
+                    /* 判断事件的时效性,超过多少秒不更新就可能是超脑挂了 */
+                    if(isEventTimeVaild(alarmInfo.EventTime))
+                    {
+                        SPDLOG_LOGGER_WARN(m_logger, "Redis Key:{} 数据长时间没有更新,EventTime:{}",strKey, alarmInfo.EventTime);
+                        std::this_thread::sleep_for(std::chrono::milliseconds(100));
+                        continue;
+                    }
+                    m_pListAlarm->addAlarmInfo(alarmInfo);
                 }
-                m_pListAlarm->addAlarmInfo(alarmInfo);
             }
         }
 
+        /* 获取当前时间 */
+        m_curTime = QDateTime::currentDateTime();
+        /* 创建本轮的临时变量 */
+        m_nowRoomOnWorkInfo.clear();
         /* 对所有房间挨个判断 */
         for(auto& roomInfo : mapRoomCamActInfo)
         {
             bool bHasPeople = false;
-            bool bHasFace = false;
+            bool bOnWork = false;
+            m_strBaseInfo = fmt::format("频道[{}][{}], 房间[{}][{}]:", m_funcThreadInfo.ChannelID, m_funcThreadInfo.strChannelName, roomInfo.second.RoomID, roomInfo.second.strRoomName);
             /* 先使用人员计数判断直播间有没有人,如果直播间有人,再使用人脸识别算法判断是否是认识的人(是认识的人才会被识别到) */
             for(auto& alarm : m_pListAlarm->listAlarmInfo)
             {
@@ -210,8 +348,8 @@ void FuncOnAndOffJob::task()
                     }
                 }
             }
-
-            /* 如果有人,再判断是不是认识的人 */
+            
+            /* 如果有人,记录可以识别到的人员信息,记录在岗时间 */
             if(bHasPeople)
             {
                 for(auto& alarm : m_pListAlarm->listAlarmInfo)
@@ -220,10 +358,13 @@ void FuncOnAndOffJob::task()
                     {
                         if(alarm->ActionID == g_actionList.ActFace)
                         {
-                            if(alarm->vecPersonInfo.size() > 0)
+                            if(alarm->listPersonInfo.size() > 0)
                             {
-                                bHasFace = true;
-                                break;
+                                bOnWork = true;
+                                /* 记录人员信息 */
+                                m_nowRoomOnWorkInfo.addPersonInfo(alarm->listPersonInfo);
+                                /* 更新在岗时间 */
+                                m_nowRoomOnWorkInfo.updateOnWorkTime(m_curTime);
                             }
                         }
                     }
@@ -241,12 +382,256 @@ void FuncOnAndOffJob::task()
             {
                 /* 没找到,就创建一个 */
                 pRoomOnWorkInfo = new RoomOnWorkInfo();
+                pRoomOnWorkInfo->bOnWork = bOnWork;
+                pRoomOnWorkInfo->ChannelID = m_funcThreadInfo.ChannelID;
                 pRoomOnWorkInfo->RoomID = roomInfo.first;
+                pRoomOnWorkInfo->RoomID = roomInfo.second.RoomID;
+                pRoomOnWorkInfo->RoomType = roomInfo.second.RoomType;
+                pRoomOnWorkInfo->StartTime = m_curTime;
+                pRoomOnWorkInfo->strImagePath = m_nowRoomOnWorkInfo.strImagePath;
+                pRoomOnWorkInfo->listPersonInfo = m_nowRoomOnWorkInfo.listPersonInfo;
 
+                m_mapRoomOnWorkInfo.insert(std::make_pair(roomInfo.first, pRoomOnWorkInfo));
+            }
+            if(pRoomOnWorkInfo == nullptr)
+            {
+                SPDLOG_LOGGER_ERROR(m_logger, "创建房间在岗信息失败,频率ID:{},房间ID:{}", m_funcThreadInfo.ChannelID, roomInfo.first);
+                continue;
             }
+
+            /* 处理此次在岗和离岗 */
+            if(bOnWork)
+            {
+                /* 在岗 */
+                onWorkProcess(pRoomOnWorkInfo, roomInfo);
+            } else 
+            {
+                /* 离岗 */
+            }
+
+        }
+
+
+    }
+
+}
+
+
+
+/* 获取当前频率信息 */
+bool FuncOnAndOffJob::getCurrentFrequencyInfo(const int ChannelID, DecCondition& info)
+{
+    auto str = m_fromWebAPI->getChannelInfo(ChannelID);
+    if(str == "")
+    {
+        SPDLOG_LOGGER_ERROR(m_logger, "获取通道信息失败, ChannelID:{}", ChannelID);
+        return false;
+    }
+    /* 解析数据 */
+    try
+    {
+        nJson json1 = nJson::parse(str);
+        info.ChannelID = ChannelID;
+        info.strChannelName = json1["chnName"].is_null() ? "" : json1["chnName"].get<std::string>();
+        info.leaveTimeMaxNum = json1["leaveNum"].is_null() ? 0 : json1["leaveNum"].get<int>();
+        info.leaveNumOnTime = json1["leaveNumTime"].is_null() ? 0 : json1["leaveNumTime"].get<int>();
+        info.leaveOneTime = json1["leaveLongTime"].is_null() ? 0 : json1["leaveLongTime"].get<int>();
+    }
+    catch (const nJson::parse_error& e) {
+        SPDLOG_LOGGER_ERROR(m_logger,"解析 tChannel数据失败 数据失败:{}, 错误ID:{}",e.what(), e.id);
+        return false;
+    }
+    catch (const nJson::type_error& e) {
+        SPDLOG_LOGGER_ERROR(m_logger,"解析 tChannel数据失败 数据失败:{}, 错误ID:{}",e.what(), e.id);
+        return false;
+    }
+    catch(...) {
+        SPDLOG_LOGGER_ERROR(m_logger,"解析 tChannel数据失败 数据失败");
+        return false;
+    }
+
+    return true;
+}
+
+
+/**
+ * @brief 人员在岗情况处理
+ * 
+ * @param pRoomOnWorkInfo 这个是内存中的记录,是历史记录
+ * @param roomInfo 
+ */
+void FuncOnAndOffJob::onWorkProcess(RoomOnWorkInfo* pRoomOnWorkInfo, std::pair<const int, RoomCamActInfo>& roomInfo)
+{
+    /* 判断上次是否在岗,上次是离岗,结束离岗报警 */
+    if(pRoomOnWorkInfo->bOnWork == false)
+    {
+        SPDLOG_LOGGER_DEBUG(m_logger, "{} 上次是离岗", m_strBaseInfo);
+        /* 判断是否已经写入数据库,已经写入就结束报警 */
+        if(pRoomOnWorkInfo->PKID > 0)
+        {
+            SPDLOG_LOGGER_INFO(m_logger, "·人员报警结束,{}", m_strBaseInfo);
+            /* 结束报警,写入数据库 */
+            m_fromWebAPI->endAlarmInfoByPKID(pRoomOnWorkInfo->PKID, m_curTime);
+            /* 删除离岗记录,重新开始 */
+            pRoomOnWorkInfo->PKID = 0;
+            pRoomOnWorkInfo->listLeaveTime.clear();
+            pRoomOnWorkInfo->StartTime = m_curTime;
+        }else 
+        {
+            /* 没有写入数据库 */
+            SPDLOG_LOGGER_INFO(m_logger, "·{}人员离岗报警结束,结束时间:{}", m_strBaseInfo, m_curTime.toString("yyyy-MM-dd hh:mm:ss").toStdString());
+        }
+    }
+    pRoomOnWorkInfo->bOnWork = true;
+    /* 记录在岗最后一次的状态,主要是更新图片 */
+    if(m_nowRoomOnWorkInfo.strImagePath != "")
+    {
+        pRoomOnWorkInfo->strImagePath = m_nowRoomOnWorkInfo.strImagePath;
+    }
+
+    /* 在岗记录还未写入数据库,就写入数据库 */
+    if(0 == pRoomOnWorkInfo->PKID)
+    {
+        SPDLOG_LOGGER_DEBUG(m_logger, "{}在岗人脸:{},{}", m_strBaseInfo, m_nowRoomOnWorkInfo.getFaceNameListString(), m_nowRoomOnWorkInfo.getLeaveTimeString());
+
+        /* 删除离岗人员和非法人员,未知人员不判断为离岗 */
+        deleteNoWorkPerson(m_nowRoomOnWorkInfo.listPersonInfo);
+        SPDLOG_LOGGER_DEBUG(m_logger, "{}删除离岗后的人员信息:{}", m_strBaseInfo, m_nowRoomOnWorkInfo.getFaceNameListString());
+
+        /* 写入数据库 */
+        if(m_nowRoomOnWorkInfo.listPersonInfo.size() > 0)
+        {
+            pRoomOnWorkInfo->listPersonInfo.assign(m_nowRoomOnWorkInfo.listPersonInfo.begin(), m_nowRoomOnWorkInfo.listPersonInfo.end());
+
+            AlarmInfo alarmInfo;
+            alarmInfo.appFunction = m_funcThreadInfo.appFunction;
+            alarmInfo.ChannelID = m_funcThreadInfo.ChannelID;
+            alarmInfo.RoomID = pRoomOnWorkInfo->RoomID;
+            alarmInfo.DeviceID = 0;
+            if(roomInfo.second.mapCameraAction.size() == 1)
+            {
+                alarmInfo.DeviceID = roomInfo.second.mapCameraAction.begin()->first;
+            }
+            alarmInfo.listBbox = getCameraNameList(roomInfo.second.mapCameraAction);    /* 直播间摄像机列表 */
+            alarmInfo.ImageInfo = pRoomOnWorkInfo->strImagePath;
+            alarmInfo.StartTime = pRoomOnWorkInfo->StartTime.toString("yyyy-MM-dd hh:mm:ss").toStdString();
+            alarmInfo.ActionID = "";
+            alarmInfo.Is_OnWork = true;
+            alarmInfo.listPersonInfo = pRoomOnWorkInfo->listPersonInfo;
+            alarmInfo.ActionDes = fmt::format("人员在岗[{}][{}]", alarmInfo.getFaceIDListString(), alarmInfo.getFaceNameListString());
+
+            int PKID = 0;
+            m_fromWebAPI->insertAlarmInfo(alarmInfo, PKID);
+            if(PKID > 0)
+            {
+                pRoomOnWorkInfo->PKID = PKID;
+            }
+        }
+    } else 
+    {
+        /* 在岗记录已经写入数据库,对比人脸列表是否相等 */
+        if(m_nowRoomOnWorkInfo.getFaceIDListString() != pRoomOnWorkInfo->getFaceIDListString())
+        {
+            if(m_nowRoomOnWorkInfo.listPersonInfo.size() > 0)
+            {
+                /* 合并在岗人员 */
+                m_nowRoomOnWorkInfo.addPersonInfo(pRoomOnWorkInfo->listPersonInfo);
+                SPDLOG_LOGGER_DEBUG(m_logger, "合并在岗人脸信息前: {}; {}", m_nowRoomOnWorkInfo.getFaceNameListString(), m_nowRoomOnWorkInfo.getLastOnWorkTimeString());
+
+                /* 删除离岗人员和非法人员 */
+                deleteNoWorkPerson(m_nowRoomOnWorkInfo.listPersonInfo);
+                SPDLOG_LOGGER_DEBUG(m_logger, "删除离岗人员信息后: {}", m_nowRoomOnWorkInfo.getFaceNameListString());
+
+                /* 更新在岗信息 */
+                if(m_nowRoomOnWorkInfo.listPersonInfo.size() > 0)
+                {
+                    pRoomOnWorkInfo->listPersonInfo.assign(m_nowRoomOnWorkInfo.listPersonInfo.begin(), m_nowRoomOnWorkInfo.listPersonInfo.end());
+                    /* 更新到数据库 */
+                    if(m_fromWebAPI->updatePersonInfo(*pRoomOnWorkInfo))
+                    {
+                        SPDLOG_LOGGER_INFO(m_logger, "·更新在岗人员信息成功,{}{}{}", m_strBaseInfo, pRoomOnWorkInfo->getFaceIDListString(), pRoomOnWorkInfo->getFaceNameListString());
+                    }else {
+                        SPDLOG_LOGGER_ERROR(m_logger, "·更新在岗人员信息失败,{}", m_strBaseInfo);
+                    }
+                }
+            }
+            if(m_nowRoomOnWorkInfo.listPersonInfo.size() <= 0)
+            {
+                SPDLOG_LOGGER_DEBUG(m_logger, "没有在岗人员信息,不更新在岗人员");
+            }
+        }else 
+        {
+            /* 人员信息没有变化,更新在岗时间 */
+            pRoomOnWorkInfo->updateOnWorkTime(m_curTime);
+            SPDLOG_LOGGER_DEBUG(m_logger, "人员信息没有变化,更新在岗时间: {}", m_nowRoomOnWorkInfo.getLastOnWorkTimeString());
+        }
+
+    }
+
+}
+
+
+/* 人员离岗情况 */
+void FuncOnAndOffJob::offWorkProcess(RoomOnWorkInfo* pRoomOnWorkInfo, std::pair<const int, RoomCamActInfo>& roomInfo)
+{
+    if(true == pRoomOnWorkInfo->bOnWork)
+    {
+        /* 上次是在岗 */
+        SPDLOG_LOGGER_DEBUG(m_logger, "{} 上次是在岗", m_strBaseInfo);
+        pRoomOnWorkInfo->bOnWork = false;
+        /* 判断有没有写入数据库 */
+        if(pRoomOnWorkInfo->PKID > 0)
+        {
+            SPDLOG_LOGGER_INFO(m_logger, "人员在岗结束(PKID:{}),离岗开始,{}", pRoomOnWorkInfo->PKID, m_strBaseInfo);
+            /* 更新数据库,结束在岗 */
+            m_fromWebAPI->endAlarmInfoByPKID(pRoomOnWorkInfo->PKID, m_curTime);
+            pRoomOnWorkInfo->PKID = 0;
+            pRoomOnWorkInfo->StartTime = m_curTime;
+        }else 
+        {
+            /* 没有写入数据库 */
+            SPDLOG_LOGGER_INFO(m_logger, "人员在岗结束,离岗开始,{}", m_strBaseInfo);
+        }
+
+        pRoomOnWorkInfo->addOneLeaveTime(m_curTime, m_nowChnDecCondition.leaveTimeMaxNum);
+        auto strLeaveTime = pRoomOnWorkInfo->getLeaveTimeString();
+        if(strLeaveTime != "")
+        {
+            SPDLOG_LOGGER_DEBUG(m_logger, "★ 人员最近离岗时间, {}, {}", m_strBaseInfo, strLeaveTime);
         }
+    } else 
+    {
+        /* 上次是离岗 */
+        SPDLOG_LOGGER_DEBUG(m_logger, "{} 没有人员,可能离岗了", m_strBaseInfo);
+    }
+
+}
 
 
+/* 删除离岗人员和未知人员信息 */
+void FuncOnAndOffJob::deleteNoWorkPerson(std::list<PersonInfo>& listPersonInfo)
+{
+    /* 删除离岗人员 */
+    for(auto it = listPersonInfo.begin(); it != listPersonInfo.end();)
+    {
+        if((it->lastOnWork < m_curTime) || it->PersonID == "-1" || it->PersonID == "-2")
+        {
+            it = listPersonInfo.erase(it);
+        } else 
+        {
+            ++it;
+        }
     }
 
 }
+
+/* 获取当前直播间的摄像机名称列表 */
+std::list<std::string> FuncOnAndOffJob::getCameraNameList(const std::map<int, std::list<std::string>>& mapCameraAction)
+{
+    std::list<std::string> listCameraName;
+    for(const auto& it : mapCameraAction)
+    {
+        listCameraName.push_back(m_funcThreadInfo.getCameraName(it.first));
+    }
+    return listCameraName;
+}

+ 57 - 14
SecurePlayAuxServer/Application/FuncOnAndOffJob.h

@@ -5,6 +5,7 @@
 
 /**
  * @brief 在岗离岗检测
+ *        理论上一个频率只有一个直播间,直播间内只要有人,且这个人是可以被人脸算法识别到的人,就是在岗
  * 
  */
 
@@ -16,7 +17,8 @@
 struct DecCondition
 {
     int ChannelID;                  /* 通道ID */
-    int leaveNum;                   /* 离岗次数 */
+    std::string strChannelName;     /* 通道名称 */
+    int leaveTimeMaxNum;            /* 离岗时间最大个数,给一个限制 */
     int leaveNumOnTime;             /* 一定时间内的离岗次数 */
     int leaveOneTime;               /* 单次离开报警时间 */
 
@@ -31,18 +33,43 @@ struct DecCondition
  */
  struct RoomOnWorkInfo
  {
-    bool bOnWork = false;          /* 是否在岗 */
-    int RoomID;                     /* 房间ID */
-    int CameraID;                   /* 摄像机ID */
-    int RoomType;                   /* 房间类型 */
-    QDateTime StartTime;            /* 开始时间 */
-    QDateTime EndTime;              /* 结束时间 */
-    std::string strImagePath;       /* 图片路径 */
-    std::list<PersonInfo> listPersonInfo; /* 人员信息 */
-
-    RoomOnWorkInfo() = default;
+    bool bOnWork = false;                   /* 是否在岗 */
+    int PKID;                               /* 主键ID,主要用来判断是否已经写入数据库 */
+    int ChannelID;                          /* 通道ID */
+    int RoomID;                             /* 房间ID */
+    int CameraID;                           /* 摄像机ID */
+    int RoomType;                           /* 房间类型 */
+    std::string strRoomName;                /* 房间名称 */
+    QDateTime StartTime;                    /* 开始时间 */
+    QDateTime EndTime;                      /* 结束时间 */
+    std::string strImagePath;               /* 图片路径 */
+    std::list<QDateTime> listLeaveTime;     /* 离岗时间 */
+    std::list<PersonInfo> listPersonInfo;   /* 人员信息 */
+
+    RoomOnWorkInfo();
     RoomOnWorkInfo& operator=(const RoomOnWorkInfo& other);
     RoomOnWorkInfo(const RoomOnWorkInfo& other);
+    void clear();
+
+    /* 添加人员信息,进行查重 */
+    void addPersonInfo(const std::list<PersonInfo>& vecInfo);
+    /* 更新在岗时间 */
+    void updateOnWorkTime(const QDateTime& time);
+    /* 获取人脸ID字符串 */
+    std::string getFaceIDListString();
+    /* 获取人脸名称字符串 */
+    std::string getFaceNameListString();
+    /* 获取离岗时间字符串 */
+    std::string getLeaveTimeString();
+    /* 获取人员最后在岗时间字符串 */
+    std::string getLastOnWorkTimeString();
+
+    /* 添加一次离岗时间 */
+    void addOneLeaveTime(const QDateTime& time, int maxLeaveTime);
+    /* 对离岗时间进行查重 */
+    bool isLeaveTimeExist(const QDateTime& time);
+    
+
 };
 
 
@@ -54,18 +81,34 @@ public:
     FuncOnAndOffJob();
     ~FuncOnAndOffJob();
 
+
+protected:
+    void task() override;
+
 private:
     /* 获取当前频率信息 */
     bool getCurrentFrequencyInfo(const int ChannelID, DecCondition& info);
-    
-protected:
-    void task() override;
+    /* 人员在岗情况 */
+    void onWorkProcess(RoomOnWorkInfo* pRoomOnWorkInfo, std::pair<const int, RoomCamActInfo>& roomInfo);
+    /* 人员离岗情况 */
+    void offWorkProcess(RoomOnWorkInfo* pRoomOnWorkInfo, std::pair<const int, RoomCamActInfo>& roomInfo);
+
+    /* 删除离岗人员和未知人员信息 */
+    void deleteNoWorkPerson(std::list<PersonInfo>& listPersonInfo);
+    /* 获取当前直播间的摄像机名称列表 */
+    std::list<std::string> getCameraNameList(const std::map<int, std::list<std::string>>& mapCameraAction);
+
 
 private:
     ListAlarmInfo* m_pListAlarm = nullptr;                  /* 报警信息 */
     // std::map<int, ListAlarmInfo*> m_mapRoomPersonCount;     /* 人员计数返回的信息,int是房间ID号 */
     // std::map<int, ListAlarmInfo*> m_mapRoomFaceInfo;        /* 人脸识别返回的信息,int是房间ID号 */
     std::map<int, RoomOnWorkInfo*> m_mapRoomOnWorkInfo;      /* 房间在岗信息 */
+
+    DecCondition m_nowChnDecCondition;                      /* 当前频率的在岗检测信息 */
+    RoomOnWorkInfo m_nowRoomOnWorkInfo;                     /* 当前房间在岗信息 */
+    std::string m_strBaseInfo;                              /* 基础信息,主要是频率ID和房间ID */
+    QDateTime m_curTime;                                    /* 当前时间 */
 };
 
 

+ 99 - 96
SecurePlayAuxServer/Application/FuncOrdinary.cpp

@@ -1,7 +1,7 @@
 #include "FuncOrdinary.h"
 #include "GlobalVariable.h"
 #include "FromRedis.h"
-#include "ToEQMDataBase.h"
+#include "FromWebAPI.h"
 #include "UniversalFunc.h"
 #include "GlobalConfig.h"
 
@@ -28,134 +28,137 @@ void FuncOrdinary::task()
     while (GThreadInfo.getRunning())
     {   
         /* 从全局的信息块中更新功能信息,如是否需要退出线程,主要是更新摄像机关联的算法信息 */
-        GThreadInfo.updateFuncInfo(m_funcAct);
+        GThreadInfo.updateFuncInfo(m_funcThreadInfo);
         /* 如果线程的运行状态为停止 */
-        if(m_funcAct.RunState == RunTimeState::RUN_STATE_STOP)
+        if(m_funcThreadInfo.RunState == RunTimeState::RUN_STATE_STOP)
         {
             /* 退出线程 */
             break;
         }
 
         /* 判断是否在检测时间段内 */
-        if(!isInDetectTime(m_funcAct.StartTime, m_funcAct.EndTime))
+        if(!isInDetectTime(m_funcThreadInfo.StartTime, m_funcThreadInfo.EndTime))
         {
             std::this_thread::sleep_for(std::chrono::milliseconds(GConfig.ThreadSleepMS));
             continue;
         }
 
         /* 读取Redis信息,处理数据,第一层循环是根据房间读取,第二个循环是根据房间内的摄像机读取 */
-        for(const auto& roomInfo : m_funcAct.listRoomCamActInfo)
+        for(const auto& roomInfo : m_funcThreadInfo.listRoomCamActInfo)
         {
             for(const auto& it : roomInfo.mapCameraAction)
             {
-                /* 读取Redis数据 */
-                std::string strKey = std::to_string(it.first) + ":" + it.second;
-                std::string strRetValue;
-                if(!m_fromRedis->getRedisString(strKey, strRetValue))
+                for(const auto act : it.second)
                 {
-                    SPDLOG_LOGGER_ERROR(m_logger, "读取Redis数据失败, Key:{}", strKey);
-                    std::this_thread::sleep_for(std::chrono::milliseconds(10));
-                    continue;
-                }
-                /* 解析数据,先设置基础数据 */
-                AlarmInfo newAlarmInfo;
-                newAlarmInfo.ActionID = it.second;
-                newAlarmInfo.appFunction = m_funcAct.appFunction;
-
-                parseRedisBaseData(strRetValue, newAlarmInfo);
-                parseRedisBBoxesData(strRetValue, newAlarmInfo);
-                /* 判断事件的时效性,超过多少秒不更新就可能是超脑挂了 */
-                if(isEventTimeVaild(newAlarmInfo.EventTime))
-                {
-                    SPDLOG_LOGGER_WARN(m_logger, "Redis Key:{} 数据长时间没有更新,EventTime:{}",strKey, newAlarmInfo.EventTime);
-                    std::this_thread::sleep_for(std::chrono::milliseconds(100));
-                    continue;
-                }
-
-                /* -------------------------------------------------------------------------------
-                 * 判断有无报警记录,新的报警就先创建一个报警信息,写入报警列表,超过报警的最小误报时间后,
-                 * 再写入到EQM的tAlarmInfo表中,正在报警的记录就判断和更新,结束报警就更新tAlarmInfo的
-                 * 报警数据的结束时间,并清空pAlarmInfo 
-                 * ------------------------------------------------------------------------------- */
-
-                /* 找出数组中与当前报警ID相同的的报警信息 */
-                auto pAlarmInfo = m_listAlarm.findAlarmInfo(newAlarmInfo);
-                /* 没有找到报警记录,就新建一个 */
-                if(pAlarmInfo == nullptr)
-                {
-                    /* 新记录有报警,新建报警记录 */
-                    if(newAlarmInfo.Is_Alarm)
+                    /* 读取Redis数据 */
+                    std::string strKey = std::to_string(it.first) + ":" + act;
+                    std::string strRetValue;
+                    if(!m_fromRedis->getRedisString(strKey, strRetValue))
                     {
-                        /* 图片不能是空,如果是空的,就不写入数据库 */
-                        if(!newAlarmInfo.ImageInfo.empty())
-                        {
-                            /* 违禁品检测,开始时间是事件时间 */
-                            newAlarmInfo.StartTime = newAlarmInfo.EventTime;
-                            newAlarmInfo.EndTime = "";
-                            /* 保存新的报警记录 */
-                            newAlarmInfo.Is_InsertEQM = false;
-                            m_listAlarm.addAlarmInfo(newAlarmInfo);
-                        }else 
-                        {
-                            SPDLOG_LOGGER_WARN(m_logger, "频道:{}, 房间:{}, 摄像机:{}, 算法:{}, 有报警区域, 但是没有图片信息", m_funcAct.ChannelID, roomInfo.RoomID, it.first, it.second);
-                        }
+                        SPDLOG_LOGGER_ERROR(m_logger, "读取Redis数据失败, Key:{}", strKey);
+                        std::this_thread::sleep_for(std::chrono::milliseconds(10));
+                        continue;
                     }
-                } 
-                /* 已有报警记录 */
-                else 
-                {
-                    /* 更新图片信息 */
-                    if(!newAlarmInfo.ImageInfo.empty())
+                    /* 解析数据,先设置基础数据 */
+                    AlarmInfo newAlarmInfo;
+                    newAlarmInfo.ActionID = act;
+                    newAlarmInfo.appFunction = m_funcThreadInfo.appFunction;
+
+                    parseRedisBaseData(strRetValue, newAlarmInfo);
+                    parseRedisBBoxesData(strRetValue, newAlarmInfo);
+                    /* 判断事件的时效性,超过多少秒不更新就可能是超脑挂了 */
+                    if(isEventTimeVaild(newAlarmInfo.EventTime))
                     {
-                        pAlarmInfo->ImageInfo = newAlarmInfo.ImageInfo;
+                        SPDLOG_LOGGER_WARN(m_logger, "Redis Key:{} 数据长时间没有更新,EventTime:{}",strKey, newAlarmInfo.EventTime);
+                        std::this_thread::sleep_for(std::chrono::milliseconds(100));
+                        continue;
                     }
-                    /* 判断是否还在报警中 */
-                    if(newAlarmInfo.Is_Alarm)
+
+                    /* -------------------------------------------------------------------------------
+                    * 判断有无报警记录,新的报警就先创建一个报警信息,写入报警列表,超过报警的最小误报时间后,
+                    * 再写入到EQM的tAlarmInfo表中,正在报警的记录就判断和更新,结束报警就更新tAlarmInfo的
+                    * 报警数据的结束时间,并清空pAlarmInfo 
+                    * ------------------------------------------------------------------------------- */
+
+                    /* 找出数组中与当前报警ID相同的的报警信息 */
+                    auto pAlarmInfo = m_listAlarm.findAlarmInfo(newAlarmInfo);
+                    /* 没有找到报警记录,就新建一个 */
+                    if(pAlarmInfo == nullptr)
                     {
-                        /* 正在报警中,检查是否已经写入到数据库中 */
-                        if(pAlarmInfo->Is_InsertEQM)
-                        {
-                            /* 已经写入到数据库中,不做处理 */
-                        }else 
+                        /* 新记录有报警,新建报警记录 */
+                        if(newAlarmInfo.Is_Alarm)
                         {
-                            /* 判断报警时长间隔是否足够 */
-                            if(!isAlarmTimeVaild(*pAlarmInfo))
+                            /* 图片不能是空,如果是空的,就不写入数据库 */
+                            if(!newAlarmInfo.ImageInfo.empty())
                             {
-                                /* 不够报警时间,直接进行下一个循环 */
-                                continue;
-                            }
-
-                            /* 写入到数据库 */
-                            pAlarmInfo->Is_InsertEQM = false;
-                            if(m_toEQMDataBase->insertAlarmInfo(*pAlarmInfo))
+                                /* 违禁品检测,开始时间是事件时间 */
+                                newAlarmInfo.StartTime = newAlarmInfo.EventTime;
+                                newAlarmInfo.EndTime = "";
+                                /* 保存新的报警记录 */
+                                newAlarmInfo.Is_InsertEQM = false;
+                                m_listAlarm.addAlarmInfo(newAlarmInfo);
+                            }else 
                             {
-                                pAlarmInfo->Is_InsertEQM = true;
-                            }else {
-                                SPDLOG_LOGGER_ERROR(m_logger, "写入tAlarmInfo报警数据失败, 频率:{}, 房间:{}, 算法:{} ", m_funcAct.ChannelID, roomInfo.RoomID, it.second);
+                                SPDLOG_LOGGER_WARN(m_logger, "频道:{}, 房间:{}, 摄像机:{}, 算法:{}, 有报警区域, 但是没有图片信息", m_funcThreadInfo.ChannelID, roomInfo.RoomID, it.first, act);
                             }
                         }
-                        
-                    } else 
+                    } 
+                    /* 已有报警记录 */
+                    else 
                     {
-                        /* 报警结束,判断时长,如果小于设置的最小间隔,可能是误报警
-                         * 更新数据库结束时间,结束时间是此时电脑时间 */
-                        if(isAlarmTimeVaild(*pAlarmInfo))
+                        /* 更新图片信息 */
+                        if(!newAlarmInfo.ImageInfo.empty())
+                        {
+                            pAlarmInfo->ImageInfo = newAlarmInfo.ImageInfo;
+                        }
+                        /* 判断是否还在报警中 */
+                        if(newAlarmInfo.Is_Alarm)
                         {
-                            pAlarmInfo->EndTime = chronoToStrTime(std::chrono::system_clock::now());
-                            /* 判断是否已经写入到数据库中 */
+                            /* 正在报警中,检查是否已经写入到数据库中 */
                             if(pAlarmInfo->Is_InsertEQM)
                             {
-                                /* 已经写入到数据库中,更新结束时间 */
-                                m_toEQMDataBase->updateAlarmEndTime(*pAlarmInfo);
-                            }else {
-                                /* 没有写入到数据库中,写入到数据库中 */
-                                m_toEQMDataBase->insertAlarmInfo(*pAlarmInfo);
+                                /* 已经写入到数据库中,不做处理 */
+                            }else 
+                            {
+                                /* 判断报警时长间隔是否足够 */
+                                if(!isAlarmTimeVaild(*pAlarmInfo))
+                                {
+                                    /* 不够报警时间,直接进行下一个循环 */
+                                    continue;
+                                }
+
+                                /* 写入到数据库 */
+                                pAlarmInfo->Is_InsertEQM = false;
+                                if(m_fromWebAPI->insertAlarmInfo(*pAlarmInfo))
+                                {
+                                    pAlarmInfo->Is_InsertEQM = true;
+                                }else {
+                                    SPDLOG_LOGGER_ERROR(m_logger, "写入tAlarmInfo报警数据失败, 频率:{}, 房间:{}, 算法:{} ", m_funcThreadInfo.ChannelID, roomInfo.RoomID, act);
+                                }
+                            }
+                            
+                        } else 
+                        {
+                            /* 报警结束,判断时长,如果小于设置的最小间隔,可能是误报警
+                            * 更新数据库结束时间,结束时间是此时电脑时间 */
+                            if(isAlarmTimeVaild(*pAlarmInfo))
+                            {
+                                pAlarmInfo->EndTime = chronoToStrTime(std::chrono::system_clock::now());
+                                /* 判断是否已经写入到数据库中 */
+                                if(pAlarmInfo->Is_InsertEQM)
+                                {
+                                    /* 已经写入到数据库中,更新结束时间 */
+                                    m_fromWebAPI->updateAlarmEndTime(*pAlarmInfo);
+                                }else {
+                                    /* 没有写入到数据库中,写入到数据库中 */
+                                    m_fromWebAPI->insertAlarmInfo(*pAlarmInfo);
+                                }
+                                SPDLOG_LOGGER_INFO(m_logger, "频率:{}, 房间:{}, 摄像机:{}, 算法:{}, 报警结束", m_funcThreadInfo.ChannelID, roomInfo.RoomID, it.first, act);
                             }
-                            SPDLOG_LOGGER_INFO(m_logger, "频率:{}, 房间:{}, 摄像机:{}, 算法:{}, 报警结束", m_funcAct.ChannelID, roomInfo.RoomID, it.first, it.second);
-                        }
 
-                        /* 删除这个报警信息 */
-                        m_listAlarm.deleteAlarmInfo(*pAlarmInfo);
+                            /* 删除这个报警信息 */
+                            m_listAlarm.deleteAlarmInfo(*pAlarmInfo);
+                        }
                     }
                 }
             }

+ 30 - 26
SecurePlayAuxServer/Application/FuncPersonOnWork.cpp

@@ -3,7 +3,7 @@
 #include "GlobalVariable.h"
 #include "GlobalConfig.h"
 #include "FromRedis.h"
-#include "ToEQMDataBase.h"
+#include "FromWebAPI.h"
 #include "UniversalFunc.h"
 
 FuncPersonOnWork::FuncPersonOnWork()
@@ -41,15 +41,15 @@ void FuncPersonOnWork::task()
     while (GThreadInfo.getRunning())
     {   
         /* 更新线程信息 */
-        GThreadInfo.updateFuncInfo(m_funcAct);
-        if( (m_funcAct.appFunction == AppFunction::APP_NONE) ||
-            (m_funcAct.RunState == RunTimeState::RUN_STATE_STOP) )
+        GThreadInfo.updateFuncInfo(m_funcThreadInfo);
+        if( (m_funcThreadInfo.appFunction == AppFunction::APP_NONE) ||
+            (m_funcThreadInfo.RunState == RunTimeState::RUN_STATE_STOP) )
         {
             break;
         }
         
         /* 判断是否在检测时间段内 */
-        if(!isInDetectTime(m_funcAct.StartTime, m_funcAct.EndTime))
+        if(!isInDetectTime(m_funcThreadInfo.StartTime, m_funcThreadInfo.EndTime))
         {
             std::this_thread::sleep_for(std::chrono::milliseconds(GConfig.ThreadSleepMS));
             continue;
@@ -59,31 +59,35 @@ void FuncPersonOnWork::task()
          * 读取Redis数据 
          * ----------------------------------------------------------------------- */
         m_pListAlarm->clear();
-        for(const auto& RoomInfo : m_funcAct.listRoomCamActInfo)
+        for(const auto& RoomInfo : m_funcThreadInfo.listRoomCamActInfo)
         {
             for(const auto& it : RoomInfo.mapCameraAction)
             {
-                std::string strKey = std::to_string(it.first) + ":" + it.second;
-                std::string strRetValue;
-                if(!m_fromRedis->getRedisString(strKey, strRetValue))
+                for(const auto& act : it.second)
                 {
-                    SPDLOG_LOGGER_ERROR(m_logger, "读取Redis数据失败, Key:{}", strKey);
-                    std::this_thread::sleep_for(std::chrono::milliseconds(10));
-                    continue;
-                }
-                /* 解析数据 */
-                AlarmInfo alarmInfo;
-                alarmInfo.ActionID = it.second;
-                parseRedisBaseData(strRetValue, alarmInfo);
-                parseRedisBBoxesData(strRetValue, alarmInfo);
-                /* 判断事件的时效性,超过多少秒不更新就可能是超脑挂了 */
-                if(isEventTimeVaild(alarmInfo.EventTime))
-                {
-                    SPDLOG_LOGGER_WARN(m_logger, "Redis Key:{} 数据长时间没有更新,EventTime:{}",strKey, alarmInfo.EventTime);
-                    std::this_thread::sleep_for(std::chrono::milliseconds(100));
-                    continue;
+                    /* 读取Redis数据 */
+                    std::string strKey = std::to_string(it.first) + ":" + act;
+                    std::string strRetValue;
+                    if(!m_fromRedis->getRedisString(strKey, strRetValue))
+                    {
+                        SPDLOG_LOGGER_ERROR(m_logger, "读取Redis数据失败, Key:{}", strKey);
+                        std::this_thread::sleep_for(std::chrono::milliseconds(10));
+                        continue;
+                    }
+                    /* 解析数据 */
+                    AlarmInfo alarmInfo;
+                    alarmInfo.ActionID = act;
+                    parseRedisBaseData(strRetValue, alarmInfo);
+                    parseRedisBBoxesData(strRetValue, alarmInfo);
+                    /* 判断事件的时效性,超过多少秒不更新就可能是超脑挂了 */
+                    if(isEventTimeVaild(alarmInfo.EventTime))
+                    {
+                        SPDLOG_LOGGER_WARN(m_logger, "Redis Key:{} 数据长时间没有更新,EventTime:{}",strKey, alarmInfo.EventTime);
+                        std::this_thread::sleep_for(std::chrono::milliseconds(100));
+                        continue;
+                    }
+                    m_pListAlarm->push_back(alarmInfo);
                 }
-                m_pListAlarm->push_back(alarmInfo);
             }
         }
 
@@ -110,7 +114,7 @@ void FuncPersonOnWork::task()
             if(now.toSecsSinceEpoch() - it->StartTime.toSecsSinceEpoch() > GConfig.AppUpdateOnWorkTimeInterval_Time)
             {
                 /* 写入数据库 */
-                if(m_toEQMDataBase->insertOnWorkInfo(*it))
+                if(m_fromWebAPI->insertOnWorkInfo(*it))
                 {
                     SPDLOG_LOGGER_INFO(m_logger, "☆ 新增人脸信息,频道[{}][{}],摄像头[{}][{}],时间范围[{} - {}],人数范围[{} - {}]", 
                     it->ChannelID, GConfig.getChannelName(it->ChannelID), it->CameraID, GConfig.getCameraName(it->CameraID), 

+ 0 - 484
SecurePlayAuxServer/GlobalInfo/GlobalConfig.cpp

@@ -128,487 +128,3 @@ std::string GlobalConfig::getCameraName(int CameraID)
 
 
 
-/* ====================================================================================
- * ************************    GlobalThreadInfo成员函数    *****************************
- * ====================================================================================*/
-
-/* 获取线程运行标志位 */
-bool GlobalThreadInfo::getRunning() const
-{
-    return m_bRunning;
-}
-
-/* 设置线程运行标志位 */
-void GlobalThreadInfo::setRunning(bool bRunning)
-{
-    m_bRunning = bRunning;
-}
-
-/* 手动给功能块列表加锁 */
-void GlobalThreadInfo::lockRunFAI()
-{
-    m_mutexRunFAI.lock();
-}
-
-/* 手动解锁 */
-void GlobalThreadInfo::unlockRunFAI()
-{
-    m_mutexRunFAI.unlock();
-}
-
-
-/**
- * @brief 添加应用信息,一个应用功能在一个频道内只有一个实例
- *        这里是添加应用功能和时间段信息
- * 
- * @param func 
- * @return true 
- * @return false 
- */
-bool GlobalThreadInfo::addFuncActionInfo(const AppAndTimeInfo& func)
-{
-    if(func.AppType == 0)
-    {
-        return false;
-    }
-    /* 解出这条信息里包含几个App,AppType按位计算,总共8个应用信息 */
-    for(int i = 0; i < 8; ++i)
-    {
-        if(func.AppType & 0x01)
-        {
-            /* 查找有没有这个应用 */
-            auto pFuncActionInfo = findAppFunction(func.ChannelID, AppFunction::APP_OnWork);
-            if(pFuncActionInfo != nullptr)
-            {
-                /* 更新时间信息 */
-                pFuncActionInfo->StartTime = func.StartTime;
-                pFuncActionInfo->EndTime = func.EndTime;
-                continue;
-            }
-            FuncActionInfo* fa = new FuncActionInfo;
-            fa->ChannelID = func.ChannelID;
-            fa->appFunction = AppFunction::APP_OnWork;
-            fa->strFunctionName = "人员在岗识别";
-            fa->StartTime = func.StartTime;
-            fa->EndTime = func.EndTime;
-            m_listFuncActionInfo.push_back(fa);
-        }
-        else if(func.AppType & 0x02)
-        {
-            auto pFuncActionInfo = findAppFunction(func.ChannelID, AppFunction::APP_Contraband);
-            if(pFuncActionInfo != nullptr)
-            {
-                /* 更新时间信息 */
-                pFuncActionInfo->StartTime = func.StartTime;
-                pFuncActionInfo->EndTime = func.EndTime;
-                continue;
-            }
-            FuncActionInfo* fa = new FuncActionInfo;
-            fa->ChannelID = func.ChannelID;
-            fa->appFunction = AppFunction::APP_Contraband;
-            fa->strFunctionName = "违禁品识别";
-            fa->StartTime = func.StartTime;
-            fa->EndTime = func.EndTime;
-            m_listFuncActionInfo.push_back(fa);
-        }
-        else if (func.AppType & 0x04)
-        {
-            auto pFuncActionInfo = findAppFunction(func.ChannelID, AppFunction::APP_Illegal);
-            if(pFuncActionInfo != nullptr)
-            {
-                /* 更新时间信息 */
-                pFuncActionInfo->StartTime = func.StartTime;
-                pFuncActionInfo->EndTime = func.EndTime;
-                continue;
-            }
-            FuncActionInfo* fa = new FuncActionInfo;
-            fa->ChannelID = func.ChannelID;
-            fa->appFunction = AppFunction::APP_Illegal;
-            fa->strFunctionName = "非法入侵检测";
-            fa->StartTime = func.StartTime;
-            fa->EndTime = func.EndTime;
-            m_listFuncActionInfo.push_back(fa);
-        }
-        else if (func.AppType & 0x08)
-        {
-            auto pFuncActionInfo = findAppFunction(func.ChannelID, AppFunction::APP_Fatigue);
-            if(pFuncActionInfo != nullptr)
-            {
-                /* 更新时间信息 */
-                pFuncActionInfo->StartTime = func.StartTime;
-                pFuncActionInfo->EndTime = func.EndTime;
-                continue;
-            }
-            FuncActionInfo* fa = new FuncActionInfo;
-            fa->ChannelID = func.ChannelID;
-            fa->appFunction = AppFunction::APP_Fatigue;
-            fa->strFunctionName = "疲劳检测";
-            fa->StartTime = func.StartTime;
-            fa->EndTime = func.EndTime;
-            m_listFuncActionInfo.push_back(fa);
-        }
-        else if (func.AppType & 0x10)
-        {
-            auto pFuncActionInfo = findAppFunction(func.ChannelID, AppFunction::APP_Regional);
-            if(pFuncActionInfo != nullptr)
-            {
-                /* 更新时间信息 */
-                pFuncActionInfo->StartTime = func.StartTime;
-                pFuncActionInfo->EndTime = func.EndTime;
-                continue;
-            }
-            FuncActionInfo* fa = new FuncActionInfo;
-            fa->ChannelID = func.ChannelID;
-            fa->appFunction = AppFunction::APP_Regional;
-            fa->strFunctionName = "区域人员检测";
-            fa->StartTime = func.StartTime;
-            fa->EndTime = func.EndTime;
-            m_listFuncActionInfo.push_back(fa);
-        }
-        else if (func.AppType & 0x20)
-        {
-            auto pFuncActionInfo = findAppFunction(func.ChannelID, AppFunction::APP_Mouse);
-            if(pFuncActionInfo != nullptr)
-            {
-                /* 更新时间信息 */
-                pFuncActionInfo->StartTime = func.StartTime;
-                pFuncActionInfo->EndTime = func.EndTime;
-                continue;
-            }
-            FuncActionInfo* fa = new FuncActionInfo;
-            fa->ChannelID = func.ChannelID;
-            fa->appFunction = AppFunction::APP_Mouse;
-            fa->strFunctionName = "老鼠识别";
-            fa->StartTime = func.StartTime;
-            fa->EndTime = func.EndTime;
-            m_listFuncActionInfo.push_back(fa);
-        }
-        else if (func.AppType & 0x40)
-        {
-            auto pFuncActionInfo = findAppFunction(func.ChannelID, AppFunction::APP_PlayPhone);
-            if(pFuncActionInfo != nullptr)
-            {
-                /* 更新时间信息 */
-                pFuncActionInfo->StartTime = func.StartTime;
-                pFuncActionInfo->EndTime = func.EndTime;
-                continue;
-            }
-            FuncActionInfo* fa = new FuncActionInfo;
-            fa->ChannelID = func.ChannelID;
-            fa->appFunction = AppFunction::APP_PlayPhone;
-            fa->strFunctionName = "玩手机识别";
-            fa->StartTime = func.StartTime;
-            fa->EndTime = func.EndTime;
-            m_listFuncActionInfo.push_back(fa);
-        }
-        else if (func.AppType & 0x80)
-        {
-            auto pFuncActionInfo = findAppFunction(func.ChannelID, AppFunction::APP_NoMask);
-            if(pFuncActionInfo != nullptr)
-            {
-                /* 更新时间信息 */
-                pFuncActionInfo->StartTime = func.StartTime;
-                pFuncActionInfo->EndTime = func.EndTime;
-                continue;
-            }
-            FuncActionInfo* fa = new FuncActionInfo;
-            fa->ChannelID = func.ChannelID;
-            fa->appFunction = AppFunction::APP_NoMask;
-            fa->strFunctionName = "未戴口罩识别";
-            fa->StartTime = func.StartTime;
-            fa->EndTime = func.EndTime;
-            m_listFuncActionInfo.push_back(fa);
-        }
-        else if (func.AppType & 0x0100)
-        {
-            auto pFuncActionInfo = findAppFunction(func.ChannelID, AppFunction::APP_AllDown);
-            if(pFuncActionInfo != nullptr)
-            {
-                /* 更新时间信息 */
-                pFuncActionInfo->StartTime = func.StartTime;
-                pFuncActionInfo->EndTime = func.EndTime;
-                continue;
-            }
-            FuncActionInfo* fa = new FuncActionInfo;
-            fa->ChannelID = func.ChannelID;
-            fa->appFunction = AppFunction::APP_AllDown;
-            fa->strFunctionName = "摔倒识别";
-            fa->StartTime = func.StartTime;
-            fa->EndTime = func.EndTime;
-            m_listFuncActionInfo.push_back(fa);
-        }
-    }
-
-
-    return true;
-}
-
-
-
-/**
- * @brief 添加算法信息,根据传进来的算法ID,将其加入到对应的功能中
- *        根据功能需要,将算法ID加入到对应的功能中
- * 
- * @param info 
- * @return true 
- * @return false 
- */
-bool GlobalThreadInfo::addActionInfo(const ActionInfo& info)
-{
-    if(info.ActionID.empty())
-    {
-        return false;
-    }
-    /* 人脸识别算法(人员在岗识别、非法入侵检测需要) */
-    if(info.ActionID == g_actionList.ActFace)
-    {
-        /* 人员在岗识别 */
-        auto pFuncActionInfo = findAppFunction(info.ChannelID, AppFunction::APP_OnWork);
-        if(pFuncActionInfo != nullptr)
-        {
-            pFuncActionInfo->addActionInfo(info);
-        }
-        /* 非法入侵检测 */
-        pFuncActionInfo = findAppFunction(info.ChannelID, AppFunction::APP_Illegal);
-        if(pFuncActionInfo != nullptr)
-        {
-            pFuncActionInfo->addActionInfo(info);
-        }
-    }
-    /* 人员计数 */
-    else if (info.ActionID == g_actionList.ActPersonNumber)
-    {
-        /* 区域人员检测(人员计数?) */
-        auto pFuncActionInfo = findAppFunction(info.ChannelID, AppFunction::APP_Regional);
-        if(pFuncActionInfo != nullptr)
-        {
-            pFuncActionInfo->addActionInfo(info);
-        }
-        /* 非法入侵检测 */
-        pFuncActionInfo = findAppFunction(info.ChannelID, AppFunction::APP_Illegal);
-        if(pFuncActionInfo != nullptr)
-        {
-            pFuncActionInfo->addActionInfo(info);
-        }
-        /* 人员在岗识别 */
-        pFuncActionInfo = findAppFunction(info.ChannelID, AppFunction::APP_OnWork);
-        if(pFuncActionInfo != nullptr)
-        {
-            pFuncActionInfo->addActionInfo(info);
-        }
-    }
-    /* 违禁物品 */
-    else if (info.ActionID == g_actionList.ActContraband)
-    {
-        auto pFuncActionInfo = findAppFunction(info.ChannelID, AppFunction::APP_Contraband);
-        if(pFuncActionInfo != nullptr)
-        {
-            pFuncActionInfo->addActionInfo(info);
-        }
-    }
-    /* 玩手机 */
-    else if (info.ActionID == g_actionList.ActPlayPhone)
-    {
-        auto pFuncActionInfo = findAppFunction(info.ChannelID, AppFunction::APP_PlayPhone);
-        if(pFuncActionInfo != nullptr)
-        {
-            pFuncActionInfo->addActionInfo(info);
-        }
-    }
-    /* 睡岗识别 */
-    else if (info.ActionID == g_actionList.ActSleep)
-    {
-        auto pFuncActionInfo = findAppFunction(info.ChannelID, AppFunction::APP_Fatigue);
-        if(pFuncActionInfo != nullptr)
-        {
-            pFuncActionInfo->addActionInfo(info);
-        }
-    }
-    /* 疲劳检测 */
-    else if(info.ActionID == g_actionList.ActFatigueDetection)
-    {
-        auto pFuncActionInfo = findAppFunction(info.ChannelID, AppFunction::APP_Fatigue);
-        if(pFuncActionInfo != nullptr)
-        {
-            pFuncActionInfo->addActionInfo(info);
-        }
-    }
-    /* 动物识别 */
-    else if (info.ActionID == g_actionList.ActAnimalDetect)
-    {
-        auto pFuncActionInfo = findAppFunction(info.ChannelID, AppFunction::APP_Mouse);
-        if(pFuncActionInfo != nullptr)
-        {
-            pFuncActionInfo->addActionInfo(info);
-        }
-    }
-    /* 老鼠识别 */
-    else if (info.ActionID == g_actionList.ActMouseDetect)
-    {
-        auto pFuncActionInfo = findAppFunction(info.ChannelID, AppFunction::APP_Mouse);
-        if(pFuncActionInfo != nullptr)
-        {
-            pFuncActionInfo->addActionInfo(info);
-        }
-    }
-    /* 口罩识别 */
-    else if (info.ActionID == g_actionList.ActMask)
-    {
-        auto pFuncActionInfo = findAppFunction(info.ChannelID, AppFunction::APP_NoMask);
-        if(pFuncActionInfo != nullptr)
-        {
-            pFuncActionInfo->addActionInfo(info);
-        }
-    }
-    else {
-        SPDLOG_WARN("未知的算法ID: {}", info.ActionID);
-        return false;
-    }
-
-    return true;
-}
-
-/**
- * @brief 清空无用的功能信息
- *          摄像机和算法信息为空的,或者运行状态为RUN_STATE_EXITCOMPLET,都会被清理掉
- * 
- */
-void GlobalThreadInfo::clearNoneFuncActionInfo()
-{
-    for(auto it0 = m_listFuncActionInfo.begin(); it0 != m_listFuncActionInfo.end();)
-    {
-        if((*it0)->listRoomCamActInfo.empty() || ((*it0)->RunState == RunTimeState::RUN_STATE_EXITCOMPLET))
-        {
-            delete *it0;
-            it0 = m_listFuncActionInfo.erase(it0);
-        }else {
-            ++it0;
-        }
-    }
-}
-
-/* 清空算法列表(直接清空房间信息) */
-void GlobalThreadInfo::clearActionList()
-{
-    for(auto& it0 : m_listFuncActionInfo)
-    {
-        // for(auto& it1 : it0->listRoomCamActInfo)
-        // {
-        //     it1.mapCameraAction.clear();
-        // }
-        it0->listRoomCamActInfo.clear();
-    }
-}
-
-/* 设置没有配置摄像机的功能退出 */
-void GlobalThreadInfo::setNoneCameraFuncStop()
-{
-    for(auto& it : m_listFuncActionInfo)
-    {
-        if(it->listRoomCamActInfo.empty())
-        {
-            it->RunState = RunTimeState::RUN_STATE_STOP;
-            SPDLOG_INFO("《{}》房间信息为空,退出检测", it->strFunctionName);
-        }
-    }
-}
-
-/* 查找应用信息 */
-bool GlobalThreadInfo::findAppFunction(const AppFunction func)
-{
-    for(const auto& it0 : m_listFuncActionInfo)
-    {
-        if(it0->appFunction == func)
-        {
-            return true;
-        }
-    }
-    return false;
-}
-
-/* 根据频率和功能查找实例 */
-FuncActionInfo* GlobalThreadInfo::findAppFunction(const int ChannelID, const AppFunction func)
-{
-    for(const auto& it0 : m_listFuncActionInfo)
-    {
-        if( (it0->appFunction == func) && (it0->ChannelID == ChannelID) )
-        {
-            return it0;
-        }
-    }
-    return nullptr;
-}
-
-/**
- * @brief 查找这个应用信息
- * 
- * @param func 
- * @return FuncActionInfo* 
- */
-FuncActionInfo* GlobalThreadInfo::findAppFunction(const FuncActionInfo& func)
-{
-    for(const auto& it0 : m_listFuncActionInfo)
-    {
-        if(it0->ChannelID == func.ChannelID && it0->appFunction == func.appFunction)
-        {
-            return it0;
-        }
-    }
-    return nullptr;
-}
-
-/* 设置线程状态 */
-void GlobalThreadInfo::setThreadState(FuncActionInfo* pInfo, RunTimeState state)
-{
-    std::lock_guard<std::mutex> look(m_mutexRunFAI);
-    auto p = findAppFunction(*pInfo);
-    if(p != nullptr)
-    {
-        p->RunState = state;
-    }
-}
-
-void GlobalThreadInfo::setThreadState(FuncActionInfo& pInfo, RunTimeState state)
-{
-    std::lock_guard<std::mutex> look(m_mutexRunFAI);
-    auto p = findAppFunction(pInfo);
-    if(p != nullptr)
-    {
-        p->RunState = state;
-    }
-}
-
-/**
- * @brief 功能线程更新功能信息,这里是从内存中的数组里获取
- * 
- * @param pInfo 
- * @return true 
- * @return false 
- */
- bool GlobalThreadInfo::updateFuncInfo(FuncActionInfo* pInfo)
-{
-    pInfo->clearActionList();
-    std::lock_guard<std::mutex> look(m_mutexRunFAI);
-    auto fa = findAppFunction(*pInfo);
-    if(fa == nullptr)
-    {
-        return false;
-    }
-    *pInfo = *fa;
-
-    return true;
-}
-bool GlobalThreadInfo::updateFuncInfo(FuncActionInfo& pInfo)
-{
-    pInfo.clearActionList();
-    std::lock_guard<std::mutex> look(m_mutexRunFAI);
-    auto fa = findAppFunction(pInfo);
-    if(fa == nullptr)
-    {
-        return false;
-    }
-    pInfo = *fa;
-
-    return true;
-}
-

+ 4 - 68
SecurePlayAuxServer/GlobalInfo/GlobalConfig.h

@@ -62,11 +62,15 @@ public:
     void clearChannelInfo();
     /* 获取通道名称 */
     std::string getChannelName(int ChannelID);
+    /* 获取通道信息 */
+    std::map<int, std::string> getChannelInfoMap();
 
     /* 添加摄像机信息 */
     void setCameraInfo(std::map<int, std::string> mapCameraName);
     /* 获取摄像机名称 */
     std::string getCameraName(int CameraID);
+    /* 获取摄像机信息列表 */
+    std::map<int, std::string> getCameraInfoMap() { return m_mapCameraName; }
 
 private:
     QReadWriteLock m_rwLockChnInfo;                     /* 读写锁 */
@@ -78,74 +82,6 @@ private:
 
 
 
-/* ====================================================================================
- * ************************    GlobalThreadInfo成员函数    ****************************
- * ====================================================================================*/
-
-#define GThreadInfo GlobalThreadInfo::getInstance()
-
-/**
- * @brief 线程信息,也是应用功能块列表,每个频率下的每个功能就是一个线程
- * 
- */
-class GlobalThreadInfo
-{
-    GlobalThreadInfo() {}
-    ~GlobalThreadInfo() {}
-    GlobalThreadInfo(const GlobalThreadInfo& other) = delete;
-    GlobalThreadInfo& operator=(const GlobalThreadInfo& other) = delete;
-public:
-    static GlobalThreadInfo& getInstance()
-    {
-        static GlobalThreadInfo instance;
-        return instance;
-    }
-    /* 获取线程运行标志位 */
-    bool getRunning() const;
-    /* 设置线程运行标志位 */
-    void setRunning(bool bRunning);
-    
-    /* 手动给功能块列表加锁 */
-    void lockRunFAI();
-    /* 手动解锁 */
-    void unlockRunFAI();
-    /* 添加功能信息 */
-    bool addFuncActionInfo(const AppAndTimeInfo& func);
-    /* 添加算法信息 */
-    bool addActionInfo(const ActionInfo& info);
-    /* 清空无用的功能信息 */
-    void clearNoneFuncActionInfo();
-    /* 清空房间和算法列表 */
-    void clearActionList();
-    /* 设置没有配置摄像机的功能退出 */
-    void setNoneCameraFuncStop();
-
-    /* 获取容器 */
-    std::list<FuncActionInfo*>& getList() {
-        return m_listFuncActionInfo;
-    }
-    /* 查找应用信息 */
-    bool findAppFunction(const AppFunction func);
-    FuncActionInfo* findAppFunction(const int ChannelID, const AppFunction func);
-    FuncActionInfo* findAppFunction(const FuncActionInfo& func);
-
-    /* 设置线程状态 */
-    void setThreadState(FuncActionInfo* pInfo, RunTimeState state);
-    void setThreadState(FuncActionInfo& pInfo, RunTimeState state);
-    /* 更新算法的摄像机ID */
-    bool updateFuncInfo(FuncActionInfo* pInfo);
-    bool updateFuncInfo(FuncActionInfo& pInfo);
-
-    
 
-private:
-    std::atomic_bool m_bRunning;    /* 线程运行状态 */
-
-    /* 运行时应用线程功能相关信息 */
-    std::mutex m_mutexRunFAI;
-    std::list<FuncActionInfo*> m_listFuncActionInfo;    /* 功能信息列表 */
-
-    
-};
 
 #endif /* GLOBALCONFIG_H */

+ 974 - 0
SecurePlayAuxServer/GlobalInfo/GlobalFuncThread.cpp

@@ -0,0 +1,974 @@
+#include "GlobalFuncThread.h"
+
+#include "spdlog/spdlog.h"
+
+FuncThreadInfo::FuncThreadInfo() 
+{
+    ChannelID = -1;
+    strChannelName = "";
+    appFunction = AppFunction::APP_NONE;
+    RunState = RunTimeState::RUN_STATE_NONE;
+    strFunctionName = "";
+    StartTime = QDateTime::currentDateTime();
+    EndTime = QDateTime::currentDateTime();
+    listRoomCamActInfo.clear();
+    mapCameraName.clear();
+}
+
+FuncThreadInfo::~FuncThreadInfo()
+{
+    
+}
+
+
+FuncThreadInfo& FuncThreadInfo::operator=(FuncThreadInfo& other)
+{
+    if(this != &other)
+    {
+        ChannelID = other.ChannelID;
+        strChannelName = other.strChannelName;
+        appFunction = other.appFunction;
+        RunState = other.RunState;
+        strFunctionName = other.strFunctionName;
+        StartTime = other.StartTime;
+        EndTime = other.EndTime;
+        listRoomCamActInfo = other.listRoomCamActInfo;
+        mapCameraName = other.mapCameraName;
+    }
+    return *this;
+}
+
+/**
+ * @brief 添加算法信息,这里不能直接创建房间,需要先判断有没有已有的房间,因为有的应用功能可能会包含多个房间
+ *        已经提前被创建过了
+ * 
+ * @param info 
+ * @return true 
+ * @return false 
+ */
+bool FuncThreadInfo::addActionInfo(const ActionInfo& info)
+{
+    /* 根据此类的功能,添加算法信息 */
+    if(appFunction == AppFunction::APP_NONE)
+    {
+        return false;
+    }
+    /* 将其添加到对应的房间 */
+    bool isFind = false;
+    for(auto& roomInfo : listRoomCamActInfo)
+    {
+        if((roomInfo.RoomID == info.RoomID) && (roomInfo.RoomType == info.RoomType))
+        {
+            isFind = true;
+            // roomInfo.mapCameraAction.insert(std::make_pair(info.CameraID, info.ActionID));
+            roomInfo.addCameraAction(info.CameraID, info.ActionID);
+            break;
+        }
+    }
+    /* 没找到这个房间,就创建 */
+    if(!isFind)
+    {
+        RoomCamActInfo roomCamActInfo;
+        roomCamActInfo.RoomID = info.RoomID;
+        roomCamActInfo.RoomType = info.RoomType;
+        roomCamActInfo.strRoomName = info.strRoomName;
+        roomCamActInfo.addCameraAction(info.CameraID, info.ActionID);
+        listRoomCamActInfo.push_back(roomCamActInfo);
+    }
+
+
+    return true;
+}
+
+/* 清空算法信息 */
+void FuncThreadInfo::clearActionList()
+{
+    listRoomCamActInfo.clear();
+}
+
+/* 获取摄像机名称 */
+std::string FuncThreadInfo::getCameraName(int CameraID)
+{
+    auto it = mapCameraName.find(CameraID);
+    if(it != mapCameraName.end())
+    {
+        return it->second;
+    }
+    return "";
+}
+
+/**
+ * @brief 添加应用信息,一个应用功能在一个频道内只有一个实例
+ *        这里是添加应用功能和时间段信息
+ * 
+ * @param func 
+ * @return true 
+ * @return false 
+ */
+bool ListFuncActInfo::addFuncThreadInfo(const AppAndTimeInfo& func)
+{
+    if(func.AppType == 0)
+    {
+        return false;
+    }
+    /* 解出这条信息里包含几个App,AppType按位计算,总共8个应用信息 */
+    for(int i = 0; i < 8; ++i)
+    {
+        if(func.AppType & 0x01)
+        {
+            /* 查找有没有这个应用 */
+            auto pFuncThreadInfo = findAppFunction(func.ChannelID, AppFunction::APP_OnWork);
+            if(pFuncThreadInfo != nullptr)
+            {
+                /* 更新时间信息 */
+                pFuncThreadInfo->StartTime = func.StartTime;
+                pFuncThreadInfo->EndTime = func.EndTime;
+                continue;
+            }
+            FuncThreadInfo* fa = new FuncThreadInfo;
+            fa->ChannelID = func.ChannelID;
+            fa->appFunction = AppFunction::APP_OnWork;
+            fa->strFunctionName = "人员在岗识别";
+            fa->StartTime = func.StartTime;
+            fa->EndTime = func.EndTime;
+            listFuncThreadInfo.push_back(fa);
+        }
+        else if(func.AppType & 0x02)
+        {
+            auto pFuncThreadInfo = findAppFunction(func.ChannelID, AppFunction::APP_Contraband);
+            if(pFuncThreadInfo != nullptr)
+            {
+                /* 更新时间信息 */
+                pFuncThreadInfo->StartTime = func.StartTime;
+                pFuncThreadInfo->EndTime = func.EndTime;
+                continue;
+            }
+            FuncThreadInfo* fa = new FuncThreadInfo;
+            fa->ChannelID = func.ChannelID;
+            fa->appFunction = AppFunction::APP_Contraband;
+            fa->strFunctionName = "违禁品识别";
+            fa->StartTime = func.StartTime;
+            fa->EndTime = func.EndTime;
+            listFuncThreadInfo.push_back(fa);
+        }
+        else if (func.AppType & 0x04)
+        {
+            auto pFuncThreadInfo = findAppFunction(func.ChannelID, AppFunction::APP_Illegal);
+            if(pFuncThreadInfo != nullptr)
+            {
+                /* 更新时间信息 */
+                pFuncThreadInfo->StartTime = func.StartTime;
+                pFuncThreadInfo->EndTime = func.EndTime;
+                continue;
+            }
+            FuncThreadInfo* fa = new FuncThreadInfo;
+            fa->ChannelID = func.ChannelID;
+            fa->appFunction = AppFunction::APP_Illegal;
+            fa->strFunctionName = "非法入侵检测";
+            fa->StartTime = func.StartTime;
+            fa->EndTime = func.EndTime;
+            listFuncThreadInfo.push_back(fa);
+        }
+        else if (func.AppType & 0x08)
+        {
+            auto pFuncThreadInfo = findAppFunction(func.ChannelID, AppFunction::APP_Fatigue);
+            if(pFuncThreadInfo != nullptr)
+            {
+                /* 更新时间信息 */
+                pFuncThreadInfo->StartTime = func.StartTime;
+                pFuncThreadInfo->EndTime = func.EndTime;
+                continue;
+            }
+            FuncThreadInfo* fa = new FuncThreadInfo;
+            fa->ChannelID = func.ChannelID;
+            fa->appFunction = AppFunction::APP_Fatigue;
+            fa->strFunctionName = "疲劳检测";
+            fa->StartTime = func.StartTime;
+            fa->EndTime = func.EndTime;
+            listFuncThreadInfo.push_back(fa);
+        }
+        else if (func.AppType & 0x10)
+        {
+            auto pFuncThreadInfo = findAppFunction(func.ChannelID, AppFunction::APP_Regional);
+            if(pFuncThreadInfo != nullptr)
+            {
+                /* 更新时间信息 */
+                pFuncThreadInfo->StartTime = func.StartTime;
+                pFuncThreadInfo->EndTime = func.EndTime;
+                continue;
+            }
+            FuncThreadInfo* fa = new FuncThreadInfo;
+            fa->ChannelID = func.ChannelID;
+            fa->appFunction = AppFunction::APP_Regional;
+            fa->strFunctionName = "区域人员检测";
+            fa->StartTime = func.StartTime;
+            fa->EndTime = func.EndTime;
+            listFuncThreadInfo.push_back(fa);
+        }
+        else if (func.AppType & 0x20)
+        {
+            auto pFuncThreadInfo = findAppFunction(func.ChannelID, AppFunction::APP_Mouse);
+            if(pFuncThreadInfo != nullptr)
+            {
+                /* 更新时间信息 */
+                pFuncThreadInfo->StartTime = func.StartTime;
+                pFuncThreadInfo->EndTime = func.EndTime;
+                continue;
+            }
+            FuncThreadInfo* fa = new FuncThreadInfo;
+            fa->ChannelID = func.ChannelID;
+            fa->appFunction = AppFunction::APP_Mouse;
+            fa->strFunctionName = "老鼠识别";
+            fa->StartTime = func.StartTime;
+            fa->EndTime = func.EndTime;
+            listFuncThreadInfo.push_back(fa);
+        }
+        else if (func.AppType & 0x40)
+        {
+            auto pFuncThreadInfo = findAppFunction(func.ChannelID, AppFunction::APP_PlayPhone);
+            if(pFuncThreadInfo != nullptr)
+            {
+                /* 更新时间信息 */
+                pFuncThreadInfo->StartTime = func.StartTime;
+                pFuncThreadInfo->EndTime = func.EndTime;
+                continue;
+            }
+            FuncThreadInfo* fa = new FuncThreadInfo;
+            fa->ChannelID = func.ChannelID;
+            fa->appFunction = AppFunction::APP_PlayPhone;
+            fa->strFunctionName = "玩手机识别";
+            fa->StartTime = func.StartTime;
+            fa->EndTime = func.EndTime;
+            listFuncThreadInfo.push_back(fa);
+        }
+        else if (func.AppType & 0x80)
+        {
+            auto pFuncThreadInfo = findAppFunction(func.ChannelID, AppFunction::APP_NoMask);
+            if(pFuncThreadInfo != nullptr)
+            {
+                /* 更新时间信息 */
+                pFuncThreadInfo->StartTime = func.StartTime;
+                pFuncThreadInfo->EndTime = func.EndTime;
+                continue;
+            }
+            FuncThreadInfo* fa = new FuncThreadInfo;
+            fa->ChannelID = func.ChannelID;
+            fa->appFunction = AppFunction::APP_NoMask;
+            fa->strFunctionName = "未戴口罩识别";
+            fa->StartTime = func.StartTime;
+            fa->EndTime = func.EndTime;
+            listFuncThreadInfo.push_back(fa);
+        }
+        else if (func.AppType & 0x0100)
+        {
+            auto pFuncThreadInfo = findAppFunction(func.ChannelID, AppFunction::APP_AllDown);
+            if(pFuncThreadInfo != nullptr)
+            {
+                /* 更新时间信息 */
+                pFuncThreadInfo->StartTime = func.StartTime;
+                pFuncThreadInfo->EndTime = func.EndTime;
+                continue;
+            }
+            FuncThreadInfo* fa = new FuncThreadInfo;
+            fa->ChannelID = func.ChannelID;
+            fa->appFunction = AppFunction::APP_AllDown;
+            fa->strFunctionName = "摔倒识别";
+            fa->StartTime = func.StartTime;
+            fa->EndTime = func.EndTime;
+            listFuncThreadInfo.push_back(fa);
+        }
+    }
+
+
+    return true;
+}
+
+
+
+/**
+ * @brief 添加算法信息,根据传进来的算法ID,将其加入到对应的功能中
+ * 
+ * @param info 
+ * @return true 
+ * @return false 
+ */
+bool ListFuncActInfo::addActionInfo(const ActionInfo& info)
+{
+    if(info.ActionID.empty())
+    {
+        return false;
+    }
+    /* 人脸识别算法(人员在岗识别、非法入侵检测需要) */
+    if(info.ActionID == g_actionList.ActFace)
+    {
+        /* 人员在岗识别 */
+        auto pFuncThreadInfo = findAppFunction(info.ChannelID, AppFunction::APP_OnWork);
+        if(pFuncThreadInfo != nullptr)
+        {
+            pFuncThreadInfo->addActionInfo(info);
+        }
+        /* 非法入侵检测 */
+        pFuncThreadInfo = findAppFunction(info.ChannelID, AppFunction::APP_Illegal);
+        if(pFuncThreadInfo != nullptr)
+        {
+            pFuncThreadInfo->addActionInfo(info);
+        }
+    }
+    /* 人员计数 */
+    else if (info.ActionID == g_actionList.ActPersonNumber)
+    {
+        auto pFuncThreadInfo = findAppFunction(info.ChannelID, AppFunction::APP_Regional);
+        if(pFuncThreadInfo != nullptr)
+        {
+            pFuncThreadInfo->addActionInfo(info);
+        }
+    }
+    /* 违禁物品 */
+    else if (info.ActionID == g_actionList.ActContraband)
+    {
+        auto pFuncThreadInfo = findAppFunction(info.ChannelID, AppFunction::APP_Contraband);
+        if(pFuncThreadInfo != nullptr)
+        {
+            pFuncThreadInfo->addActionInfo(info);
+        }
+    }
+    /* 玩手机 */
+    else if (info.ActionID == g_actionList.ActPlayPhone)
+    {
+        auto pFuncThreadInfo = findAppFunction(info.ChannelID, AppFunction::APP_PlayPhone);
+        if(pFuncThreadInfo != nullptr)
+        {
+            pFuncThreadInfo->addActionInfo(info);
+        }
+    }
+    /* 睡岗识别 */
+    else if (info.ActionID == g_actionList.ActSleep)
+    {
+        auto pFuncThreadInfo = findAppFunction(info.ChannelID, AppFunction::APP_Fatigue);
+        if(pFuncThreadInfo != nullptr)
+        {
+            pFuncThreadInfo->addActionInfo(info);
+        }
+    }
+    /* 疲劳检测 */
+    else if(info.ActionID == g_actionList.ActFatigueDetection)
+    {
+        auto pFuncThreadInfo = findAppFunction(info.ChannelID, AppFunction::APP_Fatigue);
+        if(pFuncThreadInfo != nullptr)
+        {
+            pFuncThreadInfo->addActionInfo(info);
+        }
+    }
+    /* 动物识别 */
+    else if (info.ActionID == g_actionList.ActAnimalDetect)
+    {
+        auto pFuncThreadInfo = findAppFunction(info.ChannelID, AppFunction::APP_Mouse);
+        if(pFuncThreadInfo != nullptr)
+        {
+            pFuncThreadInfo->addActionInfo(info);
+        }
+    }
+    /* 老鼠识别 */
+    else if (info.ActionID == g_actionList.ActMouseDetect)
+    {
+        auto pFuncThreadInfo = findAppFunction(info.ChannelID, AppFunction::APP_Mouse);
+        if(pFuncThreadInfo != nullptr)
+        {
+            pFuncThreadInfo->addActionInfo(info);
+        }
+    }
+    /* 口罩识别 */
+    else if (info.ActionID == g_actionList.ActMask)
+    {
+        auto pFuncThreadInfo = findAppFunction(info.ChannelID, AppFunction::APP_NoMask);
+        if(pFuncThreadInfo != nullptr)
+        {
+            pFuncThreadInfo->addActionInfo(info);
+        }
+    }
+    else {
+        SPDLOG_WARN("未知的算法ID: {}", info.ActionID);
+        return false;
+    }
+
+    return true;
+}
+
+/**
+ * @brief 清空无用的功能信息
+ *          摄像机和算法信息为空的,或者运行状态为STOP,都会被清理掉
+ * 
+ */
+void ListFuncActInfo::clearNoneFuncThreadInfo()
+{
+    for(auto it0 = listFuncThreadInfo.begin(); it0 != listFuncThreadInfo.end();)
+    {
+        if((*it0)->listRoomCamActInfo.empty() || ((*it0)->RunState == RunTimeState::RUN_STATE_STOP))
+        {
+            delete *it0;
+            it0 = listFuncThreadInfo.erase(it0);
+        }else {
+            ++it0;
+        }
+    }
+}
+
+/* 清空算法列表 */
+void ListFuncActInfo::clearActionList()
+{
+    for(auto& it0 : listFuncThreadInfo)
+    {
+        it0->listRoomCamActInfo.clear();
+    }
+}
+
+/* 查找应用信息 */
+bool ListFuncActInfo::findAppFunction(const AppFunction func)
+{
+    for(const auto& it0 : listFuncThreadInfo)
+    {
+        if(it0->appFunction == func)
+        {
+            return true;
+        }
+    }
+    return false;
+}
+/* 根据频率和功能查找实例 */
+FuncThreadInfo* ListFuncActInfo::findAppFunction(const int ChannelID, const AppFunction func)
+{
+    for(const auto& it0 : listFuncThreadInfo)
+    {
+        if( (it0->appFunction == func) && (it0->ChannelID == ChannelID) )
+        {
+            return it0;
+        }
+    }
+    return nullptr;
+}
+
+/**
+ * @brief 查找这个应用信息
+ * 
+ * @param func 
+ * @return FuncThreadInfo* 
+ */
+FuncThreadInfo* ListFuncActInfo::findAppFunction(const FuncThreadInfo& func)
+{
+    for(const auto& it0 : listFuncThreadInfo)
+    {
+        if(it0->ChannelID == func.ChannelID && it0->appFunction == func.appFunction)
+        {
+            return it0;
+        }
+    }
+    return nullptr;
+}
+
+
+
+
+
+
+
+/* ====================================================================================
+ * ************************    GlobalThreadInfo成员函数    *****************************
+ * ====================================================================================*/
+
+/* 获取线程运行标志位 */
+bool GlobalThreadInfo::getRunning() const
+{
+    return m_bRunning;
+}
+
+/* 设置线程运行标志位 */
+void GlobalThreadInfo::setRunning(bool bRunning)
+{
+    m_bRunning = bRunning;
+}
+
+/* 手动给功能块列表加锁 */
+void GlobalThreadInfo::lockRunFAI()
+{
+    m_mutexRunFAI.lock();
+}
+
+/* 手动解锁 */
+void GlobalThreadInfo::unlockRunFAI()
+{
+    m_mutexRunFAI.unlock();
+}
+
+
+/**
+ * @brief 添加应用信息,一个应用功能在一个频道内只有一个实例
+ *        这里是添加应用功能和时间段信息
+ * 
+ * @param func 
+ * @return true 
+ * @return false 
+ */
+bool GlobalThreadInfo::addFuncThreadInfo(const AppAndTimeInfo& func)
+{
+    if(func.AppType == 0)
+    {
+        return false;
+    }
+    /* 解出这条信息里包含几个App,AppType按位计算,总共8个应用信息 */
+    for(int i = 0; i < 8; ++i)
+    {
+        if(func.AppType & 0x01)
+        {
+            /* 查找有没有这个应用 */
+            auto pFuncThreadInfo = findAppFunction(func.ChannelID, AppFunction::APP_OnWork);
+            if(pFuncThreadInfo != nullptr)
+            {
+                /* 更新时间信息 */
+                pFuncThreadInfo->StartTime = func.StartTime;
+                pFuncThreadInfo->EndTime = func.EndTime;
+                continue;
+            }
+            FuncThreadInfo* fa = new FuncThreadInfo;
+            fa->ChannelID = func.ChannelID;
+            fa->appFunction = AppFunction::APP_OnWork;
+            fa->strFunctionName = "人员在岗识别";
+            fa->StartTime = func.StartTime;
+            fa->EndTime = func.EndTime;
+            m_listFuncThreadInfo.push_back(fa);
+        }
+        else if(func.AppType & 0x02)
+        {
+            auto pFuncThreadInfo = findAppFunction(func.ChannelID, AppFunction::APP_Contraband);
+            if(pFuncThreadInfo != nullptr)
+            {
+                /* 更新时间信息 */
+                pFuncThreadInfo->StartTime = func.StartTime;
+                pFuncThreadInfo->EndTime = func.EndTime;
+                continue;
+            }
+            FuncThreadInfo* fa = new FuncThreadInfo;
+            fa->ChannelID = func.ChannelID;
+            fa->appFunction = AppFunction::APP_Contraband;
+            fa->strFunctionName = "违禁品识别";
+            fa->StartTime = func.StartTime;
+            fa->EndTime = func.EndTime;
+            m_listFuncThreadInfo.push_back(fa);
+        }
+        else if (func.AppType & 0x04)
+        {
+            auto pFuncThreadInfo = findAppFunction(func.ChannelID, AppFunction::APP_Illegal);
+            if(pFuncThreadInfo != nullptr)
+            {
+                /* 更新时间信息 */
+                pFuncThreadInfo->StartTime = func.StartTime;
+                pFuncThreadInfo->EndTime = func.EndTime;
+                continue;
+            }
+            FuncThreadInfo* fa = new FuncThreadInfo;
+            fa->ChannelID = func.ChannelID;
+            fa->appFunction = AppFunction::APP_Illegal;
+            fa->strFunctionName = "非法入侵检测";
+            fa->StartTime = func.StartTime;
+            fa->EndTime = func.EndTime;
+            m_listFuncThreadInfo.push_back(fa);
+        }
+        else if (func.AppType & 0x08)
+        {
+            auto pFuncThreadInfo = findAppFunction(func.ChannelID, AppFunction::APP_Fatigue);
+            if(pFuncThreadInfo != nullptr)
+            {
+                /* 更新时间信息 */
+                pFuncThreadInfo->StartTime = func.StartTime;
+                pFuncThreadInfo->EndTime = func.EndTime;
+                continue;
+            }
+            FuncThreadInfo* fa = new FuncThreadInfo;
+            fa->ChannelID = func.ChannelID;
+            fa->appFunction = AppFunction::APP_Fatigue;
+            fa->strFunctionName = "疲劳检测";
+            fa->StartTime = func.StartTime;
+            fa->EndTime = func.EndTime;
+            m_listFuncThreadInfo.push_back(fa);
+        }
+        else if (func.AppType & 0x10)
+        {
+            auto pFuncThreadInfo = findAppFunction(func.ChannelID, AppFunction::APP_Regional);
+            if(pFuncThreadInfo != nullptr)
+            {
+                /* 更新时间信息 */
+                pFuncThreadInfo->StartTime = func.StartTime;
+                pFuncThreadInfo->EndTime = func.EndTime;
+                continue;
+            }
+            FuncThreadInfo* fa = new FuncThreadInfo;
+            fa->ChannelID = func.ChannelID;
+            fa->appFunction = AppFunction::APP_Regional;
+            fa->strFunctionName = "区域人员检测";
+            fa->StartTime = func.StartTime;
+            fa->EndTime = func.EndTime;
+            m_listFuncThreadInfo.push_back(fa);
+        }
+        else if (func.AppType & 0x20)
+        {
+            auto pFuncThreadInfo = findAppFunction(func.ChannelID, AppFunction::APP_Mouse);
+            if(pFuncThreadInfo != nullptr)
+            {
+                /* 更新时间信息 */
+                pFuncThreadInfo->StartTime = func.StartTime;
+                pFuncThreadInfo->EndTime = func.EndTime;
+                continue;
+            }
+            FuncThreadInfo* fa = new FuncThreadInfo;
+            fa->ChannelID = func.ChannelID;
+            fa->appFunction = AppFunction::APP_Mouse;
+            fa->strFunctionName = "老鼠识别";
+            fa->StartTime = func.StartTime;
+            fa->EndTime = func.EndTime;
+            m_listFuncThreadInfo.push_back(fa);
+        }
+        else if (func.AppType & 0x40)
+        {
+            auto pFuncThreadInfo = findAppFunction(func.ChannelID, AppFunction::APP_PlayPhone);
+            if(pFuncThreadInfo != nullptr)
+            {
+                /* 更新时间信息 */
+                pFuncThreadInfo->StartTime = func.StartTime;
+                pFuncThreadInfo->EndTime = func.EndTime;
+                continue;
+            }
+            FuncThreadInfo* fa = new FuncThreadInfo;
+            fa->ChannelID = func.ChannelID;
+            fa->appFunction = AppFunction::APP_PlayPhone;
+            fa->strFunctionName = "玩手机识别";
+            fa->StartTime = func.StartTime;
+            fa->EndTime = func.EndTime;
+            m_listFuncThreadInfo.push_back(fa);
+        }
+        else if (func.AppType & 0x80)
+        {
+            auto pFuncThreadInfo = findAppFunction(func.ChannelID, AppFunction::APP_NoMask);
+            if(pFuncThreadInfo != nullptr)
+            {
+                /* 更新时间信息 */
+                pFuncThreadInfo->StartTime = func.StartTime;
+                pFuncThreadInfo->EndTime = func.EndTime;
+                continue;
+            }
+            FuncThreadInfo* fa = new FuncThreadInfo;
+            fa->ChannelID = func.ChannelID;
+            fa->appFunction = AppFunction::APP_NoMask;
+            fa->strFunctionName = "未戴口罩识别";
+            fa->StartTime = func.StartTime;
+            fa->EndTime = func.EndTime;
+            m_listFuncThreadInfo.push_back(fa);
+        }
+        else if (func.AppType & 0x0100)
+        {
+            auto pFuncThreadInfo = findAppFunction(func.ChannelID, AppFunction::APP_AllDown);
+            if(pFuncThreadInfo != nullptr)
+            {
+                /* 更新时间信息 */
+                pFuncThreadInfo->StartTime = func.StartTime;
+                pFuncThreadInfo->EndTime = func.EndTime;
+                continue;
+            }
+            FuncThreadInfo* fa = new FuncThreadInfo;
+            fa->ChannelID = func.ChannelID;
+            fa->appFunction = AppFunction::APP_AllDown;
+            fa->strFunctionName = "摔倒识别";
+            fa->StartTime = func.StartTime;
+            fa->EndTime = func.EndTime;
+            m_listFuncThreadInfo.push_back(fa);
+        }
+    }
+
+
+    return true;
+}
+
+
+
+/**
+ * @brief 添加算法信息,根据传进来的算法ID,将其加入到对应的功能中
+ *        根据功能需要,将算法ID加入到对应的功能中
+ * 
+ * @param info 
+ * @return true 
+ * @return false 
+ */
+bool GlobalThreadInfo::addActionInfo(const ActionInfo& info)
+{
+    if(info.ActionID.empty())
+    {
+        return false;
+    }
+    /* 人脸识别算法(人员在岗识别、非法入侵检测需要) */
+    if(info.ActionID == g_actionList.ActFace)
+    {
+        /* 人员在岗识别 */
+        auto pFuncThreadInfo = findAppFunction(info.ChannelID, AppFunction::APP_OnWork);
+        if(pFuncThreadInfo != nullptr)
+        {
+            pFuncThreadInfo->addActionInfo(info);
+        }
+        /* 非法入侵检测 */
+        pFuncThreadInfo = findAppFunction(info.ChannelID, AppFunction::APP_Illegal);
+        if(pFuncThreadInfo != nullptr)
+        {
+            pFuncThreadInfo->addActionInfo(info);
+        }
+    }
+    /* 人员计数 */
+    else if (info.ActionID == g_actionList.ActPersonNumber)
+    {
+        /* 区域人员检测(人员计数?) */
+        auto pFuncThreadInfo = findAppFunction(info.ChannelID, AppFunction::APP_Regional);
+        if(pFuncThreadInfo != nullptr)
+        {
+            pFuncThreadInfo->addActionInfo(info);
+        }
+        /* 非法入侵检测 */
+        pFuncThreadInfo = findAppFunction(info.ChannelID, AppFunction::APP_Illegal);
+        if(pFuncThreadInfo != nullptr)
+        {
+            pFuncThreadInfo->addActionInfo(info);
+        }
+        /* 人员在岗识别 */
+        pFuncThreadInfo = findAppFunction(info.ChannelID, AppFunction::APP_OnWork);
+        if(pFuncThreadInfo != nullptr)
+        {
+            pFuncThreadInfo->addActionInfo(info);
+        }
+    }
+    /* 违禁物品 */
+    else if (info.ActionID == g_actionList.ActContraband)
+    {
+        auto pFuncThreadInfo = findAppFunction(info.ChannelID, AppFunction::APP_Contraband);
+        if(pFuncThreadInfo != nullptr)
+        {
+            pFuncThreadInfo->addActionInfo(info);
+        }
+    }
+    /* 玩手机 */
+    else if (info.ActionID == g_actionList.ActPlayPhone)
+    {
+        auto pFuncThreadInfo = findAppFunction(info.ChannelID, AppFunction::APP_PlayPhone);
+        if(pFuncThreadInfo != nullptr)
+        {
+            pFuncThreadInfo->addActionInfo(info);
+        }
+    }
+    /* 睡岗识别 */
+    else if (info.ActionID == g_actionList.ActSleep)
+    {
+        auto pFuncThreadInfo = findAppFunction(info.ChannelID, AppFunction::APP_Fatigue);
+        if(pFuncThreadInfo != nullptr)
+        {
+            pFuncThreadInfo->addActionInfo(info);
+        }
+    }
+    /* 疲劳检测 */
+    else if(info.ActionID == g_actionList.ActFatigueDetection)
+    {
+        auto pFuncThreadInfo = findAppFunction(info.ChannelID, AppFunction::APP_Fatigue);
+        if(pFuncThreadInfo != nullptr)
+        {
+            pFuncThreadInfo->addActionInfo(info);
+        }
+    }
+    /* 动物识别 */
+    else if (info.ActionID == g_actionList.ActAnimalDetect)
+    {
+        auto pFuncThreadInfo = findAppFunction(info.ChannelID, AppFunction::APP_Mouse);
+        if(pFuncThreadInfo != nullptr)
+        {
+            pFuncThreadInfo->addActionInfo(info);
+        }
+    }
+    /* 老鼠识别 */
+    else if (info.ActionID == g_actionList.ActMouseDetect)
+    {
+        auto pFuncThreadInfo = findAppFunction(info.ChannelID, AppFunction::APP_Mouse);
+        if(pFuncThreadInfo != nullptr)
+        {
+            pFuncThreadInfo->addActionInfo(info);
+        }
+    }
+    /* 口罩识别 */
+    else if (info.ActionID == g_actionList.ActMask)
+    {
+        auto pFuncThreadInfo = findAppFunction(info.ChannelID, AppFunction::APP_NoMask);
+        if(pFuncThreadInfo != nullptr)
+        {
+            pFuncThreadInfo->addActionInfo(info);
+        }
+    }
+    else {
+        SPDLOG_WARN("未知的算法ID: {}", info.ActionID);
+        return false;
+    }
+
+    return true;
+}
+
+/**
+ * @brief 清空无用的功能信息
+ *          摄像机和算法信息为空的,或者运行状态为RUN_STATE_EXITCOMPLET,都会被清理掉
+ * 
+ */
+void GlobalThreadInfo::clearNoneFuncThreadInfo()
+{
+    for(auto it0 = m_listFuncThreadInfo.begin(); it0 != m_listFuncThreadInfo.end();)
+    {
+        if((*it0)->listRoomCamActInfo.empty() || ((*it0)->RunState == RunTimeState::RUN_STATE_EXITCOMPLET))
+        {
+            delete *it0;
+            it0 = m_listFuncThreadInfo.erase(it0);
+        }else {
+            ++it0;
+        }
+    }
+}
+
+/* 清空算法列表(直接清空房间信息) */
+void GlobalThreadInfo::clearActionList()
+{
+    for(auto& it0 : m_listFuncThreadInfo)
+    {
+        // for(auto& it1 : it0->listRoomCamActInfo)
+        // {
+        //     it1.mapCameraAction.clear();
+        // }
+        it0->listRoomCamActInfo.clear();
+    }
+}
+
+/* 设置没有配置摄像机的功能退出 */
+void GlobalThreadInfo::setNoneCameraFuncStop()
+{
+    for(auto& it : m_listFuncThreadInfo)
+    {
+        if(it->listRoomCamActInfo.empty())
+        {
+            it->RunState = RunTimeState::RUN_STATE_STOP;
+            SPDLOG_INFO("《{}》房间信息为空,退出检测", it->strFunctionName);
+        }
+    }
+}
+
+/* 查找应用信息 */
+bool GlobalThreadInfo::findAppFunction(const AppFunction func)
+{
+    for(const auto& it0 : m_listFuncThreadInfo)
+    {
+        if(it0->appFunction == func)
+        {
+            return true;
+        }
+    }
+    return false;
+}
+
+/* 根据频率和功能查找实例 */
+FuncThreadInfo* GlobalThreadInfo::findAppFunction(const int ChannelID, const AppFunction func)
+{
+    for(const auto& it0 : m_listFuncThreadInfo)
+    {
+        if( (it0->appFunction == func) && (it0->ChannelID == ChannelID) )
+        {
+            return it0;
+        }
+    }
+    return nullptr;
+}
+
+/**
+ * @brief 查找这个应用信息
+ * 
+ * @param func 
+ * @return FuncThreadInfo* 
+ */
+FuncThreadInfo* GlobalThreadInfo::findAppFunction(const FuncThreadInfo& func)
+{
+    for(const auto& it0 : m_listFuncThreadInfo)
+    {
+        if(it0->ChannelID == func.ChannelID && it0->appFunction == func.appFunction)
+        {
+            return it0;
+        }
+    }
+    return nullptr;
+}
+
+/* 设置线程状态 */
+void GlobalThreadInfo::setThreadState(FuncThreadInfo* pInfo, RunTimeState state)
+{
+    std::lock_guard<std::mutex> look(m_mutexRunFAI);
+    auto p = findAppFunction(*pInfo);
+    if(p != nullptr)
+    {
+        p->RunState = state;
+    }
+}
+
+void GlobalThreadInfo::setThreadState(FuncThreadInfo& pInfo, RunTimeState state)
+{
+    std::lock_guard<std::mutex> look(m_mutexRunFAI);
+    auto p = findAppFunction(pInfo);
+    if(p != nullptr)
+    {
+        p->RunState = state;
+    }
+}
+
+/**
+ * @brief 功能线程更新功能信息,这里是从内存中的数组里获取
+ * 
+ * @param pInfo 
+ * @return true 
+ * @return false 
+ */
+ bool GlobalThreadInfo::updateFuncInfo(FuncThreadInfo* pInfo)
+{
+    pInfo->clearActionList();
+    std::lock_guard<std::mutex> look(m_mutexRunFAI);
+    auto fa = findAppFunction(*pInfo);
+    if(fa == nullptr)
+    {
+        return false;
+    }
+    *pInfo = *fa;
+
+    return true;
+}
+bool GlobalThreadInfo::updateFuncInfo(FuncThreadInfo& pInfo)
+{
+    pInfo.clearActionList();
+    std::lock_guard<std::mutex> look(m_mutexRunFAI);
+    auto fa = findAppFunction(pInfo);
+    if(fa == nullptr)
+    {
+        return false;
+    }
+    pInfo = *fa;
+
+    return true;
+}
+
+
+/* 更新频率信息 */
+// void GlobalThreadInfo::setChannelInfo(std::map<int, std::string> mapChannelName)
+// {
+    
+// }
+
+/* 设置摄像机信息 */
+void GlobalThreadInfo::setCameraInfo(std::map<int, std::string> mapCameraName)
+{
+    for(auto& it : m_listFuncThreadInfo)
+    {
+        it->mapCameraName.clear();
+        it->mapCameraName = mapCameraName;
+    }
+}
+

+ 141 - 0
SecurePlayAuxServer/GlobalInfo/GlobalFuncThread.h

@@ -0,0 +1,141 @@
+#ifndef GLOBALFUNCTHREAD_H
+#define GLOBALFUNCTHREAD_H
+
+
+#include "GlobalVariable.h"
+
+/**
+ * @brief 按照功能分类的线程信息,一个实例就是一个功能,
+            比如区域入侵检测,需要多个算法多个摄像机共同配合
+ * 
+ */
+ struct FuncThreadInfo
+ {
+    int ChannelID;                  /* 频率ID */
+    std::string strChannelName;     /* 频率名称 */
+    AppFunction appFunction;        /* 任务功能 */
+    RunTimeState RunState;          /* 线程运行状态 */
+    std::string strFunctionName;    /* 功能名称 */
+    QDateTime StartTime;            /* 开始时间 */
+    QDateTime EndTime;              /* 结束时间 */
+    std::list<RoomCamActInfo> listRoomCamActInfo;       /* 房间内的摄像机和算法关联信息 */
+
+    std::map<int, std::string> mapCameraName;        /* 摄像机名称 */
+
+    FuncThreadInfo();
+    ~FuncThreadInfo();
+    FuncThreadInfo& operator=(FuncThreadInfo& other);
+    /* 添加算法信息 */
+    bool addActionInfo(const ActionInfo& info);
+    /* 清空算法信息 */
+    void clearActionList();
+
+    /* 获取摄像机名称 */
+    std::string getCameraName(int CameraID);
+
+ };
+
+/**
+ * @brief 线程功能块
+ * 
+ */
+ struct ListFuncActInfo
+ {
+    ListFuncActInfo() = default;
+
+    /* 添加功能信息 */
+    bool addFuncThreadInfo(const AppAndTimeInfo& func);
+    /* 添加算法信息 */
+    bool addActionInfo(const ActionInfo& info);
+    /* 清空无用的功能信息 */
+    void clearNoneFuncThreadInfo();
+    /* 清空房间和算法列表 */
+    void clearActionList();
+
+    /* 获取容器 */
+    std::list<FuncThreadInfo*>& getData() {
+        return listFuncThreadInfo;
+    }
+    /* 查找应用信息 */
+    bool findAppFunction(const AppFunction func);
+    FuncThreadInfo* findAppFunction(const int ChannelID, const AppFunction func);
+    FuncThreadInfo* findAppFunction(const FuncThreadInfo& func);
+
+    std::list<FuncThreadInfo*> listFuncThreadInfo;    /* 功能信息列表 */
+ };
+
+
+/* ====================================================================================
+ * ************************    GlobalThreadInfo成员函数    ****************************
+ * ====================================================================================*/
+
+#define GThreadInfo GlobalThreadInfo::getInstance()
+/**
+ * @brief 线程信息,也是应用功能块列表,每个频率下的每个功能就是一个线程
+ * 
+ */
+class GlobalThreadInfo
+{
+    GlobalThreadInfo() {}
+    ~GlobalThreadInfo() {}
+    GlobalThreadInfo(const GlobalThreadInfo& other) = delete;
+    GlobalThreadInfo& operator=(const GlobalThreadInfo& other) = delete;
+public:
+    static GlobalThreadInfo& getInstance()
+    {
+        static GlobalThreadInfo instance;
+        return instance;
+    }
+    /* 获取线程运行标志位 */
+    bool getRunning() const;
+    /* 设置线程运行标志位 */
+    void setRunning(bool bRunning);
+    
+    /* 手动给功能块列表加锁 */
+    void lockRunFAI();
+    /* 手动解锁 */
+    void unlockRunFAI();
+    /* 添加功能信息 */
+    bool addFuncThreadInfo(const AppAndTimeInfo& func);
+    /* 添加算法信息 */
+    bool addActionInfo(const ActionInfo& info);
+    /* 清空无用的功能信息 */
+    void clearNoneFuncThreadInfo();
+    /* 清空房间和算法列表 */
+    void clearActionList();
+    /* 设置没有配置摄像机的功能退出 */
+    void setNoneCameraFuncStop();
+
+    /* 获取容器 */
+    std::list<FuncThreadInfo*>& getList() {
+        return m_listFuncThreadInfo;
+    }
+    /* 查找应用信息 */
+    bool findAppFunction(const AppFunction func);
+    FuncThreadInfo* findAppFunction(const int ChannelID, const AppFunction func);
+    FuncThreadInfo* findAppFunction(const FuncThreadInfo& func);
+
+    /* 设置线程状态 */
+    void setThreadState(FuncThreadInfo* pInfo, RunTimeState state);
+    void setThreadState(FuncThreadInfo& pInfo, RunTimeState state);
+    /* 更新算法的摄像机ID */
+    bool updateFuncInfo(FuncThreadInfo* pInfo);
+    bool updateFuncInfo(FuncThreadInfo& pInfo);
+
+    /* 更新频率信息 */
+    // void setChannelInfo(std::map<int, std::string> mapChannelName);
+    /* 设置摄像机信息 */
+    void setCameraInfo(std::map<int, std::string> mapCameraName);
+
+private:
+    std::atomic_bool m_bRunning;    /* 线程运行状态 */
+
+    /* 运行时应用线程功能相关信息 */
+    std::mutex m_mutexRunFAI;
+    std::list<FuncThreadInfo*> m_listFuncThreadInfo;    /* 功能信息列表 */
+
+    
+};
+
+
+#endif // GLOBALFUNCTHREAD_H

+ 51 - 450
SecurePlayAuxServer/GlobalInfo/GlobalVariable.cpp

@@ -2,7 +2,7 @@
 
 #include "spdlog/spdlog.h"
 
-#include "FuncBase.h"
+// #include "FuncBase.h"
 
 /* ====================================================================================
  * *******************************    全局变量定义    **********************************
@@ -76,6 +76,7 @@ AlarmInfo::AlarmInfo()
 {
     Is_Alarm = false;
     Is_InsertEQM = false;
+    Is_OnWork = false;
     AlarmID = 0;
     DeviceID = 0;
     RoomID = 0;
@@ -93,6 +94,7 @@ AlarmInfo::AlarmInfo()
     FaceIDList = "";
     FaceNameList = "";
     listBbox.clear();
+    listPersonInfo.clear();
     appFunction = AppFunction::APP_NONE;
 }
 
@@ -101,6 +103,7 @@ AlarmInfo::AlarmInfo(const AlarmInfo& other)
 {
     Is_Alarm = other.Is_Alarm;
     Is_InsertEQM = other.Is_InsertEQM;
+    Is_OnWork = other.Is_OnWork;
     AlarmID = other.AlarmID;
     DeviceID = other.DeviceID;
     RoomID = other.RoomID;
@@ -118,7 +121,7 @@ AlarmInfo::AlarmInfo(const AlarmInfo& other)
     FaceIDList = other.FaceIDList;
     FaceNameList = other.FaceNameList;
     listBbox = other.listBbox;
-    vecPersonInfo = other.vecPersonInfo;
+    listPersonInfo = other.listPersonInfo;
     appFunction = other.appFunction;
 }
 
@@ -128,6 +131,7 @@ AlarmInfo& AlarmInfo::operator=(AlarmInfo& other)
     {
         Is_Alarm = other.Is_Alarm;
         Is_InsertEQM = other.Is_InsertEQM;
+        Is_OnWork = other.Is_OnWork;
         AlarmID = other.AlarmID;
         DeviceID = other.DeviceID;
         RoomID = other.RoomID;
@@ -145,7 +149,7 @@ AlarmInfo& AlarmInfo::operator=(AlarmInfo& other)
         FaceIDList = other.FaceIDList;
         FaceNameList = other.FaceNameList;
         listBbox = other.listBbox;
-        vecPersonInfo = other.vecPersonInfo;
+        listPersonInfo = other.listPersonInfo;
         appFunction = other.appFunction;
     }
     return *this;
@@ -155,6 +159,8 @@ AlarmInfo& AlarmInfo::operator=(AlarmInfo& other)
 void AlarmInfo::reInit()
 {
     Is_Alarm = false;
+    Is_InsertEQM = false;
+    Is_OnWork = false;
     AlarmID = 0;
     DeviceID = 0;
     RoomID = 0;
@@ -172,9 +178,50 @@ void AlarmInfo::reInit()
     FaceIDList = "";
     FaceNameList = "";
     listBbox.clear();
+    listPersonInfo.clear();
     appFunction = AppFunction::APP_NONE;
 }
 
+/* 获取人脸列表 */
+std::string AlarmInfo::getFaceIDListString()
+{
+    std::string strFaceList = "";
+    for(auto& it : listPersonInfo)
+    {
+        if(it.PersonID.size() < 0)
+        {
+            continue;
+        }
+        strFaceList += it.PersonID + ";" ;
+    }
+    /* 去掉最后的“;” */
+    if(strFaceList.size() > 0)
+    {
+        strFaceList = strFaceList.substr(0, strFaceList.size() - 1);
+    }
+    return strFaceList;
+}
+
+/* 获取人脸名称列表 */
+std::string AlarmInfo::getFaceNameListString()
+{
+    std::string strFaceName;
+    for(auto& it : listPersonInfo)
+    {
+        if(it.PersonName.size() < 0)
+        {
+            continue;
+        }
+        strFaceName += it.PersonName + ";";
+    }
+    /* 去掉最后的“;” */
+    if(strFaceName.size() > 0)
+    {
+        strFaceName = strFaceName.substr(0, strFaceName.size() - 1);
+    }
+    return strFaceName;
+}
+
 /**
  * @brief 添加报警信息
  * 
@@ -275,7 +322,7 @@ void ListRoomFaceInfo::addRoomFaceInfo(AlarmInfo& info)
         listRoomFaceInfo.push_back(rfi);
     }
     /* 将人员信息加入到列表中,添加时会先查找有没有相同的信息 */
-    for(auto& it0 : info.vecPersonInfo)
+    for(auto& it0 : info.listPersonInfo)
     {
         if(!p->findPersonInfo(it0))
         {
@@ -675,449 +722,3 @@ RoomActionInfo* ListRoomActionInfo::findActionIDInList(const int chnID, const in
     return nullptr;
 }
 
-FuncActionInfo::FuncActionInfo() 
-{
-    ChannelID = -1;
-    appFunction = AppFunction::APP_NONE;
-    RunState = RunTimeState::RUN_STATE_NONE;
-    strFunctionName = "";
-    StartTime = QDateTime::currentDateTime();
-    EndTime = QDateTime::currentDateTime();
-    listRoomCamActInfo.clear();
-}
-
-FuncActionInfo::~FuncActionInfo()
-{
-    
-}
-
-
-FuncActionInfo& FuncActionInfo::operator=(FuncActionInfo& other)
-{
-    if(this != &other)
-    {
-        ChannelID = other.ChannelID;
-        appFunction = other.appFunction;
-        RunState = other.RunState;
-        strFunctionName = other.strFunctionName;
-        StartTime = other.StartTime;
-        EndTime = other.EndTime;
-        listRoomCamActInfo = other.listRoomCamActInfo;
-    }
-    return *this;
-}
-
-/**
- * @brief 添加算法信息,这里不能直接创建房间,需要先判断有没有已有的房间,因为有的应用功能可能会包含多个房间
- *        已经提前被创建过了
- * 
- * @param info 
- * @return true 
- * @return false 
- */
-bool FuncActionInfo::addActionInfo(const ActionInfo& info)
-{
-    /* 根据此类的功能,添加算法信息 */
-    if(appFunction == AppFunction::APP_NONE)
-    {
-        return false;
-    }
-    /* 将其添加到对应的房间 */
-    bool isFind = false;
-    for(auto& it0 : listRoomCamActInfo)
-    {
-        if((it0.RoomID == info.RoomID) && (it0.RoomType == info.RoomType))
-        {
-            isFind = true;
-            it0.mapCameraAction.insert(std::make_pair(info.CameraID, info.ActionID));
-            break;
-        }
-    }
-    /* 没找到这个房间,就创建 */
-    if(!isFind)
-    {
-        RoomCamActInfo roomCamActInfo;
-        roomCamActInfo.RoomID = info.RoomID;
-        roomCamActInfo.RoomType = info.RoomType;
-        roomCamActInfo.mapCameraAction.insert(std::make_pair(info.CameraID, info.ActionID));
-        listRoomCamActInfo.push_back(roomCamActInfo);
-    }
-
-
-    return true;
-}
-
-/* 清空算法信息 */
-void FuncActionInfo::clearActionList()
-{
-    listRoomCamActInfo.clear();
-}
-
-/**
- * @brief 添加应用信息,一个应用功能在一个频道内只有一个实例
- *        这里是添加应用功能和时间段信息
- * 
- * @param func 
- * @return true 
- * @return false 
- */
-bool ListFuncActInfo::addFuncActionInfo(const AppAndTimeInfo& func)
-{
-    if(func.AppType == 0)
-    {
-        return false;
-    }
-    /* 解出这条信息里包含几个App,AppType按位计算,总共8个应用信息 */
-    for(int i = 0; i < 8; ++i)
-    {
-        if(func.AppType & 0x01)
-        {
-            /* 查找有没有这个应用 */
-            auto pFuncActionInfo = findAppFunction(func.ChannelID, AppFunction::APP_OnWork);
-            if(pFuncActionInfo != nullptr)
-            {
-                /* 更新时间信息 */
-                pFuncActionInfo->StartTime = func.StartTime;
-                pFuncActionInfo->EndTime = func.EndTime;
-                continue;
-            }
-            FuncActionInfo* fa = new FuncActionInfo;
-            fa->ChannelID = func.ChannelID;
-            fa->appFunction = AppFunction::APP_OnWork;
-            fa->strFunctionName = "人员在岗识别";
-            fa->StartTime = func.StartTime;
-            fa->EndTime = func.EndTime;
-            listFuncActionInfo.push_back(fa);
-        }
-        else if(func.AppType & 0x02)
-        {
-            auto pFuncActionInfo = findAppFunction(func.ChannelID, AppFunction::APP_Contraband);
-            if(pFuncActionInfo != nullptr)
-            {
-                /* 更新时间信息 */
-                pFuncActionInfo->StartTime = func.StartTime;
-                pFuncActionInfo->EndTime = func.EndTime;
-                continue;
-            }
-            FuncActionInfo* fa = new FuncActionInfo;
-            fa->ChannelID = func.ChannelID;
-            fa->appFunction = AppFunction::APP_Contraband;
-            fa->strFunctionName = "违禁品识别";
-            fa->StartTime = func.StartTime;
-            fa->EndTime = func.EndTime;
-            listFuncActionInfo.push_back(fa);
-        }
-        else if (func.AppType & 0x04)
-        {
-            auto pFuncActionInfo = findAppFunction(func.ChannelID, AppFunction::APP_Illegal);
-            if(pFuncActionInfo != nullptr)
-            {
-                /* 更新时间信息 */
-                pFuncActionInfo->StartTime = func.StartTime;
-                pFuncActionInfo->EndTime = func.EndTime;
-                continue;
-            }
-            FuncActionInfo* fa = new FuncActionInfo;
-            fa->ChannelID = func.ChannelID;
-            fa->appFunction = AppFunction::APP_Illegal;
-            fa->strFunctionName = "非法入侵检测";
-            fa->StartTime = func.StartTime;
-            fa->EndTime = func.EndTime;
-            listFuncActionInfo.push_back(fa);
-        }
-        else if (func.AppType & 0x08)
-        {
-            auto pFuncActionInfo = findAppFunction(func.ChannelID, AppFunction::APP_Fatigue);
-            if(pFuncActionInfo != nullptr)
-            {
-                /* 更新时间信息 */
-                pFuncActionInfo->StartTime = func.StartTime;
-                pFuncActionInfo->EndTime = func.EndTime;
-                continue;
-            }
-            FuncActionInfo* fa = new FuncActionInfo;
-            fa->ChannelID = func.ChannelID;
-            fa->appFunction = AppFunction::APP_Fatigue;
-            fa->strFunctionName = "疲劳检测";
-            fa->StartTime = func.StartTime;
-            fa->EndTime = func.EndTime;
-            listFuncActionInfo.push_back(fa);
-        }
-        else if (func.AppType & 0x10)
-        {
-            auto pFuncActionInfo = findAppFunction(func.ChannelID, AppFunction::APP_Regional);
-            if(pFuncActionInfo != nullptr)
-            {
-                /* 更新时间信息 */
-                pFuncActionInfo->StartTime = func.StartTime;
-                pFuncActionInfo->EndTime = func.EndTime;
-                continue;
-            }
-            FuncActionInfo* fa = new FuncActionInfo;
-            fa->ChannelID = func.ChannelID;
-            fa->appFunction = AppFunction::APP_Regional;
-            fa->strFunctionName = "区域人员检测";
-            fa->StartTime = func.StartTime;
-            fa->EndTime = func.EndTime;
-            listFuncActionInfo.push_back(fa);
-        }
-        else if (func.AppType & 0x20)
-        {
-            auto pFuncActionInfo = findAppFunction(func.ChannelID, AppFunction::APP_Mouse);
-            if(pFuncActionInfo != nullptr)
-            {
-                /* 更新时间信息 */
-                pFuncActionInfo->StartTime = func.StartTime;
-                pFuncActionInfo->EndTime = func.EndTime;
-                continue;
-            }
-            FuncActionInfo* fa = new FuncActionInfo;
-            fa->ChannelID = func.ChannelID;
-            fa->appFunction = AppFunction::APP_Mouse;
-            fa->strFunctionName = "老鼠识别";
-            fa->StartTime = func.StartTime;
-            fa->EndTime = func.EndTime;
-            listFuncActionInfo.push_back(fa);
-        }
-        else if (func.AppType & 0x40)
-        {
-            auto pFuncActionInfo = findAppFunction(func.ChannelID, AppFunction::APP_PlayPhone);
-            if(pFuncActionInfo != nullptr)
-            {
-                /* 更新时间信息 */
-                pFuncActionInfo->StartTime = func.StartTime;
-                pFuncActionInfo->EndTime = func.EndTime;
-                continue;
-            }
-            FuncActionInfo* fa = new FuncActionInfo;
-            fa->ChannelID = func.ChannelID;
-            fa->appFunction = AppFunction::APP_PlayPhone;
-            fa->strFunctionName = "玩手机识别";
-            fa->StartTime = func.StartTime;
-            fa->EndTime = func.EndTime;
-            listFuncActionInfo.push_back(fa);
-        }
-        else if (func.AppType & 0x80)
-        {
-            auto pFuncActionInfo = findAppFunction(func.ChannelID, AppFunction::APP_NoMask);
-            if(pFuncActionInfo != nullptr)
-            {
-                /* 更新时间信息 */
-                pFuncActionInfo->StartTime = func.StartTime;
-                pFuncActionInfo->EndTime = func.EndTime;
-                continue;
-            }
-            FuncActionInfo* fa = new FuncActionInfo;
-            fa->ChannelID = func.ChannelID;
-            fa->appFunction = AppFunction::APP_NoMask;
-            fa->strFunctionName = "未戴口罩识别";
-            fa->StartTime = func.StartTime;
-            fa->EndTime = func.EndTime;
-            listFuncActionInfo.push_back(fa);
-        }
-        else if (func.AppType & 0x0100)
-        {
-            auto pFuncActionInfo = findAppFunction(func.ChannelID, AppFunction::APP_AllDown);
-            if(pFuncActionInfo != nullptr)
-            {
-                /* 更新时间信息 */
-                pFuncActionInfo->StartTime = func.StartTime;
-                pFuncActionInfo->EndTime = func.EndTime;
-                continue;
-            }
-            FuncActionInfo* fa = new FuncActionInfo;
-            fa->ChannelID = func.ChannelID;
-            fa->appFunction = AppFunction::APP_AllDown;
-            fa->strFunctionName = "摔倒识别";
-            fa->StartTime = func.StartTime;
-            fa->EndTime = func.EndTime;
-            listFuncActionInfo.push_back(fa);
-        }
-    }
-
-
-    return true;
-}
-
-
-
-/**
- * @brief 添加算法信息,根据传进来的算法ID,将其加入到对应的功能中
- * 
- * @param info 
- * @return true 
- * @return false 
- */
-bool ListFuncActInfo::addActionInfo(const ActionInfo& info)
-{
-    if(info.ActionID.empty())
-    {
-        return false;
-    }
-    /* 人脸识别算法(人员在岗识别、非法入侵检测需要) */
-    if(info.ActionID == g_actionList.ActFace)
-    {
-        /* 人员在岗识别 */
-        auto pFuncActionInfo = findAppFunction(info.ChannelID, AppFunction::APP_OnWork);
-        if(pFuncActionInfo != nullptr)
-        {
-            pFuncActionInfo->addActionInfo(info);
-        }
-        /* 非法入侵检测 */
-        pFuncActionInfo = findAppFunction(info.ChannelID, AppFunction::APP_Illegal);
-        if(pFuncActionInfo != nullptr)
-        {
-            pFuncActionInfo->addActionInfo(info);
-        }
-    }
-    /* 人员计数 */
-    else if (info.ActionID == g_actionList.ActPersonNumber)
-    {
-        auto pFuncActionInfo = findAppFunction(info.ChannelID, AppFunction::APP_Regional);
-        if(pFuncActionInfo != nullptr)
-        {
-            pFuncActionInfo->addActionInfo(info);
-        }
-    }
-    /* 违禁物品 */
-    else if (info.ActionID == g_actionList.ActContraband)
-    {
-        auto pFuncActionInfo = findAppFunction(info.ChannelID, AppFunction::APP_Contraband);
-        if(pFuncActionInfo != nullptr)
-        {
-            pFuncActionInfo->addActionInfo(info);
-        }
-    }
-    /* 玩手机 */
-    else if (info.ActionID == g_actionList.ActPlayPhone)
-    {
-        auto pFuncActionInfo = findAppFunction(info.ChannelID, AppFunction::APP_PlayPhone);
-        if(pFuncActionInfo != nullptr)
-        {
-            pFuncActionInfo->addActionInfo(info);
-        }
-    }
-    /* 睡岗识别 */
-    else if (info.ActionID == g_actionList.ActSleep)
-    {
-        auto pFuncActionInfo = findAppFunction(info.ChannelID, AppFunction::APP_Fatigue);
-        if(pFuncActionInfo != nullptr)
-        {
-            pFuncActionInfo->addActionInfo(info);
-        }
-    }
-    /* 疲劳检测 */
-    else if(info.ActionID == g_actionList.ActFatigueDetection)
-    {
-        auto pFuncActionInfo = findAppFunction(info.ChannelID, AppFunction::APP_Fatigue);
-        if(pFuncActionInfo != nullptr)
-        {
-            pFuncActionInfo->addActionInfo(info);
-        }
-    }
-    /* 动物识别 */
-    else if (info.ActionID == g_actionList.ActAnimalDetect)
-    {
-        auto pFuncActionInfo = findAppFunction(info.ChannelID, AppFunction::APP_Mouse);
-        if(pFuncActionInfo != nullptr)
-        {
-            pFuncActionInfo->addActionInfo(info);
-        }
-    }
-    /* 老鼠识别 */
-    else if (info.ActionID == g_actionList.ActMouseDetect)
-    {
-        auto pFuncActionInfo = findAppFunction(info.ChannelID, AppFunction::APP_Mouse);
-        if(pFuncActionInfo != nullptr)
-        {
-            pFuncActionInfo->addActionInfo(info);
-        }
-    }
-    /* 口罩识别 */
-    else if (info.ActionID == g_actionList.ActMask)
-    {
-        auto pFuncActionInfo = findAppFunction(info.ChannelID, AppFunction::APP_NoMask);
-        if(pFuncActionInfo != nullptr)
-        {
-            pFuncActionInfo->addActionInfo(info);
-        }
-    }
-    else {
-        SPDLOG_WARN("未知的算法ID: {}", info.ActionID);
-        return false;
-    }
-
-    return true;
-}
-
-/**
- * @brief 清空无用的功能信息
- *          摄像机和算法信息为空的,或者运行状态为STOP,都会被清理掉
- * 
- */
-void ListFuncActInfo::clearNoneFuncActionInfo()
-{
-    for(auto it0 = listFuncActionInfo.begin(); it0 != listFuncActionInfo.end();)
-    {
-        if((*it0)->listRoomCamActInfo.empty() || ((*it0)->RunState == RunTimeState::RUN_STATE_STOP))
-        {
-            delete *it0;
-            it0 = listFuncActionInfo.erase(it0);
-        }else {
-            ++it0;
-        }
-    }
-}
-
-/* 清空算法列表 */
-void ListFuncActInfo::clearActionList()
-{
-    for(auto& it0 : listFuncActionInfo)
-    {
-        it0->listRoomCamActInfo.clear();
-    }
-}
-
-/* 查找应用信息 */
-bool ListFuncActInfo::findAppFunction(const AppFunction func)
-{
-    for(const auto& it0 : listFuncActionInfo)
-    {
-        if(it0->appFunction == func)
-        {
-            return true;
-        }
-    }
-    return false;
-}
-/* 根据频率和功能查找实例 */
-FuncActionInfo* ListFuncActInfo::findAppFunction(const int ChannelID, const AppFunction func)
-{
-    for(const auto& it0 : listFuncActionInfo)
-    {
-        if( (it0->appFunction == func) && (it0->ChannelID == ChannelID) )
-        {
-            return it0;
-        }
-    }
-    return nullptr;
-}
-
-/**
- * @brief 查找这个应用信息
- * 
- * @param func 
- * @return FuncActionInfo* 
- */
-FuncActionInfo* ListFuncActInfo::findAppFunction(const FuncActionInfo& func)
-{
-    for(const auto& it0 : listFuncActionInfo)
-    {
-        if(it0->ChannelID == func.ChannelID && it0->appFunction == func.appFunction)
-        {
-            return it0;
-        }
-    }
-    return nullptr;
-}
-

+ 22 - 54
SecurePlayAuxServer/GlobalInfo/GlobalVariable.h

@@ -241,6 +241,7 @@ struct AlarmInfo
 {
     bool Is_Alarm;              /* 是否报警 */
     bool Is_InsertEQM;          /* 是否已经插入到EQM数据库中 */
+    bool Is_OnWork;             /* 是否在岗 */
     int AlarmID;                /* 报警ID */
     int DeviceID;               /* 设备ID,数据库表格中对应的是CamerID */
     
@@ -260,13 +261,17 @@ struct AlarmInfo
     std::string FaceIDList;     /* 人脸ID列表 */
     std::string FaceNameList;   /* 人脸名称列表 */
     std::list<std::string> listBbox;       /* Bbox列表,应该是图片中的报警位置 */
-    std::vector<PersonInfo> vecPersonInfo;    /* 人员信息 */
+    std::list<PersonInfo> listPersonInfo;    /* 人员信息 */
 
     AlarmInfo();
     AlarmInfo(const AlarmInfo& other);
     AlarmInfo& operator=(AlarmInfo& other);
 
     void reInit();
+    /* 获取人脸ID列表 */
+    std::string getFaceIDListString();
+    /* 获取人脸名称列表 */
+    std::string getFaceNameListString();
 };
 
 /**
@@ -542,7 +547,22 @@ public:
  {
     int RoomID;                         /* 房间ID */
     int RoomType;                       /* 房间类型 */
-    std::multimap<int, std::string> mapCameraAction;    /* 摄像机ID和算法ID关联信息 */
+    std::string strRoomName;            /* 房间名称 */
+    // std::multimap<int, std::string> mapCameraAction;    /* 摄像机ID和算法ID关联信息 */
+    std::map<int, std::list<std::string>> mapCameraAction;    /* 摄像机ID和算法ID关联信息,一个摄像机可以有多个算法列表 */
+
+    /* 添加摄像机算法 */
+    void addCameraAction(int CameraID, const std::string& ActionID) 
+    {
+        auto it = mapCameraAction.find(CameraID);
+        if(it == mapCameraAction.end()) {
+            std::list<std::string> list;
+            list.push_back(ActionID);
+            mapCameraAction.insert(std::make_pair(CameraID, list));
+        }else {
+            it->second.push_back(ActionID);
+        }
+    }
  };
 
 
@@ -569,59 +589,7 @@ public:
     }
  };
 
-/**
- * @brief 按照功能分类的线程信息,一个实例就是一个功能,
-            比如区域入侵检测,需要多个算法多个摄像机共同配合
- * 
- */
- struct FuncActionInfo
- {
-    int ChannelID;                  /* 频率ID */
-    AppFunction appFunction;        /* 任务功能 */
-    RunTimeState RunState;          /* 线程运行状态 */
-    std::string strFunctionName;    /* 功能名称 */
-    QDateTime StartTime;            /* 开始时间 */
-    QDateTime EndTime;              /* 结束时间 */
-    std::list<RoomCamActInfo> listRoomCamActInfo;       /* 房间内的摄像机和算法关联信息 */
-
-    FuncActionInfo();
-    ~FuncActionInfo();
-    FuncActionInfo& operator=(FuncActionInfo& other);
-    /* 添加算法信息 */
-    bool addActionInfo(const ActionInfo& info);
-    /* 清空算法信息 */
-    void clearActionList();
-
- };
 
-/**
- * @brief 线程功能块
- * 
- */
- struct ListFuncActInfo
- {
-    ListFuncActInfo() = default;
-
-    /* 添加功能信息 */
-    bool addFuncActionInfo(const AppAndTimeInfo& func);
-    /* 添加算法信息 */
-    bool addActionInfo(const ActionInfo& info);
-    /* 清空无用的功能信息 */
-    void clearNoneFuncActionInfo();
-    /* 清空房间和算法列表 */
-    void clearActionList();
-
-    /* 获取容器 */
-    std::list<FuncActionInfo*>& getData() {
-        return listFuncActionInfo;
-    }
-    /* 查找应用信息 */
-    bool findAppFunction(const AppFunction func);
-    FuncActionInfo* findAppFunction(const int ChannelID, const AppFunction func);
-    FuncActionInfo* findAppFunction(const FuncActionInfo& func);
-
-    std::list<FuncActionInfo*> listFuncActionInfo;    /* 功能信息列表 */
- };
 
 
 

+ 1 - 1
SecurePlayAuxServer/GlobalInfo/UniversalFunc.cpp

@@ -142,7 +142,7 @@ void parseRedisBBoxesData(const std::string& strData, AlarmInfo& alarmInfo)
                     PersonInfo personInfo;
                     personInfo.PersonID = it["personId"].get<std::string>();
                     personInfo.PersonName = it["personName"].get<std::string>();
-                    alarmInfo.vecPersonInfo.push_back(personInfo);
+                    alarmInfo.listPersonInfo.push_back(personInfo);
                 }
             }
         }

+ 73 - 53
SecurePlayAuxServer/SPAServer.cpp

@@ -8,6 +8,7 @@
 #include "UniversalFunc.h"
 #include "FuncOrdinary.h"
 #include "FuncIllegalInvasion.h"
+#include "GlobalFuncThread.h"
 
 #include <QCoreApplication>
 
@@ -33,7 +34,7 @@ SPAServer::SPAServer()
 
     m_threadRunning = true;
     /* 初始化WebAPI */
-    m_toEQMDataBase.initWebApi("http://192.1.3.133:31000/v6/", "", "4c2f9fc91c22dd98331e47af2e2964f4");
+    m_fromWebAPI.initWebApi("http://192.1.3.133:31000/v6/", "", "4c2f9fc91c22dd98331e47af2e2964f4");
     /* 模拟违禁品算法ID,后续需要动态调整 */
     g_actionList.ActContraband = "OD210_026_005246_001-IZRTKyEx";
     
@@ -81,9 +82,9 @@ void SPAServer::threadFromSuperBrain()
     {
         SPDLOG_LOGGER_INFO(m_logger, "刷新算法和设备信息");
         /* 先更新数据库的信息,防止从其他地方更改了数据库,这里没有刷新本地缓存 */
-        m_toEQMDataBase.getAlgorithmInfo(m_vecEqmAlgInfo);
-        m_toEQMDataBase.getDeviceInfo(m_vecEqmDevInfo);
-        m_toEQMDataBase.getDeviceAlgorithmInfo(m_vecEqmDevInfo, m_listDevIDDelete);
+        m_fromWebAPI.getAlgorithmInfo(m_vecEqmAlgInfo);
+        m_fromWebAPI.getDeviceInfo(m_vecEqmDevInfo);
+        m_fromWebAPI.getDeviceAlgorithmInfo(m_vecEqmDevInfo, m_listDevIDDelete);
 
         /* 从超脑获取基础信息 */
         m_fromSuperBrain.getTaskTypeList(vecAlgNewInfo);
@@ -99,18 +100,9 @@ void SPAServer::threadFromSuperBrain()
 
         /* 更新算法详细信息 */
         m_mutexActionInfo.lock();
-        m_toEQMDataBase.getActionInfo(m_listActionInfo);
+        m_fromWebAPI.getActionInfo(m_listActionInfo);
         m_mutexActionInfo.unlock();
 
-        /* 更新通道名称和摄像机名称信息 */
-        std::map<int, std::string> mapChannelName;
-        m_toEQMDataBase.getChannelInfo(mapChannelName);
-        GConfig.setChannelInfo(mapChannelName);
-
-        std::map<int, std::string> mapCameraName;
-        m_toEQMDataBase.getCameraInfo(mapCameraName);
-        GConfig.setCameraInfo(mapCameraName);
-
         /* 10秒更新一次 */
         std::this_thread::sleep_for(std::chrono::seconds(10));
     }
@@ -131,13 +123,13 @@ bool SPAServer::processAlgorithmInfo(std::vector<AlgorithmInfo> vecNewAlgInfo)
     if(vecAlgDelete.size() > 0)
     {
         SPDLOG_LOGGER_DEBUG(m_logger, "删除算法信息");
-        m_toEQMDataBase.deleteAlgorithmInfo(vecAlgDelete);
+        m_fromWebAPI.deleteAlgorithmInfo(vecAlgDelete);
         isUpdate = true;
     }
     if(vecAlgUpdate.size() > 0)
     {
         SPDLOG_LOGGER_DEBUG(m_logger, "写入算法信息");
-        m_toEQMDataBase.writeAlgorithmInfo(vecAlgUpdate);
+        m_fromWebAPI.writeAlgorithmInfo(vecAlgUpdate);
         isUpdate = true;
     }
 
@@ -221,21 +213,21 @@ bool SPAServer::processDeviceInfo(std::vector<DeviceInfo> vecNewDevInfo)
     if(vecDevDelete.size() > 0)
     {
         SPDLOG_LOGGER_DEBUG(m_logger, "删除设备信息, 表: tActionCamer");
-        m_toEQMDataBase.deleteDeviceInfo(vecDevDelete);
+        m_fromWebAPI.deleteDeviceInfo(vecDevDelete);
         isUpdate = true;
     }
     /* 更新数据 */
     if(vecDevUpdate.size() > 0)
     {
         SPDLOG_LOGGER_DEBUG(m_logger, "更新设备信息, 表: tActionCamer");
-        m_toEQMDataBase.updateDeviceInfo(vecDevUpdate);
+        m_fromWebAPI.updateDeviceInfo(vecDevUpdate);
         isUpdate = true;
     }
     /* 插入数据 */
     if(vecDevInsert.size() > 0)
     {
         SPDLOG_LOGGER_DEBUG(m_logger, "插入设备信息, 表: tActionCamer");
-        m_toEQMDataBase.insertDeviceInfo(vecDevInsert);
+        m_fromWebAPI.insertDeviceInfo(vecDevInsert);
         isUpdate = true;
     }
 
@@ -247,7 +239,7 @@ bool SPAServer::processDeviceInfo(std::vector<DeviceInfo> vecNewDevInfo)
     if(vecDevInsert.size() > 0)
     {
         SPDLOG_LOGGER_DEBUG(m_logger, "插入设备和算法关联表(tActionCamer)");
-        m_toEQMDataBase.insertDeviceAlgorithmInfo(vecDevInsert);
+        m_fromWebAPI.insertDeviceAlgorithmInfo(vecDevInsert);
         isUpdate = true;
     }
 
@@ -257,7 +249,7 @@ bool SPAServer::processDeviceInfo(std::vector<DeviceInfo> vecNewDevInfo)
     if(vecDevUpdate.size() > 0)
     {
         SPDLOG_LOGGER_DEBUG(m_logger, "更新设备和算法关联表(tActionCamer), 更新设备数目:{}", vecDevUpdate.size());
-        m_toEQMDataBase.updateDeviceAlgorithmInfo(vecDevUpdate);
+        m_fromWebAPI.updateDeviceAlgorithmInfo(vecDevUpdate);
     }
     
     
@@ -265,7 +257,7 @@ bool SPAServer::processDeviceInfo(std::vector<DeviceInfo> vecNewDevInfo)
     if(m_listDevIDDelete.size() > 0)
     {
         SPDLOG_LOGGER_DEBUG(m_logger, "删除消失的设备关联的算法(tActionCamer)");
-        m_toEQMDataBase.deleteDeviceAlgorithmInfo(m_listDevIDDelete);
+        m_fromWebAPI.deleteDeviceAlgorithmInfo(m_listDevIDDelete);
         isUpdate = true;
     }
 
@@ -469,29 +461,54 @@ void SPAServer::threadDistribution()
     /* 存储获取到的应用和启用时间的信息 */
     std::list<AppAndTimeInfo> listAppAndTime;
     /* 创建连接数据库实例 */
-    std::shared_ptr<ToEQMDataBase> toEQMDataBase = std::make_shared<ToEQMDataBase>();
+    std::shared_ptr<FromWebAPI> fromWebAPI = std::make_shared<FromWebAPI>();
+    /* 初始化WebAPI */
+    // fromWebAPI->initWebApi(const QString &url, const QString &serverIP, const QString &serID)
 
     while (m_threadRunning)
     {
+        /* ======================================================= */
+        /* 更新通道名称和摄像机名称信息 */
+        std::map<int, std::string> mapChannelName;
+        m_fromWebAPI.getChannelInfo(mapChannelName);
+        GConfig.setChannelInfo(mapChannelName);
+
+        std::map<int, std::string> mapCameraName;
+        m_fromWebAPI.getCameraInfo(mapCameraName);
+        GConfig.setCameraInfo(mapCameraName);
+
+        /* ======================================================= */
         GThreadInfo.lockRunFAI();
         /* 先清理已经退出的线程所用到的Action或者RoomAction */
-        GThreadInfo.clearNoneFuncActionInfo();
+        GThreadInfo.clearNoneFuncThreadInfo();
 
         /* 清空已经停止运行的功能类实例 */
-        clearNoneFuncActionInfo();
+        clearNoneFuncThreadInfo();
 
+        /* ======================================================= */
         /* 创建应用信息,根据从EQM数据库读取到的配置的应用信息创建 */
-        toEQMDataBase->getAlarmAppInfo(listAppAndTime);
+        fromWebAPI->getAlarmAppInfo(listAppAndTime);
         for(const auto& it : listAppAndTime)
         {
             /* 创建应用信息,如果已有该应用,就更新时间
              * 这里只创建应用信息块,没有对应的房间、算法信息 */
-            GThreadInfo.addFuncActionInfo(it);
+            GThreadInfo.addFuncThreadInfo(it);
         }
 
+        
+        /* 设置应用对应的频率信息 */
+        for(auto& func : GThreadInfo.getList())
+        {
+            /* 设置频率名称 */
+            func->strChannelName = GConfig.getChannelName(func->ChannelID);
+        }
+        
+        /* 设置对应的摄像机名称列表 */
+        GThreadInfo.setCameraInfo(GConfig.getCameraInfoMap());
+
         /* 先获取EQM数据库信息,取出房间和摄像机关联信息,包括所在的频率 */
         m_mutexActionInfo.lock();
-        toEQMDataBase->getActionInfo(m_listActionInfo);
+        fromWebAPI->getActionInfo(m_listActionInfo);
         /* 将算法信息加入到不同的功能列表中,先清空功能对应的算法设备列表 */
         GThreadInfo.clearActionList();
         for(const auto& it : m_listActionInfo.getData())
@@ -535,7 +552,7 @@ void SPAServer::threadDistribution()
  * @param info 
  * @return FuncBase* 
  */
-FuncBase* SPAServer::createFuncInstance(FuncActionInfo& info)
+FuncBase* SPAServer::createFuncInstance(FuncThreadInfo& info)
 {
     if(info.appFunction == AppFunction::APP_NONE)
     {
@@ -548,7 +565,7 @@ FuncBase* SPAServer::createFuncInstance(FuncActionInfo& info)
         info.appFunction == AppFunction::APP_Fatigue || info.appFunction == AppFunction::APP_Contraband )
     {
         auto tmpFunc = new FuncOrdinary();
-        tmpFunc->setFuncActionInfo(info);
+        tmpFunc->setFuncThreadInfo(info);
         pFunc = tmpFunc;
     }
     else if(info.appFunction == AppFunction::APP_OnWork)
@@ -559,7 +576,7 @@ FuncBase* SPAServer::createFuncInstance(FuncActionInfo& info)
     {
         /* 非法入侵 */
         auto tmpFunc = new FuncIllegalInvasion();
-        tmpFunc->setFuncActionInfo(info);
+        tmpFunc->setFuncThreadInfo(info);
         pFunc = tmpFunc;
     }
     else if(info.appFunction == AppFunction::APP_Regional)
@@ -571,7 +588,7 @@ FuncBase* SPAServer::createFuncInstance(FuncActionInfo& info)
 }
 
 /* 清理没有在运行的线程实例 */
-void SPAServer::clearNoneFuncActionInfo()
+void SPAServer::clearNoneFuncThreadInfo()
 {
     for(auto it = m_listFuncBase.begin(); it != m_listFuncBase.end(); )
     {
@@ -617,15 +634,15 @@ void SPAServer::clearNoneFuncActionInfo()
  * 
  * @param RAInfo 传入的房间ID和算法ID
  */
-void SPAServer::threadActRegionalPersonnelDetection(FuncActionInfo* RFAInfo)
+void SPAServer::threadActRegionalPersonnelDetection(FuncThreadInfo* RFAInfo)
 {
     SPDLOG_LOGGER_INFO(m_logger, "开启 {} 线程,ChannelID:{} ,", RFAInfo->strFunctionName, RFAInfo->ChannelID);
     /* 创建读取Redis的实例 */
     std::shared_ptr<FromRedis> fromRedis = std::make_shared<FromRedis>();
     /* 创建写入数据库实例 */
-    std::shared_ptr<ToEQMDataBase> toEQMDataBase = std::make_shared<ToEQMDataBase>();
+    std::shared_ptr<FromWebAPI> fromWebAPI = std::make_shared<FromWebAPI>();
     /* 局部变量,线程功能需要的信息 */
-    std::shared_ptr<FuncActionInfo> pRFAInfo = std::make_shared<FuncActionInfo>();
+    std::shared_ptr<FuncThreadInfo> pRFAInfo = std::make_shared<FuncThreadInfo>();
     *pRFAInfo = *RFAInfo;
     /* 保存每个摄像机的报警信息 */
     std::shared_ptr<std::list<AlarmInfo>> pListAlarmInfo = std::make_shared<std::list<AlarmInfo>>();
@@ -633,7 +650,7 @@ void SPAServer::threadActRegionalPersonnelDetection(FuncActionInfo* RFAInfo)
     std::shared_ptr<std::vector<PersonCountRuleInfo>> pPersonCountRuleInfo = std::make_shared<std::vector<PersonCountRuleInfo>>();
 
     /* 获取报警规则信息 */
-    toEQMDataBase->getPersonCountRuleInfo(*pPersonCountRuleInfo);
+    fromWebAPI->getPersonCountRuleInfo(*pPersonCountRuleInfo);
     
     while (m_threadRunning)
     {
@@ -651,28 +668,31 @@ void SPAServer::threadActRegionalPersonnelDetection(FuncActionInfo* RFAInfo)
         {
             for(const auto& it : RoomInfo.mapCameraAction)
             {
-                std::string strKey = std::to_string(it.first) + ":" + it.second;
-                std::string strRetValue;
-                if(!fromRedis->getRedisString(strKey, strRetValue))
-                {
-                    SPDLOG_LOGGER_ERROR(m_logger, "读取Redis数据失败, Key:{}", strKey);
-                    continue;
-                }
-                /* 解析数据 */
-                AlarmInfo alarmInfo;
-                parseRedisBaseData(strRetValue, alarmInfo);
-                parseRedisBBoxesData(strRetValue, alarmInfo);
-                /* 判断事件的时效性,超过多少秒不更新就可能是超脑挂了 */
-                if(isEventTimeVaild(alarmInfo.EventTime))
+                for(const auto& act : it.second)
                 {
-                    SPDLOG_LOGGER_WARN(m_logger, "Redis Key:{} 数据长时间没有更新,EventTime:{}",strKey, alarmInfo.EventTime);
-                    continue;
+                    std::string strKey = std::to_string(it.first) + ":" + act;
+                    std::string strRetValue;
+                    if(!fromRedis->getRedisString(strKey, strRetValue))
+                    {
+                        SPDLOG_LOGGER_ERROR(m_logger, "读取Redis数据失败, Key:{}", strKey);
+                        continue;
+                    }
+                    /* 解析数据 */
+                    AlarmInfo alarmInfo;
+                    parseRedisBaseData(strRetValue, alarmInfo);
+                    parseRedisBBoxesData(strRetValue, alarmInfo);
+                    /* 判断事件的时效性,超过多少秒不更新就可能是超脑挂了 */
+                    if(isEventTimeVaild(alarmInfo.EventTime))
+                    {
+                        SPDLOG_LOGGER_WARN(m_logger, "Redis Key:{} 数据长时间没有更新,EventTime:{}",strKey, alarmInfo.EventTime);
+                        continue;
+                    }
+                    pListAlarmInfo->push_back(alarmInfo);
                 }
-                pListAlarmInfo->push_back(alarmInfo);
             }
         }
         /************ 获取报警规则(从数据库更新?) ************/
-        if(!toEQMDataBase->getPersonCountRuleInfo(*pPersonCountRuleInfo))
+        if(!fromWebAPI->getPersonCountRuleInfo(*pPersonCountRuleInfo))
         {
             SPDLOG_LOGGER_ERROR(m_logger, "《人员计数》获取报警规则失败");
             continue;

+ 7 - 5
SecurePlayAuxServer/SPAServer.h

@@ -3,9 +3,11 @@
 
 #include "FromSuperBrain.h"
 #include "FromRedis.h"
-#include "ToEQMDataBase.h"
+#include "FromWebAPI.h"
 
 class FuncBase;
+class FuncThreadInfo;
+
 
 /**
  * 安播辅助提示系统服务类
@@ -46,12 +48,12 @@ private:
     /* 分派任务的线程 */
     void threadDistribution();
     /* 创建任务实例的函数 */
-    FuncBase* createFuncInstance(FuncActionInfo& info);
+    FuncBase* createFuncInstance(FuncThreadInfo& info);
     /* 清理没有在运行的线程实例 */
-    void clearNoneFuncActionInfo();
+    void clearNoneFuncThreadInfo();
     
     /* 区域人员检测(人员计数),检测这个区域内的人数,不能少于多少人,不能多余多少人 */
-    void threadActRegionalPersonnelDetection(FuncActionInfo* RFAInfo);
+    void threadActRegionalPersonnelDetection(FuncThreadInfo* RFAInfo);
 
 
 private:
@@ -60,7 +62,7 @@ private:
     bool m_threadRunning = true;                        /* 线程正在运行 */
 
     FromSuperBrain m_fromSuperBrain;
-    ToEQMDataBase m_toEQMDataBase;
+    FromWebAPI m_fromWebAPI;
 
     /* 算法信息,这个就是tAction在内存中的数据,方便后续对比,程序启动的时候会先获取一份 */
     std::vector<AlgorithmInfo> m_vecEqmAlgInfo;

+ 157 - 31
SecurePlayAuxServer/communication/ToEQMDataBase.cpp → SecurePlayAuxServer/communication/FromWebAPI.cpp

@@ -1,20 +1,21 @@
-#include "ToEQMDataBase.h"
+#include "FromWebAPI.h"
 
 #include <QJsonDocument>
 #include <QString>
 #include <QUuid>
+#include "FuncOnAndOffJob.h"
 
-ToEQMDataBase::ToEQMDataBase()
+FromWebAPI::FromWebAPI()
 {
-    m_logger = spdlog::get("ToEQMDataBase");
+    m_logger = spdlog::get("FromWebAPI");
     if(m_logger == nullptr)
     {
-        SPDLOG_ERROR("ToEQMDataBase logger is nullptr");
+        SPDLOG_ERROR("FromWebAPI logger is nullptr");
         return;
     }
 }
 
-ToEQMDataBase::~ToEQMDataBase()
+FromWebAPI::~FromWebAPI()
 {
     if(m_httpApi != nullptr)
     {
@@ -25,7 +26,7 @@ ToEQMDataBase::~ToEQMDataBase()
 
 
 /* 初始化WebApi */
-bool ToEQMDataBase::initWebApi(const QString& url, const QString& serverIP, const QString& serID)
+bool FromWebAPI::initWebApi(const QString& url, const QString& serverIP, const QString& serID)
 {
     if(m_httpApi == nullptr)
     {
@@ -77,7 +78,7 @@ bool ToEQMDataBase::initWebApi(const QString& url, const QString& serverIP, cons
  * @return true 
  * @return false 
  */
-bool ToEQMDataBase::writeAlgorithmInfo(std::vector<AlgorithmInfo>& vecInfo)
+bool FromWebAPI::writeAlgorithmInfo(std::vector<AlgorithmInfo>& vecInfo)
 {
     if(m_httpApi == nullptr)
     {
@@ -143,7 +144,7 @@ bool ToEQMDataBase::writeAlgorithmInfo(std::vector<AlgorithmInfo>& vecInfo)
 }
 
 /* 删除算法信息 */
-bool ToEQMDataBase::deleteAlgorithmInfo(std::vector<AlgorithmInfo>& vecDeleteInfo)
+bool FromWebAPI::deleteAlgorithmInfo(std::vector<AlgorithmInfo>& vecDeleteInfo)
 {
     if(m_httpApi == nullptr)
     {
@@ -193,7 +194,7 @@ bool ToEQMDataBase::deleteAlgorithmInfo(std::vector<AlgorithmInfo>& vecDeleteInf
 }
 
 /* 获取tAction数据 */
-bool ToEQMDataBase::getAlgorithmInfo(std::vector<AlgorithmInfo>& vecInfo)
+bool FromWebAPI::getAlgorithmInfo(std::vector<AlgorithmInfo>& vecInfo)
 {
     if(m_httpApi == nullptr)
     {
@@ -252,7 +253,7 @@ bool ToEQMDataBase::getAlgorithmInfo(std::vector<AlgorithmInfo>& vecInfo)
 
 
 /* 插入设备信息 */
-bool ToEQMDataBase::insertDeviceInfo(std::vector<DeviceInfo>& vecInfo)
+bool FromWebAPI::insertDeviceInfo(std::vector<DeviceInfo>& vecInfo)
 {
     if(m_httpApi == nullptr)
     {
@@ -345,7 +346,7 @@ bool ToEQMDataBase::insertDeviceInfo(std::vector<DeviceInfo>& vecInfo)
 
 
 /* 更新设备信息 */
-bool ToEQMDataBase::updateDeviceInfo(std::vector<DeviceInfo>& vecUpdateInfo)
+bool FromWebAPI::updateDeviceInfo(std::vector<DeviceInfo>& vecUpdateInfo)
 {
     if(m_httpApi == nullptr)
     {
@@ -411,7 +412,7 @@ bool ToEQMDataBase::updateDeviceInfo(std::vector<DeviceInfo>& vecUpdateInfo)
 
 
 /* 删除设备信息 */
-bool ToEQMDataBase::deleteDeviceInfo(std::vector<DeviceInfo>& vecDeleteInfo)
+bool FromWebAPI::deleteDeviceInfo(std::vector<DeviceInfo>& vecDeleteInfo)
 {
     if(m_httpApi == nullptr)
     {
@@ -466,7 +467,7 @@ bool ToEQMDataBase::deleteDeviceInfo(std::vector<DeviceInfo>& vecDeleteInfo)
 }
 
 /* 从EQM获取CamerInfo信息 */
-bool ToEQMDataBase::getDeviceInfo(std::vector<DeviceInfo>& vecInfo)
+bool FromWebAPI::getDeviceInfo(std::vector<DeviceInfo>& vecInfo)
 {
     if(m_httpApi == nullptr)
     {
@@ -534,7 +535,7 @@ bool ToEQMDataBase::getDeviceInfo(std::vector<DeviceInfo>& vecInfo)
 }
 
 /* 获取通道信息 */
-bool ToEQMDataBase::getChannelInfo(std::map<int, std::string>& mapChannelName)
+bool FromWebAPI::getChannelInfo(std::map<int, std::string>& mapChannelName)
 {
     if(m_httpApi == nullptr)
     {
@@ -589,7 +590,7 @@ bool ToEQMDataBase::getChannelInfo(std::map<int, std::string>& mapChannelName)
     return true;
 }
 
-std::string ToEQMDataBase::getChannelName(int chnID)
+std::string FromWebAPI::getChannelInfo(int chnID)
 {
     if(m_httpApi == nullptr)
     {
@@ -648,7 +649,7 @@ std::string ToEQMDataBase::getChannelName(int chnID)
 }
 
 /* 获取摄像机信息 */
-bool ToEQMDataBase::getCameraInfo(std::map<int, std::string>& mapCameraName)
+bool FromWebAPI::getCameraInfo(std::map<int, std::string>& mapCameraName)
 {
     if(m_httpApi == nullptr)
     {
@@ -704,7 +705,7 @@ bool ToEQMDataBase::getCameraInfo(std::map<int, std::string>& mapCameraName)
 }
 
 /* 插入设备和算法关联信息 */
-bool ToEQMDataBase::insertDeviceAlgorithmInfo(std::vector<DeviceInfo>& vecInfo)
+bool FromWebAPI::insertDeviceAlgorithmInfo(std::vector<DeviceInfo>& vecInfo)
 {
     if(m_httpApi == nullptr)
     {
@@ -756,7 +757,7 @@ bool ToEQMDataBase::insertDeviceAlgorithmInfo(std::vector<DeviceInfo>& vecInfo)
 }
 
 /* 更新设备和算法关联表 */
-bool ToEQMDataBase::updateDeviceAlgorithmInfo(std::vector<DeviceInfo>& vecInfo)
+bool FromWebAPI::updateDeviceAlgorithmInfo(std::vector<DeviceInfo>& vecInfo)
 {
     if(m_httpApi == nullptr)
     {
@@ -810,7 +811,7 @@ bool ToEQMDataBase::updateDeviceAlgorithmInfo(std::vector<DeviceInfo>& vecInfo)
 }
 
 /* 删除设备和算法关联表 */
-bool ToEQMDataBase::deleteDeviceAlgorithmInfo(std::vector<DeviceInfo>& vecInfo)
+bool FromWebAPI::deleteDeviceAlgorithmInfo(std::vector<DeviceInfo>& vecInfo)
 {
     if(m_httpApi == nullptr)
     {
@@ -843,7 +844,7 @@ bool ToEQMDataBase::deleteDeviceAlgorithmInfo(std::vector<DeviceInfo>& vecInfo)
 
 
 /* 删除设备和算法关联表 */
-bool ToEQMDataBase::deleteDeviceAlgorithmInfo(std::list<int>& vecID)
+bool FromWebAPI::deleteDeviceAlgorithmInfo(std::list<int>& vecID)
 {
     if(m_httpApi == nullptr)
     {
@@ -875,7 +876,7 @@ bool ToEQMDataBase::deleteDeviceAlgorithmInfo(std::list<int>& vecID)
 }
 
 /* 获取设备和算法信息关联表,需要先从EQM数据库中获取到设备信息 */
-bool ToEQMDataBase::getDeviceAlgorithmInfo(std::vector<DeviceInfo>& vecInfo, std::list<int>& listDevIDDelete)
+bool FromWebAPI::getDeviceAlgorithmInfo(std::vector<DeviceInfo>& vecInfo, std::list<int>& listDevIDDelete)
 {
     if(m_httpApi == nullptr)
     {
@@ -979,7 +980,7 @@ bool ToEQMDataBase::getDeviceAlgorithmInfo(std::vector<DeviceInfo>& vecInfo, std
 }
 
 /* 获取设备和算法关联信息,包括频率信息,房间信息,重载版,只获取关联关系 */
-bool ToEQMDataBase::getActionInfo(ListActionInfo& listInfo)
+bool FromWebAPI::getActionInfo(ListActionInfo& listInfo)
 {
     if(m_httpApi == nullptr)
     {
@@ -1044,7 +1045,7 @@ bool ToEQMDataBase::getActionInfo(ListActionInfo& listInfo)
 
 
 /* 获取摄像机和房间关联信息 */
-bool ToEQMDataBase::getRoomCameraInfo(std::list<RoomCameraInfo>& vecInfo)
+bool FromWebAPI::getRoomCameraInfo(std::list<RoomCameraInfo>& vecInfo)
 {
     if(m_httpApi == nullptr)
     {
@@ -1122,9 +1123,15 @@ bool ToEQMDataBase::getRoomCameraInfo(std::list<RoomCameraInfo>& vecInfo)
     return true;
 }
 
-
 /* 写入报警信息 */
-bool ToEQMDataBase::insertAlarmInfo(const AlarmInfo& alarmInfo)
+bool FromWebAPI::insertAlarmInfo(const AlarmInfo& alarmInfo)
+{
+    int PKID = 0;
+    return insertAlarmInfo(alarmInfo, PKID);
+}
+
+
+bool FromWebAPI::insertAlarmInfo(const AlarmInfo& alarmInfo, int& PKID)
 {
     if(m_httpApi == nullptr)
     {
@@ -1135,7 +1142,7 @@ bool ToEQMDataBase::insertAlarmInfo(const AlarmInfo& alarmInfo)
     if(alarmInfo.ImageInfo.empty())
     {
         SPDLOG_LOGGER_WARN(m_logger, "× 取消新增报警信息,因为没有图片,频道[{}],房间[{}],摄像头[{}],{},{},有{}个区域,有{}个人脸",
-                            alarmInfo.ChannelID, alarmInfo.RoomID, alarmInfo.DeviceID, alarmInfo.ActionDes, alarmInfo.ImageInfo, alarmInfo.listBbox.size(), alarmInfo.vecPersonInfo.size());
+                            alarmInfo.ChannelID, alarmInfo.RoomID, alarmInfo.DeviceID, alarmInfo.ActionDes, alarmInfo.ImageInfo, alarmInfo.listBbox.size(), alarmInfo.listPersonInfo.size());
         return false;
     }
     /* 拼接Bbox */
@@ -1151,7 +1158,7 @@ bool ToEQMDataBase::insertAlarmInfo(const AlarmInfo& alarmInfo)
     try
     {
         nJson json0;
-        json0["opName"] = "SPSS_InsertToAlarmInfo";
+        json0["opName"] = "SPSS_InsertToAlarm";
         nJson json1;
         json1["AlarmID"] = alarmInfo.AlarmID;
         json1["StartTime"] = alarmInfo.StartTime;
@@ -1180,6 +1187,27 @@ bool ToEQMDataBase::insertAlarmInfo(const AlarmInfo& alarmInfo)
             return false;
         }
         // SPDLOG_LOGGER_DEBUG(m_logger,"插入报警信息成功!");
+        SPDLOG_LOGGER_DEBUG(m_logger, "返回的数据:{}", strRet.toStdString());
+
+        nJson retJson = nJson::parse(strRet.toStdString());
+        int retCode = retJson["code"].get<int>();
+        if(retCode != 0)
+        {
+            SPDLOG_LOGGER_ERROR(m_logger,"插入报警信息失败, 错误信息:{}", retJson["msg"].get<std::string>());
+            return false;
+        }
+        /* 解析返回的报警ID */
+        nJson result = retJson["result"];
+        if(result.empty())
+        {
+            SPDLOG_LOGGER_ERROR(m_logger,"插入报警信息失败, 返回的结果为空");
+            return false;
+        }
+        for(const auto& it : result)
+        {
+            PKID = it["pkid"].is_null() ? 0 : it["pkid"].get<int>();
+        }
+
     }
     catch (const nJson::parse_error& e) {
         SPDLOG_LOGGER_ERROR(m_logger,"创建 写入报警信息 JSON失败 数据失败:{}, 错误ID:{}",e.what(), e.id);
@@ -1198,7 +1226,7 @@ bool ToEQMDataBase::insertAlarmInfo(const AlarmInfo& alarmInfo)
 }
 
 /* 更新报警结束时间 */
-bool ToEQMDataBase::updateAlarmEndTime(const AlarmInfo& alarmInfo)
+bool FromWebAPI::updateAlarmEndTime(const AlarmInfo& alarmInfo)
 {
     if(m_httpApi == nullptr)
     {
@@ -1242,8 +1270,106 @@ bool ToEQMDataBase::updateAlarmEndTime(const AlarmInfo& alarmInfo)
     return true;
 }
 
+/**
+ * @brief 根据PKID更新报警记录,用来结束报警,这个只需要PKID和结束时间
+ * 
+ * @param alarmInfo 
+ * @return true 
+ * @return false 
+ */
+bool FromWebAPI::endAlarmInfoByPKID(const int PKID, const QDateTime dateTime)
+{
+    if(m_httpApi == nullptr)
+    {
+        SPDLOG_LOGGER_ERROR(m_logger,"WebApi is nullptr");
+        return false;
+    }
+    try
+    {
+        nJson json0;
+        json0["opName"] = "SPSS_EndAlarmByPKID";
+        nJson json1;
+        json1["PKID"] = PKID;
+        json1["endTime"] = dateTime.toString("yyyy-MM-dd hh:mm:ss").toStdString();
+        json0["paramList"] = json1;
+
+        QString strCmd = QString::fromStdString(json0.dump());
+        QString strRet;
+        int ret = m_httpApi->DBDoInterface(enDBOperatorType::EDBOT_Update, strCmd, strRet);
+        if(ret != 0)
+        {
+            SPDLOG_LOGGER_WARN(m_logger,"更新报警结束时间失败:{}, 错误信息:{}",ret,m_httpApi->DoGetLastError(&ret).toStdString());
+            return false;
+        }
+        // SPDLOG_LOGGER_DEBUG(m_logger,"更新报警结束时间成功!");
+    }
+    catch (const nJson::parse_error& e) {
+        SPDLOG_LOGGER_ERROR(m_logger,"创建 更新报警结束时间 JSON失败 数据失败:{}, 错误ID:{}",e.what(), e.id);
+        return false;
+    }
+    catch (const nJson::type_error& e) {
+        SPDLOG_LOGGER_ERROR(m_logger,"创建 更新报警结束时间 JSON失败 数据失败:{}, 错误ID:{}",e.what(), e.id);
+        return false;
+    }
+    catch(...) {
+        SPDLOG_LOGGER_ERROR(m_logger,"创建 更新报警结束时间 JSON失败 数据失败");
+        return false;
+    }
+
+    return true;
+}
+
+
+/* 更新人员信息 */
+bool FromWebAPI::updatePersonInfo(RoomOnWorkInfo& roomInfo)
+{
+    if(m_httpApi == nullptr)
+    {
+        SPDLOG_LOGGER_ERROR(m_logger,"WebApi is nullptr");
+        return false;
+    }
+    try
+    {
+        std::string strDes = fmt::format("人员在岗[{}][{}]", roomInfo.getFaceIDListString(), roomInfo.getFaceNameListString());
+        nJson json0;
+        json0["opName"] = "SPSS_UpdateFaceInfoByPKID";
+        nJson json1;
+        json1["pkid"] = roomInfo.PKID;
+        json1["faceIDList"] = roomInfo.getFaceIDListString();
+        json1["faceNameList"] = roomInfo.getFaceNameListString();
+        json1["ActionDes"] = strDes;
+        json0["paramList"] = json1;
+
+        QString strCmd = QString::fromStdString(json0.dump());
+        QString strRet;
+        int ret = m_httpApi->DBDoInterface(enDBOperatorType::EDBOT_Update, strCmd, strRet);
+        if(ret != 0)
+        {
+            SPDLOG_LOGGER_WARN(m_logger,"更新报警结束时间失败:{}, 错误信息:{}",ret,m_httpApi->DoGetLastError(&ret).toStdString());
+            return false;
+        }
+        // SPDLOG_LOGGER_DEBUG(m_logger,"更新报警结束时间成功!");
+    }
+    catch (const nJson::parse_error& e) {
+        SPDLOG_LOGGER_ERROR(m_logger,"创建 更新人员信息 JSON失败 数据失败:{}, 错误ID:{}",e.what(), e.id);
+        return false;
+    }
+    catch (const nJson::type_error& e) {
+        SPDLOG_LOGGER_ERROR(m_logger,"创建 更新人员信息 JSON失败 数据失败:{}, 错误ID:{}",e.what(), e.id);
+        return false;
+    }
+    catch(...) {
+        SPDLOG_LOGGER_ERROR(m_logger,"创建 更新人员信息 JSON失败 数据失败");
+        return false;
+    }
+
+    return true;
+}
+
+
+
 /* 获取报警规则表 */
-bool ToEQMDataBase::getPersonCountRuleInfo(std::vector<PersonCountRuleInfo>& vecInfo)
+bool FromWebAPI::getPersonCountRuleInfo(std::vector<PersonCountRuleInfo>& vecInfo)
 {
     nJson json0;
     json0["opName"] = "SPSS_GetPersonCountRule";
@@ -1317,7 +1443,7 @@ bool ToEQMDataBase::getPersonCountRuleInfo(std::vector<PersonCountRuleInfo>& vec
 }
 
 /* 获取报警时段,也同时获取报警的应用信息,tPeriod表 */
-bool ToEQMDataBase::getAlarmAppInfo(std::list<AppAndTimeInfo>& listInfo)
+bool FromWebAPI::getAlarmAppInfo(std::list<AppAndTimeInfo>& listInfo)
 {
     nJson json0;
     json0["opName"] = "SPSS_SelectPeriod";
@@ -1376,7 +1502,7 @@ bool ToEQMDataBase::getAlarmAppInfo(std::list<AppAndTimeInfo>& listInfo)
 
 
 /* 写入在岗信息 tWorkOnInfo */
-bool ToEQMDataBase::insertOnWorkInfo(const RoomFaceInfo& onWorkInfo)
+bool FromWebAPI::insertOnWorkInfo(const RoomFaceInfo& onWorkInfo)
 {
     if(m_httpApi == nullptr)
     {

+ 19 - 7
SecurePlayAuxServer/communication/ToEQMDataBase.h → SecurePlayAuxServer/communication/FromWebAPI.h

@@ -1,15 +1,19 @@
-#ifndef TOEQMDATABASE_H
-#define TOEQMDATABASE_H
+#ifndef FROMWEBAPI_H
+#define FROMWEBAPI_H
 
 #include "spdlog/spdlog.h"
 #include "lhhttpapi.h"
 #include "GlobalVariable.h"
 
-class ToEQMDataBase
+
+class RoomOnWorkInfo;
+
+
+class FromWebAPI
 {
 public:
-    ToEQMDataBase();
-    ~ToEQMDataBase();
+    FromWebAPI();
+    ~FromWebAPI();
 
     /* 初始化WebAPI */
     bool initWebApi(const QString& url,const QString& serverIP,const QString& serID);
@@ -32,7 +36,7 @@ public:
 
     /* 获取通道信息 */
     bool getChannelInfo(std::map<int, std::string>& mapChannelName);
-    std::string getChannelName(int chnID);
+    std::string getChannelInfo(int chnID);
     /* 获取摄像机信息 */
     bool getCameraInfo(std::map<int, std::string>& mapCameraName);
     
@@ -54,8 +58,13 @@ public:
 
     /* 写入报警信息 */
     bool insertAlarmInfo(const AlarmInfo& alarmInfo);
+    bool insertAlarmInfo(const AlarmInfo& alarmInfo, int& PKID);
     /* 更新报警结束时间 */
     bool updateAlarmEndTime(const AlarmInfo& alarmInfo);
+    /* 根据PKID更新报警记录,用来结束报警 */
+    bool endAlarmInfoByPKID(const int PKID, const QDateTime dateTime);
+    /* 更新人员信息 */
+    bool updatePersonInfo(RoomOnWorkInfo& roomInfo);
 
     /* 获取人员计数规则 */
     bool getPersonCountRuleInfo(std::vector<PersonCountRuleInfo>& vecInfo);
@@ -64,6 +73,9 @@ public:
 
     /* 写入在岗信息 */
     bool insertOnWorkInfo(const RoomFaceInfo& onWorkInfo);
+    
+    /* 写入在岗离岗数据 */
+    
 
 private:
     std::shared_ptr<spdlog::logger> m_logger = nullptr;
@@ -73,4 +85,4 @@ private:
 };
 
 
-#endif /* TOEQMDATABASE_H */
+#endif /* FROMWEBAPI_H */