import React, { useEffect, useMemo, useState } from 'react'; import { Table, Button, Input, Space, Drawer, Form, Select, App, Tooltip, Tag } from 'antd'; import { PlusOutlined, EditOutlined, DeleteOutlined, KeyOutlined, SaveOutlined, SearchOutlined, UserOutlined, MailOutlined, SafetyCertificateOutlined, ReloadOutlined, } from '@ant-design/icons'; import apiClient from '../../utils/apiClient'; import { buildApiUrl, API_ENDPOINTS } from '../../config/api'; import configService from '../../utils/configService'; import AdminModuleShell from '../../components/AdminModuleShell'; const UserManagement = () => { const { message, modal } = App.useApp(); const [form] = Form.useForm(); const [users, setUsers] = useState([]); const [total, setTotal] = useState(0); const [page, setPage] = useState(1); const [pageSize, setPageSize] = useState(10); const [loading, setLoading] = useState(true); const [showUserDrawer, setShowUserDrawer] = useState(false); const [isEditing, setIsEditing] = useState(false); const [currentUser, setCurrentUser] = useState(null); const [roles, setRoles] = useState([]); const [searchText, setSearchText] = useState(''); const [debouncedSearchText, setDebouncedSearchText] = useState(''); useEffect(() => { configService.getPageSize().then((size) => { const safeSize = Number.isFinite(size) ? Math.min(100, Math.max(5, size)) : 10; setPageSize(safeSize); }); fetchRoles(); }, []); useEffect(() => { const timer = setTimeout(() => { setDebouncedSearchText(searchText.trim()); setPage(1); }, 300); return () => clearTimeout(timer); }, [searchText]); useEffect(() => { fetchUsers(); }, [page, pageSize, debouncedSearchText]); const fetchUsers = async () => { setLoading(true); try { let url = `${API_ENDPOINTS.USERS.LIST}?page=${page}&size=${pageSize}`; if (debouncedSearchText) { url += `&search=${encodeURIComponent(debouncedSearchText)}`; } const response = await apiClient.get(buildApiUrl(url)); setUsers(response.data.users || []); setTotal(response.data.total || 0); } catch { message.error('无法加载用户列表'); } finally { setLoading(false); } }; const fetchRoles = async () => { try { const response = await apiClient.get(buildApiUrl(API_ENDPOINTS.USERS.ROLES)); setRoles(response.data || []); } catch { setRoles([ { role_id: 1, role_name: '平台管理员' }, { role_id: 2, role_name: '普通用户' }, ]); } }; const handleOpenModal = (user = null) => { if (user) { setIsEditing(true); setCurrentUser(user); form.setFieldsValue(user); } else { setIsEditing(false); setCurrentUser(null); form.resetFields(); form.setFieldsValue({ role_id: 2 }); } setShowUserDrawer(true); }; const handleSave = async () => { try { const values = await form.validateFields(); if (isEditing) { await apiClient.put(buildApiUrl(API_ENDPOINTS.USERS.UPDATE(currentUser.user_id)), values); message.success('用户修改成功'); } else { await apiClient.post(buildApiUrl(API_ENDPOINTS.USERS.CREATE), values); message.success('用户添加成功'); } setShowUserDrawer(false); fetchUsers(); } catch (err) { if (err.response) { message.error(err.response.data?.message || '操作失败'); } } }; const handleDelete = (user) => { modal.confirm({ title: '删除用户', content: `确定要删除用户"${user.caption}"吗?此操作无法撤销。`, okText: '确定删除', okType: 'danger', cancelText: '取消', onOk: async () => { try { await apiClient.delete(buildApiUrl(API_ENDPOINTS.USERS.DELETE(user.user_id))); message.success('用户删除成功'); fetchUsers(); } catch { message.error('删除失败'); } }, }); }; const handleResetPassword = (user) => { modal.confirm({ title: '重置密码', content: `确定要重置用户"${user.caption}"的密码吗?重置后密码将恢复为系统默认密码。`, okText: '确定重置', cancelText: '取消', onOk: async () => { try { await apiClient.post(buildApiUrl(API_ENDPOINTS.USERS.RESET_PASSWORD(user.user_id))); message.success('密码重置成功'); } catch { message.error('重置失败'); } }, }); }; const roleNameById = useMemo(() => { return roles.reduce((map, role) => { map[role.role_id] = role.role_name; return map; }, {}); }, [roles]); const adminCountOnPage = useMemo( () => users.filter((user) => String(user.role_id) === '1' || user.role_name?.includes('管理员')).length, [users], ); const columns = [ { title: 'ID', dataIndex: 'user_id', key: 'user_id', width: 80 }, { title: '用户名', dataIndex: 'username', key: 'username' }, { title: '姓名', dataIndex: 'caption', key: 'caption' }, { title: '邮箱', dataIndex: 'email', key: 'email' }, { title: '角色', dataIndex: 'role_name', key: 'role_name', render: (text, record) => { const roleName = text || roleNameById[record.role_id] || '-'; return {roleName}; }, }, { title: '创建时间', dataIndex: 'created_at', key: 'created_at', render: (text) => (text ? new Date(text).toLocaleString() : '-'), }, { title: '操作', key: 'action', fixed: 'right', width: 150, render: (_, record) => ( } stats={[ { label: '总用户数', value: total }, { label: '当前页', value: `${users.length}/${pageSize}` }, { label: '管理员(页内)', value: adminCountOnPage }, ]} toolbar={ } value={searchText} onChange={(e) => setSearchText(e.target.value)} style={{ maxWidth: 320 }} allowClear /> } >
{ setPage(nextPage); setPageSize(size); }, showSizeChanger: true, showTotal: (count) => `共 ${count} 条记录`, }} rowKey="user_id" scroll={{ x: 900 }} /> setShowUserDrawer(false)} destroyOnClose extra={( )} >
} placeholder="请输入用户名" /> } placeholder="请输入姓名" /> } placeholder="请输入邮箱" />