From 322571382609f29e2571d5913fdcb51a1ac7b5bc Mon Sep 17 00:00:00 2001 From: shy3130 <415333856@qq.com> Date: Sun, 30 Aug 2026 19:05:45 +0800 Subject: [PATCH] =?UTF-8?q?feat(onboarding):=20=E5=BC=95=E5=AF=BC=E9=A1=B5?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=A1=AB=E5=86=99=20TickFlow=20API=20Key?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 数据源卡片网格下新增入口「为 TickFlow 填写 API Key(可选)」, 复用内联 Key 表单(TICKFLOW_API_KEY, 密码框自动聚焦) - 文案区分: 留空=免费 None 模式可直接用, 填 Key 按档位解锁更多数据集; TickFlow 不自动切换数据源(与插件不同, Key 与选源正交) - 走 /tickflow-key 先探后存: 浏览器实测假 Key 返回「Key 无效或已过期」 且 secrets.json 未落盘 --- frontend/src/pages/Onboarding.tsx | 58 +++++++++++++++++++++++-------- 1 file changed, 44 insertions(+), 14 deletions(-) diff --git a/frontend/src/pages/Onboarding.tsx b/frontend/src/pages/Onboarding.tsx index 1994e0e..3ae1d5f 100644 --- a/frontend/src/pages/Onboarding.tsx +++ b/frontend/src/pages/Onboarding.tsx @@ -350,18 +350,27 @@ function DataSourceStep({ onNext, onBack }: { onNext: () => void; onBack: () => switchProvider.mutate(name) } - // 内联 Key 配置 (先探后存): 验证通过才落盘 secrets.json, 成功即自动选用该源 - const keyPlugin = keyFor ? plugins.find(p => p.name === keyFor) : undefined - const saveKey = useMutation({ - mutationFn: (name: string) => api.savePluginKey(name, keyInput.trim()), - onSuccess: (data, name) => { + // 内联 Key 配置 (先探后存): 验证通过才落盘, 插件成功即自动选用该源 + // tickflow 走独立端点: 填 Key 解锁更高档位, 不改变数据源选择 + const TICKFLOW_KEY_META = { + name: 'tickflow', display_name: 'TickFlow', api_key_env: 'TICKFLOW_API_KEY', + homepage: 'https://tickflow.org/auth/register?ref=V3KDKGXPEA', + } + const keyPlugin = keyFor + ? (plugins.find(p => p.name === keyFor) ?? (keyFor === 'tickflow' ? TICKFLOW_KEY_META : undefined)) + : undefined + const saveKey = useMutation({ + mutationFn: (name: string) => (name === 'tickflow' + ? api.saveTickflowKey(keyInput.trim()) + : api.savePluginKey(name, keyInput.trim())), + onSuccess: (data: any, name) => { qc.invalidateQueries({ queryKey: QK.dataSources }) qc.invalidateQueries({ queryKey: QK.capabilities }) if (data.ok) { setKeyFor(null) setKeyInput('') setKeyError(null) - if (data.plugin_available) { + if (name !== 'tickflow' && data.plugin_available) { setPicked(name) switchProvider.mutate(name) } @@ -480,6 +489,18 @@ function DataSourceStep({ onNext, onBack }: { onNext: () => void; onBack: () => )} + {/* TickFlow Key 入口: 不改变数据源选择, 仅解锁更高档位 */} + {!keyFor && ( + + )} + {/* 插件化提示: 标识数据源体系已插件化, 并给出两条接入路径与文档指引 */}
@@ -504,7 +525,7 @@ function DataSourceStep({ onNext, onBack }: { onNext: () => void; onBack: () =>
)} - {/* 内联 Key 配置 (缺 Key 型插件, 如 fuyao): 先探后存, 成功即自动选用 */} + {/* 内联 Key 配置 (缺 Key 型插件如 fuyao / TickFlow 档位 Key): 先探后存 */} {keyFor && keyPlugin && (
@@ -515,16 +536,25 @@ function DataSourceStep({ onNext, onBack }: { onNext: () => void; onBack: () => {keyPlugin.api_key_env}

- {keyPlugin.homepage ? ( + {keyFor === 'tickflow' ? ( <> - 在{' '} - - 官网 - - {' '}申请 Key;仅存本地 (secrets.json),先验证后保存。保存成功后将自动选用该数据源。 + 留空即免费 None 模式,可直接使用;填写 Key 后按订阅档位解锁实时 / 分钟 / 盘口 / 财务等更多数据集。 + 仅存本地 (secrets.json),先验证后保存。 ) : ( - '向数据源官方申请 Key;仅存本地 (secrets.json),先验证后保存,成功后自动选用该数据源。' + <> + {keyPlugin.homepage ? ( + <> + 在{' '} + + 官网 + + {' '}申请 Key;仅存本地 (secrets.json),先验证后保存。保存成功后将自动选用该数据源。 + + ) : ( + '向数据源官方申请 Key;仅存本地 (secrets.json),先验证后保存,成功后自动选用该数据源。' + )} + )}