瀏覽代碼

V0.3.2
1、完成了大部分的非法入侵检测功能,写入EQM数据库还未完成

Apple 6 月之前
父節點
當前提交
5a87b487e8

+ 150 - 74
SecurePlayAuxServer/GlobalInfo/GlobalInfo.cpp

@@ -69,7 +69,7 @@ bool DeviceInfo::isEqualAlgorithmInfo(const std::vector<AlgorithmInfo>& other)
 }
 
 /* ====================================================================================
- * **************************    AlarmInfo成员函数    ****************************
+ * *******************************    各种报警信息    **********************************
  * ====================================================================================*/
 
 AlarmInfo::AlarmInfo() 
@@ -232,19 +232,26 @@ void ListRoomFaceInfo::addRoomFaceInfo(RoomFaceInfo& info)
     listRoomFaceInfo.push_back(info);
 }
 
+/**
+ * @brief 通过报警信息添加人脸信息
+ * 
+ * @param info 
+ */
 void ListRoomFaceInfo::addRoomFaceInfo(AlarmInfo& info)
 {
-    auto p = findRoomFaceInfo(info.ChannelID, info.RoomID);
+    auto p = findRoomFaceInfo(info.ChannelID, info.RoomID, info.DeviceID);
     if(p == nullptr)
     {
         RoomFaceInfo rfi;
         rfi.ChannelID = info.ChannelID;
         rfi.RoomID = info.RoomID;
+        rfi.CameraID = info.DeviceID;
         rfi.MaxNum = 0;
         rfi.MinNum = 0;
         rfi.StartTime = QDateTime::currentDateTime();
         listRoomFaceInfo.push_back(rfi);
     }
+    /* 将人员信息加入到列表中,添加时会先查找有没有相同的信息 */
     for(auto& it0 : info.vecPersonInfo)
     {
         if(!p->findPersonInfo(it0))
@@ -258,7 +265,7 @@ RoomFaceInfo* ListRoomFaceInfo::findRoomFaceInfo(RoomFaceInfo& info)
 {
     for(auto& it0 : listRoomFaceInfo)
     {
-        if(it0.ChannelID == info.ChannelID && it0.RoomID == info.RoomID)
+        if(it0.ChannelID == info.ChannelID && it0.RoomID == info.RoomID && it0.CameraID == info.CameraID)
         {
             return &it0;
         }
@@ -267,11 +274,11 @@ RoomFaceInfo* ListRoomFaceInfo::findRoomFaceInfo(RoomFaceInfo& info)
 }
 
 /* 查找有没有相同的结构 */
-RoomFaceInfo* ListRoomFaceInfo::findRoomFaceInfo(int ChannelID, int RoomID)
+RoomFaceInfo* ListRoomFaceInfo::findRoomFaceInfo(int ChannelID, int RoomID, int CameraID)
 {
     for(auto& it0 : listRoomFaceInfo)
     {
-        if(it0.ChannelID == ChannelID && it0.RoomID == RoomID)
+        if(it0.ChannelID == ChannelID && it0.RoomID == RoomID && it0.CameraID == CameraID)
         {
             return &it0;
         }
@@ -279,6 +286,128 @@ RoomFaceInfo* ListRoomFaceInfo::findRoomFaceInfo(int ChannelID, int RoomID)
     return nullptr;
 }
 
+IllegalInvasionInfo::IllegalInvasionInfo(IllegalInvasionInfo& other)
+{
+    isInsertEQM = other.isInsertEQM;
+    PKID = other.PKID;
+    CameraID = other.CameraID;
+    RoomID = other.RoomID;
+    ChannelID = other.ChannelID;
+    RoomType = other.RoomType;
+    FirstTime = other.FirstTime;
+    strActionDec = other.strActionDec;
+    strImageInfo = other.strImageInfo;
+}
+
+IllegalInvasionInfo& IllegalInvasionInfo::operator=(IllegalInvasionInfo& other)
+{
+    if(this != &other)
+    {
+        isInsertEQM = other.isInsertEQM;
+        PKID = other.PKID;
+        CameraID = other.CameraID;
+        RoomID = other.RoomID;
+        ChannelID = other.ChannelID;
+        RoomType = other.RoomType;
+        FirstTime = other.FirstTime;
+        strActionDec = other.strActionDec;
+        strImageInfo = other.strImageInfo;
+    }
+    return *this;
+}
+
+
+/* 添加信息 */
+void ListIllegalInvasionInfo::addIllInfo(IllegalInvasionInfo& info)
+{
+    if(findIllInfo(info) == nullptr)
+    {
+        listIll.push_back(info);
+    }
+}
+/* 查找相同的信息 */
+IllegalInvasionInfo* ListIllegalInvasionInfo::findIllInfo(IllegalInvasionInfo& info)
+{
+    for(auto& it : listIll)
+    {
+        if(it.RoomID == info.RoomID && it.RoomType == info.RoomType)
+        {
+            return &it;
+        }
+    }
+
+    return nullptr;
+}
+
+IllegalInvasionInfo* ListIllegalInvasionInfo::findIllInfo(int roomID, int roomType)
+{
+    for(auto& it : listIll)
+    {
+        if(it.RoomID == roomID && it.RoomType == roomType)
+        {
+            return &it;
+        }
+    }
+
+    return nullptr;
+}
+
+
+RoomIllegalInvasionInfo::RoomIllegalInvasionInfo(RoomIllegalInvasionInfo& o)
+{
+    isAlarm = o.isAlarm;
+    RoomID = o.RoomID;
+    RoomType = o.RoomType;
+    numMaxFace = o.numMaxFace;
+    numMaxPerson = o.numMaxPerson;
+    strBoxList = o.strBoxList;
+    strMessage = o.strMessage;
+    strImage = o.strImage;
+    CameraID = o.CameraID;
+}
+RoomIllegalInvasionInfo& RoomIllegalInvasionInfo::operator=(RoomIllegalInvasionInfo& o)
+{
+    if(this != &o) {
+        isAlarm = o.isAlarm;
+        RoomID = o.RoomID;
+        RoomType = o.RoomType;
+        numMaxFace = o.numMaxFace;
+        numMaxPerson = o.numMaxPerson;
+        strBoxList = o.strBoxList;
+        strMessage = o.strMessage;
+        strImage = o.strImage;
+        CameraID = o.CameraID;
+    }
+
+    return *this;
+}
+
+/* 添加房间 */
+void ListRoomIll::addRoom(int RoomID, int RoomType)
+{
+    auto p = findRoom(RoomID, RoomType);
+    if(p == nullptr)
+    {
+        RoomIllegalInvasionInfo ill;
+        ill.RoomID = RoomID;
+        ill.RoomType = RoomType;
+        listRoomIll.push_back(ill);
+    }
+}
+
+/* 查找是否有相同的房间 */
+RoomIllegalInvasionInfo* ListRoomIll::findRoom(int RoomID, int RoomType)
+{
+    for(auto& it : listRoomIll)
+    {
+        if(it.RoomID == RoomID && it.RoomType == RoomType)
+        {
+            return &it;
+        }
+    }
+    return nullptr;
+}
+
 
 
 AlarmRuleInfo::AlarmRuleInfo()
@@ -606,19 +735,19 @@ void ListRoomActionInfo::clearCameraList()
 }
 
 /* 清理设置为STOP或者ERROR的RoomAction */
-void ListRoomActionInfo::clearStopRoomAction()
-{
-    for(auto it0 = listRoomActionInfo.begin(); it0 != listRoomActionInfo.end();)
-    {
-        if(( (*it0)->RunState == RunTimeState::RUN_STATE_STOP) || ((*it0)->RunState == RunTimeState::RUN_STATE_ERROR))
-        {
-            delete *it0;
-            it0 = listRoomActionInfo.erase(it0);
-        }else {
-            ++it0;
-        }
-    }
-}
+// void ListRoomActionInfo::clearStopRoomAction()
+// {
+//     for(auto it0 = listRoomActionInfo.begin(); it0 != listRoomActionInfo.end();)
+//     {
+//         if(( (*it0)->RunState == RunTimeState::RUN_STATE_STOP) || ((*it0)->RunState == RunTimeState::RUN_STATE_ERROR))
+//         {
+//             delete *it0;
+//             it0 = listRoomActionInfo.erase(it0);
+//         }else {
+//             ++it0;
+//         }
+//     }
+// }
 
 /* 查找算法ID是否已在列表中 */
 RoomActionInfo* ListRoomActionInfo::findActionIDInList(const int chnID, const int RoomID, const std::string& strActionID)
@@ -882,62 +1011,7 @@ bool ListFuncActInfo::addFuncActionInfo(const AppAndTimeInfo& func)
     return true;
 }
 
-// /**
-//  * @brief 添加功能信息,一个应用功能在一个频道内只有一个实例
-//  * 
-//  * @param func 应用功能
-//  * @return true 添加成功,或者已有这个应用功能
-//  * @return false 
-//  */
-// bool ListFuncActInfo::addFuncActionInfo(AppFunction& func)
-// {
-//     if(func == AppFunction::APP_NONE)
-//     {
-//         return false;
-//     }
-//     /* 先查找有没有这个应用信息 */
-//     if(findAppFunction(func))
-//     {
-//         return true;
-//     }
-//     FuncActionInfo* pFuncActionInfo = new FuncActionInfo;
-//     pFuncActionInfo->appFunction = func;
-//     if(func == AppFunction::APP_ONWORK)
-//     {
-//         pFuncActionInfo->strFunctionName = "人员在岗识别";
-//     }
-//     else if(func == AppFunction::APP_ILLEGAL)
-//     {
-//         pFuncActionInfo->strFunctionName = "非法入侵检测";
-//     }
-//     else if(func == AppFunction::APP_REGIONAL)
-//     {
-//         pFuncActionInfo->strFunctionName = "人员计数";
-//     }
-//     else if(func == AppFunction::APP_CONTRABAND)
-//     {
-//         pFuncActionInfo->strFunctionName = "违禁物品";
-//     }
-//     else if(func == AppFunction::APP_PLAYPHONE)
-//     {
-//         pFuncActionInfo->strFunctionName = "玩手机";
-//     }
-//     else if(func == AppFunction::APP_FATIGUE)
-//     {
-//         pFuncActionInfo->strFunctionName = "疲劳检测";
-//     }
-//     else if(func == AppFunction::APP_MOUSE)
-//     {
-//         pFuncActionInfo->strFunctionName = "动物识别";
-//     }
-//     else if(func == AppFunction::APP_NOMASK)
-//     {
-//         pFuncActionInfo->strFunctionName = "口罩识别";
-//     }
-//     listFuncActionInfo.push_back(pFuncActionInfo);
 
-//     return true;
-// }
 
 /**
  * @brief 添加算法信息,根据传进来的算法ID,将其加入到对应的功能中
@@ -952,14 +1026,16 @@ bool ListFuncActInfo::addActionInfo(const ActionInfo& info)
     {
         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)
         {

+ 89 - 7
SecurePlayAuxServer/GlobalInfo/GlobalInfo.h

@@ -7,6 +7,7 @@
 #include <map>
 #include <mutex>
 #include <QDateTime>
+#include <QReadWriteLock>
 #include "nlohmann/json.hpp"
 
 
@@ -59,7 +60,8 @@ class ActionList
 {
 public:
     /* 全局算法ID */
-    std::mutex mutexActionID;             /* 算法ID的互斥锁 */
+    // std::mutex mutexActionID;             /* 算法ID的互斥锁 */
+    QReadWriteLock mutexRW;               /* 读写锁 */
 
     std::string ActFace;                  /* 人脸识别 */
     std::string ActPersonNumber;          /* 人员计数 */
@@ -194,14 +196,21 @@ struct CameraThreadInfo
     }
 };
 
+
+/* ====================================================================================
+ * *******************************    各种报警信息    **********************************
+ * ====================================================================================*/
+
+
 /**
  * @brief 人员信息
  * 
  */
 struct PersonInfo
 {
-    std::string PersonID;       /* 人员ID */
+    std::string PersonID;       /* 人员ID,等于-1就是无法识别出身份的人员 */
     std::string PersonName;     /* 人员名称 */
+    QDateTime lastOnWork;       /* 最后在岗时间 */
 };
 
 /**
@@ -259,6 +268,7 @@ struct RoomFaceInfo
 {
     int ChannelID = 0;
     int RoomID = 0;
+    int CameraID = 0;
     int MaxNum = 0;
     int MinNum = 0;
     QDateTime StartTime;
@@ -270,6 +280,7 @@ struct RoomFaceInfo
         if (this != &other) {
             ChannelID = other.ChannelID;
             RoomID = other.RoomID;
+            CameraID = other.CameraID;
             MaxNum = other.MaxNum;
             MinNum = other.MinNum;
             StartTime = other.StartTime;
@@ -293,9 +304,83 @@ struct ListRoomFaceInfo
     void addRoomFaceInfo(RoomFaceInfo& info);
     void addRoomFaceInfo(AlarmInfo& info);
     RoomFaceInfo* findRoomFaceInfo(RoomFaceInfo& info);
-    RoomFaceInfo* findRoomFaceInfo(int ChannelID, int RoomID);
+    RoomFaceInfo* findRoomFaceInfo(int ChannelID, int RoomID, int CameraID);
 };
 
+/**
+ * @brief 非法入侵检测信息结构体,作为缓存存储正在报警的信息
+ * 
+ */
+struct IllegalInvasionInfo
+{
+    bool isInsertEQM = false;           /* 是否已经插入到EQM数据库的报警信息中 */
+    int PKID = 0;
+    int CameraID = 0;
+    int RoomID = 0;
+    int ChannelID = 0;
+    int RoomType = 0;                   /* 房间类型 */
+    QDateTime FirstTime;                /* 最开始的报警时间 */
+    std::string strActionDec;           /* 算法描述 */
+    std::string strImageInfo;           /* 图片信息 */
+
+    IllegalInvasionInfo() = default;
+    IllegalInvasionInfo(IllegalInvasionInfo& other);
+    IllegalInvasionInfo& operator=(IllegalInvasionInfo& other);
+};
+
+/**
+ * @brief 非法入侵报警列表
+ * 
+ */
+struct ListIllegalInvasionInfo
+{
+    std::list<IllegalInvasionInfo> listIll;
+
+    std::list<IllegalInvasionInfo>& getData() { return listIll; }
+    /* 添加信息 */
+    void addIllInfo(IllegalInvasionInfo& info);
+    /* 查找相同的信息 */
+    IllegalInvasionInfo* findIllInfo(IllegalInvasionInfo& info);
+    IllegalInvasionInfo* findIllInfo(int roomID, int roomType);
+};
+
+
+/**
+ * @brief 房间为单位的非法入侵信息
+ * 
+ */
+struct RoomIllegalInvasionInfo
+{
+    bool isAlarm = false;                   /* 是否在报警 */
+    int RoomID = 0;                         /* 房间ID */
+    int RoomType = 0;                       /* 房间类型 */
+    int numMaxFace = 0;                     /* 最大人脸数 */
+    int numMaxPerson = 0;                   /* 最大人员数 */
+    int CameraID = 0;                       /* 摄像机ID,这个存储的是使用的哪个报警信息的ID */
+    std::string strBoxList;                 /* box */
+    std::string strMessage;                 /* 报警信息字符串 */
+    std::string strImage;                   /* 报警图片 */
+    std::vector<PersonInfo> vecPersonInfo;  /* 人员信息 */
+
+    RoomIllegalInvasionInfo() = default;
+    RoomIllegalInvasionInfo(RoomIllegalInvasionInfo& o);
+    RoomIllegalInvasionInfo& operator=(RoomIllegalInvasionInfo& o);
+};
+
+/**
+ * @brief 房间报警数据,以房间为单位
+ * 
+ */
+struct ListRoomIll
+{
+    std::list<RoomIllegalInvasionInfo> listRoomIll;
+
+    std::list<RoomIllegalInvasionInfo>& getData() { return listRoomIll; }
+    /* 添加房间 */
+    void addRoom(int RoomID, int RoomType);
+    /* 查找是否有相同的房间 */
+    RoomIllegalInvasionInfo* findRoom(int RoomID, int RoomType);
+};
 
 /**
  * @brief 报警规则
@@ -419,7 +504,6 @@ public:
  */
 struct RoomActionInfo
 {
-    RunTimeState RunState;          /* 线程运行状态 */
     int ChannelID;                  /* 通道ID */
     int RoomID;                     /* 房间ID */
     int RoomType;                   /* 房间类型 */
@@ -428,7 +512,6 @@ struct RoomActionInfo
     std::list<int> listCameraID;    /* 摄像机ID */
 
     RoomActionInfo() {
-        RunState = RunTimeState::RUN_STATE_INIT;
         ChannelID = -1;
         RoomID = -1;
         RoomType = -1;
@@ -477,7 +560,7 @@ public:
     /* 清空算法对应的摄像机列表 */
     void clearCameraList();
     /* 清理设置为STOP或者ERROR的RoomAction */
-    void clearStopRoomAction();
+    // void clearStopRoomAction();
     /* 查找算法ID是否已在列表中 */
     RoomActionInfo* findActionIDInList(const int chnID, const int RoomID, const std::string& strActionID);
     
@@ -559,7 +642,6 @@ public:
 
     /* 添加功能信息 */
     bool addFuncActionInfo(const AppAndTimeInfo& func);
-    // bool addFuncActionInfo(AppFunction& func);
     /* 添加算法信息 */
     bool addActionInfo(const ActionInfo& info);
     /* 清空无用的功能信息 */

+ 248 - 118
SecurePlayAuxServer/SPAServer.cpp

@@ -33,7 +33,7 @@ SPAServer::SPAServer()
     /* 初始化WebAPI */
     m_toEQMDataBase.initWebApi("http://192.1.3.133:31000/v6/", "", "4c2f9fc91c22dd98331e47af2e2964f4");
     /* 模拟违禁品算法ID,后续需要动态调整 */
-    m_keyContraband = "OD210_026_005246_001-IZRTKyEx";
+    g_actionList.ActContraband = "OD210_026_005246_001-IZRTKyEx";
     
 }
 
@@ -55,7 +55,7 @@ void SPAServer::startServer()
     info.RedisPWD = "Ff1z@TOFr^iwd%Ra";
     info.DeviceID = 117;
     info.vecAction.push_back("OD210_026_005246_001-IZRTKyEx");
-    m_keyContraband = "OD210_026_005246_001-IZRTKyEx";
+    g_actionList.ActContraband = "OD210_026_005246_001-IZRTKyEx";
     // CPPTP.add_task(&SPAServer::threadFromRedis, this, info);
     // threadFromRedis(info);
 }
@@ -467,7 +467,7 @@ void SPAServer::parseRedisData(const std::string& strData, AlarmInfo& alarmInfo)
                 /* 这一条Box数据报警了将其内容存储起来 */
                 alarmInfo.Is_Alarm = true;
                 /* 解析label,违禁品关键字,先判断这个是不是违禁品检测的算法ID */
-                if(alarmInfo.ActionID == m_keyContraband)
+                if(alarmInfo.ActionID == g_actionList.ActContraband)
                 {
                     /* 解析报警,取出报警类型 */
                     nJson label = it0["label"];
@@ -515,7 +515,7 @@ void SPAServer::parseRedisData(const std::string& strData, AlarmInfo& alarmInfo)
         {
             /* 添加报警信息的提示信息 */
             alarmInfo.BboxList = bboxList;
-            if( (alarmInfo.ActionID == m_keyContraband) && !labelList.empty() )
+            if( (alarmInfo.ActionID == g_actionList.ActContraband) && !labelList.empty() )
             {
                 alarmInfo.ActionDes = fmt::format("出现违禁品[{}]告警", labelList);
                 SPDLOG_LOGGER_INFO(m_logger, "{}", alarmInfo.ActionDes);
@@ -529,7 +529,7 @@ void SPAServer::parseRedisData(const std::string& strData, AlarmInfo& alarmInfo)
                 return;
             }
             /* 如果是人员报警,就存储人员报警信息 */
-            if(alarmInfo.ActionID == m_KeyFace)
+            if(alarmInfo.ActionID == g_actionList.ActFace)
             {
                 nJson jsonArray = json0["personList"];
                 for(auto& it : jsonArray)
@@ -625,7 +625,7 @@ void SPAServer::parseRedisBBoxesData(const std::string& strData, AlarmInfo& alar
                 /* 这一条Box数据报警了将其内容存储起来 */
                 alarmInfo.Is_Alarm = true;
                 /* 解析label,违禁品关键字,先判断这个是不是违禁品检测的算法ID */
-                if(alarmInfo.ActionID == m_keyContraband)
+                if(alarmInfo.ActionID == g_actionList.ActContraband)
                 {
                     /* 解析报警,取出报警类型 */
                     nJson label = it0["label"];
@@ -674,7 +674,7 @@ void SPAServer::parseRedisBBoxesData(const std::string& strData, AlarmInfo& alar
             /* 添加报警信息的提示信息 */
             alarmInfo.BboxList = bboxList;
             /* 违禁品报警信息,违禁品列表不是空的,就添加补充的文字 */
-            if( (alarmInfo.ActionID == m_keyContraband) && !labelList.empty() )
+            if( (alarmInfo.ActionID == g_actionList.ActContraband) && !labelList.empty() )
             {
                 alarmInfo.ActionDes = fmt::format("出现违禁品[{}]告警", labelList);
                 SPDLOG_LOGGER_INFO(m_logger, "{}", alarmInfo.ActionDes);
@@ -689,7 +689,7 @@ void SPAServer::parseRedisBBoxesData(const std::string& strData, AlarmInfo& alar
                 return;
             }
             /* 如果是人员报警,就存储人员报警信息 */
-            if(alarmInfo.ActionID == m_KeyFace)
+            if(alarmInfo.ActionID == g_actionList.ActFace)
             {
                 nJson jsonArray = json0["personList"];
                 for(auto& it : jsonArray)
@@ -833,26 +833,27 @@ void SPAServer::threadRoomCamera()
 
 
 /**
- * @brief 人员在岗识别线程,应该是人脸识别线程,这个需要房间内多个摄像机共同识别
-            1、离岗判断条件:直播间无人算离岗(直播间所有摄像头的区域人员检测算法输出结果都为0时记为离岗开始,
-                当结果存在非0时记为离岗结束)
-            2、离岗输出结果:当判断出离岗行为时,依据人脸识别结果,找到离岗时间点前有人的最近一帧画面中的人员,
-                判断为离岗人员,并计算离岗时长,形成离岗记录(频率、机房、离岗人员、离岗开始时间、离岗结束时间、离
-                岗持续时长)
-            3、在岗时长计算方式:每天00:00:00-23:59:59人脸识别结果中所有人员名称的出现次数✖抽帧频率(如5秒抽
-                取1帧,则出现200次人名表示在岗1000秒时长),形成每日的人员在岗时长记录
-            4、报警判断条件:依据离岗次数和单次离岗时长进行报警,展示报警结果
+ * @brief 人员在岗识别线程,这个功能主要是给客户端提供实时的人脸识别信息
+ *        1、这个写入tWorkOnInfo表格,十分钟写一次
+ *        2、理论上这里需要实时更新数据库,但是实际上时每十分钟写入一次数据
  * 
- * @param pRAInfo 传入房间ID和算法ID
+ * @param RFAInfo 传入房间ID和算法ID
  */
 void SPAServer::threadActPersonWork(FuncActionInfo* 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<FuncActionInfo> pRFAInfo = std::make_shared<FuncActionInfo>();
     *pRFAInfo = *RFAInfo;
+
+    /* 保存每个摄像机的报警信息 */
+    std::shared_ptr<std::list<AlarmInfo>> pListAlarmInfo = std::make_shared<std::list<AlarmInfo>>();
+    /* 保存人脸信息的数据 */
+    std::shared_ptr<ListRoomFaceInfo> pListRoomFaceInfo = std::make_shared<ListRoomFaceInfo>();
     
     while (m_threadRunning)
     {
@@ -864,6 +865,7 @@ void SPAServer::threadActPersonWork(FuncActionInfo* RFAInfo)
         }
 
         /* 读取Redis数据 */
+        pListAlarmInfo->clear();
         for(const auto& RoomInfo : pRFAInfo->listRoomCamActInfo)
         {
             for(const auto& it : RoomInfo.mapCameraAction)
@@ -879,41 +881,96 @@ void SPAServer::threadActPersonWork(FuncActionInfo* RFAInfo)
                 /* 解析数据 */
                 AlarmInfo alarmInfo;
                 parseRedisData(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;
+                }
+                pListAlarmInfo->push_back(alarmInfo);
+            }
+        }
 
-
+        /* 处理数据,将报警信息的人脸信息取出来,放入到人脸信息列表中 */
+        for(auto& alarmInfo : *pListAlarmInfo)
+        {
+            /* 添加到人脸列表中,会自动去重,自动创建对应的频道和房间信息 */
+            pListRoomFaceInfo->addRoomFaceInfo(alarmInfo);
+        }
+        /* 计算人脸个数,并判断是否需要写入数据库 */
+        QDateTime now = QDateTime::currentDateTime();
+        for(auto it = pListRoomFaceInfo->listRoomFaceInfo.begin(); it != pListRoomFaceInfo->listRoomFaceInfo.end(); )
+        {
+            if(it->MaxNum < it->listPersonInfo.size())
+            {
+                it->MaxNum = it->listPersonInfo.size();
+            }
+            if(it->MinNum > it->listPersonInfo.size())
+            {
+                it->MinNum = it->listPersonInfo.size();
+            }
+            /* 判断是否需要写入数据库,超过设置的时间就写入,默认是600秒 */
+            if(now.toSecsSinceEpoch() - it->StartTime.toSecsSinceEpoch() > g_config.AppUpdateOnWorkTimeInterval)
+            {
+                /* 写入数据库 */
+                if(toEQMDataBase->insertOnWorkInfo(*it))
+                {
+                    SPDLOG_LOGGER_INFO(m_logger, "ChannelID:{}, RoomID:{}, 在岗信息写入数据库成功, StartTime", it->ChannelID, it->RoomID, it->StartTime.toString("yyyy-MM-dd hh:mm:ss").toStdString());
+                    /* 删除这条信息 */
+                    it = pListRoomFaceInfo->listRoomFaceInfo.erase(it);
+                    continue;
+                }
             }
+            ++it;
         }
+
     }
     setThreadState(pRFAInfo, RunTimeState::RUN_STATE_STOP);
     SPDLOG_LOGGER_INFO(m_logger, "关闭 {} 线程,ChannelID:{}", pRFAInfo->strFunctionName, pRFAInfo->ChannelID);
 }
 
+
 /**
- * @brief 区域人员检测,检测这个区域内的人数,不能少于多少人,不能多余多少人
- *          1、报警判断条件:直播间报警:当前频率所有直播间摄像头的区域人员检测算法输出结果均大于或小于设定人
-               数值时,记为报警行为,直接展示报警结果
-            2、录播间报警:当前频率所有录播间摄像头的区域人员检测算法输出结果均大于或小于设定人数值时,记为报
-               警行为,直接展示报警结果
-            3、直播间+录播间报警:当前频率直播间人数+录播间人数大于或小于设定人数值时,记为报警行为,直接展示
-               报警结果
+ * @brief 区域非法入侵检测
+            1、野猫、宠物识别:报警判断条件:机房内出现摄像头的宠物识别算法输出报警结果时,记为报警行为,直接
+              展示报警结果
+            2、无权限人员识别:报警判断条件:当判断出区域非法入侵行为时,依据人脸识别结果,判断是否为人脸库人
+              员,非人脸库的人员时判断为非法入侵行为(背影需要报警需要结合区域人员检测算法判断)
+            3、人员计数和人脸识别数不相等时,判断为非法入侵行为
  * 
- * @param RAInfo 传入的房间ID和算法ID
+ * @param info 
  */
-void SPAServer::threadActRegionalPersonnelDetection(FuncActionInfo* RFAInfo)
+void SPAServer::threadActIllegalInvasion(FuncActionInfo* RFAInfo)
 {
     SPDLOG_LOGGER_INFO(m_logger, "开启 {} 线程,ChannelID:{} ,", RFAInfo->strFunctionName, RFAInfo->ChannelID);
     /* 创建读取Redis的实例 */
     std::shared_ptr<FromRedis> fromRedis = std::make_shared<FromRedis>();
-    /* 局部变量 */
-    std::shared_ptr<FuncActionInfo> pRFAInfo = std::make_shared<FuncActionInfo>();
     /* 创建写入数据库实例 */
     std::shared_ptr<ToEQMDataBase> toEQMDataBase = std::make_shared<ToEQMDataBase>();
+    /* 局部变量 */
+    std::shared_ptr<FuncActionInfo> pRFAInfo = std::make_shared<FuncActionInfo>();
     *pRFAInfo = *RFAInfo;
     /* 保存每个摄像机的报警信息 */
     std::shared_ptr<std::list<AlarmInfo>> pListAlarmInfo = std::make_shared<std::list<AlarmInfo>>();
-    /* 保存人员计数的信息 */
-    std::shared_ptr<ListRoomFaceInfo> pListRoomFaceInfo = std::make_shared<ListRoomFaceInfo>();
+    /* 保存非法入侵的信息 */
+    std::shared_ptr<ListIllegalInvasionInfo> pListIllInfo = std::make_shared<ListIllegalInvasionInfo>();
     
+    std::string strFaceActionID;            /* 人脸识别的Action */
+    std::string strCountActionID;           /* 人员计数的Action */
+
+    /* 封装lambda表达式 */
+    std::function<bool(const std::vector<PersonInfo>&)> funcIsAlarm = [](const std::vector<PersonInfo>& vecPersion) {
+        for(const auto& it : vecPersion)
+        {
+            if(it.PersonID == "-1")
+            {
+                return true;
+            }
+        }
+        return false;
+    };
+
     while (m_threadRunning)
     {
         /* 更新线程信息 */
@@ -950,40 +1007,178 @@ void SPAServer::threadActRegionalPersonnelDetection(FuncActionInfo* RFAInfo)
                 pListAlarmInfo->push_back(alarmInfo);
             }
         }
+        /* 更新算法ActionID */
+        {
+            g_actionList.mutexRW.lockForRead();
+            strFaceActionID = g_actionList.ActFace;
+            strCountActionID = g_actionList.ActPersonNumber;
+            g_actionList.mutexRW.unlock();
+        }
 
-        /* 处理数据,将报警信息的人脸信息取出来,放入到人脸信息列表中 */
-        for(auto& alarmInfo : *pListAlarmInfo)
+        /* 找出房间的个数,按照房间进行判断 */
+        ListRoomIll listRoomIll;
+        for(auto& it : pRFAInfo->listRoomCamActInfo)
         {
-            /* 添加到人脸列表中,会自动去重,自动创建对应的频道和房间信息 */
-            pListRoomFaceInfo->addRoomFaceInfo(alarmInfo);
+            listRoomIll.addRoom(it.RoomID, it.RoomType);
         }
-        /* 计算人脸个数,并判断是否需要写入数据库 */
-        QDateTime now = QDateTime::currentDateTime();
-        for(auto it = pListRoomFaceInfo->listRoomFaceInfo.begin(); it != pListRoomFaceInfo->listRoomFaceInfo.end(); )
+
+        /* 根据房间解析人脸识别的非法入侵,这个有了就不用判断后面的人员计数不相等了 */
+        for(auto& room : listRoomIll.getData())
         {
-            if(it->MaxNum < it->listPersonInfo.size())
+            for(const auto& it : *pListAlarmInfo)
             {
-                it->MaxNum = it->listPersonInfo.size();
+                /* 人俩识别算法 */
+                if(it.ActionID == strFaceActionID)
+                {
+                    if(it.vecPersonInfo.size() > room.numMaxFace)
+                    {
+                        room.numMaxFace = it.vecPersonInfo.size();
+                        room.strBoxList = it.BboxList;
+                        room.vecPersonInfo = it.vecPersonInfo;
+                    }
+                }
+                /* 判断有没有非法入侵人员 */
+                if(funcIsAlarm(it.vecPersonInfo))
+                {
+                    room.isAlarm = true;
+                    room.strMessage = "人员非法入侵(未知人员)";
+                    if( !it.ImageInfo.empty() )
+                    {
+                        room.strImage = it.ImageInfo;
+                    }
+                    room.CameraID = it.DeviceID;
+                }
             }
-            if(it->MinNum > it->listPersonInfo.size())
+            
+        }
+
+        /* 判断人脸识别到的数目和人员计数算法识别到的人数是否相等,如果上面报警了,这里就不用检测了 */
+        for(auto& room : listRoomIll.getData())
+        {
+            if(room.isAlarm)
             {
-                it->MinNum = it->listPersonInfo.size();
+                continue;
             }
-            /* 判断是否需要写入数据库,超过设置的时间就写入,默认是600秒 */
-            if(now.toSecsSinceEpoch() - it->StartTime.toSecsSinceEpoch() > g_config.AppUpdateOnWorkTimeInterval)
+            /* 这个房间的人脸算法没有识别到非法入侵 */
+            for(const auto& it : *pListAlarmInfo)
             {
-                /* 写入数据库 */
-                if(toEQMDataBase->insertOnWorkInfo(*it))
+                if(it.ActionID == strCountActionID)
                 {
-                    SPDLOG_LOGGER_INFO(m_logger, "ChannelID:{}, RoomID:{}, 在岗信息写入数据库成功, StartTime", it->ChannelID, it->RoomID, it->StartTime.toString("yyyy-MM-dd hh:mm:ss"));
-                    /* 删除这条信息 */
-                    it = pListRoomFaceInfo->listRoomFaceInfo.erase(it);
+                    if(it.vecPersonInfo.size() > room.numMaxPerson)
+                    {
+                        room.numMaxPerson = it.vecPersonInfo.size();
+                        room.strBoxList = it.BboxList;
+                        if(!it.ImageInfo.empty())
+                        {
+                            room.strImage = it.ImageInfo;
+                        }
+                        room.CameraID = it.DeviceID;
+                    }
+                }
+            }
+            /* 判断人数是否一致 */
+            if(room.numMaxFace != room.numMaxPerson)
+            {
+                room.strMessage = fmt::format("非法入侵(人员计数 {} 和人脸数 {} 不一致)", room.numMaxPerson, room.numMaxFace);
+                room.isAlarm = true;
+            }
+        }
+
+        /* 将非法入侵的信息存储到数组缓存中,等待报警结束后判断是否需要写入EQM数据库 */
+        for(auto& room : listRoomIll.getData())
+        {
+            if(room.isAlarm)
+            {
+                /* 正在报警,检查是否有 */
+                if(pListIllInfo->findIllInfo(room.RoomID, room.RoomType) == nullptr)
+                {
+                    IllegalInvasionInfo info;
+                    info.ChannelID = pRFAInfo->ChannelID;
+                    info.CameraID = room.CameraID;
+                    info.RoomID = room.RoomID;
+                    info.RoomType = room.RoomType;
+                    info.strActionDec = room.strMessage;
+                    info.strImageInfo = room.strImage;
+                    info.FirstTime = QDateTime::currentDateTime();;
+                    pListIllInfo->addIllInfo(info);
+                }
+            }
+            else {
+                /* 没有报警,检查是否是报警结束了,是否符合写入数据库的条件 */
+                QDateTime currTime = QDateTime::currentDateTime();
+            }
+        }
+
+    }
+    setThreadState(pRFAInfo, RunTimeState::RUN_STATE_STOP);
+    SPDLOG_LOGGER_INFO(m_logger, "关闭 {} 线程,ChannelID:{}", pRFAInfo->strFunctionName, pRFAInfo->ChannelID);
+}
+
+
+
+/**
+ * @brief 区域人员检测,检测这个区域内的人数,不能少于多少人,不能多余多少人
+ *          1、报警判断条件:直播间报警:当前频率所有直播间摄像头的区域人员检测算法输出结果均大于或小于设定人
+               数值时,记为报警行为,直接展示报警结果
+            2、录播间报警:当前频率所有录播间摄像头的区域人员检测算法输出结果均大于或小于设定人数值时,记为报
+               警行为,直接展示报警结果
+            3、直播间+录播间报警:当前频率直播间人数+录播间人数大于或小于设定人数值时,记为报警行为,直接展示
+               报警结果
+ * 
+ * @param RAInfo 传入的房间ID和算法ID
+ */
+void SPAServer::threadActRegionalPersonnelDetection(FuncActionInfo* 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<FuncActionInfo> pRFAInfo = std::make_shared<FuncActionInfo>();
+    *pRFAInfo = *RFAInfo;
+    /* 保存每个摄像机的报警信息 */
+    std::shared_ptr<std::list<AlarmInfo>> pListAlarmInfo = std::make_shared<std::list<AlarmInfo>>();
+    
+    while (m_threadRunning)
+    {
+        /* 更新线程信息 */
+        updateFuncInfo(pRFAInfo);
+        if(pRFAInfo->appFunction == AppFunction::APP_NONE)
+        {
+            break;
+        }
+
+        /* 读取Redis数据 */
+        pListAlarmInfo->clear();
+        for(const auto& RoomInfo : pRFAInfo->listRoomCamActInfo)
+        {
+            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);
+                    std::this_thread::sleep_for(std::chrono::milliseconds(100));
                     continue;
                 }
+                /* 解析数据 */
+                AlarmInfo alarmInfo;
+                parseRedisData(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;
+                }
+                pListAlarmInfo->push_back(alarmInfo);
             }
-            ++it;
         }
 
+        
+
 
     }
     setThreadState(pRFAInfo, RunTimeState::RUN_STATE_STOP);
@@ -1128,57 +1323,6 @@ void SPAServer::threadActNormal(FuncActionInfo* info)
     SPDLOG_LOGGER_INFO(m_logger, "{} 线程退出,Channel:{}",pFuncAct->strFunctionName, pFuncAct->ChannelID);
 }
 
-/**
- * @brief 非法入侵检测
-            1、野猫、宠物识别:报警判断条件:机房内出现摄像头的宠物识别算法输出报警结果时,记为报警行为,直接
-              展示报警结果
-            2、无权限人员识别:报警判断条件:当判断出区域非法入侵行为时,依据人脸识别结果,判断是否为人脸库人
-              员,非人脸库的人员时判断为非法入侵行为(背影需要报警需要结合区域人员检测算法判断)
- * 
- * @param info 
- */
-void SPAServer::threadActIllegalInvasion(ActionInfo* info)
-{
-    SPDLOG_LOGGER_INFO(m_logger, "开启非法入侵检测线程,RoomID:{} ,Action:{}", info->RoomID, info->ActionID);
-    /* 创建读取Redis的实例 */
-    std::shared_ptr<FromRedis> fromRedis = std::make_shared<FromRedis>();
-    /* 局部变量,保存这个线程的信息 */
-    std::shared_ptr<ActionInfo> pActInfo = std::make_shared<ActionInfo>();
-    *pActInfo = *info;
-    /* 摄像机ID小于0就退出线程 */
-    while (m_threadRunning)
-    {
-        /* 更新算法关联的摄像机ID */
-        // updateActionCameraID(pActInfo);
-        /* 如果摄像机ID是小于0,那么这个算法就没有对应的摄像机了,线程就退出了 */
-        if(pActInfo->CameraID < 0)
-        {
-            break;
-        }
-        /* 读取Redis数据 */
-        std::string strKey = std::to_string(pActInfo->CameraID) + ":" + pActInfo->ActionID;
-        std::string strRetValue;
-        if(!fromRedis->getRedisString(strKey, strRetValue))
-        {
-            SPDLOG_LOGGER_ERROR(m_logger, "读取Redis数据失败, Key:{}", strKey);
-            continue;
-        }
-        /* 解析数据 */
-        AlarmInfo alarmInfo;
-        parseRedisData(strRetValue, alarmInfo);
-        /* 判断事件的时效性,超过多少秒不更新就可能是超脑挂了 */
-        if(isEventTimeVaild(alarmInfo.EventTime))
-        {
-            SPDLOG_LOGGER_WARN(m_logger, "Redis Key:{} 数据长时间没有更新,EventTime:{}",strKey, alarmInfo.EventTime);
-            continue;
-        }
-        /* 判断有无报警记录,写入到EQM数据库 */
-    }
-    /* 设置线程退出的状态 */
-    // setThreadState(pActInfo, RunTimeState::RUN_STATE_STOP);
-    SPDLOG_LOGGER_INFO(m_logger, "非法入侵检测线程退出,RoomID:{} ,CameraID:{}, Action:{}", pActInfo->RoomID, pActInfo->CameraID, pActInfo->ActionID);
-}
-
 
 
 /* 将该算法对应的摄像机放入摄像机列表 */
@@ -1219,7 +1363,7 @@ bool SPAServer::insertCameraToAction(RoomActionInfo* pRAInfo, std::list<RoomCame
  bool SPAServer::updateFuncInfo(std::shared_ptr<FuncActionInfo> pInfo)
 {
     pInfo->clearActionList();
-    std::lock_guard<std::mutex> look(m_mutexRunAI);
+    std::lock_guard<std::mutex> look(m_mutexRunFAI);
     auto fa = m_runListFuncActInfo.findAppFunction(*pInfo);
     if(fa == nullptr)
     {
@@ -1233,7 +1377,7 @@ bool SPAServer::insertCameraToAction(RoomActionInfo* pRAInfo, std::list<RoomCame
 /* 设置线程状态 */
 void SPAServer::setThreadState(std::shared_ptr<FuncActionInfo> pInfo, RunTimeState state)
 {
-    std::lock_guard<std::mutex> look(m_mutexRunAI);
+    std::lock_guard<std::mutex> look(m_mutexRunFAI);
     auto p = m_runListFuncActInfo.findAppFunction(*pInfo);
     if(p != nullptr)
     {
@@ -1241,20 +1385,6 @@ void SPAServer::setThreadState(std::shared_ptr<FuncActionInfo> pInfo, RunTimeSta
     }
 }
 
-/* 设置线程状态 */
-void SPAServer::setThreadState(std::shared_ptr<RoomActionInfo> pInfo, RunTimeState state)
-{
-    std::lock_guard<std::mutex> look(m_mutexRunRAI);
-    for(auto& it : m_runListRoomActionInfo.getData())
-    {
-        if(it->isEqualBaseInfo(*pInfo))
-        {
-            it->RunState = state;
-            break;
-        }
-    }
-}
-
 
 
 /* 计算与当前时间的时间差,返回秒 */

+ 15 - 18
SecurePlayAuxServer/SPAServer.h

@@ -48,10 +48,11 @@ private:
     
     /* 人员在岗识别线程,应该是人脸识别线程,这个需要房间内多个摄像机共同识别 */
     void threadActPersonWork(FuncActionInfo* RFAInfo);
+    /* 非法入侵检测 */
+    void threadActIllegalInvasion(FuncActionInfo* RFAInfo);
     /* 区域人员检测(人员计数),检测这个区域内的人数,不能少于多少人,不能多余多少人 */
     void threadActRegionalPersonnelDetection(FuncActionInfo* RFAInfo);
-    /* 非法入侵检测 */
-    void threadActIllegalInvasion(ActionInfo* info);
+    
     /* 普通任务线程,一个算法值对应一个摄像机 */
     void threadActNormal(FuncActionInfo* info);
     
@@ -63,7 +64,6 @@ private:
     bool updateFuncInfo(std::shared_ptr<FuncActionInfo> pInfo);
     /* 设置线程状态 */
     void setThreadState(std::shared_ptr<FuncActionInfo> pInfo, RunTimeState state);
-    void setThreadState(std::shared_ptr<RoomActionInfo> pInfo, RunTimeState state);
 
 
     /* 计算与当前时间的时间差,返回秒 */
@@ -82,15 +82,12 @@ private:
     FromSuperBrain m_fromSuperBrain;
     ToEQMDataBase m_toEQMDataBase;
 
-    std::string m_keyContraband;                        /* 违禁品检测的Key,这个Key后面可能随时会变动 */
-    std::string m_KeyFace;                              /* 人脸检测的Key */
-
-    std::mutex m_mutexActionID;                         /* 算法ID的互斥锁 */
-    std::string ActPersonWork;                          /* 人员在岗识别 */
-    std::string ActPersonNumber;                        /* 区域人员检测(区域人员计数) */
-    std::string ActIllegalInvasion;                     /* 非法入侵检测 */
-    std::string ActContraband;                          /* 违禁品检测 */
-    std::string ActFatigueDetection;                    /* 疲劳检测 */
+    // std::mutex m_mutexActionID;                         /* 算法ID的互斥锁 */
+    // std::string ActPersonWork;                          /* 人员在岗识别 */
+    // std::string ActPersonNumber;                        /* 区域人员检测(区域人员计数) */
+    // std::string ActIllegalInvasion;                     /* 非法入侵检测 */
+    // std::string ActContraband;                          /* 违禁品检测 */
+    // std::string ActFatigueDetection;                    /* 疲劳检测 */
 
     /* 算法信息,这个就是tAction在内存中的数据,方便后续对比,程序启动的时候会先获取一份 */
     std::vector<AlgorithmInfo> m_vecEqmAlgInfo;
@@ -103,12 +100,12 @@ private:
     std::list<int> m_listDevIDDelete;
 
 
-    /* 房间和算法关联的信息,包含所需要的摄像机ID */
-    std::mutex m_mutexRunRAI;
-    ListRoomActionInfo m_runListRoomActionInfo;
-    /* 运行时的算法信息列表,这个容器存储的是不需要摄像机融合的算法 */
-    std::mutex m_mutexRunAI;
-    ListActionInfo m_runListActionInfo;
+    // /* 房间和算法关联的信息,包含所需要的摄像机ID */
+    // std::mutex m_mutexRunRAI;
+    // ListRoomActionInfo m_runListRoomActionInfo;
+    // /* 运行时的算法信息列表,这个容器存储的是不需要摄像机融合的算法 */
+    // std::mutex m_mutexRunAI;
+    // ListActionInfo m_runListActionInfo;
     /* 运行时应用线程功能相关信息 */
     std::mutex m_mutexRunFAI;
     ListFuncActInfo m_runListFuncActInfo;

+ 26 - 7
SecurePlayAuxServer/communication/ToEQMDataBase.cpp

@@ -994,17 +994,36 @@ bool ToEQMDataBase::insertOnWorkInfo(const RoomFaceInfo& onWorkInfo)
         SPDLOG_LOGGER_ERROR(m_logger,"WebApi is nullptr");
         return false;
     }
+    if(onWorkInfo.listPersonInfo.empty())
+    {
+        return false;
+    }
+    /* 拼接人脸ID和人脸名称 */
+    std::string strFaceID;
+    std::string strFaceName;
+    for(const auto& it : onWorkInfo.listPersonInfo)
+    {
+        strFaceID += it.PersonID + ";";
+        strFaceName += it.PersonName + ";";
+    }
+    /* 去掉最后的“;” */
+    strFaceID = strFaceID.substr(0, strFaceID.size() - 1);
+    strFaceName = strFaceName.substr(0, strFaceName.size() - 1);
+
+
+
     nJson json0;
     json0["opName"] = "SPSS_InsertToOnWork";
     nJson json1;
     json1["nChID"] = onWorkInfo.ChannelID;
-    json1["RoomID"] = onWorkInfo.RoomID;
-    json1["FaceID"] = onWorkInfo.FaceID;
-    json1["StartTime"] = onWorkInfo.StartTime;
-    json1["EndTime"] = onWorkInfo.EndTime;
-    
-    json1["CamerID"] = onWorkInfo.DeviceID;
-    json1["ActionID"] = onWorkInfo.ActionID;
+    json1["CamerId"] = onWorkInfo.CameraID;
+    json1["FaceIdList"] = strFaceID;
+    json1["FaceNameList"] = strFaceName;
+    json1["StartTime"] = onWorkInfo.StartTime.toString("yyyy-MM-dd hh:mm:ss").toStdString();
+    json1["EndTime"] = onWorkInfo.EndTime.toString("yyyy-MM-dd hh:mm:ss").toStdString();
+    json1["MaxNumber"] = onWorkInfo.MaxNum;
+    json1["MinNumber"] = onWorkInfo.MinNum;
+
     json0["paramList"] = json1;
 
     QString strCmd = QString::fromStdString(json0.dump());