Files
gia-gve-certificates/views/student.ejs
2026-07-01 09:18:06 +05:00

161 lines
6.5 KiB
Plaintext
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.0">
<title><%= student.last_name %> <%= student.first_name %> — Справки</title>
<link rel="stylesheet" href="/style.css">
</head>
<body>
<div class="container">
<nav class="nav">
<a href="/" class="btn">&larr; К списку</a>
<span class="user-bar"><%= user ? user.name : '' %></span>
<button id="logout-btn" class="btn btn-logout">Выйти</button>
</nav>
<h1><%= student.last_name %> <%= student.first_name %> <%= student.patronymic %></h1>
<p>Класс: <strong><%= student.class %></strong></p>
<div class="card">
<h2>Обязательные предметы</h2>
<form id="mandatory-form" class="mandatory-form">
<div class="form-row">
<label>Русский язык</label>
<input type="number" id="rus-score" class="input input-sm" placeholder="Первичный балл" value="<%= rusResult ? rusResult.primary_score || '' : '' %>">
<input type="number" id="rus-grade" class="input input-sm" placeholder="Оценка (2-5)" min="2" max="5" value="<%= rusResult ? rusResult.grade || '' : '' %>">
</div>
<div class="form-row">
<label>Математика</label>
<input type="number" id="math-score" class="input input-sm" placeholder="Первичный балл" value="<%= mathResult ? mathResult.primary_score || '' : '' %>">
<input type="number" id="math-grade" class="input input-sm" placeholder="Оценка (2-5)" min="2" max="5" value="<%= mathResult ? mathResult.grade || '' : '' %>">
</div>
<button type="submit" class="btn btn-green">Сохранить</button>
<span id="mandatory-msg" class="msg"></span>
</form>
</div>
<% if (electiveResults.length > 0) { %>
<div class="card">
<h2>Предметы по выбору (из протокола)</h2>
<table>
<thead>
<tr>
<th>Предмет</th>
<th>Первичный балл</th>
<th>Оценка</th>
</tr>
</thead>
<tbody>
<% electiveResults.forEach(r => { %>
<tr>
<td><%= r.subject_name %></td>
<td><%= r.primary_score !== null ? r.primary_score : '—' %></td>
<td><strong><%= r.grade !== null ? r.grade : '—' %></strong></td>
</tr>
<% }) %>
</tbody>
</table>
</div>
<% } %>
<div class="card">
<h2>Сформировать справку</h2>
<form id="cert-form">
<div class="form-row">
<label>
<input type="radio" name="cert-type" value="gia" checked onchange="toggleElectives()">
ГИА (ОГЭ) — 4 предмета, с первичными баллами
</label>
</div>
<div class="form-row">
<label>
<input type="radio" name="cert-type" value="gve" onchange="toggleElectives()">
ГВЭ — 2 предмета, только отметки
</label>
</div>
<div id="electives-block" style="margin-top:10px">
<p>Выберите 12 предмета для справки ГИА:</p>
<% electiveResults.forEach(r => { %>
<label class="checkbox-label">
<input type="checkbox" name="elective" value="<%= r.subject_code %>" class="elective-cb">
<%= r.subject_name %>
</label>
<% }) %>
<span id="elective-msg" class="msg"></span>
</div>
<button type="submit" class="btn btn-blue" style="margin-top:15px">Сформировать и распечатать</button>
</form>
</div>
</div>
<script>
window.__CSRF_TOKEN = '<%= csrfToken %>';
const _origFetch = window.fetch.bind(window);
window.fetch = function(input, init = {}) {
init.credentials = 'include';
const method = (init.method || 'GET').toUpperCase();
if (['POST','PUT','PATCH','DELETE'].includes(method)) {
if (!init.headers) init.headers = {};
init.headers['X-CSRF-Token'] = window.__CSRF_TOKEN || '';
}
return _origFetch(input, init);
};
document.getElementById('logout-btn').addEventListener('click', async () => {
await fetch('/api/logout', { method: 'POST' });
window.location.href = '/login';
});
document.getElementById('mandatory-form').addEventListener('submit', async (e) => {
e.preventDefault();
const score = v => { const n = parseInt(v,10); return isNaN(n)?null:n; };
const res = await fetch('/api/students/<%= student.id %>/mandatory', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
rus_score: score(document.getElementById('rus-score').value),
rus_grade: score(document.getElementById('rus-grade').value),
math_score: score(document.getElementById('math-score').value),
math_grade: score(document.getElementById('math-grade').value)
})
});
const msg = document.getElementById('mandatory-msg');
if (res.ok) { msg.textContent = 'Сохранено'; msg.className = 'msg msg-ok'; }
else { msg.textContent = 'Ошибка'; msg.className = 'msg msg-err'; }
});
document.querySelectorAll('.elective-cb').forEach(cb => {
cb.addEventListener('change', () => {
const checked = document.querySelectorAll('.elective-cb:checked');
if (checked.length > 2) cb.checked = false;
});
});
function toggleElectives() {
const type = document.querySelector('input[name="cert-type"]:checked').value;
document.getElementById('electives-block').style.display = type === 'gia' ? 'block' : 'none';
}
document.getElementById('cert-form').addEventListener('submit', (e) => {
e.preventDefault();
const type = document.querySelector('input[name="cert-type"]:checked').value;
const electives = [...document.querySelectorAll('.elective-cb:checked')].map(cb => cb.value);
const msg = document.getElementById('elective-msg');
if (type === 'gia' && electives.length < 1) {
msg.textContent = 'Выберите хотя бы 1 предмет для ГИА';
msg.className = 'msg msg-err';
return;
}
msg.textContent = '';
const url = `/certificate/<%= student.id %>?type=${type}&subjects=${electives.join(',')}`;
window.open(url, '_blank');
});
</script>
</body>
</html>