248 lines
6.7 KiB
JavaScript
248 lines
6.7 KiB
JavaScript
// 页面加载时初始化
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
loadData();
|
|
initForm();
|
|
initModal();
|
|
});
|
|
|
|
// 全局变量存储当前数据和排序状态
|
|
let currentRecords = [];
|
|
let currentSortField = null;
|
|
let currentSortOrder = 'asc'; // 'asc' 或 'desc'
|
|
|
|
// 初始化表单
|
|
function initForm() {
|
|
const form = document.getElementById('submitForm');
|
|
const noteInput = document.getElementById('note');
|
|
const noteCount = document.getElementById('noteCount');
|
|
|
|
// 字数统计
|
|
noteInput.addEventListener('input', () => {
|
|
noteCount.textContent = noteInput.value.length;
|
|
});
|
|
|
|
// 表单提交
|
|
form.addEventListener('submit', async (e) => {
|
|
e.preventDefault();
|
|
await submitForm();
|
|
});
|
|
}
|
|
|
|
// 提交表单
|
|
async function submitForm() {
|
|
const form = document.getElementById('submitForm');
|
|
const name = document.getElementById('name').value;
|
|
const link = document.getElementById('link').value;
|
|
const note = document.getElementById('note').value;
|
|
|
|
try {
|
|
const submitBtn = form.querySelector('button[type="submit"]');
|
|
submitBtn.disabled = true;
|
|
submitBtn.textContent = '提交中...';
|
|
|
|
const response = await fetch('/api/submit', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify({
|
|
name: name,
|
|
link: link,
|
|
note: note
|
|
})
|
|
});
|
|
|
|
const result = await response.json();
|
|
|
|
if (result.success) {
|
|
alert('✅ 提交成功!');
|
|
form.reset();
|
|
document.getElementById('noteCount').textContent = '0';
|
|
loadData(); // 刷新数据列表
|
|
} else {
|
|
alert('❌ ' + result.message);
|
|
}
|
|
} catch (error) {
|
|
alert('❌ 提交失败: ' + error.message);
|
|
} finally {
|
|
const submitBtn = form.querySelector('button[type="submit"]');
|
|
submitBtn.disabled = false;
|
|
submitBtn.textContent = '提交数据';
|
|
}
|
|
}
|
|
|
|
// 加载数据列表
|
|
async function loadData() {
|
|
try {
|
|
const response = await fetch('/api/list');
|
|
const result = await response.json();
|
|
|
|
if (result.success) {
|
|
currentRecords = result.records;
|
|
renderTable(currentRecords);
|
|
} else {
|
|
alert('加载数据失败: ' + result.message);
|
|
}
|
|
} catch (error) {
|
|
console.error('加载数据出错:', error);
|
|
document.getElementById('dataTableBody').innerHTML = `
|
|
<tr><td colspan="9" class="loading">加载失败,请刷新重试</td></tr>
|
|
`;
|
|
}
|
|
}
|
|
|
|
// 渲染表格
|
|
function renderTable(records) {
|
|
const tbody = document.getElementById('dataTableBody');
|
|
|
|
if (records.length === 0) {
|
|
tbody.innerHTML = '<tr><td colspan="9" class="loading">暂无数据</td></tr>';
|
|
return;
|
|
}
|
|
|
|
tbody.innerHTML = records.map((record, index) => {
|
|
const hasNaga = record.nagaLink && record.nagaLink.trim() !== '';
|
|
const nagaStatus = hasNaga
|
|
? '<span class="has-naga">✔ 有</span>'
|
|
: '<span class="no-naga">✘ 无</span>';
|
|
|
|
const nagaLinkDisplay = hasNaga
|
|
? `<a href="${escapeHtml(record.nagaLink)}" target="_blank">查看链接</a>`
|
|
: '-';
|
|
|
|
const nagaNoteDisplay = record.nagaNote && record.nagaNote.trim() !== ''
|
|
? escapeHtml(record.nagaNote)
|
|
: '-';
|
|
|
|
const imagesDisplay = record.images && record.images.length > 0
|
|
? `<div class="image-thumbs">
|
|
${record.images.map(img => `
|
|
<img src="${img}" class="thumb-img" onclick="showImages(${JSON.stringify(record.images).replace(/"/g, '"')})">
|
|
`).join('')}
|
|
</div>`
|
|
: '-';
|
|
|
|
return `
|
|
<tr>
|
|
<td>${index + 1}</td>
|
|
<td>${escapeHtml(record.submitTime)}</td>
|
|
<td>${escapeHtml(record.name)}</td>
|
|
<td class="link-cell"><a href="${escapeHtml(record.link)}" target="_blank">查看牌谱</a></td>
|
|
<td class="note-cell">${record.note ? escapeHtml(record.note) : '-'}</td>
|
|
<td>${nagaStatus}</td>
|
|
<td class="link-cell">${nagaLinkDisplay}</td>
|
|
<td class="note-cell">${nagaNoteDisplay}</td>
|
|
<td>${imagesDisplay}</td>
|
|
</tr>
|
|
`;
|
|
}).join('');
|
|
}
|
|
|
|
// 显示图片模态框
|
|
function showImages(images) {
|
|
const modal = document.getElementById('imageModal');
|
|
const modalImages = document.getElementById('modalImages');
|
|
|
|
modalImages.innerHTML = images.map(img => `
|
|
<img src="${img}" alt="图片">
|
|
`).join('');
|
|
|
|
modal.style.display = 'block';
|
|
}
|
|
|
|
// 初始化模态框
|
|
function initModal() {
|
|
const modal = document.getElementById('imageModal');
|
|
const closeBtn = modal.querySelector('.close');
|
|
|
|
closeBtn.onclick = () => {
|
|
modal.style.display = 'none';
|
|
};
|
|
|
|
window.onclick = (event) => {
|
|
if (event.target === modal) {
|
|
modal.style.display = 'none';
|
|
}
|
|
};
|
|
}
|
|
|
|
// 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;
|
|
});
|
|
|
|
renderTable(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');
|
|
}
|
|
}
|
|
});
|
|
}
|
|
} |