添加文件路径接口函数和文件下载接口函数

This commit is contained in:
lnk
2025-07-31 13:38:55 +08:00
parent 8e4e45ce31
commit 78938827f7
2 changed files with 209 additions and 4 deletions

View File

@@ -2649,6 +2649,60 @@ void Set_xml_nodeinfo()
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////录播波形匹配
// 工具函数:解析 "dd/MM/yyyy,hh:mm:ss.zzz" 格式的字符串为时间戳(毫秒)
static long long parse_datetime_to_epoch_ms(const std::string& dt_str) {
std::tm tm = {};
char dummy;
int ms = 0;
std::istringstream ss(dt_str);
ss >> std::get_time(&tm, "%d/%m/%Y,%H:%M:%S") >> dummy >> ms;
if (ss.fail()) return 0;
std::time_t time_sec = std::mktime(&tm);
if (time_sec < 0) return 0;
return static_cast<long long>(time_sec) * 1000 + ms;
}
// 主函数:从 .cfg 文件中提取起始和触发时间戳(毫秒)
bool extract_timestamp_from_cfg_file(const std::string& cfg_path, long long& start_tm, long long& trig_tm) {
struct stat st;
if (stat(cfg_path.c_str(), &st) != 0) {
std::cerr << "File not found: " << cfg_path << "\n";
return false;
}
std::ifstream infile(cfg_path);
if (!infile) {
std::cerr << "Cannot open file: " << cfg_path << "\n";
return false;
}
std::string line, prev_line, current_line;
while (std::getline(infile, line)) {
// 去除前后空白
line.erase(line.find_last_not_of(" \t\r\n") + 1);
line.erase(0, line.find_first_not_of(" \t\r\n"));
std::string upper = line;
std::transform(upper.begin(), upper.end(), upper.begin(), ::toupper);
if (upper == "ASCII" || upper == "BINARY") break;
prev_line = current_line;
current_line = line;
}
if (prev_line.length() > 3) prev_line = prev_line.substr(0, prev_line.length() - 3);
if (current_line.length() > 3) current_line = current_line.substr(0, current_line.length() - 3);
start_tm = parse_datetime_to_epoch_ms(prev_line);
trig_tm = parse_datetime_to_epoch_ms(current_line);
return start_tm > 0 && trig_tm > 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////数据转换函数
// DataArrayItem to_json
@@ -2761,3 +2815,116 @@ std::vector<DeviceInfo> GenerateDeviceInfoFromLedger(const std::vector<terminal_
return devices;
}
////////////////////////////////////////////////////////////////////////////////////////////////////录波文件通知
bool assign_qvvr_file_list(const std::string& id, ushort nCpuNo, const std::vector<std::string>& file_list_raw) {
std::vector<std::string> file_names;
// 1. 提取文件名部分
for (const auto& full_path : file_list_raw) {
size_t pos = full_path.find_last_of("/\\");
if (pos != std::string::npos && pos + 1 < full_path.size()) {
file_names.push_back(full_path.substr(pos + 1));
} else {
file_names.push_back(full_path);
}
}
// 2. 遍历终端
for (auto& dev : terminal_devlist) {
if (dev.terminal_id == id) {
for (auto& monitor : dev.line) {
try {
ushort monitor_seq = static_cast<ushort>(std::stoi(monitor.logical_device_seq));
if (monitor_seq == nCpuNo) {
// 构造 qvvr_file
qvvr_file qfile;
qfile.file_name.assign(file_names.begin(), file_names.end());
qfile.is_download = false;
qfile.is_pair = false;
qfile.file_time_count = 0; // 可后续补充
qfile.file_start =false;
// 添加到唯一的 qvvrevent
monitor.qvvrevent.qvvrfile.push_back(std::move(qfile));
return true;
}
} catch (...) {
continue;
}
}
}
}
return false;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////下载成功通知
bool update_qvvr_file_download(const std::string& filename_with_mac, const std::string& terminal_id) {
// 去除 mac 路径前缀
size_t pos = filename_with_mac.find_last_of("/\\");
std::string filename = (pos != std::string::npos) ? filename_with_mac.substr(pos + 1) : filename_with_mac;
// 提取逻辑序号(如 PQM1 → 1
size_t under_pos = filename.find('_');
if (under_pos == std::string::npos) return false;
std::string type_part = filename.substr(0, under_pos); // e.g. PQMonitor_PQM1
size_t num_start = type_part.find_last_not_of("0123456789");
if (num_start == std::string::npos || num_start + 1 >= type_part.size()) return false;
std::string seq_str = type_part.substr(num_start + 1);
ushort logical_seq = static_cast<ushort>(std::stoi(seq_str));
for (auto& dev : terminal_devlist) {
if (dev.terminal_id != terminal_id) continue;
for (auto& monitor : dev.line) {
try {
ushort monitor_seq = static_cast<ushort>(std::stoi(monitor.logical_device_seq));
if (monitor_seq != logical_seq) continue;
} catch (...) {
continue;
}
// 匹配监测点下 qvvrfile 中的 file_name
for (auto& qfile : monitor.qvvrevent.qvvrfile) {
auto it = std::find(qfile.file_name.begin(), qfile.file_name.end(), filename);
if (it != qfile.file_name.end()) {
// 添加到 file_download去重
if (std::find(qfile.file_download.begin(), qfile.file_download.end(), filename) == qfile.file_download.end()) {
qfile.file_download.push_back(filename);
}
qfile.file_time_count = 0;
qfile.file_start = true;
// 检查 file_download 是否与 file_name 完全一致(集合相同)
std::set<std::string> s_name(qfile.file_name.begin(), qfile.file_name.end());
std::set<std::string> s_down(qfile.file_download.begin(), qfile.file_download.end());
if (s_name == s_down) {
qfile.is_download = true;
// 找到其中的 .cfg 文件进行匹配
for (const auto& f : qfile.file_download) {
if (f.size() >= 4 && f.substr(f.size() - 4) == ".cfg") {
if (compare_qvvr_and_file(f)) {//提取文件时标和监测点事件的时标匹配
qfile.is_pair = true;
//发送所有文件
//发送暂态事件
}
break; // 只处理第一个 cfg 文件
}
}
}
return true;
}
}
}
}
return false;
}

View File

@@ -49,6 +49,33 @@ public:
std::string VOLTAGE; //补招暂态事件标识 0-不补招1-补招
};
//录波文件和暂态事件
class qvvr_data
{
int used_status; //是否占用
int QVVR_type; //暂态类型
uint64_t QVVR_time; //暂态开始时间 unsigned longlong
double QVVR_PerTime; //暂态持续时间
double QVVR_Amg; //暂态幅值
int phase; //相别(仅瞬态上送)0-A 1-B 2-C 3-AB 4-BC 5-CA 其他-ABC/异常
};
class qvvr_file
{
bool file_start;
int file_time_count; //组内文件下载时间计数第一个文件下载后十分钟内如果其他文件没下载全或者下载全了没匹配事件则将已下载的文件都移到备份区comtrade_bak
bool is_download; //文件是否下载完全,最后一个文件下载成功后对比成功则更新这个标志
bool is_pair; //文件是否和事件匹配从comtrade/mac/路径下取file_download中的cfg文件提取时间和持续时间来匹配匹配后接口发送这组file_download全部文件发送成功后删除这组文件然后更新事件中的文件列表
std::list<std::string> file_name; //文件列表(文件列表上送后就记录)
std::list<std::string> file_download; //文件已下载列表(每次列表上送会有多个文件多个文件都下载完全则开始匹配每次更新都去重并对比file_name
};
class qvvr_event
{
std::vector<qvvr_data> qvvrdata; //暂态事件列表
std::vector<qvvr_file> qvvrfile; //暂态文件组列表
};
//监测点台账
class ledger_monitor
{
@@ -66,6 +93,8 @@ public:
double PT2; // 电压变比2
double CT1; // 电流变比1
double CT2; // 电流变比2
qvvr_event qvvrevent; //暂态事件
};
//终端台账
@@ -84,13 +113,13 @@ public:
std::string dev_type;
std::string dev_key;
std::string dev_series;
std::string addr_str;
std::string port;
std::string addr_str; //装置ip
std::string port; //装置端口
std::string timestamp;
std::string processNo;
std::string maxProcessNum;
std::string mac; // 装置MAC地址
std::string mac; // 装置MAC地址接口中从addr_str获取因为ip和mac放同一位置
std::vector<ledger_monitor> line;
};
@@ -425,6 +454,15 @@ std::string generate_json( //构造装置主动上送数据的报文
const std::vector<DataArrayItem>& dataArray //数据数组。
);
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,
const std::string& uuid_cfg, const std::string& uuid_dat,
const std::string& mp_id, const std::string& Qvvr_rptname, const std::string& devtype);
//录波文件目录接口
//录波文件下载完成通知接口
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#endif