/** * A股量化交易系统 主要JavaScript功能 */ $(document).ready(function() { // 初始化组件 initializeComponents(); // 绑定事件 bindEvents(); // 自动刷新 setupAutoRefresh(); }); /** * 初始化组件 */ function initializeComponents() { // 初始化工具提示 $('[data-bs-toggle="tooltip"]').tooltip(); // 初始化弹出框 $('[data-bs-toggle="popover"]').popover(); // 表格排序 initializeTableSorting(); // 数字格式化 formatNumbers(); } /** * 绑定事件 */ function bindEvents() { // 表格行点击事件 $('.table tbody tr').on('click', function() { $(this).toggleClass('table-active'); }); // 筛选表单自动提交 $('.auto-submit').on('change', function() { $(this).closest('form').submit(); }); // 复制股票代码 $('.stock-code').on('click', function() { const stockCode = $(this).text().trim(); copyToClipboard(stockCode); showToast('股票代码已复制: ' + stockCode); }); // 全选/取消全选 $('#selectAll').on('change', function() { $('.row-select').prop('checked', this.checked); }); // 导出数据 $('.export-btn').on('click', function() { const format = $(this).data('format'); exportData(format); }); } /** * 设置自动刷新 */ function setupAutoRefresh() { // 每5分钟自动刷新数据 setInterval(function() { if (document.visibilityState === 'visible') { refreshData(); } }, 300000); // 5分钟 // 页面可见时刷新 document.addEventListener('visibilitychange', function() { if (document.visibilityState === 'visible') { const lastRefresh = localStorage.getItem('lastRefresh'); const now = Date.now(); // 如果超过5分钟未刷新,则自动刷新 if (!lastRefresh || (now - parseInt(lastRefresh)) > 300000) { refreshData(); } } }); } /** * 刷新数据 */ function refreshData() { // 显示加载状态 showLoading(); // 记录刷新时间 localStorage.setItem('lastRefresh', Date.now().toString()); // 刷新页面数据 if (typeof updatePageData === 'function') { updatePageData(); } else { // 默认重新加载页面 setTimeout(() => { location.reload(); }, 1000); } } /** * 显示加载状态 */ function showLoading() { const loadingHtml = '
'; $('body').append(loadingHtml); setTimeout(() => { $('.loading-overlay').remove(); }, 2000); } /** * 显示提示消息 */ function showToast(message, type = 'success') { const toastHtml = ` `; // 创建toast容器(如果不存在) if (!$('.toast-container').length) { $('body').append('
'); } const $toast = $(toastHtml); $('.toast-container').append($toast); // 显示toast const toast = new bootstrap.Toast($toast[0]); toast.show(); // 自动移除 $toast.on('hidden.bs.toast', function() { $(this).remove(); }); } /** * 复制到剪贴板 */ function copyToClipboard(text) { if (navigator.clipboard) { navigator.clipboard.writeText(text); } else { // 备用方法 const textArea = document.createElement('textarea'); textArea.value = text; document.body.appendChild(textArea); textArea.select(); document.execCommand('copy'); document.body.removeChild(textArea); } } /** * 初始化表格排序 */ function initializeTableSorting() { $('.sortable th').on('click', function() { const table = $(this).closest('table'); const column = $(this).index(); const order = $(this).hasClass('asc') ? 'desc' : 'asc'; // 移除其他列的排序样式 $(this).siblings().removeClass('asc desc'); // 添加当前列的排序样式 $(this).removeClass('asc desc').addClass(order); // 排序表格行 sortTable(table, column, order); }); } /** * 表格排序 */ function sortTable(table, column, order) { const tbody = table.find('tbody'); const rows = tbody.find('tr').toArray(); rows.sort(function(a, b) { const aVal = $(a).find('td').eq(column).text().trim(); const bVal = $(b).find('td').eq(column).text().trim(); // 尝试数字比较 if (!isNaN(aVal) && !isNaN(bVal)) { return order === 'asc' ? aVal - bVal : bVal - aVal; } // 字符串比较 return order === 'asc' ? aVal.localeCompare(bVal) : bVal.localeCompare(aVal); }); tbody.empty().append(rows); } /** * 数字格式化 */ function formatNumbers() { $('.format-number').each(function() { const value = parseFloat($(this).text()); if (!isNaN(value)) { $(this).text(value.toLocaleString()); } }); $('.format-percentage').each(function() { const value = parseFloat($(this).text()); if (!isNaN(value)) { $(this).text(value.toFixed(2) + '%'); } }); $('.format-currency').each(function() { const value = parseFloat($(this).text()); if (!isNaN(value)) { $(this).text('¥' + value.toFixed(2)); } }); } /** * 导出数据 */ function exportData(format) { const table = $('.table').first(); if (!table.length) { showToast('没有可导出的数据', 'warning'); return; } switch (format) { case 'csv': exportToCSV(table); break; case 'excel': exportToExcel(table); break; case 'json': exportToJSON(table); break; default: showToast('不支持的导出格式', 'error'); } } /** * 导出为CSV */ function exportToCSV(table) { let csv = ''; // 表头 table.find('thead tr').each(function() { const row = []; $(this).find('th').each(function() { row.push('"' + $(this).text().trim() + '"'); }); csv += row.join(',') + '\n'; }); // 数据行 table.find('tbody tr').each(function() { const row = []; $(this).find('td').each(function() { row.push('"' + $(this).text().trim() + '"'); }); csv += row.join(',') + '\n'; }); // 下载文件 downloadFile(csv, 'trading_signals.csv', 'text/csv'); } /** * 下载文件 */ function downloadFile(content, filename, contentType) { const blob = new Blob([content], { type: contentType }); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = filename; document.body.appendChild(a); a.click(); document.body.removeChild(a); window.URL.revokeObjectURL(url); } /** * 获取API数据 */ function apiRequest(endpoint, params = {}) { return $.ajax({ url: '/api/' + endpoint, method: 'GET', data: params, dataType: 'json' }); } /** * 实时更新信号数据 */ function updateSignals() { apiRequest('signals', { limit: 10 }) .done(function(response) { if (response.success && response.data.length > 0) { updateSignalTable(response.data); showToast('信号数据已更新'); } }) .fail(function() { showToast('更新信号数据失败', 'error'); }); } /** * 更新信号表格 */ function updateSignalTable(signals) { const tbody = $('.signals-table tbody'); tbody.empty(); signals.forEach(function(signal) { const row = ` ${signal.stock_code} ${signal.stock_name || '未知'} ${signal.strategy_name} ${signal.timeframe} ${signal.signal_date} ${signal.breakout_price.toFixed(2)}元 ${signal.yin_high.toFixed(2)}元 ${signal.breakout_pct.toFixed(2)}% ${signal.final_yang_entity_ratio.toFixed(2)}% ${signal.turnover_ratio.toFixed(2)}% `; tbody.append(row); }); } // 全局错误处理 window.addEventListener('error', function(e) { console.error('JavaScript Error:', e.error); showToast('页面发生错误,请刷新重试', 'error'); }); // 网络状态监控 window.addEventListener('online', function() { showToast('网络连接已恢复'); }); window.addEventListener('offline', function() { showToast('网络连接已断开', 'warning'); });