
using namespace std;

#include <QFile>
#include <QXmlStreamWriter>
#include <QtXml/QDomDocument>
#include <QtXml/QDomElement>
#include <QtXml/QDomNode>
#include <QtXml/QDomNodeList>
#include <QtCore/qglobal.h>
#include <QStringList>
#include <QSettings>
#include <QDateTime>
#include <QDir>
#include <QFileInfo>
#include <QDebug>
#include <QMutex>
#include <QMap>
#include <ctime>
#define OTL_ODBC_ODBC
#define OTL_ODBC_UNIX
#include <unistd.h>

#include "otlv4.h"
#include <stdio.h>

#include <sstream> //lnk 2024-10-16
#include <set>	//写去重的设备类型
#include <fstream>//上传文件

#include "../mms/db_interface.h"
#include "../json/save2json.h"
#include "../json/mms_json_inter.h"

#include "../mms/rdb_client.h"
#include "../mms/interface.h"
#include "../json/cjson.h"//WW 2023-08-27新增json解析函数
#include "../include/curl/curl.h" 

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

	extern pt61850app_t* g_pt61850app;
	extern node_t* g_node;
	extern apr_pool_t* g_cfg_pool;
	extern apr_pool_t* g_init_pool;
	extern apr_pool_t* g_temp_dev_pool;
	extern char			subdir[128];
	extern int g_front_seg_index;

	extern unsigned int	g_no_auth;
	extern char				g_onlyIP[255];			//直连某个IP，仅仅为方便测试

	int					g_DevFlag = 0;

#ifdef __cplusplus
}
#endif
///////////////////////////////lnk20250118台账变更使用的内存池：动态内存池的方式，每个内存池放一个ied的所有相关内容，这个方案暂不使用，只保留相关实现函数
// 用于存储终端 ID 和对应的子池
std::list<std::pair<std::string, apr_pool_t*> > pool_list;
///////////////////////////////////////////////////



//ZW 2023-10-10 单条补招结构
class RecallInfo
{
public:
	long long starttime;
	long long endtime;
};

//CZY 2023-09-17 控制命令解析
class ProgramParam //
{
public:
	QList<QString> terminal_list;//终端id列表
	QString file_name;//程序下装可用，下装程序在oss中的位置

};

//CZY 2023-09-17 控制命令解析
class RecallParam //
{
public:
	QString mp_id;//监测点id
	QString start;//补招数据起始时间
	QString end;//补招数据结束时间
	int voltage;//暂态数据标志
	int stat;//稳态数据标志
};

//CZY 2023-10-12 装置识别码与密钥
class terminal_ext //
{
public:
	char terminal_identify_code[100];//终端识别码
	char terminal_key[100];//终端密钥
};

class CJournalRecall //日志补招结构类
{
public:
	QString MonitorID; //线路监测点号
	QString StartTime; //数据补招起始时间
	QString EndTime;   //数据补招结束时间
	QString STEADY;    //补招历史统计数据标识 0-不补招；1-补招     
	QString VOLTAGE;   //补招暂态事件标识 0-不补招；1-补招
};

/*lnk 2024-10-15 */
class ledger_monitor //监测点台账
{
public:
	char monitor_id[64];
    char terminal_code[64];
    char monitor_name[64];
    char logical_device_seq[64];
    char voltage_level[64];
    char terminal_connect[64];
    char timestamp[64];
	char status[255];
	char count_cfg[64];	//不是台账的一部分，用来记录数据库或业务中台的台账数量
};

class terminal_dev //终端台账
{
public:
	char terminal_id[64];
    char terminal_code[64];
    char org_name[64];
    char maint_name[64];
    char station_name[64];
    char tmnl_factory[64];
    char tmnl_status[64];
    char dev_type[64];
    char dev_key[255];
    char dev_series[255];
    char addr_str[64];
    char port[64];
    char timestamp[64];

	//lnk20250210添加进程号
	char processNo[64];

    ledger_monitor line[10];

	char count_cfg[64];	//不是台账的一部分，用来记录数据库或业务中台的台账数量
};

class icd_model //icd模型
{
public:
	char model_id[64];
    char tmnl_type[64];
	char tmnl_type_id[64];	//不使用
    char tmnl_factory[64];	//不使用
    char file_name[128];
	char file_path[128];
    char timestamp[64];
};

class front_list//前置表
{
public:
	char front_ip[64];
    char front_port[64];
    char front_inst[64];
    char front_type[64];
    char front_status[64];
	char front_version[64];
	char mp_num[64];
};

class intact_list//前置表
{
public:
	char monitor_id[64];
    char statistical_date[64];
    char exp_num[64];
    char act_num[64];
    std::vector<std::string> value_time; //时间集合
	char last_value_time[64];
};
/*lnk 2024-10-15 */

list<CJournalRecall> g_StatisticLackList; //日志补招结构类链表

QMutex g_StatisticLackList_list_mutex; //recall队列数据锁

QString DEVIE_CONFIG_FN = QString("Device_Config.xml");//不用
QString LINE_CONFIG_FN = QString("Line_Config.xml");//不用
QString JSON_CONFIG_FN_old = QString("JiangSu_Config.xml");//默认映射文件
QString THREE_SECS_CONFIG_FN = QString("Trigger3S.xml");//实时数据用
QString RECALL_CONFIG_FN = QString("Recall.xml");//不用

//lnk20241220创建一个用来台账更新的文件，保证数据完整的情况下更新台账
std::string LEDGER_UPDATE_FN = "LedgerUpdate.log";

const int MAX_CPUNO = 10;

//lnk20250121终端台账数量配置
int IED_COUNT = 200;	//默认200

//WW 2-23-08-20 add start
otl_connect db; //OTL数据库连接对象 WW 2023-08-20
int g_iOTLFlag = 0; //Sql是否执行标志(0-不执行；1-执行) //lnk202410-22替换web接口后关闭
std::string g_strOTLType = "PostgreSQL"; //OTL连接数据库类型
//std::string g_strOTLConnect = "pqsadmin/dnzladmin_001@pgsql"; //OTL数据库连接参数
//std::string g_strOTLConnect = "postgres/postgres@pgsql"; //OTL数据库连接参数
std::string g_strOTLConnect = "postgres/bmdev@123@pgsql"; //OTL数据库连接参数


//lnk2024-8-14添加角型接线标志,0不存在角形接线，1存在角形接线
int isdelta_flag = 0;


//////CZY 2023-09-06 config
//多前置flag:1为开启,0为关闭
int MULTIPLE_NODE_FLAG = 1;
extern const char* PROGRAM_VERSION;

extern int FRONT_MP_NUM;

int ACCOUNT_UPDATE_INTERVAL;
char* ACCOUNT_UPDATE_LAST_TIME;

int MULIT_NODE_INTERVAL;

int COMMUNICATION_LOG_STATUS_TIME;
int COMMUNICATION_LOG_ABNORMAL_TIME;

char* POSTGRES_DATABASE;//数据库库名
char* POSTGRES_USERNAME;//数据库用户名
char* POSTGRES_PASSWORD;//数据库密码
char* POSTGRES_SCHEMA;//数据库模式名
char* POSTGRES_DNSNAME;//取postgres/guass库
char* POSTGRES_TABLEPREFIX;//表名前缀

char* CLIENT_ID;//中台CLIENT_ID
char* CLIENT_SECRET;//中台CLIENT_SECRET
char* TOKEN_URL;//中台取token接口
char* DEVICE_URL;//中台取终端接口
char* GRANT_TYPE;//中台GRANT_TYPE

char* UDS_UPLOAD_URL;
char* UDS_DOWNLOAD_URL;
char* UDS_DELETE_URL;

//char * OSS_ENDPOINT;
//char * ACCESS_KEY_ID;
//char * ACCESS_KEY_SECRET;
//char * BUCKET_NAME;

int  FILE_FLAG;
int  SEND_FLAG;
int FRONT_INST;
char* FRONT_IP;
int CITY_FLAG;

int recall_len;
int recall_sta;
int recall_daily;

char* BROKER_LIST;
char* TOPIC_STAT;
char* TOPIC_PST;
char* TOPIC_PLT;
char* TOPIC_EVENT;
char* TOPIC_ALARM;
char* TOPIC_SNG;

//lnk20241220
char* TOPIC_RTDATA;

char* PROTOCOL;
char* MECHANISMS;
char* KEYTAB_FILE;
char* SERVICE_NAME;
char* PRINCIPAL;
char* DOMAIN_NAME;

extern int     g_front_seg_index;
extern int     g_front_seg_num;

/*移植配置变量lnk10-9*/
//生产者
std::string G_ROCKETMQ_PRODUCER = "";//rocketmq producer
std::string G_ROCKETMQ_IPPORT = "";//rocketmq ip+port
std::string G_ROCKETMQ_TOPIC = "";//topie
std::string G_ROCKETMQ_TAG = "";//tag
std::string G_ROCKETMQ_KEY = "";//key
int QUEUENUM = 0;
std::string BROKERNAME = "";
//消费者
std::string G_ROCKETMQ_CONSUMER = "";//rocketmq consumer
std::string G_MQCONSUMER_IPPORT = "";//consumer ip+port
std::string G_MQCONSUMER_TOPIC_RT = "";//consumer topie
std::string G_MQCONSUMER_TAG_RT = "";//consumer tag
std::string G_MQCONSUMER_KEY_RT = "";//consumer key
std::string G_MQCONSUMER_ACCESSKEY = "";
std::string G_MQCONSUMER_SECRETKEY = "";
std::string G_MQCONSUMER_CHANNEL = "";
std::string G_MQCONSUMER_TOPIC_UD = "";//consumer topie
std::string G_MQCONSUMER_TAG_UD = "";//consumer tag
std::string G_MQCONSUMER_KEY_UD = "";//consumer key
std::string G_MQCONSUMER_TOPIC_RC = "";//consumer topie
std::string G_MQCONSUMER_TAG_RC = "";//consumer tag
std::string G_MQCONSUMER_KEY_RC = "";//consumer key
std::string G_MQCONSUMER_TOPIC_SET = "";//consumer topie
std::string G_MQCONSUMER_TAG_SET = "";//consumer tag
std::string G_MQCONSUMER_KEY_SET = "";//consumer key

int G_TEST_FLAG = 0;
int G_TEST_NUM = 0;

int TEST_PORT = 11000;//用于当前进程登录测试shell的端口

//终端和监测点的状态筛选
std::string TERMINAL_STATUS = "";
std::string MONITOR_STATUS = "";
std::string ICD_FLAG = "";

//保留socket连接设置开关
int SOCKET_PORT = 13000;
int SOCKETENABLE = 0;

//添加http配置和台账配置lnk20241031
int HTTPENABLE = 0;
std::string HTTP_IP = "";
int HTTP_PORT = 12000;

/*添加web接口lnk202411-6*/
std::string WEB_DEVICE = "";
std::string WEB_ICD = "";
std::string WEB_INTEGRITY = "";	//暂不使用
std::string WEB_COMFLAG = "";
std::string WEB_EVENT = "";
std::string WEB_FILEUPLOAD = "";
std::string WEB_FILEDOWNLOAD = "";

//lnk20250115添加台账锁
extern pthread_mutex_t mtx;

/*lnk 2024-10-21 */
int OTL_Select_DecideRecall_web(char* time, char* id);//判断是否需要补招
void OTL_Select_recall_web(char* time, char* id); //数据完整性补招判断
bool CheckPG_To_Recall_web(long long start, long long end, char* Monitorid);
//////////////////////////////////////////////////////////////////////////

std::string g_strUID = ""; //OTL数据库连接用户名
int g_iOTLConnectLimit = 3; //OTL数据库超时连接次数限制  注：数据库允许最大连接次数，单次数据库连接计数超过3次，重新执行数据库线程！
//数据库Sql链表---------------------------------------
extern QList<QString> Sql_data_list; //Sql执行语句链表
extern QMutex Sql_data_list_mutex; //Sql执行语句锁
extern int server_socket; //Web Socket服务端实例
extern unsigned int	g_node_id; //前置程序类型(100-500)
//WW 2023-08-20 end
////////////////////////////////////////////////////////////////////////////////////////////////////

void parse_log_switch_ini(unsigned int* error, unsigned int* warn, unsigned int* info)
{
	QString pt61850netd_pqfe_IniFilename = QString("../etc/pt61850netd_pqfe.ini");
	QSettings settings(pt61850netd_pqfe_IniFilename, QSettings::IniFormat);

	settings.beginGroup("Log");
	*error = settings.value("error", 0).toUInt();
	*warn = settings.value("warn", 0).toUInt();
	*info = settings.value("info", 0).toUInt();

	g_no_auth = settings.value("no_auth", 0).toUInt();

	g_DevFlag = settings.value("DevFlag", 0).toUInt();

	settings.endGroup();
}

//////////////////////////////////////////////////////////////////////////////////////////////////
//lnk20250114不使用的代码
#if 0
/*  xml 示例  设备终端配置
<GetDevInfoList>
<DevAccountList>
<Count>6</Count>
<DevAccount>
<DEV_Index>1268918860</DEV_Index>
<DEV_Type>PQS-882A</DEV_Type>
<DEV_IP>127.0.0.1</DEV_IP>
<DEV_PortID>102</DEV_PortID>
<DEV_Key>IXFhekB3c3gzZWRjNHJmdg==</DEV_Key>
<DEV_Series>UHFzJmNuODcwMjk5</DEV_Series>
<DEV_DevFlag>0</DEV_DevFlag>
</DevAccount>
</DevAccountList>
</GetDevInfoList>
*/
int parse_device_cfg()
{
	ied_t* ied;
	ied_usr_t* ied_usr;
	chnl_usr_t* chnl_usr;
	unsigned int count_cfg = 0;
	unsigned int count_real = 0;
	QString cfg_dir = QString("../")/*+QString::fromAscii(subdir)*/ + QString("etc/");
	QDomDocument doc;   //新建QDomDocument类对象，它代表一个XML文档
	QFile file(cfg_dir + DEVIE_CONFIG_FN);
	if (!file.open(QIODevice::ReadOnly))
		return APR_EBADPATH;  //以只读方式打开
	if (!doc.setContent(&file)) {
		file.close();
		return APR_EBADF;
	}
	//将文件内容读到doc中
	QDomElement docElem = doc.documentElement();  //返回根元素  
	QDomNode n = docElem.firstChild();   //返回根节点的第一个子节点 
	while (!n.isNull())
	{   //如果节点不为空  
		if (n.isElement())  //如果节点是元素  
		{
			QDomElement e = n.toElement();  //将其转换为元素  
			QString strTag = e.tagName();
			if (strTag == "DevAccountList") {
				QDomNodeList list = e.childNodes(); //获得元素e的所有子节点的列表  
				for (int i = 0; i < list.count(); i++) //遍历该列表  
				{
					QDomNode node = list.at(i);
					if (node.isElement()) {
						QString strTag2 = node.toElement().tagName();
						if (strTag2 == "Count") {
							count_cfg = node.toElement().text().toUInt();
							g_node->n_clients = count_cfg;
							g_node->clients = (ied_t**)apr_pcalloc(g_cfg_pool, count_cfg * sizeof(ied_t*));
							for (unsigned int k = 0; k < count_cfg; k++)
								g_node->clients[k] = (ied_t*)apr_pcalloc(g_cfg_pool, sizeof(ied_t));
						}
						else if (strTag2 == "DevAccount") {
							ied = g_node->clients[count_real++];
							ied_usr = (ied_usr_t*)apr_pcalloc(g_init_pool, sizeof(ied_usr_t));
							ied->usr_ext = ied_usr;
							if (ied_usr == NULL)
								return APR_ENOMEM;
							ied_usr->last_call_wavelist_time = sGetMsTime() + g_pt61850app->giTime * 1000;
							ied_usr->LD_info = (LD_info_t*)apr_pcalloc(g_init_pool, MAX_CPUNO * sizeof(LD_info_t));
							if (ied_usr->LD_info == NULL)
								return APR_ENOMEM;
							ied_usr->dev_flag = g_DevFlag;
							ied->chncount = 1;
							ied->channel = (channel_t*)apr_pcalloc(g_cfg_pool, sizeof(channel_t) * ied->chncount);
							ied->channel[0].ied = ied;
							ied->channel[0].status = STATUS_BREAKOFF;

							QDomNodeList list2 = node.childNodes(); //获得元素node的所有子节点的列表  
							for (int i2 = 0; i2 < list2.count(); i2++) {  //遍历该列表 							
								QDomNode node2 = list2.at(i2);
								if (node2.isElement()) {
									QString devPropTag = node2.toElement().tagName();
									QString devPropVal = node2.toElement().text();
									if (devPropTag == "DEV_Index") {
										ied_usr->dev_idx = devPropVal.toInt();
										apr_snprintf(ied_usr->terminal_code, sizeof(ied_usr->terminal_code), "%s", devPropVal.toAscii().data());
										apr_snprintf(ied_usr->terminal_id, sizeof(ied_usr->terminal_code), "%s", devPropVal.toAscii().data());
									}
									else if (devPropTag == "DEV_Type") {
										apr_snprintf(ied_usr->dev_type, sizeof(ied_usr->dev_type), "%s", devPropVal.toAscii().data());
										cout << "dev_type" << ied_usr->dev_type << endl;
									}
									else if (devPropTag == "DEV_Code") {
										apr_snprintf(ied_usr->terminal_code, sizeof(ied_usr->terminal_code), "%s", devPropVal.toAscii().data());
										cout << "dev_code" << ied_usr->terminal_code << endl;
									}
									else if (devPropTag == "DEV_Key") {
										QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());
										apr_snprintf(ied_usr->dev_key, sizeof(ied_usr->dev_key), "%s", ba.data());
									}
									else if (devPropTag == "DEV_Series") {
										QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());
										apr_snprintf(ied_usr->dev_series, sizeof(ied_usr->dev_series), "%s", ba.data());
									}
									else if (devPropTag == "DEV_DevFlag")
										ied_usr->dev_flag = devPropVal.toInt();
									else if (devPropTag == "DEV_IP") {
										ied->channel[0].channel_type = CHANNEL_TYPE_IPV4;
										ied->channel[0].addr = ntohl(inet_addr(devPropVal.toAscii().data()));
										strncpy(ied->channel[0].addr_str, devPropVal.toAscii().data(), LONGNAME - 1);
										ied->channel[0].addr_str[LONGNAME - 1] = 0;
									}
									else if (devPropTag == "DEV_PortID")
										ied->channel[0].port = devPropVal.toUInt();
								}
							}//	for(int i2=0; i2<list2.count(); i2++)
							chnl_usr = (chnl_usr_t*)apr_pcalloc(g_init_pool, sizeof(chnl_usr_t));
							ied->channel[0].connect = chnl_usr;
							chnl_usr->chnl = &(ied->channel[0]);
							chnl_usr->chnl_id = 0;
							chnl_usr->m_state = CHANNEL_DISCONNECTED;
							chnl_usr->m_ClosedMsTime = NEXT_CONNECT_TIME * (-1);
							g_pt61850app->chnl_counts++;
						} //else if ( strTag2 == "DevAccount" )
					}
				}
			}
		}
		n = n.nextSibling();  //下一个兄弟节点
	}
	if (count_real < count_cfg)
		g_node->n_clients = count_real;
	if (count_cfg != count_real)
		return APR_EBADF;
	return APR_SUCCESS;
}

int parse_line_cfg()
{
	ied_t* ied;
	ied_usr_t* ied_usr;
	int count_cfg = 0;
	int count_real = 0;
	LD_info_t line_info;
	int	dev_idx_in_line = 0;
	QString cfg_dir = QString("../")/*+QString::fromAscii(subdir)*/ + QString("etc/");
	QDomDocument doc;   //新建QDomDocument类对象，它代表一个XML文档
	QFile file(cfg_dir + LINE_CONFIG_FN);
	if (!file.open(QIODevice::ReadOnly))
		return APR_EBADPATH;  //以只读方式打开
	if (!doc.setContent(&file)) {
		file.close();
		return APR_EBADF;
	}
	//将文件内容读到doc中
	QDomElement docElem = doc.documentElement();  //返回根元素  
	QDomNode n = docElem.firstChild();   //返回根节点的第一个子节点 
	while (!n.isNull())
	{   //如果节点不为空  
		if (n.isElement())  //如果节点是元素  
		{
			QDomElement e = n.toElement();  //将其转换为元素  
			QString strTag = e.tagName();
			if (strTag == "MonitorAccountList") {
				QDomNodeList list = e.childNodes(); //获得元素e的所有子节点的列表  
				for (int i = 0; i < list.count(); i++) //遍历该列表  
				{
					QDomNode node = list.at(i);
					if (node.isElement()) {
						QString strTag2 = node.toElement().tagName();
						if (strTag2 == "Count") {
							count_cfg = node.toElement().text().toInt();
						}
						else if (strTag2 == "MonitorAccount") {
							count_real++;
							dev_idx_in_line = -1;
							memset(&line_info, 0, sizeof(line_info));
							QDomNodeList list2 = node.childNodes(); //获得元素node的所有子节点的列表  
							for (int i2 = 0; i2 < list2.count(); i2++) {  //遍历该列表 	 
								QDomNode node2 = list2.at(i2);
								if (node2.isElement()) {
									QString devPropTag = node2.toElement().tagName();
									QString devPropVal = node2.toElement().text();
									if (devPropTag == "LINE_Index") {
										line_info.line_id = devPropVal.toInt();
										strcpy(line_info.mp_id, devPropVal.toAscii().data());
									}
									else if (devPropTag == "DEV_Index") {
										strcpy(line_info.terminal_code, devPropVal.toAscii().data());
										dev_idx_in_line = devPropVal.toInt();
									}
									else if (devPropTag == "CPUNO")
										line_info.cpuno = devPropVal.toInt();
									else if (devPropTag == "Name")
										apr_snprintf(line_info.name, sizeof(line_info.name), "%s", devPropVal.toAscii().data());
									//strcpy(line_info.mp_id, "not def");
									//strcpy(line_info.terminal_code, "tmpcode1");
									strcpy(line_info.voltage_level, "14");
									line_info.read_flag = 1;
								}
							}//	for(int i2=0; i2<list2.count(); i2++)

							ied = find_ied_from_dev_idx(dev_idx_in_line);
							if (ied && ied->usr_ext && line_info.cpuno) {
								char str[256];
								byte_t cpuno = line_info.cpuno;
								ied_usr = (ied_usr_t*)ied->usr_ext;
								ied_usr->LD_info[cpuno - 1] = line_info;
								ied_usr->LD_info[cpuno - 1].ied = ied;
								apr_snprintf(str, sizeof(str), "PQMonitorPQM%d", cpuno);
								ied_usr->LD_info[cpuno - 1].LD_name = apr_pstrdup(g_init_pool, str);
								ied_usr->LD_info[cpuno - 1].ht_fcd = apr_hash_make(g_init_pool);
								ied_usr->LD_info[cpuno - 1].ht_full_fcda = apr_hash_make(g_init_pool);
								ied_usr->LD_info[cpuno - 1].rptcount = 0;
								if (cpuno > ied->cpucount)
									ied->cpucount = cpuno;
							}
						} //else if ( strTag2 == "DevAccount" )
					}
				}
			}
		}
		n = n.nextSibling();  //下一个兄弟节点
	}

	if (count_cfg != count_real)
		return APR_EBADF;
	return APR_SUCCESS;
}
#endif
//////////////////////////////////////////////////////////CZY

void update_odbc(char* newServicename, char* newPort) {
	const char* filename = "/etc/odbc.ini";
	const char* searchip = "Servername="; // 要查找的行的开头
	const char* searchport = "Port="; // 要查找的行的开头
	const char* tempFilename = "/tmp/odbc.ini.XXXXXX"; // 临时文件名

	FILE* file = fopen(filename, "r");
	if (file == NULL) {
		printf("Error opening file\n");
		return;
	}

	// 创建临时文件
	char tempFilenameBuffer[256];
	strcpy(tempFilenameBuffer, tempFilename);
	int tempfd = mkstemp(tempFilenameBuffer);
	FILE* tempfile = fdopen(tempfd, "w");

	// 逐行读取文件
	char line[256];
	while (fgets(line, sizeof(line), file)) {
		if (strncmp(line, searchip, strlen(searchip)) == 0) {
			// 如果找到要修改的行，则写入新的值
			fprintf(tempfile, "Servername=%s\n", newServicename);
		}
		else if (strncmp(line, searchport, strlen(searchport)) == 0) {
			// 如果找到要修改的行，则写入新的值
			fprintf(tempfile, "Port=%s\n", newPort);
		}
		else {
			// 否则将原始行写入临时文件
			fputs(line, tempfile);
		}
	}

	// 关闭文件
	fclose(file);
	fclose(tempfile);

	// 替换原始文件
	remove(filename);
	rename(tempFilenameBuffer, filename);
}

//CZY 2023-09-06 config
void init_config() {
	QByteArray ba;
	QString MyKafkaIniFilename = QString("../etc/") + QString("mykafka.ini"); //+QString::fromAscii(subdir)
	QSettings settings(MyKafkaIniFilename, QSettings::IniFormat);

	ACCOUNT_UPDATE_INTERVAL = settings.value("AccountUpdate/Interval", 0).toInt();
	qDebug() << "Read ACCOUNT_UPDATE_INTERVAL:" << ACCOUNT_UPDATE_INTERVAL << endl;
	ba = settings.value("AccountUpdate/LastUpdateTime", "").toString().toLatin1();
	ACCOUNT_UPDATE_LAST_TIME = strdup(ba.data());
	qDebug() << "Read ACCOUNT_UPDATE_LAST_TIME:" << ACCOUNT_UPDATE_LAST_TIME << endl;

	MULIT_NODE_INTERVAL = settings.value("MultiNode/Interval", 0).toInt();
	qDebug() << "Read MULIT_NODE_INTERVAL:" << MULIT_NODE_INTERVAL << endl;

	SEND_FLAG = settings.value("Flag/SendFlag", 0).toInt();
	qDebug() << "Read SEND_FLAG:" << SEND_FLAG << endl;
	FILE_FLAG = settings.value("Flag/FileFlag", 0).toInt();
	qDebug() << "Read FILE_FLAG:" << FILE_FLAG << endl;
	FRONT_INST = settings.value("Flag/FrontInst", 0).toInt();
	qDebug() << "Read FRONT_INST:" << FRONT_INST << endl;
	ba = settings.value("Flag/FrontIP", "").toString().toLatin1();
	FRONT_IP = strdup(ba.data());
	qDebug() << "Read FRONT_IP:" << FRONT_IP << endl;
	CITY_FLAG = settings.value("Flag/CityFlag", 0).toInt();
	qDebug() << "Read CITY_FLAG:" << CITY_FLAG << endl;

//台账配置lnk20241031//////////////////////////////////////////////////////////////
	TERMINAL_STATUS = settings.value("Ledger/TerminalStatus", 0).toString().toStdString();
	std::cout << "Read TERMINAL_STATUS:" << TERMINAL_STATUS << std::endl;
	MONITOR_STATUS = settings.value("Ledger/MonitorStatus", 0).toString().toStdString();
	std::cout << "Read MONITOR_STATUS:" << MONITOR_STATUS << std::endl;
	ICD_FLAG = settings.value("Ledger/IcdFlag", 0).toString().toStdString();
	std::cout << "Read ICD_FLAG:" << ICD_FLAG << std::endl;
	IED_COUNT = settings.value("Ledger/IedCount", 0).toInt();

//////////////////////////////////////////////////添加socket开关///////////////////
	SOCKETENABLE = settings.value("Socket/SocketEnable", 0).toInt();
	SOCKET_PORT = settings.value("Socket/SocketPort", 0).toInt();
//////添加http配置//////////////////////////////////////////////////////////////////
	HTTPENABLE = settings.value("Http/HttpEnable", 0).toInt();
	ba = settings.value("Http/HttpIp", "").toString().toLatin1();
	HTTP_IP = strdup(ba.data());
	std::cout << "Read HTTP_IP:" << HTTP_IP << std::endl;
	HTTP_PORT = settings.value("Http/HttpPort", 0).toInt();
	std::cout << "Read HTTP_PORT:" << HTTP_PORT << std::endl;

	ba = settings.value("Http/WebDevice", "").toString().toLatin1();
	WEB_DEVICE = strdup(ba.data());
	std::cout << "Read WEB_DEVICE:" << WEB_DEVICE << std::endl;
	ba = settings.value("Http/WebIcd", "").toString().toLatin1();
	WEB_ICD = strdup(ba.data());
	std::cout << "Read WEB_ICD:" << WEB_ICD << std::endl;
	ba = settings.value("Http/WebIntegrity", "").toString().toLatin1();
	WEB_INTEGRITY = strdup(ba.data());
	std::cout << "Read WEB_INTEGRITY:" << WEB_INTEGRITY << std::endl;
	ba = settings.value("Http/WebComflag", "").toString().toLatin1();
	WEB_COMFLAG = strdup(ba.data());
	std::cout << "Read WEB_COMFLAG:" << WEB_COMFLAG << std::endl;
	ba = settings.value("Http/WebEvent", "").toString().toLatin1();
	WEB_EVENT = strdup(ba.data());
	std::cout << "Read WEB_EVENT:" << WEB_EVENT << std::endl;
	ba = settings.value("Http/WebFileupload", "").toString().toLatin1();
	WEB_FILEUPLOAD = strdup(ba.data());
	std::cout << "Read WEB_FILEUPLOAD:" << WEB_FILEUPLOAD << std::endl;
	ba = settings.value("Http/WebFiledownload", "").toString().toLatin1();
	WEB_FILEDOWNLOAD = strdup(ba.data());
	std::cout << "Read WEB_FILEDOWNLOAD:" << WEB_FILEDOWNLOAD << std::endl;

///////////////////////////////////////////////////////////////////////////////////////////////////////
	recall_len = settings.value("Recall/recall_lenth", 0).toInt();
	qDebug() << "Read recall_lenth:" << recall_len << endl;
	recall_sta = settings.value("Recall/recall_start", 0).toInt();
	qDebug() << "Read recall_start:" << recall_sta << endl;
	recall_daily = settings.value("Recall/recall_dailytime", 0).toInt();
	qDebug() << "Read recall_dailytime:" << recall_daily << endl;

	COMMUNICATION_LOG_STATUS_TIME = settings.value("CommunicationLog/StatusRecordDuration", 0).toInt();
	qDebug() << "Read COMMUNICATION_LOG_STATUS_TIME:" << COMMUNICATION_LOG_STATUS_TIME << endl;
	COMMUNICATION_LOG_ABNORMAL_TIME = settings.value("CommunicationLog/AbnormalRecordDuration", 0).toInt();
	qDebug() << "Read COMMUNICATION_LOG_ABNORMAL_TIME:" << COMMUNICATION_LOG_ABNORMAL_TIME << endl;


	ba = settings.value("Postgres/Database", "").toString().toLatin1();
	POSTGRES_DATABASE = strdup(ba.data());
	ba = settings.value("Postgres/Username", "").toString().toLatin1();
	POSTGRES_USERNAME = strdup(ba.data());

	/*QString  postgres_password = settings.value("Postgres/Password", "").toString();
	ba = QByteArray::fromBase64(postgres_password.toAscii());*/
	ba = settings.value("Postgres/Password", "").toString().toLatin1();
	POSTGRES_PASSWORD = strdup(ba.data());

	ba = settings.value("Postgres/Schema", "").toString().toLatin1();
	POSTGRES_SCHEMA = strdup(ba.data());
	ba = settings.value("Postgres/Dnsname", "").toString().toLatin1();
	POSTGRES_DNSNAME = strdup(ba.data());
	ba = settings.value("Postgres/TablePrefix", "").toString().toLatin1();
	POSTGRES_TABLEPREFIX = strdup(ba.data());


	qDebug() << "Read POSTGRES_DATABASE:" << POSTGRES_DATABASE << endl;
	qDebug() << "Read POSTGRES_USERNAME:" << POSTGRES_USERNAME << endl;
	qDebug() << "Read POSTGRES_PASSWORD:" << POSTGRES_PASSWORD << endl;
	qDebug() << "Read POSTGRES_SCHEMA:" << POSTGRES_SCHEMA << endl;
	qDebug() << "Read POSTGRES_DNSNAME:" << POSTGRES_DNSNAME << endl;
	qDebug() << "Read POSTGRES_TABLEPREFIX:" << POSTGRES_TABLEPREFIX << endl;


	ba = settings.value("Oss/OssEndpoint", "").toString().toLatin1();
	OSS_ENDPOINT = strdup(ba.data());
	ba = settings.value("Oss/AccessKeyID", "").toString().toLatin1();
	ACCESS_KEY_ID = strdup(ba.data());
	ba = settings.value("Oss/AccessKeySecret", "").toString().toLatin1();
	ACCESS_KEY_SECRET = strdup(ba.data());
	ba = settings.value("Oss/BucketName", "").toString().toLatin1();
	BUCKET_NAME = strdup(ba.data());

	qDebug() << "Read OSS_ENDPOINT:" << OSS_ENDPOINT << endl;
	qDebug() << "Read ACCESS_KEY_ID:" << ACCESS_KEY_ID << endl;
	qDebug() << "Read ACCESS_KEY_SECRET:" << ACCESS_KEY_SECRET << endl;
	qDebug() << "Read BUCKET_NAME:" << BUCKET_NAME << endl;

	ba = settings.value("Kafka/brokerlist", "").toString().toLatin1();
	BROKER_LIST = strdup(ba.data());
	ba = settings.value("Kafka/HisTopic", "").toString().toLatin1();
	TOPIC_STAT = strdup(ba.data());
	ba = settings.value("Kafka/PSTTopic", "").toString().toLatin1();
	TOPIC_PST = strdup(ba.data());
	ba = settings.value("Kafka/PLTTopic", "").toString().toLatin1();
	TOPIC_PLT = strdup(ba.data());

	ba = settings.value("Kafka/EventTopic", "").toString().toLatin1();
	TOPIC_EVENT = strdup(ba.data());

	ba = settings.value("Kafka/AlmTopic", "").toString().toLatin1();
	TOPIC_ALARM = strdup(ba.data());
	ba = settings.value("Kafka/SngTopic", "").toString().toLatin1();
	TOPIC_SNG = strdup(ba.data());

	ba = settings.value("Kafka/RTDataTopic", "").toString().toLatin1();
	TOPIC_RTDATA = strdup(ba.data());

	qDebug() << "Read BROKER_LIST:" << BROKER_LIST << endl;
	qDebug() << "Read TOPIC_STAT:" << TOPIC_STAT << endl;
	qDebug() << "Read TOPIC_PST:" << TOPIC_PST << endl;
	qDebug() << "Read TOPIC_PLT:" << TOPIC_PLT << endl;
	qDebug() << "Read TOPIC_EVENT:" << TOPIC_EVENT << endl;
	qDebug() << "Read TOPIC_ALARM:" << TOPIC_ALARM << endl;
	qDebug() << "Read TOPIC_SNG:" << TOPIC_SNG << endl;
	qDebug() << "Read TOPIC_RTDATA:" << TOPIC_RTDATA << endl;


	ba = settings.value("Kafka/Protocol", "").toString().toLatin1();
	PROTOCOL = strdup(ba.data());
	ba = settings.value("Kafka/Mechanisms", "").toString().toLatin1();
	MECHANISMS = strdup(ba.data());
	ba = settings.value("Kafka/KeytabFile", "").toString().toLatin1();
	KEYTAB_FILE = strdup(ba.data());
	ba = settings.value("Kafka/ServiceName", "").toString().toLatin1();
	SERVICE_NAME = strdup(ba.data());
	ba = settings.value("Kafka/Principal", "").toString().toLatin1();
	PRINCIPAL = strdup(ba.data());
	ba = settings.value("Kafka/DomainName", "").toString().toLatin1();
	DOMAIN_NAME = strdup(ba.data());

	qDebug() << "Read PROTOCOL:" << PROTOCOL << endl;
	qDebug() << "Read MECHANISMS:" << MECHANISMS << endl;
	qDebug() << "Read KEYTAB_FILE:" << KEYTAB_FILE << endl;
	qDebug() << "Read SERVICE_NAME:" << SERVICE_NAME << endl;
	qDebug() << "Read PRINCIPAL:" << PRINCIPAL << endl;
	qDebug() << "Read DOMAIN_NAME:" << DOMAIN_NAME << endl;

	ba = settings.value("Web/ClientId", "").toString().toLatin1();
	CLIENT_ID = strdup(ba.data());
	ba = settings.value("Web/ClientSecret", "").toString().toLatin1();
	CLIENT_SECRET = strdup(ba.data());
	ba = settings.value("Web/TokenUrl", "").toString().toLatin1();
	TOKEN_URL = strdup(ba.data());
	ba = settings.value("Web/DeviceUrl", "").toString().toLatin1();
	DEVICE_URL = strdup(ba.data());
	ba = settings.value("Web/GrantType", "").toString().toLatin1();
	GRANT_TYPE = strdup(ba.data());

	qDebug() << "Read CLIENT_ID:" << CLIENT_ID << endl;
	qDebug() << "Read CLIENT_SECRET:" << CLIENT_SECRET << endl;
	qDebug() << "Read TOKEN_URL:" << TOKEN_URL << endl;
	qDebug() << "Read DEVICE_URL:" << DEVICE_URL << endl;
	qDebug() << "Read GRANT_TYPE:" << GRANT_TYPE << endl;

	ba = settings.value("Uds/UdsUploadUrl", "").toString().toLatin1();
	UDS_UPLOAD_URL = strdup(ba.data());
	ba = settings.value("Uds/UdsDownloadUrl", "").toString().toLatin1();
	UDS_DOWNLOAD_URL = strdup(ba.data());

	qDebug() << "Read UDS_UPLOAD_URL:" << UDS_UPLOAD_URL << endl;
	qDebug() << "Read UDS_DOWNLOAD_URL:" << UDS_DOWNLOAD_URL << endl;

/*添加rocketmq的解析10-9 */////////////////////////////////////////////////////////////////
//生产者
	ba = settings.value("RocketMq/producer", "").toString().toLatin1();
	G_ROCKETMQ_PRODUCER = strdup(ba.data());
	ba = settings.value("RocketMq/Ipport", "").toString().toLatin1();
	G_ROCKETMQ_IPPORT = strdup(ba.data());
	ba = settings.value("RocketMq/Topic", "").toString().toLatin1();
	G_ROCKETMQ_TOPIC = strdup(ba.data());
	ba = settings.value("RocketMq/Tag", "").toString().toLatin1();
	G_ROCKETMQ_TAG = strdup(ba.data());
	ba = settings.value("RocketMq/Key", "").toString().toLatin1();
	G_ROCKETMQ_KEY = strdup(ba.data());
	QUEUENUM = settings.value("RocketMq/Queuenum", 0).toInt();
//消费者
	ba = settings.value("RocketMq/consumer", "").toString().toLatin1();
	G_ROCKETMQ_CONSUMER = strdup(ba.data());
	ba = settings.value("RocketMq/ConsumerIpport", "").toString().toLatin1();
	G_MQCONSUMER_IPPORT = strdup(ba.data());
	ba = settings.value("RocketMq/ConsumerTopicRT", "").toString().toLatin1();
	G_MQCONSUMER_TOPIC_RT = strdup(ba.data());
	ba = settings.value("RocketMq/ConsumerTagRT", "").toString().toLatin1();
	G_MQCONSUMER_TAG_RT = strdup(ba.data());
	ba = settings.value("RocketMq/ConsumerKeyRT", "").toString().toLatin1();
	G_MQCONSUMER_KEY_RT = strdup(ba.data());
	ba = settings.value("RocketMq/ConsumerAccessKey", "").toString().toLatin1();
	G_MQCONSUMER_ACCESSKEY = strdup(ba.data());
	ba = settings.value("RocketMq/ConsumerSecretKey", "").toString().toLatin1();
	G_MQCONSUMER_SECRETKEY = strdup(ba.data());
	ba = settings.value("RocketMq/ConsumerChannel", "").toString().toLatin1();
	G_MQCONSUMER_CHANNEL = strdup(ba.data());
	ba = settings.value("RocketMq/ConsumerTopicUD", "").toString().toLatin1();
	G_MQCONSUMER_TOPIC_UD = strdup(ba.data());
	ba = settings.value("RocketMq/ConsumerTagUD", "").toString().toLatin1();
	G_MQCONSUMER_TAG_UD = strdup(ba.data());
	ba = settings.value("RocketMq/ConsumerKeyUD", "").toString().toLatin1();
	G_MQCONSUMER_KEY_UD = strdup(ba.data());
	ba = settings.value("RocketMq/ConsumerTopicRC", "").toString().toLatin1();
	G_MQCONSUMER_TOPIC_RC = strdup(ba.data());
	ba = settings.value("RocketMq/ConsumerTagRC", "").toString().toLatin1();
	G_MQCONSUMER_TAG_RC = strdup(ba.data());
	ba = settings.value("RocketMq/ConsumerKeyRC", "").toString().toLatin1();
	G_MQCONSUMER_KEY_RC = strdup(ba.data());
	ba = settings.value("RocketMq/ConsumerTopicSET", "").toString().toLatin1();
	G_MQCONSUMER_TOPIC_SET = strdup(ba.data());
	ba = settings.value("RocketMq/ConsumerTagSET", "").toString().toLatin1();
	G_MQCONSUMER_TAG_SET = strdup(ba.data());
	ba = settings.value("RocketMq/ConsumerKeySET", "").toString().toLatin1();
	G_MQCONSUMER_KEY_SET = strdup(ba.data());
//MQ测试
	G_TEST_FLAG = settings.value("RocketMq/Testflag", 0).toInt();
	G_TEST_NUM = settings.value("RocketMq/Testnum", 0).toInt();
//测试shell
	TEST_PORT = settings.value("RocketMq/TestPort", 0).toInt();
	
//生产者相关打印
	std::cout << "Read G_ROCKETMQ_PRODUCER:" << G_ROCKETMQ_PRODUCER << std::endl;
	std::cout << "Read G_ROCKETMQ_IPPORT:" << G_ROCKETMQ_IPPORT << std::endl;
	std::cout << "Read G_ROCKETMQ_TOPIC:" << G_ROCKETMQ_TOPIC << std::endl;
	std::cout << "Read G_ROCKETMQ_TAG:" << G_ROCKETMQ_TAG << std::endl;
	std::cout << "Read G_ROCKETMQ_KEY:" << G_ROCKETMQ_KEY << std::endl;
	std::cout << "Read QUEUENUM:" << QUEUENUM << std::endl;
//消费者相关打印
	std::cout << "Read G_ROCKETMQ_CONSUMER:" << G_ROCKETMQ_CONSUMER << std::endl;
	std::cout << "Read G_MQCONSUMER_IPPORT:" << G_MQCONSUMER_IPPORT << std::endl;
	std::cout << "Read G_MQCONSUMER_TOPIC_RT:" << G_MQCONSUMER_TOPIC_RT << std::endl;
	std::cout << "Read G_MQCONSUMER_TAG_RT:" << G_MQCONSUMER_TAG_RT << std::endl;
	std::cout << "Read G_MQCONSUMER_KEY_RT:" << G_MQCONSUMER_KEY_RT << std::endl;
	std::cout << "Read G_MQCONSUMER_ACCESSKEY:" << G_MQCONSUMER_ACCESSKEY << std::endl;
	std::cout << "Read G_MQCONSUMER_SECRETKEY:" << G_MQCONSUMER_SECRETKEY << std::endl;
	std::cout << "Read G_MQCONSUMER_CHANNEL:" << G_MQCONSUMER_CHANNEL << std::endl;
	std::cout << "Read G_MQCONSUMER_TOPIC_UD:" << G_MQCONSUMER_TOPIC_UD << std::endl;
	std::cout << "Read G_MQCONSUMER_TAG_UD:" << G_MQCONSUMER_TAG_UD << std::endl;
	std::cout << "Read G_MQCONSUMER_KEY_UD:" << G_MQCONSUMER_KEY_UD << std::endl;
	std::cout << "Read G_MQCONSUMER_TOPIC_RC:" << G_MQCONSUMER_TOPIC_RC << std::endl;
	std::cout << "Read G_MQCONSUMER_TAG_RC:" << G_MQCONSUMER_TAG_RC << std::endl;
	std::cout << "Read G_MQCONSUMER_KEY_RC:" << G_MQCONSUMER_KEY_RC << std::endl;
	std::cout << "Read G_MQCONSUMER_TOPIC_SET:" << G_MQCONSUMER_TOPIC_SET << std::endl;
	std::cout << "Read G_MQCONSUMER_TAG_SET:" << G_MQCONSUMER_TAG_SET << std::endl;
	std::cout << "Read G_MQCONSUMER_KEY_SET:" << G_MQCONSUMER_KEY_SET << std::endl;
//Mq测试相关打印
	std::cout << "Read G_TEST_FLAG:" << G_TEST_FLAG << std::endl;
	std::cout << "Read G_TEST_NUM:" << G_TEST_NUM << std::endl;

/////////////////////////////////////////////////////////////////////////////////////////
	/*Nacos_GetParam(POSTGRES_USERNAME, POSTGRES_PASSWORD, CLIENT_ID, CLIENT_SECRET);
	qDebug() << "Read CLIENT_ID:" << CLIENT_ID << endl;
	qDebug() << "Read CLIENT_SECRET:" << CLIENT_SECRET << endl;
	qDebug() << "Read POSTGRES_USERNAME:" << POSTGRES_USERNAME << endl;
	qDebug() << "Read POSTGRES_PASSWORD:" << POSTGRES_PASSWORD << endl;*/

/*lnk10-12 暂不使用Nacos*/
/*
	char* database_ip = NULL;
	char* database_port = NULL;
	sleep(3);
	Read_Nacos_Param_Postgres(&database_ip, &database_port, &POSTGRES_DATABASE, &POSTGRES_USERNAME, &POSTGRES_PASSWORD, &POSTGRES_SCHEMA, &POSTGRES_DNSNAME, &POSTGRES_TABLEPREFIX);
	qDebug() << "Read database_ip:" << database_ip << endl;
	qDebug() << "Read database_port:" << database_port << endl;
	update_odbc(database_ip, database_port);
	qDebug() << "Read POSTGRES_DATABASE:" << POSTGRES_DATABASE << endl;
	qDebug() << "Read POSTGRES_USERNAME:" << POSTGRES_USERNAME << endl;
	qDebug() << "Read POSTGRES_PASSWORD:" << POSTGRES_PASSWORD << endl;
	qDebug() << "Read POSTGRES_SCHEMA:" << POSTGRES_SCHEMA << endl;
	qDebug() << "Read POSTGRES_DNSNAME:" << POSTGRES_DNSNAME << endl;
	qDebug() << "Read POSTGRES_TABLEPREFIX:" << POSTGRES_TABLEPREFIX << endl;
	sleep(3);
	Read_Nacos_Param_Kafka(&BROKER_LIST, &TOPIC_STAT, &TOPIC_PST, &TOPIC_PLT, &TOPIC_EVENT, &TOPIC_ALARM, &TOPIC_SNG, &PROTOCOL, &MECHANISMS, &SERVICE_NAME, &PRINCIPAL, &DOMAIN_NAME);
	qDebug() << "Read BROKER_LIST:" << BROKER_LIST << endl;
	qDebug() << "Read TOPIC_STAT:" << TOPIC_STAT << endl;
	qDebug() << "Read TOPIC_PLT:" << TOPIC_PLT << endl;
	qDebug() << "Read TOPIC_EVENT:" << TOPIC_EVENT << endl;
	qDebug() << "Read TOPIC_ALARM:" << TOPIC_ALARM << endl;
	qDebug() << "Read TOPIC_SNG:" << TOPIC_SNG << endl;
	qDebug() << "Read PROTOCOL:" << PROTOCOL << endl;
	qDebug() << "Read PRINCIPAL:" << PRINCIPAL << endl;
	sleep(3);
	Read_Nacos_Param_Web(&CLIENT_ID, &CLIENT_SECRET, &TOKEN_URL, &DEVICE_URL, &GRANT_TYPE);
	qDebug() << "Read CLIENT_ID:" << CLIENT_ID << endl;
	qDebug() << "Read CLIENT_SECRET:" << CLIENT_SECRET << endl;
	qDebug() << "Read TOKEN_URL:" << TOKEN_URL << endl;
	qDebug() << "Read DEVICE_URL:" << DEVICE_URL << endl;
	qDebug() << "Read GRANT_TYPE:" << GRANT_TYPE << endl;
	sleep(3);
	Read_Nacos_Param_Flag(&FILE_FLAG, &SEND_FLAG, &FRONT_INST, &FRONT_IP);
	sleep(3);
	Read_Nacos_Param_Recall(&recall_len, &recall_sta, &recall_daily);
	qDebug() << "Read SEND_FLAG:" << SEND_FLAG << endl;
	qDebug() << "Read FILE_FLAG:" << FILE_FLAG << endl;
	qDebug() << "Read FRONT_INST:" << FRONT_INST << endl;
	qDebug() << "Read FRONT_IP:" << FRONT_IP << endl;

	qDebug() << "Read recall_lenth:" << recall_len << endl;
	qDebug() << "Read recall_start:" << recall_sta << endl;
	qDebug() << "Read recall_dailytime:" << recall_daily << endl;
	sleep(3);
	Read_Nacos_Param_Uds(&UDS_UPLOAD_URL, &UDS_DOWNLOAD_URL, &UDS_DELETE_URL);
	qDebug() << "Read UDS_UPLOAD_URL:" << UDS_UPLOAD_URL << endl;
	qDebug() << "Read UDS_DOWNLOAD_URL:" << UDS_DOWNLOAD_URL << endl;
	qDebug() << "Read UDS_DELETE_URL:" << UDS_DELETE_URL << endl;
*/
//2024-10-25lnk 不需要多前置，前置ip从配置文件获取，不连接数据库
/*
	if (g_front_seg_index != 0 && g_front_seg_num != 0) {
		FRONT_INST = g_front_seg_index;
		if (FRONT_IP != nullptr) {
			free(FRONT_IP); // 如果是通过malloc分配的 
		}
		FRONT_IP = (char*)malloc(64);  // 分配内存
		// 使用sprintf将int值为字符串  
		sprintf(FRONT_IP, "%d", g_front_seg_index);
	}
	qDebug() << "Read FRONT_INST:" << FRONT_INST << endl;
	qDebug() << "Read FRONT_IP:" << FRONT_IP << endl;

	g_strOTLConnect = POSTGRES_USERNAME;
	g_strOTLConnect.append("/");
	g_strOTLConnect.append(POSTGRES_PASSWORD);
	g_strOTLConnect.append("@");
	g_strOTLConnect.append(POSTGRES_DNSNAME);

	cout << "Read g_strOTLConnect:" << g_strOTLConnect << endl;*/
//20241212lnk添加多前置
	if (g_front_seg_index != 0 && g_front_seg_num != 0) {
		MULTIPLE_NODE_FLAG = 1;
		std::cout << "当前功能是多进程:" << g_front_seg_index << std::endl;
	}
	else{
		MULTIPLE_NODE_FLAG = 0;
		std::cout << "当前功能是单进程:" << std::endl;
	}
//20250109lnk添加进程测试打印端口
	if (g_node_id == STAT_DATA_BASE_NODE_ID)//统计采集
		TEST_PORT = TEST_PORT + STAT_DATA_BASE_NODE_ID +  g_front_seg_index;
	else if (g_node_id == RECALL_HIS_DATA_BASE_NODE_ID) {//补召
		TEST_PORT = TEST_PORT + RECALL_HIS_DATA_BASE_NODE_ID +  g_front_seg_index;
	}
	else if (g_node_id == THREE_SECS_DATA_BASE_NODE_ID) {//3秒采集
		TEST_PORT = TEST_PORT + THREE_SECS_DATA_BASE_NODE_ID +  g_front_seg_index;
	}
	else if (g_node_id == SOE_COMTRADE_BASE_NODE_ID) {//暂态录波
		TEST_PORT = TEST_PORT + SOE_COMTRADE_BASE_NODE_ID +  g_front_seg_index;
	}	

}

// CZY 测试 ping IP
// 执行命令并获取输出结果
std::string executeCommand(const std::string& command) {
	std::string result = "";
	FILE* pipe = popen(command.c_str(), "r");
	if (!pipe) {
		std::cerr << "Error executing command." << std::endl;
		return result;
	}

	char buffer[128];
	while (!feof(pipe)) {
		if (fgets(buffer, 128, pipe) != NULL)
			result += buffer;
	}

	pclose(pipe);
	return result;
}

bool telnet_port_socket(const char* ip, int port) {
	struct sockaddr_in server_addr;
	memset(&server_addr, 0, sizeof(server_addr));
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(port);
	inet_pton(AF_INET, ip, &server_addr.sin_addr);

	int sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if (sockfd < 0) {
		perror("socket");
		return false;
	}

	// 设置连接超时时间为5秒
	struct timeval timeout;
	timeout.tv_sec = 5;
	timeout.tv_usec = 0;
	if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)) < 0) {
		perror("setsockopt");
		close(sockfd);
		return false;
	}
	if (setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof(timeout)) < 0) {
		perror("setsockopt");
		close(sockfd);
		return false;
	}

	if (connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
		if (errno == EINPROGRESS) {
			fd_set fds;
			FD_ZERO(&fds);
			FD_SET(sockfd, &fds);

			int ret = select(sockfd + 1, NULL, &fds, NULL, &timeout);
			if (ret == -1) {
				perror("select");
				close(sockfd);
				return false;
			}
			else if (ret == 0) {
				// 连接超时
				close(sockfd);
				return false;
			}
			else {
				int error;
				socklen_t len = sizeof(error);
				getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len);
				if (error == 0) {
					// 连接成功
					close(sockfd);
					return true;
				}
				else {
					// 连接失败
					close(sockfd);
					return false;
				}
			}
		}
		else {
			// 连接失败
			close(sockfd);
			return false;
		}
	}

	// 连接成功
	close(sockfd);
	return true;
}

// ping IP
bool ping_ip(const std::string& ip) {
	std::string command = "ping -c 1 -w 2.5 " + ip;
	std::string result = executeCommand(command);

	// 判断输出结果是否包含 "1 packets transmitted, 1 received" 字符串
	if (result.find("1 packets transmitted, 1 received") != std::string::npos) {
		return true;
	}
	else {
		return false;
	}
}

int init_ping_telnet(int& ip_count, int& telnet_count) {
	cout << "start test ping telnet" << endl;
	ied_t* ied = NULL;
	int			iedno;
	LD_info_t* LD_info = NULL;
	int count = 0;
	for (iedno = 0; iedno < g_node->n_clients; iedno++) {
		ied = g_node->clients[iedno];
		if (ied) {
			//ied->channel[0].addr_str[LONGNAME - 1] = 0;//DEV_IP
			if (g_onlyIP[0] != 0 && (strcmp(g_onlyIP, ied->channel[0].addr_str) != 0)) {
				continue;
			}
			ied->channel[0].addr_str;//DEV_IP
			ied->channel[0].port;//DEV_PortID
			bool pingResult = ping_ip(ied->channel[0].addr_str);
			//bool pingResult = test_ping(ied->channel[0].addr_str);

			//bool telnetResult = telnetIPPort(ied->channel[0].addr_str, ied->channel[0].port);
			bool telnetResult = telnet_port_socket(ied->channel[0].addr_str, ied->channel[0].port);
			std::string strlog = "";
			strlog.append("Ping to IP ");
			strlog.append(ied->channel[0].addr_str);

			if (pingResult) {
				ip_count++;
				std::cout << "Ping to IP " << ied->channel[0].addr_str << " is successful." << std::endl;
				strlog.append(" is successful.");
			}
			else {
				std::cout << "Ping to IP " << ied->channel[0].addr_str << " is unsuccessful." << std::endl;
				strlog.append(" is unsuccessful.");

			}
			add_comm_log(const_cast<char*>(strlog.c_str()));
			strlog = "";
			std::string str = QString::number(ied->channel[0].port).toStdString();
			strlog.append("Telnet port ");
			strlog.append(str);
			if (telnetResult) {
				telnet_count++;
				std::cout << "Telnet port " << ied->channel[0].port << " is open on IP " << ied->channel[0].addr_str << std::endl;
				strlog.append(" is open on IP ");
			}
			else {
				std::cout << "Telnet port " << ied->channel[0].port << " is closed on IP " << ied->channel[0].addr_str << std::endl;
				strlog.append(" is closed on IP ");

			}
			strlog.append(ied->channel[0].addr_str);
			add_comm_log(const_cast<char*>(strlog.c_str()));

			cout << "iedno:" << iedno << " ip_count:" << ip_count << " telnet_count:" << telnet_count << endl;
			QString MyKafkaIniFilename = QString("../etc/") + QString("testping.ini"); //+QString::fromAscii(subdir)
			QSettings settings(MyKafkaIniFilename, QSettings::IniFormat);
			settings.setValue("test/IpCount", ip_count);
			settings.setValue("test/TelnetCount", telnet_count);
			settings.setValue("test/IedCount", iedno);
		}
	}
	cout << "end test ping telnet" << endl;

	return 1;
}

//CZY 2023-08-30 read device account from web api
long long charToLongLong(const char* time_str) {
	string str_time = "2022-01-01 10:00:00";
	struct tm tm_time = {};
	strptime(str_time.c_str(), "%Y-%m-%d %H:%M:%S", &tm_time);
	time_t time_stamp = mktime(&tm_time);
	//cout << "时间戳为：" << time_stamp << endl;
	return time_stamp;
}

//CZY 2023-08-30 chat* null or emptry
bool isCharPtrEmpty(const char* str) {
	return str == nullptr || str[0] == '\0' || str == "";
}

// CZY 2024-07-24 函数：检查字符串是否全为数字  
int isAllDigits(const char* str) {
	while (*str) {
		if (!isdigit((unsigned char)*str)) {
			return 0; // 发现非数字字符  
		}
		str++;
	}
	return 1; // 所有字符都是数字  
}

// CZY 2024-07-24函数：将字符串转换为int（如果可能）  
int stringToInt(const char* str, int* result) {
	if (isAllDigits(str)) {
		*result = atoi(str); // 使用atoi进行转换，注意atoi不会检查溢出  
		return 1; // 转换成功  
	}
	return 0; // 转换失败  
}

//lnk20241206不使用的代码
#if 0
void GetWebApiJson(int perpage, int page, int flag);
//CZY 2023-10-12 
int read_terminal_ext_pg(QMap<QString, terminal_ext*>* terminal_ext_map) {
	cout << "start read terminal_ext" << endl;
	terminal_ext* ext;
	//读取数据
	try {
		OTLConnect();
		//int rtState = OTLState();
		std::string str2 = POSTGRES_SCHEMA;//schame analy
		std::string str1 = "select \"terminal_code\",\"terminal_identify_code\",\"terminal_key\" from \"";
		str1.append(str2);
		str1.append("\".\"");
		str1.append(POSTGRES_TABLEPREFIX);
		str1.append("pq_terminal_ext");
		str1.append("\";");
		//cout << "pg sql1 is:" << str1 << endl;
		//int rtState = OTLState();
		otl_stream i(1, // buffer size
			str1.c_str(),
			//SELECT statement
			db //connect object
		);
		//create select stream


		while (!i.eof()) { //while not end-of-data
			char terminal_code[100];
			char terminal_identify_code[100];
			char terminal_key[100];
			i >> terminal_code >> terminal_identify_code >> terminal_key;
			//qDebug() << "terminal_ext1:" << terminal_code << "," <<terminal_identify_code << "," <<terminal_key << endl;
			if (!terminal_ext_map->contains(terminal_code)) {
				ext = new terminal_ext();
				terminal_ext_map->insert(terminal_code, ext);
				apr_snprintf(ext->terminal_identify_code, sizeof(ext->terminal_identify_code), "%s", terminal_identify_code);//terminal_code
				apr_snprintf(ext->terminal_key, sizeof(ext->terminal_key), "%s", terminal_key);//terminal_code
				//qDebug() << "terminal_ext2:" << terminal_code << "," << ext->terminal_identify_code << "," << ext->terminal_key << endl;
			}
			else
			{
				qDebug() << terminal_code << endl;
			}
		}
		OTLDisconnect();
		cout << "end read terminal_ext" << endl;

		return 1;
	}
	catch (otl_exception& e)
	{
		printf("\ndev PostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg);
		return e.code;
	}

}
static QString strDevCJson;
static QString strToken;
//CZY 2023-09-10 web device
//flag 
int parse_device_cfg_json()
{
	qDebug() << "parse_device_cfg_json" << endl;
	if (FRONT_INST == 0 || FRONT_IP[0] == '\0') {
		MULTIPLE_NODE_FLAG = 0;
		cout << "set MULTIPLE_NODE_FLAG:0,because do not have FRONT_INST or FRONT_IP" << endl;

	}
	char front_type[2];
	int mp_num;

	if (MULTIPLE_NODE_FLAG) {
		//std::string str2 = POSTGRES_SCHEMA;//schame analy
		std::string str1 = "select count(*) from \"";
		str1.append(POSTGRES_SCHEMA);
		str1.append("\".\"");
		str1.append(POSTGRES_TABLEPREFIX);
		str1.append("meas_pq_front_list_tr");
		str1.append("\" where \"front_ip\" = '");
		str1.append(FRONT_IP);
		str1.append("' and \"front_inst\" = ");
		std::string str3 = QString::number(FRONT_INST).toStdString();
		str1.append(str3);
		str1.append(";");
		try {
			OTLConnect();
			otl_stream i1(1, // buffer size
				str1.c_str(),
				//SELECT statement
				db //connect object
			);
			//create select stream


			int front_count;
			while (!i1.eof()) { //while not end-of-data
				i1 >> front_count;
				//cout << "count=" << f2 << endl;
			}
			cout << "count=" << front_count << endl;
			OTLDisconnect();
		}
		catch (otl_exception& e)
		{
			printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg);
			return e.code;
		}
		QString selectFrontSql;
		selectFrontSql.append(QString("select \"front_type\",\"mp_num\" from \"%1\".\"%2meas_pq_front_list_tr\" ").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX));
		selectFrontSql.append(QString("where \"front_ip\" = '0.0.0.0' and \"front_inst\"=0"));
		cout << selectFrontSql.toStdString().c_str() << endl;
		try {
			OTLConnect();
			otl_stream i2(1, // buffer size
				selectFrontSql.toStdString().c_str(),
				//SELECT statement
				db //connect object
			);
			//create select stream


			while (!i2.eof()) { //while not end-of-data
				i2 >> front_type >> mp_num;
				break;
				//cout << "count=" << f2 << endl;
			}
			OTLDisconnect();
		}
		catch (otl_exception& e)
		{
			printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg);
			return e.code;
		}

		QString addFrontSql;
		addFrontSql.append(QString("insert into \"%1\".\"%2meas_pq_front_list_tr\"(\"front_ip\",\"front_port\",\"front_inst\",\"front_type\",\"front_status\",\"front_version\",\"mp_num\") ").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX));
		addFrontSql.append(QString("values('%1',10000,%2,'%3','01','%4',200) ").arg(FRONT_IP).arg(FRONT_INST).arg(front_type).arg(PROGRAM_VERSION));
		addFrontSql.append(QString("on conflict(\"front_ip\",\"front_inst\") do update set "));
		addFrontSql.append(QString("\"front_type\"= '%1',\"front_version\"='%2'").arg(front_type).arg(PROGRAM_VERSION));
		cout << addFrontSql.toStdString().c_str() << endl;

		OTLConnect();
		int rt = write_to_db(addFrontSql.toStdString().c_str());
		OTLDisconnect();

	}
	cout << "mp_num:" << mp_num << " FRONT_INST:" << FRONT_INST << endl;

	ied_t* ied;
	ied_usr_t* ied_usr;
	chnl_usr_t* chnl_usr;
	int count_cfg = 0;
	int count_real = 0;
	//多个设备循环,中台读取台账终端数量
	int array_size = 0;
	//读取数据
	//string* json_buf;
	cJSON* json = NULL;
	cJSON* json_value = NULL;

	cJSON* json_records = NULL;
	cJSON* json_node = NULL;

	int dev_num = 0;
	QMap<QString, terminal_ext*> terminal_ext_map;
	read_terminal_ext_pg(&terminal_ext_map);
	try {
		int effective_flag = 1;
		//读取台账失败次数 5次
		int dev_read_count = 0;
		int total;
		while (effective_flag == 1 && dev_read_count <= 5) {
			effective_flag = 0;
			dev_read_count++;

			GetWebApiJson(1, 1, CITY_FLAG);
			if (strDevCJson == "") {
				cout << "json select total error" << endl;
				return APR_EBADF;
			}
			//char json_buf[] = "{\"errors\":\"成功\",\"message\":\"成功\",\"result\":{\"0751002\":{\"current\":1,\"orders\":[],\"pages\":391,\"records\":[{\"assets\":[],\"distribution\":1,\"id\":\"ff8080817efe6c21017f1064ab7c0c7e\",\"modelId\":\"0751002Z\",\"resource\":{\"deviceKind\":\"0751002\",\"maintOrg\":\"02DC9D994F2879E4E053661EDF0AFC25\",\"signalInputForm\":\"02\",\"source#Name\":\"设备增加-基本建设\",\"source\":\"01\",\"currsigInputChanqutity\":\"1\",\"astOrg#Name\":\"国网湖南省电力公司\",\"astOrg\":\"02DC9D994CE579E4E053661EDF0AFC25\",\"cabinetType\":\"05\",\"ctime\":\"2022-02-19 00:00:00\",\"model\":\"PQS-883\",\"station#Name\":\"110kV宝塔变电站\",\"equipmentOwner\":\"E94A0732B2FB5AA1E0430901E80A21E9\",\"manufactureNum\":\"202596\",\"ipAddress\":\"10.232.245.101\",\"equipCode\":\"16M00000128569231\",\"subnetMask\":\"255.255.255.224\",\"astId\":\"ff8080817efe6c21017f1064ab7c0c7e\",\"macAddress\":\"00：B7：8D：00：DC：23\",\"astNum\":\"200102118916\",\"signalInputForm#Name\":\"数字信号\",\"maintOrg#Name\":\"张家界供电公司检修公司\",\"name\":\"110kV 珍宝线504电能质量监测装置\",\"deviceLevel\":\"01\",\"projectNum\":\"GGXM20220219BT\",\"projectName\":\"电能质量监测装置\",\"operateDate\":\"2021-11-19 00:00:00\",\"deployState\":\"20\",\"hardDiskCapacity\":\"64\",\"city\":\"02DC9D994EED79E4E053661EDF0AFC25\",\"timeSynchronization\":\"02\",\"astNature\":\"03\",\"manufacturer\":\"041696\",\"astOrgName\":\"国网湖南省电力公司\",\"voltsigInputChanqutity\":\"1\",\"cabinetType#Name\":\"紧凑型金属封闭式\",\"runDevName\":\"504\",\"devPowerVoltage\":\"220\",\"station\":\"531b04dd7c8a5f84214ff783280150531a67987189\",\"manufactureDate\":\"2020-12-19 00:00:00\",\"astNature#Name\":\"省（直辖市、自治区）公司\",\"portNum\":\"102\",\"maintGroup#Name\":\"变电运维二班\",\"maintGroup\":\"02DC9D994F3A79E4E053661EDF0AFC25\",\"manufacturer#Name\":\"南京灿能电力自动化股份有限公司\",\"detectDate\":\"2021-02-19 00:00:00\",\"city#Name\":\"国网张家界供电公司\",\"deployState#Name\":\"在运\",\"equipmentOwner#Name\":\"\",\"deviceLevel#Name\":\"A类\",\"cabinet\":\"4dcc03dbc58a5f84225130303b01514dcba0cd1be5\",\"gateway\":\"10.232.245.97\"}}],\"searchCount\":true,\"size\":1,\"total\":391}},\"status\":\"000000\"}";
		/*	char json_buf[] = "{\"errors\":\"成功\",\"message\":\"成功\",\"result\":{\"0751002\":{\"current\":1,\"orders\":[],\"pages\":391,\"records\":[{\"assets\":[],\"distribution\":1,\"id\":\"ff8080817efe6c21017f1064ab7c0c7e\",\"modelId\":\"0751002Z\",\"resource\":{\"deviceKind\":\"0751002\",\"maintOrg\":\"02DC9D994F2879E4E053661EDF0AFC25\",\"signalInputForm\":\"02\",\"source#Name\":\"设备增加-基本建设\",\"source\":\"01\",\"currsigInputChanqutity\":\"1\",\"astOrg#Name\":\"国网湖南省电力公司\",\"astOrg\":\"02DC9D994CE579E4E053661EDF0AFC25\",\"cabinetType\":\"05\",\"ctime\":\"2022-02-19 00:00:00\",\"model\":\"PQS-883\",\"station#Name\":\"110kV宝塔变电站\",\"equipmentOwner\":\"E94A0732B2FB5AA1E0430901E80A21E9\",\"manufactureNum\":\"202596\",\"ipAddress\":\"10.232.245.101\",\"equipCode\":\"16M00000128569231\",\"subnetMask\":\"255.255.255.224\",\"astId\":\"ff8080817efe6c21017f1064ab7c0c7e\",\"macAddress\":\"00：B7：8D：00：DC：23\",\"astNum\":\"200102118916\",\"signalInputForm#Name\":\"数字信号\",\"maintOrg#Name\":\"张家界供电公司检修公司\",\"name\":\"110kV 珍宝线504电能质量监测装置\",\"deviceLevel\":\"01\",\"projectNum\":\"GGXM20220219BT\",\"projectName\":\"电能质量监测装置\",\"operateDate\":\"2021-11-19 00:00:00\",\"deployState\":\"20\",\"hardDiskCapacity\":\"64\",\"city\":\"02DC9D994EED79E4E053661EDF0AFC25\",\"timeSynchronization\":\"02\",\"astNature\":\"03\",\"manufacturer\":\"041696\",\"astOrgName\":\"国网湖南省电力公司\",\"voltsigInputChanqutity\":\"1\",\"cabinetType#Name\":\"紧凑型金属封闭式\",\"runDevName\":\"504\",\"devPowerVoltage\":\"220\",\"station\":\"531b04dd7c8a5f84214ff783280150531a67987189\",\"manufactureDate\":\"2020-12-19 00:00:00\",\"astNature#Name\":\"省（直辖市、自治区）公司\",\"portNum\":\"102\",\"maintGroup#Name\":\"变电运维二班\",\"maintGroup\":\"02DC9D994F3A79E4E053661EDF0AFC25\",\"manufacturer#Name\":\"南京灿能电力自动化股份有限公司\",\"detectDate\":\"2021-02-19 00:00:00\",\"city#Name\":\"国网张家界供电公司\",\"deployState#Name\":\"在运\",\"equipmentOwner#Name\":\"\",\"deviceLevel#Name\":\"A类\",\"cabinet\":\"4dcc03dbc58a5f84225130303b01514dcba0cd1be5\",\"gateway\":\"10.232.245.97\"}},{\"assets\":[],\"distribution\":1,\"id\":\"af8080817efe6c21017f1064ab7c0c7e\",\"modelId\":\"0751002Z\",\"resource\":{\"deviceKind\":\"0751002\",\"maintOrg\":\"02DC9D994F2879E4E053661EDF0AFC25\",\"signalInputForm\":\"02\",\"source#Name\":\"设备增加-基本建设\",\"source\":\"01\",\"currsigInputChanqutity\":\"1\",\"astOrg#Name\":\"国网湖南省电力公司\",\"astOrg\":\"02DC9D994CE579E4E053661EDF0AFC25\",\"cabinetType\":\"05\",\"ctime\":\"2022-02-19 00:00:00\",\"model\":\"PQS-883\",\"station#Name\":\"110kV宝塔变电站\",\"equipmentOwner\":\"E94A0732B2FB5AA1E0430901E80A21E9\",\"manufactureNum\":\"202596\",\"ipAddress\":\"10.232.245.101\",\"equipCode\":\"16M00002128569231\",\"subnetMask\":\"255.255.255.224\",\"astId\":\"af8080817efe6c21017f1064ab7c0c7e\",\"macAddress\":\"00：B7：8D：00：DC：23\",\"astNum\":\"200102118916\",\"signalInputForm#Name\":\"数字信号\",\"maintOrg#Name\":\"张家界供电公司检修公司\",\"name\":\"110kV 珍宝线504电能质量监测装置\",\"deviceLevel\":\"01\",\"projectNum\":\"GGXM20220219BT\",\"projectName\":\"电能质量监测装置\",\"operateDate\":\"2021-11-19 00:00:00\",\"deployState\":\"20\",\"hardDiskCapacity\":\"64\",\"city\":\"02DC9D994EED79E4E053661EDF0AFC25\",\"timeSynchronization\":\"02\",\"astNature\":\"03\",\"manufacturer\":\"041696\",\"astOrgName\":\"国网湖南省电力公司\",\"voltsigInputChanqutity\":\"1\",\"cabinetType#Name\":\"紧凑型金属封闭式\",\"runDevName\":\"504\",\"devPowerVoltage\":\"220\",\"station\":\"531b04dd7c8a5f84214ff783280150531a67987189\",\"manufactureDate\":\"2020-12-19 00:00:00\",\"astNature#Name\":\"省（直辖市、自治区）公司\",\"portNum\":\"102\",\"maintGroup#Name\":\"变电运维二班\",\"maintGroup\":\"02DC9D994F3A79E4E053661EDF0AFC25\",\"manufacturer#Name\":\"南京灿能电力自动化股份有限公司\",\"detectDate\":\"2021-02-19 00:00:00\",\"city#Name\":\"国网张家界供电公司\",\"deployState#Name\":\"在运\",\"equipmentOwner#Name\":\"\",\"deviceLevel#Name\":\"A类\",\"cabinet\":\"4dcc03dbc58a5f84225130303b01514dcba0cd1be5\",\"gateway\":\"100.232.245.97\"}}],\"searchCount\":true,\"size\":2,\"total\":391}},\"status\":\"000000\"}";
			json = cJSON_Parse(json_buf);*/
			//char json_buf[] = "{\"errors\":\"成功\",\"message\":\"成功\",\"result\":{\"0751002\":{\"current\":1,\"orders\":[],\"pages\":391,\"records\":[{\"assets\":[],\"distribution\":1,\"id\":\"ff8080817efe6c21017f1064ab7c0c7e\",\"modelId\":\"0751002Z\",\"resource\":{\"deviceKind\":\"0751002\",\"maintOrg\":\"02DC9D994F2879E4E053661EDF0AFC25\",\"signalInputForm\":\"02\",\"source#Name\":\"设备增加-基本建设\",\"source\":\"01\",\"currsigInputChanqutity\":\"1\",\"astOrg#Name\":\"国网湖南省电力公司\",\"astOrg\":\"02DC9D994CE579E4E053661EDF0AFC25\",\"cabinetType\":\"05\",\"ctime\":\"2022-02-19 00:00:00\",\"model\":\"E8300\",\"station#Name\":\"110kV宝塔变电站\",\"equipmentOwner\":\"E94A0732B2FB5AA1E0430901E80A21E9\",\"manufactureNum\":\"202596\",\"ipAddress\":\"10.161.208.227\",\"equipCode\":\"22M00000299758903\",\"subnetMask\":\"255.255.255.224\",\"astId\":\"ff8080817efe6c21017f1064ab7c0c7e\",\"macAddress\":\"00：B7：8D：00：DC：23\",\"astNum\":\"200102118916\",\"signalInputForm#Name\":\"数字信号\",\"maintOrg#Name\":\"张家界供电公司检修公司\",\"name\":\"110kV 珍宝线504电能质量监测装置\",\"deviceLevel\":\"01\",\"projectNum\":\"GGXM20220219BT\",\"projectName\":\"电能质量监测装置\",\"operateDate\":\"2021-11-19 00:00:00\",\"deployState\":\"20\",\"hardDiskCapacity\":\"64\",\"city\":\"02DC9D994EED79E4E053661EDF0AFC25\",\"timeSynchronization\":\"02\",\"astNature\":\"03\",\"manufacturer\":\"041696\",\"astOrgName\":\"国网湖南省电力公司\",\"voltsigInputChanqutity\":\"1\",\"cabinetType#Name\":\"紧凑型金属封闭式\",\"runDevName\":\"504\",\"devPowerVoltage\":\"220\",\"station\":\"531b04dd7c8a5f84214ff783280150531a67987189\",\"manufactureDate\":\"2020-12-19 00:00:00\",\"astNature#Name\":\"省（直辖市、自治区）公司\",\"portNum\":\"20102\",\"maintGroup#Name\":\"变电运维二班\",\"maintGroup\":\"02DC9D994F3A79E4E053661EDF0AFC25\",\"manufacturer#Name\":\"南京灿能电力自动化股份有限公司\",\"detectDate\":\"2021-02-19 00:00:00\",\"city#Name\":\"国网张家界供电公司\",\"deployState#Name\":\"在运\",\"equipmentOwner#Name\":\"\",\"deviceLevel#Name\":\"A类\",\"cabinet\":\"4dcc03dbc58a5f84225130303b01514dcba0cd1be5\",\"gateway\":\"10.232.245.97\"}},{\"assets\":[],\"distribution\":1,\"id\":\"af8080817efe6c21017f1064ab7c0c7e\",\"modelId\":\"0751002Z\",\"resource\":{\"deviceKind\":\"0751002\",\"maintOrg\":\"02DC9D994F2879E4E053661EDF0AFC25\",\"signalInputForm\":\"02\",\"source#Name\":\"设备增加-基本建设\",\"source\":\"01\",\"currsigInputChanqutity\":\"1\",\"astOrg#Name\":\"国网湖南省电力公司\",\"astOrg\":\"02DC9D994CE579E4E053661EDF0AFC25\",\"cabinetType\":\"05\",\"ctime\":\"2022-02-19 00:00:00\",\"model\":\"E8300\",\"station#Name\":\"110kV宝塔变电站\",\"equipmentOwner\":\"E94A0732B2FB5AA1E0430901E80A21E9\",\"manufactureNum\":\"202596\",\"ipAddress\":\"10.161.208.237\",\"equipCode\":\"22M00000299800679\",\"subnetMask\":\"255.255.255.224\",\"astId\":\"af8080817efe6c21017f1064ab7c0c7e\",\"macAddress\":\"00：B7：8D：00：DC：23\",\"astNum\":\"200102118916\",\"signalInputForm#Name\":\"数字信号\",\"maintOrg#Name\":\"张家界供电公司检修公司\",\"name\":\"110kV 珍宝线504电能质量监测装置\",\"deviceLevel\":\"01\",\"projectNum\":\"GGXM20220219BT\",\"projectName\":\"电能质量监测装置\",\"operateDate\":\"2021-11-19 00:00:00\",\"deployState\":\"20\",\"hardDiskCapacity\":\"64\",\"city\":\"02DC9D994EED79E4E053661EDF0AFC25\",\"timeSynchronization\":\"02\",\"astNature\":\"03\",\"manufacturer\":\"041696\",\"astOrgName\":\"国网湖南省电力公司\",\"voltsigInputChanqutity\":\"1\",\"cabinetType#Name\":\"紧凑型金属封闭式\",\"runDevName\":\"504\",\"devPowerVoltage\":\"220\",\"station\":\"531b04dd7c8a5f84214ff783280150531a67987189\",\"manufactureDate\":\"2020-12-19 00:00:00\",\"astNature#Name\":\"省（直辖市、自治区）公司\",\"portNum\":\"10022\",\"maintGroup#Name\":\"变电运维二班\",\"maintGroup\":\"02DC9D994F3A79E4E053661EDF0AFC25\",\"manufacturer#Name\":\"南京灿能电力自动化股份有限公司\",\"detectDate\":\"2021-02-19 00:00:00\",\"city#Name\":\"国网张家界供电公司\",\"deployState#Name\":\"在运\",\"equipmentOwner#Name\":\"\",\"deviceLevel#Name\":\"A类\",\"cabinet\":\"4dcc03dbc58a5f84225130303b01514dcba0cd1be5\",\"gateway\":\"100.232.245.97\"}}],\"searchCount\":true,\"size\":2,\"total\":391}},\"status\":\"000000\"}";
			//json = cJSON_Parse(json_buf);

			//char json_buf[] = "{\"errors\":\"成功\",\"message\":\"成功\",\"result\":{\"0751002\":{\"current\":1,\"orders\":[],\"pages\":391,\"records\":[{\"assets\":[],\"distribution\":1,\"id\":\"ff8080817efe6c21017f1064ab7c0c7e\",\"modelId\":\"0751002Z\",\"resource\":{\"deviceKind\":\"0751002\",\"maintOrg\":\"02DC9D994F2879E4E053661EDF0AFC25\",\"cabinet\":\"4dcc03dbc58a5f84225130303b01514dcba0cd1be5\",\"gateway\":\"10.232.245.97\"}}],\"searchCount\":true,\"size\":1,\"total\":391}},\"status\":\"000000\"}";

			json = cJSON_Parse(strDevCJson.toUtf8().constData());   //json格式序列化
			//cout << cJSON_Print(json) << endl;
			if (NULL == json)
			{
				printf("cJSON_Parse error:%s\n", cJSON_GetErrorPtr());
				return APR_EBADF;
			}
			json_records = cJSON_GetObjectItem(json, "result");    //获取result
			json_records = cJSON_GetObjectItem(json_records, "0751002");    //获取0751002 
			json_value = cJSON_GetObjectItem(json_records, "total");    //获取 total
			if (json_value != NULL) {
				total = json_value->valueint;
			}

			cJSON_Delete(json);

			if (MULTIPLE_NODE_FLAG && g_front_seg_num == 0) {
				GetWebApiJson(mp_num, FRONT_INST, CITY_FLAG);
			}
			else if (MULTIPLE_NODE_FLAG && g_front_seg_num != 0) {
				int front_num = (total / g_front_seg_num) + 1;
				GetWebApiJson(front_num, FRONT_INST, CITY_FLAG);

			}
			else {
				/*	cout << "dev total:" << total << endl;
					if (total > 300) {
						total = 300;
						cout << "update dev total:" << total << endl;

					}*/
				GetWebApiJson(total, 1, CITY_FLAG);
			}


			if (strDevCJson == "") {
				cout << "select dev json error" << endl;
				return APR_EBADF;
			}
			json = cJSON_Parse(strDevCJson.toUtf8().constData());   //json格式序列化

			//json = cJSON_Parse(json_buf);

			json_records = cJSON_GetObjectItem(json, "result");    //获取result
			json_records = cJSON_GetObjectItem(json_records, "0751002");    //获取0751002 
			json_value = cJSON_GetObjectItem(json_records, "size");    //获取 size


			json_records = cJSON_GetObjectItem(json_records, "records");    //获取records
			array_size = cJSON_GetArraySize(json_records);    //获取数组大小
			if (array_size <= 1) {
				effective_flag = 1;
				if (dev_read_count <= 5) {
					cJSON_Delete(json);
				}
			}

		}


		count_cfg = array_size;
		cout << "count_cfg" << "--" << count_cfg << endl;
		g_node->n_clients = count_cfg;
		g_node->clients = (ied_t**)apr_pcalloc(g_cfg_pool, count_cfg * sizeof(ied_t*));
		for (int k = 0; k < count_cfg; k++)
			g_node->clients[k] = (ied_t*)apr_pcalloc(g_cfg_pool, sizeof(ied_t));


		printf("array_size=%d\n", array_size);

		for (int i = 0; i < array_size; i++)
		{
			json_node = cJSON_GetArrayItem(json_records, i);//array
			json_node = cJSON_GetObjectItem(json_node, "resource");    //获取resource
			ied = g_node->clients[count_real++];
			ied_usr = (ied_usr_t*)apr_pcalloc(g_init_pool, sizeof(ied_usr_t));
			ied->usr_ext = ied_usr;
			if (ied_usr == NULL)
				return APR_ENOMEM;
			ied_usr->last_call_wavelist_time = sGetMsTime() + g_pt61850app->giTime * 1000;
			ied_usr->LD_info = (LD_info_t*)apr_pcalloc(g_init_pool, MAX_CPUNO * sizeof(LD_info_t));
			for (int num = 0; num < MAX_CPUNO; num++) {
				ied_usr->LD_info[num].read_flag = 0;
			}
			if (ied_usr->LD_info == NULL)
				return APR_ENOMEM;
			ied_usr->dev_flag = g_DevFlag;
			ied->chncount = 1;
			ied->channel = (channel_t*)apr_pcalloc(g_cfg_pool, sizeof(channel_t) * ied->chncount);
			ied->channel[0].ied = ied;
			ied->channel[0].status = STATUS_BREAKOFF;

			json_value = cJSON_GetObjectItem(json_node, "astId");    //获取 astId
			if (json_value != NULL && json_value->string != NULL) {
				apr_snprintf(ied_usr->terminal_id, sizeof(ied_usr->terminal_id), "%s", json_value->valuestring);//terminal_id
				cout << "terminal_id:" << json_value->valuestring << "--" << ied_usr->terminal_id << endl;
			}
			else {
				apr_snprintf(ied_usr->terminal_id, sizeof(ied_usr->terminal_id), "%s", "");//terminal_id
				cout << "default terminal_id:" << ied_usr->terminal_id << endl;
			}


			json_value = cJSON_GetObjectItem(json_node, "equipCode");    //获取 equipCode
			if (json_value != NULL && json_value->string != NULL) {
				apr_snprintf(ied_usr->terminal_code, sizeof(ied_usr->terminal_code), "%s", json_value->valuestring);//terminal_code
				cout << "terminal_code:" << json_value->valuestring << "--" << ied_usr->terminal_code << endl;
			}
			else {
				apr_snprintf(ied_usr->terminal_code, sizeof(ied_usr->terminal_code), "%s", "");//terminal_code
				cout << "default terminal_code:" << ied_usr->terminal_code << endl;
			}


			json_value = cJSON_GetObjectItem(json_node, "city#Name");    //获取 city#Name
			if (json_value != NULL && json_value->string != NULL) {
				apr_snprintf(ied_usr->org_name, sizeof(ied_usr->org_name), "%s", json_value->valuestring);//org_name
				cout << "org_name:" << json_value->valuestring << "--" << ied_usr->org_name << endl;
			}


			json_value = cJSON_GetObjectItem(json_node, "maintOrg#Name");    //获取 maintOrg#Name
			if (json_value != NULL && json_value->string != NULL) {
				apr_snprintf(ied_usr->maint_name, sizeof(ied_usr->maint_name), "%s", json_value->valuestring);//maint_name
				cout << "maint_name:" << json_value->valuestring << "--" << ied_usr->maint_name << endl;
			}


			json_value = cJSON_GetObjectItem(json_node, "station#Name");    //获取 station#Name
			if (json_value != NULL && json_value->string != NULL) {
				apr_snprintf(ied_usr->station_name, sizeof(ied_usr->station_name), "%s", json_value->valuestring);//station_name
				cout << "station_name:" << json_value->valuestring << "--" << ied_usr->station_name << endl;
			}


			json_value = cJSON_GetObjectItem(json_node, "manufacturer#Name");    //获取 manufacturer#Name
			if (json_value != NULL && json_value->string != NULL) {
				apr_snprintf(ied_usr->tmnl_factory, sizeof(ied_usr->tmnl_factory), "%s", json_value->valuestring);//tmnl_factory
				cout << "tmnl_factory:" << json_value->valuestring << "--" << ied_usr->tmnl_factory << endl;
			}


			json_value = cJSON_GetObjectItem(json_node, "deployState");    //获取 deployState
			if (json_value != NULL && json_value->string != NULL) {
				apr_snprintf(ied_usr->tmnl_status, sizeof(ied_usr->tmnl_status), "%s", json_value->valuestring);//tmnl_status
				cout << "tmnl_status:" << json_value->valuestring << "--" << ied_usr->tmnl_status << endl;
			}
			else {
				apr_snprintf(ied_usr->tmnl_status, sizeof(ied_usr->tmnl_status), "%s", "10");//tmnl_status
				cout << "default tmnl_status:" << ied_usr->tmnl_status << endl;

			}


			//json_value = cJSON_GetObjectItem(json_node, "lastUpdateTime");    //获取 lastUpdateTime
			json_value = cJSON_GetObjectItem(json_node, "ctime");    //获取 ctime
			if (json_value != NULL && json_value->string != NULL) {
				//ied_usr->time = strtoll(json_value->valuestring, NULL, 10);//time
				ied_usr->time = charToLongLong(json_value->valuestring);//time
				cout << "time:" << ied_usr->time << endl;
			}


			json_value = cJSON_GetObjectItem(json_node, "model");    //获取 model
			if (json_value != NULL && json_value->string != NULL) {
				apr_snprintf(ied_usr->dev_type, sizeof(ied_usr->dev_type), "%s", json_value->valuestring);//DEV_Type
				cout << "dev_type:" << json_value->valuestring << "--" << ied_usr->dev_type << endl;
			}
			else {
				apr_snprintf(ied_usr->dev_type, sizeof(ied_usr->dev_type), "%s", "no-type");//DEV_Type
				cout << "default dev_type:" << ied_usr->dev_type << endl;
			}

			int t = 0;
			if (t) {
				//QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Key
				apr_snprintf(ied_usr->dev_key, sizeof(ied_usr->dev_key), "%s", "!qaz@wsx3edc4rfv");//DEV_Key
				cout << "dev_key:" << ied_usr->dev_key << endl;

				//QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Series
				apr_snprintf(ied_usr->dev_series, sizeof(ied_usr->dev_series), "%s", "Pqs&cn870299");//DEV_Series
				cout << "dev_series:" << ied_usr->dev_series << endl;
			}
			else {
				cout << "code:" << ied_usr->terminal_code << endl;
				if (terminal_ext_map.contains(QString::fromUtf8(ied_usr->terminal_code))) {
					//terminal_ext* ext = terminal_ext_map.value(ied_usr->terminal_code);
					terminal_ext* ext = terminal_ext_map.value(QString::fromUtf8(ied_usr->terminal_code));
					//QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Key
					apr_snprintf(ied_usr->dev_key, sizeof(ied_usr->dev_key), "%s", ext->terminal_key);//DEV_Key
					cout << "dev_key:" << ied_usr->dev_key << endl;

					//QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Series
					apr_snprintf(ied_usr->dev_series, sizeof(ied_usr->dev_series), "%s", ext->terminal_identify_code);//DEV_Series
					cout << "dev_series:" << ied_usr->dev_series << endl;
				}
				else
				{

					//QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Key
					apr_snprintf(ied_usr->dev_key, sizeof(ied_usr->dev_key), "%s", "");//DEV_Key
					cout << "defalut dev_key:" << ied_usr->dev_key << endl;

					//QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Series
					apr_snprintf(ied_usr->dev_series, sizeof(ied_usr->dev_series), "%s", "");//DEV_Series
					cout << "defalut dev_series:" << ied_usr->dev_series << endl;
				}
			}

			ied_usr->dev_flag = 0;//DEV_DevFlag


			ied->channel[0].channel_type = CHANNEL_TYPE_IPV4;//channel
			cout << "channel_type:" << ied->channel[0].channel_type << endl;
			ied->channel[0].addr_str[LONGNAME - 1] = 0;//DEV_IP

			json_value = cJSON_GetObjectItem(json_node, "ipAddress");    //获取 ipAddress
			if (json_value != NULL && json_value->string != NULL) {
				if (t && i == 0) {
					ied->channel[0].addr = ntohl(inet_addr("172.40.251.35"));//DEV_IP
					strncpy(ied->channel[0].addr_str, "172.40.251.35", LONGNAME - 1);//DEV_IP
				}
				else {
					ied->channel[0].addr = ntohl(inet_addr(json_value->valuestring));//DEV_IP
					strncpy(ied->channel[0].addr_str, json_value->valuestring, LONGNAME - 1);//DEV_IP
				}
				cout << "addr:" << json_value->valuestring << "--" << ied->channel[0].addr << "--" << ied->channel[0].addr_str << endl;

			}
			else {
				ied->channel[0].addr = ntohl(inet_addr("0.0.0.1"));//DEV_IP
				strncpy(ied->channel[0].addr_str, "0.0.0.1", LONGNAME - 1);//DEV_IP
				//}
				cout << "default addr:" << ied->channel[0].addr_str << endl;

			}


			json_value = cJSON_GetObjectItem(json_node, "portNum");    //获取 portNum
			if (json_value != NULL && json_value->string != NULL) {
				ied->channel[0].port = atoi(json_value->valuestring);//DEV_PortID
				if (t) {
					ied->channel[0].port = atoi("102");//DEV_PortID
				}
				cout << "port:" << "--" << atoi(json_value->valuestring) << "--" << ied->channel[0].port << endl;
			}
			else {
				ied->channel[0].port = 0;//DEV_PortID
				if (t) {
					ied->channel[0].port = atoi("102");//DEV_PortID
				}
				cout << "default port:" << ied->channel[0].port << endl;

			}

			chnl_usr = (chnl_usr_t*)apr_pcalloc(g_init_pool, sizeof(chnl_usr_t));
			ied->channel[0].connect = chnl_usr;
			chnl_usr->chnl = &(ied->channel[0]);
			chnl_usr->chnl_id = 0;
			chnl_usr->m_state = CHANNEL_DISCONNECTED;
			chnl_usr->m_ClosedMsTime = NEXT_CONNECT_TIME * (-1);
			g_pt61850app->chnl_counts++;

		}
		cJSON_Delete(json);
		//list循环结束




		if (MULTIPLE_NODE_FLAG) {
			QString updateFrontSql;//待组装的pgsql语句
			updateFrontSql.append(QString("update \"%1\".\"%2meas_pq_front_list_tr\" ").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX));
			updateFrontSql.append(QString("set \"mp_num\"= %1 ").arg(count_real));
			updateFrontSql.append(QString("where \"front_ip\" = '%1' and \"front_inst\"=%2").arg(FRONT_IP).arg(FRONT_INST));
			OTLConnect();
			int rt = write_to_db(updateFrontSql.toStdString().c_str());
			OTLDisconnect();

		}

		if (count_real < count_cfg)
			g_node->n_clients = count_real;
		if (count_cfg != count_real)
			return APR_EBADF;
		cout << "dev init create count:" << count_real;
		return APR_SUCCESS;
	}
	catch (const std::exception& e) {
		cout << "Exception caught: " << e.what() << endl;
		// 这里可以添加其他异常处理逻辑
	}

}
//CZY 2023-09-15 pg device
int parse_device_cfg_pg()
{
	qDebug() << "parse_device_cfg_pg" << endl;

	if (FRONT_INST == 0 || FRONT_IP[0] == '\0') {
		MULTIPLE_NODE_FLAG = 0;
		cout << "set MULTIPLE_NODE_FLAG:0,because do not have FRONT_INST or FRONT_IP" << endl;

	}
	char front_type[2];
	int mp_num;

	if (MULTIPLE_NODE_FLAG) {
		QString selectFrontSql;
		selectFrontSql.append(QString("select \"front_type\",\"mp_num\" from \"%1\".\"%2meas_pq_front_list_tr\" ").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX));
		selectFrontSql.append(QString("where \"front_ip\" = '0.0.0.0' and \"front_inst\"=0"));
		cout << selectFrontSql.toStdString().c_str() << endl;
		try {
			OTLConnect();
			otl_stream i2(1, // buffer size
				selectFrontSql.toStdString().c_str(),
				//SELECT statement
				db //connect object
			);
			//create select stream


			while (!i2.eof()) { //while not end-of-data
				i2 >> front_type >> mp_num;
				break;
				//cout << "count=" << f2 << endl;
			}
			OTLDisconnect();
		}
		catch (otl_exception& e)
		{
			printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg);
			return e.code;
		}

		QString addFrontSql;
		addFrontSql.append(QString("insert into \"%1\".\"%2meas_pq_front_list_tr\"(\"front_ip\",\"front_port\",\"front_inst\",\"front_type\",\"front_status\",\"front_version\",\"mp_num\") ").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX));
		addFrontSql.append(QString("values('%1',10000,%2,'%3','01','%4',200) ").arg(FRONT_IP).arg(FRONT_INST).arg(front_type).arg(PROGRAM_VERSION));
		addFrontSql.append(QString("on conflict(\"front_ip\",\"front_inst\") do update set "));
		addFrontSql.append(QString("\"front_type\"= '%1',\"front_version\"='%2'").arg(front_type).arg(PROGRAM_VERSION));
		cout << addFrontSql.toStdString().c_str() << endl;

		OTLConnect();
		int rt = write_to_db(addFrontSql.toStdString().c_str());
		OTLDisconnect();

	}
	cout << "mp_num:" << mp_num << " FRONT_INST:" << FRONT_INST << endl;

	ied_t* ied;
	ied_usr_t* ied_usr;
	chnl_usr_t* chnl_usr;
	int count_cfg = 0;
	int count_real = 0;

	QMap<QString, terminal_ext*> terminal_ext_map;
	read_terminal_ext_pg(&terminal_ext_map);

	//读取数据
	try {
		OTLConnect();
		//int rtState = OTLState();
		std::string str2 = POSTGRES_SCHEMA;//schame analy
		std::string str1 = "select count(*) from \"";
		str1.append(str2);
		str1.append("\".\"");
		str1.append(POSTGRES_TABLEPREFIX);
		str1.append("meas_pq_dev_tr");
		str1.append("\"  where tmnl_status='20';");
		cout << "pg sql1 is:" << str1 << endl;
		//int rtState = OTLState();
		otl_stream i(1, // buffer size
			str1.c_str(),
			//SELECT statement
			db //connect object
		);
		//create select stream

		int f2;
		while (!i.eof()) { //while not end-of-data
			i >> f2;
			//cout << "count=" << f2 << endl;
		}
		OTLDisconnect();
		count_cfg = f2;;//读数据库
		cout << "dev_count=" << count_cfg << endl;


	}
	catch (otl_exception& e)
	{
		printf("\ndev PostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg);
		return e.code;
	}
	std::string strSchame = POSTGRES_SCHEMA;//schame analy
	std::string strDevSQL = "select  \"terminal_id\",\"terminal_code\",\"org_name\",\"maint_name\",\"station_name\",\"tmnl_ip\",\"tmnl_port\",\"tmnl_factory\",\"tmnl_type\",\"tmnl_status\",\"update_time\" from \"";
	strDevSQL.append(strSchame);
	strDevSQL.append("\".\"");
	strDevSQL.append(POSTGRES_TABLEPREFIX);
	strDevSQL.append("meas_pq_dev_tr");
	strDevSQL.append("\"  where tmnl_status='20'");
	if (MULTIPLE_NODE_FLAG && g_front_seg_num == 0) {
		strDevSQL.append(" ORDER BY terminal_id OFFSET ");
		strDevSQL.append(QString::number((FRONT_INST - 1) * mp_num).toStdString());
		strDevSQL.append(" LIMIT ");
		strDevSQL.append(QString::number(mp_num).toStdString());
		if (mp_num * FRONT_INST > count_cfg) {
			count_cfg = count_cfg - (FRONT_INST - 1) * mp_num;
		}
		else
		{
			count_cfg = mp_num;
		}
	}
	else if (MULTIPLE_NODE_FLAG && g_front_seg_num != 0) {
		int front_num = (count_cfg / g_front_seg_num) + 1;
		strDevSQL.append(" ORDER BY terminal_code OFFSET ");
		strDevSQL.append(QString::number((FRONT_INST - 1) * front_num).toStdString());
		strDevSQL.append(" LIMIT ");
		strDevSQL.append(QString::number(front_num).toStdString());
		if (front_num * FRONT_INST > count_cfg) {
			count_cfg = count_cfg - (FRONT_INST - 1) * front_num;
		}
		else
		{
			count_cfg = front_num;
		}
	}

	cout << strDevSQL << endl;

	g_node->n_clients = count_cfg;
	g_node->clients = (ied_t**)apr_pcalloc(g_cfg_pool, count_cfg * sizeof(ied_t*));
	for (int k = 0; k < count_cfg; k++)
		g_node->clients[k] = (ied_t*)apr_pcalloc(g_cfg_pool, sizeof(ied_t));


	//读数据
	try {
		cout << "read dev information." << endl;
		OTLConnect();

		//cout << "pg sql2 is:" << str1 << endl;
		//int rtState = OTLState();
		// 执行长的select语句
		otl_stream i(1, // buffer size
			strDevSQL.c_str(),
			//SELECT statement
			db //connect object
		);

		//create select stream

		char terminal_id[64];
		char terminal_code[64];
		char org_name[64];
		char maint_name[64];
		char station_name[64];
		char tmnl_factory[64];
		char tmnl_status[64];
		char dev_type[64];
		char dev_key[64];
		char dev_series[64];
		char addr_str[64];
		char port_char[64];
		otl_datetime  timestamp;

		while (!i.eof()) { //while not end-of-data
			i >> terminal_id >> terminal_code >> org_name >> maint_name >> station_name >> addr_str >> port_char >> tmnl_factory >> dev_type >> tmnl_status >> timestamp;
			//cout << "monitor_id=" << monitor_id << " terminal_code=" << terminal_code << " monitor_name=" << monitor_name << " logical_device_seq=" << logical_device_seq;
			//cout << " voltage_level=" << voltage_level << " terminal_connect=" << terminal_connect;
			//cout << " timestamp: " << timestamp.year << "-" << timestamp.month << "-" << timestamp.day << " " << timestamp.hour << ":" << timestamp.minute << ":" << timestamp.second << endl;

			ied = g_node->clients[count_real++];
			ied_usr = (ied_usr_t*)apr_pcalloc(g_init_pool, sizeof(ied_usr_t));
			ied->usr_ext = ied_usr;
			if (ied_usr == NULL)
				return APR_ENOMEM;
			ied_usr->last_call_wavelist_time = sGetMsTime() + g_pt61850app->giTime * 1000;
			ied_usr->LD_info = (LD_info_t*)apr_pcalloc(g_init_pool, MAX_CPUNO * sizeof(LD_info_t));
			if (ied_usr->LD_info == NULL)
				return APR_ENOMEM;
			ied_usr->dev_flag = g_DevFlag;

			ied->chncount = 1;
			ied->channel = (channel_t*)apr_pcalloc(g_cfg_pool, sizeof(channel_t) * ied->chncount);
			ied->channel[0].ied = ied;
			ied->channel[0].status = STATUS_BREAKOFF;

			ied->cpucount = 0;

			if (strlen(terminal_id) != 0) {
				apr_snprintf(ied_usr->terminal_id, sizeof(ied_usr->terminal_id), "%s", terminal_id);//terminal_id
				cout << "ied_usr->terminal_id:" << ied_usr->terminal_id << endl;
			}
			if (terminal_code != NULL) {
				apr_snprintf(ied_usr->terminal_code, sizeof(ied_usr->terminal_code), "%s", terminal_code);//terminal_code
				cout << "ied_usr->terminal_code:" << ied_usr->terminal_code << endl;

			}
			if (org_name != NULL) {
				apr_snprintf(ied_usr->org_name, sizeof(ied_usr->org_name), "%s", org_name);//org_name
				cout << "ied_usr->org_name:" << ied_usr->org_name << endl;

			}
			if (maint_name != NULL) {
				apr_snprintf(ied_usr->maint_name, sizeof(ied_usr->maint_name), "%s", maint_name);//maint_name
				cout << "ied_usr->maint_name:" << ied_usr->maint_name << endl;

			}
			if (station_name != NULL) {
				apr_snprintf(ied_usr->station_name, sizeof(ied_usr->station_name), "%s", station_name);//station_name
				cout << "ied_usr->station_name:" << ied_usr->station_name << endl;

			}
			if (tmnl_factory != NULL) {
				apr_snprintf(ied_usr->tmnl_factory, sizeof(ied_usr->tmnl_factory), "%s", tmnl_factory);//tmnl_factory
				cout << "ied_usr->tmnl_factory:" << ied_usr->tmnl_factory << endl;

			}
			if (tmnl_status != NULL) {
				apr_snprintf(ied_usr->tmnl_status, sizeof(ied_usr->tmnl_status), "%s", tmnl_status);//tmnl_status
				cout << "ied_usr->tmnl_status:" << ied_usr->tmnl_status << endl;

			}
			if (dev_type != NULL) {
				apr_snprintf(ied_usr->dev_type, sizeof(ied_usr->dev_type), "%s", dev_type);//dev_type
				cout << "ied_usr->dev_type:" << ied_usr->dev_type << endl;

			}

			cout << "code" << ied_usr->terminal_code << endl;
			if (terminal_ext_map.contains(QString::fromUtf8(ied_usr->terminal_code))) {
				//terminal_ext* ext = terminal_ext_map.value(ied_usr->terminal_code);
				terminal_ext* ext = terminal_ext_map.value(QString::fromUtf8(ied_usr->terminal_code));
				//QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Key
				apr_snprintf(ied_usr->dev_key, sizeof(ied_usr->dev_key), "%s", ext->terminal_key);//DEV_Key
				cout << "dev_key:" << ied_usr->dev_key << endl;

				//QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Series
				apr_snprintf(ied_usr->dev_series, sizeof(ied_usr->dev_series), "%s", ext->terminal_identify_code);//DEV_Series
				cout << "dev_series:" << ied_usr->dev_series << endl;
			}
			else
			{

				//QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Key
				apr_snprintf(ied_usr->dev_key, sizeof(ied_usr->dev_key), "%s", "");//DEV_Key
				cout << "defalut dev_key:" << ied_usr->dev_key << endl;

				//QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Series
				apr_snprintf(ied_usr->dev_series, sizeof(ied_usr->dev_series), "%s", "");//DEV_Series
				cout << "defalut dev_series:" << ied_usr->dev_series << endl;
			}

			ied->channel[0].channel_type = CHANNEL_TYPE_IPV4;//channel
			ied->channel[0].addr_str[LONGNAME - 1] = 0;//DEV_IP
			if (addr_str != NULL) {
				ied->channel[0].addr = ntohl(inet_addr(addr_str));//DEV_IP
				strncpy(ied->channel[0].addr_str, addr_str, LONGNAME - 1);//DEV_IP
				cout << "ied_usr->addr_str:" << ied->channel[0].addr_str << endl;

			}
			else
			{
				ied->channel[0].addr = ntohl(inet_addr("0.0.0.0"));//DEV_IP
				strncpy(ied->channel[0].addr_str, addr_str, LONGNAME - 1);//DEV_IP
				cout << "ied_usr->addr_str:" << ied->channel[0].addr_str << endl;
			}

			if (port_char != NULL) {
				int port = 102;
				if (stringToInt(port_char, &port)) {
					// 转换成功，portStr全为数字，并且已经转换为int类型的port  
					ied->channel[0].port = port;//DEV_PortID
					cout << "ied_usr->port:" << ied->channel[0].port << endl;//DEV_PortID
				}
				else {
					ied->channel[0].port = 102;//DEV_PortID
					cout << "ied_usr->port:" << port_char << ",非合法端口.使用默认端口:" << ied->channel[0].port << endl;//DEV_PortID
				}


			}
			if (timestamp.year != 0) {
				//// 构造struct tm对象
				struct tm timeinfo;
				timeinfo.tm_year = timestamp.year - 1900; // 年份需要减去1900
				timeinfo.tm_mon = timestamp.month - 1; // 月份需要减去1
				timeinfo.tm_mday = timestamp.day;
				timeinfo.tm_hour = timestamp.hour;
				timeinfo.tm_min = timestamp.minute;
				timeinfo.tm_sec = timestamp.second;

				time_t time = std::mktime(&timeinfo);
				ied_usr->time = static_cast<long long>(time);
				cout << "ied_usr->time:" << ied_usr->time << endl;


			}
			chnl_usr = (chnl_usr_t*)apr_pcalloc(g_init_pool, sizeof(chnl_usr_t));
			ied->channel[0].connect = chnl_usr;
			chnl_usr->chnl = &(ied->channel[0]);
			chnl_usr->chnl_id = 0;
			chnl_usr->m_state = CHANNEL_DISCONNECTED;
			chnl_usr->m_ClosedMsTime = NEXT_CONNECT_TIME * (-1);
			g_pt61850app->chnl_counts++;


		}

		OTLDisconnect();
		//list循环结束
		if (count_real < count_cfg)
			g_node->n_clients = count_real;
		if (count_cfg != count_real)
			return APR_EBADF;
		cout << "dev init create count:" << count_real;
		return APR_SUCCESS;
	}
	catch (otl_exception& e)
	{
		printf("\ndev PostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg);
		return e.code;
	}

}
//CZY 2023-08-30 read line account from web api
int parse_line_cfg_pg()
{
	ied_t* ied;
	ied_usr_t* ied_usr;
	int count_cfg = 0;
	int count_real = 0;
	LD_info_t line_info;

	try {
		//int rtState = OTLState();
		std::string str2 = POSTGRES_SCHEMA;//schame analy
		std::string str1 = "select count(*) from \"";
		str1.append(str2);
		str1.append("\".\"");
		str1.append(POSTGRES_TABLEPREFIX);
		str1.append("pq_ledger_monitor");
		str1.append("\" where status<>'04' and status<>'05' and \"terminal_code\" in (");
		//str1.append("\".\"MEAS_PQ_FRONT_LIST_TR\"");
		int dev_no = 0;
		cout << "n_clients:" << g_node->n_clients << endl;
		if (g_node->n_clients <= 0) {
			cout << "no terminal exist " << endl;
			return APR_EBADF;
		}
		for (dev_no = 0; dev_no < g_node->n_clients; dev_no++) {
			str1.append("'");
			str1.append(((ied_usr_t*)(g_node->clients[dev_no]->usr_ext))->terminal_code);
			str1.append("'");
			if (dev_no < g_node->n_clients - 1) {
				str1 += ",";
			}
		}
		str1.append(")");
		cout << "pg sql1 is:" << str1 << endl;
		//int rtState = OTLState();
		OTLConnect();
		otl_stream i(1, // buffer size
			str1.c_str(),
			//SELECT statement
			db //connect object
		);
		//create select stream

		int f2;
		while (!i.eof()) { //while not end-of-data
			i >> f2;
			//cout << "count=" << f2 << endl;
		}
		OTLDisconnect();
		count_cfg = f2;;//读数据库
		cout << "line_count=" << count_cfg << endl;

	}
	catch (otl_exception& e)
	{
		printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg);
		return e.code;
	}



	//读数据
	try {
		OTLConnect();
		std::string str2 = POSTGRES_SCHEMA;//schame analy
		std::string str1 = "select \"monitor_id\",\"terminal_code\",\"monitor_name\",\"logical_device_seq\",\"voltage_level\",\"terminal_connect\",\"update_time\" from \"";
		str1.append(str2);
		str1.append("\".\"");
		str1.append(POSTGRES_TABLEPREFIX);
		str1.append("pq_ledger_monitor");
		str1.append("\" where status<>'04' and status<>'05' and \"terminal_code\" in (");
		int dev_no = 0;

		for (dev_no = 0; dev_no < g_node->n_clients; dev_no++) {
			str1.append("'");
			str1.append(((ied_usr_t*)(g_node->clients[dev_no]->usr_ext))->terminal_code);
			str1.append("'");
			if (dev_no < g_node->n_clients - 1) {
				str1 += ",";
			}
		}
		str1.append(")");
		cout << "pg sql2 is:" << str1 << endl;
		//int rtState = OTLState();
		otl_stream i(1, // buffer size
			str1.c_str(),
			//SELECT statement
			db //connect object
		);
		//create select stream

		char monitor_id[64];
		char terminal_code[64];
		char monitor_name[64];
		char logical_device_seq[64];
		char voltage_level[64];
		char terminal_connect[64];
		otl_datetime  timestamp;
		while (!i.eof()) { //while not end-of-data
			i >> monitor_id >> terminal_code >> monitor_name >> logical_device_seq >> voltage_level >> terminal_connect >> timestamp;
			cout << "monitor_id=" << monitor_id << " terminal_code=" << terminal_code << " monitor_name=" << monitor_name << " logical_device_seq=" << logical_device_seq;
			cout << " voltage_level=" << voltage_level << " terminal_connect=" << terminal_connect;
			cout << " timestamp: " << timestamp.year << "-" << timestamp.month << "-" << timestamp.day << " " << timestamp.hour << ":" << timestamp.minute << ":" << timestamp.second << endl;

			count_real++;
			memset(&line_info, 0, sizeof(line_info));
			line_info.line_id = count_real;
			//cout << "line_id:" << line_info.line_id << endl;

			strcpy(line_info.mp_id, monitor_id);
			//cout << "mp_id:" << line_info.mp_id << endl;
			strcpy(line_info.terminal_code, terminal_code);
			//cout << "terminal_code:" << line_info.terminal_code << endl;
			if (isCharPtrEmpty(logical_device_seq)) {
				line_info.cpuno = 1;
				//cout << "logical_device_seq:is null~"<< line_info.cpuno << endl;
			}
			else {
				line_info.cpuno = std::atoi(logical_device_seq);
				//cout << "logical_device_seq:"<< logical_device_seq << endl;
			}
			//cout << "cpuno:" << line_info.cpuno << endl;
			strcpy(line_info.voltage_level, voltage_level);
			//cout << "voltage_level:" << line_info.voltage_level << endl;
			strcpy(line_info.v_wiring_type, terminal_connect);
			//cout << "v_wiring_type:" << line_info.v_wiring_type << endl;

			//// 构造struct tm对象
			struct tm timeinfo;
			timeinfo.tm_year = timestamp.year - 1900; // 年份需要减去1900
			timeinfo.tm_mon = timestamp.month - 1; // 月份需要减去1
			timeinfo.tm_mday = timestamp.day;
			timeinfo.tm_hour = timestamp.hour;
			timeinfo.tm_min = timestamp.minute;
			timeinfo.tm_sec = timestamp.second;

			time_t time = std::mktime(&timeinfo);
			line_info.time = static_cast<long long>(time);
			//cout << "time:" << line_info.time << endl;

			strcpy(line_info.name, monitor_name);
			//cout << "name:" << line_info.name << endl;
			line_info.read_flag = 1;
			ied = find_ied_from_dev_code(line_info.terminal_code);

			if (ied && ied->usr_ext && line_info.cpuno && line_info.cpuno < 10) {
				char str[256];
				byte_t cpuno = line_info.cpuno;
				//cout << "cpuno:" << line_info.cpuno << endl;
				//cout << "byte_t cpuno:" << cpuno-1 << endl;
				ied_usr = (ied_usr_t*)ied->usr_ext;
				ied_usr->LD_info[cpuno - 1] = line_info;
				ied_usr->LD_info[cpuno - 1].ied = ied;
				apr_snprintf(str, sizeof(str), "PQMonitorPQM%d", cpuno);
				ied_usr->LD_info[cpuno - 1].LD_name = apr_pstrdup(g_init_pool, str);
				ied_usr->LD_info[cpuno - 1].ht_fcd = apr_hash_make(g_init_pool);
				ied_usr->LD_info[cpuno - 1].ht_full_fcda = apr_hash_make(g_init_pool);
				ied_usr->LD_info[cpuno - 1].rptcount = 0;
				//cout << "rptcount:" << ied_usr->LD_info[cpuno - 1].rptcount << endl;

				if (cpuno > ied->cpucount) {
					//int c = cpuno;
					//cout << "cpucount(linecount old):" << (int)(ied->cpucount) << "new:" << c << endl;

					ied->cpucount = cpuno;
					//cout << "byte_t cpucount:" << ied->cpucount+1 << endl;
				}
			}
		}
		OTLDisconnect();
	}
	catch (otl_exception& e)
	{
		printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg);
		return e.code;
	}

	if (count_cfg != count_real)
		return APR_EBADF;
	return APR_SUCCESS;
}
int parse_device_cfg_json_test()
{

	qDebug() << "parse_device_cfg_json_test" << endl;

	ied_t* ied;
	ied_usr_t* ied_usr;
	chnl_usr_t* chnl_usr;
	int count_cfg = 0;
	int count_real = 0;

	//读取数据
	//string* json_buf;
	cJSON* json = NULL;
	cJSON* json_value = NULL;

	cJSON* json_records = NULL;
	cJSON* json_node = NULL;

	int dev_num = 0;
	QMap<QString, terminal_ext*> terminal_ext_map;
	read_terminal_ext_pg(&terminal_ext_map);
	try {
		//GetWebApiJson(1);
	/*	if (strDevCJson == "") {
			cout << "json select total error" << endl;
			return APR_EBADF;
		}*/
		char json_buf[] = "{\"errors\":\"成功\",\"message\":\"成功\",\"result\":{\"0751002\":{\"current\":1,\"orders\":[],\"pages\":391,\"records\":[{\"assets\":[],\"distribution\":1,\"id\":\"ff8080817efe6c21017f1064ab7c0c7e\",\"modelId\":\"0751002Z\",\"resource\":{\"deviceKind\":\"0751002\",\"maintOrg\":\"02DC9D994F2879E4E053661EDF0AFC25\",\"signalInputForm\":\"02\",\"source#Name\":\"设备增加-基本建设\",\"source\":\"01\",\"currsigInputChanqutity\":\"1\",\"astOrg#Name\":\"国网湖南省电力公司\",\"astOrg\":\"02DC9D994CE579E4E053661EDF0AFC25\",\"cabinetType\":\"05\",\"ctime\":\"2022-02-19 00:00:00\",\"model\":\"PQS-883\",\"station#Name\":\"110kV宝塔变电站\",\"equipmentOwner\":\"E94A0732B2FB5AA1E0430901E80A21E9\",\"manufactureNum\":\"202596\",\"ipAddress\":\"10.232.245.101\",\"equipCode\":\"testcode\",\"subnetMask\":\"255.255.255.224\",\"astId\":\"ff8080817efe6c21017f1064ab7c0c7e\",\"macAddress\":\"00：B7：8D：00：DC：23\",\"astNum\":\"200102118916\",\"signalInputForm#Name\":\"数字信号\",\"maintOrg#Name\":\"张家界供电公司检修公司\",\"name\":\"110kV 珍宝线504电能质量监测装置\",\"deviceLevel\":\"01\",\"projectNum\":\"GGXM20220219BT\",\"projectName\":\"电能质量监测装置\",\"operateDate\":\"2021-11-19 00:00:00\",\"deployState\":\"20\",\"hardDiskCapacity\":\"64\",\"city\":\"02DC9D994EED79E4E053661EDF0AFC25\",\"timeSynchronization\":\"02\",\"astNature\":\"03\",\"manufacturer\":\"041696\",\"astOrgName\":\"国网湖南省电力公司\",\"voltsigInputChanqutity\":\"1\",\"cabinetType#Name\":\"紧凑型金属封闭式\",\"runDevName\":\"504\",\"devPowerVoltage\":\"220\",\"station\":\"531b04dd7c8a5f84214ff783280150531a67987189\",\"manufactureDate\":\"2020-12-19 00:00:00\",\"astNature#Name\":\"省（直辖市、自治区）公司\",\"portNum\":\"102\",\"maintGroup#Name\":\"变电运维二班\",\"maintGroup\":\"02DC9D994F3A79E4E053661EDF0AFC25\",\"manufacturer#Name\":\"南京灿能电力自动化股份有限公司\",\"detectDate\":\"2021-02-19 00:00:00\",\"city#Name\":\"国网张家界供电公司\",\"deployState#Name\":\"在运\",\"equipmentOwner#Name\":\"\",\"deviceLevel#Name\":\"A类\",\"cabinet\":\"4dcc03dbc58a5f84225130303b01514dcba0cd1be5\",\"gateway\":\"10.232.245.97\"}}],\"searchCount\":true,\"size\":1,\"total\":391}},\"status\":\"000000\"}";
		//char json_buf[] = "{\"errors\":\"成功\",\"message\":\"成功\",\"result\":{\"0751002\":{\"current\":1,\"orders\":[],\"pages\":391,\"records\":[{\"assets\":[],\"distribution\":1,\"id\":\"ff8080817efe6c21017f1064ab7c0c7e\",\"modelId\":\"0751002Z\",\"resource\":{\"deviceKind\":\"0751002\",\"maintOrg\":\"02DC9D994F2879E4E053661EDF0AFC25\",\"signalInputForm\":\"02\",\"source#Name\":\"设备增加-基本建设\",\"source\":\"01\",\"currsigInputChanqutity\":\"1\",\"astOrg#Name\":\"国网湖南省电力公司\",\"astOrg\":\"02DC9D994CE579E4E053661EDF0AFC25\",\"cabinetType\":\"05\",\"ctime\":\"2022-02-19 00:00:00\",\"model\":\"PQS-883\",\"station#Name\":\"110kV宝塔变电站\",\"equipmentOwner\":\"E94A0732B2FB5AA1E0430901E80A21E9\",\"manufactureNum\":\"202596\",\"ipAddress\":\"10.232.245.101\",\"equipCode\":\"testcode\",\"subnetMask\":\"255.255.255.224\",\"astId\":\"ff8080817efe6c21017f1064ab7c0c7e\",\"macAddress\":\"00：B7：8D：00：DC：23\",\"astNum\":\"200102118916\",\"signalInputForm#Name\":\"数字信号\",\"maintOrg#Name\":\"张家界供电公司检修公司\",\"name\":\"110kV 珍宝线504电能质量监测装置\",\"deviceLevel\":\"01\",\"projectNum\":\"GGXM20220219BT\",\"projectName\":\"电能质量监测装置\",\"operateDate\":\"2021-11-19 00:00:00\",\"deployState\":\"20\",\"hardDiskCapacity\":\"64\",\"city\":\"02DC9D994EED79E4E053661EDF0AFC25\",\"timeSynchronization\":\"02\",\"astNature\":\"03\",\"manufacturer\":\"041696\",\"astOrgName\":\"国网湖南省电力公司\",\"voltsigInputChanqutity\":\"1\",\"cabinetType#Name\":\"紧凑型金属封闭式\",\"runDevName\":\"504\",\"devPowerVoltage\":\"220\",\"station\":\"531b04dd7c8a5f84214ff783280150531a67987189\",\"manufactureDate\":\"2020-12-19 00:00:00\",\"astNature#Name\":\"省（直辖市、自治区）公司\",\"portNum\":\"102\",\"maintGroup#Name\":\"变电运维二班\",\"maintGroup\":\"02DC9D994F3A79E4E053661EDF0AFC25\",\"manufacturer#Name\":\"南京灿能电力自动化股份有限公司\",\"detectDate\":\"2021-02-19 00:00:00\",\"city#Name\":\"国网张家界供电公司\",\"deployState#Name\":\"在运\",\"equipmentOwner#Name\":\"\",\"deviceLevel#Name\":\"A类\",\"cabinet\":\"4dcc03dbc58a5f84225130303b01514dcba0cd1be5\",\"gateway\":\"10.232.245.97\"}},{\"assets\":[],\"distribution\":1,\"id\":\"af8080817efe6c21017f1064ab7c0c7e\",\"modelId\":\"0751002Z\",\"resource\":{\"deviceKind\":\"0751002\",\"maintOrg\":\"02DC9D994F2879E4E053661EDF0AFC25\",\"signalInputForm\":\"02\",\"source#Name\":\"设备增加-基本建设\",\"source\":\"01\",\"currsigInputChanqutity\":\"1\",\"astOrg#Name\":\"国网湖南省电力公司\",\"astOrg\":\"02DC9D994CE579E4E053661EDF0AFC25\",\"cabinetType\":\"05\",\"ctime\":\"2022-02-19 00:00:00\",\"model\":\"PQS-883\",\"station#Name\":\"110kV宝塔变电站\",\"equipmentOwner\":\"E94A0732B2FB5AA1E0430901E80A21E9\",\"manufactureNum\":\"202596\",\"ipAddress\":\"10.232.245.101\",\"equipCode\":\"16M00002128569231\",\"subnetMask\":\"255.255.255.224\",\"astId\":\"af8080817efe6c21017f1064ab7c0c7e\",\"macAddress\":\"00：B7：8D：00：DC：23\",\"astNum\":\"200102118916\",\"signalInputForm#Name\":\"数字信号\",\"maintOrg#Name\":\"张家界供电公司检修公司\",\"name\":\"110kV 珍宝线504电能质量监测装置\",\"deviceLevel\":\"01\",\"projectNum\":\"GGXM20220219BT\",\"projectName\":\"电能质量监测装置\",\"operateDate\":\"2021-11-19 00:00:00\",\"deployState\":\"20\",\"hardDiskCapacity\":\"64\",\"city\":\"02DC9D994EED79E4E053661EDF0AFC25\",\"timeSynchronization\":\"02\",\"astNature\":\"03\",\"manufacturer\":\"041696\",\"astOrgName\":\"国网湖南省电力公司\",\"voltsigInputChanqutity\":\"1\",\"cabinetType#Name\":\"紧凑型金属封闭式\",\"runDevName\":\"504\",\"devPowerVoltage\":\"220\",\"station\":\"531b04dd7c8a5f84214ff783280150531a67987189\",\"manufactureDate\":\"2020-12-19 00:00:00\",\"astNature#Name\":\"省（直辖市、自治区）公司\",\"portNum\":\"102\",\"maintGroup#Name\":\"变电运维二班\",\"maintGroup\":\"02DC9D994F3A79E4E053661EDF0AFC25\",\"manufacturer#Name\":\"南京灿能电力自动化股份有限公司\",\"detectDate\":\"2021-02-19 00:00:00\",\"city#Name\":\"国网张家界供电公司\",\"deployState#Name\":\"在运\",\"equipmentOwner#Name\":\"\",\"deviceLevel#Name\":\"A类\",\"cabinet\":\"4dcc03dbc58a5f84225130303b01514dcba0cd1be5\",\"gateway\":\"100.232.245.97\"}}],\"searchCount\":true,\"size\":2,\"total\":391}},\"status\":\"000000\"}";
		json = cJSON_Parse(json_buf);

		//json = cJSON_Parse(strDevCJson.toUtf8().constData());   //json格式序列化
		//cout << cJSON_Print(json) << endl;
		int total;
		if (NULL == json)
		{
			printf("cJSON_Parse error:%s\n", cJSON_GetErrorPtr());
			return APR_EBADF;
		}
		json_records = cJSON_GetObjectItem(json, "result");    //获取result
		json_records = cJSON_GetObjectItem(json_records, "0751002");    //获取0751002 
		json_value = cJSON_GetObjectItem(json_records, "total");    //获取 total
		if (json_value != NULL && json_value != NULL) {
			total = json_value->valueint;
		}

		cout << "dev total:" << total << endl;
		cJSON_Delete(json);
		//GetWebApiJson(1);
		/*if (strDevCJson == "") {
			cout << "select dev json error" << endl;
			return APR_EBADF;
		}*/
		//json = cJSON_Parse(strDevCJson.toUtf8().constData());   //json格式序列化
		json = cJSON_Parse(json_buf);

		json_records = cJSON_GetObjectItem(json, "result");    //获取result
		json_records = cJSON_GetObjectItem(json_records, "0751002");    //获取0751002 
		json_value = cJSON_GetObjectItem(json_records, "size");    //获取 size
		if (json_value != NULL && json_value != NULL) {
			count_cfg = json_value->valueint;
			cout << "count_cfg" << "--" << json_value->valueint << "--" << count_cfg << endl;
		}
		g_node->n_clients = count_cfg;
		g_node->clients = (ied_t**)apr_pcalloc(g_cfg_pool, count_cfg * sizeof(ied_t*));
		for (int k = 0; k < count_cfg; k++)
			g_node->clients[k] = (ied_t*)apr_pcalloc(g_cfg_pool, sizeof(ied_t));


		//多个设备循环
		int array_size = 0;
		json_records = cJSON_GetObjectItem(json_records, "records");    //获取records
		array_size = cJSON_GetArraySize(json_records);    //获取数组大小

		printf("array_size=%d\n", array_size);

		for (int i = 0; i < array_size; i++)
		{
			json_node = cJSON_GetArrayItem(json_records, i);//array
			json_node = cJSON_GetObjectItem(json_node, "resource");    //获取resource
			ied = g_node->clients[count_real++];
			ied_usr = (ied_usr_t*)apr_pcalloc(g_init_pool, sizeof(ied_usr_t));
			ied->usr_ext = ied_usr;
			if (ied_usr == NULL)
				return APR_ENOMEM;
			ied_usr->last_call_wavelist_time = sGetMsTime() + g_pt61850app->giTime * 1000;
			ied_usr->LD_info = (LD_info_t*)apr_pcalloc(g_init_pool, 500 * sizeof(LD_info_t));
			if (ied_usr->LD_info == NULL)
				return APR_ENOMEM;
			ied_usr->dev_flag = g_DevFlag;
			ied->chncount = 1;
			ied->channel = (channel_t*)apr_pcalloc(g_cfg_pool, sizeof(channel_t) * ied->chncount);
			ied->channel[0].ied = ied;
			ied->channel[0].status = STATUS_BREAKOFF;

			json_value = cJSON_GetObjectItem(json_node, "astId");    //获取 astId
			if (json_value != NULL && json_value != NULL) {
				apr_snprintf(ied_usr->terminal_id, sizeof(ied_usr->terminal_id), "%s", json_value->valuestring);//terminal_id
				cout << "terminal_id" << json_value->valuestring << "--" << ied_usr->terminal_id << endl;
			}


			json_value = cJSON_GetObjectItem(json_node, "equipCode");    //获取 equipCode
			if (json_value != NULL && json_value != NULL) {
				apr_snprintf(ied_usr->terminal_code, sizeof(ied_usr->terminal_code), "%s", "testcode");//terminal_code
				cout << "terminal_code" << json_value->valuestring << "--" << ied_usr->terminal_code << endl;
			}


			json_value = cJSON_GetObjectItem(json_node, "city#Name");    //获取 city#Name
			if (json_value != NULL && json_value != NULL) {
				apr_snprintf(ied_usr->org_name, sizeof(ied_usr->org_name), "%s", json_value->valuestring);//org_name
				cout << "org_name" << json_value->valuestring << "--" << ied_usr->org_name << endl;
			}


			json_value = cJSON_GetObjectItem(json_node, "maintOrg#Name");    //获取 maintOrg#Name
			if (json_value != NULL && json_value != NULL) {
				apr_snprintf(ied_usr->maint_name, sizeof(ied_usr->maint_name), "%s", json_value->valuestring);//maint_name
				cout << "maint_name" << json_value->valuestring << "--" << ied_usr->maint_name << endl;
			}


			json_value = cJSON_GetObjectItem(json_node, "station#Name");    //获取 station#Name
			if (json_value != NULL && json_value != NULL) {
				apr_snprintf(ied_usr->station_name, sizeof(ied_usr->station_name), "%s", json_value->valuestring);//station_name
				cout << "station_name" << json_value->valuestring << "--" << ied_usr->station_name << endl;
			}


			json_value = cJSON_GetObjectItem(json_node, "manufacturer#Name");    //获取 manufacturer#Name
			if (json_value != NULL && json_value != NULL) {
				apr_snprintf(ied_usr->tmnl_factory, sizeof(ied_usr->tmnl_factory), "%s", json_value->valuestring);//tmnl_factory
				cout << "tmnl_factory" << json_value->valuestring << "--" << ied_usr->tmnl_factory << endl;
			}


			json_value = cJSON_GetObjectItem(json_node, "deployState");    //获取 deployState
			if (json_value != NULL && json_value != NULL) {
				apr_snprintf(ied_usr->tmnl_status, sizeof(ied_usr->tmnl_status), "%s", json_value->valuestring);//tmnl_status
				cout << "tmnl_status" << json_value->valuestring << "--" << ied_usr->tmnl_status << endl;
			}


			//json_value = cJSON_GetObjectItem(json_node, "lastUpdateTime");    //获取 lastUpdateTime
			json_value = cJSON_GetObjectItem(json_node, "ctime");    //获取 ctime
			if (json_value != NULL && json_value != NULL) {
				//ied_usr->time = strtoll(json_value->valuestring, NULL, 10);//time
				ied_usr->time = charToLongLong(json_value->valuestring);//time
				cout << "time" << json_value->valuestring << "--" << ied_usr->time << endl;
			}


			json_value = cJSON_GetObjectItem(json_node, "model");    //获取 model
			if (json_value != NULL && json_value != NULL) {
				apr_snprintf(ied_usr->dev_type, sizeof(ied_usr->dev_type), "%s", json_value->valuestring);//DEV_Type
				cout << "dev_type:" << json_value->valuestring << "--" << ied_usr->dev_type << endl;
			}

			int t = 1;
			if (t) {
				//QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Key
				apr_snprintf(ied_usr->dev_key, sizeof(ied_usr->dev_key), "%s", "!qaz@wsx3edc4rfv");//DEV_Key
				cout << "dev_key:" << ied_usr->dev_key << endl;

				//QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Series
				apr_snprintf(ied_usr->dev_series, sizeof(ied_usr->dev_series), "%s", "Pqs&cn870299");//DEV_Series
				cout << "dev_series:" << ied_usr->dev_series << endl;
			}
			else {
				cout << "code" << ied_usr->terminal_code << endl;
				if (terminal_ext_map.contains(QString::fromUtf8(ied_usr->terminal_code))) {
					//terminal_ext* ext = terminal_ext_map.value(ied_usr->terminal_code);
					terminal_ext* ext = terminal_ext_map.value(QString::fromUtf8(ied_usr->terminal_code));
					//QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Key
					apr_snprintf(ied_usr->dev_key, sizeof(ied_usr->dev_key), "%s", ext->terminal_identify_code);//DEV_Key
					cout << "dev_key:" << ied_usr->dev_key << endl;

					//QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Series
					apr_snprintf(ied_usr->dev_series, sizeof(ied_usr->dev_series), "%s", ext->terminal_key);//DEV_Series
					cout << "dev_series:" << ied_usr->dev_series << endl;
				}
				else
				{

					//QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Key
					apr_snprintf(ied_usr->dev_key, sizeof(ied_usr->dev_key), "%s", "");//DEV_Key
					cout << "defalut dev_key:" << ied_usr->dev_key << endl;

					//QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Series
					apr_snprintf(ied_usr->dev_series, sizeof(ied_usr->dev_series), "%s", "");//DEV_Series
					cout << "defalut dev_series:" << ied_usr->dev_series << endl;
				}
			}

			ied_usr->dev_flag = 0;//DEV_DevFlag


			ied->channel[0].channel_type = CHANNEL_TYPE_IPV4;//channel
			cout << "channel_type:" << ied->channel[0].channel_type << endl;
			ied->channel[0].addr_str[LONGNAME - 1] = 0;//DEV_IP

			json_value = cJSON_GetObjectItem(json_node, "ipAddress");    //获取 ipAddress
			if (json_value != NULL && json_value != NULL) {
				if (i == 0) {
					ied->channel[0].addr = ntohl(inet_addr("192.168.1.212"));//DEV_IP
					strncpy(ied->channel[0].addr_str, "192.168.1.212", LONGNAME - 1);//DEV_IP
				}
				else {
					ied->channel[0].addr = ntohl(inet_addr(json_value->valuestring));//DEV_IP
					strncpy(ied->channel[0].addr_str, json_value->valuestring, LONGNAME - 1);//DEV_IP
				}
				cout << "addr:" << json_value->valuestring << "--" << ied->channel[0].addr << "--" << ied->channel[0].addr_str << endl;

			}


			json_value = cJSON_GetObjectItem(json_node, "portNum");    //获取 portNum
			if (json_value != NULL && json_value != NULL) {
				//ied->channel[0].port = atoi(json_value->valuestring);//DEV_PortID
				ied->channel[0].port = atoi("102");//DEV_PortID
				cout << "port:" << "--" << atoi(json_value->valuestring) << "--" << ied->channel[0].port << endl;
			}

			chnl_usr = (chnl_usr_t*)apr_pcalloc(g_init_pool, sizeof(chnl_usr_t));
			ied->channel[0].connect = chnl_usr;
			chnl_usr->chnl = &(ied->channel[0]);
			chnl_usr->chnl_id = 0;
			chnl_usr->m_state = CHANNEL_DISCONNECTED;
			chnl_usr->m_ClosedMsTime = NEXT_CONNECT_TIME * (-1);
			g_pt61850app->chnl_counts++;

		}
		cJSON_Delete(json);
		//list循环结束
		if (count_real < count_cfg)
			g_node->n_clients = count_real;
		if (count_cfg != count_real)
			return APR_EBADF;
		cout << "dev init create count:" << count_real;
		return APR_SUCCESS;
	}
	catch (const std::exception& e) {
		cout << "Exception caught: " << e.what() << endl;
		// 这里可以添加其他异常处理逻辑
	}

}
int parse_line_cfg_pg_test()
{
	ied_t* ied;
	ied_usr_t* ied_usr;
	int count_cfg = 0;
	int count_real = 0;
	LD_info_t line_info;

	try {
		OTLConnect();
		//int rtState = OTLState();
		std::string str2 = POSTGRES_SCHEMA;//schame analy
		std::string str1 = "select count(*) from \"";
		str1.append(str2);
		str1.append("\".\"");
		str1.append(POSTGRES_TABLEPREFIX);
		str1.append("pq_ledger_monitor\"");
		cout << "pg sq1 is:" << str1 << endl;
		//int rtState = OTLState();
		otl_stream i(1, // buffer size
			str1.c_str(),
			db //connect object
		);
		//create select stream

		int f2;
		while (!i.eof()) { //while not end-of-data
			i >> f2;
			//cout << "count=" << f2 << endl;
		}
		OTLDisconnect();
		count_cfg = f2;;//读数据库
		cout << "line_count=" << count_cfg << endl;

	}
	catch (otl_exception& e)
	{
		printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg);
		return e.code;
	}




	//读数据
	try {
		OTLConnect();
		std::string str2 = POSTGRES_SCHEMA;//schame analy
		std::string str1 = "select \"monitor_id\",\"terminal_code\",\"monitor_name\",\"logical_device_seq\",\"voltage_level\",\"terminal_connect\",\"update_time\" from \"";
		str1.append(str2);
		str1.append("\".\"");
		str1.append(POSTGRES_TABLEPREFIX);
		str1.append("pq_ledger_monitor\"");
		//cout << "pg sql2 is:" << str1 << endl;
		//int rtState = OTLState();
		otl_stream i(1, // buffer size
			str1.c_str(),
			//SELECT statement
			db //connect object
		);
		//create select stream

		char monitor_id[64];
		char terminal_code[64];
		char monitor_name[64];
		char logical_device_seq[64];
		char voltage_level[64];
		char terminal_connect[64];
		otl_datetime  timestamp;
		int cpuno_count = 1;
		while (!i.eof()) { //while not end-of-data
			i >> monitor_id >> terminal_code >> monitor_name >> logical_device_seq >> voltage_level >> terminal_connect >> timestamp;
			//cout << "monitor_id=" << monitor_id << " terminal_code=" << terminal_code << " monitor_name=" << monitor_name << " logical_device_seq=" << logical_device_seq;
			//cout << " voltage_level=" << voltage_level << " terminal_connect=" << terminal_connect;
			//cout << " timestamp: " << timestamp.year << "-" << timestamp.month << "-" << timestamp.day << " " << timestamp.hour << ":" << timestamp.minute << ":" << timestamp.second << endl;

			count_real++;
			memset(&line_info, 0, sizeof(line_info));
			line_info.line_id = count_real;
			//cout << "line_id:" << line_info.line_id << endl;

			strcpy(line_info.mp_id, monitor_id);
			//cout << "mp_id:" << line_info.mp_id << endl;
			strcpy(line_info.terminal_code, "testcode");
			//cout << "terminal_code:" << line_info.terminal_code << endl;
			if (isCharPtrEmpty(logical_device_seq)) {
				line_info.cpuno = 1;
				//cout << "logical_device_seq:is null~"<< line_info.cpuno << endl;
			}
			else {
				line_info.cpuno = std::atoi(logical_device_seq);
				//cout << "logical_device_seq:"<< logical_device_seq << endl;
			}
			//cout << "cpuno:" << line_info.cpuno << endl;
			strcpy(line_info.voltage_level, voltage_level);
			//cout << "voltage_level:" << line_info.voltage_level << endl;
			strcpy(line_info.v_wiring_type, terminal_connect);
			//cout << "v_wiring_type:" << line_info.v_wiring_type << endl;

			//// 构造struct tm对象
			struct tm timeinfo;
			timeinfo.tm_year = timestamp.year - 1900; // 年份需要减去1900
			timeinfo.tm_mon = timestamp.month - 1; // 月份需要减去1
			timeinfo.tm_mday = timestamp.day;
			timeinfo.tm_hour = timestamp.hour;
			timeinfo.tm_min = timestamp.minute;
			timeinfo.tm_sec = timestamp.second;

			time_t time = std::mktime(&timeinfo);
			line_info.time = static_cast<long long>(time);
			//cout << "time:" << line_info.time << endl;

			strcpy(line_info.name, monitor_name);
			//cout << "name:" << line_info.name << endl;

			ied = find_ied_from_dev_code("testcode");

			if (ied && ied->usr_ext && line_info.cpuno) {
				char str[256];
				byte_t cpuno = cpuno_count;
				//cout << "cpuno:" << line_info.cpuno << endl;
				//cout << "byte_t cpuno:" << cpuno-1 << endl;
				ied_usr = (ied_usr_t*)ied->usr_ext;
				ied_usr->LD_info[cpuno - 1] = line_info;
				ied_usr->LD_info[cpuno - 1].ied = ied;
				apr_snprintf(str, sizeof(str), "PQMonitorPQM%d", cpuno);
				ied_usr->LD_info[cpuno - 1].LD_name = apr_pstrdup(g_init_pool, str);
				ied_usr->LD_info[cpuno - 1].ht_fcd = apr_hash_make(g_init_pool);
				ied_usr->LD_info[cpuno - 1].ht_full_fcda = apr_hash_make(g_init_pool);
				ied_usr->LD_info[cpuno - 1].rptcount = 0;
				//cout << "rptcount:" << ied_usr->LD_info[cpuno - 1].rptcount << endl;

				if (cpuno > ied->cpucount) {
					int c = cpuno;

					ied->cpucount = cpuno;
					cout << "byte_t cpucount:" << ied->cpucount + 1 << endl;
				}

			}
			cpuno_count++;
			if (cpuno_count > 150) {
				break;
			}
		}
		OTLDisconnect();
	}
	catch (otl_exception& e)
	{
		printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg);
		return e.code;
	}


	if (count_cfg != count_real)
		return APR_EBADF;
	return APR_SUCCESS;
}
void dev_account_add() {

}
void dev_account_delete() {

}
void dev_account_update() {

}
void line_account_add() {

}
void line_account_delete(int update_flag) {

}
void line_account_update(int update_flag) {

}
int create_temp_device_cfg_json(QMap<QString, ied_t*>& dev_map)
{
	qDebug() << "parse_device_cfg_json" << endl;
	if (FRONT_INST == 0 || FRONT_IP[0] == '\0') {
		MULTIPLE_NODE_FLAG = 0;
		cout << "set MULTIPLE_NODE_FLAG:0,because do not have FRONT_INST or FRONT_IP" << endl;

	}
	char front_type[2];
	int mp_num;

	if (MULTIPLE_NODE_FLAG) {
		//std::string str2 = POSTGRES_SCHEMA;//schame analy
		std::string str1 = "select count(*) from \"";
		str1.append(POSTGRES_SCHEMA);
		str1.append("\".\"");
		str1.append(POSTGRES_TABLEPREFIX);
		str1.append("meas_pq_front_list_tr");
		str1.append("\" where \"front_ip\" = '");
		str1.append(FRONT_IP);
		str1.append("' and \"front_inst\" = ");
		std::string str3 = QString::number(FRONT_INST).toStdString();
		str1.append(str3);
		str1.append(";");
		try {
			OTLConnect();
			otl_stream i1(1, // buffer size
				str1.c_str(),
				//SELECT statement
				db //connect object
			);
			//create select stream


			int front_count;
			while (!i1.eof()) { //while not end-of-data
				i1 >> front_count;
				//cout << "count=" << f2 << endl;
			}
			cout << "count=" << front_count << endl;
			OTLDisconnect();
		}
		catch (otl_exception& e)
		{
			printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg);
			return e.code;
		}
		QString selectFrontSql;
		selectFrontSql.append(QString("select \"front_type\",\"mp_num\" from \"%1\".\"%2meas_pq_front_list_tr\" ").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX));
		selectFrontSql.append(QString("where \"front_ip\" = '0.0.0.0' and \"front_inst\"=0"));
		cout << selectFrontSql.toStdString().c_str() << endl;
		try {
			OTLConnect();
			otl_stream i2(1, // buffer size
				selectFrontSql.toStdString().c_str(),
				//SELECT statement
				db //connect object
			);
			//create select stream


			while (!i2.eof()) { //while not end-of-data
				i2 >> front_type >> mp_num;
				break;
				//cout << "count=" << f2 << endl;
			}
			OTLDisconnect();
		}
		catch (otl_exception& e)
		{
			printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg);
			return e.code;
		}

	}
	cout << "mp_num:" << mp_num << " FRONT_INST:" << FRONT_INST << endl;

	ied_t* ied;
	ied_usr_t* ied_usr;
	chnl_usr_t* chnl_usr;
	int count_cfg = 0;
	int count_real = 0;

	//读取数据
	//string* json_buf;
	cJSON* json = NULL;
	cJSON* json_value = NULL;

	cJSON* json_records = NULL;
	cJSON* json_node = NULL;

	int dev_num = 0;
	QMap<QString, terminal_ext*> terminal_ext_map;
	read_terminal_ext_pg(&terminal_ext_map);
	try {
		int total;
		GetWebApiJson(1, 1, CITY_FLAG);
		if (strDevCJson == "") {
			cout << "json select total error" << endl;
			return APR_EBADF;
		}
		//char json_buf[] = "{\"errors\":\"成功\",\"message\":\"成功\",\"result\":{\"0751002\":{\"current\":1,\"orders\":[],\"pages\":391,\"records\":[{\"assets\":[],\"distribution\":1,\"id\":\"ff8080817efe6c21017f1064ab7c0c7e\",\"modelId\":\"0751002Z\",\"resource\":{\"deviceKind\":\"0751002\",\"maintOrg\":\"02DC9D994F2879E4E053661EDF0AFC25\",\"signalInputForm\":\"02\",\"source#Name\":\"设备增加-基本建设\",\"source\":\"01\",\"currsigInputChanqutity\":\"1\",\"astOrg#Name\":\"国网湖南省电力公司\",\"astOrg\":\"02DC9D994CE579E4E053661EDF0AFC25\",\"cabinetType\":\"05\",\"ctime\":\"2022-02-19 00:00:00\",\"model\":\"PQS-883\",\"station#Name\":\"110kV宝塔变电站\",\"equipmentOwner\":\"E94A0732B2FB5AA1E0430901E80A21E9\",\"manufactureNum\":\"202596\",\"ipAddress\":\"10.232.245.101\",\"equipCode\":\"16M00000128569231\",\"subnetMask\":\"255.255.255.224\",\"astId\":\"ff8080817efe6c21017f1064ab7c0c7e\",\"macAddress\":\"00：B7：8D：00：DC：23\",\"astNum\":\"200102118916\",\"signalInputForm#Name\":\"数字信号\",\"maintOrg#Name\":\"张家界供电公司检修公司\",\"name\":\"110kV 珍宝线504电能质量监测装置\",\"deviceLevel\":\"01\",\"projectNum\":\"GGXM20220219BT\",\"projectName\":\"电能质量监测装置\",\"operateDate\":\"2021-11-19 00:00:00\",\"deployState\":\"20\",\"hardDiskCapacity\":\"64\",\"city\":\"02DC9D994EED79E4E053661EDF0AFC25\",\"timeSynchronization\":\"02\",\"astNature\":\"03\",\"manufacturer\":\"041696\",\"astOrgName\":\"国网湖南省电力公司\",\"voltsigInputChanqutity\":\"1\",\"cabinetType#Name\":\"紧凑型金属封闭式\",\"runDevName\":\"504\",\"devPowerVoltage\":\"220\",\"station\":\"531b04dd7c8a5f84214ff783280150531a67987189\",\"manufactureDate\":\"2020-12-19 00:00:00\",\"astNature#Name\":\"省（直辖市、自治区）公司\",\"portNum\":\"102\",\"maintGroup#Name\":\"变电运维二班\",\"maintGroup\":\"02DC9D994F3A79E4E053661EDF0AFC25\",\"manufacturer#Name\":\"南京灿能电力自动化股份有限公司\",\"detectDate\":\"2021-02-19 00:00:00\",\"city#Name\":\"国网张家界供电公司\",\"deployState#Name\":\"在运\",\"equipmentOwner#Name\":\"\",\"deviceLevel#Name\":\"A类\",\"cabinet\":\"4dcc03dbc58a5f84225130303b01514dcba0cd1be5\",\"gateway\":\"10.232.245.97\"}}],\"searchCount\":true,\"size\":1,\"total\":391}},\"status\":\"000000\"}";
	/*	char json_buf[] = "{\"errors\":\"成功\",\"message\":\"成功\",\"result\":{\"0751002\":{\"current\":1,\"orders\":[],\"pages\":391,\"records\":[{\"assets\":[],\"distribution\":1,\"id\":\"ff8080817efe6c21017f1064ab7c0c7e\",\"modelId\":\"0751002Z\",\"resource\":{\"deviceKind\":\"0751002\",\"maintOrg\":\"02DC9D994F2879E4E053661EDF0AFC25\",\"signalInputForm\":\"02\",\"source#Name\":\"设备增加-基本建设\",\"source\":\"01\",\"currsigInputChanqutity\":\"1\",\"astOrg#Name\":\"国网湖南省电力公司\",\"astOrg\":\"02DC9D994CE579E4E053661EDF0AFC25\",\"cabinetType\":\"05\",\"ctime\":\"2022-02-19 00:00:00\",\"model\":\"PQS-883\",\"station#Name\":\"110kV宝塔变电站\",\"equipmentOwner\":\"E94A0732B2FB5AA1E0430901E80A21E9\",\"manufactureNum\":\"202596\",\"ipAddress\":\"10.232.245.101\",\"equipCode\":\"16M00000128569231\",\"subnetMask\":\"255.255.255.224\",\"astId\":\"ff8080817efe6c21017f1064ab7c0c7e\",\"macAddress\":\"00：B7：8D：00：DC：23\",\"astNum\":\"200102118916\",\"signalInputForm#Name\":\"数字信号\",\"maintOrg#Name\":\"张家界供电公司检修公司\",\"name\":\"110kV 珍宝线504电能质量监测装置\",\"deviceLevel\":\"01\",\"projectNum\":\"GGXM20220219BT\",\"projectName\":\"电能质量监测装置\",\"operateDate\":\"2021-11-19 00:00:00\",\"deployState\":\"20\",\"hardDiskCapacity\":\"64\",\"city\":\"02DC9D994EED79E4E053661EDF0AFC25\",\"timeSynchronization\":\"02\",\"astNature\":\"03\",\"manufacturer\":\"041696\",\"astOrgName\":\"国网湖南省电力公司\",\"voltsigInputChanqutity\":\"1\",\"cabinetType#Name\":\"紧凑型金属封闭式\",\"runDevName\":\"504\",\"devPowerVoltage\":\"220\",\"station\":\"531b04dd7c8a5f84214ff783280150531a67987189\",\"manufactureDate\":\"2020-12-19 00:00:00\",\"astNature#Name\":\"省（直辖市、自治区）公司\",\"portNum\":\"102\",\"maintGroup#Name\":\"变电运维二班\",\"maintGroup\":\"02DC9D994F3A79E4E053661EDF0AFC25\",\"manufacturer#Name\":\"南京灿能电力自动化股份有限公司\",\"detectDate\":\"2021-02-19 00:00:00\",\"city#Name\":\"国网张家界供电公司\",\"deployState#Name\":\"在运\",\"equipmentOwner#Name\":\"\",\"deviceLevel#Name\":\"A类\",\"cabinet\":\"4dcc03dbc58a5f84225130303b01514dcba0cd1be5\",\"gateway\":\"10.232.245.97\"}},{\"assets\":[],\"distribution\":1,\"id\":\"af8080817efe6c21017f1064ab7c0c7e\",\"modelId\":\"0751002Z\",\"resource\":{\"deviceKind\":\"0751002\",\"maintOrg\":\"02DC9D994F2879E4E053661EDF0AFC25\",\"signalInputForm\":\"02\",\"source#Name\":\"设备增加-基本建设\",\"source\":\"01\",\"currsigInputChanqutity\":\"1\",\"astOrg#Name\":\"国网湖南省电力公司\",\"astOrg\":\"02DC9D994CE579E4E053661EDF0AFC25\",\"cabinetType\":\"05\",\"ctime\":\"2022-02-19 00:00:00\",\"model\":\"PQS-883\",\"station#Name\":\"110kV宝塔变电站\",\"equipmentOwner\":\"E94A0732B2FB5AA1E0430901E80A21E9\",\"manufactureNum\":\"202596\",\"ipAddress\":\"10.232.245.101\",\"equipCode\":\"16M00002128569231\",\"subnetMask\":\"255.255.255.224\",\"astId\":\"af8080817efe6c21017f1064ab7c0c7e\",\"macAddress\":\"00：B7：8D：00：DC：23\",\"astNum\":\"200102118916\",\"signalInputForm#Name\":\"数字信号\",\"maintOrg#Name\":\"张家界供电公司检修公司\",\"name\":\"110kV 珍宝线504电能质量监测装置\",\"deviceLevel\":\"01\",\"projectNum\":\"GGXM20220219BT\",\"projectName\":\"电能质量监测装置\",\"operateDate\":\"2021-11-19 00:00:00\",\"deployState\":\"20\",\"hardDiskCapacity\":\"64\",\"city\":\"02DC9D994EED79E4E053661EDF0AFC25\",\"timeSynchronization\":\"02\",\"astNature\":\"03\",\"manufacturer\":\"041696\",\"astOrgName\":\"国网湖南省电力公司\",\"voltsigInputChanqutity\":\"1\",\"cabinetType#Name\":\"紧凑型金属封闭式\",\"runDevName\":\"504\",\"devPowerVoltage\":\"220\",\"station\":\"531b04dd7c8a5f84214ff783280150531a67987189\",\"manufactureDate\":\"2020-12-19 00:00:00\",\"astNature#Name\":\"省（直辖市、自治区）公司\",\"portNum\":\"102\",\"maintGroup#Name\":\"变电运维二班\",\"maintGroup\":\"02DC9D994F3A79E4E053661EDF0AFC25\",\"manufacturer#Name\":\"南京灿能电力自动化股份有限公司\",\"detectDate\":\"2021-02-19 00:00:00\",\"city#Name\":\"国网张家界供电公司\",\"deployState#Name\":\"在运\",\"equipmentOwner#Name\":\"\",\"deviceLevel#Name\":\"A类\",\"cabinet\":\"4dcc03dbc58a5f84225130303b01514dcba0cd1be5\",\"gateway\":\"100.232.245.97\"}}],\"searchCount\":true,\"size\":2,\"total\":391}},\"status\":\"000000\"}";
		json = cJSON_Parse(json_buf);*/
		//char json_buf[] = "{\"errors\":\"成功\",\"message\":\"成功\",\"result\":{\"0751002\":{\"current\":1,\"orders\":[],\"pages\":391,\"records\":[{\"assets\":[],\"distribution\":1,\"id\":\"ff8080817efe6c21017f1064ab7c0c7e\",\"modelId\":\"0751002Z\",\"resource\":{\"deviceKind\":\"0751002\",\"maintOrg\":\"02DC9D994F2879E4E053661EDF0AFC25\",\"signalInputForm\":\"02\",\"source#Name\":\"设备增加-基本建设\",\"source\":\"01\",\"currsigInputChanqutity\":\"1\",\"astOrg#Name\":\"国网湖南省电力公司\",\"astOrg\":\"02DC9D994CE579E4E053661EDF0AFC25\",\"cabinetType\":\"05\",\"ctime\":\"2022-02-19 00:00:00\",\"model\":\"E8300\",\"station#Name\":\"110kV宝塔变电站\",\"equipmentOwner\":\"E94A0732B2FB5AA1E0430901E80A21E9\",\"manufactureNum\":\"202596\",\"ipAddress\":\"10.161.208.227\",\"equipCode\":\"22M00000299758903\",\"subnetMask\":\"255.255.255.224\",\"astId\":\"ff8080817efe6c21017f1064ab7c0c7e\",\"macAddress\":\"00：B7：8D：00：DC：23\",\"astNum\":\"200102118916\",\"signalInputForm#Name\":\"数字信号\",\"maintOrg#Name\":\"张家界供电公司检修公司\",\"name\":\"110kV 珍宝线504电能质量监测装置\",\"deviceLevel\":\"01\",\"projectNum\":\"GGXM20220219BT\",\"projectName\":\"电能质量监测装置\",\"operateDate\":\"2021-11-19 00:00:00\",\"deployState\":\"20\",\"hardDiskCapacity\":\"64\",\"city\":\"02DC9D994EED79E4E053661EDF0AFC25\",\"timeSynchronization\":\"02\",\"astNature\":\"03\",\"manufacturer\":\"041696\",\"astOrgName\":\"国网湖南省电力公司\",\"voltsigInputChanqutity\":\"1\",\"cabinetType#Name\":\"紧凑型金属封闭式\",\"runDevName\":\"504\",\"devPowerVoltage\":\"220\",\"station\":\"531b04dd7c8a5f84214ff783280150531a67987189\",\"manufactureDate\":\"2020-12-19 00:00:00\",\"astNature#Name\":\"省（直辖市、自治区）公司\",\"portNum\":\"20102\",\"maintGroup#Name\":\"变电运维二班\",\"maintGroup\":\"02DC9D994F3A79E4E053661EDF0AFC25\",\"manufacturer#Name\":\"南京灿能电力自动化股份有限公司\",\"detectDate\":\"2021-02-19 00:00:00\",\"city#Name\":\"国网张家界供电公司\",\"deployState#Name\":\"在运\",\"equipmentOwner#Name\":\"\",\"deviceLevel#Name\":\"A类\",\"cabinet\":\"4dcc03dbc58a5f84225130303b01514dcba0cd1be5\",\"gateway\":\"10.232.245.97\"}},{\"assets\":[],\"distribution\":1,\"id\":\"af8080817efe6c21017f1064ab7c0c7e\",\"modelId\":\"0751002Z\",\"resource\":{\"deviceKind\":\"0751002\",\"maintOrg\":\"02DC9D994F2879E4E053661EDF0AFC25\",\"signalInputForm\":\"02\",\"source#Name\":\"设备增加-基本建设\",\"source\":\"01\",\"currsigInputChanqutity\":\"1\",\"astOrg#Name\":\"国网湖南省电力公司\",\"astOrg\":\"02DC9D994CE579E4E053661EDF0AFC25\",\"cabinetType\":\"05\",\"ctime\":\"2022-02-19 00:00:00\",\"model\":\"E8300\",\"station#Name\":\"110kV宝塔变电站\",\"equipmentOwner\":\"E94A0732B2FB5AA1E0430901E80A21E9\",\"manufactureNum\":\"202596\",\"ipAddress\":\"10.161.208.237\",\"equipCode\":\"22M00000299800679\",\"subnetMask\":\"255.255.255.224\",\"astId\":\"af8080817efe6c21017f1064ab7c0c7e\",\"macAddress\":\"00：B7：8D：00：DC：23\",\"astNum\":\"200102118916\",\"signalInputForm#Name\":\"数字信号\",\"maintOrg#Name\":\"张家界供电公司检修公司\",\"name\":\"110kV 珍宝线504电能质量监测装置\",\"deviceLevel\":\"01\",\"projectNum\":\"GGXM20220219BT\",\"projectName\":\"电能质量监测装置\",\"operateDate\":\"2021-11-19 00:00:00\",\"deployState\":\"20\",\"hardDiskCapacity\":\"64\",\"city\":\"02DC9D994EED79E4E053661EDF0AFC25\",\"timeSynchronization\":\"02\",\"astNature\":\"03\",\"manufacturer\":\"041696\",\"astOrgName\":\"国网湖南省电力公司\",\"voltsigInputChanqutity\":\"1\",\"cabinetType#Name\":\"紧凑型金属封闭式\",\"runDevName\":\"504\",\"devPowerVoltage\":\"220\",\"station\":\"531b04dd7c8a5f84214ff783280150531a67987189\",\"manufactureDate\":\"2020-12-19 00:00:00\",\"astNature#Name\":\"省（直辖市、自治区）公司\",\"portNum\":\"10022\",\"maintGroup#Name\":\"变电运维二班\",\"maintGroup\":\"02DC9D994F3A79E4E053661EDF0AFC25\",\"manufacturer#Name\":\"南京灿能电力自动化股份有限公司\",\"detectDate\":\"2021-02-19 00:00:00\",\"city#Name\":\"国网张家界供电公司\",\"deployState#Name\":\"在运\",\"equipmentOwner#Name\":\"\",\"deviceLevel#Name\":\"A类\",\"cabinet\":\"4dcc03dbc58a5f84225130303b01514dcba0cd1be5\",\"gateway\":\"100.232.245.97\"}}],\"searchCount\":true,\"size\":2,\"total\":391}},\"status\":\"000000\"}";
		//json = cJSON_Parse(json_buf);

		//char json_buf[] = "{\"errors\":\"成功\",\"message\":\"成功\",\"result\":{\"0751002\":{\"current\":1,\"orders\":[],\"pages\":391,\"records\":[{\"assets\":[],\"distribution\":1,\"id\":\"ff8080817efe6c21017f1064ab7c0c7e\",\"modelId\":\"0751002Z\",\"resource\":{\"deviceKind\":\"0751002\",\"maintOrg\":\"02DC9D994F2879E4E053661EDF0AFC25\",\"cabinet\":\"4dcc03dbc58a5f84225130303b01514dcba0cd1be5\",\"gateway\":\"10.232.245.97\"}}],\"searchCount\":true,\"size\":1,\"total\":391}},\"status\":\"000000\"}";

		json = cJSON_Parse(strDevCJson.toUtf8().constData());   //json格式序列化
		//cout << cJSON_Print(json) << endl;
		if (NULL == json)
		{
			printf("cJSON_Parse error:%s\n", cJSON_GetErrorPtr());
			return APR_EBADF;
		}
		json_records = cJSON_GetObjectItem(json, "result");    //获取result
		json_records = cJSON_GetObjectItem(json_records, "0751002");    //获取0751002 
		json_value = cJSON_GetObjectItem(json_records, "total");    //获取 total
		if (json_value != NULL) {
			total = json_value->valueint;
		}

		cJSON_Delete(json);
		if (MULTIPLE_NODE_FLAG && g_front_seg_num == 0) {
			if (strcmp(front_type, "01") == 0) {
				GetWebApiJson(mp_num, FRONT_INST, CITY_FLAG);
			}
			else
			{
				GetWebApiJson(mp_num, FRONT_INST, CITY_FLAG);
			}
		}
		else if (MULTIPLE_NODE_FLAG && g_front_seg_num != 0) {
			int front_num = (total / g_front_seg_num) + 1;
			GetWebApiJson(front_num, FRONT_INST, CITY_FLAG);

		}
		else {
			/*	cout << "dev total:" << total << endl;
				if (total > 300) {
					total = 300;
					cout << "update dev total:" << total << endl;

				}*/
			GetWebApiJson(total, 1, CITY_FLAG);
		}


		if (strDevCJson == "") {
			cout << "select dev json error" << endl;
			return APR_EBADF;
		}
		json = cJSON_Parse(strDevCJson.toUtf8().constData());   //json格式序列化

		//json = cJSON_Parse(json_buf);

		json_records = cJSON_GetObjectItem(json, "result");    //获取result
		json_records = cJSON_GetObjectItem(json_records, "0751002");    //获取0751002 
		json_value = cJSON_GetObjectItem(json_records, "size");    //获取 size

		//多个设备循环
		int array_size = 0;
		json_records = cJSON_GetObjectItem(json_records, "records");    //获取records
		array_size = cJSON_GetArraySize(json_records);    //获取数组大小

		/*count_cfg = array_size;
		cout << "count_cfg" << "--" << count_cfg << endl;
		g_node->n_clients = count_cfg;
		g_node->clients = (ied_t**)apr_pcalloc(g_cfg_pool, count_cfg * sizeof(ied_t*));
		for (int k = 0; k < count_cfg; k++)
			g_node->clients[k] = (ied_t*)apr_pcalloc(g_cfg_pool, sizeof(ied_t));*/


		printf("array_size=%d\n", array_size);

		for (int i = 0; i < array_size; i++)
		{
			json_node = cJSON_GetArrayItem(json_records, i);//array
			json_node = cJSON_GetObjectItem(json_node, "resource");    //获取resource
			ied = (ied_t*)apr_pcalloc(g_temp_dev_pool, sizeof(ied_t));
			count_real++;
			ied_usr = (ied_usr_t*)apr_pcalloc(g_temp_dev_pool, sizeof(ied_usr_t));
			ied->usr_ext = ied_usr;
			if (ied_usr == NULL)
				return APR_ENOMEM;
			ied_usr->last_call_wavelist_time = sGetMsTime() + g_pt61850app->giTime * 1000;
			ied_usr->LD_info = (LD_info_t*)apr_pcalloc(g_temp_dev_pool, MAX_CPUNO * sizeof(LD_info_t));
			if (ied_usr->LD_info == NULL)
				return APR_ENOMEM;
			ied_usr->dev_flag = g_DevFlag;
			ied->chncount = 1;
			ied->channel = (channel_t*)apr_pcalloc(g_temp_dev_pool, sizeof(channel_t) * ied->chncount);
			ied->channel[0].ied = ied;
			ied->channel[0].status = STATUS_BREAKOFF;

			json_value = cJSON_GetObjectItem(json_node, "astId");    //获取 astId
			if (json_value != NULL && json_value->string != NULL) {
				apr_snprintf(ied_usr->terminal_id, sizeof(ied_usr->terminal_id), "%s", json_value->valuestring);//terminal_id
				cout << "terminal_id:" << json_value->valuestring << "--" << ied_usr->terminal_id << endl;
			}
			else {
				apr_snprintf(ied_usr->terminal_id, sizeof(ied_usr->terminal_id), "%s", "");//terminal_id
				cout << "default terminal_id:" << ied_usr->terminal_id << endl;
			}


			json_value = cJSON_GetObjectItem(json_node, "equipCode");    //获取 equipCode
			if (json_value != NULL && json_value->string != NULL) {
				apr_snprintf(ied_usr->terminal_code, sizeof(ied_usr->terminal_code), "%s", json_value->valuestring);//terminal_code
				cout << "terminal_code:" << json_value->valuestring << "--" << ied_usr->terminal_code << endl;
			}
			else {
				apr_snprintf(ied_usr->terminal_code, sizeof(ied_usr->terminal_code), "%s", "");//terminal_code
				cout << "default terminal_code:" << ied_usr->terminal_code << endl;
			}


			json_value = cJSON_GetObjectItem(json_node, "city#Name");    //获取 city#Name
			if (json_value != NULL && json_value->string != NULL) {
				apr_snprintf(ied_usr->org_name, sizeof(ied_usr->org_name), "%s", json_value->valuestring);//org_name
				cout << "org_name:" << json_value->valuestring << "--" << ied_usr->org_name << endl;
			}


			json_value = cJSON_GetObjectItem(json_node, "maintOrg#Name");    //获取 maintOrg#Name
			if (json_value != NULL && json_value->string != NULL) {
				apr_snprintf(ied_usr->maint_name, sizeof(ied_usr->maint_name), "%s", json_value->valuestring);//maint_name
				cout << "maint_name:" << json_value->valuestring << "--" << ied_usr->maint_name << endl;
			}


			json_value = cJSON_GetObjectItem(json_node, "station#Name");    //获取 station#Name
			if (json_value != NULL && json_value->string != NULL) {
				apr_snprintf(ied_usr->station_name, sizeof(ied_usr->station_name), "%s", json_value->valuestring);//station_name
				cout << "station_name:" << json_value->valuestring << "--" << ied_usr->station_name << endl;
			}


			json_value = cJSON_GetObjectItem(json_node, "manufacturer#Name");    //获取 manufacturer#Name
			if (json_value != NULL && json_value->string != NULL) {
				apr_snprintf(ied_usr->tmnl_factory, sizeof(ied_usr->tmnl_factory), "%s", json_value->valuestring);//tmnl_factory
				cout << "tmnl_factory:" << json_value->valuestring << "--" << ied_usr->tmnl_factory << endl;
			}


			json_value = cJSON_GetObjectItem(json_node, "deployState");    //获取 deployState
			if (json_value != NULL && json_value->string != NULL) {
				apr_snprintf(ied_usr->tmnl_status, sizeof(ied_usr->tmnl_status), "%s", json_value->valuestring);//tmnl_status
				cout << "tmnl_status:" << json_value->valuestring << "--" << ied_usr->tmnl_status << endl;
			}
			else {
				apr_snprintf(ied_usr->tmnl_status, sizeof(ied_usr->tmnl_status), "%s", "10");//tmnl_status
				cout << "default tmnl_status:" << ied_usr->tmnl_status << endl;

			}


			//json_value = cJSON_GetObjectItem(json_node, "lastUpdateTime");    //获取 lastUpdateTime
			json_value = cJSON_GetObjectItem(json_node, "ctime");    //获取 ctime
			if (json_value != NULL && json_value->string != NULL) {
				//ied_usr->time = strtoll(json_value->valuestring, NULL, 10);//time
				ied_usr->time = charToLongLong(json_value->valuestring);//time
				cout << "time:" << ied_usr->time << endl;
			}


			json_value = cJSON_GetObjectItem(json_node, "model");    //获取 model
			if (json_value != NULL && json_value->string != NULL) {
				apr_snprintf(ied_usr->dev_type, sizeof(ied_usr->dev_type), "%s", json_value->valuestring);//DEV_Type
				cout << "dev_type:" << json_value->valuestring << "--" << ied_usr->dev_type << endl;
			}
			else {
				apr_snprintf(ied_usr->dev_type, sizeof(ied_usr->dev_type), "%s", "no-type");//DEV_Type
				cout << "default dev_type:" << ied_usr->dev_type << endl;
			}

			int t = 1;
			if (t) {
				//QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Key
				apr_snprintf(ied_usr->dev_key, sizeof(ied_usr->dev_key), "%s", "!qaz@wsx3edc4rfv");//DEV_Key
				cout << "dev_key:" << ied_usr->dev_key << endl;

				//QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Series
				apr_snprintf(ied_usr->dev_series, sizeof(ied_usr->dev_series), "%s", "Pqs&cn870299");//DEV_Series
				cout << "dev_series:" << ied_usr->dev_series << endl;
			}
			else {
				cout << "code:" << ied_usr->terminal_code << endl;
				if (terminal_ext_map.contains(QString::fromUtf8(ied_usr->terminal_code))) {
					//terminal_ext* ext = terminal_ext_map.value(ied_usr->terminal_code);
					terminal_ext* ext = terminal_ext_map.value(QString::fromUtf8(ied_usr->terminal_code));
					//QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Key
					apr_snprintf(ied_usr->dev_key, sizeof(ied_usr->dev_key), "%s", ext->terminal_key);//DEV_Key
					cout << "dev_key:" << ied_usr->dev_key << endl;

					//QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Series
					apr_snprintf(ied_usr->dev_series, sizeof(ied_usr->dev_series), "%s", ext->terminal_identify_code);//DEV_Series
					cout << "dev_series:" << ied_usr->dev_series << endl;
				}
				else
				{

					//QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Key
					apr_snprintf(ied_usr->dev_key, sizeof(ied_usr->dev_key), "%s", "");//DEV_Key
					cout << "defalut dev_key:" << ied_usr->dev_key << endl;

					//QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Series
					apr_snprintf(ied_usr->dev_series, sizeof(ied_usr->dev_series), "%s", "");//DEV_Series
					cout << "defalut dev_series:" << ied_usr->dev_series << endl;
				}
			}

			ied_usr->dev_flag = 0;//DEV_DevFlag


			ied->channel[0].channel_type = CHANNEL_TYPE_IPV4;//channel
			cout << "channel_type:" << ied->channel[0].channel_type << endl;
			ied->channel[0].addr_str[LONGNAME - 1] = 0;//DEV_IP

			json_value = cJSON_GetObjectItem(json_node, "ipAddress");    //获取 ipAddress
			if (json_value != NULL && json_value->string != NULL) {
				if (t && i == 0) {
					ied->channel[0].addr = ntohl(inet_addr("172.40.251.35"));//DEV_IP
					strncpy(ied->channel[0].addr_str, "172.40.251.35", LONGNAME - 1);//DEV_IP
				}
				else {
					ied->channel[0].addr = ntohl(inet_addr(json_value->valuestring));//DEV_IP
					strncpy(ied->channel[0].addr_str, json_value->valuestring, LONGNAME - 1);//DEV_IP
				}
				cout << "addr:" << json_value->valuestring << "--" << ied->channel[0].addr << "--" << ied->channel[0].addr_str << endl;

			}
			else {
				ied->channel[0].addr = ntohl(inet_addr("0.0.0.1"));//DEV_IP
				strncpy(ied->channel[0].addr_str, "0.0.0.1", LONGNAME - 1);//DEV_IP
				//}
				cout << "default addr:" << ied->channel[0].addr_str << endl;

			}


			json_value = cJSON_GetObjectItem(json_node, "portNum");    //获取 portNum
			if (json_value != NULL && json_value->string != NULL) {
				ied->channel[0].port = atoi(json_value->valuestring);//DEV_PortID
				if (t) {
					ied->channel[0].port = atoi("102");//DEV_PortID
				}
				cout << "port:" << "--" << atoi(json_value->valuestring) << "--" << ied->channel[0].port << endl;
			}
			else {
				ied->channel[0].port = 0;//DEV_PortID
				if (t) {
					ied->channel[0].port = atoi("102");//DEV_PortID
				}
				cout << "default port:" << ied->channel[0].port << endl;

			}
			dev_map.insert(QString::fromUtf8(ied_usr->terminal_code), ied);

		}
		cJSON_Delete(json);
		//list循环结束


		cout << "temp dev qmap init create count:" << count_real;
		return APR_SUCCESS;
	}
	catch (const std::exception& e) {
		cout << "Exception caught: " << e.what() << endl;
		// 这里可以添加其他异常处理逻辑
	}

}
int create_temp_line_cfg_pg(QMap<QString, ied_t*>& dev_map)
{

	ied_t* ied;
	ied_usr_t* ied_usr;
	int count_cfg = 0;
	int count_real = 0;
	LD_info_t line_info;

	try {
		//int rtState = OTLState();
		std::string str2 = POSTGRES_SCHEMA;//schame analy
		std::string str1 = "select count(*) from \"";
		str1.append(str2);
		str1.append("\".\"");
		str1.append(POSTGRES_TABLEPREFIX);
		str1.append("pq_ledger_monitor");
		str1.append("\" where \"terminal_code\" in (");
		//str1.append("\".\"MEAS_PQ_FRONT_LIST_TR\"");

		QMap<QString, ied_t*>::const_iterator cit;
		for (cit = dev_map.constBegin(); cit != dev_map.constEnd();) {
			QString key = cit.key();
			str1.append("'");
			str1.append(key.toStdString());
			str1.append("'");
			if (++cit != dev_map.constEnd()) {
				str1 += ",";
			}
		}

		str1.append(")");
		cout << "dev line pg  sql1 is:" << str1 << endl;
		//int rtState = OTLState();
		OTLConnect();
		otl_stream i(1, // buffer size
			str1.c_str(),
			//SELECT statement
			db //connect object
		);
		//create select stream

		int f2;
		while (!i.eof()) { //while not end-of-data
			i >> f2;
			//cout << "count=" << f2 << endl;
		}
		OTLDisconnect();
		count_cfg = f2;;//读数据库
		cout << "line_count=" << count_cfg << endl;

	}
	catch (otl_exception& e)
	{
		printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg);
		return e.code;
	}



	//读数据
	try {
		OTLConnect();
		std::string str2 = POSTGRES_SCHEMA;//schame analy
		std::string str1 = "select \"monitor_id\",\"terminal_code\",\"monitor_name\",\"logical_device_seq\",\"voltage_level\",\"terminal_connect\",\"update_time\" from \"";
		str1.append(str2);
		str1.append("\".\"");
		str1.append(POSTGRES_TABLEPREFIX);
		str1.append("pq_ledger_monitor");
		str1.append("\" where \"terminal_code\" in (");

		QMap<QString, ied_t*>::const_iterator cit;
		for (cit = dev_map.constBegin(); cit != dev_map.constEnd();) {
			QString key = cit.key();
			str1.append("'");
			str1.append(key.toStdString());
			str1.append("'");
			if (++cit != dev_map.constEnd()) {
				str1 += ",";
			}
		}

		str1.append(")");
		cout << "qmap line pg sql2 is:" << str1 << endl;
		//int rtState = OTLState();
		otl_stream i(1, // buffer size
			str1.c_str(),
			//SELECT statement
			db //connect object
		);
		//create select stream

		char monitor_id[64];
		char terminal_code[64];
		char monitor_name[64];
		char logical_device_seq[64];
		char voltage_level[64];
		char terminal_connect[64];
		otl_datetime  timestamp;
		while (!i.eof()) { //while not end-of-data
			i >> monitor_id >> terminal_code >> monitor_name >> logical_device_seq >> voltage_level >> terminal_connect >> timestamp;
			//cout << "monitor_id=" << monitor_id << " terminal_code=" << terminal_code << " monitor_name=" << monitor_name << " logical_device_seq=" << logical_device_seq;
			//cout << " voltage_level=" << voltage_level << " terminal_connect=" << terminal_connect;
			//cout << " timestamp: " << timestamp.year << "-" << timestamp.month << "-" << timestamp.day << " " << timestamp.hour << ":" << timestamp.minute << ":" << timestamp.second << endl;

			count_real++;
			memset(&line_info, 0, sizeof(line_info));
			line_info.line_id = count_real;
			//cout << "line_id:" << line_info.line_id << endl;

			strcpy(line_info.mp_id, monitor_id);
			//cout << "mp_id:" << line_info.mp_id << endl;
			strcpy(line_info.terminal_code, terminal_code);
			//cout << "terminal_code:" << line_info.terminal_code << endl;
			if (isCharPtrEmpty(logical_device_seq)) {
				line_info.cpuno = 1;
				//cout << "logical_device_seq:is null~"<< line_info.cpuno << endl;
			}
			else {
				line_info.cpuno = std::atoi(logical_device_seq);
				//cout << "logical_device_seq:"<< logical_device_seq << endl;
			}
			//cout << "cpuno:" << line_info.cpuno << endl;
			strcpy(line_info.voltage_level, voltage_level);
			//cout << "voltage_level:" << line_info.voltage_level << endl;
			strcpy(line_info.v_wiring_type, terminal_connect);
			//cout << "v_wiring_type:" << line_info.v_wiring_type << endl;

			//// 构造struct tm对象
			struct tm timeinfo;
			timeinfo.tm_year = timestamp.year - 1900; // 年份需要减去1900
			timeinfo.tm_mon = timestamp.month - 1; // 月份需要减去1
			timeinfo.tm_mday = timestamp.day;
			timeinfo.tm_hour = timestamp.hour;
			timeinfo.tm_min = timestamp.minute;
			timeinfo.tm_sec = timestamp.second;

			time_t time = std::mktime(&timeinfo);
			line_info.time = static_cast<long long>(time);
			//cout << "time:" << line_info.time << endl;

			strcpy(line_info.name, monitor_name);
			//cout << "name:" << line_info.name << endl;

			ied = dev_map.value(QString::fromUtf8(line_info.terminal_code));
			//ied = find_ied_from_dev_code(line_info.terminal_code);

			if (ied && ied->usr_ext && line_info.cpuno && line_info.cpuno < 10) {
				char str[256];
				byte_t cpuno = line_info.cpuno;
				//cout << "cpuno:" << line_info.cpuno << endl;
				//cout << "byte_t cpuno:" << cpuno-1 << endl;
				ied_usr = (ied_usr_t*)ied->usr_ext;
				ied_usr->LD_info[cpuno - 1] = line_info;
				ied_usr->LD_info[cpuno - 1].ied = ied;
				apr_snprintf(str, sizeof(str), "PQMonitorPQM%d", cpuno);
				ied_usr->LD_info[cpuno - 1].LD_name = apr_pstrdup(g_temp_dev_pool, str);
				ied_usr->LD_info[cpuno - 1].ht_fcd = apr_hash_make(g_temp_dev_pool);
				ied_usr->LD_info[cpuno - 1].ht_full_fcda = apr_hash_make(g_temp_dev_pool);
				ied_usr->LD_info[cpuno - 1].rptcount = 0;
				//cout << "rptcount:" << ied_usr->LD_info[cpuno - 1].rptcount << endl;

				if (cpuno > ied->cpucount) {
					//int c = cpuno;
					//cout << "cpucount(linecount old):" << (int)(ied->cpucount) << "new:" << c << endl;

					ied->cpucount = cpuno;
					//cout << "byte_t cpucount:" << ied->cpucount+1 << endl;
				}
			}
		}
		OTLDisconnect();
	}
	catch (otl_exception& e)
	{
		printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg);
		return e.code;
	}

	if (count_cfg != count_real)
		return APR_EBADF;
	return APR_SUCCESS;


}
void g_node_add_dev() {
	int count_cfg = g_node->n_clients;
	g_node->clients = (ied_t**)apr_pcalloc(g_cfg_pool, count_cfg * sizeof(ied_t*));
	for (int k = 0; k < count_cfg; k++)
		g_node->clients[k] = (ied_t*)apr_pcalloc(g_cfg_pool, sizeof(ied_t));
}
//CZY 2023-08-25
int compare_line_account(ied_usr_t* run_ied_usr, ied_usr_t* temp_ied_usrs, int run_cpucount, int temp_cpucount) {
	int run_cpuno, temp_cpuno;
	for (run_cpuno = 0; run_cpuno < run_cpucount; run_cpuno++) {

		int delete_flag = 1;
		for (temp_cpuno = 0; temp_cpuno < temp_cpucount; temp_cpuno++) {
			if (run_ied_usr->LD_info[run_cpuno].mp_id == temp_ied_usrs->LD_info[temp_cpuno].mp_id) {//exist same mp_id(update,keep)
				if (run_ied_usr->LD_info[run_cpuno].time < temp_ied_usrs->LD_info[temp_cpuno].time) {//line_update
					run_ied_usr->LD_info[run_cpuno].update_flag = 4;
					temp_ied_usrs->LD_info[temp_cpuno].update_flag = 4;

				}
				else {//line_keep
					run_ied_usr->LD_info[run_cpuno].update_flag = 0;
					temp_ied_usrs->LD_info[temp_cpuno].update_flag = 0;
				}
				delete_flag = 0;
				break;
			}
		}
		if (delete_flag == 1) {//line_delete
			run_ied_usr->LD_info[run_cpuno].update_flag = 2;

		}
	}
	for (temp_cpuno = 0; temp_cpuno < temp_cpucount; temp_cpuno++) {
		int  add_flag = 1;
		for (run_cpuno = 0; run_cpuno < run_cpucount; run_cpuno++) {
			if (run_ied_usr->LD_info[run_cpuno].mp_id == temp_ied_usrs->LD_info[temp_cpuno].mp_id) {//exist same mp_id

				add_flag = 0;
				break;
			}
		}
		if (add_flag == 1) {//line_add
			temp_ied_usrs->LD_info[temp_cpuno].update_flag = 8;
		}
	}
	return 0;
}
//CZY 2023-08-22 compare account
int compare_node_account(node_t* run_g_node, node_t* temp_g_node, int* add_count)
{

	if (run_g_node == NULL) {
		return 1;
	}
	if (temp_g_node == NULL) {
		return 2;
	}
	int i, j;
	for (i = 0; i < run_g_node->n_clients; i++) {
		ied_usr_t* run_ied_usr = (ied_usr_t*)run_g_node->clients[i]->usr_ext;
		run_ied_usr->update_flag = 0;
		int  delete_flag = 1;
		for (j = 0; j < temp_g_node->n_clients; j++) {
			ied_usr_t* temp_ied_usr = (ied_usr_t*)temp_g_node->clients[j]->usr_ext;
			if (run_ied_usr->terminal_id == temp_ied_usr->terminal_id) {//exist same terminal_id(update,delete,keep)

				if (temp_ied_usr->time > run_ied_usr->time)//dev_update or delete
				{
					if (strcmp(temp_ied_usr->tmnl_status, "20") != 0 && strcmp(run_ied_usr->tmnl_status, "20") == 0) {//dev_delete
						temp_ied_usr->update_flag = 2;
						run_ied_usr->update_flag = 2;

						int cpuno;
						for (cpuno = 0; cpuno < run_g_node->clients[i]->cpucount; cpuno++) {//line_delete
							run_ied_usr->LD_info[cpuno].update_flag = 2;
						}
					}
					else {//dev_update
						run_ied_usr->update_flag = 4;
						temp_ied_usr->update_flag = 4;
						int cpuno;
						//for (cpuno = 0; cpuno < temp_g_node->clients[j]->cpucount; cpuno++) {//line_update
						//	temp_ied_usr->LD_info[cpuno].update_flag = 8;
						//}
						int f = compare_line_account(run_ied_usr, temp_ied_usr, run_g_node->clients[i]->cpucount, temp_g_node->clients[j]->cpucount);//line_compare
					}

				}
				else {//dev_keep
					int f = compare_line_account(run_ied_usr, temp_ied_usr, run_g_node->clients[i]->cpucount, temp_g_node->clients[j]->cpucount);//line_compare

				}
				delete_flag = 0;
				break;
			}
		}
		if (delete_flag == 1) {//dev_delete
			run_ied_usr->update_flag = 2;

		}
	}
	for (i = 0; i < temp_g_node->n_clients; i++) {
		ied_usr_t* temp_ied_usr = (ied_usr_t*)temp_g_node->clients[i]->usr_ext;
		if (temp_ied_usr->update_flag == 2) {
			continue;
		}
		int  add_flag = 1;
		for (j = 0; j < run_g_node->n_clients; j++) {
			ied_usr_t* run_ied_usr = (ied_usr_t*)run_g_node->clients[j]->usr_ext;
			if (temp_ied_usr->terminal_id == run_ied_usr->terminal_id) {
				add_flag = 0;
				break;
			}
		}
		if (add_flag == 1) {//dev_add
			temp_ied_usr->update_flag = 8;
			int cpuno;
			for (cpuno = 0; cpuno < temp_g_node->clients[i]->cpucount; cpuno++) {//line_add
				temp_ied_usr->LD_info[cpuno].update_flag = 8;
				*add_count += 1;
			}
		}
	}
	return 0;

}
//
void handle_line_account(ied_usr_t* run_ied_usr, ied_usr_t* temp_ied_usrs, int run_cpucount, int temp_cpucount) {
	int run_cpuno, temp_cpuno;
	for (run_cpuno = 0; run_cpuno < run_cpucount; run_cpuno++) {
		if (run_ied_usr->LD_info[run_cpuno].update_flag = 0) {

		}
		else if (run_ied_usr->LD_info[run_cpuno].update_flag = 2) {
			line_account_delete(run_ied_usr->update_flag);
		}
		else if (run_ied_usr->LD_info[run_cpuno].update_flag = 4) {
			line_account_update(run_ied_usr->update_flag);
		}
	}
	for (temp_cpuno = 0; temp_cpuno < temp_cpucount; temp_cpuno++) {
		if (temp_ied_usrs->LD_info[run_cpuno].update_flag = 8) {
			line_account_add();
		}
	}
}
// CZY 2023-09-12 handle account
void handle_node_account(node_t* run_g_node, node_t* temp_g_node, int dev_count) {
	int i;
	for (i = 0; i < run_g_node->n_clients; i++) {
		ied_usr_t* run_ied_usr = (ied_usr_t*)run_g_node->clients[i]->usr_ext;
		if (run_ied_usr->update_flag == 0) {

		}
		else if (run_ied_usr->update_flag == 2) {
			dev_account_delete();
		}
		else if (run_ied_usr->update_flag == 4) {
			dev_account_update();
		}

	}
	//增加dev的数量
	for (i = 0; i < temp_g_node->n_clients; i++) {
		ied_usr_t* temp_ied_usr = (ied_usr_t*)temp_g_node->clients[i]->usr_ext;
		if (temp_ied_usr->update_flag == 8) {
			dev_account_add();
		}
	}
}
//CZY 2023-08-25
void create_temp_g_node(node_t* temp_g_node) {
	/*create_temp_device_cfg_json(temp_g_node);
	create_temp_line_cfg_pg(temp_g_node);
	int* add_count = 0;
	compare_node_account(g_node, temp_g_node, add_count);*/


}
void dev_update() {
	QMap<QString, ied_t*> dev_map;
	//create_temp_device_cfg_json(dev_map);
}
#endif

int GetServerIndexFromDB() //获取前置服务器序号
{

	register int fd, interface;
	const int MAXINTERFACES = 100;
	struct ifreq buf[MAXINTERFACES];
	struct arpreq arp;
	struct ifconf ifc;
	char mac[32] = "";

	if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) >= 0) {
		ifc.ifc_len = sizeof buf;
		ifc.ifc_buf = (caddr_t)buf;
		if (!ioctl(fd, SIOCGIFCONF, (char*)&ifc)) {
			interface = ifc.ifc_len / sizeof(struct ifreq);
			printf("\ninterface num is interface= %d\n", interface);

			while (interface-- > 0) {
				printf("net device %s\n", buf[interface].ifr_name);

				/*确保网卡是否支持混杂模式 Jugde whether the net card status is promisc */
				if (!(ioctl(fd, SIOCGIFFLAGS, (char*)&buf[interface]))) {
					if (buf[interface].ifr_flags & IFF_PROMISC) {
						printf("the interface is PROMISC \n");
					}
				}
				else {
					char str[256] = "";
					sprintf(str, "cpm: ioctl device %s", buf[interface].ifr_name);
					perror(str);
				}

				/*判断网卡状态是否打开 Judge whether the net card status is up */
				if (buf[interface].ifr_flags & IFF_UP) {
					printf("the interface status is UP\n");
				}
				else {
					printf("the interface status is DOWN\n");
				}

				/*获取网卡IP地址 Get IP of the net card */
				if (!(ioctl(fd, SIOCGIFADDR, (char*)&buf[interface]))) {
					printf("IP address is: %s\n", inet_ntoa(((struct sockaddr_in*)(&buf[interface].ifr_addr))->sin_addr));

				}
				else {
					char str[256] = "";
					sprintf(str, "cpm: ioctl device %s", buf[interface].ifr_name);
					perror(str);
				}

				/*获取网卡的HW地址 Get HW ADDRESS of the net card */
				if (!(ioctl(fd, SIOCGIFHWADDR, (char*)&buf[interface]))) {
					printf("HW address is: ");
					sprintf(mac, "%02x:%02x:%02x:%02x:%02x:%02x",
						(unsigned char)buf[interface].ifr_hwaddr.sa_data[0],
						(unsigned char)buf[interface].ifr_hwaddr.sa_data[1],
						(unsigned char)buf[interface].ifr_hwaddr.sa_data[2],
						(unsigned char)buf[interface].ifr_hwaddr.sa_data[3],
						(unsigned char)buf[interface].ifr_hwaddr.sa_data[4],
						(unsigned char)buf[interface].ifr_hwaddr.sa_data[5]);
					printf("%s\n\n", mac);
				}
				else {
					char str[256];
					sprintf(str, "cpm: ioctl device %s", buf[interface].ifr_name);
					perror(str);
				}
			}
		}
		else
			perror("cpm: ioctl");
	}
	else
		perror("cpm: socket");

	close(fd);
	return 0;
}
/////////////////////////////////////////////////////////CZY

void parse_one_rpt_log_ini(int idx, QStringList* rpt_cfg_strlist, QStringList* log_cfg_strlist, char* type)
{
	char* tmp;
	tmp = Get_xmlpath(type);//获取模型id号
	if (tmp == NULL) {//找不到模型编号使用默认的型号和配置文件
		//zw修改 2023 - 8 - 15 将触发报告的解析移至XML 原配置RptLogCfg.ini取消
		if (strcmp(subdir, "cfg_stat_data") == 0)
		{
			QString devtype;
			devtype.append(type);
			QString devtype2;
			devtype2.append("HL-6810");//稳态默认型号HL-6810

			qDebug() << "cfg_stat_data";
			QString xml_dir = QString("../") + QString("etc/"); //Linux下调试路径

			QDomDocument doc;   //新建QDomDocument类对象，它代表一个XML文档
			QFile file(xml_dir + QString("JiangSu_Config.xml"));//默认配置文件JiangSu_Config.xml
			if (!file.open(QIODevice::ReadOnly | QFile::Text)) //以只读方式打开xml
			{
				qDebug() << "Read RPT Error1";
				return;
			}
			if (!doc.setContent(&file)) //将文件内容读到doc中
			{
				qDebug() << "Read RPT Error2";
				file.close();
				return;
			}
			file.close();
			QDomNode firstNode = doc.firstChild(); //根节点"JSConfigTemplate"
			QDomElement docElem = doc.documentElement();  //返回根节点元素
			QDomNode n = docElem.firstChild(); //获得doc的第一个节点，即"Topic"
			while (!n.isNull()) //如果Topic节点不为空 
			{
				if (n.isElement())
				{
					QDomElement e = n.toElement(); //将其转换为元素
					QString strTag = e.tagName(); //
					if ("ReportMap" == strTag)//zw修改 2023 - 8 - 15 增加判断 将触发报告的解析移至XML 原配置RptLogCfg.ini取消
					{
						qDebug() << "ReportStat";
						QDomNodeList list = e.childNodes(); //获得元素的所有子节点的列表
						for (int i = 0; i < list.count(); i++) //遍历 DataType列表
						{
							QDomNode node = list.at(i); //node1 <DataType>
							if (node.isElement())
							{
								QString strTag2 = node.toElement().tagName(); //DataType节点
								if ("ReportStat" == strTag2)
								{
									QDomNodeList list2 = node.childNodes(); //获得元素DataType的所有子节点的列表 
									for (int i2 = 0; i2 < list2.count(); i2++) //遍历 Monitor列表
									{
										QDomNode node2 = list2.at(i2); //node2 <Monitor>
										if (node2.isElement())
										{
											rpt_cfg_strlist->append(node2.toElement().attribute("ReportControl"));
											qDebug() << "devtype:" << devtype << node2.toElement().attribute("ReportControl").toAscii().data();
										}
									}
								}
							}

						}
					}
				}
				n = n.nextSibling();
			}

			QString log_cfg_str = "LLN0$LG$lcStatisticData,dsStatisticData,PQM1,0,600000,1,0,0,0";
			log_cfg_strlist->append(log_cfg_str);
		}
		if (strcmp(subdir, "cfg_soe_comtrade") == 0)
		{
			qDebug() << "cfg_soe_comtrade";
			QString xml_dir = QString("../") + QString("etc/"); //Linux下调试路径

			QDomDocument doc;   //新建QDomDocument类对象，它代表一个XML文档
			QFile file(xml_dir + QString("JiangSu_Config.xml"));
			if (!file.open(QIODevice::ReadOnly | QFile::Text)) //以只读方式打开xml
			{
				qDebug() << "Read RPT Error1";
				return;
			}
			if (!doc.setContent(&file)) //将文件内容读到doc中
			{
				qDebug() << "Read RPT Error2";
				file.close();
				return;
			}
			file.close();
			QDomNode firstNode = doc.firstChild(); //根节点"JSConfigTemplate"
			QDomElement docElem = doc.documentElement();  //返回根节点元素
			QDomNode n = docElem.firstChild(); //获得doc的第一个节点，即"Topic"
			while (!n.isNull()) //如果Topic节点不为空 
			{
				if (n.isElement())
				{
					QDomElement e = n.toElement(); //将其转换为元素
					QString strTag = e.tagName(); //
					if ("ReportMap" == strTag)//zw修改 2023 - 8 - 15 增加判断 将触发报告的解析移至XML 原配置RptLogCfg.ini取消
					{
						qDebug() << "ReportEvent";
						QDomNodeList list = e.childNodes(); //获得元素的所有子节点的列表
						for (int i = 0; i < list.count(); i++) //遍历 DataType列表
						{
							QDomNode node = list.at(i); //node1 <DataType>
							if (node.isElement())
							{
								QString strTag2 = node.toElement().tagName(); //DataType节点
								if ("ReportEvent" == strTag2)
								{
									QDomNodeList list2 = node.childNodes(); //获得元素DataType的所有子节点的列表 
									for (int i2 = 0; i2 < list2.count(); i2++) //遍历 Monitor列表
									{
										QDomNode node2 = list2.at(i2); //node2 <Monitor>
										if (node2.isElement())
										{
											rpt_cfg_strlist->append(node2.toElement().attribute("ReportControl"));
											qDebug() << node2.toElement().attribute("ReportControl").toAscii().data();
										}
									}
								}
							}

						}
					}
				}
				n = n.nextSibling();
			}

			QString log_cfg_str = "LLN0$LG$lcStatisticData,dsStatisticData,PQM1,0,600000,1,0,0,0";
			log_cfg_strlist->append(log_cfg_str);
		}
		if (strcmp(subdir, "cfg_his_data") == 0 || strcmp(subdir, "cfg_newhis_data") == 0 || strcmp(subdir, "cfg_recallhis_data") == 0 || strcmp(subdir, "cfg_recallall_data") == 0)
		{
			QString log_cfg_str = "LLN0$LG$lcStatisticData,dsStatisticData,PQM1,0,600000,1,0,0,0";
			log_cfg_strlist->append(log_cfg_str);
		}
	}
	else//型号不为空读取指定的配置文件
	{
		QString tmppath;
		tmppath.append("/FeProject/dat/").append(tmp).append(".xml");
		qDebug() << tmppath;

		//lnk20241126调试用
		std::cout << "rptcfgfile:" << tmppath.toStdString() << std::endl;

		//zw修改 2023 - 8 - 15 将触发报告的解析移至XML 原配置RptLogCfg.ini取消
		if (strcmp(subdir, "cfg_stat_data") == 0)
		{
			qDebug() << "cfg_stat_data";
			QDomDocument doc;   //新建QDomDocument类对象，它代表一个XML文档
			QFile file(tmppath);
			if (!file.open(QIODevice::ReadOnly | QFile::Text)) //以只读方式打开xml
			{
				qDebug() << "Read RPT Error1";		

				//lnk20241126调试用
				std::cout << "Read RPT Error1" << std::endl;

				return;
			}
			if (!doc.setContent(&file)) //将文件内容读到doc中
			{
				qDebug() << "Read RPT Error2";

				//lnk20241126调试用
				std::cout << "Read RPT Error2" << std::endl;

				file.close();
				return;
			}
			file.close();
			QDomNode firstNode = doc.firstChild(); //根节点"JSConfigTemplate"
			QDomElement docElem = doc.documentElement();  //返回根节点元素
			QDomNode n = docElem.firstChild(); //获得doc的第一个节点，即"Topic"
			while (!n.isNull()) //如果Topic节点不为空 
			{
				if (n.isElement())
				{
					QDomElement e = n.toElement(); //将其转换为元素
					QString strTag = e.tagName(); //
					if ("ReportMap" == strTag)//zw修改 2023 - 8 - 15 增加判断 将触发报告的解析移至XML 原配置RptLogCfg.ini取消
					{
						qDebug() << "ReportStat";
						QDomNodeList list = e.childNodes(); //获得元素的所有子节点的列表
						for (int i = 0; i < list.count(); i++) //遍历 DataType列表
						{
							QDomNode node = list.at(i); //node1 <DataType>
							if (node.isElement())
							{
								QString strTag2 = node.toElement().tagName(); //DataType节点
								if ("ReportStat" == strTag2)
								{
									QDomNodeList list2 = node.childNodes(); //获得元素DataType的所有子节点的列表 
									for (int i2 = 0; i2 < list2.count(); i2++) //遍历 Monitor列表
									{
										QDomNode node2 = list2.at(i2); //node2 <Monitor>
										if (node2.isElement())
										{
											rpt_cfg_strlist->append(node2.toElement().attribute("ReportControl"));
											qDebug() << node2.toElement().attribute("ReportControl").toAscii().data();//读取各个报告配置
										}
									}
								}
							}

						}
					}
				}
				n = n.nextSibling();
			}

			QString log_cfg_str = "LLN0$LG$lcStatisticData,dsStatisticData,PQM1,0,600000,1,0,0,0";//日志的配置是写死的
			log_cfg_strlist->append(log_cfg_str);
		}
		
		//lnk添加实时数据20241125
		if (strcmp(subdir, "cfg_3s_data") == 0)
		{
			qDebug() << "cfg_3s_data";
			QDomDocument doc;   //新建QDomDocument类对象，它代表一个XML文档
			QFile file(tmppath);
			if (!file.open(QIODevice::ReadOnly | QFile::Text)) //以只读方式打开xml
			{
				qDebug() << "Read RPT Error1";
				return;
			}
			if (!doc.setContent(&file)) //将文件内容读到doc中
			{
				qDebug() << "Read RPT Error2";
				file.close();
				return;
			}
			file.close();
			QDomNode firstNode = doc.firstChild(); //根节点"JSConfigTemplate"
			QDomElement docElem = doc.documentElement();  //返回根节点元素
			QDomNode n = docElem.firstChild(); //获得doc的第一个节点，即"Topic"
			while (!n.isNull()) //如果Topic节点不为空 
			{
				if (n.isElement())
				{
					QDomElement e = n.toElement(); //将其转换为元素
					QString strTag = e.tagName(); //
					if ("ReportMap" == strTag)//zw修改 2023 - 8 - 15 增加判断 将触发报告的解析移至XML 原配置RptLogCfg.ini取消
					{
						qDebug() << "ReportReal";
						QDomNodeList list = e.childNodes(); //获得元素的所有子节点的列表
						for (int i = 0; i < list.count(); i++) //遍历 DataType列表
						{
							QDomNode node = list.at(i); //node1 <DataType>
							if (node.isElement())
							{
								QString strTag2 = node.toElement().tagName(); //DataType节点
								if ("ReportReal" == strTag2)
								{
									QDomNodeList list2 = node.childNodes(); //获得元素DataType的所有子节点的列表 
									for (int i2 = 0; i2 < list2.count(); i2++) //遍历 Monitor列表
									{
										QDomNode node2 = list2.at(i2); //node2 <Monitor>
										if (node2.isElement())
										{
											rpt_cfg_strlist->append(node2.toElement().attribute("ReportControl"));
											qDebug() << node2.toElement().attribute("ReportControl").toAscii().data();
										}
									}
								}
							}

						}
					}
				}
				n = n.nextSibling();
			}

			//实时数据没有日志
			//QString log_cfg_str = "LLN0$LG$lcStatisticData,dsStatisticData,PQM1,0,600000,1,0,0,0";
			//log_cfg_strlist->append(log_cfg_str);
		}
		
		if (strcmp(subdir, "cfg_soe_comtrade") == 0)
		{
			qDebug() << "cfg_soe_comtrade";
			QDomDocument doc;   //新建QDomDocument类对象，它代表一个XML文档
			QFile file(tmppath);
			if (!file.open(QIODevice::ReadOnly | QFile::Text)) //以只读方式打开xml
			{
				qDebug() << "Read RPT Error1";
				return;
			}
			if (!doc.setContent(&file)) //将文件内容读到doc中
			{
				qDebug() << "Read RPT Error2";
				file.close();
				return;
			}
			file.close();
			QDomNode firstNode = doc.firstChild(); //根节点"JSConfigTemplate"
			QDomElement docElem = doc.documentElement();  //返回根节点元素
			QDomNode n = docElem.firstChild(); //获得doc的第一个节点，即"Topic"
			while (!n.isNull()) //如果Topic节点不为空 
			{
				if (n.isElement())
				{
					QDomElement e = n.toElement(); //将其转换为元素
					QString strTag = e.tagName(); //
					if ("ReportMap" == strTag)//zw修改 2023 - 8 - 15 增加判断 将触发报告的解析移至XML 原配置RptLogCfg.ini取消
					{
						qDebug() << "ReportEvent";
						QDomNodeList list = e.childNodes(); //获得元素的所有子节点的列表
						for (int i = 0; i < list.count(); i++) //遍历 DataType列表
						{
							QDomNode node = list.at(i); //node1 <DataType>
							if (node.isElement())
							{
								QString strTag2 = node.toElement().tagName(); //DataType节点
								if ("ReportEvent" == strTag2)//区分点
								{
									QDomNodeList list2 = node.childNodes(); //获得元素DataType的所有子节点的列表 
									for (int i2 = 0; i2 < list2.count(); i2++) //遍历 Monitor列表
									{
										QDomNode node2 = list2.at(i2); //node2 <Monitor>
										if (node2.isElement())
										{
											rpt_cfg_strlist->append(node2.toElement().attribute("ReportControl"));
											qDebug() << node2.toElement().attribute("ReportControl").toAscii().data();
										}
									}
								}
							}

						}
					}
				}
				n = n.nextSibling();
			}

			QString log_cfg_str = "LLN0$LG$lcStatisticData,dsStatisticData,PQM1,0,600000,1,0,0,0";
			log_cfg_strlist->append(log_cfg_str);
		}
		if (strcmp(subdir, "cfg_his_data") == 0 || strcmp(subdir, "cfg_newhis_data") == 0 || strcmp(subdir, "cfg_recallhis_data") == 0 || strcmp(subdir, "cfg_recallall_data") == 0)
		{
			QString log_cfg_str = "LLN0$LG$lcStatisticData,dsStatisticData,PQM1,0,600000,1,0,0,0";
			log_cfg_strlist->append(log_cfg_str);
		}
		delete[] tmp;
	}
}

int parse_rpt_log_ini()
{
	const int MAX_DEV_FLAG = 10;
	bool not_loaded[MAX_DEV_FLAG];
	//QStringList rpt_cfg_strlists[MAX_DEV_FLAG];
	//QStringList log_cfg_strlists[MAX_DEV_FLAG];
	QMap<QString, QStringList*> rpt_cfg_strlists;
	QMap<QString, QStringList*> log_cfg_strlists;

	int			iedno, cpuno;
	ied_t* ied;
	ied_usr_t* ied_usr;
	LD_info_t* LD_info;
	char		buf[256];

	/*for (int i = 0; i < MAX_DEV_FLAG; ++i)
		not_loaded[i] = true;*/
	for (iedno = 0; iedno < g_node->n_clients; iedno++) {
		ied = g_node->clients[iedno];
		ied_usr = GET_IEDEXT_ADDR(ied);
		QString type;
		type.append(ied_usr->dev_type);
		if (!rpt_cfg_strlists.contains(type))
		{
			QStringList* rpt_temp = new QStringList();
			QStringList* log_temp = new QStringList();
			rpt_cfg_strlists.insert(type, rpt_temp);
			log_cfg_strlists.insert(type, log_temp);
			//g_DevFlag没有使用
			parse_one_rpt_log_ini(g_DevFlag, rpt_cfg_strlists[type], log_cfg_strlists[type], ied_usr->dev_type);

		}
		/*if (not_loaded[ied_usr->dev_flag]) {
			parse_one_rpt_log_ini(ied_usr->dev_flag, rpt_cfg_strlists[ied_usr->dev_flag], log_cfg_strlists[ied_usr->dev_flag], ied_usr->dev_type);
			not_loaded[ied_usr->dev_flag] = false;
		}*/

		for (cpuno = 0; cpuno < ied->cpucount; cpuno++) {
			LD_info = &(ied_usr->LD_info[cpuno]);
			char str[256];					//256大小
			char* tmp = Get_IED(ied_usr->dev_type);
			qDebug() << tmp << endl;

			apr_snprintf(str, sizeof(str), tmp, cpuno + 1);

			//lnk20250208不使用apr_pstrdup，使用固定大小，后续都在这块内存上直接复用
			//ied_usr->LD_info[cpuno].LD_name = apr_pstrdup(g_init_pool, str);//domin
			// 从 g_init_pool 内存池中分配固定 256 字节的内存
//			ied_usr->LD_info[cpuno].LD_name = (char *)apr_palloc(g_init_pool, 256);//lnk20250212重复申请删除

			// 清空内存，防止残留数据
//			memset(ied_usr->LD_info[cpuno].LD_name, 0, 256);

			// 将 str 中的内容复制到预先分配的内存中，最多复制 256 字节（包含结束符）
//			apr_cpystrn(ied_usr->LD_info[cpuno].LD_name, str, 256);

			delete[] tmp;

			init_rptctrl_by_count(LD_info, rpt_cfg_strlists[type]->size());

			for (int i = 0; i < rpt_cfg_strlists[type]->size(); ++i) {

				apr_snprintf(buf, sizeof(buf), "%s", rpt_cfg_strlists[type]->at(i).toAscii().constData());

				fill_rptctrl_by_cfg(LD_info, i, buf);//

			}

			init_logctrl_by_count(LD_info, log_cfg_strlists[type]->size());
			for (int i = 0; i < log_cfg_strlists[type]->size(); ++i) {
				apr_snprintf(buf, sizeof(buf), "%s", log_cfg_strlists[type]->at(i).toAscii().constData());
				char* tmp = Get_LDevice(ied_usr->dev_type);
				fill_logctrl_by_cfg(LD_info, i, buf, tmp);
				delete[] tmp;
			}

		}
	}

	//报告控制块和日志控制块处理结束后清理容器
	for (QMap<QString, QStringList*>::iterator it1 = log_cfg_strlists.begin(); it1 != log_cfg_strlists.end(); ++it1)
	{
		delete it1.value();
	}
	for (QMap<QString, QStringList*>::iterator it2 = rpt_cfg_strlists.begin(); it2 != rpt_cfg_strlists.end(); ++it2)
	{
		delete it2.value();
	}
	rpt_cfg_strlists.clear();
	log_cfg_strlists.clear();

	return APR_SUCCESS;
}

int parse_json_cfg()
{
	QString cfg_dir = QString("../") + QString("etc/");
	QDomDocument doc;   //新建QDomDocument类对象，它代表一个XML文档
	QFile file(cfg_dir + JSON_CONFIG_FN_old);
	if (!file.open(QIODevice::ReadOnly))
		return APR_EBADPATH;  //以只读方式打开
	if (!doc.setContent(&file)) {
		file.close();
		return APR_EBADF;
	}
	//将文件内容读到doc中
	QDomElement docElem = doc.documentElement();  //返回根元素  
	QDomNode n = docElem.firstChild();   //返回根节点的第一个子节点 
	while (!n.isNull()) {   //如果节点不为空 
		if (n.isElement()) { //如果节点是元素  
			QDomElement e = n.toElement();  //将其转换为元素  
			QString strTag = e.tagName();
			QString topic = e.attribute("name");
			if (strTag == "Topic" && (topic == "HISDATA" || topic == "RTDATA")) {
				QDomNodeList list = e.childNodes(); //获得元素e的所有子节点的列表  e<Topic>
				for (int i = 0; i < list.count(); i++) {  //遍历该列表  				
					QDomNode node = list.at(i);
					if (node.isElement()) {
						QString strTag2 = node.toElement().tagName();
						QString data_type = node.toElement().attribute("value");
						if (strTag2 == "DataType") {  //node  <DataType>
							QDomNodeList list2 = node.childNodes(); //获得元素node的所有子节点的列表  
							for (int i2 = 0; i2 < list2.count(); i2++) {  //遍历该列表 	 
								QDomNode node2 = list2.at(i2);   ////node2  <Monitor>
								if (node2.isElement()) {
									QString strTag3 = node2.toElement().tagName();
									///////////////////////////
									if (strTag3 == "Monitor") {
										QDomNodeList list3 = node2.childNodes(); //获得元素node的所有子节点的列表  
										for (int i3 = 0; i3 < list3.count(); i3++) {  //遍历该列表 	 
											QDomNode node3 = list3.at(i3);   //node3 <Item>
											if (node3.isElement()) {
												QString strTag4 = node3.toElement().tagName();
												//**////**////**////**////**////**////**////**////**////**////**//
												if (strTag4 == "Item") {
													QString item = node3.toElement().attribute("name");
													QDomNodeList list4 = node3.childNodes(); //获得元素node的所有子节点的列表  
													for (int i4 = 0; i4 < list4.count(); i4++) {  //遍历该列表 	 
														QDomNode node4 = list4.at(i4);   //node4 <Sequence>
														if (node4.isElement()) {
															QString strTag5 = node4.toElement().tagName();
															//////////*********************////////////////////
															if (strTag5 == "Sequence") {
																uint sequence = node4.toElement().attribute("value").toUInt();
																QDomNodeList list5 = node4.childNodes(); //获得元素node的所有子节点的列表  
																for (int i5 = 0; i5 < list5.count(); i5++) {  //遍历该列表 	 
																	QDomNode node5 = list5.at(i5);   //node5 <Value>
																	if (node5.isElement()) {
																		QDomElement e_Value = node5.toElement();  //将其转换为元素  
																		QString strTag6 = e_Value.tagName();
																		//<Value name="G_DELTA_V"  desc="电压偏差95值"  type="6" DO="MMXU4$MX$PhVDev"   DA="phs*$cVal$mag$f"    Coefficient="0.01" />
																		if (strTag6 == "Value") {
																			QString name_str = e_Value.attribute("name");
																			QString DO_str = e_Value.attribute("DO");
																			QString DA_str = e_Value.attribute("DA");
																			uint mask = 1;
																			for (int j = 0; j <= 3; j++) {
																				if (mask & sequence)
																					qDebug() << topic << " " << data_type << " " << item << " Phs=" << j << " " << name_str << " " << DO_str << DA_str;
																				mask *= 2;
																			}
																			//todo ,to read the attribute of Value
																		}
																	}
																}
															}
															//////////*********************////////////////////
														}
													}
												}
												//**////**////**////**////**////**////**////**////**////**////**//
											}
										}
									}
									////////////////////////////////
								}
							}//	for(int i2=0; i2<list2.count(); i2++)

						} //else if ( strTag == "DataType" )
					}
				}
			}
			else if (strTag == "Topic" && (topic == "RTDATASOE")) {  //"实时SOE事件"
				//todo 
			}
		}
		n = n.nextSibling();  //下一个兄弟节点
	}

	return APR_SUCCESS;
}

//台账更新部分///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
std::string LEDGER_UPDATE_DIR = "../etc/ledgerupdate/";

std::list<std::string> find_xml_belong_to_this_process() 
{
    char prefix[20];  // 假设最多需要20个字符（根据实际需要调整）
    sprintf(prefix, "%d_%d", g_node_id, g_front_seg_index);  // 将g_node_id和g_front_seg_index格式化为字符串

    DIR *dir = opendir(LEDGER_UPDATE_DIR.c_str());  // 打开目录
    struct dirent *entry;
    std::list<std::string> found_files;  // 用于存储找到的所有匹配文件名

    if (dir == NULL) {
        std::cout << "Failed to open directory: " << LEDGER_UPDATE_DIR << std::endl;
        return found_files;  // 返回空的list
    }

	//std::cout << "we should find file with prefix:" << prefix << std::endl;

    // 遍历目录中的所有文件
    while ((entry = readdir(dir)) != NULL) {
        std::string filename = entry->d_name;

		// 排除 "." 和 ".." 目录
    	if (filename == "." || filename == "..") {
        	continue;
    	}

		std::cout << "find" << filename << "in" << LEDGER_UPDATE_DIR << std::endl;

		//std::cout << "filename.find(prefix):" << filename.find(prefix) << std::endl;

		//std::cout << "filename.substr(filename.find_last_of('.') + 1)" << filename.substr(filename.find_last_of('.') + 1) << std::endl;

        // 判断文件名是否以 prefix 开头且扩展名是 .xml
        if (filename.find(prefix) == 0 && filename.substr(filename.find_last_of('.') + 1) == "xml") {
            std::string full_path = LEDGER_UPDATE_DIR + filename;
            found_files.push_back(full_path);  // 将完整路径加入容器
        }
    }

    closedir(dir);  // 关闭目录

    return found_files;  // 返回所有找到的文件名
}

// 提取标签中的值的通用函数
std::string extract_value(const std::string& data, const std::string& tag) {
    size_t start_pos = data.find("<" + tag + ">");
    if (start_pos == std::string::npos) return "";
    size_t end_pos = data.find("</" + tag + ">", start_pos);
    if (end_pos == std::string::npos) return "";

    return data.substr(start_pos + tag.length() + 2, end_pos - start_pos - tag.length() - 2);
}

// 根据 str_tag 将 terminal 添加到对应的数组
void add_terminal_to_trigger_update(trigger_update_xml_t* trigger_update_xml, const std::string& str_tag, const terminal& work_terminal) {
    if (str_tag == "add") {
		std::cout << "new ledger!!!!"<<std::endl;
        if (trigger_update_xml->new_update_num < MAX_UPDATEA_NUM) {
            trigger_update_xml->new_updates[trigger_update_xml->new_update_num] = work_terminal;
            trigger_update_xml->new_update_num+= 1;  // 更新新终端的数量
        } else {
            std::cerr << "Exceeded MAX_UPDATEA_NUM limit for new updates!" << std::endl;
        }
    } 
    else if (str_tag == "modify") {
		std::cout << "modify ledger!!!"<<std::endl;
        if (trigger_update_xml->modify_update_num < MAX_UPDATEA_NUM) {
            trigger_update_xml->modify_updates[trigger_update_xml->modify_update_num] = work_terminal;
            trigger_update_xml->modify_update_num+= 1;  // 更新修改终端的数量
        } else {
            std::cerr << "Exceeded MAX_UPDATEA_NUM limit for modify updates!" << std::endl;
        }
    }
    else {
        std::cerr << "Unknown tag: " << str_tag << std::endl;
    }
}

// 解析 XML 数据并提取 terminal 信息
void parse_terminal_from_data(trigger_update_xml_t* trigger_update_xml, const std::string& str_tag, const std::string& data) {
    terminal work_terminal = {};  // 创建新的 terminal 对象

    // 提取各个字段
    strcpy(work_terminal.terminal_id, extract_value(data, "id").c_str());
    strcpy(work_terminal.terminal_code, extract_value(data, "terminalCode").c_str());
    strcpy(work_terminal.org_name, extract_value(data, "orgName").c_str());
    strcpy(work_terminal.maint_name, extract_value(data, "maintName").c_str());
    strcpy(work_terminal.station_name, extract_value(data, "stationName").c_str());
    strcpy(work_terminal.tmnl_factory, extract_value(data, "manufacturer").c_str());
    strcpy(work_terminal.tmnl_status, extract_value(data, "status").c_str());
    strcpy(work_terminal.dev_type, extract_value(data, "devType").c_str());
    strcpy(work_terminal.dev_key, extract_value(data, "devKey").c_str());
    strcpy(work_terminal.dev_series, extract_value(data, "series").c_str());
	strcpy(work_terminal.processNo, extract_value(data, "processNo").c_str());
    strcpy(work_terminal.addr_str, extract_value(data, "ip").c_str());
    strcpy(work_terminal.port, extract_value(data, "port").c_str());
    strcpy(work_terminal.timestamp, extract_value(data, "updateTime").c_str());

    size_t monitor_pos = 0;
	size_t monitor_count = 0;

	// 查找每个 monitorData，最多处理 10 个
	while ((monitor_pos = data.find("<monitorData", monitor_pos)) != std::string::npos && monitor_count < 10) {
	    monitor work_monitor = {};  // 创建新的 monitor 对象

	    // 找到当前 monitorData 的结束位置
	    size_t monitor_end_pos = data.find("</monitorData", monitor_pos);
	    std::string monitor_data = data.substr(monitor_pos, monitor_end_pos - monitor_pos);

	    // 提取各个字段并填充到 work_monitor 中
	    std::string monitor_id = extract_value(monitor_data, "id");
	    std::string monitor_name = extract_value(monitor_data, "name");
	    std::string voltage_level = extract_value(monitor_data, "voltageLevel");
	    std::string terminal_connect = extract_value(monitor_data, "ptType");
	    std::string line_no = extract_value(monitor_data, "lineNo");
	    std::string timestamp = extract_value(monitor_data, "timestamp");
	    std::string terminal_code = extract_value(monitor_data, "terminal_code");
	    std::string status = extract_value(monitor_data, "status");

	    // 将提取的数据复制到 work_monitor 中，若没有数据则复制 "N/A"
	    strcpy(work_monitor.monitor_id, monitor_id.empty() ? "N/A" : monitor_id.c_str());
	    strcpy(work_monitor.monitor_name, monitor_name.empty() ? "N/A" : monitor_name.c_str());
	    strcpy(work_monitor.voltage_level, voltage_level.empty() ? "N/A" : voltage_level.c_str());
	    strcpy(work_monitor.terminal_connect, terminal_connect.empty() ? "N/A" : terminal_connect.c_str());
	    strcpy(work_monitor.logical_device_seq, line_no.empty() ? "N/A" : line_no.c_str());
	    strcpy(work_monitor.timestamp, timestamp.empty() ? "N/A" : timestamp.c_str());
	    strcpy(work_monitor.terminal_code, terminal_code.empty() ? "N/A" : terminal_code.c_str());
	    strcpy(work_monitor.status, status.empty() ? "N/A" : status.c_str());

	    // 将提取的 monitor 数据存入 work_terminal.line[monitor_count]
	    work_terminal.line[monitor_count] = work_monitor;

	    monitor_count++;  // 增加 monitor 的计数
	    monitor_pos = monitor_end_pos;  // 移动 monitor_pos 到下一个 <monitorData> 的位置
	}


    // 根据 str_tag 将 terminal 添加到相应的数组
    add_terminal_to_trigger_update(trigger_update_xml, str_tag, work_terminal);
}

void parse_ledger_update(trigger_update_xml_t* trigger_update_xml, const std::string& strTag, const std::string& data) 
{
	std::cout << "record one xml.."<<std::endl;
    // 根据 strTag 做不同处理
    if (strTag == "add" || strTag == "modify") {

        // 填充终端信息
        parse_terminal_from_data(trigger_update_xml, strTag, data);

    }else if (strTag == "delete") {

        terminal delete_terminal;
        memset(&delete_terminal, 0, sizeof(delete_terminal));
        
        if (strTag == "delete") {
			// 填充终端信息
			strcpy(delete_terminal.terminal_id, extract_value(data, "id").c_str());
            // 将删除信息写入 delete_updates
			std::cout << "delete ledger!!!!!"<<std::endl;
            if (trigger_update_xml->delete_update_num < MAX_UPDATEA_NUM) {
                trigger_update_xml->delete_updates[trigger_update_xml->delete_update_num] = delete_terminal;
                trigger_update_xml->delete_update_num += 1;  // 增加计数
            }
		}

    } else {
        std::cerr << "Unsupported strTag: " << strTag << std::endl;
    }
}


int load_ledger_update_from_xml(trigger_update_xml_t* trigger_update_xml, const std::string& xml_fn)
{
	std::cout << "start to load one xml.."<<std::endl;
    std::ifstream file(xml_fn.c_str());  // 打开XML文件
    if (!file.is_open()) {
        std::cerr << "Failed to open file: " << xml_fn << std::endl;
        return -1;
    }

    std::string line;
    std::stringstream file_content;
    
    // 读取文件内容
    while (std::getline(file, line)) {
        file_content << line << "\n";
    }
    file.close();

    std::string content = file_content.str();

    // 查找 <ledger_update> 标签
    size_t ledger_pos = content.find("<ledger_update>");
    if (ledger_pos == std::string::npos) {
        std::cerr << "ledger_update tag not found!" << std::endl;
        return -1;
    }

    // 查找 <add>, <delete>, <modify> 标签
    size_t add_pos = content.find("<add>", ledger_pos);
    size_t delete_pos = content.find("<delete>", ledger_pos);
    size_t modify_pos = content.find("<modify>", ledger_pos);

    // 确定哪个标签存在，并获取相应的位置
    size_t target_pos = std::string::npos;
    std::string target_tag;

    if (add_pos != std::string::npos) {
        target_pos = add_pos;
        target_tag = "add";
    } else if (delete_pos != std::string::npos) {
        target_pos = delete_pos;
        target_tag = "delete";
    } else if (modify_pos != std::string::npos) {
        target_pos = modify_pos;
        target_tag = "modify";
    }

	//没找到正确的标签退出处理
    if (target_pos == std::string::npos) {
        std::cerr << "No <add>, <delete>, or <modify> tag found!" << std::endl;
        return -1;
    }

    // 查找目标标签的结束位置
    size_t end_pos = content.find("</" + target_tag + ">", target_pos);
    if (end_pos == std::string::npos) {
        std::cerr << "Closing </" + target_tag + "> tag not found!" << std::endl;
        return -1;
    }

    // 提取目标标签的内容
    std::string target_content = content.substr(target_pos + target_tag.length() + 2, end_pos - (target_pos + target_tag.length() + 2));

    // 解析 <data> 和其中的内容
    size_t data_pos = 0;
    while ((data_pos = target_content.find("<terminalData>", data_pos)) != std::string::npos) {
        size_t data_end_pos = target_content.find("</terminalData>", data_pos);
        if (data_end_pos == std::string::npos) {
            std::cerr << "Closing </terminalData> tag not found!" << std::endl;
            return -1;
        }

        std::string data_content = target_content.substr(data_pos + 14, data_end_pos - (data_pos + 14));
        
		std::cout << "ledger data_content is " << data_content <<std::endl;

        // 调用parse_ledger_update处理台账的内容
        parse_ledger_update(trigger_update_xml, target_tag, data_content);

        // 移动到下一个<terminalData>标签，目前每个文件只有一个台账
        data_pos = data_end_pos + 15;
    }

	std::cout << "load one xml finish"<<std::endl;

    return 0;  // 成功返回
}

int parse_ledger_update_xml(trigger_update_xml_t* trigger_update_xml)
{
	//printf("begin ledger update xml...\n");

	std::list<std::string> result = find_xml_belong_to_this_process();

    if (!result.empty()) {
        std::cout << "Found XML files:" << std::endl;
        for (std::list<std::string>::iterator it = result.begin(); it != result.end(); ++it) {
		    const std::string& filename = *it;
		    std::cout << filename << std::endl;
		    //解析每个文件，提取终端，判断终端是否满足更新条件
		    apr_sleep(apr_time_from_sec(1) / 10);
		    //加载一个文件的内容到数据结构
		    if (!load_ledger_update_from_xml(trigger_update_xml, filename)) {
		        std::cout << "read /etc/ledgerupdate/" << filename << " success..." << std::endl;
		    }
		    //处理过的文件删除掉
		    
		    if (std::remove(filename.c_str()) != 0) {
		        std::cerr << "Failed to remove file: " << filename << " Error: " << strerror(errno) << std::endl;
		        return APR_EGENERAL;
		    }
			else{
				std::cout << "remove file: " << filename << " success..." << std::endl;
			}
		}
    } 
	else {
        std::cout << "No matching XML files found." << std::endl;
		return APR_EGENERAL;
    }

	//有数据返回成功，后续进行处理
	//printf("Modify Update Count: %d\n", trigger_update_xml->modify_update_num);
	//printf("Delete Update Count: %d\n", trigger_update_xml->delete_update_num);
	//printf("New Update Count: %d\n", trigger_update_xml->new_update_num);
	if(trigger_update_xml->modify_update_num || trigger_update_xml->delete_update_num || trigger_update_xml->new_update_num){
		printf("ledger update xml have data...\n");
		return APR_SUCCESS;
	}
	else{//无数据返回失败，后续不处理
		printf("ledger update xml no data...\n");
		return APR_EGENERAL;
	}
		
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//实时触发部分/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
QString THREE_SECS_WEBSERVICE_DIR = QString("../etc/trigger3s/");

QString get_3s_trig_fn()
{
	QDir directory(THREE_SECS_WEBSERVICE_DIR);
	QStringList filters = QStringList() << "*.xml";
	QStringList fileNames = directory.entryList(filters, QDir::Files, QDir::Time/*|QDir::Reversed*/);
	if (fileNames.size() > 0)
		return fileNames.at(0);
	else
		return "";
}
///////////////////////////////////////////////////////////////
int getValueFromElemAttrStr(QString str)
{
	if (str == "true")
		return 1;
	else if (str == "false")
		return 0;
	else
		return -1;
}

//lnk20241125添加打印调试用/////////////////////////////////////////////////////////////////////////////////////////////////
// 打印 trigger_t 结构体的函数
void print_trigger(const trigger_t& trigger) {
    printf("  dev_idx: %d, line_id: %d, real_data: %d, soe_data: %d, limit: %d, count: %d\n",
           trigger.dev_idx, trigger.line_id, trigger.real_data, trigger.soe_data, trigger.limit, trigger.count);
}
// 打印 trigger_3s_xml_t 结构体的函数
void print_trigger_3s_xml(const trigger_3s_xml_t& trigger_3s_xml) {
    printf("Work Trigger Count: %d\n", trigger_3s_xml.work_trigger_num);
    for (int i = 0; i < trigger_3s_xml.work_trigger_num; ++i) {
        printf("  Work Trigger [%d]:\n", i + 1);
        print_trigger(trigger_3s_xml.work_triggers[i]);
    }

    printf("New Trigger Count: %d\n", trigger_3s_xml.new_trigger_num);
    for (int i = 0; i < trigger_3s_xml.new_trigger_num; ++i) {
        printf("  New Trigger [%d]:\n", i + 1);
        print_trigger(trigger_3s_xml.new_triggers[i]);
    }

    printf("Delete Trigger Count: %d\n", trigger_3s_xml.delete_trigger_num);
    for (int i = 0; i < trigger_3s_xml.delete_trigger_num; ++i) {
        printf("  Delete Trigger [%d]:\n", i + 1);
        print_trigger(trigger_3s_xml.delete_triggers[i]);
    }

    printf("Modify Trigger Count: %d\n", trigger_3s_xml.modify_trigger_num);
    for (int i = 0; i < trigger_3s_xml.modify_trigger_num; ++i) {
        printf("  Modify Trigger [%d]:\n", i + 1);
        print_trigger(trigger_3s_xml.modify_triggers[i]);
    }
}

//实时触发文件处理部分//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void parse_3s_trigger(trigger_3s_xml_t* trigger_3s_xml, QString parentTag, QDomElement& trigger_e)
{
	QString e_atr("");
	trigger_t trigger;

	trigger.dev_idx = trigger_e.attribute("DevSeries").toInt();
	trigger.line_id = trigger_e.attribute("Line").toInt();

	e_atr = trigger_e.attribute("RealData").toLower();
	trigger.real_data = getValueFromElemAttrStr(e_atr);

	e_atr = trigger_e.attribute("SOEData").toLower();
	trigger.soe_data = getValueFromElemAttrStr(e_atr);

	trigger.limit = trigger_e.attribute("Limit").toInt();
	trigger.count = trigger_e.attribute("Count").toInt();
	//qDebug()<<parentTag << "-> " << dev_idx<<" "<<line_id<<" "<<real_data<<" "<<soe_data <<" " <<  limit<<" " << count;

	if (parentTag == "Work") {
		trigger_3s_xml->work_triggers[trigger_3s_xml->work_trigger_num++] = trigger;
	}
	else if (parentTag == "New") {
		trigger_3s_xml->new_triggers[trigger_3s_xml->new_trigger_num++] = trigger;
	}
	else if (parentTag == "Delete") {
		trigger_3s_xml->delete_triggers[trigger_3s_xml->delete_trigger_num++] = trigger;
	}
	else if (parentTag == "Modify") {
		trigger_3s_xml->modify_triggers[trigger_3s_xml->modify_trigger_num++] = trigger;
	}
	//调试用lnk20241125
	print_trigger_3s_xml(*trigger_3s_xml);

}

int load_3s_data_from_xml(trigger_3s_xml_t* trigger_3s_xml, QString xml_fn)
{
	QDomDocument doc;   //新建QDomDocument类对象，它代表一个XML文档
	QFile file(xml_fn);
	if (!file.open(QIODevice::ReadOnly))
		return APR_EBADPATH;  //以只读方式打开
	bool ret = doc.setContent(&file);
	file.close();
	if (!ret)
		return APR_EBADF;

	//将文件内容读到doc中
	QDomElement docElem = doc.documentElement();  //返回根元素  
	QDomNode n = docElem.firstChild();   //返回根节点的第一个子节点 
	while (!n.isNull()) {   //如果节点不为空  
		if (n.isElement()) {   //如果节点是元素  	
			QDomElement e = n.toElement();  //将其转换为元素  
			QString strTag = e.tagName();
			if (strTag == "Work" || strTag == "New" || strTag == "Delete" || strTag == "Modify") {
				QDomNodeList list = e.childNodes(); //获得元素e的所有子节点的列表  
				for (int i = 0; i < list.count(); i++) {  //遍历该列表  				
					QDomNode node = list.at(i);
					if (node.isElement()) {
						QDomElement trigger_e = node.toElement();
						QString strTag2 = trigger_e.tagName();
						if (strTag2 == "Trigger") {
							parse_3s_trigger(trigger_3s_xml, strTag, trigger_e);
						} //else if ( strTag == "Trigger" )
					}
				}
			}
		}
		n = n.nextSibling();  //下一个兄弟节点
	}

	return APR_SUCCESS;
}

QString BAK_WEBSERVICE_3S_TRIG_COMMAND_XML_FN = THREE_SECS_WEBSERVICE_DIR + "bak_3s_trig_command.txt";
int parse_3s_xml(trigger_3s_xml_t* trigger_3s_xml)
{
	printf("begin 3s xml...\n");
	memset(trigger_3s_xml, 0, sizeof(trigger_3s_xml_t));

	//这个文件是用来记录正在进行中的实时触发
	QString cfg_dir = QString("../")/*+QString::fromAscii(subdir)*/ + QString("etc/");
	load_3s_data_from_xml(trigger_3s_xml, (cfg_dir + THREE_SECS_CONFIG_FN));	//加载/Feproject/etc/Trigger3S.xml

	QString the_webservice_xml_fn = get_3s_trig_fn();//  ../etc/trigger3s/目录下的最新的xml文件，这个文件是用来打开实时触发的开关

	printf("the_webservice_xml_fn.size():%d\n",the_webservice_xml_fn.size());

	if (the_webservice_xml_fn.size() > 4) {//文件名大于4说明找到文件
		apr_sleep(apr_time_from_sec(1) / 10);
		the_webservice_xml_fn = THREE_SECS_WEBSERVICE_DIR + the_webservice_xml_fn;
		load_3s_data_from_xml(trigger_3s_xml, the_webservice_xml_fn);
		QFile::remove(BAK_WEBSERVICE_3S_TRIG_COMMAND_XML_FN);
		QFile::rename(the_webservice_xml_fn, BAK_WEBSERVICE_3S_TRIG_COMMAND_XML_FN);

		printf("/etc/trigger3s/*.xml success...\n");
		return APR_SUCCESS;
	}

	printf("3s xml fail...\n");
	return APR_EGENERAL;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//3s触发记录写入文件
void append_triggers(QDomDocument& doc, QDomElement& root, QString parentTag, trigger_t* trigger, int trigger_num)
{
	QString str;
	QDomElement funcItem = doc.createElement(parentTag);
	root.appendChild(funcItem);
	for (int i = 0; i < trigger_num; i++) {
		if (trigger[i].dev_idx == INVALID_DEV_IDX)
			continue;
		if (trigger[i].real_data == 0 && trigger[i].soe_data == 0)
			continue;
		QDomElement triggerItem = doc.createElement("Trigger");
		triggerItem.setAttribute("DevSeries", trigger[i].dev_idx);
		triggerItem.setAttribute("Line", trigger[i].line_id);
		str = trigger[i].real_data ? "true" : "false";
		triggerItem.setAttribute("RealData", str);
		str = trigger[i].soe_data ? "true" : "false";
		triggerItem.setAttribute("SOEData", str);
		triggerItem.setAttribute("Limit", trigger[i].limit);
		triggerItem.setAttribute("Count", trigger[i].count);
		funcItem.appendChild(triggerItem);
	}
}

int create_3s_xml(trigger_3s_xml_t* trigger_3s_xml)
{

	QDomDocument doc;
	doc.appendChild(doc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"gb2312\""));

	QDomElement root = doc.createElement("Trigger3S");
	doc.appendChild(root);

	append_triggers(doc, root, "Work", trigger_3s_xml->work_triggers, trigger_3s_xml->work_trigger_num);
	append_triggers(doc, root, "New", trigger_3s_xml->new_triggers, 0);
	append_triggers(doc, root, "Delete", trigger_3s_xml->delete_triggers, 0);
	append_triggers(doc, root, "Modify", trigger_3s_xml->modify_triggers, 0);

	QString cfg_dir = QString("../")/*+QString::fromAscii(subdir)*/ + QString("etc/");
	QFile file(cfg_dir + THREE_SECS_CONFIG_FN /*+".bak.xml"*/);
	if (!file.open(QIODevice::ReadWrite | QIODevice::Truncate | QIODevice::Text)) {
		return -1;
	}
	QTextStream out(&file);
	out.setCodec("gb2312");
	doc.save(out, 4);
	file.close();

	return APR_SUCCESS;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 函数功能：从指定的 .cfg 配置文件中提取起始时间和触发时间，并将其转化为毫秒级时间戳。
// 输入参数：
//    - comtrade_fn：输入的文件名，作为参考用于定位对应的 .cfg 配置文件。
// 输出参数：
//    - start_tm：返回的起始时间戳（单位：毫秒）。
//    - trig_tm：返回的触发时间戳（单位：毫秒）。
// 返回值：
//    - 返回 APR_SUCCESS 表示成功，返回 APR_EBADF 表示文件错误。
int extract_timestamp_from_cfg_file(char* comtrade_fn, long long* start_tm, long long* trig_tm)
{
    // 获取文件名信息，路径和文件名提取
    QFileInfo fi(QString::fromAscii(comtrade_fn));
    QString fn = fi.fileName();
    QString cfgFileName_temp = QString("../comtrade/") + fn;  // 拼接.cfg文件的路径

    // 检查文件是否以 ".cfg" 或 ".CFG" 结尾
    if (!cfgFileName_temp.endsWith(".cfg", Qt::CaseInsensitive) && !cfgFileName_temp.endsWith(".CFG", Qt::CaseInsensitive))
        return APR_EBADF;  // 如果文件名不符合要求，返回文件错误

    // 打开配置文件
    QFile cfgFile_temp(cfgFileName_temp);
    if (!cfgFile_temp.exists()) {  // 如果文件不存在
        qDebug() << QString("Cannot find corresponding .cfg file: %1").arg(cfgFileName_temp);
        cfgFile_temp.close();
        return APR_EBADF;
    }
    else if (!cfgFile_temp.open(QFile::ReadOnly | QFile::Text)) {  // 如果文件无法打开
        qDebug() << QString("Cannot open file %1:\n%2.").arg(cfgFileName_temp).arg(cfgFile_temp.errorString());
        return APR_EBADF;
    }
    else {
        QStringList datContentList_temp;
        QTextStream in_temp(&cfgFile_temp);  // 创建文本流读取文件
        // 忽略 GBK 编码相关的代码（被注释掉了）

        QString start_time_str("");  // 用于存储起始时间字符串
        QString trigger_time_str("");  // 用于存储触发时间字符串

        // 按行读取配置文件内容
        while (!in_temp.atEnd()) {
            QString line_temp = in_temp.readLine().trimmed();  // 读取并去除空白字符
            QString upper_line_temp = line_temp.toUpper();  // 转换为大写字符

            // 如果读取到 "ASCII" 或 "BINARY" 字符串，则停止处理
            if ((upper_line_temp == QString("ASCII")) || (upper_line_temp == QString("BINARY")))
                break;
            else {
                // 如果没有，更新起始时间和触发时间
                start_time_str = trigger_time_str;
                trigger_time_str = line_temp;
            }
        }

        // 如果提取到的 start_time_str 长度大于3，则去掉最后3个字符（通常是毫秒部分）
        if (start_time_str.size() > 3)
            start_time_str = start_time_str.left(start_time_str.size() - 3);

        // 将 start_time_str 转换为 QDateTime 对象，并转换为自纪元以来的毫秒数
        QDateTime start_time_dt = QDateTime::fromString(start_time_str, "dd/MM/yyyy,hh:mm:ss.zzz");
        *start_tm = start_time_dt.toMSecsSinceEpoch();  // 转换为毫秒时间戳并赋值给 start_tm

        // 同样处理触发时间（去掉最后3个字符并转换为时间戳）
        if (trigger_time_str.size() > 3)
            trigger_time_str = trigger_time_str.left(trigger_time_str.size() - 3);

        QDateTime trigger_time_dt = QDateTime::fromString(trigger_time_str, "dd/MM/yyyy,hh:mm:ss.zzz");
        *trig_tm = trigger_time_dt.toMSecsSinceEpoch();  // 转换为毫秒时间戳并赋值给 trig_tm

        cfgFile_temp.close();  // 关闭文件
    }
    
    return APR_SUCCESS;  // 成功返回
}
#if 0
int extract_timestamp_from_cfg_file(char* comtrade_fn, long long* start_tm, long long* trig_tm)
{
	QFileInfo fi(QString::fromAscii(comtrade_fn));
	QString fn = fi.fileName();
	QString cfgFileName_temp = QString("../comtrade/") + fn;
	if (!cfgFileName_temp.endsWith(".cfg", Qt::CaseInsensitive) && !cfgFileName_temp.endsWith(".CFG", Qt::CaseInsensitive))//fn_str.endsWith(".cfg", Qt::CaseInsensitive) || fn_str.endsWith(".CFG", Qt::CaseInsensitive)
		return APR_EBADF;

	QFile cfgFile_temp(cfgFileName_temp);
	if (!cfgFile_temp.exists()) {
		qDebug() << QString("Cannot find corresponding .cfg file: %1").arg(cfgFileName_temp);
		cfgFile_temp.close();
		return APR_EBADF;
	}
	else if (!cfgFile_temp.open(QFile::ReadOnly | QFile::Text)) {
		qDebug() << QString("Cannot open file %1:\n%2.").arg(cfgFileName_temp).arg(cfgFile_temp.errorString());
		return APR_EBADF;
	}
	else {
		QStringList datContentList_temp;
		QTextStream in_temp(&cfgFile_temp);
		/*QTextCodec *codec_temp=QTextCodec::codecForName("gbk");
		in_temp.setCodec(codec_temp);*/
		QString start_time_str("");
		QString trigger_time_str("");
		while (!in_temp.atEnd()) {
			QString line_temp = in_temp.readLine().trimmed();
			QString upper_line_temp = line_temp.toUpper();
			if ((upper_line_temp == QString("ASCII")) || (upper_line_temp == QString("BINARY")))
				break;
			else {
				start_time_str = trigger_time_str;
				trigger_time_str = line_temp;
			}
		}
		//11/05/2018,15:28:53.343000
		if (start_time_str.size() > 3)
			start_time_str = start_time_str.left(start_time_str.size() - 3);
		QDateTime start_time_dt = QDateTime::fromString(start_time_str, "dd/MM/yyyy,hh:mm:ss.zzz");
		*start_tm = start_time_dt.toMSecsSinceEpoch();

		if (trigger_time_str.size() > 3)
			trigger_time_str = trigger_time_str.left(trigger_time_str.size() - 3);
		QDateTime trigger_time_dt = QDateTime::fromString(trigger_time_str, "dd/MM/yyyy,hh:mm:ss.zzz");
		*trig_tm = trigger_time_dt.toMSecsSinceEpoch();

		cfgFile_temp.close();
	}
	return APR_SUCCESS;
}
#endif
//录波部分///////////////////////////////////////////////////////////////////////////////
//WW 2023-11-01 增加录波段号采用int类型匹配
int parse_file_names_by_fltnum(int fltnum, char* domname, char** filenames, int filenum, int* cfg_idx, int* dat_idx, char* file_base_name, char* file_yyyymm)
{
	int j;
	printf(">>>>>>>>>>>>>>>>>>pares_file_names file list match fltnum=%d", fltnum);

	*cfg_idx = -1;
	*dat_idx = -1;
	for (j = 0; j < filenum; ++j) {

		char fileNameTemp[64];
		strcpy(fileNameTemp, filenames[j]); //临时存放 装置录波文件名
		printf(" %s ", fileNameTemp);
		if (strstr(fileNameTemp, domname) == NULL) //例：域名:"PQMonitor_PQM1" 不是 装置录波文件名:"PQMonitor_PQM1_000001_20191121_154534_689.CFG/.DAT/.HDR"的子串
			continue;
		char* p = strtok(fileNameTemp, "_"); //PQMonitor
		p = strtok(NULL, "_"); //PQM1
		p = strtok(NULL, "_"); //000001
		int nFltNum = atoi(p); //将字符转换成整型

		if (nFltNum == fltnum) {

			QString fn_str = QString::fromAscii(filenames[j]);
			if (fn_str.endsWith(".cfg", Qt::CaseInsensitive) || fn_str.endsWith(".CFG", Qt::CaseInsensitive)) {
				//PQMonitor_PQM4_000349_20180531_113701_618.CFG
				*cfg_idx = j;

				QFileInfo fi(fn_str);
				QString fn = fi.baseName();
				strcpy(file_base_name, fn.toAscii().data());

				QString remain_str = fn_str.split(QString::fromAscii(p)).at(1);
				QString yyyymm_str = remain_str.mid(1, 6);
				strcpy(file_yyyymm, yyyymm_str.toAscii().data());
			}
			else if (fn_str.endsWith(".dat", Qt::CaseInsensitive) || fn_str.endsWith(".DAT", Qt::CaseInsensitive))
				*dat_idx = j;

		}
		if (*cfg_idx != -1 && *dat_idx != -1)//两个文件都已经找到
			break;
	}

	printf("\n<<<<<<<<<<<<<<<<<<<<<pares_file_names file list match end cfg_inx=%d dat_idx=%d  \n", *cfg_idx, *dat_idx);
	if ((*cfg_idx) >= 0 && (*dat_idx) >= 0)
		return APR_SUCCESS;
	else
		return APR_EBADF;
}
//WW2023-11-01 end
int parse_file_names(char* file_match_str, char** filenames, int filenum, int* cfg_idx, int* dat_idx, char* file_base_name, char* file_yyyymm)
{
	int j;

	*cfg_idx = -1;
	*dat_idx = -1;
	for (j = 0; j < filenum; ++j) {
		if (strstr(filenames[j], file_match_str) != NULL) {
			QString fn_str = QString::fromAscii(filenames[j]);
			if (fn_str.endsWith(".cfg", Qt::CaseInsensitive)) {
				//PQMonitor_PQM4_000349_20180531_113701_618.CFG
				*cfg_idx = j;

				QFileInfo fi(fn_str);
				QString fn = fi.baseName();
				strcpy(file_base_name, fn.toAscii().data());

				QString remain_str = fn_str.split(QString::fromAscii(file_match_str)).at(1);
				QString yyyymm_str = remain_str.mid(1, 6);
				strcpy(file_yyyymm, yyyymm_str.toAscii().data());
			}
			else if (fn_str.endsWith(".dat", Qt::CaseInsensitive))
				*dat_idx = j;
		}
	}

	if ((*cfg_idx) >= 0 && (*dat_idx) >= 0)
		return APR_SUCCESS;
	else
		return APR_EBADF;
}

//补招部分////////////////////////////////////////////////////////////////////////////////

void parse_recall(recall_xml_t* recall_xml, QString parentTag, QDomElement& recall_e, char* id)
{
	recall_t recall;

	/*QString ied;
	ied.append(recall_e.attribute("MonitorID"));
	QByteArray byteArray = ied.toLocal8Bit();
	char* charArray = new char[byteArray.size()];
	memcpy(charArray, byteArray.data(), byteArray.size());
	charArray[byteArray.size()] = '\0';*/

	recall.line_id = id;

	QDateTime start_dt = QDateTime::fromString(recall_e.attribute("StartTime"), "yyyy-MM-dd hh:mm:ss");
	recall.start_time = start_dt.toMSecsSinceEpoch() / 1000;
	QDateTime end_dt = QDateTime::fromString(recall_e.attribute("EndTime"), "yyyy-MM-dd hh:mm:ss");
	recall.end_time = end_dt.toMSecsSinceEpoch() / 1000;

	recall.need_steady = recall_e.attribute("STEADY").toInt();
	recall.need_voltage = recall_e.attribute("VOLTAGE").toInt();

	qDebug() << parentTag << "-> " << " " << recall.line_id << " " << recall.need_steady << " " << recall.need_voltage
		<< " " << recall.start_time << " " << recall.end_time;

	if (parentTag == "Work") {
		recall_xml->work_recalls[recall_xml->work_recall_num++] = recall;
	}
	else if (parentTag == "New") {
		recall_xml->new_recalls[recall_xml->new_recall_num++] = recall;
	}
}

int delete_recall_xml(char* id)
{
	//	ied_t		*ied;
	//	ied_usr_t	*ied_usr;
	//	LD_info_t line_info;
	//	int	dev_idx_in_line = 0;
	QString cfg_dir = QString("../")/*+QString::fromAscii(subdir)*/ + QString("etc/recall");
	QString file_name = QString(subdir) + QString("_") + QString(QString::number(g_front_seg_index, 10)) + QString("_") + QString(id) + QString("_") + QString("*") + QString("_Recall.xml");

	//指定文件夹名
	QDir dir(cfg_dir);
	if (!dir.exists()) {
		qDebug() << "folder does not exist!";
		return false;
	}
	//指定文件后缀名，可指定多种类型
	//qDebug() << qstrRecallPath;
	QStringList filter(file_name);
	//指定查找类型和排序，按最新的修改时间获取
	QStringList files = dir.entryList(filter, QDir::Files | QDir::Readable | QDir::NoDotAndDotDot, QDir::Name | QDir::Time);
	for (int i = 0; i < files.size(); i++) {//清空读取文件
		QString qstrRecallPath = cfg_dir + QString("/") + files[i];
		QFile::remove(qstrRecallPath);
	}
	return APR_SUCCESS;
}

int parse_recall_xml(recall_xml_t* recall_xml, char* id)
{
	//	ied_t		*ied;
	//	ied_usr_t	*ied_usr;
	//	LD_info_t line_info;
	//	int	dev_idx_in_line = 0;
	QString cfg_dir = QString("../")/*+QString::fromAscii(subdir)*/ + QString("etc/recall");
	QString file_name = QString(subdir) + QString("_") + QString(QString::number(g_front_seg_index, 10)) + QString("_") + QString(id) + QString("_") + QString("*") + QString("_Recall.xml");
	//lnk20241225这里文件名
	//指定文件夹名
	QDir dir(cfg_dir);
	if (!dir.exists()) {
		qDebug() << "folder does not exist!";
		return false;
	}
	//指定文件后缀名，可指定多种类型
	//qDebug() << qstrRecallPath;
	QStringList filter(file_name);
	//指定查找类型和排序，按最新的修改时间获取
	QStringList files = dir.entryList(filter, QDir::Files | QDir::Readable | QDir::NoDotAndDotDot, QDir::Name | QDir::Time);
	for (int i = 0; i < files.size(); i++) {
		QString qstrRecallPath = cfg_dir + QString("/") + files[i];
		qDebug() << qstrRecallPath;

		QDomDocument doc;   //新建QDomDocument类对象，它代表一个XML文档
		QFile file(qstrRecallPath);
		if (!file.open(QIODevice::ReadOnly))
		{
			qDebug() << "file.open error";
			continue;  //以只读方式打开
		}
		bool ret = doc.setContent(&file);
		file.close();
		if (!ret)
		{
			qDebug() << "doc.setContent error";
			continue;
		}
		//将文件内容读到doc中
		QDomElement docElem = doc.documentElement();  //返回根元素  
		QDomNode n = docElem.firstChild();   //返回根节点的第一个子节点 
		while (!n.isNull()) {   //如果节点不为空  
			if (n.isElement()) {   //如果节点是元素  	
				QDomElement e = n.toElement();  //将其转换为元素  
				QString strTag = e.tagName();
				if (strTag == "Work" || strTag == "New") {
					QDomNodeList list = e.childNodes(); //获得元素e的所有子节点的列表  
					for (int i = 0; i < list.count(); i++) {  //遍历该列表  				
						QDomNode node = list.at(i);
						if (node.isElement()) {
							QDomElement  recall_e = node.toElement();
							QString strTag2 = recall_e.tagName();
							if (strTag2 == "Recall") {
								parse_recall(recall_xml, strTag, recall_e, id);
							} //else if ( strTag == "Trigger" )
						}
					}
				}
			}
			n = n.nextSibling();  //下一个兄弟节点
		}
	}

	//for (int i = 0; i < files.size(); i++) {//清空读取文件
	//	QString qstrRecallPath = cfg_dir + QString("/") + files[i];
	//	QFile::remove(qstrRecallPath);
	//}
	return APR_SUCCESS;
}

void process_recall_config(recall_xml_t* recall_xml)
{
	int			i, j;
	recall_t* recall;
	recall_t* recall_work;
	int			recall_num;
	int			need_write_file;
	QList<RecallInfo> recallinfo_list_hour;               //待补招队列-以小时为最大间隔

	need_write_file = FALSE;
	recall = recall_xml->new_recalls;
	recall_num = recall_xml->new_recall_num;
	for (i = 0; i < recall_num; i++) {
		recall_xml->work_recalls[recall_xml->work_recall_num++] = recall[i];
		need_write_file = TRUE;
	}

	recall = recall_xml->work_recalls;
	recall_num = recall_xml->work_recall_num;

	if (recall_num > 0) {
		LD_info_t* LD_info = find_LD_info_only_from_mp_id(recall[0].line_id);
		printf("\n recall[0].line_id == %s \n", recall[0].line_id);
		printf("\n recall[0].start_time == %d \n", recall[0].start_time);
		if (LD_info == NULL || LD_info->read_flag == 0) {
			printf("\n recall[0].line_id == NULL \n");
			printf("\n Find LD_info == null \n");
		}
		else {
			printf("\n Find LD_info != null \n");
			if (LD_info->autorecallflag != 0 || LD_info->autorecallcount == 0) {	//
				if (LD_info->autorecallcount != 0) {
					for (int j = 0; j < LD_info->autorecallcount; j++) {
						delete LD_info->autorecall[j];
					}
					delete LD_info->autorecall;
					LD_info->autorecallcount = 0;
				}
				LD_info->autorecallcount = recall_num;
				LD_info->autorecall = new autorecall_t * [recall_num];
				for (int j = 0; j < recall_num; j++) {
					printf("\n %d ===== %d\n", recall[j].start_time, recall[j].end_time);
					LD_info->autorecall[j] = new autorecall_t[1];
					LD_info->autorecall[j]->start = recall[j].start_time;

					LD_info->autorecall[j]->end = recall[j].end_time;

					//lnk20241030补充补招稳态暂态标志，每个文件都有很多条时间记录
					LD_info->autorecall[j]->need_steady = recall[j].need_steady;
					LD_info->autorecall[j]->need_steady = recall[j].need_voltage;

				}
				LD_info->autorecallflag = 0;


			}
		}
	}

}

int remove_recall_xml()
{
	QString cfg_dir = QString("../")/*+QString::fromAscii(subdir)*/ + QString("etc/");
	QString filename(cfg_dir + RECALL_CONFIG_FN);

	return QFile::remove(filename);
}
//////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////////WW 20230819 增加数据库连接函数
int OTLConnect() //OTL连接Oracle数据库
{
	try {
		otl_connect::otl_initialize(); //初始化OTL连接库的环境的静态函数
		//db.rlogon(g_strOTLConnect.c_str()); //连接数据库Oracle(用户名/密码)
		//db.rlogon("postgres", "dnzl@#001", "pgsql", 0);
		//db.rlogon("postgres", "1234567", "pgsql", 0);
		//db.rlogon("postgres", "bmdev@123", "pgsql", 0);
		db.rlogon(POSTGRES_USERNAME, POSTGRES_PASSWORD, POSTGRES_DNSNAME, 0);
		printf("\nPostgreSL\"%s\"connect succ\n", g_strOTLConnect.c_str());
	}
	catch (otl_exception& e)
	{
		//printf("\nPostgreSL\"%s\"failed,ERROR code= %d, msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg);
		if (e.code != 32031)
			printf("\nPostgreSL\"%s\"failed,ERROR code= %d, msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg);
		return e.code;
	}
	return 0;
}
int OTLDisconnect() //OTL断开Oracle数据库
{
	try {
		db.logoff();
		printf("\nPostgreSL\"%s\"disconnect\n\n", g_strOTLConnect.c_str());
	}
	catch (otl_exception& e)
	{
		printf("\nPostgreSL\"%s\"disconnect failed,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg);
		return e.code;
	}
	return 0;
}
int OTLTestSelect() //OTL连接Oracle数据库
{
	try {
		OTLConnect();
		//int rtState = OTLState();
		otl_stream i(1, // buffer size
			"select \"MODEL_ID\" from \"gaussdb\".\"MEAS_PQ_ICD_MODEL_TR\"",
			//SELECT statement
			db //connect object
		);
		//create select stream

		char f2[64];
		while (!i.eof()) { //while not end-of-data
			i >> f2;
			qDebug() << " MODEL_ID =" << f2 << endl;
		}
		OTLDisconnect();
	}
	catch (otl_exception& e)
	{
		printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg);
		return e.code;
	}
	return 0;

}

int OTLState() //OTL连接Oracle数据库状态
{
	try {
		otl_datetime tm;
		std::string strSql = "select sysdate from dual";
		//std::string strSql = "select * from pgsql_test_gy";

		otl_stream i(1, strSql.c_str(), db);
		if (!i.eof()) {
			i >> tm;
			QString qstrYear = QString("%1").arg(tm.year, 4, 10, QLatin1Char('0'));
			QString qstrMonth = QString("%1").arg(tm.month, 2, 10, QLatin1Char('0'));
			int iYear = qstrYear.toInt();
			int iMonth = qstrMonth.toInt();
			QString qCurrentYear = QDateTime::currentDateTime().toString("yyyy");
			QString qCurrentMonth = QDateTime::currentDateTime().toString("MM");
			if (!qstrYear.isEmpty() && !qstrMonth.isEmpty()) {
				if ((iYear >= 1970) || (iMonth >= 1))
					return 0;
				else {
					printf("qstrYear= %s，iYear= %d，qCurrentYear= %s且qstrMonth= %s，iMonth= %d，qCurrentMonth= %s不等，需检查数据库OTL连接！\n", qstrYear.toAscii().data(), iYear, qCurrentYear.toAscii().data(), qstrMonth.toAscii().data(), iMonth, qCurrentMonth.toAscii().data());
					return -1;
				}
			}
			else {
				printf("Sql查询系统日期qstrYear= %s或qstrMonth= %s为空，需检查数据库OTL连接！\n", qstrYear.toAscii().data(), qstrMonth.toAscii().data());
				return -1;
			}

			printf(">>>Sql查询系统日期qstrYear= %s，qCurrentYear= %s，qstrMonth= %s，qCurrentMonth= %s \n", qstrYear.toAscii().data(), qCurrentYear.toAscii().data(), qstrMonth.toAscii().data(), qCurrentMonth.toAscii().data());
		}
	}
	catch (otl_exception& e)
	{
		printf("Sql查询系统日期时间失败，ERROR code= %d, msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg);
		return e.code;
	}
	return 0;
}

int OTLDbconnected() {
	cout << "db.connect is :" << db.connected << endl;
	return db.connected;
}
////////////////////////////////////////////////////////////////////////////////数据库部分
int write_to_db(const char* sqlstm) //写数据库
{
	try {
		apr_sleep(apr_time_from_sec(1) / 1000);
		otl_stream i(1, sqlstm, db);
		i.flush();
		i.close();
		db.commit();

		printf(">>>当前写数据库Sql= %s\n", sqlstm);
	}
	catch (otl_exception& e)
	{
		if (e.code != 1)
		{
			printf("写数据库失败，code= %d，msg= %s，Sql= %s\n", e.code, e.msg, sqlstm);
			OTLConnect();
		}
		return e.code;
	}
	return 0;
}

void WebSocketThread::run()
{
	//if (g_node_id != THREE_SECS_DATA_BASE_NODE_ID)
	//	return;

	printf("WebSocketThread::run() is called ...... \n");
	struct sockaddr_in client_sockaddr;
	memset(&client_sockaddr, 0, sizeof(client_sockaddr));
	socklen_t address_len = 0;
	while (1) {
		address_len = sizeof(struct sockaddr_in);
		int client_socket = accept(server_socket, (struct sockaddr*)&client_sockaddr, &address_len);
		if (client_socket == -1)
		{
			printf("accept client %s:%d failed,error msg=%s\n\a", inet_ntoa(client_sockaddr.sin_addr), htons(client_sockaddr.sin_port), strerror(errno));
			continue;
		}
		printf("\naccept client %s:%d succes，address_len= %d，client_socket= %d\n", inet_ntoa(client_sockaddr.sin_addr), htons(client_sockaddr.sin_port), address_len, client_socket);

		char buffer[256];
		int iRet = 0;
		while (1) {
			memset(buffer, 0, sizeof(buffer));
			int recvLength = recv(client_socket, buffer, sizeof(buffer), 0);
			if (recvLength > 0)
			{
				iRet = HandleReceiveMessage(client_socket, buffer);

				//if (0 != iRet)
				//	iRet = SendMessageToWeb(client_socket, iRet);
				break;
			}
			else
			{
				if (errno == EINTR)
					continue;
				printf("end socket client %d(%s:%d) msg,disconnetc Socket client\n", client_socket, inet_ntoa(client_sockaddr.sin_addr), htons(client_sockaddr.sin_port));
				break;
			}
		}

		close(client_socket);
		printf("close socket client %d(%s:%d) \n", client_socket, inet_ntoa(client_sockaddr.sin_addr), htons(client_sockaddr.sin_port));
		msleep(1);
	}

	close(server_socket);
	return;
}

string MatchErrorMessage(int errorCode) //根据错误码匹配错误消息
{
	string strErrorMessage = "";
	switch (errorCode)
	{
	case 0:
		strErrorMessage = "success"; //"成功"
		break;
	default:
		strErrorMessage = "error"; //"错误";
		break;
		//case 10002:
		//	strErrorMessage = "Incorrect message length structure"; //"报文长度结构错误";
		//	break;
		//case 10003:
		//	strErrorMessage = "JSON string parsing error"; //"JSON字符串解析出错";
		//	break;
		//case 10004:
		//	strErrorMessage = "Socket handling error"; //"socket处理出现异常";
		//	break;
		//case 10005:
		//	strErrorMessage = "The device corresponding to ID was not found"; //"ID对应的装置未找到";
		//	break;
		//case 10006:
		//	strErrorMessage = "The monitoring point corresponding to ID has not been found"; //"ID对应的监测点未找到";
		//	break;
		//case 10007:
		//	strErrorMessage = "Wrong parameter passed in"; //"传入的参数异常";
		//	break;
		//case 10008:
		//	strErrorMessage = "The same type of operation is being performed"; //"有同一类型的操作正在执行";
		//	break;
		//case 10009:
		//	strErrorMessage = "The device turned off the corresponding function"; //"装置关闭了对应功能";
		//	break;
		//case 10010:
		//	strErrorMessage = "The TYPE parameter passed in is exceptional"; //"传入的TYPE参数异常";
		//	break;
		//default:
		//	strErrorMessage = "An unknown error"; //"未知错误";
		//	break;
	}

	return strErrorMessage;
}

int SendMessageToWeb(int socketClient, int iErrorCode) //向Web Socket客户端发送消息
{
	string strSendJson = "";
	char cTemp[8];
	string strErrorCode = "";
	sprintf(cTemp, "%06d", iErrorCode);
	strErrorCode = cTemp;
	char sendBuffer[256];
	int sendLength = 0;

	string strErrorMessage = MatchErrorMessage(iErrorCode);
	//if (2 == Log_Enable)
	//	printf("错误码：%d，匹配到的消息：%s\n", iErrorCode, strErrorMessage.c_str());

	strSendJson = "{\"errors\":\"" + strErrorMessage + "\",\"status\":\"" + strErrorCode + "\"}";
	strcpy(sendBuffer, strSendJson.c_str());
	sendLength = send(socketClient, strSendJson.c_str(), strSendJson.length() + 1, 0);
	if (-1 == sendLength)
	{
		printf("服务端向客户端%d发送[%d]消息错误，错误消息：%s\n", socketClient, iErrorCode, strSendJson.c_str());
		return -1;
	}

	//if (1 == Log_Enable)
	//	printf("服务端向客户端%d发送[%d]消息：%s\n", socketClient, iErrorCode, sendBuffer);

	return sendLength;
}

int ExecuteWebCommand(LD_info_t* LD_info, int iType) //执行Web Socket命令消息
{
	try
	{
		//if (1 == Log_Enable)
		//	printf(">>>线路%d，\"%s\"，iType= %d，real_data= %s，soe_data= %s，limit= %d，count= %d\n", LD_info->line_id, LD_info->name,
		//		iType, 0 == LD_info->real_data ? "False" : "True", 0 == LD_info->soe_data ? "False" : "True", 20, LD_info->count);

		if (0 == iType || 1 == iType)
		{
			LD_info->count = 0;
			if (0 == iType)
			{
				LD_info->real_data = 1;
				LD_info->soe_data = 1;
				//if (1 == Log_Enable)
				//	printf(">>>触发%d，\"%s\"，iType= %d，real_data= %s，soe_data= %s，limit= %d，count= %d\n", LD_info->line_id, LD_info->name,
				//		iType, 0 == LD_info->real_data ? "False" : "True", 0 == LD_info->soe_data ? "False" : "True", 20, LD_info->count);
			}
			else
			{
				//LD_info->heart_beat = 1;
				//if (1 == Log_Enable)
				//	printf(">>>持续%d，\"%s\"，iType= %d，real_data= %s，soe_data= %s，limit= %d，count= %d\n", LD_info->line_id, LD_info->name,
				//		iType, 0 == LD_info->real_data ? "False" : "True", 0 == LD_info->soe_data ? "False" : "True", 20, LD_info->count);
			}
		}

		if (2 == iType)
		{
			LD_info->real_data = 0;
			LD_info->soe_data = 0;
			//if (1 == Log_Enable)
			//	printf(">>>停止%d，\"%s\"，iType= %d，real_data= %s，soe_data= %s，limit= %d，count= %d\n", LD_info->line_id, LD_info->name,
			//		iType, 0 == LD_info->real_data ? "False" : "True", 0 == LD_info->soe_data ? "False" : "True", 20, LD_info->count);
		}
	}
	catch (exception& e)
	{
		printf("触发/停止线路%d，\"%s\"失败，原因：%s\n", LD_info->line_id, LD_info->name, e.what());
		return 10004;
	}

	return 10000;
}

void Get_Recall_Time_Char(char* start_time, char* end_time, QList<RecallInfo>& recallinfo_list_hour) //数据完整性补招判断
{

	QDateTime start_dt = QDateTime::fromString(start_time, "yyyy-MM-dd HH:mm:ss");
	QDateTime end_dt = QDateTime::fromString(end_time, "yyyy-MM-dd HH:mm:ss");

	long long starttime = start_dt.toMSecsSinceEpoch() / 1000;  //补招起始时间
	long long endtime = end_dt.toMSecsSinceEpoch() / 1000;                //补招结束时间
	QList<long long> timestamp_list;                      //数据库完整性记录时间点
	QList<RecallInfo> recallinfo_list;                    //待补招队列
	//QList<RecallInfo> recallinfo_list_hour;               //待补招队列-以小时为最大间隔


	RecallInfo info;
	info.starttime = starttime;
	info.endtime = endtime;
	recallinfo_list.append(info);

	for (int i = 0; i < recallinfo_list.size(); i++)
	{
		//printf("\n %lld ----- %11d\n", recallinfo_list[i].starttime, recallinfo_list[i].endtime);
		long long duration = recallinfo_list[i].endtime - recallinfo_list[i].starttime;
		long long max_interval = 3600;
		for (long long j = 0; j <= duration; j += max_interval)
		{
			if (j + max_interval > duration) {
				long long start = recallinfo_list[i].starttime + j;
				long long end = recallinfo_list[i].endtime;

				RecallInfo info;
				info.starttime = start;
				info.endtime = end;
				recallinfo_list_hour.append(info);
			}
			else {
				long long start = recallinfo_list[i].starttime + j;
				long long end = recallinfo_list[i].starttime + j + max_interval;

				RecallInfo info;
				info.starttime = start;
				info.endtime = end - 1;
				recallinfo_list_hour.append(info);
			}
		}
	}

}

int HandleReceiveMessage(int socketClient, char buffer[256]) //接收并处理Web Socket客户端发来的信息
{
	int iErrorCode = 000000;

	try
	{
		QString qstrBuffer = QString(QLatin1String(buffer));
		printf("来自ffe客户端%d消息：qstrBur= %s\n", socketClient, qstrBuffer.toAscii().data());
		cJSON* json_root = cJSON_Parse(qstrBuffer.toUtf8().constData());   //json格式序列化
		if (json_root == NULL) {
			return 10000;
		}
		QString qstrCode = NULL;//记录指令
		cJSON* json_code = NULL;
		cJSON* json_param = NULL;
		cJSON* json_program_param = NULL;
		cJSON* json_recall_param = NULL;
		cJSON* json_wave_param = NULL;
		cJSON* json_update_time = NULL;
		cJSON* json_node = NULL;

		QString update_time;
		QList<QString> wave_param;
		ProgramParam program_param;

		json_code = cJSON_GetObjectItem(json_root, "code");    //获取code
		if (json_code != NULL) {
			qstrCode = json_code->valuestring;
		}
		else {
			return 10000;
		}
		json_param = cJSON_GetObjectItem(json_root, "param");    //获取param
		if (json_param == NULL) {
			return 10000;
		}
		if (qstrCode == "dev_update" || qstrCode == "model_update" || qstrCode == "program_update") {
			//设备更新记录更新时间
			json_update_time = cJSON_GetObjectItem(json_param, "update_time");    //获取update_time
			if (json_update_time != NULL) {
				update_time = json_update_time->valuestring;
			}
		}
		else if (qstrCode == "manual_wave") {
			//手动录波：功能未完成
			json_wave_param = cJSON_GetObjectItem(json_param, "wave_param");    //获取wave_param
			int array_size = cJSON_GetArraySize(json_wave_param);    //获取数组大小
			int i;

			for (i = 0; i < array_size; i++)
			{
				json_node = cJSON_GetArrayItem(json_wave_param, i);//array
				if (json_node != NULL) {
					wave_param.append(json_node->valuestring);
				}
			}

		}
		else if (qstrCode == "model_update") {
			//程序参数：终端列表和程序文件
			json_program_param = cJSON_GetObjectItem(json_param, "program_param");    //获取program_param
			cJSON* json_temp = NULL;
			json_temp = cJSON_GetObjectItem(json_program_param, "terminal_list");    //获取
			int array_size = cJSON_GetArraySize(json_temp);    //获取数组大小
			int i;

			for (i = 0; i < array_size; i++)
			{
				json_node = cJSON_GetArrayItem(json_temp, i);//array
				if (json_node != NULL) {
					program_param.terminal_list.append(json_node->valuestring);
				}
			}
			json_node = cJSON_GetObjectItem(json_program_param, "file_name");    //获取file_name
			if (json_node != NULL) {
				program_param.file_name = json_node->valuestring;
			}
		}
		else if (qstrCode == "manual_recall") {//手动补招的指令
			//补招参数
			json_recall_param = cJSON_GetObjectItem(json_param, "recall_param");    //获取recall_param
			cJSON* json_temp = NULL;
			int array_size = cJSON_GetArraySize(json_recall_param);    //获取数组大小
			int i;
			QList<RecallInfo> recallinfo_list_hour;
			char start_time[64];
			char end_time[64];
			QString mp_id;
			for (i = 0; i < array_size; i++)
			{
				json_temp = cJSON_GetArrayItem(json_recall_param, i);//array
				if (json_temp != NULL) {
					json_node = cJSON_GetObjectItem(json_temp, "mp_id");    //获取mp_id
					if (json_node != NULL) {
						mp_id = QString::fromUtf8(json_node->valuestring);
					}
					if (i == 0) {
						json_node = cJSON_GetObjectItem(json_temp, "start");    //获取start
						if (json_node != NULL) {
							apr_snprintf(start_time, sizeof(start_time), "%s", json_node->valuestring);//start_time
						}
						json_node = cJSON_GetObjectItem(json_temp, "end");    //获取end
						if (json_node != NULL) {
							apr_snprintf(end_time, sizeof(end_time), "%s", json_node->valuestring);//end_time
						}
						Get_Recall_Time_Char(start_time, end_time, recallinfo_list_hour);
					}
					for (int j = 0; j < recallinfo_list_hour.size(); j++) {
						CJournalRecall jr;
						jr.MonitorID = mp_id;
						jr.StartTime = QDateTime::fromTime_t(recallinfo_list_hour[j].starttime).toString("yyyy-MM-dd hh:mm:ss");
						jr.EndTime = QDateTime::fromTime_t(recallinfo_list_hour[j].endtime).toString("yyyy-MM-dd hh:mm:ss");
						jr.STEADY = QString::number(1, 10);//默认都是1，1的十进制转化
						jr.VOLTAGE = QString::number(1, 10);
						g_StatisticLackList_list_mutex.lock();
						g_StatisticLackList.push_back(jr);
						g_StatisticLackList_list_mutex.unlock();
					}
				}
			}
		}
		cJSON_Delete(json_root);
		SendMessageToWeb(socketClient, 000000);//响应web
	}
	catch (exception& e)
	{
		printf("处理客户端：%d发送的消息错误，原因：%s\n", socketClient, e.what());
		return 10004;
	}
	return 000000;
}
//// 判断时间差是否超过十分钟
//bool IsTimeDifferenceGreaterThanTenMinutes(apr_time_t time1, apr_time_t time2) {
//	// 计算时间差
//	apr_int64_t timeDiff = apr_time_diff(time1, time2);
//
//	// 转换为分钟
//	apr_int64_t minutes = apr_time_sec(timeDiff) / 60;
//
//	// 判断时间差是否大于十分钟
//	return (minutes > 10);
//}
void Get_Recall_Time(char* time, QList<RecallInfo>& recallinfo_list_hour);

void Cout_account_information() {
	ied_t* ied = NULL;
	int			iedno;
	LD_info_t* LD_info = NULL;

	for (iedno = 0; iedno < g_node->n_clients; iedno++) {
		ied = g_node->clients[iedno];
		if (ied) {
			LD_info_t* LD_info = NULL;
			ied_usr_t* ied_usr = GET_IEDEXT_ADDR(ied);
			int			cpuno;
			QString text;//待组装的pgsql语句
			text.append(QString("terminal_code: \"%1\"  ,ip:\"%2\" ,port:\"%3\" ,cpucount:\"%4\" ").arg(ied_usr->terminal_code).arg(ied->channel[0].addr_str).arg(ied->channel[0].port).arg(ied->cpucount));
			add_comm_log(const_cast<char*>(text.toLocal8Bit().constData()));
			for (cpuno = 0; cpuno < ied->cpucount; cpuno++) {
				LD_info = &(ied_usr->LD_info[cpuno]);
				QString text2;//待组装的pgsql语句
				text2.append(QString("mp_id: \"%1\" terminal_code:\"%2\" ").arg(LD_info->mp_id).arg(LD_info->terminal_code));
				add_comm_log(const_cast<char*>(text2.toLocal8Bit().constData()));
			}
		}
	}
}

//将时间戳转qstring
QString timestampToYYYYMMDD(long long timestamp) {
	// 将long long时间戳转换为QDateTime  
	QDateTime dateTime = QDateTime::fromMSecsSinceEpoch(timestamp * 1000);

	// 提取日期部分，并格式化为YYYYMMDD  
	// 格式化QDateTime对象为QString，精确到小时  
	QString formattedDateTime = dateTime.toString("yyyyMMddHH");

	return formattedDateTime;
}

bool containsDash(const char* str, size_t len) {
	for (size_t i = 0; i < len; ++i) {
		if (str[i] == '-') {
			return true; // 找到'-'字符，返回true  
		}
	}
	return false; // 没有找到'-'字符，返回false  
}

bool CheckPG_To_Recall(long long start, long long end, char* Monitorid)
{
	QDateTime deltime_Qtime = QDateTime::fromTime_t(start);
	QDateTime deltime_Qtime_end = QDateTime::fromTime_t(end);
	QString tmp_chr1 = deltime_Qtime.toString("yyyy-MM-dd"); //当前天
	QString start_chr1 = deltime_Qtime.toString("yyyy-MM-dd hh:mm:ss"); //当前天
	QString end_chr1 = deltime_Qtime_end.toString("yyyy-MM-dd hh:mm:ss"); //当前天

	int timespan = 3;//默认时间间隔

	try {
		int rtState = OTLDbconnected();
		//int rtState = db.connected;
		if (rtState == 0) {
			int ret = OTLConnect();
		}
		//printf("\nPostgreSL 1 %s \n", POSTGRES_SCHEMA);
		std::string str2 = POSTGRES_SCHEMA;//schame analy
		std::string str3 = POSTGRES_TABLEPREFIX;//schame analy
		std::string str1 = "select \"exp_num\",\"act_num\" from \"";
		str1.append(str2);
		str1.append("\".\"");
		str1.append(str3);
		str1.append("meas_pq_measpoint_intact_tr\" ");
		str1.append("WHERE \"statistical_date\" = '");
		str1.append(tmp_chr1.toAscii().data());
		str1.append("' AND \"monitor_id\" = '");
		str1.append(Monitorid);
		str1.append("'");
		otl_stream i(1, // buffer size
			str1.c_str(),
			//SELECT statement
			db //connect object
		);
		double exp_num;
		double act_num;
		while (!i.eof()) { //while not end-of-data
			i >> exp_num >> act_num;
			timespan = 1440 / exp_num;
			printf("\n %f %f %d \n", exp_num, act_num, timespan);
		}
		//OTLDisconnect();
	}
	catch (otl_exception& e)
	{
		printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg);
		return false;
	}

	try {
		long long starttime = start;                          //补招起始时间
		long long endtime = starttime + 3599;                //补招结束时间
		QList<long long> timestamp_list;                      //数据库完整性记录时间点
		QList<RecallInfo> recallinfo_list;                    //待补招队列
		QList<RecallInfo> recallinfo_list_hour;               //待补招队列-以小时为最大间隔

		int rtState = OTLDbconnected();
		//int rtState = db.connected;
		if (rtState == 0) {
			int ret = OTLConnect();
		}
		/*OTLConnect();*/
		std::string str2 = POSTGRES_SCHEMA;//schame analy
		std::string str3 = POSTGRES_TABLEPREFIX;//schame analy
		std::string str1 = "SELECT unnest(value_time) AS timestamp_value FROM \"";
		str1.append(str2);
		str1.append("\".\"");
		str1.append(str3);
		str1.append("meas_pq_measpoint_intact_tr\" ");
		str1.append("WHERE \"statistical_date\" = '");
		str1.append(tmp_chr1.toAscii().data());
		str1.append("' AND \"monitor_id\" = '");
		str1.append(Monitorid);
		str1.append("' ORDER BY timestamp_value");

		std::string str4 = "select b1.timestamp_value from (";
		str4.append(str1);
		str4.append(") b1 where b1.timestamp_value >= '");
		str4.append(start_chr1.toAscii().data());
		str4.append("' and b1.timestamp_value <= '");
		str4.append(end_chr1.toAscii().data());
		str4.append("'");
		otl_stream i(1, // buffer size
			str4.c_str(),
			//SELECT statement
			db //connect object
		);
		otl_datetime timestamp;
		while (!i.eof()) { //while not end-of-data
			i >> timestamp;

			struct tm timeinfo;
			timeinfo.tm_year = timestamp.year - 1900; // 年份需要减去1900
			timeinfo.tm_mon = timestamp.month - 1; // 月份需要减去1
			timeinfo.tm_mday = timestamp.day;
			timeinfo.tm_hour = timestamp.hour;
			timeinfo.tm_min = timestamp.minute;
			timeinfo.tm_sec = timestamp.second;

			time_t timestamp = std::mktime(&timeinfo);
			long long stamp = static_cast<long long>(timestamp);
			timestamp_list.append(stamp);
		}
		//OTLDisconnect();

		if (timestamp_list.size() <= (60 / timespan) * 0.97) //完整性数据表无数据
		{
			printf("\n return ture %d %f\n", timestamp_list.size(), (60 / timespan) * 0.97);
			return true;
		}
		else
		{
			printf("\n return false %d %f\n", timestamp_list.size(), (60 / timespan) * 0.97);
			return false;
		}
	}
	catch (otl_exception& e)
	{
		printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg);
		return false;
	}
	printf("\n>>>error quit!!\n");
	return true;
}

//2024-10-21 lnk定时任务替换web接口
#if 0
void OnTimerThread::run()
{
	msleep(10000);
	printf("OnTimerThread::run() is called ...... \n");
	static int delectflag = 1;//定时日志清理标记
	bool account_update = true;
	bool asd = true;

	apr_time_t	previousTime = apr_time_now();//
	apr_time_exp_t localTime;
	apr_time_exp_gmt(&localTime, previousTime);
	cout << "Local Time: "
		<< localTime.tm_year + 1900 << "-" << localTime.tm_mon + 1 << "-" << localTime.tm_mday << " "
		<< localTime.tm_hour << ":" << localTime.tm_min << ":" << localTime.tm_sec
		<< endl;

	QMap<QString, bool> dic_task_block;

	// 向QMap中添加键值对
	dic_task_block.insert("account", false);
	dic_task_block.insert("recruit ", false);
	dic_task_block.insert("log", false);
	dic_task_block.insert("multi_node", false);

	int ip_count = 0;
	int telnet_count = 0;
	// 查找键值对
	if (g_node_id == RECALL_HIS_DATA_BASE_NODE_ID) {
		init_ping_telnet(ip_count, telnet_count);
		Cout_account_information();
	}

	if (g_onlyIP[0] != 0)
	{
		printf("g_onlyIP[0]=!0 ontimer--%s--\n", g_onlyIP);
		add_comm_log(const_cast<char*>("g_onlyIP[0]=!0,g_onlyIP is --%s--", g_onlyIP));
	}
	else {
		printf("g_onlyIP[0] == 0!");

	}

	int pgflag = 0;
	int pgmin = 0;
	int mp_num_hour = 0;
	int recall_flag1 = 1;

	//char recalllllll[256] = "0923000982";
	//CheckPG_To_Recall(1705168800, 1705168800 + 3599, recalllllll);
	while (1)
	{
		/*cout << "ip_count:" << ip_count << " telnet_count:" << telnet_count << endl;
		msleep(1000);*/

		//进入线程时间
		previousTime = apr_time_now();
		apr_time_exp_gmt(&localTime, previousTime);
		//apr_time_t elapsedTime = currentTime - previousTime;
		//apr_time_as_msec(elapsedTime);
		//cout << "front num:" << FRONT_MP_NUM << endl;
		if (strcmp(subdir, "cfg_stat_data") == 0 || strcmp(subdir, "cfg_newhis_data") == 0) {//台账更新,多节点,通讯
			//读取上次台账更新时间

			//判断间隔执行
			if (false) {
				//执行台账任务;

			}
			//记录现在时间
			// 
			//判断执行此任务时间段内是否有 任务被堵塞
			if (MULTIPLE_NODE_FLAG && pgflag) {
				if (FRONT_INST != 0 && FRONT_IP[0] != '\0') {
					QString updateFrontSql;//待组装的pgsql语句
					updateFrontSql.append(QString("update \"%1\".\"%2meas_pq_front_list_tr\" ").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX));
					updateFrontSql.append(QString("set \"mp_num\"= %1,front_version='%2' ").arg(FRONT_MP_NUM).arg(PROGRAM_VERSION));
					updateFrontSql.append(QString("where \"front_ip\" = '%1' and \"front_inst\"=%2;").arg(FRONT_IP).arg(FRONT_INST));

					Sql_data_list_mutex.lock(); //加锁
					Sql_data_list.append(updateFrontSql);
					Sql_data_list_mutex.unlock(); //解锁

				}
				pgflag = 0;
			}
			else if (MULTIPLE_NODE_FLAG && pgmin != localTime.tm_min)
			{
				pgmin = localTime.tm_min;
				pgflag = 1;
			}

			if (mp_num_hour != localTime.tm_hour) {
				std::string mp_num_str = "";
				mp_num_str.append("connected device count:");
				mp_num_str.append(QString::number(FRONT_MP_NUM).toStdString());
				mp_num_str.append(",g_node clients:");
				mp_num_str.append(QString::number(g_node->n_clients).toStdString());

				add_comm_log(const_cast<char*>(mp_num_str.c_str()));
				mp_num_hour = localTime.tm_hour;
			}


			//2023-10-17 zw新增 定期obs oss和sql数据库记录删除
			if (delectflag == 1 && localTime.tm_hour == 16)
			{
				delectflag = 0;
				//time_t timestamp = apr_time_as_time_t(previousTime);
				long long stamp = static_cast<long long>(previousTime) / 1000000;
				cout << ">>>>>>>>>The Time is: " << stamp << endl;
				if (FILE_FLAG == 1) //阿里云 oss 文件删除
				{
					//PutOSS("comtrade/not def/20231111/temp2.log", "/FeProject/dat/9D3AAA2BDCE430BA7E3E1302F132B880.xml");

					int i = 0;
					while (i < g_pt61850app->chnl_counts)
					{
						chnl_usr_t* chnl_usr;
						ied_t* ied;
						ied_usr_t* ied_usr;
						LD_info_t* LD_info;
						int	cpuno = 0;

						chnl_usr = g_pt61850app->chnl_usr[i];
						ied = chnl_usr->chnl->ied;
						ied_usr = GET_IEDEXT_ADDR(ied);
						while (cpuno < ied->cpucount)
						{
							LD_info = &(ied_usr->LD_info[cpuno]);

							long long deltime = stamp - (60 * 60 * 24 * 30);//减去30天
							QDateTime deltime_Qtime = QDateTime::fromTime_t(deltime);
							QString tmp_chr1 = deltime_Qtime.toString("yyyyMMdd");
							QString Oss_Del_Path = NULL;
							Oss_Del_Path.append("comtrade/");
							Oss_Del_Path.append(LD_info->mp_id).append("/");
							Oss_Del_Path.append(tmp_chr1).append("/");
							//cout << Oss_Del_Path.toAscii().data() << endl;
							DelOSS(Oss_Del_Path.toAscii().data());
							cpuno++;
						}
						i++;
					}
					//PutOSS("comtrade/not def/20231111/temp.log","/FeProject/dat/6A5C8A2A7BBC1A61D9EC3F1AE2A25A03.xml");
					//PutOSS("comtrade/not def/20231111/temp2.log", "/FeProject/dat/6A5C8A2A7BBC1A61D9EC3F1AE2A25A03.xml");
					//PutOSS("comtrade/not def/20231111/temp3.log", "/FeProject/dat/6A5C8A2A7BBC1A61D9EC3F1AE2A25A03.xml");
					//DelOSS("comtrade/not def/20231111/temp3.log");
				}
				else if (FILE_FLAG == 2)//华为云 obs 文件删除
				{
					//OBSFile("/FeProject/dat/67BC249C13B5EC819CF4DF0307DB71C5.xml", "comtrade/not def/20231111/temp3.log", "putObject");
					//OBSFile_del("comtrade/not def/20231111/temp3.log", "deleteObject");

					int i = 0;
					while (i < g_pt61850app->chnl_counts)
					{
						chnl_usr_t* chnl_usr;
						ied_t* ied;
						ied_usr_t* ied_usr;
						LD_info_t* LD_info;
						int	cpuno = 0;

						chnl_usr = g_pt61850app->chnl_usr[i];
						ied = chnl_usr->chnl->ied;
						ied_usr = GET_IEDEXT_ADDR(ied);
						while (cpuno < ied->cpucount)
						{
							LD_info = &(ied_usr->LD_info[cpuno]);

							long long deltime = stamp - (60 * 60 * 24 * 30);//减去30天
							QDateTime deltime_Qtime = QDateTime::fromTime_t(deltime);
							QString tmp_chr1 = deltime_Qtime.toString("yyyyMMdd");
							QString Oss_Del_Path = NULL;
							Oss_Del_Path.append("comtrade/");
							Oss_Del_Path.append(LD_info->mp_id).append("/");
							Oss_Del_Path.append(tmp_chr1).append("/");
							//cout << Oss_Del_Path.toAscii().data() << endl;
							OBSFile_del(Oss_Del_Path.toAscii().data(), "deleteObject");
							cpuno++;
						}
						i++;
					}


				}

				//pgsql删除记录
				long long deltime = stamp - (60 * 60 * 24 * 30);//减去30天
				QDateTime deltime_Qtime = QDateTime::fromTime_t(deltime);
				QString tmp_chr1 = deltime_Qtime.toString("yyyy-MM-dd");
				QString pgsql0;
				pgsql0.append(QString("DELETE FROM \"%1\".\"%2meas_pq_comm_status_tr\ WHERE \"statistical_data\" < '%3';").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX).arg(tmp_chr1));
				QString pgsql1;
				pgsql1.append(QString("DELETE FROM \"%1\".\"%2meas_pq_comm_error_tr\ WHERE \"statistical_data\" < '%3';").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX).arg(tmp_chr1));
				QString pgsql2;
				pgsql2.append(QString("DELETE FROM \"%1\".\"%2meas_pq_measpoint_rationality_tr\ WHERE \"statistical_data\" < '%3';").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX).arg(tmp_chr1));
				QString pgsql3;
				pgsql3.append(QString("DELETE FROM \"%1\".\"%2meas_pq_measpoint_intact_tr\ WHERE \"statistical_data\" < '%3';").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX).arg(tmp_chr1));
				QString pgsql4;
				pgsql4.append(QString("DELETE FROM \"%1\".\"%2meas_pq_measpoint_match_tr\ WHERE \"statistical_data\" < '%3';").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX).arg(tmp_chr1));

				Sql_data_list_mutex.lock(); //加锁
				Sql_data_list.append(pgsql0);
				Sql_data_list.append(pgsql1);
				Sql_data_list.append(pgsql2);
				Sql_data_list.append(pgsql3);
				Sql_data_list.append(pgsql4);
				Sql_data_list_mutex.unlock(); //解锁
			}
			if (delectflag == 0 && localTime.tm_hour != 16)
			{
				delectflag = 1;
			}
			//2023-10-17 zw新增 定期obs oss和sql数据库记录删除 end

		}
		if (strcmp(subdir, "cfg_newhis_data") == 0) {//上海定时招装置日志
			static int hour_time = 0;
			if (localTime.tm_hour != hour_time) {
				hour_time = localTime.tm_hour;

				printf(">>>cfg_newhis_data is run!!!\n");
				long long stamp = static_cast<long long>(previousTime) / 1000000;
				cout << ">>>>>>>>>The Time is: " << stamp << endl;
				long long start = stamp - (stamp % 3600) - 3600 - 3600;//开始时间 当前整点值往前推两小时
				long long end = start + 3599;//结束时间

				QList<RecallInfo> recallinfo_list_hour;
				RecallInfo info;
				info.starttime = start - 10;
				info.endtime = end;
				recallinfo_list_hour.append(info);

				int i = 0;
				while (i < g_pt61850app->chnl_counts)
				{
					chnl_usr_t* chnl_usr;
					ied_t* ied;
					ied_usr_t* ied_usr;
					LD_info_t* LD_info;
					int	cpuno = 0;

					chnl_usr = g_pt61850app->chnl_usr[i];
					ied = chnl_usr->chnl->ied;
					ied_usr = GET_IEDEXT_ADDR(ied);
					printf("\n chnl_usr->m_state ===== %d\n", chnl_usr->m_state);
					//if (chnl_usr->m_state == CHANNEL_CONNECTED) {
					while (cpuno < ied->cpucount)
					{
						LD_info = &(ied_usr->LD_info[cpuno]);
						cpuno++;
						if (LD_info->logcount <= 0 || LD_info->read_flag == 0)
							continue;
						printf("/home/pq mpid=%s\n", LD_info->mp_id);
						printf("\n %d ===== %d\n", recallinfo_list_hour.size(), LD_info->autorecallflag);

						if (recallinfo_list_hour.size() != 0) {
							for (int j = 0; j < recallinfo_list_hour.size(); j++) {
								CJournalRecall jr;
								jr.MonitorID = QString(LD_info->mp_id);
								jr.StartTime = QDateTime::fromTime_t(recallinfo_list_hour[j].starttime).toString("yyyy-MM-dd hh:mm:ss");
								jr.EndTime = QDateTime::fromTime_t(recallinfo_list_hour[j].endtime).toString("yyyy-MM-dd hh:mm:ss");
								jr.STEADY = QString::number(1, 10);
								jr.VOLTAGE = QString::number(1, 10);
								g_StatisticLackList_list_mutex.lock();
								g_StatisticLackList.push_back(jr);
								g_StatisticLackList_list_mutex.unlock();
							}
						}
					}

					i++;
				}
			}
		}
		if (strcmp(subdir, "cfg_recallall_data") == 0)
		{
			static int recall_xml_time = 0;
			if (localTime.tm_min != recall_xml_time)
			{
				recall_xml_time = localTime.tm_min;
				//补招开始与截止时间
				static long long recall_start_time = 0;
				static long long recall_end_time = 0;
				static int flag = 0;
				if (recall_start_time == 0 && recall_end_time == 0) {//无缓存数据
					//查询一条 -1状态(代补招)的记录
					char front_ip[42];
					cout << "start select:" << endl;

					QString selectFrontSql;
					selectFrontSql.append(QString("select \"front_ip\" from \"%1\".\"%2meas_pq_front_list_tr\" ").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX));
					selectFrontSql.append(QString("where front_inst=%1 and \"front_status\" = '-1' LIMIT 1;").arg(g_front_seg_index));
					cout << selectFrontSql.toStdString().c_str() << endl;
					try {
						otl_stream i(1, // buffer size
							selectFrontSql.toStdString().c_str(),
							db //connect object
						);
						//create select stream
						while (!i.eof()) { //while not end-of-data
							i >> front_ip;
							break;
							//cout << "count=" << f2 << endl;
						}
					}
					catch (otl_exception& e)
					{
						printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg);
						continue;
					}
					if (containsDash(front_ip, 21)) {
						//插入更新记录
						QString insertFrontSql;
						insertFrontSql.append(QString("insert into \"%1\".\"%2meas_pq_front_list_tr\"(\"front_ip\",\"front_port\",\"front_inst\",\"front_type\",\"front_status\",\"front_version\",\"mp_num\") ").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX));
						insertFrontSql.append(QString("values('%1',10000,%2,'03','-1','%3',200) ").arg(front_ip).arg(g_front_seg_index).arg(PROGRAM_VERSION));
						insertFrontSql.append(QString("on conflict(\"front_ip\",\"front_inst\") do update set "));
						insertFrontSql.append(QString("\"front_status\"= '%1'").arg("-2"));
						cout << insertFrontSql.toStdString().c_str() << endl;
						Sql_data_list_mutex.lock(); //加锁
						Sql_data_list.append(insertFrontSql);
						Sql_data_list_mutex.unlock(); //解锁	
						//缓存数据
						cout << "front_ip=" << front_ip << endl;
						QString startDate, endDate;
						// 分割字符串  
						startDate = QString::fromAscii(front_ip).left(10); // 取前10个字符作为开始日期  
						qDebug() << "startDate=" << startDate << endl;
						endDate = QString::fromAscii(front_ip + 11).left(10); // 从第10个字符开始取8个字符作为结束日期
						qDebug() << "endDate=" << endDate << endl;

						QDateTime start_dt = QDateTime::fromString(startDate, "yyyyMMddHH");
						qDebug() << "start_dt=" << start_dt << endl;
						recall_start_time = start_dt.toMSecsSinceEpoch() / 1000;
						qDebug() << "recall_start_time=" << recall_start_time << endl;
						QDateTime end_dt = QDateTime::fromString(endDate, "yyyyMMddHH");
						qDebug() << "end_dt=" << end_dt << endl;
						recall_end_time = end_dt.toMSecsSinceEpoch() / 1000;
						qDebug() << "recall_end_time=" << recall_end_time << endl;
					}
					flag = 0;

				}
				else if (recall_start_time != 0 && recall_end_time != 0) {//有缓存数据
					// 将时间戳转换为YYYYMMDD格式  
					QString date1 = timestampToYYYYMMDD(recall_start_time);
					QString date2 = timestampToYYYYMMDD(recall_end_time);
					// 拼接两个日期，并用'-'分隔  
					QString dateRange = date1 + "-" + date2;
					qDebug() << "dateRange=" << dateRange << endl;
					char front_status[4];
					QString selectFrontSql;
					selectFrontSql.append(QString("select front_status from \"%1\".\"%2meas_pq_front_list_tr\" ").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX));
					selectFrontSql.append(QString("where front_inst=%1 and \"front_ip\" = '%2'").arg(g_front_seg_index).arg(dateRange));
					cout << selectFrontSql.toStdString().c_str() << endl;
					try {
						otl_stream i(1, // buffer size
							selectFrontSql.toStdString().c_str(),
							db //connect object
						);
						//create select stream
						while (!i.eof()) { //while not end-of-data
							i >> front_status;
							break;
							//cout << "count=" << f2 << endl;
						}
					}
					catch (otl_exception& e)
					{
						printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg);
						continue;
					}
					qDebug() << "front_status=" << front_status << endl;
					//再次判断是否为执行中状态
					if (strcmp(front_status, "-1") == 0) {
						//状态为-1 重新插入更新记录
						QString updateFrontSql;
						updateFrontSql.append(QString("insert into \"%1\".\"%2meas_pq_front_list_tr\"(\"front_ip\",\"front_port\",\"front_inst\",\"front_type\",\"front_status\",\"front_version\",\"mp_num\") ").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX));
						updateFrontSql.append(QString("values('%1',10000,%2,'03','-1','%3',200) ").arg(dateRange).arg(g_front_seg_index).arg(PROGRAM_VERSION));
						updateFrontSql.append(QString("on conflict(\"front_ip\",\"front_inst\") do update set "));
						updateFrontSql.append(QString("\"front_status\"= '%1'").arg("-2"));
						cout << updateFrontSql.toStdString().c_str() << endl;
						Sql_data_list_mutex.lock(); //加锁
						Sql_data_list.append(updateFrontSql);
						Sql_data_list_mutex.unlock(); //解锁	
						flag = 0;
					}
					else if (strcmp(front_status, "-2") == 0)
					{//状态为-2 补招

						flag = 1;
					}
					else {
						flag = 0;
						recall_end_time = 0;
						recall_start_time = 0;
					}

				}

				if (recall_start_time != 0 && recall_end_time != 0 && flag == 1)
				{
					qDebug() << "start recall time=" << recall_start_time << endl;
					qDebug() << "end recall time=" << recall_end_time << endl;

					long long starttime = recall_start_time;  //补招起始时间
					long long endtime = recall_end_time;                //补招结束时间

					flag = 0;
					recall_start_time = 0;
					recall_end_time = 0;

					QList<RecallInfo> recallinfo_list;                    //待补招队列
					QList<RecallInfo> recallinfo_list_hour;               //待补招队列-以小时为最大间隔


					RecallInfo info;
					info.starttime = starttime;
					info.endtime = endtime;
					recallinfo_list.append(info);

					for (int i = 0; i < recallinfo_list.size(); i++)
					{
						//printf("\n %lld ----- %11d\n", recallinfo_list[i].starttime, recallinfo_list[i].endtime);
						long long duration = recallinfo_list[i].endtime - recallinfo_list[i].starttime;
						long long max_interval = 3600;
						for (long long j = 0; j <= duration; j += max_interval)
						{
							if (j + max_interval > duration) {
								long long start = recallinfo_list[i].starttime + j;
								long long end = recallinfo_list[i].endtime;

								RecallInfo info;
								info.starttime = start;
								info.endtime = end;
								recallinfo_list_hour.append(info);
							}
							else {
								long long start = recallinfo_list[i].starttime + j;
								long long end = recallinfo_list[i].starttime + j + max_interval;

								RecallInfo info;
								info.starttime = start;
								info.endtime = end - 1;
								recallinfo_list_hour.append(info);
							}
						}
					}

					int i = 0;
					while (i < g_pt61850app->chnl_counts)
					{
						chnl_usr_t* chnl_usr;
						ied_t* ied;
						ied_usr_t* ied_usr;
						LD_info_t* LD_info;
						int	cpuno = 0;

						chnl_usr = g_pt61850app->chnl_usr[i];
						ied = chnl_usr->chnl->ied;
						ied_usr = GET_IEDEXT_ADDR(ied);
						printf("\n chnl_usr->m_state ===== %d\n", chnl_usr->m_state);
						//if (chnl_usr->m_state == CHANNEL_CONNECTED)
						while (cpuno < ied->cpucount)
						{
							LD_info = &(ied_usr->LD_info[cpuno]);
							cpuno++;
							printf("/home/pq mpid=%s %d\n", LD_info->mp_id, LD_info->read_flag);
							if (LD_info->logcount <= 0 || LD_info->read_flag == 0) {
								continue;
							}
							printf("\n %d ===== %d\n", recallinfo_list_hour.size(), LD_info->autorecallflag);

							if (recallinfo_list_hour.size() != 0) {
								g_StatisticLackList_list_mutex.lock();
								for (int j = 0; j < recallinfo_list_hour.size(); j++) {

//替换成web接口 2024-10-21 lnk
			//						if (CheckPG_To_Recall(recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime, LD_info->mp_id) == false) {
			//							printf("CheckPG_To_Recall == false %d-%d %s\n", recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime, LD_info->mp_id);
									if (CheckPG_To_Recall_web(recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime, LD_info->mp_id) == false) {
										printf("CheckPG_To_Recall_web == false %d-%d %s\n", recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime, LD_info->mp_id);

										continue;
									}
									CJournalRecall jr;
									jr.MonitorID = QString(LD_info->mp_id);
									jr.StartTime = QDateTime::fromTime_t(recallinfo_list_hour[j].starttime).toString("yyyy-MM-dd hh:mm:ss");
									jr.EndTime = QDateTime::fromTime_t(recallinfo_list_hour[j].endtime).toString("yyyy-MM-dd hh:mm:ss");
									jr.STEADY = QString::number(1, 10);
									jr.VOLTAGE = QString::number(1, 10);
									g_StatisticLackList.push_back(jr);

								}
								g_StatisticLackList_list_mutex.unlock();
							}
						}

						i++;
					}
				}
			}

		}
		if (strcmp(subdir, "cfg_his_data") == 0)
		{
			if (pgflag) {
				if (FRONT_INST != 0 && FRONT_IP[0] != '\0') {
					QString updateFrontSql;
					updateFrontSql.append(QString("insert into \"%1\".\"%2meas_pq_front_list_tr\"(\"front_ip\",\"front_port\",\"front_inst\",\"front_type\",\"front_status\",\"front_version\",\"mp_num\") ").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX));
					updateFrontSql.append(QString("values('his',10000,1,'02','01','%1',200) ").arg(PROGRAM_VERSION));
					updateFrontSql.append(QString("on conflict(\"front_ip\",\"front_inst\") do update set "));
					updateFrontSql.append(QString("\"mp_num\"= '%1',front_version='%2'").arg(FRONT_MP_NUM).arg(PROGRAM_VERSION));
					Sql_data_list_mutex.lock(); //加锁
					Sql_data_list.append(updateFrontSql);
					Sql_data_list_mutex.unlock(); //解锁	

				}
				pgflag = 0;
			}
			else if (pgmin != localTime.tm_min)
			{
				pgmin = localTime.tm_min;
				pgflag = 1;
			}

			static int cfg_his_data_hour_time = 0;
			if (localTime.tm_hour != cfg_his_data_hour_time) {
				cfg_his_data_hour_time = localTime.tm_hour;

				printf(">>>cfg_his_data is run!!!\n");
				long long stamp = static_cast<long long>(previousTime) / 1000000;
				cout << ">>>>>>>>>The Time is: " << stamp << endl;
				long long start = stamp - (stamp % 3600) - 3600 - 3600;//开始时间 当前整点值往前推两小时
				long long end = start + 3599;//结束时间

				QList<RecallInfo> recallinfo_list_hour;
				RecallInfo info;
				info.starttime = start - 10;
				info.endtime = end;
				recallinfo_list_hour.append(info);

				int i = 0;
				while (i < g_pt61850app->chnl_counts)
				{
					chnl_usr_t* chnl_usr;
					ied_t* ied;
					ied_usr_t* ied_usr;
					LD_info_t* LD_info;
					int	cpuno = 0;

					chnl_usr = g_pt61850app->chnl_usr[i];
					ied = chnl_usr->chnl->ied;
					ied_usr = GET_IEDEXT_ADDR(ied);
					printf("\n chnl_usr->m_state ===== %d\n", chnl_usr->m_state);
					//if (chnl_usr->m_state == CHANNEL_CONNECTED) {
					while (cpuno < ied->cpucount)
					{
						LD_info = &(ied_usr->LD_info[cpuno]);
						cpuno++;
						if (LD_info->logcount <= 0 || LD_info->read_flag == 0)
							continue;
						printf("/home/pq mpid=%s\n", LD_info->mp_id);
						printf("\n %d ===== %d\n", recallinfo_list_hour.size(), LD_info->autorecallflag);

						if (recallinfo_list_hour.size() != 0) {
							for (int j = 0; j < recallinfo_list_hour.size(); j++) {

//替换成web接口 2024-10-21 lnk
								//if (CheckPG_To_Recall(recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime, LD_info->mp_id) == false) {
									//printf("CheckPG_To_Recall == false %d-%d %s\n", recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime, LD_info->mp_id);
								if (CheckPG_To_Recall_web(recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime, LD_info->mp_id) == false) {
									printf("CheckPG_To_Recall_web == false %d-%d %s\n", recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime, LD_info->mp_id);
									
									continue;
								}
								CJournalRecall jr;
								jr.MonitorID = QString(LD_info->mp_id);
								jr.StartTime = QDateTime::fromTime_t(recallinfo_list_hour[j].starttime).toString("yyyy-MM-dd hh:mm:ss");
								jr.EndTime = QDateTime::fromTime_t(recallinfo_list_hour[j].endtime).toString("yyyy-MM-dd hh:mm:ss");
								jr.STEADY = QString::number(1, 10);
								jr.VOLTAGE = QString::number(1, 10);
								g_StatisticLackList_list_mutex.lock();
								g_StatisticLackList.push_back(jr);
								g_StatisticLackList_list_mutex.unlock();
							}
						}
					}

					i++;
				}
			}

		}
		if (strcmp(subdir, "cfg_recallhis_data") == 0)
		{
			if (pgflag) {
				if (FRONT_INST != 0 && FRONT_IP[0] != '\0') {
					QString updateFrontSql;
					updateFrontSql.append(QString("insert into \"%1\".\"%2meas_pq_front_list_tr\"(\"front_ip\",\"front_port\",\"front_inst\",\"front_type\",\"front_status\",\"front_version\",\"mp_num\") ").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX));
					updateFrontSql.append(QString("values('recallhis',10000,1,'02','01','%1',200) ").arg(PROGRAM_VERSION));
					updateFrontSql.append(QString("on conflict(\"front_ip\",\"front_inst\") do update set "));
					updateFrontSql.append(QString("\"mp_num\"= '%1',front_version='%2'").arg(FRONT_MP_NUM).arg(PROGRAM_VERSION));
					Sql_data_list_mutex.lock(); //加锁
					Sql_data_list.append(updateFrontSql);
					Sql_data_list_mutex.unlock(); //解锁	

				}
				pgflag = 0;
			}
			else if (pgmin != localTime.tm_min)
			{
				pgmin = localTime.tm_min;
				pgflag = 1;
			}

		}

		//g_node_id == HIS_DATA_BASE_NODE_ID &&
		//printf("/home/pq hour=%d\n", localTime.tm_hour);
		if (0 && g_node_id == HIS_DATA_BASE_NODE_ID && (localTime.tm_hour <= 12 || localTime.tm_hour >= 20) && recall_flag1 == 1) {
			recall_flag1 = 0;
			QString MyKafkaIniFilename = QString("../etc/") + QString("mykafka.ini"); //+QString::fromAscii(subdir)
			QSettings settings(MyKafkaIniFilename, QSettings::IniFormat);

			QString dateString = settings.value("Recall/select_day").toString();

			QList<RecallInfo> recallinfo_list_hour;
			QByteArray byteArray = dateString.toUtf8(); // 使用 UTF-8 编码  
			char* charArray = byteArray.data();
			Get_Recall_Time(charArray, recallinfo_list_hour);

			int i = 0;
			while (i < g_pt61850app->chnl_counts)
			{
				chnl_usr_t* chnl_usr;
				ied_t* ied;
				ied_usr_t* ied_usr;
				LD_info_t* LD_info;
				int	cpuno = 0;

				chnl_usr = g_pt61850app->chnl_usr[i];
				ied = chnl_usr->chnl->ied;
				ied_usr = GET_IEDEXT_ADDR(ied);
				while (cpuno < ied->cpucount)
				{
					LD_info = &(ied_usr->LD_info[cpuno]);
					if (LD_info->logcount <= 0)
						continue;
					printf("/home/pq mpid=%s\n", LD_info->mp_id);
					printf("\n %d ===== %d\n", recallinfo_list_hour.size(), LD_info->autorecallflag);
					if (recallinfo_list_hour.size() != 0) {
						if (LD_info->autorecallcount != 0) {
							for (int j = 0; j < LD_info->autorecallcount; j++) {
								delete LD_info->autorecall[j];
							}
							delete LD_info->autorecall;
							LD_info->autorecallcount = 0;
						}
						LD_info->autorecallflag = 0;
						LD_info->autorecallcount = recallinfo_list_hour.size();
						LD_info->autorecall = new autorecall_t * [recallinfo_list_hour.size()];
						printf("/home/pq recall mpid=%s\n", LD_info->mp_id);

						for (int j = 0; j < recallinfo_list_hour.size(); j++) {
							printf("\n %lld ===== %11d\n", recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime);
							LD_info->autorecall[j] = new autorecall_t[1];
							LD_info->autorecall[j]->start = recallinfo_list_hour[j].starttime;

							LD_info->autorecall[j]->end = recallinfo_list_hour[j].endtime;
						}
					}


					cpuno++;
				}
				i++;
			}

			QDate date = QDate::fromString(dateString, "yyyy-MM-dd");

			date.addDays(-1); // 一天  
			settings.setValue("Recall/select_day", date.toString("yyyy-MM-dd")); // 重新写入日期字符串  


		}
		if (localTime.tm_hour > 12 && localTime.tm_hour < 20 && recall_flag1 == 0) {
			recall_flag1 = 1;
		}

		msleep(1000);
	}

	printf(">>>OnTimerThread::run() is end!!!\n");
}
#endif

//不使用的代码lnk20241206
#if 0
/////////////////////////////////////////CZY 2023-09-04

/// <summary>
/// 拼接请求入参json
/// </summary>
/// <param name="json_roots"></param>
/// <param name="json_root"></param>
/// <param name="json_params"></param>
/// <param name="json_filters"></param>
/// <param name="perpage"></param>
/// <param name="page"></param>
/// <param name="flag">是否删选青浦地市</param>
void AppendCJson(cJSON* json_roots, cJSON* json_root, cJSON* json_params, cJSON* json_filters, int perpage, int page, int flag) {
	//[]层
	//cJSON_AddItemToArray(json_roots, json_root);
	//第一层
	cJSON_AddItemToObject(json_root, "distribution", cJSON_CreateString("1"));
	cJSON_AddItemToObject(json_root, "id", cJSON_CreateString(""));
	cJSON_AddItemToObject(json_root, "modelId", cJSON_CreateString(""));
	cJSON_AddItemToObject(json_root, "params", json_params);
	cJSON_AddItemToObject(json_root, "psrType", cJSON_CreateString("0751002"));
	//params层
	cJSON_AddItemToObject(json_params, "current", cJSON_CreateNumber(1));
	cJSON_AddItemToObject(json_params, "fields", cJSON_CreateString("astId"));
	cJSON_AddItemToObject(json_params, "filters", json_filters);
	cJSON_AddItemToObject(json_params, "orderBy", cJSON_CreateString("astId desc"));
	cJSON_AddItemToObject(json_params, "page", cJSON_CreateNumber(page));
	cJSON_AddItemToObject(json_params, "perpage", cJSON_CreateNumber(perpage));
	cJSON_AddItemToObject(json_params, "size", cJSON_CreateNumber(1));
	//filters数组层
	cJSON* json_filter = cJSON_CreateObject();
	cJSON_AddItemToArray(json_filters, json_filter);
	//filter层
	cJSON_AddItemToObject(json_filter, "compare", cJSON_CreateString("="));
	cJSON_AddItemToObject(json_filter, "fieldName", cJSON_CreateString("deployState"));
	cJSON_AddItemToObject(json_filter, "fieldValue", cJSON_CreateString("20"));

	if (g_onlyIP[0] != 0) {//单连

		//filters数组层
		cJSON* json_filter_ip = cJSON_CreateObject();
		cJSON_AddItemToArray(json_filters, json_filter_ip);
		//json_filter_ip层
		cJSON_AddItemToObject(json_filter_ip, "compare", cJSON_CreateString("="));
		cJSON_AddItemToObject(json_filter_ip, "fieldName", cJSON_CreateString("ipAddress"));
		cJSON_AddItemToObject(json_filter_ip, "fieldValue", cJSON_CreateString(g_onlyIP));
	}

	if (flag == 1)
	{
		//filters数组层
		cJSON* json_filter_city = cJSON_CreateObject();
		cJSON_AddItemToArray(json_filters, json_filter_city);
		//json_filter_city层
		cJSON_AddItemToObject(json_filter_city, "compare", cJSON_CreateString("="));
		cJSON_AddItemToObject(json_filter_city, "fieldName", cJSON_CreateString("city"));
		cJSON_AddItemToObject(json_filter_city, "fieldValue", cJSON_CreateString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFSP09"));
	}
	else if (flag == 2) {
		//json_filter_city数组层
		cJSON* json_filter_city = cJSON_CreateObject();
		cJSON_AddItemToArray(json_filters, json_filter_city);
		//json_filter_city层
		cJSON_AddItemToObject(json_filter_city, "compare", cJSON_CreateString("!="));
		cJSON_AddItemToObject(json_filter_city, "fieldName", cJSON_CreateString("city"));
		cJSON_AddItemToObject(json_filter_city, "fieldValue", cJSON_CreateString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFSP09"));
	}
}

void GetCJson(const char* ptr) {
	//cout << ">>>GetDevice in reply" << (char*)ptr;
	strDevCJson = "";
	cJSON* json = cJSON_Parse((char*)ptr);   //json格式序列化
	cJSON* json_node;
	if (json == NULL) {
		printf("cJSON pares error %s\n", cJSON_GetErrorPtr());
	}
	else {
		json_node = cJSON_GetObjectItem(json, "status");    //获取result
		if (json_node == NULL || json_node->valuestring == NULL || json_node->valuestring == "/0" || json_node->valuestring == "" || strcmp(json_node->valuestring, "000000") != 0) {
			printf("status error %s\n", cJSON_GetErrorPtr());
		}
		else {
			cout << ">>>create strDevCJson success";
			strDevCJson = QString::fromUtf8((char*)ptr);
		}
	}
	cJSON_Delete(json);
}

//////////////////////////////////

////////////////////////////////////////////WW 2023-08-19 end
//////////////////////////////////////////
//WW 2023-08-26 增加webap调用   流程上先获取token，然后用token调用API
//http://172.40.237.145:30010/psr-auth/oauth/accessToken
//鉴权信息：
//client_id : 2a78ecf0074111ed806c7a5cabbedfb4
//	client_secret : 58nOklQlP0SGEuXbrd0wgcVO7HX7IODAgvzHiCm + mAgWSadcX0we2wffjyTUYGsK
//	grant_type : credentials
//get请求和post请求数据响应函数
size_t req_reply(void* ptr, size_t size, size_t nmemb, void* stream)
{
	//在注释的里面可以打印请求流，cookie的信息
	string* str = (string*)stream;
	(*str).append((char*)ptr, size * nmemb);
	return size * nmemb;
}
//get请求和post请求数据响应函数
void req_reply_token(const char* ptr)
{
	//在注释的里面可以打印请求流，cookie的信息
	printf(">>>GetToken in reply %s\n", ptr);

	cJSON* msg = cJSON_Parse(ptr);
	if (msg == NULL)
	{
		printf("cJSON pares error %s\n", cJSON_GetErrorPtr());
	}
	else
	{
		cJSON* json_status = cJSON_GetObjectItem(msg, "status");
		cJSON* json_error = cJSON_GetObjectItem(msg, "error");
		if (json_error == NULL)
		{
			cJSON* json_result = cJSON_GetObjectItem(msg, "result");
			cJSON* json_accesstoken = cJSON_GetObjectItem(msg, "access_token");

			strToken = QString::fromAscii(json_accesstoken->valuestring);
		}
		cJSON_Delete(msg);
	}
}

void GetToken(const string strUrl, const string strclientid, const string strclientsecret)//获取Token
{
	// curl初始化  
	CURL* curl = curl_easy_init();
	// curl返回值 
	CURLcode res;

	if (curl)
	{
		// set params
		//设置curl的请求头
		struct curl_slist* header_list = NULL;
		header_list = curl_slist_append(header_list, "Content-Type:application/x-www-form-urlencoded;");

		curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list);

		//不接收响应头数据0代表不接收 1代表接收
		curl_easy_setopt(curl, CURLOPT_HEADER, 0);

		//设置请求为post请求
		//curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
		curl_easy_setopt(curl, CURLOPT_POST, 1);

		//设置请求的URL地址
		curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());
		printf("token_url2: %s\n", strUrl.c_str());

		//设置post请求的参数

		char* pszEncodeAuth = curl_easy_escape(curl, strclientid.c_str(), strclientid.length());
		char* pszEncodeSecret = curl_easy_escape(curl, strclientsecret.c_str(), strclientsecret.length());
		string strTempBody;
		strTempBody.append("client_id=");
		strTempBody.append(pszEncodeAuth);
		strTempBody.append("&");
		strTempBody.append("client_secret=");
		strTempBody.append(pszEncodeSecret);

		strTempBody.append("&grant_type=");
		strTempBody.append(GRANT_TYPE);

		printf(">>>TestTokenPost in curl %s \n", strTempBody.c_str());
		curl_free(pszEncodeAuth);
		curl_free(pszEncodeSecret);
		curl_easy_setopt(curl, CURLOPT_POSTFIELDS, strTempBody.c_str());

		//设置ssl验证
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);

		//CURLOPT_VERBOSE的值为1时，会显示详细的调试信息
		curl_easy_setopt(curl, CURLOPT_VERBOSE, 0);

		curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);

		//设置数据接收和写入函数
		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply);
		string resPost0;
		curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&resPost0);
		//curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)strBody.toAscii().data());

		curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);

		//设置超时时间
		curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10);
		curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10);

		printf(">>>Token Post in curl post\n");
		// 开启post请求
		res = curl_easy_perform(curl);
		// 检查请求是否成功
		if (res != CURLE_OK) {
			cout << "token curl_easy_perform() failed res code: " << res << endl;
		}
		else {
			cout << ">>>token curl post success res code:" << res << endl;
			req_reply_token(resPost0.c_str());
		}
		curl_slist_free_all(header_list);

	}
	else
	{
		printf(">>> token curl init failed");
	}
	curl_easy_cleanup(curl);
}
void GetDevice(const QString strUrl, const QString strxToken, int perpage, int page, int flag)
{

	// curl初始化  
	CURL* curl = curl_easy_init();
	// curl返回值 
	CURLcode res;
	if (curl)
	{
		//QDateTime askTime = QDateTime::currentDateTime();
		//long lTim = askTime.toMSecsSinceEpoch();
		//printf(">>>TestDevicePost in curl %ld\n", lTim);
		//QString xTime;

		//xTime.append(QString("x-date:%l").arg(lTim));
		printf(">>>token %s \n", strxToken.toAscii().data());
		// set params
		//设置curl的请求头
		struct curl_slist* header_list = NULL;
		header_list = curl_slist_append(header_list, "Content-Type:application/json;");
		header_list = curl_slist_append(header_list, strxToken.toAscii().data());
		//header_list = curl_slist_append(header_list, xTime.toAscii().data());
		//header_list = curl_slist_append(header_list, "x-signature:1234");


		curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list);

		//不接收响应头数据0代表不接收 1代表接收
		curl_easy_setopt(curl, CURLOPT_HEADER, 0);

		//设置请求为post请求
		curl_easy_setopt(curl, CURLOPT_POST, 1);

		//设置请求的URL地址
		curl_easy_setopt(curl, CURLOPT_URL, strUrl.toAscii().data());
		//设置post请求的参数
		cJSON* json_roots = cJSON_CreateArray();
		cJSON* json_root = cJSON_CreateObject();
		cJSON* json_params = cJSON_CreateObject();
		cJSON* json_filters = cJSON_CreateArray();

		AppendCJson(json_roots, json_root, json_params, json_filters, perpage, page, flag);

		char* szjson = cJSON_Print(json_root);
		printf(">>>json %s\n", szjson);
		//string strjson = szjson;
		//char* pszEncodeSecret = curl_easy_escape(curl, strclientsecret.c_str(), strclientsecret.length());
		curl_easy_setopt(curl, CURLOPT_POSTFIELDS, szjson);

		//设置ssl验证
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);

		//CURLOPT_VERBOSE的值为1时，会显示详细的调试信息
		curl_easy_setopt(curl, CURLOPT_VERBOSE, 0);

		curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);

		//设置数据接收和写入函数
		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply);


		string resPost0;
		curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&resPost0);

		curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);

		//设置超时时间
		curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10);
		curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10);

		printf(">>>Device Post in curl post\n");
		// 开启post请求
		res = curl_easy_perform(curl);
		// 检查请求是否成功
		if (res != CURLE_OK) {
			cout <<  "device curl_easy_perform() failed res code: " << res << endl;
		}
		else {
			cout << ">>>dev curl post success res code:" << res << endl;
			GetCJson(resPost0.c_str());
		}


		free(szjson);
		curl_slist_free_all(header_list);
		cJSON_Delete(json_roots);
	}
	else
	{
		printf(">>> token curl init failed");
	}
	curl_easy_cleanup(curl);
}

void TestToken()//获取电网资源业务中台回复
{
	string client_id = "2a78ecf0074111ed806c7a5cabbedfb4";//client_id=
	string client_secret = "58nOklQlP0SGEuXbrd0wgcVO7HX7IODAgvzHiCm+mAgWSadcX0we2wffjyTUYGsK";//client_secret=
	string  token_url = "http://172.40.237.145:30010/psr-auth/oauth/accessToken";
	QString  device_url = QString("http://172.40.237.145:30010/assetCenter/astQueryServices/listDeviceByFilters");

	GetToken(token_url, client_id, client_secret);//获取token
	QString xtoken = QString("x-token:") + strToken;
	GetDevice(device_url, xtoken, 1, 1, 0);//获取台账
}

void GetWebApiJson(int perpage, int page, int flag)//获取电网资源业务中台回复
{
	//string client_id = "2a78ecf0074111ed806c7a5cabbedfb4";//client_id=
	//string client_secret = "58nOklQlP0SGEuXbrd0wgcVO7HX7IODAgvzHiCm+mAgWSadcX0we2wffjyTUYGsK";//client_secret=
	//string  token_url = "http://172.40.237.145:30010/psr-auth/oauth/accessToken";
	//QString  device_url = QString("http://172.40.237.145:30010/assetCenter/astQueryServices/listDeviceByFilters");

	string client_id = CLIENT_ID;//client_id=
	string client_secret = CLIENT_SECRET;//client_secret=
	string  token_url = TOKEN_URL;
	QString  device_url = QString(DEVICE_URL);
	/*cout << "client_id1: " << client_id << ",client_secret1: " << client_secret<<",token_url1: "<< token_url.c_str()<<endl;
	cout << "client_id2: " << client_id2 << ",client_secret2: " << client_secret2 << ",token_url2: " << token_url2.c_str() << endl;*/


	GetToken(token_url, client_id, client_secret);//获取token
	QString xtoken = QString("x-token:") + strToken;
	GetDevice(device_url, xtoken, perpage, page, flag);//获取台账
}

void TestJson(char* szJson)
{
	string strJson = "{\"access_token\":\"ewasdasdqwdas123123124123123123123.asde234dx2dc.erdser34\",\"errors\":\"\",\"expires_in\":\"7200\",\"refresh_token\":\"vsdfa45sdfseq43aefsfwerfadsfanuuu50\",\"status\":\"000000\"}";

	printf(">>>>>cJSON pares 1 %s \n", strJson.c_str());
	cJSON* msg = cJSON_Parse(strJson.c_str());
	if (msg == NULL)
	{
		printf("cJSON pares error %s\n", cJSON_GetErrorPtr());
	}
	else
	{
		printf(">>>>>cJSON pares 3");
		cJSON* json_status = cJSON_GetObjectItem(msg, "status");
		cJSON* json_error = cJSON_GetObjectItem(msg, "error");
		if (json_error == NULL)
		{
			printf(">>>>>cJSON pares 4");
			cJSON* json_result = cJSON_GetObjectItem(msg, "result");
			cJSON* json_accesstoken = cJSON_GetObjectItem(msg, "access_token");

			printf(">>>>>cJSON pares 5");
			QString strToken1 = QString::fromAscii(json_accesstoken->valuestring);
			cJSON_Delete(msg);
			printf(">>>>>cJSON pares 6 %s\n ", strToken1.toAscii().data());
		}
	}

}
#endif
#if 0//WW 2023-08-29测试代码s
//get请求和post请求数据响应函数
size_t req_reply_test(void* ptr, size_t size, size_t nmemb, void* stream)
{
	//在注释的里面可以打印请求流，cookie的信息
	string* str = (string*)stream;
	(*str).append((char*)ptr, size * nmemb);
	return size * nmemb;
}
//http POST请求  
CURLcode curl_post_req(const string& url, const string& postParams, string& response)
{
	// curl初始化  
	CURL* curl = curl_easy_init();
	// curl返回值 
	CURLcode res;
	if (curl)
	{
		printf(">>>TestSMSPost in curl \n");
		// set params
		//设置curl的请求头
		struct curl_slist* header_list = NULL;
		header_list = curl_slist_append(header_list, "Content-Type:application/json; charset=UTF-8");
		header_list = curl_slist_append(header_list, "Authorization:Basic bmpjbnRlc3Q6bmpjbnBxcw==");
		curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list);

		//不接收响应头数据0代表不接收 1代表接收
		curl_easy_setopt(curl, CURLOPT_HEADER, 0);

		//设置请求为post请求
		curl_easy_setopt(curl, CURLOPT_POST, 1);

		//设置请求的URL地址
		curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
		//设置post请求的参数
		curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postParams.c_str());

		//设置ssl验证
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);

		//CURLOPT_VERBOSE的值为1时，会显示详细的调试信息
		curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);

		curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);

		//设置数据接收和写入函数
		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply);
		curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&response);

		curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);

		//设置超时时间
		curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 6);
		curl_easy_setopt(curl, CURLOPT_TIMEOUT, 6);

		printf(">>>TestSMSPost in curl post\n");
		// 开启post请求
		res = curl_easy_perform(curl);
		curl_slist_free_all(header_list);
	}
	//释放curl 
	curl_easy_cleanup(curl);
	printf(">>>TestSMSPost in curl end\n");
	return res;
}
void TestSMSPost()//WW 测试qt post
{
	printf(">>>TestSMSPost Start \n");

	string url_post0 = "http://192.168.1.13:10214/oauth/token";
	string paramsLogin0 = "grant_type=sms_code&phone=13914774158&smsCode=123456";
	string resPost0;
	CURLcode res3 = curl_post_req(url_post0, paramsLogin0, resPost0);

	printf(">>>TestSMSPost End %s\n", resPost0.c_str());
}

CURLcode curl_post_body_req(const string& url, string& response)
{

	// curl初始化  
	CURL* curl = curl_easy_init();
	// curl返回值 
	CURLcode res;
	if (curl)
	{
		printf(">>>TestBodyPost in curl \n");
		// set params
		//设置curl的请求头
		struct curl_slist* header_list = NULL;
		header_list = curl_slist_append(header_list, "Content-Type:application/json;");


		curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list);

		//不接收响应头数据0代表不接收 1代表接收
		curl_easy_setopt(curl, CURLOPT_HEADER, 0);

		//设置请求为post请求
		curl_easy_setopt(curl, CURLOPT_POST, 1);

		//设置请求的URL地址
		curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
		//设置post请求的参数
		cJSON* json_root = cJSON_CreateObject();

		//第一层
		cJSON_AddItemToObject(json_root, "sname", cJSON_CreateString("hongawen"));
		cJSON_AddItemToObject(json_root, "value", cJSON_CreateNumber(12.5));
		char* szjson = cJSON_Print(json_root);
		curl_easy_setopt(curl, CURLOPT_POSTFIELDS, szjson);

		//设置ssl验证
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);

		//CURLOPT_VERBOSE的值为1时，会显示详细的调试信息
		curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);

		curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);

		//设置数据接收和写入函数
		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply);


		string resPost0;
		curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&resPost0);


		curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);

		//设置超时时间
		curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 1);
		curl_easy_setopt(curl, CURLOPT_TIMEOUT, 1);

		printf(">>>TestBodyPost in curl post\n");
		// 开启post请求
		res = curl_easy_perform(curl);

		free(szjson);
		cJSON_Delete(json_root);
		curl_slist_free_all(header_list);
	}
	else
	{
		printf(">>> token curl init failed");
	}
	curl_easy_cleanup(curl);
}

void TestBodyPost()//WW 测试qt post
{
	printf(">>>TestBodyPost Start \n");

	string url_post0 = "http://192.168.1.111:8090/enhance/testBody";
	string resPost0;
	CURLcode res3 = curl_post_body_req(url_post0, resPost0);

	printf(">>>TestBodyPost End %s\n", resPost0.c_str());
}
#endif
//WW 2023-08-26 增加webap调用 end
//////////////////////////////////////////
///////zw修改 2023-8-30 xml模型数据库读取
int OTL_Select_xmlModel() //xml模型数据库读取
{
	try {
		OTLConnect();
		//printf("\nPostgreSL 1 %s \n", POSTGRES_SCHEMA);
		std::string str2 = POSTGRES_SCHEMA;//schame analy
		std::string str3 = POSTGRES_TABLEPREFIX;//schame analy
		std::string str1 = "select \"model_id\",\"tmnl_type\",\"tmnl_factory\",\"file_name\",\"update_time\" from \"";
		str1.append(str2);
		str1.append("\".\"");
		str1.append(str3);
		str1.append("meas_pq_icd_model_tr\" ");
		//int rtState = OTLState();
		otl_stream i(1, // buffer size
			str1.c_str(),
			//SELECT statement
			db //connect object
		);
		char MODEL_ID[64];
		char TMNL_TYPE[64];
		char TMNL_FACTORY[64];
		char FILE_NAME[128];
		otl_datetime UPDATE_TIME;
		//printf("\nPostgreSL 2\n");
		//create select stream
		while (!i.eof()) { //while not end-of-data
			//printf("\nPostgreSL 3\n");
			i >> MODEL_ID >> TMNL_TYPE >> TMNL_FACTORY >> FILE_NAME >> UPDATE_TIME;
			//QString tempdate = QString("%1-%2-%3 %4:%5:%6").arg(UPDATE_TIME.year, 4, 10, QLatin1Char('0')).arg(UPDATE_TIME.month, 2, 10, QLatin1Char('0')).arg(UPDATE_TIME.day, 2, 10, QLatin1Char('0')).arg(UPDATE_TIME.hour, 2, 10, QLatin1Char('0')).arg(UPDATE_TIME.minute, 2, 10, QLatin1Char('0')).arg(UPDATE_TIME.second, 2, 10, QLatin1Char('0'));
			//QDateTime dt = QDateTime::fromString(tempdate, "yyyy-MM-dd hh:mm:ss");
			Set_xml_databaseinfo(MODEL_ID, TMNL_TYPE, TMNL_FACTORY, FILE_NAME, UPDATE_TIME.year, UPDATE_TIME.month, UPDATE_TIME.day, UPDATE_TIME.hour, UPDATE_TIME.minute, UPDATE_TIME.second);
			//cout << "FRONT_IP=" << f2 << endl;
		}
		OTLDisconnect();
	}
	catch (otl_exception& e)
	{
		printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg);
		return e.code;
	}
	return 0;

}

int OTL_Select_DecideRecall(char* time, char* id)//判断是否需要补招
{
	int flag = 1;
	try {
		int rtState = OTLDbconnected();
		//int rtState = db.connected;
		if (rtState == 0) {
			int ret = OTLConnect();
		}
		//printf("\nPostgreSL 1 %s \n", POSTGRES_SCHEMA);
		std::string str2 = POSTGRES_SCHEMA;//schame analy
		std::string str3 = POSTGRES_TABLEPREFIX;//schame analy
		std::string str1 = "select \"exp_num\",\"act_num\" from \"";
		str1.append(str2);
		str1.append("\".\"");
		str1.append(str3);
		str1.append("meas_pq_measpoint_intact_tr\" ");
		str1.append("WHERE \"statistical_date\" = '");
		str1.append(time);
		str1.append("' AND \"monitor_id\" = '");
		str1.append(id);
		str1.append("'");
		otl_stream i(1, // buffer size
			str1.c_str(),
			//SELECT statement
			db //connect object
		);
		double exp_num;
		double act_num;
		while (!i.eof()) { //while not end-of-data
			i >> exp_num >> act_num;
			if (exp_num * 0.8 <= act_num) {
				flag = 0;
			}
			//printf("\n %f %f %f \n", exp_num, act_num, exp_num * 0.8);
		}
		//OTLDisconnect();
	}
	catch (otl_exception& e)
	{
		printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg);
		flag = 0;
	}
	return flag;
}

void OTL_Select_recall(char* time, char* id) //数据完整性补招判断
{
	try {
		QDateTime dt = QDateTime::fromString(time, "yyyy-MM-dd");
		long long starttime = dt.toMSecsSinceEpoch() / 1000;  //补招起始时间
		long long endtime = starttime + 86399;                //补招结束时间
		QList<long long> timestamp_list;                      //数据库完整性记录时间点
		QList<RecallInfo> recallinfo_list;                    //待补招队列
		QList<RecallInfo> recallinfo_list_hour;               //待补招队列-以小时为最大间隔

		int rtState = OTLDbconnected();
		//int rtState = db.connected;
		if (rtState == 0) {
			int ret = OTLConnect();
		}
		/*OTLConnect();*/
		std::string str2 = POSTGRES_SCHEMA;//schame analy
		std::string str3 = POSTGRES_TABLEPREFIX;//schame analy
		std::string str1 = "SELECT unnest(value_time) AS timestamp_value FROM \"";
		str1.append(str2);
		str1.append("\".\"");
		str1.append(str3);
		str1.append("meas_pq_measpoint_intact_tr\" ");
		str1.append("WHERE \"statistical_date\" = '");
		str1.append(time);
		str1.append("' AND \"monitor_id\" = '");
		str1.append(id);
		str1.append("' ORDER BY timestamp_value");
		otl_stream i(1, // buffer size
			str1.c_str(),
			//SELECT statement
			db //connect object
		);
		otl_datetime timestamp;
		while (!i.eof()) { //while not end-of-data
			i >> timestamp;

			struct tm timeinfo;
			timeinfo.tm_year = timestamp.year - 1900; // 年份需要减去1900
			timeinfo.tm_mon = timestamp.month - 1; // 月份需要减去1
			timeinfo.tm_mday = timestamp.day;
			timeinfo.tm_hour = timestamp.hour;
			timeinfo.tm_min = timestamp.minute;
			timeinfo.tm_sec = timestamp.second;

			time_t timestamp = std::mktime(&timeinfo);
			long long stamp = static_cast<long long>(timestamp);
			timestamp_list.append(stamp);

			/*QDateTime dt = QDateTime::fromString(time, "yyyy-MM-dd");
			long long timestamp2 = dt.toMSecsSinceEpoch() / 1000;
			printf("\n %lld \n", timestamp2);*/
			/*QString tempdate = QString("%1-%2-%3 %4:%5:%6").arg(UPDATE_TIME.year, 4, 10, QLatin1Char('0')).arg(UPDATE_TIME.month, 2, 10, QLatin1Char('0')).arg(UPDATE_TIME.day, 2, 10, QLatin1Char('0')).arg(UPDATE_TIME.hour, 2, 10, QLatin1Char('0')).arg(UPDATE_TIME.minute, 2, 10, QLatin1Char('0')).arg(UPDATE_TIME.second, 2, 10, QLatin1Char('0'));
			printf("\n %s \n", tempdate.toAscii().data());*/
			//QDateTime dt = QDateTime::fromString(tempdate, "yyyy-MM-dd hh:mm:ss");
		}
		//OTLDisconnect();

		if (timestamp_list.size() == 0) //完整性数据表无数据
		{
			RecallInfo info;
			info.starttime = starttime;
			info.endtime = endtime;
			recallinfo_list.append(info);
		}
		else if (timestamp_list.size() == 1)//存在1条数据
		{
			long long temptime = timestamp_list[0];
			if (temptime != starttime && temptime != endtime)
			{
				RecallInfo info1;
				info1.starttime = starttime;
				info1.endtime = temptime - 1;

				RecallInfo info2;
				info2.starttime = temptime + 1;
				info2.endtime = endtime;

				recallinfo_list.append(info1);
				recallinfo_list.append(info2);
			}
			else
			{
				RecallInfo info;
				info.starttime = starttime + 1;
				info.endtime = endtime - 1;
				recallinfo_list.append(info);
			}
		}
		else //存在多条数据
		{
			for (int i = 1; i < timestamp_list.size(); i++)
			{
				if (i == 1)
				{
					timestamp_list[0];//头数据
					timestamp_list[timestamp_list.size() - 1];//尾数据

					if (timestamp_list[0] - starttime > 600)
					{
						RecallInfo info;
						info.starttime = starttime + 1;
						info.endtime = timestamp_list[0] - 1;
						recallinfo_list.append(info);
					}
					if (endtime - timestamp_list[timestamp_list.size() - 1] > 600)
					{
						RecallInfo info;
						info.starttime = timestamp_list[timestamp_list.size() - 1] + 1;
						info.endtime = endtime - 1;
						recallinfo_list.append(info);
					}
				}

				long long temptime1 = timestamp_list[i - 1];
				long long temptime2 = timestamp_list[i];
				if (temptime2 - temptime1 > 600)
				{
					RecallInfo info;
					info.starttime = temptime1 + 1;
					info.endtime = temptime2 - 1;
					recallinfo_list.append(info);
				}
			}
		}

		for (int i = 0; i < recallinfo_list.size(); i++)
		{
			//printf("\n %lld ----- %11d\n", recallinfo_list[i].starttime, recallinfo_list[i].endtime);
			long long duration = recallinfo_list[i].endtime - recallinfo_list[i].starttime;
			long long max_interval = 3600;
			for (long long j = 0; j <= duration; j += max_interval)
			{
				if (j + max_interval > duration) {
					long long start = recallinfo_list[i].starttime + j;
					long long end = recallinfo_list[i].endtime;

					RecallInfo info;
					info.starttime = start - 10;
					info.endtime = end - 10;
					recallinfo_list_hour.append(info);
				}
				else {
					long long start = recallinfo_list[i].starttime + j;
					long long end = recallinfo_list[i].starttime + j + max_interval;

					RecallInfo info;
					info.starttime = start - 10;
					info.endtime = end - 10;
					recallinfo_list_hour.append(info);
				}
			}
		}

		LD_info_t* LD_info = find_LD_info_only_from_mp_id(id);
		if (LD_info == NULL || LD_info->read_flag == 0) {
			printf("\n Find LD_info == null \n");
		}
		else {
			for (int j = 0; j < recallinfo_list_hour.size(); j++) {
				CJournalRecall jr;
				jr.MonitorID = QString(LD_info->mp_id);
				jr.StartTime = QDateTime::fromTime_t(recallinfo_list_hour[j].starttime).toString("yyyy-MM-dd hh:mm:ss");
				jr.EndTime = QDateTime::fromTime_t(recallinfo_list_hour[j].endtime).toString("yyyy-MM-dd hh:mm:ss");
				jr.STEADY = QString::number(1, 10);
				jr.VOLTAGE = QString::number(1, 10);
				g_StatisticLackList_list_mutex.lock();
				g_StatisticLackList.push_back(jr);
				g_StatisticLackList_list_mutex.unlock();
			}
			//if (recallinfo_list_hour.size() != 0) {
			//	if (LD_info->autorecallcount != 0) {
			//		for (int j = 0; j < LD_info->autorecallcount; j++) {
			//			delete LD_info->autorecall[j];
			//		}
			//		delete LD_info->autorecall;
			//		LD_info->autorecallcount = 0;
			//	}
			//	LD_info->autorecallflag = 0;
			//	LD_info->autorecallcount = recallinfo_list_hour.size();
			//	LD_info->autorecall = new autorecall_t * [recallinfo_list_hour.size()];
			//	for (int j = 0; j < recallinfo_list_hour.size(); j++) {
			//		//printf("\n %lld ===== %11d\n", recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime);
			//		LD_info->autorecall[j] = new autorecall_t[1];
			//		LD_info->autorecall[j]->start = recallinfo_list_hour[j].starttime;

			//		LD_info->autorecall[j]->end = recallinfo_list_hour[j].endtime;
			//	}
			//}
		}
	}
	catch (otl_exception& e)
	{
		printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg);
	}
}

//CZY
void Get_Recall_Time(char* time, QList<RecallInfo>& recallinfo_list_hour) //数据完整性补招判断
{

	QDateTime dt = QDateTime::fromString(time, "yyyy-MM-dd");
	// 将 QDateTime 对象转换为字符串  
	QString dateTimeString = dt.toString("yyyy-MM-dd");

	printf("\nQDateTime dt is\"%s\" \n", dateTimeString.toStdString().c_str());
	long long starttime = dt.toMSecsSinceEpoch() / 1000;  //补招起始时间
	long long endtime = starttime + 86399;                //补招结束时间
	QList<long long> timestamp_list;                      //数据库完整性记录时间点
	QList<RecallInfo> recallinfo_list;                    //待补招队列
	//QList<RecallInfo> recallinfo_list_hour;               //待补招队列-以小时为最大间隔


	RecallInfo info;
	info.starttime = starttime;
	info.endtime = endtime;
	recallinfo_list.append(info);

	for (int i = 0; i < recallinfo_list.size(); i++)
	{
		//printf("\n %lld ----- %11d\n", recallinfo_list[i].starttime, recallinfo_list[i].endtime);
		long long duration = recallinfo_list[i].endtime - recallinfo_list[i].starttime;
		long long max_interval = 3600;
		for (long long j = 0; j <= duration; j += max_interval)
		{
			if (j + max_interval > duration) {
				long long start = recallinfo_list[i].starttime + j;
				long long end = recallinfo_list[i].endtime;

				RecallInfo info;
				info.starttime = start;
				info.endtime = end;
				recallinfo_list_hour.append(info);
			}
			else {
				long long start = recallinfo_list[i].starttime + j;
				long long end = recallinfo_list[i].starttime + j + max_interval;

				RecallInfo info;
				info.starttime = start;
				info.endtime = end;
				recallinfo_list_hour.append(info);
			}
		}
	}

}

char* getoneday(int num)
{
	apr_time_t	previousTime = apr_time_now();
	long long stamp = static_cast<long long>(previousTime) / 1000000;
	long long deltime = stamp - (60 * 60 * 24 * num);//减去1天
	QDateTime deltime_Qtime = QDateTime::fromTime_t(deltime);
	QString tmp_chr1 = deltime_Qtime.toString("yyyy-MM-dd");
	QByteArray byteArray = tmp_chr1.toLocal8Bit();
	char* charArray = new char[byteArray.size()];
	memcpy(charArray, byteArray.data(), byteArray.size());
	charArray[byteArray.size()] = '\0';
	return charArray;
}
void deletechar(char* day)
{
	delete[] day;
}

/// <summary>
/// 删除过期的xml
/// </summary>
void DeletcRecallXml() {
	QString cfg_dir = QString("../")/*+QString::fromAscii(subdir)*/ + QString("etc/recall");
	QString file_name = QString(subdir) + QString("_") + QString("*") + QString("_Recall.xml");

	//指定文件夹名
	QDir dir(cfg_dir);
	if (!dir.exists()) {
		qDebug() << "folder does not exist!";
		return;
	}
	QStringList filter(file_name);
	//指定查找类型和排序，按最新的修改时间获取
	QStringList files = dir.entryList(filter, QDir::Files | QDir::Readable | QDir::NoDotAndDotDot, QDir::Name | QDir::Time);

	// 设定过滤的日期和时间  
	QDateTime saveDaysAgo = QDateTime::currentDateTime().addDays(-2);

	for (int i = 0; i < files.size(); i++) {//清空读取文件
		QFileInfo fileInfo(dir.filePath(files[i]));
		if (fileInfo.lastModified() < saveDaysAgo) {
			QFile::remove(fileInfo.absoluteFilePath());

		}
	}

}

void CreateRecallXml()
{
	apr_time_t	previousTime = apr_time_now();
	long long stamp = static_cast<long long>(previousTime) / 1000000;
	QDateTime deltime_Qtime = QDateTime::fromTime_t(stamp);

	/*CJournalRecall jr;
	jr.MonitorID = QString::number(1100, 10);
	jr.StartTime = deltime_Qtime.toString("yyyy-MM-dd hh:mm:ss");
	jr.EndTime = deltime_Qtime.toString("yyyy-MM-dd hh:mm:ss");
	jr.STEADY = QString::number(1, 10);
	jr.VOLTAGE = QString::number(1, 10);
	for (int i = 0;i < 10;i++) {
		g_StatisticLackList.push_back(jr);
	}*/

	g_StatisticLackList_list_mutex.lock();
	if (g_StatisticLackList.size() > 0)
	{
		printf("insert ID_CJournalRecall_Map！\n");
		QMap<QString, QList<CJournalRecall> > ID_CJournalRecall_Map;

		list<CJournalRecall>::iterator sl = g_StatisticLackList.begin();
		while (sl != g_StatisticLackList.end())
		{
			CJournalRecall jr = *sl++;
			if (ID_CJournalRecall_Map.contains(jr.MonitorID))
			{
				ID_CJournalRecall_Map[jr.MonitorID].append(jr);
			}
			else
			{
				QList<CJournalRecall> TempList;
				TempList.append(jr);
				ID_CJournalRecall_Map.insert(jr.MonitorID, TempList);
			}
		}

		for (QMap<QString, QList<CJournalRecall> >::iterator it2 = ID_CJournalRecall_Map.begin(); it2 != ID_CJournalRecall_Map.end(); ++it2)
		{
			QString key2 = it2.key();
			QList<CJournalRecall> value2 = it2.value();

			QString cfg_dir = QString("../")/*+QString::fromAscii(subdir)*/ + QString("etc/recall/");
			QString qstrRecallPath = cfg_dir + QString(subdir) + QString("_") + QString(QString::number(g_front_seg_index, 10)) + QString("_") + key2 + QString("_") + QString(deltime_Qtime.toString("yyyyMMddhhmmss")) + QString("_Recall.xml");

			std::string strRecallPath = qstrRecallPath.toStdString();
			QFile file(strRecallPath.c_str());
			if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
				printf("补招查询完成,打开%s失败,无法写入线路补招配置！\n", qstrRecallPath.toAscii().data());
				QMap<QString, QList<CJournalRecall> >().swap(ID_CJournalRecall_Map);
				return;
			}

			QXmlStreamWriter writer(&file);
			writer.setAutoFormatting(true);
			writer.writeStartDocument();
			writer.writeStartElement("RecallList");
			writer.writeStartElement("Work");
			writer.writeEndElement();

			writer.writeStartElement("New");

			while (!value2.isEmpty())
			{
				CJournalRecall jr = value2.takeFirst();
				writer.writeStartElement("Recall");
				writer.writeAttribute("MonitorID", jr.MonitorID);
				writer.writeAttribute("StartTime", jr.StartTime);
				writer.writeAttribute("EndTime", jr.EndTime);
				writer.writeAttribute("STEADY", jr.STEADY);
				writer.writeAttribute("VOLTAGE", jr.VOLTAGE);
				writer.writeEndElement();
			}
			writer.writeEndElement();
			writer.writeEndElement();
			writer.writeEndDocument();
			file.close();
		}

		QMap<QString, QList<CJournalRecall> >().swap(ID_CJournalRecall_Map);
	}
	g_StatisticLackList.clear();
	g_StatisticLackList_list_mutex.unlock();
}
///////zw修改 2023-8-30 end

/*/////////////////////////////////////////////////////////lnk2024-10-11移除sql的测试代码/////////////////////////////////////////////////////////////*/
std::string intToString(int number) {
    if (number == 0) return "0";
    std::string str;
    bool isNegative = number < 0;
    if (isNegative) number = -number;

    while (number > 0) {
        str.insert(str.begin(), '0' + (number % 10));
        number /= 10;
    }

    if (isNegative) str.insert(str.begin(), '-');
    return str;
}

otl_datetime parseTimestamp(const std::string timestampStr) {
    otl_datetime timestamp;
	
	// 定义年、月、日、时、分、秒变量
    int year, month, day, hour, minute, second;

    // 使用字符串流进行解析
    std::istringstream ss(timestampStr);
    char discard; // 用于丢弃分隔符

    // 解析字符串
    ss >> year >> discard >> month >> discard >> day >> hour >> discard >> minute >> discard >> second;

    // 将解析的值赋给 otl_datetime
    timestamp.year = year;
    timestamp.month = month;
    timestamp.day = day;
    timestamp.hour = hour;
    timestamp.minute = minute;
    timestamp.second = second;

	return timestamp;
}

size_t req_reply_web(void* ptr, size_t size, size_t nmemb, void* stream)
{
	string* str = (string*)stream;
	(*str).append((char*)ptr, size * nmemb);
	return size * nmemb;
}

void SendWebAPI_web(const string strUrl, const char* code, char** ptr)
{
	// curl初始化  
	CURL* curl = curl_easy_init();
	// curl返回值 
	CURLcode res;
	if (curl)
	{
		char url[100];
		sprintf(url, "%s?%s", strUrl.c_str(), code);
		printf(">>>json %s\n", url);
		// 设置URL
		curl_easy_setopt(curl, CURLOPT_URL, url);

		//设置数据接收和写入函数
		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply_web);

		//数据接收
		string resPost0;
		curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&resPost0);

		//设置超时时间
		curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10);
		curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10);

		//设置header
		curl_slist* headers = NULL;
		headers = curl_slist_append(headers, "Content-Type: application/json");
		curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
		
		// 开启post请求
		res = curl_easy_perform(curl);

		// 检查请求是否成功
		if (res != CURLE_OK) {
			printf("web failed res code: ");
		}
		else {
			printf(">>> web return str:%s \n", resPost0.c_str());

			*ptr = (char*)malloc(strlen(resPost0.c_str()) + 1); // 分配足够的内存空间
			if (*ptr != NULL) {
				strcpy(*ptr, resPost0.c_str());
			}
			else {
				printf("Memory allocation failed!\n");
			}
		}
	}
	else
	{
		printf(">>> web curl init failed");
	}
	curl_easy_cleanup(curl);
}

//20241206不使用的代码lnk
#if 0
//终端识别码密钥web接口
int parse_device_web_test_ext(QMap<QString, terminal_ext*>* terminal_ext_map,const std::vector<std::string>& codes)
{
	std::cout << "parse_device_web_test_ext" << std::endl;

	std::string code = "";

	/*请求界定 */
	std::string function = codes[0];
	std::cout << "function:" << function << std::endl;

	if(function == "info"){
		code = std::string("code1=pg_ext&code2=read&code3=info");
	}

	char* terminal_code=NULL;
	char* terminal_identify_code=NULL;
	char* terminal_key=NULL;

	char* ptr=NULL;

	terminal_ext* ext;

	try{
		SendWebAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", code.c_str(), &ptr);

		//调试用
		printf("ptr:%s\n",ptr);

		cJSON* json = cJSON_Parse(ptr);   //json格式序列化
		cJSON* json_node = NULL;;
		cJSON* json_records = NULL;;
		cJSON* json_value = NULL;

		int array_size = 0;

		int i = 0;

		if (json == NULL) {
			printf("web error %s\n", cJSON_GetErrorPtr());
			//重发多次
			while(json == NULL){
				SendWebAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", code.c_str(), &ptr);
				json = cJSON_Parse(ptr);
				i++;if(i>3)break;
			}
		}
		else {
			json_node = cJSON_GetObjectItem(json, "result");    //获取result根节点

			json_records = cJSON_GetObjectItem(json_node, "records");    //获取记录节点

			array_size = cJSON_GetArraySize(json_records);    //获取记录数组大小

			for(i = 0;i<array_size;i++){

				json_node = cJSON_GetArrayItem(json_records, i);			//获取数组中的节点

				json_value = cJSON_GetObjectItem(json_node, "terminal_code");    //获取result
				if (json_value && json_value->type == cJSON_String) {
					if (terminal_code != NULL) {
						// 如果已经分配了内存，则释放内存
						free(terminal_code);
					}
					terminal_code = (char*)malloc(strlen(json_value->valuestring) + 1);  // 分配内存
					strcpy(terminal_code, json_value->valuestring);
					std::cout << "terminal_code:" << terminal_code <<std::endl;
				}
				json_value = cJSON_GetObjectItem(json_node, "terminal_identify_code");    //获取result
				if (json_value && json_value->type == cJSON_String) {
					if (terminal_identify_code != NULL) {
						// 如果已经分配了内存，则释放内存
						free(terminal_identify_code);
					}
					terminal_identify_code = (char*)malloc(strlen(json_value->valuestring) + 1);  // 分配内存
					strcpy(terminal_identify_code, json_value->valuestring);
					std::cout << "terminal_identify_code:" << terminal_identify_code <<std::endl;
				}
				json_value = cJSON_GetObjectItem(json_node, "terminal_key");    //获取result
				if (json_value && json_value->type == cJSON_String) {
					if (terminal_key != NULL) {
						// 如果已经分配了内存，则释放内存
						free(terminal_key);
					}
					terminal_key = (char*)malloc(strlen(json_value->valuestring) + 1);  // 分配内存
					strcpy(terminal_key, json_value->valuestring);
					std::cout << "terminal_key:" << terminal_key <<std::endl;
				}

				/*遍历一条记录一条 */
				if (!terminal_ext_map->contains(terminal_code)) {
					ext = new terminal_ext();
					terminal_ext_map->insert(terminal_code, ext);
					apr_snprintf(ext->terminal_identify_code, sizeof(ext->terminal_identify_code), "%s", terminal_identify_code);//terminal_code
					apr_snprintf(ext->terminal_key, sizeof(ext->terminal_key), "%s", terminal_key);//terminal_code
				}
				else
				{
					qDebug() << terminal_code << endl;
				}
			}	
		}
		if (ptr) {
			free(ptr);
		}
		cJSON_Delete(json);

		return APR_SUCCESS;
	}
	catch (const std::exception& e) {
		cout << "Exception caught: " << e.what() << endl;
		// 这里可以添加其他异常处理逻辑
	}
}
//模型web接口
int parse_model_web_test(QMap<QString, icd_model*>* icd_model_map,const std::vector<std::string>& codes)
{
	std::cout << "parse_model_web_test" << std::endl;

	std::string code = "";

	/*请求界定 */
	std::string function = codes[0];
	std::cout << "function:" << function << std::endl;

	if(function == "info"){
		code = std::string("code1=model&code2=read&code3=info");
	}

	char* model_id=NULL;
	char* tmnl_type=NULL;
	char* tmnl_factory=NULL;
	char* file_name=NULL;
	char* timestamp=NULL;

	char* ptr=NULL;

	icd_model* model;

	try{
		SendWebAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", code.c_str(), &ptr);

		//调试用
		printf("ptr:%s\n",ptr);

		cJSON* json = cJSON_Parse(ptr);   //json格式序列化
		cJSON* json_node = NULL;;
		cJSON* json_records = NULL;;
		cJSON* json_value = NULL;

		int array_size = 0;

		int i = 0;

		if (json == NULL) {
			printf("web error %s\n", cJSON_GetErrorPtr());
			//重发多次
			while(json == NULL){
				SendWebAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", code.c_str(), &ptr);
				json = cJSON_Parse(ptr);
				i++;if(i>3)break;
			}
		}
		else {
			json_node = cJSON_GetObjectItem(json, "result");    //获取result根节点

			json_records = cJSON_GetObjectItem(json_node, "records");    //获取记录节点

			array_size = cJSON_GetArraySize(json_records);    //获取记录数组大小

			for(i = 0;i<array_size;i++){

				json_node = cJSON_GetArrayItem(json_records, i);			//获取数组中的节点

				json_value = cJSON_GetObjectItem(json_node, "model_id");    //获取result
				if (json_value && json_value->type == cJSON_String) {
					if (model_id != NULL) {
						// 如果已经分配了内存，则释放内存
						free(model_id);
					}
					model_id = (char*)malloc(strlen(json_value->valuestring) + 1);  // 分配内存
					strcpy(model_id, json_value->valuestring);
					std::cout << "model_id:" << model_id <<std::endl;
				}
				json_value = cJSON_GetObjectItem(json_node, "tmnl_type");    //获取result
				if (json_value && json_value->type == cJSON_String) {
					if (tmnl_type != NULL) {
						// 如果已经分配了内存，则释放内存
						free(tmnl_type);
					}
					tmnl_type = (char*)malloc(strlen(json_value->valuestring) + 1);  // 分配内存
					strcpy(tmnl_type, json_value->valuestring);
					std::cout << "tmnl_type:" << tmnl_type <<std::endl;
				}
				json_value = cJSON_GetObjectItem(json_node, "tmnl_factory");    //获取result
				if (json_value && json_value->type == cJSON_String) {
					if (tmnl_factory != NULL) {
						// 如果已经分配了内存，则释放内存
						free(tmnl_factory);
					}
					tmnl_factory = (char*)malloc(strlen(json_value->valuestring) + 1);  // 分配内存
					strcpy(tmnl_factory, json_value->valuestring);
					std::cout << "tmnl_factory:" << tmnl_factory <<std::endl;
				}
				json_value = cJSON_GetObjectItem(json_node, "file_name");    //获取result
				if (json_value && json_value->type == cJSON_String) {
					if (file_name != NULL) {
						// 如果已经分配了内存，则释放内存
						free(file_name);
					}
					file_name = (char*)malloc(strlen(json_value->valuestring) + 1);  // 分配内存
					strcpy(file_name, json_value->valuestring);
					std::cout << "file_name:" << file_name <<std::endl;
				}
								json_value = cJSON_GetObjectItem(json_node, "timestamp");    //获取result
				if (json_value && json_value->type == cJSON_String) {
					if (timestamp != NULL) {
						// 如果已经分配了内存，则释放内存
						free(timestamp);
					}
					timestamp = (char*)malloc(strlen(json_value->valuestring) + 1);  // 分配内存
					strcpy(timestamp, json_value->valuestring);
					std::cout << "timestamp:" << timestamp <<std::endl;
				}

				/*遍历一条记录一条 */
				if (!icd_model_map->contains(model_id)) {
					model = new icd_model();
					icd_model_map->insert(model_id, model);
					apr_snprintf(model->model_id, sizeof(model->model_id), "%s", model_id);//org_name
					apr_snprintf(model->tmnl_type, sizeof(model->tmnl_type), "%s", tmnl_type);//maint_name
					apr_snprintf(model->tmnl_factory, sizeof(model->tmnl_factory), "%s", tmnl_factory);//station_name
					apr_snprintf(model->file_name, sizeof(model->file_name), "%s", file_name);//addr_str
					apr_snprintf(model->timestamp, sizeof(model->timestamp), "%s", timestamp);//timestamp
				}
				else
				{
					qDebug() << model_id << endl;
				}
			}	
		}
		if (ptr) {
			free(ptr);
		}
		cJSON_Delete(json);

		return APR_SUCCESS;
	}
	catch (const std::exception& e) {
		cout << "Exception caught: " << e.what() << endl;
		// 这里可以添加其他异常处理逻辑
	}
}
//监测点台账web接口
int parse_line_web_test(QMap<QString, ledger_monitor*>* ledger_monitor_map,const std::vector<std::string>& codes)
{
	std::cout << "parse_line_web_test" << std::endl;

	std::string code = "";

	/*请求界定 */
	std::string function = codes[0];
	std::cout << "function:" << function << std::endl;

	if(function == "info"){
		code = std::string("code1=line&code2=read&code3=info");
	}
	else if(function == "count_cfg"){
		//code = std::string("code1=line&code2=read&code3=count_cfg");	//读取台账表的记录总数
	}

	char* ptr=NULL;

	char* monitor_id=NULL;
	char* terminal_code=NULL;
	char* monitor_name=NULL;
	char* logical_device_seq=NULL;
	char* voltage_level=NULL;
	char* terminal_connect=NULL;
	char* timestamp=NULL;
	char* count=NULL;

	ledger_monitor* line;

	try{
		SendWebAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", code.c_str(), &ptr);

		//调试用
		printf("ptr:%s\n",ptr);

		cJSON* json = cJSON_Parse(ptr);   //json格式序列化
		cJSON* json_node = NULL;;
		cJSON* json_records = NULL;;
		cJSON* json_value = NULL;

		int array_size = 0;

		int i = 0;

		if (json == NULL) {
			printf("web error %s\n", cJSON_GetErrorPtr());

			//重发多次
			while(json == NULL){
				SendWebAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", code.c_str(), &ptr);
				json = cJSON_Parse(ptr);
				i++;if(i>3)break;
			}
		}
		if (json != NULL) {

			json_node = cJSON_GetObjectItem(json, "result");    //获取result根节点

			json_records = cJSON_GetObjectItem(json_node, "records");    //获取记录节点

			array_size = cJSON_GetArraySize(json_records);    //获取记录数组大小

			for(i = 0;i<array_size;i++){

				json_node = cJSON_GetArrayItem(json_records, i);			//获取数组中的节点

				json_value = cJSON_GetObjectItem(json_node, "monitor_id");    //获取result
				if (json_value && json_value->type == cJSON_String) {
					if (monitor_id != NULL) {
						// 如果已经分配了内存，则释放内存
						free(monitor_id);
					}
					monitor_id = (char*)malloc(strlen(json_value->valuestring) + 1);  // 分配内存
					strcpy(monitor_id, json_value->valuestring);
					std::cout << "monitor_id:" << monitor_id <<std::endl;
				}
				json_value = cJSON_GetObjectItem(json_node, "terminal_code");    //获取result
				if (json_value && json_value->type == cJSON_String) {
					if (terminal_code != NULL) {
						// 如果已经分配了内存，则释放内存
						free(terminal_code);
					}
					terminal_code = (char*)malloc(strlen(json_value->valuestring) + 1);  // 分配内存
					strcpy(terminal_code, json_value->valuestring);
					std::cout << "terminal_code:" << terminal_code <<std::endl;
				}
				json_value = cJSON_GetObjectItem(json_node, "monitor_name");    //获取result
				if (json_value && json_value->type == cJSON_String) {
					if (monitor_name != NULL) {
						// 如果已经分配了内存，则释放内存
						free(monitor_name);
					}
					monitor_name = (char*)malloc(strlen(json_value->valuestring) + 1);  // 分配内存
					strcpy(monitor_name, json_value->valuestring);
					std::cout << "monitor_name:" << monitor_name <<std::endl;
				}
				json_value = cJSON_GetObjectItem(json_node, "logical_device_seq");    //获取result
				if (json_value && json_value->type == cJSON_String) {
					if (logical_device_seq != NULL) {
						// 如果已经分配了内存，则释放内存
						free(logical_device_seq);
					}
					logical_device_seq = (char*)malloc(strlen(json_value->valuestring) + 1);  // 分配内存
					strcpy(logical_device_seq, json_value->valuestring);
					std::cout << "logical_device_seq:" << logical_device_seq <<std::endl;
				}
				json_value = cJSON_GetObjectItem(json_node, "voltage_level");    //获取result
				if (json_value && json_value->type == cJSON_String) {
					if (voltage_level != NULL) {
						// 如果已经分配了内存，则释放内存
						free(voltage_level);
					}
					voltage_level = (char*)malloc(strlen(json_value->valuestring) + 1);  // 分配内存
					strcpy(voltage_level, json_value->valuestring);
					std::cout << "voltage_level:" << voltage_level <<std::endl;
				}
				json_value = cJSON_GetObjectItem(json_node, "terminal_connect");    //获取result
				if (json_value && json_value->type == cJSON_String) {
					if (terminal_connect != NULL) {
						// 如果已经分配了内存，则释放内存
						free(terminal_connect);
					}
					terminal_connect = (char*)malloc(strlen(json_value->valuestring) + 1);  // 分配内存
					strcpy(terminal_connect, json_value->valuestring);
					std::cout << "terminal_connect:" << terminal_connect <<std::endl;
				}

				json_value = cJSON_GetObjectItem(json_node, "timestamp");    //获取result
				if (json_value && json_value->type == cJSON_String) {
					if (timestamp != NULL) {
						// 如果已经分配了内存，则释放内存
						free(timestamp);
					}
					timestamp = (char*)malloc(strlen(json_value->valuestring) + 1);  // 分配内存
					strcpy(timestamp, json_value->valuestring);
					std::cout << "timestamp:" << timestamp <<std::endl;
				}
//添加一个数据库计数的读取
				json_value = cJSON_GetObjectItem(json_node, "count");    //获取result
				if (json_value && json_value->type == cJSON_String) {
					if (count != NULL) {
						// 如果已经分配了内存，则释放内存
						free(count);
					}
					count = (char*)malloc(strlen(json_value->valuestring) + 1);  // 分配内存
					strcpy(count, json_value->valuestring);
					std::cout << "count:" << count <<std::endl;
				}
				/*遍历一条记录一条 */
				if (!ledger_monitor_map->contains(monitor_id)) {
					line = new ledger_monitor();
					
					if(function == "info"){
						ledger_monitor_map->insert(monitor_id, line);
						apr_snprintf(line->monitor_id, sizeof(line->monitor_id), "%s", monitor_id);//terminal_id
						apr_snprintf(line->terminal_code, sizeof(line->terminal_code), "%s", terminal_code);//terminal_code
						apr_snprintf(line->monitor_name, sizeof(line->monitor_name), "%s", monitor_name);//org_name
						apr_snprintf(line->logical_device_seq, sizeof(line->logical_device_seq), "%s", logical_device_seq);//maint_name
						apr_snprintf(line->voltage_level, sizeof(line->voltage_level), "%s", voltage_level);//station_name
						apr_snprintf(line->terminal_connect, sizeof(line->terminal_connect), "%s", terminal_connect);//addr_str
						apr_snprintf(line->timestamp, sizeof(line->timestamp), "%s", timestamp);//timestamp
					}
					else if(function == "count_cfg"){
						ledger_monitor_map->insert("count_cfg", line);
						apr_snprintf(line->count_cfg, sizeof(line->count_cfg), "%s", count);//表count
					}
				}
				else
				{
					qDebug() << monitor_id << endl;
				}
			}	
		}

		/* 根据前置现有的终端号筛选监测点 */
		/* 遍历 ledger_monitor_map 容器并删除不在 g_node->n_clients 中的 terminal_code */
		QMap<QString, ledger_monitor*>::iterator it;
		it = ledger_monitor_map->begin();
		while (it != ledger_monitor_map->end()) {
		    // 假设 value 是一个结构体，包含 terminal_code
		    ledger_monitor* data = it.value();  // 获取 monitor_id 对应的数据
		    std::string terminal_code_line = data->terminal_code;  // 从数据中提取 terminal_code

		    // 标志是否找到匹配的终端号
		    bool found = false;

		    // 遍历 g_node->n_clients，检查 terminal_code 是否存在
		    for (int dev_no = 0; dev_no < g_node->n_clients; dev_no++) {
		        ied_usr_t* user_ext = (ied_usr_t*)(g_node->clients[dev_no]->usr_ext);
		        std::string client_terminal_code = user_ext->terminal_code;

		        // 如果找到了匹配的终端号，标记 found 为 true 并停止循环
		        if (client_terminal_code == terminal_code_line) {

		            found = true;
		            break;
		        }
		    }

		    // 如果没找到匹配的 terminal_code，就删除该记录
		    if (!found) {

		        it = ledger_monitor_map->erase(it);  // 删除当前记录，erase 会返回下一个迭代器
		        std::cout << "Removed monitor_id: " << it.key().toStdString() << " with terminal_code: " << terminal_code << std::endl;  // 调试输出
		    } else {
		        ++it;  // 否则继续下一个记录
		    }
		}

		if (ptr) {
			free(ptr);
		}
		cJSON_Delete(json);

		return APR_SUCCESS;
	}
	catch (const std::exception& e) {
		cout << "Exception caught: " << e.what() << endl;
		// 这里可以添加其他异常处理逻辑
	}
}
//终端台账web接口
int parse_device_web_test_dev(QMap<QString, terminal_dev*>* terminal_dev_map,const std::vector<std::string>& codes)
{
	std::cout << "parse_device_web_test_dev" << std::endl;

	std::string code = "";

	/*请求界定 */
	std::string function = codes[0];
	std::cout << "function:" << function << std::endl;

	if(function == "info"){

		/*入参初始化 */
    	std::string front_inst = "";
    	std::string mp_number = "";
    	std::string cnt_cfg = "";
    	std::string mult_flag = "";
    	std::string front_num = "";

    	//入参

    	    front_inst = codes[1];
    	    mp_number = codes[2];
    	    cnt_cfg = codes[3];
    	    mult_flag = codes[4];   //单/多前置
    	    front_num = codes[5];

    	    std::cout << "param:" << front_inst << mp_number << cnt_cfg << mult_flag << front_num << std::endl;


		code = std::string("code1=pg_dev&code2=read&code3=info") + "&code4=" + front_inst + "&code5=" + mp_number + "&code6=" + cnt_cfg + "&code7=" + mult_flag + "&code8=" + front_num;

	}
	else if(function == "count_cfg"){

		code = std::string("code1=pg_dev&code2=read&code3=count_cfg");	//读取台账表的记录总数
	}

	char* ptr=NULL;

	char* terminal_id=NULL;
	char* terminal_code=NULL;
	char* org_name=NULL;
	char* maint_name=NULL;
	char* station_name=NULL;
	char* addr_str=NULL;
	char* port=NULL;
	char* tmnl_factory=NULL;
	char* dev_type=NULL;
	char* tmnl_status=NULL;
	char* timestamp=NULL;
	char* count=NULL;

	terminal_dev* dev;

	try{
		//参数：pg_dev取终端台账，后续的参数分别为：FRONT_INST 前置实例号;mp_num 前置对应检测点数;count_cfg 前置表读取的检测点数;MULTIPLE_NODE_FLAG 多前置标志;g_front_seg_num 多前置前置总数;
		SendWebAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", code.c_str(), &ptr);

		//调试用
		printf("ptr:%s\n",ptr);

		cJSON* json = cJSON_Parse(ptr);   //json格式序列化
		cJSON* json_node = NULL;;
		cJSON* json_records = NULL;;
		cJSON* json_value = NULL;

		int array_size = 0;

		int i = 0;

		if (json == NULL) {
			printf("web error %s\n", cJSON_GetErrorPtr());

			//重发多次
			while(json == NULL){
				SendWebAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", code.c_str(), &ptr);
				json = cJSON_Parse(ptr);
				i++;if(i>3)break;
			}
		}
		if (json != NULL) {

			json_node = cJSON_GetObjectItem(json, "result");    //获取result根节点

			json_records = cJSON_GetObjectItem(json_node, "records");    //获取记录节点

			array_size = cJSON_GetArraySize(json_records);    //获取记录数组大小

			for(i = 0;i<array_size;i++){

				json_node = cJSON_GetArrayItem(json_records, i);			//获取数组中的节点

				json_value = cJSON_GetObjectItem(json_node, "terminal_id");    //获取result
				if (json_value && json_value->type == cJSON_String) {
					if (terminal_id != NULL) {
						// 如果已经分配了内存，则释放内存
						free(terminal_id);
					}
					terminal_id = (char*)malloc(strlen(json_value->valuestring) + 1);  // 分配内存
					strcpy(terminal_id, json_value->valuestring);
					std::cout << "terminal_id:" << terminal_id <<std::endl;
				}
				json_value = cJSON_GetObjectItem(json_node, "terminal_code");    //获取result
				if (json_value && json_value->type == cJSON_String) {
					if (terminal_code != NULL) {
						// 如果已经分配了内存，则释放内存
						free(terminal_code);
					}
					terminal_code = (char*)malloc(strlen(json_value->valuestring) + 1);  // 分配内存
					strcpy(terminal_code, json_value->valuestring);
					std::cout << "terminal_code:" << terminal_code <<std::endl;
				}
				json_value = cJSON_GetObjectItem(json_node, "org_name");    //获取result
				if (json_value && json_value->type == cJSON_String) {
					if (org_name != NULL) {
						// 如果已经分配了内存，则释放内存
						free(org_name);
					}
					org_name = (char*)malloc(strlen(json_value->valuestring) + 1);  // 分配内存
					strcpy(org_name, json_value->valuestring);
					std::cout << "org_name:" << org_name <<std::endl;
				}
				json_value = cJSON_GetObjectItem(json_node, "maint_name");    //获取result
				if (json_value && json_value->type == cJSON_String) {
					if (maint_name != NULL) {
						// 如果已经分配了内存，则释放内存
						free(maint_name);
					}
					maint_name = (char*)malloc(strlen(json_value->valuestring) + 1);  // 分配内存
					strcpy(maint_name, json_value->valuestring);
					std::cout << "maint_name:" << maint_name <<std::endl;
				}
				json_value = cJSON_GetObjectItem(json_node, "station_name");    //获取result
				if (json_value && json_value->type == cJSON_String) {
					if (station_name != NULL) {
						// 如果已经分配了内存，则释放内存
						free(station_name);
					}
					station_name = (char*)malloc(strlen(json_value->valuestring) + 1);  // 分配内存
					strcpy(station_name, json_value->valuestring);
					std::cout << "station_name:" << station_name <<std::endl;
				}
				json_value = cJSON_GetObjectItem(json_node, "addr_str");    //获取result
				if (json_value && json_value->type == cJSON_String) {
					if (addr_str != NULL) {
						// 如果已经分配了内存，则释放内存
						free(addr_str);
					}
					addr_str = (char*)malloc(strlen(json_value->valuestring) + 1);  // 分配内存
					strcpy(addr_str, json_value->valuestring);
					std::cout << "addr_str:" << addr_str <<std::endl;
				}
				json_value = cJSON_GetObjectItem(json_node, "port");    //获取result
				if (json_value && json_value->type == cJSON_String) {
					if (port != NULL) {
						// 如果已经分配了内存，则释放内存
						free(port);
					}
					port = (char*)malloc(strlen(json_value->valuestring) + 1);  // 分配内存
					strcpy(port, json_value->valuestring);
					std::cout << "port:" << port <<std::endl;					
				}
				json_value = cJSON_GetObjectItem(json_node, "tmnl_factory");    //获取result
				if (json_value && json_value->type == cJSON_String) {
					if (tmnl_factory != NULL) {
						// 如果已经分配了内存，则释放内存
						free(tmnl_factory);
					}
					tmnl_factory = (char*)malloc(strlen(json_value->valuestring) + 1);  // 分配内存
					strcpy(tmnl_factory, json_value->valuestring);
					std::cout << "tmnl_factory:" << tmnl_factory <<std::endl;
				}
				json_value = cJSON_GetObjectItem(json_node, "dev_type");    //获取result
				if (json_value && json_value->type == cJSON_String) {
					if (dev_type != NULL) {
						// 如果已经分配了内存，则释放内存
						free(dev_type);
					}
					dev_type = (char*)malloc(strlen(json_value->valuestring) + 1);  // 分配内存
					strcpy(dev_type, json_value->valuestring);
					std::cout << "dev_type:" << dev_type <<std::endl;
				}
				json_value = cJSON_GetObjectItem(json_node, "tmnl_status");    //获取result
				if (json_value && json_value->type == cJSON_String) {
					if (tmnl_status != NULL) {
						// 如果已经分配了内存，则释放内存
						free(tmnl_status);
					}
					tmnl_status = (char*)malloc(strlen(json_value->valuestring) + 1);  // 分配内存
					strcpy(tmnl_status, json_value->valuestring);
					std::cout << "tmnl_status:" << tmnl_status <<std::endl;
				}
				json_value = cJSON_GetObjectItem(json_node, "timestamp");    //获取result
				if (json_value && json_value->type == cJSON_String) {
					if (timestamp != NULL) {
						// 如果已经分配了内存，则释放内存
						free(timestamp);
					}
					timestamp = (char*)malloc(strlen(json_value->valuestring) + 1);  // 分配内存
					strcpy(timestamp, json_value->valuestring);
					std::cout << "timestamp:" << timestamp <<std::endl;
				}
//添加一个数据库计数的读取
				json_value = cJSON_GetObjectItem(json_node, "count");    //获取result
				if (json_value && json_value->type == cJSON_String) {
					if (count != NULL) {
						// 如果已经分配了内存，则释放内存
						free(count);
					}
					count = (char*)malloc(strlen(json_value->valuestring) + 1);  // 分配内存
					strcpy(count, json_value->valuestring);
					std::cout << "count:" << count <<std::endl;
				}

				/*遍历一条记录一条 */
				if (!terminal_dev_map->contains(terminal_code)) {
					dev = new terminal_dev();
					
					if(function == "info"){
						terminal_dev_map->insert(terminal_code, dev);
						apr_snprintf(dev->terminal_id, sizeof(dev->terminal_id), "%s", terminal_id);//terminal_id
						apr_snprintf(dev->terminal_code, sizeof(dev->terminal_code), "%s", terminal_code);//terminal_code
						apr_snprintf(dev->org_name, sizeof(dev->org_name), "%s", org_name);//org_name
						apr_snprintf(dev->maint_name, sizeof(dev->maint_name), "%s", maint_name);//maint_name
						apr_snprintf(dev->station_name, sizeof(dev->station_name), "%s", station_name);//station_name
						apr_snprintf(dev->addr_str, sizeof(dev->addr_str), "%s", addr_str);//addr_str
						apr_snprintf(dev->port, sizeof(dev->port), "%s", port);//port_int
						apr_snprintf(dev->tmnl_factory, sizeof(dev->tmnl_factory), "%s", tmnl_factory);//tmnl_factory
						apr_snprintf(dev->dev_type, sizeof(dev->dev_type), "%s", dev_type);//dev_type
						apr_snprintf(dev->tmnl_status, sizeof(dev->tmnl_status), "%s", tmnl_status);//tmnl_status
						apr_snprintf(dev->timestamp, sizeof(dev->timestamp), "%s", timestamp);//timestamp
					}
					else if(function == "count_cfg"){
						terminal_dev_map->insert("count_cfg", dev);
						apr_snprintf(dev->count_cfg, sizeof(dev->count_cfg), "%s", count);//表count
					}
				}
				else
				{
					qDebug() << terminal_code << endl;
				}
			}	
		}
		if (ptr) {
			free(ptr);
		}
		cJSON_Delete(json);

		return APR_SUCCESS;
	}
	catch (const std::exception& e) {
		cout << "Exception caught: " << e.what() << endl;
		// 这里可以添加其他异常处理逻辑
	}
}
//前置表web接口-写
int parse_device_web_test_front_write(const std::vector<std::string>& codes)
{
	std::cout << "parse_device_web_test_front_write" << std::endl;

	std::string code = "";

	/*请求界定 */
	std::string function = codes[0];
	std::cout << "function:" << function << std::endl;

	char* ret=NULL;

	char* ptr=NULL;

	if(function == "insertfront"){

		/*入参初始化 */
    	std::string front_ip = "";
    	std::string front_inst = "";
    	std::string front_type = "";
    	std::string program_version = "";
		std::string front_status = "";
    	//入参
    	front_ip = codes[1];
    	front_inst = codes[2];
    	front_type = codes[3];
    	program_version = codes[4];
		front_status = codes[5];
    	std::cout << "insert param:" << front_ip << front_inst << front_type << program_version << front_status <<std::endl;

		//构造参数
		code = std::string("code1=pg_front&code2=write&code3=insertfront") + "&code4=" + front_ip + "&code5=" + front_inst + "&code6=" + front_type + "&code7=" + program_version+ "&code8=" + front_status;
	}
	else if(function == "his"){

		/*入参初始化 */
    	std::string front_ip = "";
    	std::string program_version = "";
		std::string mp_num = "";
    	//入参
    	front_ip = codes[1];
    	program_version = codes[2];
		mp_num = codes[3];

    	std::cout << "insert param:" << front_ip << program_version << mp_num <<std::endl;

		//构造参数
		code = std::string("code1=pg_front&code2=write&code3=his") + "&code4=" + front_ip + "&code5=" + program_version + "&code6=" + mp_num;
	}
	else if(function == "updatefront"){
		/*入参初始化 */
    	std::string front_ip = "";
    	std::string front_inst = "";
    	std::string count_real = "";
		std::string front_version = "";

    	//入参
    	front_ip = codes[1];
    	front_inst = codes[2];
    	count_real = codes[3];
		front_version = code[4];

    	std::cout << "update param:" << front_ip << front_inst << count_real << std::endl;

		code = std::string("code1=pg_front&code2=write&code3=updatefront") + "&code4=" + front_ip + "&code5=" + front_inst + "&code6=" + count_real + "&code7=" + front_version;
	}

	try{
		SendWebAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", code.c_str(), &ptr);

		//调试用
		printf("ptr:%s\n",ptr);

		cJSON* json = cJSON_Parse(ptr);   //json格式序列化
		cJSON* json_node = NULL;;
		cJSON* json_records = NULL;;
		cJSON* json_value = NULL;

		int array_size = 0;

		int i = 0;

		if (json == NULL) {
			printf("web error %s\n", cJSON_GetErrorPtr());
			//重发多次
			while(json == NULL){
				SendWebAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", code.c_str(), &ptr);
				json = cJSON_Parse(ptr);
				i++;if(i>3)break;
			}
		}
		else {
			json_node = cJSON_GetObjectItem(json, "result");    //获取result根节点

			json_records = cJSON_GetObjectItem(json_node, "records");    //获取记录节点

			array_size = cJSON_GetArraySize(json_records);    //获取记录数组大小

			for(i = 0;i<array_size;i++){

				json_node = cJSON_GetArrayItem(json_records, i);			//获取数组中的节点

				json_value = cJSON_GetObjectItem(json_node, "ret");    //获取result
				if (json_value && json_value->type == cJSON_String) {
					if (ret != NULL) {
						// 如果已经分配了内存，则释放内存
						free(ret);
					}
					ret = (char*)malloc(strlen(json_value->valuestring) + 1);  // 分配内存
					strcpy(ret, json_value->valuestring);
					std::cout << "ret:" << ret <<std::endl;
				}
			}	
		}
		if (ptr) {
			free(ptr);
		}
		cJSON_Delete(json);

		if(ret == "0")
		{
			std::cout << "插入成功"<<std::endl;
		}
		else
		{
			std::cout << "插入失败"<<std::endl;
		}

		return APR_SUCCESS;
	}
	catch (const std::exception& e) {
		cout << "Exception caught: " << e.what() << endl;
		// 这里可以添加其他异常处理逻辑
	}
}
//前置表web接口-读
int parse_device_web_test_front_read(QMap<QString, front_list*>* front_map,const std::vector<std::string>& codes)
{
	std::cout << "parse_device_web_test_front" << std::endl;

	std::string code = "";

	/*请求界定 */
	std::string function = codes[0];
	std::cout << "function:" << function << std::endl;

	if(function == "info"){
		code = std::string("code1=pg_front&code2=read&code3=info");
	}
	else if(function == "frontip"){
		std::string front_index = "";
        std::string front_status = "";
        front_index = codes[1];
        front_status = codes[2];
		code = std::string("code1=pg_front&code2=read&code3=frontip") + "&code4=" + front_index + "&code5=" + front_status;
	}
	else if(function == "frontstatus"){
		std::string front_ip = "";
        std::string front_index = "";
        front_ip = codes[1];
        front_index = codes[2];
		code = std::string("code1=pg_front&code2=read&code3=frontstatus") + "&code4=" + front_ip + "&code5=" + front_index;
	}

	char* front_type=NULL;
	char* mp_num=NULL;

	char* front_ip=NULL;

	char* front_status=NULL;

	char* ptr=NULL;

	//QMap<QString, front_list*> front_map;
	front_list* front;

	try{
		SendWebAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", code.c_str(), &ptr);

		//调试用
		printf("ptr:%s\n",ptr);

		cJSON* json = cJSON_Parse(ptr);   //json格式序列化
		cJSON* json_node = NULL;;
		cJSON* json_records = NULL;;
		cJSON* json_value = NULL;

		int array_size = 0;

		int i = 0;

		if (json == NULL) {
			printf("web error %s\n", cJSON_GetErrorPtr());
			//重发多次
			while(json == NULL){
				SendWebAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", code.c_str(), &ptr);
				json = cJSON_Parse(ptr);
				i++;if(i>3)break;
			}
		}
		else {
			json_node = cJSON_GetObjectItem(json, "result");    //获取result根节点

			json_records = cJSON_GetObjectItem(json_node, "records");    //获取记录节点

			array_size = cJSON_GetArraySize(json_records);    //获取记录数组大小

			for(i = 0;i<array_size;i++){

				json_node = cJSON_GetArrayItem(json_records, i);			//获取数组中的节点

				json_value = cJSON_GetObjectItem(json_node, "front_type");    //获取result
				if (json_value && json_value->type == cJSON_String) {
					if (front_type != NULL) {
						// 如果已经分配了内存，则释放内存
						free(front_type);
					}
					front_type = (char*)malloc(strlen(json_value->valuestring) + 1);  // 分配内存
					strcpy(front_type, json_value->valuestring);
					std::cout << "front_type:" << front_type <<std::endl;
				}
				json_value = cJSON_GetObjectItem(json_node, "mp_num");    //获取result
				if (json_value && json_value->type == cJSON_String) {
					if (mp_num != NULL) {
						// 如果已经分配了内存，则释放内存
						free(mp_num);
					}
					mp_num = (char*)malloc(strlen(json_value->valuestring) + 1);  // 分配内存
					strcpy(mp_num, json_value->valuestring);
					std::cout << "mp_num:" << mp_num <<std::endl;
				}
				json_value = cJSON_GetObjectItem(json_node, "front_ip");    //获取result
				if (json_value && json_value->type == cJSON_String) {
					if (front_ip != NULL) {
						// 如果已经分配了内存，则释放内存
						free(front_ip);
					}
					front_ip = (char*)malloc(strlen(json_value->valuestring) + 1);  // 分配内存
					strcpy(front_ip, json_value->valuestring);
					std::cout << "front_ip:" << front_ip <<std::endl;
				}
				json_value = cJSON_GetObjectItem(json_node, "front_status");    //获取result
				if (json_value && json_value->type == cJSON_String) {
					if (front_status != NULL) {
						// 如果已经分配了内存，则释放内存
						free(front_status);
					}
					front_status = (char*)malloc(strlen(json_value->valuestring) + 1);  // 分配内存
					strcpy(front_status, json_value->valuestring);
					std::cout << "front_status:" << front_status <<std::endl;
				}

				/*遍历一条记录一条 */
				if(function == "info"){
					if (!front_map->contains("0.0.0.0")) {
						front = new front_list();
						front_map->insert("0.0.0.0", front);
						apr_snprintf(front->front_inst, sizeof(front->front_inst), "%s", "0");//front_inst
						apr_snprintf(front->front_type, sizeof(front->front_type), "%s", front_type);//front_type
						apr_snprintf(front->mp_num, sizeof(front->mp_num), "%s", mp_num);//mp_num
					}
					else
					{
						qDebug() << "0.0.0.0 : front_type = " << front_type << "mp_num = " << mp_num << endl;
					}
				}
				else if(function == "frontip"){
					if (!front_map->contains("frontip")) {	//以"frontip"为key
						front = new front_list();
						front_map->insert("frontip", front);
						apr_snprintf(front->front_ip, sizeof(front->front_ip), "%s", front_ip);//front_type
					}
					else
					{
						qDebug() << "front_ip = " << front_ip << endl;
					}
				}
				else if(function == "frontstatus"){
					if (!front_map->contains("frontstatus")) {	//以"frontstatus"为key
						front = new front_list();
						front_map->insert("frontstatus", front);
						apr_snprintf(front->front_status, sizeof(front->front_status), "%s", front_status);//front_type
					}
					else
					{
						qDebug() << "frontstatus = " << front_status << endl;
					}
				}
			}	
		}
		if (ptr) {
			free(ptr);
		}
		cJSON_Delete(json);

		return APR_SUCCESS;
	}
	catch (const std::exception& e) {
		cout << "Exception caught: " << e.what() << endl;
		// 这里可以添加其他异常处理逻辑
	}
}
//完整性web接口-读
int parse_intact_web_test_read(QMap<QString, intact_list*>* intact_list_map,const std::vector<std::string>& codes)
{
	std::cout << "parse_intact_web_test" << std::endl;

	std::string code = "";

	/*请求界定 */
	std::string function = codes[0];
	std::cout << "function:" << function << std::endl;

	if(function == "deciderecall"){

		/*入参初始化 */
    	std::string time = "";
    	std::string id = "";

    	//入参

    	time = codes[1];
    	id = codes[2];

    	std::cout << "param:" << time << id << std::endl;

		code = std::string("code1=intact&code2=read&code3=deciderecall") + "&code4=" + time + "&code5=" + id;
	}
	else if(function == "autorecall"){

		/*入参初始化 */
    	std::string time = "";
    	std::string id = "";

    	//入参

    	time = codes[1];
    	id = codes[2];

    	std::cout << "param:" << time << id << std::endl;

		code = std::string("code1=intact&code2=read&code3=autorecall") + "&code4=" + time + "&code5=" + id;
	}
	else if(function == "handlerecall"){

		/*入参初始化 */
    	std::string tmp_time = "";
    	std::string Monitorid = "";
		std::string start_time = "";
    	std::string end_time = "";

    	//入参
    	tmp_time = codes[1];
    	Monitorid = codes[2];
		start_time = codes[3];
    	end_time = codes[4];

    	std::cout << "param:" << tmp_time << Monitorid << start_time << end_time << std::endl;

		code = std::string("code1=intact&code2=read&code3=handlerecall") + "&code4=" + tmp_time + "&code5=" + Monitorid + "&code4=" + start_time + "&code5=" + end_time;
	}

	char* exp_num=NULL;
	char* act_num=NULL;

	char* valuetime=NULL;

	char* ptr=NULL;

	intact_list* intact;

	try{
		SendWebAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", code.c_str(), &ptr);

		//调试用
		printf("ptr:%s\n",ptr);

		cJSON* json = cJSON_Parse(ptr);   //json格式序列化
		cJSON* json_node = NULL;;
		cJSON* json_records = NULL;;
		cJSON* json_value = NULL;

		int array_size = 0;

		int i = 0;

		if (json == NULL) {
			printf("web error %s\n", cJSON_GetErrorPtr());
			//重发多次
			while(json == NULL){
				SendWebAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", code.c_str(), &ptr);
				json = cJSON_Parse(ptr);
				i++;if(i>3)break;
			}
		}
		else {
			json_node = cJSON_GetObjectItem(json, "result");    //获取result根节点

			json_records = cJSON_GetObjectItem(json_node, "records");    //获取记录节点

			array_size = cJSON_GetArraySize(json_records);    //获取记录数组大小

			for(i = 0;i<array_size;i++){

				json_node = cJSON_GetArrayItem(json_records, i);			//获取数组中的节点

				json_value = cJSON_GetObjectItem(json_node, "exp_num");    //获取result
				if (json_value && json_value->type == cJSON_String) {
					if (exp_num != NULL) {
						// 如果已经分配了内存，则释放内存
						free(exp_num);
					}
					exp_num = (char*)malloc(strlen(json_value->valuestring) + 1);  // 分配内存
					strcpy(exp_num, json_value->valuestring);
					std::cout << "exp_num:" << exp_num <<std::endl;
				}
				json_value = cJSON_GetObjectItem(json_node, "act_num");    //获取result
				if (json_value && json_value->type == cJSON_String) {
					if (act_num != NULL) {
						// 如果已经分配了内存，则释放内存
						free(act_num);
					}
					act_num = (char*)malloc(strlen(json_value->valuestring) + 1);  // 分配内存
					strcpy(act_num, json_value->valuestring);
					std::cout << "act_num:" << act_num <<std::endl;
				}
				json_value = cJSON_GetObjectItem(json_node, "valuetime");    //获取result
				if (json_value && json_value->type == cJSON_String) {
					if (valuetime != NULL) {
						// 如果已经分配了内存，则释放内存
						free(valuetime);
					}
					valuetime = (char*)malloc(strlen(json_value->valuestring) + 1);  // 分配内存
					strcpy(valuetime, json_value->valuestring);
					std::cout << "valuetime:" << valuetime <<std::endl;
				}


				/*遍历一条记录一条 */
				QString id = QString::fromStdString(codes[2]);
				if (!intact_list_map->contains(id)) {
					intact = new intact_list();
					intact_list_map->insert(id, intact);	//时间数据会循环多次，id会重复
					if(function == "deciderecall"){
						apr_snprintf(intact->exp_num, sizeof(intact->exp_num), "%s", exp_num);
						apr_snprintf(intact->act_num, sizeof(intact->act_num), "%s", act_num);
					}
					else if(function == "autorecall" || function == "handlerecall"){
						intact->value_time.push_back(valuetime);
					}
				}
				else
				{
					intact = intact_list_map->value(id);	//找到这个id对应的类
					if(function == "deciderecall"){
						qDebug() << "exp_num = " << intact->exp_num << "act_num = " << intact->act_num << endl;
					}
					else if(function == "autorecall" || function == "handlerecall"){
						intact->value_time.push_back(valuetime);//记录到对应id的容器中
					}
				}
			}	
		}
		if (ptr) {
			free(ptr);
		}
		cJSON_Delete(json);

		return APR_SUCCESS;
	}
	catch (const std::exception& e) {
		cout << "Exception caught: " << e.what() << endl;
		// 这里可以添加其他异常处理逻辑
	}
}

//日志数据库接口
int parse_rationality_write(const std::vector<std::string>& codes)
{
	std::cout << "parse_rationality_write" << std::endl;

	std::string code = "";

	/*请求界定 */
	std::string function = codes[0];
	std::cout << "function:" << function << std::endl;

	char* ret=NULL;

	char* ptr=NULL;

	if(function == "log"){

		/*入参初始化 */
    	std::string id = "";
    	std::string time = "";
		std::string count = "";
    	std::string filename = "";

    	//入参
    	id = codes[1];
    	time = codes[2];
		count = codes[3];
    	filename = codes[4];

    	std::cout << "insert param:" << id << time << count << filename << std::endl;

		//构造参数
		code = std::string("code1=rationality&code2=write&code3=log") + "&code4=" + id + "&code5=" + time + "&code6=" + count + "&code7=" + filename;
	}
	try{
		SendWebAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", code.c_str(), &ptr);

		//调试用
		printf("ptr:%s\n",ptr);

		cJSON* json = cJSON_Parse(ptr);   //json格式序列化
		cJSON* json_node = NULL;;
		cJSON* json_records = NULL;;
		cJSON* json_value = NULL;

		int array_size = 0;

		int i = 0;

		if (json == NULL) {
			printf("web error %s\n", cJSON_GetErrorPtr());
			//重发多次
			while(json == NULL){
				SendWebAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", code.c_str(), &ptr);
				json = cJSON_Parse(ptr);
				i++;if(i>3)break;
			}
		}
		else {
			json_node = cJSON_GetObjectItem(json, "result");    //获取result根节点

			json_records = cJSON_GetObjectItem(json_node, "records");    //获取记录节点

			array_size = cJSON_GetArraySize(json_records);    //获取记录数组大小

			for(i = 0;i<array_size;i++){

				json_node = cJSON_GetArrayItem(json_records, i);			//获取数组中的节点

				json_value = cJSON_GetObjectItem(json_node, "ret");    //获取result
				if (json_value && json_value->type == cJSON_String) {
					if (ret != NULL) {
						// 如果已经分配了内存，则释放内存
						free(ret);
					}
					ret = (char*)malloc(strlen(json_value->valuestring) + 1);  // 分配内存
					strcpy(ret, json_value->valuestring);
					std::cout << "ret:" << ret <<std::endl;
				}
			}	
		}
		if (ptr) {
			free(ptr);
		}
		cJSON_Delete(json);

		if(ret == "0")
		{
			std::cout << "插入成功"<<std::endl;
		}
		else
		{
			std::cout << "插入失败"<<std::endl;
		}

		return APR_SUCCESS;
	}
	catch (const std::exception& e) {
		cout << "Exception caught: " << e.what() << endl;
		// 这里可以添加其他异常处理逻辑
	}
}

int parse_dataintegrity_write(const std::vector<std::string>& codes)
{
	std::cout << "parse_dataintegrity_write" << std::endl;

	std::string code = "";

	/*请求界定 */
	std::string function = codes[0];
	std::cout << "function:" << function << std::endl;

	char* ret=NULL;

	char* ptr=NULL;

	if(function == "log"){

		/*入参初始化 */
    	std::string time = "";
        std::string datatime = "";
        std::string monitorId = "";
        std::string recallflag = "";
        std::string msspan = "";

    	//入参
    	time = codes[1];
        datatime = codes[2];
        monitorId = codes[3];
        recallflag = codes[4];
        msspan = codes[5];

    	std::cout << "insert param:" << time << datatime << monitorId << recallflag << msspan <<std::endl;

		//构造参数
		code = std::string("code1=dataintegrity&code2=write&code3=log") + "&code4=" + time + "&code5=" + datatime + "&code6=" + monitorId + "&code7=" + recallflag + "&code8=" + msspan;
	}
	try{
		SendWebAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", code.c_str(), &ptr);

		//调试用
		printf("ptr:%s\n",ptr);

		cJSON* json = cJSON_Parse(ptr);   //json格式序列化
		cJSON* json_node = NULL;;
		cJSON* json_records = NULL;;
		cJSON* json_value = NULL;

		int array_size = 0;

		int i = 0;

		if (json == NULL) {
			printf("web error %s\n", cJSON_GetErrorPtr());
			//重发多次
			while(json == NULL){
				SendWebAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", code.c_str(), &ptr);
				json = cJSON_Parse(ptr);
				i++;if(i>3)break;
			}
		}
		else {
			json_node = cJSON_GetObjectItem(json, "result");    //获取result根节点

			json_records = cJSON_GetObjectItem(json_node, "records");    //获取记录节点

			array_size = cJSON_GetArraySize(json_records);    //获取记录数组大小

			for(i = 0;i<array_size;i++){

				json_node = cJSON_GetArrayItem(json_records, i);			//获取数组中的节点

				json_value = cJSON_GetObjectItem(json_node, "ret");    //获取result
				if (json_value && json_value->type == cJSON_String) {
					if (ret != NULL) {
						// 如果已经分配了内存，则释放内存
						free(ret);
					}
					ret = (char*)malloc(strlen(json_value->valuestring) + 1);  // 分配内存
					strcpy(ret, json_value->valuestring);
					std::cout << "ret:" << ret <<std::endl;
				}
			}	
		}
		if (ptr) {
			free(ptr);
		}
		cJSON_Delete(json);

		if(ret == "0")
		{
			std::cout << "插入成功"<<std::endl;
		}
		else
		{
			std::cout << "插入失败"<<std::endl;
		}

		return APR_SUCCESS;
	}
	catch (const std::exception& e) {
		cout << "Exception caught: " << e.what() << endl;
		// 这里可以添加其他异常处理逻辑
	}
}

int parse_match_write(const std::vector<std::string>& codes)
{
	std::cout << "parse_match_write" << std::endl;

	std::string code = "";

	/*请求界定 */
	std::string function = codes[0];
	std::cout << "function:" << function << std::endl;

	char* ret=NULL;

	char* ptr=NULL;

	if(function == "log"){

		/*入参初始化 */
    	std::string id = "";
        std::string time = "";
        std::string BASE_MAT_NUM = "";
        std::string ADV_MAT_NUM = "";
        std::string BASE_ACT_NUM = "";
        std::string ADV_ACT_NUM = "";
        std::string filename = "";

    	//入参
    	id = codes[1];
        time = codes[2];
        BASE_MAT_NUM = codes[3];
        ADV_MAT_NUM = codes[4];
        BASE_ACT_NUM = codes[5];
        ADV_ACT_NUM = codes[6];
        filename = codes[7];

    	std::cout << "insert param:" << id << time << BASE_MAT_NUM<< ADV_MAT_NUM<< BASE_ACT_NUM<< ADV_ACT_NUM<<filename <<std::endl;

		//构造参数
		code = std::string("code1=match&code2=write&code3=log") + "&code4=" + id + "&code5=" + time + "&code6=" + BASE_MAT_NUM + "&code7=" + ADV_MAT_NUM + "&code8=" + BASE_ACT_NUM + "&code9=" + ADV_ACT_NUM + "&code10=" + filename;
	}
	try{
		SendWebAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", code.c_str(), &ptr);

		//调试用
		printf("ptr:%s\n",ptr);

		cJSON* json = cJSON_Parse(ptr);   //json格式序列化
		cJSON* json_node = NULL;;
		cJSON* json_records = NULL;;
		cJSON* json_value = NULL;

		int array_size = 0;

		int i = 0;

		if (json == NULL) {
			printf("web error %s\n", cJSON_GetErrorPtr());
			//重发多次
			while(json == NULL){
				SendWebAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", code.c_str(), &ptr);
				json = cJSON_Parse(ptr);
				i++;if(i>3)break;
			}
		}
		else {
			json_node = cJSON_GetObjectItem(json, "result");    //获取result根节点

			json_records = cJSON_GetObjectItem(json_node, "records");    //获取记录节点

			array_size = cJSON_GetArraySize(json_records);    //获取记录数组大小

			for(i = 0;i<array_size;i++){

				json_node = cJSON_GetArrayItem(json_records, i);			//获取数组中的节点

				json_value = cJSON_GetObjectItem(json_node, "ret");    //获取result
				if (json_value && json_value->type == cJSON_String) {
					if (ret != NULL) {
						// 如果已经分配了内存，则释放内存
						free(ret);
					}
					ret = (char*)malloc(strlen(json_value->valuestring) + 1);  // 分配内存
					strcpy(ret, json_value->valuestring);
					std::cout << "ret:" << ret <<std::endl;
				}
			}	
		}
		if (ptr) {
			free(ptr);
		}
		cJSON_Delete(json);

		if(ret == "0")
		{
			std::cout << "插入成功"<<std::endl;
		}
		else
		{
			std::cout << "插入失败"<<std::endl;
		}

		return APR_SUCCESS;
	}
	catch (const std::exception& e) {
		cout << "Exception caught: " << e.what() << endl;
		// 这里可以添加其他异常处理逻辑
	}
}

int parse_commstatus_write(const std::vector<std::string>& codes)
{
		std::cout << "parse_commstatus_write" << std::endl;

	std::string code = "";

	/*请求界定 */
	std::string function = codes[0];
	std::cout << "function:" << function << std::endl;

	char* ret=NULL;

	char* ptr=NULL;

	if(function == "log"){

		/*入参初始化 */
    	std::string id = "";
        std::string currenttime = "";

    	//入参
    	id = codes[1];
        currenttime = codes[2];

    	std::cout << "insert param:" << id << currenttime <<std::endl;

		//构造参数
		code = std::string("code1=commstatus&code2=write&code3=log") + "&code4=" + id + "&code5=" + currenttime ;
	}
	try{
		SendWebAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", code.c_str(), &ptr);

		//调试用
		printf("ptr:%s\n",ptr);

		cJSON* json = cJSON_Parse(ptr);   //json格式序列化
		cJSON* json_node = NULL;;
		cJSON* json_records = NULL;;
		cJSON* json_value = NULL;

		int array_size = 0;

		int i = 0;

		if (json == NULL) {
			printf("web error %s\n", cJSON_GetErrorPtr());
			//重发多次
			while(json == NULL){
				SendWebAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", code.c_str(), &ptr);
				json = cJSON_Parse(ptr);
				i++;if(i>3)break;
			}
		}
		else {
			json_node = cJSON_GetObjectItem(json, "result");    //获取result根节点

			json_records = cJSON_GetObjectItem(json_node, "records");    //获取记录节点

			array_size = cJSON_GetArraySize(json_records);    //获取记录数组大小

			for(i = 0;i<array_size;i++){

				json_node = cJSON_GetArrayItem(json_records, i);			//获取数组中的节点

				json_value = cJSON_GetObjectItem(json_node, "ret");    //获取result
				if (json_value && json_value->type == cJSON_String) {
					if (ret != NULL) {
						// 如果已经分配了内存，则释放内存
						free(ret);
					}
					ret = (char*)malloc(strlen(json_value->valuestring) + 1);  // 分配内存
					strcpy(ret, json_value->valuestring);
					std::cout << "ret:" << ret <<std::endl;
				}
			}	
		}
		if (ptr) {
			free(ptr);
		}
		cJSON_Delete(json);

		if(ret == "0")
		{
			std::cout << "插入成功"<<std::endl;
		}
		else
		{
			std::cout << "插入失败"<<std::endl;
		}

		return APR_SUCCESS;
	}
	catch (const std::exception& e) {
		cout << "Exception caught: " << e.what() << endl;
		// 这里可以添加其他异常处理逻辑
	}
}

int parse_commerror_write(const std::vector<std::string>& codes)
{
	std::cout << "parse_commerror_write" << std::endl;

	std::string code = "";

	/*请求界定 */
	std::string function = codes[0];
	std::cout << "function:" << function << std::endl;

	char* ret=NULL;

	char* ptr=NULL;

	if(function == "log"){

		/*入参初始化 */
    	std::string id = "";
    	std::string time = "";
    	std::string filename = "";

    	//入参
    	id = codes[1];
    	time = codes[2];
    	filename = codes[3];

    	std::cout << "insert param:" << id << time << filename <<std::endl;

		//构造参数
		code = std::string("code1=commerror&code2=write&code3=log") + "&code4=" + id + "&code5=" + time + "&code6=" + filename;
	}
	try{
		SendWebAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", code.c_str(), &ptr);

		//调试用
		printf("ptr:%s\n",ptr);

		cJSON* json = cJSON_Parse(ptr);   //json格式序列化
		cJSON* json_node = NULL;;
		cJSON* json_records = NULL;;
		cJSON* json_value = NULL;

		int array_size = 0;

		int i = 0;

		if (json == NULL) {
			printf("web error %s\n", cJSON_GetErrorPtr());
			//重发多次
			while(json == NULL){
				SendWebAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", code.c_str(), &ptr);
				json = cJSON_Parse(ptr);
				i++;if(i>3)break;
			}
		}
		else {
			json_node = cJSON_GetObjectItem(json, "result");    //获取result根节点

			json_records = cJSON_GetObjectItem(json_node, "records");    //获取记录节点

			array_size = cJSON_GetArraySize(json_records);    //获取记录数组大小

			for(i = 0;i<array_size;i++){

				json_node = cJSON_GetArrayItem(json_records, i);			//获取数组中的节点

				json_value = cJSON_GetObjectItem(json_node, "ret");    //获取result
				if (json_value && json_value->type == cJSON_String) {
					if (ret != NULL) {
						// 如果已经分配了内存，则释放内存
						free(ret);
					}
					ret = (char*)malloc(strlen(json_value->valuestring) + 1);  // 分配内存
					strcpy(ret, json_value->valuestring);
					std::cout << "ret:" << ret <<std::endl;
				}
			}	
		}
		if (ptr) {
			free(ptr);
		}
		cJSON_Delete(json);

		if(ret == "0")
		{
			std::cout << "插入成功"<<std::endl;
		}
		else
		{
			std::cout << "插入失败"<<std::endl;
		}

		return APR_SUCCESS;
	}
	catch (const std::exception& e) {
		cout << "Exception caught: " << e.what() << endl;
		// 这里可以添加其他异常处理逻辑
	}
}

//删除的web接口
int parse_database_delete(const std::vector<std::string>& codes)
{
	std::cout << "parse_device_web_test_front" << std::endl;

	std::string code = "";

	/*请求界定 */
	std::string function = codes[0];
	std::cout << "function:" << function << std::endl;

	if(function == "ontime"){
		/*入参初始化 */
    	std::string time = "";

    	//入参
    	time = codes[1];

    	std::cout << "param:" << time << std::endl;

		code = std::string("code1=ontime&code2=delete&code3=deletetime") + "&code4=" + time;
	}

	char* ret=NULL;
	char* tablename=NULL;

	char* ptr=NULL;

	try{
		SendWebAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", code.c_str(), &ptr);

		//调试用
		printf("ptr:%s\n",ptr);

		cJSON* json = cJSON_Parse(ptr);   //json格式序列化
		cJSON* json_node = NULL;;
		cJSON* json_records = NULL;;
		cJSON* json_value = NULL;

		int array_size = 0;

		int i = 0;

		if (json == NULL) {
			printf("web error %s\n", cJSON_GetErrorPtr());
			//重发多次
			while(json == NULL){
				SendWebAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", code.c_str(), &ptr);
				json = cJSON_Parse(ptr);
				i++;if(i>3)break;
			}
		}
		else {
			json_node = cJSON_GetObjectItem(json, "result");    //获取result根节点

			json_records = cJSON_GetObjectItem(json_node, "records");    //获取记录节点

			array_size = cJSON_GetArraySize(json_records);    //获取记录数组大小

			for(i = 0;i<array_size;i++){

				json_node = cJSON_GetArrayItem(json_records, i);			//获取数组中的节点

				json_value = cJSON_GetObjectItem(json_node, "ret");    //获取result
				if (json_value && json_value->type == cJSON_String) {
					if (ret != NULL) {
						// 如果已经分配了内存，则释放内存
						free(ret);
					}
					ret = (char*)malloc(strlen(json_value->valuestring) + 1);  // 分配内存
					strcpy(ret, json_value->valuestring);
					std::cout << "ret:" << ret <<std::endl;
				}
				json_value = cJSON_GetObjectItem(json_node, "tablename");    //获取result
				if (json_value && json_value->type == cJSON_String) {
					if (tablename != NULL) {
						// 如果已经分配了内存，则释放内存
						free(tablename);
					}
					tablename = (char*)malloc(strlen(json_value->valuestring) + 1);  // 分配内存
					strcpy(tablename, json_value->valuestring);
					std::cout << "tablename:" << tablename <<std::endl;
				}

				if(ret == "0")
				{
					std::cout << tablename << "删除成功" <<std::endl;
				}
				else
				{
					std::cout <<  tablename << "删除失败" <<std::endl;
				}
			}	
		}
		if (ptr) {
			free(ptr);
		}
		cJSON_Delete(json);

		return APR_SUCCESS;
	}
	catch (const std::exception& e) {
		cout << "Exception caught: " << e.what() << endl;
		// 这里可以添加其他异常处理逻辑
	}
}

//补招的web接口，前两个未使用  不再由前置轮询，将由上层轮询手动让前置补招
int OTL_Select_DecideRecall_web(char* time, char* id)//判断是否需要补招
{
	int flag = 1;
	try {
		/*int rtState = OTLDbconnected();
		//int rtState = db.connected;
		if (rtState == 0) {
			int ret = OTLConnect();
		}
		//printf("\nPostgreSL 1 %s \n", POSTGRES_SCHEMA);
		std::string str2 = POSTGRES_SCHEMA;//schame analy
		std::string str3 = POSTGRES_TABLEPREFIX;//schame analy
		std::string str1 = "select \"exp_num\",\"act_num\" from \"";
		str1.append(str2);
		str1.append("\".\"");
		str1.append(str3);
		str1.append("meas_pq_measpoint_intact_tr\" ");
		str1.append("WHERE \"statistical_date\" = '");
		str1.append(time);
		str1.append("' AND \"monitor_id\" = '");
		str1.append(id);
		str1.append("'");
		otl_stream i(1, // buffer size
			str1.c_str(),
			//SELECT statement
			db //connect object
		);
		double exp_num;
		double act_num;
		while (!i.eof()) { //while not end-of-data
			i >> exp_num >> act_num;*/
		std::vector<std::string> codes;//入参集合
		QMap<QString, intact_list*>  intact_list_map;
		codes.push_back("deciderecall");
		codes.push_back(std::string(time));
		codes.push_back(std::string(id));

		parse_intact_web_test_read(&intact_list_map,codes);

		codes.clear();

		try {
			//char exp_num[64];
			//char act_num[64];
			double exp_num;
			double act_num;

			// 遍历终端台账容器
			QMap<QString, intact_list*>::iterator it;
    		for (it = intact_list_map.begin(); it != intact_list_map.end(); ++it) {
    			intact_list* value = it.value();

				// 确保 value 不为空
    			if (value != nullptr) {
    	    		// 找到容器中对应名称并取值
    	    		//strncpy(exp_num, value->exp_num.c_str(), sizeof(exp_num) - 1);
    	    		//strncpy(act_num, value->act_num.c_str(), sizeof(act_num) - 1);

					exp_num = atof(value->exp_num);
					act_num = atof(value->exp_num);

					std::cout << exp_num << " " << act_num << std::endl;

					if (exp_num * 0.8 <= act_num) {
						flag = 0;
					}
				}
			}
		}
		catch (otl_exception& e)
		{
			printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg);
			flag = 0;
		}
	}
	catch (otl_exception& e)
	{
		printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg);
		flag = 0;
	}

	return flag;
}

void OTL_Select_recall_web(char* time, char* id) //数据完整性补招判断
{
	try {
		QDateTime dt = QDateTime::fromString(time, "yyyy-MM-dd");
		long long starttime = dt.toMSecsSinceEpoch() / 1000;  //补招起始时间
		long long endtime = starttime + 86399;                //补招结束时间
		QList<long long> timestamp_list;                      //数据库完整性记录时间点
		QList<RecallInfo> recallinfo_list;                    //待补招队列
		QList<RecallInfo> recallinfo_list_hour;               //待补招队列-以小时为最大间隔

/*		int rtState = OTLDbconnected();
		//int rtState = db.connected;
		if (rtState == 0) {
			int ret = OTLConnect();
		}
		//OTLConnect();
		std::string str2 = POSTGRES_SCHEMA;//schame analy
		std::string str3 = POSTGRES_TABLEPREFIX;//schame analy
		std::string str1 = "SELECT unnest(value_time) AS timestamp_value FROM \"";
		str1.append(str2);
		str1.append("\".\"");
		str1.append(str3);
		str1.append("meas_pq_measpoint_intact_tr\" ");
		str1.append("WHERE \"statistical_date\" = '");
		str1.append(time);
		str1.append("' AND \"monitor_id\" = '");
		str1.append(id);
		str1.append("' ORDER BY timestamp_value");
		otl_stream i(1, // buffer size
			str1.c_str(),
			//SELECT statement
			db //connect object
		);
		otl_datetime timestamp;
		while (!i.eof()) { //while not end-of-data
			i >> timestamp;*/

		std::vector<std::string> codes;//入参集合
		QMap<QString, intact_list*>  intact_list_map;
		codes.push_back("autorecall");
		codes.push_back(std::string(time));
		codes.push_back(std::string(id));

		parse_intact_web_test_read(&intact_list_map,codes);

		codes.clear();

		try {
			otl_datetime timestamp;

			// 遍历终端台账容器
			if (intact_list_map.contains(id)) {
    			intact_list* value = intact_list_map.value(id);  // 找到键值为 "id" 的对象

    			if (value != nullptr) {
        			// 遍历 value_time 容器并输出所有时间字符串
        			for (std::vector<std::string>::const_iterator it = value->value_time.begin(); it != value->value_time.end(); ++it) {
    					const std::string& time = *it;

            			std::cout << "Time: " << time << std::endl;

						timestamp = parseTimestamp(time);

						struct tm timeinfo;
						timeinfo.tm_year = timestamp.year - 1900; // 年份需要减去1900
						timeinfo.tm_mon = timestamp.month - 1; // 月份需要减去1
						timeinfo.tm_mday = timestamp.day;
						timeinfo.tm_hour = timestamp.hour;
						timeinfo.tm_min = timestamp.minute;
						timeinfo.tm_sec = timestamp.second;

						time_t timestamp = std::mktime(&timeinfo);
						long long stamp = static_cast<long long>(timestamp);
						timestamp_list.append(stamp);

        			}
    			}
			} 
			else {
    			std::cout << "No entry found for id: " << id << std::endl;
			}


/*			struct tm timeinfo;
			timeinfo.tm_year = timestamp.year - 1900; // 年份需要减去1900
			timeinfo.tm_mon = timestamp.month - 1; // 月份需要减去1
			timeinfo.tm_mday = timestamp.day;
			timeinfo.tm_hour = timestamp.hour;
			timeinfo.tm_min = timestamp.minute;
			timeinfo.tm_sec = timestamp.second;

			time_t timestamp = std::mktime(&timeinfo);
			long long stamp = static_cast<long long>(timestamp);
			timestamp_list.append(stamp);*/

		}
		catch (otl_exception& e)
		{
			printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg);
			
		}

		if (timestamp_list.size() == 0) //完整性数据表无数据
		{
			RecallInfo info;
			info.starttime = starttime;
			info.endtime = endtime;
			recallinfo_list.append(info);
		}
		else if (timestamp_list.size() == 1)//存在1条数据
		{
			long long temptime = timestamp_list[0];
			if (temptime != starttime && temptime != endtime)
			{
				RecallInfo info1;
				info1.starttime = starttime;
				info1.endtime = temptime - 1;

				RecallInfo info2;
				info2.starttime = temptime + 1;
				info2.endtime = endtime;

				recallinfo_list.append(info1);
				recallinfo_list.append(info2);
			}
			else
			{
				RecallInfo info;
				info.starttime = starttime + 1;
				info.endtime = endtime - 1;
				recallinfo_list.append(info);
			}
		}
		else //存在多条数据
		{
			for (int i = 1; i < timestamp_list.size(); i++)
			{
				if (i == 1)
				{
					timestamp_list[0];//头数据
					timestamp_list[timestamp_list.size() - 1];//尾数据

					if (timestamp_list[0] - starttime > 600)
					{
						RecallInfo info;
						info.starttime = starttime + 1;
						info.endtime = timestamp_list[0] - 1;
						recallinfo_list.append(info);
					}
					if (endtime - timestamp_list[timestamp_list.size() - 1] > 600)
					{
						RecallInfo info;
						info.starttime = timestamp_list[timestamp_list.size() - 1] + 1;
						info.endtime = endtime - 1;
						recallinfo_list.append(info);
					}
				}

				long long temptime1 = timestamp_list[i - 1];
				long long temptime2 = timestamp_list[i];
				if (temptime2 - temptime1 > 600)
				{
					RecallInfo info;
					info.starttime = temptime1 + 1;
					info.endtime = temptime2 - 1;
					recallinfo_list.append(info);
				}
			}
		}

		for (int i = 0; i < recallinfo_list.size(); i++)
		{
			long long duration = recallinfo_list[i].endtime - recallinfo_list[i].starttime;
			long long max_interval = 3600;
			for (long long j = 0; j <= duration; j += max_interval)
			{
				if (j + max_interval > duration) {
					long long start = recallinfo_list[i].starttime + j;
					long long end = recallinfo_list[i].endtime;

					RecallInfo info;
					info.starttime = start - 10;
					info.endtime = end - 10;
					recallinfo_list_hour.append(info);
				}
				else {
					long long start = recallinfo_list[i].starttime + j;
					long long end = recallinfo_list[i].starttime + j + max_interval;

					RecallInfo info;
					info.starttime = start - 10;
					info.endtime = end - 10;
					recallinfo_list_hour.append(info);
				}
			}
		}

		LD_info_t* LD_info = find_LD_info_only_from_mp_id(id);
		if (LD_info == NULL || LD_info->read_flag == 0) {
			printf("\n Find LD_info == null \n");
		}
		else {
			for (int j = 0; j < recallinfo_list_hour.size(); j++) {
				CJournalRecall jr;
				jr.MonitorID = QString(LD_info->mp_id);
				jr.StartTime = QDateTime::fromTime_t(recallinfo_list_hour[j].starttime).toString("yyyy-MM-dd hh:mm:ss");
				jr.EndTime = QDateTime::fromTime_t(recallinfo_list_hour[j].endtime).toString("yyyy-MM-dd hh:mm:ss");
				jr.STEADY = QString::number(1, 10);
				jr.VOLTAGE = QString::number(1, 10);
				g_StatisticLackList_list_mutex.lock();
				g_StatisticLackList.push_back(jr);
				g_StatisticLackList_list_mutex.unlock();
			}
		}
	}
	catch (otl_exception& e)
	{
		printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg);
	}
}

bool CheckPG_To_Recall_web_test(long long start, long long end, char* Monitorid)
{
	QDateTime deltime_Qtime = QDateTime::fromTime_t(start);
	QDateTime deltime_Qtime_end = QDateTime::fromTime_t(end);
	QString tmp_chr1 = deltime_Qtime.toString("yyyy-MM-dd"); //当前天
	QString start_chr1 = deltime_Qtime.toString("yyyy-MM-dd hh:mm:ss"); //当前天
	QString end_chr1 = deltime_Qtime_end.toString("yyyy-MM-dd hh:mm:ss"); //当前天

	int timespan = 3;//默认时间间隔

	try {
		/*int rtState = OTLDbconnected();
		//int rtState = db.connected;
		if (rtState == 0) {
			int ret = OTLConnect();
		}
		//printf("\nPostgreSL 1 %s \n", POSTGRES_SCHEMA);
		std::string str2 = POSTGRES_SCHEMA;//schame analy
		std::string str3 = POSTGRES_TABLEPREFIX;//schame analy
		std::string str1 = "select \"exp_num\",\"act_num\" from \"";
		str1.append(str2);
		str1.append("\".\"");
		str1.append(str3);
		str1.append("meas_pq_measpoint_intact_tr\" ");
		str1.append("WHERE \"statistical_date\" = '");
		str1.append(tmp_chr1.toAscii().data());
		str1.append("' AND \"monitor_id\" = '");
		str1.append(Monitorid);
		str1.append("'");
		otl_stream i(1, // buffer size
			str1.c_str(),
			//SELECT statement
			db //connect object
		);
		double exp_num;
		double act_num;
		while (!i.eof()) { //while not end-of-data
			i >> exp_num >> act_num;*/
		
		std::vector<std::string> codes;//入参集合
		QMap<QString, intact_list*>  intact_list_map;

		codes.push_back("deciderecall");
		codes.push_back(tmp_chr1.toStdString());
		codes.push_back(std::string(Monitorid));

		parse_intact_web_test_read(&intact_list_map,codes);

		codes.clear();

		try {
			//char exp_num[64];
			//char act_num[64];
			double exp_num;
			double act_num;

			// 遍历终端台账容器
			QMap<QString, intact_list*>::iterator it;
    		for (it = intact_list_map.begin(); it != intact_list_map.end(); ++it) {
    			intact_list* value = it.value();

				// 确保 value 不为空
    			if (value != nullptr) {
    	    		// 找到容器中对应名称并取值
    	    		//strncpy(exp_num, value->exp_num.c_str(), sizeof(exp_num) - 1);
    	    		//strncpy(act_num, value->act_num.c_str(), sizeof(act_num) - 1);

					exp_num = atof(value->exp_num);
					act_num = atof(value->act_num);

					std::cout << exp_num << " " << act_num << std::endl;

					timespan = 1440 / exp_num;
					printf("\n %f %f %d \n", exp_num, act_num, timespan);
				}
			}
		}
		catch (otl_exception& e)
		{
			printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg);
			return false;
		}
		//OTLDisconnect();
	}
	catch (otl_exception& e)
	{
		printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg);
		return false;
	}

	try {
		long long starttime = start;                          //补招起始时间
		long long endtime = starttime + 3599;                //补招结束时间
		QList<long long> timestamp_list;                      //数据库完整性记录时间点
		QList<RecallInfo> recallinfo_list;                    //待补招队列
		QList<RecallInfo> recallinfo_list_hour;               //待补招队列-以小时为最大间隔

/*		int rtState = OTLDbconnected();
		//int rtState = db.connected;
		if (rtState == 0) {
			int ret = OTLConnect();
		}
		//OTLConnect();
		std::string str2 = POSTGRES_SCHEMA;//schame analy
		std::string str3 = POSTGRES_TABLEPREFIX;//schame analy
		std::string str1 = "SELECT unnest(value_time) AS timestamp_value FROM \"";
		str1.append(str2);
		str1.append("\".\"");
		str1.append(str3);
		str1.append("meas_pq_measpoint_intact_tr\" ");
		str1.append("WHERE \"statistical_date\" = '");
		str1.append(tmp_chr1.toAscii().data());
		str1.append("' AND \"monitor_id\" = '");
		str1.append(Monitorid);
		str1.append("' ORDER BY timestamp_value");

		std::string str4 = "select b1.timestamp_value from (";
		str4.append(str1);
		str4.append(") b1 where b1.timestamp_value >= '");
		str4.append(start_chr1.toAscii().data());
		str4.append("' and b1.timestamp_value <= '");
		str4.append(end_chr1.toAscii().data());
		str4.append("'");
		otl_stream i(1, // buffer size
			str4.c_str(),
			//SELECT statement
			db //connect object
		);
		otl_datetime timestamp;
		while (!i.eof()) { //while not end-of-data
			i >> timestamp;*/

		std::vector<std::string> codes;//入参集合
		QMap<QString, intact_list*>  intact_list_map;
		codes.push_back("handlerecall");
		codes.push_back(tmp_chr1.toStdString());
		codes.push_back(std::string(Monitorid));
		codes.push_back(start_chr1.toStdString());
		codes.push_back(end_chr1.toStdString());

		parse_intact_web_test_read(&intact_list_map,codes);

		codes.clear();

		try {
			otl_datetime timestamp;

			// 遍历终端台账容器
			if (intact_list_map.contains(Monitorid)) {
    			intact_list* value = intact_list_map.value(Monitorid);  // 找到键值为 "id" 的对象

    			if (value != nullptr) {
        			// 遍历 value_time 容器并输出所有时间字符串
        			for (std::vector<std::string>::const_iterator it = value->value_time.begin(); it != value->value_time.end(); ++it) {
    					const std::string& time = *it;

            			std::cout << "Time: " << time << std::endl;

						timestamp = parseTimestamp(time);

						struct tm timeinfo;
						timeinfo.tm_year = timestamp.year - 1900; // 年份需要减去1900
						timeinfo.tm_mon = timestamp.month - 1; // 月份需要减去1
						timeinfo.tm_mday = timestamp.day;
						timeinfo.tm_hour = timestamp.hour;
						timeinfo.tm_min = timestamp.minute;
						timeinfo.tm_sec = timestamp.second;

						time_t timestamp = std::mktime(&timeinfo);
						long long stamp = static_cast<long long>(timestamp);
						timestamp_list.append(stamp);
					}
				}
			}
		}
		catch (otl_exception& e)
		{
			printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg);
			return false;
		}
		//OTLDisconnect();

		if (timestamp_list.size() <= (60 / timespan) * 0.97) //完整性数据表无数据
		{
			printf("\n return ture %d %f\n", timestamp_list.size(), (60 / timespan) * 0.97);
			return true;
		}
		else
		{
			printf("\n return false %d %f\n", timestamp_list.size(), (60 / timespan) * 0.97);
			return false;
		}
	}
	catch (otl_exception& e)
	{
		printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg);
		return false;
	}
	printf("\n>>>error quit!!\n");
	return true;
}

//初始化的web测试接口
int parse_device_cfg_web_test()
{
	qDebug() << "parse_device_cfg_web" << endl;

	std::vector<std::string> codes;

//多前置判断
	if (FRONT_INST == 0 || FRONT_IP[0] == '\0') {
		MULTIPLE_NODE_FLAG = 0;
		cout << "set MULTIPLE_NODE_FLAG:0,because do not have FRONT_INST or FRONT_IP" << endl;
	}

	char front_type[2] = {""};
	int mp_num = 0;

//用web接口替换前置表的读写，接口中解析结果，存入容器，从接口直接取出容器，从容器中获取需要的值，写入时直接传参：
	if (MULTIPLE_NODE_FLAG) {
//前置表读取部分替换
		/*QString selectFrontSql;
		selectFrontSql.append(QString("select \"front_type\",\"mp_num\" from \"%1\".\"%2meas_pq_front_list_tr\" ").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX));
		selectFrontSql.append(QString("where \"front_ip\" = '0.0.0.0' and \"front_inst\"=0"));
		cout << selectFrontSql.toStdString().c_str() << endl;
		try {
			OTLConnect();
			otl_stream i2(1, // buffer size
				selectFrontSql.toStdString().c_str(),
				db //connect object
			);
			while (!i2.eof()) { //while not end-of-data
				i2 >> front_type >> mp_num;
				break;
			}
			OTLDisconnect();
		}
		catch (otl_exception& e)
		{
			printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg);
			return e.code;
		}*/
		QMap<QString, front_list*> front_map;
		codes.push_back("info");
		parse_device_web_test_front_read(&front_map,codes);
		codes.clear();
		// 遍历 QMap 容器
		QMap<QString, front_list*>::iterator it;
    	for (it = front_map.begin(); it != front_map.end(); ++it) {
        	front_list* value = it.value();
        	// 确保 value 不为空
        	if (it.key() == "0.0.0.0" && value != nullptr) {
            	// 从 value 中读取 front_type，保留前两个字符
            	strncpy(front_type, value->front_type, 2);
            	front_type[2] = '\0';  // 确保以空字符结尾
            	// 将 mp_num 从字符串转换为整数
            	mp_num = std::atoi(value->mp_num);
			}
		}
//前置表读取部分
//前置表写入部分
		/*QString addFrontSql;
		addFrontSql.append(QString("insert into \"%1\".\"%2meas_pq_front_list_tr\"(\"front_ip\",\"front_port\",\"front_inst\",\"front_type\",\"front_status\",\"front_version\",\"mp_num\") ").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX));
		addFrontSql.append(QString("values('%1',10000,%2,'%3','01','%4',200) ").arg(FRONT_IP).arg(FRONT_INST).arg(front_type).arg(PROGRAM_VERSION));
		addFrontSql.append(QString("on conflict(\"front_ip\",\"front_inst\") do update set "));
		addFrontSql.append(QString("\"front_type\"= '%1',\"front_version\"='%2'").arg(front_type).arg(PROGRAM_VERSION));
		cout << addFrontSql.toStdString().c_str() << endl;
		OTLConnect();
		int rt = write_to_db(addFrontSql.toStdString().c_str());
		OTLDisconnect();*/

		codes.push_back("insertfront");

		codes.push_back(std::string(FRONT_IP));
		codes.push_back(intToString(FRONT_INST));
		codes.push_back(std::string(front_type));
		codes.push_back(std::string(PROGRAM_VERSION));

		codes.push_back("01");		//添加状态值

		parse_device_web_test_front_write(codes);

		codes.clear();

//前置表写入部分
	}

	cout << "mp_num:" << mp_num << " front_type:" << front_type << endl;

	ied_t* ied;
	ied_usr_t* ied_usr;
	chnl_usr_t* chnl_usr;
	int count_cfg = 0;
	int count_real = 0;

//读取终端ext表替换为web接口
	QMap<QString, terminal_ext*> terminal_ext_map;
	//read_terminal_ext_pg(&terminal_ext_map);
	codes.push_back("info");
	parse_device_web_test_ext(&terminal_ext_map,codes);
	codes.clear();
//读取终端ext表替换为web接口

//读取终端台账表总数替换为web接口
	/*try {
		OTLConnect();
		std::string str2 = POSTGRES_SCHEMA;//schame analy
		std::string str1 = "select count(*) from \"";
		str1.append(str2);
		str1.append("\".\"");
		str1.append(POSTGRES_TABLEPREFIX);
		str1.append("meas_pq_dev_tr");
		str1.append("\"  where tmnl_status='20';");
		cout << "pg sql1 is:" << str1 << endl;
		otl_stream i(1, // buffer size
			str1.c_str(),
			db //connect object
		);
		int f2;
		while (!i.eof()) { //while not end-of-data
			i >> f2;
		}
		OTLDisconnect();
		count_cfg = f2;;//读数据库
		cout << "dev_count=" << count_cfg << endl;
	}
	catch (otl_exception& e)
	{
		printf("\ndev PostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg);
		return e.code;
	}*/
		
	QMap<QString, terminal_dev*> terminal_dev_map;
	
	codes.push_back("count_cfg");

	parse_device_web_test_dev(&terminal_dev_map,codes);

	// 遍历 QMap 容器
	QMap<QString, terminal_dev*>::iterator it;
    for (it = terminal_dev_map.begin(); it != terminal_dev_map.end(); ++it) {
    	terminal_dev* value = it.value();
    	// 确保 value 不为空
    	if (it.key() == "count_cfg" && value != nullptr) {
        	// 将 count 从字符串转换为整数
        	count_cfg = std::atoi(value->count_cfg);
		}
		//调试用
		cout << "count_cfg:" << count_cfg << " value->count_cfg:" << value->count_cfg << endl;
	}

	codes.clear();

	//取完count——cfg要将容器清0否则影响取台账逻辑
	terminal_dev_map.clear();

//读取终端台账表总数替换为web接口

//读取终端台账表替换为web接口

	codes.push_back("info");
	codes.push_back(intToString(FRONT_INST));
	codes.push_back(intToString(mp_num));
	codes.push_back(intToString(count_cfg));
	codes.push_back(intToString(MULTIPLE_NODE_FLAG));
	codes.push_back(intToString(g_front_seg_num));

	parse_device_web_test_dev(&terminal_dev_map,codes);

	codes.clear();

	if (MULTIPLE_NODE_FLAG && g_front_seg_num == 0) {
		if (mp_num * FRONT_INST > count_cfg) {
			count_cfg = count_cfg - (FRONT_INST - 1) * mp_num;
		}
		else
		{
			count_cfg = mp_num;
		}
	}
	else if (MULTIPLE_NODE_FLAG && g_front_seg_num != 0) {
		int front_num = (count_cfg / g_front_seg_num) + 1;
		if (front_num * FRONT_INST > count_cfg) {
			count_cfg = count_cfg - (FRONT_INST - 1) * front_num;
		}
		else
		{
			count_cfg = front_num;
		}
	}
	g_node->n_clients = count_cfg;		//总数读不到后续就会出错
	g_node->clients = (ied_t**)apr_pcalloc(g_cfg_pool, count_cfg * sizeof(ied_t*));
	for (int k = 0; k < count_cfg; k++)
		g_node->clients[k] = (ied_t*)apr_pcalloc(g_cfg_pool, sizeof(ied_t));
/*	std::string strSchame = POSTGRES_SCHEMA;//schame analy
	std::string strDevSQL = "select  \"terminal_id\",\"terminal_code\",\"org_name\",\"maint_name\",\"station_name\",\"tmnl_ip\",\"tmnl_port\",\"tmnl_factory\",\"tmnl_type\",\"tmnl_status\",\"update_time\" from \"";
	strDevSQL.append(strSchame);
	strDevSQL.append("\".\"");
	strDevSQL.append(POSTGRES_TABLEPREFIX);
	strDevSQL.append("meas_pq_dev_tr");
	strDevSQL.append("\"  where tmnl_status='20'");
	if (MULTIPLE_NODE_FLAG && g_front_seg_num == 0) {
		strDevSQL.append(" ORDER BY terminal_id OFFSET ");
		strDevSQL.append(QString::number((FRONT_INST - 1) * mp_num).toStdString());
		strDevSQL.append(" LIMIT ");
		strDevSQL.append(QString::number(mp_num).toStdString());
		if (mp_num * FRONT_INST > count_cfg) {
			count_cfg = count_cfg - (FRONT_INST - 1) * mp_num;
		}
		else
		{
			count_cfg = mp_num;
		}
	}
	else if (MULTIPLE_NODE_FLAG && g_front_seg_num != 0) {
		int front_num = (count_cfg / g_front_seg_num) + 1;
		strDevSQL.append(" ORDER BY terminal_code OFFSET ");
		strDevSQL.append(QString::number((FRONT_INST - 1) * front_num).toStdString());
		strDevSQL.append(" LIMIT ");
		strDevSQL.append(QString::number(front_num).toStdString());
		if (front_num * FRONT_INST > count_cfg) {
			count_cfg = count_cfg - (FRONT_INST - 1) * front_num;
		}
		else
		{
			count_cfg = front_num;
		}
	}

	cout << strDevSQL << endl;

	g_node->n_clients = count_cfg;
	g_node->clients = (ied_t**)apr_pcalloc(g_cfg_pool, count_cfg * sizeof(ied_t*));
	for (int k = 0; k < count_cfg; k++)
		g_node->clients[k] = (ied_t*)apr_pcalloc(g_cfg_pool, sizeof(ied_t));


	//读数据
	try {
		cout << "read dev information." << endl;
		OTLConnect();

		//cout << "pg sql2 is:" << str1 << endl;
		//int rtState = OTLState();
		// 执行长的select语句
		otl_stream i(1, // buffer size
			strDevSQL.c_str(),
			//SELECT statement
			db //connect object
		);

		//create select stream

		char terminal_id[64];
		char terminal_code[64];
		char org_name[64];
		char maint_name[64];
		char station_name[64];
		char tmnl_factory[64];
		char tmnl_status[64];
		char dev_type[64];
		char dev_key[64];
		char dev_series[64];
		char addr_str[64];
		char port_char[64];
		otl_datetime  timestamp;

		while (!i.eof()) { //while not end-of-data
			i >> terminal_id >> terminal_code >> org_name >> maint_name >> station_name >> addr_str >> port_char >> tmnl_factory >> dev_type >> tmnl_status >> timestamp;
*/
//读取终端台账表替换为web接口
//////////////////////////////////////////////////////////////////////////////////////////////////
	//读数据
	try {

		char terminal_id[64];
		char terminal_code[64];
		char org_name[64];
		char maint_name[64];
		char station_name[64];
		char tmnl_factory[64];
		char tmnl_status[64];
		char dev_type[64];
		char dev_key[64];
		char dev_series[64];
		char addr_str[64];
		char port_char[64];
		//char timestamp[64];
		otl_datetime timestamp;

		// 遍历终端台账容器
		QMap<QString, terminal_dev*>::iterator it;
    	for (it = terminal_dev_map.begin(); it != terminal_dev_map.end(); ++it) {
    		terminal_dev* value = it.value();

			// 确保 value 不为空
    		if (value != nullptr) {
        		// 找到容器中对应名称并取值
        		strncpy(terminal_id, value->terminal_id, sizeof(terminal_id) - 1);
        		strncpy(terminal_code, value->terminal_code, sizeof(terminal_code) - 1);
        		strncpy(org_name, value->org_name, sizeof(org_name) - 1);
        		strncpy(maint_name, value->maint_name, sizeof(maint_name) - 1);
        		strncpy(station_name, value->station_name, sizeof(station_name) - 1);
        		strncpy(tmnl_factory, value->tmnl_factory, sizeof(tmnl_factory) - 1);
        		strncpy(tmnl_status, value->tmnl_status, sizeof(tmnl_status) - 1);
        		strncpy(dev_type, value->dev_type, sizeof(dev_type) - 1);
        		//strncpy(dev_key, value->dev_key, sizeof(dev_key) - 1);
        		//strncpy(dev_series, value->dev_series, sizeof(dev_series) - 1);
        		strncpy(addr_str, value->addr_str, sizeof(addr_str) - 1);
        		strncpy(port_char, value->port, sizeof(port_char) - 1);
        		//strncpy(timestamp, value->timestamp, sizeof(timestamp) - 1);

				timestamp = parseTimestamp(value->timestamp);

    		}

/////////////////////////////////////////////////////////////////////////////////

			ied = g_node->clients[count_real++];

			ied_usr = (ied_usr_t*)apr_pcalloc(g_init_pool, sizeof(ied_usr_t));

			ied->usr_ext = ied_usr;

			if (ied_usr == NULL)
				return APR_ENOMEM;

			ied_usr->last_call_wavelist_time = sGetMsTime() + g_pt61850app->giTime * 1000;
			ied_usr->LD_info = (LD_info_t*)apr_pcalloc(g_init_pool, MAX_CPUNO * sizeof(LD_info_t));

			if (ied_usr->LD_info == NULL)
				return APR_ENOMEM;

			ied_usr->dev_flag = g_DevFlag;
			ied->chncount = 1;
			ied->channel = (channel_t*)apr_pcalloc(g_cfg_pool, sizeof(channel_t) * ied->chncount);
			ied->channel[0].ied = ied;
			ied->channel[0].status = STATUS_BREAKOFF;
			ied->cpucount = 0;

			if (strlen(terminal_id) != 0) {
				apr_snprintf(ied_usr->terminal_id, sizeof(ied_usr->terminal_id), "%s", terminal_id);//terminal_id
				cout << "ied_usr->terminal_id:" << ied_usr->terminal_id << endl;
			}

			if (terminal_code != NULL) {
				apr_snprintf(ied_usr->terminal_code, sizeof(ied_usr->terminal_code), "%s", terminal_code);//terminal_code
				cout << "ied_usr->terminal_code:" << ied_usr->terminal_code << endl;

			}

			if (org_name != NULL) {
				apr_snprintf(ied_usr->org_name, sizeof(ied_usr->org_name), "%s", org_name);//org_name
				cout << "ied_usr->org_name:" << ied_usr->org_name << endl;

			}

			if (maint_name != NULL) {
				apr_snprintf(ied_usr->maint_name, sizeof(ied_usr->maint_name), "%s", maint_name);//maint_name
				cout << "ied_usr->maint_name:" << ied_usr->maint_name << endl;

			}

			if (station_name != NULL) {
				apr_snprintf(ied_usr->station_name, sizeof(ied_usr->station_name), "%s", station_name);//station_name
				cout << "ied_usr->station_name:" << ied_usr->station_name << endl;

			}

			if (tmnl_factory != NULL) {
				apr_snprintf(ied_usr->tmnl_factory, sizeof(ied_usr->tmnl_factory), "%s", tmnl_factory);//tmnl_factory
				cout << "ied_usr->tmnl_factory:" << ied_usr->tmnl_factory << endl;

			}

			if (tmnl_status != NULL) {
				apr_snprintf(ied_usr->tmnl_status, sizeof(ied_usr->tmnl_status), "%s", tmnl_status);//tmnl_status
				cout << "ied_usr->tmnl_status:" << ied_usr->tmnl_status << endl;

			}

			if (dev_type != NULL) {
				apr_snprintf(ied_usr->dev_type, sizeof(ied_usr->dev_type), "%s", dev_type);//dev_type
				cout << "ied_usr->dev_type:" << ied_usr->dev_type << endl;

			}

			cout << "code" << ied_usr->terminal_code << endl;

			if (terminal_ext_map.contains(QString::fromUtf8(ied_usr->terminal_code))) {
				//terminal_ext* ext = terminal_ext_map.value(ied_usr->terminal_code);
				terminal_ext* ext = terminal_ext_map.value(QString::fromUtf8(ied_usr->terminal_code));
				//QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Key
				apr_snprintf(ied_usr->dev_key, sizeof(ied_usr->dev_key), "%s", ext->terminal_key);//DEV_Key
				cout << "dev_key:" << ied_usr->dev_key << endl;

				//QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Series
				apr_snprintf(ied_usr->dev_series, sizeof(ied_usr->dev_series), "%s", ext->terminal_identify_code);//DEV_Series
				cout << "dev_series:" << ied_usr->dev_series << endl;
			}
			else
			{

				//QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Key
				apr_snprintf(ied_usr->dev_key, sizeof(ied_usr->dev_key), "%s", "");//DEV_Key
				cout << "defalut dev_key:" << ied_usr->dev_key << endl;

				//QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Series
				apr_snprintf(ied_usr->dev_series, sizeof(ied_usr->dev_series), "%s", "");//DEV_Series
				cout << "defalut dev_series:" << ied_usr->dev_series << endl;
			}

			ied->channel[0].channel_type = CHANNEL_TYPE_IPV4;//channel
			ied->channel[0].addr_str[LONGNAME - 1] = 0;//DEV_IP

			if (addr_str != NULL) {
				ied->channel[0].addr = ntohl(inet_addr(addr_str));//DEV_IP
				strncpy(ied->channel[0].addr_str, addr_str, LONGNAME - 1);//DEV_IP
				cout << "ied_usr->addr_str:" << ied->channel[0].addr_str << endl;

			}
			else
			{
				ied->channel[0].addr = ntohl(inet_addr("0.0.0.0"));//DEV_IP
				strncpy(ied->channel[0].addr_str, addr_str, LONGNAME - 1);//DEV_IP
				cout << "ied_usr->addr_str:" << ied->channel[0].addr_str << endl;
			}

			if (port_char != NULL) {
				int port = 102;
				if (stringToInt(port_char, &port)) {
					// 转换成功，portStr全为数字，并且已经转换为int类型的port  
					ied->channel[0].port = port;//DEV_PortID
					cout << "ied_usr->port:" << ied->channel[0].port << endl;//DEV_PortID
				}
				else {
					ied->channel[0].port = 102;//DEV_PortID
					cout << "ied_usr->port:" << port_char << ",非合法端口.使用默认端口:" << ied->channel[0].port << endl;//DEV_PortID
				}
			}

			if (timestamp.year != 0) {
				//// 构造struct tm对象
				struct tm timeinfo;
				timeinfo.tm_year = timestamp.year - 1900; // 年份需要减去1900
				timeinfo.tm_mon = timestamp.month - 1; // 月份需要减去1
				timeinfo.tm_mday = timestamp.day;
				timeinfo.tm_hour = timestamp.hour;
				timeinfo.tm_min = timestamp.minute;
				timeinfo.tm_sec = timestamp.second;

				time_t time = std::mktime(&timeinfo);
				ied_usr->time = static_cast<long long>(time);
				cout << "ied_usr->time:" << ied_usr->time << endl;
			}
////////////////////////////////
			/*// 定义年、月、日、时、分、秒变量
    		int year, month, day, hour, minute, second;		
			// 使用字符串流进行解析
    		std::istringstream ss(timestamp);
    		char discard; // 用于丢弃分隔符

    		// 解析字符串
    		ss >> year >> discard >> month >> discard >> day >> hour >> discard >> minute >> discard >> second;

			std::cout << "" << year << "" << month<< "" << day<< "" << hour<< "" << minute<< "" << second<<std::endl;
			if (year != 0) {
				//// 构造struct tm对象
				struct tm timeinfo;
				timeinfo.tm_year = year - 1900; // 年份需要减去1900
				timeinfo.tm_mon = month - 1; // 月份需要减去1
				timeinfo.tm_mday = day;
				timeinfo.tm_hour = hour;
				timeinfo.tm_min = minute;
				timeinfo.tm_sec = second;

				time_t time = std::mktime(&timeinfo);
				ied_usr->time = static_cast<long long>(time);
				cout << "ied_usr->time:" << ied_usr->time << endl;
			}*/
/////////////////////////////////////


			chnl_usr = (chnl_usr_t*)apr_pcalloc(g_init_pool, sizeof(chnl_usr_t));
			ied->channel[0].connect = chnl_usr;
			chnl_usr->chnl = &(ied->channel[0]);
			chnl_usr->chnl_id = 0;
			chnl_usr->m_state = CHANNEL_DISCONNECTED;
			chnl_usr->m_ClosedMsTime = NEXT_CONNECT_TIME * (-1);
			g_pt61850app->chnl_counts++;


		//调试用
		std::cout << "value:" << terminal_id <<"  "<<terminal_code <<"  "<<org_name <<"  "<<maint_name <<"  "<<station_name <<"  "<<tmnl_factory <<"  "<< tmnl_status <<"  "<<dev_type <<"  "<<addr_str <<"  "<<port_char <<"  "<<timestamp.year<< std::endl;


		}

		//OTLDisconnect();//读取终端台账表替换为web接口
		//list循环结束
//替换前置表更新部分
		if (MULTIPLE_NODE_FLAG) {
			/*QString updateFrontSql;//待组装的pgsql语句
			updateFrontSql.append(QString("update \"%1\".\"%2meas_pq_front_list_tr\" ").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX));
			updateFrontSql.append(QString("set \"mp_num\"= %1 ").arg(count_real));
			updateFrontSql.append(QString("where \"front_ip\" = '%1' and \"front_inst\"=%2").arg(FRONT_IP).arg(FRONT_INST));
			OTLConnect();
			int rt = write_to_db(updateFrontSql.toStdString().c_str());
			OTLDisconnect();*/

			codes.push_back("updatefront");

			codes.push_back(std::string(FRONT_IP));
			codes.push_back(intToString(FRONT_INST));
			codes.push_back(intToString(count_real));
			codes.push_back(std::string(PROGRAM_VERSION));		//和定时任务的update一样，写入PROGRAM_VERSION

			parse_device_web_test_front_write(codes);

			codes.clear();
//替换前置表更新部分
		}

		if (count_real < count_cfg)
			g_node->n_clients = count_real;
		if (count_cfg != count_real)
			return APR_EBADF;
		cout << "dev init create count:" << count_real;
		return APR_SUCCESS;
	}
	catch (otl_exception& e)
	{
		printf("\ndev tr\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg);
		return e.code;
	}

}

int parse_line_cfg_web_test()
{
	ied_t* ied;
	ied_usr_t* ied_usr;
	int count_cfg = 0;
	int count_real = 0;
	LD_info_t line_info;

	std::vector<std::string> codes;//入参集合

//监测点数量
	/*try {
		std::string str2 = POSTGRES_SCHEMA;//schame analy
		std::string str1 = "select count(*) from \"";
		str1.append(str2);
		str1.append("\".\"");
		str1.append(POSTGRES_TABLEPREFIX);
		str1.append("pq_ledger_monitor");
		str1.append("\" where status<>'04' and status<>'05' and \"terminal_code\" in (");

		int dev_no = 0;
		cout << "n_clients:" << g_node->n_clients << endl;
		if (g_node->n_clients <= 0) {
			cout << "no terminal exist " << endl;
			return APR_EBADF;
		}
		for (dev_no = 0; dev_no < g_node->n_clients; dev_no++) {
			str1.append("'");
			str1.append(((ied_usr_t*)(g_node->clients[dev_no]->usr_ext))->terminal_code);
			str1.append("'");
			if (dev_no < g_node->n_clients - 1) {
				str1 += ",";
			}
		}
		str1.append(")");
		cout << "pg sql1 is:" << str1 << endl;
		OTLConnect();
		otl_stream i(1,str1.c_str(),db);
		int f2;
		while (!i.eof()) {
			i >> f2;
		}
		OTLDisconnect();
		count_cfg = f2;;//读数据库
		cout << "line_count=" << count_cfg << endl;
	}
	catch (otl_exception& e)
	{
		printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg);
		return e.code;
	}*/

//前置对应的监测点数量将根据监测点信息中的终端号进行统计，而不是直接从数据库获取
//监测点数量
//检测点数据
	QMap<QString, ledger_monitor*> ledger_monitor_map;
	codes.push_back("info");

	parse_line_web_test(&ledger_monitor_map,codes);

	codes.clear();

	/*根据终端号整理监测点数量和监测点数据*/
	std::cout << "n_clients:" << g_node->n_clients << std::endl;
	if (g_node->n_clients <= 0) {
		std::cout << "no terminal exist " << std::endl;
		return APR_EBADF;
	}
	/*这段处理放在容器处理中
	for (dev_no = 0; dev_no < g_node->n_clients; dev_no++) {
		if(((ied_usr_t*)(g_node->clients[dev_no]->usr_ext))->terminal_code);
	}*/

	//读数据
	/*try {
		OTLConnect();
		std::string str2 = POSTGRES_SCHEMA;//schame analy
		std::string str1 = "select \"monitor_id\",\"terminal_code\",\"monitor_name\",\"logical_device_seq\",\"voltage_level\",\"terminal_connect\",\"update_time\" from \"";
		str1.append(str2);
		str1.append("\".\"");
		str1.append(POSTGRES_TABLEPREFIX);
		str1.append("pq_ledger_monitor");
		str1.append("\" where status<>'04' and status<>'05' and \"terminal_code\" in (");
		int dev_no = 0;

		for (dev_no = 0; dev_no < g_node->n_clients; dev_no++) {
			str1.append("'");
			str1.append(((ied_usr_t*)(g_node->clients[dev_no]->usr_ext))->terminal_code);
			str1.append("'");
			if (dev_no < g_node->n_clients - 1) {
				str1 += ",";
			}
		}
		str1.append(")");
		cout << "pg sql2 is:" << str1 << endl;
		//int rtState = OTLState();
		otl_stream i(1, // buffer size
			str1.c_str(),
			//SELECT statement
			db //connect object
		);
		//create select stream

		char monitor_id[64];
		char terminal_code[64];
		char monitor_name[64];
		char logical_device_seq[64];
		char voltage_level[64];
		char terminal_connect[64];
		otl_datetime  timestamp;
		while (!i.eof()) { //while not end-of-data
			i >> monitor_id >> terminal_code >> monitor_name >> logical_device_seq >> voltage_level >> terminal_connect >> timestamp;
			cout << "monitor_id=" << monitor_id << " terminal_code=" << terminal_code << " monitor_name=" << monitor_name << " logical_device_seq=" << logical_device_seq;
			cout << " voltage_level=" << voltage_level << " terminal_connect=" << terminal_connect;
			cout << " timestamp: " << timestamp.year << "-" << timestamp.month << "-" << timestamp.day << " " << timestamp.hour << ":" << timestamp.minute << ":" << timestamp.second << endl;*/
	//读数据
	try {
		char monitor_id[64];
		char terminal_code[64];
		char monitor_name[64];
		char logical_device_seq[64];
		char voltage_level[64];
		char terminal_connect[64];
		//char timestamp[64];
		otl_datetime timestamp;

		// 遍历终端台账容器
		QMap<QString, ledger_monitor*>::iterator it;
    	for (it = ledger_monitor_map.begin(); it != ledger_monitor_map.end(); ++it) {
    		ledger_monitor* value = it.value();

			// 确保 value 不为空
    		if (value != nullptr) {
        		// 找到容器中对应名称并取值
        		strncpy(monitor_id, value->monitor_id, sizeof(monitor_id) - 1);
        		strncpy(terminal_code, value->terminal_code, sizeof(terminal_code) - 1);
        		strncpy(monitor_name, value->monitor_name, sizeof(monitor_name) - 1);
        		strncpy(logical_device_seq, value->logical_device_seq, sizeof(logical_device_seq) - 1);
        		strncpy(voltage_level, value->voltage_level, sizeof(voltage_level) - 1);
        		strncpy(terminal_connect, value->terminal_connect, sizeof(terminal_connect) - 1);
        		//strncpy(timestamp, value->timestamp, sizeof(timestamp) - 1);

				timestamp = parseTimestamp(value->timestamp);
    		}

		count_cfg = ledger_monitor_map.size();//获取监测点表的条数

//检测点数据

			count_real++;
			memset(&line_info, 0, sizeof(line_info));
			line_info.line_id = count_real;
			//cout << "line_id:" << line_info.line_id << endl;

			strcpy(line_info.mp_id, monitor_id);
			//cout << "mp_id:" << line_info.mp_id << endl;
			strcpy(line_info.terminal_code, terminal_code);
			//cout << "terminal_code:" << line_info.terminal_code << endl;

			if (isCharPtrEmpty(logical_device_seq)) {
				line_info.cpuno = 1;
				//cout << "logical_device_seq:is null~"<< line_info.cpuno << endl;
			}
			else {
				line_info.cpuno = std::atoi(logical_device_seq);
				//cout << "logical_device_seq:"<< logical_device_seq << endl;
			}

			//cout << "cpuno:" << line_info.cpuno << endl;
			strcpy(line_info.voltage_level, voltage_level);
			//cout << "voltage_level:" << line_info.voltage_level << endl;
			strcpy(line_info.v_wiring_type, terminal_connect);
			//cout << "v_wiring_type:" << line_info.v_wiring_type << endl;

			//// 构造struct tm对象
			struct tm timeinfo;
			timeinfo.tm_year = timestamp.year - 1900; // 年份需要减去1900
			timeinfo.tm_mon = timestamp.month - 1; // 月份需要减去1
			timeinfo.tm_mday = timestamp.day;
			timeinfo.tm_hour = timestamp.hour;
			timeinfo.tm_min = timestamp.minute;
			timeinfo.tm_sec = timestamp.second;

			time_t time = std::mktime(&timeinfo);
			line_info.time = static_cast<long long>(time);
			//cout << "time:" << line_info.time << endl;

			strcpy(line_info.name, monitor_name);
			//cout << "name:" << line_info.name << endl;
			line_info.read_flag = 1;
			ied = find_ied_from_dev_code(line_info.terminal_code);

			if (ied && ied->usr_ext && line_info.cpuno && line_info.cpuno < 10) {
				char str[256];
				byte_t cpuno = line_info.cpuno;
				//cout << "cpuno:" << line_info.cpuno << endl;
				//cout << "byte_t cpuno:" << cpuno-1 << endl;
				ied_usr = (ied_usr_t*)ied->usr_ext;
				ied_usr->LD_info[cpuno - 1] = line_info;
				ied_usr->LD_info[cpuno - 1].ied = ied;
				apr_snprintf(str, sizeof(str), "PQMonitorPQM%d", cpuno);
				ied_usr->LD_info[cpuno - 1].LD_name = apr_pstrdup(g_init_pool, str);
				ied_usr->LD_info[cpuno - 1].ht_fcd = apr_hash_make(g_init_pool);
				ied_usr->LD_info[cpuno - 1].ht_full_fcda = apr_hash_make(g_init_pool);
				ied_usr->LD_info[cpuno - 1].rptcount = 0;
				//cout << "rptcount:" << ied_usr->LD_info[cpuno - 1].rptcount << endl;

				if (cpuno > ied->cpucount) {
					//int c = cpuno;
					//cout << "cpucount(linecount old):" << (int)(ied->cpucount) << "new:" << c << endl;

					ied->cpucount = cpuno;
					//cout << "byte_t cpucount:" << ied->cpucount+1 << endl;
				}
			}

		}
		OTLDisconnect();
	}
	catch (otl_exception& e)
	{
		printf("\nledger monitor\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg);
		return e.code;
	}

	if (count_cfg != count_real)
		return APR_EBADF;
	return APR_SUCCESS;
}

int parse_model_cfg_web_test()
{
	std::vector<std::string> codes;//入参集合
	QMap<QString, icd_model*>  icd_model_map;
	codes.push_back("info");

	parse_model_web_test(&icd_model_map,codes);

	codes.clear();

	try {
		char model_id[64];
		char tmnl_type[64];
		char tmnl_factory[64];
		char file_name[128];
		//char timestamp[64];
		otl_datetime timestamp;

		// 遍历终端台账容器
		QMap<QString, icd_model*>::iterator it;
    	for (it = icd_model_map.begin(); it != icd_model_map.end(); ++it) {
    		icd_model* value = it.value();

			// 确保 value 不为空
    		if (value != nullptr) {
        		// 找到容器中对应名称并取值
        		strncpy(model_id, value->model_id, sizeof(model_id) - 1);
        		strncpy(tmnl_type, value->tmnl_type, sizeof(tmnl_type) - 1);
        		strncpy(tmnl_factory, value->tmnl_factory, sizeof(tmnl_factory) - 1);
        		strncpy(file_name, value->file_name, sizeof(file_name) - 1);
        		//strncpy(timestamp, value->timestamp, sizeof(timestamp) - 1);

				timestamp = parseTimestamp(value->timestamp);

				Set_xml_databaseinfo(model_id, tmnl_type, tmnl_factory, file_name, timestamp.year, timestamp.month, timestamp.day, timestamp.hour, timestamp.minute, timestamp.second);
    		}
		}
	}
	catch (otl_exception& e)
	{
		printf("\nicd model\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg);
		return e.code;
	}
}
#if 0
//定时任务的sql修改为web
void OnTimerThread::run()
{
	msleep(10000);
	printf("OnTimerThread::run() is called ...... \n");
	static int delectflag = 1;//定时日志清理标记
	bool account_update = true;
	bool asd = true;

	apr_time_t	previousTime = apr_time_now();//
	apr_time_exp_t localTime;
	apr_time_exp_gmt(&localTime, previousTime);
	cout << "Local Time: "
		<< localTime.tm_year + 1900 << "-" << localTime.tm_mon + 1 << "-" << localTime.tm_mday << " "
		<< localTime.tm_hour << ":" << localTime.tm_min << ":" << localTime.tm_sec
		<< endl;

	QMap<QString, bool> dic_task_block;

	// 向QMap中添加键值对
	dic_task_block.insert("account", false);
	dic_task_block.insert("recruit ", false);
	dic_task_block.insert("log", false);
	dic_task_block.insert("multi_node", false);

	int ip_count = 0;
	int telnet_count = 0;
	// 查找键值对
	if (g_node_id == RECALL_HIS_DATA_BASE_NODE_ID) {
		init_ping_telnet(ip_count, telnet_count);
		Cout_account_information();
	}

	if (g_onlyIP[0] != 0)
	{
		printf("g_onlyIP[0]=!0 ontimer--%s--\n", g_onlyIP);
		add_comm_log(const_cast<char*>("g_onlyIP[0]=!0,g_onlyIP is --%s--", g_onlyIP));
	}
	else {
		printf("g_onlyIP[0] == 0!");

	}

	int pgflag = 0;
	int pgmin = 0;
	int mp_num_hour = 0;
	int recall_flag1 = 1;

	//添加入参容器
	std::vector<std::string> codes;

	//char recalllllll[256] = "0923000982";
	//CheckPG_To_Recall(1705168800, 1705168800 + 3599, recalllllll);
	while (1)
	{
		/*cout << "ip_count:" << ip_count << " telnet_count:" << telnet_count << endl;
		msleep(1000);*/

		//进入线程时间
		previousTime = apr_time_now();
		apr_time_exp_gmt(&localTime, previousTime);
		//apr_time_t elapsedTime = currentTime - previousTime;
		//apr_time_as_msec(elapsedTime);
		//cout << "front num:" << FRONT_MP_NUM << endl;
		if (strcmp(subdir, "cfg_stat_data") == 0 || strcmp(subdir, "cfg_newhis_data") == 0) {//台账更新,多节点,通讯
			//读取上次台账更新时间

			//判断间隔执行
			if (false) {
				//执行台账任务;

			}
			//记录现在时间
			// 
			//判断执行此任务时间段内是否有 任务被堵塞
			if (MULTIPLE_NODE_FLAG && pgflag) {
				if (FRONT_INST != 0 && FRONT_IP[0] != '\0') {

//修改为web接口更新前置表
					/*QString updateFrontSql;//待组装的pgsql语句
					updateFrontSql.append(QString("update \"%1\".\"%2meas_pq_front_list_tr\" ").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX));
					updateFrontSql.append(QString("set \"mp_num\"= %1,front_version='%2' ").arg(FRONT_MP_NUM).arg(PROGRAM_VERSION));
					updateFrontSql.append(QString("where \"front_ip\" = '%1' and \"front_inst\"=%2;").arg(FRONT_IP).arg(FRONT_INST));
					Sql_data_list_mutex.lock(); //加锁
					Sql_data_list.append(updateFrontSql);
					Sql_data_list_mutex.unlock(); //解锁*/

					codes.push_back("updatefront");
					codes.push_back(std::string(FRONT_IP));
					codes.push_back(intToString(FRONT_INST));
					codes.push_back(intToString(FRONT_MP_NUM));
					codes.push_back(std::string(PROGRAM_VERSION));
					parse_device_web_test_front_write(codes);
					codes.clear();

				}
				pgflag = 0;
			}
			else if (MULTIPLE_NODE_FLAG && pgmin != localTime.tm_min)
			{
				pgmin = localTime.tm_min;
				pgflag = 1;
			}

			if (mp_num_hour != localTime.tm_hour) {
				std::string mp_num_str = "";
				mp_num_str.append("connected device count:");
				mp_num_str.append(QString::number(FRONT_MP_NUM).toStdString());
				mp_num_str.append(",g_node clients:");
				mp_num_str.append(QString::number(g_node->n_clients).toStdString());

				add_comm_log(const_cast<char*>(mp_num_str.c_str()));
				mp_num_hour = localTime.tm_hour;
			}


			//2023-10-17 zw新增 定期obs oss和sql数据库记录删除
			if (delectflag == 1 && localTime.tm_hour == 16)
			{
				delectflag = 0;
				//time_t timestamp = apr_time_as_time_t(previousTime);
				long long stamp = static_cast<long long>(previousTime) / 1000000;
				cout << ">>>>>>>>>The Time is: " << stamp << endl;
				if (FILE_FLAG == 1) //阿里云 oss 文件删除
				{
					//PutOSS("comtrade/not def/20231111/temp2.log", "/FeProject/dat/9D3AAA2BDCE430BA7E3E1302F132B880.xml");

					int i = 0;
					while (i < g_pt61850app->chnl_counts)
					{
						chnl_usr_t* chnl_usr;
						ied_t* ied;
						ied_usr_t* ied_usr;
						LD_info_t* LD_info;
						int	cpuno = 0;

						chnl_usr = g_pt61850app->chnl_usr[i];
						ied = chnl_usr->chnl->ied;
						ied_usr = GET_IEDEXT_ADDR(ied);
						while (cpuno < ied->cpucount)
						{
							LD_info = &(ied_usr->LD_info[cpuno]);

							long long deltime = stamp - (60 * 60 * 24 * 30);//减去30天
							QDateTime deltime_Qtime = QDateTime::fromTime_t(deltime);
							QString tmp_chr1 = deltime_Qtime.toString("yyyyMMdd");
							QString Oss_Del_Path = NULL;
							Oss_Del_Path.append("comtrade/");
							Oss_Del_Path.append(LD_info->mp_id).append("/");
							Oss_Del_Path.append(tmp_chr1).append("/");
							//cout << Oss_Del_Path.toAscii().data() << endl;
							DelOSS(Oss_Del_Path.toAscii().data());
							cpuno++;
						}
						i++;
					}
					//PutOSS("comtrade/not def/20231111/temp.log","/FeProject/dat/6A5C8A2A7BBC1A61D9EC3F1AE2A25A03.xml");
					//PutOSS("comtrade/not def/20231111/temp2.log", "/FeProject/dat/6A5C8A2A7BBC1A61D9EC3F1AE2A25A03.xml");
					//PutOSS("comtrade/not def/20231111/temp3.log", "/FeProject/dat/6A5C8A2A7BBC1A61D9EC3F1AE2A25A03.xml");
					//DelOSS("comtrade/not def/20231111/temp3.log");
				}
				else if (FILE_FLAG == 2)//华为云 obs 文件删除
				{
					//OBSFile("/FeProject/dat/67BC249C13B5EC819CF4DF0307DB71C5.xml", "comtrade/not def/20231111/temp3.log", "putObject");
					//OBSFile_del("comtrade/not def/20231111/temp3.log", "deleteObject");

					int i = 0;
					while (i < g_pt61850app->chnl_counts)
					{
						chnl_usr_t* chnl_usr;
						ied_t* ied;
						ied_usr_t* ied_usr;
						LD_info_t* LD_info;
						int	cpuno = 0;

						chnl_usr = g_pt61850app->chnl_usr[i];
						ied = chnl_usr->chnl->ied;
						ied_usr = GET_IEDEXT_ADDR(ied);
						while (cpuno < ied->cpucount)
						{
							LD_info = &(ied_usr->LD_info[cpuno]);

							long long deltime = stamp - (60 * 60 * 24 * 30);//减去30天
							QDateTime deltime_Qtime = QDateTime::fromTime_t(deltime);
							QString tmp_chr1 = deltime_Qtime.toString("yyyyMMdd");
							QString Oss_Del_Path = NULL;
							Oss_Del_Path.append("comtrade/");
							Oss_Del_Path.append(LD_info->mp_id).append("/");
							Oss_Del_Path.append(tmp_chr1).append("/");
							//cout << Oss_Del_Path.toAscii().data() << endl;
							OBSFile_del(Oss_Del_Path.toAscii().data(), "deleteObject");
							cpuno++;
						}
						i++;
					}


				}

				//pgsql删除记录
				long long deltime = stamp - (60 * 60 * 24 * 30);//减去30天
				QDateTime deltime_Qtime = QDateTime::fromTime_t(deltime);
				QString tmp_chr1 = deltime_Qtime.toString("yyyy-MM-dd");
//替换成web接口
				/*QString pgsql0;
				pgsql0.append(QString("DELETE FROM \"%1\".\"%2meas_pq_comm_status_tr\ WHERE \"statistical_data\" < '%3';").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX).arg(tmp_chr1));
				QString pgsql1;
				pgsql1.append(QString("DELETE FROM \"%1\".\"%2meas_pq_comm_error_tr\ WHERE \"statistical_data\" < '%3';").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX).arg(tmp_chr1));
				QString pgsql2;
				pgsql2.append(QString("DELETE FROM \"%1\".\"%2meas_pq_measpoint_rationality_tr\ WHERE \"statistical_data\" < '%3';").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX).arg(tmp_chr1));
				QString pgsql3;
				pgsql3.append(QString("DELETE FROM \"%1\".\"%2meas_pq_measpoint_intact_tr\ WHERE \"statistical_data\" < '%3';").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX).arg(tmp_chr1));
				QString pgsql4;
				pgsql4.append(QString("DELETE FROM \"%1\".\"%2meas_pq_measpoint_match_tr\ WHERE \"statistical_data\" < '%3';").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX).arg(tmp_chr1));
				Sql_data_list_mutex.lock(); //加锁
				Sql_data_list.append(pgsql0);
				Sql_data_list.append(pgsql1);
				Sql_data_list.append(pgsql2);
				Sql_data_list.append(pgsql3);
				Sql_data_list.append(pgsql4);
				Sql_data_list_mutex.unlock(); //解锁*/
				codes.push_back("delete");
				codes.push_back(tmp_chr1.toStdString());
				parse_database_delete(codes);
				codes.clear();

			}
			if (delectflag == 0 && localTime.tm_hour != 16)
			{
				delectflag = 1;
			}
			//2023-10-17 zw新增 定期obs oss和sql数据库记录删除 end

		}
		if (strcmp(subdir, "cfg_newhis_data") == 0) {//上海定时招装置日志
			static int hour_time = 0;
			if (localTime.tm_hour != hour_time) {
				hour_time = localTime.tm_hour;

				printf(">>>cfg_newhis_data is run!!!\n");
				long long stamp = static_cast<long long>(previousTime) / 1000000;
				cout << ">>>>>>>>>The Time is: " << stamp << endl;
				long long start = stamp - (stamp % 3600) - 3600 - 3600;//开始时间 当前整点值往前推两小时
				long long end = start + 3599;//结束时间

				QList<RecallInfo> recallinfo_list_hour;
				RecallInfo info;
				info.starttime = start - 10;
				info.endtime = end;
				recallinfo_list_hour.append(info);

				int i = 0;
				while (i < g_pt61850app->chnl_counts)
				{
					chnl_usr_t* chnl_usr;
					ied_t* ied;
					ied_usr_t* ied_usr;
					LD_info_t* LD_info;
					int	cpuno = 0;

					chnl_usr = g_pt61850app->chnl_usr[i];
					ied = chnl_usr->chnl->ied;
					ied_usr = GET_IEDEXT_ADDR(ied);
					printf("\n chnl_usr->m_state ===== %d\n", chnl_usr->m_state);
					//if (chnl_usr->m_state == CHANNEL_CONNECTED) {
					while (cpuno < ied->cpucount)
					{
						LD_info = &(ied_usr->LD_info[cpuno]);
						cpuno++;
						if (LD_info->logcount <= 0 || LD_info->read_flag == 0)
							continue;
						printf("/home/pq mpid=%s\n", LD_info->mp_id);
						printf("\n %d ===== %d\n", recallinfo_list_hour.size(), LD_info->autorecallflag);

						if (recallinfo_list_hour.size() != 0) {
							for (int j = 0; j < recallinfo_list_hour.size(); j++) {
								CJournalRecall jr;
								jr.MonitorID = QString(LD_info->mp_id);
								jr.StartTime = QDateTime::fromTime_t(recallinfo_list_hour[j].starttime).toString("yyyy-MM-dd hh:mm:ss");
								jr.EndTime = QDateTime::fromTime_t(recallinfo_list_hour[j].endtime).toString("yyyy-MM-dd hh:mm:ss");
								jr.STEADY = QString::number(1, 10);
								jr.VOLTAGE = QString::number(1, 10);
								g_StatisticLackList_list_mutex.lock();
								g_StatisticLackList.push_back(jr);
								g_StatisticLackList_list_mutex.unlock();
							}
						}
					}

					i++;
				}
			}
		}
		if (strcmp(subdir, "cfg_recallall_data") == 0)
		{
			static int recall_xml_time = 0;
			if (localTime.tm_min != recall_xml_time)
			{
				recall_xml_time = localTime.tm_min;
				//补招开始与截止时间
				static long long recall_start_time = 0;
				static long long recall_end_time = 0;
				static int flag = 0;
				if (recall_start_time == 0 && recall_end_time == 0) {//无缓存数据
					//查询一条 -1状态(代补招)的记录
					char front_ip[42];
					cout << "start select:" << endl;
//替换为web接口
					/*QString selectFrontSql;
					selectFrontSql.append(QString("select \"front_ip\" from \"%1\".\"%2meas_pq_front_list_tr\" ").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX));
					selectFrontSql.append(QString("where front_inst=%1 and \"front_status\" = '-1' LIMIT 1;").arg(g_front_seg_index));
					cout << selectFrontSql.toStdString().c_str() << endl;
					try {
						otl_stream i(1, // buffer size
							selectFrontSql.toStdString().c_str(),
							db //connect object
						);
						//create select stream
						while (!i.eof()) { //while not end-of-data
							i >> front_ip;
							break;
							//cout << "count=" << f2 << endl;
						}
					}
					catch (otl_exception& e)
					{
						printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg);
						continue;
					}*/
					QMap<QString, front_list*> front_map;
					codes.push_back("frontip");
					codes.push_back("g_front_seg_index");
					codes.push_back("-1");
					parse_device_web_test_front_read(&front_map,codes);
					codes.clear();
					// 遍历 QMap 容器
					QMap<QString, front_list*>::iterator it;
    				for (it = front_map.begin(); it != front_map.end(); ++it) {
        				front_list* value = it.value();
        				// 确保 value 不为空
        				if (value != nullptr) {
        			    	// 从 value 中读取 front_ip
        			    	strncpy(front_ip, value->front_ip, sizeof(front_ip) - 1);
							//应该只有一条记录
							std::cout << "front_ip:" <<front_ip << std::endl;
						}
					}
					
					if (containsDash(front_ip, 21)) {
//替换为web接口
						//插入更新记录
						/*QString insertFrontSql;
						insertFrontSql.append(QString("insert into \"%1\".\"%2meas_pq_front_list_tr\"(\"front_ip\",\"front_port\",\"front_inst\",\"front_type\",\"front_status\",\"front_version\",\"mp_num\") ").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX));
						insertFrontSql.append(QString("values('%1',10000,%2,'03','-1','%3',200) ").arg(front_ip).arg(g_front_seg_index).arg(PROGRAM_VERSION));
						insertFrontSql.append(QString("on conflict(\"front_ip\",\"front_inst\") do update set "));
						insertFrontSql.append(QString("\"front_status\"= '%1'").arg("-2"));
						cout << insertFrontSql.toStdString().c_str() << endl;
						Sql_data_list_mutex.lock(); //加锁
						Sql_data_list.append(insertFrontSql);
						Sql_data_list_mutex.unlock(); //解锁*/
						codes.push_back("insertfront");
						codes.push_back(std::string(front_ip));
						codes.push_back(intToString(g_front_seg_index));
						codes.push_back("03");		//前置类型
						codes.push_back(std::string(PROGRAM_VERSION));				
						codes.push_back("-1");		//状态值				
						parse_device_web_test_front_write(codes);				
						codes.clear();

						//缓存数据
						cout << "front_ip=" << front_ip << endl;
						QString startDate, endDate;
						// 分割字符串  
						startDate = QString::fromAscii(front_ip).left(10); // 取前10个字符作为开始日期  
						qDebug() << "startDate=" << startDate << endl;
						endDate = QString::fromAscii(front_ip + 11).left(10); // 从第10个字符开始取8个字符作为结束日期
						qDebug() << "endDate=" << endDate << endl;

						QDateTime start_dt = QDateTime::fromString(startDate, "yyyyMMddHH");
						qDebug() << "start_dt=" << start_dt << endl;
						recall_start_time = start_dt.toMSecsSinceEpoch() / 1000;
						qDebug() << "recall_start_time=" << recall_start_time << endl;
						QDateTime end_dt = QDateTime::fromString(endDate, "yyyyMMddHH");
						qDebug() << "end_dt=" << end_dt << endl;
						recall_end_time = end_dt.toMSecsSinceEpoch() / 1000;
						qDebug() << "recall_end_time=" << recall_end_time << endl;
					}
					flag = 0;

				}
				else if (recall_start_time != 0 && recall_end_time != 0) {//有缓存数据
					// 将时间戳转换为YYYYMMDD格式  
					QString date1 = timestampToYYYYMMDD(recall_start_time);
					QString date2 = timestampToYYYYMMDD(recall_end_time);
					// 拼接两个日期，并用'-'分隔  
					QString dateRange = date1 + "-" + date2;
					qDebug() << "dateRange=" << dateRange << endl;
					char front_status[4];
//替换为web接口

					/*QString selectFrontSql;
					selectFrontSql.append(QString("select front_status from \"%1\".\"%2meas_pq_front_list_tr\" ").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX));
					selectFrontSql.append(QString("where front_inst=%1 and \"front_ip\" = '%2'").arg(g_front_seg_index).arg(dateRange));
					cout << selectFrontSql.toStdString().c_str() << endl;
					try {
						otl_stream i(1, // buffer size
							selectFrontSql.toStdString().c_str(),
							db //connect object
						);
						//create select stream
						while (!i.eof()) { //while not end-of-data
							i >> front_status;
							break;
							//cout << "count=" << f2 << endl;
						}
					}
					catch (otl_exception& e)
					{
						printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg);
						continue;
					}*/
					QMap<QString, front_list*> front_map;
					codes.push_back("frontstatus");
					codes.push_back(dateRange.toStdString());  //ip
					codes.push_back("g_front_seg_index");	//inst
					parse_device_web_test_front_read(&front_map,codes);
					codes.clear();
					// 遍历 QMap 容器
					QMap<QString, front_list*>::iterator it;
    				for (it = front_map.begin(); it != front_map.end(); ++it) {
        				front_list* value = it.value();
        				// 确保 value 不为空
        				if (value != nullptr) {
        			    	// 从 value 中读取 front_ip
        			    	strncpy(front_status, value->front_status, sizeof(front_status) - 1);
							//应该只有一条记录
							std::cout << "front_status:" <<front_status << std::endl;
						}
					}

					qDebug() << "front_status=" << front_status << endl;
					//再次判断是否为执行中状态
					if (strcmp(front_status, "-1") == 0) {
						//状态为-1 重新插入更新记录

//替换为web接口
						/*QString updateFrontSql;
						updateFrontSql.append(QString("insert into \"%1\".\"%2meas_pq_front_list_tr\"(\"front_ip\",\"front_port\",\"front_inst\",\"front_type\",\"front_status\",\"front_version\",\"mp_num\") ").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX));
						updateFrontSql.append(QString("values('%1',10000,%2,'03','-1','%3',200) ").arg(dateRange).arg(g_front_seg_index).arg(PROGRAM_VERSION));
						updateFrontSql.append(QString("on conflict(\"front_ip\",\"front_inst\") do update set "));
						updateFrontSql.append(QString("\"front_status\"= '%1'").arg("-2"));
						cout << updateFrontSql.toStdString().c_str() << endl;
						Sql_data_list_mutex.lock(); //加锁
						Sql_data_list.append(updateFrontSql);
						Sql_data_list_mutex.unlock(); //解锁*/
						codes.push_back("insertfront");
						codes.push_back(dateRange.toStdString());
						codes.push_back(intToString(g_front_seg_index));
						codes.push_back("03");		//前置类型
						codes.push_back(std::string(PROGRAM_VERSION));				
						codes.push_back("-1");		//状态值				
						parse_device_web_test_front_write(codes);				
						codes.clear();

						flag = 0;
					}
					else if (strcmp(front_status, "-2") == 0)
					{//状态为-2 补招

						flag = 1;
					}
					else {
						flag = 0;
						recall_end_time = 0;
						recall_start_time = 0;
					}

				}

				if (recall_start_time != 0 && recall_end_time != 0 && flag == 1)
				{
					qDebug() << "start recall time=" << recall_start_time << endl;
					qDebug() << "end recall time=" << recall_end_time << endl;

					long long starttime = recall_start_time;  //补招起始时间
					long long endtime = recall_end_time;                //补招结束时间

					flag = 0;
					recall_start_time = 0;
					recall_end_time = 0;

					QList<RecallInfo> recallinfo_list;                    //待补招队列
					QList<RecallInfo> recallinfo_list_hour;               //待补招队列-以小时为最大间隔


					RecallInfo info;
					info.starttime = starttime;
					info.endtime = endtime;
					recallinfo_list.append(info);

					for (int i = 0; i < recallinfo_list.size(); i++)
					{
						//printf("\n %lld ----- %11d\n", recallinfo_list[i].starttime, recallinfo_list[i].endtime);
						long long duration = recallinfo_list[i].endtime - recallinfo_list[i].starttime;
						long long max_interval = 3600;
						for (long long j = 0; j <= duration; j += max_interval)
						{
							if (j + max_interval > duration) {
								long long start = recallinfo_list[i].starttime + j;
								long long end = recallinfo_list[i].endtime;

								RecallInfo info;
								info.starttime = start;
								info.endtime = end;
								recallinfo_list_hour.append(info);
							}
							else {
								long long start = recallinfo_list[i].starttime + j;
								long long end = recallinfo_list[i].starttime + j + max_interval;

								RecallInfo info;
								info.starttime = start;
								info.endtime = end - 1;
								recallinfo_list_hour.append(info);
							}
						}
					}

					int i = 0;
					while (i < g_pt61850app->chnl_counts)
					{
						chnl_usr_t* chnl_usr;
						ied_t* ied;
						ied_usr_t* ied_usr;
						LD_info_t* LD_info;
						int	cpuno = 0;

						chnl_usr = g_pt61850app->chnl_usr[i];
						ied = chnl_usr->chnl->ied;
						ied_usr = GET_IEDEXT_ADDR(ied);
						printf("\n chnl_usr->m_state ===== %d\n", chnl_usr->m_state);
						//if (chnl_usr->m_state == CHANNEL_CONNECTED)
						while (cpuno < ied->cpucount)
						{
							LD_info = &(ied_usr->LD_info[cpuno]);
							cpuno++;
							printf("/home/pq mpid=%s %d\n", LD_info->mp_id, LD_info->read_flag);
							if (LD_info->logcount <= 0 || LD_info->read_flag == 0) {
								continue;
							}
							printf("\n %d ===== %d\n", recallinfo_list_hour.size(), LD_info->autorecallflag);

							if (recallinfo_list_hour.size() != 0) {
								g_StatisticLackList_list_mutex.lock();
								for (int j = 0; j < recallinfo_list_hour.size(); j++) {

//替换成web接口 2024-10-21 lnk
			//						if (CheckPG_To_Recall(recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime, LD_info->mp_id) == false) {
			//							printf("CheckPG_To_Recall == false %d-%d %s\n", recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime, LD_info->mp_id);
									if (CheckPG_To_Recall_web(recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime, LD_info->mp_id) == false) {
										printf("CheckPG_To_Recall_web == false %d-%d %s\n", recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime, LD_info->mp_id);

										continue;
									}
									CJournalRecall jr;
									jr.MonitorID = QString(LD_info->mp_id);
									jr.StartTime = QDateTime::fromTime_t(recallinfo_list_hour[j].starttime).toString("yyyy-MM-dd hh:mm:ss");
									jr.EndTime = QDateTime::fromTime_t(recallinfo_list_hour[j].endtime).toString("yyyy-MM-dd hh:mm:ss");
									jr.STEADY = QString::number(1, 10);
									jr.VOLTAGE = QString::number(1, 10);
									g_StatisticLackList.push_back(jr);

								}
								g_StatisticLackList_list_mutex.unlock();
							}
						}

						i++;
					}
				}
			}

		}
		if (strcmp(subdir, "cfg_his_data") == 0)
		{
			if (pgflag) {
				if (FRONT_INST != 0 && FRONT_IP[0] != '\0') {

//替换为web接口
					/*QString updateFrontSql;
					updateFrontSql.append(QString("insert into \"%1\".\"%2meas_pq_front_list_tr\"(\"front_ip\",\"front_port\",\"front_inst\",\"front_type\",\"front_status\",\"front_version\",\"mp_num\") ").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX));
					updateFrontSql.append(QString("values('his',10000,1,'02','01','%1',200) ").arg(PROGRAM_VERSION));
					updateFrontSql.append(QString("on conflict(\"front_ip\",\"front_inst\") do update set "));
					updateFrontSql.append(QString("\"mp_num\"= '%1',front_version='%2'").arg(FRONT_MP_NUM).arg(PROGRAM_VERSION));
					Sql_data_list_mutex.lock(); //加锁
					Sql_data_list.append(updateFrontSql);
					Sql_data_list_mutex.unlock(); //解锁	*/
					codes.push_back("his");
					codes.push_back("his");	//ip
					codes.push_back(std::string(PROGRAM_VERSION));				
					codes.push_back(intToString(FRONT_MP_NUM));		//检测点数				
					parse_device_web_test_front_write(codes);				
					codes.clear();

				}
				pgflag = 0;
			}
			else if (pgmin != localTime.tm_min)
			{
				pgmin = localTime.tm_min;
				pgflag = 1;
			}

			static int cfg_his_data_hour_time = 0;
			if (localTime.tm_hour != cfg_his_data_hour_time) {
				cfg_his_data_hour_time = localTime.tm_hour;

				printf(">>>cfg_his_data is run!!!\n");
				long long stamp = static_cast<long long>(previousTime) / 1000000;
				cout << ">>>>>>>>>The Time is: " << stamp << endl;
				long long start = stamp - (stamp % 3600) - 3600 - 3600;//开始时间 当前整点值往前推两小时
				long long end = start + 3599;//结束时间

				QList<RecallInfo> recallinfo_list_hour;
				RecallInfo info;
				info.starttime = start - 10;
				info.endtime = end;
				recallinfo_list_hour.append(info);

				int i = 0;
				while (i < g_pt61850app->chnl_counts)
				{
					chnl_usr_t* chnl_usr;
					ied_t* ied;
					ied_usr_t* ied_usr;
					LD_info_t* LD_info;
					int	cpuno = 0;

					chnl_usr = g_pt61850app->chnl_usr[i];
					ied = chnl_usr->chnl->ied;
					ied_usr = GET_IEDEXT_ADDR(ied);
					printf("\n chnl_usr->m_state ===== %d\n", chnl_usr->m_state);
					//if (chnl_usr->m_state == CHANNEL_CONNECTED) {
					while (cpuno < ied->cpucount)
					{
						LD_info = &(ied_usr->LD_info[cpuno]);
						cpuno++;
						if (LD_info->logcount <= 0 || LD_info->read_flag == 0)
							continue;
						printf("/home/pq mpid=%s\n", LD_info->mp_id);
						printf("\n %d ===== %d\n", recallinfo_list_hour.size(), LD_info->autorecallflag);

						if (recallinfo_list_hour.size() != 0) {
							for (int j = 0; j < recallinfo_list_hour.size(); j++) {

//替换成web接口 2024-10-21 lnk
								//if (CheckPG_To_Recall(recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime, LD_info->mp_id) == false) {
									//printf("CheckPG_To_Recall == false %d-%d %s\n", recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime, LD_info->mp_id);
								if (CheckPG_To_Recall_web(recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime, LD_info->mp_id) == false) {
									printf("CheckPG_To_Recall_web == false %d-%d %s\n", recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime, LD_info->mp_id);
									
									continue;
								}
								CJournalRecall jr;
								jr.MonitorID = QString(LD_info->mp_id);
								jr.StartTime = QDateTime::fromTime_t(recallinfo_list_hour[j].starttime).toString("yyyy-MM-dd hh:mm:ss");
								jr.EndTime = QDateTime::fromTime_t(recallinfo_list_hour[j].endtime).toString("yyyy-MM-dd hh:mm:ss");
								jr.STEADY = QString::number(1, 10);
								jr.VOLTAGE = QString::number(1, 10);
								g_StatisticLackList_list_mutex.lock();
								g_StatisticLackList.push_back(jr);
								g_StatisticLackList_list_mutex.unlock();
							}
						}
					}

					i++;
				}
			}

		}
		if (strcmp(subdir, "cfg_recallhis_data") == 0)
		{
			if (pgflag) {
				if (FRONT_INST != 0 && FRONT_IP[0] != '\0') {
//替换为web接口
					/*QString updateFrontSql;
					updateFrontSql.append(QString("insert into \"%1\".\"%2meas_pq_front_list_tr\"(\"front_ip\",\"front_port\",\"front_inst\",\"front_type\",\"front_status\",\"front_version\",\"mp_num\") ").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX));
					updateFrontSql.append(QString("values('recallhis',10000,1,'02','01','%1',200) ").arg(PROGRAM_VERSION));
					updateFrontSql.append(QString("on conflict(\"front_ip\",\"front_inst\") do update set "));
					updateFrontSql.append(QString("\"mp_num\"= '%1',front_version='%2'").arg(FRONT_MP_NUM).arg(PROGRAM_VERSION));
					Sql_data_list_mutex.lock(); //加锁
					Sql_data_list.append(updateFrontSql);
					Sql_data_list_mutex.unlock(); //解锁	*/
					codes.push_back("his");
					codes.push_back("recallhis");	//ip
					codes.push_back(std::string(PROGRAM_VERSION));				
					codes.push_back(intToString(FRONT_MP_NUM));		//检测点数				
					parse_device_web_test_front_write(codes);				
					codes.clear();

				}
				pgflag = 0;
			}
			else if (pgmin != localTime.tm_min)
			{
				pgmin = localTime.tm_min;
				pgflag = 1;
			}

		}

		//g_node_id == HIS_DATA_BASE_NODE_ID &&
		//printf("/home/pq hour=%d\n", localTime.tm_hour);
		if (0 && g_node_id == HIS_DATA_BASE_NODE_ID && (localTime.tm_hour <= 12 || localTime.tm_hour >= 20) && recall_flag1 == 1) {
			recall_flag1 = 0;
			QString MyKafkaIniFilename = QString("../etc/") + QString("mykafka.ini"); //+QString::fromAscii(subdir)
			QSettings settings(MyKafkaIniFilename, QSettings::IniFormat);

			QString dateString = settings.value("Recall/select_day").toString();

			QList<RecallInfo> recallinfo_list_hour;
			QByteArray byteArray = dateString.toUtf8(); // 使用 UTF-8 编码  
			char* charArray = byteArray.data();
			Get_Recall_Time(charArray, recallinfo_list_hour);

			int i = 0;
			while (i < g_pt61850app->chnl_counts)
			{
				chnl_usr_t* chnl_usr;
				ied_t* ied;
				ied_usr_t* ied_usr;
				LD_info_t* LD_info;
				int	cpuno = 0;

				chnl_usr = g_pt61850app->chnl_usr[i];
				ied = chnl_usr->chnl->ied;
				ied_usr = GET_IEDEXT_ADDR(ied);
				while (cpuno < ied->cpucount)
				{
					LD_info = &(ied_usr->LD_info[cpuno]);
					if (LD_info->logcount <= 0)
						continue;
					printf("/home/pq mpid=%s\n", LD_info->mp_id);
					printf("\n %d ===== %d\n", recallinfo_list_hour.size(), LD_info->autorecallflag);
					if (recallinfo_list_hour.size() != 0) {
						if (LD_info->autorecallcount != 0) {
							for (int j = 0; j < LD_info->autorecallcount; j++) {
								delete LD_info->autorecall[j];
							}
							delete LD_info->autorecall;
							LD_info->autorecallcount = 0;
						}
						LD_info->autorecallflag = 0;
						LD_info->autorecallcount = recallinfo_list_hour.size();
						LD_info->autorecall = new autorecall_t * [recallinfo_list_hour.size()];
						printf("/home/pq recall mpid=%s\n", LD_info->mp_id);

						for (int j = 0; j < recallinfo_list_hour.size(); j++) {
							printf("\n %lld ===== %11d\n", recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime);
							LD_info->autorecall[j] = new autorecall_t[1];
							LD_info->autorecall[j]->start = recallinfo_list_hour[j].starttime;

							LD_info->autorecall[j]->end = recallinfo_list_hour[j].endtime;
						}
					}


					cpuno++;
				}
				i++;
			}

			QDate date = QDate::fromString(dateString, "yyyy-MM-dd");

			date.addDays(-1); // 一天  
			settings.setValue("Recall/select_day", date.toString("yyyy-MM-dd")); // 重新写入日期字符串  


		}
		if (localTime.tm_hour > 12 && localTime.tm_hour < 20 && recall_flag1 == 0) {
			recall_flag1 = 1;
		}

		msleep(1000);
	}

	printf(">>>OnTimerThread::run() is end!!!\n");
}
#endif
#endif
/*/////////////////////////////////////////////////////////lnk10-11移除pg库sql的测试代码/////////////////////////////////////////////////////////////*/

/*/////////////////////////////////////////////////////////lnk10-24根据web接口修改/////////////////////////////////////////////////////////////*/
//添加了json字符串的入参
// 回调函数，将数据直接追加到 *ptr 中
size_t req_reply_http(void* contents, size_t size, size_t nmemb, void* userp) {
    size_t realsize = size * nmemb;
    char** ptr = (char**)userp;

    // 动态扩展 *ptr 的内存
    char* temp = (char*)realloc(*ptr, strlen(*ptr) + realsize + 1);
    if (temp == NULL) {
        printf("Memory allocation failed!\n");
        return 0;  // 返回 0 以通知 curl 停止数据接收
    }
    *ptr = temp;

    // 追加数据到 *ptr
    strncat(*ptr, (char*)contents, realsize);
    return realsize;
}

void SendJsonAPI_web(const std::string& strUrl, const char* code, const std::string& json, char** ptr) {
    CURL* curl = curl_easy_init();
    CURLcode res;

    // 初始化 *ptr 并分配空字符串
    *ptr = (char*)malloc(1);
    if (*ptr == NULL) {
        printf("Memory allocation failed!\n");
        return;
    }
    (*ptr)[0] = '\0';  // 为空字符串以便 strncat 操作

    if (curl) {
        char url[256];
        snprintf(url, sizeof(url), "%s?%s", strUrl.c_str(), code);
        printf(">>>json %s\n", url);

        curl_easy_setopt(curl, CURLOPT_URL, url);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply_http);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, ptr);
        curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10);
        curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10);

        if (!json.empty()) {
            curl_easy_setopt(curl, CURLOPT_POST, 1L);
            curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json.c_str());
        }

        struct curl_slist* headers = NULL;
        headers = curl_slist_append(headers, "Content-Type: application/json");
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);

        res = curl_easy_perform(curl);

        if (res != CURLE_OK) {
            printf("web failed res code: %s\n", curl_easy_strerror(res));
        } else {
            //printf(">>> web return str: %s \n", *ptr);
        }

        curl_slist_free_all(headers);
        curl_easy_cleanup(curl);
    } else {
        printf(">>> web curl init failed\n");
    }
}
/*void SendJsonAPI_web(const std::string& strUrl, const char* code, const std::string& json, char** ptr) {
    // curl 初始化  
    CURL* curl = curl_easy_init();
    CURLcode res;

    if (curl) {
		char url[100];
		sprintf(url, "%s?%s", strUrl.c_str(), code);
		printf(">>>json %s\n", url);

        // 设置 URL
        curl_easy_setopt(curl, CURLOPT_URL, url);

        // 设置数据接收和写入函数
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply_web);

        // 数据接收
        std::string resPost0;
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&resPost0);

        // 设置超时时间
        curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10);
        curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10);

		if(json != ""){
			// 设置 HTTP 方法为 POST
        	curl_easy_setopt(curl, CURLOPT_POST, 1L);

        	// 设置 JSON 格式的 body 数据
        	curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json.c_str());
		}

        // 设置请求头
        struct curl_slist* headers = NULL;
        headers = curl_slist_append(headers, "Content-Type: application/json");
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
        
        // 执行请求
        res = curl_easy_perform(curl);

        // 检查请求是否成功
        if (res != CURLE_OK) {
            printf("web failed res code: %s\n", curl_easy_strerror(res));
        } else {
            printf(">>> web return str: %s \n", resPost0.c_str());

            // 分配内存并复制返回结果
            *ptr = (char*)malloc(resPost0.size() + 1); // 分配足够的内存空间
            if (*ptr != NULL) {
                strcpy(*ptr, resPost0.c_str());
            } else {
                printf("Memory allocation failed!\n");
            }
        }

        // 清理请求头
        curl_slist_free_all(headers);
    } else {
        printf(">>> web curl init failed");
    }
    curl_easy_cleanup(curl);
}*/

// 打印 terminal_dev_map 中所有内容的函数
void printTerminalDevMap(const QMap<QString, terminal_dev*>& terminal_dev_map) {
	QMap<QString, terminal_dev*>::const_iterator it;
    for (it = terminal_dev_map.constBegin(); it != terminal_dev_map.constEnd(); ++it) {
        QString key = it.key();
        terminal_dev* dev = it.value();
        
        if (dev) {
            qDebug() << "Key:" << key
                     << ", Terminal ID:" << QString(dev->terminal_id)
                     << ", Terminal Code:" << QString(dev->terminal_code)
                     << ", Organization Name:" << QString(dev->org_name)
                     << ", Maintenance Name:" << QString(dev->maint_name)
                     << ", Station Name:" << QString(dev->station_name)
                     << ", Factory:" << QString(dev->tmnl_factory)
                     << ", Status:" << QString(dev->tmnl_status)
                     << ", Device Type:" << QString(dev->dev_type)
                     << ", Device Key:" << QString(dev->dev_key)
                     << ", Device Series:" << QString(dev->dev_series)
					 << ", Device processNo:" << QString(dev->processNo)
                     << ", Address:" << QString(dev->addr_str)
                     << ", Port:" << QString(dev->port)
                     << ", Timestamp:" << QString(dev->timestamp);

            // 打印监测点信息
            for (int i = 0; i < 10; ++i) {
                qDebug() << " Monitor ID:" << QString(dev->line[i].monitor_id)
                         << ", Terminal Code:" << QString(dev->line[i].terminal_code)
                         << ", Monitor Name:" << QString(dev->line[i].monitor_name)
                         << ", Logical Device Seq:" << QString(dev->line[i].logical_device_seq)
                         << ", Voltage Level:" << QString(dev->line[i].voltage_level)
                         << ", Terminal Connect:" << QString(dev->line[i].terminal_connect)
                         << ", Timestamp:" << QString(dev->line[i].timestamp)
                         << ", Status:" << QString(dev->line[i].status);
            }
        } else {
            qDebug() << "Key:" << key << ", Value is nullptr";
        }
    }
}

//打印当前进程的台账//////////////////////////////////////////////////////////////////////////
// 打印结构体信息的递归函数
void printLedger(const ied_usr_t& ied_usr) {
    std::cout << "------------------------------------" << std::endl;
    std::cout << "|-- terminal_id: " << ied_usr.terminal_id << std::endl;
	std::cout << "|-- dev_index: " << ied_usr.dev_idx << std::endl;
    std::cout << "|-- dev_type: " << ied_usr.dev_type << std::endl;
    std::cout << "|-- dev_key: " << ied_usr.dev_key << std::endl;
    std::cout << "|-- dev_series: " << ied_usr.dev_series << std::endl;
    std::cout << "|-- dev_flag: " << ied_usr.dev_flag << std::endl;

    std::cout << "|-- last_call_wavelist_time: " << ied_usr.last_call_wavelist_time << std::endl;

    std::cout << "|-- org_name: " << ied_usr.org_name << std::endl;
    std::cout << "|-- maint_name: " << ied_usr.maint_name << std::endl;
    std::cout << "|-- station_name: " << ied_usr.station_name << std::endl;
    std::cout << "|-- tmnl_factory: " << ied_usr.tmnl_factory << std::endl;
    std::cout << "|-- time: " << ied_usr.time << std::endl;
    std::cout << "|-- tmnl_status: " << ied_usr.tmnl_status << std::endl;
    std::cout << "|-- terminal_code: " << ied_usr.terminal_code << std::endl;
    std::cout << "|-- update_flag: " << ied_usr.update_flag << std::endl;

    // 打印每个LD_info的内容
    for (int i = 0; i < 10; ++i) {
        if (strcmp(ied_usr.LD_info[i].mp_id, "") != 0) {
            std::cout << "|-- LD_info[" << i << "]:" << std::endl;
//name
            std::cout << "    |-- name: " << ied_usr.LD_info[i].name << std::endl;
			std::cout << "    |-- LD_name: " 
                      << (strlen(ied_usr.LD_info[i].LD_name) == 0 ? "NA" : ied_usr.LD_info[i].LD_name) 
                      << std::endl;
			std::cout << "    |-- read_flag: " << ied_usr.LD_info[i].read_flag << std::endl;
//index
			std::cout << "    |-- line_id: " << ied_usr.LD_info[i].line_id << std::endl;
//monitorledger
            std::cout << "    |-- mp_id: " << ied_usr.LD_info[i].mp_id << std::endl;
            std::cout << "    |-- terminal_code: " << ied_usr.LD_info[i].terminal_code << std::endl;
            std::cout << "    |-- voltage_level: " << ied_usr.LD_info[i].voltage_level << std::endl;
            std::cout << "    |-- v_wiring_type: " << ied_usr.LD_info[i].v_wiring_type << std::endl;
            std::cout << "    |-- time: " << ied_usr.LD_info[i].time << std::endl;
            std::cout << "    |-- update_flag: " << ied_usr.LD_info[i].update_flag << std::endl;
            std::cout << "    |-- monitor_status: " << ied_usr.LD_info[i].monitor_status << std::endl;
//count暂不打印数组
			std::cout << "    |-- rptcount: " << ied_usr.LD_info[i].rptcount << std::endl;
			std::cout << "    |-- logcount: " << ied_usr.LD_info[i].logcount << std::endl;
//rpt
			std::cout << "    |-- rptRecvFlag: " << ied_usr.LD_info[i].rptRecvFlag << std::endl;
			std::cout << "    |-- rptRecvCheckFlag: " << ied_usr.LD_info[i].rptRecvCheckFlag << std::endl;
			std::cout << "    |-- rptPstRecvFlag: " << ied_usr.LD_info[i].rptPstRecvFlag << std::endl;
			std::cout << "    |-- rptPstRecvCheckFlag: " << ied_usr.LD_info[i].rptPstRecvCheckFlag << std::endl;
//rtdata
			std::cout << "    |-- real_data: " << ied_usr.LD_info[i].real_data << std::endl;
			std::cout << "    |-- soe_data: " << ied_usr.LD_info[i].soe_data << std::endl;
			std::cout << "    |-- limit: " << ied_usr.LD_info[i].limit << std::endl;
			std::cout << "    |-- count: " << ied_usr.LD_info[i].count << std::endl;
//RDRE
			std::cout << "    |-- RDRE_FltNum: " << ied_usr.LD_info[i].RDRE_FltNum << std::endl;
			for (int j = 0; j < 256; ++j) { 
                if (ied_usr.LD_info[i].FltNum[j] != 0) {
					std::cout << "        |-- FltNum[" << j << "]:" << ied_usr.LD_info[i].FltNum[j] << std::endl;
				}
			}
//QVVR
			std::cout << "    |-- qvvr_idx: " << ied_usr.LD_info[i].qvvr_idx << std::endl;
            std::cout << "    |-- QVVRs:" << std::endl;
            for (int j = 0; j < 256; ++j) {  
                if (ied_usr.LD_info[i].qvvr[j].used_status != 0) {
                    std::cout << "        |-- QVVR[" << j << "]:" << std::endl;
                    std::cout << "		      |-- used_status: " << ied_usr.LD_info[i].qvvr[j].used_status << std::endl;
                    std::cout << "		      |-- QVVR_start: " << ied_usr.LD_info[i].qvvr[j].QVVR_start << std::endl;
                    std::cout << "		      |-- QVVR_type: " << ied_usr.LD_info[i].qvvr[j].QVVR_type << std::endl;
                    std::cout << "		      |-- QVVR_time: " << ied_usr.LD_info[i].qvvr[j].QVVR_time << std::endl;
                    std::cout << "		      |-- QVVR_PerTime: " << ied_usr.LD_info[i].qvvr[j].QVVR_PerTime << std::endl;
                    std::cout << "		      |-- QVVR_Amg: " << ied_usr.LD_info[i].qvvr[j].QVVR_Amg << std::endl;
                    std::cout << "		      |-- QVVR_Rptname: " << ied_usr.LD_info[i].qvvr[j].QVVR_Rptname << std::endl;
                    std::cout << "		      |-- timestamp: " << ied_usr.LD_info[i].qvvr[j].timestamp << std::endl;
                }
            }
        }
    }
    std::cout << "------------------------------------" << std::endl;
}
void printLedgerinshell(const ied_usr_t& ied_usr, QIODevice* outputDevice) {
    outputDevice->write("------------------------------------\n");
    outputDevice->write("|-- terminal_id: " + QByteArray(ied_usr.terminal_id) + "\n");
    outputDevice->write("|-- dev_index: " + QByteArray::number(ied_usr.dev_idx) + "\n");
    outputDevice->write("|-- dev_type: " + QByteArray(ied_usr.dev_type) + "\n");
    outputDevice->write("|-- dev_key: " + QByteArray(ied_usr.dev_key) + "\n");
    outputDevice->write("|-- dev_series: " + QByteArray(ied_usr.dev_series) + "\n");
	outputDevice->write("|-- dev_processNo: " + QByteArray(ied_usr.processNo) + "\n");
    outputDevice->write("|-- dev_flag: " + QByteArray::number(ied_usr.dev_flag) + "\n");

    outputDevice->write("|-- last_call_wavelist_time: " + QByteArray::number(ied_usr.last_call_wavelist_time) + "\n");

    outputDevice->write("|-- org_name: " + QByteArray(ied_usr.org_name) + "\n");
    outputDevice->write("|-- maint_name: " + QByteArray(ied_usr.maint_name) + "\n");
    outputDevice->write("|-- station_name: " + QByteArray(ied_usr.station_name) + "\n");
    outputDevice->write("|-- tmnl_factory: " + QByteArray(ied_usr.tmnl_factory) + "\n");
    outputDevice->write("|-- time: " + QByteArray::number(ied_usr.time) + "\n");
    outputDevice->write("|-- tmnl_status: " + QByteArray(ied_usr.tmnl_status) + "\n");
    outputDevice->write("|-- terminal_code: " + QByteArray(ied_usr.terminal_code) + "\n");
    outputDevice->write("|-- update_flag: " + QByteArray::number(ied_usr.update_flag) + "\n");

    // 打印每个LD_info的内容
    for (int i = 0; i < 10; ++i) {
        if (strcmp(ied_usr.LD_info[i].mp_id, "") != 0) {
            outputDevice->write("|-- LD_info[" + QByteArray::number(i) + "]:\n");
            
            // name
            outputDevice->write("    |-- name: " + QByteArray(ied_usr.LD_info[i].name) + "\n");
            outputDevice->write("    |-- LD_name: " 
                + (strlen(ied_usr.LD_info[i].LD_name) == 0 ? QByteArray("NA") : QByteArray(ied_usr.LD_info[i].LD_name))
                + "\n");
            outputDevice->write("    |-- read_flag: " + QByteArray::number(ied_usr.LD_info[i].read_flag) + "\n");

            // index
            outputDevice->write("    |-- line_id: " + QByteArray::number(ied_usr.LD_info[i].line_id) + "\n");

            // monitorledger
            outputDevice->write("    |-- mp_id: " + QByteArray(ied_usr.LD_info[i].mp_id) + "\n");
            outputDevice->write("    |-- terminal_code: " + QByteArray(ied_usr.LD_info[i].terminal_code) + "\n");
            outputDevice->write("    |-- voltage_level: " + QByteArray(ied_usr.LD_info[i].voltage_level) + "\n");
            outputDevice->write("    |-- v_wiring_type: " + QByteArray(ied_usr.LD_info[i].v_wiring_type) + "\n");
            outputDevice->write("    |-- time: " + QByteArray::number(ied_usr.LD_info[i].time) + "\n");
            outputDevice->write("    |-- update_flag: " + QByteArray::number(ied_usr.LD_info[i].update_flag) + "\n");
            outputDevice->write("    |-- monitor_status: " + QByteArray(ied_usr.LD_info[i].monitor_status) + "\n");

            // count暂不打印数组
            outputDevice->write("    |-- rptcount: " + QByteArray::number(ied_usr.LD_info[i].rptcount) + "\n");
            outputDevice->write("    |-- logcount: " + QByteArray::number(ied_usr.LD_info[i].logcount) + "\n");

            // rpt
            outputDevice->write("    |-- rptRecvFlag: " + QByteArray::number(ied_usr.LD_info[i].rptRecvFlag) + "\n");
            outputDevice->write("    |-- rptRecvCheckFlag: " + QByteArray::number(ied_usr.LD_info[i].rptRecvCheckFlag) + "\n");
            outputDevice->write("    |-- rptPstRecvFlag: " + QByteArray::number(ied_usr.LD_info[i].rptPstRecvFlag) + "\n");
            outputDevice->write("    |-- rptPstRecvCheckFlag: " + QByteArray::number(ied_usr.LD_info[i].rptPstRecvCheckFlag) + "\n");

            // rtdata
            outputDevice->write("    |-- real_data: " + QByteArray::number(ied_usr.LD_info[i].real_data) + "\n");
            outputDevice->write("    |-- soe_data: " + QByteArray::number(ied_usr.LD_info[i].soe_data) + "\n");
            outputDevice->write("    |-- limit: " + QByteArray::number(ied_usr.LD_info[i].limit) + "\n");
            outputDevice->write("    |-- count: " + QByteArray::number(ied_usr.LD_info[i].count) + "\n");

            // RDRE
            outputDevice->write("    |-- RDRE_FltNum: " + QByteArray::number(ied_usr.LD_info[i].RDRE_FltNum) + "\n");
            for (int j = 0; j < 256; ++j) {
                if (ied_usr.LD_info[i].FltNum[j] != 0) {
                    outputDevice->write("        |-- FltNum[" + QByteArray::number(j) + "]: " 
                        + QByteArray::number(ied_usr.LD_info[i].FltNum[j]) + "\n");
                }
            }

            // QVVR
            outputDevice->write("    |-- qvvr_idx: " + QByteArray::number(ied_usr.LD_info[i].qvvr_idx) + "\n");
            outputDevice->write("    |-- QVVRs:\n");
            for (int j = 0; j < 256; ++j) {
                if (ied_usr.LD_info[i].qvvr[j].used_status != 0) {
                    outputDevice->write("        |-- QVVR[" + QByteArray::number(j) + "]:\n");
                    outputDevice->write("            |-- used_status: " + QByteArray::number(ied_usr.LD_info[i].qvvr[j].used_status) + "\n");
                    outputDevice->write("            |-- QVVR_start: " + QByteArray::number(ied_usr.LD_info[i].qvvr[j].QVVR_start) + "\n");
                    outputDevice->write("            |-- QVVR_type: " + QByteArray::number(ied_usr.LD_info[i].qvvr[j].QVVR_type) + "\n");
                    outputDevice->write("            |-- QVVR_time: " + QByteArray::number(ied_usr.LD_info[i].qvvr[j].QVVR_time) + "\n");
                    outputDevice->write("            |-- QVVR_PerTime: " + QByteArray::number(ied_usr.LD_info[i].qvvr[j].QVVR_PerTime) + "\n");
                    outputDevice->write("            |-- QVVR_Amg: " + QByteArray::number(ied_usr.LD_info[i].qvvr[j].QVVR_Amg) + "\n");
                    outputDevice->write("            |-- QVVR_Rptname: " + QByteArray(ied_usr.LD_info[i].qvvr[j].QVVR_Rptname) + "\n");
                    outputDevice->write("            |-- timestamp: " + QByteArray::number(ied_usr.LD_info[i].qvvr[j].timestamp) + "\n");
                }
            }
        }
    }
    outputDevice->write("------------------------------------\n");
}

// 打印所有设备信息或特定终端信息
void ledger(const char* terminal_id, QIODevice* outputDevice) {
	outputDevice->write("print ledger in shell");
	pthread_mutex_lock(&mtx);
    bool found = false;
    ied_t* ied;
    ied_usr_t* ied_usr;
    for (int t = 0; t < g_node->n_clients; t++) {
        ied = (ied_t*)g_node->clients[t];
		if(ied != NULL){
			ied_usr = (ied_usr_t*)ied->usr_ext;
        	if (ied_usr != NULL && (terminal_id == NULL || strcmp(ied_usr->terminal_id, terminal_id) == 0)) {
            	printLedgerinshell(*ied_usr, outputDevice);  // 使用 QIODevice 输出
				std::cout << "!!! print to log !!!"<< std::endl;
				printLedger(*ied_usr);
            	found = true;
        	}
		}
        
    }
    if (!found || terminal_id == NULL) {
		std::cout << "该终端不存在: " << terminal_id << std::endl;
        QByteArray msg = "该终端不存在: " + QByteArray(terminal_id ? terminal_id : "NULL") + "\n";
        outputDevice->write(msg);  // 输出到 QIODevice
    }
	pthread_mutex_unlock(&mtx);
}

//lnk20250210打印指定的变量名
void value_print(const char *variableName, QTcpSocket *clientSocket) {
    char buffer[256];  // 用于存储变量值的缓冲区

	pthread_mutex_lock(&mtx);
    // 打印变量值
	
    if (strcmp(variableName, "frontindex") == 0) {
        sprintf(buffer, "frontindex = %d", g_front_seg_index);  // 将 int 转换为字符串
        clientSocket->write(buffer);  // 发送字符串到客户端
    }
	else if (strcmp(variableName, "remtable") == 0) {
        sprintf(buffer, "remtable = %d",g_pt61850app->chnl_counts);
        clientSocket->write(buffer);
    } 
	else if (strcmp(variableName, "iedcount") == 0) {
        sprintf(buffer, "g_node->n_clients = %d, ied config count = %d",g_node->n_clients ,IED_COUNT);
        clientSocket->write(buffer);
    } else if (strcmp(variableName, "frontfun") == 0) {
        sprintf(buffer, "frontfun = %s", subdir);
        clientSocket->write(buffer);
    } else {
        clientSocket->write("Unknown variable name\n> ");
    }
	pthread_mutex_unlock(&mtx);
    clientSocket->flush();
}

//////////////////////////////////////////////////////////////////////////////////////////////////
// 解析 JSON 的函数  多前置动态均分
int terminal_ledger_web(QMap<QString, terminal_dev*>* terminal_dev_map,
                        const std::vector<std::string>& codes,
                        int index,
                        int num)
{
	//后续修改为根据index来获取对应的台账，num就没有作用了，index用来均分的也没有作用了
	if(1 == MULTIPLE_NODE_FLAG){
		// 参数验证
    	if (num <= 0) {
    	    std::cerr << "Error: 'num' must be greater than 0." << std::endl;
    	    return 1; // 返回适当的错误码
    	}

		index = index - 1;
    	if (index < 0 || index >= num) {
    	    std::cerr << "Error: 'index' must be in the range [0, num-1]." << std::endl;
    	    return 1; // 返回适当的错误码
    	}
	}    

    // 获取参数
    if (codes.empty()) {
        std::cerr << "Error: 'codes' vector is empty." << std::endl;
        return 1;
    }

    std::string parm = codes[0];

    char* ptr = NULL;

    // 发送 API 请求
    SendJsonAPI_web(WEB_DEVICE, "",parm.c_str(), &ptr);

    if (ptr == NULL) {
        std::cerr << "Error: Received NULL response from SendJsonAPI_web." << std::endl;
        return 1;
    }

    // 调试用
    printf("ptr:%s\n", ptr);

    cJSON* root = cJSON_Parse(ptr);   //json格式序列化

	int retry = 0;

	if (root == NULL) {
		printf("web error %s\n", cJSON_GetErrorPtr());

		//重发多次
		while(root == NULL){
			// 在重试前释放之前的 ptr 以避免内存泄漏
            if (ptr != NULL) {
                free(ptr);
                ptr = NULL;
            }
			//测试用url参数
			//SendJsonAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", parm.c_str(), "",&ptr);
			SendJsonAPI_web(WEB_DEVICE, "",parm.c_str(), &ptr);

			if(ptr == NULL){
				retry++;if(retry>3)break;
				continue;
			}

			root = cJSON_Parse(ptr);
			retry++;if(retry>3)break;
		}
		// 如果重试后仍然失败，确保退出前释放任何已分配的内存
        if (root == NULL) {
			printf("web error %s\n", cJSON_GetErrorPtr());
            return 1; // 根据需要返回适当的错误码
        }
	}

    // 获取 "code" 和 "msg"
    cJSON* codeItem = cJSON_GetObjectItem(root, "code");
    cJSON* msgItem = cJSON_GetObjectItem(root, "msg");

    // 使用 std::string 获取值
    std::string code = (codeItem != NULL && codeItem->type == cJSON_String) ? codeItem->valuestring : "not found";
    std::string msg = (msgItem != NULL && msgItem->type == cJSON_String) ? msgItem->valuestring : "not found";

    // 打印结果
    std::cout << "code: " << code << std::endl;
    std::cout << "msg: " << msg << std::endl;

    // 获取 "data" 数组
    cJSON* data = cJSON_GetObjectItem(root, "data");
    if (!data || data->type != cJSON_Array) {
        std::cerr << "Error: 'data' is not an array." << std::endl;
        cJSON_Delete(root);
        free(ptr);
        return 1;
    }

    int data_size = cJSON_GetArraySize(data);

	std::cout << "data_size " << data_size << std::endl;

    if (data_size == 0) {
        std::cerr << "Error: 'data' array is empty." << std::endl;
        cJSON_Delete(root);
        free(ptr);
        return 1;
    }

	//后续修改为根据index来获取对应的台账，将不再均分，获取所有台账并判断进程号
#if 0
	int base_size = 0;
	int remainder = 0;
	int start_index = 0;
	int end_index = data_size;

	if(1 == MULTIPLE_NODE_FLAG){
		// 计算每份的大小
    	base_size = data_size / num;
    	remainder = data_size % num;

    	// 计算当前份的起始和结束索引
    	start_index = index * base_size + (index < remainder ? index : remainder);
    	end_index = start_index + base_size + (index < remainder ? 1 : 0);

    	// 确保结束索引不超过数组大小
    	if (end_index > data_size) {
    	    end_index = data_size;
    	}
	}
#endif
	int start_index = 0;
	int end_index = data_size;

    // 遍历指定范围内的元素
    for (int i = start_index; i < end_index; ++i) {
        cJSON* item = cJSON_GetArrayItem(data, i);
        if (!item || item->type != cJSON_Object) {
            std::cerr << "Warning: Invalid item at index " << i << "." << std::endl;
            continue; // 跳过无效的项
        }

        terminal_dev* dev = new terminal_dev();
        memset(dev, 0, sizeof(terminal_dev)); // 初始化结构体

        // 解析各个字段
        cJSON* id = cJSON_GetObjectItem(item, "id"); // terminal_id
        if (id && id->type == cJSON_String) strncpy(dev->terminal_id, id->valuestring, sizeof(dev->terminal_id) - 1);
        else strncpy(dev->terminal_id, "N/A", sizeof(dev->terminal_id) - 1);

        cJSON* ip = cJSON_GetObjectItem(item, "ip"); // addr_str
        if (ip && ip->type == cJSON_String) strncpy(dev->addr_str, ip->valuestring, sizeof(dev->addr_str) - 1);
        else strncpy(dev->addr_str, "N/A", sizeof(dev->addr_str) - 1);

        cJSON* terminalCode = cJSON_GetObjectItem(item, "name"); // terminal_code
        if (terminalCode && terminalCode->type == cJSON_String) strncpy(dev->terminal_code, terminalCode->valuestring, sizeof(dev->terminal_code) - 1);
        else strncpy(dev->terminal_code, "N/A", sizeof(dev->terminal_code) - 1);

        cJSON* orgName = cJSON_GetObjectItem(item, "org_name"); // org_name
        if (orgName && orgName->type == cJSON_String) strncpy(dev->org_name, orgName->valuestring, sizeof(dev->org_name) - 1);
        else strncpy(dev->org_name, "N/A", sizeof(dev->org_name) - 1);

        cJSON* maintName = cJSON_GetObjectItem(item, "maint_name"); // maint_name
        if (maintName && maintName->type == cJSON_String) strncpy(dev->maint_name, maintName->valuestring, sizeof(dev->maint_name) - 1);
        else strncpy(dev->maint_name, "N/A", sizeof(dev->maint_name) - 1);

        cJSON* stationName = cJSON_GetObjectItem(item, "stationName"); // station_name
        if (stationName && stationName->type == cJSON_String) strncpy(dev->station_name, stationName->valuestring, sizeof(dev->station_name) - 1);
        else strncpy(dev->station_name, "N/A", sizeof(dev->station_name) - 1);

        cJSON* manufacturer = cJSON_GetObjectItem(item, "manufacturer"); // tmnl_factory
        if (manufacturer && manufacturer->type == cJSON_String) strncpy(dev->tmnl_factory, manufacturer->valuestring, sizeof(dev->tmnl_factory) - 1);
        else strncpy(dev->tmnl_factory, "N/A", sizeof(dev->tmnl_factory) - 1);

        cJSON* status = cJSON_GetObjectItem(item, "status"); // tmnl_status
        if (status && status->type == cJSON_String) strncpy(dev->tmnl_status, status->valuestring, sizeof(dev->tmnl_status) - 1);
        else strncpy(dev->tmnl_status, "N/A", sizeof(dev->tmnl_status) - 1);

        cJSON* devType = cJSON_GetObjectItem(item, "devType"); // dev_type
        if (devType && devType->type == cJSON_String) strncpy(dev->dev_type, devType->valuestring, sizeof(dev->dev_type) - 1);
        else strncpy(dev->dev_type, "N/A", sizeof(dev->dev_type) - 1);

        cJSON* devKey = cJSON_GetObjectItem(item, "devKey"); // dev_key
        if (devKey && devKey->type == cJSON_String) strncpy(dev->dev_key, devKey->valuestring, sizeof(dev->dev_key) - 1);
        else strncpy(dev->dev_key, "N/A", sizeof(dev->dev_key) - 1);

        cJSON* series = cJSON_GetObjectItem(item, "series"); // dev_series
        if (series && series->type == cJSON_String) strncpy(dev->dev_series, series->valuestring, sizeof(dev->dev_series) - 1);
        else strncpy(dev->dev_series, "N/A", sizeof(dev->dev_series) - 1);

		//lnk20250210台账进程号
		cJSON* processNo = cJSON_GetObjectItem(item, "processNo"); // processNo转为字符串
        if (processNo && processNo->type == cJSON_Number) snprintf(dev->processNo, sizeof(dev->processNo), "%d", processNo->valueint);
        else strncpy(dev->processNo, "N/A", sizeof(dev->processNo) - 1);

        cJSON* port = cJSON_GetObjectItem(item, "port"); // port
        if (port && port->type == cJSON_String) strncpy(dev->port, port->valuestring, sizeof(dev->port) - 1);
        else strncpy(dev->port, "N/A", sizeof(dev->port) - 1);

        cJSON* updateTime = cJSON_GetObjectItem(item, "updateTime"); // timestamp
        if (updateTime && updateTime->type == cJSON_String) strncpy(dev->timestamp, updateTime->valuestring, sizeof(dev->timestamp) - 1);
        else strncpy(dev->timestamp, "N/A", sizeof(dev->timestamp) - 1);

        // 解析 monitorData 数组
        cJSON* monitorData = cJSON_GetObjectItem(item, "monitorData");
        if (monitorData && monitorData->type == cJSON_Array) {
            int j = 0;
            cJSON* monitorItem;
            cJSON_ArrayForEach(monitorItem, monitorData) {
                if (j >= 10){
                    std::cout << "一个终端最多只能有十个监测点" << std::endl;
                    break;  // 限制为最多10个
                }

                cJSON* monitor_id = cJSON_GetObjectItem(monitorItem, "id"); // monitor_id
                if (monitor_id && monitor_id->type == cJSON_String) strncpy(dev->line[j].monitor_id, monitor_id->valuestring, sizeof(dev->line[j].monitor_id) - 1);
                else strncpy(dev->line[j].monitor_id, "N/A", sizeof(dev->line[j].monitor_id) - 1);

                cJSON* monitor_name = cJSON_GetObjectItem(monitorItem, "name"); // monitor_name
                if (monitor_name && monitor_name->type == cJSON_String) strncpy(dev->line[j].monitor_name, monitor_name->valuestring, sizeof(dev->line[j].monitor_name) - 1);
                else strncpy(dev->line[j].monitor_name, "N/A", sizeof(dev->line[j].monitor_name) - 1);

                cJSON* lineNo = cJSON_GetObjectItem(monitorItem, "lineNo"); // logical_device_seq
                if (lineNo && lineNo->type == cJSON_String) strncpy(dev->line[j].logical_device_seq, lineNo->valuestring, sizeof(dev->line[j].logical_device_seq) - 1);
                else strncpy(dev->line[j].logical_device_seq, "N/A", sizeof(dev->line[j].logical_device_seq) - 1);

                cJSON* voltageLevel = cJSON_GetObjectItem(monitorItem, "voltageLevel"); // voltage_level
                if (voltageLevel && voltageLevel->type == cJSON_String) strncpy(dev->line[j].voltage_level, voltageLevel->valuestring, sizeof(dev->line[j].voltage_level) - 1);
                else strncpy(dev->line[j].voltage_level, "N/A", sizeof(dev->line[j].voltage_level) - 1);

                cJSON* ptType = cJSON_GetObjectItem(monitorItem, "ptType"); // terminal_connect
                if (ptType && ptType->type == cJSON_String) strncpy(dev->line[j].terminal_connect, ptType->valuestring, sizeof(dev->line[j].terminal_connect) - 1);
                else strncpy(dev->line[j].terminal_connect, "N/A", sizeof(dev->line[j].terminal_connect) - 1);

                // 添加监测点状态
                cJSON* monitorstatus = cJSON_GetObjectItem(monitorItem, "status"); // status
                if (monitorstatus && monitorstatus->type == cJSON_String) strncpy(dev->line[j].status, monitorstatus->valuestring, sizeof(dev->line[j].status) - 1);
                else strncpy(dev->line[j].status, "N/A", sizeof(dev->line[j].status) - 1);

                j++;
            }
        }

        // 准备键
    	QString key = QString(dev->terminal_id);//用id而不是code区分：有的code存在乱码

    	// 检查是否存在重复键
    	if (terminal_dev_map->contains(key)) {
        	std::cerr << "Duplicate terminal_code found: " << key.toStdString() << std::endl;

        	// 删除旧的 terminal_dev 对象以避免内存泄漏
        	delete terminal_dev_map->value(key);

        	// 移除旧的键值对
        	terminal_dev_map->remove(key);

        	// 插入新的 terminal_dev 对象
			if(atoi(dev->processNo) == g_front_seg_index || g_front_seg_index == 0){//lnk20250210匹配进程号
				//调试用
				std::cout<< "process num match" << std::endl;
        		terminal_dev_map->insert(key, dev);}//后续修改为只有进程号匹配上index才录入当前进程
    	} else {
        	// 插入新的 terminal_dev 对象
			if(atoi(dev->processNo) == g_front_seg_index ||  g_front_seg_index == 0){//lnk20250210匹配进程号
				//调试用
				std::cout<< "process num match" << std::endl;
        		terminal_dev_map->insert(key, dev);}//后续修改为只有进程号匹配上index才录入当前进程
			//调试用
			//std::cout << "i =  " << i << std::endl;
			//std::cout << "terminal_dev_map.size:" << terminal_dev_map->size() << std::endl;
    	}//如果出现重复项，日志要有体现方便排查

		
    }

    // 释放资源
    cJSON_Delete(root);
    free(ptr);

    return 0; // 确保函数有返回值
}

int parse_device_cfg_web()
{
	std::cout << "parse_device_cfg_web" << endl;

	std::vector<std::string> codes;	//入参集合

/*//多前置判断
	if (FRONT_INST == 0 || FRONT_IP[0] == '\0') {
		MULTIPLE_NODE_FLAG = 0;
		cout << "set MULTIPLE_NODE_FLAG:0,because do not have FRONT_INST or FRONT_IP" << endl;
	}
	char front_type[2] = {""};
	int mp_num = 0;
//用web接口替换前置表的读写，接口中解析结果，存入容器，从接口直接取出容器，从容器中获取需要的值，写入时直接传参：
	if (MULTIPLE_NODE_FLAG) {
//前置表读取部分替换
		QMap<QString, front_list*> front_map;
		codes.push_back("info");
		parse_device_web_test_front_read(&front_map,codes);
		codes.clear();
		// 遍历 QMap 容器
		QMap<QString, front_list*>::iterator it;
    	for (it = front_map.begin(); it != front_map.end(); ++it) {
        	front_list* value = it.value();
        	// 确保 value 不为空
        	if (it.key() == "0.0.0.0" && value != nullptr) {
            	// 从 value 中读取 front_type，保留前两个字符
            	strncpy(front_type, value->front_type, 2);
            	front_type[2] = '\0';  // 确保以空字符结尾
            	// 将 mp_num 从字符串转换为整数
            	mp_num = std::atoi(value->mp_num);
			}
		}
//前置表读取部分
//前置表写入部分
		codes.push_back("insertfront");
		codes.push_back(std::string(FRONT_IP));
		codes.push_back(intToString(FRONT_INST));
		codes.push_back(std::string(front_type));
		codes.push_back(std::string(PROGRAM_VERSION));
		codes.push_back("01");		//添加状态值
		parse_device_web_test_front_write(codes);
		codes.clear();
//前置表写入部分
	}
	cout << "mp_num:" << mp_num << " front_type:" << front_type << endl;*/
//当前前置不需要多前置，前置从配置文件（mykafka.ini）获取到ip后，将ip作为参数传送给web接口获取台账

	ied_t* ied;
	ied_usr_t* ied_usr;
	chnl_usr_t* chnl_usr;
	int count_cfg = 0;	//终端台账总数
	int count_real = 0;	//遍历终端台账的计数器

/////////////////////////////////////////////////////////////////////////////////
/*//读取终端ext表替换为web接口
	QMap<QString, terminal_ext*> terminal_ext_map;
	//read_terminal_ext_pg(&terminal_ext_map);
	codes.push_back("info");
	parse_device_web_test_ext(&terminal_ext_map,codes);
	codes.clear();
//读取终端ext表替换为web接口

//读取终端台账表总数替换为web接口
		
	QMap<QString, terminal_dev*> terminal_dev_map;
	
	codes.push_back("count_cfg");

	parse_device_web_test_dev(&terminal_dev_map,codes);

	// 遍历 QMap 容器
	QMap<QString, terminal_dev*>::iterator it;
    for (it = terminal_dev_map.begin(); it != terminal_dev_map.end(); ++it) {
    	terminal_dev* value = it.value();
    	// 确保 value 不为空
    	if (it.key() == "count_cfg" && value != nullptr) {
        	// 将 count 从字符串转换为整数
        	count_cfg = std::atoi(value->count_cfg);
		}
		//调试用
		cout << "count_cfg:" << count_cfg << " value->count_cfg:" << value->count_cfg << endl;
	}

	codes.clear();

	//取完count——cfg要将容器清0否则影响取台账逻辑
	terminal_dev_map.clear();

//读取终端台账表总数替换为web接口

//读取终端台账表替换为web接口

	codes.push_back("info");
	codes.push_back(intToString(FRONT_INST));
	codes.push_back(intToString(mp_num));
	codes.push_back(intToString(count_cfg));
	codes.push_back(intToString(MULTIPLE_NODE_FLAG));
	codes.push_back(intToString(g_front_seg_num));

	parse_device_web_test_dev(&terminal_dev_map,codes);

	codes.clear();

	if (MULTIPLE_NODE_FLAG && g_front_seg_num == 0) {
		if (mp_num * FRONT_INST > count_cfg) {
			count_cfg = count_cfg - (FRONT_INST - 1) * mp_num;
		}
		else
		{
			count_cfg = mp_num;
		}
	}
	else if (MULTIPLE_NODE_FLAG && g_front_seg_num != 0) {
		int front_num = (count_cfg / g_front_seg_num) + 1;
		if (front_num * FRONT_INST > count_cfg) {
			count_cfg = count_cfg - (FRONT_INST - 1) * front_num;
		}
		else
		{
			count_cfg = front_num;
		}
	}*/
////////////////////////////////////////////////////////////////////////////////
	//接口合并，只用一个web接口获取终端台账和监测点台账
	QMap<QString, terminal_dev*> terminal_dev_map;	

//////////////////////////////////////////////////////////////////////////////
	//测试用
	//codes.push_back("code1=ledger"); //填FRONT_IP和状态（可不填）

	//构造入参json
	std::string input_jstr = "{";
	input_jstr += "\"ip\":\"" + std::string(FRONT_IP) + "\",";
	input_jstr += "\"runFlag\":" + TERMINAL_STATUS + "";
	input_jstr += "}";

	std::cout << "input_jstr: " << input_jstr << std::endl; // 输出结果

	codes.push_back(input_jstr);	//是否需要筛选状态直接在配置文件控制
///////////////////////////////////////////////////////////////////////////////

	terminal_ledger_web(&terminal_dev_map,codes,g_front_seg_index,g_front_seg_num);
	codes.clear();

	//调试用
	//printTerminalDevMap(terminal_dev_map);

	count_cfg = terminal_dev_map.size();//容器的数量就是台账的数量

	std::cout << "terminal_ledger_num:" << count_cfg << std::endl;

	g_node->n_clients = count_cfg;
	//这里开辟的ied的空间由配置文件中的终端台账数量决定lnk20250121
	g_node->clients = (ied_t**)apr_pcalloc(g_cfg_pool, IED_COUNT * sizeof(ied_t*));//g_node->clients 这块大内存空间存储了 count_cfg 个 ied_t* 类型的指针（即一个指针数组）这是（指向内存块的指针）的指针数组
	//把ied放入数组
	
	for (int k = 0; k < count_cfg; k++){

		//调试用
		std::cout << "!!!!!!!!!!gnodeindex:" << k  << std::endl;

		g_node->clients[k] = (ied_t*)apr_pcalloc(g_cfg_pool, sizeof(ied_t));}//每个 g_node->clients[k] 指向的内存块是独立的（每个 ied_t 结构体占用的内存块）这是指向内存块的指针

//读取终端台账表替换为web接口
//////////////////////////////////////////////////////////////////////////////////////////////////
	//读数据
	try {
		char terminal_id[64];
		char terminal_code[64];
		char org_name[64];
		char maint_name[64];
		char station_name[64];
		char tmnl_factory[64];
		char tmnl_status[64];
		char dev_type[64];
		char dev_key[255];
		char dev_series[255];
		char addr_str[64];
		char port_char[64];

		//lnk20250210添加进程号
		char processNo[64];

		otl_datetime timestamp;

		// 遍历终端台账容器
		QMap<QString, terminal_dev*>::iterator it;
    	for (it = terminal_dev_map.begin(); it != terminal_dev_map.end(); ++it) {
    		terminal_dev* value = it.value();

			// 确保 value 不为空
    		if (value != nullptr) {
        		// 找到容器中对应名称并取值
        		strncpy(terminal_id, value->terminal_id, sizeof(terminal_id) - 1);
        		strncpy(terminal_code, value->terminal_code, sizeof(terminal_code) - 1);
        		strncpy(org_name, value->org_name, sizeof(org_name) - 1);
        		strncpy(maint_name, value->maint_name, sizeof(maint_name) - 1);
        		strncpy(station_name, value->station_name, sizeof(station_name) - 1);
        		strncpy(tmnl_factory, value->tmnl_factory, sizeof(tmnl_factory) - 1);
        		strncpy(tmnl_status, value->tmnl_status, sizeof(tmnl_status) - 1);
        		strncpy(dev_type, value->dev_type, sizeof(dev_type) - 1);
        		strncpy(dev_key, value->dev_key, sizeof(dev_key) - 1);
        		strncpy(dev_series, value->dev_series, sizeof(dev_series) - 1);
        		strncpy(addr_str, value->addr_str, sizeof(addr_str) - 1);
        		strncpy(port_char, value->port, sizeof(port_char) - 1);
				strncpy(processNo, value->processNo, sizeof(processNo) - 1);//进程号
				timestamp = parseTimestamp(value->timestamp);

				//处理终端台账
				ied = g_node->clients[count_real++];
				//这里申请的空间基于ied的数量，挂载到ied上
				ied_usr = (ied_usr_t*)apr_pcalloc(g_init_pool, sizeof(ied_usr_t));//终端台账在initpool中申请空间
				ied->usr_ext = ied_usr;

				if (ied_usr == NULL)
					return APR_ENOMEM;

				ied_usr->last_call_wavelist_time = sGetMsTime() + g_pt61850app->giTime * 1000;
				//这里申请的空间基于ied的数量，挂载到ied上
				ied_usr->LD_info = (LD_info_t*)apr_pcalloc(g_init_pool, MAX_CPUNO * sizeof(LD_info_t));//监测点台账在initpool中申请空间

				if (ied_usr->LD_info == NULL)
					return APR_ENOMEM;

				ied_usr->dev_flag = ENABLE;//终端有效
				ied->chncount = 1;//设备通信端口总数
				//这里申请的空间基于ied的数量，挂载到ied上
				ied->channel = (channel_t*)apr_pcalloc(g_cfg_pool, sizeof(channel_t) * ied->chncount);//通信结构在g_cfg_pool中申请空间：终端的ip端口等
				ied->channel[0].ied = ied;
				ied->channel[0].status = STATUS_BREAKOFF;
				ied->cpucount = 0;

				if (strlen(terminal_id) != 0) {
					apr_snprintf(ied_usr->terminal_id, sizeof(ied_usr->terminal_id), "%s", terminal_id);//terminal_id
					cout << "ied_usr->terminal_id:" << ied_usr->terminal_id << endl;
				}
				if (terminal_code != NULL) {
					apr_snprintf(ied_usr->terminal_code, sizeof(ied_usr->terminal_code), "%s", terminal_code);//terminal_code
					cout << "ied_usr->terminal_code:" << ied_usr->terminal_code << endl;
				}
	/*不需要这三个信息			
				if (org_name != NULL) {
					apr_snprintf(ied_usr->org_name, sizeof(ied_usr->org_name), "%s", org_name);//org_name
					cout << "ied_usr->org_name:" << ied_usr->org_name << endl;

				}
				if (maint_name != NULL) {
					apr_snprintf(ied_usr->maint_name, sizeof(ied_usr->maint_name), "%s", maint_name);//maint_name
					cout << "ied_usr->maint_name:" << ied_usr->maint_name << endl;

				}
				if (station_name != NULL) {
					apr_snprintf(ied_usr->station_name, sizeof(ied_usr->station_name), "%s", station_name);//station_name
					cout << "ied_usr->station_name:" << ied_usr->station_name << endl;
				}
				*/
				if (tmnl_factory != NULL) {
					apr_snprintf(ied_usr->tmnl_factory, sizeof(ied_usr->tmnl_factory), "%s", tmnl_factory);//tmnl_factory
					cout << "ied_usr->tmnl_factory:" << ied_usr->tmnl_factory << endl;
				}
				if (tmnl_status != NULL) {
					apr_snprintf(ied_usr->tmnl_status, sizeof(ied_usr->tmnl_status), "%s", tmnl_status);//tmnl_status
					cout << "ied_usr->tmnl_status:" << ied_usr->tmnl_status << endl;
				}
				if (dev_type != NULL) {
					apr_snprintf(ied_usr->dev_type, sizeof(ied_usr->dev_type), "%s", dev_type);//dev_type
					cout << "ied_usr->dev_type:" << ied_usr->dev_type << endl;
				}

				//lnk20250210台账进程号
				if (processNo != NULL) {
					apr_snprintf(ied_usr->processNo, sizeof(ied_usr->processNo), "%s", processNo);//processNo
					cout << "ied_usr->processNo:" << ied_usr->processNo << endl;
				}

				if (dev_series != NULL) {
					apr_snprintf(ied_usr->dev_series, sizeof(ied_usr->dev_series), "%s", dev_series);//DEV_Series
					cout << "defalut dev_series:" << ied_usr->dev_series << endl;
				}
				else
				{
					apr_snprintf(ied_usr->dev_series, sizeof(ied_usr->dev_series), "%s", "");//DEV_Series
					cout << "defalut dev_series:" << ied_usr->dev_series << endl;
				}
				if (dev_key != NULL) {
					apr_snprintf(ied_usr->dev_key, sizeof(ied_usr->dev_key), "%s", dev_key);//DEV_Key
					cout << "defalut dev_key:" << ied_usr->dev_key << endl;
				}
				else
				{
					apr_snprintf(ied_usr->dev_key, sizeof(ied_usr->dev_key), "%s", "");//DEV_Key
					cout << "defalut dev_key:" << ied_usr->dev_key << endl;
				}

				//lnk20241125实时数据用
				ied_usr->dev_idx = count_real;
				cout << "dev_idx:" << ied_usr->dev_idx << endl;

				ied->channel[0].channel_type = CHANNEL_TYPE_IPV4;//channel
				ied->channel[0].addr_str[LONGNAME - 1] = 0;//DEV_IP
				if (addr_str != NULL) {
					ied->channel[0].addr = ntohl(inet_addr(addr_str));//DEV_IP
					strncpy(ied->channel[0].addr_str, addr_str, LONGNAME - 1);//DEV_IP
					cout << "ied_usr->addr_str:" << ied->channel[0].addr_str << endl;
				}
				else
				{
					ied->channel[0].addr = ntohl(inet_addr("0.0.0.0"));//DEV_IP
					strncpy(ied->channel[0].addr_str, addr_str, LONGNAME - 1);//DEV_IP
					cout << "ied_usr->addr_str:" << ied->channel[0].addr_str << endl;
				}
				if (port_char != NULL) {
					int port = 102;
					if (stringToInt(port_char, &port)) {
						// 转换成功，portStr全为数字，并且已经转换为int类型的port  
						ied->channel[0].port = port;//DEV_PortID
						cout << "ied_usr->port:" << ied->channel[0].port << endl;//DEV_PortID
					}
					else {
						ied->channel[0].port = 102;//DEV_PortID
						cout << "ied_usr->port:" << port_char << ",非合法端口.使用默认端口:" << ied->channel[0].port << endl;//DEV_PortID
					}
				}
				if (timestamp.year != 0) {
					//// 构造struct tm对象
					struct tm timeinfo;
					timeinfo.tm_year = timestamp.year - 1900; // 年份需要减去1900
					timeinfo.tm_mon = timestamp.month - 1; // 月份需要减去1
					timeinfo.tm_mday = timestamp.day;
					timeinfo.tm_hour = timestamp.hour;
					timeinfo.tm_min = timestamp.minute;
					timeinfo.tm_sec = timestamp.second;
					time_t time = std::mktime(&timeinfo);
					ied_usr->time = static_cast<long long>(time);
					cout << "ied_usr->time:" << ied_usr->time << endl;
				}

				//这里申请的空间基于ied的数量，挂载到ied上
				chnl_usr = (chnl_usr_t*)apr_pcalloc(g_init_pool, sizeof(chnl_usr_t));//拓展定义的通信结构在g_init_pool中申请空间：拓展记录一些开关时间信息
				ied->channel[0].connect = chnl_usr;
				chnl_usr->chnl = &(ied->channel[0]);
				chnl_usr->chnl_id = 0;
				chnl_usr->m_state = CHANNEL_DISCONNECTED;
				chnl_usr->m_ClosedMsTime = NEXT_CONNECT_TIME * (-1);
				g_pt61850app->chnl_counts++;

				//调试用
				//std::cout << "value:" << terminal_id <<"  "<<terminal_code <<"  "<<tmnl_factory <<"  "<<dev_series <<"  "<<dev_key <<"  "<< tmnl_status <<"  "<<dev_type <<"  "<<addr_str <<"  "<<port_char <<"  "<< timestamp.year << std::endl;

				// 遍历监测点信息
				LD_info_t line_info;
				int count_real_monitor = 0;	//遍历监测点台账的计数器

				//调试用
				//std::cout << "n_clients:" << g_node->n_clients << std::endl;

				if (g_node->n_clients <= 0) {
					std::cout << "no terminal exist " << std::endl;
					return APR_EBADF;
				}

				char monitor_id[64];
				//char terminal_code[64];
				char monitor_name[64];
				char logical_device_seq[64];
				char voltage_level[64];
				char terminal_connect[64];
				char monitor_status[64];
				//otl_datetime timestamp;

            	//for (int j = 0; j < 10; ++j) { // 假设最多有10个监测点
				for (int j = 0; value->line[j].monitor_id[0] != '\0'; ++j){
                	ledger_monitor& monitor = value->line[j];

                	// 检查监测点 ID 是否为空以避免访问无效数据
                	/*if (monitor.monitor_id[0] != '\0') { 
                	    std::cout << "  Monitor ID: " << monitor.monitor_id << std::endl;
                	    std::cout << "  Terminal Code: " << monitor.terminal_code << std::endl;		//应该为空，json不带
                	    std::cout << "  Monitor Name: " << monitor.monitor_name << std::endl;
                	    std::cout << "  Logical Device Seq: " << monitor.logical_device_seq << std::endl;
                	    std::cout << "  Voltage Level: " << monitor.voltage_level << std::endl;
                	    std::cout << "  Terminal Connect: " << monitor.terminal_connect << std::endl;
                	    std::cout << "  Timestamp: " << monitor.timestamp << std::endl;				//应该为空json不带
						std::cout << "  monitor_status: " << monitor.status << std::endl;*/

						strncpy(monitor_id, monitor.monitor_id, sizeof(monitor_id) - 1);
        				//strncpy(terminal_code, monitor.terminal_code, sizeof(terminal_code) - 1);	//从上级获取
        				strncpy(monitor_name, monitor.monitor_name, sizeof(monitor_name) - 1);
        				strncpy(logical_device_seq, monitor.logical_device_seq, sizeof(logical_device_seq) - 1);
        				strncpy(voltage_level, monitor.voltage_level, sizeof(voltage_level) - 1);
        				strncpy(terminal_connect, monitor.terminal_connect, sizeof(terminal_connect) - 1);
						//timestamp = parseTimestamp(monitor.timestamp);								//从上级获取
						strncpy(monitor_status, monitor.status, sizeof(monitor_status) - 1);//添加监测点状态
						//监测点台账处理
						count_real_monitor++;

						memset(&line_info, 0, sizeof(line_info));

						line_info.line_id = count_real_monitor;			//监测点排号
						cout << "line_id:" << line_info.line_id << endl;

						strcpy(line_info.mp_id, monitor_id);
						cout << "mp_id:" << line_info.mp_id << endl;

						strcpy(line_info.terminal_code, terminal_code);					//从上级获取的终端号
						cout << "terminal_code:" << line_info.terminal_code << endl;

						if (isCharPtrEmpty(logical_device_seq)) {
							line_info.cpuno = 1;										//默认监测点实例号1
							cout << "logical_device_seq:is null,set cpuno:"<< line_info.cpuno << endl;
						}
						else {
							line_info.cpuno = std::atoi(logical_device_seq);
							cout << "logical_device_seq:"<< line_info.cpuno << endl;
						}
						//cout << "cpuno:" << line_info.cpuno << endl;

						strcpy(line_info.voltage_level, voltage_level);
						cout << "voltage_level:" << line_info.voltage_level << endl;

						strcpy(line_info.v_wiring_type, terminal_connect);
						cout << "v_wiring_type:" << line_info.v_wiring_type << endl;

						//lnk2024-8-14记录接线标志
						if (strcmp(line_info.v_wiring_type, "02") == 0)
						{
							isdelta_flag = 1;	//存在一个监测点为角型接线则这个前置就要启动第二个配置列表
							cout << "monitor_id" << monitor_id << "v_wiring_type:" << line_info.v_wiring_type << "is delta wiring:" << isdelta_flag << endl;
						}

						strcpy(line_info.monitor_status, monitor_status);
						cout << "monitor_status:" << line_info.monitor_status << endl;

						//// 构造struct tm对象
						struct tm timeinfo;
						timeinfo.tm_year = timestamp.year - 1900; // 年份需要减去1900		//从上级获取的timestamp
						timeinfo.tm_mon = timestamp.month - 1; // 月份需要减去1
						timeinfo.tm_mday = timestamp.day;
						timeinfo.tm_hour = timestamp.hour;
						timeinfo.tm_min = timestamp.minute;
						timeinfo.tm_sec = timestamp.second;

						time_t time = std::mktime(&timeinfo);
						line_info.time = static_cast<long long>(time);
						cout << "time:" << line_info.time << endl;

						strcpy(line_info.name, monitor_name);
						cout << "name:" << line_info.name << endl;

						line_info.read_flag = ENABLE;				//监测点有效

						//ied = find_ied_from_dev_code(line_info.terminal_code); //不需要再找上级终端了，已经在终端里了

						if (ied && ied->usr_ext && line_info.cpuno && (static_cast<int>(line_info.cpuno) < 10)) {
							char str[256];			//256大小
							byte_t cpuno = line_info.cpuno;

							cout << "cpuno:" << (int)line_info.cpuno << endl;
							cout << "index cpuno:" << cpuno-1 << endl;

							ied_usr = (ied_usr_t*)ied->usr_ext;
							ied_usr->LD_info[cpuno - 1] = line_info;   //cpuno默认是1
							ied_usr->LD_info[cpuno - 1].ied = ied;
							apr_snprintf(str, sizeof(str), "PQMonitorPQM%d", cpuno);//将监测点逻辑号转为PQMonitorPQM+逻辑号

							//lnk20250208不使用apr_pstrdup，后续直接复用
							//ied_usr->LD_info[cpuno - 1].LD_name = apr_pstrdup(g_init_pool, str);//将 str 中的格式化字符串复制到内存池 g_init_pool 中。ied_usr->LD_info[cpuno - 1].LD_name 存储了这个字符串的副本，LD_name 现在是 PQMonitorPQM{cpuno} 的形式。
							// 从 g_init_pool 内存池中分配固定 256 字节的内存
							ied_usr->LD_info[cpuno - 1].LD_name = (char *)apr_palloc(g_init_pool, 256);

							// 清空内存，防止残留数据
							memset(ied_usr->LD_info[cpuno - 1].LD_name, 0, 256);

							// 将 str 中的内容复制到预先分配的内存中，最多复制 256 字节（包含结束符）
							apr_cpystrn(ied_usr->LD_info[cpuno - 1].LD_name, str, 256);
							
							//这里申请的空间基于ied的数量，挂载到ied上
							ied_usr->LD_info[cpuno - 1].ht_fcd = apr_hash_make(g_init_pool);	//这两行代码分别为 ied_usr->LD_info[cpuno - 1] 的两个成员（ht_fcd 和 ht_full_fcda）创建了空的哈希表。apr_hash_make(g_init_pool) 会在 g_init_pool 内存池中为这两个哈希表分配内存空间
							ied_usr->LD_info[cpuno - 1].ht_full_fcda = apr_hash_make(g_init_pool);//它们的 key 值和 value 在后续的代码中可能会被填充
							ied_usr->LD_info[cpuno - 1].rptcount = 0;
							cout << "rptcount:" << ied_usr->LD_info[cpuno - 1].rptcount << endl;

							if (cpuno > ied->cpucount) {
								ied->cpucount = cpuno;
							}
						}						
                	//}					
            	}
    		}
		}
//////////////////////////////////////////////////////////////////////////////////////////////////		

		if (count_real < count_cfg)
			g_node->n_clients = count_real;
		if (count_cfg != count_real)
			return APR_EBADF;
		cout << "dev init create count:" << count_real;
		return APR_SUCCESS;
	}
	catch (otl_exception& e)
	{
		printf("\ndev tr\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg);
		return e.code;
	}
}

int parse_model_web(QMap<QString, icd_model*>* icd_model_map,const std::vector<std::string>& codes)
{
	std::string parm = codes[0];	//装置型号列表，格式["型号1","型号2"...]

	char* ptr=NULL;

	//测试用url参数
	//SendJsonAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", parm.c_str(), "",&ptr);
	SendJsonAPI_web(WEB_ICD,"",parm.c_str(),&ptr);

	// 检查 ptr 是否为 NULL，避免 std::string 初始化失败
	if (ptr == NULL) {
		// 处理 ptr 为 NULL 的情况，例如日志记录或错误处理
	    std::cout << "Error: Received NULL response"<< std::endl;
		return 1;
	}

	//调试用
	printf("ptr:%s\n",ptr);

	cJSON* root = cJSON_Parse(ptr);   //json格式序列化

	int retry = 0;

	if (root == NULL) {
		printf("web error %s\n", cJSON_GetErrorPtr());

		//重发多次
		while(root == NULL){
			// 在重试前释放之前的 ptr 以避免内存泄漏
            if (ptr != NULL) {
                free(ptr);
                ptr = NULL;
            }
			//测试用url参数
			//SendJsonAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", parm.c_str(), "",&ptr);
			SendJsonAPI_web(WEB_ICD,"",parm.c_str(),&ptr);
			if(ptr == NULL){
				retry++;if(retry>3)break;
				continue;
			}
			root = cJSON_Parse(ptr);
			retry++;if(retry>3)break;
		}
		if (root == NULL) {
        	printf("web error %s\n", cJSON_GetErrorPtr());
        	return 1;
    	}
	}

	cJSON* codeItem = cJSON_GetObjectItem(root, "code");
	cJSON* msgItem = cJSON_GetObjectItem(root, "msg");

	// 使用 std::string 获取值
    std::string code = (codeItem != NULL) ? codeItem->valuestring : "not found";
    std::string msg = (msgItem != NULL) ? msgItem->valuestring : "not found";

    // 打印结果
    std::cout << "code: " << code << std::endl;
    std::cout << "msg: " << msg << std::endl;

    cJSON* data = cJSON_GetObjectItem(root, "data");
    if (data && data->type == cJSON_Array) {
        cJSON* item;
        cJSON_ArrayForEach(item, data) {
            icd_model* model = new icd_model;

            cJSON* id = cJSON_GetObjectItem(item, "id");//model_id
            if (id && id->type == cJSON_String) strncpy(model->model_id, id->valuestring, sizeof(model->model_id) - 1);

            cJSON* fileName = cJSON_GetObjectItem(item, "fileName");//file_name
            if (fileName && fileName->type == cJSON_String) strncpy(model->file_name, fileName->valuestring, sizeof(model->file_name) - 1);

            cJSON* filePath = cJSON_GetObjectItem(item, "filePath");//新增
            if (filePath && filePath->type == cJSON_String) strncpy(model->file_path, filePath->valuestring, sizeof(model->file_path) - 1);

            cJSON* devType = cJSON_GetObjectItem(item, "devType");//tmnl_type
            if (devType && devType->type == cJSON_String) strncpy(model->tmnl_type, devType->valuestring, sizeof(model->tmnl_type) - 1);

            cJSON* updateTime = cJSON_GetObjectItem(item, "updateTime");//timestamp
            if (updateTime && updateTime->type == cJSON_String) strncpy(model->timestamp, updateTime->valuestring, sizeof(model->timestamp) - 1);

            // 添加到 QMap
            icd_model_map->insert(model->model_id, model);
        }
    }

    cJSON_Delete(root);
	free(ptr);  // 如果 SendJsonAPI_web 分配了内存，记得释放

	return 0; // 确保函数有返回值
}

int parse_model_cfg_web()
{
	std::vector<std::string> codes;//入参集合
	QMap<QString, icd_model*>  icd_model_map;
/////////////////////////////////////////////////////////////////////////
	//测试用
	//codes.push_back("code1=model1");	//填入终端型号列表

	//使用中端型号列表构建入参json字符串
	// 遍历前置所有监测点
	ied_t* ied;
	ied_usr_t* ied_usr;
	std::cout <<  "g_node->n_clients" <<  g_node->n_clients << std::endl;
    std::set<std::string> devTypes; // 用于去重的集合set

    for (int t = 0; t < g_node->n_clients; t++) {
        ied = (ied_t*)g_node->clients[t];
        ied_usr = (ied_usr_t*)ied->usr_ext;

        // 假设 dev_type 是一个字符串类型，加入集合 ,这里会去重
        if (strlen(ied_usr->dev_type) > 0) {
            devTypes.insert(std::string(ied_usr->dev_type));
        }
    }

    // 手动构建 JSON 字符串
    std::string input_jstr = "[";
    bool first = true; // 用于处理逗号

    for (std::set<std::string>::iterator it = devTypes.begin(); it != devTypes.end(); ++it) {
        if (!first) {
            input_jstr += ","; // 添加逗号
        }
        first = false; // 第一次之后设置为 false
        input_jstr += "\"" + *it + "\""; // 添加字符串
    }

    input_jstr += "]"; // 结束 JSON 数组
    std::cout << "input_jstr: " << input_jstr << std::endl; // 输出结果

	if(ICD_FLAG == "1"){
		codes.push_back(input_jstr);	//填入终端型号列表-获取指定的icd配置文件
	}
	else{
		codes.push_back("[]");	//不填-获取所有的icd配置文件
	}

/////////////////////////////////////////////////////////////////////////
	parse_model_web(&icd_model_map,codes);

	codes.clear();

	try {
		char model_id[64];
		char tmnl_type[64];
		//char tmnl_factory[64];
		char file_name[128];
		char file_path[128];
		//char timestamp[64];
		otl_datetime timestamp;

		// 遍历终端台账容器
		QMap<QString, icd_model*>::iterator it;
    	for (it = icd_model_map.begin(); it != icd_model_map.end(); ++it) {
    		icd_model* value = it.value();

			// 确保 value 不为空
    		if (value != nullptr) {
        		// 找到容器中对应名称并取值
        		strncpy(model_id, value->model_id, sizeof(model_id) - 1);
        		strncpy(tmnl_type, value->tmnl_type, sizeof(tmnl_type) - 1);
        		strncpy(file_path, value->file_path, sizeof(file_path) - 1);
        		strncpy(file_name, value->file_name, sizeof(file_name) - 1);
        		//strncpy(timestamp, value->timestamp, sizeof(timestamp) - 1);

				std::cout << "model_id" << model_id << std::endl;
				std::cout << "tmnl_type" << tmnl_type << std::endl;
				std::cout << "filepath" << file_path << std::endl;
				std::cout << "filename" << file_name << std::endl;

				//lnk20241125测试用
				//strncpy(tmnl_type, "PS_NET", sizeof(tmnl_type) - 1);

				Set_xml_databaseinfo(model_id, tmnl_type, file_path, file_name, timestamp.year, timestamp.month, timestamp.day, timestamp.hour, timestamp.minute, timestamp.second);
    		}
		}
		return APR_SUCCESS;
	}
	catch (otl_exception& e)
	{
		printf("\nicd model\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg);
		return e.code;
	}
}
////////////////////////////////////////////////////////////icd模型重构函数lnk20250116
char* parse_model_cfg_web_one(ied_t* ied)
{
	std::vector<std::string> codes;//入参集合
	QMap<QString, icd_model*>  icd_model_map;
	ied_usr_t* ied_usr;

    ied_usr = (ied_usr_t*)ied->usr_ext;

    // 手动构建 JSON 字符串
    std::string input_jstr = "[";
    input_jstr += "\"" + std::string(ied_usr->dev_type) + "\""; 
    input_jstr += "]"; // 结束 JSON 数组
    std::cout << "input_jstr: " << input_jstr << std::endl; // 输出结果

	codes.push_back(input_jstr);	//填入终端型号列表-获取指定的icd配置文件

	parse_model_web(&icd_model_map,codes);

	codes.clear();

	try {
		char model_id[64];
		char tmnl_type[64];
		//char tmnl_factory[64];
		char file_name[128];
		char file_path[128];
		//char timestamp[64];
		otl_datetime timestamp;//不使用

		// 遍历终端台账容器
		QMap<QString, icd_model*>::iterator it;
    	for (it = icd_model_map.begin(); it != icd_model_map.end(); ++it) {
    		icd_model* value = it.value();

			// 确保 value 不为空
    		if (value != nullptr) {
        		// 找到容器中对应名称并取值
        		strncpy(model_id, value->model_id, sizeof(model_id) - 1);
        		strncpy(tmnl_type, value->tmnl_type, sizeof(tmnl_type) - 1);
        		strncpy(file_path, value->file_path, sizeof(file_path) - 1);
        		strncpy(file_name, value->file_name, sizeof(file_name) - 1);
        		//strncpy(timestamp, value->timestamp, sizeof(timestamp) - 1);

				std::cout << "model_id" << model_id << std::endl;
				std::cout << "tmnl_type" << tmnl_type << std::endl;
				std::cout << "filepath" << file_path << std::endl;
				std::cout << "filename" << file_name << std::endl;

				//lnk20241125测试用
				//strncpy(tmnl_type, "PS_NET", sizeof(tmnl_type) - 1);

				Set_xml_databaseinfo(model_id, tmnl_type, file_path, file_name, timestamp.year, timestamp.month, timestamp.day, timestamp.hour, timestamp.minute, timestamp.second);
    		}
		}
		return model_id;
	}
	catch (otl_exception& e)
	{
		printf("\nicd model\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg);
		return NULL;
	}
}
////////////////////////////////////////////////////////////
//自动补招接口，暂不修改，可能不使用
#if 0 
bool CheckPG_To_Recall_web(long long start, long long end, char* Monitorid)
{
	QDateTime deltime_Qtime = QDateTime::fromTime_t(start);
	QDateTime deltime_Qtime_end = QDateTime::fromTime_t(end);
	QString tmp_chr1 = deltime_Qtime.toString("yyyy-MM-dd"); //当前天
	QString start_chr1 = deltime_Qtime.toString("yyyy-MM-dd hh:mm:ss"); //当前天
	QString end_chr1 = deltime_Qtime_end.toString("yyyy-MM-dd hh:mm:ss"); //当前天

	int timespan = 3;//默认时间间隔

	try {
		
		std::vector<std::string> codes;//入参集合
		QMap<QString, intact_list*>  intact_list_map;

		codes.push_back("deciderecall");
		codes.push_back(tmp_chr1.toStdString());
		codes.push_back(std::string(Monitorid));

		parse_intact_web_test_read(&intact_list_map,codes);

		codes.clear();

		try {

			double exp_num;
			double act_num;

			// 遍历终端台账容器
			QMap<QString, intact_list*>::iterator it;
    		for (it = intact_list_map.begin(); it != intact_list_map.end(); ++it) {
    			intact_list* value = it.value();

				// 确保 value 不为空
    			if (value != nullptr) {
    	    		// 找到容器中对应名称并取值

					exp_num = atof(value->exp_num);
					act_num = atof(value->act_num);

					std::cout << exp_num << " " << act_num << std::endl;

					timespan = 1440 / exp_num;
					printf("\n %f %f %d \n", exp_num, act_num, timespan);
				}
			}
		}
		catch (otl_exception& e)
		{
			printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg);
			return false;
		}
		//OTLDisconnect();
	}
	catch (otl_exception& e)
	{
		printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg);
		return false;
	}

	try {
		long long starttime = start;                          //补招起始时间
		long long endtime = starttime + 3599;                //补招结束时间
		QList<long long> timestamp_list;                      //数据库完整性记录时间点
		QList<RecallInfo> recallinfo_list;                    //待补招队列
		QList<RecallInfo> recallinfo_list_hour;               //待补招队列-以小时为最大间隔

		std::vector<std::string> codes;//入参集合
		QMap<QString, intact_list*>  intact_list_map;
		codes.push_back("handlerecall");
		codes.push_back(tmp_chr1.toStdString());
		codes.push_back(std::string(Monitorid));
		codes.push_back(start_chr1.toStdString());
		codes.push_back(end_chr1.toStdString());

		parse_intact_web_test_read(&intact_list_map,codes);

		codes.clear();

		try {
			otl_datetime timestamp;

			// 遍历终端台账容器
			if (intact_list_map.contains(Monitorid)) {
    			intact_list* value = intact_list_map.value(Monitorid);  // 找到键值为 "id" 的对象

    			if (value != nullptr) {
        			// 遍历 value_time 容器并输出所有时间字符串
        			for (std::vector<std::string>::const_iterator it = value->value_time.begin(); it != value->value_time.end(); ++it) {
    					const std::string& time = *it;

            			std::cout << "Time: " << time << std::endl;

						timestamp = parseTimestamp(time);

						struct tm timeinfo;
						timeinfo.tm_year = timestamp.year - 1900; // 年份需要减去1900
						timeinfo.tm_mon = timestamp.month - 1; // 月份需要减去1
						timeinfo.tm_mday = timestamp.day;
						timeinfo.tm_hour = timestamp.hour;
						timeinfo.tm_min = timestamp.minute;
						timeinfo.tm_sec = timestamp.second;

						time_t timestamp = std::mktime(&timeinfo);
						long long stamp = static_cast<long long>(timestamp);
						timestamp_list.append(stamp);
					}
				}
			}
		}
		catch (otl_exception& e)
		{
			printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg);
			return false;
		}
		//OTLDisconnect();

		if (timestamp_list.size() <= (60 / timespan) * 0.97) //完整性数据表无数据
		{
			printf("\n return ture %d %f\n", timestamp_list.size(), (60 / timespan) * 0.97);
			return true;
		}
		else
		{
			printf("\n return false %d %f\n", timestamp_list.size(), (60 / timespan) * 0.97);
			return false;
		}
	}
	catch (otl_exception& e)
	{
		printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg);
		return false;
	}
	printf("\n>>>error quit!!\n");
	return true;
}
#endif
//定时任务不需要定时日志清理和其他一些功能，统一放在这里修改
void OnTimerThread::run()
{
	msleep(10000);
	printf("OnTimerThread::run() is called ...... \n");

	bool account_update = true;
	bool asd = true;

	//当前时间获取
	apr_time_t	previousTime = apr_time_now();//
	apr_time_exp_t localTime;
	apr_time_exp_gmt(&localTime, previousTime);
	cout << "Local Time: "
		<< localTime.tm_year + 1900 << "-" << localTime.tm_mon + 1 << "-" << localTime.tm_mday << " "
		<< localTime.tm_hour << ":" << localTime.tm_min << ":" << localTime.tm_sec
		<< endl;

	//web手动补招的进程，测试前置所有连接的终端连接情况
	int ip_count = 0;
	int telnet_count = 0;
	if (g_node_id == RECALL_HIS_DATA_BASE_NODE_ID) {
		//在测试连接时给台账加锁lnk20250114
		pthread_mutex_lock(&mtx);
		init_ping_telnet(ip_count, telnet_count);
		Cout_account_information();
		pthread_mutex_unlock(&mtx);//解锁
	}

	//单联模式
	if (g_onlyIP[0] != 0)
	{
		printf("g_onlyIP[0]=!0 ontimer--%s--\n", g_onlyIP);
		add_comm_log(const_cast<char*>("g_onlyIP[0]=!0,g_onlyIP is --%s--", g_onlyIP));
	}
	else 
	{
		printf("g_onlyIP[0] == 0!");
	}

	int pgflag = 0;
	int pgmin = 0;
	int mp_num_hour = 0;
	int recall_flag1 = 1;		//补招标志

	//添加入参容器
	std::vector<std::string> codes;

	while (1)
	{
		//进入线程时间
		previousTime = apr_time_now();
		apr_time_exp_gmt(&localTime, previousTime);

		if (strcmp(subdir, "cfg_stat_data") == 0 || strcmp(subdir, "cfg_newhis_data") == 0) {//台账更新,多节点,通讯

			//不需要更新前置表
			/*//判断执行此任务时间段内是否有 任务被堵塞
			if (MULTIPLE_NODE_FLAG && pgflag) {
				if (FRONT_INST != 0 && FRONT_IP[0] != '\0') {

					
					codes.push_back("updatefront");
					codes.push_back(std::string(FRONT_IP));
					codes.push_back(intToString(FRONT_INST));
					codes.push_back(intToString(FRONT_MP_NUM));
					codes.push_back(std::string(PROGRAM_VERSION));
					parse_device_web_test_front_write(codes);
					codes.clear();

				}
				pgflag = 0;
			}
			else if (MULTIPLE_NODE_FLAG && pgmin != localTime.tm_min)
			{
				pgmin = localTime.tm_min;
				pgflag = 1;
			}*/
			
			//调试
			printf("check error10 !!!!!!!!!!!!!!\n");

			//日志记录
			if (mp_num_hour != localTime.tm_hour) {
				pthread_mutex_lock(&mtx);//lnk20250114
				std::string mp_num_str = "";
				mp_num_str.append("connected device count:");
				mp_num_str.append(QString::number(FRONT_MP_NUM).toStdString());//记录连接的检测点数
				mp_num_str.append(",g_node clients:");
				mp_num_str.append(QString::number(g_node->n_clients).toStdString());

				add_comm_log(const_cast<char*>(mp_num_str.c_str()));
				mp_num_hour = localTime.tm_hour;
				pthread_mutex_unlock(&mtx);//解锁
			}
			//调试
			printf("check error11 !!!!!!!!!!!!!!\n");

		}
//不使用的代码lnk20241206
#if 0		
		if (strcmp(subdir, "cfg_newhis_data") == 0) {//上海定时招装置日志
			static int hour_time = 0;
			if (localTime.tm_hour != hour_time) {
				hour_time = localTime.tm_hour;

				printf(">>>cfg_newhis_data is run!!!\n");
				long long stamp = static_cast<long long>(previousTime) / 1000000;
				cout << ">>>>>>>>>The Time is: " << stamp << endl;
				long long start = stamp - (stamp % 3600) - 3600 - 3600;//开始时间 当前整点值往前推两小时
				long long end = start + 3599;//结束时间

				QList<RecallInfo> recallinfo_list_hour;
				RecallInfo info;
				info.starttime = start - 10;
				info.endtime = end;
				recallinfo_list_hour.append(info);

				int i = 0;
				while (i < g_pt61850app->chnl_counts)
				{
					chnl_usr_t* chnl_usr;
					ied_t* ied;
					ied_usr_t* ied_usr;
					LD_info_t* LD_info;
					int	cpuno = 0;

					chnl_usr = g_pt61850app->chnl_usr[i];
					ied = chnl_usr->chnl->ied;
					ied_usr = GET_IEDEXT_ADDR(ied);
					printf("\n chnl_usr->m_state ===== %d\n", chnl_usr->m_state);
					//if (chnl_usr->m_state == CHANNEL_CONNECTED) {
					while (cpuno < ied->cpucount)
					{
						LD_info = &(ied_usr->LD_info[cpuno]);
						cpuno++;
						if (LD_info->logcount <= 0 || LD_info->read_flag == 0)
							continue;
						printf("/home/pq mpid=%s\n", LD_info->mp_id);
						printf("\n %d ===== %d\n", recallinfo_list_hour.size(), LD_info->autorecallflag);

						if (recallinfo_list_hour.size() != 0) {
							for (int j = 0; j < recallinfo_list_hour.size(); j++) {
								CJournalRecall jr;
								jr.MonitorID = QString(LD_info->mp_id);
								jr.StartTime = QDateTime::fromTime_t(recallinfo_list_hour[j].starttime).toString("yyyy-MM-dd hh:mm:ss");
								jr.EndTime = QDateTime::fromTime_t(recallinfo_list_hour[j].endtime).toString("yyyy-MM-dd hh:mm:ss");
								jr.STEADY = QString::number(1, 10);
								jr.VOLTAGE = QString::number(1, 10);
								g_StatisticLackList_list_mutex.lock();
								g_StatisticLackList.push_back(jr);
								g_StatisticLackList_list_mutex.unlock();
							}
						}
					}

					i++;
				}
			}
		}
		
		//全量补招将通过web下发，而不是手动操作数据库
		if (strcmp(subdir, "cfg_recallall_data") == 0)
		{
			static int recall_xml_time = 0;
			if (localTime.tm_min != recall_xml_time)
			{
				recall_xml_time = localTime.tm_min;
				//补招开始与截止时间
				static long long recall_start_time = 0;
				static long long recall_end_time = 0;
				static int flag = 0;
				if (recall_start_time == 0 && recall_end_time == 0) {//无缓存数据
					//查询一条 -1状态(代补招)的记录
					char front_ip[42];
					cout << "start select:" << endl;

					QMap<QString, front_list*> front_map;
					codes.push_back("frontip");
					codes.push_back("g_front_seg_index");
					codes.push_back("-1");
					parse_device_web_test_front_read(&front_map,codes);
					codes.clear();
					// 遍历 QMap 容器
					QMap<QString, front_list*>::iterator it;
    				for (it = front_map.begin(); it != front_map.end(); ++it) {
        				front_list* value = it.value();
        				// 确保 value 不为空
        				if (value != nullptr) {
        			    	// 从 value 中读取 front_ip
        			    	strncpy(front_ip, value->front_ip, sizeof(front_ip) - 1);
							//应该只有一条记录
							std::cout << "front_ip:" <<front_ip << std::endl;
						}
					}
					
					if (containsDash(front_ip, 21)) {

						codes.push_back("insertfront");
						codes.push_back(std::string(front_ip));
						codes.push_back(intToString(g_front_seg_index));
						codes.push_back("03");		//前置类型
						codes.push_back(std::string(PROGRAM_VERSION));				
						codes.push_back("-1");		//状态值				
						parse_device_web_test_front_write(codes);				
						codes.clear();

						//缓存数据
						cout << "front_ip=" << front_ip << endl;
						QString startDate, endDate;
						// 分割字符串  
						startDate = QString::fromAscii(front_ip).left(10); // 取前10个字符作为开始日期  
						qDebug() << "startDate=" << startDate << endl;
						endDate = QString::fromAscii(front_ip + 11).left(10); // 从第10个字符开始取8个字符作为结束日期
						qDebug() << "endDate=" << endDate << endl;

						QDateTime start_dt = QDateTime::fromString(startDate, "yyyyMMddHH");
						qDebug() << "start_dt=" << start_dt << endl;
						recall_start_time = start_dt.toMSecsSinceEpoch() / 1000;
						qDebug() << "recall_start_time=" << recall_start_time << endl;
						QDateTime end_dt = QDateTime::fromString(endDate, "yyyyMMddHH");
						qDebug() << "end_dt=" << end_dt << endl;
						recall_end_time = end_dt.toMSecsSinceEpoch() / 1000;
						qDebug() << "recall_end_time=" << recall_end_time << endl;
					}
					flag = 0;

				}
				else if (recall_start_time != 0 && recall_end_time != 0) {//有缓存数据
					// 将时间戳转换为YYYYMMDD格式  
					QString date1 = timestampToYYYYMMDD(recall_start_time);
					QString date2 = timestampToYYYYMMDD(recall_end_time);
					// 拼接两个日期，并用'-'分隔  
					QString dateRange = date1 + "-" + date2;
					qDebug() << "dateRange=" << dateRange << endl;
					char front_status[4];

					QMap<QString, front_list*> front_map;
					codes.push_back("frontstatus");
					codes.push_back(dateRange.toStdString());  //ip
					codes.push_back("g_front_seg_index");	//inst
					parse_device_web_test_front_read(&front_map,codes);
					codes.clear();
					// 遍历 QMap 容器
					QMap<QString, front_list*>::iterator it;
    				for (it = front_map.begin(); it != front_map.end(); ++it) {
        				front_list* value = it.value();
        				// 确保 value 不为空
        				if (value != nullptr) {
        			    	// 从 value 中读取 front_ip
        			    	strncpy(front_status, value->front_status, sizeof(front_status) - 1);
							//应该只有一条记录
							std::cout << "front_status:" <<front_status << std::endl;
						}
					}

					qDebug() << "front_status=" << front_status << endl;
					//再次判断是否为执行中状态
					if (strcmp(front_status, "-1") == 0) {
						//状态为-1 重新插入更新记录

						codes.push_back("insertfront");
						codes.push_back(dateRange.toStdString());
						codes.push_back(intToString(g_front_seg_index));
						codes.push_back("03");		//前置类型
						codes.push_back(std::string(PROGRAM_VERSION));				
						codes.push_back("-1");		//状态值				
						parse_device_web_test_front_write(codes);				
						codes.clear();

						flag = 0;
					}
					else if (strcmp(front_status, "-2") == 0)
					{//状态为-2 补招

						flag = 1;
					}
					else {
						flag = 0;
						recall_end_time = 0;
						recall_start_time = 0;
					}

				}

				if (recall_start_time != 0 && recall_end_time != 0 && flag == 1)
				{
					qDebug() << "start recall time=" << recall_start_time << endl;
					qDebug() << "end recall time=" << recall_end_time << endl;

					long long starttime = recall_start_time;  //补招起始时间
					long long endtime = recall_end_time;                //补招结束时间

					flag = 0;
					recall_start_time = 0;
					recall_end_time = 0;

					QList<RecallInfo> recallinfo_list;                    //待补招队列
					QList<RecallInfo> recallinfo_list_hour;               //待补招队列-以小时为最大间隔

					RecallInfo info;
					info.starttime = starttime;
					info.endtime = endtime;
					recallinfo_list.append(info);

					for (int i = 0; i < recallinfo_list.size(); i++)
					{
						//printf("\n %lld ----- %11d\n", recallinfo_list[i].starttime, recallinfo_list[i].endtime);
						long long duration = recallinfo_list[i].endtime - recallinfo_list[i].starttime;
						long long max_interval = 3600;
						for (long long j = 0; j <= duration; j += max_interval)
						{
							if (j + max_interval > duration) {
								long long start = recallinfo_list[i].starttime + j;
								long long end = recallinfo_list[i].endtime;

								RecallInfo info;
								info.starttime = start;
								info.endtime = end;
								recallinfo_list_hour.append(info);
							}
							else {
								long long start = recallinfo_list[i].starttime + j;
								long long end = recallinfo_list[i].starttime + j + max_interval;

								RecallInfo info;
								info.starttime = start;
								info.endtime = end - 1;
								recallinfo_list_hour.append(info);
							}
						}
					}

					int i = 0;
					while (i < g_pt61850app->chnl_counts)
					{
						chnl_usr_t* chnl_usr;
						ied_t* ied;
						ied_usr_t* ied_usr;
						LD_info_t* LD_info;
						int	cpuno = 0;

						chnl_usr = g_pt61850app->chnl_usr[i];
						ied = chnl_usr->chnl->ied;
						ied_usr = GET_IEDEXT_ADDR(ied);
						printf("\n chnl_usr->m_state ===== %d\n", chnl_usr->m_state);
						//if (chnl_usr->m_state == CHANNEL_CONNECTED)
						while (cpuno < ied->cpucount)
						{
							LD_info = &(ied_usr->LD_info[cpuno]);
							cpuno++;
							printf("/home/pq mpid=%s %d\n", LD_info->mp_id, LD_info->read_flag);
							if (LD_info->logcount <= 0 || LD_info->read_flag == 0) {
								continue;
							}
							printf("\n %d ===== %d\n", recallinfo_list_hour.size(), LD_info->autorecallflag);

							if (recallinfo_list_hour.size() != 0) {
								g_StatisticLackList_list_mutex.lock();
								for (int j = 0; j < recallinfo_list_hour.size(); j++) {

//替换成web接口 2024-10-21 lnk
			//						if (CheckPG_To_Recall(recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime, LD_info->mp_id) == false) {
			//							printf("CheckPG_To_Recall == false %d-%d %s\n", recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime, LD_info->mp_id);
									if (CheckPG_To_Recall_web(recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime, LD_info->mp_id) == false) {
										printf("CheckPG_To_Recall_web == false %d-%d %s\n", recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime, LD_info->mp_id);

										continue;
									}
									CJournalRecall jr;
									jr.MonitorID = QString(LD_info->mp_id);
									jr.StartTime = QDateTime::fromTime_t(recallinfo_list_hour[j].starttime).toString("yyyy-MM-dd hh:mm:ss");
									jr.EndTime = QDateTime::fromTime_t(recallinfo_list_hour[j].endtime).toString("yyyy-MM-dd hh:mm:ss");
									jr.STEADY = QString::number(1, 10);
									jr.VOLTAGE = QString::number(1, 10);
									g_StatisticLackList.push_back(jr);

								}
								g_StatisticLackList_list_mutex.unlock();
							}
						}
						i++;
					}
				}
			}
		}
		
		//自动补招可能改为web轮询下发
		if (strcmp(subdir, "cfg_his_data") == 0)
		{
			if (pgflag) {

				//当前不需要实时更新前置表对应的监测点
				/*if (FRONT_INST != 0 && FRONT_IP[0] != '\0') {
					codes.push_back("his");
					codes.push_back("his");	//ip
					codes.push_back(std::string(PROGRAM_VERSION));				
					codes.push_back(intToString(FRONT_MP_NUM));		//检测点数				
					parse_device_web_test_front_write(codes);				
					codes.clear();
				}*/

				pgflag = 0;
			}
			else if (pgmin != localTime.tm_min)
			{
				pgmin = localTime.tm_min;
				pgflag = 1;
			}

			static int cfg_his_data_hour_time = 0;
			if (localTime.tm_hour != cfg_his_data_hour_time) {
				cfg_his_data_hour_time = localTime.tm_hour;

				printf(">>>cfg_his_data is run!!!\n");
				long long stamp = static_cast<long long>(previousTime) / 1000000;
				cout << ">>>>>>>>>The Time is: " << stamp << endl;
				long long start = stamp - (stamp % 3600) - 3600 - 3600;//开始时间 当前整点值往前推两小时
				long long end = start + 3599;//结束时间

				QList<RecallInfo> recallinfo_list_hour;
				RecallInfo info;
				info.starttime = start - 10;
				info.endtime = end;
				recallinfo_list_hour.append(info);

				int i = 0;
				while (i < g_pt61850app->chnl_counts)
				{
					chnl_usr_t* chnl_usr;
					ied_t* ied;
					ied_usr_t* ied_usr;
					LD_info_t* LD_info;
					int	cpuno = 0;

					chnl_usr = g_pt61850app->chnl_usr[i];
					ied = chnl_usr->chnl->ied;
					ied_usr = GET_IEDEXT_ADDR(ied);
					printf("\n chnl_usr->m_state ===== %d\n", chnl_usr->m_state);
					//if (chnl_usr->m_state == CHANNEL_CONNECTED) {
					while (cpuno < ied->cpucount)
					{
						LD_info = &(ied_usr->LD_info[cpuno]);
						cpuno++;
						if (LD_info->logcount <= 0 || LD_info->read_flag == 0)
							continue;
						printf("/home/pq mpid=%s\n", LD_info->mp_id);
						printf("\n %d ===== %d\n", recallinfo_list_hour.size(), LD_info->autorecallflag);

						if (recallinfo_list_hour.size() != 0) {
							for (int j = 0; j < recallinfo_list_hour.size(); j++) {

//替换成web接口 2024-10-21 lnk
								//if (CheckPG_To_Recall(recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime, LD_info->mp_id) == false) {
									//printf("CheckPG_To_Recall == false %d-%d %s\n", recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime, LD_info->mp_id);
								if (CheckPG_To_Recall_web(recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime, LD_info->mp_id) == false) {
									printf("CheckPG_To_Recall_web == false %d-%d %s\n", recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime, LD_info->mp_id);
									
									continue;
								}
								CJournalRecall jr;
								jr.MonitorID = QString(LD_info->mp_id);
								jr.StartTime = QDateTime::fromTime_t(recallinfo_list_hour[j].starttime).toString("yyyy-MM-dd hh:mm:ss");
								jr.EndTime = QDateTime::fromTime_t(recallinfo_list_hour[j].endtime).toString("yyyy-MM-dd hh:mm:ss");
								jr.STEADY = QString::number(1, 10);
								jr.VOLTAGE = QString::number(1, 10);
								g_StatisticLackList_list_mutex.lock();
								g_StatisticLackList.push_back(jr);
								g_StatisticLackList_list_mutex.unlock();
							}
						}
					}
					i++;
				}
			}
		}
#endif		
		//单条补招由web触发，cfg_recallhis_data进程启动时会分配一个专用的端口，其他进程没有
		if (strcmp(subdir, "cfg_recallhis_data") == 0)
		{
			if (pgflag) {

				//当前不需要实时更新前置表对应的监测点
				/*if (FRONT_INST != 0 && FRONT_IP[0] != '\0') {
					codes.push_back("his");
					codes.push_back("recallhis");	//ip
					codes.push_back(std::string(PROGRAM_VERSION));				
					codes.push_back(intToString(FRONT_MP_NUM));		//检测点数				
					parse_device_web_test_front_write(codes);				
					codes.clear();
				}*/
				pgflag = 0;
			}
			else if (pgmin != localTime.tm_min)
			{
				pgmin = localTime.tm_min;
				pgflag = 1;
			}
		}

//不使用的代码lnk20241206
#if 0
		//自动补招处理
		if (0 && g_node_id == HIS_DATA_BASE_NODE_ID && (localTime.tm_hour <= 12 || localTime.tm_hour >= 20) && recall_flag1 == 1) {
			recall_flag1 = 0;
			QString MyKafkaIniFilename = QString("../etc/") + QString("mykafka.ini"); //+QString::fromAscii(subdir)
			QSettings settings(MyKafkaIniFilename, QSettings::IniFormat);

			QString dateString = settings.value("Recall/select_day").toString();

			QList<RecallInfo> recallinfo_list_hour;
			QByteArray byteArray = dateString.toUtf8(); // 使用 UTF-8 编码  
			char* charArray = byteArray.data();
			Get_Recall_Time(charArray, recallinfo_list_hour);

			int i = 0;
			while (i < g_pt61850app->chnl_counts)
			{
				chnl_usr_t* chnl_usr;
				ied_t* ied;
				ied_usr_t* ied_usr;
				LD_info_t* LD_info;
				int	cpuno = 0;

				chnl_usr = g_pt61850app->chnl_usr[i];
				ied = chnl_usr->chnl->ied;
				ied_usr = GET_IEDEXT_ADDR(ied);
				while (cpuno < ied->cpucount)
				{
					LD_info = &(ied_usr->LD_info[cpuno]);
					if (LD_info->logcount <= 0)
						continue;
					printf("/home/pq mpid=%s\n", LD_info->mp_id);
					printf("\n %d ===== %d\n", recallinfo_list_hour.size(), LD_info->autorecallflag);
					if (recallinfo_list_hour.size() != 0) {
						if (LD_info->autorecallcount != 0) {
							for (int j = 0; j < LD_info->autorecallcount; j++) {
								delete LD_info->autorecall[j];
							}
							delete LD_info->autorecall;
							LD_info->autorecallcount = 0;
						}
						LD_info->autorecallflag = 0;
						LD_info->autorecallcount = recallinfo_list_hour.size();
						LD_info->autorecall = new autorecall_t * [recallinfo_list_hour.size()];
						printf("/home/pq recall mpid=%s\n", LD_info->mp_id);

						for (int j = 0; j < recallinfo_list_hour.size(); j++) {
							printf("\n %lld ===== %11d\n", recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime);
							LD_info->autorecall[j] = new autorecall_t[1];
							LD_info->autorecall[j]->start = recallinfo_list_hour[j].starttime;

							LD_info->autorecall[j]->end = recallinfo_list_hour[j].endtime;
						}
					}
					cpuno++;
				}
				i++;
			}

			QDate date = QDate::fromString(dateString, "yyyy-MM-dd");
			date.addDays(-1); // 一天  
			settings.setValue("Recall/select_day", date.toString("yyyy-MM-dd")); // 重新写入日期字符串  
		}
#endif		
		if (localTime.tm_hour > 12 && localTime.tm_hour < 20 && recall_flag1 == 0) {
			recall_flag1 = 1;
		}
		msleep(1000);
	}
	printf(">>>OnTimerThread::run() is end!!!\n");
}

//补招web处理函数
/*int HandleRecall_http(const httplib::Request& req, httplib::Response& res) //接收并处理Web客户端发来的信息
{
	// 打印请求的查询参数
    std::cout << "Query parameters: " << std::endl;

    if (req.body.empty()) {
        res.status = 400; // 返回 400 Bad Request 错误
        res.set_content("Missing code or parameter", "application/json");
        return 10000;
    }       

    std::cout << "Received code: " << req.body<< std::endl;

	try
	{
		printf("来自web客户端消息：\n");
		cJSON* json_root = cJSON_Parse(req.body.c_str());   //json格式序列化  //第一个参数
		if (json_root == NULL) {
			return 10000;
		}*/
int recall_json_handle(const char* jstr)
{
	//不指定稳态/暂态则全部补招
	int stat = 0;	//都不补
	int voltage= 0;
	try{

		std::vector<RecallParam> recallParams;
		cJSON* json_root = cJSON_Parse(jstr);   //json格式序列化  //第一个参数
		if (json_root == NULL) {
			std::cout <<  "json root解析错误"<< std::endl;
			return 10000;
		}
		/*cJSON* json_code = NULL;
		cJSON* json_msg = NULL;

		std::vector<RecallParam> recallParams;

		json_code = cJSON_GetObjectItem(json_root, "code");    //获取code
		if (json_code != NULL) {
			std::cout << "Received code: " << json_code->valuestring << std::endl;
		}
		else {
			return 10000;
		}
		json_msg = cJSON_GetObjectItem(json_root, "msg");    //获取msg
		if (json_code != NULL) {
			std::cout << "Received msg: " << json_msg->valuestring << std::endl;
		}
		else {
			return 10000;
		}*/
		// 获取 "data" 数组
    	//cJSON* dataArray = cJSON_GetObjectItem(json_root, "data");

		// 遍历数组的每个对象
    	if (json_root->type == cJSON_Array) {
        	for (cJSON* item = json_root->child; item != nullptr; item = item->next) {
        	    // 获取 monitorId 数组
        	    cJSON* monitorIdArray = cJSON_GetObjectItem(item, "monitorId");
        	    cJSON* timeIntervalArray = cJSON_GetObjectItem(item, "timeInterval");
				//判断dataType是否为空
				cJSON* datatype = cJSON_GetObjectItem(item, "dataType");

				//添加异常判断防止崩溃
				if(monitorIdArray == NULL || timeIntervalArray == NULL  || datatype == NULL ){
					std::cout <<  "json内容解析错误 "<< std::endl;
					return 10000;
				}

				if(strcmp(datatype->valuestring, "") != 0)//非空
				{
					stat = (strcmp(datatype->valuestring, "0") == 0) ? 1 : 0;//稳态
					voltage= (strcmp(datatype->valuestring, "1") == 0) ? 1 : 0;//暂态
				}
				else //空或其他
				{
					stat = 1;
					voltage= 1;
				}

				//调试用
				if(monitorIdArray != nullptr && monitorIdArray->child != nullptr)std::cout <<  "monitorIdArray的成员为"<< monitorIdArray->child->valuestring << std::endl;
				if(monitorIdArray != nullptr && monitorIdArray->child == nullptr)std::cout <<  "monitorIdArray没有成员"<< std::endl;

				//monitorIdArray有数据的情况
        	    if (monitorIdArray != nullptr && monitorIdArray->type == cJSON_Array && timeIntervalArray->type == cJSON_Array && monitorIdArray->child != nullptr) {
        	        // 遍历 monitorId 数组				
        	        for (cJSON* idItem = monitorIdArray->child; idItem != nullptr; idItem = idItem->next) {
        	            QString monitorId = QString(idItem->valuestring);

						//添加判断数组中当前监测点是否属于本进程20241230，防止出现非本进程的监测点触发补招
						int mppair = 0;
						ied_t* ied;
						ied_usr_t* ied_usr;
						for (int t = 0; t < g_node->n_clients; t++){
							ied = (ied_t*)g_node->clients[t];
							ied_usr = (ied_usr_t*)ied->usr_ext;
							for (int m = 0; m<10; m++){//最多10个

								if(strcmp(ied_usr->LD_info[m].mp_id,"") == 0)continue;//跳过空的

								if(strcmp(ied_usr->LD_info[m].mp_id,monitorId.toStdString().c_str()) == 0){//匹配上了

									mppair = 1;
									break;//找到就退出监测点循环
								}
							
							}
							if(mppair == 1)break;//找到就退出终端循环
						}
						if(mppair == 0)continue;//当前进程的监测点都没有找到这个检测点号，说明不是本进程的监测点，处理数组的下一个监测点
						//调试用
						std::cout << "find mpid:" << monitorId.toStdString() << "in this process,mppair=" << mppair <<std::endl;

        	            // 遍历 timeInterval 数组
        	            for (cJSON* timeItem = timeIntervalArray->child; timeItem != nullptr; timeItem = timeItem->next) {
        	                QString timeInterval = QString(timeItem->valuestring);
        	                QString start = timeInterval.left(timeInterval.indexOf("~"));
        	                QString end = timeInterval.mid(timeInterval.indexOf("~") + 1);

        	                // 创建 RecallParam 对象并添加到列表中

        	                RecallParam param;
        	                param.mp_id = monitorId;
        	                param.start = start;
        	                param.end = end;
        	                param.stat = stat; 
							param.voltage = voltage;
        	                recallParams.push_back(param);
        	            }
        	        }
        	    }
				//monitorIdArray为空的情况
				else if (monitorIdArray != nullptr && monitorIdArray->type == cJSON_Array && monitorIdArray->child == nullptr) {
    				// monitorIdArray 为空
    				std::cout << "monitorIdArray is null" << std::endl;
					//所有监测点补招
					// 遍历前置所有监测点
					ied_t* ied;
					ied_usr_t* ied_usr;
					std::cout <<  "g_node->n_clients" <<  g_node->n_clients << std::endl;
        	        for (int t = 0; t < g_node->n_clients; t++){
						ied = (ied_t*)g_node->clients[t];
						ied_usr = (ied_usr_t*)ied->usr_ext;
						for (int m = 0; m<10; m++){

							if(strcmp(ied_usr->LD_info[m].mp_id,"") == 0)continue;
							std::cout <<  "ied_usr->LD_info[m].mp_id" <<  m  << "   "<<  ied_usr->LD_info[m].mp_id << std::endl;
        	            	QString monitorId = QString(ied_usr->LD_info[m].mp_id);

        	            	// 遍历 timeInterval 数组
        	            	for (cJSON* timeItem = timeIntervalArray->child; timeItem != nullptr; timeItem = timeItem->next) {
        	            	    QString timeInterval = QString(timeItem->valuestring);
        	            	    QString start = timeInterval.left(timeInterval.indexOf("~"));
        	            	    QString end = timeInterval.mid(timeInterval.indexOf("~") + 1);

        	            	    // 创建 RecallParam 对象并添加到列表中
        	            	    RecallParam param;
        	            	    param.mp_id = monitorId;
        	            	    param.start = start;
								param.end = end;
        	                	param.stat = stat; 
								param.voltage = voltage;
        	            	    recallParams.push_back(param);
        	            	}
						}
        	        }
				}
				else{
					std::cout << "monitorIdArray 不存在或类型不正确" << std::endl;
				}
        	}
		}
		cJSON_Delete(json_root);	//web入参处理结束
		//遍历容器取出所有补招
		for (std::vector<RecallParam>::iterator it = recallParams.begin(); it != recallParams.end(); ++it) {

			QList<RecallInfo> recallinfo_list_hour;
			char start_time[64];
			char end_time[64];
			QString mp_id;

			mp_id = it->mp_id;
			apr_snprintf(start_time, sizeof(start_time), "%s", it->start.toStdString().c_str());//start_time
			apr_snprintf(end_time, sizeof(end_time), "%s", it->end.toStdString().c_str());//end_time

			qDebug() << "mp_id" << mp_id << "  " <<  "start_time" << start_time << "  " << "end_time" << "  " << "stat" << it->stat << "  " << "voltage" << it->voltage<< end_time;
				
			Get_Recall_Time_Char(start_time, end_time, recallinfo_list_hour);
			
			for (int j = 0; j < recallinfo_list_hour.size(); j++) {
				CJournalRecall jr;
				jr.MonitorID = mp_id;
				jr.StartTime = QDateTime::fromTime_t(recallinfo_list_hour[j].starttime).toString("yyyy-MM-dd hh:mm:ss");
				jr.EndTime = QDateTime::fromTime_t(recallinfo_list_hour[j].endtime).toString("yyyy-MM-dd hh:mm:ss");

				//现在暂态稳态根据web获取
				//jr.STEADY = QString::number(1, 10); // 将整数 1 转换为字符串并赋值
				//jr.VOLTAGE = QString::number(1, 10);// 将整数 1 转换为字符串并赋值
				//调试用
				//std::cout << "stat" << it->stat << "voltage" << it->voltage << std::endl;
				jr.STEADY = QString::number(it->stat);
				jr.VOLTAGE = QString::number(it->voltage);

				g_StatisticLackList_list_mutex.lock();
				g_StatisticLackList.push_back(jr);
				g_StatisticLackList_list_mutex.unlock();
			}				
		}		
	}
	catch (exception& e)
	{
		printf("处理客户端发送的消息错误，原因：%s\n", e.what());
		return 10004;
	}

	return 000000;
}

int rtdata_http(const char* jstr)
{

}

// 声明外部函数，http功能用库链接，单独编译
#ifdef __cplusplus
extern "C" {
#endif

void httprun();
const char* getReceivedData(int fun);
void threadmsgweb(int fun);
bool threadmsghttp(int fun);

#ifdef __cplusplus
}
#endif
#if 0
void RecallJsonResponse(int result) {
    char* ptr=NULL;
	
	// 创建 JSON 对象
    cJSON* json_response = cJSON_CreateObject();

    // 添加字段
	if(result == 000000){
		cJSON_AddStringToObject(json_response, "code", "A0000");
		cJSON_AddStringToObject(json_response, "msg", "数据补招执行成功");
	}
	else{
		cJSON_AddStringToObject(json_response, "code", "A0002");
		cJSON_AddStringToObject(json_response, "msg", "数据补招执行失败");
	}
    
    cJSON_AddNullToObject(json_response, "data"); // 设置为 null

    // 将 JSON 对象转换为字符串
    char* json_string = cJSON_Print(json_response);
    std::cout << json_string << std::endl;

	//发送回复给对方，只发一次
	SendJsonAPI_web("调用方", "", json_string ,&ptr);

    // 清理
    cJSON_Delete(json_response);
    free(json_string); // 释放打印字符串的内存
}
#endif

void WebhttpThread::run()
{
	int ret = 1;
	printf("WebhttpThread::run() is called ...... \n");

	while(1){

		//补招进程
		if (!threadmsghttp(1) && g_node_id == RECALL_HIS_DATA_BASE_NODE_ID) {//http处理一条消息,状态变为false，不再处理消息（http此时可能有消息来但是不处理）后这个线程开始读取数据

			const char* data = getReceivedData(1);//从http中取数据,指针

			std::cout << "recall data cfg:" << data <<std::endl;

			pthread_mutex_lock(&mtx);
			ret = recall_json_handle(data);//处理补招指令
			pthread_mutex_unlock(&mtx);

			
			threadmsgweb(1);//读取数据后开启http消息处理，此时有消息来才会处理，处理完状态变更等下一次循环
    	}
		//3s数据进程
		if (!threadmsghttp(2) && g_node_id == THREE_SECS_DATA_BASE_NODE_ID) {//http处理一条消息,状态变为false，不再处理消息（http此时可能有消息来但是不处理）后这个线程开始读取数据

			const char* data = getReceivedData(2);//从http中取数据,指针

			std::cout << "rt data cfg:" << data <<std::endl;

			ret = rtdata_http(data);//处理补招指令

			threadmsgweb(2);//读取数据后开启http消息处理，此时有消息来才会处理，处理完状态变更等下一次循环
    	}
	}
	printf("WebhttpThread::run() is end ...... \n");
}

void httpThread::run()
{
	printf("httpThread::run() is called ...... \n");
	std::cout << "Server started at" << HTTP_IP << ":" << HTTP_PORT << std::endl;
	httprun();	//开始运行http监听所有ip，端口10004

	printf("httpThread::run() is end ...... \n");
}
//在类中定义测试线程任务lnk20250107
//不使用简单的循环线程，而是启动一个app，不仅执行循环线程，而且可以连接输入
/*void mqtestThread::run()
{
	printf("mqtestThread::run() is called ...... \n");

	while(1)
	{
		if(G_TEST_NUM != 0){
			rocketmq_test_300(G_TEST_NUM,g_front_seg_index);
			QThread::sleep(60);  // 每次发送间隔1分钟
		}		
	}

	printf("mqtestThread::run() is end ...... \n");
}*/


void curltest()
{
	char* ptr=NULL;
	std::string code = std::string("code1=recall");
	SendWebAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", code.c_str(), &ptr);
}

// Base64 编码函数，将输入的字符串编码为 Base64 格式 //实现json中的文件流
std::string base64_encode(const std::string& in) {
    // Base64 字符集，由 64 个字符组成
    static const std::string base64_chars = 
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        "abcdefghijklmnopqrstuvwxyz"
        "0123456789+/";

    std::string out;  // 输出字符串
    int val = 0;      // 当前值
    int valb = -6;    // 值的位偏移量，初始为 -6

    // 遍历输入字符串的每一个字符
    for (std::string::const_iterator it = in.begin(); it != in.end(); ++it) {
        // 将字符的 ASCII 值左移 8 位并加到 val 中
        val = (val << 8) + *it;
        valb += 8;  // 更新位偏移量，每个字符占 8 位

        // 当 valb 大于等于 0 时，说明有足够的位数可以进行编码
        while (valb >= 0) {
            // 将 val 的高 6 位转化为 Base64 字符，并添加到输出中
            out.push_back(base64_chars[(val >> valb) & 0x3F]);
            valb -= 6;  // 每次编码后，位偏移量减少 6 位
        }
    }

    // 如果还有剩余的位数，补充 '=' 字符
    while (valb > -6) {
        out.push_back('=');
        valb -= 6;  // 每次添加一个 '='，位偏移量减少 6 位
    }
    
    return out;  // 返回编码后的字符串
}

void handleUploadResponse(const std::string& response, char* wavepath) {
    
	// 解析 JSON 响应
    cJSON* json_data = cJSON_Parse(response.c_str());
    if (json_data == nullptr) {
        std::cerr << "Error parsing response: " << cJSON_GetErrorPtr() << std::endl;
        return;
    }

    // 提取字段
    cJSON* codeItem = cJSON_GetObjectItem(json_data, "code");
    cJSON* msgItem = cJSON_GetObjectItem(json_data, "msg");
    cJSON* dataItem = cJSON_GetObjectItem(json_data, "data");

    if (codeItem && dataItem) {
        std::string code = codeItem->valuestring;
		std::cout << "Response Code: " << code << std::endl;
        std::string msg = (msgItem != NULL) ? msgItem->valuestring : "not found";
		std::cout << "Message: " << msg << std::endl;

        cJSON* nameItem = cJSON_GetObjectItem(dataItem, "name");
        cJSON* fileNameItem = cJSON_GetObjectItem(dataItem, "fileName");
        cJSON* urlItem = cJSON_GetObjectItem(dataItem, "url");

        if (nameItem && fileNameItem && urlItem) {
            std::string name = nameItem->valuestring;
            std::string fileName = fileNameItem->valuestring;
            std::string url = urlItem->valuestring;

            // 输出信息
            std::cout << "File Path: " << name << std::endl;
			std::cout << "Uploaded File Name: " << fileName << std::endl;
            std::cout << "File URL: " << url << std::endl;

			//记录返回的文件路径和文件名
			strcpy(wavepath, nameItem->valuestring);
        }
    } else {
        std::cerr << "Error: Missing expected fields in JSON response." << std::endl;
    }

    // 释放 JSON 对象
    cJSON_Delete(json_data);
}
//这是json结构发送的方式
/*void SendFileWeb(const std::string& strUrl, const char* localpath, const char* cloudpath, char* wavepath) {
    // 从本地路径读取文件内容
    std::ifstream file(localpath, std::ios::binary);
    if (!file) {
        std::cerr << "Failed to open file: " << localpath << std::endl;
        return;
    }
    
    std::ostringstream ss;
    ss << file.rdbuf();	
    std::string fileContent = ss.str();//文件流
    std::string encodedFile = base64_encode(fileContent);//文件流编码

    // 创建 JSON 对象 实现入参要求

    cJSON* json_root = cJSON_CreateObject();
    cJSON_AddItemToObject(json_root, "multipartFile", cJSON_CreateString(encodedFile.c_str()));
    cJSON_AddItemToObject(json_root, "path", cJSON_CreateString(cloudpath));//远端路径
    cJSON_AddItemToObject(json_root, "isReserveName", cJSON_CreateBool(true)); // 布尔值

    char* szjson = cJSON_Print(json_root);
    std::cout << ">>> json: " << szjson << std::endl;

    // curl 初始化
    CURL* curl = curl_easy_init();
    if (curl) {
        // 设置请求为 POST 请求
        curl_easy_setopt(curl, CURLOPT_POST, 1);
        curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());
        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, szjson);
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, curl_slist_append(NULL, "Content-Type: application/json"));

        // 设置超时时间
        curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10);
        curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10);

        std::string resPost0;
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&resPost0);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply_web); // 设置数据接收和写入函数

        // 执行请求
        CURLcode res = curl_easy_perform(curl);
        if (res != CURLE_OK) {
            std::cerr << "lnk web failed: " << curl_easy_strerror(res) << std::endl;
        } else {
            std::cout << "lnk web success, response: " << resPost0 << std::endl;
			 handleUploadResponse(resPost0,wavepath); // 处理响应
        }

        // 清理
        free(szjson);
    } else {
        std::cerr << ">>> curl init failed" << std::endl;
    }
    curl_easy_cleanup(curl);
    cJSON_Delete(json_root);
}*/

//这是dataform发送方式
void SendFileWeb(const std::string& strUrl, const char* localpath, const char* cloudpath, char* wavepath) {
    // 初始化 curl
    CURL* curl = curl_easy_init();
    if (curl) {
        // 设置请求 URL 和 POST 请求
        curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());
        curl_easy_setopt(curl, CURLOPT_POST, 1);

        // 创建表单数据
        curl_httppost* formpost = nullptr;
        curl_httppost* lastptr = nullptr;

        // 添加文件字段，直接从本地路径读取文件内容
        curl_formadd(&formpost, &lastptr,
                     CURLFORM_COPYNAME, "file",
                     CURLFORM_FILE, localpath,
                     CURLFORM_END);

        // 添加 `path` 字段
        curl_formadd(&formpost, &lastptr,
                     CURLFORM_COPYNAME, "path",
                     CURLFORM_COPYCONTENTS, cloudpath,
                     CURLFORM_END);

        // 添加 `isReserveName` 字段
        curl_formadd(&formpost, &lastptr,
                     CURLFORM_COPYNAME, "isReserveName",
                     CURLFORM_COPYCONTENTS, "true",
                     CURLFORM_END);

        // 设置表单数据到请求
        curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);

        // 设置头信息
        struct curl_slist* header_list = nullptr;
        header_list = curl_slist_append(header_list, "Content-Type: multipart/form-data");
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list);

        // 设置超时时间
        curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10);
        curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10);

        // 设置写入响应数据的函数
        std::string resPost0;
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&resPost0);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply_web);

        // 执行请求
        CURLcode res = curl_easy_perform(curl);
        if (res != CURLE_OK) {
            std::cerr << "http web failed: " << curl_easy_strerror(res) << std::endl;
        } else {
            std::cout << "http web success, response: " << resPost0 << std::endl;
            handleUploadResponse(resPost0, wavepath);  // 处理响应
        }

        // 清理
        curl_formfree(formpost);  // 释放表单数据
        curl_slist_free_all(header_list);  // 释放头部列表
        curl_easy_cleanup(curl);
    } else {
        std::cerr << ">>> curl init failed" << std::endl;
    }
}

void SOEFileWeb(char* localpath,char* cloudpath, char* wavepath)
{
	//示例ip，更换为实际ip即可
	SendFileWeb(WEB_FILEUPLOAD,localpath,cloudpath,wavepath);
}

void SOEFileWeb_test()
{
	char localpath[128] = {"./file_test.txt"};
	char cloudpath[128] = {"/comtrade/file_test.txt"};
	char wavepath[128] = {""};
	SOEFileWeb(localpath,cloudpath,wavepath);
	std::cout << "wavepath" << wavepath << std::endl;
}
/*/////////////////////////////////////////////////////////lnk10-24根据web接口修改/////////////////////////////////////////////////////////////*/
/*封装C可调用的台账更新函数 */////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

int update_one_terminal_ledger(terminal* update, int i,ied_t* ied,int terminal_index,int ied_take)			
{
	chnl_usr_t* chnl_usr = NULL;
	ied_usr_t* ied_usr = NULL;
	ied_usr = (ied_usr_t*)ied->usr_ext;

	// 将 update[i] 中的数据写入到 ied_usr 中
	if (strlen(update[i].terminal_id) != 0) {
	    apr_snprintf(ied_usr->terminal_id, sizeof(ied_usr->terminal_id), "%s", update[i].terminal_id);
	    printf("ied_usr->terminal_id: %s\n", ied_usr->terminal_id);
	}
	if (update[i].terminal_code != NULL) {
	    apr_snprintf(ied_usr->terminal_code, sizeof(ied_usr->terminal_code), "%s", update[i].terminal_code);
	    printf("ied_usr->terminal_code: %s\n", ied_usr->terminal_code);
	}
	if (update[i].tmnl_factory != NULL) {
	    apr_snprintf(ied_usr->tmnl_factory, sizeof(ied_usr->tmnl_factory), "%s", update[i].tmnl_factory);
	    printf("ied_usr->tmnl_factory: %s\n", ied_usr->tmnl_factory);
	}
	if (update[i].tmnl_status != NULL) {
	    apr_snprintf(ied_usr->tmnl_status, sizeof(ied_usr->tmnl_status), "%s", update[i].tmnl_status);
	    printf("ied_usr->tmnl_status: %s\n", ied_usr->tmnl_status);
	}
	if (update[i].dev_type != NULL) {
	    apr_snprintf(ied_usr->dev_type, sizeof(ied_usr->dev_type), "%s", update[i].dev_type);
	    printf("ied_usr->dev_type: %s\n", ied_usr->dev_type);
	}
	if (update[i].processNo != NULL) {
	    apr_snprintf(ied_usr->processNo, sizeof(ied_usr->processNo), "%s", update[i].processNo);
	    printf("ied_usr->processNo: %s\n", ied_usr->processNo);
	}
	if (update[i].dev_series != NULL) {
	    apr_snprintf(ied_usr->dev_series, sizeof(ied_usr->dev_series), "%s", update[i].dev_series);
	    printf("ied_usr->dev_series: %s\n", ied_usr->dev_series);
	} else {
	    apr_snprintf(ied_usr->dev_series, sizeof(ied_usr->dev_series), "%s", "");  // 默认为空字符串
	    printf("ied_usr->dev_series (default): %s\n", ied_usr->dev_series);
	}
	if (update[i].dev_key != NULL) {
	    apr_snprintf(ied_usr->dev_key, sizeof(ied_usr->dev_key), "%s", update[i].dev_key);
	    printf("ied_usr->dev_key: %s\n", ied_usr->dev_key);
	} else {
	    apr_snprintf(ied_usr->dev_key, sizeof(ied_usr->dev_key), "%s", "");  // 默认为空字符串
	    printf("ied_usr->dev_key (default): %s\n", ied_usr->dev_key);
	}

	ied_usr->dev_idx = terminal_index;        //终端排号，g_node下标
	printf("dev_idx: %d\n", ied_usr->dev_idx);

	ied->channel[0].channel_type = CHANNEL_TYPE_IPV4;  // channel
	ied->channel[0].addr_str[LONGNAME - 1] = 0;  // DEV_IP
	if (update[i].addr_str != NULL) {
	    ied->channel[0].addr = ntohl(inet_addr(update[i].addr_str));  // DEV_IP
	    strncpy(ied->channel[0].addr_str, update[i].addr_str, LONGNAME - 1);  // DEV_IP
	    printf("ied_usr->addr_str: %s\n", ied->channel[0].addr_str);
	} else {
	    ied->channel[0].addr = ntohl(inet_addr("0.0.0.0"));  // DEV_IP
	    strncpy(ied->channel[0].addr_str, update[i].addr_str, LONGNAME - 1);  // DEV_IP
	    printf("ied_usr->addr_str: %s\n", ied->channel[0].addr_str);
	}
	if (update[i].port != NULL) {
	    int port = 102;
	    if (stringToInt(update[i].port, &port)) {
	        // 转换成功，portStr全为数字，并且已经转换为int类型的port  
	        ied->channel[0].port = port;  // DEV_PortID
	        printf("ied_usr->port: %d\n", ied->channel[0].port);  // DEV_PortID
	    } else {
	        ied->channel[0].port = 102;  // DEV_PortID
	        printf("ied_usr->port: %s, 非合法端口. 使用默认端口: %d\n", update[i].port, ied->channel[0].port);  // DEV_PortID
	    }
	}

	if (update[i].timestamp != NULL && strlen(update[i].timestamp) > 0) {
	    // 构造struct tm对象
	    struct tm timeinfo = {0};  // 初始化为0
	    // 假设时间字符串格式为 "YYYY-MM-DD HH:MM:SS"
	    // 使用sscanf从字符串中提取各个时间字段
	    if (sscanf(update[i].timestamp, "%4d-%2d-%2d %2d:%2d:%2d",
	               &timeinfo.tm_year, &timeinfo.tm_mon, &timeinfo.tm_mday,
	               &timeinfo.tm_hour, &timeinfo.tm_min, &timeinfo.tm_sec) == 6) {
	        // 将年份从1900开始计算
	        timeinfo.tm_year -= 1900;
	        // 月份从0开始计算，减去1
	        timeinfo.tm_mon -= 1;
	        // 对tm_isdst进行初始化，通常可以设置为-1，由mktime自动判断
	        timeinfo.tm_isdst = -1;
	        // 使用mktime将struct tm转换为time_t
	        time_t raw_time = mktime(&timeinfo);
	        // 判断mktime是否成功
	        if (raw_time != -1) {
	            ied_usr->time = (long long)raw_time;
	            printf("ied_usr->time: %lld\n", ied_usr->time);
	        } else {
	            printf("Error: mktime failed.\n");
	        }
	    } else {
	        printf("Error: sscanf failed. Invalid timestamp format.\n");
			return -1;
	    }
	}

	//如果是使用已有空间则不需要再申请
	if(!ied_take){
		chnl_usr = (chnl_usr_t*)apr_pcalloc(g_init_pool, sizeof(chnl_usr_t));
		ied->channel[0].connect = chnl_usr;
		g_pt61850app->chnl_counts++;	//新增的需要添加
	}
	else{
		chnl_usr = (chnl_usr_t*)ied->channel[0].connect;
	}

	chnl_usr->chnl = &(ied->channel[0]);//如果是已有的ied，这个值是原本就存在的，再赋值一次
	chnl_usr->chnl_id = 0;
	chnl_usr->m_state = CHANNEL_DISCONNECTED;
	chnl_usr->m_ClosedMsTime = NEXT_CONNECT_TIME * (-1);

	// 将 monitorData 中的数据写入到 LD_info 中
	int count_real_monitor = 0;	//遍历监测点台账的计数器
	int j;
	for (j = 0; j < 10 && update[i].line[j].monitor_id[0] != '\0'; ++j) {
	    monitor monitor_data = update[i].line[j];
		//监测点计数
		count_real_monitor++;
	    // 初始化用于值拷贝的 LD_info，里面涉及指针的部分都为空
	    LD_info_t line_info;
	    memset(&line_info, 0, sizeof(line_info));

		char logical_device_seq[64];
	    // 填充监测点信息
	    strncpy(line_info.mp_id, monitor_data.monitor_id, sizeof(line_info.mp_id) - 1);
	    strncpy(line_info.name, monitor_data.monitor_name, sizeof(line_info.name) - 1);	    
	    strncpy(line_info.voltage_level, monitor_data.voltage_level, sizeof(line_info.voltage_level) - 1);
	    strncpy(line_info.v_wiring_type, monitor_data.terminal_connect, sizeof(line_info.v_wiring_type) - 1);
	    strncpy(line_info.monitor_status, monitor_data.status, sizeof(line_info.monitor_status) - 1);
		strncpy(line_info.terminal_code, monitor_data.terminal_code, sizeof(line_info.terminal_code) - 1);
		strncpy(logical_device_seq, monitor_data.logical_device_seq, sizeof(logical_device_seq) - 1);
		if (isCharPtrEmpty(logical_device_seq)) {
		    line_info.cpuno = 1;  // 默认监测点实例号1
		    printf("logical_device_seq: is null, set cpuno: %d\n", (int)line_info.cpuno);
		} else {
		    line_info.cpuno = atoi(logical_device_seq);
		    printf("logical_device_seq: %d\n", (int)line_info.cpuno);
		}
		line_info.line_id = count_real_monitor;  // 记录终端排号

		printf("line_id: %d\n", line_info.line_id);
		printf("mp_id: %s\n", line_info.mp_id);
		printf("terminal_code: %s\n", line_info.terminal_code);
		printf("voltage_level: %s\n", line_info.voltage_level);
		printf("v_wiring_type: %s\n", line_info.v_wiring_type);
		printf("monitor_status: %s\n", line_info.monitor_status);
		printf("name: %s\n", line_info.name);

		//lnk20250214角形
		if (strcmp(line_info.v_wiring_type, "02") == 0)
		{
			isdelta_flag = 1;	//存在一个监测点为角型接线则这个前置就要启动第二个配置列表
			cout << "monitor_id" << line_info.mp_id << "v_wiring_type:" << line_info.v_wiring_type << "is delta wiring:" << isdelta_flag << endl;
		}

	    // 填充时间戳
	    if (update[i].timestamp[0] != '\0') {
		    struct tm timeinfo;
		    char timestamp[64];
		    // 假设update[i].timestamp格式为 "YYYY-MM-DD HH:MM:SS"
		    // 例如："2023-01-14 12:34:56"
		    sscanf(update[i].timestamp, "%4d-%2d-%2d %2d:%2d:%2d",
		           &timeinfo.tm_year, &timeinfo.tm_mon, &timeinfo.tm_mday,
		           &timeinfo.tm_hour, &timeinfo.tm_min, &timeinfo.tm_sec);
		    // 将年份从1900年开始计算
		    timeinfo.tm_year -= 1900;
		    // 月份从0开始，减1
		    timeinfo.tm_mon -= 1;
		    // 对tm_isdst进行初始化，通常可以设置为-1，由mktime自动判断
		    timeinfo.tm_isdst = -1;
		    // 使用mktime将struct tm转换为time_t
		    time_t raw_time = mktime(&timeinfo);
		    // 判断mktime是否成功
		    if (raw_time != -1) {
		        line_info.time = (long long)raw_time;
		        printf("time: %lld\n", line_info.time);
		    } else {
		        printf("Error: mktime failed.\n");
				return -1;
		    }
		}				
		line_info.read_flag = 1;				//监测点有效
	    // 填充 LD_info
		if (ied && ied->usr_ext && line_info.cpuno && ((int)line_info.cpuno < 10)) {
		    char str[256];
		    byte_t cpuno = line_info.cpuno;	//使用新台账的逻辑序列号，在使用原有ied的情况下，如果序列号数量小于原有数量，那么新的部分会被覆盖，如果删除时没有清理，原有的其他部分会仍存在内存中，但不会被使用
		    printf("cpuno: %d\n", (int)line_info.cpuno);
		    printf("index cpuno: %d\n", cpuno - 1);

		    ied_usr = (ied_usr_t*)ied->usr_ext;
		    //ied_usr->LD_info[cpuno - 1] = line_info;//这个放在后面，因为需要先判断原有的指针
		    //ied_usr->LD_info[cpuno - 1].ied = ied;  //这个放在后面，因为需要先判断原有的指针

			//用来记录可能的已有的ldname
			char *ldname = NULL;

			//用来记录可能已有的报告、日志数组
			loginfo_t			**loginfo = NULL;
			rptinfo_t			**rptinfo = NULL;

			//调试
			printf("check error111 !!!!!!!!!!!!!!\n");

			

/////////			//清空已有的补招数组占用空间
			if (ied_usr->LD_info[cpuno - 1].autorecallcount != 0) {
				for (int j = 0; j < ied_usr->LD_info[cpuno - 1].autorecallcount; j++) {
					if(NULL != ied_usr->LD_info[cpuno - 1].autorecall[j]){
						delete ied_usr->LD_info[cpuno - 1].autorecall[j];
					}					
				}
				if(NULL != ied_usr->LD_info[cpuno - 1].autorecall){
					delete ied_usr->LD_info[cpuno - 1].autorecall;
				}
				
				ied_usr->LD_info[cpuno - 1].autorecallcount = 0;
			}

			//调试
			printf("check error112 !!!!!!!!!!!!!!\n");

////////			//记录原有的报告和日志数组
			loginfo = ied_usr->LD_info[cpuno - 1].loginfo?ied_usr->LD_info[cpuno - 1].loginfo:NULL;
			rptinfo = ied_usr->LD_info[cpuno - 1].rptinfo?ied_usr->LD_info[cpuno - 1].rptinfo:NULL;

			//调试
			printf("check error113 !!!!!!!!!!!!!!\n");

    		//避免重复分配内存，如果使用已存在的ied，那么它之前初始化就分配了哈希表，如果在删除台账时没有清除，则需要将原来的清除
    		if (ied_usr->LD_info[cpuno - 1].ht_fcd != NULL) {
    		    apr_hash_clear(ied_usr->LD_info[cpuno - 1].ht_fcd);
    		}
    		if (ied_usr->LD_info[cpuno - 1].ht_full_fcda != NULL) {
    		    apr_hash_clear(ied_usr->LD_info[cpuno - 1].ht_full_fcda);
    		}

			//调试
			printf("check error116 !!!!!!!!!!!!!!\n");

			//这些可能是已有的内存，如果存在则需要清除，（在台账删除时就应该清除）
			apr_snprintf(str, sizeof(str), "PQMonitorPQM%d", cpuno);

			// 仅在没有值时更新 LD_name，避免重复分配内存
			if (ied_usr->LD_info[cpuno - 1].LD_name == NULL) {

				//lnk20250208调试用
				std::cout << "new space for LD_name" << std::endl;
			  
				//lnk20250208不使用apr_pstrdup，使用固定大小，后续都在这块内存上直接复用
				//ied_usr->LD_info[cpuno - 1].LD_name = apr_pstrdup(g_init_pool, str);
				// 从 g_init_pool 内存池中分配固定 256 字节的内存
				ied_usr->LD_info[cpuno - 1].LD_name = (char *)apr_palloc(g_init_pool, 256);

				// 清空内存，防止残留数据
				memset(ied_usr->LD_info[cpuno - 1].LD_name, 0, 256);

				// 将 str 中的内容复制到预先分配的内存中，最多复制 256 字节（包含结束符）
				apr_cpystrn(ied_usr->LD_info[cpuno - 1].LD_name, str, 256);

			} else {//已有则替换，在原有空间上覆盖

				//lnk20250208调试用
				std::cout << "old space for LD_name:" << ied_usr->LD_info[cpuno - 1].LD_name <<std::endl;

				// 清空内存，防止残留数据
				memset(ied_usr->LD_info[cpuno - 1].LD_name, 0, 256);

				printf("check error333 !!!!!!!!!!!!!!\n");

				apr_cpystrn(ied_usr->LD_info[cpuno - 1].LD_name, str, 256);	//原有空间覆盖

				printf("check error222 !!!!!!!!!!!!!!\n");
			}

			ldname = ied_usr->LD_info[cpuno - 1].LD_name;

			//调试
			printf("check error114 !!!!!!!!!!!!!!\n");

			ied_usr->LD_info[cpuno - 1] = line_info;//这个放在后面，因为需要先判断原有的指针
		    ied_usr->LD_info[cpuno - 1].ied = ied;  //这个放在后面，因为需要先判断原有的指针

			//调试
			printf("check error115 !!!!!!!!!!!!!!\n");



			ied_usr->LD_info[cpuno - 1].LD_name = ldname;//记录原有的或者新的ldname

			//调试
			printf("ledger ied_usr->LD_info[cpuno - 1].LD_name: %s\n", ied_usr->LD_info[cpuno - 1].LD_name);

			ied_usr->LD_info[cpuno - 1].ht_fcd = apr_hash_make(g_init_pool);	//重新创建哈希表
			ied_usr->LD_info[cpuno - 1].ht_full_fcda = apr_hash_make(g_init_pool);

		    ied_usr->LD_info[cpuno - 1].rptcount = 0;	//报告数清零，这个值在ied_usr->LD_info[cpuno - 1] = line_info;时应该就已清0，报告的空间会在报告块初始化时分配
		    printf("rptcount: %d\n", ied_usr->LD_info[cpuno - 1].rptcount);

			//使用原有的报告日志空间
			ied_usr->LD_info[cpuno - 1].loginfo = loginfo;	//不管是新的还是旧的空间，后续初始化报告都会将它覆盖
			ied_usr->LD_info[cpuno - 1].rptinfo = rptinfo;

		    if (cpuno > ied->cpucount) {//新台账的逻辑号大于ied原有的cpu数（初始化是0），则更新cpu数，用来记录有多少个监测点
		        ied->cpucount = cpuno;
		    }
		}
		printf("Monitor Info [ID: %s, Name: %s] saved in LD_info\n", line_info.mp_id, line_info.name);
	}
	return 0;
}

////////////////////////////////////////////////////////////////////////台账更新记录日志
// 获取当前时间并格式化为 "YYYY-MM-DD HH:MM:SS"
std::string get_current_time() {
    std::time_t t = std::time(NULL);
    struct std::tm tm = *std::localtime(&t);

    char buffer[80];
    strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", &tm);
    return std::string(buffer);
}

// 写入日志条目
void write_log_entry(std::ofstream &log_file, const std::string &action, const std::string &terminal_id, const std::string &current_time) {
    log_file << terminal_id << "\t" << action << "time:" << current_time << "\n";
}

// 创建台账更新日志
void create_ledger_log(trigger_update_xml_t* ledger_update_xml) {

	std::cout << "create_ledger_log." << std::endl;

    std::string log_filename = "../etc/" + std::string(LEDGER_UPDATE_FN);
    std::ofstream log_file(log_filename.c_str(), std::ios::app);  // 以追加模式打开文件

    if (!log_file.is_open()) {
        std::cerr << "Failed to open log file: " << log_filename << std::endl;
        return;
    }

	std::vector<std::pair<std::string, std::string> > new_entries;      // 用于存储new的terminal_id和时间
	std::vector<std::pair<std::string, std::string> > modify_entries;   // 用于存储modify的terminal_id和时间
	std::vector<std::pair<std::string, std::string> > delete_entries;   // 用于存储delete的terminal_id和时间

    std::string current_time = get_current_time(); // 获取当前时间

    // 处理 new_updates
    for (int i = 0; i < ledger_update_xml->new_update_num; ++i) {
        std::string terminal_id = ledger_update_xml->new_updates[i].terminal_id;
        new_entries.push_back(std::make_pair(terminal_id, current_time));
    }

    // 处理 modify_updates
    for (int i = 0; i < ledger_update_xml->modify_update_num; ++i) {
        std::string terminal_id = ledger_update_xml->modify_updates[i].terminal_id;
        modify_entries.push_back(std::make_pair(terminal_id, current_time));
    }

    // 处理 delete_updates
    for (int i = 0; i < ledger_update_xml->delete_update_num; ++i) {
        std::string terminal_id = ledger_update_xml->delete_updates[i].terminal_id;
        delete_entries.push_back(std::make_pair(terminal_id, current_time));
    }

    // 写入日志文件
    if (!new_entries.empty()) {
        log_file << "<new>\n";
        for (size_t i = 0; i < new_entries.size(); ++i) {
            write_log_entry(log_file, "add", new_entries[i].first, new_entries[i].second);
        }
        log_file << "</new>\n";
    }

    if (!modify_entries.empty()) {
        log_file << "<modify>\n";
        for (size_t i = 0; i < modify_entries.size(); ++i) {
            write_log_entry(log_file, "modify", modify_entries[i].first, modify_entries[i].second);
        }
        log_file << "</modify>\n";
    }

    if (!delete_entries.empty()) {
        log_file << "<delete>\n";
        for (size_t i = 0; i < delete_entries.size(); ++i) {
            write_log_entry(log_file, "delete", delete_entries[i].first, delete_entries[i].second);
        }
        log_file << "</delete>\n";
    }

    log_file.close();
    std::cout << "Ledger log has been updated." << std::endl;
}	
///////////////////////////////////////////////////////////////////////////台账内存分配部分功能代码：未使用
// 删除指定的子池
void delete_sub_pool(const char* terminal_id) {
    std::list<std::pair<std::string, apr_pool_t*> >::iterator it;
    
    for (it = pool_list.begin(); it != pool_list.end(); ++it) {
        if (it->first == terminal_id) {
            apr_pool_destroy(it->second);  // 销毁子池
            pool_list.erase(it);  // 从容器中移除
            break;
        }
    }
}
//找对应的子池
apr_pool_t* find_sub_pool(const char* terminal_id) {
    std::list<std::pair<std::string, apr_pool_t*> >::iterator it;
    
    for (it = pool_list.begin(); it != pool_list.end(); ++it) {
        if (it->first == terminal_id) {
            return it->second;  // 找到对应的子池
        }
    }
    
    return NULL;  // 没有找到对应的子池
}
// 创建子池并添加到容器
apr_pool_t* create_sub_pool(apr_pool_t* parent_pool, const char* terminal_id) {
    apr_pool_t* new_sub_pool = NULL;

    // 在父池中创建一个子池
    apr_pool_create(&new_sub_pool, parent_pool);
    
    if (new_sub_pool == NULL) {
        return NULL;  // 创建失败
    }

    // 将子池和终端 ID 存储在容器中
    pool_list.push_back(std::make_pair(std::string(terminal_id), new_sub_pool));

    return new_sub_pool;
}
//////////////////////////////////////////////////////////////////////////////////////////////////
//台账变更的报告块初始化
int parse_rpt_log_ini_one(ied_t* ied)
{
	QMap<QString, QStringList*> rpt_cfg_strlists;
	QMap<QString, QStringList*> log_cfg_strlists;

	int	iedno, cpuno;
	ied_usr_t* ied_usr;
	LD_info_t* LD_info;
	char		buf[256];

	ied_usr = GET_IEDEXT_ADDR(ied);
	QString type;
	type.append(ied_usr->dev_type);
	if (!rpt_cfg_strlists.contains(type))
	{
		QStringList* rpt_temp = new QStringList();
		QStringList* log_temp = new QStringList();
		rpt_cfg_strlists.insert(type, rpt_temp);//报告控制列表
		log_cfg_strlists.insert(type, log_temp);//日志控制列表
		//g_DevFlag没有使用
		parse_one_rpt_log_ini(g_DevFlag, rpt_cfg_strlists[type], log_cfg_strlists[type], ied_usr->dev_type);
	}

	//lnk20250208调试用
	std::cout << "ied->cpucount:" << (int)(ied->cpucount) <<std::endl;

	for (cpuno = 0; cpuno < ied->cpucount; cpuno++) {//根据ied实际的检测点数遍历

		//lnk20250208调试用
		std::cout << "cpuno:" << cpuno << "log init !!!!!!" <<std::endl;

		LD_info = &(ied_usr->LD_info[cpuno]);

		//这些可能是已有的内存，经过判断才能从g_init_pool中分配内存，lnk20250122
		char str[256];
		char* tmp = Get_IED(ied_usr->dev_type);
		qDebug() << tmp << endl;
		apr_snprintf(str, sizeof(str), tmp, cpuno + 1);
		//ied_usr->LD_info[cpuno].LD_name = apr_pstrdup(g_init_pool, str);//lnk20250122

//lnk20250212重复申请删除
#if 0
		// 仅在没有值时更新 LD_name，避免重复分配内存
    	if (ied_usr->LD_info[cpuno].LD_name == NULL) {

			//lnk20250208调试用
			std::cout << "cpuno:" << cpuno << "apr_pstrdup" <<std::endl;

    		
			//lnk20250208不使用apr_pstrdup，使用固定大小，后续都在这块内存上直接复用
			//ied_usr->LD_info[cpuno].LD_name = apr_pstrdup(g_init_pool, str);
			// 从 g_init_pool 内存池中分配固定 256 字节的内存
			ied_usr->LD_info[cpuno].LD_name = (char *)apr_palloc(g_init_pool, 256);

			// 清空内存，防止残留数据
			memset(ied_usr->LD_info[cpuno].LD_name, 0, 256);

			// 将 str 中的内容复制到预先分配的内存中，最多复制 256 字节（包含结束符）
			apr_cpystrn(ied_usr->LD_info[cpuno].LD_name, str, 256);

    	} else {//已有则替换，在原有空间上覆盖

    		// 调试用
			std::cout << "strlen(str):" << strlen(str) << "strlen(ied_usr->LD_info[cpuno].LD_name)" << strlen(ied_usr->LD_info[cpuno].LD_name) <<std::endl;

			// 清空内存，防止残留数据
			memset(ied_usr->LD_info[cpuno].LD_name, 0, 256);

        	apr_cpystrn(ied_usr->LD_info[cpuno].LD_name, str, 256);//apr_palloc 只是分配了一个固定大小的内存块，而没有提供直接的机制来跟踪或验证它的空间是否已被使用或填充到最大值，直接覆盖即可

    	}
#endif
		//调试
		printf("logini ied_usr->LD_info[cpuno - 1].LD_name: %s\n", ied_usr->LD_info[cpuno].LD_name);

		delete[] tmp;//Get_IED中分配了内存，使用后删除

		//lnk20250208调试用
		std::cout << "cpuno:" << cpuno << " fill report control" <<std::endl;

		//初始化监测点的报告控制
		init_rptctrl_by_count(LD_info, rpt_cfg_strlists[type]->size());
		for (int i = 0; i < rpt_cfg_strlists[type]->size(); ++i) {
			apr_snprintf(buf, sizeof(buf), "%s", rpt_cfg_strlists[type]->at(i).toAscii().constData());
			fill_rptctrl_by_cfg(LD_info, i, buf);
		}
		//初始化监测点的日志控制
		init_logctrl_by_count(LD_info, log_cfg_strlists[type]->size());
		for (int i = 0; i < log_cfg_strlists[type]->size(); ++i) {
			apr_snprintf(buf, sizeof(buf), "%s", log_cfg_strlists[type]->at(i).toAscii().constData());
			char* tmp = Get_LDevice(ied_usr->dev_type);
			fill_logctrl_by_cfg(LD_info, i, buf, tmp);
			delete[] tmp;
		}
	}

	//报告控制块和日志控制块处理结束后清理容器
	for (QMap<QString, QStringList*>::iterator it1 = log_cfg_strlists.begin(); it1 != log_cfg_strlists.end(); ++it1)
	{
		delete it1.value();
	}
	for (QMap<QString, QStringList*>::iterator it2 = rpt_cfg_strlists.begin(); it2 != rpt_cfg_strlists.end(); ++it2)
	{
		delete it2.value();
	}
	rpt_cfg_strlists.clear();
	log_cfg_strlists.clear();

	return APR_SUCCESS;
}
////////////////////////////////////////////////////////////remdibtable
apr_status_t init_rem_dib_table_one(ied_t *ied)
{
	int pos = 0;
	int			iedno,chnl_no;
	struct in_addr	ip;
	chnl_usr_t	*chnl_usr;

	ied_usr_t* ied_usr;

	//插入的位置和g_node一样
	ied_usr = (ied_usr_t*)ied->usr_ext;
	pos = ied_usr->dev_idx - 1;

	std::cout << "!!!!!!!!!rem_dib_table pos is " << pos << std::endl;

	for(chnl_no=0 ; chnl_no<ied->chncount; chnl_no++) {	
		chnl_usr = (chnl_usr_t*)ied->channel[chnl_no].connect;//初始化时已根据最大数量申请空间
		g_pt61850app->chnl_usr[pos] = chnl_usr;

		std::cout << "!!!!!!!!!g_pt61850app pos " << pos << "is " << ied_usr->terminal_id << "is" << (chnl_usr == NULL?"NULL":"NOTNULL") << std::endl;

		ip.s_addr = htonl(ied->channel[chnl_no].addr);
		strcpy(chnl_usr->ip_str,inet_ntoa(ip));
		printf( " add_rem_dib_table  %s:%d \n",chnl_usr->ip_str ,ied->channel[chnl_no].port );
		add_rem_dib_table (pos++,chnl_usr->ip_str,ied->channel[chnl_no].port );//当前终端的IP端口记录到表中，这里要注意添加的下标，如果删除终端，这个表内的内容仍存在，再次使用时会被替换
		{
			char comm_str[256]; 
			memset(comm_str,0,256);
			apr_snprintf(comm_str,sizeof(comm_str),"%16s:%d\t\tinited",chnl_usr->ip_str,ied->channel[chnl_no].port);
			add_comm_log(comm_str);
		}
	}
	return APR_SUCCESS;
}
///////////////////////////////////////////////////////////////////////////////////////////////////清理ied
void clearLogInfo(loginfo_t *loginfo) {
    if (loginfo == nullptr) {
        return; // 如果传入的指针为空，直接返回
    }

    // 清空字符数组
    memset(loginfo->logName, 0, sizeof(loginfo->logName));

    // 清空其他非指针成员
    loginfo->IntgPd = 0;
    loginfo->reasonCode = 0;
    loginfo->TrgOpt = 0;

    loginfo->start_time = 0;
    loginfo->end_time = 0;
    loginfo->need_steady = 0;
    loginfo->need_voltage = 0;

    // 对指针成员进行清理，但不释放内存
    if (loginfo->lcbName != nullptr) {
        memset(loginfo->lcbName, 0, strlen(loginfo->lcbName)); // 清空字符串内容
    }
    if (loginfo->datasetName != nullptr) {
        memset(loginfo->datasetName, 0, strlen(loginfo->datasetName)); // 清空字符串内容
    }

    // 由于 LD_info 是指针，它不清理,仍指向上级
}

void clearRptInfo(rptinfo_t *rptinfo) {
    if (rptinfo == nullptr) {
        return; // 如果传入的指针为空，直接返回
    }

    // 清空字符数组和非指针成员
	rptinfo->instanceNeedSuffix = 0;
	rptinfo->TrgOpt = 0;

    memset(rptinfo->OptFlds, 0, sizeof(rptinfo->OptFlds));
    rptinfo->IntgPd = 0;
    rptinfo->report_PQ_type = 0;

    rptinfo->rpt_registered = 0;
    rptinfo->chnl_id = 0;

    rptinfo->m_LastDataTime = 0;
    rptinfo->m_LastGITime = 0;

    rptinfo->m_LastRegisterFailedTime = 0;
    rptinfo->m_LastUnRegisterFailedTime = 0;

    memset(rptinfo->m_EntryID, 0, sizeof(rptinfo->m_EntryID));
    rptinfo->m_curRptSuffix = 0;

    rptinfo->count = 0;
    rptinfo->rptNo = 0;
    rptinfo->flickerflag = 0;

    rptinfo->pstflag = 0;

    // 对指针成员进行清理，但不释放内存
    if (rptinfo->rptID != nullptr) {
        memset(rptinfo->rptID, 0, strlen(rptinfo->rptID)); // 清空字符串内容
    }

    // 由于 LD_info 是指针，它不需要清理，仍指向父级
    //rptinfo->LD_info = nullptr;

    // 对 RCBC_INFO 结构体指针进行处理
    if (rptinfo->m_rcb_info != nullptr) {
        // 如果需要，可以选择清理结构体内部内容，但不释放内存
        rptinfo->m_rcb_info = nullptr;//这里可以清空，因为这个指针指向的区域在连接通道关闭时会被清理
    }
}

void clearLDInfo(LD_info_t *ld_info) {
    if (ld_info == nullptr) {
		std::cout << "ldinfo is null" << std::endl;
        return;
    }

	//保留原来的ied指向

	//清空报告
	if (ld_info->rptinfo != nullptr) {
        for (int i = 0; i < ld_info->rptcount; ++i) {
            if (ld_info->rptinfo[i] != nullptr) {
                clearRptInfo(ld_info->rptinfo[i]); //清空报告控制块
            }
        }
    }
	std::cout << "clean RptInfo!!!" << std::endl;

	//清空日志
    if (ld_info->loginfo != nullptr) {
        for (int i = 0; i < ld_info->logcount; ++i) {
            if (ld_info->loginfo[i] != nullptr) {
                clearLogInfo(ld_info->loginfo[i]); //清空日志控制块
            }
        }
    }
	std::cout << "clean loginfo_t!!!" << std::endl;

	//清空补招
    if (ld_info->autorecall != nullptr) {
        for (int i = 0; i < ld_info->autorecallcount; ++i) {
            if (ld_info->autorecall[i] != nullptr) {
                memset(ld_info->autorecall[i], 0, sizeof(autorecall_t));
				delete ld_info->autorecall[i];	//删除数组元素空间，如果有正在补招的内容，则已经申请空间，需要释放
            }
        }
		delete ld_info->autorecall;	//删除数组空间
    }
	std::cout << "clean autorecall_t!!!" << std::endl;

    if (ld_info->ht_fcd != nullptr) {
        apr_hash_clear(ld_info->ht_fcd);
    }
    if (ld_info->ht_full_fcda != nullptr) {
        apr_hash_clear(ld_info->ht_full_fcda);
    }

    // 清空其他指针成员
	if (ld_info->name != nullptr) {
        memset(ld_info->name, 0, sizeof(char) * 256);
    }
    if (ld_info->LD_name != nullptr) {
        memset(ld_info->LD_name, 0, sizeof(char) * 256);
    }
    if (ld_info->mp_id != nullptr) {
        memset(ld_info->mp_id, 0, sizeof(char) * 256);
    }
    if (ld_info->voltage_level != nullptr) {
        memset(ld_info->voltage_level, 0, sizeof(char) * 256);
    }
    if (ld_info->v_wiring_type != nullptr) {
        memset(ld_info->v_wiring_type, 0, sizeof(char) * 256);
    }
    if (ld_info->monitor_status != nullptr) {
        memset(ld_info->monitor_status, 0, sizeof(char) * 64);
    }
    if (ld_info->terminal_code != nullptr) {
        memset(ld_info->terminal_code, 0, sizeof(char) * 256);
    }

	ld_info->cpuno = 0;	//清空逻辑序列号

	ld_info->time = 0; //台账更新时间清0
	ld_info->update_flag = 0; //监测点更新标志，暂不使用

	ld_info->rptRecvFlag = 0;//重置报告标志
	ld_info->rptRecvCheckFlag = 0;
	ld_info->rptPstRecvFlag = 0;
	ld_info->rptPstRecvCheckFlag = 0;

	ld_info->read_flag = 0;//监测点无效

    ld_info->rptcount = 0;
    ld_info->logcount = 0;
    ld_info->autorecallflag = 0;
    ld_info->autorecallcount = 0;

	//ld_info->group = 0; //不使用

	//清空实时数据部分
    ld_info->line_id = 0;
    ld_info->real_data = 0;
    ld_info->soe_data = 0;
    ld_info->limit = 0;
    ld_info->count = 0;

    //ld_info->SubV_Index = 0;	//不使用
    //ld_info->Dev_Index = 0;	//不使用
    //ld_info->Sub_Index = 0;	//不使用
    //ld_info->GD_Index = 0;	//不使用

	//清空暂态结构
	for (int i = 0; i < QVVR_NUM; ++i) {
        ld_info->qvvr[i].used_status = 0;
        ld_info->qvvr[i].QVVR_start = 0;
        ld_info->qvvr[i].QVVR_type = 0;
        ld_info->qvvr[i].QVVR_time = 0;
        ld_info->qvvr[i].QVVR_PerTime = 0.0f;
        ld_info->qvvr[i].QVVR_Amg = 0.0f;
        memset(ld_info->qvvr[i].QVVR_Rptname, 0, sizeof(ld_info->qvvr[i].QVVR_Rptname));  // 清空字符数组
        ld_info->qvvr[i].timestamp = 0;
    }
	ld_info->qvvr_idx = 0;

	memset(ld_info->FltNum, 0, sizeof(ld_info->FltNum));

    ld_info->RDRE_FltNum = 0;	//录波号清零
    

}

void clearIedUsr(ied_usr_t *ied_usr) {
    if (ied_usr == nullptr) {
		std::cout << "ied_usr is null" << std::endl;
        return;
    }

    // 清空 ied_usr_t 中的非指针部分
    //ied_usr->dev_idx = 0;//保留index
    ied_usr->dev_flag = UNUSED;
    ied_usr->last_call_wavelist_time = 0;
    ied_usr->time = 0;			//台账更新时间
    ied_usr->update_flag = 0;	//台账更新标志暂不使用

    // 清空指针部分，但不清理非空指针
    if (ied_usr->LD_info != nullptr) {

        // 如果 LD_info 不为空，清理它内部的内容
        for (int i = 0; i < MAX_CPUNO; ++i) {
			LD_info_t * ld =NULL;
			ld = (LD_info_t *)&ied_usr->LD_info[i];
            if (ld != NULL) {
                clearLDInfo(ld);
            }
        }
    }

    if (ied_usr->cookie != nullptr) {	//不使用
		std::cout << "cookie not null" << std::endl;
    }

    // 清空其他非指针部分，也可以不清0，后续都会覆盖
    memset(ied_usr->dev_type, 0, sizeof(ied_usr->dev_type));
    memset(ied_usr->dev_key, 0, sizeof(ied_usr->dev_key));
    memset(ied_usr->dev_series, 0, sizeof(ied_usr->dev_series));
    memset(ied_usr->terminal_id, 0, sizeof(ied_usr->terminal_id));
    memset(ied_usr->org_name, 0, sizeof(ied_usr->org_name));
    memset(ied_usr->maint_name, 0, sizeof(ied_usr->maint_name));
    memset(ied_usr->station_name, 0, sizeof(ied_usr->station_name));
    memset(ied_usr->tmnl_factory, 0, sizeof(ied_usr->tmnl_factory));
    memset(ied_usr->tmnl_status, 0, sizeof(ied_usr->tmnl_status));
    memset(ied_usr->terminal_code, 0, sizeof(ied_usr->terminal_code));
}

// 清空 channel 和 cpuinfo 的非指针部分
void clear_channel_and_cpuinfo(byte_t chncount, channel_t *channel, byte_t cpucount, cpuinfo_t *cpuinfo) {
    // 清空 channel 数组中的每个元素的非指针字段
    for (byte_t i = 0; i < chncount && (&channel[i] != NULL); ++i) {
        channel[i].master = 0;
        channel[i].channel_type = 0;
        memset(channel[i].addr_str, 0, LONGNAME);
        channel[i].addr = 0;
        channel[i].port = 0;
        channel[i].status = 0;
        channel[i].last_ticks = 0;
        channel[i].last_send_ticks = 0;
        channel[i].ied_id = 0;

		// 清理 channel 里的 chnl_usr_t 部分
		// 关闭连接时已清理，保留指针本身
    }

    // 清空 cpuinfo 数组中的每个元素的非指针字段
    for (byte_t i = 0; i < cpucount  && (&cpuinfo[i] != NULL); ++i) {
        cpuinfo[i].addr = 0;
        cpuinfo[i].status = 0;
        cpuinfo[i].templ = 0;
        memset(cpuinfo[i].name, 0, LONGNAME);
        cpuinfo[i].last_gi = 0;
        cpuinfo[i].last_gi_send = 0;
        cpuinfo[i].next_gi_send = 0;
        cpuinfo[i].last_ticks = 0;
        cpuinfo[i].last_send_ticks = 0;
    }
}

void clearIed(ied_t *ied) {
    if (ied == nullptr) {
        return;
    }

    // 清空 ied_t 的id
    ied->id = 0;		
    //ied->flags = 0;	//未使用
    //ied->type = 0;	//未使用

	//清理channel	//清理cpuinfo
	clear_channel_and_cpuinfo(ied->chncount,ied->channel,ied->cpucount,ied->cpuinfo);
    ied->chncount = 0;	//清空通道数
    ied->cpucount = 0;	//清空检测点数

	//名称清理
	memset(ied->name, 0, LONGNAME);

    //ied->station = 0;		//未使用
    //ied->node = 0;		//未使用
    //ied->frequency = 0;	//未使用
    //ied->delay = 0;		//未使用
    //ied->count = 0;		//未使用
	
	//数据组定义部分未使用
	//ied->groups = NULL;
	//ied->htgroups = NULL;

	//系统令牌未使用
    //ied->systoken_st = 0;

    //ied->index = 0;			//未使用
    ied->status = STATUS_NOINIT;		//设备状态设为未初始化
    //ied->last_ticks = 0;	//未使用
    //ied->last_gi = 0;		//未使用

    // 清空指针部分
    if (ied->usr_ext != nullptr) {
        ied_usr_t *ied_usr = (ied_usr_t*)ied->usr_ext;
        clearIedUsr(ied_usr);
    }

	if (ied->sys_ext != nullptr) {
		//不使用
    }

	if (ied->app_ext != nullptr) {
		//不使用
    }

}
/*封装C可调用的台账更新函数 */////////////////////////////////////////////////////////////////////////////////////////////////////////////////////





