diff --git a/public/style.css b/public/style.css index e0c8117..f4256b2 100644 --- a/public/style.css +++ b/public/style.css @@ -39,9 +39,36 @@ h2 { margin: 15px 0 8px; font-size: 16px; } max-width: 300px; } .input-sm { max-width: 120px; } +.input-xs { max-width: 80px; } + +#subject-select { max-width: 220px; } .search-bar { margin-bottom: 15px; } +.filter-extras { + margin-bottom: 12px; + padding: 8px 12px; + background: #fafafa; + border: 1px solid #e0e0e0; + border-radius: 4px; +} +.filter-extras .form-row { + margin-bottom: 0; + display: flex; + align-items: center; + gap: 6px; + flex-wrap: wrap; +} +.filter-extras .form-row label { + min-width: auto; + font-weight: 500; + font-size: 13px; + margin-right: 2px; +} +.filter-extras .form-row label:not(:first-child) { + margin-left: 10px; +} + .filter-bar { display: flex; gap: 12px; diff --git a/src/routes/api.js b/src/routes/api.js index 7be0c78..8011e55 100644 --- a/src/routes/api.js +++ b/src/routes/api.js @@ -98,9 +98,19 @@ router.post('/import', upload.single('xlsfile'), (req, res) => { } }); +router.get('/subjects', (req, res) => { + const rows = dbAll('SELECT code, name FROM subjects ORDER BY is_mandatory DESC, name'); + res.json(rows); +}); + router.get('/students', (req, res) => { const search = req.query.search || ''; const filter = req.query.filter || ''; + const subjectCode = req.query.subject_code || ''; + const scoreMin = req.query.score_min; + const scoreMax = req.query.score_max; + const gradeMin = req.query.grade_min; + const gradeMax = req.query.grade_max; const baseQuery = ` SELECT s.*, @@ -125,6 +135,27 @@ router.get('/students', (req, res) => { params.push(like, like, like, like); } + if (subjectCode) { + whereClauses.push('er.subject_code = ?'); + params.push(subjectCode); + } + if (scoreMin !== undefined && scoreMin !== '') { + whereClauses.push('er.primary_score >= ?'); + params.push(parseInt(scoreMin, 10)); + } + if (scoreMax !== undefined && scoreMax !== '') { + whereClauses.push('er.primary_score <= ?'); + params.push(parseInt(scoreMax, 10)); + } + if (gradeMin !== undefined && gradeMin !== '') { + whereClauses.push('er.grade >= ?'); + params.push(parseInt(gradeMin, 10)); + } + if (gradeMax !== undefined && gradeMax !== '') { + whereClauses.push('er.grade <= ?'); + params.push(parseInt(gradeMax, 10)); + } + let havingClause = ''; if (filter === 'gia' || filter === 'oge') { havingClause = 'HAVING elective_count > 0'; diff --git a/views/index.ejs b/views/index.ejs index 023fc13..316cf92 100644 --- a/views/index.ejs +++ b/views/index.ejs @@ -72,6 +72,21 @@ +