import React, { useState, useEffect, useRef, useCallback, useMemo } from 'react';
import {
Card,
Table,
Button,
Space,
Modal,
Form,
Input,
Select,
message,
Tag,
Popconfirm,
Avatar,
Tooltip,
Badge,
} from 'antd';
import {
PlusOutlined,
EditOutlined,
DeleteOutlined,
UserOutlined,
ReloadOutlined,
LockOutlined,
CameraOutlined,
CheckOutlined,
CloseOutlined,
} from '@ant-design/icons';
import { userAPI, roleAPI } from '../api';
import CloseButton from '../components/CloseButton';
const { Option } = Select;
const UserManagement = () => {
const [users, setUsers] = useState([]);
const [roles, setRoles] = useState([]);
const [loading, setLoading] = useState(false);
const [pagination, setPagination] = useState({ current: 1, pageSize: 10, total: 0 });
const [modalVisible, setModalVisible] = useState(false);
const [passwordModalVisible, setPasswordModalVisible] = useState(false);
const [avatarModalVisible, setAvatarModalVisible] = useState(false);
const [editingUser, setEditingUser] = useState(null);
const [passwordUser, setPasswordUser] = useState(null);
const [avatarUser, setAvatarUser] = useState(null);
const [uploadLoading, setUploadLoading] = useState(false);
const [activeTab, setActiveTab] = useState('all');
const [form] = Form.useForm();
const [passwordForm] = Form.useForm();
const fileInputRef = useRef(null);
useEffect(() => {
fetchUsers();
fetchRoles();
}, [pagination.current]);
const fetchUsers = useCallback(async () => {
setLoading(true);
try {
const params = {
page: pagination.current,
pageSize: pagination.pageSize,
};
if (activeTab !== 'all') {
params.status = activeTab;
}
const response = await userAPI.list(params);
if (response.success) {
setUsers(response.data.users);
setPagination(prev => ({ ...prev, total: response.data.total }));
}
} catch (error) {
message.error('获取用户列表失败');
} finally {
setLoading(false);
}
}, [pagination.current, pagination.pageSize, activeTab]);
const fetchRoles = useCallback(async () => {
try {
const response = await roleAPI.all();
if (response.success) {
setRoles(response.data);
} else {
message.error('获取角色列表失败: ' + (response.message || '未知错误'));
}
} catch (error) {
console.error('获取角色列表失败:', error);
message.error('获取角色列表失败,请检查网络连接');
}
}, []);
const handleAdd = useCallback(() => {
setEditingUser(null);
form.resetFields();
setModalVisible(true);
}, []);
const handleEdit = useCallback(user => {
setEditingUser(user);
form.setFieldsValue({
username: user.username,
email: user.email,
phone: user.phone,
realName: user.realName,
status: user.status,
roleIds: user.roles?.map(r => r.roleId) || [],
});
setModalVisible(true);
}, []);
const handleResetPassword = useCallback(user => {
setPasswordUser(user);
passwordForm.resetFields();
setPasswordModalVisible(true);
}, []);
const handleAvatarClick = useCallback(user => {
setAvatarUser(user);
setAvatarModalVisible(true);
}, []);
const handleAvatarUpload = useCallback(
async e => {
const file = e.target.files[0];
if (!file) return;
if (!file.type.match(/image\/(jpeg|png|gif|webp)/)) {
message.error('只支持 JPG、PNG、GIF 和 WebP 格式的图片');
return;
}
if (file.size > 5 * 1024 * 1024) {
message.error('图片大小不能超过 5MB');
return;
}
setUploadLoading(true);
try {
const response = await userAPI.uploadAvatar(avatarUser.userId, file);
if (response.success) {
message.success('头像上传成功');
fetchUsers();
setAvatarModalVisible(false);
} else {
message.error(response.message || '上传失败');
}
} catch (error) {
message.error('上传失败');
} finally {
setUploadLoading(false);
if (fileInputRef.current) {
fileInputRef.current.value = '';
}
}
},
[avatarUser, fetchUsers]
);
const handleAvatarDelete = useCallback(async () => {
try {
const response = await userAPI.deleteAvatar(avatarUser.userId);
if (response.success) {
message.success('头像已删除');
fetchUsers();
setAvatarModalVisible(false);
} else {
message.error(response.message || '删除失败');
}
} catch (error) {
message.error('删除失败');
}
}, [avatarUser, fetchUsers]);
const handleDelete = useCallback(
async userId => {
Modal.confirm({
title: '确认删除',
content: '确定要删除这个用户吗?此操作不可恢复!',
okText: '删除',
okType: 'danger',
cancelText: '取消',
onOk: async () => {
try {
const response = await userAPI.delete(userId);
if (response.success) {
message.success('删除成功');
fetchUsers();
} else {
message.error(response.message || '删除失败');
}
} catch (error) {
message.error('删除失败');
}
},
});
},
[fetchUsers]
);
const handleLockUnlock = useCallback(
async record => {
try {
const newStatus = record.status === 'locked' ? 'active' : 'locked';
const response = await userAPI.update(record.userId, {
status: newStatus,
});
if (response.success) {
message.success(record.status === 'locked' ? '解锁成功' : '锁定成功');
fetchUsers();
} else {
message.error(response.message || '操作失败');
}
} catch (error) {
message.error('操作失败');
}
},
[fetchUsers]
);
const handleSubmit = useCallback(
async values => {
try {
let response;
if (editingUser) {
response = await userAPI.update(editingUser.userId, values);
} else {
response = await userAPI.create(values);
}
if (response.success) {
message.success(editingUser ? '更新成功' : '创建成功');
setModalVisible(false);
fetchUsers();
} else {
message.error(response.message || '操作失败');
}
} catch (error) {
message.error('操作失败');
}
},
[editingUser, fetchUsers]
);
const handleResetPasswordSubmit = useCallback(
async values => {
try {
const response = await userAPI.resetPassword(passwordUser.userId, values);
if (response.success) {
message.success('密码重置成功');
setPasswordModalVisible(false);
} else {
message.error(response.message || '重置失败');
}
} catch (error) {
message.error('重置失败');
}
},
[passwordUser]
);
const getStatusColor = status => {
const colors = {
active: 'green',
inactive: 'red',
locked: 'orange',
pending: 'blue',
};
return colors[status] || 'default';
};
const getStatusText = status => {
const texts = {
active: '正常',
inactive: '禁用',
locked: '锁定',
pending: '待审核',
};
return texts[status] || status;
};
const handleApprove = useCallback(
async userId => {
try {
const response = await userAPI.approve(userId);
if (response.success) {
message.success('审核通过');
fetchUsers();
} else {
message.error(response.message || '审核失败');
}
} catch (error) {
message.error('审核失败');
}
},
[fetchUsers]
);
const handleReject = useCallback(
async userId => {
try {
const response = await userAPI.reject(userId);
if (response.success) {
message.success('已拒绝该用户的注册申请');
fetchUsers();
} else {
message.error(response.message || '操作失败');
}
} catch (error) {
message.error('操作失败');
}
},
[fetchUsers]
);
const getAvatarUrl = user => {
if (!user?.avatar) return null;
return user.avatar;
};
const tableColumns = useMemo(
() => [
{
title: '头像',
key: 'avatar',
width: 80,
render: (_, record) => (