From 93928f4ee76d9e01acb8d93dc9da160cfa93b10f Mon Sep 17 00:00:00 2001 From: zdl <3489966805@qq.com> Date: Tue, 23 Dec 2025 10:05:45 +0800 Subject: [PATCH] =?UTF-8?q?feat(WatchSidebar):=20=E6=81=A2=E5=A4=8D?= =?UTF-8?q?=E8=AF=84=E8=AE=BA=E6=A8=A1=E5=9D=97=EF=BC=8C=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=20Tab=20=E5=88=87=E6=8D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在关注事件面板添加"我的评论" Tab - 新增 MyCommentsTab 组件显示用户评论 - 评论显示:内容、关联事件、点赞/回复数、时间 - 更新类型定义支持评论数据传递 --- src/types/center.ts | 12 + src/views/Center/Center.tsx | 4 +- .../components/FollowingEventsPanel.js | 223 +++++++++++------- .../WatchSidebar/components/MyCommentsTab.js | 121 ++++++++++ .../WatchSidebar/components/index.js | 1 + .../Profile/components/WatchSidebar/index.js | 6 +- 6 files changed, 285 insertions(+), 82 deletions(-) create mode 100644 src/views/Profile/components/WatchSidebar/components/MyCommentsTab.js diff --git a/src/types/center.ts b/src/types/center.ts index a0e377a4..96d9c1a7 100644 --- a/src/types/center.ts +++ b/src/types/center.ts @@ -203,12 +203,18 @@ export interface WatchSidebarProps { /** 关注的事件列表 */ followingEvents: FollowingEvent[]; + /** 用户评论列表 */ + eventComments?: EventComment[]; + /** 点击股票回调 */ onStockClick?: (stock: WatchlistItem) => void; /** 点击事件回调 */ onEventClick?: (event: FollowingEvent) => void; + /** 点击评论回调 */ + onCommentClick?: (comment: EventComment) => void; + /** 添加股票回调 */ onAddStock?: () => void; @@ -240,9 +246,15 @@ export interface FollowingEventsPanelProps { /** 事件列表 */ events: FollowingEvent[]; + /** 用户评论列表 */ + eventComments?: EventComment[]; + /** 点击事件回调 */ onEventClick?: (event: FollowingEvent) => void; + /** 点击评论回调 */ + onCommentClick?: (comment: EventComment) => void; + /** 添加事件回调 */ onAddEvent?: () => void; } diff --git a/src/views/Center/Center.tsx b/src/views/Center/Center.tsx index 345c87c4..fa0e683b 100644 --- a/src/views/Center/Center.tsx +++ b/src/views/Center/Center.tsx @@ -246,7 +246,7 @@ const CenterDashboard: React.FC = () => { {/* 右侧固定宽度侧边栏 */} { 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')} /> diff --git a/src/views/Profile/components/WatchSidebar/components/FollowingEventsPanel.js b/src/views/Profile/components/WatchSidebar/components/FollowingEventsPanel.js index 5964a677..1d0031eb 100644 --- a/src/views/Profile/components/WatchSidebar/components/FollowingEventsPanel.js +++ b/src/views/Profile/components/WatchSidebar/components/FollowingEventsPanel.js @@ -1,24 +1,29 @@ -// 关注事件面板 - 紧凑版 -import React from 'react'; -import { Box, Text, VStack, HStack, Icon } from '@chakra-ui/react'; -import { Star, Plus, Users } from 'lucide-react'; +// 关注事件面板 - 支持 Tab 切换(关注事件 / 我的评论) +import React, { useState } from 'react'; +import { Box, Text, VStack, HStack, Icon, Button, ButtonGroup } from '@chakra-ui/react'; +import { Star, Plus, Users, MessageSquare } from 'lucide-react'; +import MyCommentsTab from './MyCommentsTab'; + +const TAB_EVENTS = 'events'; +const TAB_COMMENTS = 'comments'; const FollowingEventsPanel = ({ events = [], + eventComments = [], onEventClick, + onCommentClick, onAddEvent, }) => { + const [activeTab, setActiveTab] = useState(TAB_EVENTS); + return ( - {/* 标题 */} + {/* 标题栏 + Tab 切换 */} - 关注事件 - - - ({events.length}) + 事件动态 - {/* 事件列表 */} - - {events.length === 0 ? ( - - - - 关注事件 - - - ) : ( - events.slice(0, 6).map((event) => { - const avgChg = event.related_avg_chg; - const isUp = avgChg > 0; - const changeColor = isUp ? '#EF4444' : avgChg < 0 ? '#22C55E' : 'rgba(255, 255, 255, 0.6)'; + {/* Tab 切换按钮 */} + + + + - return ( - onEventClick?.(event)} - > - - {event.title} - - - - - {event.follower_count || 0} - - {avgChg !== undefined && avgChg !== null && ( - - {isUp ? '+' : ''}{Number(avgChg).toFixed(2)}% - - )} - - - ); - }) - )} - {events.length > 6 && ( - - 查看全部 ({events.length}) - - )} - + {/* Tab 内容 */} + {activeTab === TAB_EVENTS ? ( + + ) : ( + + )} ); }; +/** + * 关注事件 Tab 内容 + */ +const EventsTabContent = ({ events, onEventClick, onAddEvent }) => { + if (events.length === 0) { + return ( + + + + 关注事件 + + + ); + } + + return ( + + {events.slice(0, 6).map((event) => { + const avgChg = event.related_avg_chg; + const isUp = avgChg > 0; + const changeColor = isUp ? '#EF4444' : avgChg < 0 ? '#22C55E' : 'rgba(255, 255, 255, 0.6)'; + + return ( + onEventClick?.(event)} + > + + {event.title} + + + + + {event.follower_count || 0} + + {avgChg !== undefined && avgChg !== null && ( + + {isUp ? '+' : ''}{Number(avgChg).toFixed(2)}% + + )} + + + ); + })} + {events.length > 6 && ( + + 查看全部 ({events.length}) + + )} + + ); +}; + export default FollowingEventsPanel; diff --git a/src/views/Profile/components/WatchSidebar/components/MyCommentsTab.js b/src/views/Profile/components/WatchSidebar/components/MyCommentsTab.js new file mode 100644 index 00000000..93def119 --- /dev/null +++ b/src/views/Profile/components/WatchSidebar/components/MyCommentsTab.js @@ -0,0 +1,121 @@ +// 我的评论 Tab 组件 +import React from 'react'; +import { Box, Text, VStack, HStack, Icon } from '@chakra-ui/react'; +import { MessageSquare, ThumbsUp, MessageCircle } from 'lucide-react'; + +/** + * 格式化时间为相对时间 + */ +const formatRelativeTime = (dateStr) => { + if (!dateStr) return ''; + const date = new Date(dateStr); + const now = new Date(); + const diff = now - date; + const minutes = Math.floor(diff / 60000); + const hours = Math.floor(diff / 3600000); + const days = Math.floor(diff / 86400000); + + if (minutes < 1) return '刚刚'; + if (minutes < 60) return `${minutes}分钟前`; + if (hours < 24) return `${hours}小时前`; + if (days < 30) return `${days}天前`; + return date.toLocaleDateString('zh-CN', { month: 'short', day: 'numeric' }); +}; + +/** + * 截断文本 + */ +const truncateText = (text, maxLength = 50) => { + if (!text) return ''; + return text.length > maxLength ? text.slice(0, maxLength) + '...' : text; +}; + +const MyCommentsTab = ({ + comments = [], + onCommentClick, + maxDisplay = 5, +}) => { + const displayComments = comments.slice(0, maxDisplay); + + if (comments.length === 0) { + return ( + + + + 暂无评论 + + + ); + } + + return ( + + {displayComments.map((comment) => ( + onCommentClick?.(comment)} + > + {/* 评论内容 */} + + {truncateText(comment.content, 60)} + + + {/* 关联事件 */} + {comment.event_title && ( + + 📌 {truncateText(comment.event_title, 30)} + + )} + + {/* 底部信息:点赞、回复、时间 */} + + + + + {comment.like_count || 0} + + + + {comment.reply_count || 0} + + + {formatRelativeTime(comment.created_at)} + + + ))} + + {/* 查看更多 */} + {comments.length > maxDisplay && ( + + 查看全部 ({comments.length}) + + )} + + ); +}; + +export default MyCommentsTab; diff --git a/src/views/Profile/components/WatchSidebar/components/index.js b/src/views/Profile/components/WatchSidebar/components/index.js index b0bc052f..0219caad 100644 --- a/src/views/Profile/components/WatchSidebar/components/index.js +++ b/src/views/Profile/components/WatchSidebar/components/index.js @@ -1,3 +1,4 @@ // 侧边栏子组件导出 export { default as WatchlistPanel } from './WatchlistPanel'; export { default as FollowingEventsPanel } from './FollowingEventsPanel'; +export { default as MyCommentsTab } from './MyCommentsTab'; diff --git a/src/views/Profile/components/WatchSidebar/index.js b/src/views/Profile/components/WatchSidebar/index.js index 422c8071..56fe0582 100644 --- a/src/views/Profile/components/WatchSidebar/index.js +++ b/src/views/Profile/components/WatchSidebar/index.js @@ -8,8 +8,10 @@ const WatchSidebar = ({ watchlist = [], realtimeQuotes = {}, followingEvents = [], + eventComments = [], onStockClick, onEventClick, + onCommentClick, onAddStock, onAddEvent, }) => { @@ -30,7 +32,7 @@ const WatchSidebar = ({ /> - {/* 关注事件 - 独立模块 */} + {/* 关注事件 + 我的评论 - 独立模块 */}