Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
08efc50c3f | ||
|
|
9cb7240060 | ||
|
|
389c6eeecd | ||
|
|
b86fc071c2 | ||
|
|
9fdd342234 | ||
|
|
38fde4223f | ||
|
|
1f33f0fbaa | ||
|
|
d4d607dc6a | ||
|
|
6dfba8715d | ||
|
|
dbb7059664 | ||
|
|
edb693e5af | ||
|
|
d891b4f583 | ||
|
|
5718503f26 | ||
|
|
cc7fc51399 | ||
|
|
fad539e127 | ||
|
|
4cb44fc2fa | ||
|
|
273da28390 | ||
|
|
8ecf44db1a | ||
|
|
b55596078d | ||
|
|
5f3a8cc8dd | ||
|
|
3e05ecd9d2 | ||
|
|
aa1bb42467 | ||
|
|
2af12b298c | ||
|
|
c097120ca3 | ||
|
|
fd38553be1 |
@@ -5,9 +5,18 @@
|
|||||||
!python_bindings/**
|
!python_bindings/**
|
||||||
!src/
|
!src/
|
||||||
!src/**
|
!src/**
|
||||||
|
!help/
|
||||||
|
!help/**
|
||||||
|
!resources/
|
||||||
|
!resources/**
|
||||||
!*.bat
|
!*.bat
|
||||||
!*.rc
|
!*.rc
|
||||||
!*.prp
|
!*.prp
|
||||||
!*.cpp
|
!*.cpp
|
||||||
!*.qrc
|
!*.qrc
|
||||||
|
!*.h
|
||||||
|
!*.pro
|
||||||
|
!*.md
|
||||||
!.gitignore
|
!.gitignore
|
||||||
|
!.gitkeep
|
||||||
|
!update_info.json
|
||||||
|
|||||||
@@ -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,116 @@
|
|||||||
|
# Uft30ChangeCode(UFT30 代码转换工具)
|
||||||
|
|
||||||
|
一款基于 **Qt 6 + MinGW** 开发的桌面工具,用于将 UF20 业务代码转换为 UFT3 格式,并提供功能查询、代码检索、元数据更新、数据映射等配套能力。UI 采用 [ElaWidgetTools](3rd/ElaWidgetTools) 组件库。
|
||||||
|
|
||||||
|
- 当前版本:**v1.4.0**
|
||||||
|
- 运行平台:Windows
|
||||||
|
- 界面框架:Qt Widgets + ElaWidgetTools
|
||||||
|
|
||||||
|
## 功能特性
|
||||||
|
|
||||||
|
| 模块 | 说明 |
|
||||||
|
| --- | --- |
|
||||||
|
| 业务转码 | 将 UF20 函数批量转换为 UFT3 函数格式,支持进度显示与中止 |
|
||||||
|
| 功能查询 | UF20 / UFT3 功能(函数)查找,支持 2.0 账户功能查询 |
|
||||||
|
| 代码检索 | "转码业务" / "非转码业务" 调用链路分析,支持涉及文件与调用链导出 |
|
||||||
|
| 元数据更新 | 更新 UF20 / UFT3 标准字段、数据类型、接口数据等,支持增量更新与强制全量更新 |
|
||||||
|
| 数据映射 | 表映射、函数映射 |
|
||||||
|
| 设置 | 配置 UFT30 / UF20 项目路径、账户环境路径、转码生成路径等 |
|
||||||
|
| 其它 | 在线帮助文档、关于页、版本更新提示;全局文字可选中复制、表格 Ctrl+C 导出 |
|
||||||
|
|
||||||
|
## 目录结构
|
||||||
|
|
||||||
|
```
|
||||||
|
Uft30ChangeCode/
|
||||||
|
├─ main.cpp # 程序入口,安装全局文字可复制过滤器
|
||||||
|
├─ Uft30ChangeCode.pro # qmake 工程文件
|
||||||
|
├─ build.bat # 一键构建脚本(Release)
|
||||||
|
├─ build_advanced.bat # 进阶构建脚本
|
||||||
|
├─ config/
|
||||||
|
│ └─ change_code.ini # 默认配置模板(构建时按需部署到 bin/uf2touft3/)
|
||||||
|
├─ src/
|
||||||
|
│ ├─ mainwindow/ # 主窗口
|
||||||
|
│ ├─ pages/ # 各功能页面(batchconvert / codesearch / functionsearch / metadatupdate / datamapping / settings / about)
|
||||||
|
│ ├─ metadataupdate/ # 元数据扫描与处理(UF2 / UFT3 接口、数据类型、字段等)
|
||||||
|
│ ├─ pythonrunner/ # 调用外部转码工具(uf2touft3.exe)
|
||||||
|
│ ├─ components/ # 自定义控件
|
||||||
|
│ └─ utils/ # 公共工具(日志、配置读取、调用链分析、版本检查、常量等)
|
||||||
|
├─ 3rd/ # 第三方库(ElaWidgetTools 等)
|
||||||
|
├─ resources/ resources.qrc # 图标等资源
|
||||||
|
├─ help/ # 帮助文档(Writerside)
|
||||||
|
└─ update_info.json # 版本发布说明
|
||||||
|
```
|
||||||
|
|
||||||
|
## 构建
|
||||||
|
|
||||||
|
### 环境要求
|
||||||
|
|
||||||
|
- Qt 6.6.2(mingw_64)
|
||||||
|
- MinGW 11.2.0(Qt Tools 自带)
|
||||||
|
|
||||||
|
`build.bat` 中默认路径如下,如与本机不一致请自行修改:
|
||||||
|
|
||||||
|
```bat
|
||||||
|
set QT_PATH=D:\01.InstallInfo\InstallPath\QT\6.6.2\mingw_64
|
||||||
|
set MINGW_PATH=D:\01.InstallInfo\InstallPath\QT\Tools\mingw1120_64
|
||||||
|
```
|
||||||
|
|
||||||
|
### 一键构建
|
||||||
|
|
||||||
|
```bat
|
||||||
|
build.bat
|
||||||
|
```
|
||||||
|
|
||||||
|
脚本会依次执行:关闭正在运行的程序 → 清理旧构建产物 → `qmake` → `mingw32-make release` → `windeployqt` 部署 Qt 运行库 → 按需部署默认 `change_code.ini`。
|
||||||
|
|
||||||
|
构建产物:`bin\Uft30ChangeCode.exe`
|
||||||
|
|
||||||
|
> 注意:外部转码工具 `bin\uf2touft3\uf2touft3.exe` 需自行放置,程序运行时依赖它完成实际转码。
|
||||||
|
|
||||||
|
### 手动构建
|
||||||
|
|
||||||
|
```bat
|
||||||
|
qmake Uft30ChangeCode.pro -spec win32-g++
|
||||||
|
mingw32-make release
|
||||||
|
```
|
||||||
|
|
||||||
|
## 配置说明(`config/change_code.ini`)
|
||||||
|
|
||||||
|
构建时若 `bin/uf2touft3/change_code.ini` 不存在,会从 `config/change_code.ini` 拷贝一份默认模板;已存在则保留用户配置不覆盖。
|
||||||
|
|
||||||
|
### `[codeSearch]` 代码检索路径
|
||||||
|
|
||||||
|
| 键 | 说明 |
|
||||||
|
| --- | --- |
|
||||||
|
| `convertPath` | 转码业务代码检索路径 |
|
||||||
|
| `searchPath` | 非转码业务代码检索路径 |
|
||||||
|
|
||||||
|
### `[log]` 日志配置
|
||||||
|
|
||||||
|
| 键 | 默认值 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `level` | `INFO` | 日志等级:`DEBUG` < `INFO` < `WARNING` < `ERROR`,等级越高输出越少 |
|
||||||
|
| `path` | `./logs` | 日志输出目录(相对路径基于 exe 目录,绝对路径直接生效) |
|
||||||
|
| `file` | `change_code.log` | 日志文件名 |
|
||||||
|
| `fileEnabled` | `true` | 是否写入日志文件 |
|
||||||
|
| `maxSize` | `10MB` | 单个日志文件最大大小(支持 `B`/`KB`/`MB`/`GB`,`0` 表示不限制) |
|
||||||
|
| `maxFiles` | `100` | 日志文件轮转保留数量 |
|
||||||
|
| `maxAge` | `30` | 日志文件保留天数(`0` 表示不限制) |
|
||||||
|
| `console` | `true` | 是否在控制台打印日志 |
|
||||||
|
| `caller` | `false` | 是否在日志中附加调用堆栈(仅 Windows 生效) |
|
||||||
|
| `format` | `text` | 日志格式:`text` / `json` |
|
||||||
|
| `timeFormat` | `2006-01-02 15:04:05.000` | 时间格式(支持 Go 风格布局或 Qt 格式) |
|
||||||
|
|
||||||
|
## 帮助文档
|
||||||
|
|
||||||
|
更多使用说明见 `help/` 目录(Writerside 工程),涵盖业务转码、功能查询、代码检索、元数据更新、数据映射、设置等模块的图文操作指引。
|
||||||
|
|
||||||
|
## 版本记录
|
||||||
|
|
||||||
|
| 版本 | 主要更新 |
|
||||||
|
| --- | --- |
|
||||||
|
| v1.4.0 | 提升业务转码性能;元数据更新支持增量/强制全量;新增代码检索与函数调用链路分析;支持全局文字选中复制及表格 Ctrl+C 导出 |
|
||||||
|
| v1.3.0 | 修复设置路径不生效;修复元数据更新后转码函数检查状态异常 |
|
||||||
|
| v1.2.0 | 新增数据映射(表映射、函数映射);新增版本更新提示 |
|
||||||
|
| v1.1.0 | 支持 2.0 账户功能查询及业务转码 |
|
||||||
|
| v1.0.0 | 首个版本:业务转码、UF20/UFT3 功能查找、帮助文档、接口元数据更新、设置 |
|
||||||
|
|||||||
@@ -0,0 +1,101 @@
|
|||||||
|
QT += core gui widgets sql network concurrent
|
||||||
|
|
||||||
|
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/codesearch/codesearchpage.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/settings/settingspage.cpp \
|
||||||
|
src/pages/metadatupdate/metadatupdatepage.cpp \
|
||||||
|
src/pages/datamapping/tablemappingpage.cpp \
|
||||||
|
src/pages/datamapping/functionmappingpage.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/business_strategy.cpp \
|
||||||
|
src/utils/configreaderbase.cpp \
|
||||||
|
src/utils/uf2configreader.cpp \
|
||||||
|
src/utils/uft3configreader.cpp \
|
||||||
|
src/utils/logmanager.cpp \
|
||||||
|
src/utils/configmanager.cpp \
|
||||||
|
src/utils/callchainanalyzer.cpp \
|
||||||
|
src/utils/version.cpp \
|
||||||
|
src/utils/versionchecker.cpp
|
||||||
|
|
||||||
|
HEADERS += src/mainwindow/mainwindow.h \
|
||||||
|
src/pythonrunner/PythonRunner.h \
|
||||||
|
src/pages/about/aboutdialog.h \
|
||||||
|
src/pages/batchconvert/batchconvertpage.h \
|
||||||
|
src/pages/codesearch/codesearchpage.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/settings/settingspage.h \
|
||||||
|
src/pages/metadatupdate/metadatupdatepage.h \
|
||||||
|
src/pages/datamapping/tablemappingpage.h \
|
||||||
|
src/pages/datamapping/functionmappingpage.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/business_strategy.h \
|
||||||
|
src/utils/configreaderbase.h \
|
||||||
|
src/utils/uf2configreader.h \
|
||||||
|
src/utils/uft3configreader.h \
|
||||||
|
src/utils/logmanager.h \
|
||||||
|
src/utils/configmanager.h \
|
||||||
|
src/utils/callchainanalyzer.h \
|
||||||
|
src/utils/version.h \
|
||||||
|
src/utils/versionchecker.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
|
||||||
|
LIBS += -ldbghelp # LogManager stack trace (caller)
|
||||||
|
RC_FILE = app.rc
|
||||||
|
}
|
||||||
|
|
||||||
|
DESTDIR = $$PWD/bin
|
||||||
|
OBJECTS_DIR = $$PWD/build
|
||||||
|
MOC_DIR = $$PWD/build
|
||||||
|
RCC_DIR = $$PWD/build
|
||||||
|
|
||||||
@@ -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
|
||||||
@@ -76,6 +76,27 @@ if errorlevel 1 (
|
|||||||
)
|
)
|
||||||
|
|
||||||
echo.
|
echo.
|
||||||
|
REM Deploy Qt runtime dependencies (auto-copy required Qt DLLs/plugins)
|
||||||
|
echo Deploying Qt runtime dependencies...
|
||||||
|
windeployqt --release bin\Uft30ChangeCode.exe
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo [WARN] windeployqt failed, please deploy Qt DLLs manually
|
||||||
|
) else (
|
||||||
|
echo [OK] Qt dependencies deployed
|
||||||
|
)
|
||||||
|
echo.
|
||||||
|
|
||||||
|
REM Deploy default change_code.ini (only copy when missing, to keep user's existing config)
|
||||||
|
echo Deploying default change_code.ini...
|
||||||
|
if not exist "bin\uf2touft3" mkdir "bin\uf2touft3"
|
||||||
|
if not exist "bin\uf2touft3\change_code.ini" (
|
||||||
|
copy "config\change_code.ini" "bin\uf2touft3\change_code.ini" >nul
|
||||||
|
echo [OK] change_code.ini -> bin\uf2touft3\ (default copied)
|
||||||
|
) else (
|
||||||
|
echo [SKIP] bin\uf2touft3\change_code.ini already exists, keep user config
|
||||||
|
)
|
||||||
|
echo.
|
||||||
|
|
||||||
echo ==========================================
|
echo ==========================================
|
||||||
echo Build SUCCESSFUL!
|
echo Build SUCCESSFUL!
|
||||||
echo ==========================================
|
echo ==========================================
|
||||||
|
|||||||
@@ -147,4 +147,15 @@ if exist "bin\uf2touft3\uf2touft3.exe" (
|
|||||||
echo [WARN] Please make sure bin\uf2touft3\uf2touft3.exe exists
|
echo [WARN] Please make sure bin\uf2touft3\uf2touft3.exe exists
|
||||||
)
|
)
|
||||||
echo.
|
echo.
|
||||||
|
|
||||||
|
REM Deploy default change_code.ini (only copy when missing, to keep user's existing config)
|
||||||
|
echo Deploying default change_code.ini...
|
||||||
|
if not exist "bin\uf2touft3" mkdir "bin\uf2touft3"
|
||||||
|
if not exist "bin\uf2touft3\change_code.ini" (
|
||||||
|
copy "config\change_code.ini" "bin\uf2touft3\change_code.ini" >nul
|
||||||
|
echo [OK] change_code.ini -> bin\uf2touft3\ (default copied)
|
||||||
|
) else (
|
||||||
|
echo [SKIP] bin\uf2touft3\change_code.ini already exists, keep user config
|
||||||
|
)
|
||||||
|
echo.
|
||||||
pause
|
pause
|
||||||
|
|||||||
@@ -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"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
|
||||||
|
</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,32 @@
|
|||||||
|
<?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 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="函数替换.md"/>
|
||||||
|
</toc-element>
|
||||||
|
<toc-element topic="元数据更新.md"/>
|
||||||
|
<toc-element topic="更新记录.md">
|
||||||
|
<toc-element topic="update-1-4-0.md"/>
|
||||||
|
<toc-element topic="update-1-3-0.md"/>
|
||||||
|
<toc-element topic="update-1-2-0.md"/>
|
||||||
|
<toc-element topic="update-1-1-0.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: 162 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: 58 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 50 KiB |
|
After Width: | Height: | Size: 51 KiB |
|
After Width: | Height: | Size: 33 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,3 @@
|
|||||||
|
# 1.1.0
|
||||||
|
|
||||||
|
1.支持2.0账户功能查询及业务转码
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# 1.2.0
|
||||||
|
|
||||||
|
1.新增数据映射页面,表映射、函数映射
|
||||||
|
|
||||||
|
2.新增版本更新提示功能
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# 1.3.0
|
||||||
|
|
||||||
|
1.修复设置路径不生效
|
||||||
|
|
||||||
|
2.修复元数据更新后业务转码模块对函数检查状态异常问题
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
# 1.4.0
|
||||||
|
|
||||||
|
1.提升业务转码性能;
|
||||||
|
|
||||||
|
2.元数据更新支持增量更新和强制全量更新;
|
||||||
|
|
||||||
|
3.新增代码检索功能;
|
||||||
|
|
||||||
|
4.支持函数调用链路分析;
|
||||||
|
|
||||||
|
5.支持全局文字可选中复制及表格Ctrl+C导出;
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# 下载
|
||||||
|
|
||||||
|
## 全量更新
|
||||||
|
下载全量包,解压即用。
|
||||||
|
|
||||||
|
> 1.0.0版本是基础版本,包含所需功能,如果是第一次下载,请选择全量包。
|
||||||
|
{style="note"}
|
||||||
|
## 增量更新
|
||||||
|
下载增量包,解压后替换原文件即可
|
||||||
|
> 1.0.0版本是基础版本,如若要从旧版升级到1.0.0及以上版本,可以选择增量版本下载,并将旧版根目录下的uf2touft3和当前目录替换覆盖到新版根目录。
|
||||||
|
{style="note"}
|
||||||
|
|
||||||
|
## 下载
|
||||||
|
|
||||||
|
| 版本 | 更新日期 | 全量包 | 增量包 |
|
||||||
|
|-------|------------|----------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------|
|
||||||
|
| 1.4.0 | 2026-07-21 | [Uft30ChangeCode-1.4.0.zip](http://10.20.163.105:6045/download/uft3changecode/Uft30ChangeCode-1.4.0.zip) | [Uft30ChangeCode-1.4.0-update.zip](http://10.20.163.105:6045/download/uft3changecode/Uft30ChangeCode-1.4.0-update.zip) |
|
||||||
|
| 1.3.0 | 2026-07-07 | [Uft30ChangeCode-1.3.0.zip](http://10.20.163.105:6045/download/uft3changecode/Uft30ChangeCode-1.3.0.zip) | [Uft30ChangeCode-1.3.0-update.zip](http://10.20.163.105:6045/download/uft3changecode/Uft30ChangeCode-1.3.0-update.zip) |
|
||||||
|
| 1.2.0 | 2026-07-02 | [Uft30ChangeCode-1.2.0.zip](http://10.20.163.105:6045/download/uft3changecode/Uft30ChangeCode-1.2.0.zip) | [Uft30ChangeCode-1.2.0-update.zip](http://10.20.163.105:6045/download/uft3changecode/Uft30ChangeCode-1.2.0-update.zip) |
|
||||||
|
| 1.1.0 | 2026-07-01 | [Uft30ChangeCode-1.1.0.zip](http://10.20.163.105:6045/download/uft3changecode/Uft30ChangeCode-1.1.0.zip) | [Uft30ChangeCode-1.1.0-update.zip](http://10.20.163.105:6045/download/uft3changecode/Uft30ChangeCode-1.1.0-update.zip) |
|
||||||
|
| 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,11 @@
|
|||||||
|
# 代码检索
|
||||||
|
|
||||||
|
支持"转码业务"、"非转码业务"调用链路查询和导出
|
||||||
|
|
||||||
|
## 转码业务
|
||||||
|
支持查询调用链路和导出查询函数所涉及的文件以及调用链路导出
|
||||||
|
<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,5 @@
|
|||||||
|
# 函数替换
|
||||||
|
|
||||||
|
uf2函数和uft3函数之间的映射关系,支持增、删、改、查功能
|
||||||
|
|
||||||
|
<img src="函数替换.png" alt="函数替换"/>
|
||||||
@@ -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,34 @@
|
|||||||
|
# 功能转码
|
||||||
|
提供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)
|
||||||
|
|
||||||
|
[代码检索](http://10.20.163.105:6045/uft3changecode/业务转码.html)
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
# 数据映射
|
||||||
|
|
||||||
|
## 快速跳转
|
||||||
|
[表替换](http://10.20.163.105:6045/uft3changecode/表替换.html)
|
||||||
|
|
||||||
|
[函数替换](http://10.20.163.105:6045/uft3changecode/函数替换.html)
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# 更新记录
|
||||||
|
|
||||||
|
Start typing here...
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
# 表替换
|
||||||
|
|
||||||
|
uf2表和uft3表之间的映射关系,支持增、删、改、查功能
|
||||||
|
|
||||||
|
<img src="表替换.png" alt="表替换"/>
|
||||||
|
|
||||||
@@ -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,16 @@
|
|||||||
|
<!DOCTYPE html SYSTEM "about:legacy-compat">
|
||||||
|
<html lang="en-US" data-preset="contrast" data-primary-color="#307FFF"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><meta charset="UTF-8"><meta name="robots" content="noindex"><meta name="built-on" content="2026-07-02T10:44:03.5859325"><title>下载 | Uft30ChangeCode</title><script type="application/json" id="virtual-toc-data">[{"id":"qm9v8k_3","level":0,"title":"全量更新","anchor":"#qm9v8k_3"},{"id":"qm9v8k_4","level":0,"title":"增量更新","anchor":"#qm9v8k_4"},{"id":"qm9v8k_5","level":0,"title":"下载","anchor":"#qm9v8k_5"}]</script><script type="application/json" id="topic-shortcuts"></script><link href="https://resources.jetbrains.com/writerside/apidoc/6.10.0-b419/app.css" rel="stylesheet"><link rel="icon" type="image/png" sizes="16x16" href="images/ChangeCode.png"><meta name="image" content=""><!-- Open Graph --><meta property="og:title" content="下载 | Uft30ChangeCode"><meta property="og:description" content=""><meta property="og:image" content=""><meta property="og:site_name" content="Uft30ChangeCode Help"><meta property="og:type" content="website"><meta property="og:locale" content="en_US"><meta property="og:url" content="writerside-documentation/下载.html"><!-- End Open Graph --><!-- Twitter Card --><meta name="twitter:card" content="summary_large_image"><meta name="twitter:site" content=""><meta name="twitter:title" content="下载 | Uft30ChangeCode"><meta name="twitter:description" content=""><meta name="twitter:creator" content=""><meta name="twitter:image:src" content=""><!-- End Twitter Card --><!-- Schema.org WebPage --><script type="application/ld+json">{
|
||||||
|
"@context": "http://schema.org",
|
||||||
|
"@type": "WebPage",
|
||||||
|
"@id": "writerside-documentation/下载.html#webpage",
|
||||||
|
"url": "writerside-documentation/下载.html",
|
||||||
|
"name": "下载 | Uft30ChangeCode",
|
||||||
|
"description": "",
|
||||||
|
"image": "",
|
||||||
|
"inLanguage":"en-US"
|
||||||
|
}</script><!-- End Schema.org --><!-- Schema.org WebSite --><script type="application/ld+json">{
|
||||||
|
"@type": "WebSite",
|
||||||
|
"@id": "writerside-documentation/#website",
|
||||||
|
"url": "writerside-documentation/",
|
||||||
|
"name": "Uft30ChangeCode Help"
|
||||||
|
}</script><!-- End Schema.org --></head><body data-id="下载" data-main-title="下载" data-article-props="{"seeAlsoStyle":"links"}" data-template="article" data-breadcrumbs=""><div class="wrapper"><main class="panel _main"><header class="panel__header"><div class="container"><h3>Uft30ChangeCode Help</h3><div class="panel-trigger"></div></div></header><section class="panel__content"><div class="container"><article class="article" data-shortcut-switcher="inactive"><h1 data-toc="下载" id="下载.md">下载</h1><section class="chapter"><h2 id="qm9v8k_3" data-toc="qm9v8k_3">全量更新</h2><p id="qm9v8k_6">下载全量包,解压即用。</p><aside class="prompt" data-type="note" data-title="" id="qm9v8k_7"><p id="qm9v8k_8">1.0.0版本是基础版本,包含所需功能,如果是第一次下载,请选择全量包。</p></aside></section><section class="chapter"><h2 id="qm9v8k_4" data-toc="qm9v8k_4">增量更新</h2><p id="qm9v8k_9">下载增量包,解压后替换原文件即可</p><aside class="prompt" data-type="note" data-title="" id="qm9v8k_10"><p id="qm9v8k_11">1.0.0版本是基础版本,如若要从旧版升级到1.0.0及以上版本,可以选择增量版本下载,并将旧版根目录下的uf2touft3和当前目录替换覆盖到新版根目录。</p></aside></section><section class="chapter"><h2 id="qm9v8k_5" data-toc="qm9v8k_5">下载</h2><div class="table-wrapper"><table class="wide" id="qm9v8k_12"><thead><tr class="ijRowHead" id="qm9v8k_13"><th id="qm9v8k_16"><p>版本</p></th><th id="qm9v8k_17"><p>更新日期</p></th><th id="qm9v8k_18"><p>全量包</p></th><th id="qm9v8k_19"><p>增量包</p></th></tr></thead><tbody><tr id="qm9v8k_14"><td id="qm9v8k_20"><p>1.1.0</p></td><td id="qm9v8k_21"><p>2026-07-02</p></td><td id="qm9v8k_22"><p><a href="http://10.20.163.105:6045/download/uft3changecode/Uft30ChangeCode-1.1.0.zip" id="qm9v8k_24" data-external="true" rel="noopener noreferrer">Uft30ChangeCode-1.1.0.zip</a></p></td><td id="qm9v8k_23"><p><a href="http://10.20.163.105:6045/download/uft3changecode/Uft30ChangeCode-1.1.0-update.zip" id="qm9v8k_25" data-external="true" rel="noopener noreferrer">Uft30ChangeCode-1.1.0-update.zip</a></p></td></tr><tr id="qm9v8k_15"><td id="qm9v8k_26"><p>1.0.0</p></td><td id="qm9v8k_27"><p>2026-06-01</p></td><td id="qm9v8k_28"><p><a href="http://10.20.163.105:6045/download/uft3changecode/Uft30ChangeCode-1.0.0.zip" id="qm9v8k_30" data-external="true" rel="noopener noreferrer">Uft30ChangeCode-1.0.0.zip</a></p></td><td id="qm9v8k_29"></td></tr></tbody></table></div></section><div class="last-modified">Last modified: 02 七月 2026</div><div data-feedback-placeholder="true"></div><div class="navigation-links _bottom"><a href="update-1-0-0.html" class="navigation-links__prev">1.0.0</a></div></article><div id="disqus_thread"></div></div></section></main></div><script src="https://resources.jetbrains.com/writerside/apidoc/6.10.0-b419/app.js"></script></body></html>
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<!DOCTYPE html SYSTEM "about:legacy-compat">
|
||||||
|
<html lang="en-US" data-preset="contrast" data-primary-color="#307FFF"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><meta charset="UTF-8"><meta name="robots" content="noindex"><meta name="built-on" content="2026-07-02T10:44:03.5744178"><title>更新记录 | Uft30ChangeCode</title><script type="application/json" id="virtual-toc-data">[]</script><script type="application/json" id="topic-shortcuts"></script><link href="https://resources.jetbrains.com/writerside/apidoc/6.10.0-b419/app.css" rel="stylesheet"><link rel="icon" type="image/png" sizes="16x16" href="images/ChangeCode.png"><meta name="image" content=""><!-- Open Graph --><meta property="og:title" content="更新记录 | Uft30ChangeCode"><meta property="og:description" content=""><meta property="og:image" content=""><meta property="og:site_name" content="Uft30ChangeCode Help"><meta property="og:type" content="website"><meta property="og:locale" content="en_US"><meta property="og:url" content="writerside-documentation/更新记录.html"><!-- End Open Graph --><!-- Twitter Card --><meta name="twitter:card" content="summary_large_image"><meta name="twitter:site" content=""><meta name="twitter:title" content="更新记录 | Uft30ChangeCode"><meta name="twitter:description" content=""><meta name="twitter:creator" content=""><meta name="twitter:image:src" content=""><!-- End Twitter Card --><!-- Schema.org WebPage --><script type="application/ld+json">{
|
||||||
|
"@context": "http://schema.org",
|
||||||
|
"@type": "WebPage",
|
||||||
|
"@id": "writerside-documentation/更新记录.html#webpage",
|
||||||
|
"url": "writerside-documentation/更新记录.html",
|
||||||
|
"name": "更新记录 | Uft30ChangeCode",
|
||||||
|
"description": "",
|
||||||
|
"image": "",
|
||||||
|
"inLanguage":"en-US"
|
||||||
|
}</script><!-- End Schema.org --><!-- Schema.org WebSite --><script type="application/ld+json">{
|
||||||
|
"@type": "WebSite",
|
||||||
|
"@id": "writerside-documentation/#website",
|
||||||
|
"url": "writerside-documentation/",
|
||||||
|
"name": "Uft30ChangeCode Help"
|
||||||
|
}</script><!-- End Schema.org --></head><body data-id="更新记录" data-main-title="更新记录" data-article-props="{"seeAlsoStyle":"links"}" data-template="article" data-breadcrumbs=""><div class="wrapper"><main class="panel _main"><header class="panel__header"><div class="container"><h3>Uft30ChangeCode Help</h3><div class="panel-trigger"></div></div></header><section class="panel__content"><div class="container"><article class="article" data-shortcut-switcher="inactive"><h1 data-toc="更新记录" id="更新记录.md">更新记录</h1><p id="r4m9bp_3">Start typing here...</p><div class="last-modified">Last modified: 02 七月 2026</div><div data-feedback-placeholder="true"></div><div class="navigation-links _bottom"><a href="元数据更新.html" class="navigation-links__prev">元数据更新</a><a href="update-1-1-0.html" class="navigation-links__next">1.1.0</a></div></article><div id="disqus_thread"></div></div></section></main></div><script src="https://resources.jetbrains.com/writerside/apidoc/6.10.0-b419/app.js"></script></body></html>
|
||||||
@@ -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
|
||||||
@@ -1,12 +1,105 @@
|
|||||||
#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>
|
||||||
|
#include <QEvent>
|
||||||
|
#include <QKeyEvent>
|
||||||
|
#include <QClipboard>
|
||||||
|
#include <QKeySequence>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QAbstractItemView>
|
||||||
|
#include <QModelIndex>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
// 全局文字可复制过滤器:
|
||||||
|
// 1) 所有 QLabel(含 ElaText)文字可用鼠标选中并复制;
|
||||||
|
// 2) 表格/树(QAbstractItemView)选中的单元格支持 Ctrl+C 复制,制表符分隔列、换行分隔行。
|
||||||
|
class TextSelectableFilter : public QObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using QObject::QObject;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool eventFilter(QObject *watched, QEvent *event) override
|
||||||
|
{
|
||||||
|
if (event->type() == QEvent::Polish) {
|
||||||
|
if (QLabel *label = qobject_cast<QLabel *>(watched)) {
|
||||||
|
// 跳过用作图标按钮的 QLabel(有 pixmap 无文本),
|
||||||
|
// 否则会被强制设为竖线(IBeamCursor),影响点击类图标控件
|
||||||
|
if (label->pixmap().isNull()) {
|
||||||
|
label->setTextInteractionFlags(label->textInteractionFlags()
|
||||||
|
| Qt::TextSelectableByMouse);
|
||||||
|
label->setCursor(Qt::IBeamCursor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (event->type() == QEvent::KeyPress) {
|
||||||
|
if (auto *view = qobject_cast<QAbstractItemView *>(watched)) {
|
||||||
|
auto *ke = static_cast<QKeyEvent *>(event);
|
||||||
|
if (ke->matches(QKeySequence::Copy)) {
|
||||||
|
return copySelectedCells(view);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QObject::eventFilter(watched, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static bool copySelectedCells(QAbstractItemView *view)
|
||||||
|
{
|
||||||
|
if (!view->selectionModel()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
QModelIndexList idxs = view->selectionModel()->selectedIndexes();
|
||||||
|
if (idxs.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 按行、列排序,保证复制顺序与显示一致
|
||||||
|
std::sort(idxs.begin(), idxs.end(),
|
||||||
|
[](const QModelIndex &a, const QModelIndex &b) {
|
||||||
|
if (a.row() != b.row()) {
|
||||||
|
return a.row() < b.row();
|
||||||
|
}
|
||||||
|
return a.column() < b.column();
|
||||||
|
});
|
||||||
|
|
||||||
|
QString text;
|
||||||
|
int lastRow = -1;
|
||||||
|
for (const QModelIndex &idx : idxs) {
|
||||||
|
if (idx.row() != lastRow) {
|
||||||
|
if (lastRow != -1) {
|
||||||
|
text += QLatin1Char('\n');
|
||||||
|
}
|
||||||
|
lastRow = idx.row();
|
||||||
|
} else {
|
||||||
|
text += QLatin1Char('\t');
|
||||||
|
}
|
||||||
|
text += idx.data(Qt::DisplayRole).toString();
|
||||||
|
}
|
||||||
|
if (!text.isEmpty()) {
|
||||||
|
QApplication::clipboard()->setText(text);
|
||||||
|
return true; // 已处理,消费该事件
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
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"));
|
||||||
|
|
||||||
|
// 安装全局过滤器:所有页面文字 / 表格树单元格允许用户复制
|
||||||
|
TextSelectableFilter textSelectableFilter;
|
||||||
|
a.installEventFilter(&textSelectableFilter);
|
||||||
|
|
||||||
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,13 @@
|
|||||||
<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>
|
||||||
|
<file>resources/images/expand_all.png</file>
|
||||||
|
<file>resources/images/collapse_all.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: 1.8 KiB |
|
After Width: | Height: | Size: 5.9 KiB |
|
After Width: | Height: | Size: 1.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,13 @@
|
|||||||
#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/configmanager.h"
|
||||||
|
#include "utils/logmanager.h"
|
||||||
|
#include "utils/Constants.h"
|
||||||
|
#include "utils/versionchecker.h"
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
@@ -16,42 +23,96 @@
|
|||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QDesktopServices>
|
||||||
|
#include <QUrl>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
const QString UPDATE_JSON = Constants::Urls::updateInfo();
|
||||||
|
const QString DOWNLOAD_PAGE = Constants::Urls::downloadPage();
|
||||||
|
const QString HELP_PAGE = Constants::Urls::helpPage();
|
||||||
|
}
|
||||||
|
|
||||||
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)
|
||||||
|
, m_totalFunctions(0)
|
||||||
|
, m_currentFunctionIndex(0)
|
||||||
|
, m_lastProgress(0)
|
||||||
{
|
{
|
||||||
initWindow();
|
initWindow();
|
||||||
initContent();
|
initContent();
|
||||||
|
|
||||||
// 获取应用程序目录
|
LogManager::instance()->initLogConfig(); // 先读取 change_code.ini 的 [log] 配置,再开始写日志
|
||||||
QString appDir = QCoreApplication::applicationDirPath();
|
LogManager::instance()->initLogFile();
|
||||||
|
LogManager::instance()->logInfo("应用程序启动");
|
||||||
|
|
||||||
|
loadConfigCache();
|
||||||
|
|
||||||
// 配置 Python 运行器 - 只使用打包好的 exe,路径是 uf2touft3/uf2touft3.exe
|
|
||||||
m_pythonRunner->setRunMode(PythonRunner::UsePackagedExe);
|
m_pythonRunner->setRunMode(PythonRunner::UsePackagedExe);
|
||||||
|
|
||||||
// 设置打包好的可执行文件路径和工作目录
|
QString exePath = Constants::toolExe();
|
||||||
QString exePath = appDir + "/uf2touft3/uf2touft3.exe";
|
QString workDir = Constants::toolDir();
|
||||||
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);
|
||||||
|
|
||||||
|
// 启动后延迟检查版本更新
|
||||||
|
QTimer::singleShot(3000, this, &MainWindow::checkForUpdates);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::loadConfigCache()
|
||||||
|
{
|
||||||
|
LogManager::instance()->log("正在加载配置缓存...");
|
||||||
|
|
||||||
|
// 1. 加载 config.ini 到内存缓存(ConfigManager::loadConfig 之前从未被调用过)
|
||||||
|
ConfigManager::instance()->loadConfig(QCoreApplication::applicationDirPath());
|
||||||
|
|
||||||
|
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 +121,51 @@ 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("代码检索", createCodeSearchPage(), m_funcConvertKey, ElaIconType::Cubes);
|
||||||
addPageNode("转码业务", createBatchConvertPage(), ElaIconType::FileCode);
|
|
||||||
addPageNode("功能搜索", createFunctionSearchPage(), ElaIconType::MagnifyingGlass);
|
addExpanderNode("功能查询", m_funcSearchKey, ElaIconType::MagnifyingGlass);
|
||||||
addFooterNode("帮助", createHelpPage(), helpKey, 0, ElaIconType::CircleQuestion);
|
addPageNode("UF20功能查询", createUF20FunctionSearchPage(), m_funcSearchKey, ElaIconType::MagnifyingGlassPlus);
|
||||||
addFooterNode("关于", createAboutPage(), aboutKey, 0, ElaIconType::User);
|
addPageNode("UFT3功能查询", createUFT3FunctionSearchPage(), m_funcSearchKey, ElaIconType::MagnifyingGlassPlus);
|
||||||
addFooterNode("设置", createSettingsPage(), settingKey, 0, ElaIconType::GearComplex);
|
expandNavigationNode(m_funcConvertKey);
|
||||||
|
|
||||||
|
addExpanderNode("数据映射", m_dataMappingKey, ElaIconType::TableList);
|
||||||
|
addPageNode("表替换", createTableMappingPage(), m_dataMappingKey, ElaIconType::TableColumns);
|
||||||
|
addPageNode("函数替换", createFunctionMappingPage(), m_dataMappingKey, ElaIconType::Function);
|
||||||
|
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::createCodeSearchPage()
|
||||||
|
{
|
||||||
|
_codeSearchPage = new CodeSearchPage;
|
||||||
|
return _codeSearchPage;
|
||||||
}
|
}
|
||||||
|
|
||||||
QWidget* MainWindow::createFunctionSearchPage()
|
QWidget* MainWindow::createFunctionSearchPage()
|
||||||
@@ -97,14 +173,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,58 +191,303 @@ QWidget* MainWindow::createSettingsPage()
|
|||||||
return new SettingsPage();
|
return new SettingsPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QWidget* MainWindow::createMetadataUpdatePage()
|
||||||
|
{
|
||||||
|
return new MetadataUpdatePage();
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget* MainWindow::createTableMappingPage()
|
||||||
|
{
|
||||||
|
return new TableMappingPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget* MainWindow::createFunctionMappingPage()
|
||||||
|
{
|
||||||
|
return new FunctionMappingPage();
|
||||||
|
}
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString appDir = QCoreApplication::applicationDirPath();
|
QString exePath = Constants::toolExe();
|
||||||
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 进度基准:BatchConvertPage 在开始时已将进度条置为 20(配置加载完成)
|
||||||
|
m_lastProgress = 20;
|
||||||
|
|
||||||
|
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("✓ 代码转换完成!");
|
||||||
|
if (_codeSearchPage) {
|
||||||
|
_codeSearchPage->refreshIndexSilent();
|
||||||
|
}
|
||||||
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);
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LogManager::instance()->log(output);
|
||||||
|
|
||||||
|
const QString text = output.trimmed();
|
||||||
|
|
||||||
|
// 计算本次输出对应的目标进度;-1 表示本次输出不含可识别的进度标记
|
||||||
|
int targetProgress = -1;
|
||||||
|
QString status;
|
||||||
|
|
||||||
|
// 1) 优先解析工具显式输出的 progress:xx / progress=xx
|
||||||
|
static const QRegularExpression progressRegExp(
|
||||||
|
R"(progress\s*[:=]\s*(\d+))", QRegularExpression::CaseInsensitiveOption);
|
||||||
|
QRegularExpressionMatch pm = progressRegExp.match(text);
|
||||||
|
if (pm.hasMatch()) {
|
||||||
|
targetProgress = pm.captured(1).toInt();
|
||||||
|
status = QString("转换中 %1%").arg(targetProgress);
|
||||||
|
} else {
|
||||||
|
// 2) 解析并行翻译进度 [ n/m](翻译阶段映射到 55~78)
|
||||||
|
// 注意时间戳 [2026-07-17 ...] 不含 '/' 不会误匹配
|
||||||
|
static const QRegularExpression stepRegExp(R"(\[\s*(\d+)\s*/\s*(\d+)\s*\])");
|
||||||
|
QRegularExpressionMatch stepMatch;
|
||||||
|
auto it = stepRegExp.globalMatch(text);
|
||||||
|
while (it.hasNext()) {
|
||||||
|
stepMatch = it.next(); // 取本段输出里最后一个 [n/m]
|
||||||
|
}
|
||||||
|
if (stepMatch.hasMatch()) {
|
||||||
|
int cur = stepMatch.captured(1).toInt();
|
||||||
|
int tot = stepMatch.captured(2).toInt();
|
||||||
|
if (tot > 0) {
|
||||||
|
targetProgress = 55 + (cur * 23) / tot;
|
||||||
|
status = QString("正在翻译文件 %1/%2").arg(cur).arg(tot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3) 解析流水线阶段标记(关键字命中取最大值,保证进度稳定推进)
|
||||||
|
if (targetProgress < 0) {
|
||||||
|
struct Marker { const char* key; int prog; const char* label; };
|
||||||
|
static const Marker markers[] = {
|
||||||
|
{"开始加载数据", 25, "正在加载数据..."},
|
||||||
|
{"配置文件加载完成", 30, "配置文件加载完成"},
|
||||||
|
{"元数据加载完成", 35, "元数据加载完成"},
|
||||||
|
{"全部数据加载完成", 42, "数据加载完成"},
|
||||||
|
{"数据初始化完成", 45, "数据初始化完成"},
|
||||||
|
{"校验完成", 52, "数据校验完成"},
|
||||||
|
{"翻译完成", 80, "代码翻译完成"},
|
||||||
|
{"后处理完成", 90, "后处理完成"},
|
||||||
|
{"输出完成", 96, "结果输出完成"},
|
||||||
|
{"转换流水线执行成功", 98, "转换流水线执行成功"},
|
||||||
|
{"转码完成", 98, "转码完成"},
|
||||||
|
};
|
||||||
|
for (const auto &m : markers) {
|
||||||
|
if (text.contains(QString::fromUtf8(m.key))) {
|
||||||
|
if (m.prog > targetProgress) {
|
||||||
|
targetProgress = m.prog;
|
||||||
|
status = QString::fromUtf8(m.label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_batchConvertPage) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 进度单调递增:只有更大的进度才会推进进度条,避免"一下长一下短"
|
||||||
|
if (targetProgress > m_lastProgress) {
|
||||||
|
m_lastProgress = targetProgress;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 状态文字:仅展示已识别的处理阶段;未识别的日志行不显示(保持上一次状态)
|
||||||
|
// 空 status 表示当前行无有效状态,BatchConvertPage 会保留上一次文字
|
||||||
|
m_batchConvertPage->onProgressUpdate(m_lastProgress, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
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::checkForUpdates()
|
||||||
|
{
|
||||||
|
auto *checker = new VersionChecker(this);
|
||||||
|
connect(checker, &VersionChecker::newVersionAvailable, this, &MainWindow::onNewVersionFound);
|
||||||
|
connect(checker, &VersionChecker::checkError, this, [](const QString &msg) {
|
||||||
|
LogManager::instance()->logInfo("版本检查: " + msg);
|
||||||
|
});
|
||||||
|
connect(checker, &VersionChecker::noUpdateNeeded, this, []() {
|
||||||
|
LogManager::instance()->logInfo("版本检查: 已是最新版本");
|
||||||
|
});
|
||||||
|
checker->check(UPDATE_JSON, Version::getVersionString());
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::onNewVersionFound(const QString &latestVersion, const QString &releaseNotes)
|
||||||
|
{
|
||||||
|
LogManager::instance()->logInfo(QString("发现新版本: %1").arg(latestVersion));
|
||||||
|
|
||||||
|
QString msg = QString("检测到新版本 %1\n当前版本: %2\n")
|
||||||
|
.arg(latestVersion, Version::getVersionString());
|
||||||
|
|
||||||
|
if (!releaseNotes.isEmpty()) {
|
||||||
|
msg += QString("\n──────── 更新说明 ────────\n%1\n").arg(releaseNotes);
|
||||||
|
}
|
||||||
|
|
||||||
|
msg += "\n是否前往下载最新版本?";
|
||||||
|
|
||||||
|
QMessageBox::StandardButton reply = QMessageBox::question(
|
||||||
|
this, "发现新版本", msg,
|
||||||
|
QMessageBox::Yes | QMessageBox::No);
|
||||||
|
|
||||||
|
if (reply == QMessageBox::Yes) {
|
||||||
|
QDesktopServices::openUrl(QUrl(DOWNLOAD_PAGE));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::onNavigationNodeClicked(ElaNavigationType::NavigationNodeType nodeType, QString nodeKey)
|
||||||
|
{
|
||||||
|
Q_UNUSED(nodeType);
|
||||||
|
if (nodeKey == m_helpKey) {
|
||||||
|
QDesktopServices::openUrl(QUrl(HELP_PAGE));
|
||||||
|
} else if (nodeKey == m_aboutKey) {
|
||||||
|
std::make_unique<AboutDialog>(this)->exec();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,14 +2,21 @@
|
|||||||
#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/codesearch/codesearchpage.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/pages/datamapping/tablemappingpage.h"
|
||||||
|
#include "src/pages/datamapping/functionmappingpage.h"
|
||||||
|
#include "src/utils/version.h"
|
||||||
|
|
||||||
class MainWindow : public ElaWindow
|
class MainWindow : public ElaWindow
|
||||||
{
|
{
|
||||||
@@ -24,18 +31,47 @@ private:
|
|||||||
void initContent();
|
void initContent();
|
||||||
|
|
||||||
QWidget* createBatchConvertPage();
|
QWidget* createBatchConvertPage();
|
||||||
|
QWidget* createCodeSearchPage();
|
||||||
QWidget* createFunctionSearchPage();
|
QWidget* createFunctionSearchPage();
|
||||||
QWidget* createHelpPage();
|
QWidget* createUF20FunctionSearchPage();
|
||||||
QWidget* createAboutPage();
|
QWidget* createUFT3FunctionSearchPage();
|
||||||
QWidget* createSettingsPage();
|
QWidget* createSettingsPage();
|
||||||
|
QWidget* createMetadataUpdatePage();
|
||||||
|
QWidget* createTableMappingPage();
|
||||||
|
QWidget* createFunctionMappingPage();
|
||||||
|
|
||||||
|
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 checkForUpdates();
|
||||||
|
void onNewVersionFound(const QString &latestVersion, const QString &releaseNotes);
|
||||||
|
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;
|
||||||
|
CodeSearchPage *_codeSearchPage;
|
||||||
|
|
||||||
|
int m_totalFunctions;
|
||||||
|
int m_currentFunctionIndex;
|
||||||
|
int m_lastProgress; // 已上报的最大进度,保证进度单调递增,避免进度条来回跳动
|
||||||
|
QStringList m_functionList;
|
||||||
|
QString m_helpKey;
|
||||||
|
QString m_aboutKey;
|
||||||
|
QString m_settingKey;
|
||||||
|
QString m_funcSearchKey;
|
||||||
|
QString m_funcConvertKey;
|
||||||
|
QString m_dataMappingKey;
|
||||||
};
|
};
|
||||||
|
|
||||||
#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;
|
||||||
|
}
|
||||||