Compare commits
19 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
6dfba8715d | |
|
|
dbb7059664 | |
|
|
edb693e5af | |
|
|
d891b4f583 | |
|
|
5718503f26 | |
|
|
cc7fc51399 | |
|
|
fad539e127 | |
|
|
4cb44fc2fa | |
|
|
273da28390 | |
|
|
8ecf44db1a | |
|
|
b55596078d | |
|
|
5f3a8cc8dd | |
|
|
3e05ecd9d2 | |
|
|
aa1bb42467 | |
|
|
2af12b298c | |
|
|
c097120ca3 | |
|
|
fd38553be1 | |
|
|
5bd09d58eb | |
|
|
bb126cbeeb |
|
|
@ -5,9 +5,17 @@
|
||||||
!python_bindings/**
|
!python_bindings/**
|
||||||
!src/
|
!src/
|
||||||
!src/**
|
!src/**
|
||||||
|
!help/
|
||||||
|
!help/**
|
||||||
|
!resources/
|
||||||
|
!resources/**
|
||||||
!*.bat
|
!*.bat
|
||||||
!*.rc
|
!*.rc
|
||||||
!*.prp
|
!*.prp
|
||||||
!*.cpp
|
!*.cpp
|
||||||
!*.qrc
|
!*.qrc
|
||||||
!.gitignore
|
!*.h
|
||||||
|
!*.pro
|
||||||
|
!*.md
|
||||||
|
!.gitignore
|
||||||
|
!.gitkeep
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
# 图标设置说明
|
||||||
|
|
||||||
|
## 已完成配置
|
||||||
|
|
||||||
|
1. **应用程序窗口图标** - 已设置为 `resources/icons/转码工具.svg`
|
||||||
|
2. **资源文件** - 图标已添加到 `resources.qrc`
|
||||||
|
|
||||||
|
## Windows 可执行程序图标(可选)
|
||||||
|
|
||||||
|
如需设置 Windows 可执行文件的图标(任务栏、文件管理器显示的图标),需要:
|
||||||
|
|
||||||
|
### 方法 1:使用在线工具转换
|
||||||
|
1. 将 `resources/images/转码工具.png` 转换为 `.ico` 格式
|
||||||
|
2. 推荐尺寸:包含 16x16, 32x32, 48x48, 256x256 等多种尺寸
|
||||||
|
3. 保存为 `app.ico` 并放在项目根目录
|
||||||
|
4. `app.rc` 已配置引用 `app.ico`
|
||||||
|
|
||||||
|
### 方法 2:使用 ImageMagick 转换
|
||||||
|
```bash
|
||||||
|
magick convert 转码工具.png -define icon:auto-resize=256,128,96,64,48,32,16 app.ico
|
||||||
|
```
|
||||||
|
|
||||||
|
### 重新编译
|
||||||
|
设置好图标后重新编译项目即可。
|
||||||
|
|
@ -0,0 +1,89 @@
|
||||||
|
QT += core gui widgets sql
|
||||||
|
|
||||||
|
TARGET = Uft30ChangeCode
|
||||||
|
TEMPLATE = app
|
||||||
|
|
||||||
|
DEFINES += QT_DEPRECATED_WARNINGS
|
||||||
|
|
||||||
|
SOURCES += main.cpp \
|
||||||
|
src/mainwindow/mainwindow.cpp \
|
||||||
|
src/pythonrunner/PythonRunner.cpp \
|
||||||
|
src/pages/about/aboutdialog.cpp \
|
||||||
|
src/pages/batchconvert/batchconvertpage.cpp \
|
||||||
|
src/pages/functionsearch/functionsearchpage.cpp \
|
||||||
|
src/pages/functionsearch/uf20functionsearchpage.cpp \
|
||||||
|
src/pages/functionsearch/uft3functionsearchpage.cpp \
|
||||||
|
src/components/elasearchedit.cpp \
|
||||||
|
src/components/interdialog.cpp \
|
||||||
|
src/pages/help/helpdocpage.cpp \
|
||||||
|
src/pages/settings/settingspage.cpp \
|
||||||
|
src/pages/metadatupdate/metadatupdatepage.cpp \
|
||||||
|
src/metadataupdate/filedb.cpp \
|
||||||
|
src/metadataupdate/uf2interface.cpp \
|
||||||
|
src/metadataupdate/uft3interface.cpp \
|
||||||
|
src/metadataupdate/metadataprocessor.cpp \
|
||||||
|
src/metadataupdate/uf2datatype.cpp \
|
||||||
|
src/metadataupdate/uf2stdfields.cpp \
|
||||||
|
src/metadataupdate/uf2errnumber.cpp \
|
||||||
|
src/metadataupdate/uft3datatype.cpp \
|
||||||
|
src/metadataupdate/uft3stdfields.cpp \
|
||||||
|
src/metadataupdate/uft3table.cpp \
|
||||||
|
src/utils/datacache.cpp \
|
||||||
|
src/utils/uf2configreader.cpp \
|
||||||
|
src/utils/uft3configreader.cpp \
|
||||||
|
src/utils/logmanager.cpp \
|
||||||
|
src/utils/configmanager.cpp \
|
||||||
|
src/utils/version.cpp
|
||||||
|
|
||||||
|
HEADERS += src/mainwindow/mainwindow.h \
|
||||||
|
src/pythonrunner/PythonRunner.h \
|
||||||
|
src/pages/about/aboutdialog.h \
|
||||||
|
src/pages/batchconvert/batchconvertpage.h \
|
||||||
|
src/pages/functionsearch/functionsearchpage.h \
|
||||||
|
src/pages/functionsearch/uf20functionsearchpage.h \
|
||||||
|
src/pages/functionsearch/uft3functionsearchpage.h \
|
||||||
|
src/components/elasearchedit.h \
|
||||||
|
src/components/interdialog.h \
|
||||||
|
src/pages/help/helpdocpage.h \
|
||||||
|
src/pages/settings/settingspage.h \
|
||||||
|
src/pages/metadatupdate/metadatupdatepage.h \
|
||||||
|
src/metadataupdate/filedb.h \
|
||||||
|
src/metadataupdate/uf2interface.h \
|
||||||
|
src/metadataupdate/uft3interface.h \
|
||||||
|
src/metadataupdate/metadataprocessor.h \
|
||||||
|
src/metadataupdate/uf2datatype.h \
|
||||||
|
src/metadataupdate/uf2stdfields.h \
|
||||||
|
src/metadataupdate/uf2errnumber.h \
|
||||||
|
src/metadataupdate/uft3datatype.h \
|
||||||
|
src/metadataupdate/uft3stdfields.h \
|
||||||
|
src/metadataupdate/uft3table.h \
|
||||||
|
src/utils/datacache.h \
|
||||||
|
src/utils/uf2configreader.h \
|
||||||
|
src/utils/uft3configreader.h \
|
||||||
|
src/utils/logmanager.h \
|
||||||
|
src/utils/configmanager.h \
|
||||||
|
src/utils/version.h
|
||||||
|
|
||||||
|
RESOURCES += resources.qrc
|
||||||
|
|
||||||
|
CONFIG += c++17
|
||||||
|
CONFIG += debug_and_release
|
||||||
|
|
||||||
|
QMAKE_CXXFLAGS += -Wall -Wextra
|
||||||
|
QMAKE_LFLAGS += -fno-use-linker-plugin
|
||||||
|
|
||||||
|
INCLUDEPATH += src
|
||||||
|
INCLUDEPATH += 3rd/ElaWidgetTools/include
|
||||||
|
|
||||||
|
win32 {
|
||||||
|
LIBS += -L$$PWD/3rd/ElaWidgetTools/lib -lElaWidgetTools
|
||||||
|
LIBS += -ld3d11 -ldxgi
|
||||||
|
RC_FILE = app.rc
|
||||||
|
}
|
||||||
|
|
||||||
|
DESTDIR = $$PWD/bin
|
||||||
|
OBJECTS_DIR = $$PWD/build
|
||||||
|
MOC_DIR = $$PWD/build
|
||||||
|
RCC_DIR = $$PWD/build
|
||||||
|
|
||||||
|
|
||||||
2
app.rc
|
|
@ -1 +1 @@
|
||||||
IDI_ICON1 ICON DISCARDABLE "app.ico"
|
IDI_ICON1 ICON DISCARDABLE "resources/images/ChangeCode.ico"
|
||||||
|
|
@ -66,8 +66,8 @@ echo [OK] qmake done
|
||||||
echo.
|
echo.
|
||||||
|
|
||||||
REM Compile
|
REM Compile
|
||||||
echo [4/4] Compiling Debug version...
|
echo [4/4] Compiling Release version...
|
||||||
mingw32-make debug
|
mingw32-make release
|
||||||
if errorlevel 1 (
|
if errorlevel 1 (
|
||||||
echo.
|
echo.
|
||||||
echo ERROR: Compilation failed
|
echo ERROR: Compilation failed
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
# 默认忽略的文件
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Uft30ChangeCodeHelp
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectRootManager">
|
||||||
|
<output url="file://$PROJECT_DIR$/out" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/help.iml" filepath="$PROJECT_DIR$/help.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
# 默认忽略的文件
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="JAVA_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||||
|
<exclude-output />
|
||||||
|
<content url="file://$MODULE_DIR$" />
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="21" project-jdk-type="JavaSDK">
|
||||||
|
<output url="file://$PROJECT_DIR$/out" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/Writerside.iml" filepath="$PROJECT_DIR$/.idea/Writerside.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE categories
|
||||||
|
SYSTEM "https://resources.jetbrains.com/writerside/1.0/categories.dtd">
|
||||||
|
<categories>
|
||||||
|
<category id="wrs" name="Writerside documentation" order="1"/>
|
||||||
|
</categories>
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE buildprofiles SYSTEM "https://resources.jetbrains.com/writerside/1.0/build-profiles.dtd">
|
||||||
|
<buildprofiles xsi:noNamespaceSchemaLocation="https://resources.jetbrains.com/writerside/1.0/build-profiles.xsd"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||||
|
|
||||||
|
<variables>
|
||||||
|
<custom-favicons>ChangeCode.png</custom-favicons>
|
||||||
|
</variables>
|
||||||
|
|
||||||
|
</buildprofiles>
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE terms SYSTEM "https://resources.jetbrains.com/writerside/1.0/glossary.dtd">
|
||||||
|
<terms>
|
||||||
|
<term name="foo">
|
||||||
|
Description of what "foo" is.
|
||||||
|
</term>
|
||||||
|
</terms>
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE instance-profile
|
||||||
|
SYSTEM "https://resources.jetbrains.com/writerside/1.0/product-profile.dtd">
|
||||||
|
|
||||||
|
<instance-profile id="hi"
|
||||||
|
name="Uft30ChangeCode"
|
||||||
|
start-page="Uft30ChangeCode.md">
|
||||||
|
<toc-element topic="Uft30ChangeCode.md">
|
||||||
|
<toc-element topic="设置.md"/>
|
||||||
|
</toc-element>
|
||||||
|
<toc-element topic="功能转码.md">
|
||||||
|
<toc-element topic="业务转码.md"/>
|
||||||
|
</toc-element>
|
||||||
|
<toc-element topic="功能查询.md">
|
||||||
|
<toc-element topic="UFT3功能查询.md"/>
|
||||||
|
<toc-element topic="UF20功能查询.md"/>
|
||||||
|
</toc-element>
|
||||||
|
<toc-element topic="元数据更新.md"/>
|
||||||
|
<toc-element topic="更新记录.md">
|
||||||
|
<toc-element topic="update-1-0-0.md"/>
|
||||||
|
</toc-element>
|
||||||
|
<toc-element topic="下载.md"/>
|
||||||
|
</instance-profile>
|
||||||
|
After Width: | Height: | Size: 8.0 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 51 KiB |
|
After Width: | Height: | Size: 51 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 51 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 45 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 48 KiB |
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 50 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 51 KiB |
|
|
@ -0,0 +1,13 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE rules SYSTEM "https://resources.jetbrains.com/writerside/1.0/redirection-rules.dtd">
|
||||||
|
<rules>
|
||||||
|
<!-- format is as follows
|
||||||
|
<rule id="<unique id>">
|
||||||
|
<accepts>page.html</accepts>
|
||||||
|
</rule>
|
||||||
|
-->
|
||||||
|
<rule id="42b8a0d">
|
||||||
|
<description>Created after removal of "Empty MD Topic" from Uft30ChangeCode</description>
|
||||||
|
<accepts>Empty-MD-Topic.html</accepts>
|
||||||
|
</rule>
|
||||||
|
</rules>
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
# UF20功能查询
|
||||||
|
|
||||||
|
查询UFT3系统中的函数信息。
|
||||||
|
|
||||||
|
## 查询条件
|
||||||
|
从下拉框选择查询(功能名称、功能编号),输入框输入查询关键词,点击"Aa"切换精确/模糊匹配模式,点击放大镜图标或按回车执行查询
|
||||||
|
|
||||||
|
- 功能名称
|
||||||
|
<img src="功能名称查询.png" alt="功能名称查询"/>
|
||||||
|
|
||||||
|
- 功能编号
|
||||||
|
<img src="模糊查询uf20.png" alt="模糊查询uf20"/>
|
||||||
|
<img src="精准查询uf20.png" alt="精准查询uf20"/>
|
||||||
|
|
||||||
|
## 双击添加
|
||||||
|
双击选中行添加转码业务,只支持LS功能添加
|
||||||
|
<img src="双击添加.png" alt="双击添加"/>
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
# UFT3功能查询
|
||||||
|
|
||||||
|
查询UFT3系统中的函数信息。
|
||||||
|
|
||||||
|
## 查询条件
|
||||||
|
从下拉框选择查询(功能名称、功能编号),输入框输入查询关键词,点击"Aa"切换精确/模糊匹配模式,点击放大镜图标或按回车执行查询
|
||||||
|
|
||||||
|
- 功能名称
|
||||||
|
<img src="功能名称查询uft3.png" alt="功能名称查询uft3"/>
|
||||||
|
- 功能编号
|
||||||
|
<img src="模糊查询UFT3.png" alt="模糊查询UFT3"/>
|
||||||
|
<img src="精准查询uft3.png" alt="精准查询uft3"/>
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
# Uft30ChangeCode
|
||||||
|
|
||||||
|
提供UFT30元数据、UF20公共资源搜索功能,支持业务转码
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
# 1.0.0
|
||||||
|
|
||||||
|
1.支持业务转码
|
||||||
|
|
||||||
|
2.支持代码uf20、uft3功能查找
|
||||||
|
|
||||||
|
3.支持帮助菜单和在线帮助文档
|
||||||
|
|
||||||
|
4.支持接口元数据更新
|
||||||
|
|
||||||
|
5.设置菜单UFT30项目环境路径、UF20项目环境路径、UF20账户环境路径、转码生成路径、支持弹窗选择目录。
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
# 下载
|
||||||
|
|
||||||
|
## 全量更新
|
||||||
|
下载全量包,解压即用。
|
||||||
|
|
||||||
|
> 1.0.0版本是基础版本,包含所需功能,如果是第一次下载,请选择全量包。
|
||||||
|
{style="note"}
|
||||||
|
## 增量更新
|
||||||
|
下载增量包,解压后替换原文件即可
|
||||||
|
> 1.0.0版本是基础版本,如若要从旧版升级到1.0.0及以上版本,可以选择增量版本下载,并将旧版根目录下的uf2touft3和当前目录替换覆盖到新版根目录。
|
||||||
|
{style="note"}
|
||||||
|
|
||||||
|
## 下载
|
||||||
|
|
||||||
|
| 版本 | 更新日期 | 全量包 | 增量包 |
|
||||||
|
|------|------------|---------------------------------------------------------------------------------|-----|
|
||||||
|
| 1.0.0 | 2026-06-01 | [Uft30ChangeCode-1.0.0.zip](http://10.20.163.105:6045/download/uft3changecode/Uft30ChangeCode-1.0.0.zip) | |
|
||||||
|
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
# 业务转码
|
||||||
|
|
||||||
|
将UF20函数转换为UFT3函数格式的核心功能。
|
||||||
|
|
||||||
|
## 功能列表管理
|
||||||
|
|
||||||
|
点击"添加"按钮,输入函数名添加到转码列表
|
||||||
|
<img src="添加函数.png" alt="添加函数"/>
|
||||||
|
|
||||||
|
点击表格操作按钮可编辑函数名,如下:
|
||||||
|
<img src="编辑.png" alt="编辑"/>
|
||||||
|
|
||||||
|
选中行后点击"删除"移除函数、点击"清空"清空所有函数,如下:
|
||||||
|
<img src="删除.png" alt="删除"/>
|
||||||
|
|
||||||
|
## 配置文件同步
|
||||||
|
|
||||||
|
- 自动读取 uf2touft3/cust.json 配置
|
||||||
|
- 配置文件外部修改时自动刷新列表
|
||||||
|
|
||||||
|
## 转换操作
|
||||||
|
|
||||||
|
点击"开始转换"启动转换任务,转换过程中可查看进度条和状态信息,如下:
|
||||||
|
<img src="转码.png" alt="转码"/>
|
||||||
|
|
||||||
|
点击"停止转换"中止当前任务,如下:
|
||||||
|
<img src="停止转码.png" alt="停止转码"/>
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
# 元数据更新
|
||||||
|
|
||||||
|
更新UF20和UFT3系统的元数据配置。
|
||||||
|
|
||||||
|
## 项目配置
|
||||||
|
需要先配置UFT30项目路径和UF20项目路径。
|
||||||
|
|
||||||
|
在设置-首选项页面,配置UFT30项目路径,例如:
|
||||||
|
``在设置-首选项页面,配置UFT30项目路径,例如:``
|
||||||
|
<img src="UFT3项目环境路径.png" alt="UFT3项目环境路径"/>
|
||||||
|
|
||||||
|
在设置-首选项页面,配置UF20项目路径,例如:
|
||||||
|
``E:\05.code\04.SVN\secu\dep1\hstrade20\trunk\Sources\DevCodes\经纪业务运营平台V21``
|
||||||
|
<img src="UF20项目环境路径.png" alt="UF20项目环境路径"/>
|
||||||
|
|
||||||
|
## UFT3元数据
|
||||||
|
在 元数据更新 页面,选择更新范围(标准字段、接口数据等)并点击更新UFT3按钮完成元数据更新。
|
||||||
|
<img src="UFT3元数据.png" alt="UFT3元数据"/>
|
||||||
|
**备注:接口数据更新比较久**
|
||||||
|
|
||||||
|
## 更新UF20元数据
|
||||||
|
在 元数据更新 页面,选择更新范围(标准字段、标准组件等)并点击更新UF2按钮完成公共资源更新
|
||||||
|
<img src="UF20元数据.png" alt="UF20元数据"/>
|
||||||
|
**备注:接口数据更新比较久**
|
||||||
|
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
# 功能查询
|
||||||
|
|
||||||
|
## 快速跳转
|
||||||
|
[UFT3功能查询](http://10.20.163.105:6045/uft3changecode/UFT3功能查询.html)
|
||||||
|
|
||||||
|
[UF20功能查询](http://10.20.163.105:6045/uft3changecode/UF20功能查询.html)
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
# 功能转码
|
||||||
|
提供UFT3业务转码功能,将uf20代码转成UFT3代码
|
||||||
|
|
||||||
|
## 项目配置
|
||||||
|
在使用UFT3功能转码前,需要先配置UFT30项目路径,并更新UFT3、UF20元数据
|
||||||
|
|
||||||
|
1.配置项目路径
|
||||||
|
- UFT3项目环境路径
|
||||||
|
|
||||||
|
在设置-首选项页面,配置UFT30项目路径,转码使用,例如:
|
||||||
|
``E:\05.code\03.GIT\feature_ses``
|
||||||
|
<img src="UFT3项目环境路径.png" alt="UFT3项目环境路径"/>
|
||||||
|
|
||||||
|
- UF20项目环境路径
|
||||||
|
|
||||||
|
在设置-首选项页面,UF20项目环境路径, 转码需要读取相关的文件, 例如:
|
||||||
|
``E:\05.code\04.SVN\secu\dep1\hstrade20\trunk\Sources\DevCodes\经纪业务运营平台V21``
|
||||||
|
<img src="UF20项目环境路径.png" alt="UF20项目环境路径"/>
|
||||||
|
|
||||||
|
- UF20账户环境路径
|
||||||
|
|
||||||
|
在设置-首选项页面,配置UF20账户环境路径, 转码需要读取账户相关的文件,例如:
|
||||||
|
``E:\05.code\04.SVN\secu\dep1\hstrade20\trunk\Sources\DevCodes_Acct1\客户账户管理系统V22``
|
||||||
|
<img src="UF20账户环境路径.png" alt="UF20账户环境路径"/>
|
||||||
|
- 转码生成路径
|
||||||
|
|
||||||
|
在设置-首选项页面,配置转码生成路径, 用于存放生成的转码文件, 例如:
|
||||||
|
``F:\07.tools\01.hstools\Uft30ChangeCode\bin\uf2touft3\change_code``
|
||||||
|
<img src="转码生成路径.png" alt="转码生成路径"/>
|
||||||
|
|
||||||
|
## 快速跳转
|
||||||
|
[业务转码](http://10.20.163.105:6045/uft3changecode/业务转码.html)
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
# 更新记录
|
||||||
|
|
||||||
|
Start typing here...
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
# 设置
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## UFT3项目环境路径
|
||||||
|
|
||||||
|
在设置-首选项页面,配置UFT30项目路径,转码使用,例如:
|
||||||
|
``E:\05.code\03.GIT\feature_ses``
|
||||||
|
|
||||||
|
## UF20项目环境路径 {id="uf20_1"}
|
||||||
|
|
||||||
|
在设置-首选项页面,UF20项目环境路径, 转码需要读取相关的文件, 例如:
|
||||||
|
``E:\05.code\04.SVN\secu\dep1\hstrade20\trunk\Sources\DevCodes\经纪业务运营平台V21``
|
||||||
|
|
||||||
|
## UF20账户环境路径
|
||||||
|
|
||||||
|
在设置-首选项页面,配置UF20账户环境路径, 转码需要读取账户相关的文件,例如:
|
||||||
|
``E:\05.code\04.SVN\secu\dep1\hstrade20\trunk\Sources\DevCodes_Acct1\客户账户管理系统V22``
|
||||||
|
|
||||||
|
## 转码生成路径
|
||||||
|
|
||||||
|
在设置-首选项页面,配置转码生成路径, 用于存放生成的转码文件, 例如:
|
||||||
|
``F:\07.tools\01.hstools\Uft30ChangeCode\bin\uf2touft3\change_code``
|
||||||
|
|
||||||
|
## 主题切换
|
||||||
|
包含日间模式和夜间模式。
|
||||||
|
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE vars SYSTEM "https://resources.jetbrains.com/writerside/1.0/vars.dtd">
|
||||||
|
<vars>
|
||||||
|
<var name="product" value="Writerside"/>
|
||||||
|
</vars>
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE ihp SYSTEM "https://resources.jetbrains.com/writerside/1.0/ihp.dtd">
|
||||||
|
|
||||||
|
<ihp version="2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:noNamespaceSchemaLocation="https://resources.jetbrains.com/writerside/1.0/writerside-cfg.xsd">
|
||||||
|
<topics dir="topics"/>
|
||||||
|
<images dir="images" web-path="images"/>
|
||||||
|
<categories src="c.list"/>
|
||||||
|
<vars src="v.list"/>
|
||||||
|
<instance src="hi.tree"/>
|
||||||
|
</ihp>
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
server {
|
||||||
|
listen 6045;
|
||||||
|
server_name _;
|
||||||
|
|
||||||
|
location /uft3changecode/ {
|
||||||
|
alias /home/taoc/uft30help/uft3changecode/;
|
||||||
|
index index.html;
|
||||||
|
try_files $uri $uri/ /uft3changecode/index.html;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
worker_processes 1;
|
||||||
|
pid /home/taoc/nginx/logs/nginx.pid;
|
||||||
|
|
||||||
|
events {
|
||||||
|
worker_connections 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
http {
|
||||||
|
include /home/taoc/nginx/conf/mime.types;
|
||||||
|
default_type application/octet-stream;
|
||||||
|
|
||||||
|
access_log /home/taoc/nginx/logs/help_access.log;
|
||||||
|
error_log /home/taoc/nginx/logs/help_error.log;
|
||||||
|
|
||||||
|
sendfile on;
|
||||||
|
keepalive_timeout 65;
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 6045;
|
||||||
|
server_name _;
|
||||||
|
|
||||||
|
root /home/taoc/uft30help/html/;
|
||||||
|
index index.html index.htm;
|
||||||
|
|
||||||
|
location /uft3changecode/ {
|
||||||
|
index index.html index.htm;
|
||||||
|
try_files $uri $uri/ /uft3changecode/index.html;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_page 500 502 503 504 /50x.html;
|
||||||
|
location = /50x.html {
|
||||||
|
root html;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,89 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "=== Force Restart Help Documentation Server ==="
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
echo "1. Killing all nginx processes..."
|
||||||
|
pkill -f nginx 2>/dev/null || true
|
||||||
|
sleep 2
|
||||||
|
|
||||||
|
echo "2. Checking for remaining nginx processes..."
|
||||||
|
if pgrep nginx > /dev/null; then
|
||||||
|
echo " Force killing remaining nginx processes..."
|
||||||
|
pkill -9 nginx 2>/dev/null || true
|
||||||
|
sleep 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "3. Checking port 6045..."
|
||||||
|
lsof -i :6045 2>/dev/null || echo " Port 6045 is free"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "4. Starting fresh nginx instance..."
|
||||||
|
|
||||||
|
NGINX_BIN="/home/taoc/nginx/sbin/nginx"
|
||||||
|
HELP_DOCS_DIR="/home/taoc/uft30help/"
|
||||||
|
CONF_FILE="$HELP_DOCS_DIR/workspace/nginx.conf"
|
||||||
|
|
||||||
|
if [ ! -f "$CONF_FILE" ]; then
|
||||||
|
echo " Copying nginx configuration..."
|
||||||
|
cp "$(dirname "$0")/nginx.conf" "$CONF_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -f "$HELP_DOCS_DIR/workspace/help.conf" ]; then
|
||||||
|
echo " Copying server configuration..."
|
||||||
|
cp "$(dirname "$0")/help.conf" "$HELP_DOCS_DIR/workspace/help.conf"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -f "$HELP_DOCS_DIR/uft3changecode/index.html" ]; then
|
||||||
|
echo " Creating default index.html..."
|
||||||
|
cat > "$HELP_DOCS_DIR/uft3changecode/index.html" << 'EOF'
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>UFT30ChangeCode Help</title>
|
||||||
|
<style>
|
||||||
|
body { font-family: Arial, sans-serif; text-align: center; padding: 50px; background: #f5f5f5; }
|
||||||
|
.container { background: white; padding: 40px; border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); display: inline-block; }
|
||||||
|
.logo { font-size: 64px; margin-bottom: 20px; }
|
||||||
|
h1 { color: #667eea; margin: 0; }
|
||||||
|
.subtitle { color: #666; margin-top: 10px; }
|
||||||
|
.path { background: #f0f0f0; padding: 10px 20px; border-radius: 5px; margin-top: 20px; font-family: monospace; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div class="logo">📖</div>
|
||||||
|
<h1>UFT30ChangeCode Help</h1>
|
||||||
|
<p class="subtitle">Help Documentation Server</p>
|
||||||
|
<div class="path">Path: /uft3changecode/</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "5. Testing configuration..."
|
||||||
|
"$NGINX_BIN" -t -c "$CONF_FILE"
|
||||||
|
|
||||||
|
echo "6. Starting nginx..."
|
||||||
|
"$NGINX_BIN" -c "$CONF_FILE"
|
||||||
|
|
||||||
|
sleep 2
|
||||||
|
echo ""
|
||||||
|
echo "=== Server Status ==="
|
||||||
|
if pgrep nginx > /dev/null; then
|
||||||
|
SERVER_IP=$(ip addr show | grep inet | grep -v '127.0.0.1' | grep -v '::1' | head -1 | awk '{print $2}' | cut -d'/' -f1)
|
||||||
|
echo "✅ Server started successfully!"
|
||||||
|
echo ""
|
||||||
|
echo "Access URLs:"
|
||||||
|
echo " Local: http://localhost:6045/uft3changecode/"
|
||||||
|
if [ -n "$SERVER_IP" ]; then
|
||||||
|
echo " Remote: http://$SERVER_IP:6045/uft3changecode/"
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
echo "Verify with:"
|
||||||
|
echo " curl http://localhost:6045/uft3changecode/"
|
||||||
|
else
|
||||||
|
echo "❌ Failed to start server"
|
||||||
|
echo "Check error log: /home/taoc/uft30help/workspace/logs/help_error.log"
|
||||||
|
fi
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
NGINX_BIN="/home/taoc/nginx/sbin/nginx"
|
||||||
|
CONF_DIR="/home/taoc/uft30help/workspace"
|
||||||
|
HTML_DIR="/home/taoc/uft30help/html/uft3changecode"
|
||||||
|
CONF_FILE="$CONF_DIR/nginx.conf"
|
||||||
|
|
||||||
|
echo "=== Starting Help Documentation Server (Port 6045) ==="
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
echo "1. Checking directories..."
|
||||||
|
if [ ! -d "$CONF_DIR" ]; then
|
||||||
|
mkdir -p "$CONF_DIR"
|
||||||
|
echo " Created config dir: $CONF_DIR"
|
||||||
|
else
|
||||||
|
echo " Config dir exists: $CONF_DIR"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -d "$HTML_DIR" ]; then
|
||||||
|
mkdir -p "$HTML_DIR"
|
||||||
|
echo " Created HTML dir: $HTML_DIR"
|
||||||
|
else
|
||||||
|
echo " HTML dir exists: $HTML_DIR"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "2. Killing all nginx processes..."
|
||||||
|
pkill -f nginx 2>/dev/null || true
|
||||||
|
sleep 2
|
||||||
|
pkill -9 nginx 2>/dev/null || true
|
||||||
|
sleep 1
|
||||||
|
echo " Done"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "3. Starting nginx..."
|
||||||
|
"$NGINX_BIN" -c "$CONF_FILE"
|
||||||
|
|
||||||
|
sleep 2
|
||||||
|
echo ""
|
||||||
|
echo "4. Testing..."
|
||||||
|
echo ""
|
||||||
|
echo "=== Server Status ==="
|
||||||
|
if pgrep nginx > /dev/null; then
|
||||||
|
SERVER_IP=$(ip addr show | grep inet | grep -v '127.0.0.1' | grep -v '::1' | head -1 | awk '{print $2}' | cut -d'/' -f1)
|
||||||
|
echo "✅ Server running!"
|
||||||
|
echo ""
|
||||||
|
echo "=== Access URLs ==="
|
||||||
|
echo " Local: http://localhost:6045/uft3changecode/"
|
||||||
|
if [ -n "$SERVER_IP" ]; then
|
||||||
|
echo " Remote: http://$SERVER_IP:6045/uft3changecode/"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "❌ Server not running"
|
||||||
|
echo "Error log:"
|
||||||
|
tail -20 /home/taoc/uft30help/workspace/logs/help_error.log
|
||||||
|
fi
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "Checking Help Documentation Server status..."
|
||||||
|
|
||||||
|
if pgrep nginx &> /dev/null; then
|
||||||
|
echo "✅ Help Documentation Server is running"
|
||||||
|
echo "📄 Access URL: http://localhost:8080"
|
||||||
|
else
|
||||||
|
echo "❌ Help Documentation Server is not running"
|
||||||
|
fi
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
NGINX_DIR="/home/taoc/nginx"
|
||||||
|
NGINX_BIN="$NGINX_DIR/sbin/nginx"
|
||||||
|
|
||||||
|
echo "Stopping Help Documentation Server..."
|
||||||
|
|
||||||
|
if [ ! -f "$NGINX_BIN" ]; then
|
||||||
|
echo "Error: nginx binary not found at $NGINX_BIN"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
"$NGINX_BIN" -s stop
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo "✅ Help Documentation Server stopped successfully"
|
||||||
|
else
|
||||||
|
echo "❌ Failed to stop nginx"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
10
main.cpp
|
|
@ -1,12 +1,20 @@
|
||||||
#include "src/mainwindow/mainwindow.h"
|
#include "src/mainwindow/mainwindow.h"
|
||||||
#include "ElaApplication.h"
|
#include "ElaApplication.h"
|
||||||
|
#include "src/utils/configmanager.h"
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
#include <QIcon>
|
||||||
|
#include <QCoreApplication>
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
QApplication a(argc, argv);
|
QApplication a(argc, argv);
|
||||||
|
a.setWindowIcon(QIcon(":resources/images/ChangeCode.png"));
|
||||||
eApp->init();
|
eApp->init();
|
||||||
|
|
||||||
|
QString basePath = QCoreApplication::applicationDirPath();
|
||||||
|
ConfigManager::instance()->loadConfig(basePath);
|
||||||
|
|
||||||
MainWindow w;
|
MainWindow w;
|
||||||
w.show();
|
w.showMaximized();
|
||||||
return a.exec();
|
return a.exec();
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,11 @@
|
||||||
<RCC>
|
<RCC>
|
||||||
<qresource prefix="/">
|
<qresource prefix="/">
|
||||||
|
<file>resources/images/ChangeCode.png</file>
|
||||||
|
<file>resources/images/bianji.png</file>
|
||||||
|
<file>resources/images/zhedie_left.png</file>
|
||||||
|
<file>resources/images/zhedie_right.png</file>
|
||||||
|
<file>resources/images/max.png</file>
|
||||||
|
<file>resources/images/min.png</file>
|
||||||
|
<file>resources/images/update.png</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
# 资源目录
|
||||||
|
|
||||||
|
此目录用于存放项目使用的图标、图片等资源文件。
|
||||||
|
|
||||||
|
## 目录结构
|
||||||
|
|
||||||
|
```
|
||||||
|
resources/
|
||||||
|
├── icons/ # 图标文件
|
||||||
|
└── images/ # 图片文件
|
||||||
|
```
|
||||||
|
|
||||||
|
## 添加新资源
|
||||||
|
|
||||||
|
1. 将资源文件放入对应目录
|
||||||
|
2. 更新 resources.qrc 文件添加资源引用
|
||||||
|
3. 重新编译项目
|
||||||
|
|
@ -0,0 +1,164 @@
|
||||||
|
# 使用帮助
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
欢迎使用 UFT30 Change Code 工具!这是一款强大的编码转换工具,支持批量转码和非LS格式转换。
|
||||||
|
|
||||||
|
### 功能导航
|
||||||
|
|
||||||
|
```
|
||||||
|
UFT30 Change Code
|
||||||
|
├── 📁 功能转码
|
||||||
|
│ └── 业务转码
|
||||||
|
├── 📁 功能查询
|
||||||
|
│ ├── UF20功能查询
|
||||||
|
│ └── UFT3功能查询
|
||||||
|
├── 元数据更新
|
||||||
|
├── 设置
|
||||||
|
├── 关于
|
||||||
|
└── 使用技巧
|
||||||
|
```
|
||||||
|
|
||||||
|
点击左侧导航栏的功能项,查看详细的使用说明。
|
||||||
|
|
||||||
|
## 功能转码
|
||||||
|
|
||||||
|
### 业务转码
|
||||||
|
|
||||||
|
将UF20函数转换为UFT3函数格式的核心功能。
|
||||||
|
|
||||||
|
#### 功能列表管理
|
||||||
|
|
||||||
|
- 点击"添加"按钮,输入函数名添加到转码列表
|
||||||
|
- 双击表格行可编辑函数名
|
||||||
|
- 选中行后点击"删除"移除函数
|
||||||
|
- 点击"清空"清空所有函数
|
||||||
|
|
||||||
|
#### 配置文件同步
|
||||||
|
|
||||||
|
- 自动读取 uf2touft3/cust.json 配置
|
||||||
|
- 配置文件外部修改时自动刷新列表
|
||||||
|
|
||||||
|
#### 转换操作
|
||||||
|
|
||||||
|
- 点击"开始转换"启动转换任务
|
||||||
|
- 转换过程中可查看进度条和状态信息
|
||||||
|
- 点击"停止转换"中止当前任务
|
||||||
|
|
||||||
|
## 功能查询
|
||||||
|
|
||||||
|
### UF20功能查询
|
||||||
|
|
||||||
|
查询UF20系统中的函数信息。
|
||||||
|
|
||||||
|
#### 查询条件
|
||||||
|
|
||||||
|
- 从下拉框选择查询字段:功能名称、英文名称、功能编号
|
||||||
|
- 输入框输入查询关键词
|
||||||
|
- 点击"Aa"切换精确/模糊匹配模式
|
||||||
|
- 点击放大镜图标或按回车执行查询
|
||||||
|
|
||||||
|
#### 结果操作
|
||||||
|
|
||||||
|
- 双击查询结果可直接添加到转码列表
|
||||||
|
- 结果表格显示:功能名称、英文名称、功能编号
|
||||||
|
|
||||||
|
### UFT3功能查询
|
||||||
|
|
||||||
|
查询UFT3系统中的函数信息。
|
||||||
|
|
||||||
|
#### 查询条件
|
||||||
|
|
||||||
|
- 从下拉框选择查询字段:功能名称、英文名称、功能编号
|
||||||
|
- 输入框输入查询关键词
|
||||||
|
- 点击"Aa"切换精确/模糊匹配模式
|
||||||
|
- 点击放大镜图标或按回车执行查询
|
||||||
|
|
||||||
|
#### 结果显示
|
||||||
|
|
||||||
|
- 结果表格显示:功能名称、英文名称、功能编号
|
||||||
|
|
||||||
|
## 元数据更新
|
||||||
|
|
||||||
|
更新UF20和UFT3系统的元数据配置。
|
||||||
|
|
||||||
|
### UF20配置更新
|
||||||
|
|
||||||
|
- 勾选需要更新的UF20接口项
|
||||||
|
- 点击"全选"选中所有UF20项
|
||||||
|
- 点击"取消"清除UF20选择
|
||||||
|
- 点击"更新UF20"执行更新
|
||||||
|
|
||||||
|
### UFT3配置更新
|
||||||
|
|
||||||
|
- 勾选需要更新的UFT3接口项
|
||||||
|
- 点击"全选"选中所有UFT3项
|
||||||
|
- 点击"取消"清除UFT3选择
|
||||||
|
- 点击"更新UFT3"执行更新
|
||||||
|
|
||||||
|
### 更新内容
|
||||||
|
|
||||||
|
- UF20: 接口、标准字段、数据类型、错误编号
|
||||||
|
- UFT3: 接口、标准字段、数据类型、表结构
|
||||||
|
|
||||||
|
## 设置
|
||||||
|
|
||||||
|
配置工具的运行参数和选项。
|
||||||
|
|
||||||
|
### 路径配置
|
||||||
|
|
||||||
|
- 设置Python脚本路径
|
||||||
|
- 配置转换工具路径
|
||||||
|
- 设置配置文件目录
|
||||||
|
|
||||||
|
### 显示设置
|
||||||
|
|
||||||
|
- 调整界面主题
|
||||||
|
- 设置字体大小
|
||||||
|
- 配置语言选项
|
||||||
|
|
||||||
|
### 高级设置
|
||||||
|
|
||||||
|
- 设置自动保存间隔
|
||||||
|
- 配置日志级别
|
||||||
|
- 设置最大并发任务数
|
||||||
|
|
||||||
|
## 关于
|
||||||
|
|
||||||
|
### UFT30 Change Code
|
||||||
|
|
||||||
|
一款强大的编码转换工具,支持批量转码和非LS格式转换。
|
||||||
|
|
||||||
|
#### 基本信息
|
||||||
|
|
||||||
|
- **版本**: 1.0.0
|
||||||
|
- **作者**: UFT30 Team
|
||||||
|
- **版权**: Copyright © 2024
|
||||||
|
- **联系方式**: support@uft30.com
|
||||||
|
|
||||||
|
#### 功能特性
|
||||||
|
|
||||||
|
- 支持UF20到UFT3函数格式转换
|
||||||
|
- 批量转换处理
|
||||||
|
- 非LS格式转换支持
|
||||||
|
- 功能查询与快速添加
|
||||||
|
- 元数据自动更新
|
||||||
|
|
||||||
|
## 使用技巧
|
||||||
|
|
||||||
|
### 高效使用技巧
|
||||||
|
|
||||||
|
- 在功能查询中找到需要转换的函数,双击可快速添加到转码列表
|
||||||
|
- 精确匹配适合已知完整函数名的查询
|
||||||
|
- 模糊匹配可以使用部分关键词查找
|
||||||
|
- 配置文件可以手动编辑,工具会自动检测变化
|
||||||
|
- 批量转换前建议先进行元数据更新
|
||||||
|
- 使用Ctrl+F快速搜索帮助内容
|
||||||
|
|
||||||
|
### 注意事项
|
||||||
|
|
||||||
|
- 首次使用前请先执行"元数据更新"加载最新配置
|
||||||
|
- 转换前建议备份重要文件
|
||||||
|
- 确保 uf2touft3/uf2touft3.exe 存在且可执行
|
||||||
|
- 配置文件 uf2touft3/cust.json 会自动同步转码列表
|
||||||
|
- 大文件转换可能需要较长时间,请耐心等待
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
# 💡 使用技巧
|
||||||
|
|
||||||
|
## 高效使用技巧
|
||||||
|
|
||||||
|
- 在功能查询中找到需要转换的函数,双击可快速添加到转码列表
|
||||||
|
- 精确匹配适合已知完整函数名的查询
|
||||||
|
- 模糊匹配可以使用部分关键词查找
|
||||||
|
- 配置文件可以手动编辑,工具会自动检测变化
|
||||||
|
- 批量转换前建议先进行元数据更新
|
||||||
|
- 使用Ctrl+F快速搜索帮助内容
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
|
||||||
|
- 首次使用前请先执行"元数据更新"加载最新配置
|
||||||
|
- 转换前建议备份重要文件
|
||||||
|
- 确保 uf2touft3/uf2touft3.exe 存在且可执行
|
||||||
|
- 配置文件 uf2touft3/cust.json 会自动同步转码列表
|
||||||
|
- 大文件转换可能需要较长时间,请耐心等待
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
# 此文件用于保持icons目录在Git仓库中
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
# 此文件用于保持images目录在Git仓库中
|
||||||
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 8.0 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 5.9 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 8.1 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 5.3 KiB |
|
|
@ -0,0 +1,116 @@
|
||||||
|
#include "elasearchedit.h"
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include "ElaIcon.h"
|
||||||
|
|
||||||
|
ElaSearchEdit::ElaSearchEdit(QWidget* parent)
|
||||||
|
: QWidget(parent), m_exactMatch(false)
|
||||||
|
{
|
||||||
|
initUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
ElaSearchEdit::~ElaSearchEdit()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ElaSearchEdit::initUI()
|
||||||
|
{
|
||||||
|
QHBoxLayout* mainLayout = new QHBoxLayout(this);
|
||||||
|
mainLayout->setSpacing(0);
|
||||||
|
mainLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
|
||||||
|
m_lineEdit = new ElaLineEdit(this);
|
||||||
|
m_lineEdit->setFixedHeight(35);
|
||||||
|
m_lineEdit->setPlaceholderText("输入查询内容");
|
||||||
|
m_lineEdit->setIsClearButtonEnable(false);
|
||||||
|
|
||||||
|
QHBoxLayout* inputLayout = new QHBoxLayout(m_lineEdit);
|
||||||
|
inputLayout->setContentsMargins(0, 0, 4, 0);
|
||||||
|
inputLayout->addStretch();
|
||||||
|
|
||||||
|
m_exactMatchBtn = addToolButton(m_lineEdit, ElaIconType::FontCase, "区分大小写", QSize(26, 26), true, false);
|
||||||
|
inputLayout->addWidget(m_exactMatchBtn);
|
||||||
|
|
||||||
|
resetInputMargin();
|
||||||
|
|
||||||
|
mainLayout->addWidget(m_lineEdit);
|
||||||
|
|
||||||
|
m_searchBtn = addToolButton(this, ElaIconType::MagnifyingGlass, "搜索", QSize(35, 35), false, false);
|
||||||
|
mainLayout->addWidget(m_searchBtn);
|
||||||
|
|
||||||
|
connectSignals();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ElaSearchEdit::connectSignals()
|
||||||
|
{
|
||||||
|
connect(m_lineEdit, &ElaLineEdit::textChanged, this, &ElaSearchEdit::textChanged);
|
||||||
|
connect(m_lineEdit, &ElaLineEdit::returnPressed, this, &ElaSearchEdit::returnPressed);
|
||||||
|
connect(m_searchBtn, &ElaToolButton::clicked, this, &ElaSearchEdit::searchClicked);
|
||||||
|
connect(m_exactMatchBtn, &ElaToolButton::clicked, this, [this](bool checked) {
|
||||||
|
m_exactMatch = checked;
|
||||||
|
emit exactMatchChanged(checked);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ElaSearchEdit::resetInputMargin()
|
||||||
|
{
|
||||||
|
m_lineEdit->setTextMargins(0, 0, 30, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
ElaToolButton* ElaSearchEdit::addToolButton(QWidget* parent, ElaIconType::IconName icon, const QString& tooltip, const QSize& size, bool checkable, bool checked)
|
||||||
|
{
|
||||||
|
ElaToolButton* btn = new ElaToolButton(parent);
|
||||||
|
btn->setElaIcon(icon);
|
||||||
|
btn->setFixedSize(size);
|
||||||
|
btn->setToolTip(tooltip);
|
||||||
|
btn->setCheckable(checkable);
|
||||||
|
btn->setChecked(checked);
|
||||||
|
btn->setCursor(Qt::PointingHandCursor);
|
||||||
|
return btn;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ElaSearchEdit::text() const
|
||||||
|
{
|
||||||
|
return m_lineEdit->text();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ElaSearchEdit::setText(const QString& text)
|
||||||
|
{
|
||||||
|
m_lineEdit->setText(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ElaSearchEdit::setPlaceholderText(const QString& placeholderText)
|
||||||
|
{
|
||||||
|
m_lineEdit->setPlaceholderText(placeholderText);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ElaSearchEdit::setFixedSize(const QSize& size)
|
||||||
|
{
|
||||||
|
m_lineEdit->setFixedSize(size.width() - 35, size.height());
|
||||||
|
m_searchBtn->setFixedSize(35, size.height());
|
||||||
|
QWidget::setFixedSize(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ElaSearchEdit::setFixedSize(int w, int h)
|
||||||
|
{
|
||||||
|
m_lineEdit->setFixedSize(w - 35, h);
|
||||||
|
m_searchBtn->setFixedSize(35, h);
|
||||||
|
QWidget::setFixedSize(w, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ElaSearchEdit::setFixedHeight(int h)
|
||||||
|
{
|
||||||
|
m_lineEdit->setFixedHeight(h);
|
||||||
|
m_searchBtn->setFixedSize(35, h);
|
||||||
|
QWidget::setFixedHeight(h);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ElaSearchEdit::isExactMatch() const
|
||||||
|
{
|
||||||
|
return m_exactMatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ElaSearchEdit::setExactMatch(bool exact)
|
||||||
|
{
|
||||||
|
m_exactMatch = exact;
|
||||||
|
m_exactMatchBtn->setChecked(exact);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
#ifndef ELASEARCHEDIT_H
|
||||||
|
#define ELASEARCHEDIT_H
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QList>
|
||||||
|
#include "ElaLineEdit.h"
|
||||||
|
#include "ElaToolButton.h"
|
||||||
|
|
||||||
|
class ElaSearchEdit : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ElaSearchEdit(QWidget* parent = nullptr);
|
||||||
|
~ElaSearchEdit() override;
|
||||||
|
|
||||||
|
QString text() const;
|
||||||
|
void setText(const QString& text);
|
||||||
|
void setPlaceholderText(const QString& placeholderText);
|
||||||
|
void setFixedSize(const QSize& size);
|
||||||
|
void setFixedSize(int w, int h);
|
||||||
|
void setFixedHeight(int h);
|
||||||
|
|
||||||
|
bool isExactMatch() const;
|
||||||
|
void setExactMatch(bool exact);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void textChanged(const QString& text);
|
||||||
|
void returnPressed();
|
||||||
|
void exactMatchChanged(bool exact);
|
||||||
|
void searchClicked();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void initUI();
|
||||||
|
void connectSignals();
|
||||||
|
void resetInputMargin();
|
||||||
|
ElaToolButton* addToolButton(QWidget* parent, ElaIconType::IconName icon, const QString& tooltip, const QSize& size, bool checkable = false, bool checked = false);
|
||||||
|
|
||||||
|
ElaLineEdit* m_lineEdit;
|
||||||
|
ElaToolButton* m_searchBtn;
|
||||||
|
ElaToolButton* m_exactMatchBtn;
|
||||||
|
bool m_exactMatch;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ELASEARCHEDIT_H
|
||||||
|
|
@ -0,0 +1,116 @@
|
||||||
|
#include "interdialog.h"
|
||||||
|
|
||||||
|
#include "ElaText.h"
|
||||||
|
#include "ElaPushButton.h"
|
||||||
|
|
||||||
|
#include <QSpacerItem>
|
||||||
|
|
||||||
|
InterDialog::InterDialog(QWidget* parent) : ElaDialog(parent)
|
||||||
|
{
|
||||||
|
this->setIsFixedSize(true);
|
||||||
|
this->setWindowModality(Qt::ApplicationModal);
|
||||||
|
this->setWindowButtonFlags(ElaAppBarType::CloseButtonHint);
|
||||||
|
this->setAppBarHeight(30);
|
||||||
|
|
||||||
|
_mainLayout = new QVBoxLayout(this);
|
||||||
|
_mainLayout->setContentsMargins(10, 10, 10, 10);
|
||||||
|
|
||||||
|
_centralWidget = new QWidget(this);
|
||||||
|
auto* centralVLayout = new QVBoxLayout(_centralWidget);
|
||||||
|
centralVLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
_messageLabel = new ElaText("这是消息", _centralWidget);
|
||||||
|
_messageLabel->setIsWrapAnywhere(true);
|
||||||
|
centralVLayout->addWidget(_messageLabel);
|
||||||
|
|
||||||
|
_buttonWidget = new QWidget(this);
|
||||||
|
_btnLayout = new QHBoxLayout(_buttonWidget);
|
||||||
|
_btnLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
_btnLayout->addItem(new QSpacerItem(5, 5, QSizePolicy::Policy::Expanding, QSizePolicy::Policy::Minimum));
|
||||||
|
|
||||||
|
auto *defaultButton = new QPushButton(_buttonWidget);
|
||||||
|
defaultButton->setDefault(true);
|
||||||
|
defaultButton->hide();
|
||||||
|
|
||||||
|
_okButton = new ElaPushButton("确认", _buttonWidget);
|
||||||
|
connect(_okButton, &ElaPushButton::clicked, this, [=]
|
||||||
|
{
|
||||||
|
emit okButtonClicked();
|
||||||
|
accept();
|
||||||
|
});
|
||||||
|
_okButton->setLightDefaultColor(ElaThemeColor(ElaThemeType::Light, PrimaryNormal));
|
||||||
|
_okButton->setLightHoverColor(ElaThemeColor(ElaThemeType::Light, PrimaryHover));
|
||||||
|
_okButton->setLightPressColor(ElaThemeColor(ElaThemeType::Light, PrimaryPress));
|
||||||
|
_okButton->setLightTextColor(ElaThemeColor(ElaThemeType::Dark, BasicText));
|
||||||
|
_okButton->setDarkDefaultColor(ElaThemeColor(ElaThemeType::Dark, PrimaryNormal));
|
||||||
|
_okButton->setDarkHoverColor(ElaThemeColor(ElaThemeType::Dark, PrimaryHover));
|
||||||
|
_okButton->setDarkPressColor(ElaThemeColor(ElaThemeType::Dark, PrimaryPress));
|
||||||
|
_okButton->setDarkTextColor(ElaThemeColor(ElaThemeType::Light, BasicText));
|
||||||
|
_okButton->setMinimumSize(0, 0);
|
||||||
|
_okButton->setMaximumSize(QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX));
|
||||||
|
_okButton->setFixedHeight(38);
|
||||||
|
_btnLayout->addWidget(_okButton);
|
||||||
|
|
||||||
|
_cancelButton = new ElaPushButton("取消", _buttonWidget);
|
||||||
|
connect(_cancelButton, &ElaPushButton::clicked, this, [=]
|
||||||
|
{
|
||||||
|
emit cancelButtonClicked();
|
||||||
|
reject();
|
||||||
|
});
|
||||||
|
_cancelButton->setMinimumSize(0, 0);
|
||||||
|
_cancelButton->setMaximumSize(QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX));
|
||||||
|
_cancelButton->setFixedHeight(38);
|
||||||
|
_btnLayout->addWidget(_cancelButton);
|
||||||
|
|
||||||
|
_mainLayout->addWidget(_centralWidget);
|
||||||
|
_mainLayout->addWidget(_buttonWidget);
|
||||||
|
|
||||||
|
setFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
InterDialog::~InterDialog() = default;
|
||||||
|
|
||||||
|
void InterDialog::setMessage(const QString& message)
|
||||||
|
{
|
||||||
|
if (_messageLabel)
|
||||||
|
{
|
||||||
|
_messageLabel->setText(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void InterDialog::setCentralWidget(QWidget* centralWidget)
|
||||||
|
{
|
||||||
|
_mainLayout->removeWidget(_centralWidget);
|
||||||
|
delete _messageLabel;
|
||||||
|
_messageLabel = nullptr;
|
||||||
|
delete _centralWidget;
|
||||||
|
_centralWidget = centralWidget;
|
||||||
|
QSizePolicy sizePolicy(QSizePolicy::Policy::Preferred, QSizePolicy::Policy::Expanding);
|
||||||
|
sizePolicy.setHorizontalStretch(0);
|
||||||
|
sizePolicy.setVerticalStretch(0);
|
||||||
|
sizePolicy.setHeightForWidth(centralWidget->sizePolicy().hasHeightForWidth());
|
||||||
|
centralWidget->setSizePolicy(sizePolicy);
|
||||||
|
_mainLayout->insertWidget(0, _centralWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InterDialog::setStandardButtons(const QDialogButtonBox::StandardButtons buttons) const
|
||||||
|
{
|
||||||
|
if (buttons.testFlag(QDialogButtonBox::NoButton))
|
||||||
|
{
|
||||||
|
_buttonWidget->setVisible(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_okButton->setVisible(buttons.testFlag(QDialogButtonBox::StandardButton::Ok));
|
||||||
|
_cancelButton->setVisible(buttons.testFlag(QDialogButtonBox::StandardButton::Cancel));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void InterDialog::addFirstButton(QPushButton* button) const
|
||||||
|
{
|
||||||
|
_btnLayout->insertWidget(1, button);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InterDialog::addLastButton(QPushButton* button) const
|
||||||
|
{
|
||||||
|
_btnLayout->addWidget(button);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
#ifndef METASEARCH_INTERDIALOG_H
|
||||||
|
#define METASEARCH_INTERDIALOG_H
|
||||||
|
|
||||||
|
#include "ElaDialog.h"
|
||||||
|
#include "ElaTheme.h"
|
||||||
|
#include "ElaText.h"
|
||||||
|
#include "ElaPushButton.h"
|
||||||
|
|
||||||
|
#include <QDialogButtonBox>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 带按钮栏的弹窗
|
||||||
|
*/
|
||||||
|
class InterDialog : public ElaDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit InterDialog(QWidget* parent = nullptr);
|
||||||
|
~InterDialog() override;
|
||||||
|
|
||||||
|
// 设置消息
|
||||||
|
virtual void setMessage(const QString& message);
|
||||||
|
|
||||||
|
// 设置中心区域
|
||||||
|
void setCentralWidget(QWidget* centralWidget);
|
||||||
|
|
||||||
|
// 设置按钮
|
||||||
|
void setStandardButtons(QDialogButtonBox::StandardButtons buttons) const;
|
||||||
|
|
||||||
|
// 头部添加按钮
|
||||||
|
void addFirstButton(QPushButton* button) const;
|
||||||
|
|
||||||
|
// 尾部添加按钮
|
||||||
|
void addLastButton(QPushButton* button) const;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void okButtonClicked();
|
||||||
|
void cancelButtonClicked();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// 主题
|
||||||
|
ElaThemeType::ThemeMode _themeMode;
|
||||||
|
|
||||||
|
// 主布局
|
||||||
|
QVBoxLayout* _mainLayout{nullptr};
|
||||||
|
|
||||||
|
// 中心区域
|
||||||
|
QWidget* _centralWidget{nullptr};
|
||||||
|
// 中心区域文本
|
||||||
|
ElaText* _messageLabel{nullptr};
|
||||||
|
|
||||||
|
// 按钮区域
|
||||||
|
QWidget* _buttonWidget{nullptr};
|
||||||
|
// 按钮区域布局
|
||||||
|
QHBoxLayout* _btnLayout{nullptr};
|
||||||
|
// 确认按钮
|
||||||
|
ElaPushButton* _okButton{nullptr};
|
||||||
|
// 取消按钮
|
||||||
|
ElaPushButton* _cancelButton{nullptr};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //METASEARCH_INTERDIALOG_H
|
||||||
|
|
@ -2,6 +2,10 @@
|
||||||
#include "ElaIcon.h"
|
#include "ElaIcon.h"
|
||||||
#include "ElaText.h"
|
#include "ElaText.h"
|
||||||
#include "ElaTheme.h"
|
#include "ElaTheme.h"
|
||||||
|
#include "ElaToolButton.h"
|
||||||
|
#include "utils/uf2configreader.h"
|
||||||
|
#include "utils/uft3configreader.h"
|
||||||
|
#include "utils/logmanager.h"
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
|
|
@ -16,42 +20,82 @@
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QDesktopServices>
|
||||||
|
#include <QUrl>
|
||||||
|
|
||||||
MainWindow::MainWindow(QWidget *parent)
|
MainWindow::MainWindow(QWidget *parent)
|
||||||
: ElaWindow(parent)
|
: ElaWindow(parent)
|
||||||
, m_pythonRunner(new PythonRunner(this))
|
, m_pythonRunner(new PythonRunner(this))
|
||||||
|
, m_iconsSet(false)
|
||||||
|
, m_navigationButton(nullptr)
|
||||||
|
, m_isNavigationExpanded(true)
|
||||||
{
|
{
|
||||||
initWindow();
|
initWindow();
|
||||||
initContent();
|
initContent();
|
||||||
|
|
||||||
// 获取应用程序目录
|
LogManager::instance()->initLogFile();
|
||||||
|
LogManager::instance()->logInfo("应用程序启动");
|
||||||
|
|
||||||
QString appDir = QCoreApplication::applicationDirPath();
|
QString appDir = QCoreApplication::applicationDirPath();
|
||||||
|
|
||||||
// 配置 Python 运行器 - 只使用打包好的 exe,路径是 uf2touft3/uf2touft3.exe
|
loadConfigCache();
|
||||||
|
|
||||||
m_pythonRunner->setRunMode(PythonRunner::UsePackagedExe);
|
m_pythonRunner->setRunMode(PythonRunner::UsePackagedExe);
|
||||||
|
|
||||||
// 设置打包好的可执行文件路径和工作目录
|
|
||||||
QString exePath = appDir + "/uf2touft3/uf2touft3.exe";
|
QString exePath = appDir + "/uf2touft3/uf2touft3.exe";
|
||||||
QString workDir = appDir + "/uf2touft3";
|
QString workDir = appDir + "/uf2touft3";
|
||||||
|
|
||||||
m_pythonRunner->setPackagedExePath(exePath);
|
m_pythonRunner->setPackagedExePath(exePath);
|
||||||
m_pythonRunner->setWorkingDirectory(workDir);
|
m_pythonRunner->setWorkingDirectory(workDir);
|
||||||
|
|
||||||
// 检查 exe 是否存在
|
|
||||||
QFileInfo exeInfo(exePath);
|
QFileInfo exeInfo(exePath);
|
||||||
if (!exeInfo.exists() || !exeInfo.isFile()) {
|
if (!exeInfo.exists() || !exeInfo.isFile()) {
|
||||||
m_batchLogEdit->append("⚠️ 警告:未找到 uf2touft3/uf2touft3.exe!");
|
LogManager::instance()->logError(QString("未找到转换工具: %1").arg(exePath));
|
||||||
m_batchLogEdit->append(QString(" 期望位置:%1").arg(exePath));
|
|
||||||
} else {
|
|
||||||
m_batchLogEdit->append("✓ Python 工具准备就绪");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
connect(m_pythonRunner, &PythonRunner::finished, this, &MainWindow::onPythonRunnerFinished);
|
connect(m_pythonRunner, &PythonRunner::finished, this, &MainWindow::onPythonRunnerFinished);
|
||||||
connect(m_pythonRunner, &PythonRunner::standardOutput, this, &MainWindow::onPythonRunnerOutput);
|
connect(m_pythonRunner, &PythonRunner::standardOutput, this, &MainWindow::onPythonRunnerOutput);
|
||||||
connect(m_pythonRunner, &PythonRunner::standardError, this, &MainWindow::onPythonRunnerError);
|
connect(m_pythonRunner, &PythonRunner::standardError, this, &MainWindow::onPythonRunnerError);
|
||||||
connect(m_pythonRunner, &PythonRunner::started, [this]() {
|
|
||||||
m_batchLogEdit->append("转换任务已启动...");
|
connect(this, &ElaWindow::navigationNodeClicked, this, &MainWindow::onNavigationNodeClicked);
|
||||||
});
|
|
||||||
|
QTimer::singleShot(100, this, &MainWindow::updateNavigationButtonIcon);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::loadConfigCache()
|
||||||
|
{
|
||||||
|
LogManager::instance()->log("正在加载配置缓存...");
|
||||||
|
|
||||||
|
UF2ConfigReader uf2Reader;
|
||||||
|
bool uf2Loaded = uf2Reader.loadAllUF20Config();
|
||||||
|
|
||||||
|
UFT3ConfigReader uft3Reader;
|
||||||
|
bool uft3Loaded = uft3Reader.loadAllUFT3Config();
|
||||||
|
|
||||||
|
if (uf2Loaded && uft3Loaded) {
|
||||||
|
LogManager::instance()->log("✓ 配置缓存加载完成");
|
||||||
|
} else {
|
||||||
|
LogManager::instance()->logWarning("⚠️ 部分配置加载失败");
|
||||||
|
|
||||||
|
QStringList uf2Failed = uf2Reader.getFailedFiles();
|
||||||
|
QStringList uft3Failed = uft3Reader.getFailedFiles();
|
||||||
|
|
||||||
|
if (!uf2Failed.isEmpty()) {
|
||||||
|
LogManager::instance()->log(" UF20 加载失败:");
|
||||||
|
foreach (const QString& file, uf2Failed) {
|
||||||
|
LogManager::instance()->log(QString(" - %1").arg(file));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!uft3Failed.isEmpty()) {
|
||||||
|
LogManager::instance()->log(" UFT3 加载失败:");
|
||||||
|
foreach (const QString& file, uft3Failed) {
|
||||||
|
LogManager::instance()->log(QString(" - %1").arg(file));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MainWindow::~MainWindow()
|
MainWindow::~MainWindow()
|
||||||
|
|
@ -60,36 +104,41 @@ MainWindow::~MainWindow()
|
||||||
|
|
||||||
void MainWindow::initWindow()
|
void MainWindow::initWindow()
|
||||||
{
|
{
|
||||||
setWindowTitle("UFT30 Change Code");
|
setWindowTitle(QString("UFT30 Change Code %1").arg(Version::getVersionString()));
|
||||||
setWindowIcon(QIcon(":/Resource/Image/Cirno.jpg"));
|
setWindowIcon(QIcon(":/resources/images/ChangeCode.png"));
|
||||||
resize(900, 600);
|
resize(900, 600);
|
||||||
setUserInfoCardTitle("UFT30");
|
setMinimumSize(800, 500);
|
||||||
setUserInfoCardSubTitle("Change Code Tool");
|
setUserInfoCardVisible(false);
|
||||||
|
|
||||||
|
// 隐藏返回和前进按钮
|
||||||
|
|
||||||
|
setWindowButtonFlag(ElaAppBarType::RouteBackButtonHint, false);
|
||||||
|
setWindowButtonFlag(ElaAppBarType::RouteForwardButtonHint, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::initContent()
|
void MainWindow::initContent()
|
||||||
{
|
{
|
||||||
QString helpKey;
|
addExpanderNode("功能转码", m_funcConvertKey, ElaIconType::FileCode);
|
||||||
QString aboutKey;
|
addPageNode("业务转码", createBatchConvertPage(), m_funcConvertKey, ElaIconType::ArrowsRepeat);
|
||||||
QString settingKey;
|
|
||||||
addPageNode("转码业务", createBatchConvertPage(), ElaIconType::FileCode);
|
addExpanderNode("功能查询", m_funcSearchKey, ElaIconType::MagnifyingGlass);
|
||||||
addPageNode("功能搜索", createFunctionSearchPage(), ElaIconType::MagnifyingGlass);
|
addPageNode("UF20功能查询", createUF20FunctionSearchPage(), m_funcSearchKey, ElaIconType::MagnifyingGlassPlus);
|
||||||
addFooterNode("帮助", createHelpPage(), helpKey, 0, ElaIconType::CircleQuestion);
|
addPageNode("UFT3功能查询", createUFT3FunctionSearchPage(), m_funcSearchKey, ElaIconType::MagnifyingGlassPlus);
|
||||||
addFooterNode("关于", createAboutPage(), aboutKey, 0, ElaIconType::User);
|
expandNavigationNode(m_funcConvertKey);
|
||||||
addFooterNode("设置", createSettingsPage(), settingKey, 0, ElaIconType::GearComplex);
|
|
||||||
|
addPageNode("元数据更新", createMetadataUpdatePage(), ElaIconType::ArrowsRotate);
|
||||||
|
|
||||||
|
addFooterNode("帮助", m_helpKey, 0, ElaIconType::CircleQuestion);
|
||||||
|
addFooterNode("关于", m_aboutKey, 0, ElaIconType::Info);
|
||||||
|
addFooterNode("设置", createSettingsPage(), m_settingKey, 0, ElaIconType::GearComplex);
|
||||||
}
|
}
|
||||||
|
|
||||||
QWidget* MainWindow::createBatchConvertPage()
|
QWidget* MainWindow::createBatchConvertPage()
|
||||||
{
|
{
|
||||||
BatchConvertPage *page = new BatchConvertPage;
|
m_batchConvertPage = new BatchConvertPage;
|
||||||
m_batchLogEdit = page->getLogEdit();
|
connect(m_batchConvertPage, &BatchConvertPage::startConvert, this, &MainWindow::onBatchConvertStart);
|
||||||
connect(page, &BatchConvertPage::startConvert, this, &MainWindow::onBatchConvertStart);
|
connect(m_batchConvertPage, &BatchConvertPage::stopConvert, this, &MainWindow::onBatchConvertStop);
|
||||||
connect(m_pythonRunner, &PythonRunner::started, [this]() {
|
return m_batchConvertPage;
|
||||||
if (m_batchLogEdit) {
|
|
||||||
m_batchLogEdit->append("转换任务已启动...");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return page;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QWidget* MainWindow::createFunctionSearchPage()
|
QWidget* MainWindow::createFunctionSearchPage()
|
||||||
|
|
@ -97,14 +146,17 @@ QWidget* MainWindow::createFunctionSearchPage()
|
||||||
return new FunctionSearchPage;
|
return new FunctionSearchPage;
|
||||||
}
|
}
|
||||||
|
|
||||||
QWidget* MainWindow::createHelpPage()
|
QWidget* MainWindow::createUF20FunctionSearchPage()
|
||||||
{
|
{
|
||||||
return new HelpPage;
|
UF20FunctionSearchPage *page = new UF20FunctionSearchPage;
|
||||||
|
connect(page, &UF20FunctionSearchPage::addFunctionToConvert,
|
||||||
|
m_batchConvertPage, &BatchConvertPage::addFunction);
|
||||||
|
return page;
|
||||||
}
|
}
|
||||||
|
|
||||||
QWidget* MainWindow::createAboutPage()
|
QWidget* MainWindow::createUFT3FunctionSearchPage()
|
||||||
{
|
{
|
||||||
return new AboutPage;
|
return new UFT3FunctionSearchPage;
|
||||||
}
|
}
|
||||||
|
|
||||||
QWidget* MainWindow::createSettingsPage()
|
QWidget* MainWindow::createSettingsPage()
|
||||||
|
|
@ -112,10 +164,15 @@ QWidget* MainWindow::createSettingsPage()
|
||||||
return new SettingsPage();
|
return new SettingsPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QWidget* MainWindow::createMetadataUpdatePage()
|
||||||
|
{
|
||||||
|
return new MetadataUpdatePage();
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::onBatchConvertStart()
|
void MainWindow::onBatchConvertStart()
|
||||||
{
|
{
|
||||||
if (m_pythonRunner->isRunning()) {
|
if (m_pythonRunner->isRunning()) {
|
||||||
m_batchLogEdit->append("警告: 上一个任务还在运行中...");
|
LogManager::instance()->logWarning("警告: 上一个任务还在运行中...");
|
||||||
QMessageBox::warning(this, "提示", "上一个转换任务正在运行,请等待完成或停止当前任务。");
|
QMessageBox::warning(this, "提示", "上一个转换任务正在运行,请等待完成或停止当前任务。");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -124,46 +181,213 @@ void MainWindow::onBatchConvertStart()
|
||||||
QString exePath = appDir + "/uf2touft3/uf2touft3.exe";
|
QString exePath = appDir + "/uf2touft3/uf2touft3.exe";
|
||||||
|
|
||||||
if (!m_pythonRunner->canRun()) {
|
if (!m_pythonRunner->canRun()) {
|
||||||
m_batchLogEdit->append("错误: 找不到 uf2touft3/uf2touft3.exe!");
|
LogManager::instance()->logError("错误: 找不到 uf2touft3/uf2touft3.exe!");
|
||||||
QMessageBox::critical(this, "错误",
|
QMessageBox::critical(this, "错误",
|
||||||
QString("无法启动转换任务!\n\n请确保:\nuf2touft3/uf2touft3.exe 存在,且该目录下包含 config.ini\n\n期望路径:\n%1")
|
QString("无法启动转换任务!\n\n请确保:\nuf2touft3/uf2touft3.exe 存在,且该目录下包含 config.ini\n\n期望路径:\n%1")
|
||||||
.arg(exePath));
|
.arg(exePath));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_batchLogEdit->append("========================================");
|
if (m_batchConvertPage) {
|
||||||
m_batchLogEdit->append("开始执行 UFT2 到 UFT3 的代码转换...");
|
m_totalFunctions = m_batchConvertPage->getFunctionCount();
|
||||||
m_batchLogEdit->append(QString("工具路径: %1").arg(exePath));
|
m_functionList = m_batchConvertPage->getFunctionList();
|
||||||
m_batchLogEdit->append("========================================");
|
m_currentFunctionIndex = 0;
|
||||||
|
} else {
|
||||||
|
m_totalFunctions = 0;
|
||||||
|
m_currentFunctionIndex = 0;
|
||||||
|
m_functionList.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
LogManager::instance()->log("========================================");
|
||||||
|
LogManager::instance()->log("开始执行 UFT2 到 UFT3 的代码转换...");
|
||||||
|
LogManager::instance()->log(QString("工具路径: %1").arg(exePath));
|
||||||
|
LogManager::instance()->log(QString("待转换函数数量: %1").arg(m_totalFunctions));
|
||||||
|
LogManager::instance()->log("========================================");
|
||||||
|
|
||||||
if (!m_pythonRunner->start()) {
|
if (!m_pythonRunner->start()) {
|
||||||
m_batchLogEdit->append("错误: 无法启动转换进程!");
|
LogManager::instance()->logError("错误: 无法启动转换进程!");
|
||||||
|
} else {
|
||||||
|
if (m_batchConvertPage) {
|
||||||
|
m_batchConvertPage->onConvertStarted();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::onBatchConvertStop()
|
||||||
|
{
|
||||||
|
if (m_pythonRunner->isRunning()) {
|
||||||
|
LogManager::instance()->log("正在停止转换进程...");
|
||||||
|
m_pythonRunner->stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::onPythonRunnerFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
void MainWindow::onPythonRunnerFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
||||||
{
|
{
|
||||||
m_batchLogEdit->append("========================================");
|
if (m_batchConvertPage) {
|
||||||
|
m_batchConvertPage->onConvertFinished();
|
||||||
|
}
|
||||||
|
|
||||||
|
LogManager::instance()->log("========================================");
|
||||||
if (exitStatus == QProcess::NormalExit && exitCode == 0) {
|
if (exitStatus == QProcess::NormalExit && exitCode == 0) {
|
||||||
m_batchLogEdit->append("✓ 代码转换完成!");
|
LogManager::instance()->log("✓ 代码转换完成!");
|
||||||
QMessageBox::information(this, "完成", "代码转换任务已成功完成!");
|
QMessageBox::information(this, "完成", "代码转换任务已成功完成!");
|
||||||
} else {
|
} else {
|
||||||
m_batchLogEdit->append(QString("✗ 转换失败! 退出码: %1").arg(exitCode));
|
LogManager::instance()->logError(QString("✗ 转换失败! 退出码: %1").arg(exitCode));
|
||||||
QMessageBox::warning(this, "失败", QString("代码转换任务失败,退出码: %1").arg(exitCode));
|
QMessageBox::warning(this, "失败", QString("代码转换任务失败,退出码: %1").arg(exitCode));
|
||||||
}
|
}
|
||||||
m_batchLogEdit->append("========================================");
|
LogManager::instance()->log("========================================");
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::onPythonRunnerOutput(const QString &output)
|
void MainWindow::onPythonRunnerOutput(const QString &output)
|
||||||
{
|
{
|
||||||
if (!output.trimmed().isEmpty()) {
|
if (!output.trimmed().isEmpty()) {
|
||||||
m_batchLogEdit->append(output);
|
LogManager::instance()->log(output);
|
||||||
|
|
||||||
|
QString trimmedOutput = output.trimmed();
|
||||||
|
|
||||||
|
QRegularExpression progressRegExp(R"(progress\s*[:=]\s*(\d+))");
|
||||||
|
QRegularExpressionMatch match = progressRegExp.match(trimmedOutput);
|
||||||
|
if (match.hasMatch()) {
|
||||||
|
int progress = match.captured(1).toInt();
|
||||||
|
QString status = trimmedOutput;
|
||||||
|
if (status.contains("progress", Qt::CaseInsensitive)) {
|
||||||
|
status = status.replace(progressRegExp, "").trimmed();
|
||||||
|
if (status.isEmpty()) {
|
||||||
|
status = QString("转换中 %1%").arg(progress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (m_batchConvertPage) {
|
||||||
|
m_batchConvertPage->onProgressUpdate(progress, status);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (m_batchConvertPage) {
|
||||||
|
QString currentFunction;
|
||||||
|
QRegularExpression funcRegExp(R"(([\w_]+))");
|
||||||
|
QRegularExpressionMatch funcMatch = funcRegExp.match(trimmedOutput);
|
||||||
|
if (funcMatch.hasMatch()) {
|
||||||
|
currentFunction = funcMatch.captured(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!currentFunction.isEmpty() && m_totalFunctions > 0) {
|
||||||
|
int index = m_functionList.indexOf(currentFunction);
|
||||||
|
if (index >= 0 && index >= m_currentFunctionIndex) {
|
||||||
|
m_currentFunctionIndex = index + 1;
|
||||||
|
int progress = 20 + (m_currentFunctionIndex * 80) / m_totalFunctions;
|
||||||
|
QString status = QString("正在转换: %1").arg(currentFunction);
|
||||||
|
m_batchConvertPage->onProgressUpdate(progress, status);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int currentProgress = 20;
|
||||||
|
if (trimmedOutput.contains("开始转换", Qt::CaseInsensitive)) {
|
||||||
|
currentProgress = 25;
|
||||||
|
} else if (trimmedOutput.contains("处理文件", Qt::CaseInsensitive)) {
|
||||||
|
currentProgress = 30;
|
||||||
|
} else if (trimmedOutput.contains("生成代码", Qt::CaseInsensitive)) {
|
||||||
|
currentProgress = 75;
|
||||||
|
} else if (trimmedOutput.contains("完成", Qt::CaseInsensitive)) {
|
||||||
|
currentProgress = 95;
|
||||||
|
}
|
||||||
|
m_batchConvertPage->onProgressUpdate(currentProgress, trimmedOutput);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::onPythonRunnerError(const QString &error)
|
void MainWindow::onPythonRunnerError(const QString &error)
|
||||||
{
|
{
|
||||||
if (!error.trimmed().isEmpty()) {
|
if (!error.trimmed().isEmpty()) {
|
||||||
m_batchLogEdit->append(QString("[ERROR] %1").arg(error));
|
LogManager::instance()->logError(QString("[ERROR] %1").arg(error));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::updateNavigationButtonIcon()
|
||||||
|
{
|
||||||
|
// 使用资源文件中的图标
|
||||||
|
QIcon leftIcon(":/resources/images/zhedie_left.png");
|
||||||
|
|
||||||
|
if (leftIcon.isNull()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查找所有 ElaToolButton
|
||||||
|
QList<ElaToolButton*> allButtons = this->findChildren<ElaToolButton*>(QString(), Qt::FindChildrenRecursively);
|
||||||
|
|
||||||
|
// 尝试查找导航按钮 - 可能在不同位置
|
||||||
|
for (int i = 0; i < allButtons.size(); i++) {
|
||||||
|
ElaToolButton* btn = allButtons[i];
|
||||||
|
QString objName = btn->objectName();
|
||||||
|
|
||||||
|
// 检查是否是导航按钮(可能的名称)
|
||||||
|
if (objName.contains("Nav", Qt::CaseInsensitive) ||
|
||||||
|
objName.contains("Menu", Qt::CaseInsensitive) ||
|
||||||
|
objName.contains("Navigation", Qt::CaseInsensitive)) {
|
||||||
|
m_navigationButton = btn;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果没有找到有名称的导航按钮,使用第一个可见按钮
|
||||||
|
if (!m_navigationButton) {
|
||||||
|
for (ElaToolButton* btn : allButtons) {
|
||||||
|
if (btn->isVisible()) {
|
||||||
|
m_navigationButton = btn;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_navigationButton) {
|
||||||
|
m_navigationButton->setProperty("ElaIconType", "");
|
||||||
|
m_navigationButton->setIcon(leftIcon);
|
||||||
|
m_navigationButton->setIconSize(QSize(24, 24));
|
||||||
|
m_navigationButton->update();
|
||||||
|
|
||||||
|
// 先断开可能存在的连接,然后重新连接,避免多次连接
|
||||||
|
disconnect(m_navigationButton, &ElaToolButton::clicked, this, &MainWindow::onNavigationButtonClicked);
|
||||||
|
connect(m_navigationButton, &ElaToolButton::clicked, this, &MainWindow::onNavigationButtonClicked);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
|
||||||
|
{
|
||||||
|
if (!m_iconsSet && event->type() == QEvent::Show) {
|
||||||
|
// 窗口显示后尝试设置图标
|
||||||
|
updateNavigationButtonIcon();
|
||||||
|
m_iconsSet = true;
|
||||||
|
}
|
||||||
|
return ElaWindow::eventFilter(obj, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::onNavigationButtonClicked()
|
||||||
|
{
|
||||||
|
if (!m_navigationButton) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QIcon leftIcon(":/resources/images/zhedie_left.png");
|
||||||
|
QIcon rightIcon(":/resources/images/zhedie_right.png");
|
||||||
|
|
||||||
|
// 使用状态变量来判断当前状态,而不是依赖 cacheKey
|
||||||
|
if (m_isNavigationExpanded) {
|
||||||
|
// 当前是展开状态,切换到折叠状态
|
||||||
|
m_navigationButton->setIcon(rightIcon);
|
||||||
|
m_isNavigationExpanded = false;
|
||||||
|
} else {
|
||||||
|
// 当前是折叠状态,切换到展开状态
|
||||||
|
m_navigationButton->setIcon(leftIcon);
|
||||||
|
m_isNavigationExpanded = true;
|
||||||
|
}
|
||||||
|
m_navigationButton->update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::onNavigationNodeClicked(ElaNavigationType::NavigationNodeType nodeType, QString nodeKey)
|
||||||
|
{
|
||||||
|
Q_UNUSED(nodeType);
|
||||||
|
if (nodeKey == m_helpKey) {
|
||||||
|
QDesktopServices::openUrl(QUrl("http://10.20.163.105:6045/uft3changecode"));
|
||||||
|
} else if (nodeKey == m_aboutKey) {
|
||||||
|
std::make_unique<AboutDialog>(this)->exec();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,18 @@
|
||||||
#define MAINWINDOW_H
|
#define MAINWINDOW_H
|
||||||
|
|
||||||
#include "ElaWindow.h"
|
#include "ElaWindow.h"
|
||||||
|
#include "ElaToolButton.h"
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <QTextEdit>
|
|
||||||
#include "src/pythonrunner/PythonRunner.h"
|
#include "src/pythonrunner/PythonRunner.h"
|
||||||
#include "src/pages/batchconvert/batchconvertpage.h"
|
#include "src/pages/batchconvert/batchconvertpage.h"
|
||||||
#include "src/pages/functionsearch/functionsearchpage.h"
|
#include "src/pages/functionsearch/functionsearchpage.h"
|
||||||
#include "src/pages/help/helppage.h"
|
#include "src/pages/functionsearch/uf20functionsearchpage.h"
|
||||||
#include "src/pages/about/aboutpage.h"
|
#include "src/pages/functionsearch/uft3functionsearchpage.h"
|
||||||
|
|
||||||
|
#include "src/pages/about/aboutdialog.h"
|
||||||
#include "src/pages/settings/settingspage.h"
|
#include "src/pages/settings/settingspage.h"
|
||||||
|
#include "src/pages/metadatupdate/metadatupdatepage.h"
|
||||||
|
#include "src/utils/version.h"
|
||||||
|
|
||||||
class MainWindow : public ElaWindow
|
class MainWindow : public ElaWindow
|
||||||
{
|
{
|
||||||
|
|
@ -25,17 +29,38 @@ private:
|
||||||
|
|
||||||
QWidget* createBatchConvertPage();
|
QWidget* createBatchConvertPage();
|
||||||
QWidget* createFunctionSearchPage();
|
QWidget* createFunctionSearchPage();
|
||||||
QWidget* createHelpPage();
|
QWidget* createUF20FunctionSearchPage();
|
||||||
QWidget* createAboutPage();
|
QWidget* createUFT3FunctionSearchPage();
|
||||||
QWidget* createSettingsPage();
|
QWidget* createSettingsPage();
|
||||||
|
QWidget* createMetadataUpdatePage();
|
||||||
|
|
||||||
|
void loadConfigCache();
|
||||||
|
|
||||||
void onBatchConvertStart();
|
void onBatchConvertStart();
|
||||||
|
void onBatchConvertStop();
|
||||||
void onPythonRunnerFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
void onPythonRunnerFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||||
void onPythonRunnerOutput(const QString &output);
|
void onPythonRunnerOutput(const QString &output);
|
||||||
void onPythonRunnerError(const QString &error);
|
void onPythonRunnerError(const QString &error);
|
||||||
|
|
||||||
|
void updateNavigationButtonIcon();
|
||||||
|
bool eventFilter(QObject *obj, QEvent *event) override;
|
||||||
|
void onNavigationButtonClicked();
|
||||||
|
void onNavigationNodeClicked(ElaNavigationType::NavigationNodeType nodeType, QString nodeKey);
|
||||||
|
|
||||||
PythonRunner *m_pythonRunner;
|
PythonRunner *m_pythonRunner;
|
||||||
QTextEdit *m_batchLogEdit;
|
bool m_iconsSet;
|
||||||
|
ElaToolButton* m_navigationButton;
|
||||||
|
bool m_isNavigationExpanded;
|
||||||
|
BatchConvertPage *m_batchConvertPage;
|
||||||
|
|
||||||
|
int m_totalFunctions;
|
||||||
|
int m_currentFunctionIndex;
|
||||||
|
QStringList m_functionList;
|
||||||
|
QString m_helpKey;
|
||||||
|
QString m_aboutKey;
|
||||||
|
QString m_settingKey;
|
||||||
|
QString m_funcSearchKey;
|
||||||
|
QString m_funcConvertKey;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MAINWINDOW_H
|
#endif // MAINWINDOW_H
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
#include "filedb.h"
|
||||||
|
|
||||||
|
FileDB* FileDB::m_instance = nullptr;
|
||||||
|
|
||||||
|
FileDB::FileDB(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
FileDB* FileDB::instance()
|
||||||
|
{
|
||||||
|
if (!m_instance) {
|
||||||
|
m_instance = new FileDB();
|
||||||
|
}
|
||||||
|
return m_instance;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
#ifndef FILEDB_H
|
||||||
|
#define FILEDB_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
|
class FileDB : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
static FileDB* instance();
|
||||||
|
|
||||||
|
QStringList uft3RealFunctionList;
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit FileDB(QObject *parent = nullptr);
|
||||||
|
static FileDB* m_instance;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // FILEDB_H
|
||||||
|
|
@ -0,0 +1,529 @@
|
||||||
|
#include "metadataprocessor.h"
|
||||||
|
#include "uf2interface.h"
|
||||||
|
#include "uft3interface.h"
|
||||||
|
#include "filedb.h"
|
||||||
|
#include "uf2stdfields.h"
|
||||||
|
#include "uf2datatype.h"
|
||||||
|
#include "uf2errnumber.h"
|
||||||
|
#include "uft3stdfields.h"
|
||||||
|
#include "uft3datatype.h"
|
||||||
|
#include "uft3table.h"
|
||||||
|
#include "utils/logmanager.h"
|
||||||
|
#include "utils/configmanager.h"
|
||||||
|
#include <QFile>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QSettings>
|
||||||
|
#include <QDir>
|
||||||
|
|
||||||
|
MetadataProcessor::MetadataProcessor(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void MetadataProcessor::initConfig(const QString& basePath)
|
||||||
|
{
|
||||||
|
m_basePath = basePath;
|
||||||
|
m_uf2touft3Path = QDir(basePath).filePath("uf2touft3");
|
||||||
|
|
||||||
|
LogManager::instance()->log("========== 初始化配置 ==========");
|
||||||
|
|
||||||
|
ConfigManager* configManager = ConfigManager::instance();
|
||||||
|
|
||||||
|
m_uf20Path = configManager->getValue("projectPath", "uf20");
|
||||||
|
m_ufAcct20Path = configManager->getValue("projectPath", "ufAcct20");
|
||||||
|
m_uftDbSettPath = configManager->getValue("projectPath", "UftdbSett");
|
||||||
|
m_uft30PubPath = configManager->getValue("projectPath", "uft30pub");
|
||||||
|
m_uft30CbptransPath = configManager->getValue("projectPath", "uft30cbptrans");
|
||||||
|
m_uft30Path = configManager->getValue("projectPath", "uft30");
|
||||||
|
|
||||||
|
m_supportUftdbSett = configManager->getValue("testConfig", "supportUftdbSett");
|
||||||
|
m_moduleGenerationCheck = configManager->getValue("testConfig", "moduleGenerationCheck");
|
||||||
|
|
||||||
|
LogManager::instance()->log(QString("UF2TOUFT3路径: %1").arg(m_uf2touft3Path));
|
||||||
|
LogManager::instance()->log(QString("UF20路径: %1").arg(m_uf20Path));
|
||||||
|
LogManager::instance()->log(QString("UF20会计路径: %1").arg(m_ufAcct20Path));
|
||||||
|
LogManager::instance()->log(QString("UFT数据库设置路径: %1").arg(m_uftDbSettPath));
|
||||||
|
LogManager::instance()->log(QString("UFT30公共路径: %1").arg(m_uft30PubPath));
|
||||||
|
LogManager::instance()->log(QString("UFT30交易路径: %1").arg(m_uft30CbptransPath));
|
||||||
|
LogManager::instance()->log(QString("UFT30路径: %1").arg(m_uft30Path));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool MetadataProcessor::isValidUtf8(const QByteArray& data)
|
||||||
|
{
|
||||||
|
QString test = QString::fromUtf8(data);
|
||||||
|
return test.toUtf8() == data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool MetadataProcessor::writeJson(const QString& filePath, const QJsonObject& jsonObject)
|
||||||
|
{
|
||||||
|
LogManager::instance()->log(QString("准备写入JSON文件: %1, 对象大小: %2").arg(filePath).arg(jsonObject.size()));
|
||||||
|
|
||||||
|
QFile file(filePath);
|
||||||
|
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||||
|
LogManager::instance()->logError(QString("无法打开文件: %1").arg(filePath));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonDocument doc(jsonObject);
|
||||||
|
qint64 bytesWritten = file.write(doc.toJson(QJsonDocument::Indented));
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
LogManager::instance()->log(QString("成功写入JSON文件: %1, 写入字节数: %2").arg(filePath).arg(bytesWritten));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject MetadataProcessor::interfaceInfoToUFT3Json(const InterfaceInfo& info)
|
||||||
|
{
|
||||||
|
QJsonObject interfaceJson;
|
||||||
|
interfaceJson["cname"] = info.cname;
|
||||||
|
interfaceJson["eName"] = info.eName;
|
||||||
|
interfaceJson["functionNo"] = info.functionNo;
|
||||||
|
interfaceJson["flag"] = info.flag;
|
||||||
|
interfaceJson["path"] = info.path;
|
||||||
|
interfaceJson["code"] = info.code;
|
||||||
|
interfaceJson["id"] = info.id;
|
||||||
|
interfaceJson["sysStatus"] = info.sysStatus;
|
||||||
|
interfaceJson["description"] = info.description;
|
||||||
|
interfaceJson["moudle"] = info.moudle;
|
||||||
|
|
||||||
|
QJsonObject inputFieldsJson;
|
||||||
|
for (const QString& fieldName : info.inputFields.keys()) {
|
||||||
|
const FieldInfo& field = info.inputFields[fieldName];
|
||||||
|
QJsonObject fieldJson;
|
||||||
|
fieldJson["name"] = field.name;
|
||||||
|
fieldJson["flag"] = field.flag;
|
||||||
|
fieldJson["desc"] = field.desc;
|
||||||
|
fieldJson["uuid"] = field.uuid;
|
||||||
|
inputFieldsJson[fieldName] = fieldJson;
|
||||||
|
}
|
||||||
|
interfaceJson["inputFileds"] = inputFieldsJson;
|
||||||
|
|
||||||
|
QJsonObject outputFieldsJson;
|
||||||
|
for (const QString& fieldName : info.outputFields.keys()) {
|
||||||
|
const FieldInfo& field = info.outputFields[fieldName];
|
||||||
|
QJsonObject fieldJson;
|
||||||
|
fieldJson["name"] = field.name;
|
||||||
|
fieldJson["flag"] = field.flag;
|
||||||
|
fieldJson["desc"] = field.desc;
|
||||||
|
fieldJson["paramType"] = field.paramType;
|
||||||
|
fieldJson["uuid"] = field.uuid;
|
||||||
|
outputFieldsJson[fieldName] = fieldJson;
|
||||||
|
}
|
||||||
|
interfaceJson["outputFileds"] = outputFieldsJson;
|
||||||
|
|
||||||
|
QJsonObject internalFieldsJson;
|
||||||
|
for (const QString& fieldName : info.internalFields.keys()) {
|
||||||
|
const FieldInfo& field = info.internalFields[fieldName];
|
||||||
|
QJsonObject fieldJson;
|
||||||
|
fieldJson["name"] = field.name;
|
||||||
|
fieldJson["type"] = field.type;
|
||||||
|
fieldJson["desc"] = field.desc;
|
||||||
|
fieldJson["paramType"] = field.paramType;
|
||||||
|
fieldJson["uuid"] = field.uuid;
|
||||||
|
internalFieldsJson[fieldName] = fieldJson;
|
||||||
|
}
|
||||||
|
interfaceJson["internalFileds"] = internalFieldsJson;
|
||||||
|
|
||||||
|
return interfaceJson;
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject MetadataProcessor::readJson(const QString& filePath)
|
||||||
|
{
|
||||||
|
QFile file(filePath);
|
||||||
|
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||||
|
LogManager::instance()->logError(QString("无法打开文件: %1").arg(filePath));
|
||||||
|
return QJsonObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray data = file.readAll();
|
||||||
|
QJsonDocument doc = QJsonDocument::fromJson(data);
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
if (doc.isNull()) {
|
||||||
|
LogManager::instance()->logError(QString("无效的 JSON 文件: %1").arg(filePath));
|
||||||
|
return QJsonObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
return doc.object();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString MetadataProcessor::getBasePath() const
|
||||||
|
{
|
||||||
|
return m_basePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MetadataProcessor::setBasePath(const QString& path)
|
||||||
|
{
|
||||||
|
m_basePath = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MetadataProcessor::processUf2Interfaces(const QString& basePath)
|
||||||
|
{
|
||||||
|
LogManager::instance()->log("========== 开始处理 UF2.0 接口 ==========");
|
||||||
|
LogManager::instance()->log(QString("基础路径(basePath): %1").arg(basePath));
|
||||||
|
|
||||||
|
QString configPath = QDir(m_uf2touft3Path).filePath("config.ini");
|
||||||
|
LogManager::instance()->log(QString("配置文件路径: %1").arg(configPath));
|
||||||
|
|
||||||
|
QStringList completeNameList = {"module.xml", ".project", "冲突检测.wlua"};
|
||||||
|
QStringList containNameList = {".vbusiness", "/公共资源/", "/数据库/", "/脚本/", "/通用数据/", "/.svn/"};
|
||||||
|
|
||||||
|
QMap<QString, QStringList> filterDict;
|
||||||
|
filterDict["completeNameList"] = completeNameList;
|
||||||
|
filterDict["containNameList"] = containNameList;
|
||||||
|
|
||||||
|
QString dirPath = m_uf20Path;
|
||||||
|
QString ufAcct20ProjectDir = m_ufAcct20Path;
|
||||||
|
QString uftDbSett = m_uftDbSettPath;
|
||||||
|
|
||||||
|
QString supportUftdbSett = m_supportUftdbSett;
|
||||||
|
if (supportUftdbSett == "0") {
|
||||||
|
uftDbSett.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
LogManager::instance()->log(QString("UF20 项目路径: %1").arg(dirPath));
|
||||||
|
LogManager::instance()->log(QString("UF20 会计项目路径: %1").arg(ufAcct20ProjectDir));
|
||||||
|
LogManager::instance()->log(QString("UFT 数据库设置路径: %1").arg(uftDbSett));
|
||||||
|
|
||||||
|
QString custJsonPath = QDir(m_uf2touft3Path).filePath("cust.json");
|
||||||
|
LogManager::instance()->log(QString("客户配置文件路径: %1").arg(custJsonPath));
|
||||||
|
QJsonObject custJson = readJson(custJsonPath);
|
||||||
|
|
||||||
|
Uf2Interface uf2;
|
||||||
|
QMap<QString, InterfaceInfo> resultMap = uf2.scanDir(dirPath, ufAcct20ProjectDir, uftDbSett, filterDict);
|
||||||
|
|
||||||
|
QJsonObject resultJson;
|
||||||
|
for (const QString& key : resultMap.keys()) {
|
||||||
|
const InterfaceInfo& info = resultMap[key];
|
||||||
|
|
||||||
|
QJsonObject interfaceJson;
|
||||||
|
interfaceJson["cname"] = info.cname;
|
||||||
|
interfaceJson["eName"] = info.eName;
|
||||||
|
interfaceJson["functionNo"] = info.functionNo;
|
||||||
|
interfaceJson["flag"] = info.flag;
|
||||||
|
interfaceJson["path"] = info.path;
|
||||||
|
interfaceJson["code"] = info.code;
|
||||||
|
interfaceJson["moudle"] = info.moudle;
|
||||||
|
interfaceJson["moudleEName"] = info.moudleEName;
|
||||||
|
interfaceJson["serverType"] = info.serverType;
|
||||||
|
interfaceJson["returnResultSet"] = info.returnResultSet;
|
||||||
|
interfaceJson["needTransMonitor"] = info.needTransMonitor;
|
||||||
|
interfaceJson["checkLicence"] = info.checkLicence;
|
||||||
|
|
||||||
|
QJsonObject inputFieldsJson;
|
||||||
|
for (const QString& fieldName : info.inputFields.keys()) {
|
||||||
|
const FieldInfo& field = info.inputFields[fieldName];
|
||||||
|
QJsonObject fieldJson;
|
||||||
|
fieldJson["name"] = field.name;
|
||||||
|
fieldJson["flag"] = field.flag;
|
||||||
|
fieldJson["desc"] = field.desc;
|
||||||
|
inputFieldsJson[fieldName] = fieldJson;
|
||||||
|
}
|
||||||
|
interfaceJson["inputFileds"] = inputFieldsJson;
|
||||||
|
|
||||||
|
QJsonObject outputFieldsJson;
|
||||||
|
for (const QString& fieldName : info.outputFields.keys()) {
|
||||||
|
const FieldInfo& field = info.outputFields[fieldName];
|
||||||
|
QJsonObject fieldJson;
|
||||||
|
fieldJson["name"] = field.name;
|
||||||
|
fieldJson["flag"] = field.flag;
|
||||||
|
fieldJson["desc"] = field.desc;
|
||||||
|
outputFieldsJson[fieldName] = fieldJson;
|
||||||
|
}
|
||||||
|
interfaceJson["outputFileds"] = outputFieldsJson;
|
||||||
|
|
||||||
|
QJsonObject variableFieldsJson;
|
||||||
|
for (const QString& fieldName : info.variableFields.keys()) {
|
||||||
|
const FieldInfo& field = info.variableFields[fieldName];
|
||||||
|
QJsonObject fieldJson;
|
||||||
|
fieldJson["name"] = field.name;
|
||||||
|
fieldJson["cname"] = field.cname;
|
||||||
|
fieldJson["hsType"] = field.hsType;
|
||||||
|
fieldJson["desc"] = field.desc;
|
||||||
|
variableFieldsJson[fieldName] = fieldJson;
|
||||||
|
}
|
||||||
|
interfaceJson["variableFileds"] = variableFieldsJson;
|
||||||
|
|
||||||
|
resultJson[key] = interfaceJson;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString outputPath = QDir(m_uf2touft3Path).filePath("uf2.json");
|
||||||
|
|
||||||
|
if (!writeJson(outputPath, resultJson)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
LogManager::instance()->log(QString("UF2.0 接口处理完成,结果已保存到: %1").arg(outputPath));
|
||||||
|
if (!resultMap.isEmpty()) {
|
||||||
|
QString firstKey = resultMap.keys().first();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MetadataProcessor::processUft3Interfaces(const QString& basePath)
|
||||||
|
{
|
||||||
|
LogManager::instance()->log("========== 开始处理 UFT3.0 接口 ==========");
|
||||||
|
LogManager::instance()->log(QString("基础路径(basePath): %1").arg(basePath));
|
||||||
|
|
||||||
|
QString configPath = QDir(m_uf2touft3Path).filePath("config.ini");
|
||||||
|
LogManager::instance()->log(QString("配置文件路径: %1").arg(configPath));
|
||||||
|
|
||||||
|
QString moduleGenerationCheck = m_moduleGenerationCheck;
|
||||||
|
LogManager::instance()->log(QString("模块生成检查: %1").arg(moduleGenerationCheck));
|
||||||
|
|
||||||
|
QStringList completeNameList = {"module.xml", "project.xml", "冲突检测.wlua"};
|
||||||
|
QStringList containNameList = {".extinterface", ".uftatomfunction", ".uftatomservice", ".uftfunction", ".uftservice"};
|
||||||
|
|
||||||
|
QMap<QString, QStringList> filterDict;
|
||||||
|
filterDict["completeNameList"] = completeNameList;
|
||||||
|
filterDict["containNameList"] = containNameList;
|
||||||
|
|
||||||
|
QString dirPath = m_uft30Path;
|
||||||
|
LogManager::instance()->log(QString("UFT30 项目路径: %1").arg(dirPath));
|
||||||
|
|
||||||
|
Uft3Interface uft3;
|
||||||
|
auto result = uft3.scanDir(dirPath, filterDict, moduleGenerationCheck);
|
||||||
|
|
||||||
|
QMap<QString, InterfaceInfo> resultMap = result.first;
|
||||||
|
QMap<QString, InterfaceInfo> transCodeMap = result.second;
|
||||||
|
|
||||||
|
|
||||||
|
QJsonObject resultJson;
|
||||||
|
for (const QString& key : resultMap.keys()) {
|
||||||
|
const InterfaceInfo& info = resultMap[key];
|
||||||
|
resultJson[key] = interfaceInfoToUFT3Json(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString outputPath = QDir(m_uf2touft3Path).filePath("uft3.json");
|
||||||
|
|
||||||
|
if (!writeJson(outputPath, resultJson)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject transCodeJson;
|
||||||
|
for (const QString& key : transCodeMap.keys()) {
|
||||||
|
const InterfaceInfo& info = transCodeMap[key];
|
||||||
|
transCodeJson[key] = interfaceInfoToUFT3Json(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString transOutputPath = QDir(m_uf2touft3Path).filePath("uft3Trans.json");
|
||||||
|
|
||||||
|
if (!writeJson(transOutputPath, transCodeJson)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
LogManager::instance()->log(QString("UFT3.0 接口处理完成,结果已保存到: %1").arg(outputPath));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MetadataProcessor::processUf2DataType()
|
||||||
|
{
|
||||||
|
LogManager::instance()->log("========== 开始处理 UF2.0 数据类型 ==========");
|
||||||
|
|
||||||
|
QString dirPath = m_uf20Path;
|
||||||
|
|
||||||
|
Uf2DataType uf2DataType;
|
||||||
|
auto resultMap = uf2DataType.loadData(dirPath);
|
||||||
|
|
||||||
|
QJsonObject resultJson;
|
||||||
|
for (const QString& key : resultMap.keys()) {
|
||||||
|
const QMap<QString, QString>& typeInfo = resultMap[key];
|
||||||
|
QJsonObject typeJson;
|
||||||
|
for (const QString& attrKey : typeInfo.keys()) {
|
||||||
|
typeJson[attrKey] = typeInfo[attrKey];
|
||||||
|
}
|
||||||
|
resultJson[key] = typeJson;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString outputPath = QDir(m_uf2touft3Path).filePath("uf2dataType.json");
|
||||||
|
|
||||||
|
if (!writeJson(outputPath, resultJson)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
LogManager::instance()->log(QString("UF2.0 数据类型处理完成,结果已保存到: %1").arg(outputPath));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MetadataProcessor::processUf2StdFields()
|
||||||
|
{
|
||||||
|
LogManager::instance()->log("========== 开始处理 UF2.0 标准字段 ==========");
|
||||||
|
|
||||||
|
QString dirPath = m_uf20Path;
|
||||||
|
|
||||||
|
QMap<QString, QMap<QString, QString>> uf2datatypeMap;
|
||||||
|
QString datatypeJsonPath = QDir(m_uf2touft3Path).filePath("uf2dataType.json");
|
||||||
|
QJsonObject datatypeJson = readJson(datatypeJsonPath);
|
||||||
|
for (const QString& key : datatypeJson.keys()) {
|
||||||
|
QJsonObject typeObj = datatypeJson[key].toObject();
|
||||||
|
QMap<QString, QString> typeInfo;
|
||||||
|
for (const QString& attrKey : typeObj.keys()) {
|
||||||
|
typeInfo[attrKey] = typeObj[attrKey].toString();
|
||||||
|
}
|
||||||
|
uf2datatypeMap[key] = typeInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
Uf2StdFields uf2StdFields;
|
||||||
|
auto resultMap = uf2StdFields.loadData(dirPath, uf2datatypeMap);
|
||||||
|
|
||||||
|
QJsonObject resultJson;
|
||||||
|
for (const QString& key : resultMap.keys()) {
|
||||||
|
const QMap<QString, QString>& fieldInfo = resultMap[key];
|
||||||
|
QJsonObject fieldJson;
|
||||||
|
for (const QString& attrKey : fieldInfo.keys()) {
|
||||||
|
fieldJson[attrKey] = fieldInfo[attrKey];
|
||||||
|
}
|
||||||
|
resultJson[key] = fieldJson;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString outputPath = QDir(m_uf2touft3Path).filePath("uf2stdfield.json");
|
||||||
|
|
||||||
|
if (!writeJson(outputPath, resultJson)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
LogManager::instance()->log(QString("UF2.0 标准字段处理完成,结果已保存到: %1").arg(outputPath));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MetadataProcessor::processUf2ErrNumber()
|
||||||
|
{
|
||||||
|
LogManager::instance()->log("========== 开始处理 UF2.0 标准错误号 ==========");
|
||||||
|
|
||||||
|
QString dirPath = m_uf20Path;
|
||||||
|
|
||||||
|
Uf2ErrNumber uf2ErrNumber;
|
||||||
|
auto resultMap = uf2ErrNumber.loadData(dirPath);
|
||||||
|
|
||||||
|
QJsonObject resultJson;
|
||||||
|
for (const QString& key : resultMap.keys()) {
|
||||||
|
const QMap<QString, QString>& errorInfo = resultMap[key];
|
||||||
|
QJsonObject errorJson;
|
||||||
|
for (const QString& attrKey : errorInfo.keys()) {
|
||||||
|
errorJson[attrKey] = errorInfo[attrKey];
|
||||||
|
}
|
||||||
|
resultJson[key] = errorJson;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString outputPath = QDir(m_uf2touft3Path).filePath("uf2Error.json");
|
||||||
|
|
||||||
|
if (!writeJson(outputPath, resultJson)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
LogManager::instance()->log(QString("UF2.0 标准错误号处理完成,结果已保存到: %1").arg(outputPath));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MetadataProcessor::processUft3DataType()
|
||||||
|
{
|
||||||
|
LogManager::instance()->log("========== 开始处理 UFT3.0 数据类型 ==========");
|
||||||
|
|
||||||
|
QString dirPath = m_uft30PubPath;
|
||||||
|
|
||||||
|
Uft3DataType uft3DataType;
|
||||||
|
auto resultMap = uft3DataType.loadData(dirPath);
|
||||||
|
|
||||||
|
QJsonObject resultJson;
|
||||||
|
for (const QString& key : resultMap.keys()) {
|
||||||
|
const QMap<QString, QString>& typeInfo = resultMap[key];
|
||||||
|
QJsonObject typeJson;
|
||||||
|
for (const QString& attrKey : typeInfo.keys()) {
|
||||||
|
typeJson[attrKey] = typeInfo[attrKey];
|
||||||
|
}
|
||||||
|
resultJson[key] = typeJson;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString outputPath = QDir(m_uf2touft3Path).filePath("uft3datatype.json");
|
||||||
|
|
||||||
|
if (!writeJson(outputPath, resultJson)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
LogManager::instance()->log(QString("UFT3.0 数据类型处理完成,结果已保存到: %1").arg(outputPath));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MetadataProcessor::processUft3StdFields()
|
||||||
|
{
|
||||||
|
LogManager::instance()->log("========== 开始处理 UFT3.0 标准字段 ==========");
|
||||||
|
|
||||||
|
QString dirPath = m_uft30PubPath;
|
||||||
|
|
||||||
|
QMap<QString, QMap<QString, QString>> uf3datatypeMap;
|
||||||
|
QString datatypeJsonPath = QDir(m_uf2touft3Path).filePath("uft3datatype.json");
|
||||||
|
QJsonObject datatypeJson = readJson(datatypeJsonPath);
|
||||||
|
for (const QString& key : datatypeJson.keys()) {
|
||||||
|
QJsonObject typeObj = datatypeJson[key].toObject();
|
||||||
|
QMap<QString, QString> typeInfo;
|
||||||
|
for (const QString& attrKey : typeObj.keys()) {
|
||||||
|
typeInfo[attrKey] = typeObj[attrKey].toString();
|
||||||
|
}
|
||||||
|
uf3datatypeMap[key] = typeInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
Uft3StdFields uft3StdFields;
|
||||||
|
auto resultMap = uft3StdFields.loadData(dirPath, uf3datatypeMap);
|
||||||
|
|
||||||
|
QJsonObject resultJson;
|
||||||
|
for (const QString& key : resultMap.keys()) {
|
||||||
|
const QMap<QString, QString>& fieldInfo = resultMap[key];
|
||||||
|
QJsonObject fieldJson;
|
||||||
|
for (const QString& attrKey : fieldInfo.keys()) {
|
||||||
|
fieldJson[attrKey] = fieldInfo[attrKey];
|
||||||
|
}
|
||||||
|
resultJson[key] = fieldJson;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString outputPath = QDir(m_uf2touft3Path).filePath("uft3stdfields.json");
|
||||||
|
|
||||||
|
if (!writeJson(outputPath, resultJson)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
LogManager::instance()->log(QString("UFT3.0 标准字段处理完成,结果已保存到: %1").arg(outputPath));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MetadataProcessor::processUft3Table()
|
||||||
|
{
|
||||||
|
LogManager::instance()->log("========== 开始处理 UFT3.0 表结构 ==========");
|
||||||
|
|
||||||
|
QString dirPath = m_uft30PubPath;
|
||||||
|
|
||||||
|
Uft3Table uft3Table;
|
||||||
|
auto resultMap = uft3Table.loadData(dirPath);
|
||||||
|
|
||||||
|
QJsonObject resultJson;
|
||||||
|
for (const QString& key : resultMap.keys()) {
|
||||||
|
const QMap<QString, QVariant>& tableInfo = resultMap[key];
|
||||||
|
QJsonObject tableJson;
|
||||||
|
for (const QString& attrKey : tableInfo.keys()) {
|
||||||
|
QVariant value = tableInfo[attrKey];
|
||||||
|
if (value.canConvert<QJsonValue>()) {
|
||||||
|
tableJson[attrKey] = value.toJsonValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resultJson[key] = tableJson;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString outputPath = QDir(m_uf2touft3Path).filePath("uft3Table.json");
|
||||||
|
|
||||||
|
if (!writeJson(outputPath, resultJson)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
LogManager::instance()->log(QString("UFT3.0 表结构处理完成,结果已保存到: %1").arg(outputPath));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
#ifndef METADATAPROCESSOR_H
|
||||||
|
#define METADATAPROCESSOR_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QString>
|
||||||
|
#include <QMap>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QJsonObject>
|
||||||
|
|
||||||
|
struct InterfaceInfo;
|
||||||
|
|
||||||
|
class MetadataProcessor : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit MetadataProcessor(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
bool processUf2Interfaces(const QString& basePath);
|
||||||
|
bool processUft3Interfaces(const QString& basePath);
|
||||||
|
|
||||||
|
bool processUf2StdFields();
|
||||||
|
bool processUf2DataType();
|
||||||
|
bool processUf2ErrNumber();
|
||||||
|
|
||||||
|
bool processUft3StdFields();
|
||||||
|
bool processUft3DataType();
|
||||||
|
bool processUft3Table();
|
||||||
|
|
||||||
|
QString getBasePath() const;
|
||||||
|
void setBasePath(const QString& path);
|
||||||
|
|
||||||
|
public:
|
||||||
|
void initConfig(const QString& basePath);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool isValidUtf8(const QByteArray& data);
|
||||||
|
bool writeJson(const QString& filePath, const QJsonObject& jsonObject);
|
||||||
|
QJsonObject readJson(const QString& filePath);
|
||||||
|
QJsonObject interfaceInfoToUFT3Json(const InterfaceInfo& info);
|
||||||
|
|
||||||
|
QString m_basePath;
|
||||||
|
QString m_uf2touft3Path;
|
||||||
|
|
||||||
|
QString m_uf20Path;
|
||||||
|
QString m_ufAcct20Path;
|
||||||
|
QString m_uftDbSettPath;
|
||||||
|
QString m_uft30PubPath;
|
||||||
|
QString m_uft30CbptransPath;
|
||||||
|
QString m_uft30Path;
|
||||||
|
|
||||||
|
QString m_supportUftdbSett;
|
||||||
|
QString m_moduleGenerationCheck;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // METADATAPROCESSOR_H
|
||||||
|
|
@ -0,0 +1,86 @@
|
||||||
|
#include "uf2datatype.h"
|
||||||
|
#include "utils/logmanager.h"
|
||||||
|
#include <QFile>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QXmlStreamReader>
|
||||||
|
|
||||||
|
Uf2DataType::Uf2DataType(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QMap<QString, QMap<QString, QString>> Uf2DataType::loadData(const QString& dirPath)
|
||||||
|
{
|
||||||
|
QMap<QString, QMap<QString, QString>> resultMap;
|
||||||
|
|
||||||
|
QString filePath = dirPath;
|
||||||
|
filePath.replace('\\', '/');
|
||||||
|
filePath += "/公共资源/datatypes.xml";
|
||||||
|
|
||||||
|
LogManager::instance()->log(QString("加载UF2数据类型文件: %1").arg(filePath));
|
||||||
|
|
||||||
|
QFile file(filePath);
|
||||||
|
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||||
|
LogManager::instance()->logError(QString("无法打开文件: %1").arg(filePath));
|
||||||
|
return resultMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
QXmlStreamReader xml(&file);
|
||||||
|
|
||||||
|
while (!xml.atEnd() && !xml.hasError()) {
|
||||||
|
QXmlStreamReader::TokenType token = xml.readNext();
|
||||||
|
|
||||||
|
if (token == QXmlStreamReader::StartElement) {
|
||||||
|
QString elementName = xml.name().toString();
|
||||||
|
|
||||||
|
if (elementName == "userType") {
|
||||||
|
QXmlStreamAttributes attrs = xml.attributes();
|
||||||
|
QString hsType = attrs.value("name").toString();
|
||||||
|
|
||||||
|
QString cValue = "";
|
||||||
|
QString oValue = "";
|
||||||
|
|
||||||
|
while (!xml.atEnd() && !xml.hasError()) {
|
||||||
|
token = xml.readNext();
|
||||||
|
|
||||||
|
if (token == QXmlStreamReader::StartElement) {
|
||||||
|
QString childElementName = xml.name().toString();
|
||||||
|
|
||||||
|
if (childElementName == "language") {
|
||||||
|
while (!xml.atEnd() && !xml.hasError()) {
|
||||||
|
token = xml.readNext();
|
||||||
|
if (token == QXmlStreamReader::StartElement && xml.name().toString() == "map") {
|
||||||
|
cValue = xml.attributes().value("value").toString();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (childElementName == "database") {
|
||||||
|
while (!xml.atEnd() && !xml.hasError()) {
|
||||||
|
token = xml.readNext();
|
||||||
|
if (token == QXmlStreamReader::StartElement && xml.name().toString() == "map") {
|
||||||
|
oValue = xml.attributes().value("value").toString();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (token == QXmlStreamReader::EndElement && xml.name().toString() == "userType") {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QMap<QString, QString> typeInfo;
|
||||||
|
typeInfo["HsType"] = hsType;
|
||||||
|
typeInfo["CType"] = cValue;
|
||||||
|
typeInfo["OType"] = oValue;
|
||||||
|
|
||||||
|
resultMap[hsType] = typeInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
file.close();
|
||||||
|
LogManager::instance()->log(QString("UF2数据类型加载完成,共 %1 条").arg(resultMap.size()));
|
||||||
|
|
||||||
|
return resultMap;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
#ifndef UF2DATATYPE_H
|
||||||
|
#define UF2DATATYPE_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QString>
|
||||||
|
#include <QMap>
|
||||||
|
|
||||||
|
class Uf2DataType : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit Uf2DataType(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
QMap<QString, QMap<QString, QString>> loadData(const QString& dirPath);
|
||||||
|
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
#include "uf2errnumber.h"
|
||||||
|
#include "utils/logmanager.h"
|
||||||
|
#include <QFile>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QXmlStreamReader>
|
||||||
|
|
||||||
|
Uf2ErrNumber::Uf2ErrNumber(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QMap<QString, QMap<QString, QString>> Uf2ErrNumber::loadData(const QString& dirPath)
|
||||||
|
{
|
||||||
|
QMap<QString, QMap<QString, QString>> resultMap;
|
||||||
|
|
||||||
|
QString filePath = dirPath;
|
||||||
|
filePath.replace('\\', '/');
|
||||||
|
filePath += "/公共资源/errNumbers.xml";
|
||||||
|
|
||||||
|
LogManager::instance()->log(QString("加载UF2错误号文件: %1").arg(filePath));
|
||||||
|
|
||||||
|
QFile file(filePath);
|
||||||
|
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||||
|
LogManager::instance()->logError(QString("无法打开文件: %1").arg(filePath));
|
||||||
|
return resultMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
QXmlStreamReader xml(&file);
|
||||||
|
|
||||||
|
while (!xml.atEnd() && !xml.hasError()) {
|
||||||
|
QXmlStreamReader::TokenType token = xml.readNext();
|
||||||
|
|
||||||
|
if (token == QXmlStreamReader::StartElement) {
|
||||||
|
QString elementName = xml.name().toString();
|
||||||
|
|
||||||
|
if (elementName == "error_no") {
|
||||||
|
QXmlStreamAttributes attrs = xml.attributes();
|
||||||
|
|
||||||
|
QString sErrorNo = attrs.value("code").toString();
|
||||||
|
QString sConstant = attrs.value("constant").toString();
|
||||||
|
QString sErrorInfo = attrs.value("info").toString();
|
||||||
|
|
||||||
|
QMap<QString, QString> errorInfo;
|
||||||
|
errorInfo["code"] = sErrorNo;
|
||||||
|
errorInfo["constant"] = sConstant;
|
||||||
|
errorInfo["info"] = sErrorInfo;
|
||||||
|
|
||||||
|
resultMap[sConstant] = errorInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
file.close();
|
||||||
|
LogManager::instance()->log(QString("UF2错误号加载完成,共 %1 条").arg(resultMap.size()));
|
||||||
|
|
||||||
|
return resultMap;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
#ifndef UF2ERRNUMBER_H
|
||||||
|
#define UF2ERRNUMBER_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QString>
|
||||||
|
#include <QMap>
|
||||||
|
|
||||||
|
class Uf2ErrNumber : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit Uf2ErrNumber(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
QMap<QString, QMap<QString, QString>> loadData(const QString& dirPath);
|
||||||
|
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,273 @@
|
||||||
|
#include "uf2interface.h"
|
||||||
|
#include "utils/logmanager.h"
|
||||||
|
#include <QFile>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QStack>
|
||||||
|
#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();
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
QMap<QString, InterfaceInfo> resultMap;
|
||||||
|
QStringList completeNameList = fileFilterDict.value("completeNameList");
|
||||||
|
QStringList containNameList = fileFilterDict.value("containNameList");
|
||||||
|
|
||||||
|
QMap<QString, QString> moduleCodeMap;
|
||||||
|
moduleCodeMap["转融通"] = "ref";
|
||||||
|
|
||||||
|
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);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
#ifndef UF2INTERFACE_H
|
||||||
|
#define UF2INTERFACE_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QString>
|
||||||
|
#include <QMap>
|
||||||
|
#include <QXmlStreamReader>
|
||||||
|
|
||||||
|
struct FieldInfo {
|
||||||
|
QString name;
|
||||||
|
QString flag;
|
||||||
|
QString desc;
|
||||||
|
QString uuid;
|
||||||
|
QString paramType;
|
||||||
|
QString type;
|
||||||
|
QString cname;
|
||||||
|
QString hsType;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct InterfaceInfo {
|
||||||
|
QString cname;
|
||||||
|
QString eName;
|
||||||
|
QString functionNo;
|
||||||
|
QString flag;
|
||||||
|
QString path;
|
||||||
|
QString code;
|
||||||
|
QString id;
|
||||||
|
QString sysStatus;
|
||||||
|
QString description;
|
||||||
|
QString moudle;
|
||||||
|
QString moudleEName;
|
||||||
|
QString serverType;
|
||||||
|
bool returnResultSet = false;
|
||||||
|
bool needTransMonitor = false;
|
||||||
|
bool checkLicence = false;
|
||||||
|
|
||||||
|
QMap<QString, FieldInfo> inputFields;
|
||||||
|
QMap<QString, FieldInfo> outputFields;
|
||||||
|
QMap<QString, FieldInfo> variableFields;
|
||||||
|
QMap<QString, FieldInfo> internalFields;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Uf2Interface : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit Uf2Interface(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
InterfaceInfo loadInterface(const QString& filePath);
|
||||||
|
QMap<QString, InterfaceInfo> scanDir(const QString& dirPath,
|
||||||
|
const QString& ufAcct20ProjectDir,
|
||||||
|
const QString& uftDbSett,
|
||||||
|
const QMap<QString, QStringList>& fileFilterDict);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString getModuleEName(const QString& moduleXmlPath);
|
||||||
|
bool shouldFilter(const QString& filePath,
|
||||||
|
const QStringList& completeNameList,
|
||||||
|
const QStringList& containNameList);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // UF2INTERFACE_H
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
#include "uf2stdfields.h"
|
||||||
|
#include "utils/logmanager.h"
|
||||||
|
#include <QFile>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QXmlStreamReader>
|
||||||
|
|
||||||
|
Uf2StdFields::Uf2StdFields(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QMap<QString, QMap<QString, QString>> Uf2StdFields::loadData(
|
||||||
|
const QString& dirPath,
|
||||||
|
const QMap<QString, QMap<QString, QString>>& uf2datatypeMap)
|
||||||
|
{
|
||||||
|
QMap<QString, QMap<QString, QString>> resultMap;
|
||||||
|
|
||||||
|
QString filePath = dirPath;
|
||||||
|
filePath.replace('\\', '/');
|
||||||
|
filePath += "/公共资源/stdfields.xml";
|
||||||
|
|
||||||
|
LogManager::instance()->log(QString("加载UF2标准字段文件: %1").arg(filePath));
|
||||||
|
|
||||||
|
QFile file(filePath);
|
||||||
|
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||||
|
LogManager::instance()->logError(QString("无法打开文件: %1").arg(filePath));
|
||||||
|
return resultMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
QXmlStreamReader xml(&file);
|
||||||
|
|
||||||
|
while (!xml.atEnd() && !xml.hasError()) {
|
||||||
|
QXmlStreamReader::TokenType token = xml.readNext();
|
||||||
|
|
||||||
|
if (token == QXmlStreamReader::StartElement) {
|
||||||
|
QString elementName = xml.name().toString();
|
||||||
|
|
||||||
|
if (elementName == "stdfield") {
|
||||||
|
QXmlStreamAttributes attrs = xml.attributes();
|
||||||
|
|
||||||
|
QString sFieldName = attrs.value("name").toString();
|
||||||
|
QString sCname = attrs.value("cname").toString();
|
||||||
|
QString sType = attrs.value("type").toString();
|
||||||
|
QString sDesc = attrs.value("desc").toString();
|
||||||
|
sDesc.replace("'", "\"");
|
||||||
|
QString sDictId = attrs.value("dict").toString();
|
||||||
|
|
||||||
|
QString sCtype = "";
|
||||||
|
QString sOType = "";
|
||||||
|
|
||||||
|
if (uf2datatypeMap.contains(sType)) {
|
||||||
|
sCtype = uf2datatypeMap[sType].value("CType");
|
||||||
|
sOType = uf2datatypeMap[sType].value("OType");
|
||||||
|
}
|
||||||
|
|
||||||
|
QMap<QString, QString> fieldInfo;
|
||||||
|
fieldInfo["name"] = sFieldName;
|
||||||
|
fieldInfo["cname"] = sCname;
|
||||||
|
fieldInfo["type"] = sType;
|
||||||
|
fieldInfo["desc"] = sDesc;
|
||||||
|
fieldInfo["dict"] = sDictId;
|
||||||
|
fieldInfo["cType"] = sCtype;
|
||||||
|
fieldInfo["oType"] = sOType;
|
||||||
|
|
||||||
|
resultMap[sFieldName] = fieldInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
file.close();
|
||||||
|
LogManager::instance()->log(QString("UF2标准字段加载完成,共 %1 条").arg(resultMap.size()));
|
||||||
|
|
||||||
|
return resultMap;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
#ifndef UF2STDFIELDS_H
|
||||||
|
#define UF2STDFIELDS_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QString>
|
||||||
|
#include <QMap>
|
||||||
|
|
||||||
|
class Uf2StdFields : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit Uf2StdFields(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
QMap<QString, QMap<QString, QString>> loadData(const QString& dirPath,
|
||||||
|
const QMap<QString, QMap<QString, QString>>& uf2datatypeMap);
|
||||||
|
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
#include "uft3datatype.h"
|
||||||
|
#include "utils/logmanager.h"
|
||||||
|
#include <QFile>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QXmlStreamReader>
|
||||||
|
|
||||||
|
Uft3DataType::Uft3DataType(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QMap<QString, QMap<QString, QString>> Uft3DataType::loadData(const QString& dirPath)
|
||||||
|
{
|
||||||
|
QMap<QString, QMap<QString, QString>> resultMap;
|
||||||
|
|
||||||
|
QString filePath = dirPath;
|
||||||
|
filePath.replace('\\', '/');
|
||||||
|
filePath += "/metadata/datatype.datatype";
|
||||||
|
|
||||||
|
LogManager::instance()->log(QString("加载UFT3数据类型文件: %1").arg(filePath));
|
||||||
|
|
||||||
|
QFile file(filePath);
|
||||||
|
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||||
|
LogManager::instance()->logError(QString("无法打开文件: %1").arg(filePath));
|
||||||
|
return resultMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
QXmlStreamReader xml(&file);
|
||||||
|
|
||||||
|
while (!xml.atEnd() && !xml.hasError()) {
|
||||||
|
QXmlStreamReader::TokenType token = xml.readNext();
|
||||||
|
|
||||||
|
if (token == QXmlStreamReader::StartElement) {
|
||||||
|
QString elementName = xml.name().toString();
|
||||||
|
|
||||||
|
if (elementName == "items") {
|
||||||
|
QXmlStreamAttributes attrs = xml.attributes();
|
||||||
|
|
||||||
|
QString hsType = attrs.value("name").toString();
|
||||||
|
QString uftValue = attrs.value("stdType").toString();
|
||||||
|
QString uftLen = "0";
|
||||||
|
|
||||||
|
if (uftValue.toLower() == "string") {
|
||||||
|
uftLen = attrs.value("length").toString();
|
||||||
|
uftValue = "char[" + uftLen + "]";
|
||||||
|
}
|
||||||
|
else if (uftValue.toLower() == "int32") {
|
||||||
|
uftValue = "int";
|
||||||
|
}
|
||||||
|
else if (uftValue.toLower() == "int64") {
|
||||||
|
uftValue = "double";
|
||||||
|
}
|
||||||
|
else if (uftValue.toLower() == "double") {
|
||||||
|
uftValue = "double";
|
||||||
|
}
|
||||||
|
else if (uftValue.toLower() == "char") {
|
||||||
|
uftValue = "char";
|
||||||
|
}
|
||||||
|
|
||||||
|
QMap<QString, QString> typeInfo;
|
||||||
|
typeInfo["HsType"] = hsType;
|
||||||
|
typeInfo["uftType"] = uftValue;
|
||||||
|
|
||||||
|
resultMap[hsType] = typeInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
file.close();
|
||||||
|
LogManager::instance()->log(QString("UFT3数据类型加载完成,共 %1 条").arg(resultMap.size()));
|
||||||
|
|
||||||
|
return resultMap;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
#ifndef TFT3DATATYPE_H
|
||||||
|
#define TFT3DATATYPE_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QString>
|
||||||
|
#include <QMap>
|
||||||
|
|
||||||
|
class Uft3DataType : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit Uft3DataType(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
QMap<QString, QMap<QString, QString>> loadData(const QString& dirPath);
|
||||||
|
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,245 @@
|
||||||
|
#include "uft3interface.h"
|
||||||
|
#include "utils/logmanager.h"
|
||||||
|
#include "filedb.h"
|
||||||
|
#include <QFile>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QTextStream>
|
||||||
|
|
||||||
|
Uft3Interface::Uft3Interface(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
InterfaceInfo Uft3Interface::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;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFile file(sFilePath);
|
||||||
|
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||||
|
LogManager::instance()->logError(QString("无法打开文件: %1").arg(sFilePath));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
QTextStream in(&file);
|
||||||
|
QString line = in.readLine();
|
||||||
|
line = in.readLine();
|
||||||
|
|
||||||
|
if (!line.isEmpty()) {
|
||||||
|
int pos = line.indexOf("chineseName=\"");
|
||||||
|
if (pos != -1) {
|
||||||
|
pos += QString("chineseName=\"").length();
|
||||||
|
int endPos = line.indexOf('"', pos);
|
||||||
|
if (endPos != -1) {
|
||||||
|
result.cname = line.mid(pos, endPos - pos).trimmed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pos = line.indexOf("objectId=\"");
|
||||||
|
if (pos != -1) {
|
||||||
|
pos += QString("objectId=\"").length();
|
||||||
|
int endPos = line.indexOf('"', pos);
|
||||||
|
if (endPos != -1) {
|
||||||
|
result.functionNo = line.mid(pos, endPos - pos).trimmed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pos = line.indexOf("description=\"");
|
||||||
|
if (pos != -1) {
|
||||||
|
pos += QString("description=\"").length();
|
||||||
|
int endPos = line.indexOf('"', pos);
|
||||||
|
if (endPos != -1) {
|
||||||
|
result.description = line.mid(pos, endPos - pos).trimmed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pos = line.indexOf("interfaceFlag=\"");
|
||||||
|
if (pos != -1) {
|
||||||
|
pos += QString("interfaceFlag=\"").length();
|
||||||
|
int endPos = line.indexOf('"', pos);
|
||||||
|
if (endPos != -1) {
|
||||||
|
result.flag = line.mid(pos, endPos - pos).trimmed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pos = line.indexOf("id=\"");
|
||||||
|
if (pos != -1) {
|
||||||
|
pos += QString("id=\"").length();
|
||||||
|
int endPos = line.indexOf('"', pos);
|
||||||
|
if (endPos != -1) {
|
||||||
|
result.id = line.mid(pos, endPos - pos).trimmed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pos = line.indexOf("sysStatus=\"");
|
||||||
|
if (pos != -1) {
|
||||||
|
pos += QString("sysStatus=\"").length();
|
||||||
|
int endPos = line.indexOf('"', pos);
|
||||||
|
if (endPos != -1) {
|
||||||
|
result.sysStatus = line.mid(pos, endPos - pos).trimmed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.eName = fileInfo.baseName();
|
||||||
|
|
||||||
|
file.seek(0);
|
||||||
|
QXmlStreamReader xml(&file);
|
||||||
|
|
||||||
|
while (!xml.atEnd() && !xml.hasError()) {
|
||||||
|
QXmlStreamReader::TokenType token = xml.readNext();
|
||||||
|
|
||||||
|
if (token == QXmlStreamReader::StartElement) {
|
||||||
|
QString elementName = xml.name().toString();
|
||||||
|
|
||||||
|
if (elementName == "inputParameters") {
|
||||||
|
QXmlStreamAttributes attrs = xml.attributes();
|
||||||
|
FieldInfo field;
|
||||||
|
field.name = attrs.value("id").toString();
|
||||||
|
field.flag = attrs.value("flags").toString();
|
||||||
|
field.desc = attrs.value("comments").toString();
|
||||||
|
field.uuid = attrs.value("uuid").toString();
|
||||||
|
result.inputFields[field.name] = field;
|
||||||
|
}
|
||||||
|
else if (elementName == "outputParameters") {
|
||||||
|
QXmlStreamAttributes attrs = xml.attributes();
|
||||||
|
FieldInfo field;
|
||||||
|
field.name = attrs.value("id").toString();
|
||||||
|
field.flag = attrs.value("flags").toString();
|
||||||
|
field.desc = attrs.value("comments").toString();
|
||||||
|
field.paramType = attrs.value("paramType").toString();
|
||||||
|
field.uuid = attrs.value("uuid").toString();
|
||||||
|
result.outputFields[field.name] = field;
|
||||||
|
|
||||||
|
if (field.flag.contains("IO")) {
|
||||||
|
result.inputFields[field.name] = field;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (elementName == "internalParams") {
|
||||||
|
QXmlStreamAttributes attrs = xml.attributes();
|
||||||
|
FieldInfo field;
|
||||||
|
field.name = attrs.value("id").toString();
|
||||||
|
field.type = attrs.value("type").toString();
|
||||||
|
field.desc = attrs.value("name").toString();
|
||||||
|
field.paramType = attrs.value("paramType").toString();
|
||||||
|
field.uuid = attrs.value("uuid").toString();
|
||||||
|
result.internalFields[field.name] = field;
|
||||||
|
}
|
||||||
|
else if (elementName == "code") {
|
||||||
|
result.code = xml.readElementText();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
if (!result.functionNo.isEmpty() && !FileDB::instance()->uft3RealFunctionList.contains(result.functionNo)) {
|
||||||
|
FileDB::instance()->uft3RealFunctionList.append(result.functionNo);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Uft3Interface::shouldFilter(const QString& filePath,
|
||||||
|
const QString& dirPath,
|
||||||
|
const QStringList& completeNameList,
|
||||||
|
const QStringList& containNameList,
|
||||||
|
const QString& moduleGenerationCheck)
|
||||||
|
{
|
||||||
|
QFileInfo fileInfo(filePath);
|
||||||
|
QString fileName = fileInfo.fileName();
|
||||||
|
QString relPath = filePath.mid(dirPath.length());
|
||||||
|
|
||||||
|
if (completeNameList.contains(fileName)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dotPos = relPath.indexOf('.');
|
||||||
|
QString suffix;
|
||||||
|
if (dotPos != -1) {
|
||||||
|
suffix = relPath.mid(dotPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!containNameList.contains(suffix)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (moduleGenerationCheck == "1") {
|
||||||
|
if (filePath.contains("/cbp/") || filePath.contains("/ucbp/")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Uft3Interface::scanDirRecursive(const QString& dirPath,
|
||||||
|
const QStringList& completeNameList,
|
||||||
|
const QStringList& containNameList,
|
||||||
|
const QString& moduleGenerationCheck,
|
||||||
|
QMap<QString, InterfaceInfo>& resultMap,
|
||||||
|
QMap<QString, InterfaceInfo>& transCodeMap)
|
||||||
|
{
|
||||||
|
QDir dir(dirPath);
|
||||||
|
QStringList filters;
|
||||||
|
filters << "*.*";
|
||||||
|
|
||||||
|
QFileInfoList fileList = dir.entryInfoList(filters, QDir::Files);
|
||||||
|
for (const QFileInfo& fileInfo : fileList) {
|
||||||
|
QString filePath = fileInfo.absoluteFilePath();
|
||||||
|
filePath.replace('\\', '/');
|
||||||
|
|
||||||
|
if (shouldFilter(filePath, dirPath, completeNameList, containNameList, moduleGenerationCheck)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isTransCode = (filePath.contains("/cbptrans/") ||
|
||||||
|
filePath.contains("/mgrcbptrans/") ||
|
||||||
|
filePath.contains("/converttrans/") ||
|
||||||
|
filePath.contains("/ses/")) &&
|
||||||
|
!filePath.contains("/cbptrans/cbptranspub/");
|
||||||
|
|
||||||
|
QString modName = fileInfo.dir().dirName();
|
||||||
|
InterfaceInfo interfaceInfo = loadInterface(filePath);
|
||||||
|
interfaceInfo.moudle = modName;
|
||||||
|
|
||||||
|
if (isTransCode) {
|
||||||
|
transCodeMap[interfaceInfo.cname] = interfaceInfo;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
resultMap[interfaceInfo.cname] = interfaceInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFileInfoList dirList = dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
|
||||||
|
for (const QFileInfo& dirInfo : dirList) {
|
||||||
|
scanDirRecursive(dirInfo.absoluteFilePath(), completeNameList,
|
||||||
|
containNameList, moduleGenerationCheck, resultMap, transCodeMap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QPair<QMap<QString, InterfaceInfo>, QMap<QString, InterfaceInfo>>
|
||||||
|
Uft3Interface::scanDir(const QString& dirPath,
|
||||||
|
const QMap<QString, QStringList>& fileFilterDict,
|
||||||
|
const QString& moduleGenerationCheck)
|
||||||
|
{
|
||||||
|
QMap<QString, InterfaceInfo> resultMap;
|
||||||
|
QMap<QString, InterfaceInfo> transCodeMap;
|
||||||
|
|
||||||
|
QStringList completeNameList = fileFilterDict.value("completeNameList");
|
||||||
|
QStringList containNameList = fileFilterDict.value("containNameList");
|
||||||
|
|
||||||
|
scanDirRecursive(dirPath, completeNameList, containNameList, moduleGenerationCheck, resultMap, transCodeMap);
|
||||||
|
|
||||||
|
return qMakePair(resultMap, transCodeMap);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
#ifndef UFT3INTERFACE_H
|
||||||
|
#define UFT3INTERFACE_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QString>
|
||||||
|
#include <QMap>
|
||||||
|
#include <QXmlStreamReader>
|
||||||
|
#include <QPair>
|
||||||
|
|
||||||
|
#include "uf2interface.h"
|
||||||
|
|
||||||
|
class Uft3Interface : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit Uft3Interface(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
InterfaceInfo loadInterface(const QString& filePath);
|
||||||
|
QPair<QMap<QString, InterfaceInfo>, QMap<QString, InterfaceInfo>>
|
||||||
|
scanDir(const QString& dirPath,
|
||||||
|
const QMap<QString, QStringList>& fileFilterDict,
|
||||||
|
const QString& moduleGenerationCheck);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool shouldFilter(const QString& filePath,
|
||||||
|
const QString& dirPath,
|
||||||
|
const QStringList& completeNameList,
|
||||||
|
const QStringList& containNameList,
|
||||||
|
const QString& moduleGenerationCheck);
|
||||||
|
|
||||||
|
void scanDirRecursive(const QString& dirPath,
|
||||||
|
const QStringList& completeNameList,
|
||||||
|
const QStringList& containNameList,
|
||||||
|
const QString& moduleGenerationCheck,
|
||||||
|
QMap<QString, InterfaceInfo>& resultMap,
|
||||||
|
QMap<QString, InterfaceInfo>& transCodeMap);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // UFT3INTERFACE_H
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
#include "uft3stdfields.h"
|
||||||
|
#include "utils/logmanager.h"
|
||||||
|
#include <QFile>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QXmlStreamReader>
|
||||||
|
|
||||||
|
Uft3StdFields::Uft3StdFields(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QMap<QString, QMap<QString, QString>> Uft3StdFields::loadData(
|
||||||
|
const QString& dirPath,
|
||||||
|
const QMap<QString, QMap<QString, QString>>& uf3datatypeMap)
|
||||||
|
{
|
||||||
|
QMap<QString, QMap<QString, QString>> resultMap;
|
||||||
|
|
||||||
|
QString filePath = dirPath;
|
||||||
|
filePath.replace('\\', '/');
|
||||||
|
filePath += "/metadata/stdfield.stdfield";
|
||||||
|
|
||||||
|
LogManager::instance()->log(QString("加载UFT3标准字段文件: %1").arg(filePath));
|
||||||
|
|
||||||
|
QFile file(filePath);
|
||||||
|
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||||
|
LogManager::instance()->logError(QString("无法打开文件: %1").arg(filePath));
|
||||||
|
return resultMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
QXmlStreamReader xml(&file);
|
||||||
|
|
||||||
|
while (!xml.atEnd() && !xml.hasError()) {
|
||||||
|
QXmlStreamReader::TokenType token = xml.readNext();
|
||||||
|
|
||||||
|
if (token == QXmlStreamReader::StartElement) {
|
||||||
|
QString elementName = xml.name().toString();
|
||||||
|
|
||||||
|
if (elementName == "items") {
|
||||||
|
QXmlStreamAttributes attrs = xml.attributes();
|
||||||
|
|
||||||
|
QString sFieldName = attrs.value("name").toString();
|
||||||
|
QString sCname = attrs.value("chineseName").toString();
|
||||||
|
QString sType = attrs.value("dataType").toString();
|
||||||
|
QString sDesc = attrs.value("description").toString();
|
||||||
|
sDesc.replace("'", "\"");
|
||||||
|
QString sDictId = attrs.value("dictionaryType").toString();
|
||||||
|
|
||||||
|
QString sUftType = "";
|
||||||
|
|
||||||
|
if (uf3datatypeMap.contains(sType)) {
|
||||||
|
sUftType = uf3datatypeMap[sType].value("uftType");
|
||||||
|
}
|
||||||
|
|
||||||
|
QMap<QString, QString> fieldInfo;
|
||||||
|
fieldInfo["name"] = sFieldName;
|
||||||
|
fieldInfo["cname"] = sCname;
|
||||||
|
fieldInfo["type"] = sType;
|
||||||
|
fieldInfo["desc"] = sDesc;
|
||||||
|
fieldInfo["dict"] = sDictId;
|
||||||
|
fieldInfo["uftType"] = sUftType;
|
||||||
|
|
||||||
|
resultMap[sFieldName] = fieldInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
file.close();
|
||||||
|
LogManager::instance()->log(QString("UFT3标准字段加载完成,共 %1 条").arg(resultMap.size()));
|
||||||
|
|
||||||
|
return resultMap;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
#ifndef TFT3STDFIELDS_H
|
||||||
|
#define TFT3STDFIELDS_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QString>
|
||||||
|
#include <QMap>
|
||||||
|
|
||||||
|
class Uft3StdFields : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit Uft3StdFields(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
QMap<QString, QMap<QString, QString>> loadData(const QString& dirPath,
|
||||||
|
const QMap<QString, QMap<QString, QString>>& uf3datatypeMap);
|
||||||
|
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,198 @@
|
||||||
|
#include "uft3table.h"
|
||||||
|
#include "utils/logmanager.h"
|
||||||
|
#include <QFile>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QXmlStreamReader>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QJsonArray>
|
||||||
|
|
||||||
|
Uft3Table::Uft3Table(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QMap<QString, QMap<QString, QVariant>> Uft3Table::loadData(const QString& dirPath)
|
||||||
|
{
|
||||||
|
QMap<QString, QMap<QString, QVariant>> resultMap;
|
||||||
|
|
||||||
|
QString scanPath = dirPath;
|
||||||
|
scanPath.replace('\\', '/');
|
||||||
|
scanPath += "/uftstructure";
|
||||||
|
|
||||||
|
LogManager::instance()->log(QString("加载UFT3表结构目录: %1").arg(scanPath));
|
||||||
|
|
||||||
|
QDir dir(scanPath);
|
||||||
|
if (!dir.exists()) {
|
||||||
|
LogManager::instance()->logError(QString("表结构目录不存在: %1").arg(scanPath));
|
||||||
|
return resultMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
scanDirectory(scanPath, resultMap);
|
||||||
|
|
||||||
|
for (const QString& filePath : _fileList) {
|
||||||
|
if (filePath.contains(".uftstructure")) {
|
||||||
|
parseTableFile(filePath, resultMap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LogManager::instance()->log(QString("UFT3表结构加载完成,共 %1 条").arg(resultMap.size()));
|
||||||
|
|
||||||
|
return resultMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Uft3Table::scanDirectory(const QString& dirPath, QMap<QString, QMap<QString, QVariant>>& resultMap)
|
||||||
|
{
|
||||||
|
QDir dir(dirPath);
|
||||||
|
|
||||||
|
QFileInfoList fileList = dir.entryInfoList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
|
||||||
|
|
||||||
|
for (const QFileInfo& fileInfo : fileList) {
|
||||||
|
if (fileInfo.isDir()) {
|
||||||
|
scanDirectory(fileInfo.absoluteFilePath(), resultMap);
|
||||||
|
}
|
||||||
|
else if (fileInfo.isFile()) {
|
||||||
|
_fileList.append(fileInfo.absoluteFilePath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Uft3Table::parseTableFile(const QString& filePath, QMap<QString, QMap<QString, QVariant>>& resultMap)
|
||||||
|
{
|
||||||
|
QString sFilePath = filePath;
|
||||||
|
sFilePath.replace('\\', '/');
|
||||||
|
|
||||||
|
QFile file(sFilePath);
|
||||||
|
if (!file.open(QIODevice::ReadOnly)) {
|
||||||
|
LogManager::instance()->logError(QString("无法打开表结构文件: %1").arg(sFilePath));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray data = file.readAll();
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
QXmlStreamReader xml(data);
|
||||||
|
|
||||||
|
QString tableEngName = "";
|
||||||
|
QString tablePath = "";
|
||||||
|
QString chineseName = "";
|
||||||
|
QString objectId = "";
|
||||||
|
QString spaceName = "";
|
||||||
|
QStringList fieldList;
|
||||||
|
QMap<QString, QStringList> indexMap;
|
||||||
|
QMap<QString, QStringList> uniqueIndexMap;
|
||||||
|
QMap<QString, QStringList> globalIndexMap;
|
||||||
|
|
||||||
|
int lastSlash = sFilePath.lastIndexOf('/');
|
||||||
|
if (lastSlash != -1) {
|
||||||
|
tableEngName = sFilePath.mid(lastSlash + 1);
|
||||||
|
tableEngName = tableEngName.left(tableEngName.indexOf(".uftstructure"));
|
||||||
|
}
|
||||||
|
|
||||||
|
int uftstructurePos = sFilePath.indexOf("uftstructure");
|
||||||
|
if (uftstructurePos != -1) {
|
||||||
|
tablePath = sFilePath.mid(uftstructurePos);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!xml.atEnd() && !xml.hasError()) {
|
||||||
|
QXmlStreamReader::TokenType token = xml.readNext();
|
||||||
|
|
||||||
|
if (token == QXmlStreamReader::StartElement) {
|
||||||
|
QString elementName = xml.name().toString();
|
||||||
|
QXmlStreamAttributes attrs = xml.attributes();
|
||||||
|
|
||||||
|
if (elementName == "Structure") {
|
||||||
|
if (attrs.hasAttribute("chineseName")) {
|
||||||
|
chineseName = attrs.value("chineseName").toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attrs.hasAttribute("objectId")) {
|
||||||
|
objectId = attrs.value("objectId").toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attrs.hasAttribute("space")) {
|
||||||
|
spaceName = attrs.value("space").toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (elementName == "properties") {
|
||||||
|
QString fieldId = attrs.value("id").toString();
|
||||||
|
if (!fieldId.isEmpty()) {
|
||||||
|
fieldList.append(fieldId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (elementName == "indexs") {
|
||||||
|
QString indexName = attrs.value("name").toString();
|
||||||
|
QStringList indexFieldList;
|
||||||
|
bool isUnique = !attrs.hasAttribute("containerType");
|
||||||
|
bool isGlobal = false;
|
||||||
|
|
||||||
|
if (attrs.hasAttribute("global") && attrs.value("global").toString() == "true") {
|
||||||
|
isGlobal = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!xml.atEnd() && !xml.hasError()) {
|
||||||
|
token = xml.readNext();
|
||||||
|
|
||||||
|
if (token == QXmlStreamReader::StartElement && xml.name().toString() == "items") {
|
||||||
|
QString fieldAttr = xml.attributes().value("attrname").toString();
|
||||||
|
if (!fieldAttr.isEmpty()) {
|
||||||
|
indexFieldList.append(fieldAttr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (token == QXmlStreamReader::EndElement && xml.name().toString() == "indexs") {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!indexName.isEmpty() && !indexFieldList.isEmpty()) {
|
||||||
|
indexMap[indexName] = indexFieldList;
|
||||||
|
if (isUnique) {
|
||||||
|
uniqueIndexMap[indexName] = indexFieldList;
|
||||||
|
}
|
||||||
|
if (isGlobal) {
|
||||||
|
globalIndexMap[indexName] = indexFieldList;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString sUser = "";
|
||||||
|
if (spaceName == "HS_UFT_DATA") {
|
||||||
|
sUser = "hs_uft";
|
||||||
|
}
|
||||||
|
else if (spaceName == "HS_UARG_DATA") {
|
||||||
|
sUser = "hs_uarg";
|
||||||
|
}
|
||||||
|
else if (spaceName == "HS_USMS_DATA") {
|
||||||
|
sUser = "hs_usms";
|
||||||
|
}
|
||||||
|
|
||||||
|
QMap<QString, QVariant> tableInfoDetail;
|
||||||
|
tableInfoDetail["tableEngName"] = tableEngName;
|
||||||
|
tableInfoDetail["tablePath"] = tablePath;
|
||||||
|
tableInfoDetail["chineseName"] = chineseName;
|
||||||
|
tableInfoDetail["objectId"] = objectId;
|
||||||
|
tableInfoDetail["fieldList"] = fieldList;
|
||||||
|
tableInfoDetail["user"] = sUser;
|
||||||
|
|
||||||
|
QJsonObject indexMapJson;
|
||||||
|
for (const QString& key : indexMap.keys()) {
|
||||||
|
indexMapJson[key] = QJsonArray::fromStringList(indexMap[key]);
|
||||||
|
}
|
||||||
|
tableInfoDetail["indexMap"] = indexMapJson;
|
||||||
|
|
||||||
|
QJsonObject uniqueIndexMapJson;
|
||||||
|
for (const QString& key : uniqueIndexMap.keys()) {
|
||||||
|
uniqueIndexMapJson[key] = QJsonArray::fromStringList(uniqueIndexMap[key]);
|
||||||
|
}
|
||||||
|
tableInfoDetail["uniqueIndexMap"] = uniqueIndexMapJson;
|
||||||
|
|
||||||
|
QJsonObject globalIndexMapJson;
|
||||||
|
for (const QString& key : globalIndexMap.keys()) {
|
||||||
|
globalIndexMapJson[key] = QJsonArray::fromStringList(globalIndexMap[key]);
|
||||||
|
}
|
||||||
|
tableInfoDetail["globalIndexMap"] = globalIndexMapJson;
|
||||||
|
|
||||||
|
if (!tableEngName.isEmpty()) {
|
||||||
|
resultMap[tableEngName] = tableInfoDetail;
|
||||||
|
}
|
||||||
|
}
|
||||||