| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316 |
- <template>
- <div class="flex items-center justify-center w-full mt-5 gap-2">
- <button
- :title="chooseTitle"
- class="action-button"
- :disabled="hasCompletedModule || maxAttemptsReached"
- @click="toggleClassState"
- >
- <font-awesome-icon
- v-if="addable"
- class="py-2 text-xl"
- icon="fa-solid fa-plus"
- />
- <font-awesome-icon
- v-else
- class="py-2 text-xl"
- icon="fa-solid fa-minus"
- />
- </button>
- <button
- title="Modulinformationen"
- class="action-button"
- :disabled="!module"
- @click="stateStore.inspectingModule = module"
- >
- <font-awesome-icon
- class="py-2 text-xl"
- icon="fa-solid fa-puzzle-piece"
- />
- </button>
- <a
- :href="
- !module
- ? ''
- : `${URLS.ADDITIONAL_MODULE_INFORMATION}${module.module_id}`
- "
- target="_blank"
- :title="
- module?.module_id === null
- ? 'Keine Modul-ID vorhanden'
- : `${SCHOOL_NAME} Modulbeschreibung`
- "
- class="action-button"
- :class="[!module ? 'action-button-disabled' : '']"
- >
- <font-awesome-icon
- class="py-2 text-xl"
- icon="fa-solid fa-info"
- />
- </a>
- <a
- title="Klassen PDF in einem neuem Tab öffnen"
- :href="classesPDFLink(cls)"
- target="_blank"
- class="action-button"
- >
- <font-awesome-icon
- class="py-2 text-xl"
- icon="fa-solid fa-file-pdf"
- />
- </a>
- </div>
- <table class="mt-5 w-full text-left">
- <tbody>
- <tr>
- <td class="font-bold">
- <span>Dozent</span>
- </td>
- <td>
- <ul
- class="list-inside"
- :class="[lecturers.length > 1 ? 'list-disc' : '']"
- >
- <li
- v-for="lecturer in lecturers"
- :key="lecturer.short"
- >
- <span><b>{{ lecturer.short }}</b>: {{ lecturer.firstname }} {{ lecturer.surname }}</span>
- </li>
- </ul>
- </td>
- </tr>
- <tr>
- <td class="font-bold">
- <span>Klasse</span>
- </td>
- <td>
- <span>{{ cls.class }}</span>
- </td>
- </tr>
- <tr>
- <td class="font-bold">
- <span>Raum</span>
- </td>
- <td>
- <ul
- class="list-inside"
- :class="[cls.rooms.length > 1 ? 'list-disc' : '']"
- >
- <li
- v-for="room in cls.rooms"
- :key="room"
- >
- <span>{{ room }}</span>
- </li>
- </ul>
- </td>
- </tr>
- <tr>
- <td class="font-bold">
- <span>Art</span>
- </td>
- <td>
- <TeachingTypeIcon :teaching-type="cls.teaching_type" />
- </td>
- </tr>
- <tr>
- <td class="font-bold">
- <span>Durchführung</span>
- </td>
- <td>
- <span v-if="cls.weekday !== null">{{ dayMap[cls.weekday] }}, {{ toTime(cls.from) }} -
- {{ toTime(cls.to) }}</span>
- <span v-else>Blockmodul</span>
- </td>
- </tr>
- <tr>
- <td class="font-bold">
- <span>ECTS</span>
- </td>
- <td>
- <span>{{ module?.ects ?? "-" }}</span>
- </td>
- </tr>
- <tr>
- <td class="font-bold">
- <span>Benotung</span>
- </td>
- <td>
- <span>{{ module ? module.marksClean : "?" }}</span>
- </td>
- </tr>
- <tr>
- <td
- :colspan="moduleClasses.length == 0 ? 1 : 2"
- class="font-bold"
- >
- <span>Weitere Durchführungen</span>
- </td>
- <td>
- <span v-if="moduleClasses.length == 0">Keine</span>
- </td>
- </tr>
- <tr v-if="moduleClasses.length > 0">
- <td
- colspan="2"
- class="pb-5"
- >
- <CurrentModuleExecutions
- :module-classes="moduleClasses"
- :highlight-class="cls"
- />
- </td>
- </tr>
- <tr>
- <td class="font-bold">
- <span>Abhängigkeiten</span>
- <div
- title="Abhängigkeiten sind teilweise sehr unklar von der Schule definiert und variieren basierend auf verschiedenen Dokumenten. Teilweise ist es nicht möglich, die Abhängigkeiten automatisch zu detektieren (keine Modulkürzel in der Abhängigkeitsbeschreibung)."
- class="mx-2 w-5 text-xs aspect-square rounded-full bg-gray-200 dark:bg-gray-400 inline-flex items-center justify-center cursor-help"
- >
- <font-awesome-icon icon="fa-solid fa-info" />
- </div>
- </td>
- <td>
- <span>{{ module ? (hasModuleDeps ? "" : "Keine") : "-" }}</span>
- </td>
- </tr>
- </tbody>
- </table>
- </template>
- <script lang="ts">
- import { PropType } from "vue";
- import {
- classesPDFLink,
- dayMap,
- toTime,
- MAX_ATTEMPT_COUNT,
- } from "../../helpers";
- import { useClassesStore } from "../../stores/classes";
- import { useLecturersStore } from "../../stores/lecturers";
- import { useModulesStore } from "../../stores/modules";
- import { usePlanningStore } from "../../stores/planning";
- import { useStateStore } from "../../stores/state";
- import { useStudenthubStore } from "../../stores/studenthub";
- import { Module, TaughtClass, Lecturer, TeachingType } from "../../types";
- import CurrentModuleExecutions from "./CurrentModuleExecutions.vue";
- import TeachingTypeIcon from "./TeachingTypeIcon.vue";
- import { URLS, SCHOOL_NAME } from "../../globals";
- export default {
- name: "ClassInfo",
- components: { CurrentModuleExecutions, TeachingTypeIcon },
- props: {
- cls: {
- type: Object as PropType<TaughtClass>,
- required: true,
- },
- },
- setup() {
- const modulesStore = useModulesStore();
- const lecturersStore = useLecturersStore();
- const planningStore = usePlanningStore();
- const stateStore = useStateStore();
- const studenthubStore = useStudenthubStore();
- const classesStore = useClassesStore();
- return {
- modulesStore,
- lecturersStore,
- planningStore,
- stateStore,
- studenthubStore,
- classesStore,
- dayMap,
- toTime,
- classesPDFLink,
- TeachingType,
- URLS,
- SCHOOL_NAME,
- };
- },
- computed: {
- lecturers(): Lecturer[] {
- const r = this.lecturersStore.fromShort(this.cls.teachers);
- return r;
- },
- hasCompletedModule(): boolean {
- return this.studenthubStore.hasCompletedModule(
- this.module?.module_id ?? null
- );
- },
- module(): Module | null {
- return this.cls.module;
- },
- hasModuleDeps(): boolean {
- if (this.module === null) return false;
- return (
- Object.values(this.module.dependencies).reduce(
- (sum, dep) => sum + dep.length,
- 0
- ) > 0
- );
- },
- maxAttemptsReached(): boolean {
- return (this.module?.attemptCount ?? 0) >= MAX_ATTEMPT_COUNT;
- },
- chooseTitle(): string {
- if (this.hasCompletedModule) return "Modul bereits bestanden";
- if (this.maxAttemptsReached)
- return `Du hast dieses Modul bereits ${this.module?.attemptCount} Mal versucht!`;
- if (this.classChosen) return "Von der Planung entfernen";
- return "Zur Planung hinzufügen";
- },
- classChosen(): boolean {
- return this.planningStore.isModuleChosen(this.cls);
- },
- addable(): boolean {
- return !this.classChosen || this.hasCompletedModule;
- },
- moduleClasses(): TaughtClass[] {
- if (this.module === null) return [];
- return this.classesStore.classesForModule(this.module.short);
- },
- },
- methods: {
- toggleClassState() {
- if (this.classChosen) this.planningStore.remove(this.cls);
- else this.planningStore.add(this.cls);
- },
- },
- };
- </script>
- <style scoped>
- .action-button {
- @apply text-center
- bg-gray-200
- hover:bg-gray-300
- active:bg-gray-400
- dark:bg-gray-600
- dark:hover:bg-gray-700
- dark:active:bg-gray-900
- rounded
- cursor-pointer
- w-full
- p-0
- transition-all
- duration-200
- disabled:dark:bg-gray-600
- disabled:text-gray-500
- disabled:bg-gray-100
- disabled:pointer-events-none;
- }
- .action-button-disabled {
- @apply pointer-events-none
- dark:bg-gray-600
- text-gray-500
- bg-gray-100;
- }
- </style>
|