Files
jiu/scripts/dev.sh
T
wangjia 62900c4bd8 fix(db): 修复 seed 中文乱码
mysql 命令加 --default-character-set=utf8mb4,
SQL 文件头加 SET NAMES utf8mb4

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 08:36:09 +08:00

255 lines
8.4 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# 如果用 sh 调用,自动切换到 bash
if [ -z "$BASH_VERSION" ]; then
exec bash "$0" "$@"
fi
# dev.sh — 本地开发环境管理
#
# 启动:
# sh scripts/dev.sh run # 启动前后端(后端无改动则跳过重启)
# sh scripts/dev.sh run --force # 强制重启后端
# sh scripts/dev.sh --backend-only # 仅启动后端
# sh scripts/dev.sh --frontend-only # 仅启动前端
#
# 数据库:
# sh scripts/dev.sh seed H001 # 清空并写入 H001 测试数据(SQL 文件)
# sh scripts/dev.sh reset # 删表重建(AutoMigrate
# sh scripts/dev.sh clear # 清空所有业务数据
set -e
export PATH="/opt/homebrew/bin:/opt/homebrew/sbin:$PATH"
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
BACKEND_DIR="$ROOT/backend"
CLIENT_DIR="$ROOT/client"
LOG_DIR="$ROOT/scripts/.logs"
BACKEND_LOG="$LOG_DIR/backend.log"
BACKEND_PID_FILE="$LOG_DIR/backend.pid"
BACKEND_HASH_FILE="$LOG_DIR/backend.hash"
mkdir -p "$LOG_DIR"
# ── seed 命令 ────────────────────────────────────────────────
# 用法: cmd_seed <shop_code>
# 从 backend/config/config.yaml 读取 DSN,执行 backend/seeds/<shop>.sql
cmd_seed() {
local shop="${1:-}"
if [ -z "$shop" ]; then
error "用法: sh scripts/dev.sh seed <shop_code> 示例: sh scripts/dev.sh seed H001"
exit 1
fi
local sql_file="$ROOT/backend/seeds/${shop}.sql"
if [ ! -f "$sql_file" ]; then
error "种子文件不存在: $sql_file"
exit 1
fi
# 从 docker-compose.yml 读取容器名和数据库信息
local compose_file="$ROOT/deploy/docker-compose.yml"
local container db_pass db_name
container=$(grep 'container_name:' "$compose_file" | grep -i mysql | head -1 | sed 's/.*container_name: *//')
db_pass=$(grep 'MYSQL_ROOT_PASSWORD:' "$compose_file" | head -1 | sed 's/.*MYSQL_ROOT_PASSWORD: *//')
db_name=$(grep 'MYSQL_DATABASE:' "$compose_file" | head -1 | sed 's/.*MYSQL_DATABASE: *//')
# 检查容器是否运行
if ! docker ps --format '{{.Names}}' | grep -q "^${container}$"; then
error "MySQL 容器 '${container}' 未运行,请先执行: docker compose -f deploy/docker-compose.yml up -d"
exit 1
fi
info "写入 ${shop} 种子数据 → 容器 ${container} / ${db_name}"
docker exec -i "$container" mysql --default-character-set=utf8mb4 -uroot -p"$db_pass" "$db_name" < "$sql_file"
success "${shop} 种子数据写入完成"
echo ""
echo " 登录信息:"
echo " 门店编号: ${shop}"
echo " admin / password123"
echo " operator / password123"
echo " test / password123"
}
# ── 颜色输出 ──────────────────────────────────────────────
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
CYAN='\033[0;36m'
NC='\033[0m'
info() { echo -e "${CYAN}[dev]${NC} $*"; }
success() { echo -e "${GREEN}[dev]${NC} $*"; }
warn() { echo -e "${YELLOW}[dev]${NC} $*"; }
error() { echo -e "${RED}[dev]${NC} $*"; }
# ── 参数解析 ──────────────────────────────────────────────
COMMAND="${1:-run}"
FORCE=false
RUN_BACKEND=true
RUN_FRONTEND=true
case "$COMMAND" in
run)
[ "${2:-}" = "--force" ] && FORCE=true
;;
seed)
cmd_seed "${2:-}"
exit 0
;;
reset)
info "删表重建(AutoMigrate..."
cd "$BACKEND_DIR"
go run cmd/seed/main.go --reset
exit 0
;;
clear)
info "清空所有业务数据..."
cd "$BACKEND_DIR"
go run cmd/seed/main.go --clear
exit 0
;;
--backend-only)
COMMAND=run
RUN_FRONTEND=false
[ "${2:-}" = "--force" ] && FORCE=true
;;
--frontend-only)
COMMAND=run
RUN_BACKEND=false
;;
*)
error "未知命令: $COMMAND"
echo "用法: sh scripts/dev.sh [run [--force] | seed <shop> | reset | clear | --backend-only | --frontend-only]"
exit 1
;;
esac
# ── 清理函数 ──────────────────────────────────────────────
cleanup() {
echo ""
info "正在关闭服务..."
# 不杀后端:run 模式下后端是持久进程,Ctrl+C 只退出 flutter
info "后端继续在后台运行。如需停止:bash scripts/dev.sh stop"
exit 0
}
trap cleanup INT TERM
# ── 依赖检查 ──────────────────────────────────────────────
check_deps() {
local missing=0
if [ "$RUN_BACKEND" = true ] && ! command -v go &>/dev/null; then
error "未找到 go,请确认 PATH 包含 Homebrew bin"
missing=1
fi
if [ "$RUN_FRONTEND" = true ] && ! command -v flutter &>/dev/null; then
error "未找到 flutter,请安装 Flutter SDK"
missing=1
fi
[ "$missing" -eq 1 ] && exit 1
return 0
}
# ── 计算后端源码 hash ──────────────────────────────────────
backend_hash() {
# 对所有 .go 文件 + go.mod 内容做 hash
find "$BACKEND_DIR" -name "*.go" -o -name "go.mod" -o -name "go.sum" \
| sort \
| xargs shasum 2>/dev/null \
| shasum \
| awk '{print $1}'
}
# ── 检查后端进程是否还活着 ───────────────────────────────
backend_running() {
if [ ! -f "$BACKEND_PID_FILE" ]; then return 1; fi
local pid
pid=$(cat "$BACKEND_PID_FILE")
kill -0 "$pid" 2>/dev/null
}
# ── 杀掉占用 8080 的进程 ──────────────────────────────────
kill_port_8080() {
local pids
pids=$(lsof -ti:8080 2>/dev/null || true)
if [ -n "$pids" ]; then
warn "端口 8080 被占用,正在清理..."
echo "$pids" | xargs kill -9 2>/dev/null || true
sleep 1
success "端口 8080 已释放"
fi
}
# ── 等待后端就绪 ──────────────────────────────────────────
wait_backend() {
info "等待后端启动..."
local i=0
while [ $i -lt 30 ]; do
if curl -s -o /dev/null http://localhost:8080/api/v1/auth/login 2>/dev/null; then
success "后端已就绪 → http://localhost:8080"
return 0
fi
sleep 1
i=$((i + 1))
done
warn "后端启动超时,请查看日志:tail -f $BACKEND_LOG"
}
# ── 启动后端 ──────────────────────────────────────────────
start_backend() {
local current_hash
current_hash=$(backend_hash)
local saved_hash=""
[ -f "$BACKEND_HASH_FILE" ] && saved_hash=$(cat "$BACKEND_HASH_FILE")
# 判断是否需要重启
if [ "$FORCE" = false ] && backend_running && [ "$current_hash" = "$saved_hash" ]; then
local pid
pid=$(cat "$BACKEND_PID_FILE")
success "后端无改动,跳过重启 (PID $pid) → http://localhost:8080"
return 0
fi
if backend_running; then
local pid
pid=$(cat "$BACKEND_PID_FILE")
warn "后端代码已变更,重启中 (旧 PID $pid)..."
kill "$pid" 2>/dev/null || true
sleep 1
fi
kill_port_8080
info "编译并启动后端 (Go)..."
cd "$BACKEND_DIR"
go run main.go >>"$BACKEND_LOG" 2>&1 &
local new_pid=$!
echo "$new_pid" > "$BACKEND_PID_FILE"
echo "$current_hash" > "$BACKEND_HASH_FILE"
info "后端进程 PID=$new_pid,日志:tail -f $BACKEND_LOG"
wait_backend
}
# ════════════════════════════════════════════════════════
check_deps
if [ "$RUN_BACKEND" = true ]; then
start_backend
fi
if [ "$RUN_FRONTEND" = true ]; then
info "启动 Flutter (macOS)..."
cd "$CLIENT_DIR"
flutter pub get
echo ""
success "Flutter 启动中,窗口将自动弹出..."
echo -e "${CYAN}提示:关闭 Flutter 窗口或按 q 退出前端,后端继续运行${NC}"
echo -e "${CYAN} 再次执行 bash scripts/dev.sh run 可复用已有后端${NC}"
echo ""
flutter run -d macos
else
echo ""
success "后端运行中,按 Ctrl+C 退出此脚本(后端仍在后台)"
echo -e " 查看日志:tail -f $BACKEND_LOG"
wait "$(cat "$BACKEND_PID_FILE")" 2>/dev/null || true
fi