远程列表web
This commit is contained in:
@@ -478,6 +478,45 @@
|
||||
font-size: 0.875rem;
|
||||
border-radius: var(--border-radius-sm);
|
||||
}
|
||||
|
||||
.btn-edit {
|
||||
background-color: var(--info-color);
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.btn-edit:hover {
|
||||
background-color: #2980b9;
|
||||
}
|
||||
|
||||
.checkbox-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.checkbox-label input[type="checkbox"] {
|
||||
cursor: pointer;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.list-meta {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
font-size: 0.75rem;
|
||||
color: var(--gray-500);
|
||||
}
|
||||
|
||||
.list-meta span {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
text-align: center;
|
||||
@@ -816,33 +855,36 @@
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title"><i class="fas fa-globe"></i> 远程规则管理</h3>
|
||||
<h3 class="card-title"><i class="fas fa-ban"></i> 黑名单管理</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="mb-3">
|
||||
<label for="update-interval" class="form-label">更新间隔 (秒)</label>
|
||||
<input type="number" id="update-interval" min="60" max="86400" placeholder="3600">
|
||||
<small class="form-text">远程规则自动更新的时间间隔,建议至少60秒</small>
|
||||
<small class="form-text">黑名单自动更新的时间间隔,建议至少60秒</small>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<div class="input-group">
|
||||
<input type="text" id="remote-rule-url" placeholder="输入远程规则URL">
|
||||
<button id="add-remote-rule" class="btn-secondary">
|
||||
<i class="fas fa-plus"></i> 添加规则
|
||||
<h4>添加新黑名单</h4>
|
||||
<div style="display: flex; gap: 0.5rem; flex-wrap: wrap;">
|
||||
<input type="text" id="blacklist-name" placeholder="黑名单名称">
|
||||
<input type="text" id="blacklist-url" placeholder="黑名单URL">
|
||||
<button id="add-blacklist" class="btn-secondary">
|
||||
<i class="fas fa-plus"></i> 添加
|
||||
</button>
|
||||
</div>
|
||||
<small class="form-text">添加远程黑名单源,支持HTTP/HTTPS链接</small>
|
||||
</div>
|
||||
|
||||
<div class="list-container" id="remote-rules-list">
|
||||
<div class="list-container" id="blacklists-list">
|
||||
<div class="empty-state">
|
||||
<i class="fas fa-info-circle"></i>
|
||||
<p>加载中...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button id="save-remote-settings" class="btn-primary mt-3">
|
||||
<i class="fas fa-save"></i> 保存远程设置
|
||||
<button id="save-blacklists-settings" class="btn-primary mt-3">
|
||||
<i class="fas fa-save"></i> 保存设置
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1426,7 +1468,7 @@ function loadRules() {
|
||||
typeText = '正则';
|
||||
}
|
||||
|
||||
// 转义规则中的特殊字符,确保在HTML和JavaScript中正确处理
|
||||
// 转义规则中的特殊字符并确保在HTML和JavaScript中正确处理
|
||||
const escapedRule = item.rule.replace(/'/g, "\\'");
|
||||
|
||||
ruleItem.innerHTML = `
|
||||
@@ -1504,7 +1546,19 @@ function loadRules() {
|
||||
},
|
||||
body: JSON.stringify({ rule: fullRule })
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error('保存失败');
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
showNotification('success', '黑名单设置已保存');
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('保存黑名单设置失败:', error);
|
||||
showNotification('danger', '保存失败: ' + error.message);
|
||||
});
|
||||
.then(data => {
|
||||
// 重置按钮状态
|
||||
btn.innerHTML = originalText;
|
||||
@@ -1537,7 +1591,7 @@ function loadRules() {
|
||||
fetch('/api/shield/hosts')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
// 注意:这需要在shieldManager中添加一个获取所有hosts条目的方法
|
||||
// 注意这需要在shieldManager中添加一个获取所有hosts条目的方法
|
||||
// 暂时返回统计信息
|
||||
const hostsCount = data.hostsCount || 0;
|
||||
|
||||
@@ -1766,12 +1820,12 @@ function loadRules() {
|
||||
// 加载当前屏蔽设置
|
||||
loadBlockSettings();
|
||||
|
||||
// 远程规则相关事件监听
|
||||
document.getElementById('add-remote-rule').addEventListener('click', addRemoteRule);
|
||||
document.getElementById('save-remote-settings').addEventListener('click', saveRemoteSettings);
|
||||
// 黑名单相关事件监听
|
||||
document.getElementById('add-blacklist').addEventListener('click', addBlacklist);
|
||||
document.getElementById('save-blacklists-settings').addEventListener('click', saveBlacklistsSettings);
|
||||
|
||||
// 加载远程规则设置
|
||||
loadRemoteSettings();
|
||||
// 加载黑名单设置
|
||||
loadBlacklistsSettings();
|
||||
};
|
||||
|
||||
// 加载当前屏蔽设置
|
||||
@@ -1835,82 +1889,104 @@ function loadRules() {
|
||||
});
|
||||
}
|
||||
|
||||
// 加载远程规则设置
|
||||
function loadRemoteSettings() {
|
||||
fetch('/api/config', {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
})
|
||||
// 加载黑名单设置
|
||||
function loadBlacklistsSettings() {
|
||||
fetch('/api/config')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.shield) {
|
||||
// 设置更新间隔
|
||||
document.getElementById('update-interval').value = data.shield.updateInterval || 3600;
|
||||
|
||||
// 加载远程规则列表
|
||||
renderRemoteRulesList(data.shield.remoteRules || []);
|
||||
// 加载黑名单列表
|
||||
renderBlacklistsList(data.shield.blacklists || []);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('加载远程规则设置失败:', error);
|
||||
showNotification('danger', '加载远程规则设置失败');
|
||||
renderRemoteRulesList([]);
|
||||
console.error('加载黑名单设置失败:', error);
|
||||
showNotification('danger', '加载黑名单设置失败');
|
||||
renderBlacklistsList([]);
|
||||
});
|
||||
}
|
||||
|
||||
// 渲染远程规则列表
|
||||
function renderRemoteRulesList(rules) {
|
||||
const listContainer = document.getElementById('remote-rules-list');
|
||||
// 渲染黑名单列表
|
||||
function renderBlacklistsList(blacklists) {
|
||||
const listContainer = document.getElementById('blacklists-list');
|
||||
|
||||
if (rules.length === 0) {
|
||||
if (!blacklists || blacklists.length === 0) {
|
||||
listContainer.innerHTML = `
|
||||
<div class="empty-state">
|
||||
<i class="fas fa-info-circle"></i>
|
||||
<p>暂无远程规则</p>
|
||||
<p>暂无黑名单</p>
|
||||
</div>
|
||||
`;
|
||||
return;
|
||||
}
|
||||
|
||||
let html = '<div class="list-container">';
|
||||
rules.forEach((rule, index) => {
|
||||
// 确保我们处理的是数组
|
||||
const blacklistItems = Array.isArray(blacklists) ? blacklists : [];
|
||||
|
||||
let html = '';
|
||||
blacklistItems.forEach((item, index) => {
|
||||
html += `
|
||||
<div class="list-item">
|
||||
<div class="list-content">
|
||||
<div class="list-title">远程规则 ${index + 1}</div>
|
||||
<div class="list-description">${rule}</div>
|
||||
<div class="list-title">
|
||||
<label class="checkbox-label">
|
||||
<input type="checkbox" ${item.enabled ? 'checked' : ''} class="blacklist-enabled" data-index="${index}">
|
||||
<span>${item.name || '未命名黑名单'}</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="list-description">${item.URL}</div>
|
||||
<div class="list-meta">
|
||||
<span>${item.ruleCount ? `规则数: ${item.ruleCount}` : '未加载规则'}</span>
|
||||
${item.lastUpdateTime ? `<span>更新时间: ${item.lastUpdateTime}</span>` : ''}
|
||||
</div>
|
||||
</div>
|
||||
<div class="list-actions">
|
||||
<span class="badge badge-primary">远程</span>
|
||||
<button class="btn-danger btn-sm delete-rule" data-index="${index}">
|
||||
<button class="btn-edit btn-sm" data-index="${index}">
|
||||
<i class="fas fa-edit"></i>
|
||||
</button>
|
||||
<button class="btn-danger btn-sm delete-blacklist" data-index="${index}">
|
||||
<i class="fas fa-trash-alt"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
html += '</div>';
|
||||
|
||||
listContainer.innerHTML = html;
|
||||
|
||||
// 添加删除按钮事件监听
|
||||
document.querySelectorAll('.delete-rule').forEach(btn => {
|
||||
// 添加事件监听
|
||||
document.querySelectorAll('.blacklist-enabled').forEach(checkbox => {
|
||||
checkbox.addEventListener('change', function() {
|
||||
const index = parseInt(this.getAttribute('data-index'));
|
||||
toggleBlacklistStatus(index, this.checked);
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelectorAll('.delete-blacklist').forEach(btn => {
|
||||
btn.addEventListener('click', function() {
|
||||
const index = parseInt(this.getAttribute('data-index'));
|
||||
deleteRemoteRule(index);
|
||||
deleteBlacklist(index);
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelectorAll('.btn-edit').forEach(btn => {
|
||||
btn.addEventListener('click', function() {
|
||||
const index = parseInt(this.getAttribute('data-index'));
|
||||
editBlacklist(index);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 添加远程规则
|
||||
function addRemoteRule() {
|
||||
const urlInput = document.getElementById('remote-rule-url');
|
||||
const url = urlInput.value.trim();
|
||||
// 添加黑名单
|
||||
function addBlacklist() {
|
||||
const name = document.getElementById('blacklist-name').value.trim();
|
||||
const url = document.getElementById('blacklist-url').value.trim();
|
||||
|
||||
if (!url) {
|
||||
showNotification('warning', '请输入有效的URL');
|
||||
if (!name || !url) {
|
||||
showNotification('warning', '请输入黑名单名称和URL');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1922,42 +1998,110 @@ function loadRules() {
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取当前列表中的规则
|
||||
const ruleItems = document.querySelectorAll('.list-item');
|
||||
const rules = Array.from(ruleItems).map(item =>
|
||||
item.querySelector('.list-description').textContent
|
||||
);
|
||||
// 获取当前黑名单列表
|
||||
const listItems = document.querySelectorAll('#blacklists-list .list-item');
|
||||
let blacklists = [];
|
||||
|
||||
// 检查是否已存在
|
||||
if (rules.includes(url)) {
|
||||
showNotification('warning', '该规则已存在');
|
||||
listItems.forEach((item, index) => {
|
||||
const enabled = item.querySelector('.blacklist-enabled').checked;
|
||||
const name = item.querySelector('.list-title span').textContent;
|
||||
const url = item.querySelector('.list-description').textContent;
|
||||
blacklists.push({ name, URL: url, enabled });
|
||||
});
|
||||
|
||||
// 检查URL是否已存在
|
||||
if (blacklists.some(item => item.URL === url)) {
|
||||
showNotification('warning', '该URL已存在');
|
||||
return;
|
||||
}
|
||||
|
||||
// 添加新规则
|
||||
rules.push(url);
|
||||
renderRemoteRulesList(rules);
|
||||
urlInput.value = '';
|
||||
// 添加新黑名单
|
||||
blacklists.push({ name, URL: url, enabled: true });
|
||||
renderBlacklistsList(blacklists);
|
||||
|
||||
showNotification('success', '规则已添加');
|
||||
// 清空输入框
|
||||
document.getElementById('blacklist-name').value = '';
|
||||
document.getElementById('blacklist-url').value = '';
|
||||
|
||||
showNotification('success', '黑名单已添加');
|
||||
}
|
||||
|
||||
// 删除远程规则
|
||||
function deleteRemoteRule(index) {
|
||||
const ruleItems = document.querySelectorAll('.list-item');
|
||||
const rules = Array.from(ruleItems).map(item =>
|
||||
item.querySelector('.list-description').textContent
|
||||
);
|
||||
// 编辑黑名单
|
||||
function editBlacklist(index) {
|
||||
const listItems = document.querySelectorAll('#blacklists-list .list-item');
|
||||
const item = listItems[index];
|
||||
|
||||
// 移除指定索引的规则
|
||||
rules.splice(index, 1);
|
||||
renderRemoteRulesList(rules);
|
||||
const currentName = item.querySelector('.list-title span').textContent;
|
||||
const currentUrl = item.querySelector('.list-description').textContent;
|
||||
|
||||
showNotification('success', '规则已删除');
|
||||
const newName = prompt('请输入黑名单名称:', currentName);
|
||||
if (newName === null) return;
|
||||
|
||||
const newUrl = prompt('请输入黑名单URL:', currentUrl);
|
||||
if (newUrl === null) return;
|
||||
|
||||
if (!newName.trim() || !newUrl.trim()) {
|
||||
showNotification('warning', '名称和URL不能为空');
|
||||
return;
|
||||
}
|
||||
|
||||
// URL验证
|
||||
try {
|
||||
new URL(newUrl);
|
||||
} catch (e) {
|
||||
showNotification('warning', '请输入有效的URL格式');
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取所有黑名单
|
||||
let blacklists = [];
|
||||
listItems.forEach((item, idx) => {
|
||||
const enabled = item.querySelector('.blacklist-enabled').checked;
|
||||
let name = item.querySelector('.list-title span').textContent;
|
||||
let url = item.querySelector('.list-description').textContent;
|
||||
|
||||
if (idx === index) {
|
||||
name = newName.trim();
|
||||
url = newUrl.trim();
|
||||
}
|
||||
|
||||
blacklists.push({ name, URL: url, enabled });
|
||||
});
|
||||
|
||||
renderBlacklistsList(blacklists);
|
||||
showNotification('success', '黑名单已更新');
|
||||
}
|
||||
|
||||
// 保存远程规则设置
|
||||
function saveRemoteSettings() {
|
||||
// 切换黑名单状态
|
||||
function toggleBlacklistStatus(index, enabled) {
|
||||
showNotification('info', enabled ? '黑名单已启用' : '黑名单已禁用');
|
||||
}
|
||||
|
||||
// 删除黑名单
|
||||
function deleteBlacklist(index) {
|
||||
if (!confirm('确定要删除这条黑名单吗?')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取所有黑名单
|
||||
const listItems = document.querySelectorAll('#blacklists-list .list-item');
|
||||
let blacklists = [];
|
||||
|
||||
listItems.forEach((item, idx) => {
|
||||
if (idx !== index) {
|
||||
const enabled = item.querySelector('.blacklist-enabled').checked;
|
||||
const name = item.querySelector('.list-title span').textContent;
|
||||
const url = item.querySelector('.list-description').textContent;
|
||||
blacklists.push({ name, URL: url, enabled });
|
||||
}
|
||||
});
|
||||
|
||||
renderBlacklistsList(blacklists);
|
||||
showNotification('success', '黑名单已删除');
|
||||
}
|
||||
|
||||
// 保存黑名单设置
|
||||
function saveBlacklistsSettings() {
|
||||
const updateInterval = parseInt(document.getElementById('update-interval').value);
|
||||
|
||||
// 验证更新间隔
|
||||
@@ -1966,11 +2110,16 @@ function loadRules() {
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取当前列表中的规则
|
||||
const ruleItems = document.querySelectorAll('.list-item');
|
||||
const remoteRules = Array.from(ruleItems).map(item =>
|
||||
item.querySelector('.list-description').textContent
|
||||
);
|
||||
// 获取当前黑名单列表
|
||||
const listItems = document.querySelectorAll('#blacklists-list .list-item');
|
||||
let blacklists = [];
|
||||
|
||||
listItems.forEach(item => {
|
||||
const enabled = item.querySelector('.blacklist-enabled').checked;
|
||||
const name = item.querySelector('.list-title span').textContent;
|
||||
const url = item.querySelector('.list-description').textContent;
|
||||
blacklists.push({ name, URL: url, enabled });
|
||||
});
|
||||
|
||||
fetch('/api/config', {
|
||||
method: 'POST',
|
||||
@@ -1979,7 +2128,7 @@ function loadRules() {
|
||||
},
|
||||
body: JSON.stringify({
|
||||
shield: {
|
||||
remoteRules: remoteRules,
|
||||
blacklists: blacklists,
|
||||
updateInterval: updateInterval
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user