chore: initial commit
This commit is contained in:
106
src/pages/system/role/components/assign-menus-dialog.tsx
Normal file
106
src/pages/system/role/components/assign-menus-dialog.tsx
Normal file
@@ -0,0 +1,106 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
import { toast } from 'sonner'
|
||||
|
||||
import { assignSysRoleMenus, getAllSysMenus, getSysRoleMenus } from '@/api'
|
||||
import { CheckboxTree, useCheckboxTree, type CheckboxTreeNode } from '@/components/checkbox-tree'
|
||||
import { Button } from '@/components/ui/button.tsx'
|
||||
import {
|
||||
Dialog,
|
||||
DialogClose,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from '@/components/ui/dialog.tsx'
|
||||
import { Spinner } from '@/components/ui/spinner.tsx'
|
||||
import type { SysMenu, SysRole } from '@/schemas'
|
||||
|
||||
interface Props {
|
||||
currentRow?: SysRole | null
|
||||
onClose: () => void
|
||||
onConfirm: () => void
|
||||
open: boolean
|
||||
}
|
||||
|
||||
const buildTreeData = (data: SysMenu[], parentId: string | null = null): CheckboxTreeNode[] => {
|
||||
return data
|
||||
.filter((item) => (item.parent_id?.toString() ?? null) === parentId)
|
||||
.map((item) => {
|
||||
const children = buildTreeData(data, item.id.toString())
|
||||
return {
|
||||
id: item.id.toString(),
|
||||
label: item.name,
|
||||
data: item,
|
||||
children: children.length > 0 ? children : [],
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function AssignMenusDialog({ open, onClose, onConfirm, currentRow }: Props) {
|
||||
const [treeData, setTreeData] = useState<CheckboxTreeNode[]>([])
|
||||
const { getNodeState, toggleNode, checkedIds, setCheckedIds } = useCheckboxTree(treeData, [])
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
const fetchMenus = async () => {
|
||||
const { data: menus } = await getAllSysMenus()
|
||||
const { data: checkedMenus } = await getSysRoleMenus(currentRow?.id as number)
|
||||
setTreeData(buildTreeData(menus))
|
||||
setCheckedIds(checkedMenus.map((item) => item.id.toString()))
|
||||
}
|
||||
|
||||
if (open && currentRow?.id) fetchMenus()
|
||||
}, [open, currentRow, setCheckedIds])
|
||||
|
||||
const handleConfirm = async () => {
|
||||
try {
|
||||
setLoading(true)
|
||||
await assignSysRoleMenus(
|
||||
currentRow?.id as number,
|
||||
checkedIds.map((item) => parseInt(item)),
|
||||
)
|
||||
toast('操作成功!')
|
||||
onConfirm()
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={onClose}>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>分配菜单权限</DialogTitle>
|
||||
<DialogDescription />
|
||||
</DialogHeader>
|
||||
|
||||
<div className='h-125 overflow-y-auto'>
|
||||
<CheckboxTree
|
||||
data={treeData}
|
||||
getNodeState={getNodeState}
|
||||
onToggle={toggleNode}
|
||||
renderLabel={(node: CheckboxTreeNode) => (
|
||||
<div className='flex gap-2'>
|
||||
<div>{node.data?.name}</div>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<DialogFooter>
|
||||
<DialogClose asChild>
|
||||
<Button disabled={loading} variant='outline'>
|
||||
取消
|
||||
</Button>
|
||||
</DialogClose>
|
||||
<Button disabled={loading} onClick={handleConfirm}>
|
||||
保存
|
||||
{loading && <Spinner data-icon='inline-start' />}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user