ini.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. /**
  2. * ЭЛЕКТРОННЫЙ ЖУРНАЛ «ШКАЛА»: ИНИЦИАЛИЗАЦИЯ КОНСТАНТ И ФУНКЦИЙ
  3. * Copyright © 2020, А.М.Гольдин. Modified BSD License
  4. */
  5. "use strict";
  6. /* БЛОК ОПРЕДЕЛЕНИЯ КОНСТАНТ
  7. --------------------------------------------------------------------- */
  8. // Учебные периоды
  9. // Указываются том порядке, в котором соответствующие итоговые отметки будут
  10. // следовать за датой последнего дня учебного периода в таблице отметок
  11. // и в табеле. Даты первого и последнего дней периода можно указывать
  12. // "с запасом", не обязательно точно.
  13. // Из этого массива ниже генерируется объект DTSIT в нужном формате
  14. const STPER = [
  15. ["1ч", "Первая четверть", "01.09", "05.11"],
  16. ["2ч", "Вторая четверть", "06.11", "31.12"],
  17. ["1п", "Первое полугодие", "01.09", "31.12"],
  18. ["3ч", "Третья четверть", "01.01", "28.03"],
  19. ["4ч", "Четвертая четверть", "29.03", "31.05"],
  20. ["2п", "Второе полугодие", "01.01", "31.05"],
  21. ["Год", "Учебный год", "01.09", "25.06"]
  22. ];
  23. // Наименования ролей пользователя
  24. const roleNames = {
  25. root: "Гл. администратор",
  26. admin: "Администратор",
  27. teacher: "Учитель",
  28. tutor: "Кл. руководитель",
  29. pupil: "Учащийся",
  30. parent: "Родитель"
  31. };
  32. // Показываемые пункты меню в зависимости от роли пользователя
  33. let menuItems = {
  34. root: [
  35. ["users", "Пользователи"],
  36. ["admins", "Администраторы"],
  37. ["classes", "Классы"],
  38. ["subjects", "Предметы"]
  39. ],
  40. admin: [
  41. ["register", "Журнал"],
  42. ["absent", "Посещаемость"],
  43. ["permit", "Разреш"],
  44. ["attend", "Явка"],
  45. ["notes", "Заметки"],
  46. ["distrib", "Нагрузка"],
  47. ["groups", "Группы"],
  48. ["vdreg", "Внеуроч"],
  49. ["achsheet", "Табели"],
  50. ["export", "Экспорт"],
  51. ["stat", "Статистика"],
  52. ["userlog", "Лог"]
  53. ],
  54. teacher: [
  55. ["register", "Журнал"],
  56. ["attend", "Явка"],
  57. ["grusers", "Группы"],
  58. ["vdreg", "Внеуроч"],
  59. ["notes", "Заметки"]
  60. ],
  61. tutor: [
  62. ["register", "Журнал"],
  63. ["absent", "Посещаемость"],
  64. ["attend", "Явка"],
  65. ["docs", "Уважит"],
  66. ["notes", "Заметки"],
  67. ["subgroup", "Подгруппы"],
  68. ["achsheet", "Табели"],
  69. ["vdtut", "Внеуроч"],
  70. ["parcodes", "Родители"],
  71. ["export", "Экспорт"],
  72. ["userlog", "Лог"]
  73. ],
  74. pupil: [
  75. ["journal", "Дневник"],
  76. ["achsheet", "Табель"],
  77. ["absent", "Посещаемость"],
  78. ["docs", "Уважит"],
  79. ["notes", "Заметки"]
  80. ],
  81. parent: [
  82. ["journal", "Дневник"],
  83. ["achsheet", "Табель"],
  84. ["absent", "Посещаемость"],
  85. ["docs", "Уважит"],
  86. ["notes", "Заметки"]
  87. ]
  88. };
  89. // Список предметов по умолчанию
  90. const subjDef = {
  91. s110: "Русский язык",
  92. s120: "Литература",
  93. s210: "Английский язык",
  94. s220: "Немецкий язык",
  95. s230: "Французский язык",
  96. s310: "Искусство",
  97. s320: "МХК",
  98. s330: "Музыка",
  99. s410: "Математика",
  100. s420: "Алгебра",
  101. s430: "Алгебра и начала анализа",
  102. s440: "Геометрия",
  103. s450: "Вероятность и статистика",
  104. s460: "Информатика",
  105. s510: "История",
  106. s520: "История России",
  107. s530: "Всеобщая история",
  108. s540: "Обществознание",
  109. s550: "Экономика",
  110. s560: "Право",
  111. s570: "География",
  112. s610: "Физика",
  113. s620: "Астрономия",
  114. s630: "Химия",
  115. s640: "Биология",
  116. s710: "Технология",
  117. s810: "Физическая культура",
  118. s820: "ОБЗР"
  119. };
  120. // Получение объекта со списком всех предметов {"s403":"Физика", ...}
  121. const sbListFullGet = async() => {
  122. let apiResp = await apireq("subjList");
  123. if (apiResp == "none") return {};
  124. let sbListDop = JSON.parse(apiResp);
  125. return subjSort({...subjDef, ...sbListDop})
  126. };
  127. /* БЛОК ОПРЕДЕЛЕНИЯ ФУНКЦИЙ И ГЕНЕРИРОВАНИЯ НЕКОТОРЫХ ОБЪЕКТОВ
  128. --------------------------------------------------------------------- */
  129. // Объект функций для динамической подгрузки контента в блоки
  130. let getContent = {};
  131. // Просто удобное сокращение :)
  132. const dqs = elem => document.querySelector(elem);
  133. // regNow - текущая дата в формате 2019-09-23
  134. // regYst, regYfin - даты начала и окончания учебного года
  135. let regDt = new Date,
  136. regY = regDt.getFullYear(),
  137. regM = (regDt.getMonth() + 1).toString().padStart(2, "0"),
  138. regD = regDt.getDate().toString().padStart(2, "0"),
  139. regNow = `${regY}-${regM}-${regD}`;
  140. let regYst = regDt.getMonth() > 7 ? `${regY}-09-01` : `${regY-1}-09-01`,
  141. regYfin = regDt.getMonth() > 7 ? `${regY+1}-06-30` : `${regY}-06-30`;
  142. // Создание нового элемента section на странице с id="newId"
  143. // и наполнение его содержимым inner
  144. let elems = {};
  145. const createSection = (newId, inner) => {
  146. elems[newId] = document.createElement("section");
  147. elems[newId].id = newId;
  148. elems[newId].innerHTML = inner;
  149. dqs("#content").appendChild(elems[newId])
  150. };
  151. // Запрос к API. Вызов: let apiResp = await apireq(f, z); или await apireq(f);
  152. // Аргументы: f (имя функции API) и z (строка или объект параметров API)
  153. // Если параметров нет, функция вызывается с одним аргументом f
  154. // Переменные uCateg, uLogin, uToken берутся из замыкания
  155. let apireq = async(f, z) => {
  156. let body = {t: uCateg, l: uLogin, p: uToken, f: f};
  157. if (z) body.z = z;
  158. let opt = {method: "POST", cache: "no-cache", body: JSON.stringify(body)};
  159. return await (await fetch("/", opt)).text()
  160. };
  161. // Преобразование даты из формата d613 в формат 13.03 (второго аргумента нет),
  162. // либо в формат 2019-03-13 (второй аргумент ненулевой), а также обратно
  163. // (при обратном преобразовании второй аргумент не указывается)
  164. const dateConv = (dtInp, full) => {
  165. let dtOut = "";
  166. if (dtInp.includes("-")) {
  167. let dtArr = dtInp.split("-"),
  168. y = dtArr[0],
  169. m = dtArr[1],
  170. mNum = Number(m),
  171. d = dtArr[2];
  172. m = mNum > 8 ? mNum - 9 : mNum + 3;
  173. return `d${m}${d}`
  174. }
  175. else if (dtInp.includes(".")) {
  176. let dtArr = dtInp.split("."),
  177. d = dtArr[0],
  178. m = dtArr[1],
  179. mNum = Number(m);
  180. m = mNum > 8 ? mNum - 9 : mNum + 3;
  181. return `d${m}${d}`
  182. }
  183. else {
  184. let mNum = Number(dtInp.substr(1, 1)),
  185. d = dtInp.substr(2, 2);
  186. let m = mNum < 4 ? mNum + 9 : mNum - 3;
  187. m = m.toString().padStart(2, "0");
  188. if (full) {
  189. let dateObj = new Date,
  190. y = dateObj.getFullYear(),
  191. currM = dateObj.getMonth() + 1;
  192. if (mNum < 4 && currM < 8) y--;
  193. return `${y}-${m}-${d}`
  194. }
  195. else return `${d}.${m}`
  196. }
  197. };
  198. // Объект с ключами типа d628a и краткими (типа "2ч") или полными
  199. // (типа "Вторая четверть") наименованиями учебных периодов, а также с датами
  200. // (в формате d613) их начала и окончания (генерируется из STPER (см. выше)):
  201. // {
  202. // ...
  203. // d628a: ["3ч", "Третья четверть", "d401", "d628"],
  204. // ...
  205. // }
  206. let DTSIT = {},
  207. perLiters = "abcdefghijklmnopqrstuvwxyz";
  208. for (let i = 0; i < STPER.length; i++) {
  209. let key = dateConv(STPER[i][3]) + perLiters[i];
  210. DTSIT[key] = [
  211. STPER[i][0],
  212. STPER[i][1],
  213. dateConv(STPER[i][2]),
  214. dateConv(STPER[i][3])
  215. ]
  216. }
  217. // Функция принимает аргумент - дату в формате d613 - и возвращает условный
  218. // порядковый номер (число) учебного периода (первого встретившегося
  219. // в массиве STER!), в котором находится эта дата. Если дата не принадлежит
  220. // ни одному учебному периоду, возвращается 99
  221. const whereis = dt => {
  222. let i = 1;
  223. for (let k in DTSIT) {
  224. if (dt >= DTSIT[k][2] && dt <= DTSIT[k][3]) return i;
  225. i++
  226. }
  227. return 99
  228. };
  229. // Сортировка массива названий классов и подгрупп правильным образом (11А > 1А,
  230. // подгруппы следуют непосредственно за своими классами)
  231. const classSort = classArr => classArr.map(x => {
  232. let xArr = x.split("-"),
  233. grName = xArr[1] ? `-${xArr[1]}` : "";
  234. return xArr[0].padStart(3, "0") + grName
  235. }).sort().map(x => x.replace(/^0/, ""));
  236. // Сортировка списка предметов правильным образом по ключам (d480 > s110)
  237. const subjSort = sbObj => {
  238. let res = {};
  239. Object.keys(sbObj)
  240. .sort((k1, k2) => Number(k1.substr(1, 3)) - Number(k2.substr(1, 3)))
  241. .forEach(key => {res[key] = sbObj[key]});
  242. return res
  243. };
  244. // Сортировка массива, состоящего из объектов-пользователей,
  245. // по ключу login в каждом объекте-пользователе
  246. const userSort = usArray => usArray.sort((u1, u2) => u1.login > u2.login);
  247. // Шаблон html-документов, отдаваемых пользователю для печати
  248. const HTML = `<!DOCTYPE html><html lang="ru"><head><meta charset="utf-8">
  249. <style>@page {size: A4; margin: 1.5cm}
  250. body {font: 8pt Arial, sans-serif}
  251. h3 {text-align:center; font-size: 10pt; text-transform: uppercase}
  252. p {text-align:center;}
  253. p.sgn {text-align:left; margin:30pt 0px 0px 3cm; line-height:3;}
  254. table {border-collapse: collapse; margin: 6pt auto 18pt}
  255. table th, table td {
  256. padding: 3pt; border: 0.25pt solid black; text-align: center}
  257. table td:first-child {text-align: left}
  258. </style></head><body>{{body}}</body></html>`;
  259. // Экспорт некоторых функций и объектов на серверную сторону
  260. try {
  261. module.exports = {
  262. dtConv: dateConv, sbSort: subjSort, dtsIt: DTSIT, sbDef: subjDef,
  263. whereIs: whereis
  264. }
  265. } catch (e) {}