初始化基金监控系统项目
This commit is contained in:
657
recommend_fund.js
Normal file
657
recommend_fund.js
Normal file
@@ -0,0 +1,657 @@
|
||||
/**
|
||||
* 推荐基金页面JavaScript功能
|
||||
*/
|
||||
|
||||
// 配置常量
|
||||
const API_TIMEOUT = 5000; // API 请求超时时间(毫秒)
|
||||
const MAX_RETRY_COUNT = 3; // 最大重试次数
|
||||
const RETRY_DELAY = 1000; // 重试延迟(毫秒)
|
||||
const BATCH_SIZE = 10; // 批量请求数量
|
||||
const UPDATE_INTERVAL = 60000; // 自动更新间隔(毫秒)
|
||||
const HIGHLIGHT_DURATION = 300; // 高亮效果持续时间
|
||||
|
||||
// 全局状态
|
||||
let updateIntervalId = null;
|
||||
let isLoading = false;
|
||||
let fundDataCache = {}; // 缓存基金数据
|
||||
let lastData = {}; // 上一次的数据,用于比较变化
|
||||
let errorCount = 0;
|
||||
const MAX_ERROR_COUNT = 5; // 连续错误次数上限
|
||||
|
||||
/**
|
||||
* 格式化数字(保留两位小数)
|
||||
* @param {number} num - 要格式化的数字
|
||||
* @returns {string} 格式化后的字符串
|
||||
*/
|
||||
function formatNumber(num) {
|
||||
if (typeof num !== 'number' || isNaN(num)) {
|
||||
return '--';
|
||||
}
|
||||
return num.toFixed(2);
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示加载状态
|
||||
* @param {boolean} show - 是否显示
|
||||
*/
|
||||
function showLoading(show) {
|
||||
const loadingElement = document.getElementById('loading-indicator');
|
||||
if (!loadingElement && show) {
|
||||
// 创建加载指示器
|
||||
const div = document.createElement('div');
|
||||
div.id = 'loading-indicator';
|
||||
div.className = 'loading-overlay';
|
||||
div.innerHTML = `
|
||||
<div class="loading-spinner">
|
||||
<i class="fas fa-circle-notch fa-spin"></i>
|
||||
<span>加载基金数据中...</span>
|
||||
</div>
|
||||
`;
|
||||
document.body.appendChild(div);
|
||||
} else if (loadingElement) {
|
||||
loadingElement.style.display = show ? 'flex' : 'none';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理JSONP请求的资源
|
||||
* @param {string} scriptId - script标签ID
|
||||
* @param {string} callbackName - 回调函数名
|
||||
*/
|
||||
function cleanupResources(scriptId, callbackName) {
|
||||
// 清理script标签
|
||||
const script = document.getElementById(scriptId);
|
||||
if (script && script.parentNode) {
|
||||
script.parentNode.removeChild(script);
|
||||
}
|
||||
|
||||
// 清理回调函数
|
||||
if (window[callbackName]) {
|
||||
delete window[callbackName];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理API错误
|
||||
* @param {string} errorMessage - 错误消息
|
||||
*/
|
||||
function handleApiError(errorMessage) {
|
||||
errorCount++;
|
||||
console.error(errorMessage);
|
||||
|
||||
// 如果连续错误次数过多,显示错误提示
|
||||
if (errorCount >= MAX_ERROR_COUNT) {
|
||||
updateErrorDisplay('获取基金数据时遇到问题,请稍后再试', true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取单个基金数据(使用 JSONP 方式,支持预加载)
|
||||
* @param {string} fundCode - 基金代码
|
||||
* @param {number} retryCount - 当前重试次数
|
||||
* @returns {Promise<Object>} 基金数据对象
|
||||
*/
|
||||
function fetchFundData(fundCode, retryCount = 0) {
|
||||
// 清理基金代码,确保只包含数字和字母
|
||||
const cleanFundCode = String(fundCode).replace(/[^\dA-Za-z]/g, '').trim();
|
||||
|
||||
if (!cleanFundCode) {
|
||||
console.error('无效的基金代码:', fundCode);
|
||||
return Promise.resolve({
|
||||
success: false,
|
||||
error: '无效的基金代码',
|
||||
fundCode: fundCode
|
||||
});
|
||||
}
|
||||
|
||||
// 1. 检查是否有预加载数据
|
||||
if (window.preloadedFundData && window.preloadedFundData[cleanFundCode]) {
|
||||
console.log(`使用预加载数据: ${cleanFundCode}`);
|
||||
return Promise.resolve({
|
||||
success: true,
|
||||
data: window.preloadedFundData[cleanFundCode],
|
||||
fromCache: true
|
||||
});
|
||||
}
|
||||
|
||||
// 2. 检查缓存
|
||||
const cachedData = fundDataCache[cleanFundCode];
|
||||
if (cachedData && (Date.now() - cachedData.timestamp) < 30000) { // 30秒缓存
|
||||
return Promise.resolve({
|
||||
success: true,
|
||||
data: cachedData.data,
|
||||
fromCache: true
|
||||
});
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
// 设置超时
|
||||
const timeoutId = setTimeout(() => {
|
||||
reject(new Error('请求超时'));
|
||||
}, API_TIMEOUT);
|
||||
|
||||
// 创建唯一的回调函数名
|
||||
const callbackName = `jsonp_callback_${cleanFundCode}_${Date.now()}`;
|
||||
const scriptId = `jsonp_script_${cleanFundCode}`;
|
||||
|
||||
// 定义全局回调函数
|
||||
window[callbackName] = function(data) {
|
||||
clearTimeout(timeoutId);
|
||||
|
||||
// 检查数据有效性
|
||||
if (!data || !data.fundcode || data.fundcode !== cleanFundCode) {
|
||||
cleanupResources(scriptId, callbackName);
|
||||
handleApiError(`基金${cleanFundCode}数据格式错误`);
|
||||
resolve({
|
||||
success: false,
|
||||
error: '数据格式错误',
|
||||
fundCode: cleanFundCode
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 缓存数据
|
||||
fundDataCache[cleanFundCode] = {
|
||||
data: data,
|
||||
timestamp: Date.now()
|
||||
};
|
||||
|
||||
// 重置错误计数
|
||||
errorCount = 0;
|
||||
|
||||
// 清理资源并返回结果
|
||||
cleanupResources(scriptId, callbackName);
|
||||
resolve({
|
||||
success: true,
|
||||
data: data
|
||||
});
|
||||
};
|
||||
|
||||
// 创建脚本元素
|
||||
const script = document.createElement('script');
|
||||
script.id = scriptId;
|
||||
script.src = `http://fundgz.1234567.com.cn/js/${cleanFundCode}.js?callback=${callbackName}`;
|
||||
script.onerror = function() {
|
||||
clearTimeout(timeoutId);
|
||||
cleanupResources(scriptId, callbackName);
|
||||
reject(new Error('脚本加载失败'));
|
||||
};
|
||||
|
||||
// 添加到文档中
|
||||
document.body.appendChild(script);
|
||||
}).catch(error => {
|
||||
console.error(`获取基金 ${cleanFundCode} 数据失败:`, error.message);
|
||||
|
||||
// 重试逻辑
|
||||
if (retryCount < MAX_RETRY_COUNT) {
|
||||
console.log(`尝试重试 ${cleanFundCode}, 第 ${retryCount + 1} 次`);
|
||||
return new Promise(resolve => {
|
||||
setTimeout(() => {
|
||||
resolve(fetchFundData(cleanFundCode, retryCount + 1));
|
||||
}, RETRY_DELAY * (retryCount + 1));
|
||||
});
|
||||
}
|
||||
|
||||
handleApiError(`获取基金 ${cleanFundCode} 数据失败`);
|
||||
return {
|
||||
success: false,
|
||||
error: error.message,
|
||||
fundCode: cleanFundCode
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量获取基金数据
|
||||
* @param {Array<string>} fundCodes - 基金代码数组
|
||||
* @returns {Promise<Array>} 基金数据结果数组
|
||||
*/
|
||||
async function fetchFundsDataInBatch(fundCodes) {
|
||||
// 分批处理,避免一次请求过多
|
||||
const batches = [];
|
||||
for (let i = 0; i < fundCodes.length; i += BATCH_SIZE) {
|
||||
batches.push(fundCodes.slice(i, i + BATCH_SIZE));
|
||||
}
|
||||
|
||||
const allResults = [];
|
||||
|
||||
// 逐批处理
|
||||
for (const batch of batches) {
|
||||
// 使用Promise.allSettled确保所有请求都完成
|
||||
const batchPromises = batch.map(code => fetchFundData(code));
|
||||
const batchResults = await Promise.allSettled(batchPromises);
|
||||
|
||||
batchResults.forEach((result, index) => {
|
||||
if (result.status === 'fulfilled') {
|
||||
allResults.push(result.value);
|
||||
} else {
|
||||
console.error(`处理批处理中基金 ${batch[index]} 时出错:`, result.reason);
|
||||
allResults.push({
|
||||
success: false,
|
||||
error: result.reason?.message || '未知错误',
|
||||
fundCode: batch[index]
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 批处理之间添加短暂延迟,避免请求过于密集
|
||||
if (batches.indexOf(batch) < batches.length - 1) {
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
}
|
||||
}
|
||||
|
||||
return allResults;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新基金错误状态显示
|
||||
* @param {string} fundCode - 基金代码
|
||||
*/
|
||||
function updateFundError(fundCode) {
|
||||
// 更新基金名称显示
|
||||
document.querySelectorAll(`.fund-name[data-fund-code="${fundCode}"]`).forEach(el => {
|
||||
if (el.textContent === '加载中...') {
|
||||
el.textContent = `${fundCode} (数据获取失败)`;
|
||||
el.classList.add('error-text');
|
||||
}
|
||||
});
|
||||
|
||||
// 更新涨幅显示
|
||||
document.querySelectorAll(`.fund-change[data-fund-code="${fundCode}"]`).forEach(el => {
|
||||
el.textContent = '--';
|
||||
el.classList.add('error');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载所有基金信息
|
||||
*/
|
||||
async function loadAllFundInfo() {
|
||||
if (isLoading) return;
|
||||
isLoading = true;
|
||||
showLoading(true);
|
||||
|
||||
try {
|
||||
// 保存旧数据用于比较
|
||||
lastData = {};
|
||||
for (const fundCode in fundDataCache) {
|
||||
lastData[fundCode] = fundDataCache[fundCode].data;
|
||||
}
|
||||
|
||||
// 获取所有需要的基金代码
|
||||
const fundElements = document.querySelectorAll('[data-fund-code]');
|
||||
const fundCodes = Array.from(new Set(Array.from(fundElements).map(el => {
|
||||
const code = el.getAttribute('data-fund-code');
|
||||
// 清理基金代码
|
||||
return String(code || '').replace(/[^\dA-Za-z]/g, '').trim();
|
||||
}))).filter(code => code.length > 0); // 过滤空代码
|
||||
|
||||
if (fundCodes.length === 0) {
|
||||
console.log('没有找到需要加载的基金');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`开始加载 ${fundCodes.length} 支基金数据`, fundCodes);
|
||||
|
||||
// 批量获取基金数据
|
||||
const results = await fetchFundsDataInBatch(fundCodes);
|
||||
|
||||
// 更新UI
|
||||
let successCount = 0;
|
||||
results.forEach(result => {
|
||||
if (result.success && result.data) {
|
||||
updateFundDisplay(result.data);
|
||||
successCount++;
|
||||
} else {
|
||||
// 对于失败的请求,尝试更新为错误状态
|
||||
if (result.fundCode) {
|
||||
updateFundError(result.fundCode);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 更新IP组的总涨幅
|
||||
updateIpTotalChanges();
|
||||
|
||||
console.log(`基金数据加载完成: 成功${successCount}/${fundCodes.length}`);
|
||||
} catch (error) {
|
||||
console.error('加载基金信息时发生错误:', error);
|
||||
updateErrorDisplay('加载基金数据失败,请稍后重试', true);
|
||||
} finally {
|
||||
isLoading = false;
|
||||
showLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新单个基金的显示信息
|
||||
* @param {Object} fundData - 基金数据
|
||||
*/
|
||||
function updateFundDisplay(fundData) {
|
||||
if (!fundData || !fundData.fundcode) return;
|
||||
|
||||
const fundCode = fundData.fundcode;
|
||||
const name = fundData.name || '未知名称';
|
||||
const gszzl = parseFloat(fundData.gszzl) || 0;
|
||||
|
||||
// 检查是否有数据变化
|
||||
const oldData = lastData[fundCode];
|
||||
const hasChanged = !oldData || oldData.gszzl !== fundData.gszzl;
|
||||
|
||||
// 更新基金名称
|
||||
document.querySelectorAll(`.fund-name[data-fund-code="${fundCode}"]`).forEach(el => {
|
||||
el.textContent = name;
|
||||
});
|
||||
|
||||
// 更新基金涨幅
|
||||
document.querySelectorAll(`.fund-change[data-fund-code="${fundCode}"]`).forEach(el => {
|
||||
const oldValue = el.textContent;
|
||||
|
||||
el.textContent = `${formatNumber(gszzl)}%`;
|
||||
|
||||
// 根据涨跌设置颜色
|
||||
el.classList.remove('positive', 'negative', 'neutral', 'highlight');
|
||||
if (gszzl > 0) {
|
||||
el.classList.add('positive');
|
||||
} else if (gszzl < 0) {
|
||||
el.classList.add('negative');
|
||||
} else {
|
||||
el.classList.add('neutral');
|
||||
}
|
||||
|
||||
// 如果有变化,添加高亮效果
|
||||
if (hasChanged) {
|
||||
el.classList.add('highlight');
|
||||
setTimeout(() => {
|
||||
el.classList.remove('highlight');
|
||||
}, HIGHLIGHT_DURATION);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新IP组的总涨幅
|
||||
*/
|
||||
function updateIpTotalChanges() {
|
||||
// 获取所有IP分组
|
||||
const ipGroups = document.querySelectorAll('[id^="ip-"]');
|
||||
|
||||
ipGroups.forEach(group => {
|
||||
const ipId = group.id;
|
||||
const changeElements = group.querySelectorAll('.fund-change');
|
||||
let totalChange = 0;
|
||||
let validCount = 0;
|
||||
|
||||
changeElements.forEach(el => {
|
||||
const text = el.textContent.trim();
|
||||
if (text !== '--' && text !== '') {
|
||||
const change = parseFloat(text.replace('%', ''));
|
||||
if (!isNaN(change)) {
|
||||
totalChange += change;
|
||||
validCount++;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 计算平均涨幅
|
||||
const avgChange = validCount > 0 ? totalChange / validCount : 0;
|
||||
|
||||
// 更新显示
|
||||
const totalChangeElement = document.querySelector(`#total-change-${ipId.split('-')[1]}`);
|
||||
if (totalChangeElement) {
|
||||
const oldValue = totalChangeElement.textContent;
|
||||
const newValue = `${formatNumber(avgChange)}%`;
|
||||
|
||||
totalChangeElement.textContent = newValue;
|
||||
|
||||
// 如果有变化,添加高亮效果
|
||||
if (oldValue !== newValue) {
|
||||
totalChangeElement.classList.add('highlight');
|
||||
setTimeout(() => {
|
||||
totalChangeElement.classList.remove('highlight');
|
||||
}, HIGHLIGHT_DURATION);
|
||||
}
|
||||
|
||||
// 根据涨跌设置颜色
|
||||
totalChangeElement.classList.remove('positive', 'negative', 'neutral');
|
||||
if (avgChange > 0) {
|
||||
totalChangeElement.classList.add('positive');
|
||||
} else if (avgChange < 0) {
|
||||
totalChangeElement.classList.add('negative');
|
||||
} else {
|
||||
totalChangeElement.classList.add('neutral');
|
||||
}
|
||||
|
||||
// 将平均涨幅写入分组容器的data属性,便于排序
|
||||
const dropdownItem = document.getElementById(ipId)?.closest('.dropdown-item');
|
||||
if (dropdownItem) {
|
||||
dropdownItem.dataset.avgChange = String(avgChange);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新错误显示
|
||||
* @param {string} message - 错误信息
|
||||
* @param {boolean} show - 是否显示错误
|
||||
*/
|
||||
function updateErrorDisplay(message, show = true) {
|
||||
let errorElement = document.getElementById('api-error');
|
||||
|
||||
if (!errorElement) {
|
||||
errorElement = document.createElement('div');
|
||||
errorElement.id = 'api-error';
|
||||
errorElement.className = 'error-message';
|
||||
document.body.prepend(errorElement);
|
||||
}
|
||||
|
||||
if (show) {
|
||||
errorElement.textContent = message;
|
||||
errorElement.style.display = 'block';
|
||||
|
||||
// 5秒后自动隐藏错误信息
|
||||
setTimeout(() => {
|
||||
errorElement.style.display = 'none';
|
||||
}, 5000);
|
||||
} else {
|
||||
errorElement.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换下拉菜单显示/隐藏
|
||||
* @param {string} id - 要切换的元素ID
|
||||
*/
|
||||
function toggleDropdown(id) {
|
||||
const element = document.getElementById(id);
|
||||
if (element) {
|
||||
element.classList.toggle('show');
|
||||
|
||||
// 切换箭头方向
|
||||
const header = element.previousElementSibling;
|
||||
if (header) {
|
||||
const arrow = header.querySelector('.dropdown-arrow i');
|
||||
if (arrow) {
|
||||
arrow.classList.toggle('fa-chevron-down');
|
||||
arrow.classList.toggle('fa-chevron-up');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化函数
|
||||
*/
|
||||
function init() {
|
||||
// 初始加载基金数据
|
||||
loadAllFundInfo();
|
||||
|
||||
// 设置自动更新
|
||||
updateIntervalId = setInterval(loadAllFundInfo, UPDATE_INTERVAL);
|
||||
|
||||
// 清理函数
|
||||
window.addEventListener('beforeunload', cleanup);
|
||||
|
||||
// 为所有下拉菜单添加点击事件委托
|
||||
document.addEventListener('click', function(e) {
|
||||
// 检查是否点击了下拉菜单标题
|
||||
const dropdownHeader = e.target.closest('.dropdown-header');
|
||||
|
||||
if (dropdownHeader) {
|
||||
// 获取父级dropdown-item元素
|
||||
const dropdownItem = dropdownHeader.closest('.dropdown-item');
|
||||
if (dropdownItem) {
|
||||
// 关闭所有其他下拉菜单
|
||||
document.querySelectorAll('.dropdown-item').forEach(item => {
|
||||
if (item !== dropdownItem) {
|
||||
item.classList.remove('open');
|
||||
const arrow = item.querySelector('.dropdown-arrow i');
|
||||
if (arrow) {
|
||||
arrow.classList.remove('fa-chevron-up');
|
||||
arrow.classList.add('fa-chevron-down');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 切换当前下拉菜单
|
||||
dropdownItem.classList.toggle('open');
|
||||
|
||||
// 切换箭头方向
|
||||
const arrow = dropdownHeader.querySelector('.dropdown-arrow i');
|
||||
if (arrow) {
|
||||
arrow.classList.toggle('fa-chevron-down');
|
||||
arrow.classList.toggle('fa-chevron-up');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 点击其他地方,关闭所有下拉菜单
|
||||
document.querySelectorAll('.dropdown-item').forEach(item => {
|
||||
item.classList.remove('open');
|
||||
const arrow = item.querySelector('.dropdown-arrow i');
|
||||
if (arrow) {
|
||||
arrow.classList.remove('fa-chevron-up');
|
||||
arrow.classList.add('fa-chevron-down');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 初始化排序工具条
|
||||
initSortToolbar();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理函数
|
||||
*/
|
||||
function cleanup() {
|
||||
if (updateIntervalId) {
|
||||
clearInterval(updateIntervalId);
|
||||
updateIntervalId = null;
|
||||
}
|
||||
|
||||
// 清理所有可能的JSONP回调函数
|
||||
Object.keys(window).forEach(key => {
|
||||
if (key.startsWith('jsonp_callback_')) {
|
||||
delete window[key];
|
||||
}
|
||||
});
|
||||
|
||||
// 清理所有JSONP脚本标签
|
||||
document.querySelectorAll('script[id^="jsonp_script_"]').forEach(script => {
|
||||
if (script.parentNode) {
|
||||
script.parentNode.removeChild(script);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 页面加载完成后初始化
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', init);
|
||||
} else {
|
||||
init();
|
||||
}
|
||||
/**
|
||||
* 初始化排序工具条
|
||||
*/
|
||||
function initSortToolbar() {
|
||||
const container = document.querySelector('.dropdown-container');
|
||||
const buttons = document.querySelectorAll('.sort-btn');
|
||||
const resetBtn = document.querySelector('.sort-reset');
|
||||
if (!container || buttons.length === 0) return;
|
||||
|
||||
const applyActive = (activeBtn) => {
|
||||
buttons.forEach(btn => btn.classList.toggle('active', btn === activeBtn));
|
||||
// 更新箭头指示符
|
||||
buttons.forEach(btn => {
|
||||
const indicator = btn.querySelector('.order-indicator');
|
||||
if (indicator) {
|
||||
indicator.textContent = btn.dataset.order === 'asc' ? '↑' : '↓';
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const sortIpGroups = (key, order) => {
|
||||
const items = Array.from(container.querySelectorAll('.dropdown-item'));
|
||||
const getVal = (el) => {
|
||||
switch (key) {
|
||||
case 'time': {
|
||||
const t = el.dataset.latestTime || '';
|
||||
// 兼容 YYYY-MM-DD HH:mm:ss
|
||||
const timeNum = Date.parse(t.replace(/-/g, '/')) || 0;
|
||||
return timeNum;
|
||||
}
|
||||
case 'count':
|
||||
return parseInt(el.dataset.fundCount || '0', 10);
|
||||
case 'avg':
|
||||
return parseFloat(el.dataset.avgChange || '0');
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
items.sort((a, b) => {
|
||||
const av = getVal(a);
|
||||
const bv = getVal(b);
|
||||
if (av === bv) return 0;
|
||||
return order === 'asc' ? (av - bv) : (bv - av);
|
||||
});
|
||||
|
||||
// 重新插入排序后的元素
|
||||
items.forEach(el => container.appendChild(el));
|
||||
};
|
||||
|
||||
// 绑定按钮事件
|
||||
buttons.forEach(btn => {
|
||||
btn.addEventListener('click', () => {
|
||||
const sortKey = btn.dataset.sort;
|
||||
const currentOrder = btn.dataset.order || 'desc';
|
||||
// 如果重复点击同一按钮,切换升降序
|
||||
const newOrder = (btn.classList.contains('active') && currentOrder === 'desc') ? 'asc' : 'desc';
|
||||
btn.dataset.order = newOrder;
|
||||
applyActive(btn);
|
||||
sortIpGroups(sortKey, newOrder);
|
||||
});
|
||||
});
|
||||
|
||||
// 重置排序:恢复时间倒序
|
||||
if (resetBtn) {
|
||||
resetBtn.addEventListener('click', () => {
|
||||
// 所有按钮恢复箭头为倒序
|
||||
buttons.forEach(b => { b.dataset.order = 'desc'; });
|
||||
const defaultBtn = document.querySelector('.sort-btn[data-sort="time"]');
|
||||
if (defaultBtn) {
|
||||
defaultBtn.dataset.order = 'desc';
|
||||
applyActive(defaultBtn);
|
||||
sortIpGroups('time', 'desc');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 默认执行一次“按时间倒序”排序,保持与服务端一致
|
||||
const defaultBtn = document.querySelector('.sort-btn[data-sort="time"]');
|
||||
if (defaultBtn) {
|
||||
applyActive(defaultBtn);
|
||||
sortIpGroups('time', defaultBtn.dataset.order || 'desc');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user