import { useCallback, useEffect, useState } from "react" import { toast } from "sonner" import { getAllPermissions } from "@/actions/permission" import { updateRole } from "@/actions/role" import { Button } from "@/components/ui/button" import { Checkbox } from "@/components/ui/checkbox" import { Dialog, DialogClose, DialogContent, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, } from "@/components/ui/dialog" import { cn } from "@/lib/utils" import type { Role } from "@/models/role" type TreeNode = { id: number name: string description: string children: TreeNode[] } function PermissionRow({ node, depth, selected, onToggle, }: { node: TreeNode depth: number selected: Set onToggle: (id: number, checked: boolean) => void }) { const hasChildren = node.children.length > 0 return ( <>
onToggle(node.id, checked === true)} />
{node.children.map(child => ( ))} ) } export function AssignPermissions(props: { role: Role onSuccess?: () => void }) { const [open, setOpen] = useState(false) const [loading, setLoading] = useState(false) const [submitting, setSubmitting] = useState(false) const [nodes, setNodes] = useState([]) const [selected, setSelected] = useState>(new Set()) const fetchPermissions = useCallback(async () => { setLoading(true) try { const resp = await getAllPermissions() if (!resp.success) throw new Error(resp.message) const data = resp.data ?? [] const map = new Map() data.forEach(p => { map.set(p.id, { id: p.id, name: p.name, description: p.description, children: [], }) }) const roots: TreeNode[] = [] data.forEach(p => { const node = map.get(p.id) if (!node) return if (!p.parent_id) { roots.push(node) } else { map.get(p.parent_id)?.children.push(node) } }) setNodes(roots) } catch (error) { toast.error(error instanceof Error ? error.message : "获取权限列表失败") } finally { setLoading(false) } }, []) useEffect(() => { if (open) fetchPermissions() }, [open, fetchPermissions]) const handleToggle = useCallback((id: number, checked: boolean) => { setSelected(prev => { const next = new Set(prev) if (checked) { next.add(id) } else { next.delete(id) } return next }) }, []) const handleSubmit = async () => { setSubmitting(true) try { const resp = await updateRole({ id: props.role.id, permissions: Array.from(selected), }) if (resp.success) { toast.success("权限分配成功") props.onSuccess?.() setOpen(false) } else { toast.error(resp.message ?? "权限分配失败") } } catch (error) { toast.error(error instanceof Error ? error.message : "接口请求错误") } finally { setSubmitting(false) } } const handleOpenChange = (value: boolean) => { if (value) { setSelected(new Set((props.role.permissions ?? []).map(p => p.id))) } else { setSelected(new Set()) setNodes([]) } setOpen(value) } return ( 分配权限 · {props.role.name}
{loading ? (
加载中...
) : nodes.length === 0 ? (
暂无权限数据
) : (
{nodes.map(node => ( ))}
)}
) }