/** * 开放平台页面 * * 提供API Key管理、调用统计和费用明细功能 * 需求: 6.1, 6.2, 6.3, 7, 11, 12 */ import React, { useState, useEffect } from 'react'; import { Key, BarChart3, FileText, Plus, Copy, Eye, EyeOff, Trash2, Power, Loader2, CheckCircle2 } from 'lucide-react'; import { platformApi, ApiKey, ApiKeyCreateResponse, Stats, CallLog, PaginatedResponse, API_BASE_FULL } from '../services/platformApi'; import { useToast, useConfirm } from '../contexts/NotificationContext'; import { copyToClipboard } from '../utils/clipboard'; type TabType = 'api-keys' | 'logs'; const OpenPlatform: React.FC = () => { const { showToast } = useToast(); const { showConfirm } = useConfirm(); const [activeTab, setActiveTab] = useState('api-keys'); const [apiKeys, setApiKeys] = useState([]); const [localKeys, setLocalKeys] = useState([]); const [stats, setStats] = useState(null); const [logs, setLogs] = useState | null>(null); const [loading, setLoading] = useState(false); const [statsLoading, setStatsLoading] = useState(false); const [newKeyName, setNewKeyName] = useState(''); const [newKeyType, setNewKeyType] = useState<'public' | 'local'>('public'); const [showCreateModal, setShowCreateModal] = useState(false); const [newlyCreatedKey, setNewlyCreatedKey] = useState(null); const [copiedKeyId, setCopiedKeyId] = useState(null); const [logsPage, setLogsPage] = useState(1); const [activeKeyType, setActiveKeyType] = useState<'public' | 'local'>('public'); useEffect(() => { if (activeTab === 'api-keys') { loadApiKeys(); } else if (activeTab === 'logs') { loadStats(); loadLogs(); } }, [activeTab, logsPage, activeKeyType]); const loadApiKeys = async () => { setLoading(true); try { const keys = await platformApi.getApiKeys(); setApiKeys(keys.filter(key => key.key_type !== 'local')); setLocalKeys(keys.filter(key => key.key_type === 'local')); } catch (error) { console.error('加载API Key失败:', error); } finally { setLoading(false); } }; const loadStats = async () => { setStatsLoading(true); try { const data = await platformApi.getStats(7, activeKeyType); setStats(data); } catch (error) { console.error('加载统计数据失败:', error); } finally { setStatsLoading(false); } }; const loadLogs = async () => { setLoading(true); try { const data = await platformApi.getCallLogs({ page: logsPage, page_size: 20, key_type: activeKeyType }); setLogs(data); } catch (error) { console.error('加载调用日志失败:', error); } finally { setLoading(false); } }; const handleCreateKey = async () => { try { const result = await platformApi.createApiKey(newKeyName || undefined, newKeyType); setNewlyCreatedKey(result); setNewKeyName(''); setNewKeyType('public'); loadApiKeys(); } catch (error: any) { showToast('创建失败,请稍后重试', 'error'); } }; const handleToggleStatus = async (key: ApiKey) => { try { await platformApi.updateApiKeyStatus(key.id, key.status === 'active' ? 'disabled' : 'active'); await loadApiKeys(); showToast(key.status === 'active' ? '已禁用' : '已启用', 'success'); } catch (error: any) { console.error('更新状态失败:', error); showToast(error.message || '操作失败,请稍后重试', 'error'); } }; const handleDeleteKey = async (id: number) => { const confirmed = await showConfirm({ title: '删除确认', message: '确定要删除此API Key吗?删除后将无法恢复。', confirmText: '删除', cancelText: '取消', danger: true }); if (!confirmed) return; try { await platformApi.deleteApiKey(id); await loadApiKeys(); showToast('删除成功', 'success'); } catch (error: any) { console.error('删除失败:', error); showToast(error.message || '删除失败,请稍后重试', 'error'); } }; const handleCopy = async (text: string, keyId: number) => { await copyToClipboard(text); setCopiedKeyId(keyId); setTimeout(() => setCopiedKeyId(null), 2000); }; const tabs = [ { id: 'api-keys' as TabType, label: 'API Key管理', icon: Key }, { id: 'logs' as TabType, label: '调用统计', icon: BarChart3 }, ]; return (

开放平台

管理API Key,查看调用统计

{/* 标签页 */}
{tabs.map((tab) => ( ))}
{/* API Key管理 */} {activeTab === 'api-keys' && (
{loading ? (
) : (activeKeyType === 'public' ? apiKeys.length === 0 : localKeys.length === 0) ? (

暂无{activeKeyType === 'public' ? '公钥' : '本地私钥'},点击上方按钮创建

) : (
{(activeKeyType === 'public' ? apiKeys : localKeys).map((key) => ( ))}
名称 API Key Base URL 状态 创建时间 操作
{key.name || '未命名'} {key.api_key_prefix}... {API_BASE_FULL || '-'} {key.status === 'active' ? '启用' : '禁用'} {new Date(key.created_at).toLocaleDateString()}
)}
)} {/* 调用统计与费用明细 */} {activeTab === 'logs' && (
{/* 密钥类型切换 */}
{/* 统计卡片 */} {statsLoading ? (
) : stats ? ( <>

今日调用

{stats.today_calls}

本月调用

{stats.month_calls}

总调用

{stats.total_calls}

{stats.model_distribution.length > 0 && (

模型调用分布

{stats.model_distribution.map((item, index) => (
{item.model_name}
{item.count}次 ({item.percentage}%)
))}
)} ) : null} {/* 调用明细表格 */}

调用明细

{loading ? (
) : logs && logs.items.length > 0 ? ( <>
{logs.items.map((log) => ( ))}
时间 模型 输入Token 输出Token API Key 状态
{new Date(log.created_at).toLocaleString()}
{log.model_name.startsWith('local_') ? log.model_name.split('_').slice(2).join('_') : log.model_name} {log.is_local && ( 本地 )}
{log.input_tokens} {log.output_tokens} {log.api_key_prefix} {log.status === 'success' ? '成功' : '失败'}
{logs.total_pages > 1 && (
{logsPage} / {logs.total_pages}
)} ) : (

暂无调用记录

)}
)} {/* 创建API Key模态框 */} {showCreateModal && (

创建API Key

setNewKeyName(e.target.value)} placeholder="API Key名称(可选)" className="w-full px-4 py-2 border border-gray-200 rounded-lg focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 outline-none" />
)} {/* 显示新创建的API Key */} {newlyCreatedKey && (

API Key创建成功

请立即复制保存,此密钥仅显示一次!

{newlyCreatedKey.api_key}
)}
); }; export default OpenPlatform;