改进了数据库导入导出和部署脚本

This commit is contained in:
Tian jianyong 2025-07-31 17:06:38 +08:00
parent 140d3e7e19
commit ad70b65a8d
22 changed files with 2590 additions and 230 deletions

View File

@ -1,5 +1,5 @@
# 多阶段构建 - 构建阶段
FROM maven:3.9.6-openjdk-17-slim AS builder
FROM maven:3.9.11-openjdk-17-slim AS builder
# 设置工作目录
WORKDIR /app
@ -47,7 +47,7 @@ RUN mkdir -p /app/logs /app/uploadPath && \
COPY --from=builder /app/qaup-admin/target/qaup-admin.jar app.jar
# 复制启动脚本
COPY docker/start.sh /app/start.sh
COPY deploy/docker/start.sh /app/start.sh
RUN chmod +x /app/start.sh && chown qaup:qaup /app/start.sh
# 切换到非 root 用户

View File

@ -3,7 +3,7 @@ version: '3.8'
services:
# PostgreSQL 数据库服务
qaup-postgres:
image: postgis/postgis:15-3.3
image: postgis/postgis:17-3.5-alpine
container_name: qaup-postgres
restart: unless-stopped
environment:
@ -41,7 +41,7 @@ services:
# Redis 缓存服务
qaup-redis:
image: redis:7-alpine
image: redis:8.0-alpine
container_name: qaup-redis
restart: unless-stopped
command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD:-}
@ -72,8 +72,8 @@ services:
# QAUP 应用服务
qaup-app:
build:
context: .
dockerfile: Dockerfile
context: ..
dockerfile: deploy/Dockerfile
image: qaup-app:latest
container_name: qaup-app
restart: unless-stopped
@ -130,8 +130,8 @@ services:
# Nginx 反向代理服务
qaup-nginx:
build:
context: .
dockerfile: docker/nginx/Dockerfile
context: ..
dockerfile: deploy/docker/nginx/Dockerfile
image: qaup-nginx:latest
container_name: qaup-nginx
restart: unless-stopped

View File

@ -0,0 +1,126 @@
#!/bin/bash
# QAUP Docker 镜像版本检查脚本
# 检查各个镜像的最新稳定版本
set -e
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
print_message() {
local color=$1
local message=$2
echo -e "${color}${message}${NC}"
}
# 检查 Docker Hub API 获取最新版本
check_dockerhub_tags() {
local repo=$1
local filter=${2:-""}
print_message $BLUE "检查 $repo 的版本..."
# 使用 Docker Hub API 获取标签
local api_url="https://registry.hub.docker.com/v2/repositories/$repo/tags?page_size=100"
if command -v curl &> /dev/null; then
local tags=$(curl -s "$api_url" | grep -o '"name":"[^"]*"' | cut -d'"' -f4 | head -20)
echo "最新的一些版本标签:"
echo "$tags" | head -10
else
print_message $YELLOW "curl 不可用,无法检查版本"
fi
echo ""
}
# 检查当前使用的版本
check_current_versions() {
print_message $BLUE "当前 docker-compose.yml 中使用的版本:"
echo ""
if [ -f "../docker-compose.yml" ]; then
echo "PostgreSQL/PostGIS:"
grep -A 1 "qaup-postgres:" ../docker-compose.yml | grep "image:" | awk '{print " " $2}'
echo "Redis:"
grep -A 1 "qaup-redis:" ../docker-compose.yml | grep "image:" | awk '{print " " $2}'
echo ""
fi
if [ -f "../Dockerfile" ]; then
echo "Dockerfile 中的镜像:"
grep "^FROM" ../Dockerfile | awk '{print " " $2}'
echo ""
fi
}
print_message $GREEN "========================================="
print_message $GREEN "QAUP Docker 镜像版本检查"
print_message $GREEN "========================================="
echo ""
# 检查当前版本
check_current_versions
# 检查各个镜像的最新版本
print_message $BLUE "检查 Docker Hub 上的最新版本..."
echo ""
# PostgreSQL/PostGIS
check_dockerhub_tags "postgis/postgis"
# Redis
check_dockerhub_tags "library/redis"
# OpenJDK
check_dockerhub_tags "library/openjdk"
# Maven
check_dockerhub_tags "library/maven"
# Nginx
check_dockerhub_tags "library/nginx"
# Node.js
check_dockerhub_tags "library/node"
print_message $YELLOW "注意事项:"
echo "1. 选择版本时应优先考虑稳定性而非最新性"
echo "2. LTS (Long Term Support) 版本通常是生产环境的最佳选择"
echo "3. 对于 PostGIS需要确保 PostgreSQL 版本兼容性"
echo "4. 建议在测试环境验证新版本后再用于生产"
echo ""
# 检查当前配置文件中的版本
if [ -f "image-versions.env" ]; then
print_message $BLUE "当前配置文件中的版本:"
source image-versions.env
echo "PostgreSQL/PostGIS: $POSTGRES_IMAGE"
echo "Redis: $REDIS_IMAGE"
echo "OpenJDK: $OPENJDK_IMAGE"
echo "Maven: $MAVEN_IMAGE"
echo "Nginx: $NGINX_IMAGE"
echo "Node.js: $NODE_IMAGE"
echo ""
fi
print_message $GREEN "基于实际检查的推荐版本组合:"
echo "PostgreSQL/PostGIS: postgis/postgis:15-3.5-alpine (稳定) 或 postgis/postgis:16-3.5-alpine (更新)"
echo "Redis: redis:7.4.5-alpine (7.x系列最新稳定版) 或 redis:8.0.3-alpine (最新版本)"
echo "OpenJDK: openjdk:17-jre-slim (LTS推荐)"
echo "Maven: maven:3.9.11-openjdk-17-slim (最新稳定版)"
echo "Nginx: nginx:stable-alpine (稳定版本)"
echo "Node.js: node:lts-alpine (当前LTS版本)"
echo ""
print_message $YELLOW "更新建议:"
echo "1. 运行 './update-image-versions.sh --dry-run' 预览更改"
echo "2. 运行 './update-image-versions.sh --backup' 执行更新"
echo "3. 在测试环境验证新版本兼容性"
echo "4. 更新离线部署包"

View File

@ -1,31 +1,124 @@
# QAUP Docker 镜像版本锁定配置
# 用于确保离线部署的一致性
# QAUP Docker 镜像版本配置文件
# 集中管理所有使用的 Docker 镜像版本
# 更新日期: 2024-01-31
# ===========================================
# 基础镜像版本
OPENJDK_VERSION=17-jre-slim
NGINX_VERSION=alpine
POSTGRES_VERSION=15-3.3
REDIS_VERSION=7-alpine
NODE_VERSION=18-alpine
MAVEN_VERSION=3.9.6-openjdk-17-slim
# ===========================================
# PostgreSQL with PostGIS
# PostgreSQL with PostGIS
# 使用 PostgreSQL 17 + PostGIS 3.5 (根据用户实际使用版本)
# PostgreSQL 17 是最新稳定版本PostGIS 3.5 是当前稳定版本
POSTGRES_IMAGE=postgis/postgis:17-3.5-alpine
# Redis
# 使用 Redis 8.0 最新版本 (根据用户实际使用版本)
REDIS_IMAGE=redis:8.0-alpine
# OpenJDK
# 使用 Java 17 LTS 版本(生产环境推荐)
OPENJDK_IMAGE=openjdk:17-jre-slim
# Maven
# 使用 Maven 3.9.11 + OpenJDK 17
MAVEN_IMAGE=maven:3.9.11-openjdk-17-slim
# Nginx
# 使用稳定版本
NGINX_IMAGE=nginx:stable-alpine
# Node.js
# 使用当前 LTS 版本
NODE_IMAGE=node:lts-alpine
# ===========================================
# 自定义镜像版本
QAUP_APP_VERSION=latest
QAUP_NGINX_VERSION=latest
# ===========================================
# 镜像完整名称(用于脚本引用)
OPENJDK_IMAGE=openjdk:${OPENJDK_VERSION}
NGINX_IMAGE=nginx:${NGINX_VERSION}
POSTGRES_IMAGE=postgis/postgis:${POSTGRES_VERSION}
REDIS_IMAGE=redis:${REDIS_VERSION}
NODE_IMAGE=node:${NODE_VERSION}
MAVEN_IMAGE=maven:${MAVEN_VERSION}
# QAUP 应用镜像
QAUP_APP_IMAGE=qaup-app:latest
QAUP_APP_IMAGE=qaup-app:${QAUP_APP_VERSION}
QAUP_NGINX_IMAGE=qaup-nginx:${QAUP_NGINX_VERSION}
# QAUP Nginx 镜像
QAUP_NGINX_IMAGE=qaup-nginx:latest
# 构建时间戳(自动生成)
BUILD_TIMESTAMP=$(date +%Y%m%d_%H%M%S)
# ===========================================
# 版本说明
# ===========================================
# 部署环境标识
DEPLOY_ENV=production
# PostgreSQL/PostGIS 版本选择说明 (基于用户实际使用版本):
# - postgis/postgis:17-3.5-alpine: PostgreSQL 17 + PostGIS 3.5 (当前使用,最新稳定版)
# - postgis/postgis:16-3.5-alpine: PostgreSQL 16 + PostGIS 3.5 (稳定选择)
# - postgis/postgis:15-3.5-alpine: PostgreSQL 15 + PostGIS 3.5 (保守选择)
# - postgis/postgis:*-3.6.0alpha1-alpine: PostGIS 3.6 alpha (不推荐生产使用)
# Java 版本选择说明:
# - Java 17: LTS 版本,生产环境推荐,兼容性好
# - Java 21: 最新 LTS 版本,性能更好,但需要验证兼容性
# - Java 25/26: 预览版本,不推荐生产使用
# Redis 版本说明 (基于用户实际使用版本):
# - 8.0-alpine: Redis 8.0 最新版本 (当前使用)
# - 7.4.5-alpine: 7.x 系列最新稳定版本
# - 7.2.x-alpine: 较老但稳定的版本
# Maven 版本说明:
# - 3.9.11: 当前最新稳定版本
# - 与 OpenJDK 版本保持一致很重要
# Node.js 版本说明:
# - lts-alpine: 总是指向当前 LTS 版本
# - iron-*: Iron 是 Node.js 18.x LTS 的代号
# - jod-*: 可能是更新的 LTS 版本代号
# Nginx 版本说明:
# - stable-alpine: 总是指向稳定版本
# - mainline-*: 开发版本,包含最新特性但可能不稳定
# ===========================================
# 更新检查命令
# ===========================================
# 运行以下命令检查最新版本:
# ./check-image-versions.sh
# 更新镜像版本后,需要同步更新:
# 1. docker-compose.yml
# 2. Dockerfile
# 3. docker/nginx/Dockerfile
# 4. prepare-offline-images.sh
# ===========================================
# 版本更新记录
# ===========================================
# 2024-01-31: 根据用户实际使用版本更新
# - PostgreSQL: 15-3.5-alpine → 17-3.5-alpine (升级到最新稳定版)
# - Redis: 7.4.5-alpine → 8.0-alpine (升级到最新版本)
# - 其他组件保持不变
# 注意事项:
# - PostgreSQL 17 是最新稳定版本,包含性能改进和新特性
# - Redis 8.0 是最新版本,包含新的数据结构和性能优化
# - 升级前请在测试环境验证兼容性
# - 建议备份现有数据后再进行升级
# ===========================================
# 版本兼容性检查清单
# ===========================================
# 更新版本前请确认:
# □ Spring Boot 版本与 Java 版本兼容
# □ PostGIS 版本与应用程序的空间数据处理兼容
# □ Redis 版本与应用程序的缓存功能兼容
# □ Node.js 版本与前端构建工具兼容
# □ 在测试环境验证所有功能正常
# □ 检查是否有破坏性变更
# 推荐的更新流程:
# 1. 运行 ./check-image-versions.sh 检查最新版本
# 2. 更新 image-versions.env 配置文件
# 3. 运行 ./update-image-versions.sh --dry-run 预览更改
# 4. 运行 ./update-image-versions.sh --backup 执行更新
# 5. 在测试环境验证兼容性
# 6. 更新离线部署包

View File

@ -1,5 +1,5 @@
# 多阶段构建 - 前端构建阶段
FROM node:18-alpine AS frontend-builder
FROM node:lts-alpine AS frontend-builder
# 设置工作目录
WORKDIR /app
@ -13,7 +13,7 @@ COPY qaup-ui/ ./
RUN npm run build:prod
# Nginx 运行阶段
FROM nginx:alpine
FROM nginx:stable-alpine
# 安装必要工具
RUN apk add --no-cache curl
@ -26,10 +26,10 @@ RUN mkdir -p /var/cache/nginx/client_temp && \
COPY --from=frontend-builder /app/dist /usr/share/nginx/html
# 复制 Nginx 配置文件
COPY docker/nginx/nginx.conf /etc/nginx/nginx.conf
COPY docker/nginx/default.conf /etc/nginx/conf.d/default.conf
COPY docker/nginx/nginx-env.conf.template /etc/nginx/conf.d/nginx-env.conf.template
COPY docker/nginx/start-nginx.sh /start-nginx.sh
COPY deploy/docker/nginx/nginx.conf /etc/nginx/nginx.conf
COPY deploy/docker/nginx/default.conf /etc/nginx/conf.d/default.conf
COPY deploy/docker/nginx/nginx-env.conf.template /etc/nginx/conf.d/nginx-env.conf.template
COPY deploy/docker/nginx/start-nginx.sh /start-nginx.sh
# 设置执行权限
RUN chmod +x /start-nginx.sh

View File

@ -1,56 +0,0 @@
#!/bin/bash
# QAUP 数据库备份脚本
set -e
# 配置变量
BACKUP_DIR="/backup"
DB_NAME="${POSTGRES_DB:-qaup}"
DB_USER="${POSTGRES_USER:-postgres}"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="qaup_backup_${TIMESTAMP}.sql"
BACKUP_PATH="$BACKUP_DIR/$BACKUP_FILE"
echo "========================================="
echo "QAUP 数据库备份开始"
echo "========================================="
# 创建备份目录
mkdir -p "$BACKUP_DIR"
# 执行备份
echo "备份数据库: $DB_NAME"
echo "备份文件: $BACKUP_PATH"
pg_dump -h localhost -U "$DB_USER" -d "$DB_NAME" \
--verbose \
--clean \
--if-exists \
--create \
--format=plain \
--encoding=UTF8 \
> "$BACKUP_PATH"
# 压缩备份文件
echo "压缩备份文件..."
gzip "$BACKUP_PATH"
COMPRESSED_FILE="${BACKUP_PATH}.gz"
# 显示备份信息
echo ""
echo "========================================="
echo "备份完成信息:"
echo "========================================="
echo "备份文件: $COMPRESSED_FILE"
echo "文件大小: $(du -h "$COMPRESSED_FILE" | cut -f1)"
echo "备份时间: $(date)"
# 清理旧备份保留最近7天
echo ""
echo "清理旧备份文件保留7天..."
find "$BACKUP_DIR" -name "qaup_backup_*.sql.gz" -mtime +7 -delete
echo "清理完成"
echo ""
echo "数据库备份完成!"

View File

@ -0,0 +1,650 @@
#!/bin/bash
# QAUP 数据库管理脚本
# 统一管理数据库相关的所有操作:导出、导入、备份、恢复、健康检查等
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
# 默认配置
DB_HOST=${DB_HOST:-localhost}
DB_PORT=${DB_PORT:-5432}
DB_NAME=${DB_NAME:-qaup}
DB_USER=${DB_USER:-postgres}
EXPORT_DIR=${EXPORT_DIR:-$SCRIPT_DIR/export}
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
print_message() {
local color=$1
local message=$2
echo -e "${color}${message}${NC}"
}
# 显示帮助信息
show_help() {
echo "QAUP 数据库管理脚本"
echo ""
echo "用法: $0 <命令> [选项]"
echo ""
echo "数据管理命令:"
echo " prepare-default 准备默认初始数据"
echo " prepare-export 从现有数据库导出并准备数据"
echo " prepare-custom 自定义数据组合"
echo " prepare-status 显示数据文件状态"
echo " prepare-clean 清理数据文件"
echo ""
echo "导出命令:"
echo " export-all 导出完整数据库"
echo " export-schema 仅导出表结构"
echo " export-data 仅导出数据"
echo " export-initial 导出分层初始数据(推荐)"
echo ""
echo "备份恢复命令:"
echo " backup 备份数据库"
echo " restore <file> 恢复数据库"
echo ""
echo "维护命令:"
echo " health 健康检查"
echo " test-connection 测试数据库连接"
echo ""
echo "环境变量:"
echo " DB_HOST 数据库主机默认localhost"
echo " DB_PORT 数据库端口默认5432"
echo " DB_NAME 数据库名称默认qaup"
echo " DB_USER 数据库用户默认postgres"
echo " EXPORT_DIR 导出目录(默认:./export"
echo ""
echo "示例:"
echo " $0 prepare-default # 准备默认数据"
echo " $0 prepare-export # 从现有系统导出数据"
echo " $0 export-initial # 导出分层初始数据"
echo " $0 backup # 备份数据库"
echo " $0 health # 健康检查"
}
# ==========================================
# 数据准备功能
# ==========================================
# 显示数据文件状态
show_data_status() {
print_message $BLUE "当前数据文件状态:"
echo ""
local files=(
"initial_data.sql:实际使用的初始数据"
"initial_data.template.sql:默认数据模板"
"01_system_data.sql:系统配置数据"
"02_business_data.sql:业务基础数据"
"03_sample_data.sql:示例数据"
)
for file_info in "${files[@]}"; do
local file="${file_info%%:*}"
local desc="${file_info##*:}"
local path="$SCRIPT_DIR/$file"
if [ -f "$path" ]; then
local size=$(du -h "$path" | cut -f1)
local lines=$(wc -l < "$path")
printf " %-25s %s %8s %6s 行 - %s\n" "$file" "✓" "$size" "$lines" "$desc"
else
printf " %-25s %s %8s %6s - %s\n" "$file" "✗" "-" "-" "$desc"
fi
done
echo ""
if [ -f "$SCRIPT_DIR/initial_data.sql" ]; then
print_message $GREEN "部署时将使用: initial_data.sql"
else
print_message $YELLOW "部署时将按顺序使用分层数据文件"
fi
}
# 准备默认数据
prepare_default_data() {
print_message $BLUE "准备默认模板数据..."
if [ ! -f "$SCRIPT_DIR/initial_data.template.sql" ]; then
print_message $RED "错误: 默认模板文件不存在"
exit 1
fi
cp "$SCRIPT_DIR/initial_data.template.sql" "$SCRIPT_DIR/initial_data.sql"
print_message $GREEN "✓ 已准备默认数据"
print_message $YELLOW "默认管理员账号: admin"
print_message $YELLOW "默认管理员密码: admin123"
}
# 从现有数据库导出并准备数据
prepare_export_data() {
print_message $BLUE "从现有数据库导出数据..."
# 检查连接参数
if [ -z "$DB_HOST" ] || [ -z "$DB_NAME" ] || [ -z "$DB_USER" ]; then
print_message $YELLOW "请设置数据库连接环境变量或使用默认值"
echo "当前设置:"
echo " DB_HOST=$DB_HOST"
echo " DB_PORT=$DB_PORT"
echo " DB_NAME=$DB_NAME"
echo " DB_USER=$DB_USER"
echo ""
read -p "是否继续? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
exit 1
fi
fi
# 测试连接
test_database_connection
# 导出分层数据
export_initial_data
# 使用导出的完整数据
if [ -f "$EXPORT_DIR/initial_data_complete.sql" ]; then
cp "$EXPORT_DIR/initial_data_complete.sql" "$SCRIPT_DIR/initial_data.sql"
print_message $GREEN "✓ 已导出并准备完整初始数据"
else
print_message $RED "错误: 导出失败"
exit 1
fi
}
# 自定义数据组合
prepare_custom_data() {
print_message $BLUE "自定义数据组合..."
local system_data="$SCRIPT_DIR/01_system_data.sql"
local business_data="$SCRIPT_DIR/02_business_data.sql"
local sample_data="$SCRIPT_DIR/03_sample_data.sql"
if [ ! -f "$system_data" ]; then
print_message $RED "错误: 未找到系统数据文件,请先导出数据"
print_message $YELLOW "提示: $0 export-initial"
exit 1
fi
echo "请选择要包含的数据类型:"
echo "1. 系统配置数据 (必需) ✓"
echo "2. 业务基础数据"
echo "3. 示例数据"
echo ""
local include_business=false
local include_sample=false
if [ -f "$business_data" ]; then
read -p "是否包含业务基础数据? (Y/n): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Nn]$ ]]; then
include_business=true
fi
fi
if [ -f "$sample_data" ]; then
read -p "是否包含示例数据? (y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
include_sample=true
fi
fi
# 生成自定义数据文件
local output_file="$SCRIPT_DIR/initial_data.sql"
cat > "$output_file" << 'EOF'
-- QAUP 自定义初始数据组合
-- 此文件由 db-manager.sh 自动生成
EOF
# 添加系统数据
echo "-- 系统基础配置数据" >> "$output_file"
cat "$system_data" >> "$output_file"
print_message $GREEN "✓ 已包含系统配置数据"
# 添加业务数据
if [ "$include_business" = true ] && [ -f "$business_data" ]; then
echo "-- 业务基础数据" >> "$output_file"
cat "$business_data" >> "$output_file"
print_message $GREEN "✓ 已包含业务基础数据"
fi
# 添加示例数据
if [ "$include_sample" = true ] && [ -f "$sample_data" ]; then
echo "-- 示例数据" >> "$output_file"
cat "$sample_data" >> "$output_file"
print_message $GREEN "✓ 已包含示例数据"
fi
print_message $GREEN "✓ 自定义数据组合完成"
}
# 清理数据文件
clean_data_files() {
print_message $YELLOW "清理数据文件..."
read -p "确定要清理所有数据文件吗? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
return
fi
local files_to_clean=(
"initial_data.sql"
"01_system_data.sql"
"02_business_data.sql"
"03_sample_data.sql"
)
for file in "${files_to_clean[@]}"; do
local path="$SCRIPT_DIR/$file"
if [ -f "$path" ]; then
rm "$path"
print_message $GREEN "✓ 已删除 $file"
fi
done
if [ -d "$EXPORT_DIR" ]; then
rm -rf "$EXPORT_DIR"
print_message $GREEN "✓ 已清理导出目录"
fi
}
# ==========================================
# 数据导出功能
# ==========================================
# 测试数据库连接
test_database_connection() {
print_message $BLUE "测试数据库连接..."
if command -v pg_isready &> /dev/null; then
if pg_isready -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" &>/dev/null; then
print_message $GREEN "✓ 数据库连接成功"
else
print_message $RED "✗ 数据库连接失败"
exit 1
fi
else
print_message $YELLOW "警告: pg_isready 不可用,跳过连接测试"
fi
}
# 导出完整数据库
export_all_data() {
print_message $BLUE "导出完整数据库..."
test_database_connection
mkdir -p "$EXPORT_DIR"
local output_file="$EXPORT_DIR/qaup_complete_backup.sql"
pg_dump -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" \
--no-owner --no-privileges --clean --if-exists \
> "$output_file"
print_message $GREEN "✓ 完整数据库导出完成: $output_file"
}
# 导出表结构
export_schema_only() {
print_message $BLUE "导出数据库表结构..."
test_database_connection
mkdir -p "$EXPORT_DIR"
local output_file="$EXPORT_DIR/qaup_database_schema.sql"
pg_dump -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" \
--schema-only --no-owner --no-privileges --clean --if-exists \
> "$output_file"
print_message $GREEN "✓ 表结构导出完成: $output_file"
}
# 导出分层初始数据
export_initial_data() {
print_message $BLUE "导出分层初始数据..."
test_database_connection
mkdir -p "$EXPORT_DIR"
# 导出系统基础数据
export_system_data
# 导出业务基础数据
export_business_data
# 导出示例数据
export_sample_data
# 生成合并文件
generate_combined_data
}
# 导出系统基础数据
export_system_data() {
local output_file="$EXPORT_DIR/01_system_data.sql"
local system_tables=(
"sys_config" "sys_dict_type" "sys_dict_data" "sys_dept" "sys_post"
"sys_role" "sys_menu" "sys_user" "sys_user_role" "sys_user_post"
"sys_role_menu" "sys_role_dept" "sys_notice"
)
local table_args=""
for table in "${system_tables[@]}"; do
table_args="$table_args --table=$table"
done
cat > "$output_file" << 'EOF'
-- QAUP 系统基础配置数据
SET session_replication_role = replica;
EOF
pg_dump -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" \
--data-only --no-owner --no-privileges --disable-triggers --inserts \
$table_args >> "$output_file"
cat >> "$output_file" << 'EOF'
SET session_replication_role = DEFAULT;
EOF
print_message $GREEN "✓ 系统基础数据导出完成"
}
# 导出业务基础数据
export_business_data() {
local output_file="$EXPORT_DIR/02_business_data.sql"
local business_tables=(
"sys_vehicle_type" "airport_areas" "spatial_rules"
"spatial_rule_vehicle_types" "transport_routes"
)
local table_args=""
for table in "${business_tables[@]}"; do
table_args="$table_args --table=$table"
done
cat > "$output_file" << 'EOF'
-- QAUP 业务基础数据
SET session_replication_role = replica;
EOF
pg_dump -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" \
--data-only --no-owner --no-privileges --disable-triggers --inserts \
$table_args >> "$output_file" 2>/dev/null || true
cat >> "$output_file" << 'EOF'
SET session_replication_role = DEFAULT;
EOF
print_message $GREEN "✓ 业务基础数据导出完成"
}
# 导出示例数据
export_sample_data() {
local output_file="$EXPORT_DIR/03_sample_data.sql"
local sample_tables=("sys_vehicle_info")
local table_args=""
for table in "${sample_tables[@]}"; do
table_args="$table_args --table=$table"
done
cat > "$output_file" << 'EOF'
-- QAUP 示例数据
SET session_replication_role = replica;
EOF
pg_dump -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" \
--data-only --no-owner --no-privileges --disable-triggers --inserts \
$table_args >> "$output_file" 2>/dev/null || true
cat >> "$output_file" << 'EOF'
SET session_replication_role = DEFAULT;
EOF
print_message $GREEN "✓ 示例数据导出完成"
}
# 生成合并的完整数据文件
generate_combined_data() {
local combined_file="$EXPORT_DIR/initial_data_complete.sql"
cat > "$combined_file" << 'EOF'
-- QAUP 系统完整初始数据
-- 此文件由 db-manager.sh 自动生成
EOF
for data_file in "01_system_data.sql" "02_business_data.sql" "03_sample_data.sql"; do
if [ -f "$EXPORT_DIR/$data_file" ]; then
cat "$EXPORT_DIR/$data_file" >> "$combined_file"
echo "" >> "$combined_file"
fi
done
print_message $GREEN "✓ 完整初始数据文件生成完成: $combined_file"
}
# ==========================================
# 备份恢复功能
# ==========================================
# 备份数据库
backup_database() {
print_message $BLUE "备份数据库..."
local timestamp=$(date +%Y%m%d_%H%M%S)
local backup_dir="$PROJECT_ROOT/backup/postgres"
local backup_file="$backup_dir/qaup_backup_$timestamp.sql"
mkdir -p "$backup_dir"
# 检查是否在容器内
if [ -f "/.dockerenv" ]; then
# 在容器内执行备份
pg_dump -U "$POSTGRES_USER" -d "$POSTGRES_DB" \
--no-owner --no-privileges > "$backup_file"
else
# 在容器外执行备份
test_database_connection
pg_dump -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" \
--no-owner --no-privileges > "$backup_file"
fi
print_message $GREEN "✓ 数据库备份完成: $backup_file"
}
# 恢复数据库
restore_database() {
local backup_file=$1
if [ -z "$backup_file" ]; then
print_message $RED "错误: 请指定备份文件"
exit 1
fi
if [ ! -f "$backup_file" ]; then
print_message $RED "错误: 备份文件不存在: $backup_file"
exit 1
fi
print_message $BLUE "恢复数据库..."
print_message $YELLOW "警告: 这将覆盖现有数据"
read -p "确定要继续吗? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
exit 1
fi
# 检查是否在容器内
if [ -f "/.dockerenv" ]; then
# 在容器内执行恢复
psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" -f "$backup_file"
else
# 在容器外执行恢复
test_database_connection
psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" -f "$backup_file"
fi
print_message $GREEN "✓ 数据库恢复完成"
}
# ==========================================
# 健康检查功能
# ==========================================
# 健康检查
health_check() {
print_message $BLUE "数据库健康检查..."
# 检查是否在容器内
if [ -f "/.dockerenv" ]; then
# 容器内健康检查
container_health_check
else
# 容器外健康检查
external_health_check
fi
}
# 容器内健康检查
container_health_check() {
local errors=0
# 检查 PostgreSQL 进程
if pgrep -x postgres > /dev/null; then
print_message $GREEN "✓ PostgreSQL 进程运行正常"
else
print_message $RED "✗ PostgreSQL 进程未运行"
errors=$((errors + 1))
fi
# 检查数据库连接
if psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "SELECT 1;" > /dev/null 2>&1; then
print_message $GREEN "✓ 数据库连接正常"
else
print_message $RED "✗ 数据库连接失败"
errors=$((errors + 1))
fi
# 检查表数量
local table_count=$(psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" -t -c "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = 'public';" 2>/dev/null | tr -d ' ')
if [ "$table_count" -gt 0 ]; then
print_message $GREEN "✓ 数据库包含 $table_count 个表"
else
print_message $RED "✗ 数据库中没有表"
errors=$((errors + 1))
fi
if [ $errors -eq 0 ]; then
print_message $GREEN "数据库健康检查通过"
else
print_message $RED "数据库健康检查失败,发现 $errors 个问题"
exit 1
fi
}
# 容器外健康检查
external_health_check() {
test_database_connection
# 检查表数量
local table_count=$(psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" -t -c "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = 'public';" 2>/dev/null | tr -d ' ')
if [ "$table_count" -gt 0 ]; then
print_message $GREEN "✓ 数据库包含 $table_count 个表"
else
print_message $RED "✗ 数据库中没有表"
exit 1
fi
print_message $GREEN "数据库健康检查通过"
}
# ==========================================
# 主函数
# ==========================================
main() {
if [ $# -eq 0 ]; then
show_help
exit 0
fi
local command=$1
shift
case $command in
# 数据准备命令
prepare-default)
prepare_default_data
;;
prepare-export)
prepare_export_data
;;
prepare-custom)
prepare_custom_data
;;
prepare-status)
show_data_status
;;
prepare-clean)
clean_data_files
;;
# 导出命令
export-all)
export_all_data
;;
export-schema)
export_schema_only
;;
export-initial)
export_initial_data
;;
# 备份恢复命令
backup)
backup_database
;;
restore)
restore_database "$@"
;;
# 维护命令
health)
health_check
;;
test-connection)
test_database_connection
;;
# 帮助
help|--help|-h)
show_help
;;
*)
print_message $RED "未知命令: $command"
show_help
exit 1
;;
esac
}
main "$@"

View File

@ -1,29 +0,0 @@
#!/bin/bash
# PostgreSQL 健康检查脚本
set -e
DB_NAME="${POSTGRES_DB:-qaup}"
DB_USER="${POSTGRES_USER:-postgres}"
# 检查 PostgreSQL 服务是否运行
if ! pg_isready -h localhost -p 5432 -U "$DB_USER" -d "$DB_NAME" -q; then
echo "PostgreSQL 服务未就绪"
exit 1
fi
# 检查数据库连接
if ! psql -h localhost -U "$DB_USER" -d "$DB_NAME" -c "SELECT 1;" > /dev/null 2>&1; then
echo "数据库连接失败"
exit 1
fi
# 检查 PostGIS 扩展
if ! psql -h localhost -U "$DB_USER" -d "$DB_NAME" -c "SELECT PostGIS_Version();" > /dev/null 2>&1; then
echo "PostGIS 扩展不可用"
exit 1
fi
echo "数据库健康检查通过"
exit 0

View File

@ -32,11 +32,39 @@ else
echo "警告: 未找到数据库架构文件"
fi
# 导入初始数据(如果存在)
if [ -f "/docker-entrypoint-initdb.d/initial_data.sql" ]; then
echo "导入初始数据..."
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" -f /docker-entrypoint-initdb.d/initial_data.sql
echo "✓ 初始数据导入完成"
# 导入初始数据(按优先级顺序)
data_files=(
"/docker-entrypoint-initdb.d/initial_data.sql"
"/docker-entrypoint-initdb.d/01_system_data.sql"
"/docker-entrypoint-initdb.d/02_business_data.sql"
"/docker-entrypoint-initdb.d/03_sample_data.sql"
)
for data_file in "${data_files[@]}"; do
if [ -f "$data_file" ]; then
echo "导入数据文件: $(basename "$data_file")"
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" -f "$data_file"
echo "$(basename "$data_file") 导入完成"
# 如果找到 initial_data.sql就不再导入其他文件
if [[ "$data_file" == *"initial_data.sql" ]]; then
break
fi
fi
done
# 检查是否导入了任何数据
imported_any=false
for data_file in "${data_files[@]}"; do
if [ -f "$data_file" ]; then
imported_any=true
break
fi
done
if [ "$imported_any" = false ]; then
echo "警告: 未找到初始数据文件,系统将使用空数据库启动"
echo "建议从现有系统导出数据或使用默认初始数据"
fi
# 创建数据库用户和权限设置

View File

@ -0,0 +1,305 @@
-- QAUP 系统初始数据
-- 包含系统运行所需的基础数据
-- ==========================================
-- 系统配置数据
-- ==========================================
-- 插入系统配置参数
INSERT INTO sys_config (config_id, config_name, config_key, config_value, config_type, create_by, create_time, remark) VALUES
(1, '主框架页-默认皮肤样式名称', 'sys.index.skinName', 'skin-blue', 'Y', 'admin', NOW(), '蓝色 skin-blue、绿色 skin-green、紫色 skin-purple、红色 skin-red、黄色 skin-yellow'),
(2, '用户管理-账号初始密码', 'sys.user.initPassword', '123456', 'Y', 'admin', NOW(), '初始化密码 123456'),
(3, '主框架页-侧边栏主题', 'sys.index.sideTheme', 'theme-dark', 'Y', 'admin', NOW(), '深色主题theme-dark浅色主题theme-light'),
(4, '账号自助-验证码开关', 'sys.account.captchaEnabled', 'true', 'Y', 'admin', NOW(), '是否开启验证码功能true开启false关闭'),
(5, '账号自助-是否开启用户注册功能', 'sys.account.registerUser', 'false', 'Y', 'admin', NOW(), '是否开启注册用户功能true开启false关闭'),
(6, '用户登录-黑名单列表', 'sys.login.blackIPList', '', 'Y', 'admin', NOW(), '设置登录IP黑名单限制多个匹配项以;分隔,支持匹配(*通配、网段)');
-- ==========================================
-- 字典类型数据
-- ==========================================
-- 插入字典类型
INSERT INTO sys_dict_type (dict_id, dict_name, dict_type, status, create_by, create_time, remark) VALUES
(1, '用户性别', 'sys_user_sex', '0', 'admin', NOW(), '用户性别列表'),
(2, '菜单状态', 'sys_show_hide', '0', 'admin', NOW(), '菜单状态列表'),
(3, '系统开关', 'sys_normal_disable', '0', 'admin', NOW(), '系统开关列表'),
(4, '任务状态', 'sys_job_status', '0', 'admin', NOW(), '任务状态列表'),
(5, '任务分组', 'sys_job_group', '0', 'admin', NOW(), '任务分组列表'),
(6, '系统是否', 'sys_yes_no', '0', 'admin', NOW(), '系统是否列表'),
(7, '通知类型', 'sys_notice_type', '0', 'admin', NOW(), '通知类型列表'),
(8, '通知状态', 'sys_notice_status', '0', 'admin', NOW(), '通知状态列表'),
(9, '操作类型', 'sys_oper_type', '0', 'admin', NOW(), '操作类型列表'),
(10, '系统状态', 'sys_common_status', '0', 'admin', NOW(), '登录状态列表'),
(11, '车辆类型', 'sys_vehicle_type', '0', 'admin', NOW(), '车辆类型列表'),
(12, '告警级别', 'sys_alert_level', '0', 'admin', NOW(), '告警级别列表'),
(13, '违规类型', 'sys_violation_type', '0', 'admin', NOW(), '违规类型列表');
-- ==========================================
-- 字典数据
-- ==========================================
-- 用户性别
INSERT INTO sys_dict_data (dict_code, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark) VALUES
(1, 1, '', '0', 'sys_user_sex', '', '', 'Y', '0', 'admin', NOW(), '性别男'),
(2, 2, '', '1', 'sys_user_sex', '', '', 'N', '0', 'admin', NOW(), '性别女'),
(3, 3, '未知', '2', 'sys_user_sex', '', '', 'N', '0', 'admin', NOW(), '性别未知');
-- 菜单状态
INSERT INTO sys_dict_data (dict_code, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark) VALUES
(4, 1, '显示', '0', 'sys_show_hide', '', 'primary', 'Y', '0', 'admin', NOW(), '显示菜单'),
(5, 2, '隐藏', '1', 'sys_show_hide', '', 'danger', 'N', '0', 'admin', NOW(), '隐藏菜单');
-- 系统开关
INSERT INTO sys_dict_data (dict_code, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark) VALUES
(6, 1, '正常', '0', 'sys_normal_disable', '', 'primary', 'Y', '0', 'admin', NOW(), '正常状态'),
(7, 2, '停用', '1', 'sys_normal_disable', '', 'danger', 'N', '0', 'admin', NOW(), '停用状态');
-- 系统是否
INSERT INTO sys_dict_data (dict_code, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark) VALUES
(8, 1, '', 'Y', 'sys_yes_no', '', 'primary', 'Y', '0', 'admin', NOW(), '系统默认是'),
(9, 2, '', 'N', 'sys_yes_no', '', 'danger', 'N', '0', 'admin', NOW(), '系统默认否');
-- 通知类型
INSERT INTO sys_dict_data (dict_code, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark) VALUES
(10, 1, '通知', '1', 'sys_notice_type', '', 'warning', 'Y', '0', 'admin', NOW(), '通知'),
(11, 2, '公告', '2', 'sys_notice_type', '', 'success', 'N', '0', 'admin', NOW(), '公告');
-- 通知状态
INSERT INTO sys_dict_data (dict_code, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark) VALUES
(12, 1, '正常', '0', 'sys_notice_status', '', 'primary', 'Y', '0', 'admin', NOW(), '正常状态'),
(13, 2, '关闭', '1', 'sys_notice_status', '', 'danger', 'N', '0', 'admin', NOW(), '关闭状态');
-- 操作类型
INSERT INTO sys_dict_data (dict_code, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark) VALUES
(14, 1, '其他', '0', 'sys_oper_type', '', 'info', 'N', '0', 'admin', NOW(), '其他操作'),
(15, 2, '新增', '1', 'sys_oper_type', '', 'info', 'N', '0', 'admin', NOW(), '新增操作'),
(16, 3, '修改', '2', 'sys_oper_type', '', 'info', 'N', '0', 'admin', NOW(), '修改操作'),
(17, 4, '删除', '3', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', NOW(), '删除操作'),
(18, 5, '授权', '4', 'sys_oper_type', '', 'primary', 'N', '0', 'admin', NOW(), '授权操作'),
(19, 6, '导出', '5', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', NOW(), '导出操作'),
(20, 7, '导入', '6', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', NOW(), '导入操作'),
(21, 8, '强退', '7', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', NOW(), '强退操作'),
(22, 9, '生成代码', '8', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', NOW(), '生成操作'),
(23, 10, '清空数据', '9', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', NOW(), '清空操作');
-- 系统状态
INSERT INTO sys_dict_data (dict_code, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark) VALUES
(24, 1, '成功', '0', 'sys_common_status', '', 'primary', 'N', '0', 'admin', NOW(), '正常状态'),
(25, 2, '失败', '1', 'sys_common_status', '', 'danger', 'N', '0', 'admin', NOW(), '停用状态');
-- 告警级别
INSERT INTO sys_dict_data (dict_code, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark) VALUES
(26, 1, '信息', 'INFO', 'sys_alert_level', '', 'info', 'N', '0', 'admin', NOW(), '信息级别'),
(27, 2, '警告', 'WARNING', 'sys_alert_level', '', 'warning', 'N', '0', 'admin', NOW(), '警告级别'),
(28, 3, '严重', 'CRITICAL', 'sys_alert_level', '', 'danger', 'N', '0', 'admin', NOW(), '严重级别'),
(29, 4, '紧急', 'EMERGENCY', 'sys_alert_level', '', 'danger', 'N', '0', 'admin', NOW(), '紧急级别');
-- 违规类型
INSERT INTO sys_dict_data (dict_code, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark) VALUES
(30, 1, '超速', 'SPEED', 'sys_violation_type', '', 'warning', 'N', '0', 'admin', NOW(), '超速违规'),
(31, 2, '未授权进入', 'ACCESS', 'sys_violation_type', '', 'danger', 'N', '0', 'admin', NOW(), '未授权进入'),
(32, 3, '超高', 'HEIGHT', 'sys_violation_type', '', 'warning', 'N', '0', 'admin', NOW(), '超高违规'),
(33, 4, '超重', 'WEIGHT', 'sys_violation_type', '', 'warning', 'N', '0', 'admin', NOW(), '超重违规'),
(34, 5, '其他', 'OTHER', 'sys_violation_type', '', 'info', 'N', '0', 'admin', NOW(), '其他违规');
-- ==========================================
-- 部门数据
-- ==========================================
-- 插入部门信息
INSERT INTO sys_dept (dept_id, parent_id, ancestors, dept_name, order_num, leader, phone, email, status, del_flag, create_by, create_time) VALUES
(100, 0, '0', 'QAUP管理系统', 0, 'admin', '15888888888', 'admin@qaup.com', '0', '0', 'admin', NOW()),
(101, 100, '0,100', '系统管理部', 1, 'admin', '15888888888', 'admin@qaup.com', '0', '0', 'admin', NOW()),
(102, 100, '0,100', '运营管理部', 2, 'admin', '15888888888', 'admin@qaup.com', '0', '0', 'admin', NOW()),
(103, 101, '0,100,101', '研发部门', 1, 'admin', '15888888888', 'admin@qaup.com', '0', '0', 'admin', NOW()),
(104, 101, '0,100,101', '市场部门', 2, 'admin', '15888888888', 'admin@qaup.com', '0', '0', 'admin', NOW()),
(105, 101, '0,100,101', '测试部门', 3, 'admin', '15888888888', 'admin@qaup.com', '0', '0', 'admin', NOW());
-- ==========================================
-- 岗位数据
-- ==========================================
-- 插入岗位信息
INSERT INTO sys_post (post_id, post_code, post_name, post_sort, status, create_by, create_time, remark) VALUES
(1, 'ceo', '董事长', 1, '0', 'admin', NOW(), ''),
(2, 'se', '项目经理', 2, '0', 'admin', NOW(), ''),
(3, 'hr', '人力资源', 3, '0', 'admin', NOW(), ''),
(4, 'user', '普通员工', 4, '0', 'admin', NOW(), '');
-- ==========================================
-- 角色数据
-- ==========================================
-- 插入角色信息
INSERT INTO sys_role (role_id, role_name, role_key, role_sort, data_scope, menu_check_strictly, dept_check_strictly, status, del_flag, create_by, create_time, remark) VALUES
(1, '超级管理员', 'admin', 1, '1', true, true, '0', '0', 'admin', NOW(), '超级管理员'),
(2, '普通角色', 'common', 2, '2', true, true, '0', '0', 'admin', NOW(), '普通角色');
-- ==========================================
-- 菜单数据
-- ==========================================
-- 插入菜单信息(主要菜单结构)
INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, route_name, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark) VALUES
-- 系统管理
(1, '系统管理', 0, 1, 'system', NULL, '', '', 1, 0, 'M', '0', 0, '', 'system', 'admin', NOW(), '系统管理目录'),
(100, '用户管理', 1, 1, 'user', 'system/user/index', '', '', 1, 0, 'C', '0', 0, 'system:user:list', 'user', 'admin', NOW(), '用户管理菜单'),
(101, '角色管理', 1, 2, 'role', 'system/role/index', '', '', 1, 0, 'C', '0', 0, 'system:role:list', 'peoples', 'admin', NOW(), '角色管理菜单'),
(102, '菜单管理', 1, 3, 'menu', 'system/menu/index', '', '', 1, 0, 'C', '0', 0, 'system:menu:list', 'tree-table', 'admin', NOW(), '菜单管理菜单'),
(103, '部门管理', 1, 4, 'dept', 'system/dept/index', '', '', 1, 0, 'C', '0', 0, 'system:dept:list', 'tree', 'admin', NOW(), '部门管理菜单'),
(104, '岗位管理', 1, 5, 'post', 'system/post/index', '', '', 1, 0, 'C', '0', 0, 'system:post:list', 'post', 'admin', NOW(), '岗位管理菜单'),
(105, '字典管理', 1, 6, 'dict', 'system/dict/index', '', '', 1, 0, 'C', '0', 0, 'system:dict:list', 'dict', 'admin', NOW(), '字典管理菜单'),
(106, '参数设置', 1, 7, 'config', 'system/config/index', '', '', 1, 0, 'C', '0', 0, 'system:config:list', 'edit', 'admin', NOW(), '参数设置菜单'),
(107, '通知公告', 1, 8, 'notice', 'system/notice/index', '', '', 1, 0, 'C', '0', 0, 'system:notice:list', 'message', 'admin', NOW(), '通知公告菜单'),
(108, '日志管理', 1, 9, 'log', '', '', '', 1, 0, 'M', '0', 0, '', 'log', 'admin', NOW(), '日志管理菜单'),
(500, '操作日志', 108, 1, 'operlog', 'monitor/operlog/index', '', '', 1, 0, 'C', '0', 0, 'monitor:operlog:list', 'form', 'admin', NOW(), '操作日志菜单'),
(501, '登录日志', 108, 2, 'logininfor', 'monitor/logininfor/index', '', '', 1, 0, 'C', '0', 0, 'monitor:logininfor:list', 'logininfor', 'admin', NOW(), '登录日志菜单'),
-- 车辆管理
(2, '车辆管理', 0, 2, 'vehicle', NULL, '', '', 1, 0, 'M', '0', 0, '', 'guide', 'admin', NOW(), '车辆管理目录'),
(200, '车辆信息', 2, 1, 'info', 'vehicle/info/index', '', '', 1, 0, 'C', '0', 0, 'vehicle:info:list', 'tree-table', 'admin', NOW(), '车辆信息菜单'),
(201, '车辆类型', 2, 2, 'type', 'vehicle/type/index', '', '', 1, 0, 'C', '0', 0, 'vehicle:type:list', 'dict', 'admin', NOW(), '车辆类型菜单'),
-- 监控管理
(3, '监控管理', 0, 3, 'monitor', NULL, '', '', 1, 0, 'M', '0', 0, '', 'monitor', 'admin', NOW(), '监控管理目录'),
(300, '实时监控', 3, 1, 'realtime', 'monitor/realtime/index', '', '', 1, 0, 'C', '0', 0, 'monitor:realtime:view', 'online', 'admin', NOW(), '实时监控菜单'),
(301, '告警管理', 3, 2, 'alert', 'monitor/alert/index', '', '', 1, 0, 'C', '0', 0, 'monitor:alert:list', 'message', 'admin', NOW(), '告警管理菜单');
-- ==========================================
-- 用户数据
-- ==========================================
-- 插入管理员用户密码admin123已加密
INSERT INTO sys_user (user_id, dept_id, user_name, user_type, email, phonenumber, sex, avatar, password, status, del_flag, create_by, create_time, remark) VALUES
(1, 103, 'admin', '00', 'admin@qaup.com', '15888888888', '1', '', '$2a$10$7JB720yubVSOfvVMe6/YqOsrtwt07CFgLjxkKyQbCpTHWpK7S/pSe', '0', '0', 'admin', NOW(), '管理员');
-- 用户角色关联
INSERT INTO sys_user_role (user_id, role_id) VALUES (1, 1);
-- 用户岗位关联
INSERT INTO sys_user_post (user_id, post_id) VALUES (1, 1);
-- 角色菜单关联(超级管理员拥有所有菜单权限)
INSERT INTO sys_role_menu (role_id, menu_id) VALUES
(1, 1), (1, 100), (1, 101), (1, 102), (1, 103), (1, 104), (1, 105), (1, 106), (1, 107), (1, 108), (1, 500), (1, 501),
(1, 2), (1, 200), (1, 201),
(1, 3), (1, 300), (1, 301);
-- ==========================================
-- 车辆类型数据
-- ==========================================
-- 插入车辆类型数据(基于路径编码模式)
INSERT INTO sys_vehicle_type (id, type_code, type_name, display_name_cn, display_name_en, path_level, parent_code, full_path, is_leaf, sort_order, enabled, description, create_by, create_time) VALUES
-- 一级分类
(1, 'UV', 'UNMANNED_VEHICLE', '无人车', 'Unmanned Vehicle', 1, NULL, '无人车', false, 1, true, '机场无人驾驶车辆', 'admin', NOW()),
(2, 'SP', 'SPECIAL_VEHICLE', '特种车辆', 'Special Vehicle', 1, NULL, '特种车辆', false, 2, true, '机场特种作业车辆', 'admin', NOW()),
(3, 'NV', 'NORMAL_VEHICLE', '普通车辆', 'Normal Vehicle', 1, NULL, '普通车辆', false, 3, true, '机场普通车辆', 'admin', NOW()),
-- 无人车二级分类
(4, 'UV.PT', 'PATROL', '巡逻车', 'Patrol Vehicle', 2, 'UV', '无人车 > 巡逻车', true, 1, true, '无人巡逻车', 'admin', NOW()),
(5, 'UV.CL', 'CLEANING', '清洁车', 'Cleaning Vehicle', 2, 'UV', '无人车 > 清洁车', true, 2, true, '无人清洁车', 'admin', NOW()),
(6, 'UV.TR', 'TRANSPORT', '运输车', 'Transport Vehicle', 2, 'UV', '无人车 > 运输车', true, 3, true, '无人运输车', 'admin', NOW()),
-- 特种车辆二级分类
(7, 'SP.FF', 'FIRE_FIGHTING', '消防车', 'Fire Fighting Vehicle', 2, 'SP', '特种车辆 > 消防车', true, 1, true, '消防救援车辆', 'admin', NOW()),
(8, 'SP.AM', 'AMBULANCE', '救护车', 'Ambulance', 2, 'SP', '特种车辆 > 救护车', true, 2, true, '医疗救护车辆', 'admin', NOW()),
(9, 'SP.MT', 'MAINTENANCE', '维修车', 'Maintenance Vehicle', 2, 'SP', '特种车辆 > 维修车', true, 3, true, '设备维修车辆', 'admin', NOW()),
-- 普通车辆二级分类
(10, 'NV.BU', 'BUS', '班车', 'Bus', 2, 'NV', '普通车辆 > 班车', true, 1, true, '员工班车', 'admin', NOW()),
(11, 'NV.CA', 'CAR', '轿车', 'Car', 2, 'NV', '普通车辆 > 轿车', true, 2, true, '普通轿车', 'admin', NOW()),
(12, 'NV.VN', 'VAN', '面包车', 'Van', 2, 'NV', '普通车辆 > 面包车', true, 3, true, '面包车', 'admin', NOW());
-- ==========================================
-- 机场区域数据(示例)
-- ==========================================
-- 插入示例机场区域
INSERT INTO airport_areas (id, area_id, name, type, boundary, description, enabled, priority, area_sqm, functional_category, created_at, updated_at) VALUES
(1, 'RUNWAY_01', '01号跑道', 'RUNWAY',
ST_GeomFromText('POLYGON((116.3 39.9, 116.4 39.9, 116.4 39.95, 116.3 39.95, 116.3 39.9))', 4326),
'主跑道区域', true, 10, 50000, 'FLIGHT_OPERATIONS', NOW(), NOW()),
(2, 'TAXIWAY_A', 'A滑行道', 'TAXIWAY',
ST_GeomFromText('POLYGON((116.35 39.92, 116.38 39.92, 116.38 39.93, 116.35 39.93, 116.35 39.92))', 4326),
'A滑行道区域', true, 8, 15000, 'FLIGHT_OPERATIONS', NOW(), NOW()),
(3, 'APRON_01', '01号停机坪', 'APRON',
ST_GeomFromText('POLYGON((116.32 39.88, 116.36 39.88, 116.36 39.91, 116.32 39.91, 116.32 39.88))', 4326),
'01号停机坪区域', true, 6, 30000, 'AIRCRAFT_PARKING', NOW(), NOW());
-- ==========================================
-- 空间规则数据(示例)
-- ==========================================
-- 插入示例空间规则
INSERT INTO spatial_rules (rule_id, rule_name, description, rule_category, status, priority, spatial_object_type, spatial_object_id, rule_parameters, alert_level, alert_message, created_at, updated_at, created_by) VALUES
('SPEED_LIMIT_RUNWAY', '跑道限速规则', '跑道区域车辆限速5km/h', 'SPEED_LIMIT', 'ACTIVE', 10, 'AREA', 'RUNWAY_01',
'{"maxSpeed": 5.0, "warningThreshold": 4.0}', 'CRITICAL', '车辆在跑道区域超速', NOW(), NOW(), 'admin'),
('SPEED_LIMIT_TAXIWAY', '滑行道限速规则', '滑行道区域车辆限速10km/h', 'SPEED_LIMIT', 'ACTIVE', 8, 'AREA', 'TAXIWAY_A',
'{"maxSpeed": 10.0, "warningThreshold": 8.0}', 'WARNING', '车辆在滑行道区域超速', NOW(), NOW(), 'admin'),
('ACCESS_CONTROL_RUNWAY', '跑道准入控制', '只允许特种车辆进入跑道', 'ACCESS_CONTROL', 'ACTIVE', 10, 'AREA', 'RUNWAY_01',
'{"allowedVehicleTypes": ["SP"]}', 'CRITICAL', '未授权车辆进入跑道区域', NOW(), NOW(), 'admin');
-- 规则适用车辆类型关联
INSERT INTO spatial_rule_vehicle_types (rule_id, vehicle_type) VALUES
('SPEED_LIMIT_RUNWAY', 'SP.FF'),
('SPEED_LIMIT_RUNWAY', 'SP.AM'),
('SPEED_LIMIT_RUNWAY', 'SP.MT'),
('SPEED_LIMIT_TAXIWAY', 'UV.PT'),
('SPEED_LIMIT_TAXIWAY', 'UV.CL'),
('SPEED_LIMIT_TAXIWAY', 'SP.FF'),
('ACCESS_CONTROL_RUNWAY', 'SP.FF'),
('ACCESS_CONTROL_RUNWAY', 'SP.AM');
-- ==========================================
-- 示例车辆数据
-- ==========================================
-- 插入示例车辆信息
INSERT INTO sys_vehicle_info (vehicle_id, license_plate, vin_number, brand, owning_unit, contact_person, phone_number, type_code, create_by, create_time, remark) VALUES
(1, '京A12345', 'WVWZZZ1JZ3W386752', '大众', '机场运营部', '张三', '13800138001', 'UV.PT', 'admin', NOW(), '无人巡逻车001'),
(2, '京A12346', 'WVWZZZ1JZ3W386753', '比亚迪', '机场运营部', '李四', '13800138002', 'UV.CL', 'admin', NOW(), '无人清洁车001'),
(3, '京A12347', 'WVWZZZ1JZ3W386754', '奔驰', '机场消防队', '王五', '13800138003', 'SP.FF', 'admin', NOW(), '消防车001'),
(4, '京A12348', 'WVWZZZ1JZ3W386755', '福特', '机场医疗中心', '赵六', '13800138004', 'SP.AM', 'admin', NOW(), '救护车001');
-- ==========================================
-- 系统通知数据
-- ==========================================
-- 插入系统通知
INSERT INTO sys_notice (notice_id, notice_title, notice_type, notice_content, status, create_by, create_time, remark) VALUES
(1, '温馨提醒2024-01-01 QAUP系统上线', '2', '各位用户QAUP机场无人车管理系统已正式上线请及时登录系统进行相关操作。', '0', 'admin', NOW(), '管理员'),
(2, '维护通知:系统将于本周日凌晨进行维护', '1', '为了更好地为您提供服务QAUP系统将于本周日凌晨2:00-4:00进行系统维护届时系统将暂停服务请您合理安排时间。给您带来的不便敬请谅解', '0', 'admin', NOW(), '管理员');
-- ==========================================
-- 更新序列值
-- ==========================================
-- 更新所有序列的当前值,确保后续插入不会冲突
SELECT setval('sys_config_config_id_seq', (SELECT MAX(config_id) FROM sys_config));
SELECT setval('sys_dict_type_dict_id_seq', (SELECT MAX(dict_id) FROM sys_dict_type));
SELECT setval('sys_dict_data_dict_code_seq', (SELECT MAX(dict_code) FROM sys_dict_data));
SELECT setval('sys_dept_dept_id_seq', (SELECT MAX(dept_id) FROM sys_dept));
SELECT setval('sys_post_post_id_seq', (SELECT MAX(post_id) FROM sys_post));
SELECT setval('sys_role_role_id_seq', (SELECT MAX(role_id) FROM sys_role));
SELECT setval('sys_menu_menu_id_seq', (SELECT MAX(menu_id) FROM sys_menu));
SELECT setval('sys_user_user_id_seq', (SELECT MAX(user_id) FROM sys_user));
SELECT setval('sys_vehicle_type_new_id_seq', (SELECT MAX(id) FROM sys_vehicle_type));
SELECT setval('sys_vehicle_info_vehicle_id_seq', (SELECT MAX(vehicle_id) FROM sys_vehicle_info));
SELECT setval('airport_areas_id_seq', (SELECT MAX(id) FROM airport_areas));
SELECT setval('sys_notice_notice_id_seq', (SELECT MAX(notice_id) FROM sys_notice));
-- ==========================================
-- 完成提示
-- ==========================================
-- 显示初始化完成信息
DO $$
BEGIN
RAISE NOTICE '========================================';
RAISE NOTICE 'QAUP 系统初始数据导入完成!';
RAISE NOTICE '========================================';
RAISE NOTICE '默认管理员账号admin';
RAISE NOTICE '默认管理员密码admin123';
RAISE NOTICE '========================================';
END $$;

View File

@ -1,72 +0,0 @@
#!/bin/bash
# QAUP 数据库恢复脚本
set -e
# 检查参数
if [ $# -eq 0 ]; then
echo "用法: $0 <备份文件路径>"
echo "示例: $0 /backup/qaup_backup_20241231_120000.sql.gz"
exit 1
fi
BACKUP_FILE="$1"
DB_NAME="${POSTGRES_DB:-qaup}"
DB_USER="${POSTGRES_USER:-postgres}"
echo "========================================="
echo "QAUP 数据库恢复开始"
echo "========================================="
# 检查备份文件是否存在
if [ ! -f "$BACKUP_FILE" ]; then
echo "错误: 备份文件不存在: $BACKUP_FILE"
exit 1
fi
echo "恢复文件: $BACKUP_FILE"
echo "目标数据库: $DB_NAME"
# 确认操作
read -p "警告: 此操作将覆盖现有数据库。是否继续? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "操作已取消"
exit 1
fi
# 停止应用连接(可选)
echo "建议在恢复前停止应用服务以避免数据冲突"
# 解压备份文件(如果是压缩的)
TEMP_FILE=""
if [[ "$BACKUP_FILE" == *.gz ]]; then
echo "解压备份文件..."
TEMP_FILE="/tmp/restore_$(basename "$BACKUP_FILE" .gz)"
gunzip -c "$BACKUP_FILE" > "$TEMP_FILE"
RESTORE_FILE="$TEMP_FILE"
else
RESTORE_FILE="$BACKUP_FILE"
fi
# 执行恢复
echo "开始恢复数据库..."
psql -h localhost -U "$DB_USER" -d postgres -f "$RESTORE_FILE"
# 清理临时文件
if [ -n "$TEMP_FILE" ] && [ -f "$TEMP_FILE" ]; then
rm -f "$TEMP_FILE"
fi
# 验证恢复结果
echo ""
echo "验证恢复结果..."
TABLE_COUNT=$(psql -h localhost -U "$DB_USER" -d "$DB_NAME" -t -c "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = 'public';")
echo "恢复后表数量: $TABLE_COUNT"
echo ""
echo "========================================="
echo "数据库恢复完成!"
echo "========================================="
echo "请重启应用服务以确保正常连接"

View File

@ -1,10 +1,72 @@
#!/bin/bash
# QAUP 离线部署镜像准备脚本
# 此脚本需要在有网络连接的环境中运行
# 此脚本需要在有网络连接的环境中运行,用于准备离线部署所需的所有镜像
set -e
# 显示帮助信息
show_help() {
echo "QAUP 离线部署镜像准备脚本"
echo ""
echo "用法: $0 [选项]"
echo ""
echo "选项:"
echo " -h, --help 显示帮助信息"
echo " --no-build 跳过自定义镜像构建(仅拉取基础镜像)"
echo " --clean 清理现有的离线部署目录"
echo ""
echo "功能:"
echo " - 自动检测 docker-compose.yml 中的镜像版本"
echo " - 拉取所有必需的基础镜像"
echo " - 构建 QAUP 自定义镜像"
echo " - 导出所有镜像为 tar.gz 文件"
echo " - 生成校验和文件"
echo " - 创建导入脚本和部署包"
echo ""
echo "系统要求:"
echo " - Docker 已安装并运行"
echo " - 网络连接正常"
echo " - 足够的磁盘空间(建议 10GB+"
}
# 检查参数
NO_BUILD=false
CLEAN=false
while [[ $# -gt 0 ]]; do
case $1 in
-h|--help)
show_help
exit 0
;;
--no-build)
NO_BUILD=true
shift
;;
--clean)
CLEAN=true
shift
;;
*)
echo "未知选项: $1"
show_help
exit 1
;;
esac
done
# 检查 Docker 是否可用
if ! command -v docker &> /dev/null; then
echo "错误: Docker 未安装或不在 PATH 中"
exit 1
fi
if ! docker info &> /dev/null; then
echo "错误: Docker 服务未运行"
exit 1
fi
# 配置变量
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
@ -12,13 +74,49 @@ IMAGES_DIR="$PROJECT_ROOT/offline-deploy/images"
CONFIG_DIR="$PROJECT_ROOT/offline-deploy/config"
SCRIPTS_DIR="$PROJECT_ROOT/offline-deploy/scripts"
# 镜像版本配置
OPENJDK_IMAGE="openjdk:17-jre-slim"
NGINX_IMAGE="nginx:alpine"
POSTGRES_IMAGE="postgis/postgis:15-3.3"
REDIS_IMAGE="redis:7-alpine"
NODE_IMAGE="node:18-alpine"
MAVEN_IMAGE="maven:3.9.6-openjdk-17-slim"
# 加载镜像版本配置
IMAGE_VERSIONS_FILE="$SCRIPT_DIR/image-versions.env"
if [ -f "$IMAGE_VERSIONS_FILE" ]; then
echo "从配置文件加载镜像版本: $IMAGE_VERSIONS_FILE"
source "$IMAGE_VERSIONS_FILE"
else
echo "警告: 镜像版本配置文件不存在,使用默认版本"
# 默认版本(如果配置文件不存在)
POSTGRES_IMAGE="postgis/postgis:16-3.4"
REDIS_IMAGE="redis:7.2-alpine"
OPENJDK_IMAGE="openjdk:21-jre-slim"
MAVEN_IMAGE="maven:3.9-openjdk-21-slim"
NGINX_IMAGE="nginx:1.25-alpine"
NODE_IMAGE="node:20-alpine"
QAUP_APP_IMAGE="qaup-app:latest"
QAUP_NGINX_IMAGE="qaup-nginx:latest"
fi
echo "使用的镜像版本:"
echo " PostgreSQL/PostGIS: $POSTGRES_IMAGE"
echo " Redis: $REDIS_IMAGE"
echo " Maven: $MAVEN_IMAGE"
echo " OpenJDK: $OPENJDK_IMAGE"
echo " Nginx: $NGINX_IMAGE"
echo " Node.js: $NODE_IMAGE"
echo " QAUP App: $QAUP_APP_IMAGE"
echo " QAUP Nginx: $QAUP_NGINX_IMAGE"
echo ""
# 检查是否需要更新 docker-compose.yml 和 Dockerfile
echo "检查配置文件同步状态..."
COMPOSE_POSTGRES=$(grep -A 1 "qaup-postgres:" "$PROJECT_ROOT/docker-compose.yml" | grep "image:" | awk '{print $2}' | head -1)
COMPOSE_REDIS=$(grep -A 1 "qaup-redis:" "$PROJECT_ROOT/docker-compose.yml" | grep "image:" | awk '{print $2}' | head -1)
if [ "$COMPOSE_POSTGRES" != "$POSTGRES_IMAGE" ]; then
echo "警告: docker-compose.yml 中的 PostgreSQL 版本 ($COMPOSE_POSTGRES) 与配置文件不一致 ($POSTGRES_IMAGE)"
fi
if [ "$COMPOSE_REDIS" != "$REDIS_IMAGE" ]; then
echo "警告: docker-compose.yml 中的 Redis 版本 ($COMPOSE_REDIS) 与配置文件不一致 ($REDIS_IMAGE)"
fi
echo ""
# 自定义镜像名称
QAUP_APP_IMAGE="qaup-app:latest"
@ -28,53 +126,165 @@ echo "========================================="
echo "QAUP 离线部署镜像准备开始"
echo "========================================="
# 清理现有目录(如果需要)
if [ "$CLEAN" = true ] && [ -d "$PROJECT_ROOT/offline-deploy" ]; then
echo "清理现有离线部署目录..."
rm -rf "$PROJECT_ROOT/offline-deploy"
fi
# 创建目录结构
echo "创建离线部署目录结构..."
mkdir -p "$IMAGES_DIR" "$CONFIG_DIR" "$SCRIPTS_DIR"
# 拉取基础镜像函数
pull_image() {
local image=$1
echo "拉取镜像: $image"
if docker pull "$image"; then
echo "$image 拉取成功"
else
echo "$image 拉取失败"
exit 1
fi
}
# 拉取基础镜像
echo "拉取基础镜像..."
docker pull $OPENJDK_IMAGE
docker pull $NGINX_IMAGE
docker pull $POSTGRES_IMAGE
docker pull $REDIS_IMAGE
docker pull $NODE_IMAGE
docker pull $MAVEN_IMAGE
pull_image "$OPENJDK_IMAGE"
pull_image "$NGINX_IMAGE"
pull_image "$POSTGRES_IMAGE"
pull_image "$REDIS_IMAGE"
pull_image "$NODE_IMAGE"
pull_image "$MAVEN_IMAGE"
# 构建自定义镜像
echo "构建 QAUP 应用镜像..."
cd "$PROJECT_ROOT"
docker build -t $QAUP_APP_IMAGE .
if docker build -t $QAUP_APP_IMAGE .; then
echo "✓ QAUP 应用镜像构建成功"
else
echo "✗ QAUP 应用镜像构建失败"
exit 1
fi
echo "构建 QAUP Nginx 镜像..."
docker build -f docker/nginx/Dockerfile -t $QAUP_NGINX_IMAGE .
if docker build -f deploy/docker/nginx/Dockerfile -t $QAUP_NGINX_IMAGE .; then
echo "✓ QAUP Nginx 镜像构建成功"
else
echo "✗ QAUP Nginx 镜像构建失败"
exit 1
fi
# 导出镜像
# 导出镜像函数
export_image() {
local image=$1
local filename=$2
echo "导出镜像: $image -> $filename"
if docker save "$image" | gzip > "$IMAGES_DIR/$filename"; then
echo "$filename 导出成功"
else
echo "$filename 导出失败"
exit 1
fi
}
# 导出镜像文件
echo "导出镜像文件..."
docker save $OPENJDK_IMAGE | gzip > "$IMAGES_DIR/openjdk-17-jre-slim.tar.gz"
docker save $NGINX_IMAGE | gzip > "$IMAGES_DIR/nginx-alpine.tar.gz"
docker save $POSTGRES_IMAGE | gzip > "$IMAGES_DIR/postgis-15-3.3.tar.gz"
docker save $REDIS_IMAGE | gzip > "$IMAGES_DIR/redis-7-alpine.tar.gz"
docker save $QAUP_APP_IMAGE | gzip > "$IMAGES_DIR/qaup-app.tar.gz"
docker save $QAUP_NGINX_IMAGE | gzip > "$IMAGES_DIR/qaup-nginx.tar.gz"
export_image "$OPENJDK_IMAGE" "openjdk-17-jre-slim.tar.gz"
export_image "$NGINX_IMAGE" "nginx-alpine.tar.gz"
export_image "$POSTGRES_IMAGE" "postgis.tar.gz"
export_image "$REDIS_IMAGE" "redis-alpine.tar.gz"
export_image "$NODE_IMAGE" "node-alpine.tar.gz"
export_image "$MAVEN_IMAGE" "maven-openjdk.tar.gz"
export_image "$QAUP_APP_IMAGE" "qaup-app.tar.gz"
export_image "$QAUP_NGINX_IMAGE" "qaup-nginx.tar.gz"
# 创建镜像清单文件
echo "创建镜像清单..."
cat > "$IMAGES_DIR/images-list.txt" << EOF
# QAUP 离线部署镜像清单
# 生成时间: $(date)
# 生成主机: $(hostname)
# 基础镜像
openjdk-17-jre-slim.tar.gz -> $OPENJDK_IMAGE
nginx-alpine.tar.gz -> $NGINX_IMAGE
postgis-15-3.3.tar.gz -> $POSTGRES_IMAGE
redis-7-alpine.tar.gz -> $REDIS_IMAGE
postgis.tar.gz -> $POSTGRES_IMAGE
redis-alpine.tar.gz -> $REDIS_IMAGE
node-alpine.tar.gz -> $NODE_IMAGE
maven-openjdk.tar.gz -> $MAVEN_IMAGE
# 自定义镜像
qaup-app.tar.gz -> $QAUP_APP_IMAGE
qaup-nginx.tar.gz -> $QAUP_NGINX_IMAGE
# 使用说明
# 1. 将所有 .tar.gz 文件复制到目标服务器
# 2. 运行 load-images.sh 脚本导入镜像
# 3. 验证校验和: sha256sum -c checksums.sha256
EOF
# 创建镜像导入脚本
echo "创建镜像导入脚本..."
cat > "$SCRIPTS_DIR/load-images.sh" << 'EOF'
#!/bin/bash
# QAUP 离线镜像导入脚本
# 在目标服务器上运行此脚本导入镜像
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
IMAGES_DIR="$SCRIPT_DIR/../images"
echo "========================================="
echo "QAUP 离线镜像导入开始"
echo "========================================="
# 检查镜像文件
if [ ! -d "$IMAGES_DIR" ]; then
echo "错误: 镜像目录不存在: $IMAGES_DIR"
exit 1
fi
# 验证校验和
if [ -f "$IMAGES_DIR/checksums.sha256" ]; then
echo "验证文件校验和..."
cd "$IMAGES_DIR"
if sha256sum -c checksums.sha256; then
echo "✓ 文件校验和验证通过"
else
echo "✗ 文件校验和验证失败"
exit 1
fi
cd - > /dev/null
fi
# 导入镜像
echo "导入镜像文件..."
for image_file in "$IMAGES_DIR"/*.tar.gz; do
if [ -f "$image_file" ]; then
echo "导入: $(basename "$image_file")"
if gunzip -c "$image_file" | docker load; then
echo "$(basename "$image_file") 导入成功"
else
echo "$(basename "$image_file") 导入失败"
exit 1
fi
fi
done
echo ""
echo "========================================="
echo "镜像导入完成!"
echo "========================================="
echo "已导入的镜像:"
docker images | grep -E "(qaup|postgres|redis|nginx|openjdk|node|maven)"
EOF
# 设置执行权限
chmod +x "$SCRIPTS_DIR/load-images.sh"
# 计算文件大小和校验和
echo "计算文件校验和..."
cd "$IMAGES_DIR"
@ -92,6 +302,58 @@ echo "镜像文件列表:"
ls -lh *.tar.gz
echo ""
echo "校验和文件已生成: checksums.sha256"
# 复制必要的配置文件
echo "复制配置文件..."
cp "$PROJECT_ROOT/docker-compose.yml" "$CONFIG_DIR/"
cp "$PROJECT_ROOT/docker-compose.prod.yml" "$CONFIG_DIR/"
cp "$PROJECT_ROOT/.env.template" "$CONFIG_DIR/"
# 复制部署脚本
cp "$PROJECT_ROOT/deploy.sh" "$SCRIPTS_DIR/"
# 创建离线部署说明
cat > "$PROJECT_ROOT/offline-deploy/README-离线部署.md" << 'EOF'
# QAUP 离线部署包
## 包含内容
- `images/` - Docker 镜像文件
- `config/` - 配置文件
- `scripts/` - 部署脚本
## 部署步骤
1. 将整个 `offline-deploy` 目录复制到目标服务器
2. 导入镜像:`./scripts/load-images.sh`
3. 配置环境:`cp config/.env.template .env` 并编辑
4. 启动服务:`./scripts/deploy.sh install`
## 系统要求
- Docker 20.10+
- Docker Compose 1.29+
- 至少 4GB 内存
- 至少 20GB 磁盘空间
EOF
# 创建离线部署包
echo "创建离线部署包..."
cd "$PROJECT_ROOT"
PACKAGE_NAME="qaup-offline-deploy-$(date +%Y%m%d_%H%M%S).tar.gz"
tar -czf "$PACKAGE_NAME" offline-deploy/
echo ""
echo "离线部署镜像准备完成!"
echo "镜像文件位置: $IMAGES_DIR"
echo "========================================="
echo "离线部署准备完成!"
echo "========================================="
echo "镜像文件位置: $IMAGES_DIR"
echo "配置文件位置: $CONFIG_DIR"
echo "脚本文件位置: $SCRIPTS_DIR"
echo "离线部署包: $PROJECT_ROOT/$PACKAGE_NAME"
echo ""
echo "部署包大小: $(du -sh "$PROJECT_ROOT/$PACKAGE_NAME" | cut -f1)"
echo ""
echo "使用方法:"
echo "1. 将 $PACKAGE_NAME 传输到目标服务器"
echo "2. 解压: tar -xzf $PACKAGE_NAME"
echo "3. 按照 offline-deploy/README-离线部署.md 中的说明进行部署"

View File

@ -0,0 +1,262 @@
#!/bin/bash
# QAUP Docker 镜像版本同步更新脚本
# 根据 image-versions.env 配置文件更新所有相关文件中的镜像版本
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
IMAGE_VERSIONS_FILE="$SCRIPT_DIR/image-versions.env"
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
print_message() {
local color=$1
local message=$2
echo -e "${color}${message}${NC}"
}
# 显示帮助信息
show_help() {
echo "QAUP Docker 镜像版本同步更新脚本"
echo ""
echo "用法: $0 [选项]"
echo ""
echo "选项:"
echo " -h, --help 显示帮助信息"
echo " --dry-run 仅显示将要进行的更改,不实际修改文件"
echo " --backup 更新前备份原文件"
echo ""
echo "功能:"
echo " - 从 image-versions.env 读取最新版本配置"
echo " - 更新 docker-compose.yml 中的镜像版本"
echo " - 更新 Dockerfile 中的基础镜像版本"
echo " - 生成版本更新报告"
}
# 检查参数
DRY_RUN=false
BACKUP=false
while [[ $# -gt 0 ]]; do
case $1 in
-h|--help)
show_help
exit 0
;;
--dry-run)
DRY_RUN=true
shift
;;
--backup)
BACKUP=true
shift
;;
*)
echo "未知选项: $1"
show_help
exit 1
;;
esac
done
# 检查配置文件
if [ ! -f "$IMAGE_VERSIONS_FILE" ]; then
print_message $RED "错误: 镜像版本配置文件不存在: $IMAGE_VERSIONS_FILE"
exit 1
fi
# 加载配置
source "$IMAGE_VERSIONS_FILE"
print_message $BLUE "========================================="
print_message $BLUE "QAUP Docker 镜像版本同步更新"
print_message $BLUE "========================================="
echo ""
if [ "$DRY_RUN" = true ]; then
print_message $YELLOW "运行模式: 预览模式(不会实际修改文件)"
else
print_message $GREEN "运行模式: 更新模式"
fi
echo ""
# 备份函数
backup_file() {
local file=$1
if [ "$BACKUP" = true ] && [ -f "$file" ]; then
local backup_file="${file}.backup.$(date +%Y%m%d_%H%M%S)"
cp "$file" "$backup_file"
print_message $GREEN "已备份: $file -> $backup_file"
fi
}
# 更新 docker-compose.yml
update_docker_compose() {
local compose_file="$PROJECT_ROOT/docker-compose.yml"
if [ ! -f "$compose_file" ]; then
print_message $YELLOW "警告: docker-compose.yml 不存在,跳过更新"
return
fi
print_message $BLUE "更新 docker-compose.yml..."
# 检查当前版本
local current_postgres=$(grep -A 1 "qaup-postgres:" "$compose_file" | grep "image:" | awk '{print $2}' | head -1)
local current_redis=$(grep -A 1 "qaup-redis:" "$compose_file" | grep "image:" | awk '{print $2}' | head -1)
echo "PostgreSQL: $current_postgres -> $POSTGRES_IMAGE"
echo "Redis: $current_redis -> $REDIS_IMAGE"
if [ "$DRY_RUN" = false ]; then
backup_file "$compose_file"
# 更新 PostgreSQL 镜像
sed -i.tmp "s|image: postgis/postgis:.*|image: $POSTGRES_IMAGE|g" "$compose_file"
# 更新 Redis 镜像
sed -i.tmp "s|image: redis:.*|image: $REDIS_IMAGE|g" "$compose_file"
# 清理临时文件
rm -f "${compose_file}.tmp"
print_message $GREEN "✓ docker-compose.yml 更新完成"
fi
echo ""
}
# 更新 Dockerfile
update_dockerfile() {
local dockerfile="$PROJECT_ROOT/Dockerfile"
if [ ! -f "$dockerfile" ]; then
print_message $YELLOW "警告: Dockerfile 不存在,跳过更新"
return
fi
print_message $BLUE "更新 Dockerfile..."
# 检查当前版本
local current_maven=$(grep "^FROM maven:" "$dockerfile" | awk '{print $2}' | head -1)
local current_openjdk=$(grep "^FROM openjdk:" "$dockerfile" | awk '{print $2}' | head -1)
echo "Maven: $current_maven -> $MAVEN_IMAGE"
echo "OpenJDK: $current_openjdk -> $OPENJDK_IMAGE"
if [ "$DRY_RUN" = false ]; then
backup_file "$dockerfile"
# 更新 Maven 镜像
sed -i.tmp "s|FROM maven:.*AS builder|FROM $MAVEN_IMAGE AS builder|g" "$dockerfile"
# 更新 OpenJDK 镜像
sed -i.tmp "s|FROM openjdk:.*|FROM $OPENJDK_IMAGE|g" "$dockerfile"
# 清理临时文件
rm -f "${dockerfile}.tmp"
print_message $GREEN "✓ Dockerfile 更新完成"
fi
echo ""
}
# 更新 Nginx Dockerfile
update_nginx_dockerfile() {
local nginx_dockerfile="$PROJECT_ROOT/docker/nginx/Dockerfile"
if [ ! -f "$nginx_dockerfile" ]; then
print_message $YELLOW "警告: Nginx Dockerfile 不存在,跳过更新"
return
fi
print_message $BLUE "更新 Nginx Dockerfile..."
# 检查当前版本
local current_node=$(grep "^FROM node:" "$nginx_dockerfile" | awk '{print $2}' | head -1)
local current_nginx=$(grep "^FROM nginx:" "$nginx_dockerfile" | awk '{print $2}' | head -1)
echo "Node.js: $current_node -> $NODE_IMAGE"
echo "Nginx: $current_nginx -> $NGINX_IMAGE"
if [ "$DRY_RUN" = false ]; then
backup_file "$nginx_dockerfile"
# 更新 Node.js 镜像
sed -i.tmp "s|FROM node:.*AS frontend-builder|FROM $NODE_IMAGE AS frontend-builder|g" "$nginx_dockerfile"
# 更新 Nginx 镜像
sed -i.tmp "s|FROM nginx:.*|FROM $NGINX_IMAGE|g" "$nginx_dockerfile"
# 清理临时文件
rm -f "${nginx_dockerfile}.tmp"
print_message $GREEN "✓ Nginx Dockerfile 更新完成"
fi
echo ""
}
# 生成更新报告
generate_report() {
local report_file="$PROJECT_ROOT/image-version-update-report.txt"
cat > "$report_file" << EOF
QAUP Docker 镜像版本更新报告
生成时间: $(date)
更新模式: $([ "$DRY_RUN" = true ] && echo "预览模式" || echo "实际更新")
更新的镜像版本:
- PostgreSQL/PostGIS: $POSTGRES_IMAGE
- Redis: $REDIS_IMAGE
- Maven: $MAVEN_IMAGE
- OpenJDK: $OPENJDK_IMAGE
- Nginx: $NGINX_IMAGE
- Node.js: $NODE_IMAGE
更新的文件:
- docker-compose.yml
- Dockerfile
- docker/nginx/Dockerfile
后续操作建议:
1. 测试新版本的兼容性
2. 更新离线部署镜像包
3. 更新部署文档中的版本信息
4. 在测试环境验证后再部署到生产环境
EOF
print_message $GREEN "更新报告已生成: $report_file"
}
# 执行更新
print_message $BLUE "开始更新镜像版本..."
echo ""
update_docker_compose
update_dockerfile
update_nginx_dockerfile
if [ "$DRY_RUN" = false ]; then
print_message $GREEN "========================================="
print_message $GREEN "镜像版本更新完成!"
print_message $GREEN "========================================="
echo ""
print_message $YELLOW "重要提醒:"
echo "1. 请在测试环境验证新版本的兼容性"
echo "2. 运行 ./prepare-offline-images.sh 更新离线部署包"
echo "3. 考虑更新相关文档中的版本信息"
else
print_message $BLUE "========================================="
print_message $BLUE "预览完成(未实际修改文件)"
print_message $BLUE "========================================="
echo ""
print_message $YELLOW "如需实际更新,请运行: $0"
fi
generate_report

View File

@ -0,0 +1,120 @@
#!/bin/bash
# QAUP Docker 镜像版本验证脚本
# 验证配置文件中的版本与实际使用的版本是否一致
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
print_message() {
local color=$1
local message=$2
echo -e "${color}${message}${NC}"
}
print_message $BLUE "========================================="
print_message $BLUE "QAUP Docker 镜像版本验证"
print_message $BLUE "========================================="
echo ""
# 加载配置文件
if [ -f "$SCRIPT_DIR/image-versions.env" ]; then
source "$SCRIPT_DIR/image-versions.env"
print_message $GREEN "✓ 已加载镜像版本配置文件"
else
print_message $RED "✗ 镜像版本配置文件不存在"
exit 1
fi
echo ""
print_message $BLUE "配置文件中的版本:"
echo "PostgreSQL/PostGIS: $POSTGRES_IMAGE"
echo "Redis: $REDIS_IMAGE"
echo "OpenJDK: $OPENJDK_IMAGE"
echo "Maven: $MAVEN_IMAGE"
echo "Nginx: $NGINX_IMAGE"
echo "Node.js: $NODE_IMAGE"
echo ""
# 检查 docker-compose.yml 中的版本
print_message $BLUE "docker-compose.yml 中的版本:"
if [ -f "$PROJECT_ROOT/docker-compose.yml" ]; then
compose_postgres=$(grep -A 1 "qaup-postgres:" "$PROJECT_ROOT/docker-compose.yml" | grep "image:" | awk '{print $2}')
compose_redis=$(grep -A 1 "qaup-redis:" "$PROJECT_ROOT/docker-compose.yml" | grep "image:" | awk '{print $2}')
echo "PostgreSQL/PostGIS: $compose_postgres"
echo "Redis: $compose_redis"
# 验证一致性
if [ "$compose_postgres" = "$POSTGRES_IMAGE" ]; then
print_message $GREEN "✓ PostgreSQL 版本一致"
else
print_message $RED "✗ PostgreSQL 版本不一致"
echo " 配置文件: $POSTGRES_IMAGE"
echo " docker-compose.yml: $compose_postgres"
fi
if [ "$compose_redis" = "$REDIS_IMAGE" ]; then
print_message $GREEN "✓ Redis 版本一致"
else
print_message $RED "✗ Redis 版本不一致"
echo " 配置文件: $REDIS_IMAGE"
echo " docker-compose.yml: $compose_redis"
fi
else
print_message $YELLOW "警告: docker-compose.yml 文件不存在"
fi
echo ""
# 检查 Dockerfile 中的版本
print_message $BLUE "Dockerfile 中的版本:"
if [ -f "$PROJECT_ROOT/Dockerfile" ]; then
dockerfile_maven=$(grep "^FROM maven:" "$PROJECT_ROOT/Dockerfile" | awk '{print $2}' | head -1)
dockerfile_openjdk=$(grep "^FROM openjdk:" "$PROJECT_ROOT/Dockerfile" | awk '{print $2}' | head -1)
echo "Maven: $dockerfile_maven"
echo "OpenJDK: $dockerfile_openjdk"
# 验证一致性
if [ "$dockerfile_maven" = "$MAVEN_IMAGE" ]; then
print_message $GREEN "✓ Maven 版本一致"
else
print_message $RED "✗ Maven 版本不一致"
echo " 配置文件: $MAVEN_IMAGE"
echo " Dockerfile: $dockerfile_maven"
fi
if [ "$dockerfile_openjdk" = "$OPENJDK_IMAGE" ]; then
print_message $GREEN "✓ OpenJDK 版本一致"
else
print_message $RED "✗ OpenJDK 版本不一致"
echo " 配置文件: $OPENJDK_IMAGE"
echo " Dockerfile: $dockerfile_openjdk"
fi
else
print_message $YELLOW "警告: Dockerfile 文件不存在"
fi
echo ""
print_message $BLUE "当前使用的版本总结:"
echo "✓ PostgreSQL 17 + PostGIS 3.5 (最新稳定版)"
echo "✓ Redis 8.0 (最新版本)"
echo "✓ OpenJDK 17 (LTS 版本)"
echo "✓ Maven 3.9.11 (最新稳定版)"
echo ""
print_message $YELLOW "升级注意事项:"
echo "1. PostgreSQL 17 包含性能改进和新特性"
echo "2. Redis 8.0 引入了新的数据结构和命令"
echo "3. 升级前请备份数据并在测试环境验证"
echo "4. 检查应用程序与新版本的兼容性"

View File

@ -0,0 +1,115 @@
# QAUP Docker 部署检查清单
## 部署前检查
### ✅ 环境准备
- [ ] 确认操作系统版本 (Ubuntu 18.04+ 推荐)
- [ ] 安装 Docker (20.10+)
- [ ] 安装 Docker Compose (1.29+)
- [ ] 确认用户在 docker 组中
- [ ] 确认网络连接正常
### ✅ 文件准备
- [ ] 项目文件完整下载/解压
- [ ] 进入 deploy 目录 (`cd QAUP-Management/deploy`)
- [ ] 运行路径验证 (`./test-paths.sh`)
- [ ] 所有脚本具有执行权限
### ✅ 数据准备
- [ ] 查看数据文件状态 (`./docker/postgres/db-manager.sh prepare-status`)
- [ ] 选择数据准备方式:
- [ ] 全新部署:`./docker/postgres/db-manager.sh prepare-default`
- [ ] 现有系统迁移:`./docker/postgres/db-manager.sh prepare-export`
- [ ] 自定义组合:`./docker/postgres/db-manager.sh prepare-custom`
- [ ] 验证数据文件已准备完成
### ✅ 配置检查
- [ ] 复制 `.env.template``.env`
- [ ] 修改数据库密码 (POSTGRES_PASSWORD, APP_DB_PASSWORD)
- [ ] 设置 Redis 密码 (REDIS_PASSWORD)
- [ ] 配置服务器域名 (SERVER_NAME)
- [ ] 调整 JVM 参数 (根据服务器配置)
## 部署过程检查
### ✅ 系统验证
- [ ] 运行环境验证 (`./docker/validate-environment.sh`)
- [ ] 检查端口占用情况
- [ ] 确认磁盘空间充足 (至少 20GB)
- [ ] 确认内存充足 (至少 4GB)
### ✅ 部署执行
- [ ] 运行完整部署 (`./deploy.sh install`)
- [ ] 等待所有服务启动完成
- [ ] 检查容器状态 (`docker ps`)
- [ ] 验证服务健康检查
### ✅ 功能验证
- [ ] 访问前端页面 (`http://localhost`)
- [ ] 测试 API 接口 (`http://localhost/prod-api`)
- [ ] 检查健康检查端点 (`http://localhost/health`)
- [ ] 验证数据库连接
- [ ] 测试文件上传功能
## 部署后检查
### ✅ 监控配置
- [ ] 查看系统监控 (`./docker/monitor.sh watch`)
- [ ] 检查日志输出 (`./deploy.sh logs`)
- [ ] 验证告警配置
- [ ] 测试备份功能
### ✅ 安全检查
- [ ] 修改默认密码
- [ ] 检查防火墙配置
- [ ] 验证网络隔离
- [ ] 确认敏感信息保护
### ✅ 性能优化
- [ ] 监控资源使用情况
- [ ] 调整 JVM 参数
- [ ] 优化数据库配置
- [ ] 配置日志轮转
## 常用命令参考
```bash
# 系统状态
./docker/ops-manager.sh overview
# 查看日志
./deploy.sh logs [服务名]
# 重启服务
./deploy.sh restart
# 备份数据
./docker/backup-restore.sh backup
# 系统监控
./docker/monitor.sh watch
# 性能分析
./docker/ops-manager.sh performance
```
## 故障排除
如果遇到问题,请按以下顺序检查:
1. **路径配置**: 运行 `./test-paths.sh` 验证
2. **环境验证**: 运行 `./docker/validate-environment.sh`
3. **容器状态**: 运行 `docker ps -a` 查看容器状态
4. **日志分析**: 运行 `./deploy.sh logs` 查看详细日志
5. **资源检查**: 运行 `./docker/monitor.sh health` 检查资源
更多故障排除信息请参考 `docs/故障排除.md`
## 联系支持
如果遇到无法解决的问题,请提供以下信息:
- 操作系统版本
- Docker 版本信息
- 错误日志内容
- 系统资源状态
- 部署步骤记录

View File

@ -48,6 +48,12 @@
- **详细文档**: 部署指南、故障排除和离线部署指南
- **Docker Compose 管理器**: 服务管理和操作脚本
### ✅ 8. 路径配置优化
- **统一部署目录**: 所有部署文件集中在 deploy 目录
- **构建上下文优化**: Docker 构建上下文指向项目根目录
- **路径自动处理**: 脚本自动处理相对路径和绝对路径
- **路径验证工具**: test-paths.sh 脚本验证路径配置正确性
### ✅ 8. 生产环境优化
- **性能调优脚本**: JVM、数据库、Nginx 性能优化
- **零停机更新**: 滚动更新和蓝绿部署
@ -138,6 +144,35 @@ QAUP-Management/
└── README-Docker.md # Docker 部署说明
```
## 路径配置技术说明
### 部署目录结构优化
为了提高部署的便利性和可维护性,我们将所有部署相关文件集中在 `deploy` 目录下:
- **工作目录**: 所有部署操作都在 `deploy` 目录下进行
- **构建上下文**: Docker 构建上下文指向项目根目录 (`context: ..`)
- **路径映射**: 脚本自动处理相对路径和绝对路径的转换
### 关键路径配置
```yaml
# docker-compose.yml 中的构建配置
qaup-app:
build:
context: .. # 指向项目根目录
dockerfile: deploy/Dockerfile # Dockerfile 相对于根目录的路径
qaup-nginx:
build:
context: .. # 指向项目根目录
dockerfile: deploy/docker/nginx/Dockerfile # Nginx Dockerfile 路径
```
### 路径验证工具
提供了 `test-paths.sh` 脚本来验证路径配置的正确性:
- 检查关键文件和目录是否存在
- 验证 Docker Compose 构建上下文配置
- 确认 Dockerfile 中的路径引用正确
## 核心特性
### 🚀 生产就绪

View File

@ -1,7 +1,26 @@
# QAUP 系统 Docker 部署
## 重要说明
**工作目录**: 请确保在 `deploy` 目录下执行所有部署命令。
```bash
cd QAUP-Management/deploy # 进入部署目录
./test-paths.sh # 验证路径配置(推荐)
```
## 快速开始
### 数据准备(首次部署必需)
```bash
# 全新部署(使用默认数据)
./docker/postgres/db-manager.sh prepare-default
# 或从现有系统迁移
./docker/postgres/db-manager.sh prepare-export
```
### 一键部署
```bash

View File

@ -0,0 +1,204 @@
# QAUP 数据导出导入指南
## 概述
本指南介绍如何从现有 QAUP 数据库导出数据,并在新环境中导入这些数据。我们采用分层数据管理策略,将数据分为不同类别,以便灵活管理。
## 数据分类
### 1. 系统基础配置数据(必需)
- **包含表**: `sys_config`, `sys_dict_type`, `sys_dict_data`, `sys_dept`, `sys_post`, `sys_role`, `sys_menu`, `sys_user`, `sys_user_role`, `sys_user_post`, `sys_role_menu`, `sys_role_dept`, `sys_notice`
- **用途**: 系统运行的基础配置,包括菜单、角色、权限等
- **特点**: 必须导入,否则系统无法正常运行
### 2. 业务基础数据(推荐)
- **包含表**: `sys_vehicle_type`, `airport_areas`, `spatial_rules`, `spatial_rule_vehicle_types`, `transport_routes`
- **用途**: 业务配置数据,如车辆类型、机场区域、空间规则等
- **特点**: 建议导入,包含实际业务配置
### 3. 示例数据(可选)
- **包含表**: `sys_vehicle_info`
- **用途**: 示例车辆信息,用于演示和测试
- **特点**: 可选导入,生产环境可能不需要
### 4. 实时数据(不导出)
- **包含表**: `vehicle_locations`, `vehicle_trajectories`, `vehicle_commands`, `geofence_events`, `uv_violation_events`, `sys_logininfor`, `sys_oper_log`, `sys_job_log`
- **用途**: 实时运行数据、日志等
- **特点**: 不导出,新环境启动后自动生成
## 数据导出
### 前提条件
- 安装 PostgreSQL 客户端工具(包含 `pg_dump`
- 能够连接到现有的 QAUP 数据库
- 有足够的磁盘空间存储导出文件
### 导出步骤
#### 1. 设置环境变量
```bash
export DB_HOST=localhost # 数据库主机
export DB_PORT=5432 # 数据库端口
export DB_NAME=qaup # 数据库名称
export DB_USER=postgres # 数据库用户
export EXPORT_DIR=./export # 导出目录
```
#### 2. 执行导出(推荐方式)
```bash
cd deploy/docker/postgres
./db-manager.sh export-initial
```
这将生成以下文件:
- `01_system_data.sql` - 系统基础配置数据
- `02_business_data.sql` - 业务基础数据
- `03_sample_data.sql` - 示例数据
- `initial_data_complete.sql` - 合并的完整初始数据文件
#### 3. 其他导出选项
```bash
# 导出分层初始数据(推荐)
./db-manager.sh export-initial
# 导出完整数据库
./db-manager.sh export-all
# 仅导出表结构
./db-manager.sh export-schema
# 数据库备份
./db-manager.sh backup
```
## 数据导入
### 方法一:使用合并文件(推荐)
1. 将 `initial_data_complete.sql` 复制到 `deploy/docker/postgres/initial_data.sql`
2. 启动 Docker 容器,数据会自动导入
```bash
cp export/initial_data_complete.sql deploy/docker/postgres/initial_data.sql
./deploy.sh install
```
### 方法二:分层导入
如果需要选择性导入,可以分别处理各层数据:
```bash
# 1. 复制系统基础数据(必需)
cp export/01_system_data.sql deploy/docker/postgres/initial_data.sql
# 2. 可选:追加业务数据
cat export/02_business_data.sql >> deploy/docker/postgres/initial_data.sql
# 3. 可选:追加示例数据
cat export/03_sample_data.sql >> deploy/docker/postgres/initial_data.sql
# 4. 启动容器
./deploy.sh install
```
### 方法三:手动导入
如果容器已经运行,可以手动导入数据:
```bash
# 进入数据库容器
docker exec -it qaup-postgres psql -U postgres -d qaup
# 在容器内执行
\i /docker-entrypoint-initdb.d/initial_data.sql
```
## 验证导入
### 1. 检查表数据
```sql
-- 检查用户表
SELECT COUNT(*) FROM sys_user;
-- 检查菜单表
SELECT COUNT(*) FROM sys_menu;
-- 检查车辆类型表
SELECT COUNT(*) FROM sys_vehicle_type;
-- 检查机场区域表
SELECT COUNT(*) FROM airport_areas;
```
### 2. 测试登录
- 使用导出的管理员账号登录系统
- 检查菜单和权限是否正确显示
- 验证业务功能是否正常
## 注意事项
### 1. 密码处理
- 导出的用户密码是加密的,可以直接使用
- 如果需要重置密码,请在系统中操作
### 2. 序列值
- 导出脚本会自动更新序列值
- 确保新插入的数据不会产生主键冲突
### 3. 外键约束
- 导入时会临时禁用触发器
- 导入完成后会重新启用
### 4. 数据一致性
- 建议在业务低峰期进行导出
- 确保导出过程中数据不被修改
## 故障排除
### 1. 连接失败
```bash
# 检查数据库连接
pg_isready -h $DB_HOST -p $DB_PORT -U $DB_USER -d $DB_NAME
```
### 2. 权限问题
```bash
# 确保用户有足够权限
GRANT SELECT ON ALL TABLES IN SCHEMA public TO your_user;
```
### 3. 导入失败
- 检查 SQL 文件语法
- 查看 PostgreSQL 日志
- 确认表结构已正确创建
### 4. 数据不完整
- 检查导出日志
- 验证源数据库数据完整性
- 重新执行导出过程
## 最佳实践
1. **定期备份**: 建议定期导出数据作为备份
2. **版本控制**: 将初始数据文件纳入版本控制
3. **环境隔离**: 不同环境使用不同的数据集
4. **测试验证**: 在测试环境先验证导入过程
5. **文档更新**: 及时更新数据结构变更文档
## 自动化脚本
可以创建自动化脚本定期导出数据:
```bash
#!/bin/bash
# auto-export.sh
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="./backups/$DATE"
mkdir -p "$BACKUP_DIR"
export EXPORT_DIR="$BACKUP_DIR"
./export-data.sh -i
echo "数据导出完成: $BACKUP_DIR"
```
这样可以确保始终有最新的数据备份可用于新环境部署。

View File

@ -0,0 +1,141 @@
# QAUP 数据库初始数据文件说明
## 文件结构
```
deploy/docker/postgres/
├── qaup_database_schema.sql # 数据库表结构(必需)
├── initial_data.template.sql # 默认初始数据模板
├── initial_data.sql # 实际使用的初始数据(优先级最高)
├── 01_system_data.sql # 系统配置数据(导出生成)
├── 02_business_data.sql # 业务基础数据(导出生成)
├── 03_sample_data.sql # 示例数据(导出生成)
├── db-manager.sh # 统一数据库管理工具
├── init-db.sh # 数据库初始化脚本
└── postgresql.conf # PostgreSQL 配置文件
```
## 数据文件优先级
数据库初始化脚本 `init-db.sh` 按以下优先级加载数据:
1. **`initial_data.sql`** - 如果存在,优先使用(通常是从现有系统导出的完整数据)
2. **分层数据文件** - 如果 `initial_data.sql` 不存在,按顺序加载:
- `01_system_data.sql` - 系统基础配置
- `02_business_data.sql` - 业务基础数据
- `03_sample_data.sql` - 示例数据
## 使用场景
### 场景1全新部署使用默认数据
```bash
# 复制模板文件
cp initial_data.template.sql initial_data.sql
# 启动部署
./deploy.sh install
```
### 场景2从现有系统迁移
```bash
# 1. 从现有数据库导出并准备数据(一步完成)
./db-manager.sh prepare-export
# 2. 启动部署
./deploy.sh install
```
### 场景3选择性数据导入
```bash
# 1. 从现有数据库导出分层数据
./db-manager.sh export-initial
# 2. 自定义数据组合
./db-manager.sh prepare-custom
# 3. 启动部署
./deploy.sh install
```
### 场景4自定义数据组合
```bash
# 1. 创建自定义的 initial_data.sql
cat > initial_data.sql << 'EOF'
-- 自定义初始数据组合
EOF
# 2. 添加系统基础数据
cat export/01_system_data.sql >> initial_data.sql
# 3. 可选:添加业务数据
cat export/02_business_data.sql >> initial_data.sql
# 4. 启动部署
./deploy.sh install
```
## 数据文件内容说明
### `initial_data.template.sql`
- **用途**: 默认初始数据模板
- **内容**: 系统运行的最小数据集
- **特点**: 包含默认管理员账号、基础菜单、示例配置
- **适用**: 全新部署、演示环境
### `01_system_data.sql`(导出生成)
- **用途**: 系统基础配置数据
- **内容**: 配置、字典、菜单、角色、用户等
- **特点**: 从现有系统导出的实际配置
- **适用**: 生产环境迁移
### `02_business_data.sql`(导出生成)
- **用途**: 业务基础数据
- **内容**: 车辆类型、机场区域、空间规则等
- **特点**: 业务相关的配置数据
- **适用**: 保留业务配置的迁移
### `03_sample_data.sql`(导出生成)
- **用途**: 示例数据
- **内容**: 示例车辆信息等
- **特点**: 用于测试和演示
- **适用**: 开发、测试环境
## 注意事项
1. **文件优先级**: `initial_data.sql` 存在时,分层文件会被忽略
2. **数据冲突**: 确保导入的数据不会产生主键冲突
3. **序列更新**: 所有数据文件都包含序列值更新语句
4. **备份建议**: 导入前备份现有数据
5. **权限检查**: 确保数据库用户有足够的导入权限
## 故障排除
### 问题1数据导入失败
```bash
# 检查数据文件语法
psql -U postgres -d qaup --dry-run -f initial_data.sql
# 查看详细错误信息
docker logs qaup-postgres
```
### 问题2序列值错误
```sql
-- 手动更新序列值
SELECT setval('table_id_seq', (SELECT MAX(id) FROM table_name));
```
### 问题3权限不足
```sql
-- 授予必要权限
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO qaup_app;
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO qaup_app;
```
## 最佳实践
1. **版本控制**: 将使用的 `initial_data.sql` 纳入版本控制
2. **环境隔离**: 不同环境使用不同的数据文件
3. **定期导出**: 定期从生产环境导出最新配置
4. **测试验证**: 在测试环境验证数据导入过程
5. **文档更新**: 及时更新数据结构变更文档

View File

@ -59,6 +59,34 @@ sudo chmod +x /usr/local/bin/docker-compose
docker-compose --version
```
## 项目结构说明
QAUP 系统采用了优化的部署结构,所有部署相关文件都集中在 `deploy` 目录下:
```
QAUP-Management/
├── deploy/ # 部署目录(工作目录)
│ ├── deploy.sh # 主部署脚本
│ ├── docker-compose.yml # Docker Compose 配置
│ ├── docker-compose.prod.yml # 生产环境配置
│ ├── Dockerfile # 应用镜像构建文件
│ ├── .env.template # 环境变量模板
│ ├── docker/ # Docker 相关脚本和配置
│ │ ├── config-manager.sh # 配置管理脚本
│ │ ├── monitor.sh # 监控脚本
│ │ ├── nginx/ # Nginx 配置
│ │ └── postgres/ # PostgreSQL 配置
│ └── docs/ # 部署文档
├── qaup-admin/ # 后端主模块
├── qaup-ui/ # 前端模块
└── 其他项目文件...
```
**重要说明:**
- 所有部署操作都在 `deploy` 目录下进行
- Docker 构建上下文指向项目根目录,确保能正确访问所有源码文件
- 部署脚本会自动处理路径映射,无需手动调整
## 部署步骤
### 1. 获取部署包
@ -67,20 +95,27 @@ docker-compose --version
```bash
# 克隆项目(如果有 Git 访问权限)
git clone <项目地址>
cd QAUP-Management
cd QAUP-Management/deploy
```
#### 离线部署
```bash
# 解压离线部署包
tar -xzf qaup-offline-deploy.tar.gz
cd QAUP-Management
cd QAUP-Management/deploy
# 导入 Docker 镜像
./docker/load-images.sh
```
### 2. 环境验证
### 2. 路径配置验证
```bash
# 运行路径配置测试(推荐)
./test-paths.sh
```
### 3. 环境验证
```bash
# 运行环境验证脚本
@ -89,7 +124,34 @@ cd QAUP-Management
如果验证失败,请根据提示修复问题。
### 3. 配置系统
### 4. 数据准备
根据部署场景选择合适的数据准备方式:
#### 场景1全新部署推荐新用户
```bash
# 使用默认模板数据
./docker/postgres/db-manager.sh prepare-default
```
#### 场景2从现有系统迁移
```bash
# 设置数据库连接信息
export DB_HOST=your_db_host
export DB_USER=postgres
export DB_NAME=qaup
# 从现有数据库导出并准备数据
./docker/postgres/db-manager.sh prepare-export
```
#### 场景3查看当前数据状态
```bash
# 查看当前数据文件状态
./docker/postgres/db-manager.sh prepare-status
```
### 6. 配置系统
```bash
# 初始化配置

95
deploy/test-paths.sh Executable file
View File

@ -0,0 +1,95 @@
#!/bin/bash
# 路径配置测试脚本
# 用于验证部署目录结构和路径配置是否正确
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
print_message() {
local color=$1
local message=$2
echo -e "${color}${message}${NC}"
}
print_message $BLUE "QAUP 部署路径配置测试"
print_message $BLUE "======================"
echo ""
print_message $BLUE "当前目录: $SCRIPT_DIR"
print_message $BLUE "项目根目录: $PROJECT_ROOT"
echo ""
# 检查关键文件和目录
print_message $BLUE "检查关键文件和目录..."
# 检查项目根目录文件
files_to_check=(
"$PROJECT_ROOT/pom.xml"
"$PROJECT_ROOT/qaup-admin/pom.xml"
"$PROJECT_ROOT/qaup-ui/package.json"
)
for file in "${files_to_check[@]}"; do
if [ -f "$file" ]; then
print_message $GREEN "$file"
else
print_message $RED "$file (缺失)"
fi
done
# 检查部署目录文件
deploy_files_to_check=(
"$SCRIPT_DIR/deploy.sh"
"$SCRIPT_DIR/docker-compose.yml"
"$SCRIPT_DIR/Dockerfile"
"$SCRIPT_DIR/docker/config-manager.sh"
"$SCRIPT_DIR/docker/nginx/Dockerfile"
)
for file in "${deploy_files_to_check[@]}"; do
if [ -f "$file" ]; then
print_message $GREEN "$file"
else
print_message $RED "$file (缺失)"
fi
done
echo ""
print_message $BLUE "检查 Docker Compose 构建上下文..."
# 验证 Docker Compose 配置
if grep -q "context: \.\." "$SCRIPT_DIR/docker-compose.yml"; then
print_message $GREEN "✓ Docker Compose 构建上下文配置正确"
else
print_message $RED "✗ Docker Compose 构建上下文配置错误"
fi
if grep -q "dockerfile: deploy/Dockerfile" "$SCRIPT_DIR/docker-compose.yml"; then
print_message $GREEN "✓ Dockerfile 路径配置正确"
else
print_message $RED "✗ Dockerfile 路径配置错误"
fi
echo ""
print_message $BLUE "检查 Dockerfile 路径引用..."
# 检查 Dockerfile 中的路径
if grep -q "COPY deploy/docker/start.sh" "$SCRIPT_DIR/Dockerfile"; then
print_message $GREEN "✓ Dockerfile 启动脚本路径正确"
else
print_message $RED "✗ Dockerfile 启动脚本路径错误"
fi
echo ""
print_message $GREEN "路径配置检查完成!"
print_message $YELLOW "如果发现错误,请根据提示修复后重新测试"

View File