// ============================================================ // API 密钥管理 // ============================================================ import { useState } from 'react' import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' import { Button, message, Tag, Modal, Form, Input, InputNumber, Select, Popconfirm, Space, Typography } from 'antd' import { PlusOutlined, CopyOutlined } from '@ant-design/icons' import type { ProColumns } from '@ant-design/pro-components' import { ProTable } from '@ant-design/pro-components' import { apiKeyService } from '@/services/api-keys' import type { TokenInfo } from '@/types' const { Text } = Typography export default function ApiKeys() { const queryClient = useQueryClient() const [form] = Form.useForm() const [modalOpen, setModalOpen] = useState(false) const [newToken, setNewToken] = useState(null) const { data, isLoading } = useQuery({ queryKey: ['api-keys'], queryFn: ({ signal }) => apiKeyService.list(signal), }) const createMutation = useMutation({ mutationFn: (data: { name: string; expires_days?: number; permissions: string[] }) => apiKeyService.create(data), onSuccess: (result: TokenInfo) => { message.success('创建成功') queryClient.invalidateQueries({ queryKey: ['api-keys'] }) if (result.token) { setNewToken(result.token) } setModalOpen(false) form.resetFields() }, onError: (err: Error) => message.error(err.message || '创建失败'), }) const revokeMutation = useMutation({ mutationFn: (id: string) => apiKeyService.revoke(id), onSuccess: () => { message.success('已撤销') queryClient.invalidateQueries({ queryKey: ['api-keys'] }) }, onError: (err: Error) => message.error(err.message || '撤销失败'), }) const columns: ProColumns[] = [ { title: '名称', dataIndex: 'name', width: 160 }, { title: '前缀', dataIndex: 'token_prefix', width: 120, render: (_, r) => {r.token_prefix}... }, { title: '权限', dataIndex: 'permissions', width: 200, render: (_, r) => r.permissions?.map((p) => {p}), }, { title: '过期时间', dataIndex: 'expires_at', width: 180, render: (_, r) => r.expires_at ? new Date(r.expires_at).toLocaleString('zh-CN') : '永不过期', }, { title: '最后使用', dataIndex: 'last_used_at', width: 180, render: (_, r) => r.last_used_at ? new Date(r.last_used_at).toLocaleString('zh-CN') : '-', }, { title: '创建时间', dataIndex: 'created_at', width: 180, render: (_, r) => new Date(r.created_at).toLocaleString('zh-CN'), }, { title: '操作', width: 100, render: (_, record) => ( revokeMutation.mutate(record.id)}> ), }, ] const handleCreate = async () => { const values = await form.validateFields() createMutation.mutate(values) } const copyToken = () => { if (newToken) { navigator.clipboard.writeText(newToken) message.success('已复制到剪贴板') } } return (
columns={columns} dataSource={data?.items ?? []} loading={isLoading} rowKey="id" search={false} toolBarRender={() => [ , ]} pagination={{ total: data?.total ?? 0, pageSize: data?.page_size ?? 20, current: data?.page ?? 1, showSizeChanger: false, }} /> { setModalOpen(false); form.resetFields() }} confirmLoading={createMutation.isPending} >