import { Button, DatePicker, Form, Input, InputNumber, Modal, Space, Table, Tag, Typography, message } from 'antd'; import { useEffect, useState } from 'react'; import { api } from '../lib/api'; type Row = { id: string; code: string; max_uses: number; used_count: number; effective_status: string; expires_at?: string; note?: string; created_at: string }; const statusText: Record = { active: ['可使用', 'green'], exhausted: ['已用完', 'default'], expired: ['已过期', 'orange'], revoked: ['已作废', 'red'], }; export function InvitationCodesPage() { const [rows, setRows] = useState([]); const [loading, setLoading] = useState(false); const [open, setOpen] = useState(false); const [generated, setGenerated] = useState([]); const [form] = Form.useForm(); const load = async () => { setLoading(true); try { setRows((await api.listInvitationCodes())?.data?.items || []); } catch (e: any) { message.error(e?.message || '加载失败'); } finally { setLoading(false); } }; useEffect(() => { void load(); }, []); const generate = async () => { try { const value = await form.validateFields(); const res = await api.generateInvitationCodes({ ...value, expires_at: value.expires_at?.toISOString() }); setGenerated((res?.data?.codes || []).map((item: any) => item.code)); setOpen(false); form.resetFields(); await load(); } catch (e: any) { if (!e?.errorFields) message.error(e?.message || '生成失败'); } }; const copyGenerated = async () => { await navigator.clipboard.writeText(generated.join('\n')); message.success('已复制全部邀请码'); }; const columns = [ { title: '邀请码', dataIndex: 'code' }, { title: '状态', dataIndex: 'effective_status', render: (v: string) => { const item = statusText[v] || [v, 'default']; return {item[0]}; } }, { title: '使用量', render: (_: unknown, row: Row) => `${row.used_count} / ${row.max_uses}` }, { title: '有效期至', dataIndex: 'expires_at', render: (v?: string) => v ? new Date(v).toLocaleString() : '永久' }, { title: '备注', dataIndex: 'note' }, { title: '操作', render: (_: unknown, row: Row) => }, ]; return 邀请码管理 setOpen(false)} okText="生成" cancelText="取消">
0} onCancel={() => setGenerated([])} footer={}> 完整邀请码只显示这一次,请立即复制保存。 ; }