diff --git a/application/controllers/api/frontend/v1/lv/Lehreinheit.php b/application/controllers/api/frontend/v1/lv/Lehreinheit.php index b851f8c22..958007901 100644 --- a/application/controllers/api/frontend/v1/lv/Lehreinheit.php +++ b/application/controllers/api/frontend/v1/lv/Lehreinheit.php @@ -350,7 +350,7 @@ class Lehreinheit extends FHCAPI_Controller $this->form_validation->set_rules($field, 'Start KW', 'integer|greater_than[0]|less_than_equal_to[53]'); break; case 'gewicht': - $this->form_validation->set_rules($field, 'Gewicht', 'numeric'); + $this->form_validation->set_rules($field, 'Gewicht', 'numeric|greater_than_equal_to[0]'); break; case 'raumtyp': $this->form_validation->set_rules($field, 'Raumtyp', 'required|max_length[16]'); @@ -365,7 +365,7 @@ class Lehreinheit extends FHCAPI_Controller $this->form_validation->set_rules($field, 'LVNR', 'integer'); break; case 'unr': - $this->form_validation->set_rules($field, 'UNR', 'integer'); + $this->form_validation->set_rules($field, 'UNR', 'integer|greater_than_equal_to[0]'); break; case 'lehre': $this->form_validation->set_rules($field, 'Lehre', 'trim'); diff --git a/application/controllers/api/frontend/v1/lv/Lektor.php b/application/controllers/api/frontend/v1/lv/Lektor.php index 4a244c1a1..68bec1bc4 100644 --- a/application/controllers/api/frontend/v1/lv/Lektor.php +++ b/application/controllers/api/frontend/v1/lv/Lektor.php @@ -107,7 +107,8 @@ class Lektor extends FHCAPI_Controller $this->form_validation->set_rules($field, 'Planstunden', 'integer|greater_than_equal_to[0]'); break; case 'stundensatz': - $this->form_validation->set_rules($field, 'Stundensatz', 'numeric|greater_than_equal_to[0]'); + $formData['stundensatz'] = str_replace(',', '.', $formData['stundensatz']); + $this->form_validation->set_rules($field, 'Stundensatz', 'callback__check_stundensatz'); break; case 'faktor': $this->form_validation->set_rules($field, 'Faktor', 'numeric|greater_than_equal_to[0]'); @@ -119,6 +120,7 @@ class Lektor extends FHCAPI_Controller $this->form_validation->set_rules($field, 'Bis Melden', 'trim'); break; case 'semesterstunden': + $formData['semesterstunden'] = str_replace(',', '.', $formData['semesterstunden']); $this->form_validation->set_rules($field, 'Semesterstunden', 'callback__check_semesterstunden'); break; case 'mitarbeiter_uid': @@ -129,7 +131,7 @@ class Lektor extends FHCAPI_Controller } if (!$this->form_validation->run()) { - $this->terminateWithError($this->form_validation->error_array()); + $this->terminateWithValidationErrors($this->form_validation->error_array()); } if (isset($formData['semesterstunden']) && (!is_numeric($formData['semesterstunden']) || $formData['semesterstunden'] === '')) @@ -145,9 +147,26 @@ class Lektor extends FHCAPI_Controller $result = $this->_ci->lektorlib->updateLektorFromLehreinheit($lehreinheit_id, $mitarbeiter_uid, $formData); if (isError($result)) $this->terminateWithError(getError($result)); - $this->terminateWithSuccess("Erfolgreich geupdated"); + $this->terminateWithSuccess($result); } + public function _check_stundensatz($value) + { + $value = str_replace(',', '.', $value); + + if (!is_numeric($value)) + { + $this->form_validation->set_message('_check_decimal', 'Das Feld {field} muss eine Zahl sein.'); + return false; + } + + if ($value < 0 || $value >= 10000) { + $this->form_validation->set_message('_check_decimal', 'Das Feld {field} muss zwischen 0 und 10000 liegen.'); + return false; + } + + return true; + } public function _check_semesterstunden($value) { if ($value === null || $value === '') { @@ -171,6 +190,14 @@ class Lektor extends FHCAPI_Controller ); return false; } + if ($value > 999.99) + { + $this->form_validation->set_message( + '_check_semesterstunden', + 'Das Feld {field} darf maximal 999,99 betragen.' + ); + return false; + } return true; } diff --git a/application/controllers/api/frontend/v1/lv/Setup.php b/application/controllers/api/frontend/v1/lv/Setup.php index cf73697a7..a2c167dd6 100644 --- a/application/controllers/api/frontend/v1/lv/Setup.php +++ b/application/controllers/api/frontend/v1/lv/Setup.php @@ -50,6 +50,11 @@ class Setup extends FHCAPI_Controller 'component' => APP_ROOT . 'public/js/components/LVVerwaltung/Tabs/Details.js', 'config' => [] ); + $tabs['gruppen'] = array ( + 'title' => 'Gruppen', + 'component' => APP_ROOT . 'public/js/components/LVVerwaltung/Tabs/Gruppen.js', + 'config' => [] + ); $tabs['lektor'] = array ( 'title' => 'LektorInnenzuteilung', 'component' => APP_ROOT . 'public/js/components/LVVerwaltung/Tabs/Lektor.js', diff --git a/application/libraries/LektorLib.php b/application/libraries/LektorLib.php index 44c71cdaa..e06e2b728 100644 --- a/application/libraries/LektorLib.php +++ b/application/libraries/LektorLib.php @@ -176,11 +176,11 @@ class LektorLib if (!$echter_dv && (!$this->_ci->permissionlib->isBerechtigt('admin'))) { if (!$this->LehrauftragAufFirma(isset($formData['mitarbeiter_uid']) ? $formData['mitarbeiter_uid'] : $mitarbeiter_uid)) - return error("ACHTUNG: Die maximal erlaubte Semesterstundenanzahl des Lektors von $summe Stunden ($stundengrenze->stunden) wurde ueberschritten!\n Daten wurden NICHT gespeichert!\n\n"); + return error("ACHTUNG: Die maximal erlaubte Semesterstundenanzahl des Lektors von $summe Stunden ($stundengrenze->stunden) wurde ueberschritten!\nDaten wurden NICHT gespeichert!\n\n"); } else { - $warning .= "ACHTUNG: Die maximal erlaubte Semesterstundenanzahl des Lektors von $summe Stunden ($stundengrenze->stunden) wurde ueberschritten!\n Daten wurden gespeichert!\n\n"; + $warning .= "ACHTUNG: Die maximal erlaubte Semesterstundenanzahl des Lektors von $summe Stunden ($stundengrenze->stunden) wurde ueberschritten!\nDaten wurden gespeichert!\n\n"; } $stunden_limit_result = $this->getStundenInstitut($mitarbeiter_uid, $lehreinheit->studiensemester_kurzbz, $oe_array); @@ -190,7 +190,7 @@ class LektorLib $stunden_limit_array = getData($stunden_limit_result); foreach ($stunden_limit_array as $stunden_limit) { - $warning .= $stunden_limit->summe . ' Stunden' . $stunden_limit->bezeichnung; + $warning .= $stunden_limit->summe . ' Stunden ' . $stunden_limit->bezeichnung . "\n"; } } } @@ -206,7 +206,7 @@ class LektorLib $benutzer_aktiv = getData($benutzer_result)[0]->aktiv; if (!$benutzer_aktiv) - $warning .= "Achtung: Der/Die Benutzer*in ist inaktiv!\nBitte informieren Sie die Personalbteilung.\n\nDaten wurden gespeichert.\n\n"; + $warning .= "Achtung: Der/Die Benutzer*in ist inaktiv!\nBitte informieren Sie die Personalbteilung.\nDaten wurden gespeichert.\n\n"; $updatableFields = array( 'semesterstunden', @@ -236,9 +236,9 @@ class LektorLib if (isError($result)) return $result; - if ($warning !== '') return error($warning); + if ($warning !== '') return success(['warning' => $warning]); - return success('Successfully updated Lehreinheit'); + return success('Erfolgreich geupdated'); } private function getMaxStunden($mitarbeiter_uid, $studiensemester_kurzbz, $studiengang_kz, $echter_dv) @@ -280,7 +280,7 @@ class LektorLib foreach ($stunden_limit_array as $stunden_limit) { - $error .= $stunden_limit->summe . ' Stunden' . $stunden_limit->bezeichnung; + $error .= $stunden_limit->summe . ' Stunden ' . $stunden_limit->bezeichnung . "\n"; } } return error($error); diff --git a/public/css/Lvverwaltung.css b/public/css/Lvverwaltung.css index 38d74def4..6e0f4c760 100644 --- a/public/css/Lvverwaltung.css +++ b/public/css/Lvverwaltung.css @@ -28,3 +28,13 @@ textarea[name="anmerkung"] { content: '\f073'; color: #f3c541; } + + +.modal-dialog.modal-xxl { + max-width: 95% !important; +} + +.tabulator-menu .tabulator-menu-item.tabulator-menu-item-submenu:after +{ + border-color: black; +} diff --git a/public/css/Tabulator6.css b/public/css/Tabulator6.css index 8be726544..7a66dd2f6 100644 --- a/public/css/Tabulator6.css +++ b/public/css/Tabulator6.css @@ -1 +1,153 @@ -@import '../../vendor/olifolkerd/tabulator6/dist/css/tabulator_simple.min.css'; \ No newline at end of file +@import '../../vendor/olifolkerd/tabulator6/dist/css/tabulator_simple.min.css'; +.tabulator-row { + border-bottom: none; +} +.tabulator-row .tabulator-frozen, +.tabulator-row .tabulator-cell { + border-bottom: 1px solid #dee2e6; +} +.tabulator-row.tabulator-row-even { + background-color: transparent; +} +.tabulator-headers .tabulator-frozen, +.tabulator-row.tabulator-row-odd .tabulator-frozen, +.tabulator-row.tabulator-row-odd .tabulator-cell { + background-color: #fff; +} +.tabulator-row.tabulator-row-even .tabulator-frozen, +.tabulator-row.tabulator-row-even .tabulator-cell { + background-color: #f2f2f2; +} +.tabulator-row.tabulator-selectable:hover .tabulator-frozen, +.tabulator-row.tabulator-selectable:hover .tabulator-cell { + background-color: #ececec; +} +.tabulator-row.tabulator-selected .tabulator-frozen, +.tabulator-row.tabulator-selected .tabulator-cell { + background-color: #9abcea; +} +.tabulator-row.tabulator-selected:hover .tabulator-frozen, +.tabulator-row.tabulator-selected:hover .tabulator-cell { + background-color: #769bcc; +} +.tabulator .tabulator-col-resize-handle:last-of-type { + z-index: 999999; +} + +/* classes for rows that are not selectable in the tabulator, except for rows that are used for calculation */ +.tabulator-row.tabulator-unselectable:not(.tabulator-calcs) { + color: #adb5bd !important; + pointer-events: none !important; +} + +.tabulator-row.tabulator-unselectable a { + pointer-events: auto !important; +} + +/* using bootstrap background classes to style the background color of tabulator rows */ +/* bg-warning */ +/* odd-rows */ +.tabulator-headers .tabulator-frozen.bg-warning, +.tabulator-row.tabulator-row-odd .tabulator-frozen.bg-warning, +.tabulator-row.tabulator-row-odd .tabulator-cell.bg-warning { + background-color: #fcf8e3; + +} +/* even-rows */ +.tabulator-headers .tabulator-frozen.bg-warning, +.tabulator-row.tabulator-row-even .tabulator-frozen.bg-warning, +.tabulator-row.tabulator-row-even .tabulator-cell.bg-warning { + background-color: #fcf8e3; + +} + +/* bg-success */ +/* odd-rows */ +.tabulator-headers .tabulator-frozen.bg-success, +.tabulator-row.tabulator-row-odd .tabulator-frozen.bg-success, +.tabulator-row.tabulator-row-odd .tabulator-cell.bg-success { + background-color: #dff0d8; + +} +/* even-rows */ +.tabulator-headers .tabulator-frozen.bg-success, +.tabulator-row.tabulator-row-even .tabulator-frozen.bg-success, +.tabulator-row.tabulator-row-even .tabulator-cell.bg-success { + background-color: #dff0d8; + +} + +/* bg-info */ +/* odd-rows */ +.tabulator-headers .tabulator-frozen.bg-info, +.tabulator-row.tabulator-row-odd .tabulator-frozen.bg-info, +.tabulator-row.tabulator-row-odd .tabulator-cell.bg-info { + background-color: #d9edf7; + +} +/* even-rows */ +.tabulator-headers .tabulator-frozen.bg-info, +.tabulator-row.tabulator-row-even .tabulator-frozen.bg-info, +.tabulator-row.tabulator-row-even .tabulator-cell.bg-info { + background-color: #d9edf7; + +} + +/* special bootstrap5 styling for tableWidget and their accordion-item ::after content */ +.accordion-button::after{ + content:none !important; +} + + +.tabulator { + font-size: 1rem; +} + +.tabulator-initialfontsize .tabulator { + font-size: 14px; +} + +.tabulator-row.tabulator-unselectable .tabulator-cell { + pointer-events: all; +} + +.tabulator-tooltip { + color: #fff; + background-color: #000; +} + +.tabulator-row.tabulator-unselectable:not(.tabulator-calcs) { + color: #777 !important; +} + +.tabulator-cell .btn { + padding: 0 .375rem; + font-size: calc(1rem - 2px / 1.5); /* substract border (2 x 1px) modified by the line-height (1.5) */ + border-radius: .2rem; + vertical-align: baseline; +} + +.tabulator-row.tabulator-selectable:focus { + box-shadow: 0 0 0 .24rem rgba(13,110,253,.25); + z-index: 1; + outline: 0; +} + +.btn-select-col-selected +{ + background-color: #e6e6e6; +} + +.accordion-item-dark, .accordion-item-dark:focus{ + background-color:#CED4DA !important; + border-color:#ADB5BD !important; + box-shadow: none !important; +} + +/** + * Make keyboard-focused list items look like the mouse-hovered list items + */ +.tabulator-edit-list .tabulator-edit-list-item.focused { + color: #fff; + background: #1d68cd; +} diff --git a/public/js/components/LVVerwaltung/Details/Form.js b/public/js/components/LVVerwaltung/Details/Form.js index eed65f7ad..5908512d7 100644 --- a/public/js/components/LVVerwaltung/Details/Form.js +++ b/public/js/components/LVVerwaltung/Details/Form.js @@ -38,33 +38,6 @@ export default { }, template: `
-
- - - -
-
- -
+ - - - -
- -
- - - -
@@ -179,30 +112,109 @@ export default { {{ raumtyp.raumtyp_kurzbz }} {{ raumtyp.beschreibung }} + + +
+ + +
+ + + + + + + + + +
+ +
+ +
+ +
+ +
+ + +
` diff --git a/public/js/components/LVVerwaltung/Details/Gruppen.js b/public/js/components/LVVerwaltung/Details/Gruppen.js index 219b956d8..a6f9df005 100644 --- a/public/js/components/LVVerwaltung/Details/Gruppen.js +++ b/public/js/components/LVVerwaltung/Details/Gruppen.js @@ -50,7 +50,7 @@ export default{ let button = document.createElement('button'); container.className = "d-flex gap-1"; - button.className = 'btn btn-outline-secondary btn-action'; + button.className = 'btn btn-outline-secondary'; button.innerHTML = ''; button.title = this.$p.t('ui', 'loeschen'); button.addEventListener('click', (event) => { @@ -63,7 +63,7 @@ export default{ { button = document.createElement('button'); container.className = "d-flex gap-2"; - button.className = 'btn btn-outline-secondary btn-action'; + button.className = 'btn btn-outline-secondary'; button.innerHTML = ''; button.title = this.$p.t('lehre', 'auslvplanentfernen'); button.disabled = !cell.getData().verplant; diff --git a/public/js/components/LVVerwaltung/LVVerwaltung.js b/public/js/components/LVVerwaltung/LVVerwaltung.js index e9d132848..a1ff28a2e 100644 --- a/public/js/components/LVVerwaltung/LVVerwaltung.js +++ b/public/js/components/LVVerwaltung/LVVerwaltung.js @@ -88,10 +88,12 @@ export default { }, selectedStudiengang: '', searchbaroptions: { + origin: 'lvverwaltung', cssclass: "position-relative", calcheightonly: true, types: [ - "mitarbeiter" + "mitarbeiter", + "mitarbeiter_ohne_zuordnung" ], actions: { employee: { diff --git a/public/js/components/LVVerwaltung/Lektor/Daten.js b/public/js/components/LVVerwaltung/Lektor/Daten.js index 0f6b9e0f7..d4c6aa5e3 100644 --- a/public/js/components/LVVerwaltung/Lektor/Daten.js +++ b/public/js/components/LVVerwaltung/Lektor/Daten.js @@ -121,9 +121,9 @@ export default{ } this.$refs.form.call(ApiLektor.update(updatedData)) .then(result => { - let error = result.data?.error; - if (error) - this.$fhcAlert.alertWarning(error) + let warning = result.data?.retval?.warning; + if (warning) + this.$fhcAlert.alertWarning(warning) this.original = {...this.data}; if (this.changed.mitarbeiter_uid) @@ -192,6 +192,7 @@ export default{ container-class="col-3" dropdown @complete="searchLektor" + name="lektorautocomplete" > { event.stopPropagation(); this.deleteLVPlan(cell.getData().mitarbeiter_uid, cell.getData().lehreinheit_id) diff --git a/public/js/components/LVVerwaltung/Lektor/Vertrag.js b/public/js/components/LVVerwaltung/Lektor/Vertrag.js index f36fad8e0..bdb156546 100644 --- a/public/js/components/LVVerwaltung/Lektor/Vertrag.js +++ b/public/js/components/LVVerwaltung/Lektor/Vertrag.js @@ -88,8 +88,14 @@ export default{ .catch(this.$fhcAlert.handleSystemError); }, - cancelVertrag() + async cancelVertrag() { + + if (await this.$fhcAlert.confirm({ + message: this.$p.t('lehre', 'vertragConfirm'), + acceptLabel: this.$p.t('ui', 'ja').charAt(0).toUpperCase() + this.$p.t('ui', 'ja').slice(1), + acceptClass: 'btn btn-danger'}) === false) + return; let needUpdate = { vertrag_id: this.data.vertrag.vertrag_id, mitarbeiter_uid: this.mitarbeiter_uid, @@ -126,6 +132,7 @@ export default{ type="button" class="btn btn-outline-secondary w-100" @click="cancelVertrag" + :title="$p.t('lehre', 'cancelvertrag')" > diff --git a/public/js/components/LVVerwaltung/Setup/Table.js b/public/js/components/LVVerwaltung/Setup/Table.js index fa288f8d7..2f37e4207 100644 --- a/public/js/components/LVVerwaltung/Setup/Table.js +++ b/public/js/components/LVVerwaltung/Setup/Table.js @@ -670,19 +670,19 @@ export default { - - + + - + - - + + ` }; \ No newline at end of file diff --git a/public/js/components/LVVerwaltung/Setup/Tabs.js b/public/js/components/LVVerwaltung/Setup/Tabs.js index af14fbf32..62c5bbc31 100644 --- a/public/js/components/LVVerwaltung/Setup/Tabs.js +++ b/public/js/components/LVVerwaltung/Setup/Tabs.js @@ -50,7 +50,6 @@ export default { :modelValue="lv[0]" :config="configLVTabs" :default="$route.params.tab" - style="flex: 1 1 0%; height: 0%" @changed="reload" /> diff --git a/public/js/components/LVVerwaltung/Tabs/Details.js b/public/js/components/LVVerwaltung/Tabs/Details.js index ce0102177..cb3275d23 100644 --- a/public/js/components/LVVerwaltung/Tabs/Details.js +++ b/public/js/components/LVVerwaltung/Tabs/Details.js @@ -111,23 +111,14 @@ export default {
- {{this.$p.t('lehre', 'lehreinheit')}} +
+ {{ this.$p.t('lehre', 'lehreinheit') }} + +
-
-
-
- {{this.$p.t('lehre', 'gruppen')}} - -
-
- {{this.$p.t('lehre', 'assignedPersons')}} - -
-
- -
` + ` }; \ No newline at end of file diff --git a/public/js/components/LVVerwaltung/Tabs/Gruppen.js b/public/js/components/LVVerwaltung/Tabs/Gruppen.js new file mode 100644 index 000000000..2879c1959 --- /dev/null +++ b/public/js/components/LVVerwaltung/Tabs/Gruppen.js @@ -0,0 +1,39 @@ +import GruppenTable from '../Details/Gruppen.js'; +import GruppenDirektTable from '../Details/Direktinskription.js'; + +export default { + name: "LVTabGruppen", + components: { + GruppenTable, + GruppenDirektTable, + }, + props: { + modelValue: Object, + config: { + type: Object, + default: {} + }, + }, + inject: { + dropdowns: { + from: 'dropdowns' + } + }, + + template: ` + +
+
+
+ {{this.$p.t('lehre', 'gruppen')}} + +
+
+ {{this.$p.t('lehre', 'assignedPersons')}} + +
+
+ +
+ ` +}; \ No newline at end of file diff --git a/system/phrasesupdate.php b/system/phrasesupdate.php index 0927ea309..6a4c98fd9 100644 --- a/system/phrasesupdate.php +++ b/system/phrasesupdate.php @@ -2984,6 +2984,46 @@ $phrases = array( ) ) ), + array( + 'app' => 'core', + 'category' => 'lehre', + 'phrase' => 'cancelvertrag', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Vertrag stornieren', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Cancel Contract', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'lehre', + 'phrase' => 'vertragConfirm', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Möchten Sie den Vertrag wirklich stornieren?', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Do you really want to cancel the contract?', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), array( 'app' => 'core', 'category' => 'lehre',