import { Button, Drawer, Form, Input, message, Tag, Typography, Tree } from "antd"; import type { DataNode } from "antd/es/tree"; import { useEffect, useMemo, useState } from "react"; import { createRole, listPermissions, listRolePermissions, listRoles, saveRolePermissions, updateRole } from "../api"; import type { SysPermission, SysRole } from "../types"; import { usePermission } from "../hooks/usePermission"; import { EditOutlined, PlusOutlined, SafetyCertificateOutlined } from "@ant-design/icons"; import "./Roles.css"; const { Title, Text } = Typography; const DEFAULT_STATUS = 1; type PermissionNode = SysPermission & { key: number; children?: PermissionNode[] }; const buildPermissionTree = (list: SysPermission[]): PermissionNode[] => { const active = list.filter((p) => p.status !== 0); const map = new Map(); const roots: PermissionNode[] = []; active.forEach((item) => { map.set(item.permId, { ...item, key: item.permId, children: [] }); }); map.forEach((node) => { if (node.parentId && map.has(node.parentId)) { map.get(node.parentId)!.children!.push(node); } else { roots.push(node); } }); const sortNodes = (nodes: PermissionNode[]) => { nodes.sort((a, b) => (a.sortOrder || 0) - (b.sortOrder || 0)); nodes.forEach((n) => n.children && sortNodes(n.children)); }; sortNodes(roots); return roots; }; const toTreeData = (nodes: PermissionNode[]): DataNode[] => nodes.map((node) => ({ key: node.permId, title: ( {node.name} {node.permType === "button" && 按钮} ), children: node.children ? toTreeData(node.children) : undefined })); const generateRoleCode = () => `ROLE-${Date.now().toString(36).toUpperCase()}`; export default function Roles() { const [loading, setLoading] = useState(false); const [saving, setSaving] = useState(false); const [data, setData] = useState([]); const [permissions, setPermissions] = useState([]); const [rolePermMap, setRolePermMap] = useState>({}); const [drawerOpen, setDrawerOpen] = useState(false); const [editing, setEditing] = useState(null); const [selectedPermIds, setSelectedPermIds] = useState([]); const [form] = Form.useForm(); const { can } = usePermission(); const permissionMap = useMemo(() => { const map = new Map(); permissions.forEach((p) => map.set(p.permId, p)); return map; }, [permissions]); const permissionTreeData = useMemo( () => toTreeData(buildPermissionTree(permissions)), [permissions] ); const loadPermissions = async () => { try { const list = await listPermissions(); setPermissions(list || []); } catch (e) { setPermissions([]); message.error("加载权限失败,请确认有管理员权限"); } }; const loadRolePermissions = async (roles: SysRole[]) => { const entries = await Promise.all( roles.map(async (role) => { try { const ids = await listRolePermissions(role.roleId); const normalized = (ids || []).map((id) => Number(id)).filter((id) => !Number.isNaN(id)); return [role.roleId, normalized] as const; } catch (e) { return [role.roleId, []] as const; } }) ); setRolePermMap(Object.fromEntries(entries)); }; const loadRoles = async () => { setLoading(true); try { const list = await listRoles(); const roles = list || []; setData(roles); await loadPermissions(); await loadRolePermissions(roles); } finally { setLoading(false); } }; useEffect(() => { loadRoles(); }, []); const openCreate = () => { setEditing(null); setSelectedPermIds([]); form.resetFields(); setDrawerOpen(true); }; const openEdit = (record: SysRole) => { setEditing(record); setSelectedPermIds(rolePermMap[record.roleId] || []); form.setFieldsValue({ roleName: record.roleName, remark: record.remark }); setDrawerOpen(true); }; useEffect(() => { if (editing) { setSelectedPermIds(rolePermMap[editing.roleId] || []); } }, [editing, rolePermMap]); const handleClose = () => { setDrawerOpen(false); }; const submit = async () => { try { const values = await form.validateFields(); setSaving(true); const payload: Partial = { roleCode: editing?.roleCode || generateRoleCode(), roleName: values.roleName, remark: values.remark, status: editing?.status ?? DEFAULT_STATUS }; let roleId = editing?.roleId; if (editing) { await updateRole(editing.roleId, payload); } else { await createRole(payload); } const list = await listRoles(); const roles = list || []; setData(roles); if (!roleId) { roleId = roles.find((r) => r.roleCode === payload.roleCode)?.roleId; } if (roleId) { await saveRolePermissions(roleId, selectedPermIds); } await loadRolePermissions(roles); setDrawerOpen(false); message.success(editing ? "角色已更新" : "角色已创建"); } catch (e) { if (e instanceof Error && e.message) { message.error(e.message); } } finally { setSaving(false); } }; const renderRolePermissions = (role: SysRole) => { const permIds = rolePermMap[role.roleId] || []; const perms = permIds .map((id) => permissionMap.get(id)) .filter((p): p is SysPermission => Boolean(p)); const preview = perms.slice(0, 3); const totalCount = permIds.length; return ( <>
权限概览 {`${totalCount}个权限`}
{preview.length ? ( preview.map((p) => ( {p.name} )) ) : ( {totalCount ? "已选权限" : "暂无权限"} )}
); }; return (
系统角色权限 设置系统中不同角色的访问权限和操作边界
{can("sys_role:create") && ( )}
{data.map((role) => (
{can("sys_role:update") && (
{role.roleName}
{`ID: ${role.roleCode || role.roleId}`}
{renderRolePermissions(role)}
最后同步 {role.updatedAt ? "刚刚" : "刚刚"}
))} {!data.length && !loading && (
暂无角色
)}
{editing ? "编辑角色" : "创建新角色"}
} footer={
} >
权限选择
{ const raw = Array.isArray(keys) ? keys : keys.checked; const normalized = (raw as Array).map((k) => Number(k)); setSelectedPermIds(normalized.filter((id) => !Number.isNaN(id))); }} defaultExpandAll />
); }