refactor(assignments): единый модуль assignment-utils.js (тип/«сдано»/срочность)
Логика классификации типа задания и статуса «сдано» дублировалась в трёх местах (dashboard.html, homework.html, assignmentController.js) и начала расходиться. Вынес в один UMD-модуль frontend/js/assignment-utils.js (грузится и в браузере, и в Node через require — как svg-sanitize.js): type(a), isDone(a, sub, opts), urgencyScore(a). Нюанс «сдано» для upload/file параметризован: вид ученика (acceptedOnly) — закрыто только при принятой сдаче; учитель/обзор долгов — любая сдача не на доработке. Поведение всех трёх поверхностей сохранено 1:1. - homework.html: asgnType/asgnDone/urgencyScore → тонкие делегаты в AssignmentUtils. - dashboard.html: urgencyScore делегирует; classify и upload-ветка buildAssignCard через AssignmentUtils.type/isDone (заодно корректнее: учебник-ДЗ больше не путается с upload). - assignmentController: classOutstanding/_assignTypeOf → AssignmentUtils. Verified: AU-контракт 25/25 (типы, isDone teacher vs acceptedOnly, порядок urgency); интеграция 8/8 (classOutstanding те же 14 уч./42 просрочено; homework делегирует). node --check всех файлов + инлайна обоих HTML. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,7 @@ const db = require('../db/db');
|
||||
const { pushNotif } = require('../utils/notifications');
|
||||
const { stripTags } = require('../utils/sanitize');
|
||||
const { SESSION_MODES } = require('../constants');
|
||||
const AssignmentUtils = require('../../../frontend/js/assignment-utils.js'); // единый источник: тип/«сдано»
|
||||
|
||||
const VALID_ASSIGN_MODES = SESSION_MODES;
|
||||
|
||||
@@ -344,14 +345,6 @@ function myAssignments(req, res) {
|
||||
res.json(assignmentRowsForUser(req.user.id));
|
||||
}
|
||||
|
||||
/* Тип задания — те же признаки, что на /homework (asgnType). */
|
||||
function _assignTypeOf(r) {
|
||||
if (r.textbook_id) return 'textbook';
|
||||
if (r.file_id) return 'file';
|
||||
if (r.is_homework && (r.count == null || r.count <= 1) && (!r.subject_slug || r.subject_slug === 'other')) return 'upload';
|
||||
return 'test';
|
||||
}
|
||||
|
||||
/* ── GET /api/classes/:id/outstanding ── что «висит» у каждого ученика класса ──
|
||||
Учитель/админ видят по каждому ученику его НЕзакрытые задания (классовые + личные
|
||||
от этого учителя) со статусом: не начато / в процессе / на доработке / просрочено. */
|
||||
@@ -388,23 +381,16 @@ function classOutstanding(req, res) {
|
||||
);
|
||||
const pending = [];
|
||||
for (const r of rows) {
|
||||
const type = _assignTypeOf(r);
|
||||
const t = AssignmentUtils.type(r);
|
||||
const st = (t === 'upload' || t === 'file') ? subMap.get(r.id + '_' + m.id) : null;
|
||||
// Учительская семантика: любая сдача не на доработке = не долг (default opts).
|
||||
if (AssignmentUtils.isDone(r, st ? { status: st } : null)) continue;
|
||||
const overdue = r.deadline && new Date(r.deadline).getTime() < now;
|
||||
let done = false, status = overdue ? 'overdue' : 'not_started';
|
||||
if (type === 'textbook') {
|
||||
done = !!(r.textbook_all_read || r.completed_at);
|
||||
} else if (type === 'upload' || type === 'file') {
|
||||
const st = subMap.get(r.id + '_' + m.id);
|
||||
if (st && st !== 'revision') done = true; // сдал — на проверке/принято
|
||||
else if (st === 'revision') status = 'revision'; // вернули на доработку
|
||||
} else { // test
|
||||
const maxAtt = r.max_attempts || 0, used = r.attempts_used || 0;
|
||||
if (maxAtt > 0 && used >= maxAtt) done = true;
|
||||
else if (r.session_status === 'completed' && r.mode !== 'repeat') done = true;
|
||||
else if (r.session_status === 'in_progress') status = 'in_progress';
|
||||
}
|
||||
if (!done) pending.push({
|
||||
assignment_id: r.id, title: r.title, type, deadline: r.deadline,
|
||||
let status = overdue ? 'overdue' : 'not_started';
|
||||
if (st === 'revision') status = 'revision'; // вернули на доработку
|
||||
else if (t === 'test' && r.session_status === 'in_progress') status = 'in_progress';
|
||||
pending.push({
|
||||
assignment_id: r.id, title: r.title, type: t, deadline: r.deadline,
|
||||
status, is_homework: r.is_homework ? 1 : 0,
|
||||
scope: r.class_id === cidNum ? 'class' : 'direct',
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user