From aa522936c39ead64662f310eb2091fc5ed7e8407 Mon Sep 17 00:00:00 2001 From: yml2213 Date: Sat, 23 May 2026 08:22:31 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=B8=80=E9=94=AE=E5=90=AF?= =?UTF-8?q?=E5=8A=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 14 +++++ scripts/dev.sh | 163 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 177 insertions(+) create mode 100755 scripts/dev.sh diff --git a/README.md b/README.md index 27d01f3..f8d1410 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,20 @@ ## 快速开始 +一键启动开发版本: + +```bash +./scripts/dev.sh +``` + +脚本会自动启动 MySQL、Redis、MinIO,首次初始化数据库结构,刷新开发测试数据,并同时启动后端和前端。 + +前端地址:`http://localhost:5173` + +后台地址:`http://localhost:5173/admin/login`,开发态默认管理员为 `admin / admin123456`。 + +如需拆分调试,可手动执行: + ```bash docker compose -f deploy/docker-compose.dev.yml up -d diff --git a/scripts/dev.sh b/scripts/dev.sh new file mode 100755 index 0000000..e54636d --- /dev/null +++ b/scripts/dev.sh @@ -0,0 +1,163 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +COMPOSE_FILE="${ROOT_DIR}/deploy/docker-compose.dev.yml" +BACKEND_ENV="${ROOT_DIR}/backend/.env" +BACKEND_ENV_EXAMPLE="${ROOT_DIR}/backend/.env.example" + +BACKEND_PID="" +FRONTEND_PID="" +CLEANED_UP=0 + +log() { + printf "\033[1;34m[dev]\033[0m %s\n" "$*" +} + +need_cmd() { + if ! command -v "$1" >/dev/null 2>&1; then + printf "缺少命令:%s\n" "$1" >&2 + exit 1 + fi +} + +cleanup() { + if [[ "${CLEANED_UP}" == "1" ]]; then + return + fi + CLEANED_UP=1 + + log "正在停止前后端开发进程..." + if [[ -n "${FRONTEND_PID}" ]] && kill -0 "${FRONTEND_PID}" >/dev/null 2>&1; then + kill "${FRONTEND_PID}" >/dev/null 2>&1 || true + fi + if [[ -n "${BACKEND_PID}" ]] && kill -0 "${BACKEND_PID}" >/dev/null 2>&1; then + kill "${BACKEND_PID}" >/dev/null 2>&1 || true + fi +} + +wait_container_healthy() { + local container_name="$1" + local label="$2" + local attempt + + log "等待 ${label} 就绪..." + for attempt in {1..60}; do + local status + status="$(docker inspect -f '{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}' "${container_name}" 2>/dev/null || true)" + if [[ "${status}" == "healthy" || "${status}" == "running" ]]; then + log "${label} 已就绪" + return 0 + fi + sleep 2 + done + + printf "%s 启动超时,请检查:docker logs %s\n" "${label}" "${container_name}" >&2 + exit 1 +} + +init_database() { + local table_count + table_count="$( + docker exec hfb-mysql mysql -uhfb -psecret -N -s -e \ + "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = 'hfb_sys' AND table_name = 'users';" 2>/dev/null + )" + + if [[ "${table_count}" == "0" ]]; then + log "首次启动,初始化数据库结构..." + docker exec -i hfb-mysql mysql -uhfb -psecret hfb_sys < "${ROOT_DIR}/backend/migrations/000001_init.sql" + else + log "数据库结构已存在,跳过迁移" + fi + + log "刷新开发测试数据..." + docker exec -i hfb-mysql mysql -uhfb -psecret hfb_sys < "${ROOT_DIR}/backend/seeds/dev_orders.sql" +} + +load_env_file() { + local env_file="$1" + local line + + while IFS= read -r line || [[ -n "${line}" ]]; do + [[ -z "${line}" || "${line}" =~ ^[[:space:]]*# ]] && continue + line="${line#export }" + export "${line}" + done < "${env_file}" +} + +start_backend() { + if [[ ! -f "${BACKEND_ENV}" ]]; then + log "创建 backend/.env" + cp "${BACKEND_ENV_EXAMPLE}" "${BACKEND_ENV}" + fi + + log "启动后端:http://localhost:8080" + ( + cd "${ROOT_DIR}/backend" + load_env_file "${BACKEND_ENV}" + go run ./cmd/api + ) & + BACKEND_PID="$!" +} + +start_frontend() { + if [[ ! -d "${ROOT_DIR}/frontend/node_modules" ]]; then + log "安装前端依赖..." + ( + cd "${ROOT_DIR}/frontend" + npm ci + ) + fi + + log "启动前端:http://localhost:5173" + ( + cd "${ROOT_DIR}/frontend" + npm run dev + ) & + FRONTEND_PID="$!" +} + +watch_processes() { + while true; do + if ! kill -0 "${BACKEND_PID}" >/dev/null 2>&1; then + wait "${BACKEND_PID}" || true + printf "后端进程已退出\n" >&2 + exit 1 + fi + if ! kill -0 "${FRONTEND_PID}" >/dev/null 2>&1; then + wait "${FRONTEND_PID}" || true + printf "前端进程已退出\n" >&2 + exit 1 + fi + sleep 2 + done +} + +main() { + need_cmd docker + need_cmd go + need_cmd npm + + trap cleanup EXIT + trap 'cleanup; exit 130' INT TERM + + log "启动开发依赖:MySQL、Redis、MinIO" + docker compose -f "${COMPOSE_FILE}" up -d + + wait_container_healthy hfb-mysql "MySQL" + wait_container_healthy hfb-redis "Redis" + wait_container_healthy hfb-minio "MinIO" + + init_database + start_backend + start_frontend + + log "开发环境已启动" + log "前台:http://localhost:5173" + log "后台:http://localhost:5173/admin/login(admin / admin123456)" + log "按 Ctrl+C 停止前后端;Docker 依赖会保留运行" + + watch_processes +} + +main "$@"