Files
WhatIDo/public/links.html
T

180 lines
7.6 KiB
HTML
Raw 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.
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Ссылки — Админ-панель</title>
<link rel="stylesheet" href="admin.css">
</head>
<body data-page="links">
<div class="layout">
<div class="sidebar" id="sidebar"></div>
<div class="main">
<h2>Ссылки</h2>
<p style="color:var(--muted);font-size:.85rem;margin-bottom:20px;max-width:680px">Каждая ссылка открывает публичную страницу с карточками записей выбранной группы за указанный период — без входа и выбора параметров.</p>
<div class="list" id="linksList"><div class="empty">Загрузка...</div></div>
</div>
</div>
<div class="modal-overlay" id="linkModal" onclick="if(event.target===this)closeLinkModal()">
<div class="edit-modal">
<h3 id="linkModalTitle">Новая ссылка</h3>
<div>
<label>Название</label>
<input type="text" id="linkName" placeholder="Например: СБ1400 05.09">
</div>
<div>
<label>Группа</label>
<select id="linkGroup"><option value="">— без группы —</option></select>
</div>
<div>
<label>Ученик (необязательно)</label>
<input type="text" id="linkStudent" list="linkStudentList" placeholder="Все / введите имя..."><datalist id="linkStudentList"></datalist>
</div>
<div style="display:flex;gap:12px">
<div style="flex:1">
<label>С</label>
<input type="date" id="linkDateFrom">
</div>
<div style="flex:1">
<label>По</label>
<input type="date" id="linkDateTo">
</div>
</div>
<div class="actions">
<button class="cancel" onclick="closeLinkModal()">Отмена</button>
<button class="save" onclick="saveLink()">Сохранить</button>
</div>
</div>
</div>
<div class="toast" id="toast"></div>
<script src="admin.js"></script>
<script>
let links = [];
let groups = [];
let editingId = null;
let studentsLoaded = false;
function linkUrl(token) { return `${location.origin}/s/${token}`; }
async function loadLinks() {
const res = await fetch(`${API}/api/links`, { headers: hdr() });
links = await res.json();
const el = document.getElementById('linksList');
if (!links.length) { el.innerHTML = '<div class="empty">Ссылок пока нет. Создайте её в Журнале кнопкой «Ссылка».</div>'; return; }
el.innerHTML = links.map(l => `
<div class="item">
<div style="min-width:0">
<div class="name">${esc(l.name)}</div>
<div style="font-size:.8rem;color:var(--muted);margin-top:2px">
${l.group_name ? `Группа: <b>${esc(l.group_name)}</b>` : ''}
${l.student_name ? `${l.group_name ? ' · ' : ''}Ученик: <b>${esc(l.student_name)}</b>` : ''}
${l.date_from || l.date_to ? ` · период: <b>${l.date_from ? l.date_from.split('-').reverse().join('.') : '…'}</b> — <b>${l.date_to ? l.date_to.split('-').reverse().join('.') : '…'}</b>` : ' · весь период'}
· создана ${new Date(l.created_at).toLocaleString('ru')}
</div>
</div>
<div style="display:flex;gap:8px;flex-shrink:0;align-items:center">
<a class="btn-link" style="text-decoration:none" href="/s/${l.token}" target="_blank" title="Открыть">Открыть</a>
<button class="btn-link" onclick="copyText('${linkUrl(l.token)}')" title="Копировать ссылку">Копировать</button>
<button class="btn-link" onclick="openLinkEdit(${l.id})" title="Редактировать">✎</button>
<button class="btn-link" style="color:var(--muted)" onclick="delLink(${l.id})" title="Удалить">&times;</button>
</div>
</div>
`).join('');
}
function fmtDate(d) { const [y, m, day] = (d || '').split('-'); return d ? `${day}.${m}.${y}` : ''; }
async function openLinkModal() {
editingId = null;
document.getElementById('linkModalTitle').textContent = 'Новая ссылка';
document.getElementById('linkName').value = '';
document.getElementById('linkDateFrom').value = '';
document.getElementById('linkDateTo').value = '';
if (!groups.length) {
const res = await fetch(`${API}/api/groups`, { headers: hdr() });
groups = await res.json();
document.getElementById('linkGroup').innerHTML = '<option value="">— без группы —</option>' +
groups.map(g => `<option value="${g.id}">${esc(g.name)}</option>`).join('');
}
if (!studentsLoaded) {
const res = await fetch(`${API}/api/students/names`, { headers: hdr() });
const names = await res.json();
const dl = document.getElementById('linkStudentList');
dl.innerHTML = names.map(n => `<option value="${esc(n)}">`).join('');
studentsLoaded = true;
}
document.getElementById('linkModal').classList.add('open');
}
async function openLinkEdit(id) {
const l = links.find(x => x.id === id);
if (!l) return;
editingId = id;
document.getElementById('linkModalTitle').textContent = 'Редактирование ссылки';
document.getElementById('linkName').value = l.name;
document.getElementById('linkDateFrom').value = l.date_from || '';
document.getElementById('linkDateTo').value = l.date_to || '';
if (!groups.length) {
const res = await fetch(`${API}/api/groups`, { headers: hdr() });
groups = await res.json();
document.getElementById('linkGroup').innerHTML = '<option value="">— без группы —</option>' +
groups.map(g => `<option value="${g.id}">${esc(g.name)}</option>`).join('');
}
document.getElementById('linkGroup').value = l.group_id || '';
if (!studentsLoaded) {
const res = await fetch(`${API}/api/students/names`, { headers: hdr() });
const names = await res.json();
const dl = document.getElementById('linkStudentList');
dl.innerHTML = names.map(n => `<option value="${esc(n)}">`).join('');
studentsLoaded = true;
}
document.getElementById('linkStudent').value = l.student_name || '';
document.getElementById('linkModal').classList.add('open');
}
function closeLinkModal() {
document.getElementById('linkModal').classList.remove('open');
editingId = null;
}
async function saveLink() {
const name = document.getElementById('linkName').value.trim();
const group_id = document.getElementById('linkGroup').value;
const student_name = document.getElementById('linkStudent').value;
const date_from = document.getElementById('linkDateFrom').value;
const date_to = document.getElementById('linkDateTo').value;
if (!name) { alert('Введите название'); return; }
const body = JSON.stringify({ name, group_id: group_id || null, student_name: student_name || null, date_from: date_from || null, date_to: date_to || null });
const res = await fetch(editingId ? `${API}/api/links/${editingId}` : `${API}/api/links`, {
method: editingId ? 'PUT' : 'POST',
headers: hdrJson(),
body
});
if (res.ok) {
closeLinkModal();
loadLinks();
showToast(editingId ? 'Ссылка обновлена' : 'Ссылка создана');
} else {
const err = await res.json();
alert(err.error || 'Ошибка');
}
}
async function delLink(id) {
if (!confirm('Удалить ссылку?')) return;
await fetch(`${API}/api/links/${id}`, { method: 'DELETE', headers: hdr() });
loadLinks();
showToast('Ссылка удалена');
}
(async () => {
if (await checkAuth()) {
buildSidebar(document.body.dataset.page);
loadLinks();
}
})();
</script>
</body>
</html>