const express = require('express'); const { dbGet, dbAll } = require('../db'); const router = express.Router(); const requireAuth = (req, res, next) => { if (!req.session.user) return res.redirect('/login'); next(); }; router.get('/login', (req, res) => { if (req.session.user) return res.redirect('/'); res.render('login'); }); router.get('/', requireAuth, (req, res) => { res.render('index', { user: req.session.user }); }); router.get('/student/:id', requireAuth, (req, res) => { const student = dbGet('SELECT * FROM students WHERE id = ?', [req.params.id]); if (!student) return res.status(404).send('Ученик не найден'); const results = dbAll(` SELECT er.*, s.name as subject_name, s.is_mandatory, s.code as subject_code FROM exam_results er JOIN subjects s ON s.code = er.subject_code WHERE er.student_id = ? ORDER BY s.is_mandatory DESC, s.name `, [req.params.id]); const mandatoryResults = results.filter(r => r.is_mandatory); const electiveResults = results.filter(r => !r.is_mandatory); const rusResult = mandatoryResults.find(r => r.subject_code === '01') || null; const mathResult = mandatoryResults.find(r => r.subject_code === '02') || null; res.render('student', { student, electiveResults, rusResult, mathResult, user: req.session.user }); }); router.get('/import', requireAuth, (req, res) => { res.render('import', { user: req.session.user }); }); router.get('/certificate/:id', requireAuth, (req, res) => { const { id } = req.params; const type = req.query.type || 'gia'; const subjectCodes = req.query.subjects ? req.query.subjects.split(',') : []; const student = dbGet('SELECT * FROM students WHERE id = ?', [id]); if (!student) return res.status(404).send('Ученик не найден'); const rusResult = dbGet(` SELECT er.*, s.name as subject_name FROM exam_results er JOIN subjects s ON s.code = er.subject_code WHERE er.student_id = ? AND er.subject_code = '01' `, [id]); const mathResult = dbGet(` SELECT er.*, s.name as subject_name FROM exam_results er JOIN subjects s ON s.code = er.subject_code WHERE er.student_id = ? AND er.subject_code = '02' `, [id]); let electives = []; if (type === 'gia' && subjectCodes.length > 0) { const placeholders = subjectCodes.map(() => '?').join(','); electives = dbAll(` SELECT er.*, s.name as subject_name FROM exam_results er JOIN subjects s ON s.code = er.subject_code WHERE er.student_id = ? AND er.subject_code IN (${placeholders}) `, [id, ...subjectCodes]); } const today = new Date(); const certNumber = `${today.getFullYear()}${String(id).padStart(4, '0')}`; const months = ['января', 'февраля', 'марта', 'апреля', 'мая', 'июня', 'июля', 'августа', 'сентября', 'октября', 'ноября', 'декабря']; const dateStr = `«${String(today.getDate()).padStart(2, '0')}» ${months[today.getMonth()]} ${today.getFullYear()} года`; const gender = detectGender(student.patronymic); const fioDative = formatNameDative(student, gender); const verbEnding = gender === 'm' ? 'обучался' : 'обучалась'; const verbEnding2 = gender === 'm' ? 'получил' : 'получила'; res.render('certificate', { type, student: { ...student, fioDative, gender }, certNumber, dateStr, verbEnding, verbEnding2, rusResult: rusResult || null, mathResult: mathResult || null, electives, allSubjects: type === 'gia' ? [ rusResult || { subject_name: 'Русский язык', primary_score: null, grade: null }, mathResult || { subject_name: 'Математика', primary_score: null, grade: null }, ...electives ] : [ rusResult || { subject_name: 'Русский язык', grade: null }, mathResult || { subject_name: 'Математика', grade: null } ] }); }); function detectGender(patronymic) { if (!patronymic) return 'm'; const last = patronymic.toLowerCase(); if (/вна|чна|нична$/.test(last)) return 'f'; return 'm'; } function formatNameDative(student, gender) { const l = student.last_name || ''; const f = student.first_name || ''; const p = student.patronymic || ''; if (gender === 'f') { return `${declineFemaleLast(l)} ${declineFemaleFirst(f)} ${declineFemalePatr(p)}`; } return `${declineMaleLast(l)} ${declineMaleFirst(f)} ${declineMalePatr(p)}`; } function declineFemaleLast(name) { if (!name) return ''; if (name.endsWith('ая')) return name.slice(0, -2) + 'ой'; if (name.endsWith('яя')) return name.slice(0, -2) + 'ей'; if (name.endsWith('а')) return name.slice(0, -1) + 'ой'; if (name.endsWith('я')) return name.slice(0, -1) + 'е'; if (name.endsWith('ова') || name.endsWith('ева') || name.endsWith('ина')) return name.slice(0, -1) + 'ой'; return name + 'ой'; } function declineFemaleFirst(name) { if (!name) return ''; if (name.endsWith('а') || name.endsWith('я')) return name.slice(0, -1) + 'е'; return name + 'е'; } function declineFemalePatr(name) { if (!name) return ''; if (name.endsWith('на')) return name.slice(0, -1) + 'е'; return name + 'е'; } function declineMaleLast(name) { if (!name) return ''; if (name.endsWith('ов') || name.endsWith('ев') || name.endsWith('ин') || name.endsWith('ёв')) return name + 'у'; if (name.endsWith('ий') || name.endsWith('ый')) return name.slice(0, -2) + 'ому'; if (name.endsWith('ой')) return name.slice(0, -2) + 'ому'; return name + 'у'; } function declineMaleFirst(name) { if (!name) return ''; if (name.endsWith('й') || name.endsWith('ь')) return name.slice(0, -1) + 'ю'; if (name.endsWith('а') || name.endsWith('я')) return name.slice(0, -1) + 'е'; return name + 'у'; } function declineMalePatr(name) { if (!name) return ''; if (name.endsWith('ич')) return name + 'у'; if (name.endsWith('на')) return name.slice(0, -1) + 'е'; return name + 'у'; } router.get('/batch-print', requireAuth, (req, res) => { const { class: cls, parallel, type } = req.query; let students; if (cls) { students = dbAll('SELECT * FROM students WHERE class = ? ORDER BY last_name, first_name', [cls]); } else if (parallel) { students = dbAll('SELECT * FROM students WHERE class LIKE ? ORDER BY class, last_name, first_name', [parallel + '%']); } else { students = dbAll('SELECT * FROM students ORDER BY class, last_name, first_name'); } const today = new Date(); const months = ['января', 'февраля', 'марта', 'апреля', 'мая', 'июня', 'июля', 'августа', 'сентября', 'октября', 'ноября', 'декабря']; const dateStr = `«${String(today.getDate()).padStart(2, '0')}» ${months[today.getMonth()]} ${today.getFullYear()} года`; const studentData = students.map(st => { const results = dbAll(` SELECT er.*, s.name as subject_name, s.is_mandatory FROM exam_results er JOIN subjects s ON s.code = er.subject_code WHERE er.student_id = ? `, [st.id]); const rusResult = results.find(r => r.subject_code === '01') || null; const mathResult = results.find(r => r.subject_code === '02') || null; const electives = results.filter(r => !r.is_mandatory); // Автоопределение: элективы есть → ОГЭ, 1 предмет всего → второгодник ОГЭ, иначе ГВЭ const totalResults = results.length; const autoType = (electives.length > 0 || totalResults === 1) ? 'gia' : 'gve'; const finalType = (type === 'gia' || type === 'gve') ? type : autoType; const gender = detectGender(st.patronymic); const fioDative = formatNameDative(st, gender); let allSubjects; if (finalType === 'gia') { allSubjects = [ rusResult || { subject_name: 'Русский язык', primary_score: null, grade: null }, mathResult || { subject_name: 'Математика', primary_score: null, grade: null }, ...electives ]; } else { allSubjects = [ rusResult || { subject_name: 'Русский язык', grade: null }, mathResult || { subject_name: 'Математика', grade: null } ]; } return { student: { ...st, fioDative, gender }, certNumber: `${today.getFullYear()}${String(st.id).padStart(4, '0')}`, dateStr, verbEnding: gender === 'm' ? 'обучался' : 'обучалась', verbEnding2: gender === 'm' ? 'получил' : 'получила', allSubjects, type: finalType }; }); res.render('batch-certificate', { students: studentData }); }); module.exports = router;