import React, { useState } from 'react'; import { useQuery } from '@tanstack/react-query'; import { format } from 'date-fns'; import { Plus, Search, Edit, Trash2, User, Mail, Phone } from 'lucide-react'; import { userClient, roleClient } from '@/client/api'; import type { InferResponseType, InferRequestType } from 'hono/client'; import { Button } from '@/client/components/ui/button'; import { Input } from '@/client/components/ui/input'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/client/components/ui/card'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/client/components/ui/table'; import { Badge } from '@/client/components/ui/badge'; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@/client/components/ui/dialog'; import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from '@/client/components/ui/form'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/client/components/ui/select'; import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import { z } from 'zod'; import { toast } from 'sonner'; import { Skeleton } from '@/client/components/ui/skeleton'; import { Switch } from '@/client/components/ui/switch'; import { Label } from '@/client/components/ui/label'; type UserListResponse = InferResponseType; type CreateUserRequest = InferRequestType['json']; type UpdateUserRequest = InferRequestType['json']; // 表单验证Schema const userFormSchema = z.object({ username: z.string().min(3, '用户名至少3个字符'), nickname: z.string().optional(), email: z.string().email('请输入有效的邮箱地址').optional().or(z.literal('')), phone: z.string().regex(/^1[3-9]\d{9}$/, '请输入有效的手机号').optional().or(z.literal('')), name: z.string().optional(), password: z.string().min(6, '密码至少6个字符').optional(), isDisabled: z.boolean().default(false), }); type UserFormData = z.infer; export const UsersPage = () => { const [searchParams, setSearchParams] = useState({ page: 1, limit: 10, search: '' }); const [isModalOpen, setIsModalOpen] = useState(false); const [editingUser, setEditingUser] = useState(null); const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); const [userToDelete, setUserToDelete] = useState(null); const form = useForm({ resolver: zodResolver(userFormSchema), defaultValues: { username: '', nickname: '', email: '', phone: '', name: '', password: '', isDisabled: false, }, }); const { data: usersData, isLoading, refetch } = useQuery({ queryKey: ['users', searchParams], queryFn: async () => { const res = await userClient.$get({ query: { page: searchParams.page, pageSize: searchParams.limit, keyword: searchParams.search } }); if (res.status !== 200) { throw new Error('获取用户列表失败'); } return await res.json(); } }); const users = usersData?.data || []; const totalCount = usersData?.pagination?.total || 0; // 处理搜索 const handleSearch = (e: React.FormEvent) => { e.preventDefault(); setSearchParams(prev => ({ ...prev, page: 1 })); }; // 处理分页 const handlePageChange = (page: number, limit: number) => { setSearchParams(prev => ({ ...prev, page, limit })); }; // 打开创建用户对话框 const handleCreateUser = () => { setEditingUser(null); form.reset({ username: '', nickname: '', email: '', phone: '', name: '', password: '', isDisabled: false, }); setIsModalOpen(true); }; // 打开编辑用户对话框 const handleEditUser = (user: any) => { setEditingUser(user); form.reset({ username: user.username, nickname: user.nickname || '', email: user.email || '', phone: user.phone || '', name: user.name || '', isDisabled: user.isDisabled === 1, }); setIsModalOpen(true); }; // 处理表单提交 const handleSubmit = async (data: UserFormData) => { try { if (editingUser) { // 编辑用户 const res = await userClient[':id']['$put']({ param: { id: editingUser.id }, json: { ...data, isDisabled: data.isDisabled ? 1 : 0, } as UpdateUserRequest }); if (res.status !== 200) { throw new Error('更新用户失败'); } toast.success('用户更新成功'); } else { // 创建用户 const res = await userClient.$post({ json: { ...data, isDisabled: data.isDisabled ? 1 : 0, } as CreateUserRequest }); if (res.status !== 201) { throw new Error('创建用户失败'); } toast.success('用户创建成功'); } setIsModalOpen(false); refetch(); } catch (error) { console.error('操作失败:', error); toast.error('操作失败,请重试'); } }; // 处理删除用户 const handleDeleteUser = (id: number) => { setUserToDelete(id); setDeleteDialogOpen(true); }; const confirmDelete = async () => { if (!userToDelete) return; try { const res = await userClient[':id']['$delete']({ param: { id: userToDelete } }); if (res.status !== 204) { throw new Error('删除用户失败'); } toast.success('用户删除成功'); refetch(); } catch (error) { console.error('删除用户失败:', error); toast.error('删除失败,请重试'); } finally { setDeleteDialogOpen(false); setUserToDelete(null); } }; // 渲染加载骨架 if (isLoading) { return (

用户管理

); } return (

用户管理

用户列表 管理系统中的所有用户,共 {totalCount} 位用户
setSearchParams(prev => ({ ...prev, search: e.target.value }))} className="pl-8" />
用户名 昵称 邮箱 真实姓名 角色 状态 创建时间 操作 {users.map((user) => ( {user.username} {user.nickname || '-'} {user.email || '-'} {user.name || '-'} {user.role === 'admin' ? '管理员' : '普通用户'} {user.isDisabled === 1 ? '禁用' : '启用'} {format(new Date(user.createdAt), 'yyyy-MM-dd HH:mm')}
))}
第 {searchParams.page} 页,共 {Math.ceil(totalCount / searchParams.limit)} 页
{/* 创建/编辑用户对话框 */} {editingUser ? '编辑用户' : '创建用户'} {editingUser ? '编辑现有用户信息' : '创建一个新的用户账户'}
( 用户名 )} /> ( 昵称 )} /> ( 邮箱 )} /> ( 手机号 )} /> ( 真实姓名 )} /> {!editingUser && ( ( 密码 )} /> )} (
用户状态 禁用后用户将无法登录系统
)} />
{/* 删除确认对话框 */} 确认删除 确定要删除这个用户吗?此操作无法撤销。
); };