import { useState, type FormEvent } from 'react' import { api, type Channel, type Key, type Stats } from '../api' import { channelName, num, type Action } from '../common' import { formatTime, keyExpiry } from '../time' import { IconPlus } from '../components/icons' import { Badge, Dialog, Feedback, Table } from '../components/ui' interface KeyForm { name: string all_channels: boolean channels: string[] expires_at: string } const EMPTY_FORM: KeyForm = { name: '', all_channels: false, channels: [], expires_at: '' } interface KeysProps { keys: Key[] stats: Stats | null channels: Channel[] timezone: string busy: boolean error: string notice: string action: Action refresh: () => void notify: (msg: string) => void clearError: () => void /** 跳转到概览页并按该 Key 筛选统计。 */ onViewStats: (k: Key) => void } export function KeysPage({ keys, stats, channels, timezone, busy, error, notice, action, refresh, notify, clearError, onViewStats }: KeysProps) { const [creating, setCreating] = useState(false) const [keyForm, setKeyForm] = useState(EMPTY_FORM) const [newKey, setNewKey] = useState('') const time = formatTime function openCreate() { setCreating(true) setKeyForm(EMPTY_FORM) } function closeCreate() { setCreating(false) clearError() } function submit(e: FormEvent) { e.preventDefault() action(async () => { if (!keyForm.all_channels && !keyForm.channels.length) throw new Error('请选择至少一个渠道,或授权全部渠道。') const expires_at = keyExpiry(keyForm.expires_at) const r = await api<{ key: string }>('/keys', 'POST', { ...keyForm, channels: keyForm.all_channels ? [] : keyForm.channels, expires_at }) setNewKey(r.key) setCreating(false) refresh() }) } function toggle(k: Key) { action(async () => { await api('/keys/' + encodeURIComponent(k.id), 'PATCH', { enabled: !k.enabled }) refresh() }) } function revoke(k: Key) { if (!confirm(`确定撤销 Key“${k.name}”?历史记录将保留。`)) return action(async () => { await api('/keys/' + encodeURIComponent(k.id), 'DELETE') refresh() notify('Key 已撤销,历史记录已保留。') }) } function copyKey() { action(async () => { if (!navigator.clipboard) throw new Error('无法自动复制,请选中密钥手动复制。') await navigator.clipboard.writeText(newKey) notify('密钥已复制。') }) } function toggleChannel(id: string, checked: boolean) { setKeyForm({ ...keyForm, channels: checked ? [...keyForm.channels, id] : keyForm.channels.filter(c => c !== id), }) } return (

访问密钥 {keys.length}

{ const u = stats?.by_key?.find(u => u.key_id === k.id) return [ <>{k.prefix}…, k.all_channels ? '全部渠道' : k.channels?.map(id => channelName(channels, id)).join('、') || '无渠道权限', {k.revoked ? '已撤销' : k.enabled ? '启用' : '停用'}, <>{num(u?.requests ?? 0)} 次输入 {num(u?.input_tokens ?? 0)} / 输出 {num(u?.output_tokens ?? 0)}, <>{time(k.expires_at) === '—' ? '永不过期' : time(k.expires_at)}创建于 {time(k.created_at)},
, ] })} /> {creating && (
{!keyForm.all_channels && (

选择允许访问的渠道

{!channels.length &&

暂无渠道,请先创建渠道。

} {channels.map(c => ( ))}
)}
)} {newKey && (
完整密钥仅展示这一次。请立即复制并妥善保存,关闭后无法再次查看。