/* 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 . For commercial licensing, please contact support@quantumnous.com */ import React, { useMemo, useCallback } from 'react'; import { useLocation, useNavigate } from 'react-router-dom'; import { Button, Dropdown } from '@douyinfe/semi-ui'; import { ChevronDown } from 'lucide-react'; import SkeletonWrapper from '../components/SkeletonWrapper'; import { StatusContext } from '../../../context/Status'; import { isAdmin, userIsSupplierUser } from '../../../helpers'; /** 主站入口顺序(与桌面顶栏一致) */ const PRIMARY_NAV_KEYS = ['home', 'pricing', 'docs', 'about']; const menuClass = '!bg-semi-color-bg-overlay !border-semi-color-border !shadow-lg !rounded-lg dark:!bg-gray-700 dark:!border-gray-600'; const supplierApplyPath = '/console/supplier/apply'; const MobileSiteNavDropdown = ({ mainNavLinks, pricingRequireAuth, userState, isLoading, t, }) => { const location = useLocation(); const navigate = useNavigate(); const user = userState?.user; const [statusState] = React.useContext(StatusContext); const byNavKey = useMemo( () => Object.fromEntries(mainNavLinks.map((l) => [l.itemKey, l])), [mainNavLinks], ); const primaryAndConsoleLinks = useMemo(() => { const primary = PRIMARY_NAV_KEYS.map((k) => byNavKey[k]).filter(Boolean); const consoleLink = byNavKey.console; if (consoleLink) { return [...primary, consoleLink]; } return primary; }, [byNavKey]); const applyEntries = useMemo(() => { const hideApplyLinks = isAdmin(); if (!hideApplyLinks && !userIsSupplierUser(user)) { try { const roleModulesRaw = statusState?.status?.SidebarModulesByRole; if (roleModulesRaw) { const roleConfig = JSON.parse(roleModulesRaw); const userRole = String(user?.role ?? 0); const config = roleConfig[userRole]; if (config) { const consoleSection = config.console; if (consoleSection) { if (consoleSection.enabled === false || consoleSection.supplierApply === false) { return []; } } } } } catch {} return [ { itemKey: 'supplier-apply', text: t('提供算力'), redirectPath: supplierApplyPath, }, ]; } return []; }, [user, t, statusState?.status?.SidebarModulesByRole]); const currentPageLabel = useMemo(() => { const p = location.pathname; if (p === '/') return t('首页'); if (p === '/pricing' || p.startsWith('/pricing/')) return t('模型广场'); if (p === '/about' || p.startsWith('/about/')) return t('关于'); if (/\/[a-z]{2}\/docs\b/i.test(p) || p.includes('/docs')) { return t('文档'); } if (p.startsWith(supplierApplyPath)) return t('提供算力'); if (p.startsWith('/console')) return t('控制台'); if (p === '/login') return t('登录'); return t('页面导航'); }, [location.pathname, t]); const isActivePath = useCallback( (linkPath) => { if (!linkPath) return false; const currentPath = location.pathname; if (linkPath === '/') { return currentPath === '/'; } return currentPath.startsWith(linkPath); }, [location.pathname], ); const resolveInternalTarget = useCallback( (link) => { let targetPath = link.to; if (link.itemKey === 'console' && !user) { targetPath = '/login'; } if (link.itemKey === 'pricing' && pricingRequireAuth && !user) { targetPath = '/login'; } return targetPath; }, [pricingRequireAuth, user], ); const handleSelectMain = useCallback( (link) => { const run = () => { if (link.isExternal && link.externalLink) { const openInNewTab = link.openInNewTab !== false; if (openInNewTab) { window.open(link.externalLink, '_blank', 'noopener,noreferrer'); } else { window.location.assign(link.externalLink); } return; } navigate(resolveInternalTarget(link)); }; window.setTimeout(run, 10); }, [navigate, resolveInternalTarget], ); const handleSelectApply = useCallback( (entry) => { window.setTimeout(() => { if (user) { navigate(entry.redirectPath); return; } navigate(`/login?redirect=${encodeURIComponent(entry.redirectPath)}`); }, 10); }, [navigate, user], ); if (primaryAndConsoleLinks.length === 0 && applyEntries.length === 0) { return null; } const itemClass = (active) => `!px-3 !py-2 !text-sm !text-semi-color-text-0 dark:!text-gray-200 ${ active ? '!bg-semi-color-primary-light-default dark:!bg-blue-600 !font-semibold' : 'hover:!bg-semi-color-fill-1 dark:hover:!bg-gray-600' }`; return (
document.body} render={ {primaryAndConsoleLinks.map((link) => { const active = !link.isExternal && isActivePath(link.to); return ( { e.stopPropagation(); }} onClick={() => handleSelectMain(link)} className={itemClass(active)} > {link.text} ); })} {applyEntries.length > 0 && primaryAndConsoleLinks.length > 0 && ( )} {applyEntries.map((entry) => { const active = isActivePath(entry.redirectPath); return ( { e.stopPropagation(); }} onClick={() => handleSelectApply(entry)} className={itemClass(active)} > {entry.text} ); })} } >
); }; export default MobileSiteNavDropdown;