|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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, |
|
|
}; |
|
|
}; |
|
|
|