import { useEffect, useState } from "react"; import { api, ApiError } from "../api"; import type { ApiKey } from "../types"; import { Copy, KeyRound, Plus, Trash2 } from "lucide-react"; const TIERS = [ { key: "free", label: "免费 (free)", rate: 120 }, { key: "partner", label: "合作方 (partner)", rate: 600 }, { key: "internal", label: "内部 (internal)", rate: 6000 }, ]; function tierLabel(tier: string): string { return TIERS.find((t) => t.key === tier)?.label ?? tier; } export default function ApiKeysPage() { const [rows, setRows] = useState([]); const [error, setError] = useState(""); const [creating, setCreating] = useState(false); const [newKey, setNewKey] = useState(null); async function load() { setError(""); try { const res = await api.listApiKeys(); setRows(res.items); } catch (e) { setError(e instanceof ApiError ? e.message : "加载失败"); } } useEffect(() => { load(); }, []); async function revoke(id: string, name: string) { if (!confirm(`确认吊销密钥「${name}」?使用该密钥的请求将立即被拒绝。`)) return; try { await api.revokeApiKey(id); await load(); } catch (e) { setError(e instanceof ApiError ? e.message : "操作失败"); } } return (

API 密钥

公开 API 免费只读,匿名也可调用(低额度)。签发密钥可获得更高速率上限并归属用量。

{error && (
{error}
)} {newKey && (
密钥已生成,请立即复制保存——它只显示这一次。
{newKey}
)} {creating && ( setCreating(false)} onCreated={(plaintext) => { setCreating(false); setNewKey(plaintext); load(); }} /> )}
{rows.length === 0 ? ( ) : ( rows.map((k) => ( )) )}
名称 前缀 级别 速率/分钟 用量(今日/累计) 状态
暂无密钥
{k.name} {k.owner_email && ( {k.owner_email} )} {k.key_prefix}… {tierLabel(k.tier)} {k.rate_limit_per_min} {k.usage.today} / {k.usage.total} {k.revoked_at ? ( 已吊销 ) : ( 启用中 )} {!k.revoked_at && ( )}
); } function CreateKeyForm({ onClose, onCreated, }: { onClose: () => void; onCreated: (plaintext: string) => void; }) { const [name, setName] = useState(""); const [ownerEmail, setOwnerEmail] = useState(""); const [tier, setTier] = useState("free"); const [rate, setRate] = useState(120); const [busy, setBusy] = useState(false); const [error, setError] = useState(""); function pickTier(t: string) { setTier(t); const def = TIERS.find((x) => x.key === t); if (def) setRate(def.rate); } async function submit() { if (!name.trim()) { setError("名称不能为空"); return; } setBusy(true); setError(""); try { const res = await api.createApiKey({ name: name.trim(), owner_email: ownerEmail.trim() || undefined, tier, rate_limit_per_min: rate, }); onCreated(res.key); } catch (e) { setError(e instanceof ApiError ? e.message : "创建失败"); } finally { setBusy(false); } } return (

签发新密钥

{error &&
{error}
}
); }