mirror of
https://github.com/fastapiadmin/FastapiAdmin.git
synced 2026-09-21 04:46:26 +00:00
refactor: 迁移前端资源文件至web目录 feat: 新增多种图标资源 style: 统一代码风格和格式化配置 docs: 更新README和文档说明 chore: 更新依赖和配置文件 fix: 修复部分类型定义和枚举 perf: 优化路由和组件加载逻辑
605 lines
21 KiB
Bash
605 lines
21 KiB
Bash
#!/bin/bash
|
||
|
||
# 设置脚本选项,提高健壮性
|
||
set -e # 遇到错误立即退出
|
||
set -u # 遇到未定义变量立即退出
|
||
set -o pipefail # 管道命令失败时整个命令失败
|
||
|
||
# 设置全局变量
|
||
PROJECT_NAME="FastapiAdmin"
|
||
WORK_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||
DOCKER_DIR="${WORK_DIR}/docker"
|
||
ENV_FILE="${DOCKER_DIR}/.env"
|
||
|
||
GIT_REPO="https://gitee.com/fastapiadmin/${PROJECT_NAME}.git"
|
||
|
||
# 是否有更新前端
|
||
UPDATE_FRONTEND=false
|
||
# 是否有更新移动端
|
||
UPDATE_FASTAPP=false
|
||
# 是否有更新官网
|
||
UPDATE_FASTDOCS=false
|
||
# 是否跳过前端构建
|
||
SKIP_FRONTEND=true
|
||
|
||
# 部署状态跟踪
|
||
DEPLOY_STATUS=""
|
||
|
||
# 日志级别控制
|
||
LOG_LEVEL=${LOG_LEVEL:-INFO}
|
||
|
||
# 颜色定义
|
||
readonly COLOR_RESET='\033[0m'
|
||
readonly COLOR_RED='\033[0;31m'
|
||
readonly COLOR_GREEN='\033[0;32m'
|
||
readonly COLOR_YELLOW='\033[0;33m'
|
||
readonly COLOR_BLUE='\033[0;34m'
|
||
readonly COLOR_CYAN='\033[0;36m'
|
||
|
||
# 打印带时间戳的日志(带颜色)
|
||
log() {
|
||
local message="$1"
|
||
local level=${2:-INFO}
|
||
local color=""
|
||
|
||
case $level in
|
||
DEBUG) color="${COLOR_RESET}" ;;
|
||
INFO) color="${COLOR_BLUE}" ;;
|
||
WARN) color="${COLOR_YELLOW}" ;;
|
||
ERROR) color="${COLOR_RED}" ;;
|
||
SUCCESS) color="${COLOR_GREEN}" ;;
|
||
*) color="${COLOR_RESET}" ;;
|
||
esac
|
||
|
||
case $LOG_LEVEL in
|
||
DEBUG) ;;
|
||
INFO) [[ $level == "DEBUG" ]] && return ;;
|
||
WARN) [[ $level == "DEBUG" || $level == "INFO" ]] && return ;;
|
||
ERROR) [[ $level != "ERROR" ]] && return ;;
|
||
SUCCESS) [[ $level == "DEBUG" || $level == "INFO" || $level == "WARN" ]] && return ;;
|
||
esac
|
||
|
||
echo -e "${color}[$(date '+%Y-%m-%d %H:%M:%S')] [${level}] ${message}${COLOR_RESET}"
|
||
}
|
||
|
||
# 检查并设置脚本执行权限
|
||
check_and_setup_permissions() {
|
||
log "==========🔐 检查脚本执行权限...==========" "INFO"
|
||
|
||
local script_path="${WORK_DIR}/deploy.sh"
|
||
local docker_compose_file="${DOCKER_DIR}/docker-compose.yaml"
|
||
|
||
if [ ! -x "$script_path" ]; then
|
||
log "⚠️ deploy.sh 缺少执行权限,正在自动设置..." "WARN"
|
||
chmod +x "$script_path"
|
||
log "✅ deploy.sh 执行权限已设置" "INFO"
|
||
else
|
||
log "✅ deploy.sh 执行权限正常" "INFO"
|
||
fi
|
||
|
||
if [ ! -f "$docker_compose_file" ]; then
|
||
log "❌ docker-compose.yaml 文件不存在: ${docker_compose_file}" "ERROR"
|
||
exit 1
|
||
fi
|
||
|
||
log "✅ 权限检查完成" "INFO"
|
||
}
|
||
|
||
# 加载环境变量
|
||
load_env() {
|
||
log "==========🔍 加载环境变量...==========" "INFO"
|
||
|
||
if [ -f "${ENV_FILE}" ]; then
|
||
log "📁 加载环境变量文件: ${ENV_FILE}" "INFO"
|
||
set -a
|
||
source "${ENV_FILE}"
|
||
set +a
|
||
log "✅ 环境变量加载成功" "INFO"
|
||
else
|
||
log "⚠️ 环境变量文件 ${ENV_FILE} 不存在,使用默认值" "WARN"
|
||
if [ -f "${DOCKER_DIR}/.env.example" ]; then
|
||
log "📁 从示例文件创建环境变量文件" "INFO"
|
||
cp "${DOCKER_DIR}/.env.example" "${ENV_FILE}"
|
||
log "✅ 环境变量文件创建成功" "INFO"
|
||
set -a
|
||
source "${ENV_FILE}"
|
||
set +a
|
||
else
|
||
log "❌ 环境变量示例文件 ${DOCKER_DIR}/.env.example 不存在" "ERROR"
|
||
exit 1
|
||
fi
|
||
fi
|
||
}
|
||
|
||
# 检查系统依赖
|
||
check_permissions() {
|
||
log "==========🔍 检查系统依赖...==========" "INFO"
|
||
local missing_deps=()
|
||
local optional_deps_missing=()
|
||
|
||
for cmd in git docker docker-compose; do
|
||
if ! command -v $cmd &> /dev/null; then
|
||
missing_deps+=($cmd)
|
||
log "❌ $cmd 未安装" "ERROR"
|
||
else
|
||
local version=$($cmd --version 2>/dev/null | head -n1 || $cmd -v 2>/dev/null | head -n1)
|
||
log "🎉 $cmd 已安装 - ${version}" "INFO"
|
||
fi
|
||
done
|
||
|
||
if command -v docker &> /dev/null; then
|
||
if docker compose version &> /dev/null; then
|
||
log "🎉 docker compose 已安装 - $(docker compose version | head -n1)" "INFO"
|
||
elif docker-compose --version &> /dev/null; then
|
||
log "🎉 docker-compose 已安装 - $(docker-compose --version | head -n1)" "INFO"
|
||
fi
|
||
fi
|
||
|
||
if [ -d "frontend/web" ] || [ -d "frontend/app" ] || [ -d "frontend/docs" ]; then
|
||
for cmd in node pnpm; do
|
||
if ! command -v $cmd &> /dev/null; then
|
||
optional_deps_missing+=($cmd)
|
||
log "⚠️ $cmd 未安装(前端构建需要)" "WARN"
|
||
else
|
||
log "🎉 $cmd 已安装 - $($cmd --version 2>/dev/null || $cmd -v)" "INFO"
|
||
fi
|
||
done
|
||
fi
|
||
|
||
if [ ${#missing_deps[@]} -ne 0 ]; then
|
||
log "❌ 缺少必需依赖: ${missing_deps[*]}" "ERROR"
|
||
log "❌ 请安装缺失的依赖后重试" "ERROR"
|
||
exit 1
|
||
fi
|
||
|
||
log "✅ 所有必需依赖检查通过" "INFO"
|
||
}
|
||
|
||
# 更新代码
|
||
update_code() {
|
||
log "==========🔄 更新最新代码...==========" "INFO"
|
||
log "📂 当前工作目录: $(pwd)" "INFO"
|
||
log "🎯 项目路径: ${WORK_DIR}" "INFO"
|
||
|
||
if [ "$(pwd)" != "${WORK_DIR}" ]; then
|
||
cd "${WORK_DIR}" || { log "❌ 无法进入项目根目录" "ERROR"; exit 1; }
|
||
log "📂 进入项目根目录" "INFO"
|
||
fi
|
||
|
||
if [ -d ".git" ]; then
|
||
local current_branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown")
|
||
log "📂 当前Git分支: ${current_branch}" "INFO"
|
||
git fetch origin || { log "⚠️ 获取远程分支失败" "WARN"; }
|
||
git pull --force || { log "❌ 拉取更新失败" "ERROR"; exit 1; }
|
||
local commit_info=$(git log -1 --oneline 2>/dev/null || echo "无法获取提交信息")
|
||
log "📝 最新提交: ${commit_info}" "INFO"
|
||
else
|
||
log "📥 初始化Git仓库..." "INFO"
|
||
git init
|
||
git remote add origin "${GIT_REPO}"
|
||
git pull origin master || git pull origin main || { log "❌ 拉取代码失败" "ERROR"; exit 1; }
|
||
fi
|
||
|
||
if [ -d "frontend/web" ]; then
|
||
UPDATE_FRONTEND=true
|
||
log "📦 检测到前端工程" "INFO"
|
||
fi
|
||
if [ -d "frontend/app" ]; then
|
||
UPDATE_FASTAPP=true
|
||
log "📦 检测到移动端工程" "INFO"
|
||
fi
|
||
if [ -d "frontend/docs" ]; then
|
||
UPDATE_FASTDOCS=true
|
||
log "📦 检测到官网工程" "INFO"
|
||
fi
|
||
|
||
log "✅ 代码更新成功" "INFO"
|
||
}
|
||
|
||
# 打包前端
|
||
build_frontend() {
|
||
log "==========🚀 构建前端...==========" "INFO"
|
||
|
||
if [ "$SKIP_FRONTEND" = true ]; then
|
||
log "⚠️ 跳过前端构建(使用已上传的静态文件)" "WARN"
|
||
return 0
|
||
fi
|
||
|
||
if ! command -v node &> /dev/null || ! command -v pnpm &> /dev/null; then
|
||
log "⚠️ Node.js 或 pnpm 未安装,跳过前端构建" "WARN"
|
||
log "💡 提示: 请在本地构建前端,然后将 dist 目录上传到 docker/nginx/ 对应目录" "WARN"
|
||
return 0
|
||
fi
|
||
|
||
if [ -d "frontend/web" ] && [ "$UPDATE_FRONTEND" = true ]; then
|
||
log "📦 开始构建前端工程..." "INFO"
|
||
cd frontend/web || { log "❌ 无法进入前端目录" "ERROR"; exit 1; }
|
||
|
||
log "📦 安装前端依赖..." "INFO"
|
||
pnpm install --frozen-lockfile || pnpm install || { log "❌ 前端依赖安装失败" "WARN"; cd ..; return 0; }
|
||
|
||
log "🔨 打包前端工程..." "INFO"
|
||
pnpm run build || { log "❌ 前端工程打包失败" "WARN"; cd ..; return 0; }
|
||
log "✅ 前端工程打包成功" "INFO"
|
||
|
||
mkdir -p "${WORK_DIR}/docker/nginx/web"
|
||
|
||
if [ -d "dist" ]; then
|
||
rm -rf "${WORK_DIR}/docker/nginx/web"/*
|
||
mv -f "dist"/* "${WORK_DIR}/docker/nginx/web/" || { log "❌ 移动前端打包到docker/nginx/web目录失败" "ERROR"; cd ..; exit 1; }
|
||
log "✅ 前端打包文件已移动到 docker/nginx/web" "INFO"
|
||
fi
|
||
|
||
cd .. || { log "❌ 无法返回项目根目录" "ERROR"; exit 1; }
|
||
fi
|
||
|
||
if [ -d "frontend/app" ] && [ "$UPDATE_FASTAPP" = true ]; then
|
||
log "📦 开始构建小程序工程..." "INFO"
|
||
cd frontend/app || { log "❌ 无法进入小程序目录" "ERROR"; exit 1; }
|
||
|
||
log "📦 安装小程序依赖..." "INFO"
|
||
pnpm install --frozen-lockfile || pnpm install || { log "❌ 小程序依赖安装失败" "WARN"; cd ..; return 0; }
|
||
|
||
log "🔨 打包小程序工程..." "INFO"
|
||
pnpm run build:h5 || { log "❌ 小程序工程打包失败" "WARN"; cd ..; return 0; }
|
||
log "✅ 小程序工程打包成功" "INFO"
|
||
|
||
mkdir -p "${WORK_DIR}/docker/nginx/app"
|
||
|
||
if [ -d "dist" ]; then
|
||
rm -rf "${WORK_DIR}/docker/nginx/app"/*
|
||
mv -f "dist"/* "${WORK_DIR}/docker/nginx/app/" || { log "❌ 移动小程序打包到docker/nginx/app目录失败" "ERROR"; cd ..; exit 1; }
|
||
log "✅ 小程序打包文件已移动到 docker/nginx/app" "INFO"
|
||
fi
|
||
|
||
cd .. || { log "❌ 无法返回项目根目录" "ERROR"; exit 1; }
|
||
fi
|
||
|
||
if [ -d "frontend/docs" ] && [ "$UPDATE_FASTDOCS" = true ]; then
|
||
log "📦 开始构建项目文档..." "INFO"
|
||
cd frontend/docs || { log "❌ 无法进入项目文档目录" "ERROR"; exit 1; }
|
||
|
||
log "📦 安装项目文档依赖..." "INFO"
|
||
pnpm install --frozen-lockfile || pnpm install || { log "❌ 项目文档依赖安装失败" "WARN"; cd ..; return 0; }
|
||
|
||
log "🔨 打包项目文档..." "INFO"
|
||
pnpm run docs:build || { log "❌ 项目文档打包生成失败" "WARN"; cd ..; return 0; }
|
||
log "✅ 项目文档打包成功" "INFO"
|
||
|
||
mkdir -p "${WORK_DIR}/docker/nginx/docs"
|
||
|
||
if [ -d "dist" ]; then
|
||
rm -rf "${WORK_DIR}/docker/nginx/docs"/*
|
||
mv -f "dist"/* "${WORK_DIR}/docker/nginx/docs/" || { log "❌ 移动项目文档打包到docker/nginx/docs目录失败" "ERROR"; cd ..; exit 1; }
|
||
log "✅ 项目文档打包文件已移动到 docker/nginx/docs" "INFO"
|
||
fi
|
||
|
||
cd .. || { log "❌ 无法返回项目根目录" "ERROR"; exit 1; }
|
||
fi
|
||
}
|
||
|
||
# 构建镜像
|
||
build_containers() {
|
||
log "==========🔨 构建Docker镜像...==========" "INFO"
|
||
cd "${DOCKER_DIR}" || { log "❌ 无法进入项目 docker 目录" "ERROR"; exit 1; }
|
||
log "📂 进入项目 docker 目录: $(pwd)" "INFO"
|
||
|
||
export DOCKER_BUILDKIT=1
|
||
docker compose build --no-cache || { log "❌ 镜像构建失败" "ERROR"; exit 1; }
|
||
log "✅ Docker镜像构建成功" "SUCCESS"
|
||
}
|
||
|
||
# 启动容器
|
||
start_containers() {
|
||
log "==========🚀 启动容器...==========" "INFO"
|
||
cd "${DOCKER_DIR}" || { log "❌ 无法进入项目 docker 目录" "ERROR"; exit 1; }
|
||
|
||
if docker compose ps --format '{{.Names}}' 2>/dev/null | grep -q .; then
|
||
log "📦 停止旧容器..." "INFO"
|
||
docker compose down || true
|
||
fi
|
||
|
||
log "🚀 启动新容器..." "INFO"
|
||
docker compose up -d --force-recreate || { log "❌ 容器启动失败" "ERROR"; exit 1; }
|
||
|
||
log "⏳ 等待容器启动完成..." "INFO"
|
||
local max_wait=60
|
||
local wait_count=0
|
||
|
||
while [ $wait_count -lt $max_wait ]; do
|
||
if docker compose ps mysql --format '{{.Status}}' 2>/dev/null | grep -q "healthy"; then
|
||
log "✅ MySQL 已就绪" "SUCCESS"
|
||
break
|
||
fi
|
||
sleep 2
|
||
wait_count=$((wait_count + 2))
|
||
echo -n "."
|
||
done
|
||
echo ""
|
||
|
||
log "📊 容器状态检查..." "INFO"
|
||
docker compose ps
|
||
|
||
log "✅ 项目容器已启动" "SUCCESS"
|
||
}
|
||
|
||
# 停止项目容器
|
||
stop_containers() {
|
||
log "==========⏹️ 停止项目容器...==========" "INFO"
|
||
|
||
if [ -d "${DOCKER_DIR}" ]; then
|
||
cd "${DOCKER_DIR}" || { log "❌ 无法进入项目 docker 目录" "ERROR"; exit 1; }
|
||
log "📂 进入项目 docker 目录" "INFO"
|
||
|
||
docker compose down || { log "⚠️ 停止容器时发生错误" "WARN"; }
|
||
log "✅ 项目容器已停止并删除" "INFO"
|
||
|
||
cd .. || { log "❌ 无法返回项目根目录" "ERROR"; exit 1; }
|
||
log "📂 返回项目根目录" "INFO"
|
||
fi
|
||
}
|
||
|
||
# 重启容器
|
||
restart_containers() {
|
||
log "==========🔄 重启容器...==========" "INFO"
|
||
cd "${DOCKER_DIR}" || { log "❌ 无法进入项目 docker 目录" "ERROR"; exit 1; }
|
||
docker compose restart || { log "❌ 容器重启失败" "ERROR"; exit 1; }
|
||
log "✅ 容器重启成功" "SUCCESS"
|
||
docker compose ps
|
||
}
|
||
|
||
# 清理旧镜像
|
||
clear_old_images() {
|
||
log "==========🗑️ 清理旧镜像...==========" "INFO"
|
||
local project_images=$(docker images | grep ${PROJECT_NAME} | awk '{print $3}' | wc -l)
|
||
if [ $project_images -gt 0 ]; then
|
||
local before_count=$(docker images | grep ${PROJECT_NAME} | wc -l)
|
||
docker image prune -f --filter "until=72h" --filter "label=com.docker.compose.project=${PROJECT_NAME}" >/dev/null 2>&1 || true
|
||
local after_count=$(docker images | grep ${PROJECT_NAME} | wc -l)
|
||
local cleaned_count=$((before_count - after_count))
|
||
log "✅ 旧镜像清理完成,清理了 ${cleaned_count} 个镜像" "SUCCESS"
|
||
else
|
||
log "⚠️ 没有找到项目相关镜像,跳过清理" "WARN"
|
||
fi
|
||
}
|
||
|
||
# 显示日志
|
||
show_containers_logs() {
|
||
log "==========📋 查看所有容器日志... ==========" "INFO"
|
||
cd "${DOCKER_DIR}" || { log "❌ 无法进入项目 docker 目录" "ERROR"; exit 1; }
|
||
|
||
log "📊 当前容器状态:" "INFO"
|
||
docker compose ps --format "table {{.Service}}\t{{.Name}}\t{{.Status}}\t{{.Ports}}"
|
||
|
||
log "📋 服务日志:" "INFO"
|
||
echo "----------------------------------------"
|
||
docker compose logs
|
||
echo "----------------------------------------"
|
||
}
|
||
|
||
# 验证部署
|
||
verify_deployment() {
|
||
log "==========🔍 验证部署结果...==========" "INFO"
|
||
|
||
local all_healthy=true
|
||
|
||
log "📊 检查容器运行状态..." "INFO"
|
||
for service in mysql redis backend nginx; do
|
||
local status=$(docker compose ps "$service" --format '{{.Status}}' 2>/dev/null || echo "not found")
|
||
if echo "$status" | grep -q "Up\|healthy"; then
|
||
log "✅ ${service}: ${status}" "SUCCESS"
|
||
else
|
||
log "❌ ${service}: ${status}" "ERROR"
|
||
all_healthy=false
|
||
fi
|
||
done
|
||
|
||
log "📊 检查端口监听..." "INFO"
|
||
local backend_port="${BACKEND_PORT:-8001}"
|
||
if command -v nc &> /dev/null; then
|
||
if nc -z localhost ${backend_port} 2>/dev/null; then
|
||
log "✅ 后端服务端口 ${backend_port} 已监听" "SUCCESS"
|
||
else
|
||
log "⚠️ 后端服务端口 ${backend_port} 未监听" "WARN"
|
||
fi
|
||
fi
|
||
|
||
local http_port="${HTTP_PORT:-80}"
|
||
if nc -z localhost ${http_port} 2>/dev/null; then
|
||
log "✅ Nginx服务端口 ${http_port} 已监听" "SUCCESS"
|
||
else
|
||
log "⚠️ Nginx服务端口 ${http_port} 未监听" "WARN"
|
||
fi
|
||
|
||
if [ "$all_healthy" = true ]; then
|
||
log "✅ 所有服务运行正常!" "SUCCESS"
|
||
return 0
|
||
else
|
||
log "⚠️ 部分服务可能存在问题,请检查日志" "WARN"
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
# 信号处理
|
||
handle_interrupt() {
|
||
log "" "INFO"
|
||
log "==========⚠️ 收到中断信号,正在停止部署...==========" "WARN"
|
||
if [ -d "${DOCKER_DIR}" ]; then
|
||
cd "${DOCKER_DIR}"
|
||
docker compose down >/dev/null 2>&1 || true
|
||
fi
|
||
exit 130
|
||
}
|
||
|
||
# 主函数
|
||
main() {
|
||
log "==========🚀 开始部署流程==========" "INFO"
|
||
log "📂 脚本所在目录: $(pwd)" "INFO"
|
||
log "📅 部署时间: $(date '+%Y-%m-%d %H:%M:%S')" "INFO"
|
||
|
||
DEPLOY_STATUS="检查脚本权限"
|
||
log "==========🔐 开始${DEPLOY_STATUS}...==========" "INFO"
|
||
check_and_setup_permissions
|
||
log "✅ ${DEPLOY_STATUS}完成" "INFO"
|
||
|
||
DEPLOY_STATUS="加载环境变量"
|
||
log "==========🔍 开始${DEPLOY_STATUS}...==========" "INFO"
|
||
load_env
|
||
log "✅ ${DEPLOY_STATUS}完成" "INFO"
|
||
|
||
DEPLOY_STATUS="检查系统依赖"
|
||
log "==========🔍 开始${DEPLOY_STATUS}...==========" "INFO"
|
||
check_permissions
|
||
log "✅ ${DEPLOY_STATUS}完成" "INFO"
|
||
|
||
DEPLOY_STATUS="停止现有容器"
|
||
log "==========⏹️ 开始${DEPLOY_STATUS}...==========" "INFO"
|
||
stop_containers
|
||
log "✅ ${DEPLOY_STATUS}完成" "INFO"
|
||
|
||
DEPLOY_STATUS="更新代码"
|
||
log "==========🔄 开始${DEPLOY_STATUS}...==========" "INFO"
|
||
update_code
|
||
log "✅ ${DEPLOY_STATUS}完成" "INFO"
|
||
|
||
DEPLOY_STATUS="构建前端"
|
||
log "==========🚀 开始${DEPLOY_STATUS}...==========" "INFO"
|
||
build_frontend
|
||
log "✅ ${DEPLOY_STATUS}完成" "INFO"
|
||
|
||
DEPLOY_STATUS="构建镜像"
|
||
log "==========🔨 开始${DEPLOY_STATUS}...==========" "INFO"
|
||
build_containers
|
||
log "✅ ${DEPLOY_STATUS}完成" "INFO"
|
||
|
||
DEPLOY_STATUS="启动容器"
|
||
log "==========🚀 开始${DEPLOY_STATUS}...==========" "INFO"
|
||
start_containers
|
||
log "✅ ${DEPLOY_STATUS}完成" "INFO"
|
||
|
||
DEPLOY_STATUS="验证部署"
|
||
log "==========🔍 开始${DEPLOY_STATUS}...==========" "INFO"
|
||
verify_deployment || log "⚠️ 部署验证发现问题,请检查日志" "WARN"
|
||
log "✅ ${DEPLOY_STATUS}完成" "INFO"
|
||
|
||
DEPLOY_STATUS="显示日志"
|
||
log "==========📋 开始${DEPLOY_STATUS}...==========" "INFO"
|
||
show_containers_logs
|
||
log "✅ ${DEPLOY_STATUS}完成" "INFO"
|
||
|
||
log "" "INFO"
|
||
log "🎉🎉🎉 部署完成!🎉🎉🎉" "SUCCESS"
|
||
log "" "INFO"
|
||
log "📌 访问信息:" "INFO"
|
||
log " 🌐 官网: http://域名(或ip:${HTTP_PORT:-80})" "INFO"
|
||
log " 🌐 前端: http://域名(或ip:${HTTP_PORT:-80})/web" "INFO"
|
||
log " 🌐 小程序: http://域名(或ip:${HTTP_PORT:-80})/app" "INFO"
|
||
log " 🔌 后端API: http://域名(或ip):${BACKEND_PORT:-8001}/api/v1/docs" "INFO"
|
||
log " 📝 登录信息: 账号 admin,密码 123456" "INFO"
|
||
log "" "INFO"
|
||
log "💡 常用命令:" "INFO"
|
||
log " 🚀 启动服务: ./deploy.sh start" "INFO"
|
||
log " ⏹️ 停止服务: ./deploy.sh stop" "INFO"
|
||
log " 🔄 重启服务: ./deploy.sh restart" "INFO"
|
||
log " 📋 查看日志: ./deploy.sh logs" "INFO"
|
||
log " 🔍 验证部署: ./deploy.sh verify" "INFO"
|
||
log " 🧹 清理镜像: ./deploy.sh clean" "INFO"
|
||
log " ℹ️ 显示帮助: ./deploy.sh help|-h" "INFO"
|
||
log "" "INFO"
|
||
log "🔧 前端构建选项:" "INFO"
|
||
log " 默认: 跳过前端构建,使用已上传的静态文件" "INFO"
|
||
log " 启用: ./deploy.sh --build-frontend" "INFO"
|
||
log "" "INFO"
|
||
}
|
||
|
||
# 设置信号处理
|
||
trap handle_interrupt INT TERM
|
||
|
||
# 解析命令行参数
|
||
if [ $# -eq 0 ]; then
|
||
main "$@"
|
||
exit 0
|
||
fi
|
||
|
||
while [[ $# -gt 0 ]]; do
|
||
case $1 in
|
||
--skip-frontend)
|
||
SKIP_FRONTEND=true
|
||
log "⚠️ 跳过前端构建" "WARN"
|
||
shift
|
||
;;
|
||
--build-frontend)
|
||
SKIP_FRONTEND=false
|
||
log "🔨 启用前端构建" "INFO"
|
||
shift
|
||
;;
|
||
start)
|
||
load_env
|
||
start_containers
|
||
exit 0
|
||
;;
|
||
stop)
|
||
load_env
|
||
stop_containers
|
||
exit 0
|
||
;;
|
||
restart)
|
||
load_env
|
||
restart_containers
|
||
exit 0
|
||
;;
|
||
logs)
|
||
load_env
|
||
show_containers_logs
|
||
exit 0
|
||
;;
|
||
verify)
|
||
load_env
|
||
verify_deployment
|
||
exit 0
|
||
;;
|
||
clean)
|
||
clear_old_images
|
||
exit 0
|
||
;;
|
||
help|-h|--help)
|
||
echo "使用说明:"
|
||
echo " $0 [选项]"
|
||
echo ""
|
||
echo "选项:"
|
||
echo " start 启动所有容器"
|
||
echo " stop 停止所有容器"
|
||
echo " restart 重启所有容器"
|
||
echo " logs 查看所有容器日志"
|
||
echo " verify 验证部署状态"
|
||
echo " clean 清理旧镜像"
|
||
echo " --skip-frontend 跳过前端构建(默认)"
|
||
echo " --build-frontend 启用前端构建(在服务器上构建)"
|
||
echo " help|-h 显示此帮助信息"
|
||
echo ""
|
||
echo "默认执行完整部署流程:"
|
||
echo " 1. 检查脚本权限"
|
||
echo " 2. 加载环境变量"
|
||
echo " 3. 检查系统依赖"
|
||
echo " 4. 停止现有容器"
|
||
echo " 5. 更新代码"
|
||
echo " 6. 构建前端(默认跳过,使用已上传的静态文件)"
|
||
echo " 7. 构建镜像"
|
||
echo " 8. 启动容器"
|
||
echo " 9. 验证部署"
|
||
echo " 10. 显示日志"
|
||
echo ""
|
||
echo "日志查看命令:"
|
||
echo " 查看实时日志:docker compose logs -f [服务名]"
|
||
echo " 服务名:backend, nginx, mysql, redis"
|
||
exit 0
|
||
;;
|
||
*)
|
||
echo "未知参数: $1"
|
||
echo "使用 $0 help 查看帮助信息"
|
||
exit 1
|
||
;;
|
||
esac
|
||
done
|
||
|
||
main "$@" |