feat: 路由改造
This commit is contained in:
@@ -34,6 +34,7 @@ import { authService } from "../../services/authService";
|
||||
import AuthHeader from './AuthHeader';
|
||||
import VerificationCodeInput from './VerificationCodeInput';
|
||||
import WechatRegister from './WechatRegister';
|
||||
import { setCurrentUser } from '../../mocks/data/users';
|
||||
|
||||
// 统一配置对象
|
||||
const AUTH_CONFIG = {
|
||||
@@ -261,6 +262,12 @@ export default function AuthFormContent() {
|
||||
}
|
||||
|
||||
if (response.ok && data.success) {
|
||||
// ⚡ Mock 模式:先在前端侧写入 localStorage,确保时序正确
|
||||
if (process.env.REACT_APP_ENABLE_MOCK === 'true' && data.user) {
|
||||
setCurrentUser(data.user);
|
||||
console.log('[Auth] 前端侧设置当前用户(Mock模式):', data.user);
|
||||
}
|
||||
|
||||
// 更新session
|
||||
await checkSession();
|
||||
|
||||
|
||||
@@ -76,6 +76,14 @@ const SecondaryNav = () => {
|
||||
{ path: '/stocks', label: '个股中心', badges: [{ text: 'HOT', colorScheme: 'green' }] },
|
||||
{ path: '/trading-simulation', label: '模拟盘', badges: [{ text: 'NEW', colorScheme: 'red' }] }
|
||||
]
|
||||
},
|
||||
'/trading-simulation': {
|
||||
title: '行情复盘',
|
||||
items: [
|
||||
{ path: '/limit-analyse', label: '涨停分析', badges: [{ text: 'FREE', colorScheme: 'blue' }] },
|
||||
{ path: '/stocks', label: '个股中心', badges: [{ text: 'HOT', colorScheme: 'green' }] },
|
||||
{ path: '/trading-simulation', label: '模拟盘', badges: [{ text: 'NEW', colorScheme: 'red' }] }
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
@@ -181,9 +189,9 @@ const NavItems = ({ isAuthenticated, user }) => {
|
||||
const location = useLocation();
|
||||
|
||||
// 辅助函数:判断导航项是否激活
|
||||
const isActive = (paths) => {
|
||||
const isActive = useCallback((paths) => {
|
||||
return paths.some(path => location.pathname.includes(path));
|
||||
};
|
||||
}, [location.pathname]);
|
||||
|
||||
if (isAuthenticated && user) {
|
||||
return (
|
||||
@@ -203,45 +211,35 @@ const NavItems = ({ isAuthenticated, user }) => {
|
||||
高频跟踪
|
||||
</MenuButton>
|
||||
<MenuList minW="260px" p={2}>
|
||||
<VStack spacing={1} align="stretch">
|
||||
<Link
|
||||
onClick={() => navigate('/community')}
|
||||
py={2}
|
||||
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'}
|
||||
>
|
||||
<Flex justify="space-between" align="center">
|
||||
<Text fontSize="sm">新闻催化分析</Text>
|
||||
<HStack spacing={1}>
|
||||
<Badge size="sm" colorScheme="green">HOT</Badge>
|
||||
<Badge size="sm" colorScheme="red">NEW</Badge>
|
||||
</HStack>
|
||||
</Flex>
|
||||
</Link>
|
||||
<Link
|
||||
onClick={() => navigate('/concepts')}
|
||||
py={2}
|
||||
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'}
|
||||
>
|
||||
<Flex justify="space-between" align="center">
|
||||
<Text fontSize="sm">概念中心</Text>
|
||||
<MenuItem
|
||||
onClick={() => navigate('/community')}
|
||||
borderRadius="md"
|
||||
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'}
|
||||
>
|
||||
<Flex justify="space-between" align="center" w="100%">
|
||||
<Text fontSize="sm">新闻催化分析</Text>
|
||||
<HStack spacing={1}>
|
||||
<Badge size="sm" colorScheme="green">HOT</Badge>
|
||||
<Badge size="sm" colorScheme="red">NEW</Badge>
|
||||
</Flex>
|
||||
</Link>
|
||||
</VStack>
|
||||
</HStack>
|
||||
</Flex>
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
onClick={() => navigate('/concepts')}
|
||||
borderRadius="md"
|
||||
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'}
|
||||
>
|
||||
<Flex justify="space-between" align="center" w="100%">
|
||||
<Text fontSize="sm">概念中心</Text>
|
||||
<Badge size="sm" colorScheme="red">NEW</Badge>
|
||||
</Flex>
|
||||
</MenuItem>
|
||||
</MenuList>
|
||||
</Menu>
|
||||
|
||||
@@ -260,59 +258,45 @@ const NavItems = ({ isAuthenticated, user }) => {
|
||||
行情复盘
|
||||
</MenuButton>
|
||||
<MenuList minW="260px" p={2}>
|
||||
<VStack spacing={1} align="stretch">
|
||||
<Link
|
||||
onClick={() => navigate('/limit-analyse')}
|
||||
py={2}
|
||||
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'}
|
||||
>
|
||||
<Flex justify="space-between" align="center">
|
||||
<Text fontSize="sm">涨停分析</Text>
|
||||
<Badge size="sm" colorScheme="blue">FREE</Badge>
|
||||
</Flex>
|
||||
</Link>
|
||||
<Link
|
||||
onClick={() => navigate('/stocks')}
|
||||
py={2}
|
||||
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'}
|
||||
>
|
||||
<Flex justify="space-between" align="center">
|
||||
<Text fontSize="sm">个股中心</Text>
|
||||
<Badge size="sm" colorScheme="green">HOT</Badge>
|
||||
</Flex>
|
||||
</Link>
|
||||
<Link
|
||||
onClick={() => navigate('/trading-simulation')}
|
||||
py={2}
|
||||
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'}
|
||||
>
|
||||
<Flex justify="space-between" align="center">
|
||||
<Text fontSize="sm">模拟盘</Text>
|
||||
<Badge size="sm" colorScheme="red">NEW</Badge>
|
||||
</Flex>
|
||||
</Link>
|
||||
</VStack>
|
||||
<MenuItem
|
||||
onClick={() => navigate('/limit-analyse')}
|
||||
borderRadius="md"
|
||||
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'}
|
||||
>
|
||||
<Flex justify="space-between" align="center" w="100%">
|
||||
<Text fontSize="sm">涨停分析</Text>
|
||||
<Badge size="sm" colorScheme="blue">FREE</Badge>
|
||||
</Flex>
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
onClick={() => navigate('/stocks')}
|
||||
borderRadius="md"
|
||||
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'}
|
||||
>
|
||||
<Flex justify="space-between" align="center" w="100%">
|
||||
<Text fontSize="sm">个股中心</Text>
|
||||
<Badge size="sm" colorScheme="green">HOT</Badge>
|
||||
</Flex>
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
onClick={() => navigate('/trading-simulation')}
|
||||
borderRadius="md"
|
||||
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'}
|
||||
>
|
||||
<Flex justify="space-between" align="center" w="100%">
|
||||
<Text fontSize="sm">模拟盘</Text>
|
||||
<Badge size="sm" colorScheme="red">NEW</Badge>
|
||||
</Flex>
|
||||
</MenuItem>
|
||||
</MenuList>
|
||||
</Menu>
|
||||
|
||||
@@ -327,30 +311,20 @@ const NavItems = ({ isAuthenticated, user }) => {
|
||||
AGENT社群
|
||||
</MenuButton>
|
||||
<MenuList minW="300px" p={4}>
|
||||
<VStack spacing={2} align="stretch">
|
||||
<Link
|
||||
py={2}
|
||||
px={3}
|
||||
borderRadius="md"
|
||||
_hover={{}}
|
||||
cursor="not-allowed"
|
||||
color="gray.400"
|
||||
pointerEvents="none"
|
||||
>
|
||||
<Text fontSize="sm" color="gray.400">今日热议</Text>
|
||||
</Link>
|
||||
<Link
|
||||
py={2}
|
||||
px={3}
|
||||
borderRadius="md"
|
||||
_hover={{}}
|
||||
cursor="not-allowed"
|
||||
color="gray.400"
|
||||
pointerEvents="none"
|
||||
>
|
||||
<Text fontSize="sm" color="gray.400">个股社区</Text>
|
||||
</Link>
|
||||
</VStack>
|
||||
<MenuItem
|
||||
isDisabled
|
||||
cursor="not-allowed"
|
||||
color="gray.400"
|
||||
>
|
||||
<Text fontSize="sm" color="gray.400">今日热议</Text>
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
isDisabled
|
||||
cursor="not-allowed"
|
||||
color="gray.400"
|
||||
>
|
||||
<Text fontSize="sm" color="gray.400">个股社区</Text>
|
||||
</MenuItem>
|
||||
</MenuList>
|
||||
</Menu>
|
||||
|
||||
@@ -373,7 +347,7 @@ const NavItems = ({ isAuthenticated, user }) => {
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 计算 API 基础地址(移到组件外部,避免每次 render 重新创建)
|
||||
const getApiBase = () => (process.env.NODE_ENV === 'production' ? '' : (process.env.REACT_APP_API_URL || 'http://49.232.185.254:5001'));
|
||||
|
||||
27
src/components/ScrollToTop/index.js
Normal file
27
src/components/ScrollToTop/index.js
Normal file
@@ -0,0 +1,27 @@
|
||||
// src/components/ScrollToTop/index.js
|
||||
// 路由切换时自动滚动到页面顶部
|
||||
|
||||
import { useEffect } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
|
||||
/**
|
||||
* ScrollToTop - 路由切换时自动滚动到顶部
|
||||
*
|
||||
* 使用方式:在 App.js 的 Router 内部添加此组件
|
||||
*
|
||||
* @example
|
||||
* <BrowserRouter>
|
||||
* <ScrollToTop />
|
||||
* <Routes>...</Routes>
|
||||
* </BrowserRouter>
|
||||
*/
|
||||
export default function ScrollToTop() {
|
||||
const { pathname } = useLocation();
|
||||
|
||||
useEffect(() => {
|
||||
// 路径改变时滚动到顶部
|
||||
window.scrollTo(0, 0);
|
||||
}, [pathname]);
|
||||
|
||||
return null;
|
||||
}
|
||||
Reference in New Issue
Block a user