Add components and endpoints for room type CRD and room to room type relation CRD

This commit is contained in:
Ivymaster
2026-05-04 16:28:09 +02:00
parent fe507e4185
commit a44d0f65b3
15 changed files with 1269 additions and 195 deletions
+1 -1
View File
@@ -122,7 +122,7 @@ $route['api/frontend/v1/stv/[sS]tudents/([WS]S[0-9]{4})/person/(:num)'] = 'api/f
// load routes from extensions, also look for environment-specific configs
$subdirs = ['application/config/extensions', 'application/config/' . ENVIRONMENT . '/extensions'];
$route['lehre/RoomManager/.*'] = 'lehre/RoomManager/index';
$route['RoomManager/.*'] = 'RoomManager/index';
foreach($subdirs as $subdir)
{
+171 -110
View File
@@ -52,6 +52,7 @@ class Ort extends FHCAPI_Controller
$this->loadPhrases([
'global',
'ui',
'lehre'
]);
}
@@ -64,30 +65,49 @@ class Ort extends FHCAPI_Controller
$filterData = [];
$query = "SELECT public.tbl_ort.*, pr.ort_kurzbz as pr_ort_kurzbz, org.bezeichnung as org_bezeichnung
FROM public.tbl_ort
LEFT JOIN public.tbl_ort as pr ON pr.ort_kurzbz = public.tbl_ort.parent_ort_kurzbz
LEFT JOIN public.tbl_organisationseinheit as org ON org.oe_kurzbz = public.tbl_ort.oe_kurzbz";
$whereItems = [];
if (isset($filter['locationId']) && $filter['locationId'] !== '') {
$filterData['standort_id'] = $filter['locationId'];
$whereItems[] = 'public.tbl_ort.standort_id = ?';
$filterData[] = $filter['locationId'];
}
if (isset($filter['organizationalUnitShortCode']) && $filter['organizationalUnitShortCode'] !== '') {
$filterData['oe_kurzbz'] = $filter['organizationalUnitShortCode'];
$whereItems[] = 'public.tbl_ort.oe_kurzbz = ?';
$filterData[] = $filter['organizationalUnitShortCode'];
}
if (isset($filter['buildingComponent']) && $filter['buildingComponent'] !== '') {
$filterData['gebteil'] = $filter['buildingComponent'];
$whereItems[] = 'public.tbl_ort.gebteil = ?';
$filterData[] = $filter['buildingComponent'];
}
if (isset($filter['isForTrainingProgram']) && $filter['isForTrainingProgram'] === 'true') {
$filterData['lehre'] = $filter['isForTrainingProgram'] === 'true' ? true : false;
$whereItems[] = 'public.tbl_ort.lehre = ?';
$filterData[] = $filter['isForTrainingProgram'] === 'true' ? true : false;
}
if (isset($filter['isReservationNeeded']) && $filter['isReservationNeeded'] === 'true') {
$filterData['reservieren'] = $filter['isReservationNeeded'] === 'true' ? true : false;
$whereItems[] = 'public.tbl_ort.reservieren = ?';
$filterData[] = $filter['isReservationNeeded'] === 'true' ? true : false;
}
if (isset($filter['isActive']) && $filter['isActive'] === 'true') {
$filterData['aktiv'] = $filter['isActive'] === 'true' ? true : false;
$whereItems[] = 'public.tbl_ort.aktiv = ?';
$filterData[] = $filter['isActive'] === 'true' ? true : false;
}
if (count($whereItems) > 0) {
$query .= ' WHERE ' . implode(' AND ', $whereItems);
}
$this->OrtModel->addOrder("ort_kurzbz", "ASC");
$query .= ' ORDER BY public.tbl_ort.ort_kurzbz ASC';
$result = $this->OrtModel->loadWhere($filterData);
$this->terminateWithSuccess($this->getDataOrTerminateWithError($result));
$result = $this->OrtModel->execReadOnlyQuery($query, $filterData);
$this->terminateWithSuccess(getData($result));
}
/**
@@ -144,8 +164,7 @@ class Ort extends FHCAPI_Controller
)
";
$params = array_merge($params, [$datum, $vonStunde, $bisStunde, $datum, $vonStunde, $bisStunde]);
// $this->addMeta('qry', $qry);
// $this->addMeta('params', $params);
$result = $this->OrtModel->execReadOnlyQuery($qry, $params);
$this->terminateWithSuccess($result);
@@ -234,65 +253,81 @@ class Ort extends FHCAPI_Controller
public function createRoom()
{
$this->form_validation->set_rules('ort_kurzbz', 'ort_kurzbz', 'required', [
'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => $this->p->t('ui', 'shortCode')])
$this->form_validation->set_rules('ort_kurzbz', 'kurzbezeichnung', 'required|is_unique[tbl_ort.ort_kurzbz]', [
'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => $this->p->t('lehre', 'kurzbz')])
]);
$this->form_validation->set_rules('content_id', 'content_id', 'number', [
'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => $this->p->t('lehre', 'content_id')])
]);
if($this->form_validation->run() == FALSE) $this->terminateWithValidationErrors($this->form_validation->error_array());
$parent_ort_kurzbz = $this->input->post('parent_ort_kurzbz');
if ($parent_ort_kurzbz) {
$this->load->model('ressource/Ort_model', 'ParentRoomModel');
$parentRoom = $this->ParentRoomModel->load($parent_ort_kurzbz);
if (isError($parentRoom) || !hasData($parentRoom)) {
$this->terminateWithError("Parent room with shortcode $parent_ort_kurzbz does not exist", self::ERROR_TYPE_GENERAL);
}
}
$oe_kurzbz = $this->input->post('oe_kurzbz');
if ($oe_kurzbz) {
$this->load->model('organisation/Organisationseinheit_model', 'OrganisationseinheitModel');
$orgUnit = $this->OrganisationseinheitModel->load($oe_kurzbz);
if (isError($orgUnit) || !hasData($orgUnit)) {
$this->terminateWithError("Organizational unit with shortcode $oe_kurzbz does not exist", self::ERROR_TYPE_GENERAL);
}
}
$standort_id = $this->input->post('standort_id');
if ($standort_id) {
$this->load->model('organisation/Standort_model', 'StandortModel');
$location = $this->StandortModel->load($standort_id);
if (isError($location) || !hasData($location)) {
$this->terminateWithError("Location with id $standort_id does not exist", self::ERROR_TYPE_GENERAL);
}
}
$content_id = $this->input->post('content_id');
if ($content_id) {
$this->load->model('content/Content_model', 'ContentModel');
$content = $this->ContentModel->load($content_id);
if (isError($content) || !hasData($content)) {
$this->terminateWithError("Content with id $content_id does not exist", self::ERROR_TYPE_GENERAL);
}
}
$this->db->trans_start();
$result = $this->OrtModel->db->query("INSERT INTO public.tbl_ort
(
oe_kurzbz,
content_id,
standort_id,
ort_kurzbz,
bezeichnung,
planbezeichnung,
aktiv,
lehre,
reservieren,
max_person,
stockwerk,
lageplan,
dislozierung,
kosten,
ausstattung,
telefonklappe,
m2,
gebteil,
arbeitsplaetze,
insertamum,
insertvon,
updateamum,
updatevon
)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", [
$this->input->post('oe_kurzbz'),
$this->input->post('contentId'),
$this->input->post('standort_id'),
$this->input->post('ort_kurzbz'),
$this->input->post('bezeichnung'),
$this->input->post('planbezeichnung'),
$this->input->post('aktiv') ? true : false,
$this->input->post('lehre') ? true : false,
$this->input->post('reservieren') ? true : false,
$this->input->post('max_person'),
$this->input->post('stockwerk'),
$this->input->post('lageplan'),
$this->input->post('dislozierung'),
$this->input->post('kosten'),
$this->input->post('ausstattung'),
$this->input->post('telefonklappe'),
$this->input->post('m2'),
$this->input->post('gebteil'),
$this->input->post('arbeitsplatze'),
date('c'),
getAuthUid(),
date('c'),
getAuthUid()
]);
$data = [
"parent_ort_kurzbz" => $this->input->post('parent_ort_kurzbz'),
"oe_kurzbz" => $this->input->post('oe_kurzbz'),
"content_id" => !empty($this->input->post('content_id')) ? $this->input->post('content_id') : null,
"standort_id" => $this->input->post('standort_id'),
"ort_kurzbz" => $this->input->post('ort_kurzbz'),
"bezeichnung" => $this->input->post('bezeichnung'),
"planbezeichnung" => $this->input->post('planbezeichnung'),
"aktiv" => $this->input->post('aktiv') ? true : false,
"lehre" => $this->input->post('lehre') ? true : false,
"reservieren" => $this->input->post('reservieren') ? true : false,
"max_person" => $this->input->post('max_person'),
"stockwerk" => $this->input->post('stockwerk'),
"lageplan" => $this->input->post('lageplan'),
"dislozierung" => $this->input->post('dislozierung'),
"kosten" => $this->input->post('kosten'),
"ausstattung" => $this->input->post('ausstattung'),
"telefonklappe" => $this->input->post('telefonklappe'),
"m2" => $this->input->post('m2'),
"gebteil" => $this->input->post('gebteil'),
"arbeitsplaetze" => $this->input->post('arbeitsplatze'),
'insertamum' => date('c'),
'insertvon' => getAuthUid(),
'updateamum' => date('c'),
'updatevon' => getAuthUid()
];
$this->OrtModel->db->set($data);
$result = $this->OrtModel->db->insert($this->OrtModel->getDbTable());
$this->db->trans_complete();
@@ -306,52 +341,78 @@ class Ort extends FHCAPI_Controller
$this->terminateWithError("missing ort_kurzbz parameter", self::ERROR_TYPE_GENERAL);
}
$parent_ort_kurzbz = $this->input->post('parent_ort_kurzbz');
if ($parent_ort_kurzbz) {
$this->load->model('ressource/Ort_model', 'ParentRoomModel');
$parentRoom = $this->ParentRoomModel->load($parent_ort_kurzbz);
if (isError($parentRoom) || !hasData($parentRoom)) {
$this->terminateWithError("Parent room with shortcode $parent_ort_kurzbz does not exist", self::ERROR_TYPE_GENERAL);
}
}
$oe_kurzbz = $this->input->post('oe_kurzbz');
if ($oe_kurzbz) {
$this->load->model('organisation/Organisationseinheit_model', 'OrganisationseinheitModel');
$orgUnit = $this->OrganisationseinheitModel->load($oe_kurzbz);
if (isError($orgUnit) || !hasData($orgUnit)) {
$this->terminateWithError("Organizational unit with shortcode $oe_kurzbz does not exist", self::ERROR_TYPE_GENERAL);
}
}
$standort_id = $this->input->post('standort_id');
if ($standort_id) {
$this->load->model('organisation/Standort_model', 'StandortModel');
$location = $this->StandortModel->load($standort_id);
if (isError($location) || !hasData($location)) {
$this->terminateWithError("Location with id $standort_id does not exist", self::ERROR_TYPE_GENERAL);
}
}
$content_id = $this->input->post('content_id');
if ($content_id) {
$this->load->model('content/Content_model', 'ContentModel');
$content = $this->ContentModel->load($content_id);
if (isError($content) || !hasData($content)) {
$this->terminateWithError("Content with id $content_id does not exist", self::ERROR_TYPE_GENERAL);
}
}
$this->db->trans_start();
$result = $this->OrtModel->db->query("UPDATE public.tbl_ort SET
oe_kurzbz = ?,
content_id = ?,
standort_id = ?,
bezeichnung = ?,
planbezeichnung = ?,
aktiv = ?,
lehre = ?,
reservieren = ?,
max_person = ?,
stockwerk = ?,
lageplan = ?,
dislozierung = ?,
kosten = ?,
ausstattung = ?,
telefonklappe = ?,
m2 = ?,
gebteil = ?,
arbeitsplaetze = ?,
updateamum = ?,
updatevon = ?
WHERE ort_kurzbz = ?", [
$this->input->post('oe_kurzbz'),
$this->input->post('contentId'),
$this->input->post('standort_id'),
$this->input->post('bezeichnung'),
$this->input->post('planbezeichnung'),
$this->input->post('aktiv') ? true : false,
$this->input->post('lehre') ? true : false,
$this->input->post('reservieren') ? true : false,
$this->input->post('max_person'),
$this->input->post('stockwerk'),
$this->input->post('lageplan'),
$this->input->post('dislozierung'),
$this->input->post('kosten'),
$this->input->post('ausstattung'),
$this->input->post('telefonklappe'),
$this->input->post('m2'),
$this->input->post('gebteil'),
$this->input->post('arbeitsplatze'),
date('c'),
getAuthUid(),
$ort_kurzbz
]);
$fields = [
"parent_ort_kurzbz",
"oe_kurzbz",
"content_id",
"standort_id",
"bezeichnung",
"planbezeichnung",
"aktiv",
"lehre",
"reservieren",
"max_person",
"stockwerk",
"lageplan",
"dislozierung",
"kosten",
"ausstattung",
"telefonklappe",
"m2",
"gebteil",
"arbeitsplaetze"
];
foreach ($fields as $field) {
if (array_key_exists($field, $this->input->post())) {
$data[$field] = $this->input->post($field);
}
}
$data['updateamum'] = date('c');
$data['updatevon'] = getAuthUid();
$this->OrtModel->db->set($data);
$this->OrtModel->db->where('ort_kurzbz', $ort_kurzbz);
$result = $this->OrtModel->db->update($this->OrtModel->getDbTable());
$this->db->trans_complete();
@@ -0,0 +1,121 @@
<?php
/**
* Copyright (C) 2024 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 <https://www.gnu.org/licenses/>.
*/
if (! defined('BASEPATH')) exit('No direct script access allowed');
/**
* This controller operates between (interface) the JS (GUI) and the SearchBarLib (back-end)
* Provides data to the ajax get calls about the searchbar component
* This controller works with JSON calls on the HTTP GET and the output is always JSON
*/
class RoomToRoomTypeApi extends FHCAPI_Controller
{
/**
* Object initialization
*/
public function __construct()
{
// NOTE(chris): additional permission checks will be done in SearchBarLib
parent::__construct([
'getRoomToRoomTypeRelationsByRoomShortCode' => self::PERM_LOGGED,
'createRoomToRoomTypeRelation' => self::PERM_LOGGED,
'deleteRoomToRoomTypeRelation' => self::PERM_LOGGED,
]);
$this->load->library('form_validation');
$this->load->model('ressource/Ortraumtyp_model', 'OrtRoomTypeModel');
$this->loadPhrases([
'global',
'ui',
'lehre'
]);
}
//------------------------------------------------------------------------------------------------------------------
// Public methods
public function getRoomToRoomTypeRelationsByRoomShortCode($roomShortCode) {
$this->OrtRoomTypeModel->db->select('public.tbl_ortraumtyp.*, public.tbl_raumtyp.beschreibung as raumtyp_beschreibung');
$this->OrtRoomTypeModel->db->join('public.tbl_raumtyp', 'public.tbl_raumtyp.raumtyp_kurzbz = public.tbl_ortraumtyp.raumtyp_kurzbz', 'left');
$this->OrtRoomTypeModel->db->order_by('hierarchie', 'ASC');
$result = $this->OrtRoomTypeModel->loadWhere(['ort_kurzbz' => $roomShortCode]);
return $this->terminateWithSuccess($this->getDataOrTerminateWithError($result));
}
public function createRoomToRoomTypeRelation() {
$this->form_validation->set_rules('roomShortCode', 'roomShortCode', 'required', [
'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => $this->p->t('lehre', 'kurzbz')])
]);
$this->form_validation->set_rules('roomTypeShortCode', 'roomTypeShortCode', 'required', [
'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => $this->p->t('lehre', 'kurzbz')])
]);
$this->form_validation->set_rules('hierarchy', 'hierarchy', 'required|integer', [
'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => $this->p->t('ui', 'hierarchy')]),
'integer' => $this->p->t('ui', 'error_fieldInteger', ['field' => $this->p->t('ui', 'hierarchy')])
]);
if($this->form_validation->run() == FALSE) $this->terminateWithValidationErrors($this->form_validation->error_array());
$existingRelationResponse = $this->OrtRoomTypeModel->loadWhere([
'ort_kurzbz' => $this->input->post('roomShortCode'),
'hierarchie' => $this->input->post('hierarchy'),
]);
if (hasData($existingRelationResponse)) {
$this->terminateWithError($this->p->t('ui', 'error_roomToRoomTypeRelationAlreadyExists'), self::ERROR_TYPE_GENERAL);
}
$data = [
'ort_kurzbz' => $this->input->post('roomShortCode'),
'raumtyp_kurzbz' => $this->input->post('roomTypeShortCode'),
'hierarchie' => $this->input->post('hierarchy'),
];
$this->OrtRoomTypeModel->db->set($data);
$result = $this->OrtRoomTypeModel->db->insert($this->OrtRoomTypeModel->getDbTable());
if ($result === false) {
return $this->terminateWithError($this->OrtRoomTypeModel->getLastError());
}
return $this->terminateWithSuccess(['message' => 'Room to Room Type relation created successfully.']);
}
public function deleteRoomToRoomTypeRelation() {
$this->form_validation->set_rules('roomShortCode', 'roomShortCode', 'required');
$this->form_validation->set_rules('roomTypeShortCode', 'roomTypeShortCode', 'required');
if ($this->form_validation->run() === false) {
return $this->terminateWithError(validation_errors());
}
$result = $this->OrtRoomTypeModel->db->delete($this->OrtRoomTypeModel->getDbTable(), [
'ort_kurzbz' => $this->input->post('roomShortCode'),
'raumtyp_kurzbz' => $this->input->post('roomTypeShortCode'),
]);
if ($result === false) {
return $this->terminateWithError($this->OrtRoomTypeModel->getLastError());
}
return $this->terminateWithSuccess(['message' => 'Room to Room Type relation deleted successfully.']);
}
}
@@ -0,0 +1,83 @@
<?php
/**
* Copyright (C) 2024 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 <https://www.gnu.org/licenses/>.
*/
if (! defined('BASEPATH')) exit('No direct script access allowed');
/**
* This controller operates between (interface) the JS (GUI) and the SearchBarLib (back-end)
* Provides data to the ajax get calls about the searchbar component
* This controller works with JSON calls on the HTTP GET and the output is always JSON
*/
class RoomTypeApi extends FHCAPI_Controller
{
/**
* Object initialization
*/
public function __construct()
{
parent::__construct([
'getAllRoomTypes' => self::PERM_LOGGED,
'createRoomType' => self::PERM_LOGGED,
]);
$this->load->library('form_validation');
$this->load->model('ressource/Raumtyp_model', 'RoomTypeModel');
$this->loadPhrases([
'global',
'ui',
'lehre'
]);
}
//------------------------------------------------------------------------------------------------------------------
// Public methods
public function getAllRoomTypes() {
$this->RoomTypeModel->addOrder('raumtyp_kurzbz', 'ASC');
$result = $this->RoomTypeModel->load();
return $this->terminateWithSuccess($this->getDataOrTerminateWithError($result));
}
public function createRoomType() {
$this->form_validation->set_rules('kurzbezeichnung', 'kurzbezeichnung', 'required|max_length[255]|is_unique[tbl_raumtyp.raumtyp_kurzbz]', [
'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => $this->p->t('lehre', 'kurzbz')]),
'is_unique' => $this->p->t('ui', 'error_fieldUnique', ['field' => $this->p->t('lehre', 'kurzbz')]),
]);
$this->form_validation->set_rules('beschreibung', 'beschreibung', 'max_length[255]');
if($this->form_validation->run() == FALSE) $this->terminateWithValidationErrors($this->form_validation->error_array());
$data = [
'raumtyp_kurzbz' => $this->input->post('kurzbezeichnung'),
'beschreibung' => $this->input->post('beschreibung'),
];
$this->RoomTypeModel->db->set($data);
$result = $this->RoomTypeModel->db->insert($this->RoomTypeModel->getDbTable());
if ($result === false) {
return $this->terminateWithError($this->RoomTypeModel->getLastError());
}
return $this->terminateWithSuccess();
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
<?php
$includesArray = array(
'title' => 'Raumverwaltung',
'title' => ucfirst($this->p->t('ui', 'roomManagerPageTitle')),
'vue3' => true,
'axios027' => true,
'bootstrap5' => true,
+6 -6
View File
@@ -21,12 +21,12 @@ export default {
method: 'get',
url: 'api/frontend/v1/Ort/getAllRooms',
params: {
"filter[organizationalUnitShortCode]" : params.organizationalUnitShortCode,
"filter[locationId]" : params.locationId,
"filter[buildingComponent]" : params.buildingComponent,
"filter[isForTrainingProgram]" : params.isForTrainingProgram,
"filter[isReservationNeeded]" : params.isReservationNeeded,
"filter[isActive]" : params.isActive,
"filter[organizationalUnitShortCode]" : params?.organizationalUnitShortCode,
"filter[locationId]" : params?.locationId,
"filter[buildingComponent]" : params?.buildingComponent,
"filter[isForTrainingProgram]" : params?.isForTrainingProgram,
"filter[isReservationNeeded]" : params?.isReservationNeeded,
"filter[isActive]" : params?.isActive,
}
}
},
-18
View File
@@ -1,18 +0,0 @@
export default {
getAllRooms(params) {
console.log("API Call with params: ", params);
return {
method: 'get',
url: 'api/frontend/v1/Ort/getAllRooms',
params: {
"filter[organizationalUnitShortCode]" : params.organizationalUnitShortCode,
"filter[locationId]" : params.locationId,
"filter[buildingComponent]" : params.buildingComponent,
"filter[isForTrainingProgram]" : params.isForTrainingProgram,
"filter[isReservationNeeded]" : params.isReservationNeeded,
"filter[isActive]" : params.isActive,
}
}
},
};
+46
View File
@@ -0,0 +1,46 @@
/**
* 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 <https://www.gnu.org/licenses/>.
*/
export default {
getRoomToRoomTypeRelationsByRoomShortCode(roomShortCode) {
return {
method: 'get',
url: `api/frontend/v1/RoomToRoomTypeApi/getRoomToRoomTypeRelationsByRoomShortCode/${roomShortCode}`,
}
},
createRoomToRoomTypeRelation(roomShortCode, roomTypeShortCode, hierarchy) {
return {
method: 'post',
url: `api/frontend/v1/RoomToRoomTypeApi/createRoomToRoomTypeRelation`,
params: {
roomShortCode,
roomTypeShortCode,
hierarchy
},
}
},
deleteRoomToRoomTypeRelation(roomShortCode, roomTypeShortCode) {
return {
method: 'post',
url: `api/frontend/v1/RoomToRoomTypeApi/deleteRoomToRoomTypeRelation`,
params: {
roomShortCode,
roomTypeShortCode
},
}
}
};
+32
View File
@@ -0,0 +1,32 @@
/**
* 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 <https://www.gnu.org/licenses/>.
*/
export default {
getAllRoomTypes() {
return {
method: 'get',
url: 'api/frontend/v1/RoomTypeApi/getAllRoomTypes',
}
},
createRoomType(roomTypeData) {
return {
method: 'post',
url: 'api/frontend/v1/RoomTypeApi/createRoomType',
params: roomTypeData,
}
},
};
@@ -46,6 +46,8 @@ export default {
organizationalUnits: [],
filteredOrganizationalUnits: [],
locations: [],
rooms: [],
filteredRooms: [],
editedRoom: null,
roomFormData: {
aktiv: true,
@@ -61,6 +63,14 @@ export default {
};
});
},
dropdownParsedRooms() {
return this.rooms.map((room) => {
return {
label: `${room.ort_kurzbz} - ${room.bezeichnung}`,
value: room.ort_kurzbz,
};
});
},
},
methods: {
filterOrganizationalUnits(event) {
@@ -83,6 +93,26 @@ export default {
}),
));
},
filterRooms(event) {
let defaultItem = {
label: "----------",
value: null,
};
const query = event.query.toLowerCase();
if (!query) {
return (this.filteredRooms = [
defaultItem,
...this.dropdownParsedRooms,
]);
}
return (this.filteredRooms = [defaultItem]
.concat(this.dropdownParsedRooms)
.filter((room) => {
return room.label?.toLowerCase().includes(query);
}));
},
createRoom() {
return this.$refs.roomForm
.call(ApiRoom.createRoom(this.getApiCallParsedRoomFormData()))
@@ -108,19 +138,30 @@ export default {
return;
}
this.isEditInProgress = true;
let orgUnitData = null;
let orgUnit = this.organizationalUnits.find(
(unit) => unit.oe_kurzbz === this.editedRoom.oe_kurzbz,
);
if (orgUnit) {
orgUnitData = {
label: `${orgUnit.bezeichnung} (${orgUnit.organisationseinheittyp_kurzbz})`,
value: orgUnit.oe_kurzbz,
};
}
let orgUnitData = {
label: `${orgUnit.bezeichnung} (${orgUnit.organisationseinheittyp_kurzbz})`,
value: orgUnit.oe_kurzbz,
let parentRoom = this.rooms.find(
(room) => room.ort_kurzbz === this.editedRoom.parent_ort_kurzbz,
);
let parentRoomData = {
label: parentRoom?.bezeichnung || "",
value: parentRoom?.ort_kurzbz || null,
};
this.roomFormData = {
parentRoom: parentRoomData,
locationId: this.editedRoom.standort_id,
organizationalUnit: orgUnitData,
contentId: this.editedRoom.content_id,
@@ -161,6 +202,7 @@ export default {
},
getApiCallParsedRoomFormData() {
return {
parent_ort_kurzbz: this.roomFormData.parentRoom?.value,
standort_id: this.roomFormData.locationId,
oe_kurzbz: this.roomFormData.organizationalUnit?.value,
content_id: this.roomFormData.contentId,
@@ -188,6 +230,7 @@ export default {
this.resetRoomForm();
},
resetRoomForm() {
this.$refs.roomForm.clearValidation();
this.isEditInProgress = false;
this.editedRoom = null;
this.roomFormData = {
@@ -221,6 +264,18 @@ export default {
getAllOrganizationalUnitsResponse.meta.message,
);
}
let getRoomsResponse = await this.$api.call(
ApiRoom.getAllRooms(),
);
if (getRoomsResponse.meta.status === "success") {
this.rooms = getRoomsResponse.data;
} else {
console.error(
"Error fetching rooms:",
getRoomsResponse.meta.message,
);
}
},
template: /* html */ `
<bs-modal ref="roomFormModal" size="sm" @hideBsModal="() => { $emit('hideBsModal'); resetRoomForm(); }" class="modal-lg">
@@ -230,6 +285,21 @@ export default {
</template>
<template #default>
<core-form ref="roomForm" class="row g-3 pb-3">
<div class="row mb-3">
<form-input
v-model="roomFormData.parentRoom"
:label="$capitalize($p.t('ui/parentRoom'))"
:suggestions="filteredRooms"
:optionValue="(option) => option.value"
:optionLabel="(option) => option.label"
@complete="filterRooms"
dropdown
forceSelection
type="autocomplete"
name="parentRoomShortCode"
>
</form-input>
</div>
<div class="row mb-3">
<div class="col">
<form-input
@@ -249,7 +319,7 @@ export default {
<div class="col">
<form-input
v-model="roomFormData.locationId"
:label="$capitalize($p.t('global', 'raum'))"
:label="$capitalize($p.t('global/ortLocation'))"
type="select"
id="location"
name="location"
@@ -298,7 +368,7 @@ export default {
v-model="roomFormData.kurzbezeichnung"
:label="$capitalize($p.t('gruppenmanagement', 'kurzbezeichnung'))"
type="text"
name="kurzbezeichnung"
name="ort_kurzbz"
>
</form-input>
</div>
@@ -6,8 +6,7 @@ import { CoreFilterCmpt } from "../filter/Filter.js";
import CoreForm from "../Form/Form.js";
import FormInput from "../Form/Input.js";
import RoomFormModal from "./RoomFormModal.js";
import ApiCms from "../../../js/api/factory/cms.js";
import RoomTypeFormModal from "./RoomTypeFormModal.js";
export default {
name: "RoomManagerOverview",
@@ -16,18 +15,12 @@ export default {
CoreForm,
FormInput,
RoomFormModal,
RoomTypeFormModal,
},
watch: {
filterData: {
handler(newValue) {
this.$refs.roomManagerOverviewTable.tabulator.setData("/", {
organizationalUnitShortCode: newValue.organizationalUnit?.value,
locationId: newValue.locationId,
buildingComponent: newValue.buildingComponent,
isForTrainingProgram: newValue.isForTrainingProgram,
isReservationNeeded: newValue.isReservationNeeded,
isActive: newValue.isActive,
});
this.reloadTableData();
},
deep: true,
},
@@ -48,7 +41,9 @@ export default {
filteredOrganizationalUnits: [],
buildingComponents: ["A", "B", "C", "D", "E", "F"],
isRoomFormModalVisible: false,
isRoomTypeFormModalVisible: false,
editedRoomShortCode: null,
editedRoomForRoomTypeManagement: null,
};
},
computed: {
@@ -70,54 +65,101 @@ export default {
ajaxResponse: (url, params, response) => response.data,
persistenceID: "core_class_schedule_validity_periods",
selectableRows: true,
index: "ort_kurzbz",
columns: [
{
title: this.$capitalize(this.$p.t("gruppenmanagement", "kurzbezeichnung")),
title: this.$capitalize(
this.$p.t("gruppenmanagement", "kurzbezeichnung"),
),
field: "ort_kurzbz",
headerFilter: true,
width: 150,
},
{
title: this.$capitalize(this.$p.t("gruppenmanagement", "bezeichnung")),
field: "bezeichnun",
title: this.$capitalize(
this.$p.t("gruppenmanagement", "bezeichnung"),
),
field: "bezeichnung",
headerFilter: true,
width: 200,
},
{
title: this.$capitalize(this.$p.t("ui", "planbezeichnung")),
field: "planbezeichnung",
headerFilter: true,
width: 200,
},
{
title: this.$capitalize(this.$p.t("ui", "maxPersons")),
field: "max_person",
headerFilter: true,
width: 100,
},
{
title: this.$capitalize(this.$p.t("ui", "arbeitsplaetze")),
field: "arbeitsplaetze",
headerFilter: true,
width: 100,
},
{
title: this.$capitalize(this.$p.t("ui", "quadratmeter")),
field: "m2",
headerFilter: true,
width: 100
},
{
title: this.$capitalize(this.$p.t("lehre", "organisationseinheit")),
field: "oe_kurzbz",
field: "org_bezeichnung",
headerFilter: true,
width: 200,
},
{
title: this.$capitalize(this.$p.t("ui", "lehre")),
field: "lehre",
headerFilter: true,
formatter: "tickCross",
hozAlign: "center",
formatterParams: {
tickElement: '<i class="fa fa-check text-success"></i>',
crossElement: '<i class="fa fa-xmark text-danger"></i>',
},
},
{
title: this.$capitalize(this.$p.t("ui", "reservieren")),
field: "reservieren",
headerFilter: true,
formatter: "tickCross",
hozAlign: "center",
formatterParams: {
tickElement: '<i class="fa fa-check text-success"></i>',
crossElement: '<i class="fa fa-xmark text-danger"></i>',
},
},
{
title: this.$capitalize(this.$p.t("gruppenmanagement", "aktiv")),
field: "aktiv",
headerFilter: true,
formatter: "tickCross",
hozAlign: "center",
formatterParams: {
tickElement: '<i class="fa fa-check text-success"></i>',
crossElement: '<i class="fa fa-xmark text-danger"></i>',
},
},
{
title: this.$capitalize(this.$p.t("ui", "kosten")),
field: "kosten",
headerFilter: true,
},
{
title: this.$capitalize(this.$p.t("ui", "stockwerk")),
field: "stockwerk",
headerFilter: true,
},
{
title: this.$capitalize(this.$p.t("ui", "parentRoom")),
field: "pr_ort_kurzbz",
headerFilter: true,
},
{
title: this.$capitalize(this.$p.t("global", "actions")),
@@ -133,14 +175,18 @@ export default {
button = document.createElement("button");
button.className = "btn btn-outline-secondary btn-action";
button.innerHTML = '<i class="fa fa-edit"></i>';
button.title = this.$p.t(
"ui",
"btn_editRoom",
);
button.title = this.$p.t("ui", "btn_editRoom");
button.addEventListener("click", (event) =>
this.editRoom(
cell.getData().ort_kurzbz,
),
this.editRoom(cell.getData().ort_kurzbz),
);
container.append(button);
button = document.createElement("button");
button.className = "btn btn-outline-secondary btn-action";
button.innerHTML = '<i class="fa fa-layer-group"></i>';
button.title = this.$p.t("ui", "btn_editRoomType");
button.addEventListener("click", (event) =>
this.editRoomType(cell.getData().ort_kurzbz),
);
container.append(button);
@@ -148,22 +194,14 @@ export default {
button.className =
"btn btn-outline-secondary btn-action bg-danger";
button.innerHTML = '<i class="fa fa-xmark text-white"></i>';
button.title = this.$p.t(
"ui",
"btn_deleteRoom",
);
button.title = this.$p.t("ui", "btn_deleteRoom");
button.addEventListener("click", () => {
let isDeletionConfirmed = confirm(
this.$p.t(
"ui",
"deleteRoomConfirmation",
),
this.$p.t("ui", "deleteRoomConfirmation"),
);
if (!isDeletionConfirmed) return;
this.deleteRoom(
cell.getData().ort_kurzbz
);
this.deleteRoom(cell.getData().ort_kurzbz);
});
container.append(button);
@@ -172,6 +210,7 @@ export default {
frozen: true,
},
],
layout: "fitColumns",
};
return options;
},
@@ -181,6 +220,29 @@ export default {
event: "renderComplete",
handler: async () => {},
},
{
event: "cellClick",
handler: async (e, cell) => {
let updateableFieldsByClick = ["lehre", "reservieren", "aktiv"];
for (let field of updateableFieldsByClick) {
if (cell.getField() === field) {
let updatedValue = !cell.getValue();
this.$refs.roomManagerOverviewTable.tabulator.updateData([
{
ort_kurzbz: cell.getData().ort_kurzbz,
[field]: updatedValue,
},
]);
this.partialRoomUpdate(
cell.getData().ort_kurzbz,
field,
updatedValue,
);
this.$refs.roomManagerOverviewTable.tabulator.replaceData("/");
}
}
},
},
];
return events;
},
@@ -208,11 +270,11 @@ export default {
]);
}
return (this.filteredOrganizationalUnits = [defaultItem].concat(
this.dropdownParsedOrganizationalUnits.filter((unit) => {
return (this.filteredOrganizationalUnits = [defaultItem]
.concat(this.dropdownParsedOrganizationalUnits)
.filter((unit) => {
return unit.label.toLowerCase().includes(query);
}),
));
}));
},
showRoomFormModal() {
this.isRoomFormModalVisible = true;
@@ -225,27 +287,57 @@ export default {
.call(ApiRoom.deleteRoom(roomShortCode))
.then((response) => {
if (response.meta.status === "success") {
this.$refs.roomManagerOverviewTable.reloadTable();
alert(this.$p.t("ui", "roomDeletedSuccessfully"));
this.reloadTableData();
this.$fhcAlert.alertSuccess(
this.$p.t("ui", "roomDeletedSuccessfully"),
);
} else {
console.error("Error deleting room:", response.meta.message);
alert(this.$p.t("ui", "errorDeletingRoom"));
this.reloadTableData();
this.$fhcAlert.alertError(this.$p.t("ui", "errorDeletingRoom"));
}
})
.catch((error) => {
console.error("Error deleting room:", error);
alert(this.$p.t("ui", "errorDeletingRoom"));
this.$fhcAlert.alertError(this.$p.t("ui", "errorDeletingRoom"));
});
}
},
showRoomTypeFormModal() {
this.isRoomTypeFormModalVisible = true;
},
editRoomType(roomShortCode) {
this.editedRoomForRoomTypeManagement = roomShortCode;
},
async reloadTableData() {
this.$refs.roomManagerOverviewTable.tabulator.replaceData("/", {
organizationalUnitShortCode: this.filterData.organizationalUnit?.value,
locationId: this.filterData.locationId,
buildingComponent: this.filterData.buildingComponent,
isForTrainingProgram: this.filterData.isForTrainingProgram,
isReservationNeeded: this.filterData.isReservationNeeded,
isActive: this.filterData.isActive,
});
},
handleRoomUpdated() {
this.editedRoomShortCode = null;
this.reloadTableData();
},
async partialRoomUpdate(roomShortCode, attribute, value) {
let response = await this.$api.call(
ApiRoom.updateRoom(roomShortCode, {
[attribute]: value,
}),
);
if (response.meta.status === "success") {
this.$fhcAlert.alertSuccess(this.$p.t("ui", "successUpdate"));
this.reloadTableData();
} else {
console.error("Error updating room:", response.meta.message);
this.$fhcAlert.alertError(this.$p.t("ui", "errorUpdatingRoom"));
}
},
},
async created() {
let getContent = await this.$api.call(ApiCms.content(7601));
if (getContent.meta.status === "success") {
console.log;
} else {
console.error("Error fetching locations:", getContent.meta.message);
}
let getLocationsResponse = await this.$api.call(
ApiLocation.getLocationsByCompanyType("Intern"),
);
@@ -274,7 +366,14 @@ export default {
},
mounted() {
this.$p
.loadCategory(["global", "lehre", "ui", "gruppenmanagement", "core", "person"])
.loadCategory([
"global",
"lehre",
"ui",
"gruppenmanagement",
"core",
"person",
])
.then(() => {
this.phrasesLoaded = true;
});
@@ -300,12 +399,12 @@ export default {
<core-form class="d-flex flex-column flex-md-row align-items-md-end gap-3">
<div>
<form-input
v-model="filterData.organizationalUnit"
:label="$capitalize($p.t('lehre/organisationseinheit'))"
:suggestions="filteredOrganizationalUnits"
:optionValue="(option) => option.value"
:optionLabel="(option) => option.label"
@complete="filterOrganizationalUnits"
@itemSelect="(option) => { filterData.organizationalUnit = option.value; }"
dropdown
forceSelection
type="autocomplete"
@@ -382,8 +481,13 @@ export default {
:isVisible="isRoomFormModalVisible"
:editedRoomShortCode="editedRoomShortCode"
@hideBsModal="() => { isRoomFormModalVisible = false; editedRoomShortCode = null; }"
@roomCreated="() => { $refs.roomManagerOverviewTable.reloadTable(); editedRoomShortCode = null; }"
@roomUpdated="() => { $refs.roomManagerOverviewTable.reloadTable(); editedRoomShortCode = null; }"
@roomCreated="handleRoomUpdated"
@roomUpdated="handleRoomUpdated"
/>
<room-type-form-modal
:isVisible="isRoomTypeFormModalVisible"
:editedRoomShortCode="editedRoomForRoomTypeManagement"
@hideBsModal="() => { isRoomTypeFormModalVisible = false; editedRoomForRoomTypeManagement = null; }"
/>
</div>
`,
@@ -0,0 +1,353 @@
import ApiRoom from "../../../js/api/factory/ort.js";
import ApiRoomType from "../../../js/api/factory/roomType.js";
import ApiRoomToRoomType from "../../../js/api/factory/roomToRoomType.js";
import { CoreFilterCmpt } from "../filter/Filter.js";
import BsModal from "../Bootstrap/Modal.js";
import CoreForm from "../Form/Form.js";
import FormInput from "../Form/Input.js";
export default {
name: "RoomTypeFormModal",
components: {
BsModal,
CoreForm,
FormInput,
CoreFilterCmpt,
},
props: {
isVisible: {
type: Boolean,
required: true,
},
editedRoomShortCode: {
type: String,
default: null,
},
},
emits: [
"hideBsModal",
"roomTypeCreated",
"roomToRoomTypeCreated",
"roomToRoomTypeDeleted",
],
watch: {
isVisible(newValue) {
if (newValue) {
this.$refs.roomTypeFormModal.show();
} else {
this.$refs.roomTypeFormModal.hide();
}
},
async editedRoomShortCode(newValue) {
if (newValue) {
await this.$refs.roomTypesTable.reloadTable();
this.$refs.roomTypeFormModal.show();
} else {
this.resetRoomTypeForm();
}
},
},
data: () => {
return {
phrasesLoaded: false,
isEditInProgress: false,
editedRoom: null,
isRoomTypeFormVisible: false,
roomTypeFormData: {
aktiv: true,
},
roomToRoomTypeFormData: {},
roomTypes: [],
filteredRoomTypes: [],
};
},
computed: {
tabulatorOptions() {
const options = {
ajaxURL: "dummy",
ajaxRequestFunc: async () =>
this.$api.call(
ApiRoomToRoomType.getRoomToRoomTypeRelationsByRoomShortCode(
this.editedRoomShortCode,
),
),
ajaxResponse: (url, params, response) => response.data,
persistenceID: "core_class_schedule_validity_periods",
selectableRows: true,
columns: [
{
title: this.$capitalize(this.$p.t("ui", "roomType")),
field: "raumtyp_kurzbz",
},
{
title: this.$capitalize(this.$p.t("ui", "hierarchy")),
field: "hierarchie",
},
{
title: this.$capitalize(this.$p.t("gruppenmanagement", "beschreibung")),
field: "raumtyp_beschreibung",
},
{
title: this.$capitalize(this.$p.t("global", "actions")),
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 = document.createElement("button");
button.className =
"btn btn-outline-secondary btn-action bg-danger";
button.innerHTML = '<i class="fa fa-xmark text-white"></i>';
button.title = this.$p.t(
"ui",
"btn_deleteRoomToRoomTypeRelation",
);
button.addEventListener("click", () => {
let isDeletionConfirmed = confirm(
this.$p.t("ui", "deleteRoomToRoomTypeRelationConfirmation"),
);
if (!isDeletionConfirmed) return;
this.deleteRoomToRoomTypeRelation(
cell.getData().ort_kurzbz,
cell.getData().raumtyp_kurzbz,
);
});
container.append(button);
return container;
},
frozen: true,
},
],
};
return options;
},
tabulatorEvents() {
const events = [
{
event: "renderComplete",
handler: async () => {},
},
];
return events;
},
dropdownParsedRoomTypes() {
return this.roomTypes.map((roomType) => {
return {
label: `${roomType.raumtyp_kurzbz} - ${roomType.beschreibung}`,
value: roomType.raumtyp_kurzbz,
};
});
},
},
methods: {
filterRoomTypes(event) {
let defaultItem = {
label: "----------",
value: null,
};
const query = event.query.toLowerCase();
if (!query) {
return (this.filteredRoomTypes = [
defaultItem,
...this.dropdownParsedRoomTypes,
]);
}
return (this.filteredRoomTypes = [defaultItem]
.concat(this.dropdownParsedRoomTypes)
.filter((roomType) => {
return roomType.label?.toLowerCase().includes(query);
}));
},
createRoomType() {
return this.$refs.roomTypeForm
.call(
ApiRoomType.createRoomType({
kurzbezeichnung: this.roomTypeFormData.shortCode,
beschreibung: this.roomTypeFormData.description,
}),
)
.then((response) => {
this.$fhcAlert.alertSuccess(this.$p.t("ui", "successSave"));
this.$emit("roomTypeCreated");
this.resetRoomTypeForm();
this.isRoomTypeFormVisible = false;
this.fetchRoomTypes();
});
},
createRoomToRoomTypeRelation() {
return this.$refs.roomToRoomTypeForm
.call(
ApiRoomToRoomType.createRoomToRoomTypeRelation(
this.editedRoomShortCode,
this.roomToRoomTypeFormData.roomType?.value,
this.roomToRoomTypeFormData.hierarchy,
),
)
.then((response) => {
this.$fhcAlert.alertSuccess(this.$p.t("ui", "successSave"));
this.$emit("roomToRoomTypeCreated");
this.resetRoomTypeForm();
this.$refs.roomTypesTable.tabulator.replaceData("/");
});
},
deleteRoomToRoomTypeRelation(roomShortCode, roomTypeShortCode) {
return this.$api
.call(
ApiRoomToRoomType.deleteRoomToRoomTypeRelation(
roomShortCode,
roomTypeShortCode,
),
)
.then((response) => {
this.$fhcAlert.alertSuccess(this.$p.t("ui", "successDelete"));
this.$emit("roomToRoomTypeDeleted");
this.resetRoomTypeForm();
this.$refs.roomTypesTable.tabulator.replaceData("/");
});
},
hideRoomTypeFormModal() {
this.$refs.roomTypeFormModal.hide();
this.$emit("hideBsModal");
this.resetRoomTypeForm();
},
resetRoomTypeForm() {
this.$refs.roomTypeForm?.clearValidation();
this.isEditInProgress = false;
this.isRoomTypeFormVisible = false;
this.editedRoom = null;
this.roomTypeFormData = {
aktiv: true,
};
},
async fetchRoomTypes() {
let getRoomTypesResponse = await this.$api.call(
ApiRoomType.getAllRoomTypes(),
);
if (getRoomTypesResponse.meta.status === "success") {
this.roomTypes = getRoomTypesResponse.data;
} else {
console.error(
"Error fetching room types:",
getRoomTypesResponse.meta.message,
);
}
},
},
async created() {
this.fetchRoomTypes();
this.$p
.loadCategory(["global", "lehre", "ui", "gruppenmanagement", "core", "person"])
.then(() => {
this.phrasesLoaded = true;
});
},
template: /* html */ `
<bs-modal ref="roomTypeFormModal" size="sm" @hideBsModal="() => { $emit('hideBsModal'); resetRoomTypeForm(); }" class="modal-lg">
<template #title>
<p class="fw-bold mt-3">{{$capitalize($p.t('ui', 'assignRoomTypeToRoomModalTitle'))}}</p>
</template>
<template #default>
<div class="justify-content-end d-flex mb-1">
<a
v-if="!isRoomTypeFormVisible"
:title='$p.t("ui", "createRoomType")'
@click.prevent="isRoomTypeFormVisible = !isRoomTypeFormVisible"
href="#"
class="btn btn-primary rounded-circle">
<i
class="fa fa-plus"
></i>
</a>
</div>
<core-form v-if="isRoomTypeFormVisible" ref="roomTypeForm" class="row g-3 pb-3">
<div class="row">
<div class="col">
<p class="fw-bold">{{$capitalize($p.t('ui', 'createRoomTypeFormTitle'))}}</p>
</div>
</div>
<div class="row mb-3">
<div class="col">
<form-input
v-model="roomTypeFormData.shortCode"
:label="$capitalize($p.t('gruppenmanagement', 'kurzbezeichnung'))"
type="text"
name="kurzbezeichnung"
>
</form-input>
</div>
<div class="col">
<form-input
v-model="roomTypeFormData.description"
:label="$capitalize($p.t('gruppenmanagement', 'beschreibung'))"
type="text"
name="beschreibung"
>
</form-input>
</div>
</div>
<div class="col d-flex justify-content-end gap-2">
<button type="button" class="btn btn-secondary" @click="isRoomTypeFormVisible = false">{{$p.t('ui', 'abbrechen')}}</button>
<button type="button" class="btn btn-primary" @click="createRoomType()">{{$p.t('ui', 'speichern')}}</button>
</div>
</core-form>
<core-form v-if="!isRoomTypeFormVisible" ref="roomToRoomTypeForm" class="row g-3 pb-3">
<div class="col-8">
<form-input
v-model="roomToRoomTypeFormData.roomType"
:label="$capitalize($p.t('ui/parentRoom'))"
:suggestions="filteredRoomTypes"
:optionValue="(option) => option.value"
:optionLabel="(option) => option.label"
@complete="filterRoomTypes"
dropdown
forceSelection
type="autocomplete"
name="roomTypeShortCode"
>
</form-input>
</div>
<div class="col">
<form-input
v-model="roomToRoomTypeFormData.hierarchy"
:label="$capitalize($p.t('ui', 'hierarchy'))"
type="number"
name="hierarchy"
>
</form-input>
</div>
<div class="col justify-content-end align-items-end d-flex">
<button type="button" class="btn btn-primary" @click="createRoomToRoomTypeRelation()">{{$p.t('ui', 'speichern')}}</button>
</div>
</core-form>
<hr>
<div class="row my-1">
<div class="col">
<p class="fw-bold">{{$capitalize($p.t('ui', 'assignedRoomTypesTitle'))}}</p>
</div>
</div>
<core-filter-cmpt
v-if="phrasesLoaded"
ref="roomTypesTable"
table-only
:side-menu="false"
:tabulator-options="tabulatorOptions"
:tabulator-events="tabulatorEvents"
>
</core-filter-cmpt>
</template>
</bs-modal>
`,
};
+1 -1
View File
@@ -94,7 +94,7 @@ require_once('dbupdate_3.4/71399_dashboard_update_widget_paths.php');
require_once('dbupdate_3.4/71645_studvw_messagetab_ladezeit.php');
require_once('dbupdate_3.4/71566_studienordnungsdokument_neuer_organisationseinheitstyp_programm.php');
require_once('dbupdate_3.4/70376_lohnguide.php');
require_once('dbupdate_3.4/76663_tempus_rekursive_raum_struktur.php');
// *** Pruefung und hinzufuegen der neuen Attribute und Tabellen
echo '<H2>Pruefe Tabellen und Attribute!</H2>';
@@ -0,0 +1,22 @@
<?php
if (! defined('DB_NAME')) exit('No direct script access allowed');
if(!$result = @$db->db_query("SELECT parent_ort_kurzbz FROM public.tbl_ort LIMIT 1;"))
{
$qry = 'ALTER TABLE public.tbl_ort ADD COLUMN parent_ort_kurzbz VARCHAR(16);';
if(!$db->db_query($qry))
echo '<strong>public.tbl_ort: '.$db->db_last_error().'</strong><br>';
else
echo ' public.tbl_ort: parent_ort_kurzbz added successfully.<br>';
}
$result = $db->db_query("SELECT constraint_name FROM information_schema.table_constraints
WHERE table_name='tbl_ort' AND constraint_type='FOREIGN KEY' AND constraint_name='fk_parent_ort_kurzbz'");
if($db->db_num_rows($result)==0)
{
$qry = "ALTER TABLE public.tbl_ort ADD CONSTRAINT fk_parent_ort_kurzbz FOREIGN KEY(parent_ort_kurzbz) REFERENCES public.tbl_ort(ort_kurzbz);";
if(!$db->db_query($qry))
echo '<strong>public.tbl_ort: '.$db->db_last_error().'</strong><br>';
else
echo '<br>Added foreign key constraint fk_parent_ort_kurzbz to public.tbl_ort';
}
+200
View File
@@ -58657,6 +58657,206 @@ I have been informed that I am under no obligation to consent to the transmissio
)
)
),
array(
'app' => 'core',
'category' => 'ui',
'phrase' => 'parentRoom',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'übergeordneter Raum',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'parent room',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'ui',
'phrase' => 'assignRoomTypeToRoomModalTitle',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'raumtyp zu raum zuweisen',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'assign room type to room',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'ui',
'phrase' => 'createRoomType',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'raumtyp erstellen',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'create room type',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'ui',
'phrase' => 'createRoomTypeFormTitle',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'raumtyp erstellen',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'create room type',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'ui',
'phrase' => 'hierarchy',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'hierarchie',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'hierarchy',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'ui',
'phrase' => 'assignedRoomTypesTitle',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'zugewiesene Raumtypen',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'assigned room types',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'ui',
'phrase' => 'roomType',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Raumtyp',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'room type',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'ui',
'phrase' => 'error_fieldUnique',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => '{field} muss einzigartig sein',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => '{field} must be unique',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'ui',
'phrase' => 'error_roomToRoomTypeRelationAlreadyExists',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Die Relation mit der gleichen Hierarchie ist diesem Raum bereits zugeordnet',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'The relation with the same hierarchy is already assigned to this room',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'ui',
'phrase' => 'roomManagerPageTitle',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'raumverwaltung',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'room management',
'description' => '',
'insertvon' => 'system'
)
)
),
);