270 lines
7.7 KiB
JavaScript
270 lines
7.7 KiB
JavaScript
// 屏蔽规则管理模块
|
||
|
||
// 全局变量
|
||
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);
|
||
|
||
const data = await apiRequest('/shield', 'GET');
|
||
rules = data.rules || [];
|
||
filteredRules = [...rules];
|
||
currentPage = 1; // 重置为第一页
|
||
renderRulesList();
|
||
} catch (error) {
|
||
showError('加载规则失败:' + error.message);
|
||
} 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 = '<tr><td colspan="4" class="text-center">暂无规则</td></tr>';
|
||
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;
|
||
|
||
row.innerHTML = `
|
||
<td class="rule-id">${globalIndex + 1}</td>
|
||
<td class="rule-content"><pre>${escapeHtml(rule)}</pre></td>
|
||
<td class="rule-actions">
|
||
<button class="btn btn-danger btn-sm delete-rule" data-index="${globalIndex}">
|
||
<i class="fas fa-trash"></i> 删除
|
||
</button>
|
||
</td>
|
||
`;
|
||
|
||
rulesList.appendChild(row);
|
||
});
|
||
|
||
// 绑定删除按钮事件
|
||
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) {
|
||
showNotification('请输入规则内容', 'warning');
|
||
return;
|
||
}
|
||
|
||
try {
|
||
const response = await apiRequest('/shield/rule', 'POST', { rule });
|
||
|
||
if (response.success) {
|
||
rules.push(rule);
|
||
filteredRules = [...rules];
|
||
ruleInput.value = '';
|
||
|
||
// 添加后跳转到最后一页,显示新添加的规则
|
||
currentPage = Math.ceil(filteredRules.length / itemsPerPage);
|
||
renderRulesList();
|
||
|
||
showNotification('规则添加成功', 'success');
|
||
} else {
|
||
showNotification('规则添加失败:' + (response.message || '未知错误'), 'error');
|
||
}
|
||
} catch (error) {
|
||
showError('添加规则失败:' + error.message);
|
||
}
|
||
}
|
||
|
||
// 删除规则
|
||
async function deleteRule(index) {
|
||
if (!confirm('确定要删除这条规则吗?')) {
|
||
return;
|
||
}
|
||
|
||
try {
|
||
const rule = filteredRules[index];
|
||
const response = await apiRequest('/shield/rule', 'DELETE', { rule });
|
||
|
||
if (response.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;
|
||
}
|
||
|
||
renderRulesList();
|
||
showNotification('规则删除成功', 'success');
|
||
} else {
|
||
showNotification('规则删除失败:' + (response.message || '未知错误'), 'error');
|
||
}
|
||
} catch (error) {
|
||
showError('删除规则失败:' + error.message);
|
||
}
|
||
}
|
||
|
||
// 重新加载规则
|
||
async function reloadRules() {
|
||
if (!confirm('确定要重新加载所有规则吗?这将覆盖当前内存中的规则。')) {
|
||
return;
|
||
}
|
||
|
||
try {
|
||
const rulesPanel = document.getElementById('rules-panel');
|
||
showLoading(rulesPanel);
|
||
|
||
await apiRequest('/shield/reload', 'POST');
|
||
|
||
// 重新加载规则列表
|
||
await loadRules();
|
||
showNotification('规则重新加载成功', 'success');
|
||
} catch (error) {
|
||
showError('重新加载规则失败:' + error.message);
|
||
} 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]);
|
||
}
|
||
|
||
// 导出初始化函数
|
||
window.initRulesPanel = initRulesPanel; |