2025-06-26 15:44:44 +08:00
|
|
|
#!/bin/bash
|
|
|
|
|
|
2025-06-28 12:56:30 +08:00
|
|
|
# 前端远程部署脚本 - 本地构建版本
|
|
|
|
|
# 本地构建,远程部署,避免服务器环境依赖
|
2025-06-26 15:44:44 +08:00
|
|
|
|
|
|
|
|
# 服务器配置
|
2025-06-28 12:56:30 +08:00
|
|
|
SERVER_HOST="120.79.214.48"
|
2025-06-26 15:44:44 +08:00
|
|
|
SERVER_USER="root"
|
|
|
|
|
SERVER_PASSWORD='Kola123!@#'
|
|
|
|
|
SERVER="$SERVER_USER@$SERVER_HOST"
|
|
|
|
|
SERVER_PATH="/www/wwwroot/leaser_front"
|
|
|
|
|
DIST_DIR="dist"
|
2025-06-28 12:56:30 +08:00
|
|
|
FRONTEND_PORT="9501"
|
2025-06-26 15:44:44 +08:00
|
|
|
|
|
|
|
|
# 检测是否安装了sshpass
|
|
|
|
|
if command -v sshpass >/dev/null 2>&1; then
|
|
|
|
|
USE_SSHPASS=true
|
|
|
|
|
SSH_CMD="sshpass -p $SERVER_PASSWORD ssh -o StrictHostKeyChecking=no"
|
|
|
|
|
SCP_CMD="sshpass -p $SERVER_PASSWORD scp -o StrictHostKeyChecking=no -r"
|
|
|
|
|
else
|
|
|
|
|
USE_SSHPASS=false
|
|
|
|
|
SSH_CMD="ssh -o StrictHostKeyChecking=no"
|
|
|
|
|
SCP_CMD="scp -o StrictHostKeyChecking=no -r"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
# 颜色定义
|
|
|
|
|
GREEN='\033[0;32m'
|
|
|
|
|
BLUE='\033[0;34m'
|
|
|
|
|
RED='\033[0;31m'
|
|
|
|
|
YELLOW='\033[1;33m'
|
|
|
|
|
NC='\033[0m'
|
|
|
|
|
|
2025-06-28 12:56:30 +08:00
|
|
|
log() { echo -e "${BLUE}[INFO]${NC} $1"; }
|
|
|
|
|
success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; }
|
|
|
|
|
error() { echo -e "${RED}[ERROR]${NC} $1"; }
|
|
|
|
|
warn() { echo -e "${YELLOW}[WARNING]${NC} $1"; }
|
2025-06-26 15:44:44 +08:00
|
|
|
|
|
|
|
|
# SSH执行函数
|
|
|
|
|
run_ssh() {
|
|
|
|
|
local cmd="$1"
|
|
|
|
|
if [ "$USE_SSHPASS" = true ]; then
|
|
|
|
|
$SSH_CMD "$SERVER" "$cmd"
|
|
|
|
|
else
|
|
|
|
|
echo -e "${YELLOW}[SSH连接]${NC} 请输入服务器密码: $SERVER_PASSWORD"
|
|
|
|
|
$SSH_CMD "$SERVER" "$cmd"
|
|
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# SCP上传函数
|
|
|
|
|
run_scp() {
|
|
|
|
|
local source="$1"
|
|
|
|
|
local dest="$2"
|
|
|
|
|
if [ "$USE_SSHPASS" = true ]; then
|
|
|
|
|
$SCP_CMD "$source" "$SERVER:$dest"
|
|
|
|
|
else
|
|
|
|
|
echo -e "${YELLOW}[SCP上传]${NC} 请输入服务器密码: $SERVER_PASSWORD"
|
|
|
|
|
$SCP_CMD "$source" "$SERVER:$dest"
|
|
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 显示密码提示
|
|
|
|
|
show_password_hint() {
|
|
|
|
|
if [ "$USE_SSHPASS" = true ]; then
|
|
|
|
|
echo -e "${GREEN}[sshpass]${NC} 已启用自动登录,无需手动输入密码 ✅"
|
|
|
|
|
else
|
|
|
|
|
echo -e "${YELLOW}[密码提示]${NC} 服务器密码: $SERVER_PASSWORD"
|
|
|
|
|
echo -e "${BLUE}[建议]${NC} 安装 sshpass 以启用自动登录"
|
|
|
|
|
echo " Mac: brew install hudochenkov/sshpass/sshpass"
|
|
|
|
|
echo " Ubuntu/Debian: apt-get install sshpass"
|
|
|
|
|
echo " CentOS/RHEL: yum install sshpass"
|
|
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-28 12:56:30 +08:00
|
|
|
# 本地构建
|
|
|
|
|
local_build() {
|
|
|
|
|
log "本地构建项目..."
|
2025-06-26 15:44:44 +08:00
|
|
|
|
2025-06-28 12:56:30 +08:00
|
|
|
# 检查本地环境
|
|
|
|
|
if ! command -v node >/dev/null 2>&1; then
|
|
|
|
|
error "本地未安装 Node.js,请先安装"
|
|
|
|
|
return 1
|
2025-06-26 15:44:44 +08:00
|
|
|
fi
|
|
|
|
|
|
2025-06-28 12:56:30 +08:00
|
|
|
if ! command -v pnpm >/dev/null 2>&1; then
|
|
|
|
|
warn "本地未安装 pnpm,尝试安装..."
|
|
|
|
|
npm install -g pnpm || {
|
|
|
|
|
error "pnpm 安装失败"
|
|
|
|
|
return 1
|
|
|
|
|
}
|
2025-06-26 15:44:44 +08:00
|
|
|
fi
|
|
|
|
|
|
2025-06-28 12:56:30 +08:00
|
|
|
log "Node版本: $(node -v)"
|
|
|
|
|
log "pnpm版本: $(pnpm -v)"
|
|
|
|
|
|
|
|
|
|
# 清理本地构建目录
|
|
|
|
|
if [ -d "$DIST_DIR" ]; then
|
|
|
|
|
log "清理本地构建目录..."
|
|
|
|
|
rm -rf "$DIST_DIR"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
# 安装依赖
|
|
|
|
|
log "安装项目依赖..."
|
|
|
|
|
pnpm install || {
|
|
|
|
|
error "依赖安装失败"
|
|
|
|
|
return 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 构建项目
|
|
|
|
|
log "开始构建..."
|
|
|
|
|
NODE_ENV=production pnpm build || {
|
|
|
|
|
error "构建失败"
|
|
|
|
|
return 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 检查构建结果
|
|
|
|
|
if [ -d "$DIST_DIR" ] && [ "$(ls -A $DIST_DIR 2>/dev/null)" ]; then
|
|
|
|
|
success "✅ 本地构建成功"
|
|
|
|
|
log "构建文件数量: $(find $DIST_DIR -type f | wc -l)"
|
2025-06-26 15:44:44 +08:00
|
|
|
return 0
|
|
|
|
|
else
|
2025-06-28 12:56:30 +08:00
|
|
|
error "构建目录为空或不存在"
|
2025-06-26 15:44:44 +08:00
|
|
|
return 1
|
|
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-28 12:56:30 +08:00
|
|
|
# 上传构建文件
|
|
|
|
|
upload_files() {
|
|
|
|
|
log "上传构建文件到服务器..."
|
|
|
|
|
|
|
|
|
|
if [ ! -d "$DIST_DIR" ]; then
|
|
|
|
|
error "本地构建目录不存在,请先执行构建"
|
|
|
|
|
return 1
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
# 确保服务器dist目录存在并清理
|
|
|
|
|
run_ssh "mkdir -p $SERVER_PATH/$DIST_DIR && rm -rf $SERVER_PATH/$DIST_DIR/* 2>/dev/null || true"
|
|
|
|
|
|
|
|
|
|
# 上传到目标目录
|
|
|
|
|
run_scp "$DIST_DIR/" "$SERVER_PATH/$DIST_DIR/"
|
|
|
|
|
|
|
|
|
|
if [ $? -eq 0 ]; then
|
|
|
|
|
success "✅ 文件上传成功"
|
|
|
|
|
return 0
|
|
|
|
|
else
|
|
|
|
|
error "文件上传失败"
|
|
|
|
|
return 1
|
|
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 检查部署结果
|
|
|
|
|
verify_deployment() {
|
|
|
|
|
log "检查部署结果..."
|
|
|
|
|
run_ssh "cd $SERVER_PATH/$DIST_DIR && if [ -f index.html ]; then echo '✅ index.html 部署成功'; file_count=\$(find . -type f -not -path '*/\.*' | wc -l); echo \"✅ 共部署 \$file_count 个文件\"; else echo '❌ 部署验证失败'; exit 1; fi"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 检查前端端口配置
|
|
|
|
|
check_frontend_port() {
|
|
|
|
|
log "检查前端站点配置..."
|
|
|
|
|
local port_info=$(run_ssh "grep -r 'leaser_front' /www/server/panel/vhost/nginx/ 2>/dev/null | grep -i listen | head -1" 2>/dev/null || echo "")
|
|
|
|
|
|
|
|
|
|
if [[ $port_info =~ listen[[:space:]]+([0-9]+) ]]; then
|
|
|
|
|
FRONTEND_PORT=${BASH_REMATCH[1]}
|
|
|
|
|
success "检测到前端站点端口: $FRONTEND_PORT"
|
|
|
|
|
else
|
|
|
|
|
warn "未找到宝塔面板站点配置,使用默认端口: $FRONTEND_PORT"
|
|
|
|
|
warn "请在宝塔面板创建站点,目录指向: $SERVER_PATH/$DIST_DIR"
|
|
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
echo "========================================"
|
|
|
|
|
log "前端远程部署工具 - 本地构建版本"
|
|
|
|
|
echo "服务器: $SERVER"
|
|
|
|
|
echo "项目路径: $SERVER_PATH"
|
|
|
|
|
echo "本地目录: $(pwd)"
|
|
|
|
|
echo "========================================"
|
|
|
|
|
show_password_hint
|
|
|
|
|
echo ""
|
|
|
|
|
|
2025-06-26 15:44:44 +08:00
|
|
|
case "${1:-deploy}" in
|
|
|
|
|
"test"|"t")
|
|
|
|
|
log "测试服务器连接..."
|
2025-06-28 12:56:30 +08:00
|
|
|
run_ssh "echo '✅ 连接成功' && echo '服务器信息:' && uname -a"
|
2025-06-26 15:44:44 +08:00
|
|
|
;;
|
|
|
|
|
|
|
|
|
|
"status"|"s")
|
|
|
|
|
log "查看前端项目状态..."
|
2025-06-28 12:56:30 +08:00
|
|
|
run_ssh "cd $SERVER_PATH/$DIST_DIR && echo '=== 目录信息 ===' && pwd && ls -la | head -10 && echo '=== 文件统计 ===' && find . -type f -not -path '*/\.*' -not -path '*/node_modules*' | wc -l && echo '个文件' && echo '=== 最新文件 ===' && find . -maxdepth 1 -type f -not -path '*/\.*' | head -5 | xargs ls -la 2>/dev/null || echo '无文件'"
|
2025-06-26 15:44:44 +08:00
|
|
|
;;
|
|
|
|
|
|
|
|
|
|
"logs"|"l")
|
|
|
|
|
log "查看Nginx访问日志..."
|
2025-06-28 12:56:30 +08:00
|
|
|
run_ssh "tail -20 /var/log/nginx/access.log 2>/dev/null || tail -20 /www/wwwlogs/access.log 2>/dev/null || echo '找不到Nginx访问日志'"
|
2025-06-26 15:44:44 +08:00
|
|
|
;;
|
|
|
|
|
|
|
|
|
|
"check"|"c")
|
|
|
|
|
log "检查前端部署情况..."
|
2025-06-28 12:56:30 +08:00
|
|
|
run_ssh "cd $SERVER_PATH/$DIST_DIR && echo '=== 关键文件检查 ===' && [ -f index.html ] && echo '✅ index.html 存在' || echo '❌ index.html 不存在' && echo '=== 静态资源检查 ===' && ls -la *.js *.css 2>/dev/null | head -3 || echo '无JS/CSS文件' && echo '=== 目录大小 ===' && du -sh . 2>/dev/null || echo '无法获取大小'"
|
2025-06-26 15:44:44 +08:00
|
|
|
;;
|
|
|
|
|
|
|
|
|
|
"nginx")
|
|
|
|
|
log "检查Nginx配置..."
|
2025-06-28 12:56:30 +08:00
|
|
|
run_ssh "nginx -t 2>/dev/null && echo '✅ Nginx配置正确' || echo '❌ Nginx配置有误'"
|
|
|
|
|
check_frontend_port
|
2025-06-26 15:44:44 +08:00
|
|
|
;;
|
|
|
|
|
|
|
|
|
|
"portconfig")
|
|
|
|
|
check_frontend_port
|
|
|
|
|
;;
|
|
|
|
|
|
|
|
|
|
"build"|"b")
|
|
|
|
|
local_build
|
|
|
|
|
;;
|
|
|
|
|
|
|
|
|
|
"upload"|"u")
|
|
|
|
|
if [ -d "$DIST_DIR" ]; then
|
|
|
|
|
upload_files
|
|
|
|
|
else
|
|
|
|
|
error "未找到 $DIST_DIR 目录,请先执行构建命令"
|
|
|
|
|
fi
|
|
|
|
|
;;
|
|
|
|
|
|
2025-06-28 12:56:30 +08:00
|
|
|
"pull"|"p")
|
|
|
|
|
log "拉取最新代码到服务器..."
|
|
|
|
|
run_ssh "cd $SERVER_PATH && (git pull 2>/dev/null || git pull https://kola:Cyne2012@\$(git config --get remote.origin.url | sed 's|https://||'))"
|
|
|
|
|
;;
|
|
|
|
|
|
2025-06-26 15:44:44 +08:00
|
|
|
"deploy"|"d"|"")
|
2025-06-28 12:56:30 +08:00
|
|
|
log "开始前端部署流程..."
|
2025-06-26 15:44:44 +08:00
|
|
|
echo ""
|
|
|
|
|
|
2025-06-28 12:56:30 +08:00
|
|
|
log "步骤 1/3: 本地构建"
|
|
|
|
|
if ! local_build; then
|
|
|
|
|
error "本地构建失败,部署终止"
|
2025-06-26 15:44:44 +08:00
|
|
|
exit 1
|
|
|
|
|
fi
|
2025-06-28 12:56:30 +08:00
|
|
|
|
|
|
|
|
log "步骤 2/3: 上传文件"
|
|
|
|
|
if ! upload_files; then
|
|
|
|
|
error "文件上传失败,部署终止"
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
log "步骤 3/3: 检查部署结果"
|
|
|
|
|
verify_deployment
|
|
|
|
|
|
|
|
|
|
# 检查端口配置
|
|
|
|
|
check_frontend_port
|
|
|
|
|
|
|
|
|
|
# 清理本地构建文件
|
|
|
|
|
log "清理本地构建文件..."
|
|
|
|
|
rm -rf "$DIST_DIR"
|
|
|
|
|
|
|
|
|
|
success "🎉 部署完成!"
|
|
|
|
|
if [ "$FRONTEND_PORT" = "80" ]; then
|
|
|
|
|
echo "🌐 访问地址: http://$SERVER_HOST"
|
|
|
|
|
else
|
|
|
|
|
echo "🌐 访问地址: http://$SERVER_HOST:$FRONTEND_PORT"
|
|
|
|
|
fi
|
|
|
|
|
echo ""
|
|
|
|
|
warn "如果网站无法访问,请检查:"
|
|
|
|
|
echo " 1. 在宝塔面板中创建站点,目录指向: $SERVER_PATH"
|
|
|
|
|
echo " 2. 确保防火墙开放端口: $FRONTEND_PORT"
|
|
|
|
|
echo " 3. 检查域名解析是否正确"
|
2025-06-26 15:44:44 +08:00
|
|
|
;;
|
|
|
|
|
|
|
|
|
|
"help"|"h"|"--help")
|
2025-06-28 12:56:30 +08:00
|
|
|
echo "前端远程部署工具 - 本地构建版本"
|
2025-06-26 15:44:44 +08:00
|
|
|
echo ""
|
|
|
|
|
echo "用法: $0 [命令]"
|
|
|
|
|
echo ""
|
|
|
|
|
echo "命令:"
|
2025-06-28 12:56:30 +08:00
|
|
|
echo " deploy/d 完整部署流程(默认)"
|
|
|
|
|
echo " test/t 测试服务器连接"
|
|
|
|
|
echo " status/s 查看项目状态"
|
|
|
|
|
echo " check/c 检查部署情况"
|
|
|
|
|
echo " logs/l 查看Nginx日志"
|
|
|
|
|
echo " nginx 检查Nginx配置"
|
|
|
|
|
echo " portconfig 检查端口配置"
|
|
|
|
|
echo " build/b 仅本地构建"
|
|
|
|
|
echo " upload/u 仅上传构建文件"
|
|
|
|
|
echo " pull/p 拉取代码到服务器"
|
|
|
|
|
echo " help/h 显示帮助"
|
2025-06-26 15:44:44 +08:00
|
|
|
;;
|
|
|
|
|
|
|
|
|
|
*)
|
|
|
|
|
error "未知命令: $1"
|
2025-06-28 12:56:30 +08:00
|
|
|
echo "使用 '$0 help' 查看可用命令"
|
2025-06-26 15:44:44 +08:00
|
|
|
exit 1
|
|
|
|
|
;;
|
|
|
|
|
esac
|