import { useState, useEffect } from 'react' import { Card, CardContent } from '@/components/ui/card' import { Input } from '@/components/ui/input' import { Button } from '@/components/ui/button' import { Label } from '@/components/ui/label' import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@/components/ui/table' import { Badge } from '@/components/ui/badge' import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, } from '@/components/ui/dialog' import { ShieldCheck, Plus, Edit3, Trash2, X, Save, RefreshCw } from 'lucide-react' import { get, post, put, del } from '@/api/client' import { Pagination } from '@/components/ui/Pagination' import { useDebounce } from '@/hooks/useDebounce' interface AdminUser { id: number username: string role: string name: string status: string createdAt: string updatedAt?: string } interface ListRes { success?: boolean records?: AdminUser[] total?: number page?: number pageSize?: number totalPages?: number error?: string } function confirmDangerousDelete(entity: string): boolean { if (!confirm(`确定删除该${entity}?此操作不可恢复。`)) return false const verifyText = window.prompt(`请输入「删除」以确认删除${entity}`) return verifyText === '删除' } export function AdminUsersPage() { const [records, setRecords] = useState([]) const [total, setTotal] = useState(0) const [page, setPage] = useState(1) const [pageSize] = useState(10) const [totalPages, setTotalPages] = useState(0) const [searchTerm, setSearchTerm] = useState('') const debouncedSearch = useDebounce(searchTerm, 300) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) const [showModal, setShowModal] = useState(false) const [editingUser, setEditingUser] = useState(null) const [formUsername, setFormUsername] = useState('') const [formPassword, setFormPassword] = useState('') const [formName, setFormName] = useState('') const [formRole, setFormRole] = useState<'super_admin' | 'admin'>('admin') const [formStatus, setFormStatus] = useState<'active' | 'disabled'>('active') const [saving, setSaving] = useState(false) async function loadList() { setLoading(true) setError(null) try { const params = new URLSearchParams({ page: String(page), pageSize: String(pageSize), }) if (debouncedSearch.trim()) params.set('search', debouncedSearch.trim()) const data = await get(`/api/admin/users?${params}`) if (data?.success) { setRecords((data as ListRes).records || []) setTotal((data as ListRes).total ?? 0) setTotalPages((data as ListRes).totalPages ?? 0) } else { setError((data as ListRes).error || '加载失败') } } catch (e: unknown) { const err = e as { status?: number; data?: { error?: string } } setError(err.status === 403 ? '无权限访问' : err?.data?.error || '加载失败') setRecords([]) } finally { setLoading(false) } } useEffect(() => { loadList() }, [page, pageSize, debouncedSearch]) const handleAdd = () => { setEditingUser(null) setFormUsername('') setFormPassword('') setFormName('') setFormRole('admin') setFormStatus('active') setShowModal(true) } const handleEdit = (u: AdminUser) => { setEditingUser(u) setFormUsername(u.username) setFormPassword('') setFormName(u.name || '') setFormRole((u.role === 'super_admin' ? 'super_admin' : 'admin') as 'super_admin' | 'admin') setFormStatus((u.status === 'disabled' ? 'disabled' : 'active') as 'active' | 'disabled') setShowModal(true) } const handleSave = async () => { if (!formUsername.trim()) { setError('用户名不能为空') return } if (!editingUser && !formPassword) { setError('新建时密码必填,至少 6 位') return } if (formPassword && formPassword.length < 6) { setError('密码至少 6 位') return } setError(null) setSaving(true) try { if (editingUser) { const data = await put<{ success?: boolean; error?: string }>('/api/admin/users', { id: editingUser.id, password: formPassword || undefined, name: formName.trim(), role: formRole, status: formStatus, }) if (data?.success) { setShowModal(false) loadList() } else { setError(data?.error || '保存失败') } } else { const data = await post<{ success?: boolean; error?: string }>('/api/admin/users', { username: formUsername.trim(), password: formPassword, name: formName.trim(), role: formRole, }) if (data?.success) { setShowModal(false) loadList() } else { setError(data?.error || '保存失败') } } } catch (e: unknown) { const err = e as { data?: { error?: string } } setError(err?.data?.error || '保存失败') } finally { setSaving(false) } } const handleDelete = async (id: number) => { if (!confirmDangerousDelete('管理员')) { setError('已取消删除') return } try { const data = await del<{ success?: boolean; error?: string }>(`/api/admin/users?id=${id}`) if (data?.success) loadList() else setError(data?.error || '删除失败') } catch (e: unknown) { const err = e as { data?: { error?: string } } setError(err?.data?.error || '删除失败') } } const formatDate = (s: string) => { if (!s) return '-' try { const d = new Date(s) return isNaN(d.getTime()) ? s : d.toLocaleString('zh-CN') } catch { return s } } return (

管理员用户

后台登录账号管理,仅超级管理员可操作

setSearchTerm(e.target.value)} className="w-48 bg-[#0f2137] border-gray-700 text-white placeholder:text-gray-500" />
{error && (
{error}
)} {loading ? (
加载中...
) : ( <> ID 用户名 昵称 角色 状态 创建时间 操作 {records.map((u) => ( {u.id} {u.username} {u.name || '-'} {u.role === 'super_admin' ? '超级管理员' : '管理员'} {u.status === 'active' ? '正常' : '已禁用'} {formatDate(u.createdAt)} ))} {records.length === 0 && !loading && ( {error === '无权限访问' ? '仅超级管理员可查看' : '暂无管理员'} )}
{totalPages > 1 && (
)} )}
{editingUser ? '编辑管理员' : '新增管理员'}
setFormUsername(e.target.value)} disabled={!!editingUser} /> {editingUser && (

用户名不可修改

)}
setFormPassword(e.target.value)} />
setFormName(e.target.value)} />
{editingUser && (
)}
) }