diff --git a/.gitignore b/.gitignore index 38dd725..171258a 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,7 @@ frontend/node_modules/.vite/ # 本地启动/部署日志 backend.log frontend.log +.run/ # 临时文件 *.swp diff --git a/frontend/src/components/AppShell.vue b/frontend/src/components/AppShell.vue index 160e19b..52f8dee 100644 --- a/frontend/src/components/AppShell.vue +++ b/frontend/src/components/AppShell.vue @@ -29,18 +29,6 @@ > Gallery - - - - - - Star -
diff --git a/frontend/vite.config.js b/frontend/vite.config.js index 00aec21..2443820 100644 --- a/frontend/vite.config.js +++ b/frontend/vite.config.js @@ -4,10 +4,11 @@ import vue from '@vitejs/plugin-vue' export default defineConfig({ plugins: [vue()], server: { - port: 3000, + port: 31400, + strictPort: true, proxy: { '/api': { - target: 'http://localhost:8000', + target: 'http://localhost:31401', changeOrigin: true, }, }, diff --git a/start.sh b/start.sh index 8e8dd76..aaeca9c 100755 --- a/start.sh +++ b/start.sh @@ -1,54 +1,60 @@ #!/usr/bin/env bash -# MiroSociety 启动脚本 (开发模式) +# MiroSociety 后台启动 (开发模式) # 前置: 请先执行 ./deploy.sh 安装依赖 # 前端: http://localhost:31400 后端: http://localhost:31401 +# +# 直接 ./start.sh 即可启动;已在跑会自动重启。 set -euo pipefail +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" FRONTEND_PORT=31400 BACKEND_PORT=31401 -# 解析到脚本所在目录,并使用绝对路径避免子 shell cd 后路径重复 -SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" VENV_DIR="$SCRIPT_DIR/backend/.venv" BACKEND_DIR="$SCRIPT_DIR/backend" FRONTEND_DIR="$SCRIPT_DIR/frontend" +RUN_DIR="$SCRIPT_DIR/.run" +BACKEND_PID_FILE="$RUN_DIR/backend.pid" +FRONTEND_PID_FILE="$RUN_DIR/frontend.pid" +BACKEND_LOG="$SCRIPT_DIR/backend.log" +FRONTEND_LOG="$SCRIPT_DIR/frontend.log" -# 切到脚本所在目录,确保相对路径正确 -cd "$(dirname "$0")" +cd "$SCRIPT_DIR" # --- 颜色 --- -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -NC='\033[0m' - +RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m' log() { echo -e "${GREEN}[start.sh]${NC} $*"; } warn() { echo -e "${YELLOW}[start.sh]${NC} $*"; } err() { echo -e "${RED}[start.sh]${NC} $*" >&2; } -# --- 检查命令依赖 --- +# --- 检查依赖 --- for cmd in lsof npm node curl; do - if ! command -v "$cmd" >/dev/null 2>&1; then - err "缺少依赖命令: $cmd" - exit 1 - fi + command -v "$cmd" >/dev/null 2>&1 || { err "缺少依赖命令: $cmd"; exit 1; } done +[[ -x "$VENV_DIR/bin/python3" ]] || { err "未检测到 $VENV_DIR/bin/python3,请先执行 ./deploy.sh"; exit 1; } +"$VENV_DIR/bin/python3" -c "import uvicorn" 2>/dev/null || { err "venv 缺少 uvicorn,请先执行 ./deploy.sh"; exit 1; } +[[ -d "$FRONTEND_DIR/node_modules" ]] || { err "未检测到 frontend/node_modules,请先执行 ./deploy.sh"; exit 1; } + +mkdir -p "$RUN_DIR" + +# --- 已在跑 → 先杀 --- +read_pid() { [[ -f "$1" ]] && cat "$1" || echo ""; } +kill_pid_file() { + local pid_file="$1" label="$2" + local pid + pid=$(read_pid "$pid_file") + if [[ -n "$pid" ]] && kill -0 "$pid" 2>/dev/null; then + kill "$pid" 2>/dev/null || true + for _ in $(seq 1 10); do + kill -0 "$pid" 2>/dev/null || break + sleep 0.3 + done + kill -9 "$pid" 2>/dev/null || true + log "$label 已停止 (pid=$pid)" + fi + rm -f "$pid_file" +} -# --- 检查依赖是否已部署 --- -if [[ ! -x "$VENV_DIR/bin/python3" ]]; then - err "未检测到 $VENV_DIR/bin/python3,请先执行 ./deploy.sh" - exit 1 -fi -if ! "$VENV_DIR/bin/python3" -c "import uvicorn" 2>/dev/null; then - err "venv 缺少 uvicorn,请先执行 ./deploy.sh" - exit 1 -fi -if [[ ! -d frontend/node_modules ]]; then - err "未检测到 frontend/node_modules,请先执行 ./deploy.sh" - exit 1 -fi - -# --- 释放端口: kill 占用进程 --- free_port() { local port="$1" local pids @@ -61,39 +67,35 @@ free_port() { fi } -free_port "$FRONTEND_PORT" +# --- 启动后端 --- free_port "$BACKEND_PORT" - -# --- 清理函数: 退出时杀掉所有子进程 --- -cleanup() { - log "正在关闭子进程..." - if [[ -n "${BACKEND_PID:-}" ]]; then kill -9 "$BACKEND_PID" 2>/dev/null || true; fi - if [[ -n "${FRONTEND_PID:-}" ]]; then kill -9 "$FRONTEND_PID" 2>/dev/null || true; fi - exit 0 -} -trap cleanup INT TERM EXIT - -# --- 启动后端 (后台, 使用 venv 内的 uvicorn) --- -log "启动后端 FastAPI @ :$BACKEND_PORT" +kill_pid_file "$BACKEND_PID_FILE" "后端" +log "启动后端 FastAPI @ :$BACKEND_PORT (后台)" +: >"$BACKEND_LOG" ( cd "$BACKEND_DIR" HOST=0.0.0.0 PORT="$BACKEND_PORT" \ - exec "$VENV_DIR/bin/python3" -m uvicorn app.main:app --host 0.0.0.0 --port "$BACKEND_PORT" -) >"$SCRIPT_DIR/backend.log" 2>&1 & -BACKEND_PID=$! - -# --- 启动前端 (后台, 端口固定为 31400) --- -log "启动前端 Vite @ :$FRONTEND_PORT" + nohup "$VENV_DIR/bin/python3" -m uvicorn app.main:app \ + --host 0.0.0.0 --port "$BACKEND_PORT" \ + >>"$BACKEND_LOG" 2>&1 & + echo $! >"$BACKEND_PID_FILE" + disown || true +) + +# --- 启动前端 --- +free_port "$FRONTEND_PORT" +kill_pid_file "$FRONTEND_PID_FILE" "前端" +log "启动前端 Vite @ :$FRONTEND_PORT (后台)" +: >"$FRONTEND_LOG" ( cd "$FRONTEND_DIR" - npx vite --port "$FRONTEND_PORT" --strictPort -) >"$SCRIPT_DIR/frontend.log" 2>&1 & -FRONTEND_PID=$! - -log "后端 pid=$BACKEND_PID 前端 pid=$FRONTEND_PID" -log "等待服务就绪..." + nohup npx vite >>"$FRONTEND_LOG" 2>&1 & + echo $! >"$FRONTEND_PID_FILE" + disown || true +) # --- 健康检查 --- +log "等待服务就绪..." wait_for() { local url="$1" name="$2" for _ in $(seq 1 30); do @@ -107,16 +109,11 @@ wait_for() { return 1 } -wait_for "http://localhost:$BACKEND_PORT/health" "后端" -wait_for "http://localhost:$FRONTEND_PORT" "前端" +wait_for "http://localhost:$BACKEND_PORT/health" "后端" || true +wait_for "http://localhost:$FRONTEND_PORT" "前端" || true echo -log "全部就绪!" +log "全部就绪 ✓" echo -e " ${GREEN}前端:${NC} http://localhost:$FRONTEND_PORT" echo -e " ${GREEN}后端:${NC} http://localhost:$BACKEND_PORT (健康检查: /health)" -echo -e " ${GREEN}日志:${NC} backend.log / frontend.log" -echo -warn "按 Ctrl+C 终止所有服务" - -# --- 保持前台,跟随日志 --- -tail -F "$SCRIPT_DIR/backend.log" "$SCRIPT_DIR/frontend.log" \ No newline at end of file +echo -e " ${GREEN}日志:${NC} backend.log / frontend.log" \ No newline at end of file