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:
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user