viewExport.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. // ЭЛЕКТРОННЫЙ ЖУРНАЛ «ШКАЛА»: ПРОСМОТР ЭКСПОРТИРОВАННОГО ФАЙЛА ЭЖ
  2. // Copyright © 2020, А.М.Гольдин. Modified BSD License
  3. // Скрипт подписывается в каждый экспортируемый html-файл с журналом класса
  4. "use strict";
  5. // Получаем объект с данными журнала, вырезаем все ссылки
  6. let body = document.querySelector("article");
  7. let bodyInner = body.innerHTML.replace(/<a .+?>/g, '').replace(/<\/a>/g, '');
  8. let scole = JSON.parse(bodyInner);
  9. // Формируем заголовок страницы и определения стилей
  10. let title = document.createElement("title");
  11. title.textContent = `Журнал ${scole.className} класса`;
  12. document.head.prepend(title);
  13. let stl = document.createElement("style");
  14. stl.textContent = `
  15. @page {size: A4 portrait; margin:1.5cm 2.5cm}
  16. body {width:16cm; margin:auto; font:10pt Arial, sans-serif; text-align:center}
  17. nav {text-align:center; margin-bottom:6pt; page-break-before:always}
  18. h1, h2, h3, p {text-align:center;}
  19. h1 {font-size:18pt; margin:0pt}
  20. h2 {font-size:12pt; margin:36pt 0pt 12pt}
  21. h2:first-of-type {font-size:10pt; margin:12pt 0pt 0pt}
  22. h3 {font-size:12pt; margin:0pt 0pt 12pt}
  23. p {margin:48pt 0pt; border-top:0.25pt solid black}
  24. button {position:fixed; top:5px; right:20px; font-size:24pt; display:none;}
  25. /* Оглавление */
  26. section p {text-align:left; margin:3pt 0pt; border:none}
  27. section b {display:inline-block; width:3em; text-align:right}
  28. /* Последняя страница */
  29. aside {width:10cm; margin:auto; padding-top:5cm; page-break-before:always}
  30. aside p {border:none}
  31. aside p:nth-child(2) {border-top:0.25pt solid black}
  32. aside p:nth-child(3) {text-align:left; font-style:italic}
  33. /* Таблица с отметками */
  34. .pupCol, .gradeCol {
  35. display:inline-block; width:3.5cm; border-top:0.25pt solid black;}
  36. .gradeCol {width:1.1cm;}
  37. .pupCol div, .gradeCol div {
  38. border-bottom:0.25pt solid black; padding:1pt 0pt; text-align:left;}
  39. .gradeCol div {text-align:center; border-left:0.25pt solid black;}
  40. .gradeCol div:first-child {font-stretch:condensed}
  41. /* Таблица с темами */
  42. .topicsStr {border:0.25pt solid black; border-style:none none solid}
  43. h3 + .topicsStr {border-top:0.25pt solid black}
  44. .topicsStr div {
  45. display:inline-block; padding:3pt; text-align:center; vertical-align:top;
  46. -webkit-hyphens:auto; -moz-hyphens:auto; -ms-hyphens:auto; hiphens:auto;}
  47. .topicsStr div:nth-child(1) {width:1cm; border-left:none}
  48. .topicsStr div:nth-child(2) {width:0.6cm}
  49. .topicsStr div:nth-child(3) {width:0.8cm}
  50. .topicsStr div:nth-child(4) {width:6.4cm; text-align:left}
  51. .topicsStr div:nth-child(5) {width:6cm; text-align:left}
  52. h3 + .topicsStr div:nth-child(3),
  53. h3 + .topicsStr div:nth-child(4),
  54. h3 + .topicsStr div:nth-child(5) {
  55. text-align:center;}
  56. h3 + .topicsStr div {border-left:0.25pt solid black}
  57. h3 + .topicsStr div:first-child {border-left:none}
  58. /* Таблица со сводной ведомостью успеваемости */
  59. table {border-collapse:collapse; width:100%}
  60. th, td {padding:2pt; border:0.25pt solid black; text-align:center}
  61. th {font-weight:normal}
  62. td:first-child {text-align:left}
  63. @media screen {
  64. html {background:#ccc}
  65. body {background:white; margin:2cm auto; padding-top:1cm;}
  66. nav, aside {padding-top:12pt; border-top:5px groove #ccc; margin-top:24pt}
  67. aside {padding:12pt 3cm 2cm}
  68. button {display:block;}
  69. }
  70. `;
  71. document.head.prepend(stl);
  72. let doc = `
  73. <button type="button" onClick="window.print()" title="Печать"
  74. >&#128424;</button>
  75. <p><small>(наименование образовательной организации)</small></p>
  76. <h1>Классный журнал ${scole.className} класса</h1>
  77. <h2>20_____/_____ учебный год</h2>
  78. <h2>Содержание</h2>`;
  79. doc += `<section>{{toc}}</section>`;
  80. let toc = '';
  81. let listFull = new Set(); // полный список класса
  82. let vedom = []; // массив со сводной ведомостью
  83. let pageNum = 2;
  84. // Цикл по предметам в данном классе
  85. for (let subjObj of scole.content) {
  86. // Формируем колонку с фамилиями учащихся;
  87. // заодно накапливаем все фамилии в множестве listFull
  88. let pupCol = "<div class='pupCol'><div>&nbsp;</div>";
  89. for (let pupil of subjObj.list) {
  90. pupCol += `<div>${pupil}</div>`;
  91. listFull.add(pupil);
  92. }
  93. pupCol += "</div>";
  94. // Формируем элемент оглавления
  95. let teachArr = subjObj.p.split(' '),
  96. teach = `${teachArr[0]}&nbsp;${teachArr[1][0]}.&nbsp;${teachArr[2][0]}.`;
  97. toc += `<p><b>${pageNum}</b>&emsp;${subjObj.s} (${teach})</p>`;
  98. // Пополняем массив со сводной ведомостью vedom =
  99. // [
  100. // [
  101. // "Русский язык (Петров К. С.)",
  102. // {"Иванов В.": {"1ч.": 5, ...}, "Петров П.": {"1ч.": 3, ...}, ...}
  103. // ],
  104. // ...
  105. // ]
  106. // (массив учебных периодов PERDS подписан спереди скриптом export.js)
  107. let vedomAdd = {};
  108. for (let dt of subjObj.l) {
  109. let dateBrief = dt.d.replace(/<.{0,1}b>/g, ''); // убираем <b></b>
  110. if (PERDS.includes(dateBrief)) {
  111. for (let i=0; i<subjObj.list.length; i++) {
  112. let fio = subjObj.list[i];
  113. if (!vedomAdd[fio]) vedomAdd[fio] = {};
  114. vedomAdd[fio][dateBrief] = (dt.g)[i];
  115. }
  116. }
  117. }
  118. vedom.push([`${subjObj.s} (${teach})`, vedomAdd]);
  119. // Текущая печатаемая страница (левая/четная и правая/нечетная)
  120. let currPageLeft = '', currPageRight = '';
  121. // Цикл по всем датам (урокам) в данном предмете
  122. // (11 - количество записанных уроков на одной странице)
  123. let lessNum = 0;
  124. for (let lessObj of subjObj.l) {
  125. if (!(lessNum % 11)) {
  126. doc += currPageLeft + currPageRight;
  127. currPageLeft = `<nav>${pageNum}</nav>`; pageNum++;
  128. currPageLeft += `<h3>${subjObj.s}</h3>`;
  129. currPageLeft += pupCol; // список учащихся
  130. currPageRight = `<nav>${pageNum}</nav>`; pageNum++;
  131. currPageRight += `<h3>${subjObj.p}</h3>`;
  132. currPageRight += "<div class='topicsStr'>"
  133. + "<div>Дата</div><div>ч</div><div>Вес</div>"
  134. + "<div>Содержание урока</div><div>Задание на дом</div>"
  135. + "</div>";
  136. }
  137. // Подписываем текущий столбик урока в таблицу с отметками
  138. // (кроме пропущенных учителем уроков)
  139. if (lessObj.w != 9) {
  140. currPageLeft += `<div class='gradeCol'><div>${lessObj.d}</div>`;
  141. for (let gr of lessObj.g)
  142. currPageLeft += `<div>${gr ? gr : ' '}</div>`;
  143. currPageLeft += "</div>";
  144. }
  145. // Подписываем текущую тему в таблицу с темами
  146. if (lessObj.t) {
  147. let vol = lessObj.v ? lessObj.v : 1;
  148. let wgt = lessObj.w == 9 ? '' : (lessObj.w)/2;
  149. let cursiv = lessObj.w == 9 ? " style='font-style:italic'" : '';
  150. currPageRight += `<div class='topicsStr'><div>${lessObj.d}</div>`
  151. + `<div>${vol}</div><div>${wgt}</div>`
  152. + `<div${cursiv}>${lessObj.t.substr(0,120)}</div>`
  153. + `<div>${lessObj.h.substr(0,120)}</div></div>`;
  154. }
  155. lessNum++;
  156. }
  157. doc += currPageLeft + currPageRight;
  158. }
  159. // Сводная ведомость учета успеваемости
  160. toc += `<p><b>${pageNum}</b>&emsp;Сводная ведомость учета успеваемости</p>`;
  161. doc += `<nav>${pageNum}</nav>`;
  162. doc += `<h3>Сводная ведомость учета успеваемости ${scole.className} класса<br>`
  163. + `<small>Классный руководитель: ${scole.tutor}</small></h3>`;
  164. // Полный список учащихся, разбитый по 2 (массив pup2):
  165. // [["Кац И.", "Ким Ю."], ["Иванов И.", "Петров П."], ...]
  166. let pupils = [...listFull].sort((a,b) => a.localeCompare(b, "ru"));
  167. let pup2 = [], innerArr;
  168. for (let i=0; i<Math.ceil(pupils.length / 2); i++) {
  169. innerArr = [];
  170. for (let j=0; j<2; j++) if(pupils[2*i+j]) innerArr.push(pupils[2*i+j]);
  171. pup2.push(innerArr);
  172. }
  173. // Цикл по этим двойкам (каждой двойке соответствует страница с таблицей)
  174. for (let vNum=0; vNum<pup2.length; vNum++) {
  175. if (vNum) doc += `<nav>${pageNum}</nav>`; pageNum++;
  176. // Печатаем заголовочную часть таблицы с фио детей и учебными периодами
  177. // (массив учебных периодов PERDS подписан спереди скриптом export.js)
  178. let itVal = PERDS.length;
  179. doc += "<table><tr><th rowspan='2'>Предмет и учитель</th>";
  180. for (let pup of pup2[vNum]) {doc += `<th colspan='${itVal}'>${pup}</th>`;}
  181. doc += "</tr><tr>";
  182. for (let pup of pup2[vNum]) {
  183. for (let period of PERDS) doc += `<th>${period}</th>`;
  184. }
  185. doc += "</tr>";
  186. // Цикл по ранее сформированному массиву vedom, формируем строки таблицы
  187. for (let subjEl of vedom) {
  188. doc += "<tr>";
  189. doc += `<td>${subjEl[0]}</td>`;
  190. for (let pup of pup2[vNum]) {
  191. for (let per of PERDS) {
  192. let tdCont = '';
  193. if (subjEl[1][pup]) if (subjEl[1][pup][per])
  194. tdCont = subjEl[1][pup][per];
  195. doc += `<td>${tdCont}</td>`;
  196. }
  197. }
  198. doc += "</tr>";
  199. }
  200. doc += "</table>";
  201. }
  202. doc += "<aside><p>В настоящем журнале пронумеровано,<br>" +
  203. "прошнуровано и скреплено печатью</p><p>листов</p><p>Подпись:</p></aside>";
  204. body.innerHTML = doc.replace("{{toc}}", toc);