'use client' // src/app/admin/users/page.tsx — 用户管理 import { useState, useEffect, useCallback } from 'react' import { Users, RotateCw } from 'lucide-react' interface User { id: number; username: string; display_name: string | null; email: string | null role: string; is_active: number; last_login_at: string | null } export default function UsersPage() { const [users, setUsers] = useState([]) const [loading, setLoading] = useState(true) const [editingId, setEditingId] = useState(null) const [editRole, setEditRole] = useState('') const [saving, setSaving] = useState(false) const [toast, setToast] = useState<{ type: 'ok' | 'err'; msg: string } | null>(null) const load = useCallback(async () => { setLoading(true) const res = await fetch('/api/admin/users') if (res.ok) setUsers(await res.json()) setLoading(false) }, []) useEffect(() => { load() }, [load]) const showToast = (type: 'ok' | 'err', msg: string) => { setToast({ type, msg }) setTimeout(() => setToast(null), 3000) } const handleSave = async (id: number) => { setSaving(true) try { const res = await fetch(`/api/admin/users/${id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ role: editRole }), }) if (res.ok) { showToast('ok', '角色已更新'); setEditingId(null); load() } else { const d = await res.json(); showToast('err', d.error || '保存失败') } } catch { showToast('err', '网络错误') } setSaving(false) } return (
{toast && (
{toast.msg}
)}

用户管理

管理用户角色和权限

{loading ? ( ) : users.map(user => ( ))}
用户名 显示名 邮箱 角色 状态 操作
加载中...
{user.username} {user.display_name || '—'} {user.email || '—'} {editingId === user.id ? ( ) : ( {user.role} )} {user.is_active ? '启用' : '禁用'} {editingId === user.id ? (
) : ( )}
) }