diff --git a/LTEMvcApp/Views/Home/Logs.cshtml b/LTEMvcApp/Views/Home/Logs.cshtml index 64fb14f..b6fcc85 100644 --- a/LTEMvcApp/Views/Home/Logs.cshtml +++ b/LTEMvcApp/Views/Home/Logs.cshtml @@ -265,21 +265,105 @@ } /* Layer过滤器样式 */ - .layer-filter-dropdown { + .layer-filter-container { + position: relative; margin-left: 8px; - padding: 2px 6px; - font-size: 0.8em; + } + + .layer-filter-trigger { + padding: 4px 8px; border: 1px solid #ced4da; border-radius: 3px; background-color: #fff; cursor: pointer; + display: flex; + align-items: center; + gap: 4px; min-width: 80px; + font-size: 0.8em; } - .layer-filter-dropdown:focus { - outline: none; + .layer-filter-trigger:hover { border-color: #007bff; - box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25); + } + + .filter-text { + font-size: 0.8em; + } + + .filter-arrow { + font-size: 0.8em; + transition: transform 0.2s; + } + + .layer-filter-container.open .filter-arrow { + transform: rotate(180deg); + } + + .layer-filter-dropdown { + position: absolute; + top: 100%; + left: 0; + width: 150px; + background-color: #fff; + border: 1px solid #ced4da; + border-radius: 3px; + max-height: 200px; + overflow-y: auto; + z-index: 1000; + display: none; + box-shadow: 0 2px 8px rgba(0,0,0,0.1); + } + + .layer-filter-container.open .layer-filter-dropdown { + display: block; + } + + .filter-header { + padding: 8px 10px; + background-color: #f8f9fa; + border-bottom: 1px solid #dee2e6; + } + + .select-all-label { + display: flex; + align-items: center; + gap: 4px; + font-size: 0.8em; + cursor: pointer; + } + + .select-all-label input { + margin: 0; + } + + .filter-options { + padding: 8px 10px; + } + + .filter-option { + margin-bottom: 6px; + } + + .filter-option:last-child { + margin-bottom: 0; + } + + .filter-option label { + display: flex; + align-items: center; + gap: 4px; + font-size: 0.8em; + cursor: pointer; + padding: 2px 0; + } + + .filter-option label:hover { + background-color: #f8f9fa; + } + + .filter-option input { + margin: 0; } .log-layer { @@ -299,9 +383,22 @@ Timestamp Layer - +
+
+ 全部 + +
+
+
+ +
+
+ +
+
+
Direction Message @@ -362,10 +459,15 @@ const reconnectBtn = document.getElementById('reconnect-btn'); const logListPanel = document.querySelector('.log-list-panel'); const resizer = document.getElementById('drag-resizer'); - const layerFilter = document.getElementById('layer-filter'); + const layerFilter = document.getElementById('layer-filter-dropdown'); + const layerFilterTrigger = document.getElementById('layer-filter-trigger'); + const layerFilterOptions = document.getElementById('layer-filter-options'); + const selectAllLayers = document.getElementById('select-all-layers'); + const filterText = document.querySelector('.filter-text'); let allLogsData = []; - let availableLayers = new Set(); // 用于跟踪可用的日志层 + let availableLayers = new Set(['PHY', 'MAC', 'RLC', 'PDCP', 'RRC', 'NAS']); // 初始化标准LTE层 + let selectedLayers = new Set(); // 用于跟踪选中的日志层 let eventSource = null; let reconnectAttempts = 0; const maxReconnectAttempts = 5; @@ -381,29 +483,86 @@ no_data_text: "正在等待日志..." }); + // 更新过滤器显示文本 + function updateFilterText() { + if (selectedLayers.size === 0) { + filterText.textContent = '全部'; + } else if (selectedLayers.size === availableLayers.size) { + filterText.textContent = '全部'; + } else if (selectedLayers.size === 1) { + filterText.textContent = Array.from(selectedLayers)[0]; + } else { + filterText.textContent = `${selectedLayers.size}个层`; + } + } + + // 更新全选复选框状态 + function updateSelectAllState() { + if (availableLayers.size === 0) { + selectAllLayers.checked = false; + selectAllLayers.indeterminate = false; + } else if (selectedLayers.size === 0) { + selectAllLayers.checked = false; + selectAllLayers.indeterminate = false; + } else if (selectedLayers.size === availableLayers.size) { + selectAllLayers.checked = true; + selectAllLayers.indeterminate = false; + } else { + selectAllLayers.checked = false; + selectAllLayers.indeterminate = true; + } + } + // 更新Layer过滤器选项 function updateLayerFilter() { - const currentValue = layerFilter.value; - const options = ['']; + const options = []; // 按字母顺序排序 const sortedLayers = Array.from(availableLayers).sort(); sortedLayers.forEach(layer => { - const selected = layer === currentValue ? ' selected' : ''; - options.push(``); + const isChecked = selectedLayers.has(layer) ? ' checked' : ''; + options.push(`
+ +
`); }); - layerFilter.innerHTML = options.join(''); + layerFilterOptions.innerHTML = options.join(''); + + // 重新绑定事件 + bindFilterEvents(); + + // 更新显示文本和全选状态 + updateFilterText(); + updateSelectAllState(); + } + + // 绑定过滤器事件 + function bindFilterEvents() { + // 绑定单个复选框事件 + layerFilterOptions.querySelectorAll('input[type="checkbox"]').forEach(checkbox => { + checkbox.addEventListener('change', function() { + if (this.checked) { + selectedLayers.add(this.value); + } else { + selectedLayers.delete(this.value); + } + updateFilterText(); + updateSelectAllState(); + refreshLogList(); + }); + }); } // 根据当前过滤器重新渲染日志列表 function refreshLogList() { - const selectedLayer = layerFilter.value; let filteredLogs = allLogsData; - if (selectedLayer) { - filteredLogs = allLogsData.filter(log => log.Layer === selectedLayer); + if (selectedLayers.size > 0 && selectedLayers.size < availableLayers.size) { + filteredLogs = allLogsData.filter(log => selectedLayers.has(log.Layer)); } const rows = filteredLogs.map((log, i) => formatLogItem(log, i)); @@ -442,6 +601,7 @@ function clearLogsDisplay() { allLogsData = []; availableLayers.clear(); + selectedLayers.clear(); clusterize.clear(); totalLogsEl.textContent = '0'; newLogsCountEl.textContent = ''; @@ -668,11 +828,51 @@ }; } - // Layer过滤器变化事件 - layerFilter.addEventListener('change', function() { + // 切换下拉框显示状态 + function toggleFilterDropdown() { + const container = layerFilterTrigger.parentElement; + container.classList.toggle('open'); + } + + // 关闭下拉框 + function closeFilterDropdown() { + const container = layerFilterTrigger.parentElement; + container.classList.remove('open'); + } + + // 事件监听器 + layerFilterTrigger.addEventListener('click', function(e) { + e.stopPropagation(); + toggleFilterDropdown(); + }); + + // 全选/取消全选 + selectAllLayers.addEventListener('change', function() { + const isChecked = selectAllLayers.checked; + if (isChecked) { + // 全选 + selectedLayers.clear(); + availableLayers.forEach(layer => selectedLayers.add(layer)); + } else { + // 取消全选 + selectedLayers.clear(); + } + updateLayerFilter(); refreshLogList(); }); + // 点击外部关闭下拉框 + document.addEventListener('click', function(e) { + if (!layerFilterTrigger.contains(e.target) && !layerFilter.contains(e.target)) { + closeFilterDropdown(); + } + }); + + // 阻止下拉框内部点击事件冒泡 + layerFilter.addEventListener('click', function(e) { + e.stopPropagation(); + }); + // 事件委托处理点击事件 contentArea.addEventListener('click', function(e) { const item = e.target.closest('.log-item'); @@ -785,6 +985,9 @@ // 初始化连接 connectSSE(); + + // 初始化Layer过滤器,显示标准LTE层 + updateLayerFilter(); }); }