feat: 新增实时要闻·动态追踪与市场复盘功能,优化导航体验

新增功能:
- 实时要闻·动态追踪横向滚动卡片(DynamicNewsCard)
- 动态新闻事件卡片组件(DynamicNewsEventCard)
- 市场复盘卡片组件(MarketReviewCard)
- 股票涨跌幅指标组件(StockChangeIndicators)
- 交易时间工具函数(tradingTimeUtils)
- Mock API 支持动态新闻数据生成

UI 优化:
- EventFollowButton 改用 react-icons 星星图标,实现真正的空心/实心效果
- 关注按钮添加半透明白色背景(whiteAlpha.500),悬停效果更明显
- 事件卡片标题添加右侧留白,防止关注按钮遮挡文字

性能优化:
- 禁用 Router v7_startTransition 特性,解决路由切换延迟 2 秒问题
- 调整导航菜单点击顺序(先跳转后关闭),提升响应速度

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
zdl
2025-10-31 14:11:03 +08:00
parent 5d8ad5e442
commit c372832f1f
11 changed files with 1211 additions and 23 deletions

View File

@@ -650,7 +650,7 @@ export function generateMockEvents(params = {}) {
const allEvents = [];
const importanceLevels = ['S', 'A', 'B', 'C'];
const baseDate = new Date('2025-01-15');
const baseDate = new Date(); // 使用当前日期作为基准
for (let i = 0; i < totalEvents; i++) {
const industry = industries[i % industries.length];
@@ -816,3 +816,95 @@ export function generatePopularKeywords(limit = 20) {
trend: index % 3 === 0 ? 'up' : index % 3 === 1 ? 'down' : 'stable',
}));
}
/**
* 生成动态新闻事件(实时要闻·动态追踪专用)
* @param {Object} timeRange - 时间范围 { startTime, endTime }
* @param {number} count - 生成事件数量默认30条
* @returns {Array} - 事件列表
*/
export function generateDynamicNewsEvents(timeRange = null, count = 30) {
const events = [];
const importanceLevels = ['S', 'A', 'B', 'C'];
// 如果没有提供时间范围默认生成最近24小时的事件
let startTime, endTime;
if (timeRange) {
startTime = new Date(timeRange.startTime);
endTime = new Date(timeRange.endTime);
} else {
endTime = new Date();
startTime = new Date(endTime.getTime() - 24 * 60 * 60 * 1000); // 24小时前
}
// 计算时间跨度(毫秒)
const timeSpan = endTime.getTime() - startTime.getTime();
for (let i = 0; i < count; i++) {
const industry = industries[i % industries.length];
const imp = importanceLevels[i % importanceLevels.length];
const eventType = eventTypes[i % eventTypes.length];
// 在时间范围内随机生成事件时间
const randomOffset = Math.random() * timeSpan;
const createdAt = new Date(startTime.getTime() + randomOffset);
// 生成随机热度和收益率
const hotScore = Math.max(60, 100 - i * 1.2); // 动态新闻热度更高
const relatedAvgChg = (Math.random() * 15 - 3).toFixed(2); // -3% 到 12%
const relatedMaxChg = (Math.random() * 25).toFixed(2); // 0% 到 25%
const relatedWeekChg = (Math.random() * 30 - 10).toFixed(2); // -10% 到 20%
// 为每个事件随机选择2-5个相关股票
const relatedStockCount = 2 + (i % 4);
const relatedStocks = [];
const industryStocks = stockPool.filter(s => s.industry === industry);
// 优先选择同行业股票
if (industryStocks.length > 0) {
for (let j = 0; j < Math.min(relatedStockCount, industryStocks.length); j++) {
relatedStocks.push(industryStocks[j % industryStocks.length].stock_code);
}
}
// 如果同行业股票不够,从整个 stockPool 中补充
while (relatedStocks.length < relatedStockCount && relatedStocks.length < stockPool.length) {
const randomStock = stockPool[relatedStocks.length % stockPool.length];
if (!relatedStocks.includes(randomStock.stock_code)) {
relatedStocks.push(randomStock.stock_code);
}
}
events.push({
id: `dynamic_${i + 1}`,
title: generateEventTitle(industry, i),
description: generateEventDescription(industry, imp, i),
content: generateEventDescription(industry, imp, i),
event_type: eventType,
importance: imp,
status: 'published',
created_at: createdAt.toISOString(),
updated_at: createdAt.toISOString(),
hot_score: hotScore,
view_count: Math.floor(Math.random() * 5000) + 1000, // 1000-6000 浏览量
follower_count: Math.floor(Math.random() * 500) + 50, // 50-550 关注数
post_count: Math.floor(Math.random() * 100) + 10, // 10-110 帖子数
related_avg_chg: parseFloat(relatedAvgChg),
related_max_chg: parseFloat(relatedMaxChg),
related_week_chg: parseFloat(relatedWeekChg),
keywords: generateKeywords(industry, i),
is_ai_generated: i % 3 === 0, // 33% 的事件是AI生成
industry: industry,
related_stocks: relatedStocks,
creator: {
username: authorPool[i % authorPool.length],
avatar_url: null
}
});
}
// 按时间倒序排序(最新的在前)
events.sort((a, b) => new Date(b.created_at) - new Date(a.created_at));
return events;
}