diff --git a/package.json b/package.json
index 0fca715..6ff1fe5 100644
--- a/package.json
+++ b/package.json
@@ -39,6 +39,7 @@
"react-layout-kit": "^1.9.0",
"react-rnd": "^10.4.2-test2",
"react-use": "^17.5.0",
+ "throttle-debounce": "^5.0.0",
"wonka": "^6.3.4"
},
"devDependencies": {
diff --git a/src/layout/_authenticated.tsx b/src/_authenticatedRoute.tsx
similarity index 76%
rename from src/layout/_authenticated.tsx
rename to src/_authenticatedRoute.tsx
index aeec104..7c72a4d 100644
--- a/src/layout/_authenticated.tsx
+++ b/src/_authenticatedRoute.tsx
@@ -1,7 +1,7 @@
import { isAuthenticated } from '@/utils/auth.ts'
-import { createFileRoute,redirect } from '@tanstack/react-router'
+import { createFileRoute, redirect } from '@tanstack/react-router'
-export const Route = createFileRoute('/_authenticated')({
+export const AuthenticatedRoute = createFileRoute('/_authenticated')({
beforeLoad: async ({ location }) => {
if (!isAuthenticated()) {
throw redirect({
diff --git a/src/components/loading/index.tsx b/src/components/loading/index.tsx
index dae467b..b4ba7bd 100644
--- a/src/components/loading/index.tsx
+++ b/src/components/loading/index.tsx
@@ -1,17 +1,43 @@
-import React from 'react'
+import { useEffect, useState } from 'react'
import { useStyles } from './style.ts'
+import { debounce } from 'throttle-debounce'
interface ILoading {
loading: boolean,
className?: string
+ //延时加载
+ delay?: number
}
-export const Loading = ({ loading, className }: ILoading) => {
+function shouldDelay(loading?: boolean, delay?: number): boolean {
+ return !!loading && !!delay && !isNaN(Number(delay))
+}
+
+export const Loading = ({ loading, className, delay }: ILoading) => {
const { styles, cx } = useStyles({ className })
- return (
-
+ const [ isLoading, setLoading ] = useState(() => {
+ return loading && !shouldDelay(loading, delay)
+ })
+
+ useEffect(() => {
+ if (loading) {
+ const loadingFunc = debounce(delay, () => {
+ setLoading(true)
+ })
+ loadingFunc()
+ return () => {
+ loadingFunc?.cancel?.()
+ }
+ }
+
+ setLoading(false)
+
+ }, [ loading, delay ])
+
+ const render = () => {
+ return
- )
+ }
+
+ return render()
}
export default Loading
\ No newline at end of file
diff --git a/src/components/loading/style.ts b/src/components/loading/style.ts
index aa6f69a..3f0bfe7 100644
--- a/src/components/loading/style.ts
+++ b/src/components/loading/style.ts
@@ -1,12 +1,12 @@
import { createStyles } from '@/theme'
// Define styles using createStyles
-export const useStyles = createStyles(({ token, css, cx, prefixCls }, { className }) => {
+export const useStyles = createStyles(({ token, css, cx, prefixCls }, props: any) => {
const prefix = `${prefixCls}-${token.proPrefix}-loading`
return {
- container: cx(prefix, className),
+ container: cx(prefix, props.className),
base: css`
--tw-translate-x: 0;
diff --git a/src/components/user-picker/Item.tsx b/src/components/user-picker/Item.tsx
new file mode 100644
index 0000000..8bd15b5
--- /dev/null
+++ b/src/components/user-picker/Item.tsx
@@ -0,0 +1,22 @@
+import { IUser } from '@/types/user'
+import { useAtom } from 'jotai'
+import { useStyle } from './style.ts'
+import { Checkbox } from 'antd'
+
+export const Item = ( props: {
+ value: IUser,
+ onChange:( value: IUser)=>void
+} )=>{
+
+ const { styles } = useStyle()
+
+
+ return (
+
+ }>
+ {props.value.name}
+
+
+ )
+
+}
\ No newline at end of file
diff --git a/src/components/user-picker/UserPicker.tsx b/src/components/user-picker/UserPicker.tsx
new file mode 100644
index 0000000..d2c015a
--- /dev/null
+++ b/src/components/user-picker/UserPicker.tsx
@@ -0,0 +1,61 @@
+import { Modal, ModalProps, Select, SelectProps } from 'antd'
+import { memo } from 'react'
+import { Flexbox } from 'react-layout-kit'
+import { useStyle } from './style.ts'
+
+export interface UserSelectProps extends SelectProps {
+
+}
+
+export interface UserModelProps extends ModalProps {
+
+}
+
+export type UserPickerProps =
+ | {
+ type?: 'modal';
+ /** Props for the modal component */
+} & UserModelProps
+ | {
+ type: 'select';
+ /** Props for the select component */
+} & UserSelectProps
+
+const UserSelect = memo((props: UserSelectProps) => {
+ console.log(props)
+ return (
+
+ )
+})
+
+const UserModel = memo(({ open, ...props }: UserModelProps) => {
+ const { styles } = useStyle()
+
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ )
+})
+
+
+const UserPicker = memo(({ type, ...props }: UserPickerProps) => {
+
+ return type === 'modal' ?
:
+})
+
+export default UserPicker
\ No newline at end of file
diff --git a/src/components/user-picker/index.ts b/src/components/user-picker/index.ts
new file mode 100644
index 0000000..f445245
--- /dev/null
+++ b/src/components/user-picker/index.ts
@@ -0,0 +1 @@
+export * from './UserPicker.tsx'
\ No newline at end of file
diff --git a/src/components/user-picker/store.ts b/src/components/user-picker/store.ts
new file mode 100644
index 0000000..3ec8af6
--- /dev/null
+++ b/src/components/user-picker/store.ts
@@ -0,0 +1,5 @@
+import { IUser } from '@/types/user'
+import { atom } from 'jotai'
+
+export const userSelectedAtom = atom
([])
+
diff --git a/src/components/user-picker/style.ts b/src/components/user-picker/style.ts
new file mode 100644
index 0000000..fdc2942
--- /dev/null
+++ b/src/components/user-picker/style.ts
@@ -0,0 +1,25 @@
+import { createStyles } from '@/theme'
+
+export const useStyle = createStyles(({ token, css, cx, prefixCls }) => {
+ const prefix = `${prefixCls}-${token?.proPrefix}-user-picker`
+
+ const list = css``
+
+ const listItem = css`
+
+ padding: 5px;
+ height: 40px;
+ background-color: ${token.colorBgContainer};
+
+ :hover {
+ background-color: ${token.controlItemBgActiveHover};
+ }
+
+ `
+
+ return {
+ container: cx(prefix),
+ list,
+ listItem,
+ }
+})
\ No newline at end of file
diff --git a/src/pages/list/list.tsx b/src/pages/list/list.tsx
deleted file mode 100644
index 7335122..0000000
--- a/src/pages/list/list.tsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import { createLazyRoute } from '@tanstack/react-router'
-import { ProCard } from '@ant-design/pro-components'
-const List = () => {
- return (
-
- 列表页面
-
- )
-}
-export const Route = createLazyRoute('/list/index')({
- component: List,
-})
-
-
-export default List
\ No newline at end of file
diff --git a/src/pages/list/tree.tsx b/src/pages/list/tree.tsx
deleted file mode 100644
index 005dcbc..0000000
--- a/src/pages/list/tree.tsx
+++ /dev/null
@@ -1,146 +0,0 @@
-import { LightFilter, PageContainer, ProCard, ProColumns, ProTable } from '@ant-design/pro-components'
-import { Tree, Input, Space, Button } from 'antd'
-import { createLazyRoute } from '@tanstack/react-router'
-import { departmentAtom } from '../../store/department.ts'
-import { useAtomValue } from 'jotai'
-import { getIcon } from '../../components/icon'
-import dayjs from 'dayjs'
-
-//递归渲染树形结构,将name->title, id->key
-const renderTree = (data: any[]) => {
- return data?.map((item) => {
- if (item.children) {
- return {
- title: item.name,
- key: item.id,
- children: renderTree(item.children),
- }
- }
- return {
- title: item.name,
- key: item.id,
- }
- })
-}
-
-
-const columns: ProColumns[] = [
- {
- title: '姓名',
- dataIndex: 'name',
- render: (_) => {_},
- formItemProps: {
- lightProps: {
- labelFormatter: (value) => `app-${value}`,
- },
- },
- },
- {
- title: '帐号',
- dataIndex: 'account',
- },
- {
- title: '创建者',
- dataIndex: 'creator',
- valueType: 'select',
- search: false,
- valueEnum: {
- all: { text: '全部' },
- 付小小: { text: '付小小' },
- 曲丽丽: { text: '曲丽丽' },
- 林东东: { text: '林东东' },
- 陈帅帅: { text: '陈帅帅' },
- 兼某某: { text: '兼某某' },
- },
- },
- //操作
- {
- title: '操作',
- valueType: 'option',
- render: (_, record) => {
- return [
- {
- alert('edit')
- }}>编辑,
- {
- alert('delete')
- }}>删除,
- ]
- }
- },
-]
-
-const TreePage = () => {
-
- const { data, isError, isPending } = useAtomValue(departmentAtom)
-
- if (isError) {
- return Error
- }
- // if (isPending){
- // return Loading
- // }
-
- return (
-
-
-
-
-
-
-
{
- alert(value)
- },
- },
- actions: [
- ,
- ],
- }}
-
- />
-
-
-
-
-
- )
-}
-
-
-export default TreePage
\ No newline at end of file
diff --git a/src/pages/system/departments/components/DepartmentTree.tsx b/src/pages/system/departments/components/DepartmentTree.tsx
index 2aeabb3..b51f828 100644
--- a/src/pages/system/departments/components/DepartmentTree.tsx
+++ b/src/pages/system/departments/components/DepartmentTree.tsx
@@ -1,10 +1,11 @@
+import { usePageStoreOptions } from '@/store'
import { Empty, Spin, Tree } from 'antd'
import { useStyle } from '../style.ts'
import { useTranslation } from '@/i18n.ts'
import { useSetAtom } from 'jotai'
-import { selectedDepartAtom, departTreeAtom, batchIdsAtom } from '../store.ts'
+import { selectedDepartAtom, departTreeAtom, batchIdsAtom } from '@/store/department.ts'
import { FormInstance } from 'antd/lib'
-import { useAtomValue } from 'jotai/index'
+import { useAtomValue } from 'jotai'
import { TreeNodeRender } from './TreeNodeRender.tsx'
import { useEffect, useRef } from 'react'
import { flattenTree } from '@/utils'
@@ -13,69 +14,69 @@ import { IDepartment } from '@/types/department'
export const DepartmentTree = ({ form }: { form: FormInstance }) => {
- const { styles } = useStyle()
- const { t } = useTranslation()
- const setIds = useSetAtom(batchIdsAtom)
- const setCurrent = useSetAtom(selectedDepartAtom)
- const { data = [], isLoading } = useAtomValue(departTreeAtom)
- const flattenMenusRef = useRef([])
+ const { styles } = useStyle()
+ const { t } = useTranslation()
+ const setIds = useSetAtom(batchIdsAtom, usePageStoreOptions())
+ const setCurrent = useSetAtom(selectedDepartAtom, usePageStoreOptions())
+ const { data = [], isLoading } = useAtomValue(departTreeAtom, usePageStoreOptions())
+ const flattenMenusRef = useRef([])
- useDeepCompareEffect(() => {
+ useDeepCompareEffect(() => {
- if (isLoading) return
+ if (isLoading) return
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
- // @ts-ignore array
- if (data.length) {
- // @ts-ignore flattenTree
- flattenMenusRef.current = flattenTree(data as any)
- }
-
- }, [ data, isLoading ])
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+ // @ts-ignore array
+ if (data.length) {
+ // @ts-ignore flattenTree
+ flattenMenusRef.current = flattenTree(data as any)
+ }
- useEffect(() => {
+ }, [ data, isLoading ])
- return () => {
- setCurrent({} as IDepartment)
- }
- }, [])
+ useEffect(() => {
- const renderEmpty = () => {
- if ((data as any).length > 0 || isLoading) return null
- return
+ return () => {
+ setCurrent({} as IDepartment)
}
+ }, [])
+
+ const renderEmpty = () => {
+ if ((data as any).length > 0 || isLoading) return null
+ return
+ }
- return (<>
-
- {
- renderEmpty()
- }
- {
- return ()
- }}
- fieldNames={{
- title: 'name',
- key: 'id'
- }}
- onSelect={(item) => {
- const current = flattenMenusRef.current?.find((menu) => menu.id === item[0])
- setCurrent(current as IDepartment)
- form.setFieldsValue({ ...current })
- }}
- onCheck={(item) => {
- setIds(item as number[])
- }}
- // checkable={true}
- showIcon={false}
- />
-
- >
- )
+ return (<>
+
+ {
+ renderEmpty()
+ }
+ {
+ return ()
+ }}
+ fieldNames={{
+ title: 'name',
+ key: 'id'
+ }}
+ onSelect={(item) => {
+ const current = flattenMenusRef.current?.find((menu) => menu.id === item[0])
+ setCurrent(current as IDepartment)
+ form.setFieldsValue({ ...current })
+ }}
+ onCheck={(item) => {
+ setIds(item as number[])
+ }}
+ // checkable={true}
+ showIcon={false}
+ />
+
+ >
+ )
}
export default DepartmentTree
\ No newline at end of file
diff --git a/src/pages/system/departments/components/TreeNodeRender.tsx b/src/pages/system/departments/components/TreeNodeRender.tsx
index 4044f2b..89192c0 100644
--- a/src/pages/system/departments/components/TreeNodeRender.tsx
+++ b/src/pages/system/departments/components/TreeNodeRender.tsx
@@ -1,58 +1,59 @@
+import { usePageStoreOptions } from '@/store'
import { memo } from 'react'
import { MenuItem } from '@/types'
import { Popconfirm, Space, TreeDataNode } from 'antd'
import { FormInstance } from 'antd/lib'
import { useTranslation } from '@/i18n.ts'
import { useStyle } from '../style.ts'
-import { useAtomValue, useSetAtom } from 'jotai/index'
-import { selectedDepartAtom, deleteDepartAtom, defaultDepart } from '../store.ts'
+import { useAtomValue, useSetAtom } from 'jotai'
+import { selectedDepartAtom, deleteDepartAtom, defaultDepart } from '@/store/department.ts'
import { PlusOutlined } from '@ant-design/icons'
import ActionIcon, { DeleteAction } from '@/components/icon/action'
export const TreeNodeRender = memo(({ node, form }: { node: MenuItem & TreeDataNode, form: FormInstance }) => {
- const { name } = node
- const { t } = useTranslation()
- const { styles } = useStyle()
- const { mutate } = useAtomValue(deleteDepartAtom)
+ const { name } = node
+ const { t } = useTranslation()
+ const { styles } = useStyle()
+ const { mutate } = useAtomValue(deleteDepartAtom, usePageStoreOptions())
- const setCurrent = useSetAtom(selectedDepartAtom)
+ const setCurrent = useSetAtom(selectedDepartAtom, usePageStoreOptions())
- return (
-
-
{name as any}
-
+ return (
+
+
{name as any}
+
}
- title={t('actions.add', '添加')}
- onClick={(e) => {
- // console.log('add')
- e.stopPropagation()
- e.preventDefault()
- const data = {
- ...defaultDepart,
- parent_id: node.id,
- }
- setCurrent(data)
- form.setFieldsValue(data)
+ size={12}
+ icon={}
+ title={t('actions.add', '添加')}
+ onClick={(e) => {
+ // console.log('add')
+ e.stopPropagation()
+ e.preventDefault()
+ const data = {
+ ...defaultDepart,
+ parent_id: node.id,
+ }
+ setCurrent(data)
+ form.setFieldsValue(data)
- }}/>
+ }}/>
{
- mutate([ (node as any).id ])
- }}
+ title={t('message.deleteConfirm', '确定要删除吗?')}
+ onConfirm={() => {
+ mutate([ (node as any).id ])
+ }}
>
{
- e.stopPropagation()
- e.stopPropagation()
- }}/>
+ size={12}
+ onClick={(e) => {
+ e.stopPropagation()
+ e.stopPropagation()
+ }}/>
-
- )
+
+ )
})
\ No newline at end of file
diff --git a/src/pages/system/departments/index.tsx b/src/pages/system/departments/index.tsx
index 88734f3..07016e7 100644
--- a/src/pages/system/departments/index.tsx
+++ b/src/pages/system/departments/index.tsx
@@ -1,3 +1,4 @@
+import { usePageStoreOptions } from '@/store'
import { PageContainer, ProCard } from '@ant-design/pro-components'
import { Flexbox } from 'react-layout-kit'
import { DraggablePanel } from '@/components/draggable-panel'
@@ -6,149 +7,149 @@ import { useStyle } from './style.ts'
import DepartmentTree from './components/DepartmentTree.tsx'
import { Alert, Button, Divider, Form, Input, InputNumber, InputRef, notification, TreeSelect } from 'antd'
import { PlusOutlined } from '@ant-design/icons'
-import { defaultDepart, selectedDepartAtom, departTreeAtom, saveOrUpdateDepartAtom } from './store.ts'
+import { defaultDepart, selectedDepartAtom, departTreeAtom, saveOrUpdateDepartAtom } from '@/store/department.ts'
import { useAtom, useAtomValue, } from 'jotai'
import Glass from '@/components/glass'
import { useEffect, useRef } from 'react'
const Departments = () => {
- const { t } = useTranslation()
- const { styles, cx } = useStyle()
- const [ form ] = Form.useForm()
- const inputRef = useRef()
- const { data } = useAtomValue(departTreeAtom)
- const { mutate, isPending, isError, error } = useAtomValue(saveOrUpdateDepartAtom)
- const [ current, setCurrent ] = useAtom(selectedDepartAtom)
+ const { t } = useTranslation()
+ const { styles, cx } = useStyle()
+ const [ form ] = Form.useForm()
+ const inputRef = useRef()
+ const { data } = useAtomValue(departTreeAtom, usePageStoreOptions())
+ const { mutate, isPending, isError, error } = useAtomValue(saveOrUpdateDepartAtom, usePageStoreOptions())
+ const [ current, setCurrent ] = useAtom(selectedDepartAtom, usePageStoreOptions())
- useEffect(() => {
+ useEffect(() => {
- if (isError) {
- notification.error({
- message: t('message.error', '错误'),
- description: (error as any).message ?? t('message.saveFail', '保存失败'),
- })
- }
- }, [ isError ])
+ if (isError) {
+ notification.error({
+ message: t('message.error', '错误'),
+ description: (error as any).message ?? t('message.saveFail', '保存失败'),
+ })
+ }
+ }, [ isError ])
- useEffect(() => {
- if (current.id === 0 && inputRef.current) {
- inputRef.current.focus()
- }
- }, [ current ])
+ useEffect(() => {
+ if (current.id === 0 && inputRef.current) {
+ inputRef.current.focus()
+ }
+ }, [ current ])
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- >}
- >
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >}
+ >
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
-
-
+
+
-
-
-
-
- )
+
+
+
+
+ )
}
diff --git a/src/pages/system/departments/store.ts b/src/pages/system/departments/store.ts
deleted file mode 100644
index 4a582a8..0000000
--- a/src/pages/system/departments/store.ts
+++ /dev/null
@@ -1,84 +0,0 @@
-import { atomWithMutation, atomWithQuery, queryClientAtom } from 'jotai-tanstack-query'
-import systemServ from '@/service/system.ts'
-import { IApiResult, IPage } from '@/types'
-import { IDepartment } from '@/types/department'
-import { atom, createStore } from 'jotai'
-import { t } from 'i18next'
-import { message } from 'antd'
-
-
-const store = createStore()
-
-export const departPageAtom = atom({})
-
-export const defaultDepart = {
- id: 0,
- parent_id: 0,
- name: '',
- manager_user_id: 0,
- phone: '',
- sort: 0,
-} as IDepartment
-
-export const batchIdsAtom = atom([])
-
-export const selectedDepartAtom = atom({} as IDepartment)
-
-export const departTreeAtom = atomWithQuery(() => {
-
- return {
- queryKey: [ 'departTree' ],
- queryFn: async () => {
- return await systemServ.dept.tree()
- },
- select: (res) => {
- return res.data.tree ?? []
- }
- }
-})
-
-export const saveOrUpdateDepartAtom = atomWithMutation((get) => {
-
- return {
- mutationKey: [ 'saveOrUpdateDepart' ],
- mutationFn: async (data: IDepartment) => {
- if (data.id) {
- return await systemServ.dept.update(data)
- }
- return await systemServ.dept.add(data)
- },
- onSuccess: (res) => {
- const isAdd = !!res.data?.id
- message.success(t(isAdd ? 'message.saveSuccess' : 'message.editSuccess', '保存成功'))
-
- if (isAdd) {
- store.set(selectedDepartAtom, prev => ({
- ...prev,
- id: res.data.id
- }))
- }
-
- get(queryClientAtom).invalidateQueries({ queryKey: [ 'departTree' ] }).then()
- }
- }
-
-})
-
-
-export const deleteDepartAtom = atomWithMutation((get) => {
-
- return {
- mutationKey: [ 'deleteDepart', get(batchIdsAtom) ],
- mutationFn: async (ids: number[]) => {
- return await systemServ.dept.batchDelete(ids)
- },
- onSuccess: () => {
- message.success(t('message.deleteSuccess', '删除成功'))
- store.set(batchIdsAtom, [])
- get(queryClientAtom).invalidateQueries({ queryKey: [ 'departTree' ] }).then()
-
- }
- }
-
-})
-
diff --git a/src/pages/system/menus/components/BatchButton.tsx b/src/pages/system/menus/components/BatchButton.tsx
index 8e5a45c..b6e938d 100644
--- a/src/pages/system/menus/components/BatchButton.tsx
+++ b/src/pages/system/menus/components/BatchButton.tsx
@@ -1,34 +1,35 @@
+import { usePageStoreOptions } from '@/store'
import { Button, Popconfirm } from 'antd'
import { useAtomValue } from 'jotai'
-import { batchIdsAtom, deleteMenuAtom } from '../store.ts'
+import { batchIdsAtom, deleteMenuAtom } from '@/store/menu.ts'
import { useTranslation } from '@/i18n.ts'
const BatchButton = () => {
- const { t } = useTranslation()
- const { isPending, mutate, } = useAtomValue(deleteMenuAtom)
- const ids = useAtomValue(batchIdsAtom)
+ const { t } = useTranslation()
+ const { isPending, mutate, } = useAtomValue(deleteMenuAtom, usePageStoreOptions())
+ const ids = useAtomValue(batchIdsAtom, usePageStoreOptions())
- if (ids.length === 0) {
- return null
- }
+ if (ids.length === 0) {
+ return null
+ }
- return (
- {
- mutate(ids as number[])
- }}
- title={t('message.batchDelete', '确定要删除所选数据吗?')}>
-
-
- )
+ return (
+ {
+ mutate(ids as number[])
+ }}
+ title={t('message.batchDelete', '确定要删除所选数据吗?')}>
+
+
+ )
}
export default BatchButton
\ No newline at end of file
diff --git a/src/pages/system/menus/components/MenuTree.tsx b/src/pages/system/menus/components/MenuTree.tsx
index ae1ee6c..5f95081 100644
--- a/src/pages/system/menus/components/MenuTree.tsx
+++ b/src/pages/system/menus/components/MenuTree.tsx
@@ -1,11 +1,12 @@
+import { usePageStoreOptions } from '@/store'
import { Empty, Spin, Tree } from 'antd'
import { MenuItem } from '@/types'
import { useStyle } from '../style.ts'
import { useTranslation } from '@/i18n.ts'
import { useSetAtom } from 'jotai'
-import { batchIdsAtom, menuDataAtom, selectedMenuAtom } from '../store.ts'
+import { batchIdsAtom, menuDataAtom, selectedMenuAtom } from '@/store/menu.ts'
import { FormInstance } from 'antd/lib'
-import { useAtomValue } from 'jotai/index'
+import { useAtomValue } from 'jotai'
import { TreeNodeRender } from './TreeNodeRender.tsx'
import { useEffect, useRef } from 'react'
import { flattenTree } from '@/utils'
@@ -14,71 +15,71 @@ import { useDeepCompareEffect } from 'react-use'
const MenuTree = ({ form }: { form: FormInstance }) => {
- const { styles } = useStyle()
- const { t } = useTranslation()
- const setCurrentMenu = useSetAtom(selectedMenuAtom)
- const setIds = useSetAtom(batchIdsAtom)
- const { data = [], isLoading } = useAtomValue(menuDataAtom)
- const flattenMenusRef = useRef