#include "FuncOnAndOffWork.h" #include "GlobalVariable.h" #include "GlobalConfig.h" #include "UniversalFunc.h" #include "FromRedis.h" #include "FromWebAPI.h" DecCondition::DecCondition() { ChannelID = -1; leaveTimeMaxNum = 0; leaveNumOnTime = 0; leaveOneTime = 0; } DecCondition::DecCondition(const DecCondition& other) { ChannelID = other.ChannelID; leaveTimeMaxNum = other.leaveTimeMaxNum; leaveNumOnTime = other.leaveNumOnTime; leaveOneTime = other.leaveOneTime; } DecCondition& DecCondition::operator=(const DecCondition& other) { if (this != &other) { ChannelID = other.ChannelID; leaveTimeMaxNum = other.leaveTimeMaxNum; leaveNumOnTime = other.leaveNumOnTime; leaveOneTime = other.leaveOneTime; } return *this; } RoomOnWorkInfo::RoomOnWorkInfo() { bOnWork = false; PKID = 0; ChannelID = 0; RoomID = 0; CameraID = 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"); strImagePath = ""; listLeaveTime.clear(); listPersonInfo.clear(); } RoomOnWorkInfo& RoomOnWorkInfo::operator=(const RoomOnWorkInfo& other) { if (this != &other) { bOnWork = other.bOnWork; PKID = other.PKID; ChannelID = other.ChannelID; RoomID = other.RoomID; CameraID = other.CameraID; RoomType = other.RoomType; strRoomName = other.strRoomName; StartTime = other.StartTime; EndTime = other.EndTime; strImagePath = other.strImagePath; listPersonInfo = other.listPersonInfo; listLeaveTime = other.listLeaveTime; } return *this; } RoomOnWorkInfo::RoomOnWorkInfo(const RoomOnWorkInfo& other) { bOnWork = other.bOnWork; PKID = other.PKID; ChannelID = other.ChannelID; RoomID = other.RoomID; CameraID = other.CameraID; RoomType = other.RoomType; strRoomName = other.strRoomName; StartTime = other.StartTime; EndTime = other.EndTime; strImagePath = other.strImagePath; listPersonInfo = other.listPersonInfo; listLeaveTime = other.listLeaveTime; } void RoomOnWorkInfo::clear() { bOnWork = false; PKID = 0; ChannelID = 0; RoomID = 0; CameraID = 0; RoomType = 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"); strImagePath = ""; listLeaveTime.clear(); listPersonInfo.clear(); } /* 添加人员信息,进行查重 */ void RoomOnWorkInfo::addPersonInfo(const std::list& vecInfo) { for(auto& it : vecInfo) { /* 查重 */ bool bFind = false; for(auto& it0 : listPersonInfo) { if(it0.PersonID == it.PersonID && it0.PersonName == it.PersonName) { bFind = true; break; } } if(!bFind) { listPersonInfo.push_back(it); } } } /* 更新在岗时间 */ void RoomOnWorkInfo::updateOnWorkTime(const QDateTime& time) { for(auto& it : listPersonInfo) { it.lastOnWork = time; } } /* 获取人脸ID字符串 */ std::string RoomOnWorkInfo::getFaceIDListString() { std::string strFaceList; for(const auto& it : listPersonInfo) { strFaceList += it.PersonID + ";" ; } /* 去掉最后的“;” */ strFaceList = strFaceList.substr(0, strFaceList.size() - 1); return strFaceList; } /* 获取人脸字符串 */ std::string RoomOnWorkInfo::getFaceNameListString() { std::string strFaceName; for(const auto& it : listPersonInfo) { strFaceName += it.PersonName + ";"; } /* 去掉最后的“;” */ strFaceName = strFaceName.substr(0, strFaceName.size() - 1); return strFaceName; } /* 获取离岗时间字符串 */ std::string RoomOnWorkInfo::getLeaveTimeString() { std::string strLeaveTime; for(const auto& it : listLeaveTime) { strLeaveTime += it.toString("yyyy-MM-dd hh:mm:ss").toStdString() + ";"; } /* 去掉最后的“;” */ strLeaveTime = strLeaveTime.substr(0, strLeaveTime.size() - 1); return strLeaveTime; } /* 获取人员最后在岗时间字符串 */ std::string RoomOnWorkInfo::getLastOnWorkTimeString() { std::string strLastOnWorkTime; for(const auto& it : listPersonInfo) { strLastOnWorkTime += it.lastOnWork.toString("yyyy-MM-dd hh:mm:ss").toStdString() + ";"; } /* 去掉最后的“;” */ strLastOnWorkTime = strLastOnWorkTime.substr(0, strLastOnWorkTime.size() - 1); return strLastOnWorkTime; } /* 添加一次离岗时间 */ void RoomOnWorkInfo::addOneLeaveTime(const QDateTime& time, int maxLeaveTime) { if(isLeaveTimeExist(time)) { return; } /* 对时间个数进行限制,不能太多 */ if(listLeaveTime.size() > maxLeaveTime) { listLeaveTime.pop_front(); } listLeaveTime.push_back(time); } /* 对离岗时间进行查重 */ bool RoomOnWorkInfo::isLeaveTimeExist(const QDateTime& time) { for(auto& it : listLeaveTime) { if(it == time) { return true; } } return false; } FuncOnAndOffWork::FuncOnAndOffWork() { m_logger = spdlog::get("SPAServer"); if(m_logger == nullptr) { SPDLOG_ERROR("FuncOnAndOffWork logger is nullptr"); return; } } FuncOnAndOffWork::~FuncOnAndOffWork() { } void FuncOnAndOffWork::task() { while(GThreadInfo.getRunning()) { /* 休眠一段时间 */ std::this_thread::sleep_for(std::chrono::milliseconds(GVariable.ThreadSleepMS)); /* 判断是否需要退出 */ if(m_funcThreadInfo.RunState == RunTimeState::RUN_STATE_STOP) { break; } /* 判断是否在检测时间段内 */ if(!isInDetectTime(m_periodInfo)) { continue; } /* ----------------------------------------------------------------------- * 读取Redis数据(读取全部的数据,后面根据不同情况自己处理) * ----------------------------------------------------------------------- */ readRedisData(m_listSrcAlarm); /* ----------------------------------------------------------------------- * 处理数据 * ----------------------------------------------------------------------- */ /* 记录人员在岗情况 */ recordPersonOnWork(); /* 处理直播间在岗离岗报警情况 */ processRoomOnWorkAlarm(); } /* 清空数据 */ for(auto& it : m_mapRoomOnWorkInfo) { delete it.second; } m_mapRoomOnWorkInfo.clear(); m_listSrcAlarm.clearAlarmInfo(); } /* 记录在岗离岗情况 */ void FuncOnAndOffWork::recordPersonOnWork() { /* ----------------------------------------------------------------------- * 处理数据 * ----------------------------------------------------------------------- */ /* 处理数据,将报警信息的人脸信息取出来,放入到人脸信息列表中 */ for(auto& alarmInfo : m_listSrcAlarm.listAlarmInfo) { /* 添加到人脸列表中,会自动去重,自动创建对应的频道和房间信息 */ m_pListRoomFace->addRoomFaceInfo(*alarmInfo); } /* 计算人脸个数,每个房间逐个对比 */ m_nowTime = QDateTime::currentDateTime(); for(auto it = m_pListRoomFace->listRoomFaceInfo.begin(); it != m_pListRoomFace->listRoomFaceInfo.end(); ) { /* m_pListRoomFace的数据不会删除,会和历史对比,这里的MaxNum和MinNum就是历史数据 */ if(it->MaxNum < it->listPersonInfo.size()) { it->MaxNum = it->listPersonInfo.size(); } if(it->MinNum > it->listPersonInfo.size()) { it->MinNum = it->listPersonInfo.size(); } /* 判断是否需要写入数据库,一定时间写入一次,默认是10分钟写一次 */ if(m_nowTime.toSecsSinceEpoch() - it->StartTime.toSecsSinceEpoch() > GVariable.AppUpdateOnWorkTimeInterval_Time) { /* 写入数据库 */ if(m_fromWebAPI->insertOnWorkInfo(*it)) { SPDLOG_LOGGER_INFO(m_logger, "☆ 新增人脸信息,频道[{}][{}],摄像头[{}][{}],时间范围[{} - {}],人数范围[{} - {}]", it->ChannelID, GConfig.getChannelName(it->ChannelID), it->CameraID, GConfig.getCameraName(it->CameraID), it->StartTime.toString("yyyy-MM-dd hh:mm:ss").toStdString(), it->EndTime.toString("yyyy-MM-dd hh:mm:ss").toStdString(), it->MinNum, it->MaxNum); /* 删除这条信息 */ it = m_pListRoomFace->listRoomFaceInfo.erase(it); continue; }else { SPDLOG_LOGGER_ERROR(m_logger, "写入数据库tWorkOnInfo失败"); } } ++it; } } /* 处理房间人员在岗离岗报警信息(这里只有直播间的在岗离岗报警) */ void FuncOnAndOffWork::processRoomOnWorkAlarm() { /* 先获取所有的直播间,这里不需要读取所有的房间数据 * 理论上一个频率只有一个直播间 */ std::map mapRoomCamActInfo; for(auto& it : m_funcThreadInfo.listRoomCamActInfo) { /* 判断是不是直播间 */ if(it.RoomType == Enum_RoomType::ROOM_LIVE) { mapRoomCamActInfo.insert(std::make_pair(it.RoomID, it)); } } /* 获取当前频率的在岗离岗信息,在表格“tChannel”中 */ if(!getCurrentFrequencyInfo(m_funcThreadInfo.ChannelID, m_nowChnDetecRule)) { SPDLOG_LOGGER_ERROR(m_logger, "{} 获取在岗离岗信息失败", m_baseLog); return; } /* 获取当前时间 */ m_nowTime = QDateTime::currentDateTime(); /* 创建本轮的临时变量 */ m_nowRoomOnWorkInfo.clear(); /* 对所有房间挨个判断 */ for(auto& roomInfo : mapRoomCamActInfo) { bool bHasPeople = false; bool bOnWork = false; m_strBaseInfo = fmt::format("频道[{}][{}], 房间[{}][{}]:", m_funcThreadInfo.ChannelID, m_funcThreadInfo.strChannelName, roomInfo.second.RoomID, roomInfo.second.strRoomName); /* 先使用人员计数判断直播间有没有人,如果直播间有人,再使用人脸识别算法判断是否是认识的人(是认识的人才会被识别到) */ for(auto& alarm : m_listSrcAlarm.listAlarmInfo) { if(alarm->RoomID == roomInfo.first) { if(alarm->ActionID == GVariable.ActPersonCount()) { if(alarm->listBbox.size() > 0) { bHasPeople = true; break; } } } } /* 如果有人,记录可以识别到的人员信息,记录在岗时间 */ if(bHasPeople) { for(auto& alarm : m_listSrcAlarm.listAlarmInfo) { if(alarm->RoomID == roomInfo.first) { if(alarm->ActionID == GVariable.ActFaceIdentify()) { if(alarm->listPersonInfo.size() > 0) { bOnWork = true; /* 记录人员信息 */ m_nowRoomOnWorkInfo.addPersonInfo(alarm->listPersonInfo); /* 更新在岗时间 */ m_nowRoomOnWorkInfo.updateOnWorkTime(m_nowTime); } } } } } /* 查找这个房间对应的房间信息 */ RoomOnWorkInfo* pRoomOnWorkInfo = nullptr; auto it0 = m_mapRoomOnWorkInfo.find(roomInfo.first); if(it0 != m_mapRoomOnWorkInfo.end()) { pRoomOnWorkInfo = it0->second; } else { /* 没找到,就创建一个 */ pRoomOnWorkInfo = new RoomOnWorkInfo(); pRoomOnWorkInfo->bOnWork = bOnWork; pRoomOnWorkInfo->ChannelID = m_funcThreadInfo.ChannelID; pRoomOnWorkInfo->RoomID = roomInfo.first; pRoomOnWorkInfo->RoomID = roomInfo.second.RoomID; pRoomOnWorkInfo->RoomType = roomInfo.second.RoomType; pRoomOnWorkInfo->StartTime = m_nowTime; pRoomOnWorkInfo->strImagePath = m_nowRoomOnWorkInfo.strImagePath; pRoomOnWorkInfo->listPersonInfo = m_nowRoomOnWorkInfo.listPersonInfo; m_mapRoomOnWorkInfo.insert(std::make_pair(roomInfo.first, pRoomOnWorkInfo)); } if(pRoomOnWorkInfo == nullptr) { SPDLOG_LOGGER_ERROR(m_logger, "{} 创建房间在岗信息失败, 房间: {}", m_baseLog, roomInfo.second.strRoomName); continue; } /* 处理此次在岗和离岗 */ if(bOnWork) { /* 在岗 */ onWorkProcess(pRoomOnWorkInfo, roomInfo); } else { /* 离岗 */ offWorkProcess(pRoomOnWorkInfo, roomInfo); } } } /* 获取当前频率信息 */ bool FuncOnAndOffWork::getCurrentFrequencyInfo(const int ChannelID, DecCondition& info) { auto str = m_fromWebAPI->getChannelInfo(ChannelID); if(str == "") { SPDLOG_LOGGER_ERROR(m_logger, "获取通道信息失败, ChannelID:{}", ChannelID); return false; } /* 解析数据 */ try { nJson json1 = nJson::parse(str); info.ChannelID = ChannelID; info.strChannelName = json1["chnName"].is_null() ? "" : json1["chnName"].get(); info.leaveTimeMaxNum = json1["leaveNum"].is_null() ? 0 : json1["leaveNum"].get(); info.leaveNumOnTime = json1["leaveNumTime"].is_null() ? 0 : json1["leaveNumTime"].get(); info.leaveOneTime = json1["leaveLongTime"].is_null() ? 0 : json1["leaveLongTime"].get(); } catch (const nJson::parse_error& e) { SPDLOG_LOGGER_ERROR(m_logger,"解析 tChannel数据失败 数据失败:{}, 错误ID:{}",e.what(), e.id); return false; } catch (const nJson::type_error& e) { SPDLOG_LOGGER_ERROR(m_logger,"解析 tChannel数据失败 数据失败:{}, 错误ID:{}",e.what(), e.id); return false; } catch(...) { SPDLOG_LOGGER_ERROR(m_logger,"解析 tChannel数据失败 数据失败"); return false; } return true; } /** * @brief 人员在岗情况处理 1、判断上次是在岗还是离岗 (1) 上次是离岗,结束离岗报警,需要判断是否已经写入数据库 1) 已经写入数据库,更新数据库报警记录,更新结束时间,清空内存中的报警记录,主要是清空PKID,置为0 2) 还未写入数据库,打印个日志,不需要做什么操作 (2) 上次是在岗,更新数据,主要是更新图片 1) 如果上次在岗记录已经写入数据库,判断人脸列表是否相等 1) 不相等,更新数据库 2) 相等,更新在岗时间 2) 如果上次在岗记录还未写入数据库,直接写入数据库 * @param pRoomOnWorkInfo 这个是内存中的记录,是历史记录 * @param roomInfo */ void FuncOnAndOffWork::onWorkProcess(RoomOnWorkInfo* pRoomOnWorkInfo, std::pair& roomInfo) { /* 判断上次是否在岗,上次是离岗,结束离岗报警 */ if(pRoomOnWorkInfo->bOnWork == false) { SPDLOG_LOGGER_DEBUG(m_logger, "{} 上次是离岗", m_strBaseInfo); /* 判断是否已经写入数据库,已经写入就结束报警 */ if(pRoomOnWorkInfo->PKID > 0) { SPDLOG_LOGGER_INFO(m_logger, "·人员报警结束,{}", m_strBaseInfo); /* 结束报警,写入数据库 */ m_fromWebAPI->endAlarmInfoByPKID(pRoomOnWorkInfo->PKID, m_nowTime); /* 删除离岗记录,重新开始 */ pRoomOnWorkInfo->PKID = 0; pRoomOnWorkInfo->listLeaveTime.clear(); pRoomOnWorkInfo->StartTime = m_nowTime; }else { /* 没有写入数据库 */ SPDLOG_LOGGER_INFO(m_logger, "·{}人员离岗报警结束,结束时间:{}", m_strBaseInfo, m_nowTime.toString("yyyy-MM-dd hh:mm:ss").toStdString()); } } pRoomOnWorkInfo->bOnWork = true; /* 记录在岗最后一次的状态,主要是更新图片 */ if(m_nowRoomOnWorkInfo.strImagePath != "") { pRoomOnWorkInfo->strImagePath = m_nowRoomOnWorkInfo.strImagePath; } /* 在岗记录还未写入数据库,就写入数据库 */ if(0 == pRoomOnWorkInfo->PKID) { SPDLOG_LOGGER_DEBUG(m_logger, "{}在岗人脸:{},{}", m_strBaseInfo, m_nowRoomOnWorkInfo.getFaceNameListString(), m_nowRoomOnWorkInfo.getLeaveTimeString()); /* 删除离岗人员和非法人员,未知人员不判断为离岗 */ deleteNoWorkPerson(m_nowRoomOnWorkInfo.listPersonInfo); SPDLOG_LOGGER_DEBUG(m_logger, "{}删除离岗后的人员信息:{}", m_strBaseInfo, m_nowRoomOnWorkInfo.getFaceNameListString()); /* 写入数据库 */ if(m_nowRoomOnWorkInfo.listPersonInfo.size() > 0) { pRoomOnWorkInfo->listPersonInfo.assign(m_nowRoomOnWorkInfo.listPersonInfo.begin(), m_nowRoomOnWorkInfo.listPersonInfo.end()); AlarmInfo alarmInfo; alarmInfo.appFunction = m_funcThreadInfo.appFunction; alarmInfo.ChannelID = m_funcThreadInfo.ChannelID; alarmInfo.RoomID = pRoomOnWorkInfo->RoomID; alarmInfo.DeviceID = 0; if(roomInfo.second.mapCameraAction.size() == 1) { alarmInfo.DeviceID = roomInfo.second.mapCameraAction.begin()->first; } alarmInfo.listBbox = getCameraNameList(roomInfo.second.mapCameraAction); /* 直播间摄像机列表 */ alarmInfo.ImageInfo = pRoomOnWorkInfo->strImagePath; alarmInfo.EventTime = pRoomOnWorkInfo->StartTime; alarmInfo.ActionID = ""; alarmInfo.Is_OnWork = true; alarmInfo.listPersonInfo = pRoomOnWorkInfo->listPersonInfo; alarmInfo.ActionDes = fmt::format("人员在岗[{}][{}]", alarmInfo.getFaceIDListString(), alarmInfo.getFaceNameListString()); int PKID = 0; m_fromWebAPI->insertAlarmInfo(alarmInfo, PKID); if(PKID > 0) { pRoomOnWorkInfo->PKID = PKID; } } } else { /* 在岗记录已经写入数据库,对比人脸列表是否相等 */ if(m_nowRoomOnWorkInfo.getFaceIDListString() != pRoomOnWorkInfo->getFaceIDListString()) { if(m_nowRoomOnWorkInfo.listPersonInfo.size() > 0) { /* 合并在岗人员 */ m_nowRoomOnWorkInfo.addPersonInfo(pRoomOnWorkInfo->listPersonInfo); SPDLOG_LOGGER_DEBUG(m_logger, "合并在岗人脸信息前: {}; {}", m_nowRoomOnWorkInfo.getFaceNameListString(), m_nowRoomOnWorkInfo.getLastOnWorkTimeString()); /* 删除离岗人员和非法人员 */ deleteNoWorkPerson(m_nowRoomOnWorkInfo.listPersonInfo); SPDLOG_LOGGER_DEBUG(m_logger, "删除离岗人员信息后: {}", m_nowRoomOnWorkInfo.getFaceNameListString()); /* 更新在岗信息 */ if(m_nowRoomOnWorkInfo.listPersonInfo.size() > 0) { pRoomOnWorkInfo->listPersonInfo.assign(m_nowRoomOnWorkInfo.listPersonInfo.begin(), m_nowRoomOnWorkInfo.listPersonInfo.end()); /* 更新到数据库 */ if(m_fromWebAPI->updatePersonInfo(*pRoomOnWorkInfo)) { SPDLOG_LOGGER_INFO(m_logger, "·更新在岗人员信息成功,{}{}{}", m_strBaseInfo, pRoomOnWorkInfo->getFaceIDListString(), pRoomOnWorkInfo->getFaceNameListString()); }else { SPDLOG_LOGGER_ERROR(m_logger, "·更新在岗人员信息失败,{}", m_strBaseInfo); } } } if(m_nowRoomOnWorkInfo.listPersonInfo.size() <= 0) { SPDLOG_LOGGER_DEBUG(m_logger, "没有在岗人员信息,不更新在岗人员"); } }else { /* 人员信息没有变化,更新在岗时间 */ pRoomOnWorkInfo->updateOnWorkTime(m_nowTime); SPDLOG_LOGGER_DEBUG(m_logger, "人员信息没有变化,更新在岗时间: {}", m_nowRoomOnWorkInfo.getLastOnWorkTimeString()); } } } /** * @brief 人员离岗情况处理 1、判断上次是在岗还是离岗 (1) 上次是在岗,开启离岗报警,然后判断是否已经写入数据库,更新离岗时间 1) 已经写入数据库,更新在岗结束,离岗开始 2) 还未写入数据库,打印个日志,不需要做什么操作 (2) 上次是离岗,不需要做啥 2、更新在岗离岗状态,主要是更新图片 3、判断有没有写入数据库 * @param pRoomOnWorkInfo * @param roomInfo */ void FuncOnAndOffWork::offWorkProcess(RoomOnWorkInfo* pRoomOnWorkInfo, std::pair& roomInfo) { if(true == pRoomOnWorkInfo->bOnWork) { /* 上次是在岗 */ SPDLOG_LOGGER_DEBUG(m_logger, "{} 上次是在岗", m_strBaseInfo); pRoomOnWorkInfo->bOnWork = false; /* 判断有没有写入数据库 */ if(pRoomOnWorkInfo->PKID > 0) { SPDLOG_LOGGER_INFO(m_logger, "人员在岗结束(PKID:{}),离岗开始,{}", pRoomOnWorkInfo->PKID, m_strBaseInfo); /* 更新数据库,结束在岗 */ m_fromWebAPI->endAlarmInfoByPKID(pRoomOnWorkInfo->PKID, m_nowTime); pRoomOnWorkInfo->PKID = 0; pRoomOnWorkInfo->StartTime = m_nowTime; }else { /* 没有写入数据库 */ SPDLOG_LOGGER_INFO(m_logger, "人员在岗结束,离岗开始,{}", m_strBaseInfo); } pRoomOnWorkInfo->addOneLeaveTime(m_nowTime, m_nowChnDetecRule.leaveTimeMaxNum); auto strLeaveTime = pRoomOnWorkInfo->getLeaveTimeString(); if(strLeaveTime != "") { SPDLOG_LOGGER_DEBUG(m_logger, "★ 人员最近离岗时间, {}, {}", m_strBaseInfo, strLeaveTime); } } else { /* 上次是离岗 */ 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_nowTime); 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; 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_nowTime); 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(); 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); } } } } } } /* 删除离岗人员和未知人员信息 */ void FuncOnAndOffWork::deleteNoWorkPerson(std::list& listPersonInfo) { /* 删除离岗人员 */ for(auto it = listPersonInfo.begin(); it != listPersonInfo.end();) { if((it->lastOnWork < m_nowTime) || it->PersonID == "-1" || it->PersonID == "-2") { it = listPersonInfo.erase(it); } else { ++it; } } } /* 获取当前直播间的摄像机名称列表 */ std::list FuncOnAndOffWork::getCameraNameList(const std::map>& mapCameraAction) { std::list listCameraName; for(const auto& it : mapCameraAction) { listCameraName.push_back(m_funcThreadInfo.getCameraName(it.first)); } return listCameraName; } /* 创建报警记录 */ // void FuncOnAndOffWork::createAlarmInfo(RoomOnWorkInfo* pRoomOnWorkInfo, std::pair& 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; // } /* 读取Redis数据 */ // void FuncOnAndOffWork::readRedisData() // { // m_listSrcAlarm.clearAlarmInfo(); // /* 读取Redis数据 */ // for(const auto& roomInfo : m_funcThreadInfo.listRoomCamActInfo) // { // for(const auto& cam : roomInfo.mapCameraAction) // { // for(const auto act : cam.second) // { // /* 读取Redis数据 */ // std::string strKey = std::to_string(cam.first) + ":" + act; // std::string strRetValue; // // SPDLOG_LOGGER_DEBUG(m_logger, "读取Redis数据, Key:{}", strKey); // if(!m_fromRedis->getRedisString(strKey, strRetValue)) // { // // SPDLOG_LOGGER_ERROR(m_logger, "读取Redis数据失败, Key:{}", strKey); // std::this_thread::sleep_for(std::chrono::milliseconds(10)); // continue; // } // /* 解析数据,先设置基础数据 */ // AlarmInfo newAlarmInfo; // newAlarmInfo.ChannelID = m_funcThreadInfo.ChannelID; // newAlarmInfo.appFunction = m_funcThreadInfo.appFunction; // newAlarmInfo.RoomID = roomInfo.RoomID; // newAlarmInfo.DeviceID = cam.first; // newAlarmInfo.ActionID = act; // parseRedisBaseData(strRetValue, newAlarmInfo); // parseRedisBBoxesData(strRetValue, newAlarmInfo); // /* 判断事件的时效性,超过多少秒不更新就可能是超脑挂了 */ // if(!isEventTimeVaild(newAlarmInfo.EventTime)) // { // /* 事件时间超过600秒,可能是超脑挂了 */ // SPDLOG_LOGGER_WARN(m_logger, "Redis Key:{} 数据长时间没有更新,EventTime:{}",strKey, newAlarmInfo.EventTime.toString("yyyy-MM-dd hh:mm:ss").toStdString()); // std::this_thread::sleep_for(std::chrono::milliseconds(100)); // continue; // } // m_listSrcAlarm.addAlarmInfo(newAlarmInfo); // SPDLOG_LOGGER_DEBUG(m_logger, "报警数据: {}, 房间ID: {}, 报警时间: {}, bBox数目: {}, Person数目: {}", // strKey, roomInfo.RoomID, newAlarmInfo.EventTime.toString("yyyy-MM-dd hh:mm:ss").toStdString(), // newAlarmInfo.listBbox.size(), newAlarmInfo.listPersonInfo.size()); // } // } // } // }