absent.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. /**
  2. * ЭЛЕКТРОННЫЙ ЖУРНАЛ «ШКАЛА»: БЛОК УЧЕТА ПОСЕЩАЕМОСТИ
  3. * Copyright © 2019, А.М.Гольдин. Modified BSD License
  4. */
  5. "use strict";
  6. // Текущий список класса
  7. let absClList = [];
  8. // Справочник предметов
  9. let absSbList = {};
  10. // Функция получает данные о посещаемости и об уважительных причинах пропусков
  11. // уроков, все это обсчитывает и публикует на странице. Аргумент - либо логин
  12. // ученика, либо наименование класса типа 11Б
  13. const absShow = async (clORpup) => {
  14. dqs("#absResult").innerHTML = "<img src='static/preloader.gif'>";
  15. let reqObj = [], onePupil = false;
  16. if (/[А-Я]/.test(clORpup)) reqObj = [clORpup, '']; // запрошен весь класс
  17. else {onePupil = true; reqObj = ['', clORpup];} // запрошен один ученик
  18. // Получаем исходный массив absentArr объектов с данными о посещаемости
  19. // (учитель Сидоров, учащийся Иванов)
  20. // [{d: "d730", s: s430, p: ivanov, abs: 2}, ...]
  21. let apiResp = await apireq("absentGet", reqObj);
  22. if (apiResp == "none") {info(1, "Не могу получить данные"); return;}
  23. let absentArr = JSON.parse(apiResp);
  24. // Получаем объект respectObj с данными об уважительных причинах пропусков:
  25. // {
  26. // ivanov: [["d002", "d013"], ...],
  27. // petrov: ...
  28. // }
  29. apiResp = await apireq("sprResp", reqObj);
  30. if (apiResp == "none") {info(1, "Не могу получить данные"); return;}
  31. let respectObjApi = JSON.parse(apiResp);
  32. // Переформатируем из формата 2019-09-02, полученного от API, в формат d002
  33. let respectObj = {};
  34. for (let pup of Object.keys(respectObjApi)) {
  35. respectObj[pup] = [];
  36. for (let para of respectObjApi[pup]) {
  37. para[0] = dateConv(para[0]);
  38. para[1] = dateConv(para[1]);
  39. respectObj[pup].push([para[0], para[1]]);
  40. }
  41. }
  42. // Подсчет числа пропусков (общего и по неуважительной) всех учеников
  43. // по учебным периодам; результат в объекте absVal:
  44. // {
  45. // ivanov: {d628a: [34, 28], ...},
  46. // petrov: {d628a: [56, 13], ...},
  47. // ...
  48. // }
  49. // Итоговый результат по всему классу - в объекте absItog:
  50. // {d628a: [156, 122], ...}
  51. let absVal = {}, pattern = {}; // шаблон объекта одного ученика
  52. for (let itName of Object.keys(DTSIT)) {
  53. pattern[itName] = [0, 0];
  54. }
  55. let pattStr = JSON.stringify(pattern);
  56. let absItog = JSON.parse(pattStr);
  57. for (let propusk of absentArr) {
  58. // Сначала считаем все пропуски
  59. if (!absVal[propusk.p]) absVal[propusk.p] = JSON.parse(pattStr);
  60. for (let itName of Object.keys(DTSIT)) {
  61. if (propusk.d >= DTSIT[itName][2] && propusk.d <= DTSIT[itName][3]) {
  62. absVal[propusk.p][itName][0] += propusk.abs; // все пропуски
  63. absItog[itName][0] += propusk.abs;
  64. }
  65. }
  66. // Теперь считаем уважительные, цикл по объекту respectObj
  67. // чтобы понять, уважительный наш текущий пропуск или нет
  68. let absIsResp = false;
  69. if (!respectObj[propusk.p]) continue; // если у него нет справок вообще
  70. for (let dats of respectObj[propusk.p])
  71. if (propusk.d >= dats[0] && propusk.d <= dats[1]) absIsResp = true;
  72. // Если пропуск был уважительный, пишем его в нужные периоды уч. года
  73. if (absIsResp) for (let itName of Object.keys(DTSIT)) {
  74. if (propusk.d >= DTSIT[itName][2] && propusk.d <= DTSIT[itName][3]) {
  75. absVal[propusk.p][itName][1] += propusk.abs;
  76. absItog[itName][1] += propusk.abs;
  77. }
  78. }
  79. } // конец подсчета общего числа пропусков всех учеников
  80. // Публикация данных о посещаемости
  81. let dann = '';
  82. if (Object.keys(absVal).length) {
  83. // Сначала публикуем таблицу со сводными данными
  84. dann = "<h3>Сводные данные посещаемости</h3>";
  85. dann += "<table><tr><th rowspan=2> </th>";
  86. let str1 = '', str2 = '';
  87. for (let itName of Object.keys(DTSIT)) {
  88. str1 += `<th colspan=2>${DTSIT[itName][0]}</th>`;
  89. str2 += "<th>всего</th><th>неув.</th>";
  90. }
  91. dann += `${str1}</tr><tr>${str2}</tr>`;
  92. let list4table = [...absClList];
  93. if (onePupil) {
  94. let famil = "Пропущено уроков";
  95. for (let pupil of absClList) // ищем фамилию, если получен absClList
  96. if (pupil[1] == clORpup) {famil = pupil[0]; break;}
  97. list4table = [[famil, clORpup]];
  98. }
  99. for (let pupil of list4table) {
  100. dann += `<tr><td>${pupil[0]}</td>`;
  101. for (let itName of Object.keys(DTSIT)) {
  102. if (absVal[pupil[1]]) {
  103. let vsego = absVal[pupil[1]][itName][0],
  104. uvaj = absVal[pupil[1]][itName][1],
  105. neuv = vsego - uvaj;
  106. dann += `<td>${vsego}</td><td>${neuv}</td>`;
  107. }
  108. else dann += "<td>0</td><td>0</td>";
  109. }
  110. dann += "</tr>";
  111. }
  112. // Если запрошен весь класс, подписываем еще итоговую строку
  113. if (!onePupil) {
  114. dann += `<tr class="bold"><td>Итого</td>`;
  115. for (let itName of Object.keys(DTSIT)) {
  116. dann += `<td>${absItog[itName][0]}</td>`
  117. + `<td>${absItog[itName][0] - absItog[itName][1]}</td>`;
  118. }
  119. dann += "</tr>";
  120. }
  121. dann += "</table>";
  122. // Если запрашивался один ребенок, еще публикуем расшифровку его прогулов
  123. if (onePupil) {
  124. dann += "<h3>Пропуски уроков без уважительной причины</h3>";
  125. // Загружаем справочник предметов, если он не загружен ранее
  126. if (!Object.keys(absSbList).length) {
  127. let apiResp = await apireq("subjList");
  128. let subjListDop = JSON.parse(apiResp);
  129. absSbList = {...subjDef, ...subjListDop};
  130. }
  131. // Результат - в объекте absNoResp с ключами - кодами предметов
  132. // {s110: ["d730(1)", "d023(2)"], ...}
  133. // Идем циклом по всем пропускам
  134. let absNoResp = {};
  135. for (let propusk of absentArr) {
  136. // Цикл по объекту respectObj (уважительный ли текущий пропуск)
  137. let noResp = true;
  138. if (respectObj[clORpup]) for (let dats of respectObj[clORpup])
  139. if (propusk.d >= dats[0] && propusk.d <= dats[1]) noResp = false;
  140. // Неуважительный пропуск пишем в объект absNoResp
  141. if (noResp) {
  142. if (!absNoResp[propusk.s]) absNoResp[propusk.s] = [];
  143. absNoResp[propusk.s].push(`${propusk.d}(${propusk.abs})`);
  144. }
  145. }
  146. // Публикуем расшифровку прогулов на страничке
  147. if (!Object.keys(absNoResp).length)
  148. dann += "<p>Пропусков уроков без уважительной причины нет</p>";
  149. else {
  150. dann += "<table id='noRespect'>";
  151. for (let subjCode of Object.keys(absNoResp)
  152. .sort((a,b) => a.substr(1,3) > b.substr(1,3))) {
  153. dann += `<tr><td>${absSbList[subjCode]}</td><td>`;
  154. let tdInn = '';
  155. for (let dt of absNoResp[subjCode].sort())
  156. tdInn += `${dateConv(dt.substr(0,4))}${dt.substr(4)}, `;
  157. tdInn = tdInn.trim().replace(/,$/, '');
  158. dann += tdInn + "</td></tr>";
  159. }
  160. dann += "</table>";
  161. }
  162. } // конец расшифровки прогулов одного ребенка
  163. }
  164. else dann = "<h3>Пропусков уроков нет</h3>";
  165. dqs("#absResult").innerHTML =
  166. dann + "<p><a id='absPrint'>Версия для печати</a></p>";
  167. // Подготавливаем версию для печати (HTML определен в ini.js)
  168. let printCont = HTML.replace("{{body}}", dann);
  169. let dataLink = new Blob([printCont], {type: "text/html"});
  170. dqs("#absPrint").href = window.URL.createObjectURL(dataLink);
  171. dqs("#absPrint").download = "absent.html";
  172. } // конец функции подсчета и публикации данных о посещаемости
  173. // Формирование списка детей в селекте выбора учащегося
  174. const absPupListShow = async () => {
  175. let clName = dqs("#absSelClass").value;
  176. let apiResp = await apireq("pupilsList", [clName]);
  177. if (apiResp != "none") {
  178. absClList = JSON.parse(apiResp);
  179. let selPupilInner = `<option value="${clName}">ВЕСЬ КЛАСС</option>`;
  180. for (let pup of absClList) {
  181. let imya = pup[0].split(' ')[1] || 'N';
  182. pup[0] = pup[0].split(' ')[0] + ` ${imya[0]}.`;
  183. selPupilInner += `<option value="${pup[1]}">${pup[0]}</option>`;
  184. }
  185. dqs("#absSelPupil").innerHTML = selPupilInner;
  186. absShow(clName); // показываем пропуски всего класса
  187. }
  188. else {
  189. dqs("#absSelPupil").innerHTML = '';
  190. dqs("#absResult").innerHTML = "<h3>В этом классе нет учащихся</h3>";
  191. }
  192. }
  193. // Формирование контента страницы
  194. createSection("absent", `
  195. <select id="absSelClass" onChange="absPupListShow()"></select>
  196. <select id="absSelPupil" onChange="absShow(this.value)"></select>
  197. <div id="absResult"><img src='static/preloader.gif'></div>
  198. `);
  199. // Динамически подгружаем контент страницы (имя метода = имени пункта меню!)
  200. getContent.absent = async () => {
  201. let absRole = dqs("#selRole").value;
  202. // Если он учащийся или родитель, показываем ему только его пропуски
  203. if (absRole == "pupil" || absRole == "parent") {
  204. dqs("#absSelClass").style.display = "none";
  205. dqs("#absSelPupil").style.display = "none";
  206. absShow(uLogin);
  207. }
  208. else {
  209. let selClassInner = '';
  210. // Если он классный руководитель, показываем ему его классы
  211. if (absRole == "tutor")
  212. for (let cl of uTutorCls) selClassInner += `<option>${cl}</option>`;
  213. // Если он администратор, показываем ему все классы
  214. else if (absRole == "admin") {
  215. let apiResp = await apireq("classesList");
  216. if (apiResp == "none") {info(1, "Не могу получить данные"); return;}
  217. let absAllClasses = classSort(JSON.parse(apiResp));
  218. for (let cl of absAllClasses)
  219. selClassInner += `<option>${cl}</option>`;
  220. }
  221. dqs("#absSelClass").innerHTML = selClassInner;
  222. absPupListShow(); // показываем список детей
  223. }
  224. };