Files
OpenLesson/public/info.js
Калугин Олег Александрович 2d007d2359 hfcg
2026-04-13 12:06:31 +00:00

169 lines
6.4 KiB
JavaScript
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.
// public/info.js страница просмотра записей
let currentUser = null;
let currentRegistrations = [];
document.addEventListener('DOMContentLoaded', async () => {
await checkAuth();
await loadFilterOptions();
loadRegistrations();
setupEventListeners();
});
async function checkAuth() {
try {
const res = await fetch('/api/me');
const data = await res.json();
if (!data.authenticated || (data.user.role !== 'admin' && data.user.role !== 'user')) {
window.location.href = '/login.html';
return;
}
currentUser = data.user;
document.getElementById('userInfo').innerHTML = `👋 ${currentUser.full_name} (${currentUser.role})`;
} catch (err) {
window.location.href = '/login.html';
}
}
async function loadFilterOptions() {
try {
const [classes, teachers, subjects] = await Promise.all([
fetch('/api/filter-options/class-names').then(r => r.json()),
fetch('/api/filter-options/teachers').then(r => r.json()),
fetch('/api/filter-options/subjects').then(r => r.json())
]);
populateSelect('filterClass', classes, 'Все классы');
populateSelect('filterTeacher', teachers, 'Все учителя');
populateSelect('filterSubject', subjects, 'Все предметы');
} catch (err) {
console.error('Ошибка загрузки опций', err);
}
}
function populateSelect(selectId, options, defaultLabel) {
const select = document.getElementById(selectId);
if (!select) return;
select.innerHTML = `<option value="">${defaultLabel}</option>`;
options.forEach(opt => {
const option = document.createElement('option');
option.value = opt;
option.textContent = opt;
select.appendChild(option);
});
}
async function loadRegistrations() {
const params = new URLSearchParams({
parent_name: document.getElementById('filterParentName').value,
class_name: document.getElementById('filterClass').value,
subject: document.getElementById('filterSubject').value,
teacher: document.getElementById('filterTeacher').value
});
try {
const res = await fetch(`/api/info/registrations?${params}`);
currentRegistrations = await res.json();
renderTable(currentRegistrations);
document.getElementById('recordsCount').innerText = `Найдено: ${currentRegistrations.length}`;
} catch (err) {
console.error(err);
document.getElementById('tableBody').innerHTML = '<td><td colspan="9">Ошибка загрузки</td></tr>';
}
}
function renderTable(registrations) {
const tbody = document.getElementById('tableBody');
if (!registrations.length) {
tbody.innerHTML = '<tr><td colspan="9">Нет записей</td></tr>';
return;
}
tbody.innerHTML = registrations.map(reg => {
let dateStr = '', timeStr = '';
if (reg.topic === 'Консультация' && reg.date && reg.time) {
dateStr = escapeHtml(reg.date);
timeStr = escapeHtml(reg.time);
} else {
dateStr = 'Согласно расписания';
timeStr = '';
}
return `
<tr>
<td>${escapeHtml(reg.parent_name)}</td>
<td>${escapeHtml(reg.parent_phone)}</td>
<td>${escapeHtml(reg.class_name)}</td>
<td>${escapeHtml(reg.subject)}</td>
<td>${escapeHtml(reg.teacher)}</td>
<td>${escapeHtml(reg.topic || '—')}</td>
<td>${dateStr}</td>
<td>${timeStr}</td>
<td>${new Date(reg.created_at).toLocaleString()}</td>
</tr>
`;
}).join('');
}
function escapeHtml(str) {
if (!str) return '';
return str.replace(/[&<>]/g, function(m) {
if (m === '&') return '&amp;';
if (m === '<') return '&lt;';
if (m === '>') return '&gt;';
return m;
});
}
function exportToCSV() {
if (!currentRegistrations.length) {
alert('Нет данных для экспорта');
return;
}
const headers = ['ФИО родителя', 'Телефон', 'Класс', 'Предмет', 'Учитель', 'Тема урока', 'Дата урока', 'Время', 'Дата регистрации'];
const rows = currentRegistrations.map(reg => {
let dateVal = '', timeVal = '';
if (reg.topic === 'Консультация' && reg.date && reg.time) {
dateVal = reg.date;
timeVal = reg.time;
} else {
dateVal = 'Согласно расписания';
timeVal = '';
}
return [
reg.parent_name,
reg.parent_phone,
reg.class_name,
reg.subject,
reg.teacher,
reg.topic || '',
dateVal,
timeVal,
new Date(reg.created_at).toLocaleString()
];
});
const csvContent = [headers, ...rows]
.map(row => row.map(cell => `"${String(cell).replace(/"/g, '""')}"`).join(';'))
.join('\n');
const blob = new Blob(['\uFEFF' + csvContent], { type: 'text/csv;charset=utf-8;' });
const link = document.createElement('a');
const url = URL.createObjectURL(blob);
link.href = url;
link.setAttribute('download', 'zapis_roditelei.csv');
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
}
function setupEventListeners() {
document.getElementById('applyFiltersBtn')?.addEventListener('click', () => loadRegistrations());
document.getElementById('resetFiltersBtn')?.addEventListener('click', () => {
document.getElementById('filterParentName').value = '';
document.getElementById('filterClass').value = '';
document.getElementById('filterSubject').value = '';
document.getElementById('filterTeacher').value = '';
loadRegistrations();
});
document.getElementById('exportBtn')?.addEventListener('click', exportToCSV);
document.getElementById('logoutBtn')?.addEventListener('click', async () => {
await fetch('/api/logout', { method: 'POST' });
window.location.href = '/';
});
}