// channel-enhancements.js - 频道搜索、面包屑、快捷键增强功能(终极修复版) (function() { if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } function init() { addStyles(); createSearchBox(); createBreadcrumb(); createShortcutHint(); initShortcuts(); bindCardClicks(); // ★ 新增:为卡片绑定点击切换模块 window.addEventListener('hashchange', updateBreadcrumb); updateBreadcrumb(); } function addStyles() { const style = document.createElement('style'); style.textContent = ` .channel-search-container { padding: 16px 20px; background: #f8f9fa; border-bottom: 1px solid #e9ecef; display: flex; align-items: center; gap: 10px; } .channel-search-input { flex: 1; padding: 10px 16px; border: 1px solid #ced4da; border-radius: 24px; font-size: 14px; outline: none; transition: border-color 0.2s; } .channel-search-input:focus { border-color: #4d6bfe; box-shadow: 0 0 0 3px rgba(77,107,254,0.1); } .channel-search-clear { background: none; border: none; font-size: 18px; cursor: pointer; color: #6c757d; padding: 0 8px; display: none; } .channel-search-clear:hover { color: #212529; } .channel-search-input:not(:placeholder-shown) + .channel-search-clear { display: inline-block; } .highlight { background-color: #ffeb3b; padding: 2px 0; border-radius: 2px; } .no-results { text-align: center; padding: 40px; color: #6c757d; font-style: italic; } .channel-breadcrumb { padding: 12px 20px; background: white; border-bottom: 1px solid #e9ecef; font-size: 14px; } .channel-breadcrumb a { color: #4d6bfe; text-decoration: none; } .channel-breadcrumb a:hover { text-decoration: underline; } .channel-breadcrumb span { color: #6c757d; } .channel-breadcrumb .current { color: #212529; font-weight: 500; } .shortcut-hint { position: fixed; bottom: 20px; right: 20px; background: rgba(0,0,0,0.7); color: white; padding: 8px 16px; border-radius: 30px; font-size: 12px; backdrop-filter: blur(4px); z-index: 1000; } .shortcut-hint kbd { background: rgba(255,255,255,0.2); padding: 2px 6px; border-radius: 4px; margin: 0 2px; } .module-card.selected { outline: 2px solid #4d6bfe; outline-offset: 2px; transform: scale(1.02); transition: all 0.2s; } `; document.head.appendChild(style); } function createSearchBox() { const container = document.querySelector('.module-grid') || document.querySelector('#module-list') || document.querySelector('.channel-content'); if (!container) return; const searchContainer = document.createElement('div'); searchContainer.className = 'channel-search-container'; searchContainer.innerHTML = ` `; container.parentNode.insertBefore(searchContainer, container); const searchInput = searchContainer.querySelector('.channel-search-input'); const clearBtn = searchContainer.querySelector('.channel-search-clear'); searchInput.addEventListener('input', function() { filterModules(this.value); }); clearBtn.addEventListener('click', function() { searchInput.value = ''; filterModules(''); searchInput.focus(); }); window.__channelSearchInput = searchInput; } function filterModules(keyword) { const cards = document.querySelectorAll('.module-card'); const container = document.querySelector('.module-grid') || document.querySelector('#module-list'); let hasResults = false; // 移除所有高亮 removeAllHighlights(); cards.forEach(card => { const text = card.innerText || card.textContent; if (keyword === '') { card.style.display = ''; hasResults = true; } else { const lowerText = text.toLowerCase(); const lowerKeyword = keyword.toLowerCase(); if (lowerText.includes(lowerKeyword)) { card.style.display = ''; highlightText(card, keyword); hasResults = true; } else { card.style.display = 'none'; } } }); let noResultsEl = document.querySelector('.no-results'); if (!hasResults && keyword !== '') { if (!noResultsEl) { noResultsEl = document.createElement('div'); noResultsEl.className = 'no-results'; noResultsEl.textContent = '没有找到匹配的模块'; container.parentNode.insertBefore(noResultsEl, container.nextSibling); } } else { if (noResultsEl) noResultsEl.remove(); } } function removeAllHighlights() { document.querySelectorAll('.highlight').forEach(span => { const parent = span.parentNode; parent.replaceChild(document.createTextNode(span.textContent), span); parent.normalize(); }); } function highlightText(card, keyword) { const regex = new RegExp(`(${keyword})`, 'gi'); const walk = document.createTreeWalker(card, NodeFilter.SHOW_TEXT, { acceptNode: function(node) { if (node.parentNode.classList && node.parentNode.classList.contains('highlight')) { return NodeFilter.FILTER_REJECT; } return NodeFilter.FILTER_ACCEPT; } }, false); const textNodes = []; while (walk.nextNode()) textNodes.push(walk.currentNode); textNodes.forEach(node => { const text = node.nodeValue; if (regex.test(text)) { const span = document.createElement('span'); span.className = 'highlight'; span.innerHTML = text.replace(regex, '$1'); node.parentNode.replaceChild(span, node); } }); } function createBreadcrumb() { const searchContainer = document.querySelector('.channel-search-container'); const breadcrumb = document.createElement('div'); breadcrumb.className = 'channel-breadcrumb'; breadcrumb.id = 'channelBreadcrumb'; if (searchContainer) { searchContainer.parentNode.insertBefore(breadcrumb, searchContainer.nextSibling); } else { const container = document.querySelector('.module-grid') || document.querySelector('#module-list'); if (container) { container.parentNode.insertBefore(breadcrumb, container); } } } function updateBreadcrumb() { const breadcrumb = document.getElementById('channelBreadcrumb'); if (!breadcrumb) return; const hash = window.location.hash.slice(1) || ''; let moduleName = '频道'; if (hash.startsWith('module-')) { const moduleId = hash.replace('module-', ''); const moduleNames = { 'M06': '工单管理', 'M08': '数据看板', 'M11': '组件库', 'debug': '调试面板' }; moduleName = moduleNames[moduleId] || moduleId; } breadcrumb.innerHTML = ` 首页 > 频道 > ${moduleName} `; } function createShortcutHint() { const hint = document.createElement('div'); hint.className = 'shortcut-hint'; hint.innerHTML = ` ⌘K 搜索 · 选择 · Enter 打开 · Esc 关闭 `; document.body.appendChild(hint); } function initShortcuts() { document.addEventListener('keydown', function(e) { if ((e.ctrlKey || e.metaKey) && e.key === 'k') { e.preventDefault(); const searchInput = window.__channelSearchInput; if (searchInput) searchInput.focus(); } if (e.key === 'Escape') { const searchInput = window.__channelSearchInput; if (searchInput && document.activeElement === searchInput) { searchInput.value = ''; filterModules(''); searchInput.blur(); } else if (searchInput && searchInput.value) { searchInput.value = ''; filterModules(''); } } if (e.key === 'ArrowDown' || e.key === 'ArrowUp') { const cards = Array.from(document.querySelectorAll('.module-card:not([style*="display: none"])')); if (cards.length === 0) return; e.preventDefault(); let selectedIndex = cards.findIndex(card => card.classList.contains('selected')); if (selectedIndex === -1) { selectedIndex = e.key === 'ArrowDown' ? 0 : cards.length - 1; } else { cards[selectedIndex].classList.remove('selected'); if (e.key === 'ArrowDown') { selectedIndex = (selectedIndex + 1) % cards.length; } else { selectedIndex = (selectedIndex - 1 + cards.length) % cards.length; } } cards[selectedIndex].classList.add('selected'); cards[selectedIndex].scrollIntoView({ block: 'nearest' }); } if (e.key === 'Enter') { const selected = document.querySelector('.module-card.selected'); if (selected) { selected.click(); // 触发我们绑定的点击事件 } } }); } // ★★★ 核心修复:为所有卡片绑定点击切换模块 ★★★ function bindCardClicks() { const grid = document.querySelector('.module-grid') || document.querySelector('#module-list') || document.body; grid.addEventListener('click', function(e) { const card = e.target.closest('.module-card'); if (!card) return; // 阻止可能冲突的其他事件(可选) e.preventDefault(); // 根据卡片文字判断是哪个模块 const text = card.innerText || card.textContent; let moduleId = null; if (text.includes('工单管理')) moduleId = 'M06'; else if (text.includes('数据统计')) moduleId = 'M08'; else if (text.includes('组件库')) moduleId = 'M11'; else if (text.includes('调试面板')) moduleId = 'debug'; // 如果识别不到,尝试从其他属性获取(比如 data-module-id) else if (card.dataset.moduleId) moduleId = card.dataset.moduleId; if (moduleId) { // 改变 hash,触发路由更新 window.location.hash = `module-${moduleId}`; } }); } })();