From 7fbff20dd97d66a15cd0242214c96616530fe924 Mon Sep 17 00:00:00 2001 From: ma0068 Date: Tue, 4 Feb 2025 14:49:41 +0100 Subject: [PATCH 001/107] new Tab Gruppen --- .../api/frontend/v1/stv/Config.php | 4 + .../api/frontend/v1/stv/Favorites.php | 2 +- .../api/frontend/v1/stv/Gruppen.php | 81 ++++++++ public/js/api/stv.js | 2 + public/js/api/stv/group.js | 8 + .../js/components/Stv/Studentenverwaltung.js | 1 + .../Studentenverwaltung/Details/Gruppen.js | 19 ++ .../Details/Gruppen/Gruppen.js | 182 ++++++++++++++++++ system/phrasesupdate.php | 83 ++++++++ 9 files changed, 381 insertions(+), 1 deletion(-) create mode 100644 application/controllers/api/frontend/v1/stv/Gruppen.php create mode 100644 public/js/api/stv/group.js create mode 100644 public/js/components/Stv/Studentenverwaltung/Details/Gruppen.js create mode 100644 public/js/components/Stv/Studentenverwaltung/Details/Gruppen/Gruppen.js diff --git a/application/controllers/api/frontend/v1/stv/Config.php b/application/controllers/api/frontend/v1/stv/Config.php index c28c49485..12cd77048 100644 --- a/application/controllers/api/frontend/v1/stv/Config.php +++ b/application/controllers/api/frontend/v1/stv/Config.php @@ -91,6 +91,10 @@ class Config extends FHCAPI_Controller 'title' => $this->p->t('stv', 'tab_resources'), 'component' => './Stv/Studentenverwaltung/Details/Betriebsmittel.js' ]; + $result['groups'] = [ + 'title' => $this->p->t('stv', 'tab_groups'), + 'component' => './Stv/Studentenverwaltung/Details/Gruppen.js' + ]; /* TODO(chris): Ausgeblendet für Testing $result['grades'] = [ 'title' => $this->p->t('stv', 'tab_grades'), diff --git a/application/controllers/api/frontend/v1/stv/Favorites.php b/application/controllers/api/frontend/v1/stv/Favorites.php index 8d7a6cd14..b8fe6f3d7 100644 --- a/application/controllers/api/frontend/v1/stv/Favorites.php +++ b/application/controllers/api/frontend/v1/stv/Favorites.php @@ -48,7 +48,7 @@ class Favorites extends FHCAPI_Controller if (!$data) $this->terminateWithSuccess(null); else - $this->terminateWithSuccess($data['stv_favorites']); + $this->terminateWithSuccess($data['stv_favorites'] ?? null); } public function set() diff --git a/application/controllers/api/frontend/v1/stv/Gruppen.php b/application/controllers/api/frontend/v1/stv/Gruppen.php new file mode 100644 index 000000000..39c5efe21 --- /dev/null +++ b/application/controllers/api/frontend/v1/stv/Gruppen.php @@ -0,0 +1,81 @@ + ['admin:r', 'assistenz:r'], + 'deleteGruppe' => ['admin:rw', 'assistenz:rw'], + ]); + + // Load Libraries + $this->load->library('VariableLib', ['uid' => getAuthUID()]); + + // Load language phrases + $this->loadPhrases([ + 'ui', 'gruppenmanagement' + ]); + + // Load models + $this->load->model('person/Benutzergruppe_model', 'BenutzergruppeModel'); + $this->load->model('organisation/Gruppe_model', 'GruppeModel'); + } + + public function getGruppen($student_uid) + { + $this->BenutzergruppeModel ->addSelect('gruppe_kurzbz'); + $this->BenutzergruppeModel ->addSelect('bezeichnung'); + $this->BenutzergruppeModel ->addSelect('generiert'); + $this->BenutzergruppeModel ->addSelect('uid'); + $this->BenutzergruppeModel ->addSelect('studiensemester_kurzbz'); + $this->BenutzergruppeModel ->addSelect('public.tbl_benutzergruppe.insertvon'); + $this->BenutzergruppeModel ->addJoin('public.tbl_gruppe', 'gruppe_kurzbz'); + $this->BenutzergruppeModel-> addOrder('bezeichnung', 'ASC'); + + $result = $this->BenutzergruppeModel->loadWhere( + array( + 'uid' => $student_uid + ) + ); + + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + + public function deleteGruppe() + { + $student_uid = $this->input->post('id'); + $gruppe_kurzbz = $this->input->post('gruppe_kurzbz'); + + //Validate if automatic group generation + $result = $this->GruppeModel-> loadWhere( + array( + 'gruppe_kurzbz' => $gruppe_kurzbz + ) + ); + $data = $this->getDataOrTerminateWithError($result); + $generation = current($data); + + if($generation->generiert) + { + $this->terminateWithError($this->p->t('gruppenmanagement', 'error_deleteGeneratedGroups'), self::ERROR_TYPE_GENERAL); + } + + $result = $this->BenutzergruppeModel->delete( + array( + 'gruppe_kurzbz' => $gruppe_kurzbz, + 'uid' => $student_uid + ) + ); + + $data = $this->getDataOrTerminateWithError($result); + + return $this->terminateWithSuccess($data); + } +} diff --git a/public/js/api/stv.js b/public/js/api/stv.js index 14fcc6661..8b14beb14 100644 --- a/public/js/api/stv.js +++ b/public/js/api/stv.js @@ -2,12 +2,14 @@ import verband from './stv/verband.js'; import students from './stv/students.js'; import filter from './stv/filter.js'; import konto from './stv/konto.js'; +import group from './stv/group.js'; export default { verband, students, filter, konto, + group, configStudent() { return this.$fhcApi.get('api/frontend/v1/stv/config/student'); }, diff --git a/public/js/api/stv/group.js b/public/js/api/stv/group.js new file mode 100644 index 000000000..af6e6e122 --- /dev/null +++ b/public/js/api/stv/group.js @@ -0,0 +1,8 @@ +export default { + getGruppen(url, config, params) { + return this.$fhcApi.get('api/frontend/v1/stv/Gruppen/getGruppen/' + params.id); + }, + deleteGroup(params) { + return this.$fhcApi.post('api/frontend/v1/stv/Gruppen/deleteGruppe/', params); + } +} \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung.js b/public/js/components/Stv/Studentenverwaltung.js index 8779e4bf1..eaa253c2c 100644 --- a/public/js/components/Stv/Studentenverwaltung.js +++ b/public/js/components/Stv/Studentenverwaltung.js @@ -57,6 +57,7 @@ export default { hasPermissionToSkipStatusCheck: this.permissions['student/keine_studstatuspruefung'], hasPermissionRtAufsicht: this.permissions['lehre/reihungstestAufsicht'], lists: this.lists, + currentSemester: Vue.computed(() => this.studiensemesterKurzbz), defaultSemester: this.defaultSemester, $reloadList: () => { this.$refs.stvList.reload(); diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Gruppen.js b/public/js/components/Stv/Studentenverwaltung/Details/Gruppen.js new file mode 100644 index 000000000..1c7c47d6b --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Details/Gruppen.js @@ -0,0 +1,19 @@ +import GruppenList from './Gruppen/Gruppen.js'; + +export default { + components: { + GruppenList + }, + props: { + modelValue: Object + }, + methods: { + reload() { + this.$refs.gruppen.$refs.table.reloadTable(); + } + }, + template: ` +
+ +
` +}; \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Gruppen/Gruppen.js b/public/js/components/Stv/Studentenverwaltung/Details/Gruppen/Gruppen.js new file mode 100644 index 000000000..6a657a793 --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Details/Gruppen/Gruppen.js @@ -0,0 +1,182 @@ +import {CoreFilterCmpt} from "../../../../filter/Filter.js"; + +export default { + components: { + CoreFilterCmpt, + }, + inject: { + currentSemester: { + from: 'currentSemester', + }, + }, + props: { + student: Object + }, + data() { + return { + tabulatorOptions: { + ajaxURL: 'dummy', + ajaxRequestFunc: this.$fhcApi.factory.stv.group.getGruppen, + ajaxParams: () => { + return { + id: this.student.uid + }; + }, + ajaxResponse: (url, params, response) => response.data, + initialFilter: [ + {field: "uid", type: "=", value: this.student.uid}, + [ + {field: "studiensemester_kurzbz", type: "=", value: this.currentSemester}, + {field: "insertvon", type: "=", value: "mlists_generate"} + ] + ], + columns: [ + {title: "Gruppe", field: "gruppe_kurzbz"}, + {title: "Bezeichnung", field: "bezeichnung"}, + {title: "Semester", field: "studiensemester_kurzbz"}, + { + title: "automatisch generiert", + field: "generiert", + formatter: "tickCross", + hozAlign: "center", + formatterParams: { + tickElement: '', + crossElement: '' + } + }, + {title: "UID", field: "uid"}, + {title: "InsertVon", field: "insertvon", visible: false}, + { + title: 'Aktionen', field: 'actions', + minWidth: 150, // Ensures Action-buttons will be always fully displayed + formatter: (cell, formatterParams, onRendered) => { + const container = document.createElement('div'); + container.className = "d-flex gap-2"; + + const data = cell.getData(); + + const 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.actionDeleteGroup(data.gruppe_kurzbz) + ); + if (data.generiert) + button.disabled = true; + container.append(button); + + return container; + }, + frozen: true + }, + ], + layout: 'fitDataFill', + height: 'auto', + selectable: true, + index: 'group_id', + persistenceID: 'stv-details-gruppe' + }, + tabulatorEvents: [ + { + event: 'tableBuilt', + handler: async () => { + + await this.$p.loadCategory(['global', 'person', 'stv', 'ui', 'gruppenmanagement']); + + let cm = this.$refs.table.tabulator.columnManager; + + cm.getColumnByField('gruppe_kurzbz').component.updateDefinition({ + title: this.$p.t('gruppenmanagement', 'gruppe') + }); + + cm.getColumnByField('bezeichnung').component.updateDefinition({ + title: this.$p.t('ui', 'bezeichnung') + }); + + cm.getColumnByField('generiert').component.updateDefinition({ + title: this.$p.t('gruppenmanagement', 'automatisch_generiert') + }); + + cm.getColumnByField('uid').component.updateDefinition({ + title: this.$p.t('ui', 'student_uid') + }); + + //Interference with Filter if not commented out + /* + cm.getColumnByField('studiensemester_kurzbz').component.updateDefinition({ + title: this.$p.t('lehre', 'studiensemester') + });*/ + + } + } + ], + } + }, + methods: { + actionDeleteGroup(gruppe_kurzbz) { + this.$fhcAlert + .confirmDelete() + .then(result => result + ? gruppe_kurzbz + : Promise.reject({handled: true})) + .then(this.deleteGroup) + .catch(this.$fhcAlert.handleSystemError); + + }, + deleteGroup(gruppe_kurzbz) { + const group_id = { + id: this.student.uid, + gruppe_kurzbz: gruppe_kurzbz + }; + + return this.$fhcApi.factory.stv.group.deleteGroup(group_id) + .then(response => { + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successDelete')); + }).catch(this.$fhcAlert.handleSystemError) + .finally(() => { + window.scrollTo(0, 0); + this.reload(); + }); + }, + reload() { + this.$refs.table.reloadTable(); + }, + }, + watch: { + currentSemester(newVal) { + if (newVal) { + + this.$refs.table.tabulator.clearFilter(); // Clear old filters + + this.$refs.table.tabulator.setFilter([ + {field: "uid", type: "=", value: this.student.uid}, + [ + {field: "studiensemester_kurzbz", type: "=", value: newVal}, + {field: "insertvon", type: "=", value: "mlists_generate"} + ] + ]); + + + } + }, + student() { + this.$refs.table.reloadTable(); + } + }, + template: ` +
+
{{$p.t('stv', 'tab_groups')}}
+ + + +
+ ` +} \ No newline at end of file diff --git a/system/phrasesupdate.php b/system/phrasesupdate.php index 746c24da3..160db2853 100644 --- a/system/phrasesupdate.php +++ b/system/phrasesupdate.php @@ -37297,7 +37297,90 @@ array( 'insertvon' => 'system' ) ) + ), + //////////// FHC4 Phrases Gruppen Start //////////// + array( + 'app' => 'core', + 'category' => 'stv', + 'phrase' => 'tab_groups', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Gruppen', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Groups', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'gruppenmanagement', + 'phrase' => 'gruppe', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Gruppe', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Group', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'gruppenmanagement', + 'phrase' => 'automatisch_generiert', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'automatisch generiert', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'automatically generated', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'gruppenmanagement', + 'phrase' => 'error_deleteGeneratedGroups', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Automatisch generierte Gruppenzuordnungen können nicht gelöscht werden.', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Automatically generated group assignments cannot be deleted.', + 'description' => '', + 'insertvon' => 'system' + ) + ) ) + //////////// FHC4 Phrases Gruppen End //////////// + ); From 6eb9c2ac223e34fe6bd5e89310615e3822e58bf2 Mon Sep 17 00:00:00 2001 From: ma0068 Date: Tue, 4 Feb 2025 14:57:35 +0100 Subject: [PATCH 002/107] update filtering --- application/controllers/api/frontend/v1/stv/Gruppen.php | 1 - .../Stv/Studentenverwaltung/Details/Gruppen/Gruppen.js | 5 ++--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/application/controllers/api/frontend/v1/stv/Gruppen.php b/application/controllers/api/frontend/v1/stv/Gruppen.php index 39c5efe21..c30816f2a 100644 --- a/application/controllers/api/frontend/v1/stv/Gruppen.php +++ b/application/controllers/api/frontend/v1/stv/Gruppen.php @@ -33,7 +33,6 @@ class Gruppen extends FHCAPI_Controller $this->BenutzergruppeModel ->addSelect('generiert'); $this->BenutzergruppeModel ->addSelect('uid'); $this->BenutzergruppeModel ->addSelect('studiensemester_kurzbz'); - $this->BenutzergruppeModel ->addSelect('public.tbl_benutzergruppe.insertvon'); $this->BenutzergruppeModel ->addJoin('public.tbl_gruppe', 'gruppe_kurzbz'); $this->BenutzergruppeModel-> addOrder('bezeichnung', 'ASC'); diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Gruppen/Gruppen.js b/public/js/components/Stv/Studentenverwaltung/Details/Gruppen/Gruppen.js index 6a657a793..63a9b24e1 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Gruppen/Gruppen.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Gruppen/Gruppen.js @@ -27,7 +27,7 @@ export default { {field: "uid", type: "=", value: this.student.uid}, [ {field: "studiensemester_kurzbz", type: "=", value: this.currentSemester}, - {field: "insertvon", type: "=", value: "mlists_generate"} + {field: "studiensemester_kurzbz", type: "=", value: null} ] ], columns: [ @@ -45,7 +45,6 @@ export default { } }, {title: "UID", field: "uid"}, - {title: "InsertVon", field: "insertvon", visible: false}, { title: 'Aktionen', field: 'actions', minWidth: 150, // Ensures Action-buttons will be always fully displayed @@ -153,7 +152,7 @@ export default { {field: "uid", type: "=", value: this.student.uid}, [ {field: "studiensemester_kurzbz", type: "=", value: newVal}, - {field: "insertvon", type: "=", value: "mlists_generate"} + {field: "studiensemester_kurzbz", type: "=", value: null} ] ]); From 018220594a82590cffbcbc612f0f767a314387d7 Mon Sep 17 00:00:00 2001 From: ma0068 Date: Thu, 6 Feb 2025 08:34:34 +0100 Subject: [PATCH 003/107] prepare basic framework --- .../api/frontend/v1/messages/Messages.php | 45 +++++++ .../api/frontend/v1/stv/Config.php | 4 + .../api/frontend/v1/stv/Favorites.php | 2 +- application/models/system/Message_model.php | 9 +- public/js/api/fhcapifactory.js | 4 +- public/js/api/messages.js | 5 + public/js/api/messages/person.js | 6 + .../components/Messages/Details/NewMessage.js | 13 ++ .../Messages/Details/TableMessages.js | 117 ++++++++++++++++++ public/js/components/Messages/Messages.js | 48 +++++++ .../Studentenverwaltung/Details/Messages.js | 25 ++++ system/phrasesupdate.php | 25 +++- 12 files changed, 297 insertions(+), 6 deletions(-) create mode 100644 application/controllers/api/frontend/v1/messages/Messages.php create mode 100644 public/js/api/messages.js create mode 100644 public/js/api/messages/person.js create mode 100644 public/js/components/Messages/Details/NewMessage.js create mode 100644 public/js/components/Messages/Details/TableMessages.js create mode 100644 public/js/components/Messages/Messages.js create mode 100644 public/js/components/Stv/Studentenverwaltung/Details/Messages.js diff --git a/application/controllers/api/frontend/v1/messages/Messages.php b/application/controllers/api/frontend/v1/messages/Messages.php new file mode 100644 index 000000000..f81e85e9a --- /dev/null +++ b/application/controllers/api/frontend/v1/messages/Messages.php @@ -0,0 +1,45 @@ + ['admin:r', 'assistenz:r'], + ]); + + //Load Models + $this->load->model('system/Message_model', 'MessageModel'); + + // Additional Permission Checks + //TODO(manu) check permissions + + // Load Libraries + $this->load->library('VariableLib', ['uid' => getAuthUID()]); + $this->load->library('form_validation'); + + // Load language phrases + $this->loadPhrases([ + 'ui' + ]); + } + + public function getMessages($id, $type_id) + { + //$this->terminateWithError("in backend " . $type_id . ": " . $id, self::ERROR_TYPE_GENERAL); + + if ($type_id != "person_id") + { + $this->terminateWithError("logic for type_id " . $type_id . " not defined yet", self::ERROR_TYPE_GENERAL); + } + + $result = $this->MessageModel->getMessagesOfPerson($id); + + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } +} \ No newline at end of file diff --git a/application/controllers/api/frontend/v1/stv/Config.php b/application/controllers/api/frontend/v1/stv/Config.php index c28c49485..9dec3015f 100644 --- a/application/controllers/api/frontend/v1/stv/Config.php +++ b/application/controllers/api/frontend/v1/stv/Config.php @@ -91,6 +91,10 @@ class Config extends FHCAPI_Controller 'title' => $this->p->t('stv', 'tab_resources'), 'component' => './Stv/Studentenverwaltung/Details/Betriebsmittel.js' ]; + $result['messages'] = [ + 'title' => $this->p->t('stv', 'tab_messages'), + 'component' => './Stv/Studentenverwaltung/Details/Messages.js' + ]; /* TODO(chris): Ausgeblendet für Testing $result['grades'] = [ 'title' => $this->p->t('stv', 'tab_grades'), diff --git a/application/controllers/api/frontend/v1/stv/Favorites.php b/application/controllers/api/frontend/v1/stv/Favorites.php index 8d7a6cd14..b8fe6f3d7 100644 --- a/application/controllers/api/frontend/v1/stv/Favorites.php +++ b/application/controllers/api/frontend/v1/stv/Favorites.php @@ -48,7 +48,7 @@ class Favorites extends FHCAPI_Controller if (!$data) $this->terminateWithSuccess(null); else - $this->terminateWithSuccess($data['stv_favorites']); + $this->terminateWithSuccess($data['stv_favorites'] ?? null); } public function set() diff --git a/application/models/system/Message_model.php b/application/models/system/Message_model.php index d9f8585ed..6288f54f3 100644 --- a/application/models/system/Message_model.php +++ b/application/models/system/Message_model.php @@ -85,7 +85,7 @@ class Message_model extends DB_Model */ public function getMessagesOfPerson($person_id, $status = null) { - $sql = 'SELECT m.message_id, + $sql = "SELECT m.message_id, m.person_id, m.subject, m.body, @@ -109,7 +109,10 @@ class Message_model extends DB_Model re.vornamen AS revornamen, s.status, s.statusinfo, - s.insertamum AS statusamum + s.insertamum AS statusamum, + CONCAT(se.titelpre, ' ', se.vorname, ' ', se.nachname, ' ', se.titelpost) as sender, + CONCAT(re.titelpre, ' ', re.vorname, ' ', re.nachname, ' ', re.titelpost ) as recipient, + TO_CHAR(s.insertamum::timestamp, 'DD.MM.YYYY HH24:MI') AS format_insertamum FROM public.tbl_msg_message m JOIN public.tbl_msg_recipient r ON m.message_id = r.message_id JOIN public.tbl_person se ON (m.person_id = se.person_id) @@ -122,7 +125,7 @@ class Message_model extends DB_Model ) s ON (m.message_id = s.message_id AND re.person_id = s.person_id) WHERE se.person_id = ? OR re.person_id = ? - '; + "; if (is_numeric($status)) { diff --git a/public/js/api/fhcapifactory.js b/public/js/api/fhcapifactory.js index c4106c3f6..7bc510b6e 100644 --- a/public/js/api/fhcapifactory.js +++ b/public/js/api/fhcapifactory.js @@ -33,6 +33,7 @@ import ort from "./ort.js"; import cms from "./cms.js"; import lehre from "./lehre.js"; import addons from "./addons.js"; +import messages from "./messages.js"; export default { search, @@ -52,5 +53,6 @@ export default { ort, cms, lehre, - addons + addons, + messages }; diff --git a/public/js/api/messages.js b/public/js/api/messages.js new file mode 100644 index 000000000..f1378c69d --- /dev/null +++ b/public/js/api/messages.js @@ -0,0 +1,5 @@ +import person from "./messages/person.js"; + +export default { + person +} \ No newline at end of file diff --git a/public/js/api/messages/person.js b/public/js/api/messages/person.js new file mode 100644 index 000000000..bfbdaf123 --- /dev/null +++ b/public/js/api/messages/person.js @@ -0,0 +1,6 @@ +export default { + getMessages(url, config, params){ + console.log("in api", params); + return this.$fhcApi.get('api/frontend/v1/messages/messages/getMessages/' + params.id + '/' + params.type); + }, +} \ No newline at end of file diff --git a/public/js/components/Messages/Details/NewMessage.js b/public/js/components/Messages/Details/NewMessage.js new file mode 100644 index 000000000..bf60842d2 --- /dev/null +++ b/public/js/components/Messages/Details/NewMessage.js @@ -0,0 +1,13 @@ +export default { + data(){ + return { + + } + }, + template: ` +
+

New Message

+
+ ` + +} \ No newline at end of file diff --git a/public/js/components/Messages/Details/TableMessages.js b/public/js/components/Messages/Details/TableMessages.js new file mode 100644 index 000000000..bc7e6a02a --- /dev/null +++ b/public/js/components/Messages/Details/TableMessages.js @@ -0,0 +1,117 @@ +import {CoreFilterCmpt} from "../../filter/Filter.js"; + +export default { + components: { + CoreFilterCmpt, + }, + props: { + endpoint: { + type: String, + required: true + }, + typeId: String, + id: { + type: [Number, String], + required: true + }, + }, + //TODO(Manu) endpoint macht Probleme + data(){ + return { + tabulatorOptions: { + ajaxURL: 'dummy', + ajaxRequestFunc: this.$fhcApi.factory.messages.person.getMessages, + ajaxParams: () => { + return { + id: this.id, + type: this.typeId + }; + }, + ajaxResponse: (url, params, response) => response.data, + columns: [ + {title: "subject", field: "subject"}, + {title: "body", field: "body", visible: false}, + {title: "message_id", field: "message_id", visible: false}, + {title: "datum", field: "format_insertamum"}, + {title: "sender", field: "sender"}, + {title: "recipient", field: "recipient"}, + {title: "sepersonid", field: "sepersonid"}, + {title: "repersonid", field: "repersonid"}, + {title: "status", field: "status"}, + { + title: 'Aktionen', field: 'actions', + width: 100, + 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.title = this.$p.t('ui', 'notiz_edit'); + button.innerHTML = ''; + button.addEventListener( + 'click', + (event) => + this.actionEditNotiz(cell.getData().notiz_id) + ); + container.append(button); + + button = document.createElement('button'); + button.className = 'btn btn-outline-secondary btn-action'; + button.title = this.$p.t('notiz', 'notiz_delete'); + button.innerHTML = ''; + button.addEventListener( + 'click', + () => + this.actionDeleteNotiz(cell.getData().notiz_id) + ); + container.append(button); + + return container; + }, + frozen: true + }], + layout: 'fitColumns', + layoutColumnsOnNewData: false, + height: '250', + selectableRangeMode: 'click', + selectable: true, + index: 'message_id', + persistenceID: 'core-message' + }, + } + }, +/* computed: { + statusText(){ + 0: this.$p.t('messsages', 'unread'), + 1: this.$p.t('messsages', 'read'), + 2: this.$p.t('messsages', 'archived'), + 0: this.$p.t('messsages', 'unread'), + 3: this.$p.t('person', 'deleted'), + } + },*/ + template: ` +
+

Table Messages

+

type_id: {{typeId}}

+

id: {{id}}

+

endpoint: {{endpoint}}

+ + + + + + +
+ ` + +} \ No newline at end of file diff --git a/public/js/components/Messages/Messages.js b/public/js/components/Messages/Messages.js new file mode 100644 index 000000000..6811a3aed --- /dev/null +++ b/public/js/components/Messages/Messages.js @@ -0,0 +1,48 @@ +import TableMessages from "./Details/TableMessages.js"; +import NewMessage from "./Details/NewMessage.js"; + +export default { + components: { + TableMessages, + NewMessage + }, + props: { + endpoint: { + type: String, + required: true + }, + typeId: String, + id: { + type: [Number, String], + required: true + }, + showNew: Boolean, + showTable: Boolean + }, + data() { + return {} + }, + template: ` +
+

endpoint: {{endpoint}}

+
+ + +
+ +
+ + + +
+ +
+ ` + +} \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Messages.js b/public/js/components/Stv/Studentenverwaltung/Details/Messages.js new file mode 100644 index 000000000..7bd6d4b4d --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Details/Messages.js @@ -0,0 +1,25 @@ +import CoreMessages from "../../../Messages/Messages.js"; + +export default { + components: { + CoreMessages + }, + props: { + modelValue: Object + }, + template: ` +
+ + + + + +
+ ` +}; \ No newline at end of file diff --git a/system/phrasesupdate.php b/system/phrasesupdate.php index cfaf85ec7..f25cc72ec 100644 --- a/system/phrasesupdate.php +++ b/system/phrasesupdate.php @@ -37297,7 +37297,30 @@ array( 'insertvon' => 'system' ) ) - ) + ), + /////////// FHC4 Phrases Messages START /////////// + array( + 'app' => 'core', + 'category' => 'stv', + 'phrase' => 'tab_messages', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Nachrichten', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Messages', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + /////////// FHC4 Phrases Messages END /////////// + ); From ae3072be924940441968f5d65a352245af043afc Mon Sep 17 00:00:00 2001 From: ma0068 Date: Tue, 11 Feb 2025 09:02:56 +0100 Subject: [PATCH 004/107] listTables with preview in two layouts --- .../api/frontend/v1/messages/Messages.php | 2 +- application/models/system/Message_model.php | 57 +++- public/css/Studentenverwaltung.css | 1 + public/css/components/Messages.css | 4 + public/js/api/messages/person.js | 1 - .../Messages/Details/TableMessages.js | 272 +++++++++++++++--- public/js/components/Messages/Messages.js | 15 +- .../Studentenverwaltung/Details/Messages.js | 3 +- system/phrasesupdate.php | 200 +++++++++++++ 9 files changed, 508 insertions(+), 47 deletions(-) create mode 100644 public/css/components/Messages.css diff --git a/application/controllers/api/frontend/v1/messages/Messages.php b/application/controllers/api/frontend/v1/messages/Messages.php index f81e85e9a..adf1d52e9 100644 --- a/application/controllers/api/frontend/v1/messages/Messages.php +++ b/application/controllers/api/frontend/v1/messages/Messages.php @@ -36,7 +36,7 @@ class Messages extends FHCAPI_Controller $this->terminateWithError("logic for type_id " . $type_id . " not defined yet", self::ERROR_TYPE_GENERAL); } - $result = $this->MessageModel->getMessagesOfPerson($id); + $result = $this->MessageModel->getMessagesForTable($id); $data = $this->getDataOrTerminateWithError($result); diff --git a/application/models/system/Message_model.php b/application/models/system/Message_model.php index 6288f54f3..1b201fc1b 100644 --- a/application/models/system/Message_model.php +++ b/application/models/system/Message_model.php @@ -109,10 +109,7 @@ class Message_model extends DB_Model re.vornamen AS revornamen, s.status, s.statusinfo, - s.insertamum AS statusamum, - CONCAT(se.titelpre, ' ', se.vorname, ' ', se.nachname, ' ', se.titelpost) as sender, - CONCAT(re.titelpre, ' ', re.vorname, ' ', re.nachname, ' ', re.titelpost ) as recipient, - TO_CHAR(s.insertamum::timestamp, 'DD.MM.YYYY HH24:MI') AS format_insertamum + s.insertamum AS statusamum FROM public.tbl_msg_message m JOIN public.tbl_msg_recipient r ON m.message_id = r.message_id JOIN public.tbl_person se ON (m.person_id = se.person_id) @@ -233,4 +230,56 @@ class Message_model extends DB_Model return $this->execQuery($query, $params); } + + /** + * Gets messages for a person for tableMessages. + * @param $person_id + * @param null $status message status. by default, latest status is returned + * @return array|null + */ + public function getMessagesForTable($person_id, $status = null) + { + $sql = " + SELECT + m.message_id AS message_id, + m.subject AS subject, + m.body AS body, + m.insertamum AS insertamum, + m.relationmessage_id AS relationmessage_id, + (SELECT COALESCE(titelpre,'') || ' ' || COALESCE(vorname,'') || ' ' || COALESCE(nachname,'') || ' ' || COALESCE(titelpost,'') FROM public.tbl_person WHERE person_id = m.person_id) as sender, + (SELECT COALESCE(titelpre,'') || ' ' || COALESCE(vorname,'') || ' ' || COALESCE(nachname,'') || ' ' || COALESCE(titelpost,'') FROM public.tbl_person WHERE person_id = r.person_id) as recipient, + m.person_id as sender_id, + r.person_id as recipient_id, + MAX(ss.status) as status, + MAX(ss.insertamum) as statusdatum + FROM public.tbl_msg_message m + JOIN public.tbl_msg_recipient r USING(message_id) + JOIN public.tbl_msg_status ss ON(r.message_id = ss.message_id AND ss.person_id = r.person_id) + WHERE m.person_id = ? + GROUP BY m.message_id, m.subject, m.body, m.insertamum, m.relationmessage_id, sender, recipient, sender_id, recipient_id + UNION ALL + SELECT + m.message_id AS message_id, + m.subject AS subject, + m.body AS body, + m.insertamum AS insertamum, + m.relationmessage_id AS relationmessage_id, + (SELECT COALESCE(titelpre,'') || ' ' || COALESCE(vorname,'') || ' ' || COALESCE(nachname,'') || ' ' || COALESCE(titelpost,'') FROM public.tbl_person WHERE person_id = m.person_id) as sender, + (SELECT COALESCE(titelpre,'') || ' ' || COALESCE(vorname,'') || ' ' || COALESCE(nachname,'') || ' ' || COALESCE(titelpost,'') FROM public.tbl_person WHERE person_id = r.person_id) as recipient, + m.person_id as sender_id, + r.person_id as recipient_id, + MAX(ss.status) as status, + MAX(ss.insertamum) as statusdatum + FROM public.tbl_msg_recipient r + JOIN public.tbl_msg_status ss USING(message_id, person_id) + JOIN public.tbl_msg_message m USING(message_id) + WHERE r.person_id = ? + GROUP BY m.message_id, m.subject, m.body, m.insertamum, m.relationmessage_id, sender, recipient, sender_id, recipient_id + ORDER BY insertamum + "; + + $parametersArray = array($person_id, $person_id); + + return $this->execQuery($sql, $parametersArray); + } } diff --git a/public/css/Studentenverwaltung.css b/public/css/Studentenverwaltung.css index f179c3667..cc2eff51d 100644 --- a/public/css/Studentenverwaltung.css +++ b/public/css/Studentenverwaltung.css @@ -4,6 +4,7 @@ @import './components/FilterComponent.css'; @import './components/Tabs.css'; @import './components/Notiz.css'; +@import './components/Messages.css'; html { font-size: .875em; diff --git a/public/css/components/Messages.css b/public/css/components/Messages.css new file mode 100644 index 000000000..1c004f6b0 --- /dev/null +++ b/public/css/components/Messages.css @@ -0,0 +1,4 @@ +.twoColumns { + height: 400px; + overflow-y: auto; +} diff --git a/public/js/api/messages/person.js b/public/js/api/messages/person.js index bfbdaf123..baf8bd39f 100644 --- a/public/js/api/messages/person.js +++ b/public/js/api/messages/person.js @@ -1,6 +1,5 @@ export default { getMessages(url, config, params){ - console.log("in api", params); return this.$fhcApi.get('api/frontend/v1/messages/messages/getMessages/' + params.id + '/' + params.type); }, } \ No newline at end of file diff --git a/public/js/components/Messages/Details/TableMessages.js b/public/js/components/Messages/Details/TableMessages.js index bc7e6a02a..c4fd4d4d7 100644 --- a/public/js/components/Messages/Details/TableMessages.js +++ b/public/js/components/Messages/Details/TableMessages.js @@ -1,8 +1,12 @@ import {CoreFilterCmpt} from "../../filter/Filter.js"; +import FormForm from '../../Form/Form.js'; +//import FormInput from '../../Form/Input.js'; export default { components: { CoreFilterCmpt, + FormForm, + // FormInput }, props: { endpoint: { @@ -14,6 +18,7 @@ export default { type: [Number, String], required: true }, + messageLayout: String, }, //TODO(Manu) endpoint macht Probleme data(){ @@ -32,12 +37,65 @@ export default { {title: "subject", field: "subject"}, {title: "body", field: "body", visible: false}, {title: "message_id", field: "message_id", visible: false}, - {title: "datum", field: "format_insertamum"}, + { + title: "Datum", + field: "insertamum", + formatter: function (cell) { + const dateStr = cell.getValue(); + const date = new Date(dateStr); // Convert to Date object + return date.toLocaleString("de-DE", { + day: "2-digit", + month: "2-digit", + year: "numeric", + hour: "2-digit", + minute: "2-digit", + hour12: false + }); + } + }, {title: "sender", field: "sender"}, {title: "recipient", field: "recipient"}, - {title: "sepersonid", field: "sepersonid"}, - {title: "repersonid", field: "repersonid"}, - {title: "status", field: "status"}, + {title: "senderId", field: "sender_id"}, + {title: "recipientId", field: "recipient_id"}, + { + title: "status", + field: "status", + formatter: function (cell) { + //TODO(Manu) get phrases in this context to work? + + /* const statusMap = { + 0: this.$p.t('messsages', 'unread'), + 1: this.$p.t('messsages', 'read'), + 2: this.$p.t('messsages', 'archived'), + 3: this.$p.t('messsages', 'deleted') + };*/ + const statusMap = { + 0: 'unread', + 1: 'read', + 2: 'archived', + 3: 'deleted' + }; + return statusMap[cell.getValue()]; + // return this.$p.t('messsages', 'deleted'); + } + + }, + { + title: "letzte Änderung", + field: "statusdatum", + formatter: function (cell) { + const dateStr = cell.getValue(); + const date = new Date(dateStr); // Convert to Date object + return date.toLocaleString("de-DE", { + day: "2-digit", + month: "2-digit", + year: "numeric", + hour: "2-digit", + minute: "2-digit", + hour12: false + }); + } + }, { title: 'Aktionen', field: 'actions', width: 100, @@ -47,23 +105,23 @@ export default { let button = document.createElement('button'); button.className = 'btn btn-outline-secondary btn-action'; - button.title = this.$p.t('ui', 'notiz_edit'); - button.innerHTML = ''; + button.title = this.$p.t('global', 'reply'); + button.innerHTML = ''; button.addEventListener( 'click', (event) => - this.actionEditNotiz(cell.getData().notiz_id) + this.reply(cell.getData().message_id) ); container.append(button); button = document.createElement('button'); button.className = 'btn btn-outline-secondary btn-action'; - button.title = this.$p.t('notiz', 'notiz_delete'); + button.title = this.$p.t('ui', 'loeschen'); button.innerHTML = ''; button.addEventListener( 'click', () => - this.actionDeleteNotiz(cell.getData().notiz_id) + this.deleteMessage(cell.getData().message_id) ); container.append(button); @@ -71,46 +129,186 @@ export default { }, frozen: true }], - layout: 'fitColumns', - layoutColumnsOnNewData: false, - height: '250', + layout: 'fitDataFill', + layoutColumnsOnNewData: false, + // height: 'auto', + height: '400', + selectable: true, + selectableRangeMode: 'click', +/* layoutColumnsOnNewData: false, + selectableRangeMode: 'click', selectable: true, index: 'message_id', - persistenceID: 'core-message' + persistenceID: 'core-message'*/ }, + tabulatorEvents: [ + { + event: 'dataLoaded', + handler: data => this.tabulatorData = data.map(item => { + return item; + }), + }, + { + event: 'tableBuilt', + handler: async() => { + await this.$p.loadCategory(['global', 'person', 'stv', 'messages', 'ui', 'notiz']); + + + let cm = this.$refs.table.tabulator.columnManager; + + cm.getColumnByField('subject').component.updateDefinition({ + title: this.$p.t('global', 'betreff') + }); + cm.getColumnByField('body').component.updateDefinition({ + title: this.$p.t('messages', 'body') + }); + cm.getColumnByField('message_id').component.updateDefinition({ + title: this.$p.t('messages', 'message_id') + }); + cm.getColumnByField('insertamum').component.updateDefinition({ + title: this.$p.t('global', 'datum') + }); + cm.getColumnByField('sender').component.updateDefinition({ + title: this.$p.t('messages', 'sender') + }); + cm.getColumnByField('recipient').component.updateDefinition({ + title: this.$p.t('messages', 'recipient') + }); + cm.getColumnByField('sender_id').component.updateDefinition({ + title: this.$p.t('messages', 'senderId') + }); + cm.getColumnByField('recipient_id').component.updateDefinition({ + title: this.$p.t('messages', 'recipientId') + }); + cm.getColumnByField('statusdatum').component.updateDefinition({ + title: this.$p.t('notiz', 'letzte_aenderung') + }); + /* + cm.getColumnByField('actions').component.updateDefinition({ + title: this.$p.t('global', 'aktionen') + }); + */ + } + }, + { + event: 'rowClick', + handler: (e, row) => { + const selectedMessage = row.getData().message_id; + const body = row.getData().body; + this.previewBody = body; + console.log(selectedMessage); + } + }, + ], + tabulatorData: [], + previewBody: "" } }, -/* computed: { + methods: { + reply(message_id){ + console.log("in reply " + message_id); + }, + deleteMessage(message_id){ + console.log("deleteMessage " + message_id); + }, + actionNewMessage(){ + console.log("action new message"); + }, + }, + computed: { statusText(){ - 0: this.$p.t('messsages', 'unread'), - 1: this.$p.t('messsages', 'read'), - 2: this.$p.t('messsages', 'archived'), - 0: this.$p.t('messsages', 'unread'), - 3: this.$p.t('person', 'deleted'), + return { + 0: this.$p.t('messsages', 'unread'), + 1: this.$p.t('messsages', 'read'), + 2: this.$p.t('messsages', 'archived'), + 3: this.$p.t('messsages', 'deleted') + } } - },*/ + }, + mounted() { + // change to target="_blank" +/* this.$nextTick(() => { + const links = document.querySelectorAll('.preview a'); + links.forEach(link => { + link.setAttribute('target', '_blank'); + link.setAttribute('rel', 'noopener noreferrer'); // Sicherheitsmaßnahme + }); + });*/ + }, template: `
-

Table Messages

-

type_id: {{typeId}}

-

id: {{id}}

endpoint: {{endpoint}}

+

{{messageLayout}}

+ + + + + + +
- - - - - +
+ +
+ + +
+ + +
+



+ +
+
+
+ +
+ +
+
+ + +
+ + +
+ + +
+ + +
+ +
+
+
+ +
+
+
` diff --git a/public/js/components/Messages/Messages.js b/public/js/components/Messages/Messages.js index 6811a3aed..3fd6e2a02 100644 --- a/public/js/components/Messages/Messages.js +++ b/public/js/components/Messages/Messages.js @@ -17,14 +17,24 @@ export default { required: true }, showNew: Boolean, - showTable: Boolean + showTable: Boolean, + messageLayout: { + type: String, + default: 'twoColumnsTableLeft', + validator(value) { + return [ + 'twoColumnsTableLeft', + 'listTableTop' + ].includes(value) + } + }, }, data() { return {} }, template: `
-

endpoint: {{endpoint}}

+

endpoint Messages.js: {{endpoint}}

diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Messages.js b/public/js/components/Stv/Studentenverwaltung/Details/Messages.js index 7bd6d4b4d..e9f542945 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Messages.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Messages.js @@ -14,12 +14,11 @@ export default { endpoint="$fhcApi.factory.messages.person" type-id="person_id" :id="modelValue.person_id" + messageLayout="listTableTop" show-table > - -
` }; \ No newline at end of file diff --git a/system/phrasesupdate.php b/system/phrasesupdate.php index f25cc72ec..95a505a23 100644 --- a/system/phrasesupdate.php +++ b/system/phrasesupdate.php @@ -37319,6 +37319,206 @@ array( ) ) ), + array( + 'app' => 'core', + 'category' => 'messages', + 'phrase' => 'unread', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'ungelesen', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'unread', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'messages', + 'phrase' => 'read', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'gelesen', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'read', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'messages', + 'phrase' => 'archived', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'archiviert', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'archived', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'messages', + 'phrase' => 'deleted', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'gelöscht', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'deleted', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'messages', + 'phrase' => 'body', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Nachrichtentext', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Body', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'messages', + 'phrase' => 'message_id', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Message ID', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Message ID', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'messages', + 'phrase' => 'sender', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'SenderIn', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Sender', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'messages', + 'phrase' => 'recipient', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'EmpfängerIn', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Recipient', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'messages', + 'phrase' => 'senderId', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'SenderIn ID', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Sender ID', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'messages', + 'phrase' => 'recipientId', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'EmpfängerIn ID', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Recipient ID', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), /////////// FHC4 Phrases Messages END /////////// ); From f89c194d3288d83aec44082fd1f8db4b7010618c Mon Sep 17 00:00:00 2001 From: ma0068 Date: Wed, 19 Feb 2025 11:36:00 +0100 Subject: [PATCH 005/107] add Vorlagendropdown Component and Listboxes for Messaging Variables --- .../api/frontend/v1/messages/Messages.php | 246 +++++++++- .../api/frontend/v1/vorlagen/Vorlagen.php | 63 +++ application/models/system/Message_model.php | 42 ++ application/models/system/Vorlage_model.php | 116 +++++ public/js/api/fhcapifactory.js | 4 +- public/js/api/messages/person.js | 29 ++ public/js/api/vorlagen.js | 8 + .../components/Messages/Details/NewMessage.js | 440 +++++++++++++++++- .../Messages/Details/TableMessages.js | 53 ++- public/js/components/Messages/Messages.js | 6 +- .../Studentenverwaltung/Details/Messages.js | 7 +- .../VorlagenDropdown/VorlagenDropdown.js | 109 +++++ system/phrasesupdate.php | 20 + 13 files changed, 1123 insertions(+), 20 deletions(-) create mode 100644 application/controllers/api/frontend/v1/vorlagen/Vorlagen.php create mode 100644 public/js/api/vorlagen.js create mode 100644 public/js/components/VorlagenDropdown/VorlagenDropdown.js diff --git a/application/controllers/api/frontend/v1/messages/Messages.php b/application/controllers/api/frontend/v1/messages/Messages.php index adf1d52e9..ac107f687 100644 --- a/application/controllers/api/frontend/v1/messages/Messages.php +++ b/application/controllers/api/frontend/v1/messages/Messages.php @@ -9,6 +9,14 @@ class Messages extends FHCAPI_Controller { parent::__construct([ 'getMessages' => ['admin:r', 'assistenz:r'], + 'getVorlagen' => ['admin:r', 'assistenz:r'], + 'getMessageVarsPerson' => ['admin:r', 'assistenz:r'], + 'getMsgVarsPrestudent' => ['admin:r', 'assistenz:r'], + 'getMsgVarsLoggedInUser' => ['admin:r', 'assistenz:r'], + 'getNameOfDefaultRecipient' => ['admin:r', 'assistenz:r'], + 'sendMessage' => ['admin:r', 'assistenz:r'], + 'deleteMessage' => ['admin:r', 'assistenz:r'], + 'getVorlagentext' => ['admin:r', 'assistenz:r'], ]); //Load Models @@ -20,6 +28,7 @@ class Messages extends FHCAPI_Controller // Load Libraries $this->load->library('VariableLib', ['uid' => getAuthUID()]); $this->load->library('form_validation'); + $this->load->library('MessageLib'); // Load language phrases $this->loadPhrases([ @@ -29,11 +38,17 @@ class Messages extends FHCAPI_Controller public function getMessages($id, $type_id) { - //$this->terminateWithError("in backend " . $type_id . ": " . $id, self::ERROR_TYPE_GENERAL); - - if ($type_id != "person_id") + switch($type_id) { - $this->terminateWithError("logic for type_id " . $type_id . " not defined yet", self::ERROR_TYPE_GENERAL); + case 'uid': + $id = $this->_getPersonIdFromUid($id); + break; + case 'person_id': + $id = $id; + break; + default: + $this->terminateWithError("MESSAGES::getMessages logic for type_id " . $type_id . " not defined yet", self::ERROR_TYPE_GENERAL); + break; } $result = $this->MessageModel->getMessagesForTable($id); @@ -42,4 +57,227 @@ class Messages extends FHCAPI_Controller $this->terminateWithSuccess($data); } + + public function getVorlagen() + { + //get oe of user + $uid = getAuthUID(); + $this->load->model('person/Benutzerfunktion_model', 'BenutzerfunktionModel'); + $result = $this->BenutzerfunktionModel->getBenutzerfunktionByUid($uid, 'oezuordnung'); + + $data = $this->getDataOrTerminateWithError($result); + $oe_kurzbz = current($data); + + // $this->terminateWithError("oe: ". $oe_kurzbz->oe_kurzbz, self::ERROR_TYPE_GENERAL); + + $this->load->model('system/Vorlage_model', 'VorlageModel'); + + //39 Stück Variante OE + $result = $this->VorlageModel->getAllVorlagenByOe($oe_kurzbz->oe_kurzbz); + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + + //IF ADMIN 167 + $this->VorlageModel->addOrder('vorlage_kurzbz', 'ASC'); + //only HTML-vorlagen -> for admin + $result = $this->VorlageModel->loadWhere( + array( + 'mimetype' => 'text/html' + )); + + + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + + public function getVorlagentext($vorlage_kurzbz) + { + //$this->terminateWithError("vor " . $vorlage_kurzbz, self::ERROR_TYPE_GENERAL); + //$studiengang_kz = 227; //TODO(Manu) check dynamisieren NULL + $studiengang_kz = 0; + $this->load->model('system/Vorlagestudiengang_model', 'VorlagestudiengangModel'); + $this->VorlagestudiengangModel->addOrder('version', 'DESC'); + + $result = $this->VorlagestudiengangModel->loadWhere( + [ + 'vorlage_kurzbz' =>$vorlage_kurzbz, + 'studiengang_kz' => $studiengang_kz + ]); + + $data = $this->getDataOrTerminateWithError($result); + + //not correct with Vorlage + $vorlage = current($data); + + //$this->terminateWithSuccess($data); + $this->terminateWithSuccess($vorlage->text); + } + + public function getMessageVarsPerson() + { + $result = $this->MessageModel->getMessageVarsPerson(); + + $data = $this->getDataOrTerminateWithError($result); + + + $this->terminateWithSuccess($data); + } + + public function getMsgVarsPrestudent($uid) + { + + $prestudent_id = $this-> _getPrestudentIdFromUid($uid); + + // $this->terminateWithError("prestudent_id " . $prestudent_id, self::ERROR_TYPE_GENERAL); + + $result = $this->MessageModel->getMsgVarsDataByPrestudentId($prestudent_id); + + $data = $this->getDataOrTerminateWithError($result); + + + $this->terminateWithSuccess($data); + } + + public function getMsgVarsLoggedInUser() + { + $uid = getAuthUID(); + + $result = $this->MessageModel->getMsgVarsLoggedInUser(); + + $data = $this->getDataOrTerminateWithError($result); + + + $this->terminateWithSuccess($data); + } + + public function getNameOfDefaultRecipient($id, $type_id) + { + switch($type_id) + { + case 'uid': + $id = $this->_getPersonIdFromUid($id); + break; + case 'person_id': + $id = $id; + break; + default: + $this->terminateWithError("MESSAGES::getNameOfDefaultRecipient logic for type_id " . $type_id . " not defined yet", self::ERROR_TYPE_GENERAL); + break; + } + + $this->load->model('person/Person_model', 'PersonModel'); + + $result = $this->PersonModel->load($id); + //$this->terminateWithSuccess($result); + $data = $this->getDataOrTerminateWithError($result); + $name = current($data); + + $this->terminateWithSuccess($name->vorname . " " . $name->nachname ); + } + + public function sendMessage($recipient_id) + { + //TODO(manu) Problems with Vorlagen... + //TODO(Manu) Problems with VARS + $receiversPersonId = $this->_getPersonIdFromUid($recipient_id); + + $uid = getAuthUID(); + $this->load->model('person/Benutzer_model', 'BenutzerModel'); + $result = $this->BenutzerModel->loadWhere( + ['uid' => $uid] + ); + + $data = $this->getDataOrTerminateWithError($result); + $benutzer = current($data); + + if (isset($_POST['data'])) + { + $data = json_decode($_POST['data']); + unset($_POST['data']); + foreach ($data as $k => $v) { + $_POST[$k] = $v; + } + } + + $subject = $this->input->post('subject'); + + $body = $this->input->post('body'); + + // $this->terminateWithError("rp_id " . $receiversPersonId, self::ERROR_TYPE_GENERAL); + +/* $subject = $this->input->post('subject'); + + $formData = $this->input->post('data');*/ + + //$_POST['subject'] = $formData['subject']; + // $subject = $formData['subject']; + // $body = $formData['body']; + + // $subject = isset($_POST['subject']) ? $_POST['subject'] : null; + // $body = isset($_POST['body']) ? $_POST['body'] : null; + + // $this->terminateWithError("person_id " . $receiversPersonId, self::ERROR_TYPE_GENERAL); + + // $this->terminateWithError("subject " . $subject, self::ERROR_TYPE_GENERAL); + // $this->terminateWithError("body " . $body, self::ERROR_TYPE_GENERAL); + + // $this->terminateWithError("person_id " . $benutzer->person_id, self::ERROR_TYPE_GENERAL); + // $this->terminateWithError("subject " . $subject, self::ERROR_TYPE_GENERAL); + $result = $this->messagelib->sendMessageUser($receiversPersonId, $subject, $body, $benutzer->person_id); + + $this->terminateWithSuccess($result); + } + + public function deleteMessage($messageId) + { + // Start DB transaction + $this->db->trans_begin(); + + $result = $this->MessageModel->deleteMessageRecipient($messageId); + if (isError($result)) { + return $this->terminateWithError($result, self::ERROR_TYPE_GENERAL); + } + + $result = $this->MessageModel->deleteMessageStatus($messageId); + if (isError($result)) { + return $this->terminateWithError($result, self::ERROR_TYPE_GENERAL); + } + + $result = $this->MessageModel->deleteMessage($messageId); + if (isError($result)) { + return $this->terminateWithError($result, self::ERROR_TYPE_GENERAL); + } + + $this->db->trans_commit(); + + $this->terminateWithSuccess($result); + } + + private function _getPersonIdFromUid($uid) + { + $this->load->model('person/Benutzer_model', 'BenutzerModel'); + $result = $this->BenutzerModel->loadWhere( + ['uid' => $uid] + ); + + $data = $this->getDataOrTerminateWithError($result); + $benutzer = current($data); + + return $benutzer->person_id; + } + + private function _getPrestudentIdFromUid($uid) + { + $this->load->model('crm/Student_model', 'StudentModel'); + $result = $this->StudentModel->loadWhere( + ['student_uid' => $uid] + ); + + $data = $this->getDataOrTerminateWithError($result); + $student = current($data); + + return $student->prestudent_id; + } } \ No newline at end of file diff --git a/application/controllers/api/frontend/v1/vorlagen/Vorlagen.php b/application/controllers/api/frontend/v1/vorlagen/Vorlagen.php new file mode 100644 index 000000000..01edb33d1 --- /dev/null +++ b/application/controllers/api/frontend/v1/vorlagen/Vorlagen.php @@ -0,0 +1,63 @@ + ['admin:r', 'assistenz:r'], + 'getVorlagenByLoggedInUser' => ['admin:r', 'assistenz:r'], + ]); + + //Load Models + $this->load->model('system/Vorlage_model', 'VorlageModel'); + + // Additional Permission Checks + //TODO(manu) check permissions + + // Load Libraries + $this->load->library('VariableLib', ['uid' => getAuthUID()]); + $this->load->library('form_validation'); + $this->load->library('VorlageLib'); + + // Load language phrases + $this->loadPhrases([ + 'ui' + ]); + } + + public function getVorlagen() + { + $this->load->model('system/Vorlage_model', 'VorlageModel'); + + $this->VorlageModel->addOrder('vorlage_kurzbz', 'ASC'); + + $result = $this->VorlageModel->loadWhere( + array( + 'mimetype' => 'text/html' + )); + + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + + public function getVorlagenByLoggedInUser() + { + //get oe of user + $uid = getAuthUID(); + $this->load->model('person/Benutzerfunktion_model', 'BenutzerfunktionModel'); + $result = $this->BenutzerfunktionModel->getBenutzerfunktionByUid($uid, 'oezuordnung'); + + $data = $this->getDataOrTerminateWithError($result); + $oe_kurzbz = current($data); + + $result = $this->VorlageModel->getAllVorlagenByOe($oe_kurzbz->oe_kurzbz); + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + +} \ No newline at end of file diff --git a/application/models/system/Message_model.php b/application/models/system/Message_model.php index 1b201fc1b..7ecb54a9e 100644 --- a/application/models/system/Message_model.php +++ b/application/models/system/Message_model.php @@ -282,4 +282,46 @@ class Message_model extends DB_Model return $this->execQuery($sql, $parametersArray); } + + /** + * Deletes a messages from tableMessages and tbl_msg_recipient + * TODO(MANU) CHECK IF NECESSARY + * dependency with other tables + * in case of reply... more messages + * maybe anonimize it + * @param $message_id + * @return boolean success + */ + public function deleteMessageRecipient($message_id) + { + $sql = " + DELETE FROM public.tbl_msg_recipient + WHERE message_id = ?; + "; + + return $this->execQuery($sql, array($message_id)); + } + + + public function deleteMessageStatus($message_id) + { + $sql = " + DELETE FROM public.tbl_msg_status + WHERE message_id = ?; + "; + + return $this->execQuery($sql, array($message_id)); + } + + public function deleteMessage($message_id) + { + $sql = " + DELETE FROM public.tbl_msg_message + WHERE message_id = ?; + "; + + return $this->execQuery($sql, array($message_id)); + } + + } diff --git a/application/models/system/Vorlage_model.php b/application/models/system/Vorlage_model.php index 8022e71fc..69aa0aa3f 100644 --- a/application/models/system/Vorlage_model.php +++ b/application/models/system/Vorlage_model.php @@ -21,4 +21,120 @@ class Vorlage_model extends DB_Model return $this->execQuery($query); } + + /** + * Returns all Vorlagen + * that belongs to the organisation units of the user + * and the parents of those organisation units until the root of the + * @param Array Array of $oe_kurzbz + * @return object Array of Vorlagen + */ + public function getAllVorlagenByOe($oe_kurzbz) + { + // Loads library OrganisationseinheitLib + $this->load->library('OrganisationseinheitLib'); + + $vorlage = success(array()); // Default value + + $table = '( + SELECT v.vorlage_kurzbz, + v.bezeichnung, + vs.version, + vs.oe_kurzbz, + vs.aktiv, + vs.subject, + vs.text, + v.mimetype + FROM tbl_vorlagestudiengang vs + JOIN tbl_vorlage v USING(vorlage_kurzbz) + ) templates'; + + $alias = 'templates'; + + $fields = array( + 'templates.vorlage_kurzbz AS id', + 'templates.bezeichnung || \' (\' || UPPER(templates.oe_kurzbz) || \')\' AS description' + ); + + $where = 'templates.aktiv = TRUE + AND templates.subject IS NOT NULL + AND templates.text IS NOT NULL + AND templates.mimetype = \'text/html\' + GROUP BY 1, 2, 3'; + + $order_by = 'description ASC'; + + if (!is_array($oe_kurzbz)) + { + $vorlage = $this->organisationseinheitlib->treeSearchEntire( + $table, + $alias, + $fields, + $where, + $order_by, + $oe_kurzbz + ); + } + else // is an array + { + // Get the vorlage for each organisation unit + foreach($oe_kurzbz as $val) + { + $tmpVorlage = $this->organisationseinheitlib->treeSearchEntire( + $table, + $alias, + $fields, + $where, + $order_by, + $val + ); + + // Everything is ok and data are inside + if (hasData($tmpVorlage)) + { + // If it's the first vorlage copy it + if (!hasData($vorlage)) + { + for ($j = 0; $j < count(getData($tmpVorlage)); $j++) + { + if (getData($tmpVorlage)[$j]->id != '') + { + array_push($vorlage->retval, getData($tmpVorlage)[$j]); + } + } + } + else // checks for duplicates, if it's not already present push it into the array getData($vorlage) + { + for ($j = 0; $j < count(getData($tmpVorlage)); $j++) + { + $found = false; + $currentTmpVorlageData = null; + + for ($i = 0; $i < count(getData($vorlage)); $i++) + { + $currentTmpVorlageData = getData($tmpVorlage)[$j]; + + if (getData($vorlage)[$i]->id == getData($tmpVorlage)[$j]->id + && getData($vorlage)[$i]->_pk == getData($tmpVorlage)[$j]->_pk + && getData($vorlage)[$i]->_ppk == getData($tmpVorlage)[$j]->_ppk + && getData($vorlage)[$i]->_jtpk == getData($tmpVorlage)[$j]->_jtpk) + { + $found = true; + break; + } + } + + if (!$found && $currentTmpVorlageData->id != '') + { + array_push($vorlage->retval, $currentTmpVorlageData); + } + } + } + } + } + } + + return $vorlage; + } + } diff --git a/public/js/api/fhcapifactory.js b/public/js/api/fhcapifactory.js index 7bc510b6e..8a4a2132a 100644 --- a/public/js/api/fhcapifactory.js +++ b/public/js/api/fhcapifactory.js @@ -34,6 +34,7 @@ import cms from "./cms.js"; import lehre from "./lehre.js"; import addons from "./addons.js"; import messages from "./messages.js"; +import vorlagen from "./vorlagen.js"; export default { search, @@ -54,5 +55,6 @@ export default { cms, lehre, addons, - messages + messages, + vorlagen }; diff --git a/public/js/api/messages/person.js b/public/js/api/messages/person.js index baf8bd39f..6a0ac8c7c 100644 --- a/public/js/api/messages/person.js +++ b/public/js/api/messages/person.js @@ -2,4 +2,33 @@ export default { getMessages(url, config, params){ return this.$fhcApi.get('api/frontend/v1/messages/messages/getMessages/' + params.id + '/' + params.type); }, + getVorlagen(){ + return this.$fhcApi.get('api/frontend/v1/messages/messages/getVorlagen/'); + }, + getMsgVarsLoggedInUser(){ + return this.$fhcApi.get('api/frontend/v1/messages/messages/getMsgVarsLoggedInUser/'); + }, + getMessageVarsPerson(){ + return this.$fhcApi.get('api/frontend/v1/messages/messages/getMessageVarsPerson/'); + }, + getMsgVarsPrestudent(uid){ + return this.$fhcApi.get('api/frontend/v1/messages/messages/getMsgVarsPrestudent/' + uid); + }, + getVorlagentext(vorlage_kurzbz){ + return this.$fhcApi.get('api/frontend/v1/messages/messages/getVorlagentext/' + vorlage_kurzbz); + }, + getNameOfDefaultRecipient(params){ + return this.$fhcApi.get('api/frontend/v1/messages/messages/getNameOfDefaultRecipient/' + params.id + '/' + params.type_id); + }, + sendMessage(form, id, data) { + console.log("factory " + id); + console.log(JSON.stringify(data)); + + return this.$fhcApi.post(form, 'api/frontend/v1/messages/messages/sendMessage/' + id, + data + ); + }, + deleteMessage(messageId){ + return this.$fhcApi.post('api/frontend/v1/messages/messages/deleteMessage/' + messageId); + } } \ No newline at end of file diff --git a/public/js/api/vorlagen.js b/public/js/api/vorlagen.js new file mode 100644 index 000000000..2933ccf97 --- /dev/null +++ b/public/js/api/vorlagen.js @@ -0,0 +1,8 @@ +export default { + getVorlagen() { + return this.$fhcApi.get('api/frontend/v1/vorlagen/vorlagen/getVorlagen/'); + }, + getVorlagenByLoggedInUser() { + return this.$fhcApi.get('api/frontend/v1/vorlagen/vorlagen/getVorlagenByLoggedInUser/'); + } +} \ No newline at end of file diff --git a/public/js/components/Messages/Details/NewMessage.js b/public/js/components/Messages/Details/NewMessage.js index bf60842d2..2d85c8e00 100644 --- a/public/js/components/Messages/Details/NewMessage.js +++ b/public/js/components/Messages/Details/NewMessage.js @@ -1,12 +1,448 @@ +import FormForm from '../../Form/Form.js'; +import FormInput from '../../Form/Input.js'; +import ListBox from "../../../../../index.ci.php/public/js/components/primevue/listbox/listbox.esm.min.js"; +import DropdownComponent from '../../VorlagenDropdown/VorlagenDropdown.js'; + + export default { + components: { + FormForm, + FormInput, + ListBox, + DropdownComponent + }, + props: { + endpoint: { + type: String, + required: true + }, + typeId: String, + id: { + type: [Number, String], + required: true + }, + }, data(){ return { - + formData: { + recipient: this.id, + subject: null, + body: null, + vorlage_kurzbz: null, + selectedValue: '', + }, + statusNew: true, + vorlagen: [], + defaultRecipient: null, + editor: null, + isVisible: true, + fieldsUser: [], + fieldsPerson: [], + fieldsPrestudent: [], + selectedFieldPrestudent: null, + selectedFieldUser: null, + selectedFieldPerson: null, + itemsPrestudent: [], + itemsPerson: [], + itemsUser: [], + selectedFieldStudent: null, + itemsStudent: [ + { label: "Variable 1", value: "var1" }, + { label: "Variable 2", value: "var2" }, + { label: "Variable 3", value: "var3" } + ] } }, + methods: { + initTinyMCE() { + const vm = this; + tinymce.init({ + target: this.$refs.editor.$refs.input, //Important: not selector: to enable multiple import of component + //height: 800, + //plugins: ['lists'], + toolbar: 'styleselect | bold italic underline | alignleft aligncenter alignright alignjustify', + style_formats: [ + {title: 'Blocks', block: 'div'}, + {title: 'Paragraph', block: 'p'}, + {title: 'Heading 1', block: 'h1'}, + {title: 'Heading 2', block: 'h2'}, + {title: 'Heading 3', block: 'h3'}, + {title: 'Heading 4', block: 'h4'}, + {title: 'Heading 5', block: 'h5'}, + {title: 'Heading 6', block: 'h6'}, + ], + autoresize_bottom_margin: 16, + + setup: (editor) => { + vm.editor = editor; + + editor.on('input', () => { + const newContent = editor.getContent(); + vm.formData.body = newContent; + }); + }, + }); + }, + updateText(value) { + this.formData.body = value; + }, + sendMessage(){ + //TODO(Manu) check default recipient(s) + const data = new FormData(); + + data.append('data', JSON.stringify(this.formData)); + return this.$fhcApi.factory.messages.person.sendMessage(this.$refs.formVorlage, this.id, data) + .then(response => { + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSent')); + //this.hideModal('messageModal'); + this.resetForm(); + }).catch(this.$fhcAlert.handleSystemError) + .finally(() => { + //this.resetForm(); + //closeModal + //closewindwo + } + ); + }, + getVorlagentext(vorlage_kurzbz){ + //console.log(typeof vorlage_kurzbz); + return this.$fhcApi.factory.messages.person.getVorlagentext(vorlage_kurzbz) + .then(response => { + //this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSent')); + //this.hideModal('messageModal'); + //this.resetForm(); + //TODO(Manu) CHECK + this.formData.body = response.data; + }).catch(this.$fhcAlert.handleSystemError) + .finally(() => { + //this.resetForm(); + //closeModal + //closewindwo + }); + }, + insertVariable(selectedItem){ + if (this.editor) { + this.editor.insertContent(selectedItem.value + " "); + } else { + console.error("Editor instance is not available."); + } + }, + //TODO(Manu) refactor +/* insertVariablePrestudent() { + if (this.editor) { + //const lastVariable = this.selectedFieldsPrestudent[this.selectedFieldsPrestudent.length - 1].value; + const lastVariable = this.selectedFieldPrestudent.value; + + //Use insertContent method + this.editor.insertContent(lastVariable + " "); + } else { + console.error("Editor instance is not available."); + } + },*/ +/* insertVariablePrestudentByClick(selectedItem) { + + if (selectedItem) { + this.editor.insertContent(selectedItem.value + " "); + console.log("Eingefügte Variable:", selectedItem); + } else { + console.warn("Keine Variable ausgewählt!"); + } + }, + + insertVariablePerson() { + if (this.editor) { + //const lastVariable = this.selectedFieldsPrestudent[this.selectedFieldsPrestudent.length - 1].value; + const lastVariable = this.selectedFieldPerson.value; + + //Use insertContent method + this.editor.insertContent(lastVariable + " "); + } else { + console.error("Editor instance is not available."); + } + }, + insertVariableUser() { + if (this.editor) { + console.log(this.selectedFieldUser.value); + const lastVariable = this.selectedFieldUser.value; + + //Multiple + //const lastVariable = this.selectedFieldsPrestudent[this.selectedFieldsPrestudent.length - 1].value; + + //Use insertContent method + this.editor.insertContent(lastVariable + " "); + this.selectedFieldUser = null; + } else { + console.error("Editor instance is not available."); + } + }, + insertVariableStudent(selectedItem) { + if (selectedItem) { + console.log("Eingefügte Variable:", selectedItem); + this.editor.insertContent(selectedItem.value + " "); + } else { + console.warn("Keine Variable ausgewählt!"); + } + },*/ + replyMessage(message_id){ + console.log("auf message " + message_id + " antworten"); + }, + resetForm(){ + this.formData = { + vorlage_kurzbz: null, + body: null, + subject: null, + }; + if (this.editor) { + this.editor.setContent(""); + } + this.$refs.dropdownComp.setValue(null); + + }, + toggleDivNewMessage(){ + this.isVisible = !this.isVisible; + }, + handleSelectedVorlage(vorlage_kurzbz) { + if (typeof vorlage_kurzbz === "string") { + this.getVorlagentext(vorlage_kurzbz); + this.formData.subject = vorlage_kurzbz; + } + }, + }, + watch: { + 'formData.body': { + handler(newVal) { + const tinymcsVal = this.editor.getContent(); + + if (newVal && tinymcsVal != newVal) { + //Inhalt des Editors aktualisieren + this.editor.setContent(newVal); + } + } + }, + 'formData.vorlage_kurzbz': { + handler(newVal){ + // console.log("Vorlage: " + newVal); + + if (newVal && newVal != null) { + this.formData.subject = newVal; + return this.getVorlagentext(newVal); + } + //TODO(Manu) own function or retval to getVorlagentext + //component VorlagenComponent + + } + } + }, + created(){ + + if(this.typeId == 'person_id'){ + this.$fhcApi.factory.messages.person.getMessageVarsPerson() + .then(result => { + this.fieldsPerson = result.data; + this.itemsPerson = Object.entries(this.fieldsPerson).map(([key, value]) => ({ + label: value, + value: '{' + value + '}' + })); + }) + .catch(this.$fhcAlert.handleSystemError); + } + + if(this.typeId == 'uid') { + this.$fhcApi.factory.messages.person.getMsgVarsPrestudent(this.id) + .then(result => { + this.fieldsPrestudent = result.data; + const prestudent = this.fieldsPrestudent[0]; + //Just for testing with inserting values +/* this.itemsPrestudent = Object.entries(prestudent).map(([key, value]) => ({ + label: key, + value: value + }));*/ + this.itemsPrestudent = Object.entries(prestudent).map(([key, value]) => ({ + label: key, + value: '{' + key + '}' + })); + }) + .catch(this.$fhcAlert.handleSystemError); + } + + this.$fhcApi.factory.messages.person.getMsgVarsLoggedInUser() + .then(result => { + this.fieldsUser = result.data; + const user = this.fieldsUser; + this.itemsUser = Object.entries(user).map(([key, value]) => ({ + label: value, + value: '{' + value + '}' + })); + }) + .catch(this.$fhcAlert.handleSystemError); + + this.$fhcApi.factory.messages.person.getNameOfDefaultRecipient({ + id: this.id, + type_id: this.typeId}) + .then(result => { + this.defaultRecipient = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + }, + async mounted() { + this.initTinyMCE(); + }, + beforeDestroy() { + this.editor.destroy(); + }, template: `
-

New Message

+ +
+

New Message

+ + {{typeId}} {{id}} + + {{formData.subject}} + {{formData.vorlage_kurzbz}} + +

+ formData.body befüllt +

+ +
+ +
+ + + +
+ + + +
+ +
+ + +
+ + +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+ Felder Prestudent +
+ + + + + +
+ + +

{{selectedFieldPrestudent}}

+ +
+ +
+ Felder Person +
+ + + + + +
+ +

{{selectedFieldPerson}}

+
+ +
+ Meine Felder +
+ + + + + +
+ +
+ + +
+ + + + + +
+ +
+ +
+
+ +
+ +
` diff --git a/public/js/components/Messages/Details/TableMessages.js b/public/js/components/Messages/Details/TableMessages.js index c4fd4d4d7..0025d7b47 100644 --- a/public/js/components/Messages/Details/TableMessages.js +++ b/public/js/components/Messages/Details/TableMessages.js @@ -1,12 +1,15 @@ import {CoreFilterCmpt} from "../../filter/Filter.js"; import FormForm from '../../Form/Form.js'; -//import FormInput from '../../Form/Input.js'; export default { components: { CoreFilterCmpt, FormForm, - // FormInput + }, + inject: { + cisRoot: { + from: 'cisRoot' + }, }, props: { endpoint: { @@ -121,7 +124,7 @@ export default { button.addEventListener( 'click', () => - this.deleteMessage(cell.getData().message_id) + this.actionDeleteMessage(cell.getData().message_id) ); container.append(button); @@ -197,7 +200,6 @@ export default { const selectedMessage = row.getData().message_id; const body = row.getData().body; this.previewBody = body; - console.log(selectedMessage); } }, ], @@ -209,11 +211,45 @@ export default { reply(message_id){ console.log("in reply " + message_id); }, + actionDeleteMessage(message_id){ + this.$fhcAlert + .confirmDelete() + .then(result => result + ? message_id + : Promise.reject({handled: true})) + .then(this.deleteMessage) + .catch(this.$fhcAlert.handleSystemError); + }, deleteMessage(message_id){ - console.log("deleteMessage " + message_id); + // console.log("deleteMessage " + message_id); + return this.$fhcApi.factory.messages.person.deleteMessage(message_id) + .then(response => { + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successDelete')); + }).catch(this.$fhcAlert.handleSystemError) + .finally(()=> { + window.scrollTo(0, 0); + this.reload(); + }); }, actionNewMessage(){ - console.log("action new message"); + //console.log("action new message"); + if (this.openMode == "window") { + console.log("openInNewWindow") + const linkWindowNewMessage = this.cisRoot + '/public/js/components/Messages/Details/NewMessage.js'; + window.open(linkWindowNewMessage, '_blank'); + } + else if (this.openmode == "modal"){ + console.log("open with bootstrap Modal"); + } + else if (this.openmode == "showDiv"){ + console.log("open div in NewMessage.js"); + //emit to NewMessage.js + } + else + console.log("no valid openmode: yet to be developed"); + }, + reload() { + this.$refs.table.reloadTable(); }, }, computed: { @@ -238,8 +274,9 @@ export default { }, template: `
-

endpoint: {{endpoint}}

-

{{messageLayout}}

+ + +
diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Messages.js b/public/js/components/Stv/Studentenverwaltung/Details/Messages.js index e9f542945..14d74e56c 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Messages.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Messages.js @@ -12,10 +12,11 @@ export default { diff --git a/public/js/components/VorlagenDropdown/VorlagenDropdown.js b/public/js/components/VorlagenDropdown/VorlagenDropdown.js new file mode 100644 index 000000000..e4c48501a --- /dev/null +++ b/public/js/components/VorlagenDropdown/VorlagenDropdown.js @@ -0,0 +1,109 @@ +import {CoreFilterCmpt} from "../filter/Filter.js"; +import FormForm from '../Form/Form'; +import FormInput from '../Form/Input.js'; + +export default { + components: { + FormForm, + FormInput, + CoreFilterCmpt + }, + props: { + label: { + type: String, + required: true + }, + modelValue: { + type: String, + required: true + }, +/* oe: { + type: Array, + required: false + }, */ + isAdmin: { + type: Boolean, + required: true + }, + useLoggedInUserOe: { + type: Boolean, + required: true + } + }, + data() { + return { + vorlagen: [], + selectedValue: null, + vorlagenOe: [] + } + }, + methods: { + updateValue() { + // console.log("in COMPO: update: " + this.selectedValue + ' jetzt ' + 'InfocenterMailErgaenzungsprfEng'); + this.$emit('change', this.selectedValue); + //this.$emit('change', this.selectedValue); // Emit-Event beim Ändern des Wertes + }, + setValue(value) { + this.selectedValue = value; + }, + }, + created() { + + if(this.isAdmin) { + this.$fhcApi.factory.vorlagen.getVorlagen() + .then(result => { + this.vorlagen = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + } + + if(this.useLoggedInUserOe){ + this.$fhcApi.factory.vorlagen.getVorlagenByLoggedInUser() + .then(result => { + console.log(this.vorlagenOe); + this.vorlagenOe = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + } + }, +template: ` +
+
+ + + +
+ +
+ + + +
+ +
+ `, +} \ No newline at end of file diff --git a/system/phrasesupdate.php b/system/phrasesupdate.php index 95a505a23..63cf34038 100644 --- a/system/phrasesupdate.php +++ b/system/phrasesupdate.php @@ -37519,6 +37519,26 @@ array( ) ) ), + array( + 'app' => 'core', + 'category' => 'ui', + 'phrase' => 'successSent', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Nachricht erfolgreich versandt', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Message sent successfully', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), /////////// FHC4 Phrases Messages END /////////// ); From 3c34b17d2d37dcc87489cdf26d478e44a01fbe33 Mon Sep 17 00:00:00 2001 From: ma0068 Date: Fri, 21 Feb 2025 14:58:59 +0100 Subject: [PATCH 006/107] add Preview-logic, update function sendMessage --- .../api/frontend/v1/messages/Messages.php | 96 +++- application/models/system/Message_model.php | 1 - public/js/api/messages/person.js | 12 +- .../components/Messages/Details/NewMessage.js | 411 +++++++++++------- .../Messages/Details/TableMessages.js | 10 +- public/js/components/Messages/Messages.js | 33 +- .../Studentenverwaltung/Details/Messages.js | 2 + .../VorlagenDropdown/VorlagenDropdown.js | 8 +- 8 files changed, 368 insertions(+), 205 deletions(-) diff --git a/application/controllers/api/frontend/v1/messages/Messages.php b/application/controllers/api/frontend/v1/messages/Messages.php index ac107f687..788c8861e 100644 --- a/application/controllers/api/frontend/v1/messages/Messages.php +++ b/application/controllers/api/frontend/v1/messages/Messages.php @@ -17,10 +17,12 @@ class Messages extends FHCAPI_Controller 'sendMessage' => ['admin:r', 'assistenz:r'], 'deleteMessage' => ['admin:r', 'assistenz:r'], 'getVorlagentext' => ['admin:r', 'assistenz:r'], + 'getPreviewText' => ['admin:r', 'assistenz:r'], ]); //Load Models $this->load->model('system/Message_model', 'MessageModel'); + $this->load->model('CL/Messages_model', 'MessagesModel'); // Additional Permission Checks //TODO(manu) check permissions @@ -179,8 +181,7 @@ class Messages extends FHCAPI_Controller public function sendMessage($recipient_id) { - //TODO(manu) Problems with Vorlagen... - //TODO(Manu) Problems with VARS + //default setting $receiversPersonId = $this->_getPersonIdFromUid($recipient_id); $uid = getAuthUID(); @@ -201,35 +202,94 @@ class Messages extends FHCAPI_Controller } } - $subject = $this->input->post('subject'); + $this->load->library('form_validation'); + $this->form_validation->set_rules('subject', 'Betreff', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Betreff']) + ]); + + $this->form_validation->set_rules('body', 'Text', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Text']) + ]); + + if ($this->form_validation->run() == false) + { + $this->terminateWithValidationErrors($this->form_validation->error_array()); + } + + $subject = $this->input->post('subject'); $body = $this->input->post('body'); - // $this->terminateWithError("rp_id " . $receiversPersonId, self::ERROR_TYPE_GENERAL); -/* $subject = $this->input->post('subject'); - $formData = $this->input->post('data');*/ + $typeId = $this->input->post('type_id'); + $id = $this->input->post('id'); - //$_POST['subject'] = $formData['subject']; - // $subject = $formData['subject']; - // $body = $formData['body']; + if($typeId == 'uid') + { + //$this->terminateWithError("uid ", self::ERROR_TYPE_GENERAL); + $prestudent_id = $this-> _getPrestudentIdFromUid($id); - // $subject = isset($_POST['subject']) ? $_POST['subject'] : null; - // $body = isset($_POST['body']) ? $_POST['body'] : null; + //parseMessagetext for variables Prestudent + $result = $this->MessagesModel->parseMessageTextPrestudent($prestudent_id, $body); + $bodyParsed = $this->getDataOrTerminateWithError($result); + } + elseif($typeId == 'person_id') + { + $this->terminateWithError("person_id ", self::ERROR_TYPE_GENERAL); - // $this->terminateWithError("person_id " . $receiversPersonId, self::ERROR_TYPE_GENERAL); + $result = $this->MessagesModel->parseMessageTextPerson($id, $body); + $bodyParsed = $this->getDataOrTerminateWithError($result); + } + elseif($typeId == 'prestudent_id') + { + $this->terminateWithError("prestudent_id ", self::ERROR_TYPE_GENERAL); - // $this->terminateWithError("subject " . $subject, self::ERROR_TYPE_GENERAL); - // $this->terminateWithError("body " . $body, self::ERROR_TYPE_GENERAL); + $result = $this->MessagesModel->parseMessageTextPrestudent($id, $body); + $bodyParsed = $this->getDataOrTerminateWithError($result); + } + else + { + $this->terminateWithError("type_id " . $typeId . " not valid", self::ERROR_TYPE_GENERAL); + } - // $this->terminateWithError("person_id " . $benutzer->person_id, self::ERROR_TYPE_GENERAL); - // $this->terminateWithError("subject " . $subject, self::ERROR_TYPE_GENERAL); - $result = $this->messagelib->sendMessageUser($receiversPersonId, $subject, $body, $benutzer->person_id); + $result = $this->messagelib->sendMessageUser($receiversPersonId, $subject, $bodyParsed, $benutzer->person_id); $this->terminateWithSuccess($result); } + public function getPreviewText($id, $type_id) + { + if (isset($_POST['data'])) + { + $data = json_decode($_POST['data']); + unset($_POST['data']); + + } + else + $this->terminateWithError("Textbody missing ", self::ERROR_TYPE_GENERAL); + + switch($type_id) + { + case 'uid': + $prestudent_id = $this->_getPrestudentIdFromUid($id); + $result = $this->MessagesModel->parseMessageTextPrestudent($prestudent_id, $data); + + break; + case 'person_id': + $id = $id; + break; + default: + $this->terminateWithError("MESSAGES::getPreviewText logic for type_id " . $type_id . " not defined yet", self::ERROR_TYPE_GENERAL); + break; + } + + //$this->terminateWithSuccess($result); + $bodyParsed = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($bodyParsed); + } + public function deleteMessage($messageId) { // Start DB transaction @@ -238,6 +298,7 @@ class Messages extends FHCAPI_Controller $result = $this->MessageModel->deleteMessageRecipient($messageId); if (isError($result)) { return $this->terminateWithError($result, self::ERROR_TYPE_GENERAL); + return $this->terminateWithError($result, self::ERROR_TYPE_GENERAL); } $result = $this->MessageModel->deleteMessageStatus($messageId); @@ -265,6 +326,7 @@ class Messages extends FHCAPI_Controller $data = $this->getDataOrTerminateWithError($result); $benutzer = current($data); + //return $data->person_id; return $benutzer->person_id; } diff --git a/application/models/system/Message_model.php b/application/models/system/Message_model.php index 7ecb54a9e..0fdb39736 100644 --- a/application/models/system/Message_model.php +++ b/application/models/system/Message_model.php @@ -323,5 +323,4 @@ class Message_model extends DB_Model return $this->execQuery($sql, array($message_id)); } - } diff --git a/public/js/api/messages/person.js b/public/js/api/messages/person.js index 6a0ac8c7c..5cbb49550 100644 --- a/public/js/api/messages/person.js +++ b/public/js/api/messages/person.js @@ -20,13 +20,13 @@ export default { getNameOfDefaultRecipient(params){ return this.$fhcApi.get('api/frontend/v1/messages/messages/getNameOfDefaultRecipient/' + params.id + '/' + params.type_id); }, + getPreviewText(params, data){ + return this.$fhcApi.post('api/frontend/v1/messages/messages/getPreviewText/' + params.id + '/' + params.type_id, + data); + }, sendMessage(form, id, data) { - console.log("factory " + id); - console.log(JSON.stringify(data)); - - return this.$fhcApi.post(form, 'api/frontend/v1/messages/messages/sendMessage/' + id, - data - ); + return this.$fhcApi.post(form,'api/frontend/v1/messages/messages/sendMessage/' + id, + data); }, deleteMessage(messageId){ return this.$fhcApi.post('api/frontend/v1/messages/messages/deleteMessage/' + messageId); diff --git a/public/js/components/Messages/Details/NewMessage.js b/public/js/components/Messages/Details/NewMessage.js index 2d85c8e00..c8aae2124 100644 --- a/public/js/components/Messages/Details/NewMessage.js +++ b/public/js/components/Messages/Details/NewMessage.js @@ -3,7 +3,6 @@ import FormInput from '../../Form/Input.js'; import ListBox from "../../../../../index.ci.php/public/js/components/primevue/listbox/listbox.esm.min.js"; import DropdownComponent from '../../VorlagenDropdown/VorlagenDropdown.js'; - export default { components: { FormForm, @@ -21,6 +20,7 @@ export default { type: [Number, String], required: true }, + openMode: String, }, data(){ return { @@ -45,12 +45,14 @@ export default { itemsPrestudent: [], itemsPerson: [], itemsUser: [], - selectedFieldStudent: null, +/* selectedFieldStudent: null, itemsStudent: [ { label: "Variable 1", value: "var1" }, { label: "Variable 2", value: "var2" }, { label: "Variable 3", value: "var3" } - ] + ]*/ + previewText: null, + previewBody: "" } }, methods: { @@ -86,22 +88,35 @@ export default { updateText(value) { this.formData.body = value; }, - sendMessage(){ + sendMessage() { //TODO(Manu) check default recipient(s) const data = new FormData(); + const params = { + id: this.id, + type_id: this.typeId + }; + const merged = { + ...this.formData, + ...params + }; + data.append('data', JSON.stringify(merged)); - data.append('data', JSON.stringify(this.formData)); - return this.$fhcApi.factory.messages.person.sendMessage(this.$refs.formVorlage, this.id, data) + return this.$fhcApi.factory.messages.person.sendMessage( + this.$refs.formMessage, + this.id, + data) .then(response => { this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSent')); //this.hideModal('messageModal'); + this.hideTemplate(); this.resetForm(); }).catch(this.$fhcAlert.handleSystemError) .finally(() => { - //this.resetForm(); - //closeModal - //closewindwo - } + //this.resetForm(); + //closeModal + //closewindwo + this.$emit('reloadTable'); + } ); }, getVorlagentext(vorlage_kurzbz){ @@ -120,9 +135,37 @@ export default { //closewindwo }); }, + getPreviewText(){ + const data = new FormData(); + + data.append('data', JSON.stringify(this.formData.body)); + return this.$fhcApi.factory.messages.person.getPreviewText({ + id: this.id, + type_id: this.typeId}, data) + .then(response => { + this.previewText = response.data; + }).catch(this.$fhcAlert.handleSystemError) + .finally(() => { + //this.resetForm(); + //closeModal + //closewindwo + }); + }, insertVariable(selectedItem){ if (this.editor) { this.editor.insertContent(selectedItem.value + " "); + //TODO(Manu) check: nicht mal mit Punkt adden gehts ohne eintrag nach vars +/* this.editor.focus(); + this.editor.setDirty(true);*/ + + //this.editor.fire('change'); //forces + + //this.editor.undoManager.add(); + + //this.editor.insertContent(selectedItem.value + "\u00A0"); + //this.editor.insertContent(`${selectedItem.value} `); + //this.editor.selection.setCursorLocation(this.editor.getBody(), 1); + } else { console.error("Editor instance is not available."); } @@ -207,6 +250,19 @@ export default { this.formData.subject = vorlage_kurzbz; } }, + hideTemplate(){ + if (this.openMode == "showDiv") + this.isVisible = false; + }, + showTemplate(){ + if (this.openMode == "showDiv") + this.isVisible = true; + }, + showPreview(){ + this.getPreviewText().then(() => { + this.previewBody = this.previewText; + }); + } }, watch: { 'formData.body': { @@ -227,14 +283,10 @@ export default { this.formData.subject = newVal; return this.getVorlagentext(newVal); } - //TODO(Manu) own function or retval to getVorlagentext - //component VorlagenComponent - } } }, created(){ - if(this.typeId == 'person_id'){ this.$fhcApi.factory.messages.person.getMessageVarsPerson() .then(result => { @@ -246,7 +298,6 @@ export default { }) .catch(this.$fhcAlert.handleSystemError); } - if(this.typeId == 'uid') { this.$fhcApi.factory.messages.person.getMsgVarsPrestudent(this.id) .then(result => { @@ -258,8 +309,8 @@ export default { value: value }));*/ this.itemsPrestudent = Object.entries(prestudent).map(([key, value]) => ({ - label: key, - value: '{' + key + '}' + label: key.toLowerCase(), + value: '{' + key.toLowerCase() + '}' })); }) .catch(this.$fhcAlert.handleSystemError); @@ -292,157 +343,185 @@ export default { }, template: `
- -
-

New Message

- - {{typeId}} {{id}} - - {{formData.subject}} - {{formData.vorlage_kurzbz}} - -

- formData.body befüllt -

- -
- -
- - - -
- - - -
- -
- - -
- - -
- - -
- -
- - -
- -
-
- -
- -
- Felder Prestudent -
- - - - - -
- - -

{{selectedFieldPrestudent}}

- -
- -
- Felder Person -
- - - - - -
- -

{{selectedFieldPerson}}

-
- -
- Meine Felder -
- - - - - -
- -
- - -
- - - - - -
- -
- -
-
- -
+

+ +
+
+ +

New Message

+ + +
+
+ + + +
+ + + +
+ +
+ + +
+ + +
+ + +
+ +
+ + +
+ +
+
+ +
+
+ Felder Prestudent +
+ + + + + +
+ + +

{{selectedFieldPrestudent}}

+ +
+ +
+ Felder Person +
+ + + + + +
+ +

{{selectedFieldPerson}}

+
+ +
+ Meine Felder +
+ + + + + +
+ +
+ +
+ + + + + +
+ +
+ +
+ +
+ +

Vorschau:

+
+ + +
+ + +
+ +
+
+ +
+
+ +
+
+
+
+
+ +
+ +
+ +
+ +
+
` diff --git a/public/js/components/Messages/Details/TableMessages.js b/public/js/components/Messages/Details/TableMessages.js index 0025d7b47..10210ece4 100644 --- a/public/js/components/Messages/Details/TableMessages.js +++ b/public/js/components/Messages/Details/TableMessages.js @@ -22,6 +22,7 @@ export default { required: true }, messageLayout: String, + openMode: String }, //TODO(Manu) endpoint macht Probleme data(){ @@ -238,15 +239,14 @@ export default { const linkWindowNewMessage = this.cisRoot + '/public/js/components/Messages/Details/NewMessage.js'; window.open(linkWindowNewMessage, '_blank'); } - else if (this.openmode == "modal"){ + else if (this.openMode == "modal"){ console.log("open with bootstrap Modal"); } - else if (this.openmode == "showDiv"){ - console.log("open div in NewMessage.js"); - //emit to NewMessage.js + else if (this.openMode == "showDiv"){ + this.$emit('showNewMessageTemplate'); } else - console.log("no valid openmode: yet to be developed"); + console.log("no valid openMode"); }, reload() { this.$refs.table.reloadTable(); diff --git a/public/js/components/Messages/Messages.js b/public/js/components/Messages/Messages.js index a7cccb8cb..f862ebc46 100644 --- a/public/js/components/Messages/Messages.js +++ b/public/js/components/Messages/Messages.js @@ -28,31 +28,56 @@ export default { ].includes(value) } }, + openMode: { + type: String, + default: 'window', + validator(value) { + return [ + 'window', + 'modal', + 'showDiv' + ].includes(value) + } + } }, data() { return {} }, + methods: { + showNewMessageTemplate(){ + this.$refs.templateNewMessage.showTemplate(); + }, + reloadTable(){ + this.$refs.templateTableMessage.reload(); + } + }, template: `
- - +
- - +
diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Messages.js b/public/js/components/Stv/Studentenverwaltung/Details/Messages.js index 14d74e56c..bc07401e6 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Messages.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Messages.js @@ -1,4 +1,5 @@ import CoreMessages from "../../../Messages/Messages.js"; +//import CoreMessages from "@/Messages/Messages.js"; export default { components: { @@ -17,6 +18,7 @@ export default { messageLayout="twoColumnsTableLeft" show-table show-new + open-mode="showDiv" > diff --git a/public/js/components/VorlagenDropdown/VorlagenDropdown.js b/public/js/components/VorlagenDropdown/VorlagenDropdown.js index e4c48501a..b074711f4 100644 --- a/public/js/components/VorlagenDropdown/VorlagenDropdown.js +++ b/public/js/components/VorlagenDropdown/VorlagenDropdown.js @@ -1,5 +1,5 @@ import {CoreFilterCmpt} from "../filter/Filter.js"; -import FormForm from '../Form/Form'; +import FormForm from '../Form/Form.js'; import FormInput from '../Form/Input.js'; export default { @@ -39,16 +39,13 @@ export default { }, methods: { updateValue() { - // console.log("in COMPO: update: " + this.selectedValue + ' jetzt ' + 'InfocenterMailErgaenzungsprfEng'); this.$emit('change', this.selectedValue); - //this.$emit('change', this.selectedValue); // Emit-Event beim Ändern des Wertes }, setValue(value) { this.selectedValue = value; }, }, - created() { - + created() { if(this.isAdmin) { this.$fhcApi.factory.vorlagen.getVorlagen() .then(result => { @@ -103,7 +100,6 @@ template: `
-
`, } \ No newline at end of file From f9f185bfef0291274011e99fe057da8a3b42f994 Mon Sep 17 00:00:00 2001 From: ma0068 Date: Thu, 27 Feb 2025 14:06:25 +0100 Subject: [PATCH 007/107] Views modal, new tab, new page, app and controller for newMessage to open in tab or window --- application/controllers/NeueNachricht.php | 30 ++ .../api/frontend/v1/messages/Messages.php | 2 +- application/views/Nachrichten.php | 48 ++ public/js/apps/Messages/NewMessage.js | 27 + public/js/apps/Nachrichten.js | 25 + .../components/Messages/Details/NewMessage.js | 92 +--- .../Messages/Details/NewMessage/Modal.js | 468 +++++++++++++++++ .../Messages/Details/NewMessage/NewDiv.js | 488 ++++++++++++++++++ .../Messages/Details/TableMessages.js | 32 +- public/js/components/Messages/Messages.js | 108 +++- .../Studentenverwaltung/Details/Messages.js | 2 +- .../VorlagenDropdown/VorlagenDropdown.js | 2 +- 12 files changed, 1218 insertions(+), 106 deletions(-) create mode 100644 application/controllers/NeueNachricht.php create mode 100644 application/views/Nachrichten.php create mode 100644 public/js/apps/Messages/NewMessage.js create mode 100644 public/js/apps/Nachrichten.js create mode 100644 public/js/components/Messages/Details/NewMessage/Modal.js create mode 100644 public/js/components/Messages/Details/NewMessage/NewDiv.js diff --git a/application/controllers/NeueNachricht.php b/application/controllers/NeueNachricht.php new file mode 100644 index 000000000..9e9e0a39b --- /dev/null +++ b/application/controllers/NeueNachricht.php @@ -0,0 +1,30 @@ +method] = ['vertrag/mitarbeiter:r']; + parent::__construct($permissions); + + // Load Libraries + $this->load->library('VariableLib', ['uid' => getAuthUID()]); + } + + /** + * @return void + */ + public function _remap() + { + //now working + $this->load->view('Nachrichten', [ + 'permissions' => [ + 'vertragsverwaltung_schreibrechte' => $this->permissionlib->isBerechtigt('vertrag/mitarbeiter', 'suid') + ] + ]); + } +} diff --git a/application/controllers/api/frontend/v1/messages/Messages.php b/application/controllers/api/frontend/v1/messages/Messages.php index 788c8861e..4bc9a13ab 100644 --- a/application/controllers/api/frontend/v1/messages/Messages.php +++ b/application/controllers/api/frontend/v1/messages/Messages.php @@ -129,7 +129,7 @@ class Messages extends FHCAPI_Controller public function getMsgVarsPrestudent($uid) { - + //$this->terminateWithError($uid, self::ERROR_TYPE_GENERAL); $prestudent_id = $this-> _getPrestudentIdFromUid($uid); // $this->terminateWithError("prestudent_id " . $prestudent_id, self::ERROR_TYPE_GENERAL); diff --git a/application/views/Nachrichten.php b/application/views/Nachrichten.php new file mode 100644 index 000000000..cf34bfd53 --- /dev/null +++ b/application/views/Nachrichten.php @@ -0,0 +1,48 @@ + 'Nachrichten', + 'axios027' => true, + 'bootstrap5' => true, + 'fontawesome6' => true, + 'vue3' => true, + 'primevue3' => true, + #'filtercomponent' => true, + 'tabulator5' => true, + 'tinymce5' => true, + 'phrases' => array( + 'global', + 'ui', + ), + 'customCSSs' => [ + 'public/css/components/vue-datepicker.css', + 'public/css/components/primevue.css', + ], + 'customJSs' => [ + #'vendor/npm-asset/primevue/tree/tree.min.js', + #'vendor/npm-asset/primevue/toast/toast.min.js' + ], + 'customJSModules' => [ + 'public/js/apps/Nachrichten.js' + ] +); + +$this->load->view('templates/FHC-Header', $includesArray); +?> + + !defined('DOMAIN') ? 'notDefined' : DOMAIN, +]; +?> + +
+ + +
+ +load->view('templates/FHC-Footer', $includesArray); ?> + diff --git a/public/js/apps/Messages/NewMessage.js b/public/js/apps/Messages/NewMessage.js new file mode 100644 index 000000000..693c8b0e2 --- /dev/null +++ b/public/js/apps/Messages/NewMessage.js @@ -0,0 +1,27 @@ +//TODO Manu +//use this instead of Nachrichten.js +import NewMessage from "../../components/Messages/Details/NewMessage/NewDiv.js"; +import Phrasen from "../../plugin/Phrasen.js"; + +const ciPath = FHC_JS_DATA_STORAGE_OBJECT.app_root.replace(/(https:|)(^|\/\/)(.*?\/)/g, '') + FHC_JS_DATA_STORAGE_OBJECT.ci_router; + +const router = VueRouter.createRouter({ + history: VueRouter.createWebHistory(), + routes: [ + { path: `/${ciPath}/NeueNachricht`, component: NewMessage }, + { path: `/${ciPath}/NeueNachricht/:id`, component: NewMessage }, + { path: `/${ciPath}/NeueNachricht/:id/:typeId`, component: NewMessage }, + ] +}); + +const app = Vue.createApp(); + +app + .use(router) + .use(primevue.config.default, { + zIndex: { + overlay: 1100 + } + }) + .use(Phrasen) + .mount('#main'); diff --git a/public/js/apps/Nachrichten.js b/public/js/apps/Nachrichten.js new file mode 100644 index 000000000..0f921a9f8 --- /dev/null +++ b/public/js/apps/Nachrichten.js @@ -0,0 +1,25 @@ +import NewMessage from "../components/Messages/Details/NewMessage/NewDiv.js"; + +import Phrasen from "../plugin/Phrasen.js"; + +const ciPath = FHC_JS_DATA_STORAGE_OBJECT.app_root.replace(/(https:|)(^|\/\/)(.*?\/)/g, '') + FHC_JS_DATA_STORAGE_OBJECT.ci_router; + +const router = VueRouter.createRouter({ + history: VueRouter.createWebHistory(), + routes: [ + { path: `/${ciPath}/NeueNachricht/:id/:typeId`, component: NewMessage }, + ] +}); + + +const app = Vue.createApp(); + +app + .use(router) + .use(primevue.config.default, { + zIndex: { + overlay: 1100 + } + }) + .use(Phrasen) + .mount('#main'); \ No newline at end of file diff --git a/public/js/components/Messages/Details/NewMessage.js b/public/js/components/Messages/Details/NewMessage.js index c8aae2124..33ff74d9c 100644 --- a/public/js/components/Messages/Details/NewMessage.js +++ b/public/js/components/Messages/Details/NewMessage.js @@ -2,13 +2,15 @@ import FormForm from '../../Form/Form.js'; import FormInput from '../../Form/Input.js'; import ListBox from "../../../../../index.ci.php/public/js/components/primevue/listbox/listbox.esm.min.js"; import DropdownComponent from '../../VorlagenDropdown/VorlagenDropdown.js'; +import MessageModal from "../Details/NewMessage/Modal.js"; export default { components: { FormForm, FormInput, ListBox, - DropdownComponent + DropdownComponent, + MessageModal, }, props: { endpoint: { @@ -35,7 +37,7 @@ export default { vorlagen: [], defaultRecipient: null, editor: null, - isVisible: true, + isVisible: false, fieldsUser: [], fieldsPerson: [], fieldsPrestudent: [], @@ -45,12 +47,6 @@ export default { itemsPrestudent: [], itemsPerson: [], itemsUser: [], -/* selectedFieldStudent: null, - itemsStudent: [ - { label: "Variable 1", value: "var1" }, - { label: "Variable 2", value: "var2" }, - { label: "Variable 3", value: "var3" } - ]*/ previewText: null, previewBody: "" } @@ -170,62 +166,6 @@ export default { console.error("Editor instance is not available."); } }, - //TODO(Manu) refactor -/* insertVariablePrestudent() { - if (this.editor) { - //const lastVariable = this.selectedFieldsPrestudent[this.selectedFieldsPrestudent.length - 1].value; - const lastVariable = this.selectedFieldPrestudent.value; - - //Use insertContent method - this.editor.insertContent(lastVariable + " "); - } else { - console.error("Editor instance is not available."); - } - },*/ -/* insertVariablePrestudentByClick(selectedItem) { - - if (selectedItem) { - this.editor.insertContent(selectedItem.value + " "); - console.log("Eingefügte Variable:", selectedItem); - } else { - console.warn("Keine Variable ausgewählt!"); - } - }, - - insertVariablePerson() { - if (this.editor) { - //const lastVariable = this.selectedFieldsPrestudent[this.selectedFieldsPrestudent.length - 1].value; - const lastVariable = this.selectedFieldPerson.value; - - //Use insertContent method - this.editor.insertContent(lastVariable + " "); - } else { - console.error("Editor instance is not available."); - } - }, - insertVariableUser() { - if (this.editor) { - console.log(this.selectedFieldUser.value); - const lastVariable = this.selectedFieldUser.value; - - //Multiple - //const lastVariable = this.selectedFieldsPrestudent[this.selectedFieldsPrestudent.length - 1].value; - - //Use insertContent method - this.editor.insertContent(lastVariable + " "); - this.selectedFieldUser = null; - } else { - console.error("Editor instance is not available."); - } - }, - insertVariableStudent(selectedItem) { - if (selectedItem) { - console.log("Eingefügte Variable:", selectedItem); - this.editor.insertContent(selectedItem.value + " "); - } else { - console.warn("Keine Variable ausgewählt!"); - } - },*/ replyMessage(message_id){ console.log("auf message " + message_id + " antworten"); }, @@ -241,9 +181,9 @@ export default { this.$refs.dropdownComp.setValue(null); }, - toggleDivNewMessage(){ +/* toggleDivNewMessage(){ this.isVisible = !this.isVisible; - }, + },*/ handleSelectedVorlage(vorlage_kurzbz) { if (typeof vorlage_kurzbz === "string") { this.getVorlagentext(vorlage_kurzbz); @@ -254,15 +194,17 @@ export default { if (this.openMode == "showDiv") this.isVisible = false; }, - showTemplate(){ + showTemplate(id, typeId){ if (this.openMode == "showDiv") this.isVisible = true; + //just for testing: + this.isVisible = true; }, showPreview(){ this.getPreviewText().then(() => { this.previewBody = this.previewText; }); - } + }, }, watch: { 'formData.body': { @@ -343,9 +285,19 @@ export default { }, template: `
-
+ + + +
diff --git a/public/js/components/Messages/Details/NewMessage/Modal.js b/public/js/components/Messages/Details/NewMessage/Modal.js new file mode 100644 index 000000000..9bfe49929 --- /dev/null +++ b/public/js/components/Messages/Details/NewMessage/Modal.js @@ -0,0 +1,468 @@ +import BsModal from "../../../Bootstrap/Modal.js"; +import FormForm from "../../../Form/Form.js"; +import FormInput from '../../../Form/Input.js'; +import ListBox from "../../../../../../index.ci.php/public/js/components/primevue/listbox/listbox.esm.min.js"; +import DropdownComponent from "../../../VorlagenDropdown/VorlagenDropdown.js"; + +export default { + components: { + BsModal, + FormForm, + DropdownComponent, + FormInput, + ListBox + }, + props: { + endpoint: { + type: String, + required: true + }, + typeId: String, + id: { + type: [Number, String], + required: true + }, + openMode: String, + }, + data(){ + return { + formData: { + recipient: this.id, + subject: null, + body: null, + vorlage_kurzbz: null, + selectedValue: '', + }, + statusNew: true, + vorlagen: [], + defaultRecipient: null, + editor: null, + fieldsUser: [], + fieldsPerson: [], + fieldsPrestudent: [], + selectedFieldPrestudent: null, + selectedFieldUser: null, + selectedFieldPerson: null, + itemsPrestudent: [], + itemsPerson: [], + itemsUser: [], + previewText: null, + previewBody: "" + } + }, + methods: { + initTinyMCE() { + const vm = this; + tinymce.init({ + target: this.$refs.editor.$refs.input, //Important: not selector: to enable multiple import of component + //height: 800, + //plugins: ['lists'], + toolbar: 'styleselect | bold italic underline | alignleft aligncenter alignright alignjustify', + style_formats: [ + {title: 'Blocks', block: 'div'}, + {title: 'Paragraph', block: 'p'}, + {title: 'Heading 1', block: 'h1'}, + {title: 'Heading 2', block: 'h2'}, + {title: 'Heading 3', block: 'h3'}, + {title: 'Heading 4', block: 'h4'}, + {title: 'Heading 5', block: 'h5'}, + {title: 'Heading 6', block: 'h6'}, + ], + autoresize_bottom_margin: 16, + + setup: (editor) => { + vm.editor = editor; + + editor.on('input', () => { + const newContent = editor.getContent(); + vm.formData.body = newContent; + }); + }, + }); + }, + updateText(value) { + this.formData.body = value; + }, + sendMessage() { + //TODO(Manu) check default recipient(s) + const data = new FormData(); + const params = { + id: this.id, + type_id: this.typeId + }; + const merged = { + ...this.formData, + ...params + }; + data.append('data', JSON.stringify(merged)); + + return this.$fhcApi.factory.messages.person.sendMessage( + this.$refs.formMessage, + this.id, + data) + .then(response => { + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSent')); + //this.hideModal('messageModal'); + this.hideTemplate(); + this.resetForm(); + }).catch(this.$fhcAlert.handleSystemError) + .finally(() => { + //this.resetForm(); + //closeModal + //closewindwo + this.$emit('reloadTable'); + } + ); + }, + getVorlagentext(vorlage_kurzbz){ + //console.log(typeof vorlage_kurzbz); + return this.$fhcApi.factory.messages.person.getVorlagentext(vorlage_kurzbz) + .then(response => { + //this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSent')); + //this.hideModal('messageModal'); + //this.resetForm(); + //TODO(Manu) CHECK + this.formData.body = response.data; + }).catch(this.$fhcAlert.handleSystemError) + .finally(() => { + //this.resetForm(); + //closeModal + //closewindwo + }); + }, + getPreviewText(){ + const data = new FormData(); + + data.append('data', JSON.stringify(this.formData.body)); + return this.$fhcApi.factory.messages.person.getPreviewText({ + id: this.id, + type_id: this.typeId}, data) + .then(response => { + this.previewText = response.data; + }).catch(this.$fhcAlert.handleSystemError) + .finally(() => { + //this.resetForm(); + //closeModal + //closewindwo + }); + }, + insertVariable(selectedItem){ + if (this.editor) { + this.editor.insertContent(selectedItem.value + " "); + //TODO(Manu) check: nicht mal mit Punkt adden gehts ohne eintrag nach vars + /* this.editor.focus(); + this.editor.setDirty(true);*/ + + //this.editor.fire('change'); //forces + + //this.editor.undoManager.add(); + + //this.editor.insertContent(selectedItem.value + "\u00A0"); + //this.editor.insertContent(`${selectedItem.value} `); + //this.editor.selection.setCursorLocation(this.editor.getBody(), 1); + + } else { + console.error("Editor instance is not available."); + } + }, + replyMessage(message_id){ + console.log("auf message " + message_id + " antworten"); + }, + resetForm(){ + this.formData = { + vorlage_kurzbz: null, + body: null, + subject: null, + }; + if (this.editor) { + this.editor.setContent(""); + } + this.$refs.dropdownComp.setValue(null); + + }, + handleSelectedVorlage(vorlage_kurzbz) { + if (typeof vorlage_kurzbz === "string") { + this.getVorlagentext(vorlage_kurzbz); + this.formData.subject = vorlage_kurzbz; + } + }, + hideTemplate(){ + if (this.openMode == "showDiv") + this.isVisible = false; + }, + showTemplate(){ + if (this.openMode == "showDiv") + this.isVisible = true; + }, + showPreview(){ + this.getPreviewText().then(() => { + this.previewBody = this.previewText; + }); + }, + show(){ + this.$refs.modalNewMessage.show(); + } + }, + watch: { + 'formData.body': { + handler(newVal) { + const tinymcsVal = this.editor.getContent(); + + if (newVal && tinymcsVal != newVal) { + //Inhalt des Editors aktualisieren + this.editor.setContent(newVal); + } + } + }, + 'formData.vorlage_kurzbz': { + handler(newVal){ + // console.log("Vorlage: " + newVal); + + if (newVal && newVal != null) { + this.formData.subject = newVal; + return this.getVorlagentext(newVal); + } + } + } + }, + created(){ + if(this.typeId == 'person_id'){ + this.$fhcApi.factory.messages.person.getMessageVarsPerson() + .then(result => { + this.fieldsPerson = result.data; + this.itemsPerson = Object.entries(this.fieldsPerson).map(([key, value]) => ({ + label: value, + value: '{' + value + '}' + })); + }) + .catch(this.$fhcAlert.handleSystemError); + } + if(this.typeId == 'uid') { + this.$fhcApi.factory.messages.person.getMsgVarsPrestudent(this.id) + .then(result => { + this.fieldsPrestudent = result.data; + const prestudent = this.fieldsPrestudent[0]; + //Just for testing with inserting values + /* this.itemsPrestudent = Object.entries(prestudent).map(([key, value]) => ({ + label: key, + value: value + }));*/ + this.itemsPrestudent = Object.entries(prestudent).map(([key, value]) => ({ + label: key.toLowerCase(), + value: '{' + key.toLowerCase() + '}' + })); + }) + .catch(this.$fhcAlert.handleSystemError); + } + + this.$fhcApi.factory.messages.person.getMsgVarsLoggedInUser() + .then(result => { + this.fieldsUser = result.data; + const user = this.fieldsUser; + this.itemsUser = Object.entries(user).map(([key, value]) => ({ + label: value, + value: '{' + value + '}' + })); + }) + .catch(this.$fhcAlert.handleSystemError); + + this.$fhcApi.factory.messages.person.getNameOfDefaultRecipient({ + id: this.id, + type_id: this.typeId}) + .then(result => { + this.defaultRecipient = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + }, + async mounted() { + this.initTinyMCE(); + }, + beforeDestroy() { + this.editor.destroy(); + }, + template: ` + + + + + + +
+ + +
+
+ + + +
+ + + +
+ +
+ + +
+ + +
+ + +
+ +
+ + +
+ +
+
+ +
+
+ Felder Prestudent +
+ + + + + +
+ + +

{{selectedFieldPrestudent}}

+ +
+ +
+ Felder Person +
+ + + + + +
+ +

{{selectedFieldPerson}}

+
+ +
+ Meine Felder +
+ + + + + +
+ +
+ +
+ +
+ +
+ +

Vorschau:

+
+ + +
+ + +
+ +
+
+ +
+
+ +
+
+
+
+
+ +
+ +
+ +
+ +
+ + + +
+ +
+ `, +} \ No newline at end of file diff --git a/public/js/components/Messages/Details/NewMessage/NewDiv.js b/public/js/components/Messages/Details/NewMessage/NewDiv.js new file mode 100644 index 000000000..b31cd9932 --- /dev/null +++ b/public/js/components/Messages/Details/NewMessage/NewDiv.js @@ -0,0 +1,488 @@ +import FormForm from '../../../Form/Form.js'; +import FormInput from '../../../Form/Input.js'; +import ListBox from "../../../../../../index.ci.php/public/js/components/primevue/listbox/listbox.esm.min.js"; +import DropdownComponent from '../../../VorlagenDropdown/VorlagenDropdown.js'; + +export default { + components: { + FormForm, + FormInput, + ListBox, + DropdownComponent, + }, + props: { + endpoint: { + type: String, + required: true + }, + //for open in div and modal +/* typeId: String, + id: { + type: [Number, String], + required: true + },*/ + openMode: String, + }, + computed: { + //params with routes for new tab and new window AND props +/* id(){ + return this.$route.params.id || this.id; + }, + typeId(){ + return this.$route.params.typeId || this.typeId; + },*/ + id(){ + return this.$route.params.id || this.$props.id; + }, + typeId(){ + return this.$route.params.typeId || this.$props.id; + } + }, + data(){ + return { + formData: { + recipient: this.id, + subject: null, + body: null, + vorlage_kurzbz: null, + selectedValue: '', + }, + statusNew: true, + vorlagen: [], + defaultRecipient: null, + editor: null, + isVisible: false, + fieldsUser: [], + fieldsPerson: [], + fieldsPrestudent: [], + selectedFieldPrestudent: null, + selectedFieldUser: null, + selectedFieldPerson: null, + itemsPrestudent: [], + itemsPerson: [], + itemsUser: [], + previewText: null, + previewBody: "" + } + }, + methods: { + initTinyMCE() { + const vm = this; + tinymce.init({ + target: this.$refs.editor.$refs.input, //Important: not selector: to enable multiple import of component + //height: 800, + //plugins: ['lists'], + toolbar: 'styleselect | bold italic underline | alignleft aligncenter alignright alignjustify', + style_formats: [ + {title: 'Blocks', block: 'div'}, + {title: 'Paragraph', block: 'p'}, + {title: 'Heading 1', block: 'h1'}, + {title: 'Heading 2', block: 'h2'}, + {title: 'Heading 3', block: 'h3'}, + {title: 'Heading 4', block: 'h4'}, + {title: 'Heading 5', block: 'h5'}, + {title: 'Heading 6', block: 'h6'}, + ], + autoresize_bottom_margin: 16, + + setup: (editor) => { + vm.editor = editor; + + editor.on('input', () => { + const newContent = editor.getContent(); + vm.formData.body = newContent; + }); + }, + }); + }, + updateText(value) { + this.formData.body = value; + }, + sendMessage() { + //TODO(Manu) check default recipient(s) + const data = new FormData(); + const params = { + id: this.id, + type_id: this.typeId + }; + const merged = { + ...this.formData, + ...params + }; + data.append('data', JSON.stringify(merged)); + + return this.$fhcApi.factory.messages.person.sendMessage( + this.$refs.formMessage, + this.id, + data) + .then(response => { + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSent')); + //this.hideModal('messageModal'); + this.hideTemplate(); + this.resetForm(); + }).catch(this.$fhcAlert.handleSystemError) + .finally(() => { + //this.resetForm(); + //closeModal + //closewindwo + this.$emit('reloadTable'); + } + ); + }, + getVorlagentext(vorlage_kurzbz){ + return this.$fhcApi.factory.messages.person.getVorlagentext(vorlage_kurzbz) + .then(response => { + //this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSent')); + //this.hideModal('messageModal'); + //this.resetForm(); + //TODO(Manu) CHECK + this.formData.body = response.data; + }).catch(this.$fhcAlert.handleSystemError) + .finally(() => { + //this.resetForm(); + //closeModal + //closewindwo + }); + }, + getPreviewText(){ + const data = new FormData(); + + data.append('data', JSON.stringify(this.formData.body)); + return this.$fhcApi.factory.messages.person.getPreviewText({ + id: this.id, + type_id: this.typeId}, data) + .then(response => { + this.previewText = response.data; + }).catch(this.$fhcAlert.handleSystemError) + .finally(() => { + //this.resetForm(); + //closeModal + //closewindwo + }); + }, + insertVariable(selectedItem){ + if (this.editor) { + this.editor.insertContent(selectedItem.value + " "); + //TODO(Manu) check: nicht mal mit Punkt adden gehts ohne eintrag nach vars + /* this.editor.focus(); + this.editor.setDirty(true);*/ + + //this.editor.fire('change'); //forces + + //this.editor.undoManager.add(); + + //this.editor.insertContent(selectedItem.value + "\u00A0"); + //this.editor.insertContent(`${selectedItem.value} `); + //this.editor.selection.setCursorLocation(this.editor.getBody(), 1); + + } else { + console.error("Editor instance is not available."); + } + }, + replyMessage(message_id){ + console.log("auf message " + message_id + " antworten"); + }, + resetForm(){ + this.formData = { + vorlage_kurzbz: null, + body: null, + subject: null, + }; + if (this.editor) { + this.editor.setContent(""); + } + this.$refs.dropdownComp.setValue(null); + + this.previewBody = null; + + }, + toggleDivNewMessage(){ + this.isVisible = !this.isVisible; + }, + handleSelectedVorlage(vorlage_kurzbz) { + if (typeof vorlage_kurzbz === "string") { + this.getVorlagentext(vorlage_kurzbz); + this.formData.subject = vorlage_kurzbz; + } + }, + hideTemplate(){ + if (this.openMode == "showDiv") + this.isVisible = false; + }, + showTemplate(){ + if (this.openMode == "showDiv") + this.isVisible = true; + //just for testing: + this.isVisible = true; + }, + showPreview(){ + this.getPreviewText().then(() => { + this.previewBody = this.previewText; + }); + }, + }, + watch: { + 'formData.body': { + handler(newVal) { + const tinymcsVal = this.editor.getContent(); + + if (newVal && tinymcsVal != newVal) { + //Inhalt des Editors aktualisieren + this.editor.setContent(newVal); + } + } + }, + 'formData.vorlage_kurzbz': { + handler(newVal){ + // console.log("Vorlage: " + newVal); + + if (newVal && newVal != null) { + this.formData.subject = newVal; + return this.getVorlagentext(newVal); + } + } + }, + }, + created(){ + if(this.typeId == 'person_id'){ + this.$fhcApi.factory.messages.person.getMessageVarsPerson() + .then(result => { + this.fieldsPerson = result.data; + this.itemsPerson = Object.entries(this.fieldsPerson).map(([key, value]) => ({ + label: value, + value: '{' + value + '}' + })); + }) + .catch(this.$fhcAlert.handleSystemError); + } + if(this.typeId == 'uid') { + this.$fhcApi.factory.messages.person.getMsgVarsPrestudent(this.id) + .then(result => { + this.fieldsPrestudent = result.data; + const prestudent = this.fieldsPrestudent[0]; + //Just for testing with inserting values + /* this.itemsPrestudent = Object.entries(prestudent).map(([key, value]) => ({ + label: key, + value: value + }));*/ + this.itemsPrestudent = Object.entries(prestudent).map(([key, value]) => ({ + label: key.toLowerCase(), + value: '{' + key.toLowerCase() + '}' + })); + }) + .catch(this.$fhcAlert.handleSystemError); + } + + this.$fhcApi.factory.messages.person.getMsgVarsLoggedInUser() + .then(result => { + this.fieldsUser = result.data; + const user = this.fieldsUser; + this.itemsUser = Object.entries(user).map(([key, value]) => ({ + label: value, + value: '{' + value + '}' + })); + }) + .catch(this.$fhcAlert.handleSystemError); + + this.$fhcApi.factory.messages.person.getNameOfDefaultRecipient({ + id: this.id, + type_id: this.typeId + }) + .then(result => { + this.defaultRecipient = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + + }, + async mounted() { + this.initTinyMCE(); + }, + beforeDestroy() { + this.editor.destroy(); + }, + template: ` + +
+ + + + + +
+ + {{id}} || {{typeId}} + +

New Message

+ + +
+
+ + + +
+ + + +
+ +
+ + +
+ + +
+ + +
+ +
+ + +
+ +
+
+ +
+
+ Felder Prestudent +
+ + + + + +
+ +
+ +
+ +
+ Felder Person +
+ + + + + +
+ +
+ +
+ Meine Felder +
+ + + + + +
+ +
+ +
+ +
+ + + + + +
+ +
+ +
+ +
+ +

Vorschau:

+
+ + +
+ + +
+ +
+
+ +
+
+ +
+
+
+
+
+ +
+ +
+ +
+ +
+ ` + +} \ No newline at end of file diff --git a/public/js/components/Messages/Details/TableMessages.js b/public/js/components/Messages/Details/TableMessages.js index 10210ece4..7994cbe1d 100644 --- a/public/js/components/Messages/Details/TableMessages.js +++ b/public/js/components/Messages/Details/TableMessages.js @@ -1,10 +1,12 @@ import {CoreFilterCmpt} from "../../filter/Filter.js"; import FormForm from '../../Form/Form.js'; +import NewMessage from "../Details/NewMessage.js"; export default { components: { CoreFilterCmpt, FormForm, + NewMessage, }, inject: { cisRoot: { @@ -205,7 +207,8 @@ export default { }, ], tabulatorData: [], - previewBody: "" + previewBody: "", + open: false } }, methods: { @@ -233,20 +236,9 @@ export default { }); }, actionNewMessage(){ + this.$emit('newMessage', this.id, this.typeId); //console.log("action new message"); - if (this.openMode == "window") { - console.log("openInNewWindow") - const linkWindowNewMessage = this.cisRoot + '/public/js/components/Messages/Details/NewMessage.js'; - window.open(linkWindowNewMessage, '_blank'); - } - else if (this.openMode == "modal"){ - console.log("open with bootstrap Modal"); - } - else if (this.openMode == "showDiv"){ - this.$emit('showNewMessageTemplate'); - } - else - console.log("no valid openMode"); + }, reload() { this.$refs.table.reloadTable(); @@ -274,19 +266,10 @@ export default { }, template: `
- - - - - - -
- +
@@ -307,7 +290,6 @@ export default {




-
diff --git a/public/js/components/Messages/Messages.js b/public/js/components/Messages/Messages.js index f862ebc46..49fdbdf79 100644 --- a/public/js/components/Messages/Messages.js +++ b/public/js/components/Messages/Messages.js @@ -1,10 +1,20 @@ import TableMessages from "./Details/TableMessages.js"; import NewMessage from "./Details/NewMessage.js"; - +import FormOnly from "./Details/NewMessage/NewDiv.js"; +import FhcApi from "../../../../public/js/plugin/FhcApi.js"; +import Phrasen from "../../../../public/js/plugin/Phrasen.js"; export default { components: { TableMessages, - NewMessage + NewMessage, + FormOnly, + FhcApi, + Phrasen + }, + inject: { + cisRoot: { + from: 'cisRoot' + } }, props: { endpoint: { @@ -34,6 +44,7 @@ export default { validator(value) { return [ 'window', + 'newTab', 'modal', 'showDiv' ].includes(value) @@ -41,18 +52,85 @@ export default { } }, data() { - return {} + return { + showDiv: false + } }, methods: { - showNewMessageTemplate(){ - this.$refs.templateNewMessage.showTemplate(); - }, reloadTable(){ this.$refs.templateTableMessage.reload(); - } + }, + newMessage(id, typeId){ + if (this.openMode == "window") { + this.openInNewWindow(id, typeId); + } + else if (this.openMode == "newTab"){ + this.openInNewTab(id, typeId); + } + else if (this.openMode == "modal"){ + this.openInModal(id, typeId); + } + else if (this.openMode == "showDiv"){ + this.$refs.templateNewMessage.showTemplate(id, typeId); + } + else + console.log("no valid openMode"); + }, + openInDiv(id, typeId){ + this.$refs.templateNewMessage.showTemplate(id, typeId); + //this.showDiv = true; //local variante + //this.$refs.templateNewMessage.showTemplate(); + }, + openInModal(id, typeId){ + //TODO(manu) define bs-modal in this component + this.$refs.templateNewMessage.$refs.modalMsg.show(); + }, + openInNewTab(id, typeId){ + //TODO(MANU) check if array of ids... +/* let path = FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router; + path += "/NeueNachricht/" + this.id + "/" + this.typeId;*/ + + //als param + let path = FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router; + path += "/NeueNachricht/" + id + "/" + typeId; + + const newTab = window.open(path, "_blank"); + }, + openInNewWindow(id, typeId){ + //TODO(MANU) check if array of ids... + let path = FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router; + path += "/NeueNachricht/" + id + "/" + typeId; + + const newTab = window.open(path, "_blank"); + + const width = Math.round(window.innerWidth * 0.75); + const height = Math.round(window.innerHeight * 0.75); + const left = Math.round((window.innerWidth - width) / 2); + const top = Math.round((window.innerHeight - height) / 2); + + const newWindow = window.open(path, "_blank", `width=${width},height=${height},left=${left},top=${top}`); + }, + }, template: `
+ + + + +
+ + +
+ + +
+
diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Messages.js b/public/js/components/Stv/Studentenverwaltung/Details/Messages.js index bc07401e6..44f1a6aa2 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Messages.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Messages.js @@ -18,7 +18,7 @@ export default { messageLayout="twoColumnsTableLeft" show-table show-new - open-mode="showDiv" + open-mode="newTab" > diff --git a/public/js/components/VorlagenDropdown/VorlagenDropdown.js b/public/js/components/VorlagenDropdown/VorlagenDropdown.js index b074711f4..e5d80077e 100644 --- a/public/js/components/VorlagenDropdown/VorlagenDropdown.js +++ b/public/js/components/VorlagenDropdown/VorlagenDropdown.js @@ -57,7 +57,7 @@ export default { if(this.useLoggedInUserOe){ this.$fhcApi.factory.vorlagen.getVorlagenByLoggedInUser() .then(result => { - console.log(this.vorlagenOe); + //console.log(this.vorlagenOe); this.vorlagenOe = result.data; }) .catch(this.$fhcAlert.handleSystemError); From 815307e392cb245dd696e10edf1ae018040bd5fb Mon Sep 17 00:00:00 2001 From: ma0068 Date: Tue, 4 Mar 2025 07:32:14 +0100 Subject: [PATCH 008/107] Reply functionality and Pagination --- application/controllers/NeueNachricht.php | 2 +- .../api/frontend/v1/messages/Messages.php | 82 +++++++++++++++++-- application/models/system/Message_model.php | 4 +- public/js/api/messages/person.js | 7 ++ public/js/apps/Nachrichten.js | 1 + .../Messages/Details/NewMessage/NewDiv.js | 29 +++++-- .../Messages/Details/TableMessages.js | 29 +++++-- public/js/components/Messages/Messages.js | 41 ++++++++-- 8 files changed, 162 insertions(+), 33 deletions(-) diff --git a/application/controllers/NeueNachricht.php b/application/controllers/NeueNachricht.php index 9e9e0a39b..9b61b78ef 100644 --- a/application/controllers/NeueNachricht.php +++ b/application/controllers/NeueNachricht.php @@ -23,7 +23,7 @@ class NeueNachricht extends Auth_Controller //now working $this->load->view('Nachrichten', [ 'permissions' => [ - 'vertragsverwaltung_schreibrechte' => $this->permissionlib->isBerechtigt('vertrag/mitarbeiter', 'suid') + 'assistenz_schreibrechte' => $this->permissionlib->isBerechtigt('assistenz','suid'), ] ]); } diff --git a/application/controllers/api/frontend/v1/messages/Messages.php b/application/controllers/api/frontend/v1/messages/Messages.php index 4bc9a13ab..d080cbee3 100644 --- a/application/controllers/api/frontend/v1/messages/Messages.php +++ b/application/controllers/api/frontend/v1/messages/Messages.php @@ -18,6 +18,8 @@ class Messages extends FHCAPI_Controller 'deleteMessage' => ['admin:r', 'assistenz:r'], 'getVorlagentext' => ['admin:r', 'assistenz:r'], 'getPreviewText' => ['admin:r', 'assistenz:r'], + 'getReplyData' => ['admin:r', 'assistenz:r'], + 'getPersonIdFromUid' => ['admin:r', 'assistenz:r'], ]); //Load Models @@ -70,8 +72,6 @@ class Messages extends FHCAPI_Controller $data = $this->getDataOrTerminateWithError($result); $oe_kurzbz = current($data); - // $this->terminateWithError("oe: ". $oe_kurzbz->oe_kurzbz, self::ERROR_TYPE_GENERAL); - $this->load->model('system/Vorlage_model', 'VorlageModel'); //39 Stück Variante OE @@ -129,11 +129,8 @@ class Messages extends FHCAPI_Controller public function getMsgVarsPrestudent($uid) { - //$this->terminateWithError($uid, self::ERROR_TYPE_GENERAL); $prestudent_id = $this-> _getPrestudentIdFromUid($uid); - // $this->terminateWithError("prestudent_id " . $prestudent_id, self::ERROR_TYPE_GENERAL); - $result = $this->MessageModel->getMsgVarsDataByPrestudentId($prestudent_id); $data = $this->getDataOrTerminateWithError($result); @@ -290,6 +287,46 @@ class Messages extends FHCAPI_Controller $this->terminateWithSuccess($bodyParsed); } + public function getReplyData($messageId) + { + // return $this->terminateWithError("in get ReplyBody" . $messageId, self::ERROR_TYPE_GENERAL); + //TODO(Manu) validation of messageId: if number + + + $this->MessageModel->addSelect('public.tbl_msg_message.*'); + $this->MessageModel->addSelect('r.*'); + $this->MessageModel->addSelect('p.nachname'); + $this->MessageModel->addSelect('p.vorname'); + $this->MessageModel->addJoin('public.tbl_msg_recipient r', 'ON (r.message_id = public.tbl_msg_message.message_id)'); + $this->MessageModel->addJoin('public.tbl_person p', 'ON (p.person_id = public.tbl_msg_message.person_id)'); + + $result = $this->MessageModel->loadWhere( + array('r.message_id' => $messageId) + ); + + // $this->terminateWithSuccess((getData($result) ?: [])); + $dataMessage = $this->getDataOrTerminateWithError($result); + + $prefix = "Re: "; // reply subject prefix + +/* $body = current($dataMessage->body); + $subject = $dataMessage->subject;*/ + + $subject = $dataMessage[0]->subject; + $body = $dataMessage[0]->body; + + + $replyBody = $this->_getReplyBody($body, $dataMessage[0]->nachname, $dataMessage[0]->vorname, $dataMessage[0]->insertamum); + + $dataMessage[0]->replyBody = $replyBody; + $dataMessage[0]->rest = "Help Manu"; + $dataMessage[0]->replySubject = $prefix . $subject; + + $this->terminateWithSuccess($dataMessage); + + + } + public function deleteMessage($messageId) { // Start DB transaction @@ -298,7 +335,7 @@ class Messages extends FHCAPI_Controller $result = $this->MessageModel->deleteMessageRecipient($messageId); if (isError($result)) { return $this->terminateWithError($result, self::ERROR_TYPE_GENERAL); - return $this->terminateWithError($result, self::ERROR_TYPE_GENERAL); + } $result = $this->MessageModel->deleteMessageStatus($messageId); @@ -316,6 +353,19 @@ class Messages extends FHCAPI_Controller $this->terminateWithSuccess($result); } + public function getPersonIdFromUid($uid) + { + $this->load->model('person/Benutzer_model', 'BenutzerModel'); + $result = $this->BenutzerModel->loadWhere( + ['uid' => $uid] + ); + + $data = $this->getDataOrTerminateWithError($result); + $benutzer = current($data); + + $this->terminateWithSuccess($benutzer->person_id); + } + private function _getPersonIdFromUid($uid) { $this->load->model('person/Benutzer_model', 'BenutzerModel'); @@ -326,7 +376,6 @@ class Messages extends FHCAPI_Controller $data = $this->getDataOrTerminateWithError($result); $benutzer = current($data); - //return $data->person_id; return $benutzer->person_id; } @@ -342,4 +391,23 @@ class Messages extends FHCAPI_Controller return $student->prestudent_id; } + + private function _getReplyBody($body, $receiverName, $receiverSurname, $sentDate) + { + // To quote a reply body message + $bodyFormat = "
+
+
+ + On %s %s %s wrote: + +
+
+ %s +
"; + return sprintf( + $bodyFormat, + date_format(date_create($sentDate), 'd.m.Y H:i'), $receiverName, $receiverSurname, $body + ); + } } \ No newline at end of file diff --git a/application/models/system/Message_model.php b/application/models/system/Message_model.php index 0fdb39736..38defa383 100644 --- a/application/models/system/Message_model.php +++ b/application/models/system/Message_model.php @@ -275,7 +275,7 @@ class Message_model extends DB_Model JOIN public.tbl_msg_message m USING(message_id) WHERE r.person_id = ? GROUP BY m.message_id, m.subject, m.body, m.insertamum, m.relationmessage_id, sender, recipient, sender_id, recipient_id - ORDER BY insertamum + ORDER BY insertamum DESC "; $parametersArray = array($person_id, $person_id); @@ -287,7 +287,7 @@ class Message_model extends DB_Model * Deletes a messages from tableMessages and tbl_msg_recipient * TODO(MANU) CHECK IF NECESSARY * dependency with other tables - * in case of reply... more messages + * in case of reply... more messages?? delete all dependent ones? * maybe anonimize it * @param $message_id * @return boolean success diff --git a/public/js/api/messages/person.js b/public/js/api/messages/person.js index 5cbb49550..7693c5189 100644 --- a/public/js/api/messages/person.js +++ b/public/js/api/messages/person.js @@ -14,6 +14,9 @@ export default { getMsgVarsPrestudent(uid){ return this.$fhcApi.get('api/frontend/v1/messages/messages/getMsgVarsPrestudent/' + uid); }, + getPersonIdFromUid(uid){ + return this.$fhcApi.get('api/frontend/v1/messages/messages/getPersonIdFromUid/' + uid); + }, getVorlagentext(vorlage_kurzbz){ return this.$fhcApi.get('api/frontend/v1/messages/messages/getVorlagentext/' + vorlage_kurzbz); }, @@ -24,6 +27,10 @@ export default { return this.$fhcApi.post('api/frontend/v1/messages/messages/getPreviewText/' + params.id + '/' + params.type_id, data); }, + getReplyData(messageId){ + return this.$fhcApi.get('api/frontend/v1/messages/messages/getReplyData/' + messageId); + + }, sendMessage(form, id, data) { return this.$fhcApi.post(form,'api/frontend/v1/messages/messages/sendMessage/' + id, data); diff --git a/public/js/apps/Nachrichten.js b/public/js/apps/Nachrichten.js index 0f921a9f8..84b9ddee5 100644 --- a/public/js/apps/Nachrichten.js +++ b/public/js/apps/Nachrichten.js @@ -8,6 +8,7 @@ const router = VueRouter.createRouter({ history: VueRouter.createWebHistory(), routes: [ { path: `/${ciPath}/NeueNachricht/:id/:typeId`, component: NewMessage }, + { path: `/${ciPath}/NeueNachricht/:id/:typeId/:messageId`, component: NewMessage }, ] }); diff --git a/public/js/components/Messages/Details/NewMessage/NewDiv.js b/public/js/components/Messages/Details/NewMessage/NewDiv.js index b31cd9932..1eb59aa20 100644 --- a/public/js/components/Messages/Details/NewMessage/NewDiv.js +++ b/public/js/components/Messages/Details/NewMessage/NewDiv.js @@ -36,6 +36,9 @@ export default { }, typeId(){ return this.$route.params.typeId || this.$props.id; + }, + messageId(){ + return this.$route.params.messageId; } }, data(){ @@ -62,7 +65,8 @@ export default { itemsPerson: [], itemsUser: [], previewText: null, - previewBody: "" + previewBody: "", + replyData: null } }, methods: { @@ -179,9 +183,9 @@ export default { console.error("Editor instance is not available."); } }, - replyMessage(message_id){ +/* replyMessage(message_id){ console.log("auf message " + message_id + " antworten"); - }, + },*/ resetForm(){ this.formData = { vorlage_kurzbz: null, @@ -293,6 +297,19 @@ export default { }) .catch(this.$fhcAlert.handleSystemError); + if(this.messageId != null) { + + //get replayBody.. body receivername, receiverSurname, sentDate of message + this.$fhcApi.factory.messages.person.getReplyData(this.messageId) + .then(result => { + this.replyData = result.data; + this.formData.subject = this.replyData[0].replySubject; + this.formData.body = this.replyData[0].replyBody; + }) + .catch(this.$fhcAlert.handleSystemError); + + } + }, async mounted() { this.initTinyMCE(); @@ -309,13 +326,7 @@ export default {
- - {{id}} || {{typeId}} -

New Message

-
diff --git a/public/js/components/Messages/Details/TableMessages.js b/public/js/components/Messages/Details/TableMessages.js index 7994cbe1d..ab6a76599 100644 --- a/public/js/components/Messages/Details/TableMessages.js +++ b/public/js/components/Messages/Details/TableMessages.js @@ -1,12 +1,12 @@ import {CoreFilterCmpt} from "../../filter/Filter.js"; import FormForm from '../../Form/Form.js'; -import NewMessage from "../Details/NewMessage.js"; +//import NewMessage from "../Details/NewMessage.js"; export default { components: { CoreFilterCmpt, FormForm, - NewMessage, + // NewMessage, }, inject: { cisRoot: { @@ -110,13 +110,15 @@ export default { container.className = "d-flex gap-2"; let button = document.createElement('button'); + if (this.personId != cell.getData().recipient_id) + button.disabled = true; button.className = 'btn btn-outline-secondary btn-action'; button.title = this.$p.t('global', 'reply'); button.innerHTML = ''; button.addEventListener( 'click', (event) => - this.reply(cell.getData().message_id) + this.actionReplyToMessage(cell.getData().message_id) ); container.append(button); @@ -141,6 +143,8 @@ export default { height: '400', selectable: true, selectableRangeMode: 'click', + pagination: true, + // paginationSize: 5, /* layoutColumnsOnNewData: false, selectableRangeMode: 'click', @@ -208,13 +212,11 @@ export default { ], tabulatorData: [], previewBody: "", - open: false + open: false, + personId: null } }, methods: { - reply(message_id){ - console.log("in reply " + message_id); - }, actionDeleteMessage(message_id){ this.$fhcAlert .confirmDelete() @@ -225,7 +227,6 @@ export default { .catch(this.$fhcAlert.handleSystemError); }, deleteMessage(message_id){ - // console.log("deleteMessage " + message_id); return this.$fhcApi.factory.messages.person.deleteMessage(message_id) .then(response => { this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successDelete')); @@ -240,6 +241,9 @@ export default { //console.log("action new message"); }, + actionReplyToMessage(message_id){ + this.$emit('replyToMessage', this.id, this.typeId, message_id); + }, reload() { this.$refs.table.reloadTable(); }, @@ -264,6 +268,15 @@ export default { }); });*/ }, + created(){ + if(this.typeId == 'uid') { + this.$fhcApi.factory.messages.person.getPersonIdFromUid(this.id) + .then(result => { + this.personId = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + } + }, template: `
diff --git a/public/js/components/Messages/Messages.js b/public/js/components/Messages/Messages.js index 49fdbdf79..e6947a72a 100644 --- a/public/js/components/Messages/Messages.js +++ b/public/js/components/Messages/Messages.js @@ -76,6 +76,23 @@ export default { else console.log("no valid openMode"); }, + handleMessage(id, typeId, messageId){ + console.log("in handleMessage " + messageId); + if (this.openMode == "window") { + this.openInNewWindow(id, typeId, messageId); + } + else if (this.openMode == "newTab"){ + this.openInNewTab(id, typeId, messageId); + } + else if (this.openMode == "modal"){ + this.openInModal(id, typeId, messageId); + } + else if (this.openMode == "showDiv"){ + this.$refs.templateNewMessage.showTemplate(id, typeId, messageId); + } + else + console.log("no valid openMode"); + }, openInDiv(id, typeId){ this.$refs.templateNewMessage.showTemplate(id, typeId); //this.showDiv = true; //local variante @@ -85,15 +102,26 @@ export default { //TODO(manu) define bs-modal in this component this.$refs.templateNewMessage.$refs.modalMsg.show(); }, - openInNewTab(id, typeId){ +/* openInNewTab(id, typeId){ //TODO(MANU) check if array of ids... -/* let path = FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router; - path += "/NeueNachricht/" + this.id + "/" + this.typeId;*/ - - //als param let path = FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router; path += "/NeueNachricht/" + id + "/" + typeId; + const newTab = window.open(path, "_blank"); + },*/ + openInNewTab(id, typeId, messageId=null){ + //TODO(MANU) check if array of ids... + let path = FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router; + + if (messageId){ + path += "/NeueNachricht/" + id + "/" + typeId + "/" + messageId; + } + + else { + path += "/NeueNachricht/" + id + "/" + typeId; + } + + const newTab = window.open(path, "_blank"); }, openInNewWindow(id, typeId){ @@ -152,7 +180,8 @@ export default { :endpoint="endpoint" :messageLayout="messageLayout" :openMode="openMode" - @newMessage="newMessage" + @newMessage="newMessage" + @replyToMessage="handleMessage" > From 1989e65d72d1532ab943c71eaaff4b6207581c79 Mon Sep 17 00:00:00 2001 From: ma0068 Date: Mon, 10 Mar 2025 07:51:53 +0100 Subject: [PATCH 009/107] Tree structure for messages, preview in NewDiv, Note to close window, check recipient_id, save relationmessage_id --- .../api/frontend/v1/messages/Messages.php | 163 ++++++++++-------- public/js/api/messages/person.js | 12 +- .../Messages/Details/NewMessage/NewDiv.js | 117 ++++++++++--- .../Messages/Details/TableMessages.js | 144 +++++++++++++--- public/js/components/Messages/Messages.js | 3 +- .../Studentenverwaltung/Details/Messages.js | 14 +- 6 files changed, 329 insertions(+), 124 deletions(-) diff --git a/application/controllers/api/frontend/v1/messages/Messages.php b/application/controllers/api/frontend/v1/messages/Messages.php index d080cbee3..65c354c4f 100644 --- a/application/controllers/api/frontend/v1/messages/Messages.php +++ b/application/controllers/api/frontend/v1/messages/Messages.php @@ -19,7 +19,8 @@ class Messages extends FHCAPI_Controller 'getVorlagentext' => ['admin:r', 'assistenz:r'], 'getPreviewText' => ['admin:r', 'assistenz:r'], 'getReplyData' => ['admin:r', 'assistenz:r'], - 'getPersonIdFromUid' => ['admin:r', 'assistenz:r'], + 'getPersonId' => ['admin:r', 'assistenz:r'], + 'getUid' => ['admin:r', 'assistenz:r'], ]); //Load Models @@ -42,17 +43,8 @@ class Messages extends FHCAPI_Controller public function getMessages($id, $type_id) { - switch($type_id) - { - case 'uid': - $id = $this->_getPersonIdFromUid($id); - break; - case 'person_id': - $id = $id; - break; - default: - $this->terminateWithError("MESSAGES::getMessages logic for type_id " . $type_id . " not defined yet", self::ERROR_TYPE_GENERAL); - break; + if($type_id != 'person_id'){ + $id = $this->_getPersonId($id, $type_id); } $result = $this->MessageModel->getMessagesForTable($id); @@ -74,15 +66,13 @@ class Messages extends FHCAPI_Controller $this->load->model('system/Vorlage_model', 'VorlageModel'); - //39 Stück Variante OE $result = $this->VorlageModel->getAllVorlagenByOe($oe_kurzbz->oe_kurzbz); $data = $this->getDataOrTerminateWithError($result); $this->terminateWithSuccess($data); - //IF ADMIN 167 + //If admin $this->VorlageModel->addOrder('vorlage_kurzbz', 'ASC'); - //only HTML-vorlagen -> for admin $result = $this->VorlageModel->loadWhere( array( 'mimetype' => 'text/html' @@ -97,7 +87,7 @@ class Messages extends FHCAPI_Controller public function getVorlagentext($vorlage_kurzbz) { //$this->terminateWithError("vor " . $vorlage_kurzbz, self::ERROR_TYPE_GENERAL); - //$studiengang_kz = 227; //TODO(Manu) check dynamisieren NULL + //$studiengang_kz = 227; //TODO(Manu) dynamisieren NULL $studiengang_kz = 0; $this->load->model('system/Vorlagestudiengang_model', 'VorlagestudiengangModel'); $this->VorlagestudiengangModel->addOrder('version', 'DESC'); @@ -127,49 +117,32 @@ class Messages extends FHCAPI_Controller $this->terminateWithSuccess($data); } - public function getMsgVarsPrestudent($uid) + public function getMsgVarsPrestudent($id, $typeId) { - $prestudent_id = $this-> _getPrestudentIdFromUid($uid); + $prestudent_id = ($typeId == 'prestudent_id') ? $id : $this->_getPrestudentIdFromUid($id); $result = $this->MessageModel->getMsgVarsDataByPrestudentId($prestudent_id); $data = $this->getDataOrTerminateWithError($result); - $this->terminateWithSuccess($data); } public function getMsgVarsLoggedInUser() { - $uid = getAuthUID(); - $result = $this->MessageModel->getMsgVarsLoggedInUser(); - $data = $this->getDataOrTerminateWithError($result); - $this->terminateWithSuccess($data); } public function getNameOfDefaultRecipient($id, $type_id) { - switch($type_id) - { - case 'uid': - $id = $this->_getPersonIdFromUid($id); - break; - case 'person_id': - $id = $id; - break; - default: - $this->terminateWithError("MESSAGES::getNameOfDefaultRecipient logic for type_id " . $type_id . " not defined yet", self::ERROR_TYPE_GENERAL); - break; - } + $id = $type_id!='person_id)' ? $this->_getPersonId($id, $type_id) : $id; $this->load->model('person/Person_model', 'PersonModel'); $result = $this->PersonModel->load($id); - //$this->terminateWithSuccess($result); $data = $this->getDataOrTerminateWithError($result); $name = current($data); @@ -178,8 +151,11 @@ class Messages extends FHCAPI_Controller public function sendMessage($recipient_id) { + //is always uid in FAS + //TODO(Manu) make dynamic for other ids + //default setting - $receiversPersonId = $this->_getPersonIdFromUid($recipient_id); + $receiversPersonId = $this->_getPersonId($recipient_id, 'uid'); $uid = getAuthUID(); $this->load->model('person/Benutzer_model', 'BenutzerModel'); @@ -216,15 +192,13 @@ class Messages extends FHCAPI_Controller $subject = $this->input->post('subject'); $body = $this->input->post('body'); - - + $relationmessage_id = $this->input->post('relationmessage_id'); $typeId = $this->input->post('type_id'); $id = $this->input->post('id'); if($typeId == 'uid') { - //$this->terminateWithError("uid ", self::ERROR_TYPE_GENERAL); $prestudent_id = $this-> _getPrestudentIdFromUid($id); //parseMessagetext for variables Prestudent @@ -240,7 +214,7 @@ class Messages extends FHCAPI_Controller } elseif($typeId == 'prestudent_id') { - $this->terminateWithError("prestudent_id ", self::ERROR_TYPE_GENERAL); + // $this->terminateWithError("prestudent_id ", self::ERROR_TYPE_GENERAL); $result = $this->MessagesModel->parseMessageTextPrestudent($id, $body); $bodyParsed = $this->getDataOrTerminateWithError($result); @@ -250,7 +224,7 @@ class Messages extends FHCAPI_Controller $this->terminateWithError("type_id " . $typeId . " not valid", self::ERROR_TYPE_GENERAL); } - $result = $this->messagelib->sendMessageUser($receiversPersonId, $subject, $bodyParsed, $benutzer->person_id); + $result = $this->messagelib->sendMessageUser($receiversPersonId, $subject, $bodyParsed, $benutzer->person_id, null, $relationmessage_id); $this->terminateWithSuccess($result); } @@ -271,17 +245,15 @@ class Messages extends FHCAPI_Controller case 'uid': $prestudent_id = $this->_getPrestudentIdFromUid($id); $result = $this->MessagesModel->parseMessageTextPrestudent($prestudent_id, $data); - break; - case 'person_id': - $id = $id; + case 'prestudent_id': + $result = $this->MessagesModel->parseMessageTextPrestudent($id, $data); break; default: $this->terminateWithError("MESSAGES::getPreviewText logic for type_id " . $type_id . " not defined yet", self::ERROR_TYPE_GENERAL); break; } - //$this->terminateWithSuccess($result); $bodyParsed = $this->getDataOrTerminateWithError($result); $this->terminateWithSuccess($bodyParsed); @@ -289,10 +261,8 @@ class Messages extends FHCAPI_Controller public function getReplyData($messageId) { - // return $this->terminateWithError("in get ReplyBody" . $messageId, self::ERROR_TYPE_GENERAL); //TODO(Manu) validation of messageId: if number - $this->MessageModel->addSelect('public.tbl_msg_message.*'); $this->MessageModel->addSelect('r.*'); $this->MessageModel->addSelect('p.nachname'); @@ -304,14 +274,9 @@ class Messages extends FHCAPI_Controller array('r.message_id' => $messageId) ); - // $this->terminateWithSuccess((getData($result) ?: [])); $dataMessage = $this->getDataOrTerminateWithError($result); - $prefix = "Re: "; // reply subject prefix -/* $body = current($dataMessage->body); - $subject = $dataMessage->subject;*/ - $subject = $dataMessage[0]->subject; $body = $dataMessage[0]->body; @@ -323,8 +288,6 @@ class Messages extends FHCAPI_Controller $dataMessage[0]->replySubject = $prefix . $subject; $this->terminateWithSuccess($dataMessage); - - } public function deleteMessage($messageId) @@ -353,30 +316,94 @@ class Messages extends FHCAPI_Controller $this->terminateWithSuccess($result); } - public function getPersonIdFromUid($uid) + public function getPersonId($id, $typeId) { - $this->load->model('person/Benutzer_model', 'BenutzerModel'); - $result = $this->BenutzerModel->loadWhere( - ['uid' => $uid] - ); + if ($typeId == 'uid') + { + $this->load->model('person/Benutzer_model', 'BenutzerModel'); + $result = $this->BenutzerModel->loadWhere( + ['uid' => $id] + ); + } + elseif($typeId == 'prestudent_id') + { + $this->load->model('crm/Prestudent_model', 'PrestudentModel'); + $result = $this->PrestudentModel->loadWhere( + ['prestudent_id' => $id] + ); + } $data = $this->getDataOrTerminateWithError($result); - $benutzer = current($data); + $person = current($data); - $this->terminateWithSuccess($benutzer->person_id); + $this->terminateWithSuccess($person->person_id); } - private function _getPersonIdFromUid($uid) + public function getUid($id, $typeId) { - $this->load->model('person/Benutzer_model', 'BenutzerModel'); - $result = $this->BenutzerModel->loadWhere( - ['uid' => $uid] - ); + if (!$typeId) + { + $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Type ID']), self::ERROR_TYPE_GENERAL); + } + elseif ($typeId == 'person_id') + { + $this->load->model('person/Benutzer_model', 'BenutzerModel'); + $result = $this->BenutzerModel->loadWhere( + ['person_id' => $id] + ); + } + elseif($typeId == 'prestudent_id') + { + $this->load->model('crm/Prestudent_model', 'PrestudentModel'); + $result = $this->PrestudentModel->loadWhere( + ['prestudent_id' => $id] + ); + + $data = $this->getDataOrTerminateWithError($result); + $person = current($data); + $person_id = $person->person_id; + + $this->load->model('person/Benutzer_model', 'BenutzerModel'); + $result = $this->BenutzerModel->loadWhere( + ['person_id' => $person_id] + ); + } + elseif($typeId == 'uid') + { + $this->terminateWithSuccess($id); + } + else + { + $this->terminateWithError("MESSAGES::getUID logic for type_id " . $typeId . " not defined yet", self::ERROR_TYPE_GENERAL); + } $data = $this->getDataOrTerminateWithError($result); $benutzer = current($data); - return $benutzer->person_id; + $this->terminateWithSuccess($benutzer->uid); + } + + private function _getPersonId($id, $typeId) + { + if ($typeId == 'uid') + { + $this->load->model('person/Benutzer_model', 'BenutzerModel'); + $result = $this->BenutzerModel->loadWhere( + ['uid' => $id] + ); + } + elseif($typeId == 'prestudent_id') + { + $this->load->model('crm/Prestudent_model', 'PrestudentModel'); + $result = $this->PrestudentModel->loadWhere( + ['prestudent_id' => $id] + ); + } + + $data = $this->getDataOrTerminateWithError($result); + $person = current($data); + + return $person->person_id; } private function _getPrestudentIdFromUid($uid) diff --git a/public/js/api/messages/person.js b/public/js/api/messages/person.js index 7693c5189..e53f23f6a 100644 --- a/public/js/api/messages/person.js +++ b/public/js/api/messages/person.js @@ -11,11 +11,14 @@ export default { getMessageVarsPerson(){ return this.$fhcApi.get('api/frontend/v1/messages/messages/getMessageVarsPerson/'); }, - getMsgVarsPrestudent(uid){ - return this.$fhcApi.get('api/frontend/v1/messages/messages/getMsgVarsPrestudent/' + uid); + getMsgVarsPrestudent(params){ + return this.$fhcApi.get('api/frontend/v1/messages/messages/getMsgVarsPrestudent/' + params.id + '/' + params.type_id); }, - getPersonIdFromUid(uid){ - return this.$fhcApi.get('api/frontend/v1/messages/messages/getPersonIdFromUid/' + uid); + getPersonId(params){ + return this.$fhcApi.get('api/frontend/v1/messages/messages/getPersonId/'+ params.id + '/' + params.type_id); + }, + getUid(params){ + return this.$fhcApi.get('api/frontend/v1/messages/messages/getUid/'+ params.id + '/' + params.type_id); }, getVorlagentext(vorlage_kurzbz){ return this.$fhcApi.get('api/frontend/v1/messages/messages/getVorlagentext/' + vorlage_kurzbz); @@ -29,7 +32,6 @@ export default { }, getReplyData(messageId){ return this.$fhcApi.get('api/frontend/v1/messages/messages/getReplyData/' + messageId); - }, sendMessage(form, id, data) { return this.$fhcApi.post(form,'api/frontend/v1/messages/messages/sendMessage/' + id, diff --git a/public/js/components/Messages/Details/NewMessage/NewDiv.js b/public/js/components/Messages/Details/NewMessage/NewDiv.js index 1eb59aa20..d8611d611 100644 --- a/public/js/components/Messages/Details/NewMessage/NewDiv.js +++ b/public/js/components/Messages/Details/NewMessage/NewDiv.js @@ -44,14 +44,16 @@ export default { data(){ return { formData: { - recipient: this.id, + recipient: null, subject: null, body: null, vorlage_kurzbz: null, selectedValue: '', + relationmessage_id: null }, statusNew: true, vorlagen: [], + recipientsArray: [], defaultRecipient: null, editor: null, isVisible: false, @@ -66,7 +68,9 @@ export default { itemsUser: [], previewText: null, previewBody: "", - replyData: null + replyData: null, + uid: null, + messageSent: false } }, methods: { @@ -105,19 +109,22 @@ export default { sendMessage() { //TODO(Manu) check default recipient(s) const data = new FormData(); + const params = { id: this.id, type_id: this.typeId }; + const merged = { ...this.formData, ...params }; data.append('data', JSON.stringify(merged)); + //this.uid is important for existing sendFunction return this.$fhcApi.factory.messages.person.sendMessage( this.$refs.formMessage, - this.id, + this.uid, data) .then(response => { this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSent')); @@ -129,6 +136,10 @@ export default { //this.resetForm(); //closeModal //closewindwo + this.messageSent = true; + //TODO(Manu) hier route definieren? ist kein child sondern mit route aufgerufen + //würde allerdings neues fenster aktualisiert öffnen, altes bleibt ohne reload gleich + //Reload vorheriges tab??? this.$emit('reloadTable'); } ); @@ -148,13 +159,13 @@ export default { //closewindwo }); }, - getPreviewText(){ + getPreviewText(id, typeId){ const data = new FormData(); data.append('data', JSON.stringify(this.formData.body)); return this.$fhcApi.factory.messages.person.getPreviewText({ - id: this.id, - type_id: this.typeId}, data) + id: id, + type_id: typeId}, data) .then(response => { this.previewText = response.data; }).catch(this.$fhcAlert.handleSystemError) @@ -167,7 +178,8 @@ export default { insertVariable(selectedItem){ if (this.editor) { this.editor.insertContent(selectedItem.value + " "); - //TODO(Manu) check: nicht mal mit Punkt adden gehts ohne eintrag nach vars + //TODO(Manu) check: Laden von Variblen geht nicht wenn kein Zeichen danach kommt + // nicht mal mit Punkt adden gehts ohne eintrag nach vars /* this.editor.focus(); this.editor.setDirty(true);*/ @@ -183,9 +195,6 @@ export default { console.error("Editor instance is not available."); } }, -/* replyMessage(message_id){ - console.log("auf message " + message_id + " antworten"); - },*/ resetForm(){ this.formData = { vorlage_kurzbz: null, @@ -219,11 +228,22 @@ export default { //just for testing: this.isVisible = true; }, - showPreview(){ - this.getPreviewText().then(() => { + showPreview(id, typeId){ + this.getPreviewText(id, typeId).then(() => { this.previewBody = this.previewText; }); }, + getUid(id, typeId){ + const params = { + id: id, + type_id: typeId + }; + this.$fhcApi.factory.messages.person.getUid(params) + .then(result => { + this.uid = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + } }, watch: { 'formData.body': { @@ -238,7 +258,6 @@ export default { }, 'formData.vorlage_kurzbz': { handler(newVal){ - // console.log("Vorlage: " + newVal); if (newVal && newVal != null) { this.formData.subject = newVal; @@ -248,6 +267,9 @@ export default { }, }, created(){ + if(this.typeId != 'uid') + this.getUid(this.id, this.typeId); + if(this.typeId == 'person_id'){ this.$fhcApi.factory.messages.person.getMessageVarsPerson() .then(result => { @@ -259,8 +281,13 @@ export default { }) .catch(this.$fhcAlert.handleSystemError); } - if(this.typeId == 'uid') { - this.$fhcApi.factory.messages.person.getMsgVarsPrestudent(this.id) + + if(this.typeId == 'uid' || this.typeId == 'prestudent_id') { + const params = { + id: this.id, + type_id: this.typeId + }; + this.$fhcApi.factory.messages.person.getMsgVarsPrestudent(params) .then(result => { this.fieldsPrestudent = result.data; const prestudent = this.fieldsPrestudent[0]; @@ -294,20 +321,21 @@ export default { }) .then(result => { this.defaultRecipient = result.data; + this.recipientsArray.push({'uid': this.uid, + 'details': this.defaultRecipient}); }) .catch(this.$fhcAlert.handleSystemError); + //case of reply if(this.messageId != null) { - - //get replayBody.. body receivername, receiverSurname, sentDate of message this.$fhcApi.factory.messages.person.getReplyData(this.messageId) .then(result => { this.replyData = result.data; this.formData.subject = this.replyData[0].replySubject; this.formData.body = this.replyData[0].replyBody; + this.formData.relationmessage_id = this.messageId; }) .catch(this.$fhcAlert.handleSystemError); - } }, @@ -320,12 +348,11 @@ export default { template: `
- -
+

New Message

@@ -465,19 +492,26 @@ export default {
-
+
+ +

- +
@@ -492,6 +526,43 @@ export default {
+ + +
+
+
+
+
+ Message sent successfully! +
+
+ Nachricht erfolgreich versandt! +
+
+ +
+
+ You can safely close this window. +
+
+ Sie können dieses Fenster schließen. +
+
+
+
+

+ Fachhochschule Technikum Wien | University of Applied Sciences Technikum Wien +
Hoechstaedtplatz 6, 1200 Wien, AUSTRIA +
www.technikum-wien.at +

+ +
+ + +
+ +
+
` diff --git a/public/js/components/Messages/Details/TableMessages.js b/public/js/components/Messages/Details/TableMessages.js index ab6a76599..317291c56 100644 --- a/public/js/components/Messages/Details/TableMessages.js +++ b/public/js/components/Messages/Details/TableMessages.js @@ -26,7 +26,6 @@ export default { messageLayout: String, openMode: String }, - //TODO(Manu) endpoint macht Probleme data(){ return { tabulatorOptions: { @@ -38,7 +37,7 @@ export default { type: this.typeId }; }, - ajaxResponse: (url, params, response) => response.data, + ajaxResponse: (url, params, response) => this.buildTreemap(response.data), columns: [ {title: "subject", field: "subject"}, {title: "body", field: "body", visible: false}, @@ -63,6 +62,7 @@ export default { {title: "recipient", field: "recipient"}, {title: "senderId", field: "sender_id"}, {title: "recipientId", field: "recipient_id"}, + {title: "relationmessage_id", field: "relationmessage_id"}, { title: "status", field: "status", @@ -110,7 +110,7 @@ export default { container.className = "d-flex gap-2"; let button = document.createElement('button'); - if (this.personId != cell.getData().recipient_id) + if (this.personId != cell.getData().sender_id) button.disabled = true; button.className = 'btn btn-outline-secondary btn-action'; button.title = this.$p.t('global', 'reply'); @@ -136,29 +136,23 @@ export default { return container; }, frozen: true - }], + } + ], layout: 'fitDataFill', layoutColumnsOnNewData: false, - // height: 'auto', height: '400', - selectable: true, selectableRangeMode: 'click', - pagination: true, - // paginationSize: 5, -/* layoutColumnsOnNewData: false, - - selectableRangeMode: 'click', - selectable: true, index: 'message_id', - persistenceID: 'core-message'*/ + pagination: true, + dataTree: true, + headerSort: true, + dataTreeChildField: "children", + dataTreeCollapseElement:"", + dataTreeChildIndent: 15, + dataTreeStartExpanded: false, + persistenceID: 'core-message' }, tabulatorEvents: [ - { - event: 'dataLoaded', - handler: data => this.tabulatorData = data.map(item => { - return item; - }), - }, { event: 'tableBuilt', handler: async() => { @@ -213,7 +207,59 @@ export default { tabulatorData: [], previewBody: "", open: false, - personId: null + personId: null, + //Testdata +/* messages: [ + { + message_id: 7, + subject: "Antwort auf 4", + body: "Text 5", + insertamum: "2024-03-05", + relationmessage_id: 6, + }, + { + message_id: 1, + subject: "Hauptnachricht", + body: "Text 1", + insertamum: "2024-03-05", + relationmessage_id: null, + }, + { + message_id: 2, + subject: "Antwort auf 1", + body: "Text 2", + insertamum: "2024-03-05", + relationmessage_id: 1, + }, + { + message_id: 3, + subject: "Antwort auf 2", + body: "Text 3", + insertamum: "2024-03-05", + relationmessage_id: 2, + }, + { + message_id: 4, + subject: "Neue Nachricht", + body: "Text 4", + insertamum: "2024-03-05", + relationmessage_id: null, + }, + { + message_id: 5, + subject: "Antwort auf 4", + body: "Text 5", + insertamum: "2024-03-05", + relationmessage_id: 4, + }, + { + message_id: 6, + subject: "Antwort auf 4", + body: "Text 5", + insertamum: "2024-03-05", + relationmessage_id: 5, + }, + ],*/ } }, methods: { @@ -237,7 +283,11 @@ export default { }); }, actionNewMessage(){ + // this.$emit('newMessage', this.id, this.typeId); + + //here already use person_id?? this.$emit('newMessage', this.id, this.typeId); + //console.log("action new message"); }, @@ -247,6 +297,47 @@ export default { reload() { this.$refs.table.reloadTable(); }, + buildTreemap(messages) { + const messageMap = new Map(); + const messageNested = []; + const remainingMessages = new Set(messages); + + //save all Data in Map + messages.forEach(msg => messageMap.set(msg.message_id, msg)); + + let iteration = 0; + let changes = true; + + // do until each relationmessage_id finds message_id (not sensitive to order) + while (changes) { + changes = false; + iteration++; + + remainingMessages.forEach(msg => { + if (msg.relationmessage_id === null) { + messageNested.push(messageMap.get(msg.message_id)); + remainingMessages.delete(msg); + changes = true; + } else if (messageMap.has(msg.relationmessage_id)) { + + const parent = messageMap.get(msg.relationmessage_id); + + if (!parent.children) { + parent.children = []; + } + parent.children.push(messageMap.get(msg.message_id)); + remainingMessages.delete(msg); + changes = true; + } + }); + + // to avoid endless loop + if (iteration > messages.length) break; + } + return messageNested; +} + + }, computed: { statusText(){ @@ -256,7 +347,7 @@ export default { 2: this.$p.t('messsages', 'archived'), 3: this.$p.t('messsages', 'deleted') } - } + }, }, mounted() { // change to target="_blank" @@ -269,8 +360,12 @@ export default { });*/ }, created(){ - if(this.typeId == 'uid') { - this.$fhcApi.factory.messages.person.getPersonIdFromUid(this.id) + if(this.typeId == 'uid' || this.typeId == 'prestudent_id') { + const params = { + id: this.id, + type_id: this.typeId + }; + this.$fhcApi.factory.messages.person.getPersonId(params) .then(result => { this.personId = result.data; }) @@ -279,7 +374,7 @@ export default { }, template: `
- +
@@ -313,6 +408,7 @@ export default {
+
diff --git a/public/js/components/Messages/Messages.js b/public/js/components/Messages/Messages.js index e6947a72a..fc73768f1 100644 --- a/public/js/components/Messages/Messages.js +++ b/public/js/components/Messages/Messages.js @@ -58,6 +58,7 @@ export default { }, methods: { reloadTable(){ + console.log("in parent reload"); this.$refs.templateTableMessage.reload(); }, newMessage(id, typeId){ @@ -121,7 +122,6 @@ export default { path += "/NeueNachricht/" + id + "/" + typeId; } - const newTab = window.open(path, "_blank"); }, openInNewWindow(id, typeId){ @@ -160,6 +160,7 @@ export default {
--> +
+ + +
` From a0ce635c7eb60460cd8075c7f208d9f721979e3d Mon Sep 17 00:00:00 2001 From: ma0068 Date: Wed, 12 Mar 2025 15:04:37 +0100 Subject: [PATCH 010/107] Refactor and Cleanup - adapt tabulator and queries for remote pagination - use formatterParams for messageStati to enable phrase logic - adapt logic for mitarbeiter_uid - refactor logic to use new Page, new Tab and newDiv with one child component - add phrases --- .../api/frontend/v1/messages/Messages.php | 59 +++++-- application/models/system/Message_model.php | 62 ++++++-- public/js/api/messages/person.js | 14 +- .../{NewMessage.js => Depr_NewMessage.js} | 0 .../Messages/Details/NewMessage/Modal.js | 148 +++++++++++++----- .../Messages/Details/NewMessage/NewDiv.js | 116 +++++++------- .../Messages/Details/TableMessages.js | 108 ++++--------- public/js/components/Messages/Messages.js | 140 +++++++---------- .../Studentenverwaltung/Details/Messages.js | 31 +++- system/phrasesupdate.php | 80 ++++++++++ 10 files changed, 459 insertions(+), 299 deletions(-) rename public/js/components/Messages/Details/{NewMessage.js => Depr_NewMessage.js} (100%) diff --git a/application/controllers/api/frontend/v1/messages/Messages.php b/application/controllers/api/frontend/v1/messages/Messages.php index 65c354c4f..7834ba5f7 100644 --- a/application/controllers/api/frontend/v1/messages/Messages.php +++ b/application/controllers/api/frontend/v1/messages/Messages.php @@ -41,17 +41,27 @@ class Messages extends FHCAPI_Controller ]); } - public function getMessages($id, $type_id) + public function getMessages($id, $type_id, $size, $page) { if($type_id != 'person_id'){ $id = $this->_getPersonId($id, $type_id); } - $result = $this->MessageModel->getMessagesForTable($id); + $offset = $size * ($page - 1); + $limit = $size; + + $result = $this->MessageModel->getMessagesForTable($id, $offset, $limit); $data = $this->getDataOrTerminateWithError($result); - $this->terminateWithSuccess($data); + //return null if count == 0 + if($data['count'] == 0){ + $this->terminateWithSuccess([]); + } + + $this->addMeta('count', $data['count']); + + $this->terminateWithSuccess($data['data']); } public function getVorlagen() @@ -107,9 +117,10 @@ class Messages extends FHCAPI_Controller $this->terminateWithSuccess($vorlage->text); } - public function getMessageVarsPerson() + public function getMessageVarsPerson($id, $typeId) { - $result = $this->MessageModel->getMessageVarsPerson(); + $person_id = ($typeId == 'mitarbeiter_uid') ? $this->_getPersonId($id, $typeId) : $id; + $result = $this->MessageModel->getMessageVarsPerson($person_id); $data = $this->getDataOrTerminateWithError($result); @@ -119,7 +130,7 @@ class Messages extends FHCAPI_Controller public function getMsgVarsPrestudent($id, $typeId) { - $prestudent_id = ($typeId == 'prestudent_id') ? $id : $this->_getPrestudentIdFromUid($id); + $prestudent_id = ($typeId == 'uid') ? $this->_getPrestudentIdFromUid($id) : $id; $result = $this->MessageModel->getMsgVarsDataByPrestudentId($prestudent_id); @@ -138,7 +149,7 @@ class Messages extends FHCAPI_Controller public function getNameOfDefaultRecipient($id, $type_id) { - $id = $type_id!='person_id)' ? $this->_getPersonId($id, $type_id) : $id; + $id = ($type_id != 'person_id') ? $this->_getPersonId($id, $type_id) : $id; $this->load->model('person/Person_model', 'PersonModel'); @@ -151,8 +162,8 @@ class Messages extends FHCAPI_Controller public function sendMessage($recipient_id) { - //is always uid in FAS - //TODO(Manu) make dynamic for other ids + //has to be uid + // $this->terminateWithError("uid", $recipient_id, self::ERROR_TYPE_GENERAL); //default setting $receiversPersonId = $this->_getPersonId($recipient_id, 'uid'); @@ -205,10 +216,17 @@ class Messages extends FHCAPI_Controller $result = $this->MessagesModel->parseMessageTextPrestudent($prestudent_id, $body); $bodyParsed = $this->getDataOrTerminateWithError($result); } + if($typeId == 'mitarbeiter_uid') + { + $person_id = $this->_getPersonId($id, $typeId); + + $result = $this->MessagesModel->parseMessageTextPerson($person_id, $body); + $bodyParsed = $this->getDataOrTerminateWithError($result); + $this->terminateWithError($bodyParsed, self::ERROR_TYPE_GENERAL); + + } elseif($typeId == 'person_id') { - $this->terminateWithError("person_id ", self::ERROR_TYPE_GENERAL); - $result = $this->MessagesModel->parseMessageTextPerson($id, $body); $bodyParsed = $this->getDataOrTerminateWithError($result); } @@ -235,7 +253,6 @@ class Messages extends FHCAPI_Controller { $data = json_decode($_POST['data']); unset($_POST['data']); - } else $this->terminateWithError("Textbody missing ", self::ERROR_TYPE_GENERAL); @@ -249,6 +266,15 @@ class Messages extends FHCAPI_Controller case 'prestudent_id': $result = $this->MessagesModel->parseMessageTextPrestudent($id, $data); break; + case 'person_id': + $result = $this->MessagesModel->parseMessageTextPerson($id, $data); + break; + case 'mitarbeiter_uid': + { + $person_id = $this->_getPersonId($id, $type_id); + $result = $this->MessagesModel->parseMessageTextPerson($person_id, $data); + } + break; default: $this->terminateWithError("MESSAGES::getPreviewText logic for type_id " . $type_id . " not defined yet", self::ERROR_TYPE_GENERAL); break; @@ -318,7 +344,7 @@ class Messages extends FHCAPI_Controller public function getPersonId($id, $typeId) { - if ($typeId == 'uid') + if ($typeId == 'uid' || $typeId == 'mitarbeiter_uid') { $this->load->model('person/Benutzer_model', 'BenutzerModel'); $result = $this->BenutzerModel->loadWhere( @@ -368,7 +394,7 @@ class Messages extends FHCAPI_Controller ['person_id' => $person_id] ); } - elseif($typeId == 'uid') + elseif($typeId == 'uid' || $typeId == 'mitarbeiter_uid') { $this->terminateWithSuccess($id); } @@ -385,7 +411,7 @@ class Messages extends FHCAPI_Controller private function _getPersonId($id, $typeId) { - if ($typeId == 'uid') + if ($typeId == 'uid' || $typeId == 'mitarbeiter_uid') { $this->load->model('person/Benutzer_model', 'BenutzerModel'); $result = $this->BenutzerModel->loadWhere( @@ -408,6 +434,7 @@ class Messages extends FHCAPI_Controller private function _getPrestudentIdFromUid($uid) { + // $this->terminateWithError($uid, self::ERROR_TYPE_GENERAL); $this->load->model('crm/Student_model', 'StudentModel'); $result = $this->StudentModel->loadWhere( ['student_uid' => $uid] @@ -415,7 +442,7 @@ class Messages extends FHCAPI_Controller $data = $this->getDataOrTerminateWithError($result); $student = current($data); - + // $this->terminateWithError($student->prestudent_id, self::ERROR_TYPE_GENERAL); return $student->prestudent_id; } diff --git a/application/models/system/Message_model.php b/application/models/system/Message_model.php index 38defa383..acbe3a44c 100644 --- a/application/models/system/Message_model.php +++ b/application/models/system/Message_model.php @@ -234,12 +234,15 @@ class Message_model extends DB_Model /** * Gets messages for a person for tableMessages. * @param $person_id - * @param null $status message status. by default, latest status is returned + * paginationInitialPage: 1, + * @param $offset number to skip, calculated by tabulatorParam paginationInitialPage and paginationSize, refers to specified numer of skipped items + * and page + * @param $limit refers to tabulatorParam paginationSize * @return array|null */ - public function getMessagesForTable($person_id, $status = null) + public function getMessagesForTable($person_id, $offset, $limit) { - $sql = " + $sql_base = " SELECT m.message_id AS message_id, m.subject AS subject, @@ -275,20 +278,45 @@ class Message_model extends DB_Model JOIN public.tbl_msg_message m USING(message_id) WHERE r.person_id = ? GROUP BY m.message_id, m.subject, m.body, m.insertamum, m.relationmessage_id, sender, recipient, sender_id, recipient_id - ORDER BY insertamum DESC + "; + $sql = " + SELECT COUNT(*) AS count FROM ( + " . $sql_base . " + ) a "; $parametersArray = array($person_id, $person_id); - return $this->execQuery($sql, $parametersArray); + $count = $this->execQuery($sql, $parametersArray); + + if (isError($count)) + return $count; + + $count = floor(current(getData($count))->count/$limit); + $sql = " + SELECT * FROM ( + " . $sql_base . " + ) a + ORDER BY insertamum DESC + LIMIT ? + OFFSET ? + "; + + $parametersArray = array($person_id, $person_id, $limit, $offset); + + $data = $this->execQuery($sql, $parametersArray); + + if (isError($data)) + return $data; + + $data = getData($data); + + return success(['data' => $data, 'count' => $count]); } /** - * Deletes a messages from tableMessages and tbl_msg_recipient - * TODO(MANU) CHECK IF NECESSARY - * dependency with other tables - * in case of reply... more messages?? delete all dependent ones? - * maybe anonimize it + * Deletes entry in dependency table tbl_msg_recipient + * * @param $message_id * @return boolean success */ @@ -302,7 +330,12 @@ class Message_model extends DB_Model return $this->execQuery($sql, array($message_id)); } - + /** + * Deletes entry in dependency table tbl_msg_status + * + * @param $message_id + * @return boolean success + */ public function deleteMessageStatus($message_id) { $sql = " @@ -312,7 +345,12 @@ class Message_model extends DB_Model return $this->execQuery($sql, array($message_id)); } - + /** + * Deletes entry in dependency table tbl_msg_message + * + * @param $message_id + * @return boolean success + */ public function deleteMessage($message_id) { $sql = " diff --git a/public/js/api/messages/person.js b/public/js/api/messages/person.js index e53f23f6a..6fa39c6ba 100644 --- a/public/js/api/messages/person.js +++ b/public/js/api/messages/person.js @@ -1,6 +1,7 @@ export default { - getMessages(url, config, params){ - return this.$fhcApi.get('api/frontend/v1/messages/messages/getMessages/' + params.id + '/' + params.type); + getMessages(url, config, params) { + console.log('page ' + params.page + ' size ' + params.size); + return this.$fhcApi.get('api/frontend/v1/messages/messages/getMessages/' + params.id + '/' + params.type + '/' + params.size + '/' + params.page); }, getVorlagen(){ return this.$fhcApi.get('api/frontend/v1/messages/messages/getVorlagen/'); @@ -8,8 +9,8 @@ export default { getMsgVarsLoggedInUser(){ return this.$fhcApi.get('api/frontend/v1/messages/messages/getMsgVarsLoggedInUser/'); }, - getMessageVarsPerson(){ - return this.$fhcApi.get('api/frontend/v1/messages/messages/getMessageVarsPerson/'); + getMessageVarsPerson(params){ + return this.$fhcApi.get('api/frontend/v1/messages/messages/getMessageVarsPerson/' + params.id + '/' + params.type_id); }, getMsgVarsPrestudent(params){ return this.$fhcApi.get('api/frontend/v1/messages/messages/getMsgVarsPrestudent/' + params.id + '/' + params.type_id); @@ -34,9 +35,14 @@ export default { return this.$fhcApi.get('api/frontend/v1/messages/messages/getReplyData/' + messageId); }, sendMessage(form, id, data) { + console.log("id" + id); return this.$fhcApi.post(form,'api/frontend/v1/messages/messages/sendMessage/' + id, data); }, +/* sendMessage(id, data) { + return this.$fhcApi.post('api/frontend/v1/messages/messages/sendMessage/' + id, + data); + },*/ deleteMessage(messageId){ return this.$fhcApi.post('api/frontend/v1/messages/messages/deleteMessage/' + messageId); } diff --git a/public/js/components/Messages/Details/NewMessage.js b/public/js/components/Messages/Details/Depr_NewMessage.js similarity index 100% rename from public/js/components/Messages/Details/NewMessage.js rename to public/js/components/Messages/Details/Depr_NewMessage.js diff --git a/public/js/components/Messages/Details/NewMessage/Modal.js b/public/js/components/Messages/Details/NewMessage/Modal.js index 9bfe49929..c6d3e1210 100644 --- a/public/js/components/Messages/Details/NewMessage/Modal.js +++ b/public/js/components/Messages/Details/NewMessage/Modal.js @@ -22,19 +22,25 @@ export default { type: [Number, String], required: true }, + messageId: { + type: Number, + required: false, + }, openMode: String, }, data(){ return { formData: { - recipient: this.id, + recipient: null, subject: null, body: null, vorlage_kurzbz: null, selectedValue: '', + relationmessage_id: null }, statusNew: true, vorlagen: [], + recipientsArray: [], defaultRecipient: null, editor: null, fieldsUser: [], @@ -47,7 +53,9 @@ export default { itemsPerson: [], itemsUser: [], previewText: null, - previewBody: "" + previewBody: "", + replyData: null, + uid: null, } }, methods: { @@ -98,12 +106,14 @@ export default { return this.$fhcApi.factory.messages.person.sendMessage( this.$refs.formMessage, - this.id, + this.uid, data) +/* return this.$fhcApi.factory.messages.person.sendMessage( + this.uid, + data)*/ .then(response => { this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSent')); - //this.hideModal('messageModal'); - this.hideTemplate(); + this.hideModal('modalNewMessage'); this.resetForm(); }).catch(this.$fhcAlert.handleSystemError) .finally(() => { @@ -119,7 +129,7 @@ export default { return this.$fhcApi.factory.messages.person.getVorlagentext(vorlage_kurzbz) .then(response => { //this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSent')); - //this.hideModal('messageModal'); + //this.hideModal('modalNewMessage'); //this.resetForm(); //TODO(Manu) CHECK this.formData.body = response.data; @@ -165,20 +175,22 @@ export default { console.error("Editor instance is not available."); } }, - replyMessage(message_id){ - console.log("auf message " + message_id + " antworten"); - }, resetForm(){ this.formData = { vorlage_kurzbz: null, body: null, subject: null, }; + this.$emit('resetMessageId'); + if (this.editor) { this.editor.setContent(""); } + this.$refs.dropdownComp.setValue(null); + this.previewBody = null; + }, handleSelectedVorlage(vorlage_kurzbz) { if (typeof vorlage_kurzbz === "string") { @@ -186,22 +198,28 @@ export default { this.formData.subject = vorlage_kurzbz; } }, - hideTemplate(){ - if (this.openMode == "showDiv") - this.isVisible = false; - }, - showTemplate(){ - if (this.openMode == "showDiv") - this.isVisible = true; - }, showPreview(){ this.getPreviewText().then(() => { this.previewBody = this.previewText; }); }, + getUid(id, typeId){ + const params = { + id: id, + type_id: typeId + }; + this.$fhcApi.factory.messages.person.getUid(params) + .then(result => { + this.uid = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + }, show(){ this.$refs.modalNewMessage.show(); - } + }, + hideModal(modalRef){ + this.$refs[modalRef].hide(); + }, }, watch: { 'formData.body': { @@ -223,11 +241,37 @@ export default { return this.getVorlagentext(newVal); } } + }, + messageId: { + immediate: true, + handler: async function (newMessageId) { + if (!newMessageId) return; + + try { + const result = await this.$fhcApi.factory.messages.person.getReplyData(newMessageId); + this.replyData = result.data; + console.log(this.replyData); + + if (this.replyData.length > 0) { + this.formData.subject = this.replyData[0].replySubject; + this.formData.body = this.replyData[0].replyBody; + this.formData.relationmessage_id = newMessageId; + } + } catch (error) { + this.$fhcAlert.handleSystemError(error); + } + } } }, created(){ - if(this.typeId == 'person_id'){ - this.$fhcApi.factory.messages.person.getMessageVarsPerson() + this.getUid(this.id, this.typeId); + + if(this.typeId == 'person_id' || this.typeId == 'mitarbeiter_uid'){ + const params = { + id: this.id, + type_id: this.typeId + }; + this.$fhcApi.factory.messages.person.getMessageVarsPerson(params) .then(result => { this.fieldsPerson = result.data; this.itemsPerson = Object.entries(this.fieldsPerson).map(([key, value]) => ({ @@ -237,16 +281,16 @@ export default { }) .catch(this.$fhcAlert.handleSystemError); } - if(this.typeId == 'uid') { - this.$fhcApi.factory.messages.person.getMsgVarsPrestudent(this.id) + + if(this.typeId == 'prestudent_id' || this.typeId == 'uid'){ + const params = { + id: this.id, + type_id: this.typeId + }; + this.$fhcApi.factory.messages.person.getMsgVarsPrestudent(params) .then(result => { this.fieldsPrestudent = result.data; const prestudent = this.fieldsPrestudent[0]; - //Just for testing with inserting values - /* this.itemsPrestudent = Object.entries(prestudent).map(([key, value]) => ({ - label: key, - value: value - }));*/ this.itemsPrestudent = Object.entries(prestudent).map(([key, value]) => ({ label: key.toLowerCase(), value: '{' + key.toLowerCase() + '}' @@ -271,8 +315,25 @@ export default { type_id: this.typeId}) .then(result => { this.defaultRecipient = result.data; + // console.log("check " + this.uid + "|" + this.defaultRecipient); + this.recipientsArray.push({ + 'uid': this.uid, + 'details': this.defaultRecipient}); + // console.log(JSON.stringify(this.recipientsArray)); }) .catch(this.$fhcAlert.handleSystemError); + + //case of reply + if(this.messageId) { + this.$fhcApi.factory.messages.person.getReplyData(this.messageId) + .then(result => { + this.replyData = result.data; + this.formData.subject = this.replyData[0].replySubject; + this.formData.body = this.replyData[0].replyBody; + this.formData.relationmessage_id = this.messageId; + }) + .catch(this.$fhcAlert.handleSystemError); + } }, async mounted() { this.initTinyMCE(); @@ -281,10 +342,15 @@ export default { this.editor.destroy(); }, template: ` - + @@ -296,7 +362,6 @@ export default {
-
- Felder Prestudent + {{$p.t('ui', 'felder')}} {{$p.t('lehre', 'prestudent')}}
- -

{{selectedFieldPrestudent}}

-
@@ -387,12 +449,10 @@ export default {
- -

{{selectedFieldPerson}}

- Meine Felder + {{$p.t('messages', 'meineFelder')}}
-
@@ -417,7 +476,7 @@ export default {
-

Vorschau:

+

{{ $p.t('global', 'vorschau') }}:

@@ -428,12 +487,19 @@ export default { :label="$p.t('messages/recipient')" v-model="defaultRecipient" > + +

- +
@@ -454,7 +520,7 @@ export default { - -
`, } \ No newline at end of file diff --git a/public/js/components/Messages/Details/NewMessage/NewDiv.js b/public/js/components/Messages/Details/NewMessage/NewDiv.js index f1dc4c88a..4331dd734 100644 --- a/public/js/components/Messages/Details/NewMessage/NewDiv.js +++ b/public/js/components/Messages/Details/NewMessage/NewDiv.js @@ -104,7 +104,6 @@ export default { this.formData.body = value; }, sendMessage() { - //TODO(Manu) check default recipient(s) const data = new FormData(); const params = { @@ -118,42 +117,34 @@ export default { }; data.append('data', JSON.stringify(merged)); - //this.uid is important for existing sendFunction + //this.uid is necessary for existing sendFunction return this.$fhcApi.factory.messages.person.sendMessage( - this.$refs.formMessage, this.uid, data) .then(response => { this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSent')); - //this.hideModal('messageModal'); this.hideTemplate(); this.resetForm(); + this.messageSent = true; }).catch(this.$fhcAlert.handleSystemError) .finally(() => { - //this.resetForm(); - //closeModal - //closewindwo - this.messageSent = true; - //TODO(Manu) hier route definieren? ist kein child sondern mit route aufgerufen + //TODO(Manu) hier route definieren für openmode in Tab, Page? + // ist kein child sondern mit route aufgerufen //würde allerdings neues fenster aktualisiert öffnen, altes bleibt ohne reload gleich //Reload vorheriges tab??? + if(this.openMode == "inSamePage"){ this.$emit('reloadTable'); + } } ); }, getVorlagentext(vorlage_kurzbz){ return this.$fhcApi.factory.messages.person.getVorlagentext(vorlage_kurzbz) .then(response => { - //this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSent')); - //this.hideModal('messageModal'); - //this.resetForm(); - //TODO(Manu) CHECK this.formData.body = response.data; }).catch(this.$fhcAlert.handleSystemError) .finally(() => { //this.resetForm(); - //closeModal - //closewindwo }); }, getPreviewText(id, typeId){ @@ -168,8 +159,6 @@ export default { }).catch(this.$fhcAlert.handleSystemError) .finally(() => { //this.resetForm(); - //closeModal - //closewindwo }); }, insertVariable(selectedItem){ @@ -275,9 +264,10 @@ export default { this.$fhcApi.factory.messages.person.getMessageVarsPerson(params) .then(result => { this.fieldsPerson = result.data; - this.itemsPerson = Object.entries(this.fieldsPerson).map(([key, value]) => ({ - label: value, - value: '{' + value + '}' + const person = this.fieldsPerson[0]; + this.itemsPerson = Object.entries(person).map(([key, value]) => ({ + label: key.toLowerCase(), + value: '{' + key.toLowerCase() + '}' })); }) .catch(this.$fhcAlert.handleSystemError); @@ -345,9 +335,6 @@ export default { template: `
- - -

{{ $p.t('messages', 'neueNachricht') }}

@@ -356,7 +343,6 @@ export default {
-
-
+
- + + + + diff --git a/public/js/components/VorlagenDropdown/VorlagenDropdown.js b/public/js/components/VorlagenDropdown/VorlagenDropdown.js index e5d80077e..03d8564d6 100644 --- a/public/js/components/VorlagenDropdown/VorlagenDropdown.js +++ b/public/js/components/VorlagenDropdown/VorlagenDropdown.js @@ -23,11 +23,11 @@ export default { }, */ isAdmin: { type: Boolean, - required: true + required: false }, useLoggedInUserOe: { type: Boolean, - required: true + required: false } }, data() { From 3b8b8d7882ee052e930da2c0df2b5f4b16ee9527 Mon Sep 17 00:00:00 2001 From: ma0068 Date: Thu, 13 Mar 2025 09:34:06 +0100 Subject: [PATCH 012/107] remove testdata in getFunction --- .../controllers/api/frontend/v1/messages/Messages.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/application/controllers/api/frontend/v1/messages/Messages.php b/application/controllers/api/frontend/v1/messages/Messages.php index 101a47185..dbc11735a 100644 --- a/application/controllers/api/frontend/v1/messages/Messages.php +++ b/application/controllers/api/frontend/v1/messages/Messages.php @@ -54,11 +54,6 @@ class Messages extends FHCAPI_Controller $data = $this->getDataOrTerminateWithError($result); - //return null if count == 0 - if($data['count'] == 0){ - $this->terminateWithSuccess([]); - } - $this->addMeta('count', $data['count']); $this->terminateWithSuccess($data['data']); From b75c9cc524420a68b85167e0db82da220c3d9dac Mon Sep 17 00:00:00 2001 From: ma0068 Date: Thu, 20 Mar 2025 11:16:05 +0100 Subject: [PATCH 013/107] portation of tab Anrechnungen - switch version edit / non edit in config --- application/config/stv.php | 6 +- .../api/frontend/v1/stv/Anrechnungen.php | 241 ++++++++++ .../api/frontend/v1/stv/Config.php | 6 + .../models/education/Anrechnung_model.php | 62 +++ .../education/Lehrveranstaltung_model.php | 37 ++ .../models/ressource/Mitarbeiter_model.php | 35 +- public/js/api/stv.js | 3 + public/js/api/stv/exemptions.js | 29 ++ .../Details/Anrechnungen.js | 25 ++ .../Details/Anrechnungen/Anrechnungen.js | 425 ++++++++++++++++++ system/phrasesupdate.php | 142 ++++++ 11 files changed, 1007 insertions(+), 4 deletions(-) create mode 100644 application/controllers/api/frontend/v1/stv/Anrechnungen.php create mode 100644 public/js/api/stv/exemptions.js create mode 100644 public/js/components/Stv/Studentenverwaltung/Details/Anrechnungen.js create mode 100644 public/js/components/Stv/Studentenverwaltung/Details/Anrechnungen/Anrechnungen.js diff --git a/application/config/stv.php b/application/config/stv.php index 31ce3f521..1fdd5b28a 100644 --- a/application/config/stv.php +++ b/application/config/stv.php @@ -52,7 +52,11 @@ $config['tabs'] = ], ], ], - ] + ], + 'exemptions' => [ + //if true, Anrechnungen can be added and edited in tab Anrechnungen + 'editableAnrechnungen' => false, + ], ]; // List of fields to show when ZGV_DOKTOR_ANZEIGEN is defined diff --git a/application/controllers/api/frontend/v1/stv/Anrechnungen.php b/application/controllers/api/frontend/v1/stv/Anrechnungen.php new file mode 100644 index 000000000..85019334f --- /dev/null +++ b/application/controllers/api/frontend/v1/stv/Anrechnungen.php @@ -0,0 +1,241 @@ + ['admin:r', 'assistenz:r'], + 'deleteAnrechnung' => ['admin:rw', 'assistenz:rw'], + 'getLehrveranstaltungen' => ['admin:r', 'assistenz:r'], + 'getBegruendungen' => ['admin:r', 'assistenz:r'], + 'getLektoren' => ['admin:r', 'assistenz:r'], + 'getLvsKompatibel' => ['admin:r', 'assistenz:r'], + 'insertAnrechnung' => ['admin:rw', 'assistenz:rw'], + 'loadAnrechnung' => ['admin:rw', 'assistenz:rw'], + 'updateAnrechnung' => ['admin:rw', 'assistenz:rw'], + ]); + + // Load Libraries + $this->load->library('VariableLib', ['uid' => getAuthUID()]); + + // Load language phrases + $this->loadPhrases([ + 'ui', 'lehre' + ]); + + // Load models + $this->load->model('education/Anrechnung_model', 'AnrechnungsModel'); + } + + public function getAnrechnungen($prestudent_id) + { + $result = $this->AnrechnungsModel->getAnrechnungsData($prestudent_id); + + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + + public function getBegruendungen() + { + $this->load->model('education/Anrechnungbegruendung_model', 'AnrechnungbegrueundungsModel'); + + $result = $this->AnrechnungbegrueundungsModel->load(); + if (isError($result)) { + $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + } + $this->terminateWithSuccess(getData($result) ?: []); + } + + public function getLehrveranstaltungen($prestudent_id) + { + $this->load->model('crm/Prestudentstatus_model', 'PrestudentstatusModel'); + $result = $this->PrestudentstatusModel->getLastStatus($prestudent_id); + + $data = $this->getDataOrTerminateWithError($result); + $studienplan_id = current($data)->studienplan_id; + + $this->load->model('education/Lehrveranstaltung_model', 'LehrveranstaltungModel'); + $result = $this->LehrveranstaltungModel->getLvsByStudienplanId($studienplan_id); + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + + public function getLvsKompatibel($lehrveranstaltung_id) + { + $this->AnrechnungsModel->addJoin('lehre.tbl_lehrveranstaltung lv', 'ON (lv.lehrveranstaltung_id = lehre.tbl_anrechnung.lehrveranstaltung_id)'); + $result = $this->AnrechnungsModel->loadWhere( + ['lehrveranstaltung_id_kompatibel' => $lehrveranstaltung_id] + ); + + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + + public function getLektoren($studiengang_kz) + { + $this->load->model('ressource/Mitarbeiter_model', 'MitarbeiterModel'); + + $result = $this->MitarbeiterModel->getLektoren($studiengang_kz); + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + + public function insertAnrechnung() + { + $this->load->library('form_validation'); + + $prestudent_id = $this->input->post('prestudent_id'); + + if(!$prestudent_id) + { + return $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Student UID']), self::ERROR_TYPE_GENERAL); + } + + $formData = $this->input->post('formData'); + $_POST['lehrveranstaltung_id'] = + (isset($formData['lehrveranstaltung_id']) && !empty($formData['lehrveranstaltung_id'])) + ? $formData['lehrveranstaltung_id'] + : null; + $_POST['lehrveranstaltung_id_kompatibel'] = + (isset($formData['lehrveranstaltung_id_kompatibel']) && !empty($formData['lehrveranstaltung_id_kompatibel'])) + ? $formData['lehrveranstaltung_id_kompatibel'] + : null; + $_POST['begruendung'] = + (isset($formData['begruendung_id']) && !empty($formData['begruendung_id'])) + ? $formData['begruendung_id'] + : null; + $_POST['genehmigtVon'] = (isset($formData['genehmigt_von']) && !empty($formData['genehmigt_von'])) + ? $formData['genehmigt_von'] + : null; + + $this->form_validation->set_rules('lehrveranstaltung_id', 'Lehrveranstaltung_id', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Lehrveranstaltung']) + ]); + + $this->form_validation->set_rules('begruendung', 'Begruendung', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Begruendung']) + ]); + + if($_POST['begruendung'] == 2) + { + $this->form_validation->set_rules('lehrveranstaltung_id_kompatibel', 'Lehrveranstaltung_id', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Lehrveranstaltung Kompatibel']) + ]); + } + + $this->form_validation->set_rules('genehmigtVon', 'GenehmigtVon', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'GenehmigtVon']) + ]); + + if ($this->form_validation->run() == false) + { + $this->terminateWithValidationErrors($this->form_validation->error_array()); + } + + $result = $this->AnrechnungsModel->insert( + [ + 'prestudent_id' => $prestudent_id, + 'lehrveranstaltung_id' => $_POST['lehrveranstaltung_id'], + 'lehrveranstaltung_id_kompatibel' => $_POST['lehrveranstaltung_id_kompatibel'], + 'begruendung_id' => $_POST['begruendung'], + 'genehmigt_von' => $_POST['genehmigtVon'] + ] + ); + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + + public function loadAnrechnung($anrechnung_id) + { + $result = $this->AnrechnungsModel->loadWhere( + array('anrechnung_id' => $anrechnung_id) + ); + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess(current($data)); + } + + public function updateAnrechnung() + { + $this->load->library('form_validation'); + + $anrechnung_id = $this->input->post('anrechnung_id'); + + if(!$anrechnung_id) + { + return $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Anrechnung UID']), self::ERROR_TYPE_GENERAL); + } + + $formData = $this->input->post('formData'); + $_POST['lehrveranstaltung_id'] = + (isset($formData['lehrveranstaltung_id']) && !empty($formData['lehrveranstaltung_id'])) + ? $formData['lehrveranstaltung_id'] + : null; + $_POST['lehrveranstaltung_id_kompatibel'] = + (isset($formData['lehrveranstaltung_id_kompatibel']) && !empty($formData['lehrveranstaltung_id_kompatibel'])) + ? $formData['lehrveranstaltung_id_kompatibel'] + : null; + $_POST['begruendung'] = (isset($formData['begruendung_id']) && !empty($formData['begruendung_id'])) ? $formData['begruendung_id'] : null; + $_POST['genehmigtVon'] = (isset($formData['genehmigt_von']) && !empty($formData['genehmigt_von'])) ? $formData['genehmigt_von'] : null; + + $this->form_validation->set_rules('lehrveranstaltung_id', 'Lehrveranstaltung_id', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Lehrveranstaltung']) + ]); + + $this->form_validation->set_rules('begruendung', 'Begruendung', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Begruendung']) + ]); + + if($_POST['begruendung'] == 2) + { + $this->form_validation->set_rules('lehrveranstaltung_id_kompatibel', 'Lehrveranstaltung_id', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Lehrveranstaltung Kompatibel']) + ]); + } + + $this->form_validation->set_rules('genehmigtVon', 'GenehmigtVon', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'GenehmigtVon']) + ]); + + if ($this->form_validation->run() == false) + { + $this->terminateWithValidationErrors($this->form_validation->error_array()); + } + + $result = $this->AnrechnungsModel->update( + [ + 'anrechnung_id' => $anrechnung_id, + ], + [ + + 'lehrveranstaltung_id' => $_POST['lehrveranstaltung_id'], + 'lehrveranstaltung_id_kompatibel' => $_POST['lehrveranstaltung_id_kompatibel'], + 'begruendung_id' => $_POST['begruendung'], + 'genehmigt_von' => $_POST['genehmigtVon'] + ] + ); + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + + public function deleteAnrechnung($anrechnung_id) + { + $result = $this->AnrechnungsModel->delete( + array('anrechnung_id' => $anrechnung_id) + ); + + $data = $this->getDataOrTerminateWithError($result); + $this->terminateWithSuccess($data); + } +} diff --git a/application/controllers/api/frontend/v1/stv/Config.php b/application/controllers/api/frontend/v1/stv/Config.php index 42de1b02f..319abdd83 100644 --- a/application/controllers/api/frontend/v1/stv/Config.php +++ b/application/controllers/api/frontend/v1/stv/Config.php @@ -117,6 +117,12 @@ class Config extends FHCAPI_Controller 'component' => './Stv/Studentenverwaltung/Details/Pruefung.js' ]; + $result['exemptions'] = [ + 'title' => $this->p->t('lehre', 'anrechnungen'), + 'component' => './Stv/Studentenverwaltung/Details/Anrechnungen.js', + 'config' => $config['exemptions'] + ]; + $result['finalexam'] = [ 'title' => $this->p->t('stv', 'tab_finalexam'), 'component' => './Stv/Studentenverwaltung/Details/Abschlusspruefung.js', diff --git a/application/models/education/Anrechnung_model.php b/application/models/education/Anrechnung_model.php index cbfdb6607..0b81be80c 100644 --- a/application/models/education/Anrechnung_model.php +++ b/application/models/education/Anrechnung_model.php @@ -202,4 +202,66 @@ class Anrechnung_model extends DB_Model return success(); } + + /** + * Get Anrechnungsdata for Table Anrechnungen + * + * @param $prestudent_id + * @return array + */ + public function getAnrechnungsData($prestudent_id) + { + $qry = ' + SELECT + lehre.tbl_anrechnung.anrechnung_id, + lehre.tbl_anrechnung.prestudent_id, + lehre.tbl_anrechnung.lehrveranstaltung_id, + lehre.tbl_lehrveranstaltung.bezeichnung AS bez_lehrveranstaltung, + lehre.tbl_anrechnung_begruendung.bezeichnung AS begruendung, + lehre.tbl_anrechnung_anrechnungstatus.status_kurzbz AS status, + genehmigt_von, + lehre.tbl_anrechnung.insertamum, + lehre.tbl_anrechnung.insertvon, + lehre.tbl_anrechnung.updateamum, + lehre.tbl_anrechnung.updatevon, + lehrveranstaltung_id_kompatibel, + lv_comp.bezeichnung as lehrveranstaltung_bez_kompatibel, + count(nz.notizzuordnung_id) AS notizen_anzahl + FROM + lehre.tbl_anrechnung + JOIN lehre.tbl_lehrveranstaltung USING (lehrveranstaltung_id) + LEFT JOIN lehre.tbl_lehrveranstaltung lv_comp ON (lehre.tbl_anrechnung.lehrveranstaltung_id_kompatibel = lv_comp.lehrveranstaltung_id) + JOIN lehre.tbl_anrechnung_begruendung USING (begruendung_id) + LEFT JOIN lehre.tbl_anrechnung_anrechnungstatus ON (lehre.tbl_anrechnung_anrechnungstatus.anrechnung_id = lehre.tbl_anrechnung.anrechnung_id) + AND lehre.tbl_anrechnung_anrechnungstatus.insertamum = ( + SELECT MAX(insertamum) + FROM lehre.tbl_anrechnung_anrechnungstatus + WHERE anrechnung_id = lehre.tbl_anrechnung.anrechnung_id + ) + LEFT JOIN lehre.tbl_anrechnungstatus USING (status_kurzbz) + LEFT JOIN public.tbl_notizzuordnung nz ON (nz.anrechnung_id = lehre.tbl_anrechnung.anrechnung_id) + WHERE + lehre.tbl_anrechnung.prestudent_id = ? + GROUP BY + nz.anrechnung_id, + lehre.tbl_anrechnung.anrechnung_id, + lehre.tbl_anrechnung.prestudent_id, + lehre.tbl_anrechnung.lehrveranstaltung_id, + bez_lehrveranstaltung, + begruendung, + status, + genehmigt_von, + lehre.tbl_anrechnung.insertamum, + lehre.tbl_anrechnung.insertvon, + lehre.tbl_anrechnung.updateamum, + lehre.tbl_anrechnung.updatevon, + lehrveranstaltung_id_kompatibel, + lehrveranstaltung_bez_kompatibel + ORDER BY + lehre.tbl_anrechnung.updateamum ASC + '; + + return $this->execQuery($qry, array($prestudent_id)); + + } } diff --git a/application/models/education/Lehrveranstaltung_model.php b/application/models/education/Lehrveranstaltung_model.php index 0a48965b5..6176f00b1 100644 --- a/application/models/education/Lehrveranstaltung_model.php +++ b/application/models/education/Lehrveranstaltung_model.php @@ -1071,4 +1071,41 @@ class Lehrveranstaltung_model extends DB_Model return $this->execQuery($qry, $params); } + + /** + * Gets lehrveranstaltungen of Studienplan + * @param $studienplan_id ID des Studienplans + * @param $semester Semester optional + * @return array|null + */ + public function getLvsByStudienplanId($studienplan_id, $semester = null) + { + $params = array($studienplan_id); + + $qry = "SELECT tbl_lehrveranstaltung.*, + tbl_studienplan_lehrveranstaltung.studienplan_lehrveranstaltung_id, + tbl_studienplan_lehrveranstaltung.semester as stpllv_semester, + tbl_studienplan_lehrveranstaltung.pflicht as stpllv_pflicht, + tbl_studienplan_lehrveranstaltung.koordinator as stpllv_koordinator, + tbl_studienplan_lehrveranstaltung.studienplan_lehrveranstaltung_id_parent, + tbl_studienplan_lehrveranstaltung.sort stpllv_sort, + tbl_studienplan_lehrveranstaltung.curriculum, + tbl_studienplan_lehrveranstaltung.export, + tbl_studienplan_lehrveranstaltung.genehmigung + FROM lehre.tbl_lehrveranstaltung + JOIN lehre.tbl_studienplan_lehrveranstaltung + USING(lehrveranstaltung_id) + WHERE tbl_studienplan_lehrveranstaltung.studienplan_id = ? + "; + + if ($semester !== null) + { + $qry.= " AND tbl_studienplan_lehrveranstaltung.semester = ?"; + $params[] = $semester; + } + + $qry .= " ORDER BY stpllv_sort, semester, sort"; + + return $this->execQuery($qry, $params); + } } diff --git a/application/models/ressource/Mitarbeiter_model.php b/application/models/ressource/Mitarbeiter_model.php index 836f5d65a..2b652c65b 100644 --- a/application/models/ressource/Mitarbeiter_model.php +++ b/application/models/ressource/Mitarbeiter_model.php @@ -261,9 +261,9 @@ class Mitarbeiter_model extends DB_Model * @param $lehrveranstaltung_id * @return array with Mitarbeiter and their Lehreinheiten */ - public function getMitarbeiterFromLV($lehrveranstaltung_id){ - //TODO(manu) maybe filter that in pruefungslist.js ? - $qry = "SELECT DISTINCT + public function getMitarbeiterFromLV($lehrveranstaltung_id) + { + $qry = "SELECT DISTINCT lehrveranstaltung_id, uid, vorname, wahlname, vornamen, nachname, titelpre, titelpost, kurzbz, mitarbeiter_uid FROM lehre.tbl_lehreinheitmitarbeiter, campus.vw_mitarbeiter, lehre.tbl_lehreinheit @@ -278,4 +278,33 @@ class Mitarbeiter_model extends DB_Model return $this->execQuery($qry, $parametersArray); } + + /** + * Get Lektoren by studiengang_kz + * + * @param $studiengang_kz + * @return array with Mitarbeiter + */ + public function getLektoren($studiengang_kz) + { + $qry = " + SELECT DISTINCT + campus.vw_mitarbeiter.uid, + campus.vw_mitarbeiter.vorname, + campus.vw_mitarbeiter.nachname, + studiengang_kz, + tbl_studiengang.typ, + tbl_studiengang.kurzbz AS stg_kurzbz + FROM + campus.vw_mitarbeiter + JOIN public.tbl_benutzerfunktion USING (uid) + JOIN public.tbl_studiengang USING(oe_kurzbz) + WHERE studiengang_kz = ? + AND lektor is true + ORDER BY campus.vw_mitarbeiter.nachname"; + + $parametersArray = array($studiengang_kz); + + return $this->execQuery($qry, $parametersArray); + } } diff --git a/public/js/api/stv.js b/public/js/api/stv.js index ae88b0516..0de3ac1fa 100644 --- a/public/js/api/stv.js +++ b/public/js/api/stv.js @@ -10,6 +10,8 @@ import exam from './stv/exam.js'; import abschlusspruefung from './stv/abschlusspruefung.js'; import grades from './stv/grades.js'; import mobility from './stv/mobility.js'; +import exemptions from './stv/exemptions.js'; + export default { verband, @@ -24,6 +26,7 @@ export default { abschlusspruefung, grades, mobility, + exemptions, configStudent() { return this.$fhcApi.get('api/frontend/v1/stv/config/student'); }, diff --git a/public/js/api/stv/exemptions.js b/public/js/api/stv/exemptions.js new file mode 100644 index 000000000..f8b421200 --- /dev/null +++ b/public/js/api/stv/exemptions.js @@ -0,0 +1,29 @@ +export default { + getAnrechnungen(url, config, params) { + return this.$fhcApi.get('api/frontend/v1/stv/anrechnungen/getAnrechnungen/' + params.id); + }, + getLehrveranstaltungen(prestudent_id){ + return this.$fhcApi.get('api/frontend/v1/stv/anrechnungen/getLehrveranstaltungen/' + prestudent_id); + }, + getBegruendungen(){ + return this.$fhcApi.get('api/frontend/v1/stv/anrechnungen/getBegruendungen/'); + }, + getLvsKompatibel(lv_id){ + return this.$fhcApi.get('api/frontend/v1/stv/anrechnungen/getLvsKompatibel/' + lv_id); + }, + getLektoren(studiengang_kz){ + return this.$fhcApi.get('api/frontend/v1/stv/anrechnungen/getLektoren/' + studiengang_kz); + }, + addNewAnrechnung(form, data){ + return this.$fhcApi.post(form, 'api/frontend/v1/stv/anrechnungen/insertAnrechnung/', data); + }, + loadAnrechnung(anrechnung_id){ + return this.$fhcApi.get('api/frontend/v1/stv/anrechnungen/loadAnrechnung/' + anrechnung_id); + }, + editAnrechnung(form, data){ + return this.$fhcApi.post(form, 'api/frontend/v1/stv/anrechnungen/updateAnrechnung/', data); + }, + deleteAnrechnung(anrechnung_id){ + return this.$fhcApi.post('api/frontend/v1/stv/anrechnungen/deleteAnrechnung/' + anrechnung_id); + }, +} \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Anrechnungen.js b/public/js/components/Stv/Studentenverwaltung/Details/Anrechnungen.js new file mode 100644 index 000000000..76d8ae7dd --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Details/Anrechnungen.js @@ -0,0 +1,25 @@ +import AnrechnungenList from './Anrechnungen/Anrechnungen.js'; + +export default { + components: { + AnrechnungenList + }, + provide() { + return { + config: this.config + }; + }, + props: { + modelValue: Object, + config: Object + }, + methods: { + reload() { + this.$refs.anrechnungen.$refs.table.reloadTable(); + } + }, + template: ` +
+ +
` +}; \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Anrechnungen/Anrechnungen.js b/public/js/components/Stv/Studentenverwaltung/Details/Anrechnungen/Anrechnungen.js new file mode 100644 index 000000000..0560f1b5c --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Details/Anrechnungen/Anrechnungen.js @@ -0,0 +1,425 @@ +import {CoreFilterCmpt} from "../../../../filter/Filter.js"; +import BsModal from "../../../../Bootstrap/Modal.js"; +import CoreForm from "../../../../Form/Form.js"; +import FormInput from "../../../../Form/Input.js"; +import CoreNotiz from "../../../../Notiz/Notiz.js"; + +export default { + components: { + CoreFilterCmpt, + BsModal, + CoreForm, + FormInput, + CoreNotiz + }, + inject: { + $reloadList: { + from: '$reloadList', + required: true + }, + config: { + from: 'config', + required: true + }, + }, + props: { + student: Object + }, + data() { + return { + tabulatorOptions: { + ajaxURL: 'dummy', + ajaxRequestFunc: this.$fhcApi.factory.stv.exemptions.getAnrechnungen, + ajaxParams: () => { + return { + id: this.student.prestudent_id + }; + }, + ajaxResponse: (url, params, response) => response.data, + columns: [ + {title: "anrechnung_id", field: "anrechnung_id", visible: false}, + {title: "lehrveranstaltung_id", field: "lehrveranstaltung_id", visible: false}, + {title: "Lehrveranstaltung", field: "bez_lehrveranstaltung"}, + {title: "Begründung", field: "begruendung"}, + {title: "lehrveranstaltung_id_kompatibel", field: "lehrveranstaltung_id_kompatibel", visible: false}, + {title: "lehrveranstaltung_bez_kompatibel", field: "lehrveranstaltung_bez_kompatibel"}, + {title: "status", field: "status"}, + {title: "genehmigt_von", field: "genehmigt_von"}, + {title: "notizen_anzahl", field: "notizen_anzahl", visible: false}, + {title: "Datum", field: "insertamum", + 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", + }); + } + }, + { + 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"; + + if(this.config.editableAnrechnungen){ + let buttonEdit = document.createElement('button'); + buttonEdit.className = 'btn btn-outline-secondary btn-action'; + buttonEdit.innerHTML = ''; + buttonEdit.title = this.$p.t('ui', 'bearbeiten'); + buttonEdit.addEventListener('click', (event) => + this.actionEditAnrechnung(cell.getData().anrechnung_id) + ); + container.append(buttonEdit); + } + + let 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.deleteAnrechnung(cell.getData().anrechnung_id) + ); + container.append(button); + + let countNotizen = cell.getData().notizen_anzahl; + let buttonNotes = document.createElement('button'); + buttonNotes.className = 'btn btn-outline-secondary btn-action'; + if (countNotizen > 0){ + buttonNotes.innerHTML = countNotizen + this.$p.t('anrechnung', 'existingNotes'); + } + else + buttonNotes.innerHTML = '+' + this.$p.t('global', 'notiz'); + + buttonNotes.addEventListener('click', (event) => + this.addNote(cell.getData().anrechnung_id) + ); + container.append(buttonNotes); + + return container; + }, + frozen: true + }, + ], + layout: 'fitDataFill', + height: '500', + index: 'anrechnung_id', + persistenceID: 'stv-details-anrechnungen' + }, + tabulatorEvents: [ + { + event: 'tableBuilt', + handler: async () => { + + await this.$p.loadCategory(['anrechnungen', 'global', 'ui', 'lehre']); + + let cm = this.$refs.table.tabulator.columnManager; + + cm.getColumnByField('anrechnung_id').component.updateDefinition({ + title: this.$p.t('ui', 'anrechnung_id'), + }); + cm.getColumnByField('lehrveranstaltung_id').component.updateDefinition({ + title: this.$p.t('lehre', 'lehrveranstaltung_id'), + }); + cm.getColumnByField('bez_lehrveranstaltung').component.updateDefinition({ + title: this.$p.t('lehre', 'lehrveranstaltung'), + }); + cm.getColumnByField('begruendung').component.updateDefinition({ + title: this.$p.t('global', 'begruendung'), + }); + cm.getColumnByField('lehrveranstaltung_id_kompatibel').component.updateDefinition({ + title: this.$p.t('anrechnung', 'lehrveranstaltung_id_kompatibel'), + }); + cm.getColumnByField('lehrveranstaltung_bez_kompatibel').component.updateDefinition({ + title: this.$p.t('anrechnung', 'lehrveranstaltung_bez_kompatibel'), + }); + cm.getColumnByField('genehmigt_von').component.updateDefinition({ + title: this.$p.t('anrechnung', 'genehmigtVon'), + }); + cm.getColumnByField('notizen_anzahl').component.updateDefinition({ + title: this.$p.t('anrechnung', 'existingNotes'), + }); + cm.getColumnByField('insertamum').component.updateDefinition({ + title: this.$p.t('global', 'datum'), + }); + + } + } + ], + formData: {}, + listBegruendungen: [], + listNewLehrveranstaltungen: [], + listLektoren: [], + listKompatibleLehrveranstaltungen: [], + statusNew: true, + showNotizen: false, + currentAnrechnung_id: null + } + }, + watch: { + student(){ + if (this.$refs.table) { + this.$refs.table.reloadTable(); + } + }, + }, + methods: { + actionNewAnrechnung(){ + this.statusNew = true; + this.$refs.anrechnungsModal.show(); + }, + actionEditAnrechnung(anrechnung_id){ + this.resetForm(); + this.statusNew = false; + this.loadAnrechnung(anrechnung_id); + this.$refs.anrechnungsModal.show(); + }, + addNote(anrechnung_id){ + this.currentAnrechnung_id = anrechnung_id; + this.showNotizen = true; + }, + addNewAnrechnung(){ + const dataToSend = { + prestudent_id: this.student.prestudent_id, + formData: this.formData + }; + return this.$fhcApi.factory.stv.exemptions.addNewAnrechnung(this.$refs.formExemptions, dataToSend) + .then(response => { + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSave')); + this.$refs.anrechnungsModal.hide(); + this.resetForm(); + }) + .catch(this.$fhcAlert.handleSystemError) + .finally(() => { + this.reload(); + }); + }, + editAnrechnung(anrechnung_id){ + const dataToSend = { + anrechnung_id: anrechnung_id, + formData: this.formData + }; + return this.$fhcApi.factory.stv.exemptions.editAnrechnung(this.$refs.formExemptions, dataToSend) + .then(response => { + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSave')); + this.$refs.anrechnungsModal.hide(); + this.resetForm(); + }) + .catch(this.$fhcAlert.handleSystemError) + .finally(() => { + this.reload(); + }); + }, + deleteAnrechnung(anrechnung_id){ + this.$fhcAlert + .confirmDelete() + .then(result => result + ? anrechnung_id + : Promise.reject({handled: true})) + .then(this.$fhcApi.factory.stv.exemptions.deleteAnrechnung) + .then(result => { + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successDelete')); + this.reload(); + }) + .catch(this.$fhcAlert.handleSystemError); + }, + getLvsKompatibel(){ + if(this.formData.lehrveranstaltung_id) { + this.$fhcApi.factory.stv.exemptions.getLvsKompatibel(this.formData.lehrveranstaltung_id) + .then(result => { + this.listKompatibleLehrveranstaltungen = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + } + }, + handleInput(){ + if(this.formData.begruendung == 2) { + this.getLvsKompatibel(); + } + }, + loadAnrechnung(anrechnung_id){ + return this.$fhcApi.factory.stv.exemptions.loadAnrechnung(anrechnung_id) + .then(result => { + this.formData = result.data; + this.getLvsKompatibel(); + }) + .catch(this.$fhcAlert.handleSystemError); + }, + reload() { + this.$refs.table.reloadTable(); + }, + resetForm(){ + this.formData = {}; + this.statusNew = true; + }, + resetLvKompatibel(){ + this.formData.lehrveranstaltung_id_kompatibel = null; + this.handleInput(); + } + }, + created() { + this.$fhcApi.factory.stv.exemptions.getLehrveranstaltungen(this.student.prestudent_id) + .then(result => { + this.listNewLehrveranstaltungen = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + + this.$fhcApi.factory.stv.exemptions.getBegruendungen() + .then(result => { + this.listBegruendungen = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + + this.$fhcApi.factory.stv.exemptions.getLektoren(this.student.studiengang_kz) + .then(result => { + this.listLektoren = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + + }, + template: ` +
+
{{$p.t('lehre', 'anrechnungen')}}
+ +
+
+ + +
+ + + +
+ + + + + + + + +
+ + + +
+ +
+ + + +
+ + +
+ + + +
+ +
+ + + +
+
+ + + +
+ ` +} \ No newline at end of file diff --git a/system/phrasesupdate.php b/system/phrasesupdate.php index acb7a12e6..54297fb6a 100644 --- a/system/phrasesupdate.php +++ b/system/phrasesupdate.php @@ -40432,6 +40432,148 @@ array( ) ), // FHC4 Phrases Mobility End + // FHC4 Phrases Anrechnungen Start + array( + 'app' => 'core', + 'category' => 'anrechnung', + 'phrase' => 'begruendung', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Begründung', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Reason', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'anrechnung', + 'phrase' => 'genehmigtVon', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'genehmigt von', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'approved by', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'anrechnung', + 'phrase' => 'editAnrechnung', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => "Anrechnung bearbeiten", + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => "Edit Exemption", + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'anrechnung', + 'phrase' => 'existingNotes', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => " Notiz(en)", + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => " note(s)", + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'ui', + 'phrase' => 'anrechnung_id', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Anrechnung ID', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Exemption ID', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'anrechnung', + 'phrase' => 'lehrveranstaltung_id_kompatibel', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'LV kompatibel ID', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Course compatible ID', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'anrechnung', + 'phrase' => 'lehrveranstaltung_bez_kompatibel', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'LV kompatibel', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Course compatible', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + // FHC4 Phrases Anrechnungen End ); From 199141893197adb85db4a306e81fc54026e730a3 Mon Sep 17 00:00:00 2001 From: ma0068 Date: Thu, 3 Apr 2025 16:54:56 +0200 Subject: [PATCH 014/107] New tab Dokumente --- .../api/frontend/v1/stv/Config.php | 4 + .../api/frontend/v1/stv/Dokumente.php | 553 ++++++++++++++ application/models/crm/Akte_model.php | 57 +- application/models/crm/Dokument_model.php | 87 +++ .../models/crm/Dokumentprestudent_model.php | 35 + public/js/api/stv.js | 2 + public/js/api/stv/documents.js | 33 + .../Studentenverwaltung/Details/Dokumente.js | 22 + .../Details/Dokumente/Dokumente.js | 51 ++ .../Details/Dokumente/List/Accepted.js | 331 +++++++++ .../Details/Dokumente/List/Unaccepted.js | 344 +++++++++ .../Details/Dokumente/Modal/Edit.js | 137 ++++ .../Details/Dokumente/Modal/Upload.js | 124 ++++ system/phrasesupdate.php | 682 ++++++++++++++++++ 14 files changed, 2461 insertions(+), 1 deletion(-) create mode 100644 application/controllers/api/frontend/v1/stv/Dokumente.php create mode 100644 public/js/api/stv/documents.js create mode 100644 public/js/components/Stv/Studentenverwaltung/Details/Dokumente.js create mode 100644 public/js/components/Stv/Studentenverwaltung/Details/Dokumente/Dokumente.js create mode 100644 public/js/components/Stv/Studentenverwaltung/Details/Dokumente/List/Accepted.js create mode 100644 public/js/components/Stv/Studentenverwaltung/Details/Dokumente/List/Unaccepted.js create mode 100644 public/js/components/Stv/Studentenverwaltung/Details/Dokumente/Modal/Edit.js create mode 100644 public/js/components/Stv/Studentenverwaltung/Details/Dokumente/Modal/Upload.js diff --git a/application/controllers/api/frontend/v1/stv/Config.php b/application/controllers/api/frontend/v1/stv/Config.php index 42de1b02f..ecc17119d 100644 --- a/application/controllers/api/frontend/v1/stv/Config.php +++ b/application/controllers/api/frontend/v1/stv/Config.php @@ -83,6 +83,10 @@ class Config extends FHCAPI_Controller 'title' => 'Status', 'component' => './Stv/Studentenverwaltung/Details/MultiStatus.js' ]; + $result['documents'] = [ + 'title' => $this->p->t('stv', 'tab_dokumente'), + 'component' => './Stv/Studentenverwaltung/Details/Dokumente.js' + ]; $result['banking'] = [ 'title' => $this->p->t('stv', 'tab_banking'), 'component' => './Stv/Studentenverwaltung/Details/Konto.js', diff --git a/application/controllers/api/frontend/v1/stv/Dokumente.php b/application/controllers/api/frontend/v1/stv/Dokumente.php new file mode 100644 index 000000000..2923f7204 --- /dev/null +++ b/application/controllers/api/frontend/v1/stv/Dokumente.php @@ -0,0 +1,553 @@ + ['admin:r', 'assistenz:r'], + 'getDocumentsAccepted' => ['admin:r', 'assistenz:r'], + 'deleteZuordnung' => ['admin:rw', 'assistenz:rw'], + 'createZuordnung' => ['admin:rw', 'assistenz:rw'], + 'loadAkte' => ['admin:rw', 'assistenz:rw'], + 'deleteAkte' => ['admin:rw', 'assistenz:rw'], + 'updateAkte' => ['admin:rw', 'assistenz:rw'], + 'getDoktypen' => ['admin:r', 'assistenz:r'], + 'uploadDokument' => ['admin:rw', 'assistenz:rw'], + 'download' => ['admin:rw', 'assistenz:rw'], + ]); + + // Load Libraries + $this->load->library('VariableLib', ['uid' => getAuthUID()]); + $this->load->library('form_validation'); + + // Load language phrases + $this->loadPhrases([ + 'ui', + 'dokumente' + ]); + + // Load models + $this->load->model('crm/Akte_model', 'AkteModel'); + $this->load->model('crm/Dokument_model', 'DokumentModel'); + $this->load->model('crm/Dokumentprestudent_model', 'DokumentprestudentModel'); + + //TODO(Manu) check additional Berechtigungen + //TODO(Manu) check if using dokument lib instead of dokument model? + } + + public function getDocumentsUnaccepted($prestudent_id, $studiengang_kz) + { + if(!$prestudent_id) + $this->terminateWithError($this->p->t('ui', 'errorMissingValue', ['value' => 'Prestudent ID']), self::ERROR_TYPE_GENERAL); + + if (!is_numeric($prestudent_id)) + $this->terminateWithError($this->p->t('ui', 'error_valueNotNumeric', ['value' => 'Prestudent ID']), self::ERROR_TYPE_GENERAL); + + if(!$studiengang_kz) + $this->terminateWithError($this->p->t('ui', 'errorMissingValue', ['value' => 'Studiengang_kz']), self::ERROR_TYPE_GENERAL); + + $person_id = $this->_getPersonId($prestudent_id); + $result = $this->DokumentModel->getUnacceptedDocuments($prestudent_id, $person_id); + + $dataAkteUnaccepted = $this->getDataOrTerminateWithError($result); + $resultMd = $this->_getMissingDocuments($studiengang_kz, $prestudent_id); + + $data = $this->_mergeDocuments($dataAkteUnaccepted, $resultMd); + + $this->terminateWithSuccess($data); + } + + public function getDocumentsAccepted($prestudent_id, $studiengang_kz) + { + if(!$prestudent_id) + $this->terminateWithError($this->p->t('ui', 'errorMissingValue', ['value' => 'Prestudent ID']), self::ERROR_TYPE_GENERAL); + + if (!is_numeric($prestudent_id)) + $this->terminateWithError($this->p->t('ui', 'error_valueNotNumeric', ['value' => 'Prestudent ID']), self::ERROR_TYPE_GENERAL); + + if(!$studiengang_kz) + $this->terminateWithError($this->p->t('ui', 'errorMissingValue', ['value' => 'Studiengang_kz']), self::ERROR_TYPE_GENERAL); + + $resultPreDoc = $this->_getPrestudentDokumente($prestudent_id); + + $arrayAccepted = []; + $person_id = $this->_getPersonId($prestudent_id); + + $docNames = array_map(function ($item) { + return $item->dokument_kurzbz; + }, $resultPreDoc); + + foreach($docNames as $doc) + { + $result = $this->AkteModel->getAktenFAS($person_id, $doc, $studiengang_kz, $prestudent_id, true); + + if (isError($result)) + { + return $this->terminateWithError($result, self::ERROR_TYPE_GENERAL); + } + if (hasData($result)) + { + $data = getData($result); + array_push($arrayAccepted, current($data)); + } + } + + //Merge with Data of Akte + $newDataMap = []; + //helper, lookupArray + foreach ($arrayAccepted as $item) { + $newDataMap[$item->dokument_kurzbz] = $item; + } + + //add Data of Akte to PrestudentData + foreach ($resultPreDoc as $obj) { + if (isset($newDataMap[$obj->dokument_kurzbz])) { + $obj->akte_id = $newDataMap[$obj->dokument_kurzbz]->akte_id; + $obj->hochgeladenamum = $newDataMap[$obj->dokument_kurzbz]->hochgeladenamum; + $obj->titel_intern = $newDataMap[$obj->dokument_kurzbz]->titel_intern; + $obj->nachgereicht = $newDataMap[$obj->dokument_kurzbz]->nachgereicht; + $obj->akzeptiertamum = $newDataMap[$obj->dokument_kurzbz]->akzeptiertamum; + $obj->dms_id = $newDataMap[$obj->dokument_kurzbz]->dms_id; + $obj->infotext = $newDataMap[$obj->dokument_kurzbz]->infotext; + $obj->anmerkung_intern = $newDataMap[$obj->dokument_kurzbz]->anmerkung_intern; + $obj->nachgereicht_am = $newDataMap[$obj->dokument_kurzbz]->nachgereicht_am; + $obj->vorhanden = $newDataMap[$obj->dokument_kurzbz]->vorhanden; + } + } + $this->terminateWithSuccess($resultPreDoc); + } + + public function deleteZuordnung($prestudent_id, $dokument_kurzbz) + { + if(!$prestudent_id) + $this->terminateWithError($this->p->t('ui', 'errorMissingValue', ['value' => 'Prestudent ID']), self::ERROR_TYPE_GENERAL); + + if (!is_numeric($prestudent_id)) + $this->terminateWithError($this->p->t('ui', 'error_valueNotNumeric', ['value' => 'Prestudent ID']), self::ERROR_TYPE_GENERAL); + + if(!$dokument_kurzbz) + $this->terminateWithError($this->p->t('ui', 'errorMissingValue', ['value' => 'Dokument_kurzbz']), self::ERROR_TYPE_GENERAL); + + $result = $this->DokumentprestudentModel->delete( + [ + 'prestudent_id' => $prestudent_id, + 'dokument_kurzbz' => $dokument_kurzbz + ] + ); + + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + + public function loadAkte($akte_id) + { + if (!$akte_id) + $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id' => 'Akte ID']), self::ERROR_TYPE_GENERAL); + + $this->AkteModel->addSelect('public.tbl_akte.*'); + $this->AkteModel->addSelect("CONCAT(public.tbl_person.vorname, ' ' , public.tbl_person.nachname) AS namePerson"); + $this->AkteModel->addJoin('public.tbl_person', 'person_id'); + $result = $this->AkteModel->loadWhere( + [ + 'akte_id' => $akte_id, + ] + ); + + $data = $this->getDataOrTerminateWithError($result); + $data = current($data); + $this->terminateWithSuccess($data); + } + + public function updateAkte() + { + $this->form_validation->set_rules('akte_id', 'Akte ID', 'required', [ + 'required' => $this->p->t('dokumente', 'err_updateNotAllowed') + ]); + + $this->form_validation->set_rules('dokument_kurzbz', 'Dokumenttyp', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Dokumenttyp']) + ]); + + $this->form_validation->set_rules('nachreichung_am', 'Nachreichung am', 'is_valid_date', [ + 'is_valid_date' => $this->p->t('ui', 'error_notValidDate', ['field' => 'Nachreichung am']) + ]); + + if ($this->form_validation->run() == false) + { + $this->terminateWithValidationErrors($this->form_validation->error_array()); + } + + $uid = getAuthUID(); + + $result = $this->AkteModel->update( + [ + 'akte_id' => $this->input->post('akte_id'), + ], + [ + 'dokument_kurzbz' => $this->input->post('dokument_kurzbz'), + 'anmerkung_intern' => $this->input->post('anmerkung_intern'), + 'titel_intern' => $this->input->post('titel_intern'), + 'nachgereicht_am' => $this->input->post('nachgereicht_am'), + 'updateamum' => date('c'), + 'updatevon' => $uid, + ] + ); + + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess(current($data)); + } + + public function createZuordnung($prestudent_id, $dokument_kurzbz) + { + if (!$prestudent_id) + $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id' => 'Prestudent ID']), self::ERROR_TYPE_GENERAL); + + if(!$dokument_kurzbz) + $this->terminateWithError($this->p->t('ui', 'errorMissingValue', ['value' => 'Dokument_kurzbz']), self::ERROR_TYPE_GENERAL); + + $uid = getAuthUid(); + + $result = $this->DokumentprestudentModel->insert( + [ + 'prestudent_id' => $prestudent_id, + 'dokument_kurzbz' => $dokument_kurzbz, + 'mitarbeiter_uid' => $uid, + 'datum' => date('c'), + 'insertamum' => date('c'), + 'insertvon' => $uid, + ] + ); + + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + + public function deleteAkte($akte_id) + { + if (!$akte_id) + $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id' => 'Akte ID']), self::ERROR_TYPE_GENERAL); + + $result = $this->AkteModel->load($akte_id); + $dataAkte = $this->getDataOrTerminateWithError($result); + + $logdata_akte = var_export($dataAkte, true); + + $dms_id = current($dataAkte)->dms_id; + $nachgereicht = current($dataAkte)->nachgereicht; + $inhalt = current($dataAkte)->inhalt; + $inhaltVorhanden = $inhalt != ''; + $uid = getAuthUid(); + + $this->db->trans_start(); + + if($dms_id) + { + $this->load->model('content/Dms_model', 'DmsModel'); + $result = $this->DmsModel->load($dms_id); + $data = $this->getDataOrTerminateWithError($result); + + $logdata_dms = (array)$data; + $logdata_dms = "Logdata: " . var_export($logdata_dms, true); + + //delete from dmsLib + $this->load->library('DmsLib'); + $person_id = current($dataAkte)->person_id; + $result = $this->dmslib->delete($person_id, $dms_id); + $this->getDataOrTerminateWithError($result); + + //LOGGING Dms ID + $this->load->model('system/Log_model', 'LogModel'); + $result = $this->LogModel->insert([ + 'executetime' => date('c'), + 'mitarbeiter_uid' => $uid, + 'beschreibung' => "Löschen der DMS_ID ". $dms_id, + 'sql' => $logdata_dms + ]); + $this->getDataOrTerminateWithError($result); + + //delete akte + $result = $this->AkteModel->delete( + [ + 'akte_id' => $akte_id + ] + ); + $data = $this->getDataOrTerminateWithError($result); + + //Logging Deletion Akte + $result = $this->LogModel->insert([ + 'executetime' => date('c'), + 'mitarbeiter_uid' => $uid, + 'beschreibung' => "Löschen der Akte ". $akte_id, + 'sql' => "DELETE FROM public.tbl_akte WHERE akte_id=" .$akte_id. " LogData: ". $logdata_akte + ]); + $this->getDataOrTerminateWithError($result); + $this->db->trans_complete(); + $this->terminateWithSuccess($data); + } + elseif (!!$dms_id || ($nachgereicht && !$inhaltVorhanden)) + { + $result = $this->AkteModel->delete( + [ + 'akte_id' => $akte_id + ] + ); + $data = $this->getDataOrTerminateWithError($result); + + $result = $this->LogModel->insert([ + 'executetime' => date('c'), + 'mitarbeiter_uid' => $uid, + 'beschreibung' => "Löschen der Akte ". $akte_id, + 'sql' => "DELETE FROM public.tbl_akte WHERE akte_id=" .$akte_id. " LogData: ". $logdata_akte + ]); + $this->getDataOrTerminateWithError($result); + + $this->db->trans_complete(); + $this->terminateWithSuccess($data); + } + else + $this->terminateWithError($this->p->t('dokumente', 'err_deleteDokHere'), self::ERROR_TYPE_GENERAL); + } + + public function uploadDokument() + { + $this->load->library('DmsLib'); + $prestudent_id = $this->input->post('prestudent_id'); + $anmerkung_intern = $this->input->post('anmerkung_intern'); + $titel_intern = $this->input->post('titel_intern'); + $dokument_kurzbz = $this->input->post('dokument_kurzbz'); + + $this->form_validation->set_rules('prestudent_id', 'Prestudent_id', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Prestudent ID']) + ]); + + $this->form_validation->set_rules('dokument_kurzbz', 'Dokumenttyp', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Dokumenttyp']) + ]); + + //validation if attachment was added + $this->form_validation->set_rules('anhang', 'Attachment', 'callback_file_check'); + + if ($this->form_validation->run() == false) + { + $this->terminateWithValidationErrors($this->form_validation->error_array()); + } + + $this->db->trans_start(); + $uid = getAuthUID(); + + $dms = array( + 'kategorie_kurzbz' => 'Akte', + 'version' => 0, + 'name' => $_FILES['anhang']['name'], + 'mimetype' => $_FILES['anhang']['type'], + 'insertamum' => date('c'), + 'insertvon' => $uid + ); + + $result = $this->dmslib->upload($dms, 'anhang', array("jpg", "png", "pdf")); + + if (isError($result)) + { + return $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + } + $dms_id = $result->retval['dms_id']; + + $person_id = $this->_getPersonId($prestudent_id); + + $result = $this->DokumentModel->load($dokument_kurzbz); + $data = $this->getDataOrTerminateWithError($result); + + $bezeichnung = current($data)->bezeichnung; + + //save entry in akte + if($dms_id) + { + $result = $this->AkteModel->insert([ + 'person_id' => $person_id, + 'dms_id' => $dms_id, + 'dokument_kurzbz' => $dokument_kurzbz, + 'mimetype' => $_FILES['anhang']['type'], + 'insertamum' => date('c'), + 'erstelltam' => date('c'), + 'insertvon' => $uid, + 'anmerkung_intern' => $anmerkung_intern, + 'titel_intern' => $titel_intern, + 'bezeichnung' => $bezeichnung, + 'titel' => $_FILES['anhang']['name'] + ]); + + $data = $this->getDataOrTerminateWithError($result); + $this->db->trans_complete(); + $this->terminateWithSuccess($data); + } + $this->db->trans_complete(); + $this->terminateWithSuccess($data); + } + + public function getDoktypen() + { + $this->DokumentModel->addSelect('dokument_kurzbz'); + $this->DokumentModel->addSelect('bezeichnung'); + $this->DokumentModel->addOrder('dokument_kurzbz', 'ASC'); + $result = $this->DokumentModel->load(); + + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + + public function download() + { + //TODO(Manu) check filetype, Decoding + $akte_id = $this->input->get('akte_id'); + + if(!$akte_id) + $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id' => 'Akte ID']), self::ERROR_TYPE_GENERAL); + + if (!is_numeric($akte_id)) + $this->terminateWithError($this->p->t('ui', 'error_valueNotNumeric', ['value' => 'Akte ID']), self::ERROR_TYPE_GENERAL); + + + $result = $this->AkteModel->load($akte_id); + + if (!hasData($result)) $this->terminateWithError('Akte not found'); + + $data = getData($result)[0]; + + header('Content-Description: File Transfer'); + header('Content-Type: '. $data->mimetype); + header('Content-Disposition: attachment; filename="'.$data->titel.'"'); + header('Expires: 0'); + header('Cache-Control: must-revalidate'); + header('Pragma: public'); + if (isset($data->inhalt) && !empty($data->inhalt)) { + $decodedContent = base64_decode($data->inhalt, true); + + if ($decodedContent === false) { + die('Error: Base64-Dekodierung failed.'); + } + echo $decodedContent; + } + die(); + } + + private function _getMissingDocuments($studiengang_kz, $prestudent_id) + { + $result = $this->DokumentModel->getMissingDocuments($studiengang_kz, $prestudent_id); + + $data = $this->getDataOrTerminateWithError($result); + + return $data; + } + + private function _getUnacceptedDocuments($prestudent_id) + { + $person_id = $this->_getPersonId($prestudent_id); + $result = $this->DokumentModel->getUnacceptedDocuments($prestudent_id, $person_id); + + $data = $this->getDataOrTerminateWithError($result); + + return $data; + } + + /** + * helper function for merging objects + * sorts object after merging according to dokument_kurzbz + * @param $original object of documents of akte + * @param object $toMerge documents to merge (of dokumentprestudent, dokumentstudiengang) + * @return Array mergedObject + */ + private function _mergeDocuments($original, $toMerge) + { + $existingKurzbez = []; + foreach ($original as $doc) { + $existingKurzbez[$doc->dokument_kurzbz] = true; + } + + foreach ($toMerge as $doc) { + if (!isset($existingKurzbez[$doc->dokument_kurzbz])) { + $original[] = $doc; + $existingKurzbez[$doc->dokument_kurzbz] = true; + } + else + { + foreach($original as $docOriginal) + { + if ($docOriginal->dokument_kurzbz == $doc->dokument_kurzbz) + { + $docOriginal->pflicht = $doc->pflicht; + $docOriginal->onlinebewerbung = $doc->onlinebewerbung; + } + } + } + } + + usort($original, function ($a, $b) { + return strcmp($a->dokument_kurzbz, $b->dokument_kurzbz); + }); + + return $original; + } + + private function _getDocumentsOfAkte($person_id) + { + $result = $this->AkteModel->getAktenFAS($person_id); + + $data = $this->getDataOrTerminateWithError($result); + + return $data; + } + + private function _getPrestudentDokumente($prestudent_id) + { + $result = $this->DokumentprestudentModel->getPrestudentDokumente($prestudent_id); + + $data = $this->getDataOrTerminateWithError($result); + + return $data; + } + + private function _getPersonId($prestudent_id) + { + $this->load->model('crm/Prestudent_model', 'PrestudentModel'); + $result = $this->PrestudentModel->loadWhere( + ['prestudent_id' => $prestudent_id] + ); + + $data = $this->getDataOrTerminateWithError($result); + $person = current($data); + + return $person->person_id; + } + + public function file_check($str) + { + if (isset($_FILES['anhang']) && $_FILES['anhang']['size'] > 0) + { + $allowed_mime_types = ['image/jpeg', 'image/png', 'application/pdf']; + $mime = mime_content_type($_FILES['anhang']['tmp_name']); + + if (in_array($mime, $allowed_mime_types)) + { + return true; + } else + { + $this->form_validation->set_message('file_check', $this->p->t('dokumente', 'error_fileType')); + return false; + } + } + else + { + $this->form_validation->set_message('file_check', $this->p->t('dokumente', 'error_fileMissing')); + return false; + } + } +} diff --git a/application/models/crm/Akte_model.php b/application/models/crm/Akte_model.php index 57b6e0665..4b36e8267 100644 --- a/application/models/crm/Akte_model.php +++ b/application/models/crm/Akte_model.php @@ -92,7 +92,7 @@ class Akte_model extends DB_Model a.anmerkung, a.nachgereicht, a.nachgereicht_am, - CASE WHEN MAX(dp.dokument_kurzbz) IS NOT NULL THEN TRUE ELSE FALSE END AS accepted + CASE WHEN MAX(dp.dokument_kurzbz) IS NOT NULL THEN TRUE ELSE FALSE END AS accepted, FROM public.tbl_akte a INNER JOIN public.tbl_prestudent p USING(person_id) LEFT JOIN public.tbl_dokumentprestudent dp USING(prestudent_id, dokument_kurzbz) @@ -111,6 +111,61 @@ class Akte_model extends DB_Model return $this->execQuery($query, $parametersArray); } + /** + * getAktenAccepted FAS + */ + public function getAktenFAS($person_id, $dokument_kurzbz = null, $stg_kz = null, $prestudent_id = null, $returnInhalt = false) + { + $query = 'SELECT + a.akte_id, + a.bezeichnung, + a.dokument_kurzbz, + a.titel_intern, + a.anmerkung_intern, + a.insertamum as hochgeladenamum, + a.updatevon, a.insertvon, a.uid, + a.dms_id, a.anmerkung as infotext, + a.nachgereicht, + CASE + WHEN inhalt IS NOT NULL OR a.dms_id IS NOT NULL + THEN true + ELSE false + END AS vorhanden, + a.nachgereicht_am, + ausstellungsnation, formal_geprueft_amum, archiv, + signiert, stud_selfservice, akzeptiertamum, inhalt + FROM public.tbl_akte a + WHERE a.person_id = ?'; + + $parametersArray = array($person_id); + + if (!isEmptyString($dokument_kurzbz)) + { + $query .= " AND dokument_kurzbz = ? + AND dokument_kurzbz NOT IN ('Zeugnis','DiplSupp','Bescheid')"; + array_push($parametersArray, $dokument_kurzbz); + } + + if($stg_kz != null && $prestudent_id != null) + { + $query.= " AND dokument_kurzbz not in ( + SELECT dokument_kurzbz + FROM public.tbl_dokument + JOIN public.tbl_dokumentstudiengang USING(dokument_kurzbz) + WHERE studiengang_kz= ? + AND dokument_kurzbz NOT IN( + SELECT dokument_kurzbz FROM public.tbl_dokumentprestudent + JOIN public.tbl_dokument USING(dokument_kurzbz) + WHERE prestudent_id=?))"; + array_push($parametersArray, $stg_kz); + array_push($parametersArray, $prestudent_id); + } + + $query .= ' ORDER BY erstelltam'; + + return $this->execQuery($query, $parametersArray); + } + /** * getAktenAcceptedDms */ diff --git a/application/models/crm/Dokument_model.php b/application/models/crm/Dokument_model.php index 7ef2be716..8008202c1 100644 --- a/application/models/crm/Dokument_model.php +++ b/application/models/crm/Dokument_model.php @@ -11,4 +11,91 @@ class Dokument_model extends DB_Model $this->dbTable = 'public.tbl_dokument'; $this->pk = 'dokument_kurzbz'; } + + /** + * Loads all missing Documents of a Studiengang + * a Prestudent has not submitted + * @param integer studiengang_kz + * @param integer prestudent_id + * @param boolean archivdokumente + * Default: true. + * If false, documents that are archivable (tbl_vorlage.archivierbar e.g. certificate, notice, ...) not retrieved + * @return Array of Documents || error + */ + public function getMissingDocuments($studiengang_kz, $prestudent_id = null, $archivdokumente = false, $person_id = null) + { + $parametersArray = array($studiengang_kz); + + $qry = "SELECT + tbl_dokument.* , + tbl_dokumentstudiengang.* + FROM public.tbl_dokument + JOIN public.tbl_dokumentstudiengang USING(dokument_kurzbz) + LEFT JOIN public.tbl_vorlage ON (tbl_dokument.dokument_kurzbz = tbl_vorlage.vorlage_kurzbz) + WHERE studiengang_kz = ? "; + + if($prestudent_id) + { + array_push($parametersArray, $prestudent_id); + $qry.=" AND tbl_dokument.dokument_kurzbz NOT IN ( + SELECT dokument_kurzbz FROM public.tbl_dokumentprestudent WHERE prestudent_id= ?)"; + } + + if(!$archivdokumente) + { + $qry.=" AND (tbl_vorlage.archivierbar = FALSE OR tbl_vorlage.archivierbar IS NULL)"; + } + + $qry.=" ORDER BY tbl_dokument.dokument_kurzbz;"; + + return $this->execQuery($qry, $parametersArray); + } + + public function getUnacceptedDocuments($prestudent_id, $person_id) + { + $parametersArray = array($person_id, $prestudent_id); + + $qry = " SELECT + a.akte_id, + a.bezeichnung, + a.dokument_kurzbz, + a.titel_intern, + a.anmerkung_intern, + a.insertamum as hochgeladenamum, + a.updatevon, + a.insertvon, + a.uid, + a.dms_id, + a.anmerkung as infotext, + a.nachgereicht, + CASE + WHEN inhalt IS NOT NULL + OR a.dms_id IS NOT NULL THEN true + ELSE false + END AS vorhanden, + a.nachgereicht_am, + ausstellungsnation, + formal_geprueft_amum, + archiv, + signiert, + stud_selfservice, + akzeptiertamum, + inhalt + FROM + public.tbl_akte a + WHERE + a.person_id = ? + AND a.dokument_kurzbz NOT IN ( + SELECT + dokument_kurzbz + FROM + public.tbl_dokumentprestudent + WHERE + prestudent_id = ? + ) + AND a.dokument_kurzbz NOT IN ('Zeugnis','DiplSupp','Bescheid') + ORDER BY a.dokument_kurzbz;"; + + return $this->execQuery($qry, $parametersArray); + } } diff --git a/application/models/crm/Dokumentprestudent_model.php b/application/models/crm/Dokumentprestudent_model.php index 0a6669359..2415ee483 100644 --- a/application/models/crm/Dokumentprestudent_model.php +++ b/application/models/crm/Dokumentprestudent_model.php @@ -69,4 +69,39 @@ class Dokumentprestudent_model extends DB_Model return $result; } + + /** + * Loads all Documents of Prestudent, already submitted + * @param integer prestudent_id + * @param boolean archivdokumente Default true. if false, archivable Documents (tbl_vorlage.archivierbar zB Zeugnis, Bescheid, ...) not retrieved + * @return Array of Documents || error + */ + public function getPrestudentDokumente($prestudent_id, $archivdokumente = true) + { + $parametersArray = array($prestudent_id); + + $qry = "SELECT + d.bezeichnung, + d.dokument_kurzbz, + dp.datum as Docdatum, + dp.mitarbeiter_uid as DocMitarbeiter_uid, + dp.insertamum as Docinsertamum, + dp.prestudent_id, + CONCAT(p.vorname, ' ', p.nachname) as insertvonma + FROM + public.tbl_dokumentprestudent dp + JOIN public.tbl_dokument d USING(dokument_kurzbz) + LEFT JOIN public.tbl_vorlage v ON (d.dokument_kurzbz = v.vorlage_kurzbz) + LEFT JOIN public.tbl_benutzer bn ON (bn.uid = dp.mitarbeiter_uid) + LEFT JOIN public.tbl_person p ON (p.person_id = bn.person_id) + WHERE + prestudent_id = ?"; + + if(!$archivdokumente) + { + $qry.=" AND (v.archivierbar = FALSE OR v.archivierbar IS NULL)"; + } + + return $this->execQuery($qry, $parametersArray); + } } diff --git a/public/js/api/stv.js b/public/js/api/stv.js index ae88b0516..b1d83df88 100644 --- a/public/js/api/stv.js +++ b/public/js/api/stv.js @@ -10,6 +10,7 @@ import exam from './stv/exam.js'; import abschlusspruefung from './stv/abschlusspruefung.js'; import grades from './stv/grades.js'; import mobility from './stv/mobility.js'; +import documents from './stv/documents.js'; export default { verband, @@ -24,6 +25,7 @@ export default { abschlusspruefung, grades, mobility, + documents, configStudent() { return this.$fhcApi.get('api/frontend/v1/stv/config/student'); }, diff --git a/public/js/api/stv/documents.js b/public/js/api/stv/documents.js new file mode 100644 index 000000000..9934520fc --- /dev/null +++ b/public/js/api/stv/documents.js @@ -0,0 +1,33 @@ +export default { + getDocumentsUnaccepted(url, config, params) { + return this.$fhcApi.get('api/frontend/v1/stv/dokumente/getDocumentsUnaccepted/' + params.id + '/' + params.studiengang_kz); + }, + getDocumentsAccepted(url, config, params) { + return this.$fhcApi.get('api/frontend/v1/stv/dokumente/getDocumentsAccepted/' + params.id + '/' + params.studiengang_kz); + }, + deleteZuordnung(params){ + return this.$fhcApi.post('api/frontend/v1/stv/dokumente/deleteZuordnung/' + params.prestudent_id + '/' + params.dokument_kurzbz); + }, + createZuordnung(params){ + return this.$fhcApi.post('api/frontend/v1/stv/dokumente/createZuordnung/' + + params.prestudent_id + '/' + + params.dokument_kurzbz); + }, + loadAkte(akte_id){ + return this.$fhcApi.get('api/frontend/v1/stv/dokumente/loadAkte/' + akte_id); + }, + getDoktypen(){ + return this.$fhcApi.get('api/frontend/v1/stv/dokumente/getDoktypen/'); + }, + updateFile(akte_id, data){ + return this.$fhcApi.post('api/frontend/v1/stv/dokumente/updateAkte/' + akte_id, + data); + }, + deleteFile(akte_id){ + return this.$fhcApi.post('api/frontend/v1/stv/dokumente/deleteAkte/' + akte_id); + }, + uploadFile(prestudent_id, data){ + return this.$fhcApi.post('api/frontend/v1/stv/dokumente/uploadDokument/' + prestudent_id, + data); + }, +} \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Dokumente.js b/public/js/components/Stv/Studentenverwaltung/Details/Dokumente.js new file mode 100644 index 000000000..39dbeb914 --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Details/Dokumente.js @@ -0,0 +1,22 @@ +import ViewDocuments from "./Dokumente/Dokumente.js"; + +export default { + components: { + ViewDocuments + }, +/* provide() { + return { + config: this.config + }; + },*/ + props: { + modelValue: Object, + }, + data(){ + return {} + }, + template: ` +
+ +
` +}; \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Dokumente/Dokumente.js b/public/js/components/Stv/Studentenverwaltung/Details/Dokumente/Dokumente.js new file mode 100644 index 000000000..be69ae70d --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Details/Dokumente/Dokumente.js @@ -0,0 +1,51 @@ +import DocumentsUnaccepted from './List/Unaccepted.js'; +import DocumentsAccepted from './List/Accepted.js'; + +export default { + components: { + DocumentsUnaccepted, + DocumentsAccepted + }, + props: { + student: Object + }, + data(){ + return { + listMissingDocuments: [] + } + }, + methods: { + reloadUnaccepted(){ + this.$refs.tableUnaccepted.reload(); + }, + reloadAccepted(){ + this.$refs.tableAccepted.reload(); + }, + }, + template: ` +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ ` +} diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Dokumente/List/Accepted.js b/public/js/components/Stv/Studentenverwaltung/Details/Dokumente/List/Accepted.js new file mode 100644 index 000000000..505ee9840 --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Details/Dokumente/List/Accepted.js @@ -0,0 +1,331 @@ +import {CoreFilterCmpt} from "../../../../../filter/Filter.js"; +import ModalEdit from "../Modal/Edit.js"; +import ModalUpload from "../Modal/Upload.js"; + +export default { + components: { + CoreFilterCmpt, + ModalEdit, + ModalUpload + }, + props: { + prestudent_id: Number, + studiengang_kz: Number + }, + data(){ + return { + tabulatorOptions: { + ajaxURL: 'dummy', + ajaxRequestFunc: this.$fhcApi.factory.stv.documents.getDocumentsAccepted, + ajaxParams: () => { + return { + id: this.prestudent_id, + studiengang_kz: this.studiengang_kz + }; + }, + ajaxResponse: (url, params, response) => { + return response.data; + }, + columns: [ + {title: "Dokument", field: "bezeichnung"}, + {title: "Akzeptiertdatum", field: "docdatum", + 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: "Akzeptiertvon", field: "insertvonma"}, + { + title: "UploadDatum", field: "hochgeladenamum", + 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: "Kurzbz", field: "dokument_kurzbz", visible: false}, + {title: "Prestudent ID", field: "prestudent_id", visible: false}, + {title: "nachgereicht", field: "nachgereicht", visible: false, + formatter:"tickCross", + hozAlign:"center", + formatterParams: { + tickElement: '', + crossElement: '' + }}, + {title: "infotext", field: "infotext"}, + {title: "akte_id", field: "akte_id"}, + {title: "dms_id", field: "dms_id", visible: false}, + {title: "titel", field: "titel_intern"}, + {title: "vorhanden", field: "vorhanden", + formatter:"tickCross", + hozAlign:"center", + formatterParams: { + tickElement: '', + crossElement: '' + }}, + {title: "Anmerkung_intern", field: "anmerkung_intern", visible: false}, + {title: "Nachreichung am", field: "nachgereicht_am", + 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: 'Aktionen', field: 'actions', + minWidth: 50, + maxWidth: 100, + formatter: (cell, formatterParams, onRendered) => { + + let container = document.createElement('div'); + container.className = "d-flex gap-2"; + + if(cell.getData().vorhanden){ + let button = document.createElement('button'); + button.className = 'btn btn-outline-secondary btn-action'; + button.innerHTML = ''; + button.title = this.$p.t('ui', 'downloadDok'); + button.addEventListener('click', (event) => + this.actionDownloadFile(cell.getData().akte_id) + ); + container.append(button); + + button = document.createElement('button'); + button.className = 'btn btn-outline-secondary btn-action'; + button.innerHTML = ''; + button.title = this.$p.t('ui', 'editDokument'); + button.addEventListener('click', (event) => + this.actionEditDocument(cell.getData().akte_id) + ); + container.append(button); + + button = document.createElement('button'); + button.className = 'btn btn-outline-secondary btn-action'; + button.innerHTML = ''; + button.title = this.$p.t('ui', 'deleteDokument'); + button.addEventListener('click', () => + this.actionDeleteFile(cell.getData().akte_id) + ); + container.append(button); + } + else + { + let button = document.createElement('button'); + button.className = 'btn btn-outline-secondary btn-action'; + button.innerHTML = ''; + button.title = this.$p.t('ui', 'uploadDokument'); + button.addEventListener('click', () => + this.actionUploadFile(cell.getData().dokument_kurzbz) + ); + container.append(button); + } + + + return container; + }, + frozen: true + }, + ], + layout: 'fitColumns', + layoutColumnsOnNewData: false, + height: 300, + selectable: true, + selectableRangeMode: 'click', + persistenceID: 'core-details-documents-accepted', + listDocuments: [], + }, + tabulatorEvents: [ + { + event: 'tableBuilt', + handler: async () => { + await this.$p.loadCategory(['global', 'dokumente', 'ui', 'mobility', 'ampeln']); + + let cm = this.$refs.table.tabulator.columnManager; + + cm.getColumnByField('bezeichnung').component.updateDefinition({ + title: this.$p.t('global', 'dokument') + }); + cm.getColumnByField('docdatum').component.updateDefinition({ + title: this.$p.t('dokumente', 'datumAkzeptiert') + }); + cm.getColumnByField('dokument_kurzbz').component.updateDefinition({ + title: this.$p.t('mobility', 'kurzbz') + }); + cm.getColumnByField('insertvonma').component.updateDefinition({ + title: this.$p.t('global', 'uploaddatum') + }); + cm.getColumnByField('hochgeladenamum').component.updateDefinition({ + title: this.$p.t('global', 'uploaddatum') + }); + cm.getColumnByField('nachgereicht').component.updateDefinition({ + title: this.$p.t('dokumente', 'nachgereicht') + }); + cm.getColumnByField('vorhanden').component.updateDefinition({ + title: this.$p.t('dokumente', 'vorhanden') + }); + cm.getColumnByField('dms_id').component.updateDefinition({ + title: this.$p.t('global', 'dms_id') + }); + cm.getColumnByField('titel_intern').component.updateDefinition({ + title: this.$p.t('global', 'titel') + }); + cm.getColumnByField('anmerkung_intern').component.updateDefinition({ + title: this.$p.t('global', 'anmerkung') + }); + cm.getColumnByField('akte_id').component.updateDefinition({ + title: this.$p.t('global', 'akte_id') + }); + cm.getColumnByField('nachgereicht_am').component.updateDefinition({ + title: this.$p.t('global', 'dokument') + }); + } + } + ] + } + }, + computed: { + tabulatorEvents() { + const events = [ + { + event: "rowDblClick", + handler: (e, row) => { + this.actionDownloadFile(row.getData().akte_id); + } + } + ]; + return events; + } + }, + methods: { + actionDownloadFile(akte_id){ + window.open( + FHC_JS_DATA_STORAGE_OBJECT.app_root + + FHC_JS_DATA_STORAGE_OBJECT.ci_router + '/api/frontend/v1/stv/dokumente/download?akte_id=' + encodeURIComponent(akte_id), + '_blank' + ); + }, + actionUploadFile(dokument_kurzbz){ + this.$refs.modalUpload.open(this.prestudent_id, dokument_kurzbz); + }, + actionEditDocument(akte_id){ + this.$refs.modalEdit.open(akte_id); + }, + actionDeleteFile(akte_id){ + this.$fhcAlert + .confirmDelete() + .then(result => result + ? akte_id + : Promise.reject({handled: true})) + .then(this.deleteFile) + .catch(this.$fhcAlert.handleSystemError); + }, + deleteFile(akte_id){ + return this.$fhcApi.factory.stv.documents.deleteFile(akte_id) + .then(response => { + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successDelete')); + }) + .catch(this.$fhcAlert.handleSystemError) + .finally(()=> { + this.reload(); + }); + }, + deleteZuordnung(selected) { + Promise.allSettled( + selected.map(e => + this.$fhcApi.factory.stv.documents.deleteZuordnung({ + prestudent_id: this.prestudent_id, + dokument_kurzbz: e.dokument_kurzbz + }).then(() => ({ + success: true, + dokument_bz: e.bezeichnung + })) + .catch(() => ({ + success: false, + dokument_bz: e.bezeichnung + })) + ) + ).then(results => { + const failed = results.filter(res => !res.value.success); + const suceeded = results.filter(res => res.value.success); + if (failed.length > 0) { + failed.forEach(res => { + this.$fhcAlert.alertError(this.$p.t('dokumente', 'errorUnaccepted', + {'dokument_kurzbz': res.value.dokument_bz} + )); + }); + let countSuceeded = suceeded.length; + if(countSuceeded > 0) + this.$fhcAlert.alertSuccess(this.$p.t('dokumente', 'successCountUnaccepted', + {'count': countSuceeded})); + + } else { + this.$fhcAlert.alertSuccess(this.$p.t('dokumente', 'successUnaccepted')); + } + this.reloadAll(); + }); + }, + + reload(){ + this.$refs.table.reloadTable(); + }, + reloadAll(){ + this.reload(); + this.$emit('reloadUnaccepted'); + } + }, + template: ` +
+
{{$p.t('dokumente', 'accepted')}}
+ + + + + + + + + + +
+ ` +} \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Dokumente/List/Unaccepted.js b/public/js/components/Stv/Studentenverwaltung/Details/Dokumente/List/Unaccepted.js new file mode 100644 index 000000000..08a9d8f92 --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Details/Dokumente/List/Unaccepted.js @@ -0,0 +1,344 @@ +import {CoreFilterCmpt} from "../../../../../filter/Filter.js"; +import ModalEdit from "../Modal/Edit.js"; +import ModalUpload from "../Modal/Upload.js"; + +export default { + components: { + CoreFilterCmpt, + ModalEdit, + ModalUpload + }, + props: { + prestudent_id: Number, + studiengang_kz: Number + }, + data(){ + return { + tabulatorOptions: { + ajaxURL: 'dummy', + ajaxRequestFunc: this.$fhcApi.factory.stv.documents.getDocumentsUnaccepted, + ajaxParams: () => { + return { + id: this.prestudent_id, + studiengang_kz: this.studiengang_kz + }; + }, + ajaxResponse: (url, params, response) => response.data, + columns: [ + {title: "Dokument", field: "bezeichnung"}, + {title: "Kurzbz", field: "dokument_kurzbz", visible: false}, + { + title: "UploadDatum", field: "hochgeladenamum", + 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: "nachgereicht", field: "nachgereicht", visible: false, + formatter:"tickCross", + hozAlign:"center", + formatterParams: { + tickElement: '', + crossElement: '' + }}, + {title: "vorhanden", + field: "vorhanden", + formatter: function(cell, formatterParams, onRendered) { + let value = cell.getValue(); + let rowData = cell.getRow().getData(); // Zugriff auf gesamte Zeile + let dueDate = rowData["nachgereicht_am"]; + const date = new Date(dueDate); + let dateFormatted = date.toLocaleString("de-DE", { + day: "2-digit", + month: "2-digit", + year: "numeric", + hour12: false + }); + + let tickCrossIcon = value + ? '' + : ''; + + // if nachgereicht_am show datum + let pill = dueDate + ? `${dateFormatted}` + : ''; + + return `${tickCrossIcon} ${pill}`; + }, + hozAlign: "center" + }, + {title: "infotext", field: "infotext"}, + {title: "akte_id", field: "akte_id"}, + {title: "titel_intern", field: "titel_intern"}, + {title: "Anmerkung_intern", field: "anmerkung_intern", visible: false}, + {title: "Online", field: "onlinebewerbung", + formatter:"tickCross", + hozAlign:"center", + formatterParams: { + tickElement: '', + crossElement: '' + }}, + {title: "Pflicht", field: "pflicht", + formatter:"tickCross", + hozAlign:"center", + formatterParams: { + tickElement: '', + crossElement: '' + }}, + {title: "Nachreichung am", field: "nachgereicht_am", + 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: 'Aktionen', field: 'actions', + minWidth: 50, + maxWidth: 100, + formatter: (cell, formatterParams, onRendered) => { + + let container = document.createElement('div'); + container.className = "d-flex gap-2"; + + if(cell.getData().akte_id){ + let button = document.createElement('button'); + button.className = 'btn btn-outline-secondary btn-action'; + button.innerHTML = ''; + button.title = this.$p.t('ui', 'downloadDok'); + button.addEventListener('click', (event) => + this.actionDownloadFile(cell.getData().akte_id) + ); + container.append(button); + + button = document.createElement('button'); + button.className = 'btn btn-outline-secondary btn-action'; + button.innerHTML = ''; + button.title = this.$p.t('ui', 'editDokument'); + button.addEventListener('click', (event) => + this.actionEditFile(cell.getData().akte_id) + ); + container.append(button); + + button = document.createElement('button'); + button.className = 'btn btn-outline-secondary btn-action'; + button.innerHTML = ''; + button.title = this.$p.t('ui', 'deleteDokument'); + button.addEventListener('click', () => + this.actionDeleteFile(cell.getData().akte_id) + ); + container.append(button); + } + else + { + let button = document.createElement('button'); + button.className = 'btn btn-outline-secondary btn-action'; + button.innerHTML = ''; + button.title = this.$p.t('ui', 'uploadDokument'); + button.addEventListener('click', () => + this.actionUploadFile(cell.getData().dokument_kurzbz) + ); + container.append(button); + } + + return container; + }, + frozen: true + }, + ], + layout: 'fitColumns', + layoutColumnsOnNewData: false, + height: 300, + selectable: true, + selectableRangeMode: 'click', + persistenceID: 'core-details-documents-unaccepted', + listDocuments: [], + prestudentDocumentData: [], + }, + tabulatorEvents: [ + { + event: 'tableBuilt', + handler: async () => { + await this.$p.loadCategory(['global', 'dokumente', 'ui', 'mobility', 'ampeln']); + + let cm = this.$refs.table.tabulator.columnManager; + + cm.getColumnByField('bezeichnung').component.updateDefinition({ + title: this.$p.t('global', 'dokument') + }); + cm.getColumnByField('dokument_kurzbz').component.updateDefinition({ + title: this.$p.t('mobility', 'kurzbz') + }); + cm.getColumnByField('hochgeladenamum').component.updateDefinition({ + title: this.$p.t('global', 'uploaddatum') + }); + cm.getColumnByField('nachgereicht').component.updateDefinition({ + title: this.$p.t('dokumente', 'nachgereicht') + }); + cm.getColumnByField('vorhanden').component.updateDefinition({ + title: this.$p.t('dokumente', 'vorhanden') + }); + cm.getColumnByField('anmerkung_intern').component.updateDefinition({ + title: this.$p.t('global', 'anmerkung') + }); + cm.getColumnByField('akte_id').component.updateDefinition({ + title: this.$p.t('global', 'akte_id') + }); + cm.getColumnByField('pflicht').component.updateDefinition({ + title: this.$p.t('ampeln', 'mandatory') + }); + cm.getColumnByField('nachgereicht_am').component.updateDefinition({ + title: this.$p.t('global', 'dokument') + }); + } + } + ] + } + }, + computed: { + tabulatorEvents() { + const events = [ + { + event: "rowDblClick", + handler: (e, row) => { + this.actionDownloadFile(row.getData().akte_id); + } + } + ]; + + return events; + } + }, + methods: { + actionDownloadFile(akte_id){ + window.open( + FHC_JS_DATA_STORAGE_OBJECT.app_root + + FHC_JS_DATA_STORAGE_OBJECT.ci_router + '/api/frontend/v1/stv/dokumente/download?akte_id=' + encodeURIComponent(akte_id), + '_blank' + ); + }, + actionUploadFile(dokument_kurzbz){ + this.$refs.modalUpload.open(this.prestudent_id, dokument_kurzbz); + }, + actionDeleteFile(akte_id){ + this.$fhcAlert + .confirmDelete() + .then(result => result + ? akte_id + : Promise.reject({handled: true})) + .then(this.deleteFile) + .catch(this.$fhcAlert.handleSystemError); + }, + actionEditFile(akte_id){ + this.$refs.modalEdit.open(akte_id); + }, + acceptDocuments(selected){ + Promise + .allSettled( + selected.map(e => + this.$fhcApi.factory.stv.documents.createZuordnung({ + prestudent_id: this.prestudent_id, + dokument_kurzbz: e.dokument_kurzbz, + }).then(() => ({ + success: true, + dokument_bz: e.bezeichnung + })) + .catch(() => ({ + success: false, + dokument_bz: e.bezeichnung + })) + ) + ) + .then(results => { + const failed = results.filter(res => !res.value.success); + const suceeded = results.filter(res => res.value.success); + if (failed.length > 0) { + failed.forEach(res => { + this.$fhcAlert.alertError(this.$p.t('dokumente', 'errorAccepted', + {'dokument_kurzbz': res.value.dokument_bz} + )); + }); + let countSuceeded = suceeded.length; + if(countSuceeded > 0) + this.$fhcAlert.alertSuccess(this.$p.t('dokumente', 'successCountAccepted', + {'count': countSuceeded})); + + } else { + this.$fhcAlert.alertSuccess(this.$p.t('dokumente', 'successAccepted')); + } + this.reloadAll(); + }); + }, + deleteFile(akte_id){ + return this.$fhcApi.factory.stv.documents.deleteFile(akte_id) + .then(response => { + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successDelete')); + }) + .catch(this.$fhcAlert.handleSystemError) + .finally(()=> { + this.reload(); + }); + }, + reload(){ + this.$refs.table.reloadTable(); + }, + reloadAll() { + this.reload(); + this.$emit('reloadAccepted'); + } + }, + template: ` +
+
{{$p.t('dokumente', 'unaccepted')}}
+ + + + + + + + + + +
+ ` +} \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Dokumente/Modal/Edit.js b/public/js/components/Stv/Studentenverwaltung/Details/Dokumente/Modal/Edit.js new file mode 100644 index 000000000..7b8f1b984 --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Details/Dokumente/Modal/Edit.js @@ -0,0 +1,137 @@ +import BsModal from "../../../../../Bootstrap/Modal.js"; +import FormForm from "../../../../../Form/Form.js"; +import FormInput from "../../../../../Form/Input.js"; + +export default { + components: { + BsModal, + FormForm, + FormInput + }, + data(){ + return { + formData: [], + listDokTypen: [] + } + }, + methods: { + updateFile(akte_id){ + console.log("in update" + akte_id); + + this.$fhcApi.factory.stv.documents.updateFile(akte_id, this.formData). + then(response => { + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSave')); + this.$refs.modalEditDocument.hide(); + this.$emit('reload'); + }) + .catch(this.$fhcAlert.handleSystemError); + }, + open(akte_id){ + this.loadFormData(akte_id); + this.$refs.modalEditDocument.show(); + }, + loadFormData(akte_id){ + return this.$fhcApi.factory.stv.documents.loadAkte(akte_id) + .then(result => { + this.formData = result.data; + return result; + }) + .catch(this.$fhcAlert.handleSystemError); + } + }, + created(){ + this.$fhcApi.factory.stv.documents.getDoktypen() + .then(result => { + this.listDokTypen = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + }, + template: ` + + + + +
+
+ + + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ + + +
+ `, +} diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Dokumente/Modal/Upload.js b/public/js/components/Stv/Studentenverwaltung/Details/Dokumente/Modal/Upload.js new file mode 100644 index 000000000..84fa4a57b --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Details/Dokumente/Modal/Upload.js @@ -0,0 +1,124 @@ +import BsModal from "../../../../../Bootstrap/Modal.js"; +import FormForm from "../../../../../Form/Form.js"; +import FormInput from "../../../../../Form/Input.js"; +import FormUploadDms from "../../../../../Form/Upload/Dms.js"; + +export default { + components: { + BsModal, + FormForm, + FormInput, + FormUploadDms + }, + data(){ + return{ + formData: { + dokument_kurzbz: null, + anhang: [], + anmerkung_intern: null + }, + listDokTypen: [] + } + }, + methods:{ + open(prestudent_id, dokument_kurzbz){ + console.log("ps: " + prestudent_id + 'dok: ' + dokument_kurzbz); + this.formData.dokument_kurzbz = dokument_kurzbz; + this.formData.prestudent_id = prestudent_id; + this.$refs.modalUploadFile.show(); + }, + uploadFile(){ + console.log(this.formData.anhang[0]); + + return this.$fhcApi.factory.stv.documents.uploadFile(this.formData.prestudent_id, this.formData) + .then(result => { + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successUpload')); + this.resetModal(); + this.$refs.modalUploadFile.hide(); + this.$emit('reload'); + }) + .catch(this.$fhcAlert.handleSystemError); + }, + resetModal(){ + this.formData.dokument_kurzbz = null; + this.formData.anhang = []; + this.formData.anmerkung_intern = null; + this.formData.titel_intern = null; + } + }, + created(){ + this.$fhcApi.factory.stv.documents.getDoktypen() + .then(result => { + this.listDokTypen = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + }, + template: ` + + + + + +
+
+ + +
+ +
+ + + + +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ + + +
+ `, +} \ No newline at end of file diff --git a/system/phrasesupdate.php b/system/phrasesupdate.php index a5b83c31d..5a63713b2 100644 --- a/system/phrasesupdate.php +++ b/system/phrasesupdate.php @@ -40534,6 +40534,688 @@ array( ) ), // feature-55614 end + // FHC4 Studierendenverwaltung Dokumente START + array( + 'app' => 'core', + 'category' => 'stv', + 'phrase' => 'tab_documents', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Dokumente', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Documents', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'ui', + 'phrase' => 'uploadDokument', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Dokument hochladen', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Upload document', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'ui', + 'phrase' => 'deleteDokument', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Dokument löschen', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Delete document', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'ui', + 'phrase' => 'editDokument', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Dokument bearbeiten', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Edit document', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'dokumente', + 'phrase' => 'title', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Titel', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'title', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'dokumente', + 'phrase' => 'dokTyp', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Dokumententyp', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Document type', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'dokumente', + 'phrase' => 'nachreichungAm', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Nachreichung am', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Submission on', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'dokumente', + 'phrase' => 'dokDetails', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Dokumentendetails', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Document Details', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'dokumente', + 'phrase' => 'anmerkung_person', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Anmerkung der Person', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Notes of the Person', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'ui', + 'phrase' => 'successUpload', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Dokument erfolgreich hochgeladen', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Dokumentupload successful', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'dokumente', + 'phrase' => 'dokumentAccept', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Akzeptieren', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Accept', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'dokumente', + 'phrase' => 'dokumentUnaccept', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Entakzeptieren', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Unaccept', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'dokumente', + 'phrase' => 'accepted', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Akzeptiert', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Accepted', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'dokumente', + 'phrase' => 'unaccepted', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Nicht Akzeptiert', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Not Accepted', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'dokumente', + 'phrase' => 'err_deleteDokHere', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Dieses Dokument darf hier nicht gelöscht werden', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'This document may not be deleted here', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'dokumente', + 'phrase' => 'err_updateNotAllowed', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Es können nur Eintraege geändert werden zu denen Dokumente hochgeladen wurden', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Only entries to which documents have been uploaded can be changed', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'ui', + 'phrase' => 'downloadDok', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Dokument herunterladen', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Download Document', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'dokumente', + 'phrase' => 'successAccepted', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Akzeptieren erfolgreich', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Successfully set to accepted', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'dokumente', + 'phrase' => 'successUnaccepted', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Entakzeptieren erfolgreich', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Successfully set to unaccepted', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'dokumente', + 'phrase' => 'successCountUnaccepted', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Entakzeptieren von {count} Dokument(en) erfolgreich', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => '{count} Document(s) successfully set to unaccepted', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'dokumente', + 'phrase' => 'successCountAccepted', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Akzeptieren von {count} Dokument(en) erfolgreich', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => '{count} Document(s) successfully set to accepted', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'dokumente', + 'phrase' => 'errorUnaccepted', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Fehler beim Entakzeptieren von Dokument {dokument_kurzbz}', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Error unaccepting document {dokument_kurzbz}', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'dokumente', + 'phrase' => 'errorAccepted', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Fehler beim Akzeptieren von Dokument {dokument_kurzbz}', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Error Accepting document {dokument_kurzbz}', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'ui', + 'phrase' => 'errorMissingValue', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => '{value} fehlt', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => '{value} missing', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'ui', + 'phrase' => 'error_valueNotNumeric', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => '{value} darf nur Ziffern enthalten.', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => '{value} must contain only numbers.', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'dokumente', + 'phrase' => 'nachgereicht', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Nachgereicht', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Submitted later', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'dokumente', + 'phrase' => 'vorhanden', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Vorhanden', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Available', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'global', + 'phrase' => 'akte_id', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Akte ID', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'File ID', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'global', + 'phrase' => 'nachgereicht_am', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Nachgereicht am', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Submitted on', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'dokumente', + 'phrase' => 'datumAkzeptiert', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Akzeptiertdatum', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Accepted on', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'dokumente', + 'phrase' => 'akzeptiertVon', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Akzeptiert von', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Accepted by', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'global', + 'phrase' => 'dms_id', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Dms ID', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Dms ID', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'dokumente', + 'phrase' => 'error_fileMissing', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Bitte eine Datei anhängen', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Please attach a file', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'dokumente', + 'phrase' => 'error_fileType', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Nur Dateitypen JPEG, PNG oder PDF sind erlaubt', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Only JPEG, PNG, or PDF files are allowed.', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + // FHC4 Studierendenverwaltung Dokumente END ); From 4d1fc5e48c9bddaffcb5290c1c319639f9d05c42 Mon Sep 17 00:00:00 2001 From: ma0068 Date: Fri, 4 Apr 2025 09:41:11 +0200 Subject: [PATCH 015/107] added name attribute to components --- .../components/Stv/Studentenverwaltung/Details/Dokumente.js | 6 +----- .../Studentenverwaltung/Details/Dokumente/List/Accepted.js | 1 + .../Details/Dokumente/List/Unaccepted.js | 1 + .../Stv/Studentenverwaltung/Details/Dokumente/Modal/Edit.js | 1 + .../Studentenverwaltung/Details/Dokumente/Modal/Upload.js | 1 + 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Dokumente.js b/public/js/components/Stv/Studentenverwaltung/Details/Dokumente.js index 39dbeb914..01ca2d373 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Dokumente.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Dokumente.js @@ -1,14 +1,10 @@ import ViewDocuments from "./Dokumente/Dokumente.js"; export default { + name:"TabDocuments", components: { ViewDocuments }, -/* provide() { - return { - config: this.config - }; - },*/ props: { modelValue: Object, }, diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Dokumente/List/Accepted.js b/public/js/components/Stv/Studentenverwaltung/Details/Dokumente/List/Accepted.js index 505ee9840..e22ad4cdb 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Dokumente/List/Accepted.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Dokumente/List/Accepted.js @@ -4,6 +4,7 @@ import ModalUpload from "../Modal/Upload.js"; export default { components: { + name: "AcceptedDocuments", CoreFilterCmpt, ModalEdit, ModalUpload diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Dokumente/List/Unaccepted.js b/public/js/components/Stv/Studentenverwaltung/Details/Dokumente/List/Unaccepted.js index 08a9d8f92..5b2a2d080 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Dokumente/List/Unaccepted.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Dokumente/List/Unaccepted.js @@ -3,6 +3,7 @@ import ModalEdit from "../Modal/Edit.js"; import ModalUpload from "../Modal/Upload.js"; export default { + name: "UnacceptedDocuments", components: { CoreFilterCmpt, ModalEdit, diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Dokumente/Modal/Edit.js b/public/js/components/Stv/Studentenverwaltung/Details/Dokumente/Modal/Edit.js index 7b8f1b984..95a12a669 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Dokumente/Modal/Edit.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Dokumente/Modal/Edit.js @@ -3,6 +3,7 @@ import FormForm from "../../../../../Form/Form.js"; import FormInput from "../../../../../Form/Input.js"; export default { + name: "modalEditDocuments", components: { BsModal, FormForm, diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Dokumente/Modal/Upload.js b/public/js/components/Stv/Studentenverwaltung/Details/Dokumente/Modal/Upload.js index 84fa4a57b..dec8da503 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Dokumente/Modal/Upload.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Dokumente/Modal/Upload.js @@ -4,6 +4,7 @@ import FormInput from "../../../../../Form/Input.js"; import FormUploadDms from "../../../../../Form/Upload/Dms.js"; export default { + name: "modalUploadDocuments", components: { BsModal, FormForm, From b2fef71b4779aaadbe662b606935a84a019700e3 Mon Sep 17 00:00:00 2001 From: ma0068 Date: Fri, 4 Apr 2025 09:53:54 +0200 Subject: [PATCH 016/107] added name attribute to components --- .../Messages/Details/Depr_NewMessage.js | 480 ------------------ .../Messages/Details/NewMessage/Modal.js | 1 + .../Messages/Details/NewMessage/NewDiv.js | 1 + .../Messages/Details/TableMessages.js | 3 +- public/js/components/Messages/Messages.js | 1 + .../Studentenverwaltung/Details/Messages.js | 1 + 6 files changed, 5 insertions(+), 482 deletions(-) delete mode 100644 public/js/components/Messages/Details/Depr_NewMessage.js diff --git a/public/js/components/Messages/Details/Depr_NewMessage.js b/public/js/components/Messages/Details/Depr_NewMessage.js deleted file mode 100644 index 33ff74d9c..000000000 --- a/public/js/components/Messages/Details/Depr_NewMessage.js +++ /dev/null @@ -1,480 +0,0 @@ -import FormForm from '../../Form/Form.js'; -import FormInput from '../../Form/Input.js'; -import ListBox from "../../../../../index.ci.php/public/js/components/primevue/listbox/listbox.esm.min.js"; -import DropdownComponent from '../../VorlagenDropdown/VorlagenDropdown.js'; -import MessageModal from "../Details/NewMessage/Modal.js"; - -export default { - components: { - FormForm, - FormInput, - ListBox, - DropdownComponent, - MessageModal, - }, - props: { - endpoint: { - type: String, - required: true - }, - typeId: String, - id: { - type: [Number, String], - required: true - }, - openMode: String, - }, - data(){ - return { - formData: { - recipient: this.id, - subject: null, - body: null, - vorlage_kurzbz: null, - selectedValue: '', - }, - statusNew: true, - vorlagen: [], - defaultRecipient: null, - editor: null, - isVisible: false, - fieldsUser: [], - fieldsPerson: [], - fieldsPrestudent: [], - selectedFieldPrestudent: null, - selectedFieldUser: null, - selectedFieldPerson: null, - itemsPrestudent: [], - itemsPerson: [], - itemsUser: [], - previewText: null, - previewBody: "" - } - }, - methods: { - initTinyMCE() { - const vm = this; - tinymce.init({ - target: this.$refs.editor.$refs.input, //Important: not selector: to enable multiple import of component - //height: 800, - //plugins: ['lists'], - toolbar: 'styleselect | bold italic underline | alignleft aligncenter alignright alignjustify', - style_formats: [ - {title: 'Blocks', block: 'div'}, - {title: 'Paragraph', block: 'p'}, - {title: 'Heading 1', block: 'h1'}, - {title: 'Heading 2', block: 'h2'}, - {title: 'Heading 3', block: 'h3'}, - {title: 'Heading 4', block: 'h4'}, - {title: 'Heading 5', block: 'h5'}, - {title: 'Heading 6', block: 'h6'}, - ], - autoresize_bottom_margin: 16, - - setup: (editor) => { - vm.editor = editor; - - editor.on('input', () => { - const newContent = editor.getContent(); - vm.formData.body = newContent; - }); - }, - }); - }, - updateText(value) { - this.formData.body = value; - }, - sendMessage() { - //TODO(Manu) check default recipient(s) - const data = new FormData(); - const params = { - id: this.id, - type_id: this.typeId - }; - const merged = { - ...this.formData, - ...params - }; - data.append('data', JSON.stringify(merged)); - - return this.$fhcApi.factory.messages.person.sendMessage( - this.$refs.formMessage, - this.id, - data) - .then(response => { - this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSent')); - //this.hideModal('messageModal'); - this.hideTemplate(); - this.resetForm(); - }).catch(this.$fhcAlert.handleSystemError) - .finally(() => { - //this.resetForm(); - //closeModal - //closewindwo - this.$emit('reloadTable'); - } - ); - }, - getVorlagentext(vorlage_kurzbz){ - //console.log(typeof vorlage_kurzbz); - return this.$fhcApi.factory.messages.person.getVorlagentext(vorlage_kurzbz) - .then(response => { - //this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSent')); - //this.hideModal('messageModal'); - //this.resetForm(); - //TODO(Manu) CHECK - this.formData.body = response.data; - }).catch(this.$fhcAlert.handleSystemError) - .finally(() => { - //this.resetForm(); - //closeModal - //closewindwo - }); - }, - getPreviewText(){ - const data = new FormData(); - - data.append('data', JSON.stringify(this.formData.body)); - return this.$fhcApi.factory.messages.person.getPreviewText({ - id: this.id, - type_id: this.typeId}, data) - .then(response => { - this.previewText = response.data; - }).catch(this.$fhcAlert.handleSystemError) - .finally(() => { - //this.resetForm(); - //closeModal - //closewindwo - }); - }, - insertVariable(selectedItem){ - if (this.editor) { - this.editor.insertContent(selectedItem.value + " "); - //TODO(Manu) check: nicht mal mit Punkt adden gehts ohne eintrag nach vars -/* this.editor.focus(); - this.editor.setDirty(true);*/ - - //this.editor.fire('change'); //forces - - //this.editor.undoManager.add(); - - //this.editor.insertContent(selectedItem.value + "\u00A0"); - //this.editor.insertContent(`${selectedItem.value} `); - //this.editor.selection.setCursorLocation(this.editor.getBody(), 1); - - } else { - console.error("Editor instance is not available."); - } - }, - replyMessage(message_id){ - console.log("auf message " + message_id + " antworten"); - }, - resetForm(){ - this.formData = { - vorlage_kurzbz: null, - body: null, - subject: null, - }; - if (this.editor) { - this.editor.setContent(""); - } - this.$refs.dropdownComp.setValue(null); - - }, -/* toggleDivNewMessage(){ - this.isVisible = !this.isVisible; - },*/ - handleSelectedVorlage(vorlage_kurzbz) { - if (typeof vorlage_kurzbz === "string") { - this.getVorlagentext(vorlage_kurzbz); - this.formData.subject = vorlage_kurzbz; - } - }, - hideTemplate(){ - if (this.openMode == "showDiv") - this.isVisible = false; - }, - showTemplate(id, typeId){ - if (this.openMode == "showDiv") - this.isVisible = true; - //just for testing: - this.isVisible = true; - }, - showPreview(){ - this.getPreviewText().then(() => { - this.previewBody = this.previewText; - }); - }, - }, - watch: { - 'formData.body': { - handler(newVal) { - const tinymcsVal = this.editor.getContent(); - - if (newVal && tinymcsVal != newVal) { - //Inhalt des Editors aktualisieren - this.editor.setContent(newVal); - } - } - }, - 'formData.vorlage_kurzbz': { - handler(newVal){ - // console.log("Vorlage: " + newVal); - - if (newVal && newVal != null) { - this.formData.subject = newVal; - return this.getVorlagentext(newVal); - } - } - } - }, - created(){ - if(this.typeId == 'person_id'){ - this.$fhcApi.factory.messages.person.getMessageVarsPerson() - .then(result => { - this.fieldsPerson = result.data; - this.itemsPerson = Object.entries(this.fieldsPerson).map(([key, value]) => ({ - label: value, - value: '{' + value + '}' - })); - }) - .catch(this.$fhcAlert.handleSystemError); - } - if(this.typeId == 'uid') { - this.$fhcApi.factory.messages.person.getMsgVarsPrestudent(this.id) - .then(result => { - this.fieldsPrestudent = result.data; - const prestudent = this.fieldsPrestudent[0]; - //Just for testing with inserting values -/* this.itemsPrestudent = Object.entries(prestudent).map(([key, value]) => ({ - label: key, - value: value - }));*/ - this.itemsPrestudent = Object.entries(prestudent).map(([key, value]) => ({ - label: key.toLowerCase(), - value: '{' + key.toLowerCase() + '}' - })); - }) - .catch(this.$fhcAlert.handleSystemError); - } - - this.$fhcApi.factory.messages.person.getMsgVarsLoggedInUser() - .then(result => { - this.fieldsUser = result.data; - const user = this.fieldsUser; - this.itemsUser = Object.entries(user).map(([key, value]) => ({ - label: value, - value: '{' + value + '}' - })); - }) - .catch(this.$fhcAlert.handleSystemError); - - this.$fhcApi.factory.messages.person.getNameOfDefaultRecipient({ - id: this.id, - type_id: this.typeId}) - .then(result => { - this.defaultRecipient = result.data; - }) - .catch(this.$fhcAlert.handleSystemError); - }, - async mounted() { - this.initTinyMCE(); - }, - beforeDestroy() { - this.editor.destroy(); - }, - template: ` -
- - - - - -
-
- -

New Message

- - -
-
- - - -
- - - -
- -
- - -
- - -
- - -
- -
- - -
- -
-
- -
-
- Felder Prestudent -
- - - - - -
- - -

{{selectedFieldPrestudent}}

- -
- -
- Felder Person -
- - - - - -
- -

{{selectedFieldPerson}}

-
- -
- Meine Felder -
- - - - - -
- -
- -
- - - - - -
- -
- -
- -
- -

Vorschau:

-
- - -
- - -
- -
-
- -
-
- -
-
-
-
-
- -
- -
- -
- -
- -
- ` - -} \ No newline at end of file diff --git a/public/js/components/Messages/Details/NewMessage/Modal.js b/public/js/components/Messages/Details/NewMessage/Modal.js index 03345e9d4..33698f1c8 100644 --- a/public/js/components/Messages/Details/NewMessage/Modal.js +++ b/public/js/components/Messages/Details/NewMessage/Modal.js @@ -5,6 +5,7 @@ import ListBox from "../../../../../../index.ci.php/public/js/components/primevu import DropdownComponent from "../../../VorlagenDropdown/VorlagenDropdown.js"; export default { + name: "ModalNewMessages", components: { BsModal, FormForm, diff --git a/public/js/components/Messages/Details/NewMessage/NewDiv.js b/public/js/components/Messages/Details/NewMessage/NewDiv.js index 4331dd734..d8db657df 100644 --- a/public/js/components/Messages/Details/NewMessage/NewDiv.js +++ b/public/js/components/Messages/Details/NewMessage/NewDiv.js @@ -4,6 +4,7 @@ import ListBox from "../../../../../../index.ci.php/public/js/components/primevu import DropdownComponent from '../../../VorlagenDropdown/VorlagenDropdown.js'; export default { + name: "ComponentNewMessages", components: { FormForm, FormInput, diff --git a/public/js/components/Messages/Details/TableMessages.js b/public/js/components/Messages/Details/TableMessages.js index 89a118fd1..9047d6726 100644 --- a/public/js/components/Messages/Details/TableMessages.js +++ b/public/js/components/Messages/Details/TableMessages.js @@ -1,12 +1,11 @@ import {CoreFilterCmpt} from "../../filter/Filter.js"; import FormForm from '../../Form/Form.js'; -//import NewMessage from "../Details/NewMessage.js"; export default { + name: "TableMessages", components: { CoreFilterCmpt, FormForm, - // NewMessage, }, inject: { cisRoot: { diff --git a/public/js/components/Messages/Messages.js b/public/js/components/Messages/Messages.js index 5aa7eb7de..337883be3 100644 --- a/public/js/components/Messages/Messages.js +++ b/public/js/components/Messages/Messages.js @@ -2,6 +2,7 @@ import TableMessages from "./Details/TableMessages.js"; import FormOnly from "./Details/NewMessage/NewDiv.js"; import MessageModal from "../Messages/Details/NewMessage/Modal.js"; export default { + name: "MessagesComponent", components: { TableMessages, FormOnly, diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Messages.js b/public/js/components/Stv/Studentenverwaltung/Details/Messages.js index 4c1d9bd6b..0c46a6333 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Messages.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Messages.js @@ -1,6 +1,7 @@ import CoreMessages from "../../../Messages/Messages.js"; export default { + name: "TabMessages", components: { CoreMessages }, From 01b3d4580e0015e8130be52d38df2d1f37c98811 Mon Sep 17 00:00:00 2001 From: ma0068 Date: Fri, 4 Apr 2025 11:03:00 +0200 Subject: [PATCH 017/107] set name attribute to components --- public/js/components/Stv/Studentenverwaltung/Details/Gruppen.js | 1 + .../Stv/Studentenverwaltung/Details/Gruppen/Gruppen.js | 1 + 2 files changed, 2 insertions(+) diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Gruppen.js b/public/js/components/Stv/Studentenverwaltung/Details/Gruppen.js index 1c7c47d6b..96fc6c772 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Gruppen.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Gruppen.js @@ -1,6 +1,7 @@ import GruppenList from './Gruppen/Gruppen.js'; export default { + name: 'TabGroups', components: { GruppenList }, diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Gruppen/Gruppen.js b/public/js/components/Stv/Studentenverwaltung/Details/Gruppen/Gruppen.js index 63a9b24e1..6434f9fa8 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Gruppen/Gruppen.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Gruppen/Gruppen.js @@ -1,6 +1,7 @@ import {CoreFilterCmpt} from "../../../../filter/Filter.js"; export default { + name: 'TblGroups', components: { CoreFilterCmpt, }, From 958577902decc826190b75c2ef8c41e957ea1032 Mon Sep 17 00:00:00 2001 From: ma0068 Date: Fri, 4 Apr 2025 11:07:54 +0200 Subject: [PATCH 018/107] set name attribute to components --- .../components/Stv/Studentenverwaltung/Details/Anrechnungen.js | 1 + .../Stv/Studentenverwaltung/Details/Anrechnungen/Anrechnungen.js | 1 + 2 files changed, 2 insertions(+) diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Anrechnungen.js b/public/js/components/Stv/Studentenverwaltung/Details/Anrechnungen.js index 76d8ae7dd..c98f0598f 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Anrechnungen.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Anrechnungen.js @@ -1,6 +1,7 @@ import AnrechnungenList from './Anrechnungen/Anrechnungen.js'; export default { + name: "TabExemptions", components: { AnrechnungenList }, diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Anrechnungen/Anrechnungen.js b/public/js/components/Stv/Studentenverwaltung/Details/Anrechnungen/Anrechnungen.js index 0560f1b5c..9515f2be6 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Anrechnungen/Anrechnungen.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Anrechnungen/Anrechnungen.js @@ -5,6 +5,7 @@ import FormInput from "../../../../Form/Input.js"; import CoreNotiz from "../../../../Notiz/Notiz.js"; export default { + name: "ExemptionComponent", components: { CoreFilterCmpt, BsModal, From d75e26f8aea359d073d46d54d7801c681721af10 Mon Sep 17 00:00:00 2001 From: ma0068 Date: Mon, 7 Apr 2025 14:46:36 +0200 Subject: [PATCH 019/107] add basis framework for lv dates --- .../api/frontend/v1/stv/Config.php | 5 ++ .../api/frontend/v1/stv/Lvtermine.php | 67 +++++++++++++++++++ .../models/ressource/Stundenplan_model.php | 2 +- public/js/api/stv.js | 2 + public/js/api/stv/courselist.js | 6 ++ .../Details/Lehrveranstaltungstermine.js | 18 +++++ .../ListLehrveranstaltungstermine.js | 47 +++++++++++++ system/phrasesupdate.php | 24 ++++++- 8 files changed, 169 insertions(+), 2 deletions(-) create mode 100644 application/controllers/api/frontend/v1/stv/Lvtermine.php create mode 100644 public/js/api/stv/courselist.js create mode 100644 public/js/components/Stv/Studentenverwaltung/Details/Lehrveranstaltungstermine.js create mode 100644 public/js/components/Stv/Studentenverwaltung/Details/Lehrveranstaltungstermine/ListLehrveranstaltungstermine.js diff --git a/application/controllers/api/frontend/v1/stv/Config.php b/application/controllers/api/frontend/v1/stv/Config.php index 42de1b02f..2232189b5 100644 --- a/application/controllers/api/frontend/v1/stv/Config.php +++ b/application/controllers/api/frontend/v1/stv/Config.php @@ -128,6 +128,11 @@ class Config extends FHCAPI_Controller 'component' => './Stv/Studentenverwaltung/Details/Mobility.js' ]; + $result['coursedates'] = [ + 'title' => $this->p->t('stv', 'tab_courseDates'), + 'component' => './Stv/Studentenverwaltung/Details/Lehrveranstaltungstermine.js' + ]; + Events::trigger('stv_conf_student', function & () use (&$result) { return $result; }); diff --git a/application/controllers/api/frontend/v1/stv/Lvtermine.php b/application/controllers/api/frontend/v1/stv/Lvtermine.php new file mode 100644 index 000000000..17a529f85 --- /dev/null +++ b/application/controllers/api/frontend/v1/stv/Lvtermine.php @@ -0,0 +1,67 @@ + ['admin:r', 'assistenz:r'], + 'getLvsStudent' => ['admin:r', 'assistenz:r'], + ]); + + // Load Libraries + $this->load->library('VariableLib', ['uid' => getAuthUID()]); + $this->load->library('form_validation'); + + // Load language phrases + $this->loadPhrases([ + 'ui', + ]); + + // Load models + $this->load->model('ressource/Stundenplan_model', 'StundenplanModel'); + } + + public function getStundenplan($uid) + { + //get stundenplan for uid + $result = $this->StundenplanModel->loadForUid($uid); + + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + + } + + public function getLvsStudent($uid) + { + $authUID = getAuthUID(); + //$this->terminateWithError('uid' . $uid, self::ERROR_TYPE_GENERAL); + //$this->terminateWithError('uid' . $authUID, self::ERROR_TYPE_GENERAL); + + $this->load->model('system/Variable_model', 'VariableModel'); + $result = $this->VariableModel->getVariables($authUID); + $data = $this->getDataOrTerminateWithError($result); + + //$this->terminateWithSuccess(current($data)); // WS2025 + + $this->load->model('ressource/Stunde_model', 'StundeModel'); + $this->StundeModel->addOrder('stunde', 'ASC'); + $result = $this->StundeModel->load(); + $dataStunden = $this->getDataOrTerminateWithError($result); + $this->terminateWithSuccess($dataStunden); + // $this->terminateWithSuccess(current($data)); + + //TODO(manu) check existing apis for liste stundenplan und lvs + // version for student + // version for lehrfaecherverteilung + + + + + } +} \ No newline at end of file diff --git a/application/models/ressource/Stundenplan_model.php b/application/models/ressource/Stundenplan_model.php index 012ce0a57..40498a766 100644 --- a/application/models/ressource/Stundenplan_model.php +++ b/application/models/ressource/Stundenplan_model.php @@ -421,7 +421,7 @@ class Stundenplan_model extends DB_Model */ public function loadForUid($uid) { - $this->addSelect(['sp.*','le.studiensemester_kurzbz']); + $this->addSelect(['5sp.*','le.studiensemester_kurzbz']); $this->db->join('public.tbl_benutzergruppe bg', 'sp.gruppe_kurzbz=bg.gruppe_kurzbz AND bg.uid=?', 'LEFT', false); $this->addJoin('public.tbl_studiensemester ss1', 'bg.studiensemester_kurzbz=ss1.studiensemester_kurzbz AND ss1.start<=sp.datum AND ss1.ende>=sp.datum', 'LEFT'); $this->db->join('public.tbl_studentlehrverband slv', "sp.studiengang_kz=slv.studiengang_kz AND slv.student_uid=? AND (slv.semester=sp.semester OR sp.semester IS NULL) AND (slv.verband=sp.verband OR sp.verband IS NULL OR sp.verband='' OR sp.verband='0') AND (slv.gruppe=sp.gruppe OR sp.gruppe IS NULL OR sp.gruppe='' OR sp.gruppe='0') AND sp.gruppe_kurzbz IS NULL", 'LEFT', false); diff --git a/public/js/api/stv.js b/public/js/api/stv.js index ae88b0516..e9f0fd2f5 100644 --- a/public/js/api/stv.js +++ b/public/js/api/stv.js @@ -10,6 +10,7 @@ import exam from './stv/exam.js'; import abschlusspruefung from './stv/abschlusspruefung.js'; import grades from './stv/grades.js'; import mobility from './stv/mobility.js'; +import courselist from './stv/courselist.js'; export default { verband, @@ -24,6 +25,7 @@ export default { abschlusspruefung, grades, mobility, + courselist, configStudent() { return this.$fhcApi.get('api/frontend/v1/stv/config/student'); }, diff --git a/public/js/api/stv/courselist.js b/public/js/api/stv/courselist.js new file mode 100644 index 000000000..b6035c098 --- /dev/null +++ b/public/js/api/stv/courselist.js @@ -0,0 +1,6 @@ +export default { + getCourselist(url, config, params) { + console.log("her"); + return this.$fhcApi.get('api/frontend/v1/stv/Lvtermine/getLvsStudent/' + params.id); + }, +} \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Lehrveranstaltungstermine.js b/public/js/components/Stv/Studentenverwaltung/Details/Lehrveranstaltungstermine.js new file mode 100644 index 000000000..6845613ab --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Details/Lehrveranstaltungstermine.js @@ -0,0 +1,18 @@ +import TableLvList from "./Lehrveranstaltungstermine/ListLehrveranstaltungstermine.js"; + +export default { + name: "TabCourseList", + components: { + TableLvList + }, + props: { + modelValue: Object, + }, + data(){ + return {} + }, + template: ` +
+ +
` +}; \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Lehrveranstaltungstermine/ListLehrveranstaltungstermine.js b/public/js/components/Stv/Studentenverwaltung/Details/Lehrveranstaltungstermine/ListLehrveranstaltungstermine.js new file mode 100644 index 000000000..8a6c0d2b0 --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Details/Lehrveranstaltungstermine/ListLehrveranstaltungstermine.js @@ -0,0 +1,47 @@ +import {CoreFilterCmpt} from "../../../../filter/Filter.js"; + +export default { + name: "TblCourseList", + components: { + CoreFilterCmpt + }, + props: { + student: Object + }, + data(){ + return { + tabulatorOptions: { + ajaxURL: 'dummy', + ajaxRequestFunc: this.$fhcApi.factory.stv.courselist.getCourselist, + ajaxParams: () => { + return { + id: this.student.uid + }; + }, + ajaxResponse: (url, params, response) => response.data, + columns: [ + {title: "Prestudent_id", field: "prestudent_id"}, + ] + }, + tabulatorEvents: [], + } + + }, + methods: {}, + template: ` +
+

Termine

+ {{student}} + + + +
+ ` +} \ No newline at end of file diff --git a/system/phrasesupdate.php b/system/phrasesupdate.php index cd17215ee..7d6d7361d 100644 --- a/system/phrasesupdate.php +++ b/system/phrasesupdate.php @@ -41393,8 +41393,30 @@ and represent the current state of research on the topic. The prescribed citatio 'insertvon' => 'system' ) ) - ) + ), // PROJEKTARBEITSBEURTEILUNG SS2025 ENDE --------------------------------------------------------------------------- + // FHC 4 Lehrveranstaltungstermine START --------------------------------------------------------------------------- + array( + 'app' => 'core', + 'category' => 'stv', + 'phrase' => 'tab_courseDates', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'LV Termine', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Course Dates', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + // FHC 4 Lehrveranstaltungstermine ENDE --------------------------------------------------------------------------- ); From 419c199e84ab9d2c3590546c224ff3d2c2c053c6 Mon Sep 17 00:00:00 2001 From: ma0068 Date: Wed, 9 Apr 2025 11:06:50 +0200 Subject: [PATCH 020/107] new Tab GemeinsameStudien --- .../api/frontend/v1/stv/Config.php | 5 + .../api/frontend/v1/stv/GemeinsameStudien.php | 283 +++++++++++ .../models/codex/Mobilitaetstyp_model.php | 14 + public/js/api/stv.js | 2 + public/js/api/stv/jointstudies.js | 33 ++ .../Details/JointStudies.js | 16 + .../Details/JointStudies/JointStudies.js | 467 ++++++++++++++++++ system/phrasesupdate.php | 144 +++++- 8 files changed, 963 insertions(+), 1 deletion(-) create mode 100644 application/controllers/api/frontend/v1/stv/GemeinsameStudien.php create mode 100644 application/models/codex/Mobilitaetstyp_model.php create mode 100644 public/js/api/stv/jointstudies.js create mode 100644 public/js/components/Stv/Studentenverwaltung/Details/JointStudies.js create mode 100644 public/js/components/Stv/Studentenverwaltung/Details/JointStudies/JointStudies.js diff --git a/application/controllers/api/frontend/v1/stv/Config.php b/application/controllers/api/frontend/v1/stv/Config.php index 42de1b02f..e0d9daf26 100644 --- a/application/controllers/api/frontend/v1/stv/Config.php +++ b/application/controllers/api/frontend/v1/stv/Config.php @@ -128,6 +128,11 @@ class Config extends FHCAPI_Controller 'component' => './Stv/Studentenverwaltung/Details/Mobility.js' ]; + $result['jointstudies'] = [ + 'title' => $this->p->t('stv', 'tab_jointstudies'), + 'component' => './Stv/Studentenverwaltung/Details/JointStudies.js' + ]; + Events::trigger('stv_conf_student', function & () use (&$result) { return $result; }); diff --git a/application/controllers/api/frontend/v1/stv/GemeinsameStudien.php b/application/controllers/api/frontend/v1/stv/GemeinsameStudien.php new file mode 100644 index 000000000..dbf9efce1 --- /dev/null +++ b/application/controllers/api/frontend/v1/stv/GemeinsameStudien.php @@ -0,0 +1,283 @@ + ['admin:r', 'assistenz:r'], + 'loadStudie' => ['admin:r', 'assistenz:r'], + 'insertStudie' => ['admin:rw', 'assistenz:rw'], + 'updateStudie' => ['admin:rw', 'assistenz:rw'], + 'deleteStudie' => ['admin:rw', 'assistenz:rw'], + 'getProgramsStudien' => ['admin:r', 'assistenz:r'], + 'getTypenMobility' => ['admin:r', 'assistenz:r'], + 'getStudiensemester' => ['admin:r', 'assistenz:r'], + 'getStudienprogramme' => ['admin:r', 'assistenz:r'], + 'getPartnerfirmen' => ['admin:r', 'assistenz:r'], + 'getStatiPrestudent' => ['admin:r', 'assistenz:r'], + ]); + + // Load Libraries + $this->load->library('VariableLib', ['uid' => getAuthUID()]); + $this->load->library('form_validation'); + + // Load language phrases + $this->loadPhrases([ + 'ui', + 'jointstudies' + ]); + + // Load models + $this->load->model('codex/Mobilitaet_model', 'MobilitaetModel'); + + //TODO(check if additional Permissions necessary): 'student/stammdaten' + } + + public function getStudien($prestudent_id) + { + $this->MobilitaetModel->addSelect('mobilitaet_id'); + $this->MobilitaetModel->addSelect('mobilitaetstyp_kurzbz'); + $this->MobilitaetModel->addSelect('prestudent_id'); + $this->MobilitaetModel->addSelect('studiensemester_kurzbz'); + $this->MobilitaetModel->addSelect('bis.tbl_mobilitaet.mobilitaetsprogramm_code'); + $this->MobilitaetModel->addSelect('bis.tbl_mobilitaet.gsprogramm_id'); + $this->MobilitaetModel->addSelect('bis.tbl_mobilitaet.firma_id'); + $this->MobilitaetModel->addSelect('status_kurzbz'); + $this->MobilitaetModel->addSelect('ausbildungssemester'); + $this->MobilitaetModel->addSelect('bis.tbl_mobilitaet.insertvon'); + $this->MobilitaetModel->addSelect('bis.tbl_mobilitaet.insertamum'); + $this->MobilitaetModel->addSelect('bis.tbl_mobilitaet.updatevon'); + $this->MobilitaetModel->addSelect('bis.tbl_mobilitaet.updateamum'); + $this->MobilitaetModel->addSelect('mp.kurzbz'); + $this->MobilitaetModel->addSelect('gp.gsprogrammtyp_kurzbz'); + $this->MobilitaetModel->addSelect('gp.bezeichnung as studienprogramm'); + $this->MobilitaetModel->addSelect('f.name as partner'); + + $this->MobilitaetModel->addJoin('bis.tbl_mobilitaetsprogramm mp', 'ON (mp.mobilitaetsprogramm_code = bis.tbl_mobilitaet.mobilitaetsprogramm_code)', 'LEFT'); + $this->MobilitaetModel->addJoin('bis.tbl_gsprogramm gp', 'ON (gp.gsprogramm_id = bis.tbl_mobilitaet.gsprogramm_id)', 'LEFT'); + $this->MobilitaetModel->addJoin('public.tbl_firma f', 'ON (f.firma_id = bis.tbl_mobilitaet.firma_id)', 'LEFT'); + + $result = $this->MobilitaetModel->loadWhere([ + 'prestudent_id' => $prestudent_id, + ]); + + $data = $this->getDataOrTerminateWithError($result); + $this->terminateWithSuccess($data); + } + + public function getTypenMobility() + { + $this->load->model('codex/Mobilitaetstyp_model', 'MobilitaetstypModel'); + + $result = $this->MobilitaetstypModel->load(); + $data = $this->getDataOrTerminateWithError($result); + $this->terminateWithSuccess($data); + } + + public function getStudiensemester() + { + $this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel'); + + $this->StudiensemesterModel->addOrder('studienjahr_kurzbz', 'DESC'); + $result = $this->StudiensemesterModel->load(); + $data = $this->getDataOrTerminateWithError($result); + $this->terminateWithSuccess($data); + } + + public function getStudienprogramme() + { + $this->load->model('codex/Gsprogramm_model', 'GsprogrammModel'); + + $result = $this->GsprogrammModel->load(); + $data = $this->getDataOrTerminateWithError($result); + $this->terminateWithSuccess($data); + } + + public function getPartnerfirmen() + { + $this->load->model('ressource/Firma_model', 'FirmaModel'); + + $result = $this->FirmaModel->loadWhere( + ['partner_code !=' => null] + ); + $data = $this->getDataOrTerminateWithError($result); + $this->terminateWithSuccess($data); + } + + public function getStatiPrestudent() + { + $this->load->model('crm/Status_model', 'StatusModel'); + + $result = $this->StatusModel->load(); + $data = $this->getDataOrTerminateWithError($result); + $this->terminateWithSuccess($data); + } + + public function loadStudie($mobilitaet_id) + { + $result = $this->MobilitaetModel->load($mobilitaet_id); + $data = $this->getDataOrTerminateWithError($result); + $this->terminateWithSuccess(current($data)); + } + + public function insertStudie() + { + $this->load->library('form_validation'); + $authUID = getAuthUID(); + + $prestudent_id = $this->input->post('prestudent_id'); + if(!$prestudent_id) + { + return $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Prestudent ID']), self::ERROR_TYPE_GENERAL); + } + + $formData = $this->input->post('formData'); + $_POST['ausbildungssemester'] = (isset($formData['ausbildungssemester']) && !empty($formData['ausbildungssemester'])) + ? $formData['ausbildungssemester'] + : null; + $_POST['mobilitaetstyp_kurzbz'] = (isset($formData['mobilitaetstyp_kurzbz']) && !empty($formData['mobilitaetstyp_kurzbz'])) + ? $formData['mobilitaetstyp_kurzbz'] + : null; + $_POST['studiensemester_kurzbz'] = (isset($formData['studiensemester_kurzbz']) && !empty($formData['studiensemester_kurzbz'])) + ? $formData['studiensemester_kurzbz'] : null; + + $this->form_validation->set_rules('mobilitaetstyp_kurzbz', 'Typ', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Typ']) + ]); + + $this->form_validation->set_rules('studiensemester_kurzbz', 'Studiensemester', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Studiensemester']) + ]); + + $this->form_validation->set_rules('ausbildungssemester', 'Ausbildungssemester', 'required|numeric', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Ausbildungssemester']), + 'numeric' => $this->p->t('ui', 'error_fieldNotNumeric', ['field' => 'Ausbildungssemester']), + ]); + + if ($this->form_validation->run() == false) + { + $this->terminateWithValidationErrors($this->form_validation->error_array()); + } + + $status_kurzbz = (isset($formData['status_kurzbz']) && !empty($formData['status_kurzbz'])) + ? $formData['status_kurzbz'] + : null; + $mobilitaetsprogramm_code = (isset($formData['mobilitaetsprogramm_code']) && !empty($formData['mobilitaetsprogramm_code'])) + ? $formData['mobilitaetsprogramm_code'] + : null; + $gsprogramm_id = (isset($formData['gsprogramm_id']) && !empty($formData['gsprogramm_id'])) + ? $formData['gsprogramm_id'] + : null; + $firma_id= (isset($formData['firma_id']) && !empty($formData['firma_id'])) ? $formData['firma_id'] : null; + + $result = $this->MobilitaetModel->insert([ + 'prestudent_id' => $prestudent_id, + 'mobilitaetstyp_kurzbz' => $_POST['mobilitaetstyp_kurzbz'], + 'status_kurzbz' => $status_kurzbz, + 'studiensemester_kurzbz' => $_POST['studiensemester_kurzbz'], + 'mobilitaetsprogramm_code' => $mobilitaetsprogramm_code, + 'gsprogramm_id' => $gsprogramm_id, + 'firma_id' => $firma_id, + 'ausbildungssemester' => $_POST['ausbildungssemester'], + 'insertvon' => $authUID, + 'insertamum' => date('c'), + ]); + + $data = $this->getDataOrTerminateWithError($result); + $this->terminateWithSuccess($data); + } + + public function updateStudie() + { + $this->load->library('form_validation'); + $authUID = getAuthUID(); + + $prestudent_id = $this->input->post('prestudent_id'); + if(!$prestudent_id) + { + return $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Prestudent ID']), self::ERROR_TYPE_GENERAL); + } + + $formData = $this->input->post('formData'); + + $_POST['mobilitaet_id'] = (isset($formData['mobilitaet_id']) && !empty($formData['mobilitaet_id'])) + ? $formData['mobilitaet_id'] : + $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Mobilitaet ID']), self::ERROR_TYPE_GENERAL); + $_POST['ausbildungssemester'] = (isset($formData['ausbildungssemester']) && !empty($formData['ausbildungssemester'])) + ? $formData['ausbildungssemester'] + : null; + $_POST['mobilitaetstyp_kurzbz'] = (isset($formData['mobilitaetstyp_kurzbz']) && !empty($formData['mobilitaetstyp_kurzbz'])) + ? $formData['mobilitaetstyp_kurzbz'] + : null; + $_POST['studiensemester_kurzbz'] = (isset($formData['studiensemester_kurzbz']) && !empty($formData['studiensemester_kurzbz'])) + ? $formData['studiensemester_kurzbz'] + : null; + + $this->form_validation->set_rules('mobilitaetstyp_kurzbz', 'Typ', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Typ']) + ]); + + $this->form_validation->set_rules('studiensemester_kurzbz', 'Studiensemester', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Studiensemester']) + ]); + + $this->form_validation->set_rules('ausbildungssemester', 'Ausbildungssemester', 'required|numeric', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Ausbildungssemester']), + 'numeric' => $this->p->t('ui', 'error_fieldNotNumeric', ['field' => 'Ausbildungssemester']), + ]); + + if ($this->form_validation->run() == false) + { + $this->terminateWithValidationErrors($this->form_validation->error_array()); + } + + $status_kurzbz = (isset($formData['status_kurzbz']) && !empty($formData['status_kurzbz'])) ? $formData['status_kurzbz'] : null; + $mobilitaetsprogramm_code = (isset($formData['mobilitaetsprogramm_code']) && !empty($formData['mobilitaetsprogramm_code'])) + ? $formData['mobilitaetsprogramm_code'] + : null; + $gsprogramm_id = (isset($formData['gsprogramm_id']) && !empty($formData['gsprogramm_id'])) + ? $formData['gsprogramm_id'] + : null; + $firma_id= (isset($formData['firma_id']) && !empty($formData['firma_id'])) ? $formData['firma_id'] : null; + + $result = $this->MobilitaetModel->update( + [ + 'mobilitaet_id' => $_POST['mobilitaet_id'], + ], + [ + 'prestudent_id' => $prestudent_id, + 'mobilitaetstyp_kurzbz' => $_POST['mobilitaetstyp_kurzbz'], + 'status_kurzbz' => $status_kurzbz, + 'studiensemester_kurzbz' => $_POST['studiensemester_kurzbz'], + 'mobilitaetsprogramm_code' => $mobilitaetsprogramm_code, + 'gsprogramm_id' => $gsprogramm_id, + 'firma_id' => $firma_id, + 'ausbildungssemester' => $_POST['ausbildungssemester'], + 'updatevon' => $authUID, + 'updateamum' => date('c'), + ] + ); + + $data = $this->getDataOrTerminateWithError($result); + $this->terminateWithSuccess($data); + } + + public function deleteStudie($mobilitaet_id) + { + if(!$mobilitaet_id) + { + return $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Mobilität ID']), self::ERROR_TYPE_GENERAL); + } + $result = $this->MobilitaetModel->delete( + array('mobilitaet_id' => $mobilitaet_id) + ); + + $data = $this->getDataOrTerminateWithError($result); + $this->terminateWithSuccess($data); + } +} diff --git a/application/models/codex/Mobilitaetstyp_model.php b/application/models/codex/Mobilitaetstyp_model.php new file mode 100644 index 000000000..f93f588a0 --- /dev/null +++ b/application/models/codex/Mobilitaetstyp_model.php @@ -0,0 +1,14 @@ +dbTable = 'bis.tbl_mobilitaetstyp'; + $this->pk = 'mobilitaetstyp_kurzbz'; + } +} diff --git a/public/js/api/stv.js b/public/js/api/stv.js index ae88b0516..89a69c84e 100644 --- a/public/js/api/stv.js +++ b/public/js/api/stv.js @@ -10,6 +10,7 @@ import exam from './stv/exam.js'; import abschlusspruefung from './stv/abschlusspruefung.js'; import grades from './stv/grades.js'; import mobility from './stv/mobility.js'; +import jointstudies from "./stv/jointstudies.js"; export default { verband, @@ -24,6 +25,7 @@ export default { abschlusspruefung, grades, mobility, + jointstudies, configStudent() { return this.$fhcApi.get('api/frontend/v1/stv/config/student'); }, diff --git a/public/js/api/stv/jointstudies.js b/public/js/api/stv/jointstudies.js new file mode 100644 index 000000000..b550852df --- /dev/null +++ b/public/js/api/stv/jointstudies.js @@ -0,0 +1,33 @@ +export default { + getStudies(url, config, params) { + return this.$fhcApi.get('api/frontend/v1/stv/GemeinsameStudien/getStudien/' + params.id); + }, + getTypenMobility(){ + return this.$fhcApi.get('api/frontend/v1/stv/GemeinsameStudien/getTypenMobility/'); + }, + getStudiensemester(){ + return this.$fhcApi.get('api/frontend/v1/stv/GemeinsameStudien/getStudiensemester/'); + }, + getStudyprograms(){ + return this.$fhcApi.get('api/frontend/v1/stv/GemeinsameStudien/getStudienprogramme/'); + }, + getListPartner(){ + return this.$fhcApi.get('api/frontend/v1/stv/GemeinsameStudien/getPartnerfirmen/'); + }, + getStatiPrestudent(){ + return this.$fhcApi.get('api/frontend/v1/stv/GemeinsameStudien/getStatiPrestudent/'); + }, + loadStudy(id){ + return this.$fhcApi.get('api/frontend/v1/stv/GemeinsameStudien/loadStudie/' + id); + }, + insertStudy(form, data){ + return this.$fhcApi.post(form,'api/frontend/v1/stv/GemeinsameStudien/insertStudie/', data); + }, + updateStudy(form, data){ + return this.$fhcApi.post(form,'api/frontend/v1/stv/GemeinsameStudien/updateStudie/', data); + }, + deleteStudy(id){ + return this.$fhcApi.post('api/frontend/v1/stv/GemeinsameStudien/deleteStudie/' + id); + }, + +} \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung/Details/JointStudies.js b/public/js/components/Stv/Studentenverwaltung/Details/JointStudies.js new file mode 100644 index 000000000..e80ae34f6 --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Details/JointStudies.js @@ -0,0 +1,16 @@ +import TblJointStudies from "./JointStudies/JointStudies.js"; + +export default { + name: 'Tab_JointStudies', + components: { + TblJointStudies + }, + props: { + modelValue: Object, + }, + template: ` +
+ +
+ ` +} \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung/Details/JointStudies/JointStudies.js b/public/js/components/Stv/Studentenverwaltung/Details/JointStudies/JointStudies.js new file mode 100644 index 000000000..1c75486de --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Details/JointStudies/JointStudies.js @@ -0,0 +1,467 @@ +import {CoreFilterCmpt} from "../../../../filter/Filter.js"; +import BsModal from "../../../../Bootstrap/Modal.js"; +import FormForm from "../../../../Form/Form.js"; +import FormInput from "../../../../Form/Input.js"; + +export default { + name: 'Tbl_JointStudies', + components: { + CoreFilterCmpt, + BsModal, + FormForm, + FormInput, + }, + inject: { + currentSemester: { + from: 'currentSemester', + }, + }, + props: { + student: Object + }, + data(){ + return { + tabulatorOptions: { + ajaxURL: 'dummy', + ajaxRequestFunc: this.$fhcApi.factory.stv.jointstudies.getStudies, + ajaxParams: () => { + return { + id: this.student.prestudent_id + }; + }, + ajaxResponse: (url, params, response) => response.data, + columns: [ + {title: "mobilitaet_id", field: "mobilitaet_id", visible: false}, + {title: "StSem", field: "studiensemester_kurzbz"}, + // {title: "mobilitaetstyp_kurzbz", field: "mobilitaetstyp_kurzbz"}, + {title: "kurzbz", field: "kurzbz"}, + {title: "prestudent_id", field: "prestudent_id", visible: false}, + {title: "Status", field: "status_kurzbz"}, + {title: "Partner", field: "partner", visible: false}, + {title: "Sem", field: "ausbildungssemester"}, + {title: "gsprogrammtyp_kurzbz", field: "gsprogrammtyp_kurzbz"}, + {title: "studienprogramm", field: "studienprogramm", visible: false}, + {title: "insertvon", field: "insertvon", visible: false}, + { + title: "insertamum", field: "insertamum", + 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", + }); + }, + visible: false + }, + {title: "updatevon", field: "updatevon", visible: false}, + { + title: "updateamum", field: "updateamum", + 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", + }); + }, + visible: false + }, + { + title: 'Aktionen', + field: 'actions', + minWidth: 150, + maxWidth: 150, + 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('exam', 'newFromOld_studies'); + button.addEventListener( + 'click', + (event) => + this.actionNewFromOldJointStudy(cell.getData().mobilitaet_id) + ); + container.append(button); + + button = document.createElement('button'); + button.className = 'btn btn-outline-secondary btn-action'; + button.innerHTML = ''; + button.title = this.$p.t('exam', 'edit_studies'); + button.addEventListener( + 'click', + (event) => + this.actionEditJointStudy(cell.getData().mobilitaet_id) + ); + container.append(button); + + button = document.createElement('button'); + button.className = 'btn btn-outline-secondary btn-action'; + button.innerHTML = ''; + button.title = this.$p.t('exam', 'delete_studies'); + button.addEventListener( + 'click', + () => + this.actionDeleteJointStudy(cell.getData().mobilitaet_id) + ); + container.append(button); + + return container; + }, + frozen: true + }, + ], + }, + tabulatorEvents: [ + { + event: 'tableBuilt', + handler: async() => { + await this.$p.loadCategory(['global', 'jointstudies', 'ui', 'lehre', 'mobility']); + + + let cm = this.$refs.table.tabulator.columnManager; + + cm.getColumnByField('mobilitaet_id').component.updateDefinition({ + title: this.$p.t('global', 'mobilitaet_id') + }); +/* cm.getColumnByField('studiensemester_kurzbz').component.updateDefinition({ + title: this.$p.t('lehre', 'studiensemester') + });*/ + cm.getColumnByField('gsprogrammtyp_kurzbz').component.updateDefinition({ + title: this.$p.t('global', 'typ') + }); +/* cm.getColumnByField('ausbildungssemester').component.updateDefinition({ + title: this.$p.t('lehre', 'semester') + });*/ + cm.getColumnByField('prestudent_id').component.updateDefinition({ + title: this.$p.t('global', 'prestudentID') + }); + cm.getColumnByField('kurzbz').component.updateDefinition({ + title: this.$p.t('mobility', 'mobilitaetsprogramm') + }); + cm.getColumnByField('studienprogramm').component.updateDefinition({ + title: this.$p.t('jointstudies', 'studienprogramm') + }); + cm.getColumnByField('insertamum').component.updateDefinition({ + title: this.$p.t('global', 'insertamum') + }); + cm.getColumnByField('insertvon').component.updateDefinition({ + title: this.$p.t('global', 'insertvon') + }); + cm.getColumnByField('updateamum').component.updateDefinition({ + title: this.$p.t('global', 'updateamum') + }); + cm.getColumnByField('updatevon').component.updateDefinition({ + title: this.$p.t('global', 'updatevon') + }); + +/* cm.getColumnByField('actions').component.updateDefinition({ + title: this.$p.t('global', 'aktionen') + });*/ + } + } + ], + formData: { + mobilitaetstyp_kurzbz: "GS", + studiensemester_kurzbz: this.currentSemester, + status_kurzbz: 'Student', + mobilitaet_id: null + }, + statusNew: true, + listTypenMobility: [], + listStudiensemester: [], + programsMobility: [], + listStudienprogramme: [], + listPartner: [], + statiPrestudent: [], + } + }, + methods: { + actionDeleteJointStudy(mobilitaet_id) { + this.$fhcAlert + .confirmDelete() + .then(result => result + ? mobilitaet_id + : Promise.reject({handled: true})) + .then(this.deleteJointStudy) + .catch(this.$fhcAlert.handleSystemError); + }, + actionEditJointStudy(mobilitaet_id) { + this.resetForm(); + this.statusNew = false; + this.loadJointStudy(mobilitaet_id); + this.$refs.jointstudyModal.show(); + }, + actionNewFromOldJointStudy(mobilitaet_id) { + this.resetForm(); + this.loadJointStudy(mobilitaet_id); + this.statusNew = true; + this.$refs.jointstudyModal.show(); + }, + actionNewJointStudy() { + this.resetForm(); + this.statusNew = true; + this.$refs.jointstudyModal.show(); + }, + addNewJointStudy() { + const data = { + prestudent_id: this.student.prestudent_id, + formData: this.formData + }; + return this.$fhcApi.factory.stv.jointstudies.insertStudy(this.$refs.formJointStudies, data) + .then(response => { + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSave')); + this.hideModal("jointstudyModal"); + this.resetForm(); + }) + .catch(this.$fhcAlert.handleSystemError) + .finally(() => { + this.reload(); + }); + }, + updateJointStudy() { + const data = { + prestudent_id: this.student.prestudent_id, + formData: this.formData + }; + return this.$fhcApi.factory.stv.jointstudies.updateStudy(this.$refs.formJointStudies, data) + .then(response => { + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSave')); + this.hideModal("jointstudyModal"); + this.resetForm(); + }) + .catch(this.$fhcAlert.handleSystemError) + .finally(() => { + this.reload(); + }); + }, + loadJointStudy(mobilitaet_id) { + return this.$fhcApi.factory.stv.jointstudies.loadStudy(mobilitaet_id) + .then(result => { + this.formData = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + }, + deleteJointStudy(mobilitaet_id) { + return this.$fhcApi.factory.stv.jointstudies.deleteStudy(mobilitaet_id) + .then(response => { + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successDelete')); + }) + .catch(this.$fhcAlert.handleSystemError) + .finally(() => { + this.reload(); + }); + }, + hideModal(modalRef){ + this.$refs[modalRef].hide(); + }, + reload() { + this.$refs.table.reloadTable(); + }, + resetForm() { + this.formData = {}; + this.formData.mobilitaetstyp_kurzbz = "GS"; + this.formData.status_kurzbz = 'Student'; + this.formData.studiensemester_kurzbz = this.currentSemester; + this.formData.prestudent_id = this.student.prestudent_id; + } + }, + created(){ + this.$fhcApi.factory.stv.jointstudies.getTypenMobility() + .then(result => { + this.listTypenMobility = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + this.$fhcApi.factory.stv.jointstudies.getStudiensemester() + .then(result => { + this.listStudiensemester = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + this.$fhcApi.factory.stv.mobility.getProgramsMobility() + .then(result => { + this.programsMobility = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + this.$fhcApi.factory.stv.jointstudies.getStudyprograms() + .then(result => { + this.listStudienprogramme = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + this.$fhcApi.factory.stv.jointstudies.getListPartner() + .then(result => { + this.listPartner = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + this.$fhcApi.factory.stv.jointstudies.getStatiPrestudent() + .then(result => { + this.statiPrestudent = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + + }, + template: ` +
+

{{$p.t('jointstudies', 'gemeinsameStudien')}}

+ + + + + + + + + +
+ + + +
+ +
+ + + +
+ +
+ + + +
+ +
+ + + +
+ +
+ + + +
+ +
+ + + +
+
+ + +
+ +
+ + + +
+ +
+ ` +} diff --git a/system/phrasesupdate.php b/system/phrasesupdate.php index cd17215ee..81089fcd6 100644 --- a/system/phrasesupdate.php +++ b/system/phrasesupdate.php @@ -41393,8 +41393,150 @@ and represent the current state of research on the topic. The prescribed citatio 'insertvon' => 'system' ) ) - ) + ), // PROJEKTARBEITSBEURTEILUNG SS2025 ENDE --------------------------------------------------------------------------- + // FHC4 JOINT STUDIES START ---------------------------------------------------------------------------------------- + array( + 'app' => 'core', + 'category' => 'stv', + 'phrase' => 'tab_jointstudies', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'GS', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Joint Studies', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'jointstudies', + 'phrase' => 'gemeinsamesStudium', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Gemeinsames Studium', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Joint Study', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'jointstudies', + 'phrase' => 'gemeinsameStudien', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Gemeinsame Studien', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Joint Studies', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'jointstudies', + 'phrase' => 'studienprogramm', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Studienprogramm', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Study Program', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'jointstudies', + 'phrase' => 'neuAnlegen', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Gemeinsames Studium anlegen', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Add Joint Study', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'jointstudies', + 'phrase' => 'edit', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Gemeinsames Studium bearbeiten', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Edit Joint Study', + 'description' => '', + 'insertvon' => 'system', + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'global', + 'phrase' => 'mobilitaet_id', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Mobilität ID', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Mobility Id', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + // FHC4 JOINT STUDIES END ---------------------------------------------------------------------------------------- ); From af30a3408cd3d6dfc462554ffdb6c3a48c90fa35 Mon Sep 17 00:00:00 2001 From: ma0068 Date: Tue, 15 Apr 2025 14:22:39 +0200 Subject: [PATCH 021/107] add switch stundenplan, excel export, phrases --- .../api/frontend/v1/stv/LvTermine.php | 408 ++++++++++++++++++ .../api/frontend/v1/stv/Lvtermine.php | 67 --- .../models/ressource/Stundenplan_model.php | 124 +++++- public/css/Studentenverwaltung.css | 4 + public/js/api/stv/courselist.js | 13 +- .../ListLehrveranstaltungstermine.js | 175 +++++++- system/phrasesupdate.php | 180 ++++++++ 7 files changed, 876 insertions(+), 95 deletions(-) create mode 100644 application/controllers/api/frontend/v1/stv/LvTermine.php delete mode 100644 application/controllers/api/frontend/v1/stv/Lvtermine.php diff --git a/application/controllers/api/frontend/v1/stv/LvTermine.php b/application/controllers/api/frontend/v1/stv/LvTermine.php new file mode 100644 index 000000000..c29f56964 --- /dev/null +++ b/application/controllers/api/frontend/v1/stv/LvTermine.php @@ -0,0 +1,408 @@ + ['admin:r', 'assistenz:r'], + 'getStudiensemester' => ['admin:r', 'assistenz:r'], + ]); + + // Load Libraries + $this->load->library('VariableLib', ['uid' => getAuthUID()]); + $this->load->library('form_validation'); + + // Load language phrases + $this->loadPhrases([ + 'ui', + ]); + + // Load models + $this->load->model('ressource/Stundenplan_model', 'StundenplanModel'); + + //query verwenden wie im Cis endpoint + $this->load->model('ressource/Mitarbeiter_model', 'MitarbeiterModel'); + $this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel'); + $this->load->model('education/Studentlehrverband_model', 'StudentlehrverbandModel'); + $this->load->model('person/Benutzergruppe_model', 'BenutzergruppeModel'); + } + + //TODO Build own lib or combine with Controller Stundenplan.php + //here use of logic of Stundenplan.php, extended with parameters uid, grouping, and used dbTable + public function getStundenplan($uid, $start_date = null, $end_date = null, $groupConsecutiveHours = false, $dbStundenplanTable = "stundenplan") + { + $student_uid = $uid; + $semester_range = $this->studienSemesterErmitteln($start_date, $end_date); + + $this->sortStudienSemester($semester_range); + $this->applyLoadUeberSemesterHaelfte($semester_range); + + $benutzer_gruppen = $this->fetchBenutzerGruppenFromStudiensemester($semester_range, $student_uid); + $student_lehrverband = $this->fetchStudentlehrverbandFromStudiensemester($semester_range, $student_uid); + + if(!$groupConsecutiveHours) + $stundenplan_query = $this->StundenplanModel->getStundenplanQuery( + $start_date, + $end_date, + $semester_range, + $benutzer_gruppen, + $student_lehrverband + ); + else + $stundenplan_query = $this->StundenplanModel->getStundenplanQuery( + $start_date, + $end_date, + $semester_range, + $benutzer_gruppen, + $student_lehrverband, + true, + $dbStundenplanTable + ); + + if(!$stundenplan_query) + { + $this->terminateWithSuccess([]); + } + + if($groupConsecutiveHours) + { + $stundenplan_data = $this->StundenplanModel->stundenplanGruppierungConsecutive($stundenplan_query); + } + else + { + $stundenplan_data = $this->StundenplanModel->stundenplanGruppierung($stundenplan_query); + } + + $stundenplan_data = $this->getDataOrTerminateWithError($stundenplan_data) ?? []; + $this->terminateWithSuccess($stundenplan_data); + + $this->expand_object_information($stundenplan_data); + + $this->returnObj['$stundenplan_query'] = $stundenplan_query; + $this->returnObj['$student_lehrverband'] = $student_lehrverband; + $this->returnObj['$benutzer_gruppen'] = $benutzer_gruppen; + $this->terminateWithSuccess($stundenplan_data); + } + + public function getStudiensemester() + { + $this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel'); + + $this->StudiensemesterModel->addOrder('studienjahr_kurzbz', 'DESC'); + $result = $this->StudiensemesterModel->load(); + $data = $this->getDataOrTerminateWithError($result); + $this->terminateWithSuccess($data); + } + + //copied from Stundenplan.php + private function studienSemesterErmitteln($start_date, $end_date) + { + // gets all studiensemester from the student from start_date to end_date + $semester_range = $this->StudiensemesterModel->getByDateRange($start_date, $end_date); + $semester_range = array_map( + function ($sem) { + return $sem->studiensemester_kurzbz; + }, + $this->getDataOrTerminateWithError($semester_range) + ); + + // if no studiensemester is found for the given timespan, get the nearest studiensemester + if(count($semester_range) == 0) + { + $aktuelle_studiensemester = $this->StudiensemesterModel->getNearest(); + $aktuelle_studiensemester = $this->getDataOrTerminateWithError($aktuelle_studiensemester); + if (count($aktuelle_studiensemester) == 0) { + $this->terminateWithError("No aktuelles semester"); + } + $aktuelle_studiensemester = current($aktuelle_studiensemester)->studiensemester_kurzbz; + // push aktuelles semester in active semester array + array_push($semester_range, $aktuelle_studiensemester); + } + return $semester_range; + } + + //copied from Stundenplan.php + private function sortStudienSemester(&$semester_range) + { + usort( + $semester_range, + function ($first, $second) { + $sem_first = null; + $year_first = null; + $match_first = null; + + $sem_second = null; + $year_second = null; + $match_second = null; + + preg_match('/([WS]+)([0-9]+)/', $first, $match_first); + preg_match('/([WS]+)([0-9]+)/', $second, $match_second); + + $sem_first = $match_first[1]; + $year_first = intval($match_first[2]); + + $sem_second = $match_second[1]; + $year_second = intval($match_second[2]); + + if($year_first < $year_second) + { + return -1; + } + elseif($year_first > $year_second) + { + return 1; + } + elseif($year_first == $year_second && $sem_first > $sem_second) + { + return 1; + } + elseif($year_first == $year_second && $sem_first < $sem_second) + { + return -1; + } + return 0; + } + ); + } + + //copied from Stundenplan.php + private function applyLoadUeberSemesterHaelfte(&$semester_range) + { + /* + @var($semester_collection) + convert the array of studiensemester into an associative array with the studiensemester as the key + and the values of each key are the studiensemester needed for the query associated to that studiensemester + example: + + #INPUT: + ['WS2023','SS2024','WS2024'] + #OUTPUT: + [ + 'WS2023' => ['SS2023','WS2023'] + 'SS2024' => ['WS2023','SS2024'] + 'WS2024' => ['SS2024','WS2024'] + ] + */ + $semester_collection = []; + foreach($semester_range as $studiensemester) + { + $previous_studiensemester = $this->StudiensemesterModel->getPreviousFrom($studiensemester); + $previous_studiensemester = $this->getDataOrTerminateWithError($previous_studiensemester); + if (count($previous_studiensemester) == 0) { + $this->terminateWithError("No previous semester"); + } + $previous_studiensemester = current($previous_studiensemester)->studiensemester_kurzbz; + $semester_collection[$studiensemester] = [$previous_studiensemester, $studiensemester]; + } + + /* + @var($studienSemesterDateRanges) + fetches for each studiensemester the start and end date, (SS) summer studiensemester are extended by 1 month to cover the summerbreak + based on the LVPLAN_LOAD_UEBER_SEMESTERHAELFTE constant it will load both the semester and the previous semester with the full date range + or the semester with the full date range and the previous semester with the half date range: + + #INPUT: + [ + 'WS2023' => ['SS2023','WS2023'] + 'SS2024' => ['WS2023','SS2024'] + 'WS2024' => ['SS2024','WS2024'] + ] + #OUTPUT: depends whether LVPLAN_LOAD_UEBER_SEMESTERHAELFTE is true or false + ~ if LVPLAN_LOAD_UEBER_SEMESTERHAELFTE == true + [ + "SS2024": [ + "WS2023": [ + "start"=> "2024-02-03", + "ende"=> "2024-08-31" + ], + "SS2024": [ + "start"=> "2024-02-03", + "ende"=> "2024-08-31" + ] + ] + ] + ~ if LVPLAN_LOAD_UEBER_SEMESTERHAELFTE == false + [ + "SS2024": [ + "WS2023": [ + "start"=> "2024-02-03", + "ende"=> "2024-05-17" + ], + "SS2024": [ + "start"=> "2024-02-03", + "ende"=> "2024-08-31" + ] + ] + ] + */ + $studienSemesterDateRanges=[]; + foreach($semester_collection as $semester_original => $semester_adjoint) + { + $semester_start_ende = $this->StudiensemesterModel->getStartEndeFromStudiensemester($semester_original); + $semester_start_ende = current($this->getDataOrTerminateWithError($semester_start_ende)); + + // initialize empty arrays to add key value pairs + $studienSemesterDateRanges[$semester_original] = []; + + // check if the studiensemester is a summer semester and add 1 month to bridge the school summer break + $match = null; + preg_match("/^(SS)([0-9]+)/", $semester_original, $match); + if(count($match) >0) + { + $one_month = new DateInterval('P1M'); + $one_day = DateInterval::createFromDateString('1 days'); + $summer_studiensemester_end_date = DateTime::createFromFormat('Y-m-d', $semester_start_ende->ende); + $summer_studiensemester_end_date->add($one_month); + $summer_studiensemester_end_date->sub($one_day); + $semester_start_ende->ende = date_format($summer_studiensemester_end_date, 'Y-m-d'); + } + if (defined('LVPLAN_LOAD_UEBER_SEMESTERHAELFTE') && LVPLAN_LOAD_UEBER_SEMESTERHAELFTE === true) + { + foreach($semester_adjoint as $adjoint) + { + $studienSemesterDateRanges[$semester_original][$adjoint]=$semester_start_ende; + } + } + else + { + //TODO: half of a DateInterval might not be correctly calculated + // calculate the half of the studiensemester + $studiensemester_start_date = DateTime::createFromFormat('Y-m-d', $semester_start_ende->start); + $studiensemester_end_date = DateTime::createFromFormat('Y-m-d', $semester_start_ende->ende); + $studiensemester_time_difference = $studiensemester_start_date->diff($studiensemester_end_date); + $half_dateNumber = ceil($studiensemester_time_difference->d/2)+ceil(($studiensemester_time_difference->m*30)/2); + $half_dateInterval = new DateInterval('P'.strval($half_dateNumber) .'D'); + $studiensemester_half = date_format($studiensemester_start_date->add($half_dateInterval), 'Y-m-d'); + + $first_half = new stdClass(); + $first_half->start = $semester_start_ende->start; + $first_half->ende = $studiensemester_half; + + $studienSemesterDateRanges[$semester_original][$semester_adjoint[0]] = $first_half; + $studienSemesterDateRanges[$semester_original][$semester_adjoint[1]] = $semester_start_ende; + } + $semester_range = $studienSemesterDateRanges; + } + } + + //copied from Stundenplan.php, extended with $student_uid + private function fetchBenutzerGruppenFromStudiensemester($semester_range, $student_uid) + { + //$student_uid = getAuthUID(); + $benutzer_gruppen = []; + // for each studiensemester fetch the benutzer gruppen and add them to an associate $bentuzer_gruppen array + /* + [ + ['WS2023'] => [['gruppe1_SS2023','gruppe2_SS2023'],['gruppe1_WS2023','gruppe2_WS2023']], + ['SS2024'] => [['gruppe1_WS2023','gruppe2_WS2023'],['gruppe1_SS2024','gruppe2_SS2024']], + ['WS2024'] => [['gruppe1_SS2024','gruppe2_SS2024'],['gruppe1_WS2024','gruppe2_WS2024']], + ] + */ + foreach($semester_range as $semester_key => $semester_array) + { + $benutzer_gruppen[$semester_key] = []; + // each semester could have ajoint semesters that need to be checked + foreach($semester_array as $semester => $semester_date_range) + { + // for each active semester query the benutzer_gruppen associated to the semester + $benutzer_query = $this->BenutzergruppeModel->execReadOnlyQuery(" + SELECT * FROM tbl_benutzergruppe where uid = ? AND studiensemester_kurzbz = ?", [$student_uid, $semester]); + $benutzer_query_result = $this->getDataOrTerminateWithError($benutzer_query); + array_push( + $benutzer_gruppen[$semester_key], + array_map( + function ($item) { + return "'".$item->gruppe_kurzbz. "'"; + }, + $benutzer_query_result + ) + ); + } + } + + // merge the gruppen of each studiensemester together for the original studiensemester + /* + [ + ['WS2023'] => ['gruppe1_SS2023','gruppe2_SS2023','gruppe1_WS2023','gruppe2_WS2023'], + ['SS2024'] => ['gruppe1_WS2023','gruppe2_WS2023','gruppe1_SS2024','gruppe2_SS2024'], + ['WS2024'] => ['gruppe1_SS2024','gruppe2_SS2024','gruppe1_WS2024','gruppe2_WS2024'], + ] + */ + $benutzer_gruppen = array_map( + function ($gruppe) { + $merged_gruppe = []; + foreach($gruppe as $gruppen_array) + { + $merged_gruppe = array_merge($merged_gruppe, $gruppen_array); + } + return $merged_gruppe; + }, + $benutzer_gruppen + ); + + return $benutzer_gruppen; + } + + //copied from Stundenplan.php, extended with $student_uid + private function fetchStudentlehrverbandFromStudiensemester($semester_range, $student_uid) + { + //$student_uid = getAuthUID(); + $student_lehrverband = []; + // for each studiensemester fetch the studentlehrverbaende and add them to an associate $student_lehrverband array + /* + [ + ['WS2023'] => [ [ ['stg_kz'=>298,'semester'=>1,'verband'=>"A",'gruppe'=>""] ] ], + ['SS2024'] => [ [ ['stg_kz'=>298,'semester'=>1,'verband'=>"A",'gruppe'=>""] ], [ ['stg_kz'=>298,'semester'=>2,'verband'=>"A",'gruppe'=>""] ] ], + ['WS2024'] => [ [ ['stg_kz'=>298,'semester'=>2,'verband'=>"A",'gruppe'=>""] ], [ ['stg_kz'=>298,'semester'=>3,'verband'=>"A",'gruppe'=>""] ] ], + ] + */ + foreach($semester_range as $semester_key => $semester_array) + { + $student_lehrverband[$semester_key] = []; + foreach($semester_array as $semester => $semester_date_range) + { + // for each active semester query the student_lehrverband associated to the semester + $lehrverband_query = $this->BenutzergruppeModel->execReadOnlyQuery(" + SELECT * FROM tbl_studentlehrverband where student_uid = ? AND studiensemester_kurzbz = ?", [$student_uid, $semester]); + $lehrverband_query_result = $this->getDataOrTerminateWithError($lehrverband_query); + array_push($student_lehrverband[$semester_key], array_map( + function ($item) { + $result = new stdClass(); + $result->studiengang_kz = $item->studiengang_kz; + $result->semester = $item->semester; + $result->verband = $item->verband; + $result->gruppe = $item->gruppe; + return $result; + }, + $lehrverband_query_result)); + } + } + + // merge the studentlehrverband of each studiensemester together for the original studiensemester + /* + [ + ['WS2023'] => [ ['stg_kz'=>298,'semester'=>1,'verband'=>"A",'gruppe'=>""] ], + ['SS2024'] => [ ['stg_kz'=>298,'semester'=>1,'verband'=>"A",'gruppe'=>""], ['stg_kz'=>298,'semester'=>2,'verband'=>"A",'gruppe'=>""] ], + ['WS2024'] => [ ['stg_kz'=>298,'semester'=>2,'verband'=>"A",'gruppe'=>""], ['stg_kz'=>298,'semester'=>3,'verband'=>"A",'gruppe'=>""] ], + ] + */ + $student_lehrverband = array_map( + function ($studentlehrverband) { + $merged_studentlehrverband = []; + foreach($studentlehrverband as $studentlehrverband_array) + { + $merged_studentlehrverband = array_merge($merged_studentlehrverband, $studentlehrverband_array); + } + return $merged_studentlehrverband; + }, + $student_lehrverband + ); + + return $student_lehrverband; + } +} diff --git a/application/controllers/api/frontend/v1/stv/Lvtermine.php b/application/controllers/api/frontend/v1/stv/Lvtermine.php deleted file mode 100644 index 17a529f85..000000000 --- a/application/controllers/api/frontend/v1/stv/Lvtermine.php +++ /dev/null @@ -1,67 +0,0 @@ - ['admin:r', 'assistenz:r'], - 'getLvsStudent' => ['admin:r', 'assistenz:r'], - ]); - - // Load Libraries - $this->load->library('VariableLib', ['uid' => getAuthUID()]); - $this->load->library('form_validation'); - - // Load language phrases - $this->loadPhrases([ - 'ui', - ]); - - // Load models - $this->load->model('ressource/Stundenplan_model', 'StundenplanModel'); - } - - public function getStundenplan($uid) - { - //get stundenplan for uid - $result = $this->StundenplanModel->loadForUid($uid); - - $data = $this->getDataOrTerminateWithError($result); - - $this->terminateWithSuccess($data); - - } - - public function getLvsStudent($uid) - { - $authUID = getAuthUID(); - //$this->terminateWithError('uid' . $uid, self::ERROR_TYPE_GENERAL); - //$this->terminateWithError('uid' . $authUID, self::ERROR_TYPE_GENERAL); - - $this->load->model('system/Variable_model', 'VariableModel'); - $result = $this->VariableModel->getVariables($authUID); - $data = $this->getDataOrTerminateWithError($result); - - //$this->terminateWithSuccess(current($data)); // WS2025 - - $this->load->model('ressource/Stunde_model', 'StundeModel'); - $this->StundeModel->addOrder('stunde', 'ASC'); - $result = $this->StundeModel->load(); - $dataStunden = $this->getDataOrTerminateWithError($result); - $this->terminateWithSuccess($dataStunden); - // $this->terminateWithSuccess(current($data)); - - //TODO(manu) check existing apis for liste stundenplan und lvs - // version for student - // version for lehrfaecherverteilung - - - - - } -} \ No newline at end of file diff --git a/application/models/ressource/Stundenplan_model.php b/application/models/ressource/Stundenplan_model.php index 40498a766..ac20c96c3 100644 --- a/application/models/ressource/Stundenplan_model.php +++ b/application/models/ressource/Stundenplan_model.php @@ -50,7 +50,6 @@ class Stundenplan_model extends DB_Model */ public function groupedCalendarEvents($ort_kurzbz,$start_date,$end_date){ - $gruppierteEvents= $this->execReadOnlyQuery(" SELECT @@ -186,6 +185,99 @@ class Stundenplan_model extends DB_Model return $query_result; } + /** + * groups rows of a subquery that fetches data from the lehre.vw_stundenplan table or lehre.vw_stundenplandev + * @param string $stundenplanViewQuery the subquery used to group the result regarding consecutive hours (Tab LV Termine) + * + * @return stdClass + */ + public function stundenplanGruppierungConsecutive($stundenplanViewQuery) + { + $query_result = $this->execReadOnlyQuery(" + SELECT + distinct lehrveranstaltung_id, + datum, + MIN(beginn) as beginn, + MAX(ende) as ende, + type, + topic, + gruppe, + ort_kurzbz, + lehreinheit_id, + lehrfach_bez, + lektor, + lektorname, + gruppen_kuerzel, + farbe + FROM + ( + SELECT + 'lehreinheit' as type, beginn, ende, datum, + CONCAT(lehrfach,'-',lehrform) as topic, + array_agg(DISTINCT lektor) as lektor, + array_agg(DISTINCT lektorname) as lektorname, + array_agg(DISTINCT (gruppe,verband,semester,studiengang_kz,gruppen_kuerzel)) as gruppe, + array_agg(DISTINCT (gruppen_kuerzel)) as gruppen_kuerzel, + string_agg(DISTINCT ort_kurzbz, '/') as ort_kurzbz, + array_agg(DISTINCT lehreinheit_id) as lehreinheit_id, + titel, lehrfach, lehrform, lehrfach_bez, organisationseinheit, farbe, lehrveranstaltung_id + + FROM + ( + SELECT unr,datum,beginn, ende, + CASE + WHEN sp.mitarbeiter_kurzbz IS NOT NULL THEN sp.mitarbeiter_kurzbz + ELSE lektor + END as lektor, + CASE + WHEN gruppe_kurzbz IS NOT NULL THEN gruppe_kurzbz + ELSE (SELECT UPPER(typ || kurzbz) + FROM public.tbl_studiengang + WHERE studiengang_kz=sp.studiengang_kz) || COALESCE(sp.semester,'0') || COALESCE(sp.verband,'') || COALESCE(sp.gruppe,'') + END as gruppen_kuerzel, + (SELECT bezeichnung + FROM public.tbl_organisationseinheit + WHERE oe_kurzbz IN( + SELECT oe_kurzbz + FROM lehre.tbl_lehrveranstaltung + WHERE lehrveranstaltung_id = sp.lehrveranstaltung_id + )) as organisationseinheit, + ort_kurzbz, studiengang_kz, titel,lehreinheit_id,lehrfach_id,sp.anmerkung,fix,lehrveranstaltung_id, + stg_kurzbzlang,stg_bezeichnung,stg_typ,fachbereich_kurzbz,lehrfach,lehrfach_bez,farbe,lehrform, + anmerkung_lehreinheit,gruppe, verband, semester,stg_kurzbz, + CONCAT(p.nachname, ' ', p.vorname) as lektorname + + FROM (".$stundenplanViewQuery.") sp + JOIN lehre.tbl_stunde ON lehre.tbl_stunde.stunde = sp.stunde + LEFT JOIN public.tbl_benutzer bn ON bn.uid = sp.uid + LEFT JOIN public.tbl_person p ON p.person_id = bn.person_id + ) as subquery + + GROUP BY unr, datum, beginn, ende, ort_kurzbz, titel, lehrform, lehrfach, lehrfach_bez, organisationseinheit, + farbe, lehrveranstaltung_id + + ORDER BY datum, beginn) t + + GROUP BY + lehrveranstaltung_id, + type, + datum, + topic, + lektor, + lehrfach_bez, + gruppe, + ort_kurzbz, + lehreinheit_id, + lektorname, + gruppen_kuerzel, + farbe + ORDER BY + datum, beginn + " + ); + return $query_result; + } + /** * queries Stundenplan but for a whole lva, irrespective of who is requesting it * @@ -300,10 +392,13 @@ class Stundenplan_model extends DB_Model /** * NO STANDALONE FUNCTION - Generates a SQL query string to fetch 'stundenplan' events for a specific student within the current semester. * + * @param isLvList if condition needed for Tab LV Termine is given + * @param db_stpl_table enables switch to db 'stundenplandev' + * * @return mixed */ - public function getStundenplanQuery($start_date, $end_date,$semester,$gruppen,$studentlehrverbaende){ - + public function getStundenplanQuery($start_date, $end_date, $semester, $gruppen, $studentlehrverbaende, $isLvList=false, $db_stpl_table='stundenplan'){ + // helper function to check if either $gruppen or $studentlehrverbaende are empty for each semester $emptyCheck = function($toBeCheckedArray) use ($semester){ $result = true; @@ -325,7 +420,7 @@ class Stundenplan_model extends DB_Model $query = "select sp.* - from lehre.vw_stundenplan sp + from lehre.vw_".$db_stpl_table." sp WHERE sp.datum >= ".$this->escape($start_date)." AND sp.datum <= ".$this->escape($end_date); @@ -335,10 +430,10 @@ class Stundenplan_model extends DB_Model { $query .= " AND ( "; } - + foreach($semester as $sem => $semester_date_range) { - + foreach($semester_date_range as $sem_date => $sem_date_range) { // if there are not groups for the semester skip the iteration step @@ -358,7 +453,13 @@ class Stundenplan_model extends DB_Model { $query = substr($query, 0, -2); } - + + //Condition for showLVList FHC4 + if(!$isLvList) + $stringGroupLv = "AND gruppe_kurzbz is null"; + else + $stringGroupLv =""; + foreach($semester as $sem=>$semester_date_range) { foreach($semester_date_range as $sem_date => $sem_date_range) @@ -373,10 +474,10 @@ class Stundenplan_model extends DB_Model // Eintraege fuer den ganzen Verband $query .= "OR (sp.studiengang_kz = ".$this->escape($lehrverband->studiengang_kz)." AND sp.semester = ".$this->escape($lehrverband->semester)." AND sp.verband = ".$this->escape($lehrverband->verband)." AND (sp.gruppe is null OR sp.gruppe='') AND sp.datum BETWEEN ".$this->escape($sem_date_range->start)." AND ".$this->escape($sem_date_range->ende).")"; // Eintraege fuer das ganze Semester - $query .= "OR (sp.studiengang_kz = ".$this->escape($lehrverband->studiengang_kz)." AND sp.semester = ".$this->escape($lehrverband->semester)." AND (sp.verband is null OR sp.verband='') AND sp.datum BETWEEN ".$this->escape($sem_date_range->start)." AND ".$this->escape($sem_date_range->ende).") AND gruppe_kurzbz is null)"; - + $query .= "OR (sp.studiengang_kz = ".$this->escape($lehrverband->studiengang_kz)." AND sp.semester = ".$this->escape($lehrverband->semester)." AND (sp.verband is null OR sp.verband='') AND sp.datum BETWEEN ".$this->escape($sem_date_range->start) + ." AND ".$this->escape($sem_date_range->ende).")". $stringGroupLv. ")"; + $query .="OR"; - } } } @@ -421,7 +522,7 @@ class Stundenplan_model extends DB_Model */ public function loadForUid($uid) { - $this->addSelect(['5sp.*','le.studiensemester_kurzbz']); + $this->addSelect(['sp.*','le.studiensemester_kurzbz']); $this->db->join('public.tbl_benutzergruppe bg', 'sp.gruppe_kurzbz=bg.gruppe_kurzbz AND bg.uid=?', 'LEFT', false); $this->addJoin('public.tbl_studiensemester ss1', 'bg.studiensemester_kurzbz=ss1.studiensemester_kurzbz AND ss1.start<=sp.datum AND ss1.ende>=sp.datum', 'LEFT'); $this->db->join('public.tbl_studentlehrverband slv', "sp.studiengang_kz=slv.studiengang_kz AND slv.student_uid=? AND (slv.semester=sp.semester OR sp.semester IS NULL) AND (slv.verband=sp.verband OR sp.verband IS NULL OR sp.verband='' OR sp.verband='0') AND (slv.gruppe=sp.gruppe OR sp.gruppe IS NULL OR sp.gruppe='' OR sp.gruppe='0') AND sp.gruppe_kurzbz IS NULL", 'LEFT', false); @@ -434,5 +535,4 @@ class Stundenplan_model extends DB_Model return $this->execQuery($query, [$uid, $uid]); } - } diff --git a/public/css/Studentenverwaltung.css b/public/css/Studentenverwaltung.css index 1ccac1273..67cff2982 100644 --- a/public/css/Studentenverwaltung.css +++ b/public/css/Studentenverwaltung.css @@ -77,6 +77,10 @@ html { overflow: visible !important; } +.highlight-row { + background-color: #e5aeae !important; +} + @media (min-width: 768px) { #sidebarMenu { visibility: visible!important; diff --git a/public/js/api/stv/courselist.js b/public/js/api/stv/courselist.js index b6035c098..6bd999e5f 100644 --- a/public/js/api/stv/courselist.js +++ b/public/js/api/stv/courselist.js @@ -1,6 +1,15 @@ export default { getCourselist(url, config, params) { - console.log("her"); - return this.$fhcApi.get('api/frontend/v1/stv/Lvtermine/getLvsStudent/' + params.id); + //corresponding logic controller Stundenplan.php + return this.$fhcApi.get('api/frontend/v1/stv/LvTermine/getStundenplan/' + + params.student_uid + '/' + + params.start_date + '/' + + params.end_date + '/' + + params.group_consecutiveHours + '/' + + params.dbStundenplanTable + ); + }, + getStudiensemester(){ + return this.$fhcApi.get('api/frontend/v1/stv/LvTermine/getStudiensemester/'); }, } \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Lehrveranstaltungstermine/ListLehrveranstaltungstermine.js b/public/js/components/Stv/Studentenverwaltung/Details/Lehrveranstaltungstermine/ListLehrveranstaltungstermine.js index 8a6c0d2b0..bc4e02b51 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Lehrveranstaltungstermine/ListLehrveranstaltungstermine.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Lehrveranstaltungstermine/ListLehrveranstaltungstermine.js @@ -1,39 +1,173 @@ import {CoreFilterCmpt} from "../../../../filter/Filter.js"; +import FormInput from "../../../../Form/Input.js"; +import FormForm from '../../../../Form/Form.js'; export default { name: "TblCourseList", components: { - CoreFilterCmpt + CoreFilterCmpt, + FormInput, + FormForm + }, + computed: { + downloadLink: function(){ + if(!this.dataSem.start || !this.dataSem.ende || !this.student.uid) return; + let start = new Date(this.dataSem.start); + start = Math.floor(start.getTime()/1000); + let ende = new Date(this.dataSem.ende); + ende = Math.floor(ende.getTime() / 1000); + + let link = + FHC_JS_DATA_STORAGE_OBJECT.app_root + "cis/private/lvplan/stpl_kalender.php?type=student&pers_uid=" + this.student.uid + "&begin=" + start + "&ende= " +ende + "&format=excel"; + return link; + }, + dbStundenplanTable: function (){ + return this.showStundenplanDev ? 'stundenplandev' : 'stundenplan'; + } + }, + inject: { + currentSemester: { + from: 'currentSemester', + }, }, props: { student: Object }, data(){ return { - tabulatorOptions: { + tabulatorOptions: null, + tabulatorEvents: [], + listStudiensemester: [], + dataSem: {}, + showStundenplanDev: false + }; + }, + methods: { + initTabulatorOptions(){ + this.tabulatorOptions = { ajaxURL: 'dummy', ajaxRequestFunc: this.$fhcApi.factory.stv.courselist.getCourselist, ajaxParams: () => { return { - id: this.student.uid + student_uid: this.student.uid, + start_date: this.dataSem.start, + end_date: this.dataSem.ende, + group_consecutiveHours: true, + dbStundenplanTable: this.dbStundenplanTable }; }, - ajaxResponse: (url, params, response) => response.data, + ajaxResponse: (url, params, response) => { + return response.data; + }, columns: [ - {title: "Prestudent_id", field: "prestudent_id"}, - ] - }, - tabulatorEvents: [], - } + {title: "lv_id", field: "lehrveranstaltung_id", visible: false}, + {title: "lehreinheit_id", field: "lehreinheit_id", 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: "beginn", field: "beginn"}, + {title: "ende", field: "ende"}, + {title: "farbe", field: "farbe", visible: false}, + {title: "Gruppen", field: "gruppen_kuerzel"}, + {title: "ort", field: "ort_kurzbz"}, + {title: "lektorIn", field: "lektorname"}, + {title: "Lehrfach", field: "lehrfach_bez"} + ], + rowFormatter: function(row){ + var data = row.getData(); + //highlight background of row if color red in table + if(data.farbe == "A4A7FC"){ + let el = row.getElement(); + row.getElement().classList.add("highlight-row"); + row.getElement().classList.remove("tabulator-row-odd"); + row.getElement().classList.remove("tabulator-row-even"); + } + } + }; + this.tabulatorEvents = [ + { + event: 'tableBuilt', + handler: async() => { + await this.$p.loadCategory(['global', 'ui', 'lehre']); + + let cm = this.$refs.table.tabulator.columnManager; + + cm.getColumnByField('lehrveranstaltung_id').component.updateDefinition({ + title: this.$p.t('lehre', 'lehrveranstaltung_id') + }); + cm.getColumnByField('lehreinheit_id').component.updateDefinition({ + title: this.$p.t('global', 'lehreinheit_id') + }); + cm.getColumnByField('datum').component.updateDefinition({ + title: this.$p.t('global', 'datum') + }); + cm.getColumnByField('beginn').component.updateDefinition({ + title: this.$p.t('ui', 'dateFrom') + }); + cm.getColumnByField('ende').component.updateDefinition({ + title: this.$p.t('ui', 'dateTo') + }); + cm.getColumnByField('gruppen_kuerzel').component.updateDefinition({ + title: this.$p.t('global', 'gruppen') + }); + cm.getColumnByField('ort_kurzbz').component.updateDefinition({ + title: this.$p.t('global', 'ortLocation') + }); + cm.getColumnByField('lektorname').component.updateDefinition({ + title: this.$p.t('lehre', 'lektor') + }); + cm.getColumnByField('lehrfach_bez').component.updateDefinition({ + title: this.$p.t('global', 'lehrfach') + }); + } + } + ]; + }, + getDatesOfSemester(studiensemester_kurzbz) { + this.dataSem = this.listStudiensemester.find(item => item.studiensemester_kurzbz === studiensemester_kurzbz); + }, + exportToExcel(){ + window.open(this.downloadLink, '_blank'); + }, + reload() { + this.$refs.table.reloadTable(); + }, + switchStundenplan(){ + this.showStundenplanDev = !this.showStundenplanDev; + this.reload(); + } + }, + watch: { + currentSemester(newVal, oldVal) { + this.getDatesOfSemester(newVal); + }, + }, + created(){ + this.$fhcApi.factory.stv.courselist.getStudiensemester() + .then(result => { + this.listStudiensemester = result.data; + this.getDatesOfSemester(this.currentSemester); + this.initTabulatorOptions(); + + }) + .catch(this.$fhcAlert.handleSystemError); }, - methods: {}, template: `
-

Termine

- {{student}} - +

{{$p.t('global', 'termine')}}

+ +
` -} \ No newline at end of file +} diff --git a/system/phrasesupdate.php b/system/phrasesupdate.php index 7d6d7361d..5749562ac 100644 --- a/system/phrasesupdate.php +++ b/system/phrasesupdate.php @@ -41416,6 +41416,186 @@ and represent the current state of research on the topic. The prescribed citatio ) ) ), + array( + 'app' => 'core', + 'category' => 'ui', + 'phrase' => 'export', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Exportieren', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Export', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'lehre', + 'phrase' => 'stundenplanDev', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Stundenplan DEV', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Timetable DEV', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'global', + 'phrase' => 'lehreinheit_id', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Lehreinheit ID', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Teaching Unit ID', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'ui', + 'phrase' => 'dateFrom', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'von', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'from', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'ui', + 'phrase' => 'dateTo', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'bis', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'to', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'global', + 'phrase' => 'gruppen', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Gruppen', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'groups', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'global', + 'phrase' => 'ortLocation', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Ort', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'location', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'global', + 'phrase' => 'lehrfach', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Lehrfach', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'subject', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'global', + 'phrase' => 'termine', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Termine', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Dates', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), // FHC 4 Lehrveranstaltungstermine ENDE --------------------------------------------------------------------------- ); From 2d8766384176f6b736607cc95e2b66924b39961d Mon Sep 17 00:00:00 2001 From: ma0068 Date: Tue, 22 Apr 2025 13:35:31 +0200 Subject: [PATCH 022/107] basic structure for Tab Admission Dates --- .../api/frontend/v1/stv/Aufnahmetermine.php | 506 ++++++++++++++++++ .../api/frontend/v1/stv/Config.php | 5 + public/js/api/factory/stv.js | 4 +- public/js/api/factory/stv/admissionDates.js | 25 + public/js/api/stv/admissionDates.js | 0 .../Details/Aufnahmetermine.js | 26 + .../Aufnahmetermine/Aufnahmetermine.js | 58 ++ .../Aufnahmetermine/HeaderReihungstest.js | 14 + system/phrasesupdate.php | 25 +- 9 files changed, 661 insertions(+), 2 deletions(-) create mode 100644 application/controllers/api/frontend/v1/stv/Aufnahmetermine.php create mode 100644 public/js/api/factory/stv/admissionDates.js create mode 100644 public/js/api/stv/admissionDates.js create mode 100644 public/js/components/Stv/Studentenverwaltung/Details/Aufnahmetermine.js create mode 100644 public/js/components/Stv/Studentenverwaltung/Details/Aufnahmetermine/Aufnahmetermine.js create mode 100644 public/js/components/Stv/Studentenverwaltung/Details/Aufnahmetermine/HeaderReihungstest.js diff --git a/application/controllers/api/frontend/v1/stv/Aufnahmetermine.php b/application/controllers/api/frontend/v1/stv/Aufnahmetermine.php new file mode 100644 index 000000000..519e8125d --- /dev/null +++ b/application/controllers/api/frontend/v1/stv/Aufnahmetermine.php @@ -0,0 +1,506 @@ + ['admin:r', 'assistenz:r'], + 'loadAufnahmetermin' => ['admin:r', 'assistenz:r'], + 'insertAufnahmetermin' => ['admin:rw', 'assistenz:rw'], + 'updateAufnahmetermin' => ['admin:rw', 'assistenz:rw'], + 'deleteAufnahmetermin' => ['admin:rw', 'assistenz:rw'], + ]); + + // Load Libraries + $this->load->library('VariableLib', ['uid' => getAuthUID()]); + $this->load->library('form_validation'); + + // Load language phrases + $this->loadPhrases([ + 'ui', + 'mobility' + ]); + + // Load models + $this->load->model('codex/Bisio_model', 'BisioModel'); + } + + public function getAufnahmetermine($student_uid) + { + $this->BisioModel->addSelect("*"); + $this->BisioModel->addJoin('bis.tbl_mobilitaetsprogramm mp', 'ON (mp.mobilitaetsprogramm_code = bis.tbl_bisio.mobilitaetsprogramm_code)', 'LEFT'); + $this->BisioModel->addJoin('lehre.tbl_lehreinheit le', 'ON (le.lehreinheit_id = bis.tbl_bisio.lehreinheit_id)','LEFT'); + $this->BisioModel->addOrder('von', 'DESC'); + $this->BisioModel->addOrder('bis', 'DESC'); + $this->BisioModel->addOrder('aufnahmetermin_id', 'DESC'); + $result = $this->BisioModel->loadWhere( + array('student_uid' => $student_uid) + ); + + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + + public function insertAufnahmetermin() + { + $this->load->library('form_validation'); + $authUID = getAuthUID(); + + $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); + } + + $formData = $this->input->post('formData'); + + $_POST['von'] = (isset($formData['von']) && !empty($formData['von'])) ? $formData['von'] : null; + $_POST['bis'] = (isset($formData['bis']) && !empty($formData['bis'])) ? $formData['bis'] : null; + $_POST['nation_code'] = (isset($formData['nation_code']) && !empty($formData['nation_code'])) ? $formData['nation_code'] : 'A'; + $_POST['mobilitaetsprogramm_code'] = (isset($formData['mobilitaetsprogramm_code']) && !empty($formData['mobilitaetsprogramm_code'])) ? $formData['mobilitaetsprogramm_code'] : null; + $_POST['herkunftsland_code'] = (isset($formData['herkunftsland_code']) && !empty($formData['herkunftsland_code'])) ? $formData['herkunftsland_code'] : 'A'; + $_POST['ects_erworben'] = (isset($formData['ects_erworben']) && !empty($formData['ects_erworben'])) ? $formData['ects_erworben'] : null; + $_POST['ects_angerechnet'] = (isset($formData['ects_angerechnet']) && !empty($formData['ects_angerechnet'])) ? $formData['ects_angerechnet'] : null; + $_POST['lehreinheit_id'] = (isset($formData['lehreinheit_id']) && !empty($formData['lehreinheit_id'])) ? $formData['lehreinheit_id'] : null; + + $this->form_validation->set_rules('nation_code', 'Nation_code', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Nation_code']) + ]); + $this->form_validation->set_rules('herkunftsland_code', 'Herkunftsland_code', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Herkunftsland_code']) + ]); + $this->form_validation->set_rules('mobilitaetsprogramm_code', 'Mobilitaetsprogramm_code', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Mobilitaetsprogramm_code']) + ]); + $this->form_validation->set_rules('von', 'VonDatum', 'is_valid_date', [ + 'is_valid_date' => $this->p->t('ui', 'error_notValidDate', ['field' => 'VonDatum']) + ]); + + $this->form_validation->set_rules('bis', 'VBisDatum', 'is_valid_date', [ + 'is_valid_date' => $this->p->t('ui', 'error_notValidDate', ['field' => 'VBisDatum']) + ]); + + $this->form_validation->set_rules('ects_erworben', 'Ects_erworben', 'numeric', [ + 'numeric' => $this->p->t('ui', 'error_fieldNotNumeric', ['field' => 'Ects_erworben']) + ]); + + $this->form_validation->set_rules('ects_angerechnet', 'Ects_angerechnet', 'numeric', [ + 'numeric' => $this->p->t('ui', 'error_fieldNotNumeric', ['field' => 'Ects_angerechnet']) + ]); + + $this->form_validation->set_rules('lehreinheit_id', 'Lehreinheit', 'numeric', [ + 'numeric' => $this->p->t('ui', 'error_fieldNotNumeric', ['field' => 'Lehreinheit']) + ]); + + if ($this->form_validation->run() == false) + { + $this->terminateWithValidationErrors($this->form_validation->error_array()); + } + + $ort = (isset($formData['ort']) && !empty($formData['ort'])) ? $formData['ort'] : null; + $universitaet = (isset($formData['universitaet']) && !empty($formData['universitaet'])) ? $formData['universitaet'] : null; + $localPurposes = (isset($formData['localPurposes']) && !empty($formData['localPurposes'])) ? $formData['localPurposes'] : null; + $localSupports = (isset($formData['localSupports']) && !empty($formData['localSupports'])) ? $formData['localSupports'] : null; + + $result = $this->BisioModel->insert([ + 'student_uid' => $student_uid, + 'von' => $_POST['von'], + 'bis' => $_POST['bis'], + 'mobilitaetsprogramm_code' => $_POST['mobilitaetsprogramm_code'], + 'nation_code' => $_POST['nation_code'], + 'herkunftsland_code' => $_POST['herkunftsland_code'], + 'lehreinheit_id' => $_POST['lehreinheit_id'], + 'ort' => $ort, + 'universitaet' => $universitaet, + 'ects_erworben' => $_POST['ects_erworben'] , + 'ects_angerechnet' => $_POST['ects_angerechnet'], + 'insertamum' => date('c'), + 'insertvon' => $authUID, + ]); + + $aufnahmetermin_id = $this->getDataOrTerminateWithError($result); + + //check if localData (purposes) + if(count($localPurposes) > 0){ + foreach ($localPurposes as $zweck){ + $zweck = (int)$zweck; + $this->addAufnahmeterminPurpose($aufnahmetermin_id, $zweck); + } + } + + //check if localData (supports) + if(count($localSupports) > 0){ + foreach ($localSupports as $support){ + $this->addAufnahmeterminSupport($aufnahmetermin_id, $support); + } + } + + $this->terminateWithSuccess($aufnahmetermin_id); + } + + public function loadAufnahmetermin($aufnahmetermin_id) + { + $this->BisioModel->addSelect("*"); + $this->BisioModel->addJoin('bis.tbl_mobilitaetsprogramm mp', 'ON (mp.mobilitaetsprogramm_code = bis.tbl_bisio.mobilitaetsprogramm_code)', 'LEFT'); + $this->BisioModel->addJoin('lehre.tbl_lehreinheit le', 'ON (le.lehreinheit_id = bis.tbl_bisio.lehreinheit_id)','LEFT'); + $result = $this->BisioModel->loadWhere( + array('aufnahmetermin_id' => $aufnahmetermin_id) + ); + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess(current($data)); + } + + public function updateAufnahmetermin() + { + + $this->load->library('form_validation'); + $authUID = getAuthUID(); + + $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); + } + $formData = $this->input->post('formData'); + + $_POST['von'] = (isset($formData['von']) && !empty($formData['von'])) ? $formData['von'] : null; + $_POST['bis'] = (isset($formData['bis']) && !empty($formData['bis'])) ? $formData['bis'] : null; + $_POST['nation_code'] = (isset($formData['nation_code']) && !empty($formData['nation_code'])) ? $formData['nation_code'] : 'A'; + $_POST['mobilitaetsprogramm_code'] = (isset($formData['mobilitaetsprogramm_code']) && !empty($formData['mobilitaetsprogramm_code'])) ? $formData['mobilitaetsprogramm_code'] : null; + $_POST['herkunftsland_code'] = (isset($formData['herkunftsland_code']) && !empty($formData['herkunftsland_code'])) ? $formData['herkunftsland_code'] : 'A'; + $_POST['ects_erworben'] = (isset($formData['ects_erworben']) && !empty($formData['ects_erworben'])) ? $formData['ects_erworben'] : null; + $_POST['ects_angerechnet'] = (isset($formData['ects_angerechnet']) && !empty($formData['ects_angerechnet'])) ? $formData['ects_angerechnet'] : null; + $_POST['lehreinheit_id'] = (isset($formData['lehreinheit_id']) && !empty($formData['lehreinheit_id'])) ? $formData['lehreinheit_id'] : null; + + $this->form_validation->set_rules('nation_code', 'Nation_code', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Nation_code']) + ]); + $this->form_validation->set_rules('herkunftsland_code', 'Herkunftsland_code', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Herkunftsland_code']) + ]); + $this->form_validation->set_rules('mobilitaetsprogramm_code', 'Mobilitaetsprogramm_code', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Mobilitaetsprogramm_code']) + ]); + $this->form_validation->set_rules('von', 'VonDatum', 'is_valid_date', [ + 'is_valid_date' => $this->p->t('ui', 'error_notValidDate', ['field' => 'VonDatum']) + ]); + + $this->form_validation->set_rules('bis', 'VBisDatum', 'is_valid_date', [ + 'is_valid_date' => $this->p->t('ui', 'error_notValidDate', ['field' => 'VBisDatum']) + ]); + + $this->form_validation->set_rules('ects_erworben', 'Ects_erworben', 'numeric', [ + 'numeric' => $this->p->t('ui', 'error_fieldNotNumeric', ['field' => 'Ects_erworben']) + ]); + + $this->form_validation->set_rules('ects_angerechnet', 'Ects_angerechnet', 'numeric', [ + 'numeric' => $this->p->t('ui', 'error_fieldNotNumeric', ['field' => 'Ects_angerechnet']) + ]); + + $this->form_validation->set_rules('lehreinheit_id', 'Lehreinheit', 'numeric', [ + 'numeric' => $this->p->t('ui', 'error_fieldNotNumeric', ['field' => 'Lehreinheit']) + ]); + + if ($this->form_validation->run() == false) + { + $this->terminateWithValidationErrors($this->form_validation->error_array()); + } + + $result = $this->BisioModel->update( + [ + 'aufnahmetermin_id' => $formData['aufnahmetermin_id'] + ], + [ + 'student_uid' => $student_uid, + 'von' => $_POST['von'], + 'bis' => $_POST['bis'], + 'mobilitaetsprogramm_code' => $_POST['mobilitaetsprogramm_code'], + 'nation_code' => $_POST['nation_code'], + 'herkunftsland_code' => $_POST['herkunftsland_code'], + 'lehreinheit_id' => $_POST['lehreinheit_id'], + 'ort' => $formData['ort'], + 'universitaet' => $formData['universitaet'], + 'ects_erworben' => $_POST['ects_erworben'] , + 'ects_angerechnet' => $_POST['ects_angerechnet'], + 'updateamum' => date('c'), + 'updatevon' => $authUID, + ] + ); + + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess(current($data)); + } + + public function deleteAufnahmetermin($aufnahmetermin_id) + { + //check if extension table exists + $result = $this->BisioModel->tableExists('extension', 'tbl_mo_bisioidzuordnung'); + $data = $this->getDataOrTerminateWithError($result); + + //if table exists check if existing entry + if(!empty($data)) + { + $this->BisioModel->addSelect("count(*)"); + $this->BisioModel->addJoin('extension.tbl_mo_bisioidzuordnung mo', 'ON (mo.aufnahmetermin_id = bis.tbl_bisio.aufnahmetermin_id)', 'LEFT'); + + $resultCheckMo = $this->BisioModel->loadWhere( + array('mo.aufnahmetermin_id' => $aufnahmetermin_id) + ); + + $resultCheckMo = $this->getDataOrTerminateWithError($resultCheckMo); + $count = current($resultCheckMo)->count; + + $existsInExtension = $count > 0 ? true : false; + + if($existsInExtension) + $this->terminateWithError($this->p->t('mobility', 'error_existingEntryInExtension'), self::ERROR_TYPE_GENERAL); + } + + $result = $this->BisioModel->delete( + array('aufnahmetermin_id' => $aufnahmetermin_id) + ); + + $data = $this->getDataOrTerminateWithError($result); + $this->terminateWithSuccess($data); + } + + public function getLVList($studiengang_kz) + { + $this->load->model('education/Lehrveranstaltung_model', 'LehrveranstaltungModel'); + + $result = $this->LehrveranstaltungModel->getLvsByStudiengangkz($studiengang_kz); + + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + + public function getAllLehreinheiten() + { + $lv_id = $this->input->post('lv_id'); + $studiensemester_kurzbz = $this->input->post('studiensemester_kurzbz'); + + $this->load->model('education/Lehreinheit_model', 'LehreinheitModel'); + + $result = $this->LehreinheitModel->getLesFromLvIds($lv_id, $studiensemester_kurzbz); + + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + + public function getLvsandLesByStudent($student_uid) + { + $this->load->model('education/Lehrveranstaltung_model', 'LehrveranstaltungModel'); + + $result = $this->LehrveranstaltungModel->getLvsByStudent($student_uid); + + $data = $this->getDataOrTerminateWithError($result); + + $lv_ids = array(); + $allData = array(); + + foreach ($data as $lehrveranstaltung) { + $lv_ids[] = $lehrveranstaltung->lehrveranstaltung_id; + } + + $this->load->model('education/Lehreinheit_model', 'LehreinheitModel'); + + foreach ($lv_ids as $id) + { + $result = $this->LehreinheitModel->getLesFromLvIds($id); + $data = $this->getDataOrTerminateWithError($result); + + if (is_array($data)) { + $allData = array_merge($allData, $data); + } + } + + return $this->terminateWithSuccess($allData); + } + + public function getPurposes($aufnahmetermin_id) + { + $aufnahmetermin_id = (int)$aufnahmetermin_id; + + $this->load->model('codex/Bisiozweck_model', 'BisiozweckModel'); + + $this->BisiozweckModel->addSelect("*"); + $this->BisiozweckModel->addJoin('bis.tbl_zweck zw', 'ON (zw.zweck_code = bis.tbl_bisio_zweck.zweck_code)'); + + $result = $this->BisiozweckModel->loadWhere( + array('aufnahmetermin_id' => $aufnahmetermin_id) + ); + + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + + public function getSupports($aufnahmetermin_id) + { + $aufnahmetermin_id = (int)$aufnahmetermin_id; + + $this->load->model('codex/Bisioaufenthaltfoerderung_model', 'BisioaufenthaltfoerderungModel'); + + $this->BisioaufenthaltfoerderungModel->addSelect("*"); + $this->BisioaufenthaltfoerderungModel->addJoin('bis.tbl_aufenthaltfoerderung af', 'ON (af.aufenthaltfoerderung_code = bis.tbl_bisio_aufenthaltfoerderung.aufenthaltfoerderung_code)'); + + $result = $this->BisioaufenthaltfoerderungModel->loadWhere( + array('aufnahmetermin_id' => $aufnahmetermin_id) + ); + + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + + public function getListPurposes() + { + $this->load->model('codex/Zweck_model', 'ZweckModel'); + + $result = $this->ZweckModel->load(); + + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + + public function getListSupports() + { + $this->load->model('codex/Aufenthaltfoerderung_model', 'AufenthaltfoerderungModel'); + + $result = $this->AufenthaltfoerderungModel->load(); + + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + + public function addAufnahmeterminPurpose($aufnahmetermin_id, $local_purpose = null) + { + $zweck_code = $this->input->post('zweck_code'); + + if($local_purpose){ + $zweck_code = $local_purpose; + } + + $this->load->model('codex/Bisiozweck_model', 'BisiozweckModel'); + if(!$local_purpose) + { + $check = $this->BisiozweckModel->loadWhere( + [ + 'aufnahmetermin_id' => $aufnahmetermin_id, + 'zweck_code' => $zweck_code, + ] + ); + if (hasData($check)) + { + $this->terminateWithError($this->p->t('ui', 'error_entryExisting'), self::ERROR_TYPE_GENERAL); + } + } + + $result = $this->BisiozweckModel->insert( + array( + 'aufnahmetermin_id' => $aufnahmetermin_id, + 'zweck_code' => $zweck_code + ) + ); + + $data = $this->getDataOrTerminateWithError($result); + + if($local_purpose) + { + return $data; + } + + return $this->terminateWithSuccess(current($data)); + } + + public function deleteAufnahmeterminPurpose($aufnahmetermin_id) + { + $zweck_code = $this->input->post('zweck_code'); + + $this->load->model('codex/Bisiozweck_model', 'BisiozweckModel'); + + + $result = $this->BisiozweckModel->delete( + array( + 'aufnahmetermin_id' => $aufnahmetermin_id, + 'zweck_code' => $zweck_code + ) + ); + + $data = $this->getDataOrTerminateWithError($result); + + return $this->terminateWithSuccess(current($data)); + } + + public function addAufnahmeterminSupport($aufnahmetermin_id, $local_support = null) + { + $aufenthaltfoerderung_code = $this->input->post('aufenthaltfoerderung_code'); + + if($local_support){ + $aufenthaltfoerderung_code = $local_support; + } + + $this->load->model('codex/Bisioaufenthaltfoerderung_model', 'BisioaufenthaltfoerderungModel'); + + if(!$local_support) + { + $check = $this->BisioaufenthaltfoerderungModel->loadWhere( + [ + 'aufnahmetermin_id' => $aufnahmetermin_id, + 'aufenthaltfoerderung_code' => $aufenthaltfoerderung_code, + ] + ); + if (hasData($check)) + { + $this->terminateWithError($this->p->t('ui', 'error_entryExisting'), self::ERROR_TYPE_GENERAL); + } + } + + $result = $this->BisioaufenthaltfoerderungModel->insert( + array( + 'aufnahmetermin_id' => $aufnahmetermin_id, + 'aufenthaltfoerderung_code' => $aufenthaltfoerderung_code + ) + ); + + $data = $this->getDataOrTerminateWithError($result); + + if($local_support) + { + return $data; + } + + return $this->terminateWithSuccess(current($data)); + } + + public function deleteAufnahmeterminSupport($aufnahmetermin_id) + { + $aufenthaltfoerderung_code = $this->input->post('aufenthaltfoerderung_code'); + + $this->load->model('codex/Bisioaufenthaltfoerderung_model', 'BisioaufenthaltfoerderungModel'); + + $result = $this->BisioaufenthaltfoerderungModel->delete( + array( + 'aufnahmetermin_id' => $aufnahmetermin_id, + 'aufenthaltfoerderung_code' => $aufenthaltfoerderung_code + ) + ); + $data = $this->getDataOrTerminateWithError($result); + + return $this->terminateWithSuccess(current($data)); + } +} diff --git a/application/controllers/api/frontend/v1/stv/Config.php b/application/controllers/api/frontend/v1/stv/Config.php index 42de1b02f..f65daf627 100644 --- a/application/controllers/api/frontend/v1/stv/Config.php +++ b/application/controllers/api/frontend/v1/stv/Config.php @@ -128,6 +128,11 @@ class Config extends FHCAPI_Controller 'component' => './Stv/Studentenverwaltung/Details/Mobility.js' ]; + $result['admissionDates'] = [ + 'title' => $this->p->t('stv', 'tab_admissionDates'), + 'component' => './Stv/Studentenverwaltung/Details/Aufnahmetermine.js' + ]; + Events::trigger('stv_conf_student', function & () use (&$result) { return $result; }); diff --git a/public/js/api/factory/stv.js b/public/js/api/factory/stv.js index 7ea387263..95bc227f5 100644 --- a/public/js/api/factory/stv.js +++ b/public/js/api/factory/stv.js @@ -29,6 +29,7 @@ import exam from './stv/exam.js'; import abschlusspruefung from './stv/abschlusspruefung.js'; import grades from './stv/grades.js'; import mobility from './stv/mobility.js'; +import admissionDates from './stv/admissionDates.js'; export default { app, @@ -44,5 +45,6 @@ export default { exam, abschlusspruefung, grades, - mobility + mobility, + admissionDates }; \ No newline at end of file diff --git a/public/js/api/factory/stv/admissionDates.js b/public/js/api/factory/stv/admissionDates.js new file mode 100644 index 000000000..fc96f47be --- /dev/null +++ b/public/js/api/factory/stv/admissionDates.js @@ -0,0 +1,25 @@ +/** + * 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 { + getAufnahmetermine(prestudent_id) { + return { + method: 'get', + url: 'api/frontend/v1/stv/aufnahmetermine/' + prestudent_id + }; + }, +} \ No newline at end of file diff --git a/public/js/api/stv/admissionDates.js b/public/js/api/stv/admissionDates.js new file mode 100644 index 000000000..e69de29bb diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Aufnahmetermine.js b/public/js/components/Stv/Studentenverwaltung/Details/Aufnahmetermine.js new file mode 100644 index 000000000..4ad8c6002 --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Details/Aufnahmetermine.js @@ -0,0 +1,26 @@ +import AdmissionDates from "./Aufnahmetermine/Aufnahmetermine.js"; +import HeaderPlacement from "./Aufnahmetermine/HeaderReihungstest.js"; + +export default { + name: "TabAdmissionDates", + components: { + AdmissionDates, + HeaderPlacement + }, + provide() { + return { + config: this.config + }; + }, + props: { + modelValue: Object, + }, + data(){ + return {} + }, + template: ` +
+ + +
` +}; \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Aufnahmetermine/Aufnahmetermine.js b/public/js/components/Stv/Studentenverwaltung/Details/Aufnahmetermine/Aufnahmetermine.js new file mode 100644 index 000000000..58f440836 --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Details/Aufnahmetermine/Aufnahmetermine.js @@ -0,0 +1,58 @@ +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 ApiStvAdmissionDates from '../../../../../api/factory/stv/admissionDates'; + +export default { + name: 'ListAdmissionDates', + components: { + CoreFilterCmpt, + BsModal, + FormForm, + FormInput + }, + inject: { + $reloadList: { + from: '$reloadList', + required: true + }, + }, + props: { + student: Object + }, + data() { + return { + tabulatorOptions: { + ajaxURL: 'dummy', + ajaxRequestFunc: () => this.$api.call( + ApiStvAdmissionDates.getAufnahmetermin(this.student.prestudent_id) + ), + ajaxResponse: (url, params, response) => response.data, + columns: [ + {title: "aufnahmetermin_id", field: "aufnahmetermin_id"}, + {title: "prestudent_id", field: "prestudent_id"}, + ], + layout: 'fitDataFill', + layoutColumnsOnNewData: false, + height: 'auto', + minHeight: 200, + index: 'aufnahmetermin_id', + persistenceID: 'stv-details-table_admission-dates' + }, + tabulatorEvents: [], + formData: {}, + statusNew: true, + } + }, + methods: {}, + created() { + }, + template: ` +
+

Allgemein

+ +
+ ` +} diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Aufnahmetermine/HeaderReihungstest.js b/public/js/components/Stv/Studentenverwaltung/Details/Aufnahmetermine/HeaderReihungstest.js new file mode 100644 index 000000000..529979b3c --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Details/Aufnahmetermine/HeaderReihungstest.js @@ -0,0 +1,14 @@ +export default { + name: 'HeaderPlacement', + data(){ + return { + statusNew: true, + } + }, + template: ` +
+

Studiengang

+ +
+ ` +} \ No newline at end of file diff --git a/system/phrasesupdate.php b/system/phrasesupdate.php index cd17215ee..fd54d9f66 100644 --- a/system/phrasesupdate.php +++ b/system/phrasesupdate.php @@ -41393,8 +41393,31 @@ and represent the current state of research on the topic. The prescribed citatio 'insertvon' => 'system' ) ) - ) + ), // PROJEKTARBEITSBEURTEILUNG SS2025 ENDE --------------------------------------------------------------------------- + // FHC4 STUDIERENDENVERWALTUNG AUFNAHMETERMINE START --------------------------------------------------------------- + array( + 'app' => 'core', + 'category' => 'stv', + 'phrase' => 'tab_admissionDates', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Aufnahmetermine', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Admission Dates', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + // FHC4 STUDIERENDENVERWALTUNG AUFNAHMETERMINE ENDE --------------------------------------------------------------- + ); From 08b27edd648762142c1bfc4c0021dbd648f31edb Mon Sep 17 00:00:00 2001 From: ma0068 Date: Tue, 22 Apr 2025 14:29:45 +0200 Subject: [PATCH 023/107] Refactoring FhcApi_Factory --- public/js/api/factory/stv/group.js | 33 +++++++++++++++++++ .../Details/Gruppen/Gruppen.js | 14 ++++---- 2 files changed, 40 insertions(+), 7 deletions(-) create mode 100644 public/js/api/factory/stv/group.js diff --git a/public/js/api/factory/stv/group.js b/public/js/api/factory/stv/group.js new file mode 100644 index 000000000..b395fbf43 --- /dev/null +++ b/public/js/api/factory/stv/group.js @@ -0,0 +1,33 @@ +/** + * 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 { + getGruppen(id) { + return { + method: 'get', + url: 'api/frontend/v1/stv/Gruppen/getGruppen/' + id + }; + }, + deleteGroup(params) { + return { + method: 'post', + url: 'api/frontend/v1/stv/Gruppen/deleteGruppe/', + params + }; + } +} + diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Gruppen/Gruppen.js b/public/js/components/Stv/Studentenverwaltung/Details/Gruppen/Gruppen.js index 6434f9fa8..67f422efb 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Gruppen/Gruppen.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Gruppen/Gruppen.js @@ -1,5 +1,7 @@ import {CoreFilterCmpt} from "../../../../filter/Filter.js"; +import ApiStvGroups from '../../../../../api/factory/stv/group.js'; + export default { name: 'TblGroups', components: { @@ -17,12 +19,9 @@ export default { return { tabulatorOptions: { ajaxURL: 'dummy', - ajaxRequestFunc: this.$fhcApi.factory.stv.group.getGruppen, - ajaxParams: () => { - return { - id: this.student.uid - }; - }, + ajaxRequestFunc: () => this.$api.call( + ApiStvGroups.getGruppen(this.student.uid) + ), ajaxResponse: (url, params, response) => response.data, initialFilter: [ {field: "uid", type: "=", value: this.student.uid}, @@ -130,7 +129,8 @@ export default { gruppe_kurzbz: gruppe_kurzbz }; - return this.$fhcApi.factory.stv.group.deleteGroup(group_id) + return this.$api + .call(ApiStvGroups.deleteGroup(group_id)) .then(response => { this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successDelete')); }).catch(this.$fhcAlert.handleSystemError) From 65c398498fc538df8e93e543cb01b45a6a412ce6 Mon Sep 17 00:00:00 2001 From: ma0068 Date: Wed, 23 Apr 2025 09:32:49 +0200 Subject: [PATCH 024/107] Refactoring FhcApi_Factory View Modal --- public/js/api/factory/messages/messages.js | 112 ++++++++++++++++++ public/js/api/messages/person.js | 4 +- .../Messages/Details/NewMessage/Modal.js | 47 +++++--- .../Messages/Details/NewMessage/NewDiv.js | 45 ++++--- .../Messages/Details/TableMessages.js | 42 ++++--- 5 files changed, 201 insertions(+), 49 deletions(-) create mode 100644 public/js/api/factory/messages/messages.js diff --git a/public/js/api/factory/messages/messages.js b/public/js/api/factory/messages/messages.js new file mode 100644 index 000000000..8424e14f2 --- /dev/null +++ b/public/js/api/factory/messages/messages.js @@ -0,0 +1,112 @@ +/** + * 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 { + //TODO(manu) check how to get params size and page + getMessages(params) { + console.log('page ' + params.page + ' size ' + params.size); + return { + method: 'get', + url: 'api/frontend/v1/messages/messages/getMessages/' + + params.id + '/' + + params.type + '/' + + params.size + '/' + + params.page + }; + }, + getVorlagen(){ + return { + method: 'get', + url: 'api/frontend/v1/messages/messages/getVorlagen/' + }; + }, + getMsgVarsLoggedInUser(){ + return { + method: 'get', + url: 'api/frontend/v1/messages/messages/getMsgVarsLoggedInUser/' + }; + }, + getMessageVarsPerson(userParams){ + return { + method: 'post', + url: 'api/frontend/v1/messages/messages/getMessageVarsPerson/' + userParams.id + '/' + userParams.type_id + }; + }, + getMsgVarsPrestudent(userParams){ + return { + method: 'post', + url: 'api/frontend/v1/messages/messages/getMsgVarsPrestudent/' + userParams.id + '/' + userParams.type_id + }; + }, + getPersonId(params){ + return { + method: 'post', + url: 'api/frontend/v1/messages/messages/getPersonId/' + params.id + '/' + params.type_id + }; + }, + getUid(userParams){ + return { + method: 'get', + url: 'api/frontend/v1/messages/messages/getUid/' + userParams.id + '/' + userParams.type_id + }; + }, + getVorlagentext(vorlage_kurzbz){ + return { + method: 'get', + url: 'api/frontend/v1/messages/messages/getVorlagentext/' + vorlage_kurzbz + }; + }, + getNameOfDefaultRecipient(params){ + return { + method: 'get', + url: 'api/frontend/v1/messages/messages/getNameOfDefaultRecipient/' + params.id + '/' + params.type_id + }; + }, + getPreviewText(userParams, params){ + return { + method: 'post', + url: 'api/frontend/v1/messages/messages/getPreviewText/' + userParams.id + '/' + userParams.type_id, + params + }; + }, + getReplyData(messageId){ + return { + method: 'get', + url: 'api/frontend/v1/messages/messages/getReplyData/' + messageId + }; + }, + sendMessageFromModalContext(id, params) { + return { + method: 'post', + url: 'api/frontend/v1/messages/messages/sendMessage/' + id, + params + }; + }, + sendMessage(id, params) { + return { + method: 'post', + url: 'api/frontend/v1/messages/messages/sendMessage/' + id, + params + }; + }, + deleteMessage(messageId){ + return { + method: 'post', + url: 'api/frontend/v1/messages/messages/deleteMessage/' + messageId + }; + } +} \ No newline at end of file diff --git a/public/js/api/messages/person.js b/public/js/api/messages/person.js index 9bfae6f38..f41050770 100644 --- a/public/js/api/messages/person.js +++ b/public/js/api/messages/person.js @@ -3,7 +3,7 @@ export default { console.log('page ' + params.page + ' size ' + params.size); return this.$fhcApi.get('api/frontend/v1/messages/messages/getMessages/' + params.id + '/' + params.type + '/' + params.size + '/' + params.page); }, - getVorlagen(){ +/* getVorlagen(){ return this.$fhcApi.get('api/frontend/v1/messages/messages/getVorlagen/'); }, getMsgVarsLoggedInUser(){ @@ -44,5 +44,5 @@ export default { }, deleteMessage(messageId){ return this.$fhcApi.post('api/frontend/v1/messages/messages/deleteMessage/' + messageId); - } + }*/ } \ No newline at end of file diff --git a/public/js/components/Messages/Details/NewMessage/Modal.js b/public/js/components/Messages/Details/NewMessage/Modal.js index 33698f1c8..5bbf29f16 100644 --- a/public/js/components/Messages/Details/NewMessage/Modal.js +++ b/public/js/components/Messages/Details/NewMessage/Modal.js @@ -4,6 +4,8 @@ import FormInput from '../../../Form/Input.js'; import ListBox from "../../../../../../index.ci.php/public/js/components/primevue/listbox/listbox.esm.min.js"; import DropdownComponent from "../../../VorlagenDropdown/VorlagenDropdown.js"; +import ApiMessages from '../../../../api/factory/messages/messages.js'; + export default { name: "ModalNewMessages", components: { @@ -104,10 +106,8 @@ export default { }; data.append('data', JSON.stringify(merged)); - return this.$fhcApi.factory.messages.person.sendMessageFromModalContext( - this.$refs.formMessage, - this.uid, - data) + return this.$refs.formMessage + .call(ApiMessages.sendMessageFromModalContext(this.uid, data)) .then(response => { this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSent')); this.hideModal('modalNewMessage'); @@ -122,7 +122,8 @@ export default { ); }, getVorlagentext(vorlage_kurzbz){ - return this.$fhcApi.factory.messages.person.getVorlagentext(vorlage_kurzbz) + return this.$api + .call(ApiMessages.getVorlagentext(vorlage_kurzbz)) .then(response => { this.formData.body = response.data; }).catch(this.$fhcAlert.handleSystemError) @@ -136,9 +137,10 @@ export default { const data = new FormData(); data.append('data', JSON.stringify(this.formData.body)); - return this.$fhcApi.factory.messages.person.getPreviewText({ - id: this.id, - type_id: this.typeId}, data) + return this.$api + .call(ApiMessages.getPreviewText({ + id: this.id, + type_id: this.typeId}, data)) .then(response => { this.previewText = response.data; }).catch(this.$fhcAlert.handleSystemError) @@ -200,7 +202,8 @@ export default { id: id, type_id: typeId }; - this.$fhcApi.factory.messages.person.getUid(params) + this.$api + .call(ApiMessages.getUid(params)) .then(result => { this.uid = result.data; }) @@ -238,9 +241,9 @@ export default { if (!newMessageId) return; try { - const result = await this.$fhcApi.factory.messages.person.getReplyData(newMessageId); + //const result = await this.$fhcApi.factory.messages.person.getReplyData(newMessageId); + const result = await this.$api.call(ApiMessages.getReplyData(newMessageId)); this.replyData = result.data; - console.log(this.replyData); if (this.replyData.length > 0) { this.formData.subject = this.replyData[0].replySubject; @@ -261,7 +264,9 @@ export default { id: this.id, type_id: this.typeId }; - this.$fhcApi.factory.messages.person.getMessageVarsPerson(params) + //this.$fhcApi.factory.messages.person.getMessageVarsPerson(params) + this.$api + .call(ApiMessages.getMessageVarsPerson(params)) .then(result => { this.fieldsPerson = result.data; const person = this.fieldsPerson[0]; @@ -278,7 +283,8 @@ export default { id: this.id, type_id: this.typeId }; - this.$fhcApi.factory.messages.person.getMsgVarsPrestudent(params) + this.$api + .call(ApiMessages.getMsgVarsPrestudent(params)) .then(result => { this.fieldsPrestudent = result.data; const prestudent = this.fieldsPrestudent[0]; @@ -290,7 +296,8 @@ export default { .catch(this.$fhcAlert.handleSystemError); } - this.$fhcApi.factory.messages.person.getMsgVarsLoggedInUser() + this.$api + .call(ApiMessages.getMsgVarsLoggedInUser()) .then(result => { this.fieldsUser = result.data; const user = this.fieldsUser; @@ -301,9 +308,10 @@ export default { }) .catch(this.$fhcAlert.handleSystemError); - this.$fhcApi.factory.messages.person.getNameOfDefaultRecipient({ - id: this.id, - type_id: this.typeId}) + this.$api + .call(ApiMessages.getNameOfDefaultRecipient({ + id: this.id, + type_id: this.typeId})) .then(result => { this.defaultRecipient = result.data; this.recipientsArray.push({ @@ -314,7 +322,8 @@ export default { //case of reply if(this.messageId) { - this.$fhcApi.factory.messages.person.getReplyData(this.messageId) + this.$api + .call(ApiMessages.getReplyData(this.messageId)) .then(result => { this.replyData = result.data; this.formData.subject = this.replyData[0].replySubject; @@ -380,7 +389,7 @@ export default { :label="$p.t('global','nachricht') + ' *'" type="textarea" v-model="formData.body" - name="text" + name="body" rows="15" cols="75" > diff --git a/public/js/components/Messages/Details/NewMessage/NewDiv.js b/public/js/components/Messages/Details/NewMessage/NewDiv.js index d8db657df..11335ed2a 100644 --- a/public/js/components/Messages/Details/NewMessage/NewDiv.js +++ b/public/js/components/Messages/Details/NewMessage/NewDiv.js @@ -2,6 +2,7 @@ import FormForm from '../../../Form/Form.js'; import FormInput from '../../../Form/Input.js'; import ListBox from "../../../../../../index.ci.php/public/js/components/primevue/listbox/listbox.esm.min.js"; import DropdownComponent from '../../../VorlagenDropdown/VorlagenDropdown.js'; +import ApiMessages from "../../../../api/factory/messages/messages"; export default { name: "ComponentNewMessages", @@ -119,9 +120,11 @@ export default { data.append('data', JSON.stringify(merged)); //this.uid is necessary for existing sendFunction - return this.$fhcApi.factory.messages.person.sendMessage( +/* return this.$fhcApi.factory.messages.person.sendMessage( this.uid, - data) + data)*/ + return this.$api + .call(ApiMessages.sendMessage(this.uid, data)) .then(response => { this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSent')); this.hideTemplate(); @@ -140,7 +143,9 @@ export default { ); }, getVorlagentext(vorlage_kurzbz){ - return this.$fhcApi.factory.messages.person.getVorlagentext(vorlage_kurzbz) + // return this.$fhcApi.factory.messages.person.getVorlagentext(vorlage_kurzbz) + return this.$api + .call(ApiMessages.getVorlagentext(vorlage_kurzbz)) .then(response => { this.formData.body = response.data; }).catch(this.$fhcAlert.handleSystemError) @@ -152,9 +157,13 @@ export default { const data = new FormData(); data.append('data', JSON.stringify(this.formData.body)); - return this.$fhcApi.factory.messages.person.getPreviewText({ +/* return this.$fhcApi.factory.messages.person.getPreviewText({ id: id, - type_id: typeId}, data) + type_id: typeId}, data)*/ + return this.$api + .call(ApiMessages.getPreviewText({ + id: this.id, + type_id: this.typeId}, data)) .then(response => { this.previewText = response.data; }).catch(this.$fhcAlert.handleSystemError) @@ -226,7 +235,8 @@ export default { id: id, type_id: typeId }; - this.$fhcApi.factory.messages.person.getUid(params) + this.$api + .call(ApiMessages.getUid(params)) .then(result => { this.uid = result.data; }) @@ -262,7 +272,9 @@ export default { id: this.id, type_id: this.typeId }; - this.$fhcApi.factory.messages.person.getMessageVarsPerson(params) + // this.$fhcApi.factory.messages.person.getMessageVarsPerson(params) + this.$api + .call(ApiMessages.getMessageVarsPerson(params)) .then(result => { this.fieldsPerson = result.data; const person = this.fieldsPerson[0]; @@ -279,7 +291,9 @@ export default { id: this.id, type_id: this.typeId }; - this.$fhcApi.factory.messages.person.getMsgVarsPrestudent(params) + //this.$fhcApi.factory.messages.person.getMsgVarsPrestudent(params) + this.$api + .call(ApiMessages.getMsgVarsPrestudent(params)) .then(result => { this.fieldsPrestudent = result.data; const prestudent = this.fieldsPrestudent[0]; @@ -292,7 +306,8 @@ export default { .catch(this.$fhcAlert.handleSystemError); } - this.$fhcApi.factory.messages.person.getMsgVarsLoggedInUser() + this.$api + .call(ApiMessages.getMsgVarsLoggedInUser()) .then(result => { this.fieldsUser = result.data; const user = this.fieldsUser; @@ -303,10 +318,11 @@ export default { }) .catch(this.$fhcAlert.handleSystemError); - this.$fhcApi.factory.messages.person.getNameOfDefaultRecipient({ - id: this.id, - type_id: this.typeId - }).then(result => { + this.$api + .call(ApiMessages.getNameOfDefaultRecipient({ + id: this.id, + type_id: this.typeId})) + .then(result => { this.defaultRecipient = result.data; this.recipientsArray.push({ 'uid': this.uid, @@ -316,7 +332,8 @@ export default { //case of reply if(this.messageId != null) { - this.$fhcApi.factory.messages.person.getReplyData(this.messageId) + this.$api + .call(ApiMessages.getReplyData(this.messageId)) .then(result => { this.replyData = result.data; this.formData.subject = this.replyData[0].replySubject; diff --git a/public/js/components/Messages/Details/TableMessages.js b/public/js/components/Messages/Details/TableMessages.js index 9047d6726..07fdd8f20 100644 --- a/public/js/components/Messages/Details/TableMessages.js +++ b/public/js/components/Messages/Details/TableMessages.js @@ -1,6 +1,8 @@ import {CoreFilterCmpt} from "../../filter/Filter.js"; import FormForm from '../../Form/Form.js'; +import ApiMessages from '../../../api/factory/messages/messages.js'; + export default { name: "TableMessages", components: { @@ -27,8 +29,20 @@ export default { }, data(){ return { +/* paginationSize: 15, + paginationInitialPage: 1,*/ tabulatorOptions: { ajaxURL: 'dummy', + //TODO(Manu) how to handle size and page? +/* ajaxRequestFunc: () => this.$api.call( + ApiMessages.getMessages({ + id: this.id, + type: this.typeId, + size: this.paginationSize, + page: this.paginationInitialPage + }) + ),*/ + //OLD WORKING VERSION ajaxRequestFunc: this.$fhcApi.factory.messages.person.getMessages, ajaxParams: () => { return { @@ -36,6 +50,7 @@ export default { type: this.typeId }; }, + ajaxResponse: (url, params, response) => this.buildTreemap(response), //ajaxResponse: (url, params, response) => this.buildTreemap(response.data), columns: [ @@ -222,7 +237,8 @@ export default { .catch(this.$fhcAlert.handleSystemError); }, deleteMessage(message_id){ - return this.$fhcApi.factory.messages.person.deleteMessage(message_id) + return this.$api + .call(ApiMessages.deleteMessage(message_id)) .then(response => { this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successDelete')); }).catch(this.$fhcAlert.handleSystemError) @@ -276,13 +292,11 @@ export default { } }); - // to avoid endless loop - if (iteration > messages.length) break; - } - return {data: messageNested, last_page}; -} - - + // to avoid endless loop + if (iteration > messages.length) break; + } + return {data: messageNested, last_page}; + } }, computed: { statusText(){ @@ -310,11 +324,12 @@ export default { id: this.id, type_id: this.typeId }; - this.$fhcApi.factory.messages.person.getPersonId(params) - .then(result => { - this.personId = result.data; - }) - .catch(this.$fhcAlert.handleSystemError); + this.$api + .call(ApiMessages.getPersonId(params)) + .then(result => { + this.personId = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); } }, template: ` @@ -353,7 +368,6 @@ export default {
-
From 3200a94d17bfc4c87c3d98e845e8449b9aafd4f9 Mon Sep 17 00:00:00 2001 From: ma0068 Date: Wed, 23 Apr 2025 11:06:08 +0200 Subject: [PATCH 025/107] Refactoring FhcApi_Factory --- public/js/api/factory/stv/jointstudies.js | 81 +++++++++++++++++++ .../Details/JointStudies/JointStudies.js | 42 ++++++---- 2 files changed, 107 insertions(+), 16 deletions(-) create mode 100644 public/js/api/factory/stv/jointstudies.js diff --git a/public/js/api/factory/stv/jointstudies.js b/public/js/api/factory/stv/jointstudies.js new file mode 100644 index 000000000..18f398bb4 --- /dev/null +++ b/public/js/api/factory/stv/jointstudies.js @@ -0,0 +1,81 @@ +/** + * 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 { + getStudies(uid) { + return { + method: 'get', + url: 'api/frontend/v1/stv/GemeinsameStudien/getStudien/' + uid + }; + }, + getTypenMobility(){ + return { + method: 'get', + url: 'api/frontend/v1/stv/GemeinsameStudien/getTypenMobility/' + }; + }, + getStudiensemester(){ + return { + method: 'get', + url: 'api/frontend/v1/stv/GemeinsameStudien/getStudiensemester/' + }; + }, + getStudyprograms(){ + return { + method: 'get', + url: 'api/frontend/v1/stv/GemeinsameStudien/getStudienprogramme/' + }; + }, + getListPartner(){ + return { + method: 'get', + url: 'api/frontend/v1/stv/GemeinsameStudien/getPartnerfirmen/' + }; + }, + getStatiPrestudent(){ + return { + method: 'get', + url: 'api/frontend/v1/stv/GemeinsameStudien/getStatiPrestudent/' + }; + }, + loadStudy(id){ + return { + method: 'get', + url: 'api/frontend/v1/stv/GemeinsameStudien/loadStudie/' + id + }; + }, + insertStudy(params){ + return { + method: 'post', + url: 'api/frontend/v1/stv/GemeinsameStudien/insertStudie/', + params + }; + }, + updateStudy(params){ + return { + method: 'post', + url: 'api/frontend/v1/stv/GemeinsameStudien/updateStudie/', + params + }; + }, + deleteStudy(id){ + return { + method: 'post', + url: 'api/frontend/v1/stv/GemeinsameStudien/deleteStudie/' + id + }; + }, +} diff --git a/public/js/components/Stv/Studentenverwaltung/Details/JointStudies/JointStudies.js b/public/js/components/Stv/Studentenverwaltung/Details/JointStudies/JointStudies.js index 1c75486de..16d1593d3 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/JointStudies/JointStudies.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/JointStudies/JointStudies.js @@ -3,6 +3,9 @@ import BsModal from "../../../../Bootstrap/Modal.js"; import FormForm from "../../../../Form/Form.js"; import FormInput from "../../../../Form/Input.js"; +import ApiStvJointstudies from '../../../../../api/factory/stv/jointstudies.js'; +import ApiStvMobility from "../../../../../api/factory/stv/mobility"; + export default { name: 'Tbl_JointStudies', components: { @@ -23,12 +26,9 @@ export default { return { tabulatorOptions: { ajaxURL: 'dummy', - ajaxRequestFunc: this.$fhcApi.factory.stv.jointstudies.getStudies, - ajaxParams: () => { - return { - id: this.student.prestudent_id - }; - }, + ajaxRequestFunc: () => this.$api.call( + ApiStvJointstudies.getStudies(this.student.prestudent_id) + ), ajaxResponse: (url, params, response) => response.data, columns: [ {title: "mobilitaet_id", field: "mobilitaet_id", visible: false}, @@ -217,7 +217,8 @@ export default { prestudent_id: this.student.prestudent_id, formData: this.formData }; - return this.$fhcApi.factory.stv.jointstudies.insertStudy(this.$refs.formJointStudies, data) + return this.$refs.formJointStudies + .call(ApiStvJointstudies.insertStudy(data)) .then(response => { this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSave')); this.hideModal("jointstudyModal"); @@ -233,7 +234,8 @@ export default { prestudent_id: this.student.prestudent_id, formData: this.formData }; - return this.$fhcApi.factory.stv.jointstudies.updateStudy(this.$refs.formJointStudies, data) + return this.$refs.formJointStudies + .call(ApiStvJointstudies.updateStudy(data)) .then(response => { this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSave')); this.hideModal("jointstudyModal"); @@ -245,14 +247,16 @@ export default { }); }, loadJointStudy(mobilitaet_id) { - return this.$fhcApi.factory.stv.jointstudies.loadStudy(mobilitaet_id) + return this.$api + .call(ApiStvJointstudies.loadStudy(mobilitaet_id)) .then(result => { this.formData = result.data; }) .catch(this.$fhcAlert.handleSystemError); }, deleteJointStudy(mobilitaet_id) { - return this.$fhcApi.factory.stv.jointstudies.deleteStudy(mobilitaet_id) + return this.$api + .call(ApiStvJointstudies.deleteStudy(mobilitaet_id)) .then(response => { this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successDelete')); }) @@ -276,32 +280,38 @@ export default { } }, created(){ - this.$fhcApi.factory.stv.jointstudies.getTypenMobility() + this.$api + .call(ApiStvJointstudies.getTypenMobility()) .then(result => { this.listTypenMobility = result.data; }) .catch(this.$fhcAlert.handleSystemError); - this.$fhcApi.factory.stv.jointstudies.getStudiensemester() + this.$api + .call(ApiStvJointstudies.getStudiensemester()) .then(result => { this.listStudiensemester = result.data; }) .catch(this.$fhcAlert.handleSystemError); - this.$fhcApi.factory.stv.mobility.getProgramsMobility() + this.$api + .call(ApiStvMobility.getProgramsMobility()) .then(result => { this.programsMobility = result.data; }) .catch(this.$fhcAlert.handleSystemError); - this.$fhcApi.factory.stv.jointstudies.getStudyprograms() + this.$api + .call(ApiStvJointstudies.getStudyprograms()) .then(result => { this.listStudienprogramme = result.data; }) .catch(this.$fhcAlert.handleSystemError); - this.$fhcApi.factory.stv.jointstudies.getListPartner() + this.$api + .call(ApiStvJointstudies.getListPartner()) .then(result => { this.listPartner = result.data; }) .catch(this.$fhcAlert.handleSystemError); - this.$fhcApi.factory.stv.jointstudies.getStatiPrestudent() + this.$api + .call(ApiStvJointstudies.getStatiPrestudent()) .then(result => { this.statiPrestudent = result.data; }) From 8442a3d758e837114c23827fc9065fb807234e9f Mon Sep 17 00:00:00 2001 From: ma0068 Date: Wed, 23 Apr 2025 12:03:21 +0200 Subject: [PATCH 026/107] Refactoring FhcApi_Factory --- public/js/api/factory/stv/exemptions.js | 75 +++++++++++++++++++ .../Details/Anrechnungen/Anrechnungen.js | 60 +++++++++------ 2 files changed, 113 insertions(+), 22 deletions(-) create mode 100644 public/js/api/factory/stv/exemptions.js diff --git a/public/js/api/factory/stv/exemptions.js b/public/js/api/factory/stv/exemptions.js new file mode 100644 index 000000000..2bf8ee610 --- /dev/null +++ b/public/js/api/factory/stv/exemptions.js @@ -0,0 +1,75 @@ +/** + * 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 { + getAnrechnungen(id) { + return { + method: 'get', + url: 'api/frontend/v1/stv/anrechnungen/getAnrechnungen/' + id + }; + }, + getLehrveranstaltungen(prestudent_id){ + return { + method: 'get', + url: 'api/frontend/v1/stv/anrechnungen/getLehrveranstaltungen/' + prestudent_id + }; + }, + getBegruendungen(){ + return { + method: 'get', + url: 'api/frontend/v1/stv/anrechnungen/getBegruendungen/' + }; + }, + getLvsKompatibel(lv_id){ + return { + method: 'get', + url: 'api/frontend/v1/stv/anrechnungen/getLvsKompatibel/' + lv_id + }; + }, + getLektoren(studiengang_kz){ + return { + method: 'get', + url: 'api/frontend/v1/stv/anrechnungen/getLektoren/' + studiengang_kz + }; + }, + addNewAnrechnung(params){ + return { + method: 'post', + url: 'api/frontend/v1/stv/anrechnungen/insertAnrechnung/', + params + }; + }, + loadAnrechnung(anrechnung_id){ + return { + method: 'get', + url: 'api/frontend/v1/stv/anrechnungen/loadAnrechnung/' + anrechnung_id + }; + }, + editAnrechnung(params){ + return { + method: 'post', + url: 'api/frontend/v1/stv/anrechnungen/updateAnrechnung/', + params + }; + }, + deleteAnrechnung(anrechnung_id){ + return { + method: 'post', + url: 'api/frontend/v1/stv/anrechnungen/deleteAnrechnung/' + anrechnung_id + }; + }, +} diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Anrechnungen/Anrechnungen.js b/public/js/components/Stv/Studentenverwaltung/Details/Anrechnungen/Anrechnungen.js index 9515f2be6..1d6bd20df 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Anrechnungen/Anrechnungen.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Anrechnungen/Anrechnungen.js @@ -4,6 +4,9 @@ import CoreForm from "../../../../Form/Form.js"; import FormInput from "../../../../Form/Input.js"; import CoreNotiz from "../../../../Notiz/Notiz.js"; +import ApiStvExemptions from "../../../../../api/factory/stv/exemptions.js"; +import ApiNotizPerson from '../../../../../api/factory/notiz/person.js'; + export default { name: "ExemptionComponent", components: { @@ -30,12 +33,9 @@ export default { return { tabulatorOptions: { ajaxURL: 'dummy', - ajaxRequestFunc: this.$fhcApi.factory.stv.exemptions.getAnrechnungen, - ajaxParams: () => { - return { - id: this.student.prestudent_id - }; - }, + ajaxRequestFunc: () => this.$api.call( + ApiStvExemptions.getAnrechnungen(this.student.prestudent_id) + ), ajaxResponse: (url, params, response) => response.data, columns: [ {title: "anrechnung_id", field: "anrechnung_id", visible: false}, @@ -83,7 +83,7 @@ export default { button.innerHTML = ''; button.title = this.$p.t('ui', 'loeschen'); button.addEventListener('click', () => - this.deleteAnrechnung(cell.getData().anrechnung_id) + this.actionDeleteAnrechnung(cell.getData().anrechnung_id) ); container.append(button); @@ -158,7 +158,8 @@ export default { listKompatibleLehrveranstaltungen: [], statusNew: true, showNotizen: false, - currentAnrechnung_id: null + currentAnrechnung_id: null, + endpoint: ApiNotizPerson } }, watch: { @@ -188,7 +189,9 @@ export default { prestudent_id: this.student.prestudent_id, formData: this.formData }; - return this.$fhcApi.factory.stv.exemptions.addNewAnrechnung(this.$refs.formExemptions, dataToSend) + + return this.$refs.formExemptions + .call(ApiStvExemptions.addNewAnrechnung(dataToSend)) .then(response => { this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSave')); this.$refs.anrechnungsModal.hide(); @@ -204,7 +207,8 @@ export default { anrechnung_id: anrechnung_id, formData: this.formData }; - return this.$fhcApi.factory.stv.exemptions.editAnrechnung(this.$refs.formExemptions, dataToSend) + return this.$refs.formExemptions + .call(ApiStvExemptions.editAnrechnung(dataToSend)) .then(response => { this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSave')); this.$refs.anrechnungsModal.hide(); @@ -215,22 +219,30 @@ export default { this.reload(); }); }, - deleteAnrechnung(anrechnung_id){ + actionDeleteAnrechnung(anrechnung_id) { this.$fhcAlert .confirmDelete() .then(result => result ? anrechnung_id : Promise.reject({handled: true})) - .then(this.$fhcApi.factory.stv.exemptions.deleteAnrechnung) - .then(result => { - this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successDelete')); - this.reload(); - }) + .then(this.deleteAnrechnung) .catch(this.$fhcAlert.handleSystemError); }, + deleteAnrechnung(anrechnung_id){ + return this.$api + .call(ApiStvExemptions.deleteAnrechnung(anrechnung_id)) + .then(response => { + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successDelete')); + }) + .catch(this.$fhcAlert.handleSystemError) + .finally(() => { + this.reload(); + }); + }, getLvsKompatibel(){ if(this.formData.lehrveranstaltung_id) { - this.$fhcApi.factory.stv.exemptions.getLvsKompatibel(this.formData.lehrveranstaltung_id) + this.$api + .call(ApiStvExemptions.getLvsKompatibel(this.formData.lehrveranstaltung_id)) .then(result => { this.listKompatibleLehrveranstaltungen = result.data; }) @@ -243,7 +255,8 @@ export default { } }, loadAnrechnung(anrechnung_id){ - return this.$fhcApi.factory.stv.exemptions.loadAnrechnung(anrechnung_id) + return this.$api + .call(ApiStvExemptions.loadAnrechnung(anrechnung_id)) .then(result => { this.formData = result.data; this.getLvsKompatibel(); @@ -263,19 +276,22 @@ export default { } }, created() { - this.$fhcApi.factory.stv.exemptions.getLehrveranstaltungen(this.student.prestudent_id) + this.$api + .call(ApiStvExemptions.getLehrveranstaltungen(this.student.prestudent_id)) .then(result => { this.listNewLehrveranstaltungen = result.data; }) .catch(this.$fhcAlert.handleSystemError); - this.$fhcApi.factory.stv.exemptions.getBegruendungen() + this.$api + .call(ApiStvExemptions.getBegruendungen()) .then(result => { this.listBegruendungen = result.data; }) .catch(this.$fhcAlert.handleSystemError); - this.$fhcApi.factory.stv.exemptions.getLektoren(this.student.studiengang_kz) + this.$api + .call(ApiStvExemptions.getLektoren(this.student.studiengang_kz)) .then(result => { this.listLektoren = result.data; }) @@ -298,7 +314,7 @@ export default {
Date: Thu, 24 Apr 2025 07:54:06 +0200 Subject: [PATCH 027/107] Refactoring FhcApi_Factory --- public/js/api/factory/stv/documents.js | 76 +++++++++++++++++++ .../Details/Dokumente/List/Accepted.js | 25 +++--- .../Details/Dokumente/List/Unaccepted.js | 20 ++--- .../Details/Dokumente/Modal/Edit.js | 15 ++-- .../Details/Dokumente/Modal/Upload.js | 12 +-- 5 files changed, 117 insertions(+), 31 deletions(-) create mode 100644 public/js/api/factory/stv/documents.js diff --git a/public/js/api/factory/stv/documents.js b/public/js/api/factory/stv/documents.js new file mode 100644 index 000000000..1898023cd --- /dev/null +++ b/public/js/api/factory/stv/documents.js @@ -0,0 +1,76 @@ +/** + * 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 { + getDocumentsUnaccepted(params) { + return { + method: 'get', + url: 'api/frontend/v1/stv/dokumente/getDocumentsUnaccepted/' + params.id + '/' + params.studiengang_kz + }; + }, + getDocumentsAccepted(params) { + return { + method: 'get', + url: 'api/frontend/v1/stv/dokumente/getDocumentsAccepted/' + params.id + '/' + params.studiengang_kz + }; + }, + deleteZuordnung(params){ + return { + method: 'post', + url: 'api/frontend/v1/stv/dokumente/deleteZuordnung/' + params.prestudent_id + '/' + params.dokument_kurzbz + }; + }, + createZuordnung(params){ + return { + method: 'post', + url: 'api/frontend/v1/stv/dokumente/createZuordnung/' + params.prestudent_id + '/' + params.dokument_kurzbz + }; + }, + loadAkte(akte_id){ + return { + method: 'get', + url: 'api/frontend/v1/stv/dokumente/loadAkte/' + akte_id + }; + }, + getDoktypen(){ + return { + method: 'get', + url: 'api/frontend/v1/stv/dokumente/getDoktypen/' + }; + }, + updateFile(akte_id, params){ + return { + method: 'post', + url: 'api/frontend/v1/stv/dokumente/updateAkte/' + akte_id, + params + }; + }, + deleteFile(akte_id){ + console.log("in deleteFile " + akte_id); + return { + method: 'post', + url: 'api/frontend/v1/stv/dokumente/deleteAkte/' + akte_id, + }; + }, + uploadFile(prestudent_id, params){ + return { + method: 'post', + url: 'api/frontend/v1/stv/dokumente/uploadDokument/' + prestudent_id, + params + }; + }, +} \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Dokumente/List/Accepted.js b/public/js/components/Stv/Studentenverwaltung/Details/Dokumente/List/Accepted.js index e22ad4cdb..7790e12f8 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Dokumente/List/Accepted.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Dokumente/List/Accepted.js @@ -2,6 +2,8 @@ import {CoreFilterCmpt} from "../../../../../filter/Filter.js"; import ModalEdit from "../Modal/Edit.js"; import ModalUpload from "../Modal/Upload.js"; +import ApiStvDocuments from "../../../../../../api/factory/stv/documents.js"; + export default { components: { name: "AcceptedDocuments", @@ -17,13 +19,11 @@ export default { return { tabulatorOptions: { ajaxURL: 'dummy', - ajaxRequestFunc: this.$fhcApi.factory.stv.documents.getDocumentsAccepted, - ajaxParams: () => { - return { + ajaxRequestFunc: () => this.$api.call( + ApiStvDocuments.getDocumentsAccepted({ id: this.prestudent_id, - studiengang_kz: this.studiengang_kz - }; - }, + studiengang_kz: this.studiengang_kz}) + ), ajaxResponse: (url, params, response) => { return response.data; }, @@ -240,7 +240,8 @@ export default { .catch(this.$fhcAlert.handleSystemError); }, deleteFile(akte_id){ - return this.$fhcApi.factory.stv.documents.deleteFile(akte_id) + return this.$api + .call(ApiStvDocuments.deleteFile(akte_id)) .then(response => { this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successDelete')); }) @@ -252,10 +253,12 @@ export default { deleteZuordnung(selected) { Promise.allSettled( selected.map(e => - this.$fhcApi.factory.stv.documents.deleteZuordnung({ - prestudent_id: this.prestudent_id, - dokument_kurzbz: e.dokument_kurzbz - }).then(() => ({ + this.$api + .call(ApiStvDocuments.deleteZuordnung({ + prestudent_id: this.prestudent_id, + dokument_kurzbz: e.dokument_kurzbz + })) + .then(() => ({ success: true, dokument_bz: e.bezeichnung })) diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Dokumente/List/Unaccepted.js b/public/js/components/Stv/Studentenverwaltung/Details/Dokumente/List/Unaccepted.js index 5b2a2d080..6cc25cb6f 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Dokumente/List/Unaccepted.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Dokumente/List/Unaccepted.js @@ -2,6 +2,8 @@ import {CoreFilterCmpt} from "../../../../../filter/Filter.js"; import ModalEdit from "../Modal/Edit.js"; import ModalUpload from "../Modal/Upload.js"; +import ApiStvDocuments from "../../../../../../api/factory/stv/documents.js"; + export default { name: "UnacceptedDocuments", components: { @@ -17,13 +19,11 @@ export default { return { tabulatorOptions: { ajaxURL: 'dummy', - ajaxRequestFunc: this.$fhcApi.factory.stv.documents.getDocumentsUnaccepted, - ajaxParams: () => { - return { + ajaxRequestFunc: () => this.$api.call( + ApiStvDocuments.getDocumentsUnaccepted({ id: this.prestudent_id, - studiengang_kz: this.studiengang_kz - }; - }, + studiengang_kz: this.studiengang_kz}) + ), ajaxResponse: (url, params, response) => response.data, columns: [ {title: "Dokument", field: "bezeichnung"}, @@ -252,10 +252,12 @@ export default { Promise .allSettled( selected.map(e => - this.$fhcApi.factory.stv.documents.createZuordnung({ + this.$api + .call(ApiStvDocuments.createZuordnung({ prestudent_id: this.prestudent_id, - dokument_kurzbz: e.dokument_kurzbz, - }).then(() => ({ + dokument_kurzbz: e.dokument_kurzbz + })) + .then(() => ({ success: true, dokument_bz: e.bezeichnung })) diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Dokumente/Modal/Edit.js b/public/js/components/Stv/Studentenverwaltung/Details/Dokumente/Modal/Edit.js index 95a12a669..29c98020e 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Dokumente/Modal/Edit.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Dokumente/Modal/Edit.js @@ -2,6 +2,8 @@ import BsModal from "../../../../../Bootstrap/Modal.js"; import FormForm from "../../../../../Form/Form.js"; import FormInput from "../../../../../Form/Input.js"; +import ApiStvDocuments from "../../../../../../api/factory/stv/documents.js"; + export default { name: "modalEditDocuments", components: { @@ -17,10 +19,9 @@ export default { }, methods: { updateFile(akte_id){ - console.log("in update" + akte_id); - - this.$fhcApi.factory.stv.documents.updateFile(akte_id, this.formData). - then(response => { + this.$api + .call(ApiStvDocuments.updateFile(akte_id, this.formData)) + .then(response => { this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSave')); this.$refs.modalEditDocument.hide(); this.$emit('reload'); @@ -32,7 +33,8 @@ export default { this.$refs.modalEditDocument.show(); }, loadFormData(akte_id){ - return this.$fhcApi.factory.stv.documents.loadAkte(akte_id) + return this.$api + .call(ApiStvDocuments.loadAkte(akte_id)) .then(result => { this.formData = result.data; return result; @@ -41,7 +43,8 @@ export default { } }, created(){ - this.$fhcApi.factory.stv.documents.getDoktypen() + this.$api + .call(ApiStvDocuments.getDoktypen()) .then(result => { this.listDokTypen = result.data; }) diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Dokumente/Modal/Upload.js b/public/js/components/Stv/Studentenverwaltung/Details/Dokumente/Modal/Upload.js index dec8da503..f6280a9cf 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Dokumente/Modal/Upload.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Dokumente/Modal/Upload.js @@ -3,6 +3,8 @@ import FormForm from "../../../../../Form/Form.js"; import FormInput from "../../../../../Form/Input.js"; import FormUploadDms from "../../../../../Form/Upload/Dms.js"; +import ApiStvDocuments from "../../../../../../api/factory/stv/documents.js"; + export default { name: "modalUploadDocuments", components: { @@ -23,15 +25,14 @@ export default { }, methods:{ open(prestudent_id, dokument_kurzbz){ - console.log("ps: " + prestudent_id + 'dok: ' + dokument_kurzbz); this.formData.dokument_kurzbz = dokument_kurzbz; this.formData.prestudent_id = prestudent_id; this.$refs.modalUploadFile.show(); }, uploadFile(){ - console.log(this.formData.anhang[0]); - - return this.$fhcApi.factory.stv.documents.uploadFile(this.formData.prestudent_id, this.formData) + // console.log(this.formData.anhang[0]); + return this.$api + .call(ApiStvDocuments.uploadFile(this.formData.prestudent_id, this.formData)) .then(result => { this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successUpload')); this.resetModal(); @@ -48,7 +49,8 @@ export default { } }, created(){ - this.$fhcApi.factory.stv.documents.getDoktypen() + this.$api + .call(ApiStvDocuments.getDoktypen()) .then(result => { this.listDokTypen = result.data; }) From ed6b9310aeaf568836007919244e017b6e1c4fc5 Mon Sep 17 00:00:00 2001 From: ma0068 Date: Thu, 24 Apr 2025 08:23:24 +0200 Subject: [PATCH 028/107] Refactoring FhcApi_Factory --- public/js/api/factory/stv/coursedates.js | 35 +++++++++++++++++++ .../ListLehrveranstaltungstermine.js | 15 ++++---- 2 files changed, 43 insertions(+), 7 deletions(-) create mode 100644 public/js/api/factory/stv/coursedates.js diff --git a/public/js/api/factory/stv/coursedates.js b/public/js/api/factory/stv/coursedates.js new file mode 100644 index 000000000..71ded7285 --- /dev/null +++ b/public/js/api/factory/stv/coursedates.js @@ -0,0 +1,35 @@ +/** + * 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 { + getCourselist(params) { + return { + method: 'get', + url: 'api/frontend/v1/stv/LvTermine/getStundenplan/' + params.student_uid + '/' + + params.start_date + '/' + + params.end_date + '/' + + params.group_consecutiveHours + '/' + + params.dbStundenplanTable + }; + }, + getStudiensemester(){ + return { + method: 'get', + url: 'api/frontend/v1/stv/LvTermine/getStudiensemester/' + }; + }, +} \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Lehrveranstaltungstermine/ListLehrveranstaltungstermine.js b/public/js/components/Stv/Studentenverwaltung/Details/Lehrveranstaltungstermine/ListLehrveranstaltungstermine.js index bc4e02b51..0f1c2f2f0 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Lehrveranstaltungstermine/ListLehrveranstaltungstermine.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Lehrveranstaltungstermine/ListLehrveranstaltungstermine.js @@ -2,6 +2,8 @@ import {CoreFilterCmpt} from "../../../../filter/Filter.js"; import FormInput from "../../../../Form/Input.js"; import FormForm from '../../../../Form/Form.js'; +import ApiStvCoursedates from "../../../../../api/factory/stv/coursedates.js"; + export default { name: "TblCourseList", components: { @@ -46,16 +48,14 @@ export default { initTabulatorOptions(){ this.tabulatorOptions = { ajaxURL: 'dummy', - ajaxRequestFunc: this.$fhcApi.factory.stv.courselist.getCourselist, - ajaxParams: () => { - return { + ajaxRequestFunc: () => this.$api.call( + ApiStvCoursedates.getCourselist({ student_uid: this.student.uid, start_date: this.dataSem.start, end_date: this.dataSem.ende, group_consecutiveHours: true, - dbStundenplanTable: this.dbStundenplanTable - }; - }, + dbStundenplanTable: this.dbStundenplanTable}) + ), ajaxResponse: (url, params, response) => { return response.data; }, @@ -153,7 +153,8 @@ export default { }, }, created(){ - this.$fhcApi.factory.stv.courselist.getStudiensemester() + this.$api + .call(ApiStvCoursedates.getStudiensemester()) .then(result => { this.listStudiensemester = result.data; this.getDatesOfSemester(this.currentSemester); From d48a0b62fd68566d0412b5cf944c979bda553ebd Mon Sep 17 00:00:00 2001 From: ma0068 Date: Thu, 24 Apr 2025 12:59:47 +0200 Subject: [PATCH 029/107] Refactoring FhcApi_Factory --- public/js/api/factory/messages/messages.js | 2 - public/js/api/messages/person.js | 91 +++++++++---------- .../Messages/Details/NewMessage/Modal.js | 2 - .../Messages/Details/NewMessage/NewDiv.js | 13 +-- .../Messages/Details/TableMessages.js | 33 ++++--- 5 files changed, 64 insertions(+), 77 deletions(-) diff --git a/public/js/api/factory/messages/messages.js b/public/js/api/factory/messages/messages.js index 8424e14f2..cec34ad8b 100644 --- a/public/js/api/factory/messages/messages.js +++ b/public/js/api/factory/messages/messages.js @@ -16,9 +16,7 @@ */ export default { - //TODO(manu) check how to get params size and page getMessages(params) { - console.log('page ' + params.page + ' size ' + params.size); return { method: 'get', url: 'api/frontend/v1/messages/messages/getMessages/' diff --git a/public/js/api/messages/person.js b/public/js/api/messages/person.js index f41050770..e2d2fd0c4 100644 --- a/public/js/api/messages/person.js +++ b/public/js/api/messages/person.js @@ -1,48 +1,47 @@ export default { - getMessages(url, config, params) { - console.log('page ' + params.page + ' size ' + params.size); - return this.$fhcApi.get('api/frontend/v1/messages/messages/getMessages/' + params.id + '/' + params.type + '/' + params.size + '/' + params.page); - }, -/* getVorlagen(){ - return this.$fhcApi.get('api/frontend/v1/messages/messages/getVorlagen/'); - }, - getMsgVarsLoggedInUser(){ - return this.$fhcApi.get('api/frontend/v1/messages/messages/getMsgVarsLoggedInUser/'); - }, - getMessageVarsPerson(params){ - return this.$fhcApi.get('api/frontend/v1/messages/messages/getMessageVarsPerson/' + params.id + '/' + params.type_id); - }, - getMsgVarsPrestudent(params){ - return this.$fhcApi.get('api/frontend/v1/messages/messages/getMsgVarsPrestudent/' + params.id + '/' + params.type_id); - }, - getPersonId(params){ - return this.$fhcApi.get('api/frontend/v1/messages/messages/getPersonId/'+ params.id + '/' + params.type_id); - }, - getUid(params){ - return this.$fhcApi.get('api/frontend/v1/messages/messages/getUid/'+ params.id + '/' + params.type_id); - }, - getVorlagentext(vorlage_kurzbz){ - return this.$fhcApi.get('api/frontend/v1/messages/messages/getVorlagentext/' + vorlage_kurzbz); - }, - getNameOfDefaultRecipient(params){ - return this.$fhcApi.get('api/frontend/v1/messages/messages/getNameOfDefaultRecipient/' + params.id + '/' + params.type_id); - }, - getPreviewText(params, data){ - return this.$fhcApi.post('api/frontend/v1/messages/messages/getPreviewText/' + params.id + '/' + params.type_id, - data); - }, - getReplyData(messageId){ - return this.$fhcApi.get('api/frontend/v1/messages/messages/getReplyData/' + messageId); - }, - sendMessageFromModalContext(form, id, data) { - return this.$fhcApi.post(form,'api/frontend/v1/messages/messages/sendMessage/' + id, - data); - }, - sendMessage(id, data) { - return this.$fhcApi.post('api/frontend/v1/messages/messages/sendMessage/' + id, - data); - }, - deleteMessage(messageId){ - return this.$fhcApi.post('api/frontend/v1/messages/messages/deleteMessage/' + messageId); - }*/ + getMessages(url, config, params) { + return this.$fhcApi.get('api/frontend/v1/messages/messages/getMessages/' + params.id + '/' + params.type + '/' + params.size + '/' + params.page); + }, + getVorlagen(){ + return this.$fhcApi.get('api/frontend/v1/messages/messages/getVorlagen/'); + }, + getMsgVarsLoggedInUser(){ + return this.$fhcApi.get('api/frontend/v1/messages/messages/getMsgVarsLoggedInUser/'); + }, + getMessageVarsPerson(params){ + return this.$fhcApi.get('api/frontend/v1/messages/messages/getMessageVarsPerson/' + params.id + '/' + params.type_id); + }, + getMsgVarsPrestudent(params){ + return this.$fhcApi.get('api/frontend/v1/messages/messages/getMsgVarsPrestudent/' + params.id + '/' + params.type_id); + }, + getPersonId(params){ + return this.$fhcApi.get('api/frontend/v1/messages/messages/getPersonId/'+ params.id + '/' + params.type_id); + }, + getUid(params){ + return this.$fhcApi.get('api/frontend/v1/messages/messages/getUid/'+ params.id + '/' + params.type_id); + }, + getVorlagentext(vorlage_kurzbz){ + return this.$fhcApi.get('api/frontend/v1/messages/messages/getVorlagentext/' + vorlage_kurzbz); + }, + getNameOfDefaultRecipient(params){ + return this.$fhcApi.get('api/frontend/v1/messages/messages/getNameOfDefaultRecipient/' + params.id + '/' + params.type_id); + }, + getPreviewText(params, data){ + return this.$fhcApi.post('api/frontend/v1/messages/messages/getPreviewText/' + params.id + '/' + params.type_id, + data); + }, + getReplyData(messageId){ + return this.$fhcApi.get('api/frontend/v1/messages/messages/getReplyData/' + messageId); + }, + sendMessageFromModalContext(form, id, data) { + return this.$fhcApi.post(form,'api/frontend/v1/messages/messages/sendMessage/' + id, + data); + }, + sendMessage(id, data) { + return this.$fhcApi.post('api/frontend/v1/messages/messages/sendMessage/' + id, + data); + }, + deleteMessage(messageId){ + return this.$fhcApi.post('api/frontend/v1/messages/messages/deleteMessage/' + messageId); + } } \ No newline at end of file diff --git a/public/js/components/Messages/Details/NewMessage/Modal.js b/public/js/components/Messages/Details/NewMessage/Modal.js index 5bbf29f16..d44d0faeb 100644 --- a/public/js/components/Messages/Details/NewMessage/Modal.js +++ b/public/js/components/Messages/Details/NewMessage/Modal.js @@ -241,7 +241,6 @@ export default { if (!newMessageId) return; try { - //const result = await this.$fhcApi.factory.messages.person.getReplyData(newMessageId); const result = await this.$api.call(ApiMessages.getReplyData(newMessageId)); this.replyData = result.data; @@ -264,7 +263,6 @@ export default { id: this.id, type_id: this.typeId }; - //this.$fhcApi.factory.messages.person.getMessageVarsPerson(params) this.$api .call(ApiMessages.getMessageVarsPerson(params)) .then(result => { diff --git a/public/js/components/Messages/Details/NewMessage/NewDiv.js b/public/js/components/Messages/Details/NewMessage/NewDiv.js index 11335ed2a..34401f6ea 100644 --- a/public/js/components/Messages/Details/NewMessage/NewDiv.js +++ b/public/js/components/Messages/Details/NewMessage/NewDiv.js @@ -118,11 +118,6 @@ export default { ...params }; data.append('data', JSON.stringify(merged)); - - //this.uid is necessary for existing sendFunction -/* return this.$fhcApi.factory.messages.person.sendMessage( - this.uid, - data)*/ return this.$api .call(ApiMessages.sendMessage(this.uid, data)) .then(response => { @@ -143,7 +138,6 @@ export default { ); }, getVorlagentext(vorlage_kurzbz){ - // return this.$fhcApi.factory.messages.person.getVorlagentext(vorlage_kurzbz) return this.$api .call(ApiMessages.getVorlagentext(vorlage_kurzbz)) .then(response => { @@ -157,9 +151,6 @@ export default { const data = new FormData(); data.append('data', JSON.stringify(this.formData.body)); -/* return this.$fhcApi.factory.messages.person.getPreviewText({ - id: id, - type_id: typeId}, data)*/ return this.$api .call(ApiMessages.getPreviewText({ id: this.id, @@ -174,7 +165,6 @@ export default { insertVariable(selectedItem){ if (this.editor) { this.editor.insertContent(selectedItem.value + " "); - // this.editor.insertContent(selectedItem.value + ". "); //TODO(Manu) check: Laden von Variblen geht nicht wenn kein Zeichen danach kommt // nicht mal mit Punkt adden gehts ohne eintrag nach vars //this.editor.focus(); @@ -272,7 +262,7 @@ export default { id: this.id, type_id: this.typeId }; - // this.$fhcApi.factory.messages.person.getMessageVarsPerson(params) + this.$api .call(ApiMessages.getMessageVarsPerson(params)) .then(result => { @@ -291,7 +281,6 @@ export default { id: this.id, type_id: this.typeId }; - //this.$fhcApi.factory.messages.person.getMsgVarsPrestudent(params) this.$api .call(ApiMessages.getMsgVarsPrestudent(params)) .then(result => { diff --git a/public/js/components/Messages/Details/TableMessages.js b/public/js/components/Messages/Details/TableMessages.js index 07fdd8f20..ac3d616ec 100644 --- a/public/js/components/Messages/Details/TableMessages.js +++ b/public/js/components/Messages/Details/TableMessages.js @@ -29,30 +29,17 @@ export default { }, data(){ return { -/* paginationSize: 15, - paginationInitialPage: 1,*/ + pageNo: 1, tabulatorOptions: { ajaxURL: 'dummy', - //TODO(Manu) how to handle size and page? -/* ajaxRequestFunc: () => this.$api.call( - ApiMessages.getMessages({ - id: this.id, - type: this.typeId, - size: this.paginationSize, - page: this.paginationInitialPage - }) - ),*/ - //OLD WORKING VERSION - ajaxRequestFunc: this.$fhcApi.factory.messages.person.getMessages, + ajaxRequestFunc: this.loadAjaxCall, ajaxParams: () => { return { id: this.id, type: this.typeId }; }, - ajaxResponse: (url, params, response) => this.buildTreemap(response), - //ajaxResponse: (url, params, response) => this.buildTreemap(response.data), columns: [ {title: "subject", field: "subject"}, {title: "body", field: "body", visible: false}, @@ -220,6 +207,12 @@ export default { this.previewBody = body; } }, + { + event: 'pageLoaded', + handler: (pageno) => { + this.pageNo = pageno+1; + } + } ], previewBody: "", open: false, @@ -296,6 +289,16 @@ export default { if (iteration > messages.length) break; } return {data: messageNested, last_page}; + }, + loadAjaxCall(params){ + return this.$api.call( + ApiMessages.getMessages({ + id: this.id, + type: this.typeId, + size: this.tabulatorOptions.paginationSize, + page: this.pageNo + }) + ); } }, computed: { From 2ab01132b1a069390abc360bb359fc4dc12bf89f Mon Sep 17 00:00:00 2001 From: ma0068 Date: Thu, 24 Apr 2025 16:30:50 +0200 Subject: [PATCH 030/107] show List Admission Dates --- .../api/frontend/v1/stv/Aufnahmetermine.php | 243 +----------------- application/models/crm/Reihungstest_model.php | 39 +++ public/js/api/factory/stv/admissionDates.js | 4 +- public/js/api/stv/admissionDates.js | 0 .../Aufnahmetermine/Aufnahmetermine.js | 31 ++- system/phrasesupdate.php | 20 ++ 6 files changed, 92 insertions(+), 245 deletions(-) delete mode 100644 public/js/api/stv/admissionDates.js diff --git a/application/controllers/api/frontend/v1/stv/Aufnahmetermine.php b/application/controllers/api/frontend/v1/stv/Aufnahmetermine.php index 519e8125d..3a0be3d40 100644 --- a/application/controllers/api/frontend/v1/stv/Aufnahmetermine.php +++ b/application/controllers/api/frontend/v1/stv/Aufnahmetermine.php @@ -27,20 +27,12 @@ class Aufnahmetermine extends FHCAPI_Controller ]); // Load models - $this->load->model('codex/Bisio_model', 'BisioModel'); + $this->load->model('crm/Reihungstest_model', 'ReihungstestModel'); } - public function getAufnahmetermine($student_uid) + public function getAufnahmetermine($person_id) { - $this->BisioModel->addSelect("*"); - $this->BisioModel->addJoin('bis.tbl_mobilitaetsprogramm mp', 'ON (mp.mobilitaetsprogramm_code = bis.tbl_bisio.mobilitaetsprogramm_code)', 'LEFT'); - $this->BisioModel->addJoin('lehre.tbl_lehreinheit le', 'ON (le.lehreinheit_id = bis.tbl_bisio.lehreinheit_id)','LEFT'); - $this->BisioModel->addOrder('von', 'DESC'); - $this->BisioModel->addOrder('bis', 'DESC'); - $this->BisioModel->addOrder('aufnahmetermin_id', 'DESC'); - $result = $this->BisioModel->loadWhere( - array('student_uid' => $student_uid) - ); + $result = $this->ReihungstestModel->getReihungstestPerson($person_id); $data = $this->getDataOrTerminateWithError($result); @@ -274,233 +266,4 @@ class Aufnahmetermine extends FHCAPI_Controller $this->terminateWithSuccess($data); } - public function getLVList($studiengang_kz) - { - $this->load->model('education/Lehrveranstaltung_model', 'LehrveranstaltungModel'); - - $result = $this->LehrveranstaltungModel->getLvsByStudiengangkz($studiengang_kz); - - $data = $this->getDataOrTerminateWithError($result); - - $this->terminateWithSuccess($data); - } - - public function getAllLehreinheiten() - { - $lv_id = $this->input->post('lv_id'); - $studiensemester_kurzbz = $this->input->post('studiensemester_kurzbz'); - - $this->load->model('education/Lehreinheit_model', 'LehreinheitModel'); - - $result = $this->LehreinheitModel->getLesFromLvIds($lv_id, $studiensemester_kurzbz); - - $data = $this->getDataOrTerminateWithError($result); - - $this->terminateWithSuccess($data); - } - - public function getLvsandLesByStudent($student_uid) - { - $this->load->model('education/Lehrveranstaltung_model', 'LehrveranstaltungModel'); - - $result = $this->LehrveranstaltungModel->getLvsByStudent($student_uid); - - $data = $this->getDataOrTerminateWithError($result); - - $lv_ids = array(); - $allData = array(); - - foreach ($data as $lehrveranstaltung) { - $lv_ids[] = $lehrveranstaltung->lehrveranstaltung_id; - } - - $this->load->model('education/Lehreinheit_model', 'LehreinheitModel'); - - foreach ($lv_ids as $id) - { - $result = $this->LehreinheitModel->getLesFromLvIds($id); - $data = $this->getDataOrTerminateWithError($result); - - if (is_array($data)) { - $allData = array_merge($allData, $data); - } - } - - return $this->terminateWithSuccess($allData); - } - - public function getPurposes($aufnahmetermin_id) - { - $aufnahmetermin_id = (int)$aufnahmetermin_id; - - $this->load->model('codex/Bisiozweck_model', 'BisiozweckModel'); - - $this->BisiozweckModel->addSelect("*"); - $this->BisiozweckModel->addJoin('bis.tbl_zweck zw', 'ON (zw.zweck_code = bis.tbl_bisio_zweck.zweck_code)'); - - $result = $this->BisiozweckModel->loadWhere( - array('aufnahmetermin_id' => $aufnahmetermin_id) - ); - - $data = $this->getDataOrTerminateWithError($result); - - $this->terminateWithSuccess($data); - } - - public function getSupports($aufnahmetermin_id) - { - $aufnahmetermin_id = (int)$aufnahmetermin_id; - - $this->load->model('codex/Bisioaufenthaltfoerderung_model', 'BisioaufenthaltfoerderungModel'); - - $this->BisioaufenthaltfoerderungModel->addSelect("*"); - $this->BisioaufenthaltfoerderungModel->addJoin('bis.tbl_aufenthaltfoerderung af', 'ON (af.aufenthaltfoerderung_code = bis.tbl_bisio_aufenthaltfoerderung.aufenthaltfoerderung_code)'); - - $result = $this->BisioaufenthaltfoerderungModel->loadWhere( - array('aufnahmetermin_id' => $aufnahmetermin_id) - ); - - $data = $this->getDataOrTerminateWithError($result); - - $this->terminateWithSuccess($data); - } - - public function getListPurposes() - { - $this->load->model('codex/Zweck_model', 'ZweckModel'); - - $result = $this->ZweckModel->load(); - - $data = $this->getDataOrTerminateWithError($result); - - $this->terminateWithSuccess($data); - } - - public function getListSupports() - { - $this->load->model('codex/Aufenthaltfoerderung_model', 'AufenthaltfoerderungModel'); - - $result = $this->AufenthaltfoerderungModel->load(); - - $data = $this->getDataOrTerminateWithError($result); - - $this->terminateWithSuccess($data); - } - - public function addAufnahmeterminPurpose($aufnahmetermin_id, $local_purpose = null) - { - $zweck_code = $this->input->post('zweck_code'); - - if($local_purpose){ - $zweck_code = $local_purpose; - } - - $this->load->model('codex/Bisiozweck_model', 'BisiozweckModel'); - if(!$local_purpose) - { - $check = $this->BisiozweckModel->loadWhere( - [ - 'aufnahmetermin_id' => $aufnahmetermin_id, - 'zweck_code' => $zweck_code, - ] - ); - if (hasData($check)) - { - $this->terminateWithError($this->p->t('ui', 'error_entryExisting'), self::ERROR_TYPE_GENERAL); - } - } - - $result = $this->BisiozweckModel->insert( - array( - 'aufnahmetermin_id' => $aufnahmetermin_id, - 'zweck_code' => $zweck_code - ) - ); - - $data = $this->getDataOrTerminateWithError($result); - - if($local_purpose) - { - return $data; - } - - return $this->terminateWithSuccess(current($data)); - } - - public function deleteAufnahmeterminPurpose($aufnahmetermin_id) - { - $zweck_code = $this->input->post('zweck_code'); - - $this->load->model('codex/Bisiozweck_model', 'BisiozweckModel'); - - - $result = $this->BisiozweckModel->delete( - array( - 'aufnahmetermin_id' => $aufnahmetermin_id, - 'zweck_code' => $zweck_code - ) - ); - - $data = $this->getDataOrTerminateWithError($result); - - return $this->terminateWithSuccess(current($data)); - } - - public function addAufnahmeterminSupport($aufnahmetermin_id, $local_support = null) - { - $aufenthaltfoerderung_code = $this->input->post('aufenthaltfoerderung_code'); - - if($local_support){ - $aufenthaltfoerderung_code = $local_support; - } - - $this->load->model('codex/Bisioaufenthaltfoerderung_model', 'BisioaufenthaltfoerderungModel'); - - if(!$local_support) - { - $check = $this->BisioaufenthaltfoerderungModel->loadWhere( - [ - 'aufnahmetermin_id' => $aufnahmetermin_id, - 'aufenthaltfoerderung_code' => $aufenthaltfoerderung_code, - ] - ); - if (hasData($check)) - { - $this->terminateWithError($this->p->t('ui', 'error_entryExisting'), self::ERROR_TYPE_GENERAL); - } - } - - $result = $this->BisioaufenthaltfoerderungModel->insert( - array( - 'aufnahmetermin_id' => $aufnahmetermin_id, - 'aufenthaltfoerderung_code' => $aufenthaltfoerderung_code - ) - ); - - $data = $this->getDataOrTerminateWithError($result); - - if($local_support) - { - return $data; - } - - return $this->terminateWithSuccess(current($data)); - } - - public function deleteAufnahmeterminSupport($aufnahmetermin_id) - { - $aufenthaltfoerderung_code = $this->input->post('aufenthaltfoerderung_code'); - - $this->load->model('codex/Bisioaufenthaltfoerderung_model', 'BisioaufenthaltfoerderungModel'); - - $result = $this->BisioaufenthaltfoerderungModel->delete( - array( - 'aufnahmetermin_id' => $aufnahmetermin_id, - 'aufenthaltfoerderung_code' => $aufenthaltfoerderung_code - ) - ); - $data = $this->getDataOrTerminateWithError($result); - - return $this->terminateWithSuccess(current($data)); - } } diff --git a/application/models/crm/Reihungstest_model.php b/application/models/crm/Reihungstest_model.php index 86ebfd0af..f2732b636 100644 --- a/application/models/crm/Reihungstest_model.php +++ b/application/models/crm/Reihungstest_model.php @@ -511,4 +511,43 @@ class Reihungstest_model extends DB_Model return $this->execQuery($query, array($date, $studiengang_kz)); } + + /** + * Loads all placement tests of a given person + * @param integer $person_id + * @return array Returns object array with data of placement tests + */ + public function getReihungstestPerson($person_id) + { + $query = ' + SELECT + tbl_rt_person.*, + tbl_reihungstest.studiengang_kz, + tbl_reihungstest.anmerkung, + tbl_reihungstest.datum, + tbl_reihungstest.uhrzeit, + tbl_reihungstest.ext_id, + tbl_reihungstest.max_teilnehmer, + tbl_reihungstest.oeffentlich, + tbl_reihungstest.freigeschaltet, + tbl_reihungstest.studiensemester_kurzbz, + tbl_reihungstest.stufe, + tbl_reihungstest.anmeldefrist, + tbl_reihungstest.aufnahmegruppe_kurzbz, + tbl_studiengang.typ, + UPPER(typ::varchar(1) || kurzbz) AS stg_kuerzel, + so.studiengangbezeichnung, + so.studiengangbezeichnung_englisch + FROM + public.tbl_rt_person + JOIN public.tbl_reihungstest ON (rt_id=reihungstest_id) + JOIN public.tbl_studiengang ON tbl_reihungstest.studiengang_kz = tbl_studiengang.studiengang_kz + JOIN lehre.tbl_studienplan sp USING(studienplan_id) + JOIN lehre.tbl_studienordnung so USING(studienordnung_id) + WHERE + tbl_rt_person.person_id = ? + ORDER BY datum, uhrzeit ASC'; + + return $this->execQuery($query, array($person_id)); + } } \ No newline at end of file diff --git a/public/js/api/factory/stv/admissionDates.js b/public/js/api/factory/stv/admissionDates.js index fc96f47be..51a92c331 100644 --- a/public/js/api/factory/stv/admissionDates.js +++ b/public/js/api/factory/stv/admissionDates.js @@ -16,10 +16,10 @@ */ export default { - getAufnahmetermine(prestudent_id) { + getAufnahmetermine(person_id) { return { method: 'get', - url: 'api/frontend/v1/stv/aufnahmetermine/' + prestudent_id + url: 'api/frontend/v1/stv/aufnahmetermine/getAufnahmetermine/' + person_id, }; }, } \ No newline at end of file diff --git a/public/js/api/stv/admissionDates.js b/public/js/api/stv/admissionDates.js deleted file mode 100644 index e69de29bb..000000000 diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Aufnahmetermine/Aufnahmetermine.js b/public/js/components/Stv/Studentenverwaltung/Details/Aufnahmetermine/Aufnahmetermine.js index 58f440836..7e7e2ae97 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Aufnahmetermine/Aufnahmetermine.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Aufnahmetermine/Aufnahmetermine.js @@ -27,12 +27,24 @@ export default { tabulatorOptions: { ajaxURL: 'dummy', ajaxRequestFunc: () => this.$api.call( - ApiStvAdmissionDates.getAufnahmetermin(this.student.prestudent_id) + ApiStvAdmissionDates.getAufnahmetermine(this.student.person_id) ), ajaxResponse: (url, params, response) => response.data, columns: [ - {title: "aufnahmetermin_id", field: "aufnahmetermin_id"}, - {title: "prestudent_id", field: "prestudent_id"}, + {title: "rt_id", field: "rt_id"}, + {title: "rt_person_id", field: "rt_person_id"}, + {title: "person_id", field: "person_id"}, + {title: "datum", field: "datum"}, + {title: "stufe", field: "stufe"}, + {title: "studiensemester", field: "studiensemester_kurzbz"}, + {title: "anmerkung", field: "anmerkung", visible: false}, + {title: "anmeldedatum", field: "anmeldedatum", visible: false}, + {title: "punkte", field: "punkte"}, + {title: "teilgenommen", field: "teilgenommen"}, + {title: "ort", field: "ort", visible: false}, + {title: "studienplan", field: "studienplan", visible: false}, + {title: "studienplan_id", field: "studienplan_id", visible: false}, + {title: "stg_kuerzel", field: "stg_kuerzel"}, ], layout: 'fitDataFill', layoutColumnsOnNewData: false, @@ -53,6 +65,19 @@ export default {

Allgemein

+ + +
` } diff --git a/system/phrasesupdate.php b/system/phrasesupdate.php index fd54d9f66..bf18f50c8 100644 --- a/system/phrasesupdate.php +++ b/system/phrasesupdate.php @@ -41416,6 +41416,26 @@ and represent the current state of research on the topic. The prescribed citatio ) ) ), + array( + 'app' => 'core', + 'category' => 'lehre', + 'phrase' => 'reihungstest', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Reihungstest', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Placement Test', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), // FHC4 STUDIERENDENVERWALTUNG AUFNAHMETERMINE ENDE --------------------------------------------------------------- ); From bf0cd8e8e3341138a2e7f74cc1927989ef14732e Mon Sep 17 00:00:00 2001 From: ma0068 Date: Fri, 25 Apr 2025 16:15:27 +0200 Subject: [PATCH 031/107] actions new, update and delete aufnahmetermine --- .../api/frontend/v1/stv/Aufnahmetermine.php | 250 ++++++---------- application/models/crm/Reihungstest_model.php | 33 ++ .../models/organisation/Studienplan_model.php | 13 + public/js/api/factory/stv/admissionDates.js | 39 +++ .../Aufnahmetermine/Aufnahmetermine.js | 282 +++++++++++++++++- system/phrasesupdate.php | 100 +++++++ 6 files changed, 556 insertions(+), 161 deletions(-) diff --git a/application/controllers/api/frontend/v1/stv/Aufnahmetermine.php b/application/controllers/api/frontend/v1/stv/Aufnahmetermine.php index 3a0be3d40..6b0356bc3 100644 --- a/application/controllers/api/frontend/v1/stv/Aufnahmetermine.php +++ b/application/controllers/api/frontend/v1/stv/Aufnahmetermine.php @@ -14,6 +14,9 @@ class Aufnahmetermine extends FHCAPI_Controller 'insertAufnahmetermin' => ['admin:rw', 'assistenz:rw'], 'updateAufnahmetermin' => ['admin:rw', 'assistenz:rw'], 'deleteAufnahmetermin' => ['admin:rw', 'assistenz:rw'], + 'getListPlacementTests' => ['admin:rw', 'assistenz:rw'], + 'getListStudyPlans' => ['admin:rw', 'assistenz:rw'], + ]); // Load Libraries @@ -23,11 +26,12 @@ class Aufnahmetermine extends FHCAPI_Controller // Load language phrases $this->loadPhrases([ 'ui', - 'mobility' + 'admission' ]); // Load models $this->load->model('crm/Reihungstest_model', 'ReihungstestModel'); + $this->load->model('crm/RtPerson_model', 'RtPersonModel'); } public function getAufnahmetermine($person_id) @@ -44,106 +48,62 @@ class Aufnahmetermine extends FHCAPI_Controller $this->load->library('form_validation'); $authUID = getAuthUID(); - $student_uid = $this->input->post('uid'); + $formData = $this->input->post('formData'); + $person_id = $this->input->post('person_id'); - if(!$student_uid) + if(!$person_id) { - return $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Student UID']), self::ERROR_TYPE_GENERAL); + return $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Person ID']), self::ERROR_TYPE_GENERAL); } - $formData = $this->input->post('formData'); - $_POST['von'] = (isset($formData['von']) && !empty($formData['von'])) ? $formData['von'] : null; - $_POST['bis'] = (isset($formData['bis']) && !empty($formData['bis'])) ? $formData['bis'] : null; - $_POST['nation_code'] = (isset($formData['nation_code']) && !empty($formData['nation_code'])) ? $formData['nation_code'] : 'A'; - $_POST['mobilitaetsprogramm_code'] = (isset($formData['mobilitaetsprogramm_code']) && !empty($formData['mobilitaetsprogramm_code'])) ? $formData['mobilitaetsprogramm_code'] : null; - $_POST['herkunftsland_code'] = (isset($formData['herkunftsland_code']) && !empty($formData['herkunftsland_code'])) ? $formData['herkunftsland_code'] : 'A'; - $_POST['ects_erworben'] = (isset($formData['ects_erworben']) && !empty($formData['ects_erworben'])) ? $formData['ects_erworben'] : null; - $_POST['ects_angerechnet'] = (isset($formData['ects_angerechnet']) && !empty($formData['ects_angerechnet'])) ? $formData['ects_angerechnet'] : null; - $_POST['lehreinheit_id'] = (isset($formData['lehreinheit_id']) && !empty($formData['lehreinheit_id'])) ? $formData['lehreinheit_id'] : null; - $this->form_validation->set_rules('nation_code', 'Nation_code', 'required', [ - 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Nation_code']) + $_POST['rt_id'] = (isset($formData['rt_id']) && !empty($formData['rt_id'])) ? $formData['rt_id'] : null; + $_POST['anmeldedatum'] = (isset($formData['anmeldedatum']) && !empty($formData['anmeldedatum'])) ? $formData['anmeldedatum'] : null; + $_POST['teilgenommen'] = (isset($formData['teilgenommen']) && !empty($formData['teilgenommen'])) ? $formData['teilgenommen'] : false; + $_POST['studienplan_id'] = (isset($formData['studienplan_id']) && !empty($formData['studienplan_id'])) ? $formData['studienplan_id'] : null; + $_POST['punkte'] = (isset($formData['punkte']) && !empty($formData['punkte'])) ? $formData['punkte'] : null; + + $this->form_validation->set_rules('punkte', 'Punkte', 'numeric', [ + 'required' => $this->p->t('ui', 'error_fieldNotNumeric', ['field' => 'Punkte']) ]); - $this->form_validation->set_rules('herkunftsland_code', 'Herkunftsland_code', 'required', [ - 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Herkunftsland_code']) + $this->form_validation->set_rules('studienplan_id', 'studienplan_id', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Studienplan']) ]); - $this->form_validation->set_rules('mobilitaetsprogramm_code', 'Mobilitaetsprogramm_code', 'required', [ - 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Mobilitaetsprogramm_code']) - ]); - $this->form_validation->set_rules('von', 'VonDatum', 'is_valid_date', [ - 'is_valid_date' => $this->p->t('ui', 'error_notValidDate', ['field' => 'VonDatum']) + $this->form_validation->set_rules('rt_id', 'Reihungstest_id', 'required', [ + 'is_valid_date' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Reihungstest']) ]); - $this->form_validation->set_rules('bis', 'VBisDatum', 'is_valid_date', [ - 'is_valid_date' => $this->p->t('ui', 'error_notValidDate', ['field' => 'VBisDatum']) + $this->form_validation->set_rules('anmeldedatum', 'AnmeldeDatum', 'is_valid_date', [ + 'is_valid_date' => $this->p->t('ui', 'error_notValidDate', ['field' => 'Anmeldedatum']) ]); - $this->form_validation->set_rules('ects_erworben', 'Ects_erworben', 'numeric', [ - 'numeric' => $this->p->t('ui', 'error_fieldNotNumeric', ['field' => 'Ects_erworben']) - ]); - - $this->form_validation->set_rules('ects_angerechnet', 'Ects_angerechnet', 'numeric', [ - 'numeric' => $this->p->t('ui', 'error_fieldNotNumeric', ['field' => 'Ects_angerechnet']) - ]); - - $this->form_validation->set_rules('lehreinheit_id', 'Lehreinheit', 'numeric', [ - 'numeric' => $this->p->t('ui', 'error_fieldNotNumeric', ['field' => 'Lehreinheit']) - ]); if ($this->form_validation->run() == false) { $this->terminateWithValidationErrors($this->form_validation->error_array()); } - $ort = (isset($formData['ort']) && !empty($formData['ort'])) ? $formData['ort'] : null; - $universitaet = (isset($formData['universitaet']) && !empty($formData['universitaet'])) ? $formData['universitaet'] : null; - $localPurposes = (isset($formData['localPurposes']) && !empty($formData['localPurposes'])) ? $formData['localPurposes'] : null; - $localSupports = (isset($formData['localSupports']) && !empty($formData['localSupports'])) ? $formData['localSupports'] : null; - - $result = $this->BisioModel->insert([ - 'student_uid' => $student_uid, - 'von' => $_POST['von'], - 'bis' => $_POST['bis'], - 'mobilitaetsprogramm_code' => $_POST['mobilitaetsprogramm_code'], - 'nation_code' => $_POST['nation_code'], - 'herkunftsland_code' => $_POST['herkunftsland_code'], - 'lehreinheit_id' => $_POST['lehreinheit_id'], - 'ort' => $ort, - 'universitaet' => $universitaet, - 'ects_erworben' => $_POST['ects_erworben'] , - 'ects_angerechnet' => $_POST['ects_angerechnet'], + $result = $this->RtPersonModel->insert([ + 'person_id' => $person_id, + 'rt_id' => $_POST['rt_id'], + 'anmeldedatum' => $_POST['anmeldedatum'], + 'teilgenommen' => $_POST['teilgenommen'], + 'studienplan_id' => $_POST['studienplan_id'], + 'punkte' => $_POST['punkte'], 'insertamum' => date('c'), 'insertvon' => $authUID, ]); - $aufnahmetermin_id = $this->getDataOrTerminateWithError($result); + $data = $this->getDataOrTerminateWithError($result); - //check if localData (purposes) - if(count($localPurposes) > 0){ - foreach ($localPurposes as $zweck){ - $zweck = (int)$zweck; - $this->addAufnahmeterminPurpose($aufnahmetermin_id, $zweck); - } - } - - //check if localData (supports) - if(count($localSupports) > 0){ - foreach ($localSupports as $support){ - $this->addAufnahmeterminSupport($aufnahmetermin_id, $support); - } - } - - $this->terminateWithSuccess($aufnahmetermin_id); + $this->terminateWithSuccess($data); } - public function loadAufnahmetermin($aufnahmetermin_id) + public function loadAufnahmetermin($rt_person_id) { - $this->BisioModel->addSelect("*"); - $this->BisioModel->addJoin('bis.tbl_mobilitaetsprogramm mp', 'ON (mp.mobilitaetsprogramm_code = bis.tbl_bisio.mobilitaetsprogramm_code)', 'LEFT'); - $this->BisioModel->addJoin('lehre.tbl_lehreinheit le', 'ON (le.lehreinheit_id = bis.tbl_bisio.lehreinheit_id)','LEFT'); - $result = $this->BisioModel->loadWhere( - array('aufnahmetermin_id' => $aufnahmetermin_id) + $result = $this->RtPersonModel->loadWhere( + array('rt_person_id' => $rt_person_id) ); $data = $this->getDataOrTerminateWithError($result); @@ -152,118 +112,96 @@ class Aufnahmetermine extends FHCAPI_Controller public function updateAufnahmetermin() { - $this->load->library('form_validation'); $authUID = getAuthUID(); - $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); - } $formData = $this->input->post('formData'); + $rt_person_id = $this->input->post('rt_person_id'); + $person_id = (isset($formData['person_id']) && !empty($formData['person_id'])) ? $formData['person_id'] : null; - $_POST['von'] = (isset($formData['von']) && !empty($formData['von'])) ? $formData['von'] : null; - $_POST['bis'] = (isset($formData['bis']) && !empty($formData['bis'])) ? $formData['bis'] : null; - $_POST['nation_code'] = (isset($formData['nation_code']) && !empty($formData['nation_code'])) ? $formData['nation_code'] : 'A'; - $_POST['mobilitaetsprogramm_code'] = (isset($formData['mobilitaetsprogramm_code']) && !empty($formData['mobilitaetsprogramm_code'])) ? $formData['mobilitaetsprogramm_code'] : null; - $_POST['herkunftsland_code'] = (isset($formData['herkunftsland_code']) && !empty($formData['herkunftsland_code'])) ? $formData['herkunftsland_code'] : 'A'; - $_POST['ects_erworben'] = (isset($formData['ects_erworben']) && !empty($formData['ects_erworben'])) ? $formData['ects_erworben'] : null; - $_POST['ects_angerechnet'] = (isset($formData['ects_angerechnet']) && !empty($formData['ects_angerechnet'])) ? $formData['ects_angerechnet'] : null; - $_POST['lehreinheit_id'] = (isset($formData['lehreinheit_id']) && !empty($formData['lehreinheit_id'])) ? $formData['lehreinheit_id'] : null; - $this->form_validation->set_rules('nation_code', 'Nation_code', 'required', [ - 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Nation_code']) + if(!$person_id) + { + return $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Person ID']), self::ERROR_TYPE_GENERAL); + } + if(!$rt_person_id) + { + return $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'RT_Person ID']), self::ERROR_TYPE_GENERAL); + } + + + $_POST['rt_id'] = (isset($formData['rt_id']) && !empty($formData['rt_id'])) ? $formData['rt_id'] : null; + $_POST['anmeldedatum'] = (isset($formData['anmeldedatum']) && !empty($formData['anmeldedatum'])) ? $formData['anmeldedatum'] : null; + $_POST['teilgenommen'] = (isset($formData['teilgenommen']) && !empty($formData['teilgenommen'])) ? $formData['teilgenommen'] : false; + $_POST['studienplan_id'] = (isset($formData['studienplan_id']) && !empty($formData['studienplan_id'])) ? $formData['studienplan_id'] : null; + $_POST['punkte'] = (isset($formData['punkte']) && !empty($formData['punkte'])) ? $formData['punkte'] : null; + + $this->form_validation->set_rules('punkte', 'Punkte', 'numeric', [ + 'required' => $this->p->t('ui', 'error_fieldNotNumeric', ['field' => 'Punkte']) ]); - $this->form_validation->set_rules('herkunftsland_code', 'Herkunftsland_code', 'required', [ - 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Herkunftsland_code']) + $this->form_validation->set_rules('studienplan_id', 'studienplan_id', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Studienplan']) ]); - $this->form_validation->set_rules('mobilitaetsprogramm_code', 'Mobilitaetsprogramm_code', 'required', [ - 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Mobilitaetsprogramm_code']) - ]); - $this->form_validation->set_rules('von', 'VonDatum', 'is_valid_date', [ - 'is_valid_date' => $this->p->t('ui', 'error_notValidDate', ['field' => 'VonDatum']) + $this->form_validation->set_rules('rt_id', 'Reihungstest_id', 'required', [ + 'is_valid_date' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Reihungstest']) ]); - $this->form_validation->set_rules('bis', 'VBisDatum', 'is_valid_date', [ - 'is_valid_date' => $this->p->t('ui', 'error_notValidDate', ['field' => 'VBisDatum']) + $this->form_validation->set_rules('anmeldedatum', 'AnmeldeDatum', 'is_valid_date', [ + 'is_valid_date' => $this->p->t('ui', 'error_notValidDate', ['field' => 'Anmeldedatum']) ]); - $this->form_validation->set_rules('ects_erworben', 'Ects_erworben', 'numeric', [ - 'numeric' => $this->p->t('ui', 'error_fieldNotNumeric', ['field' => 'Ects_erworben']) - ]); - - $this->form_validation->set_rules('ects_angerechnet', 'Ects_angerechnet', 'numeric', [ - 'numeric' => $this->p->t('ui', 'error_fieldNotNumeric', ['field' => 'Ects_angerechnet']) - ]); - - $this->form_validation->set_rules('lehreinheit_id', 'Lehreinheit', 'numeric', [ - 'numeric' => $this->p->t('ui', 'error_fieldNotNumeric', ['field' => 'Lehreinheit']) - ]); if ($this->form_validation->run() == false) { $this->terminateWithValidationErrors($this->form_validation->error_array()); } - $result = $this->BisioModel->update( + $result = $this->RtPersonModel->update( [ - 'aufnahmetermin_id' => $formData['aufnahmetermin_id'] + 'rt_person_id' => $rt_person_id, + 'person_id' => $person_id, ], [ - 'student_uid' => $student_uid, - 'von' => $_POST['von'], - 'bis' => $_POST['bis'], - 'mobilitaetsprogramm_code' => $_POST['mobilitaetsprogramm_code'], - 'nation_code' => $_POST['nation_code'], - 'herkunftsland_code' => $_POST['herkunftsland_code'], - 'lehreinheit_id' => $_POST['lehreinheit_id'], - 'ort' => $formData['ort'], - 'universitaet' => $formData['universitaet'], - 'ects_erworben' => $_POST['ects_erworben'] , - 'ects_angerechnet' => $_POST['ects_angerechnet'], - 'updateamum' => date('c'), - 'updatevon' => $authUID, - ] - ); + 'rt_id' => $_POST['rt_id'], + 'anmeldedatum' => $_POST['anmeldedatum'], + 'teilgenommen' => $_POST['teilgenommen'], + 'studienplan_id' => $_POST['studienplan_id'], + 'punkte' => $_POST['punkte'], + 'insertamum' => date('c'), + 'insertvon' => $authUID, + ]); $data = $this->getDataOrTerminateWithError($result); - $this->terminateWithSuccess(current($data)); + $this->terminateWithSuccess($data); } - public function deleteAufnahmetermin($aufnahmetermin_id) + public function deleteAufnahmetermin($rt_person_id) { - //check if extension table exists - $result = $this->BisioModel->tableExists('extension', 'tbl_mo_bisioidzuordnung'); - $data = $this->getDataOrTerminateWithError($result); - - //if table exists check if existing entry - if(!empty($data)) - { - $this->BisioModel->addSelect("count(*)"); - $this->BisioModel->addJoin('extension.tbl_mo_bisioidzuordnung mo', 'ON (mo.aufnahmetermin_id = bis.tbl_bisio.aufnahmetermin_id)', 'LEFT'); - - $resultCheckMo = $this->BisioModel->loadWhere( - array('mo.aufnahmetermin_id' => $aufnahmetermin_id) - ); - - $resultCheckMo = $this->getDataOrTerminateWithError($resultCheckMo); - $count = current($resultCheckMo)->count; - - $existsInExtension = $count > 0 ? true : false; - - if($existsInExtension) - $this->terminateWithError($this->p->t('mobility', 'error_existingEntryInExtension'), self::ERROR_TYPE_GENERAL); - } - - $result = $this->BisioModel->delete( - array('aufnahmetermin_id' => $aufnahmetermin_id) + $result = $this->RtPersonModel->delete( + array('rt_person_id' => $rt_person_id) ); $data = $this->getDataOrTerminateWithError($result); $this->terminateWithSuccess($data); } + public function getListPlacementTests() + { + $result = $this->ReihungstestModel->getAllReihungstests(); + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + + public function getListStudyPlans($person_id) + { + $this->load->model('organisation/Studienplan_model','StudienplanModel'); + + $result = $this->StudienplanModel->getStudienplaeneForPerson($person_id);; + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + } diff --git a/application/models/crm/Reihungstest_model.php b/application/models/crm/Reihungstest_model.php index f2732b636..2eb08ee86 100644 --- a/application/models/crm/Reihungstest_model.php +++ b/application/models/crm/Reihungstest_model.php @@ -550,4 +550,37 @@ class Reihungstest_model extends DB_Model return $this->execQuery($query, array($person_id)); } + + /** + * Loads all placement tests + * @return array Returns object array with data of placement tests + */ + //TODO(Manu) finish Details + public function getAllReihungstests() + { + $query = ' + SELECT * FROM public.tbl_reihungstest + JOIN public.tbl_studiengang ON tbl_reihungstest.studiengang_kz = tbl_studiengang.studiengang_kz + -- JOIN lehre.tbl_studienplan sp USING(studienplan_id) + -- JOIN lehre.tbl_studienordnung so USING(studienordnung_id) + ORDER BY datum DESC NULLS LAST, uhrzeit + '; + + return $this->execQuery($query); + } + + public function getReihungstestsPs($prestudent_id) + { + $query = ' + SELECT * FROM public.tbl_reihungstest + JOIN public.tbl_studiengang ON tbl_reihungstest.studiengang_kz = tbl_studiengang.studiengang_kz + JOIN lehre.tbl_studienplan sp USING(studienplan_id) + JOIN lehre.tbl_studienordnung so USING(studienordnung_id) + ORDER BY datum DESC, uhrzeit + '; + + return $this->execQuery($query); + } + + } \ No newline at end of file diff --git a/application/models/organisation/Studienplan_model.php b/application/models/organisation/Studienplan_model.php index e35ba52fb..569aebd0b 100644 --- a/application/models/organisation/Studienplan_model.php +++ b/application/models/organisation/Studienplan_model.php @@ -134,4 +134,17 @@ class Studienplan_model extends DB_Model 'prestudent_id' => $prestudent_id ]); } + + public function getStudienplaeneForPerson($person_id) + { + $this->addDistinct(); + $this->addSelect($this->dbTable . '.*'); + $this->addSelect('ps.*'); + $this->addJoin('public.tbl_prestudentstatus pss', 'studienplan_id'); + $this->addJoin('public.tbl_prestudent ps', 'prestudent_id'); + + return $this->loadWhere([ + 'person_id' => $person_id + ]); + } } diff --git a/public/js/api/factory/stv/admissionDates.js b/public/js/api/factory/stv/admissionDates.js index 51a92c331..a5b0697da 100644 --- a/public/js/api/factory/stv/admissionDates.js +++ b/public/js/api/factory/stv/admissionDates.js @@ -22,4 +22,43 @@ export default { url: 'api/frontend/v1/stv/aufnahmetermine/getAufnahmetermine/' + person_id, }; }, + getListPlacementTests(){ + return { + method: 'get', + url: 'api/frontend/v1/stv/aufnahmetermine/getListPlacementTests/', + }; + }, + getListStudyPlans(person_id){ + return { + method: 'get', + url: 'api/frontend/v1/stv/aufnahmetermine/getListStudyPlans/' + person_id, + }; + }, + addNewPlacementTest(params){ + return { + method: 'post', + url: 'api/frontend/v1/stv/aufnahmetermine/insertAufnahmetermin/', + params + }; + }, + loadPlacementTest(rt_person_id){ + return { + method: 'get', + url: 'api/frontend/v1/stv/aufnahmetermine/loadAufnahmetermin/' + rt_person_id, + }; + }, + updatePlacementTest(params){ + return { + method: 'post', + url: 'api/frontend/v1/stv/aufnahmetermine/updateAufnahmetermin/', + params + }; + }, + deletePlacementTest(rt_person_id){ + return { + method: 'post', + url: 'api/frontend/v1/stv/aufnahmetermine/deleteAufnahmetermin/' + rt_person_id + }; + } + } \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Aufnahmetermine/Aufnahmetermine.js b/public/js/components/Stv/Studentenverwaltung/Details/Aufnahmetermine/Aufnahmetermine.js index 7e7e2ae97..5fe32e885 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Aufnahmetermine/Aufnahmetermine.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Aufnahmetermine/Aufnahmetermine.js @@ -34,17 +34,70 @@ export default { {title: "rt_id", field: "rt_id"}, {title: "rt_person_id", field: "rt_person_id"}, {title: "person_id", field: "person_id"}, - {title: "datum", field: "datum"}, + {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", + }); + } + }, {title: "stufe", field: "stufe"}, {title: "studiensemester", field: "studiensemester_kurzbz"}, {title: "anmerkung", field: "anmerkung", visible: false}, - {title: "anmeldedatum", field: "anmeldedatum", visible: false}, + {title: "anmeldedatum", field: "anmeldedatum", visible: false, + 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", + }); + } + }, {title: "punkte", field: "punkte"}, {title: "teilgenommen", field: "teilgenommen"}, {title: "ort", field: "ort", visible: false}, {title: "studienplan", field: "studienplan", visible: false}, {title: "studienplan_id", field: "studienplan_id", visible: false}, {title: "stg_kuerzel", field: "stg_kuerzel"}, + { + 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.actionEditPlacementTest(cell.getData().rt_person_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.actionDeletePlacementTest(cell.getData().rt_person_id) + ); + container.append(button); + + return container; + }, + frozen: true + } ], layout: 'fitDataFill', layoutColumnsOnNewData: false, @@ -56,13 +109,129 @@ export default { tabulatorEvents: [], formData: {}, statusNew: true, + listPlacementTests: [], + listStudyPlans: [] } }, - methods: {}, + methods: { + actionNewPlacementTest() { + this.resetForm(); + this.statusNew = true; + this.$refs.placementTestModal.show(); + }, + actionEditPlacementTest(rt_person_id) { + console.log("edit Test " + rt_person_id); + this.resetForm(); + this.statusNew = false; + this.loadPlacementTest(rt_person_id); + this.$refs.placementTestModal.show(); + }, + actionDeletePlacementTest(rt_person_id) { + this.$fhcAlert + .confirmDelete() + .then(result => result + ? rt_person_id + : Promise.reject({handled: true})) + .then(this.deletePlacementTest) + .catch(this.$fhcAlert.handleSystemError); + }, + addNewPlacementTest() { + const dataToSend = { + person_id: this.student.person_id, + formData: this.formData + }; + return this.$refs.formPlacementTest + .call(ApiStvAdmissionDates.addNewPlacementTest(dataToSend)) + .then(response => { + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSave')); + this.hideModal("placementTestModal"); + this.resetForm(); + }) + .catch(this.$fhcAlert.handleSystemError) + .finally(() => { + this.reload(); + }); + }, + hideModal(modalRef){ + this.$refs[modalRef].hide(); + }, + reload() { + this.$refs.table.reloadTable(); + }, + loadPlacementTest(rt_person_id) { + console.log("load Test " + rt_person_id); + return this.$api + .call(ApiStvAdmissionDates.loadPlacementTest(rt_person_id)) + .then(result => { + this.formData = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + }, + updatePlacementTest(rt_person_id) { + const dataToSend = { + formData: this.formData, + rt_person_id: rt_person_id, + }; + this.$refs.formPlacementTest + .call(ApiStvAdmissionDates.updatePlacementTest(dataToSend)) + .then(response => { + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSave')); + this.hideModal("placementTestModal"); + this.resetForm(); + }) + .catch(this.$fhcAlert.handleSystemError) + .finally(() => { + this.reload(); + }); + }, + deletePlacementTest(rt_person_id) { + console.log("delete Test" + rt_person_id); + return this.$api + .call(ApiStvAdmissionDates.deletePlacementTest(rt_person_id)) + .then(response => { + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successDelete')); + }) + .catch(this.$fhcAlert.handleSystemError) + .finally(() => { + this.reload(); + }); + }, + resetForm() { + console.log("resetForm"); + this.formData = {}; + /* + + this.formData.von = new Date(); + this.formData.bis = new Date(); + this.formData.mobilitaetsprogramm_code = 7; + this.formData.nation_code = 'A'; + this.formData.herkunftsland_code = 'A'; + this.formData.rt_id = null; + this.formData.localPurposes = []; + this.formData.localSupports = []; + this.formData.lehrveranstaltung_id = '', + this.formData.lehreinheit_id = '', + this.statusNew = true; + this.listLes = [];*/ + }, + }, created() { + this.$api + .call(ApiStvAdmissionDates.getListPlacementTests()) + .then(result => { + this.listPlacementTests = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + + this.$api + .call(ApiStvAdmissionDates.getListStudyPlans(this.student.person_id)) + .then(result => { + this.listStudyPlans = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); }, template: ` -
+

Allgemein

+ {{formData}} + + + + + + + + + + + + +
+ + + + +
+ +
+ + +
+ +
+ + +
+ +
+ + + + +
+ +
+ + +
+ + + + +
+ + +
` } diff --git a/system/phrasesupdate.php b/system/phrasesupdate.php index bf18f50c8..66fd48a8b 100644 --- a/system/phrasesupdate.php +++ b/system/phrasesupdate.php @@ -41436,6 +41436,106 @@ and represent the current state of research on the topic. The prescribed citatio ) ) ), + array( + 'app' => 'core', + 'category' => 'admission', + 'phrase' => 'admission_edit', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Aufnahmetermin bearbeiten', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Edit appointment for participation placement test', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'admission', + 'phrase' => 'admission_delete', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Aufnahmetermin Löschen', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Delete Admission Date', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'admission', + 'phrase' => 'admission_new', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Termin für Teilnahme am Reihungstest anlegen', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Create appointment for participation placement test', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'admission', + 'phrase' => 'anmeldundRtAm', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Anmeldung zum Reihungstest am', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Registration for the ranking test on', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'admission', + 'phrase' => 'rtAngetreten', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Zum Reihungstest angetreten', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Participated in the ranking test', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), // FHC4 STUDIERENDENVERWALTUNG AUFNAHMETERMINE ENDE --------------------------------------------------------------- ); From 9d4568e15eea009573960a8edb56bc2c79f57f4f Mon Sep 17 00:00:00 2001 From: ma0068 Date: Thu, 8 May 2025 09:58:08 +0200 Subject: [PATCH 032/107] client side placementtest handling, filtering Dropdowns placementtests, Phrases, show future Placementtests, open Reihungstestverwaltung --- .../api/frontend/v1/stv/Aufnahmetermine.php | 209 ++++++++++- application/models/crm/Reihungstest_model.php | 222 ++++++++++-- .../models/person/Benutzergruppe_model.php | 12 + application/models/testtool/Ablauf_model.php | 27 ++ application/views/Studentenverwaltung.php | 5 +- public/js/api/factory/stv/admissionDates.js | 41 ++- .../js/components/Stv/Studentenverwaltung.js | 5 +- .../Details/Aufnahmetermine.js | 2 +- .../Aufnahmetermine/Aufnahmetermine.js | 338 +++++++++++++----- .../Aufnahmetermine/HeaderReihungstest.js | 145 +++++++- rdf/reihungstest.rdf.php | 5 + system/phrasesupdate.php | 280 +++++++++++++++ 12 files changed, 1157 insertions(+), 134 deletions(-) diff --git a/application/controllers/api/frontend/v1/stv/Aufnahmetermine.php b/application/controllers/api/frontend/v1/stv/Aufnahmetermine.php index 6b0356bc3..538626789 100644 --- a/application/controllers/api/frontend/v1/stv/Aufnahmetermine.php +++ b/application/controllers/api/frontend/v1/stv/Aufnahmetermine.php @@ -14,9 +14,13 @@ class Aufnahmetermine extends FHCAPI_Controller 'insertAufnahmetermin' => ['admin:rw', 'assistenz:rw'], 'updateAufnahmetermin' => ['admin:rw', 'assistenz:rw'], 'deleteAufnahmetermin' => ['admin:rw', 'assistenz:rw'], - 'getListPlacementTests' => ['admin:rw', 'assistenz:rw'], - 'getListStudyPlans' => ['admin:rw', 'assistenz:rw'], - + 'getListPlacementTests' => ['admin:r', 'assistenz:r'], + 'getListStudyPlans' => ['admin:r', 'assistenz:r'], + 'loadDataRtPrestudent' => ['admin:r', 'assistenz:r'], + 'insertOrUpdateDataRtPrestudent' => ['admin:r', 'assistenz:r'], + 'loadAufnahmegruppen' => ['admin:r', 'assistenz:r'], + 'getResultReihungstest' => ['admin:r', 'assistenz:r'], + 'getZukuenftigeReihungstestStg' => ['admin:r', 'assistenz:r'], ]); // Load Libraries @@ -169,7 +173,8 @@ class Aufnahmetermine extends FHCAPI_Controller 'punkte' => $_POST['punkte'], 'insertamum' => date('c'), 'insertvon' => $authUID, - ]); + ] + ); $data = $this->getDataOrTerminateWithError($result); @@ -186,9 +191,53 @@ class Aufnahmetermine extends FHCAPI_Controller $this->terminateWithSuccess($data); } - public function getListPlacementTests() + public function getListPlacementTests($prestudent_id) { - $result = $this->ReihungstestModel->getAllReihungstests(); + if(!$prestudent_id) + { + return $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Prestudent ID']), self::ERROR_TYPE_GENERAL); + } + + //get studienplan array + $this->load->model('crm/Prestudentstatus_model', 'PrestudentstatusModel'); + + $this->PrestudentstatusModel->addSelect('*'); + $this->PrestudentstatusModel->addSelect('sp.studienplan_id'); + + $this->PrestudentstatusModel->addJoin('lehre.tbl_studienplan sp', 'studienplan_id', 'LEFT'); + + $result = $this->PrestudentstatusModel->loadWhere( + array( + 'prestudent_id' => $prestudent_id, + 'status_kurzbz' => 'Interessent' + ) + ); + + $data = $this->getDataOrTerminateWithError($result); + + $studienplan_arr = []; + $include_ids = []; + foreach ($data as $item) + { + if($item->studienplan_id != null) + $studienplan_arr[] = $item->studienplan_id; + } + + //get Placementtests Person + $person_id = $this->_getPersonId($prestudent_id); + $resultRt = $this->ReihungstestModel->getReihungstestPerson($person_id); + + $dataRt = $this->getDataOrTerminateWithError($resultRt); + + foreach ($dataRt as $item) + { + if(!in_array($item->studienplan_id, $studienplan_arr)) + $studienplan_arr[] = $item->studienplan_id; + if(!in_array($item->rt_id, $include_ids) && ($item->rt_id != null)) + $include_ids[] = $item->rt_id; + } + + $result = $this->ReihungstestModel->getReihungstestByStudyPlanAndIds($studienplan_arr, $include_ids); $data = $this->getDataOrTerminateWithError($result); $this->terminateWithSuccess($data); @@ -196,12 +245,156 @@ class Aufnahmetermine extends FHCAPI_Controller public function getListStudyPlans($person_id) { - $this->load->model('organisation/Studienplan_model','StudienplanModel'); + $this->load->model('organisation/Studienplan_model', 'StudienplanModel'); - $result = $this->StudienplanModel->getStudienplaeneForPerson($person_id);; + $result = $this->StudienplanModel->getStudienplaeneForPerson($person_id); $data = $this->getDataOrTerminateWithError($result); $this->terminateWithSuccess($data); } + public function loadDataRtPrestudent($prestudent_id) + { + $this->load->model('crm/Prestudent_model', 'PrestudentModel'); + + $this->PrestudentModel->addSelect(["reihungstestangetreten"]); + $this->PrestudentModel->addSelect(["rt_gesamtpunkte"]); + $this->PrestudentModel->addSelect(["aufnahmegruppe_kurzbz"]); + $result = $this->PrestudentModel->loadWhere( + array('prestudent_id' => $prestudent_id) + ); + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess(current($data)); + } + + public function insertOrUpdateDataRtPrestudent() + { + $this->load->library('form_validation'); + $authUID = getAuthUID(); + + $formData = $this->input->post('formData'); + $prestudent_id = $this->input->post('prestudent_id'); + + if(!$prestudent_id) + { + return $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Prestudent ID']), self::ERROR_TYPE_GENERAL); + } + $_POST['rt_gesamtpunkte'] = + (isset($formData['rt_gesamtpunkte']) && !empty($formData['rt_gesamtpunkte'])) + ? $formData['rt_gesamtpunkte'] + : null; + $_POST['reihungstestangetreten'] = + (isset($formData['reihungstestangetreten']) && !empty($formData['reihungstestangetreten'])) + ? $formData['reihungstestangetreten'] + : null; + $_POST['aufnahmegruppe_kurzbz'] = + (isset($formData['aufnahmegruppe_kurzbz']) && !empty($formData['aufnahmegruppe_kurzbz'])) + ? $formData['aufnahmegruppe_kurzbz'] + : null; + + $this->form_validation->set_rules('rt_gesamtpunkte', 'Rt_gesamtpunkte', 'numeric', [ + 'required' => $this->p->t('ui', 'error_fieldNotNumeric', ['field' => 'Rt_gesamtpunkte']) + ]); + + if ($this->form_validation->run() == false) + { + $this->terminateWithValidationErrors($this->form_validation->error_array()); + } + + $this->load->model('crm/Prestudent_model', 'PrestudentModel'); + + $result = $this->PrestudentModel->update( + [ + 'prestudent_id' => $prestudent_id, + ], + [ + 'reihungstestangetreten' => $_POST['reihungstestangetreten'], + 'rt_gesamtpunkte' => $_POST['rt_gesamtpunkte'], + 'aufnahmegruppe_kurzbz' => $_POST['aufnahmegruppe_kurzbz'], + 'updateamum' => date('c'), + 'updatevon' => $authUID, + ] + ); + + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + + public function loadAufnahmegruppen() + { + $uid = $this->input->get('uid'); + $studiensemester_kurzbz = $this->input->get('studiensemester_kurzbz'); + + $this->load->model('person/Benutzergruppe_model', 'BenutzergruppeModel'); + + $result = $this->BenutzergruppeModel->loadAufnahmegruppen($uid, $studiensemester_kurzbz); + + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess(($data)); + } + + public function getResultReihungstest() + { + $person_id = $this->input->get('person_id'); + $punkte = $this->input->get('punkte'); + $reihungstest_id = $this->input->get('reihungstest_id'); + + if(!$reihungstest_id) + { + $this->terminateWithSuccess(null); + } + + //for gewichtung + $studiengang_kz = $this->input->get('studiengang_kz'); + + $this->load->model('testtool/Ablauf_model', 'AblaufModel'); + $result = $this->AblaufModel->getAblaufGebieteAndGewichte($studiengang_kz); + $data = $this->getDataOrTerminateWithError($result); + + $weightedArray = []; + foreach ($data as $abl) + { + $weightedArray[$abl->gebiet_id] = $abl->gewicht; + } + + $result = $this->ReihungstestModel->getReihungstestErgebnisPerson($person_id, $punkte, $reihungstest_id, $weightedArray); + +/* if (isError($result)) + { + $this->terminateWithError($result, self::ERROR_TYPE_GENERAL); + }*/ + + $this->terminateWithSuccess($result); + } + + public function getZukuenftigeReihungstestStg() + { + $studiengang_kz = $this->input->get('studiengang_kz'); + if(!$studiengang_kz) + { + return $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Studiengang_kz']), self::ERROR_TYPE_GENERAL); + } + + $result = $this->ReihungstestModel->getZukuenftigeReihungstestStg($studiengang_kz); + + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + + private function _getPersonId($prestudent_id) + { + $this->load->model('crm/Prestudent_model', 'PrestudentModel'); + $result = $this->PrestudentModel->loadWhere( + ['prestudent_id' => $prestudent_id] + ); + + $data = $this->getDataOrTerminateWithError($result); + $person = current($data); + + return $person->person_id; + } } diff --git a/application/models/crm/Reihungstest_model.php b/application/models/crm/Reihungstest_model.php index 2eb08ee86..a685b01cd 100644 --- a/application/models/crm/Reihungstest_model.php +++ b/application/models/crm/Reihungstest_model.php @@ -530,14 +530,15 @@ class Reihungstest_model extends DB_Model tbl_reihungstest.max_teilnehmer, tbl_reihungstest.oeffentlich, tbl_reihungstest.freigeschaltet, - tbl_reihungstest.studiensemester_kurzbz, + tbl_reihungstest.studiensemester_kurzbz as studiensemester, tbl_reihungstest.stufe, tbl_reihungstest.anmeldefrist, tbl_reihungstest.aufnahmegruppe_kurzbz, tbl_studiengang.typ, UPPER(typ::varchar(1) || kurzbz) AS stg_kuerzel, so.studiengangbezeichnung, - so.studiengangbezeichnung_englisch + so.studiengangbezeichnung_englisch, + so.studiengangkurzbzlang FROM public.tbl_rt_person JOIN public.tbl_reihungstest ON (rt_id=reihungstest_id) @@ -552,35 +553,208 @@ class Reihungstest_model extends DB_Model } /** - * Loads all placement tests - * @return array Returns object array with data of placement tests + * Calculates Result of Placement Test for a given Person and given placementtest + * and with taking account of weighting per area + * + * @param $person_id ID of Person + * @param $punkte if true result is points else result is percentage of sum + * @param $reihungstest_id ID of Placementtest + * @param $weightedArray array of weighting per area (gewicht per gebiet_id) + * @return float result */ - //TODO(Manu) finish Details - public function getAllReihungstests() + public function getReihungstestErgebnisPerson($person_id, $punkte, $reihungstest_id, $weightedArray = null) { - $query = ' - SELECT * FROM public.tbl_reihungstest - JOIN public.tbl_studiengang ON tbl_reihungstest.studiengang_kz = tbl_studiengang.studiengang_kz - -- JOIN lehre.tbl_studienplan sp USING(studienplan_id) - -- JOIN lehre.tbl_studienordnung so USING(studienordnung_id) - ORDER BY datum DESC NULLS LAST, uhrzeit - '; + $parametersArray = array($reihungstest_id); - return $this->execQuery($query); + $qry = " + SELECT DISTINCT ON (vw_auswertung_ablauf.gebiet_id) gebiet_id, + vw_auswertung_ablauf.*, + tbl_studiengang.typ + FROM + testtool.vw_auswertung_ablauf + JOIN + public.tbl_studiengang USING (studiengang_kz) + WHERE + reihungstest_id = ? "; + + //using prestudent Status to avoid to get the sum of more than 1 placement tests + $qry .= " + AND prestudent_id = ( + SELECT + prestudent_id + FROM + public.tbl_rt_person + JOIN + public.tbl_prestudent USING(person_id) + JOIN + public.tbl_prestudentstatus USING (prestudent_id, studienplan_id) + JOIN + tbl_reihungstest ON ( + tbl_rt_person.rt_id = tbl_reihungstest.reihungstest_id + ) + WHERE + tbl_rt_person.person_id = ? + AND + tbl_rt_person.rt_id = ? + AND + tbl_prestudentstatus.status_kurzbz = 'Interessent' + AND + tbl_prestudentstatus.studiensemester_kurzbz = tbl_reihungstest.studiensemester_kurzbz + ORDER BY tbl_reihungstest.datum DESC, tbl_prestudent.priorisierung ASC LIMIT 1 + ) + "; + array_push($parametersArray, $person_id); + array_push($parametersArray, $reihungstest_id); + + $resultRtPerson = $this->execQuery($qry, $parametersArray); + + $ergebnis = 0; + $summeGewicht = 0; + + foreach ($resultRtPerson->retval as $row) + { + $prozent = 0; + if($row->punkte>=$row->maxpunkte) + { + $prozent = 100; + $row->punkte = $row->maxpunkte; + } + else + $prozent = (($row->punkte + $row->offsetpunkte)/($row->maxpunkte + $row->offsetpunkte))*100; + + if($punkte == 'true') + { + if($row->punkte) + { + $ergebnis += $row->punkte; + } + } + else + { + if ($row->punkte) + { + $gew = isset($weightedArray[$row->gebiet_id]) ? $weightedArray[$row->gebiet_id] : 1; + $ergebnis += $prozent * $gew; + $summeGewicht += $gew; + } + } + } + $return = $summeGewicht > 0 + ? number_format($ergebnis/$summeGewicht, 4, '.', '') + : number_format($ergebnis, 4, '.', ''); + + return $return; } - public function getReihungstestsPs($prestudent_id) + /** + * returns Reihungstests for given studyplans and include_ids + * + * @param Array $studienplan_arr array of studienplaene + * @param Array $include_ids array of include_ids + * @return Array List of Reihungstests + */ + public function getReihungstestByStudyPlanAndIds($studienplan_arr, $include_ids = null) { - $query = ' - SELECT * FROM public.tbl_reihungstest - JOIN public.tbl_studiengang ON tbl_reihungstest.studiengang_kz = tbl_studiengang.studiengang_kz - JOIN lehre.tbl_studienplan sp USING(studienplan_id) - JOIN lehre.tbl_studienordnung so USING(studienordnung_id) - ORDER BY datum DESC, uhrzeit - '; + $studienplan_ids_string = implode(',', $studienplan_arr); + $studienplan_arr = explode(',', $studienplan_ids_string); - return $this->execQuery($query); + $parametersArray = array($studienplan_arr); + + $qry = " + SELECT + distinct a.*, + CASE EXTRACT(DOW FROM a.datum) + WHEN 0 THEN 'So' + WHEN 1 THEN 'Mo' + WHEN 2 THEN 'Di' + WHEN 3 THEN 'Mi' + WHEN 4 THEN 'Do' + WHEN 5 THEN 'Fr' + WHEN 6 THEN 'Sa' + END AS wochentag, + sg.kurzbzlang as stg, + ( + SELECT count(*) FROM public.tbl_rt_person + WHERE rt_id = a.reihungstest_id + ) as angemeldete_teilnehmer + FROM + public.tbl_reihungstest a + JOIN public.tbl_rt_studienplan USING(reihungstest_id) + JOIN public.tbl_studiengang sg USING(studiengang_kz) + WHERE studienplan_id IN ?"; + + if($include_ids && is_array($include_ids) && count($include_ids) > 0) + { + $include_ids_string = implode(',', $include_ids); + $include_ids = explode(',', $include_ids_string); + + array_push($parametersArray, $include_ids); + + $qry .= "OR reihungstest_id in ?"; + } + $qry .= "ORDER BY a.datum DESC"; + + return $this->execQuery($qry, $parametersArray); } + /** + * returns Reihungstests for given studyplans and include_ids + * + * @param Integer $studiengang_kz + * @param $include_id optional (here null) + * @return Array List of Reihungstests + */ + public function getZukuenftigeReihungstestStg($studiengang_kz, $include_id = null) + { + $parametersArray = array($studiengang_kz, $studiengang_kz, $include_id); + $qry = " + SELECT *, + CASE EXTRACT(DOW FROM a.datum) + WHEN 0 THEN 'So' + WHEN 1 THEN 'Mo' + WHEN 2 THEN 'Di' + WHEN 3 THEN 'Mi' + WHEN 4 THEN 'Do' + WHEN 5 THEN 'Fr' + WHEN 6 THEN 'Sa' + END AS wochentag, + ( + SELECT count(*) FROM public.tbl_prestudent + WHERE reihungstest_id=a.reihungstest_id + ) as angemeldete_teilnehmer + FROM + ( + SELECT *, '1' as sortierung, + ( + SELECT upper(typ || kurzbz) FROM public.tbl_studiengang + WHERE studiengang_kz=tbl_reihungstest.studiengang_kz + ) as stg + FROM + public.tbl_reihungstest + WHERE + datum>=now()-'1 days'::interval AND studiengang_kz=? + UNION + SELECT *, '2' as sortierung, + ( + SELECT upper(typ || kurzbz) FROM public.tbl_studiengang + WHERE studiengang_kz=tbl_reihungstest.studiengang_kz + ) as stg + FROM + public.tbl_reihungstest + WHERE datum>=now()-'1 days'::interval AND studiengang_kz!=? + UNION + SELECT *, '0' as sortierung, + ( + SELECT upper(typ || kurzbz) FROM public.tbl_studiengang + WHERE studiengang_kz=tbl_reihungstest.studiengang_kz + ) as stg + FROM + public.tbl_reihungstest + WHERE reihungstest_id=? + ORDER BY sortierung, stg, datum + ) a + "; -} \ No newline at end of file + return $this->execQuery($qry, $parametersArray); + } +} diff --git a/application/models/person/Benutzergruppe_model.php b/application/models/person/Benutzergruppe_model.php index fba797641..271402ffe 100644 --- a/application/models/person/Benutzergruppe_model.php +++ b/application/models/person/Benutzergruppe_model.php @@ -33,4 +33,16 @@ class Benutzergruppe_model extends DB_Model $uids = (hasData($res)) ? getData($res) : array(); return $uids; } + + /** + * Laedt die Aufnahmegruppe(n) in Abhängigkeit von User und Studiensemester + * @param uid, gruppe_kurzbz, studiensemester_kurzbz + * @return array + */ + public function loadAufnahmegruppen($uid, $stsem) + { + $query = " + SELECT * FROM tbl_gruppe WHERE aufnahmegruppe=true;"; + return $this->execReadOnlyQuery($query); + } } diff --git a/application/models/testtool/Ablauf_model.php b/application/models/testtool/Ablauf_model.php index 748926658..d6d6ebe74 100644 --- a/application/models/testtool/Ablauf_model.php +++ b/application/models/testtool/Ablauf_model.php @@ -11,4 +11,31 @@ class Ablauf_model extends DB_Model $this->dbTable = 'testtool.tbl_ablauf'; $this->pk = 'ablauf_id'; } + + /** + * Returns Weighting of the respective ranking test areas + * @param $studiengang_kz Studiengang_kz + * @param $semester Integer optional + * @return array of weightings per ranking test areas of given studiengang + */ + public function getAblaufGebieteAndGewichte($studiengang_kz, $semester = null) + { + $parametersArray = array($studiengang_kz); + + $qry = " + SELECT + tbl_ablauf.gebiet_id, tbl_ablauf.gewicht + FROM + testtool.tbl_ablauf + WHERE + tbl_ablauf.studiengang_kz= ?"; + + if($semester) + { + $qry .= " AND semester = ?"; + array_push($parametersArray, $semester); + + } + return $this->execQuery($qry, $parametersArray); + } } diff --git a/application/views/Studentenverwaltung.php b/application/views/Studentenverwaltung.php index c10dc475a..8e4c523d6 100644 --- a/application/views/Studentenverwaltung.php +++ b/application/views/Studentenverwaltung.php @@ -37,7 +37,10 @@ $configArray = [ //replaced by possibility to hide each formular field via config stv.php #'showZgvDoktor' => !defined('ZGV_DOKTOR_ANZEIGEN') ? false : ZGV_DOKTOR_ANZEIGEN, #'showZgvErfuellt' => !defined('ZGV_ERFUELLT_ANZEIGEN') ? false : ZGV_ERFUELLT_ANZEIGEN - 'showHintKommPrfg' => !defined('FAS_STUDSTATUS_SHOW_KOMM_PRFG_HINT') ? false : FAS_STUDSTATUS_SHOW_KOMM_PRFG_HINT + 'showHintKommPrfg' => !defined('FAS_STUDSTATUS_SHOW_KOMM_PRFG_HINT') ? false : FAS_STUDSTATUS_SHOW_KOMM_PRFG_HINT, + 'showAufnahmegruppen' => !defined('FAS_REIHUNGSTEST_AUFNAHMEGRUPPEN') ? false : FAS_REIHUNGSTEST_AUFNAHMEGRUPPEN, + 'allowUebernahmePunkte' => !defined('FAS_REIHUNGSTEST_PUNKTEUEBERNAHME') ? true : FAS_REIHUNGSTEST_PUNKTEUEBERNAHME, + 'useReihungstestPunkte' => !defined('FAS_REIHUNGSTEST_PUNKTE') ? true : FAS_REIHUNGSTEST_PUNKTE, ]; ?> diff --git a/public/js/api/factory/stv/admissionDates.js b/public/js/api/factory/stv/admissionDates.js index a5b0697da..a6d743276 100644 --- a/public/js/api/factory/stv/admissionDates.js +++ b/public/js/api/factory/stv/admissionDates.js @@ -22,10 +22,10 @@ export default { url: 'api/frontend/v1/stv/aufnahmetermine/getAufnahmetermine/' + person_id, }; }, - getListPlacementTests(){ + getListPlacementTests(prestudent_id){ return { method: 'get', - url: 'api/frontend/v1/stv/aufnahmetermine/getListPlacementTests/', + url: 'api/frontend/v1/stv/aufnahmetermine/getListPlacementTests/' + prestudent_id, }; }, getListStudyPlans(person_id){ @@ -59,6 +59,41 @@ export default { method: 'post', url: 'api/frontend/v1/stv/aufnahmetermine/deleteAufnahmetermin/' + rt_person_id }; - } + }, + loadDataRtPrestudent(prestudent_id){ + return { + method: 'get', + url: 'api/frontend/v1/stv/aufnahmetermine/loadDataRtPrestudent/' + prestudent_id, + }; + }, + saveDataRtPrestudent(params){ + return { + method: 'post', + url: 'api/frontend/v1/stv/aufnahmetermine/insertOrUpdateDataRtPrestudent/', + params + }; + }, + loadAufnahmegruppen(params){ + return { + method: 'get', + url: 'api/frontend/v1/stv/aufnahmetermine/loadAufnahmegruppen/', + params + }; + }, + getResultReihungstest(params){ + return { + method: 'get', + url: 'api/frontend/v1/stv/aufnahmetermine/getResultReihungstest/', + params + }; + }, + loadFutureReihungstests(params){ + return { + method: 'get', + url: 'api/frontend/v1/stv/aufnahmetermine/getZukuenftigeReihungstestStg/', + params + }; + }, + } \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung.js b/public/js/components/Stv/Studentenverwaltung.js index 248cfd55c..36340a767 100644 --- a/public/js/components/Stv/Studentenverwaltung.js +++ b/public/js/components/Stv/Studentenverwaltung.js @@ -65,7 +65,10 @@ export default { defaultSemester: this.defaultSemester, $reloadList: () => { this.$refs.stvList.reload(); - } + }, + configShowAufnahmegruppen: this.config.showAufnahmegruppen, + configAllowUebernahmePunkte: this.config.allowUebernahmePunkte, + configUseReihungstestPunkte: this.config.useReihungstestPunkte } }, data() { diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Aufnahmetermine.js b/public/js/components/Stv/Studentenverwaltung/Details/Aufnahmetermine.js index 4ad8c6002..53ae524e0 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Aufnahmetermine.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Aufnahmetermine.js @@ -20,7 +20,7 @@ export default { }, template: `
- +
` }; \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Aufnahmetermine/Aufnahmetermine.js b/public/js/components/Stv/Studentenverwaltung/Details/Aufnahmetermine/Aufnahmetermine.js index 5fe32e885..cf8a47dd3 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Aufnahmetermine/Aufnahmetermine.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Aufnahmetermine/Aufnahmetermine.js @@ -14,10 +14,22 @@ export default { FormInput }, inject: { + allowUebernahmePunkte: { + from: 'configAllowUebernahmePunkte', + default: true + }, + //if true use punkte, false: use percentage + useReihungstestPunkte: { + from: 'configUseReihungstestPunkte', + default: true + }, $reloadList: { from: '$reloadList', required: true }, + cisRoot: { + from: 'cisRoot' + }, }, props: { student: Object @@ -31,9 +43,9 @@ export default { ), ajaxResponse: (url, params, response) => response.data, columns: [ - {title: "rt_id", field: "rt_id"}, - {title: "rt_person_id", field: "rt_person_id"}, - {title: "person_id", field: "person_id"}, + {title: "rt_id", field: "rt_id", visible: false}, + {title: "rt_person_id", field: "rt_person_id", visible: false}, + {title: "person_id", field: "person_id", visible: false}, {title: "datum", field: "datum", formatter: function (cell) { const dateStr = cell.getValue(); @@ -48,7 +60,7 @@ export default { } }, {title: "stufe", field: "stufe"}, - {title: "studiensemester", field: "studiensemester_kurzbz"}, + {title: "studiensemester", field: "studiensemester"}, {title: "anmerkung", field: "anmerkung", visible: false}, {title: "anmeldedatum", field: "anmeldedatum", visible: false, formatter: function (cell) { @@ -64,11 +76,20 @@ export default { } }, {title: "punkte", field: "punkte"}, - {title: "teilgenommen", field: "teilgenommen"}, + { + title: "teilgenommen", field: "teilgenommen", + formatter: "tickCross", + hozAlign: "center", + formatterParams: { + tickElement: '', + crossElement: '' + } + }, {title: "ort", field: "ort", visible: false}, {title: "studienplan", field: "studienplan", visible: false}, {title: "studienplan_id", field: "studienplan_id", visible: false}, - {title: "stg_kuerzel", field: "stg_kuerzel"}, + {title: "stg", field: "studiengangkurzbzlang"}, + {title: "Stg", field: "stg_kuerzel"}, { title: 'Aktionen', field: 'actions', minWidth: 150, // Ensures Action-buttons will be always fully displayed @@ -106,21 +127,77 @@ export default { index: 'aufnahmetermin_id', persistenceID: 'stv-details-table_admission-dates' }, - tabulatorEvents: [], + tabulatorEvents: [ + { + event: 'tableBuilt', + handler: async () => { + await this.$p.loadCategory(['admission', 'global', 'person', 'ui', 'projektarbeitsbeurteilung']); + let cm = this.$refs.table.tabulator.columnManager; + + cm.getColumnByField('rt_id').component.updateDefinition({ + title: this.$p.t('ui', 'reihungstest_id') + }); + cm.getColumnByField('rt_person_id').component.updateDefinition({ + title: this.$p.t('ui', 'reihungstest_person_id') + }); + cm.getColumnByField('person_id').component.updateDefinition({ + title: this.$p.t('person', 'person_id') + }); + cm.getColumnByField('datum').component.updateDefinition({ + title: this.$p.t('global', 'datum') + }); + cm.getColumnByField('stufe').component.updateDefinition({ + title: this.$p.t('admission', 'stufe') + }); + cm.getColumnByField('studiensemester').component.updateDefinition({ + title: this.$p.t('lehre', 'studiensemester') + }); + cm.getColumnByField('anmerkung').component.updateDefinition({ + title: this.$p.t('global', 'anmerkung') + }); + cm.getColumnByField('anmeldedatum').component.updateDefinition({ + title: this.$p.t('admission', 'anmeldedatum') + }); + cm.getColumnByField('punkte').component.updateDefinition({ + title: this.$p.t('exam', 'punkte') + }); + cm.getColumnByField('teilgenommen').component.updateDefinition({ + title: this.$p.t('admission', 'teilgenommen') + }); + cm.getColumnByField('ort').component.updateDefinition({ + title: this.$p.t('person', 'ort') + }); + cm.getColumnByField('studienplan').component.updateDefinition({ + title: this.$p.t('lehre', 'studienplan') + }); + cm.getColumnByField('studienplan_id').component.updateDefinition({ + title: this.$p.t('ui', 'studienplan_id') + }); + cm.getColumnByField('studiengangkurzbzlang').component.updateDefinition({ + title: this.$p.t('projektarbeitsbeurteilung', 'studiengang') + }); + cm.getColumnByField('stg_kuerzel').component.updateDefinition({ + title: this.$p.t('admission', 'stg_kurz') + }); + } + } + ], formData: {}, statusNew: true, listPlacementTests: [], - listStudyPlans: [] + listStudyPlans: [], + filterOnlyFutureTestsSet: false, + filteredPlacementTests: [] } }, methods: { actionNewPlacementTest() { this.resetForm(); this.statusNew = true; + this.formData.anmeldedatum = new Date(); this.$refs.placementTestModal.show(); }, actionEditPlacementTest(rt_person_id) { - console.log("edit Test " + rt_person_id); this.resetForm(); this.statusNew = false; this.loadPlacementTest(rt_person_id); @@ -159,7 +236,6 @@ export default { this.$refs.table.reloadTable(); }, loadPlacementTest(rt_person_id) { - console.log("load Test " + rt_person_id); return this.$api .call(ApiStvAdmissionDates.loadPlacementTest(rt_person_id)) .then(result => { @@ -185,7 +261,6 @@ export default { }); }, deletePlacementTest(rt_person_id) { - console.log("delete Test" + rt_person_id); return this.$api .call(ApiStvAdmissionDates.deletePlacementTest(rt_person_id)) .then(response => { @@ -196,30 +271,72 @@ export default { this.reload(); }); }, - resetForm() { - console.log("resetForm"); - this.formData = {}; - /* + getResultReihungstest(reihungstest_id){ + const paramsRt = { + reihungstest_id: reihungstest_id, + person_id: this.student.person_id, + punkte: this.useReihungstestPunkte, + studiengang_kz: this.student.studiengang_kz + }; - this.formData.von = new Date(); - this.formData.bis = new Date(); - this.formData.mobilitaetsprogramm_code = 7; - this.formData.nation_code = 'A'; - this.formData.herkunftsland_code = 'A'; - this.formData.rt_id = null; - this.formData.localPurposes = []; - this.formData.localSupports = []; - this.formData.lehrveranstaltung_id = '', - this.formData.lehreinheit_id = '', - this.statusNew = true; - this.listLes = [];*/ + return this.$api + .call(ApiStvAdmissionDates.getResultReihungstest(paramsRt)) + .then(response => { + this.formData.punkte = response.data; + }) + .catch(this.$fhcAlert.handleSystemError) + .finally(() => { + this.reload(); + }); + }, + loadFutureReihungstests(){ + const arrayReihungstestIds = this.listPlacementTests.map(item => item.reihungstest_id); + const paramsRt = { + studiengang_kz: this.student.studiengang_kz, + arrayReihungstestIds : arrayReihungstestIds + }; + + return this.$api + .call(ApiStvAdmissionDates.loadFutureReihungstests(paramsRt)) + .then(response => { + this.filteredPlacementTests = response.data; + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'filterOnlyFutureActive')); + this.$refs.filterButton.className = 'btn btn-secondary w-100'; + this.$refs.filterButton.title = this.$p.t('ui', 'alleAnzeigen'); + }) + .catch(this.$fhcAlert.handleSystemError) + .finally(() => { + this.reload(); + }); + }, + toggleFilter(){ + this.filterOnlyFutureTestsSet = !this.filterOnlyFutureTestsSet; + + if(this.filterOnlyFutureTestsSet) { + this.loadFutureReihungstests(); + } + else + { + this.filteredPlacementTests = this.listPlacementTests; + this.$refs.filterButton.className = 'btn btn-outline-secondary w-100'; + this.$refs.filterButton.title = this.$p.t('admission', 'loadZukuenftigeRT');} + }, + openAdministrationPlacementTest(reihungstest_id){ + let link = this.cisRoot + 'vilesci/stammdaten/reihungstestverwaltung.php'; + if(reihungstest_id){ + link += '?reihungstest_id=' + reihungstest_id; + } + window.open(link, '_blank'); + }, + resetForm() { + this.formData = {}; }, }, created() { this.$api - .call(ApiStvAdmissionDates.getListPlacementTests()) + .call(ApiStvAdmissionDates.getListPlacementTests(this.student.prestudent_id)) .then(result => { - this.listPlacementTests = result.data; + this.listPlacementTests = this.filteredPlacementTests = result.data; }) .catch(this.$fhcAlert.handleSystemError); @@ -232,7 +349,7 @@ export default { }, template: `
-

Allgemein

+

{{$p.t('admission', 'allgemein')}}

- {{formData}} - - - - - - + - -
- -
@@ -410,60 +407,56 @@ export default {
{{$p.t('ui', 'felder')}} {{$p.t('lehre', 'prestudent')}} -
- - - - -
+ + +
Felder Person -
- - - + + + -
{{$p.t('messages', 'meineFelder')}} -
- - - + + + -
@@ -508,9 +501,6 @@ export default {
- -
-
+ + + +
+
+
@@ -385,34 +398,35 @@ export default { type="textarea" v-model="formData.body" name="body" - rows="15" + rows="35" cols="75" >
-
- - -
-
+ +
+ + +
+
- {{$p.t('ui', 'felder')}} {{$p.t('lehre', 'prestudent')}} +
{{$p.t('ui', 'felder')}} {{$p.t('lehre', 'prestudent')}}