Todo: 集成多平台 解决因SaiNiu线程抢占资源问题 本地提交测试环境打包 和 正式打包脚本与正式环境打包bat

This commit is contained in:
2025-09-17 17:48:35 +08:00
parent 256e6c21a5
commit 8b9fc925fa
11 changed files with 2020 additions and 610 deletions

300
quick_build.py Normal file
View File

@@ -0,0 +1,300 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
快速打包脚本 - 避免spec文件缩进问题
"""
import os
import subprocess
import shutil
def clean_build():
"""清理构建目录"""
print("🧹 清理旧的构建文件...")
# 跳过进程结束步骤,避免影响当前脚本运行
print("🔄 跳过进程结束步骤(避免脚本自终止)...")
# 等待少量时间确保文件句柄释放
import time
print("⏳ 等待文件句柄释放...")
time.sleep(0.5)
dirs_to_clean = ['dist', 'build']
for dir_name in dirs_to_clean:
print(f"🔍 检查目录: {dir_name}")
if os.path.exists(dir_name):
try:
print(f"🗑️ 正在删除: {dir_name}")
shutil.rmtree(dir_name)
print(f"✅ 已删除: {dir_name}")
except PermissionError as e:
print(f"⚠️ {dir_name} 被占用,尝试强制删除... 错误: {e}")
try:
subprocess.run(['rd', '/s', '/q', dir_name],
shell=True, check=True)
print(f"✅ 强制删除成功: {dir_name}")
except Exception as e2:
print(f"❌ 无法删除 {dir_name}: {e2}")
print("💡 请手动删除或运行 force_clean_dist.bat")
except Exception as e:
print(f"❌ 删除 {dir_name} 时出错: {e}")
else:
print(f" {dir_name} 不存在,跳过")
print("✅ 清理阶段完成")
def build_with_command():
"""使用命令行参数直接打包"""
print("🚀 开始打包...")
cmd = [
'pyinstaller',
'--name=main',
'--onedir', # 相当于 --exclude-binaries
'--windowed', # 相当于 -w
'--add-data=config.py;.',
'--add-data=exe_file_logger.py;.',
'--add-data=Utils/PythonNew32;Utils/PythonNew32',
'--add-data=Utils/JD;Utils/JD',
'--add-data=Utils/Dy;Utils/Dy',
'--add-data=Utils/Pdd;Utils/Pdd',
'--add-data=Utils/QianNiu;Utils/QianNiu',
'--add-data=Utils/message_models.py;Utils',
'--add-data=Utils/__init__.py;Utils',
'--add-data=WebSocket;WebSocket',
'--add-data=static;static',
'--add-binary=Utils/PythonNew32/SaiNiuApi.dll;Utils/PythonNew32',
'--add-binary=Utils/PythonNew32/SaiNiuSys.dll;Utils/PythonNew32',
'--add-binary=Utils/PythonNew32/SaiNiuServer.dll;Utils/PythonNew32',
'--add-binary=Utils/PythonNew32/python32.exe;Utils/PythonNew32',
'--add-binary=Utils/PythonNew32/python313.dll;Utils/PythonNew32',
'--add-binary=Utils/PythonNew32/vcruntime140.dll;Utils/PythonNew32',
'--hidden-import=PyQt5.QtCore',
'--hidden-import=PyQt5.QtGui',
'--hidden-import=PyQt5.QtWidgets',
'--hidden-import=websockets',
'--hidden-import=asyncio',
'--hidden-import=Utils.QianNiu.QianNiuUtils',
'--hidden-import=Utils.JD.JdUtils',
'--hidden-import=Utils.Dy.DyUtils',
'--hidden-import=Utils.Pdd.PddUtils',
'--hidden-import=WebSocket.backend_singleton',
'--hidden-import=WebSocket.BackendClient',
'main.py'
]
try:
print(f"执行命令: {' '.join(cmd[:5])}... (共{len(cmd)}个参数)")
result = subprocess.run(cmd, capture_output=True, text=True, encoding='utf-8')
if result.returncode == 0:
print("✅ 打包成功!")
print("📁 打包结果: dist/main/")
# 重命名目录
if os.path.exists('dist/main'):
try:
if os.path.exists('dist/MultiPlatformGUI'):
shutil.rmtree('dist/MultiPlatformGUI')
os.rename('dist/main', 'dist/MultiPlatformGUI')
print("✅ 已重命名为: dist/MultiPlatformGUI/")
except Exception as e:
print(f"⚠️ 重命名失败: {e}")
print("💡 可以手动重命名: dist/main -> dist/MultiPlatformGUI")
print("📁 当前可用路径: dist/main/")
# 创建使用说明
try:
create_usage_guide()
except:
create_usage_guide_fallback()
return True
else:
print("❌ 打包失败")
if result.stderr:
print("错误信息:")
print(result.stderr)
return False
except Exception as e:
print(f"❌ 打包过程出错: {e}")
return False
def create_usage_guide():
"""创建使用说明"""
guide_content = r"""# 多平台客服GUI使用说明
## 🚀 运行方式
```
cd dist/MultiPlatformGUI
.\main.exe
```
## 📝 支持平台
- 千牛 (淘宝)
- 京东 (JD)
- 抖音 (DY)
- 拼多多 (PDD)
## 🎯 特点
- 支持多平台同时监听
- 无平台间冲突
- 自动生成日志文件
## 📁 文件结构
```
MultiPlatformGUI/
├── main.exe # 主程序
├── qianniu_exe_*.log # 运行日志
└── _internal/ # 程序依赖文件
├── Utils/
│ ├── PythonNew32/ # 千牛DLL文件
│ ├── JD/ # 京东模块
│ ├── Dy/ # 抖音模块
│ └── Pdd/ # 拼多多模块
└── ...
```
"""
try:
with open('dist/MultiPlatformGUI/使用说明.txt', 'w', encoding='utf-8') as f:
f.write(guide_content)
print("✅ 已生成使用说明文件")
except:
print("⚠️ 使用说明生成失败")
def create_usage_guide_fallback():
"""备用使用说明生成"""
guide_content = r"""# 多平台客服GUI使用说明
## 🚀 运行方式
```
cd dist/main
.\main.exe
```
## 📝 支持平台
- 千牛 (淘宝)
- 京东 (JD)
- 抖音 (DY)
- 拼多多 (PDD)
## 🎯 特点
- 支持多平台同时监听
- 无平台间冲突
- 自动生成日志文件
"""
try:
with open('dist/main/使用说明.txt', 'w', encoding='utf-8') as f:
f.write(guide_content)
print("✅ 已生成使用说明文件 (备用路径)")
except:
print("⚠️ 使用说明生成失败")
def verify_result():
"""验证打包结果"""
print("\n🔍 验证打包结果...")
# 先检查MultiPlatformGUI再检查main目录
base_dirs = ["dist/MultiPlatformGUI", "dist/main"]
for base_dir in base_dirs:
if os.path.exists(base_dir):
exe_path = f"{base_dir}/main.exe"
dll_path = f"{base_dir}/_internal/Utils/PythonNew32/SaiNiuApi.dll"
if os.path.exists(exe_path):
size = os.path.getsize(exe_path)
print(f"✅ 主程序: {exe_path} ({size:,} bytes)")
if os.path.exists(dll_path):
dll_size = os.path.getsize(dll_path)
print(f"✅ 千牛DLL: SaiNiuApi.dll ({dll_size:,} bytes)")
print(f"📁 有效路径: {base_dir}/")
print("✅ 验证通过")
return True
else:
print("❌ 千牛DLL不存在")
else:
print(f"{exe_path} 不存在")
print("❌ 未找到有效的打包结果")
return False
def main():
"""主函数"""
print("🔥 多平台客服GUI快速打包工具")
print("=" * 60)
try:
# 检查依赖
print("🔍 检查打包依赖...")
try:
import subprocess
result = subprocess.run(['pyinstaller', '--version'],
capture_output=True, text=True, check=False)
if result.returncode == 0:
print(f"✅ PyInstaller 版本: {result.stdout.strip()}")
else:
print("❌ PyInstaller 未安装或不可用")
print("💡 请运行: pip install pyinstaller")
return False
except Exception as e:
print(f"❌ 检查PyInstaller时出错: {e}")
return False
# 清理
print("\n📍 开始清理阶段...")
clean_build()
print("📍 清理阶段完成")
# 打包
print("\n📍 开始打包阶段...")
if not build_with_command():
print("❌ 打包阶段失败")
return False
print("📍 打包阶段完成")
# 验证
print("\n📍 开始验证阶段...")
if not verify_result():
print("❌ 验证阶段失败")
return False
print("📍 验证阶段完成")
print("\n" + "=" * 60)
print("🎉 打包完成!")
# 智能显示可用路径
if os.path.exists("dist/MultiPlatformGUI"):
print("📁 打包结果: dist/MultiPlatformGUI/")
print("🚀 运行方式: cd dist/MultiPlatformGUI && .\\main.exe")
elif os.path.exists("dist/main"):
print("📁 打包结果: dist/main/")
print("🚀 运行方式: cd dist/main && .\\main.exe")
print("💡 提示: 可手动重命名为 MultiPlatformGUI")
print("=" * 60)
return True
except Exception as e:
print(f"❌ 打包失败: {e}")
return False
if __name__ == "__main__":
success = main()
if success:
print("\n✅ 可以开始测试了!")
else:
print("\n❌ 请检查错误信息并重试")