docs.js 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. /**
  2. * ЭЛЕКТРОННЫЙ ЖУРНАЛ «ШКАЛА»: РАБОТА С ЗАПИСЯМИ О ПРИЧИНАХ ПРОПУСКОВ УРОКОВ
  3. * И ДОБАВЛЕНИЕ ЗАЯВЛЕНИЙ О ПРИЧИНАХ ПРОПУСКОВ РОДИТЕЛЯМИ
  4. * Copyright © 2019, А.М.Гольдин. Modified BSD License
  5. */
  6. "use strict";
  7. const statuses = {
  8. new: ["новая", ''],
  9. reject: ["отклонена", "style='background:#fabec3'"],
  10. accept: ["одобрена", "style='background:#bbc274'"]
  11. };
  12. // Добавление нового заявления от родителей (запрос к API)
  13. const sprAdd = async () => {
  14. let vid = dqs("#sprVid").value,
  15. start = dqs("#sprStart").value,
  16. fin = dqs("#sprFin").value;
  17. if (start > fin) {info(1, "Неверные даты!"); return;}
  18. let apiResp = await apireq("sprAdd", [vid, start, fin]);
  19. if (apiResp == "success") {
  20. info(0, "Ваше заявление принято "
  21. + "и будет рассмотрено классным руководителем");
  22. sprDocsShow("pupil");
  23. }
  24. else info(1, "Ошибка на сервере,<br>заявление не принято");
  25. }
  26. // Удаление записи по её id
  27. const sprDel = async (id) => {
  28. if (!confirm("Заявление будет удалено. Вы уверены?")) return;
  29. let apiResp = await apireq("sprDel", [id]);
  30. if (apiResp != "none") sprDocsShow(dqs("#sprSelPupil").value);
  31. else info(1, "Ошибка на сервере,<br>запись не удалена");
  32. }
  33. // Редактирование статуса записи по её id
  34. // Без второго аргумента - одобрить, со вторым аргументом - отклонить
  35. const sprEdit = async (id, reject) => {
  36. let act = reject ? "reject" : "accept",
  37. go = reject ? "отклонено" : "одобрено";
  38. if (!confirm(`Заявление будет ${go}. Вы уверены?`)) return;
  39. let apiResp = await apireq("sprEdit", [id, act]);
  40. if (apiResp == "success") {
  41. info(0, `Заявление отредактировано (${go})`);
  42. sprDocsShow(dqs("#sprSelPupil").value);
  43. }
  44. else info(1, "Ошибка на сервере,<br>запись не изменена");
  45. }
  46. // Формирование содержимого таблицы с записями по одному учащемуся
  47. // (API возвращает массив объектов записей по одному учащемуся)
  48. const sprDocsShow = async pupil => {
  49. // Преобразование даты вида 2019-09-13 к формату 13.09
  50. const dConv = d => `${d.substr(8,2)}.${d.substr(5,2)}`;
  51. let innerTable = "<tr><th> </th><th> </th><th> </th>"
  52. + "<th>Кем внесена</th><th>Даты</th>"
  53. + "<th>Основание</th><th>Статус</th></tr>";
  54. let apiResp = await apireq("sprGet", [pupil]);
  55. if (apiResp != "none") {
  56. let sprList = JSON.parse(apiResp);
  57. if (!sprList.length) innerTable +=
  58. "<tr><td colspan=7 class='bg0'>Записей не найдено</td></tr>";
  59. else {
  60. sprList.sort((x,y) => x.start < y.start); // свежие сверху
  61. let i = 0;
  62. for (let spr of sprList) {
  63. i++;
  64. let start = dConv(spr.start), fin = dConv(spr.fin);
  65. let dt = (start == fin) ? start : `${start} – ${fin}`;
  66. let firstTD =
  67. `<td title="Одобрить" `
  68. + `onClick="sprEdit('${spr._id}')">&#10133;</td>`
  69. + `<td title="Отклонить" `
  70. + `onClick="sprEdit('${spr._id}', 1)">&#10134;</td>`
  71. + `<td title="Удалить" `
  72. + `onClick="sprDel('${spr._id}')">&#10060;</td>`;
  73. if (
  74. dqs("#selRole").value == "pupil" ||
  75. dqs("#selRole").value == "parent"
  76. ) firstTD = `<td class="bg0">${i}</td>`
  77. + `<td class="bg0"> </td><td class="bg0"> </td>`;
  78. let vidSpr = spr.vid == "par" ? "родители" : spr.vid,
  79. osnov = spr.prim == "med" ? "медсправка" :
  80. (spr.prim == "doc" ? "документ" :
  81. (spr.prim == "fam" ? "семейные обст." : spr.prim));
  82. innerTable += `<tr>${firstTD}<td>${vidSpr}</td>`
  83. + `<td>${dt}</td><td>${osnov}</td>`
  84. + `<td ${statuses[spr.state][1]}>`
  85. + `${statuses[spr.state][0]}</td></tr>`;
  86. }
  87. }
  88. dqs("#sprShowDel").innerHTML = innerTable;
  89. }
  90. else info(1, "Не могу загрузить записи");
  91. };
  92. // Формирование списка детей в селекте выбора учащегося
  93. const sprPupListShow = async () => {
  94. let clName = dqs("#sprSelClass").value;
  95. let apiResp = await apireq("pupilsList", [clName]);
  96. if (apiResp != "none") {
  97. let pupilsList = JSON.parse(apiResp);
  98. let selPupilInner = '';
  99. for (let pup of pupilsList)
  100. selPupilInner += `<option value="${pup[1]}">${pup[0]}</option>`;
  101. dqs("#sprSelPupil").innerHTML = selPupilInner;
  102. sprDocsShow(pupilsList[0][1]); // показываем записи первого учащегося
  103. }
  104. else info(1, "Не могу загрузить список учащихся");
  105. }
  106. // Формирование контента страницы (regNow, regYst, regYfin определены в ini.js)
  107. createSection("docs", `
  108. <h2>Уважительные причины <nobr>пропуска уроков</nobr></h2>
  109. <select id="sprSelClass" onChange="sprPupListShow()"></select>
  110. <select id="sprSelPupil" onChange="sprDocsShow(this.value)"></select>
  111. <div id="sprAdd">
  112. <h3>Подать заявление<br>об уважительной причине
  113. <nobr>пропуска уроков</nobr></h3>
  114. <p><b>Уважаемые родители!</b> Указанное вами основание пропуска уроков
  115. может быть признано уважительным (одобрено) только после представления
  116. классному руководителю документа на бумажном носителе.
  117. Ис&shy;клю&shy;че&shy;ни&shy;ем являются семейные обстоятельства, но и
  118. их необходимо разъяснить классному руководителю по согласованным с ним
  119. каналам связи (телефонный звонок, email, мессенджеры).</p><p>Под
  120. «документом организации» понимается, например, письмо из музыкальной или
  121. спортивной школы, повестка из военкомата и т.&thinsp;п.</p>
  122. <b>Выберите основание пропуска:</b>
  123. <select id="sprVid">
  124. <option value="med">медицинская справка</option>
  125. <option value="doc">документ организации</option>
  126. <option value="fam">семейные обстоятельства</option>
  127. </select><br>
  128. <b>Пропуск уроков:</b> <nobr>с <input id="sprStart" type="date"
  129. min="${regYst}" max="${regYfin}" value="${regNow}"></nobr>
  130. <nobr>по <input id="sprFin" type="date"
  131. min="${regYst}" max="${regYfin}" value="${regNow}"></nobr>
  132. <button id="sprSubm" type="button" onClick="sprAdd()"
  133. >Подать заявление</button>
  134. <h3>Зарегистрированные записи</h3>
  135. </div>
  136. <table id="sprShowDel"></table>
  137. `);
  138. // Динамически формируем содержимое страницы (имя метода = имени пункта меню!)
  139. getContent.docs = async () => {
  140. let sprRole = dqs("#selRole").value;
  141. // Если он учащийся или родитель, показываем ему только его записи
  142. if (sprRole == "pupil" || sprRole == "parent") {
  143. dqs("#sprSelClass").style.display = "none";
  144. dqs("#sprSelPupil").style.display = "none";
  145. // Если он учащийся, не показываем ему блок добавления заявления
  146. if (sprRole == "pupil") dqs("#sprAdd").style.display = "none";
  147. sprDocsShow("pupil"); // реальный логин подпишется на бэкенде
  148. }
  149. // Если он классный руководитель, показываем ему его классы
  150. // и не показываем блок добавления заявления
  151. else if (sprRole == "tutor") {
  152. let selClassInner = '';
  153. for (let cl of uTutorCls) selClassInner += `<option>${cl}</option>`;
  154. dqs("#sprSelClass").innerHTML = selClassInner;
  155. sprPupListShow(); // показываем список детей
  156. dqs("#sprAdd").style.display = "none";
  157. }
  158. }