|
|
@ -9,12 +9,13 @@ import { ProConfigProvider, ProLayout, } from '@ant-design/pro-components' |
|
|
|
import { zhCNIntl, enUSIntl } from '@ant-design/pro-provider/es/intl' |
|
|
|
import { CatchBoundary, Link, Outlet } from '@tanstack/react-router' |
|
|
|
import { ConfigProvider } from '@/components/config-provider' |
|
|
|
import { useState } from 'react' |
|
|
|
import defaultProps from './_defaultProps' |
|
|
|
import { useEffect, useRef, useState } from 'react' |
|
|
|
import { useAtomValue } from 'jotai' |
|
|
|
import { useStyle } from '@/layout/style.ts' |
|
|
|
import zh from 'antd/locale/zh_CN' |
|
|
|
import en from 'antd/locale/en_US' |
|
|
|
import type { MenuDataItem } from '@ant-design/pro-layout/es/typing' |
|
|
|
import { flattenTree } from '@/utils' |
|
|
|
|
|
|
|
//根据menuData生成Breadcrumb所需的数据
|
|
|
|
const getBreadcrumbData = (menuData: MenuItem[], pathname: string) => { |
|
|
@ -46,98 +47,181 @@ export default () => { |
|
|
|
const items = getBreadcrumbData(menuData, location.pathname) |
|
|
|
const [ pathname, setPathname ] = useState(location.pathname) |
|
|
|
|
|
|
|
const menusFlatten = useRef<MenuItem[]>() |
|
|
|
if (!menusFlatten.current) { |
|
|
|
menusFlatten.current = flattenTree<MenuItem>(menuData, { key: 'id', title: 'name' }) |
|
|
|
} |
|
|
|
const [ rootMenuKeys, setRootMenuKeys ] = useState<string[]>(() => { |
|
|
|
const item = menusFlatten.current?.find(item => item.path === location.pathname) |
|
|
|
return item ? item.parentName : [] |
|
|
|
}) |
|
|
|
|
|
|
|
const childMenuRef = useRef<MenuItem[]>([]) |
|
|
|
|
|
|
|
childMenuRef.current = menuData.find(item => { |
|
|
|
return item.key === rootMenuKeys?.[0] |
|
|
|
})?.children || [] |
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
const item = menusFlatten.current?.find(item => item.path === location.pathname) |
|
|
|
if (item && item.key !== rootMenuKeys?.[0]) { |
|
|
|
setRootMenuKeys(item.parentName) |
|
|
|
} |
|
|
|
}, [ location.pathname ]) |
|
|
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
<div |
|
|
|
className={styles.container} |
|
|
|
id="crazy-pro-layout" |
|
|
|
style={{ |
|
|
|
height: '100vh', |
|
|
|
// overflow: 'auto',
|
|
|
|
}} |
|
|
|
> |
|
|
|
<CatchBoundary |
|
|
|
getResetKey={() => 'reset-page'} |
|
|
|
errorComponent={ErrorPage} |
|
|
|
> |
|
|
|
<ProConfigProvider hashed={false} intl={language === 'zh-CN' ? zhCNIntl : enUSIntl}> |
|
|
|
<ConfigProvider |
|
|
|
locale={language === 'zh-CN' ? zh : en} |
|
|
|
getTargetContainer={() => { |
|
|
|
return document.getElementById('crazy-pro-layout') || document.body |
|
|
|
}} |
|
|
|
<div |
|
|
|
className={styles.container} |
|
|
|
id="crazy-pro-layout" |
|
|
|
style={{ |
|
|
|
height: '100vh', |
|
|
|
// overflow: 'auto',
|
|
|
|
}} |
|
|
|
> |
|
|
|
<ProLayout |
|
|
|
headerContentRender={() => <PageBreadcrumb |
|
|
|
className={'top-breadcrumb'} |
|
|
|
showIcon={false} |
|
|
|
items={items}/>} |
|
|
|
title="Crazy Pro" |
|
|
|
{...defaultProps} |
|
|
|
route={{ |
|
|
|
path: '/', |
|
|
|
routes: menuData |
|
|
|
}} |
|
|
|
location={{ |
|
|
|
pathname, |
|
|
|
}} |
|
|
|
token={{ |
|
|
|
header: { |
|
|
|
colorBgMenuItemSelected: 'rgba(0,0,0,0.04)', |
|
|
|
}, |
|
|
|
}} |
|
|
|
menu={{ |
|
|
|
collapsedShowGroupTitle: true, |
|
|
|
loading: isLoading, |
|
|
|
}} |
|
|
|
<CatchBoundary |
|
|
|
getResetKey={() => 'reset-page'} |
|
|
|
errorComponent={ErrorPage} |
|
|
|
> |
|
|
|
<ProConfigProvider hashed={false} intl={language === 'zh-CN' ? zhCNIntl : enUSIntl}> |
|
|
|
<ConfigProvider |
|
|
|
locale={language === 'zh-CN' ? zh : en} |
|
|
|
getTargetContainer={() => { |
|
|
|
return document.getElementById('crazy-pro-layout') || document.body |
|
|
|
}} |
|
|
|
> |
|
|
|
<ProLayout |
|
|
|
token={{ |
|
|
|
header: { |
|
|
|
colorBgMenuItemSelected: 'rgba(0,0,0,0.04)', |
|
|
|
}, |
|
|
|
}} |
|
|
|
fixedHeader={true} |
|
|
|
headerContentRender={() => <PageBreadcrumb |
|
|
|
className={'top-breadcrumb'} |
|
|
|
showIcon={false} |
|
|
|
items={items}/>} |
|
|
|
title="Crazy Pro" |
|
|
|
layout={'mix'} |
|
|
|
fixSiderbar={true} |
|
|
|
siderWidth={100} |
|
|
|
collapsedButtonRender={false} |
|
|
|
// collapsed={false}
|
|
|
|
postMenuData={() => { |
|
|
|
return menuData.map(item => ({ |
|
|
|
...item, |
|
|
|
children: [], |
|
|
|
})) as any |
|
|
|
}} |
|
|
|
route={ |
|
|
|
{ |
|
|
|
path: '/', |
|
|
|
routes: menuData.map(item => ({ |
|
|
|
...item, |
|
|
|
// path: item.path ?? `/${item.key}`,
|
|
|
|
children: [], |
|
|
|
// routes: undefined
|
|
|
|
})) |
|
|
|
} |
|
|
|
} |
|
|
|
location={ |
|
|
|
{ |
|
|
|
pathname, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
menu={{ |
|
|
|
collapsedShowGroupTitle: true, |
|
|
|
|
|
|
|
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/>, |
|
|
|
] |
|
|
|
}} |
|
|
|
menuProps={{ |
|
|
|
className: styles.sideMenu, |
|
|
|
}} |
|
|
|
menuRender={(_, defaultDom) => ( |
|
|
|
<span style={{ userSelect: 'none' }}> |
|
|
|
{defaultDom} |
|
|
|
}} |
|
|
|
menuItemRender={(item: MenuDataItem) => { |
|
|
|
return <span style={{ userSelect: 'none' }} onClick={() => { |
|
|
|
setRootMenuKeys([ (item as any).key || 'dashboard' ]) |
|
|
|
setPathname(item.path || '/dashboard') |
|
|
|
}} |
|
|
|
> |
|
|
|
<Link to={item.path} className={'menu-link'} target={item.type === 'url' ? '_blank' : '_self'}> |
|
|
|
<span>{item.icon}</span> |
|
|
|
<span>{item.name}</span> |
|
|
|
</Link> |
|
|
|
</span> |
|
|
|
)} |
|
|
|
menuItemRender={(item, dom) => { |
|
|
|
return <span style={{ userSelect: 'none' }} onClick={() => { |
|
|
|
setPathname(item.path || '/dashboard') |
|
|
|
}} |
|
|
|
> |
|
|
|
}} |
|
|
|
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/>, |
|
|
|
] |
|
|
|
}} |
|
|
|
menuProps={{ |
|
|
|
className: styles.mySiderMenu, |
|
|
|
selectedKeys: rootMenuKeys, |
|
|
|
}} |
|
|
|
// navTheme={'light'}
|
|
|
|
contentStyle={{ paddingBlock: 0, paddingInline: 0 }} |
|
|
|
> |
|
|
|
<ProLayout |
|
|
|
className={styles.mySider} |
|
|
|
headerRender={false} |
|
|
|
hasSiderMenu={false} |
|
|
|
postMenuData={() => { |
|
|
|
return (childMenuRef.current || []) as any |
|
|
|
}} |
|
|
|
route={{ |
|
|
|
path: '/', |
|
|
|
routes: menuData |
|
|
|
}} |
|
|
|
location={{ |
|
|
|
pathname, |
|
|
|
}} |
|
|
|
token={{ |
|
|
|
header: { |
|
|
|
colorBgMenuItemSelected: 'rgba(0,0,0,0.04)', |
|
|
|
}, |
|
|
|
}} |
|
|
|
menuProps={{ |
|
|
|
className: styles.sideMenu, |
|
|
|
}} |
|
|
|
menu={{ |
|
|
|
hideMenuWhenCollapsed: false, |
|
|
|
// collapsedShowGroupTitle: true,
|
|
|
|
loading: isLoading, |
|
|
|
}} |
|
|
|
menuRender={childMenuRef.current?.length ? undefined : false} |
|
|
|
menuItemRender={(item, dom) => { |
|
|
|
return <span style={{ userSelect: 'none' }} onClick={() => { |
|
|
|
setPathname(item.path || '/dashboard') |
|
|
|
}} |
|
|
|
> |
|
|
|
<Link to={item.path} target={item.type === 'url' ? '_blank' : '_self'}> |
|
|
|
{dom} |
|
|
|
</Link> |
|
|
|
</span> |
|
|
|
}} |
|
|
|
{...{ |
|
|
|
'layout': 'mix', |
|
|
|
'navTheme': 'light', |
|
|
|
'contentWidth': 'Fluid', |
|
|
|
'fixSiderbar': true, |
|
|
|
// 'colorPrimary': '#1677FF',
|
|
|
|
'siderMenuType': 'group', |
|
|
|
// layout: 'side',
|
|
|
|
}} |
|
|
|
> |
|
|
|
<Outlet/> |
|
|
|
</ProLayout> |
|
|
|
</ConfigProvider> |
|
|
|
</ProConfigProvider> |
|
|
|
</CatchBoundary> |
|
|
|
</div> |
|
|
|
}} |
|
|
|
{...{ |
|
|
|
'layout': 'mix', |
|
|
|
'navTheme': 'light', |
|
|
|
'contentWidth': 'Fluid', |
|
|
|
'fixSiderbar': false, |
|
|
|
// 'colorPrimary': '#1677FF',
|
|
|
|
// 'siderMenuType': 'group',
|
|
|
|
// layout: 'side',
|
|
|
|
}} |
|
|
|
> |
|
|
|
<Outlet/> |
|
|
|
</ProLayout> |
|
|
|
</ProLayout> |
|
|
|
</ConfigProvider> |
|
|
|
</ProConfigProvider> |
|
|
|
</CatchBoundary> |
|
|
|
</div> |
|
|
|
) |
|
|
|
} |