/**
* 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');
});