Files
tick-stock-panel/dev.sh
T
shy3130 b5780b5e30 feat: 统一监控引擎 + AlertToast通知 + 声音/角标/看板/Dev页 + 股票名称批量查询
监控引擎 (backend):
- MonitorRuleEngine 统一规则引擎,支持策略/信号/价格/行情四种类型
- JSONL 追加存储 (alert_store.py),支持分页 + 清理
- alert/monitor_rules CRUD API + seed 演示数据
- POST /api/kline/instruments/names 批量股票名称查询
- SSE strategy_alert 事件触发前端通知

前端通知体系:
- AlertToast 自定义弹窗 (Framer Motion + AnimatePresence)
- Web Audio API 合成音效 (12种预设,无需音频文件)
- 侧边栏角标 (monitorBadge.ts) localStorage 持久化未读数
- pendingSeen 机制解决 markSeen/setCurrentTotal 竞态
- 系统设置页: 通知开关 + 最大条数 + 音效选择
- 菜单设置页: 角标数字开关

监控中心 (Monitor.tsx):
- 双栏布局: 左侧实时告警列表 + 右侧规则管理
- RulesList 股票代码后显示中文名称
- RuleEditor 完整规则编辑器组件
- 告警支持查看详情 (StockPreviewDialog)

Dashboard:
- MonitorWidget: Top 10 实时告警卡片

Dev 页面:
- 一键填充演示告警 + 规则 + 分钟探测
- 可视化 SSE 事件流查看

其他:
- v0.1.19 → v0.1.28 (VERSION 从 pyproject.toml 读取)
- dev.ps1/dev.sh 添加 --host 0.0.0.0 (局域网访问)
- 修复 Screener.tsx presets.length 可选链
- README 截图表格更新 (6张) + 监控章节重写
- 删除 MinuteDataProbe 页面 (合并至 Dev)
2026-06-21 14:18:08 +08:00

143 lines
4.3 KiB
Bash
Executable File

#!/usr/bin/env bash
# tickflow-stock-panel — 一键启动前后端
#
# 用法:
# ./dev.sh # 默认 backend:3018 frontend:3011
# BACKEND_PORT=8000 ./dev.sh # 改后端端口
# FRONTEND_PORT=5173 ./dev.sh # 改前端端口
#
# Ctrl-C 同时关闭两端。
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
BACKEND_DIR="$ROOT/backend"
FRONTEND_DIR="$ROOT/frontend"
BACKEND_PORT="${BACKEND_PORT:-3018}"
FRONTEND_PORT="${FRONTEND_PORT:-3011}"
BLUE='\033[0;34m'
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[0;33m'
GRAY='\033[0;90m'
NC='\033[0m'
info() { echo -e "${GRAY}[dev]${NC} $*"; }
ok() { echo -e "${GREEN}[dev]${NC} $*"; }
warn() { echo -e "${YELLOW}[dev]${NC} $*"; }
err() { echo -e "${RED}[dev]${NC} $*" >&2; }
# ===== 1. 依赖检查 =====
require_cmd() {
local cmd="$1" hint="$2"
if ! command -v "$cmd" >/dev/null 2>&1; then
err "$cmd 未安装"
echo " 安装方式:$hint"
exit 1
fi
}
require_cmd uv "curl -LsSf https://astral.sh/uv/install.sh | sh"
require_cmd pnpm "npm i -g pnpm 或 corepack enable && corepack prepare pnpm@9 --activate"
# ===== 2. 端口占用检查 —— 占用就直接 kill =====
free_port() {
local name="$1" port="$2"
local pids
pids=$(lsof -nP -tiTCP:"$port" -sTCP:LISTEN 2>/dev/null || true)
if [ -z "$pids" ]; then
return 0
fi
warn "端口 $port($name)被占用,kill 现有进程 PID: $(echo "$pids" | xargs)"
# 先 TERM
echo "$pids" | xargs kill 2>/dev/null || true
sleep 1
# 还活着就 KILL
pids=$(lsof -nP -tiTCP:"$port" -sTCP:LISTEN 2>/dev/null || true)
if [ -n "$pids" ]; then
warn "TERM 没杀掉,改用 KILL -9"
echo "$pids" | xargs kill -9 2>/dev/null || true
sleep 1
fi
# 再确认一次
pids=$(lsof -nP -tiTCP:"$port" -sTCP:LISTEN 2>/dev/null || true)
if [ -n "$pids" ]; then
err "端口 $port 仍被占用 — kill 失败。请手动处理:lsof -i :$port"
exit 1
fi
ok "端口 $port 已释放"
}
free_port backend "$BACKEND_PORT"
free_port frontend "$FRONTEND_PORT"
# ===== 3. 首次依赖安装 =====
if [ ! -d "$BACKEND_DIR/.venv" ]; then
info "后端首次启动 — 安装 Python 依赖(约 1-2 分钟)..."
( cd "$BACKEND_DIR" && uv sync )
ok "后端依赖装好了"
fi
if [ ! -d "$FRONTEND_DIR/node_modules" ]; then
info "前端首次启动 — 安装 Node 依赖..."
( cd "$FRONTEND_DIR" && pnpm install )
ok "前端依赖装好了"
fi
# ===== 4. 启动 + 日志前缀 =====
PIDS=()
cleanup() {
echo
info "关闭服务..."
for pid in "${PIDS[@]:-}"; do
if [ -n "$pid" ]; then
kill "$pid" 2>/dev/null || true
fi
done
# 等子进程退出,避免孤儿
wait 2>/dev/null || true
ok "已退出"
exit 0
}
trap cleanup INT TERM
# 用 awk 加前缀(macOS sed 没有 -u line-buffered,改用 awk + fflush 兼容)
prefix_awk() {
awk -v p="$1" '{ print p $0; fflush() }'
}
echo
echo -e "${BLUE}╭──────────────────────────────────────────────╮${NC}"
echo -e "${BLUE}${NC} ${GREEN}tickflow-stock-panel${NC} ${BLUE}${NC}"
echo -e "${BLUE}${NC} ${BLUE}${NC}"
echo -e "${BLUE}${NC} backend ${YELLOW}http://localhost:$BACKEND_PORT${NC} ${BLUE}${NC}"
echo -e "${BLUE}${NC} frontend ${YELLOW}http://localhost:$FRONTEND_PORT${NC} ${BLUE}${NC}"
echo -e "${BLUE}${NC} ${BLUE}${NC}"
echo -e "${BLUE}${NC} Ctrl-C 同时关闭两端 ${BLUE}${NC}"
echo -e "${BLUE}╰──────────────────────────────────────────────╯${NC}"
echo
(
cd "$BACKEND_DIR"
uv run uvicorn app.main:app --reload --host 0.0.0.0 --port "$BACKEND_PORT" 2>&1 \
| prefix_awk "$(printf "${BLUE}[backend ]${NC} ")"
) &
PIDS+=("$!")
(
cd "$FRONTEND_DIR"
pnpm dev --host 0.0.0.0 --port "$FRONTEND_PORT" 2>&1 \
| prefix_awk "$(printf "${GREEN}[frontend]${NC} ")"
) &
PIDS+=("$!")
# 等任一退出(bash 4.3+)或全部退出(老 bash)
if wait -n 2>/dev/null; then
warn "其中一个进程退出,正在关闭另一个..."
cleanup
else
# 老 bash 没有 wait -n,退化为 wait 全部
wait
fi