Spaces:
Build error
Build error
| /* | |
| Copyright (C) 2025 QuantumNous | |
| This program is free software: you can redistribute it and/or modify | |
| it under the terms of the GNU Affero General Public License as | |
| published by the Free Software Foundation, either version 3 of the | |
| License, or (at your option) any later version. | |
| This program is distributed in the hope that it will be useful, | |
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| GNU Affero General Public License for more details. | |
| You should have received a copy of the GNU Affero General Public License | |
| along with this program. If not, see <https://www.gnu.org/licenses/>. | |
| For commercial licensing, please contact support@quantumnous.com | |
| */ | |
| import { useState, useEffect, useContext, useCallback, useMemo } from 'react'; | |
| import { useNavigate, useLocation } from 'react-router-dom'; | |
| import { useTranslation } from 'react-i18next'; | |
| import { UserContext } from '../../context/User'; | |
| import { StatusContext } from '../../context/Status'; | |
| import { useSetTheme, useTheme, useActualTheme } from '../../context/Theme'; | |
| import { getLogo, getSystemName, API, showSuccess } from '../../helpers'; | |
| import { useIsMobile } from './useIsMobile'; | |
| import { useSidebarCollapsed } from './useSidebarCollapsed'; | |
| import { useMinimumLoadingTime } from './useMinimumLoadingTime'; | |
| export const useHeaderBar = ({ onMobileMenuToggle, drawerOpen }) => { | |
| const { t, i18n } = useTranslation(); | |
| const [userState, userDispatch] = useContext(UserContext); | |
| const [statusState] = useContext(StatusContext); | |
| const isMobile = useIsMobile(); | |
| const [collapsed, toggleCollapsed] = useSidebarCollapsed(); | |
| const [logoLoaded, setLogoLoaded] = useState(false); | |
| const navigate = useNavigate(); | |
| const [currentLang, setCurrentLang] = useState(i18n.language); | |
| const location = useLocation(); | |
| const loading = statusState?.status === undefined; | |
| const isLoading = useMinimumLoadingTime(loading, 200); | |
| const systemName = getSystemName(); | |
| const logo = getLogo(); | |
| const currentDate = new Date(); | |
| const isNewYear = currentDate.getMonth() === 0 && currentDate.getDate() === 1; | |
| const isSelfUseMode = statusState?.status?.self_use_mode_enabled || false; | |
| const docsLink = statusState?.status?.docs_link || ''; | |
| const isDemoSiteMode = statusState?.status?.demo_site_enabled || false; | |
| // 获取顶栏模块配置 | |
| const headerNavModulesConfig = statusState?.status?.HeaderNavModules; | |
| // 使用useMemo确保headerNavModules正确响应statusState变化 | |
| const headerNavModules = useMemo(() => { | |
| if (headerNavModulesConfig) { | |
| try { | |
| const modules = JSON.parse(headerNavModulesConfig); | |
| // 处理向后兼容性:如果pricing是boolean,转换为对象格式 | |
| if (typeof modules.pricing === 'boolean') { | |
| modules.pricing = { | |
| enabled: modules.pricing, | |
| requireAuth: false, // 默认不需要登录鉴权 | |
| }; | |
| } | |
| return modules; | |
| } catch (error) { | |
| console.error('解析顶栏模块配置失败:', error); | |
| return null; | |
| } | |
| } | |
| return null; | |
| }, [headerNavModulesConfig]); | |
| // 获取模型广场权限配置 | |
| const pricingRequireAuth = useMemo(() => { | |
| if (headerNavModules?.pricing) { | |
| return typeof headerNavModules.pricing === 'object' | |
| ? headerNavModules.pricing.requireAuth | |
| : false; // 默认不需要登录 | |
| } | |
| return false; // 默认不需要登录 | |
| }, [headerNavModules]); | |
| const isConsoleRoute = location.pathname.startsWith('/console'); | |
| const theme = useTheme(); | |
| const actualTheme = useActualTheme(); | |
| const setTheme = useSetTheme(); | |
| // Logo loading effect | |
| useEffect(() => { | |
| setLogoLoaded(false); | |
| if (!logo) return; | |
| const img = new Image(); | |
| img.src = logo; | |
| img.onload = () => setLogoLoaded(true); | |
| }, [logo]); | |
| // Send theme to iframe | |
| useEffect(() => { | |
| try { | |
| const iframe = document.querySelector('iframe'); | |
| const cw = iframe && iframe.contentWindow; | |
| if (cw) { | |
| cw.postMessage({ themeMode: actualTheme }, '*'); | |
| } | |
| } catch (e) { | |
| // Silently ignore cross-origin or access errors | |
| } | |
| }, [actualTheme]); | |
| // Language change effect | |
| useEffect(() => { | |
| const handleLanguageChanged = (lng) => { | |
| setCurrentLang(lng); | |
| try { | |
| const iframe = document.querySelector('iframe'); | |
| const cw = iframe && iframe.contentWindow; | |
| if (cw) { | |
| cw.postMessage({ lang: lng }, '*'); | |
| } | |
| } catch (e) { | |
| // Silently ignore cross-origin or access errors | |
| } | |
| }; | |
| i18n.on('languageChanged', handleLanguageChanged); | |
| return () => { | |
| i18n.off('languageChanged', handleLanguageChanged); | |
| }; | |
| }, [i18n]); | |
| // Actions | |
| const logout = useCallback(async () => { | |
| await API.get('/api/user/logout'); | |
| showSuccess(t('注销成功!')); | |
| userDispatch({ type: 'logout' }); | |
| localStorage.removeItem('user'); | |
| navigate('/login'); | |
| }, [navigate, t, userDispatch]); | |
| const handleLanguageChange = useCallback( | |
| (lang) => { | |
| i18n.changeLanguage(lang); | |
| }, | |
| [i18n], | |
| ); | |
| const handleThemeToggle = useCallback( | |
| (newTheme) => { | |
| if ( | |
| !newTheme || | |
| (newTheme !== 'light' && newTheme !== 'dark' && newTheme !== 'auto') | |
| ) { | |
| return; | |
| } | |
| setTheme(newTheme); | |
| }, | |
| [setTheme], | |
| ); | |
| const handleMobileMenuToggle = useCallback(() => { | |
| if (isMobile) { | |
| onMobileMenuToggle(); | |
| } else { | |
| toggleCollapsed(); | |
| } | |
| }, [isMobile, onMobileMenuToggle, toggleCollapsed]); | |
| return { | |
| // State | |
| userState, | |
| statusState, | |
| isMobile, | |
| collapsed, | |
| logoLoaded, | |
| currentLang, | |
| location, | |
| isLoading, | |
| systemName, | |
| logo, | |
| isNewYear, | |
| isSelfUseMode, | |
| docsLink, | |
| isDemoSiteMode, | |
| isConsoleRoute, | |
| theme, | |
| drawerOpen, | |
| headerNavModules, | |
| pricingRequireAuth, | |
| // Actions | |
| logout, | |
| handleLanguageChange, | |
| handleThemeToggle, | |
| handleMobileMenuToggle, | |
| navigate, | |
| t, | |
| }; | |
| }; | |