添加注释

This commit is contained in:
lnk
2026-07-14 17:02:23 +08:00
parent 6bfaa32db4
commit c5d296f7a5
23 changed files with 5513 additions and 1324 deletions

View File

@@ -32,12 +32,27 @@
* 2. 组成 DO keylnClass + inst + "$MX$" + DOI/@name
* 3. 工作簿未匹配页的“原始路径”如果等于该 key或以 key + "$" 开头,
* 就认为该原始 MMS 路径属于这个 DOI把 DOI/@desc 写入目标列。
*
* 阅读本文件时可留意的 C++/库语法:
* - namespace fs = std::filesystem 是命名空间别名,后文 fs::path 即文件系统路径类型;
* - namespace { ... } 是匿名命名空间,使辅助函数只在当前编译单元内可见;
* - tinyxml2::XMLDocument 拥有解析后的节点XMLNode/XMLElement 指针不能脱离文档存活;
* - std::unordered_map 用散列表保存 ICD key -> desc适合大量精确查询
* - std::sort/std::transform 中的 [](...) { ... } 是短生命周期 lambda匿名函数
* - MultiByteToWideChar/WideCharToMultiByte 负责 Windows 本地代码页与 UTF-8 转换。
*/
namespace fs = std::filesystem;
namespace {
/**
* Function: readAllBinary
*
* @brief 读取或加载 “readAllBinary” 对应的数据,并转换为本模块后续逻辑使用的内存结构。
* @details 本文件使用 tinyxml2 遍历 ICD/Excel XML并使用 Windows 代码页 API 兼容 GBK/GB2312文件操作采用 std::filesystem 与二进制流,失败时抛出异常交给公共入口处理。
* @param path 文件或目录路径;函数按 UTF-8/Windows 路径规则读取或写入。
* @return 构造、解析或查找到的结果;所有权与生命周期遵循返回类型。
*/
std::string readAllBinary(const fs::path& path) {
std::ifstream ifs(path, std::ios::binary);
if (!ifs) throw std::runtime_error("Failed to open file: " + path.string());
@@ -45,26 +60,54 @@ std::string readAllBinary(const fs::path& path) {
ss << ifs.rdbuf();
return ss.str();
}
/**
* Function: writeAllBinary
*
* @brief 把 “writeAllBinary” 对应的内存数据序列化并写入目标位置。
* @details 本文件使用 tinyxml2 遍历 ICD/Excel XML并使用 Windows 代码页 API 兼容 GBK/GB2312文件操作采用 std::filesystem 与二进制流,失败时抛出异常交给公共入口处理。
* @param path 文件或目录路径;函数按 UTF-8/Windows 路径规则读取或写入。
* @param text 待解析、比较、显示或发送的 UTF-8 文本。
*/
void writeAllBinary(const fs::path& path, const std::string& text) {
std::ofstream ofs(path, std::ios::binary);
if (!ofs) throw std::runtime_error("Failed to write file: " + path.string());
ofs << text;
}
/**
* Function: lowerAscii
*
* @brief 规范化 “lowerAscii” 对应的字符串或标识,减少格式差异对匹配造成的影响。
* @details 本文件使用 tinyxml2 遍历 ICD/Excel XML并使用 Windows 代码页 API 兼容 GBK/GB2312文件操作采用 std::filesystem 与二进制流,失败时抛出异常交给公共入口处理。
* @param s 调用方传入的业务参数;其用途与约束由类型、名称及函数体共同定义。
* @return 构造、解析或查找到的结果;所有权与生命周期遵循返回类型。
*/
std::string lowerAscii(std::string s) {
std::transform(s.begin(), s.end(), s.begin(),
[](unsigned char c) { return static_cast<char>(std::tolower(c)); });
return s;
}
/**
* Function: declaresGbEncoding
*
* @brief 判断 “declaresGbEncoding” 所表达的条件;该函数只读取输入,不负责修改业务状态。
* @details 本文件使用 tinyxml2 遍历 ICD/Excel XML并使用 Windows 代码页 API 兼容 GBK/GB2312文件操作采用 std::filesystem 与二进制流,失败时抛出异常交给公共入口处理。
* @param text 待解析、比较、显示或发送的 UTF-8 文本。
* @return 条件成立或操作成功时为 true否则为 false。
*/
bool declaresGbEncoding(const std::string& text) {
std::string head = lowerAscii(text.substr(0, std::min<size_t>(text.size(), 256)));
return head.find("gb2312") != std::string::npos ||
head.find("gbk") != std::string::npos ||
head.find("gb18030") != std::string::npos;
}
/**
* Function: isLikelyUtf8
*
* @brief 判断 “isLikelyUtf8” 所表达的条件;该函数只读取输入,不负责修改业务状态。
* @details 本文件使用 tinyxml2 遍历 ICD/Excel XML并使用 Windows 代码页 API 兼容 GBK/GB2312文件操作采用 std::filesystem 与二进制流,失败时抛出异常交给公共入口处理。
* @param text 待解析、比较、显示或发送的 UTF-8 文本。
* @return 条件成立或操作成功时为 true否则为 false。
*/
bool isLikelyUtf8(const std::string& text) {
// 只做 UTF-8 字节合法性判断,不判断语义;合法就优先按 UTF-8 给 tinyxml2。
int remaining = 0;
@@ -82,7 +125,14 @@ bool isLikelyUtf8(const std::string& text) {
}
return remaining == 0;
}
/**
* Function: ansiToUtf8
*
* @brief 实现 “ansiToUtf8” 对应的模块内功能。
* @details 本文件使用 tinyxml2 遍历 ICD/Excel XML并使用 Windows 代码页 API 兼容 GBK/GB2312文件操作采用 std::filesystem 与二进制流,失败时抛出异常交给公共入口处理。
* @param text 待解析、比较、显示或发送的 UTF-8 文本。
* @return 构造、解析或查找到的结果;所有权与生命周期遵循返回类型。
*/
std::string ansiToUtf8(const std::string& text) {
// 936 是 Windows 简体中文代码页,兼容常见 GBK/GB2312 ICD 文件。
if (text.empty()) return "";
@@ -95,26 +145,55 @@ std::string ansiToUtf8(const std::string& text) {
WideCharToMultiByte(CP_UTF8, 0, wide.data(), wideLen, out.data(), utf8Len, nullptr, nullptr);
return out;
}
/**
* Function: loadXmlText
*
* @brief 读取或加载 “loadXmlText” 对应的数据,并转换为本模块后续逻辑使用的内存结构。
* @details 本文件使用 tinyxml2 遍历 ICD/Excel XML并使用 Windows 代码页 API 兼容 GBK/GB2312文件操作采用 std::filesystem 与二进制流,失败时抛出异常交给公共入口处理。
* @param path 文件或目录路径;函数按 UTF-8/Windows 路径规则读取或写入。
* @return 构造、解析或查找到的结果;所有权与生命周期遵循返回类型。
*/
std::string loadXmlText(const fs::path& path) {
std::string raw = readAllBinary(path);
// ICD 声明 GB 编码或字节本身不像 UTF-8 时,先转成 UTF-8 再交给 tinyxml2。
if (declaresGbEncoding(raw) || !isLikelyUtf8(raw)) return ansiToUtf8(raw);
return raw;
}
/**
* Function: localName
*
* @brief 实现 “localName” 对应的模块内功能。
* @details 本文件使用 tinyxml2 遍历 ICD/Excel XML并使用 Windows 代码页 API 兼容 GBK/GB2312文件操作采用 std::filesystem 与二进制流,失败时抛出异常交给公共入口处理。
* @param name 待解析、比较、显示或发送的 UTF-8 文本。
* @return 构造、解析或查找到的结果;所有权与生命周期遵循返回类型。
*/
std::string localName(const char* name) {
if (!name) return "";
std::string s(name);
size_t pos = s.find(':');
return pos == std::string::npos ? s : s.substr(pos + 1);
}
/**
* Function: attr
*
* @brief 实现 “attr” 对应的模块内功能。
* @details 本文件使用 tinyxml2 遍历 ICD/Excel XML并使用 Windows 代码页 API 兼容 GBK/GB2312文件操作采用 std::filesystem 与二进制流,失败时抛出异常交给公共入口处理。
* @param e 调用方传入的业务参数;其用途与约束由类型、名称及函数体共同定义。
* @param name 待解析、比较、显示或发送的 UTF-8 文本。
* @return 构造、解析或查找到的结果;所有权与生命周期遵循返回类型。
*/
std::string attr(const tinyxml2::XMLElement* e, const char* name) {
const char* v = e ? e->Attribute(name) : nullptr;
return v ? v : "";
}
/**
* Function: collectIcdDescriptions
*
* @brief 遍历输入结构并收集 “collectIcdDescriptions” 所需的候选数据。
* @details 本文件使用 tinyxml2 遍历 ICD/Excel XML并使用 Windows 代码页 API 兼容 GBK/GB2312文件操作采用 std::filesystem 与二进制流,失败时抛出异常交给公共入口处理。
* @param element 当前处理的数据行、单元格、XML 节点或模型项。
* @param descByDo 调用方传入的业务参数;其用途与约束由类型、名称及函数体共同定义。
*/
void collectIcdDescriptions(const tinyxml2::XMLElement* element,
std::unordered_map<std::string, std::string>& descByDo) {
if (!element) return;
@@ -141,7 +220,14 @@ void collectIcdDescriptions(const tinyxml2::XMLElement* element,
collectIcdDescriptions(child, descByDo);
}
}
/**
* Function: parseIcdDescriptions
*
* @brief 解析 “parseIcdDescriptions” 对应的文本或结构,提取经过校验的业务字段。
* @details 本文件使用 tinyxml2 遍历 ICD/Excel XML并使用 Windows 代码页 API 兼容 GBK/GB2312文件操作采用 std::filesystem 与二进制流,失败时抛出异常交给公共入口处理。
* @param icdPath 文件或目录路径;函数按 UTF-8/Windows 路径规则读取或写入。
* @return 构造、解析或查找到的结果;所有权与生命周期遵循返回类型。
*/
std::unordered_map<std::string, std::string> parseIcdDescriptions(const fs::path& icdPath) {
tinyxml2::XMLDocument doc;
std::string xml = loadXmlText(icdPath);
@@ -153,18 +239,41 @@ std::unordered_map<std::string, std::string> parseIcdDescriptions(const fs::path
collectIcdDescriptions(doc.RootElement(), descByDo);
return descByDo;
}
/**
* Function: cellText
*
* @brief 实现 “cellText” 对应的模块内功能。
* @details 本文件使用 tinyxml2 遍历 ICD/Excel XML并使用 Windows 代码页 API 兼容 GBK/GB2312文件操作采用 std::filesystem 与二进制流,失败时抛出异常交给公共入口处理。
* @param cell 当前处理的数据行、单元格、XML 节点或模型项。
* @return 构造、解析或查找到的结果;所有权与生命周期遵循返回类型。
*/
std::string cellText(const tinyxml2::XMLElement* cell) {
const tinyxml2::XMLElement* data = cell ? cell->FirstChildElement("Data") : nullptr;
const char* text = data ? data->GetText() : nullptr;
return text ? text : "";
}
/**
* Function: cellIndex
*
* @brief 实现 “cellIndex” 对应的模块内功能。
* @details 本文件使用 tinyxml2 遍历 ICD/Excel XML并使用 Windows 代码页 API 兼容 GBK/GB2312文件操作采用 std::filesystem 与二进制流,失败时抛出异常交给公共入口处理。
* @param cell 当前处理的数据行、单元格、XML 节点或模型项。
* @param fallback 调用方传入的业务参数;其用途与约束由类型、名称及函数体共同定义。
* @return 整数状态、索引或计数;入口函数以 0 表示成功。
*/
int cellIndex(const tinyxml2::XMLElement* cell, int fallback) {
const char* idx = cell ? cell->Attribute("ss:Index") : nullptr;
return idx && *idx ? std::max(1, std::atoi(idx)) : fallback;
}
/**
* Function: cellAt
*
* @brief 实现 “cellAt” 对应的模块内功能。
* @details 本文件使用 tinyxml2 遍历 ICD/Excel XML并使用 Windows 代码页 API 兼容 GBK/GB2312文件操作采用 std::filesystem 与二进制流,失败时抛出异常交给公共入口处理。
* @param row 当前处理的数据行、单元格、XML 节点或模型项。
* @param col 索引、数量、范围或偏移参数;具体边界由函数体校验。
* @return 构造、解析或查找到的结果;所有权与生命周期遵循返回类型。
*/
tinyxml2::XMLElement* cellAt(tinyxml2::XMLElement* row, int col) {
int current = 1;
for (tinyxml2::XMLElement* cell = row ? row->FirstChildElement("Cell") : nullptr;
@@ -176,7 +285,16 @@ tinyxml2::XMLElement* cellAt(tinyxml2::XMLElement* row, int col) {
}
return nullptr;
}
/**
* Function: ensureCell
*
* @brief 向目标结构追加或保证存在 “ensureCell” 所描述的数据。
* @details 本文件使用 tinyxml2 遍历 ICD/Excel XML并使用 Windows 代码页 API 兼容 GBK/GB2312文件操作采用 std::filesystem 与二进制流,失败时抛出异常交给公共入口处理。
* @param doc tinyxml2 文档对象;节点的生命周期由该文档管理。
* @param row 当前处理的数据行、单元格、XML 节点或模型项。
* @param col 索引、数量、范围或偏移参数;具体边界由函数体校验。
* @return 构造、解析或查找到的结果;所有权与生命周期遵循返回类型。
*/
tinyxml2::XMLElement* ensureCell(tinyxml2::XMLDocument& doc, tinyxml2::XMLElement* row, int col) {
if (tinyxml2::XMLElement* existing = cellAt(row, col)) return existing;
// Excel XML 允许通过 ss:Index 跳列;补列时直接设置 ss:Index避免改动前面已有单元格。
@@ -185,7 +303,15 @@ tinyxml2::XMLElement* ensureCell(tinyxml2::XMLDocument& doc, tinyxml2::XMLElemen
row->InsertEndChild(cell);
return cell;
}
/**
* Function: setCellText
*
* @brief 把 “setCellText” 对应的变更应用到模型、控件或输出文档。
* @details 本文件使用 tinyxml2 遍历 ICD/Excel XML并使用 Windows 代码页 API 兼容 GBK/GB2312文件操作采用 std::filesystem 与二进制流,失败时抛出异常交给公共入口处理。
* @param doc tinyxml2 文档对象;节点的生命周期由该文档管理。
* @param cell 当前处理的数据行、单元格、XML 节点或模型项。
* @param text 待解析、比较、显示或发送的 UTF-8 文本。
*/
void setCellText(tinyxml2::XMLDocument& doc, tinyxml2::XMLElement* cell, const std::string& text) {
tinyxml2::XMLElement* data = cell->FirstChildElement("Data");
if (!data) {
@@ -195,7 +321,14 @@ void setCellText(tinyxml2::XMLDocument& doc, tinyxml2::XMLElement* cell, const s
}
data->SetText(text.c_str());
}
/**
* Function: sortedKeysByLength
*
* @brief 实现 “sortedKeysByLength” 对应的模块内功能。
* @details 本文件使用 tinyxml2 遍历 ICD/Excel XML并使用 Windows 代码页 API 兼容 GBK/GB2312文件操作采用 std::filesystem 与二进制流,失败时抛出异常交给公共入口处理。
* @param values 调用方传入的业务参数;其用途与约束由类型、名称及函数体共同定义。
* @return 构造、解析或查找到的结果;所有权与生命周期遵循返回类型。
*/
std::vector<std::string> sortedKeysByLength(const std::unordered_map<std::string, std::string>& values) {
std::vector<std::string> keys;
keys.reserve(values.size());
@@ -207,7 +340,15 @@ std::vector<std::string> sortedKeysByLength(const std::unordered_map<std::string
});
return keys;
}
/**
* Function: pathMatchesDo
*
* @brief 实现 “pathMatchesDo” 对应的模块内功能。
* @details 本文件使用 tinyxml2 遍历 ICD/Excel XML并使用 Windows 代码页 API 兼容 GBK/GB2312文件操作采用 std::filesystem 与二进制流,失败时抛出异常交给公共入口处理。
* @param rawPath 文件或目录路径;函数按 UTF-8/Windows 路径规则读取或写入。
* @param doKey 调用方传入的业务参数;其用途与约束由类型、名称及函数体共同定义。
* @return 条件成立或操作成功时为 true否则为 false。
*/
bool pathMatchesDo(const std::string& rawPath, const std::string& doKey) {
// rawPath 可以正好是 DO也可以是 DO$DA...;必须在 "$" 边界匹配,避免误命中相似前缀。
return rawPath == doKey ||
@@ -215,7 +356,16 @@ bool pathMatchesDo(const std::string& rawPath, const std::string& doKey) {
rawPath.compare(0, doKey.size(), doKey) == 0 &&
rawPath[doKey.size()] == '$');
}
/**
* Function: descForPath
*
* @brief 实现 “descForPath” 对应的模块内功能。
* @details 本文件使用 tinyxml2 遍历 ICD/Excel XML并使用 Windows 代码页 API 兼容 GBK/GB2312文件操作采用 std::filesystem 与二进制流,失败时抛出异常交给公共入口处理。
* @param rawPath 文件或目录路径;函数按 UTF-8/Windows 路径规则读取或写入。
* @param descByDo 调用方传入的业务参数;其用途与约束由类型、名称及函数体共同定义。
* @param orderedKeys 调用方传入的业务参数;其用途与约束由类型、名称及函数体共同定义。
* @return 构造、解析或查找到的结果;所有权与生命周期遵循返回类型。
*/
std::string descForPath(const std::string& rawPath,
const std::unordered_map<std::string, std::string>& descByDo,
const std::vector<std::string>& orderedKeys) {
@@ -227,7 +377,15 @@ std::string descForPath(const std::string& rawPath,
}
return "";
}
/**
* Function: findWorksheet
*
* @brief 在现有数据结构中查找 “findWorksheet” 对应的对象或位置。
* @details 本文件使用 tinyxml2 遍历 ICD/Excel XML并使用 Windows 代码页 API 兼容 GBK/GB2312文件操作采用 std::filesystem 与二进制流,失败时抛出异常交给公共入口处理。
* @param doc tinyxml2 文档对象;节点的生命周期由该文档管理。
* @param sheetName 调用方传入的业务参数;其用途与约束由类型、名称及函数体共同定义。
* @return 构造、解析或查找到的结果;所有权与生命周期遵循返回类型。
*/
tinyxml2::XMLElement* findWorksheet(tinyxml2::XMLDocument& doc, const char* sheetName) {
tinyxml2::XMLElement* workbook = doc.FirstChildElement("Workbook");
for (tinyxml2::XMLElement* ws = workbook ? workbook->FirstChildElement("Worksheet") : nullptr;
@@ -238,7 +396,15 @@ tinyxml2::XMLElement* findWorksheet(tinyxml2::XMLDocument& doc, const char* shee
}
return nullptr;
}
/**
* Function: headerColumn
*
* @brief 实现 “headerColumn” 对应的模块内功能。
* @details 本文件使用 tinyxml2 遍历 ICD/Excel XML并使用 Windows 代码页 API 兼容 GBK/GB2312文件操作采用 std::filesystem 与二进制流,失败时抛出异常交给公共入口处理。
* @param headerRow 当前处理的数据行、单元格、XML 节点或模型项。
* @param title 待解析、比较、显示或发送的 UTF-8 文本。
* @return 整数状态、索引或计数;入口函数以 0 表示成功。
*/
int headerColumn(tinyxml2::XMLElement* headerRow, const std::string& title) {
int current = 1;
for (tinyxml2::XMLElement* cell = headerRow ? headerRow->FirstChildElement("Cell") : nullptr;
@@ -250,9 +416,17 @@ int headerColumn(tinyxml2::XMLElement* headerRow, const std::string& title) {
}
return 0;
}
} // namespace
/**
* Function: pqApplyIcdDescriptionsToWorkbook
*
* @brief 实现 “pqApplyIcdDescriptionsToWorkbook” 对应的模块内功能。
* @details 本文件使用 tinyxml2 遍历 ICD/Excel XML并使用 Windows 代码页 API 兼容 GBK/GB2312文件操作采用 std::filesystem 与二进制流,失败时抛出异常交给公共入口处理。
* @param icdPath 文件或目录路径;函数按 UTF-8/Windows 路径规则读取或写入。
* @param workbookPath 文件或目录路径;函数按 UTF-8/Windows 路径规则读取或写入。
* @param message 输出参数;函数在成功或失败时写入结果或诊断信息。
* @return 条件成立或操作成功时为 true否则为 false。
*/
bool pqApplyIcdDescriptionsToWorkbook(const std::string& icdPath,
const std::string& workbookPath,
std::string* message) {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -157,7 +157,12 @@ struct PqMqEvent {
using PqMqEventFn = std::function<void(const PqMqEvent&)>;
// 默认配置。mq.cpp 会把运行期路径修正到 exe 所在目录旁的 runtime 目录。
/**
* @brief 创建一份完整的默认运行配置。
* @details mq.cpp 会把相对路径修正到 exe 所在目录旁的 runtime 目录GUI 随后再用
* 编辑框内容覆盖相应字段。返回值是独立副本,调用方可以安全修改。
* @return 包含 HTTP、RocketMQ、Topic/Tag/Key 和落盘路径默认值的 PqToolConfig。
*/
PqToolConfig pqDefaultConfig();
/*
@@ -214,17 +219,37 @@ bool pqSendTraceRequest(const PqToolConfig& cfg,
PqLogFn log,
PqMqEventFn event = {});
// 清空某个追踪目录下的 txt/json/jsonl/log 文本记录,保留目录本身。
/**
* @brief 清空指定装置/测点本次追踪可消费的历史文本记录。
* @details 路径由 pqTraceDirectoryFor() 统一计算;只移除 txt、json、jsonl、log 等
* 追踪记录并保留目录,以保证点击“数据追踪”后只读取新到达的数据。
* @param cfg 包含 traceRootDir 的运行配置。
* @param device 当前台账装置,参与进程和装置目录名计算。
* @param monitor 当前测点,参与最终目录名计算。
*/
void pqClearTraceRecords(const PqToolConfig& cfg,
const PqLedgerDevice& device,
const PqLedgerMonitor& monitor);
// 按 traceRootDir/process_x/device_x/monitor_x 生成稳定追踪目录。
/**
* @brief 计算某个装置和测点的稳定追踪目录。
* @details 目录布局为 traceRootDir/process_x/device_x/monitor_x实现会清理不适合
* Windows 文件名的字符,所有发送、消费、自动解析流程都应调用本函数,避免
* 各模块自行拼路径后指向不同目录。
* @return UTF-8 编码的目录字符串;本函数只计算路径,不创建目录。
*/
std::string pqTraceDirectoryFor(const PqToolConfig& cfg,
const PqLedgerDevice& device,
const PqLedgerMonitor& monitor);
// 为装置寻找 XML优先 device.xmlPath其次 icd_response.json 下载缓存,最后 cfg.xmlPath。
/**
* @brief 为当前装置选择最合适的 ICD/XML 映射模板。
* @details 查找顺序为 device.xmlPath、icd_response.json 中的下载缓存、cfg.xmlPath
* 只有实际存在的普通文件才会返回,防止解析阶段拿到失效路径。
* @param cfg 提供 XML 缓存目录和用户配置的兜底路径。
* @param device 提供装置自身的 xmlPath、devType 等识别信息。
* @return 找到时返回 UTF-8 路径,未找到时返回空字符串。
*/
std::string pqFindDeviceXmlPath(const PqToolConfig& cfg, const PqLedgerDevice& device);
/*
@@ -266,5 +291,10 @@ bool pqApplyIcdDescriptionsToWorkbook(const std::string& icdPath,
const std::string& workbookPath,
std::string* message = nullptr);
// GUI 入口。main.cpp 无命令行参数时调用,内部创建 Win32 主窗口和消息循环。
/**
* @brief 启动 Win32 图形界面并运行消息循环。
* @details main.cpp 在无命令行参数时调用;函数注册窗口类、创建 AppState 和各页面,
* 然后通过 GetMessage/DispatchMessage 把用户操作交给 interface.cpp::wndProc。
* @return 正常退出时返回消息循环的退出码,初始化失败时返回非零值。
*/
int runPqGuiApp();