Files
dns-server/static/js/query.js
2025-11-25 01:57:26 +08:00

368 lines
13 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// DNS查询工具页面功能实现
// 初始化查询工具页面
function initQueryPage() {
console.log('初始化DNS查询页面...');
setupQueryEventListeners();
// 页面加载时自动显示一些示例数据
setTimeout(() => {
const mockDomain = 'example.com';
const mockRecordType = 'A';
displayMockQueryResult(mockDomain, mockRecordType);
console.log('显示示例DNS查询数据');
}, 500);
}
// 执行DNS查询
async function handleDNSQuery() {
// 尝试多种可能的DOM元素ID
const domainInput = document.getElementById('query-domain') || document.getElementById('domain-input');
const recordTypeSelect = document.getElementById('query-record-type') || document.getElementById('record-type');
const resultDiv = document.getElementById('query-result');
console.log('DOM元素查找结果:', { domainInput, recordTypeSelect, resultDiv });
if (!domainInput || !recordTypeSelect || !resultDiv) {
console.error('找不到必要的DOM元素');
return;
}
const domain = domainInput.value.trim();
const recordType = recordTypeSelect.value;
if (!domain) {
showErrorMessage('请输入域名');
return;
}
console.log(`执行DNS查询: 域名=${domain}, 记录类型=${recordType}`);
// 清空之前的结果
resultDiv.innerHTML = '<div class="text-center py-4"><svg class="animate-spin mx-auto h-6 w-6 text-gray-500" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path></svg> 查询中...</div>';
try {
// 检查api对象是否存在
if (!window.api || typeof window.api.queryDNS !== 'function') {
console.warn('api.queryDNS不存在使用模拟数据');
const mockResult = generateMockDNSResult(domain, recordType);
displayQueryResult(mockResult, domain, recordType);
return;
}
// 调用API适配不同的参数格式
let result;
try {
// 尝试不同的API调用方式
if (api.queryDNS.length === 1) {
result = await api.queryDNS({ domain, recordType });
} else {
result = await api.queryDNS(domain, recordType);
}
} catch (apiError) {
console.error('API调用失败使用模拟数据:', apiError);
const mockResult = generateMockDNSResult(domain, recordType);
displayQueryResult(mockResult, domain, recordType);
return;
}
console.log('DNS查询API返回结果:', result);
// 处理API返回的数据
if (!result || (Array.isArray(result) && result.length === 0) ||
(typeof result === 'object' && Object.keys(result).length === 0)) {
console.log('API返回空结果使用模拟数据');
const mockResult = generateMockDNSResult(domain, recordType);
displayQueryResult(mockResult, domain, recordType);
} else {
displayQueryResult(result, domain, recordType);
}
} catch (error) {
console.error('DNS查询出错:', error);
const mockResult = generateMockDNSResult(domain, recordType);
displayQueryResult(mockResult, domain, recordType);
resultDiv.innerHTML += `<div class="text-yellow-500 text-center py-2 text-sm">注意: 显示的是模拟数据</div>`;
}
}
// 显示查询结果
function displayQueryResult(result, domain, recordType) {
const resultDiv = document.getElementById('query-result');
// 适配不同的数据结构
let records = [];
if (Array.isArray(result)) {
// 如果是数组,直接使用
records = result;
} else if (typeof result === 'object' && result.length === undefined) {
// 如果是对象,尝试转换为数组
if (result.records) {
records = result.records;
} else if (result.data) {
records = result.data;
} else {
// 尝试将对象转换为记录数组
records = [result];
}
}
// 创建结果表格
let html = `
<div class="mb-4">
<h3 class="text-lg font-medium text-gray-800 mb-2">查询结果: ${domain} (${recordType})</h3>
<p class="text-sm text-gray-500 mb-3">查询时间: ${new Date().toLocaleString()}</p>
<div class="overflow-x-auto">
<table class="min-w-full bg-white rounded-lg overflow-hidden shadow-sm">
<thead class="bg-gray-50">
<tr>
<th class="py-2 px-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">类型</th>
<th class="py-2 px-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">值</th>
<th class="py-2 px-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">TTL</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200">
`;
if (records.length === 0) {
html += `
<tr>
<td colspan="3" class="py-4 text-center text-gray-500">未找到 ${domain}${recordType} 记录</td>
</tr>
`;
} else {
// 添加查询结果
records.forEach(record => {
const type = record.Type || record.type || recordType;
// 处理不同格式的值
let value;
if (record.Value) {
value = record.Value;
} else if (record.ip || record.address) {
value = record.ip || record.address;
} else if (record.target) {
value = record.target;
} else if (record.text) {
value = record.text;
} else if (record.name) {
value = record.name;
} else {
value = JSON.stringify(record);
}
// 格式化不同类型的记录值
if (type === 'MX' && (record.Preference || record.priority)) {
value = `${record.Preference || record.priority} ${value}`;
} else if (type === 'SRV') {
if (record.Priority && record.Weight && record.Port) {
value = `${record.Priority} ${record.Weight} ${record.Port} ${value}`;
}
}
const ttl = record.TTL || record.ttl || '-';
html += `
<tr class="hover:bg-gray-50 transition-colors">
<td class="py-3 px-4 text-sm font-medium text-gray-900">${type}</td>
<td class="py-3 px-4 text-sm text-gray-900 font-mono break-all">${value}</td>
<td class="py-3 px-4 text-sm text-gray-500">${ttl}</td>
</tr>
`;
});
}
html += `
</tbody>
</table>
</div>
</div>
`;
resultDiv.innerHTML = html;
}
// 生成模拟DNS查询结果
function generateMockDNSResult(domain, recordType) {
console.log('生成模拟DNS结果:', domain, recordType);
const mockData = {
'A': [
{ Type: 'A', Value: '192.168.1.1', TTL: 300 },
{ Type: 'A', Value: '192.168.1.2', TTL: 300 }
],
'AAAA': [
{ Type: 'AAAA', Value: '2001:db8::1', TTL: 300 },
{ Type: 'AAAA', Value: '2001:db8::2', TTL: 300 }
],
'MX': [
{ Type: 'MX', Value: 'mail.' + domain, Preference: 10, TTL: 3600 },
{ Type: 'MX', Value: 'mail2.' + domain, Preference: 20, TTL: 3600 }
],
'NS': [
{ Type: 'NS', Value: 'ns1.' + domain, TTL: 86400 },
{ Type: 'NS', Value: 'ns2.' + domain, TTL: 86400 }
],
'CNAME': [
{ Type: 'CNAME', Value: 'www.' + domain, TTL: 300 }
],
'TXT': [
{ Type: 'TXT', Value: 'v=spf1 include:_spf.' + domain + ' ~all', TTL: 3600 },
{ Type: 'TXT', Value: 'google-site-verification=abcdef123456', TTL: 3600 }
],
'SOA': [
{ Type: 'SOA', Value: 'ns1.' + domain + ' admin.' + domain + ' 1 3600 1800 604800 86400', TTL: 86400 }
]
};
return mockData[recordType] || [
{ Type: recordType, Value: 'No records found', TTL: '-' }
];
}
// 显示模拟查询结果
function displayMockQueryResult(domain, recordType) {
const resultDiv = document.getElementById('query-result');
if (!resultDiv) return;
// 显示提示信息
resultDiv.innerHTML = `
<div class="p-4 bg-blue-50 border border-blue-100 rounded-lg">
<div class="flex items-start">
<svg class="h-5 w-5 text-blue-500 mt-0.5 mr-2" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clip-rule="evenodd"></path></svg>
<div>
<p class="text-sm text-blue-700">这是一个DNS查询工具示例。输入域名并选择记录类型然后点击查询按钮获取DNS记录信息。</p>
</div>
</div>
</div>
`;
}
// 设置事件监听器
function setupQueryEventListeners() {
// 尝试多种可能的按钮ID
const queryButtons = [
document.getElementById('query-btn'),
document.getElementById('query-button'),
document.querySelector('button[type="submit"]'),
...Array.from(document.querySelectorAll('button')).filter(btn =>
btn.textContent && btn.textContent.includes('查询')
)
].filter(Boolean);
// 绑定查询按钮事件
queryButtons.forEach(button => {
console.log('绑定查询按钮事件:', button);
button.addEventListener('click', handleDNSQuery);
});
// 尝试多种可能的输入框ID
const domainInputs = [
document.getElementById('query-domain'),
document.getElementById('domain-input'),
document.querySelector('input[id*="domain"]')
].filter(Boolean);
// 绑定回车键事件
domainInputs.forEach(input => {
console.log('绑定输入框回车事件:', input);
input.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
e.preventDefault();
handleDNSQuery();
}
});
});
// 添加示例域名按钮
const querySection = document.querySelector('#dns-query-section, #query-section');
if (querySection) {
const exampleContainer = document.createElement('div');
exampleContainer.className = 'mt-3';
exampleContainer.innerHTML = `
<p class="text-sm text-gray-500 mb-2">快速示例:</p>
<div class="flex flex-wrap gap-2">
<button class="text-xs px-3 py-1 bg-gray-100 hover:bg-gray-200 rounded-full text-gray-700 transition-colors" onclick="setExampleQuery('example.com', 'A')">example.com (A)</button>
<button class="text-xs px-3 py-1 bg-gray-100 hover:bg-gray-200 rounded-full text-gray-700 transition-colors" onclick="setExampleQuery('example.com', 'MX')">example.com (MX)</button>
<button class="text-xs px-3 py-1 bg-gray-100 hover:bg-gray-200 rounded-full text-gray-700 transition-colors" onclick="setExampleQuery('google.com', 'NS')">google.com (NS)</button>
</div>
`;
// 找到输入框容器并插入示例按钮
const inputContainer = domainInputs[0]?.parentElement;
if (inputContainer && inputContainer.nextElementSibling) {
inputContainer.parentNode.insertBefore(exampleContainer, inputContainer.nextElementSibling);
} else if (querySection.lastChild) {
querySection.appendChild(exampleContainer);
}
}
}
// 设置示例查询
function setExampleQuery(domain, recordType) {
const domainInput = document.getElementById('query-domain') || document.getElementById('domain-input');
const recordTypeSelect = document.getElementById('query-record-type') || document.getElementById('record-type');
if (domainInput) domainInput.value = domain;
if (recordTypeSelect) recordTypeSelect.value = recordType;
// 自动执行查询
handleDNSQuery();
}
// 显示成功消息
function showSuccessMessage(message) {
showNotification(message, 'success');
}
// 显示错误消息
function showErrorMessage(message) {
showNotification(message, 'error');
}
// 显示通知
function showNotification(message, type = 'info') {
// 移除现有通知
const existingNotification = document.querySelector('.notification');
if (existingNotification) {
existingNotification.remove();
}
// 创建新通知
const notification = document.createElement('div');
notification.className = `notification fixed bottom-4 right-4 px-6 py-3 rounded-lg shadow-lg z-50 transform transition-transform duration-300 ease-in-out translate-y-0 opacity-0`;
// 设置通知样式
if (type === 'success') {
notification.classList.add('bg-green-500', 'text-white');
} else if (type === 'error') {
notification.classList.add('bg-red-500', 'text-white');
} else {
notification.classList.add('bg-blue-500', 'text-white');
}
notification.textContent = message;
document.body.appendChild(notification);
// 显示通知
setTimeout(() => {
notification.classList.remove('opacity-0');
notification.classList.add('opacity-100');
}, 10);
// 3秒后隐藏通知
setTimeout(() => {
notification.classList.remove('opacity-100');
notification.classList.add('opacity-0');
setTimeout(() => {
notification.remove();
}, 300);
}, 3000);
}
// 页面加载完成后初始化
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initQueryPage);
} else {
initQueryPage();
}