// 股票数据展示系统前端应用 class StockDataApp { constructor() { this.currentPage = 1; this.pageSize = 20; this.currentStock = null; this.klineChart = null; this.init(); } // 初始化应用 async init() { this.setupEventListeners(); await this.loadSystemOverview(); await this.loadStockData(); this.setupNavigation(); } // 设置事件监听器 setupEventListeners() { // 搜索功能 const searchInput = document.getElementById('stock-search'); const searchBtn = document.getElementById('search-btn'); searchBtn.addEventListener('click', () => this.searchStocks()); searchInput.addEventListener('keypress', (e) => { if (e.key === 'Enter') this.searchStocks(); }); // 股票选择器 const stockSelector = document.getElementById('stock-selector'); stockSelector.addEventListener('change', (e) => { this.currentStock = e.target.value; if (this.currentStock) this.loadKlineChart(); }); // 周期选择器 const periodSelector = document.getElementById('period-selector'); periodSelector.addEventListener('change', () => { if (this.currentStock) this.loadKlineChart(); }); // 财务数据选择器 const financialStockSelector = document.getElementById('financial-stock-selector'); financialStockSelector.addEventListener('change', (e) => { if (e.target.value) this.loadFinancialData(e.target.value); }); // 日志刷新 const refreshLogsBtn = document.getElementById('refresh-logs'); refreshLogsBtn.addEventListener('click', () => this.loadSystemLogs()); // 日志过滤器 const logLevelFilter = document.getElementById('log-level-filter'); logLevelFilter.addEventListener('change', () => this.loadSystemLogs()); const logDateFilter = document.getElementById('log-date-filter'); logDateFilter.addEventListener('change', () => this.loadSystemLogs()); } // 设置导航 setupNavigation() { const navLinks = document.querySelectorAll('.nav-link'); const sections = document.querySelectorAll('.content-section'); navLinks.forEach(link => { link.addEventListener('click', (e) => { e.preventDefault(); // 移除所有激活状态 navLinks.forEach(l => l.classList.remove('active')); sections.forEach(s => s.classList.remove('active')); // 添加当前激活状态 link.classList.add('active'); const targetSection = document.querySelector(link.getAttribute('href')); if (targetSection) { targetSection.classList.add('active'); // 加载对应数据 switch(link.getAttribute('href')) { case '#kline-chart': this.loadKlineChart(); break; case '#financial-data': this.loadFinancialData(); break; case '#system-logs': this.loadSystemLogs(); break; } } }); }); } // 显示加载遮罩 showLoading() { document.getElementById('loading-overlay').classList.add('show'); } // 隐藏加载遮罩 hideLoading() { document.getElementById('loading-overlay').classList.remove('show'); } // 加载系统概览数据 async loadSystemOverview() { try { const response = await this.apiCall('/api/system/overview'); if (response.success) { document.getElementById('stock-count').textContent = this.formatNumber(response.stock_count); document.getElementById('kline-count').textContent = this.formatNumber(response.kline_count); document.getElementById('financial-count').textContent = this.formatNumber(response.financial_count); document.getElementById('log-count').textContent = this.formatNumber(response.log_count); } } catch (error) { console.error('加载系统概览失败:', error); } } // 加载股票数据 async loadStockData(page = 1) { try { this.showLoading(); const response = await this.apiCall(`/api/stocks?page=${page}&limit=${this.pageSize}`); if (response.success) { this.renderStockTable(response.data); this.setupPagination(response.total, page); this.populateStockSelectors(response.data); } } catch (error) { console.error('加载股票数据失败:', error); this.showError('加载股票数据失败'); } finally { this.hideLoading(); } } // 渲染股票表格 renderStockTable(stocks) { const tbody = document.getElementById('stock-table-body'); tbody.innerHTML = ''; stocks.forEach(stock => { const row = document.createElement('tr'); row.innerHTML = ` ${stock.code} ${stock.name} ${stock.exchange} ${this.formatDate(stock.listing_date)} ${stock.industry || '-'} `; tbody.appendChild(row); }); } // 设置分页 setupPagination(total, currentPage) { const pagination = document.getElementById('stock-pagination'); const totalPages = Math.ceil(total / this.pageSize); if (totalPages <= 1) { pagination.innerHTML = ''; return; } let html = ''; // 上一页按钮 if (currentPage > 1) { html += ``; } // 页码按钮 for (let i = 1; i <= totalPages; i++) { if (i === currentPage) { html += ``; } else { html += ``; } } // 下一页按钮 if (currentPage < totalPages) { html += ``; } pagination.innerHTML = html; } // 填充股票选择器 populateStockSelectors(stocks) { const selectors = [ document.getElementById('stock-selector'), document.getElementById('financial-stock-selector') ]; selectors.forEach(selector => { // 清空现有选项(保留第一个选项) while (selector.children.length > 1) { selector.removeChild(selector.lastChild); } // 添加股票选项 stocks.forEach(stock => { const option = document.createElement('option'); option.value = stock.code; option.textContent = `${stock.code} - ${stock.name}`; selector.appendChild(option); }); }); } // 搜索股票 async searchStocks() { const query = document.getElementById('stock-search').value.trim(); if (!query) { await this.loadStockData(); return; } try { this.showLoading(); const response = await this.apiCall(`/api/stocks/search?q=${encodeURIComponent(query)}`); if (response.success) { this.renderStockTable(response.data); document.getElementById('stock-pagination').innerHTML = ''; } } catch (error) { console.error('搜索股票失败:', error); this.showError('搜索股票失败'); } finally { this.hideLoading(); } } // 加载K线图表 async loadKlineChart() { if (!this.currentStock) return; try { this.showLoading(); const period = document.getElementById('period-selector').value; const response = await this.apiCall(`/api/kline/${this.currentStock}?period=${period}`); if (response.success) { this.renderKlineChart(response.data); } } catch (error) { console.error('加载K线数据失败:', error); this.showError('加载K线数据失败'); } finally { this.hideLoading(); } } // 渲染K线图表 renderKlineChart(klineData) { const ctx = document.getElementById('kline-chart-canvas').getContext('2d'); // 销毁现有图表 if (this.klineChart) { this.klineChart.destroy(); } const dates = klineData.map(item => item.date); const prices = klineData.map(item => item.close); this.klineChart = new Chart(ctx, { type: 'line', data: { labels: dates, datasets: [{ label: '收盘价', data: prices, borderColor: '#667eea', backgroundColor: 'rgba(102, 126, 234, 0.1)', fill: true, tension: 0.1 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { title: { display: true, text: '股票价格走势图' } }, scales: { y: { beginAtZero: false } } } }); } // 加载财务数据 async loadFinancialData(stockCode = null) { try { this.showLoading(); if (!stockCode) { stockCode = document.getElementById('financial-stock-selector').value; } if (!stockCode) return; const period = document.getElementById('report-period').value; const year = document.getElementById('report-year').value; const response = await this.apiCall(`/api/financial/${stockCode}?year=${year}&period=${period}`); if (response.success) { this.renderFinancialTable(response.data); } } catch (error) { console.error('加载财务数据失败:', error); this.showError('加载财务数据失败'); } finally { this.hideLoading(); } } // 渲染财务数据表格 renderFinancialTable(financialData) { const tbody = document.getElementById('financial-table-body'); tbody.innerHTML = ''; if (!financialData || Object.keys(financialData).length === 0) { tbody.innerHTML = '暂无财务数据'; return; } const financialItems = [ { key: 'revenue', label: '营业收入', unit: '万元' }, { key: 'net_profit', label: '净利润', unit: '万元' }, { key: 'total_assets', label: '总资产', unit: '万元' }, { key: 'total_liabilities', label: '总负债', unit: '万元' }, { key: 'eps', label: '每股收益', unit: '元' }, { key: 'roe', label: '净资产收益率', unit: '%' } ]; financialItems.forEach(item => { if (financialData[item.key] !== undefined) { const row = document.createElement('tr'); row.innerHTML = ` ${item.label} ${this.formatNumber(financialData[item.key])} ${item.unit} ${this.calculateChange(financialData[item.key])} `; tbody.appendChild(row); } }); } // 加载系统日志 async loadSystemLogs() { try { this.showLoading(); const level = document.getElementById('log-level-filter').value; const date = document.getElementById('log-date-filter').value; let url = '/api/system/logs'; const params = []; if (level) params.push(`level=${level}`); if (date) params.push(`date=${date}`); if (params.length > 0) { url += '?' + params.join('&'); } const response = await this.apiCall(url); if (response.success) { this.renderSystemLogs(response.data); } } catch (error) { console.error('加载系统日志失败:', error); this.showError('加载系统日志失败'); } finally { this.hideLoading(); } } // 渲染系统日志 renderSystemLogs(logs) { const logList = document.getElementById('log-list'); logList.innerHTML = ''; if (!logs || logs.length === 0) { logList.innerHTML = '
暂无系统日志
'; return; } logs.forEach(log => { const logItem = document.createElement('div'); logItem.className = `log-item ${log.level.toLowerCase()}`; logItem.innerHTML = `
${log.level} ${this.formatDateTime(log.timestamp)}
${log.message}
模块: ${log.module_name} | 事件: ${log.event_type} ${log.exception_type ? ` | 异常: ${log.exception_type}` : ''}
`; logList.appendChild(logItem); }); } // 查看股票详情 viewStockDetails(stockCode) { alert(`查看股票 ${stockCode} 的详细信息`); // 这里可以扩展为显示详细模态框 } // API调用封装 async apiCall(url) { // 模拟API调用,实际项目中需要连接到后端API return new Promise((resolve) => { setTimeout(() => { // 模拟数据 const mockData = this.getMockData(url); resolve(mockData); }, 500); }); } // 获取模拟数据 getMockData(url) { if (url.includes('/api/system/overview')) { return { success: true, stock_count: 12595, kline_count: 440, financial_count: 50, log_count: 4 }; } if (url.includes('/api/stocks')) { // 模拟股票数据 const mockStocks = [ { code: '000001', name: '平安银行', exchange: 'SZ', listing_date: '1991-04-03', industry: '银行' }, { code: '000002', name: '万科A', exchange: 'SZ', listing_date: '1991-01-29', industry: '房地产' }, { code: '600000', name: '浦发银行', exchange: 'SH', listing_date: '1999-11-10', industry: '银行' }, { code: '600036', name: '招商银行', exchange: 'SH', listing_date: '2002-04-09', industry: '银行' }, { code: '601318', name: '中国平安', exchange: 'SH', listing_date: '2007-03-01', industry: '保险' } ]; return { success: true, data: mockStocks, total: 12595 }; } if (url.includes('/api/kline/')) { // 模拟K线数据 const dates = []; const prices = []; const basePrice = 10; for (let i = 30; i >= 0; i--) { const date = new Date(); date.setDate(date.getDate() - i); dates.push(date.toISOString().split('T')[0]); // 模拟价格波动 const price = basePrice + Math.random() * 5; prices.push({ date: date.toISOString().split('T')[0], open: price - 0.5, high: price + 0.8, low: price - 0.8, close: price, volume: Math.floor(Math.random() * 1000000) }); } return { success: true, data: prices }; } if (url.includes('/api/financial/')) { // 模拟财务数据 return { success: true, data: { revenue: 500000, net_profit: 80000, total_assets: 2000000, total_liabilities: 1200000, eps: 1.5, roe: 15.2 } }; } if (url.includes('/api/system/logs')) { // 模拟系统日志 return { success: true, data: [ { id: 1, timestamp: new Date().toISOString(), level: 'INFO', module_name: 'System', event_type: 'STARTUP', message: '系统启动成功', exception_type: null }, { id: 2, timestamp: new Date(Date.now() - 3600000).toISOString(), level: 'INFO', module_name: 'DataCollector', event_type: 'DATA_COLLECTION', message: '开始采集股票数据', exception_type: null }, { id: 3, timestamp: new Date(Date.now() - 1800000).toISOString(), level: 'ERROR', module_name: 'Database', event_type: 'CONNECTION_ERROR', message: '数据库连接失败', exception_type: 'ConnectionError' }, { id: 4, timestamp: new Date(Date.now() - 900000).toISOString(), level: 'WARNING', module_name: 'DataProcessor', event_type: 'DATA_FORMAT', message: '数据格式异常,已自动修复', exception_type: 'FormatError' } ] }; } return { success: false, message: 'API endpoint not found' }; } // 工具函数 formatNumber(num) { if (num === null || num === undefined) return '-'; return new Intl.NumberFormat('zh-CN').format(num); } formatDate(dateString) { if (!dateString) return '-'; return new Date(dateString).toLocaleDateString('zh-CN'); } formatDateTime(dateString) { if (!dateString) return '-'; return new Date(dateString).toLocaleString('zh-CN'); } calculateChange(value) { const change = (Math.random() - 0.5) * 20; const sign = change >= 0 ? '+' : ''; const color = change >= 0 ? '#27ae60' : '#e74c3c'; return `${sign}${change.toFixed(2)}%`; } showError(message) { alert(`错误: ${message}`); } } // 全局应用实例 const app = new StockDataApp(); // 页面加载完成后初始化 document.addEventListener('DOMContentLoaded', () => { console.log('股票数据展示系统已加载'); });