|
|
import Avatar from '@/components/avatar' import PageBreadcrumb from '@/components/breadcrumb' import ErrorPage from '@/components/error/error.tsx' import SelectLang from '@/components/select-lang' import { appAtom, currentMenuAtom } from '@/store/system.ts' import { currentStaticUserAtom, userMenuDataAtom } from '@/store/system/user.ts' import { MenuItem } from '@/global' import { ProConfigProvider, ProLayout, } from '@ant-design/pro-components' import { enUSIntl, zhCNIntl } from '@ant-design/pro-provider/es/intl' import { CatchBoundary, Link, Outlet, useNavigate, useRouterState } from '@tanstack/react-router' import { ConfigProvider } from '@/components/config-provider' import { useEffect, useRef, useState } from 'react' import { useAtomValue, useSetAtom } 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 { convertToMenu, flattenTree } from '@/utils' import { Flex, Menu, Space, Watermark } from 'antd' import { MenuFoldOutlined, MenuUnfoldOutlined } from '@ant-design/icons' import { If, Then } from 'react-if'
//根据menuData生成Breadcrumb所需的数据
const getBreadcrumbData = (menuData: MenuItem[], pathname: string) => { const breadcrumbData: any[] = [] const findItem = (menuData: any[], pathname: string) => { for (let i = 0; i < menuData.length; i++) { if (menuData[i].path === pathname) { menuData[i].label = <span className={'s-title'}>{menuData[i].name}</span> breadcrumbData.push(menuData[i]) return true } if (menuData[i].children) { if (findItem(menuData[i].children, pathname)) { breadcrumbData.push(menuData[i]) return true } } } return false } findItem(menuData, pathname) return breadcrumbData.reverse() }
export default () => {
const { location } = useRouterState() const navigate = useNavigate() const { styles } = useStyle() const currentUser = useAtomValue(currentStaticUserAtom) const { data: menuData = [], isLoading } = useAtomValue(userMenuDataAtom) const { language } = useAtomValue(appAtom) const setCurrentMenu = useSetAtom(currentMenuAtom) const items = getBreadcrumbData(menuData, location.pathname) const [ pathname, setPathname ] = useState(location.pathname) const [ openMenuKeys, setOpenKeys ] = useState<string[]>([]) const [ collapsed, setCollapsed ] = useState(false) const [ childPath, setChildPath ] = useState<string>('') const menusFlatten = useRef<MenuItem[]>() if (!menusFlatten.current) { menusFlatten.current = flattenTree<MenuItem>(menuData, { key: 'id', title: 'name' }) } const [ rootMenuKeys, setRootMenuKeys ] = useState<string[]>(() => { let item = menusFlatten.current?.find(item => item.path === location.pathname) if (item && item.hidden && item.active) { setCurrentMenu(item) item = menusFlatten.current?.find(i => i.path === item?.active) }
if (item?.meta.affix) { // affix = true 为 dashboard页面
return [ item.meta.name ] } return item ? item.parentName : [] })
const childMenuRef = useRef<MenuItem[]>([]) const currentMenu = menuData.find(item => { return item.key === rootMenuKeys?.[0] }) // console.log(rootMenuKeys)
childMenuRef.current = currentMenu?.children || []
useEffect(() => { const item = menusFlatten.current?.find(item => item.path === location.pathname) if (item && item.meta.name !== rootMenuKeys?.[0]) { setRootMenuKeys(item.parentName) }
setCurrentMenu(item!)
if (item && item.hidden && item.active) { item.parent = menusFlatten.current?.find(i => i.path === item?.active) setChildPath(item.active) } else { setChildPath('') } }, [ location.pathname ])
return ( <div className={styles.container} id="crazy-pro-layout" style={{ // height: '100vh',
// overflow: 'auto',
}} > <CatchBoundary getResetKey={() => 'reset-page'} errorComponent={ErrorPage as any} > <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 { ...{ rotate: -31, content: currentUser?.nickname, font: { color: '#00000012', size: 17, }, zindex: 1009, } as any } style={{ width: '100vw', height: '100vh' }}> <ProLayout token={{ header: { colorBgMenuItemSelected: 'rgba(0,0,0,0.04)', }, sider: { colorMenuBackground: '#222b45', } }} 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" // layout={'mix'}
fixSiderbar={true} siderWidth={80} collapsedButtonRender={false} // collapsed={false}
postMenuData={() => { return menuData.filter(item => !item.hidden).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, }} 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>) }} avatarProps={false} actionsRender={false} menuProps={{ className: styles.mySiderMenu, selectedKeys: rootMenuKeys, theme: 'dark', }} loading={isLoading} contentStyle={{ paddingBlock: 0, paddingInline: 0 }} { ...{ // "fixSiderbar": true,
// "layout": "side",
'splitMenus': false, 'navTheme': 'realDark', 'contentWidth': 'Fluid', 'colorPrimary': '#1677FF', // "menuHeaderRender": false
} } >
<If condition={childMenuRef.current?.length > 0}> <Then> <Flex className={styles.childMenus}> { !collapsed && <div className={styles.childMenuTop}> <h2>{currentMenu?.title}</h2> </div> }
<Menu mode={'inline'} inlineCollapsed={collapsed} selectedKeys={[ childPath || location.pathname ]} openKeys={openMenuKeys} onOpenChange={(keys) => { setOpenKeys(keys) }} onClick={(menu) => { const info = menusFlatten.current?.find(item => item.path === menu.key) if (info) { setCurrentMenu(info) // setOpenKeys([ info.path as string ])
navigate({ to: info.path, }) }
}} items={convertToMenu((childMenuRef.current || []), (item => { return { data: item, icon: item.icon, key: item.path || item.meta.name, label: item.title, } })) as any} style={!collapsed ? { width: 210 } : {}} /> <div className={styles.childMenuBottom} onClick={() => { setCollapsed(!collapsed) }}> { collapsed ? <MenuUnfoldOutlined/> : <MenuFoldOutlined/> } </div> </Flex> </Then> </If>
<Flex flex={1} className={styles.body} aria-description={'main-body'} vertical={true}> <div className={styles.bodyHeader}> <PageBreadcrumb menusFlatten={menusFlatten} 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} 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': false, // 'colorPrimary': '#1677FF',
// 'siderMenuType': 'group',
// layout: 'side',
}} > </ProLayout>*/} </ProLayout> </div> </ConfigProvider> </ProConfigProvider> </CatchBoundary> </div> ) }
|