diff --git a/web/deploy.py b/web/deploy.py new file mode 100644 index 0000000..31e3b1d --- /dev/null +++ b/web/deploy.py @@ -0,0 +1,178 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +前端应用部署脚本 - 将构建好的文件上传到服务器 +使用方法: python deploy.py +""" + +import os +import sys +import subprocess +from pathlib import Path + +# 服务器配置 +SERVER_IP = "101.200.208.45" +USERNAME = "root" +REMOTE_PATH = "/data/www/emotion-museum" + +# 本地路径 +SCRIPT_DIR = Path(__file__).parent.absolute() +DIST_DIR = SCRIPT_DIR / "dist" + + +class Colors: + """终端颜色""" + GREEN = '\033[32m' + RED = '\033[31m' + RESET = '\033[0m' + + +def log_info(msg): + """打印信息日志""" + print(f"{Colors.GREEN}✅{Colors.RESET} {msg}") + + +def log_error(msg): + """打印错误日志""" + print(f"{Colors.RED}❌{Colors.RESET} {msg}") + + +def log_step(msg): + """打印步骤日志""" + print(f"📦 {msg}") + + +def run_command(cmd, cwd=None, shell=True, capture=True, timeout=None): + """执行本地命令""" + try: + if capture: + result = subprocess.run( + cmd, cwd=cwd, shell=shell, + capture_output=True, text=True, timeout=timeout + ) + return result.returncode == 0, result.stdout, result.stderr + else: + result = subprocess.run(cmd, cwd=cwd, shell=shell, timeout=timeout) + return result.returncode == 0, "", "" + except subprocess.TimeoutExpired: + return False, "", "命令执行超时" + except Exception as e: + return False, "", str(e) + + +def scp_upload(local_path, remote_path, recursive=False): + """通过SCP上传文件或目录""" + r_flag = "-r" if recursive else "" + scp_cmd = f'scp -o ConnectTimeout=10 -o BatchMode=yes {r_flag} "{local_path}" {USERNAME}@{SERVER_IP}:{remote_path}' + try: + result = subprocess.run( + scp_cmd, shell=True, capture_output=True, text=True, timeout=120 + ) + if result.returncode != 0: + log_error(f"SCP上传失败: {result.stderr}") + return False + return True + except subprocess.TimeoutExpired: + log_error("SCP上传超时") + return False + except Exception as e: + log_error(f"SCP上传异常: {e}") + return False + + +def check_npm(): + """检查npm是否安装""" + success, _, _ = run_command("npm --version") + if not success: + log_error("错误: 未找到npm命令,请先安装Node.js") + sys.exit(1) + + +def build_project(): + """构建项目""" + log_step("开始构建前端项目...") + + os.chdir(SCRIPT_DIR) + + success, _, _ = run_command("npm run build", capture=False) + if not success: + log_error("前端项目构建失败,请检查代码") + sys.exit(1) + + log_info("前端项目构建成功") + + +def verify_dist(): + """验证dist目录是否存在""" + if not DIST_DIR.exists(): + log_error("错误: 构建后dist目录仍不存在,请检查构建配置") + sys.exit(1) + + index_file = DIST_DIR / "index.html" + assets_dir = DIST_DIR / "assets" + + if not index_file.exists(): + log_error("错误: dist/index.html 不存在") + sys.exit(1) + + if not assets_dir.exists(): + log_error("错误: dist/assets 目录不存在") + sys.exit(1) + + +def upload_files(): + """上传文件到服务器""" + print(f"正在上传文件到服务器 {SERVER_IP}...") + + # 上传 index.html + index_file = DIST_DIR / "index.html" + if not scp_upload(index_file, f"{REMOTE_PATH}/"): + return False + + # 上传 assets 目录 + assets_dir = DIST_DIR / "assets" + if not scp_upload(assets_dir, f"{REMOTE_PATH}/", recursive=True): + return False + + # 上传测试文件(如果存在) + test_file = DIST_DIR / "test-login-redirect.html" + if test_file.exists(): + # 上传所有 test-*.html 文件 + for f in DIST_DIR.glob("test-*.html"): + scp_upload(f, f"{REMOTE_PATH}/") + + return True + + +def deploy(): + """执行部署""" + print("开始部署前端应用到服务器...") + + # 检查npm + check_npm() + + # 构建项目 + build_project() + + # 验证构建结果 + verify_dist() + + # 上传文件 + if upload_files(): + log_info("部署完成!") + print(f"📱 访问地址: http://{SERVER_IP}/emotion-museum/") + else: + log_error("部署失败,请检查:") + print("1. 服务器IP地址是否正确") + print("2. SSH密钥是否配置正确") + print("3. 服务器目录权限是否正确") + sys.exit(1) + + +def main(): + """主函数""" + deploy() + + +if __name__ == "__main__": + main()