import { useEffect, useState } from 'react' import { Plus, Trash2, Users as UsersIcon, AlertCircle, Loader2 } from 'lucide-react' import { api, UserInfo } from '@/lib/api' import { canDeleteUsers, getStoredUser, roleLabel, RoleName } from '@/lib/auth' import { CreateUserDialog } from '@/components/CreateUserDialog' import { cn } from '@/lib/cn' const creatableRoles: Record = { system_admin: ['admin', 'user'], admin: ['user'], user: [], } export function Users() { const [users, setUsers] = useState([]) const [loading, setLoading] = useState(true) const [error, setError] = useState('') const [dialogOpen, setDialogOpen] = useState(false) const currentUser = getStoredUser() const allowedRoles = currentUser ? creatableRoles[currentUser.role] : [] const fetchData = async () => { setLoading(true) try { const u = await api.listUsers() setUsers(u) setError('') } catch (err: any) { setError(err?.message || '加载失败') } finally { setLoading(false) } } useEffect(() => { fetchData() }, []) const handleDelete = async (id: string) => { if (!confirm('确定删除该用户?')) return try { await api.deleteUser(id) fetchData() } catch (err: any) { setError(err?.message || '删除失败') } } const handleStatusChange = async (user: UserInfo, status: string) => { try { await api.updateUser(user.id, { status }) fetchData() } catch (err: any) { setError(err?.message || '更新失败') } } const current = users.find((u) => u.username === currentUser?.username) return (

用户管理

{error && (
{error}
)}
{loading ? ( ) : users.length === 0 ? ( ) : ( users.map((u) => ( )) )}
用户名 角色 状态 创建时间 操作
暂无用户
{u.username} {roleLabel(u.role)} {new Date(u.created_at).toLocaleString()} {canDeleteUsers(current?.role || 'user') && u.id !== current?.id && ( )}
setDialogOpen(false)} onSuccess={() => { setDialogOpen(false) fetchData() }} allowedRoles={allowedRoles} />
) } function roleBadge(role: string) { switch (role) { case 'system_admin': return 'bg-accent/10 text-accent' case 'admin': return 'bg-purple-500/10 text-purple-400' case 'user': return 'bg-bear/10 text-bear' default: return 'bg-muted/10 text-muted' } }