alta_de_horario.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. <?php
  2. require_once 'class/c_login.php';
  3. if (!isset($_SESSION['user']))
  4. die(header('Location: index.php'));
  5. $user = unserialize($_SESSION['user']);
  6. $user->access();
  7. if (!$user->admin && in_array($user->acceso, ['r', 'n']))
  8. die(header('Location: main.php?error=1'));
  9. $user->print_to_log('Consultar: Alta de horario');
  10. ?>
  11. <!DOCTYPE html>
  12. <html lang="en">
  13. <head>
  14. <title>Cargar horario desde Excel | <?= $user->facultad['facultad'] ?? 'General' ?></title>
  15. <meta charset="utf-8">
  16. <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  17. <?php include_once "import/html_css_files.php"; ?>
  18. </head>
  19. <body style="display: block;">
  20. <?php
  21. include('include/constantes.php');
  22. include("import/html_header.php");
  23. html_header("Cargar horario desde Excel", "Sistema de gestión de checador");
  24. ?>
  25. <main class="container content marco content-margin" id="local-app">
  26. <div class="row mb-3">
  27. <div class="col-12 text-right">
  28. <button class="btn btn-outline-secondary" data-toggle="modal" data-target="#modalDescargarPlantilla">
  29. <span class="ing-descarga ing-fw"></span>
  30. Descargar plantilla
  31. </button>
  32. </div>
  33. </div>
  34. <section id="message"></section>
  35. <?php require('import/periodo.php') ?>
  36. <form>
  37. <div class="form-group">
  38. <div class="form-box">
  39. <?php
  40. $periodo = $db->where('id', $user->periodo)->getOne('fs_periodo');
  41. $carreras = $db
  42. ->where('nivel', $periodo['nivel_id'])
  43. ->where('facultad', $user->facultad['facultad_id'])
  44. ->orderBy('carrera')
  45. ->get('fs_carrera');
  46. ?>
  47. <div class="form-group row" id="input-carrera">
  48. <label for="filter_carrera" class="col-4 col-form-label">Carrera</label>
  49. <div class="col-6">
  50. <div id="dlcarrera" class="datalist datalist-select mb-1 w-100">
  51. <div class="datalist-input">Seleccionar carrera</div>
  52. <span class="ing-buscar icono"></span>
  53. <ul style="display:none">
  54. <?php
  55. foreach ($carreras as $carrera) {
  56. ?>
  57. <li data-id="<?= $carrera['id'] ?>">
  58. <?= $carrera['carrera'] ?>
  59. </li>
  60. <?php
  61. }
  62. ?>
  63. </ul>
  64. <input type="hidden" id="filter_carrera" name="carrera" value="">
  65. </div>
  66. </div>
  67. </div>
  68. <div class="form-group row" id="input-file">
  69. <label for="excel" class="col-4 col-form-label">Archivo de horarios</label>
  70. <div class="col-8 col-sm-6">
  71. <input class="form-control-file" id="excel" name="archivo" accept=".xlsx, .xls" require>
  72. </div>
  73. </div>
  74. <div class="form-group mt-5 row justify-content-center">
  75. <!-- on click reload -->
  76. <button id="btn-cancelar" type="button" class="btn btn-danger mx-2" onclick="location.reload()">
  77. <span class="ing-cancelar"></span>
  78. Cancelar
  79. </button>
  80. <button id="btn-cargar" type="button" class="btn btn-primary" onclick="submit_files()">
  81. <span class="ing-guardar"></span>
  82. Guardar horario
  83. </button>
  84. </div>
  85. </div>
  86. </div>
  87. </form>
  88. </main>
  89. <div class="modal fade" id="modalDescargarPlantilla" tabindex="-1" aria-labelledby="descargarPlantillaModalLabel" aria-hidden="true">
  90. <div class="modal-dialog modal-xl modal-dialog-centered modal-dialog-scrollable">
  91. <div class="modal-content">
  92. <div class="modal-header">
  93. <h5 class="modal-title" id="descargarPlantillaModalLabel">Instrucciones</h5>
  94. <button type="button" class="close text-white" data-dismiss="modal" aria-label="Close">
  95. <span aria-hidden="true">&times;</span>
  96. </button>
  97. </div>
  98. <div class="modal-body">
  99. <ol>
  100. <li> Los encabezados deberán mantenerse en todo momento, tal cual se encuentran en la plantilla. </li>
  101. <li> Las horas válidas son de 7:00 a 22:00 en bloques de 15 minutos. </li>
  102. <li> La columna DURACIÓN es la duración de una clase en horas. Si la clase es de 7:15–8:45 se pone que la hora de la clase es de 7:15 con una duración de 180. </li>
  103. <!-- <li> Únicamente las columnas de … </li> -->
  104. <li> Si se encuentra un error en la revisión del archivo no se guardará ningún registro. </li>
  105. <li> Una vez revisado el archivo haz clic en el botón [Guardar horario] para que se guarde la información. </li>
  106. </ol>
  107. </div>
  108. <div class="modal-footer">
  109. <button type="button" class="btn btn-danger" data-dismiss="modal">Aceptar</button>
  110. <button type="button" class="btn btn-primary" id="descargarPlantilla"><span class="ing-descarga"></span> Descargar</button>
  111. <button type="button" class="btn btn-primary" id="descargarPlantillaEjemplo"><span class="ing-descarga"></span> Descargar ejemplo</button>
  112. </div>
  113. </div>
  114. </div>
  115. </div>
  116. </body>
  117. <?php
  118. require_once("import/html_footer.php");
  119. require_once("js/messages.php")
  120. ?>
  121. <script src="js/scrollables.js"></script>
  122. <script src="js/jquery.min.js"></script>
  123. <script src="js/bootstrap/bootstrap.min.js"></script>
  124. <script src="js/custominputfile.min-es.js"></script>
  125. <link rel="stylesheet" href="css/custominputfile.min.css">
  126. <script src="js/fetchlib.js"></script>
  127. <script>
  128. var datum = []
  129. $(document).ready(function() {
  130. $('#excel').customFile({
  131. allowed: ['xlsx', 'xls'],
  132. maxFiles: 1,
  133. callbacks: {
  134. onSuccess: async function(item) {
  135. var formData = $.customFile.serialize('archivo');
  136. const {
  137. status,
  138. message,
  139. data
  140. } = await fetch('action/action_revisar_excel.php', {
  141. method: 'POST',
  142. body: formData,
  143. })
  144. .then(response => response.json())
  145. .catch(error => {
  146. return {
  147. status: 'error',
  148. message: 'Error al cargar el archivo',
  149. }
  150. });
  151. if (status == 'error') {
  152. triggerMessage(message, 'Error en el formato del archivo');
  153. item.destroy();
  154. return
  155. }
  156. triggerMessage(message + " Haz clic en el botón <b>Guardar horario</b> para guardar los datos", `Archivo revisado, aún <b>no guardado</b>`, 'primary');
  157. datum = data;
  158. // hide form
  159. document.querySelector('#input-file').classList.add('d-none');
  160. document.querySelector('#input-carrera').classList.add('d-none');
  161. // show button
  162. document.querySelector('#btn-cargar').classList.remove('d-none');
  163. document.querySelector('#btn-cancelar').classList.remove('d-none');
  164. },
  165. }
  166. });
  167. // hide
  168. document.querySelector('#input-file').classList.add('d-none');
  169. document.querySelector('#btn-cancelar').classList.add('d-none');
  170. document.querySelector('#btn-cargar').classList.add('d-none');
  171. // on click in carrera
  172. [... document.querySelectorAll('#dlcarrera ul li')].forEach(
  173. li => li.addEventListener('click', () => {
  174. document.querySelector('#input-file').classList.remove('d-none')
  175. })
  176. )
  177. })
  178. async function submit_files() {
  179. // disable button
  180. const button = document.querySelector('#btn-cargar');
  181. // add class disabled to button
  182. button.classList.add('disabled');
  183. // disable button
  184. button.disabled = true;
  185. // add loading icon
  186. button.innerHTML = '<span class="ing-cargando"></span> Cargando...';
  187. let missing = [];
  188. let carrera = $('#filter_carrera').val();
  189. if (carrera == '') missing.push('Carrera');
  190. if (datum.length == 0) missing.push('Archivo de horarios');
  191. let facultad = <?= $user->facultad['facultad_id'] ?>;
  192. if (missing.length > 0) {
  193. messageMissingInputs(missing);
  194. // remove class disabled to button
  195. button.classList.remove('disabled');
  196. // enable button
  197. button.disabled = false;
  198. // remove loading icon
  199. button.innerHTML = '<span class="ing-guardar"></span> Guardar horario';
  200. return;
  201. }
  202. const formData = new FormData();
  203. formData.append('carrera', carrera);
  204. formData.append('facultad', facultad);
  205. formData.append('periodo', <?= $user->periodo ?>);
  206. formData.append('data', JSON.stringify(datum));
  207. const {
  208. status,
  209. message
  210. } = await fetch('action/action_horario_excel.php', {
  211. method: 'POST',
  212. body: formData
  213. })
  214. .then(response => response.json())
  215. .catch(error => {
  216. return {
  217. status: 'error',
  218. message: 'Error al cargar el archivo',
  219. }
  220. });
  221. triggerMessage(message, (status == 'error') ? 'Error al guardar el archivo' : 'Horarios guardados', (status == 'error') ? 'danger' : 'success');
  222. // await 1 second
  223. // await setTimeout(() => {}, 1000);
  224. // remove class disabled to
  225. button.classList.remove('disabled');
  226. // enable button
  227. button.disabled = false;
  228. button.innerHTML = 'Cargar otro horario';
  229. // refresh page
  230. button.onclick = () => location.reload()
  231. // hide button
  232. document.querySelector('#btn-cancelar').classList.add('d-none');
  233. }
  234. document.querySelector('#descargarPlantilla').addEventListener('click', function() {
  235. window.open('template/plantilla.xlsx', '_blank');
  236. });
  237. document.querySelector('#descargarPlantillaEjemplo').addEventListener('click', function() {
  238. window.open('template/ejemplo.xlsx', '_blank');
  239. });
  240. </script>
  241. </html>