diff --git a/backend/app/__init__.py b/backend/app/__init__.py index 7efdd83..4778f59 100644 --- a/backend/app/__init__.py +++ b/backend/app/__init__.py @@ -2,7 +2,7 @@ import sys -__version__ = "0.1.40" +__version__ = "0.1.41" # Windows 默认 stdout/stderr 编码为 GBK(cp936),TickFlow SDK 内部输出含 emoji 的 # 指数/标的名称(如 \U0001f193)时会抛 UnicodeEncodeError,导致请求失败。 diff --git a/backend/pyproject.toml b/backend/pyproject.toml index 17607b3..ba458f0 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "tickflow-stock-panel-backend" -version = "0.1.40" +version = "0.1.41" description = "A 股选股 + 监控 + 回测面板 — TickFlow 适配" readme = "../README.md" requires-python = ">=3.11" diff --git a/frontend/package.json b/frontend/package.json index b76ab79..582ed66 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,7 +1,7 @@ { "name": "tickflow-stock-panel-frontend", "private": true, - "version": "0.1.40", + "version": "0.1.41", "type": "module", "scripts": { "dev": "vite", diff --git a/frontend/src/components/Layout.tsx b/frontend/src/components/Layout.tsx index debe33a..0af878b 100644 --- a/frontend/src/components/Layout.tsx +++ b/frontend/src/components/Layout.tsx @@ -1,4 +1,4 @@ -import { useEffect } from 'react' +import { useEffect, useRef, useState } from 'react' import { NavLink, Outlet, useNavigate } from 'react-router-dom' import { useQuery, useQueryClient } from '@tanstack/react-query' import { motion } from 'framer-motion' @@ -26,6 +26,7 @@ import { Key, Database, Timer, + Loader2, LayoutDashboard, Tags, TrendingUp, @@ -36,6 +37,7 @@ import { Landmark, Cable, RadioTower, + CheckCircle2, } from 'lucide-react' import { Logo } from './Logo' import { api, type IndexQuote } from '@/lib/api' @@ -258,6 +260,30 @@ export function Layout() { queryFn: api.analysisMenus, }) + // 数据同步状态轮询: 有活跃 job 时「数据」菜单项显示转圈 + const { data: pipelineJobs } = useQuery({ + queryKey: QK.pipelineJobs, + queryFn: () => api.pipelineJobs(1), + refetchInterval: (query) => (query.state.data?.active_id ? 2000 : 15000), + refetchIntervalInBackground: true, + }) + const isDataSyncing = !!pipelineJobs?.active_id + + // 数据同步完成的"瞬时反馈": isDataSyncing 从 true→false 时显示绿色对勾, + // 闪烁约 3 秒后自动消失。 + const [dataSyncJustDone, setDataSyncJustDone] = useState(false) + const prevSyncingRef = useRef(false) + useEffect(() => { + // 仅在"刚结束"(true→false)且非首次挂载时触发 + if (prevSyncingRef.current && !isDataSyncing) { + setDataSyncJustDone(true) + const t = setTimeout(() => setDataSyncJustDone(false), 3000) + prevSyncingRef.current = isDataSyncing + return () => clearTimeout(t) + } + prevSyncingRef.current = isDataSyncing + }, [isDataSyncing]) + const qc = useQueryClient() const navigate = useNavigate() const version = versionData?.version @@ -392,6 +418,13 @@ export function Layout() { <> {label} + {/* 数据同步状态: 同步中转圈, 刚完成显示绿色对勾闪烁 3 秒 */} + {to === '/data' && isDataSyncing && ( + + )} + {to === '/data' && !isDataSyncing && dataSyncJustDone && ( + + )} {/* 监控中心徽标: 仅非监控页且有未读时显示 */} {to === '/monitor' && }