// 屏蔽规则管理模块 // 全局变量 let rules = []; let currentPage = 1; let itemsPerPage = 50; // 默认每页显示50条规则 let filteredRules = []; // 初始化屏蔽规则面板 function initRulesPanel() { // 加载规则列表 loadRules(); // 绑定添加规则按钮事件 document.getElementById('add-rule-btn').addEventListener('click', addNewRule); // 绑定刷新规则按钮事件 document.getElementById('reload-rules-btn').addEventListener('click', reloadRules); // 绑定搜索框事件 document.getElementById('rule-search').addEventListener('input', filterRules); // 绑定每页显示数量变更事件 document.getElementById('items-per-page').addEventListener('change', () => { itemsPerPage = parseInt(document.getElementById('items-per-page').value); currentPage = 1; // 重置为第一页 renderRulesList(); }); // 绑定分页按钮事件 document.getElementById('prev-page-btn').addEventListener('click', goToPreviousPage); document.getElementById('next-page-btn').addEventListener('click', goToNextPage); document.getElementById('first-page-btn').addEventListener('click', goToFirstPage); document.getElementById('last-page-btn').addEventListener('click', goToLastPage); } // 加载规则列表 async function loadRules() { try { const rulesPanel = document.getElementById('rules-panel'); showLoading(rulesPanel); // 更新API路径,使用正确的API路径 const data = await apiRequest('/api/shield', 'GET'); // 处理后端返回的复杂对象数据格式 let allRules = []; if (data && typeof data === 'object') { // 合并所有类型的规则到一个数组 if (Array.isArray(data.domainRules)) allRules = allRules.concat(data.domainRules); if (Array.isArray(data.domainExceptions)) allRules = allRules.concat(data.domainExceptions); if (Array.isArray(data.regexRules)) allRules = allRules.concat(data.regexRules); if (Array.isArray(data.regexExceptions)) allRules = allRules.concat(data.regexExceptions); } rules = allRules; filteredRules = [...rules]; currentPage = 1; // 重置为第一页 renderRulesList(); // 更新规则数量统计卡片 if (window.updateRulesCount && typeof window.updateRulesCount === 'function') { window.updateRulesCount(rules.length); } } catch (error) { console.error('加载规则失败:', error); if (typeof window.showNotification === 'function') { window.showNotification('加载规则失败', 'danger'); } } finally { const rulesPanel = document.getElementById('rules-panel'); hideLoading(rulesPanel); } } // 渲染规则列表 function renderRulesList() { const rulesList = document.getElementById('rules-list'); const paginationInfo = document.getElementById('pagination-info'); // 清空列表 rulesList.innerHTML = ''; if (filteredRules.length === 0) { // 使用更友好的空状态显示 rulesList.innerHTML = '' + '
' + '
' + '
暂无规则
' + '
点击添加按钮或刷新规则来获取规则列表
' + '
' + ''; paginationInfo.textContent = '共0条规则'; updatePaginationButtons(); return; } // 计算分页数据 const totalPages = Math.ceil(filteredRules.length / itemsPerPage); const startIndex = (currentPage - 1) * itemsPerPage; const endIndex = Math.min(startIndex + itemsPerPage, filteredRules.length); const currentRules = filteredRules.slice(startIndex, endIndex); // 渲染当前页的规则 currentRules.forEach((rule, index) => { const row = document.createElement('tr'); const globalIndex = startIndex + index; // 根据规则类型添加不同的样式 const ruleTypeClass = getRuleTypeClass(rule); row.innerHTML = ` ${globalIndex + 1}
${escapeHtml(rule)}
`; // 添加行动画效果 row.style.opacity = '0'; row.style.transform = 'translateY(10px)'; rulesList.appendChild(row); // 使用requestAnimationFrame确保动画平滑 requestAnimationFrame(() => { row.style.transition = 'opacity 0.3s ease, transform 0.3s ease'; row.style.opacity = '1'; row.style.transform = 'translateY(0)'; }); }); // 绑定删除按钮事件 document.querySelectorAll('.delete-rule').forEach(button => { button.addEventListener('click', (e) => { const index = parseInt(e.currentTarget.dataset.index); deleteRule(index); }); }); // 更新分页信息 paginationInfo.textContent = `显示 ${startIndex + 1}-${endIndex} 条,共 ${filteredRules.length} 条规则,第 ${currentPage}/${totalPages} 页`; // 更新分页按钮状态 updatePaginationButtons(); } // 更新分页按钮状态 function updatePaginationButtons() { const totalPages = Math.ceil(filteredRules.length / itemsPerPage); const prevBtn = document.getElementById('prev-page-btn'); const nextBtn = document.getElementById('next-page-btn'); const firstBtn = document.getElementById('first-page-btn'); const lastBtn = document.getElementById('last-page-btn'); prevBtn.disabled = currentPage === 1; nextBtn.disabled = currentPage === totalPages || totalPages === 0; firstBtn.disabled = currentPage === 1; lastBtn.disabled = currentPage === totalPages || totalPages === 0; } // 上一页 function goToPreviousPage() { if (currentPage > 1) { currentPage--; renderRulesList(); } } // 下一页 function goToNextPage() { const totalPages = Math.ceil(filteredRules.length / itemsPerPage); if (currentPage < totalPages) { currentPage++; renderRulesList(); } } // 第一页 function goToFirstPage() { currentPage = 1; renderRulesList(); } // 最后一页 function goToLastPage() { currentPage = Math.ceil(filteredRules.length / itemsPerPage); renderRulesList(); } // 添加新规则 async function addNewRule() { const ruleInput = document.getElementById('rule-input'); const rule = ruleInput.value.trim(); if (!rule) { if (typeof window.showNotification === 'function') { window.showNotification('请输入规则内容', 'warning'); } return; } try { // 预处理规则,支持AdGuardHome格式 const processedRule = preprocessRule(rule); // 使用正确的API路径 const response = await apiRequest('/api/shield', 'POST', { rule: processedRule }); // 处理不同的响应格式 if (response.success || response.status === 'success') { rules.push(processedRule); filteredRules = [...rules]; ruleInput.value = ''; // 添加后跳转到最后一页,显示新添加的规则 currentPage = Math.ceil(filteredRules.length / itemsPerPage); renderRulesList(); // 更新规则数量统计 if (window.updateRulesCount && typeof window.updateRulesCount === 'function') { window.updateRulesCount(rules.length); } if (typeof window.showNotification === 'function') { window.showNotification('规则添加成功', 'success'); } } else { if (typeof window.showNotification === 'function') { window.showNotification('规则添加失败:' + (response.message || '未知错误'), 'danger'); } } } catch (error) { console.error('添加规则失败:', error); if (typeof window.showNotification === 'function') { window.showNotification('添加规则失败', 'danger'); } } } // 删除规则 async function deleteRule(index) { if (!confirm('确定要删除这条规则吗?')) { return; } try { const rule = filteredRules[index]; const rowElement = document.querySelectorAll('#rules-list tr')[index]; // 添加删除动画 if (rowElement) { rowElement.style.transition = 'opacity 0.3s ease, transform 0.3s ease'; rowElement.style.opacity = '0'; rowElement.style.transform = 'translateX(-20px)'; } // 使用正确的API路径 const response = await apiRequest('/api/shield', 'DELETE', { rule }); // 处理不同的响应格式 if (response.success || response.status === 'success') { // 在原规则列表中找到并删除 const originalIndex = rules.indexOf(rule); if (originalIndex !== -1) { rules.splice(originalIndex, 1); } // 在过滤后的列表中删除 filteredRules.splice(index, 1); // 如果当前页没有数据了,回到上一页 const totalPages = Math.ceil(filteredRules.length / itemsPerPage); if (currentPage > totalPages && totalPages > 0) { currentPage = totalPages; } // 等待动画完成后重新渲染列表 setTimeout(() => { renderRulesList(); // 更新规则数量统计 if (window.updateRulesCount && typeof window.updateRulesCount === 'function') { window.updateRulesCount(rules.length); } if (typeof window.showNotification === 'function') { window.showNotification('规则删除成功', 'success'); } }, 300); } else { // 恢复行样式 if (rowElement) { rowElement.style.opacity = '1'; rowElement.style.transform = 'translateX(0)'; } if (typeof window.showNotification === 'function') { window.showNotification('规则删除失败:' + (response.message || '未知错误'), 'danger'); } } } catch (error) { console.error('删除规则失败:', error); if (typeof window.showNotification === 'function') { window.showNotification('删除规则失败', 'danger'); } } } // 重新加载规则 async function reloadRules() { if (!confirm('确定要重新加载所有规则吗?这将覆盖当前内存中的规则。')) { return; } try { const rulesPanel = document.getElementById('rules-panel'); showLoading(rulesPanel); // 使用正确的API路径和方法 - PUT请求到/api/shield await apiRequest('/api/shield', 'PUT'); // 重新加载规则列表 await loadRules(); // 触发数据刷新事件,通知其他模块数据已更新 if (typeof window.triggerDataRefresh === 'function') { window.triggerDataRefresh('rules'); } if (typeof window.showNotification === 'function') { window.showNotification('规则重新加载成功', 'success'); } } catch (error) { console.error('重新加载规则失败:', error); if (typeof window.showNotification === 'function') { window.showNotification('重新加载规则失败', 'danger'); } } finally { const rulesPanel = document.getElementById('rules-panel'); hideLoading(rulesPanel); } } // 过滤规则 function filterRules() { const searchTerm = document.getElementById('rule-search').value.toLowerCase(); if (searchTerm) { filteredRules = rules.filter(rule => rule.toLowerCase().includes(searchTerm)); } else { filteredRules = [...rules]; } currentPage = 1; // 重置为第一页 renderRulesList(); } // HTML转义,防止XSS攻击 function escapeHtml(text) { const map = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }; return text.replace(/[&<>'"]/g, m => map[m]); } // 根据规则类型返回对应的CSS类名 function getRuleTypeClass(rule) { // 简单的规则类型判断 if (rule.startsWith('||') || rule.startsWith('|http')) { return 'rule-type-url'; } else if (rule.startsWith('@@')) { return 'rule-type-exception'; } else if (rule.startsWith('#')) { return 'rule-type-comment'; } else if (rule.includes('$')) { return 'rule-type-filter'; } return 'rule-type-standard'; } // 预处理规则,支持多种规则格式 function preprocessRule(rule) { // 移除首尾空白字符 let processed = rule.trim(); // 处理AdGuardHome格式的规则 if (processed.startsWith('0.0.0.0 ') || processed.startsWith('127.0.0.1 ')) { const parts = processed.split(' '); if (parts.length >= 2) { // 转换为AdBlock Plus格式 processed = '||' + parts[1] + '^'; } } return processed; } // 导出函数,供其他模块调用 window.updateRulesCount = function(count) { const rulesCountElement = document.getElementById('rules-count'); if (rulesCountElement) { rulesCountElement.textContent = count; } } // 导出初始化函数 window.initRulesPanel = initRulesPanel; // 注册到面板导航系统 if (window.registerPanelModule) { window.registerPanelModule('rules-panel', { init: initRulesPanel, refresh: loadRules }); }