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 (
您确定要删除密钥 {deleteConfirm.key?.substring(0, 8)}... 吗?
此操作无法撤销,相关应用将立即失去访问权限。
生成和管理 API 访问密钥
暂无 API 密钥
请在左侧创建您的第一个密钥
{maskKey(k.key)}