754 lines
19 KiB
Bash
754 lines
19 KiB
Bash
#!/bin/bash
|
||
|
||
set -euo pipefail
|
||
|
||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
cd "$ROOT_DIR"
|
||
|
||
VENV_DIR=".venv"
|
||
VENV_PYTHON="$VENV_DIR/bin/python"
|
||
LOG_DIR="logs"
|
||
API_PID_FILE="$LOG_DIR/api.pid"
|
||
FRONTEND_PID_FILE="$LOG_DIR/frontend.pid"
|
||
API_LOG_FILE="$LOG_DIR/api.log"
|
||
FRONTEND_LOG_FILE="$LOG_DIR/frontend.log"
|
||
DISPLAY_HOST="localhost"
|
||
SERVICE_HOST="6.86.80.8"
|
||
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
CYAN='\033[0;36m'
|
||
NC='\033[0m'
|
||
|
||
load_env() {
|
||
load_env_file ".env"
|
||
load_env_file ".env.development"
|
||
|
||
API_HOST="${API_HOST:-0.0.0.0}"
|
||
API_PORT="${API_PORT:-8000}"
|
||
FRONTEND_PORT="${FRONTEND_PORT:-5173}"
|
||
FRONTEND_MODE="${FRONTEND_MODE:-dev}"
|
||
}
|
||
|
||
load_env_file() {
|
||
local env_file="$1"
|
||
|
||
if [ -f "$env_file" ]; then
|
||
while IFS='=' read -r key value; do
|
||
key="${key%$'\r'}"
|
||
value="${value%$'\r'}"
|
||
|
||
case "$key" in
|
||
""|\#*)
|
||
continue
|
||
;;
|
||
API_HOST|API_PORT|FRONTEND_PORT|FRONTEND_MODE)
|
||
export "$key=$value"
|
||
;;
|
||
esac
|
||
done < "$env_file"
|
||
fi
|
||
}
|
||
|
||
ensure_log_dir() {
|
||
mkdir -p "$LOG_DIR"
|
||
}
|
||
|
||
check_tcp_connectivity() {
|
||
local host="$1"
|
||
local port="$2"
|
||
|
||
if command -v nc > /dev/null 2>&1; then
|
||
nc -z -w 3 "$host" "$port" > /dev/null 2>&1
|
||
return
|
||
fi
|
||
|
||
require_python_bootstrap
|
||
"$PYTHON_BOOTSTRAP" - <<PY > /dev/null 2>&1
|
||
import socket
|
||
import sys
|
||
|
||
try:
|
||
with socket.create_connection(("${host}", ${port}), timeout=3):
|
||
pass
|
||
except Exception:
|
||
sys.exit(1)
|
||
|
||
sys.exit(0)
|
||
PY
|
||
}
|
||
|
||
check_foundation_services() {
|
||
local name
|
||
local port
|
||
|
||
for service in \
|
||
"Milvus:19530" \
|
||
"MinIO API:9000" \
|
||
"MinIO Console:9001" \
|
||
"Redis:6379" \
|
||
"PostgreSQL:5432"
|
||
do
|
||
name="${service%%:*}"
|
||
port="${service##*:}"
|
||
if check_tcp_connectivity "$SERVICE_HOST" "$port"; then
|
||
success "${name}: ${SERVICE_HOST}:${port} 可连通"
|
||
else
|
||
warn "${name}: ${SERVICE_HOST}:${port} 不可连通"
|
||
fi
|
||
done
|
||
}
|
||
|
||
print_header() {
|
||
echo ""
|
||
echo -e "${CYAN}========================================${NC}"
|
||
echo -e "${CYAN} $1${NC}"
|
||
echo -e "${CYAN}========================================${NC}"
|
||
echo ""
|
||
}
|
||
|
||
info() {
|
||
echo -e "${CYAN}$1${NC}"
|
||
}
|
||
|
||
success() {
|
||
echo -e "${GREEN}$1${NC}"
|
||
}
|
||
|
||
warn() {
|
||
echo -e "${YELLOW}$1${NC}"
|
||
}
|
||
|
||
error() {
|
||
echo -e "${RED}$1${NC}" >&2
|
||
}
|
||
|
||
die() {
|
||
error "$1"
|
||
exit 1
|
||
}
|
||
|
||
is_pid_running() {
|
||
local pid="$1"
|
||
[ -n "$pid" ] && ps -p "$pid" > /dev/null 2>&1
|
||
}
|
||
|
||
read_pid() {
|
||
local pid_file="$1"
|
||
if [ -f "$pid_file" ]; then
|
||
cat "$pid_file"
|
||
fi
|
||
}
|
||
|
||
cleanup_stale_pid() {
|
||
local pid_file="$1"
|
||
local pid
|
||
pid="$(read_pid "$pid_file")"
|
||
if [ -n "$pid" ] && ! is_pid_running "$pid"; then
|
||
rm -f "$pid_file"
|
||
fi
|
||
}
|
||
|
||
port_pid() {
|
||
local port="$1"
|
||
|
||
if command -v lsof > /dev/null 2>&1; then
|
||
lsof -ti tcp:"$port" 2>/dev/null | head -n 1 || true
|
||
return 0
|
||
fi
|
||
|
||
if command -v ss > /dev/null 2>&1; then
|
||
ss -lptn "sport = :$port" 2>/dev/null | awk -F 'pid=' 'NR>1 && NF>1 {split($2,a,/,/); print a[1]; exit}' || true
|
||
return 0
|
||
fi
|
||
|
||
if command -v netstat > /dev/null 2>&1; then
|
||
netstat -lntp 2>/dev/null | awk -v port=":$port" '$4 ~ port {split($7,a,"/"); if (a[1] != "-") {print a[1]; exit}}' || true
|
||
fi
|
||
|
||
return 0
|
||
}
|
||
|
||
require_python_bootstrap() {
|
||
if command -v python3 > /dev/null 2>&1; then
|
||
PYTHON_BOOTSTRAP="python3"
|
||
elif command -v python > /dev/null 2>&1; then
|
||
PYTHON_BOOTSTRAP="python"
|
||
else
|
||
die "未找到 Python,请先安装 Python 3.10+。"
|
||
fi
|
||
}
|
||
|
||
require_venv() {
|
||
[ -x "$VENV_PYTHON" ] || die "虚拟环境不存在,请先运行 ./dev.sh setup"
|
||
}
|
||
|
||
ensure_frontend_deps() {
|
||
if [ ! -d "frontend" ]; then
|
||
die "前端目录不存在: frontend"
|
||
fi
|
||
|
||
if [ ! -d "frontend/node_modules" ] || [ ! -d "frontend/node_modules/vite" ]; then
|
||
warn "前端依赖不存在或不完整,正在执行 npm install..."
|
||
npm --prefix frontend install
|
||
fi
|
||
}
|
||
|
||
validate_frontend_mode() {
|
||
case "$1" in
|
||
dev|static)
|
||
;;
|
||
*)
|
||
die "前端模式仅支持 dev 或 static,当前值: $1"
|
||
;;
|
||
esac
|
||
}
|
||
|
||
check_python_version() {
|
||
local python_cmd="$1"
|
||
"$python_cmd" -c 'import sys; raise SystemExit(0 if sys.version_info >= (3, 10) else 1)'
|
||
}
|
||
|
||
run_setup() {
|
||
load_env
|
||
ensure_log_dir
|
||
print_header "AI+合规智能中枢 - 环境初始化"
|
||
|
||
require_python_bootstrap
|
||
|
||
info "[1/4] 检查 Python 版本"
|
||
check_python_version "$PYTHON_BOOTSTRAP" || die "需要 Python 3.10+"
|
||
success "Python 版本检查通过"
|
||
echo ""
|
||
|
||
info "[2/4] 准备虚拟环境"
|
||
if [ ! -d "$VENV_DIR" ]; then
|
||
"$PYTHON_BOOTSTRAP" -m venv "$VENV_DIR"
|
||
success "已创建虚拟环境: $VENV_DIR"
|
||
else
|
||
success "虚拟环境已存在: $VENV_DIR"
|
||
fi
|
||
|
||
"$VENV_PYTHON" -m pip install --upgrade pip
|
||
"$VENV_PYTHON" -m pip install -r backend/requirements.txt
|
||
success "后端依赖安装完成"
|
||
echo ""
|
||
|
||
info "[3/4] 准备前端依赖"
|
||
if ! command -v npm > /dev/null 2>&1; then
|
||
die "未找到 npm,请先安装 Node.js 20+。"
|
||
fi
|
||
npm --prefix frontend install
|
||
success "前端依赖安装完成"
|
||
echo ""
|
||
|
||
info "[4/4] 检查 6.86.80.8 基础服务连通性"
|
||
check_foundation_services
|
||
|
||
echo ""
|
||
success "环境初始化完成"
|
||
echo "后续常用命令:"
|
||
echo " ./dev.sh start"
|
||
echo " ./dev.sh status"
|
||
echo " ./dev.sh logs api --follow"
|
||
}
|
||
|
||
api_health_ok() {
|
||
if command -v curl > /dev/null 2>&1; then
|
||
curl -fsS "http://${DISPLAY_HOST}:$API_PORT/health" > /dev/null 2>&1
|
||
return
|
||
fi
|
||
|
||
require_venv
|
||
"$VENV_PYTHON" - <<PY > /dev/null 2>&1
|
||
import sys
|
||
from urllib.request import urlopen
|
||
|
||
try:
|
||
with urlopen("http://${DISPLAY_HOST}:${API_PORT}/health", timeout=3) as response:
|
||
body = response.read().decode("utf-8", errors="ignore")
|
||
sys.exit(0 if "healthy" in body.lower() else 1)
|
||
except Exception:
|
||
sys.exit(1)
|
||
PY
|
||
}
|
||
|
||
start_api() {
|
||
local mode="${1:-background}"
|
||
load_env
|
||
ensure_log_dir
|
||
require_venv
|
||
cleanup_stale_pid "$API_PID_FILE"
|
||
|
||
local pid
|
||
pid="$(read_pid "$API_PID_FILE")"
|
||
if is_pid_running "$pid"; then
|
||
warn "API 已在运行 (PID: $pid)"
|
||
return
|
||
fi
|
||
|
||
export PYTHONPATH="backend${PYTHONPATH:+:$PYTHONPATH}"
|
||
|
||
if [ "$mode" = "foreground" ]; then
|
||
print_header "AI+合规智能中枢 - 启动 API"
|
||
echo "运行模式: 前台调试(带 --reload)"
|
||
echo "服务地址: http://${DISPLAY_HOST}:$API_PORT"
|
||
echo "文档地址: http://${DISPLAY_HOST}:$API_PORT/docs"
|
||
echo "健康检查: http://${DISPLAY_HOST}:$API_PORT/health"
|
||
echo ""
|
||
exec "$VENV_PYTHON" -m uvicorn app.main:app --host "$API_HOST" --port "$API_PORT" --reload
|
||
fi
|
||
|
||
nohup "$VENV_PYTHON" -m uvicorn app.main:app --host "$API_HOST" --port "$API_PORT" > "$API_LOG_FILE" 2>&1 &
|
||
pid=$!
|
||
echo "$pid" > "$API_PID_FILE"
|
||
sleep 3
|
||
|
||
if is_pid_running "$pid"; then
|
||
success "API 启动成功 (PID: $pid)"
|
||
echo " 地址: http://${DISPLAY_HOST}:$API_PORT"
|
||
echo " 文档: http://${DISPLAY_HOST}:$API_PORT/docs"
|
||
echo " 日志: $API_LOG_FILE"
|
||
else
|
||
rm -f "$API_PID_FILE"
|
||
die "API 启动失败,请查看日志: $API_LOG_FILE"
|
||
fi
|
||
}
|
||
|
||
start_frontend() {
|
||
local mode="${1:-$FRONTEND_MODE}"
|
||
load_env
|
||
ensure_log_dir
|
||
cleanup_stale_pid "$FRONTEND_PID_FILE"
|
||
|
||
local pid
|
||
pid="$(read_pid "$FRONTEND_PID_FILE")"
|
||
if is_pid_running "$pid"; then
|
||
warn "前端已在运行 (PID: $pid)"
|
||
return
|
||
fi
|
||
|
||
if ! command -v npm > /dev/null 2>&1; then
|
||
die "未找到 npm,请先安装 Node.js 20+。"
|
||
fi
|
||
|
||
ensure_frontend_deps
|
||
|
||
if [ "$mode" = "static" ]; then
|
||
require_python_bootstrap
|
||
npm --prefix frontend run build
|
||
nohup "$PYTHON_BOOTSTRAP" -m http.server "$FRONTEND_PORT" --bind 0.0.0.0 --directory frontend/dist > "$FRONTEND_LOG_FILE" 2>&1 &
|
||
else
|
||
nohup npm --prefix frontend run dev -- --host 0.0.0.0 --port "$FRONTEND_PORT" > "$FRONTEND_LOG_FILE" 2>&1 &
|
||
fi
|
||
|
||
pid=$!
|
||
echo "$pid" > "$FRONTEND_PID_FILE"
|
||
sleep 4
|
||
|
||
if is_pid_running "$pid"; then
|
||
success "前端启动成功 (PID: $pid)"
|
||
echo " 地址: http://${DISPLAY_HOST}:$FRONTEND_PORT"
|
||
echo " 模式: $mode"
|
||
echo " 日志: $FRONTEND_LOG_FILE"
|
||
else
|
||
rm -f "$FRONTEND_PID_FILE"
|
||
die "前端启动失败,请查看日志: $FRONTEND_LOG_FILE"
|
||
fi
|
||
}
|
||
|
||
kill_pid_file_process() {
|
||
local pid_file="$1"
|
||
local label="$2"
|
||
local pid
|
||
pid="$(read_pid "$pid_file")"
|
||
|
||
if ! is_pid_running "$pid"; then
|
||
rm -f "$pid_file"
|
||
warn "$label 未通过 PID 文件发现运行中的进程"
|
||
return 1
|
||
fi
|
||
|
||
kill "$pid" 2>/dev/null || true
|
||
sleep 2
|
||
if is_pid_running "$pid"; then
|
||
kill -9 "$pid" 2>/dev/null || true
|
||
fi
|
||
rm -f "$pid_file"
|
||
success "$label 已停止"
|
||
return 0
|
||
}
|
||
|
||
stop_api() {
|
||
load_env
|
||
ensure_log_dir
|
||
|
||
if kill_pid_file_process "$API_PID_FILE" "API"; then
|
||
return
|
||
fi
|
||
|
||
local port_listener
|
||
port_listener="$(port_pid "$API_PORT")"
|
||
if [ -n "$port_listener" ]; then
|
||
kill "$port_listener" 2>/dev/null || true
|
||
sleep 1
|
||
if is_pid_running "$port_listener"; then
|
||
kill -9 "$port_listener" 2>/dev/null || true
|
||
fi
|
||
success "已停止监听 API 端口 $API_PORT 的进程 (PID: $port_listener)"
|
||
else
|
||
warn "未发现运行中的 API 服务"
|
||
fi
|
||
|
||
rm -f "$API_PID_FILE"
|
||
}
|
||
|
||
stop_frontend() {
|
||
load_env
|
||
ensure_log_dir
|
||
|
||
if kill_pid_file_process "$FRONTEND_PID_FILE" "前端"; then
|
||
return
|
||
fi
|
||
|
||
local port_listener
|
||
port_listener="$(port_pid "$FRONTEND_PORT")"
|
||
if [ -n "$port_listener" ]; then
|
||
kill "$port_listener" 2>/dev/null || true
|
||
sleep 1
|
||
if is_pid_running "$port_listener"; then
|
||
kill -9 "$port_listener" 2>/dev/null || true
|
||
fi
|
||
success "已停止监听前端端口 $FRONTEND_PORT 的进程 (PID: $port_listener)"
|
||
else
|
||
warn "未发现运行中的前端服务"
|
||
fi
|
||
|
||
rm -f "$FRONTEND_PID_FILE"
|
||
}
|
||
|
||
run_status() {
|
||
load_env
|
||
ensure_log_dir
|
||
print_header "AI+合规智能中枢 - 服务状态"
|
||
|
||
cleanup_stale_pid "$API_PID_FILE"
|
||
cleanup_stale_pid "$FRONTEND_PID_FILE"
|
||
|
||
local api_running=false
|
||
local frontend_running=false
|
||
local pid
|
||
local port_listener
|
||
local service_name
|
||
local service_port
|
||
|
||
echo -e "${YELLOW}API 服务:${NC}"
|
||
pid="$(read_pid "$API_PID_FILE")"
|
||
if is_pid_running "$pid"; then
|
||
api_running=true
|
||
success " 状态: 运行中"
|
||
echo " PID: $pid"
|
||
else
|
||
port_listener="$(port_pid "$API_PORT")"
|
||
if [ -n "$port_listener" ]; then
|
||
api_running=true
|
||
success " 状态: 运行中 (无 PID 文件)"
|
||
echo " PID: $port_listener"
|
||
else
|
||
error " 状态: 已停止"
|
||
fi
|
||
fi
|
||
|
||
if [ "$api_running" = true ]; then
|
||
if api_health_ok; then
|
||
success " 健康检查: 正常"
|
||
else
|
||
warn " 健康检查: 未通过"
|
||
fi
|
||
fi
|
||
echo " 地址: http://${DISPLAY_HOST}:$API_PORT"
|
||
echo " 文档: http://${DISPLAY_HOST}:${API_PORT}/docs"
|
||
echo ""
|
||
|
||
echo -e "${YELLOW}前端服务:${NC}"
|
||
pid="$(read_pid "$FRONTEND_PID_FILE")"
|
||
if is_pid_running "$pid"; then
|
||
frontend_running=true
|
||
success " 状态: 运行中"
|
||
echo " PID: $pid"
|
||
else
|
||
port_listener="$(port_pid "$FRONTEND_PORT")"
|
||
if [ -n "$port_listener" ]; then
|
||
frontend_running=true
|
||
success " 状态: 运行中 (无 PID 文件)"
|
||
echo " PID: $port_listener"
|
||
else
|
||
error " 状态: 已停止"
|
||
fi
|
||
fi
|
||
echo " 模式: $FRONTEND_MODE"
|
||
echo " 地址: http://${DISPLAY_HOST}:$FRONTEND_PORT"
|
||
echo ""
|
||
|
||
echo -e "${YELLOW}基础服务连通性:${NC}"
|
||
for service in \
|
||
"Milvus:19530" \
|
||
"MinIO API:9000" \
|
||
"MinIO Console:9001" \
|
||
"Redis:6379" \
|
||
"PostgreSQL:5432"
|
||
do
|
||
service_name="${service%%:*}"
|
||
service_port="${service##*:}"
|
||
if check_tcp_connectivity "$SERVICE_HOST" "$service_port"; then
|
||
success " ${service_name}: ${SERVICE_HOST}:${service_port} 可连通"
|
||
else
|
||
warn " ${service_name}: ${SERVICE_HOST}:${service_port} 不可连通"
|
||
fi
|
||
done
|
||
|
||
echo ""
|
||
if [ "$api_running" = true ] && [ "$frontend_running" = true ]; then
|
||
success "所有核心服务均在运行"
|
||
else
|
||
warn "存在未运行的服务,可使用 ./dev.sh start 启动"
|
||
fi
|
||
}
|
||
|
||
run_logs() {
|
||
local target="${1:-}"
|
||
local follow="${2:-}"
|
||
local log_file
|
||
|
||
case "$target" in
|
||
api)
|
||
log_file="$API_LOG_FILE"
|
||
;;
|
||
frontend)
|
||
log_file="$FRONTEND_LOG_FILE"
|
||
;;
|
||
*)
|
||
die "请指定日志类型: api 或 frontend"
|
||
;;
|
||
esac
|
||
|
||
[ -f "$log_file" ] || die "日志文件不存在: $log_file"
|
||
|
||
if [ "$follow" = "--follow" ]; then
|
||
tail -f "$log_file"
|
||
else
|
||
tail -n 50 "$log_file"
|
||
fi
|
||
}
|
||
|
||
show_help() {
|
||
cat <<'EOF'
|
||
AI+合规智能中枢统一脚本
|
||
|
||
用法:
|
||
./dev.sh help
|
||
./dev.sh setup
|
||
./dev.sh start [all|api|frontend] [--foreground] [--mode dev|static]
|
||
./dev.sh stop [all|api|frontend]
|
||
./dev.sh restart [all|api|frontend] [--mode dev|static]
|
||
./dev.sh status
|
||
./dev.sh logs <api|frontend> [--follow]
|
||
|
||
命令说明:
|
||
help
|
||
输出完整帮助信息、默认端口、日志目录和常见示例。
|
||
|
||
setup
|
||
进行一次性的本地初始化。
|
||
包含 Python 版本检查、.venv 虚拟环境创建、后端依赖安装、前端 npm install、
|
||
以及 6.86.80.8 基础服务端口连通性检查。
|
||
|
||
start
|
||
启动服务。默认行为等同于 ./dev.sh start all。
|
||
可选目标:
|
||
all 同时启动 API 和前端。
|
||
api 只启动后端 API。
|
||
frontend 只启动前端。
|
||
可选参数:
|
||
--foreground 仅对 start api 生效,前台运行并开启 --reload,便于调试。
|
||
--mode dev 前端使用 Vite 开发服务器,默认端口 5173。
|
||
--mode static 前端先执行 npm run build,再以静态文件服务器方式启动。
|
||
|
||
stop
|
||
停止服务。默认行为等同于 ./dev.sh stop all。
|
||
会优先读取 logs/*.pid,PID 文件失效时会回退到端口探测。
|
||
|
||
restart
|
||
先停止再启动,支持 all/api/frontend。
|
||
restart frontend --mode static 可直接切换前端启动模式。
|
||
|
||
status
|
||
查看 API、前端、6.86.80.8 基础服务的状态。
|
||
API 状态包含健康检查;前端状态包含当前模式和访问地址。
|
||
|
||
logs
|
||
查看日志。默认输出最后 50 行。
|
||
追加 --follow 后会持续跟踪日志输出。
|
||
|
||
默认约定:
|
||
API_HOST 默认 0.0.0.0
|
||
API_PORT 默认 8000
|
||
FRONTEND_PORT 默认 5173
|
||
FRONTEND_MODE 默认 dev
|
||
日志目录 logs/
|
||
PID 文件 logs/api.pid, logs/frontend.pid
|
||
|
||
常用示例:
|
||
./dev.sh setup
|
||
./dev.sh start
|
||
./dev.sh start api --foreground
|
||
./dev.sh start frontend --mode static
|
||
./dev.sh restart frontend --mode dev
|
||
./dev.sh status
|
||
./dev.sh logs api --follow
|
||
./dev.sh logs frontend
|
||
EOF
|
||
}
|
||
|
||
parse_target() {
|
||
local default_target="$1"
|
||
local candidate="${2:-}"
|
||
case "$candidate" in
|
||
all|api|frontend)
|
||
echo "$candidate"
|
||
;;
|
||
*)
|
||
echo "$default_target"
|
||
;;
|
||
esac
|
||
}
|
||
|
||
main() {
|
||
local command="${1:-help}"
|
||
local target="all"
|
||
local mode=""
|
||
local foreground=false
|
||
local log_target=""
|
||
shift || true
|
||
load_env
|
||
|
||
case "$command" in
|
||
help|-h|--help)
|
||
show_help
|
||
;;
|
||
setup)
|
||
run_setup
|
||
;;
|
||
start)
|
||
target="$(parse_target all "${1:-}")"
|
||
if [ "$target" != "all" ]; then
|
||
shift || true
|
||
fi
|
||
|
||
while [ $# -gt 0 ]; do
|
||
case "$1" in
|
||
--foreground)
|
||
foreground=true
|
||
;;
|
||
--mode)
|
||
shift || die "--mode 需要指定 dev 或 static"
|
||
mode="$1"
|
||
validate_frontend_mode "$mode"
|
||
;;
|
||
*)
|
||
die "未知参数: $1"
|
||
;;
|
||
esac
|
||
shift || true
|
||
done
|
||
|
||
case "$target" in
|
||
all)
|
||
[ "$foreground" = false ] || die "start all 不支持 --foreground,请使用 start api --foreground"
|
||
print_header "AI+合规智能中枢 - 启动服务"
|
||
start_api background
|
||
start_frontend "${mode:-$FRONTEND_MODE}"
|
||
;;
|
||
api)
|
||
if [ "$foreground" = true ]; then
|
||
start_api foreground
|
||
else
|
||
print_header "AI+合规智能中枢 - 启动 API"
|
||
start_api background
|
||
fi
|
||
;;
|
||
frontend)
|
||
print_header "AI+合规智能中枢 - 启动前端"
|
||
start_frontend "${mode:-$FRONTEND_MODE}"
|
||
;;
|
||
esac
|
||
;;
|
||
stop)
|
||
target="$(parse_target all "${1:-}")"
|
||
print_header "AI+合规智能中枢 - 停止服务"
|
||
case "$target" in
|
||
all)
|
||
stop_frontend
|
||
stop_api
|
||
;;
|
||
api)
|
||
stop_api
|
||
;;
|
||
frontend)
|
||
stop_frontend
|
||
;;
|
||
esac
|
||
;;
|
||
restart)
|
||
target="$(parse_target all "${1:-}")"
|
||
if [ "$target" != "all" ]; then
|
||
shift || true
|
||
fi
|
||
while [ $# -gt 0 ]; do
|
||
case "$1" in
|
||
--mode)
|
||
shift || die "--mode 需要指定 dev 或 static"
|
||
mode="$1"
|
||
validate_frontend_mode "$mode"
|
||
;;
|
||
*)
|
||
die "未知参数: $1"
|
||
;;
|
||
esac
|
||
shift || true
|
||
done
|
||
|
||
print_header "AI+合规智能中枢 - 重启服务"
|
||
case "$target" in
|
||
all)
|
||
stop_frontend
|
||
stop_api
|
||
start_api background
|
||
start_frontend "${mode:-$FRONTEND_MODE}"
|
||
;;
|
||
api)
|
||
stop_api
|
||
start_api background
|
||
;;
|
||
frontend)
|
||
stop_frontend
|
||
start_frontend "${mode:-$FRONTEND_MODE}"
|
||
;;
|
||
esac
|
||
;;
|
||
status)
|
||
run_status
|
||
;;
|
||
logs)
|
||
log_target="${1:-}"
|
||
run_logs "$log_target" "${2:-}"
|
||
;;
|
||
*)
|
||
die "未知命令: $command。可使用 ./dev.sh help 查看帮助。"
|
||
;;
|
||
esac
|
||
}
|
||
|
||
main "$@"
|