财务分析移除 Expert 套餐能力门控
serve 只读模式,财务数据仅来自 local 同步, 不再依赖 TickFlow Expert 能力。 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -2,8 +2,7 @@ import { useState, useEffect } from 'react'
|
|||||||
import { RefreshCw, Lock, Loader2, X, Search, FileText, Database, CheckCircle2, Hourglass, Lightbulb, ExternalLink } from 'lucide-react'
|
import { RefreshCw, Lock, Loader2, X, Search, FileText, Database, CheckCircle2, Hourglass, Lightbulb, ExternalLink } from 'lucide-react'
|
||||||
import { PageHeader } from '@/components/PageHeader'
|
import { PageHeader } from '@/components/PageHeader'
|
||||||
import { EmptyState } from '@/components/EmptyState'
|
import { EmptyState } from '@/components/EmptyState'
|
||||||
import { useCapabilities } from '@/lib/useSharedQueries'
|
import { useFinancialStatus } from '@/lib/useFinancials'
|
||||||
import { useFinancialStatus, useFinancialSync } from '@/lib/useFinancials'
|
|
||||||
import { StockFinancialSearch } from '@/components/financials/StockFinancialSearch'
|
import { StockFinancialSearch } from '@/components/financials/StockFinancialSearch'
|
||||||
import { StockFinancialDetail } from '@/components/financials/StockFinancialDetail'
|
import { StockFinancialDetail } from '@/components/financials/StockFinancialDetail'
|
||||||
import { ReportHistoryPanel } from '@/components/financials/ReportHistoryPanel'
|
import { ReportHistoryPanel } from '@/components/financials/ReportHistoryPanel'
|
||||||
@@ -27,63 +26,32 @@ const TABLE_ICON: Record<string, typeof FileText> = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function Financials() {
|
export function Financials() {
|
||||||
const { data: caps } = useCapabilities()
|
|
||||||
const hasFinancial = caps?.capabilities?.['financial'] != null
|
|
||||||
const { data: status, isLoading } = useFinancialStatus()
|
const { data: status, isLoading } = useFinancialStatus()
|
||||||
const syncMut = useFinancialSync()
|
|
||||||
// 同步进行中 = 服务端真值(status.syncing)或本地乐观态(请求已发出待确认)。
|
|
||||||
// 乐观窗口:点击后到 invalidate 触发的 refetch 返回之间,status.syncing 暂为 false,
|
|
||||||
// 用 syncMut.isPending 覆盖,让按钮立即置灰、避免重复点击。
|
|
||||||
// 后端 trigger() 返回时 syncing 已为 true,refetch 到达后 status.syncing 接管。
|
|
||||||
const syncing = (status?.syncing ?? false) || syncMut.isPending
|
|
||||||
// 本次同步开始时间戳(ms): 用于判断每张表的 last_sync 是否属于本次同步
|
|
||||||
// (后端每张表完成即更新 last_sync, 前端轮询时对比时间戳得到精确进度)
|
|
||||||
const [syncStartedAt, setSyncStartedAt] = useState<number | null>(null)
|
|
||||||
// 单表同步时记录表名 (null = 全量同步), 用于区分卡片状态
|
|
||||||
const [syncSingleTable, setSyncSingleTable] = useState<string | null>(null)
|
|
||||||
// 同步自然结束(服务端 syncing 由 true→false):清空本次同步记录。
|
|
||||||
// 这是可靠的收尾时机 —— 不依赖 mutation 的 onSettled(它现在瞬间触发,会误清)。
|
|
||||||
useEffect(() => {
|
|
||||||
if (!syncing && syncStartedAt !== null) {
|
|
||||||
setSyncStartedAt(null)
|
|
||||||
setSyncSingleTable(null)
|
|
||||||
}
|
|
||||||
}, [syncing, syncStartedAt])
|
|
||||||
// 选中的个股(模糊搜索结果);null 时显示搜索引导
|
|
||||||
const [selected, setSelected] = useState<{ symbol: string; name: string } | null>(null)
|
|
||||||
const { last: lastStock, remember: rememberStock } = useLastStock('financials')
|
const { last: lastStock, remember: rememberStock } = useLastStock('financials')
|
||||||
|
const [selected, setSelected] = useState<{ symbol: string; name: string } | null>(null)
|
||||||
const pick = (symbol: string, name: string) => {
|
const pick = (symbol: string, name: string) => {
|
||||||
setSelected({ symbol, name })
|
setSelected({ symbol, name })
|
||||||
rememberStock(symbol, name)
|
rememberStock(symbol, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 无 Expert 能力时: 等 status 加载完, 判断是否有从 local 同步来的数据
|
// 等待 status 加载完, 判断是否有从 local 同步来的数据
|
||||||
if (!hasFinancial) {
|
if (isLoading) {
|
||||||
if (isLoading) {
|
return (
|
||||||
return (
|
<>
|
||||||
<>
|
<PageHeader title="财务分析" subtitle="利润表 / 资负表 / 现金流 / 关键指标 / AI分析" />
|
||||||
<PageHeader title="财务分析" subtitle="利润表 / 资负表 / 现金流 / 关键指标 / AI分析 · Expert" />
|
<div className="flex items-center justify-center py-16">
|
||||||
<div className="flex items-center justify-center py-16">
|
<Loader2 className="h-5 w-5 animate-spin text-muted" />
|
||||||
<Loader2 className="h-5 w-5 animate-spin text-muted" />
|
</div>
|
||||||
</div>
|
</>
|
||||||
</>
|
)
|
||||||
)
|
}
|
||||||
}
|
if (!status?.available) {
|
||||||
if (!status?.available) {
|
// 无同步数据
|
||||||
// 既无 Expert 能力, 也无同步数据 → 锁定页
|
return (
|
||||||
return (
|
<>
|
||||||
<>
|
<PageHeader title="财务分析" subtitle="利润表 / 资负表 / 现金流 / 关键指标 / AI分析" />
|
||||||
<PageHeader title="财务分析" subtitle="利润表 / 资负表 / 现金流 / 关键指标 / AI分析 · Expert" />
|
<div className="px-8 py-10">
|
||||||
<div className="px-8 py-10">
|
<div className="mx-auto max-w-md rounded-card border border-warning/30 bg-warning/[0.04] p-8 text-center">
|
||||||
<div className="mx-auto max-w-md rounded-card border border-warning/30 bg-warning/[0.04] p-8 text-center">
|
|
||||||
<div className="mx-auto flex h-12 w-12 items-center justify-center rounded-full bg-warning/10">
|
|
||||||
<Lock className="h-6 w-6 text-warning" />
|
|
||||||
</div>
|
|
||||||
<h3 className="mt-4 text-base font-semibold text-foreground">需要 Expert 套餐</h3>
|
|
||||||
<p className="mt-2 text-xs leading-relaxed text-secondary">
|
|
||||||
财务数据接口仅 Expert 套餐可用。升级后此页自动显示财务数据面板。
|
|
||||||
</p>
|
|
||||||
<div className="mt-5 rounded-btn border border-accent/25 bg-accent/[0.05] px-3.5 py-3 text-left">
|
|
||||||
<div className="flex items-center gap-1.5 text-xs font-medium text-accent">
|
<div className="flex items-center gap-1.5 text-xs font-medium text-accent">
|
||||||
<Lightbulb className="h-3.5 w-3.5 shrink-0" />
|
<Lightbulb className="h-3.5 w-3.5 shrink-0" />
|
||||||
关于数据源
|
关于数据源
|
||||||
|
|||||||
Reference in New Issue
Block a user