| 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(); |