Files
vf_react/src/mocks/handlers/concept.js
zdl c1b8a98bb4 fix: 添加热门概念静态数据的 mock handler
- 拦截 /data/concept/latest.json 请求
- 返回 mock 生成的热门概念数据
- 修复 HeroPanel 热门概念模块无数据问题

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-15 14:52:31 +08:00

866 lines
39 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// src/mocks/handlers/concept.js
// 概念相关的 Mock Handlers
import { http, HttpResponse } from 'msw';
// 模拟延迟
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
// 生成历史触发时间3-5个历史日期
const generateHappenedTimes = (seed) => {
const times = [];
const count = 3 + (seed % 3); // 3-5个时间点
for (let i = 0; i < count; i++) {
const daysAgo = 30 + (seed * 7 + i * 11) % 330; // 30-360天前
const date = new Date();
date.setDate(date.getDate() - daysAgo);
times.push(date.toISOString().split('T')[0]);
}
return times.sort().reverse(); // 降序排列
};
// 生成核心相关股票
const generateStocksForConcept = (seed, count = 4) => {
const stockPool = [
{ name: '贵州茅台', code: '600519' },
{ name: '宁德时代', code: '300750' },
{ name: '中国平安', code: '601318' },
{ name: '比亚迪', code: '002594' },
{ name: '隆基绿能', code: '601012' },
{ name: '阳光电源', code: '300274' },
{ name: '三一重工', code: '600031' },
{ name: '中芯国际', code: '688981' },
{ name: '京东方A', code: '000725' },
{ name: '立讯精密', code: '002475' }
];
const stocks = [];
for (let i = 0; i < count; i++) {
const stockIndex = (seed + i * 7) % stockPool.length;
const stock = stockPool[stockIndex];
stocks.push({
stock_name: stock.name,
stock_code: stock.code,
reason: `作为行业龙头企业,${stock.name}在该领域具有核心竞争优势,市场份额领先,技术实力雄厚。`,
change_pct: parseFloat((Math.random() * 15 - 5).toFixed(2)) // -5% ~ +10%
});
}
return stocks;
};
// 生成热门概念数据
export const generatePopularConcepts = (size = 20) => {
const concepts = [
'人工智能', '新能源汽车', '半导体', '光伏', '锂电池',
'储能', '氢能源', '风电', '特高压', '工业母机',
'军工', '航空航天', '卫星导航', '量子科技', '数字货币',
'云计算', '大数据', '物联网', '5G', '6G',
'元宇宙', '虚拟现实', 'AIGC', 'ChatGPT', '算力',
'芯片设计', '芯片制造', '半导体设备', '半导体材料', 'EDA',
'新能源', '风光储', '充电桩', '智能电网', '特斯拉',
'比亚迪', '宁德时代', '华为', '苹果产业链', '鸿蒙',
'国产软件', '信创', '网络安全', '数据安全', '量子通信',
'医疗器械', '创新药', '医美', 'CXO', '生物医药',
'疫苗', '中药', '医疗信息化', '智慧医疗', '基因测序'
];
const conceptDescriptions = {
'人工智能': '人工智能是"技术突破+政策扶持"双轮驱动的硬科技主题。随着大模型技术的突破AI应用场景不断拓展预计将催化算力、数据、应用三大产业链。',
'新能源汽车': '新能源汽车行业景气度持续向好,渗透率不断提升。政策支持力度大,产业链上下游企业均受益明显。',
'半导体': '国产半导体替代加速,自主可控需求强烈。政策和资金支持力度大,行业迎来黄金发展期。',
'光伏': '光伏装机量快速增长,成本持续下降,行业景气度维持高位。双碳目标下,光伏行业前景广阔。',
'锂电池': '锂电池技术进步,成本优势扩大,下游应用领域持续扩张。新能源汽车和储能需求旺盛。',
'储能': '储能市场爆发式增长,政策支持力度大,应用场景不断拓展。未来市场空间巨大。',
'默认': '该概念市场关注度较高,具有一定的投资价值。相关企业技术实力雄厚,市场前景广阔。'
};
const matchTypes = ['hybrid_knn', 'keyword', 'semantic'];
const results = [];
for (let i = 0; i < Math.min(size, concepts.length); i++) {
const changePct = (Math.random() * 12 - 2).toFixed(2); // -2% 到 +10%
const stockCount = Math.floor(Math.random() * 50) + 10; // 10-60 只股票
const score = parseFloat((Math.random() * 5 + 3).toFixed(2)); // 3-8 分数范围
results.push({
concept: concepts[i],
concept_id: `CONCEPT_${1000 + i}`,
stock_count: stockCount,
score: score, // 相关度分数
match_type: matchTypes[i % 3], // 匹配类型
description: conceptDescriptions[concepts[i]] || conceptDescriptions['默认'],
price_info: {
avg_change_pct: parseFloat(changePct),
avg_price: parseFloat((Math.random() * 100 + 10).toFixed(2)),
total_market_cap: parseFloat((Math.random() * 1000 + 100).toFixed(2))
},
happened_times: generateHappenedTimes(i), // 历史触发时间
stocks: generateStocksForConcept(i, 4), // 核心相关股票
hot_score: Math.floor(Math.random() * 100)
});
}
// 按涨跌幅降序排序
results.sort((a, b) => b.price_info.avg_change_pct - a.price_info.avg_change_pct);
return results;
};
// 生成完整的概念统计数据(用于 ConceptStatsPanel
const generateConceptStats = () => {
// 热门概念涨幅最大的前5
const hot_concepts = [
{ name: '小米大模型', change_pct: 18.76, stock_count: 12, news_count: 35 },
{ name: '人工智能', change_pct: 15.67, stock_count: 45, news_count: 23 },
{ name: '新能源汽车', change_pct: 12.34, stock_count: 38, news_count: 18 },
{ name: '芯片概念', change_pct: 9.87, stock_count: 52, news_count: 31 },
{ name: '5G通信', change_pct: 8.45, stock_count: 29, news_count: 15 },
];
// 冷门概念跌幅最大的前5
const cold_concepts = [
{ name: '房地产', change_pct: -8.76, stock_count: 33, news_count: 12 },
{ name: '煤炭开采', change_pct: -6.54, stock_count: 25, news_count: 8 },
{ name: '传统零售', change_pct: -5.43, stock_count: 19, news_count: 6 },
{ name: '钢铁冶炼', change_pct: -4.21, stock_count: 28, news_count: 9 },
{ name: '纺织服装', change_pct: -3.98, stock_count: 15, news_count: 4 },
];
// 活跃概念(新闻+研报最多的前5
const active_concepts = [
{ name: '人工智能', news_count: 89, report_count: 15, total_mentions: 104 },
{ name: '芯片概念', news_count: 76, report_count: 12, total_mentions: 88 },
{ name: '新能源汽车', news_count: 65, report_count: 18, total_mentions: 83 },
{ name: '生物医药', news_count: 54, report_count: 9, total_mentions: 63 },
{ name: '量子科技', news_count: 41, report_count: 7, total_mentions: 48 },
];
// 波动最大的概念前5
const volatile_concepts = [
{ name: '区块链', volatility: 23.45, avg_change: 3.21, max_change: 12.34 },
{ name: '元宇宙', volatility: 21.87, avg_change: 2.98, max_change: 11.76 },
{ name: '虚拟现实', volatility: 19.65, avg_change: -1.23, max_change: 9.87 },
{ name: '游戏概念', volatility: 18.32, avg_change: 4.56, max_change: 10.45 },
{ name: '在线教育', volatility: 17.89, avg_change: -2.11, max_change: 8.76 },
];
// 动量概念连续上涨的前5
const momentum_concepts = [
{ name: '数字经济', consecutive_days: 5, total_change: 18.76, avg_daily: 3.75 },
{ name: '云计算', consecutive_days: 4, total_change: 14.32, avg_daily: 3.58 },
{ name: '物联网', consecutive_days: 4, total_change: 12.89, avg_daily: 3.22 },
{ name: '大数据', consecutive_days: 3, total_change: 11.45, avg_daily: 3.82 },
{ name: '工业互联网', consecutive_days: 3, total_change: 9.87, avg_daily: 3.29 },
];
return {
hot_concepts,
cold_concepts,
active_concepts,
volatile_concepts,
momentum_concepts
};
};
// 概念相关的 Handlers
export const conceptHandlers = [
// 搜索概念(热门概念)
http.post('/concept-api/search', async ({ request }) => {
await delay(300);
try {
const body = await request.json();
const { query = '', size = 20, page = 1, sort_by = 'change_pct' } = body;
console.log('[Mock Concept] 搜索概念:', { query, size, page, sort_by });
// 生成数据(不过滤,模拟真实 API 的语义搜索返回热门概念)
let results = generatePopularConcepts(size);
console.log('[Mock Concept] 生成概念数量:', results.length);
// Mock 环境下不做过滤,直接返回热门概念
// 真实环境会根据 query 进行语义搜索
// 根据排序字段排序
if (sort_by === 'change_pct') {
results.sort((a, b) => b.price_info.avg_change_pct - a.price_info.avg_change_pct);
} else if (sort_by === 'stock_count') {
results.sort((a, b) => b.stock_count - a.stock_count);
} else if (sort_by === 'hot_score') {
results.sort((a, b) => b.hot_score - a.hot_score);
}
return HttpResponse.json({
results,
total: results.length,
page,
size,
message: '搜索成功'
});
} catch (error) {
console.error('[Mock Concept] 搜索概念失败:', error);
return HttpResponse.json(
{
results: [],
total: 0,
error: '搜索失败'
},
{ status: 500 }
);
}
}),
// 获取单个概念详情
http.get('/concept-api/concepts/:conceptId', async ({ params }) => {
await delay(300);
const { conceptId } = params;
console.log('[Mock Concept] 获取概念详情:', conceptId);
const concepts = generatePopularConcepts(50);
const concept = concepts.find(c => c.concept_id === conceptId || c.concept === conceptId);
if (concept) {
return HttpResponse.json({
...concept,
related_stocks: [
{ stock_code: '600519', stock_name: '贵州茅台', change_pct: 2.34 },
{ stock_code: '000858', stock_name: '五粮液', change_pct: 1.89 },
{ stock_code: '000568', stock_name: '泸州老窖', change_pct: 3.12 }
],
news: [
{ title: `${concept.concept}板块异动`, date: '2024-10-24', source: '财经新闻' }
]
});
} else {
return HttpResponse.json(
{ error: '概念不存在' },
{ status: 404 }
);
}
}),
// 获取概念相关股票concept-api 路由)
http.get('/concept-api/concepts/:conceptId/stocks', async ({ params, request }) => {
await delay(300);
const { conceptId } = params;
const url = new URL(request.url);
const limit = parseInt(url.searchParams.get('limit') || '20');
console.log('[Mock Concept] 获取概念相关股票:', { conceptId, limit });
// 生成模拟股票数据(确保 change_pct 是数字类型)
const stocks = [];
for (let i = 0; i < limit; i++) {
const code = 600000 + i;
stocks.push({
stock_code: `${code}.SH`,
code: `${code}.SH`,
stock_name: `股票${i + 1}`,
name: `股票${i + 1}`,
change_pct: parseFloat((Math.random() * 10 - 2).toFixed(2)),
price: parseFloat((Math.random() * 100 + 10).toFixed(2)),
market_cap: parseFloat((Math.random() * 1000 + 100).toFixed(2)),
reason: '板块核心成分股'
});
}
return HttpResponse.json({
stocks,
total: stocks.length,
concept_id: conceptId
});
}),
// 获取概念相关股票(/api/concept 路由 - 热点概览异动列表使用)
http.get('/api/concept/:conceptId/stocks', async ({ params, request }) => {
await delay(200);
const { conceptId } = params;
const url = new URL(request.url);
const limit = parseInt(url.searchParams.get('limit') || '15');
console.log('[Mock Concept] /api/concept/:conceptId/stocks:', { conceptId, limit });
// 股票池
const stockPool = [
{ code: '600519', name: '贵州茅台' },
{ code: '300750', name: '宁德时代' },
{ code: '601318', name: '中国平安' },
{ code: '002594', name: '比亚迪' },
{ code: '601012', name: '隆基绿能' },
{ code: '300274', name: '阳光电源' },
{ code: '688981', name: '中芯国际' },
{ code: '000725', name: '京东方A' },
{ code: '002230', name: '科大讯飞' },
{ code: '300124', name: '汇川技术' },
{ code: '002049', name: '紫光国微' },
{ code: '688012', name: '中微公司' },
{ code: '603501', name: '韦尔股份' },
{ code: '600036', name: '招商银行' },
{ code: '000858', name: '五粮液' },
];
// 生成模拟股票数据(确保 change_pct 是数字类型)
const stocks = [];
const count = Math.min(limit, stockPool.length);
for (let i = 0; i < count; i++) {
const stock = stockPool[i];
// 根据股票代码判断交易所后缀
let suffix = '.SZ';
if (stock.code.startsWith('6')) {
suffix = '.SH';
} else if (stock.code.startsWith('8') || stock.code.startsWith('9') || stock.code.startsWith('4')) {
suffix = '.BJ';
}
stocks.push({
stock_code: `${stock.code}${suffix}`,
code: `${stock.code}${suffix}`,
stock_name: stock.name,
name: stock.name,
change_pct: parseFloat((Math.random() * 12 - 3).toFixed(2)), // -3% ~ +9%
price: parseFloat((Math.random() * 100 + 10).toFixed(2)),
market_cap: parseFloat((Math.random() * 1000 + 100).toFixed(2)),
reason: '板块核心标的'
});
}
return HttpResponse.json({
success: true,
data: {
stocks,
total: stocks.length,
concept_id: conceptId
}
});
}),
// 获取最新交易日期
http.get('http://111.198.58.126:16801/price/latest', async () => {
await delay(200);
const today = new Date();
const dateStr = today.toISOString().split('T')[0].replace(/-/g, '');
console.log('[Mock Concept] 获取最新交易日期:', dateStr);
return HttpResponse.json({
latest_date: dateStr,
timestamp: today.toISOString()
});
}),
// 搜索概念(硬编码 URL
http.post('http://111.198.58.126:16801/search', async ({ request }) => {
await delay(300);
try {
const body = await request.json();
const { query = '', size = 20, page = 1, sort_by = 'change_pct' } = body;
console.log('[Mock Concept] 搜索概念 (硬编码URL):', { query, size, page, sort_by });
let results = generatePopularConcepts(size);
if (query) {
results = results.filter(item =>
item.concept.toLowerCase().includes(query.toLowerCase())
);
}
if (sort_by === 'change_pct') {
results.sort((a, b) => b.price_info.avg_change_pct - a.price_info.avg_change_pct);
} else if (sort_by === 'stock_count') {
results.sort((a, b) => b.stock_count - a.stock_count);
} else if (sort_by === 'hot_score') {
results.sort((a, b) => b.hot_score - a.hot_score);
}
return HttpResponse.json({
results,
total: results.length,
page,
size,
message: '搜索成功'
});
} catch (error) {
console.error('[Mock Concept] 搜索失败:', error);
return HttpResponse.json(
{ results: [], total: 0, error: '搜索失败' },
{ status: 500 }
);
}
}),
// 获取统计数据(直接访问外部 API
http.get('http://111.198.58.126:16801/statistics', async ({ request }) => {
await delay(300);
const url = new URL(request.url);
const minStockCount = parseInt(url.searchParams.get('min_stock_count') || '3');
const days = parseInt(url.searchParams.get('days') || '7');
const startDate = url.searchParams.get('start_date');
const endDate = url.searchParams.get('end_date');
console.log('[Mock Concept] 获取统计数据 (直接API):', { minStockCount, days, startDate, endDate });
// 生成完整的统计数据
const statsData = generateConceptStats();
return HttpResponse.json({
success: true,
data: statsData,
note: 'Mock 数据',
params: {
min_stock_count: minStockCount,
days: days,
start_date: startDate,
end_date: endDate
},
updated_at: new Date().toISOString()
});
}),
// 获取统计数据(通过 nginx 代理)
http.get('/concept-api/statistics', async ({ request }) => {
await delay(300);
const url = new URL(request.url);
const minStockCount = parseInt(url.searchParams.get('min_stock_count') || '3');
const days = parseInt(url.searchParams.get('days') || '7');
const startDate = url.searchParams.get('start_date');
const endDate = url.searchParams.get('end_date');
console.log('[Mock Concept] 获取统计数据 (nginx代理):', { minStockCount, days, startDate, endDate });
// 生成完整的统计数据
const statsData = generateConceptStats();
return HttpResponse.json({
success: true,
data: statsData,
note: 'Mock 数据(通过 nginx 代理)',
params: {
min_stock_count: minStockCount,
days: days,
start_date: startDate,
end_date: endDate
},
updated_at: new Date().toISOString()
});
}),
// 获取概念价格时间序列
http.get('http://111.198.58.126:16801/concept/:conceptId/price-timeseries', async ({ params, request }) => {
await delay(300);
const { conceptId } = params;
const url = new URL(request.url);
const startDate = url.searchParams.get('start_date');
const endDate = url.searchParams.get('end_date');
console.log('[Mock Concept] 获取价格时间序列:', { conceptId, startDate, endDate });
// 生成时间序列数据
const timeseries = [];
const start = new Date(startDate || '2024-01-01');
const end = new Date(endDate || new Date());
const daysDiff = Math.ceil((end - start) / (1000 * 60 * 60 * 24));
for (let i = 0; i <= daysDiff; i++) {
const date = new Date(start);
date.setDate(date.getDate() + i);
// 跳过周末
if (date.getDay() !== 0 && date.getDay() !== 6) {
timeseries.push({
trade_date: date.toISOString().split('T')[0], // 改为 trade_date
avg_change_pct: parseFloat((Math.random() * 8 - 2).toFixed(2)), // 转为数值
stock_count: Math.floor(Math.random() * 30) + 10,
volume: Math.floor(Math.random() * 1000000000)
});
}
}
return HttpResponse.json({
concept_id: conceptId,
timeseries: timeseries,
start_date: startDate,
end_date: endDate
});
}),
// 获取概念相关新闻 (search_china_news)
http.get('http://111.198.58.126:21891/search_china_news', async ({ request }) => {
await delay(300);
const url = new URL(request.url);
const query = url.searchParams.get('query');
const exactMatch = url.searchParams.get('exact_match');
const startDate = url.searchParams.get('start_date');
const endDate = url.searchParams.get('end_date');
const topK = parseInt(url.searchParams.get('top_k') || '100');
console.log('[Mock Concept] 搜索中国新闻:', { query, exactMatch, startDate, endDate, topK });
// 生成新闻数据
const news = [];
const newsCount = Math.min(topK, Math.floor(Math.random() * 15) + 5); // 5-20 条新闻
for (let i = 0; i < newsCount; i++) {
const daysAgo = Math.floor(Math.random() * 100); // 0-100 天前
const date = new Date();
date.setDate(date.getDate() - daysAgo);
const hour = Math.floor(Math.random() * 24);
const minute = Math.floor(Math.random() * 60);
const publishedTime = `${date.toISOString().split('T')[0]} ${String(hour).padStart(2, '0')}:${String(minute).padStart(2, '0')}:00`;
news.push({
id: `news_${i}`,
title: `${query || '概念'}板块动态:${['利好政策发布', '行业景气度提升', '龙头企业业绩超预期', '技术突破进展', '市场需求旺盛'][i % 5]}`,
detail: `${query || '概念'}相关新闻详细内容。近期${query || '概念'}板块表现活跃,市场关注度持续上升。多家券商研报指出,${query || '概念'}行业前景广阔,建议重点关注龙头企业投资机会。`,
description: `${query || '概念'}板块最新动态摘要...`,
source: ['新浪财经', '东方财富网', '财联社', '证券时报', '中国证券报', '上海证券报'][Math.floor(Math.random() * 6)],
published_time: publishedTime,
url: `https://finance.sina.com.cn/stock/news/${date.getFullYear()}${String(date.getMonth() + 1).padStart(2, '0')}${String(date.getDate()).padStart(2, '0')}/news_${i}.html`
});
}
// 按时间降序排序
news.sort((a, b) => new Date(b.published_time) - new Date(a.published_time));
// 返回数组(不是对象)
return HttpResponse.json(news);
}),
// 获取概念相关研报 (search)
http.get('http://111.198.58.126:8811/search', async ({ request }) => {
await delay(300);
const url = new URL(request.url);
const query = url.searchParams.get('query');
const mode = url.searchParams.get('mode');
const exactMatch = url.searchParams.get('exact_match');
const size = parseInt(url.searchParams.get('size') || '30');
const startDate = url.searchParams.get('start_date');
console.log('[Mock Concept] 搜索研报:', { query, mode, exactMatch, size, startDate });
// 生成研报数据
const reports = [];
const reportCount = Math.min(size, Math.floor(Math.random() * 10) + 3); // 3-12 份研报
const publishers = ['中信证券', '国泰君安', '华泰证券', '招商证券', '海通证券', '广发证券', '申万宏源', '兴业证券'];
const authors = ['张明', '李华', '王强', '刘洋', '陈杰', '赵敏'];
const ratings = ['买入', '增持', '中性', '减持', '强烈推荐'];
const securityNames = ['行业研究', '公司研究', '策略研究', '宏观研究', '固收研究'];
for (let i = 0; i < reportCount; i++) {
const daysAgo = Math.floor(Math.random() * 100); // 0-100 天前
const date = new Date();
date.setDate(date.getDate() - daysAgo);
const declareDate = `${date.toISOString().split('T')[0]} ${String(Math.floor(Math.random() * 24)).padStart(2, '0')}:${String(Math.floor(Math.random() * 60)).padStart(2, '0')}:00`;
reports.push({
id: `report_${i}`,
report_title: `${query || '概念'}行业${['深度研究报告', '投资策略分析', '行业景气度跟踪', '估值分析报告', '竞争格局研究'][i % 5]}`,
content: `${query || '概念'}行业研究报告内容摘要。\n\n核心观点:\n1. ${query || '概念'}行业景气度持续向好,市场规模预计将保持高速增长。\n2. 龙头企业凭借技术优势和规模效应,市场份额有望进一步提升。\n3. 政策支持力度加大,为行业发展提供有力保障。\n\n投资建议:建议重点关注行业龙头企业,给予"${ratings[Math.floor(Math.random() * ratings.length)]}"评级。`,
abstract: `本报告深入分析了${query || '概念'}行业的发展趋势、竞争格局和投资机会,认为行业具备良好的成长性...`,
publisher: publishers[Math.floor(Math.random() * publishers.length)],
author: authors[Math.floor(Math.random() * authors.length)],
declare_date: declareDate,
rating: ratings[Math.floor(Math.random() * ratings.length)],
security_name: securityNames[Math.floor(Math.random() * securityNames.length)],
content_url: `https://pdf.dfcfw.com/pdf/H3_${1000000 + i}_1_${date.getFullYear()}${String(date.getMonth() + 1).padStart(2, '0')}${String(date.getDate()).padStart(2, '0')}.pdf`
});
}
// 按时间降序排序
reports.sort((a, b) => new Date(b.declare_date) - new Date(a.declare_date));
// 返回符合组件期望的格式
return HttpResponse.json({
results: reports,
total: reports.length,
query: query,
mode: mode
});
}),
// ============ 层级结构 API ============
// 获取完整层级结构
http.get('/concept-api/hierarchy', async () => {
await delay(300);
console.log('[Mock Concept] 获取层级结构');
// 模拟层级结构数据
const hierarchy = [
{
id: 'lv1_1',
name: '人工智能',
concept_count: 98,
children: [
{
id: 'lv2_1_1',
name: 'AI基础设施',
concept_count: 52,
children: [
{ id: 'lv3_1_1_1', name: 'AI算力硬件', concept_count: 16, concepts: ['AI芯片', 'GPU概念股', '服务器', 'AI一体机'] },
{ id: 'lv3_1_1_2', name: 'AI关键组件', concept_count: 24, concepts: ['HBM', 'PCB', '光通信', '存储芯片'] },
{ id: 'lv3_1_1_3', name: 'AI配套设施', concept_count: 12, concepts: ['数据中心', '液冷', '电力设备'] }
]
},
{
id: 'lv2_1_2',
name: 'AI模型与软件',
concept_count: 13,
concepts: ['DeepSeek', 'KIMI', 'SORA概念', '国产大模型']
},
{
id: 'lv2_1_3',
name: 'AI应用',
concept_count: 17,
children: [
{ id: 'lv3_1_3_1', name: '智能体与陪伴', concept_count: 11, concepts: ['AI伴侣', 'AI智能体', 'AI陪伴'] },
{ id: 'lv3_1_3_2', name: '行业应用', concept_count: 6, concepts: ['AI编程', '低代码'] }
]
}
]
},
{
id: 'lv1_2',
name: '半导体',
concept_count: 45,
children: [
{ id: 'lv2_2_1', name: '半导体设备', concept_count: 10, concepts: ['光刻机', 'EDA', '半导体设备'] },
{ id: 'lv2_2_2', name: '半导体材料', concept_count: 8, concepts: ['光刻胶', '半导体材料', '石英砂'] },
{ id: 'lv2_2_3', name: '芯片设计与制造', concept_count: 10, concepts: ['第三代半导体', '碳化硅', '功率半导体'] },
{ id: 'lv2_2_4', name: '先进封装', concept_count: 5, concepts: ['玻璃基板', '半导体封测'] }
]
},
{
id: 'lv1_3',
name: '机器人',
concept_count: 42,
children: [
{ id: 'lv2_3_1', name: '人形机器人整机', concept_count: 20, concepts: ['特斯拉机器人', '人形机器人', '智元机器人'] },
{ id: 'lv2_3_2', name: '机器人核心零部件', concept_count: 12, concepts: ['滚柱丝杆', '电子皮肤', '轴向磁通电机'] },
{ id: 'lv2_3_3', name: '其他类型机器人', concept_count: 10, concepts: ['工业机器人', '机器狗', '外骨骼机器人'] }
]
},
{
id: 'lv1_4',
name: '消费电子',
concept_count: 38,
children: [
{ id: 'lv2_4_1', name: '智能终端', concept_count: 8, concepts: ['AI PC', 'AI手机'] },
{ id: 'lv2_4_2', name: 'XR与空间计算', concept_count: 14, concepts: ['AR眼镜', 'MR', '智能眼镜'] },
{ id: 'lv2_4_3', name: '华为产业链', concept_count: 16, concepts: ['华为Mate70', '鸿蒙', '华为昇腾'] }
]
},
{
id: 'lv1_5',
name: '智能驾驶与汽车',
concept_count: 35,
children: [
{ id: 'lv2_5_1', name: '自动驾驶解决方案', concept_count: 12, concepts: ['Robotaxi', '无人驾驶', '特斯拉FSD'] },
{ id: 'lv2_5_2', name: '智能汽车产业链', concept_count: 15, concepts: ['比亚迪产业链', '小米汽车产业链'] },
{ id: 'lv2_5_3', name: '车路协同', concept_count: 8, concepts: ['车路云一体化', '车路协同'] }
]
},
{
id: 'lv1_6',
name: '新能源与电力',
concept_count: 52,
children: [
{ id: 'lv2_6_1', name: '新型电池技术', concept_count: 18, concepts: ['固态电池', '钠离子电池', '硅基负极'] },
{ id: 'lv2_6_2', name: '电力设备与电网', concept_count: 20, concepts: ['电力', '变压器出海', '燃料电池'] },
{ id: 'lv2_6_3', name: '清洁能源', concept_count: 14, concepts: ['光伏', '核电', '可控核聚变'] }
]
},
{
id: 'lv1_7',
name: '空天经济',
concept_count: 28,
children: [
{ id: 'lv2_7_1', name: '低空经济', concept_count: 14, concepts: ['低空经济', 'eVTOL', '飞行汽车'] },
{ id: 'lv2_7_2', name: '商业航天', concept_count: 14, concepts: ['卫星互联网', '商业航天', '北斗导航'] }
]
},
{
id: 'lv1_8',
name: '国防军工',
concept_count: 25,
children: [
{ id: 'lv2_8_1', name: '无人作战与信息化', concept_count: 10, concepts: ['AI军工', '无人机蜂群', '军工信息化'] },
{ id: 'lv2_8_2', name: '海军装备', concept_count: 8, concepts: ['国产航母', '电磁弹射'] },
{ id: 'lv2_8_3', name: '军贸出海', concept_count: 7, concepts: ['军贸', '巴黎航展'] }
]
}
];
return HttpResponse.json({
hierarchy,
total_lv1: hierarchy.length,
total_concepts: hierarchy.reduce((acc, h) => acc + h.concept_count, 0)
});
}),
// 获取层级统计数据(包含涨跌幅)
http.get('/concept-api/statistics/hierarchy', async () => {
await delay(300);
console.log('[Mock Concept] 获取层级统计数据');
const statistics = [
{ lv1: '人工智能', concept_count: 98, avg_change_pct: 3.56, top_gainer: 'DeepSeek', top_gainer_change: 15.23 },
{ lv1: '半导体', concept_count: 45, avg_change_pct: 2.12, top_gainer: '光刻机', top_gainer_change: 8.76 },
{ lv1: '机器人', concept_count: 42, avg_change_pct: 4.28, top_gainer: '人形机器人', top_gainer_change: 12.45 },
{ lv1: '消费电子', concept_count: 38, avg_change_pct: 1.45, top_gainer: 'AR眼镜', top_gainer_change: 6.78 },
{ lv1: '智能驾驶与汽车', concept_count: 35, avg_change_pct: 2.89, top_gainer: 'Robotaxi', top_gainer_change: 9.32 },
{ lv1: '新能源与电力', concept_count: 52, avg_change_pct: -0.56, top_gainer: '固态电池', top_gainer_change: 5.67 },
{ lv1: '空天经济', concept_count: 28, avg_change_pct: 3.12, top_gainer: '低空经济', top_gainer_change: 11.23 },
{ lv1: '国防军工', concept_count: 25, avg_change_pct: 1.78, top_gainer: 'AI军工', top_gainer_change: 7.89 }
];
return HttpResponse.json({
statistics,
total_lv1: statistics.length,
total_concepts: statistics.reduce((acc, s) => acc + s.concept_count, 0),
market_avg_change: 2.34,
update_time: new Date().toISOString()
});
}),
// 获取层级涨跌幅数据(实时价格)
http.get('/concept-api/hierarchy/price', async ({ request }) => {
await delay(200);
const url = new URL(request.url);
const tradeDate = url.searchParams.get('trade_date');
console.log('[Mock Concept] 获取层级涨跌幅数据:', { tradeDate });
// 模拟 lv1 层级涨跌幅数据
const lv1_concepts = [
{ concept_name: '人工智能', avg_change_pct: 3.56, stock_count: 245 },
{ concept_name: '半导体', avg_change_pct: 2.12, stock_count: 156 },
{ concept_name: '机器人', avg_change_pct: 4.28, stock_count: 128 },
{ concept_name: '消费电子', avg_change_pct: 1.45, stock_count: 98 },
{ concept_name: '智能驾驶与汽车', avg_change_pct: 2.89, stock_count: 112 },
{ concept_name: '新能源与电力', avg_change_pct: -0.56, stock_count: 186 },
{ concept_name: '空天经济', avg_change_pct: 3.12, stock_count: 76 },
{ concept_name: '国防军工', avg_change_pct: 1.78, stock_count: 89 }
];
// 模拟 lv2 层级涨跌幅数据
const lv2_concepts = [
// 人工智能下的 lv2
{ concept_name: 'AI基础设施', avg_change_pct: 4.12, stock_count: 85 },
{ concept_name: 'AI模型与软件', avg_change_pct: 5.67, stock_count: 42 },
{ concept_name: 'AI应用', avg_change_pct: 2.34, stock_count: 65 },
// 半导体下的 lv2
{ concept_name: '半导体设备', avg_change_pct: 3.21, stock_count: 38 },
{ concept_name: '半导体材料', avg_change_pct: 1.89, stock_count: 32 },
{ concept_name: '芯片设计与制造', avg_change_pct: 2.45, stock_count: 56 },
{ concept_name: '先进封装', avg_change_pct: 1.23, stock_count: 22 },
// 机器人下的 lv2
{ concept_name: '人形机器人整机', avg_change_pct: 5.89, stock_count: 45 },
{ concept_name: '机器人核心零部件', avg_change_pct: 3.45, stock_count: 52 },
{ concept_name: '其他类型机器人', avg_change_pct: 2.12, stock_count: 31 },
// 消费电子下的 lv2
{ concept_name: '智能终端', avg_change_pct: 1.78, stock_count: 28 },
{ concept_name: 'XR与空间计算', avg_change_pct: 2.56, stock_count: 36 },
{ concept_name: '华为产业链', avg_change_pct: 0.89, stock_count: 48 },
// 智能驾驶下的 lv2
{ concept_name: '自动驾驶解决方案', avg_change_pct: 4.23, stock_count: 35 },
{ concept_name: '智能汽车产业链', avg_change_pct: 2.45, stock_count: 52 },
{ concept_name: '车路协同', avg_change_pct: 1.56, stock_count: 25 },
// 新能源下的 lv2
{ concept_name: '新型电池技术', avg_change_pct: 0.67, stock_count: 62 },
{ concept_name: '电力设备与电网', avg_change_pct: -1.23, stock_count: 78 },
{ concept_name: '清洁能源', avg_change_pct: -0.45, stock_count: 46 },
// 空天经济下的 lv2
{ concept_name: '低空经济', avg_change_pct: 4.56, stock_count: 42 },
{ concept_name: '商业航天', avg_change_pct: 1.89, stock_count: 34 },
// 国防军工下的 lv2
{ concept_name: '无人作战与信息化', avg_change_pct: 2.34, stock_count: 28 },
{ concept_name: '海军装备', avg_change_pct: 1.45, stock_count: 32 },
{ concept_name: '军贸出海', avg_change_pct: 1.12, stock_count: 18 }
];
// 模拟 lv3 层级涨跌幅数据
const lv3_concepts = [
// AI基础设施下的 lv3
{ concept_name: 'AI算力硬件', avg_change_pct: 5.23, stock_count: 32 },
{ concept_name: 'AI关键组件', avg_change_pct: 3.89, stock_count: 45 },
{ concept_name: 'AI配套设施', avg_change_pct: 2.67, stock_count: 28 },
// AI应用下的 lv3
{ concept_name: '智能体与陪伴', avg_change_pct: 3.12, stock_count: 24 },
{ concept_name: '行业应用', avg_change_pct: 1.56, stock_count: 18 }
];
// 计算交易日期(如果没有传入则使用今天)
const today = tradeDate ? new Date(tradeDate) : new Date();
const tradeDateStr = today.toISOString().split('T')[0];
return HttpResponse.json({
trade_date: tradeDateStr,
lv1_concepts,
lv2_concepts,
lv3_concepts,
update_time: new Date().toISOString()
});
}),
// 获取指定层级的概念列表
http.get('/concept-api/hierarchy/:lv1Id', async ({ params, request }) => {
await delay(300);
const { lv1Id } = params;
const url = new URL(request.url);
const lv2Id = url.searchParams.get('lv2_id');
console.log('[Mock Concept] 获取层级概念列表:', { lv1Id, lv2Id });
// 返回该层级下的概念列表
let concepts = generatePopularConcepts(20);
// 添加层级信息
concepts = concepts.map(c => ({
...c,
hierarchy: {
lv1: '人工智能',
lv1_id: lv1Id,
lv2: lv2Id ? 'AI基础设施' : null,
lv2_id: lv2Id
}
}));
return HttpResponse.json({
concepts,
total: concepts.length,
lv1_id: lv1Id,
lv2_id: lv2Id
});
}),
// 热门概念静态数据文件HeroPanel 使用)
http.get('/data/concept/latest.json', async () => {
await delay(200);
console.log('[Mock Concept] 获取热门概念静态数据');
const concepts = generatePopularConcepts(30);
return HttpResponse.json({
date: new Date().toISOString().split('T')[0],
results: concepts
});
})
];