"use client" import { useState, useEffect } from "react" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { Key, Plus, Loader2, Copy, Trash2, ChevronDown, ChevronUp } from "lucide-react" import { useToast } from "@/components/ui/use-toast" import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger, DialogFooter, DialogDescription, DialogClose, } from "@/components/ui/dialog" import { Switch } from "@/components/ui/switch" import { Label } from "@/components/ui/label" import { useCopy } from "@/hooks/use-copy" import { useRolePermission } from "@/hooks/use-role-permission" import { PERMISSIONS } from "@/lib/permissions" import { useConfig } from "@/hooks/use-config" type ApiKey = { id: string name: string key: string createdAt: string expiresAt: string | null enabled: boolean } export function ApiKeyPanel() { const [apiKeys, setApiKeys] = useState([]) const [loading, setLoading] = useState(false) const [createDialogOpen, setCreateDialogOpen] = useState(false) const [newKeyName, setNewKeyName] = useState("") const [newKey, setNewKey] = useState(null) const { toast } = useToast() const { copyToClipboard } = useCopy() const [showExamples, setShowExamples] = useState(false) const [isLoading, setIsLoading] = useState(true) const { checkPermission } = useRolePermission() const canManageApiKey = checkPermission(PERMISSIONS.MANAGE_API_KEY) const fetchApiKeys = async () => { try { const res = await fetch("/api/api-keys") if (!res.ok) throw new Error("获取 API Keys 失败") const data = await res.json() as { apiKeys: ApiKey[] } setApiKeys(data.apiKeys) } catch (error) { console.error(error) toast({ title: "获取失败", description: "获取 API Keys 列表失败", variant: "destructive" }) } finally { setIsLoading(false) } } useEffect(() => { if (canManageApiKey) { fetchApiKeys() } }, [canManageApiKey]) const { config } = useConfig() const createApiKey = async () => { if (!newKeyName.trim()) return setLoading(true) try { const res = await fetch("/api/api-keys", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ name: newKeyName }) }) if (!res.ok) throw new Error("创建 API Key 失败") const data = await res.json() as { key: string } setNewKey(data.key) fetchApiKeys() } catch (error) { toast({ title: "创建失败", description: error instanceof Error ? error.message : "请稍后重试", variant: "destructive" }) setCreateDialogOpen(false) } finally { setLoading(false) } } const handleDialogClose = () => { setCreateDialogOpen(false) setNewKeyName("") setNewKey(null) } const toggleApiKey = async (id: string, enabled: boolean) => { try { const res = await fetch(`/api/api-keys/${id}`, { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ enabled }) }) if (!res.ok) throw new Error("更新失败") setApiKeys(keys => keys.map(key => key.id === id ? { ...key, enabled } : key ) ) } catch (error) { console.error(error) toast({ title: "更新失败", description: "更新 API Key 状态失败", variant: "destructive" }) } } const deleteApiKey = async (id: string) => { try { const res = await fetch(`/api/api-keys/${id}`, { method: "DELETE" }) if (!res.ok) throw new Error("删除失败") setApiKeys(keys => keys.filter(key => key.id !== id)) toast({ title: "删除成功", description: "API Key 已删除" }) } catch (error) { console.error(error) toast({ title: "删除失败", description: "删除 API Key 失败", variant: "destructive" }) } } return (

API Keys

{ canManageApiKey && ( {newKey ? "API Key 创建成功" : "创建新的 API Key"} {newKey && ( 请立即保存此密钥,它只会显示一次且无法恢复 )} {!newKey ? (
setNewKeyName(e.target.value)} placeholder="为你的 API Key 起个名字" />
) : (
)} {!newKey && ( )}
) }
{ !canManageApiKey ? (

需要公爵或更高权限才能管理 API Key

请联系网站管理员升级您的角色

{ config?.adminContact && (

管理员联系方式:{config.adminContact}

) }
) : (
{isLoading ? (

加载中...

) : apiKeys.length === 0 ? (

没有 API Keys

点击上方的创建 "API Key" 按钮来创建你的第一个 API Key

) : ( <> {apiKeys.map((key) => (
{key.name}
创建于 {new Date(key.createdAt).toLocaleString()}
toggleApiKey(key.id, checked)} />
))}
{showExamples && (
生成临时邮箱
                          {`curl -X POST ${window.location.protocol}//${window.location.host}/api/emails/generate \\
  -H "X-API-Key: YOUR_API_KEY" \\
  -H "Content-Type: application/json" \\
  -d '{
    "name": "test",
    "expiryTime": 3600000,
    "domain": "moemail.app"
  }'`}
                        
获取邮箱列表
                          {`curl ${window.location.protocol}//${window.location.host}/api/emails?cursor=CURSOR \\
  -H "X-API-Key: YOUR_API_KEY"`}
                        
获取邮件列表
                          {`curl ${window.location.protocol}//${window.location.host}/api/emails/{emailId}?cursor=CURSOR \\
  -H "X-API-Key: YOUR_API_KEY"`}
                        
获取单封邮件
                          {`curl ${window.location.protocol}//${window.location.host}/api/emails/{emailId}/{messageId} \\
  -H "X-API-Key: YOUR_API_KEY"`}
                        

注意:

  • 请将 YOUR_API_KEY 替换为你的实际 API Key
  • emailId 是邮箱的唯一标识符
  • messageId 是邮件的唯一标识符
  • expiryTime 是邮箱的有效期(毫秒),可选值:3600000(1小时)、86400000(1天)、604800000(7天)、0(永久)
  • domain 是邮箱域名,可通过 /api/emails/domains 获取可用域名列表
  • cursor 用于分页,从上一次请求的响应中获取 nextCursor
  • 所有请求都需要包含 X-API-Key 请求头
)}
)}
) }
) }