|
@ -7,7 +7,7 @@ import { userMenuDataAtom } from '@/store/system/user.ts' |
|
|
import { MenuItem } from '@/global' |
|
|
import { MenuItem } from '@/global' |
|
|
import { ProConfigProvider, ProLayout, } from '@ant-design/pro-components' |
|
|
import { ProConfigProvider, ProLayout, } from '@ant-design/pro-components' |
|
|
import { zhCNIntl, enUSIntl } from '@ant-design/pro-provider/es/intl' |
|
|
import { zhCNIntl, enUSIntl } from '@ant-design/pro-provider/es/intl' |
|
|
import { CatchBoundary, Link, Outlet } from '@tanstack/react-router' |
|
|
|
|
|
|
|
|
import { CatchBoundary, Link, Outlet, useNavigate } from '@tanstack/react-router' |
|
|
import { ConfigProvider } from '@/components/config-provider' |
|
|
import { ConfigProvider } from '@/components/config-provider' |
|
|
import { useEffect, useRef, useState } from 'react' |
|
|
import { useEffect, useRef, useState } from 'react' |
|
|
import { useAtomValue } from 'jotai' |
|
|
import { useAtomValue } from 'jotai' |
|
@ -15,7 +15,9 @@ import { useStyle } from '@/layout/style.ts' |
|
|
import zh from 'antd/locale/zh_CN' |
|
|
import zh from 'antd/locale/zh_CN' |
|
|
import en from 'antd/locale/en_US' |
|
|
import en from 'antd/locale/en_US' |
|
|
import type { MenuDataItem } from '@ant-design/pro-layout/es/typing' |
|
|
import type { MenuDataItem } from '@ant-design/pro-layout/es/typing' |
|
|
import { flattenTree } from '@/utils' |
|
|
|
|
|
|
|
|
import { convertToMenu, flattenTree } from '@/utils' |
|
|
|
|
|
import { Flex, Menu, Space } from 'antd' |
|
|
|
|
|
import { MenuFoldOutlined, MenuUnfoldOutlined } from '@ant-design/icons' |
|
|
|
|
|
|
|
|
//根据menuData生成Breadcrumb所需的数据
|
|
|
//根据menuData生成Breadcrumb所需的数据
|
|
|
const getBreadcrumbData = (menuData: MenuItem[], pathname: string) => { |
|
|
const getBreadcrumbData = (menuData: MenuItem[], pathname: string) => { |
|
@ -41,11 +43,14 @@ const getBreadcrumbData = (menuData: MenuItem[], pathname: string) => { |
|
|
|
|
|
|
|
|
export default () => { |
|
|
export default () => { |
|
|
|
|
|
|
|
|
|
|
|
const navigate = useNavigate() |
|
|
const { styles } = useStyle() |
|
|
const { styles } = useStyle() |
|
|
const { data: menuData = [], isLoading } = useAtomValue(userMenuDataAtom) |
|
|
const { data: menuData = [], isLoading } = useAtomValue(userMenuDataAtom) |
|
|
const { language } = useAtomValue(appAtom) |
|
|
const { language } = useAtomValue(appAtom) |
|
|
const items = getBreadcrumbData(menuData, location.pathname) |
|
|
const items = getBreadcrumbData(menuData, location.pathname) |
|
|
const [ pathname, setPathname ] = useState(location.pathname) |
|
|
const [ pathname, setPathname ] = useState(location.pathname) |
|
|
|
|
|
const [ openMenuKeys, setOpenKeys ] = useState<string[]>([]) |
|
|
|
|
|
const [ collapsed, setCollapsed ] = useState(false) |
|
|
|
|
|
|
|
|
const menusFlatten = useRef<MenuItem[]>() |
|
|
const menusFlatten = useRef<MenuItem[]>() |
|
|
if (!menusFlatten.current) { |
|
|
if (!menusFlatten.current) { |
|
@ -59,10 +64,12 @@ export default () => { |
|
|
return item ? item.parentName : [] |
|
|
return item ? item.parentName : [] |
|
|
}) |
|
|
}) |
|
|
const childMenuRef = useRef<MenuItem[]>([]) |
|
|
const childMenuRef = useRef<MenuItem[]>([]) |
|
|
|
|
|
|
|
|
childMenuRef.current = menuData.find(item => { |
|
|
|
|
|
|
|
|
const currentMenu = menuData.find(item => { |
|
|
return item.key === rootMenuKeys?.[0] |
|
|
return item.key === rootMenuKeys?.[0] |
|
|
})?.children || [] |
|
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
childMenuRef.current = currentMenu?.children || [] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
useEffect(() => { |
|
|
const item = menusFlatten.current?.find(item => item.path === location.pathname) |
|
|
const item = menusFlatten.current?.find(item => item.path === location.pathname) |
|
@ -71,13 +78,12 @@ export default () => { |
|
|
} |
|
|
} |
|
|
}, [ location.pathname ]) |
|
|
}, [ location.pathname ]) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return ( |
|
|
return ( |
|
|
<div |
|
|
<div |
|
|
className={styles.container} |
|
|
className={styles.container} |
|
|
id="crazy-pro-layout" |
|
|
id="crazy-pro-layout" |
|
|
style={{ |
|
|
style={{ |
|
|
height: '100vh', |
|
|
|
|
|
|
|
|
// height: '100vh',
|
|
|
// overflow: 'auto',
|
|
|
// overflow: 'auto',
|
|
|
}} |
|
|
}} |
|
|
> |
|
|
> |
|
@ -97,16 +103,25 @@ export default () => { |
|
|
header: { |
|
|
header: { |
|
|
colorBgMenuItemSelected: 'rgba(0,0,0,0.04)', |
|
|
colorBgMenuItemSelected: 'rgba(0,0,0,0.04)', |
|
|
}, |
|
|
}, |
|
|
|
|
|
sider: { |
|
|
|
|
|
colorMenuBackground: '#222b45', |
|
|
|
|
|
} |
|
|
}} |
|
|
}} |
|
|
fixedHeader={true} |
|
|
|
|
|
headerContentRender={() => <PageBreadcrumb |
|
|
|
|
|
className={'top-breadcrumb'} |
|
|
|
|
|
showIcon={false} |
|
|
|
|
|
items={items}/>} |
|
|
|
|
|
|
|
|
className={styles.myLayout} |
|
|
|
|
|
// fixedHeader={true}
|
|
|
|
|
|
headerContentRender={false} |
|
|
|
|
|
headerTitleRender={false} |
|
|
|
|
|
menuHeaderRender={() => { |
|
|
|
|
|
return <> |
|
|
|
|
|
<img height={40} |
|
|
|
|
|
src={'https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg'}/> |
|
|
|
|
|
</> |
|
|
|
|
|
}} |
|
|
|
|
|
headerRender={false} |
|
|
title="Crazy Pro" |
|
|
title="Crazy Pro" |
|
|
layout={'mix'} |
|
|
|
|
|
|
|
|
// layout={'mix'}
|
|
|
fixSiderbar={true} |
|
|
fixSiderbar={true} |
|
|
siderWidth={100} |
|
|
|
|
|
|
|
|
siderWidth={65} |
|
|
collapsedButtonRender={false} |
|
|
collapsedButtonRender={false} |
|
|
// collapsed={false}
|
|
|
// collapsed={false}
|
|
|
postMenuData={() => { |
|
|
postMenuData={() => { |
|
@ -137,40 +152,100 @@ export default () => { |
|
|
|
|
|
|
|
|
}} |
|
|
}} |
|
|
menuItemRender={(item: MenuDataItem) => { |
|
|
menuItemRender={(item: MenuDataItem) => { |
|
|
return <span style={{ userSelect: 'none' }} onClick={() => { |
|
|
|
|
|
|
|
|
return (<span style={{ userSelect: 'none' }} onClick={() => { |
|
|
setRootMenuKeys([ (item as any).key || 'dashboard' ]) |
|
|
setRootMenuKeys([ (item as any).key || 'dashboard' ]) |
|
|
setPathname(item.path || '/dashboard') |
|
|
setPathname(item.path || '/dashboard') |
|
|
}} |
|
|
}} |
|
|
> |
|
|
> |
|
|
<Link to={item.path} className={'menu-link'} target={item.type === 'url' ? '_blank' : '_self'}> |
|
|
|
|
|
|
|
|
<Link to={item.path} className={'menu-link'} |
|
|
|
|
|
target={item.type === 'url' ? '_blank' : '_self'}> |
|
|
<span>{item.icon}</span> |
|
|
<span>{item.icon}</span> |
|
|
<span>{item.name}</span> |
|
|
<span>{item.name}</span> |
|
|
</Link> |
|
|
</Link> |
|
|
</span> |
|
|
|
|
|
}} |
|
|
|
|
|
avatarProps={{ |
|
|
|
|
|
// src: 'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
|
|
|
|
|
|
render: () => { |
|
|
|
|
|
return ( |
|
|
|
|
|
<Avatar/> |
|
|
|
|
|
) |
|
|
|
|
|
}, |
|
|
|
|
|
}} |
|
|
|
|
|
actionsRender={(props) => { |
|
|
|
|
|
if (props.isMobile) return [] |
|
|
|
|
|
if (typeof window === 'undefined') return [] |
|
|
|
|
|
return [ |
|
|
|
|
|
<SelectLang/>, |
|
|
|
|
|
] |
|
|
|
|
|
|
|
|
</span>) |
|
|
}} |
|
|
}} |
|
|
|
|
|
avatarProps={false} |
|
|
|
|
|
actionsRender={false} |
|
|
menuProps={{ |
|
|
menuProps={{ |
|
|
className: styles.mySiderMenu, |
|
|
className: styles.mySiderMenu, |
|
|
selectedKeys: rootMenuKeys, |
|
|
selectedKeys: rootMenuKeys, |
|
|
|
|
|
theme: 'dark', |
|
|
}} |
|
|
}} |
|
|
// navTheme={'light'}
|
|
|
|
|
|
|
|
|
loading={isLoading} |
|
|
contentStyle={{ paddingBlock: 0, paddingInline: 0 }} |
|
|
contentStyle={{ paddingBlock: 0, paddingInline: 0 }} |
|
|
|
|
|
{ |
|
|
|
|
|
...{ |
|
|
|
|
|
// "fixSiderbar": true,
|
|
|
|
|
|
// "layout": "side",
|
|
|
|
|
|
'splitMenus': false, |
|
|
|
|
|
'navTheme': 'realDark', |
|
|
|
|
|
'contentWidth': 'Fluid', |
|
|
|
|
|
'colorPrimary': '#1677FF', |
|
|
|
|
|
// "menuHeaderRender": false
|
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
> |
|
|
> |
|
|
<ProLayout |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<Flex className={styles.childMenus}> |
|
|
|
|
|
{ |
|
|
|
|
|
!collapsed && <div className={styles.childMenuTop}> |
|
|
|
|
|
<h2>{currentMenu?.title}</h2> |
|
|
|
|
|
</div> |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
<Menu |
|
|
|
|
|
mode={'inline'} |
|
|
|
|
|
inlineCollapsed={collapsed} |
|
|
|
|
|
selectedKeys={[ location.pathname ]} |
|
|
|
|
|
openKeys={openMenuKeys} |
|
|
|
|
|
onOpenChange={(keys) => { |
|
|
|
|
|
setOpenKeys(keys) |
|
|
|
|
|
}} |
|
|
|
|
|
onClick={(menu) => { |
|
|
|
|
|
const info = menusFlatten.current?.find(item => item.path === menu.key) |
|
|
|
|
|
if (info) { |
|
|
|
|
|
setOpenKeys([ info.path as string ]) |
|
|
|
|
|
navigate({ |
|
|
|
|
|
to: info.path, |
|
|
|
|
|
}) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
}} |
|
|
|
|
|
items={convertToMenu((childMenuRef.current || []), (item => { |
|
|
|
|
|
return { |
|
|
|
|
|
...item, |
|
|
|
|
|
key: item.path, |
|
|
|
|
|
label: item.title, |
|
|
|
|
|
} |
|
|
|
|
|
})) as any} |
|
|
|
|
|
style={!collapsed ? { width: 210 } : {}} |
|
|
|
|
|
/> |
|
|
|
|
|
<div className={styles.childMenuBottom} |
|
|
|
|
|
onClick={() => { |
|
|
|
|
|
setCollapsed(!collapsed) |
|
|
|
|
|
}}> |
|
|
|
|
|
{ |
|
|
|
|
|
collapsed ? <MenuUnfoldOutlined/> : <MenuFoldOutlined/> |
|
|
|
|
|
} |
|
|
|
|
|
</div> |
|
|
|
|
|
</Flex> |
|
|
|
|
|
<Flex flex={1} className={styles.body} aria-description={'main-body'} vertical={true}> |
|
|
|
|
|
<div className={styles.bodyHeader}> |
|
|
|
|
|
<PageBreadcrumb |
|
|
|
|
|
className={'top-breadcrumb'} |
|
|
|
|
|
showIcon={false} |
|
|
|
|
|
items={items}/> |
|
|
|
|
|
<Flex flex={1}> |
|
|
|
|
|
<></> |
|
|
|
|
|
</Flex> |
|
|
|
|
|
<Space className={styles.headerRight}> |
|
|
|
|
|
<SelectLang/> |
|
|
|
|
|
<Avatar/> |
|
|
|
|
|
</Space> |
|
|
|
|
|
</div> |
|
|
|
|
|
<Outlet/> |
|
|
|
|
|
</Flex> |
|
|
|
|
|
{/*<ProLayout |
|
|
className={styles.mySider} |
|
|
className={styles.mySider} |
|
|
headerRender={false} |
|
|
headerRender={false} |
|
|
hasSiderMenu={false} |
|
|
hasSiderMenu={false} |
|
@ -218,8 +293,7 @@ export default () => { |
|
|
// layout: 'side',
|
|
|
// layout: 'side',
|
|
|
}} |
|
|
}} |
|
|
> |
|
|
> |
|
|
<Outlet/> |
|
|
|
|
|
</ProLayout> |
|
|
|
|
|
|
|
|
</ProLayout>*/} |
|
|
</ProLayout> |
|
|
</ProLayout> |
|
|
</ConfigProvider> |
|
|
</ConfigProvider> |
|
|
</ProConfigProvider> |
|
|
</ProConfigProvider> |
|
|