|
|
@ -79,6 +79,46 @@ |
|
|
|
white-space: nowrap; |
|
|
|
} |
|
|
|
|
|
|
|
/* 排序相关样式 */ |
|
|
|
.sortable-header { |
|
|
|
cursor: pointer; |
|
|
|
user-select: none; |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
gap: 4px; |
|
|
|
transition: background-color 0.2s; |
|
|
|
} |
|
|
|
|
|
|
|
.sortable-header:hover { |
|
|
|
background-color: #e9ecef; |
|
|
|
border-radius: 3px; |
|
|
|
padding: 2px 4px; |
|
|
|
margin: -2px -4px; |
|
|
|
} |
|
|
|
|
|
|
|
.sort-icon { |
|
|
|
font-size: 0.8em; |
|
|
|
opacity: 0.5; |
|
|
|
transition: opacity 0.2s; |
|
|
|
} |
|
|
|
|
|
|
|
.sortable-header:hover .sort-icon { |
|
|
|
opacity: 1; |
|
|
|
} |
|
|
|
|
|
|
|
.sort-icon.active { |
|
|
|
opacity: 1; |
|
|
|
color: #007bff; |
|
|
|
} |
|
|
|
|
|
|
|
.sort-icon.asc::after { |
|
|
|
content: " ▲"; |
|
|
|
} |
|
|
|
|
|
|
|
.sort-icon.desc::after { |
|
|
|
content: " ▼"; |
|
|
|
} |
|
|
|
|
|
|
|
/* 右侧日志详情 */ |
|
|
|
.log-detail-panel { |
|
|
|
flex-grow: 1; |
|
|
@ -382,7 +422,10 @@ |
|
|
|
<div id="info-message" class="info-message"></div> |
|
|
|
|
|
|
|
<div class="log-list-header"> |
|
|
|
<span class="log-timestamp">Timestamp</span> |
|
|
|
<span class="log-timestamp sortable-header" id="timestamp-sort"> |
|
|
|
Timestamp |
|
|
|
<span class="sort-icon" id="timestamp-sort-icon"></span> |
|
|
|
</span> |
|
|
|
<span class="log-layer">Layer</span> |
|
|
|
<span class="log-direction">Direction</span> |
|
|
|
<span class="log-message">Message</span> |
|
|
@ -472,6 +515,10 @@ |
|
|
|
const maxReconnectAttempts = 5; |
|
|
|
const reconnectDelay = 3000; // 3秒 |
|
|
|
|
|
|
|
// 排序相关变量 |
|
|
|
let sortField = 'timestamp'; // 当前排序字段 |
|
|
|
let sortDirection = 'desc'; // 当前排序方向:'asc' 或 'desc' |
|
|
|
|
|
|
|
let clusterize = new Clusterize({ |
|
|
|
rows: [], |
|
|
|
scrollId: 'log-scroll-area', |
|
|
@ -499,6 +546,28 @@ |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 更新排序图标 |
|
|
|
function updateSortIcon() { |
|
|
|
const sortIcon = document.getElementById('timestamp-sort-icon'); |
|
|
|
sortIcon.className = 'sort-icon'; |
|
|
|
|
|
|
|
if (sortField === 'timestamp') { |
|
|
|
sortIcon.classList.add('active', sortDirection); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 排序数据 |
|
|
|
function sortLogsData() { |
|
|
|
allLogsData.sort((a, b) => { |
|
|
|
if (sortField === 'timestamp') { |
|
|
|
const timeA = a.Timestamp || 0; |
|
|
|
const timeB = b.Timestamp || 0; |
|
|
|
return sortDirection === 'asc' ? timeA - timeB : timeB - timeA; |
|
|
|
} |
|
|
|
return 0; |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
// 更新Layer过滤器选项 |
|
|
|
function updateLayerFilter() { |
|
|
|
const options = []; |
|
|
@ -549,6 +618,15 @@ |
|
|
|
filteredLogs = allLogsData.filter(log => selectedLayers.has(log.Layer)); |
|
|
|
} |
|
|
|
|
|
|
|
// 对过滤后的数据进行排序 |
|
|
|
if (sortField === 'timestamp') { |
|
|
|
filteredLogs.sort((a, b) => { |
|
|
|
const timeA = a.Timestamp || 0; |
|
|
|
const timeB = b.Timestamp || 0; |
|
|
|
return sortDirection === 'asc' ? timeA - timeB : timeB - timeA; |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
const rows = filteredLogs.map((log, i) => formatLogItem(log, i)); |
|
|
|
clusterize.clear(); |
|
|
|
clusterize.append(rows); |
|
|
@ -594,11 +672,37 @@ |
|
|
|
detailPlaceholder.classList.remove('d-none'); |
|
|
|
detailContent.classList.add('d-none'); |
|
|
|
updateLayerFilter(); |
|
|
|
|
|
|
|
// 重置排序状态 |
|
|
|
sortField = 'timestamp'; |
|
|
|
sortDirection = 'desc'; |
|
|
|
updateSortIcon(); |
|
|
|
} |
|
|
|
|
|
|
|
// 处理时间戳排序 |
|
|
|
function handleTimestampSort() { |
|
|
|
if (sortField === 'timestamp') { |
|
|
|
// 切换排序方向 |
|
|
|
sortDirection = sortDirection === 'asc' ? 'desc' : 'asc'; |
|
|
|
} else { |
|
|
|
// 首次点击时间戳排序 |
|
|
|
sortField = 'timestamp'; |
|
|
|
sortDirection = 'desc'; |
|
|
|
} |
|
|
|
|
|
|
|
updateSortIcon(); |
|
|
|
refreshLogList(); |
|
|
|
} |
|
|
|
|
|
|
|
// 美化方向 |
|
|
|
function formatDirection(dir) { |
|
|
|
return dir === 0 ? "Uplink" : "Downlink"; |
|
|
|
if (dir === 1) { |
|
|
|
return "UL"; |
|
|
|
} else if (dir === 2) { |
|
|
|
return "DL"; |
|
|
|
} else { |
|
|
|
return "Unknown"; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
function formatDuration(ms) { |
|
|
@ -830,6 +934,9 @@ |
|
|
|
refreshLogList(); |
|
|
|
}); |
|
|
|
|
|
|
|
// 时间戳排序点击事件 |
|
|
|
document.getElementById('timestamp-sort').addEventListener('click', handleTimestampSort); |
|
|
|
|
|
|
|
// 事件委托处理点击事件 |
|
|
|
contentArea.addEventListener('click', function(e) { |
|
|
|
const item = e.target.closest('.log-item'); |
|
|
@ -945,6 +1052,9 @@ |
|
|
|
|
|
|
|
// 初始化Layer过滤器,显示标准LTE层 |
|
|
|
updateLayerFilter(); |
|
|
|
|
|
|
|
// 初始化排序状态 |
|
|
|
updateSortIcon(); |
|
|
|
}); |
|
|
|
</script> |
|
|
|
} |
|
|
|