PageLayout.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. import HeaderBar from './HeaderBar.js';
  2. import { Layout } from '@douyinfe/semi-ui';
  3. import SiderBar from './SiderBar.js';
  4. import App from '../../App.js';
  5. import FooterBar from './Footer.js';
  6. import { ToastContainer } from 'react-toastify';
  7. import React, { useContext, useEffect } from 'react';
  8. import { useStyle } from '../../context/Style/index.js';
  9. import { useTranslation } from 'react-i18next';
  10. import { API, getLogo, getSystemName, showError, setStatusData } from '../../helpers/index.js';
  11. import { UserContext } from '../../context/User/index.js';
  12. import { StatusContext } from '../../context/Status/index.js';
  13. import { useLocation } from 'react-router-dom';
  14. const { Sider, Content, Header, Footer } = Layout;
  15. const PageLayout = () => {
  16. const [userState, userDispatch] = useContext(UserContext);
  17. const [statusState, statusDispatch] = useContext(StatusContext);
  18. const { state: styleState } = useStyle();
  19. const { i18n } = useTranslation();
  20. const location = useLocation();
  21. const shouldHideFooter = location.pathname === '/console/playground' || location.pathname.startsWith('/console/chat');
  22. const shouldInnerPadding = location.pathname.includes('/console') &&
  23. !location.pathname.startsWith('/console/chat') &&
  24. location.pathname !== '/console/playground';
  25. const loadUser = () => {
  26. let user = localStorage.getItem('user');
  27. if (user) {
  28. let data = JSON.parse(user);
  29. userDispatch({ type: 'login', payload: data });
  30. }
  31. };
  32. const loadStatus = async () => {
  33. try {
  34. const res = await API.get('/api/status');
  35. const { success, data } = res.data;
  36. if (success) {
  37. statusDispatch({ type: 'set', payload: data });
  38. setStatusData(data);
  39. } else {
  40. showError('Unable to connect to server');
  41. }
  42. } catch (error) {
  43. showError('Failed to load status');
  44. }
  45. };
  46. useEffect(() => {
  47. loadUser();
  48. loadStatus().catch(console.error);
  49. let systemName = getSystemName();
  50. if (systemName) {
  51. document.title = systemName;
  52. }
  53. let logo = getLogo();
  54. if (logo) {
  55. let linkElement = document.querySelector("link[rel~='icon']");
  56. if (linkElement) {
  57. linkElement.href = logo;
  58. }
  59. }
  60. // 从localStorage获取上次使用的语言
  61. const savedLang = localStorage.getItem('i18nextLng');
  62. if (savedLang) {
  63. i18n.changeLanguage(savedLang);
  64. }
  65. }, [i18n]);
  66. return (
  67. <Layout
  68. style={{
  69. height: '100vh',
  70. display: 'flex',
  71. flexDirection: 'column',
  72. overflow: styleState.isMobile ? 'visible' : 'hidden',
  73. }}
  74. >
  75. <Header
  76. style={{
  77. padding: 0,
  78. height: 'auto',
  79. lineHeight: 'normal',
  80. position: 'fixed',
  81. width: '100%',
  82. top: 0,
  83. zIndex: 100,
  84. }}
  85. >
  86. <HeaderBar />
  87. </Header>
  88. <Layout
  89. style={{
  90. marginTop: '64px',
  91. height: 'calc(100vh - 64px)',
  92. overflow: styleState.isMobile ? 'visible' : 'auto',
  93. display: 'flex',
  94. flexDirection: 'column',
  95. }}
  96. >
  97. {styleState.showSider && (
  98. <Sider
  99. style={{
  100. position: 'fixed',
  101. left: 0,
  102. top: '64px',
  103. zIndex: 99,
  104. border: 'none',
  105. paddingRight: '0',
  106. height: 'calc(100vh - 64px)',
  107. }}
  108. >
  109. <SiderBar />
  110. </Sider>
  111. )}
  112. <Layout
  113. style={{
  114. marginLeft: styleState.isMobile
  115. ? '0'
  116. : styleState.showSider
  117. ? styleState.siderCollapsed
  118. ? '60px'
  119. : '180px'
  120. : '0',
  121. transition: 'margin-left 0.3s ease',
  122. flex: '1 1 auto',
  123. display: 'flex',
  124. flexDirection: 'column',
  125. }}
  126. >
  127. <Content
  128. style={{
  129. flex: '1 0 auto',
  130. overflowY: styleState.isMobile ? 'visible' : 'hidden',
  131. WebkitOverflowScrolling: 'touch',
  132. padding: shouldInnerPadding ? (styleState.isMobile ? '5px' : '24px') : '0',
  133. position: 'relative',
  134. }}
  135. >
  136. <App />
  137. </Content>
  138. {!shouldHideFooter && (
  139. <Layout.Footer
  140. style={{
  141. flex: '0 0 auto',
  142. width: '100%',
  143. }}
  144. >
  145. <FooterBar />
  146. </Layout.Footer>
  147. )}
  148. </Layout>
  149. </Layout>
  150. <ToastContainer />
  151. </Layout>
  152. );
  153. };
  154. export default PageLayout;