import { useState, useEffect } from 'react'; import { Dropdown, Avatar, Space, Typography, message, Modal, Table, Button, Tag, Popconfirm, Pagination, Form, Input } from 'antd'; import { UserOutlined, LogoutOutlined, TeamOutlined, CrownOutlined, LockOutlined, KeyOutlined } from '@ant-design/icons'; import { authApi, userApi } from '../services/api'; import type { User } from '../types'; import type { MenuProps } from 'antd'; const { Text } = Typography; export default function UserMenu() { const [currentUser, setCurrentUser] = useState(null); const [showUserManagement, setShowUserManagement] = useState(false); const [showChangePassword, setShowChangePassword] = useState(false); const [users, setUsers] = useState([]); const [loading, setLoading] = useState(false); const [currentPage, setCurrentPage] = useState(1); const [pageSize, setPageSize] = useState(10); const [changePasswordForm] = Form.useForm(); const [changingPassword, setChangingPassword] = useState(false); useEffect(() => { loadCurrentUser(); }, []); const loadCurrentUser = async () => { try { const user = await authApi.getCurrentUser(); setCurrentUser(user); } catch (error) { console.error('获取用户信息失败:', error); } }; const handleLogout = async () => { try { await authApi.logout(); message.success('已退出登录'); window.location.href = '/login'; } catch (error) { console.error('退出登录失败:', error); message.error('退出登录失败'); } }; const handleShowUserManagement = async () => { if (!currentUser?.is_admin) { message.warning('只有管理员可以访问用户管理'); return; } setShowUserManagement(true); loadUsers(); }; const loadUsers = async () => { try { setLoading(true); const userList = await userApi.listUsers(); setUsers(userList); } catch (error) { console.error('获取用户列表失败:', error); message.error('获取用户列表失败'); } finally { setLoading(false); } }; const handleSetAdmin = async (userId: string, isAdmin: boolean) => { try { await userApi.setAdmin(userId, isAdmin); message.success(isAdmin ? '已设置为管理员' : '已取消管理员权限'); loadUsers(); } catch (error) { console.error('设置管理员失败:', error); message.error('设置管理员失败'); } }; const handleDeleteUser = async (userId: string) => { try { await userApi.deleteUser(userId); message.success('用户已删除'); loadUsers(); } catch (error) { console.error('删除用户失败:', error); message.error('删除用户失败'); } }; const handleResetPassword = async (userId: string, username: string) => { Modal.confirm({ title: '重置用户密码', content: (

确定要重置用户 {username} 的密码吗?

密码将被重置为默认密码:{username}@666

), okText: '确定重置', cancelText: '取消', onOk: async () => { try { const result = await userApi.resetPassword(userId); if (result.default_password) { Modal.success({ title: '密码重置成功', content: (

用户 {result.username} 的密码已重置为:

{result.default_password}

请将此密码告知用户,建议用户登录后立即修改密码

), }); } else { message.success('密码重置成功'); } loadUsers(); } catch (error: any) { console.error('重置密码失败:', error); message.error(error.response?.data?.detail || '重置密码失败'); } }, }); }; const handleChangePassword = async (values: { oldPassword: string; newPassword: string }) => { try { setChangingPassword(true); await authApi.setPassword(values.newPassword); message.success('密码修改成功'); setShowChangePassword(false); changePasswordForm.resetFields(); } catch (error: any) { console.error('修改密码失败:', error); message.error(error.response?.data?.detail || '修改密码失败'); } finally { setChangingPassword(false); } }; const menuItems: MenuProps['items'] = [ { key: 'user-info', label: (
{currentUser?.display_name || currentUser?.username}
Trust Level: {currentUser?.trust_level} {currentUser?.is_admin && ' · 管理员'}
), disabled: true, }, { type: 'divider', }, ...(currentUser?.is_admin ? [{ key: 'user-management', icon: , label: '用户管理', onClick: handleShowUserManagement, }, { type: 'divider' as const, }] : []), { key: 'change-password', icon: , label: '修改密码', onClick: () => setShowChangePassword(true), }, { type: 'divider', }, { key: 'logout', icon: , label: '退出登录', onClick: handleLogout, }, ]; const columns = [ { title: '用户名', dataIndex: 'username', key: 'username', render: (text: string, record: User) => ( } size="small" />
{record.display_name || text}
{text}
), }, { title: 'Trust Level', dataIndex: 'trust_level', key: 'trust_level', width: 120, render: (level: number) => {level}, }, { title: '角色', dataIndex: 'is_admin', key: 'is_admin', width: 100, render: (isAdmin: boolean) => ( isAdmin ? }>管理员 : 普通用户 ), }, { title: '最后登录', dataIndex: 'last_login', key: 'last_login', width: 180, render: (date: string) => new Date(date).toLocaleString('zh-CN'), }, { title: '操作', key: 'actions', width: 280, render: (_: unknown, record: User) => { const isSelf = record.user_id === currentUser?.user_id; return ( {record.is_admin ? ( handleSetAdmin(record.user_id, false)} disabled={isSelf} > ) : ( )} handleDeleteUser(record.user_id)} disabled={isSelf} > ); }, }, ]; if (!currentUser) { return null; } return ( <>
{ e.currentTarget.style.background = 'rgba(255, 255, 255, 1)'; e.currentTarget.style.transform = 'translateY(-2px)'; e.currentTarget.style.boxShadow = '0 4px 12px rgba(102, 126, 234, 0.3)'; }} onMouseLeave={(e) => { e.currentTarget.style.background = 'rgba(255, 255, 255, 0.95)'; e.currentTarget.style.transform = 'translateY(0)'; e.currentTarget.style.boxShadow = '0 2px 8px rgba(0, 0, 0, 0.1)'; }} >
} size={40} style={{ backgroundColor: '#1890ff', border: '3px solid #fff', boxShadow: '0 2px 8px rgba(102, 126, 234, 0.3)', }} /> {currentUser.is_admin && (
)}
{currentUser.display_name || currentUser.username} {currentUser.is_admin ? '👑 管理员' : `🎖️ Trust Level ${currentUser.trust_level}`}
setShowUserManagement(false)} footer={null} width={900} centered styles={{ body: { padding: 0, display: 'flex', flexDirection: 'column', height: 'calc(100vh - 380px)', } }} >
`共 ${total} 个用户`} pageSizeOptions={['10', '20', '50', '100']} onChange={(page, newPageSize) => { setCurrentPage(page); setPageSize(newPageSize); }} />
{ setShowChangePassword(false); changePasswordForm.resetFields(); }} footer={null} width={480} centered >
} placeholder="请输入新密码(至少6个字符)" autoComplete="new-password" /> ({ validator(_, value) { if (!value || getFieldValue('newPassword') === value) { return Promise.resolve(); } return Promise.reject(new Error('两次输入的密码不一致')); }, }), ]} > } placeholder="请再次输入新密码" autoComplete="new-password" />
); }