diff --git a/etl_billiards/ETL_Manager.spec b/etl_billiards/ETL_Manager.spec deleted file mode 100644 index 66892de..0000000 --- a/etl_billiards/ETL_Manager.spec +++ /dev/null @@ -1,44 +0,0 @@ -# -*- mode: python ; coding: utf-8 -*- - - -a = Analysis( - ['C:\\dev\\LLTQ\\ETL\\feiqiu-ETL\\etl_billiards\\gui\\main.py'], - pathex=[], - binaries=[], - datas=[('C:\\dev\\LLTQ\\ETL\\feiqiu-ETL\\etl_billiards\\gui\\resources', 'gui/resources'), ('C:\\dev\\LLTQ\\ETL\\feiqiu-ETL\\etl_billiards\\database\\schema_dwd_doc.sql', 'database'), ('C:\\dev\\LLTQ\\ETL\\feiqiu-ETL\\etl_billiards\\database\\schema_dws.sql', 'database'), ('C:\\dev\\LLTQ\\ETL\\feiqiu-ETL\\etl_billiards\\database\\schema_etl_admin.sql', 'database'), ('C:\\dev\\LLTQ\\ETL\\feiqiu-ETL\\etl_billiards\\database\\schema_ODS_doc.sql', 'database'), ('C:\\dev\\LLTQ\\ETL\\feiqiu-ETL\\etl_billiards\\database\\seed_ods_tasks.sql', 'database'), ('C:\\dev\\LLTQ\\ETL\\feiqiu-ETL\\etl_billiards\\database\\seed_scheduler_tasks.sql', 'database')], - hiddenimports=['PySide6.QtCore', 'PySide6.QtGui', 'PySide6.QtWidgets', 'psycopg2', 'psycopg2.extras', 'psycopg2.extensions', 'gui.models.task_model', 'gui.models.schedule_model', 'gui.utils.cli_builder', 'gui.utils.config_helper', 'gui.utils.app_settings', 'gui.workers.task_worker', 'gui.workers.db_worker', 'gui.widgets.settings_dialog'], - hookspath=[], - hooksconfig={}, - runtime_hooks=[], - excludes=['matplotlib', 'numpy', 'pandas', 'scipy', 'PIL', 'cv2', 'tkinter'], - noarchive=False, - optimize=0, -) -pyz = PYZ(a.pure) - -exe = EXE( - pyz, - a.scripts, - [], - exclude_binaries=True, - name='ETL_Manager', - debug=False, - bootloader_ignore_signals=False, - strip=False, - upx=True, - console=False, - disable_windowed_traceback=False, - argv_emulation=False, - target_arch=None, - codesign_identity=None, - entitlements_file=None, -) -coll = COLLECT( - exe, - a.binaries, - a.datas, - strip=False, - upx=True, - upx_exclude=[], - name='ETL_Manager', -) diff --git a/etl_billiards/build_exe.py b/etl_billiards/build_exe.py index 217c201..c7f3d35 100644 --- a/etl_billiards/build_exe.py +++ b/etl_billiards/build_exe.py @@ -140,6 +140,9 @@ def build_exe(onefile: bool = False, console: bool = False): result = subprocess.run(cmd, cwd=str(project_root)) if result.returncode == 0: + # 打包后精简:删除不需要的文件 + slim_dist(project_root / "dist" / "ETL_Manager" / "_internal") + print() print("=" * 50) print("打包成功!") @@ -151,6 +154,77 @@ def build_exe(onefile: bool = False, console: bool = False): sys.exit(1) +def slim_dist(internal_dir: Path): + """精简打包后的文件,删除不需要的内容""" + if not internal_dir.exists(): + return + + print() + print("精简打包文件...") + + removed_size = 0 + + # 1. 删除不需要的翻译文件(只保留中文和英文) + translations_dir = internal_dir / "PySide6" / "translations" + if translations_dir.exists(): + keep_langs = {"zh_CN", "zh_TW", "en"} + for qm_file in translations_dir.glob("*.qm"): + # 检查是否是需要保留的语言 + keep = False + for lang in keep_langs: + if lang in qm_file.name: + keep = True + break + if not keep: + size = qm_file.stat().st_size + qm_file.unlink() + removed_size += size + + # 2. 删除 opengl32sw.dll(软件渲染,20MB,通常不需要) + opengl_sw = internal_dir / "PySide6" / "opengl32sw.dll" + if opengl_sw.exists(): + size = opengl_sw.stat().st_size + opengl_sw.unlink() + removed_size += size + print(f" 删除: opengl32sw.dll ({size / 1024 / 1024:.1f} MB)") + + # 3. 删除不需要的 Qt 模块 DLL(如果存在) + unnecessary_dlls = [ + "Qt6Pdf.dll", # PDF 支持 + "Qt6Qml.dll", # QML 引擎 + "Qt6QmlMeta.dll", + "Qt6QmlModels.dll", + "Qt6QmlWorkerScript.dll", + "Qt6Quick.dll", # Quick UI + "Qt6VirtualKeyboard.dll", # 虚拟键盘 + ] + pyside6_dir = internal_dir / "PySide6" + for dll_name in unnecessary_dlls: + dll_path = pyside6_dir / dll_name + if dll_path.exists(): + size = dll_path.stat().st_size + dll_path.unlink() + removed_size += size + print(f" 删除: {dll_name} ({size / 1024 / 1024:.1f} MB)") + + # 4. 删除不需要的插件目录 + unnecessary_plugins = [ + "networkinformation", # 网络信息 + "tls", # TLS 支持(数据库已有) + ] + plugins_dir = pyside6_dir / "plugins" + if plugins_dir.exists(): + for plugin_name in unnecessary_plugins: + plugin_path = plugins_dir / plugin_name + if plugin_path.exists(): + size = sum(f.stat().st_size for f in plugin_path.rglob("*") if f.is_file()) + shutil.rmtree(plugin_path) + removed_size += size + print(f" 删除插件: {plugin_name}") + + print(f"共节省: {removed_size / 1024 / 1024:.1f} MB") + + def main(): """主函数""" import argparse diff --git a/etl_billiards/启动ETL管理器.bat b/etl_billiards/启动ETL管理器.bat new file mode 100644 index 0000000..b286a5e --- /dev/null +++ b/etl_billiards/启动ETL管理器.bat @@ -0,0 +1,10 @@ +@echo off +chcp 65001 >nul +cd /d "%~dp0" +python -m gui.main +if errorlevel 1 ( + echo. + echo 启动失败!请检查是否已安装 Python 和依赖。 + echo 安装依赖命令: pip install -r ..\requirements.txt + pause +) diff --git a/etl_billiards/安装依赖.bat b/etl_billiards/安装依赖.bat new file mode 100644 index 0000000..1c69a60 --- /dev/null +++ b/etl_billiards/安装依赖.bat @@ -0,0 +1,36 @@ +@echo off +chcp 65001 >nul +echo ======================================== +echo ETL Manager 依赖安装脚本 +echo ======================================== +echo. + +:: 检查 Python +python --version >nul 2>&1 +if errorlevel 1 ( + echo [错误] 未检测到 Python,请先安装 Python 3.10+ + echo 下载地址: https://www.python.org/downloads/ + pause + exit /b 1 +) + +echo [1/2] 检测到 Python: +python --version +echo. + +echo [2/2] 安装依赖... +pip install -r ..\requirements.txt + +if errorlevel 1 ( + echo. + echo [错误] 依赖安装失败,请检查网络连接 + pause + exit /b 1 +) + +echo. +echo ======================================== +echo 安装完成! +echo 双击 "启动ETL管理器.bat" 运行程序 +echo ======================================== +pause diff --git a/requirements.txt b/requirements.txt index b903978..acc0f26 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,12 @@ +# ETL 核心依赖 requests psycopg2-binary python-dateutil tzdata +python-dotenv + +# GUI 依赖 +PySide6>=6.5.0 + +# Web API(可选) flask>=2.3