'use client'; import { useState, useEffect } from 'react'; import { useConfig, testConfig, useDataSourcesConfig, updateDataSourcesConfig } from '@/hooks/useApi'; import { useConfigStore } from '@/stores/useConfigStore'; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Button } from "@/components/ui/button"; import type { DataSourcesConfig, DataSourceProvider } from '@/types'; import { AIConfigTab } from './components/AIConfigTab'; import { DataSourcesConfigTab } from './components/DataSourcesConfigTab'; import { AnalysisConfigTab } from './components/AnalysisConfigTab'; import { SystemConfigTab } from './components/SystemConfigTab'; const defaultUrls: Partial> = { tushare: 'http://api.tushare.pro', finnhub: 'https://finnhub.io/api/v1', alphavantage: 'https://mcp.alphavantage.co/mcp', }; export default function ConfigPage() { // 从 Zustand store 获取全局状态 const { config, loading, error, setConfig } = useConfigStore(); // 使用 SWR hook 加载初始配置 useConfig(); // 本地表单状态 // 数据源本地状态 const { data: initialDataSources, error: dsError, isLoading: dsLoading, mutate: mutateDataSources } = useDataSourcesConfig(); const [localDataSources, setLocalDataSources] = useState({}); // 测试结果状态 const [testResults, setTestResults] = useState>({}); // 保存状态 const [saving, setSaving] = useState(false); const [saveMessage, setSaveMessage] = useState(''); // Shared state for AI Tab (needed for System Tab's import feature) const [newProviderBaseUrl, setNewProviderBaseUrl] = useState(''); useEffect(() => { if (initialDataSources) { setLocalDataSources(initialDataSources); } }, [initialDataSources]); const handleSave = async () => { setSaving(true); setSaveMessage('保存中...'); try { if (initialDataSources) { // Create a deep copy to avoid mutating the local state directly const finalDataSources = JSON.parse(JSON.stringify(localDataSources)); for (const key in finalDataSources) { const providerKey = key as DataSourceProvider; const source = finalDataSources[providerKey]; // If the URL is empty or null, and there is a default URL, use it if (source && (source.api_url === null || source.api_url.trim() === '') && defaultUrls[providerKey]) { source.api_url = defaultUrls[providerKey]; } } await updateDataSourcesConfig(finalDataSources); // After saving, mutate the local SWR cache with the final data // and also update the component's local state to reflect the change. await mutateDataSources(finalDataSources, false); setLocalDataSources(finalDataSources); } setSaveMessage('保存成功!'); } catch (e: any) { setSaveMessage(`保存失败: ${e.message}`); } finally { setSaving(false); setTimeout(() => setSaveMessage(''), 5000); } }; const handleTest = async (type: string, data: any) => { try { const result = await testConfig(type, data); const success = !!result?.success; const summary = typeof result?.message === 'string' && result.message.trim().length > 0 ? result.message : (success ? '测试成功' : '测试失败'); setTestResults(prev => ({ ...prev, [type]: { success, summary } })); } catch (e: any) { // 结构化错误对象:{ summary, details? } const summary: string = (e && typeof e === 'object' && 'summary' in e) ? String(e.summary) : (e?.message || '未知错误'); const details: string | undefined = (e && typeof e === 'object' && 'details' in e) ? (e.details ? String(e.details) : undefined) : undefined; setTestResults(prev => ({ ...prev, [type]: { success: false, summary, details } })); } }; const handleTestTushare = () => { const cfg = localDataSources['tushare']; handleTest('tushare', { api_key: cfg?.api_key, api_url: cfg?.api_url, enabled: cfg?.enabled }); }; const handleTestFinnhub = () => { const cfg = localDataSources['finnhub']; handleTest('finnhub', { api_key: cfg?.api_key, api_url: cfg?.api_url, enabled: cfg?.enabled }); }; const handleTestAlphaVantage = () => { const cfg = localDataSources['alphavantage']; handleTest('alphavantage', { api_key: cfg?.api_key, api_url: cfg?.api_url, enabled: cfg?.enabled }); }; const handleReset = () => { if (initialDataSources) setLocalDataSources(initialDataSources); setTestResults({}); setSaveMessage(''); }; if (loading) return (

加载配置中...

); if (error) return (
⚠️

加载配置失败: {error}

); return (

配置中心

管理系统配置,包括 AI 服务与数据源等。敏感信息不回显,留空表示保持当前值。

AI服务 数据源 分析配置 系统
{saveMessage && ( {saveMessage} )}
最后更新: {new Date().toLocaleString()}
); }