chore: initial commit

This commit is contained in:
2026-07-22 17:50:30 +08:00
parent d46cdd676e
commit 3abf272e33
190 changed files with 18073 additions and 0 deletions

View 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>
)
}