#include "uf2interface.h" #include "utils/logmanager.h" #include #include #include #include #include #include #include Uf2Interface::Uf2Interface(QObject *parent) : QObject(parent) { } InterfaceInfo Uf2Interface::loadInterface(const QString& filePath) { InterfaceInfo result; result.path = filePath; QString sFilePath = filePath; sFilePath.replace('\\', '/'); QFileInfo fileInfo(sFilePath); if (!fileInfo.exists()) { LogManager::instance()->logError(QString("%1 文件不存在!").arg(sFilePath)); return result; } QString sCodeName = fileInfo.baseName(); result.cname = sCodeName; QFile file(sFilePath); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { LogManager::instance()->logError(QString("%1 无法打开文件").arg(sFilePath)); return result; } QXmlStreamReader xml(&file); QStack elementStack; while (!xml.atEnd() && !xml.hasError()) { QXmlStreamReader::TokenType token = xml.readNext(); if (token == QXmlStreamReader::StartElement) { QString elementName = xml.name().toString(); elementStack.push(elementName); if (elementName == "basic") { QXmlStreamAttributes attrs = xml.attributes(); if (attrs.hasAttribute("englishName")) { result.eName = attrs.value("englishName").toString(); } if (attrs.hasAttribute("objectId")) { result.functionNo = attrs.value("objectId").toString(); } if (attrs.hasAttribute("flag")) { result.flag = attrs.value("flag").toString(); } if (attrs.hasAttribute("checkLicence")) { result.checkLicence = (attrs.value("checkLicence").toString() == "true"); } if (attrs.hasAttribute("returnResultSet")) { result.returnResultSet = (attrs.value("returnResultSet").toString() == "true"); } if (attrs.hasAttribute("needTransMonitor")) { result.needTransMonitor = (attrs.value("needTransMonitor").toString() == "true"); } } else if (elementName == "stdFieldQuote") { QXmlStreamAttributes attrs = xml.attributes(); QString parentName = elementStack.size() > 1 ? elementStack[elementStack.size() - 2] : QString(); FieldInfo field; field.name = attrs.value("name").toString(); field.flag = attrs.value("flag").toString(); field.desc = attrs.value("comment").toString(); if (parentName == "import") { result.inputFields[field.name] = field; } else if (parentName == "export") { result.outputFields[field.name] = field; if (field.flag.contains("IO")) { result.inputFields[field.name] = field; } } } else if (elementName == "variableField") { QXmlStreamAttributes attrs = xml.attributes(); FieldInfo field; field.name = attrs.value("name").toString(); field.cname = attrs.value("cname").toString(); field.hsType = attrs.value("type").toString(); field.desc = attrs.value("desc").toString(); result.variableFields[field.name] = field; } else if (elementName == "code") { result.code = xml.readElementText(); // readElementText() 内部消费了 EndElement, // 但 elementStack 中 "code" 未被弹出,需要手动同步 if (!elementStack.isEmpty() && elementStack.top() == "code") { elementStack.pop(); } if (filePath.contains("不用编译")) { result.code.clear(); } } } else if (token == QXmlStreamReader::EndElement) { if (!elementStack.isEmpty()) { elementStack.pop(); } } } file.close(); return result; } QString Uf2Interface::getModuleEName(const QString& moduleXmlPath) { QFile file(moduleXmlPath); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { return QString(); } QXmlStreamReader xml(&file); while (!xml.atEnd() && !xml.hasError()) { QXmlStreamReader::TokenType token = xml.readNext(); if (token == QXmlStreamReader::StartElement) { QString elementName = xml.name().toString(); if (elementName == "info") { QXmlStreamAttributes attrs = xml.attributes(); if (attrs.hasAttribute("ename")) { return attrs.value("ename").toString(); } } } } file.close(); return QString(); } bool Uf2Interface::shouldFilter(const QString& filePath, const QStringList& completeNameList, const QStringList& containNameList) { QFileInfo fileInfo(filePath); QString fileName = fileInfo.fileName(); if (completeNameList.contains(fileName)) { return true; } for (const QString& name : containNameList) { if (filePath.contains(name, Qt::CaseInsensitive)) { return true; } } return false; } QMap Uf2Interface::scanDir(const QString& dirPath, const QString& ufAcct20ProjectDir, const QString& uftDbSett, const QMap& fileFilterDict, const QJsonObject& custJson) { QMap resultMap; QStringList completeNameList = fileFilterDict.value("completeNameList"); QStringList containNameList = fileFilterDict.value("containNameList"); QMap moduleCodeMap; moduleCodeMap["转融通"] = "ref"; // 预提取cust.json中的模块英文名映射 QMap custMoudleENameMap; if (!custJson.isEmpty() && custJson.contains("moudleEName")) { QJsonObject moudleENameObj = custJson["moudleEName"].toObject(); for (const QString& key : moudleENameObj.keys()) { custMoudleENameMap[key] = moudleENameObj[key].toString(); } } std::function scanModuleXmlRecursive; scanModuleXmlRecursive = [&](const QString& path) { if (path.isEmpty()) return; QDir dir(path); QStringList filters; filters << "module.xml"; QFileInfoList fileList = dir.entryInfoList(filters, QDir::Files); for (const QFileInfo& fileInfo : fileList) { QString filePath = fileInfo.absoluteFilePath(); filePath.replace('\\', '/'); if (filePath.contains("/数据库/")) { continue; } QString modName = fileInfo.dir().dirName(); QString modEName = getModuleEName(filePath); // cust.json回退:当路径包含"外部接口(不用编译)"且英文名为空时 if (filePath.contains("外部接口(不用编译)") && modEName.trimmed().isEmpty()) { if (custMoudleENameMap.contains(modName)) { modEName = custMoudleENameMap[modName]; } } moduleCodeMap[modName] = modEName; } QFileInfoList dirList = dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot); for (const QFileInfo& dirInfo : dirList) { scanModuleXmlRecursive(dirInfo.absoluteFilePath()); } }; auto scanModuleXml = [&](const QString& path) { scanModuleXmlRecursive(path); }; scanModuleXml(dirPath); scanModuleXml(ufAcct20ProjectDir); scanModuleXml(uftDbSett); std::function scanInterfaceFilesRecursive; scanInterfaceFilesRecursive = [&](const QString& path, const QString& serverType) { if (path.isEmpty()) { LogManager::instance()->log("路径为空,跳过"); return; } QDir dir(path); if (!dir.exists()) { LogManager::instance()->log(QString("目录不存在: %1").arg(path)); return; } QStringList filters; filters << "*.*"; QFileInfoList fileList = dir.entryInfoList(filters, QDir::Files); for (const QFileInfo& fileInfo : fileList) { QString filePath = fileInfo.absoluteFilePath(); filePath.replace('\\', '/'); if (shouldFilter(filePath, completeNameList, containNameList)) { continue; } QString sFilePath = filePath; int lastSlash = sFilePath.lastIndexOf('/'); QString pathWithoutFile = sFilePath.left(lastSlash); int secondLastSlash = pathWithoutFile.lastIndexOf('/'); QString pathWithoutLastDir = pathWithoutFile.left(secondLastSlash); int thirdLastSlash = pathWithoutLastDir.lastIndexOf('/'); QString modName = pathWithoutLastDir.mid(thirdLastSlash + 1); InterfaceInfo interfaceInfo = loadInterface(filePath); interfaceInfo.moudle = modName; QString moudleEName = moduleCodeMap.value(modName); interfaceInfo.moudleEName = moudleEName; interfaceInfo.serverType = serverType; QString key = interfaceInfo.cname; if (resultMap.contains(key)) { QString existingPath = resultMap[key].path; if (existingPath.contains("不用编译")) { resultMap[key] = interfaceInfo; } else if (!filePath.contains("不用编译")) { LogManager::instance()->logWarning(QString("存在重复接口名: %1").arg(key)); } } else { resultMap[key] = interfaceInfo; } } QFileInfoList dirList = dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot); for (const QFileInfo& dirInfo : dirList) { QString subDirPath = dirInfo.absoluteFilePath(); subDirPath.replace('\\', '/'); scanInterfaceFilesRecursive(subDirPath, serverType); } }; auto scanInterfaceFiles = [&](const QString& path, const QString& serverType) { scanInterfaceFilesRecursive(path, serverType); }; scanInterfaceFiles(dirPath, "trade"); scanInterfaceFiles(ufAcct20ProjectDir, "acct"); scanInterfaceFiles(uftDbSett, "dbsett"); LogManager::instance()->log(QString("扫描完成,共找到 %1 个接口").arg(resultMap.size())); return resultMap; } QMap Uf2Interface::buildModuleCodeMap(const QString& dirPath, const QString& ufAcct20ProjectDir, const QString& uftDbSett, const QJsonObject& custJson) { QMap moduleCodeMap; moduleCodeMap["转融通"] = "ref"; // 预提取cust.json中的模块英文名映射 QMap custMoudleENameMap; if (!custJson.isEmpty() && custJson.contains("moudleEName")) { QJsonObject moudleENameObj = custJson["moudleEName"].toObject(); for (const QString& key : moudleENameObj.keys()) { custMoudleENameMap[key] = moudleENameObj[key].toString(); } } std::function scanModuleXmlRecursive = [&](const QString& path) { if (path.isEmpty()) return; QDir dir(path); QStringList filters; filters << "module.xml"; QFileInfoList fileList = dir.entryInfoList(filters, QDir::Files); for (const QFileInfo& fileInfo : fileList) { QString filePath = fileInfo.absoluteFilePath(); filePath.replace('\\', '/'); if (filePath.contains("/数据库/")) continue; QString modName = fileInfo.dir().dirName(); QString modEName = getModuleEName(filePath); if (filePath.contains("外部接口(不用编译)") && modEName.trimmed().isEmpty()) { if (custMoudleENameMap.contains(modName)) modEName = custMoudleENameMap[modName]; } moduleCodeMap[modName] = modEName; } QFileInfoList dirList = dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot); for (const QFileInfo& dirInfo : dirList) scanModuleXmlRecursive(dirInfo.absoluteFilePath()); }; scanModuleXmlRecursive(dirPath); scanModuleXmlRecursive(ufAcct20ProjectDir); scanModuleXmlRecursive(uftDbSett); return moduleCodeMap; } InterfaceInfo Uf2Interface::assemble(const QString& filePath, const QString& serverType, const QMap& moduleCodeMap) { QString sFilePath = filePath; sFilePath.replace('\\', '/'); int lastSlash = sFilePath.lastIndexOf('/'); QString pathWithoutFile = sFilePath.left(lastSlash); int secondLastSlash = pathWithoutFile.lastIndexOf('/'); QString pathWithoutLastDir = pathWithoutFile.left(secondLastSlash); int thirdLastSlash = pathWithoutLastDir.lastIndexOf('/'); QString modName = pathWithoutLastDir.mid(thirdLastSlash + 1); InterfaceInfo interfaceInfo = loadInterface(filePath); interfaceInfo.moudle = modName; interfaceInfo.moudleEName = moduleCodeMap.value(modName); interfaceInfo.serverType = serverType; return interfaceInfo; } QList Uf2Interface::collectFiles(const QString& dirPath, const QString& serverType, const QMap& fileFilterDict) { QList result; QStringList completeNameList = fileFilterDict.value("completeNameList"); QStringList containNameList = fileFilterDict.value("containNameList"); std::function scanInterfaceFilesRecursive = [&](const QString& path, const QString& st) { if (path.isEmpty()) return; QDir dir(path); if (!dir.exists()) return; QFileInfoList fileList = dir.entryInfoList(QStringList() << "*.*", QDir::Files); for (const QFileInfo& fileInfo : fileList) { QString filePath = fileInfo.absoluteFilePath(); filePath.replace('\\', '/'); if (shouldFilter(filePath, completeNameList, containNameList)) continue; Uf2FileEntry entry; entry.path = filePath; entry.serverType = st; entry.mtime = fileInfo.lastModified().toMSecsSinceEpoch(); result.append(entry); } QFileInfoList dirList = dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot); for (const QFileInfo& dirInfo : dirList) scanInterfaceFilesRecursive(dirInfo.absoluteFilePath(), st); }; scanInterfaceFilesRecursive(dirPath, serverType); return result; }