| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
|
|
| 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;
|
|
|
|
|
| const headerNavModules = useMemo(() => {
|
| if (headerNavModulesConfig) {
|
| try {
|
| const modules = JSON.parse(headerNavModulesConfig);
|
|
|
|
|
| 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();
|
|
|
|
|
| useEffect(() => {
|
| setLogoLoaded(false);
|
| if (!logo) return;
|
| const img = new Image();
|
| img.src = logo;
|
| img.onload = () => setLogoLoaded(true);
|
| }, [logo]);
|
|
|
|
|
| useEffect(() => {
|
| try {
|
| const iframe = document.querySelector('iframe');
|
| const cw = iframe && iframe.contentWindow;
|
| if (cw) {
|
| cw.postMessage({ themeMode: actualTheme }, '*');
|
| }
|
| } catch (e) {
|
|
|
| }
|
| }, [actualTheme]);
|
|
|
|
|
| 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) {
|
|
|
| }
|
| };
|
|
|
| i18n.on('languageChanged', handleLanguageChanged);
|
| return () => {
|
| i18n.off('languageChanged', handleLanguageChanged);
|
| };
|
| }, [i18n]);
|
|
|
|
|
| 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 {
|
|
|
| userState,
|
| statusState,
|
| isMobile,
|
| collapsed,
|
| logoLoaded,
|
| currentLang,
|
| location,
|
| isLoading,
|
| systemName,
|
| logo,
|
| isNewYear,
|
| isSelfUseMode,
|
| docsLink,
|
| isDemoSiteMode,
|
| isConsoleRoute,
|
| theme,
|
| drawerOpen,
|
| headerNavModules,
|
| pricingRequireAuth,
|
|
|
|
|
| logout,
|
| handleLanguageChange,
|
| handleThemeToggle,
|
| handleMobileMenuToggle,
|
| navigate,
|
| t,
|
| };
|
| };
|
|
|