|  | @@ -540,6 +540,17 @@ uint32_t CResistAlarmMng::GeneralAlarmSet(uint8_t** pack, int* len)
 | 
	
		
			
				|  |  |  			yyjson_mut_obj_add_int(doc, conf, "up_warn_high_limit", pInfo->up_warn_high_limit);
 | 
	
		
			
				|  |  |  		}
 | 
	
		
			
				|  |  |  		break;
 | 
	
		
			
				|  |  | +		case eZL_ALARMTYPE::RETENSION_FORCE:
 | 
	
		
			
				|  |  | +		{
 | 
	
		
			
				|  |  | +			auto conf = yyjson_mut_arr(doc);
 | 
	
		
			
				|  |  | +			yyjson_mut_obj_add_val(doc, obj, "conf", conf);
 | 
	
		
			
				|  |  | +			auto pInfo = (tagRetension_Force_Drop*)ss;
 | 
	
		
			
				|  |  | +			yyjson_mut_obj_add_bool(doc, conf, "enable", pInfo->enable);
 | 
	
		
			
				|  |  | +			yyjson_mut_obj_add_int(doc, conf, "dw_alarm_low_drop", pInfo->dw_alarm_low_drop);
 | 
	
		
			
				|  |  | +			yyjson_mut_obj_add_int(doc, conf, "alarm_low_percent", pInfo->alarm_low_percent);
 | 
	
		
			
				|  |  | +			yyjson_mut_obj_add_int(doc, conf, "alarm_high_percent", pInfo->alarm_high_percent);
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +		break;
 | 
	
		
			
				|  |  |  		default:
 | 
	
		
			
				|  |  |  			ASSERT(0);
 | 
	
		
			
				|  |  |  			break;
 | 
	
	
		
			
				|  | @@ -1524,7 +1535,7 @@ void CResistAlarmMng::JudgeAlarm(CResistAlarmMng* pService, RETENSION_FORCE_DROP
 | 
	
		
			
				|  |  |  	bool bAlarm = false, bWarn = false;
 | 
	
		
			
				|  |  |  	if (show_val < pConstRetensionForceWaveInfo->dw_alarm_low_drop) //当前值小于预警值
 | 
	
		
			
				|  |  |  	{
 | 
	
		
			
				|  |  | -		bWarn = true;
 | 
	
		
			
				|  |  | +		bAlarm = true;
 | 
	
		
			
				|  |  |  		alarm_refer = pConstRetensionForceWaveInfo->dw_alarm_low_drop;
 | 
	
		
			
				|  |  |  		alarm_value = show_val;
 | 
	
		
			
				|  |  |  		loworhigh = eLowHigh::LH_LOW;
 | 
	
	
		
			
				|  | @@ -1579,7 +1590,7 @@ void CResistAlarmMng::JudgeAlarm(CResistAlarmMng* pService, RETENSION_FORCE_DROP
 | 
	
		
			
				|  |  |  			pAlarmInfo = new ALARM_INFO;
 | 
	
		
			
				|  |  |  			pAlarmInfo->event_id = hjfunc_GetGUID();
 | 
	
		
			
				|  |  |  			pAlarmInfo->id = ++pService->m_nAlarmID;
 | 
	
		
			
				|  |  | -			pAlarmInfo->level = level;// 预警
 | 
	
		
			
				|  |  | +			pAlarmInfo->level = level;
 | 
	
		
			
				|  |  |  			pAlarmInfo->mo = mo;
 | 
	
		
			
				|  |  |  			pAlarmInfo->mp = mp;
 | 
	
		
			
				|  |  |  			pAlarmInfo->no = (uint8_t)posi;
 | 
	
	
		
			
				|  | @@ -1593,8 +1604,16 @@ void CResistAlarmMng::JudgeAlarm(CResistAlarmMng* pService, RETENSION_FORCE_DROP
 | 
	
		
			
				|  |  |  			pAlarmInfo->zzjno = pMoMpInfo->zzjno;
 | 
	
		
			
				|  |  |  			pAlarmInfo->sunroof = bSkylight;
 | 
	
		
			
				|  |  |  			char szInfo[200] = { 0 };
 | 
	
		
			
				|  |  | -			sprintf_s(szInfo, sizeof(szInfo), "保持力异常预警,位置:%s, 报警值为%dN, 上一次值:%dN, 参考值为%dN",
 | 
	
		
			
				|  |  | -				posi == eSuoBiPosi::SB_FIX ? "定位" : "反位", show_val, nOldVal, alarm_refer);
 | 
	
		
			
				|  |  | +			if (level == 1) {
 | 
	
		
			
				|  |  | +				sprintf_s(szInfo, sizeof(szInfo), "保持力超最低值报警,位置:%s, 报警值为%dN,  参考值为%dN",
 | 
	
		
			
				|  |  | +					posi == eSuoBiPosi::SB_FIX ? "定位" : "反位", show_val, alarm_refer);
 | 
	
		
			
				|  |  | +			}else if(loworhigh == eLowHigh::LH_LOW){
 | 
	
		
			
				|  |  | +				sprintf_s(szInfo, sizeof(szInfo), "保持力下降超%d%%预警,位置:%s, 报警值为%dN,  参考值为%dN", pConstRetensionForceWaveInfo->alarm_low_percent,
 | 
	
		
			
				|  |  | +					posi == eSuoBiPosi::SB_FIX ? "定位" : "反位", show_val, alarm_refer);
 | 
	
		
			
				|  |  | +			}else if (loworhigh == eLowHigh::LH_HIGH) {
 | 
	
		
			
				|  |  | +				sprintf_s(szInfo, sizeof(szInfo), "保持力上升超%d%%预警,位置:%s, 报警值为%dN,  参考值为%dN", pConstRetensionForceWaveInfo->alarm_high_percent,
 | 
	
		
			
				|  |  | +					posi == eSuoBiPosi::SB_FIX ? "定位" : "反位", show_val, alarm_refer);
 | 
	
		
			
				|  |  | +			}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  			pAlarmInfo->desc = szInfo;
 | 
	
		
			
				|  |  |  			lock_guard<mutex> lock(pService->m_mtxAlarm);
 | 
	
	
		
			
				|  | @@ -1883,6 +1902,30 @@ void CResistAlarmMng::ThreadProcAlarmSet(DWORD_PTR param)
 | 
	
		
			
				|  |  |  	Sleep(2000);
 | 
	
		
			
				|  |  |  	time_t tmNow;
 | 
	
		
			
				|  |  |  	bool bLock = false;
 | 
	
		
			
				|  |  | +	
 | 
	
		
			
				|  |  | +	int detectTimeByna = ::GetPrivateProfileInt("SET", "retension_dynamic", 600, g_strIniPath);//动态保持力检测时间为10分钟 600
 | 
	
		
			
				|  |  | +	int detectTimeRed = ::GetPrivateProfileInt("SET", "retension_red", 30, g_strIniPath);//红线保持力检测时间为30秒    30
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	time_t detectTimeBynaTime = 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	long  detectFourAlarm = 4 * 60 * 60; //4*60*60; //四个小时重复报警
 | 
	
		
			
				|  |  | +	time_t detectFourAlarmTime = 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	int dwAlarmLowDropGet = 3000;    //获取到的最低预警值
 | 
	
		
			
				|  |  | +	int alarmLowPercentGet = 20;    //下降百分比报警值,20%
 | 
	
		
			
				|  |  | +	int alarmHighPercentGet = 40;    //上升百分比报警值,40%
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	int detectToday0 = 3000;//定位保持力参考值
 | 
	
		
			
				|  |  | +	time_t detectTodayTime0=0;
 | 
	
		
			
				|  |  | +	int detectToday1 = 3000;//反位保持力参考值
 | 
	
		
			
				|  |  | +	time_t detectTodayTime1=0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	eDaoChaPosi posiToday = eDaoChaPosi::DCP_FIX; //当日位置
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	DAOCHA_POSITION	posiLast = DAOCHA_POSITION::MP_FIX;	  //最近一次过车位置
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	time_t detectlastMoveTime = 0;//20秒内是否板动的,最近一次
 | 
	
		
			
				|  |  | +	
 | 
	
		
			
				|  |  |  	do 
 | 
	
		
			
				|  |  |  	{
 | 
	
		
			
				|  |  |  		if (bLock)
 | 
	
	
		
			
				|  | @@ -2536,7 +2579,7 @@ void CResistAlarmMng::ThreadProcAlarmSet(DWORD_PTR param)
 | 
	
		
			
				|  |  |  		}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  		//保持力下降检测
 | 
	
		
			
				|  |  | -		if (tmNow - pService->m_lastDetectDrop >= 30)
 | 
	
		
			
				|  |  | +		if (tmNow - pService->m_lastDetectDrop >= detectTimeRed)
 | 
	
		
			
				|  |  |  		{
 | 
	
		
			
				|  |  |  			pService->m_lastDetectDrop = tmNow;
 | 
	
		
			
				|  |  |  			time_t tt;
 | 
	
	
		
			
				|  | @@ -2547,8 +2590,11 @@ void CResistAlarmMng::ThreadProcAlarmSet(DWORD_PTR param)
 | 
	
		
			
				|  |  |  				if (item.second->enable == false) continue;
 | 
	
		
			
				|  |  |  				if (item.second->type != eZL_ALARMTYPE::RETENSION_FORCE) //这个逻辑里面只支持保持力
 | 
	
		
			
				|  |  |  					continue;
 | 
	
		
			
				|  |  | +				auto pAlarmSet = (RETENSION_FORCE_DROP*)item.second;
 | 
	
		
			
				|  |  |  				if ((eSuoBiPosi)item.second->no != eSuoBiPosi::SB_FIX && (eSuoBiPosi)item.second->no != eSuoBiPosi::SB_INVERT)
 | 
	
		
			
				|  |  |  					continue;
 | 
	
		
			
				|  |  | +				int isRedAlarm = 0;
 | 
	
		
			
				|  |  | +			
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  				string momp = item.second->momp;
 | 
	
		
			
				|  |  |  				if (momp.empty())
 | 
	
	
		
			
				|  | @@ -2566,7 +2612,7 @@ void CResistAlarmMng::ThreadProcAlarmSet(DWORD_PTR param)
 | 
	
		
			
				|  |  |  				if (pInfo == nullptr) continue;
 | 
	
		
			
				|  |  |  				if (pInfo->pDeivce == nullptr) continue;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -				auto pAlarmSet = (RETENSION_FORCE_DROP*)item.second;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  				auto pMap0 = pInfo->pDeivce->GetStatInfo(pInfo->idx, 0);
 | 
	
		
			
				|  |  |  				auto pMap1 = pInfo->pDeivce->GetStatInfo(pInfo->idx, 1);
 | 
	
		
			
				|  |  |  				if (pMap0->size() < 2) continue;
 | 
	
	
		
			
				|  | @@ -3489,9 +3535,9 @@ void CResistAlarmMng::ThreadProcMoveFromDB(DWORD_PTR param)
 | 
	
		
			
				|  |  |  			   //mg_315_server->SendCurveData(pMompInfo->zzjno, posi, 1, true, mapData, it.tmStart, it.tmEnd);
 | 
	
		
			
				|  |  |  		   }
 | 
	
		
			
				|  |  |  			   break;
 | 
	
		
			
				|  |  | -		   default:
 | 
	
		
			
				|  |  | -			   SPDLOG_WARN("[扳动数据有误]{}:{} type:{}", mo, mp, type);
 | 
	
		
			
				|  |  | -			   ASSERT(0);
 | 
	
		
			
				|  |  | +		   default:
 | 
	
		
			
				|  |  | +			   SPDLOG_WARN("[扳动数据有误]{}:{} type:{}", mo, mp, type);
 | 
	
		
			
				|  |  | +			   ASSERT(0);
 | 
	
		
			
				|  |  |  			   break;
 | 
	
		
			
				|  |  |  		   }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -3838,11 +3884,68 @@ BOOL CResistAlarmMng::LoadAlarmID()
 | 
	
		
			
				|  |  |  	return TRUE;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +BOOL CResistAlarmMng::LoadMoveData(string momp, time_t* showTime,int* showVal, int posi)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	 SYSTEMTIME tmNow;
 | 
	
		
			
				|  |  | +	GetLocalTime(&tmNow);
 | 
	
		
			
				|  |  | +	string table_name = fmt::format("rm_move_{:0>4}{:0>2}", tmNow.wYear, tmNow.wMonth);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	CString sql = fmt::format("SELECT TOP 1 show_time,show_val FROM  {} WHERE  mo +'.'+  mp = '{}'  and type = 2  and posi = {} ORDER BY show_time DESC;", table_name, momp,posi).c_str();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	COdbcStatement stmt;
 | 
	
		
			
				|  |  | +	if (!CDBConnectPool::Instance()->DBQuery(stmt, sql))
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		CSimpleLog::Error("执行语句失败" + sql);
 | 
	
		
			
				|  |  | +		return FALSE;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +	TIMESTAMP_STRUCT	showTimeT;
 | 
	
		
			
				|  |  | +	
 | 
	
		
			
				|  |  | +	int nCol = 1;
 | 
	
		
			
				|  |  | +	int   showValT;
 | 
	
		
			
				|  |  | +	stmt.BindTimeStampCol(nCol++, &showTimeT);	
 | 
	
		
			
				|  |  | +	stmt.BindIntCol(nCol++, &showValT);
 | 
	
		
			
				|  |  | +	int i = 0;
 | 
	
		
			
				|  |  | +	do
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		
 | 
	
		
			
				|  |  | +		if (stmt.FetchNext() != 0) {
 | 
	
		
			
				|  |  | +			return false;
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +		*showTime = CTime(showTimeT.year, showTimeT.month, showTimeT.day, showTimeT.hour, showTimeT.minute, showTimeT.second).GetTime() * 1000 + showTimeT.fraction / 1000000;
 | 
	
		
			
				|  |  | +		*showVal = showValT;
 | 
	
		
			
				|  |  | +	} while (false);
 | 
	
		
			
				|  |  | +	stmt.Close();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return true;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +BOOL CResistAlarmMng::isBetweenFiveAndFiveTen() {
 | 
	
		
			
				|  |  | +	auto now = std::chrono::system_clock::now();
 | 
	
		
			
				|  |  | +	std::time_t now_c = std::chrono::system_clock::to_time_t(now);
 | 
	
		
			
				|  |  | +	std::tm* now_tm = std::localtime(&now_c);
 | 
	
		
			
				|  |  | +	bool is_between = (now_tm->tm_hour == 5) && (now_tm->tm_min >= 0) && (now_tm->tm_min <= 15);
 | 
	
		
			
				|  |  | +	return is_between;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +time_t CResistAlarmMng::SystemTimeToTimeT(const SYSTEMTIME& st) {
 | 
	
		
			
				|  |  | +	struct tm t = { 0 };   
 | 
	
		
			
				|  |  | +	t.tm_year = st.wYear - 1900; // 年份减去1900,因为tm结构中的年份是从1900年开始计算的   
 | 
	
		
			
				|  |  | +	t.tm_mon = st.wMonth - 1;    // 月份从0开始,所以需要减1   
 | 
	
		
			
				|  |  | +	t.tm_mday = st.wDay;         // 日    
 | 
	
		
			
				|  |  | +	t.tm_hour = st.wHour;        // 小时    
 | 
	
		
			
				|  |  | +	t.tm_min = st.wMinute;       // 分钟   
 | 
	
		
			
				|  |  | +	t.tm_sec = st.wSecond;       // 秒        
 | 
	
		
			
				|  |  | +	time_t time = mktime(&t);    // mktime会将tm结构转换为自1970年1月1日以来的秒数
 | 
	
		
			
				|  |  | +	return time;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  //加载未受理和未恢复的报警
 | 
	
		
			
				|  |  |  BOOL CResistAlarmMng::LoadUnAck()
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |  	//只加载31天内的报警
 | 
	
		
			
				|  |  | -	CString sql = "  SELECT [ID],a.[mo],a.[mp],[no],[type],[occur_time],[level],[desc],[suggest],[val],[event_id],[rel_id],[posi],[loworhigh],[referval],[recovery_time],[sunroof],zzjno FROM [rm_alarm] as A \
 | 
	
		
			
				|  |  | +	CString sql = "  SELECT [ID],a.[mo],a.[mp],[no],[type],[occur_time],[level],[desc],[suggest],[val],[event_id],[rel_id],[posi],[loworhigh],[referval],[recovery_time],[sunroof],zzjno,[ack_result] FROM [rm_alarm] as A \
 | 
	
		
			
				|  |  |  		LEFT JOIN(SELECT mo, mp, zzjno FROM rm_map) AS B ON a.mo = b.mo and a.mp = b.mp \
 | 
	
		
			
				|  |  |  		WHERE DATEADD(dd, -31, getdate()) < occur_time and (ack_result = 0 OR [recovery_time] < '2000') \
 | 
	
		
			
				|  |  |  		ORDER BY ID; ";
 | 
	
	
		
			
				|  | @@ -3859,6 +3962,7 @@ BOOL CResistAlarmMng::LoadUnAck()
 | 
	
		
			
				|  |  |  	int val;
 | 
	
		
			
				|  |  |  	int id;
 | 
	
		
			
				|  |  |  	int zzjno;
 | 
	
		
			
				|  |  | +	int ackResult;
 | 
	
		
			
				|  |  |  	TIMESTAMP_STRUCT ts,tsRecovery;
 | 
	
		
			
				|  |  |  	int referval;
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -3881,6 +3985,7 @@ BOOL CResistAlarmMng::LoadUnAck()
 | 
	
		
			
				|  |  |  	stmt.BindTimeStampCol(nCol++, &tsRecovery);
 | 
	
		
			
				|  |  |  	stmt.BindTinyIntCol(nCol++, &sunroof);
 | 
	
		
			
				|  |  |  	stmt.BindIntCol(nCol++, &zzjno);
 | 
	
		
			
				|  |  | +	stmt.BindIntCol(nCol++, &ackResult);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	do
 | 
	
		
			
				|  |  |  	{
 | 
	
	
		
			
				|  | @@ -3906,6 +4011,7 @@ BOOL CResistAlarmMng::LoadUnAck()
 | 
	
		
			
				|  |  |  		ConvertData(tsRecovery, pAlarm->recoveryTime);
 | 
	
		
			
				|  |  |  		pAlarm->sunroof = sunroof;
 | 
	
		
			
				|  |  |  		pAlarm->zzjno = zzjno;
 | 
	
		
			
				|  |  | +		pAlarm->ack_result = ackResult;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  		m_lstUnConfirmAlarm.push_back(pAlarm);
 | 
	
		
			
				|  |  |  
 |