Files
vf_react/src/components/Navbars/components/MobileDrawer/MobileDrawer.js
2025-11-15 09:10:26 +08:00

340 lines
16 KiB
JavaScript

// src/components/Navbars/components/MobileDrawer/MobileDrawer.js
// 移动端抽屉菜单组件
import React, { memo } from 'react';
import {
Drawer,
DrawerOverlay,
DrawerContent,
DrawerCloseButton,
DrawerHeader,
DrawerBody,
VStack,
HStack,
Box,
Text,
Button,
Badge,
Link,
Divider,
Avatar,
useColorMode,
useColorModeValue
} from '@chakra-ui/react';
import { SunIcon, MoonIcon } from '@chakra-ui/icons';
import { useNavigate, useLocation } from 'react-router-dom';
/**
* 移动端抽屉菜单组件
* 包含完整的导航菜单和用户功能
*
* @param {Object} props
* @param {boolean} props.isOpen - Drawer 是否打开
* @param {Function} props.onClose - 关闭 Drawer 的回调
* @param {boolean} props.isAuthenticated - 用户是否已登录
* @param {Object} props.user - 用户信息
* @param {Function} props.handleLogout - 退出登录回调
* @param {Function} props.openAuthModal - 打开登录弹窗回调
*/
const MobileDrawer = memo(({
isOpen,
onClose,
isAuthenticated,
user,
handleLogout,
openAuthModal
}) => {
const navigate = useNavigate();
const location = useLocation();
const { colorMode, toggleColorMode } = useColorMode();
const userBgColor = useColorModeValue('gray.50', 'whiteAlpha.100');
const contactTextColor = useColorModeValue('gray.500', 'gray.300');
const emailTextColor = useColorModeValue('gray.500', 'gray.300');
// 获取显示名称
const getDisplayName = () => {
if (!user) return '用户';
if (user.nickname) return user.nickname;
if (user.username) return user.username;
if (user.email) return user.email.split('@')[0];
if (user.phone) return user.phone;
return '用户';
};
// 导航点击处理
const handleNavigate = (path) => {
navigate(path);
onClose();
};
return (
<Drawer isOpen={isOpen} placement="right" onClose={onClose}>
<DrawerOverlay />
<DrawerContent>
<DrawerCloseButton />
<DrawerHeader>
<HStack>
<Text>菜单</Text>
{isAuthenticated && user && (
<Badge colorScheme="green" ml={2}>已登录</Badge>
)}
</HStack>
</DrawerHeader>
<DrawerBody>
<VStack spacing={4} align="stretch">
{/* 移动端:日夜模式切换 */}
<Button
leftIcon={colorMode === 'light' ? <MoonIcon /> : <SunIcon />}
variant="ghost"
justifyContent="flex-start"
onClick={toggleColorMode}
size="sm"
>
切换到{colorMode === 'light' ? '深色' : '浅色'}模式
</Button>
{/* 移动端用户信息 */}
{isAuthenticated && user && (
<>
<Box p={3} bg={userBgColor} borderRadius="md">
<HStack>
<Avatar
size="sm"
name={getDisplayName()}
src={user.avatar_url}
bg="blue.500"
/>
<Box>
<Text fontSize="sm" fontWeight="bold">{getDisplayName()}</Text>
<Text fontSize="xs" color={emailTextColor}>{user.email}</Text>
</Box>
</HStack>
</Box>
<Divider />
</>
)}
{/* 首页链接 */}
<Link
onClick={() => handleNavigate('/home')}
py={2}
px={3}
borderRadius="md"
_hover={{ bg: 'gray.100' }}
cursor="pointer"
color="blue.500"
fontWeight="bold"
bg={location.pathname === '/home' ? 'blue.50' : 'transparent'}
borderLeft={location.pathname === '/home' ? '3px solid' : 'none'}
borderColor="blue.600"
>
<Text fontSize="md">🏠 首页</Text>
</Link>
<Divider />
{/* 高频跟踪 */}
<Box>
<Text fontWeight="bold" mb={2}>高频跟踪</Text>
<VStack spacing={2} align="stretch">
<Link
onClick={() => handleNavigate('/community')}
py={1}
px={3}
borderRadius="md"
_hover={{ bg: 'gray.100' }}
cursor="pointer"
bg={location.pathname.includes('/community') ? 'blue.50' : 'transparent'}
borderLeft={location.pathname.includes('/community') ? '3px solid' : 'none'}
borderColor="blue.600"
fontWeight={location.pathname.includes('/community') ? 'bold' : 'normal'}
>
<HStack justify="space-between">
<Text fontSize="sm">事件中心</Text>
<HStack spacing={1}>
<Badge size="xs" colorScheme="green">HOT</Badge>
<Badge size="xs" colorScheme="red">NEW</Badge>
</HStack>
</HStack>
</Link>
<Link
onClick={() => handleNavigate('/concepts')}
py={1}
px={3}
borderRadius="md"
_hover={{ bg: 'gray.100' }}
cursor="pointer"
bg={location.pathname.includes('/concepts') ? 'blue.50' : 'transparent'}
borderLeft={location.pathname.includes('/concepts') ? '3px solid' : 'none'}
borderColor="blue.600"
fontWeight={location.pathname.includes('/concepts') ? 'bold' : 'normal'}
>
<HStack justify="space-between">
<Text fontSize="sm">概念中心</Text>
<Badge size="xs" colorScheme="red">NEW</Badge>
</HStack>
</Link>
</VStack>
</Box>
<Divider />
{/* 行情复盘 */}
<Box>
<Text fontWeight="bold" mb={2}>行情复盘</Text>
<VStack spacing={2} align="stretch">
<Link
onClick={() => handleNavigate('/limit-analyse')}
py={1}
px={3}
borderRadius="md"
_hover={{ bg: 'gray.100' }}
cursor="pointer"
bg={location.pathname.includes('/limit-analyse') ? 'blue.50' : 'transparent'}
borderLeft={location.pathname.includes('/limit-analyse') ? '3px solid' : 'none'}
borderColor="blue.600"
fontWeight={location.pathname.includes('/limit-analyse') ? 'bold' : 'normal'}
>
<HStack justify="space-between">
<Text fontSize="sm">涨停分析</Text>
<Badge size="xs" colorScheme="blue">FREE</Badge>
</HStack>
</Link>
<Link
onClick={() => handleNavigate('/stocks')}
py={1}
px={3}
borderRadius="md"
_hover={{ bg: 'gray.100' }}
cursor="pointer"
bg={location.pathname.includes('/stocks') ? 'blue.50' : 'transparent'}
borderLeft={location.pathname.includes('/stocks') ? '3px solid' : 'none'}
borderColor="blue.600"
fontWeight={location.pathname.includes('/stocks') ? 'bold' : 'normal'}
>
<HStack justify="space-between">
<Text fontSize="sm">个股中心</Text>
<Badge size="xs" colorScheme="green">HOT</Badge>
</HStack>
</Link>
<Link
onClick={() => handleNavigate('/trading-simulation')}
py={1}
px={3}
borderRadius="md"
_hover={{ bg: 'gray.100' }}
cursor="pointer"
bg={location.pathname.includes('/trading-simulation') ? 'blue.50' : 'transparent'}
borderLeft={location.pathname.includes('/trading-simulation') ? '3px solid' : 'none'}
borderColor="blue.600"
fontWeight={location.pathname.includes('/trading-simulation') ? 'bold' : 'normal'}
>
<HStack justify="space-between">
<Text fontSize="sm">模拟盘</Text>
<Badge size="xs" colorScheme="red">NEW</Badge>
</HStack>
</Link>
</VStack>
</Box>
<Divider />
{/* AGENT社群 */}
<Box>
<Text fontWeight="bold" mb={2}>AGENT社群</Text>
<VStack spacing={2} align="stretch">
<Link
onClick={() => handleNavigate('/agent-chat')}
py={1}
px={3}
borderRadius="md"
_hover={{ bg: 'gray.100' }}
cursor="pointer"
bg={location.pathname.includes('/agent-chat') ? 'blue.50' : 'transparent'}
borderLeft={location.pathname.includes('/agent-chat') ? '3px solid' : 'none'}
borderColor="blue.600"
fontWeight={location.pathname.includes('/agent-chat') ? 'bold' : 'normal'}
>
<HStack justify="space-between">
<Text fontSize="sm">AI聊天助手</Text>
<HStack spacing={1}>
<Badge size="xs" colorScheme="green">AI</Badge>
<Badge size="xs" colorScheme="red">NEW</Badge>
</HStack>
</HStack>
</Link>
<Link
onClick={() => handleNavigate('/value-forum')}
py={1}
px={3}
borderRadius="md"
_hover={{ bg: 'gray.50' }}
bg={location.pathname.includes('/value-forum') ? 'blue.50' : 'transparent'}
>
<HStack justify="space-between">
<Text fontSize="sm">价值论坛</Text>
<HStack spacing={1}>
<Badge size="xs" colorScheme="yellow">黑金</Badge>
<Badge size="xs" colorScheme="red">NEW</Badge>
</HStack>
</HStack>
</Link>
<Link
py={1}
px={3}
borderRadius="md"
_hover={{}}
cursor="not-allowed"
color="gray.400"
pointerEvents="none"
>
<Text fontSize="sm" color="gray.400">个股社区</Text>
</Link>
</VStack>
</Box>
<Divider />
{/* 联系我们 */}
<Box>
<Text fontWeight="bold" mb={2}>联系我们</Text>
<Text fontSize="sm" color={contactTextColor}>敬请期待</Text>
</Box>
{/* 移动端登录/登出按钮 */}
<Divider />
{isAuthenticated && user ? (
<Button
colorScheme="red"
variant="outline"
size="sm"
onClick={() => {
handleLogout();
onClose();
}}
>
🚪 退出登录
</Button>
) : (
<Button
colorScheme="blue"
size="sm"
onClick={() => {
openAuthModal();
onClose();
}}
>
🔐 登录 / 注册
</Button>
)}
</VStack>
</DrawerBody>
</DrawerContent>
</Drawer>
);
});
MobileDrawer.displayName = 'MobileDrawer';
export default MobileDrawer;