mirror of
https://ghfast.top/https://github.com/aeroxw/tick-stock-panel.git
synced 2026-09-12 17:54:15 +08:00
feat: 看板刷新按钮改为后端缓存重载
原「刷新」只重新请求前端数据(overview.refetch), 不动后端缓存, 跨天 残留时拿到的是旧数据。改为「重载」: - 新增 POST /api/data/refresh-cache 端点: clear_cache + refresh_cache 重建 enriched 内存缓存, 同时清 overview 聚合缓存 + screener TTL 缓存 - 看板按钮先调后端重建缓存, 再刷新看板数据 - 与设置页「清理并刷新」(清前端 react-query)互补, 这个重建后端 Polars 缓存
This commit is contained in:
@@ -862,3 +862,22 @@ def get_version(request: Request) -> dict:
|
||||
return {"version": v}
|
||||
|
||||
return {"version": "v0.0.0"}
|
||||
|
||||
|
||||
@router.post("/refresh-cache")
|
||||
def refresh_cache(request: Request) -> dict:
|
||||
"""重建 Polars 内存缓存 (clear + refresh), 不清数据、不清 alerts。
|
||||
|
||||
用于跨天后缓存残留、或维表更新后手动刷新场景。
|
||||
与设置页「清理并刷新」的区别: 那个清前端 react-query, 这个重建后端 enriched 缓存。
|
||||
"""
|
||||
repo = request.app.state.repo
|
||||
repo.clear_cache()
|
||||
repo.refresh_cache()
|
||||
# 清除 Overview 总览聚合结果缓存 + Screener 历史 TTL 缓存
|
||||
from app.api.overview import invalidate_overview_cache
|
||||
invalidate_overview_cache()
|
||||
from app.services.screener import ScreenerService
|
||||
ScreenerService.clear_history_cache()
|
||||
logger.info("refresh-cache: Polars 缓存已重建")
|
||||
return {"ok": True}
|
||||
|
||||
@@ -1317,6 +1317,7 @@ export const api = {
|
||||
|
||||
dataStatus: () => request<DataStatus>('/api/data/status'),
|
||||
dataClear: () => request<{ deleted_files: number }>('/api/data/clear', { method: 'POST' }),
|
||||
refreshCache: () => request<{ ok: boolean }>('/api/data/refresh-cache', { method: 'POST' }),
|
||||
enrichedSchema: (table: string) => request<EnrichedField[]>(`/api/data/schema/${table}`),
|
||||
|
||||
testEndpoint: (url: string, rounds?: number) =>
|
||||
|
||||
@@ -573,10 +573,14 @@ export function Dashboard() {
|
||||
}).catch(() => { /* 查询失败不阻塞, 用户仍可手动点击获取 */ })
|
||||
}, [hasNoData, fetchJobId])
|
||||
|
||||
// 手动刷新: 显示旋转动画; SSE 自动刷新: 静默, 无体感
|
||||
// 手动刷新: 先重建后端 Polars 缓存(解决跨天残留), 再重新拉看板数据
|
||||
const handleRefresh = () => {
|
||||
setManualFetching(true)
|
||||
overview.refetch().finally(() => setManualFetching(false))
|
||||
api.refreshCache()
|
||||
.then(() => qc.invalidateQueries({ queryKey: ['overview-market'] }))
|
||||
.finally(() => {
|
||||
overview.refetch().finally(() => setManualFetching(false))
|
||||
})
|
||||
}
|
||||
|
||||
if (overview.isLoading && !data) {
|
||||
@@ -671,7 +675,7 @@ export function Dashboard() {
|
||||
disabled={manualFetching}
|
||||
className="inline-flex items-center gap-1 rounded-btn border border-border bg-elevated px-2 py-1 text-[11px] text-secondary transition-colors hover:text-foreground disabled:opacity-50"
|
||||
>
|
||||
<RefreshCw className={`h-3 w-3 ${manualFetching ? 'animate-spin' : ''}`} />刷新
|
||||
<RefreshCw className={`h-3 w-3 ${manualFetching ? 'animate-spin' : ''}`} />重载
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user