import os import subprocess import sys import shutil import platform MAIN_FILE = "main_nicegui.py" # 【关键修改】提取应用名称为变量,确保打包目录和复制目录一致 APP_NAME = "尚城幼儿园幼儿学期发展报告" def copy_resources(): """ 将资源文件从项目根目录复制到 dist/APP_NAME 文件夹中 (与 exe 同级), 以便用户可以直接在 exe 旁边修改这些文件。 """ current_dir = os.path.dirname(os.path.abspath(__file__)) project_root = os.path.dirname(current_dir) # 【关键修改】目标目录改为 dist/APP_NAME # 这样资源文件才会出现在 exe 旁边,而不是 dist 根目录 dist_dir = os.path.join(current_dir, "dist", APP_NAME) print(f"\n--- 正在复制外部资源到 {dist_dir} ---") if not os.path.exists(dist_dir): print(f"错误: 目标文件夹不存在: {dist_dir}") print("请检查是否打包成功,或者是否使用了 --onedir 模式。") return # 这里的列表是【给用户看/改的】 resources_to_copy = [ ("config.toml", ""), ("fonts", "fonts"), ("data", "data"), ("templates", "templates"), ("public", "public"), ] for src_name, dest_name in resources_to_copy: src_path = os.path.join(project_root, src_name) dest_path = os.path.join(dist_dir, dest_name) try: if os.path.isfile(src_path): shutil.copy2(src_path, dest_path) print(f"✅ 已复制文件: {src_name}") elif os.path.isdir(src_path): # dirs_exist_ok=True 允许覆盖已存在的目录(Python 3.8+) shutil.copytree(src_path, dest_path, dirs_exist_ok=True) print(f"✅ 已复制目录: {src_name}") else: print(f"⚠️ 警告: 源文件不存在,跳过: {src_path}") except Exception as e: print(f"❌ 复制失败 {src_name}: {e}") def build_exe(): """使用 PyInstaller 打包""" sep = ';' if platform.system() == "Windows" else ':' # 内部资源 (打入 exe 内部的) resource_paths = [ f"../config.toml{sep}.", f"../fonts{sep}fonts", f"../templates{sep}templates", f"../ui/assets{sep}ui/assets", ] try: command = [ sys.executable, "-m", "PyInstaller", "--onedir", # 文件夹模式 "--windowed", # 隐藏控制台 (调试时建议先注释掉) f"--name={APP_NAME}", # 【关键修改】使用变量 "--clean", "--distpath=./dist", "--workpath=./build", "--icon=../public/icon.ico", "../" + MAIN_FILE ] for res in resource_paths: command.append(f"--add-data={res}") command.extend(["--hidden-import=nicegui", "--hidden-import=uvicorn"]) print("--- 开始打包 (PyInstaller) ---") subprocess.run(command, check=True, cwd=os.path.dirname(os.path.abspath(__file__))) print("\n--- PyInstaller 打包完成!---") # 打包完成后执行复制 copy_resources() # 打印最终 exe 的位置提示 exe_path = os.path.join("dist", APP_NAME, f"{APP_NAME}.exe") print(f"\n🎉 全部完成!可执行文件位于: {exe_path}") except subprocess.CalledProcessError as e: print(f"\n❌ 打包失败: {e}") except Exception as e: print(f"\n❌ 发生错误: {e}") if __name__ == "__main__": build_exe()