'use client' import { useState, useEffect } from 'react' import { Card, Button, Table, Badge, Modal, Input } from '@/components/ui' import { Plus, Trash2, Copy, Check, Key } from 'lucide-react' interface ApiKey { id: number name: string permissions: string last_used_at: string | null expires_at: string | null is_active: number created_at: string } export default function ApiKeysPage() { const [keys, setKeys] = useState([]) const [loading, setLoading] = useState(true) const [createOpen, setCreateOpen] = useState(false) const [editTarget, setEditTarget] = useState(null) const [deleteTarget, setDeleteTarget] = useState(null) const [name, setName] = useState('') const [saving, setSaving] = useState(false) const [error, setError] = useState('') const [newKey, setNewKey] = useState(null) const [copied, setCopied] = useState(false) const fetchKeys = () => { fetch('/api/api-keys') .then(r => r.json()) .then(d => { if (d.keys) setKeys(d.keys) }) .catch(() => {}) .finally(() => setLoading(false)) } useEffect(() => { fetchKeys() }, []) const handleCreate = async () => { if (!name.trim()) return setSaving(true) setError('') try { const res = await fetch('/api/api-keys', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: name.trim(), permissions: ['tickets:read'] }), }) const data = await res.json() if (!res.ok) { setError(data.error || '创建失败'); return } setNewKey(data.key) setCreateOpen(false) setName('') fetchKeys() } catch { setError('创建失败') } finally { setSaving(false) } } const handleDelete = async () => { if (!deleteTarget) return const res = await fetch(`/api/api-keys/${deleteTarget.id}`, { method: 'DELETE' }) if (res.ok) { setDeleteTarget(null) fetchKeys() } } const handleToggleActive = async (k: ApiKey) => { await fetch(`/api/api-keys/${k.id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: k.name, permissions: JSON.parse(k.permissions), is_active: !k.is_active }), }) fetchKeys() } const copyKey = (key: string) => { navigator.clipboard.writeText(key) setCopied(true) setTimeout(() => setCopied(false), 2000) } return (

API Key 管理

用于第三方系统调用工单系统 API

{newKey && (

API Key 已创建(仅显示一次,请妥善保存)

{newKey}
)} {loading ? (
加载中...
) : keys.length === 0 ? (

暂无 API Key

点击右上角「创建 Key」生成新的密钥

) : ( {keys.map(k => { const perms: string[] = JSON.parse(k.permissions) return ( ) })}
{k.name}
{perms.map(p => {p})}
{k.last_used_at ? new Date(k.last_used_at).toLocaleString('zh-CN') : '从未使用'} {k.expires_at ? new Date(k.expires_at).toLocaleString('zh-CN') : '永不过期'} {new Date(k.created_at).toLocaleString('zh-CN')}
)} { setCreateOpen(false); setName(''); setError('') }} title="创建 API Key">
setName(e.target.value)} placeholder="例如:资产管理系统调用" />

默认权限:tickets:read(仅读取工单数据)

{error &&

{error}

}
setDeleteTarget(null)} title="确认删除">

确定要删除 API Key「{deleteTarget?.name}」吗?使用该 Key 的应用将无法再访问此系统。

) }