let adminPassword = sessionStorage.getItem('adminPassword'); const loginSection = document.getElementById('loginSection'); const adminSection = document.getElementById('adminSection'); const loginError = document.getElementById('loginError'); const uploadMessage = document.getElementById('uploadMessage'); if (adminPassword) { checkAuth(); } else { showLogin(); } document.getElementById('loginButton').addEventListener('click', () => { adminPassword = document.getElementById('passwordInput').value; checkAuth(); }); document.getElementById('passwordInput').addEventListener('keydown', (e) => { if (e.key === 'Enter') document.getElementById('loginButton').click(); }); document.getElementById('uploadButton').addEventListener('click', async () => { const file = document.getElementById('uploadInput').files[0]; uploadMessage.textContent = ''; if (!file) { uploadMessage.textContent = '請選擇檔案。'; return; } const formData = new FormData(); formData.append('template', file); const res = await fetchAdmin('/api/admin/templates', { method: 'POST', body: formData }); const body = await res.json().catch(() => ({})); if (res.ok) { uploadMessage.textContent = `已上傳:${body.name}`; document.getElementById('uploadInput').value = ''; loadTemplates(); } else { uploadMessage.textContent = body.error || '上傳失敗。'; } }); async function checkAuth() { loginError.textContent = ''; try { const res = await fetchAdmin('/api/admin/check'); if (res.ok) { sessionStorage.setItem('adminPassword', adminPassword); showAdmin(); } else { loginError.textContent = '密碼錯誤。'; adminPassword = null; sessionStorage.removeItem('adminPassword'); showLogin(); } } catch { loginError.textContent = '連線失敗。'; } } function showLogin() { loginSection.hidden = false; adminSection.hidden = true; } function showAdmin() { loginSection.hidden = true; adminSection.hidden = false; loadTemplates(); } async function loadTemplates() { const list = document.getElementById('templateList'); try { const res = await fetch('/api/templates'); const { templates } = await res.json(); if (templates.length === 0) { list.innerHTML = '
'; return; } list.replaceChildren(...templates.map((name) => { const row = document.createElement('div'); row.style.cssText = 'display:flex;align-items:center;gap:12px;padding:8px 0;border-bottom:1px solid var(--border)'; const label = document.createElement('span'); label.textContent = name; label.style.flex = '1'; label.style.fontSize = '0.9rem'; const btn = document.createElement('button'); btn.className = 'secondary-button'; btn.textContent = '刪除'; btn.style.minHeight = '34px'; btn.style.padding = '0 14px'; btn.addEventListener('click', () => deleteTemplate(name, row)); row.append(label, btn); return row; })); } catch { list.innerHTML = ''; } } async function deleteTemplate(name, row) { if (!confirm(`確定要刪除「${name}」?此動作無法復原。`)) return; const res = await fetchAdmin(`/api/admin/templates/${encodeURIComponent(name)}`, { method: 'DELETE' }); if (res.ok) { row.remove(); if (!document.getElementById('templateList').children.length) { document.getElementById('templateList').innerHTML = ''; } } else { const body = await res.json().catch(() => ({})); alert(body.error || '刪除失敗。'); } } function fetchAdmin(url, options = {}) { const headers = new Headers(options.headers); headers.set('Authorization', `Basic ${btoa('admin:' + adminPassword)}`); return fetch(url, { ...options, headers }); }