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