瀏覽代碼

V0.4.7
1、完成了在岗离岗功能

Apple 3 天之前
父節點
當前提交
3197435afd

+ 16 - 0
SQL/SecurePlay.sqlbook

@@ -142,6 +142,22 @@ UPDATE "tAlarmInfo"
 SET "FaceIdList" = :faceIDList, "FaceNameList" = :faceNameList, "ActionDes" = :actionDes, "CreateTime" = GetDate()
 WHERE "PKID" = :pkid;
 
+#获取某个频率的最大PKID
+SELECT MAX("PKID") AS MaxPKID
+FROM "tAlarmInfo"
+WHERE "chnID" = :ChannelID AND "Appid" = :AppID;
+
+
+#清空在岗离岗报警的在岗人员信息
+UPDATE "tAlarmInfo"
+SET "FaceIdList" = '', "FaceNameList" = '', "ActionDes" = @actionDes, "CreateTime" = GetDate()
+WHERE "PKID" = @pkid AND "OnWork" = @onWork;
+
+
+#结束人员计数的报警,通过频率ID和应用ID
+UPDATE "tAlarmInfo"
+SET "EndTime" = GetDate()
+WHERE "chnID" = @channelID AND "Appid" = @appID;
 
 -- SQLBook: Code
 #报警规则表

+ 15 - 1
SecurePlayAuxServer/Application/FuncBase.cpp

@@ -13,7 +13,21 @@ FuncBase::FuncBase()
 
 FuncBase::~FuncBase()
 {
-
+    if(m_fromRedis != nullptr)
+    {
+        m_fromRedis.reset();
+        m_fromRedis = nullptr;
+    }
+    if(m_fromWebAPI != nullptr)
+    {
+        m_fromWebAPI.reset();
+        m_fromWebAPI = nullptr;
+    }
+    if(m_logger != nullptr)
+    {
+        m_logger.reset();
+        m_logger = nullptr;
+    }
 }
 
 /* 任务线程 */

+ 14 - 5
SecurePlayAuxServer/Application/FuncIllegalInvasion.cpp

@@ -38,7 +38,7 @@ RoomIllegalInvasionInfo& RoomIllegalInvasionInfo::operator=(const RoomIllegalInv
 }
 
 /* 添加房间 */
-void ListRoomIll::addRoom(int RoomID, int RoomType)
+void ListRoomIll::addRoom(int RoomID, Enum_RoomType RoomType)
 {
     auto p = findRoom(RoomID, RoomType);
     if(p == nullptr)
@@ -51,7 +51,7 @@ void ListRoomIll::addRoom(int RoomID, int RoomType)
 }
 
 /* 查找是否有相同的房间 */
-RoomIllegalInvasionInfo* ListRoomIll::findRoom(int RoomID, int RoomType)
+RoomIllegalInvasionInfo* ListRoomIll::findRoom(int RoomID, Enum_RoomType RoomType)
 {
     for(auto& it : listRoomIll)
     {
@@ -117,7 +117,7 @@ IllegalInvasionInfo* ListIllegalInvasionInfo::findIllInfo(IllegalInvasionInfo& i
     return nullptr;
 }
 
-IllegalInvasionInfo* ListIllegalInvasionInfo::findIllInfo(int roomID, int roomType)
+IllegalInvasionInfo* ListIllegalInvasionInfo::findIllInfo(int roomID, Enum_RoomType roomType)
 {
     for(auto& it : listIll)
     {
@@ -144,7 +144,7 @@ void ListIllegalInvasionInfo::deleteIllInfo(IllegalInvasionInfo& info)
     }
 }
 
-void ListIllegalInvasionInfo::deleteIllInfo(int roomID, int roomType)
+void ListIllegalInvasionInfo::deleteIllInfo(int roomID, Enum_RoomType roomType)
 {
     for(auto it = listIll.begin(); it != listIll.end();)
     {
@@ -176,7 +176,16 @@ FuncIllegalInvasion::FuncIllegalInvasion()
 
 FuncIllegalInvasion::~FuncIllegalInvasion()
 {
-
+    if(m_pListAlarm != nullptr)
+    {
+        m_pListAlarm.reset();
+        m_pListAlarm = nullptr;
+    }
+    if(m_pListIllInfo != nullptr)
+    {
+        m_pListIllInfo.reset();
+        m_pListIllInfo = nullptr;
+    }
 }
 
 /* 是否报警 */

+ 6 - 6
SecurePlayAuxServer/Application/FuncIllegalInvasion.h

@@ -29,7 +29,7 @@ struct RoomIllegalInvasionInfo
 {
     bool isAlarm = false;                   /* 是否在报警 */
     int RoomID = 0;                         /* 房间ID */
-    int RoomType = 0;                       /* 房间类型 */
+    Enum_RoomType RoomType = Enum_RoomType::ROOM_NONE;/* 房间类型 */
     int numMaxFace = 0;                     /* 最大人脸数 */
     int numMaxPerson = 0;                   /* 最大人员数 */
     int CameraID = 0;                       /* 摄像机ID,这个存储的是使用的哪个报警信息的ID */
@@ -53,9 +53,9 @@ struct ListRoomIll
 
     std::list<RoomIllegalInvasionInfo>& getData() { return listRoomIll; }
     /* 添加房间 */
-    void addRoom(int RoomID, int RoomType);
+    void addRoom(int RoomID, Enum_RoomType RoomType);
     /* 查找是否有相同的房间 */
-    RoomIllegalInvasionInfo* findRoom(int RoomID, int RoomType);
+    RoomIllegalInvasionInfo* findRoom(int RoomID, Enum_RoomType RoomType);
 };
 
 /**
@@ -69,7 +69,7 @@ struct IllegalInvasionInfo
     int CameraID = 0;
     int RoomID = 0;
     int ChannelID = 0;
-    int RoomType = 0;                   /* 房间类型 */
+    Enum_RoomType RoomType = Enum_RoomType::ROOM_NONE;/* 房间类型 */
     QDateTime FirstTime;                /* 最开始的报警时间 */
     std::string strActionDec;           /* 算法描述 */
     std::string strImageInfo;           /* 图片信息 */
@@ -92,10 +92,10 @@ struct ListIllegalInvasionInfo
     void addIllInfo(IllegalInvasionInfo& info);
     /* 查找相同的信息 */
     IllegalInvasionInfo* findIllInfo(IllegalInvasionInfo& info);
-    IllegalInvasionInfo* findIllInfo(int roomID, int roomType);
+    IllegalInvasionInfo* findIllInfo(int roomID, Enum_RoomType roomType);
     /* 删除报警信息 */
     void deleteIllInfo(IllegalInvasionInfo& info);
-    void deleteIllInfo(int roomID, int roomType);
+    void deleteIllInfo(int roomID, Enum_RoomType roomType);
 };
  
 

+ 184 - 14
SecurePlayAuxServer/Application/FuncOnAndOffJob.cpp

@@ -13,7 +13,7 @@
 DecCondition::DecCondition()
 {
     ChannelID = -1;
-    leaveNum = 0;
+    leaveTimeMaxNum = 0;
     leaveNumOnTime = 0;
     leaveOneTime = 0;
 }
@@ -21,7 +21,7 @@ DecCondition::DecCondition()
 DecCondition::DecCondition(const DecCondition& other)
 {
     ChannelID = other.ChannelID;
-    leaveNum = other.leaveNum;
+    leaveTimeMaxNum = other.leaveTimeMaxNum;
     leaveNumOnTime = other.leaveNumOnTime;
     leaveOneTime = other.leaveOneTime;
 }
@@ -31,7 +31,7 @@ DecCondition& DecCondition::operator=(const DecCondition& other)
     if (this != &other)
     {
         ChannelID = other.ChannelID;
-        leaveNum = other.leaveNum;
+        leaveTimeMaxNum = other.leaveTimeMaxNum;
         leaveNumOnTime = other.leaveNumOnTime;
         leaveOneTime = other.leaveOneTime;
     }
@@ -46,7 +46,7 @@ RoomOnWorkInfo::RoomOnWorkInfo()
     ChannelID = 0;
     RoomID = 0;
     CameraID = 0;
-    RoomType = 0;
+    RoomType = Enum_RoomType::ROOM_NONE;
     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");
@@ -101,7 +101,7 @@ void RoomOnWorkInfo::clear()
     ChannelID = 0;
     RoomID = 0;
     CameraID = 0;
-    RoomType = 0;
+    RoomType = Enum_RoomType::ROOM_NONE;
     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");
@@ -248,7 +248,11 @@ FuncOnAndOffJob::FuncOnAndOffJob()
 
 FuncOnAndOffJob::~FuncOnAndOffJob()
 {
-
+    if(m_pListAlarm != nullptr)
+    {
+        delete m_pListAlarm;
+        m_pListAlarm = nullptr;
+    }
 }
 
 
@@ -276,14 +280,14 @@ void FuncOnAndOffJob::task()
         for(auto& it : m_funcThreadInfo.listRoomCamActInfo)
         {
             /* 判断是不是直播间 */
-            if(it.RoomType == GConfig.liveRoomType)
+            if(it.RoomType == Enum_RoomType::ROOM_LIVE)
             {
                 mapRoomCamActInfo.insert(std::make_pair(it.RoomID, it));
             }
         }
 
         /* 获取当前频率的在岗离岗信息,在表格“tChannel”中 */
-        if(!getCurrentFrequencyInfo(m_funcThreadInfo.ChannelID, m_nowChnDecCondition))
+        if(!getCurrentFrequencyInfo(m_funcThreadInfo.ChannelID, m_nowChnDetecRule))
         {
             SPDLOG_LOGGER_ERROR(m_logger, "获取当前频率信息失败, ChannelID:{}", m_funcThreadInfo.ChannelID);
             std::this_thread::sleep_for(std::chrono::milliseconds(GConfig.ThreadSleepMS));
@@ -407,11 +411,10 @@ void FuncOnAndOffJob::task()
             } else 
             {
                 /* 离岗 */
+                offWorkProcess(pRoomOnWorkInfo, roomInfo);
             }
 
         }
-
-
     }
 
 }
@@ -456,7 +459,16 @@ bool FuncOnAndOffJob::getCurrentFrequencyInfo(const int ChannelID, DecCondition&
 
 /**
  * @brief 人员在岗情况处理
- * 
+            1、判断上次是在岗还是离岗
+                (1) 上次是离岗,结束离岗报警,需要判断是否已经写入数据库
+                    1) 已经写入数据库,更新数据库报警记录,更新结束时间,清空内存中的报警记录,主要是清空PKID,置为0
+                    2) 还未写入数据库,打印个日志,不需要做什么操作
+                (2) 上次是在岗,更新数据,主要是更新图片
+                    1) 如果上次在岗记录已经写入数据库,判断人脸列表是否相等
+                        1) 不相等,更新数据库
+                        2) 相等,更新在岗时间
+                    2) 如果上次在岗记录还未写入数据库,直接写入数据库
+  
  * @param pRoomOnWorkInfo 这个是内存中的记录,是历史记录
  * @param roomInfo 
  */
@@ -514,7 +526,7 @@ void FuncOnAndOffJob::onWorkProcess(RoomOnWorkInfo* pRoomOnWorkInfo, std::pair<c
             }
             alarmInfo.listBbox = getCameraNameList(roomInfo.second.mapCameraAction);    /* 直播间摄像机列表 */
             alarmInfo.ImageInfo = pRoomOnWorkInfo->strImagePath;
-            alarmInfo.StartTime = pRoomOnWorkInfo->StartTime.toString("yyyy-MM-dd hh:mm:ss").toStdString();
+            alarmInfo.EventTime = pRoomOnWorkInfo->StartTime.toString("yyyy-MM-dd hh:mm:ss").toStdString();
             alarmInfo.ActionID = "";
             alarmInfo.Is_OnWork = true;
             alarmInfo.listPersonInfo = pRoomOnWorkInfo->listPersonInfo;
@@ -571,7 +583,19 @@ void FuncOnAndOffJob::onWorkProcess(RoomOnWorkInfo* pRoomOnWorkInfo, std::pair<c
 }
 
 
-/* 人员离岗情况 */
+/**
+ * @brief 人员离岗情况处理
+            1、判断上次是在岗还是离岗
+                (1) 上次是在岗,开启离岗报警,然后判断是否已经写入数据库,更新离岗时间
+                    1) 已经写入数据库,更新在岗结束,离岗开始
+                    2) 还未写入数据库,打印个日志,不需要做什么操作
+                (2) 上次是离岗,不需要做啥
+            2、更新在岗离岗状态,主要是更新图片
+            3、判断有没有写入数据库
+  
+ * @param pRoomOnWorkInfo 
+ * @param roomInfo 
+ */
 void FuncOnAndOffJob::offWorkProcess(RoomOnWorkInfo* pRoomOnWorkInfo, std::pair<const int, RoomCamActInfo>& roomInfo)
 {
     if(true == pRoomOnWorkInfo->bOnWork)
@@ -593,7 +617,7 @@ void FuncOnAndOffJob::offWorkProcess(RoomOnWorkInfo* pRoomOnWorkInfo, std::pair<
             SPDLOG_LOGGER_INFO(m_logger, "人员在岗结束,离岗开始,{}", m_strBaseInfo);
         }
 
-        pRoomOnWorkInfo->addOneLeaveTime(m_curTime, m_nowChnDecCondition.leaveTimeMaxNum);
+        pRoomOnWorkInfo->addOneLeaveTime(m_curTime, m_nowChnDetecRule.leaveTimeMaxNum);
         auto strLeaveTime = pRoomOnWorkInfo->getLeaveTimeString();
         if(strLeaveTime != "")
         {
@@ -604,6 +628,124 @@ void FuncOnAndOffJob::offWorkProcess(RoomOnWorkInfo* pRoomOnWorkInfo, std::pair<
         /* 上次是离岗 */
         SPDLOG_LOGGER_DEBUG(m_logger, "{} 没有人员,可能离岗了", m_strBaseInfo);
     }
+    if(!m_nowRoomOnWorkInfo.strImagePath.empty())
+    {
+        pRoomOnWorkInfo->strImagePath = m_nowRoomOnWorkInfo.strImagePath;
+    }
+    /* 判断有没有写入数据库 */
+    if(pRoomOnWorkInfo->PKID == 0)
+    {
+        /* 没有写入数据库,现在写入 */
+        
+        /* 判断单次离岗超时,计算时间差,leaveOneTime设置为0表示不启用检测 */
+        int nLeaveTime = pRoomOnWorkInfo->StartTime.secsTo(m_curTime);
+        if(nLeaveTime > m_nowChnDetecRule.leaveOneTime && m_nowChnDetecRule.leaveOneTime > 0)
+        {
+            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.EventTime = pRoomOnWorkInfo->StartTime.toString("yyyy-MM-dd hh:mm:ss").toStdString();
+            alarmInfo.ActionID = "";
+            alarmInfo.Is_OnWork = false;
+            alarmInfo.listPersonInfo = pRoomOnWorkInfo->listPersonInfo;
+            if(alarmInfo.listPersonInfo.size() > 0)
+            {
+                alarmInfo.ActionDes = fmt::format("离岗人员[{}][{}],人员单次离岗时间超过{}秒", alarmInfo.getFaceIDListString(), alarmInfo.getFaceNameListString(), m_nowChnDetecRule.leaveOneTime);
+            }else {
+                alarmInfo.ActionDes = fmt::format("人员单次离岗时间超过{}秒", m_nowChnDetecRule.leaveOneTime);
+            }
+            /* 写入数据库 */
+            m_fromWebAPI->insertAlarmInfo(alarmInfo, pRoomOnWorkInfo->PKID);
+            if(pRoomOnWorkInfo->PKID > 0)
+            {
+                SPDLOG_LOGGER_INFO(m_logger, "写入离岗报警成功,{}{}", m_strBaseInfo, pRoomOnWorkInfo->getFaceNameListString());
+            }else {
+                SPDLOG_LOGGER_ERROR(m_logger, "写入离岗报警失败,{}", m_strBaseInfo);
+            }
+            pRoomOnWorkInfo->listLeaveTime.clear();
+
+            /* 获取当前频率,应用的报警信息的最大PKID */
+            int maxPKID = 0;
+            m_fromWebAPI->getMaxAlarmPKID(m_funcThreadInfo.ChannelID, m_funcThreadInfo.appFunction, maxPKID);
+            if(maxPKID > 0)
+            {
+                std::string actionDes = "人员离岗了清空在岗人员信息,方便客户端显示";
+                /* 不知道这里为啥要单独获取PKID,按理说用上面返回的即可 */
+                if(m_fromWebAPI->clearOnWorkAlarmInfo(maxPKID, true, actionDes))
+                {
+                    SPDLOG_LOGGER_INFO(m_logger, "☆ {} 人员离岗了清空在岗人员信息,方便客户端显示", m_strBaseInfo);
+                } else {
+                    SPDLOG_LOGGER_ERROR(m_logger, "× {} 人员离岗了清空在岗人员信息失败", m_strBaseInfo);
+                }
+            }
+        }
+
+        /* 判断多次频繁离岗 */
+        if((pRoomOnWorkInfo->listLeaveTime.size() >= m_nowChnDetecRule.leaveNumOnTime) && 
+            (m_nowChnDetecRule.leaveNumOnTime > 0) && (m_nowChnDetecRule.leaveTimeMaxNum > 0))
+        {
+            /* 计算距离第一次离岗时间长度 */
+            int nLeaveTime = pRoomOnWorkInfo->listLeaveTime.front().secsTo(m_curTime);
+            if(nLeaveTime <= m_nowChnDetecRule.leaveOneTime)
+            {
+                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.EventTime = pRoomOnWorkInfo->listLeaveTime.front().toString("yyyy-MM-dd hh:mm:ss").toStdString();
+                alarmInfo.ActionID = "";
+                alarmInfo.Is_OnWork = false;
+                alarmInfo.listPersonInfo = pRoomOnWorkInfo->listPersonInfo;
+                if(alarmInfo.listPersonInfo.size() > 0)
+                {
+                    alarmInfo.ActionDes = fmt::format("离岗人员[{}],人员离岗([]秒内发生{}次离岗)", 
+                        alarmInfo.getFaceNameListString(), m_nowChnDetecRule.leaveOneTime, m_nowChnDetecRule.leaveNumOnTime);
+                }else {
+                    alarmInfo.ActionDes = fmt::format("人员离岗({}秒内发生{}次离岗)", m_nowChnDetecRule.leaveOneTime, m_nowChnDetecRule.leaveNumOnTime);
+                }
+
+                /* 写入数据库报警表 */
+                m_fromWebAPI->insertAlarmInfo(alarmInfo, pRoomOnWorkInfo->PKID);
+                if(pRoomOnWorkInfo->PKID > 0)
+                {
+                    SPDLOG_LOGGER_INFO(m_logger, "写入离岗报警成功,{}{}", m_strBaseInfo, pRoomOnWorkInfo->getFaceNameListString());
+                }else {
+                    SPDLOG_LOGGER_ERROR(m_logger, "写入离岗报警失败,{}", m_strBaseInfo);
+                }
+                pRoomOnWorkInfo->listLeaveTime.clear();
+
+                /* 获取当前频率,应用的报警信息的最大PKID */
+                int maxPKID = 0;
+                m_fromWebAPI->getMaxAlarmPKID(m_funcThreadInfo.ChannelID, m_funcThreadInfo.appFunction, maxPKID);
+                if(maxPKID > 0)
+                {
+                    std::string actionDes = "人员离岗了清空在岗人员信息,方便客户端显示";
+                    /* 不知道这里为啥要单独获取PKID,按理说用上面返回的即可 */
+                    if(m_fromWebAPI->clearOnWorkAlarmInfo(maxPKID, true, actionDes))
+                    {
+                        SPDLOG_LOGGER_INFO(m_logger, "☆ {} 人员离岗了清空在岗人员信息,方便客户端显示", m_strBaseInfo);
+                    } else {
+                        SPDLOG_LOGGER_ERROR(m_logger, "× {} 人员离岗了清空在岗人员信息失败", m_strBaseInfo);
+                    }
+                }
+            }
+        }
+    }
 
 }
 
@@ -635,3 +777,31 @@ std::list<std::string> FuncOnAndOffJob::getCameraNameList(const std::map<int, st
     }
     return listCameraName;
 }
+
+
+/* 创建报警记录 */
+// void FuncOnAndOffJob::createAlarmInfo(RoomOnWorkInfo* pRoomOnWorkInfo, std::pair<const int, RoomCamActInfo>& roomInfo, std::string actionDes, AlarmInfo& alarmInfo)
+// {
+//     if(pRoomOnWorkInfo == nullptr)
+//     {
+//         return;
+//     }
+
+//     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.EventTime = pRoomOnWorkInfo->StartTime.toString("yyyy-MM-dd hh:mm:ss").toStdString();
+//     alarmInfo.ActionID = "";
+//     alarmInfo.Is_OnWork = false;
+//     alarmInfo.listPersonInfo = pRoomOnWorkInfo->listPersonInfo;
+//     alarmInfo.ActionDes = actionDes;
+// }
+
+

+ 7 - 4
SecurePlayAuxServer/Application/FuncOnAndOffJob.h

@@ -5,7 +5,8 @@
 
 /**
  * @brief 在岗离岗检测
- *        理论上一个频率只有一个直播间,直播间内只要有人,且这个人是可以被人脸算法识别到的人,就是在岗
+            1、需要从“tChannel”表中获取在岗离岗的检测规则
+            2、理论上一个频率只有一个直播间,直播间内只要有人,且这个人是可以被人脸算法识别到的人,就是在岗
  * 
  */
 
@@ -20,7 +21,7 @@ struct DecCondition
     std::string strChannelName;     /* 通道名称 */
     int leaveTimeMaxNum;            /* 离岗时间最大个数,给一个限制 */
     int leaveNumOnTime;             /* 一定时间内的离岗次数 */
-    int leaveOneTime;               /* 单次离开报警时间 */
+    int leaveOneTime;               /* 单次离开报警时间,设置为0是不启用 */
 
     DecCondition();
     DecCondition(const DecCondition& other);
@@ -38,7 +39,7 @@ struct DecCondition
     int ChannelID;                          /* 通道ID */
     int RoomID;                             /* 房间ID */
     int CameraID;                           /* 摄像机ID */
-    int RoomType;                           /* 房间类型 */
+    Enum_RoomType RoomType;                 /* 房间类型 */
     std::string strRoomName;                /* 房间名称 */
     QDateTime StartTime;                    /* 开始时间 */
     QDateTime EndTime;                      /* 结束时间 */
@@ -97,6 +98,8 @@ private:
     void deleteNoWorkPerson(std::list<PersonInfo>& listPersonInfo);
     /* 获取当前直播间的摄像机名称列表 */
     std::list<std::string> getCameraNameList(const std::map<int, std::list<std::string>>& mapCameraAction);
+    /* 创建报警记录 */
+    // void createAlarmInfo(RoomOnWorkInfo* pRoomOnWorkInfo, std::pair<const int, RoomCamActInfo>& roomInfo, std::string actionDes, AlarmInfo& alarmInfo);
 
 
 private:
@@ -105,7 +108,7 @@ private:
     // std::map<int, ListAlarmInfo*> m_mapRoomFaceInfo;        /* 人脸识别返回的信息,int是房间ID号 */
     std::map<int, RoomOnWorkInfo*> m_mapRoomOnWorkInfo;      /* 房间在岗信息 */
 
-    DecCondition m_nowChnDecCondition;                      /* 当前频率的在岗检测信息 */
+    DecCondition m_nowChnDetecRule;                         /* 当前频率的在岗离岗的检测规则 */
     RoomOnWorkInfo m_nowRoomOnWorkInfo;                     /* 当前房间在岗信息 */
     std::string m_strBaseInfo;                              /* 基础信息,主要是频率ID和房间ID */
     QDateTime m_curTime;                                    /* 当前时间 */

+ 375 - 0
SecurePlayAuxServer/Application/FuncRegionalPerson.cpp

@@ -0,0 +1,375 @@
+#include "FuncRegionalPerson.h"
+
+#include "FromWebAPI.h"
+#include "FromRedis.h"
+#include "GlobalConfig.h"
+#include "GlobalVariable.h"
+#include "UniversalFunc.h"
+
+
+PersonCountRuleInfo::PersonCountRuleInfo()
+{
+    ChannelID = -1;
+    week = 0;
+    RuleType = Enum_PeriodType::PERIOD_ALL;
+
+    LiveMinEnable = false;
+    LiveMaxEnable = false;
+    DicMinEnable = false;
+    DicMaxEnable = false;
+    LiveDicMinEnable = false;
+    LiveDicMaxEnable = false;
+    LiveMin = 0;
+    LiveMax = 0;
+    DicMin = 0;
+    DicMax = 0;
+    LiveDicMin = 0;
+    LiveDicMax = 0;
+    RuleName = "";
+}
+
+PersonCountRuleInfo& PersonCountRuleInfo::operator=(PersonCountRuleInfo& other)
+{
+    if(this != &other)
+    {
+        ChannelID = other.ChannelID;
+        week = other.week;
+        RuleType = other.RuleType;
+        PeriodName = other.PeriodName;
+        StartTime = other.StartTime;
+        EndTime = other.EndTime;
+
+        LiveMinEnable = other.LiveMinEnable;
+        LiveMaxEnable = other.LiveMaxEnable;
+        DicMinEnable = other.DicMinEnable;
+        DicMaxEnable = other.DicMaxEnable;
+        LiveDicMinEnable = other.LiveDicMinEnable;
+        LiveDicMaxEnable = other.LiveDicMaxEnable;
+        LiveMin = other.LiveMin;
+        LiveMax = other.LiveMax;
+        DicMin = other.DicMin;
+        DicMax = other.DicMax;
+        LiveDicMin = other.LiveDicMin;
+        LiveDicMax = other.LiveDicMax;
+        RuleName = other.RuleName;
+    }
+    return *this;
+}
+
+
+EndAlarmParam::EndAlarmParam()
+{
+    ChannelID = -1;
+    AppID = AppFunction::APP_NONE;
+    CameraID = -1;
+    insertAlarmNum = 0;
+}
+
+EndAlarmParam::EndAlarmParam(const EndAlarmParam& other)
+{
+    ChannelID = other.ChannelID;
+    AppID = other.AppID;
+    CameraID = other.CameraID;
+    insertAlarmNum = other.insertAlarmNum;
+}
+
+EndAlarmParam& EndAlarmParam::operator=(const EndAlarmParam& other)
+{
+    if(this != &other)
+    {
+        ChannelID = other.ChannelID;
+        AppID = other.AppID;
+        CameraID = other.CameraID;
+        insertAlarmNum = other.insertAlarmNum;
+    }
+    return *this;
+}
+
+bool EndAlarmParam::operator==(const EndAlarmParam& other)
+{
+    if(this == &other)
+    {
+        return true;
+    }
+    if(ChannelID != other.ChannelID)
+    {
+        return false;
+    }
+    if(AppID != other.AppID)
+    {
+        return false;
+    }
+    if(CameraID != other.CameraID)
+    {
+        return false;
+    }
+    if(insertAlarmNum != other.insertAlarmNum)
+    {
+        return false;
+    }
+    return true;
+}
+
+
+
+
+FuncRegionalPersonCount::FuncRegionalPersonCount()
+{
+    m_logger = spdlog::get("SPAServer");
+    if(m_logger == nullptr)
+    {
+        SPDLOG_ERROR("SPAServer logger is nullptr");
+        return;
+    }
+    m_pListAlarm = new ListAlarmInfo();
+    if(m_pListAlarm == nullptr)
+    {
+        SPDLOG_ERROR("FuncRegionalPersonDetection m_pListAlarm is nullptr");
+        return;
+    }
+}
+
+FuncRegionalPersonCount::~FuncRegionalPersonCount()
+{
+    if(m_pListAlarm != nullptr)
+    {
+        delete m_pListAlarm;
+        m_pListAlarm = nullptr;
+    }
+}
+
+
+void FuncRegionalPersonCount::task()
+{
+    
+    
+    while (m_bRunning)
+    {
+        std::this_thread::sleep_for(std::chrono::milliseconds(GConfig.ThreadSleepMS));
+        /* 更新线程信息,并判断是否需要退出 */
+        GThreadInfo.updateFuncInfo(m_funcThreadInfo);
+        if( (m_funcThreadInfo.appFunction == AppFunction::APP_NONE) ||
+            (m_funcThreadInfo.RunState == RunTimeState::RUN_STATE_STOP) )
+        {
+            break;
+        }
+        
+        /* 判断是否在检测时间段内 */
+        // if(!isInDetectTime(m_funcThreadInfo.StartTime, m_funcThreadInfo.EndTime))
+        // {
+        //     continue;
+        // }
+
+        /* 更新报警规则 */
+        if(!getPersonCountRuleInfo(m_personCountRule))
+        {
+            /* 判断报警是否已经结束,没有结束就结束报警 */
+            autoEndAlarm();
+            continue;
+        }
+
+        m_nowTime = QDateTime::currentDateTime();
+        /************ 判断是否在检测时间内 ************/
+        if(!isInPeriodTime())
+        {
+            SPDLOG_LOGGER_INFO(m_logger, "★ 频道[{}][{}],{},不在检测时段", 
+                                m_funcThreadInfo.ChannelID, m_funcThreadInfo.strChannelName, 
+                                getAppFunctionName(m_funcThreadInfo.appFunction));
+            /* 判断报警是否已经结束,没有结束就结束报警 */
+            autoEndAlarm();
+            continue;
+        }
+
+        /* 更新房间列表 */
+        updateRoomList();
+        if(m_listRoomCamAct.empty())
+        {
+            SPDLOG_LOGGER_ERROR(m_logger, "★ 频道[{}][{}],{},房间列表为空", 
+                                m_funcThreadInfo.ChannelID, m_funcThreadInfo.strChannelName, 
+                                getAppFunctionName(m_funcThreadInfo.appFunction));
+            /* 判断报警是否已经结束,没有结束就结束报警 */
+            autoEndAlarm();
+            continue;
+        }
+        
+
+        /* -----------------------------------------------------------------------
+         * 读取Redis数据 
+         * ----------------------------------------------------------------------- */
+        m_pListAlarm->clearAlarmInfo();
+
+        for(const auto& RoomInfo : m_listRoomCamAct)
+        {
+            for(const auto& it : RoomInfo.mapCameraAction)
+            {
+                for(const auto& act : it.second)
+                {
+                    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);
+                        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;
+                    }
+                    m_pListAlarm->addAlarmInfo(alarmInfo);
+                }
+            }
+        }
+
+        /************ 挨个房间检测人数 ************/
+        
+
+        /************ 检测频率直播间 + 导播间房间的人数 ************/
+
+    }
+
+}
+
+/* 获取该频率的人员计数规则 */
+bool FuncRegionalPersonCount::getPersonCountRuleInfo(PersonCountRuleInfo& personCountRuleInfo)
+{
+    std::list<PersonCountRuleInfo> listRule;
+    if(!m_fromWebAPI->getPersonCountRuleInfo(listRule))
+    {
+        SPDLOG_LOGGER_ERROR(m_logger, "获取《人员计数》报警规则失败");
+        return false;
+    }
+    if(listRule.size() == 0)
+    {
+        SPDLOG_LOGGER_ERROR(m_logger, "★ 频道[{}][{}],{},未配置人员计数规则", 
+                            m_funcThreadInfo.ChannelID, m_funcThreadInfo.strChannelName, 
+                            getAppFunctionName(m_funcThreadInfo.appFunction));
+        return false;
+    }
+    /* 获取这个频率的报警信息 */
+    m_personCountRule.ChannelID = -1;
+    for(auto& it : listRule)
+    {
+        if(it.ChannelID == m_funcThreadInfo.ChannelID)
+        {
+            m_personCountRule = it;
+            break;
+        }
+    }
+    if(m_personCountRule.ChannelID == -1)
+    {
+        SPDLOG_LOGGER_ERROR(m_logger, "频率:{}《人员计数》无报警规则", m_funcThreadInfo.ChannelID);
+        return false;
+    }
+
+    return true;
+}
+
+/* 判断是否在检测时间段内 */
+bool FuncRegionalPersonCount::isInPeriodTime()
+{
+    /* 所有时段 */
+    if(m_personCountRule.RuleType == Enum_PeriodType::PERIOD_ALL)
+    {
+        return true;
+    }
+    /* 按天检测 */
+    else if(m_personCountRule.RuleType == Enum_PeriodType::PERIOD_DAY)
+    {
+        if(m_personCountRule.StartTime <= m_nowTime && m_personCountRule.EndTime >= m_nowTime)
+        {
+            /* 在检测时间内 */
+            return true;
+        } else {
+            /* 不在检测时间内 */
+            return false;
+        }
+    }
+    /* 按周检测 */
+    else if (m_personCountRule.RuleType == Enum_PeriodType::PERIOD_WEEK)
+    {
+        if(m_personCountRule.week != m_nowTime.date().dayOfWeek())
+        {
+            /* 一周日期不相等 */
+            return false;
+        }
+        /* 判断周日期是否相等 */
+        if(m_personCountRule.StartTime.time() <= m_nowTime.time() && m_personCountRule.EndTime.time() >= m_nowTime.time())
+        {
+            return true;
+        } else {
+            /* 不在检测时间内 */
+            return false;
+        }
+    }
+
+    return true;
+}
+
+
+/* 更新房间列表 */
+void FuncRegionalPersonCount::updateRoomList()
+{
+    /* 清空房间列表 */
+    m_listRoomCamAct.clear();
+    for(const auto& it : m_funcThreadInfo.listRoomCamActInfo)
+    {
+        /* 只添加直播间和导播间 */
+        if(it.RoomType == Enum_RoomType::ROOM_LIVE || it.RoomType == Enum_RoomType::ROOM_DIC)
+        {
+            m_listRoomCamAct.push_back(it);
+        }
+    }
+    
+}
+
+
+/* 自动结束报警 */
+void FuncRegionalPersonCount::autoEndAlarm()
+{
+    EndAlarmParam alarmParam;
+    alarmParam.ChannelID = m_funcThreadInfo.ChannelID;
+    alarmParam.AppID = m_funcThreadInfo.appFunction;
+    /* 判断报警是否已经结束,没有结束就结束报警 */
+    if(findAlarmEnd(alarmParam))
+    {
+        SPDLOG_LOGGER_DEBUG(m_logger, "频率:{}《人员计数》报警已经结束", m_funcThreadInfo.strChannelName);
+        return;
+    }
+    if(!m_fromWebAPI->endPersonCountAlarm(alarmParam))
+    {
+        SPDLOG_LOGGER_ERROR(m_logger, "频率:{}《人员计数》结束报警失败", m_funcThreadInfo.strChannelName);
+        return;
+    }
+    /* 记录已经结束报警的信息,限制一下记录列表的大小 */
+    if(m_listEndAlarmPara.size() > 1024)
+    {
+        m_listEndAlarmPara.clear();
+    }
+    m_listEndAlarmPara.push_back(alarmParam);
+    
+}
+
+/* 查找是否已经结束了报警 */
+bool FuncRegionalPersonCount::findAlarmEnd(EndAlarmParam& alarmParam)
+{
+    if(m_listEndAlarmPara.empty())
+    {
+        return false;
+    }
+    for(auto& it : m_listEndAlarmPara)
+    {
+        if(it == alarmParam)
+        {
+            return true;
+        }
+    }
+    return false;
+}
+
+

+ 107 - 0
SecurePlayAuxServer/Application/FuncRegionalPerson.h

@@ -0,0 +1,107 @@
+#ifndef FUNCREGIONALPERSON_H
+#define FUNCREGIONALPERSON_H
+
+#include "FuncBase.h"
+
+
+enum class Enum_PeriodType
+{
+    PERIOD_ALL = 0,         /* 所有时段 */
+    PERIOD_DAY,             /* 按天 */
+    PERIOD_WEEK,            /* 按周 */
+};
+
+/**
+ * @brief 报警规则
+ * 
+ */
+struct PersonCountRuleInfo
+{
+    int ChannelID;              /* 通道ID */
+    std::string PeriodName;     /* 时间段名称 */
+    QDateTime StartTime;        /* 开始时间 */
+    QDateTime EndTime;          /* 结束时间 */
+    int week;                   /* 星期 */
+    Enum_PeriodType RuleType;   /* 规则类型,0表示所有时段,1表示按天,2表示按周 */
+
+    bool LiveMinEnable;         /* 启用直播间最小人数 */
+    bool LiveMaxEnable;         /* 启用直播间最大人数 */
+    bool DicMinEnable;          /* 启用导播间最小人数 */
+    bool DicMaxEnable;          /* 启用导播间最大人数 */
+    bool LiveDicMinEnable;      /* 启用直播间和导播间最小人数 */
+    bool LiveDicMaxEnable;      /* 启用直播间和导播间最大人数 */
+    int LiveMin;                /* 直播间最小人数 */
+    int LiveMax;                /* 直播间最大人数 */
+    int DicMin;                 /* 导播间最小人数 */
+    int DicMax;                 /* 导播间最大人数 */
+    int LiveDicMin;             /* 直播间和导播间最小人数 */
+    int LiveDicMax;             /* 直播间和导播间最大人数 */
+    std::string RuleName;       /* 规则名称 */
+
+    PersonCountRuleInfo();
+    PersonCountRuleInfo& operator=(PersonCountRuleInfo& other);
+};
+
+/**
+ * @brief 报警参数
+ * 
+ */
+struct EndAlarmParam
+{
+    int ChannelID;              /* 通道ID */
+    AppFunction AppID;          /* 应用功能 */
+    int CameraID;               /* 摄像机ID */
+    uint64_t insertAlarmNum;    /* 报警编号?PKID? */ 
+
+    EndAlarmParam();
+    EndAlarmParam(const EndAlarmParam& other);
+    EndAlarmParam& operator=(const EndAlarmParam& other);
+    bool operator==(const EndAlarmParam& other);
+};
+
+
+
+/**
+ * @brief 区域人员检测,检测这个区域内的人数,不能少于多少人,不能多余多少人
+ *          1、报警判断条件:直播间报警:当前频率所有直播间摄像头的区域人员检测算法输出结果均大于或小于设定人
+               数值时,记为报警行为,直接展示报警结果
+            2、录播间报警:当前频率所有录播间摄像头的区域人员检测算法输出结果均大于或小于设定人数值时,记为报
+               警行为,直接展示报警结果
+            3、直播间+录播间报警:当前频率直播间人数+录播间人数大于或小于设定人数值时,记为报警行为,直接展示
+               报警结果
+ * 
+ */
+class FuncRegionalPersonCount : public FuncBase
+{
+public:
+    FuncRegionalPersonCount();
+    ~FuncRegionalPersonCount();
+
+protected:
+    void task() override;
+
+private:
+    /* 获取该频率的人员计数规则 */
+    bool getPersonCountRuleInfo(PersonCountRuleInfo& personCountRuleInfo);
+    /* 判断是否在检测时间段内 */
+    bool isInPeriodTime();
+    /* 更新房间列表 */
+    void updateRoomList();
+
+    /* 自动结束报警 */
+    void autoEndAlarm();
+    /* 查找是否已经结束了报警 */
+    bool findAlarmEnd(EndAlarmParam& alarmParam);
+
+
+private:
+    ListAlarmInfo* m_pListAlarm = nullptr;                      /* 报警信息 */
+    std::list<RoomCamActInfo> m_listRoomCamAct;                 /* 房间和算法ID关联列表,这里存储的是直播间和导播间的房间信息 */
+    PersonCountRuleInfo m_personCountRule;                      /* 人员计数规则 */
+    QDateTime m_nowTime;                                        /* 当前时间 */
+
+    std::list<EndAlarmParam> m_listEndAlarmPara;                /* 报警列表 */
+};
+
+
+#endif /* FUNCREGIONALPERSON_H */

+ 0 - 3
SecurePlayAuxServer/GlobalInfo/GlobalConfig.h

@@ -29,9 +29,6 @@ public:
         return gc;
     }
 
-    const int liveRoomType = 1;             /* 直播间类型 */
-    const int dicRoomType = 2;              /* 导播间类型 */
-
     /* 读取配置文件 */
     bool readConfig(const QString& strConfigFile);
     /* 打印读取到的值 */

+ 15 - 52
SecurePlayAuxServer/GlobalInfo/GlobalVariable.cpp

@@ -88,7 +88,7 @@ AlarmInfo::AlarmInfo()
     EventTime = "";
     PicUrl = "";
     ImageInfo = "";
-    AppID = "";
+    // AppID = "";
     ActionID = "";
     ActionDes = "";
     FaceIDList = "";
@@ -115,7 +115,7 @@ AlarmInfo::AlarmInfo(const AlarmInfo& other)
     EventTime = other.EventTime;
     PicUrl = other.PicUrl;
     ImageInfo = other.ImageInfo;
-    AppID = other.AppID;
+    // AppID = other.AppID;
     ActionID = other.ActionID;
     ActionDes = other.ActionDes;
     FaceIDList = other.FaceIDList;
@@ -143,7 +143,7 @@ AlarmInfo& AlarmInfo::operator=(AlarmInfo& other)
         EventTime = other.EventTime;
         PicUrl = other.PicUrl;
         ImageInfo = other.ImageInfo;
-        AppID = other.AppID;
+        // AppID = other.AppID;
         ActionID = other.ActionID;
         ActionDes = other.ActionDes;
         FaceIDList = other.FaceIDList;
@@ -172,7 +172,7 @@ void AlarmInfo::reInit()
     EventTime = "";
     PicUrl = "";
     ImageInfo = "";
-    AppID = "";
+    // AppID = "";
     ActionID = "";
     ActionDes = "";
     FaceIDList = "";
@@ -276,6 +276,16 @@ void ListAlarmInfo::deleteAlarmInfo(AlarmInfo& info)
     }
 }
 
+/* 清空报警记录 */
+void ListAlarmInfo::clearAlarmInfo()
+{
+    for(auto& it : listAlarmInfo)
+    {
+        delete it;
+    }
+    listAlarmInfo.clear();
+}
+
 
 /* 查找是否有相同的人脸信息 */
 bool RoomFaceInfo::findPersonInfo(const PersonInfo& info)
@@ -359,54 +369,7 @@ RoomFaceInfo* ListRoomFaceInfo::findRoomFaceInfo(int ChannelID, int RoomID, int
 
 
 
-PersonCountRuleInfo::PersonCountRuleInfo()
-{
-    ChannelID = -1;
-    week = 0;
-    RuleType = 0;
-
-    LiveMinEnable = false;
-    LiveMaxEnable = false;
-    DicMinEnable = false;
-    DicMaxEnable = false;
-    LiveDicMinEnable = false;
-    LiveDicMaxEnable = false;
-    LiveMin = 0;
-    LiveMax = 0;
-    DicMin = 0;
-    DicMax = 0;
-    LiveDicMin = 0;
-    LiveDicMax = 0;
-    RuleName = "";
-}
-
-PersonCountRuleInfo& PersonCountRuleInfo::operator=(PersonCountRuleInfo& other)
-{
-    if(this != &other)
-    {
-        ChannelID = other.ChannelID;
-        week = other.week;
-        RuleType = other.RuleType;
-        PeriodName = other.PeriodName;
-        StartTime = other.StartTime;
-        EndTime = other.EndTime;
 
-        LiveMinEnable = other.LiveMinEnable;
-        LiveMaxEnable = other.LiveMaxEnable;
-        DicMinEnable = other.DicMinEnable;
-        DicMaxEnable = other.DicMaxEnable;
-        LiveDicMinEnable = other.LiveDicMinEnable;
-        LiveDicMaxEnable = other.LiveDicMaxEnable;
-        LiveMin = other.LiveMin;
-        LiveMax = other.LiveMax;
-        DicMin = other.DicMin;
-        DicMax = other.DicMax;
-        LiveDicMin = other.LiveDicMin;
-        LiveDicMax = other.LiveDicMax;
-        RuleName = other.RuleName;
-    }
-    return *this;
-}
 
 /* ====================================================================================
  * **************************    ListActionInfo成员函数    ****************************
@@ -418,7 +381,7 @@ ActionInfo::ActionInfo()
     ChannelID = -1;
     RoomID = -1;
     CameraID = -1;
-    RoomType = -1;
+    RoomType = Enum_RoomType::ROOM_NONE;
     ActionID = "";
     strRoomName = "";
     strActionName = "";

+ 18 - 36
SecurePlayAuxServer/GlobalInfo/GlobalVariable.h

@@ -56,6 +56,17 @@ enum class AppFunction
     APP_AllDown,                /* 摔倒识别 */
 };
 
+/**
+ * @brief 房间类型
+ * 
+ */
+enum class Enum_RoomType
+{
+    ROOM_NONE = 0,              /* 无房间 */
+    ROOM_LIVE = 1,              /* 直播间 */
+    ROOM_DIC = 2,               /* 导播间 */
+    ROOM_ALL = 3,               /* 所有房间 */
+};
 
 /**
  * @brief 全局算法列表,理论上算法ID是不会变的,但是现在好像是变化的,暂时还不知道从哪里区分
@@ -256,7 +267,7 @@ struct AlarmInfo
     std::string EventTime;      /* 事件时间(报警发生时间,在数据库里对应的是CreateTime) */
     std::string PicUrl;         /* 报警图片URL */
     std::string ImageInfo;      /* 图片信息 */
-    std::string AppID;          /* 客户端应用ID */
+    // std::string AppID;          /* 客户端应用ID */
     std::string ActionDes;      /* 算法描述信息 */
     std::string FaceIDList;     /* 人脸ID列表 */
     std::string FaceNameList;   /* 人脸名称列表 */
@@ -288,6 +299,8 @@ struct ListAlarmInfo
     AlarmInfo* findAlarmInfo(AlarmInfo& info);
     /* 删除报警记录 */
     void deleteAlarmInfo(AlarmInfo& info);
+    /* 清空报警记录 */
+    void clearAlarmInfo();
 };
 
 
@@ -341,36 +354,6 @@ struct ListRoomFaceInfo
 
 
 
-/**
- * @brief 报警规则
- * 
- */
-struct PersonCountRuleInfo
-{
-    int ChannelID;              /* 通道ID */
-    std::string PeriodName;     /* 时间段名称 */
-    QDateTime StartTime;        /* 开始时间 */
-    QDateTime EndTime;          /* 结束时间 */
-    int week;                   /* 星期 */
-    int RuleType;               /* 规则类型,0表示所有时段,1表示按天,2表示按周 */
-
-    bool LiveMinEnable;         /* 启用直播间最小人数 */
-    bool LiveMaxEnable;         /* 启用直播间最大人数 */
-    bool DicMinEnable;          /* 启用导播间最小人数 */
-    bool DicMaxEnable;          /* 启用导播间最大人数 */
-    bool LiveDicMinEnable;      /* 启用直播间和导播间最小人数 */
-    bool LiveDicMaxEnable;      /* 启用直播间和导播间最大人数 */
-    int LiveMin;                /* 直播间最小人数 */
-    int LiveMax;                /* 直播间最大人数 */
-    int DicMin;                 /* 导播间最小人数 */
-    int DicMax;                 /* 导播间最大人数 */
-    int LiveDicMin;             /* 直播间和导播间最小人数 */
-    int LiveDicMax;             /* 直播间和导播间最大人数 */
-    std::string RuleName;       /* 规则名称 */
-
-    PersonCountRuleInfo();
-    PersonCountRuleInfo& operator=(PersonCountRuleInfo& other);
-};
 
 /**
  * @brief 房间和摄像机关联信息,这个是从客户端配置的
@@ -415,7 +398,7 @@ struct ActionInfo
     int ChannelID;                  /* 通道ID */
     int RoomID;                     /* 房间ID */
     int CameraID;                   /* 摄像机ID */
-    int RoomType;                   /* 房间类型 */
+    Enum_RoomType RoomType;         /* 房间类型 */
     std::string ActionID;           /* 算法ID */
     std::string strRoomName;        /* 房间名称 */
     std::string strActionName;      /* 算法名称,这个是自定义的,不需要对比 */
@@ -472,7 +455,7 @@ struct RoomActionInfo
 {
     int ChannelID;                  /* 通道ID */
     int RoomID;                     /* 房间ID */
-    int RoomType;                   /* 房间类型 */
+    Enum_RoomType RoomType;         /* 房间类型 */
     std::string ActionID;           /* 算法ID */
     std::string strRoomName;        /* 房间名称 */
     std::list<int> listCameraID;    /* 摄像机ID */
@@ -480,7 +463,7 @@ struct RoomActionInfo
     RoomActionInfo() {
         ChannelID = -1;
         RoomID = -1;
-        RoomType = -1;
+        RoomType = Enum_RoomType::ROOM_NONE;
         ActionID = "";
         strRoomName = "";
         listCameraID.clear();
@@ -546,9 +529,8 @@ public:
  struct RoomCamActInfo
  {
     int RoomID;                         /* 房间ID */
-    int RoomType;                       /* 房间类型 */
+    Enum_RoomType RoomType;             /* 房间类型 */
     std::string strRoomName;            /* 房间名称 */
-    // std::multimap<int, std::string> mapCameraAction;    /* 摄像机ID和算法ID关联信息 */
     std::map<int, std::list<std::string>> mapCameraAction;    /* 摄像机ID和算法ID关联信息,一个摄像机可以有多个算法列表 */
 
     /* 添加摄像机算法 */

+ 41 - 0
SecurePlayAuxServer/GlobalInfo/UniversalFunc.cpp

@@ -1,6 +1,7 @@
 #include "UniversalFunc.h"
 
 #include "spdlog/spdlog.h"
+#include "GlobalVariable.h"
 
 /**
  * @brief 解析Redis的基础通用数据,不包含bBoxes数组数据
@@ -228,3 +229,43 @@ std::string chronoToStrTime(const std::chrono::system_clock::time_point& timePoi
 }
 
 
+/* 通过应用ID获取应用名称 */
+std::string getAppFunctionName(const AppFunction appID)
+{
+    std::string strRet;
+    switch(appID)
+    {
+    case AppFunction::APP_OnWork:
+        strRet = "人员在岗识别";
+        break;
+    case AppFunction::APP_Contraband:
+        strRet = "违禁物品识别";
+        break;
+    case AppFunction::APP_Illegal:
+        strRet = "区域非法入侵检测";
+        break;
+    case AppFunction::APP_Fatigue:
+        strRet = "疲劳检测识别";
+        break;
+    case AppFunction::APP_Regional:
+        strRet = "区域人员统计";
+        break;
+    case AppFunction::APP_Mouse:
+        strRet = "老鼠识别";
+        break;
+    case AppFunction::APP_PlayPhone:
+        strRet = "玩手机识别";
+        break;
+    case AppFunction::APP_NoMask:
+        strRet = "未戴口罩识别";
+        break;
+    case AppFunction::APP_AllDown:
+        strRet = "摔倒识别";
+        break;
+    default:
+        strRet = "未知功能";
+        break;
+    }
+    return strRet;
+}
+

+ 3 - 0
SecurePlayAuxServer/GlobalInfo/UniversalFunc.h

@@ -23,5 +23,8 @@ std::chrono::system_clock::time_point strTimeToChrono(const std::string& strTime
 /* 时间点转换成字符串 */
 std::string chronoToStrTime(const std::chrono::system_clock::time_point& timePoint);
 
+/* 通过应用ID获取应用名称 */
+std::string getAppFunctionName(const AppFunction appID);
+
 
 #endif // UNIVERSALFUNC_H

+ 0 - 143
SecurePlayAuxServer/SPAServer.cpp

@@ -623,147 +623,4 @@ void SPAServer::clearNoneFuncThreadInfo()
 
 
 
-/**
- * @brief 区域人员检测,检测这个区域内的人数,不能少于多少人,不能多余多少人
- *          1、报警判断条件:直播间报警:当前频率所有直播间摄像头的区域人员检测算法输出结果均大于或小于设定人
-               数值时,记为报警行为,直接展示报警结果
-            2、录播间报警:当前频率所有录播间摄像头的区域人员检测算法输出结果均大于或小于设定人数值时,记为报
-               警行为,直接展示报警结果
-            3、直播间+录播间报警:当前频率直播间人数+录播间人数大于或小于设定人数值时,记为报警行为,直接展示
-               报警结果
- * 
- * @param RAInfo 传入的房间ID和算法ID
- */
-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<FromWebAPI> fromWebAPI = std::make_shared<FromWebAPI>();
-    /* 局部变量,线程功能需要的信息 */
-    std::shared_ptr<FuncThreadInfo> pRFAInfo = std::make_shared<FuncThreadInfo>();
-    *pRFAInfo = *RFAInfo;
-    /* 保存每个摄像机的报警信息 */
-    std::shared_ptr<std::list<AlarmInfo>> pListAlarmInfo = std::make_shared<std::list<AlarmInfo>>();
-    /* 报警时间段 */
-    std::shared_ptr<std::vector<PersonCountRuleInfo>> pPersonCountRuleInfo = std::make_shared<std::vector<PersonCountRuleInfo>>();
-
-    /* 获取报警规则信息 */
-    fromWebAPI->getPersonCountRuleInfo(*pPersonCountRuleInfo);
-    
-    while (m_threadRunning)
-    {
-        std::this_thread::sleep_for(std::chrono::milliseconds(GConfig.ThreadSleepMS));
-        /************ 更新线程信息 ************/
-        GThreadInfo.updateFuncInfo(pRFAInfo.get());
-        if(pRFAInfo->appFunction == AppFunction::APP_NONE)
-        {
-            break;
-        }
-
-        /************ 读取Redis数据 ************/
-        pListAlarmInfo->clear();
-        for(const auto& RoomInfo : pRFAInfo->listRoomCamActInfo)
-        {
-            for(const auto& it : RoomInfo.mapCameraAction)
-            {
-                for(const auto& act : it.second)
-                {
-                    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);
-                }
-            }
-        }
-        /************ 获取报警规则(从数据库更新?) ************/
-        if(!fromWebAPI->getPersonCountRuleInfo(*pPersonCountRuleInfo))
-        {
-            SPDLOG_LOGGER_ERROR(m_logger, "《人员计数》获取报警规则失败");
-            continue;
-        }
-        if(pPersonCountRuleInfo->size() == 0)
-        {
-            SPDLOG_LOGGER_ERROR(m_logger, "《人员计数》无报警规则");
-            break;
-        }
-        /* 获取这个频率的报警信息 */
-        PersonCountRuleInfo personCountRuleInfo;
-        for(auto& it : *pPersonCountRuleInfo)
-        {
-            if(it.ChannelID == pRFAInfo->ChannelID)
-            {
-                personCountRuleInfo = it;
-                break;
-            }
-        }
-        if(personCountRuleInfo.ChannelID < 0)
-        {
-            SPDLOG_LOGGER_ERROR(m_logger, "《人员计数》获取报警规则失败, ChannelID:{}", pRFAInfo->ChannelID);
-            break;
-        }
-
-        /************ 判断是否在检测时间内 ************/
-        QDateTime now = QDateTime::currentDateTime();
-        /* 判断检测时间类型 */
-        if(personCountRuleInfo.RuleType == 0)
-        {
-            /* 所有时段 */
-        }
-        else if(personCountRuleInfo.RuleType == 1)
-        {
-            /* 按天检测 */
-            if(personCountRuleInfo.StartTime <= now && personCountRuleInfo.EndTime >= now)
-            {
-                /* 在检测时间内 */
-            } else
-            {
-                /* 不在检测时间内 */
-                continue;
-            }
-        }
-        else if (personCountRuleInfo.RuleType == 2)
-        {
-            /* 按周检测 */
-            if(personCountRuleInfo.week != now.date().dayOfWeek())
-            {
-                /* 不在检测时间内 */
-                continue;
-            }
-            /* 在检测时间内 */
-            if(personCountRuleInfo.StartTime.time() <= now.time() && personCountRuleInfo.EndTime.time() >= now.time())
-            {
-                /* 在检测时间内 */
-            } else
-            {
-                /* 不在检测时间内 */
-                continue;
-            }
-        }
-
-        /************ 挨个房间检测人数 ************/
-        
-
-        /************ 检测频率直播间 + 导播间房间的人数 ************/
-
-    }
-    GThreadInfo.setThreadState(pRFAInfo.get(), RunTimeState::RUN_STATE_STOP);
-    SPDLOG_LOGGER_INFO(m_logger, "关闭 {} 线程,ChannelID:{}", pRFAInfo->strFunctionName, pRFAInfo->ChannelID);
-}
-
 

+ 0 - 4
SecurePlayAuxServer/SPAServer.h

@@ -51,10 +51,6 @@ private:
     FuncBase* createFuncInstance(FuncThreadInfo& info);
     /* 清理没有在运行的线程实例 */
     void clearNoneFuncThreadInfo();
-    
-    /* 区域人员检测(人员计数),检测这个区域内的人数,不能少于多少人,不能多余多少人 */
-    void threadActRegionalPersonnelDetection(FuncThreadInfo* RFAInfo);
-
 
 private:
     std::shared_ptr<spdlog::logger> m_logger = nullptr;

+ 148 - 6
SecurePlayAuxServer/communication/FromWebAPI.cpp

@@ -4,6 +4,8 @@
 #include <QString>
 #include <QUuid>
 #include "FuncOnAndOffJob.h"
+#include "FuncRegionalPerson.h"
+
 
 FromWebAPI::FromWebAPI()
 {
@@ -1021,7 +1023,8 @@ bool FromWebAPI::getActionInfo(ListActionInfo& listInfo)
             info.ActionID = it["actionId"].is_null() ? "" : it["actionId"].get<std::string>();
             info.RoomID = it["roomId"].is_null() ? -1 : it["roomId"].get<int>();
             info.ChannelID = it["chnId"].is_null() ? -1 : it["chnId"].get<int>();
-            info.RoomType = it["rtype"].is_null() ? -1 : it["rtype"].get<int>();
+            int roomType = it["rtype"].is_null() ? 0 : it["rtype"].get<int>();
+            info.RoomType = static_cast<Enum_RoomType>(roomType);
             info.strRoomName = it["rname"].is_null() ? "" : it["rname"].get<std::string>();
             listInfo.insertActionInfo(&info);
         }
@@ -1166,7 +1169,7 @@ bool FromWebAPI::insertAlarmInfo(const AlarmInfo& alarmInfo, int& PKID)
         json1["EndTime"] = alarmInfo.EndTime;
         json1["bBox"] = strBbox;
         json1["PicUrl"] = alarmInfo.PicUrl;
-        json1["AppID"] = alarmInfo.AppID;
+        json1["AppID"] = static_cast<int>(alarmInfo.appFunction);
         json1["ActionID"] = alarmInfo.ActionID;
         json1["ActionDes"] = alarmInfo.ActionDes;
         json1["CamerID"] = alarmInfo.DeviceID;
@@ -1367,10 +1370,106 @@ bool FromWebAPI::updatePersonInfo(RoomOnWorkInfo& roomInfo)
 }
 
 
+/* 通过频率ID和应用ID获取最大的PKID报警 */
+bool FromWebAPI::getMaxAlarmPKID(const int ChannelID, const AppFunction AppID, int& PKID)
+{
+    if(m_httpApi == nullptr)
+    {
+        SPDLOG_LOGGER_ERROR(m_logger,"WebApi is nullptr");
+        return false;
+    }
+    PKID = 0;
+    nJson json0;
+    json0["opName"] = "SPSS_GetChnAlarmMaxPKID";
+    nJson json1;
+    json1["ChannelID"] = ChannelID;
+    json1["AppID"] = static_cast<int>(AppID);
+    json0["paramList"] = json1;
+
+    QString strCmd = QString::fromStdString(json0.dump());
+    QString strRet;
+    auto ret = m_httpApi->DBDoInterface(enDBOperatorType::EDBOT_Select, strCmd, strRet);
+    if(ret != 0)
+    {
+        SPDLOG_LOGGER_DEBUG(m_logger,"获取Alarma max PKID失败:{}, 错误信息:{}",ret,m_httpApi->DoGetLastError(&ret).toStdString());
+        return false;
+    }
+    try 
+    {
+        nJson json1 = nJson::parse(strRet.toStdString());
+        int retCode = json1["code"].get<int>();
+        if(retCode != 0)
+        {
+            SPDLOG_LOGGER_ERROR(m_logger,"获取Alarma max PKID失败");
+            return false;
+        }
+        nJson result = json1["result"];
+        if(result.empty())
+        {
+            return false;
+        }
+        for(const auto& it : result)
+        {
+            PKID = it["maxPKID"].is_null() ? 0 : it["maxPKID"].get<int>();
+        }
+    } 
+    catch (const nJson::parse_error& e) {
+        SPDLOG_LOGGER_ERROR(m_logger,"解析 Alarma max PKID 失败:{}, 错误ID:{}",e.what(), e.id);
+        return false;
+    }
+    catch(const nJson::type_error& e)
+    {
+        SPDLOG_LOGGER_ERROR(m_logger,"解析 Alarma max PKID 失败:{}, 错误ID:{}",e.what(), e.id);
+        return false;
+    }
+    catch(...)
+    {
+        SPDLOG_LOGGER_ERROR(m_logger,"解析 Alarma max PKID 失败");
+        return false;
+    }
+
+    return true;
+}
+
+/* 清空在岗离岗报警的在岗人员信息 */
+bool FromWebAPI::clearOnWorkAlarmInfo(const int PKID, const bool onWork, const std::string actionDes)
+{
+    if(m_httpApi == nullptr)
+    {
+        SPDLOG_LOGGER_ERROR(m_logger,"WebApi is nullptr");
+        return false;
+    }
+
+    nJson json0;
+    json0["opName"] = "SPSS_ClearAlarmOnWorkPersonInfo";
+    nJson json1;
+    json1["pkid"] = PKID;
+    json1["onWork"] = onWork;
+    json1["actionDes"] = actionDes;
+    json0["paramList"] = json1;
+    QString strCmd = QString::fromStdString(json0.dump());
+    QString strRet;
+    auto ret = m_httpApi->DBDoInterface(enDBOperatorType::EDBOT_Update, strCmd, strRet);
+    if(ret != 0)
+    {
+        SPDLOG_LOGGER_DEBUG(m_logger,"清空在岗离岗报警的在岗人员信息失败:{}, 错误信息:{}",ret,m_httpApi->DoGetLastError(&ret).toStdString());
+        return false;
+    }
+
+    return true;
+}
+
+
 
 /* 获取报警规则表 */
-bool FromWebAPI::getPersonCountRuleInfo(std::vector<PersonCountRuleInfo>& vecInfo)
+bool FromWebAPI::getPersonCountRuleInfo(std::list<PersonCountRuleInfo>& list)
 {
+    if(m_httpApi == nullptr)
+    {
+        SPDLOG_LOGGER_ERROR(m_logger,"WebApi is nullptr");
+        return false;
+    }
+
     nJson json0;
     json0["opName"] = "SPSS_GetPersonCountRule";
     QString strCmd = QString::fromStdString(json0.dump());
@@ -1395,7 +1494,7 @@ bool FromWebAPI::getPersonCountRuleInfo(std::vector<PersonCountRuleInfo>& vecInf
         {
             return false;
         }
-        vecInfo.clear();
+        list.clear();
         for(const auto& it : result)
         {
             PersonCountRuleInfo info;
@@ -1406,7 +1505,7 @@ bool FromWebAPI::getPersonCountRuleInfo(std::vector<PersonCountRuleInfo>& vecInf
             QString strEnd = QString::fromStdString(it["endTime"].get<std::string>());
             info.EndTime = QDateTime::fromString(strEnd, "yyyy-MM-ss hh:mm:ss");
             info.week = it["week"].get<int>();
-            info.RuleType = it["type"].get<int>();
+            info.RuleType = static_cast<Enum_PeriodType>(it["type"].get<int>());
 
             info.RuleName = it["ruleName"].get<std::string>();
             info.LiveMinEnable = it["liveMinEnable"].get<bool>();
@@ -1421,7 +1520,7 @@ bool FromWebAPI::getPersonCountRuleInfo(std::vector<PersonCountRuleInfo>& vecInf
             info.DicMax = it["dicMax"].get<int>();
             info.LiveDicMin = it["liveDicMin"].get<int>();
             info.LiveDicMax = it["liveDicMax"].get<int>();
-            vecInfo.push_back(info);
+            list.push_back(info);
         }
     } 
     catch (const nJson::parse_error& e) {
@@ -1501,6 +1600,49 @@ bool FromWebAPI::getAlarmAppInfo(std::list<AppAndTimeInfo>& listInfo)
 }
 
 
+/* 结束人员计数报警,通过频率ID和应用ID */
+bool FromWebAPI::endPersonCountAlarm(EndAlarmParam& alarmParam)
+{
+    if(m_httpApi == nullptr)
+    {
+        SPDLOG_LOGGER_ERROR(m_logger,"WebApi is nullptr");
+        return false;
+    }
+    try
+    {
+        nJson json0;
+        json0["opName"] = "SPSS_EndPersonCountAlarm";
+        nJson json1;
+        json1["channelID"] = alarmParam.ChannelID;
+        json1["appID"] = static_cast<int>(alarmParam.AppID);
+        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;
+        }
+    }
+    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;
+}
+
+
 /* 写入在岗信息 tWorkOnInfo */
 bool FromWebAPI::insertOnWorkInfo(const RoomFaceInfo& onWorkInfo)
 {

+ 13 - 1
SecurePlayAuxServer/communication/FromWebAPI.h

@@ -7,6 +7,8 @@
 
 
 class RoomOnWorkInfo;
+class PersonCountRuleInfo;
+class EndAlarmParam;
 
 
 class FromWebAPI
@@ -56,6 +58,9 @@ public:
     /* 获取摄像机和房间关联信息 */
     bool getRoomCameraInfo(std::list<RoomCameraInfo>& vecInfo);
 
+    /* ================================================================================
+     * “tAlarmInfo”表相关操作
+     * ================================================================================ */
     /* 写入报警信息 */
     bool insertAlarmInfo(const AlarmInfo& alarmInfo);
     bool insertAlarmInfo(const AlarmInfo& alarmInfo, int& PKID);
@@ -65,11 +70,18 @@ public:
     bool endAlarmInfoByPKID(const int PKID, const QDateTime dateTime);
     /* 更新人员信息 */
     bool updatePersonInfo(RoomOnWorkInfo& roomInfo);
+    /* 通过频率ID和应用ID获取最大的PKID报警 */
+    bool getMaxAlarmPKID(const int ChannelID, const AppFunction AppID, int& PKID);
+    /* 清空在岗离岗报警的在岗人员信息 */
+    bool clearOnWorkAlarmInfo(const int PKID, const bool onWork, const std::string actionDes);
+
 
     /* 获取人员计数规则 */
-    bool getPersonCountRuleInfo(std::vector<PersonCountRuleInfo>& vecInfo);
+    bool getPersonCountRuleInfo(std::list<PersonCountRuleInfo>& vecInfo);
     /* 获取报警时段,也同时获取报警的应用信息 */
     bool getAlarmAppInfo(std::list<AppAndTimeInfo>& listInfo);
+    /* 结束人员计数报警,通过频率ID和应用ID */
+    bool endPersonCountAlarm(EndAlarmParam& alarmParam);
 
     /* 写入在岗信息 */
     bool insertOnWorkInfo(const RoomFaceInfo& onWorkInfo);