import { useEffect, useState, useCallback } from 'react'; import { Table, Button, Modal, Form, Input, Select, Tag, Popconfirm, message, Space, Checkbox, Divider, Alert, Tooltip, } from 'antd'; import { PlusOutlined, EditOutlined, DeleteOutlined, SafetyOutlined } from '@ant-design/icons'; import { userApi, type UserInfo } from '../api/modules'; import { usePermissions } from '../hooks/usePermissions'; import { getErrorMessage } from '../utils/error'; const ROLE_OPTIONS = [ { value: 'super_admin', label: '超级管理员' }, { value: 'operation', label: '运营' }, { value: 'support', label: '客服' }, ]; const ROLE_COLORS: Record = { super_admin: 'red', operation: 'blue', support: 'green', }; // 权限分组定义 const PERMISSION_GROUPS = [ { label: '用户管理', prefix: 'user:' }, { label: '账号管理', prefix: 'account:' }, { label: '登录任务', prefix: 'login:' }, { label: 'Cookie', prefix: 'cookie:' }, { label: '代理 & 白名单', prefix: ['proxy:', 'whitelist:'] }, { label: '系统', prefix: ['system:', 'audit:'] }, ]; function isPrefixMatch(key: string, prefix: string | string[]): boolean { if (Array.isArray(prefix)) return prefix.some(p => key.startsWith(p)); return key.startsWith(prefix); } export default function UsersPage() { const [users, setUsers] = useState([]); const [loading, setLoading] = useState(false); const [modalOpen, setModalOpen] = useState(false); const [editing, setEditing] = useState(null); const [form] = Form.useForm(); const [pageSize, setPageSize] = useState(() => { const v = localStorage.getItem('user_page_size'); return v ? Number(v) || 20 : 20; }); const [currentPage, setCurrentPage] = useState(1); // 权限管理 const [permModalOpen, setPermModalOpen] = useState(false); const [permUser, setPermUser] = useState(null); const [permList, setPermList] = useState>({}); const [rolePermMap, setRolePermMap] = useState>({}); const [selectedPerms, setSelectedPerms] = useState([]); const [useCustom, setUseCustom] = useState(false); const [permLoading, setPermLoading] = useState(false); const { can } = usePermissions(); const canAssignPerm = can('user:assign_permissions'); const loadUsers = useCallback(async () => { setLoading(true); try { const data = await userApi.list(); setUsers(data); } catch (e: unknown) { message.error(getErrorMessage(e)); } finally { setLoading(false); } }, []); useEffect(() => { loadUsers(); }, [loadUsers]); const handleCreate = () => { setEditing(null); form.resetFields(); form.setFieldsValue({ role: 'support' }); setModalOpen(true); }; const handleEdit = (user: UserInfo) => { setEditing(user); form.setFieldsValue({ username: user.username, role: user.role, remark: user.remark, }); setModalOpen(true); }; const handleSave = async () => { try { const values = await form.validateFields(); if (editing) { const updateData: { role: string; remark: string; password?: string } = { role: values.role, remark: values.remark }; if (values.password) updateData.password = values.password; await userApi.update(editing.id, updateData); message.success('已更新'); } else { await userApi.create(values); message.success('已创建'); } setModalOpen(false); loadUsers(); } catch (e: unknown) { message.error(getErrorMessage(e)); } }; const handleDelete = async (id: number) => { try { await userApi.delete(id); message.success('已删除'); loadUsers(); } catch (e: unknown) { message.error(getErrorMessage(e)); } }; // ---- 权限管理 ---- const handlePermClick = async (user: UserInfo) => { setPermUser(user); setPermModalOpen(true); setPermLoading(true); try { const data = await userApi.listPermissions(); setPermList(data.permissions || {}); setRolePermMap(data.role_permissions || {}); // 初始化选中权限:如果用户有 custom_permissions 则使用,否则使用角色默认 if (user.custom_permissions !== null && user.custom_permissions !== undefined) { setUseCustom(true); setSelectedPerms(user.custom_permissions); } else { setUseCustom(false); setSelectedPerms(data.role_permissions?.[user.role] || []); } } catch (e: unknown) { message.error(getErrorMessage(e)); } finally { setPermLoading(false); } }; const handlePermSave = async () => { if (!permUser) return; setPermLoading(true); try { await userApi.update(permUser.id, { custom_permissions: useCustom ? selectedPerms : null, }); message.success('权限已更新'); setPermModalOpen(false); loadUsers(); } catch (e: unknown) { message.error(getErrorMessage(e)); } finally { setPermLoading(false); } }; const handleRoleChangeForPerm = (role: string) => { const rolePerms = rolePermMap[role] || []; setSelectedPerms(rolePerms); }; const columns = [ { title: 'ID', dataIndex: 'id', width: 60 }, { title: '用户名', dataIndex: 'username' }, { title: '角色', dataIndex: 'role', render: (role: string) => { const label = ROLE_OPTIONS.find((r) => r.value === role)?.label || role; return {label}; }, }, { title: '权限模式', dataIndex: 'custom_permissions', width: 100, render: (_: unknown, record: UserInfo) => record.custom_permissions !== null && record.custom_permissions !== undefined ? 自定义 : 角色默认, }, { title: '状态', dataIndex: 'is_active', width: 80, render: (active: boolean) => active ? 启用 : 禁用, }, { title: '备注', dataIndex: 'remark', ellipsis: true }, { title: '操作', width: 200, render: (_: unknown, record: UserInfo) => ( {canAssignPerm && ( )} {record.role !== 'super_admin' && ( handleDelete(record.id)}> )} ), }, ]; return (

用户管理

`共 ${t} 条`, onChange: (page, size) => { setCurrentPage(page); if (size !== pageSize) { setPageSize(size); localStorage.setItem('user_page_size', String(size)); setCurrentPage(1); // 切换 pageSize 时重置到第1页 } }, }} /> {/* 编辑/新建用户 Modal */} setModalOpen(false)} onOk={handleSave} okText="保存" >
{/* 权限管理 Modal */} setPermModalOpen(false)} onOk={handlePermSave} okText="保存" width={640} confirmLoading={permLoading} > {permUser && ( <>
权限模式: