Files
jiu/scripts/dev.sh
T
wangjia d717fb3735 feat(client): 全模块 API 对接 + 修复登陆跳转 + 菜单 UI 优化
API 对接:
- 入库/出库/库存/财务/往来单位/基础数据全部对接后端 REST API
- 新增 repositories、providers、models 层,统一分层架构
- auth 从 flutter_secure_storage 迁移到 shared_preferences

登陆跳转修复:
- 将 _RouterNotifier 提取为独立 Riverpod provider,appRouterProvider
  使用 ref.read 避免依赖链导致 router 重建后跳回 /login
- redirect 函数新增 initialized 守卫,防止 auth 未恢复时误重定向
- 添加调试日志(Router/Auth/ApiClient)定位 401 触发的 logout 链路

退出菜单 UI:
- 去掉 ListTile,改用 Row + 自定义 padding,文字左对齐
- MouseRegion + AnimatedContainer 实现 hover 高亮(普通项蓝底/退出红底)
- 菜单圆角 6px,elevation 8,分割线高度 1px

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 22:20:28 +08:00

210 lines
6.8 KiB
Bash
Executable File

#!/usr/bin/env bash
# 如果用 sh 调用,自动切换到 bash
if [ -z "$BASH_VERSION" ]; then
exec bash "$0" "$@"
fi
# dev.sh — 本地开发环境管理
#
# 启动:
# bash scripts/dev.sh run # 启动前后端(后端无改动则跳过重启)
# bash scripts/dev.sh run --force # 强制重启后端
# bash scripts/dev.sh --backend-only # 仅启动后端
# bash scripts/dev.sh --frontend-only # 仅启动前端
#
# 数据库:
# bash scripts/dev.sh reset # 删表重建 + 写入测试数据
# bash scripts/dev.sh seed # 写入测试数据(已存在则跳过)
# bash 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"
# ── 颜色输出 ──────────────────────────────────────────────
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|reset|clear)
# seed / reset / clear 三个命令
SEED_ARG=""
[ "$COMMAND" = "reset" ] && SEED_ARG="--reset"
[ "$COMMAND" = "clear" ] && SEED_ARG="--clear"
[ -n "${2:-}" ] && SEED_ARG="$2"
info "写入初始测试数据..."
cd "$BACKEND_DIR"
go run cmd/seed/main.go $SEED_ARG
exit 0
;;
--backend-only)
COMMAND=run
RUN_FRONTEND=false
[ "${2:-}" = "--force" ] && FORCE=true
;;
--frontend-only)
COMMAND=run
RUN_BACKEND=false
;;
*)
error "未知命令: $COMMAND"
echo "用法: bash scripts/dev.sh [run [--force] | reset | clear | seed | --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