Files

63 lines
6.2 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const $ = (selector) => document.querySelector(selector);
const escapeHtml = (value) => String(value ?? '').replace(/[&<>'"]/g, (char) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', "'": '&#39;', '"': '&quot;' }[char]));
let modules = [];
let editingId = null;
function token() { return sessionStorage.getItem('daily_digest_admin_token') || ''; }
function headers(json = false) { const value = { 'X-Admin-Token': token() }; if (json) value['Content-Type'] = 'application/json'; return value; }
function message(selector, text, type = '') { const el = $(selector); el.textContent = text; el.className = `form-message ${type}`; }
async function api(path, options = {}) {
const response = await fetch(path, { ...options, headers: { ...headers(Boolean(options.body)), ...(options.headers || {}) } });
const payload = await response.json().catch(() => ({}));
if (!response.ok) throw new Error(payload.error || `请求失败 (${response.status})`);
return payload;
}
function renderModuleOptions(selected = []) {
$('#moduleOptions').innerHTML = modules.map((module) => `<label class="module-option"><input type="checkbox" value="${escapeHtml(module.module_key)}" ${selected.includes(module.module_key) ? 'checked' : ''}><span>${escapeHtml(module.module_name)}</span></label>`).join('');
}
function selectedModules() { return [...document.querySelectorAll('#moduleOptions input:checked')].map((input) => input.value); }
function renderRecipients(recipients) {
$('#recipientCount').textContent = recipients.length;
if (!recipients.length) { $('#recipientList').innerHTML = '<div class="empty-state"><strong>还没有收件邮箱</strong><span>在左侧添加第一个日报收件人。</span></div>'; return; }
const names = Object.fromEntries(modules.map((module) => [module.module_key, module.module_name]));
$('#recipientList').innerHTML = recipients.map((recipient) => `<div class="recipient-item">
<div><div class="recipient-email">${escapeHtml(recipient.email)} ${recipient.enabled ? '' : '<span class="tag">已停用</span>'}</div><div class="recipient-sub">${escapeHtml(recipient.display_name || '未设置名称')} · 每天 ${escapeHtml(String(recipient.send_time).slice(0, 5))} · ${escapeHtml(recipient.timezone)}</div><div class="chips">${recipient.send_all_modules ? '<span class="chip">全部模块</span>' : (recipient.modules || []).map((key) => `<span class="chip">${escapeHtml(names[key] || key)}</span>`).join('')}</div></div>
<div class="recipient-actions"><button class="icon-button" type="button" data-edit="${recipient.id}" title="编辑">✎</button><button class="icon-button delete" type="button" data-delete="${recipient.id}" title="删除">×</button></div>
</div>`).join('');
document.querySelectorAll('[data-edit]').forEach((button) => button.addEventListener('click', () => editRecipient(recipients.find((item) => item.id === Number(button.dataset.edit)))));
document.querySelectorAll('[data-delete]').forEach((button) => button.addEventListener('click', () => removeRecipient(Number(button.dataset.delete))));
}
async function loadRecipients() {
try { renderRecipients((await api('/api/recipients')).recipients); }
catch (error) { $('#recipientList').innerHTML = `<div class="empty-state"><strong>无法读取邮箱设置</strong><span>${escapeHtml(error.message)}</span></div>`; }
}
function editRecipient(recipient) {
editingId = recipient.id; $('#formTitle').textContent = '编辑收件邮箱'; $('#submitLabel').textContent = '保存修改'; $('#cancelEdit').classList.remove('hidden');
$('#recipientId').value = recipient.id; $('#emailInput').value = recipient.email; $('#emailInput').disabled = true; $('#nameInput').value = recipient.display_name || ''; $('#timeInput').value = String(recipient.send_time).slice(0, 5); $('#timezoneInput').value = recipient.timezone || 'Asia/Shanghai'; $('#allModulesInput').checked = recipient.send_all_modules; renderModuleOptions(recipient.modules || []); window.scrollTo({ top: 0, behavior: 'smooth' });
}
function resetForm() { editingId = null; $('#formTitle').textContent = '添加收件邮箱'; $('#submitLabel').textContent = '保存邮箱设置'; $('#cancelEdit').classList.add('hidden'); $('#recipientForm').reset(); $('#emailInput').disabled = false; $('#timeInput').value = '07:30'; $('#timezoneInput').value = 'Asia/Shanghai'; renderModuleOptions([]); message('#formMessage', ''); }
async function removeRecipient(id) {
if (!window.confirm('确定删除这个收件邮箱吗?历史发送记录会保留,但以后不会再发送。')) return;
try { await api(`/api/recipients/${id}`, { method: 'DELETE' }); message('#tokenMessage', '邮箱已删除', 'success'); await loadRecipients(); }
catch (error) { message('#tokenMessage', error.message, 'error'); }
}
$('#saveToken').addEventListener('click', async () => { const value = $('#tokenInput').value.trim(); if (!value) return message('#tokenMessage', '请输入管理令牌', 'error'); sessionStorage.setItem('daily_digest_admin_token', value); message('#tokenMessage', '令牌已保存,正在验证…'); await loadRecipients(); });
$('#tokenInput').value = token();
$('#cancelEdit').addEventListener('click', resetForm);
$('#allModulesInput').addEventListener('change', (event) => { document.querySelectorAll('#moduleOptions input').forEach((input) => { input.disabled = event.target.checked; }); });
$('#recipientForm').addEventListener('submit', async (event) => {
event.preventDefault();
const body = { email: $('#emailInput').value.trim(), display_name: $('#nameInput').value.trim(), send_time: $('#timeInput').value, timezone: $('#timezoneInput').value.trim(), send_all_modules: $('#allModulesInput').checked, modules: selectedModules() };
try { await api(editingId ? `/api/recipients/${editingId}` : '/api/recipients', { method: editingId ? 'PUT' : 'POST', body: JSON.stringify(body) }); message('#formMessage', editingId ? '邮箱设置已更新' : '邮箱已添加', 'success'); resetForm(); await loadRecipients(); }
catch (error) { message('#formMessage', error.message, 'error'); }
});
(async function init() { try { modules = (await fetch('/api/modules').then((response) => response.json())).modules || []; renderModuleOptions(); await loadRecipients(); } catch (error) { message('#tokenMessage', error.message, 'error'); } })();