import { useState, useEffect, useCallback } from 'react'; import { toast } from 'sonner'; import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from '@/components/ui/dialog'; import { Plus, Shield, Edit, Eye, Trash2 } from 'lucide-react'; import { userApi } from '@/services/api'; import { useConfirm } from '@/components/ui/confirm-dialog'; import type { Role } from '@/types'; import { RoleFormDialog, type RoleFormData, type PermissionOption, } from './RoleFormDialog'; interface SystemRolesTabProps { selectedRole: Role | null; setSelectedRole: (role: Role | null) => void; } // 将后端角色数据规范化为前端 Role 类型 // Logan.Li function normalizeRole(raw: any): Role { const rawPerms = Array.isArray(raw.permissions) ? raw.permissions : []; return { id: String(raw.id ?? ''), name: raw.name ?? '', code: raw.code ?? '', description: raw.description ?? '', // 后端可能返回权限对象数组或字符串数组,统一映射为编码字符串数组 permissions: rawPerms.map((p: any) => (typeof p === 'string' ? p : p?.code ?? '')).filter(Boolean), createdAt: raw.createdAt ?? raw.created_at ?? '', // 保留原始权限 ID 供编辑使用 _permissionIds: Array.isArray(raw.permissions) ? raw.permissions.map((p: any) => (typeof p === 'object' ? Number(p.id) : 0)).filter(Boolean) : [], } as Role & { _permissionIds: number[] }; } const emptyForm: RoleFormData = { name: '', code: '', description: '', permission_ids: [], }; export function SystemRolesTab({ selectedRole, setSelectedRole }: SystemRolesTabProps) { const confirm = useConfirm(); const [roles, setRoles] = useState([]); const [loading, setLoading] = useState(true); const [permissions, setPermissions] = useState([]); // 新建 / 编辑弹窗 const [dialogOpen, setDialogOpen] = useState(false); const [editingRole, setEditingRole] = useState(null); const [form, setForm] = useState({ ...emptyForm }); const [saving, setSaving] = useState(false); const loadRoles = useCallback(async () => { setLoading(true); try { const resp = await userApi.getRoles(); const list = resp?.list ?? []; setRoles(list.map(normalizeRole)); } catch (err) { setRoles([]); } finally { setLoading(false); } }, []); const loadPermissions = useCallback(async () => { try { const resp = await userApi.getPermissions(); const list = resp?.list ?? []; setPermissions( list.map((p: any) => ({ id: Number(p.id), name: p.name ?? p.code ?? '', code: p.code ?? '', type: p.type, })) ); } catch { setPermissions([]); } }, []); useEffect(() => { loadRoles(); loadPermissions(); }, [loadRoles, loadPermissions]); const openCreate = () => { setEditingRole(null); setForm({ ...emptyForm }); setDialogOpen(true); }; const openEdit = (role: any) => { setEditingRole(role); setForm({ name: role.name ?? '', code: role.code ?? '', description: role.description ?? '', permission_ids: Array.isArray(role._permissionIds) ? [...role._permissionIds] : [], }); setDialogOpen(true); }; const handleSubmit = async () => { if (!form.name.trim()) { toast.error('请输入角色名称'); return; } if (!form.code.trim()) { toast.error('请输入角色编码'); return; } setSaving(true); try { const payload = { name: form.name.trim(), code: form.code.trim(), description: form.description.trim(), permission_ids: form.permission_ids, }; if (editingRole) { await userApi.updateRole(editingRole.id, payload); toast.success('角色更新成功'); } else { await userApi.createRole(payload); toast.success('角色创建成功'); } setDialogOpen(false); await loadRoles(); } catch (err: any) { toast.error(err?.message || '保存失败'); } finally { setSaving(false); } }; const handleDelete = async (role: any) => { const ok = await confirm({ title: '删除角色', description: `确认删除角色「${role.name}」吗?该操作不可恢复。`, confirmText: '删除', variant: 'destructive', }); if (!ok) return; try { await userApi.deleteRole(role.id); toast.success('角色已删除'); await loadRoles(); } catch (err: any) { toast.error(err?.message || '删除失败'); } }; return ( <>
{loading ? (
) : roles.length === 0 ? (

暂无角色数据

) : (
{roles.map((role) => (
{role.name} {role.code}

{role.description || '暂无描述'}

{role.permissions.slice(0, 5).map((permission) => ( {permission} ))} {role.permissions.length > 5 && ( +{role.permissions.length - 5} )} {role.permissions.length === 0 && ( 未分配权限 )}
))}
)} {/* 角色详情 Dialog */} setSelectedRole(null)} onEdit={(r) => { setSelectedRole(null); openEdit(r); }} /> {/* 新建 / 编辑角色 Dialog */} ); } // 角色详情查看 Dialog function RoleDetailDialog({ role, onClose, onEdit, }: { role: Role | null; onClose: () => void; onEdit: (role: Role) => void; }) { return ( !v && onClose()}> {role?.name} 编码:{role?.code}

描述

{role?.description || '暂无描述'}

权限列表

{role && role.permissions.length > 0 ? (
{role.permissions.map((p) => ( {p} ))}
) : (

未分配权限

)}
); }