diff --git a/config.json b/config.json index 08f8ad7..a9c3c9c 100644 --- a/config.json +++ b/config.json @@ -36,6 +36,11 @@ "name": "My GitHub Rules", "url": "https://gitea.amazehome.xyz/AMAZEHOME/hosts-and-filters/raw/branch/main/rules/costomize.txt", "enabled": true + }, + { + "name": "China List", + "url": "https://gitea.amazehome.xyz/AMAZEHOME/hosts-and-Filters/raw/branch/main/list/china.txt", + "enabled": true } ], "updateInterval": 3600, diff --git a/dns-server b/dns-server deleted file mode 100755 index 27039ec..0000000 Binary files a/dns-server and /dev/null differ diff --git a/http/server.go b/http/server.go index 63510e4..ad6fdc0 100644 --- a/http/server.go +++ b/http/server.go @@ -731,6 +731,14 @@ func (s *Server) handleShieldBlacklists(w http.ResponseWriter, r *http.Request) blacklists[targetIndex].LastUpdateTime = time.Now().Format(time.RFC3339) // 保存更新后的黑名单列表 s.shieldManager.UpdateBlacklist(blacklists) + // 更新全局配置中的黑名单 + s.globalConfig.Shield.Blacklists = blacklists + // 保存配置到文件 + if err := saveConfigToFile(s.globalConfig, "config.json"); err != nil { + logger.Error("保存配置文件失败", "error", err) + http.Error(w, "保存配置失败", http.StatusInternalServerError) + return + } // 重新加载规则以获取最新的远程规则 s.shieldManager.LoadRules() @@ -753,6 +761,14 @@ func (s *Server) handleShieldBlacklists(w http.ResponseWriter, r *http.Request) } s.shieldManager.UpdateBlacklist(newBlacklists) + // 更新全局配置中的黑名单 + s.globalConfig.Shield.Blacklists = newBlacklists + // 保存配置到文件 + if err := saveConfigToFile(s.globalConfig, "config.json"); err != nil { + logger.Error("保存配置文件失败", "error", err) + http.Error(w, "保存配置失败", http.StatusInternalServerError) + return + } json.NewEncoder(w).Encode(map[string]string{"status": "success"}) return } @@ -800,6 +816,14 @@ func (s *Server) handleShieldBlacklists(w http.ResponseWriter, r *http.Request) blacklists = append(blacklists, newEntry) s.shieldManager.UpdateBlacklist(blacklists) + // 更新全局配置中的黑名单 + s.globalConfig.Shield.Blacklists = blacklists + // 保存配置到文件 + if err := saveConfigToFile(s.globalConfig, "config.json"); err != nil { + logger.Error("保存配置文件失败", "error", err) + http.Error(w, "保存配置失败", http.StatusInternalServerError) + return + } // 重新加载规则以获取新添加的远程规则 s.shieldManager.LoadRules() @@ -815,6 +839,14 @@ func (s *Server) handleShieldBlacklists(w http.ResponseWriter, r *http.Request) } s.shieldManager.UpdateBlacklist(blacklists) + // 更新全局配置中的黑名单 + s.globalConfig.Shield.Blacklists = blacklists + // 保存配置到文件 + if err := saveConfigToFile(s.globalConfig, "config.json"); err != nil { + logger.Error("保存配置文件失败", "error", err) + http.Error(w, "保存配置失败", http.StatusInternalServerError) + return + } // 重新加载所有规则 s.shieldManager.LoadRules() diff --git a/static/js/shield.js b/static/js/shield.js index 8f6bd80..7a4a9d1 100644 --- a/static/js/shield.js +++ b/static/js/shield.js @@ -293,6 +293,19 @@ async function loadRemoteBlacklists() { } } +// 判断黑名单是否过期(超过24小时未更新视为过期) +function isBlacklistExpired(lastUpdateTime) { + if (!lastUpdateTime) { + return true; // 从未更新过,视为过期 + } + + const lastUpdate = new Date(lastUpdateTime); + const now = new Date(); + const hoursDiff = (now - lastUpdate) / (1000 * 60 * 60); + + return hoursDiff > 24; // 超过24小时视为过期 +} + // 更新黑名单表格 function updateBlacklistsTable(blacklists) { const tbody = document.getElementById('blacklists-table-body'); @@ -300,7 +313,8 @@ function updateBlacklistsTable(blacklists) { // 清空表格 tbody.innerHTML = ''; - if (blacklists.length === 0) { + // 检查黑名单数据是否为空 + if (!blacklists || blacklists.length === 0) { const emptyRow = document.createElement('tr'); emptyRow.innerHTML = '暂无黑名单'; tbody.appendChild(emptyRow); @@ -316,12 +330,12 @@ function updateBlacklistsTable(blacklists) { blacklistsToShow.forEach(blacklist => { const tr = document.createElement('tr'); - tr.className = 'border-b border-gray-200'; + tr.className = 'border-b border-gray-200 hover:bg-gray-50'; // 名称单元格 const tdName = document.createElement('td'); tdName.className = 'py-3 px-4'; - tdName.textContent = blacklist.Name; + tdName.textContent = blacklist.Name || '未命名'; // URL单元格 const tdUrl = document.createElement('td'); @@ -331,29 +345,58 @@ function updateBlacklistsTable(blacklists) { // 状态单元格 const tdStatus = document.createElement('td'); tdStatus.className = 'py-3 px-4 text-center'; + + // 判断状态颜色:绿色(正常)、黄色(过期)、灰色(禁用) + let statusColor = 'bg-gray-300'; // 默认禁用 + let statusText = '禁用'; + + if (blacklist.Enabled) { + const expired = isBlacklistExpired(blacklist.lastUpdateTime || blacklist.LastUpdateTime); + if (expired) { + statusColor = 'bg-warning'; // 黄色表示过期 + statusText = '过期'; + } else { + statusColor = 'bg-success'; // 绿色表示正常 + statusText = '正常'; + } + } + + const statusContainer = document.createElement('div'); + statusContainer.className = 'flex items-center justify-center'; + const statusDot = document.createElement('span'); - statusDot.className = `inline-block w-3 h-3 rounded-full ${blacklist.Enabled ? 'bg-success' : 'bg-gray-300'}`; - tdStatus.appendChild(statusDot); + statusDot.className = `inline-block w-3 h-3 rounded-full ${statusColor}`; + statusDot.title = statusText; + + const statusTextSpan = document.createElement('span'); + statusTextSpan.className = 'text-sm ml-2'; + statusTextSpan.textContent = statusText; + + statusContainer.appendChild(statusDot); + statusContainer.appendChild(statusTextSpan); + tdStatus.appendChild(statusContainer); // 操作单元格 const tdActions = document.createElement('td'); tdActions.className = 'py-3 px-4 text-right space-x-2'; - // 更新按钮 - const updateBtn = document.createElement('button'); - updateBtn.className = 'update-blacklist-btn px-3 py-1 bg-primary text-white rounded-md hover:bg-primary/90 transition-colors text-sm'; - updateBtn.dataset.url = blacklist.URL; - updateBtn.innerHTML = ''; - updateBtn.addEventListener('click', handleUpdateBlacklist); + // 刷新按钮 + const refreshBtn = document.createElement('button'); + refreshBtn.className = 'update-blacklist-btn px-3 py-1 bg-primary text-white rounded-md hover:bg-primary/90 transition-colors text-sm'; + refreshBtn.dataset.url = blacklist.URL; + refreshBtn.innerHTML = ''; + refreshBtn.title = '刷新黑名单'; + refreshBtn.addEventListener('click', handleUpdateBlacklist); // 删除按钮 const deleteBtn = document.createElement('button'); deleteBtn.className = 'delete-blacklist-btn px-3 py-1 bg-danger text-white rounded-md hover:bg-danger/90 transition-colors text-sm'; deleteBtn.dataset.url = blacklist.URL; deleteBtn.innerHTML = ''; + deleteBtn.title = '删除黑名单'; deleteBtn.addEventListener('click', handleDeleteBlacklist); - tdActions.appendChild(updateBtn); + tdActions.appendChild(refreshBtn); tdActions.appendChild(deleteBtn); tr.appendChild(tdName); @@ -377,25 +420,35 @@ function updateBlacklistsTable(blacklists) { // 处理更新单个黑名单 async function handleUpdateBlacklist(e) { const url = e.target.closest('.update-blacklist-btn').dataset.url; + + if (!url) { + showToast('无效的黑名单URL', 'error'); + return; + } + showLoading('更新黑名单中...'); try { const response = await fetch(`/api/shield/blacklists/${encodeURIComponent(url)}/update`, { - method: 'POST' + method: 'POST', + headers: { + 'Content-Type': 'application/json' + } }); if (!response.ok) { - throw new Error('Failed to update blacklist'); + const errorData = await response.json().catch(() => ({})); + throw new Error(errorData.error || 'Failed to update blacklist'); } - showSuccessMessage('黑名单更新成功'); // 重新加载黑名单 loadRemoteBlacklists(); // 重新加载统计信息 loadShieldStats(); - hideLoading(); + showToast('黑名单更新成功'); } catch (error) { - console.error('Error updating blacklist:', error); - showErrorMessage('更新黑名单失败'); + console.error('更新黑名单失败:', error); + showToast('更新黑名单失败: ' + error.message, 'error'); + } finally { hideLoading(); } } @@ -403,39 +456,71 @@ async function handleUpdateBlacklist(e) { // 处理删除黑名单 async function handleDeleteBlacklist(e) { const url = e.target.closest('.delete-blacklist-btn').dataset.url; + + if (!url) { + showToast('无效的黑名单URL', 'error'); + return; + } + + // 确认删除 + if (!confirm('确定要删除这个黑名单吗?删除后将无法恢复。')) { + return; + } + showLoading('删除黑名单中...'); try { const response = await fetch(`/api/shield/blacklists/${encodeURIComponent(url)}`, { - method: 'DELETE' + method: 'DELETE', + headers: { + 'Content-Type': 'application/json' + } }); if (!response.ok) { - throw new Error('Failed to delete blacklist'); + const errorData = await response.json().catch(() => ({})); + throw new Error(errorData.error || 'Failed to delete blacklist'); } - showSuccessMessage('黑名单删除成功'); // 重新加载黑名单 loadRemoteBlacklists(); // 重新加载统计信息 loadShieldStats(); - hideLoading(); + showToast('黑名单删除成功'); } catch (error) { - console.error('Error deleting blacklist:', error); - showErrorMessage('删除黑名单失败'); + console.error('删除黑名单失败:', error); + showToast('删除黑名单失败: ' + error.message, 'error'); + } finally { hideLoading(); } } // 处理添加黑名单 -async function handleAddBlacklist() { - const name = document.getElementById('blacklist-name').value.trim(); - const url = document.getElementById('blacklist-url').value.trim(); +async function handleAddBlacklist(event) { + // 如果存在event参数,则调用preventDefault()防止表单默认提交 + if (event && typeof event.preventDefault === 'function') { + event.preventDefault(); + } + const nameInput = document.getElementById('blacklist-name'); + const urlInput = document.getElementById('blacklist-url'); + + const name = nameInput ? nameInput.value.trim() : ''; + const url = urlInput ? urlInput.value.trim() : ''; + + // 简单验证 if (!name || !url) { showErrorMessage('名称和URL不能为空'); return; } + // 验证URL格式 + try { + new URL(url); + } catch (e) { + showErrorMessage('URL格式不正确'); + return; + } + showLoading('添加黑名单中...'); try { const response = await fetch('/api/shield/blacklists', { @@ -447,13 +532,23 @@ async function handleAddBlacklist() { }); if (!response.ok) { - throw new Error('Failed to add blacklist'); + // 尝试从响应中获取更详细的错误信息 + let errorMessage = '添加黑名单失败'; + try { + const errorData = await response.json(); + if (errorData.error) { + errorMessage = errorData.error; + } + } catch (jsonError) { + // 忽略JSON解析错误 + } + throw new Error(errorMessage); } showSuccessMessage('黑名单添加成功'); // 清空输入框 - document.getElementById('blacklist-name').value = ''; - document.getElementById('blacklist-url').value = ''; + if (nameInput) nameInput.value = ''; + if (urlInput) urlInput.value = ''; // 重新加载黑名单 loadRemoteBlacklists(); // 重新加载统计信息 @@ -461,7 +556,7 @@ async function handleAddBlacklist() { hideLoading(); } catch (error) { console.error('Error adding blacklist:', error); - showErrorMessage('添加黑名单失败'); + showErrorMessage(error.message || '添加黑名单失败'); hideLoading(); } }