From 405062f5493fcdaaf3ed0e9b501a08e5aa93f081 Mon Sep 17 00:00:00 2001 From: Alexei Karpenko Date: Wed, 7 May 2025 18:36:51 +0200 Subject: [PATCH 01/27] added Projektarbeit tab to Studierendenverwaltung, adding, editing, deleting of Projektarbeiten now possible --- .../api/frontend/v1/stv/Config.php | 5 + .../api/frontend/v1/stv/Projektarbeit.php | 334 +++++++ .../education/Lehrveranstaltung_model.php | 57 ++ .../models/education/Projektarbeit_model.php | 34 +- application/models/ressource/Firma_model.php | 21 +- public/js/api/factory/stv/projektarbeit.js | 80 ++ .../Details/Projektarbeit.js | 24 + .../Details/Projektarbeit/Betreuung.js | 847 ++++++++++++++++++ .../Details/Projektarbeit/Details.js | 461 ++++++++++ .../Details/Projektarbeit/Projektarbeit.js | 377 ++++++++ 10 files changed, 2230 insertions(+), 10 deletions(-) create mode 100644 application/controllers/api/frontend/v1/stv/Projektarbeit.php create mode 100644 public/js/api/factory/stv/projektarbeit.js create mode 100644 public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit.js create mode 100644 public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Betreuung.js create mode 100644 public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Details.js create mode 100644 public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektarbeit.js diff --git a/application/controllers/api/frontend/v1/stv/Config.php b/application/controllers/api/frontend/v1/stv/Config.php index 455b1e8fc..dd2eaed02 100644 --- a/application/controllers/api/frontend/v1/stv/Config.php +++ b/application/controllers/api/frontend/v1/stv/Config.php @@ -123,6 +123,11 @@ class Config extends FHCAPI_Controller 'config' => $config['finalexam'] ]; + $result['projektarbeit'] = [ + 'title' => $this->p->t('stv', 'tab_projektarbeit'), + 'component' => './Stv/Studentenverwaltung/Details/Projektarbeit.js' + ]; + $result['mobility'] = [ 'title' => $this->p->t('stv', 'tab_mobility'), 'component' => './Stv/Studentenverwaltung/Details/Mobility.js' diff --git a/application/controllers/api/frontend/v1/stv/Projektarbeit.php b/application/controllers/api/frontend/v1/stv/Projektarbeit.php new file mode 100644 index 000000000..3be2b26a3 --- /dev/null +++ b/application/controllers/api/frontend/v1/stv/Projektarbeit.php @@ -0,0 +1,334 @@ + ['admin:r', 'assistenz:r'], + 'loadProjektarbeit' => ['admin:r', 'assistenz:r'], + 'insertProjektarbeit' => ['admin:rw', 'assistenz:rw'], + 'updateProjektarbeit' => ['admin:rw', 'assistenz:rw'], + 'deleteProjektarbeit' => ['admin:rw', 'assistenz:rw'], + 'getTypenProjektarbeit' => ['admin:r', 'assistenz:r'], + 'getFirmen' => ['admin:r', 'assistenz:r'], + 'getLehrveranstaltungen' => ['admin:r', 'assistenz:r'], + 'getNoten' => ['admin:rw', 'assistenz:rw'] + ]); + + // Load Libraries + $this->load->library('form_validation'); + + // Load language phrases + $this->loadPhrases([ + 'ui', + 'person', + 'projektarbeit' + ]); + + // Load models + $this->load->model('education/Projektarbeit_model', 'ProjektarbeitModel'); + $this->load->model('education/Projekttyp_model', 'ProjekttypModel'); + $this->load->model('education/Paabgabe_model', 'PaabgabeModel'); + $this->load->model('ressource/Firma_model', 'FirmaModel'); + $this->load->model('education/Lehrveranstaltung_model', 'LehrveranstaltungModel'); + $this->load->model('education/Lehreinheit_model', 'LehreinheitModel'); + $this->load->model('ressource/Mitarbeiter_model', 'MitarbeiterModel'); + $this->load->model('education/Note_model', 'NoteModel'); + $this->load->model('education/Projektbetreuer_model', 'BetreuerModel'); + + // load libraries + $this->load->library('PermissionLib'); + } + + public function getProjektarbeit() + { + $student_uid = $this->input->get('uid'); + + if (!isset($student_uid)) $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Student UID']), self::ERROR_TYPE_GENERAL); + + $result = $this->ProjektarbeitModel->getProjektarbeit($student_uid); + + if (isError($result)) + { + $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + } + + if (!hasData($result)) $this->terminateWithSuccess([]); + + $projektarbeiten = getData($result); + + foreach ($projektarbeiten as $projektarbeit) + { + $projektarbeit_id = $projektarbeit->projektarbeit_id; + $abgabeRes = $this->PaabgabeModel->getEndabgabe($projektarbeit_id); + + if (isError($abgabeRes)) $this->terminateWithError(getError($abgabeRes), self::ERROR_TYPE_GENERAL); + + if (hasData($abgabeRes)) + { + $paabgabe = getData($abgabeRes)[0]; + $projektarbeit->abgabedatum = $paabgabe->abgabedatum; + } + } + + $this->terminateWithSuccess($projektarbeiten); + } + + public function loadProjektarbeit() + { + $projektarbeit_id = $this->input->get('projektarbeit_id'); + + if (!isset($projektarbeit_id) || !is_numeric($projektarbeit_id)) return $this->terminateWithError('Projektarbeit Id missing', self::ERROR_TYPE_GENERAL); + + $this->ProjektarbeitModel->addSelect( + 'lehre.tbl_projektarbeit.projektarbeit_id, titel, titel_english, themenbereich, projekttyp_kurzbz, firma_id, + lehrveranstaltung_id, lehreinheit_id, beginn, note, final, freigegeben, tbl_projektarbeit.anmerkung, fa.name AS firma_name' + ); + $this->ProjektarbeitModel->addJoin('lehre.tbl_lehreinheit le', 'lehreinheit_id'); + $this->ProjektarbeitModel->addJoin('lehre.tbl_lehrveranstaltung lv', 'lehrveranstaltung_id'); + $this->ProjektarbeitModel->addJoin('public.tbl_firma fa', 'firma_id'); + $result = $this->ProjektarbeitModel->loadWhere( + array('projektarbeit_id' => $projektarbeit_id) + ); + + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess(current($data)); + } + + public function insertProjektarbeit() + { + $student_uid = $this->input->post('uid'); + + if (!$student_uid) return $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Student UID']), self::ERROR_TYPE_GENERAL); + + if (!$this->_hasBerechtigungForStudent($student_uid)) + return $this->_outputAuthError([$this->router->method => ['admin:rw', 'assistenz:rw']]); + + $formData = $this->input->post('formData'); + + $this->addMeta('form', $formData); + + if ($this->_validate($formData) == false) + { + $this->terminateWithValidationErrors($this->form_validation->error_array()); + } + + $result = $this->ProjektarbeitModel->insert( + array_merge($formData, ['insertamum' => date('c'), 'insertvon' => getAuthUID(), 'student_uid' => $student_uid]) + ); + + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + + public function updateProjektarbeit() + { + $projektarbeit_id = $this->input->post('projektarbeit_id'); + + if (!$projektarbeit_id || !is_numeric($projektarbeit_id)) + return $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Projektarbeit ID']), self::ERROR_TYPE_GENERAL); + + if (!$this->ProjektarbeitModel->hasBerechtigungForProjektarbeit($projektarbeit_id)) + return $this->_outputAuthError([$this->router->method => ['admin:rw', 'assistenz:rw']]); + + $formData = $this->input->post('formData'); + + if ($this->_validate($formData) == false) + { + $this->terminateWithValidationErrors($this->form_validation->error_array()); + } + + $result = $this->ProjektarbeitModel->update( + $projektarbeit_id, + array_merge($formData, ['updateamum' => date('c'), 'updatevon' => getAuthUID()]) + ); + + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + + public function deleteProjektarbeit() + { + $projektarbeit_id = $this->input->post('projektarbeit_id'); + + if (!isset($projektarbeit_id) || !is_numeric($projektarbeit_id)) + return $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Projektarbeit ID'], self::ERROR_TYPE_GENERAL)); + + if (!$this->ProjektarbeitModel->hasBerechtigungForProjektarbeit($projektarbeit_id)) + return $this->_outputAuthError([$this->router->method => ['admin:rw', 'assistenz:rw']]); + + $validate = $this->_validateDelete($projektarbeit_id); + + if (isError($validate)) return $this->terminateWithError(getError($validate), self::ERROR_TYPE_GENERAL); + + $result = $this->ProjektarbeitModel->delete( + array('projektarbeit_id' => $projektarbeit_id) + ); + + if (isError($result)) return $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + + if (!hasData($result)) + { + $this->outputJson($result); + } + + return $this->terminateWithSuccess(current(getData($result)) ? : null); + } + + public function getTypenProjektarbeit() + { + $result = $this->ProjekttypModel->loadWhere(['aktiv' => true]); + + if (isError($result)) return $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + + return $this->terminateWithSuccess(hasData($result) ? getData($result) : []); + } + + public function getFirmen() + { + $searchString = $this->input->get('searchString'); + + if (!isset($searchString)) $this->terminateWithError($this->p->t('projektarbeit', 'error_searchStringMissing', self::ERROR_TYPE_GENERAL)); + + $result = $this->FirmaModel->searchFirmen($searchString, $aktiv = true); + + if (isError($result)) return $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + + return $this->terminateWithSuccess(hasData($result) ? getData($result) : []); + } + + public function getLehrveranstaltungen() + { + $student_uid = $this->input->get('student_uid'); + $studiengang_kz = $this->input->get('studiengang_kz'); + $studiensemester_kurzbz = $this->input->get('studiensemester_kurzbz'); + $additional_lehrveranstaltung_id = $this->input->get('additional_lehrveranstaltung_id'); + + if (!isset($student_uid)) $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Student UID']), self::ERROR_TYPE_GENERAL); + if (!isset($studiensemester_kurzbz)) $this->terminateWithError('Studiensemster missing', self::ERROR_TYPE_GENERAL); + + $lvsResult = $this->LehrveranstaltungModel->getLvsForProjektarbeit($student_uid, $studiengang_kz, $additional_lehrveranstaltung_id); + + if (isError($lvsResult)) return $this->terminateWithError($lvsResult, self::ERROR_TYPE_GENERAL); + + $lvs = hasData($lvsResult) ? getData($lvsResult) : []; + + foreach ($lvs as $lv) + { + $lehreinheiten = $this->LehreinheitModel->getLesForLv( + $lv->lehrveranstaltung_id, $studiensemester_kurzbz + ); + + foreach ($lehreinheiten as $lehreinheit) + { + if (!isEmptyArray($lehreinheit->lektoren)) + { + $this->MitarbeiterModel->addSelect('kurzbz'); + $this->MitarbeiterModel->db->where_in('tbl_mitarbeiter.mitarbeiter_uid', $lehreinheit->lektoren); + $maResult = $this->MitarbeiterModel->load(); + + if (isError($maResult)) return $this->terminateWithError($lvsResult, self::ERROR_TYPE_GENERAL); + + $lehreinheit->lektoren = array_column(getData($maResult), 'kurzbz'); + } + } + + $lv->lehreinheiten = $lehreinheiten; + } + + return $this->terminateWithSuccess($lvs); + } + + public function getNoten() + { + $result = $this->NoteModel->load(); + + if (isError($result)) return $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + + return $this->terminateWithSuccess(hasData($result) ? getData($result) : []); + } + + /** + * + * @param + * @return object success or error + */ + private function _validate($formData) + { + $this->form_validation->set_data($formData); + + $this->form_validation->set_rules('titel', 'Titel', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Titel']) + ]); + + $this->form_validation->set_rules('projekttyp_kurzbz', 'Projekttyp', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Projekttyp']) + ]); + + $this->form_validation->set_rules('lehreinheit_id', 'Lehreinheit', 'required|numeric', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Lehreinheit']), + //'matches' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Lehreinheit']), + 'numeric' => $this->p->t('ui', 'error_fieldNotNumeric', ['field' => 'Lehreinheit']) + ]); + + $this->form_validation->set_rules('beginn', 'Beginn', 'is_valid_date', [ + 'is_valid_date' => $this->p->t('ui', 'error_notValidDate', ['field' => 'Beginn']) + ]); + + return $this->form_validation->run(); + } + + /** + * + * @param + * @return object success or error + */ + private function _validateDelete($projektarbeit_id) + { + $this->BetreuerModel->addSelect('1'); + $result = $this->BetreuerModel->loadWhere(['projektarbeit_id' => $projektarbeit_id]); + + if (isError($result)) return $result; + + if (hasData($result)) return error($this->p->t('projektarbeit', 'error_betreuerNichtGeloescht')); + + $this->PaabgabeModel->addSelect('1'); + $result = $this->PaabgabeModel->loadWhere(['projektarbeit_id' => $projektarbeit_id]); + + if (isError($result)) return $result; + + if (hasData($result)) return error($this->p->t('projektarbeit', 'error_paabgabeNichtGeloescht')); + + return success(); + } + + private function _hasBerechtigungForStudent($student_uid) + { + if (!$student_uid) + return false; + + $this->load->model('crm/Student_model', 'StudentModel'); + + $this->StudentModel->addSelect('studiengang_kz'); + $result = $this->StudentModel->load([$student_uid]); + if (isError($result) || !hasData($result)) + return false; + + $studiengang_kz = getData($result)[0]->studiengang_kz; + + if ($this->permissionlib->isBerechtigt('admin', 'suid', $studiengang_kz)) + return true; + if ($this->permissionlib->isBerechtigt('assistenz', 'suid', $studiengang_kz)) + return true; + + return false; + } +} diff --git a/application/models/education/Lehrveranstaltung_model.php b/application/models/education/Lehrveranstaltung_model.php index 056fb45d7..446e6e9cf 100644 --- a/application/models/education/Lehrveranstaltung_model.php +++ b/application/models/education/Lehrveranstaltung_model.php @@ -988,4 +988,61 @@ class Lehrveranstaltung_model extends DB_Model return $this->execQuery($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/application/models/education/Projektarbeit_model.php b/application/models/education/Projektarbeit_model.php index 109e23373..2be79f8e9 100644 --- a/application/models/education/Projektarbeit_model.php +++ b/application/models/education/Projektarbeit_model.php @@ -24,15 +24,17 @@ class Projektarbeit_model extends DB_Model public function getProjektarbeit($student_uid, $studiengang_kz = null, $studiensemester_kurzbz = null, $projekttyp = null, $final = null) { $qry = "SELECT - tbl_projektarbeit.* , tbl_projekttyp.bezeichnung + tbl_projektarbeit.*, tbl_projekttyp.bezeichnung, + tbl_lehreinheit.studiensemester_kurzbz, tbl_lehrveranstaltung.lehrveranstaltung_id, + tbl_firma.name AS firma_name FROM lehre.tbl_projektarbeit JOIN - lehre.tbl_projekttyp USING (projekttyp_kurzbz), lehre.tbl_lehreinheit, lehre.tbl_lehrveranstaltung - + lehre.tbl_projekttyp USING (projekttyp_kurzbz), lehre.tbl_lehreinheit, lehre.tbl_lehrveranstaltung, public.tbl_firma WHERE tbl_projektarbeit.lehreinheit_id=tbl_lehreinheit.lehreinheit_id AND tbl_lehreinheit.lehrveranstaltung_id = tbl_lehrveranstaltung.lehrveranstaltung_id AND + tbl_projektarbeit.firma_id = tbl_firma.firma_id AND tbl_projektarbeit.student_uid = ?"; $params = array($student_uid); @@ -69,4 +71,30 @@ class Projektarbeit_model extends DB_Model return $this->execQuery($qry, $params); } + + /** + * + * @param + * @return object success or error + */ + public function hasBerechtigungForProjektarbeit($projektarbeit_id) + { + if (!$projektarbeit_id || !is_numeric($projektarbeit_id)) + return false; + + $this->ProjektarbeitModel->addSelect('studiengang_kz'); + $this->ProjektarbeitModel->addJoin('public.tbl_student', 'student_uid'); + $result = $this->ProjektarbeitModel->load($projektarbeit_id); + if (isError($result) || !hasData($result)) + return false; + + $studiengang_kz = getData($result)[0]->studiengang_kz; + + if ($this->permissionlib->isBerechtigt('admin', 'suid', $studiengang_kz)) + return true; + if ($this->permissionlib->isBerechtigt('assistenz', 'suid', $studiengang_kz)) + return true; + + return false; + } } diff --git a/application/models/ressource/Firma_model.php b/application/models/ressource/Firma_model.php index 431f0815f..5ae53eeaf 100644 --- a/application/models/ressource/Firma_model.php +++ b/application/models/ressource/Firma_model.php @@ -12,17 +12,24 @@ class Firma_model extends DB_Model $this->pk = 'firma_id'; } - public function searchFirmen($filter) + public function searchFirmen($filter, $aktiv = null) { + $params = []; $filter = strtoLower($filter); $qry = " - SELECT + SELECT f.name, f.firma_id - FROM - public.tbl_firma f - WHERE - lower (f.name) LIKE '%". $this->db->escape_like_str($filter)."%'"; + FROM + public.tbl_firma f + WHERE + lower (f.name) LIKE '%". $this->db->escape_like_str($filter)."%'"; - return $this->execQuery($qry); + if (isset($aktiv) && is_bool($aktiv)) + { + $params[] = $aktiv; + $qry .= " AND aktiv = ?"; + } + + return $this->execQuery($qry, $params); } } diff --git a/public/js/api/factory/stv/projektarbeit.js b/public/js/api/factory/stv/projektarbeit.js new file mode 100644 index 000000000..243383de0 --- /dev/null +++ b/public/js/api/factory/stv/projektarbeit.js @@ -0,0 +1,80 @@ +/** + * Copyright (C) 2025 fhcomplete.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +export default { + getProjektarbeit(uid) { + return { + method: 'get', + url: 'api/frontend/v1/stv/projektarbeit/getProjektarbeit', + params: { uid } + }; + }, + getTypenProjektarbeit() { + return { + method: 'get', + url: 'api/frontend/v1/stv/projektarbeit/getTypenProjektarbeit' + }; + }, + getFirmen(searchString) { + return { + method: 'get', + url: 'api/frontend/v1/stv/projektarbeit/getFirmen', + params: {searchString} + }; + }, + getLehrveranstaltungen(student_uid, studiengang_kz, studiensemester_kurzbz, additional_lehrveranstaltung_id) { + return { + method: 'get', + url: 'api/frontend/v1/stv/projektarbeit/getLehrveranstaltungen', + params: { student_uid, studiengang_kz, studiensemester_kurzbz, additional_lehrveranstaltung_id } + }; + }, + getNoten() { + return { + method: 'get', + url: 'api/frontend/v1/stv/projektarbeit/getNoten' + }; + }, + loadProjektarbeit(projektarbeit_id) { + return { + method: 'get', + url: 'api/frontend/v1/stv/projektarbeit/loadProjektarbeit', + params: { projektarbeit_id } + }; + }, + addNewProjektarbeit(params) { + return { + method: 'post', + url: 'api/frontend/v1/stv/projektarbeit/insertProjektarbeit', + params + }; + }, + updateProjektarbeit(params) { + return { + method: 'post', + url: 'api/frontend/v1/stv/projektarbeit/updateProjektarbeit', + params + }; + }, + deleteProjektarbeit(projektarbeit_id) { + return { + method: 'post', + url: 'api/frontend/v1/stv/projektarbeit/deleteProjektarbeit', + params: { projektarbeit_id } + }; + } +}; \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit.js b/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit.js new file mode 100644 index 000000000..3615e8f5d --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit.js @@ -0,0 +1,24 @@ +import Projektarbeit from './Projektarbeit/Projektarbeit.js'; + +export default { + name: "TabProjektarbeit", + components: { + Projektarbeit + }, + provide() { + return { + config: this.config + }; + }, + props: { + modelValue: Object, + config: Object + }, + data(){ + return {} + }, + template: ` +
+ +
` +}; \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Betreuung.js b/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Betreuung.js new file mode 100644 index 000000000..5d223d694 --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Betreuung.js @@ -0,0 +1,847 @@ +import {CoreFilterCmpt} from "../../../../filter/Filter.js"; +import FormForm from '../../../../Form/Form.js'; +import FormInput from '../../../../Form/Input.js'; +import PvAutoComplete from "../../../../../../../index.ci.php/public/js/components/primevue/autocomplete/autocomplete.esm.min.js"; + +import ApiStvAbschlusspruefung from '../../../../../api/factory/stv/abschlusspruefung.js'; + +export default { + components: { + CoreFilterCmpt, + BsModal, + FormForm, + FormInput, + PvAutoComplete, + AbschlusspruefungDropdown, + PruefungList + }, + inject: { + cisRoot: { + from: 'cisRoot' + }, + config: { + from: 'config', + required: true + }, + $reloadList: { + from: '$reloadList', + required: true + }, + isBerechtigtDocAndOdt: { + from: 'hasPermissionOutputformat', + default: false + } + }, + computed: { + studentUids() { + if (this.student.uid) + { + return [this.student.uid]; + } + return this.student.map(e => e.uid); + }, + studentKzs(){ + if (this.student.uid) + { + return [this.student.studiengang_kz]; + } + return this.student.map(e => e.studiengang_kz); + }, + stg_kz(){ + return this.studentKzs[0]; + }, + }, + props: { + student: Object + }, + data() { + return { + tabulatorOptions: { + ajaxURL: 'dummy', + ajaxRequestFunc: () => this.$api.call(ApiStvAbschlusspruefung.getAbschlusspruefung(this.student.uid)), + ajaxResponse: (url, params, response) => response.data, + columns: [ + {title: "vorsitz", field: "vorsitz_nachname"}, + {title: "abschlussbeurteilung", field: "beurteilung_bezeichnung"}, + {title: "prueferIn1", field: "p1_nachname", visible: false}, + {title: "prueferIn2", field: "p2_nachname", visible: false}, + {title: "prueferIn3", field: "p3_nachname", visible: false}, + { + title: "datum", + field: "datum", + formatter: function (cell) { + const dateStr = cell.getValue(); + if (!dateStr) return ""; + + const date = new Date(dateStr); + return date.toLocaleString("de-DE", { + day: "2-digit", + month: "2-digit", + year: "numeric", + hour12: false + }); + } + }, + {title: "uhrzeit", field: "uhrzeit"}, + { + title: "freigabe", + field: "freigabedatum", + formatter: function (cell) { + const dateStr = cell.getValue(); + if (!dateStr) return ""; + + const date = new Date(dateStr); + return date.toLocaleString("de-DE", { + day: "2-digit", + month: "2-digit", + year: "numeric", + hour12: false + }); + } + }, + {title: "pruefungsantritt", field: "antritt_bezeichnung"}, + { + title: "sponsion", + field: "sponsion", + formatter: function (cell) { + const dateStr = cell.getValue(); + if (!dateStr) return ""; + + const date = new Date(dateStr); + return date.toLocaleString("de-DE", { + day: "2-digit", + month: "2-digit", + year: "numeric", + hour12: false + }); + } + }, + {title: "anmerkung", field: "anmerkung"}, + {title: "abschlusspruefung_id", field: "abschlusspruefung_id", visible: false}, + {title: "typ", field: "pruefungstyp_kurzbz", visible: false}, + + { + title: 'Aktionen', field: 'actions', + minWidth: 150, // Ensures Action-buttons will be always fully displayed + formatter: (cell, formatterParams, onRendered) => { + let container = document.createElement('div'); + container.className = "d-flex gap-2"; + + let button = document.createElement('button'); + button.className = 'btn btn-outline-secondary btn-action'; + button.innerHTML = ''; + button.title = this.$p.t('ui', 'bearbeiten'); + button.addEventListener('click', (event) => + this.actionEditAbschlusspruefung(cell.getData().abschlusspruefung_id) + ); + container.append(button); + + button = document.createElement('button'); + button.className = 'btn btn-outline-secondary btn-action'; + button.innerHTML = ''; + button.title = this.$p.t('ui', 'loeschen'); + button.addEventListener('click', () => + this.actionDeleteAbschlusspruefung(cell.getData().abschlusspruefung_id) + ); + container.append(button); + + container.append(cell.getData().actionDiv); + + return container; + }, + frozen: true + }, + ], + layout: 'fitDataFill', + layoutColumnsOnNewData: false, + height: 'auto', + minHeight: '200', + selectable: true, + index: 'abschlusspruefung_id', + persistenceID: 'stv-details-finalexam' + }, + 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', 'abschlusspruefung', 'ui']); + + + let cm = this.$refs.table.tabulator.columnManager; + + cm.getColumnByField('vorsitz_nachname').component.updateDefinition({ + title: this.$p.t('abschlusspruefung', 'vorsitz_header') + }); + cm.getColumnByField('beurteilung_bezeichnung').component.updateDefinition({ + title: this.$p.t('abschlusspruefung', 'abschlussbeurteilung') + }); + cm.getColumnByField('p1_nachname').component.updateDefinition({ + title: this.$p.t('abschlusspruefung', 'pruefer1') + }); + cm.getColumnByField('p2_nachname').component.updateDefinition({ + title: this.$p.t('abschlusspruefung', 'pruefer2') + }); + cm.getColumnByField('p3_nachname').component.updateDefinition({ + title: this.$p.t('abschlusspruefung', 'pruefer3') + }); + cm.getColumnByField('datum').component.updateDefinition({ + title: this.$p.t('global', 'datum') + }); + cm.getColumnByField('uhrzeit').component.updateDefinition({ + title: this.$p.t('global', 'uhrzeit') + }); + cm.getColumnByField('freigabedatum').component.updateDefinition({ + title: this.$p.t('abschlusspruefung', 'freigabe') + }); + cm.getColumnByField('antritt_bezeichnung').component.updateDefinition({ + title: this.$p.t('abschlusspruefung', 'pruefungsantritt') + }); + cm.getColumnByField('sponsion').component.updateDefinition({ + title: this.$p.t('abschlusspruefung', 'sponsion') + }); + cm.getColumnByField('anmerkung').component.updateDefinition({ + title: this.$p.t('global', 'anmerkung') + }); + cm.getColumnByField('pruefungstyp_kurzbz').component.updateDefinition({ + title: this.$p.t('global', 'typ') + }); + cm.getColumnByField('abschlusspruefung_id').component.updateDefinition({ + title: this.$p.t('ui', 'abschlusspruefung_id') + }); + /* + cm.getColumnByField('actions').component.updateDefinition({ + title: this.$p.t('global', 'aktionen') + }); + */ + } + } + ], + tabulatorData: [], + lastSelected: null, + formData: { + typStg: null, + pruefungstyp_kurzbz: null, + akadgrad_id: null, + vorsitz: null, + pruefungsantritt_kurzbz: null, + abschlussbeurteilung_kurzbz: null, + datum: null, + sponsion: null, + pruefer1: null, + pruefer2: null, + pruefer3: null, + anmerkung: null, + protokoll: null, + note: null, + link: null + }, + statusNew: true, + arrTypen: [], + arrAntritte: [], + arrBeurteilungen: [], + arrAkadGrad: [], + arrNoten: [], + filteredMitarbeiter: [], + filteredPruefer: [], + abortController: { + mitarbeiter: null, + pruefer: null + }, + stgInfo: { typ: '', oe_kurzbz: '' } + } + }, + watch: { + student(){ + if (this.$refs.table) { + this.$refs.table.reloadTable(); + } + this.getStudiengangByKz(); + } + }, + methods: { + getStudiengangByKz(){ + this.stgInfo = { typ: '', oe_kurzbz: '' }; + this.$api + .call(ApiStudiengang.getStudiengangByKz(this.stg_kz)) + .then(result => this.stgInfo = result.data) + .catch(this.$fhcAlert.handleSystemError); + }, + actionNewAbschlusspruefung() { + this.resetForm(); + this.statusNew = true; + this.$refs.finalexamModal.show(); + this.setDefaultFormData(); + }, + actionEditAbschlusspruefung(abschlusspruefung_id) { + this.resetForm(); + this.statusNew = false; + this.$refs.finalexamModal.show(); + this.loadAbschlusspruefung(abschlusspruefung_id); + }, + actionDeleteAbschlusspruefung(abschlusspruefung_id) { + this.$fhcAlert + .confirmDelete() + .then(result => result + ? abschlusspruefung_id + : Promise.reject({handled: true})) + .then(this.deleteAbschlusspruefung) + .catch(this.$fhcAlert.handleSystemError); + }, + addNewAbschlusspruefung() { + const dataToSend = { + uid: this.student.uid, + formData: this.formData + }; + + return this.$refs.formFinalExam + .call(ApiStvAbschlusspruefung.addNewAbschlusspruefung(dataToSend)) + .then(response => { + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSave')); + this.hideModal('finalexamModal'); + this.resetForm(); + }) + .catch(this.$fhcAlert.handleSystemError) + .finally(() => { + this.reload(); + }); + }, + hideModal(modalRef){ + this.$refs[modalRef].hide(); + }, + reload() { + this.$refs.table.reloadTable(); + }, + loadAbschlusspruefung(abschlusspruefung_id) { + return this.$api + .call(ApiStvAbschlusspruefung.loadAbschlusspruefung(abschlusspruefung_id)) + .then(result => { + this.formData = result.data; + //TODO(Manu) check if cisRoot is okay + this.formData.link = this.cisRoot + 'index.ci.php/lehre/Pruefungsprotokoll/showProtokoll?abschlusspruefung_id=' + this.formData.abschlusspruefung_id + '&fhc_controller_id=67481e5ed5490'; + return result; + }) + .catch(this.$fhcAlert.handleSystemError); + }, + updateAbschlusspruefung(abschlusspruefung_id) { + const dataToSend = { + id: abschlusspruefung_id, + formData: this.formData + }; + return this.$refs.formFinalExam + .call(ApiStvAbschlusspruefung.updateAbschlusspruefung(dataToSend)) + .then(response => { + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSave')); + this.hideModal('finalexamModal'); + this.resetForm(); + }) + .catch(this.$fhcAlert.handleSystemError) + .finally(() => { + this.reload(); + }); + }, + deleteAbschlusspruefung(abschlusspruefung_id) { + return this.$api + .call(ApiStvAbschlusspruefung.deleteAbschlusspruefung(abschlusspruefung_id)) + .then(response => { + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successDelete')); + }) + .catch(this.$fhcAlert.handleSystemError) + .finally(() => { + this.reload(); + }); + }, + resetForm() { + this.formData.pruefungstyp_kurzbz = null; + this.formData.akadgrad_id = null; + this.formData.vorsitz = null; + this.formData.pruefungsantritt_kurzbz = null; + this.formData.abschlussbeurteilung_kurzbz = null; + this.formData.datum = null; //oder new Date(); + this.formData.sponsion = null; + this.formData.pruefer1 = null; + this.formData.pruefer2 = null; + this.formData.pruefer3 = null; + this.formData.anmerkung = null; + this.formData.protokoll = null; + this.formData.note = null; + this.formData.p1 = null; + this.formData.p2 = null; + this.formData.p3 = null; + this.formData.pv = null; + }, + search(event) { + if (this.abortController.mitarbeiter) { + this.abortController.mitarbeiter.abort(); + } + this.abortController.mitarbeiter = new AbortController(); + + return this.$api + .call(ApiStvAbschlusspruefung.getMitarbeiter(event.query)) + .then(result => { + this.filteredMitarbeiter = result.data.retval; + }); + }, + searchNotAkad(event) { + if (this.abortController.pruefer) { + this.abortController.pruefer.abort(); + } + this.abortController.pruefer = new AbortController(); + + return this.$api + .call(ApiStvAbschlusspruefung.getPruefer(event.query)) + .then(result => { + this.filteredPruefer = result.data.retval; + }); + }, + setDefaultFormData() { + + this.resetForm(); + + if (this.stgInfo.typ === 'b') { + this.formData.pruefungstyp_kurzbz = 'Bachelor'; + this.formData.protokoll = this.$p.t('abschlusspruefung', 'pruefungsnotizenMaster'); + } + if (this.stgInfo.typ === 'd' || this.stgInfo === 'm') { + this.formData.pruefungstyp_kurzbz = 'Diplom'; + this.formData.protokoll = this.$p.t('abschlusspruefung', 'pruefungsnotizenMaster'); + } + if (this.stgInfo.typ === 'lg') { + this.formData.pruefungstyp_kurzbz = 'lgabschluss'; + } + + if (!this.formData.akadgrad_id && this.arrAkadGrad.length > 0) { + this.formData.akadgrad_id = this.arrAkadGrad[0].akadgrad_id; + } + }, + printDocument(link) { + window.open(link, '_blank'); + }, + }, + created() { + this.$api + .call(ApiStvAbschlusspruefung.getTypenAbschlusspruefung()) + .then(result => { + this.arrTypen = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + + this.$api + .call(ApiStvAbschlusspruefung.getTypenAntritte()) + .then(result => { + this.arrAntritte = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + + this.$api + .call(ApiStvAbschlusspruefung.getBeurteilungen()) + .then(result => { + this.arrBeurteilungen = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + + this.$api + .call(ApiStvAbschlusspruefung.getNoten()) + .then(result => { + this.arrNoten = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + + this.$api + .call(ApiStvAbschlusspruefung.getAkadGrade(this.student.studiengang_kz)) + .then(result => { + this.arrAkadGrad = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + if (!this.student.length) { + this.$api + .call(ApiStudiengang.getStudiengangByKz(this.student.studiengang_kz)) + .then(result => { + this.stgInfo = result.data; + this.setDefaultFormData(); + }) + .catch(this.$fhcAlert.handleSystemError); + } else + this.getStudiengangByKz(); + }, + template: ` +
+

{{this.$p.t('stv','tab_finalexam')}}

+ +
+ +
+ + + + + + + + + + + + + {{this.$p.t('global','details')}} +

[{{$p.t('ui', 'neu')}}]

+
+ + + + + + + +
+ +
+ + + + +
+ +
+ + + + + +
+ +
+ + + + + + + +
+ +
+ + + + + +
+ +
+ + + + +
+ +
+ + + + +
+ +
+
+

{{$p.t('abschlusspruefung', 'zurBeurteilung')}}

+
+ +
+ +
+ + + +
+ + + + +
+` +} diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Details.js b/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Details.js new file mode 100644 index 000000000..a6256ceb1 --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Details.js @@ -0,0 +1,461 @@ +import {CoreFilterCmpt} from "../../../../filter/Filter.js"; +import FormForm from '../../../../Form/Form.js'; +import FormInput from '../../../../Form/Input.js'; +import PvAutoComplete from "../../../../../../../index.ci.php/public/js/components/primevue/autocomplete/autocomplete.esm.min.js"; + +import ApiStvProjektarbeit from '../../../../../api/factory/stv/projektarbeit.js'; + +export default { + components: { + CoreFilterCmpt, + FormForm, + FormInput, + PvAutoComplete + }, + emits: ['details-saved'], + inject: { + defaultSemester: { + from: 'defaultSemester' + } + //~ cisRoot: { + //~ from: 'cisRoot' + //~ }, + //~ config: { + //~ from: 'config', + //~ required: true + //~ } + }, + computed: { + arrLes() { + let lehreinheiten = []; + if (this.formData.lehrveranstaltung_id) { + let lv = this.arrLvs.find(lv => {return lv.lehrveranstaltung_id == this.formData.lehrveranstaltung_id}); + if (lv) lehreinheiten = lv.lehreinheiten + } + + for (let le of lehreinheiten) + { + let bezeichnung = le.lehrfach_kurzbz + '-' + le.lehrform_kurzbz + ' ' + le.lehrfach_bezeichnung + ' '; + + for (let grp of le.lehreinheitgruppen) + { + bezeichnung += grp.gruppe_kurzbz ? grp.gruppe_kurzbz : '' + grp.semester ?? '' + grp.verband ?? '' + grp.gruppe ?? ''; + } + + bezeichnung += ' (' + le.lektoren.join(' ') + ') ID: ' + le.lehreinheit_id; + + le.bezeichnung = bezeichnung; + } + + return lehreinheiten; + }, + //~ preparedFormData() { + //~ console.log("FOR DATA CALLEd"); + //~ if (this.formData.projektarbeit_id == null) delete(this.formData.projektarbeit_id); + //~ if (this.formData.firma) this.formData.firma_id = this.formData.firma.firma_id; + //~ delete(this.formData.firma); + //~ delete(this.formData.firma_name); + //~ delete(this.formData.lehrveranstaltung_id); + //~ // convert null value fields from string to null + //~ return this.formData; + //~ } + }, + props: { + statusNew: Boolean, + student: Object, + projektarbeit: Object, + stg_kz: Number + }, + data() { + return { + formData: { + projektarbeit_id: null, + titel: null, + titel_english: null, + themenbereich: null, + projekttyp_kurzbz: null, + firma: null, + lehrveranstaltung_id: null, + lehreinheit_id: null, + beginn: null, + ende: null, + freigegeben: true, + gesperrtbis: null, + note: null, + final: true, + anmerkung: null + }, + arrTypen: [], + arrFirmen: [], + arrLvs: [], + arrNoten: [], + filteredFirmen: [], + abortController: { + firma: null + } + } + }, + methods: { + resetForm() { + this.formData.projektarbeit_id = null; + this.formData.titel = null; + this.formData.titel_english = null; + this.formData.themenbereich = null; + this.formData.projekttyp_kurzbz = null; + this.formData.firma = null; + this.formData.lehrveranstaltung_id = null; + this.formData.lehreinheit_id = null; + this.formData.beginn = null; + this.formData.ende = null; + this.formData.freigegeben = true; + this.formData.gesperrtbis = null; + this.formData.note = null; + this.formData.final = true; + this.formData.anmerkung = null; + }, + getFormData(statusNew, studiensemester_kurzbz, additional_lehrveranstaltung_id/*, successCallback*/) { + + //~ let callArray = [ + //~ this.$api.call(ApiStvProjektarbeit.getTypenProjektarbeit()), + //~ this.$api.call(ApiStvProjektarbeit.getLehrveranstaltungen( + //~ this.student.uid, + //~ projektarbeit_id ? null : this.student.studiengang_kz, + //~ studiensemester_kurzbz ?? this.defaultSemester, + //~ additional_lehrveranstaltung_id ?? null + //~ )), + //~ this.$api.call(ApiStvProjektarbeit.getNoten()) + //~ ]; + + //~ if (projektarbeit_id) callArray.push(this.$api.call(ApiStvProjektarbeit.loadProjektarbeit(projektarbeit_id))); + + //~ // Run when All promises are settled + //~ Promise.allSettled(callArray).then((results) => { + //~ let hasError = false; + //~ let allFormData = []; + //~ results.forEach((promise_result) => { + + //~ if (promise_result.status === 'fulfilled' && promise_result.value.meta.status === "success") { + //~ allFormData.push(promise_result.value.data); + //~ } else { + //~ hasError = true; + //~ //this.$fhcAlert.handleSystemError(promise_result); + //~ } + //~ //let data = promise_result.value.data; + //~ console.log(promise_result.status); + //~ }); + + //~ if (!hasError) { + //~ this.setFormData(allFormData[0], allFormData[1], allFormData[2], allFormData[3], allFormData[4] ?? null); + //~ if (successCallback) successCallback(); + //~ } + //~ }); + + this.$api + .call(ApiStvProjektarbeit.getTypenProjektarbeit()) + .then(result => { + this.arrTypen = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + + this.$api + .call(ApiStvProjektarbeit.getLehrveranstaltungen( + this.student.uid, + statusNew ? this.student.studiengang_kz : null, + studiensemester_kurzbz ?? this.defaultSemester, + additional_lehrveranstaltung_id + )) + .then(result => { + this.arrLvs = result.data + } + ) + .catch(this.$fhcAlert.handleSystemError); + + this.$api + .call(ApiStvProjektarbeit.getNoten()) + .then(result => { + this.arrNoten = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + }, + setFormData(arrTypen, arrLvs, arrNoten, projektarbeitData) { + this.arrTypen = arrTypen; + this.arrLvs = arrLvs; + this.arrNoten = arrNoten; + if (projektarbeitData) { + projektarbeitData.firma = {firma_id: projektarbeitData.firma_id, name: projektarbeitData.firma_name}; + this.formData = projektarbeitData; + } + }, + loadProjektarbeit(projektarbeit_id) { + + return this.$api + .call(ApiStvProjektarbeit.loadProjektarbeit(projektarbeit_id)) + .then(result => { + this.formData = result.data; + return result; + }) + .catch(this.$fhcAlert.handleSystemError) + }, + addNewProjektarbeit() { + + let dataToSend = { + uid: this.student.uid, + formData: this.getPreparedFormData() + }; + + return this.$refs.formDetails + .call(ApiStvProjektarbeit.addNewProjektarbeit(dataToSend)); + }, + updateProjektarbeit() { + + let dataToSend = { + projektarbeit_id: this.formData.projektarbeit_id, + formData: this.getPreparedFormData() + }; + return this.$refs.formDetails + .call(ApiStvProjektarbeit.updateProjektarbeit(dataToSend)); + }, + searchFirma(event) { + if (this.abortController.firma) { + this.abortController.firma.abort(); + } + this.abortController.firma = new AbortController(); + + return this.$api + .call(ApiStvProjektarbeit.getFirmen(event.query)) + .then(result => { + this.filteredFirmen = result.data; + }); + }, + lvChanged(event) { + this.formData.lehreinheit_id = null; + }, + getPreparedFormData() { + let preparedFormData = JSON.parse(JSON.stringify(this.formData)); // deep copy + + // delete "helper" fields + if (preparedFormData.projektarbeit_id == null) delete(preparedFormData.projektarbeit_id); + if (preparedFormData.firma) preparedFormData.firma_id = preparedFormData.firma.firma_id; + delete(preparedFormData.firma); + delete(preparedFormData.firma_name); + delete(preparedFormData.lehrveranstaltung_id); + + return preparedFormData; + } + //~ setDefaultFormData() { + //~ this.resetForm(); + //~ }, + }, + template: ` + + + {{this.$p.t('global','details')}} +

[{{$p.t('ui', 'neu')}}]

+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + + +
+ + +
+ + + +
+ +
+ + + + +
+ +
+ + + + +
+ +
+ + + + +
+ +
+ + +
+ + +
+
+ +
+ + + + +
+ + +
+
+ +
+ + +
+ +
` +} diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektarbeit.js b/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektarbeit.js new file mode 100644 index 000000000..034b3fd6c --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektarbeit.js @@ -0,0 +1,377 @@ +import {CoreFilterCmpt} from "../../../../filter/Filter.js"; +import BsModal from "../../../../Bootstrap/Modal.js"; +import FormForm from '../../../../Form/Form.js'; +import FormInput from '../../../../Form/Input.js'; +import PvAutoComplete from "../../../../../../../index.ci.php/public/js/components/primevue/autocomplete/autocomplete.esm.min.js"; + + +import ApiStvProjektarbeit from '../../../../../api/factory/stv/projektarbeit.js'; +import ProjektarbeitDetails from "./Details.js"; + +export default { + components: { + CoreFilterCmpt, + BsModal, + FormForm, + FormInput, + PvAutoComplete, + ProjektarbeitDetails + }, + inject: { + cisRoot: { + from: 'cisRoot' + }, + config: { + from: 'config', + required: true + }, + $reloadList: { + from: '$reloadList', + required: true + }, + isBerechtigtDocAndOdt: { + from: 'hasPermissionOutputformat', + default: false + } + }, + computed: { + //~ studentUids() { + //~ if (this.student.uid) + //~ { + //~ return [this.student.uid]; + //~ } + //~ return this.student.map(e => e.uid); + //~ }, + studentKzs(){ + if (this.student.uid) + { + return [this.student.studiengang_kz]; + } + return this.student.map(e => e.studiengang_kz); + }, + stg_kz(){ + return this.studentKzs.length > 0 ? this.studentKzs.length[0] : null; + } + }, + props: { + student: Object + }, + data() { + return { + tabulatorOptions: { + ajaxURL: 'dummy', + ajaxRequestFunc: () => this.$api.call(ApiStvProjektarbeit.getProjektarbeit(this.student.uid)), + ajaxResponse: (url, params, response) => response.data, + columns: [ + {title: "Projektarbeit ID", field: "projektarbeit_id", visible: false}, + {title: "Typ", field: "projekttyp_kurzbz"}, + {title: "Studiensemester", field: "studiensemester_kurzbz"}, + {title: "Titel", field: "titel"}, + { + title: "Abgabe Enduplad", + field: "abgabedatum", + formatter: function (cell) { + const dateStr = cell.getValue(); + if (!dateStr) return ""; + + const date = new Date(dateStr); + return date.toLocaleString("de-DE", { + day: "2-digit", + month: "2-digit", + year: "numeric", + hour12: false + }); + } + }, + { + title: "Beginn", + field: "beginn", + formatter: function (cell) { + const dateStr = cell.getValue(); + if (!dateStr) return ""; + + const date = new Date(dateStr); + return date.toLocaleString("de-DE", { + day: "2-digit", + month: "2-digit", + year: "numeric", + hour12: false + }); + }, + visible: false + }, + { + title: "Ende", + field: "ende", + formatter: function (cell) { + const dateStr = cell.getValue(); + if (!dateStr) return ""; + + const date = new Date(dateStr); + return date.toLocaleString("de-DE", { + day: "2-digit", + month: "2-digit", + year: "numeric", + hour12: false + }); + }, + visible: false + }, + { + title:"Freigegeben", + field:"freigegeben", + formatter:"tickCross", + hozAlign:"center", + formatterParams: { + tickElement: '', + crossElement: '' + }, + visible: false + }, + { + title: "Gesperrt bis", + field: "gesperrtbis", + formatter: function (cell) { + const dateStr = cell.getValue(); + if (!dateStr) return ""; + + const date = new Date(dateStr); + return date.toLocaleString("de-DE", { + day: "2-digit", + month: "2-digit", + year: "numeric", + hour12: false + }); + }, + visible: false + }, + {title: "Themenbereich", field: "themenbereich", visible: false}, + {title: "Anmerkung", field: "anmerkung", visible: false}, + {title: "Lehreinheit ID", field: "lehreinheit_id", visible: false}, + {title: "Student UID", field: "student_uid", visible: false}, + { + title:"Final", + field:"final", + formatter:"tickCross", + hozAlign:"center", + formatterParams: { + tickElement: '', + crossElement: '' + }, + visible: false + }, + {title: "Firma ID", field: "firma_id", visible: false}, + { + title: 'Aktionen', field: 'actions', + minWidth: 150, // Ensures Action-buttons will be always fully displayed + formatter: (cell, formatterParams, onRendered) => { + let container = document.createElement('div'); + container.className = "d-flex gap-2"; + + let button = document.createElement('button'); + button.className = 'btn btn-outline-secondary btn-action'; + button.innerHTML = ''; + 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); + }); + container.append(button); + + button = document.createElement('button'); + button.className = 'btn btn-outline-secondary btn-action'; + button.innerHTML = ''; + button.title = this.$p.t('ui', 'loeschen'); + button.addEventListener('click', () => + this.actionDeleteProjektarbeit(cell.getData().projektarbeit_id) + ); + container.append(button); + + container.append(cell.getData().actionDiv); + + return container; + }, + frozen: true + }, + ], + layout: 'fitDataFill', + layoutColumnsOnNewData: false, + height: 'auto', + minHeight: '200', + selectable: 1, + index: 'projektarbeit_id', + 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']); + + + let cm = this.$refs.table.tabulator.columnManager; + + //~ cm.getColumnByField('vorsitz_nachname').component.updateDefinition({ + //~ title: this.$p.t('abschlusspruefung', 'vorsitz_header') + //~ }); + /* + cm.getColumnByField('actions').component.updateDefinition({ + title: this.$p.t('global', 'aktionen') + }); + */ + } + }, + ], + tabulatorData: [], + lastSelected: null, + statusNew: true, + studiensemester_kurzbz: null, + lehrveranstaltung_id: null + } + }, + //~ watch: { + //~ student(){ + //~ if (this.$refs.table) { + //~ this.$refs.table.reloadTable(); + //~ } + //~ this.getStudiengangByKz(); + //~ } + //~ }, + methods: { + actionNewProjektarbeit() { + this.statusNew = true; + this.$refs.projektarbeitDetails.resetForm(); + this.$refs.projektarbeitDetails.getFormData(); + this.$refs.projektarbeitModal.show(); + }, + actionEditProjektarbeit(projektarbeit_id, studiensemester_kurzbz, lehrveranstaltung_id) { + this.statusNew = false; + this.$refs.projektarbeitDetails.getFormData(this.statusNew, studiensemester_kurzbz, lehrveranstaltung_id); + this.$refs.projektarbeitDetails.loadProjektarbeit(projektarbeit_id); + this.$refs.projektarbeitModal.show(); + }, + actionDeleteProjektarbeit(projektarbeit_id) { + this.$fhcAlert + .confirmDelete() + .then(result => result + ? projektarbeit_id + : Promise.reject({handled: true})) + .then(this.deleteProjektarbeit) + .catch(this.$fhcAlert.handleSystemError); + }, + addNewProjektarbeit() { + Promise.allSettled([ + this.$refs.projektarbeitDetails.addNewProjektarbeit() + ]).then((results) => { + let hasError = false; + results.forEach((promise_result) => { + + if (!(promise_result.status === 'fulfilled' && promise_result.value.meta.status === "success")) { + + hasError = true; + } + }); + + if (!hasError) { + this.projektarbeitSaved(); + } + }); + }, + updateProjektarbeit() { + Promise.allSettled( + [ + this.$refs.projektarbeitDetails.updateProjektarbeit() + ]).then((results) => { + let hasError = false; + results.forEach((promise_result) => { + + if (!(promise_result.status === 'fulfilled' && promise_result.value.meta.status === "success")) { + + hasError = true; + } + }); + + if (!hasError) { + this.projektarbeitSaved(); + } + }); + }, + deleteProjektarbeit(projektarbeit_id) { + return this.$api + .call(ApiStvProjektarbeit.deleteProjektarbeit(projektarbeit_id)) + .then(response => { + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successDelete')); + }) + .catch(this.$fhcAlert.handleSystemError) + .finally(() => { + this.reload(); + }); + }, + projektarbeitSaved() { + this.reload(); + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSave')); + this.hideModal('projektarbeitModal'); + this.$refs.projektarbeitDetails.resetForm(); + }, + rowSelectionChanged(data) { + console.log("selection changed"); + this.lastSelected = data.length > 0 ? data[0] : null; + }, + hideModal(modalRef){ + this.$refs[modalRef].hide(); + }, + reload() { + this.$refs.table.reloadTable(); + } + }, + created() { + }, + template: ` +
+

{{this.$p.t('stv','tab_projektarbeit')}}

+ + + + + + + + + + + + + +
+` +} + From 382006aa8bfdec7696256d2b2236eb448003daf7 Mon Sep 17 00:00:00 2001 From: Alexei Karpenko Date: Fri, 16 May 2025 13:37:21 +0200 Subject: [PATCH 02/27] Projektarbeit Studierendenverwaltung: now possible to save and edit Projektbetreuer --- application/config/stv.php | 7 +- .../api/frontend/v1/stv/Config.php | 5 +- .../api/frontend/v1/stv/Projektarbeit.php | 11 +- .../api/frontend/v1/stv/Projektbetreuer.php | 333 +++++++ .../models/education/Projektarbeit_model.php | 9 +- .../education/Projektbetreuer_model.php | 1 + application/models/person/Person_model.php | 19 +- .../models/ressource/Stundensatz_model.php | 95 +- public/js/api/factory/stv/projektbetreuer.js | 73 ++ .../Details/Projektarbeit/Betreuung.js | 847 ------------------ .../Details/Projektarbeit/Details.js | 27 +- .../Details/Projektarbeit/Projektarbeit.js | 86 +- .../Details/Projektarbeit/Projektbetreuer.js | 421 +++++++++ system/phrasesupdate.php | 2 +- 14 files changed, 1002 insertions(+), 934 deletions(-) create mode 100644 application/controllers/api/frontend/v1/stv/Projektbetreuer.php create mode 100644 public/js/api/factory/stv/projektbetreuer.js delete mode 100644 public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Betreuung.js create mode 100644 public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektbetreuer.js diff --git a/application/config/stv.php b/application/config/stv.php index 31ce3f521..f5c1599ab 100644 --- a/application/config/stv.php +++ b/application/config/stv.php @@ -54,7 +54,7 @@ $config['tabs'] = ], ] ]; - + // List of fields to show when ZGV_DOKTOR_ANZEIGEN is defined $fieldsZgvDoktor = ['zgvdoktorort', 'zgvdoktordatum', 'zgvdoktornation', 'zgvdoktor_erfuellt', 'zgvdoktor_code']; @@ -74,3 +74,8 @@ if (!defined('ZGV_DOKTOR_ANZEIGEN') || !ZGV_DOKTOR_ANZEIGEN) { $fieldsZgvDoktor ); } + +$config['tabs']['projektarbeit']['defaultProjektbetreuerStunden'] = '4.0'; +$config['tabs']['projektarbeit']['defaultProjektbetreuerStundenDiplom'] = '5.0'; +$config['tabs']['projektarbeit']['lvLektroinnenzuteilungFixangestelltStundensatz'] = true; +$config['tabs']['projektarbeit']['defaultProjektbetreuerStundensatz'] = '80.0'; diff --git a/application/controllers/api/frontend/v1/stv/Config.php b/application/controllers/api/frontend/v1/stv/Config.php index dd2eaed02..afdf8efb8 100644 --- a/application/controllers/api/frontend/v1/stv/Config.php +++ b/application/controllers/api/frontend/v1/stv/Config.php @@ -125,7 +125,8 @@ class Config extends FHCAPI_Controller $result['projektarbeit'] = [ 'title' => $this->p->t('stv', 'tab_projektarbeit'), - 'component' => './Stv/Studentenverwaltung/Details/Projektarbeit.js' + 'component' => './Stv/Studentenverwaltung/Details/Projektarbeit.js', + 'config' => $config['projektarbeit'] ]; $result['mobility'] = [ @@ -323,7 +324,7 @@ class Config extends FHCAPI_Controller $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" . diff --git a/application/controllers/api/frontend/v1/stv/Projektarbeit.php b/application/controllers/api/frontend/v1/stv/Projektarbeit.php index 3be2b26a3..70775fdbc 100644 --- a/application/controllers/api/frontend/v1/stv/Projektarbeit.php +++ b/application/controllers/api/frontend/v1/stv/Projektarbeit.php @@ -17,7 +17,7 @@ class Projektarbeit extends FHCAPI_Controller 'getTypenProjektarbeit' => ['admin:r', 'assistenz:r'], 'getFirmen' => ['admin:r', 'assistenz:r'], 'getLehrveranstaltungen' => ['admin:r', 'assistenz:r'], - 'getNoten' => ['admin:rw', 'assistenz:rw'] + 'getNoten' => ['admin:r', 'assistenz:r'] ]); // Load Libraries @@ -91,7 +91,7 @@ class Projektarbeit extends FHCAPI_Controller ); $this->ProjektarbeitModel->addJoin('lehre.tbl_lehreinheit le', 'lehreinheit_id'); $this->ProjektarbeitModel->addJoin('lehre.tbl_lehrveranstaltung lv', 'lehrveranstaltung_id'); - $this->ProjektarbeitModel->addJoin('public.tbl_firma fa', 'firma_id'); + $this->ProjektarbeitModel->addJoin('public.tbl_firma fa', 'firma_id', 'LEFT'); $result = $this->ProjektarbeitModel->loadWhere( array('projektarbeit_id' => $projektarbeit_id) ); @@ -170,7 +170,7 @@ class Projektarbeit extends FHCAPI_Controller if (isError($validate)) return $this->terminateWithError(getError($validate), self::ERROR_TYPE_GENERAL); $result = $this->ProjektarbeitModel->delete( - array('projektarbeit_id' => $projektarbeit_id) + ['projektarbeit_id' => $projektarbeit_id] ); if (isError($result)) return $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); @@ -273,10 +273,9 @@ class Projektarbeit extends FHCAPI_Controller 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Projekttyp']) ]); - $this->form_validation->set_rules('lehreinheit_id', 'Lehreinheit', 'required|numeric', [ + $this->form_validation->set_rules('lehreinheit_id', 'Lehreinheit', 'required|is_natural', [ 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Lehreinheit']), - //'matches' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Lehreinheit']), - 'numeric' => $this->p->t('ui', 'error_fieldNotNumeric', ['field' => 'Lehreinheit']) + 'is_natural' => $this->p->t('ui', 'error_fieldNotNumeric', ['field' => 'Lehreinheit']) ]); $this->form_validation->set_rules('beginn', 'Beginn', 'is_valid_date', [ diff --git a/application/controllers/api/frontend/v1/stv/Projektbetreuer.php b/application/controllers/api/frontend/v1/stv/Projektbetreuer.php new file mode 100644 index 000000000..ac6663132 --- /dev/null +++ b/application/controllers/api/frontend/v1/stv/Projektbetreuer.php @@ -0,0 +1,333 @@ + ['admin:r', 'assistenz:r'], + 'saveProjektbetreuer' => ['admin:rw', 'assistenz:rw'], + 'deleteProjektbetreuer' => ['admin:rw', 'assistenz:rw'], + 'getBetreuerarten' => ['admin:r', 'assistenz:r'], + 'getNoten' => ['admin:r', 'assistenz:r'], + 'getDefaultStundensaetze' => ['admin:r', 'assistenz:r'], + 'getProjektbetreuerBySearchQuery' => ['admin:r', 'assistenz:r'], + 'validateProjektbetreuer' => ['admin:r', 'assistenz:r'] + ]); + + // Load Libraries + $this->load->library('form_validation'); + + // Load language phrases + $this->loadPhrases([ + 'ui', + 'person', + 'projektarbeit' + ]); + + // Load models + $this->load->model('education/Projektbetreuer_model', 'ProjektbetreuerModel'); + $this->load->model('education/Betreuerart_model', 'BetreuerartModel'); + $this->load->model('ressource/Stundensatz_model', 'StundensatzModel'); + $this->load->model('education/Projektarbeit_model', 'ProjektarbeitModel'); + $this->load->model('education/Note_model', 'NoteModel'); + $this->load->model('person/Person_model', 'PersonModel'); + + // load libraries + $this->load->library('PermissionLib'); + } + + public function getProjektbetreuer() + { + $projektarbeit_id = $this->input->get('projektarbeit_id'); + + if (!isset($projektarbeit_id)) $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Projektarbeit ID']), self::ERROR_TYPE_GENERAL); + + $this->ProjektbetreuerModel->addSelect( + 'projektarbeit_id, person_id, nachname, vorname, note, punkte, stunden, stundensatz, betreuerart_kurzbz, vertrag_id, titelpre, titelpost' + ); + $this->ProjektbetreuerModel-> addSelect("CASE + WHEN EXISTS + (SELECT 1 FROM public.tbl_benutzer JOIN public.tbl_mitarbeiter ON(uid=mitarbeiter_uid) WHERE person_id=pers.person_id) + THEN 'Mitarbeiter' + WHEN EXISTS + (SELECT 1 FROM public.tbl_benutzer JOIN public.tbl_student ON(uid=student_uid) WHERE person_id=pers.person_id) + THEN 'Student' + ELSE 'Person' + END AS status"); + $this->ProjektbetreuerModel->addJoin('public.tbl_person pers', 'person_id'); + $result = $this->ProjektbetreuerModel->loadWhere(['projektarbeit_id' => $projektarbeit_id]); + + if (isError($result)) $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + + if (!hasData($result)) $this->terminateWithSuccess([]); + + $projektbetreuer = getData($result); + + //~ foreach ($projektbetreuer as $projektarbeit) + //~ { + //~ $projektarbeit_id = $projektarbeit->projektarbeit_id; + //~ $abgabeRes = $this->PaabgabeModel->getEndabgabe($projektarbeit_id); + + //~ if (isError($abgabeRes)) $this->terminateWithError(getError($abgabeRes), self::ERROR_TYPE_GENERAL); + + //~ if (hasData($abgabeRes)) + //~ { + //~ $paabgabe = getData($abgabeRes)[0]; + //~ $projektarbeit->abgabedatum = $paabgabe->abgabedatum; + //~ } + //~ } + + $this->terminateWithSuccess($this->_addFullNameToBetreuer($projektbetreuer)); + } + + public function saveProjektbetreuer() + { + $projektarbeit_id = $this->input->post('projektarbeit_id'); + + if (!isset($projektarbeit_id) || !is_numeric($projektarbeit_id)) + return $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Projektarbeit ID']), self::ERROR_TYPE_GENERAL); + + if (!$this->ProjektarbeitModel->hasBerechtigungForProjektarbeit($projektarbeit_id)) + return $this->_outputAuthError([$this->router->method => ['admin:rw', 'assistenz:rw']]); + + $projektbetreuer = $this->input->post('projektbetreuerListe'); + + //$this->addMeta('form', $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->addMeta('test', 'foisch'); + $this->terminateWithValidationErrors($this->form_validation->error_array()); + } + } + + $result = null; + + foreach ($projektbetreuer as $pb) + { + //~ $this->addMeta('form', $pb); + //~ error_log(print_r($pb, true)); + //die(); + + //~ $this->ProjektbetreuerModel->addSelect('1'); + //~ $checkResult = $this->ProjektbetreuerModel->loadWhere( + //~ ['person_id' => $pb['person_id'], 'projektarbeit_id' => $projektarbeit_id, 'betreuerart_kurzbz' => $pb['betreuerart_kurzbz']] + //~ ); + + //~ if (isError($checkResult)) $this->terminateWithError(getError($checkResult), self::ERROR_TYPE_GENERAL); + + $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); + } + + $this->terminateWithSuccess(hasData($result) ? getData($result) : []); + } + + public function deleteProjektbetreuer() + { + $projektarbeit_id = $this->input->post('projektarbeit_id'); + $person_id = $this->input->post('person_id'); + $betreuerart_kurzbz = $this->input->post('betreuerart_kurzbz'); + + if (!isset($projektarbeit_id) || !is_numeric($projektarbeit_id)) + return $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Projektbetreuer ID'], self::ERROR_TYPE_GENERAL)); + + if (!isset($person_id) || !is_numeric($person_id)) + return $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Person ID'], self::ERROR_TYPE_GENERAL)); + + if (!isset($betreuerart_kurzbz)) + return $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Betreuerart'], self::ERROR_TYPE_GENERAL)); + + if (!$this->ProjektarbeitModel->hasBerechtigungForProjektarbeit($projektarbeit_id)) + return $this->_outputAuthError([$this->router->method => ['admin:rw', 'assistenz:rw']]); + + $validate = $this->_validateDelete($projektarbeit_id, $person_id); + + if (isError($validate)) return $this->terminateWithError(getError($validate), self::ERROR_TYPE_GENERAL); + + $result = $this->ProjektbetreuerModel->delete( + ['projektarbeit_id' => $projektarbeit_id, 'person_id' => $person_id, 'betreuerart_kurzbz' => $betreuerart_kurzbz] + ); + + if (isError($result)) return $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + + if (!hasData($result)) + { + $this->outputJson($result); + } + + return $this->terminateWithSuccess(current(getData($result)) ? : null); + } + + public function getBetreuerarten() + { + $result = $this->BetreuerartModel->loadWhere(['aktiv' => true]); + + if (isError($result)) return $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + + return $this->terminateWithSuccess(hasData($result) ? getData($result) : []); + } + + public function getNoten() + { + $result = $this->NoteModel->load(); + + if (isError($result)) return $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + + return $this->terminateWithSuccess(hasData($result) ? getData($result) : []); + } + + public function getDefaultStundensaetze() + { + $person_id = $this->input->get('person_id'); + $studiensemester_kurzbz = $this->input->get('studiensemester_kurzbz'); + + $result = $this->StundensatzModel->getStundensatzForMitarbeiter($person_id, $studiensemester_kurzbz); + + $this->addMeta('res', $result); + + //if (isError($result)) return $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + + return $this->terminateWithSuccess($result); + } + + public function getProjektbetreuerBySearchQuery() + { + $searchString = $this->input->get('searchString'); + + if (!isset($searchString)) $this->terminateWithError($this->p->t('projektarbeit', 'error_searchStringMissing', self::ERROR_TYPE_GENERAL)); + + $result = $this->PersonModel->searchPerson($searchString); + + $this->addMeta('met', $result); + + if (isError($result)) return $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + + return $this->terminateWithSuccess(hasData($result) ? $this->_addFullNameToBetreuer(getData($result)) : []); + } + + /** + * + * @param + * @return object success or error + */ + public function validateProjektbetreuer() + { + $projektbetreuerArr = $this->input->post('projektbetreuer'); + + if (!is_array($projektbetreuerArr)) $projektbetreuerArr = [$projektbetreuerArr]; + + foreach ($projektbetreuerArr as $pb) + { + if ($this->_validate($pb) == false) + { + $this->terminateWithValidationErrors($this->form_validation->error_array()); + } + } + + $this->terminateWithSuccess([]); + } + + /** + * + * @param + * @return object success or error + */ + private function _validate($formData) + { + $this->form_validation->set_data($formData); + + $this->form_validation->set_rules('betreuerart_kurzbz', 'Betreuerart', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Betreuerart']) + ]); + + $this->form_validation->set_rules('person_id', 'Person', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Person ID']) + ]); + + $this->form_validation->set_rules('stunden', 'Stunden', 'numeric', [ + 'numeric' => $this->p->t('ui', 'error_fieldNotNumeric', ['field' => 'Stunden']) + ]); + + $this->form_validation->set_rules('stundensatz', 'Stundensatz', 'numeric', [ + 'numeric' => $this->p->t('ui', 'error_fieldNotNumeric', ['field' => 'Stundensatz']) + ]); + + + return $this->form_validation->run(); + } + + /** + * + * @param + * @return object success or error + */ + private function _validateDelete($projektarbeit_id, $person_id) + { + $this->ProjektbetreuerModel->addSelect('vertrag_id'); + $result = $this->ProjektbetreuerModel->loadWhere(['projektarbeit_id' => $projektarbeit_id, 'person_id' => $person_id]); + + if (isError($result)) return $result; + + if (hasData($result) && getData($result)[0]->vertrag_id != null) return error($this->p->t('projektarbeit', 'error_betreuerHatVertrag')); + + return success(); + } + + /** + * + * @param + * @return object success or error + */ + private function _addFullNameToBetreuer($betreuerArr) + { + foreach ($betreuerArr as $betreuer) + { + $betreuer->name = ($betreuer->titelpre ? $betreuer->titelpre . ' ' : '') . + $betreuer->nachname . ' ' . $betreuer->vorname . ($betreuer->titelpost ? ' ' . $betreuer->titelpre : ''). + ' (' . $betreuer->status . ')'; + } + + return $betreuerArr; + } +} diff --git a/application/models/education/Projektarbeit_model.php b/application/models/education/Projektarbeit_model.php index 2be79f8e9..357886de1 100644 --- a/application/models/education/Projektarbeit_model.php +++ b/application/models/education/Projektarbeit_model.php @@ -29,12 +29,11 @@ class Projektarbeit_model extends DB_Model tbl_firma.name AS firma_name FROM lehre.tbl_projektarbeit - JOIN - lehre.tbl_projekttyp USING (projekttyp_kurzbz), lehre.tbl_lehreinheit, lehre.tbl_lehrveranstaltung, public.tbl_firma + JOIN lehre.tbl_projekttyp USING (projekttyp_kurzbz) + JOIN lehre.tbl_lehreinheit USING (lehreinheit_id) + JOIN lehre.tbl_lehrveranstaltung USING (lehrveranstaltung_id) + LEFT JOIN public.tbl_firma USING (firma_id) WHERE - tbl_projektarbeit.lehreinheit_id=tbl_lehreinheit.lehreinheit_id AND - tbl_lehreinheit.lehrveranstaltung_id = tbl_lehrveranstaltung.lehrveranstaltung_id AND - tbl_projektarbeit.firma_id = tbl_firma.firma_id AND tbl_projektarbeit.student_uid = ?"; $params = array($student_uid); diff --git a/application/models/education/Projektbetreuer_model.php b/application/models/education/Projektbetreuer_model.php index 95950bf95..02368ae21 100644 --- a/application/models/education/Projektbetreuer_model.php +++ b/application/models/education/Projektbetreuer_model.php @@ -10,6 +10,7 @@ class Projektbetreuer_model extends DB_Model parent::__construct(); $this->dbTable = 'lehre.tbl_projektbetreuer'; $this->pk = array('betreuerart_kurzbz', 'projektarbeit_id', 'person_id'); + $this->hasSequence = false; } /** diff --git a/application/models/person/Person_model.php b/application/models/person/Person_model.php index 997048972..d955f6401 100644 --- a/application/models/person/Person_model.php +++ b/application/models/person/Person_model.php @@ -151,12 +151,21 @@ class Person_model extends DB_Model */ public function searchPerson($filter) { - $this->addSelect('vorname, nachname, gebdatum, person_id'); + $this->addSelect('vorname, nachname, gebdatum, person_id, titelpre, titelpost'); + $this->addSelect("CASE + WHEN EXISTS + (SELECT 1 FROM public.tbl_benutzer JOIN public.tbl_mitarbeiter ON(uid=mitarbeiter_uid) WHERE person_id=tbl_person.person_id) + THEN 'Mitarbeiter' + WHEN EXISTS + (SELECT 1 FROM public.tbl_benutzer JOIN public.tbl_student ON(uid=student_uid) WHERE person_id=tbl_person.person_id) + THEN 'Student' + ELSE 'Person' + END AS status"); $result = $this->loadWhere( - 'lower(nachname) like '.$this->db->escape('%'.$filter.'%')." + 'lower(nachname) like '.$this->db->escape('%'.mb_strtolower($filter).'%')." OR lower(vorname) like ".$this->db->escape('%'.$filter.'%')." - OR lower(nachname || ' ' || vorname) like ".$this->db->escape('%'.$filter.'%')." - OR lower(vorname || ' ' || nachname) like ".$this->db->escape('%'.$filter.'%') + OR lower(nachname || ' ' || vorname) like ".$this->db->escape('%'.mb_strtolower($filter).'%')." + OR lower(vorname || ' ' || nachname) like ".$this->db->escape('%'.mb_strtolower($filter).'%') ); return $result; @@ -423,4 +432,4 @@ class Person_model extends DB_Model return success($result); } } -} \ No newline at end of file +} diff --git a/application/models/ressource/Stundensatz_model.php b/application/models/ressource/Stundensatz_model.php index 10f5a6aa1..9d41dfbd9 100644 --- a/application/models/ressource/Stundensatz_model.php +++ b/application/models/ressource/Stundensatz_model.php @@ -2,7 +2,7 @@ class Stundensatz_model extends DB_Model { - + /** * Constructor */ @@ -42,4 +42,95 @@ class Stundensatz_model extends DB_Model return $this->execQuery($qry, $params); } -} \ No newline at end of file + + public function getStundensatzForMitarbeiter($person_id, $studiensemester_kurzbz) + { + $this->load->config('stv'); + + $useFixangestelltStundensatz = $this->config->item('tabs')['projektarbeit']['lvLektroinnenzuteilungFixangestelltStundensatz']; + $defaultStundensatz = $this->config->item('tabs')['projektarbeit']['defaultProjektbetreuerStundensatz']; + + $stundensatz = ''; + + if(isset($person_id) && isset($studiensemester_kurzbz)) + { + $this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel'); + + $this->StudiensemesterModel->addSelect('start, ende'); + $result = $this->StudiensemesterModel->load($studiensemester_kurzbz); + + if (hasData($result)) + { + $studiensemester = getData($result)[0]; + + if (isset($useFixangestelltStundensatz) && !$useFixangestelltStundensatz) + { + // load Mitarbeiter + $params = [$person_id]; + $qry = " + SELECT + mitarbeiter_uid, fixangestellt + FROM + public.tbl_mitarbeiter + JOIN public.tbl_benutzer ON(tbl_benutzer.uid=tbl_mitarbeiter.mitarbeiter_uid) + WHERE + person_id=? + ORDER BY + tbl_mitarbeiter.insertamum DESC NULLS LAST + LIMIT 1"; + + $result = $this->execQuery($qry, $params); + + if (hasData($result)) + { + foreach (getData($result) as $ma) + { + if (!$ma->fixangestellt) + { + $stundensatzRes = $this->getStundensatzByDatum( + $ma->mitarbeiter_uid, $studiensemester->start, $studiensemester->ende, 'lehre' + ); + + if (hasData($stundensatzRes)) + $stundensatz = getData($stundensatzRes)[0]->stundensatz; + else + $stundensatz = '0.00'; + } + } + } + else + { + $stundensatz = '0.00'; + } + + } + else + { + $params = [$person_id, $studiensemester->ende, $studiensemester->start]; + $qry = "SELECT ss.stundensatz + FROM hr.tbl_stundensatz ss + JOIN public.tbl_mitarbeiter ON ss.uid = tbl_mitarbeiter.mitarbeiter_uid + JOIN public.tbl_benutzer ON(tbl_benutzer.uid=tbl_mitarbeiter.mitarbeiter_uid) + WHERE person_id=? + AND stundensatztyp = 'lehre' + AND gueltig_von <= ? + AND (gueltig_bis >= ? OR gueltig_bis IS NULL) + ORDER BY gueltig_bis DESC NULLS FIRST, gueltig_von DESC NULLS LAST LIMIT 1"; + + $result = $this->execQuery($qry, $params); + + if (hasData($result)) + { + $stundensatz = getData($result)[0]->stundensatz; + } + else + { + $stundensatz = $defaultStundensatz; + } + } + } + } + + return $stundensatz; + } +} diff --git a/public/js/api/factory/stv/projektbetreuer.js b/public/js/api/factory/stv/projektbetreuer.js new file mode 100644 index 000000000..fc710fe81 --- /dev/null +++ b/public/js/api/factory/stv/projektbetreuer.js @@ -0,0 +1,73 @@ +/** + * Copyright (C) 2025 fhcomplete.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +export default { + getProjektbetreuer(projektarbeit_id ) { + return { + method: 'get', + url: 'api/frontend/v1/stv/projektbetreuer/getProjektbetreuer', + params: { projektarbeit_id } + }; + }, + getBetreuerarten() { + return { + method: 'get', + url: 'api/frontend/v1/stv/projektbetreuer/getBetreuerarten' + }; + }, + getDefaultStundensaetze(person_id, studiensemester_kurzbz) { + return { + method: 'get', + url: 'api/frontend/v1/stv/projektbetreuer/getDefaultStundensaetze', + params: { person_id, studiensemester_kurzbz } + }; + }, + getNoten() { + return { + method: 'get', + url: 'api/frontend/v1/stv/projektbetreuer/getNoten' + }; + }, + saveProjektbetreuer(projektarbeit_id, projektbetreuerListe) { + return { + method: 'post', + url: 'api/frontend/v1/stv/projektbetreuer/saveProjektbetreuer', + params: { projektarbeit_id, projektbetreuerListe } + }; + }, + deleteProjektbetreuer(projektarbeit_id, person_id, betreuerart_kurzbz) { + return { + method: 'post', + url: 'api/frontend/v1/stv/projektbetreuer/deleteProjektbetreuer', + params: { projektarbeit_id, person_id, betreuerart_kurzbz } + }; + }, + getProjektbetreuerBySearchQuery(searchString) { + return { + method: 'get', + url: 'api/frontend/v1/stv/projektbetreuer/getProjektbetreuerBySearchQuery', + params: { searchString } + }; + }, + validateProjektbetreuer(projektbetreuer) { + return { + method: 'post', + url: 'api/frontend/v1/stv/projektbetreuer/validateProjektbetreuer', + params: { projektbetreuer } + }; + } +}; diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Betreuung.js b/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Betreuung.js deleted file mode 100644 index 5d223d694..000000000 --- a/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Betreuung.js +++ /dev/null @@ -1,847 +0,0 @@ -import {CoreFilterCmpt} from "../../../../filter/Filter.js"; -import FormForm from '../../../../Form/Form.js'; -import FormInput from '../../../../Form/Input.js'; -import PvAutoComplete from "../../../../../../../index.ci.php/public/js/components/primevue/autocomplete/autocomplete.esm.min.js"; - -import ApiStvAbschlusspruefung from '../../../../../api/factory/stv/abschlusspruefung.js'; - -export default { - components: { - CoreFilterCmpt, - BsModal, - FormForm, - FormInput, - PvAutoComplete, - AbschlusspruefungDropdown, - PruefungList - }, - inject: { - cisRoot: { - from: 'cisRoot' - }, - config: { - from: 'config', - required: true - }, - $reloadList: { - from: '$reloadList', - required: true - }, - isBerechtigtDocAndOdt: { - from: 'hasPermissionOutputformat', - default: false - } - }, - computed: { - studentUids() { - if (this.student.uid) - { - return [this.student.uid]; - } - return this.student.map(e => e.uid); - }, - studentKzs(){ - if (this.student.uid) - { - return [this.student.studiengang_kz]; - } - return this.student.map(e => e.studiengang_kz); - }, - stg_kz(){ - return this.studentKzs[0]; - }, - }, - props: { - student: Object - }, - data() { - return { - tabulatorOptions: { - ajaxURL: 'dummy', - ajaxRequestFunc: () => this.$api.call(ApiStvAbschlusspruefung.getAbschlusspruefung(this.student.uid)), - ajaxResponse: (url, params, response) => response.data, - columns: [ - {title: "vorsitz", field: "vorsitz_nachname"}, - {title: "abschlussbeurteilung", field: "beurteilung_bezeichnung"}, - {title: "prueferIn1", field: "p1_nachname", visible: false}, - {title: "prueferIn2", field: "p2_nachname", visible: false}, - {title: "prueferIn3", field: "p3_nachname", visible: false}, - { - title: "datum", - field: "datum", - formatter: function (cell) { - const dateStr = cell.getValue(); - if (!dateStr) return ""; - - const date = new Date(dateStr); - return date.toLocaleString("de-DE", { - day: "2-digit", - month: "2-digit", - year: "numeric", - hour12: false - }); - } - }, - {title: "uhrzeit", field: "uhrzeit"}, - { - title: "freigabe", - field: "freigabedatum", - formatter: function (cell) { - const dateStr = cell.getValue(); - if (!dateStr) return ""; - - const date = new Date(dateStr); - return date.toLocaleString("de-DE", { - day: "2-digit", - month: "2-digit", - year: "numeric", - hour12: false - }); - } - }, - {title: "pruefungsantritt", field: "antritt_bezeichnung"}, - { - title: "sponsion", - field: "sponsion", - formatter: function (cell) { - const dateStr = cell.getValue(); - if (!dateStr) return ""; - - const date = new Date(dateStr); - return date.toLocaleString("de-DE", { - day: "2-digit", - month: "2-digit", - year: "numeric", - hour12: false - }); - } - }, - {title: "anmerkung", field: "anmerkung"}, - {title: "abschlusspruefung_id", field: "abschlusspruefung_id", visible: false}, - {title: "typ", field: "pruefungstyp_kurzbz", visible: false}, - - { - title: 'Aktionen', field: 'actions', - minWidth: 150, // Ensures Action-buttons will be always fully displayed - formatter: (cell, formatterParams, onRendered) => { - let container = document.createElement('div'); - container.className = "d-flex gap-2"; - - let button = document.createElement('button'); - button.className = 'btn btn-outline-secondary btn-action'; - button.innerHTML = ''; - button.title = this.$p.t('ui', 'bearbeiten'); - button.addEventListener('click', (event) => - this.actionEditAbschlusspruefung(cell.getData().abschlusspruefung_id) - ); - container.append(button); - - button = document.createElement('button'); - button.className = 'btn btn-outline-secondary btn-action'; - button.innerHTML = ''; - button.title = this.$p.t('ui', 'loeschen'); - button.addEventListener('click', () => - this.actionDeleteAbschlusspruefung(cell.getData().abschlusspruefung_id) - ); - container.append(button); - - container.append(cell.getData().actionDiv); - - return container; - }, - frozen: true - }, - ], - layout: 'fitDataFill', - layoutColumnsOnNewData: false, - height: 'auto', - minHeight: '200', - selectable: true, - index: 'abschlusspruefung_id', - persistenceID: 'stv-details-finalexam' - }, - 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', 'abschlusspruefung', 'ui']); - - - let cm = this.$refs.table.tabulator.columnManager; - - cm.getColumnByField('vorsitz_nachname').component.updateDefinition({ - title: this.$p.t('abschlusspruefung', 'vorsitz_header') - }); - cm.getColumnByField('beurteilung_bezeichnung').component.updateDefinition({ - title: this.$p.t('abschlusspruefung', 'abschlussbeurteilung') - }); - cm.getColumnByField('p1_nachname').component.updateDefinition({ - title: this.$p.t('abschlusspruefung', 'pruefer1') - }); - cm.getColumnByField('p2_nachname').component.updateDefinition({ - title: this.$p.t('abschlusspruefung', 'pruefer2') - }); - cm.getColumnByField('p3_nachname').component.updateDefinition({ - title: this.$p.t('abschlusspruefung', 'pruefer3') - }); - cm.getColumnByField('datum').component.updateDefinition({ - title: this.$p.t('global', 'datum') - }); - cm.getColumnByField('uhrzeit').component.updateDefinition({ - title: this.$p.t('global', 'uhrzeit') - }); - cm.getColumnByField('freigabedatum').component.updateDefinition({ - title: this.$p.t('abschlusspruefung', 'freigabe') - }); - cm.getColumnByField('antritt_bezeichnung').component.updateDefinition({ - title: this.$p.t('abschlusspruefung', 'pruefungsantritt') - }); - cm.getColumnByField('sponsion').component.updateDefinition({ - title: this.$p.t('abschlusspruefung', 'sponsion') - }); - cm.getColumnByField('anmerkung').component.updateDefinition({ - title: this.$p.t('global', 'anmerkung') - }); - cm.getColumnByField('pruefungstyp_kurzbz').component.updateDefinition({ - title: this.$p.t('global', 'typ') - }); - cm.getColumnByField('abschlusspruefung_id').component.updateDefinition({ - title: this.$p.t('ui', 'abschlusspruefung_id') - }); - /* - cm.getColumnByField('actions').component.updateDefinition({ - title: this.$p.t('global', 'aktionen') - }); - */ - } - } - ], - tabulatorData: [], - lastSelected: null, - formData: { - typStg: null, - pruefungstyp_kurzbz: null, - akadgrad_id: null, - vorsitz: null, - pruefungsantritt_kurzbz: null, - abschlussbeurteilung_kurzbz: null, - datum: null, - sponsion: null, - pruefer1: null, - pruefer2: null, - pruefer3: null, - anmerkung: null, - protokoll: null, - note: null, - link: null - }, - statusNew: true, - arrTypen: [], - arrAntritte: [], - arrBeurteilungen: [], - arrAkadGrad: [], - arrNoten: [], - filteredMitarbeiter: [], - filteredPruefer: [], - abortController: { - mitarbeiter: null, - pruefer: null - }, - stgInfo: { typ: '', oe_kurzbz: '' } - } - }, - watch: { - student(){ - if (this.$refs.table) { - this.$refs.table.reloadTable(); - } - this.getStudiengangByKz(); - } - }, - methods: { - getStudiengangByKz(){ - this.stgInfo = { typ: '', oe_kurzbz: '' }; - this.$api - .call(ApiStudiengang.getStudiengangByKz(this.stg_kz)) - .then(result => this.stgInfo = result.data) - .catch(this.$fhcAlert.handleSystemError); - }, - actionNewAbschlusspruefung() { - this.resetForm(); - this.statusNew = true; - this.$refs.finalexamModal.show(); - this.setDefaultFormData(); - }, - actionEditAbschlusspruefung(abschlusspruefung_id) { - this.resetForm(); - this.statusNew = false; - this.$refs.finalexamModal.show(); - this.loadAbschlusspruefung(abschlusspruefung_id); - }, - actionDeleteAbschlusspruefung(abschlusspruefung_id) { - this.$fhcAlert - .confirmDelete() - .then(result => result - ? abschlusspruefung_id - : Promise.reject({handled: true})) - .then(this.deleteAbschlusspruefung) - .catch(this.$fhcAlert.handleSystemError); - }, - addNewAbschlusspruefung() { - const dataToSend = { - uid: this.student.uid, - formData: this.formData - }; - - return this.$refs.formFinalExam - .call(ApiStvAbschlusspruefung.addNewAbschlusspruefung(dataToSend)) - .then(response => { - this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSave')); - this.hideModal('finalexamModal'); - this.resetForm(); - }) - .catch(this.$fhcAlert.handleSystemError) - .finally(() => { - this.reload(); - }); - }, - hideModal(modalRef){ - this.$refs[modalRef].hide(); - }, - reload() { - this.$refs.table.reloadTable(); - }, - loadAbschlusspruefung(abschlusspruefung_id) { - return this.$api - .call(ApiStvAbschlusspruefung.loadAbschlusspruefung(abschlusspruefung_id)) - .then(result => { - this.formData = result.data; - //TODO(Manu) check if cisRoot is okay - this.formData.link = this.cisRoot + 'index.ci.php/lehre/Pruefungsprotokoll/showProtokoll?abschlusspruefung_id=' + this.formData.abschlusspruefung_id + '&fhc_controller_id=67481e5ed5490'; - return result; - }) - .catch(this.$fhcAlert.handleSystemError); - }, - updateAbschlusspruefung(abschlusspruefung_id) { - const dataToSend = { - id: abschlusspruefung_id, - formData: this.formData - }; - return this.$refs.formFinalExam - .call(ApiStvAbschlusspruefung.updateAbschlusspruefung(dataToSend)) - .then(response => { - this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSave')); - this.hideModal('finalexamModal'); - this.resetForm(); - }) - .catch(this.$fhcAlert.handleSystemError) - .finally(() => { - this.reload(); - }); - }, - deleteAbschlusspruefung(abschlusspruefung_id) { - return this.$api - .call(ApiStvAbschlusspruefung.deleteAbschlusspruefung(abschlusspruefung_id)) - .then(response => { - this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successDelete')); - }) - .catch(this.$fhcAlert.handleSystemError) - .finally(() => { - this.reload(); - }); - }, - resetForm() { - this.formData.pruefungstyp_kurzbz = null; - this.formData.akadgrad_id = null; - this.formData.vorsitz = null; - this.formData.pruefungsantritt_kurzbz = null; - this.formData.abschlussbeurteilung_kurzbz = null; - this.formData.datum = null; //oder new Date(); - this.formData.sponsion = null; - this.formData.pruefer1 = null; - this.formData.pruefer2 = null; - this.formData.pruefer3 = null; - this.formData.anmerkung = null; - this.formData.protokoll = null; - this.formData.note = null; - this.formData.p1 = null; - this.formData.p2 = null; - this.formData.p3 = null; - this.formData.pv = null; - }, - search(event) { - if (this.abortController.mitarbeiter) { - this.abortController.mitarbeiter.abort(); - } - this.abortController.mitarbeiter = new AbortController(); - - return this.$api - .call(ApiStvAbschlusspruefung.getMitarbeiter(event.query)) - .then(result => { - this.filteredMitarbeiter = result.data.retval; - }); - }, - searchNotAkad(event) { - if (this.abortController.pruefer) { - this.abortController.pruefer.abort(); - } - this.abortController.pruefer = new AbortController(); - - return this.$api - .call(ApiStvAbschlusspruefung.getPruefer(event.query)) - .then(result => { - this.filteredPruefer = result.data.retval; - }); - }, - setDefaultFormData() { - - this.resetForm(); - - if (this.stgInfo.typ === 'b') { - this.formData.pruefungstyp_kurzbz = 'Bachelor'; - this.formData.protokoll = this.$p.t('abschlusspruefung', 'pruefungsnotizenMaster'); - } - if (this.stgInfo.typ === 'd' || this.stgInfo === 'm') { - this.formData.pruefungstyp_kurzbz = 'Diplom'; - this.formData.protokoll = this.$p.t('abschlusspruefung', 'pruefungsnotizenMaster'); - } - if (this.stgInfo.typ === 'lg') { - this.formData.pruefungstyp_kurzbz = 'lgabschluss'; - } - - if (!this.formData.akadgrad_id && this.arrAkadGrad.length > 0) { - this.formData.akadgrad_id = this.arrAkadGrad[0].akadgrad_id; - } - }, - printDocument(link) { - window.open(link, '_blank'); - }, - }, - created() { - this.$api - .call(ApiStvAbschlusspruefung.getTypenAbschlusspruefung()) - .then(result => { - this.arrTypen = result.data; - }) - .catch(this.$fhcAlert.handleSystemError); - - this.$api - .call(ApiStvAbschlusspruefung.getTypenAntritte()) - .then(result => { - this.arrAntritte = result.data; - }) - .catch(this.$fhcAlert.handleSystemError); - - this.$api - .call(ApiStvAbschlusspruefung.getBeurteilungen()) - .then(result => { - this.arrBeurteilungen = result.data; - }) - .catch(this.$fhcAlert.handleSystemError); - - this.$api - .call(ApiStvAbschlusspruefung.getNoten()) - .then(result => { - this.arrNoten = result.data; - }) - .catch(this.$fhcAlert.handleSystemError); - - this.$api - .call(ApiStvAbschlusspruefung.getAkadGrade(this.student.studiengang_kz)) - .then(result => { - this.arrAkadGrad = result.data; - }) - .catch(this.$fhcAlert.handleSystemError); - if (!this.student.length) { - this.$api - .call(ApiStudiengang.getStudiengangByKz(this.student.studiengang_kz)) - .then(result => { - this.stgInfo = result.data; - this.setDefaultFormData(); - }) - .catch(this.$fhcAlert.handleSystemError); - } else - this.getStudiengangByKz(); - }, - template: ` -
-

{{this.$p.t('stv','tab_finalexam')}}

- -
- -
- - - - - - - - - - - - - {{this.$p.t('global','details')}} -

[{{$p.t('ui', 'neu')}}]

-
- - - - - - - -
- -
- - - - -
- -
- - - - - -
- -
- - - - - - - -
- -
- - - - - -
- -
- - - - -
- -
- - - - -
- -
-
-

{{$p.t('abschlusspruefung', 'zurBeurteilung')}}

-
- -
- -
- - - -
- - - - -
-` -} diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Details.js b/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Details.js index a6256ceb1..7f98948d4 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Details.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Details.js @@ -1,4 +1,3 @@ -import {CoreFilterCmpt} from "../../../../filter/Filter.js"; import FormForm from '../../../../Form/Form.js'; import FormInput from '../../../../Form/Input.js'; import PvAutoComplete from "../../../../../../../index.ci.php/public/js/components/primevue/autocomplete/autocomplete.esm.min.js"; @@ -7,7 +6,6 @@ import ApiStvProjektarbeit from '../../../../../api/factory/stv/projektarbeit.js export default { components: { - CoreFilterCmpt, FormForm, FormInput, PvAutoComplete @@ -48,23 +46,12 @@ export default { } return lehreinheiten; - }, - //~ preparedFormData() { - //~ console.log("FOR DATA CALLEd"); - //~ if (this.formData.projektarbeit_id == null) delete(this.formData.projektarbeit_id); - //~ if (this.formData.firma) this.formData.firma_id = this.formData.firma.firma_id; - //~ delete(this.formData.firma); - //~ delete(this.formData.firma_name); - //~ delete(this.formData.lehrveranstaltung_id); - //~ // convert null value fields from string to null - //~ return this.formData; - //~ } + } }, props: { statusNew: Boolean, student: Object, - projektarbeit: Object, - stg_kz: Number + projektarbeit: Object }, data() { return { @@ -177,21 +164,13 @@ export default { }) .catch(this.$fhcAlert.handleSystemError); }, - setFormData(arrTypen, arrLvs, arrNoten, projektarbeitData) { - this.arrTypen = arrTypen; - this.arrLvs = arrLvs; - this.arrNoten = arrNoten; - if (projektarbeitData) { - projektarbeitData.firma = {firma_id: projektarbeitData.firma_id, name: projektarbeitData.firma_name}; - this.formData = projektarbeitData; - } - }, loadProjektarbeit(projektarbeit_id) { return this.$api .call(ApiStvProjektarbeit.loadProjektarbeit(projektarbeit_id)) .then(result => { this.formData = result.data; + if (this.formData.firma_id) this.formData.firma = {firma_id: this.formData.firma_id, name: this.formData.firma_name}; return result; }) .catch(this.$fhcAlert.handleSystemError) diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektarbeit.js b/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektarbeit.js index 034b3fd6c..15c9aeeee 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektarbeit.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektarbeit.js @@ -7,6 +7,7 @@ import PvAutoComplete from "../../../../../../../index.ci.php/public/js/componen import ApiStvProjektarbeit from '../../../../../api/factory/stv/projektarbeit.js'; import ProjektarbeitDetails from "./Details.js"; +import Projektbetreuer from "./Projektbetreuer.js"; export default { components: { @@ -15,7 +16,8 @@ export default { FormForm, FormInput, PvAutoComplete, - ProjektarbeitDetails + ProjektarbeitDetails, + Projektbetreuer }, inject: { cisRoot: { @@ -174,7 +176,9 @@ 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); + this.actionEditProjektarbeit( + data.projektarbeit_id, data.studiensemester_kurzbz, data.lehrveranstaltung_id, data.projekttyp_kurzbz + ); }); container.append(button); @@ -195,7 +199,6 @@ export default { }, ], layout: 'fitDataFill', - layoutColumnsOnNewData: false, height: 'auto', minHeight: '200', selectable: 1, @@ -240,25 +243,20 @@ export default { lehrveranstaltung_id: null } }, - //~ watch: { - //~ student(){ - //~ if (this.$refs.table) { - //~ this.$refs.table.reloadTable(); - //~ } - //~ this.getStudiengangByKz(); - //~ } - //~ }, methods: { actionNewProjektarbeit() { this.statusNew = true; this.$refs.projektarbeitDetails.resetForm(); this.$refs.projektarbeitDetails.getFormData(); + this.$refs.projektbetreuer.getData(); this.$refs.projektarbeitModal.show(); }, - actionEditProjektarbeit(projektarbeit_id, studiensemester_kurzbz, lehrveranstaltung_id) { + actionEditProjektarbeit(projektarbeit_id, studiensemester_kurzbz, lehrveranstaltung_id, projekttyp_kurzbz) { this.statusNew = false; this.$refs.projektarbeitDetails.getFormData(this.statusNew, studiensemester_kurzbz, lehrveranstaltung_id); + // TODO: maybe preload projektarbeit? not just on edit? this.$refs.projektarbeitDetails.loadProjektarbeit(projektarbeit_id); + this.$refs.projektbetreuer.getData(projektarbeit_id, studiensemester_kurzbz, projekttyp_kurzbz); this.$refs.projektarbeitModal.show(); }, actionDeleteProjektarbeit(projektarbeit_id) { @@ -271,41 +269,41 @@ export default { .catch(this.$fhcAlert.handleSystemError); }, addNewProjektarbeit() { - Promise.allSettled([ - this.$refs.projektarbeitDetails.addNewProjektarbeit() - ]).then((results) => { - let hasError = false; - results.forEach((promise_result) => { + this.$refs.projektbetreuer.validateProjektbetreuer() + .then(() => { + return this.$refs.projektarbeitDetails.addNewProjektarbeit(); + }) + .then((result) => { + const projektarbeit_id = result.data; + console.log(projektarbeit_id); - if (!(promise_result.status === 'fulfilled' && promise_result.value.meta.status === "success")) { - - hasError = true; + if (!isNaN(projektarbeit_id)) { + return this.$refs.projektbetreuer.saveProjektbetreuer(projektarbeit_id); } - }); - - if (!hasError) { + }) + .then((result) => { + console.log(result); this.projektarbeitSaved(); - } - }); + }) + .catch(this.$fhcAlert.handleSystemError); }, updateProjektarbeit() { - Promise.allSettled( - [ - this.$refs.projektarbeitDetails.updateProjektarbeit() - ]).then((results) => { - let hasError = false; - results.forEach((promise_result) => { + this.$refs.projektbetreuer.validateProjektbetreuer() + .then(() => { + return this.$refs.projektarbeitDetails.updateProjektarbeit(); + }) + .then((result) => { + const projektarbeit_id = result.data; + console.log(projektarbeit_id); - if (!(promise_result.status === 'fulfilled' && promise_result.value.meta.status === "success")) { - - hasError = true; + if (!isNaN(projektarbeit_id)) { + return this.$refs.projektbetreuer.saveProjektbetreuer(projektarbeit_id); } - }); - - if (!hasError) { + }) + .then((result) => { this.projektarbeitSaved(); - } - }); + }) + .catch(this.$fhcAlert.handleSystemError); }, deleteProjektarbeit(projektarbeit_id) { return this.$api @@ -325,7 +323,6 @@ export default { this.$refs.projektarbeitDetails.resetForm(); }, rowSelectionChanged(data) { - console.log("selection changed"); this.lastSelected = data.length > 0 ? data[0] : null; }, hideModal(modalRef){ @@ -362,7 +359,14 @@ export default {

{{$p.t('projektarbeit', 'projektarbeitBearbeiten')}}

- +
+
+ +
+
+ +
+
` -}; \ No newline at end of file +}; diff --git a/system/phrasesupdate.php b/system/phrasesupdate.php index a4381b00d..433a52d3e 100644 --- a/system/phrasesupdate.php +++ b/system/phrasesupdate.php @@ -41789,7 +41789,7 @@ and represent the current state of research on the topic. The prescribed citatio ), array( 'sprache' => 'English', - 'text' => 'Title', + 'text' => 'title', 'description' => '', 'insertvon' => 'system' ) @@ -41809,7 +41809,7 @@ and represent the current state of research on the topic. The prescribed citatio ), array( 'sprache' => 'English', - 'text' => 'Title English', + 'text' => 'title English', 'description' => '', 'insertvon' => 'system' ) @@ -41829,7 +41829,7 @@ and represent the current state of research on the topic. The prescribed citatio ), array( 'sprache' => 'English', - 'text' => 'Topic area', + 'text' => 'topic area', 'description' => '', 'insertvon' => 'system' ) @@ -41849,7 +41849,7 @@ and represent the current state of research on the topic. The prescribed citatio ), array( 'sprache' => 'English', - 'text' => 'Type', + 'text' => 'type', 'description' => '', 'insertvon' => 'system' ) @@ -41869,7 +41869,7 @@ and represent the current state of research on the topic. The prescribed citatio ), array( 'sprache' => 'English', - 'text' => 'Company', + 'text' => 'company', 'description' => '', 'insertvon' => 'system' ) @@ -41889,7 +41889,7 @@ and represent the current state of research on the topic. The prescribed citatio ), array( 'sprache' => 'English', - 'text' => 'Course', + 'text' => 'course', 'description' => '', 'insertvon' => 'system' ) @@ -41909,7 +41909,7 @@ and represent the current state of research on the topic. The prescribed citatio ), array( 'sprache' => 'English', - 'text' => 'Teaching unit', + 'text' => 'teaching unit', 'description' => '', 'insertvon' => 'system' ) @@ -41920,6 +41920,26 @@ and represent the current state of research on the topic. The prescribed citatio 'category' => 'projektarbeit', 'phrase' => 'betreuer', 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Betreuer', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'assessor', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'projektarbeit', + 'phrase' => 'betreuerGross', + 'insertvon' => 'system', 'phrases' => array( array( 'sprache' => 'German', @@ -41935,6 +41955,26 @@ and represent the current state of research on the topic. The prescribed citatio ) ) ), + array( + 'app' => 'core', + 'category' => 'projektarbeit', + 'phrase' => 'betreuerart', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Betreuerart', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'assessor type', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), array( 'app' => 'core', 'category' => 'projektarbeit', @@ -41949,7 +41989,7 @@ and represent the current state of research on the topic. The prescribed citatio ), array( 'sprache' => 'English', - 'text' => 'Grade', + 'text' => 'grade', 'description' => '', 'insertvon' => 'system' ) @@ -41969,7 +42009,7 @@ and represent the current state of research on the topic. The prescribed citatio ), array( 'sprache' => 'English', - 'text' => 'Hours', + 'text' => 'hours', 'description' => '', 'insertvon' => 'system' ) @@ -41989,7 +42029,7 @@ and represent the current state of research on the topic. The prescribed citatio ), array( 'sprache' => 'English', - 'text' => 'Hourly rate', + 'text' => 'hourly rate', 'description' => '', 'insertvon' => 'system' ) @@ -42029,7 +42069,7 @@ and represent the current state of research on the topic. The prescribed citatio ), array( 'sprache' => 'English', - 'text' => 'Start', + 'text' => 'start', 'description' => '', 'insertvon' => 'system' ) @@ -42049,7 +42089,7 @@ and represent the current state of research on the topic. The prescribed citatio ), array( 'sprache' => 'English', - 'text' => 'End', + 'text' => 'end', 'description' => '', 'insertvon' => 'system' ) @@ -42089,7 +42129,7 @@ and represent the current state of research on the topic. The prescribed citatio ), array( 'sprache' => 'English', - 'text' => 'Locked until', + 'text' => 'locked until', 'description' => '', 'insertvon' => 'system' ) @@ -42109,7 +42149,7 @@ and represent the current state of research on the topic. The prescribed citatio ), array( 'sprache' => 'English', - 'text' => 'Annotation', + 'text' => 'annotation', 'description' => '', 'insertvon' => 'system' ) @@ -42129,7 +42169,7 @@ and represent the current state of research on the topic. The prescribed citatio ), array( 'sprache' => 'English', - 'text' => 'Company Id', + 'text' => 'company Id', 'description' => '', 'insertvon' => 'system' ) @@ -42215,6 +42255,326 @@ and represent the current state of research on the topic. The prescribed citatio ) ) ), + array( + 'app' => 'core', + 'category' => 'projektarbeit', + 'phrase' => 'neuePersonAnlegen', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Neue Person anlegen', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Create new person', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'person', + 'phrase' => 'titelPre', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Titel (Pre)', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'title (Pre)', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'person', + 'phrase' => 'titelPost', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Titel (Post)', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'title (Post)', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'person', + 'phrase' => 'weitereVornamen', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Weitere Vornamen', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'other first names', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'person', + 'phrase' => 'bestehendeAdresseUeberschreiben', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Bestehende Adresse überschreiben', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Replace existing address', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'person', + 'phrase' => 'adresseHinzufuegen', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Adresse hinzufügen', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Add new address', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'person', + 'phrase' => 'adresseNichtAnlegen', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Adresse nicht anlegen', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Do not create address', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'person', + 'phrase' => 'land', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Land', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'nation', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'person', + 'phrase' => 'mobil', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Mobil', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'mobile phone', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'lehre', + 'phrase' => 'letzeAusbildung', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Letzte Ausbildung', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'most recent education', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'lehre', + 'phrase' => 'ausbildungsart', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Ausbildungsart', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'education type', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'lehre', + 'phrase' => 'anmerkungen', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Anmerkungen', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'notes', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'person', + 'phrase' => 'personAnlegen', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Person anlegen', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Create person', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'lehre', + 'phrase' => 'interessentAnlegen', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'InteressentIn anlegen', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Create candidate', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'person', + 'phrase' => 'personExistiertPruefung', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Prüfung ob Person bereits existiert', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Check if a person already exists', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'ui', + 'phrase' => 'zurueck', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Zurück', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Back', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), ); From 750b956dd22ce736fe8341312ec141dad0265cad Mon Sep 17 00:00:00 2001 From: Alexei Karpenko Date: Mon, 2 Jun 2025 15:28:10 +0200 Subject: [PATCH 09/27] Studentenverwaltung Projektarbeit: added button for editing contact data --- .../Details/Projektarbeit/Projektbetreuer.js | 31 +++++++++++++++++-- system/phrasesupdate.php | 20 ++++++++++++ 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektbetreuer.js b/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektbetreuer.js index 079b8b796..4f3095cab 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektbetreuer.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektbetreuer.js @@ -1,18 +1,22 @@ import {CoreFilterCmpt} from "../../../../filter/Filter.js"; +import BsModal from "../../../../Bootstrap/Modal.js"; import FormForm from '../../../../Form/Form.js'; import FormInput from '../../../../Form/Input.js'; import PvAutoComplete from "../../../../../../../index.ci.php/public/js/components/primevue/autocomplete/autocomplete.esm.min.js"; import NewPerson from "../../List/New.js"; +import Contact from "../Kontakt/Contact.js"; import ApiStvProjektbetreuer from '../../../../../api/factory/stv/projektbetreuer.js'; export default { components: { CoreFilterCmpt, + BsModal, FormForm, FormInput, PvAutoComplete, - NewPerson + NewPerson, + Contact }, inject: { }, @@ -340,6 +344,10 @@ export default { this.$refs.newPersonModal.reset(); this.$refs.newPersonModal.open(); }, + actionKontaktdatenBearbeiten() { + if (!this.autocompleteSelectedBetreuer) return; + this.$refs.kontaktdatenModal.show(); + }, personSaved(result) { this.$api .call(ApiStvProjektbetreuer.getPerson(result.person_id)) @@ -384,9 +392,12 @@ export default {
-
+
+
+ +
@@ -455,6 +466,22 @@ export default { + + + + + + +
+
+ + +
+
+ +
` } diff --git a/system/phrasesupdate.php b/system/phrasesupdate.php index 433a52d3e..d467252d7 100644 --- a/system/phrasesupdate.php +++ b/system/phrasesupdate.php @@ -42575,6 +42575,26 @@ and represent the current state of research on the topic. The prescribed citatio ) ) ), + array( + 'app' => 'core', + 'category' => 'projektarbeit', + 'phrase' => 'kontaktdatenBearbeiten', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Kontaktdaten bearbeiten', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Edit contact data', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ) ); From fe81e7fb7c5bb528f911d315bd64c28c894fb0e6 Mon Sep 17 00:00:00 2001 From: Alexei Karpenko Date: Tue, 3 Jun 2025 21:18:03 +0200 Subject: [PATCH 10/27] Studierendenverwaltung Projektarbeit: added button for Projektarbeit download --- .../api/frontend/v1/stv/Projektbetreuer.php | 26 +- .../Details/Projektarbeit/Projektbetreuer.js | 251 ++++++++++-------- system/phrasesupdate.php | 20 ++ 3 files changed, 171 insertions(+), 126 deletions(-) diff --git a/application/controllers/api/frontend/v1/stv/Projektbetreuer.php b/application/controllers/api/frontend/v1/stv/Projektbetreuer.php index 34f626eca..7a1b803b9 100644 --- a/application/controllers/api/frontend/v1/stv/Projektbetreuer.php +++ b/application/controllers/api/frontend/v1/stv/Projektbetreuer.php @@ -3,6 +3,7 @@ if (! defined('BASEPATH')) exit('No direct script access allowed'); use \DateTime as DateTime; +use CI3_Events as Events; class Projektbetreuer extends FHCAPI_Controller { @@ -85,6 +86,21 @@ class Projektbetreuer extends FHCAPI_Controller //~ } //~ } + foreach ($projektbetreuer as $pb) + { + $downloadLink = null; + Events::trigger( + 'projektbeurteilung_download_link', + $pb->projektarbeit_id, + $pb->betreuerart_kurzbz, + $pb->person_id, + function ($value) use (&$downloadLink) { + $downloadLink = $value; + } + ); + $pb->projektarbeitDownload = $downloadLink; + } + $this->terminateWithSuccess($this->_addFullNameToBetreuer($projektbetreuer)); } @@ -105,11 +121,7 @@ class Projektbetreuer extends FHCAPI_Controller foreach ($projektbetreuer as $pb) { - if ($this->_validate($pb) == false) - { - $this->addMeta('test', 'foisch'); - $this->terminateWithValidationErrors($this->form_validation->error_array()); - } + if ($this->_validate($pb) == false) $this->terminateWithValidationErrors($this->form_validation->error_array()); } $result = null; @@ -210,10 +222,6 @@ class Projektbetreuer extends FHCAPI_Controller $result = $this->StundensatzModel->getStundensatzForMitarbeiter($person_id, $studiensemester_kurzbz); - $this->addMeta('res', $result); - - //if (isError($result)) return $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); - return $this->terminateWithSuccess($result); } diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektbetreuer.js b/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektbetreuer.js index 4f3095cab..bf459ebc5 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektbetreuer.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektbetreuer.js @@ -113,6 +113,7 @@ export default { arrNoten: [], filteredBetreuer: [], autocompleteSelectedBetreuer: null, + projektarbeitDownload: null, abortController: { betreuer: null } @@ -146,6 +147,7 @@ export default { if (idx >= 0) { betreuer = projektbetreuerListe[idx]; this.formData = betreuer; + if (betreuer.projektarbeitDownload) this.projektarbeitDownload = betreuer.projektarbeitDownload this.autocompleteSelectedBetreuer = { person_id: this.formData.person_id, name: this.formData.name, @@ -268,6 +270,7 @@ export default { }, resetForm() { this.formData = this.getDefaultFormData(); + this.projektarbeitDownload = null; this.autocompleteSelectedBetreuer = null; this.initialFormData = null; if (this.projekttyp_kurzbz) this.setDefaultStunden(this.projekttyp_kurzbz); @@ -358,130 +361,144 @@ export default { } }, template: ` -
+
- {{this.$p.t('projektarbeit','betreuerGross')}} - +
- - + {{this.$p.t('projektarbeit','betreuerGross')}} + - -
- - -
+ + -
-
- -
-
- -
-
- -
- -
+ + +
+ + + + + + + + + +
+
+ + +
+
+ +
` } diff --git a/system/phrasesupdate.php b/system/phrasesupdate.php index d467252d7..d10f915cc 100644 --- a/system/phrasesupdate.php +++ b/system/phrasesupdate.php @@ -42594,6 +42594,26 @@ and represent the current state of research on the topic. The prescribed citatio 'insertvon' => 'system' ) ) + ), + array( + 'app' => 'core', + 'category' => 'projektarbeit', + 'phrase' => 'projektbeurteilungErstellen', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Projektbeurteilung erstellen', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Create project assessment document', + 'description' => '', + 'insertvon' => 'system' + ) + ) ) ); From e26bce2cf7d21d78e59c09ba16c46097c6d4ef0b Mon Sep 17 00:00:00 2001 From: Alexei Karpenko Date: Tue, 10 Jun 2025 14:14:32 +0200 Subject: [PATCH 11/27] removed merge text from code --- application/models/ressource/Stundensatz_model.php | 1 - 1 file changed, 1 deletion(-) diff --git a/application/models/ressource/Stundensatz_model.php b/application/models/ressource/Stundensatz_model.php index 553bdd20b..c8ee367d8 100644 --- a/application/models/ressource/Stundensatz_model.php +++ b/application/models/ressource/Stundensatz_model.php @@ -150,4 +150,3 @@ class Stundensatz_model extends DB_Model return $default_stundensatz; } } -==== BASE ==== From d15d27b3e14dbbf179fa85e4167b71c09c49c5f0 Mon Sep 17 00:00:00 2001 From: Alexei Karpenko Date: Fri, 13 Jun 2025 16:19:53 +0200 Subject: [PATCH 12/27] =?UTF-8?q?Studierendenverwaltung=20Projektarbeit:?= =?UTF-8?q?=20added=20Vertr=C3=A4ge?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/frontend/v1/stv/Config.php | 6 +- .../api/frontend/v1/stv/Projektbetreuer.php | 2 +- .../api/frontend/v1/stv/Vertrag.php | 104 +++++++++++ .../models/accounting/Vertrag_model.php | 20 +++ public/js/api/factory/stv/vertrag.js | 20 +++ .../Details/Projektarbeit/Details.js | 6 +- .../Details/Projektarbeit/Projektarbeit.js | 24 --- .../Details/Projektarbeit/Projektbetreuer.js | 103 +++++++---- .../Details/Projektarbeit/Vertrag.js | 168 ++++++++++++++++++ system/phrasesupdate.php | 68 ++++++- 10 files changed, 457 insertions(+), 64 deletions(-) create mode 100644 application/controllers/api/frontend/v1/stv/Vertrag.php create mode 100644 public/js/api/factory/stv/vertrag.js create mode 100644 public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Vertrag.js diff --git a/application/controllers/api/frontend/v1/stv/Config.php b/application/controllers/api/frontend/v1/stv/Config.php index 98a06ffb5..83173375e 100644 --- a/application/controllers/api/frontend/v1/stv/Config.php +++ b/application/controllers/api/frontend/v1/stv/Config.php @@ -127,7 +127,11 @@ class Config extends FHCAPI_Controller $result['projektarbeit'] = [ 'title' => $this->p->t('stv', 'tab_projektarbeit'), 'component' => './Stv/Studentenverwaltung/Details/Projektarbeit.js', - 'config' => $config['projektarbeit'] + 'config' => array_merge( + $config['projektarbeit'], + ['showVertragsdetails' => + defined('FAS_STUDIERENDE_PROJEKTARBEIT_VERTRAGSDETAILS_ANZEIGEN') && FAS_STUDIERENDE_PROJEKTARBEIT_VERTRAGSDETAILS_ANZEIGEN] + ) ]; $result['mobility'] = [ diff --git a/application/controllers/api/frontend/v1/stv/Projektbetreuer.php b/application/controllers/api/frontend/v1/stv/Projektbetreuer.php index 7a1b803b9..af0a11d0f 100644 --- a/application/controllers/api/frontend/v1/stv/Projektbetreuer.php +++ b/application/controllers/api/frontend/v1/stv/Projektbetreuer.php @@ -98,7 +98,7 @@ class Projektbetreuer extends FHCAPI_Controller $downloadLink = $value; } ); - $pb->projektarbeitDownload = $downloadLink; + $pb->beurteilungDownloadLink = $downloadLink; } $this->terminateWithSuccess($this->_addFullNameToBetreuer($projektbetreuer)); diff --git a/application/controllers/api/frontend/v1/stv/Vertrag.php b/application/controllers/api/frontend/v1/stv/Vertrag.php new file mode 100644 index 000000000..f94fe795e --- /dev/null +++ b/application/controllers/api/frontend/v1/stv/Vertrag.php @@ -0,0 +1,104 @@ + ['admin:r', 'assistenz:r'], + 'cancelVertrag' => ['admin:r', 'assistenz:r'] + ]); + + // Load Libraries + $this->load->library('form_validation'); + + // Load language phrases + $this->loadPhrases([ + 'ui', + 'person', + 'projektarbeit' + ]); + + // Load models + $this->load->model('accounting/Vertrag_model', 'VertragModel'); + $this->load->model('education/Lehrveranstaltung_model', 'LehrveranstaltungModel'); + $this->load->model('person/Benutzer_model', 'BenutzerModel'); + + // load libraries + $this->load->library('PermissionLib'); + } + + public function getVertrag() + { + $vertrag_id = $this->input->get('vertrag_id'); + + if (!isset($vertrag_id) || !is_numeric($vertrag_id)) + $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Vertrag ID']), self::ERROR_TYPE_GENERAL); + + $result = $this->VertragModel->getVertragById($vertrag_id); + + if (isError($result)) + { + $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + } + + if (!hasData($result)) $this->terminateWithSuccess([]); + + $vertrag = getData($result)[0]; + + $this->terminateWithSuccess($vertrag); + } + + public function cancelVertrag() + { + $vertrag_id = $this->input->post('vertrag_id'); + $person_id = $this->input->post('person_id'); + + if (!isset($vertrag_id) || !is_numeric($vertrag_id)) + $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Vertrag ID']), self::ERROR_TYPE_GENERAL); + if (!isset($person_id) || !is_numeric($person_id)) + $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Person ID']), self::ERROR_TYPE_GENERAL); + + // * first find lehrveranstaltung_id of the contracts lehrveranstaltung + $this->VertragModel->addSelect('lehrveranstaltung_id'); + $this->VertragModel->addJoin('lehre.tbl_lehrveranstaltung', 'lehrveranstaltung_id', 'LEFT'); + $result = $this->VertragModel->loadWhere(['vertrag_id' => $vertrag_id]); + + if (isError($result)) $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + + if (!hasData($result)) $this->terminateWithSuccess([]); + + $lehrveranstaltung_id = getData($result)[0]->lehrveranstaltung_id; + + $allOe = $this->LehrveranstaltungModel->getAllOe($lehrveranstaltung_id); + + if (isError($allOe)) $this->terminateWithError(getError($allOe), self::ERROR_TYPE_GENERAL); + + $allOe = hasData($allOe) ? getData($allOe) : []; + + $this->addMeta('oe', $allOe); + + // * then check if the user has permissions to cancel the corresponding lv-organisational units + if (!$this->permissionlib->isBerechtigtMultipleOe('admin', $allOe, 'suid') && + !$this->permissionlib->isBerechtigtMultipleOe('lehre/lehrauftrag_bestellen', $allOe, 'suid')) + { + return $this->_outputAuthError([$this->router->method => ['admin:rw', 'lehrauftrag_bestellen:rw']]); + } + + $uidResult = $this->BenutzerModel->getFromPersonId($person_id); + + if (isError($uidResult)) $this->terminateWithError(getError($uidResult), self::ERROR_TYPE_GENERAL); + + if (!hasData($uidResult)) $this->terminateWithError("no user found", self::ERROR_TYPE_GENERAL); + + $mitarbeiter_uid = getData($uidResult)[0]->uid; + + $result = $this->VertragModel->cancelVertrag($vertrag_id, $mitarbeiter_uid); + + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } +} diff --git a/application/models/accounting/Vertrag_model.php b/application/models/accounting/Vertrag_model.php index c17c676c7..4c036369b 100644 --- a/application/models/accounting/Vertrag_model.php +++ b/application/models/accounting/Vertrag_model.php @@ -402,6 +402,26 @@ class Vertrag_model extends DB_Model return $this->loadWhere(array('mitarbeiter_uid' => $mitarbeiter_uid, 'lehreinheit_id' => $lehreinheit_id)); } + public function getVertragById($vertrag_id) + { + $this->addSelect( + 'tbl_vertrag.vertrag_id, vertragstyp_kurzbz, vertragsstunden, vertragsstunden_studiensemester_kurzbz, status.vertragsstatus_kurzbz, + status.bezeichnung AS vertragsstatus, tbl_vertrag.betrag, lema.semesterstunden, lema.stundensatz' + ); + $this->addJoin('lehre.tbl_lehreinheitmitarbeiter lema', 'tbl_vertrag.vertrag_id = lema.vertrag_id', 'LEFT'); + $this->addJoin(' + ( + SELECT DISTINCT ON(vst.vertrag_id) vst.vertrag_id, + bezeichnung, + tbl_vertragsstatus.vertragsstatus_kurzbz + FROM lehre.tbl_vertrag_vertragsstatus vst + JOIN lehre.tbl_vertragsstatus USING(vertragsstatus_kurzbz) + ORDER BY vst.vertrag_id, datum DESC + ) as status', 'status.vertrag_id = lehre.tbl_vertrag.vertrag_id', 'LEFT'); + + return $this->loadWhere(['tbl_vertrag.vertrag_id' => $vertrag_id]); + } + public function cancelVertrag($vertrag_id, $mitarbeiter_uid) { $vertrag = $this->load($vertrag_id); diff --git a/public/js/api/factory/stv/vertrag.js b/public/js/api/factory/stv/vertrag.js new file mode 100644 index 000000000..9070936da --- /dev/null +++ b/public/js/api/factory/stv/vertrag.js @@ -0,0 +1,20 @@ +export default { + + getVertrag(vertrag_id) + { + return { + method: 'get', + url: 'api/frontend/v1/stv/vertrag/getVertrag', + params: { vertrag_id }, + }; + }, + + cancelVertrag(data) + { + return { + method: 'post', + url: '/api/frontend/v1/stv/vertrag/cancelVertrag/', + params: data + }; + } +} diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Details.js b/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Details.js index 4f833621d..c2269c1b3 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Details.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Details.js @@ -15,15 +15,13 @@ export default { defaultSemester: { from: 'defaultSemester' } - //~ cisRoot: { - //~ from: 'cisRoot' - //~ }, //~ config: { //~ from: 'config', //~ required: true //~ } }, computed: { + // prepared Lehreinheiten (with compound Bezeichnung) arrLes() { let lehreinheiten = []; if (this.formData.lehrveranstaltung_id) { @@ -133,7 +131,6 @@ export default { //~ //this.$fhcAlert.handleSystemError(promise_result); //~ } //~ //let data = promise_result.value.data; - //~ console.log(promise_result.status); //~ }); //~ if (!hasError) { @@ -214,6 +211,7 @@ export default { lvChanged(event) { this.formData.lehreinheit_id = null; }, + // enrich and modify data before sending getPreparedFormData() { let preparedFormData = JSON.parse(JSON.stringify(this.formData)); // deep copy diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektarbeit.js b/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektarbeit.js index 8314db8b3..3f9958a26 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektarbeit.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektarbeit.js @@ -30,29 +30,6 @@ export default { from: '$reloadList', required: true } - //~ isBerechtigtDocAndOdt: { - //~ from: 'hasPermissionOutputformat', - //~ default: false - //~ } - }, - computed: { - //~ studentUids() { - //~ if (this.student.uid) - //~ { - //~ return [this.student.uid]; - //~ } - //~ return this.student.map(e => e.uid); - //~ }, - //~ studentKzs(){ - //~ if (this.student.uid) - //~ { - //~ return [this.student.studiengang_kz]; - //~ } - //~ return this.student.map(e => e.studiengang_kz); - //~ }, - //~ stg_kz(){ - //~ return this.studentKzs.length > 0 ? this.studentKzs.length[0] : null; - //~ } }, props: { student: Object @@ -271,7 +248,6 @@ export default { actionEditProjektarbeit(projektarbeit_id, studiensemester_kurzbz, lehrveranstaltung_id, projekttyp_kurzbz) { this.statusNew = false; this.$refs.projektarbeitDetails.getFormData(this.statusNew, studiensemester_kurzbz, lehrveranstaltung_id); - // TODO: maybe preload projektarbeit? not just on edit? this.$refs.projektarbeitDetails.loadProjektarbeit(projektarbeit_id); this.$refs.projektbetreuer.getData(projektarbeit_id, studiensemester_kurzbz, projekttyp_kurzbz); this.$refs.projektarbeitModal.show(); diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektbetreuer.js b/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektbetreuer.js index bf459ebc5..8368534c7 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektbetreuer.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektbetreuer.js @@ -5,6 +5,7 @@ import FormInput from '../../../../Form/Input.js'; import PvAutoComplete from "../../../../../../../index.ci.php/public/js/components/primevue/autocomplete/autocomplete.esm.min.js"; import NewPerson from "../../List/New.js"; import Contact from "../Kontakt/Contact.js"; +import Vertrag from "./Vertrag.js"; import ApiStvProjektbetreuer from '../../../../../api/factory/stv/projektbetreuer.js'; @@ -16,9 +17,13 @@ export default { FormInput, PvAutoComplete, NewPerson, - Contact + Contact, + Vertrag }, - inject: { + provide() { + return { + configShowVertragsdetails: this.config.showVertragsdetails + } }, computed: { betreuerFormOpened() { @@ -107,13 +112,13 @@ export default { initialFormData: null, defaultFormDataValues: {stunden: null, stundensatz: null}, projektarbeit_id: null, - statusNew: true, editedBetreuerIdx: -1, arrBetreuerart: [], arrNoten: [], filteredBetreuer: [], autocompleteSelectedBetreuer: null, - projektarbeitDownload: null, + beurteilungDownloadLink: null, + vertragFieldsDisabled: false, abortController: { betreuer: null } @@ -122,19 +127,19 @@ export default { methods: { actionNewProjektbetreuer() { this.resetForm(); - this.statusNew = true; this.newMode = !this.newMode; this.editMode = false; this.captureFormData(); }, actionEditProjektbetreuer(projektarbeit_id, person_id, betreuerart_kurzbz) { - - this.statusNew = false; this.editMode = true; + this.newMode = false; this.$api .call(ApiStvProjektbetreuer.getDefaultStundensaetze(person_id, this.studiensemester_kurzbz)) .then(result => { this.resetForm(); + + // get betreuer from tabulator list let projektbetreuerListe = this.$refs.projektbetreuerTable.tabulator.getData(); const idx = projektbetreuerListe.findIndex( betr => @@ -144,18 +149,29 @@ export default { ); let betreuer = []; - if (idx >= 0) { + if (idx >= 0) { // if betreuer found betreuer = projektbetreuerListe[idx]; + + // set currently edited betreuera this.formData = betreuer; - if (betreuer.projektarbeitDownload) this.projektarbeitDownload = betreuer.projektarbeitDownload + + // set download link + if (betreuer.beurteilungDownloadLink) this.beurteilungDownloadLink = betreuer.beurteilungDownloadLink + + // set betreuer for autocomplete field this.autocompleteSelectedBetreuer = { person_id: this.formData.person_id, name: this.formData.name, vorname: this.formData.vorname, - nachname: this.formData.nachname + nachname: this.formData.nachname, + vertrag_id: this.formData.vertrag_id }; } + + // set default stundensatz (if no other is set yet) if (this.formData.stundensatz == null) this.formData.stundensatz = result.data; + + // capture initial form data for detecting changes this.captureFormData(); }) .catch(this.$fhcAlert.handleSystemError); @@ -167,10 +183,12 @@ export default { ? {projektarbeit_id, person_id, betreuerart_kurzbz} : Promise.reject({handled: true})) .then(result => { - return this.deleteProjektbetreuer(projektarbeit_id, person_id, betreuerart_kurzbz) + return this.$api + .call(ApiStvProjektbetreuer.deleteProjektbetreuer(projektarbeit_id, person_id, betreuerart_kurzbz)) }) .then(result => { this.$refs.projektbetreuerTable.tabulator.deleteRow(betreuer_id); + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successDelete')); }) .catch(this.$fhcAlert.handleSystemError); }, @@ -178,9 +196,12 @@ export default { this.studiensemester_kurzbz = studiensemester_kurzbz; + // default Stundensätze from config this.defaultFormDataValues.stunden = this.getDefaultStunden(projekttyp_kurzbz); this.defaultFormDataValues.stundensatz = this.config.defaultProjektbetreuerStundensatz; + this.resetModes(); + // get other initial data this.$api .call(ApiStvProjektbetreuer.getBetreuerarten()) .then(result => { @@ -209,6 +230,7 @@ export default { this.resetForm(); } }, + // confirming Betreuer means adding/updating him in list (but not yet saving in db) confirmProjektbetreuer() { if (!this.betreuerFormOpened) return; @@ -217,11 +239,9 @@ export default { this.$refs.projektbetreuerTable.tabulator.addData(this.addAutoCompleteBetreuerToFormData(this.formData)); } else { this.$refs.projektbetreuerTable.tabulator.updateData([this.formData]); - this.statusNew = true; } - this.newMode = false; - this.editMode = false; + this.resetModes(); }, confirmProjektbetreuerAfterValidation() { //if (!this.formDataModified()) return; @@ -239,14 +259,6 @@ export default { ApiStvProjektbetreuer.saveProjektbetreuer(projektarbeit_id, this.$refs.projektbetreuerTable.tabulator.getData()) ); }, - deleteProjektbetreuer(projektarbeit_id, person_id, betreuerart_kurzbz) { - return this.$api - .call(ApiStvProjektbetreuer.deleteProjektbetreuer(projektarbeit_id, person_id, betreuerart_kurzbz)) - .then(response => { - this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successDelete')); - }) - .catch(this.$fhcAlert.handleSystemError) - }, searchBetreuer(event) { if (this.abortController.betreuer) { this.abortController.betreuer.abort(); @@ -259,6 +271,7 @@ export default { this.filteredBetreuer = result.data; }); }, + // validate betreuer for data validateProjektbetreuer() { let alleBetreuer = this.$refs.projektbetreuerTable.tabulator.getData(); @@ -270,10 +283,15 @@ export default { }, resetForm() { this.formData = this.getDefaultFormData(); - this.projektarbeitDownload = null; + this.beurteilungDownloadLink = null; this.autocompleteSelectedBetreuer = null; this.initialFormData = null; if (this.projekttyp_kurzbz) this.setDefaultStunden(this.projekttyp_kurzbz); + this.disableVertragFields(false); + }, + resetModes() { + this.newMode = false; + this.editMode = false; }, getDefaultFormData() { let formData = {betreuerart_kurzbz : null, note: null}; @@ -287,6 +305,7 @@ export default { captureFormData() { this.initialFormData = JSON.parse(JSON.stringify(this.formData)); // deep copy }, + // add own betreuer ids to betreuer liste addIds(betreuerListe) { for (const idx in betreuerListe) { @@ -298,6 +317,7 @@ export default { } return betreuerListe; }, + // add the betreuer selected in automomplete to betreuer liste addAutoCompleteBetreuerToFormData() { let preparedFormData = this.formData; @@ -311,6 +331,7 @@ export default { return preparedFormData; }, + // get default values for stunden getDefaultStunden(projekttyp_kurzbz) { let stunden = '0.0'; if (projekttyp_kurzbz == 'Bachelor') stunden = this.config.defaultProjektbetreuerStunden; @@ -319,8 +340,10 @@ export default { }, setDefaultStunden(projekttyp_kurzbz) { this.projekttyp_kurzbz = projekttyp_kurzbz; + // 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; @@ -330,6 +353,7 @@ export default { return max + 1; }, + // check if form data has been modified since initial data has been captured formDataModified() { if (this.autocompleteSelectedBetreuer != null) return true; @@ -351,22 +375,27 @@ export default { if (!this.autocompleteSelectedBetreuer) return; this.$refs.kontaktdatenModal.show(); }, + // stuff to do after new person has been saved personSaved(result) { this.$api .call(ApiStvProjektbetreuer.getPerson(result.person_id)) .then(response => { + // set the new person in autocomplete field this.autocompleteSelectedBetreuer = response.data; }) .catch(this.$fhcAlert.handleSystemError) + }, + // disable fields which are dependent on Vertrag status + disableVertragFields(disabled) { + this.vertragFieldsDisabled = disabled; } }, template: `
-
+
{{this.$p.t('projektarbeit','betreuerGross')}} -
@@ -448,6 +478,7 @@ export default { type="text" name="stunden" :label="$p.t('projektarbeit', 'stunden')" + :disabled="vertragFieldsDisabled" v-model="formData.stunden" > @@ -459,6 +490,7 @@ export default { type="text" name="stundensatz" :label="$p.t('projektarbeit', 'stundensatz')" + :disabled="vertragFieldsDisabled" v-model="formData.stundensatz" > @@ -469,11 +501,23 @@ export default { - +
+ + {{ autocompleteSelectedBetreuer?.person_id && (!beurteilungDownloadLink || beurteilungDownloadLink == '') ? $p.t('projektarbeit', 'projektarbeitNochNichtBeurteilt') : ''}} +
- @@ -485,8 +529,7 @@ export default { + v-if="autocompleteSelectedBetreuer && autocompleteSelectedBetreuer.person_id">
-
+
-
+
diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektbetreuer.js b/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektbetreuer.js index fd796e3e1..9b02f9b01 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektbetreuer.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektbetreuer.js @@ -84,13 +84,16 @@ export default { frozen: true }, ], - layout: 'fitDataFill', + //layout: 'fitDataFill', layoutColumnsOnNewData: false, height: 'auto', minHeight: '100', selectable: true, selectable: 1, index: 'betreuer_id', + persistence:{ + columns: true, //persist column layout + }, persistenceID: 'stv-details-projektbetreuer' }, tabulatorEvents: [ @@ -99,6 +102,13 @@ export default { handler: async() => { await this.$p.loadCategory(['global', 'person', 'stv', 'projektarbeit', 'ui']); } + }, + { + event: 'rowSelected', + handler: row => { + let data = row.getData(); + this.actionEditProjektbetreuer(data.projektarbeit_id, data.person_id, data.betreuerart_kurzbz); + } } ], formData: { @@ -156,7 +166,7 @@ export default { this.formData = betreuer; // set download link - if (betreuer.beurteilungDownloadLink) this.beurteilungDownloadLink = betreuer.beurteilungDownloadLink + if (betreuer.beurteilungDownloadLink !== null) this.beurteilungDownloadLink = betreuer.beurteilungDownloadLink; // set betreuer for autocomplete field this.autocompleteSelectedBetreuer = { @@ -279,15 +289,16 @@ export default { alleBetreuer.push(this.addAutoCompleteBetreuerToFormData(this.formData)); } - return this.$api.call(ApiStvProjektbetreuer.validateProjektbetreuer(alleBetreuer)); + return this.$refs.formProjektbetreuer.call(ApiStvProjektbetreuer.validateProjektbetreuer(alleBetreuer)); }, resetForm() { this.formData = this.getDefaultFormData(); - this.beurteilungDownloadLink = null; + if (this.beurteilungDownloadLink !== null) this.beurteilungDownloadLink = ''; this.autocompleteSelectedBetreuer = null; this.initialFormData = null; if (this.projekttyp_kurzbz) this.setDefaultStunden(this.projekttyp_kurzbz); this.disableVertragFields(false); + this.$refs.formProjektbetreuer.clearValidation(); }, resetModes() { this.newMode = false; @@ -417,7 +428,7 @@ export default { type="autocomplete" optionLabel="name" v-model="autocompleteSelectedBetreuer" - name="betreuer" + name="person_id" :suggestions="filteredBetreuer" @complete="searchBetreuer" :min-length="3" @@ -501,13 +512,13 @@ export default { -
+
- {{ autocompleteSelectedBetreuer?.person_id && (!beurteilungDownloadLink || beurteilungDownloadLink == '') ? $p.t('projektarbeit', 'projektarbeitNochNichtBeurteilt') : ''}} + {{ autocompleteSelectedBetreuer?.person_id && beurteilungDownloadLink === '' ? $p.t('projektarbeit', 'projektarbeitNochNichtBeurteilt') : ''}}
diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Vertrag.js b/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Vertrag.js index 1f494d1ec..074d22bde 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Vertrag.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Vertrag.js @@ -125,36 +125,22 @@ export default{
{{ betreuerProjektarbeit?.betreuerart_kurzbz && betreuerProjektarbeit?.vertrag_id == null ? ' – '+$p.t('lehre', 'nochKeinVertrag') : '' }}
-
- -
- {{$p.t('lehre', 'vertragurfassung')}}
- - +
+ {{ $p.t('lehre', 'vertragsstatus') }}: {{ vertragsstatus }} +
- - +
+ {{$p.t('lehre', 'vertragurfassung')}} +
+
+
+
+ {{ $p.t('lehre', 'semesterstunden') }}: {{ data.vertragsstunden }} +
+ {{ $p.t('lehre', 'studiensemester') }}: {{ data.vertragsstunden_studiensemester_kurzbz }} +
@@ -164,7 +150,7 @@ export default{ :disabled="vertragsstatus == vertragsstatus_storniert" @click="cancelVertrag" > - {{ $p.t('lehre', 'stornieren') }} + {{ $p.t('lehre', 'vertragStornieren') }}
diff --git a/system/phrasesupdate.php b/system/phrasesupdate.php index db16dc247..24b37f594 100644 --- a/system/phrasesupdate.php +++ b/system/phrasesupdate.php @@ -43778,7 +43778,7 @@ and represent the current state of research on the topic. The prescribed citatio array( 'app' => 'core', 'category' => 'lehre', - 'phrase' => 'stornieren', + 'phrase' => 'vertragStornieren', 'insertvon' => 'system', 'phrases' => array( array( @@ -43789,7 +43789,7 @@ and represent the current state of research on the topic. The prescribed citatio ), array( 'sprache' => 'English', - 'text' => 'Cancel', + 'text' => 'Cancel contract', 'description' => '', 'insertvon' => 'system' ) From 4eaf71e5c634cfe7a96bdce0b3d5d7a3b423eee6 Mon Sep 17 00:00:00 2001 From: Alexei Karpenko Date: Mon, 14 Jul 2025 17:01:16 +0200 Subject: [PATCH 17/27] cancel Vertrag: correct error handling --- .../Stv/Studentenverwaltung/Details/Projektarbeit/Vertrag.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Vertrag.js b/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Vertrag.js index 074d22bde..c5de5a1fb 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Vertrag.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Vertrag.js @@ -96,7 +96,7 @@ export default{ ? {vertrag_id: this.vertrag_id, person_id: this.person_id} : Promise.reject({handled: true})) .then(result => { - this.$api.call(ApiVertrag.cancelVertrag({vertrag_id: this.vertrag_id, person_id: this.person_id})) + return this.$api.call(ApiVertrag.cancelVertrag({vertrag_id: this.vertrag_id, person_id: this.person_id})) }) .then(result => { this.resetForm(); From 1f258c84d4d01aa4db7df27480d8cea3042b7772 Mon Sep 17 00:00:00 2001 From: Alexei Karpenko Date: Tue, 15 Jul 2025 18:56:49 +0200 Subject: [PATCH 18/27] Studierendenverwaltung Projektarbeit: moved Beurteilung download to table actions, separate tabs for details and Betreuer --- .../Details/Projektarbeit/Projektarbeit.js | 34 +++++-- .../Details/Projektarbeit/Projektbetreuer.js | 88 +++++++++++++------ 2 files changed, 87 insertions(+), 35 deletions(-) diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektarbeit.js b/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektarbeit.js index dd7c4913c..76953867f 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektarbeit.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektarbeit.js @@ -348,19 +348,39 @@ 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 9b02f9b01..183c81bc0 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektbetreuer.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektbetreuer.js @@ -51,7 +51,8 @@ export default { {title: "Vertrag ID", field: "vertrag_id", visible: false}, {title: "Projektarbeit ID", field: "projektarbeit_id", visible: false}, { - title: 'Aktionen', field: 'actions', + title: 'Aktionen', + field: 'actions', minWidth: 150, // Ensures Action-buttons will be always fully displayed formatter: (cell, formatterParams, onRendered) => { let container = document.createElement('div'); @@ -62,6 +63,8 @@ export default { button.innerHTML = ''; button.title = this.$p.t('ui', 'bearbeiten'); button.addEventListener('click', (event) => { + event.stopPropagation(); + event.preventDefault(); let data = cell.getData(); this.actionEditProjektbetreuer(data.projektarbeit_id, data.person_id, data.betreuerart_kurzbz); }); @@ -71,13 +74,41 @@ export default { button.className = 'btn btn-outline-secondary btn-action'; button.innerHTML = ''; button.title = this.$p.t('ui', 'loeschen'); - button.addEventListener('click', () => { + button.addEventListener('click', (event) => { + event.stopPropagation(); + event.preventDefault(); const data = cell.getData(); this.actionDeleteProjektbetreuer(data.betreuer_id, data.projektarbeit_id, data.person_id, data.betreuerart_kurzbz) }); container.append(button); - //container.append(cell.getData().actionDiv); + let data = cell.getData(); + if (data.beurteilungDownloadLink !== null) { + if (data.beurteilungDownloadLink == '') { + button = document.createElement('span'); + button.title = this.$p.t('projektarbeit', 'projektarbeitNochNichtBeurteilt') + button.innerHTML = ''; + button.addEventListener('click', (event) => { + event.stopPropagation(); + event.preventDefault(); + }); + } + else { + button = document.createElement('a'); + button.setAttribute('href', data.beurteilungDownloadLink); + button.setAttribute('role', 'button'); + button.innerHTML = ''; + button.title = this.$p.t('projektarbeit', 'projektbeurteilungErstellen'); + button.className = 'btn btn-outline-secondary btn-action'; + button.addEventListener('click', (event) => { + event.stopPropagation(); + event.preventDefault(); + window.location.href = data.beurteilungDownloadLink; + }); + } + container.append(button); + } return container; }, @@ -404,7 +435,7 @@ export default { template: `
-
+
{{this.$p.t('projektarbeit','betreuerGross')}} @@ -484,27 +515,28 @@ export default {
- - -
- -
- - +
+ + +
+
+ + +
@@ -512,17 +544,17 @@ export default { -
+
-
+
Date: Tue, 15 Jul 2025 23:08:12 +0200 Subject: [PATCH 19/27] Studierendenverwaltung archiv: removed tabulator columns from computed --- .../Stv/Studentenverwaltung/Details/Archiv.js | 91 ------------------- 1 file changed, 91 deletions(-) diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Archiv.js b/public/js/components/Stv/Studentenverwaltung/Details/Archiv.js index 41bd222b8..d02b64c18 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Archiv.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Archiv.js @@ -67,97 +67,6 @@ export default { }; }, computed: { - tabulatorColumns() { - const columns = [ - {title: "Akte Id", field: "akte_id", visible: false}, - {title: this.$p.t('stv', 'archiv_title'), field: "titel"}, - {title: this.$p.t('stv', 'archiv_description'), field: "bezeichnung"}, - {title: this.$p.t('stv', 'archiv_creation_date'), field: "erstelltam"}, - { - title: this.$p.t('stv', 'archiv_signiert'), - field: "signiert", - formatter:"tickCross", - hozAlign:"center", - formatterParams: { - tickElement: '', - crossElement: '' - } - }, - { - title: "Selfservice", - field: "stud_selfservice", - formatter:"tickCross", - hozAlign:"center", - formatterParams: { - tickElement: '', - crossElement: '' - }, - }, - {title: this.$p.t('stv', 'archiv_accepted_on_at'), field: "akzeptiertamum"}, - { - title: this.$p.t('stv', 'archiv_gedruckt'), - field: "gedruckt", - visible: false, - formatter:"tickCross", - hozAlign:"center", - formatterParams: { - tickElement: '', - crossElement: '' - } - }, - { - title: 'Aktionen', field: 'actions', - formatter: (cell, formatterParams, onRendered) => { - let container = document.createElement('div'); - container.className = "d-flex gap-2"; - - let downloadButton = document.createElement('button'); - downloadButton.className = 'btn btn-outline-secondary'; - downloadButton.innerHTML = ''; - downloadButton.title = this.$p.t('ui', 'downloadDok'); - downloadButton.addEventListener('click', evt => { - evt.stopPropagation(); - this.actionDownload(cell.getData().akte_id); - }); - container.append(downloadButton); - - if (this.config.showEdit) - { - let editButton = document.createElement('button'); - editButton.className = 'btn btn-outline-secondary'; - editButton.innerHTML = ''; - editButton.addEventListener('click', () => - this.$refs.edit.open(cell.getData()) - ); - container.append(editButton); - } - - let deleteButton = document.createElement('button'); - deleteButton.className = 'btn btn-outline-secondary'; - deleteButton.innerHTML = ''; - deleteButton.addEventListener('click', evt => { - evt.stopPropagation(); - this.$fhcAlert - .confirmDelete() - .then(result => result ? {akte_id: cell.getData().akte_id, studiengang_kz: this.modelValue.studiengang_kz} : Promise.reject({handled:true})) - .then(this.$fhcApi.factory.stv.archiv.delete) - .then(() => { - //cell.getRow().delete(); - this.reload(); - }) - .catch(this.$fhcAlert.handleSystemError); - }); - container.append(deleteButton); - - return container; - }, - minWidth: 150, // Ensures Action-buttons will be always fully displayed - maxWidth: 150, - frozen: true - } - ]; - return columns; - }, tabulatorOptions() { const options = { ajaxURL: 'dummy', From 75adcefd5168f2b3da82d7fa19aaeb7eb6343821 Mon Sep 17 00:00:00 2001 From: Alexei Karpenko Date: Mon, 21 Jul 2025 17:52:21 +0200 Subject: [PATCH 20/27] Studentenverwaltung Projektarbeit: made text input possible for all date input --- .../Studentenverwaltung/Details/Projektarbeit/Details.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Details.js b/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Details.js index e51828f98..2fdc9d996 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Details.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Details.js @@ -350,7 +350,10 @@ export default { v-model="formData.beginn" auto-apply :enable-time-picker="false" + text-input + locale="de" format="dd.MM.yyyy" + model-type="yyyy-MM-dd" name="beginn" > @@ -361,7 +364,10 @@ export default { v-model="formData.ende" auto-apply :enable-time-picker="false" + text-input + locale="de" format="dd.MM.yyyy" + model-type="yyyy-MM-dd" name="ende" > @@ -375,7 +381,10 @@ export default { v-model="formData.gesperrtbis" auto-apply :enable-time-picker="false" + text-input + locale="de" format="dd.MM.yyyy" + model-type="yyyy-MM-dd" name="gesperrtbis" > From fc845ebf4e75c1ec26b32186eef8b8f02ab6ea37 Mon Sep 17 00:00:00 2001 From: Alexei Karpenko Date: Tue, 2 Sep 2025 15:04:45 +0200 Subject: [PATCH 21/27] 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 { -