From b14ffda1bdf038cd1880529ac6ce2f3389abcbeb Mon Sep 17 00:00:00 2001 From: shy3130 <415333856@qq.com> Date: Mon, 24 Aug 2026 17:14:48 +0800 Subject: [PATCH] =?UTF-8?q?feat(ui):=20=E6=95=B0=E6=8D=AE=E6=BA=90?= =?UTF-8?q?=E8=83=BD=E5=8A=9B=E5=8D=A1=E7=89=87=E6=98=BE=E7=A4=BA=20TickFl?= =?UTF-8?q?ow=20=E8=AE=A2=E9=98=85=E6=A1=A3=E4=BD=8D=E8=A6=81=E6=B1=82?= =?UTF-8?q?=E4=B8=8E=E5=85=A8=E6=A1=A3=E4=BD=8D=E6=A0=87=E8=AF=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 每张能力卡右上角显示该能力所需最低档位(全档位/Starter+/Pro+/Expert+, 配色与左侧菜单档位体系一致, 当前档位不足时琥珀描边提示), 替代原 "当前提供方"徽标(信息已由下方高亮标签承载)。TickFlow 详情头部与 列表卡片在"第三方"后增加 Expert 三色渐变的"已适配全档位"标识。 --- frontend/src/pages/settings/DataSources.tsx | 78 ++++++++++++++++----- 1 file changed, 60 insertions(+), 18 deletions(-) diff --git a/frontend/src/pages/settings/DataSources.tsx b/frontend/src/pages/settings/DataSources.tsx index e90454c..06f90f3 100644 --- a/frontend/src/pages/settings/DataSources.tsx +++ b/frontend/src/pages/settings/DataSources.tsx @@ -4,7 +4,8 @@ import { motion, AnimatePresence } from 'framer-motion' import { Check, Database, Eye, EyeOff, KeyRound, Plus, RefreshCw, Zap, FileWarning, Puzzle, AlertCircle, CheckCircle2, Loader2, Save, Trash2 } from 'lucide-react' import { api, type DataSourceItem, type PluginDataSourceItem } from '@/lib/api' import { QK } from '@/lib/queryKeys' -import { usePreferences } from '@/lib/useSharedQueries' +import { useCapabilities, usePreferences } from '@/lib/useSharedQueries' +import { TIER_RANK, tierRank, tierStyle } from '@/lib/capability-labels' import { toast } from '@/components/Toast' import { DataSourceEditor } from './DataSourceEditor' import { TickFlowKeyConfig } from './Keys' @@ -37,6 +38,50 @@ const DATASET_ROUTE: Record = { + daily: 'none', + adj_factor: 'starter', + realtime: 'starter', + minute: 'pro', + financial: 'expert', +} + +/** TickFlow 档位要求徽标: 按所需档位配色(与左侧菜单/Key 页一致), 当前档位不足时琥珀描边提示 */ +function TierReqChip({ tier, currentLabel }: { tier: string; currentLabel?: string }) { + const text = tier === 'none' ? '全档位' : `${tier}+` + const req = TIER_RANK[tier] ?? -1 + const unmet = currentLabel != null && tierRank(currentLabel) < req + const t = tierStyle(tier) + return ( + + + {text} + + ) +} + +/** TickFlow「已适配全档位」标识: Expert 三色渐变(全档位体系里最醒目的身份色) */ +function AllTiersBadge({ size = 'text-[10px]' }: { size?: string }) { + const t = tierStyle('expert') + return ( + + ✦ 已适配全档位 + + ) +} + /** 卡片内静态数据集标签: 只展示该源适配了哪些数据集 (路由选择在下方能力卡片) */ function DatasetChipRow({ datasets }: { datasets: string[] }) { if (datasets.length === 0) return null @@ -55,7 +100,7 @@ function DatasetChipRow({ datasets }: { datasets: string[] }) { /** 按能力路由网格: 每个数据源详情下展示一张能力卡,卡片上以可点标签列出 * 所有具备该能力的数据源 — 点谁,该数据集就立刻由谁提供,可跨源自由组合。 * TickFlow 详情含全部能力; 其他源只列自己参与的能力。 */ -function SourceCapabilityGrid({ sourceName, sourceDisplay, datasets, candidatesOf, providerOf, displayOf, pending, onSelect, anyCustom, onReset }: { +function SourceCapabilityGrid({ sourceName, sourceDisplay, datasets, candidatesOf, providerOf, pending, onSelect, anyCustom, onReset }: { sourceName: string sourceDisplay: string datasets: string[] @@ -63,7 +108,6 @@ function SourceCapabilityGrid({ sourceName, sourceDisplay, datasets, candidatesO candidatesOf: (dataset: string) => { name: string; display: string }[] /** 该数据集当前的原始路由偏好值 (adj_factor 可能是 same_as_daily) */ providerOf: (dataset: string) => string - displayOf: (name?: string) => string pending?: boolean onSelect: (dataset: string, provider: string) => void anyCustom?: boolean @@ -71,6 +115,7 @@ function SourceCapabilityGrid({ sourceName, sourceDisplay, datasets, candidatesO }) { const isDefault = sourceName === 'tickflow' const dsList = isDefault ? [...datasets, 'financial'] : datasets + const caps = useCapabilities() if (dsList.length === 0) return null return ( @@ -103,10 +148,13 @@ function SourceCapabilityGrid({ sourceName, sourceDisplay, datasets, candidatesO
-
{label}
+
{label}
{desc &&
{desc}
}
- 固定 +
+ {isDefault && } + 固定 +
) @@ -120,15 +168,8 @@ function SourceCapabilityGrid({ sourceName, sourceDisplay, datasets, candidatesO
{label}
{desc &&
{desc}
} - {/* 右上角: 当前提供方 */} - - {displayOf(raw)} - + {/* 右上角: TickFlow 所需档位 (当前提供方由下方高亮标签指示) */} + {isDefault && } {/* 提供方标签: 点谁该数据集就由谁提供,当前项高亮 */}
@@ -626,7 +667,10 @@ export function SettingsDataSourcesPanel() { )} {item.name === 'tickflow' && ( - 第三方 + <> + 第三方 + + )} {pluginNames.has(item.name) && ( 第三方 @@ -785,7 +829,6 @@ export function SettingsDataSourcesPanel() { datasets={selectedCustom?.datasets || []} candidatesOf={routeCtx.candidatesOf} providerOf={routeCtx.providerOf} - displayOf={routeCtx.displayOf} pending={routeCtx.pending} onSelect={routeCtx.onSelect} /> @@ -887,7 +930,6 @@ function PluginDetail({ plugin, isActive, onSwitch, switching, route }: { datasets={plugin.datasets} candidatesOf={route.candidatesOf} providerOf={route.providerOf} - displayOf={route.displayOf} pending={route.pending} onSelect={route.onSelect} /> @@ -935,6 +977,7 @@ function TickFlowDetail({ active, onSwitch, switching, route }: {

TickFlow

第三方 + {active && ( 服务中 @@ -954,7 +997,6 @@ function TickFlowDetail({ active, onSwitch, switching, route }: { datasets={['daily', 'adj_factor', 'realtime', 'minute']} candidatesOf={route.candidatesOf} providerOf={route.providerOf} - displayOf={route.displayOf} pending={route.pending} onSelect={route.onSelect} anyCustom={route.anyCustom}