From fc845ebf4e75c1ec26b32186eef8b8f02ab6ea37 Mon Sep 17 00:00:00 2001 From: Alexei Karpenko Date: Tue, 2 Sep 2025 15:04:45 +0200 Subject: [PATCH] Studierendenverwaltung Projektarbeit: separate saving of Projektarbeit and Betreuer, added action for editing Betreuer --- .../api/frontend/v1/stv/Projektarbeit.php | 6 +- .../api/frontend/v1/stv/Projektbetreuer.php | 65 +++--- .../education/Lehrveranstaltung_model.php | 57 ++++++ public/js/api/factory/stv/projektarbeit.js | 2 +- public/js/api/factory/stv/projektbetreuer.js | 4 +- .../Details/Projektarbeit/Details.js | 5 +- .../Details/Projektarbeit/Projektarbeit.js | 188 +++++++++--------- .../Details/Projektarbeit/Projektbetreuer.js | 82 +++----- system/phrasesupdate.php | 60 ++++-- 9 files changed, 248 insertions(+), 221 deletions(-) diff --git a/application/controllers/api/frontend/v1/stv/Projektarbeit.php b/application/controllers/api/frontend/v1/stv/Projektarbeit.php index e7d1af1f9..75478332f 100644 --- a/application/controllers/api/frontend/v1/stv/Projektarbeit.php +++ b/application/controllers/api/frontend/v1/stv/Projektarbeit.php @@ -310,13 +310,13 @@ class Projektarbeit extends FHCAPI_Controller 'projekttyp_kurzbz' => $formData['projekttyp_kurzbz'], 'firma_id' => $formData['firma_id'] ?? null, 'lehreinheit_id' => $formData['lehreinheit_id'], - 'beginn' => $formData['beginn'] ?? null, - 'ende' => $formData['ende'] ?? null, + 'beginn' => isset($formData['beginn']) && !isEmptyString($formData['beginn']) ? $formData['beginn'] : null, + 'ende' => isset($formData['ende']) && !isEmptyString($formData['ende']) ? $formData['ende'] : null, 'note' => $formData['note'] ?? null, 'final' => $formData['final'] ?? null, 'freigegeben' => $formData['freigegeben'] ?? null, 'anmerkung' => $formData['anmerkung'] ?? null, - 'gesperrtbis' => $formData['gesperrtbis'] ?? null + 'gesperrtbis' => isset($formData['gesperrtbis']) && !isEmptyString($formData['gesperrtbis']) ? $formData['gesperrtbis'] : null ]; } diff --git a/application/controllers/api/frontend/v1/stv/Projektbetreuer.php b/application/controllers/api/frontend/v1/stv/Projektbetreuer.php index 625a30c40..98567ecde 100644 --- a/application/controllers/api/frontend/v1/stv/Projektbetreuer.php +++ b/application/controllers/api/frontend/v1/stv/Projektbetreuer.php @@ -114,49 +114,40 @@ class Projektbetreuer extends FHCAPI_Controller if (!$this->ProjektarbeitModel->hasBerechtigungForProjektarbeit($projektarbeit_id)) return $this->_outputAuthError([$this->router->method => ['admin:rw', 'assistenz:rw']]); - $projektbetreuer = $this->input->post('projektbetreuerListe'); + $projektbetreuer = $this->input->post('projektbetreuer'); - if (!is_array($projektbetreuer)) - return $this->terminateWithError($this->p->t('projektarbeit', 'error_invalidProjektbetreuer'), self::ERROR_TYPE_GENERAL); - - foreach ($projektbetreuer as $pb) - { - if ($this->_validate($pb) == false) $this->terminateWithValidationErrors($this->form_validation->error_array()); - } + if ($this->_validate($projektbetreuer) == false) $this->terminateWithValidationErrors($this->form_validation->error_array()); $result = null; - foreach ($projektbetreuer as $pb) + $betreuer = [ + 'projektarbeit_id' => $projektarbeit_id, + 'person_id' => $projektbetreuer['person_id'], + 'note' => $projektbetreuer['note'], + 'stunden' => $projektbetreuer['stunden'], + 'stundensatz' => $projektbetreuer['stundensatz'], + 'betreuerart_kurzbz' => $projektbetreuer['betreuerart_kurzbz'] + ]; + + if (isset($projektbetreuer['person_id_old']) && isset($projektbetreuer['betreuerart_kurzbz_old'])) { - $betreuer = [ - 'projektarbeit_id' => $projektarbeit_id, - 'person_id' => $pb['person_id'], - 'note' => $pb['note'], - 'stunden' => $pb['stunden'], - 'stundensatz' => $pb['stundensatz'], - 'betreuerart_kurzbz' => $pb['betreuerart_kurzbz'] - ]; - - if (isset($pb['person_id_old']) && isset($pb['betreuerart_kurzbz_old'])) - { - $result = $this->ProjektbetreuerModel->update( - [ - 'projektarbeit_id' => $projektarbeit_id, - 'person_id' => $pb['person_id_old'], - 'betreuerart_kurzbz' => $pb['betreuerart_kurzbz_old'] - ], - array_merge($betreuer, ['updateamum' => date('c'), 'updatevon' => getAuthUID()]) - ); - } - else - { - $result = $this->ProjektbetreuerModel->insert( - array_merge($betreuer, ['insertamum' => date('c'), 'insertvon' => getAuthUID()]) - ); - } - - if (isError($result)) $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + $result = $this->ProjektbetreuerModel->update( + [ + 'projektarbeit_id' => $projektarbeit_id, + 'person_id' => $projektbetreuer['person_id_old'], + 'betreuerart_kurzbz' => $projektbetreuer['betreuerart_kurzbz_old'] + ], + array_merge($betreuer, ['updateamum' => date('c'), 'updatevon' => getAuthUID()]) + ); } + else + { + $result = $this->ProjektbetreuerModel->insert( + array_merge($betreuer, ['insertamum' => date('c'), 'insertvon' => getAuthUID()]) + ); + } + + if (isError($result)) $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); $this->terminateWithSuccess(hasData($result) ? getData($result) : []); } diff --git a/application/models/education/Lehrveranstaltung_model.php b/application/models/education/Lehrveranstaltung_model.php index 1b3b9e9d7..7347cf2ca 100644 --- a/application/models/education/Lehrveranstaltung_model.php +++ b/application/models/education/Lehrveranstaltung_model.php @@ -1255,4 +1255,61 @@ class Lehrveranstaltung_model extends DB_Model return $this->execReadOnlyQuery($qry, $params); } + + /** + * Gets Lehrveranstaltungen for a student, as needed for a Projektarbeit. + * @param student_uid + * @param studiengang_kz optional, all Lvs of this Studiengang will be included + * @param additional_lehrveranstaltung_id optional, this lv will be added to result + * @return object success or error + */ + public function getLvsForProjektarbeit($student_uid, $studiengang_kz = null, $additional_lehrveranstaltung_id = null) + { + $params = array($student_uid, $student_uid); + + $qry = " + SELECT * + FROM + lehre.tbl_lehrveranstaltung + WHERE + ( + lehrveranstaltung_id IN ( + + SELECT + lehrveranstaltung_id + FROM + campus.vw_student_lehrveranstaltung + WHERE + uid=? + + UNION + + SELECT + lehrveranstaltung_id + FROM + lehre.tbl_zeugnisnote + WHERE + student_uid=? + )"; + + if (isset($studiengang_kz)) + { + $params[] = $studiengang_kz; + $qry .= " OR (studiengang_kz = ? AND semester IS NOT NULL)"; + } + + if (isset($additional_lehrveranstaltung_id)) + { + $params[] = $additional_lehrveranstaltung_id; + $qry .= " OR lehrveranstaltung_id = ?"; + } + + $qry .= " + ) + AND projektarbeit = TRUE + ORDER BY + semester, bezeichnung"; + + return $this->execQuery($qry, $params); + } } diff --git a/public/js/api/factory/stv/projektarbeit.js b/public/js/api/factory/stv/projektarbeit.js index 243383de0..4412f1842 100644 --- a/public/js/api/factory/stv/projektarbeit.js +++ b/public/js/api/factory/stv/projektarbeit.js @@ -77,4 +77,4 @@ export default { params: { projektarbeit_id } }; } -}; \ No newline at end of file +}; diff --git a/public/js/api/factory/stv/projektbetreuer.js b/public/js/api/factory/stv/projektbetreuer.js index 211eaaca8..4ea7bc782 100644 --- a/public/js/api/factory/stv/projektbetreuer.js +++ b/public/js/api/factory/stv/projektbetreuer.js @@ -42,11 +42,11 @@ export default { url: 'api/frontend/v1/stv/projektbetreuer/getNoten' }; }, - saveProjektbetreuer(projektarbeit_id, projektbetreuerListe) { + saveProjektbetreuer(projektarbeit_id, projektbetreuer) { return { method: 'post', url: 'api/frontend/v1/stv/projektbetreuer/saveProjektbetreuer', - params: { projektarbeit_id, projektbetreuerListe } + params: { projektarbeit_id, projektbetreuer } }; }, deleteProjektbetreuer(projektarbeit_id, person_id, betreuerart_kurzbz) { diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Details.js b/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Details.js index 2fdc9d996..b7aea7169 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Details.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Details.js @@ -15,10 +15,6 @@ export default { defaultSemester: { from: 'defaultSemester' } - //~ config: { - //~ from: 'config', - //~ required: true - //~ } }, computed: { // prepared Lehreinheiten (with compound Bezeichnung) @@ -169,6 +165,7 @@ export default { }, loadProjektarbeit(projektarbeit_id) { + this.resetForm(); return this.$api .call(ApiStvProjektarbeit.loadProjektarbeit(projektarbeit_id)) .then(result => { diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektarbeit.js b/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektarbeit.js index 76953867f..952c47860 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektarbeit.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektarbeit.js @@ -36,7 +36,63 @@ export default { }, data() { return { - tabulatorOptions: { + tabulatorEvents: [ + { + event: 'dataLoaded', + handler: data => this.tabulatorData = data.map(item => { + item.actionDiv = document.createElement('div'); + return item; + }), + }, + { + event: 'tableBuilt', + handler: async() => { + await this.$p.loadCategory(['global', 'person', 'stv', 'ui', 'projektarbeit']); + + let cm = this.$refs.table.tabulator.columnManager; + + cm.getColumnByField('projekttyp_kurzbz').component.updateDefinition({ + title: this.$p.t('projektarbeit', 'typ') + }); + cm.getColumnByField('titel').component.updateDefinition({ + title: this.$p.t('projektarbeit', 'titel') + }); + cm.getColumnByField('beginn').component.updateDefinition({ + title: this.$p.t('projektarbeit', 'beginn') + }); + cm.getColumnByField('ende').component.updateDefinition({ + title: this.$p.t('projektarbeit', 'ende') + }); + cm.getColumnByField('freigegeben').component.updateDefinition({ + title: this.$p.t('projektarbeit', 'freigegeben') + }); + cm.getColumnByField('gesperrtbis').component.updateDefinition({ + title: this.$p.t('projektarbeit', 'gesperrtBis') + }); + cm.getColumnByField('themenbereich').component.updateDefinition({ + title: this.$p.t('projektarbeit', 'themenbereich') + }); + cm.getColumnByField('anmerkung').component.updateDefinition({ + title: this.$p.t('projektarbeit', 'anmerkung') + }); + cm.getColumnByField('firma_id').component.updateDefinition({ + title: this.$p.t('projektarbeit', 'firmaId') + }); + } + }, + ], + tabulatorData: [], + //lastSelected: null, + editedProjektarbeit: null, + statusNew: true, + studiensemester_kurzbz: null, + lehrveranstaltung_id: null, + activeTab: 'details' + } + }, + computed: { + tabulatorOptions() { + const options = { ajaxURL: 'dummy', ajaxRequestFunc: () => this.$api.call(ApiStvProjektarbeit.getProjektarbeit(this.student.uid)), ajaxResponse: (url, params, response) => response.data, @@ -153,9 +209,19 @@ export default { button.title = this.$p.t('ui', 'bearbeiten'); button.addEventListener('click', (event) => { let data = cell.getData(); - this.actionEditProjektarbeit( - data.projektarbeit_id, data.studiensemester_kurzbz, data.lehrveranstaltung_id, data.projekttyp_kurzbz - ); + this.editedProjektarbeit = data; + this.actionEditProjektarbeit(); + }); + container.append(button); + + button = document.createElement('button'); + button.className = 'btn btn-outline-secondary btn-action'; + button.innerHTML = ''; + button.title = this.$p.t('projektarbeit', 'betreuerBearbeiten'); + button.addEventListener('click', (event) => { + let data = cell.getData(); + this.editedProjektarbeit = data; + this.actionEditBetreuer(); }); container.append(button); @@ -184,76 +250,27 @@ export default { columns: true, //persist column layout }, persistenceID: 'stv-details-projektarbeit' - }, - tabulatorEvents: [ - { - event: 'rowSelectionChanged', - handler: this.rowSelectionChanged - }, - { - event: 'dataLoaded', - handler: data => this.tabulatorData = data.map(item => { - item.actionDiv = document.createElement('div'); - return item; - }), - }, - { - event: 'tableBuilt', - handler: async() => { - await this.$p.loadCategory(['global', 'person', 'stv', 'ui', 'projektarbeit']); - - let cm = this.$refs.table.tabulator.columnManager; - - cm.getColumnByField('projekttyp_kurzbz').component.updateDefinition({ - title: this.$p.t('projektarbeit', 'typ') - }); - cm.getColumnByField('titel').component.updateDefinition({ - title: this.$p.t('projektarbeit', 'titel') - }); - cm.getColumnByField('beginn').component.updateDefinition({ - title: this.$p.t('projektarbeit', 'beginn') - }); - cm.getColumnByField('ende').component.updateDefinition({ - title: this.$p.t('projektarbeit', 'ende') - }); - cm.getColumnByField('freigegeben').component.updateDefinition({ - title: this.$p.t('projektarbeit', 'freigegeben') - }); - cm.getColumnByField('gesperrtbis').component.updateDefinition({ - title: this.$p.t('projektarbeit', 'gesperrtBis') - }); - cm.getColumnByField('themenbereich').component.updateDefinition({ - title: this.$p.t('projektarbeit', 'themenbereich') - }); - cm.getColumnByField('anmerkung').component.updateDefinition({ - title: this.$p.t('projektarbeit', 'anmerkung') - }); - cm.getColumnByField('firma_id').component.updateDefinition({ - title: this.$p.t('projektarbeit', 'firmaId') - }); - } - }, - ], - tabulatorData: [], - lastSelected: null, - statusNew: true, - studiensemester_kurzbz: null, - lehrveranstaltung_id: null + } + return options; } }, methods: { actionNewProjektarbeit() { this.statusNew = true; - this.$refs.projektarbeitDetails.resetForm(); this.$refs.projektarbeitDetails.getFormData(this.statusNew); - this.$refs.projektbetreuer.getData(); this.$refs.projektarbeitModal.show(); }, - actionEditProjektarbeit(projektarbeit_id, studiensemester_kurzbz, lehrveranstaltung_id, projekttyp_kurzbz) { + actionEditProjektarbeit() { this.statusNew = false; - this.$refs.projektarbeitDetails.getFormData(this.statusNew, studiensemester_kurzbz, lehrveranstaltung_id); - this.$refs.projektarbeitDetails.loadProjektarbeit(projektarbeit_id); - this.$refs.projektbetreuer.getData(projektarbeit_id, studiensemester_kurzbz, projekttyp_kurzbz); + this.toggleMenu('details'); + this.$refs.projektarbeitDetails.getFormData(this.statusNew, this.editedProjektarbeit.studiensemester_kurzbz, this.editedProjektarbeit.lehrveranstaltung_id); + this.$refs.projektarbeitDetails.loadProjektarbeit(this.editedProjektarbeit.projektarbeit_id); + this.$refs.projektarbeitModal.show(); + }, + actionEditBetreuer() { + this.statusNew = false; + this.toggleMenu('betreuer'); + this.$refs.projektbetreuer.getData(this.editedProjektarbeit.projektarbeit_id, this.editedProjektarbeit.studiensemester_kurzbz, this.editedProjektarbeit.projekttyp_kurzbz); this.$refs.projektarbeitModal.show(); }, actionDeleteProjektarbeit(projektarbeit_id) { @@ -266,34 +283,14 @@ export default { .catch(this.$fhcAlert.handleSystemError); }, addNewProjektarbeit() { - this.$refs.projektbetreuer.validateProjektbetreuer() - .then(() => { - return this.$refs.projektarbeitDetails.addNewProjektarbeit(); - }) - .then((result) => { - const projektarbeit_id = result.data; - - if (!isNaN(projektarbeit_id)) { - return this.$refs.projektbetreuer.saveProjektbetreuer(projektarbeit_id); - } - }) + this.$refs.projektarbeitDetails.addNewProjektarbeit() .then((result) => { this.projektarbeitSaved(); }) .catch(this.$fhcAlert.handleSystemError); }, updateProjektarbeit() { - this.$refs.projektbetreuer.validateProjektbetreuer() - .then(() => { - return this.$refs.projektarbeitDetails.updateProjektarbeit(); - }) - .then((result) => { - const projektarbeit_id = result.data; - - if (!isNaN(projektarbeit_id)) { - return this.$refs.projektbetreuer.saveProjektbetreuer(projektarbeit_id); - } - }) + this.$refs.projektarbeitDetails.updateProjektarbeit() .then((result) => { this.projektarbeitSaved(); }) @@ -314,10 +311,6 @@ export default { this.reload(); this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSave')); this.hideModal('projektarbeitModal'); - this.$refs.projektarbeitDetails.resetForm(); - }, - rowSelectionChanged(data) { - this.lastSelected = data.length > 0 ? data[0] : null; }, setDefaultStunden(projekttyp_kurzbz) { this.$refs.projektbetreuer.setDefaultStunden(projekttyp_kurzbz); @@ -327,6 +320,9 @@ export default { }, reload() { this.$refs.table.reloadTable(); + }, + toggleMenu(tabId) { + this.activeTab = tabId; } }, template: ` @@ -357,16 +353,16 @@ export default {
-
+
@@ -375,7 +371,7 @@ export default {
-
+
@@ -387,7 +383,7 @@ export default { diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektbetreuer.js b/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektbetreuer.js index 183c81bc0..1eb19e3fd 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektbetreuer.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektbetreuer.js @@ -132,6 +132,10 @@ export default { event: 'tableBuilt', handler: async() => { await this.$p.loadCategory(['global', 'person', 'stv', 'projektarbeit', 'ui']); + + // Force layout recalculation for handling overflow text + this.$refs.projektbetreuerTable.tabulator.redraw(true); + } }, { @@ -193,7 +197,7 @@ export default { if (idx >= 0) { // if betreuer found betreuer = projektbetreuerListe[idx]; - // set currently edited betreuera + // set currently edited betreuer this.formData = betreuer; // set download link @@ -259,46 +263,31 @@ export default { if (projektarbeit_id) { this.projektarbeit_id = projektarbeit_id; - this.$api - .call(ApiStvProjektbetreuer.getProjektbetreuer(projektarbeit_id)) - .then(result => { - this.$refs.projektbetreuerTable.tabulator.setData(this.addIds(result.data)); - this.resetForm(); - }) - .catch(this.$fhcAlert.handleSystemError); + this.getProjektbetreuer(); } else { this.$refs.projektbetreuerTable.tabulator.setData([]); this.resetForm(); } }, - // confirming Betreuer means adding/updating him in list (but not yet saving in db) - confirmProjektbetreuer() { - if (!this.betreuerFormOpened) return; - - if (typeof this.formData.betreuer_id == 'undefined') { - this.formData.betreuer_id = this.getNewBetreuerId(); - this.$refs.projektbetreuerTable.tabulator.addData(this.addAutoCompleteBetreuerToFormData(this.formData)); - } else { - this.$refs.projektbetreuerTable.tabulator.updateData([this.formData]); - } - - this.resetModes(); - }, - confirmProjektbetreuerAfterValidation() { - //if (!this.formDataModified()) return; - - this.validateProjektbetreuer() + getProjektbetreuer() { + this.$api + .call(ApiStvProjektbetreuer.getProjektbetreuer(this.projektarbeit_id)) .then(result => { - this.confirmProjektbetreuer(); + this.$refs.projektbetreuerTable.tabulator.replaceData(this.addIds(result.data)); this.resetForm(); }) .catch(this.$fhcAlert.handleSystemError); }, - saveProjektbetreuer(projektarbeit_id) { - this.confirmProjektbetreuer(); - return this.$refs.formProjektbetreuer.call( - ApiStvProjektbetreuer.saveProjektbetreuer(projektarbeit_id, this.$refs.projektbetreuerTable.tabulator.getData()) - ); + saveProjektbetreuer() { + this.$refs.formProjektbetreuer.call( + ApiStvProjektbetreuer.saveProjektbetreuer(this.projektarbeit_id, this.getFormDataWithBetreuer()) + ) + .then(result => { + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSave')); + this.getProjektbetreuer(); + this.resetModes(); + }) + .catch(this.$fhcAlert.handleSystemError); }, searchBetreuer(event) { if (this.abortController.betreuer) { @@ -312,16 +301,6 @@ export default { this.filteredBetreuer = result.data; }); }, - // validate betreuer for data - validateProjektbetreuer() { - let alleBetreuer = this.$refs.projektbetreuerTable.tabulator.getData(); - - if (this.betreuerFormOpened) { - alleBetreuer.push(this.addAutoCompleteBetreuerToFormData(this.formData)); - } - - return this.$refs.formProjektbetreuer.call(ApiStvProjektbetreuer.validateProjektbetreuer(alleBetreuer)); - }, resetForm() { this.formData = this.getDefaultFormData(); if (this.beurteilungDownloadLink !== null) this.beurteilungDownloadLink = ''; @@ -360,7 +339,7 @@ export default { return betreuerListe; }, // add the betreuer selected in automomplete to betreuer liste - addAutoCompleteBetreuerToFormData() { + getFormDataWithBetreuer() { let preparedFormData = this.formData; preparedFormData.projektarbeit_id = this.projektarbeit_id; @@ -385,16 +364,6 @@ export default { // if form data has not already been modified by user, set the default stunden if (!this.formDataModified()) this.formData.stunden = this.getDefaultStunden(projekttyp_kurzbz); }, - // get a new betreuer id (max + 1) - getNewBetreuerId() { - let max = 0; - - for (const betreuer of this.$refs.projektbetreuerTable.tabulator.getData()) { - if (betreuer.betreuer_id > max) max = betreuer.betreuer_id; - } - - return max + 1; - }, // check if form data has been modified since initial data has been captured formDataModified() { if (this.autocompleteSelectedBetreuer != null) return true; @@ -406,9 +375,6 @@ export default { return false; }, - reload() { - this.$refs.projektbetreuerTable.reloadTable(); - }, actionNewPerson() { this.$refs.newPersonModal.reset(); this.$refs.newPersonModal.open(); @@ -422,7 +388,7 @@ export default { this.$api .call(ApiStvProjektbetreuer.getPerson(result.person_id)) .then(response => { - // set the new person in autocomplete field + // set the new person in Betreuer autocomplete field this.autocompleteSelectedBetreuer = response.data; }) .catch(this.$fhcAlert.handleSystemError) @@ -541,8 +507,8 @@ export default { -