feat(mock): 完善 Mock 数据,修复 API 返回格式
- event.js: 修复 /api/events 返回格式,匹配 useEventData 期望的结构 - stock.js: 添加 /api/stock/:code/quote-detail handler(完整行情数据含买卖盘) - stock.js: 添加 /api/flex-screen/quotes handler(指数行情) - stock.js: 修复 /api/index/:code/kline 支持 minute 类型 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -120,12 +120,14 @@ export const eventHandlers = [
|
|||||||
try {
|
try {
|
||||||
const result = generateMockEvents(params);
|
const result = generateMockEvents(params);
|
||||||
|
|
||||||
// 返回格式兼容 NewsPanel 期望的结构
|
// 返回格式兼容 useEventData 期望的结构
|
||||||
// NewsPanel 期望: { success, data: [], pagination: {} }
|
// useEventData 期望: { success, data: { events: [], pagination: {} } }
|
||||||
return HttpResponse.json({
|
return HttpResponse.json({
|
||||||
success: true,
|
success: true,
|
||||||
data: result.events, // 事件数组
|
data: {
|
||||||
pagination: result.pagination, // 分页信息
|
events: result.events, // 事件数组
|
||||||
|
pagination: result.pagination // 分页信息
|
||||||
|
},
|
||||||
message: '获取成功'
|
message: '获取成功'
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -263,15 +263,15 @@ export const stockHandlers = [
|
|||||||
try {
|
try {
|
||||||
let data;
|
let data;
|
||||||
|
|
||||||
if (type === 'timeline') {
|
if (type === 'timeline' || type === 'minute') {
|
||||||
|
// timeline 和 minute 都使用分时数据
|
||||||
data = generateTimelineData(indexCode);
|
data = generateTimelineData(indexCode);
|
||||||
} else if (type === 'daily') {
|
} else if (type === 'daily') {
|
||||||
data = generateDailyData(indexCode, 30);
|
data = generateDailyData(indexCode, 30);
|
||||||
} else {
|
} else {
|
||||||
return HttpResponse.json(
|
// 其他类型也降级使用 timeline 数据
|
||||||
{ error: '不支持的类型' },
|
console.log('[Mock Stock] 未知类型,降级使用 timeline:', type);
|
||||||
{ status: 400 }
|
data = generateTimelineData(indexCode);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return HttpResponse.json({
|
return HttpResponse.json({
|
||||||
@@ -558,4 +558,133 @@ export const stockHandlers = [
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
// 获取股票详细行情(quote-detail)
|
||||||
|
http.get('/api/stock/:stockCode/quote-detail', async ({ params }) => {
|
||||||
|
await delay(200);
|
||||||
|
|
||||||
|
const { stockCode } = params;
|
||||||
|
console.log('[Mock Stock] 获取股票详细行情:', { stockCode });
|
||||||
|
|
||||||
|
const stocks = generateStockList();
|
||||||
|
const codeWithoutSuffix = stockCode.replace(/\.(SH|SZ)$/i, '');
|
||||||
|
const stockInfo = stocks.find(s => s.code === codeWithoutSuffix);
|
||||||
|
const stockName = stockInfo?.name || `股票${stockCode}`;
|
||||||
|
|
||||||
|
// 生成基础价格(10-200之间)
|
||||||
|
const basePrice = parseFloat((Math.random() * 190 + 10).toFixed(2));
|
||||||
|
// 涨跌幅(-10% 到 +10%)
|
||||||
|
const changePercent = parseFloat((Math.random() * 20 - 10).toFixed(2));
|
||||||
|
// 涨跌额
|
||||||
|
const change = parseFloat((basePrice * changePercent / 100).toFixed(2));
|
||||||
|
// 昨收
|
||||||
|
const prevClose = parseFloat((basePrice - change).toFixed(2));
|
||||||
|
|
||||||
|
return HttpResponse.json({
|
||||||
|
success: true,
|
||||||
|
data: {
|
||||||
|
stock_code: stockCode,
|
||||||
|
stock_name: stockName,
|
||||||
|
price: basePrice,
|
||||||
|
change: change,
|
||||||
|
change_percent: changePercent,
|
||||||
|
prev_close: prevClose,
|
||||||
|
open: parseFloat((prevClose * (1 + (Math.random() * 0.02 - 0.01))).toFixed(2)),
|
||||||
|
high: parseFloat((basePrice * (1 + Math.random() * 0.05)).toFixed(2)),
|
||||||
|
low: parseFloat((basePrice * (1 - Math.random() * 0.05)).toFixed(2)),
|
||||||
|
volume: Math.floor(Math.random() * 100000000),
|
||||||
|
amount: parseFloat((Math.random() * 10000000000).toFixed(2)),
|
||||||
|
turnover_rate: parseFloat((Math.random() * 10).toFixed(2)),
|
||||||
|
amplitude: parseFloat((Math.random() * 8).toFixed(2)),
|
||||||
|
market: stockCode.startsWith('6') ? 'SH' : 'SZ',
|
||||||
|
update_time: new Date().toISOString(),
|
||||||
|
// 买卖盘口
|
||||||
|
bid1: parseFloat((basePrice * 0.998).toFixed(2)),
|
||||||
|
bid1_volume: Math.floor(Math.random() * 10000),
|
||||||
|
bid2: parseFloat((basePrice * 0.996).toFixed(2)),
|
||||||
|
bid2_volume: Math.floor(Math.random() * 10000),
|
||||||
|
bid3: parseFloat((basePrice * 0.994).toFixed(2)),
|
||||||
|
bid3_volume: Math.floor(Math.random() * 10000),
|
||||||
|
bid4: parseFloat((basePrice * 0.992).toFixed(2)),
|
||||||
|
bid4_volume: Math.floor(Math.random() * 10000),
|
||||||
|
bid5: parseFloat((basePrice * 0.990).toFixed(2)),
|
||||||
|
bid5_volume: Math.floor(Math.random() * 10000),
|
||||||
|
ask1: parseFloat((basePrice * 1.002).toFixed(2)),
|
||||||
|
ask1_volume: Math.floor(Math.random() * 10000),
|
||||||
|
ask2: parseFloat((basePrice * 1.004).toFixed(2)),
|
||||||
|
ask2_volume: Math.floor(Math.random() * 10000),
|
||||||
|
ask3: parseFloat((basePrice * 1.006).toFixed(2)),
|
||||||
|
ask3_volume: Math.floor(Math.random() * 10000),
|
||||||
|
ask4: parseFloat((basePrice * 1.008).toFixed(2)),
|
||||||
|
ask4_volume: Math.floor(Math.random() * 10000),
|
||||||
|
ask5: parseFloat((basePrice * 1.010).toFixed(2)),
|
||||||
|
ask5_volume: Math.floor(Math.random() * 10000),
|
||||||
|
// 关键指标
|
||||||
|
pe: parseFloat((Math.random() * 50 + 5).toFixed(2)),
|
||||||
|
pb: parseFloat((Math.random() * 8 + 0.5).toFixed(2)),
|
||||||
|
eps: parseFloat((Math.random() * 5 + 0.1).toFixed(3)),
|
||||||
|
market_cap: `${(Math.random() * 5000 + 100).toFixed(0)}亿`,
|
||||||
|
circulating_market_cap: `${(Math.random() * 3000 + 50).toFixed(0)}亿`,
|
||||||
|
total_shares: `${(Math.random() * 100 + 10).toFixed(2)}亿`,
|
||||||
|
circulating_shares: `${(Math.random() * 80 + 5).toFixed(2)}亿`,
|
||||||
|
week52_high: parseFloat((basePrice * 1.3).toFixed(2)),
|
||||||
|
week52_low: parseFloat((basePrice * 0.7).toFixed(2))
|
||||||
|
},
|
||||||
|
message: '获取成功'
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
|
||||||
|
// FlexScreen 行情数据
|
||||||
|
http.get('/api/flex-screen/quotes', async ({ request }) => {
|
||||||
|
await delay(200);
|
||||||
|
|
||||||
|
const url = new URL(request.url);
|
||||||
|
const codes = url.searchParams.get('codes')?.split(',') || [];
|
||||||
|
|
||||||
|
console.log('[Mock Stock] 获取 FlexScreen 行情:', { codes });
|
||||||
|
|
||||||
|
// 默认主要指数
|
||||||
|
const defaultIndices = ['000001', '399001', '399006'];
|
||||||
|
const targetCodes = codes.length > 0 ? codes : defaultIndices;
|
||||||
|
|
||||||
|
const indexData = {
|
||||||
|
'000001': { name: '上证指数', basePrice: 3200 },
|
||||||
|
'399001': { name: '深证成指', basePrice: 10500 },
|
||||||
|
'399006': { name: '创业板指', basePrice: 2100 },
|
||||||
|
'000300': { name: '沪深300', basePrice: 3800 },
|
||||||
|
'000016': { name: '上证50', basePrice: 2600 },
|
||||||
|
'000905': { name: '中证500', basePrice: 5800 },
|
||||||
|
};
|
||||||
|
|
||||||
|
const quotesData = {};
|
||||||
|
targetCodes.forEach(code => {
|
||||||
|
const codeWithoutSuffix = code.replace(/\.(SH|SZ)$/i, '');
|
||||||
|
const info = indexData[codeWithoutSuffix] || { name: `指数${code}`, basePrice: 3000 };
|
||||||
|
|
||||||
|
const changePercent = parseFloat((Math.random() * 4 - 2).toFixed(2));
|
||||||
|
const price = parseFloat((info.basePrice * (1 + changePercent / 100)).toFixed(2));
|
||||||
|
const change = parseFloat((price - info.basePrice).toFixed(2));
|
||||||
|
|
||||||
|
quotesData[code] = {
|
||||||
|
code: code,
|
||||||
|
name: info.name,
|
||||||
|
price: price,
|
||||||
|
change: change,
|
||||||
|
change_percent: changePercent,
|
||||||
|
prev_close: info.basePrice,
|
||||||
|
open: parseFloat((info.basePrice * (1 + (Math.random() * 0.01 - 0.005))).toFixed(2)),
|
||||||
|
high: parseFloat((price * (1 + Math.random() * 0.01)).toFixed(2)),
|
||||||
|
low: parseFloat((price * (1 - Math.random() * 0.01)).toFixed(2)),
|
||||||
|
volume: parseFloat((Math.random() * 5000 + 2000).toFixed(2)), // 亿手
|
||||||
|
amount: parseFloat((Math.random() * 8000 + 3000).toFixed(2)), // 亿元
|
||||||
|
update_time: new Date().toISOString()
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return HttpResponse.json({
|
||||||
|
success: true,
|
||||||
|
data: quotesData,
|
||||||
|
message: '获取成功'
|
||||||
|
});
|
||||||
|
}),
|
||||||
];
|
];
|
||||||
|
|||||||
Reference in New Issue
Block a user