refactor(Center): 大幅简化,移除侧边栏逻辑

- 移除 WatchSidebar 相关代码(已移至全局 GlobalSidebar)
- 移除数据加载逻辑(由 GlobalSidebarContext 统一管理)
- 移除 useAuth、useLocation、useNavigate 等依赖
- 保留核心功能:MarketDashboard、ForumCenter、InvestmentPlanningCenter
- 代码从 ~260 行精简至 ~40 行

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
zdl
2025-12-23 11:56:30 +08:00
parent bb0506b2bb
commit dafef2c572

View File

@@ -5,261 +5,38 @@
* 功能:自选股监控、关注事件、投资规划等 * 功能:自选股监控、关注事件、投资规划等
*/ */
import React, { useEffect, useState, useCallback, useRef } from 'react'; import React from 'react';
import { logger } from '@/utils/logger'; import { Box } from '@chakra-ui/react';
import { getApiBase } from '@/utils/apiConfig';
import { useDashboardEvents } from '@/hooks/useDashboardEvents';
import {
Box,
Flex,
Text,
VStack,
useToast,
Spinner,
Center,
} from '@chakra-ui/react';
import { useCenterColors } from './hooks';
import { useAuth } from '@/contexts/AuthContext';
import { useLocation, useNavigate } from 'react-router-dom';
import InvestmentPlanningCenter from './components/InvestmentPlanningCenter'; import InvestmentPlanningCenter from './components/InvestmentPlanningCenter';
import { getEventDetailUrl } from '@/utils/idEncoder';
import MarketDashboard from '@views/Profile/components/MarketDashboard'; import MarketDashboard from '@views/Profile/components/MarketDashboard';
import ForumCenter from '@views/Profile/components/ForumCenter'; import ForumCenter from '@views/Profile/components/ForumCenter';
import WatchSidebar from '@views/Profile/components/WatchSidebar';
import { THEME } from '@views/Profile/components/MarketDashboard/constants'; import { THEME } from '@views/Profile/components/MarketDashboard/constants';
import type {
WatchlistItem,
RealtimeQuotesMap,
FollowingEvent,
EventComment,
WatchlistApiResponse,
RealtimeQuotesApiResponse,
FollowingEventsApiResponse,
EventCommentsApiResponse,
DashboardEventsResult,
} from '@/types';
/** /**
* CenterDashboard 组件 * CenterDashboard 组件
* 个人中心仪表板主页面 * 个人中心仪表板主页面
*
* 注意:右侧 WatchSidebar 已移至全局 GlobalSidebar在 MainLayout 中渲染)
*/ */
const CenterDashboard: React.FC = () => { const CenterDashboard: React.FC = () => {
const { user } = useAuth();
const location = useLocation();
const navigate = useNavigate();
const toast = useToast();
// 提取 userId 为独立变量(优化依赖项)
const userId = user?.id;
// 初始化 Dashboard 埋点 Hook类型断言为 DashboardEventsResult
const dashboardEvents = useDashboardEvents({
pageType: 'center',
navigate
}) as DashboardEventsResult;
// 颜色主题(使用 useCenterColors 封装,避免 7 次 useColorModeValue 调用)
const { secondaryText } = useCenterColors();
// 数据状态
const [watchlist, setWatchlist] = useState<WatchlistItem[]>([]);
const [realtimeQuotes, setRealtimeQuotes] = useState<RealtimeQuotesMap>({});
const [followingEvents, setFollowingEvents] = useState<FollowingEvent[]>([]);
const [eventComments, setEventComments] = useState<EventComment[]>([]);
const [loading, setLoading] = useState<boolean>(true);
const [quotesLoading, setQuotesLoading] = useState<boolean>(false);
// 使用 ref 跟踪是否已经加载过数据(首次加载标记)
const hasLoadedRef = useRef<boolean>(false);
/**
* 加载实时行情
*/
const loadRealtimeQuotes = useCallback(async (): Promise<void> => {
try {
setQuotesLoading(true);
const base = getApiBase();
const response = await fetch(base + '/api/account/watchlist/realtime', {
credentials: 'include',
cache: 'no-store'
});
if (response.ok) {
const data: RealtimeQuotesApiResponse = await response.json();
if (data.success) {
const quotesMap: RealtimeQuotesMap = {};
data.data.forEach(item => {
quotesMap[item.stock_code] = item;
});
setRealtimeQuotes(quotesMap);
}
}
} catch (error) {
logger.error('Center', 'loadRealtimeQuotes', error, {
userId,
timestamp: new Date().toISOString()
});
} finally {
setQuotesLoading(false);
}
}, [userId]);
/**
* 加载所有数据(自选股、关注事件、评论)
*/
const loadData = useCallback(async (): Promise<void> => {
try {
const base = getApiBase();
const ts = Date.now();
const [w, e, c] = await Promise.all([
fetch(base + `/api/account/watchlist?_=${ts}`, { credentials: 'include', cache: 'no-store' }),
fetch(base + `/api/account/events/following?_=${ts}`, { credentials: 'include', cache: 'no-store' }),
fetch(base + `/api/account/events/posts?_=${ts}`, { credentials: 'include', cache: 'no-store' }),
]);
const jw: WatchlistApiResponse = await w.json();
const je: FollowingEventsApiResponse = await e.json();
const jc: EventCommentsApiResponse = await c.json();
if (jw.success) {
const watchlistData = Array.isArray(jw.data) ? jw.data : [];
setWatchlist(watchlistData);
// 追踪自选股列表查看
if (watchlistData.length > 0) {
dashboardEvents.trackWatchlistViewed(watchlistData.length, true);
}
// 加载实时行情
if (jw.data && jw.data.length > 0) {
loadRealtimeQuotes();
}
}
if (je.success) {
const eventsData = Array.isArray(je.data) ? je.data : [];
setFollowingEvents(eventsData);
// 追踪关注的事件列表查看
dashboardEvents.trackFollowingEventsViewed(eventsData.length);
}
if (jc.success) {
const commentsData = Array.isArray(jc.data) ? jc.data : [];
setEventComments(commentsData);
// 追踪评论列表查看
dashboardEvents.trackCommentsViewed(commentsData.length);
}
} catch (err) {
logger.error('Center', 'loadData', err, {
userId,
timestamp: new Date().toISOString()
});
} finally {
setLoading(false);
}
}, [userId, loadRealtimeQuotes, dashboardEvents]);
// 首次加载和页面可见性变化时加载数据
useEffect(() => {
const isOnCenterPage = location.pathname.includes('/home/center');
// 首次进入页面且有用户时加载数据
if (user && isOnCenterPage && !hasLoadedRef.current) {
console.log('[Center] 🚀 首次加载数据');
hasLoadedRef.current = true;
loadData();
}
const onVis = (): void => {
if (document.visibilityState === 'visible' && location.pathname.includes('/home/center')) {
console.log('[Center] 👁️ visibilitychange 触发 loadData');
loadData();
}
};
document.addEventListener('visibilitychange', onVis);
return () => document.removeEventListener('visibilitychange', onVis);
}, [userId, location.pathname, loadData, user]);
// 当用户登出再登入userId 变化)时,重置加载标记
useEffect(() => {
if (!user) {
hasLoadedRef.current = false;
}
}, [user]);
// 定时刷新实时行情(每分钟一次)
useEffect(() => {
if (watchlist.length > 0) {
const interval = setInterval(() => {
loadRealtimeQuotes();
}, 60000); // 60秒刷新一次
return () => clearInterval(interval);
}
}, [watchlist.length, loadRealtimeQuotes]);
// 渲染加载状态
if (loading) {
return (
<Center h="60vh">
<VStack spacing={4}>
<Spinner size="xl" color="blue.500" thickness="4px" />
<Text color={secondaryText}>...</Text>
</VStack>
</Center>
);
}
return ( return (
<Box bg={THEME.bg.primary} minH="100vh" overflowX="hidden"> <Box bg={THEME.bg.primary} minH="100vh" overflowX="hidden">
<Box px={{ base: 3, md: 4 }} py={{ base: 4, md: 6 }} maxW="container.xl" mx="auto"> <Box px={{ base: 3, md: 4 }} py={{ base: 4, md: 6 }} maxW="container.xl" mx="auto">
{/* 左右布局左侧自适应右侧固定200px */} {/* 市场概览仪表盘 */}
<Flex gap={4}> <Box mb={4}>
{/* 左侧主内容区 */} <MarketDashboard />
<Box flex={1} minW={0}> </Box>
{/* 市场概览仪表盘 */}
<Box mb={4}>
<MarketDashboard />
</Box>
{/* 价值论坛 / 互动中心 */} {/* 价值论坛 / 互动中心 */}
<Box mb={4}> <Box mb={4}>
<ForumCenter /> <ForumCenter />
</Box> </Box>
{/* 投资规划中心(整合了日历、计划、复盘,应用 FUI 毛玻璃风格) */} {/* 投资规划中心(整合了日历、计划、复盘,应用 FUI 毛玻璃风格) */}
<Box> <Box>
<InvestmentPlanningCenter /> <InvestmentPlanningCenter />
</Box> </Box>
</Box>
{/* 右侧固定宽度侧边栏 */}
<Box
w={{ base: '100%', md: '300px' }}
flexShrink={0}
display={{ base: 'none', md: 'block' }}
position="sticky"
top="80px"
alignSelf="flex-start"
>
<WatchSidebar
watchlist={watchlist}
realtimeQuotes={realtimeQuotes}
followingEvents={followingEvents}
eventComments={eventComments}
onStockClick={(stock: WatchlistItem) => navigate(`/company/${stock.stock_code}`)}
onEventClick={(event: FollowingEvent) => navigate(getEventDetailUrl(event.id))}
onCommentClick={(comment: EventComment) => navigate(getEventDetailUrl(comment.event_id))}
onAddStock={() => navigate('/stocks')}
onAddEvent={() => navigate('/community')}
/>
</Box>
</Flex>
</Box> </Box>
</Box> </Box>
); );