| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| import HeaderBar from './headerbar'; |
| import { Layout } from '@douyinfe/semi-ui'; |
| import SiderBar from './SiderBar'; |
| import App from '../../App'; |
| import FooterBar from './Footer'; |
| import { ToastContainer } from 'react-toastify'; |
| import React, { useContext, useEffect, useState } from 'react'; |
| import { useIsMobile } from '../../hooks/common/useIsMobile'; |
| import { useSidebarCollapsed } from '../../hooks/common/useSidebarCollapsed'; |
| import { useTranslation } from 'react-i18next'; |
| import { |
| API, |
| getLogo, |
| getSystemName, |
| showError, |
| setStatusData, |
| } from '../../helpers'; |
| import { UserContext } from '../../context/User'; |
| import { StatusContext } from '../../context/Status'; |
| import { useLocation } from 'react-router-dom'; |
| const { Sider, Content, Header } = Layout; |
|
|
| const PageLayout = () => { |
| const [, userDispatch] = useContext(UserContext); |
| const [, statusDispatch] = useContext(StatusContext); |
| const isMobile = useIsMobile(); |
| const [collapsed, , setCollapsed] = useSidebarCollapsed(); |
| const [drawerOpen, setDrawerOpen] = useState(false); |
| const { i18n } = useTranslation(); |
| const location = useLocation(); |
|
|
| const cardProPages = [ |
| '/console/channel', |
| '/console/log', |
| '/console/redemption', |
| '/console/user', |
| '/console/token', |
| '/console/midjourney', |
| '/console/task', |
| '/console/models', |
| '/pricing', |
| ]; |
|
|
| const shouldHideFooter = cardProPages.includes(location.pathname); |
|
|
| const shouldInnerPadding = |
| location.pathname.includes('/console') && |
| !location.pathname.startsWith('/console/chat') && |
| location.pathname !== '/console/playground'; |
|
|
| const isConsoleRoute = location.pathname.startsWith('/console'); |
| const showSider = isConsoleRoute && (!isMobile || drawerOpen); |
|
|
| useEffect(() => { |
| if (isMobile && drawerOpen && collapsed) { |
| setCollapsed(false); |
| } |
| }, [isMobile, drawerOpen, collapsed, setCollapsed]); |
|
|
| const loadUser = () => { |
| let user = localStorage.getItem('user'); |
| if (user) { |
| let data = JSON.parse(user); |
| userDispatch({ type: 'login', payload: data }); |
| } |
| }; |
|
|
| const loadStatus = async () => { |
| try { |
| const res = await API.get('/api/status'); |
| const { success, data } = res.data; |
| if (success) { |
| statusDispatch({ type: 'set', payload: data }); |
| setStatusData(data); |
| } else { |
| showError('Unable to connect to server'); |
| } |
| } catch (error) { |
| showError('Failed to load status'); |
| } |
| }; |
|
|
| useEffect(() => { |
| loadUser(); |
| loadStatus().catch(console.error); |
| let systemName = getSystemName(); |
| if (systemName) { |
| document.title = systemName; |
| } |
| let logo = getLogo(); |
| if (logo) { |
| let linkElement = document.querySelector("link[rel~='icon']"); |
| if (linkElement) { |
| linkElement.href = logo; |
| } |
| } |
| const savedLang = localStorage.getItem('i18nextLng'); |
| if (savedLang) { |
| i18n.changeLanguage(savedLang); |
| } |
| }, [i18n]); |
|
|
| return ( |
| <Layout |
| style={{ |
| height: '100vh', |
| display: 'flex', |
| flexDirection: 'column', |
| overflow: isMobile ? 'visible' : 'hidden', |
| }} |
| > |
| <Header |
| style={{ |
| padding: 0, |
| height: 'auto', |
| lineHeight: 'normal', |
| position: 'fixed', |
| width: '100%', |
| top: 0, |
| zIndex: 100, |
| }} |
| > |
| <HeaderBar |
| onMobileMenuToggle={() => setDrawerOpen((prev) => !prev)} |
| drawerOpen={drawerOpen} |
| /> |
| </Header> |
| <Layout |
| style={{ |
| overflow: isMobile ? 'visible' : 'auto', |
| display: 'flex', |
| flexDirection: 'column', |
| }} |
| > |
| {showSider && ( |
| <Sider |
| style={{ |
| position: 'fixed', |
| left: 0, |
| top: '64px', |
| zIndex: 99, |
| border: 'none', |
| paddingRight: '0', |
| height: 'calc(100vh - 64px)', |
| width: 'var(--sidebar-current-width)', |
| }} |
| > |
| <SiderBar |
| onNavigate={() => { |
| if (isMobile) setDrawerOpen(false); |
| }} |
| /> |
| </Sider> |
| )} |
| <Layout |
| style={{ |
| marginLeft: isMobile |
| ? '0' |
| : showSider |
| ? 'var(--sidebar-current-width)' |
| : '0', |
| flex: '1 1 auto', |
| display: 'flex', |
| flexDirection: 'column', |
| }} |
| > |
| <Content |
| style={{ |
| flex: '1 0 auto', |
| overflowY: isMobile ? 'visible' : 'hidden', |
| WebkitOverflowScrolling: 'touch', |
| padding: shouldInnerPadding ? (isMobile ? '5px' : '24px') : '0', |
| position: 'relative', |
| }} |
| > |
| <App /> |
| </Content> |
| {!shouldHideFooter && ( |
| <Layout.Footer |
| style={{ |
| flex: '0 0 auto', |
| width: '100%', |
| }} |
| > |
| <FooterBar /> |
| </Layout.Footer> |
| )} |
| </Layout> |
| </Layout> |
| <ToastContainer /> |
| </Layout> |
| ); |
| }; |
|
|
| export default PageLayout; |
|
|