diff --git a/application/controllers/api/frontend/v1/Noten.php b/application/controllers/api/frontend/v1/Noten.php index 68bd3f4fd..290105cdf 100644 --- a/application/controllers/api/frontend/v1/Noten.php +++ b/application/controllers/api/frontend/v1/Noten.php @@ -69,8 +69,8 @@ class Noten extends FHCAPI_Controller // get studenten for lva & sem with zeugnisnote if available $studenten = $this->LehrveranstaltungModel->getStudentsByLv($sem_kurzbz, $lv_id); -// $studentenData = $this->getDataOrTerminateWithError($studenten); - $studentenData = getData($studenten); + $studentenData = $this->getDataOrTerminateWithError($studenten); +// $studentenData = getData($studenten); $this->addMeta('$studentenData', $studentenData); $func = function ($value) { diff --git a/public/js/components/Cis/Benotungstool/Benotungstool.js b/public/js/components/Cis/Benotungstool/Benotungstool.js index fdbcf098d..cbc73415c 100644 --- a/public/js/components/Cis/Benotungstool/Benotungstool.js +++ b/public/js/components/Cis/Benotungstool/Benotungstool.js @@ -143,7 +143,6 @@ export const Benotungstool = { return true; // student can be selected to add pruefung }, - rowFormatter: this.unselectableFormatter, columns: [ { formatter: "rowSelection", @@ -203,15 +202,19 @@ export const Benotungstool = { formatter: this.notenFormatter, headerFilter: 'list', headerFilterParams: () => { - return { values: ["\u00A0",...this.notenOptions.map(opt => opt.bezeichnung)] } // TODO: fix option render height lmao... + return { values: ["\u00A0",this.$p.t('benotungstool/c4noteEmpty') ,this.$p.t('benotungstool/c4positiv'), this.$p.t('benotungstool/c4negativ') ,...this.notenOptions.map(opt => opt.bezeichnung)] } }, headerFilterFunc: this.notenFilterFunc, widthGrow: 1}, {title: Vue.computed(() => this.$p.t('benotungstool/c4freigabe')), field: 'freigegeben', widthGrow: 1, formatter: this.freigabeFormatter}, {title: Vue.computed(() => this.$p.t('benotungstool/c4zeugnisnote')), - headerFilter: true, field: 'note', formatter: this.notenFormatter, + headerFilter: 'list', + headerFilterParams: () => { + return { values: ["\u00A0", this.$p.t('benotungstool/c4noteEmpty'),this.$p.t('benotungstool/c4positiv'), this.$p.t('benotungstool/c4negativ') ,...this.notenOptions.map(opt => opt.bezeichnung)] } + }, + headerFilterFunc: this.notenFilterFunc, widthGrow: 1}, {title: Vue.computed(() => this.$p.t('benotungstool/c4kommPruef')), field: 'kommPruef', widthGrow: 1, formatter: this.pruefungFormatter, hozAlign:"center", minWidth: 150} ], @@ -219,9 +222,33 @@ export const Benotungstool = { } }, notenFilterFunc(filterVal, rowVal) { + // option of the searchterm const opt = this.notenOptions.find(opt => opt.bezeichnung === filterVal) - if(opt.note == rowVal) return true - if(filterVal === "" || filterVal === null) return true + // searchterm is not empty fallback and the note finds an option match + if(rowVal !== null && rowVal !== undefined && opt?.note == rowVal) { + return true + } + + // empty searchterm fallback to show all + if(filterVal === "\u00A0" || filterVal === "" || filterVal === null) { + return true + } + + // specific searchterm cases + if(filterVal === this.$p.t('benotungstool/c4positiv')) { + // option of the rowValue + const valOpt = this.notenOptions.find(opt => opt.note == rowVal) + if(!valOpt) return false + return valOpt.positiv + } + if(filterVal === this.$p.t('benotungstool/c4negativ')) { + const valOpt = this.notenOptions.find(opt => opt.note == rowVal) + if(!valOpt) return false + return !valOpt.positiv + } + if(filterVal === this.$p.t('benotungstool/c4noteEmpty') && rowVal === null) { + return true + } return false }, @@ -701,7 +728,51 @@ export const Benotungstool = { lv_id: e.value.lehrveranstaltung_id } }) + + // reload related LE to LV to repopulate LE filter dropdown + + // TODO: reset old LE selection to null + this.$api.call(ApiLehre.getLeForLv(e.value.lehrveranstaltung_id, this.sem_kurzbz)).then(res => { + const data = [] + // TODO: could be done on server in some shared function, copied from anw extension for now + res.data?.retval?.forEach(entry => { + + const existing = data.find(e => e.lehreinheit_id === entry.lehreinheit_id) + if (existing) { + // supplement info + existing.infoString += ', ' + if (entry.gruppe_kurzbz !== null) { + existing.infoString += entry.gruppe_kurzbz + } else { + existing.infoString += entry.kurzbzlang + '-' + entry.semester + + (entry.verband ? entry.verband : '') + + (entry.gruppe ? entry.gruppe : '') + } + } else { + // entries are supposed to be fetched ordered by non null gruppe_kurzbz first + // so a new entry will always start with those groups, others are appended afterwards + entry.infoString = entry.kurzbz + ' - ' + entry.lehrform_kurzbz + ' - ' + if (entry.gruppe_kurzbz !== null) { + entry.infoString += entry.gruppe_kurzbz + } else { + entry.infoString += entry.kurzbzlang + '-' + entry.semester + + (entry.verband ? entry.verband : '') + + (entry.gruppe ? entry.gruppe : '') + } + + data.push(entry) + } + }) + + data.forEach(entry => { + entry.infoString += ' | 👥' + entry.studentcount + ' | 📅' + entry.termincount + }) + + this.lehreinheiten = [...data] + + }) + // reload data this.loadNoten(e.value.lehrveranstaltung_id, this.sem_kurzbz) }, @@ -716,7 +787,7 @@ export const Benotungstool = { }) // diff lv_id -> reload zugewiesene lv - this.$api.call(ApiLehre.getZugewieseneLv(this.viewData?.uid, this.sem_kurzbz)).then(res => { + this.$api.call(ApiLehre.getZugewieseneLv(this.viewData?.uid, e.value.studiensemester_kurzbz)).then(res => { this.lehrveranstaltungen = res.data // build dropdown option string @@ -726,6 +797,49 @@ export const Benotungstool = { this.selectedLehrveranstaltung = this.lehrveranstaltungen.find(lva => lva.lehrveranstaltung_id == this.lv_id) }).then(()=>{ + + // TODO: reset old LE selection to null + this.$api.call(ApiLehre.getLeForLv(this.lv_id, e.value.studiensemester_kurzbz)).then(res => { + + const data = [] + // TODO: could be done on server in some shared function, copied from anw extension for now + res.data?.retval?.forEach(entry => { + + const existing = data.find(e => e.lehreinheit_id === entry.lehreinheit_id) + if (existing) { + // supplement info + existing.infoString += ', ' + if (entry.gruppe_kurzbz !== null) { + existing.infoString += entry.gruppe_kurzbz + } else { + existing.infoString += entry.kurzbzlang + '-' + entry.semester + + (entry.verband ? entry.verband : '') + + (entry.gruppe ? entry.gruppe : '') + } + } else { + // entries are supposed to be fetched ordered by non null gruppe_kurzbz first + // so a new entry will always start with those groups, others are appended afterwards + entry.infoString = entry.kurzbz + ' - ' + entry.lehrform_kurzbz + ' - ' + if (entry.gruppe_kurzbz !== null) { + entry.infoString += entry.gruppe_kurzbz + } else { + entry.infoString += entry.kurzbzlang + '-' + entry.semester + + (entry.verband ? entry.verband : '') + + (entry.gruppe ? entry.gruppe : '') + } + + data.push(entry) + } + }) + + data.forEach(entry => { + entry.infoString += ' | 👥' + entry.studentcount + ' | 📅' + entry.termincount + }) + + this.lehreinheiten = [...data] + + }) + // reload data this.loadNoten(this.lv_id, e.value.studiensemester_kurzbz) }) @@ -802,11 +916,23 @@ export const Benotungstool = { // antritte might have changed due to different benotung s.hoechsterAntritt = this.getAntrittCountStudent(s) } - + + // TODO: maybe fake rerun the selectable check by just assigning + // css classes tabulator-selectable/tabulator-unselectable on row elements + + // const rows = this.$refs.notenTable.tabulator.getRows() + // const row = rows.find(r => { + // const data = r.getData() + // return data.uid == this.pruefungStudent.uid + // }) + // row.reformat() this.$refs.notenTable.tabulator.redraw(true) this.$fhcAlert.alertInfo('Prüfung gespeichert') // TODO: phrase } + }).finally(()=> { + this.pruefungStudent = null + this.pruefung = null }) this.$refs.modalContainerPruefung.hide() @@ -863,7 +989,7 @@ export const Benotungstool = { // TODO: should studenten without shadow pruefung Termin have their "ursprüngliche Zeugnisnote" // col filled for consistency reasons? - // TODO: test if this holds true + // TODO: test if this holds true, maybe in case where there are only kommPruef? const originalNote = index === 0 cols.push({ title: titledate,//this.$p.t('benotungstool/pruefungNr', [index+1]), @@ -878,10 +1004,12 @@ export const Benotungstool = { }) cols.push(kommCol) // keep kommPruef Col as last - // redraw table - - + + // set Cols + this.$refs.notenTable.tabulator.clearSort() + this.$refs.notenTable.tabulator.setColumns(cols) + // redraw table outside this function }, saveNoteneingabe() { this.$api.call(ApiNoten.saveStudentenNoten(this.password, this.changedNoten, this.lv_id, this.sem_kurzbz)) @@ -1141,7 +1269,6 @@ export const Benotungstool = {
{{$p.t('lehre/note')}}:
- -
-
+

{{$p.t('benotungstool/benotungstoolTitle')}}

{{ lv?.bezeichnung }}

@@ -1233,7 +1358,7 @@ export const Benotungstool = {
+ v-model="selectedLehrveranstaltung" :options="lehrveranstaltungen" appendTo="self"> @@ -1244,7 +1369,7 @@ export const Benotungstool = {
+ v-model="selectedLehreinheit" :options="lehreinheiten" showClear appendTo="self"> @@ -1255,7 +1380,7 @@ export const Benotungstool = {
+ v-model="selectedSemester" :options="studiensemester" appendTo="self"> @@ -1265,27 +1390,27 @@ export const Benotungstool = {

- - - - - +
+ + + +
`, }; diff --git a/system/phrasesupdate.php b/system/phrasesupdate.php index 5fd21a182..5cfa302cd 100644 --- a/system/phrasesupdate.php +++ b/system/phrasesupdate.php @@ -41976,6 +41976,66 @@ and represent the current state of research on the topic. The prescribed citatio ) ) ), + array( + 'app' => 'core', + 'category' => 'benotungstool', + 'phrase' => 'c4positiv', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Positiv', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'positive', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'benotungstool', + 'phrase' => 'c4negativ', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Negativ', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'negative', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'benotungstool', + 'phrase' => 'c4noteEmpty', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Unbenotet', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Ungraded', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), array( 'app' => 'core', 'category' => 'benotungstool',