import { useState, useEffect } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; import { Key, Plus, Trash2, Copy, Check, Shield, Clock, Zap, AlertCircle, RefreshCw, AlertTriangle, Eye, EyeOff } from 'lucide-react'; import { useAuth } from '../context/AuthContext'; import { cn } from '../lib/utils'; export default function Keys() { const { token: adminToken } = useAuth(); const [keys, setKeys] = useState([]); const [isLoading, setIsLoading] = useState(true); const [isGenerating, setIsGenerating] = useState(false); // Form State const [keyName, setKeyName] = useState(''); const [customKey, setCustomKey] = useState(''); const [enableRateLimit, setEnableRateLimit] = useState(false); const [maxRequests, setMaxRequests] = useState(100); const [windowSeconds, setWindowSeconds] = useState(60); const [copiedKey, setCopiedKey] = useState(''); const [message, setMessage] = useState({ type: '', content: '' }); // UI State const [deleteConfirm, setDeleteConfirm] = useState({ isOpen: false, key: null }); const [visibleKeys, setVisibleKeys] = useState(new Set()); const fetchKeys = async () => { setIsLoading(true); try { const res = await fetch('/admin/keys', { headers: { 'X-Admin-Token': adminToken } }); const data = await res.json(); setKeys(data); } catch (error) { console.error('Failed to fetch keys', error); setMessage({ type: 'error', content: '加载密钥失败' }); } finally { setIsLoading(false); } }; useEffect(() => { fetchKeys(); }, [adminToken]); const generateKey = async () => { setIsGenerating(true); try { const body = { name: keyName, key: customKey || undefined, rate_limit: enableRateLimit ? { requests: parseInt(maxRequests), window: parseInt(windowSeconds) } : undefined }; const res = await fetch('/admin/keys/generate', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Admin-Token': adminToken }, body: JSON.stringify(body) }); const data = await res.json(); if (data.key) { setMessage({ type: 'success', content: '密钥生成成功' }); setKeyName(''); setCustomKey(''); setEnableRateLimit(false); fetchKeys(); } else { setMessage({ type: 'error', content: data.error || '生成失败' }); } } catch (error) { setMessage({ type: 'error', content: '请求失败: ' + error.message }); } finally { setIsGenerating(false); } }; const handleDeleteClick = (key) => { setDeleteConfirm({ isOpen: true, key }); }; const confirmDelete = async () => { if (!deleteConfirm.key) return; try { const res = await fetch(`/admin/keys/${deleteConfirm.key}`, { method: 'DELETE', headers: { 'X-Admin-Token': adminToken } }); if (res.ok) { fetchKeys(); setDeleteConfirm({ isOpen: false, key: null }); } } catch (error) { console.error('Delete failed', error); } }; const copyToClipboard = (text) => { navigator.clipboard.writeText(text); setCopiedKey(text); setTimeout(() => setCopiedKey(''), 2000); }; const toggleKeyVisibility = (key) => { setVisibleKeys(prev => { const newSet = new Set(prev); if (newSet.has(key)) { newSet.delete(key); } else { newSet.add(key); } return newSet; }); }; const maskKey = (key) => { if (visibleKeys.has(key)) return key; return key.substring(0, 3) + '•'.repeat(20) + key.substring(key.length - 4); }; return (
{/* Delete Confirmation Modal */} {deleteConfirm.isOpen && (

确认删除密钥?

您确定要删除密钥 {deleteConfirm.key?.substring(0, 8)}... 吗?
此操作无法撤销,相关应用将立即失去访问权限。

)}

密钥管理

生成和管理 API 访问密钥

{/* Generator Card */}

生成新密钥

setKeyName(e.target.value)} placeholder="例如: 我的应用密钥" className="w-full px-4 py-2.5 bg-zinc-50 border border-zinc-200 rounded-lg focus:ring-2 focus:ring-zinc-900/5 focus:border-zinc-900 outline-none transition-all text-sm placeholder:text-zinc-400" />
setCustomKey(e.target.value)} placeholder="留空自动生成" className="w-full pl-10 pr-4 py-2.5 bg-zinc-50 border border-zinc-200 rounded-lg focus:ring-2 focus:ring-zinc-900/5 focus:border-zinc-900 outline-none transition-all font-mono text-sm placeholder:text-zinc-400" />
{enableRateLimit && (
setMaxRequests(e.target.value)} min="1" className="w-full px-3 py-2 bg-white border border-zinc-200 rounded-md text-sm focus:border-zinc-900 outline-none" />
setWindowSeconds(e.target.value)} min="1" className="w-full px-3 py-2 bg-white border border-zinc-200 rounded-md text-sm focus:border-zinc-900 outline-none" />
)}
{message.content && ( {message.content} )}
{/* Keys List */}
密钥列表 {keys.length} ACTIVE
{keys.length === 0 ? (

暂无 API 密钥

请在左侧创建您的第一个密钥

) : (
{keys.map((k) => (

{k.name || '未命名密钥'}

{k.rate_limit ? ( {k.rate_limit.requests}/{k.rate_limit.window}s ) : ( 无限制 )}
{maskKey(k.key)}
创建于: {new Date(k.created).toLocaleString()}
))}
)}
); }