From e7fdbe13d0aea584567e98bcfdf624a7702340da Mon Sep 17 00:00:00 2001 From: ma0048 Date: Thu, 20 Nov 2025 15:32:27 +0100 Subject: [PATCH 01/18] nullable felder speichern --- .../controllers/api/frontend/v1/lv/Lektor.php | 11 +++++++--- application/libraries/LektorLib.php | 21 +++++++++++++++---- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/application/controllers/api/frontend/v1/lv/Lektor.php b/application/controllers/api/frontend/v1/lv/Lektor.php index cce7f6e8b..d13bb94dd 100644 --- a/application/controllers/api/frontend/v1/lv/Lektor.php +++ b/application/controllers/api/frontend/v1/lv/Lektor.php @@ -134,9 +134,14 @@ class Lektor extends FHCAPI_Controller $this->terminateWithValidationErrors($this->form_validation->error_array()); } - if (isset($formData['semesterstunden']) && (!is_numeric($formData['semesterstunden']) || $formData['semesterstunden'] === '')) + $nullable_fields = array('semesterstunden', 'stundensatz', 'planstunden'); + + foreach ($nullable_fields as $nullable_field) { - $formData['semesterstunden'] = null; + if (isset($formData[$nullable_field]) && (!is_numeric($formData[$nullable_field]) || $formData[$nullable_field] === '')) + { + $formData[$nullable_field] = null; + } } $lehreinheit_permission = $this->checkPermission($lehreinheit_id, array('admin', 'assistenz', 'lv-plan')); @@ -154,7 +159,7 @@ class Lektor extends FHCAPI_Controller { $value = str_replace(',', '.', $value); - if (!is_numeric($value)) + if (!is_numeric($value) && $value !== "") { $this->form_validation->set_message('_check_decimal', 'Das Feld {field} muss eine Zahl sein.'); return false; diff --git a/application/libraries/LektorLib.php b/application/libraries/LektorLib.php index bbe630eaf..6cc58d3ba 100644 --- a/application/libraries/LektorLib.php +++ b/application/libraries/LektorLib.php @@ -142,10 +142,12 @@ class LektorLib $oe_result = $this->_ci->OrganisationseinheitModel->getChilds($stundengrenze->oe_kurzbz); $oe_array = hasData($oe_result) ? array_column(getData($oe_result), 'oe_kurzbz') : array(''); + $old_semesterstunden = $lehreinheit->semesterstunden ?: 0; + if ($alte_stunden_eingerechnet && $neue_stunden_eingerechnet) - $this->_ci->LehreinheitmitarbeiterModel->addSelect("(SUM(tbl_lehreinheitmitarbeiter.semesterstunden) - ($lehreinheit->semesterstunden) + {$this->_ci->LehreinheitmitarbeiterModel->db->escape($new_data['semesterstunden'])}) as summe"); + $this->_ci->LehreinheitmitarbeiterModel->addSelect("(SUM(tbl_lehreinheitmitarbeiter.semesterstunden) - ($old_semesterstunden) + {$this->_ci->LehreinheitmitarbeiterModel->db->escape($new_data['semesterstunden'])}) as summe"); else if ($alte_stunden_eingerechnet && !$neue_stunden_eingerechnet) - $this->_ci->LehreinheitmitarbeiterModel->addSelect("(SUM(tbl_lehreinheitmitarbeiter.semesterstunden) - ($lehreinheit->semesterstunden)) as summe"); + $this->_ci->LehreinheitmitarbeiterModel->addSelect("(SUM(tbl_lehreinheitmitarbeiter.semesterstunden) - ($old_semesterstunden)) as summe"); else if (!$alte_stunden_eingerechnet && $neue_stunden_eingerechnet) $this->_ci->LehreinheitmitarbeiterModel->addSelect("(SUM(tbl_lehreinheitmitarbeiter.semesterstunden) + ({$this->_ci->LehreinheitmitarbeiterModel->db->escape($new_data['semesterstunden'])})) as summe"); else if (!$alte_stunden_eingerechnet && !$neue_stunden_eingerechnet) @@ -227,12 +229,23 @@ class LektorLib 'bismelden' ); + $nullable_fields = array('stundensatz', 'semesterstunden', 'planstunden'); + $updateData = array(); foreach ($updatableFields as $field) { - $value = isset($new_data[$field]) ? $new_data[$field] : null; + if (!array_key_exists($field, $new_data)) + { + continue; + } - if ($value !== null) + $value = $new_data[$field]; + + if (in_array($field, $nullable_fields)) + { + $updateData[$field] = $value; + } + elseif ($value !== null) { $updateData[$field] = $value; } From 1ab96350390a778c084168b7b7c5fb99df066c52 Mon Sep 17 00:00:00 2001 From: ma0048 Date: Wed, 26 Nov 2025 13:56:37 +0100 Subject: [PATCH 02/18] disitnct lv id --- application/models/education/Lehrveranstaltung_model.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/models/education/Lehrveranstaltung_model.php b/application/models/education/Lehrveranstaltung_model.php index 7347cf2ca..95ccccd71 100644 --- a/application/models/education/Lehrveranstaltung_model.php +++ b/application/models/education/Lehrveranstaltung_model.php @@ -1211,7 +1211,7 @@ class Lehrveranstaltung_model extends DB_Model { return " SELECT - lehrveranstaltung_id, tbl_lehrveranstaltung.kurzbz as lv_kurzbz, tbl_lehrveranstaltung.bezeichnung as lv_bezeichnung, bezeichnung_english as lv_bezeichnung_english, studiengang_kz, + distinct on (lehrveranstaltung_id) lehrveranstaltung_id, tbl_lehrveranstaltung.kurzbz as lv_kurzbz, tbl_lehrveranstaltung.bezeichnung as lv_bezeichnung, bezeichnung_english as lv_bezeichnung_english, studiengang_kz, tbl_studienplan_lehrveranstaltung.semester, tbl_lehrveranstaltung.sprache, ects as lv_ects, semesterstunden, anmerkung, lehre, lehreverzeichnis as lv_lehreverzeichnis, tbl_lehrveranstaltung.aktiv, planfaktor as lv_planfaktor, planlektoren as lv_planlektoren, planpersonalkosten as lv_planpersonalkosten, From 0de033e42884a27440c2bb594a910203bf0d5da2 Mon Sep 17 00:00:00 2001 From: ma0048 Date: Mon, 1 Dec 2025 10:55:04 +0100 Subject: [PATCH 03/18] termine tab hinzugefuegt --- .../controllers/api/frontend/v1/LvPlan.php | 43 +++++++++++++- .../controllers/api/frontend/v1/lv/Setup.php | 16 +++++ .../api/frontend/v1/stv/LvTermine.php | 9 +-- application/libraries/StundenplanLib.php | 15 +++++ .../models/ressource/Stundenplan_model.php | 58 +++++++++++++++++++ public/js/api/factory/studiensemester.js | 8 +++ public/js/api/factory/stv/coursedates.js | 20 +++---- public/js/api/lehrveranstaltung/letermine.js | 13 +++++ public/js/api/lehrveranstaltung/lvtermine.js | 13 +++++ public/js/api/lehrveranstaltung/setup.js | 7 +++ .../components/LVVerwaltung/LVVerwaltung.js | 1 - .../js/components/LVVerwaltung/Setup/Table.js | 3 +- .../js/components/LVVerwaltung/Setup/Tabs.js | 18 +++++- .../components/LVVerwaltung/Tabs/LVTermine.js | 21 +++++++ .../components/LVVerwaltung/Tabs/Termine.js | 21 +++++++ .../Details/Lehrveranstaltungstermine.js | 10 +++- .../ListLehrveranstaltungstermine.js | 38 +++++------- 17 files changed, 263 insertions(+), 51 deletions(-) create mode 100644 public/js/api/factory/studiensemester.js create mode 100644 public/js/api/lehrveranstaltung/letermine.js create mode 100644 public/js/api/lehrveranstaltung/lvtermine.js create mode 100644 public/js/components/LVVerwaltung/Tabs/LVTermine.js create mode 100644 public/js/components/LVVerwaltung/Tabs/Termine.js diff --git a/application/controllers/api/frontend/v1/LvPlan.php b/application/controllers/api/frontend/v1/LvPlan.php index 28b48e3f1..257c04960 100644 --- a/application/controllers/api/frontend/v1/LvPlan.php +++ b/application/controllers/api/frontend/v1/LvPlan.php @@ -41,7 +41,9 @@ class LvPlan extends FHCAPI_Controller 'getLehreinheitStudiensemester' => self::PERM_LOGGED, 'studiensemesterDateInterval' => self::PERM_LOGGED, 'getLvPlanForStudiensemester' => self::PERM_LOGGED, - 'getLv' => self::PERM_LOGGED + 'getLv' => self::PERM_LOGGED, + 'getLeEvents' => self::PERM_LOGGED, + 'getLvEvents' => self::PERM_LOGGED, ]); $this->load->library('LogLib'); @@ -54,6 +56,12 @@ class LvPlan extends FHCAPI_Controller )); $this->load->library('form_validation'); + $this->load->library('PhrasesLib'); + $this->loadPhrases( + array( + 'ui' + ) + ); } //------------------------------------------------------------------------------------------------------------------ @@ -145,6 +153,39 @@ class LvPlan extends FHCAPI_Controller )); } + public function getLeEvents($le_id = null, $start_date = null, $end_date = null, $stundenplan = 'stundenplandev') + { + + if (is_null($le_id) || is_null($start_date) || is_null($end_date)) + $this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL); + + if ($stundenplan !== 'stundenplandev' && $stundenplan !== 'stundenplan') + $this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL); + + $this->load->library('StundenplanLib'); + + $result = $this->stundenplanlib->getEventsByLE($le_id, $start_date, $end_date, $stundenplan); + $lvplanEvents = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($lvplanEvents); + } + + public function getLvEvents($lv_id = null, $start_date = null, $end_date = null, $stundenplan = 'stundenplandev') + { + if (is_null($lv_id) || is_null($start_date) || is_null($end_date)) + $this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL); + + if ($stundenplan !== 'stundenplandev' && $stundenplan !== 'stundenplan') + $this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL); + + $this->load->library('StundenplanLib'); + + $result = $this->stundenplanlib->getEventsByLV($lv_id, $start_date, $end_date, $stundenplan); + $lvplanEvents = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($lvplanEvents); + } + //TODO: delete this function if we don't use the old calendar export endpoints anymore public function studiensemesterDateInterval($date){ $this->load->model('organisation/Studiensemester_model','StudiensemesterModel'); diff --git a/application/controllers/api/frontend/v1/lv/Setup.php b/application/controllers/api/frontend/v1/lv/Setup.php index a2c167dd6..77ab0edda 100644 --- a/application/controllers/api/frontend/v1/lv/Setup.php +++ b/application/controllers/api/frontend/v1/lv/Setup.php @@ -28,6 +28,7 @@ class Setup extends FHCAPI_Controller { parent::__construct([ 'getTabs' => ['admin:r', 'assistenz:r'], + 'getTab' => ['admin:r', 'assistenz:r'], 'getStudiensemester' => ['admin:r', 'assistenz:r'], 'getSprache' => ['admin:r', 'assistenz:r'], 'getRaumtyp' => ['admin:r', 'assistenz:r'], @@ -60,6 +61,11 @@ class Setup extends FHCAPI_Controller 'component' => APP_ROOT . 'public/js/components/LVVerwaltung/Tabs/Lektor.js', 'config' => [] ); + $tabs['termine'] = array ( + 'title' => 'Termine', + 'component' => APP_ROOT . 'public/js/components/LVVerwaltung/Tabs/Termine.js', + 'config' => [] + ); $tabs['notiz'] = array ( 'title' => 'Notizen', 'component' => APP_ROOT . 'public/js/components/LVVerwaltung/Tabs/Notiz.js', @@ -68,6 +74,16 @@ class Setup extends FHCAPI_Controller $this->terminateWithSuccess($tabs); } + public function getTab() + { + $tabs['termine'] = array ( + 'title' => 'Termine', + 'component' => APP_ROOT . 'public/js/components/LVVerwaltung/Tabs/LVTermine.js', + 'config' => [] + ); + $this->terminateWithSuccess($tabs); + } + public function getStudiensemester() { $this->_ci->load->model('organisation/Studiensemester_model', 'StudiensemesterModel'); diff --git a/application/controllers/api/frontend/v1/stv/LvTermine.php b/application/controllers/api/frontend/v1/stv/LvTermine.php index c29f56964..b9e23e77d 100644 --- a/application/controllers/api/frontend/v1/stv/LvTermine.php +++ b/application/controllers/api/frontend/v1/stv/LvTermine.php @@ -34,7 +34,7 @@ class LvTermine extends FHCAPI_Controller //TODO Build own lib or combine with Controller Stundenplan.php //here use of logic of Stundenplan.php, extended with parameters uid, grouping, and used dbTable - public function getStundenplan($uid, $start_date = null, $end_date = null, $groupConsecutiveHours = false, $dbStundenplanTable = "stundenplan") + public function getStundenplan($uid, $start_date = null, $end_date = null, $dbStundenplanTable = "stundenplan", $groupConsecutiveHours = false) { $student_uid = $uid; $semester_range = $this->studienSemesterErmitteln($start_date, $end_date); @@ -80,13 +80,6 @@ class LvTermine extends FHCAPI_Controller $stundenplan_data = $this->getDataOrTerminateWithError($stundenplan_data) ?? []; $this->terminateWithSuccess($stundenplan_data); - - $this->expand_object_information($stundenplan_data); - - $this->returnObj['$stundenplan_query'] = $stundenplan_query; - $this->returnObj['$student_lehrverband'] = $student_lehrverband; - $this->returnObj['$benutzer_gruppen'] = $benutzer_gruppen; - $this->terminateWithSuccess($stundenplan_data); } public function getStudiensemester() diff --git a/application/libraries/StundenplanLib.php b/application/libraries/StundenplanLib.php index 7ed64da2c..b65922633 100644 --- a/application/libraries/StundenplanLib.php +++ b/application/libraries/StundenplanLib.php @@ -181,6 +181,21 @@ class StundenplanLib return success($stundenplan_data); } + public function getEventsByLE($lehreinheit_id, $start, $end, $stundenplan) + { + $this->_ci =& get_instance(); + + $this->_ci->load->model('ressource/Stundenplan_model', 'StundenplanModel'); + return $this->_ci->StundenplanModel->getStundenplanLE($lehreinheit_id, $start, $end, $stundenplan); + } + + public function getEventsByLV($lehrveranstaltung_id, $start, $end, $stundenplan) + { + $this->_ci =& get_instance(); + + $this->_ci->load->model('ressource/Stundenplan_model', 'StundenplanModel'); + return $this->_ci->StundenplanModel->getStundenplanLV($lehrveranstaltung_id, $start, $end, $stundenplan); + } /** * Get stundenplan for a room * diff --git a/application/models/ressource/Stundenplan_model.php b/application/models/ressource/Stundenplan_model.php index 389be582d..6e20a3bc2 100644 --- a/application/models/ressource/Stundenplan_model.php +++ b/application/models/ressource/Stundenplan_model.php @@ -333,6 +333,64 @@ class Stundenplan_model extends DB_Model ", [$start_date, $end_date, $lv_id]); } + public function getStundenplanLE($lehreinheit, $start_date, $end_date, $stundenplan) + { + $qry = " + WITH lehreinheiten AS ( + SELECT lehreinheit_id FROM lehre.tbl_lehreinheit WHERE lehreinheit_id = ? + ), " . $this->getStundenplanCTE($stundenplan) . " + SELECT * + FROM stundenplanentries + "; + + return $this->execReadOnlyQuery($qry, array($lehreinheit, $start_date, $end_date)); + } + + public function getStundenplanLV($lehrveranstaltung_id, $start_date, $end_date, $stundenplan) + { + $qry = " + WITH lehreinheiten AS ( + SELECT lehreinheit_id FROM lehre.tbl_lehreinheit WHERE lehrveranstaltung_id = ? + ), " . $this->getStundenplanCTE($stundenplan) . " + SELECT * + FROM stundenplanentries + "; + + return $this->execReadOnlyQuery($qry, array($lehrveranstaltung_id, $start_date, $end_date)); + } + + private function getStundenplanCTE($stundenplan) + { + return "entries AS ( + SELECT + datum, min(stunde) as stunde_beginn, max(stunde) as stunde_ende, + array_agg(DISTINCT( + CASE WHEN gruppe_kurzbz is not null THEN gruppe_kurzbz + ELSE (UPPER(stg_typ || stg_kurzbz) || COALESCE(semester,'0') || COALESCE(verband,'') || COALESCE(gruppe,'')) + END)) as gruppen_kuerzel, + array_agg(DISTINCT CONCAT(vorname || ' ' || nachname)) as lektorname, + array_agg(DISTINCT stundenplan.ort_kurzbz) as ort_kurzbz, + array_agg(DISTINCT titel) as titel, + lehrfach_bez, stundenplan.lehreinheit_id, lehrveranstaltung_id + FROM lehre.vw_$stundenplan as stundenplan + JOIN public.tbl_mitarbeiter ON stundenplan.uid = tbl_mitarbeiter.mitarbeiter_uid + JOIN tbl_benutzer ON tbl_mitarbeiter.mitarbeiter_uid = tbl_benutzer.uid + JOIN tbl_person USING(person_id) + JOIN lehreinheiten ON stundenplan.lehreinheit_id = lehreinheiten.lehreinheit_id + WHERE datum >= ? AND datum <= ? + GROUP BY datum, unr, stundenplan.lehreinheit_id, lehrveranstaltung_id, lehrfach_bez, lehrfach_bez + ORDER BY datum, min(stunde), unr, lehreinheit_id + ), + stundenplanentries AS ( + SELECT + entries.*, + stundeb.beginn AS beginn, + stundee.ende AS ende + FROM entries + JOIN lehre.tbl_stunde stundeb ON stundeb.stunde = entries.stunde_beginn + JOIN lehre.tbl_stunde stundee ON stundee.stunde = entries.stunde_ende + )"; + } /** * queries Stundenplan and filters by assigned ma_kurzbz, very similar to get by LVA * diff --git a/public/js/api/factory/studiensemester.js b/public/js/api/factory/studiensemester.js new file mode 100644 index 000000000..7e4bf7515 --- /dev/null +++ b/public/js/api/factory/studiensemester.js @@ -0,0 +1,8 @@ +export default { + getStudiensemester(){ + return { + method: 'get', + url: 'api/frontend/v1/stv/LvTermine/getStudiensemester/' + }; + }, +}; diff --git a/public/js/api/factory/stv/coursedates.js b/public/js/api/factory/stv/coursedates.js index 71ded7285..987e65750 100644 --- a/public/js/api/factory/stv/coursedates.js +++ b/public/js/api/factory/stv/coursedates.js @@ -16,20 +16,18 @@ */ export default { - getCourselist(params) { + getCourselist(student_uid, start_date, end_date, stundenplan) { return { method: 'get', - url: 'api/frontend/v1/stv/LvTermine/getStundenplan/' + params.student_uid + '/' - + params.start_date + '/' - + params.end_date + '/' - + params.group_consecutiveHours + '/' - + params.dbStundenplanTable + url: 'api/frontend/v1/stv/LvTermine/getStundenplan/' + encodeURIComponent(student_uid) + '/' + + encodeURIComponent(start_date) + '/' + + encodeURIComponent(end_date) + '/' + + encodeURIComponent(stundenplan) + '/' + + encodeURIComponent(true) }; }, - getStudiensemester(){ - return { - method: 'get', - url: 'api/frontend/v1/stv/LvTermine/getStudiensemester/' - }; + exportCalendar(student_uid, stundenplan) + { + return FHC_JS_DATA_STORAGE_OBJECT.app_root + 'content/statistik/termine.xls.php?student_uid=' + encodeURIComponent(student_uid) + '&db_stpl_table='+encodeURIComponent(stundenplan); }, } \ No newline at end of file diff --git a/public/js/api/lehrveranstaltung/letermine.js b/public/js/api/lehrveranstaltung/letermine.js new file mode 100644 index 000000000..8cdb51070 --- /dev/null +++ b/public/js/api/lehrveranstaltung/letermine.js @@ -0,0 +1,13 @@ +export default { + getCourselist(le_id, start_date, end_date, stundenplan) + { + return { + method: 'get', + url: '/api/frontend/v1/lvPlan/getLeEvents/' + encodeURIComponent(le_id) + "/" + encodeURIComponent(start_date) + "/" + encodeURIComponent(end_date) + "/" + encodeURIComponent(stundenplan), + }; + }, + exportCalendar(le_id, stundenplan) + { + return FHC_JS_DATA_STORAGE_OBJECT.app_root + 'content/statistik/termine.xls.php?lehreinheit_id=' + encodeURIComponent(le_id) + '&db_stpl_table='+encodeURIComponent(stundenplan); + } +}; diff --git a/public/js/api/lehrveranstaltung/lvtermine.js b/public/js/api/lehrveranstaltung/lvtermine.js new file mode 100644 index 000000000..f199ee4b0 --- /dev/null +++ b/public/js/api/lehrveranstaltung/lvtermine.js @@ -0,0 +1,13 @@ +export default { + getCourselist(lv_id, start_date, end_date, stundenplan) + { + return { + method: 'get', + url: '/api/frontend/v1/lvPlan/getLvEvents/' + encodeURIComponent(lv_id) + "/" + encodeURIComponent(start_date) + "/" + encodeURIComponent(end_date) + "/" + encodeURIComponent(stundenplan), + }; + }, + exportCalendar(lv_id, stundenplan) + { + return FHC_JS_DATA_STORAGE_OBJECT.app_root + 'content/statistik/termine.xls.php?lehrveranstaltung_id=' + encodeURIComponent(lv_id) + '&db_stpl_table='+encodeURIComponent(stundenplan); + } +}; diff --git a/public/js/api/lehrveranstaltung/setup.js b/public/js/api/lehrveranstaltung/setup.js index 78f78b05b..e6b0cd645 100644 --- a/public/js/api/lehrveranstaltung/setup.js +++ b/public/js/api/lehrveranstaltung/setup.js @@ -6,4 +6,11 @@ export default { url: '/api/frontend/v1/lv/setup/getTabs/' }; }, + getTab() + { + return { + method: 'get', + url: '/api/frontend/v1/lv/setup/getTab/' + }; + }, } diff --git a/public/js/components/LVVerwaltung/LVVerwaltung.js b/public/js/components/LVVerwaltung/LVVerwaltung.js index 42c50bdfa..e9c1da205 100644 --- a/public/js/components/LVVerwaltung/LVVerwaltung.js +++ b/public/js/components/LVVerwaltung/LVVerwaltung.js @@ -8,7 +8,6 @@ import LvTabs from "./Setup/Tabs.js"; import ApiDetails from "../../api/lehrveranstaltung/details.js"; import ApiLektor from "../../api/lehrveranstaltung/lektor.js"; -import ApiGruppe from "../../api/lehrveranstaltung/gruppe.js"; import ApiStudiengangTree from "../../api/lehrveranstaltung/studiengangtree.js"; import ApiSearchbar from "../../api/factory/searchbar.js"; diff --git a/public/js/components/LVVerwaltung/Setup/Table.js b/public/js/components/LVVerwaltung/Setup/Table.js index 830cfc9ea..e0153a612 100644 --- a/public/js/components/LVVerwaltung/Setup/Table.js +++ b/public/js/components/LVVerwaltung/Setup/Table.js @@ -367,14 +367,13 @@ export default { if (data[0]?.lehreinheit_id !== undefined && this.selectedColumnValues.length === 1) { - this.$emit('update:selected', [data[0]]); this.lv_info = false } else if (data[0]?.lehrveranstaltung_id) { - this.$emit('update:selected', {}); this.getLVInfos(data[0]); } + this.$emit('update:selected', [data[0]]); }, getLVInfos(data) { diff --git a/public/js/components/LVVerwaltung/Setup/Tabs.js b/public/js/components/LVVerwaltung/Setup/Tabs.js index 62c5bbc31..1a2c87f9d 100644 --- a/public/js/components/LVVerwaltung/Setup/Tabs.js +++ b/public/js/components/LVVerwaltung/Setup/Tabs.js @@ -9,6 +9,7 @@ export default { data() { return { configLVTabs: {}, + configLVTab: {}, }; }, props: { @@ -37,21 +38,34 @@ export default { }) .catch(this.$fhcAlert.handleSystemError); + this.$api.call(Setup.getTab()) + .then(result => { + this.configLVTab = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); }, template: `
Bitte eine Lehreinheit auswählen!
-
+
+
Loading... diff --git a/public/js/components/LVVerwaltung/Tabs/LVTermine.js b/public/js/components/LVVerwaltung/Tabs/LVTermine.js new file mode 100644 index 000000000..b3ce8d2f6 --- /dev/null +++ b/public/js/components/LVVerwaltung/Tabs/LVTermine.js @@ -0,0 +1,21 @@ +import TableLvList from "../../Stv/Studentenverwaltung/Details/Lehrveranstaltungstermine/ListLehrveranstaltungstermine.js"; +import ApiLVTermine from "../../../api/lehrveranstaltung/lvtermine.js"; + +export default { + name: "TabCourseList", + components: { + TableLvList + }, + props: { + modelValue: Object, + }, + data() { + return { + endpoint: ApiLVTermine + }; + }, + template: ` +
+ +
` +}; \ No newline at end of file diff --git a/public/js/components/LVVerwaltung/Tabs/Termine.js b/public/js/components/LVVerwaltung/Tabs/Termine.js new file mode 100644 index 000000000..b262eabb6 --- /dev/null +++ b/public/js/components/LVVerwaltung/Tabs/Termine.js @@ -0,0 +1,21 @@ +import TableLvList from "../../Stv/Studentenverwaltung/Details/Lehrveranstaltungstermine/ListLehrveranstaltungstermine.js"; +import ApiLETermine from "../../../api/lehrveranstaltung/letermine.js"; + +export default { + name: "TabCourseList", + components: { + TableLvList + }, + props: { + modelValue: Object, + }, + data() { + return { + endpoint: ApiLETermine + }; + }, + template: ` +
+ +
` +}; \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Lehrveranstaltungstermine.js b/public/js/components/Stv/Studentenverwaltung/Details/Lehrveranstaltungstermine.js index 6845613ab..a41ce90bc 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Lehrveranstaltungstermine.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Lehrveranstaltungstermine.js @@ -1,4 +1,6 @@ import TableLvList from "./Lehrveranstaltungstermine/ListLehrveranstaltungstermine.js"; +import ApiStvCoursedates from "../../../../api/factory/stv/coursedates.js"; + export default { name: "TabCourseList", @@ -8,11 +10,13 @@ export default { props: { modelValue: Object, }, - data(){ - return {} + data() { + return { + endpoint: ApiStvCoursedates + }; }, template: `
- +
` }; \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Lehrveranstaltungstermine/ListLehrveranstaltungstermine.js b/public/js/components/Stv/Studentenverwaltung/Details/Lehrveranstaltungstermine/ListLehrveranstaltungstermine.js index 20cb95fbd..bc3bf4bc7 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Lehrveranstaltungstermine/ListLehrveranstaltungstermine.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Lehrveranstaltungstermine/ListLehrveranstaltungstermine.js @@ -2,7 +2,7 @@ import {CoreFilterCmpt} from "../../../../filter/Filter.js"; import FormInput from "../../../../Form/Input.js"; import FormForm from '../../../../Form/Form.js'; -import ApiStvCoursedates from "../../../../../api/factory/stv/coursedates.js"; +import ApiStudiensemester from "../../../../../api/factory/studiensemester.js"; export default { name: "TblCourseList", @@ -12,17 +12,6 @@ export default { FormForm }, computed: { - downloadLink: function(){ - if(!this.dataSem.start || !this.dataSem.ende || !this.student.uid) return; - let start = new Date(this.dataSem.start); - start = Math.floor(start.getTime()/1000); - let ende = new Date(this.dataSem.ende); - ende = Math.floor(ende.getTime() / 1000); - - let link = - FHC_JS_DATA_STORAGE_OBJECT.app_root + "cis/private/lvplan/stpl_kalender.php?type=student&pers_uid=" + this.student.uid + "&begin=" + start + "&ende= " +ende + "&format=excel"; - return link; - }, dbStundenplanTable: function (){ return this.showStundenplanDev ? 'stundenplandev' : 'stundenplan'; } @@ -33,7 +22,14 @@ export default { }, }, props: { - student: Object + id: { + type: [Number, String], + required: true + }, + endpoint: { + type: Object, + required: true + }, }, data(){ return { @@ -48,14 +44,7 @@ export default { initTabulatorOptions(){ this.tabulatorOptions = { ajaxURL: 'dummy', - ajaxRequestFunc: () => this.$api.call( - ApiStvCoursedates.getCourselist({ - student_uid: this.student.uid, - start_date: this.dataSem.start, - end_date: this.dataSem.ende, - group_consecutiveHours: true, - dbStundenplanTable: this.dbStundenplanTable}) - ), + ajaxRequestFunc: () => this.$api.call(this.endpoint.getCourselist(this.id, this.dataSem.start, this.dataSem.ende, this.dbStundenplanTable)), ajaxResponse: (url, params, response) => { return response.data; }, @@ -137,7 +126,7 @@ export default { this.dataSem = this.listStudiensemester.find(item => item.studiensemester_kurzbz === studiensemester_kurzbz); }, exportToExcel(){ - window.open(this.downloadLink, '_blank'); + window.open(this.endpoint.exportCalendar(this.id, this.dbStundenplanTable), '_blank'); }, reload() { this.$refs.table.reloadTable(); @@ -151,10 +140,13 @@ export default { currentSemester(newVal, oldVal) { this.getDatesOfSemester(newVal); }, + id() { + this.reload(); + } }, created(){ this.$api - .call(ApiStvCoursedates.getStudiensemester()) + .call(ApiStudiensemester.getStudiensemester()) .then(result => { this.listStudiensemester = result.data; this.getDatesOfSemester(this.currentSemester); From d9cdeb977335b503d5af346885cf70d3ed0941e8 Mon Sep 17 00:00:00 2001 From: ma0048 Date: Tue, 2 Dec 2025 08:42:04 +0100 Subject: [PATCH 04/18] scroll verhalten angepasst --- .../js/components/LVVerwaltung/Setup/Table.js | 90 ++++++++++--------- 1 file changed, 47 insertions(+), 43 deletions(-) diff --git a/public/js/components/LVVerwaltung/Setup/Table.js b/public/js/components/LVVerwaltung/Setup/Table.js index 830cfc9ea..db1053875 100644 --- a/public/js/components/LVVerwaltung/Setup/Table.js +++ b/public/js/components/LVVerwaltung/Setup/Table.js @@ -138,7 +138,8 @@ export default { headerFilterFunc: extendedHeaderFilter, }, layout: 'fitDataStretch', - persistenceID: 'lehrveranstaltungen_2025_07_31_v1', + height: '100%', + persistenceID: 'lehrveranstaltungen_2025_12_02_v1', selectableRowsRangeMode: 'click', selectableRows: true, rowContextMenu: (component, e) => { @@ -669,47 +670,50 @@ export default { }, }, template: ` - - - - - - - - - - - - - +
+
+ + + + + +
+ + + + + + + +
` }; \ No newline at end of file From a91fe05395e9b856df41a4fc8dc6be2e05d2fe9a Mon Sep 17 00:00:00 2001 From: ma0048 Date: Tue, 2 Dec 2025 13:23:09 +0100 Subject: [PATCH 05/18] funktionen umbenannt --- .../controllers/api/frontend/v1/lv/Setup.php | 8 ++++---- public/js/api/factory/studiensemester.js | 8 -------- public/js/api/factory/stv/coursedates.js | 6 ++++++ public/js/api/lehrveranstaltung/letermine.js | 8 +++++++- public/js/api/lehrveranstaltung/lvtermine.js | 8 +++++++- public/js/api/lehrveranstaltung/setup.js | 8 ++++---- .../js/components/LVVerwaltung/Setup/Tabs.js | 18 +++++++++--------- .../components/LVVerwaltung/Tabs/LVTermine.js | 4 ++-- .../js/components/LVVerwaltung/Tabs/Termine.js | 4 ++-- .../Details/Lehrveranstaltungstermine.js | 1 - .../ListLehrveranstaltungstermine.js | 4 +--- 11 files changed, 42 insertions(+), 35 deletions(-) delete mode 100644 public/js/api/factory/studiensemester.js diff --git a/application/controllers/api/frontend/v1/lv/Setup.php b/application/controllers/api/frontend/v1/lv/Setup.php index 77ab0edda..fe8450f06 100644 --- a/application/controllers/api/frontend/v1/lv/Setup.php +++ b/application/controllers/api/frontend/v1/lv/Setup.php @@ -27,8 +27,8 @@ class Setup extends FHCAPI_Controller public function __construct() { parent::__construct([ - 'getTabs' => ['admin:r', 'assistenz:r'], - 'getTab' => ['admin:r', 'assistenz:r'], + 'getLETabs' => ['admin:r', 'assistenz:r'], + 'getLVTabs' => ['admin:r', 'assistenz:r'], 'getStudiensemester' => ['admin:r', 'assistenz:r'], 'getSprache' => ['admin:r', 'assistenz:r'], 'getRaumtyp' => ['admin:r', 'assistenz:r'], @@ -44,7 +44,7 @@ class Setup extends FHCAPI_Controller $this->_ci->load->library('VariableLib', ['uid' => $this->_uid]); } - public function getTabs() + public function getLETabs() { $tabs['details'] = array ( 'title' => 'Details', @@ -74,7 +74,7 @@ class Setup extends FHCAPI_Controller $this->terminateWithSuccess($tabs); } - public function getTab() + public function getLVTabs() { $tabs['termine'] = array ( 'title' => 'Termine', diff --git a/public/js/api/factory/studiensemester.js b/public/js/api/factory/studiensemester.js deleted file mode 100644 index 7e4bf7515..000000000 --- a/public/js/api/factory/studiensemester.js +++ /dev/null @@ -1,8 +0,0 @@ -export default { - getStudiensemester(){ - return { - method: 'get', - url: 'api/frontend/v1/stv/LvTermine/getStudiensemester/' - }; - }, -}; diff --git a/public/js/api/factory/stv/coursedates.js b/public/js/api/factory/stv/coursedates.js index 987e65750..dc047f815 100644 --- a/public/js/api/factory/stv/coursedates.js +++ b/public/js/api/factory/stv/coursedates.js @@ -30,4 +30,10 @@ export default { { return FHC_JS_DATA_STORAGE_OBJECT.app_root + 'content/statistik/termine.xls.php?student_uid=' + encodeURIComponent(student_uid) + '&db_stpl_table='+encodeURIComponent(stundenplan); }, + getStudiensemester(){ + return { + method: 'get', + url: 'api/frontend/v1/stv/LvTermine/getStudiensemester/' + }; + }, } \ No newline at end of file diff --git a/public/js/api/lehrveranstaltung/letermine.js b/public/js/api/lehrveranstaltung/letermine.js index 8cdb51070..e5b3093f5 100644 --- a/public/js/api/lehrveranstaltung/letermine.js +++ b/public/js/api/lehrveranstaltung/letermine.js @@ -9,5 +9,11 @@ export default { exportCalendar(le_id, stundenplan) { return FHC_JS_DATA_STORAGE_OBJECT.app_root + 'content/statistik/termine.xls.php?lehreinheit_id=' + encodeURIComponent(le_id) + '&db_stpl_table='+encodeURIComponent(stundenplan); - } + }, + getStudiensemester(){ + return { + method: 'get', + url: '/api/frontend/v1/lv/setup/getStudiensemester/' + }; + }, }; diff --git a/public/js/api/lehrveranstaltung/lvtermine.js b/public/js/api/lehrveranstaltung/lvtermine.js index f199ee4b0..35fdc5ca8 100644 --- a/public/js/api/lehrveranstaltung/lvtermine.js +++ b/public/js/api/lehrveranstaltung/lvtermine.js @@ -9,5 +9,11 @@ export default { exportCalendar(lv_id, stundenplan) { return FHC_JS_DATA_STORAGE_OBJECT.app_root + 'content/statistik/termine.xls.php?lehrveranstaltung_id=' + encodeURIComponent(lv_id) + '&db_stpl_table='+encodeURIComponent(stundenplan); - } + }, + getStudiensemester(){ + return { + method: 'get', + url: '/api/frontend/v1/lv/setup/getStudiensemester/' + }; + }, }; diff --git a/public/js/api/lehrveranstaltung/setup.js b/public/js/api/lehrveranstaltung/setup.js index e6b0cd645..dab1062a4 100644 --- a/public/js/api/lehrveranstaltung/setup.js +++ b/public/js/api/lehrveranstaltung/setup.js @@ -1,16 +1,16 @@ export default { - getTabs() + getLETabs() { return { method: 'get', - url: '/api/frontend/v1/lv/setup/getTabs/' + url: '/api/frontend/v1/lv/setup/getLETabs/' }; }, - getTab() + getLVTabs() { return { method: 'get', - url: '/api/frontend/v1/lv/setup/getTab/' + url: '/api/frontend/v1/lv/setup/getLVTabs/' }; }, } diff --git a/public/js/components/LVVerwaltung/Setup/Tabs.js b/public/js/components/LVVerwaltung/Setup/Tabs.js index 1a2c87f9d..fbb18bedf 100644 --- a/public/js/components/LVVerwaltung/Setup/Tabs.js +++ b/public/js/components/LVVerwaltung/Setup/Tabs.js @@ -8,8 +8,8 @@ export default { }, data() { return { + configLETabs: {}, configLVTabs: {}, - configLVTab: {}, }; }, props: { @@ -20,7 +20,7 @@ export default { if (!this.lv || !this.lv.length) return {}; - return this.configLVTabs; + return this.configLETabs; } }, methods: { @@ -32,15 +32,15 @@ export default { } }, created() { - this.$api.call(Setup.getTabs()) + this.$api.call(Setup.getLETabs()) .then(result => { - this.configLVTabs = result.data; + this.configLETabs = result.data; }) .catch(this.$fhcAlert.handleSystemError); - this.$api.call(Setup.getTab()) + this.$api.call(Setup.getLVTabs()) .then(result => { - this.configLVTab = result.data; + this.configLVTabs = result.data; }) .catch(this.$fhcAlert.handleSystemError); }, @@ -49,12 +49,12 @@ export default {
Bitte eine Lehreinheit auswählen!
-
+
@@ -62,7 +62,7 @@ export default { v-else-if="lv.length === 1" ref="tabs" :modelValue="lv[0]" - :config="configLVTab" + :config="configLVTabs" :default="$route.params.tab" @changed="reload" /> diff --git a/public/js/components/LVVerwaltung/Tabs/LVTermine.js b/public/js/components/LVVerwaltung/Tabs/LVTermine.js index b3ce8d2f6..e064dbae9 100644 --- a/public/js/components/LVVerwaltung/Tabs/LVTermine.js +++ b/public/js/components/LVVerwaltung/Tabs/LVTermine.js @@ -2,7 +2,7 @@ import TableLvList from "../../Stv/Studentenverwaltung/Details/Lehrveranstaltung import ApiLVTermine from "../../../api/lehrveranstaltung/lvtermine.js"; export default { - name: "TabCourseList", + name: "LVTabTermine", components: { TableLvList }, @@ -15,7 +15,7 @@ export default { }; }, template: ` -
+
` }; \ No newline at end of file diff --git a/public/js/components/LVVerwaltung/Tabs/Termine.js b/public/js/components/LVVerwaltung/Tabs/Termine.js index b262eabb6..8b005b6b4 100644 --- a/public/js/components/LVVerwaltung/Tabs/Termine.js +++ b/public/js/components/LVVerwaltung/Tabs/Termine.js @@ -2,7 +2,7 @@ import TableLvList from "../../Stv/Studentenverwaltung/Details/Lehrveranstaltung import ApiLETermine from "../../../api/lehrveranstaltung/letermine.js"; export default { - name: "TabCourseList", + name: "LETabTermine", components: { TableLvList }, @@ -15,7 +15,7 @@ export default { }; }, template: ` -
+
` }; \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Lehrveranstaltungstermine.js b/public/js/components/Stv/Studentenverwaltung/Details/Lehrveranstaltungstermine.js index a41ce90bc..6eb324f27 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Lehrveranstaltungstermine.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Lehrveranstaltungstermine.js @@ -1,7 +1,6 @@ import TableLvList from "./Lehrveranstaltungstermine/ListLehrveranstaltungstermine.js"; import ApiStvCoursedates from "../../../../api/factory/stv/coursedates.js"; - export default { name: "TabCourseList", components: { diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Lehrveranstaltungstermine/ListLehrveranstaltungstermine.js b/public/js/components/Stv/Studentenverwaltung/Details/Lehrveranstaltungstermine/ListLehrveranstaltungstermine.js index bc3bf4bc7..67052460c 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Lehrveranstaltungstermine/ListLehrveranstaltungstermine.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Lehrveranstaltungstermine/ListLehrveranstaltungstermine.js @@ -2,8 +2,6 @@ import {CoreFilterCmpt} from "../../../../filter/Filter.js"; import FormInput from "../../../../Form/Input.js"; import FormForm from '../../../../Form/Form.js'; -import ApiStudiensemester from "../../../../../api/factory/studiensemester.js"; - export default { name: "TblCourseList", components: { @@ -146,7 +144,7 @@ export default { }, created(){ this.$api - .call(ApiStudiensemester.getStudiensemester()) + .call(this.endpoint.getStudiensemester()) .then(result => { this.listStudiensemester = result.data; this.getDatesOfSemester(this.currentSemester); From 8f974e89029bf451e40cb2716f257c3256212b3e Mon Sep 17 00:00:00 2001 From: ma0048 Date: Wed, 3 Dec 2025 08:37:38 +0100 Subject: [PATCH 06/18] sql angepasst --- application/controllers/api/frontend/v1/LvPlan.php | 3 +-- application/models/ressource/Stundenplan_model.php | 8 ++++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/application/controllers/api/frontend/v1/LvPlan.php b/application/controllers/api/frontend/v1/LvPlan.php index 257c04960..571af6876 100644 --- a/application/controllers/api/frontend/v1/LvPlan.php +++ b/application/controllers/api/frontend/v1/LvPlan.php @@ -181,9 +181,8 @@ class LvPlan extends FHCAPI_Controller $this->load->library('StundenplanLib'); $result = $this->stundenplanlib->getEventsByLV($lv_id, $start_date, $end_date, $stundenplan); - $lvplanEvents = $this->getDataOrTerminateWithError($result); - $this->terminateWithSuccess($lvplanEvents); + $this->terminateWithSuccess(hasData($result) ? getData($result) : []); } //TODO: delete this function if we don't use the old calendar export endpoints anymore diff --git a/application/models/ressource/Stundenplan_model.php b/application/models/ressource/Stundenplan_model.php index 6e20a3bc2..c5cfa34d1 100644 --- a/application/models/ressource/Stundenplan_model.php +++ b/application/models/ressource/Stundenplan_model.php @@ -350,13 +350,17 @@ class Stundenplan_model extends DB_Model { $qry = " WITH lehreinheiten AS ( - SELECT lehreinheit_id FROM lehre.tbl_lehreinheit WHERE lehrveranstaltung_id = ? + SELECT lehreinheit_id + FROM lehre.tbl_lehreinheit + JOIN tbl_studiensemester USING(studiensemester_kurzbz) + WHERE lehrveranstaltung_id = ? + AND tbl_studiensemester.start >= ? AND tbl_studiensemester.ende <= ? ), " . $this->getStundenplanCTE($stundenplan) . " SELECT * FROM stundenplanentries "; - return $this->execReadOnlyQuery($qry, array($lehrveranstaltung_id, $start_date, $end_date)); + return $this->execReadOnlyQuery($qry, array($lehrveranstaltung_id, $start_date, $end_date, $start_date, $end_date)); } private function getStundenplanCTE($stundenplan) From cc0a89c924414858e874709c7fb92f768ea69a6a Mon Sep 17 00:00:00 2001 From: ma0048 Date: Thu, 4 Dec 2025 14:18:13 +0100 Subject: [PATCH 07/18] lvverwaltung noten hinzugefuegt noten highlight wenn keine note im zeugnis eingetragen ist --- .../controllers/api/frontend/v1/lv/Noten.php | 84 ++++++++ .../controllers/api/frontend/v1/lv/Setup.php | 13 ++ .../api/frontend/v1/stv/Config.php | 189 +---------------- application/helpers/hlp_document_helper.php | 188 +++++++++++++++++ .../models/education/Lvgesamtnote_model.php | 4 + .../models/education/Zeugnisnote_model.php | 19 +- public/js/api/lehrveranstaltung/noten.js | 25 +++ .../js/components/LVVerwaltung/Tabs/Noten.js | 116 +++++++++++ .../Stv/Studentenverwaltung/Details/Noten.js | 36 +++- .../Details/Noten/Teacher.js | 121 +++++++++-- .../Details/Noten/Zeugnis.js | 197 +++++++++++++++--- public/js/helpers/DocumentHelper.js | 44 ++++ 12 files changed, 793 insertions(+), 243 deletions(-) create mode 100644 application/controllers/api/frontend/v1/lv/Noten.php create mode 100644 application/helpers/hlp_document_helper.php create mode 100644 public/js/api/lehrveranstaltung/noten.js create mode 100644 public/js/components/LVVerwaltung/Tabs/Noten.js create mode 100644 public/js/helpers/DocumentHelper.js diff --git a/application/controllers/api/frontend/v1/lv/Noten.php b/application/controllers/api/frontend/v1/lv/Noten.php new file mode 100644 index 000000000..614ee6609 --- /dev/null +++ b/application/controllers/api/frontend/v1/lv/Noten.php @@ -0,0 +1,84 @@ + 'student/noten:r', + 'getTeacherProposal' => 'student/noten:r', + ]); + + // Load Libraries + $this->load->library('VariableLib', ['uid' => getAuthUID()]); + + // Load Phrases + $this->loadPhrases([ + 'stv', + 'person', + 'lehre' + ]); + } + + public function getCertificate($lv_id, $studiensemester_kurzbz = null) + { + if (is_null($lv_id) || !ctype_digit((string)$lv_id)) + $this->terminateWithError( $this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL); + + $this->load->model('education/lehrveranstaltung_model', 'LehrveranstaltungModel'); + $this->load->model('education/Zeugnisnote_model', 'ZeugnisnoteModel'); + $this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel'); + + $result = $this->LehrveranstaltungModel->loadWhere([ + 'lehrveranstaltung_id' => $lv_id + ]); + + $lehrveranstaltung = $this->getDataOrTerminateWithError($result); + + if (!$lehrveranstaltung) + $this->terminateWithSuccess([]); + + if ($studiensemester_kurzbz !== null && !$this->StudiensemesterModel->isValidStudiensemester($studiensemester_kurzbz)) + { + $this->terminateWithError($studiensemester_kurzbz . ' - ' . $this->p->t('lehre', 'error_noStudiensemester')); + } + + $result = $this->ZeugnisnoteModel->getZeugnisnoten(null, $studiensemester_kurzbz, $lehrveranstaltung[0]->lehrveranstaltung_id); + + $grades = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($grades); + } + + public function getTeacherProposal($lv_id, $studiensemester_kurzbz = null) + { + if (is_null($lv_id) || !ctype_digit((string)$lv_id)) + $this->terminateWithError( $this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL); + + $this->load->model('education/lehrveranstaltung_model', 'LehrveranstaltungModel'); + $this->load->model('education/Lvgesamtnote_model', 'LvgesamtnoteModel'); + $this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel'); + + $result = $this->LehrveranstaltungModel->loadWhere([ + 'lehrveranstaltung_id' => $lv_id + ]); + + $lehrveranstaltung = $this->getDataOrTerminateWithError($result); + + if (!$lehrveranstaltung) + $this->terminateWithSuccess([]); + + if ($studiensemester_kurzbz !== null && !$this->StudiensemesterModel->isValidStudiensemester($studiensemester_kurzbz)) + { + $this->terminateWithError($studiensemester_kurzbz . ' - ' . $this->p->t('lehre', 'error_noStudiensemester')); + } + + $result = $this->LvgesamtnoteModel->getLvGesamtNoten($lv_id, null, $studiensemester_kurzbz); + + $grades = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($grades); + } + +} diff --git a/application/controllers/api/frontend/v1/lv/Setup.php b/application/controllers/api/frontend/v1/lv/Setup.php index fe8450f06..e506a9d1b 100644 --- a/application/controllers/api/frontend/v1/lv/Setup.php +++ b/application/controllers/api/frontend/v1/lv/Setup.php @@ -42,6 +42,7 @@ class Setup extends FHCAPI_Controller $this->_ci->load->model('education/Lehrveranstaltung_model', 'LehrveranstaltungModel'); $this->_ci->load->library('VariableLib', ['uid' => $this->_uid]); + $this->_ci->load->helper('hlp_document'); } public function getLETabs() @@ -81,6 +82,18 @@ class Setup extends FHCAPI_Controller 'component' => APP_ROOT . 'public/js/components/LVVerwaltung/Tabs/LVTermine.js', 'config' => [] ); + $tabs['noten'] = array ( + 'title' => 'Noten', + 'component' => APP_ROOT . 'public/js/components/LVVerwaltung/Tabs/Noten.js', + 'config' => [ + 'usePoints' => defined('CIS_GESAMTNOTE_PUNKTE') && CIS_GESAMTNOTE_PUNKTE, + 'edit' => 'both', // Possible values: both|header|inline + 'delete' => 'inline', // Possible values: both|header|inline + 'documents' => 'inline', // Possible values: both|header|inline + 'documentslist' => gradesDocumentsList(), + 'semesterSelect' => false + ] + ); $this->terminateWithSuccess($tabs); } diff --git a/application/controllers/api/frontend/v1/stv/Config.php b/application/controllers/api/frontend/v1/stv/Config.php index 3bf48bf5b..05e642182 100644 --- a/application/controllers/api/frontend/v1/stv/Config.php +++ b/application/controllers/api/frontend/v1/stv/Config.php @@ -299,6 +299,7 @@ class Config extends FHCAPI_Controller public function student() { + $this->load->helper('hlp_document'); $result = []; $config = $this->config->item('tabs'); @@ -372,9 +373,9 @@ class Config extends FHCAPI_Controller 'config' => [ 'usePoints' => defined('CIS_GESAMTNOTE_PUNKTE') && CIS_GESAMTNOTE_PUNKTE, 'edit' => 'both', // Possible values: both|header|inline - 'delete' => 'both', // Possible values: both|header|inline - 'documents' => 'both', // Possible values: both|header|inline - 'documentslist' => $this->gradesDocumentsList() + 'delete' => 'inline', // Possible values: both|header|inline + 'documents' => 'inline', // Possible values: both|header|inline + 'documentslist' => gradesDocumentsList() ] ]; @@ -613,188 +614,6 @@ class Config extends FHCAPI_Controller ] + $this->kontoColumns(); } - /** - * Helper function to generate the default documentslist config for the - * grades tab. - * - * The resulting array consists of elements which are associative arrays - * that can have the following entries: - * title (required) on the first level this can be HTML code. - * permissioncheck (optional) an URL to an FHCAPI endpoint which returns - * true or false. - * link (optional) an URL that will be called if "action" and - * "children" are not defined. - * action (optional) an associative array that describes an - * POST action that will be called if "children" is - * not defined. - * It can have the following entries: - * - url (required) an URL to an FHCAPI endpoint. - * - post (optional) an associative array with the POST data to - * be sent. - * - response (optional) a string that will be displayed on success. - * children (optional) an array of child elements - * - * All strings that start with { and end with } in the URLs and the - * actions post parameter will be replaced with the corresponding - * attribute of the current dataset (e.G: {uid} will be replaced with the - * uid of the current dataset) - * - * @return array - */ - protected function gradesDocumentsList() - { - $permissioncheck = site_url("api/frontend/v1/documents/permissionAlternativeFormat/{studiengang_kz}"); - - $title_ger = $this->p->t("global", "deutsch"); - $title_eng = $this->p->t("global", "englisch"); - $title_ff = $this->p->t("stv", "document_certificate"); - $title_lv = $this->p->t("stv", "document_coursecertificate"); - - $link_ff = "documents/export/" . - "zertifikat.rdf.php/" . - "Zertifikat" . - "?stg_kz={studiengang_kz_lv}" . - "&uid={uid}" . - "&ss={studiensemester_kurzbz}" . - "&lvid={lehrveranstaltung_id}"; - $link_lv_ger = "documents/export/" . - "lehrveranstaltungszeugnis.rdf.php/" . - "LVZeugnis" . - "?stg_kz={studiengang_kz}" . - "&uid={uid}" . - "&ss={studiensemester_kurzbz}" . - "&lvid={lehrveranstaltung_id}"; - $link_lv_eng = "documents/export/" . - "lehrveranstaltungszeugnis.rdf.php/" . - "LVZeugnisEng" . - "?stg_kz={studiengang_kz}" . - "&uid={uid}" . - "&ss={studiensemester_kurzbz}" . - "&lvid={lehrveranstaltung_id}"; - - $archive_url = "api/frontend/v1/documents/archiveSigned"; - $archive_response = $this->p->t("stv", "document_signed_and_archived"); - $archive_post_ff = [ - "xml" => "zertifikat.rdf.php", - "xsl" => "Zertifikat", - "stg_kz" => "{studiengang_kz_lv}", - "uid" => "{uid}", - "ss" => "{studiensemester_kurzbz}", - "lvid" => "{lehrveranstaltung_id}" - ]; - $archive_post_lv_ger = [ - "xml" => "lehrveranstaltungszeugnis.rdf.php", - "xsl" => "LVZeugnis", - "stg_kz" => "{studiengang_kz}", - "uid" => "{uid}", - "ss" => "{studiensemester_kurzbz}", - "lvid" => "{lehrveranstaltung_id}" - ]; - $archive_post_lv_eng = [ - "xml" => "lehrveranstaltungszeugnis.rdf.php", - "xsl" => "LVZeugnisEng", - "stg_kz" => "{studiengang_kz}", - "uid" => "{uid}", - "ss" => "{studiensemester_kurzbz}", - "lvid" => "{lehrveranstaltung_id}" - ]; - - $list = [ - [ - 'title' => '', - 'children' => [ - [ - 'title' => $title_ff, - 'link' => site_url($link_ff) - ], - [ - 'title' => $title_lv, - 'children' => [ - [ - 'title' => $title_ger, - 'link' => site_url($link_lv_ger), - 'children' => [ - [ - 'title' => 'PDF', - 'permissioncheck' => $permissioncheck, - 'link' => site_url($link_lv_ger) - ], - [ - 'title' => 'DOC', - 'permissioncheck' => $permissioncheck, - 'link' => site_url($link_lv_ger . "&output=doc") - ], - [ - 'title' => 'ODT', - 'permissioncheck' => $permissioncheck, - 'link' => site_url($link_lv_ger . "&output=odt") - ] - ] - ], - [ - 'title' => $title_eng, - 'link' => site_url($link_lv_eng), - 'children' => [ - [ - 'title' => 'PDF', - 'permissioncheck' => $permissioncheck, - 'link' => site_url($link_lv_eng) - ], - [ - 'title' => 'DOC', - 'permissioncheck' => $permissioncheck, - 'link' => site_url($link_lv_eng . "&output=doc") - ], - [ - 'title' => 'ODT', - 'permissioncheck' => $permissioncheck, - 'link' => site_url($link_lv_eng . "&output=odt") - ] - ] - ] - ] - ] - ] - ], - [ - 'title' => '', - 'children' => [ - [ - 'title' => $title_ff, - 'action' => [ - 'url' => site_url($archive_url), - 'post' => $archive_post_ff, - 'response' => $archive_response - ] - ], - [ - 'title' => $title_lv, - 'children' => [ - [ - 'title' => $title_ger, - 'action' => [ - 'url' => site_url($archive_url), - 'post' => $archive_post_lv_ger, - 'response' => $archive_response - ] - ], - [ - 'title' => $title_eng, - 'action' => [ - 'url' => site_url($archive_url), - 'post' => $archive_post_lv_eng, - 'response' => $archive_response - ] - ] - ] - ] - ] - ] - ]; - - return $list; - } - /** * Sort tab list * diff --git a/application/helpers/hlp_document_helper.php b/application/helpers/hlp_document_helper.php new file mode 100644 index 000000000..5b457fe82 --- /dev/null +++ b/application/helpers/hlp_document_helper.php @@ -0,0 +1,188 @@ +load->library('PhrasesLib', array('stv'), 'p'); + + $permissioncheck = site_url("api/frontend/v1/documents/permissionAlternativeFormat/{studiengang_kz}"); + + $title_ger = $ci->p->t("global", "deutsch"); + $title_eng = $ci->p->t("global", "englisch"); + $title_ff = $ci->p->t("stv", "document_certificate"); + $title_lv = $ci->p->t("stv", "document_coursecertificate"); + + $link_ff = "documents/export/" . + "zertifikat.rdf.php/" . + "Zertifikat" . + "?stg_kz={studiengang_kz_lv}" . + "&uid={uid}" . + "&ss={studiensemester_kurzbz}" . + "&lvid={lehrveranstaltung_id}"; + $link_lv_ger = "documents/export/" . + "lehrveranstaltungszeugnis.rdf.php/" . + "LVZeugnis" . + "?stg_kz={studiengang_kz}" . + "&uid={uid}" . + "&ss={studiensemester_kurzbz}" . + "&lvid={lehrveranstaltung_id}"; + $link_lv_eng = "documents/export/" . + "lehrveranstaltungszeugnis.rdf.php/" . + "LVZeugnisEng" . + "?stg_kz={studiengang_kz}" . + "&uid={uid}" . + "&ss={studiensemester_kurzbz}" . + "&lvid={lehrveranstaltung_id}"; + + $archive_url = "api/frontend/v1/documents/archiveSigned"; + $archive_response = $ci->p->t("stv", "document_signed_and_archived"); + $archive_post_ff = [ + "xml" => "zertifikat.rdf.php", + "xsl" => "Zertifikat", + "stg_kz" => "{studiengang_kz_lv}", + "uid" => "{uid}", + "ss" => "{studiensemester_kurzbz}", + "lvid" => "{lehrveranstaltung_id}" + ]; + $archive_post_lv_ger = [ + "xml" => "lehrveranstaltungszeugnis.rdf.php", + "xsl" => "LVZeugnis", + "stg_kz" => "{studiengang_kz}", + "uid" => "{uid}", + "ss" => "{studiensemester_kurzbz}", + "lvid" => "{lehrveranstaltung_id}" + ]; + $archive_post_lv_eng = [ + "xml" => "lehrveranstaltungszeugnis.rdf.php", + "xsl" => "LVZeugnisEng", + "stg_kz" => "{studiengang_kz}", + "uid" => "{uid}", + "ss" => "{studiensemester_kurzbz}", + "lvid" => "{lehrveranstaltung_id}" + ]; + + $list = [ + [ + 'title' => '', + 'children' => [ + [ + 'title' => $title_ff, + 'link' => site_url($link_ff) + ], + [ + 'title' => $title_lv, + 'children' => [ + [ + 'title' => $title_ger, + 'link' => site_url($link_lv_ger), + 'children' => [ + [ + 'title' => 'PDF', + 'permissioncheck' => $permissioncheck, + 'link' => site_url($link_lv_ger) + ], + [ + 'title' => 'DOC', + 'permissioncheck' => $permissioncheck, + 'link' => site_url($link_lv_ger . "&output=doc") + ], + [ + 'title' => 'ODT', + 'permissioncheck' => $permissioncheck, + 'link' => site_url($link_lv_ger . "&output=odt") + ] + ] + ], + [ + 'title' => $title_eng, + 'link' => site_url($link_lv_eng), + 'children' => [ + [ + 'title' => 'PDF', + 'permissioncheck' => $permissioncheck, + 'link' => site_url($link_lv_eng) + ], + [ + 'title' => 'DOC', + 'permissioncheck' => $permissioncheck, + 'link' => site_url($link_lv_eng . "&output=doc") + ], + [ + 'title' => 'ODT', + 'permissioncheck' => $permissioncheck, + 'link' => site_url($link_lv_eng . "&output=odt") + ] + ] + ] + ] + ] + ] + ], + [ + 'title' => '', + 'children' => [ + [ + 'title' => $title_ff, + 'action' => [ + 'url' => site_url($archive_url), + 'post' => $archive_post_ff, + 'response' => $archive_response + ] + ], + [ + 'title' => $title_lv, + 'children' => [ + [ + 'title' => $title_ger, + 'action' => [ + 'url' => site_url($archive_url), + 'post' => $archive_post_lv_ger, + 'response' => $archive_response + ] + ], + [ + 'title' => $title_eng, + 'action' => [ + 'url' => site_url($archive_url), + 'post' => $archive_post_lv_eng, + 'response' => $archive_response + ] + ] + ] + ] + ] + ] + ]; + + return $list; +} diff --git a/application/models/education/Lvgesamtnote_model.php b/application/models/education/Lvgesamtnote_model.php index c30045ff0..0a7638869 100644 --- a/application/models/education/Lvgesamtnote_model.php +++ b/application/models/education/Lvgesamtnote_model.php @@ -29,10 +29,14 @@ class Lvgesamtnote_model extends DB_Model $this->addSelect("lv.bezeichnung AS lehrveranstaltung_bezeichnung"); $this->addSelect("lv.studiengang_kz"); $this->addSelect("UPPER(stg.typ || stg.kurzbz) AS studiengang"); + $this->addSelect("person.vorname"); + $this->addSelect("person.nachname"); $this->addJoin("lehre.tbl_note n", "note"); $this->addJoin("lehre.tbl_lehrveranstaltung lv", "lehrveranstaltung_id"); $this->addJoin("public.tbl_studiengang stg", "studiengang_kz"); + $this->addJoin("public.tbl_benutzer benutzer", "uid = student_uid", "LEFT"); + $this->addJoin("public.tbl_person person", "person_id", "LEFT"); $this->db->where($this->dbTable . ".freigabedatum <", "NOW()", false); diff --git a/application/models/education/Zeugnisnote_model.php b/application/models/education/Zeugnisnote_model.php index f32713dec..694c5d5c0 100644 --- a/application/models/education/Zeugnisnote_model.php +++ b/application/models/education/Zeugnisnote_model.php @@ -148,7 +148,7 @@ class Zeugnisnote_model extends DB_Model * * @return object */ - public function getZeugnisnoten($student_uid, $studiensemester_kurzbz) + public function getZeugnisnoten($student_uid, $studiensemester_kurzbz, $lehrveranstaltung_id = null) { $params = array(); $where=''; @@ -163,6 +163,11 @@ class Zeugnisnote_model extends DB_Model $where.=" AND vw_student_lehrveranstaltung.studiensemester_kurzbz= ?"; $params[] = $studiensemester_kurzbz; } + if($lehrveranstaltung_id != null) + { + $where .= " AND vw_student_lehrveranstaltung.lehrveranstaltung_id = ?"; + $params[] = $lehrveranstaltung_id; + } $where2=''; @@ -176,6 +181,11 @@ class Zeugnisnote_model extends DB_Model $where2 .= " AND studiensemester_kurzbz= ?"; $params[] = $studiensemester_kurzbz; } + if($lehrveranstaltung_id != null) + { + $where2 .=" AND lehrveranstaltung_id = ?"; + $params[] = $lehrveranstaltung_id; + } $qry = "SELECT a.*, @@ -188,7 +198,10 @@ class Zeugnisnote_model extends DB_Model lv.semester AS semester_lv, lv.ects AS ects_lv, lv.zeugnis, - lv.bezeichnung_english AS lehrveranstaltung_bezeichnung_english + lv.bezeichnung_english AS lehrveranstaltung_bezeichnung_english, + s.verband, + person.vorname, + person.nachname FROM ( SELECT vw_student_lehrveranstaltung.lehrveranstaltung_id, uid, vw_student_lehrveranstaltung.studiensemester_kurzbz, note, punkte, uebernahmedatum, benotungsdatum, @@ -231,6 +244,8 @@ class Zeugnisnote_model extends DB_Model ORDER BY sort ) a LEFT JOIN public.tbl_student s ON (a.uid = s.student_uid) + LEFT JOIN public.tbl_benutzer benutzer ON benutzer.uid = s.student_uid + LEFT JOIN public.tbl_person person ON benutzer.person_id = person.person_id LEFT JOIN public.tbl_studiengang stg1 ON (s.studiengang_kz = stg1.studiengang_kz) LEFT JOIN lehre.tbl_lehrveranstaltung lv USING (lehrveranstaltung_id) LEFT JOIN public.tbl_studiengang stg2 ON (lv.studiengang_kz = stg2.studiengang_kz)"; diff --git a/public/js/api/lehrveranstaltung/noten.js b/public/js/api/lehrveranstaltung/noten.js new file mode 100644 index 000000000..fdcbb6f1e --- /dev/null +++ b/public/js/api/lehrveranstaltung/noten.js @@ -0,0 +1,25 @@ +import Grades from '../factory/stv/grades.js'; + +export default { + ...Grades, + getCertificate(lv_id, studiensemester_kurzbz) { + let url = 'api/frontend/v1/lv/noten/getCertificate/' + encodeURIComponent(lv_id); + if (!!studiensemester_kurzbz) { + url = url + '/' + encodeURIComponent(studiensemester_kurzbz); + } + return { + method: 'get', + url: url + }; + }, + getTeacherProposal(lv_id, studiensemester_kurzbz) { + let url = 'api/frontend/v1/lv/noten/getTeacherProposal/' + encodeURIComponent(lv_id); + if (!!studiensemester_kurzbz) { + url = url + '/' + encodeURIComponent(studiensemester_kurzbz); + } + return { + method: 'get', + url: url + }; + }, +}; \ No newline at end of file diff --git a/public/js/components/LVVerwaltung/Tabs/Noten.js b/public/js/components/LVVerwaltung/Tabs/Noten.js new file mode 100644 index 000000000..8b01a017d --- /dev/null +++ b/public/js/components/LVVerwaltung/Tabs/Noten.js @@ -0,0 +1,116 @@ +import NotenZeugnis from "../../Stv/Studentenverwaltung/Details/Noten/Zeugnis.js"; +import NotenTeacher from "../../Stv/Studentenverwaltung/Details/Noten/Teacher.js"; +import NotenRepeater from "../../Stv/Studentenverwaltung/Details/Noten/Repeater.js"; +import ApiLVNoten from "../../../api/lehrveranstaltung/noten.js"; +import { highlightGesamtnote } from "../../../helpers/DocumentHelper.js"; +const LOCAL_STORAGE_ID = 'lv_details_noten_2025_12_02_stdsem_all'; + +export default { + name: "LVTabNoten", + components: { + NotenZeugnis, + NotenTeacher, + NotenRepeater + }, + provide() { + return { + config: this.config + } + }, + props: { + modelValue: Object, + config: Object + }, + data() { + return { + stdsem: '', + endpoint: ApiLVNoten, + tabulatorOptions: { + visibleColumns: { + vorname: true, + nachname: true, + lehrveranstaltung_bezeichnung: false + }, + headerFilter: { + vorname: true, + nachname: true, + lehrveranstaltung_bezeichnung: false + }, + persistenceZeugnisID: 'lv-details-noten-zeugnis-2025120401', + persistenceTeacherID: 'lv-details-noten-teacher-2025120401', + }, + zeugnisLoaded: false, + teacherLoaded: false, + }; + }, + methods: { + reload() { + this.zeugnisLoaded = false; + this.teacherLoaded = false; + + this.$refs.zeugnis.$refs.table.reloadTable(); + this.$refs.teacher.$refs.table.reloadTable(); + }, + saveStdsem(event) { + window.localStorage.setItem(LOCAL_STORAGE_ID, event.target.value); + }, + onZeugnisLoaded() { + this.zeugnisLoaded = true; + this.checkHighlight(); + }, + onTeacherLoaded() { + this.teacherLoaded = true; + this.checkHighlight(); + }, + checkHighlight() + { + if (!this.zeugnisLoaded || !this.teacherLoaded) + return; + + if (!this.$refs.zeugnis || !this.$refs.teacher) + return; + + let zeugnisTable = this.$refs.zeugnis.$refs.table.tabulator; + let teacherTable = this.$refs.teacher.$refs.table.tabulator; + + if (!zeugnisTable || !teacherTable) + return; + + highlightGesamtnote(zeugnisTable, teacherTable); + } + }, + created() { + const savedPath = window.localStorage.getItem(LOCAL_STORAGE_ID); + this.stdsem = savedPath || ''; + }, + template: ` +
+
+ +
+
+
+ +
+
+ +
+
+
` +}; \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Noten.js b/public/js/components/Stv/Studentenverwaltung/Details/Noten.js index 71b8096ec..3217f192c 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Noten.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Noten.js @@ -2,6 +2,9 @@ import NotenZeugnis from './Noten/Zeugnis.js'; import NotenTeacher from './Noten/Teacher.js'; import NotenRepeater from './Noten/Repeater.js'; +import ApiStvGrades from '../../../../api/factory/stv/grades.js'; +import { highlightGesamtnote } from "../../../../helpers/DocumentHelper"; + const LOCAL_STORAGE_ID = 'stv_details_noten_2024-11-25_stdsem_all'; export default { @@ -22,7 +25,10 @@ export default { }, data() { return { - stdsem: '' + stdsem: '', + endpoint: ApiStvGrades, + zeugnisLoaded: false, + teacherLoaded: false, }; }, methods: { @@ -33,6 +39,30 @@ export default { }, saveStdsem(event) { window.localStorage.setItem(LOCAL_STORAGE_ID, event.target.value); + }, + onZeugnisLoaded() { + this.zeugnisLoaded = true; + this.checkHighlight(); + }, + onTeacherLoaded() { + this.teacherLoaded = true; + this.checkHighlight(); + }, + checkHighlight() + { + if (!this.zeugnisLoaded || !this.teacherLoaded) + return; + + if (!this.$refs.zeugnis || !this.$refs.teacher) + return; + + let zeugnisTable = this.$refs.zeugnis.$refs.table.tabulator; + let teacherTable = this.$refs.teacher.$refs.table.tabulator; + + if (!zeugnisTable || !teacherTable) + return; + + highlightGesamtnote(zeugnisTable, teacherTable); } }, created() { @@ -49,10 +79,10 @@ export default {
- +
- +
diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Noten/Teacher.js b/public/js/components/Stv/Studentenverwaltung/Details/Noten/Teacher.js index e566d3a09..f25d291cf 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Noten/Teacher.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Noten/Teacher.js @@ -1,13 +1,12 @@ import {CoreFilterCmpt} from "../../../../filter/Filter.js"; -import ApiStvGrades from '../../../../../api/factory/stv/grades.js'; - export default { components: { CoreFilterCmpt }, emits: [ - "copied" + "copied", + "loaded" ], inject: { currentSemester: { @@ -16,47 +15,127 @@ export default { } }, props: { - student: Object, - allSemester: Boolean + endpoint: { + type: Object, + required: true + }, + id: { + type: [Number, String], + required: true + }, + allSemester: Boolean, + optionalTabulatorOptions: Object, }, data() { return { - tabulatorEvents: [] + tabulatorEvents: [ + { + event: "dataProcessed", + handler: () => this.$emit("loaded"), + }, + ] }; }, computed: { tabulatorOptions() { return { ajaxURL: 'dummy', - ajaxRequestFunc: () => this.$api.call(ApiStvGrades.getTeacherProposal( - this.student.prestudent_id, + ajaxRequestFunc: () => this.$api.call(this.endpoint.getTeacherProposal( + this.id, (!this.allSemester ? this.currentSemester : null) )), ajaxResponse: (url, params, response) => { return response.data || []; }, columns: [ - { field: 'lehrveranstaltung_bezeichnung', title: this.$p.t('lehre/lehrveranstaltung') }, - { field: 'note_bezeichnung', title: this.$p.t('lehre/note') }, - { field: 'mitarbeiter_uid', title: this.$p.t('profil/mitarbeiterIn'), visible: false }, - { field: 'benotungsdatum', title: this.$p.t('stv/grades_gradingdate'), visible: false }, - { field: 'freigabedatum', title: this.$p.t('stv/grades_approvaldate'), visible: false }, - { field: 'studiensemester_kurzbz', title: this.$p.t('lehre/studiensemester'), visible: false }, - { field: 'note', title: this.$p.t('stv/grades_numericgrade'), visible: false }, - { field: 'student_uid', title: this.$p.t('profil/studentIn'), visible: false }, - { field: 'lehrveranstaltung_id', title: this.$p.t('lehre/lehrveranstaltung_id'), visible: false }, - { field: 'punkte', title: this.$p.t('stv/grades_points'), visible: false } + { + field: 'lehrveranstaltung_bezeichnung', + title: this.$p.t('lehre/lehrveranstaltung'), + visible: this.optionalTabulatorOptions?.visibleColumns?.lehrveranstaltung_bezeichnung ?? true, + headerFilter: this.optionalTabulatorOptions?.headerFilter?.lehrveranstaltung_bezeichnung || this.optionalTabulatorOptions?.headerFilter || false + }, + { + field: 'note_bezeichnung', + title: this.$p.t('lehre/note'), + visible: this.optionalTabulatorOptions?.visibleColumns?.note_bezeichnung ?? true, + headerFilter: this.optionalTabulatorOptions?.headerFilter?.note_bezeichnung || this.optionalTabulatorOptions?.headerFilter || false + }, + { + field: 'mitarbeiter_uid', + title: this.$p.t('profil/mitarbeiterIn'), + visible: this.optionalTabulatorOptions?.visibleColumns?.mitarbeiter_uid ?? false, + headerFilter: this.optionalTabulatorOptions?.headerFilter?.mitarbeiter_uid || this.optionalTabulatorOptions?.headerFilter || false + }, + { + field: 'benotungsdatum', + title: this.$p.t('stv/grades_gradingdate'), + visible: this.optionalTabulatorOptions?.visibleColumns?.benotungsdatum ?? false, + headerFilter: this.optionalTabulatorOptions?.headerFilter?.benotungsdatum || this.optionalTabulatorOptions?.headerFilter || false + }, + { + field: 'freigabedatum', + title: this.$p.t('stv/grades_approvaldate'), + visible: this.optionalTabulatorOptions?.visibleColumns?.freigabedatum ?? false, + headerFilter: this.optionalTabulatorOptions?.headerFilter?.freigabedatum || this.optionalTabulatorOptions?.headerFilter || false + }, + { + field: 'studiensemester_kurzbz', + title: this.$p.t('lehre/studiensemester'), + visible: this.optionalTabulatorOptions?.visibleColumns?.studiensemester_kurzbz ?? false, + headerFilter: this.optionalTabulatorOptions?.headerFilter?.studiensemester_kurzbz || this.optionalTabulatorOptions?.headerFilter || false + }, + { + field: 'note', + title: this.$p.t('stv/grades_numericgrade'), + visible: this.optionalTabulatorOptions?.visibleColumns?.note ?? false, + headerFilter: this.optionalTabulatorOptions?.headerFilter?.note || this.optionalTabulatorOptions?.headerFilter || false + }, + { + field: 'student_uid', + title: this.$p.t('profil/studentIn'), + visible: this.optionalTabulatorOptions?.visibleColumns?.student_uid ?? false, + headerFilter: this.optionalTabulatorOptions?.headerFilter?.student_uid || this.optionalTabulatorOptions?.headerFilter || false + }, + { + field: 'lehrveranstaltung_id', + title: this.$p.t('lehre/lehrveranstaltung_id'), + visible: this.optionalTabulatorOptions?.visibleColumns?.lehrveranstaltung_id ?? false, + headerFilter: this.optionalTabulatorOptions?.headerFilter?.lehrveranstaltung_id || this.optionalTabulatorOptions?.headerFilter || false + }, + { + field: 'punkte', + title: this.$p.t('stv/grades_points'), + visible: this.optionalTabulatorOptions?.visibleColumns?.punkte ?? false, + headerFilter: this.optionalTabulatorOptions?.headerFilter?.punkte || this.optionalTabulatorOptions?.headerFilter || false + }, + { + field: 'vorname', + title: this.$p.t('person/vorname'), + visible: this.optionalTabulatorOptions?.visibleColumns?.vorname ?? false, + headerFilter: this.optionalTabulatorOptions?.headerFilter?.vorname || this.optionalTabulatorOptions?.headerFilter || false + }, + { + field: 'nachname', + title: this.$p.t('person/nachname'), + visible: this.optionalTabulatorOptions?.visibleColumns?.nachname ?? false, + headerFilter: this.optionalTabulatorOptions?.headerFilter?.nachname || this.optionalTabulatorOptions?.headerFilter || false + } ], + columnDefaults: { + headerFilter: this.optionalTabulatorOptions?.headerFilter ?? false, + }, layout: 'fitDataStretch', height: '100%', selectable: true, + selectableRows: true, // needed for Tabulator v6 + selectableRowsRangeMode: 'click', // needed for Tabulator v6 selectableRangeMode: 'click', - persistenceID: 'stv-details-noten-teacher' + persistenceID: this.optionalTabulatorOptions?.persistenceTeacherID ?? 'stv-details-noten-teacher-2025120401', }; } }, watch: { - student(n) { + id() { this.$refs.table.reloadTable(); }, allSemester(n) { @@ -67,7 +146,7 @@ export default { copyGrades(selected) { const promises = selected.map( grade => this.$api - .call(ApiStvGrades.copyTeacherProposalToCertificate(grade), { + .call(this.endpoint.copyTeacherProposalToCertificate(grade), { errorHeader: grade.lehrveranstaltung_bezeichnung }) .then(() => { diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Noten/Zeugnis.js b/public/js/components/Stv/Studentenverwaltung/Details/Noten/Zeugnis.js index 4d0996b6b..8e921c668 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Noten/Zeugnis.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Noten/Zeugnis.js @@ -2,8 +2,6 @@ import {CoreFilterCmpt} from "../../../../filter/Filter.js"; import ZeugnisActions from './Zeugnis/Actions.js'; import ZeugnisDocuments from './Zeugnis/Documents.js'; -import ApiStvGrades from '../../../../../api/factory/stv/grades.js'; - export default { name: 'Zeugnis', components: { @@ -11,6 +9,7 @@ export default { ZeugnisActions, ZeugnisDocuments }, + emits: ['loaded'], inject: { config: { from: 'config', @@ -22,7 +21,15 @@ export default { } }, props: { - student: Object, + endpoint: { + type: Object, + required: true + }, + id: { + type: [Number, String], + required: true + }, + optionalTabulatorOptions: Object, allSemester: Boolean }, data() { @@ -35,6 +42,10 @@ export default { return item; }) }, + { + event: "dataProcessed", + handler: () => this.$emit("loaded") + }, { event: "rowSelected", handler: row => row.getElement().style.zIndex = 12 @@ -53,7 +64,7 @@ export default { computed: { tabulatorOptions() { const listPromise = this.$api - .call(ApiStvGrades.list()) + .call(this.endpoint.list()) .then(res => res.data.map(({bezeichnung: label, note: value}) => ({label, value}))); let gradeField = { @@ -86,7 +97,7 @@ export default { note_bezeichnung })) // send to backend - .then(data => this.$api.call(ApiStvGrades.updateCertificate(data))) + .then(data => this.$api.call(this.endpoint.updateCertificate(data))) // get bezeichnung again .then(() => listPromise) .then(list => list.find(el => el.value == note)) @@ -109,7 +120,7 @@ export default { if (filterTerm) { return this.$api .call( - ApiStvGrades.getGradeFromPoints( + this.endpoint.getGradeFromPoints( filterTerm, cell.getData().lehrveranstaltung_id, this.currentSemester @@ -142,27 +153,146 @@ export default { .then(() => node.innerText = this.$p.t('ui/loading')) .catch(this.$fhcAlert.handleSystemError); gradeField.editorParams.placeholderLoading = node; + gradeField.visible = this.optionalTabulatorOptions?.visibleColumns?.note ?? true + gradeField.headerFiler = this.optionalTabulatorOptions?.headerFilter?.note || this.optionalTabulatorOptions?.note || false } const columns = [ - { field: 'zeugnis', title: this.$p.t('stv/grades_zeugnis'), formatter: 'tickCross' }, - { field: 'lehrveranstaltung_bezeichnung', title: this.$p.t('lehre/lehrveranstaltung') }, - gradeField, - { field: 'uebernahmedatum', title: this.$p.t('stv/grades_takeoverdate'), visible: false }, - { field: 'benotungsdatum', title: this.$p.t('stv/grades_gradingdate'), visible: false }, - { field: 'studiensemester_kurzbz', title: this.$p.t('lehre/studiensemester'), visible: false }, - { field: 'note_number', title: this.$p.t('stv/grades_numericgrade'), visible: false, formatter: cell => cell.getData().note, tooltip: (evt, cell) => cell.getData().note }, - { field: 'lehrveranstaltung_id', title: this.$p.t('lehre/lehrveranstaltung_id'), visible: false }, - { field: 'studiengang', title: this.$p.t('lehre/studiengang'), visible: false }, - { field: 'studiengang_kz', title: this.$p.t('lehre/studiengangskennzahlLehre'), visible: false }, - { field: 'studiengang_lv', title: this.$p.t('stv/grades_studiengang_lv'), visible: false }, - { field: 'studiengang_kz_lv', title: this.$p.t('stv/grades_studiengang_kz_lv'), visible: false }, - { field: 'semester_lv', title: this.$p.t('stv/grades_semester_lv'), visible: false }, - { field: 'ects_lv', title: this.$p.t('lehre/ects'), visible: false }, - { field: 'lehrform', title: this.$p.t('lehre/lehrform'), visible: false }, - { field: 'kurzbz', title: this.$p.t('lehre/kurzbz'), visible: false }, - { field: 'punkte', title: this.$p.t('stv/grades_points'), visible: false }, - { field: 'lehrveranstaltung_bezeichnung_english', title: this.$p.t('stv/grades_lehrveranstaltung_bezeichnung_english'), visible: false } + { + field: 'zeugnis', + title: this.$p.t('stv/grades_zeugnis'), + formatter: 'tickCross', + visible: this.optionalTabulatorOptions?.visibleColumns?.zeugnis ?? true, + headerFilter: this.optionalTabulatorOptions?.headerFilter?.zeugnis || this.optionalTabulatorOptions?.zeugnis || false + }, + { + field: 'lehrveranstaltung_bezeichnung', + title: this.$p.t('lehre/lehrveranstaltung'), + visible: this.optionalTabulatorOptions?.visibleColumns?.lehrveranstaltung_bezeichnung ?? true, + headerFilter: this.optionalTabulatorOptions?.headerFilter?.lehrveranstaltung_bezeichnung || this.optionalTabulatorOptions?.lehrveranstaltung_bezeichnung || false + + }, + gradeField, + { + field: 'uebernahmedatum', + title: this.$p.t('stv/grades_takeoverdate'), + visible: this.optionalTabulatorOptions?.visibleColumns?.uebernahmedatum ?? false, + headerFilter: this.optionalTabulatorOptions?.headerFilter?.uebernahmedatum || this.optionalTabulatorOptions?.uebernahmedatum || false + + }, + { + field: 'benotungsdatum', + title: this.$p.t('stv/grades_gradingdate'), + visible: this.optionalTabulatorOptions?.visibleColumns?.benotungsdatum ?? false, + headerFilter: this.optionalTabulatorOptions?.headerFilter?.benotungsdatum || this.optionalTabulatorOptions?.benotungsdatum || false + + }, + { + field: 'studiensemester_kurzbz', + title: this.$p.t('lehre/studiensemester'), + visible: this.optionalTabulatorOptions?.visibleColumns?.studiensemester_kurzbz ?? false, + headerFilter: this.optionalTabulatorOptions?.headerFilter?.studiensemester_kurzbz || this.optionalTabulatorOptions?.studiensemester_kurzbz || false + + }, + { + field: 'note_number', + title: this.$p.t('stv/grades_numericgrade'), + visible: this.optionalTabulatorOptions?.visibleColumns?.note_number ?? false, + formatter: cell => cell.getData().note, tooltip: (evt, cell) => cell.getData().note, + headerFilter: this.optionalTabulatorOptions?.headerFilter?.note_number || this.optionalTabulatorOptions?.note_number || false + + }, + { + field: 'lehrveranstaltung_id', + title: this.$p.t('lehre/lehrveranstaltung_id'), + visible: this.optionalTabulatorOptions?.visibleColumns?.lehrveranstaltung_id ?? false, + headerFilter: this.optionalTabulatorOptions?.headerFilter?.lehrveranstaltung_id || this.optionalTabulatorOptions?.lehrveranstaltung_id || false + + }, + { + field: 'studiengang', + title: this.$p.t('lehre/studiengang'), + visible: this.optionalTabulatorOptions?.visibleColumns?.studiengang ?? false, + headerFilter: this.optionalTabulatorOptions?.headerFilter?.studiengang || this.optionalTabulatorOptions?.studiengang || false + + }, + { + field: 'studiengang_kz', + title: this.$p.t('lehre/studiengangskennzahlLehre'), + visible: this.optionalTabulatorOptions?.visibleColumns?.studiengang_kz ?? false, + headerFilter: this.optionalTabulatorOptions?.headerFilter?.studiengang_kz || this.optionalTabulatorOptions?.studiengang_kz || false + + }, + { + field: 'studiengang_lv', + title: this.$p.t('stv/grades_studiengang_lv'), + visible: this.optionalTabulatorOptions?.visibleColumns?.studiengang_lv ?? false, + headerFilter: this.optionalTabulatorOptions?.headerFilter?.studiengang_lv || this.optionalTabulatorOptions?.studiengang_lv || false + + }, + { + field: 'studiengang_kz_lv', + title: this.$p.t('stv/grades_studiengang_kz_lv'), + visible: this.optionalTabulatorOptions?.visibleColumns?.studiengang_kz_lv ?? false, + headerFilter: this.optionalTabulatorOptions?.headerFilter?.studiengang_kz_lv || this.optionalTabulatorOptions?.studiengang_kz_lv || false + + }, + { + field: 'semester_lv', + title: this.$p.t('stv/grades_semester_lv'), + visible: this.optionalTabulatorOptions?.visibleColumns?.semester_lv ?? false, + headerFilter: this.optionalTabulatorOptions?.headerFilter?.semester_lv || this.optionalTabulatorOptions?.semester_lv || false + + }, + { + field: 'ects_lv', + title: this.$p.t('lehre/ects'), + visible: this.optionalTabulatorOptions?.visibleColumns?.ects_lv ?? false, + headerFilter: this.optionalTabulatorOptions?.headerFilter?.ects_lv || this.optionalTabulatorOptions?.ects_lv || false + + }, + { + field: 'lehrform', + title: this.$p.t('lehre/lehrform'), + visible: this.optionalTabulatorOptions?.visibleColumns?.lehrform ?? false, + headerFilter: this.optionalTabulatorOptions?.headerFilter?.lehrform || this.optionalTabulatorOptions?.lehrform || false + + }, + { + field: 'kurzbz', + title: this.$p.t('lehre/kurzbz'), + visible: this.optionalTabulatorOptions?.visibleColumns?.kurzbz ?? false, + headerFilter: this.optionalTabulatorOptions?.headerFilter?.kurzbz || this.optionalTabulatorOptions?.kurzbz || false + + }, + { + field: 'punkte', + title: this.$p.t('stv/grades_points'), + visible: this.optionalTabulatorOptions?.visibleColumns?.punkte ?? false, + headerFilter: this.optionalTabulatorOptions?.headerFilter?.punkte || this.optionalTabulatorOptions?.punkte || false + + }, + { + field: 'vorname', + title: this.$p.t('person/vorname'), + visible: this.optionalTabulatorOptions?.visibleColumns?.vorname ?? false, + headerFilter: this.optionalTabulatorOptions?.headerFilter?.vorname || this.optionalTabulatorOptions?.vorname || false + + }, + { + field: 'nachname', + title: this.$p.t('person/nachname'), + visible: this.optionalTabulatorOptions?.visibleColumns?.nachname ?? false, + headerFilter: this.optionalTabulatorOptions?.headerFilter?.nachname || this.optionalTabulatorOptions?.nachname || false + + }, + { + field: 'lehrveranstaltung_bezeichnung_english', + title: this.$p.t('stv/grades_lehrveranstaltung_bezeichnung_english'), + visible: this.optionalTabulatorOptions?.visibleColumns?.lehrveranstaltung_bezeichnung_english ?? false, + headerFilter: this.optionalTabulatorOptions?.headerFilter?.lehrveranstaltung_bezeichnung_english || this.optionalTabulatorOptions?.lehrveranstaltung_bezeichnung_english || false + + } ]; const hasDocuments = ['both', 'inline'].includes(this.config.documents); @@ -208,8 +338,8 @@ export default { return { ajaxURL: 'dummy', - ajaxRequestFunc: () => this.$api.call(ApiStvGrades.getCertificate( - this.student.prestudent_id, + ajaxRequestFunc: () => this.$api.call(this.endpoint.getCertificate( + this.id, (!this.allSemester ? this.currentSemester : null) )), ajaxResponse: (url, params, response) => { @@ -218,9 +348,11 @@ export default { columns, height: '100%', layout: 'fitDataStretchFrozen', - selectable: 1, + selectable: true, selectableRangeMode: 'click', - persistenceID: 'stv-details-noten-zeugnis-2025112401', + selectableRowsRangeMode: 'click', //needed for Tabulator v6 + selectableRows: true, //needed for Tabulator v6 + persistenceID: this.optionalTabulatorOptions?.persistenceZeugnisID ?? 'stv-details-noten-zeugnis-2025120302', persistence:{ columns: ["width", "visible", "frozen"] } @@ -228,7 +360,8 @@ export default { } }, watch: { - student(n) { + id() + { this.$refs.table.reloadTable(); }, allSemester(n) { @@ -239,7 +372,7 @@ export default { setGrade(data) { this.$api .call( - ApiStvGrades.updateCertificate(data), + this.endpoint.updateCertificate(data), { errorHeader: data.lehrveranstaltung_bezeichnung } ) .then(this.$refs.table.reloadTable) @@ -252,7 +385,7 @@ export default { .confirmDelete() .then(result => result ? data : Promise.reject({handled:true})) .then(data => this.$api.call( - ApiStvGrades.deleteCertificate(data), + this.endpoint.deleteCertificate(data), { errorHeader: data.lehrveranstaltung_bezeichnung } )) .then(this.$refs.table.reloadTable) @@ -261,7 +394,7 @@ export default { } }, created() { - this.$p.loadCategory(['global', 'stv', 'lehre']) + this.$p.loadCategory(['global', 'stv', 'lehre', 'person']) .then(() => { if (this.$refs.table.tableBuilt) this.$refs.table.tabulator.columnManager.setColumns(this.tabulatorOptions.columns); diff --git a/public/js/helpers/DocumentHelper.js b/public/js/helpers/DocumentHelper.js new file mode 100644 index 000000000..c37c632d5 --- /dev/null +++ b/public/js/helpers/DocumentHelper.js @@ -0,0 +1,44 @@ +export function highlightGesamtnote(zeugnisTable, teacherTable) +{ + let zeugnisData = zeugnisTable.getData(); + + let studentsWithNote = new Set(); + + zeugnisData.forEach(row => { + let student = row.uid; + let lv = row.lehrveranstaltung_id; + let note = row.note; + + if (!student || !lv) + return; + + if (note == null || note === "") + return; + + let key = `${student}_${lv}`; + studentsWithNote.add(key); + }); + + teacherTable.deselectRow(); + + teacherTable.getRows().forEach(row => { + let data = row.getData(); + + let student = data.student_uid; + let lv = data.lehrveranstaltung_id; + let note = data.note; + + if (!student || !lv) + return; + + if (note == null || note === "") + return; + + let key = `${student}_${lv}`; + + if (!studentsWithNote.has(key)) + { + row.select(); + } + }); +} \ No newline at end of file From 60f128b314a73bb2edd6046620ccd48e4d8a8c4d Mon Sep 17 00:00:00 2001 From: ma0048 Date: Tue, 9 Dec 2025 13:00:40 +0100 Subject: [PATCH 08/18] tabs gleichgezogen --- public/js/components/LVVerwaltung/Setup/Tabs.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/public/js/components/LVVerwaltung/Setup/Tabs.js b/public/js/components/LVVerwaltung/Setup/Tabs.js index fbb18bedf..5425b5169 100644 --- a/public/js/components/LVVerwaltung/Setup/Tabs.js +++ b/public/js/components/LVVerwaltung/Setup/Tabs.js @@ -53,17 +53,21 @@ export default {
From ab63bf9d74def7764a66c7942e9410a241892692 Mon Sep 17 00:00:00 2001 From: ma0048 Date: Mon, 12 Jan 2026 09:27:27 +0100 Subject: [PATCH 09/18] gruppen in baum anzeigen und drag and drop von gruppen --- .../controllers/api/frontend/v1/lv/Gruppe.php | 68 +++++++- .../api/frontend/v1/lv/StgTree.php | 146 +++++++++++++++++- .../education/Lehreinheitgruppe_model.php | 47 +++--- public/css/Lvverwaltung.css | 6 + public/js/api/lehrveranstaltung/gruppe.js | 8 + .../LVVerwaltung/Details/Gruppen.js | 66 +++++--- .../components/LVVerwaltung/LVVerwaltung.js | 2 +- .../Stv/Studentenverwaltung/Verband.js | 26 +++- public/js/helpers/DragAndDrop.js | 4 + 9 files changed, 325 insertions(+), 48 deletions(-) diff --git a/application/controllers/api/frontend/v1/lv/Gruppe.php b/application/controllers/api/frontend/v1/lv/Gruppe.php index daebe8a61..f60d3a99a 100644 --- a/application/controllers/api/frontend/v1/lv/Gruppe.php +++ b/application/controllers/api/frontend/v1/lv/Gruppe.php @@ -15,6 +15,7 @@ class Gruppe extends FHCAPI_Controller 'getBenutzerSearch' => ['admin:r', 'assistenz:r'], 'getAllSearch' => ['admin:r', 'assistenz:r'], 'getByLehreinheit' => ['admin:r', 'assistenz:r'], + 'getGruppe' => ['admin:r', 'assistenz:r'], ]); $this->_ci = &get_instance(); @@ -67,7 +68,7 @@ class Gruppe extends FHCAPI_Controller $this->checkPermission($lehreinheit_id); - $result = $this->_ci->LehreinheitgruppeModel->addGroup($lehreinheit_id, $gid, !($lehrverband === 'false')); + $result = $this->_ci->LehreinheitgruppeModel->addGroup($lehreinheit_id, $gid, $lehrverband === true || $lehrverband === 'true'); if (isError($result)) $this->terminateWithError(getError($result)); @@ -75,6 +76,71 @@ class Gruppe extends FHCAPI_Controller $this->terminateWithSuccess($result); } + public function getGruppe() + { + $lehrverband = $this->input->post('lehrverband'); + + $gruppen_result = array(); + + if ($lehrverband === false) + { + $gruppen_result = $this->_ci->GruppeModel->loadWhere(array( + 'studiengang_kz' => $this->input->post('stg_kz'), + 'gruppe_kurzbz' => $this->input->post('gruppe_kurzbz'), + 'aktiv' => true + )); + } + else if ($lehrverband === true) + { + + if (!isEmptyString($this->input->post('verband'))) + { + $this->LehrverbandModel->db->where('verband', $this->input->post('verband')); + } + else + { + $this->LehrverbandModel->db->group_start(); + $this->LehrverbandModel->db->where("trim(verband) = ''"); + $this->LehrverbandModel->db->or_where("verband IS NULL"); + $this->LehrverbandModel->db->group_end(); + } + + if (!isEmptyString($this->input->post('gruppe'))) + { + $this->LehrverbandModel->db->where('gruppe', $this->input->post('gruppe')); + } + else + { + $this->LehrverbandModel->db->group_start(); + $this->LehrverbandModel->db->where("trim(gruppe) = ''"); + $this->LehrverbandModel->db->or_where("gruppe IS NULL"); + $this->LehrverbandModel->db->group_end(); + } + + if (!isEmptyString((string)$this->input->post('semester'))) + { + $this->LehrverbandModel->db->where('semester', $this->input->post('semester')); + } + else + { + + $this->LehrverbandModel->db->group_start(); + $this->LehrverbandModel->db->where("semester = ''"); + $this->LehrverbandModel->db->or_where("semester IS NULL"); + $this->LehrverbandModel->db->group_end(); + } + + $gruppen_result = $this->LehrverbandModel->loadWhere(array('studiengang_kz' => $this->input->post('stg_kz'), 'aktiv' => true)); + } + + if (!hasData($gruppen_result)) + return $this->terminateWithError('No group found'); + + $gruppen_array = getData($gruppen_result)[0]; + + $this->terminateWithSuccess($gruppen_array->gid); + } + public function getByLehreinheit($lehreinheit_id = null) { if (is_null($lehreinheit_id) || !ctype_digit((string)$lehreinheit_id)) diff --git a/application/controllers/api/frontend/v1/lv/StgTree.php b/application/controllers/api/frontend/v1/lv/StgTree.php index 8272da978..f36d4030f 100644 --- a/application/controllers/api/frontend/v1/lv/StgTree.php +++ b/application/controllers/api/frontend/v1/lv/StgTree.php @@ -25,7 +25,25 @@ class StgTree extends FHCAPI_Controller return $this->_outputAuthError([$method => ['admin:r', 'assistenz:r']]); } - return $this->getStudiengang($method); + $count = count($params); + if (!$count) + return $this->getStudiengang($method); + + if ($count == 1) { + if (is_numeric($params[0])) + return $this->getSemester($method, $params[0]); + else + return $this->getStudiengang($method, $params[0]); + } + if ($count == 2) { + if (is_numeric($params[0])) + return $this->getVerband($method, $params[0], $params[1]); + else + return $this->getSemester($method, $params[1], $params[0]); + } + + + show_404(); } @@ -64,16 +82,27 @@ class StgTree extends FHCAPI_Controller $this->terminateWithSuccess($list); } - protected function getStudiengang($studiengang_kz) + protected function getStudiengang($studiengang_kz, $org_form = null) { $link = $studiengang_kz . '/'; + if ($org_form !== null) + $link .= $org_form . '/'; $this->StudiengangModel->addJoin('public.tbl_lehrverband v', 'studiengang_kz'); $this->StudiengangModel->addDistinct(); $this->StudiengangModel->addSelect("CONCAT(" . $this->StudiengangModel->escape($link) . ", semester) AS link", false); - $this->StudiengangModel->addSelect("CONCAT(UPPER(CONCAT(typ, kurzbz)), '-', semester, (SELECT CASE WHEN bezeichnung IS NULL OR bezeichnung='' THEN ''::TEXT ELSE CONCAT(' (', bezeichnung, ')') END FROM public.tbl_lehrverband WHERE studiengang_kz=v.studiengang_kz AND semester=v.semester ORDER BY verband, gruppe LIMIT 1)) AS name", false); - $this->StudiengangModel->addSelect("TRUE AS leaf", false); + $this->StudiengangModel->addSelect("CONCAT( + UPPER(CONCAT(typ, kurzbz)), + '-', + semester, + ( + SELECT CASE WHEN bezeichnung IS NULL OR bezeichnung='' THEN ''::TEXT ELSE CONCAT(' (', bezeichnung, ')') END + FROM public.tbl_lehrverband + WHERE studiengang_kz=v.studiengang_kz AND semester=v.semester + ORDER BY verband, gruppe LIMIT 1 + ) + ) AS name", false); $this->StudiengangModel->addSelect('semester'); $this->StudiengangModel->addSelect($this->StudiengangModel->escape($studiengang_kz) . '::integer AS stg_kz', false); @@ -111,6 +140,115 @@ class StgTree extends FHCAPI_Controller $list = array_merge($list, $result); } } + $this->terminateWithSuccess($list); + } + + protected function getSemester($studiengang_kz, $semester, $org_form = null) + { + $link = $studiengang_kz . '/'; + if ($org_form !== null) + $link .= $org_form . '/'; + $link .= $semester . '/'; + + + $this->load->model('organisation/Gruppe_model', 'GruppeModel'); + + $this->GruppeModel->addDistinct(); + $this->GruppeModel->addSelect("CONCAT(" . $this->GruppeModel->escape($link . 'grp/') . ", gruppe_kurzbz) AS link", false); + $this->GruppeModel->addSelect("CONCAT(gruppe_kurzbz, ' (', bezeichnung, ')') AS name", false); + $this->GruppeModel->addSelect("TRUE AS leaf", false); + + $this->GruppeModel->addSelect('sort'); + $this->GruppeModel->addSelect('gruppe_kurzbz'); + $this->GruppeModel->addSelect($this->GruppeModel->escape($studiengang_kz) . '::integer AS stg_kz', false); + + $this->GruppeModel->addOrder('sort'); + $this->GruppeModel->addOrder('gruppe_kurzbz'); + + $where = [ + 'studiengang_kz' => $studiengang_kz, + 'semester' => $semester, + 'lehre' => true, + 'sichtbar' => true, + 'aktiv' => true, + 'direktinskription' => false + ]; + + if ($org_form !== null) + $where['orgform_kurzbz'] = $org_form; + + $result = $this->GruppeModel->loadWhere($where); + + $list = $this->getDataOrTerminateWithError($result); + + $this->StudiengangModel->addJoin('public.tbl_lehrverband v', 'studiengang_kz'); + + $this->StudiengangModel->addSelect("CONCAT(" . $this->StudiengangModel->escape($link) . ", verband) AS link", false); + $this->StudiengangModel->addSelect("CONCAT(UPPER(CONCAT(typ, kurzbz)), '-', semester, verband, (SELECT CASE WHEN bezeichnung IS NULL OR bezeichnung='' THEN ''::TEXT ELSE CONCAT(' (', bezeichnung, ')') END FROM public.tbl_lehrverband WHERE studiengang_kz=v.studiengang_kz AND semester=v.semester AND verband=v.verband ORDER BY gruppe LIMIT 1)) AS name", false); + $this->StudiengangModel->addSelect("CASE WHEN MAX(gruppe)='' OR MAX(gruppe)=' ' THEN TRUE ELSE FALSE END AS leaf"); + + $this->StudiengangModel->addSelect($this->StudiengangModel->escape($semester) . ' AS semester'); + $this->StudiengangModel->addSelect('verband'); + $this->StudiengangModel->addSelect($this->StudiengangModel->escape($studiengang_kz) . '::integer AS stg_kz', false); + + $this->StudiengangModel->addOrder('verband'); + + $this->StudiengangModel->addGroupBy('link, name, verband'); + + $where = [ + 'v.studiengang_kz' => $studiengang_kz, + 'v.semester' => $semester, + 'v.verband !=' => '', + 'v.aktiv' => true + ]; + + if ($org_form !== null && $semester) // NOTE(chris): on semester 0 show all? + $where['v.orgform_kurzbz'] = $org_form; + + $result = $this->StudiengangModel->loadWhere($where); + $result = $this->getDataOrTerminateWithError($result); + + $list = array_merge($list, $result); + + $this->terminateWithSuccess($list); + } + + protected function getVerband($studiengang_kz, $semester, $verband, $org_form = null) + { + $link = $studiengang_kz . '/'; + if ($org_form !== null) + $link .= $org_form . '/'; + $link .= $semester . '/'. $verband . '/'; + + + $this->StudiengangModel->addJoin('public.tbl_lehrverband v', 'studiengang_kz'); + + $this->StudiengangModel->addDistinct(); + $this->StudiengangModel->addSelect("CONCAT(" . $this->StudiengangModel->escape($link) . ", gruppe) AS link", false); + $this->StudiengangModel->addSelect("CONCAT(UPPER(CONCAT(typ, kurzbz)), '-', semester, verband, gruppe, (SELECT CASE WHEN bezeichnung IS NULL OR bezeichnung='' THEN ''::TEXT ELSE CONCAT(' (', bezeichnung, ')') END FROM public.tbl_lehrverband WHERE studiengang_kz=v.studiengang_kz AND semester=v.semester AND verband=v.verband AND gruppe=v.gruppe ORDER BY gruppe LIMIT 1)) AS name", false); + $this->StudiengangModel->addSelect("TRUE AS leaf", false); + + $this->StudiengangModel->addSelect('v.semester'); + $this->StudiengangModel->addSelect('v.verband'); + $this->StudiengangModel->addSelect('gruppe'); + $this->StudiengangModel->addSelect($this->StudiengangModel->escape($studiengang_kz) . '::integer AS stg_kz', false); + + $this->StudiengangModel->addOrder('gruppe'); + + $where = [ + 'v.studiengang_kz' => $studiengang_kz, + 'v.semester' => $semester, + 'v.verband' => $verband, + 'v.gruppe !=' => '', + 'v.aktiv' => true + ]; + + if ($org_form !== null && $semester) + $where['v.orgform_kurzbz'] = $org_form; + + $result = $this->StudiengangModel->loadWhere($where); + + $list = $this->getDataOrTerminateWithError($result); $this->terminateWithSuccess($list); } diff --git a/application/models/education/Lehreinheitgruppe_model.php b/application/models/education/Lehreinheitgruppe_model.php index dee8bbfe1..139d639cb 100644 --- a/application/models/education/Lehreinheitgruppe_model.php +++ b/application/models/education/Lehreinheitgruppe_model.php @@ -341,7 +341,7 @@ class Lehreinheitgruppe_model extends DB_Model $this->db->where('lehreinheit_id', $lehreinheit_id); $this->db->where('studiengang_kz', $gruppen_array->studiengang_kz); - if (!isEmptyString($gruppen_array->semester)) + if (!isEmptyString((string)$gruppen_array->semester)) { $this->db->where('semester', $gruppen_array->semester); } @@ -444,30 +444,37 @@ class Lehreinheitgruppe_model extends DB_Model ) ELSE tbl_gruppe.beschreibung END AS beschreibung"); - $this->addSelect("CASE - WHEN tbl_lehreinheitgruppe.gruppe_kurzbz IS NULL THEN - ( - SELECT EXISTS ( - SELECT 1 - FROM lehre.tbl_stundenplandev - WHERE lehreinheit_id = tbl_lehreinheitgruppe.lehreinheit_id - AND studiengang_kz = tbl_lehreinheitgruppe.studiengang_kz - AND semester = tbl_lehreinheitgruppe.semester - AND TRIM(COALESCE(verband, '')) = TRIM(tbl_lehreinheitgruppe.verband) - AND TRIM(COALESCE(gruppe, '')) = TRIM(tbl_lehreinheitgruppe.gruppe) - AND (gruppe_kurzbz IS NULL OR gruppe_kurzbz = '') - ) - ) - ELSE + $this->addSelect(" + CASE + WHEN trim(COALESCE(tbl_lehreinheitgruppe.gruppe_kurzbz, '')) = '' THEN ( SELECT EXISTS ( SELECT 1 - FROM lehre.tbl_stundenplandev - WHERE lehreinheit_id = tbl_lehreinheitgruppe.lehreinheit_id - AND gruppe_kurzbz = tbl_lehreinheitgruppe.gruppe_kurzbz + FROM lehre.tbl_stundenplandev sp + WHERE sp.lehreinheit_id = tbl_lehreinheitgruppe.lehreinheit_id + AND sp.studiengang_kz = tbl_lehreinheitgruppe.studiengang_kz + AND sp.semester = tbl_lehreinheitgruppe.semester + AND trim(COALESCE(sp.verband, '')) = trim(COALESCE(tbl_lehreinheitgruppe.verband, '')) + AND trim(COALESCE(sp.gruppe, '')) = trim(COALESCE(tbl_lehreinheitgruppe.gruppe, '')) + AND trim(COALESCE(sp.gruppe_kurzbz, '')) = '' ) ) - END AS verplant"); + ELSE + ( + SELECT EXISTS ( + SELECT 1 + FROM lehre.tbl_stundenplandev sp + WHERE sp.lehreinheit_id = tbl_lehreinheitgruppe.lehreinheit_id + AND sp.studiengang_kz = tbl_lehreinheitgruppe.studiengang_kz + AND sp.semester = tbl_lehreinheitgruppe.semester + AND trim(COALESCE(sp.verband, '')) = trim(COALESCE(tbl_lehreinheitgruppe.verband, '')) + AND trim(COALESCE(sp.gruppe, '')) = trim(COALESCE(tbl_lehreinheitgruppe.gruppe, '')) + AND trim(COALESCE(sp.gruppe_kurzbz, '')) = trim(COALESCE(tbl_lehreinheitgruppe.gruppe_kurzbz, '')) + ) + ) + END AS verplant + "); + $this->addJoin('tbl_studiengang', 'studiengang_kz', 'LEFT'); $this->addJoin('public.tbl_gruppe', 'gruppe_kurzbz', 'LEFT'); diff --git a/public/css/Lvverwaltung.css b/public/css/Lvverwaltung.css index 6e0f4c760..b8152d39a 100644 --- a/public/css/Lvverwaltung.css +++ b/public/css/Lvverwaltung.css @@ -38,3 +38,9 @@ textarea[name="anmerkung"] { { border-color: black; } + +.node-verband { + user-select: none; + -webkit-user-select: none; + -moz-user-select: none; +} diff --git a/public/js/api/lehrveranstaltung/gruppe.js b/public/js/api/lehrveranstaltung/gruppe.js index 44340bec7..23db4c069 100644 --- a/public/js/api/lehrveranstaltung/gruppe.js +++ b/public/js/api/lehrveranstaltung/gruppe.js @@ -18,6 +18,14 @@ export default { params: newData }; }, + getGruppe(gruppe) + { + return { + method: 'post', + url: '/api/frontend/v1/lv/gruppe/getGruppe/', + params: gruppe + }; + }, getByLehreinheit(lehreinheit_id) { return { diff --git a/public/js/components/LVVerwaltung/Details/Gruppen.js b/public/js/components/LVVerwaltung/Details/Gruppen.js index 024bf6468..5244136cc 100644 --- a/public/js/components/LVVerwaltung/Details/Gruppen.js +++ b/public/js/components/LVVerwaltung/Details/Gruppen.js @@ -2,6 +2,7 @@ import {CoreFilterCmpt} from "../../filter/Filter.js"; import FormForm from '../../Form/Form.js'; import FormInput from '../../Form/Input.js'; import ApiGruppe from "../../../api/lehrveranstaltung/gruppe.js"; +import drop from '../../../directives/drop.js'; export default{ name: "LVGruppen", components: { @@ -9,6 +10,9 @@ export default{ FormForm, FormInput }, + directives: { + drop + }, props: { lehreinheit_id: Number }, @@ -187,28 +191,48 @@ export default{ this.reload(); }) }, + onDropVerband(node, gruppe) { + this.$api.call(ApiGruppe.getGruppe(gruppe)) + .then(result => result.data) + .then(result => { + + let newData = { + 'gid': result, + 'lehreinheit_id': this.lehreinheit_id, + 'lehrverband': gruppe.lehrverband, + } + this.$api.call(ApiGruppe.add(newData)) + .then(result => { + this.reload() + }) + }); + + }, + }, template: ` - - - - +
+ + + + +
` }; \ No newline at end of file diff --git a/public/js/components/LVVerwaltung/LVVerwaltung.js b/public/js/components/LVVerwaltung/LVVerwaltung.js index 42c50bdfa..9a68c3781 100644 --- a/public/js/components/LVVerwaltung/LVVerwaltung.js +++ b/public/js/components/LVVerwaltung/LVVerwaltung.js @@ -285,7 +285,7 @@ export default {
- + diff --git a/public/js/components/Stv/Studentenverwaltung/Verband.js b/public/js/components/Stv/Studentenverwaltung/Verband.js index 1ff9d2ed9..4490901e9 100644 --- a/public/js/components/Stv/Studentenverwaltung/Verband.js +++ b/public/js/components/Stv/Studentenverwaltung/Verband.js @@ -1,5 +1,6 @@ import drop from '../../../directives/drop.js'; import dragClick from '../../../directives/dragClick.js'; +import draggable from '../../../directives/draggable.js'; import ApiStvGroups from '../../../api/factory/stv/group.js'; import ApiStvDetails from '../../../api/factory/stv/details.js'; @@ -11,7 +12,8 @@ export default { }, directives: { drop, - dragClick + dragClick, + draggable }, inject: { $reloadList: { @@ -40,6 +42,10 @@ export default { preselectedKey: { type: String, default: null + }, + dragEnabled: { + type: Boolean, + default: false } }, data() { @@ -79,6 +85,22 @@ export default { } }, methods: { + dragVerband(node) { + const gruppe = node?.data || {}; + + const id = gruppe.gruppe_kurzbz ?? gruppe.link ?? node?.key ?? null; + + return [{ + type: 'verband', + id: id, + gruppe_kurzbz: gruppe.gruppe_kurzbz ?? null, + semester: gruppe.semester ?? null, + verband: gruppe.verband ?? null, + gruppe: gruppe.gruppe ?? null, + lehrverband: gruppe.gruppe_kurzbz == null, + stg_kz: gruppe.stg_kz ?? null, + }]; + }, findNodeByKey(key, arr) { if (!arr) arr = this.nodes; @@ -359,7 +381,9 @@ export default { :data-tree-item-key="node.key" :title="node.data.studiengang_kz" v-drag-click="() => toggleTreeNode(node)" + class="node-verband" v-drop:link-strict.student-collection="(evt, students) => dropStudents(node, students)" + v-draggable:link-strict="dragEnabled && dragVerband(node)" > {{ node.data.name }} diff --git a/public/js/helpers/DragAndDrop.js b/public/js/helpers/DragAndDrop.js index f98697eb2..3eeff0ee2 100644 --- a/public/js/helpers/DragAndDrop.js +++ b/public/js/helpers/DragAndDrop.js @@ -30,6 +30,10 @@ const TYPE_DEFINITION = { prestudent: { id: "prestudent_id", dragIcon: "fa-solid fa-user-graduate text-muted" + }, + verband: { + id: "gruppe_id", + dragIcon: "fa-solid fa-user-group text-muted" } // TODO: IMPLEMENT OTHER TYPES }; From e26387a75a6075ee1c9ab2bc87bb96af52338907 Mon Sep 17 00:00:00 2001 From: ma0048 Date: Mon, 19 Jan 2026 15:08:59 +0100 Subject: [PATCH 10/18] lektoren tausch auch bei verplanten lektoren hinzugefuegt --- .../controllers/api/frontend/v1/lv/Config.php | 86 +++++++ .../controllers/api/frontend/v1/lv/Lektor.php | 3 + application/libraries/LektorLib.php | 240 ++++++++++++------ .../models/ressource/Reservierung_model.php | 11 + .../models/ressource/Stundenplandev_model.php | 11 + .../models/ressource/Zeitsperre_model.php | 36 +++ application/views/LVVerwaltung.php | 2 + public/js/api/lehrveranstaltung/config.js | 15 ++ .../components/LVVerwaltung/LVVerwaltung.js | 57 ++++- .../components/LVVerwaltung/Lektor/Daten.js | 5 +- 10 files changed, 382 insertions(+), 84 deletions(-) create mode 100644 application/controllers/api/frontend/v1/lv/Config.php create mode 100644 public/js/api/lehrveranstaltung/config.js diff --git a/application/controllers/api/frontend/v1/lv/Config.php b/application/controllers/api/frontend/v1/lv/Config.php new file mode 100644 index 000000000..4f39c6b8b --- /dev/null +++ b/application/controllers/api/frontend/v1/lv/Config.php @@ -0,0 +1,86 @@ + ['admin:r', 'assistenz:r'], + 'set' => ['admin:r', 'assistenz:r'], + ]); + + $this->_ci = &get_instance(); + $this->_setAuthUID(); + + $this->loadPhrases([ + 'lehre' + ]); + + $this->_ci->load->library('VariableLib', ['uid' => $this->_uid]); + $this->_ci->load->library('PermissionLib'); + + } + + + public function get() + { + if (!($this->permissionlib->isBerechtigt('basis/tempus')) && !($this->permissionlib->isBerechtigt('lv-plan'))) + $this->terminateWithSuccess([]); + + $ignore_kollision = $this->_ci->variablelib->getVar('ignore_kollision'); + $ignore_zeitsperre = $this->_ci->variablelib->getVar('ignore_zeitsperre'); + $ignore_reservierung = $this->_ci->variablelib->getVar('ignore_reservierung'); + + $config['ignore_kollision'] = [ + "type" => "checkbox", + "label" => 'ignore_kollision', + "value" => $ignore_kollision, + ]; + + $config['ignore_zeitsperre'] = [ + "type" => "checkbox", + "label" => 'ignore_zeitsperre', + "value" => $ignore_zeitsperre, + ]; + + $config['ignore_reservierung'] = [ + "type" => "checkbox", + "label" => 'ignore_reservierung', + "value" => $ignore_reservierung, + ]; + + $this->terminateWithSuccess($config); + } + public function set() + { + if (!($this->permissionlib->isBerechtigt('basis/tempus')) && !($this->permissionlib->isBerechtigt('lv-plan'))) + $this->terminateWithSuccess([]); + + $this->load->model('system/Variable_model', 'VariableModel'); + + foreach (['ignore_kollision','ignore_zeitsperre','ignore_reservierung'] as $variable) + { + if ($this->_ci->input->post($variable) !== null) + { + $this->VariableModel->update(array('uid' => $this->_uid, 'name' => $variable), array('wert' => $this->input->post($variable))); + + } + } + + $this->terminateWithSuccess(); + } + + private function _setAuthUID() + { + $this->_uid = getAuthUID(); + + if (!$this->_uid) + show_error('User authentification failed'); + } +} diff --git a/application/controllers/api/frontend/v1/lv/Lektor.php b/application/controllers/api/frontend/v1/lv/Lektor.php index cce7f6e8b..7db23e75f 100644 --- a/application/controllers/api/frontend/v1/lv/Lektor.php +++ b/application/controllers/api/frontend/v1/lv/Lektor.php @@ -144,6 +144,9 @@ class Lektor extends FHCAPI_Controller if (!$lehreinheit_permission) $this->terminateWithError($this->p->t('ui', 'error_fieldWriteAccess')); + if (!is_null($this->getLektorVertrag($lehreinheit_id, $mitarbeiter_uid)) && (array_key_exists('mitarbeiter_uid', $formData) && $mitarbeiter_uid !== $formData['mitarbeiter_uid'])) + $this->terminateWithError($this->p->t('ui', 'error_fieldWriteAccess')); + $result = $this->_ci->lektorlib->updateLektorFromLehreinheit($lehreinheit_id, $mitarbeiter_uid, $formData); if (isError($result)) $this->terminateWithError(getError($result)); diff --git a/application/libraries/LektorLib.php b/application/libraries/LektorLib.php index bbe630eaf..0e96a1070 100644 --- a/application/libraries/LektorLib.php +++ b/application/libraries/LektorLib.php @@ -17,7 +17,12 @@ class LektorLib $this->_ci->load->model('organisation/Organisationseinheit_model', 'OrganisationseinheitModel'); $this->_ci->load->model('ressource/mitarbeiter_model', 'MitarbeiterModel'); $this->_ci->load->model('person/Benutzer_model', 'BenutzerModel'); + $this->_ci->load->model('ressource/Zeitsperre_model', 'ZeitsperreModel'); + $this->_ci->load->model('ressource/Reservierung_model', 'ReservierungModel'); + $this->_ci->load->model('ressource/stundenplandev_model', 'StundenplandevModel'); + $this->_ci->load->library('PhrasesLib', array('lehre')); + $this->_ci->load->library('VariableLib', ['uid' => getAuthUID()]); } public function addLektorToLehreinheit($lehreinheit_id, $mitarbeiter_uid) @@ -78,10 +83,13 @@ class LektorLib public function updateLektorFromLehreinheit($lehreinheit_id, $mitarbeiter_uid, $new_data) { + $old_uid = $mitarbeiter_uid; + $new_uid = isset($new_data['mitarbeiter_uid']) ? $new_data['mitarbeiter_uid'] : $mitarbeiter_uid; + $this->_ci->LehreinheitmitarbeiterModel->addSelect('lehre.tbl_lehreinheitmitarbeiter.*, lehre.tbl_lehreinheit.studiensemester_kurzbz, tbl_lehrveranstaltung.studiengang_kz'); $this->_ci->LehreinheitmitarbeiterModel->addJoin('lehre.tbl_lehreinheit', 'lehreinheit_id'); $this->_ci->LehreinheitmitarbeiterModel->addJoin('lehre.tbl_lehrveranstaltung', 'lehrveranstaltung_id'); - $lehreinheit_result = $this->_ci->LehreinheitmitarbeiterModel->loadWhere(array('lehreinheit_id' => $lehreinheit_id, 'mitarbeiter_uid' => $mitarbeiter_uid)); + $lehreinheit_result = $this->_ci->LehreinheitmitarbeiterModel->loadWhere(array('lehreinheit_id' => $lehreinheit_id, 'mitarbeiter_uid' => $old_uid)); if (isError($lehreinheit_result)) return $lehreinheit_result; @@ -89,27 +97,47 @@ class LektorLib $lehreinheit = getData($lehreinheit_result)[0]; + $semesterstunden_alt = $lehreinheit->semesterstunden; + $semesterstunden_neu = isset($new_data['semesterstunden']) ? $new_data['semesterstunden'] : $semesterstunden_alt; + $bismelden_neu = isset($new_data['bismelden']) ? $new_data['bismelden'] : $lehreinheit->bismelden; + $neue_stunden_eingerechnet = (bool)$bismelden_neu; + $alte_stunden_eingerechnet = (bool)$lehreinheit->bismelden; + $stundenplan_update = false; - //TODO kollision check, wird vorerst nicht implementiert -> nur über das FAS möglich - if (isset($new_data['mitarbeiter_uid']) && $new_data['mitarbeiter_uid'] !== $mitarbeiter_uid) + if ($old_uid !== $new_uid) { - $this->_ci->load->model('ressource/stundenplandev_model', 'StundenplandevModel'); - $this->_ci->StundenplandevModel->addGroupBy('stundenplandev_id'); - $this->_ci->StundenplandevModel->addGroupBy('mitarbeiter_uid'); - $this->_ci->StundenplandevModel->addGroupBy('mitarbeiter_uid'); - $verplant = $this->_ci->StundenplandevModel->loadWhere(array('lehreinheit_id' => $lehreinheit_id, 'mitarbeiter_uid' => $mitarbeiter_uid)); - - if (hasData($verplant)) - return error($this->_ci->phraseslib->t("lehre", "lektorbereitsverplant")); - - $lehreinheit_data = $this->_ci->LehreinheitmitarbeiterModel->loadWhere(array('mitarbeiter_uid' => $new_data['mitarbeiter_uid'], 'lehreinheit_id' => $lehreinheit_id)); + $lehreinheit_data = $this->_ci->LehreinheitmitarbeiterModel->loadWhere(array('mitarbeiter_uid' => $new_uid, 'lehreinheit_id' => $lehreinheit_id)); if (hasData($lehreinheit_data)) return error($this->_ci->phraseslib->t("lehre", "bereitzugeteilt")); + $this->_ci->StundenplandevModel->addGroupBy('stundenplandev_id'); + $this->_ci->StundenplandevModel->addGroupBy('mitarbeiter_uid'); + $verplant = $this->_ci->StundenplandevModel->loadWhere(array('lehreinheit_id' => $lehreinheit_id, 'mitarbeiter_uid' => $old_uid)); + + if (hasData($verplant)) + { + $kollision = $this->hasKollision(getData($verplant), $new_uid); + + $ignore_kollision = $this->_ci->variablelib->getVar('ignore_kollision'); + + if ($kollision === false || $ignore_kollision == 'true') + { + $stundenplan_update = true; + } + else if (is_array($kollision)) + { + return error( "Änderung fehlgeschlagen! Die Änderung des Lektors führt zu ".count($kollision)." Kollision(en) im LV-Plan. Deaktivieren Sie die Kollisionspruefung oder wenden Sie sich an die LV-Planung!\n zB. $kollision[0]"); + } + else + { + return error($kollision); + } + } } + $warning = ''; - if (isset($new_data['semesterstunden'])) + if (($semesterstunden_neu !== '' && $semesterstunden_alt !== '') && (($semesterstunden_neu > $semesterstunden_alt) || $neue_stunden_eingerechnet)) { $studiengang_result = $this->_ci->StudiengangModel->loadWhere(array('studiengang_kz' => $lehreinheit->studiengang_kz)); if (isError($studiengang_result)) return $studiengang_result; @@ -120,7 +148,7 @@ class LektorLib if (isError($studiensemester_result)) return $studiensemester_result; $studiensemester = getData($studiensemester_result)[0]; - $echter_dv_result = $this->_ci->DienstverhaeltnisModel->existsDienstverhaeltnis($mitarbeiter_uid, $studiensemester->start, $studiensemester->ende, 'echterdv'); + $echter_dv_result = $this->_ci->DienstverhaeltnisModel->existsDienstverhaeltnis($new_uid, $studiensemester->start, $studiensemester->ende, 'echterdv'); $echter_dv = false; @@ -129,83 +157,78 @@ class LektorLib $echter_dv = true; } - $neue_stunden_eingerechnet = isset($new_data['bismelden']) ? $new_data['bismelden'] : $lehreinheit->bismelden; - $alte_stunden_eingerechnet = $lehreinheit->bismelden; + $stundengrenze_result = $this->_ci->OrganisationseinheitModel->getStundengrenze($studiengang->oe_kurzbz, $echter_dv); + if (isError($stundengrenze_result)) return $stundengrenze_result; - if (($new_data['semesterstunden'] > $lehreinheit->semesterstunden) || $neue_stunden_eingerechnet) + $stundengrenze = getData($stundengrenze_result)[0]; + + $oe_result = $this->_ci->OrganisationseinheitModel->getChilds($stundengrenze->oe_kurzbz); + $oe_array = hasData($oe_result) ? array_column(getData($oe_result), 'oe_kurzbz') : array(); + + if ($alte_stunden_eingerechnet && $neue_stunden_eingerechnet) + $this->_ci->LehreinheitmitarbeiterModel->addSelect("(SUM(tbl_lehreinheitmitarbeiter.semesterstunden) - ($semesterstunden_alt) + {$this->_ci->LehreinheitmitarbeiterModel->db->escape($semesterstunden_neu)}) as summe"); + else if ($alte_stunden_eingerechnet && !$neue_stunden_eingerechnet) + $this->_ci->LehreinheitmitarbeiterModel->addSelect("(SUM(tbl_lehreinheitmitarbeiter.semesterstunden) - ($semesterstunden_alt)) as summe"); + else if (!$alte_stunden_eingerechnet && $neue_stunden_eingerechnet) + $this->_ci->LehreinheitmitarbeiterModel->addSelect("(SUM(tbl_lehreinheitmitarbeiter.semesterstunden) + ({$this->_ci->LehreinheitmitarbeiterModel->db->escape($semesterstunden_neu)})) as summe"); + else if (!$alte_stunden_eingerechnet && !$neue_stunden_eingerechnet) + $this->_ci->LehreinheitmitarbeiterModel->addSelect("(SUM(tbl_lehreinheitmitarbeiter.semesterstunden)) as summe"); + + $this->_ci->LehreinheitmitarbeiterModel->addJoin('lehre.tbl_lehreinheit', 'lehreinheit_id'); + $this->_ci->LehreinheitmitarbeiterModel->addJoin('lehre.tbl_lehrveranstaltung', 'lehrveranstaltung_id'); + $this->_ci->LehreinheitmitarbeiterModel->addJoin('public.tbl_studiengang', 'studiengang_kz'); + + $this->_ci->LehreinheitmitarbeiterModel->db->where('mitarbeiter_uid', $new_uid); + $this->_ci->LehreinheitmitarbeiterModel->db->where('studiensemester_kurzbz', $lehreinheit->studiensemester_kurzbz); + $this->_ci->LehreinheitmitarbeiterModel->db->where('bismelden', true); + $this->_ci->LehreinheitmitarbeiterModel->db->where('lower(mitarbeiter_uid) NOT LIKE', '_dummy%'); + + if (count($oe_array) > 0) { - $stundengrenze_result = $this->_ci->OrganisationseinheitModel->getStundengrenze($studiengang->oe_kurzbz, $echter_dv); - if (isError($stundengrenze_result)) return $stundengrenze_result; - - $stundengrenze = getData($stundengrenze_result)[0]; - - $oe_result = $this->_ci->OrganisationseinheitModel->getChilds($stundengrenze->oe_kurzbz); - $oe_array = hasData($oe_result) ? array_column(getData($oe_result), 'oe_kurzbz') : array(''); - - if ($alte_stunden_eingerechnet && $neue_stunden_eingerechnet) - $this->_ci->LehreinheitmitarbeiterModel->addSelect("(SUM(tbl_lehreinheitmitarbeiter.semesterstunden) - ($lehreinheit->semesterstunden) + {$this->_ci->LehreinheitmitarbeiterModel->db->escape($new_data['semesterstunden'])}) as summe"); - else if ($alte_stunden_eingerechnet && !$neue_stunden_eingerechnet) - $this->_ci->LehreinheitmitarbeiterModel->addSelect("(SUM(tbl_lehreinheitmitarbeiter.semesterstunden) - ($lehreinheit->semesterstunden)) as summe"); - else if (!$alte_stunden_eingerechnet && $neue_stunden_eingerechnet) - $this->_ci->LehreinheitmitarbeiterModel->addSelect("(SUM(tbl_lehreinheitmitarbeiter.semesterstunden) + ({$this->_ci->LehreinheitmitarbeiterModel->db->escape($new_data['semesterstunden'])})) as summe"); - else if (!$alte_stunden_eingerechnet && !$neue_stunden_eingerechnet) - $this->_ci->LehreinheitmitarbeiterModel->addSelect("(SUM(tbl_lehreinheitmitarbeiter.semesterstunden)) as summe"); - - $this->_ci->LehreinheitmitarbeiterModel->addJoin('lehre.tbl_lehreinheit', 'lehreinheit_id'); - $this->_ci->LehreinheitmitarbeiterModel->addJoin('lehre.tbl_lehrveranstaltung', 'lehrveranstaltung_id'); - $this->_ci->LehreinheitmitarbeiterModel->addJoin('public.tbl_studiengang', 'studiengang_kz'); - - $this->_ci->LehreinheitmitarbeiterModel->db->where('mitarbeiter_uid', (isset($new_data['mitarbeiter_uid']) ? $new_data['mitarbeiter_uid'] : $mitarbeiter_uid)); - $this->_ci->LehreinheitmitarbeiterModel->db->where('studiensemester_kurzbz', $lehreinheit->studiensemester_kurzbz); - $this->_ci->LehreinheitmitarbeiterModel->db->where('bismelden', true); - $this->_ci->LehreinheitmitarbeiterModel->db->where('lower(mitarbeiter_uid) NOT LIKE', '_dummy%'); - $this->_ci->LehreinheitmitarbeiterModel->db->where_in('tbl_studiengang.oe_kurzbz', $oe_array); + } + if(defined('FAS_LV_LEKTORINNENZUTEILUNG_STUNDEN_IGNORE_OE') + && is_array(FAS_LV_LEKTORINNENZUTEILUNG_STUNDEN_IGNORE_OE) + && count(FAS_LV_LEKTORINNENZUTEILUNG_STUNDEN_IGNORE_OE) > 0) + { + $this->_ci->LehreinheitmitarbeiterModel->db->where_not_in('tbl_studiengang.oe_kurzbz', FAS_LV_LEKTORINNENZUTEILUNG_STUNDEN_IGNORE_OE); + } - if(defined('FAS_LV_LEKTORINNENZUTEILUNG_STUNDEN_IGNORE_OE') - && is_array(FAS_LV_LEKTORINNENZUTEILUNG_STUNDEN_IGNORE_OE) - && count(FAS_LV_LEKTORINNENZUTEILUNG_STUNDEN_IGNORE_OE) > 0) + $summe_result = $this->_ci->LehreinheitmitarbeiterModel->load(); + + if (isError($summe_result)) return $summe_result; + + if (!hasData($summe_result)) return error('Fehler beim Ermitteln der Gesamtstunden'); + + $summe = getData($summe_result)[0]->summe; + + if ($summe > $stundengrenze->stunden) + { + if (!$echter_dv && (!$this->_ci->permissionlib->isBerechtigt('admin'))) { - $this->_ci->LehreinheitmitarbeiterModel->db->where_not_in('tbl_studiengang.oe_kurzbz', FAS_LV_LEKTORINNENZUTEILUNG_STUNDEN_IGNORE_OE); + if (!$this->LehrauftragAufFirma($new_uid)) + return error("ACHTUNG: Die maximal erlaubte Semesterstundenanzahl des Lektors von $summe Stunden ($stundengrenze->stunden) wurde ueberschritten!\nDaten wurden NICHT gespeichert!\n\n"); + } + else + { + $warning .= "ACHTUNG: Die maximal erlaubte Semesterstundenanzahl des Lektors von $summe Stunden ($stundengrenze->stunden) wurde ueberschritten!\nDaten wurden gespeichert!\n\n"; } - $summe_result = $this->_ci->LehreinheitmitarbeiterModel->load(); + $stunden_limit_result = $this->getStundenInstitut($new_uid, $lehreinheit->studiensemester_kurzbz, $oe_array); - if (isError($summe_result)) return $summe_result; - - if (!hasData($summe_result)) return error('Fehler beim Ermitteln der Gesamtstunden'); - - $summe = getData($summe_result)[0]->summe; - - if ($summe > $stundengrenze->stunden) + if (hasData($stunden_limit_result)) { - - if (!$echter_dv && (!$this->_ci->permissionlib->isBerechtigt('admin'))) + $stunden_limit_array = getData($stunden_limit_result); + foreach ($stunden_limit_array as $stunden_limit) { - if (!$this->LehrauftragAufFirma(isset($formData['mitarbeiter_uid']) ? $formData['mitarbeiter_uid'] : $mitarbeiter_uid)) - return error("ACHTUNG: Die maximal erlaubte Semesterstundenanzahl des Lektors von $summe Stunden ($stundengrenze->stunden) wurde ueberschritten!\nDaten wurden NICHT gespeichert!\n\n"); - } - else - { - $warning .= "ACHTUNG: Die maximal erlaubte Semesterstundenanzahl des Lektors von $summe Stunden ($stundengrenze->stunden) wurde ueberschritten!\nDaten wurden gespeichert!\n\n"; - } - - $stunden_limit_result = $this->getStundenInstitut($mitarbeiter_uid, $lehreinheit->studiensemester_kurzbz, $oe_array); - - if (hasData($stunden_limit_result)) - { - $stunden_limit_array = getData($stunden_limit_result); - foreach ($stunden_limit_array as $stunden_limit) - { - $warning .= $stunden_limit->summe . ' Stunden ' . $stunden_limit->bezeichnung . "\n"; - } + $warning .= $stunden_limit->summe . ' Stunden ' . $stunden_limit->bezeichnung . "\n"; } } } } - $benutzer_result = $this->_ci->BenutzerModel->load(array(isset($formData['mitarbeiter_uid']) ? $formData['mitarbeiter_uid'] : $mitarbeiter_uid)); + $benutzer_result = $this->_ci->BenutzerModel->load(array($new_uid)); if (isError($benutzer_result)) return $benutzer_result; @@ -240,10 +263,24 @@ class LektorLib $updateData['updatevon'] = getAuthUID(); $updateData['updateamum'] = date('Y-m-d H:i:s'); - $result = $this->_ci->LehreinheitmitarbeiterModel->update(array('lehreinheit_id' => $lehreinheit_id, 'mitarbeiter_uid' => $mitarbeiter_uid), $updateData); + $result = $this->_ci->LehreinheitmitarbeiterModel->update(array('lehreinheit_id' => $lehreinheit_id, 'mitarbeiter_uid' => $old_uid), $updateData); if (isError($result)) return $result; + if ($stundenplan_update) + { + $update_result = $this->_ci->StundenplandevModel->update([ + 'lehreinheit_id' => $lehreinheit_id, + 'mitarbeiter_uid' => $old_uid, + ], [ + 'mitarbeiter_uid' => $new_uid, + 'updateamum' => date('Y-m-d H:i:s'), + 'updatevon' => getAuthUID() + ]); + + if (isError($update_result)) return $update_result; + } + if ($warning !== '') return success(['warning' => $warning]); return success('Erfolgreich geupdated'); @@ -347,4 +384,53 @@ class LektorLib $this->_ci->LehreinheitmitarbeiterModel->addGroupBy('tbl_studiengang.bezeichnung'); return $this->_ci->LehreinheitmitarbeiterModel->load(); } +//if($rechte->isBerechtigt('lv-plan')) + + private function hasKollision($stunden, $mitarbeiter) + { + $kollision = array(); + + $ignore_zeitsperre = $this->_ci->variablelib->getVar('ignore_zeitsperre'); + $ignore_reservierung = $this->_ci->variablelib->getVar('ignore_reservierung'); + + foreach ($stunden as $stunde) + { + $stundenplan_result = $this->_ci->StundenplandevModel->lektorHasStundenplandevEintrag($mitarbeiter, $stunde->datum, $stunde->stunde); + + if (isError($stundenplan_result)) + return $stundenplan_result; + + if (hasData($stundenplan_result)) + { + $stundenplan_result = getData($stundenplan_result)[0]; + $kollision[] = "Kollision stundenplandev: $stundenplan_result->stundenplandev_id|$stundenplan_result->lektor|$stundenplan_result->ort_kurzbz|$stundenplan_result->stg_kurzbz-$stundenplan_result->semester$stundenplan_result->verband$stundenplan_result->gruppe$stundenplan_result->gruppe_kurzbz - $stundenplan_result->datum/$stundenplan_result->stunde"; + } + else + { + if ($ignore_zeitsperre == 'false' && (!defined('KOLLISIONSFREIE_USER') || !in_array($mitarbeiter, unserialize(KOLLISIONSFREIE_USER)))) + { + $zeitsperre_result = $this->_ci->ZeitsperreModel->checkIfZeitsperreExists($mitarbeiter, $stunde->datum, $stunde->stunde); + + if (hasData($zeitsperre_result)) + { + $zeitsperre_result = getData($zeitsperre_result)[0]; + $kollision[] = "Kollision (Zeitsperre): $zeitsperre_result->zeitsperre_id|$zeitsperre_result->mitarbeiter_uid|$zeitsperre_result->zeitsperretyp_kurzbz - $zeitsperre_result->vondatum/$zeitsperre_result->vonstunde|$zeitsperre_result->bisdatum/$zeitsperre_result->bisstunde"; + } + } + + if ($ignore_reservierung == 'false' && (!defined('KOLLISIONSFREIE_USER') || !in_array($mitarbeiter, unserialize(KOLLISIONSFREIE_USER)))) + { + $reservierung_result = $this->_ci->ReservierungModel->lektorHasReservierung($mitarbeiter, $stunde->datum, $stunde->stunde); + + if (hasData($reservierung_result)) + { + $reservierung_result = getData($reservierung_result)[0]; + $kollision[] = "Kollision (Reservierung): $reservierung_result->reservierung_id|$reservierung_result->uid|$reservierung_result->ort_kurzbz|$reservierung_result->stg_kurzbz-$reservierung_result->semester$reservierung_result->verband$reservierung_result->gruppe$reservierung_result->gruppe_kurzbz - $reservierung_result->datum/$reservierung_result->stunde"; + } + } + } + } + + return isEmptyArray($kollision) ? false : $kollision; + } } diff --git a/application/models/ressource/Reservierung_model.php b/application/models/ressource/Reservierung_model.php index 0c391ea20..8049838eb 100644 --- a/application/models/ressource/Reservierung_model.php +++ b/application/models/ressource/Reservierung_model.php @@ -135,4 +135,15 @@ class Reservierung_model extends DB_Model return $this->execQuery($query, [$uid, $uid]); } + public function lektorHasReservierung($uid, $datum, $stunde) + { + $qry = "SELECT reservierung_id, uid, stg_kurzbz, ort_kurzbz, semester, verband, gruppe, gruppe_kurzbz, datum, stunde + FROM lehre.vw_reservierung + WHERE uid = ? + AND datum = ? + AND stunde = ?"; + + return $this->execReadOnlyQuery($qry, [$uid, $datum, $stunde]); + } + } diff --git a/application/models/ressource/Stundenplandev_model.php b/application/models/ressource/Stundenplandev_model.php index e718ba073..355283b90 100644 --- a/application/models/ressource/Stundenplandev_model.php +++ b/application/models/ressource/Stundenplandev_model.php @@ -241,4 +241,15 @@ class Stundenplandev_model extends DB_Model return $this->delete(array('lehreinheit_id' => $lehreinheit_id, 'mitarbeiter_uid' => $mitarbeiter_uid)); } + + public function lektorHasStundenplandevEintrag($uid, $datum, $stunde) + { + $qry = "SELECT stundenplandev_id, lektor, stg_kurzbz, ort_kurzbz, semester, verband, gruppe, gruppe_kurzbz, datum, stunde + FROM lehre.vw_stundenplandev + WHERE uid = ? + AND datum = ? + AND stunde = ?"; + + return $this->execReadOnlyQuery($qry, [$uid, $datum, $stunde]); + } } diff --git a/application/models/ressource/Zeitsperre_model.php b/application/models/ressource/Zeitsperre_model.php index 078d29d8b..50ba4cb1d 100644 --- a/application/models/ressource/Zeitsperre_model.php +++ b/application/models/ressource/Zeitsperre_model.php @@ -61,4 +61,40 @@ class Zeitsperre_model extends DB_Model return $this->execQuery($qry); } + + public function checkIfZeitsperreExists($uid, $datum, $stunde) + { + $this->db->select("*"); + + $this->db->where('mitarbeiter_uid', $uid); + $this->db->where('zeitsperretyp_kurzbz !=', 'ZVerfueg'); + + $this->db->group_start(); + + $this->db->where('vondatum <', $datum); + $this->db->or_group_start(); + $this->db->where('vondatum', $datum); + $this->db->group_start(); + $this->db->where('vonstunde <=', $stunde); + $this->db->or_where('vonstunde IS NULL', null, false); + $this->db->group_end(); + $this->db->group_end(); + $this->db->group_end(); + + + $this->db->group_start(); + $this->db->where('bisdatum >', $datum); + $this->db->or_group_start(); + $this->db->where('bisdatum', $datum); + $this->db->group_start(); + $this->db->where('bisstunde >=', $stunde); + $this->db->or_where('bisstunde IS NULL', null, false); + $this->db->group_end(); + + $this->db->group_end(); + $this->db->group_end(); + + return $this->load(); + + } } diff --git a/application/views/LVVerwaltung.php b/application/views/LVVerwaltung.php index 4cebae839..42d4631f1 100644 --- a/application/views/LVVerwaltung.php +++ b/application/views/LVVerwaltung.php @@ -31,6 +31,8 @@ lv-root="" :permissions="" :config="" + avatar-url="" + logout-url="" > diff --git a/public/js/api/lehrveranstaltung/config.js b/public/js/api/lehrveranstaltung/config.js new file mode 100644 index 000000000..40d275145 --- /dev/null +++ b/public/js/api/lehrveranstaltung/config.js @@ -0,0 +1,15 @@ +export default { + get() { + return { + method: 'get', + url: '/api/frontend/v1/lv/config/get' + }; + }, + set(params) { + return { + method: 'post', + url: 'api/frontend/v1/lv/config/set', + params + }; + } +}; diff --git a/public/js/components/LVVerwaltung/LVVerwaltung.js b/public/js/components/LVVerwaltung/LVVerwaltung.js index 42c50bdfa..4854854b9 100644 --- a/public/js/components/LVVerwaltung/LVVerwaltung.js +++ b/public/js/components/LVVerwaltung/LVVerwaltung.js @@ -8,9 +8,10 @@ import LvTabs from "./Setup/Tabs.js"; import ApiDetails from "../../api/lehrveranstaltung/details.js"; import ApiLektor from "../../api/lehrveranstaltung/lektor.js"; -import ApiGruppe from "../../api/lehrveranstaltung/gruppe.js"; import ApiStudiengangTree from "../../api/lehrveranstaltung/studiengangtree.js"; import ApiSearchbar from "../../api/factory/searchbar.js"; +import AppConfig from "../AppConfig.js"; +import ApiLvConfig from "../../api/lehrveranstaltung/config.js"; export default { @@ -23,6 +24,7 @@ export default { StvStudiensemester, LvTable, LvTabs, + AppConfig }, props: { defaultSemester: String, @@ -32,7 +34,9 @@ export default { stg: { type: String, required: false }, semester: { type: [Number, String], required: false, default: null }, studiensemester_kurzbz: { type: String, required: false, default: null }, - emp: { type: String, required: false, default: null } + emp: { type: String, required: false, default: null }, + avatarUrl: String, + logoutUrl: String, }, provide() { @@ -44,7 +48,6 @@ export default { lehreinheitAnmerkungDefault: (this.config.lehreinheitAnmerkungDefault || '').replace(/\\n/g, '\n'), lehreinheitRaumtypDefault: this.config.lehreinheitRaumtypDefault, lehreinheitRaumtypAlternativeDefault: this.config.lehreinheitRaumtypAlternativeDefault, - permissionLehrveranstaltung: this.permissions['lehre/lehrveranstaltung'], permissionGruppenEntfernen: this.permissions['lv-plan/gruppenentfernen'], permissionLektorEntfernen: this.permissions['lv-plan/lektorentfernen'], @@ -72,6 +75,8 @@ export default { }, data() { return { + appconfig:{}, + configEndpoints: ApiLvConfig, selected: [], studiengang: "", filter: {}, @@ -269,6 +274,51 @@ export default { +
@@ -327,5 +377,6 @@ export default {
+
` }; diff --git a/public/js/components/LVVerwaltung/Lektor/Daten.js b/public/js/components/LVVerwaltung/Lektor/Daten.js index 21e5dc196..0263b236f 100644 --- a/public/js/components/LVVerwaltung/Lektor/Daten.js +++ b/public/js/components/LVVerwaltung/Lektor/Daten.js @@ -140,7 +140,7 @@ export default{ { this.$emit('changedLektor', this.changed.mitarbeiter_uid); } - if (this.changed.semesterstunden || this.changed.stundensatz) + else if (this.changed.semesterstunden || this.changed.stundensatz) { this.$emit('changedCosts'); } @@ -183,9 +183,6 @@ export default{ }, }, - created() { - this.getLektorData() - }, template: `
From bb236796835f4a325b54056621f31990d7b81f3a Mon Sep 17 00:00:00 2001 From: ma0048 Date: Thu, 12 Feb 2026 10:45:32 +0100 Subject: [PATCH 11/18] auskommentierten code entfernt --- application/libraries/LektorLib.php | 1 - 1 file changed, 1 deletion(-) diff --git a/application/libraries/LektorLib.php b/application/libraries/LektorLib.php index 0e96a1070..a89ccdf6b 100644 --- a/application/libraries/LektorLib.php +++ b/application/libraries/LektorLib.php @@ -384,7 +384,6 @@ class LektorLib $this->_ci->LehreinheitmitarbeiterModel->addGroupBy('tbl_studiengang.bezeichnung'); return $this->_ci->LehreinheitmitarbeiterModel->load(); } -//if($rechte->isBerechtigt('lv-plan')) private function hasKollision($stunden, $mitarbeiter) { From 233a6e8b8915173eb59add4a3d2a3741161c1305 Mon Sep 17 00:00:00 2001 From: ma0048 Date: Wed, 25 Feb 2026 15:25:36 +0100 Subject: [PATCH 12/18] =?UTF-8?q?lvverwaltung:=20-=20event=20hinzugefuegt?= =?UTF-8?q?=20damit=20tabs=20erweitert=20werden=20k=C3=B6nnen=20-=20berich?= =?UTF-8?q?te=20hinzugefuegt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controllers/api/frontend/v1/lv/Setup.php | 7 ++ .../statistik/lehrauftragsliste_gst.xls.php | 6 ++ content/statistik/lvplanung.php | 6 ++ .../components/LVVerwaltung/LVVerwaltung.js | 98 ++++++++++++++++- system/phrasesupdate.php | 100 ++++++++++++++++++ 5 files changed, 215 insertions(+), 2 deletions(-) diff --git a/application/controllers/api/frontend/v1/lv/Setup.php b/application/controllers/api/frontend/v1/lv/Setup.php index eea4befa5..2c1c1d842 100644 --- a/application/controllers/api/frontend/v1/lv/Setup.php +++ b/application/controllers/api/frontend/v1/lv/Setup.php @@ -19,6 +19,8 @@ if (!defined('BASEPATH')) exit('No direct script access allowed'); +use CI3_Events as Events; + class Setup extends FHCAPI_Controller { private $_ci; @@ -65,6 +67,11 @@ class Setup extends FHCAPI_Controller 'component' => absoluteJsImportUrl('public/js/components/LVVerwaltung/Tabs/Notiz.js'), 'config' => [] ); + + Events::trigger('lvv_conf_tabs', function & () use (&$tabs) { + return $tabs; + }); + $this->terminateWithSuccess($tabs); } diff --git a/content/statistik/lehrauftragsliste_gst.xls.php b/content/statistik/lehrauftragsliste_gst.xls.php index 990216c09..d44c91e63 100644 --- a/content/statistik/lehrauftragsliste_gst.xls.php +++ b/content/statistik/lehrauftragsliste_gst.xls.php @@ -41,6 +41,12 @@ else $user = get_uid(); loadVariables($user); +if (isset($_GET['studiensemester_kurzbz'])) +{ + if (check_stsem($_GET['studiensemester_kurzbz'])) + $semester_aktuell = $_GET['studiensemester_kurzbz']; +} + //Studiengang laden $studiengang = new studiengang($studiengang_kz); diff --git a/content/statistik/lvplanung.php b/content/statistik/lvplanung.php index b0169dade..fe69e4160 100644 --- a/content/statistik/lvplanung.php +++ b/content/statistik/lvplanung.php @@ -50,6 +50,12 @@ else $user = get_uid(); loadVariables($user); +if (isset($_GET['studiensemester_kurzbz'])) +{ + if (check_stsem($_GET['studiensemester_kurzbz'])) + $semester_aktuell = $_GET['studiensemester_kurzbz']; +} + $rechte = new benutzerberechtigung(); $rechte->getBerechtigungen($user); diff --git a/public/js/components/LVVerwaltung/LVVerwaltung.js b/public/js/components/LVVerwaltung/LVVerwaltung.js index 42c50bdfa..8b688cdb3 100644 --- a/public/js/components/LVVerwaltung/LVVerwaltung.js +++ b/public/js/components/LVVerwaltung/LVVerwaltung.js @@ -8,7 +8,6 @@ import LvTabs from "./Setup/Tabs.js"; import ApiDetails from "../../api/lehrveranstaltung/details.js"; import ApiLektor from "../../api/lehrveranstaltung/lektor.js"; -import ApiGruppe from "../../api/lehrveranstaltung/gruppe.js"; import ApiStudiengangTree from "../../api/lehrveranstaltung/studiengangtree.js"; import ApiSearchbar from "../../api/factory/searchbar.js"; @@ -205,6 +204,21 @@ export default { this.$router.push({ name: routeName, params: newParams }); this.selected = []; }, + isDisabled(item) + { + if (!item?.requires?.length) + return false; + + const values = { + stg: this.stg, + emp: this.emp, + studiensemester: this.selectedStudiensemester, + semester: this.semester + }; + + return item.requires.some(req => !values[req]); + + } }, created() { this.$p.loadCategory(['lehre', 'person', 'global']) @@ -239,6 +253,62 @@ export default { }) .catch(this.$fhcAlert.handleSystemError); }, + computed: + { + appMenuExtraItems() + { + let extraItems = []; + + const studiengang_kz = this.stg || ''; + const studiensemester = this.selectedStudiensemester; + const semester = this.semester || ''; + const uid = this.emp || ''; + + extraItems.push({ + link: FHC_JS_DATA_STORAGE_OBJECT.app_root + + 'content/statistik/lvplanung.xls.php' + + '?studiengang_kz=' + studiengang_kz + + '&studiensemester_kurzbz=' + studiensemester + + '&semester=' + semester, + description: 'lehre/lvplanung', + requires: ['stg'] + }); + + extraItems.push({ + link: FHC_JS_DATA_STORAGE_OBJECT.app_root + + 'content/statistik/lehrauftragsliste_gst.xls.php' + + '?studiengang_kz=' + studiengang_kz + + '&studiensemester_kurzbz=' + studiensemester + + '&semester=' + semester, + description: 'lehre/lehrauftragsliste', + requires: ['stg'] + }); + + extraItems.push({ + link: FHC_JS_DATA_STORAGE_OBJECT.app_root + + 'content/pdfExport.php?xml=lehrauftrag.xml.php' + + '&xsl=Lehrauftrag' + + '&stg_kz=' + studiengang_kz + + '&ss=' + studiensemester, + description: 'lehre/lehrauftraege', + requires: ['stg'] + }); + + extraItems.push({ + link: FHC_JS_DATA_STORAGE_OBJECT.app_root + + 'content/pdfExport.php?xml=lehrauftrag.xml.php' + + '&xsl=Lehrauftrag' + + '&stg_kz=' + studiengang_kz + + '&ss=' + studiensemester + + '&uid=' + uid, + description: 'lehre/lehrauftragslisteemp', + requires: ['emp'] + }); + + return extraItems; + + } + }, template: /* html */`
@@ -278,7 +348,31 @@ export default {
diff --git a/system/phrasesupdate.php b/system/phrasesupdate.php index b09a24a6f..f24efcebc 100644 --- a/system/phrasesupdate.php +++ b/system/phrasesupdate.php @@ -48901,7 +48901,7 @@ array( 'description' => '', 'insertvon' => 'system' ), - array(w + array( 'sprache' => 'English', 'text' => 'Teaching Assignments', 'description' => '', @@ -48949,6 +48949,26 @@ array( ) ) ), + array( + 'app' => 'core', + 'category' => 'lehre', + 'phrase' => 'extrakvverwaltung', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Lehrveranstaltung Verwaltung', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Course Management', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), // feature-55614 end array( 'app' => 'softwarebereitstellung', From e80ee0336595b89225293d138dbd5a0490c34134 Mon Sep 17 00:00:00 2001 From: ma0048 Date: Tue, 28 Apr 2026 14:13:22 +0200 Subject: [PATCH 14/18] fixed bug --- public/js/components/LVVerwaltung/Setup/Table.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/js/components/LVVerwaltung/Setup/Table.js b/public/js/components/LVVerwaltung/Setup/Table.js index e0153a612..9e48f070d 100644 --- a/public/js/components/LVVerwaltung/Setup/Table.js +++ b/public/js/components/LVVerwaltung/Setup/Table.js @@ -373,7 +373,7 @@ export default { { this.getLVInfos(data[0]); } - this.$emit('update:selected', [data[0]]); + this.$emit('update:selected', data); }, getLVInfos(data) { From b57836c2af784e0310785a74031e9997f455ca3f Mon Sep 17 00:00:00 2001 From: ma0048 Date: Tue, 28 Apr 2026 14:17:23 +0200 Subject: [PATCH 15/18] fixed bug --- public/js/components/LVVerwaltung/Setup/Table.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/js/components/LVVerwaltung/Setup/Table.js b/public/js/components/LVVerwaltung/Setup/Table.js index e0153a612..9e48f070d 100644 --- a/public/js/components/LVVerwaltung/Setup/Table.js +++ b/public/js/components/LVVerwaltung/Setup/Table.js @@ -373,7 +373,7 @@ export default { { this.getLVInfos(data[0]); } - this.$emit('update:selected', [data[0]]); + this.$emit('update:selected', data); }, getLVInfos(data) { From e9312dfbb34b8305370ee1597fc9d2396dbd6b5b Mon Sep 17 00:00:00 2001 From: ma0048 Date: Wed, 15 Jul 2026 11:35:37 +0200 Subject: [PATCH 16/18] lvverwaltung new release --- application/controllers/api/frontend/v1/lv/Setup.php | 6 +++--- application/libraries/LektorLib.php | 9 ++++++--- public/js/components/LVVerwaltung/Setup/Table.js | 3 ++- .../components/Stv/Studentenverwaltung/Details/Noten.js | 2 +- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/application/controllers/api/frontend/v1/lv/Setup.php b/application/controllers/api/frontend/v1/lv/Setup.php index fa5b542bf..4b91b99c1 100644 --- a/application/controllers/api/frontend/v1/lv/Setup.php +++ b/application/controllers/api/frontend/v1/lv/Setup.php @@ -66,7 +66,7 @@ class Setup extends FHCAPI_Controller ); $tabs['termine'] = array ( 'title' => 'Termine', - 'component' => APP_ROOT . 'public/js/components/LVVerwaltung/Tabs/Termine.js', + 'component' => absoluteJsImportUrl('public/js/components/LVVerwaltung/Tabs/Termine.js'), 'config' => [] ); $tabs['notiz'] = array ( @@ -86,12 +86,12 @@ class Setup extends FHCAPI_Controller { $tabs['termine'] = array ( 'title' => 'Termine', - 'component' => APP_ROOT . 'public/js/components/LVVerwaltung/Tabs/LVTermine.js', + 'component' => absoluteJsImportUrl('public/js/components/LVVerwaltung/Tabs/LVTermine.js'), 'config' => [] ); $tabs['noten'] = array ( 'title' => 'Noten', - 'component' => APP_ROOT . 'public/js/components/LVVerwaltung/Tabs/Noten.js', + 'component' => absoluteJsImportUrl('public/js/components/LVVerwaltung/Tabs/Noten.js'), 'config' => [ 'usePoints' => defined('CIS_GESAMTNOTE_PUNKTE') && CIS_GESAMTNOTE_PUNKTE, 'edit' => 'both', // Possible values: both|header|inline diff --git a/application/libraries/LektorLib.php b/application/libraries/LektorLib.php index 7deed3a11..8a60e0aaa 100644 --- a/application/libraries/LektorLib.php +++ b/application/libraries/LektorLib.php @@ -165,12 +165,15 @@ class LektorLib $oe_result = $this->_ci->OrganisationseinheitModel->getChilds($stundengrenze->oe_kurzbz); $oe_array = hasData($oe_result) ? array_column(getData($oe_result), 'oe_kurzbz') : array(); + $semesterstunden_alt_sql = is_null($semesterstunden_alt) ? 0 : $semesterstunden_alt; + $semesterstunden_neu_sql = is_null($semesterstunden_neu) ? 0 : $semesterstunden_neu; + if ($alte_stunden_eingerechnet && $neue_stunden_eingerechnet) - $this->_ci->LehreinheitmitarbeiterModel->addSelect("(SUM(tbl_lehreinheitmitarbeiter.semesterstunden) - ($semesterstunden_alt) + {$this->_ci->LehreinheitmitarbeiterModel->db->escape($semesterstunden_neu)}) as summe"); + $this->_ci->LehreinheitmitarbeiterModel->addSelect("(SUM(tbl_lehreinheitmitarbeiter.semesterstunden) - ($semesterstunden_alt_sql) + {$this->_ci->LehreinheitmitarbeiterModel->db->escape($semesterstunden_neu_sql)}) as summe"); else if ($alte_stunden_eingerechnet && !$neue_stunden_eingerechnet) - $this->_ci->LehreinheitmitarbeiterModel->addSelect("(SUM(tbl_lehreinheitmitarbeiter.semesterstunden) - ($semesterstunden_alt)) as summe"); + $this->_ci->LehreinheitmitarbeiterModel->addSelect("(SUM(tbl_lehreinheitmitarbeiter.semesterstunden) - ($semesterstunden_alt_sql)) as summe"); else if (!$alte_stunden_eingerechnet && $neue_stunden_eingerechnet) - $this->_ci->LehreinheitmitarbeiterModel->addSelect("(SUM(tbl_lehreinheitmitarbeiter.semesterstunden) + ({$this->_ci->LehreinheitmitarbeiterModel->db->escape($semesterstunden_neu)})) as summe"); + $this->_ci->LehreinheitmitarbeiterModel->addSelect("(SUM(tbl_lehreinheitmitarbeiter.semesterstunden) + ({$this->_ci->LehreinheitmitarbeiterModel->db->escape($semesterstunden_neu_sql)})) as summe"); else if (!$alte_stunden_eingerechnet && !$neue_stunden_eingerechnet) $this->_ci->LehreinheitmitarbeiterModel->addSelect("(SUM(tbl_lehreinheitmitarbeiter.semesterstunden)) as summe"); diff --git a/public/js/components/LVVerwaltung/Setup/Table.js b/public/js/components/LVVerwaltung/Setup/Table.js index 0e2092723..751fe459a 100644 --- a/public/js/components/LVVerwaltung/Setup/Table.js +++ b/public/js/components/LVVerwaltung/Setup/Table.js @@ -54,6 +54,7 @@ export default { if (this.$refs.table && this.$refs.table.tabulator) { this.expanded = []; + this.currentTreeLevel = 0; this.reload(); } }, @@ -141,7 +142,7 @@ export default { }, layout: 'fitDataStretch', height: '100%', - persistenceID: 'lehrveranstaltungen_2025_12_02_v1', + persistenceID: 'lehrveranstaltungen_2026_07_15_v1', selectableRowsRangeMode: 'click', selectableRows: true, rowContextMenu: (component, e) => { diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Noten.js b/public/js/components/Stv/Studentenverwaltung/Details/Noten.js index 3217f192c..48863da9c 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Noten.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Noten.js @@ -3,7 +3,7 @@ import NotenTeacher from './Noten/Teacher.js'; import NotenRepeater from './Noten/Repeater.js'; import ApiStvGrades from '../../../../api/factory/stv/grades.js'; -import { highlightGesamtnote } from "../../../../helpers/DocumentHelper"; +import { highlightGesamtnote } from "../../../../helpers/DocumentHelper.js"; const LOCAL_STORAGE_ID = 'stv_details_noten_2024-11-25_stdsem_all'; From a36ed5539093e40d0727db85e6945d08bd9a589e Mon Sep 17 00:00:00 2001 From: chfhtw Date: Thu, 16 Jul 2026 11:43:10 +0200 Subject: [PATCH 17/18] Add new props to beginning to avoid merge conflicts --- public/js/components/LVVerwaltung/LVVerwaltung.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/public/js/components/LVVerwaltung/LVVerwaltung.js b/public/js/components/LVVerwaltung/LVVerwaltung.js index 6d57554de..4fa7064a3 100644 --- a/public/js/components/LVVerwaltung/LVVerwaltung.js +++ b/public/js/components/LVVerwaltung/LVVerwaltung.js @@ -27,6 +27,8 @@ export default { AppConfig }, props: { + avatarUrl: String, + logoutUrl: String, defaultSemester: String, lvRoot: String, permissions: Object, @@ -34,9 +36,7 @@ export default { stg: { type: String, required: false }, semester: { type: [Number, String], required: false, default: null }, studiensemester_kurzbz: { type: String, required: false, default: null }, - emp: { type: String, required: false, default: null }, - avatarUrl: String, - logoutUrl: String, + emp: { type: String, required: false, default: null } }, provide() { From d391d1f09c35fcc9f940008dc1720942296336a5 Mon Sep 17 00:00:00 2001 From: chfhtw Date: Thu, 16 Jul 2026 11:43:51 +0200 Subject: [PATCH 18/18] Move computed to the correct position to avoid merge conflicts --- .../components/LVVerwaltung/LVVerwaltung.js | 135 +++++++++--------- 1 file changed, 67 insertions(+), 68 deletions(-) diff --git a/public/js/components/LVVerwaltung/LVVerwaltung.js b/public/js/components/LVVerwaltung/LVVerwaltung.js index 4fa7064a3..a71c2b7b7 100644 --- a/public/js/components/LVVerwaltung/LVVerwaltung.js +++ b/public/js/components/LVVerwaltung/LVVerwaltung.js @@ -112,6 +112,73 @@ export default { }, } }, + computed: { + appMenuExtraItems() + { + let extraItems = []; + + const studiengang_kz = this.stg || ''; + const studiensemester = this.selectedStudiensemester; + const semester = this.semester || ''; + const uid = this.emp || ''; + + + extraItems.push( + { + description: 'lehre/berichte', + requires: ['stg'], + children: [ + { + link: FHC_JS_DATA_STORAGE_OBJECT.app_root + + 'content/statistik/lvplanung.xls.php' + + '?studiengang_kz=' + studiengang_kz + + '&studiensemester_kurzbz=' + studiensemester + + '&semester=' + semester, + description: 'lehre/lvplanung', + requires: ['stg'] + }, + { + link: FHC_JS_DATA_STORAGE_OBJECT.app_root + + 'content/statistik/lehrauftragsliste_gst.xls.php' + + '?studiengang_kz=' + studiengang_kz + + '&studiensemester_kurzbz=' + studiensemester + + '&semester=' + semester, + description: 'lehre/lehrauftragsliste', + requires: ['stg'] + }, + { + link: FHC_JS_DATA_STORAGE_OBJECT.app_root + + 'content/pdfExport.php?xml=lehrauftrag.xml.php' + + '&xsl=Lehrauftrag' + + '&stg_kz=' + studiengang_kz + + '&ss=' + studiensemester, + description: 'lehre/lehrauftraege', + requires: ['stg'] + }, + { + link: FHC_JS_DATA_STORAGE_OBJECT.app_root + + 'content/pdfExport.php?xml=lehrauftrag.xml.php' + + '&xsl=Lehrauftrag' + + '&stg_kz=' + studiengang_kz + + '&ss=' + studiensemester + + '&uid=' + uid, + description: 'lehre/lehrauftragslisteemp', + requires: ['emp'] + } + ] + }, + { + link: FHC_JS_DATA_STORAGE_OBJECT.app_root + + 'vilesci/lehre/lehrveranstaltung.php' + + '?stg_kz=' + studiengang_kz, + description: 'lehre/extrakvverwaltung', + requires: ['stg'] + } + ); + + return extraItems; + } + }, methods: { updateFilter() { @@ -259,74 +326,6 @@ export default { }) .catch(this.$fhcAlert.handleSystemError); }, - computed: - { - appMenuExtraItems() - { - let extraItems = []; - - const studiengang_kz = this.stg || ''; - const studiensemester = this.selectedStudiensemester; - const semester = this.semester || ''; - const uid = this.emp || ''; - - - extraItems.push( - { - description: 'lehre/berichte', - requires: ['stg'], - children: [ - { - link: FHC_JS_DATA_STORAGE_OBJECT.app_root - + 'content/statistik/lvplanung.xls.php' - + '?studiengang_kz=' + studiengang_kz - + '&studiensemester_kurzbz=' + studiensemester - + '&semester=' + semester, - description: 'lehre/lvplanung', - requires: ['stg'] - }, - { - link: FHC_JS_DATA_STORAGE_OBJECT.app_root - + 'content/statistik/lehrauftragsliste_gst.xls.php' - + '?studiengang_kz=' + studiengang_kz - + '&studiensemester_kurzbz=' + studiensemester - + '&semester=' + semester, - description: 'lehre/lehrauftragsliste', - requires: ['stg'] - }, - { - link: FHC_JS_DATA_STORAGE_OBJECT.app_root - + 'content/pdfExport.php?xml=lehrauftrag.xml.php' - + '&xsl=Lehrauftrag' - + '&stg_kz=' + studiengang_kz - + '&ss=' + studiensemester, - description: 'lehre/lehrauftraege', - requires: ['stg'] - }, - { - link: FHC_JS_DATA_STORAGE_OBJECT.app_root - + 'content/pdfExport.php?xml=lehrauftrag.xml.php' - + '&xsl=Lehrauftrag' - + '&stg_kz=' + studiengang_kz - + '&ss=' + studiensemester - + '&uid=' + uid, - description: 'lehre/lehrauftragslisteemp', - requires: ['emp'] - } - ] - }, - { - link: FHC_JS_DATA_STORAGE_OBJECT.app_root - + 'vilesci/lehre/lehrveranstaltung.php' - + '?stg_kz=' + studiengang_kz, - description: 'lehre/extrakvverwaltung', - requires: ['stg'] - } - ); - - return extraItems; - } - }, template: /* html */`