import { Button, Card, Form, Input, Modal, Space, Table, Typography, message } from 'antd'; import { useEffect, useMemo, useState } from 'react'; import { api } from '../lib/api'; type UserRow = { id: string; username: string; nickname: string; email?: string; email_verified: boolean; phone?: string; role: number; created_at: string; }; type ResetValues = { newPassword: string; }; export function UsersPage() { const [loading, setLoading] = useState(false); const [rows, setRows] = useState([]); const [resetOpen, setResetOpen] = useState(false); const [resetUserId, setResetUserId] = useState(null); const [resetForm] = Form.useForm(); const columns = useMemo( () => [ { title: 'ID', dataIndex: 'id', key: 'id', width: 90 }, { title: '用户名', dataIndex: 'username', key: 'username' }, { title: '昵称', dataIndex: 'nickname', key: 'nickname' }, { title: '邮箱', dataIndex: 'email', key: 'email' }, { title: '邮箱验证', dataIndex: 'email_verified', key: 'email_verified', render: (v: boolean) => (v ? '已验证' : '未验证'), width: 100, }, { title: '手机号', dataIndex: 'phone', key: 'phone' }, { title: '角色', dataIndex: 'role', key: 'role', width: 80 }, { title: '创建时间', dataIndex: 'created_at', key: 'created_at', width: 180 }, { title: '操作', key: 'actions', width: 160, render: (_: any, row: UserRow) => ( ), }, ], [resetForm], ); const load = async () => { setLoading(true); try { const res = await api.listUsers(200, 0); const users = res?.data?.users || []; setRows( users.map((u: any) => ({ id: u.id, username: u.username, nickname: u.nickname, email: u.email || undefined, email_verified: Boolean(u.email_verified), phone: u.phone || undefined, role: u.role, created_at: u.created_at, })), ); } catch (e: any) { message.error(e?.message || '加载失败'); } finally { setLoading(false); } }; useEffect(() => { void load(); }, []); const onResetOk = async () => { try { const values = await resetForm.validateFields(); if (!resetUserId) return; await api.resetUserPassword(resetUserId, values.newPassword); message.success('密码已重置'); setResetOpen(false); } catch (e: any) { if (e?.errorFields) return; message.error(e?.message || '重置失败'); } }; return ( 用户管理 setResetOpen(false)} okText="确认" cancelText="取消" >
{ const hasLetter = /[a-zA-Z]/.test(v || ''); const hasNumber = /\d/.test(v || ''); if (!v) return Promise.resolve(); if (!hasLetter || !hasNumber) return Promise.reject(new Error('必须包含字母和数字')); return Promise.resolve(); }, }, ]} >
); }