// ============================================================================= // Список уроков без ДЗ в указанном интервале дат для указанных учителей // или для всех учителей. // В данный список будут включены уроки, на которые не задано ДЗ явно или // не поставлена метка "Без ДЗ". // ============================================================================= // 1. ОБЯЗАТЕЛЬНО заходите в старую админку, на любую страницу. // 2. Открываете в браузере панель инструментов разработчика. // 3. Переходите на закладку Консоль. // 4. Открываете файл со скриптом и копируете все его содержимое в окно консоли // (в ФайрФоксе возможно придется подтвердить вставку кода ручным вводом указанной фразы). // 5. Проверяете начальные параметры - код учебного года, интервал дат, список учителей. // 6. Жмете Enter. В зависимости от браузера или будет предложено сохранить csv-файл // или он автоматически будет сохранен в папку "Загрузки". // Наименование файла - "Без ДЗ (ГГГГ-ММ-ДД - ГГГГ-ММ-ДД).csv". // Сортировка по ФИО учителя, дате, номеру урока. // Кодировка текста в файле "Windows-1251", так что его сразу можно открывать в Excel // и сортировать/фильтровать по нужным критериям. // // Как просто узнать ИД нужных учителей: // 1. Заходите в справочник кадров и открываете карточку нужного учителя. // 2. Кликаете мышкой в адресную строку браузера и видите число в конце адреса - // это и есть ИД учителя. // // ============================================================================= var year_id = 13; // Идентификатор учебного года (2025-2026) // Основные параметры // Список (через запятую) ИД проверяемых учителей. // Если список пустой - проверка по всем учителям. var th_ids = []; var date_start = "2025-09-16"; // Начало интервала дат (обязательно с ведущим нулём!) var date_end = "2025-09-16"; // Конец интервала дат (обязательно с ведущим нулём!) // Если date_start не указана (date_start = ""), то будет принята текущая дата // а для date_end будет принята завтрашняя дата. // Если date_start указана, но не указана date_end (date_end = ""), то для date_end // будет принята дата date_start + 1 день. // Глобальные переменные var no_dz = []; (async () => { // Функция преобразования текста из кодировки UTF-8 // в кодовый массив Windows-1251 async function toWin(s){ let code = []; for(let i = 0; i < s.length; i++){ let c = s.charCodeAt(i); if (c == 0x401){ code.push(0xA8); } else if (c == 0x451){ code.push(0xB8); } else if (c < 0x410){ code.push(c); } else { code.push(c - 848); }; }; return (new Uint8Array(code)); }; // Функция чтения одной страницы данных в формате JSON async function fetchOne(url) { const res = await fetch(url); const json = await res.json(); return(json); }; // Функция чтения всех страниц данных в формате JSON async function fetchAll(url, pagesProp="x-pagination-total-pages") { if (url.indexOf("?") == -1){ url += "?per_page=1000"; } else { url += "&per_page=1000"; } let recs = []; let page = 0, pages = 0; while (true){ page += 1; const res = await fetch(url +"&page="+ page); const hdr = await res.headers; recs.push(...(await res.json())); pages = hdr.get(pagesProp); if (!pages || (page >= pages)){break}; }; return(recs); }; if (!th_ids || !th_ids.length){ // Если список учителей пустой - формируем словарь всех учителей let th = await fetchAll("core/api/teacher_profiles"); for(let i = 0; i < th.length; i++){ th_ids.push(th[i].id); }; }; if (!date_start){ date_start = (new Date()).toISOString().slice(0, 10); date_end = ""; }; if (!date_end){ date_end = (new Date((new Date(date_start)) .getTime() + 24*60*60*1000)).toISOString().slice(0, 10); }; // Основной цикл - обход учителей let sch_dates = "&from="+ date_start +"&to="+ date_end; let hw_dates = "&begin_date="+ date_start.split("-").reverse().join(".") + "&end_date="+ date_end.split("-").reverse().join("."); for (let th of th_ids){ // Словарь меток "Без ДЗ" учителя let dz_mark = new Map(); // Читаем расписание учителя let sch = await fetchAll("jersey/api/schedule_items?academic_year_id="+ year_id + "&teacher_id="+ th + sch_dates + "&with_lesson_info=true&with_group_class_subject_info=true"); if (!sch || !sch.length){continue}; console.log(sch[0].teacher_name || "???"); for (let ls of sch){ if ((ls.homeworks_to_verify || []).length){continue}; // Явного ДЗ на данный урок нет, проверяем наличие метки "Без ДЗ" marks = dz_mark.get(ls.group_id) if (marks === undefined){ // Для данной группы еще не запрашивали метки "Без ДЗ" marks = []; let hw_abs = await fetchAll("core/api/homework_absences?group_id="+ ls.group_id + hw_dates); for (let mark of hw_abs){ marks.push(mark.date.split(".").reverse().map(Number).join("-")); }; dz_mark.set(ls.group_id, marks); }; if (!marks.includes(ls.date.join("-"))){ no_dz.push((ls.teacher_name || "???") +";"+ ls.date[0] +"-"+ ("0"+ls.date[1]).substr(-2) +"-"+ ("0"+ls.date[2]).substr(-2) +";"+ ls.study_ordinal +";"+ ls.class_unit_name +";"+ ls.subject_name +";"+ ls.group_name + ";" + "https://school.mos.ru/teacher/study-process/journal/grade/" + ls.group_id +"?scheduleItemId="+ ls.id); }; }; }; if (!no_dz.length){ console.log("Нет уроков без ДЗ!"); } else { no_dz.sort(); let csv = "ФИО учителя;Дата урока;Урок;Класс;Предмет;Группа;Журнал\n"+ no_dz.join("\n"); // Создание файла формата CSV в кодировке Windows-1251 // и сохранение его браузером const link = document.createElement("a"); const file = new Blob([await toWin(csv)], {type:'text/csv'}); link.href = URL.createObjectURL(file); link.download = "Без ДЗ ("+ date_start +" - "+ date_end +").csv"; link.click(); URL.revokeObjectURL(link.href); console.log("Всего уроков без ДЗ: "+ no_dz.length); }; })()