
#include <QtCore/QCoreApplication>
#include <iostream>
#include <fstream>
#include <qdebug.h>

#include <QFile>
#include <QtXml/QDomDocument>
#include <QtXml/QDomElement>
#include <QtXml/QDomNode>
#include <QtXml/QDomNodeList>
#include <QtCore/qglobal.h>
#include <list> //C++ STL的list
#include <map>  //C++ STL的map
#include <QStringList>

#include <QDateTime>//zw修改 2023-08-22 存储数据合理性相关属性
#include <QMap>//zw修改 2023-08-22 存储数据合理性相关属性

#include "mms_json_inter.h" //json头文件
#include "../mms/db_interface.h" //json头文件
#include "../mms/rdb_client.h"		//台账更新引用接口

//lnk20241031用于上传和下载文件
#include "../json/cjson.h"

#include "../log4cplus/log4.h"//lnk添加log4

///////////////////////////////////////////////////////////////////////lnk20260305数据追踪相关
#include <QHash>
#include <QMutex>
#include <QMutexLocker>
#include <QMapIterator>
#include <QStringList>
#include <QByteArray>
#include <QList>

//全局追踪表：mp_id -> rpt_no -> remaining times
static QMutex g_trace_mutex;
static QHash<QString, QHash<int, int> > g_trace_map;

///////////////////////////////////////////////////lnk2024-10-21////////////////////////////////////////////////////////
extern void SendJsonAPI_web(const std::string& strUrl, const char* code, const std::string& json, char** ptr);
extern std::string WEB_INTEGRITY;
extern std::string WEB_COMFLAG;
extern std::string WEB_EVENT;
extern std::string WEB_FILEDOWNLOAD;
extern std::string G_CONNECT_TOPIC;
extern std::string DATA_TRACE_TOPIC;//lnk20260609数据追踪topic

extern int RECALL_ONLY_FLAG;

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

bool DEBUGOPEN = 0;

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
using namespace std;

extern std::string intToString(int number);

QString JSON_CONFIG_FN = QString("JiangSu_Config.xml");
#define APR_SUCCESS 1
#define APR_EBADPATH 0
#define APR_EBADF 0
const string PhsSTR = "ABCT";
extern int FILE_FLAG;

//lnk20250214
extern int isdelta_flag;
//江苏Kafka发送数据类定义-------------------------------------------------------------/*
class CEventData //SOE事件类
{
public:
	int nDataType;       //告警SOE事件类型
	QString type;        //参数等级type类型：0-DataType 1-监测点 2-剔除标记 3-发生时刻，毫秒 4-数据链表 5-相位 6-值索引 9-实时SOE事件
	QString triggerFlag; //告警SOE事件触发指标名称
	int nIndex;          //数据在每条线路LineInfo值数组中的位置
	
	QString desc;     //soe事件描述
	
	QString DO;          //数据对象名
	QString DA;          //数据属性名
	QString strFullName; //数据对象名 $ 数据属性名
};

class CDataValue //数据值类
{
public:
	QString strName;     //数据名
	float fValue;        //数据值         
	bool bIsValue;       //数据是否赋值成功标识
	int nIndex;          //数据在每条线路LineInfo值数组中的位置
	QString type;        //参数等级type类型：0-DataType 1-监测点 2-剔除标记 3-发生时刻，毫秒 4-数据链表 5-相位 6-值索引 9-实时SOE事件
	QString DO;          //数据对象名
	QString DA;          //数据属性名
	QString strFullName; //数据对象名 $ 数据属性名
	QString strCoefficient; //数据系数(字符型)
	float fCoefficient;  //数据系数(浮点型)
	QString strOffset;   //起始序号偏移量(字符型)
	int iOffset;         //起始序号偏移量(整型) = 江苏电科院臻迪数据项起始序号 - 装置数据项实际起始序号
	bool bIsAngle;       //角度标志 WW 2018-06-28
	bool bPlt;			 //长时闪变标识：true-长时闪变 false-短时闪变
	QString BaseFlag;    //zw修改 2023 - 8 - 14 为历史数据部分 Value节点新增指标-BaseFlag LimitUp LimitDown
	QString LimitUp;     //zw修改 2023 - 8 - 14 为历史数据部分 Value节点新增指标-BaseFlag LimitUp LimitDown
	QString LimitDown;   //zw修改 2023 - 8 - 14 为历史数据部分 Value节点新增指标-BaseFlag LimitUp LimitDown
	
	

	CDataValue()
	{
		fCoefficient = 1.0f; //数据系数(浮点型)
		iOffset = 0; //起始序号偏移量(整型) 
		bIsAngle = false; //非角度标志
		bPlt = false; //短时闪变标识
	}
};

class CSequence //相别(A、B、C、T)类
{
public:
	QString strSValue; //相别值  例：7：ABC三项，8：T相
	QString strSeq;    //相别  例：A、B、C、T
	QString type;      //参数等级type类型：0-DataType 1-监测点 2-剔除标记 3-发生时刻，毫秒 4-数据链表 5-相位 6-值索引 9-实时SOE事件
	list<CDataValue*> DataValueList; //数据值链表
};

class CItem //数据项类
{
public:
	QString strItemName;  //数据项名
	QString strItemValue; //数据项值
	QString type;         //参数等级type类型：0-DataType 1-监测点 2-剔除标记 3-发生时刻，毫秒 4-数据链表 5-相位 6-值索引 9-实时SOE事件
	list<CSequence*> SequenceList; //相别链表
};

class CMonitor //监测点类
{
public:
	QString strMonitor;    //监测点名
	QString type;          //参数等级type类型：0-DataType 1-监测点 2-剔除标记 3-发生时刻，毫秒 4-数据链表 5-相位 6-值索引 9-实时SOE事件
	list<CItem*> ItemList; //数据项链表
};

class CDataType //数据类型类
{
public:
	int iDataType;               //数据类型值：1-稳态 2-闪变 3-长闪
	QString type;                //参数等级type类型：0-DataType 1-监测点 2-剔除标记 3-发生时刻，毫秒 4-数据链表 5-相位 6-值索引 9-实时SOE事件
	int BaseFlag1;     //zw修改 2023-8-25 记录基础数据总个数
	int BaseFlag0;     //zw修改 2023-8-25 记录非基础数据个数
	list<CMonitor*> MonitorList; //监测点链表     
	list<CEventData*> SOEList;   //SOE事件链表   
};

class CTopic //Kafka Producer发送主题类
{
public:
	QString strTopic;              //Kafka Producer发送主题值
	list<CDataType*> DataTypeList; //数据类型链表
};

class XmlConfig //zw修改 2023 - 8 - 14 增加xml解析的配置类 
{
public:
	QString WavePhasicFlag;        //是否分相 0-不分相 1-分相 如果Flag=0 A，B，C配置成一样，如果Flag=1，A，B，C根据实际配置
	QString WavePhasicA;           
	QString WavePhasicB;
	QString WavePhasicC;
	QString TypeOfData; 			//闪变和统计是否合并 0-分开 1-合并
	QString IEDControl;		  		//例：LD0  lnk2026-5-13
	QString UnitOfTimeUnit;        //暂态事件持续事件单位：0 - 毫秒 1 - 秒  lnk20260127
	QString ValueOfTimeUnit;       //上送值的时间：UTC-UTC时间 beijing-北京时间
	QString WaveTimeFlag;          //录波文件的时间：UTC-UTC时间 beijing-北京时间
	QString IEDname;               //例：PQMonitor
	QString LDevicePrefix;         //例：PQM
	list<CEventData*> SOEList;   //SOE告警事件链表   
};

class XmlDataBase //zw修改 2023-8-30 增加解析数据库模型表数据类
{
public:
	QString MODEL_ID;//模型编码 guid
	QString TMNL_TYPE;//终端型号
	QString TMNL_FACTORY;//终端厂家
	QString FILE_PATH;//远端模型文件路径  lnk2024-10-28
	QString FILE_NAME;//oss文件存储路径
	QDateTime datetime;//更新时间 时间戳
};

class MP_RATIONALITY //zw修改 2023 - 8 - 22 增加数据不合理性记录类
{
public:
	double fValue;//zw修改 2023-08-22 第一次记录的不合理数值
	QDateTime dtvalue;//zw修改 2023-08-22 第一次记录的不合理数值出现时间
	int over_time;//zw修改 2023-08-22 该记录属性不合理数值出现次数
};

class Mn_Timespan //zw修改 2023-08-29 时间间隔保存类
{
public:
	QList<long long> timespan;//时间戳队列
	int msspan;

	Mn_Timespan()
	{
		msspan = 0;
	}
};

class Xmldata //zw修改 2023-08-30
{
public:
	XmlDataBase xmlbase;//xml数据库数据
	XmlConfig xmlcfg;//新増的xml节点解析数据
	list<CTopic*> topicList; //Kafka发送主题链表
	bool updataflag = true;
};

//-------------------------------------------------------------------------------------*/
//主程序已定义该变量

extern int FILE_FLAG;

QMutex kafka_data_list_mutex; //Kafka发送数据锁
QList<Ckafka_data_t> kafka_data_list; //kafka发送数据链表

QMutex oss_data_list_mutex; //oss发送数据锁 zw新增
QList<oss_data_t> oss_data_list; //oss发送数据链表 zw新增
//-------------------------------------------------------------------------------------*/

QMap<QString,Mn_Timespan*> data_timespan_list;//zw修改 2023 - 8 - 29 计算时间间隔

QMap<QString, Xmldata*> xmlinfo_list;//zw修改 保存所有型号对应的xml数据-数据库数据 新增的节点解析数据 kafka发送链表
XmlConfig xmlcfg;//zw修改 2023 - 8 - 14 新増xml节点解析的数据
list<CTopic *> topicList; //Kafka发送主题链表

int inited = false; //JiangSu_Config.xml是否初始化标识

XmlConfig xmlcfg2;//lnk2024 - 8 - 13 新増角型xml节点解析的数据
list<CTopic*> topicList2; //lnk2024-8-14角型Kafka发送主题链表
QMap<QString, Xmldata*> xmlinfo_list2;//lnk2024-8-14 保存角型所有型号对应的xml数据-数据库数据 新增的节点解析数据 kafka发送链表

extern int isdelta_flag;//lnk2024-8-16 角型接线标志

///////////////////////////////////////////////lnk20241021替换web接口//////////////////////////////////
void connectlog_pgsql(char* id,char* datetime,int status);
///////////////////////////////////////////////lnk20241021替换web接口//////////////////////////////////

/////////////////////////////////////////////////////////////////////////////////////////////lnk20260305数据追踪
static QString escape_json_string(const QString& s)
{
    QString out = s;
    out.replace("\\", "\\\\");
    out.replace("\"", "\\\"");
    out.replace("\r", "\\r");
    out.replace("\n", "\\n");
    out.replace("\t", "\\t");
    return out;
}

// 打开追踪：每个报告各追踪一次
void process_trace_command(const std::string& id, int times)
{
    (void)times;
    QString qid = QString::fromStdString(id).trimmed();
    if (qid.isEmpty()) return;

    QList<int> rpt_nos;

    QByteArray qid_bytes = qid.toLocal8Bit();

    pthread_mutex_lock(&mtx);
    LD_info_t *ld_info = find_LD_info_only_from_mp_id(qid_bytes.data());
    if (ld_info != NULL && ld_info->rptinfo != NULL && ld_info->rptcount > 0) {
        for (int i = 0; i < ld_info->rptcount; ++i) {
            if (ld_info->rptinfo[i] == NULL)
                continue;

            int rpt_no = ld_info->rptinfo[i]->rptNo;
            if (!rpt_nos.contains(rpt_no))
                rpt_nos.append(rpt_no);
        }
    }
    pthread_mutex_unlock(&mtx);

    if (rpt_nos.isEmpty()) {
        cout << "[TRACE] mp_id=" << id << " has no report info" << endl;
        return;
    }

    QMutexLocker lk(&g_trace_mutex);
    QHash<int, int>& rpt_map = g_trace_map[qid];
    for (int i = 0; i < rpt_nos.size(); ++i) {
        int rpt_no = rpt_nos.at(i);
        rpt_map[rpt_no] = 1;
        cout << "[TRACE] mp_id=" << id << " add rpt_no=" << rpt_no
             << " left=" << rpt_map.value(rpt_no) << endl;
    }
}

// 查询是否要追踪
static bool trace_is_enabled(const QString& mp_id, int rpt_no)
{
    QMutexLocker lk(&g_trace_mutex);
    QHash<QString, QHash<int, int> >::const_iterator mp_it = g_trace_map.constFind(mp_id);
    if (mp_it == g_trace_map.constEnd())
        return false;

    QHash<int, int>::const_iterator rpt_it = mp_it.value().constFind(rpt_no);
    return (rpt_it != mp_it.value().constEnd() && rpt_it.value() > 0);
}

// 命中一次并扣减；扣到 0 自动删
static void trace_hit_and_decrement(const QString& mp_id, int rpt_no)
{
    QMutexLocker lk(&g_trace_mutex);
    QHash<QString, QHash<int, int> >::iterator mp_it = g_trace_map.find(mp_id);
    if (mp_it == g_trace_map.end()) return;

    QHash<int, int>::iterator rpt_it = mp_it.value().find(rpt_no);
    if (rpt_it == mp_it.value().end()) return;

    int left = rpt_it.value();
    left -= 1;
    if (left <= 0)
        mp_it.value().erase(rpt_it);
    else
        rpt_it.value() = left;

    if (mp_it.value().isEmpty())
        g_trace_map.erase(mp_it);
}

//追踪61850原始数据
static QString build_mms_json_object(const json_block_data* data)
{
    QString json = "{";

    QMapIterator<QString, double> it(data->mms_str_map);
    bool first = true;

    while (it.hasNext()) {
        it.next();

        if (!first)
            json += ",";

        json += QString("\"%1\":%2")
                    .arg(escape_json_string(it.key()))
                    .arg(QString::number(it.value(), 'g', 15));

        first = false;
    }

    json += "}";

    return json;
}

static QString build_trace_json(const json_block_data* data, const char *v_wiring_type, const char *rpt_id, int rpt_no)
{
    if (!data) return "{}";

    QString mms_json = build_mms_json_object(data);
    QString wiring_type = v_wiring_type ? QString::fromLocal8Bit(v_wiring_type) : "";
    QString rpt = rpt_id ? QString::fromLocal8Bit(rpt_id) : "";

    QString json;
    json += "{";
    json += QString("\"mp_id\":\"%1\",").arg(escape_json_string(data->mp_id));
    json += QString("\"v_wiring_type\":\"%1\",").arg(escape_json_string(wiring_type));
    json += QString("\"rpt_id\":\"%1\",").arg(escape_json_string(rpt));
    json += QString("\"rpt_no\":%1,").arg(rpt_no);
    json += QString("\"func_type\":%1,").arg(data->func_type);
    json += QString("\"data_time\":%1,").arg(QString::number((qlonglong)data->time));
    json += QString("\"voltage_level\":\"%1\",").arg(QString::number(data->voltage_level, 'f', 6));
    json += QString("\"dev_type\":\"%1\",").arg(escape_json_string(data->dev_type));
    json += QString("\"mms_json\":%1").arg(mms_json);
    json += "}";

    return json;
}

static void send_trace_if_needed(json_block_data* pdata, const char *v_wiring_type, const char *rpt_id, int rpt_no)
{
    const QString mp_id_q = pdata->mp_id;
    if (trace_is_enabled(mp_id_q, rpt_no)) {

        // 1) 组 json
        QString jsonText = build_trace_json(pdata, v_wiring_type, rpt_id, rpt_no);

        // 2) 组 KafkaData
        Ckafka_data_t KafkaData;
        KafkaData.monitor_id = pdata->monitorId;
        KafkaData.mp_id = pdata->mp_id;
	    KafkaData.strTopic = QString::fromStdString(DATA_TRACE_TOPIC);
        KafkaData.strText = jsonText;

        kafka_data_list_mutex.lock();
        kafka_data_list.append(KafkaData);
        kafka_data_list_mutex.unlock();

        // 3) 次数 -1
        trace_hit_and_decrement(mp_id_q, rpt_no);
    }
}

int trace_json_block_data(char v_wiring_type[], json_block_data *data, const char *rpt_id, int rpt_no)
{
    send_trace_if_needed(data, v_wiring_type, rpt_id, rpt_no);
    return 1;
}

int trace_json_is_enabled(const char *mp_id, int rpt_no)
{
    QString mp_id_q = mp_id ? QString::fromLocal8Bit(mp_id).trimmed() : "";
    if (mp_id_q.isEmpty())
        return 0;

    return trace_is_enabled(mp_id_q, rpt_no) ? 1 : 0;
}

////////////////////////////////////////////////////////////////////////////////////////////lnk20250710添加频率值存储
struct mp_freq_save {
    double G_FREQ;
    double FREQ;
    double MAX_FREQ;
    double MIN_FREQ;

    mp_freq_save()
        : G_FREQ(0.0), FREQ(0.0), MAX_FREQ(0.0), MIN_FREQ(0.0) {}
};
std::map<std::string,mp_freq_save> mp_freq_save_map;

//lnk20250520 获取映射文件中的一些数据/////////////////////////////////////////////////////////////////
bool get_xml_config_by_dev_type(const char* dev_type, XmlConfigC* out_cfg) {
    if (!dev_type || !out_cfg) 
	{
		printf("null dev_type");
		return false;
	}

	memset(out_cfg, 0, sizeof(*out_cfg));

    QString dev_type_q = QString::fromUtf8(dev_type);
    QMap<QString, Xmldata*>::iterator it = xmlinfo_list.find(dev_type_q);
    if (it == xmlinfo_list.end() || it.value() == nullptr) {
		printf("this dev_type not contain");
        return false;
    }

    const XmlConfig& cfg = it.value()->xmlcfg;

    // 将 QString 复制到结构体中的 char[]，确保不越界
    strncpy(out_cfg->WavePhasicFlag,  cfg.WavePhasicFlag.toUtf8().constData(), sizeof(out_cfg->WavePhasicFlag) - 1);
    strncpy(out_cfg->WavePhasicA,     cfg.WavePhasicA.toUtf8().constData(),    sizeof(out_cfg->WavePhasicA) - 1);
    strncpy(out_cfg->WavePhasicB,     cfg.WavePhasicB.toUtf8().constData(),    sizeof(out_cfg->WavePhasicB) - 1);
    strncpy(out_cfg->WavePhasicC,     cfg.WavePhasicC.toUtf8().constData(),    sizeof(out_cfg->WavePhasicC) - 1);
    strncpy(out_cfg->UnitOfTimeUnit,  cfg.UnitOfTimeUnit.toUtf8().constData(), sizeof(out_cfg->UnitOfTimeUnit) - 1);
	strncpy(out_cfg->TypeOfData,  	  cfg.TypeOfData.toUtf8().constData(), 	   sizeof(out_cfg->TypeOfData) - 1);	out_cfg->TypeOfData[sizeof(out_cfg->TypeOfData) - 1] = '\0';//lnk20260127
    strncpy(out_cfg->ValueOfTimeUnit, cfg.ValueOfTimeUnit.toUtf8().constData(),sizeof(out_cfg->ValueOfTimeUnit) - 1);
    strncpy(out_cfg->WaveTimeFlag,    cfg.WaveTimeFlag.toUtf8().constData(),   sizeof(out_cfg->WaveTimeFlag) - 1);
	strncpy(out_cfg->IEDControl,      cfg.IEDControl.toUtf8().constData(),     sizeof(out_cfg->IEDControl) - 1);//lnk2026-5-13
    strncpy(out_cfg->IEDname,         cfg.IEDname.toUtf8().constData(),        sizeof(out_cfg->IEDname) - 1);
    strncpy(out_cfg->LDevicePrefix,   cfg.LDevicePrefix.toUtf8().constData(),  sizeof(out_cfg->LDevicePrefix) - 1);

    return true;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//lnk2024-8-16 适配角型接线
bool ParseXMLConfig2(int xml_flag, XmlConfig *cfg, list<CTopic*> *ctopiclist,QString path) //解析JiangSu_Config.xml配置文件
{
	//注：①#7#代表通配符，用于通配数据类型 采用8421码，8-CP95 4-最小值 2-最大值 1-平均值
	//    ②%2,50%代表通配符，用于通配谐波数据，采用范围编码，第一个数字表示谐波起始号，第二个数字谐波结束号
	//    ③SEQ=后面的值采用8421码 8-T 4-C 2-B 1-A
	//注：type类型：0-DataType 1-监测点 2-剔除标记 3-发生时刻，毫秒 4-数据链表 5-相位 6-值索引 9-实时SOE事件 11-实时SOE事件	
	QString strPhasic[4] = { "A", "B", "C", "T" }; //数组枚举 相别(A-T)
	QString strLine[4] = { "AB", "BC", "CA", "T" }; //lnk2024-8-14数组枚举 角型相别(AB-T)
	int nStart = 1, nEnd = 1; //谐波起、止次数
	QString strValueTemp; //临时存放谐波次数字符串  例：%0,49% 或 %2,50%

	//加载JiangSu_Config.xml配置文件
	//QString xml_dir = QString("D:/")+QString("PQD-9k/config/"); //相对路径读取xml失败，此处改用绝对路径！ zl 2018-11-14 15:43:34
	QDomDocument doc;   //新建QDomDocument类对象，它代表一个XML文档
	if ("not define" == path) {
		QString xml_dir = QString("../") + QString("etc/"); //Linux下调试路径
		QFile file(xml_dir + JSON_CONFIG_FN);
		if (!file.open(QIODevice::ReadOnly | QFile::Text)) //以只读方式打开xml
		{
			return 0;
		}
		if (!doc.setContent(&file)) //将文件内容读到doc中
		{
			file.close();
			return 0;
		}
		file.close();
		cout << "not define xml" << endl;
	}
	else {
		QString tmppath;
		tmppath.append("/FeProject/dat/").append(path).append(".xml");
		QFile file(tmppath);
		if (!file.open(QIODevice::ReadOnly | QFile::Text)) //以只读方式打开xml
		{
			return 0;
		}
		if (!doc.setContent(&file)) //将文件内容读到doc中
		{
			file.close();
			return 0;
		}
		file.close();
		cout << "define xml" << endl;
	}
	//将xml文件内容读到doc中
	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(); //Topic节点

			if ("Topic" == strTag)//zw修改 2023 - 8 - 14 增加判断 将topic节点和其他节点的解析分离
			{
				CTopic* topic = new CTopic(); //发送主题类指针
				topic->strTopic = e.attribute("name"); //发送主题名
				ctopiclist->push_back(topic); //添加 Kafka发送主题链表

				//zw修改 2023 - 8 - 14 为历史数据部分 Value节点新增指标-BaseFlag LimitUp LimitDown
				if ("Topic" == strTag && ("HISDATA" == topic->strTopic || "RTDATA" == topic->strTopic)) //①读取Topic，HISDATA、RTDATA主题---------------------------------------------------
				{
					QDomNodeList list = e.childNodes(); //获得元素Topic的所有子节点的列表
					for (int i = 0; i < list.count(); i++) //遍历 DataType列表
					{
						QDomNode node = list.at(i); //node1 <DataType>
						if (node.isElement())
						{
							CDataType* dt = new CDataType(); //数据类型指针
							dt->iDataType = node.toElement().attribute("value").toInt(); //数据类型值(1-实时/历史稳态、2-实时/历史闪变、3-实时/历史暂态、4-补招稳态、5-补招闪变、6-补招暂态)
							dt->type = node.toElement().attribute("type"); //参数等级
							dt->BaseFlag0 = 0;
							dt->BaseFlag1 = 0;
							topic->DataTypeList.push_back(dt); //添加 数据类型链表

							QString strTag2 = node.toElement().tagName(); //DataType节点
							if ("DataType" == strTag2) //②读取数据类型DataType
							{
								QDomNodeList list2 = node.childNodes(); //获得元素DataType的所有子节点的列表  
								for (int i2 = 0; i2 < list2.count(); i2++) //遍历 Monitor列表
								{
									QDomNode node2 = list2.at(i2); //node2 <Monitor>
									if (node2.isElement())
									{
										CMonitor* mt = new CMonitor(); //监测点类型指针
										mt->strMonitor = node2.toElement().attribute("name"); //监测点名称 注：该值需要从Rpt解析中获取监测点号
										mt->type = node2.toElement().attribute("type"); //参数等级
										dt->MonitorList.push_back(mt); //添加 监测点链表

										QString strTag3 = node2.toElement().tagName(); //Monitor节点
										if ("Monitor" == strTag3) //③读取监测点Monitor
										{
											QDomNodeList list3 = node2.childNodes(); //获得元素Monitor的所有子节点的列表
											for (int i3 = 0; i3 < list3.count(); i3++) //遍历 Item列表
											{
												QDomNode node3 = list3.at(i3); //node3 <Item>
												if (node3.isElement())
												{
													CItem* it = new CItem(); //数据项类指针
													it->strItemName = node3.toElement().attribute("name"); //FLAG、TIME、V、I、PQ
													it->type = node3.toElement().attribute("type"); //参数等级
													if ("FLAG" == it->strItemName) //剔除标记(1：不剔除，0：剔除，默认剔除)
														it->strItemValue = node3.toElement().attribute("value"); //数据项值
													mt->ItemList.push_back(it); //添加 数据项链表

													QString strTag4 = node3.toElement().tagName(); //Item节点
													if ("Item" == strTag4) //④读取数据项Item
													{
														QDomNodeList list4 = node3.childNodes(); //获得元素Item的所有子节点的列表  
														for (int i4 = 0; i4 < list4.count(); i4++) //遍历 Sequence列表 
														{
															QDomNode node4 = list4.at(i4); //node4 <Sequence>
															if (node4.isElement())
															{
																QString strPhase = node4.toElement().attribute("value"); //相别
																if ((!xml_flag || ("V" != it->strItemName && "F_S" != it->strItemName && "F_L" != it->strItemName)) && "7" == strPhase) //⑤-①读取ABC三相数据 //lnk2024-8-14 角型判断
																{
																	for (int n = 0; n < 3; n++) //遍历 相别(ABC三相)
																	{
																		CSequence* sq = new CSequence(); //ABC三相相别类指针
																		sq->strSValue = node4.toElement().attribute("value"); //相别值(7：ABC三相、8：T相)
																		sq->type = node4.toElement().attribute("type"); //参数等级
																		sq->strSeq = strPhasic[n]; //相别赋值  例：A、B、C
																		it->SequenceList.push_back(sq); //添加 相别链表

																		QString strTag5 = node4.toElement().tagName(); //Sequence节点
																		if ("Sequence" == strTag5) //⑤读取相别Sequence
																		{
																			QDomNodeList list5 = node4.childNodes(); //获得元素Sequence的所有子节点的列表
																			for (int i5 = 0; i5 < list5.count(); i5++) //遍历 ABC三相Value列表
																			{
																				QDomNode node5 = list5.at(i5); //node5 <Value>
																				if (node5.isElement())
																				{
																					QDomElement e_Value = node5.toElement(); //将其转换为元素
																					QString strTag6 = e_Value.tagName(); //相别Sequence下 所有DataValue子节点
																					if ("Value" == strTag6) //⑥读取ABC三相Value
																					{
																						QString strDVName = e_Value.attribute("name"); //数据名
																						QString strDAName = e_Value.attribute("DA"); //数据属性名
																						
																						
																						if (strDAName.indexOf("l_phs*") >= 0){ //DA包含"l_phs*"//lnk20250221星形接线也可以接受PPV
																							strDAName = strDAName.replace("l_phs", "phs");
																							strDAName = strDAName.replace("*", strLine[n]);
																							
																						} //将DA相别*替换为具体相别(AB、BC、CA)  例：phsAB$cVal$mag$f

																						else if (strDAName.indexOf("phs*") >= 0) {//DA包含"phs*"
																							strDAName = strDAName.replace("*", sq->strSeq);} //将DA相别*替换为具体相别(A、B、C)  例：phsA$cVal$mag$f
																							
																							//⑥-①谐波数据读取(ABC三相)-------------------------------------
																						if (strDVName.indexOf("%") >= 0 && strDAName.indexOf("%-") >= 0) //数据名包含% 且 DA包含%-  例：V_%0,49%_MAX
																						{
																							QStringList strHarm1 = strDVName.split('%');
																							if (strHarm1.count() >= 2) //例：V_ | 0,49 | _MAX
																							{
																								strValueTemp = "%" + strHarm1.at(1) + "%"; //例：%0,49%
																								QStringList strHarm2 = strHarm1.at(1).split(','); //例：0,49
																								if (strHarm2.count() >= 2)
																								{
																									nStart = (strHarm2.at(0)).toInt(); //谐波起始次数  例：0
																									nEnd = (strHarm2.at(1)).toInt();   //谐波结束次数  例：49
																								}
																							}

																							QString substring = strDAName.mid(strDAName.indexOf("[") + 1, strDAName.indexOf("]") - strDAName.indexOf("[") - 1);
																							QStringList strDAList1 = substring.split('-');
																							int strDAoffset = (strDAList1.at(1)).toInt();

																							for (int i = nStart; i <= nEnd; i++) //遍历 ABC三相谐波次数
																							{
																								QString strDVNameTemp = strDVName; //临时 数据名
																								QString strDANameTemp = strDAName; //临时 数据属性名
																								CDataValue* dv1 = new CDataValue(); //ABC三相谐波数据值类指针
																								dv1->type = e_Value.attribute("type"); //参数等级
																								if (e_Value.attributes().contains("Coefficient")) {
																									dv1->strCoefficient = e_Value.attribute("Coefficient"); //数据系数(字符型)
																									dv1->fCoefficient = e_Value.attribute("Coefficient").toFloat(); //数据系数(浮点型)
																								}
																								dv1->strOffset = e_Value.attribute("Offset"); //起始序号偏移量(字符型)
																								dv1->iOffset = e_Value.attribute("Offset").toInt(); //起始序号偏移量(整型) = 江苏电科院臻迪数据项起始序号 - 装置数据项实际起始序号
																								dv1->DO = e_Value.attribute("DO"); //数据对象名
																								dv1->strName = strDVNameTemp.replace(strValueTemp, QString::number(i + e_Value.attribute("Offset").toInt())); //将数据名中%0,49%替换为具体数字  例：SI_%0,49%变为SI_1
																								dv1->DA = strDANameTemp.replace(substring, QString::number(i - strDAoffset)); //将DA中%-2替换为具体数字  例：phs*Har[1]$mag$f
																								
																								//zw修改 2023 - 8 - 14 为历史数据部分 Value节点新增指标-BaseFlag LimitUp LimitDown
																								if (e_Value.attributes().contains("BaseFlag"))
																								{
																									dv1->BaseFlag = e_Value.attribute("BaseFlag");
																									if (dv1->BaseFlag == "1") {
																										dt->BaseFlag1++;
																									}
																									else {
																										dt->BaseFlag0++;
																									}
																								}
																								else
																								{
																									dt->BaseFlag0++;
																									dv1->BaseFlag = "0";
																								}
																								if (e_Value.attributes().contains("LimitUp"))
																								{
																									dv1->LimitUp = e_Value.attribute("LimitUp");
																								}
																								else
																								{
																									dv1->LimitUp = "not define";
																								}
																								if (e_Value.attributes().contains("LimitDown"))
																								{
																									dv1->LimitDown = e_Value.attribute("LimitDown");
																								}
																								else
																								{
																									dv1->LimitDown = "not define";
																								}
																								if (!dv1->DO.isEmpty() && !dv1->DA.isEmpty()) //数据对象名和数据属性名均不为空                                              
																									dv1->strFullName = dv1->DO + "$" + dv1->DA;
																								else
																									dv1->strFullName = "not define";
																								sq->DataValueList.push_back(dv1); //添加 数据链表(ABC三相)
																							} //遍历ABC三相谐波次数 结束
																							
																						}
																						else //⑥-②非谐波数据读取(ABC三相)-------------------------------
																						{
																							CDataValue* dv2 = new CDataValue(); //ABC三相非谐波数据值类指针
																							dv2->strName = e_Value.attribute("name"); //数据名                                    
																							dv2->type = e_Value.attribute("type"); //参数等级
																							if (e_Value.attributes().contains("Coefficient")) {
																								dv2->strCoefficient = e_Value.attribute("Coefficient"); //数据系数(字符型)
																								dv2->fCoefficient = e_Value.attribute("Coefficient").toFloat(); //数据系数(浮点型)    
																							}                                                                                     
																							dv2->DO = e_Value.attribute("DO"); //数据对象名
																							dv2->DA = strDAName; //数据属性名

																							//zw修改 2023 - 8 - 14 为历史数据部分 Value节点新增指标-BaseFlag LimitUp LimitDown
																							if (e_Value.attributes().contains("BaseFlag"))
																							{
																								dv2->BaseFlag = e_Value.attribute("BaseFlag");
																								if (dv2->BaseFlag == "1") {
																									dt->BaseFlag1++;
																								}
																								else {
																									dt->BaseFlag0++;
																								}
																							}
																							else
																							{
																								dt->BaseFlag0++;
																								dv2->BaseFlag = "0";
																							}
																							if (e_Value.attributes().contains("LimitUp"))
																							{
																								dv2->LimitUp = e_Value.attribute("LimitUp");
																							}
																							else
																							{
																								dv2->LimitUp = "not define";
																							}
																							if (e_Value.attributes().contains("LimitDown"))
																							{
																								dv2->LimitDown = e_Value.attribute("LimitDown");
																							}
																							else
																							{
																								dv2->LimitDown = "not define";
																							}
																							if (!e_Value.attribute("PltFlag").isEmpty() && e_Value.attribute("PltFlag") == "True") //长时闪变标识
																								dv2->bPlt = true; //长时闪变标识
																							else
																								dv2->bPlt = false; //短时闪变 或 其他数据

																							if (!dv2->DO.isEmpty() && !dv2->DA.isEmpty()) //数据对象名和数据属性名均不为空                                              
																								dv2->strFullName = dv2->DO + "$" + dv2->DA;
																							else
																								dv2->strFullName = "not define";
																							sq->DataValueList.push_back(dv2); //添加 数据链表(ABC三相)
																						}
																					} //读取ABC三相Value 结束
																				} //判断node5为元素 结束
																			} //遍历ABC三相Value列表 结束
																		} //遍历 ABC三相 结束
																	}
																} //⑤-①读取ABC三相数据 结束

																if (xml_flag && ("V" == it->strItemName || "F_S" == it->strItemName || "F_L" == it->strItemName) && "112" == strPhase) //lnk2024-8-13角型//lnk20250729闪变也要加上角形
																{
																	for (int n = 0; n < 3; n++) //遍历 相别(AB、BC、CA三相)
																	{
																		CSequence* sq = new CSequence(); //AB、BC、CA三相别类指针
																		sq->strSValue = node4.toElement().attribute("value"); //相别值(7：ABC三相、112:线AB,BC,CA 8：T相)
																		sq->type = node4.toElement().attribute("type"); //参数等级
																		sq->strSeq = strLine[n]; //相别赋值  例：AB、BC、CA
																		it->SequenceList.push_back(sq); //添加 相别链表

																		QString strTag5 = node4.toElement().tagName(); //Sequence节点
																		if ("Sequence" == strTag5) //⑤读取相别Sequence
																		{
																			QDomNodeList list5 = node4.childNodes(); //获得元素Sequence的所有子节点的列表
																			for (int i5 = 0; i5 < list5.count(); i5++) //遍历 AB、BC、CA三相Value列表
																			{
																				QDomNode node5 = list5.at(i5); //node5 <Value>
																				if (node5.isElement())
																				{
																					QDomElement e_Value = node5.toElement(); //将其转换为元素
																					QString strTag6 = e_Value.tagName(); //相别Sequence下 所有DataValue子节点
																					if ("Value" == strTag6) //⑥读取AB、BC、CA三相Value
																					{
																						QString strDVName = e_Value.attribute("name"); //数据名
																						QString strDAName = e_Value.attribute("DA"); //数据属性名
																						if (strDAName.indexOf("phs*") >= 0) //DA包含"phs*"
																							strDAName = strDAName.replace("*", sq->strSeq); //将DA相别*替换为具体相别(AB、BC、CA)  例：phsAB$cVal$mag$f
																						//⑥-①谐波数据读取(AB、BC、CA三相)-------------------------------------
																						if (strDVName.indexOf("%") >= 0 && strDAName.indexOf("%-") >= 0) //数据名包含% 且 DA包含%-  例：V_%0,49%_MAX
																						{
																							QStringList strHarm1 = strDVName.split('%');
																							if (strHarm1.count() >= 2) //例：%0,49%
																							{
																								strValueTemp = "%" + strHarm1.at(1) + "%"; //例：%0,49%
																								QStringList strHarm2 = strHarm1.at(1).split(','); //例：0,49
																								if (strHarm2.count() >= 2)
																								{
																									nStart = (strHarm2.at(0)).toInt(); //谐波起始次数  例：0
																									nEnd = (strHarm2.at(1)).toInt();    //谐波结束次数  例：49
																								}
																							}

																							QString substring = strDAName.mid(strDAName.indexOf("[") + 1, strDAName.indexOf("]") - strDAName.indexOf("[") - 1);
																							QStringList strDAList1 = substring.split('-');
																							int strDAoffset = (strDAList1.at(1)).toInt();

																							for (int i = nStart; i <= nEnd; i++) //遍历 AB、BC、CA三相谐波次数
																							{
																								QString strDVNameTemp = strDVName; //临时 数据名
																								QString strDANameTemp = strDAName;//临时 数据属性名
																								CDataValue* dv1 = new CDataValue(); //AB、BC、CA三相谐波数据值类指针
																								dv1->type = e_Value.attribute("type"); //参数等级
																								if (e_Value.attributes().contains("Coefficient")) {
																									dv1->strCoefficient = e_Value.attribute("Coefficient"); //数据系数(字符型)
																									dv1->fCoefficient = e_Value.attribute("Coefficient").toFloat(); //数据系数(浮点型)
																								}
																								dv1->strOffset = e_Value.attribute("Offset"); //起始序号偏移量(字符型)
																								dv1->iOffset = e_Value.attribute("Offset").toInt(); //起始序号偏移量(整型) = 江苏电科院臻迪数据项起始序号 - 装置数据项实际起始序号
																								dv1->DO = e_Value.attribute("DO"); //数据对象名

																								//std::cout << "!!!!!!!!!!!!!ppv!!!!!!!!!!!!!!!!!!!!!!!!!!ppv!!!!!!!!!!!!!!!!!!!!!!" << std::endl;
																								if(DEBUGOPEN)std::cout << dv1->DO.toUtf8().constData() << std::endl;	//lnk 输出ppv
																								//std::cout << "!!!!!!!!!!!!!ppv!!!!!!!!!!!!!!!!!!!!!!!!!!ppv!!!!!!!!!!!!!!!!!!!!!!" << std::endl;

																								dv1->strName = strDVNameTemp.replace(strValueTemp, QString::number(i + e_Value.attribute("Offset").toInt())); //将数据名中%0,49%替换为具体数字  例：SI_%0,49%变为SI_1
																								dv1->DA = strDANameTemp.replace(substring, QString::number(i - strDAoffset)); //将DA中%-2替换为具体数字  例：phs*Har[1]$mag$f
																								
																								//zw修改 2023 - 8 - 14 为历史数据部分 Value节点新增指标-BaseFlag LimitUp LimitDown
																								if (e_Value.attributes().contains("BaseFlag"))
																								{
																									dv1->BaseFlag = e_Value.attribute("BaseFlag");
																									if (dv1->BaseFlag == "1") {
																										dt->BaseFlag1++;
																									}
																									else {
																										dt->BaseFlag0++;
																									}
																								}
																								else
																								{
																									dt->BaseFlag0++;
																									dv1->BaseFlag = "0";
																								}
																								if (e_Value.attributes().contains("LimitUp"))
																								{
																									dv1->LimitUp = e_Value.attribute("LimitUp");
																								}
																								else
																								{
																									dv1->LimitUp = "not define";
																								}
																								if (e_Value.attributes().contains("LimitDown"))
																								{
																									dv1->LimitDown = e_Value.attribute("LimitDown");
																								}
																								else
																								{
																									dv1->LimitDown = "not define";
																								}
																								if (!dv1->DO.isEmpty() && !dv1->DA.isEmpty()) //数据对象名和数据属性名均不为空                                
																									dv1->strFullName = dv1->DO + "$" + dv1->DA;
																								else
																									dv1->strFullName = "not define";
																								sq->DataValueList.push_back(dv1); //添加 数据链表(AB、BC、CA三相)
																							} //遍历ABC三相谐波次数 结束
																							
																						}
																						else //⑥-②非谐波数据读取(AB、BC、CA三相)-------------------------------
																						{
																							CDataValue* dv2 = new CDataValue(); //ABC三相非谐波数据值类指针
																							dv2->strName = e_Value.attribute("name"); //数据名       
																							dv2->type = e_Value.attribute("type"); //参数等级
																							if (e_Value.attributes().contains("Coefficient")) {
																								dv2->strCoefficient = e_Value.attribute("Coefficient"); //数据系数(字符型)
																								dv2->fCoefficient = e_Value.attribute("Coefficient").toFloat(); //数据系数(浮点型) 
																							}
																							dv2->DO = e_Value.attribute("DO"); //数据对象名
																							dv2->DA = strDAName; //数据属性名

																							//std::cout << "!!!!!!!!!!!!!ppv!!!!!!!!!!!!!!!!!!!!!!!!!!ppv!!!!!!!!!!!!!!!!!!!!!!" << std::endl;
																							if(DEBUGOPEN)std::cout << dv2->DO.toUtf8().constData() << std::endl;	//lnk 输出ppv
																							//std::cout << "!!!!!!!!!!!!!ppv!!!!!!!!!!!!!!!!!!!!!!!!!!ppv!!!!!!!!!!!!!!!!!!!!!!" << std::endl;

																							//zw修改 2023 - 8 - 14 为历史数据部分 Value节点新增指标-BaseFlag LimitUp LimitDown
																							if (e_Value.attributes().contains("BaseFlag"))
																							{
																								dv2->BaseFlag = e_Value.attribute("BaseFlag");
																								if (dv2->BaseFlag == "1") {
																									dt->BaseFlag1++;
																								}
																								else {
																									dt->BaseFlag0++;
																								}
																							}
																							else
																							{
																								dt->BaseFlag0++;
																								dv2->BaseFlag = "0";
																							}
																							if (e_Value.attributes().contains("LimitUp"))
																							{
																								dv2->LimitUp = e_Value.attribute("LimitUp");
																							}
																							else
																							{
																								dv2->LimitUp = "not define";
																							}
																							if (e_Value.attributes().contains("LimitDown"))
																							{
																								dv2->LimitDown = e_Value.attribute("LimitDown");
																							}
																							else
																							{
																								dv2->LimitDown = "not define";
																							}
																							if (!e_Value.attribute("PltFlag").isEmpty() && e_Value.attribute("PltFlag") == "True") //长时闪变标识
																								dv2->bPlt = true; //长时闪变标识
																							else
																								dv2->bPlt = false;//短时闪变 或 其他数据

																							if (!dv2->DO.isEmpty() && !dv2->DA.isEmpty()) //数据对象名和数据属性名均不为空                
																								dv2->strFullName = dv2->DO + "$" + dv2->DA;
																							else
																								dv2->strFullName = "not define";
																							sq->DataValueList.push_back(dv2); //添加 数据链表(AB、BC、CA三相)
																						}
																					} //读取AB、BC、CA三相Value 结束
																				}//判断node5为元素 结束
																			}  //遍历AB、BC、CA三相Value列表 结束
																		} //遍历 AB、BC、CA三相 结束
																	}
																}//⑤-①读取AB、BC、CA三相数据 结束

																if ("8" == strPhase) //⑤-②读取T相数据
																{
																	CSequence* sq = new CSequence(); //T相相别类指针
																	sq->strSValue = node4.toElement().attribute("value"); //相别值
																	sq->type = node4.toElement().attribute("type"); //参数等级
																	sq->strSeq = strPhasic[3]; //相别赋值
																	it->SequenceList.push_back(sq); //添加 相别链表(T相)

																	QDomNodeList list5 = node4.childNodes(); //获得元素Sequence的所有子节点的列表
																	for (int i5 = 0; i5 < list5.count(); i5++) //遍历 T相Value列表
																	{
																		QDomNode node5 = list5.at(i5); //node5 <Value>
																		if (node5.isElement())
																		{
																			QDomElement e_Value = node5.toElement(); //将其转换为元素
																			QString strTag6 = e_Value.tagName(); //相别Sequence下 所有DataValue子节点
																			if ("Value" == strTag6) //⑥读取T相Value
																			{
																				//⑥-①谐波数据读取(T相)  注：T相没有谐波数据
																				//⑥-②非谐波数据读取(T相)
																				CDataValue* dv2 = new CDataValue(); //T相非谐波数据值类指针
																				dv2->strName = e_Value.attribute("name"); //数据名                                    
																				dv2->type = e_Value.attribute("type"); //参数等级
																				if (e_Value.attributes().contains("Coefficient")) {
																					dv2->strCoefficient = e_Value.attribute("Coefficient"); //数据系数(字符型)
																					dv2->fCoefficient = e_Value.attribute("Coefficient").toFloat(); //数据系数(浮点型)   
																				}                                                                                      
																				dv2->DO = e_Value.attribute("DO"); //数据对象名
																				dv2->DA = e_Value.attribute("DA"); //数据属性名

																				//zw修改 2023 - 8 - 14 为历史数据部分 Value节点新增指标-BaseFlag LimitUp LimitDown
																				if (e_Value.attributes().contains("BaseFlag"))
																				{
																					dv2->BaseFlag = e_Value.attribute("BaseFlag");
																					if (dv2->BaseFlag == "1") {
																						dt->BaseFlag1++;
																					}
																					else {
																						dt->BaseFlag0++;
																					}
																				}
																				else
																				{
																					dt->BaseFlag0++;
																					dv2->BaseFlag = "0";
																				}
																				if (e_Value.attributes().contains("LimitUp"))
																				{
																					dv2->LimitUp = e_Value.attribute("LimitUp");
																				}
																				else
																				{
																					dv2->LimitUp = "not define";
																				}
																				if (e_Value.attributes().contains("LimitDown"))
																				{
																					dv2->LimitDown = e_Value.attribute("LimitDown");
																				}
																				else
																				{
																					dv2->LimitDown = "not define";
																				}

																				if (!dv2->DO.isEmpty() && !dv2->DA.isEmpty()) //数据对象名和数据属性名均不为空                                              
																					dv2->strFullName = dv2->DO + "$" + dv2->DA;
																				else
																					dv2->strFullName = "not define";
																				sq->DataValueList.push_back(dv2); //添加 数据链表(ABC三相)
																			} //读取T相Value 结束
																		} //判断node5为元素 结束
																	} //遍历T相Value列表 结束
																} //⑤-②读取T相数据 结束
															} //判断node4为元素 结束
														} //遍历Sequence列表 结束
													} //读取数据项Item 结束
												} //判断node3为元素 结束
											} //遍历Item列表 结束
										} //读取Monitor节点 结束
									} //判断node2为元素 结束
								} //遍历Monitor列表 结束				
							} //读取数据类型DataType 结束
						} //判断node为元素 结束
					}	//遍历DataType列表 结束
				} //读取Topic节点HISDATA、RTDATA 结束
				else if ("Topic" == strTag && "RTDATASOE" == topic->strTopic) //SOE事件-------------------------------------------------------
				{
					QDomNodeList list = e.childNodes(); //获得元素Topic的所有子节点的列表
					for (int i = 0; i < list.count(); i++) //遍历 DataType列表
					{
						QDomNode node = list.at(i); //node1 <DataType>
						if (node.isElement())
						{
							CDataType* dt = new CDataType(); //数据类型类指针
							dt->iDataType = node.toElement().attribute("value").toInt(); //数据类型值(1-稳态SOE、2-闪变SOE、3-暂态SOE)
							dt->type = node.toElement().attribute("type"); //参数等级
							topic->DataTypeList.push_back(dt); //添加 数据类型链表

							QString strTag2 = node.toElement().tagName(); //DataType节点
							if ("DataType" == strTag2) //②读取数据类型DataType
							{
								QDomNodeList list2 = node.childNodes(); //获得元素DataType的所有子节点的列表  
								for (int i2 = 0; i2 < list2.count(); i2++) //遍历 SOE列表
								{
									QDomNode node2 = list2.at(i2); //node2 <SOE>
									if (node2.isElement())
									{
										CEventData* ed = new CEventData(); //SOE事件类指针
										ed->triggerFlag = node2.toElement().attribute("TriggerFlag"); //SOE触发标识
										ed->DO = node2.toElement().attribute("DO"); //数据对象名
										ed->DA = node2.toElement().attribute("DA"); //数据属性名
										ed->type = node2.toElement().attribute("type"); //参数等级type类型：0-DataType 1-监测点 2-剔除标记 3-发生时刻，毫秒 4-数据链表 5-相位 6-值索引 9-实时SOE事件
										if (!ed->DO.isEmpty() && !ed->DA.isEmpty()) //数据对象名和数据属性名均不为空                                              
											ed->strFullName = ed->DO + "$" + ed->DA;
										else
											ed->strFullName = "not define";
										dt->SOEList.push_back(ed); //添加 SOE事件链表
									} //判断node2为元素 结束
								} //遍历SOE列表 结束
							} //读取数据类型DataType节点 结束						
						} //判断node为元素 结束
					}	//遍历DataType列表 结束	
				} //Topic节点RTDATASOE 结束
				else if ("Topic" == strTag && "SOEDATA" == topic->strTopic)
                {
				    QDomNodeList list = e.childNodes(); //获得元素Topic的所有子节点的列表
					for (int i = 0; i < list.count(); i++) //遍历 DataType列表
					{
						QDomNode node = list.at(i); //node1 <DataType>
						if (node.isElement()) 
						{
							CEventData* ed = new CEventData(); //SOE事件类指针
							ed->triggerFlag = node.toElement().attribute("name"); //SOE名称
							ed->desc = node.toElement().attribute("desc"); //SOE描述
							ed->DO = node.toElement().attribute("DO"); //数据对象名
							ed->DA = node.toElement().attribute("DA"); //数据属性名
							ed->type = node.toElement().attribute("type"); //参数等级type类型：0-DataType 1-监测点 2-剔除标记 3-发生时刻，毫秒 4-数据链表 5-相位 6-值索引 9-实时SOE事件
							if (!ed->DO.isEmpty() && !ed->DA.isEmpty()) //数据对象名和数据属性名均不为空                                              
								ed->strFullName = ed->DO + "$" + ed->DA;
							else
								ed->strFullName = "not define";
							
							cfg->SOEList.push_back(ed);
						}
					}
                }
			}
			if ("ReportMap" == strTag)//zw修改 2023 - 8 - 15 增加判断 将触发报告的解析移至XML 原配置RptLogCfg.ini取消
			{
				
			}
			if ("Topic" != strTag && "ReportMap" != strTag)//zw修改 2023 - 8 - 14 增加判断 新增部分节点解析
			{
				if ("WavePhasic" == strTag)
				{
					cfg->WavePhasicFlag.append(e.attribute("Flag"));
					if (cfg->WavePhasicFlag == "1") {
						cfg->WavePhasicA.append(e.attribute("A"));
						cfg->WavePhasicB.append(e.attribute("B"));
						cfg->WavePhasicC.append(e.attribute("C"));
					}
					
				}
				if ("UnitOfTime" == strTag)
				{
					cfg->UnitOfTimeUnit.append(e.attribute("Unit"));
				}
				//lnk 20260127
				if ("TypeOfData" == strTag)
				{
					cfg->TypeOfData.append(e.attribute("Unit"));
				}
				if ("ValueOfTime" == strTag)
				{
					cfg->ValueOfTimeUnit.append(e.attribute("Unit"));
				}
				if ("ComtradeFile" == strTag)
				{
					cfg->WaveTimeFlag.append(e.attribute("WaveTimeFlag"));
					
				}
				if ("IEDControl" == strTag)
				{
					cfg->IEDControl.append(e.attribute("name"));
				}
				if ("IED" == strTag)
				{
					cfg->IEDname.append(e.attribute("name"));
					
				}
				if ("LDevice" == strTag)
				{
					cfg->LDevicePrefix.append(e.attribute("Prefix"));
					
				}
			}
		} //判断n为元素 结束

		n = n.nextSibling();//获取下一个兄弟节点(HISDATA —> RTDATA —> RTDATASOE)
	} //while (!n.isNull) 结束

	return true;
}


/// <summary>
/// czy  2023-11-23 测试json的装置间隔频,打印前台
/// </summary>
/// <param name="flag">1是,2是,3是填入计算的interval</param>
/// <param name="interval">1是,2是,3是填入计算的interval</param>
void print_interval(int flag,int interval) {
	if (flag == 1) {
		cout << "interval!!dont't contain mp_id ,interval=1" << endl;
	}
	else if (flag == 2) {
		cout << "interval!!contain mp_id but interval=0, set interval=1" << endl;

	}
	else 
	{
		cout << "interval!!contain mp_id , find interval=" << interval << endl;

	}
}

/// <summary>
/// czy kafka的json中将线电压转成相电压
/// </summary>
/// <param name="pSequence"></param>
/// <returns></returns>
QString line_to_phasic(QString qstrSeq) {
	if (qstrSeq == "A" || qstrSeq == "AB") {
		return "A";
	}
	else if (qstrSeq == "B" || qstrSeq == "BC") {
		return "B";
	}
	else if (qstrSeq == "C" || qstrSeq == "CA") {
		return "C";
	}
	else {
		return qstrSeq;
	}
}

//调试用
void printCTopicList(const std::list<CTopic*>& ctopic_list) {
    int topicIndex = 0;
    for (const auto& topic : ctopic_list) {
        printf("==== Topic[%d] ====\n", topicIndex++);
        printf("Topic name: %s\n", topic->strTopic.toStdString().c_str());

        int dtypeIndex = 0;
        for (const auto& dtype : topic->DataTypeList) {
            printf("  -- DataType[%d] --\n", dtypeIndex++);
            printf("    iDataType: %d, type: %s, BaseFlag1: %d, BaseFlag0: %d\n",
                   dtype->iDataType,
                   dtype->type.toStdString().c_str(),
                   dtype->BaseFlag1,
                   dtype->BaseFlag0);

            int monitorIndex = 0;
            for (const auto& monitor : dtype->MonitorList) {
                printf("      >> Monitor[%d] name: %s, type: %s\n",
                       monitorIndex++,
                       monitor->strMonitor.toStdString().c_str(),
                       monitor->type.toStdString().c_str());

                int itemIndex = 0;
                for (const auto& item : monitor->ItemList) {
                    printf("        >> Item[%d] name: %s, value: %s, type: %s\n",
                           itemIndex++,
                           item->strItemName.toStdString().c_str(),
                           item->strItemValue.toStdString().c_str(),
                           item->type.toStdString().c_str());

                    int seqIndex = 0;
                    for (const auto& seq : item->SequenceList) {
                        printf("          >> Sequence[%d] strSeq: %s, strSValue: %s, type: %s\n",
                               seqIndex++,
                               seq->strSeq.toStdString().c_str(),
                               seq->strSValue.toStdString().c_str(),
                               seq->type.toStdString().c_str());

                        int valIndex = 0;
                        for (const auto& val : seq->DataValueList) {
                            printf("            >> DataValue[%d] name: %s, value: %f\n",
                                   valIndex++,
                                   val->strName.toStdString().c_str(),
                                   val->fValue);
                        }
                    }
					break; // 只打印第一个 Item 的 SequenceList 和 DataValueList，避免输出过多
                }
				break; // 只打印第一个 Monitor 的 ItemList，避免输出过多
            }


            // 如果需要打印 SOEList，可加以下：
            /*
            int soeIndex = 0;
            for (const auto& soe : dtype->SOEList) {
                printf("      >> SOE[%d] ... \n", soeIndex++);
                // 打印 SOE 具体字段（如有定义）
            }
            */
        }
    }
}

// ===== DEBUG 打印: mms_str_map (属性名 -> 值) =====
static void print_mms_str_map(const json_block_data* data)
{
    if (!data) {
        std::cout << "[DBG] json_block_data is NULL\n";
        return;
    }

    std::cout << "\n========== [DBG] json_block_data.mms_str_map ==========\n";
    std::cout << "[DBG] monitorId=" << data->monitorId
              << " func_type=" << data->func_type
              << " flag=" << data->flag
              << " time(ms)=" << data->time
              << " voltage_level=" << data->voltage_level
              << "\n";

    std::cout << "[DBG] mp_id=" << data->mp_id.toStdString()
              << " dev_type=" << data->dev_type.toStdString()
              << "\n";

    std::cout << "[DBG] mms_str_map size=" << data->mms_str_map.size() << "\n";

    // Qt4/Qt5 都稳：QMapIterator
    QMapIterator<QString, double> it(data->mms_str_map);
    while (it.hasNext()) {
        it.next();
        std::cout << "  " << it.key().toStdString() << " = " << it.value() << "\n";
    }

    std::cout << "======================================================\n\n";
}

//20250214添加角型接线处理
int transfer_json_block_data(char v_wiring_type[], json_block_data *data) //json生成函数 zw修改 2023-8-11 调整传送json结构 目前仅限历史稳态数据
{
	// 刚进函数就打印 mms_str_map
    if (DEBUGOPEN) {
        print_mms_str_map(data);
    }

	list<CTopic*> ctopic_list;

	////lnk2024-8-15 区分星型,角型接线
	if (strcmp(v_wiring_type, "0") == 0)	//lnk2024-8-15 星型接线
	{
		cout << "1 report v_wiring_type is" << v_wiring_type << endl;
		if (xmlinfo_list.contains(data->dev_type)) {
			cout << "transfer_json_block_data contain data->dev_type" << endl;
			ctopic_list = xmlinfo_list[data->dev_type]->topicList;
		}
		else {
			cout << "transfer_json_block_data not contain data->dev_type:"  << data->dev_type.toStdString()  << "  !!!!"<< endl;
			ctopic_list = topicList;
		}
	}
	else	//lnk2024-8-15 角型接线
	{
		cout << "2 report v_wiring_type is" << v_wiring_type << endl;
		if (xmlinfo_list2.contains(data->dev_type)) {
			cout << "transfer_json_block_data contain data->dev_type" << endl;
			ctopic_list = xmlinfo_list2[data->dev_type]->topicList;

			
		}
		else {
			cout << "transfer_json_block_data not contain data->dev_type:"  << data->dev_type.toStdString() << "  !!!!"<< endl;
			ctopic_list = topicList2;
			
		}
	}

	if(DEBUGOPEN)printCTopicList(ctopic_list);

	//lnk20260127 添加数据类型区分
	bool typeofdata = false;
	bool data_have_static = data->data_have_statistic;

	QString devType = data->dev_type;
	QByteArray devTypeBytes = devType.toUtf8();
	const char* dev_type_cstr = devTypeBytes.constData();
	qDebug() << "[DBG] devType (QString) =" << devType;
	qDebug() << "[DBG] devType length =" << devType.length();
	qDebug() << "[DBG] devTypeBytes =" << devTypeBytes;
	qDebug() << "[DBG] devTypeBytes size =" << devTypeBytes.size();

	printf("[DBG] dev_type_cstr = '%s'\n", dev_type_cstr);
	XmlConfigC cfg1;
	if (get_xml_config_by_dev_type(dev_type_cstr, &cfg1)) {
	    printf("========== XmlConfigC dump ==========\n");
    	printf("WavePhasicFlag  = '%s'\n", cfg1.WavePhasicFlag);
    	printf("WavePhasicA     = '%s'\n", cfg1.WavePhasicA);
    	printf("WavePhasicB     = '%s'\n", cfg1.WavePhasicB);
    	printf("WavePhasicC     = '%s'\n", cfg1.WavePhasicC);
    	printf("UnitOfTimeUnit  = '%s'\n", cfg1.UnitOfTimeUnit);
    	printf("TypeOfData      = '%s'\n", cfg1.TypeOfData);
    	printf("ValueOfTimeUnit = '%s'\n", cfg1.ValueOfTimeUnit);
    	printf("WaveTimeFlag    = '%s'\n", cfg1.WaveTimeFlag);
		printf("IEDControl      = '%s'\n", cfg1.IEDControl);
    	printf("IEDname         = '%s'\n", cfg1.IEDname);
    	printf("LDevicePrefix   = '%s'\n", cfg1.LDevicePrefix);
    	printf("=====================================\n");
		// 如果 TypeOfData == "1"，则置 true
    	if (strcmp(cfg1.TypeOfData, "1") == 0) {
    	    typeofdata = true;
    	}
	} else {
	    printf("not find this dev_type\n");
	}

	bool shortjumpflag = false;
	bool longjumpflag = false;

	//zw修改 end
	if (!inited) //初始化 JiangSu_Config.xml
	{
		inited = true;
	}

	if (NULL == data) //json拼接参数类指针为空
		return 0;

	if (100 == data->func_type) //一、稳态/统计数据 ——> MMS_Client
	{		
		list<CTopic*>::iterator tp = ctopic_list.begin();
		while (tp != ctopic_list.end()) //①遍历 Kafka发送主题链表
		{
			CTopic* pTopic = *tp++;
			if ("HISDATA" == pTopic->strTopic) //Topic等于HISDATA
			{					
				list<CDataType*>::iterator dt = pTopic->DataTypeList.begin(); //②遍历 DataTypeList
				while (dt != pTopic->DataTypeList.end())
				{
					bool isJump = false; //是否跳出(整个数据类型)循环
					CDataType* pDataType = *dt++;

					if (2 == pDataType->iDataType) //②-②历史短闪变数据------------------------------------------------------------
					{
						Ckafka_data_t KafkaData; //kafka发送数据结构类对象
						KafkaData.monitor_id = data->monitorId; //监测点ID	
						KafkaData.mp_id = data->mp_id;
						KafkaData.strTopic = "PST"; //kafka发送主题		
						KafkaData.strText = ""; //kafka发送的json字符串

						long long  time_sec; //时间戳(秒)
						KafkaData.strText.append("{"); //拼接 json起始
						KafkaData.strText.append(QString("\"DATA_TYPE\":\"%1\" ").arg(pDataType->iDataType, 2, 10, QChar('0'))); //拼接 json数据类型  例：历史闪变 "02"
						KafkaData.strText.append(QString(", \"Monitor\":\"%1\" ").arg(data->mp_id));//例：监测点 "1100"

						list<CMonitor*>::iterator mt = pDataType->MonitorList.begin(); //③遍历 MonitorList
						int countflag = 0, num = 0;
						while (mt != pDataType->MonitorList.end())
						{
							CMonitor* pMonitor = *mt++;
							KafkaData.strText.append(QString(", \"%1\":{").arg("Value")); //拼接 json监测点

							list<CItem*>::iterator it = pMonitor->ItemList.begin(); //④遍历 ItemList
							list<CItem*>::iterator itEnd = pMonitor->ItemList.end(); //ItemList链表最后一个数据值元素
							while (it != pMonitor->ItemList.end())
							{
								CItem* pItem = *it++;
								//////////////////////////////////////////////////////////lnk20250306为了数据入库，构造数据添加FLAG
								if ("FLAG" == pItem->strItemName) //剔除"FLAG"，防止sq相别出现错误指针
								{
									KafkaData.strText.append(QString("\"FLAG\":%1, ").arg(data->flag)); //拼接 json剔除标记，1不剔除，0剔除，默认剔除
									continue;
								}
								//////////////////////////////////////////////////////////
								if ("TIME" == pItem->strItemName) //剔除"FLAG"，防止sq相别出现错误指针
								{
									KafkaData.strText.append(QString("\"TIME\":\"%1\", ").arg(data->time)); //拼接 json发生时刻，毫秒
									time_sec = data->time / 1000; //时间戳(秒)
									continue;
								}
								KafkaData.strText.append(QString("\"%1\":{").arg(pItem->strItemName)); //拼接 json数据项 F

								list<CSequence*>::iterator sq = pItem->SequenceList.begin(); //⑤遍历 SequenceList
								list<CSequence*>::iterator sqEnd = pItem->SequenceList.end(); //SequenceList链表最后一个数据值元素
								while (sq != pItem->SequenceList.end())
								{
									CSequence* pSequence = *sq++;
									
									KafkaData.strText.append(QString("\"%1\":{ ").arg(line_to_phasic(pSequence->strSeq))); //拼接 json相别 A、B、C、T相

									list<CDataValue*>::iterator dv = pSequence->DataValueList.begin(); //⑥遍历 DataValueList
									CDataValue* pDataValueBegin = *dv;
									list<CDataValue*>::iterator dvEnd = pSequence->DataValueList.end(); //DataValueList链表最后一个数据值元素
									num = num + pSequence->DataValueList.size();
									while (dv != pSequence->DataValueList.end())
									{
										CDataValue* pDataValue = *dv++;

										if ("NOT DEFINE" == pDataValue->strFullName || "not define" == pDataValue->strFullName) //数据对象名 $ 数据属性名  即：拼接名为空
										{
											countflag++;
											continue;
										}
											
										if (!data->mms_str_map.contains(pDataValue->strFullName))//确认字典里不含有该key
										{
											isJump = false; //跳出本层循环
											countflag++;
											if (dv != dvEnd) //非单相最后一个数据值元素
												KafkaData.strText.append(QString("\"%1\":%2, ").arg(pDataValue->strName).arg("null")); //拼接
											else
												KafkaData.strText.append(QString("\"%1\":%2 ").arg(pDataValue->strName).arg("null")); //拼接
											continue;
										}

										try
										{
											double dTemp = data->mms_str_map.value(pDataValue->strFullName) * pDataValue->fCoefficient; //接口数据 * 系数
											if (dv != dvEnd) //非单相最后一个数据值元素
												KafkaData.strText.append(QString("\"%1\":\"%2\",").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //拼接 json数据值(角度值)
											else
												KafkaData.strText.append(QString("\"%1\":\"%2\" ").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //拼接 json数据值(角度值)
										}
										catch (exception& e)
										{
											cout << "历史闪变数据值拼接json错误，原因: " << e.what() << endl;
											return false;
										}
									} //DataValueList 结束

									if (!KafkaData.strText.isEmpty()) {
										if (KafkaData.strText[KafkaData.strText.length() - 1] == ',') {
											KafkaData.strText = KafkaData.strText.remove(KafkaData.strText.size() - 1, 1);
											KafkaData.strText.append(" ");
											cout << "KafkaData.strText = KafkaData.strText.chopped(1) " << endl;
										}
									}
									if (isJump) break; //跳出循环
									if (sq != sqEnd) //非A、B、C、T最后一个相别元素
										KafkaData.strText.append("}, "); //拼接 json相别结尾
									else
										KafkaData.strText.append("}"); //拼接 json相别结尾
								} //SequenceList 结束

								if (isJump) break; //跳出循环
								if (it != itEnd) //非 V、I、PQ最后一个json数据项元素
									KafkaData.strText.append("}, "); //拼接 json数据项结尾
								else
									KafkaData.strText.append("}}"); //拼接 json数据项结尾
							} //ItemList 结束
							if (isJump) break; //跳出循环
						} //MonitorList 结束
						if (isJump) continue; //跳出本数据类型循环
						KafkaData.strText.append("}"); //拼接 json稳态数据结尾

						cout << countflag << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!send name=\"DATA_TYPE\" value=\"02\" " << num << endl;
						cout << KafkaData.strText.toAscii().data() << endl;
						if (countflag < num) {
							kafka_data_list_mutex.lock(); //加锁
							kafka_data_list.append(KafkaData); //添加 kafka发送链表
							kafka_data_list_mutex.unlock(); //解锁
							shortjumpflag = true;
						}
					} //②-②历史闪变数据解析结束！--------------------------------

					//20241204长闪变类型应该为3
					if (3 == pDataType->iDataType) //②-②历史长闪变数据------------------------------------------------------------
					{
						Ckafka_data_t KafkaData; //kafka发送数据结构类对象
						KafkaData.monitor_id = data->monitorId; //监测点ID	
						KafkaData.mp_id = data->mp_id;
						KafkaData.strTopic = "PLT"; //kafka发送主题		
						KafkaData.strText = ""; //kafka发送的json字符串

						long long  time_sec; //时间戳(秒)
						KafkaData.strText.append("{"); //拼接 json起始
						KafkaData.strText.append(QString("\"DATA_TYPE\":\"%1\" ").arg(pDataType->iDataType, 2, 10, QChar('0'))); //拼接 json数据类型  例：历史闪变 "02"
						KafkaData.strText.append(QString(", \"Monitor\":\"%1\" ").arg(data->mp_id));//例：监测点 "1100"

						list<CMonitor*>::iterator mt = pDataType->MonitorList.begin(); //③遍历 MonitorList
						int countflag = 0,num = 0;
						while (mt != pDataType->MonitorList.end())
						{
							CMonitor* pMonitor = *mt++;
							KafkaData.strText.append(QString(", \"%1\":{").arg("Value")); //拼接 json监测点

							list<CItem*>::iterator it = pMonitor->ItemList.begin(); //④遍历 ItemList
							list<CItem*>::iterator itEnd = pMonitor->ItemList.end(); //ItemList链表最后一个数据值元素
							while (it != pMonitor->ItemList.end())
							{
								CItem* pItem = *it++;
								//////////////////////////////////////////////////////////lnk20250306为了数据入库，构造数据添加FLAG
								if ("FLAG" == pItem->strItemName) //剔除"FLAG"，防止sq相别出现错误指针
								{
									KafkaData.strText.append(QString("\"FLAG\":%1, ").arg(data->flag)); //拼接 json剔除标记，1不剔除，0剔除，默认剔除
									continue;
								}
								//////////////////////////////////////////////////////////
								if ("TIME" == pItem->strItemName) //剔除"FLAG"，防止sq相别出现错误指针
								{
									KafkaData.strText.append(QString("\"TIME\":\"%1\", ").arg(data->time)); //拼接 json发生时刻，毫秒
									time_sec = data->time / 1000; //时间戳(秒)
									continue;
								}
								KafkaData.strText.append(QString("\"%1\":{").arg(pItem->strItemName)); //拼接 json数据项 F

								list<CSequence*>::iterator sq = pItem->SequenceList.begin(); //⑤遍历 SequenceList
								list<CSequence*>::iterator sqEnd = pItem->SequenceList.end(); //SequenceList链表最后一个数据值元素
								while (sq != pItem->SequenceList.end())
								{
									CSequence* pSequence = *sq++;
									//KafkaData.strText.append(QString("{\"SEQ\":\"%1\", ").arg(pSequence->strSeq)); //拼接 json相别 A、B、C相
									KafkaData.strText.append(QString("\"%1\":{ ").arg(line_to_phasic(pSequence->strSeq))); //拼接 json相别 A、B、C、T相

									list<CDataValue*>::iterator dv = pSequence->DataValueList.begin(); //⑥遍历 DataValueList
									CDataValue* pDataValueBegin = *dv;
									list<CDataValue*>::iterator dvEnd = pSequence->DataValueList.end(); //DataValueList链表最后一个数据值元素
									num = num + pSequence->DataValueList.size();
									while (dv != pSequence->DataValueList.end())
									{
										CDataValue* pDataValue = *dv++;

										if ("NOT DEFINE" == pDataValue->strFullName || "not define" == pDataValue->strFullName) //数据对象名 $ 数据属性名  即：拼接名为空
										{
											countflag++;
											continue;
										}
										if (!data->mms_str_map.contains(pDataValue->strFullName))//确认字典里不含有该key
										{
											isJump = false; //跳出本层循环
											countflag++;
											if (dv != dvEnd) //非单相最后一个数据值元素
												KafkaData.strText.append(QString("\"%1\":%2, ").arg(pDataValue->strName).arg("null")); //拼接
											else
												KafkaData.strText.append(QString("\"%1\":%2 ").arg(pDataValue->strName).arg("null")); //拼接
											continue;
										}

										try
										{
											if (0 == time_sec % 7200) //2小时间隔，长时闪变
											{
												double dTemp = data->mms_str_map.value(pDataValue->strFullName) * pDataValue->fCoefficient; //接口数据 * 系数
												if (dv != dvEnd) //非单相最后一个数据值元素
													KafkaData.strText.append(QString("\"%1\":\"%2\", ").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //拼接 json数据值(角度值)
												else
													KafkaData.strText.append(QString("\"%1\":\"%2\" ").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //拼接 json数据值(角度值)
											}
										}
										catch (exception& e)
										{
											cout << "历史闪变数据值拼接json错误，原因: " << e.what() << endl;
											return false;
										}
									} //DataValueList 结束

									if (!KafkaData.strText.isEmpty()) {
										if (KafkaData.strText[KafkaData.strText.length() - 1] == ',') {
											KafkaData.strText = KafkaData.strText.remove(KafkaData.strText.size() - 1, 1);
											KafkaData.strText.append(" ");
											cout << "KafkaData.strText = KafkaData.strText.chopped(1) " << endl;
										}
									}
									if (isJump) break; //跳出循环
									if (sq != sqEnd) //非A、B、C、T最后一个相别元素
										KafkaData.strText.append("}, "); //拼接 json相别结尾
									else
										KafkaData.strText.append("}"); //拼接 json相别结尾
								} //SequenceList 结束

								if (isJump) break; //跳出循环
								if (it != itEnd) //非 V、I、PQ最后一个json数据项元素
									KafkaData.strText.append("}, "); //拼接 json数据项结尾
								else
									KafkaData.strText.append("}}"); //拼接 json数据项结尾
							} //ItemList 结束
							if (isJump) break; //跳出循环
						} //MonitorList 结束
						if (isJump) continue; //跳出本数据类型循环
						KafkaData.strText.append("}"); //拼接 json稳态数据结尾

						cout<< countflag << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!send name=\"DATA_TYPE\" value=\"03\" " << num << endl;
						cout << KafkaData.strText.toAscii().data() << endl;
						if (countflag < num && 0 == time_sec % 7200) {
							kafka_data_list_mutex.lock(); //加锁
							kafka_data_list.append(KafkaData); //添加 kafka发送链表
							kafka_data_list_mutex.unlock(); //解锁
							longjumpflag = true;
						}
						else if (countflag < num && 0 != time_sec % 7200) {
							longjumpflag = true;//不发送数据
						}
						//lnk20260127
						if (typeofdata == false || data_have_static == false) {//不合并则处理完闪变就不处理其他数据,如果有统计数据或者数据类型区分了就继续处理其他数据
							if (longjumpflag == true || shortjumpflag == true) {
								return 1;
							}
						}						
					} //②-②历史闪变数据解析结束！--------------------------------

					//合并则继续处理其他数据
					if (1 == pDataType->iDataType) //②-①历史稳态数据-----------------------------------------------------------
					{
						Ckafka_data_t KafkaData; //kafka发送数据结构类对象
						KafkaData.monitor_id = data->monitorId; //监测点ID	
						KafkaData.mp_id = data->mp_id;
						KafkaData.strTopic = "HISDATA"; //kafka发送主题		
						KafkaData.strText = ""; //kafka发送的json字符串

						KafkaData.strText.append("{"); //拼接 json起始
						KafkaData.strText.append(QString("\"DATA_TYPE\":\"%1\" ").arg(pDataType->iDataType, 2, 10,QChar('0'))); //拼接 json数据类型  例：历史稳态 "01"
						KafkaData.strText.append(QString(", \"Monitor\":\"%1\" ").arg(data->mp_id));//例：监测点 "1100"
						
						list<CMonitor*>::iterator mt = pDataType->MonitorList.begin(); //③遍历 MonitorList
						while (mt != pDataType->MonitorList.end())
						{							
							CMonitor* pMonitor = *mt++;
							KafkaData.strText.append(QString(", \"%1\":{").arg("Value")); //拼接 json监测点

							list<CItem*>::iterator it = pMonitor->ItemList.begin(); //④遍历 ItemList
							list<CItem*>::iterator itEnd = pMonitor->ItemList.end(); //ItemList链表最后一个数据值元素
							while (it != pMonitor->ItemList.end())
							{
								CItem* pItem = *it++;
								if ("FLAG" == pItem->strItemName) //剔除"FLAG"，防止sq相别出现错误指针
								{
									KafkaData.strText.append(QString("\"FLAG\":%1, ").arg(data->flag)); //拼接 json剔除标记，1不剔除，0剔除，默认剔除
									continue;
								}
								if ("TIME" == pItem->strItemName) //剔除"TIME"，防止sq相别出现错误指针
								{
									KafkaData.strText.append(QString("\"TIME\":%1, ").arg(data->time)); //拼接 json发生时刻，毫秒

									if (!data_timespan_list.contains(data->mp_id)) {
										KafkaData.strText.append(QString("\"interval\":%1, ").arg(3)); //拼接 json发生时刻，毫秒
									}
									else if (data_timespan_list[data->mp_id]->msspan == 0)
									{
										KafkaData.strText.append(QString("\"interval\":%1, ").arg(3)); //拼接 json发生时刻，毫秒

									}
									else {
										KafkaData.strText.append(QString("\"interval\":%1, ").arg(data_timespan_list[data->mp_id]->msspan)); //拼接 json发生时刻，毫秒

									}
									continue;
								}
								KafkaData.strText.append(QString("\"%1\":{").arg(pItem->strItemName)); //拼接 json数据项 V、I、PQ

								list<CSequence*>::iterator sq = pItem->SequenceList.begin(); //⑤遍历 SequenceList
								list<CSequence*>::iterator sqEnd = pItem->SequenceList.end(); //SequenceList链表最后一个数据值元素
								while (sq != pItem->SequenceList.end())
								{
									CSequence* pSequence = *sq++;
									
									KafkaData.strText.append(QString("\"%1\":{ ").arg(line_to_phasic(pSequence->strSeq))); //拼接 json相别 A、B、C、T相

									list<CDataValue*>::iterator dv = pSequence->DataValueList.begin(); //⑥遍历 DataValueList
									CDataValue* pDataValueBegin = *dv;
									list<CDataValue*>::iterator dvEnd = pSequence->DataValueList.end(); //DataValueList链表最后一个数据值元素
									while (dv != pSequence->DataValueList.end())
									{
										CDataValue* pDataValue = *dv++;

										if ("NOT DEFINE" == pDataValue->strFullName || "not define" == pDataValue->strFullName) //数据对象名 $ 数据属性名  即：拼接名为空
										  continue;
										if (!data->mms_str_map.contains(pDataValue->strFullName))//确认字典里不含有该key
										{
											isJump = false; //跳出本层循环
											//zw修改 2023-8-28 不匹配数据添加
											if (dv != dvEnd) //非单相最后一个数据值元素
												KafkaData.strText.append(QString("\"%1\":%2, ").arg(pDataValue->strName).arg("null")); //拼接
											else
												KafkaData.strText.append(QString("\"%1\":%2 ").arg(pDataValue->strName).arg("null")); //拼接

											
											continue;
										}

										try
										{
											if (pDataValue->strFullName.indexOf("$ang$f") != -1) //查找61850属性名中含有相角的定义
											{
												double dAngleTemp = data->mms_str_map.value(pDataValue->strFullName); //角度值(-180度 ~ 180度)
												dAngleTemp = dAngleTemp > 180.0f ? dAngleTemp - 360.0f : dAngleTemp;
												if (dv != dvEnd) //非单相最后一个数据值元素
													KafkaData.strText.append(QString("\"%1\":\"%2\", ").arg(pDataValue->strName).arg(QString::number(dAngleTemp, 10, 6))); //拼接 json数据值(角度值)
												else
													KafkaData.strText.append(QString("\"%1\":\"%2\" ").arg(pDataValue->strName).arg(QString::number(dAngleTemp, 10, 6))); //拼接 json数据值(角度值)
												
											}
											else
											{
												double dTemp = data->mms_str_map.value(pDataValue->strFullName) * pDataValue->fCoefficient; //接口数据 * 系数
												if (dv != dvEnd) //非单相最后一个数据值元素
													KafkaData.strText.append(QString("\"%1\":\"%2\", ").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //拼接 json数据值(非角度值)
												else
													KafkaData.strText.append(QString("\"%1\":\"%2\" ").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //拼接 json数据值(非角度值)

												//lnk20250710添加频率存储
												if(dTemp > 0.99){
													//printf("pDataValue->strName==========================%s",pDataValue->strName.toStdString().c_str());
													if(pDataValue->strName == "G_FREQ")	{
														mp_freq_save_map[data->mp_id.toStdString()].G_FREQ = dTemp;	//保存95值
													}
													else if(pDataValue->strName == "FREQ")	{
														mp_freq_save_map[data->mp_id.toStdString()].FREQ = dTemp;	//保存平均值
													}
													else if(pDataValue->strName == "MAX_FREQ")	{
														mp_freq_save_map[data->mp_id.toStdString()].MAX_FREQ = dTemp;	//保存最大值
													}
													else if(pDataValue->strName == "MIN_FREQ")	{
														mp_freq_save_map[data->mp_id.toStdString()].MIN_FREQ = dTemp;	//保存最小值
													}

												}
												else{
													if(pDataValue->strName == "G_FREQ")	{
														dTemp = mp_freq_save_map[data->mp_id.toStdString()].G_FREQ;	//保存95值
													}
													else if(pDataValue->strName == "FREQ")	{
														dTemp = mp_freq_save_map[data->mp_id.toStdString()].FREQ;	//保存平均值
													}
													else if(pDataValue->strName == "MAX_FREQ")	{
														dTemp = mp_freq_save_map[data->mp_id.toStdString()].MAX_FREQ;	//保存最大值
													}
													else if(pDataValue->strName == "MIN_FREQ")	{
														dTemp = mp_freq_save_map[data->mp_id.toStdString()].MIN_FREQ;	//保存最小值
													}
												}
												//lnk20250710添加频率存储
												
											}
										}
										catch (exception& e)
										{
											cout << "历史稳态数据值拼接json错误，原因: " << e.what() << endl;
											return false;
										}
									} //DataValueList 结束

									if (!KafkaData.strText.isEmpty()) {
										if (KafkaData.strText[KafkaData.strText.length() - 1] == ',') {
											KafkaData.strText = KafkaData.strText.remove(KafkaData.strText.size() - 1, 1);
											KafkaData.strText.append(" ");
											cout << "KafkaData.strText = KafkaData.strText.chopped(1) " << endl;
										}
									}
									if (isJump) break; //跳出循环
									if (sq != sqEnd) //非A、B、C、T最后一个相别元素
										KafkaData.strText.append("}, "); //拼接 json相别结尾
									else
										KafkaData.strText.append("}"); //拼接 json相别结尾
								} //SequenceList 结束

								if (isJump) break; //跳出循环
								if (it != itEnd) //非 V、I、PQ最后一个json数据项元素
									KafkaData.strText.append("}, "); //拼接 json数据项结尾
								else
									KafkaData.strText.append("}}"); //拼接 json数据项结尾
							} //ItemList 结束
							if (isJump) break; //跳出循环
						} //MonitorList 结束
						if (isJump) continue; //跳出本数据类型循环
						KafkaData.strText.append("}"); //拼接 json稳态数据结尾

						//调试用
						if(DEBUGOPEN)cout << KafkaData.strText.toAscii().data() << endl;

						kafka_data_list_mutex.lock(); //加锁
							kafka_data_list.append(KafkaData); //添加 kafka发送链表
						kafka_data_list_mutex.unlock(); //解锁

						return 1; //结束该函数，停止后续代码执行
					} //②-①历史稳态数据解析结束！--------------------------------
				} //DataTypeList 结束
			} //遍历 HISDATA 结束！
		} //TopicList 结束
	} //一、结束

	if (200 == data->func_type) //二、3秒数据/实时数据 ——> MMS_Assist
	{		
		list<CTopic*>::iterator tp = ctopic_list.begin();
		while (tp != ctopic_list.end()) //①遍历 Kafka发送主题链表
		{			
			CTopic* pTopic = *tp++;
			if ("RTDATA" == pTopic->strTopic) //Topic等于RTDATA------------------------------------------------------------
			{
				list<CDataType*>::iterator dt = pTopic->DataTypeList.begin(); //②遍历 DataTypeList
				while (dt != pTopic->DataTypeList.end())
				{
					bool isJump = false; //是否跳出(整个数据类型)循环
					CDataType* pDataType = *dt++;
					if (1 == pDataType->iDataType) //②-①实时3s数据--------------------------------------------------------------
					{
						Ckafka_data_t KafkaData; //kafka发送数据结构类对象
						KafkaData.monitor_id = data->monitorId; //监测点ID	
						KafkaData.mp_id = data->mp_id;
						KafkaData.strTopic = "RTDATA"; //kafka发送主题	
						KafkaData.strText = ""; //kafka发送的json字符串

						KafkaData.strText.append("{"); //拼接 json起始
						KafkaData.strText.append(QString("\"DATA_TYPE\":\"%1\" ").arg(pDataType->iDataType, 2, 10, QChar('0'))); //拼接 json数据类型  例：实时稳态 "01"
						KafkaData.strText.append(QString(", \"Monitor\":\"%1\" ").arg(data->mp_id));//例：监测点 "1100"
						
						list<CMonitor*>::iterator mt = pDataType->MonitorList.begin(); //③遍历 MonitorList
						while (mt != pDataType->MonitorList.end())
						{
							CMonitor* pMonitor = *mt++;
							KafkaData.strText.append(QString(", \"%1\":{").arg("Value")); //拼接 json监测点

							list<CItem*>::iterator it = pMonitor->ItemList.begin(); //④遍历 ItemList
							list<CItem*>::iterator itEnd = pMonitor->ItemList.end(); //ItemList链表最后一个数据值元素
							while (it != pMonitor->ItemList.end())
							{
								CItem* pItem = *it++;
								if ("FLAG" == pItem->strItemName) //剔除"FLAG"，防止sq相别出现错误指针
								{
									KafkaData.strText.append(QString("\"FLAG\":\"%1\", ").arg(data->flag)); //拼接 json剔除标记，1不剔除，0剔除，默认剔除
									continue;
								}
								if ("TIME" == pItem->strItemName) //剔除"TIME"，防止sq相别出现错误指针
								{
									KafkaData.strText.append(QString("\"TIME\":\"%1\", ").arg(data->time)); //拼接 json发生时刻，毫秒
									continue;
								}
								KafkaData.strText.append(QString("\"%1\":{").arg(pItem->strItemName)); //拼接 json数据项 V、I、PQ

								list<CSequence*>::iterator sq = pItem->SequenceList.begin(); //⑤遍历 SequenceList
								list<CSequence*>::iterator sqEnd = pItem->SequenceList.end(); //SequenceList链表最后一个数据值元素
								while (sq != pItem->SequenceList.end())
								{
									CSequence* pSequence = *sq++;
									
									KafkaData.strText.append(QString("\"%1\":{ ").arg(line_to_phasic(pSequence->strSeq))); //拼接 json相别 A、B、C、T相

									list<CDataValue*>::iterator dv = pSequence->DataValueList.begin(); //⑥遍历 DataValueList
									CDataValue* pDataValueBegin = *dv;
									list<CDataValue*>::iterator dvEnd = pSequence->DataValueList.end(); //DataValueList链表最后一个数据值元素
									while (dv != pSequence->DataValueList.end())
									{
										CDataValue* pDataValue = *dv++;

										if ("NOT DEFINE" == pDataValue->strFullName || "not define" == pDataValue->strFullName) //数据对象名 $ 数据属性名  即：拼接名为空
											continue;
										if (!data->mms_str_map.contains(pDataValue->strFullName) && pDataValueBegin->strName == pDataValue->strName)//确认字典里不含有该key
										{
											isJump = true; //跳出本层循环
											break;
										}

										try
										{
											if (pDataValue->strFullName.indexOf("$ang$f") != -1) //查找61850属性名中含有相角的定义
											{
												double dAngleTemp = data->mms_str_map.value(pDataValue->strFullName); //角度值(-180度 ~ 180度)
												dAngleTemp = dAngleTemp > 180.0f ? dAngleTemp - 360.0f : dAngleTemp;
												if (dv != dvEnd) //非单相最后一个数据值元素
													KafkaData.strText.append(QString("\"%1\":\"%2\", ").arg(pDataValue->strName).arg(QString::number(dAngleTemp, 10, 6))); //拼接 json数据值(角度值)
												else
													KafkaData.strText.append(QString("\"%1\":\"%2\" ").arg(pDataValue->strName).arg(QString::number(dAngleTemp, 10, 6))); //拼接 json数据值(角度值)
											}
											else
											{
												double dTemp = data->mms_str_map.value(pDataValue->strFullName) * pDataValue->fCoefficient; //接口数据 * 系数

												//lnk20250710添加频率存储
												if(dTemp > 0.99){
													//printf("pDataValue->strName==========================%s",pDataValue->strName.toStdString().c_str());
													if(pDataValue->strName == "G_FREQ")	{
														mp_freq_save_map[data->mp_id.toStdString()].G_FREQ = dTemp;	//保存95值
													}
													else if(pDataValue->strName == "FREQ")	{
														mp_freq_save_map[data->mp_id.toStdString()].FREQ = dTemp;	//保存平均值
													}
													else if(pDataValue->strName == "MAX_FREQ")	{
														mp_freq_save_map[data->mp_id.toStdString()].MAX_FREQ = dTemp;	//保存最大值
													}
													else if(pDataValue->strName == "MIN_FREQ")	{
														mp_freq_save_map[data->mp_id.toStdString()].MIN_FREQ = dTemp;	//保存最小值
													}

												}
												else{
													if(pDataValue->strName == "G_FREQ")	{
														dTemp = mp_freq_save_map[data->mp_id.toStdString()].G_FREQ;	//保存95值
													}
													else if(pDataValue->strName == "FREQ")	{
														dTemp = mp_freq_save_map[data->mp_id.toStdString()].FREQ;	//保存平均值
													}
													else if(pDataValue->strName == "MAX_FREQ")	{
														dTemp = mp_freq_save_map[data->mp_id.toStdString()].MAX_FREQ;	//保存最大值
													}
													else if(pDataValue->strName == "MIN_FREQ")	{
														dTemp = mp_freq_save_map[data->mp_id.toStdString()].MIN_FREQ;	//保存最小值
													}
												}
												//lnk20250710添加频率存储

												if (dv != dvEnd) //非单相最后一个数据值元素
													KafkaData.strText.append(QString("\"%1\":\"%2\", ").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //拼接 json数据值(非角度值)
												else
													KafkaData.strText.append(QString("\"%1\":\"%2\" ").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //拼接 json数据值(非角度值)

												
											}
										}
										catch (exception& e)
										{
											cout << "实时3s数据值拼接json错误，原因: " << e.what() << endl;
											return false;
										}
									} //DataValueList 结束

									if (!KafkaData.strText.isEmpty()) {
										if (KafkaData.strText[KafkaData.strText.length() - 1] == ',') {
											KafkaData.strText = KafkaData.strText.remove(KafkaData.strText.size() - 1, 1);
											KafkaData.strText.append(" ");
											cout << "KafkaData.strText = KafkaData.strText.chopped(1) " << endl;
										}
									}
									if (isJump) break; //跳出循环
									if (sq != sqEnd) //非A、B、C、T最后一个相别元素
										KafkaData.strText.append("}, "); //拼接 json相别结尾
									else
										KafkaData.strText.append("}"); //拼接 json相别结尾
								} //SequenceList 结束

								if (isJump) break; //跳出循环
								if (it != itEnd) //非 V、I、PQ最后一个json数据项元素
									KafkaData.strText.append("}, "); //拼接 json数据项结尾
								else
									KafkaData.strText.append("}}"); //拼接 json数据项结尾
							} //ItemList 结束
							if (isJump) break; //跳出循环
						} //MonitorList 结束
						if (isJump) continue; //跳出本数据类型循环
						KafkaData.strText.append("}"); //拼接 json稳态数据结尾

						kafka_data_list_mutex.lock(); //加锁
							kafka_data_list.append(KafkaData); //添加 kafka发送链表
						kafka_data_list_mutex.unlock(); //解锁
						
						return 1; //结束该函数，停止后续代码执行
					} //②-①实时3s数据解析结束！----------------------------------

					if (2 == pDataType->iDataType) //②-②实时闪变数据-----------------------------------------------------------
					{
						Ckafka_data_t KafkaData; //kafka发送数据结构类对象
						KafkaData.monitor_id = data->monitorId; //监测点ID	
						KafkaData.mp_id = data->mp_id;
						KafkaData.strTopic = "RTDATA"; //kafka发送主题	
						KafkaData.strText = ""; //kafka发送的json字符串

						long long  time_sec; //时间戳(秒)
						KafkaData.strText.append("{"); //拼接 json起始
						KafkaData.strText.append(QString("\"DATA_TYPE\":\"%1\" ").arg(pDataType->iDataType, 2, 10, QChar('0'))); //拼接 json数据类型  例：实时闪变 "02"
						KafkaData.strText.append(QString(", \"Monitor\":\"%1\" ").arg(data->mp_id));//例：监测点 "1100"

						list<CMonitor*>::iterator mt = pDataType->MonitorList.begin(); //③遍历 MonitorList
						while (mt != pDataType->MonitorList.end())
						{
							CMonitor* pMonitor = *mt++;
							KafkaData.strText.append(QString(", \"%1\":{").arg("Value")); //拼接 json监测点

							list<CItem*>::iterator it = pMonitor->ItemList.begin(); //④遍历 ItemList
							list<CItem*>::iterator itEnd = pMonitor->ItemList.end(); //ItemList链表最后一个数据值元素
							while (it != pMonitor->ItemList.end())
							{
								CItem* pItem = *it++;
								//////////////////////////////////////////////////////////lnk20250306为了数据入库，构造数据添加FLAG
								if ("FLAG" == pItem->strItemName) //剔除"FLAG"，防止sq相别出现错误指针
								{
									KafkaData.strText.append(QString("\"FLAG\":%1, ").arg(data->flag)); //拼接 json剔除标记，1不剔除，0剔除，默认剔除
									continue;
								}
								//////////////////////////////////////////////////////////
								if ("TIME" == pItem->strItemName) //剔除"FLAG"，防止sq相别出现错误指针
								{
									KafkaData.strText.append(QString("\"TIME\":\"%1\", ").arg(data->time)); //拼接 json发生时刻，毫秒
									time_sec = data->time / 1000; //时间戳(秒)
									continue;
								}
								KafkaData.strText.append(QString("\"%1\":{").arg(pItem->strItemName)); //拼接 json数据项 F

								list<CSequence*>::iterator sq = pItem->SequenceList.begin(); //⑤遍历 SequenceList
								list<CSequence*>::iterator sqEnd = pItem->SequenceList.end(); //SequenceList链表最后一个数据值元素
								while (sq != pItem->SequenceList.end())
								{
									CSequence* pSequence = *sq++;
									
									KafkaData.strText.append(QString("\"%1\":{ ").arg(line_to_phasic(pSequence->strSeq))); //拼接 json相别 A、B、C、T相

									list<CDataValue*>::iterator dv = pSequence->DataValueList.begin(); //⑥遍历 DataValueList
									CDataValue* pDataValueBegin = *dv;
									list<CDataValue*>::iterator dvEnd = pSequence->DataValueList.end(); //DataValueList链表最后一个数据值元素
									while (dv != pSequence->DataValueList.end())
									{
										CDataValue* pDataValue = *dv++;

										if ("NOT DEFINE" == pDataValue->strFullName || "not define" == pDataValue->strFullName) //数据对象名 $ 数据属性名  即：拼接名为空
											continue;
										if (!data->mms_str_map.contains(pDataValue->strFullName) && pDataValueBegin->strName == pDataValue->strName)//确认字典里不含有该key
										{
											isJump = true; //跳出本层循环
											break;
										}

										try
										{
											if (!pDataValue->bPlt) //短时闪变
											{
												double dTemp = data->mms_str_map.value(pDataValue->strFullName) * pDataValue->fCoefficient; //接口数据 * 系数
												if (dv != dvEnd) //非单相最后一个数据值元素
													KafkaData.strText.append(QString("\"%1\":\"%2\", ").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //拼接 json数据值(角度值)
												else
													KafkaData.strText.append(QString("\"%1\":\"%2\" ").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //拼接 json数据值(角度值)
											}
											else //长时闪变
											{
												if (0 == time_sec % 7200) //2小时间隔，长时闪变
												{
													double dTemp = data->mms_str_map.value(pDataValue->strFullName) * pDataValue->fCoefficient; //接口数据 * 系数
													if (dv != dvEnd) //非单相最后一个数据值元素
														KafkaData.strText.append(QString("\"%1\":\"%2\", ").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //拼接 json数据值(非角度值)
													else
														KafkaData.strText.append(QString("\"%1\":\"%2\" ").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //拼接 json数据值(非角度值)
												}
											}
										}
										catch (exception& e)
										{
											cout << "实时闪变数据值拼接json错误，原因: " << e.what() << endl;
											return false;
										}
									} //DataValueList 结束

									if (isJump) break; //跳出循环
									if (sq != sqEnd) //非A、B、C、T最后一个相别元素
										KafkaData.strText.append("}, "); //拼接 json相别结尾
									else
										KafkaData.strText.append("}"); //拼接 json相别结尾
								} //SequenceList 结束

								if (isJump) break; //跳出循环
								if (it != itEnd) //非 V、I、PQ最后一个json数据项元素
									KafkaData.strText.append("}, "); //拼接 json数据项结尾
								else
									KafkaData.strText.append("}}"); //拼接 json数据项结尾
							} //ItemList 结束
							if (isJump) break; //跳出循环
						} //MonitorList 结束
						if (isJump) continue; //跳出本数据类型循环
						KafkaData.strText.append("}"); //拼接 json稳态数据结尾

						//调试用
						if(DEBUGOPEN)cout << KafkaData.strText.toAscii().data() << endl;

						kafka_data_list_mutex.lock(); //加锁
							kafka_data_list.append(KafkaData); //添加 kafka发送链表
						kafka_data_list_mutex.unlock(); //解锁

						
						
						return 1; //结束该函数，停止后续代码执行
					} //②-②实时闪变数据解析结束！--------------------------------
				} //DataTypeList 结束
			} //遍历 RTDATA 结束！

			if ("RTDATASOE" == pTopic->strTopic) //Topic等于RTDATASOE----------------------------------------------------------
			{
				list<CDataType*>::iterator dt = pTopic->DataTypeList.begin(); //②遍历 DataTypeList
				while (dt != pTopic->DataTypeList.end())
				{
					int triggerCount = 0; //SOE触发标识计数
					CDataType* pDataType = *dt++;
					if (1 == pDataType->iDataType) //②-①SOE稳态事件------------------------------------------------------------
					{
						Ckafka_data_t KafkaData; //kafka发送数据结构类对象
						KafkaData.monitor_id = data->monitorId; //监测点ID	
						KafkaData.mp_id = data->mp_id;
						KafkaData.strTopic = "RTDATASOE"; //kafka发送主题
						KafkaData.strText = ""; //kafka发送的json字符串

						KafkaData.strText.append("{"); //拼接 json起始
						KafkaData.strText.append(QString("\"DATA_TYPE\":\"%1\", ").arg(pDataType->iDataType)); //拼接 json数据类型
						KafkaData.strText.append(QString("\"TIME\":\"%1\", ").arg(data->time)); //拼接 json发生时刻(毫秒)
						KafkaData.strText.append(QString("\"%1\":[").arg(data->mp_id)); //拼接 json监测点号

						list<CEventData*>::iterator ed = pDataType->SOEList.begin(); //③遍历 SOEList
						list<CEventData*>::iterator edEnd = pDataType->SOEList.end(); //SOEList尾元素
						while (ed != pDataType->SOEList.end())
						{
							CEventData* pEventData = *ed++;

							if ("NOT DEFINE" == pEventData->strFullName || "not define" == pEventData->strFullName) //数据对象名 $ 数据属性名  即：拼接名为空
								continue;
							if (!data->mms_str_map.contains(pEventData->strFullName))//确认字典里不含有该key
								continue;

							try
							{
								double dTemp = data->mms_str_map.value(pEventData->strFullName);
								if (dTemp >= 0.9) //SOE事件发生
								{
									if (0 == triggerCount) //SOE触发标识计数
									{
										KafkaData.strText.append(QString("\"%1\" ").arg(pEventData->triggerFlag)); //拼接 json SOE触发标识
										triggerCount++; //SOE触发标识计数
									}
									else
										KafkaData.strText.append(QString(", \"%1\" ").arg(pEventData->triggerFlag)); //拼接 json SOE触发标识
								}
							}
							catch (exception& e)
							{
								cout << "SOE稳态事件拼接json错误，原因: " << e.what() << endl;
								return false;
							}
						} //SOEList 结束
						KafkaData.strText.append("]}"); //拼接 json稳态数据结尾

						kafka_data_list_mutex.lock(); //加锁
							kafka_data_list.append(KafkaData); //添加 kafka发送链表
						kafka_data_list_mutex.unlock(); //解锁
						
						return 1; //结束该函数，停止后续代码执行
					} //②-①SOE稳态事件解析结束！---------------------------------

					if (2 == pDataType->iDataType) //②-②SOE暂态事件------------------------------------------------------------
					{
						Ckafka_data_t KafkaData; //kafka发送数据结构类对象
						KafkaData.monitor_id = data->monitorId; //监测点ID	
						KafkaData.mp_id = data->mp_id;
						KafkaData.strTopic = "RTDATASOE"; //kafka发送主题
						KafkaData.strText = ""; //kafka发送的json字符串

						KafkaData.strText.append("{"); //拼接 json起始
						KafkaData.strText.append(QString("\"DATA_TYPE\":\"%1\", ").arg(pDataType->iDataType)); //拼接 json数据类型
						KafkaData.strText.append(QString("\"TIME\":\"%1\", ").arg(data->time)); //拼接 json发生时刻(毫秒)
						KafkaData.strText.append(QString("\"%1\":[").arg(data->mp_id)); //拼接 json监测点号

						list<CEventData*>::iterator ed = pDataType->SOEList.begin(); //③遍历 SOEList
						list<CEventData*>::iterator edEnd = pDataType->SOEList.end(); //SOEList尾元素
						while (ed != pDataType->SOEList.end())
						{
							CEventData* pEventData = *ed++;

							if ("NOT DEFINE" == pEventData->strFullName || "not define" == pEventData->strFullName) //数据对象名 $ 数据属性名  即：拼接名为空
								continue;
							if (!data->mms_str_map.contains(pEventData->strFullName))//确认字典里不含有该key
								continue;

							try
							{
								double dTemp = data->mms_str_map.value(pEventData->strFullName);
								if (dTemp >= 0.9) //SOE事件发生
								{
									if (0 == triggerCount) //SOE触发标识计数
									{
										KafkaData.strText.append(QString("\"%1\" ").arg(pEventData->triggerFlag)); //拼接 json SOE触发标识
										triggerCount++; //SOE触发标识计数
									}
									else
										KafkaData.strText.append(QString(", \"%1\" ").arg(pEventData->triggerFlag)); //拼接 json SOE触发标识
								}
							}
							catch (exception& e)
							{
								cout << "SOE暂态事件拼接json错误，原因: " << e.what() << endl;
								return false;
							}
						} //SOEList 结束
						KafkaData.strText.append("]}"); //拼接 json稳态数据结尾

						kafka_data_list_mutex.lock(); //加锁
							kafka_data_list.append(KafkaData); //添加 kafka发送链表
						kafka_data_list_mutex.unlock(); //解锁
						
						return 1; //结束该函数，停止后续代码执行
					} //②-②SOE暂态事件解析结束！---------------------------------

					if (3 == pDataType->iDataType) //②-③SOE状态事件------------------------------------------------------------
					{
						Ckafka_data_t KafkaData; //kafka发送数据结构类对象
						KafkaData.monitor_id = data->monitorId; //监测点ID	
						KafkaData.mp_id = data->mp_id;
						KafkaData.strTopic = "RTDATASOE"; //kafka发送主题
						KafkaData.strText = ""; //kafka发送的json字符串

						KafkaData.strText.append("{"); //拼接 json起始
						KafkaData.strText.append(QString("\"DATA_TYPE\":\"%1\", ").arg(pDataType->iDataType)); //拼接 json数据类型
						KafkaData.strText.append(QString("\"TIME\":\"%1\", ").arg(data->time)); //拼接 json发生时刻(毫秒)
						KafkaData.strText.append(QString("\"%1\":[").arg(data->mp_id)); //拼接 json监测点号

						list<CEventData*>::iterator ed = pDataType->SOEList.begin(); //③遍历 SOEList
						list<CEventData*>::iterator edEnd = pDataType->SOEList.end(); //SOEList尾元素
						while (ed != pDataType->SOEList.end())
						{
							CEventData* pEventData = *ed++;

							if ("NOT DEFINE" == pEventData->strFullName || "not define" == pEventData->strFullName) //数据对象名 $ 数据属性名  即：拼接名为空
								continue;
							if (!data->mms_str_map.contains(pEventData->strFullName))//确认字典里不含有该key
								continue;

							try
							{
								double dTemp = data->mms_str_map.value(pEventData->strFullName);
								if (dTemp >= 0.9) //SOE事件发生
								{
									if (0 == triggerCount) //SOE触发标识计数
									{
										KafkaData.strText.append(QString("\"%1\" ").arg(pEventData->triggerFlag)); //拼接 json SOE触发标识
										triggerCount++; //SOE触发标识计数
									}
									else
										KafkaData.strText.append(QString(", \"%1\" ").arg(pEventData->triggerFlag)); //拼接 json SOE触发标识
								}
							}
							catch (exception& e)
							{
								cout << "SOE状态事件拼接json错误，原因: " << e.what() << endl;
								return false;
							}
						} //SOEList 结束
						KafkaData.strText.append("]}"); //拼接 json稳态数据结尾

						kafka_data_list_mutex.lock(); //加锁
							kafka_data_list.append(KafkaData); //添加 kafka发送链表
						kafka_data_list_mutex.unlock(); //解锁
						
						return 1; //结束该函数，停止后续代码执行
					} //②-③SOE状态事件解析结束！---------------------------------
				} //DataTypeList 结束
			} //遍历 RTDATASOE 结束！
		} //TopicList 结束
	} //二、结束

	if (400 == data->func_type || 500 == data->func_type || 600 == data->func_type || 700 == data->func_type) //三、补招历史数据 ——> MMS_Recall
	{		
		list<CTopic*>::iterator tp = ctopic_list.begin();
		while (tp != ctopic_list.end()) //①遍历 Kafka发送主题链表
		{			
			CTopic* pTopic = *tp++;
			if ("HISDATA" == pTopic->strTopic) //Topic等于HISDATA----------------------------------------------------------
			{
				list<CDataType*>::iterator dt = pTopic->DataTypeList.begin(); //②遍历 DataTypeList
				while (dt != pTopic->DataTypeList.end())
				{
					bool isJump = false; //是否跳出(整个数据类型)循环
					CDataType* pDataType = *dt++;

					if (2 == pDataType->iDataType) //②-②历史短闪变数据------------------------------------------------------------
					{
						Ckafka_data_t KafkaData; //kafka发送数据结构类对象
						KafkaData.monitor_id = data->monitorId; //监测点ID	
						KafkaData.mp_id = data->mp_id;
						KafkaData.strTopic = "PST"; //kafka发送主题		
						KafkaData.strText = ""; //kafka发送的json字符串

						long long  time_sec; //时间戳(秒)
						KafkaData.strText.append("{"); //拼接 json起始
						KafkaData.strText.append(QString("\"DATA_TYPE\":\"%1\" ").arg(pDataType->iDataType, 2, 10, QChar('0'))); //拼接 json数据类型  例：历史闪变 "02"
						KafkaData.strText.append(QString(", \"Monitor\":\"%1\" ").arg(data->mp_id));//例：监测点 "1100"

						list<CMonitor*>::iterator mt = pDataType->MonitorList.begin(); //③遍历 MonitorList
						int countflag = 0, num = 0;
						while (mt != pDataType->MonitorList.end())
						{
							CMonitor* pMonitor = *mt++;
							KafkaData.strText.append(QString(", \"%1\":{").arg("Value")); //拼接 json监测点

							list<CItem*>::iterator it = pMonitor->ItemList.begin(); //④遍历 ItemList
							list<CItem*>::iterator itEnd = pMonitor->ItemList.end(); //ItemList链表最后一个数据值元素
							while (it != pMonitor->ItemList.end())
							{
								CItem* pItem = *it++;
								//////////////////////////////////////////////////////////lnk20250306为了数据入库，构造数据添加FLAG
								if ("FLAG" == pItem->strItemName) //剔除"FLAG"，防止sq相别出现错误指针
								{
									KafkaData.strText.append(QString("\"FLAG\":%1, ").arg(data->flag)); //拼接 json剔除标记，1不剔除，0剔除，默认剔除
									continue;
								}
								//////////////////////////////////////////////////////////
								if ("TIME" == pItem->strItemName) //剔除"FLAG"，防止sq相别出现错误指针
								{
									KafkaData.strText.append(QString("\"TIME\":\"%1\", ").arg(data->time)); //拼接 json发生时刻，毫秒
									time_sec = data->time / 1000; //时间戳(秒)
									continue;
								}
								KafkaData.strText.append(QString("\"%1\":{").arg(pItem->strItemName)); //拼接 json数据项 F

								list<CSequence*>::iterator sq = pItem->SequenceList.begin(); //⑤遍历 SequenceList
								list<CSequence*>::iterator sqEnd = pItem->SequenceList.end(); //SequenceList链表最后一个数据值元素
								while (sq != pItem->SequenceList.end())
								{
									CSequence* pSequence = *sq++;
									//KafkaData.strText.append(QString("{\"SEQ\":\"%1\", ").arg(pSequence->strSeq)); //拼接 json相别 A、B、C相
									KafkaData.strText.append(QString("\"%1\":{ ").arg(line_to_phasic(pSequence->strSeq))); //拼接 json相别 A、B、C、T相

									list<CDataValue*>::iterator dv = pSequence->DataValueList.begin(); //⑥遍历 DataValueList
									CDataValue* pDataValueBegin = *dv;
									list<CDataValue*>::iterator dvEnd = pSequence->DataValueList.end(); //DataValueList链表最后一个数据值元素
									num = num + pSequence->DataValueList.size();
									while (dv != pSequence->DataValueList.end())
									{
										CDataValue* pDataValue = *dv++;

										if ("NOT DEFINE" == pDataValue->strFullName || "not define" == pDataValue->strFullName) //数据对象名 $ 数据属性名  即：拼接名为空
										{
											countflag++;
											continue;
										}
											
										if (!data->mms_str_map.contains(pDataValue->strFullName))//确认字典里不含有该key
										{
											isJump = false; //跳出本层循环
											countflag++;
											if (dv != dvEnd) //非单相最后一个数据值元素
												KafkaData.strText.append(QString("\"%1\":%2, ").arg(pDataValue->strName).arg("null")); //拼接
											else
												KafkaData.strText.append(QString("\"%1\":%2 ").arg(pDataValue->strName).arg("null")); //拼接
											continue;
										}

										try
										{
											double dTemp = data->mms_str_map.value(pDataValue->strFullName) * pDataValue->fCoefficient; //接口数据 * 系数
											if (dv != dvEnd) //非单相最后一个数据值元素
												KafkaData.strText.append(QString("\"%1\":\"%2\",").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //拼接 json数据值(角度值)
											else
												KafkaData.strText.append(QString("\"%1\":\"%2\" ").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //拼接 json数据值(角度值)
										}
										catch (exception& e)
										{
											cout << "历史闪变数据值拼接json错误，原因: " << e.what() << endl;
											return false;
										}
									} //DataValueList 结束

									if (!KafkaData.strText.isEmpty()) {
										if (KafkaData.strText[KafkaData.strText.length() - 1] == ',') {
											KafkaData.strText = KafkaData.strText.remove(KafkaData.strText.size() - 1, 1);
											KafkaData.strText.append(" ");
											cout << "KafkaData.strText = KafkaData.strText.chopped(1) " << endl;
										}
									}
									if (isJump) break; //跳出循环
									if (sq != sqEnd) //非A、B、C、T最后一个相别元素
										KafkaData.strText.append("}, "); //拼接 json相别结尾
									else
										KafkaData.strText.append("}"); //拼接 json相别结尾
								} //SequenceList 结束

								if (isJump) break; //跳出循环
								if (it != itEnd) //非 V、I、PQ最后一个json数据项元素
									KafkaData.strText.append("}, "); //拼接 json数据项结尾
								else
									KafkaData.strText.append("}}"); //拼接 json数据项结尾
							} //ItemList 结束
							if (isJump) break; //跳出循环
						} //MonitorList 结束
						if (isJump) continue; //跳出本数据类型循环
						KafkaData.strText.append("}"); //拼接 json稳态数据结尾

						cout << countflag << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!send name=\"DATA_TYPE\" value=\"02\" " << num << endl;
						cout << KafkaData.strText.toAscii().data() << endl;
						if (countflag < num) {
							kafka_data_list_mutex.lock(); //加锁
							kafka_data_list.append(KafkaData); //添加 kafka发送链表
							kafka_data_list_mutex.unlock(); //解锁
							shortjumpflag = true;
						}
					} //②-②历史闪变数据解析结束！--------------------------------

					//20241204长闪变类型应该为3
					if (3 == pDataType->iDataType) //②-②历史长闪变数据------------------------------------------------------------
					{
						Ckafka_data_t KafkaData; //kafka发送数据结构类对象
						KafkaData.monitor_id = data->monitorId; //监测点ID	
						KafkaData.mp_id = data->mp_id;
						KafkaData.strTopic = "PLT"; //kafka发送主题		
						KafkaData.strText = ""; //kafka发送的json字符串

						long long  time_sec; //时间戳(秒)
						KafkaData.strText.append("{"); //拼接 json起始
						KafkaData.strText.append(QString("\"DATA_TYPE\":\"%1\" ").arg(pDataType->iDataType, 2, 10, QChar('0'))); //拼接 json数据类型  例：历史闪变 "02"
						KafkaData.strText.append(QString(", \"Monitor\":\"%1\" ").arg(data->mp_id));//例：监测点 "1100"

						list<CMonitor*>::iterator mt = pDataType->MonitorList.begin(); //③遍历 MonitorList
						int countflag = 0, num = 0;
						while (mt != pDataType->MonitorList.end())
						{
							CMonitor* pMonitor = *mt++;
							KafkaData.strText.append(QString(", \"%1\":{").arg("Value")); //拼接 json监测点

							list<CItem*>::iterator it = pMonitor->ItemList.begin(); //④遍历 ItemList
							list<CItem*>::iterator itEnd = pMonitor->ItemList.end(); //ItemList链表最后一个数据值元素
							while (it != pMonitor->ItemList.end())
							{
								CItem* pItem = *it++;
								//////////////////////////////////////////////////////////lnk20250306为了数据入库，构造数据添加FLAG
								if ("FLAG" == pItem->strItemName) //剔除"FLAG"，防止sq相别出现错误指针
								{
									KafkaData.strText.append(QString("\"FLAG\":%1, ").arg(data->flag)); //拼接 json剔除标记，1不剔除，0剔除，默认剔除
									continue;
								}
								//////////////////////////////////////////////////////////
								if ("TIME" == pItem->strItemName) //剔除"FLAG"，防止sq相别出现错误指针
								{
									KafkaData.strText.append(QString("\"TIME\":\"%1\", ").arg(data->time)); //拼接 json发生时刻，毫秒
									time_sec = data->time / 1000; //时间戳(秒)
									continue;
								}
								KafkaData.strText.append(QString("\"%1\":{").arg(pItem->strItemName)); //拼接 json数据项 F

								list<CSequence*>::iterator sq = pItem->SequenceList.begin(); //⑤遍历 SequenceList
								list<CSequence*>::iterator sqEnd = pItem->SequenceList.end(); //SequenceList链表最后一个数据值元素
								while (sq != pItem->SequenceList.end())
								{
									CSequence* pSequence = *sq++;
									//KafkaData.strText.append(QString("{\"SEQ\":\"%1\", ").arg(pSequence->strSeq)); //拼接 json相别 A、B、C相
									KafkaData.strText.append(QString("\"%1\":{ ").arg(line_to_phasic(pSequence->strSeq))); //拼接 json相别 A、B、C、T相

									list<CDataValue*>::iterator dv = pSequence->DataValueList.begin(); //⑥遍历 DataValueList
									CDataValue* pDataValueBegin = *dv;
									list<CDataValue*>::iterator dvEnd = pSequence->DataValueList.end(); //DataValueList链表最后一个数据值元素
									num = num + pSequence->DataValueList.size();
									while (dv != pSequence->DataValueList.end())
									{
										CDataValue* pDataValue = *dv++;

										if ("NOT DEFINE" == pDataValue->strFullName || "not define" == pDataValue->strFullName) //数据对象名 $ 数据属性名  即：拼接名为空
										{
											countflag++;
											continue;
										}
										if (!data->mms_str_map.contains(pDataValue->strFullName))//确认字典里不含有该key
										{
											isJump = false; //跳出本层循环
											countflag++;
											if (dv != dvEnd) //非单相最后一个数据值元素
												KafkaData.strText.append(QString("\"%1\":%2, ").arg(pDataValue->strName).arg("null")); //拼接
											else
												KafkaData.strText.append(QString("\"%1\":%2 ").arg(pDataValue->strName).arg("null")); //拼接
											continue;
										}

										try
										{
											if (0 == time_sec % 7200) //2小时间隔，长时闪变
											{
												double dTemp = data->mms_str_map.value(pDataValue->strFullName) * pDataValue->fCoefficient; //接口数据 * 系数
												if (dv != dvEnd) //非单相最后一个数据值元素
													KafkaData.strText.append(QString("\"%1\":\"%2\", ").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //拼接 json数据值(角度值)
												else
													KafkaData.strText.append(QString("\"%1\":\"%2\" ").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //拼接 json数据值(角度值)
											}
										}
										catch (exception& e)
										{
											cout << "历史闪变数据值拼接json错误，原因: " << e.what() << endl;
											return false;
										}
									} //DataValueList 结束

									if (!KafkaData.strText.isEmpty()) {
										if (KafkaData.strText[KafkaData.strText.length() - 1] == ',') {
											KafkaData.strText = KafkaData.strText.remove(KafkaData.strText.size() - 1, 1);
											KafkaData.strText.append(" ");
											cout << "KafkaData.strText = KafkaData.strText.chopped(1) " << endl;
										}
									}
									if (isJump) break; //跳出循环
									if (sq != sqEnd) //非A、B、C、T最后一个相别元素
										KafkaData.strText.append("}, "); //拼接 json相别结尾
									else
										KafkaData.strText.append("}"); //拼接 json相别结尾
								} //SequenceList 结束

								if (isJump) break; //跳出循环
								if (it != itEnd) //非 V、I、PQ最后一个json数据项元素
									KafkaData.strText.append("}, "); //拼接 json数据项结尾
								else
									KafkaData.strText.append("}}"); //拼接 json数据项结尾
							} //ItemList 结束
							if (isJump) break; //跳出循环
						} //MonitorList 结束
						if (isJump) continue; //跳出本数据类型循环
						KafkaData.strText.append("}"); //拼接 json稳态数据结尾

						cout << countflag << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!send name=\"DATA_TYPE\" value=\"03\" " << num << endl;
						cout << KafkaData.strText.toAscii().data() << endl;
						if (countflag < num && 0 == time_sec % 7200) {
							kafka_data_list_mutex.lock(); //加锁
							kafka_data_list.append(KafkaData); //添加 kafka发送链表
							kafka_data_list_mutex.unlock(); //解锁
							longjumpflag = true;
						}
						else if (countflag < num && 0 != time_sec % 7200) {
							longjumpflag = true;//不发送数据
						}
						if (typeofdata == false || data_have_static == false) {//不合并则处理完闪变就不处理其他数据
							if (longjumpflag == true || shortjumpflag == true) {
								return 1;
							}
						}
						//return 1; //结束该函数，停止后续代码执行
					} //②-②历史闪变数据解析结束！--------------------------------

					if (1 == pDataType->iDataType) //②-①历史稳态数据-----------------------------------------------------------
					{
						Ckafka_data_t KafkaData; //kafka发送数据结构类对象
						KafkaData.monitor_id = data->monitorId; //监测点ID	
						KafkaData.mp_id = data->mp_id;
						KafkaData.strTopic = "HISDATA"; //kafka发送主题		
						KafkaData.strText = ""; //kafka发送的json字符串

						KafkaData.strText.append("{"); //拼接 json起始
						KafkaData.strText.append(QString("\"DATA_TYPE\":\"%1\" ").arg(pDataType->iDataType, 2, 10, QChar('0'))); //拼接 json数据类型  例：历史稳态 "01"
						KafkaData.strText.append(QString(", \"Monitor\":\"%1\" ").arg(data->mp_id));//例：监测点 "1100"

						list<CMonitor*>::iterator mt = pDataType->MonitorList.begin(); //③遍历 MonitorList
						while (mt != pDataType->MonitorList.end())
						{
							CMonitor* pMonitor = *mt++;
							KafkaData.strText.append(QString(", \"%1\":{").arg("Value")); //拼接 json监测点

							list<CItem*>::iterator it = pMonitor->ItemList.begin(); //④遍历 ItemList
							list<CItem*>::iterator itEnd = pMonitor->ItemList.end(); //ItemList链表最后一个数据值元素
							while (it != pMonitor->ItemList.end())
							{
								CItem* pItem = *it++;
								if ("FLAG" == pItem->strItemName) //剔除"FLAG"，防止sq相别出现错误指针
								{
									KafkaData.strText.append(QString("\"FLAG\":%1, ").arg(data->flag)); //拼接 json剔除标记，1不剔除，0剔除，默认剔除
									continue;
								}
								if ("TIME" == pItem->strItemName) //剔除"TIME"，防止sq相别出现错误指针
								{
									KafkaData.strText.append(QString("\"TIME\":%1, ").arg(data->time)); //拼接 json发生时刻，毫秒
									if (!data_timespan_list.contains(data->mp_id)) {
										KafkaData.strText.append(QString("\"interval\":%1, ").arg(3)); //拼接 json发生时刻，毫秒
										
									}
									else if (data_timespan_list[data->mp_id]->msspan == 0)
									{
										KafkaData.strText.append(QString("\"interval\":%1, ").arg(3)); //拼接 json发生时刻，毫秒
									}
									else {
										KafkaData.strText.append(QString("\"interval\":%1, ").arg(data_timespan_list[data->mp_id]->msspan)); //拼接 json发生时刻，毫秒
									}
									continue;
								}
								KafkaData.strText.append(QString("\"%1\":{").arg(pItem->strItemName)); //拼接 json数据项 V、I、PQ

								list<CSequence*>::iterator sq = pItem->SequenceList.begin(); //⑤遍历 SequenceList
								list<CSequence*>::iterator sqEnd = pItem->SequenceList.end(); //SequenceList链表最后一个数据值元素
								while (sq != pItem->SequenceList.end())
								{
									CSequence* pSequence = *sq++;
									//KafkaData.strText.append(QString("{\"SEQ\":\"%1\", ").arg(pSequence->strSeq)); //拼接 json相别 A、B、C、T相
									KafkaData.strText.append(QString("\"%1\":{ ").arg(line_to_phasic(pSequence->strSeq))); //拼接 json相别 A、B、C、T相

									list<CDataValue*>::iterator dv = pSequence->DataValueList.begin(); //⑥遍历 DataValueList
									CDataValue* pDataValueBegin = *dv;
									list<CDataValue*>::iterator dvEnd = pSequence->DataValueList.end(); //DataValueList链表最后一个数据值元素
									while (dv != pSequence->DataValueList.end())
									{
										CDataValue* pDataValue = *dv++;

										if ("NOT DEFINE" == pDataValue->strFullName || "not define" == pDataValue->strFullName) //数据对象名 $ 数据属性名  即：拼接名为空
											continue;
										if (!data->mms_str_map.contains(pDataValue->strFullName))//确认字典里不含有该key
										{
											isJump = false; //跳出本层循环
											//zw修改 2023-8-28 不匹配数据添加
											if (dv != dvEnd) //非单相最后一个数据值元素
												KafkaData.strText.append(QString("\"%1\":%2, ").arg(pDataValue->strName).arg("null")); //拼接
											else
												KafkaData.strText.append(QString("\"%1\":%2 ").arg(pDataValue->strName).arg("null")); //拼接

										
											continue;
										}

										try
										{
											if (pDataValue->strFullName.indexOf("$ang$f") != -1) //查找61850属性名中含有相角的定义
											{
												double dAngleTemp = data->mms_str_map.value(pDataValue->strFullName); //角度值(-180度 ~ 180度)
												dAngleTemp = dAngleTemp > 180.0f ? dAngleTemp - 360.0f : dAngleTemp;
												if (dv != dvEnd) //非单相最后一个数据值元素
													KafkaData.strText.append(QString("\"%1\":\"%2\", ").arg(pDataValue->strName).arg(QString::number(dAngleTemp, 10, 6))); //拼接 json数据值(角度值)
												else
													KafkaData.strText.append(QString("\"%1\":\"%2\" ").arg(pDataValue->strName).arg(QString::number(dAngleTemp, 10, 6))); //拼接 json数据值(角度值)
												
											}
											else
											{
												double dTemp = data->mms_str_map.value(pDataValue->strFullName) * pDataValue->fCoefficient; //接口数据 * 系数
												if (dv != dvEnd) //非单相最后一个数据值元素
													KafkaData.strText.append(QString("\"%1\":\"%2\", ").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //拼接 json数据值(非角度值)
												else
													KafkaData.strText.append(QString("\"%1\":\"%2\" ").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //拼接 json数据值(非角度值)
												
											}
										}
										catch (exception& e)
										{
											cout << "历史稳态数据值拼接json错误，原因: " << e.what() << endl;
											return false;
										}
									} //DataValueList 结束

									if (!KafkaData.strText.isEmpty()) {
										if (KafkaData.strText[KafkaData.strText.length() - 1] == ',') {
											KafkaData.strText = KafkaData.strText.remove(KafkaData.strText.size() - 1, 1);
											KafkaData.strText.append(" ");
											cout << "KafkaData.strText = KafkaData.strText.chopped(1) " << endl;
										}
									}
									if (isJump) break; //跳出循环
									if (sq != sqEnd) //非A、B、C、T最后一个相别元素
										KafkaData.strText.append("}, "); //拼接 json相别结尾
									else
										KafkaData.strText.append("}"); //拼接 json相别结尾
								} //SequenceList 结束

								if (isJump) break; //跳出循环
								if (it != itEnd) //非 V、I、PQ最后一个json数据项元素
									KafkaData.strText.append("}, "); //拼接 json数据项结尾
								else
									KafkaData.strText.append("}}"); //拼接 json数据项结尾
							} //ItemList 结束
							if (isJump) break; //跳出循环
						} //MonitorList 结束
						if (isJump) continue; //跳出本数据类型循环
						KafkaData.strText.append("}"); //拼接 json稳态数据结尾

						//调试用
						if(DEBUGOPEN)cout << KafkaData.strText.toAscii().data() << endl;

						kafka_data_list_mutex.lock(); //加锁
						kafka_data_list.append(KafkaData); //添加 kafka发送链表
						kafka_data_list_mutex.unlock(); //解锁

						return 1; //结束该函数，停止后续代码执行
					} //②-①历史稳态数据解析结束！--------------------------------
				} //DataTypeList 结束
			} //遍历 HISDATA 结束！

			if ("RTDATASOE" == pTopic->strTopic) //Topic等于RTDATASOE----------------------------------------------------------
			{
				list<CDataType*>::iterator dt = pTopic->DataTypeList.begin(); //②遍历 DataTypeList
				while (dt != pTopic->DataTypeList.end())
				{
					int triggerCount = 0; //SOE触发标识计数
					CDataType* pDataType = *dt++;
					if (1 == pDataType->iDataType) //②-①SOE稳态事件------------------------------------------------------------
					{
						Ckafka_data_t KafkaData; //kafka发送数据结构类对象
						KafkaData.monitor_id = data->monitorId; //监测点ID	
						KafkaData.mp_id = data->mp_id;
						KafkaData.strTopic = "RTDATASOE"; //kafka发送主题
						KafkaData.strText = ""; //kafka发送的json字符串

						KafkaData.strText.append("{"); //拼接 json起始
						KafkaData.strText.append(QString("\"DATA_TYPE\":\"%1\", ").arg(pDataType->iDataType)); //拼接 json数据类型
						KafkaData.strText.append(QString("\"TIME\":\"%1\", ").arg(data->time)); //拼接 json发生时刻(毫秒)
						KafkaData.strText.append(QString("\"%1\":[").arg(data->mp_id)); //拼接 json监测点号

						list<CEventData*>::iterator ed = pDataType->SOEList.begin(); //③遍历 SOEList
						list<CEventData*>::iterator edEnd = pDataType->SOEList.end(); //SOEList尾元素
						while (ed != pDataType->SOEList.end())
						{
							CEventData* pEventData = *ed++;

							if ("NOT DEFINE" == pEventData->strFullName || "not define" == pEventData->strFullName) //数据对象名 $ 数据属性名  即：拼接名为空
								continue;
							if (!data->mms_str_map.contains(pEventData->strFullName))//确认字典里不含有该key
								continue;

							try
							{
								double dTemp = data->mms_str_map.value(pEventData->strFullName);
								if (dTemp >= 0.9) //SOE事件发生
								{
									if (0 == triggerCount) //SOE触发标识计数
									{
										KafkaData.strText.append(QString("\"%1\" ").arg(pEventData->triggerFlag)); //拼接 json SOE触发标识
										triggerCount++; //SOE触发标识计数
									}
									else
										KafkaData.strText.append(QString(", \"%1\" ").arg(pEventData->triggerFlag)); //拼接 json SOE触发标识
								}
							}
							catch (exception& e)
							{
								cout << "SOE稳态事件拼接json错误，原因: " << e.what() << endl;
								return false;
							}
						} //SOEList 结束
						KafkaData.strText.append("]}"); //拼接 json稳态数据结尾

						kafka_data_list_mutex.lock(); //加锁
							kafka_data_list.append(KafkaData); //添加 kafka发送链表
						kafka_data_list_mutex.unlock(); //解锁
						
						return 1; //结束该函数，停止后续代码执行
					} //②-①SOE稳态事件解析结束！---------------------------------

					if (1 == pDataType->iDataType) //②-②SOE暂态事件------------------------------------------------------------
					{
						Ckafka_data_t KafkaData; //kafka发送数据结构类对象
						KafkaData.monitor_id = data->monitorId; //监测点ID	
						KafkaData.mp_id = data->mp_id;
						KafkaData.strTopic = "RTDATASOE"; //kafka发送主题
						KafkaData.strText = ""; //kafka发送的json字符串

						KafkaData.strText.append("{"); //拼接 json起始
						KafkaData.strText.append(QString("\"DATA_TYPE\":\"%1\", ").arg(pDataType->iDataType)); //拼接 json数据类型
						KafkaData.strText.append(QString("\"TIME\":\"%1\", ").arg(data->time)); //拼接 json发生时刻(毫秒)
						KafkaData.strText.append(QString("\"%1\":[").arg(data->mp_id)); //拼接 json监测点号

						list<CEventData*>::iterator ed = pDataType->SOEList.begin(); //③遍历 SOEList
						list<CEventData*>::iterator edEnd = pDataType->SOEList.end(); //SOEList尾元素
						while (ed != pDataType->SOEList.end())
						{
							CEventData* pEventData = *ed++;

							if ("NOT DEFINE" == pEventData->strFullName || "not define" == pEventData->strFullName) //数据对象名 $ 数据属性名  即：拼接名为空
								continue;
							if (!data->mms_str_map.contains(pEventData->strFullName))//确认字典里不含有该key
								continue;

							try
							{
								double dTemp = data->mms_str_map.value(pEventData->strFullName);
								if (dTemp >= 0.9) //SOE事件发生
								{
									if (0 == triggerCount) //SOE触发标识计数
									{
										KafkaData.strText.append(QString("\"%1\" ").arg(pEventData->triggerFlag)); //拼接 json SOE触发标识
										triggerCount++; //SOE触发标识计数
									}
									else
										KafkaData.strText.append(QString(", \"%1\" ").arg(pEventData->triggerFlag)); //拼接 json SOE触发标识
								}
							}
							catch (exception& e)
							{
								cout << "SOE暂态事件拼接json错误，原因: " << e.what() << endl;
								return false;
							}
						} //SOEList 结束
						KafkaData.strText.append("]}"); //拼接 json稳态数据结尾

						kafka_data_list_mutex.lock(); //加锁
							kafka_data_list.append(KafkaData); //添加 kafka发送链表
						kafka_data_list_mutex.unlock(); //解锁
						
						return 1; //结束该函数，停止后续代码执行
					} //②-②SOE暂态事件解析结束！---------------------------------

					if (1 == pDataType->iDataType) //②-③SOE状态事件------------------------------------------------------------
					{
						Ckafka_data_t KafkaData; //kafka发送数据结构类对象
						KafkaData.monitor_id = data->monitorId; //监测点ID	
						KafkaData.mp_id = data->mp_id;
						KafkaData.strTopic = "RTDATASOE"; //kafka发送主题
						KafkaData.strText = ""; //kafka发送的json字符串

						KafkaData.strText.append("{"); //拼接 json起始
						KafkaData.strText.append(QString("\"DATA_TYPE\":\"%1\", ").arg(pDataType->iDataType)); //拼接 json数据类型
						KafkaData.strText.append(QString("\"TIME\":\"%1\", ").arg(data->time)); //拼接 json发生时刻(毫秒)
						KafkaData.strText.append(QString("\"%1\":[").arg(data->mp_id)); //拼接 json监测点号

						list<CEventData*>::iterator ed = pDataType->SOEList.begin(); //③遍历 SOEList
						list<CEventData*>::iterator edEnd = pDataType->SOEList.end(); //SOEList尾元素
						while (ed != pDataType->SOEList.end())
						{
							CEventData* pEventData = *ed++;

							if ("NOT DEFINE" == pEventData->strFullName || "not define" == pEventData->strFullName) //数据对象名 $ 数据属性名  即：拼接名为空
								continue;
							if (!data->mms_str_map.contains(pEventData->strFullName))//确认字典里不含有该key
								continue;

							try
							{
								double dTemp = data->mms_str_map.value(pEventData->strFullName);
								if (dTemp >= 0.9) //SOE事件发生
								{
									if (0 == triggerCount) //SOE触发标识计数
									{
										KafkaData.strText.append(QString("\"%1\" ").arg(pEventData->triggerFlag)); //拼接 json SOE触发标识
										triggerCount++; //SOE触发标识计数
									}
									else
										KafkaData.strText.append(QString(", \"%1\" ").arg(pEventData->triggerFlag)); //拼接 json SOE触发标识
								}
							}
							catch (exception& e)
							{
								cout << "SOE状态事件拼接json错误，原因: " << e.what() << endl;
								return false;
							}
						} //SOEList 结束
						KafkaData.strText.append("]}"); //拼接 json稳态数据结尾

						kafka_data_list_mutex.lock(); //加锁
							kafka_data_list.append(KafkaData); //添加 kafka发送链表
						kafka_data_list_mutex.unlock(); //解锁
						
						return 1; //结束该函数，停止后续代码执行
					} //②-③SOE状态事件解析结束！---------------------------------
				} //DataTypeList 结束
			} //遍历 RTDATASOE 结束！
		} //TopicList 结束
	} //三、结束
	
	return 1;
}

static void format_time_ms(long long ms, char* buf, size_t buf_len)
{
    time_t sec = ms / 1000;
    int milli = ms % 1000;

    struct tm tm_time;
    localtime_r(&sec, &tm_time);   // 线程安全

    snprintf(buf, buf_len,
             "%04d-%02d-%02d %02d:%02d:%02d.%03d",
             tm_time.tm_year + 1900,
             tm_time.tm_mon + 1,
             tm_time.tm_mday,
             tm_time.tm_hour,
             tm_time.tm_min,
             tm_time.tm_sec,
             milli);
}

void processGGIO_start_data_end(char* mp_id,char* fullname,double v,long long time,char* devtype,int monitor_id)
{

	XmlConfig c_xmlcfg;
	if (xmlinfo_list.contains(devtype)) {
		c_xmlcfg = xmlinfo_list[devtype]->xmlcfg;
	}
	else {
		c_xmlcfg = xmlcfg;
	}

	QString Full_name;
	Full_name.append(fullname);

	Ckafka_data_t KafkaData; //kafka发送数据结构类对象
	KafkaData.monitor_id = monitor_id;
	KafkaData.mp_id = mp_id;
	KafkaData.strTopic = "Alm"; //kafka发送主题

	KafkaData.strText.append("{"); //拼接 json起始
	KafkaData.strText.append("\"DATA_TYPE\":\"05\", "); //拼接 数据类型
	KafkaData.strText.append(QString("\"Monitor\":\"%1\", ").arg(mp_id)); //拼接 json监测点
	KafkaData.strText.append(QString("\"Value\":{")); //拼接 json监测点
	KafkaData.strText.append(QString("\"FLAG\":%1,").arg(1)); //拼接 剔除标记
	KafkaData.strText.append(QString("\"TIME\":%1,").arg(time)); //拼接 时间
	KafkaData.strText.append(QString("\"SOE\":[")); //拼接 SOE

	list<CEventData*>::iterator ed = c_xmlcfg.SOEList.begin(); //③遍历 SOEList
	while (ed != c_xmlcfg.SOEList.end())
	{
		CEventData* pEventData = *ed++;
		if (pEventData->strFullName.indexOf(Full_name) != -1)
		{
			KafkaData.strText.append(QString("\"%1\"").arg(pEventData->triggerFlag));

			//使用日志接口记录日志
			char time_str[64];
			format_time_ms(time, time_str, sizeof(time_str));

			QByteArray descBa = pEventData->desc.toLocal8Bit();

			pthread_mutex_lock(&mtx);   std::cout << "ggio hold lock !!!!!!!!!!!" << std::endl;
			const char* mp_name_raw = find_mp_name_from_mp_id(mp_id);
			pthread_mutex_unlock(&mtx);   std::cout << "ggio unlock lock !!!!!!!!!!!" << std::endl;

			char mp_name[128];
			if (mp_name_raw && mp_name_raw[0] != '\0') {
			    snprintf(mp_name, sizeof(mp_name), "%s", mp_name_raw);
			} else {
			    snprintf(mp_name, sizeof(mp_name), "unknown");
			}

			DIY_WARNLOG_CODE(mp_id,2 ,LOG_CODE_GGIO_LPHD,
			    "监测点:%s(%s),在%s发生事件:%s,事件值:%.2f",
			    mp_name, mp_id, time_str, descBa.constData(), v);

			break;
		}
	}

	KafkaData.strText.append(QString("]")); //拼接 SOE结束
	KafkaData.strText.append("}"); //拼接 value结束
	KafkaData.strText.append("}"); //拼接 json结束

	printf("transfer json ggio data: %s==%s \n", KafkaData.strText.toStdString().c_str(), fullname);
	kafka_data_list_mutex.lock(); //加锁
	//kafka_data_list.append(KafkaData); //添加 kafka发送链表
	kafka_data_list_mutex.unlock(); //解锁

}

//zw修改 2023-8-31 新增或更新list队列 写入xml数据库信息 模型编码 终端型号 终端厂家 oss存储路径 时间
//lnk修改 2024-10-28 去掉终端厂家，换成远端模型文件路径
//void Set_xml_databaseinfo(char* MODEL_ID, char* TMNL_TYPE, char* TMNL_FACTORY, char* FILE_NAME, int year, int month, int day, int hour, int minute, int second)
void Set_xml_databaseinfo(char* MODEL_ID, char* TMNL_TYPE, char* FILE_PATH, char* FILE_NAME, int year, int month, int day, int hour, int minute, int second)
{
	if (MODEL_ID == NULL || TMNL_TYPE == NULL || FILE_PATH == NULL || FILE_NAME == NULL)
	{
		cout << "Function Set_xml_databaseinfo Error!" << endl;
		return;
	}
	cout << "Function Set_xml_databaseinfo Start!" << endl;
	QString id, type, filepath, name;
	id.append(MODEL_ID);
	type.append(TMNL_TYPE);
	filepath.append(FILE_PATH);
	name.append(FILE_NAME);

	//调试用lnk20241125
	cout << "setxmldatabase:" << TMNL_TYPE << endl;

	if (!xmlinfo_list.contains(type))//在终端类型列表中没查到
	{
		Xmldata* config = new Xmldata();	//没找到就插个新的终端类型到列表中
		xmlinfo_list.insert(type, config);

		xmlinfo_list[type]->updataflag = true;//lnk20250820
		//调试用lnk20241125
		cout << "xmlinfo_list insert type:" << type.toStdString() << endl;
	}
	else//查到就更新覆盖
	{
		//调试用lnk20241125
		cout << "xmlinfo_list type contain:" << type.toStdString() << endl;

		QDateTime time(QDate(year, month, day), QTime(hour, minute, second));
		if (xmlinfo_list[type]->xmlbase.datetime == time) {		//终端型号更新标志，如果新增的型号错误，导致实际用的映射文件不一样，或者覆盖了原来的映射文件这里可能出问题。数据库在录入型号和映射文件时要注意
			xmlinfo_list[type]->updataflag = false;		//时间值一样说明是没有更新，当前业务中不包含时间值，所以每次都会更新
		}
		else {
			xmlinfo_list[type]->updataflag = true;
		}
		//lnk20250208如果类型存在则不再往下执行
	}

	//lnk20250208这里应该是覆盖而不是追加
	//xmlinfo_list[type]->xmlbase.MODEL_ID.append(id);
	//xmlinfo_list[type]->xmlbase.TMNL_TYPE.append(type);
	//xmlinfo_list[type]->xmlbase.FILE_PATH.append(filepath);
	//xmlinfo_list[type]->xmlbase.FILE_NAME.append(name);
	xmlinfo_list[type]->xmlbase.MODEL_ID = id;
	xmlinfo_list[type]->xmlbase.TMNL_TYPE = type;
	xmlinfo_list[type]->xmlbase.FILE_PATH = filepath;
	xmlinfo_list[type]->xmlbase.FILE_NAME = name;

	QDateTime time(QDate(year, month, day), QTime(hour, minute, second));
	xmlinfo_list[type]->xmlbase.datetime = time;

	cout << "##################################isdelta_flag is " << isdelta_flag << endl;
	/*lnk2024-8-14 根据isdelta_flag 选择xmllist*/
	if (isdelta_flag) {
		cout << "xmllist2 create" << endl;
		if (!xmlinfo_list2.contains(type))
		{
			Xmldata* config2 = new Xmldata();
			xmlinfo_list2.insert(type, config2);
			xmlinfo_list2[type]->updataflag = true;
		}
		else
		{
			QDateTime time(QDate(year, month, day), QTime(hour, minute, second));
			if (xmlinfo_list2[type]->xmlbase.datetime == time) {
				xmlinfo_list2[type]->updataflag = false;
			}
			else {
				xmlinfo_list2[type]->updataflag = true;
			}
		}
		xmlinfo_list2[type]->xmlbase.MODEL_ID = id;
		xmlinfo_list2[type]->xmlbase.TMNL_TYPE = type;
		xmlinfo_list2[type]->xmlbase.FILE_PATH = filepath;
		xmlinfo_list2[type]->xmlbase.FILE_NAME = name;
		xmlinfo_list2[type]->xmlbase.datetime = time;
	}
	/*lnk2024-8-14*/

	char file_name[256];
	memset(file_name, 0, 256);
	snprintf(file_name, sizeof(file_name), "%s", FILE_NAME);
	file_name[sizeof(file_name) - 1] = '\0';
	QString Qsavename;
	Qsavename.append("/FeProject/dat/").append(id).append(".xml");		//本地保存路径
	char save_name[256];
	memset(save_name, 0, 256);
	snprintf(save_name, sizeof(save_name), "%s", Qsavename.toAscii().data());
	save_name[sizeof(save_name) - 1] = '\0';
	cout << file_name << "!!!!!!!!!!!!!!!!!!!!!!!!!!" << save_name << endl;

	//mq日志
	DIY_WARNLOG_CODE("process",0,LOG_CODE_ICD_AND_DOWNLOAD,"【WARN】前置获取到终端类型%s,该终端类型对应的映射文件为%s,映射文件将下载并保存在本地为%s",TMNL_TYPE,FILE_PATH,save_name);


	// 调用web获取文件内容
    char* fileContent = NULL;

	std::string fullPath = std::string("filePath=") + std::string(FILE_PATH);

	//调试用
	std::cout << "fullpath" << fullPath << std::endl;

	SendJsonAPI_web(WEB_FILEDOWNLOAD, fullPath.c_str(), "", &fileContent);
    if (fileContent != NULL && fileContent[0] != '\0') {
        // 创建并打开文件

		//判断返回的是不是错误json响应
		bool isErrorJson = false;
        cJSON* root = cJSON_Parse(fileContent);
        if (root != NULL) {
            cJSON* codeItem = cJSON_GetObjectItem(root, "code");
            cJSON* dataItem = cJSON_GetObjectItem(root, "data");
            if (codeItem && codeItem->valuestring &&
                strcmp(codeItem->valuestring, "A00555") == 0 &&
                (dataItem == NULL || (dataItem->type == cJSON_NULL))) {
                isErrorJson = true;
                std::cerr << "Error: Server returned empty file stream, code=A00555." << std::endl;
                DIY_ERRORLOG_CODE("process",0, LOG_CODE_ICD_AND_DOWNLOAD,
                                  "【ERROR】前置下载文件失败，服务端返回A00555(文件流为空)，文件=%s",
                                  save_name);
            }
            cJSON_Delete(root);
        }

		//测试
		//std::ofstream outFile(downpath, std::ios::binary);//二进制的方式打开

        std::ofstream outFile(save_name, std::ios::out);//文本模式打开
        if (outFile.is_open()) {
            // 将文件流写入文件
            outFile.write(fileContent, strlen(fileContent));
            outFile.close();
            std::cout << "File saved successfully!" << std::endl;
			//mq日志
			DIY_INFOLOG_CODE("process",0,LOG_CODE_ICD_AND_DOWNLOAD,"【NORMAL】前置下载映射文件%s成功",save_name);
        } else {
            std::cerr << "Error: Unable to open file for writing." << std::endl;
			DIY_ERRORLOG_CODE("process",0,LOG_CODE_ICD_AND_DOWNLOAD,"【ERROR】前置写入本地映射文件%s失败",save_name);
        }

        // 释放分配的内存
        free(fileContent);
    } else {
        std::cerr << "Error: Unable to download file." << std::endl;
		DIY_ERRORLOG_CODE("process",0,LOG_CODE_ICD_AND_DOWNLOAD,"【ERROR】前置调用文件下载接口下载远端文件文件%s失败",FILE_PATH);
    }

}
//zw修改 2023-9-4 读取装置类型对应的xml文件
void Set_xml_nodeinfo()
{
	//配置无对应xml文件时的默认解析配置
	if (!inited) //初始化 JiangSu_Config.xml 
	{
		QString path;
		path.append("not define");
		ParseXMLConfig2(0, &xmlcfg, &topicList, path); //调用 ParseXMLConfig() 解析JiangSu_Config.xml配置文件
		if (isdelta_flag) {
			ParseXMLConfig2(1, &xmlcfg2, &topicList2, path);	//lnk2024-8-13角型接线
		}
		inited = true;
	}

	if (xmlinfo_list.size() != 0)
	{
		cout << "!!!!!!!!!! xmlinfo_list.size() != 0 !!!!!!!!!!!" << endl;
		for (QMap<QString, Xmldata*>::iterator it2 = xmlinfo_list.begin(); it2 != xmlinfo_list.end(); ++it2)
		{
			QString key2 = it2.key();
			Xmldata* value2 = it2.value();

			if (value2->updataflag == true) {
				ParseXMLConfig2(0,&(value2->xmlcfg), &(value2->topicList), value2->xmlbase.MODEL_ID);
			}
		}
		//lnk2024-8-14 选择角型接线
		if (isdelta_flag) {
			for (QMap<QString, Xmldata*>::iterator it3 = xmlinfo_list2.begin(); it3 != xmlinfo_list2.end(); ++it3)
			{
				QString key3 = it3.key();
				Xmldata* value3 = it3.value();	//

				if (value3->updataflag == true) {
					ParseXMLConfig2(1, &(value3->xmlcfg), &(value3->topicList), value3->xmlbase.MODEL_ID);
				}
			}
		}
	}
	else {
		cout << "!!!!!!!!!! xmlinfo_list.size() == 0 !!!!!!!!!!!" << endl;
	}

}
//zw修改 2023-9-4 获取xml路径
char* Get_xmlpath(char* devtype)
{
	QString type;
	type.append(devtype);

	//调试用lnk20241125
	std::cout << type.toStdString() << std::endl;

	if (xmlinfo_list.contains(devtype) &&
    xmlinfo_list[devtype] != NULL &&   // 先检查指针是否为空
    !xmlinfo_list[devtype]->xmlbase.MODEL_ID.isNull() &&   // 确保 QString 不是 NULL
    !xmlinfo_list[devtype]->xmlbase.MODEL_ID.isEmpty() &&  // 确保字符串不为空
    xmlinfo_list[devtype]->xmlbase.MODEL_ID.trimmed().length() >= 4) { //确保modelid存在lnk20250313
		cout << "!!!!!!!!!! xmlinfo_list.contains(devtype) == 1 !!!!!!!!!!!" << endl;
		QByteArray byteArray = xmlinfo_list[devtype]->xmlbase.MODEL_ID.toLocal8Bit();//易崩溃点,一定要确保modelid存在lnk20250313
		char* charArray = new char[byteArray.size()+1];//分配内存时+1防止内存泄漏lnk20250305
		memcpy(charArray, byteArray.data(), byteArray.size());
		charArray[byteArray.size()] = '\0';
		return charArray;
	}
	else {
		cout << "!!!!!!!!!! xmlinfo_list.contains(devtype) == 0 !!!!!!!!!!!" << endl;
		return NULL;
	}
}
//zw修改 2023-9-5 获取IED模型
char* Get_IED(char* devtype)
{
	QString type;
	type.append(devtype);
	if (xmlinfo_list.contains(type) && xmlinfo_list[type] != NULL) {
		cout << "!!!!!!!!!! Get_IED xmlinfo_list.contains(devtype) == 1 !!!!!!!!!!!" << endl;
	
		// 确保 xmlcfg 及其成员非空
		if (xmlinfo_list[type]->xmlcfg.IEDname.isNull() || xmlinfo_list[type]->xmlcfg.LDevicePrefix.isNull()) {
			cout << "Error: IEDname or LDevicePrefix is NULL in Get_IED!" << endl;
			return NULL;
		}
	
		QString ied;
		ied.append(xmlinfo_list[type]->xmlcfg.IEDname);   // 从配置文件读取的终端名PQ
		ied.append(xmlinfo_list[type]->xmlcfg.LDevicePrefix);	//// 从配置文件读取的监测点名PQM
		ied.append("%d");//最后构成PQPQM1
	
		QByteArray byteArray = ied.toLocal8Bit();
		
		if (byteArray.isEmpty()) {
			cout << "Error: Generated QByteArray is empty!" << endl;
			return NULL;
		}
	
		// 分配内存，确保足够大小并安全拷贝
		char* charArray = new char[byteArray.size() + 1];
		if (!charArray) {
			cout << "Error: Memory allocation failed!" << endl;
			return NULL;
		}
	
		memcpy(charArray, byteArray.data(), byteArray.size());
		charArray[byteArray.size()] = '\0';  // 确保字符串以 '\0' 结尾
	
		return charArray;
	} 
	else {
		cout << "!!!!!!!!!! Get_IED xmlinfo_list.contains(devtype) == 0 !!!!!!!!!!!" << endl;

		QString ied;
		ied.append(xmlcfg.IEDname);
		ied.append(xmlcfg.LDevicePrefix);
		ied.append("%d");
		QByteArray byteArray = ied.toLocal8Bit();
		char* charArray = new char[byteArray.size()+1];//分配内存时+1防止内存泄漏lnk20250305
		memcpy(charArray, byteArray.data(), byteArray.size());
		charArray[byteArray.size()] = '\0';
		return charArray;
	}
}
char* Get_LDevice(char* devtype) 
{
	QString type;
	type.append(devtype);
	if (xmlinfo_list.contains(type) && xmlinfo_list[type] != NULL) { // 确保类型存在且不为空
		if (xmlinfo_list[type]->xmlcfg.LDevicePrefix.isNull() || xmlinfo_list[type]->xmlcfg.LDevicePrefix.isEmpty()) {
			cout << "Error: LDevicePrefix is NULL or empty in Get_IED!" << endl;
			return NULL;
		}
	
		QString ied;
		ied.append(xmlinfo_list[type]->xmlcfg.LDevicePrefix); // 使用解析列表的终端前缀
		ied.append("%d");
	
		QByteArray byteArray = ied.toLocal8Bit();
	
		if (byteArray.isEmpty()) {
			cout << "Error: Generated QByteArray is empty!" << endl;
			return NULL;
		}
	
		// 分配内存，确保足够大小
		char* charArray = new char[byteArray.size() + 1];
		if (!charArray) {
			cout << "Error: Memory allocation failed!" << endl;
			return NULL;
		}
	
		memcpy(charArray, byteArray.data(), byteArray.size());
		charArray[byteArray.size()] = '\0';  // 确保字符串以 '\0' 结尾
	
		return charArray;
	}
	else {

		QString ied;
		ied.append(xmlcfg.LDevicePrefix);//使用默认解析配置的终端前缀
		ied.append("%d");
		QByteArray byteArray = ied.toLocal8Bit();
		char* charArray = new char[byteArray.size()+1];//分配内存时+1防止内存泄漏lnk20250305
		memcpy(charArray, byteArray.data(), byteArray.size());
		charArray[byteArray.size()] = '\0';
		return charArray;
	}
}



///////////////////////////////////////////////////lnk2024-10-21////////////////////////////////////////////////////////
void handleCommentResponse(const std::string& response) {
    
	// 解析 JSON 响应
    cJSON* json_data = cJSON_Parse(response.c_str());
    if (json_data == NULL) {
        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) {
        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;
        
    } else {
        std::cerr << "Error: Missing expected fields in JSON response." << std::endl;
    }

    // 释放 JSON 对象
    cJSON_Delete(json_data);
}

std::string boolToString(bool value) {
    return value ? "1" : "0";
}

//添加入参、时间和状态lnk202411-4
void connectlog_pgsql(char* id,char* datetime,int status)
{

	//创建响应接收
	char* ptr=NULL;

    // 创建 JSON 对象
    cJSON* jsonObject = cJSON_CreateObject();
	if (jsonObject == NULL) {
        std::cerr << "Failed to create JSON object." << std::endl;
        return;
    }

    // 添加字段到 JSON 对象
    cJSON* id_item = cJSON_CreateString(id);
	if (!id_item) {
    	std::cerr << "Failed to create 'id' string." << std::endl;
    	cJSON_Delete(jsonObject);
    	return;
	}
	cJSON_AddItemToObject(jsonObject, "id", id_item);

    cJSON* datetime_item = cJSON_CreateString(datetime);
	if (!datetime_item) {
    	std::cerr << "Failed to create 'Datetime' string." << std::endl;
    	cJSON_Delete(jsonObject);
    	return;
	}
	cJSON_AddItemToObject(jsonObject, "date", datetime_item);

 	char statusStr[12];  // 足够容纳一个整数（包括负号和 '\0'）   
    sprintf(statusStr, "%d", status);// 使用 sprintf 将 int 转换为字符串
	
	cJSON* status_item = cJSON_CreateString(statusStr);
	if (!status_item) {
    	std::cerr << "Failed to create 'status' string." << std::endl;
    	cJSON_Delete(jsonObject);
    	return;
	}
	cJSON_AddItemToObject(jsonObject, "status", status_item);


	char* jsonString = cJSON_Print(jsonObject);
	if (jsonString == NULL) {
        std::cerr << "Failed to print JSON object." << std::endl;
        cJSON_Delete(jsonObject);
        return;
    }

	//使用mq
	Ckafka_data_t connect_info;
	connect_info.strTopic = QString::fromStdString(G_CONNECT_TOPIC);
	connect_info.mp_id = QString::fromLocal8Bit(id);//这里填装置id，后续作为key
	connect_info.strText = QString::fromStdString(std::string(jsonString));

	if((g_node_id == STAT_DATA_BASE_NODE_ID && RECALL_ONLY_FLAG == 0) || (g_node_id == RECALL_HIS_DATA_BASE_NODE_ID && RECALL_ONLY_FLAG == 1)){//稳态或者补招才上传
		kafka_data_list_mutex.lock(); //加锁
		kafka_data_list.append(connect_info); //添加 kafka发送链表
		kafka_data_list_mutex.unlock(); //解锁
	}

    // 释放内存
    cJSON_Delete(jsonObject);
    free(jsonString); // cJSON_PrintUnformatted使用malloc分配内存
	
}

//lnk202411-5 暂态数据不再使用kafka发送，改成http接口
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////暂态事件放入文件
// 下面这部分是你要在原函数中“插入的新增功能”所需的辅助函数
// *****************************************************************************************
// 获取指定目录下所有文件的信息(文件名、修改时间、大小)，以便后续做删除或判断文件总大小
struct FileInfo {
    std::string fileName;
    time_t      modTime;  // 上次修改时间
    long long   fileSize; // 文件大小
};

// 扫描目录，获取该目录下所有普通文件的信息
static void getDirectoryFilesInfo(const std::string &dirPath, std::vector<FileInfo> &fileList)
{
    DIR* dp = opendir(dirPath.c_str());
    if (!dp) {
		std::cerr << "Failed to get info from  : " << dirPath << std::endl;
        return; // 打开失败则直接返回
    }

    struct dirent* entry = NULL;
    while ((entry = readdir(dp)) != NULL) {
        // 跳过 . 和 ..
        if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
            continue;
        }

        // 拼出完整路径
        std::string fullPath = dirPath + entry->d_name;

        // 获取文件信息
        struct stat st;
        if (stat(fullPath.c_str(), &st) == 0) {
            if (S_ISREG(st.st_mode)) {
                FileInfo fi;
                fi.fileName = fullPath;     // 包含路径
                fi.modTime  = st.st_mtime;  // 修改时间
                fi.fileSize = (long long)st.st_size; // 文件大小

                fileList.push_back(fi);
            }
        }
    }
    closedir(dp);
}

// 将 JSON 字符串写入指定文件
static bool writeJsonToFile(const char* filePath, const char* jsonString)
{
    FILE* fp = fopen(filePath, "w");
    if (!fp) {
		//DIY_ERRORLOG_CODE("process",0,LOG_CODE_TRANSIENT_COMM,"【ERROR】无法将暂态事件写入本地缓存");
        std::cerr << "Failed to write in file : " << filePath << std::endl;
        return false;
    }
    fprintf(fp, "%s", jsonString);
    fclose(fp);
    return true;
}

// 检查 qvvr 目录下文件总大小，若超过 10M 则删除最老的一个文件
// 注意：该逻辑严格按照你需求“只删一个最老的文件”来实现，而不是循环删到小于10M
static void checkAndRemoveOldestIfNeeded(const std::string &dirPath, long long maxBytes)
{
    // 1) 判断目录是否存在，不存在则尝试创建
    {
        struct stat st;
        // 调用 stat() 判断是否存在
        if (stat(dirPath.c_str(), &st) == -1) {
            if (errno == ENOENT) {
                // 目录不存在，尝试创建
                // 注意：mkdir 只会创建最后一级目录，若需要递归创建父目录，请自行扩展
                if (mkdir(dirPath.c_str(), 0777) != 0) {
                    // 若 mkdir 失败，可根据实际需求进行日志输出或错误处理
                    std::cerr << "Failed to create directory: " << dirPath << std::endl;
                    return; // 创建失败则直接返回，避免后续操作报错
                }
            } else {
                // stat() 调用出错，但并非 ENOENT，可根据需求处理
                std::cerr << "stat error: " << strerror(errno) << std::endl;
                return;
            }
        }
        else {
            // 如果能 stat 到 dirPath，需要再判断是否真的是个“目录”而非普通文件
            if (!S_ISDIR(st.st_mode)) {
                // 存在同名的非目录文件，无法作为目录使用
                std::cerr << dirPath << " exists but is not a directory." << std::endl;
                return;
            }
        }
    }

    // ==============  以下是原有的逻辑  ==============
    // 获取目录下所有文件信息
    std::vector<FileInfo> fileList;
    getDirectoryFilesInfo(dirPath, fileList);

    // 计算总大小
    long long totalSize = 0;
    for (size_t i = 0; i < fileList.size(); ++i) {
        totalSize += fileList[i].fileSize;
    }

    // 如果超过阈值，则删除最老的那个
    if (totalSize > maxBytes && !fileList.empty()) {
        // 按修改时间升序排序，最老(修改时间最早)的排在最前面
        std::sort(fileList.begin(), fileList.end(), 
            // C++98 的比较写法
            static_cast<bool(*)(const FileInfo&, const FileInfo&)>(
                // 不能使用lambda，用函数指针
                // 比较函数
                (bool (*)(const FileInfo&, const FileInfo&))[] (const FileInfo &a, const FileInfo &b) {
                    return a.modTime < b.modTime; 
                }
            )
        );

        // 删掉第一个(最老的文件)
        remove(fileList[0].fileName.c_str());
    }
}

// 扫描目录下的离线文件，依次读取并发送；若发送成功则删除该文件，发送不成功则保留
static void scanAndResendOfflineFiles(const std::string &dirPath)
{
    // 获取目录下所有文件信息
    std::vector<FileInfo> fileList;

	std::cout << "getDirectoryFilesInfo" << std::endl;
    getDirectoryFilesInfo(dirPath, fileList);

	std::cout << "send every file" << std::endl;
    // 逐个文件尝试重发
    for (size_t i = 0; i < fileList.size(); ++i) {
        // 读取文件内容(即之前存的 JSON)
        FILE* fp = fopen(fileList[i].fileName.c_str(), "r");
        if (!fp) {
			DIY_ERRORLOG_CODE("process",0,LOG_CODE_TRANSIENT_COMM,"【ERROR】无法打开本地缓存的暂态事件");
            std::cerr << " fail to open exsist file " << fileList[i].fileName << std::endl;
            continue;
        }
        
        // 读取到内存
        std::string jsonContent;
        char buf[1024];
        while (!feof(fp)) {
            if (fgets(buf, sizeof(buf), fp)) {
                jsonContent += buf;
            }
        }
        fclose(fp);

		std::cout << "send jsonContent" << jsonContent << std::endl;

        // 尝试发送
        char* ptr = NULL; // 接收返回
        SendJsonAPI_web(WEB_EVENT, "", jsonContent.c_str(), &ptr); 
        if (ptr != NULL && ptr[0] != '\0') {

			cJSON* j_r = cJSON_Parse(ptr);
    		if (j_r == NULL) {
				std::cout << "old file send fail" << std::endl;
            	

				DIY_WARNLOG_CODE("process",0,LOG_CODE_TRANSIENT_COMM,"【WARN】前置重发暂态事件失败");

			}
			else{
				// 表示有响应，则可视为成功；根据项目需要可加更精细的判断
            	handleCommentResponse(std::string(ptr));

				DIY_WARNLOG_CODE("process",0,LOG_CODE_TRANSIENT_COMM,"【WARN】前置重发暂态事件成功");
				
				std::cout << "old file send success,remove it" << std::endl;
				// 删除文件
				remove(fileList[i].fileName.c_str());

				cJSON_Delete(j_r);
			}           
			
        } 
        else {
            // 发送失败，保留文件，以便下次重试
			std::cout << "old file send fail" << std::endl;
        }
		free(ptr);
    }
}
// *****************************************************************************************

std::string FormatTimeForFilename(const std::string& timeStr) {
    std::string result;
    for (char c : timeStr) {
        if (isdigit(c)) {
            result += c;
        }
    }
    return result;
}
// ========================  原先的函数  ========================
int transfer_json_qvvr_data(unsigned int func_type, int monitor_id, 
double mag, double dur, long long start_tm, long long end_tm, int dis_kind, 
char* uuid_cfg,char* uuid_dat,
char* mp_id,char* Qvvr_rptname,char* devtype)
{	

    // 原本的逻辑，不做任何改动
    // ---------------------------------------------------------------
    XmlConfig c_xmlcfg;
    if (xmlinfo_list.contains(devtype)) {
        c_xmlcfg = xmlinfo_list[devtype]->xmlcfg;//查找映射
    }
    else {
        c_xmlcfg = xmlcfg;
    }

    if (NULL == mp_id || strlen(mp_id) == 0 ) {
        std::cout << "mp_id is null" << std::endl;
        return 0;
    }

    cJSON* root = cJSON_CreateObject();
    cJSON_AddStringToObject(root, "monitorId", mp_id);
    cJSON_AddNumberToObject(root, "amplitude", mag);
    cJSON_AddNumberToObject(root, "duration", dur);
    cJSON_AddNumberToObject(root, "eventType", dis_kind);

    char start_time_str[25];
    time_t start_sec = start_tm / 1000;
    struct tm* time_info = localtime(&start_sec);
    strftime(start_time_str, sizeof(start_time_str), "%Y-%m-%d %H:%M:%S", time_info);
    snprintf(start_time_str + strlen(start_time_str), sizeof(start_time_str) - strlen(start_time_str), ".%03lld", start_tm % 1000);
    cJSON_AddStringToObject(root, "startTime", start_time_str);

    // cJSON_AddStringToObject(root, "wavePathcfg", uuid_cfg);
    // cJSON_AddStringToObject(root, "wavePathdat", uuid_dat);
    cJSON_AddStringToObject(root, "wavePath", uuid_dat);

    if (c_xmlcfg.WavePhasicFlag == "1") {
        QString Qvvr_Rptname;
        Qvvr_Rptname.append(Qvvr_rptname);
        if (Qvvr_Rptname.indexOf(c_xmlcfg.WavePhasicA) != -1) {
            cJSON_AddStringToObject(root, "phase", "A");
        }
        else if (Qvvr_Rptname.indexOf(c_xmlcfg.WavePhasicB) != -1) {
            cJSON_AddStringToObject(root, "phase", "B");
        }
        else if (Qvvr_Rptname.indexOf(c_xmlcfg.WavePhasicC) != -1) {
            cJSON_AddStringToObject(root, "phase", "C");
        }
        else {
            cJSON_AddStringToObject(root, "phase", "unknow");
        }
    }
    else {
        cJSON_AddStringToObject(root, "phase", "unknow");
    }

    char* json_string = cJSON_Print(root);
	if (json_string == NULL) {
		DIY_ERRORLOG_CODE(mp_id,2,LOG_CODE_TRANSIENT_COMM,"【ERROR】监测点：%s暂态事件生成JSON字符串失败",mp_id);
		std::cerr << "Failed to print JSON object." << std::endl;
	    cJSON_Delete(root);
	    return 0;
	}
    printf("%s\n", json_string);  // 输出 JSON 字符串

    // 发送到暂态接口
    char* ptr = NULL;
    SendJsonAPI_web(WEB_EVENT, "", json_string, &ptr);

    // ================  插入新功能  =========================
    // ********** 新增功能开始 **********
	if(ptr != NULL && ptr[0] != '\0')
    {
		cJSON* j_r = cJSON_Parse(ptr);
        // 如果发送失败(j_r == NULL)，则把当前 json 存入指定目录(/FeProject/dat/qvvr/)
        if (j_r == NULL) {

			//mq日志
			DIY_ERRORLOG_CODE(mp_id,2,LOG_CODE_TRANSIENT_COMM,"【ERROR】暂态接口响应异常,无法上送监测点%s的暂态事件",mp_id);

			std::cout << "qvvr send fail ,store in local" << std::endl;
            // 1) 先检查/FeProject/dat/qvvr/目录文件大小是否超过 10M，若超过则删除最老的一个文件
            std::string qvvrDir = "/FeProject/dat/qvvr/";
            

            // 2) 将此条 json 存为文件，文件名: mp_id-start_time_str-dis_kind.txt
            //    例如：  502-2025-04-02 15:25:30.123-3.txt (仅示例)
            std::string fileName = qvvrDir;
            fileName += mp_id;
            fileName += "-";
            fileName += FormatTimeForFilename(start_time_str);
            fileName += "-";
            
            char buf[64];
            sprintf(buf, "%d", dis_kind);
            fileName += buf;
            fileName += ".txt";

            // 把 json_string 写入文件
            if(!writeJsonToFile(fileName.c_str(), json_string)){
				DIY_ERRORLOG_CODE(mp_id,2,LOG_CODE_TRANSIENT_COMM,"【ERROR】监测点：%s无法将暂态时间为%lld的暂态事件写入本地缓存",mp_id,start_tm);
			}

			checkAndRemoveOldestIfNeeded(qvvrDir, 10LL * 1024 * 1024);
        }
		else{
			cJSON_Delete(j_r);
			//后续处理
		}	
    }
	// 无论此次发送成功或失败，都要扫描/FeProject/dat/qvvr/目录下的文件并尝试依次重发
	if(1)
	{
		std::string qvvrDir = "/FeProject/dat/qvvr/";
		scanAndResendOfflineFiles(qvvrDir);
	}
    // ********** 新增功能结束 **********

    // 下面继续原逻辑，不动，处理本次发送
    if (ptr != NULL && ptr[0] != '\0') {
		std::cout << "current qvvr handle response" << std::endl;
        handleCommentResponse(std::string(ptr));
        free(ptr);
		ptr = NULL;
    } else {
        // 处理 ptr 为 NULL 的情况，例如日志记录或错误处理
        std::cout << "Error: Received NULL response" << std::endl;

		//mq日志
		DIY_ERRORLOG_CODE(mp_id,2,LOG_CODE_TRANSIENT_COMM,"【ERROR】暂态接口无响应,无法上送监测点%s的暂态事件",mp_id);

		std::cout << "qvvr send fail ,store in local" << std::endl;
        // 1) 先检查/FeProject/dat/qvvr/目录文件大小是否超过 10M，若超过则删除最老的一个文件
        std::string qvvrDir = "/FeProject/dat/qvvr/";
        
        // 2) 将此条 json 存为文件，文件名: mp_id-start_time_str-dis_kind.txt
        //    例如：  502-2025-04-02 15:25:30.123-3.txt (仅示例)
        std::string fileName = qvvrDir;
        fileName += mp_id;
        fileName += "-";
        fileName += FormatTimeForFilename(start_time_str);
        fileName += "-";
        
        char buf[64];
        sprintf(buf, "%d", dis_kind);
        fileName += buf;
        fileName += ".txt";
        // 把 json_string 写入文件
        if(!writeJsonToFile(fileName.c_str(), json_string)){
			DIY_ERRORLOG_CODE(mp_id,2,LOG_CODE_TRANSIENT_COMM,"【ERROR】监测点：%s无法将暂态时间为%lld的暂态事件写入本地缓存",mp_id,start_tm);
		}

		checkAndRemoveOldestIfNeeded(qvvrDir, 10LL * 1024 * 1024);

		// 释放内存
		cJSON_Delete(root);
		free(json_string);
        return 0;
    }

    // 释放内存
    cJSON_Delete(root);
    free(json_string);
    return 1;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////暂态事件放入文件

void qvvr_test()
{
	char uuid_cfg[] = {"/comtrade/"};
	char uuid_dat[] = {"/comtrade/"};
	char mp_id[] = {"000cf2a27f3f13f330b9e8690641e7f2"};
	char Qvvr_rptname[] = {"unknow"};
	char devtype[] = {"01"};

	transfer_json_qvvr_data(1, 123456789, 220, 180, 1730894400.123, 1730894580, 1210001,uuid_cfg,uuid_dat,mp_id,Qvvr_rptname,devtype);
}

void comflag_test()
{
	char id[] = {"000cf2a27f3f13f330b9e8690641e7f2"};
	char datetime[] = {"2024-11-6 15:15:15"};
	connectlog_pgsql(id,datetime,1);
}

///////////////////////////////////////////////////lnk2024-10-21////////////////////////////////////////////////////////
void clearXmlConfigAndTopicList(Xmldata* data) {
    // 清空 XmlConfig
    data->xmlcfg = XmlConfig();  // 通过重新赋值重置 xmlcfg

    // 清空 topicList
    list<CTopic*>::iterator it;
    for (it = data->topicList.begin(); it != data->topicList.end(); ++it) {
        delete *it;  // 释放内存
    }
    data->topicList.clear();  // 清空链表
}
//4-配置映射文件//////////////////////////////
void Set_xml_nodeinfo_one(char* dev_type)
{
	bool ret = false;

	if(xmlinfo_list[QString::fromUtf8(dev_type)] != NULL){	//原来已存在这个类型的节点
		//if(xmlinfo_list[QString::fromUtf8(dev_type)]->updataflag == true){	//需要更新

			//将这个点的xmlcfg和topicList删除
			clearXmlConfigAndTopicList(xmlinfo_list[QString::fromUtf8(dev_type)]);

			ret = ParseXMLConfig2(0,&(xmlinfo_list[QString::fromUtf8(dev_type)]->xmlcfg), &(xmlinfo_list[QString::fromUtf8(dev_type)]->topicList), xmlinfo_list[QString::fromUtf8(dev_type)]->xmlbase.MODEL_ID);
			if(!ret)
			{
				std::cout << "!!!! this ledger xml config fail!!!!" << std::endl;
			}
		//}
		
	}
	else{
		std::cout << "xmlinfo_list not contain this devtype" << std::endl;
	}
	//添加角形
	if(isdelta_flag){
		if(xmlinfo_list2[QString::fromUtf8(dev_type)] != NULL){	//原来已存在这个类型的节点
			//if(xmlinfo_list2[QString::fromUtf8(dev_type)]->updataflag == true){	//需要更新
	
				//将这个点的xmlcfg和topicList删除
				clearXmlConfigAndTopicList(xmlinfo_list2[QString::fromUtf8(dev_type)]);
	
				ret = ParseXMLConfig2(1,&(xmlinfo_list2[QString::fromUtf8(dev_type)]->xmlcfg), &(xmlinfo_list2[QString::fromUtf8(dev_type)]->topicList), xmlinfo_list2[QString::fromUtf8(dev_type)]->xmlbase.MODEL_ID);
				if(!ret)
				{
					std::cout << "!!!! this ledger xml config fail!!!!" << std::endl;
				}
			//}
			
		}
		else{
			std::cout << "xmlinfo_list2 not contain this devtype" << std::endl;
		}
	}
		
}
