// src/mocks/handlers/simulation.js import { http, HttpResponse, delay } from 'msw'; import { getCurrentUser } from '../data/users'; // 模拟网络延迟(毫秒) const NETWORK_DELAY = 300; // 模拟交易账户数据 let mockTradingAccount = { account_id: 'sim_001', account_name: '模拟交易账户', initial_capital: 1000000, available_cash: 850000, frozen_cash: 0, position_value: 150000, total_assets: 1000000, total_profit: 0, total_profit_rate: 0, daily_profit: 0, daily_profit_rate: 0, created_at: '2024-01-01T00:00:00Z', updated_at: new Date().toISOString() }; // 模拟持仓数据 let mockPositions = [ { id: 1, stock_code: '600036', stock_name: '招商银行', position_qty: 1000, available_qty: 1000, frozen_qty: 0, avg_cost: 42.50, current_price: 42.80, market_value: 42800, profit: 300, profit_rate: 0.71, today_profit: 100, today_profit_rate: 0.23, updated_at: new Date().toISOString() }, { id: 2, stock_code: '000001', stock_name: '平安银行', position_qty: 2000, available_qty: 2000, frozen_qty: 0, avg_cost: 12.30, current_price: 12.50, market_value: 25000, profit: 400, profit_rate: 1.63, today_profit: -50, today_profit_rate: -0.20, updated_at: new Date().toISOString() } ]; // 模拟交易历史 let mockOrders = [ { id: 1, order_no: 'ORD20240101001', stock_code: '600036', stock_name: '招商银行', order_type: 'BUY', price_type: 'MARKET', order_price: 42.50, order_qty: 1000, filled_qty: 1000, filled_price: 42.50, filled_amount: 42500, commission: 12.75, stamp_tax: 0, transfer_fee: 0.42, total_fee: 13.17, status: 'FILLED', reject_reason: null, order_time: '2024-01-15T09:30:00Z', filled_time: '2024-01-15T09:30:05Z' }, { id: 2, order_no: 'ORD20240102001', stock_code: '000001', stock_name: '平安银行', order_type: 'BUY', price_type: 'LIMIT', order_price: 12.30, order_qty: 2000, filled_qty: 2000, filled_price: 12.30, filled_amount: 24600, commission: 7.38, stamp_tax: 0, transfer_fee: 0.25, total_fee: 7.63, status: 'FILLED', reject_reason: null, order_time: '2024-01-16T10:15:00Z', filled_time: '2024-01-16T10:15:10Z' } ]; export const simulationHandlers = [ // ==================== 获取模拟账户信息 ==================== http.get('/api/simulation/account', async () => { await delay(NETWORK_DELAY); const currentUser = getCurrentUser(); // 未登录时返回401 if (!currentUser) { return HttpResponse.json({ success: false, error: '未登录' }, { status: 401 }); } console.log('[Mock] 获取模拟账户信息:', currentUser); return HttpResponse.json({ success: true, data: mockTradingAccount }); }), // ==================== 获取持仓列表 ==================== http.get('/api/simulation/positions', async () => { await delay(NETWORK_DELAY); const currentUser = getCurrentUser(); if (!currentUser) { return HttpResponse.json({ success: false, error: '未登录' }, { status: 401 }); } console.log('[Mock] 获取持仓列表'); return HttpResponse.json({ success: true, data: mockPositions }); }), // ==================== 获取交易订单历史 ==================== http.get('/api/simulation/orders', async ({ request }) => { await delay(NETWORK_DELAY); const currentUser = getCurrentUser(); if (!currentUser) { return HttpResponse.json({ success: false, error: '未登录' }, { status: 401 }); } const url = new URL(request.url); const limit = parseInt(url.searchParams.get('limit') || '100'); console.log('[Mock] 获取交易订单历史, limit:', limit); return HttpResponse.json({ success: true, data: mockOrders.slice(0, limit) }); }), // ==================== 下单(买入/卖出)==================== http.post('/api/simulation/place-order', async ({ request }) => { await delay(NETWORK_DELAY); const currentUser = getCurrentUser(); if (!currentUser) { return HttpResponse.json({ success: false, error: '未登录' }, { status: 401 }); } const body = await request.json(); console.log('[Mock] 下单请求:', body); const { stock_code, order_type, order_qty, price_type } = body; // 生成订单号 const orderNo = 'ORD' + Date.now(); // 创建新订单 const newOrder = { id: mockOrders.length + 1, order_no: orderNo, stock_code: stock_code, stock_name: '模拟股票', // 实际应该查询股票名称 order_type: order_type, price_type: price_type, order_price: 0, order_qty: order_qty, filled_qty: order_qty, filled_price: 0, filled_amount: 0, commission: 0, stamp_tax: 0, transfer_fee: 0, total_fee: 0, status: 'FILLED', reject_reason: null, order_time: new Date().toISOString(), filled_time: new Date().toISOString() }; // 添加到订单列表 mockOrders.unshift(newOrder); return HttpResponse.json({ success: true, message: '下单成功', data: { order_no: orderNo, order_id: newOrder.id } }); }), // ==================== 撤销订单 ==================== http.post('/api/simulation/cancel-order/:orderId', async ({ params }) => { await delay(NETWORK_DELAY); const currentUser = getCurrentUser(); if (!currentUser) { return HttpResponse.json({ success: false, error: '未登录' }, { status: 401 }); } const { orderId } = params; console.log('[Mock] 撤销订单:', orderId); // 查找并更新订单状态 const order = mockOrders.find(o => o.id.toString() === orderId || o.order_no === orderId); if (order) { order.status = 'CANCELLED'; } return HttpResponse.json({ success: true, message: '撤单成功' }); }), // ==================== 获取资产统计数据 ==================== http.get('/api/simulation/statistics', async ({ request }) => { await delay(NETWORK_DELAY); const currentUser = getCurrentUser(); if (!currentUser) { return HttpResponse.json({ success: false, error: '未登录' }, { status: 401 }); } const url = new URL(request.url); const days = parseInt(url.searchParams.get('days') || '30'); console.log('[Mock] 获取资产统计, days:', days); // 生成模拟的资产历史数据 const dailyReturns = []; const baseAssets = 1000000; for (let i = 0; i < days; i++) { const date = new Date(); date.setDate(date.getDate() - (days - 1 - i)); // 生成随机波动 const randomChange = (Math.random() - 0.5) * 0.02; // ±1% const assets = baseAssets * (1 + randomChange * i / days); dailyReturns.push({ date: date.toISOString().split('T')[0], closing_assets: assets, total_assets: assets, daily_profit: assets - baseAssets, daily_profit_rate: ((assets - baseAssets) / baseAssets * 100).toFixed(2) }); } return HttpResponse.json({ success: true, data: { daily_returns: dailyReturns, summary: { total_profit: 0, total_profit_rate: 0, win_rate: 50, max_drawdown: -5.2 } } }); }), // ==================== 获取交易记录 ==================== http.get('/api/simulation/transactions', async ({ request }) => { await delay(NETWORK_DELAY); const currentUser = getCurrentUser(); if (!currentUser) { return HttpResponse.json({ success: false, error: '未登录' }, { status: 401 }); } const url = new URL(request.url); const limit = parseInt(url.searchParams.get('limit') || '50'); console.log('[Mock] 获取交易记录, limit:', limit); // 返回已成交的订单作为交易记录 const transactions = mockOrders .filter(order => order.status === 'FILLED') .slice(0, limit); return HttpResponse.json({ success: true, data: transactions }); }), // ==================== 搜索股票 ==================== http.get('/api/stocks/search', async ({ request }) => { await delay(200); const url = new URL(request.url); const keyword = url.searchParams.get('q') || ''; const limit = parseInt(url.searchParams.get('limit') || '10'); console.log('[Mock] 搜索股票:', keyword); // 模拟股票数据 const allStocks = [ { stock_code: '000001', stock_name: '平安银行', current_price: 12.50, pinyin_abbr: 'payh', security_type: 'A股', exchange: '深交所' }, { stock_code: '000002', stock_name: '万科A', current_price: 8.32, pinyin_abbr: 'wka', security_type: 'A股', exchange: '深交所' }, { stock_code: '600036', stock_name: '招商银行', current_price: 42.80, pinyin_abbr: 'zsyh', security_type: 'A股', exchange: '上交所' }, { stock_code: '600519', stock_name: '贵州茅台', current_price: 1680.50, pinyin_abbr: 'gzmt', security_type: 'A股', exchange: '上交所' }, { stock_code: '601318', stock_name: '中国平安', current_price: 45.20, pinyin_abbr: 'zgpa', security_type: 'A股', exchange: '上交所' }, { stock_code: '688256', stock_name: '寒武纪', current_price: 1394.94, pinyin_abbr: 'hwj', security_type: 'A股', exchange: '上交所科创板' }, ]; // 过滤股票 const results = allStocks.filter(stock => stock.stock_code.includes(keyword) || stock.stock_name.includes(keyword) || stock.pinyin_abbr.includes(keyword.toLowerCase()) ).slice(0, limit); return HttpResponse.json({ success: true, data: results }); }) ];