375 lines
13 KiB
JavaScript
375 lines
13 KiB
JavaScript
// 域名信息管理模块
|
|
// 用于管理远程域名信息列表的加载、更新和显示
|
|
|
|
(function() {
|
|
'use strict';
|
|
|
|
// 域名信息列表缓存
|
|
let domainInfoCache = null;
|
|
let cacheTimestamp = 0;
|
|
const CACHE_DURATION = 5 * 60 * 1000; // 5 分钟缓存
|
|
|
|
/**
|
|
* 加载域名信息列表
|
|
*/
|
|
function loadDomainInfoLists() {
|
|
const tbody = document.getElementById('domain-info-lists-table-body');
|
|
if (!tbody) {
|
|
console.warn('未找到域名信息列表表格元素');
|
|
return;
|
|
}
|
|
|
|
showLoading(tbody);
|
|
|
|
// 检查缓存
|
|
if (domainInfoCache && (Date.now() - cacheTimestamp) < CACHE_DURATION) {
|
|
console.log('使用缓存的域名信息列表');
|
|
renderDomainInfoLists(domainInfoCache);
|
|
return;
|
|
}
|
|
|
|
apiRequest('/api/domain-info')
|
|
.then(data => {
|
|
domainInfoCache = data;
|
|
cacheTimestamp = Date.now();
|
|
renderDomainInfoLists(data);
|
|
})
|
|
.catch(error => {
|
|
console.error('获取域名信息列表失败:', error);
|
|
showError(tbody, '获取域名信息列表失败');
|
|
window.showNotification('获取域名信息列表失败', 'error');
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 渲染域名信息列表
|
|
*/
|
|
function renderDomainInfoLists(data) {
|
|
const tbody = document.getElementById('domain-info-lists-table-body');
|
|
if (!tbody) return;
|
|
|
|
tbody.innerHTML = '';
|
|
|
|
if (!data || !data.lists || data.lists.length === 0) {
|
|
const emptyRow = document.createElement('tr');
|
|
emptyRow.innerHTML = '<td colspan="6" class="py-4 text-center text-gray-500">暂无域名信息列表</td>';
|
|
tbody.appendChild(emptyRow);
|
|
return;
|
|
}
|
|
|
|
const fragment = document.createDocumentFragment();
|
|
|
|
data.lists.forEach((list, index) => {
|
|
const tr = document.createElement('tr');
|
|
tr.className = 'border-b border-gray-200 hover:bg-gray-50';
|
|
|
|
const typeLabel = getTypeLabel(list.type);
|
|
const statusClass = list.enabled ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-800';
|
|
const statusText = list.enabled ? '启用' : '禁用';
|
|
|
|
tr.innerHTML = `
|
|
<td class="py-3 px-4 font-medium">${escapeHtml(list.name)}</td>
|
|
<td class="py-3 px-4">
|
|
<span class="px-2 py-1 rounded-full text-xs font-medium ${statusClass}">${statusText}</span>
|
|
</td>
|
|
<td class="py-3 px-4">
|
|
<span class="px-2 py-1 rounded-full text-xs font-medium bg-blue-100 text-blue-800">${typeLabel}</span>
|
|
</td>
|
|
<td class="py-3 px-4 text-center">${list.ruleCount || 0}</td>
|
|
<td class="py-3 px-4 text-sm text-gray-600">${formatLastUpdateTime(list.lastUpdateTime)}</td>
|
|
<td class="py-3 px-4 text-center">
|
|
<div class="flex space-x-2 justify-center">
|
|
<button onclick="window.domainInfo.updateDomainInfo('${list.type}')"
|
|
class="px-3 py-1 bg-blue-500 text-white rounded hover:bg-blue-600 text-sm"
|
|
title="更新此列表">
|
|
更新
|
|
</button>
|
|
<button onclick="window.domainInfo.removeDomainInfo('${list.type}')"
|
|
class="px-3 py-1 bg-red-500 text-white rounded hover:bg-red-600 text-sm"
|
|
title="删除此列表">
|
|
删除
|
|
</button>
|
|
</div>
|
|
</td>
|
|
`;
|
|
|
|
fragment.appendChild(tr);
|
|
});
|
|
|
|
tbody.appendChild(fragment);
|
|
|
|
// 更新统计信息
|
|
updateDomainInfoStats(data);
|
|
}
|
|
|
|
/**
|
|
* 更新域名信息统计
|
|
*/
|
|
function updateDomainInfoStats(data) {
|
|
if (document.getElementById('domain-info-count')) {
|
|
document.getElementById('domain-info-count').textContent = data.domainInfoCount || 0;
|
|
}
|
|
if (document.getElementById('threat-count')) {
|
|
document.getElementById('threat-count').textContent = data.threatCount || 0;
|
|
}
|
|
if (document.getElementById('tracker-count')) {
|
|
document.getElementById('tracker-count').textContent = data.trackerCount || 0;
|
|
}
|
|
if (document.getElementById('last-update-time')) {
|
|
document.getElementById('last-update-time').textContent = formatLastUpdateTime(data.lastUpdateTime);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 更新域名信息
|
|
*/
|
|
function updateDomainInfo(type) {
|
|
const url = `/api/domain-info/update/${encodeURIComponent(type)}`;
|
|
|
|
apiRequest(url, 'POST')
|
|
.then(data => {
|
|
if (data.status === 'success') {
|
|
window.showNotification(`域名信息更新任务已启动:${getTypeLabel(type)}`, 'success');
|
|
// 延迟刷新列表
|
|
setTimeout(() => {
|
|
loadDomainInfoLists();
|
|
}, 2000);
|
|
} else {
|
|
window.showNotification(`更新失败:${data.message || '未知错误'}`, 'error');
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('更新域名信息失败:', error);
|
|
window.showNotification('更新域名信息失败', 'error');
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 更新所有域名信息
|
|
*/
|
|
function updateAllDomainInfo() {
|
|
if (!confirm('确定要更新所有域名信息吗?这可能需要一些时间。')) {
|
|
return;
|
|
}
|
|
|
|
apiRequest('/api/domain-info/update', 'POST')
|
|
.then(data => {
|
|
if (data.status === 'success') {
|
|
window.showNotification('所有域名信息更新任务已启动', 'success');
|
|
setTimeout(() => {
|
|
loadDomainInfoLists();
|
|
}, 2000);
|
|
} else {
|
|
window.showNotification(`更新失败:${data.message || '未知错误'}`, 'error');
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('更新所有域名信息失败:', error);
|
|
window.showNotification('更新所有域名信息失败', 'error');
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 获取类型标签
|
|
*/
|
|
function getTypeLabel(type) {
|
|
const labels = {
|
|
'domain-info': '域名信息',
|
|
'threat-database': '威胁数据库',
|
|
'tracker': '跟踪器'
|
|
};
|
|
return labels[type] || type;
|
|
}
|
|
|
|
/**
|
|
* 格式化最后更新时间
|
|
*/
|
|
function formatLastUpdateTime(timeStr) {
|
|
if (!timeStr) return '从未更新';
|
|
const date = new Date(timeStr);
|
|
const now = new Date();
|
|
const diff = now - date;
|
|
|
|
const minutes = Math.floor(diff / 60000);
|
|
const hours = Math.floor(diff / 3600000);
|
|
const days = Math.floor(diff / 86400000);
|
|
|
|
if (minutes < 1) return '刚刚';
|
|
if (minutes < 60) return `${minutes}分钟前`;
|
|
if (hours < 24) return `${hours}小时前`;
|
|
if (days < 30) return `${days}天前`;
|
|
|
|
return date.toLocaleDateString('zh-CN');
|
|
}
|
|
|
|
/**
|
|
* 显示加载状态
|
|
*/
|
|
function showLoading(container) {
|
|
container.innerHTML = `
|
|
<tr>
|
|
<td colspan="6" class="py-8 text-center">
|
|
<div class="flex items-center justify-center">
|
|
<div class="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-500"></div>
|
|
<span class="ml-3 text-gray-600">加载中...</span>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
`;
|
|
}
|
|
|
|
/**
|
|
* 显示错误状态
|
|
*/
|
|
function showError(container, message) {
|
|
container.innerHTML = `
|
|
<tr>
|
|
<td colspan="6" class="py-8 text-center text-red-500">
|
|
<svg class="w-12 h-12 mx-auto mb-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
|
</svg>
|
|
${escapeHtml(message)}
|
|
</td>
|
|
</tr>
|
|
`;
|
|
}
|
|
|
|
/**
|
|
* HTML 转义
|
|
*/
|
|
function escapeHtml(text) {
|
|
const div = document.createElement('div');
|
|
div.textContent = text;
|
|
return div.innerHTML;
|
|
}
|
|
|
|
/**
|
|
* API 请求封装
|
|
*/
|
|
function apiRequest(url, method = 'GET', data = null) {
|
|
const options = {
|
|
method: method,
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
credentials: 'same-origin' // 添加认证信息
|
|
};
|
|
|
|
if (data && method !== 'GET') {
|
|
options.body = JSON.stringify(data);
|
|
}
|
|
|
|
return fetch(url, options)
|
|
.then(response => {
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
}
|
|
return response.json();
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 显示添加列表模态框
|
|
*/
|
|
function showAddListModal() {
|
|
const modal = document.getElementById('add-domain-info-modal');
|
|
if (modal) {
|
|
modal.classList.remove('hidden');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 隐藏添加列表模态框
|
|
*/
|
|
function hideAddListModal() {
|
|
const modal = document.getElementById('add-domain-info-modal');
|
|
if (modal) {
|
|
modal.classList.add('hidden');
|
|
// 重置表单
|
|
document.getElementById('add-domain-info-form').reset();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 添加域名信息列表
|
|
*/
|
|
function addDomainInfo(e) {
|
|
e.preventDefault();
|
|
|
|
const name = document.getElementById('list-name').value.trim();
|
|
const url = document.getElementById('list-url').value.trim();
|
|
const type = document.getElementById('list-type').value;
|
|
const enabled = document.getElementById('list-enabled').checked;
|
|
|
|
if (!name || !url) {
|
|
window.showNotification('请填写名称和URL', 'error');
|
|
return;
|
|
}
|
|
|
|
const data = {
|
|
name: name,
|
|
url: url,
|
|
type: type,
|
|
enabled: enabled
|
|
};
|
|
|
|
apiRequest('/api/domain-info/add', 'POST', data)
|
|
.then(response => {
|
|
if (response.status === 'success') {
|
|
window.showNotification('域名信息列表添加成功', 'success');
|
|
hideAddListModal();
|
|
loadDomainInfoLists();
|
|
} else {
|
|
window.showNotification(`添加失败:${response.message || '未知错误'}`, 'error');
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('添加域名信息列表失败:', error);
|
|
window.showNotification('添加域名信息列表失败', 'error');
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 删除域名信息列表
|
|
*/
|
|
function removeDomainInfo(type) {
|
|
if (!confirm('确定要删除此域名信息列表吗?此操作不可恢复。')) {
|
|
return;
|
|
}
|
|
|
|
apiRequest(`/api/domain-info/remove/${encodeURIComponent(type)}`, 'POST')
|
|
.then(response => {
|
|
if (response.status === 'success') {
|
|
window.showNotification('域名信息列表删除成功', 'success');
|
|
loadDomainInfoLists();
|
|
} else {
|
|
window.showNotification(`删除失败:${response.message || '未知错误'}`, 'error');
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('删除域名信息列表失败:', error);
|
|
window.showNotification('删除域名信息列表失败', 'error');
|
|
});
|
|
}
|
|
|
|
// 绑定添加列表表单提交事件
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const form = document.getElementById('add-domain-info-form');
|
|
if (form) {
|
|
form.addEventListener('submit', addDomainInfo);
|
|
}
|
|
});
|
|
|
|
// 暴露到全局命名空间
|
|
window.domainInfo = {
|
|
loadDomainInfoLists,
|
|
updateDomainInfo,
|
|
updateAllDomainInfo,
|
|
renderDomainInfoLists,
|
|
showAddListModal,
|
|
hideAddListModal,
|
|
removeDomainInfo
|
|
};
|
|
|
|
})();
|