From 070044f131e4561646015f8781652a3133214125 Mon Sep 17 00:00:00 2001 From: hz4th_coder Date: Mon, 24 Aug 2026 15:09:21 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E9=A1=B9=E7=9B=AE=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E6=96=B0=E5=A2=9E=E6=90=9C=E7=B4=A2/?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E7=AD=9B=E9=80=89/=E7=AB=AF=E5=8F=A3?= =?UTF-8?q?=E6=8E=92=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增关键字搜索框:按服务名称/描述/id/端口实时过滤 - 新增状态筛选按钮:全部状态/在线中(running|partial)/有后台(admin_url) - 新增端口排序按钮:点击三态切换 无排序→升序→降序 - 筛选栏分组 + 分隔线,样式与现有主题一致 --- templates_full.txt | 84 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 81 insertions(+), 3 deletions(-) diff --git a/templates_full.txt b/templates_full.txt index ad81287..b72af3e 100644 --- a/templates_full.txt +++ b/templates_full.txt @@ -28,6 +28,12 @@ .nav-btn i { font-size: 20px; color: #94a3b8; } .nav-btn:hover i { color: #f1f5f9; } .filter-bar { position: sticky; top: 0; z-index: 50; display: flex; gap: 8px; padding: 12px 0; background: #0f172a; margin-bottom: 16px; flex-wrap: wrap; } + .filter-search { padding: 8px 12px; border-radius: 8px; background: #1e293b; border: 1px solid #334155; color: #f1f5f9; font-size: 14px; outline: none; min-width: 200px; transition: border-color 0.2s; } + .filter-search:focus { border-color: #3b82f6; } + .filter-search::placeholder { color: #64748b; } + .filter-divider { width: 1px; height: 24px; background: #334155; margin: 0 4px; } + .filter-bar-btn[data-status].active { background: #8b5cf6; border-color: #8b5cf6; } + .filter-bar-btn.sort-active { background: #0ea5e9; border-color: #0ea5e9; color: #fff; } .filter-bar-btn { display: flex; align-items: center; gap: 6px; padding: 8px 16px; border-radius: 8px; background: #1e293b; border: 1px solid #334155; color: #94a3b8; font-size: 14px; cursor: pointer; transition: all 0.2s; } .filter-bar-btn:hover { background: #334155; color: #f1f5f9; } .filter-bar-btn.active { background: #3b82f6; border-color: #3b82f6; color: #fff; } @@ -171,11 +177,18 @@
+ + + + + + +
@@ -1001,6 +1014,9 @@ let cronTasks = []; let currentTab = 'projects'; let currentFilter = 'all'; + let searchKeyword = ''; + let statusFilter = ''; // '' = all, 'online' = running/partial, 'admin' = has admin_url + let portSort = ''; // '' = none, 'asc', 'desc' let externalIp = localStorage.getItem('externalIp') || '192.168.2.17'; let enableLogs = localStorage.getItem('enableLogs') === 'true'; @@ -1526,11 +1542,40 @@ function filterType(type) { currentFilter = type; document.querySelectorAll('.filter-bar-btn').forEach(btn => { - btn.classList.toggle('active', btn.dataset.type === type); + if (btn.dataset.type !== undefined) { + btn.classList.toggle('active', btn.dataset.type === type); + } }); renderProjects(); } + function setSearch(val) { + searchKeyword = (val || '').trim().toLowerCase(); + renderProjects(); + } + + function setStatusFilter(status) { + statusFilter = status; + document.querySelectorAll('.filter-bar-btn[data-status]').forEach(btn => { + btn.classList.toggle('active', btn.dataset.status === status); + }); + renderProjects(); + } + + function togglePortSort() { + if (!portSort) portSort = 'asc'; + else if (portSort === 'asc') portSort = 'desc'; + else portSort = ''; + const btn = document.getElementById('portSortBtn'); + btn.classList.toggle('sort-active', !!portSort); + const icon = btn.querySelector('i'); + const label = btn.querySelector('span'); + if (portSort === 'asc') { icon.className = 'ri-sort-asc'; label.textContent = '端口↑'; } + else if (portSort === 'desc') { icon.className = 'ri-sort-desc'; label.textContent = '端口↓'; } + else { icon.className = 'ri-sort-asc'; label.textContent = '端口排序'; } + renderProjects(); + } + function renderProjects() { const list = document.getElementById('projectsList'); @@ -1538,10 +1583,43 @@ const customServices = getCustomServices(); const allProjects = [...projects, ...customServices]; - const filtered = currentFilter === 'all' ? allProjects : allProjects.filter(p => p.type === currentFilter || (currentFilter === 'web' && p.isCustom)); + let filtered = currentFilter === 'all' ? allProjects : allProjects.filter(p => p.type === currentFilter || (currentFilter === 'web' && p.isCustom)); + + // 关键字搜索:名称/描述/id/端口 + if (searchKeyword) { + filtered = filtered.filter(p => { + const haystack = [ + p.name || '', + p.description || '', + p.id || '', + ...(p.ports || []), + p.url || '' + ].join(' ').toLowerCase(); + return haystack.includes(searchKeyword); + }); + } + + // 状态筛选:在线中(running/partial)/ 有后台(admin_url) + if (statusFilter === 'online') { + filtered = filtered.filter(p => { + const st = p.status?.status; + return st === 'running' || st === 'partial'; + }); + } else if (statusFilter === 'admin') { + filtered = filtered.filter(p => !!p.admin_url); + } + + // 端口排序:升/降序 + if (portSort) { + filtered = filtered.slice().sort((a, b) => { + const pa = a.ports && a.ports.length ? a.ports[0] : 0; + const pb = b.ports && b.ports.length ? b.ports[0] : 0; + return portSort === 'asc' ? pa - pb : pb - pa; + }); + } if (filtered.length === 0) { - list.innerHTML = '

暂无项目

'; + list.innerHTML = '

暂无匹配项目

'; return; }