v1.0.0 高考志愿门户完整修复
变更摘要: - [fix] 清理根目录 index.html 遗留代码(questionnaire-error + retryLoad 移除) - [fix] 副标题同步更新为自估591分 + 候选志愿546条数据校准 - [fix] 页脚注入版本号 v1.0.0 - [fix] 部署版 index.html: 取消家长标签,统一 filler-tianheng - [fix] Dashboard 文案修正(4份→2份线上问卷) - [fix] 清理冗余部署脚本(v1-v4归档至 archived_scripts/) - [fix] 等效位次工具纳入 deploy 目录 - [chore] .gitignore 初始化 - [init] Git 仓库初始化
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
"""
|
||||
部署汇总系统到 NAS — 含完成后端重构
|
||||
上传文件 → 删旧DB → 重建容器
|
||||
"""
|
||||
import paramiko, base64, os, sys, time
|
||||
|
||||
NAS_HOST = "100.85.152.112"
|
||||
NAS_USER = "simon"
|
||||
NAS_PASS = "Nas82829330"
|
||||
NAS_PATH = "/volume1/docker/gaokao-portal"
|
||||
SUDO_DOCKER = "echo 'Nas82829330' | sudo -S /usr/local/bin/docker"
|
||||
|
||||
PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
FILES_TO_DEPLOY = [
|
||||
("deploy/backend/app.py", "backend/app.py"),
|
||||
("deploy/backend/seed_data.py", "backend/seed_data.py"),
|
||||
("deploy/nginx/html/index.html", "nginx/html/index.html"),
|
||||
("deploy/nginx/html/dashboard.html", "nginx/html/dashboard.html"),
|
||||
("deploy/nginx/html/summary.html", "nginx/html/summary.html"),
|
||||
("deploy/nginx/html/css/style.css", "nginx/html/css/style.css"),
|
||||
("deploy/nginx/html/questionnaire.html", "nginx/html/questionnaire.html"),
|
||||
("deploy/nginx/html/霍兰德职业兴趣测试-自评版.html", "nginx/html/霍兰德职业兴趣测试-自评版.html"),
|
||||
("deploy/nginx/html/MBTI性格测试-自评版.html", "nginx/html/MBTI性格测试-自评版.html"),
|
||||
]
|
||||
|
||||
def run_cmd(client, cmd, desc, timeout=60):
|
||||
print(f" [{desc}] ", end="", flush=True)
|
||||
stdin, stdout, stderr = client.exec_command(cmd, timeout=timeout)
|
||||
out = stdout.read().decode("utf-8", errors="replace").strip()
|
||||
err = stderr.read().decode("utf-8", errors="replace").strip()
|
||||
status = stdout.channel.recv_exit_status()
|
||||
if status != 0 and err:
|
||||
print(f"WARN (exit={status})\n {err[:200]}")
|
||||
elif out:
|
||||
print(f"OK\n {out[:200]}")
|
||||
else:
|
||||
print("OK")
|
||||
return out, err, status
|
||||
|
||||
def upload_base64(client, local_rel, remote_rel):
|
||||
"""用 base64 编码上传文件到 NAS,避免中文路径编码问题"""
|
||||
local_path = os.path.join(PROJECT_ROOT, local_rel)
|
||||
remote_path = f"{NAS_PATH}/{remote_rel}"
|
||||
|
||||
with open(local_path, 'rb') as f:
|
||||
data = base64.b64encode(f.read()).decode()
|
||||
|
||||
print(f" 上传: {local_rel} → {remote_path} ({len(data)} bytes base64)", flush=True)
|
||||
channel = client.get_transport().open_session()
|
||||
channel.exec_command(f"base64 -d > '{remote_path}' 2>/dev/null && echo OK || echo FAIL")
|
||||
channel.sendall(data.encode() + b'\n')
|
||||
channel.shutdown_write()
|
||||
result = channel.recv(1024).decode().strip()
|
||||
channel.close()
|
||||
print(f" 结果: {result}")
|
||||
|
||||
def main():
|
||||
print("=" * 60)
|
||||
print("部署汇总系统到 NAS")
|
||||
print("=" * 60)
|
||||
|
||||
client = paramiko.SSHClient()
|
||||
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
|
||||
try:
|
||||
print(f"\n🔌 连接 {NAS_HOST}:22 ...")
|
||||
client.connect(NAS_HOST, 22, NAS_USER, NAS_PASS, timeout=15)
|
||||
print("✅ 已连接")
|
||||
|
||||
# 1. 上传所有文件
|
||||
print("\n📤 上传文件...")
|
||||
for local_rel, remote_rel in FILES_TO_DEPLOY:
|
||||
upload_base64(client, local_rel, remote_rel)
|
||||
|
||||
# 2. 删除旧数据库(重新 seed 以获得 target_user 列)
|
||||
print("\n🗑️ 删除旧数据库...")
|
||||
run_cmd(client, f"rm -f {NAS_PATH}/backend/data/gaokao.db", "删除 gaokao.db")
|
||||
|
||||
# 3. 重建并启动容器
|
||||
print("\n🔨 重建容器(build + up)...")
|
||||
run_cmd(client, f"cd '{NAS_PATH}' && {SUDO_DOCKER} compose down 2>&1", "停止旧容器", timeout=60)
|
||||
|
||||
out, err, status = run_cmd(
|
||||
client,
|
||||
f"cd '{NAS_PATH}' && {SUDO_DOCKER} compose up -d --build 2>&1",
|
||||
"构建并启动",
|
||||
timeout=180
|
||||
)
|
||||
|
||||
# 等待容器就绪
|
||||
print("\n⏳ 等待容器就绪...")
|
||||
for i in range(8):
|
||||
time.sleep(5)
|
||||
out, _, _ = run_cmd(
|
||||
client,
|
||||
f"cd '{NAS_PATH}' && {SUDO_DOCKER} compose ps --format json 2>&1",
|
||||
f"状态检查 {i+1}/8"
|
||||
)
|
||||
if '"running"' in out:
|
||||
print(" ✅ 检测到运行中容器")
|
||||
break
|
||||
|
||||
# 4. 验证
|
||||
print("\n🧪 验证 API...")
|
||||
run_cmd(client, f"curl -s http://localhost:8080/api/completion-status | python3 -m json.tool 2>&1 | head -20", "completion-status API")
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("✅ 部署完成")
|
||||
print(f" 内网访问: http://100.85.152.112:8080")
|
||||
print(f" 问卷面板: http://100.85.152.112:8080/dashboard.html")
|
||||
print(f" 汇总报告: http://100.85.152.112:8080/summary.html")
|
||||
print("=" * 60)
|
||||
|
||||
except Exception as e:
|
||||
print(f"\n❌ 错误: {e}")
|
||||
sys.exit(1)
|
||||
finally:
|
||||
client.close()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user