优化修复
This commit is contained in:
@@ -10,9 +10,11 @@ let logsChart = null;
|
||||
let currentSortField = '';
|
||||
let currentSortDirection = 'desc'; // 默认降序
|
||||
|
||||
// IP地理位置缓存
|
||||
let ipGeolocationCache = {};
|
||||
const GEOLOCATION_CACHE_EXPIRY = 24 * 60 * 60 * 1000; // 缓存有效期24小时
|
||||
// IP地理位置缓存(检查是否已经存在,避免重复声明)
|
||||
if (typeof ipGeolocationCache === 'undefined') {
|
||||
var ipGeolocationCache = {};
|
||||
var GEOLOCATION_CACHE_EXPIRY = 24 * 60 * 60 * 1000; // 缓存有效期24小时
|
||||
}
|
||||
|
||||
// 获取IP地理位置信息
|
||||
async function getIpGeolocation(ip) {
|
||||
@@ -112,10 +114,12 @@ function isPrivateIP(ip) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 跟踪器数据库缓存
|
||||
let trackersDatabase = null;
|
||||
let trackersLoaded = false;
|
||||
let trackersLoading = false;
|
||||
// 跟踪器数据库缓存(检查是否已经存在,避免重复声明)
|
||||
if (typeof trackersDatabase === 'undefined') {
|
||||
var trackersDatabase = null;
|
||||
var trackersLoaded = false;
|
||||
var trackersLoading = false;
|
||||
}
|
||||
|
||||
// 域名信息数据库缓存
|
||||
let domainInfoDatabase = null;
|
||||
@@ -477,6 +481,270 @@ function extractPrimaryDomain(domain) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// 初始化列宽调节功能
|
||||
function initResizableColumns() {
|
||||
const table = document.querySelector('.resizable-table');
|
||||
if (!table) return;
|
||||
|
||||
// 为每个表头添加调整手柄元素
|
||||
function addResizeHandles() {
|
||||
const headers = table.querySelectorAll('th');
|
||||
headers.forEach(header => {
|
||||
// 移除已存在的手柄
|
||||
const existingHandle = header.querySelector('.resize-handle');
|
||||
if (existingHandle) {
|
||||
existingHandle.remove();
|
||||
}
|
||||
|
||||
// 创建新的调整手柄
|
||||
const resizeHandle = document.createElement('div');
|
||||
resizeHandle.className = 'resize-handle';
|
||||
resizeHandle.style.cssText = `
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 10px;
|
||||
height: 100%;
|
||||
cursor: col-resize;
|
||||
background: rgba(59, 130, 246, 0.1);
|
||||
z-index: 10;
|
||||
transition: background-color 0.2s ease;
|
||||
`;
|
||||
|
||||
// 添加悬停效果
|
||||
resizeHandle.addEventListener('mouseenter', () => {
|
||||
resizeHandle.style.background = 'rgba(59, 130, 246, 0.3)';
|
||||
});
|
||||
|
||||
resizeHandle.addEventListener('mouseleave', () => {
|
||||
if (!resizeHandle.classList.contains('dragging')) {
|
||||
resizeHandle.style.background = 'rgba(59, 130, 246, 0.1)';
|
||||
}
|
||||
});
|
||||
|
||||
header.style.position = 'relative';
|
||||
header.appendChild(resizeHandle);
|
||||
});
|
||||
}
|
||||
|
||||
// 计算列宽并设置固定宽度
|
||||
function calculateAndSetColumnWidths() {
|
||||
// 确保表格可见
|
||||
table.style.visibility = 'visible';
|
||||
|
||||
// 保存当前表格布局
|
||||
const originalLayout = table.style.tableLayout;
|
||||
table.style.tableLayout = 'auto';
|
||||
|
||||
// 获取所有表头和数据行
|
||||
const headers = table.querySelectorAll('th');
|
||||
const rows = table.querySelectorAll('tbody tr');
|
||||
|
||||
// 计算每列的最大宽度
|
||||
const columnWidths = [];
|
||||
headers.forEach((header, index) => {
|
||||
// 获取表头宽度
|
||||
let maxWidth = header.offsetWidth;
|
||||
|
||||
// 遍历所有数据行,找到该列的最大宽度
|
||||
rows.forEach(row => {
|
||||
const cell = row.children[index];
|
||||
if (cell) {
|
||||
maxWidth = Math.max(maxWidth, cell.offsetWidth);
|
||||
}
|
||||
});
|
||||
|
||||
// 添加一些 padding
|
||||
maxWidth += 20;
|
||||
|
||||
// 保存最大宽度
|
||||
columnWidths[index] = maxWidth;
|
||||
});
|
||||
|
||||
// 设置每列的固定宽度
|
||||
headers.forEach((header, index) => {
|
||||
const width = `${columnWidths[index]}px`;
|
||||
header.style.width = width;
|
||||
header.style.minWidth = width;
|
||||
header.style.maxWidth = width;
|
||||
|
||||
// 找到对应的数据列并设置宽度
|
||||
rows.forEach(row => {
|
||||
const cell = row.children[index];
|
||||
if (cell) {
|
||||
cell.style.width = width;
|
||||
cell.style.minWidth = width;
|
||||
cell.style.maxWidth = width;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 恢复表格布局
|
||||
table.style.tableLayout = 'fixed';
|
||||
}
|
||||
|
||||
// 保存列宽设置的函数
|
||||
function saveColumnWidths() {
|
||||
const headers = table.querySelectorAll('th');
|
||||
const columnWidths = {};
|
||||
headers.forEach((header, index) => {
|
||||
columnWidths[index] = header.style.width;
|
||||
});
|
||||
localStorage.setItem('logsTableColumnWidths', JSON.stringify(columnWidths));
|
||||
}
|
||||
|
||||
// 恢复列宽设置的函数
|
||||
function restoreColumnWidths() {
|
||||
const headers = table.querySelectorAll('th');
|
||||
const savedWidths = localStorage.getItem('logsTableColumnWidths');
|
||||
|
||||
if (savedWidths) {
|
||||
const columnWidths = JSON.parse(savedWidths);
|
||||
|
||||
// 设置表格布局为fixed
|
||||
table.style.tableLayout = 'fixed';
|
||||
|
||||
headers.forEach((header, index) => {
|
||||
if (columnWidths[index]) {
|
||||
const width = columnWidths[index];
|
||||
header.style.width = width;
|
||||
header.style.minWidth = width;
|
||||
header.style.maxWidth = width;
|
||||
|
||||
// 找到对应的数据列并设置宽度
|
||||
const rows = table.querySelectorAll('tbody tr');
|
||||
rows.forEach(row => {
|
||||
const cell = row.children[index];
|
||||
if (cell) {
|
||||
cell.style.width = width;
|
||||
cell.style.minWidth = width;
|
||||
cell.style.maxWidth = width;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// 没有保存的宽度,计算并设置列宽
|
||||
calculateAndSetColumnWidths();
|
||||
}
|
||||
}
|
||||
|
||||
// 恢复保存的列宽设置或计算初始列宽
|
||||
restoreColumnWidths();
|
||||
|
||||
// 添加调整手柄
|
||||
addResizeHandles();
|
||||
|
||||
// 拖拽状态变量
|
||||
let currentHeader = null;
|
||||
let startX = 0;
|
||||
let startWidth = 0;
|
||||
let isDragging = false;
|
||||
|
||||
// 鼠标按下事件
|
||||
table.addEventListener('mousedown', (e) => {
|
||||
const resizeHandle = e.target.closest('.resize-handle');
|
||||
if (resizeHandle) {
|
||||
currentHeader = resizeHandle.parentElement;
|
||||
startX = e.clientX;
|
||||
startWidth = currentHeader.offsetWidth;
|
||||
isDragging = true;
|
||||
|
||||
// 添加拖拽状态类
|
||||
currentHeader.classList.add('dragging');
|
||||
resizeHandle.classList.add('dragging');
|
||||
|
||||
// 改变拖拽手柄样式
|
||||
resizeHandle.style.background = 'rgba(59, 130, 246, 0.6)';
|
||||
|
||||
// 阻止默认事件和冒泡
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
// 阻止文本选择
|
||||
document.addEventListener('selectstart', preventSelect, { capture: true });
|
||||
document.addEventListener('copy', preventCopy, { capture: true });
|
||||
|
||||
// 添加全局事件监听器
|
||||
document.addEventListener('mousemove', onMouseMove, { capture: true });
|
||||
document.addEventListener('mouseup', onMouseUp, { capture: true });
|
||||
}
|
||||
});
|
||||
|
||||
// 鼠标移动事件处理函数
|
||||
function onMouseMove(e) {
|
||||
if (!currentHeader) return;
|
||||
|
||||
// 阻止默认事件
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
// 计算新宽度
|
||||
const deltaX = e.clientX - startX;
|
||||
const newWidth = Math.max(50, startWidth + deltaX);
|
||||
|
||||
// 设置新宽度
|
||||
const width = `${newWidth}px`;
|
||||
currentHeader.style.width = width;
|
||||
currentHeader.style.minWidth = width;
|
||||
currentHeader.style.maxWidth = width;
|
||||
|
||||
// 找到对应的数据列并设置宽度
|
||||
const headers = table.querySelectorAll('th');
|
||||
const index = Array.from(headers).indexOf(currentHeader);
|
||||
const rows = table.querySelectorAll('tbody tr');
|
||||
rows.forEach(row => {
|
||||
const cell = row.children[index];
|
||||
if (cell) {
|
||||
cell.style.width = width;
|
||||
cell.style.minWidth = width;
|
||||
cell.style.maxWidth = width;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 鼠标释放事件处理函数
|
||||
function onMouseUp(e) {
|
||||
if (!currentHeader) return;
|
||||
|
||||
// 阻止默认事件
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
// 获取调整手柄
|
||||
const resizeHandle = currentHeader.querySelector('.resize-handle');
|
||||
|
||||
// 移除拖拽状态类
|
||||
currentHeader.classList.remove('dragging');
|
||||
resizeHandle.classList.remove('dragging');
|
||||
|
||||
// 恢复拖拽手柄样式
|
||||
resizeHandle.style.background = 'rgba(59, 130, 246, 0.1)';
|
||||
|
||||
// 保存列宽设置
|
||||
saveColumnWidths();
|
||||
|
||||
// 重置状态
|
||||
currentHeader = null;
|
||||
isDragging = false;
|
||||
|
||||
// 移除事件监听器
|
||||
document.removeEventListener('selectstart', preventSelect, { capture: true });
|
||||
document.removeEventListener('copy', preventCopy, { capture: true });
|
||||
document.removeEventListener('mousemove', onMouseMove, { capture: true });
|
||||
document.removeEventListener('mouseup', onMouseUp, { capture: true });
|
||||
}
|
||||
|
||||
// 阻止文本选择和复制
|
||||
function preventSelect(e) {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
function preventCopy(e) {
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化查询日志页面
|
||||
function initLogsPage() {
|
||||
console.log('初始化查询日志页面');
|
||||
@@ -499,6 +767,9 @@ function initLogsPage() {
|
||||
// 建立WebSocket连接,用于实时更新统计数据和图表
|
||||
connectLogsWebSocket();
|
||||
|
||||
// 初始化列宽调节功能
|
||||
initResizableColumns();
|
||||
|
||||
// 窗口大小改变时重新加载日志表格
|
||||
window.addEventListener('resize', handleWindowResize);
|
||||
|
||||
@@ -723,7 +994,7 @@ function loadLogsStats() {
|
||||
}
|
||||
|
||||
// 加载日志详情
|
||||
function loadLogs() {
|
||||
async function loadLogs() {
|
||||
// 显示加载状态
|
||||
const loadingEl = document.getElementById('logs-loading');
|
||||
if (loadingEl) {
|
||||
@@ -748,61 +1019,70 @@ function loadLogs() {
|
||||
endpoint += `&sort=${currentSortField}&direction=${currentSortDirection}`;
|
||||
}
|
||||
|
||||
// 使用封装的apiRequest函数进行API调用
|
||||
apiRequest(endpoint)
|
||||
.then(data => {
|
||||
if (data && data.error) {
|
||||
console.error('加载日志详情失败:', data.error);
|
||||
// 隐藏加载状态
|
||||
if (loadingEl) {
|
||||
loadingEl.classList.add('hidden');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 加载日志总数
|
||||
return apiRequest('/logs/count').then(countData => {
|
||||
return { logs: data, count: countData.count };
|
||||
});
|
||||
})
|
||||
.then(result => {
|
||||
if (!result || !result.logs) {
|
||||
console.error('加载日志详情失败: 无效的响应数据');
|
||||
// 隐藏加载状态
|
||||
if (loadingEl) {
|
||||
loadingEl.classList.add('hidden');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const logs = result.logs;
|
||||
const totalLogs = result.count;
|
||||
|
||||
// 计算总页数
|
||||
totalPages = Math.ceil(totalLogs / logsPerPage);
|
||||
|
||||
// 更新日志表格
|
||||
updateLogsTable(logs);
|
||||
|
||||
// 绑定操作按钮事件
|
||||
bindActionButtonsEvents();
|
||||
|
||||
// 更新分页信息
|
||||
updateLogsPagination();
|
||||
|
||||
try {
|
||||
// 使用封装的apiRequest函数进行API调用
|
||||
const logsData = await apiRequest(endpoint);
|
||||
|
||||
if (logsData && logsData.error) {
|
||||
console.error('加载日志详情失败:', logsData.error);
|
||||
// 隐藏加载状态
|
||||
if (loadingEl) {
|
||||
loadingEl.classList.add('hidden');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('加载日志详情失败:', error);
|
||||
|
||||
// 隐藏加载状态
|
||||
if (loadingEl) {
|
||||
loadingEl.classList.add('hidden');
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 加载日志总数
|
||||
const [logs, countData] = await Promise.all([
|
||||
Promise.resolve(logsData || []), // 确保logsData是数组
|
||||
apiRequest('/logs/count')
|
||||
]);
|
||||
|
||||
// 确保logs是数组
|
||||
const logsArray = Array.isArray(logs) ? logs : [];
|
||||
// 确保countData是有效的
|
||||
const totalLogs = countData && countData.count ? countData.count : logsArray.length;
|
||||
|
||||
// 计算总页数
|
||||
totalPages = Math.ceil(totalLogs / logsPerPage);
|
||||
|
||||
// 更新日志表格
|
||||
await updateLogsTable(logsArray);
|
||||
|
||||
// 绑定操作按钮事件
|
||||
bindActionButtonsEvents();
|
||||
|
||||
// 更新分页信息
|
||||
updateLogsPagination();
|
||||
|
||||
// 重新初始化列宽调节功能,确保新添加的行也能继承列宽设置
|
||||
initResizableColumns();
|
||||
|
||||
// 隐藏加载状态
|
||||
if (loadingEl) {
|
||||
loadingEl.classList.add('hidden');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载日志详情失败:', error);
|
||||
|
||||
// 隐藏加载状态
|
||||
if (loadingEl) {
|
||||
loadingEl.classList.add('hidden');
|
||||
}
|
||||
|
||||
// 显示空状态
|
||||
const tableBody = document.getElementById('logs-table-body');
|
||||
if (tableBody) {
|
||||
tableBody.innerHTML = `
|
||||
<tr>
|
||||
<td colspan="5" class="py-8 text-center text-gray-500 border-b border-gray-100">
|
||||
<i class="fa fa-file-text-o text-4xl mb-2 text-gray-300"></i>
|
||||
<div>暂无查询日志</div>
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 更新日志表格
|
||||
|
||||
Reference in New Issue
Block a user