From 398e3aa139073e430f9c1d9721243a4741d1cde9 Mon Sep 17 00:00:00 2001 From: Johann Hoffmann Date: Thu, 7 May 2026 16:18:58 +0200 Subject: [PATCH] block deletion of benotet qulity gates; sync filter clear & semester dropdown; setSelecetedFields for flat table; WIP testing & refinement of everything; --- .../Cis/Abgabetool/AbgabeMitarbeiterDetail.js | 6 +- .../Cis/Abgabetool/AbgabetoolAssistenz.js | 80 +++++++++++++++---- .../Cis/Abgabetool/AbgabetoolMitarbeiter.js | 5 +- public/js/components/filter/Filter.js | 1 + 4 files changed, 75 insertions(+), 17 deletions(-) diff --git a/public/js/components/Cis/Abgabetool/AbgabeMitarbeiterDetail.js b/public/js/components/Cis/Abgabetool/AbgabeMitarbeiterDetail.js index 3c5855cad..c278b43ea 100644 --- a/public/js/components/Cis/Abgabetool/AbgabeMitarbeiterDetail.js +++ b/public/js/components/Cis/Abgabetool/AbgabeMitarbeiterDetail.js @@ -111,6 +111,8 @@ export const AbgabeMitarbeiterDetail = { if(newTerminRes.note) { newTerminRes.note = noteOpt newTerminRes.noteBackend = noteOpt // certain UI elements should only reflect persisted state + termin.allowedToDelete = false + newTerminRes.allowedToDelete = false } newTerminRes.invertedFixtermin = !newTerminRes.fixtermin const existingTerminRes = res.data[1] @@ -130,7 +132,7 @@ export const AbgabeMitarbeiterDetail = { } else { const noteOptExisting = this.allowedNotenOptions.find(opt => opt.note == existingTerminRes.note) existingTerminRes.note = noteOptExisting - + termin.paabgabetyp_kurzbz = newTerminRes.paabgabetyp_kurzbz termin.noteBackend = noteOpt // do NOT take noteOptExisting -> should reflect the "yes the qgate grade is confirmed in backend ux behaviour" termin.dateStyle = getDateStyleClass(termin, this.notenOptions) @@ -444,7 +446,7 @@ export const AbgabeMitarbeiterDetail = { } }, getMessagePtStyle() { - // adjust outer spacing and internal padding to appear similar to doenload button in size + // adjust outer spacing and internal padding to appear similar to download button in size return { root: { style: { diff --git a/public/js/components/Cis/Abgabetool/AbgabetoolAssistenz.js b/public/js/components/Cis/Abgabetool/AbgabetoolAssistenz.js index 58d894ec6..a45f1a301 100644 --- a/public/js/components/Cis/Abgabetool/AbgabetoolAssistenz.js +++ b/public/js/components/Cis/Abgabetool/AbgabetoolAssistenz.js @@ -67,6 +67,7 @@ export const AbgabetoolAssistenz = { filteredRowsFlat: null, studiensemesterOptions: null, allSem: null, + allSemOption: null, curSem: null, notenOptionFilter: null, inplaceToggle: false, @@ -312,8 +313,7 @@ export const AbgabetoolAssistenz = { .filter(r => filteredOutSet.has(r.getData())) .forEach(r => r.deselect()); } - } - ], + }], abgabeTableOptionsFlat: { minHeight: 250, height: 700, @@ -401,7 +401,7 @@ export const AbgabetoolAssistenz = { title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4zieldatumv2'))), field: 'datum', headerFilter: dateFilter, - headerFilterFunc: this.headerFilterTerminCol, + headerFilterFunc: this.headerFilterTerminColISO, sorter: (a, b) => new Date(a) - new Date(b), formatter: (cell) => this.formatDate(cell.getValue()), minWidth: 100 @@ -410,7 +410,7 @@ export const AbgabetoolAssistenz = { title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4abgabedatum'))), field: 'abgabedatum', headerFilter: dateFilter, - headerFilterFunc: this.headerFilterTerminCol, + headerFilterFunc: this.headerFilterTerminColISO, sorter: (a, b) => new Date(a) - new Date(b), formatter: (cell) => this.formatDate(cell.getValue()), minWidth: 100 @@ -435,7 +435,9 @@ export const AbgabetoolAssistenz = { if (!val) return ''; return val?.bezeichnung ?? this.notenOptions?.find(n => n.note == val)?.bezeichnung ?? val; }, - minWidth: 100 + minWidth: 100, + tooltip: false, + headerFilter: true }, { title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4notetermin'))), @@ -445,7 +447,8 @@ export const AbgabetoolAssistenz = { if (!val) return ''; return val?.bezeichnung ?? this.notenOptions?.find(n => n.note == val)?.bezeichnung ?? val; }, - minWidth: 100 + minWidth: 100, + headerFilter: true }, { title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4notizQualGatev2'))), @@ -516,6 +519,11 @@ export const AbgabetoolAssistenz = { }; }, methods: { + handleFilterActiveChanged(active) { + if(!active && this.allSemOption) { + this.curSem = this.allSemOption + } + }, reloadData() { this.loadProjektarbeiten() }, @@ -971,6 +979,41 @@ export const AbgabetoolAssistenz = { // just in case someone reuses this return Math.abs(b.diffMs) - Math.abs(a.diffMs) }, + headerFilterTerminColISO(filterVal, rowVal) { + if (!rowVal) { + return false; + } + + const toLuxon = (val) => { + if (!val) return null; + let dt; + if (val instanceof Date) { + dt = luxon.DateTime.fromJSDate(val); + } else if (typeof val === "string") { + dt = luxon.DateTime.fromISO(val); + } else { // fallback + dt = luxon.DateTime.fromMillis(Number(val)); + } + + return dt.isValid ? dt : null; + }; + + const rowDate = toLuxon(rowVal); + const von = toLuxon(filterVal[0]); + const bis = toLuxon(filterVal[1]); + + // specific day + if (von && !bis) { + return rowDate.hasSame(von, "day"); + } + + // range case + if (von && bis) { + return rowDate >= von.startOf("day") && rowDate <= bis.endOf("day"); + } + + return false + }, headerFilterTerminCol(filterVal, rowVal) { if (!rowVal || !rowVal.luxonDate || !rowVal.luxonDate.isValid) { return false; @@ -1736,7 +1779,7 @@ export const AbgabetoolAssistenz = { termin.allowedToSave = paIsBenotet ? false : true // assistenz are not allowed to delete deadlines with existing submissions - termin.allowedToDelete = paIsBenotet ? false : !termin.abgabedatum + termin.allowedToDelete = paIsBenotet ? false : !termin.abgabedatum && !termin.note }) @@ -1837,14 +1880,14 @@ export const AbgabetoolAssistenz = { const bezeichnung = val.bezeichnung?.bezeichnung ?? val.bezeichnung if(formatterParams?.iconOnly) { - return '
' + + return '
' + '
' + icon + '
' + '
' } - return '
' + + return '
' + '
' + icon + '
' + @@ -1966,14 +2009,18 @@ export const AbgabetoolAssistenz = { }, }, computed: { + getDisableDeleteForSelectedFlat() { + return this.selectedDataFlat.some(s => s.allowedToDelete === false) + }, + getDisableSaveForSelectedFlat(){ + return this.selectedDataFlat.some(s => s.allowedToSave === false) + }, getAllTermine() { if (!this.projektarbeiten) return []; return this.projektarbeiten.flatMap(pa => pa.abgabetermine.map(termin => { - // TODO: allowedToDelete prüfung auf terminnote? benotete qgate termine sollten "sicher" sein? - const allowedToSave = pa.note !== null ? false : true - const allowedToDelete = pa.note !== null ? false : !termin.abgabedatum + const allowedToDelete = pa.note !== null ? false : !termin.abgabedatum && !termin.note return { allowedToSave, allowedToDelete, @@ -1986,6 +2033,9 @@ export const AbgabetoolAssistenz = { pa_note: pa.note, projektarbeit_id: pa.projektarbeit_id, stg: pa.stg, + pkz: pa.pkz, + studienstatus: pa.studienstatus, + orgform: pa.orgform } } @@ -2149,6 +2199,7 @@ export const AbgabetoolAssistenz = { this.allSem = res.data[0]; const all = { studiensemester_kurzbz: this.$p.t('abgabetool/c4all') }; + this.allSemOption = all this.studiensemesterOptions = [all, ...this.allSem]; const currentSemObj = res.data[1]; @@ -2559,6 +2610,7 @@ export const AbgabetoolAssistenz = { :tabulator-options="abgabeTableOptions" :tabulator-events="abgabeTableEventHandlers" @tableBuilt="handleTableBuilt" + @headerFilterOn="handleFilterActiveChanged" tableOnly :sideMenu="false" :useSelectionSpan="false" @@ -2613,12 +2665,12 @@ export const AbgabetoolAssistenz = { :useSelectionSpan="false" >