From bb2be17ae215da9b12c4784213bca429609de5c5 Mon Sep 17 00:00:00 2001 From: Sakurasan <26715255+Sakurasan@users.noreply.github.com> Date: Tue, 18 Aug 2026 04:14:17 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=83=AD=E7=82=B9=E7=A9=BF=E9=80=8F?= =?UTF-8?q?=E9=A2=98=E6=9D=90=E6=95=B0=E4=BB=8E50=E6=8F=90=E5=8D=87?= =?UTF-8?q?=E5=88=B0100=EF=BC=8C=E6=94=AF=E6=8C=81=E7=BC=93=E5=AD=98?= =?UTF-8?q?=E5=AE=9A=E5=90=91=E6=B8=85=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 热点穿透top由50提升到100(涨幅榜+热度榜各取前100合并),保证题材数≥100 - themes.py graph路由top上限le由60放宽到200 - daily_collector HOTMAP_TOP_N同步到100与页面一致 - auvops.sh新增cache-clear-graph子命令定向清理theme_graph缓存 --- backend/auvops.sh | 18 ++++++++++++++++++ backend/routes/themes.py | 2 +- backend/services/daily_collector.py | 2 +- backend/services/themes.py | 4 ++-- src/routes/hot-map.tsx | 2 +- 5 files changed, 23 insertions(+), 5 deletions(-) diff --git a/backend/auvops.sh b/backend/auvops.sh index a0be088..f643ddf 100755 --- a/backend/auvops.sh +++ b/backend/auvops.sh @@ -6,6 +6,7 @@ # # 用法(容器内): # ./auvops.sh cache-clear # 清空全部缓存(当日数据全新) +# ./auvops.sh cache-clear-graph # 只清空热点穿透(theme_graph)缓存 # ./auvops.sh clean-expired # 只清理已过期的缓存 # ./auvops.sh cache-count # 查看缓存条数 # ./auvops.sh recollect [DATE] # 删除并重采指定交易日(默认当天) @@ -57,6 +58,22 @@ EOF echo "✅ 缓存已清空" } +# 仅清空热点穿透(theme_graph)缓存:改写 top/排序后旧图数据过期,删掉让下次请求重建 +cmd_cache_clear_graph() { + echo "① 清空热点穿透(theme_graph)缓存" + "${PY}" - <<'EOF' +from database import get_connection +conn = get_connection() +try: + cur = conn.execute("DELETE FROM cache WHERE key LIKE 'theme_graph:%'") + conn.commit() + print(f" 已删除 {cur.rowcount} 条 theme_graph 缓存") +finally: + conn.close() +EOF + echo "✅ 热点穿透缓存已清空" +} + # 只清理已过期缓存 cmd_clean_expired() { echo "① 清理过期缓存" @@ -138,6 +155,7 @@ main() { local cmd="$1"; shift case "${cmd}" in cache-clear|cc) cmd_cache_clear "$@" ;; + cache-clear-graph) cmd_cache_clear_graph "$@" ;; clean-expired) cmd_clean_expired "$@" ;; cache-count) cmd_cache_count "$@" ;; recollect) cmd_recollect "$@" ;; diff --git a/backend/routes/themes.py b/backend/routes/themes.py index 952b67a..08551c8 100644 --- a/backend/routes/themes.py +++ b/backend/routes/themes.py @@ -29,7 +29,7 @@ async def theme_list( @router.get("/graph", summary="热点穿透:题材-股票网状关系图") async def theme_graph( sort_field: int = Query(1, description="题材排序:1=涨幅 4=热度"), - top: int = Query(30, ge=1, le=60, description="题材数量"), + top: int = Query(30, ge=1, le=200, description="题材数量"), limit: int = Query(1000, ge=100, le=2000, description="下发的股票节点上限(按穿透度取前 N 只)"), ): if sort_field not in (1, 4): diff --git a/backend/services/daily_collector.py b/backend/services/daily_collector.py index 926547c..6aed654 100644 --- a/backend/services/daily_collector.py +++ b/backend/services/daily_collector.py @@ -19,7 +19,7 @@ CHECK_INTERVAL_SECONDS = 300 COLLECT_AFTER_TIME = dtime(15, 1) # 收盘后 15:01 开始允许采集(留 1 分钟等收盘数据稳定) CORE_STOCK_LIMIT = 100 # 题材领涨股涨幅前100 TOP_THEME_LIMIT = 20 # 题材涨幅前20 -HOTMAP_TOP_N = 50 # 热点穿透采样题材数:涨幅榜+热度榜各取前50,合并(与热点穿透页一致) +HOTMAP_TOP_N = 100 # 热点穿透采样题材数:涨幅榜+热度榜各取前100,合并(与热点穿透页一致) HOTMAP_CORE_LIMIT = 100 # 热点穿透核心股前100(按覆盖题材数降序) CORE_COVER_THRESHOLD = 2 # 热点穿透核心股门槛:覆盖题材数 ≥2 diff --git a/backend/services/themes.py b/backend/services/themes.py index df6b8bb..a11aaad 100644 --- a/backend/services/themes.py +++ b/backend/services/themes.py @@ -308,7 +308,7 @@ async def _build_theme_graph(sort_field: int, top_n: int) -> dict: Args: sort_field: 题材排序 1=涨幅, 4=热度(当前榜在前,另一榜合并补充) - top_n: 每个榜单的题材数量(1-60) + top_n: 每个榜单的题材数量(1-200) Returns: { @@ -422,7 +422,7 @@ async def fetch_theme_graph(sort_field: int = 1, top_n: int = 30, limit: int = 1 Args: sort_field: 题材排序 1=涨幅, 4=热度 - top_n: 每个榜单的题材数量(1-60) + top_n: 每个榜单的题材数量(1-200) limit: 下发 stocks 上限(穿透度最高的 N 只) """ cache_key = f"theme_graph:{sort_field}:{top_n}" diff --git a/src/routes/hot-map.tsx b/src/routes/hot-map.tsx index c75000b..fad026d 100644 --- a/src/routes/hot-map.tsx +++ b/src/routes/hot-map.tsx @@ -52,7 +52,7 @@ function HotMapPage() { const { data: graph, isLoading, isFetching, isError, refetch } = useQuery({ queryKey: ["themeGraph", mode], - queryFn: () => fetchThemeGraph(mode, 50), + queryFn: () => fetchThemeGraph(mode, 100), staleTime: 60_000, retry: false, });