279 lines
10 KiB
JavaScript
279 lines
10 KiB
JavaScript
// 初始化DNS查询面板
|
||
function initQueryPanel() {
|
||
// 初始化事件监听器
|
||
initQueryEventListeners();
|
||
|
||
// 确保结果容器默认隐藏
|
||
const resultContainer = document.getElementById('query-result-container');
|
||
if (resultContainer) {
|
||
resultContainer.classList.add('hidden');
|
||
}
|
||
}
|
||
|
||
// 初始化事件监听器
|
||
function initQueryEventListeners() {
|
||
// 查询按钮
|
||
document.getElementById('run-query').addEventListener('click', runDnsQuery);
|
||
|
||
// 按Enter键执行查询
|
||
document.getElementById('query-domain').addEventListener('keypress', function(e) {
|
||
if (e.key === 'Enter') {
|
||
runDnsQuery();
|
||
}
|
||
});
|
||
}
|
||
|
||
// 执行DNS查询
|
||
function runDnsQuery() {
|
||
const domainInput = document.getElementById('query-domain');
|
||
const domain = domainInput.value.trim();
|
||
|
||
if (!domain) {
|
||
if (typeof window.showNotification === 'function') {
|
||
window.showNotification('请输入要查询的域名', 'warning');
|
||
}
|
||
domainInput.focus();
|
||
return;
|
||
}
|
||
|
||
// 显示查询中状态
|
||
showQueryLoading();
|
||
|
||
// 更新API路径,使用完整路径
|
||
apiRequest('/query', 'GET', { domain: domain })
|
||
.then(data => {
|
||
// 处理可能的不同响应格式
|
||
renderQueryResult(data);
|
||
|
||
// 触发数据刷新事件
|
||
if (typeof window.triggerDataRefresh === 'function') {
|
||
window.triggerDataRefresh('query');
|
||
}
|
||
})
|
||
.catch(error => {
|
||
console.error('DNS查询失败:', error);
|
||
showQueryError('查询失败,请稍后重试');
|
||
if (typeof window.showNotification === 'function') {
|
||
window.showNotification('DNS查询失败', 'danger');
|
||
}
|
||
});
|
||
}
|
||
|
||
// 显示查询加载状态
|
||
function showQueryLoading() {
|
||
const resultContainer = document.getElementById('query-result-container');
|
||
if (!resultContainer) return;
|
||
|
||
// 添加加载动画类
|
||
resultContainer.classList.add('loading-animation');
|
||
resultContainer.classList.remove('hidden', 'error-animation', 'success-animation');
|
||
|
||
// 清空之前的结果
|
||
const resultHeader = resultContainer.querySelector('.result-header h3');
|
||
const resultContent = resultContainer.querySelector('.result-content');
|
||
|
||
if (resultHeader) resultHeader.textContent = '查询中...';
|
||
if (resultContent) {
|
||
resultContent.innerHTML = '<div class="loading">' +
|
||
'<div class="spinner"></div><span>正在查询...</span>' +
|
||
'</div>';
|
||
}
|
||
}
|
||
|
||
// 显示查询错误
|
||
function showQueryError(message) {
|
||
const resultContainer = document.getElementById('query-result-container');
|
||
if (!resultContainer) return;
|
||
|
||
// 添加错误动画类
|
||
resultContainer.classList.add('error-animation');
|
||
resultContainer.classList.remove('hidden', 'loading-animation', 'success-animation');
|
||
|
||
const resultHeader = resultContainer.querySelector('.result-header h3');
|
||
const resultContent = resultContainer.querySelector('.result-content');
|
||
|
||
if (resultHeader) resultHeader.textContent = '查询错误';
|
||
if (resultContent) {
|
||
resultContent.innerHTML = `<div class="result-item error-message">
|
||
<i class="fas fa-exclamation-circle"></i>
|
||
<span>${message}</span>
|
||
</div>`;
|
||
}
|
||
}
|
||
|
||
// 渲染查询结果
|
||
function renderQueryResult(result) {
|
||
const resultContainer = document.getElementById('query-result-container');
|
||
if (!resultContainer) return;
|
||
|
||
// 添加成功动画类
|
||
resultContainer.classList.add('success-animation');
|
||
resultContainer.classList.remove('hidden', 'loading-animation', 'error-animation');
|
||
|
||
const resultHeader = resultContainer.querySelector('.result-header h3');
|
||
const resultContent = resultContainer.querySelector('.result-content');
|
||
|
||
if (resultHeader) resultHeader.textContent = '查询结果';
|
||
if (!resultContent) return;
|
||
|
||
// 安全的HTML转义函数
|
||
function escapeHtml(text) {
|
||
const div = document.createElement('div');
|
||
div.textContent = text;
|
||
return div.innerHTML;
|
||
}
|
||
|
||
// 根据查询结果构建内容
|
||
let content = '<div class="result-grid">';
|
||
|
||
// 域名
|
||
const safeDomain = escapeHtml(result.domain || '');
|
||
content += `<div class="result-item domain-item">
|
||
<div class="result-label"><i class="fas fa-globe"></i> 域名</div>
|
||
<div class="result-value" id="result-domain">${safeDomain}</div>
|
||
</div>`;
|
||
|
||
// 状态
|
||
const statusText = result.isBlocked ? '被屏蔽' : result.isAllowed ? '允许访问' : '未知';
|
||
const statusClass = result.isBlocked ? 'status-error' : result.isAllowed ? 'status-success' : '';
|
||
const statusIcon = result.isBlocked ? 'fa-ban' : result.isAllowed ? 'fa-check-circle' : 'fa-question-circle';
|
||
content += `<div class="result-item status-item">
|
||
<div class="result-label"><i class="fas fa-shield-alt"></i> 状态</div>
|
||
<div class="result-value" id="result-status" class="${statusClass}">
|
||
<i class="fas ${statusIcon}"></i> ${statusText}
|
||
</div>
|
||
</div>`;
|
||
|
||
// 规则类型
|
||
let ruleType = '';
|
||
if (result.isBlocked) {
|
||
if (result.isRegexMatch) {
|
||
ruleType = '正则表达式规则';
|
||
} else if (result.isDomainMatch) {
|
||
ruleType = '域名规则';
|
||
} else {
|
||
ruleType = '未知规则类型';
|
||
}
|
||
} else {
|
||
ruleType = result.isWhitelist ? '白名单规则' : result.isHosts ? 'Hosts记录' : '未匹配任何规则';
|
||
}
|
||
content += `<div class="result-item rule-type-item">
|
||
<div class="result-label"><i class="fas fa-list-alt"></i> 规则类型</div>
|
||
<div class="result-value" id="result-rule-type">${escapeHtml(ruleType)}</div>
|
||
</div>`;
|
||
|
||
// 匹配规则
|
||
const matchedRule = escapeHtml(result.matchedRule || '无');
|
||
content += `<div class="result-item matched-rule-item">
|
||
<div class="result-label"><i class="fas fa-sitemap"></i> 匹配规则</div>
|
||
<div class="result-value rule-code" id="result-rule">${matchedRule}</div>
|
||
</div>`;
|
||
|
||
// Hosts记录
|
||
const hostsRecord = result.hostsRecord ?
|
||
escapeHtml(`${result.hostsRecord.ip} ${result.hostsRecord.domain}`) : '无';
|
||
content += `<div class="result-item hosts-item">
|
||
<div class="result-label"><i class="fas fa-file-alt"></i> Hosts记录</div>
|
||
<div class="result-value" id="result-hosts">${hostsRecord}</div>
|
||
</div>`;
|
||
|
||
// 查询时间
|
||
const queryTime = `${(result.queryTime || 0).toFixed(2)} ms`;
|
||
content += `<div class="result-item time-item">
|
||
<div class="result-label"><i class="fas fa-clock"></i> 查询时间</div>
|
||
<div class="result-value" id="result-time">${queryTime}</div>
|
||
</div>`;
|
||
|
||
content += '</div>'; // 结束result-grid
|
||
|
||
// DNS响应(如果有)
|
||
if (result.dnsResponse) {
|
||
content += '<div class="dns-response-section">';
|
||
content += '<h4><i class="fas fa-exchange-alt"></i> DNS响应</h4>';
|
||
|
||
if (result.dnsResponse.answers && result.dnsResponse.answers.length > 0) {
|
||
content += '<div class="dns-answers">';
|
||
result.dnsResponse.answers.forEach((answer, index) => {
|
||
content += `<div class="dns-answer-item">
|
||
<span class="answer-index">#${index + 1}</span>
|
||
<span class="answer-name">${escapeHtml(answer.name)}</span>
|
||
<span class="answer-type">${escapeHtml(answer.type)}</span>
|
||
<span class="answer-value">${escapeHtml(answer.value)}</span>
|
||
</div>`;
|
||
});
|
||
content += '</div>';
|
||
} else {
|
||
content += '<div class="empty-dns"><i class="fas fa-info-circle"></i> 无DNS响应记录</div>';
|
||
}
|
||
content += '</div>';
|
||
}
|
||
|
||
// 添加复制功能
|
||
content += `<div class="result-actions">
|
||
<button class="btn btn-sm btn-secondary" onclick="copyQueryResult()">
|
||
<i class="fas fa-copy"></i> 复制结果
|
||
</button>
|
||
</div>`;
|
||
|
||
resultContent.innerHTML = content;
|
||
|
||
// 通知用户查询成功
|
||
if (typeof window.showNotification === 'function') {
|
||
const statusMsg = result.isBlocked ? '查询完成,该域名被屏蔽' :
|
||
result.isAllowed ? '查询完成,该域名允许访问' : '查询完成';
|
||
window.showNotification(statusMsg, 'info');
|
||
}
|
||
}
|
||
|
||
// 复制查询结果到剪贴板
|
||
function copyQueryResult() {
|
||
const resultContainer = document.getElementById('query-result-container');
|
||
if (!resultContainer) return;
|
||
|
||
// 收集关键信息
|
||
const domain = document.getElementById('result-domain')?.textContent || '未知域名';
|
||
const status = document.getElementById('result-status')?.textContent || '未知状态';
|
||
const ruleType = document.getElementById('result-rule-type')?.textContent || '无规则类型';
|
||
const matchedRule = document.getElementById('result-rule')?.textContent || '无匹配规则';
|
||
const queryTime = document.getElementById('result-time')?.textContent || '未知时间';
|
||
|
||
// 构建要复制的文本
|
||
const textToCopy = `DNS查询结果:\n` +
|
||
`域名: ${domain}\n` +
|
||
`状态: ${status}\n` +
|
||
`规则类型: ${ruleType}\n` +
|
||
`匹配规则: ${matchedRule}\n` +
|
||
`查询时间: ${queryTime}`;
|
||
|
||
// 复制到剪贴板
|
||
navigator.clipboard.writeText(textToCopy)
|
||
.then(() => {
|
||
if (typeof window.showNotification === 'function') {
|
||
window.showNotification('查询结果已复制到剪贴板', 'success');
|
||
}
|
||
})
|
||
.catch(err => {
|
||
console.error('复制失败:', err);
|
||
if (typeof window.showNotification === 'function') {
|
||
window.showNotification('复制失败,请手动复制', 'warning');
|
||
}
|
||
});
|
||
}
|
||
|
||
// 导出函数,供其他模块调用
|
||
window.initQueryPanel = initQueryPanel;
|
||
window.runDnsQuery = runDnsQuery;
|
||
|
||
// 注册到面板导航系统
|
||
if (window.registerPanelModule) {
|
||
window.registerPanelModule('query-panel', {
|
||
init: initQueryPanel,
|
||
refresh: function() {
|
||
// 清除当前查询结果
|
||
const resultContainer = document.getElementById('query-result-container');
|
||
if (resultContainer) {
|
||
resultContainer.classList.add('hidden');
|
||
}
|
||
}
|
||
});
|
||
} |