- 支持 DELETE /api/posts/:postId 请求 - 从内存存储中正确删除评论 - 修复 mock 模式下删除评论失败的问题 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1586 lines
71 KiB
JavaScript
1586 lines
71 KiB
JavaScript
// src/mocks/handlers/event.js
|
||
// 事件相关的 Mock API Handlers
|
||
|
||
import { http, HttpResponse } from 'msw';
|
||
import { getEventRelatedStocks, generateMockEvents, generateHotEvents, generatePopularKeywords, generateDynamicNewsEvents } from '../data/events';
|
||
import { getMockFutureEvents, getMockEventCountsForMonth, toggleEventFollowStatus, isEventFollowed } from '../data/account';
|
||
import { generatePopularConcepts } from './concept';
|
||
import { getCurrentUser } from '../data/users';
|
||
|
||
// 模拟网络延迟
|
||
const delay = (ms = 300) => new Promise(resolve => setTimeout(resolve, ms));
|
||
|
||
// ==================== 评论内存存储 ====================
|
||
// 用于在 Mock 环境下持久化评论数据(按 eventId 分组)
|
||
const commentsStore = new Map();
|
||
|
||
/**
|
||
* 初始化某个事件的 mock 评论列表
|
||
* @param {string} eventId - 事件 ID
|
||
* @returns {Array} 初始的 15 条 mock 评论
|
||
*/
|
||
const initializeMockComments = (eventId) => {
|
||
const comments = [];
|
||
const users = [
|
||
{ username: '张三', avatar: null },
|
||
{ username: '李四', avatar: null },
|
||
{ username: '王五', avatar: null },
|
||
{ username: '赵六', avatar: null },
|
||
{ username: '投资达人', avatar: null },
|
||
{ username: '价值投资者', avatar: null },
|
||
{ username: '技术分析师', avatar: null },
|
||
{ username: '基本面研究员', avatar: null },
|
||
{ username: '量化交易员', avatar: null },
|
||
{ username: '市场观察者', avatar: null },
|
||
{ username: '行业分析师', avatar: null },
|
||
{ username: '财经评论员', avatar: null },
|
||
{ username: '趋势跟踪者', avatar: null },
|
||
{ username: '价值发现者', avatar: null },
|
||
{ username: '理性投资人', avatar: null },
|
||
];
|
||
|
||
const commentTemplates = [
|
||
'这个事件对相关板块影响很大,值得关注后续发展',
|
||
'相关概念股已经开始异动了,市场反应很快',
|
||
'感谢分享,这个事件我之前没注意到',
|
||
'从基本面来看,这个事件会带来实质性利好',
|
||
'需要观察后续政策落地情况,现在下结论还太早',
|
||
'相关产业链的龙头企业值得重点关注',
|
||
'这类事件一般都是短期刺激,长期影响有限',
|
||
'建议大家理性对待,不要盲目追高',
|
||
'这个消息已经在预期之中,股价可能提前反应了',
|
||
'关键要看后续的执行力度和落地速度',
|
||
'建议关注产业链上下游的投资机会',
|
||
'短期可能会有波动,但长期逻辑依然成立',
|
||
'市场情绪很高涨,需要警惕追高风险',
|
||
'从历史数据来看,类似事件后续表现都不错',
|
||
'这是一个结构性机会,需要精选个股',
|
||
];
|
||
|
||
for (let i = 0; i < 15; i++) {
|
||
const hoursAgo = Math.floor(Math.random() * 48) + 1; // 1-48 小时前
|
||
const createdAt = new Date(Date.now() - hoursAgo * 60 * 60 * 1000);
|
||
const user = users[i % users.length];
|
||
|
||
comments.push({
|
||
id: `comment_${eventId}_${i + 1}`,
|
||
content: commentTemplates[i % commentTemplates.length],
|
||
content_type: 'text',
|
||
author: {
|
||
id: `user_${i + 1}`,
|
||
username: user.username,
|
||
avatar: user.avatar,
|
||
},
|
||
created_at: createdAt.toISOString(),
|
||
likes_count: Math.floor(Math.random() * 20),
|
||
is_liked: false,
|
||
});
|
||
}
|
||
|
||
// 按时间升序排序(最旧的在前)
|
||
comments.sort((a, b) => new Date(a.created_at) - new Date(b.created_at));
|
||
|
||
return comments;
|
||
};
|
||
|
||
/**
|
||
* 获取或初始化评论列表
|
||
* @param {string} eventId - 事件 ID
|
||
* @returns {Array} 评论列表
|
||
*/
|
||
const getOrInitComments = (eventId) => {
|
||
if (!commentsStore.has(eventId)) {
|
||
commentsStore.set(eventId, initializeMockComments(eventId));
|
||
}
|
||
return commentsStore.get(eventId);
|
||
};
|
||
|
||
export const eventHandlers = [
|
||
// ==================== 事件列表相关 ====================
|
||
|
||
// 获取事件列表
|
||
http.get('/api/events', async ({ request }) => {
|
||
await delay(500);
|
||
|
||
const url = new URL(request.url);
|
||
const params = {
|
||
page: parseInt(url.searchParams.get('page') || '1'),
|
||
per_page: parseInt(url.searchParams.get('per_page') || '10'),
|
||
sort: url.searchParams.get('sort') || 'new',
|
||
importance: url.searchParams.get('importance') || 'all',
|
||
date_range: url.searchParams.get('date_range') || '',
|
||
q: url.searchParams.get('q') || '',
|
||
industry_code: url.searchParams.get('industry_code') || '',
|
||
industry_classification: url.searchParams.get('industry_classification') || '',
|
||
stock_code: url.searchParams.get('stock_code') || '',
|
||
};
|
||
|
||
console.log('[Mock] 获取事件列表:', params);
|
||
|
||
try {
|
||
const result = generateMockEvents(params);
|
||
|
||
return HttpResponse.json({
|
||
success: true,
|
||
data: result,
|
||
message: '获取成功'
|
||
});
|
||
} catch (error) {
|
||
console.error('[Mock] 获取事件列表失败:', error);
|
||
console.error('[Mock] Error details:', {
|
||
message: error.message,
|
||
stack: error.stack,
|
||
params: params
|
||
});
|
||
return HttpResponse.json(
|
||
{
|
||
success: false,
|
||
error: '获取事件列表失败',
|
||
data: {
|
||
events: [],
|
||
pagination: {
|
||
page: 1,
|
||
per_page: 10,
|
||
total: 0,
|
||
pages: 0, // ← 对齐后端字段名
|
||
has_prev: false, // ← 对齐后端
|
||
has_next: false // ← 对齐后端
|
||
}
|
||
}
|
||
},
|
||
{ status: 500 }
|
||
);
|
||
}
|
||
}),
|
||
|
||
// 获取热点事件
|
||
http.get('/api/events/hot', async ({ request }) => {
|
||
await delay(300);
|
||
|
||
const url = new URL(request.url);
|
||
const limit = parseInt(url.searchParams.get('limit') || '5');
|
||
|
||
console.log('[Mock] 获取热点事件, limit:', limit);
|
||
|
||
try {
|
||
const hotEvents = generateHotEvents(limit);
|
||
|
||
return HttpResponse.json({
|
||
success: true,
|
||
data: hotEvents,
|
||
message: '获取成功'
|
||
});
|
||
} catch (error) {
|
||
console.error('[Mock] 获取热点事件失败:', error);
|
||
return HttpResponse.json(
|
||
{
|
||
success: false,
|
||
error: '获取热点事件失败',
|
||
data: []
|
||
},
|
||
{ status: 500 }
|
||
);
|
||
}
|
||
}),
|
||
|
||
// 获取热门关键词
|
||
http.get('/api/events/keywords/popular', async ({ request }) => {
|
||
await delay(300);
|
||
|
||
const url = new URL(request.url);
|
||
const limit = parseInt(url.searchParams.get('limit') || '20');
|
||
|
||
console.log('[Mock] 获取热门关键词, limit:', limit);
|
||
|
||
try {
|
||
const keywords = generatePopularKeywords(limit);
|
||
|
||
return HttpResponse.json({
|
||
success: true,
|
||
data: keywords,
|
||
message: '获取成功'
|
||
});
|
||
} catch (error) {
|
||
console.error('[Mock] 获取热门关键词失败:', error);
|
||
return HttpResponse.json(
|
||
{
|
||
success: false,
|
||
error: '获取热门关键词失败',
|
||
data: []
|
||
},
|
||
{ status: 500 }
|
||
);
|
||
}
|
||
}),
|
||
|
||
// 获取动态新闻(实时要闻·动态追踪专用)
|
||
http.get('/api/events/dynamic-news', async ({ request }) => {
|
||
await delay(400);
|
||
|
||
const url = new URL(request.url);
|
||
const count = parseInt(url.searchParams.get('count') || '30');
|
||
const startTime = url.searchParams.get('start_time');
|
||
const endTime = url.searchParams.get('end_time');
|
||
|
||
console.log('[Mock] 获取动态新闻, count:', count, 'startTime:', startTime, 'endTime:', endTime);
|
||
|
||
try {
|
||
let timeRange = null;
|
||
if (startTime && endTime) {
|
||
timeRange = {
|
||
startTime: new Date(startTime),
|
||
endTime: new Date(endTime)
|
||
};
|
||
}
|
||
|
||
const events = generateDynamicNewsEvents(timeRange, count);
|
||
|
||
return HttpResponse.json({
|
||
success: true,
|
||
data: events,
|
||
total: events.length,
|
||
message: '获取成功'
|
||
});
|
||
} catch (error) {
|
||
console.error('[Mock] 获取动态新闻失败:', error);
|
||
return HttpResponse.json(
|
||
{
|
||
success: false,
|
||
error: '获取动态新闻失败',
|
||
data: []
|
||
},
|
||
{ status: 500 }
|
||
);
|
||
}
|
||
}),
|
||
|
||
// ==================== 事件详情相关 ====================
|
||
|
||
// 获取事件详情
|
||
http.get('/api/events/:eventId', async ({ params }) => {
|
||
await delay(200);
|
||
|
||
const { eventId } = params;
|
||
const numericEventId = parseInt(eventId, 10);
|
||
|
||
console.log('[Mock] 获取事件详情, eventId:', numericEventId);
|
||
|
||
try {
|
||
// 检查是否已关注
|
||
const isFollowing = isEventFollowed(numericEventId);
|
||
|
||
// 返回模拟的事件详情数据
|
||
return HttpResponse.json({
|
||
success: true,
|
||
data: {
|
||
id: numericEventId,
|
||
title: `测试事件 ${eventId} - 重大政策发布`,
|
||
description: '这是一个模拟的事件描述,用于开发测试。该事件涉及重要政策变化,可能对相关板块产生显著影响。建议关注后续发展动态。',
|
||
importance: ['S', 'A', 'B', 'C'][Math.floor(Math.random() * 4)],
|
||
created_at: new Date().toISOString(),
|
||
trading_date: new Date().toISOString().split('T')[0],
|
||
event_type: ['政策', '财报', '行业', '宏观'][Math.floor(Math.random() * 4)],
|
||
related_avg_chg: parseFloat((Math.random() * 10 - 5).toFixed(2)),
|
||
follower_count: Math.floor(Math.random() * 500) + 50,
|
||
view_count: Math.floor(Math.random() * 5000) + 100,
|
||
is_following: isFollowing, // 使用内存状态
|
||
post_count: Math.floor(Math.random() * 50),
|
||
expectation_surprise_score: parseFloat((Math.random() * 100).toFixed(1)),
|
||
},
|
||
message: '获取成功'
|
||
});
|
||
} catch (error) {
|
||
console.error('[Mock] 获取事件详情失败:', error);
|
||
return HttpResponse.json(
|
||
{
|
||
success: false,
|
||
error: '获取事件详情失败',
|
||
data: null
|
||
},
|
||
{ status: 500 }
|
||
);
|
||
}
|
||
}),
|
||
|
||
// 获取事件超预期得分
|
||
http.get('/api/events/:eventId/expectation-score', async ({ params }) => {
|
||
await delay(200);
|
||
|
||
const { eventId } = params;
|
||
|
||
console.log('[Mock] 获取事件超预期得分, eventId:', eventId);
|
||
|
||
try {
|
||
// 生成模拟的超预期得分数据
|
||
const score = parseFloat((Math.random() * 100).toFixed(1));
|
||
const avgChange = parseFloat((Math.random() * 10 - 2).toFixed(2));
|
||
const maxChange = parseFloat((Math.random() * 15).toFixed(2));
|
||
|
||
return HttpResponse.json({
|
||
success: true,
|
||
data: {
|
||
event_id: parseInt(eventId),
|
||
expectation_score: score,
|
||
avg_change: avgChange,
|
||
max_change: maxChange,
|
||
stock_count: Math.floor(Math.random() * 20) + 5,
|
||
updated_at: new Date().toISOString(),
|
||
},
|
||
message: '获取成功'
|
||
});
|
||
} catch (error) {
|
||
console.error('[Mock] 获取事件超预期得分失败:', error);
|
||
return HttpResponse.json(
|
||
{
|
||
success: false,
|
||
error: '获取事件超预期得分失败',
|
||
data: null
|
||
},
|
||
{ status: 500 }
|
||
);
|
||
}
|
||
}),
|
||
|
||
// 获取事件相关股票
|
||
http.get('/api/events/:eventId/stocks', async ({ params }) => {
|
||
await delay(300);
|
||
|
||
const { eventId } = params;
|
||
|
||
console.log('[Mock] 获取事件相关股票, eventId:', eventId);
|
||
|
||
try {
|
||
const relatedStocks = getEventRelatedStocks(eventId);
|
||
|
||
return HttpResponse.json({
|
||
success: true,
|
||
data: relatedStocks,
|
||
message: '获取成功'
|
||
});
|
||
} catch (error) {
|
||
console.error('[Mock] 获取事件相关股票失败:', error);
|
||
return HttpResponse.json(
|
||
{
|
||
success: false,
|
||
error: '获取事件相关股票失败',
|
||
data: []
|
||
},
|
||
{ status: 500 }
|
||
);
|
||
}
|
||
}),
|
||
|
||
// 获取事件相关概念
|
||
http.get('/api/events/:eventId/concepts', async ({ params }) => {
|
||
await delay(300);
|
||
|
||
const { eventId } = params;
|
||
|
||
console.log('[Mock] 获取事件相关概念, eventId:', eventId);
|
||
|
||
try {
|
||
// 返回热门概念列表(模拟真实场景下根据事件标题搜索的结果)
|
||
const concepts = generatePopularConcepts(5);
|
||
|
||
return HttpResponse.json({
|
||
success: true,
|
||
data: concepts,
|
||
message: '获取成功'
|
||
});
|
||
} catch (error) {
|
||
console.error('[Mock] 获取事件相关概念失败:', error);
|
||
return HttpResponse.json(
|
||
{
|
||
success: false,
|
||
error: '获取事件相关概念失败',
|
||
data: []
|
||
},
|
||
{ status: 500 }
|
||
);
|
||
}
|
||
}),
|
||
|
||
// 切换事件关注状态(使用内存状态管理)
|
||
http.post('/api/events/:eventId/follow', async ({ params, request }) => {
|
||
await delay(200);
|
||
|
||
const { eventId } = params;
|
||
const numericEventId = parseInt(eventId, 10);
|
||
|
||
console.log('[Mock] 切换事件关注状态, eventId:', numericEventId);
|
||
|
||
try {
|
||
// 尝试从请求体获取事件数据(用于新关注时保存完整信息)
|
||
let eventData = null;
|
||
try {
|
||
const body = await request.json();
|
||
if (body && body.title) {
|
||
eventData = body;
|
||
}
|
||
} catch {
|
||
// 没有请求体或解析失败,忽略
|
||
}
|
||
|
||
// 使用内存状态管理切换关注
|
||
const { isFollowing, followerCount } = toggleEventFollowStatus(numericEventId, eventData);
|
||
|
||
return HttpResponse.json({
|
||
success: true,
|
||
data: {
|
||
is_following: isFollowing,
|
||
follower_count: followerCount
|
||
},
|
||
message: isFollowing ? '关注成功' : '取消关注成功'
|
||
});
|
||
} catch (error) {
|
||
console.error('[Mock] 切换事件关注状态失败:', error);
|
||
return HttpResponse.json(
|
||
{
|
||
success: false,
|
||
error: '切换关注状态失败',
|
||
data: null
|
||
},
|
||
{ status: 500 }
|
||
);
|
||
}
|
||
}),
|
||
|
||
// 获取事件传导链分析数据
|
||
http.get('/api/events/:eventId/transmission', async ({ params }) => {
|
||
await delay(500);
|
||
|
||
const { eventId } = params;
|
||
|
||
console.log('[Mock] 获取事件传导链分析, eventId:', eventId);
|
||
|
||
// Mock数据:事件传导链
|
||
const mockTransmissionData = {
|
||
success: true,
|
||
data: {
|
||
nodes: [
|
||
{
|
||
id: '1',
|
||
name: '主要事件',
|
||
category: '事件',
|
||
value: 50,
|
||
extra: {
|
||
node_type: 'event',
|
||
description: '这是主要事件节点',
|
||
importance_score: 50,
|
||
is_main_event: true
|
||
}
|
||
},
|
||
{
|
||
id: '2',
|
||
name: '半导体行业',
|
||
category: '行业',
|
||
value: 40,
|
||
extra: {
|
||
node_type: 'industry',
|
||
description: '受影响的半导体行业',
|
||
importance_score: 40,
|
||
is_main_event: false
|
||
}
|
||
},
|
||
{
|
||
id: '3',
|
||
name: '芯片制造',
|
||
category: '行业',
|
||
value: 35,
|
||
extra: {
|
||
node_type: 'industry',
|
||
description: '芯片制造产业链',
|
||
importance_score: 35,
|
||
is_main_event: false
|
||
}
|
||
},
|
||
{
|
||
id: '4',
|
||
name: 'A公司',
|
||
category: '公司',
|
||
value: 30,
|
||
extra: {
|
||
node_type: 'company',
|
||
description: '龙头企业A',
|
||
importance_score: 30,
|
||
stock_code: '600000',
|
||
is_main_event: false
|
||
}
|
||
},
|
||
{
|
||
id: '5',
|
||
name: 'B公司',
|
||
category: '公司',
|
||
value: 25,
|
||
extra: {
|
||
node_type: 'company',
|
||
description: '龙头企业B',
|
||
importance_score: 25,
|
||
stock_code: '600001',
|
||
is_main_event: false
|
||
}
|
||
},
|
||
{
|
||
id: '6',
|
||
name: '相关政策',
|
||
category: '政策',
|
||
value: 30,
|
||
extra: {
|
||
node_type: 'policy',
|
||
description: '国家产业政策支持',
|
||
importance_score: 30,
|
||
is_main_event: false
|
||
}
|
||
}
|
||
],
|
||
edges: [
|
||
{
|
||
source: '1',
|
||
target: '2',
|
||
value: 0.8,
|
||
extra: {
|
||
transmission_strength: 0.8,
|
||
transmission_type: '直接影响',
|
||
description: '主事件对半导体行业的直接影响'
|
||
}
|
||
},
|
||
{
|
||
source: '2',
|
||
target: '3',
|
||
value: 0.7,
|
||
extra: {
|
||
transmission_strength: 0.7,
|
||
transmission_type: '产业链传导',
|
||
description: '半导体到芯片制造的传导'
|
||
}
|
||
},
|
||
{
|
||
source: '3',
|
||
target: '4',
|
||
value: 0.6,
|
||
extra: {
|
||
transmission_strength: 0.6,
|
||
transmission_type: '企业影响',
|
||
description: '对龙头企业A的影响'
|
||
}
|
||
},
|
||
{
|
||
source: '3',
|
||
target: '5',
|
||
value: 0.5,
|
||
extra: {
|
||
transmission_strength: 0.5,
|
||
transmission_type: '企业影响',
|
||
description: '对龙头企业B的影响'
|
||
}
|
||
},
|
||
{
|
||
source: '6',
|
||
target: '1',
|
||
value: 0.7,
|
||
extra: {
|
||
transmission_strength: 0.7,
|
||
transmission_type: '政策驱动',
|
||
description: '政策对主事件的推动作用'
|
||
}
|
||
},
|
||
{
|
||
source: '6',
|
||
target: '2',
|
||
value: 0.6,
|
||
extra: {
|
||
transmission_strength: 0.6,
|
||
transmission_type: '政策支持',
|
||
description: '政策对行业的支持'
|
||
}
|
||
}
|
||
],
|
||
categories: ['事件', '行业', '公司', '政策', '技术', '市场', '其他']
|
||
},
|
||
message: '获取成功'
|
||
};
|
||
|
||
return HttpResponse.json(mockTransmissionData);
|
||
}),
|
||
|
||
// 获取桑基图数据
|
||
http.get('/api/events/:eventId/sankey-data', async ({ params }) => {
|
||
await delay(300);
|
||
const { eventId } = params;
|
||
console.log('[Mock] 获取桑基图数据, eventId:', eventId);
|
||
|
||
const mockSankeyData = {
|
||
success: true,
|
||
data: {
|
||
nodes: [
|
||
{
|
||
name: '相关政策',
|
||
type: 'policy',
|
||
level: 0,
|
||
color: '#10ac84'
|
||
},
|
||
{
|
||
name: '主要事件',
|
||
type: 'event',
|
||
level: 0,
|
||
color: '#ff4757'
|
||
},
|
||
{
|
||
name: '半导体行业',
|
||
type: 'industry',
|
||
level: 1,
|
||
color: '#00d2d3'
|
||
},
|
||
{
|
||
name: '芯片制造',
|
||
type: 'industry',
|
||
level: 2,
|
||
color: '#00d2d3'
|
||
},
|
||
{
|
||
name: 'A公司',
|
||
type: 'company',
|
||
level: 3,
|
||
color: '#54a0ff'
|
||
},
|
||
{
|
||
name: 'B公司',
|
||
type: 'company',
|
||
level: 3,
|
||
color: '#54a0ff'
|
||
}
|
||
],
|
||
links: [
|
||
{ source: 0, target: 1, value: 7 }, // 相关政策 -> 主要事件
|
||
{ source: 0, target: 2, value: 6 }, // 相关政策 -> 半导体行业
|
||
{ source: 1, target: 2, value: 8 }, // 主要事件 -> 半导体行业
|
||
{ source: 2, target: 3, value: 7 }, // 半导体行业 -> 芯片制造
|
||
{ source: 3, target: 4, value: 6 }, // 芯片制造 -> A公司
|
||
{ source: 3, target: 5, value: 5 } // 芯片制造 -> B公司
|
||
]
|
||
},
|
||
message: '获取成功'
|
||
};
|
||
|
||
return HttpResponse.json(mockSankeyData);
|
||
}),
|
||
|
||
// 获取传导链节点详情
|
||
http.get('/api/events/:eventId/chain-node/:nodeId', async ({ params }) => {
|
||
await delay(300);
|
||
|
||
const { eventId, nodeId } = params;
|
||
|
||
console.log('[Mock] 获取节点详情, eventId:', eventId, 'nodeId:', nodeId);
|
||
|
||
// 根据节点ID返回不同的详细信息
|
||
const nodeDetailsMap = {
|
||
'1': {
|
||
success: true,
|
||
data: {
|
||
node: {
|
||
id: '1',
|
||
name: '主要事件',
|
||
type: 'event',
|
||
description: '这是影响整个产业链的重大事件,涉及政策调整和技术突破,对下游产业产生深远影响。',
|
||
importance_score: 50,
|
||
total_connections: 2,
|
||
incoming_connections: 1,
|
||
outgoing_connections: 1
|
||
},
|
||
parents: [
|
||
{
|
||
id: '6',
|
||
name: '相关政策',
|
||
transmission_mechanism: {
|
||
data: [
|
||
{
|
||
author: "国务院",
|
||
sentences: "为加快实施创新驱动发展战略,推动产业转型升级,国家将对重点领域给予财政补贴支持,单个项目最高补贴金额可达5000万元,同时享受研发费用加计扣除175%的税收优惠政策",
|
||
query_part: "国家财政补贴最高5000万元,研发费用加计扣除175%",
|
||
match_score: "好",
|
||
declare_date: "2024-01-15T00:00:00",
|
||
report_title: "关于促进产业高质量发展的若干政策措施"
|
||
},
|
||
{
|
||
author: "工信部",
|
||
sentences: "根据《重点产业扶持目录》,对符合条件的企业和项目,将优先纳入政府采购名单,并提供专项资金支持,确保政策红利直接惠及实体经济",
|
||
query_part: "政府采购优先支持,专项资金直达企业",
|
||
match_score: "好",
|
||
declare_date: "2024-01-20T00:00:00",
|
||
report_title: "工业和信息化部关于落实产业扶持政策的通知"
|
||
}
|
||
]
|
||
},
|
||
direction: 'positive',
|
||
strength: 70,
|
||
is_circular: false
|
||
}
|
||
],
|
||
children: [
|
||
{
|
||
id: '2',
|
||
name: '半导体行业(正向影响)',
|
||
transmission_mechanism: {
|
||
data: [
|
||
{
|
||
author: "李明",
|
||
organization: "中国电子信息产业发展研究院",
|
||
sentences: "在技术突破和应用场景快速扩张的双重驱动下,国内半导体市场呈现爆发式增长态势。据统计,2024年上半年半导体市场规模达到1.2万亿元,同比增长32%,其中新能源汽车和AI算力芯片需求贡献了超过60%的增量",
|
||
query_part: "技术突破和需求激增推动半导体市场增长32%",
|
||
match_score: "好",
|
||
declare_date: "2024-07-10T00:00:00",
|
||
report_title: "2024年上半年中国半导体产业发展报告"
|
||
}
|
||
]
|
||
},
|
||
direction: 'positive',
|
||
strength: 80,
|
||
is_circular: false
|
||
},
|
||
{
|
||
id: '7',
|
||
name: '传统制造业(负向影响)',
|
||
transmission_mechanism: {
|
||
data: [
|
||
{
|
||
author: "张华",
|
||
organization: "经济观察报",
|
||
sentences: "随着半导体等高科技产业获得大量政策和资金支持,传统制造业面临融资难、用工成本上升等多重压力。部分劳动密集型企业利润率下降15%,行业整体投资意愿降低",
|
||
query_part: "资源向高科技倾斜导致传统制造业承压",
|
||
match_score: "好",
|
||
declare_date: "2024-06-15T00:00:00",
|
||
report_title: "传统制造业转型升级调研报告"
|
||
}
|
||
]
|
||
},
|
||
direction: 'negative',
|
||
strength: 60,
|
||
is_circular: false
|
||
},
|
||
{
|
||
id: '8',
|
||
name: '能源行业(中性影响)',
|
||
transmission_mechanism: {
|
||
data: [
|
||
{
|
||
author: "王刚",
|
||
organization: "能源研究所",
|
||
sentences: "半导体产业扩张带来电力需求增长约8%,但同时推动节能技术应用,整体能源消费结构趋于优化。新建芯片工厂虽增加用电负荷,但智能电网技术应用使能源利用效率提升12%",
|
||
query_part: "半导体产业对能源行业影响相对中性",
|
||
match_score: "中",
|
||
declare_date: "2024-07-01T00:00:00",
|
||
report_title: "高科技产业能源消费分析"
|
||
}
|
||
]
|
||
},
|
||
direction: 'neutral',
|
||
strength: 40,
|
||
is_circular: false
|
||
},
|
||
{
|
||
id: '9',
|
||
name: '教育培训行业(未明确方向)',
|
||
transmission_mechanism: {
|
||
data: [
|
||
{
|
||
author: "赵敏",
|
||
organization: "教育部职业教育司",
|
||
sentences: "半导体产业快速发展催生大量专业人才需求,各类培训机构、职业院校纷纷开设相关课程。预计未来三年将新增半导体专业学员超过50万人,带动职业教育市场规模扩大",
|
||
query_part: "半导体产业推动职业教育发展",
|
||
match_score: "好",
|
||
declare_date: "2024-06-20T00:00:00",
|
||
report_title: "半导体人才培养白皮书"
|
||
}
|
||
]
|
||
},
|
||
strength: 50,
|
||
is_circular: false
|
||
}
|
||
]
|
||
}
|
||
},
|
||
'2': {
|
||
success: true,
|
||
data: {
|
||
node: {
|
||
id: '2',
|
||
name: '半导体行业',
|
||
type: 'industry',
|
||
description: '半导体行业是现代科技产业的基础,受到主事件和政策的双重推动,迎来新一轮发展机遇。',
|
||
importance_score: 40,
|
||
total_connections: 3,
|
||
incoming_connections: 2,
|
||
outgoing_connections: 1
|
||
},
|
||
parents: [
|
||
{
|
||
id: '1',
|
||
name: '主要事件',
|
||
transmission_mechanism: {
|
||
data: [
|
||
{
|
||
author: "刘洋",
|
||
organization: "中国半导体行业协会",
|
||
sentences: "受益于新能源汽车、5G通信等新兴应用领域的爆发式增长,国内半导体市场需求持续旺盛,2024年Q1市场规模同比增长28%,创历史新高",
|
||
query_part: "新兴应用推动半导体需求增长28%",
|
||
match_score: "好",
|
||
declare_date: "2024-04-05T00:00:00",
|
||
report_title: "2024年Q1中国半导体行业景气度报告"
|
||
},
|
||
{
|
||
author: "刘洋",
|
||
organization: "中国半导体行业协会",
|
||
sentences: "受益于新能源汽车、5G通信等新兴应用领域的爆发式增长,国内半导体市场需求持续旺盛,2024年Q1市场规模同比增长28%,创历史新高",
|
||
query_part: "新兴应用推动半导体需求增长28%",
|
||
match_score: "好",
|
||
declare_date: "2024-04-05T00:00:00",
|
||
report_title: "2024年Q1中国半导体行业景气度报告"
|
||
}
|
||
]
|
||
},
|
||
direction: 'positive',
|
||
strength: 80,
|
||
is_circular: false
|
||
},
|
||
{
|
||
id: '6',
|
||
name: '相关政策',
|
||
transmission_mechanism: {
|
||
data: [
|
||
{
|
||
author: "国家发改委",
|
||
sentences: "《国家集成电路产业发展推进纲要》明确提出,到2025年半导体产业自给率要达到70%以上,国家将设立专项基金规模超过3000亿元,重点支持半导体设备、材料、设计等关键环节",
|
||
query_part: "半导体自给率目标70%,专项基金3000亿",
|
||
match_score: "好",
|
||
declare_date: "2024-02-01T00:00:00",
|
||
report_title: "国家集成电路产业发展推进纲要(2024-2030)"
|
||
}
|
||
]
|
||
},
|
||
direction: 'positive',
|
||
strength: 60,
|
||
is_circular: false
|
||
}
|
||
],
|
||
children: [
|
||
{
|
||
id: '3',
|
||
name: '芯片制造',
|
||
transmission_mechanism: {
|
||
data: [
|
||
{
|
||
author: "张明",
|
||
organization: "中信证券",
|
||
sentences: "在半导体行业景气度持续提升的背景下,下游芯片制造企业订单饱满,产能利用率达到历史新高,预计2024年产能扩张将达到30%以上,技术工艺也将从28nm向14nm升级",
|
||
query_part: "半导体行业繁荣带动芯片制造产能扩张30%",
|
||
match_score: "好",
|
||
declare_date: "2024-03-15T00:00:00",
|
||
report_title: "半导体行业深度报告:产业链景气度传导分析"
|
||
},
|
||
{
|
||
author: "李华",
|
||
organization: "海通证券",
|
||
sentences: "芯片制造环节作为半导体产业链核心,受益于上游材料供应稳定和下游应用需求旺盛,技术迭代速度明显加快,先进制程占比持续提升",
|
||
query_part: "技术迭代加快,先进制程占比提升",
|
||
match_score: "好",
|
||
declare_date: "2024-02-28T00:00:00",
|
||
report_title: "芯片制造行业跟踪报告"
|
||
}
|
||
]
|
||
},
|
||
direction: 'positive',
|
||
strength: 70,
|
||
is_circular: false
|
||
}
|
||
]
|
||
}
|
||
},
|
||
'3': {
|
||
success: true,
|
||
data: {
|
||
node: {
|
||
id: '3',
|
||
name: '芯片制造',
|
||
type: 'industry',
|
||
description: '芯片制造作为半导体产业链的核心环节,在上游需求推动下,产能利用率提升,技术迭代加快。',
|
||
importance_score: 35,
|
||
total_connections: 3,
|
||
incoming_connections: 1,
|
||
outgoing_connections: 2
|
||
},
|
||
parents: [
|
||
{
|
||
id: '2',
|
||
name: '半导体行业',
|
||
transmission_mechanism: {
|
||
data: [
|
||
{
|
||
author: "张明",
|
||
sentences: "在半导体行业景气度持续提升的背景下,下游芯片制造企业订单饱满,产能利用率达到历史新高,预计2024年产能扩张将达到30%以上,技术工艺也将从28nm向14nm升级",
|
||
query_part: "半导体行业繁荣带动芯片制造产能扩张30%",
|
||
match_score: "好",
|
||
declare_date: "2024-03-15T00:00:00",
|
||
report_title: "半导体行业深度报告:产业链景气度传导分析"
|
||
},
|
||
{
|
||
author: "李华",
|
||
sentences: "芯片制造环节作为半导体产业链核心,受益于上游材料供应稳定和下游应用需求旺盛,技术迭代速度明显加快,先进制程占比持续提升",
|
||
query_part: "技术迭代加快,先进制程占比提升",
|
||
match_score: "好",
|
||
declare_date: "2024-02-28T00:00:00",
|
||
report_title: "芯片制造行业跟踪报告"
|
||
}
|
||
]
|
||
},
|
||
direction: 'positive',
|
||
strength: 70,
|
||
is_circular: false
|
||
}
|
||
],
|
||
children: [
|
||
{
|
||
id: '4',
|
||
name: 'A公司',
|
||
transmission_mechanism: {
|
||
data: [
|
||
{
|
||
author: "王芳",
|
||
organization: "国泰君安",
|
||
sentences: "A公司作为国内芯片制造龙头企业,在手订单已排至2024年Q4,预计全年营收增长45%,净利润增长60%以上。公司28nm及以下先进制程产能占比已达到40%,技术实力行业领先",
|
||
query_part: "A公司在手订单充足,预计营收增长45%",
|
||
match_score: "好",
|
||
declare_date: "2024-04-10T00:00:00",
|
||
report_title: "A公司深度研究:受益芯片制造景气周期"
|
||
}
|
||
]
|
||
},
|
||
direction: 'positive',
|
||
strength: 60,
|
||
is_circular: false
|
||
},
|
||
{
|
||
id: '5',
|
||
name: 'B公司',
|
||
transmission_mechanism: {
|
||
data: [
|
||
{
|
||
author: "赵强",
|
||
organization: "华泰证券",
|
||
sentences: "随着芯片制造产能的大规模扩张,上游设备和材料供应商迎来历史性机遇。B公司作为核心配套企业,订单量同比增长55%,产品供不应求,预计2024年营收将突破百亿大关。公司在封装测试领域的市场份额已提升至国内第二位",
|
||
query_part: "B公司订单增长55%,营收将破百亿",
|
||
match_score: "好",
|
||
declare_date: "2024-05-08T00:00:00",
|
||
report_title: "B公司跟踪报告:芯片产业链配套龙头崛起"
|
||
},
|
||
{
|
||
author: "陈彤",
|
||
organization: "国信证券",
|
||
sentences: "B公司深度受益于芯片制造产业链的景气度传导。公司凭借先进的封装技术和完善的产能布局,成功绑定多家头部芯片制造企业,形成稳定的供应关系。随着下游客户产能持续扩张,公司业绩增长确定性强",
|
||
query_part: "B公司受益产业链景气度,业绩增长确定性强",
|
||
match_score: "好",
|
||
declare_date: "2024-06-01T00:00:00",
|
||
report_title: "半导体封装测试行业专题:产业链景气度传导分析"
|
||
}
|
||
]
|
||
},
|
||
direction: 'positive',
|
||
strength: 50,
|
||
is_circular: false
|
||
}
|
||
]
|
||
}
|
||
},
|
||
'4': {
|
||
success: true,
|
||
data: {
|
||
node: {
|
||
id: '4',
|
||
name: 'A公司',
|
||
type: 'company',
|
||
description: 'A公司是行业龙头企业,拥有先进的芯片制造技术和完整的产业链布局,在本轮产业升级中占据有利位置。',
|
||
importance_score: 30,
|
||
stock_code: '600000',
|
||
total_connections: 1,
|
||
incoming_connections: 1,
|
||
outgoing_connections: 0
|
||
},
|
||
parents: [
|
||
{
|
||
id: '3',
|
||
name: '芯片制造',
|
||
transmission_mechanism: {
|
||
data: [
|
||
{
|
||
author: "王芳",
|
||
sentences: "A公司作为国内芯片制造龙头企业,在手订单已排至2024年Q4,预计全年营收增长45%,净利润增长60%以上。公司28nm及以下先进制程产能占比已达到40%,技术实力行业领先",
|
||
query_part: "A公司在手订单充足,预计营收增长45%",
|
||
match_score: "好",
|
||
declare_date: "2024-04-10T00:00:00",
|
||
report_title: "A公司深度研究:受益芯片制造景气周期"
|
||
}
|
||
]
|
||
},
|
||
direction: 'positive',
|
||
strength: 60,
|
||
is_circular: false
|
||
}
|
||
],
|
||
children: []
|
||
}
|
||
},
|
||
'5': {
|
||
success: true,
|
||
data: {
|
||
node: {
|
||
id: '5',
|
||
name: 'B公司',
|
||
type: 'company',
|
||
description: 'B公司专注于芯片封装测试领域,随着上游制造产能释放,公司订单饱满,业绩稳步增长。',
|
||
importance_score: 25,
|
||
stock_code: '600001',
|
||
total_connections: 1,
|
||
incoming_connections: 1,
|
||
outgoing_connections: 0
|
||
},
|
||
parents: [
|
||
{
|
||
id: '3',
|
||
name: '芯片制造',
|
||
transmission_mechanism: {
|
||
data: [
|
||
{
|
||
author: "赵强",
|
||
organization: "华泰证券",
|
||
sentences: "随着芯片制造产能的大规模扩张,上游设备和材料供应商迎来历史性机遇。B公司作为核心配套企业,订单量同比增长55%,产品供不应求,预计2024年营收将突破百亿大关",
|
||
query_part: "B公司订单增长55%,营收将破百亿",
|
||
match_score: "好",
|
||
declare_date: "2024-05-08T00:00:00",
|
||
report_title: "B公司跟踪报告:芯片产业链配套龙头崛起"
|
||
}
|
||
]
|
||
},
|
||
direction: 'positive',
|
||
strength: 50,
|
||
is_circular: false
|
||
}
|
||
],
|
||
children: []
|
||
}
|
||
},
|
||
'6': {
|
||
success: true,
|
||
data: {
|
||
node: {
|
||
id: '6',
|
||
name: '相关政策',
|
||
type: 'policy',
|
||
description: '国家出台了一系列产业扶持政策,包括财政补贴、税收减免和研发支持,旨在推动产业自主创新和进口替代。',
|
||
importance_score: 30,
|
||
total_connections: 2,
|
||
incoming_connections: 0,
|
||
outgoing_connections: 2
|
||
},
|
||
parents: [],
|
||
children: [
|
||
{
|
||
id: '1',
|
||
name: '主要事件',
|
||
transmission_mechanism: {
|
||
data: [
|
||
{
|
||
author: "国务院",
|
||
sentences: "为加快实施创新驱动发展战略,推动产业转型升级,国家将对重点领域给予财政补贴支持,单个项目最高补贴金额可达5000万元,同时享受研发费用加计扣除175%的税收优惠政策",
|
||
query_part: "国家财政补贴最高5000万元,研发费用加计扣除175%",
|
||
match_score: "好",
|
||
declare_date: "2024-01-15T00:00:00",
|
||
report_title: "关于促进产业高质量发展的若干政策措施"
|
||
},
|
||
{
|
||
author: "工信部",
|
||
sentences: "将重点支持关键核心技术攻关和产业化应用,建立产业发展专项基金,规模达到1000亿元,引导社会资本共同参与产业发展",
|
||
query_part: "设立1000亿元产业发展专项基金",
|
||
match_score: "好",
|
||
declare_date: "2024-02-01T00:00:00",
|
||
report_title: "产业发展专项基金管理办法"
|
||
}
|
||
]
|
||
},
|
||
direction: 'positive',
|
||
strength: 70,
|
||
is_circular: false
|
||
},
|
||
{
|
||
id: '2',
|
||
name: '半导体行业',
|
||
transmission_mechanism: {
|
||
data: [
|
||
{
|
||
author: "国家发改委",
|
||
sentences: "《国家集成电路产业发展推进纲要》明确提出,到2025年半导体产业自给率要达到70%以上,国家将设立专项基金规模超过3000亿元,重点支持半导体设备、材料、设计等关键环节。同时,通过进口替代战略,加快培育本土产业链",
|
||
query_part: "半导体自给率目标70%,专项基金3000亿",
|
||
match_score: "好",
|
||
declare_date: "2024-02-01T00:00:00",
|
||
report_title: "国家集成电路产业发展推进纲要(2024-2030)"
|
||
},
|
||
{
|
||
author: "工信部",
|
||
sentences: "将重点支持关键核心技术攻关和产业化应用,建立产业发展专项基金,规模达到1000亿元,引导社会资本共同参与产业发展。通过税收优惠、研发补贴等政策工具,为半导体行业创造良好的发展环境",
|
||
query_part: "设立1000亿元产业发展专项基金",
|
||
match_score: "好",
|
||
declare_date: "2024-02-01T00:00:00",
|
||
report_title: "产业发展专项基金管理办法"
|
||
}
|
||
]
|
||
},
|
||
direction: 'positive',
|
||
strength: 60,
|
||
is_circular: false
|
||
}
|
||
]
|
||
}
|
||
}
|
||
};
|
||
|
||
// 返回对应节点的详情,如果不存在则返回默认数据
|
||
const nodeDetail = nodeDetailsMap[nodeId] || {
|
||
success: true,
|
||
data: {
|
||
node: {
|
||
id: nodeId,
|
||
name: '未知节点',
|
||
type: 'other',
|
||
description: '该节点暂无详细信息',
|
||
importance_score: 0,
|
||
total_connections: 0,
|
||
incoming_connections: 0,
|
||
outgoing_connections: 0
|
||
},
|
||
parents: [],
|
||
children: []
|
||
}
|
||
};
|
||
|
||
return HttpResponse.json(nodeDetail);
|
||
}),
|
||
|
||
// ==================== 投资日历相关 ====================
|
||
|
||
// 获取月度事件统计
|
||
http.get('/api/v1/calendar/event-counts', async ({ request }) => {
|
||
await delay(300);
|
||
|
||
const url = new URL(request.url);
|
||
const year = parseInt(url.searchParams.get('year'));
|
||
const month = parseInt(url.searchParams.get('month'));
|
||
|
||
console.log('[Mock] 获取月度事件统计:', { year, month });
|
||
|
||
const eventCounts = getMockEventCountsForMonth(year, month);
|
||
|
||
return HttpResponse.json({
|
||
success: true,
|
||
data: eventCounts
|
||
});
|
||
}),
|
||
|
||
// 获取指定日期的事件列表
|
||
http.get('/api/v1/calendar/events', async ({ request }) => {
|
||
await delay(300);
|
||
|
||
const url = new URL(request.url);
|
||
const dateStr = url.searchParams.get('date');
|
||
const type = url.searchParams.get('type') || 'all';
|
||
|
||
console.log('[Mock] 获取日历事件列表:', { date: dateStr, type });
|
||
|
||
if (!dateStr) {
|
||
return HttpResponse.json({
|
||
success: false,
|
||
error: 'Date parameter required'
|
||
}, { status: 400 });
|
||
}
|
||
|
||
const events = getMockFutureEvents(dateStr, type);
|
||
|
||
return HttpResponse.json({
|
||
success: true,
|
||
data: events
|
||
});
|
||
}),
|
||
|
||
// 切换未来事件关注状态
|
||
http.post('/api/v1/calendar/events/:eventId/follow', async ({ params }) => {
|
||
await delay(300);
|
||
|
||
const { eventId } = params;
|
||
|
||
console.log('[Mock] 切换事件关注状态, eventId:', eventId);
|
||
|
||
// 简单返回成功,实际状态管理可以后续完善
|
||
return HttpResponse.json({
|
||
success: true,
|
||
data: {
|
||
is_following: true,
|
||
message: '关注成功'
|
||
}
|
||
});
|
||
}),
|
||
|
||
// ==================== 历史事件对比相关 ====================
|
||
|
||
// 获取历史事件列表
|
||
http.get('/api/events/:eventId/historical', async ({ params }) => {
|
||
await delay(400);
|
||
|
||
const { eventId } = params;
|
||
|
||
console.log('[Mock] 获取历史事件列表, eventId:', eventId);
|
||
|
||
// 生成历史事件数据
|
||
const generateHistoricalEvents = (count = 5) => {
|
||
const events = [];
|
||
const eventTitles = [
|
||
'芯片产业链政策扶持升级',
|
||
'新能源汽车销量创历史新高',
|
||
'人工智能大模型技术突破',
|
||
'半导体设备国产化加速',
|
||
'数字经济政策利好发布',
|
||
'新能源产业链整合提速',
|
||
'医药创新药获批上市',
|
||
'5G应用场景扩展',
|
||
'智能驾驶技术迭代升级',
|
||
'储能行业景气度上行'
|
||
];
|
||
|
||
const importanceLevels = [1, 2, 3, 4, 5];
|
||
|
||
for (let i = 0; i < count; i++) {
|
||
const daysAgo = Math.floor(Math.random() * 180) + 30; // 30-210 天前
|
||
const date = new Date();
|
||
date.setDate(date.getDate() - daysAgo);
|
||
|
||
const importance = importanceLevels[Math.floor(Math.random() * importanceLevels.length)];
|
||
const title = eventTitles[i % eventTitles.length];
|
||
|
||
// 带引用来源的研报数据
|
||
const researchReports = [
|
||
{
|
||
author: '中信证券',
|
||
report_title: `${title}深度研究报告`,
|
||
declare_date: new Date(date.getTime() - Math.floor(Math.random() * 10) * 24 * 60 * 60 * 1000).toISOString()
|
||
},
|
||
{
|
||
author: '国泰君安',
|
||
report_title: `行业专题:${title}影响分析`,
|
||
declare_date: new Date(date.getTime() - Math.floor(Math.random() * 15) * 24 * 60 * 60 * 1000).toISOString()
|
||
},
|
||
{
|
||
author: '华泰证券',
|
||
report_title: `${title}投资机会深度解析`,
|
||
declare_date: new Date(date.getTime() - Math.floor(Math.random() * 20) * 24 * 60 * 60 * 1000).toISOString()
|
||
}
|
||
];
|
||
|
||
// 生成带引用标记的content(data结构)
|
||
const contentWithCitations = {
|
||
data: [
|
||
{
|
||
query_part: `${title}的详细描述。该事件对相关产业链产生重要影响【1】,市场关注度高,相关概念股表现活跃。`,
|
||
sentences: `根据券商研报分析,${title}将推动相关产业链快速发展【2】。预计未来${Math.floor(Math.random() * 2 + 1)}年内,相关企业营收增速有望达到${Math.floor(Math.random() * 30 + 20)}%以上【3】。该事件的影响范围广泛,涉及多个细分领域,投资机会显著。`,
|
||
match_score: importance >= 4 ? '好' : (importance >= 2 ? '中' : '一般'),
|
||
author: researchReports[0].author,
|
||
declare_date: researchReports[0].declare_date,
|
||
report_title: researchReports[0].report_title
|
||
},
|
||
{
|
||
query_part: `市场分析师认为,该事件将带动产业链上下游企业协同发展【2】,形成良性循环。`,
|
||
sentences: `从产业趋势来看,相关板块估值仍处于合理区间,具备较高的安全边际。机构投资者持续加仓相关标的,显示出对长期发展前景的看好。`,
|
||
match_score: importance >= 3 ? '好' : '中',
|
||
author: researchReports[1].author,
|
||
declare_date: researchReports[1].declare_date,
|
||
report_title: researchReports[1].report_title
|
||
},
|
||
{
|
||
query_part: `根据行业数据显示,受此事件影响,相关企业订单量同比增长${Math.floor(Math.random() * 40 + 30)}%【3】。`,
|
||
sentences: `行业景气度持续提升,龙头企业凭借技术优势和规模效应,市场份额有望进一步扩大。建议关注产业链核心环节的投资机会。`,
|
||
match_score: '好',
|
||
author: researchReports[2].author,
|
||
declare_date: researchReports[2].declare_date,
|
||
report_title: researchReports[2].report_title
|
||
}
|
||
]
|
||
};
|
||
|
||
events.push({
|
||
id: `hist_event_${i + 1}`,
|
||
title: title,
|
||
content: contentWithCitations, // 升级版本:带引用来源的data结构
|
||
description: `${title}的详细描述。该事件对相关产业链产生重要影响,市场关注度高,相关概念股表现活跃。`, // 降级兼容
|
||
date: date.toISOString().split('T')[0],
|
||
importance: importance,
|
||
similarity: Math.floor(Math.random() * 10) + 1, // 1-10
|
||
impact_sectors: [
|
||
['半导体', '芯片设计', 'EDA'],
|
||
['新能源汽车', '锂电池', '充电桩'],
|
||
['人工智能', '算力', '大模型'],
|
||
['半导体设备', '国产替代', '集成电路'],
|
||
['数字经济', '云计算', '大数据']
|
||
][i % 5],
|
||
affected_stocks_count: Math.floor(Math.random() * 30) + 10, // 10-40 只股票
|
||
avg_change_pct: parseFloat((Math.random() * 10 - 2).toFixed(2)), // -2% to +8%
|
||
created_at: date.toISOString()
|
||
});
|
||
}
|
||
|
||
// 按日期降序排序
|
||
return events.sort((a, b) => new Date(b.date) - new Date(a.date));
|
||
};
|
||
|
||
try {
|
||
const historicalEvents = generateHistoricalEvents(5);
|
||
|
||
return HttpResponse.json({
|
||
success: true,
|
||
data: historicalEvents,
|
||
total: historicalEvents.length,
|
||
message: '获取历史事件列表成功'
|
||
});
|
||
} catch (error) {
|
||
console.error('[Mock] 获取历史事件列表失败:', error);
|
||
return HttpResponse.json(
|
||
{
|
||
success: false,
|
||
error: '获取历史事件列表失败',
|
||
data: []
|
||
},
|
||
{ status: 500 }
|
||
);
|
||
}
|
||
}),
|
||
|
||
// 获取历史事件相关股票
|
||
http.get('/api/historical-events/:eventId/stocks', async ({ params }) => {
|
||
await delay(500);
|
||
|
||
const { eventId } = params;
|
||
|
||
console.log('[Mock] 获取历史事件相关股票, eventId:', eventId);
|
||
|
||
// 生成历史事件相关股票数据
|
||
const generateHistoricalEventStocks = (count = 10) => {
|
||
const stocks = [];
|
||
const sectors = ['半导体', '新能源', '医药', '消费电子', '人工智能', '5G通信'];
|
||
const stockNames = [
|
||
'中芯国际', '长江存储', '华为海思', '紫光国微', '兆易创新',
|
||
'宁德时代', '比亚迪', '隆基绿能', '阳光电源', '亿纬锂能',
|
||
'恒瑞医药', '迈瑞医疗', '药明康德', '泰格医药', '康龙化成',
|
||
'立讯精密', '歌尔声学', '京东方A', 'TCL科技', '海康威视',
|
||
'科大讯飞', '商汤科技', '寒武纪', '海光信息', '中兴通讯'
|
||
];
|
||
|
||
for (let i = 0; i < count; i++) {
|
||
const stockCode = `${Math.random() > 0.5 ? '6' : '0'}${String(Math.floor(Math.random() * 100000)).padStart(5, '0')}`;
|
||
const changePct = (Math.random() * 15 - 3).toFixed(2); // -3% ~ +12%
|
||
const correlation = (Math.random() * 0.4 + 0.6).toFixed(2); // 0.6 ~ 1.0
|
||
|
||
stocks.push({
|
||
id: `stock_${i}`,
|
||
stock_code: `${stockCode}.${Math.random() > 0.5 ? 'SH' : 'SZ'}`,
|
||
stock_name: stockNames[i % stockNames.length],
|
||
sector: sectors[Math.floor(Math.random() * sectors.length)],
|
||
correlation: parseFloat(correlation),
|
||
event_day_change_pct: parseFloat(changePct),
|
||
relation_desc: {
|
||
data: [
|
||
{
|
||
query_part: `该公司是${sectors[Math.floor(Math.random() * sectors.length)]}行业龙头,受事件影响显著,市场关注度高,订单量同比增长${Math.floor(Math.random() * 50 + 20)}%`,
|
||
sentences: `根据行业研究报告,该公司在${sectors[Math.floor(Math.random() * sectors.length)]}领域具有核心技术优势,产能利用率达到${Math.floor(Math.random() * 20 + 80)}%,随着事件的深入发展,公司业绩有望持续受益。机构预测未来三年复合增长率将达到${Math.floor(Math.random() * 30 + 15)}%以上`,
|
||
match_score: correlation > 0.8 ? '好' : (correlation > 0.6 ? '中' : '一般'),
|
||
author: ['中信证券', '国泰君安', '华泰证券', '招商证券'][Math.floor(Math.random() * 4)],
|
||
declare_date: new Date(Date.now() - Math.floor(Math.random() * 90) * 24 * 60 * 60 * 1000).toISOString(),
|
||
report_title: `${stockNames[i % stockNames.length]}深度研究报告`
|
||
}
|
||
]
|
||
}
|
||
});
|
||
}
|
||
|
||
// 按相关度降序排序
|
||
return stocks.sort((a, b) => b.correlation - a.correlation);
|
||
};
|
||
|
||
try {
|
||
const stocks = generateHistoricalEventStocks(15);
|
||
|
||
return HttpResponse.json({
|
||
success: true,
|
||
data: stocks,
|
||
message: '获取历史事件相关股票成功'
|
||
});
|
||
} catch (error) {
|
||
console.error('[Mock] 获取历史事件相关股票失败:', error);
|
||
return HttpResponse.json(
|
||
{
|
||
success: false,
|
||
error: '获取历史事件相关股票失败',
|
||
data: []
|
||
},
|
||
{ status: 500 }
|
||
);
|
||
}
|
||
}),
|
||
|
||
// ==================== 评论相关 ====================
|
||
|
||
// 获取事件评论列表
|
||
http.get('/api/events/:eventId/posts', async ({ params, request }) => {
|
||
await delay(300);
|
||
|
||
const { eventId } = params;
|
||
const url = new URL(request.url);
|
||
const sort = url.searchParams.get('sort') || 'latest';
|
||
const page = parseInt(url.searchParams.get('page') || '1');
|
||
const perPage = parseInt(url.searchParams.get('per_page') || '20');
|
||
|
||
console.log('[Mock] 获取评论列表, eventId:', eventId, 'sort:', sort);
|
||
|
||
try {
|
||
// 从内存存储获取评论列表
|
||
const allComments = getOrInitComments(eventId);
|
||
|
||
// ✅ 创建副本并排序(避免直接修改原数组)
|
||
let sortedComments = [...allComments];
|
||
if (sort === 'hot') {
|
||
sortedComments.sort((a, b) => b.likes_count - a.likes_count);
|
||
} else {
|
||
// 默认按时间升序(oldest first)- 最旧评论在前,最新在后
|
||
sortedComments.sort((a, b) => new Date(a.created_at) - new Date(b.created_at));
|
||
}
|
||
|
||
// 分页处理(使用排序后的副本)
|
||
const startIndex = (page - 1) * perPage;
|
||
const endIndex = startIndex + perPage;
|
||
const paginatedComments = sortedComments.slice(startIndex, endIndex);
|
||
|
||
return HttpResponse.json({
|
||
success: true,
|
||
data: paginatedComments,
|
||
pagination: {
|
||
page: page,
|
||
per_page: perPage,
|
||
total: allComments.length,
|
||
pages: Math.ceil(allComments.length / perPage),
|
||
has_prev: page > 1,
|
||
has_next: endIndex < allComments.length,
|
||
},
|
||
message: '获取评论成功',
|
||
});
|
||
} catch (error) {
|
||
console.error('[Mock] 获取评论列表失败:', error);
|
||
return HttpResponse.json(
|
||
{
|
||
success: false,
|
||
error: '获取评论失败',
|
||
data: [],
|
||
},
|
||
{ status: 500 }
|
||
);
|
||
}
|
||
}),
|
||
|
||
// 发表评论
|
||
http.post('/api/events/:eventId/posts', async ({ params, request }) => {
|
||
await delay(500);
|
||
|
||
const { eventId } = params;
|
||
const body = await request.json();
|
||
|
||
console.log('[Mock] 发表评论, eventId:', eventId, 'content:', body.content);
|
||
|
||
try {
|
||
// 获取当前登录用户信息
|
||
const currentUser = getCurrentUser();
|
||
|
||
// 模拟创建新评论
|
||
const newComment = {
|
||
id: `comment_${eventId}_${Date.now()}`,
|
||
content: body.content,
|
||
content_type: body.content_type || 'text',
|
||
author: {
|
||
id: currentUser?.id || 'current_user',
|
||
// 与导航区保持一致:优先显示昵称
|
||
username: currentUser?.nickname || currentUser?.username || currentUser?.email || '当前用户',
|
||
avatar: currentUser?.avatar_url || null,
|
||
},
|
||
created_at: new Date().toISOString(),
|
||
likes_count: 0,
|
||
is_liked: false,
|
||
};
|
||
|
||
// 将新评论添加到内存存储(插入到列表开头)
|
||
const comments = getOrInitComments(eventId);
|
||
comments.unshift(newComment);
|
||
|
||
console.log('[Mock] 评论已添加到内存存储, 当前评论总数:', comments.length);
|
||
|
||
return HttpResponse.json({
|
||
success: true,
|
||
data: newComment,
|
||
message: '评论发布成功',
|
||
});
|
||
} catch (error) {
|
||
console.error('[Mock] 发表评论失败:', error);
|
||
return HttpResponse.json(
|
||
{
|
||
success: false,
|
||
error: '评论发布失败',
|
||
message: '系统错误,请稍后重试',
|
||
},
|
||
{ status: 500 }
|
||
);
|
||
}
|
||
}),
|
||
|
||
// 删除帖子/评论
|
||
http.delete('/api/posts/:postId', async ({ params }) => {
|
||
await delay(300);
|
||
const { postId } = params;
|
||
|
||
console.log('[Mock] 删除帖子, postId:', postId);
|
||
|
||
try {
|
||
// 从内存存储中删除评论
|
||
let deleted = false;
|
||
for (const [eventId, comments] of commentsStore.entries()) {
|
||
const index = comments.findIndex(c => String(c.id) === String(postId));
|
||
if (index !== -1) {
|
||
comments.splice(index, 1);
|
||
deleted = true;
|
||
console.log('[Mock] 评论已从事件', eventId, '中删除');
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (!deleted) {
|
||
console.log('[Mock] 未找到评论,但仍返回成功(可能是乐观更新的评论)');
|
||
}
|
||
|
||
return HttpResponse.json({
|
||
success: true,
|
||
message: '删除成功',
|
||
});
|
||
} catch (error) {
|
||
console.error('[Mock] 删除帖子失败:', error);
|
||
return HttpResponse.json(
|
||
{
|
||
success: false,
|
||
error: '删除失败',
|
||
message: '系统错误,请稍后重试',
|
||
},
|
||
{ status: 500 }
|
||
);
|
||
}
|
||
}),
|
||
];
|