// 管理员密码(实际应用中应该使用更安全的方式)
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');
}
}
});
}
}