// 管理员密码(实际应用中应该使用更安全的方式) const ADMIN_PASSWORD = 'JLUnaga2026'; // 全局变量存储当前数据和排序状态 let currentRecords = []; let currentSortField = null; let currentSortOrder = 'asc'; // 'asc' 或 'desc' // 页面加载时初始化 document.addEventListener('DOMContentLoaded', () => { checkAuth(); initAuthForm(); initEditForm(); initModal(); }); // 检查认证状态 function checkAuth() { const isAuth = localStorage.getItem('adminAuth') === 'true'; if (isAuth) { showAdminSection(); loadAdminData(); } } // 初始化认证表单 function initAuthForm() { const authForm = document.getElementById('authForm'); authForm.addEventListener('submit', (e) => { e.preventDefault(); const password = document.getElementById('adminPassword').value; if (password === ADMIN_PASSWORD) { localStorage.setItem('adminAuth', 'true'); showAdminSection(); loadAdminData(); } else { alert('❌ 密码错误'); } }); } // 显示管理员区域 function showAdminSection() { document.getElementById('authSection').style.display = 'none'; document.getElementById('adminSection').style.display = 'block'; } // 加载管理员数据 async function loadAdminData() { try { const response = await fetch('/api/list'); const result = await response.json(); if (result.success) { currentRecords = result.records; renderAdminTable(currentRecords); } else { alert('加载数据失败: ' + result.message); } } catch (error) { console.error('加载数据出错:', error); document.getElementById('adminTableBody').innerHTML = ` 加载失败,请刷新重试 `; } } // 渲染管理员表格 function renderAdminTable(records) { const tbody = document.getElementById('adminTableBody'); if (records.length === 0) { tbody.innerHTML = '暂无数据'; return; } tbody.innerHTML = records.map((record, index) => { const hasNaga = record.nagaLink && record.nagaLink.trim() !== ''; const nagaStatus = hasNaga ? '✔ 有' : '✘ 无'; const nagaLinkDisplay = hasNaga ? `查看链接` : '-'; const nagaNoteDisplay = record.nagaNote && record.nagaNote.trim() !== '' ? escapeHtml(record.nagaNote) : '-'; const imagesDisplay = record.images && record.images.length > 0 ? `
${record.images.map(img => ` `).join('')}
` : '-'; return ` ${index + 1} ${escapeHtml(record.submitTime)} ${escapeHtml(record.name)} 查看牌谱 ${record.note ? escapeHtml(record.note) : '-'} ${nagaStatus} ${nagaLinkDisplay} ${nagaNoteDisplay} ${imagesDisplay} `; }).join(''); } // 打开编辑模态框 async function openEditModal(id) { try { const response = await fetch('/api/list'); const result = await response.json(); if (!result.success) { alert('获取数据失败'); return; } const record = result.records.find(r => r.id === id); if (!record) { alert('记录不存在'); return; } // 填充表单 document.getElementById('editId').value = record.id; document.getElementById('editNagaLink').value = record.nagaLink || ''; document.getElementById('editNagaNote').value = record.nagaNote || ''; document.getElementById('nagaNoteCount').textContent = (record.nagaNote || '').length; // 清空图片预览和已有图片 document.getElementById('imagePreview').innerHTML = ''; document.getElementById('editImages').value = ''; // 显示已有图片 const existingImagesDiv = document.getElementById('existingImages'); if (record.images && record.images.length > 0) { existingImagesDiv.innerHTML = record.images.map(img => `
已上传图片
`).join(''); } else { existingImagesDiv.innerHTML = '

暂无图片

'; } // 显示只读信息 const readonlyInfo = document.getElementById('readonlyInfo'); readonlyInfo.innerHTML = `

人名: ${escapeHtml(record.name)}

提交时间: ${escapeHtml(record.submitTime)}

牌谱链接: 查看

备注: ${record.note ? escapeHtml(record.note) : '无'}

`; // 显示模态框 document.getElementById('editModal').style.display = 'block'; } catch (error) { alert('打开编辑器失败: ' + error.message); } } // 关闭编辑模态框 function closeEditModal() { document.getElementById('editModal').style.display = 'none'; } // 初始化编辑表单 function initEditForm() { const editForm = document.getElementById('editForm'); const nagaNoteInput = document.getElementById('editNagaNote'); const nagaNoteCount = document.getElementById('nagaNoteCount'); const imageInput = document.getElementById('editImages'); const imagePreview = document.getElementById('imagePreview'); // 字数统计 nagaNoteInput.addEventListener('input', () => { nagaNoteCount.textContent = nagaNoteInput.value.length; }); // 图片预览 imageInput.addEventListener('change', (e) => { imagePreview.innerHTML = ''; const files = e.target.files; if (files.length > 10) { alert('最多只能上传 10 张图片'); imageInput.value = ''; return; } Array.from(files).forEach(file => { if (file.size > 5 * 1024 * 1024) { alert(`文件 ${file.name} 超过 5MB`); return; } const reader = new FileReader(); reader.onload = (e) => { const div = document.createElement('div'); div.className = 'preview-item'; div.innerHTML = `预览`; imagePreview.appendChild(div); }; reader.readAsDataURL(file); }); }); // 表单提交 editForm.addEventListener('submit', async (e) => { e.preventDefault(); await updateRecord(); }); } // 更新记录 async function updateRecord() { const id = document.getElementById('editId').value; const nagaLink = document.getElementById('editNagaLink').value; const nagaNote = document.getElementById('editNagaNote').value; const imageInput = document.getElementById('editImages'); try { // 获取已有图片列表 const response = await fetch('/api/list'); const result = await response.json(); const record = result.records.find(r => r.id === parseInt(id)); const existingImages = record ? record.images : []; // 创建 FormData const formData = new FormData(); formData.append('id', id); formData.append('nagaLink', nagaLink.trim()); formData.append('nagaNote', nagaNote.trim()); formData.append('existingImages', JSON.stringify(existingImages)); // 添加新图片 if (imageInput.files.length > 0) { Array.from(imageInput.files).forEach(file => { formData.append('images', file); }); } const updateResponse = await fetch('/api/admin/update', { method: 'POST', body: formData }); const updateResult = await updateResponse.json(); if (updateResult.success) { alert('✅ 更新成功!'); closeEditModal(); loadAdminData(); } else { alert('❌ ' + updateResult.message); } } catch (error) { alert('❌ 更新失败: ' + error.message); } } // 删除单张图片 async function removeImage(id, imagePath) { if (!confirm('确定要删除这张图片吗?')) { return; } try { const response = await fetch('/api/admin/delete-image', { method: 'DELETE', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ id: id, imagePath: imagePath }) }); const result = await response.json(); if (result.success) { alert('✅ 图片删除成功!'); // 重新打开编辑框以刷新图片列表 openEditModal(id); } else { alert('❌ ' + result.message); } } catch (error) { alert('❌ 删除图片失败: ' + error.message); } } // 删除记录 async function deleteRecord(id) { if (!confirm('确定要删除这条记录吗?此操作不可恢复!')) { return; } try { const response = await fetch(`/api/admin/delete/${id}`, { method: 'DELETE' }); const result = await response.json(); if (result.success) { alert('✅ 删除成功!'); loadAdminData(); } else { alert('❌ ' + result.message); } } catch (error) { alert('❌ 删除失败: ' + error.message); } } // 显示图片模态框 function showImages(images) { const modal = document.getElementById('imageModal'); const modalImages = document.getElementById('modalImages'); modalImages.innerHTML = images.map(img => ` 图片 `).join(''); modal.style.display = 'block'; } // 初始化图片模态框 function initModal() { const imageModal = document.getElementById('imageModal'); const editModal = document.getElementById('editModal'); // 图片模态框关闭 imageModal.querySelector('.close').onclick = () => { imageModal.style.display = 'none'; }; // 点击模态框外部关闭 window.onclick = (event) => { if (event.target === imageModal) { imageModal.style.display = 'none'; } if (event.target === editModal) { closeEditModal(); } }; } // HTML 转义函数 function escapeHtml(text) { const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } // 排序表格 function sortTable(field) { // 如果点击同一列,切换排序方向 if (currentSortField === field) { currentSortOrder = currentSortOrder === 'asc' ? 'desc' : 'asc'; } else { currentSortField = field; currentSortOrder = 'asc'; } // 复制数组进行排序 const sortedRecords = [...currentRecords]; sortedRecords.sort((a, b) => { let valueA, valueB; switch(field) { case 'id': valueA = a.id; valueB = b.id; break; case 'submitTime': valueA = a.submitTime; valueB = b.submitTime; break; case 'name': valueA = a.name.toLowerCase(); valueB = b.name.toLowerCase(); break; case 'hasNaga': valueA = (a.nagaLink && a.nagaLink.trim() !== '') ? 1 : 0; valueB = (b.nagaLink && b.nagaLink.trim() !== '') ? 1 : 0; break; default: return 0; } if (valueA < valueB) { return currentSortOrder === 'asc' ? -1 : 1; } if (valueA > valueB) { return currentSortOrder === 'asc' ? 1 : -1; } return 0; }); renderAdminTable(sortedRecords); updateSortIcons(); } // 更新排序图标 function updateSortIcons() { // 移除所有排序图标的激活状态 document.querySelectorAll('.sort-icon').forEach(icon => { icon.textContent = '⇅'; icon.classList.remove('sort-asc', 'sort-desc'); }); // 如果有当前排序字段,更新对应图标 if (currentSortField) { const headers = document.querySelectorAll('th.sortable'); headers.forEach(th => { const onclick = th.getAttribute('onclick'); if (onclick && onclick.includes(`'${currentSortField}'`)) { const icon = th.querySelector('.sort-icon'); if (icon) { icon.textContent = currentSortOrder === 'asc' ? '↑' : '↓'; icon.classList.add(currentSortOrder === 'asc' ? 'sort-asc' : 'sort-desc'); } } }); } }