blob: 642d4bc39a17fd386fdb7c0d9b4defbd52dd5aa1 [file] [log] [blame] [raw]
let currentHosts = {};
let originalHosts = {}; // 保存原始配置用于比较
let currentPage = 1;
const itemsPerPage = 10;
let filteredHosts = [];
// 加载当前配置
async function loadConfig() {
const response = await fetch('http://localhost:3001/api/config');
const data = await response.json();
document.getElementById('oversea-version').textContent = data.overseaVersion;
document.getElementById('cn-version').textContent = data.cnVersion;
currentHosts = data.hosts;
originalHosts = {...data.hosts}; // 保存原始配置的副本
filterAndRenderTable();
}
// 过滤和渲染表格
function filterAndRenderTable() {
const domainSearch = document.getElementById('domain-search').value.toLowerCase();
const ipSearch = document.getElementById('ip-search').value.toLowerCase();
// 过滤数据
filteredHosts = Object.entries(currentHosts)
.filter(([domain, ip]) => {
const matchDomain = domain.toLowerCase().includes(domainSearch);
const matchIP = ip.toLowerCase().includes(ipSearch);
return matchDomain && matchIP;
})
.sort((a, b) => a[0].localeCompare(b[0]));
// 更新分页
const totalPages = Math.ceil(filteredHosts.length / itemsPerPage);
if (currentPage > totalPages) {
currentPage = totalPages || 1;
}
renderPagination(totalPages);
renderHostsTable();
updatePaginationInfo();
}
// 渲染分页控件
function renderPagination(totalPages) {
const pagination = document.getElementById('pagination');
pagination.innerHTML = '';
// 上一页
const prevLi = document.createElement('li');
prevLi.className = `page-item ${currentPage === 1 ? 'disabled' : ''}`;
prevLi.innerHTML = '<a class="page-link" href="#"><i class="bi bi-chevron-left"></i></a>';
prevLi.onclick = () => {
if (currentPage > 1) {
currentPage--;
filterAndRenderTable();
}
};
pagination.appendChild(prevLi);
// 页码
for (let i = 1; i <= totalPages; i++) {
const li = document.createElement('li');
li.className = `page-item ${currentPage === i ? 'active' : ''}`;
li.innerHTML = `<a class="page-link" href="#">${i}</a>`;
li.onclick = () => {
currentPage = i;
filterAndRenderTable();
};
pagination.appendChild(li);
}
// 下一页
const nextLi = document.createElement('li');
nextLi.className = `page-item ${currentPage === totalPages ? 'disabled' : ''}`;
nextLi.innerHTML = '<a class="page-link" href="#"><i class="bi bi-chevron-right"></i></a>';
nextLi.onclick = () => {
if (currentPage < totalPages) {
currentPage++;
filterAndRenderTable();
}
};
pagination.appendChild(nextLi);
}
// 渲染hosts表格
function renderHostsTable() {
const tbody = document.querySelector('#hosts-table tbody');
tbody.innerHTML = '';
const start = (currentPage - 1) * itemsPerPage;
const end = start + itemsPerPage;
const pageHosts = filteredHosts.slice(start, end);
pageHosts.forEach(([domain, ip]) => {
const tr = document.createElement('tr');
tr.innerHTML = `
<td>
<input type="text" value="${domain}" class="form-control domain-input">
<div class="duplicate-warning"></div>
</td>
<td>
<input type="text" value="${ip}" class="form-control ip-input">
</td>
<td class="text-center">
<button onclick="deleteHost(this)" class="btn btn-danger btn-sm btn-delete">
<i class="bi bi-trash"></i>
</button>
</td>
`;
tbody.appendChild(tr);
// 添加域名输入事件监听
const domainInput = tr.querySelector('.domain-input');
domainInput.addEventListener('input', function() {
const warningDiv = this.parentElement.querySelector('.duplicate-warning');
const domain = this.value.trim();
if (checkDuplicate(domain, this.closest('tr'))) {
warningDiv.textContent = '警告:该域名已存在';
} else {
warningDiv.textContent = '';
}
});
});
}
// 添加新host记录
document.getElementById('add-host').onclick = () => {
const tbody = document.querySelector('#hosts-table tbody');
const tr = document.createElement('tr');
tr.innerHTML = `
<td>
<input type="text" class="form-control domain-input">
<div class="duplicate-warning"></div>
</td>
<td>
<input type="text" class="form-control ip-input">
</td>
<td class="text-center">
<button onclick="deleteHost(this)" class="btn btn-danger btn-sm btn-delete">
<i class="bi bi-trash"></i>
</button>
</td>
`;
tbody.appendChild(tr);
// 添加域名输入事件监听
const domainInput = tr.querySelector('.domain-input');
domainInput.addEventListener('input', function() {
const warningDiv = this.parentElement.querySelector('.duplicate-warning');
const domain = this.value.trim();
if (checkDuplicate(domain, this.closest('tr'))) {
warningDiv.textContent = '警告:该域名已存在';
} else {
warningDiv.textContent = '';
}
});
};
// 删除host记录
function deleteHost(button) {
button.closest('tr').remove();
filterAndRenderTable();
}
// 保存更改
document.getElementById('save-hosts').onclick = async () => {
const newHosts = {};
const duplicates = [];
const rows = document.querySelectorAll('#hosts-table tbody tr');
rows.forEach(row => {
const domain = row.querySelector('.domain-input').value.trim();
const ip = row.querySelector('.ip-input').value.trim();
if (domain && ip) {
if (domain in newHosts) {
duplicates.push(domain);
}
newHosts[domain] = ip;
}
});
if (duplicates.length > 0) {
alert(`错误:存在重复的域名记录:\n${duplicates.join('\n')}`);
return;
}
try {
const response = await fetch('http://localhost:3001/api/config', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ hosts: newHosts })
});
if (response.ok) {
alert('配置已更新');
loadConfig();
} else {
alert('更新失败');
}
} catch (err) {
alert('更新失败: ' + err.message);
}
};
// 检查重复记录
function checkDuplicate(domain, currentRow) {
const rows = document.querySelectorAll('#hosts-table tbody tr');
let duplicateFound = false;
rows.forEach(row => {
if (row !== currentRow) {
const existingDomain = row.querySelector('.domain-input').value.trim();
if (domain === existingDomain) {
duplicateFound = true;
}
}
});
return duplicateFound;
}
// 更新分页信息
function updatePaginationInfo() {
const start = (currentPage - 1) * itemsPerPage + 1;
const end = Math.min(currentPage * itemsPerPage, filteredHosts.length);
const total = filteredHosts.length;
document.getElementById('showing-entries').textContent =
total === 0 ? '0-0' : `${start}-${end}`;
document.getElementById('total-entries').textContent = total;
}
// 添加搜索功能
document.getElementById('domain-search').addEventListener('input', filterAndRenderTable);
document.getElementById('ip-search').addEventListener('input', filterAndRenderTable);
// 初始加载
loadConfig();