change_code/src/metadataupdate/uf2interface.cpp

392 lines
15 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "uf2interface.h"
#include "utils/logmanager.h"
#include <QFile>
#include <QFileInfo>
#include <QDebug>
#include <QDir>
#include <QStack>
#include <functional>
#include <functional>
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<QString> 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() 内部消费了 </code> 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<QString, InterfaceInfo> Uf2Interface::scanDir(const QString& dirPath,
const QString& ufAcct20ProjectDir,
const QString& uftDbSett,
const QMap<QString, QStringList>& fileFilterDict,
const QJsonObject& custJson)
{
QMap<QString, InterfaceInfo> resultMap;
QStringList completeNameList = fileFilterDict.value("completeNameList");
QStringList containNameList = fileFilterDict.value("containNameList");
QMap<QString, QString> moduleCodeMap;
moduleCodeMap["转融通"] = "ref";
// 预提取cust.json中的模块英文名映射
QMap<QString, QString> 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<void(const QString&)> 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<void(const QString&, const QString&)> 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<QString, QString> Uf2Interface::buildModuleCodeMap(const QString& dirPath,
const QString& ufAcct20ProjectDir,
const QString& uftDbSett,
const QJsonObject& custJson)
{
QMap<QString, QString> moduleCodeMap;
moduleCodeMap["转融通"] = "ref";
// 预提取cust.json中的模块英文名映射
QMap<QString, QString> 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<void(const QString&)> 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<QString, QString>& 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<Uf2FileEntry> Uf2Interface::collectFiles(const QString& dirPath,
const QString& serverType,
const QMap<QString, QStringList>& fileFilterDict)
{
QList<Uf2FileEntry> result;
QStringList completeNameList = fileFilterDict.value("completeNameList");
QStringList containNameList = fileFilterDict.value("containNameList");
std::function<void(const QString&, const QString&)> 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;
}