修复: - latest_date → latest_trade_date(与前端字段名一致) - 日期格式使用 YYYY-MM-DD 确保 Date 解析正确 扩充: - 新增 /concept-api/ 路径的 MSW handler(代理兼容) - 层级结构数据从 8 个一级分类扩充到 15 个 - 添加更丰富的二级/三级概念数据 - 新增 limitAnalyse mock handler 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
575 lines
23 KiB
JavaScript
575 lines
23 KiB
JavaScript
// src/mocks/handlers/limitAnalyse.js
|
||
// 涨停分析相关的 Mock Handlers
|
||
|
||
import { http, HttpResponse } from 'msw';
|
||
|
||
// 模拟延迟
|
||
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
|
||
|
||
// 生成可用日期列表(最近30个交易日)
|
||
const generateAvailableDates = () => {
|
||
const dates = [];
|
||
const today = new Date();
|
||
let count = 0;
|
||
|
||
for (let i = 0; i < 60 && count < 30; i++) {
|
||
const date = new Date(today);
|
||
date.setDate(date.getDate() - i);
|
||
const dayOfWeek = date.getDay();
|
||
|
||
// 跳过周末
|
||
if (dayOfWeek !== 0 && dayOfWeek !== 6) {
|
||
const year = date.getFullYear();
|
||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||
const day = String(date.getDate()).padStart(2, '0');
|
||
const dateStr = `${year}${month}${day}`;
|
||
|
||
// 返回包含 date 和 count 字段的对象
|
||
dates.push({
|
||
date: dateStr,
|
||
count: Math.floor(Math.random() * 80) + 30 // 30-110 只涨停股票
|
||
});
|
||
count++;
|
||
}
|
||
}
|
||
|
||
return dates;
|
||
};
|
||
|
||
// 生成板块数据
|
||
const generateSectors = (count = 8) => {
|
||
const sectorNames = [
|
||
'人工智能', 'ChatGPT', '数字经济',
|
||
'新能源汽车', '光伏', '锂电池',
|
||
'半导体', '芯片', '5G通信',
|
||
'医疗器械', '创新药', '中药',
|
||
'白酒', '食品饮料', '消费电子',
|
||
'军工', '航空航天', '新材料'
|
||
];
|
||
|
||
const sectors = [];
|
||
for (let i = 0; i < Math.min(count, sectorNames.length); i++) {
|
||
const stockCount = Math.floor(Math.random() * 15) + 5;
|
||
const stocks = [];
|
||
|
||
for (let j = 0; j < stockCount; j++) {
|
||
stocks.push({
|
||
code: `${Math.random() > 0.5 ? '6' : '0'}${String(Math.floor(Math.random() * 100000)).padStart(5, '0')}`,
|
||
name: `${sectorNames[i]}股票${j + 1}`,
|
||
latest_limit_time: `${Math.floor(Math.random() * 4) + 9}:${String(Math.floor(Math.random() * 60)).padStart(2, '0')}:${String(Math.floor(Math.random() * 60)).padStart(2, '0')}`,
|
||
limit_up_count: Math.floor(Math.random() * 3) + 1,
|
||
price: (Math.random() * 100 + 10).toFixed(2),
|
||
change_pct: (Math.random() * 5 + 5).toFixed(2),
|
||
turnover_rate: (Math.random() * 30 + 5).toFixed(2),
|
||
volume: Math.floor(Math.random() * 100000000 + 10000000),
|
||
amount: (Math.random() * 1000000000 + 100000000).toFixed(2),
|
||
limit_type: Math.random() > 0.7 ? '一字板' : (Math.random() > 0.5 ? 'T字板' : '普通涨停'),
|
||
封单金额: (Math.random() * 500000000).toFixed(2),
|
||
});
|
||
}
|
||
|
||
sectors.push({
|
||
sector_name: sectorNames[i],
|
||
stock_count: stockCount,
|
||
avg_limit_time: `${Math.floor(Math.random() * 2) + 10}:${String(Math.floor(Math.random() * 60)).padStart(2, '0')}`,
|
||
stocks: stocks,
|
||
});
|
||
}
|
||
|
||
return sectors;
|
||
};
|
||
|
||
// 生成高位股数据(用于 HighPositionStocks 组件)
|
||
const generateHighPositionStocks = () => {
|
||
const stocks = [];
|
||
const stockNames = [
|
||
'宁德时代', '比亚迪', '隆基绿能', '东方财富', '中际旭创',
|
||
'京东方A', '海康威视', '立讯精密', '三一重工', '恒瑞医药',
|
||
'三六零', '东方通信', '贵州茅台', '五粮液', '中国平安'
|
||
];
|
||
const industries = [
|
||
'锂电池', '新能源汽车', '光伏', '金融科技', '通信设备',
|
||
'显示器件', '安防设备', '电子元件', '工程机械', '医药制造',
|
||
'网络安全', '通信服务', '白酒', '食品饮料', '保险'
|
||
];
|
||
|
||
for (let i = 0; i < stockNames.length; i++) {
|
||
const code = `${Math.random() > 0.5 ? '6' : '0'}${String(Math.floor(Math.random() * 100000)).padStart(5, '0')}`;
|
||
const continuousDays = Math.floor(Math.random() * 8) + 2; // 2-9连板
|
||
const price = parseFloat((Math.random() * 100 + 20).toFixed(2));
|
||
const increaseRate = parseFloat((Math.random() * 3 + 8).toFixed(2)); // 8%-11%
|
||
const turnoverRate = parseFloat((Math.random() * 20 + 5).toFixed(2)); // 5%-25%
|
||
|
||
stocks.push({
|
||
stock_code: code,
|
||
stock_name: stockNames[i],
|
||
price: price,
|
||
increase_rate: increaseRate,
|
||
continuous_limit_up: continuousDays,
|
||
industry: industries[i],
|
||
turnover_rate: turnoverRate,
|
||
});
|
||
}
|
||
|
||
// 按连板天数降序排序
|
||
stocks.sort((a, b) => b.continuous_limit_up - a.continuous_limit_up);
|
||
|
||
return stocks;
|
||
};
|
||
|
||
// 生成高位股统计数据
|
||
const generateHighPositionStatistics = (stocks) => {
|
||
if (!stocks || stocks.length === 0) {
|
||
return {
|
||
total_count: 0,
|
||
avg_continuous_days: 0,
|
||
max_continuous_days: 0,
|
||
};
|
||
}
|
||
|
||
const totalCount = stocks.length;
|
||
const sumDays = stocks.reduce((sum, stock) => sum + stock.continuous_limit_up, 0);
|
||
const maxDays = Math.max(...stocks.map(s => s.continuous_limit_up));
|
||
|
||
return {
|
||
total_count: totalCount,
|
||
avg_continuous_days: parseFloat((sumDays / totalCount).toFixed(1)),
|
||
max_continuous_days: maxDays,
|
||
};
|
||
};
|
||
|
||
// 生成词云数据
|
||
const generateWordCloudData = () => {
|
||
const keywords = [
|
||
'人工智能', 'ChatGPT', 'AI芯片', '大模型', '算力',
|
||
'新能源', '光伏', '锂电池', '储能', '充电桩',
|
||
'半导体', '芯片', 'EDA', '国产替代', '集成电路',
|
||
'医疗', '创新药', 'CXO', '医疗器械', '生物医药',
|
||
'消费', '白酒', '食品', '零售', '餐饮',
|
||
'金融', '券商', '保险', '银行', '金融科技'
|
||
];
|
||
|
||
return keywords.map(keyword => ({
|
||
text: keyword,
|
||
value: Math.floor(Math.random() * 50) + 10,
|
||
category: ['科技', '新能源', '医疗', '消费', '金融'][Math.floor(Math.random() * 5)],
|
||
}));
|
||
};
|
||
|
||
// 生成每日分析数据
|
||
const generateDailyAnalysis = (date) => {
|
||
const sectorNames = [
|
||
'公告', '人工智能', 'ChatGPT', '数字经济',
|
||
'新能源汽车', '光伏', '锂电池',
|
||
'半导体', '芯片', '5G通信',
|
||
'医疗器械', '创新药', '其他'
|
||
];
|
||
|
||
const stockNameTemplates = [
|
||
'龙头', '科技', '新能源', '智能', '数字', '云计算', '创新',
|
||
'生物', '医疗', '通信', '电子', '材料', '能源', '互联'
|
||
];
|
||
|
||
// 生成 sector_data(SectorDetails 组件需要的格式)
|
||
const sectorData = {};
|
||
let totalStocks = 0;
|
||
|
||
sectorNames.forEach((sectorName, sectorIdx) => {
|
||
const stockCount = Math.floor(Math.random() * 12) + 3; // 每个板块 3-15 只股票
|
||
const stocks = [];
|
||
|
||
for (let i = 0; i < stockCount; i++) {
|
||
const code = `${Math.random() > 0.5 ? '6' : '0'}${String(Math.floor(Math.random() * 100000)).padStart(5, '0')}`;
|
||
const continuousDays = Math.floor(Math.random() * 6) + 1; // 1-6连板
|
||
const ztHour = Math.floor(Math.random() * 5) + 9; // 9-13点
|
||
const ztMinute = Math.floor(Math.random() * 60);
|
||
const ztSecond = Math.floor(Math.random() * 60);
|
||
const ztTime = `2024-10-28 ${String(ztHour).padStart(2, '0')}:${String(ztMinute).padStart(2, '0')}:${String(ztSecond).padStart(2, '0')}`;
|
||
|
||
const stockName = `${stockNameTemplates[i % stockNameTemplates.length]}${sectorName === '公告' ? '公告' : ''}股份${i + 1}`;
|
||
|
||
stocks.push({
|
||
scode: code,
|
||
sname: stockName,
|
||
zt_time: ztTime,
|
||
formatted_time: `${String(ztHour).padStart(2, '0')}:${String(ztMinute).padStart(2, '0')}`,
|
||
continuous_days: continuousDays === 1 ? '首板' : `${continuousDays}连板`,
|
||
brief: `${sectorName}板块异动,${stockName}因${sectorName === '公告' ? '重大公告利好' : '板块热点'}涨停。公司是${sectorName}行业龙头企业之一。`,
|
||
summary: `${sectorName}概念持续活跃`,
|
||
first_time: `2024-10-${String(28 - (continuousDays - 1)).padStart(2, '0')}`,
|
||
change_pct: parseFloat((Math.random() * 2 + 9).toFixed(2)), // 9%-11%
|
||
core_sectors: [
|
||
sectorName,
|
||
sectorNames[Math.floor(Math.random() * sectorNames.length)],
|
||
sectorNames[Math.floor(Math.random() * sectorNames.length)]
|
||
].filter((v, i, a) => a.indexOf(v) === i) // 去重
|
||
});
|
||
}
|
||
|
||
sectorData[sectorName] = {
|
||
count: stockCount,
|
||
stocks: stocks.sort((a, b) => a.zt_time.localeCompare(b.zt_time)) // 按涨停时间排序
|
||
};
|
||
|
||
totalStocks += stockCount;
|
||
});
|
||
|
||
// 统计数据
|
||
const morningCount = Math.floor(totalStocks * 0.35); // 早盘涨停
|
||
const announcementCount = sectorData['公告']?.count || 0;
|
||
const topSector = sectorNames.filter(s => s !== '公告' && s !== '其他')
|
||
.reduce((max, name) =>
|
||
(sectorData[name]?.count || 0) > (sectorData[max]?.count || 0) ? name : max
|
||
, '人工智能');
|
||
|
||
return {
|
||
date: date,
|
||
total_stocks: totalStocks,
|
||
total_sectors: Object.keys(sectorData).length,
|
||
sector_data: sectorData, // 👈 SectorDetails 组件需要的数据
|
||
summary: {
|
||
top_sector: topSector,
|
||
top_sector_count: sectorData[topSector]?.count || 0,
|
||
announcement_stocks: announcementCount,
|
||
zt_time_distribution: {
|
||
morning: morningCount,
|
||
afternoon: totalStocks - morningCount,
|
||
}
|
||
}
|
||
};
|
||
};
|
||
|
||
// ==================== 静态文件 Mock Handlers ====================
|
||
// 这些 handlers 用于拦截 /data/zt/* 静态文件请求
|
||
|
||
// 生成 dates.json 数据
|
||
const generateDatesJson = () => {
|
||
const dates = [];
|
||
const today = new Date();
|
||
|
||
for (let i = 0; i < 60; i++) {
|
||
const date = new Date(today);
|
||
date.setDate(date.getDate() - i);
|
||
const dayOfWeek = date.getDay();
|
||
|
||
// 跳过周末
|
||
if (dayOfWeek !== 0 && dayOfWeek !== 6) {
|
||
const year = date.getFullYear();
|
||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||
const day = String(date.getDate()).padStart(2, '0');
|
||
|
||
dates.push({
|
||
date: `${year}${month}${day}`,
|
||
formatted_date: `${year}-${month}-${day}`,
|
||
count: Math.floor(Math.random() * 60) + 40 // 40-100 只涨停股票
|
||
});
|
||
|
||
if (dates.length >= 30) break;
|
||
}
|
||
}
|
||
|
||
return { dates };
|
||
};
|
||
|
||
// 生成每日分析 JSON 数据(用于 /data/zt/daily/${date}.json)
|
||
const generateDailyJson = (date) => {
|
||
// 板块名称列表
|
||
const sectorNames = [
|
||
'公告', '人工智能', 'ChatGPT', '大模型', '算力',
|
||
'光伏', '新能源汽车', '锂电池', '储能', '充电桩',
|
||
'半导体', '芯片', '集成电路', '国产替代',
|
||
'医药', '创新药', 'CXO', '医疗器械',
|
||
'军工', '航空航天', '其他'
|
||
];
|
||
|
||
// 股票名称模板
|
||
const stockPrefixes = [
|
||
'龙头', '科技', '新能', '智能', '数字', '云计', '创新',
|
||
'生物', '医疗', '通信', '电子', '材料', '能源', '互联',
|
||
'天马', '华鑫', '中科', '东方', '西部', '南方', '北方',
|
||
'金龙', '银河', '星辰', '宏达', '盛世', '鹏程', '万里'
|
||
];
|
||
|
||
const stockSuffixes = [
|
||
'股份', '科技', '电子', '信息', '新材', '能源', '医药',
|
||
'通讯', '智造', '集团', '实业', '控股', '产业', '发展'
|
||
];
|
||
|
||
// 生成所有股票
|
||
const stocks = [];
|
||
const sectorData = {};
|
||
let stockIndex = 0;
|
||
|
||
sectorNames.forEach((sectorName, sectorIdx) => {
|
||
const stockCount = sectorName === '公告'
|
||
? Math.floor(Math.random() * 5) + 8 // 公告板块 8-12 只
|
||
: sectorName === '其他'
|
||
? Math.floor(Math.random() * 4) + 3 // 其他板块 3-6 只
|
||
: Math.floor(Math.random() * 8) + 3; // 普通板块 3-10 只
|
||
|
||
const sectorStockCodes = [];
|
||
|
||
for (let i = 0; i < stockCount; i++) {
|
||
const code = `${Math.random() > 0.6 ? '6' : Math.random() > 0.3 ? '0' : '3'}${String(Math.floor(Math.random() * 100000)).padStart(5, '0')}`;
|
||
const continuousDays = Math.floor(Math.random() * 6) + 1;
|
||
const ztHour = Math.floor(Math.random() * 4) + 9;
|
||
const ztMinute = Math.floor(Math.random() * 60);
|
||
const ztSecond = Math.floor(Math.random() * 60);
|
||
|
||
const prefix = stockPrefixes[Math.floor(Math.random() * stockPrefixes.length)];
|
||
const suffix = stockSuffixes[Math.floor(Math.random() * stockSuffixes.length)];
|
||
const stockName = `${prefix}${suffix}`;
|
||
|
||
// 生成关联板块
|
||
const coreSectors = [sectorName];
|
||
if (Math.random() > 0.5) {
|
||
const otherSector = sectorNames[Math.floor(Math.random() * (sectorNames.length - 1))];
|
||
if (otherSector !== sectorName && otherSector !== '其他' && otherSector !== '公告') {
|
||
coreSectors.push(otherSector);
|
||
}
|
||
}
|
||
|
||
stocks.push({
|
||
scode: code,
|
||
sname: stockName,
|
||
zt_time: `${date.slice(0,4)}-${date.slice(4,6)}-${date.slice(6,8)} ${String(ztHour).padStart(2,'0')}:${String(ztMinute).padStart(2,'0')}:${String(ztSecond).padStart(2,'0')}`,
|
||
formatted_time: `${String(ztHour).padStart(2,'0')}:${String(ztMinute).padStart(2,'0')}`,
|
||
continuous_days: continuousDays === 1 ? '首板' : `${continuousDays}连板`,
|
||
brief: sectorName === '公告'
|
||
? `${stockName}发布重大公告,公司拟收购资产/重组/增发等利好消息。`
|
||
: `${sectorName}板块异动,${stockName}因板块热点涨停。公司是${sectorName}行业核心标的。`,
|
||
summary: `${sectorName}概念活跃`,
|
||
first_time: `${date.slice(0,4)}-${date.slice(4,6)}-${String(parseInt(date.slice(6,8)) - (continuousDays - 1)).padStart(2,'0')}`,
|
||
change_pct: parseFloat((Math.random() * 1.5 + 9.5).toFixed(2)),
|
||
core_sectors: coreSectors
|
||
});
|
||
|
||
sectorStockCodes.push(code);
|
||
stockIndex++;
|
||
}
|
||
|
||
sectorData[sectorName] = {
|
||
count: stockCount,
|
||
stock_codes: sectorStockCodes
|
||
};
|
||
});
|
||
|
||
// 生成词频数据
|
||
const wordFreqData = [
|
||
{ name: '人工智能', value: Math.floor(Math.random() * 30) + 20 },
|
||
{ name: 'ChatGPT', value: Math.floor(Math.random() * 25) + 15 },
|
||
{ name: '大模型', value: Math.floor(Math.random() * 20) + 12 },
|
||
{ name: '算力', value: Math.floor(Math.random() * 18) + 10 },
|
||
{ name: '光伏', value: Math.floor(Math.random() * 15) + 10 },
|
||
{ name: '新能源', value: Math.floor(Math.random() * 15) + 8 },
|
||
{ name: '锂电池', value: Math.floor(Math.random() * 12) + 8 },
|
||
{ name: '储能', value: Math.floor(Math.random() * 12) + 6 },
|
||
{ name: '半导体', value: Math.floor(Math.random() * 15) + 10 },
|
||
{ name: '芯片', value: Math.floor(Math.random() * 15) + 8 },
|
||
{ name: '集成电路', value: Math.floor(Math.random() * 10) + 5 },
|
||
{ name: '国产替代', value: Math.floor(Math.random() * 10) + 5 },
|
||
{ name: '医药', value: Math.floor(Math.random() * 12) + 6 },
|
||
{ name: '创新药', value: Math.floor(Math.random() * 10) + 5 },
|
||
{ name: '医疗器械', value: Math.floor(Math.random() * 8) + 4 },
|
||
{ name: '军工', value: Math.floor(Math.random() * 10) + 5 },
|
||
{ name: '航空航天', value: Math.floor(Math.random() * 8) + 4 },
|
||
{ name: '数字经济', value: Math.floor(Math.random() * 12) + 6 },
|
||
{ name: '工业4.0', value: Math.floor(Math.random() * 8) + 4 },
|
||
{ name: '机器人', value: Math.floor(Math.random() * 10) + 5 },
|
||
{ name: '自动驾驶', value: Math.floor(Math.random() * 8) + 4 },
|
||
{ name: '元宇宙', value: Math.floor(Math.random() * 6) + 3 },
|
||
{ name: 'Web3.0', value: Math.floor(Math.random() * 5) + 2 },
|
||
{ name: '区块链', value: Math.floor(Math.random() * 5) + 2 },
|
||
];
|
||
|
||
return {
|
||
date: date,
|
||
total_stocks: stocks.length,
|
||
total_sectors: Object.keys(sectorData).length,
|
||
stocks: stocks,
|
||
sector_data: sectorData,
|
||
word_freq_data: wordFreqData,
|
||
summary: {
|
||
top_sector: '人工智能',
|
||
top_sector_count: sectorData['人工智能']?.count || 0,
|
||
announcement_stocks: sectorData['公告']?.count || 0,
|
||
zt_time_distribution: {
|
||
morning: Math.floor(stocks.length * 0.4),
|
||
afternoon: Math.floor(stocks.length * 0.6),
|
||
}
|
||
}
|
||
};
|
||
};
|
||
|
||
// 生成 stocks.jsonl 数据
|
||
const generateStocksJsonl = () => {
|
||
const stocks = [];
|
||
const today = new Date();
|
||
|
||
// 生成 200 只历史涨停股票记录
|
||
for (let i = 0; i < 200; i++) {
|
||
const daysAgo = Math.floor(Math.random() * 30);
|
||
const date = new Date(today);
|
||
date.setDate(date.getDate() - daysAgo);
|
||
|
||
// 跳过周末
|
||
while (date.getDay() === 0 || date.getDay() === 6) {
|
||
date.setDate(date.getDate() - 1);
|
||
}
|
||
|
||
const year = date.getFullYear();
|
||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||
const day = String(date.getDate()).padStart(2, '0');
|
||
|
||
stocks.push({
|
||
scode: `${Math.random() > 0.6 ? '6' : Math.random() > 0.3 ? '0' : '3'}${String(Math.floor(Math.random() * 100000)).padStart(5, '0')}`,
|
||
sname: ['龙头', '科技', '新能', '智能', '数字', '云计'][Math.floor(Math.random() * 6)] +
|
||
['股份', '科技', '电子', '信息', '新材'][Math.floor(Math.random() * 5)],
|
||
date: `${year}${month}${day}`,
|
||
formatted_date: `${year}-${month}-${day}`,
|
||
continuous_days: Math.floor(Math.random() * 5) + 1,
|
||
core_sectors: [['人工智能', 'ChatGPT', '光伏', '锂电池', '芯片'][Math.floor(Math.random() * 5)]]
|
||
});
|
||
}
|
||
|
||
return stocks;
|
||
};
|
||
|
||
// Mock Handlers
|
||
export const limitAnalyseHandlers = [
|
||
// ==================== 静态文件路径 Handlers ====================
|
||
|
||
// 1. /data/zt/dates.json - 可用日期列表
|
||
http.get('/data/zt/dates.json', async () => {
|
||
await delay(200);
|
||
console.log('[Mock LimitAnalyse] 获取 dates.json');
|
||
const data = generateDatesJson();
|
||
return HttpResponse.json(data);
|
||
}),
|
||
|
||
// 2. /data/zt/daily/:date.json - 每日分析数据
|
||
http.get('/data/zt/daily/:date', async ({ params }) => {
|
||
await delay(300);
|
||
// 移除 .json 后缀和查询参数
|
||
const dateParam = params.date.replace('.json', '').split('?')[0];
|
||
console.log('[Mock LimitAnalyse] 获取每日数据:', dateParam);
|
||
const data = generateDailyJson(dateParam);
|
||
return HttpResponse.json(data);
|
||
}),
|
||
|
||
// 3. /data/zt/stocks.jsonl - 股票列表(用于搜索)
|
||
http.get('/data/zt/stocks.jsonl', async () => {
|
||
await delay(200);
|
||
console.log('[Mock LimitAnalyse] 获取 stocks.jsonl');
|
||
const stocks = generateStocksJsonl();
|
||
// JSONL 格式:每行一个 JSON
|
||
const jsonl = stocks.map(s => JSON.stringify(s)).join('\n');
|
||
return new HttpResponse(jsonl, {
|
||
headers: { 'Content-Type': 'text/plain' }
|
||
});
|
||
}),
|
||
|
||
// ==================== API 路径 Handlers (兼容旧版本) ====================
|
||
|
||
// 1. 获取可用日期列表
|
||
http.get('http://111.198.58.126:5001/api/v1/dates/available', async () => {
|
||
await delay(300);
|
||
|
||
const availableDates = generateAvailableDates();
|
||
|
||
return HttpResponse.json({
|
||
success: true,
|
||
events: availableDates,
|
||
message: '可用日期列表获取成功',
|
||
});
|
||
}),
|
||
|
||
// 2. 获取每日分析数据
|
||
http.get('http://111.198.58.126:5001/api/v1/analysis/daily/:date', async ({ params }) => {
|
||
await delay(500);
|
||
|
||
const { date } = params;
|
||
const data = generateDailyAnalysis(date);
|
||
|
||
return HttpResponse.json({
|
||
success: true,
|
||
data: data,
|
||
message: `${date} 每日分析数据获取成功`,
|
||
});
|
||
}),
|
||
|
||
// 3. 获取词云数据
|
||
http.get('http://111.198.58.126:5001/api/v1/analysis/wordcloud/:date', async ({ params }) => {
|
||
await delay(300);
|
||
|
||
const { date } = params;
|
||
const wordCloudData = generateWordCloudData();
|
||
|
||
return HttpResponse.json({
|
||
success: true,
|
||
data: wordCloudData,
|
||
message: `${date} 词云数据获取成功`,
|
||
});
|
||
}),
|
||
|
||
// 4. 混合搜索(POST)
|
||
http.post('http://111.198.58.126:5001/api/v1/stocks/search/hybrid', async ({ request }) => {
|
||
await delay(400);
|
||
|
||
const body = await request.json();
|
||
const { query, type = 'all', mode = 'hybrid' } = body;
|
||
|
||
// 生成模拟搜索结果
|
||
const results = [];
|
||
const count = Math.floor(Math.random() * 10) + 5;
|
||
|
||
for (let i = 0; i < count; i++) {
|
||
results.push({
|
||
code: `${Math.random() > 0.5 ? '6' : '0'}${String(Math.floor(Math.random() * 100000)).padStart(5, '0')}`,
|
||
name: `${query || '搜索'}相关股票${i + 1}`,
|
||
sector: ['人工智能', 'ChatGPT', '新能源'][Math.floor(Math.random() * 3)],
|
||
limit_date: new Date().toISOString().split('T')[0].replace(/-/g, ''),
|
||
limit_time: `${Math.floor(Math.random() * 4) + 9}:${String(Math.floor(Math.random() * 60)).padStart(2, '0')}`,
|
||
price: (Math.random() * 100 + 10).toFixed(2),
|
||
change_pct: (Math.random() * 10).toFixed(2),
|
||
match_score: (Math.random() * 0.5 + 0.5).toFixed(2),
|
||
});
|
||
}
|
||
|
||
return HttpResponse.json({
|
||
success: true,
|
||
data: {
|
||
query: query,
|
||
type: type,
|
||
mode: mode,
|
||
results: results,
|
||
total: results.length,
|
||
},
|
||
message: '搜索完成',
|
||
});
|
||
}),
|
||
|
||
// 5. 获取高位股列表(涨停股票列表)
|
||
http.get('http://111.198.58.126:5001/api/limit-analyse/high-position-stocks', async ({ request }) => {
|
||
await delay(400);
|
||
|
||
const url = new URL(request.url);
|
||
const date = url.searchParams.get('date');
|
||
|
||
console.log('[Mock LimitAnalyse] 获取高位股列表:', { date });
|
||
|
||
const stocks = generateHighPositionStocks();
|
||
const statistics = generateHighPositionStatistics(stocks);
|
||
|
||
return HttpResponse.json({
|
||
success: true,
|
||
data: {
|
||
stocks: stocks,
|
||
statistics: statistics,
|
||
date: date,
|
||
},
|
||
message: '高位股数据获取成功',
|
||
});
|
||
}),
|
||
];
|