ModuleSelector.vue 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. <template>
  2. <LoadSaveView />
  3. <form
  4. @submit.prevent=""
  5. @keydown.enter.prevent=""
  6. >
  7. <ul>
  8. <li
  9. v-for="(filterSet, idx) in classesStore.filterRules"
  10. :key="filterSet.pk"
  11. class="mb-2"
  12. >
  13. <ClassFilter
  14. v-model="classesStore.filterRules[idx]"
  15. :is-last-filter="classesStore.filterRules.length == 1"
  16. @add-filter="classesStore.insertFilter"
  17. @remove-filter="classesStore.removeFilter"
  18. />
  19. </li>
  20. </ul>
  21. </form>
  22. <table
  23. class="module-table mt-5 border-collapse w-full text-center text-xs xl:text-sm 2xl:text-base"
  24. >
  25. <thead>
  26. <tr
  27. class="border-b dark:border-gray-500 font-bold bg-gray-200 h-10 dark:bg-gray-500 dark:text-white"
  28. >
  29. <td>
  30. <OrderingControl
  31. title="Modul"
  32. @changed="
  33. (order) => orderingChanged(ClassSelectorColumn.Module, order)
  34. "
  35. />
  36. </td>
  37. <td>
  38. <OrderingControl
  39. title="Durchführung"
  40. @changed="
  41. (order) => orderingChanged(ClassSelectorColumn.Time, order)
  42. "
  43. />
  44. </td>
  45. <td>
  46. <OrderingControl
  47. title="Klasse"
  48. @changed="
  49. (order) => orderingChanged(ClassSelectorColumn.Class, order)
  50. "
  51. />
  52. </td>
  53. <td class="hidden md:table-cell">
  54. <OrderingControl
  55. title="Dozent"
  56. @changed="
  57. (order) => orderingChanged(ClassSelectorColumn.Lecturer, order)
  58. "
  59. />
  60. </td>
  61. <td class="hidden md:table-cell">
  62. <OrderingControl
  63. title="Raum"
  64. @changed="
  65. (order) => orderingChanged(ClassSelectorColumn.Room, order)
  66. "
  67. />
  68. </td>
  69. <td>
  70. <OrderingControl
  71. title="Art"
  72. @changed="
  73. (order) =>
  74. orderingChanged(ClassSelectorColumn.TeachingType, order)
  75. "
  76. />
  77. </td>
  78. <td class="hidden xl:table-cell">
  79. <OrderingControl
  80. title="MSP"
  81. @changed="
  82. (order) => orderingChanged(ClassSelectorColumn.MSP, order)
  83. "
  84. />
  85. </td>
  86. <td />
  87. </tr>
  88. </thead>
  89. <ClassRow
  90. v-for="cls in paginatedClasses"
  91. :key="cls.id"
  92. :cls="cls"
  93. />
  94. </table>
  95. <div
  96. v-if="filteredModules.length == 0"
  97. class="flex flex-wrap justify-center mt-10 text-center"
  98. >
  99. <span
  100. class="text-2xl text-gray-400 dark:text-gray-600 no-results-text font-mono w-full"
  101. >Schade, leider gibt es keine Resultate...</span>
  102. <button
  103. title="Module durchsuchen"
  104. class="action-button mt-5"
  105. @click="stateStore.showingModuleSearch = true"
  106. >
  107. Alle Module durchsuchen
  108. </button>
  109. </div>
  110. <NumberedPagination
  111. v-model="currentPageIdx"
  112. :page-size="pageSize"
  113. :result-count="filteredModules.length"
  114. />
  115. <ModuleSearchModal />
  116. </template>
  117. <script lang="ts">
  118. import { useClassesStore } from "../../stores/classes";
  119. import { usePlanningStore } from "../../stores/planning";
  120. import { classesPDFLink, dayMap, toTime } from "../../helpers";
  121. import { watch } from "vue";
  122. import LoadSaveView from "../general/ModulesetManager.vue";
  123. import OrderingControl from "../general/OrderingControl.vue";
  124. import { TaughtClass, ClassSelectorColumn, Ordering } from "../../types";
  125. import { useStateStore } from "../../stores/state";
  126. import { useStudenthubStore } from "../../stores/studenthub";
  127. import { useModulesStore } from "../../stores/modules";
  128. import ClassFilter from "../general/ClassFilter.vue";
  129. import ClassRow from "../general/ClassRow.vue";
  130. import ModuleSearchModal from "../modals/ModuleSearchModal.vue";
  131. import NumberedPagination from "../general/NumberedPagination.vue";
  132. export default {
  133. name: "ModuleSelector",
  134. components: {
  135. LoadSaveView,
  136. OrderingControl,
  137. ClassFilter,
  138. ClassRow,
  139. ModuleSearchModal,
  140. NumberedPagination,
  141. },
  142. setup() {
  143. const classesStore = useClassesStore();
  144. const planningStore = usePlanningStore();
  145. const stateStore = useStateStore();
  146. const studenthubStore = useStudenthubStore();
  147. const modulesStore = useModulesStore();
  148. return {
  149. classesStore,
  150. planningStore,
  151. studenthubStore,
  152. modulesStore,
  153. toTime,
  154. classesPDFLink,
  155. dayMap,
  156. pageSize: 12,
  157. stateStore,
  158. ClassSelectorColumn,
  159. };
  160. },
  161. data() {
  162. return {
  163. currentPageIdx: 0,
  164. inspectingClass: null as TaughtClass | null,
  165. };
  166. },
  167. computed: {
  168. filteredModules() {
  169. return this.classesStore.filteredModules;
  170. },
  171. paginatedClasses() {
  172. const idx = this.currentPageIdx;
  173. return this.filteredModules.slice(
  174. idx * this.pageSize,
  175. (idx + 1) * this.pageSize,
  176. );
  177. },
  178. },
  179. mounted() {
  180. watch(
  181. () => this.filteredModules,
  182. () => (this.currentPageIdx = 0),
  183. );
  184. },
  185. methods: {
  186. orderingChanged(col: ClassSelectorColumn, dir: Ordering) {
  187. this.classesStore.updateOrdering(col, dir);
  188. },
  189. },
  190. };
  191. </script>
  192. <style scoped>
  193. .no-results-text::after {
  194. @apply bg-gray-600 dark:bg-gray-300;
  195. content: "";
  196. width: 10px;
  197. height: 20px;
  198. margin-left: 3px;
  199. display: inline-block;
  200. animation: cursor-blink 1s alternate infinite;
  201. }
  202. @keyframes cursor-blink {
  203. 0% {
  204. opacity: 0;
  205. }
  206. }
  207. .action-button {
  208. @apply h-10
  209. text-xs
  210. px-10
  211. md:text-base
  212. mx-0.5
  213. md:mx-1
  214. block
  215. bg-gray-300
  216. dark:bg-gray-700
  217. hover:bg-gray-400
  218. active:bg-gray-500
  219. dark:hover:bg-gray-600
  220. dark:active:bg-gray-700
  221. dark:disabled:bg-gray-800
  222. dark:disabled:text-gray-600
  223. disabled:pointer-events-none
  224. rounded
  225. transition-all
  226. duration-200;
  227. }
  228. </style>