mirror of
https://github.com/FH-Complete/FHC-Core.git
synced 2026-07-26 00:54:27 +00:00
Merge branch 'master' into feature-25999/C4_ma0594_profilePage
This commit is contained in:
+81
-64
@@ -1,83 +1,100 @@
|
||||
.text-prewrap {
|
||||
.fhc-header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
align-items: baseline;
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
.fhc-header > h1:first-child {
|
||||
font-size: calc(1.325rem + .9vw);
|
||||
}
|
||||
.fhc-header > :first-child > small {
|
||||
color: var(--bs-secondary);
|
||||
font-size: .65em;
|
||||
padding-inline-start: 1em;
|
||||
}
|
||||
|
||||
.fhc-alert.p-toast-center {
|
||||
width: 35rem;
|
||||
max-width: 100vw;
|
||||
}
|
||||
.fhc-alert.p-toast-top-right {
|
||||
max-width: calc(100vw - 40px);
|
||||
}
|
||||
.fhc-alert.p-toast-top-right .p-toast-detail,
|
||||
.fhc-alert.p-toast-center .p-toast-message-text .card {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.text-preline {
|
||||
white-space: pre-line;
|
||||
}
|
||||
|
||||
.accordion-button-primary {
|
||||
background-color: #e7f1ff;
|
||||
color: #0c63e4;
|
||||
}
|
||||
.accordion-button-primary:not(.collapsed) {
|
||||
background-color: #cfe2ff;
|
||||
color: #0a58ca;
|
||||
.text-prewrap {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.accordion-button-secondary {
|
||||
background-color: #f0f1f2;
|
||||
color: #616971;
|
||||
}
|
||||
.accordion-button-secondary:not(.collapsed) {
|
||||
background-color: #e2e3e5;
|
||||
color: #565e64;
|
||||
.btn-p-0 {
|
||||
padding: 0 .375rem;
|
||||
}
|
||||
|
||||
.accordion-button-success {
|
||||
background-color: #e8f3ee;
|
||||
color: #177a4c;
|
||||
}
|
||||
.accordion-button-success:not(.collapsed) {
|
||||
background-color: #d1e7dd;
|
||||
color: #146c43;
|
||||
.z-1 {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.accordion-button-info {
|
||||
background-color: #e7fafe;
|
||||
color: #0cb6d8;
|
||||
}
|
||||
.accordion-button-info:not(.collapsed) {
|
||||
background-color: #cff4fc;
|
||||
color: #0aa2c0;
|
||||
.input-group > .input-group-item {
|
||||
position: relative;
|
||||
flex: 1 1 auto;
|
||||
width: 1%;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.accordion-button-warning {
|
||||
background-color: #fff9e6;
|
||||
color: #e6ae06;
|
||||
}
|
||||
.accordion-button-warning:not(.collapsed) {
|
||||
background-color: #fff3cd;
|
||||
color: #cc9a06;
|
||||
.input-group > .input-group-item .form-control:focus,
|
||||
.input-group > .input-group-item .form-select:focus {
|
||||
z-index: 3;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.accordion-button-danger {
|
||||
background-color: #fcebec;
|
||||
color: #c6303e;
|
||||
}
|
||||
.accordion-button-danger:not(.collapsed) {
|
||||
background-color: #f8d7da;
|
||||
color: #b02a37;
|
||||
.input-group-lg > .input-group-item .form-control,
|
||||
.input-group-lg > .input-group-item .form-select {
|
||||
padding: 0.5rem 1rem;
|
||||
font-size: 1.25rem;
|
||||
border-radius: 0.3rem;
|
||||
}
|
||||
|
||||
.accordion-button-light {
|
||||
background-color: #fefeff;
|
||||
color: #dfe0e1;
|
||||
}
|
||||
.accordion-button-light:not(.collapsed) {
|
||||
background-color: #fefefe;
|
||||
color: #c6c7c8;
|
||||
|
||||
.input-group-sm > .input-group-item .form-control,
|
||||
.input-group-sm > .input-group-item .form-select {
|
||||
padding: 0.25rem 0.5rem;
|
||||
font-size: 0.875rem;
|
||||
border-radius: 0.2rem;
|
||||
}
|
||||
|
||||
.accordion-button-dark {
|
||||
background-color: #e9e9ea;
|
||||
color: #1e2125;
|
||||
}
|
||||
.accordion-button-dark:not(.collapsed) {
|
||||
background-color: #d3d3d4;
|
||||
color: #1a1e21;
|
||||
.input-group-lg > .input-group-item .form-select,
|
||||
.input-group-sm > .input-group-item .form-select {
|
||||
padding-right: 3rem;
|
||||
}
|
||||
|
||||
.tabulator-edit-list .tabulator-edit-list-item {
|
||||
background-color: white;
|
||||
.input-group:not(.has-validation) > .input-group-item:not(:last-child) .form-control,
|
||||
.input-group:not(.has-validation) > .input-group-item:not(:last-child) .form-select {
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
.input-group.has-validation > .input-group-item:nth-last-child(n+3) .form-control,
|
||||
.input-group.has-validation > .input-group-item:nth-last-child(n+3) .form-select {
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
.input-group > .input-group-item:not(:first-child) .form-control,
|
||||
.input-group > .input-group-item:not(:first-child) .form-select {
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
|
||||
.form-control-color.is-invalid,
|
||||
.was-validated .form-control-color:invalid,
|
||||
.form-control-color.is-valid,
|
||||
.was-validated .form-control-color:valid {
|
||||
padding-right: .375rem;
|
||||
background-image: none;
|
||||
}
|
||||
.tabulator-edit-list .tabulator-edit-list-item:hover,
|
||||
.tabulator-edit-list .tabulator-edit-list-item.active {
|
||||
color: white;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
@import '../../vendor/olifolkerd/tabulator5/dist/css/tabulator_bootstrap5.min.css';
|
||||
@import '../../vendor/olifolkerd/tabulator5/dist/css/tabulator_simple.min.css';
|
||||
|
||||
/* Apply borders and background to Cell instead of the Row
|
||||
* otherwise frozen columns won't look good (columns behind
|
||||
@@ -38,3 +38,9 @@
|
||||
.tabulator .tabulator-col-resize-handle:last-of-type {
|
||||
z-index: 999999;
|
||||
}
|
||||
|
||||
.tabulator-cell .btn {
|
||||
padding: 0 .5rem;
|
||||
max-height: 22px;
|
||||
min-width: 30px;
|
||||
}
|
||||
|
||||
@@ -64,7 +64,12 @@
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.tabulator{
|
||||
font-size:1rem;
|
||||
.tabulator {
|
||||
font-size: 1rem;
|
||||
}
|
||||
.tabulator-cell .btn {
|
||||
padding: 0 .375rem;
|
||||
font-size: .875rem;
|
||||
border-radius: .2rem;
|
||||
}
|
||||
|
||||
|
||||
@@ -82,6 +82,7 @@
|
||||
/*
|
||||
* To be moved outside
|
||||
*/
|
||||
.navbar.navbar-left-side ~ *,
|
||||
#content {
|
||||
position: inherit;
|
||||
margin: 0 0 0 250px;
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
.nav-item.nav-link:focus {
|
||||
box-shadow: 0 0 0 .24rem rgba(13,110,253,.25);
|
||||
z-index: 1;
|
||||
outline: 0;
|
||||
position: relative;
|
||||
}
|
||||
.nav-item.nav-link:focus::after {
|
||||
content: "";
|
||||
display: block;
|
||||
position: absolute;
|
||||
left: -.5rem;
|
||||
right: -.5rem;
|
||||
top: calc(100% + 1px);
|
||||
background: white;
|
||||
height: .25rem;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,46 @@
|
||||
@import '../../../vendor/vuejs/vuedatepicker_css/main.css';
|
||||
:root {
|
||||
/*General*/
|
||||
--dp-font-family: var(--bs-body-font-family);
|
||||
--dp-border-radius: .25rem;
|
||||
--dp-cell-border-radius: .25rem; /*Specific border radius for the calendar cell*/
|
||||
|
||||
/*Sizing*/
|
||||
--dp-button-height: 2.1875rem; /*Size for buttons in overlays*/
|
||||
--dp-month-year-row-height: 2.1875rem; /*Height of the month-year select row*/
|
||||
--dp-month-year-row-button-size: 2.1875rem; /*Specific height for the next/previous buttons*/
|
||||
--dp-button-icon-height: 1.25rem; /*Icon sizing in buttons*/
|
||||
--dp-cell-size: 2.1875rem; /*Width and height of calendar cell*/
|
||||
--dp-cell-padding: .3125rem; /*Padding in the cell*/
|
||||
--dp-common-padding: .625rem; /*Common padding used*/
|
||||
--dp-input-icon-padding: 2.1875rem;
|
||||
--dp-input-padding: .375rem .75rem;
|
||||
--dp-action-buttons-padding: .125rem .3125rem; /*Adjust padding for the action buttons in action row*/
|
||||
--dp-row-margin: .3125rem 0; /*Adjust the spacing between rows in the calendar*/
|
||||
--dp-calendar-header-cell-padding: 0.5rem; /*Adjust padding in calendar header cells*/
|
||||
--dp-two-calendars-spacing: .625rem; /*Space between multiple calendars*/
|
||||
--dp-overlay-col-padding: .1875rem; /*Padding in the overlay column*/
|
||||
--dp-time-inc-dec-button-size: 2rem; /*Sizing for arrow buttons in the time picker*/
|
||||
--dp-menu-padding: .375rem .5rem; /*Menu padding*/
|
||||
}
|
||||
.dp__theme_light {
|
||||
--dp-text-color: var(--text-color);
|
||||
--dp-primary-color: var(--bs-primary);
|
||||
--dp-primary-disabled-color: rgba(var(--bs-primary-rgb), .65);
|
||||
--dp-primary-text-color: var(--primary-color-text);
|
||||
--dp-secondary-color: var(--bs-secondary);
|
||||
--dp-border-color: var(--bs-gray-400);
|
||||
--dp-menu-border-color: var(--bs-gray-400);
|
||||
--dp-border-color-hover: var(--bs-gray-400);
|
||||
--dp-icon-color: rgba(var(--bs-black-rgb), .5);
|
||||
--dp-hover-icon-color: rgba(var(--bs-black-rgb), .75);
|
||||
--dp-range-between-dates-text-color: var(--dp-hover-text-color, var(--text-color));
|
||||
}
|
||||
.dp__theme_light .form-control.is-invalid {
|
||||
--dp-border-color-hover: var(--bs-danger);
|
||||
}
|
||||
.dp__theme_light .form-control.is-valid {
|
||||
--dp-border-color-hover: var(--bs-success);
|
||||
}
|
||||
.form-control.is-invalid ~ .dp__clear_icon,
|
||||
.was-validated .form-control:invalid ~ .dp__clear_icon { margin-right: calc(1.5em + .75rem - 12px) }
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
import search from "./search.js";
|
||||
import phrasen from "./phrasen.js";
|
||||
import navigation from "./navigation.js";
|
||||
import filter from "./filter.js";
|
||||
import studstatus from "./studstatus.js";
|
||||
|
||||
export default {
|
||||
search,
|
||||
phrasen,
|
||||
navigation,
|
||||
filter,
|
||||
studstatus
|
||||
};
|
||||
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
export default {
|
||||
saveCustomFilter(wsParams) {
|
||||
return this.$fhcApi.post(
|
||||
'/api/frontend/v1/filter/saveCustomFilter',
|
||||
{
|
||||
filterUniqueId: wsParams.filterUniqueId,
|
||||
filterType: wsParams.filterType,
|
||||
customFilterName: wsParams.customFilterName
|
||||
}
|
||||
);
|
||||
},
|
||||
removeCustomFilter(wsParams) {
|
||||
return this.$fhcApi.post(
|
||||
'/api/frontend/v1/filter/removeCustomFilter',
|
||||
{
|
||||
filterUniqueId: wsParams.filterUniqueId,
|
||||
filterType: wsParams.filterType,
|
||||
filterId: wsParams.filterId
|
||||
}
|
||||
);
|
||||
},
|
||||
applyFilterFields(wsParams) {
|
||||
return this.$fhcApi.post(
|
||||
'/api/frontend/v1/filter/applyFilterFields',
|
||||
{
|
||||
filterUniqueId: wsParams.filterUniqueId,
|
||||
filterType: wsParams.filterType,
|
||||
filterFields: wsParams.filterFields
|
||||
}
|
||||
);
|
||||
},
|
||||
addFilterField(wsParams) {
|
||||
return this.$fhcApi.post(
|
||||
'/api/frontend/v1/filter/addFilterField',
|
||||
{
|
||||
filterUniqueId: wsParams.filterUniqueId,
|
||||
filterType: wsParams.filterType,
|
||||
filterField: wsParams.filterField
|
||||
}
|
||||
);
|
||||
},
|
||||
removeFilterField(wsParams) {
|
||||
return this.$fhcApi.post(
|
||||
'/api/frontend/v1/filter/removeFilterField',
|
||||
{
|
||||
filterUniqueId: wsParams.filterUniqueId,
|
||||
filterType: wsParams.filterType,
|
||||
filterField: wsParams.filterField
|
||||
}
|
||||
);
|
||||
},
|
||||
getFilterById(wsParams) {
|
||||
return this.$fhcApi.get(
|
||||
'/api/frontend/v1/filter/getFilter',
|
||||
{
|
||||
filterUniqueId: wsParams.filterUniqueId,
|
||||
filterType: wsParams.filterType,
|
||||
filterId: wsParams.filterId
|
||||
}
|
||||
);
|
||||
},
|
||||
getFilter(wsParams) {
|
||||
return this.$fhcApi.get(
|
||||
'/api/frontend/v1/filter/getFilter',
|
||||
{
|
||||
filterUniqueId: wsParams.filterUniqueId,
|
||||
filterType: wsParams.filterType
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
export default {
|
||||
getHeader(navigation_page) {
|
||||
return this.$fhcApi.get(
|
||||
'/api/frontend/v1/navigation/header',
|
||||
{ navigation_page }
|
||||
);
|
||||
},
|
||||
getMenu: function(navigation_page) {
|
||||
return this.$fhcApi.get(
|
||||
'/api/frontend/v1/navigation/menu',
|
||||
{ navigation_page }
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
export default {
|
||||
loadCategory(category) {
|
||||
return this.$fhcApi.get('/api/frontend/v1/phrasen/loadModule/' + category);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
export default {
|
||||
search(searchsettings) {
|
||||
const url = '/api/frontend/v1/searchbar/search';
|
||||
return this.$fhcApi.post(url, searchsettings);
|
||||
},
|
||||
searchdummy(searchsettings) {
|
||||
const url = 'public/js/apps/api/dummyapi.php/Search';
|
||||
return this.$fhcApi.post(url, searchsettings);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,223 @@
|
||||
/**
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
export default {
|
||||
abmeldung: {
|
||||
getDetails(antrag_id, prestudent_id) {
|
||||
const url = '/api/frontend/v1/studstatus/abmeldung/'
|
||||
+ (antrag_id !== undefined ? 'getDetailsForAntrag/' + antrag_id : 'getDetailsForNewAntrag/' + prestudent_id);
|
||||
return this.$fhcApi.get(url);
|
||||
},
|
||||
create(stdsem, prestudent_id, grund) {
|
||||
return this.$fhcApi.post('/api/frontend/v1/studstatus/abmeldung/createAntrag', {
|
||||
studiensemester: stdsem,
|
||||
prestudent_id,
|
||||
grund
|
||||
}, {
|
||||
errorHandling: 'strict'
|
||||
});
|
||||
},
|
||||
cancel(antrag_id) {
|
||||
if (!Array.isArray(antrag_id))
|
||||
return this.$fhcApi.post(
|
||||
'/api/frontend/v1/studstatus/abmeldung/cancelAntrag',
|
||||
{ antrag_id }
|
||||
);
|
||||
return Promise.allSettled(antrag_id.map(antrag => this.$fhcApi.post(
|
||||
'/api/frontend/v1/studstatus/abmeldung/cancelAntrag',
|
||||
{ antrag_id: antrag.studierendenantrag_id },
|
||||
{ errorHeader: '#' + antrag.studierendenantrag_id }
|
||||
)));
|
||||
}
|
||||
},
|
||||
unterbrechung: {
|
||||
getDetails(antrag_id, prestudent_id) {
|
||||
const url = '/api/frontend/v1/studstatus/unterbrechung/'
|
||||
+ (antrag_id !== undefined ? 'getDetailsForAntrag/' + antrag_id : 'getDetailsForNewAntrag/' + prestudent_id);
|
||||
return this.$fhcApi.get(url);
|
||||
},
|
||||
create(studiensemester, prestudent_id, grund, datum_wiedereinstieg, attachment) {
|
||||
return this.$fhcApi.post('/api/frontend/v1/studstatus/unterbrechung/createAntrag', {
|
||||
studiensemester,
|
||||
prestudent_id,
|
||||
grund,
|
||||
datum_wiedereinstieg,
|
||||
attachment
|
||||
}, {
|
||||
errorHandling: 'strict'
|
||||
});
|
||||
},
|
||||
cancel(antrag_id) {
|
||||
return this.$fhcApi.post('/api/frontend/v1/studstatus/unterbrechung/cancelAntrag', {
|
||||
antrag_id
|
||||
}, {
|
||||
errorHandling: 'strict'
|
||||
});
|
||||
}
|
||||
},
|
||||
wiederholung: {
|
||||
getDetails(prestudent_id) {
|
||||
const url = '/api/frontend/v1/studstatus/wiederholung/getDetailsForNewAntrag/' + prestudent_id;
|
||||
return this.$fhcApi.get(url)
|
||||
},
|
||||
getLvs(antrag_id) {
|
||||
const url = '/api/frontend/v1/studstatus/wiederholung/getLvs/' + antrag_id;
|
||||
return this.$fhcApi.get(url)
|
||||
},
|
||||
create(prestudent_id, studiensemester) {
|
||||
return this.$fhcApi.post('/api/frontend/v1/studstatus/wiederholung/createAntrag', {
|
||||
prestudent_id,
|
||||
studiensemester
|
||||
}, {
|
||||
errorHandling: 'strict'
|
||||
});
|
||||
},
|
||||
cancel(prestudent_id, studiensemester) {
|
||||
return this.$fhcApi.post('/api/frontend/v1/studstatus/wiederholung/cancelAntrag', {
|
||||
prestudent_id,
|
||||
studiensemester
|
||||
}, {
|
||||
errorHandling: 'strict'
|
||||
});
|
||||
},
|
||||
saveLvs(forbiddenLvs, mandatoryLvs) {
|
||||
return this.$fhcApi.post('/api/frontend/v1/studstatus/wiederholung/saveLvs', {
|
||||
forbiddenLvs,
|
||||
mandatoryLvs
|
||||
});
|
||||
}
|
||||
},
|
||||
leitung: {
|
||||
getStgs() {
|
||||
return this.$fhcApi.get('/api/frontend/v1/studstatus/leitung/getActiveStgs');
|
||||
},
|
||||
getAntraege(url, config, params) {
|
||||
return this.$fhcApi
|
||||
.get('/api/frontend/v1/studstatus/leitung/getAntraege/' + url)
|
||||
.then(res => res.data); // Return data for tabulator
|
||||
},
|
||||
getHistory(antrag_id) {
|
||||
return this.$fhcApi.get('/api/frontend/v1/studstatus/leitung/getHistory/' + antrag_id)
|
||||
},
|
||||
getPrestudents(query, signal) {
|
||||
return this.$fhcApi.post(
|
||||
'/api/frontend/v1/studstatus/leitung/getPrestudents',
|
||||
{ query },
|
||||
{
|
||||
signal: signal,
|
||||
timeout: 30000
|
||||
}
|
||||
);
|
||||
},
|
||||
approve(antrag) {
|
||||
if (!Array.isArray(antrag))
|
||||
return this.$fhcApi.post(
|
||||
'/api/frontend/v1/studstatus/leitung/approveAntrag',
|
||||
antrag
|
||||
);
|
||||
return Promise.allSettled(antrag.map(a => this.$fhcApi.post(
|
||||
'/api/frontend/v1/studstatus/leitung/approveAntrag',
|
||||
a,
|
||||
{ errorHeader: '#' + a.studierendenantrag_id }
|
||||
)));
|
||||
},
|
||||
reject(antrag) {
|
||||
if (!Array.isArray(antrag))
|
||||
return this.$fhcApi.post(
|
||||
'/api/frontend/v1/studstatus/leitung/rejectAntrag',
|
||||
antrag
|
||||
);
|
||||
return Promise.allSettled(antrag.map(a => this.$fhcApi.post(
|
||||
'/api/frontend/v1/studstatus/leitung/rejectAntrag',
|
||||
a,
|
||||
{ errorHeader: '#' + a.studierendenantrag_id }
|
||||
)));
|
||||
},
|
||||
reopen(antrag) {
|
||||
if (!Array.isArray(antrag))
|
||||
return this.$fhcApi.post(
|
||||
'/api/frontend/v1/studstatus/leitung/reopenAntrag',
|
||||
antrag
|
||||
);
|
||||
return Promise.allSettled(antrag.map(a => this.$fhcApi.post(
|
||||
'/api/frontend/v1/studstatus/leitung/reopenAntrag',
|
||||
a,
|
||||
{ errorHeader: '#' + a.studierendenantrag_id }
|
||||
)));
|
||||
},
|
||||
pause(antrag) {
|
||||
if (!Array.isArray(antrag))
|
||||
return this.$fhcApi.post(
|
||||
'/api/frontend/v1/studstatus/leitung/pauseAntrag',
|
||||
antrag
|
||||
);
|
||||
return Promise.allSettled(antrag.map(a => this.$fhcApi.post(
|
||||
'/api/frontend/v1/studstatus/leitung/pauseAntrag',
|
||||
a,
|
||||
{ errorHeader: '#' + a.studierendenantrag_id }
|
||||
)));
|
||||
},
|
||||
unpause(antrag) {
|
||||
if (!Array.isArray(antrag))
|
||||
return this.$fhcApi.post(
|
||||
'/api/frontend/v1/studstatus/leitung/unpauseAntrag',
|
||||
antrag
|
||||
);
|
||||
return Promise.allSettled(antrag.map(a => this.$fhcApi.post(
|
||||
'/api/frontend/v1/studstatus/leitung/unpauseAntrag',
|
||||
a,
|
||||
{ errorHeader: '#' + a.studierendenantrag_id }
|
||||
)));
|
||||
},
|
||||
object(antrag) {
|
||||
if (!Array.isArray(antrag))
|
||||
return this.$fhcApi.post(
|
||||
'/api/frontend/v1/studstatus/leitung/objectAntrag',
|
||||
antrag
|
||||
);
|
||||
return Promise.allSettled(antrag.map(a => this.$fhcApi.post(
|
||||
'/api/frontend/v1/studstatus/leitung/objectAntrag',
|
||||
a,
|
||||
{ errorHeader: '#' + a.studierendenantrag_id }
|
||||
)));
|
||||
},
|
||||
approveObjection(antrag) {
|
||||
if (!Array.isArray(antrag))
|
||||
return this.$fhcApi.post(
|
||||
'/api/frontend/v1/studstatus/leitung/approveObjection',
|
||||
antrag
|
||||
);
|
||||
return Promise.allSettled(antrag.map(a => this.$fhcApi.post(
|
||||
'/api/frontend/v1/studstatus/leitung/approveObjection',
|
||||
a,
|
||||
{ errorHeader: '#' + a.studierendenantrag_id }
|
||||
)));
|
||||
},
|
||||
denyObjection(antrag) {
|
||||
if (!Array.isArray(antrag))
|
||||
return this.$fhcApi.post(
|
||||
'/api/frontend/v1/studstatus/leitung/denyObjection',
|
||||
antrag
|
||||
);
|
||||
return Promise.allSettled(antrag.map(a => this.$fhcApi.post(
|
||||
'/api/frontend/v1/studstatus/leitung/denyObjection',
|
||||
a,
|
||||
{ errorHeader: '#' + a.studierendenantrag_id }
|
||||
)));
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -24,6 +24,8 @@ import {CoreRESTClient} from '../../RESTClient.js';
|
||||
import {CoreFetchCmpt} from '../../components/Fetch.js';
|
||||
import {BismeldestichtagAPIs} from './API.js';
|
||||
|
||||
import Phrasen from '../../plugin/Phrasen.js';
|
||||
|
||||
const bismeldestichtagApp = Vue.createApp({
|
||||
data: function() {
|
||||
return {
|
||||
@@ -187,4 +189,4 @@ const bismeldestichtagApp = Vue.createApp({
|
||||
}
|
||||
});
|
||||
|
||||
bismeldestichtagApp.mount('#main');
|
||||
bismeldestichtagApp.use(Phrasen).mount('#main');
|
||||
|
||||
@@ -21,6 +21,8 @@ import {LogsViewerTabulatorEventHandlers} from './TabulatorSetup.js';
|
||||
import {CoreFilterCmpt} from '../../components/filter/Filter.js';
|
||||
import {CoreNavigationCmpt} from '../../components/navigation/Navigation.js';
|
||||
|
||||
import Phrasen from '../../plugin/Phrasen.js';
|
||||
|
||||
const logsViewerApp = Vue.createApp({
|
||||
data: function() {
|
||||
return {
|
||||
@@ -40,5 +42,5 @@ const logsViewerApp = Vue.createApp({
|
||||
}
|
||||
});
|
||||
|
||||
logsViewerApp.mount('#main');
|
||||
logsViewerApp.use(Phrasen).mount('#main');
|
||||
|
||||
|
||||
+194
-194
@@ -1,195 +1,195 @@
|
||||
import {CoreFilterCmpt} from '../components/Filter.js';
|
||||
import {CoreNavigationCmpt} from '../components/Navigation.js';
|
||||
import verticalsplit from "../components/verticalsplit/verticalsplit.js";
|
||||
import searchbar from "../components/searchbar/searchbar.js";
|
||||
import fhcapifactory from "./api/fhcapifactory.js";
|
||||
import {CoreFilterCmpt} from '../components/filter/Filter.js';
|
||||
import {CoreNavigationCmpt} from '../components/navigation/Navigation.js';
|
||||
import CoreVerticalsplit from "../components/verticalsplit/verticalsplit.js";
|
||||
import CoreSearchbar from "../components/searchbar/searchbar.js";
|
||||
import FhcApi from "../plugin/FhcApi.js";
|
||||
|
||||
Vue.$fhcapi = fhcapifactory;
|
||||
|
||||
Vue.createApp({
|
||||
"data": function() {
|
||||
return {
|
||||
"title": "Test Search",
|
||||
"appSideMenuEntries": {},
|
||||
"searchbaroptions": {
|
||||
"types": [
|
||||
"person",
|
||||
"raum",
|
||||
"mitarbeiter",
|
||||
"student",
|
||||
"prestudent",
|
||||
"document",
|
||||
"cms",
|
||||
"organisationunit"
|
||||
],
|
||||
"actions": {
|
||||
"person": {
|
||||
"defaultaction": {
|
||||
"type": "link",
|
||||
"action": function(data) {
|
||||
//alert('person defaultaction ' + JSON.stringify(data));
|
||||
//window.location.href = data.profil;
|
||||
return data.profil;
|
||||
}
|
||||
},
|
||||
"childactions": [
|
||||
{
|
||||
"label": "testchildaction1",
|
||||
"icon": "fas fa-check-circle",
|
||||
"type": "function",
|
||||
"action": function(data) {
|
||||
alert('person testchildaction 01 ' + JSON.stringify(data));
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "testchildaction2",
|
||||
"icon": "fas fa-file-csv",
|
||||
"type": "function",
|
||||
"action": function(data) {
|
||||
alert('person testchildaction 02 ' + JSON.stringify(data));
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"raum": {
|
||||
"defaultaction": {
|
||||
"type": "function",
|
||||
"action": function(data) {
|
||||
alert('raum defaultaction ' + JSON.stringify(data));
|
||||
}
|
||||
},
|
||||
"childactions": [
|
||||
{
|
||||
"label": "Rauminformation",
|
||||
"icon": "fas fa-info-circle",
|
||||
"type": "link",
|
||||
"action": function(data) {
|
||||
return data.infolink;
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "Raumreservierung",
|
||||
"icon": "fas fa-bookmark",
|
||||
"type": "link",
|
||||
"action": function(data) {
|
||||
return data.booklink;
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"employee": {
|
||||
"defaultaction": {
|
||||
"type": "function",
|
||||
"action": function(data) {
|
||||
alert('employee defaultaction ' + JSON.stringify(data));
|
||||
}
|
||||
},
|
||||
"childactions": [
|
||||
{
|
||||
"label": "testchildaction1",
|
||||
"icon": "fas fa-address-book",
|
||||
"type": "function",
|
||||
"action": function(data) {
|
||||
alert('employee testchildaction 01 ' + JSON.stringify(data));
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "testchildaction2",
|
||||
"icon": "fas fa-user-slash",
|
||||
"type": "function",
|
||||
"action": function(data) {
|
||||
alert('employee testchildaction 02 ' + JSON.stringify(data));
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "testchildaction3",
|
||||
"icon": "fas fa-bell",
|
||||
"type": "function",
|
||||
"action": function(data) {
|
||||
alert('employee testchildaction 03 ' + JSON.stringify(data));
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "testchildaction4",
|
||||
"icon": "fas fa-calculator",
|
||||
"type": "function",
|
||||
"action": function(data) {
|
||||
alert('employee testchildaction 04 ' + JSON.stringify(data));
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"organisationunit": {
|
||||
"defaultaction": {
|
||||
"type": "function",
|
||||
"action": function(data) {
|
||||
alert('organisationunit defaultaction ' + JSON.stringify(data));
|
||||
}
|
||||
},
|
||||
"childactions": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"searchbaroptions2": {
|
||||
"types": [
|
||||
"raum",
|
||||
"organisationunit"
|
||||
],
|
||||
"actions": {
|
||||
"raum": {
|
||||
"defaultaction": {
|
||||
"type": "function",
|
||||
"action": function(data) {
|
||||
alert('raum defaultaction ' + JSON.stringify(data));
|
||||
}
|
||||
},
|
||||
"childactions": [
|
||||
{
|
||||
"label": "Rauminformation",
|
||||
"icon": "fas fa-info-circle",
|
||||
"type": "link",
|
||||
"action": function(data) {
|
||||
return data.infolink;
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "Raumreservierung",
|
||||
"icon": "fas fa-bookmark",
|
||||
"type": "link",
|
||||
"action": function(data) {
|
||||
return data.booklink;
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"organisationunit": {
|
||||
"defaultaction": {
|
||||
"type": "function",
|
||||
"action": function(data) {
|
||||
alert('organisationunit defaultaction ' + JSON.stringify(data));
|
||||
}
|
||||
},
|
||||
"childactions": []
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
"components": {
|
||||
"CoreNavigationCmpt": CoreNavigationCmpt,
|
||||
"CoreFilterCmpt": CoreFilterCmpt,
|
||||
"verticalsplit": verticalsplit,
|
||||
"searchbar": searchbar
|
||||
},
|
||||
"methods": {
|
||||
"newSideMenuEntryHandler": function(payload) {
|
||||
this.appSideMenuEntries = payload;
|
||||
},
|
||||
"searchfunction": function(searchsettings) {
|
||||
return Vue.$fhcapi.Search.search(searchsettings);
|
||||
},
|
||||
"searchfunctiondummy": function(searchsettings) {
|
||||
return Vue.$fhcapi.Search.searchdummy(searchsettings);
|
||||
}
|
||||
}
|
||||
}).mount('#main');
|
||||
const app = Vue.createApp({
|
||||
components: {
|
||||
CoreNavigationCmpt,
|
||||
CoreFilterCmpt,
|
||||
CoreVerticalsplit,
|
||||
CoreSearchbar
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
title: "Test Search",
|
||||
appSideMenuEntries: {},
|
||||
searchbaroptions: {
|
||||
types: [
|
||||
"person",
|
||||
"raum",
|
||||
"mitarbeiter",
|
||||
"student",
|
||||
"prestudent",
|
||||
"document",
|
||||
"cms",
|
||||
"organisationunit"
|
||||
],
|
||||
actions: {
|
||||
person: {
|
||||
defaultaction: {
|
||||
type: "link",
|
||||
action(data) {
|
||||
//alert('person defaultaction ' + JSON.stringify(data));
|
||||
//window.location.href = data.profil;
|
||||
return data.profil;
|
||||
}
|
||||
},
|
||||
childactions: [
|
||||
{
|
||||
label: "testchildaction1",
|
||||
icon: "fas fa-check-circle",
|
||||
type: "function",
|
||||
action(data) {
|
||||
alert('person testchildaction 01 ' + JSON.stringify(data));
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "testchildaction2",
|
||||
icon: "fas fa-file-csv",
|
||||
type: "function",
|
||||
action(data) {
|
||||
alert('person testchildaction 02 ' + JSON.stringify(data));
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
raum: {
|
||||
defaultaction: {
|
||||
type: "function",
|
||||
action(data) {
|
||||
alert('raum defaultaction ' + JSON.stringify(data));
|
||||
}
|
||||
},
|
||||
childactions: [
|
||||
{
|
||||
label: "Rauminformation",
|
||||
icon: "fas fa-info-circle",
|
||||
type: "link",
|
||||
action(data) {
|
||||
return data.infolink;
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "Raumreservierung",
|
||||
icon: "fas fa-bookmark",
|
||||
type: "link",
|
||||
action(data) {
|
||||
return data.booklink;
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
employee: {
|
||||
defaultaction: {
|
||||
type: "function",
|
||||
action(data) {
|
||||
alert('employee defaultaction ' + JSON.stringify(data));
|
||||
}
|
||||
},
|
||||
childactions: [
|
||||
{
|
||||
label: "testchildaction1",
|
||||
icon: "fas fa-address-book",
|
||||
type: "function",
|
||||
action(data) {
|
||||
alert('employee testchildaction 01 ' + JSON.stringify(data));
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "testchildaction2",
|
||||
icon: "fas fa-user-slash",
|
||||
type: "function",
|
||||
action(data) {
|
||||
alert('employee testchildaction 02 ' + JSON.stringify(data));
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "testchildaction3",
|
||||
icon: "fas fa-bell",
|
||||
type: "function",
|
||||
action(data) {
|
||||
alert('employee testchildaction 03 ' + JSON.stringify(data));
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "testchildaction4",
|
||||
icon: "fas fa-calculator",
|
||||
type: "function",
|
||||
action(data) {
|
||||
alert('employee testchildaction 04 ' + JSON.stringify(data));
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
organisationunit: {
|
||||
defaultaction: {
|
||||
type: "function",
|
||||
action(data) {
|
||||
alert('organisationunit defaultaction ' + JSON.stringify(data));
|
||||
}
|
||||
},
|
||||
childactions: []
|
||||
}
|
||||
}
|
||||
},
|
||||
searchbaroptions2: {
|
||||
types: [
|
||||
"raum",
|
||||
"organisationunit"
|
||||
],
|
||||
actions: {
|
||||
raum: {
|
||||
defaultaction: {
|
||||
type: "function",
|
||||
action(data) {
|
||||
alert('raum defaultaction ' + JSON.stringify(data));
|
||||
}
|
||||
},
|
||||
childactions: [
|
||||
{
|
||||
label: "Rauminformation",
|
||||
icon: "fas fa-info-circle",
|
||||
type: "link",
|
||||
action(data) {
|
||||
return data.infolink;
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "Raumreservierung",
|
||||
icon: "fas fa-bookmark",
|
||||
type: "link",
|
||||
action(data) {
|
||||
return data.booklink;
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
organisationunit: {
|
||||
defaultaction: {
|
||||
type: "function",
|
||||
action(data) {
|
||||
alert('organisationunit defaultaction ' + JSON.stringify(data));
|
||||
}
|
||||
},
|
||||
childactions: []
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
newSideMenuEntryHandler(payload) {
|
||||
this.appSideMenuEntries = payload;
|
||||
},
|
||||
searchfunction(searchsettings) {
|
||||
return this.$fhcApi.factory.search.search(searchsettings);
|
||||
},
|
||||
searchfunctiondummy(searchsettings) {
|
||||
return this.$fhcApi.factory.search.searchdummy(searchsettings);
|
||||
}
|
||||
}
|
||||
});
|
||||
app.use(FhcApi)
|
||||
app.mount('#main');
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
import StudierendenantragAntrag from "../../components/Studierendenantrag/Antrag.js";
|
||||
import StudierendenantragStatus from "../../components/Studierendenantrag/Status.js";
|
||||
import StudierendenantragInfoblock from "../../components/Studierendenantrag/Infoblock.js";
|
||||
import VueDatePicker from "../../components/vueDatepicker.js.php";
|
||||
import Phrasen from '../../plugin/Phrasen.js';
|
||||
|
||||
const app = Vue.createApp({
|
||||
components: {
|
||||
VueDatePicker,
|
||||
StudierendenantragAntrag,
|
||||
StudierendenantragStatus,
|
||||
StudierendenantragInfoblock
|
||||
|
||||
@@ -99,8 +99,10 @@ export const CoreFetchCmpt = {
|
||||
*
|
||||
*/
|
||||
errorHandler: function(error) {
|
||||
if (error.response.data.retval)
|
||||
if (error.response?.data?.retval)
|
||||
this.setError(error.response.data.retval);
|
||||
else if (error.data?.message)
|
||||
this.setError(error.data.message);
|
||||
else
|
||||
this.setError(error.message);
|
||||
},
|
||||
|
||||
@@ -9,7 +9,8 @@ export default {
|
||||
$registerToForm: component => {
|
||||
if (this.inputs.indexOf(component) < 0)
|
||||
this.inputs.push(component);
|
||||
}
|
||||
},
|
||||
$clearValidationForName: this.clearValidationForName
|
||||
};
|
||||
},
|
||||
props: {
|
||||
@@ -40,9 +41,34 @@ export default {
|
||||
|
||||
return a;
|
||||
}, {});
|
||||
},
|
||||
factory() {
|
||||
const factory = Object.create(Object.getPrototypeOf(this.$fhcApi.factory), Object.getOwnPropertyDescriptors(this.$fhcApi.factory));
|
||||
factory.$fhcApi = {
|
||||
get: this.get,
|
||||
post: this.post,
|
||||
_defaultErrorHandlers: this.$fhcApi._defaultErrorHandlers
|
||||
};
|
||||
return factory;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
get(...args) {
|
||||
if (typeof args[0] == 'object' && args[0].clearValidation && args[0].setFeedback)
|
||||
args[0] = this;
|
||||
else
|
||||
args.unshift(this);
|
||||
|
||||
return this.$fhcApi.get(...args);
|
||||
},
|
||||
post(...args) {
|
||||
if (typeof args[0] == 'object' && args[0].clearValidation && args[0].setFeedback)
|
||||
args[0] = this;
|
||||
else
|
||||
args.unshift(this);
|
||||
|
||||
return this.$fhcApi.post(...args);
|
||||
},
|
||||
_sendFeedbackToInput(inputs, feedback, valid) {
|
||||
if (inputs.length) {
|
||||
inputs.forEach(input => input.setFeedback(valid, feedback));
|
||||
@@ -128,6 +154,10 @@ export default {
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
clearValidationForName(name) {
|
||||
(this.sortedInputs[name.split('.')[0] + name.split('.').slice(1).map(p => `[${p}]`).join("")] || this.sortedInputs['_default'] || [])
|
||||
.forEach(input => input.clearValidation());
|
||||
}
|
||||
},
|
||||
template: `
|
||||
|
||||
@@ -7,9 +7,16 @@ export default {
|
||||
components: {
|
||||
FhcFragment
|
||||
},
|
||||
inject: [
|
||||
'$registerToForm'
|
||||
],
|
||||
inject: {
|
||||
registerToForm: {
|
||||
from: '$registerToForm',
|
||||
default: null
|
||||
},
|
||||
clearValidationForName: {
|
||||
from: '$clearValidationForName',
|
||||
default: null
|
||||
}
|
||||
},
|
||||
props: {
|
||||
bsFeedback: Boolean,
|
||||
noAutoClass: Boolean,
|
||||
@@ -22,7 +29,8 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
valid: undefined,
|
||||
feedback: []
|
||||
feedback: [],
|
||||
modelValueDummy: undefined
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -31,8 +39,9 @@ export default {
|
||||
return true;
|
||||
if (this.containerClass)
|
||||
return true;
|
||||
if (this.autoContainerClass)
|
||||
return true;
|
||||
for (const prop in this.autoContainerClass)
|
||||
if (Object.hasOwn(this.autoContainerClass, prop))
|
||||
return true;
|
||||
return false;
|
||||
},
|
||||
acc() {
|
||||
@@ -111,13 +120,19 @@ export default {
|
||||
if (!c.includes('form-check-input') && !c.includes('btn-check'))
|
||||
classes.push('form-check-input');
|
||||
break;
|
||||
case 'color':
|
||||
if (!c.includes('form-control-color'))
|
||||
classes.push('form-control-color');
|
||||
if (!c.includes('form-control'))
|
||||
classes.push('form-control');
|
||||
break;
|
||||
case 'autocomplete':
|
||||
case 'datepicker':
|
||||
classes.push('p-0');
|
||||
classes.push('border-0');
|
||||
case 'color':
|
||||
if (!c.includes('form-control-color'))
|
||||
classes.push('form-control-color');
|
||||
if (!c.includes('form-control'))
|
||||
classes.push('form-control');
|
||||
break;
|
||||
case 'text':
|
||||
case 'number':
|
||||
case 'password':
|
||||
@@ -145,9 +160,13 @@ export default {
|
||||
},
|
||||
modelValueCmp: {
|
||||
get() {
|
||||
if (this.$attrs.modelValue === undefined)
|
||||
return this.modelValueDummy;
|
||||
return this.$attrs.modelValue;
|
||||
},
|
||||
set(v) {
|
||||
if (this.$attrs.modelValue === undefined)
|
||||
this.modelValueDummy = v;
|
||||
this.$emit('update:modelValue', v);
|
||||
}
|
||||
},
|
||||
@@ -171,12 +190,26 @@ export default {
|
||||
this.valid = undefined;
|
||||
this.feedback = [];
|
||||
},
|
||||
clearValidationForThisName() {
|
||||
if (this.valid === undefined)
|
||||
return;
|
||||
if (this.clearValidationForName && this.name)
|
||||
this.clearValidationForName(this.name);
|
||||
else
|
||||
this.clearValidation();
|
||||
},
|
||||
setFeedback(valid, feedback) {
|
||||
if (!feedback)
|
||||
feedback = [];
|
||||
if (!Array.isArray(feedback))
|
||||
feedback = [feedback];
|
||||
this.valid = valid;
|
||||
// NOTE(chris): On a list of radios/checkboxes only add the feedback message to the last item
|
||||
if (this.name && (this.lcType == 'radio' || this.lcType == 'checkbox')) {
|
||||
const selector = 'input[type="' + this.lcType + '"][name="' + this.name + '"]';
|
||||
if ([...this.$el.parentNode.querySelectorAll(selector)].pop() != this.$refs.input)
|
||||
return;
|
||||
}
|
||||
this.feedback = feedback;
|
||||
},
|
||||
_loadComponents() {
|
||||
@@ -198,19 +231,20 @@ export default {
|
||||
this._loadComponents();
|
||||
},
|
||||
mounted() {
|
||||
if (this.$registerToForm)
|
||||
this.$registerToForm(this);
|
||||
if (this.registerToForm)
|
||||
this.registerToForm(this);
|
||||
},
|
||||
template: `
|
||||
<component :is="!hasContainer ? 'FhcFragment' : 'div'" class="position-relative" :class="autoContainerClass">
|
||||
<label v-if="$attrs.label && lcType != 'radio' && lcType != 'checkbox'" :for="idCmp">{{$attrs.label}}</label>
|
||||
<input v-if="tag == 'input'" :type="lcType" v-model="modelValueCmp" v-bind="$attrs" :id="idCmp" :name="name" :class="validationClass" :modelValue="undefined" @input="clearValidation(); $emit('input', $event)">
|
||||
<textarea v-else-if="tag == 'textarea'" v-model="modelValueCmp" v-bind="$attrs" :id="idCmp" :name="name" :class="validationClass" :modelValue="undefined" @input="clearValidation(); $emit('input', $event)"></textarea>
|
||||
<select v-else-if="tag == 'select'" v-model="modelValueCmp" v-bind="$attrs" :id="idCmp" :name="name" :class="validationClass" :modelValue="undefined" @input="clearValidation(); $emit('input', $event)">
|
||||
<input v-if="tag == 'input'" :type="lcType" ref="input" v-model="modelValueCmp" v-bind="$attrs" :id="idCmp" :name="name" :class="validationClass" :modelValue="undefined" @input="clearValidationForThisName(); $emit('input', $event)">
|
||||
<textarea v-else-if="tag == 'textarea'" ref="input" v-model="modelValueCmp" v-bind="$attrs" :id="idCmp" :name="name" :class="validationClass" :modelValue="undefined" @input="clearValidationForThisName(); $emit('input', $event)"></textarea>
|
||||
<select v-else-if="tag == 'select'" ref="input" v-model="modelValueCmp" v-bind="$attrs" :id="idCmp" :name="name" :class="validationClass" :modelValue="undefined" @input="clearValidationForThisName(); $emit('input', $event)">
|
||||
<slot></slot>
|
||||
</select>
|
||||
<component
|
||||
v-else-if="tag == 'VueDatePicker'"
|
||||
ref="input"
|
||||
:is="tag"
|
||||
:type="type"
|
||||
v-model="modelValueCmp"
|
||||
@@ -220,26 +254,25 @@ export default {
|
||||
:class="validationClass"
|
||||
:input-class-name=
|
||||
"[...Object.entries({'form-control': !noAutoClass, 'is-valid': valid === true, 'is-invalid': valid === false}).reduce((a,[k,v]) => {if(v) a.push(k);return a}, []), ...($attrs['input-class-name'] ? $attrs['input-class-name'].split(' ') : [])].join(' ')"
|
||||
@update:model-value="clearValidation"
|
||||
@update:model-value="clearValidationForThisName"
|
||||
>
|
||||
<slot></slot>
|
||||
</component>
|
||||
<component
|
||||
v-else-if="tag == 'PvAutocomplete'"
|
||||
:is="tag"
|
||||
:type="type"
|
||||
ref="input"
|
||||
v-model="modelValueCmp"
|
||||
v-bind="$attrs"
|
||||
:id="idCmp"
|
||||
:input-props="{name}"
|
||||
:class="validationClass"
|
||||
:input-class="[...Object.entries({'form-control': !noAutoClass, 'is-valid': valid === true, 'is-invalid': valid === false}).reduce((a,[k,v]) => {if(v) a.push(k);return a}, []), ...($attrs['input-class'] ? $attrs['input-class'].split(' ') : [])].join(' ')"
|
||||
@update:model-value="clearValidation"
|
||||
@update:model-value="clearValidationForThisName"
|
||||
>
|
||||
<slot></slot>
|
||||
</component>
|
||||
<component
|
||||
v-else-if="tag == 'UploadDms'"
|
||||
ref="input"
|
||||
:is="tag"
|
||||
:type="type"
|
||||
v-model="modelValueCmp"
|
||||
@@ -249,12 +282,13 @@ export default {
|
||||
:class="validationClass"
|
||||
:input-class="validationClass"
|
||||
:no-list="inputGroup"
|
||||
@update:model-value="clearValidation"
|
||||
@update:model-value="clearValidationForThisName"
|
||||
>
|
||||
<slot></slot>
|
||||
</component>
|
||||
<component
|
||||
v-else
|
||||
ref="input"
|
||||
:is="tag"
|
||||
:type="type"
|
||||
v-model="modelValueCmp"
|
||||
@@ -262,7 +296,7 @@ export default {
|
||||
:id="idCmp"
|
||||
:name="name"
|
||||
:class="validationClass"
|
||||
@update:model-value="clearValidation"
|
||||
@update:model-value="clearValidationForThisName"
|
||||
>
|
||||
<slot></slot>
|
||||
</component>
|
||||
|
||||
@@ -53,29 +53,29 @@ export default {
|
||||
},
|
||||
watch: {
|
||||
modelValue(n) {
|
||||
if (n instanceof FileList)
|
||||
return this.$refs.upload.files = n;
|
||||
|
||||
const dt = new DataTransfer();
|
||||
const dms = [];
|
||||
for (var file of n) {
|
||||
if (file instanceof File) {
|
||||
dt.items.add(file);
|
||||
} else {
|
||||
const dmsFile = new File([JSON.stringify(file)], file.name, {
|
||||
type: 'application/x.fhc-dms+json'
|
||||
});
|
||||
dt.items.add(dmsFile);
|
||||
}
|
||||
if (n instanceof FileList)
|
||||
return this.$refs.upload.files = n;
|
||||
|
||||
const dt = new DataTransfer();
|
||||
const dms = [];
|
||||
for (var file of n) {
|
||||
if (file instanceof File) {
|
||||
dt.items.add(file);
|
||||
} else {
|
||||
const dmsFile = new File([JSON.stringify(file)], file.name, {
|
||||
type: 'application/x.fhc-dms+json'
|
||||
});
|
||||
dt.items.add(dmsFile);
|
||||
}
|
||||
this.$emit('update:modelValue', dt.files);
|
||||
},
|
||||
}
|
||||
this.$emit('update:modelValue', dt.files);
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<div class="form-upload-dms">
|
||||
<input ref="upload" class="form-control" :class="inputClass" :id="id" :name="name" :multiple="multiple" type="file" @change="addFiles">
|
||||
<ul v-if="modelValue.length && multiple && !noList" class="list-unstyled m-0">
|
||||
<li v-for="(file, index) in modelValue" :key="index" class="d-flex mx-1 mt-1 align-items-center">
|
||||
<li v-for="(file, index) in modelValue" :key="index" class="d-flex mx-1 mt-1 align-items-start">
|
||||
<span class="col-auto"><i class="fa fa-file me-1"></i></span>
|
||||
<span class="col">{{ file.name }}</span>
|
||||
<button class="col-auto btn btn-outline-secondary btn-p-0" @click="removeFile(index)">
|
||||
|
||||
@@ -1,26 +1,29 @@
|
||||
const FEEDBACK_DEFAULT = {
|
||||
success: [],
|
||||
danger: []
|
||||
};
|
||||
export default {
|
||||
inject: [
|
||||
'$registerToForm'
|
||||
],
|
||||
data() {
|
||||
return {
|
||||
feedback: FEEDBACK_DEFAULT
|
||||
feedback: {
|
||||
success: [],
|
||||
danger: []
|
||||
}
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
clearValidation() {
|
||||
this.feedback = FEEDBACK_DEFAULT;
|
||||
this.feedback = {
|
||||
success: [],
|
||||
danger: []
|
||||
};
|
||||
},
|
||||
setFeedback(valid, feedback) {
|
||||
if (!feedback)
|
||||
feedback = [];
|
||||
if (!Array.isArray(feedback))
|
||||
feedback = [feedback];
|
||||
this.feedback[valid ? 'success' : 'danger'] = feedback;
|
||||
const ts = Date.now();
|
||||
this.feedback[valid ? 'success' : 'danger'] = feedback.map(msg => [msg, ts]);
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
@@ -29,7 +32,7 @@ export default {
|
||||
},
|
||||
template: `
|
||||
<template v-for="(arr, key) in feedback" :key="key">
|
||||
<div v-for="msg in arr" :key="msg" class="alert alert-dismissible fade show" :class="'alert-' + key" role="alert">
|
||||
<div v-for="[msg, ts] in arr" :key="ts + msg" class="alert alert-dismissible fade show" :class="'alert-' + key" role="alert">
|
||||
{{msg}}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
export default {
|
||||
render() {
|
||||
return (this.$slots && this.$slots.default) ? this.$slots.default() : null;
|
||||
}
|
||||
};
|
||||
@@ -1,10 +1,16 @@
|
||||
import {CoreFetchCmpt} from '../../Fetch.js';
|
||||
import CoreForm from '../../Form/Form.js';
|
||||
import FormValidation from '../../Form/Validation.js';
|
||||
import FormInput from '../../Form/Input.js';
|
||||
|
||||
var _uuid = 0;
|
||||
|
||||
export default {
|
||||
components: {
|
||||
CoreFetchCmpt
|
||||
CoreFetchCmpt,
|
||||
CoreForm,
|
||||
FormValidation,
|
||||
FormInput
|
||||
},
|
||||
emits: [
|
||||
'setInfos',
|
||||
@@ -18,9 +24,8 @@ export default {
|
||||
return {
|
||||
data: null,
|
||||
saving: false,
|
||||
errors: {
|
||||
grund: [],
|
||||
default: []
|
||||
formData: {
|
||||
grund: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -29,36 +34,32 @@ export default {
|
||||
switch (this.data.status)
|
||||
{
|
||||
case 'Erstellt': return 'info';
|
||||
case 'Pause':
|
||||
case 'Zurueckgezogen': return 'danger';
|
||||
case 'Genehmigt': return 'success';
|
||||
default: return 'info';
|
||||
default: return 'warning';
|
||||
}
|
||||
},
|
||||
loadUrl() {
|
||||
if (this.studierendenantragId)
|
||||
return '/components/Antrag/Abmeldung/getDetailsForAntrag/'+
|
||||
this.studierendenantragId;
|
||||
return '/components/Antrag/Abmeldung/getDetailsForNewAntrag/' +
|
||||
this.prestudentId;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
load() {
|
||||
return axios.get(
|
||||
FHC_JS_DATA_STORAGE_OBJECT.app_root +
|
||||
FHC_JS_DATA_STORAGE_OBJECT.ci_router +
|
||||
this.loadUrl
|
||||
).then(
|
||||
result => {
|
||||
this.data = result.data.retval;
|
||||
return this.$fhcApi.factory
|
||||
.studstatus.abmeldung.getDetails(this.studierendenantragId, this.prestudentId)
|
||||
.then(result => {
|
||||
this.data = result.data;
|
||||
if (this.data.status) {
|
||||
const msg = (this.data.status == 'Pause' && this.data.status_insertvon == "Studienabbruch") ? Vue.computed(() => {
|
||||
let status = this.$p.t('studierendenantrag/status_stop');
|
||||
return this.$p.t('studierendenantrag', 'status_x', {status});
|
||||
}) : Vue.computed(() => this.$p.t('studierendenantrag', 'status_x', {status: this.data.statustyp}));
|
||||
this.$emit("setStatus", {
|
||||
msg: Vue.computed(() => this.$p.t('studierendenantrag', 'status_x', {status: this.data.statustyp})),
|
||||
msg,
|
||||
severity: this.statusSeverity
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
);
|
||||
})
|
||||
.catch(this.$fhcAlert.handleSystemError);
|
||||
},
|
||||
createAntrag() {
|
||||
bootstrap.Modal.getOrCreateInstance(this.$refs.modal).hide();
|
||||
@@ -67,52 +68,39 @@ export default {
|
||||
severity: 'warning'
|
||||
});
|
||||
this.saving = true;
|
||||
for(var k in this.errors)
|
||||
this.errors[k] = [];
|
||||
axios.post(
|
||||
FHC_JS_DATA_STORAGE_OBJECT.app_root +
|
||||
FHC_JS_DATA_STORAGE_OBJECT.ci_router +
|
||||
'/components/Antrag/Abmeldung/createAntrag/', {
|
||||
studiensemester: this.data.studiensemester_kurzbz,
|
||||
prestudent_id: this.data.prestudent_id,
|
||||
grund: this.$refs.grund.value
|
||||
}
|
||||
).then(
|
||||
result => {
|
||||
if (result.data.error)
|
||||
{
|
||||
for (var k in result.data.retval)
|
||||
{
|
||||
if (this.errors[k] !== undefined)
|
||||
this.errors[k].push(result.data.retval[k]);
|
||||
else
|
||||
this.errors.default.push(result.data.retval[k]);
|
||||
}
|
||||
this.$emit('setStatus', {
|
||||
msg: Vue.computed(() => this.$p.t('studierendenantrag', 'status_x', {status: this.$p.t('studierendenantrag', 'status_error')})),
|
||||
severity: 'danger'
|
||||
|
||||
this.$refs.form.clearValidation();
|
||||
this.$refs.form.factory
|
||||
.studstatus.abmeldung.create(
|
||||
this.data.studiensemester_kurzbz,
|
||||
this.data.prestudent_id,
|
||||
this.formData.grund
|
||||
)
|
||||
.then(result => {
|
||||
if (result.data === true)
|
||||
document.location += "";
|
||||
|
||||
this.data = result.data;
|
||||
if (this.data.status)
|
||||
this.$emit("setStatus", {
|
||||
msg: Vue.computed(() => this.$p.t('studierendenantrag', 'status_x', {status: this.data.statustyp})),
|
||||
severity: this.statusSeverity
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
if (result.data.retval === true)
|
||||
document.location += "";
|
||||
this.data = result.data.retval;
|
||||
if (this.data.status) {
|
||||
this.$emit("setStatus", {
|
||||
msg: Vue.computed(() => this.$p.t('studierendenantrag', 'status_x', {status: this.data.statustyp})),
|
||||
severity: this.statusSeverity
|
||||
});
|
||||
}
|
||||
else
|
||||
this.$emit('setStatus', {
|
||||
msg: Vue.computed(() => this.$p.t('studierendenantrag', 'status_x', {status: this.$p.t('studierendenantrag', 'status_open')})),
|
||||
severity:'success'
|
||||
});
|
||||
}
|
||||
this.$emit('setStatus', {
|
||||
msg: Vue.computed(() => this.$p.t('studierendenantrag', 'status_x', {status: this.$p.t('studierendenantrag', 'status_open')})),
|
||||
severity:'success'
|
||||
});
|
||||
this.saving = false;
|
||||
}
|
||||
);
|
||||
})
|
||||
.catch(error => {
|
||||
this.$emit('setStatus', {
|
||||
msg: Vue.computed(() => this.$p.t('studierendenantrag', 'status_x', {status: this.$p.t('studierendenantrag', 'status_error')})),
|
||||
severity: 'danger'
|
||||
});
|
||||
this.saving = false;
|
||||
this.$fhcAlert.handleSystemError(error);
|
||||
});
|
||||
},
|
||||
cancelAntrag() {
|
||||
this.$emit('setStatus', {
|
||||
@@ -120,51 +108,37 @@ export default {
|
||||
severity: 'warning'
|
||||
});
|
||||
this.saving = true;
|
||||
for(var k in this.errors)
|
||||
this.errors[k] = [];
|
||||
axios.post(
|
||||
FHC_JS_DATA_STORAGE_OBJECT.app_root +
|
||||
FHC_JS_DATA_STORAGE_OBJECT.ci_router +
|
||||
'/components/Antrag/Abmeldung/cancelAntrag/', {
|
||||
antrag_id: this.data.studierendenantrag_id
|
||||
}
|
||||
).then(
|
||||
result => {
|
||||
if (result.data.error)
|
||||
{
|
||||
for (var k in result.data.retval)
|
||||
{
|
||||
if (this.errors[k] !== undefined)
|
||||
this.errors[k].push(result.data.retval[k]);
|
||||
else
|
||||
this.errors.default.push(result.data.retval[k]);
|
||||
}
|
||||
this.$emit('setStatus', {
|
||||
msg: Vue.computed(() => this.$p.t('studierendenantrag', 'status_x', {status: this.$p.t('studierendenantrag', 'status_error')})),
|
||||
severity:'danger'
|
||||
|
||||
this.$refs.form.clearValidation();
|
||||
this.$refs.form.factory
|
||||
.studstatus.abmeldung.cancel(
|
||||
this.data.studierendenantrag_id
|
||||
)
|
||||
.then(result => {
|
||||
if (Number.isInteger(result.data))
|
||||
document.location = document.location.replace(/abmeldung\/([0-9]*)\/[0-9]*[\/]?$/, 'abmeldung/$1') + "/" + result.data;
|
||||
|
||||
this.data = result.data;
|
||||
if (this.data.status)
|
||||
this.$emit("setStatus", {
|
||||
msg: Vue.computed(() => this.$p.t('studierendenantrag', 'status_x', {status: this.data.statustyp})),
|
||||
severity: this.statusSeverity
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Number.isInteger(result.data.retval)) {
|
||||
document.location = document.location.replace(/abmeldung\/([0-9]*)\/[0-9]*[\/]?$/, 'abmeldung/$1') + "/" + result.data.retval;
|
||||
}
|
||||
this.data = result.data.retval;
|
||||
if (this.data.status) {
|
||||
this.$emit("setStatus", {
|
||||
msg: Vue.computed(() => this.$p.t('studierendenantrag', 'status_x', {status: this.data.statustyp})),
|
||||
severity: this.statusSeverity
|
||||
});
|
||||
}
|
||||
else
|
||||
this.$emit('setStatus', {
|
||||
msg: Vue.computed(() => this.$p.t('studierendenantrag', 'status_x', {status: this.$p.t('studierendenantrag', 'status_cancelled')})),
|
||||
severity: 'danger'
|
||||
});
|
||||
}
|
||||
this.$emit('setStatus', {
|
||||
msg: Vue.computed(() => this.$p.t('studierendenantrag', 'status_x', {status: this.$p.t('studierendenantrag', 'status_cancelled')})),
|
||||
severity: 'danger'
|
||||
});
|
||||
this.saving = false;
|
||||
}
|
||||
);
|
||||
})
|
||||
.catch(error => {
|
||||
this.$emit('setStatus', {
|
||||
msg: Vue.computed(() => this.$p.t('studierendenantrag', 'status_x', {status: this.$p.t('studierendenantrag', 'status_error')})),
|
||||
severity: 'danger'
|
||||
});
|
||||
this.saving = false;
|
||||
this.$fhcAlert.handleSystemError(error);
|
||||
});
|
||||
}
|
||||
},
|
||||
created() {
|
||||
@@ -173,10 +147,9 @@ export default {
|
||||
template: `
|
||||
<div class="studierendenantrag-form-abmeldung">
|
||||
<core-fetch-cmpt :api-function="load">
|
||||
<div class="row">
|
||||
<core-form ref="form" class="row">
|
||||
<div class="col-12">
|
||||
<div v-for="error in errors.default" class="alert alert-danger" role="alert" v-html="error">
|
||||
</div>
|
||||
<form-validation></form-validation>
|
||||
<table class="table">
|
||||
<tr>
|
||||
<th>{{$p.t('lehre', 'studiengang')}}</th>
|
||||
@@ -213,19 +186,16 @@ export default {
|
||||
<pre>{{data.grund}}</pre>
|
||||
</div>
|
||||
<div v-else class="col-sm-6 mb-3">
|
||||
<label :for="'studierendenantrag-form-abmeldung-' + uuid + '-grund'" class="form-label">Grund:</label>
|
||||
<textarea
|
||||
class="form-control"
|
||||
:class="{'is-invalid': errors.grund.length}"
|
||||
:id="'studierendenantrag-form-abmeldung-' + uuid + '-grund'"
|
||||
<form-input
|
||||
type="textarea"
|
||||
label="Grund:"
|
||||
v-model="formData.grund"
|
||||
name="grund"
|
||||
rows="5"
|
||||
:disabled="saving"
|
||||
ref="grund"
|
||||
required
|
||||
></textarea>
|
||||
<div v-if="errors.grund.length" class="invalid-feedback">
|
||||
{{errors.grund.join(".")}}
|
||||
</div>
|
||||
>
|
||||
</form-input>
|
||||
</div>
|
||||
<div class="col-12 text-end">
|
||||
<button
|
||||
@@ -280,13 +250,13 @@ export default {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</core-form>
|
||||
|
||||
<template v-slot:error="{errorMessage}">
|
||||
<div class="alert alert-danger m-0" role="alert">
|
||||
{{ errorMessage }}
|
||||
</div>
|
||||
</template>
|
||||
</core-fetch-cmpt>
|
||||
</div>
|
||||
`
|
||||
</div>`
|
||||
}
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
import {CoreFetchCmpt} from '../../Fetch.js';
|
||||
import CoreForm from '../../Form/Form.js';
|
||||
import FormValidation from '../../Form/Validation.js';
|
||||
import FormInput from '../../Form/Input.js';
|
||||
|
||||
var _uuid = 0;
|
||||
|
||||
export default {
|
||||
components: {
|
||||
CoreFetchCmpt
|
||||
CoreFetchCmpt,
|
||||
CoreForm,
|
||||
FormValidation,
|
||||
FormInput
|
||||
},
|
||||
emits: [
|
||||
'setInfos',
|
||||
@@ -18,9 +24,8 @@ export default {
|
||||
return {
|
||||
data: null,
|
||||
saving: false,
|
||||
errors: {
|
||||
grund: [],
|
||||
default: []
|
||||
formData: {
|
||||
grund: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -29,37 +34,32 @@ export default {
|
||||
switch (this.data?.status)
|
||||
{
|
||||
case 'Erstellt': return 'info';
|
||||
case 'Genehmigt':
|
||||
case 'Pause':
|
||||
case 'Zurueckgezogen': return 'danger';
|
||||
case 'EinspruchAbgelehnt':
|
||||
case 'Abgemeldet': return 'success';
|
||||
default: return 'info';
|
||||
default: return 'warning';
|
||||
}
|
||||
},
|
||||
loadUrl() {
|
||||
if (this.studierendenantragId)
|
||||
return '/components/Antrag/Abmeldung/getDetailsForAntrag/'+
|
||||
this.studierendenantragId;
|
||||
return '/components/Antrag/Abmeldung/getDetailsForNewAntrag/' +
|
||||
this.prestudentId;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
load() {
|
||||
return axios.get(
|
||||
FHC_JS_DATA_STORAGE_OBJECT.app_root +
|
||||
FHC_JS_DATA_STORAGE_OBJECT.ci_router +
|
||||
this.loadUrl
|
||||
).then(
|
||||
result => {
|
||||
this.data = result.data.retval;
|
||||
return this.$fhcApi.factory
|
||||
.studstatus.abmeldung.getDetails(this.studierendenantragId, this.prestudentId)
|
||||
.then(result => {
|
||||
this.data = result.data;
|
||||
if (this.data.status) {
|
||||
const msg = (this.data.status == 'Pause' && this.data.status_insertvon == "Studienabbruch") ? Vue.computed(() => {
|
||||
let status = this.$p.t('studierendenantrag/status_stop');
|
||||
return this.$p.t('studierendenantrag', 'status_x', {status});
|
||||
}) : Vue.computed(() => this.$p.t('studierendenantrag', 'status_x', {status: this.data.statustyp}));
|
||||
this.$emit("setStatus", {
|
||||
msg: Vue.computed(() => this.$p.t('studierendenantrag', 'status_x', {status: this.data.statustyp})),
|
||||
msg,
|
||||
severity: this.statusSeverity
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
);
|
||||
});
|
||||
},
|
||||
createAntrag() {
|
||||
bootstrap.Modal.getOrCreateInstance(this.$refs.modal).hide();
|
||||
@@ -68,63 +68,44 @@ export default {
|
||||
severity: 'warning'
|
||||
});
|
||||
this.saving = true;
|
||||
for(var k in this.errors)
|
||||
this.errors[k] = [];
|
||||
axios.post(
|
||||
FHC_JS_DATA_STORAGE_OBJECT.app_root +
|
||||
FHC_JS_DATA_STORAGE_OBJECT.ci_router +
|
||||
'/components/Antrag/Abmeldung/createAntrag/', {
|
||||
studiensemester: this.data.studiensemester_kurzbz,
|
||||
prestudent_id: this.data.prestudent_id,
|
||||
grund: this.$refs.grund.value
|
||||
}
|
||||
).then(
|
||||
result => {
|
||||
if (result.data.error)
|
||||
{
|
||||
for (var k in result.data.retval)
|
||||
{
|
||||
if (this.errors[k] !== undefined)
|
||||
this.errors[k].push(result.data.retval[k]);
|
||||
else
|
||||
this.errors.default.push(result.data.retval[k]);
|
||||
}
|
||||
this.$emit('setStatus', {
|
||||
msg: Vue.computed(() => this.$p.t('studierendenantrag', 'status_x', {status: this.$p.t('studierendenantrag', 'status_error')})),
|
||||
severity: 'danger'
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
if (result.data.retval === true)
|
||||
document.location += "";
|
||||
this.data = result.data.retval;
|
||||
if (this.data.status) {
|
||||
this.$emit("setStatus", {
|
||||
msg: Vue.computed(() => this.$p.t('studierendenantrag', 'status_x', {status: this.data.statustyp})),
|
||||
severity: this.statusSeverity
|
||||
});
|
||||
}
|
||||
else
|
||||
this.$emit('setStatus', {
|
||||
msg: Vue.computed(() => this.$p.t('studierendenantrag', 'status_x', {status: this.$p.t('studierendenantrag', 'status_open')})),
|
||||
severity:'success'
|
||||
});
|
||||
}
|
||||
this.saving = false;
|
||||
}
|
||||
);
|
||||
},
|
||||
appendDropDownText(event){
|
||||
let templateText = this.$refs.grund;
|
||||
|
||||
if(event.target.value)
|
||||
{
|
||||
let templateT= this.$p.t('studierendenantrag', event.target.value);
|
||||
templateText.value = templateT;
|
||||
}
|
||||
else
|
||||
templateText.value = '';
|
||||
this.$refs.form.clearValidation();
|
||||
this.$refs.form.factory
|
||||
.studstatus.abmeldung.create(
|
||||
this.data.studiensemester_kurzbz,
|
||||
this.data.prestudent_id,
|
||||
this.formData.grund
|
||||
)
|
||||
.then(result => {
|
||||
if (result.data === true)
|
||||
document.location += "";
|
||||
|
||||
this.data = result.data;
|
||||
if (this.data.status)
|
||||
this.$emit("setStatus", {
|
||||
msg: Vue.computed(() => this.$p.t('studierendenantrag', 'status_x', {status: this.data.statustyp})),
|
||||
severity: this.statusSeverity
|
||||
});
|
||||
else
|
||||
this.$emit('setStatus', {
|
||||
msg: Vue.computed(() => this.$p.t('studierendenantrag', 'status_x', {status: this.$p.t('studierendenantrag', 'status_open')})),
|
||||
severity:'success'
|
||||
});
|
||||
this.saving = false;
|
||||
})
|
||||
.catch(error => {
|
||||
this.$emit('setStatus', {
|
||||
msg: Vue.computed(() => this.$p.t('studierendenantrag', 'status_x', {status: this.$p.t('studierendenantrag', 'status_error')})),
|
||||
severity: 'danger'
|
||||
});
|
||||
this.saving = false;
|
||||
this.$fhcAlert.handleSystemError(error);
|
||||
});
|
||||
},
|
||||
appendDropDownText(event) {
|
||||
this.formData.grund = event.target.value
|
||||
? this.$p.t('studierendenantrag', event.target.value)
|
||||
: '';
|
||||
},
|
||||
},
|
||||
created() {
|
||||
@@ -133,8 +114,9 @@ export default {
|
||||
template: `
|
||||
<div class="studierendenantrag-form-abmeldung">
|
||||
<core-fetch-cmpt :api-function="load">
|
||||
<div class="row">
|
||||
<core-form ref="form" class="row">
|
||||
<div class="col-12">
|
||||
<form-validation></form-validation>
|
||||
<table class="table">
|
||||
<tr>
|
||||
<th>{{$p.t('lehre', 'studiengang')}}</th>
|
||||
@@ -175,8 +157,7 @@ export default {
|
||||
<div v-else class="col-sm-6 mb-3">
|
||||
<label :for="'studierendenantrag-form-abmeldung-' + uuid + '-grund'" class="form-label">Grund:</label>
|
||||
<div class="mb-2">
|
||||
<select name="grundAv" @change="appendDropDownText
|
||||
($event)">
|
||||
<select name="grundAv" class="form-select" @change="appendDropDownText">
|
||||
<option value="" > --- bitte auswählen, sofern zutreffend ---- </option>
|
||||
<option value="textLong_NichtantrittStudium">{{$p.t('studierendenantrag', 'dropdown_NichtantrittStudium')}}
|
||||
</option>
|
||||
@@ -193,19 +174,17 @@ export default {
|
||||
<option value="textLong_MissingZgv">{{$p.t('studierendenantrag', 'dropdown_MissingZgv')}}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<textarea
|
||||
class="form-control"
|
||||
:class="{'is-invalid': errors.grund.length}"
|
||||
</div>
|
||||
<form-input
|
||||
type="textarea"
|
||||
v-model="formData.grund"
|
||||
name="grund"
|
||||
:id="'studierendenantrag-form-abmeldung-' + uuid + '-grund'"
|
||||
rows="5"
|
||||
:disabled="saving"
|
||||
ref="grund"
|
||||
required
|
||||
></textarea>
|
||||
<div v-if="errors.grund.length" class="invalid-feedback">
|
||||
{{errors.grund.join(".")}}
|
||||
</div>
|
||||
>
|
||||
</form-input>
|
||||
</div>
|
||||
|
||||
<div class="col-12 text-end">
|
||||
@@ -251,7 +230,7 @@ export default {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</core-form>
|
||||
|
||||
<template v-slot:error="{errorMessage}">
|
||||
<div class="alert alert-danger m-0" role="alert">
|
||||
@@ -259,6 +238,5 @@ export default {
|
||||
</div>
|
||||
</template>
|
||||
</core-fetch-cmpt>
|
||||
</div>
|
||||
`
|
||||
</div>`
|
||||
}
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
import {CoreFetchCmpt} from '../../Fetch.js';
|
||||
import VueDatepicker from '../../vueDatepicker.js.php';
|
||||
import CoreForm from '../../Form/Form.js';
|
||||
import FormValidation from '../../Form/Validation.js';
|
||||
import FormInput from '../../Form/Input.js';
|
||||
|
||||
var _uuid = 0;
|
||||
|
||||
export default {
|
||||
components: {
|
||||
CoreFetchCmpt,
|
||||
VueDatepicker
|
||||
CoreForm,
|
||||
FormValidation,
|
||||
FormInput
|
||||
},
|
||||
emits: [
|
||||
'setInfos',
|
||||
@@ -20,12 +23,7 @@ export default {
|
||||
return {
|
||||
data: null,
|
||||
saving: false,
|
||||
errors: {
|
||||
grund: [],
|
||||
studiensemester: [],
|
||||
datum_wiedereinstieg: [],
|
||||
default: []
|
||||
},
|
||||
attachment: [],
|
||||
stsem: null,
|
||||
currentWiedereinstieg: '',
|
||||
siteUrl: FHC_JS_DATA_STORAGE_OBJECT.app_root +
|
||||
@@ -37,18 +35,14 @@ export default {
|
||||
switch (this.data.status)
|
||||
{
|
||||
case 'Erstellt': return 'info';
|
||||
case 'Genehmigt': return 'success';
|
||||
case 'Zurueckgezogen': return 'danger';
|
||||
default: return 'info';
|
||||
case 'Pause':
|
||||
case 'Zurueckgezogen':
|
||||
case 'Abgelehnt': return 'danger';
|
||||
case 'Genehmigt':
|
||||
case 'EmailVersandt': return 'success';
|
||||
default: return 'warning';
|
||||
}
|
||||
},
|
||||
loadUrl() {
|
||||
if (this.studierendenantragId)
|
||||
return '/components/Antrag/Unterbrechung/getDetailsForAntrag/'+
|
||||
this.studierendenantragId;
|
||||
return '/components/Antrag/Unterbrechung/getDetailsForNewAntrag/' +
|
||||
this.prestudentId;
|
||||
},
|
||||
datumWsFormatted() {
|
||||
let datumUnformatted = '';
|
||||
|
||||
@@ -62,26 +56,40 @@ export default {
|
||||
return datumUnformatted;
|
||||
let datum = new Date(datumUnformatted);
|
||||
return datum.toLocaleDateString();
|
||||
},
|
||||
semesterOffsets() {
|
||||
if (!this.data || !this.data.studiensemester)
|
||||
return [];
|
||||
return Object.values(this.data.studiensemester)
|
||||
.filter(el => !el.disabled)
|
||||
.map(el => el.studiensemester_kurzbz);
|
||||
},
|
||||
semester() {
|
||||
if (!this.stsem)
|
||||
return '';
|
||||
return this.data.semester + this.semesterOffsets.indexOf(this.stsem);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
load() {
|
||||
return axios.get(
|
||||
FHC_JS_DATA_STORAGE_OBJECT.app_root +
|
||||
FHC_JS_DATA_STORAGE_OBJECT.ci_router +
|
||||
this.loadUrl
|
||||
).then(
|
||||
result => {
|
||||
this.data = result.data.retval;
|
||||
if (this.data.status) {
|
||||
this.$emit("setStatus", {
|
||||
msg: Vue.computed(() => this.$p.t('studierendenantrag', 'status_x', {status: this.data.statustyp})),
|
||||
severity: this.statusSeverity
|
||||
});
|
||||
return this.$fhcApi.factory
|
||||
.studstatus.unterbrechung.getDetails(this.studierendenantragId, this.prestudentId)
|
||||
.then(
|
||||
result => {
|
||||
this.data = result.data;
|
||||
if (this.data.status) {
|
||||
const msg = (this.data.status == 'Pause' && this.data.status_insertvon == "Studienabbruch") ? Vue.computed(() => {
|
||||
let status = this.$p.t('studierendenantrag/status_stop');
|
||||
return this.$p.t('studierendenantrag', 'status_x', {status});
|
||||
}) : Vue.computed(() => this.$p.t('studierendenantrag', 'status_x', {status: this.data.statustyp}));
|
||||
this.$emit("setStatus", {
|
||||
msg,
|
||||
severity: this.statusSeverity
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
);
|
||||
);
|
||||
},
|
||||
createAntrag() {
|
||||
this.$emit('setStatus', {
|
||||
@@ -89,63 +97,41 @@ export default {
|
||||
severity: 'warning'
|
||||
});
|
||||
this.saving = true;
|
||||
for(var k in this.errors)
|
||||
this.errors[k] = [];
|
||||
|
||||
var formData = new FormData();
|
||||
var attachment = this.$refs.attachment;
|
||||
formData.append("attachment", attachment.files[0]);
|
||||
formData.append("studiensemester", this.stsem !== null && this.data.studiensemester[this.stsem].studiensemester_kurzbz);
|
||||
formData.append("prestudent_id", this.data.prestudent_id);
|
||||
formData.append("grund", this.$refs.grund.value);
|
||||
formData.append("datum_wiedereinstieg", this.stsem !== null && this.currentWiedereinstieg);
|
||||
this.$refs.form.clearValidation();
|
||||
this.$refs.form.factory
|
||||
.studstatus.unterbrechung.create(
|
||||
this.stsem !== null && this.data.studiensemester[this.stsem].studiensemester_kurzbz,
|
||||
this.data.prestudent_id,
|
||||
this.data.grund,
|
||||
this.stsem !== null && this.currentWiedereinstieg,
|
||||
this.attachment
|
||||
)
|
||||
.then(result => {
|
||||
if (Number.isInteger(result.data))
|
||||
document.location += "/" + result.data;
|
||||
|
||||
axios.post(
|
||||
FHC_JS_DATA_STORAGE_OBJECT.app_root +
|
||||
FHC_JS_DATA_STORAGE_OBJECT.ci_router +
|
||||
'/components/Antrag/Unterbrechung/createAntrag/',
|
||||
formData,
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data'
|
||||
}
|
||||
}
|
||||
).then(
|
||||
result => {
|
||||
if (result.data.error)
|
||||
{
|
||||
for (var k in result.data.retval)
|
||||
{
|
||||
if (this.errors[k] !== undefined)
|
||||
this.errors[k].push(result.data.retval[k]);
|
||||
else
|
||||
this.errors.default.push(result.data.retval[k]);
|
||||
}
|
||||
this.$emit('setStatus', {
|
||||
msg: Vue.computed(() => this.$p.t('studierendenantrag', 'status_x', {status: this.$p.t('studierendenantrag', 'status_error')})),
|
||||
severity: 'danger'
|
||||
this.data = result.data;
|
||||
if (this.data.status)
|
||||
this.$emit("setStatus", {
|
||||
msg: Vue.computed(() => this.$p.t('studierendenantrag', 'status_x', {status: this.data.statustyp})),
|
||||
severity: this.statusSeverity
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Number.isInteger(result.data.retval))
|
||||
document.location += "/" + result.data.retval;
|
||||
this.data = result.data.retval;
|
||||
if (this.data.status) {
|
||||
this.$emit("setStatus", {
|
||||
msg: Vue.computed(() => this.$p.t('studierendenantrag', 'status_x', {status: this.data.statustyp})),
|
||||
severity: this.statusSeverity
|
||||
});
|
||||
}
|
||||
else
|
||||
this.$emit('setStatus', {
|
||||
msg: Vue.computed(() => this.$p.t('studierendenantrag', 'status_x', {status: this.$p.t('studierendenantrag', 'status_created')})),
|
||||
severity: 'info'
|
||||
});
|
||||
}
|
||||
this.$emit('setStatus', {
|
||||
msg: Vue.computed(() => this.$p.t('studierendenantrag', 'status_x', {status: this.$p.t('studierendenantrag', 'status_created')})),
|
||||
severity: 'info'
|
||||
});
|
||||
this.saving = false;
|
||||
}
|
||||
);
|
||||
})
|
||||
.catch(error => {
|
||||
this.$emit('setStatus', {
|
||||
msg: Vue.computed(() => this.$p.t('studierendenantrag', 'status_x', {status: this.$p.t('studierendenantrag', 'status_error')})),
|
||||
severity: 'danger'
|
||||
});
|
||||
this.saving = false;
|
||||
this.$fhcAlert.handleSystemError(error);
|
||||
});
|
||||
},
|
||||
cancelAntrag() {
|
||||
this.$emit('setStatus', {
|
||||
@@ -153,63 +139,45 @@ export default {
|
||||
severity: 'warning'
|
||||
});
|
||||
this.saving = true;
|
||||
for(var k in this.errors)
|
||||
this.errors[k] = [];
|
||||
axios.post(
|
||||
FHC_JS_DATA_STORAGE_OBJECT.app_root +
|
||||
FHC_JS_DATA_STORAGE_OBJECT.ci_router +
|
||||
'/components/Antrag/Unterbrechung/cancelAntrag/', {
|
||||
antrag_id: this.data.studierendenantrag_id
|
||||
}
|
||||
).then(
|
||||
result => {
|
||||
if (result.data.error)
|
||||
{
|
||||
for (var k in result.data.retval)
|
||||
{
|
||||
if (this.errors[k] !== undefined)
|
||||
this.errors[k].push(result.data.retval[k]);
|
||||
else
|
||||
this.errors.default.push(result.data.retval[k]);
|
||||
}
|
||||
|
||||
this.$refs.form.clearValidation();
|
||||
this.$refs.form.factory
|
||||
.studstatus.unterbrechung.cancel(
|
||||
this.data.studierendenantrag_id
|
||||
)
|
||||
.then(result => {
|
||||
if (Number.isInteger(result.data))
|
||||
document.location = document.location.replace(/unterbrechung\/([0-9]*)\/[0-9]*[\/]?$/, 'unterbrechung/$1') + "/" + result.data;
|
||||
|
||||
this.data = result.data;
|
||||
if (this.data.status)
|
||||
this.$emit("setStatus", {
|
||||
msg: Vue.computed(() => this.$p.t('studierendenantrag', 'status_x', {status: this.data.statustyp})),
|
||||
severity: this.statusSeverity
|
||||
});
|
||||
else
|
||||
this.$emit('setStatus', {
|
||||
msg: Vue.computed(() => this.$p.t('studierendenantrag', 'status_x', {status: this.$p.t('studierendenantrag', 'status_error')})),
|
||||
msg: Vue.computed(() => this.$p.t('studierendenantrag', 'status_x', {status: this.$p.t('studierendenantrag', 'status_cancelled')})),
|
||||
severity: 'danger'
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Number.isInteger(result.data.retval)) {
|
||||
document.location = document.location.replace(/unterbrechung\/([0-9]*)\/[0-9]*[\/]?$/, 'unterbrechung/$1') + "/" + result.data.retval;
|
||||
}
|
||||
this.data = result.data.retval;
|
||||
if (this.data.status) {
|
||||
this.$emit("setStatus", {
|
||||
msg: Vue.computed(() => this.$p.t('studierendenantrag', 'status_x', {status: this.data.statustyp})),
|
||||
severity: this.statusSeverity
|
||||
});
|
||||
}
|
||||
else
|
||||
this.$emit('setStatus', {
|
||||
msg: Vue.computed(() => this.$p.t('studierendenantrag', 'status_x', {status: this.$p.t('studierendenantrag', 'status_cancelled')})),
|
||||
severity: 'danger'
|
||||
});
|
||||
}
|
||||
this.saving = false;
|
||||
}
|
||||
);
|
||||
})
|
||||
.catch(error => {
|
||||
this.$emit('setStatus', {
|
||||
msg: Vue.computed(() => this.$p.t('studierendenantrag', 'status_x', {status: this.$p.t('studierendenantrag', 'status_error')})),
|
||||
severity: 'danger'
|
||||
});
|
||||
this.saving = false;
|
||||
this.$fhcAlert.handleSystemError(error);
|
||||
});
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.uuid = _uuid++;
|
||||
},
|
||||
template: `
|
||||
<div class="studierendenantrag-form-unterbrechung">
|
||||
<core-fetch-cmpt :api-function="load">
|
||||
<div class="row">
|
||||
<core-form ref="form" class="row">
|
||||
<div class="col-12">
|
||||
<div v-for="error in errors.default" class="alert alert-danger" role="alert" v-html="error">
|
||||
</div>
|
||||
<form-validation></form-validation>
|
||||
<table class="table">
|
||||
<tr>
|
||||
<th>{{$p.t('lehre', 'studiengang')}}</th>
|
||||
@@ -235,99 +203,105 @@ export default {
|
||||
<tr>
|
||||
<th>{{$p.t('lehre', 'semester')}}</th>
|
||||
<td align="right" v-if="data.studierendenantrag_id">{{data.semester}}</td>
|
||||
<td align="right" v-else>{{stsem === null ? '' : data.studiensemester[stsem].semester}}</td>
|
||||
<td align="right" v-else>{{semester}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-6 mb-3">
|
||||
<label :for="'studierendenantrag-form-abmeldung-' + uuid + '-stsem'" class="form-label">
|
||||
{{$p.t('lehre', 'studiensemester')}}
|
||||
</label>
|
||||
<div v-if="data.studierendenantrag_id">
|
||||
{{data.studiensemester_kurzbz}}
|
||||
</div>
|
||||
<div v-else>
|
||||
<select
|
||||
class="form-select"
|
||||
:class="{'is-invalid': errors.studiensemester.length}"
|
||||
v-model="stsem"
|
||||
required
|
||||
:id="'studierendenantrag-form-abmeldung-' + uuid + '-stsem'"
|
||||
@input="currentWiedereinstieg = ''"
|
||||
>
|
||||
<option v-for="(stsem, index) in data.studiensemester" :key="index" :value="index">
|
||||
{{stsem.studiensemester_kurzbz}}
|
||||
</option>
|
||||
</select>
|
||||
<div v-if="errors.studiensemester.length" class="invalid-feedback">
|
||||
{{errors.studiensemester.join(".")}}
|
||||
<label class="form-label">
|
||||
{{$p.t('lehre', 'studiensemester')}}
|
||||
</label>
|
||||
<div>
|
||||
{{data.studiensemester_kurzbz}}
|
||||
</div>
|
||||
</div>
|
||||
<form-input
|
||||
v-else
|
||||
type="select"
|
||||
v-model="stsem"
|
||||
name="studiensemester"
|
||||
:label="$p.t('lehre', 'studiensemester')"
|
||||
required
|
||||
@input="currentWiedereinstieg = ''"
|
||||
>
|
||||
<option v-for="(stsem, index) in data.studiensemester" :key="index" :value="index" :disabled="stsem.disabled">
|
||||
{{stsem.studiensemester_kurzbz}}
|
||||
</option>
|
||||
</form-input>
|
||||
</div>
|
||||
<div class="col-sm-6 mb-3">
|
||||
<label class="form-label">
|
||||
{{$p.t('studierendenantrag', 'antrag_datum_wiedereinstieg')}}
|
||||
</label>
|
||||
|
||||
<div v-if="data.studierendenantrag_id">
|
||||
{{datumWsFormatted}}
|
||||
</div>
|
||||
<div v-else-if="stsem === null">
|
||||
<select class="form-select" disabled>
|
||||
<option selected>{{$p.t('ui/select_studiensemester')}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div v-else>
|
||||
<select v-model="currentWiedereinstieg" class="form-select">
|
||||
<option v-for="sem in data.studiensemester[stsem].wiedereinstieg" :key="sem.studiensemester_kurzbz" :value="sem.start">
|
||||
{{sem.studiensemester_kurzbz}}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div v-if="errors.datum_wiedereinstieg.length" class="invalid-feedback d-block">
|
||||
{{errors.datum_wiedereinstieg.join(".")}}
|
||||
<label class="form-label">
|
||||
{{$p.t('studierendenantrag', 'antrag_datum_wiedereinstieg')}}
|
||||
</label>
|
||||
<div>
|
||||
{{datumWsFormatted}}
|
||||
</div>
|
||||
</div>
|
||||
<form-input
|
||||
v-else-if="stsem === null"
|
||||
type="select"
|
||||
:label="$p.t('studierendenantrag', 'antrag_datum_wiedereinstieg')"
|
||||
modelValue=""
|
||||
name="datum_wiedereinstieg"
|
||||
disabled
|
||||
>
|
||||
<template #default>
|
||||
<option value="" selected disabled hidden>{{$p.t('ui/select_studiensemester')}}</option>
|
||||
</template>
|
||||
</form-input>
|
||||
<form-input
|
||||
v-else
|
||||
type="select"
|
||||
:label="$p.t('studierendenantrag', 'antrag_datum_wiedereinstieg')"
|
||||
v-model="currentWiedereinstieg"
|
||||
name="datum_wiedereinstieg"
|
||||
>
|
||||
<option v-for="sem in data.studiensemester[stsem].wiedereinstieg" :key="sem.studiensemester_kurzbz" :value="sem.start" :disabled="sem.disabled">
|
||||
{{sem.studiensemester_kurzbz}}
|
||||
</option>
|
||||
</form-input>
|
||||
</div>
|
||||
<div v-if="data.studierendenantrag_id" class="mb-3">
|
||||
<h5>{{$p.t('studierendenantrag', 'antrag_grund')}}:</h5>
|
||||
<textarea class="form-control" rows="5" readonly>{{data.grund}}</textarea>
|
||||
</div>
|
||||
<div v-else class="col-sm-6 mb-3">
|
||||
<label :for="'studierendenantrag-form-abmeldung-' + uuid + '-grund'" class="form-label">Grund:</label>
|
||||
<textarea
|
||||
class="form-control"
|
||||
:class="{'is-invalid': errors.grund.length}"
|
||||
:id="'studierendenantrag-form-abmeldung-' + uuid + '-grund'"
|
||||
<div class="col-sm-6 mb-3">
|
||||
<form-input
|
||||
v-if="data.studierendenantrag_id"
|
||||
type="textarea"
|
||||
:label="$p.t('studierendenantrag', 'antrag_grund') + ':'"
|
||||
v-model="data.grund"
|
||||
name="grund"
|
||||
rows="5"
|
||||
:disabled="saving"
|
||||
readonly
|
||||
>
|
||||
</form-input>
|
||||
<form-input
|
||||
v-else
|
||||
ref="grund"
|
||||
type="textarea"
|
||||
:label="$p.t('studierendenantrag', 'antrag_grund') + ':'"
|
||||
v-model="data.grund"
|
||||
name="grund"
|
||||
:disabled="saving"
|
||||
rows="5"
|
||||
required
|
||||
></textarea>
|
||||
<div v-if="errors.grund.length" class="invalid-feedback">
|
||||
{{errors.grund.join(".")}}
|
||||
</div>
|
||||
>
|
||||
</form-input>
|
||||
</div>
|
||||
<div class="col-12 mb-3">
|
||||
|
||||
<div v-if="data.studierendenantrag_id">
|
||||
<a v-if="data.dms_id" target="_blank" :href="siteUrl + '/lehre/Antrag/Attachment/Show/' + data.dms_id"> {{$p.t('studierendenantrag', 'antrag_dateianhaenge')}} </a>
|
||||
<span v-else>{{$p.t('studierendenantrag', 'no_attachments')}}</span>
|
||||
</div>
|
||||
<div v-else>
|
||||
<label
|
||||
:for="'studierendenantrag-form-abmeldung-' + uuid + '-attachment'"
|
||||
class="form-label">
|
||||
{{$p.t('studierendenantrag', 'antrag_dateianhaenge')}}
|
||||
</label>
|
||||
<input
|
||||
class="form-control"
|
||||
type="file"
|
||||
ref="attachment"
|
||||
:id="'studierendenantrag-form-abmeldung-' + uuid + '-attachment'"
|
||||
name="attachment">
|
||||
</div>
|
||||
<form-input
|
||||
v-else
|
||||
ref="attachment"
|
||||
type="uploadfile"
|
||||
:label="$p.t('studierendenantrag', 'antrag_dateianhaenge')"
|
||||
v-model="attachment"
|
||||
name="attachment"
|
||||
>
|
||||
</form-input>
|
||||
</div>
|
||||
<div class="col-12 text-end">
|
||||
<button
|
||||
@@ -349,13 +323,12 @@ export default {
|
||||
{{$p.t('studierendenantrag', 'btn_cancel')}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</core-form>
|
||||
<template v-slot:error="{errorMessage}">
|
||||
<div class="alert alert-danger m-0" role="alert">
|
||||
{{ errorMessage }}
|
||||
</div>
|
||||
</template>
|
||||
</core-fetch-cmpt>
|
||||
</div>
|
||||
`
|
||||
</div>`
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import {CoreFetchCmpt} from '../../Fetch.js';
|
||||
import VueDatepicker from '../../vueDatepicker.js.php';
|
||||
import CoreForm from '../../Form/Form.js';
|
||||
import FormValidation from '../../Form/Validation.js';
|
||||
|
||||
var _uuid = 0;
|
||||
|
||||
export default {
|
||||
components: {
|
||||
CoreFetchCmpt,
|
||||
VueDatepicker
|
||||
CoreForm,
|
||||
FormValidation
|
||||
},
|
||||
emits: [
|
||||
'setInfos',
|
||||
@@ -22,12 +23,6 @@ export default {
|
||||
return {
|
||||
data: null,
|
||||
saving: false,
|
||||
errors: {
|
||||
grund: [],
|
||||
default: []
|
||||
},
|
||||
siteUrl: FHC_JS_DATA_STORAGE_OBJECT.app_root +
|
||||
FHC_JS_DATA_STORAGE_OBJECT.ci_router,
|
||||
infos: []
|
||||
}
|
||||
},
|
||||
@@ -35,17 +30,16 @@ export default {
|
||||
statusSeverity() {
|
||||
switch (this.data.status)
|
||||
{
|
||||
case 'Erstellt': return 'info';
|
||||
case 'Offen':
|
||||
case 'Erstellt':
|
||||
case 'ErsteAufforderungVersandt': return 'info';
|
||||
case 'Genehmigt': return 'success';
|
||||
case 'Pause':
|
||||
case 'Verzichtet':
|
||||
case 'Abgemeldet': return 'danger';
|
||||
default: return 'info';
|
||||
default: return 'warning';
|
||||
}
|
||||
},
|
||||
loadUrl() {
|
||||
return '/components/Antrag/Wiederholung/getDetailsForNewAntrag/' +
|
||||
this.prestudentId;
|
||||
},
|
||||
datumPruefungFormatted() {
|
||||
if(!this.data.pruefungsdatum)
|
||||
return '';
|
||||
@@ -55,25 +49,27 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
load() {
|
||||
return axios.get(
|
||||
FHC_JS_DATA_STORAGE_OBJECT.app_root +
|
||||
FHC_JS_DATA_STORAGE_OBJECT.ci_router +
|
||||
this.loadUrl
|
||||
).then(
|
||||
result => {
|
||||
this.data = result.data.retval;
|
||||
return this.$fhcApi.factory
|
||||
.studstatus.wiederholung.getDetails(
|
||||
this.prestudentId
|
||||
)
|
||||
.then(result => {
|
||||
this.data = result.data;
|
||||
if (!this.data.status || this.data.status == 'ErsteAufforderungVersandt' || this.data.status == 'ZweiteAufforderungVersandt') {
|
||||
this.data.status = 'Offen';
|
||||
this.data.statustyp = this.$p.t('studierendenantrag', 'status_open');
|
||||
}
|
||||
this.$emit('update:status', this.data.status);
|
||||
const msg = (this.data.status == 'Pause' && this.data.status_insertvon == "Studienabbruch") ? Vue.computed(() => {
|
||||
let status = this.$p.t('studierendenantrag/status_stop');
|
||||
return this.$p.t('studierendenantrag', 'status_x', {status});
|
||||
}) : Vue.computed(() => this.$p.t('studierendenantrag', 'status_x', {status: this.data.statustyp}));
|
||||
this.$emit("setStatus", {
|
||||
msg: Vue.computed(() => this.$p.t('studierendenantrag', 'status_x', {status: this.data.statustyp})),
|
||||
msg,
|
||||
severity: this.statusSeverity
|
||||
});
|
||||
return result;
|
||||
}
|
||||
);
|
||||
});
|
||||
},
|
||||
createAntrag() {
|
||||
this.createAntragWithStatus(true);
|
||||
@@ -82,7 +78,7 @@ export default {
|
||||
this.createAntragWithStatus(false);
|
||||
},
|
||||
createAntragWithStatus(repeat) {
|
||||
let func = repeat ? 'createAntrag' : 'cancelAntrag';
|
||||
let func = repeat ? 'create' : 'cancel';
|
||||
let nextState = repeat ? 'Erstellt' : 'Verzichtet';
|
||||
|
||||
this.$emit('setStatus', {
|
||||
@@ -90,54 +86,36 @@ export default {
|
||||
severity: 'warning'
|
||||
});
|
||||
this.saving = true;
|
||||
for(var k in this.errors)
|
||||
this.errors[k] = [];
|
||||
|
||||
axios.post(
|
||||
FHC_JS_DATA_STORAGE_OBJECT.app_root +
|
||||
FHC_JS_DATA_STORAGE_OBJECT.ci_router +
|
||||
'/components/Antrag/Wiederholung/' + func + '/',
|
||||
{
|
||||
prestudent_id: this.data.prestudent_id,
|
||||
studiensemester: this.data.studiensemester_kurzbz
|
||||
}
|
||||
).then(
|
||||
result => {
|
||||
if (result.data.error)
|
||||
{
|
||||
for (var k in result.data.retval)
|
||||
{
|
||||
if (this.errors[k] !== undefined)
|
||||
this.errors[k].push(result.data.retval[k]);
|
||||
else
|
||||
this.errors.default.push(result.data.retval[k]);
|
||||
}
|
||||
this.$emit('setStatus', {
|
||||
msg: Vue.computed(() => this.$p.t('studierendenantrag', 'status_x', {status: this.$p.t('studierendenantrag', 'status_error')})),
|
||||
severity: 'danger'
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
if (result.data.retval === true)
|
||||
document.location += "";
|
||||
this.data = result.data.retval;
|
||||
if (!this.data.status)
|
||||
this.data.status = nextState;
|
||||
this.$emit('update:status', this.data.status);
|
||||
this.$emit("setStatus", {
|
||||
msg: Vue.computed(() => this.$p.t('studierendenantrag', 'status_x', {status: this.data.statustyp})),
|
||||
severity: this.statusSeverity
|
||||
});
|
||||
}
|
||||
this.$refs.form.factory
|
||||
.studstatus.wiederholung[func](
|
||||
this.data.prestudent_id,
|
||||
this.data.studiensemester_kurzbz
|
||||
)
|
||||
.then(result => {
|
||||
if (result.data === true)
|
||||
document.location += "";
|
||||
|
||||
this.data = result.data;
|
||||
if (!this.data.status)
|
||||
this.data.status = nextState;
|
||||
this.$emit('update:status', this.data.status);
|
||||
this.$emit("setStatus", {
|
||||
msg: Vue.computed(() => this.$p.t('studierendenantrag', 'status_x', {status: this.data.statustyp})),
|
||||
severity: this.statusSeverity
|
||||
});
|
||||
this.saving = false;
|
||||
}
|
||||
);
|
||||
})
|
||||
.catch(error => {
|
||||
this.$emit('setStatus', {
|
||||
msg: Vue.computed(() => this.$p.t('studierendenantrag', 'status_x', {status: this.$p.t('studierendenantrag', 'status_error')})),
|
||||
severity: 'danger'
|
||||
});
|
||||
this.saving = false;
|
||||
this.$fhcAlert.handleSystemError(error);
|
||||
});
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.uuid = _uuid++;
|
||||
},
|
||||
mounted() {
|
||||
this.infos = [...Array(5).keys()].map(n => ({
|
||||
body: Vue.computed(() => this.$p.t('studierendenantrag', 'infotext_Wiederholung_' + n))
|
||||
@@ -147,10 +125,9 @@ export default {
|
||||
template: `
|
||||
<div class="studierendenantrag-form-wiederholung">
|
||||
<core-fetch-cmpt :api-function="load">
|
||||
<div class="row">
|
||||
<core-form ref="form" class="row">
|
||||
<div class="col-12">
|
||||
<div v-for="error in errors.default" class="alert alert-danger" role="alert" v-html="error">
|
||||
</div>
|
||||
<form-validation></form-validation>
|
||||
<table class="table">
|
||||
<tr>
|
||||
<th>{{$p.t('lehre', 'studiengang')}}</th>
|
||||
@@ -199,7 +176,7 @@ export default {
|
||||
{{$p.t('studierendenantrag/antrag_Wiederholung_button_no')}}
|
||||
</button>-->
|
||||
</div>
|
||||
</div>
|
||||
</core-form>
|
||||
<template v-slot:error="{errorMessage}">
|
||||
<div class="alert alert-danger m-0" role="alert">
|
||||
{{ errorMessage }}
|
||||
|
||||
@@ -39,15 +39,10 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
loadFilter() {
|
||||
axios.get(
|
||||
FHC_JS_DATA_STORAGE_OBJECT.app_root +
|
||||
FHC_JS_DATA_STORAGE_OBJECT.ci_router +
|
||||
'/components/Antrag/Leitung/getActiveStgs'
|
||||
).then(result => {
|
||||
this.stgs = result.data.retval;
|
||||
}).catch(error => {
|
||||
console.error(error);
|
||||
});
|
||||
this.$fhcApi.factory
|
||||
.studstatus.leitung.getStgs()
|
||||
.then(result => this.stgs = result.data)
|
||||
.catch(this.$fhcAlert.handleSystemError);
|
||||
},
|
||||
changeFilter(filter) {
|
||||
this.filter = filter || undefined;
|
||||
@@ -103,21 +98,9 @@ export default {
|
||||
}
|
||||
} else {
|
||||
this.$refs.loader.show();
|
||||
axios
|
||||
.all(
|
||||
oks.map(
|
||||
antrag => axios.post(
|
||||
FHC_JS_DATA_STORAGE_OBJECT.app_root +
|
||||
FHC_JS_DATA_STORAGE_OBJECT.ci_router +
|
||||
'/components/Antrag/Leitung/approve' + antrag.typ,
|
||||
{
|
||||
studierendenantrag_id: antrag.studierendenantrag_id
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
.then(this.showValidation)
|
||||
.catch(this.showError);
|
||||
this.$fhcApi.factory
|
||||
.studstatus.leitung.approve(oks)
|
||||
.then(this.showResults);
|
||||
}
|
||||
},
|
||||
actionReject(evt, gruende) {
|
||||
@@ -147,61 +130,38 @@ export default {
|
||||
.catch(() => {});
|
||||
} else {
|
||||
this.$refs.loader.show();
|
||||
axios
|
||||
.all(
|
||||
gruende.map(
|
||||
antrag => axios.post(
|
||||
FHC_JS_DATA_STORAGE_OBJECT.app_root +
|
||||
FHC_JS_DATA_STORAGE_OBJECT.ci_router +
|
||||
'/components/Antrag/Leitung/reject' + antrag.typ,
|
||||
{
|
||||
studierendenantrag_id: antrag.studierendenantrag_id,
|
||||
grund: antrag.grund
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
.then(this.showValidation)
|
||||
.catch(this.showError);
|
||||
this.$fhcApi.factory
|
||||
.studstatus.leitung.reject(gruende)
|
||||
.then(this.showResults);
|
||||
}
|
||||
},
|
||||
actionReopen(evt) {
|
||||
var antraege = evt || this.selectedData;
|
||||
this.$refs.loader.show();
|
||||
axios
|
||||
.all(
|
||||
antraege.map(
|
||||
antrag => axios.post(
|
||||
FHC_JS_DATA_STORAGE_OBJECT.app_root +
|
||||
FHC_JS_DATA_STORAGE_OBJECT.ci_router +
|
||||
'/components/Antrag/Leitung/reopenAntrag/',
|
||||
{
|
||||
studierendenantrag_id: antrag.studierendenantrag_id
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
.then(this.showValidation)
|
||||
.catch(this.showError);
|
||||
this.$fhcApi.factory
|
||||
.studstatus.leitung.reopen(gruende)
|
||||
.then(this.showResults);
|
||||
},
|
||||
actionPause(evt) {
|
||||
var antraege = evt || this.selectedData;
|
||||
this.$refs.loader.show();
|
||||
this.$fhcApi.factory
|
||||
.studstatus.leitung.pause(antraege)
|
||||
.then(this.showResults);
|
||||
},
|
||||
actionUnpause(evt) {
|
||||
var antraege = evt || this.selectedData;
|
||||
this.$refs.loader.show();
|
||||
this.$fhcApi.factory
|
||||
.studstatus.leitung.unpause(antraege)
|
||||
.then(this.showResults);
|
||||
},
|
||||
actionObject(evt) {
|
||||
var antraege = evt || this.selectedData;
|
||||
this.$refs.loader.show();
|
||||
axios
|
||||
.all(
|
||||
antraege.map(
|
||||
antrag => axios.post(
|
||||
FHC_JS_DATA_STORAGE_OBJECT.app_root +
|
||||
FHC_JS_DATA_STORAGE_OBJECT.ci_router +
|
||||
'/components/Antrag/Leitung/objectAntrag/',
|
||||
{
|
||||
studierendenantrag_id: antrag.studierendenantrag_id
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
.then(this.showValidation)
|
||||
.catch(this.showError);
|
||||
this.$fhcApi.factory
|
||||
.studstatus.leitung.object(antraege)
|
||||
.then(this.showResults);
|
||||
},
|
||||
actionoObjectionDeny(evt, gruende) {
|
||||
var antraege = evt || this.selectedData;
|
||||
@@ -229,84 +189,31 @@ export default {
|
||||
.catch(() => {});
|
||||
} else {
|
||||
this.$refs.loader.show();
|
||||
axios
|
||||
.all(
|
||||
gruende.map(
|
||||
antrag => axios.post(
|
||||
FHC_JS_DATA_STORAGE_OBJECT.app_root +
|
||||
FHC_JS_DATA_STORAGE_OBJECT.ci_router +
|
||||
'/components/Antrag/Leitung/objectionDeny/',
|
||||
{
|
||||
studierendenantrag_id: antrag.studierendenantrag_id,
|
||||
grund: antrag.grund
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
.then(this.showValidation)
|
||||
.catch(this.showError);
|
||||
this.$fhcApi.factory
|
||||
.studstatus.leitung.denyObjection(gruende)
|
||||
.then(this.showResults);
|
||||
}
|
||||
},
|
||||
actionObjectionApprove(evt, gruende) {
|
||||
var antraege = evt || this.selectedData;
|
||||
this.$refs.loader.show();
|
||||
axios
|
||||
.all(
|
||||
antraege.map(
|
||||
antrag => axios.post(
|
||||
FHC_JS_DATA_STORAGE_OBJECT.app_root +
|
||||
FHC_JS_DATA_STORAGE_OBJECT.ci_router +
|
||||
'/components/Antrag/Leitung/objectionApprove/',
|
||||
{
|
||||
studierendenantrag_id: antrag.studierendenantrag_id
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
.then(this.showValidation)
|
||||
.catch(this.showError);
|
||||
this.$fhcApi.factory
|
||||
.studstatus.leitung.approveObjection(antraege)
|
||||
.then(this.showResults);
|
||||
},
|
||||
actionCancel(evt) {
|
||||
var antraege = evt || this.selectedData;
|
||||
this.$refs.loader.show();
|
||||
axios
|
||||
.all(
|
||||
antraege.map(
|
||||
antrag => axios.post(
|
||||
FHC_JS_DATA_STORAGE_OBJECT.app_root +
|
||||
FHC_JS_DATA_STORAGE_OBJECT.ci_router +
|
||||
'/components/Antrag/Abmeldung/cancelAntrag/',
|
||||
{
|
||||
antrag_id: antrag.studierendenantrag_id
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
.then(this.showValidation)
|
||||
.catch(this.showError);
|
||||
this.$fhcApi.factory
|
||||
.studstatus.abmeldung.cancel(antraege)
|
||||
.then(this.showResults);
|
||||
},
|
||||
showValidation(results) {
|
||||
var errors = results.filter(res => res.data.error);
|
||||
showResults(results) {
|
||||
let fulfilled = results.filter(res => res.status == 'fulfilled');
|
||||
this.$refs.loader.hide();
|
||||
if (errors.length) {
|
||||
let errorMsg = errors.map(
|
||||
error =>
|
||||
'Antrag ' +
|
||||
JSON.parse(error.config.data).studierendenantrag_id +
|
||||
'\n' +
|
||||
Object.values(error.data.retval).join('\n')
|
||||
).join('\n');
|
||||
|
||||
BsAlert.popup(errorMsg, {dialogClass: 'alert alert-danger'});
|
||||
}
|
||||
this.reload();
|
||||
},
|
||||
showError(error) {
|
||||
this.$refs.loader.hide();
|
||||
let msg = error.response.data;
|
||||
if (msg.replace(/^\s+/, '').substr(0, 9) == '<!DOCTYPE' || msg.replace(/^\s+/, '').substr(0, 4).toLowerCase() == '<div')
|
||||
msg = error.message;
|
||||
BsAlert.popup(msg, {dialogClass: 'alert alert-danger'});
|
||||
//fulfilled.forEach(a => this.$fhcAlert.alertDefault('success', '#' + a.value.data, 'Approved, ...'));
|
||||
if (fulfilled.length)
|
||||
this.reload();
|
||||
}
|
||||
},
|
||||
created() {
|
||||
@@ -347,6 +254,8 @@ export default {
|
||||
@action:objectionDeny="actionoObjectionDeny"
|
||||
@action:objectionApprove="actionObjectionApprove"
|
||||
@action:cancel="actionCancel"
|
||||
@action:pause="actionPause"
|
||||
@action:unpause="actionUnpause"
|
||||
@reload="reload"
|
||||
>
|
||||
</leitung-table>
|
||||
|
||||
@@ -35,28 +35,32 @@ export default {
|
||||
});
|
||||
},
|
||||
loadData(evt) {
|
||||
if (this.abortController)
|
||||
this.abortController.abort();
|
||||
if( evt.query.length < 2 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.abortController instanceof AbortController
|
||||
&& this.abortController.signal.aborted === false)
|
||||
{
|
||||
this.abortController.abort();
|
||||
}
|
||||
this.abortController = new AbortController();
|
||||
|
||||
axios.post(
|
||||
FHC_JS_DATA_STORAGE_OBJECT.app_root +
|
||||
FHC_JS_DATA_STORAGE_OBJECT.ci_router +
|
||||
'/components/Antrag/Abmeldung/getStudiengaengeAssistenz/',
|
||||
evt,
|
||||
{
|
||||
signal: this.abortController.signal
|
||||
}
|
||||
).then(
|
||||
result => {
|
||||
if (result.data.error) {
|
||||
BsAlert.popup(result.data.retval, {dialogClass: 'alert alert-danger'});
|
||||
} else {
|
||||
this.data = result.data.retval;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
).catch(() => {});
|
||||
this.$fhcApi.factory
|
||||
.studstatus.leitung.getPrestudents(evt.query, this.abortController.signal)
|
||||
.then(result => {
|
||||
this.data = result.data;
|
||||
this.abortController = null;
|
||||
})
|
||||
.catch(error => {
|
||||
if (this.abortController instanceof AbortController
|
||||
&& this.abortController.signal.aborted === false)
|
||||
{
|
||||
this.abortController.abort();
|
||||
}
|
||||
this.$fhcAlert.handleSystemError(error);
|
||||
});
|
||||
}
|
||||
},
|
||||
template: `
|
||||
@@ -79,15 +83,20 @@ export default {
|
||||
class="w-100"
|
||||
v-model="student"
|
||||
:suggestions="data"
|
||||
optionLabel = "name"
|
||||
option-label = "name"
|
||||
@complete="loadData"
|
||||
inputId="newAntragModalAutoComplete"
|
||||
input-id="newAntragModalAutoComplete"
|
||||
dropdown
|
||||
dropdown-mode="current"
|
||||
>
|
||||
<template #option="slotProps">
|
||||
<div :title="slotProps.option.prestudent_id">
|
||||
{{slotProps.option.name}}
|
||||
{{slotProps.option.name}}
|
||||
</div>
|
||||
</template>
|
||||
<template #empty>
|
||||
<div class="text-muted px-3 py-2">
|
||||
{{ $p.t('ui/keineEintraegeGefunden') }}
|
||||
</div>
|
||||
</template>
|
||||
</auto-complete>
|
||||
|
||||
@@ -36,21 +36,17 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
setlvs(param) {
|
||||
if(param.error) {
|
||||
this.$refs.fetchCompt.error = true;
|
||||
this.$refs.fetchCompt.errorMessage = param.retval;
|
||||
} else {
|
||||
this.repeat_last = !!param.retval.repeat_last;
|
||||
if (this.repeat_last) {
|
||||
delete param.retval.repeat_last;
|
||||
}
|
||||
this.lvs = param.retval;
|
||||
this.repeat_last = !!param.repeat_last;
|
||||
if (this.repeat_last) {
|
||||
delete param.repeat_last;
|
||||
}
|
||||
this.lvs = param;
|
||||
},
|
||||
loadlvs() {
|
||||
if (!this.antragId)
|
||||
return new Promise(() => {});
|
||||
return axios.get(FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + '/components/Antrag/Wiederholung/getLvs/' + this.antragId);
|
||||
return this.$fhcApi.factory
|
||||
.studstatus.wiederholung.getLvs(this.antragId);
|
||||
},
|
||||
submit(result) {
|
||||
this.result = [result, this.check];
|
||||
|
||||
@@ -25,13 +25,12 @@ export default {
|
||||
'action:object',
|
||||
'action:objectionDeny',
|
||||
'action:objectionApprove',
|
||||
'action:cancel'
|
||||
'action:cancel',
|
||||
'action:pause',
|
||||
'action:unpause'
|
||||
],
|
||||
data() {
|
||||
return {
|
||||
ajaxUrl: FHC_JS_DATA_STORAGE_OBJECT.app_root +
|
||||
FHC_JS_DATA_STORAGE_OBJECT.ci_router +
|
||||
'/components/Antrag/Leitung/getAntraege/',
|
||||
table: null,
|
||||
lastHistoryClickedId: null,
|
||||
historyData: [],
|
||||
@@ -40,7 +39,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
reload(stg) {
|
||||
this.table.setData(this.ajaxUrl + (stg || ''));
|
||||
this.table.setData('/' + (stg || ''));
|
||||
},
|
||||
download() {
|
||||
this.table.download("csv", "data.csv", {
|
||||
@@ -51,14 +50,35 @@ export default {
|
||||
getHistory() {
|
||||
if (this.lastHistoryClickedId === null)
|
||||
return null;
|
||||
return axios.get(
|
||||
FHC_JS_DATA_STORAGE_OBJECT.app_root +
|
||||
FHC_JS_DATA_STORAGE_OBJECT.ci_router +
|
||||
'/components/Antrag/Leitung/getHistory/' +
|
||||
this.lastHistoryClickedId
|
||||
).then(res => {
|
||||
this.historyData = res.data.retval.sort((a, b) => a.insertamum > b.insertamum);
|
||||
});
|
||||
return this.$fhcApi.factory
|
||||
.studstatus.leitung.getHistory(this.lastHistoryClickedId)
|
||||
.then(res => {
|
||||
this.historyData = res.data.sort((a, b) => a.insertamum > b.insertamum);
|
||||
})
|
||||
.catch(this.$fhcApi.handleSystemError);
|
||||
},
|
||||
getHistoryStatus(data, index) {
|
||||
if (data.insertvon == 'Studienabbruch')
|
||||
return this.$p.t('studierendenantrag/status_stop');
|
||||
if (index > 0 && this.historyData[index-1].studierendenantrag_statustyp_kurzbz == 'Pause') {
|
||||
if (index > 1 && this.historyData[index-2].studierendenantrag_statustyp_kurzbz != 'Pause') {
|
||||
// NOTE(chris): this is a AbmeldungStgl Pause right after a manual Pause
|
||||
if (data.studierendenantrag_statustyp_kurzbz == 'Pause')
|
||||
return data.typ;
|
||||
// NOTE(chris): this is a manual Pause resumed
|
||||
else
|
||||
return data.typ + ' (' + this.$p.t('studierendenantrag/status_unpaused') + ')';
|
||||
}
|
||||
// NOTE(chris): a series of pause stati always starts with a manual and alternate afterwards
|
||||
let i = 2;
|
||||
while (index-i > 0 && this.historyData[index-i].studierendenantrag_statustyp_kurzbz == 'Pause') i++;
|
||||
if (data.studierendenantrag_statustyp_kurzbz == 'Pause')
|
||||
i++;
|
||||
return i%2
|
||||
? data.typ
|
||||
: data.typ + ' (' + this.$p.t('studierendenantrag/status_unpaused') + ')';
|
||||
}
|
||||
return data.typ;
|
||||
},
|
||||
showHistoryGrund(grund) {
|
||||
this.$refs.modalGrund.$el.addEventListener(
|
||||
@@ -89,9 +109,10 @@ export default {
|
||||
this.table = new Tabulator(this.$refs.table, {
|
||||
placeholder:"Keine zu bearbeitenden Datensätze",
|
||||
movableColumns: true,
|
||||
maxHeight: '50vh',
|
||||
height: '65vh',
|
||||
layout: "fitDataFill",
|
||||
ajaxURL: this.ajaxUrl + (this.filter || ''),
|
||||
ajaxURL: '/' + (this.filter || ''),
|
||||
ajaxRequestFunc: this.$fhcApi.factory.studstatus.leitung.getAntraege,
|
||||
persistence: { // NOTE(chris): do not store column titles
|
||||
sort: true, //persist column sorting
|
||||
filter: true, //persist filters
|
||||
@@ -153,9 +174,13 @@ export default {
|
||||
autocomplete: true,
|
||||
},
|
||||
formatter: (cell, formatterParams, onRendered) => {
|
||||
let data = cell.getData();
|
||||
let status = cell.getValue();
|
||||
if (data.status_insertvon == 'Studienabbruch' && data.status == 'Pause')
|
||||
status = this.$p.t('studierendenantrag/status_stop');
|
||||
let link = document.createElement('a');
|
||||
link.href = "#";
|
||||
link.innerHTML = cell.getValue();
|
||||
link.innerHTML = status;
|
||||
link.addEventListener('click', e => {
|
||||
e.preventDefault();
|
||||
this.lastHistoryClickedId = cell.getData().studierendenantrag_id;
|
||||
@@ -176,7 +201,7 @@ export default {
|
||||
}, {
|
||||
field: 'name',
|
||||
title: this.$p.t('global', 'name'),
|
||||
mutator: (value, data) => (data.vorname + ' ' + data.nachname).replace(/^\s*(.*)\s*$/, '$1'),
|
||||
mutator: (value, data) => (data.nachname + ' ' + data.vorname).replace(/^\s*(.*)\s*$/, '$1'),
|
||||
headerFilter: 'input'
|
||||
}, {
|
||||
field: 'datum',
|
||||
@@ -234,7 +259,22 @@ export default {
|
||||
|
||||
container.className = "d-flex gap-2";
|
||||
|
||||
if ((data.typ == 'Abmeldung' || data.typ == 'AbmeldungStgl' || data.typ == 'Unterbrechung') && (data.status == 'Genehmigt' || data.status == 'Beeinsprucht' || data.status == 'EinspruchAbgelehnt' || data.status == 'EmailVersandt')) {
|
||||
let allowed_status_for_download = [];
|
||||
switch (data.typ) {
|
||||
case 'Abmeldung':
|
||||
allowed_status_for_download = ['Genehmigt'];
|
||||
break;
|
||||
case 'AbmeldungStgl':
|
||||
allowed_status_for_download = ['Genehmigt', 'Beeinsprucht', 'EinspruchAbgelehnt', 'Abgemeldet'];
|
||||
break;
|
||||
case 'Unterbrechung':
|
||||
allowed_status_for_download = ['Genehmigt', 'EmailVersandt'];
|
||||
break;
|
||||
case 'Wiederholung':
|
||||
allowed_status_for_download = ['Abgemeldet'];
|
||||
break;
|
||||
}
|
||||
if (allowed_status_for_download.includes(data.status)) {
|
||||
// NOTE(chris): Download PDF
|
||||
let button = document.createElement('a');
|
||||
// NOTE(chris): phrasen in attribues don't work if they are not preloaded
|
||||
@@ -246,6 +286,56 @@ export default {
|
||||
'content/pdfExport.php?xml=Antrag' + data.typ + '.xml.php&xsl=Antrag' + data.typ + '&id=' + data.studierendenantrag_id + '&output=pdf';
|
||||
container.append(button);
|
||||
}
|
||||
|
||||
if (data.typ == 'Wiederholung' && (data.status == 'ErsteAufforderungVersandt' || data.status == 'ZweiteAufforderungVersandt')) {
|
||||
// NOTE(chris): Pause
|
||||
let button = document.createElement('button');
|
||||
let icon = document.createElement('i');
|
||||
let span = document.createElement('span');
|
||||
|
||||
icon.className = "fa-solid fa-pause";
|
||||
icon.setAttribute('aria-hidden', true);
|
||||
icon.setAttribute('title', this.$p.t('studierendenantrag', 'btn_pause'));
|
||||
|
||||
span.className = "fa-sr-only";
|
||||
span.append(this.$p.t('studierendenantrag', 'btn_pause'));
|
||||
|
||||
button.append(icon);
|
||||
button.append(span);
|
||||
button.className = "btn btn-outline-secondary";
|
||||
button.addEventListener('click', () => this.$emit('action:pause', [cell.getData()]));
|
||||
container.append(button);
|
||||
}
|
||||
|
||||
let canUnpause = data.status == 'Pause' && !['AbmeldungStgl', 'Studienabbruch'].includes(data.status_insertvon);
|
||||
if (!canUnpause && data.status == 'Pause' && data.status_insertvon == 'AbmeldungStgl') {
|
||||
canUnpause = cell.getTable().getData().filter(row =>
|
||||
row.prestudent_id == data.prestudent_id
|
||||
&& row.typ == 'AbmeldungStgl'
|
||||
&& row.status == 'Zurueckgezogen'
|
||||
&& row.status_insertamum == data.status_insertamum
|
||||
).length;
|
||||
}
|
||||
if (canUnpause) {
|
||||
// NOTE(chris): Unpause
|
||||
let button = document.createElement('button');
|
||||
let icon = document.createElement('i');
|
||||
let span = document.createElement('span');
|
||||
|
||||
icon.className = "fa-solid fa-play";
|
||||
icon.setAttribute('aria-hidden', true);
|
||||
icon.setAttribute('title', this.$p.t('studierendenantrag', 'btn_unpause'));
|
||||
|
||||
span.className = "fa-sr-only";
|
||||
span.append(this.$p.t('studierendenantrag', 'btn_unpause'));
|
||||
|
||||
button.append(icon);
|
||||
button.append(span);
|
||||
button.className = "btn btn-outline-secondary";
|
||||
button.addEventListener('click', () => this.$emit('action:unpause', [cell.getData()]));
|
||||
container.append(button);
|
||||
}
|
||||
|
||||
if (data.typ == 'AbmeldungStgl' && data.status == 'Genehmigt') {
|
||||
// NOTE(chris): Object
|
||||
let button = document.createElement('button');
|
||||
@@ -377,10 +467,10 @@ export default {
|
||||
<template #title>{{$p.t('studierendenantrag', 'title_history', {id: lastHistoryClickedId})}}</template>
|
||||
<core-fetch-cmpt ref="historyLoader" :api-function="getHistory">
|
||||
<table v-if="historyData.length" class="table">
|
||||
<tr v-for="status in historyData" :key="status.studierendenantrag_status_id">
|
||||
<tr v-for="(status, index) in historyData" :key="status.studierendenantrag_status_id">
|
||||
<td>{{(new Date(status.insertamum)).toLocaleString()}}</td>
|
||||
<td>{{status.insertvon}}</td>
|
||||
<td>{{status.typ}}</td>
|
||||
<td>{{getHistoryStatus(status, index)}}</td>
|
||||
<td>
|
||||
<a v-if="status.grund" href="#modal-grund" data-bs-toggle="modal" @click="showHistoryGrund(status.grund)">
|
||||
{{$p.t('studierendenantrag', 'antrag_grund')}}
|
||||
|
||||
@@ -56,39 +56,19 @@ export default {
|
||||
anmerkung: lv.antrag_anmerkung || "",
|
||||
studiensemester_kurzbz: this.lvs2sem
|
||||
}));
|
||||
axios.post(FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + '/components/Antrag/Wiederholung/saveLvs/', {forbiddenLvs, mandatoryLvs})
|
||||
this.$fhcApi.factory
|
||||
.studstatus.wiederholung.saveLvs(forbiddenLvs, mandatoryLvs)
|
||||
.then(response => {
|
||||
if(!response.data.error) {
|
||||
this.addAlert('Speichern erfolgreich', 'alert-success');
|
||||
this.statusCode = response.data.retval[0].studierendenantrag_statustyp_kurzbz;
|
||||
this.statusMsg = response.data.retval[0].typ;
|
||||
} else {
|
||||
this.addAlert(response.data.retval.message || response.data.retval, 'alert-danger');
|
||||
this.statusCode = 0;
|
||||
this.statusMsg = 'Error';
|
||||
}
|
||||
this.$fhcAlert.alertSuccess('Speichern erfolgreich');
|
||||
this.statusCode = response.data[0].studierendenantrag_statustyp_kurzbz;
|
||||
this.statusMsg = response.data[0].typ;
|
||||
this.isloading = false;
|
||||
}).catch(error => {
|
||||
this.addAlert(error.message, 'alert-danger');
|
||||
})
|
||||
.catch(error => {
|
||||
this.statusCode = 0;
|
||||
this.statusMsg = 'Error';
|
||||
this.isloading = false;
|
||||
}).finally(() => {
|
||||
window.scrollTo(0, 0);
|
||||
});
|
||||
},
|
||||
addAlert(text, type) {
|
||||
const para = document.createElement("p");
|
||||
para.innerText = text;
|
||||
para.className = "alert " + type + " alert-dismissible fade show";
|
||||
const btn = document.createElement("button");
|
||||
btn.className = "btn-close";
|
||||
btn.type = "button";
|
||||
btn.setAttribute("aria-label", "Close");
|
||||
btn.setAttribute("data-bs-dismiss", "alert");
|
||||
para.appendChild(btn);
|
||||
|
||||
this.$refs.alertbox.appendChild(para);
|
||||
}
|
||||
},
|
||||
created() {
|
||||
@@ -96,149 +76,141 @@ export default {
|
||||
this.statusMsg = this.initialStatusMsg;
|
||||
},
|
||||
mounted() {
|
||||
axios.get(FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + '/components/Antrag/Wiederholung/getLvs/' + this.antragId).then(
|
||||
result => {
|
||||
if(result.data.error)
|
||||
{
|
||||
this.addAlert(result.data.retval, 'alert-danger');
|
||||
this.isloading = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
let res = {};
|
||||
this.$p
|
||||
.loadCategory(['ui', 'lehre', 'studierendenantrag', 'global'])
|
||||
.then(() => {
|
||||
for (var k in result.data.retval) {
|
||||
if (k === 'repeat_last')
|
||||
continue;
|
||||
if (result.data.retval[k] === null) {
|
||||
const alert = document.createElement('div');
|
||||
alert.innerHTML = this.$p.t('studierendenantrag', 'error_stg_last_semester');
|
||||
alert.className = 'alert alert-warning';
|
||||
alert.role = 'alert';
|
||||
this.$refs["lvtable" + k.substr(0,1)].append(alert);
|
||||
continue;
|
||||
this.$p
|
||||
.loadCategory(['ui', 'lehre', 'studierendenantrag', 'global'])
|
||||
.then(() => this.antragId)
|
||||
.then(this.$fhcApi.factory.studstatus.wiederholung.getLvs)
|
||||
.then(result => {
|
||||
let res = {};
|
||||
for (var k in result.data) {
|
||||
if (k === 'repeat_last')
|
||||
continue;
|
||||
if (result.data[k] === null) {
|
||||
const alert = document.createElement('div');
|
||||
alert.innerHTML = this.$p.t('studierendenantrag', 'error_stg_last_semester');
|
||||
alert.className = 'alert alert-warning';
|
||||
alert.role = 'alert';
|
||||
this.$refs["lvtable" + k.substr(0,1)].append(alert);
|
||||
continue;
|
||||
}
|
||||
let lvs = result.data[k].reduce((obj,lv) => {
|
||||
obj[lv.studienplan_lehrveranstaltung_id] = lv;
|
||||
return obj;
|
||||
}, {});
|
||||
for (var lv of Object.values(lvs)) {
|
||||
if (!lv.studienplan_lehrveranstaltung_id_parent)
|
||||
continue;
|
||||
if (!lvs[lv.studienplan_lehrveranstaltung_id_parent])
|
||||
console.error('parent not available');
|
||||
else {
|
||||
if (!lvs[lv.studienplan_lehrveranstaltung_id_parent]._children)
|
||||
lvs[lv.studienplan_lehrveranstaltung_id_parent]._children = [];
|
||||
lvs[lv.studienplan_lehrveranstaltung_id_parent]._children.push(lv);
|
||||
}
|
||||
}
|
||||
res[k] = Object.values(lvs).filter(lv => !lv.studienplan_lehrveranstaltung_id_parent);
|
||||
let current = res[k];
|
||||
let index = k.substr(0,1);
|
||||
|
||||
const options = {
|
||||
data: current,
|
||||
dataTree: true,
|
||||
dataTreeStartExpanded: true, //start with an expanded tree
|
||||
dataTreeChildIndent: 15,
|
||||
layout: "fitDataStretch",
|
||||
columns: [
|
||||
{title: this.$p.t('ui', 'bezeichnung'), field: "bezeichnung"},
|
||||
{title: this.$p.t('lehre','lehrform'), field: "lehrform_kurzbz"},
|
||||
{title: "ECTS", field: "ects"},
|
||||
{title: this.$p.t('lehre','note'), field: "note", formatter:(cell, formatterParams, onRendered) => cell.getValue() || "---"},
|
||||
{
|
||||
title: index == 1 && !result.data.repeat_last ? this.$p.t('studierendenantrag','lv_nicht_zulassen') : this.$p.t('studierendenantrag','lv_wiederholen'),
|
||||
field: "antrag_zugelassen",
|
||||
formatter: (cell, formatterParams, onRendered) => {
|
||||
let data = cell.getData();
|
||||
if (data._children || !data.zeugnis)
|
||||
return "";
|
||||
let input = document.createElement('input');
|
||||
input.className = "form-check-input";
|
||||
input.type = "checkbox";
|
||||
input.role = "switch";
|
||||
input.checked = cell.getValue();
|
||||
input.addEventListener('input', () => {
|
||||
lvs[data.studienplan_lehrveranstaltung_id].antrag_zugelassen = input.checked;
|
||||
cell.getRow().reformat();
|
||||
});
|
||||
if (this.disabled) {
|
||||
input.disabled = true;
|
||||
}
|
||||
|
||||
let div = document.createElement('div');
|
||||
div.className = 'form-check form-switch';
|
||||
div.append(input);
|
||||
|
||||
return div;
|
||||
}
|
||||
let lvs = result.data.retval[k].reduce((obj,lv) => {
|
||||
obj[lv.studienplan_lehrveranstaltung_id] = lv;
|
||||
return obj;
|
||||
}, {});
|
||||
for (var lv of Object.values(lvs)) {
|
||||
if (!lv.studienplan_lehrveranstaltung_id_parent)
|
||||
continue;
|
||||
if (!lvs[lv.studienplan_lehrveranstaltung_id_parent])
|
||||
console.error('parent not available');
|
||||
else {
|
||||
if (!lvs[lv.studienplan_lehrveranstaltung_id_parent]._children)
|
||||
lvs[lv.studienplan_lehrveranstaltung_id_parent]._children = [];
|
||||
lvs[lv.studienplan_lehrveranstaltung_id_parent]._children.push(lv);
|
||||
},
|
||||
{
|
||||
title: this.$p.t('global','anmerkung'),
|
||||
field: "antrag_anmerkung",
|
||||
headerSort:false,
|
||||
titleFormatter:(cell, formatterParams, onRendered)=>{
|
||||
let link = document.createElement('a');
|
||||
link.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
link.href ="#";
|
||||
link.title = this.$p.t('studierendenantrag','anmerkung_tooltip');
|
||||
new bootstrap.Tooltip(link);
|
||||
let tooltip = document.createElement('span');
|
||||
tooltip.innerHTML = this.$p.t('global','anmerkung') + " ";
|
||||
tooltip.append(link);
|
||||
|
||||
let icon = document.createElement('i');
|
||||
link.append(icon);
|
||||
icon.className = "fa fa-info-circle";
|
||||
icon.setAttribute("aria-hidden", "true");
|
||||
icon.style.minWidth = '1em';
|
||||
|
||||
return tooltip;
|
||||
|
||||
},
|
||||
formatter: (cell, formatterParams, onRendered) => {
|
||||
if (this.disabled) {
|
||||
return cell.getValue() || "";
|
||||
}
|
||||
var data = cell.getData();
|
||||
if (lvs[data.studienplan_lehrveranstaltung_id].antrag_zugelassen)
|
||||
{
|
||||
let input = document.createElement('input');
|
||||
input.className = "form-control";
|
||||
input.type = "text";
|
||||
input.value = cell.getValue() || "";
|
||||
input.addEventListener('input', () => {
|
||||
lvs[data.studienplan_lehrveranstaltung_id].antrag_anmerkung = input.value;
|
||||
});
|
||||
return input;
|
||||
}
|
||||
else
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
res[k] = Object.values(lvs).filter(lv => !lv.studienplan_lehrveranstaltung_id_parent);
|
||||
let current = res[k];
|
||||
let index = k.substr(0,1);
|
||||
|
||||
const options = {
|
||||
data: current,
|
||||
dataTree: true,
|
||||
dataTreeStartExpanded: true, //start with an expanded tree
|
||||
dataTreeChildIndent: 15,
|
||||
layout: "fitDataStretch",
|
||||
columns: [
|
||||
{title: this.$p.t('ui', 'bezeichnung'), field: "bezeichnung"},
|
||||
{title: this.$p.t('lehre','lehrform'), field: "lehrform_kurzbz"},
|
||||
{title: "ECTS", field: "ects"},
|
||||
{title: this.$p.t('lehre','note'), field: "note", formatter:(cell, formatterParams, onRendered)=>cell.getValue() || "---"},
|
||||
{
|
||||
title: index == 1 && !result.data.retval.repeat_last ? this.$p.t('studierendenantrag','lv_nicht_zulassen') : this.$p.t('studierendenantrag','lv_wiederholen'),
|
||||
field: "antrag_zugelassen",
|
||||
formatter: (cell, formatterParams, onRendered) => {
|
||||
let data = cell.getData();
|
||||
if(data._children || !data.zeugnis)
|
||||
return "";
|
||||
let input = document.createElement('input');
|
||||
input.className = "form-check-input";
|
||||
input.type = "checkbox";
|
||||
input.role = "switch";
|
||||
input.checked = cell.getValue();
|
||||
input.addEventListener('input', () => {
|
||||
lvs[data.studienplan_lehrveranstaltung_id].antrag_zugelassen = input.checked;
|
||||
cell.getRow().reformat();
|
||||
});
|
||||
if (this.disabled) {
|
||||
input.disabled = true;
|
||||
}
|
||||
|
||||
let div = document.createElement('div');
|
||||
div.className = 'form-check form-switch';
|
||||
div.append(input);
|
||||
|
||||
return div;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: this.$p.t('global','anmerkung'),
|
||||
field: "antrag_anmerkung",
|
||||
headerSort:false,
|
||||
titleFormatter:(cell, formatterParams, onRendered)=>{
|
||||
let link = document.createElement('a');
|
||||
link.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
link.href ="#";
|
||||
link.title = this.$p.t('studierendenantrag','anmerkung_tooltip');
|
||||
new bootstrap.Tooltip(link);
|
||||
let tooltip = document.createElement('span');
|
||||
tooltip.innerHTML = this.$p.t('global','anmerkung') + " ";
|
||||
tooltip.append(link);
|
||||
|
||||
let icon = document.createElement('i');
|
||||
link.append(icon);
|
||||
icon.className = "fa fa-info-circle";
|
||||
icon.setAttribute("aria-hidden", "true");
|
||||
icon.style.minWidth = '1em';
|
||||
|
||||
return tooltip;
|
||||
|
||||
},
|
||||
formatter: (cell, formatterParams, onRendered) => {
|
||||
if (this.disabled) {
|
||||
return cell.getValue() || "";
|
||||
}
|
||||
var data = cell.getData();
|
||||
if (lvs[data.studienplan_lehrveranstaltung_id].antrag_zugelassen)
|
||||
{
|
||||
let input = document.createElement('input');
|
||||
input.className = "form-control";
|
||||
input.type = "text";
|
||||
input.value = cell.getValue() || "";
|
||||
input.addEventListener('input', () => {
|
||||
lvs[data.studienplan_lehrveranstaltung_id].antrag_anmerkung = input.value;
|
||||
});
|
||||
return input;
|
||||
}
|
||||
else
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
var table = new Tabulator(this.$refs["lvtable" + k.substr(0,1)], options);
|
||||
}
|
||||
this.lvs = result.data.retval;
|
||||
});
|
||||
]
|
||||
};
|
||||
var table = new Tabulator(this.$refs["lvtable" + k.substr(0,1)], options);
|
||||
}
|
||||
}
|
||||
);
|
||||
this.lvs = result.data;
|
||||
})
|
||||
.catch(error => {
|
||||
this.$fhcAlert.handleSystemError(error);
|
||||
this.isloading = true;
|
||||
});
|
||||
},
|
||||
template: `
|
||||
<div class="col-sm-10">
|
||||
<div ref="alertbox"></div>
|
||||
|
||||
<span class="d-flex justify-content-between h4">
|
||||
<span>{{lvs.repeat_last ? $p.t('studierendenantrag', 'title_lv_wiederholen') : $p.t('studierendenantrag', 'title_lv_nicht_zugelassen')}}</span>
|
||||
<span>{{lvs1sem}}</span>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import {CoreRESTClient} from '../RESTClient.js';
|
||||
import accessibility from "../directives/accessibility.js";
|
||||
|
||||
export default {
|
||||
@@ -6,12 +5,19 @@ export default {
|
||||
accessibility
|
||||
},
|
||||
emits: [
|
||||
'update:modelValue'
|
||||
'update:modelValue',
|
||||
'change',
|
||||
'changed'
|
||||
],
|
||||
props: {
|
||||
configUrl: String,
|
||||
config: {
|
||||
type: [String, Array, Object, Promise],
|
||||
required: true
|
||||
},
|
||||
default: String,
|
||||
modelValue: [String, Number, Boolean, Array, Object, Date, Function, Symbol]
|
||||
modelValue: [String, Number, Boolean, Array, Object, Date, Function, Symbol],
|
||||
vertical: Boolean,
|
||||
border: Boolean
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -35,51 +41,82 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
CoreRESTClient
|
||||
.get(this.configUrl)
|
||||
.then(result => CoreRESTClient.getData(result.data))
|
||||
.then(result => {
|
||||
const tabs = {};
|
||||
// TODO(chris): check if result is array
|
||||
Object.entries(result).forEach(([key, config]) => {
|
||||
if (!config.component)
|
||||
return console.error('Component missing for ' + key);
|
||||
watch: {
|
||||
config(n) {
|
||||
this.initConfig(n);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
change(key) {
|
||||
this.$emit("change", key)
|
||||
this.current = key;
|
||||
this.$nextTick(() => this.$emit("changed", key));
|
||||
},
|
||||
initConfig(config) {
|
||||
if (!config)
|
||||
return;
|
||||
if (config instanceof Promise)
|
||||
return config
|
||||
.then(result => result.data)
|
||||
.then(this.initConfig)
|
||||
.catch(this.$fhcAlert.handleSystemError);
|
||||
if (typeof config === 'string' || config instanceof String)
|
||||
return this.$fhcApi
|
||||
.get(config)
|
||||
.then(result => result.data)
|
||||
.then(this.initConfig)
|
||||
.catch(this.$fhcAlert.handleSystemError);
|
||||
|
||||
tabs[key] = {
|
||||
component: Vue.markRaw(Vue.defineAsyncComponent(() => import(config.component))),
|
||||
title: config.title || key,
|
||||
config: config.config,
|
||||
key
|
||||
}
|
||||
});
|
||||
const tabs = {};
|
||||
|
||||
function _addToTabs(key, item) {
|
||||
if (!item.component)
|
||||
return console.error('Component missing for ' + key);
|
||||
|
||||
tabs[key] = {
|
||||
component: Vue.markRaw(Vue.defineAsyncComponent(() => import(item.component))),
|
||||
title: item.title || key,
|
||||
config: item.config,
|
||||
key
|
||||
}
|
||||
}
|
||||
|
||||
if (Array.isArray(config))
|
||||
config.forEach((item, key) => _addToTabs(key, item));
|
||||
else
|
||||
Object.entries(config).forEach(([key, item]) => _addToTabs(key, item));
|
||||
|
||||
if (this.current === null || !tabs[this.current]) {
|
||||
if (tabs[this.default])
|
||||
this.current = this.default;
|
||||
else
|
||||
this.current = Object.keys(tabs)[0];
|
||||
this.tabs = tabs;
|
||||
})
|
||||
.catch(this.$fhcAlert.handleSystemError);
|
||||
}
|
||||
this.tabs = tabs;
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.initConfig(this.config);
|
||||
},
|
||||
template: `
|
||||
<div class="fhc-tabs d-flex flex-column">
|
||||
<div class="nav nav-tabs">
|
||||
<div class="fhc-tabs d-flex" :class="vertical ? 'align-items-stretch gap-3' : (border ? 'flex-column' : 'flex-column gap-3')" v-if="Object.keys(tabs).length">
|
||||
<div class="nav" :class="vertical ? 'nav-pills flex-column' : 'nav-tabs'">
|
||||
<div
|
||||
v-for="tab in tabs"
|
||||
:key="tab.key"
|
||||
class="nav-item nav-link"
|
||||
:class="{active: tab.key == current}"
|
||||
@click="current=tab.key"
|
||||
@click="change(tab.key)"
|
||||
:aria-current="tab.key == current ? 'page' : ''"
|
||||
v-accessibility:tab
|
||||
v-accessibility:tab.[vertical]
|
||||
>
|
||||
{{tab.title}}
|
||||
</div>
|
||||
</div>
|
||||
<div style="flex: 1 1 0%; height: 0%" class="border-bottom border-start border-end overflow-auto p-3">
|
||||
<div :style="vertical ? '' : 'flex: 1 1 0%; height: 0%'" class="overflow-auto flex-grow-1" :class="vertical || !border ? '' : 'p-3 border-bottom border-start border-end'">
|
||||
<keep-alive>
|
||||
<component :is="currentTab.component" v-model="value" :config="currentTab.config"></component>
|
||||
<component ref="current" :is="currentTab.component" v-model="value" :config="currentTab.config"></component>
|
||||
</keep-alive>
|
||||
</div>
|
||||
</div>`
|
||||
};
|
||||
};
|
||||
|
||||
@@ -21,7 +21,7 @@ import {CoreRESTClient} from '../../RESTClient.js';
|
||||
const CORE_FILTER_CMPT_TIMEOUT = 7000;
|
||||
|
||||
/**
|
||||
*
|
||||
* TODO(chris): deprecated
|
||||
*/
|
||||
export const CoreFilterAPIs = {
|
||||
/**
|
||||
|
||||
@@ -15,8 +15,6 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {CoreFilterAPIs} from './API.js';
|
||||
import {CoreRESTClient} from '../../RESTClient.js';
|
||||
import {CoreFetchCmpt} from '../../components/Fetch.js';
|
||||
import FilterConfig from './Filter/Config.js';
|
||||
import FilterColumns from './Filter/Columns.js';
|
||||
@@ -137,9 +135,9 @@ export const CoreFilterCmpt = {
|
||||
for (let col of columns)
|
||||
{
|
||||
// If the column has to be displayed or not
|
||||
col.visible = selectedFields.indexOf(col.field) >= 0;
|
||||
if (col.formatter == 'rowSelection')
|
||||
col.visible = true;
|
||||
/* fields.indexOf(col.field) == -1; ensures displaying formatter colums
|
||||
e.g. column with rowSelection checkboxes or with custom formatted action buttons */
|
||||
col.visible = selectedFields.indexOf(col.field) >= 0 || fields.indexOf(col.field) == -1;
|
||||
|
||||
if (col.hasOwnProperty('resizable'))
|
||||
col.resizable = col.visible;
|
||||
@@ -186,13 +184,23 @@ export const CoreFilterCmpt = {
|
||||
else
|
||||
this.getFilter();
|
||||
},
|
||||
initTabulator() {
|
||||
async initTabulator() {
|
||||
let placeholder = '< Phrasen Plugin not loaded! >';
|
||||
if (this.$p) {
|
||||
await this.$p.loadCategory('ui');
|
||||
placeholder = this.$p.t('ui/keineDatenVorhanden');
|
||||
}
|
||||
// Define a default tabulator options in case it was not provided
|
||||
let tabulatorOptions = {...{
|
||||
height: 500,
|
||||
layout: "fitColumns",
|
||||
height: 500,
|
||||
layout: "fitDataStretch",
|
||||
movableColumns: true,
|
||||
reactiveData: true
|
||||
columnDefaults:{
|
||||
tooltip: true,
|
||||
},
|
||||
placeholder,
|
||||
reactiveData: true,
|
||||
persistence: true
|
||||
}, ...(this.tabulatorOptions || {})};
|
||||
|
||||
if (!this.tableOnly) {
|
||||
@@ -246,12 +254,12 @@ export const CoreFilterCmpt = {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
getFilter: function() {
|
||||
getFilter() {
|
||||
if (this.selectedFilter === null)
|
||||
this.startFetchCmpt(CoreFilterAPIs.getFilter, null, this.render);
|
||||
this.startFetchCmpt(this.$fhcApi.factory.filter.getFilter, null, this.render);
|
||||
else
|
||||
this.startFetchCmpt(
|
||||
CoreFilterAPIs.getFilterById,
|
||||
this.$fhcApi.factory.filter.getFilterById,
|
||||
{
|
||||
filterId: this.selectedFilter
|
||||
},
|
||||
@@ -261,54 +269,47 @@ export const CoreFilterCmpt = {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
render: function(response) {
|
||||
render(response) {
|
||||
let data = response;
|
||||
this.filterName = data.filterName;
|
||||
this.dataset = data.dataset;
|
||||
this.datasetMetadata = data.datasetMetadata;
|
||||
|
||||
if (CoreRESTClient.hasData(response))
|
||||
this.fields = data.fields;
|
||||
this.selectedFields = data.selectedFields;
|
||||
this.notSelectedFields = this.fields.filter(x => this.selectedFields.indexOf(x) === -1);
|
||||
this.filterFields = [];
|
||||
|
||||
for (let i = 0; i < data.datasetMetadata.length; i++)
|
||||
{
|
||||
let data = CoreRESTClient.getData(response);
|
||||
this.filterName = data.filterName;
|
||||
this.dataset = data.dataset;
|
||||
this.datasetMetadata = data.datasetMetadata;
|
||||
this.fields = data.fields;
|
||||
this.selectedFields = data.selectedFields;
|
||||
this.notSelectedFields = this.fields.filter(x => this.selectedFields.indexOf(x) === -1);
|
||||
this.filterFields = [];
|
||||
|
||||
for (let i = 0; i < data.datasetMetadata.length; i++)
|
||||
for (let j = 0; j < data.filters.length; j++)
|
||||
{
|
||||
for (let j = 0; j < data.filters.length; j++)
|
||||
if (data.datasetMetadata[i].name == data.filters[j].name)
|
||||
{
|
||||
if (data.datasetMetadata[i].name == data.filters[j].name)
|
||||
{
|
||||
let filter = data.filters[j];
|
||||
filter.type = data.datasetMetadata[i].type;
|
||||
let filter = data.filters[j];
|
||||
filter.type = data.datasetMetadata[i].type;
|
||||
|
||||
this.filterFields.push(filter);
|
||||
//break;
|
||||
}
|
||||
this.filterFields.push(filter);
|
||||
//break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the side menu is active
|
||||
if (this.sideMenu === true)
|
||||
{
|
||||
this.setSideMenu(data);
|
||||
}
|
||||
else // otherwise use the dropdown in the filter options
|
||||
{
|
||||
this.setDropDownMenu(data);
|
||||
}
|
||||
this.updateTabulator();
|
||||
}
|
||||
else
|
||||
// If the side menu is active
|
||||
if (this.sideMenu === true)
|
||||
{
|
||||
console.error(CoreRESTClient.getError(response));
|
||||
this.setSideMenu(data);
|
||||
}
|
||||
else // otherwise use the dropdown in the filter options
|
||||
{
|
||||
this.setDropDownMenu(data);
|
||||
}
|
||||
this.updateTabulator();
|
||||
},
|
||||
/**
|
||||
* Set the menu
|
||||
*/
|
||||
setSideMenu: function(data) {
|
||||
setSideMenu(data) {
|
||||
let filters = data.sideMenu.filters;
|
||||
let personalFilters = data.sideMenu.personalFilters;
|
||||
let filtersArray = [];
|
||||
@@ -362,7 +363,7 @@ export const CoreFilterCmpt = {
|
||||
/**
|
||||
* Set the drop down menu
|
||||
*/
|
||||
setDropDownMenu: function(data) {
|
||||
setDropDownMenu(data) {
|
||||
let filters = data.sideMenu.filters;
|
||||
let personalFilters = data.sideMenu.personalFilters;
|
||||
let filtersArray = [];
|
||||
@@ -398,7 +399,7 @@ export const CoreFilterCmpt = {
|
||||
/**
|
||||
* Used to start/refresh the FetchCmpt
|
||||
*/
|
||||
startFetchCmpt: function(apiFunction, apiFunctionParameters, dataFetchedCallback) {
|
||||
startFetchCmpt(apiFunction, apiFunctionParameters, dataFetchedCallback) {
|
||||
// Assign the function api of the FetchCmpt binded property
|
||||
this.fetchCmptApiFunction = apiFunction;
|
||||
|
||||
@@ -424,11 +425,11 @@ export const CoreFilterCmpt = {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
handlerSaveCustomFilter: function(customFilterName) {
|
||||
handlerSaveCustomFilter(customFilterName) {
|
||||
this.selectedFilter = null;
|
||||
//
|
||||
this.startFetchCmpt(
|
||||
CoreFilterAPIs.saveCustomFilter,
|
||||
this.$fhcApi.factory.filter.saveCustomFilter,
|
||||
{
|
||||
customFilterName
|
||||
},
|
||||
@@ -438,13 +439,13 @@ export const CoreFilterCmpt = {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
handlerRemoveCustomFilter: function(event) {
|
||||
filterId = event.currentTarget.getAttribute("href").substring(1);
|
||||
handlerRemoveCustomFilter(event) {
|
||||
let filterId = event.currentTarget.getAttribute("href").substring(1);
|
||||
if (filterId === this.selectedFilter)
|
||||
this.selectedFilter = null;
|
||||
//
|
||||
this.startFetchCmpt(
|
||||
CoreFilterAPIs.removeCustomFilter,
|
||||
this.$fhcApi.factory.filter.removeCustomFilter,
|
||||
{
|
||||
filterId: filterId
|
||||
},
|
||||
@@ -481,7 +482,7 @@ export const CoreFilterCmpt = {
|
||||
applyFilterConfig(filterFields) {
|
||||
this.selectedFilter = null;
|
||||
this.startFetchCmpt(
|
||||
CoreFilterAPIs.applyFilterFields,
|
||||
this.$fhcApi.factory.filter.applyFilterFields,
|
||||
{
|
||||
filterFields
|
||||
},
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Copyright (C) 2022 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 {
|
||||
props: {
|
||||
title: '',
|
||||
subtitle: '',
|
||||
mainCols: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
asideCols: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
mainGridCols() {
|
||||
return this.mainCols.length > 0 ? `col-md-${this.mainCols[0]}` : "col-md-12";
|
||||
},
|
||||
asideGridCols() {
|
||||
return this.asideCols.length > 0 ? `col-md-${this.asideCols[0]}` : "";
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<div class="overflow-hidden">
|
||||
<header v-if="title">
|
||||
<h1 class="h2 mb-5">{{ title }}<span class="fhc-subtitle">{{ subtitle }}</span></h1>
|
||||
</header>
|
||||
<div class="row gx-5">
|
||||
<main :class="mainGridCols">
|
||||
<slot name="main">{{ mainGridCols }}</slot>
|
||||
</main>
|
||||
<aside v-if="asideCols.length > 0" :class="asideGridCols">
|
||||
<slot name="aside">{{ asideGridCols }}</slot>
|
||||
</aside>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
};
|
||||
@@ -21,7 +21,7 @@ import {CoreRESTClient} from '../../RESTClient.js';
|
||||
const CORE_NAVIGATION_CMPT_TIMEOUT = 5000;
|
||||
|
||||
/**
|
||||
*
|
||||
* TODO(chris): deprecated
|
||||
*/
|
||||
export const CoreNavigationAPIs = {
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (C) 2022 fhcomplete.org
|
||||
* 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
|
||||
@@ -15,8 +15,6 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {CoreNavigationAPIs} from './API.js';
|
||||
import {CoreRESTClient} from '../../RESTClient.js';
|
||||
import {CoreFetchCmpt} from '../../components/Fetch.js';
|
||||
|
||||
/**
|
||||
@@ -30,12 +28,12 @@ export const CoreNavigationCmpt = {
|
||||
addHeaderMenuEntries: Object, // property used to add new header menu entries from another app/component
|
||||
addSideMenuEntries: Object, // property used to add new side menu entries from another app/component
|
||||
hideTopMenu: Boolean,
|
||||
leftNavCssClasses: {
|
||||
type: String,
|
||||
default: 'navbar navbar-left-side'
|
||||
}
|
||||
leftNavCssClasses: {
|
||||
type: String,
|
||||
default: 'navbar navbar-left-side'
|
||||
}
|
||||
},
|
||||
data: function() {
|
||||
data() {
|
||||
return {
|
||||
headerMenu: {}, // header menu entries
|
||||
sideMenu: {} // side menu entries
|
||||
@@ -45,61 +43,63 @@ export const CoreNavigationCmpt = {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
headerMenuEntries: function() {
|
||||
headerMenuEntries() {
|
||||
//
|
||||
let hm = this.headerMenu ? {...this.headerMenu} : {};
|
||||
if (this.headerMenu != null && this.addHeaderMenuEntries != null && Object.keys(this.addHeaderMenuEntries).length > 0)
|
||||
{
|
||||
this.headerMenu[this.addHeaderMenuEntries.description] = this.addHeaderMenuEntries;
|
||||
hm[this.addHeaderMenuEntries.description] = this.addHeaderMenuEntries;
|
||||
}
|
||||
return this.headerMenu;
|
||||
return hm;
|
||||
},
|
||||
/**
|
||||
*
|
||||
*/
|
||||
sideMenuEntries: function() {
|
||||
sideMenuEntries() {
|
||||
//
|
||||
let sm = this.sideMenu ? {...this.sideMenu} : {};
|
||||
if (this.sideMenu != null && this.addSideMenuEntries != null && Object.keys(this.addSideMenuEntries).length > 0)
|
||||
{
|
||||
this.sideMenu[this.addSideMenuEntries.description] = this.addSideMenuEntries;
|
||||
sm[this.addSideMenuEntries.description] = this.addSideMenuEntries;
|
||||
}
|
||||
return this.sideMenu;
|
||||
return sm;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
getNavigationPage: function() {
|
||||
getNavigationPage() {
|
||||
return FHC_JS_DATA_STORAGE_OBJECT.called_path + "/" + FHC_JS_DATA_STORAGE_OBJECT.called_method;
|
||||
},
|
||||
/**
|
||||
*
|
||||
*/
|
||||
fetchCmptApiFunctionHeader: function() {
|
||||
return CoreNavigationAPIs.getHeader(this.getNavigationPage());
|
||||
fetchCmptApiFunctionHeader() {
|
||||
return this.$fhcApi.factory.navigation.getHeader(this.getNavigationPage());
|
||||
},
|
||||
/**
|
||||
*
|
||||
*/
|
||||
fetchCmptApiFunctionSideMenu: function() {
|
||||
return CoreNavigationAPIs.getMenu(this.getNavigationPage());
|
||||
fetchCmptApiFunctionSideMenu() {
|
||||
return this.$fhcApi.factory.navigation.getMenu(this.getNavigationPage());
|
||||
},
|
||||
/**
|
||||
*
|
||||
*/
|
||||
fetchCmptDataFetchedHeader: function(data) {
|
||||
if (CoreRESTClient.hasData(data)) this.headerMenu = CoreRESTClient.getData(data);
|
||||
fetchCmptDataFetchedHeader(data) {
|
||||
this.headerMenu = data || {};
|
||||
},
|
||||
/**
|
||||
*
|
||||
*/
|
||||
fetchCmptDataFetchedMenu: function(data) {
|
||||
if (CoreRESTClient.hasData(data)) this.sideMenu = CoreRESTClient.getData(data);
|
||||
fetchCmptDataFetchedMenu(data) {
|
||||
this.sideMenu = data || {};
|
||||
},
|
||||
/**
|
||||
*
|
||||
*/
|
||||
getDataBsToggle: function(header) {
|
||||
getDataBsToggle(header) {
|
||||
return !header.children ? null : 'dropdown';
|
||||
}
|
||||
},
|
||||
|
||||
@@ -105,7 +105,11 @@ export default {
|
||||
this.showsearchresult();
|
||||
this.searchfunction(this.searchsettings)
|
||||
.then(function(response) {
|
||||
that.searchresult = response.data.data;
|
||||
if( response.data?.error === 1 ) {
|
||||
that.error = 'Bei der Suche ist ein Fehler aufgetreten.';
|
||||
} else {
|
||||
that.searchresult = response.data.data;
|
||||
}
|
||||
})
|
||||
.catch(function(error) {
|
||||
that.error = 'Bei der Suche ist ein Fehler aufgetreten.'
|
||||
|
||||
@@ -133,8 +133,8 @@ const helperApp = Vue.createApp({
|
||||
helperAppContainer.parentElement.removeChild(helperAppContainer);
|
||||
},
|
||||
template: `
|
||||
<pv-toast ref="toast" base-z-index="99999"></pv-toast>
|
||||
<pv-toast ref="alert" base-z-index="99999" position="center">
|
||||
<pv-toast ref="toast" class="fhc-alert" :base-z-index="99999"></pv-toast>
|
||||
<pv-toast ref="alert" class="fhc-alert" :base-z-index="99999" position="center">
|
||||
<template #message="slotProps">
|
||||
<i class="fa fa-circle-exclamation fa-2xl mt-3"></i>
|
||||
<div class="p-toast-message-text">
|
||||
@@ -161,7 +161,7 @@ const helperApp = Vue.createApp({
|
||||
</a>
|
||||
</div>
|
||||
<div ref="messageCard" :id="'fhcAlertCollapseMessageCard' + slotProps.message.id" class="collapse mt-3">
|
||||
<div class="card card-body text-body small" style="white-space: pre-wrap">
|
||||
<div class="card card-body text-body small">
|
||||
{{slotProps.message.detail}}
|
||||
</div>
|
||||
</div>
|
||||
@@ -237,7 +237,7 @@ export default {
|
||||
alertMultiple(messageArray, severity = 'info', title = 'Info', sticky = false){
|
||||
// Check, if array has only string values
|
||||
if (messageArray.every(message => typeof message === 'string')) {
|
||||
messageArray.every(message => this.alertDefault(severity, title, message, sticky));
|
||||
messageArray.forEach(message => this.alertDefault(severity, title, message, sticky));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -250,6 +250,10 @@ export default {
|
||||
// Error is array of strings
|
||||
if (Array.isArray(error) && error.every(err => typeof err === 'string'))
|
||||
return error.every($fhcAlert.alertSystemError);
|
||||
|
||||
// Error has been handled already
|
||||
if (error.hasOwnProperty('handled') && error.handled)
|
||||
return;
|
||||
|
||||
// Error is object
|
||||
if (typeof error === 'object' && error !== null) {
|
||||
@@ -281,21 +285,21 @@ export default {
|
||||
handleSystemMessage(message) {
|
||||
// Message is string
|
||||
if (typeof message === 'string')
|
||||
return fhcerror.alertWarning(message);
|
||||
return $fhcAlert.alertWarning(message);
|
||||
|
||||
// Message is array of strings
|
||||
if (Array.isArray(message)) {
|
||||
// If Array has only Strings
|
||||
if (message.every(msg => typeof msg === 'string'))
|
||||
return message.every(fhcerror.alertWarning);
|
||||
return message.every($fhcAlert.alertWarning);
|
||||
|
||||
// If Array has only Objects
|
||||
if (message.every(msg => typeof msg === 'object') && msg !== null) {
|
||||
return message.every(msg => {
|
||||
if (msg.hasOwnProperty('data') && msg.data.hasOwnProperty('retval')) {
|
||||
fhcerror.alertWarning(JSON.stringify(msg.data.retval));
|
||||
$fhcAlert.alertWarning(JSON.stringify(msg.data.retval));
|
||||
} else {
|
||||
fhcerror.alertSystemError(JSON.stringify(msg));
|
||||
$fhcAlert.alertSystemError(JSON.stringify(msg));
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -305,15 +309,15 @@ export default {
|
||||
if (typeof message === 'object' && message !== null){
|
||||
if (message.hasOwnProperty('data') && message.data.hasOwnProperty('retval')) {
|
||||
// NOTE(chris): changed: alertSystemError => alertWarning
|
||||
fhcerror.alertWarning(JSON.stringify(message.data.retval));
|
||||
$fhcAlert.alertWarning(JSON.stringify(message.data.retval));
|
||||
} else {
|
||||
fhcerror.alertSystemError(JSON.stringify(message));
|
||||
$fhcAlert.alertSystemError(JSON.stringify(message));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Fallback
|
||||
fhcerror.alertSystemError('alertSystemError throws Generic Error\r\nError Controller Path: ' + FHC_JS_DATA_STORAGE_OBJECT.called_path + '/' + FHC_JS_DATA_STORAGE_OBJECT.called_method);
|
||||
$fhcAlert.alertSystemError('alertSystemError throws Generic Error\r\nError Controller Path: ' + FHC_JS_DATA_STORAGE_OBJECT.called_path + '/' + FHC_JS_DATA_STORAGE_OBJECT.called_method);
|
||||
},
|
||||
resetFormValidation(form) {
|
||||
const event = new Event('fhc-form-reset');
|
||||
|
||||
@@ -0,0 +1,318 @@
|
||||
import FhcAlert from './FhcAlert.js';
|
||||
import FhcApiFactory from '../api/fhcapifactory.js';
|
||||
|
||||
|
||||
export default {
|
||||
install: (app, options) => {
|
||||
app.use(FhcAlert);
|
||||
|
||||
function _get_config(form, uri, data, config) {
|
||||
if (typeof form == 'string' && config === undefined) {
|
||||
[uri, data, config] = [form, uri, data];
|
||||
form = undefined;
|
||||
} else if (form) {
|
||||
if (typeof form != 'object')
|
||||
throw new TypeError('Parameter 1 of _get_config must be an object or a string');
|
||||
if (uri === undefined && data === undefined && config === undefined) {
|
||||
config = form;
|
||||
form = undefined;
|
||||
}
|
||||
}
|
||||
if (form) {
|
||||
// NOTE(chris): check if form is fhc-form
|
||||
if (!form.clearValidation || !form.setFeedback)
|
||||
throw new TypeError("'form' is not a Form Component");
|
||||
|
||||
form = {
|
||||
clearValidation: form.clearValidation,
|
||||
setFeedback: form.setFeedback
|
||||
};
|
||||
|
||||
if (config)
|
||||
config.form = form;
|
||||
else
|
||||
config = {form};
|
||||
}
|
||||
|
||||
return [uri, data, config];
|
||||
}
|
||||
|
||||
function _clean_return_value(response) {
|
||||
const result = response.data;
|
||||
delete response.data;
|
||||
if (!result.meta)
|
||||
result.meta = {response};
|
||||
else
|
||||
result.meta.response = response;
|
||||
return result;
|
||||
}
|
||||
|
||||
const fhcApiAxios = axios.create({
|
||||
timeout: 5000,
|
||||
baseURL: FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + "/"
|
||||
});
|
||||
|
||||
fhcApiAxios.interceptors.request.use(config => {
|
||||
if (config.method != 'post' || !config.data)
|
||||
return config;
|
||||
|
||||
if (config.data instanceof FormData)
|
||||
return config;
|
||||
|
||||
if (!Object.values(config.data).every(item => {
|
||||
if (item instanceof FileList)
|
||||
return false;
|
||||
if (Array.isArray(item))
|
||||
return item.every(i => !(i instanceof File));
|
||||
return true;
|
||||
})) {
|
||||
const newData = Object.entries(config.data).reduce((nd, [key, item]) => {
|
||||
if (item instanceof FileList) {
|
||||
for (const file of item)
|
||||
nd.FormData.append(key + (item.length > 1 ? '[]' : ''), file);
|
||||
} else if (Array.isArray(item)) {
|
||||
if (item.every(i => !(i instanceof File))) {
|
||||
nd.jsondata[key] = item;
|
||||
} else {
|
||||
item.forEach(file => nd.FormData.append(key + (item.length > 1 ? '[]' : ''), file));
|
||||
}
|
||||
} else {
|
||||
nd.jsondata[key] = item;
|
||||
}
|
||||
return nd;
|
||||
}, {
|
||||
FormData: new FormData(),
|
||||
jsondata: {}
|
||||
});
|
||||
newData.FormData.append('_jsondata', JSON.stringify(newData.jsondata));
|
||||
config.data = newData.FormData;
|
||||
}
|
||||
|
||||
return config;
|
||||
});
|
||||
|
||||
fhcApiAxios.interceptors.response.use(response => {
|
||||
if (response.config?.errorHandling == 'off'
|
||||
|| response.config?.errorHandling === false
|
||||
|| response.config?.errorHandling == 'fail')
|
||||
return _clean_return_value(response);
|
||||
|
||||
// NOTE(chris): loop through errors
|
||||
if (response.data.errors)
|
||||
response.data.errors = response.data.errors.filter(
|
||||
err => (response.config[err.type + 'ErrorHandler'] || app.config.globalProperties.$fhcApi._defaultErrorHandlers[err.type])(err, response.config)
|
||||
);
|
||||
|
||||
return _clean_return_value(response);
|
||||
}, error => {
|
||||
if (error.code == 'ERR_CANCELED')
|
||||
return Promise.reject({...{handled: true}, ...error});
|
||||
|
||||
if (error.config?.errorHandling == 'off'
|
||||
|| error.config?.errorHandling === false
|
||||
|| error.config?.errorHandling == 'success')
|
||||
return Promise.reject(error);
|
||||
|
||||
if (error.response) {
|
||||
if (error.response.status == 404) {
|
||||
app.config.globalProperties.$fhcAlert.alertDefault('error', error.message, error.request.responseURL, true);
|
||||
return Promise.reject({...{handled: true}, ...error});
|
||||
}
|
||||
|
||||
// NOTE(chris): loop through errors
|
||||
error.response.data.errors = error.response.data.errors.filter(
|
||||
err => (error.config[err.type + 'ErrorHandler'] || app.config.globalProperties.$fhcApi._defaultErrorHandlers[err.type])(err, error.config)
|
||||
);
|
||||
if (!error.response.data.errors.length)
|
||||
return Promise.reject({...{handled: true}, ...error});
|
||||
} else if (error.request) {
|
||||
app.config.globalProperties.$fhcAlert.alertDefault('error', error.message, error.request.responseURL);
|
||||
return Promise.reject({...{handled: true}, ...error});
|
||||
} else {
|
||||
app.config.globalProperties.$fhcAlert.alertError(error.message);
|
||||
return Promise.reject({...{handled: true}, ...error});
|
||||
}
|
||||
|
||||
return Promise.reject(error);
|
||||
});
|
||||
|
||||
app.config.globalProperties.$fhcApi = {
|
||||
get(form, uri, params, config) {
|
||||
[uri, params, config] = _get_config(form, uri, params, config);
|
||||
if (params) {
|
||||
if (config)
|
||||
config.params = params;
|
||||
else
|
||||
config = {params};
|
||||
}
|
||||
return fhcApiAxios.get(uri, config);
|
||||
},
|
||||
post(form, uri, data, config) {
|
||||
[uri, data, config] = _get_config(form, uri, data, config);
|
||||
return fhcApiAxios.post(uri, data, config);
|
||||
},
|
||||
_defaultErrorHandlers: {
|
||||
validation(error, config) {
|
||||
const $fhcAlert = app.config.globalProperties.$fhcAlert;
|
||||
|
||||
if (config?.form) {
|
||||
config.form.clearValidation();
|
||||
config.form.setFeedback(false, error.messages);
|
||||
return false;
|
||||
}
|
||||
if (Array.isArray(error.messages)) {
|
||||
error.messages.forEach($fhcAlert.alertError);
|
||||
return false;
|
||||
} else if (typeof error.messages == 'object') {
|
||||
if (config?.errorHeader)
|
||||
Object.values(error.messages).forEach(
|
||||
value => $fhcAlert.alertDefault(
|
||||
'error',
|
||||
Array.isArray(config.errorHeader) ? app.config.globalProperties.$p.t.apply(null, config.errorHeader) : config.errorHeader,
|
||||
value,
|
||||
true
|
||||
)
|
||||
);
|
||||
else
|
||||
Object.entries(error.messages).forEach(
|
||||
([key, value]) => $fhcAlert.alertDefault('error', key, value, true)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
general(error, config) {
|
||||
const $fhcAlert = app.config.globalProperties.$fhcAlert;
|
||||
|
||||
if (config?.form)
|
||||
config.form.setFeedback(false, error.message);
|
||||
else if (config?.errorHeader)
|
||||
$fhcAlert.alertDefault(
|
||||
'error',
|
||||
Array.isArray(config.errorHeader) ? app.config.globalProperties.$p.t.apply(null, config.errorHeader) : config.errorHeader,
|
||||
error.message,
|
||||
true
|
||||
);
|
||||
else
|
||||
$fhcAlert.alertError(error.message);
|
||||
},
|
||||
php(error) {
|
||||
const $fhcAlert = app.config.globalProperties.$fhcAlert;
|
||||
|
||||
var message = '';
|
||||
message += 'Message: ' + error.message + '\n\n';
|
||||
message += 'Filename: ' + error.filename + '\n';
|
||||
message += 'Line Number: ' + error.line + '\n';
|
||||
if (error.backtrace && error.backtrace.length) {
|
||||
message += '\nBacktrace: ';
|
||||
error.backtrace.forEach(err => {
|
||||
message += '\n\tFile: ' + err.file + '\n';
|
||||
message += '\tLine: ' + err.line + '\n';
|
||||
message += '\tFunction: ' + err.function + '\n';
|
||||
});
|
||||
}
|
||||
switch (error.severity) {
|
||||
case 'Warning':
|
||||
case 'Core Warning':
|
||||
case 'Compile Warning':
|
||||
case 'User Warning':
|
||||
$fhcAlert.alertDefault('warn', 'PHP ' + error.severity, message, true);
|
||||
break;
|
||||
case 'Notice':
|
||||
case 'User Notice':
|
||||
case 'Runtime Notice':
|
||||
$fhcAlert.alertDefault('info', 'PHP ' + error.severity, message, true);
|
||||
break;
|
||||
default:
|
||||
message = 'Type: PHP ' + error.severity + '\n\n' + message;
|
||||
$fhcAlert.alertSystemError(message);
|
||||
break;
|
||||
}
|
||||
},
|
||||
exception(error) {
|
||||
const $fhcAlert = app.config.globalProperties.$fhcAlert;
|
||||
|
||||
var message = '';
|
||||
message += 'Type: ' + error.class + '\n\n';
|
||||
message += 'Message: ' + error.message + '\n\n';
|
||||
message += 'Filename: ' + error.filename + '\n';
|
||||
message += 'Line Number: ' + error.line + '\n';
|
||||
if (error.backtrace && error.backtrace.length) {
|
||||
message += '\nBacktrace: ';
|
||||
error.backtrace.forEach(err => {
|
||||
message += '\n\tFile: ' + err.file + '\n';
|
||||
message += '\tLine: ' + err.line + '\n';
|
||||
message += '\tFunction: ' + err.function + '\n';
|
||||
});
|
||||
}
|
||||
$fhcAlert.alertSystemError(message);
|
||||
},
|
||||
db(error) {
|
||||
const $fhcAlert = app.config.globalProperties.$fhcAlert;
|
||||
|
||||
var message = '';
|
||||
if (error.heading !== undefined)
|
||||
message += error.heading + '\n\n';
|
||||
if (error.code !== undefined)
|
||||
message += 'Code: ' + error.code + '\n\n';
|
||||
if (error.sql !== undefined)
|
||||
message += 'SQL: ' + error.sql + '\n\n';
|
||||
if (error.message !== undefined)
|
||||
message += 'Message: ' + error.message + '\n\n';
|
||||
else if (error.messages !== undefined)
|
||||
message += 'Messages: ' + error.messages.join('\n\t') + '\n\n';
|
||||
if (error.filename !== undefined)
|
||||
message += 'Filename: ' + error.filename + '\n';
|
||||
if (error.line !== undefined)
|
||||
message += 'Line Number: ' + error.line + '\n';
|
||||
|
||||
$fhcAlert.alertSystemError(message);
|
||||
},
|
||||
auth(error, config) {
|
||||
const $fhcAlert = app.config.globalProperties.$fhcAlert;
|
||||
|
||||
var message = '';
|
||||
message += 'Controller name: ' + error.controller + '\n';
|
||||
message += 'Method name: ' + error.method + '\n';
|
||||
message += 'Required permissions: ' + error.required_permissions;
|
||||
if (config?.errorHeader)
|
||||
$fhcAlert.alertDefault(
|
||||
'error',
|
||||
Array.isArray(config.errorHeader) ? app.config.globalProperties.$p.t.apply(null, config.errorHeader) : config.errorHeader,
|
||||
error.message,
|
||||
true
|
||||
);
|
||||
else
|
||||
$fhcAlert.alertDefault('error', error.message, message);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class FhcApiFactoryWrapper {
|
||||
constructor(factorypart, root) {
|
||||
if (root === undefined)
|
||||
this.$fhcApi = app.config.globalProperties.$fhcApi;
|
||||
else
|
||||
Object.defineProperty(this, '$fhcApi', {
|
||||
get() {
|
||||
return (root || this).$fhcApi;
|
||||
}
|
||||
})
|
||||
Object.keys(factorypart).forEach(key => {
|
||||
Object.defineProperty(this, key, {
|
||||
get() {
|
||||
if (typeof factorypart[key] == 'function')
|
||||
return factorypart[key].bind(this);
|
||||
return new FhcApiFactoryWrapper(factorypart[key], root || this);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const mergedFhcApiFactory = options?.factory ? {...FhcApiFactory, ...options.factory} : FhcApiFactory;
|
||||
|
||||
app.config.globalProperties.$fhcApi.factory = new FhcApiFactoryWrapper(mergedFhcApiFactory);
|
||||
|
||||
}
|
||||
};
|
||||
@@ -1,3 +1,5 @@
|
||||
import FhcApi from './FhcApi.js';
|
||||
|
||||
const categories = Vue.reactive({});
|
||||
const loadingModules = {};
|
||||
|
||||
@@ -21,20 +23,19 @@ function getValueForLoadedPhrase(category, phrase, params) {
|
||||
const phrasen = {
|
||||
loadCategory(category) {
|
||||
if (Array.isArray(category))
|
||||
return Promise.all(category.map(cat => this.loadCategory(cat)));
|
||||
return Promise.all(category.map(this.config.globalProperties
|
||||
.$p.loadCategory));
|
||||
if (!loadingModules[category])
|
||||
loadingModules[category] = axios
|
||||
.get(FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + '/components/Phrasen/loadModule/' + category)
|
||||
loadingModules[category] = this.config.globalProperties
|
||||
.$fhcApi.factory.phrasen.loadCategory(category)
|
||||
.then(res => res?.data ? extractCategory(res.data, category) : {})
|
||||
.then(res => {
|
||||
if (res.data.retval)
|
||||
categories[category] = extractCategory(res.data.retval, category);
|
||||
else
|
||||
categories[category] = {};
|
||||
categories[category] = res;
|
||||
});
|
||||
return loadingModules[category];
|
||||
},
|
||||
t_ref(category, phrase, params) {
|
||||
console.warn('depricated');
|
||||
console.warn('deprecated');
|
||||
return Vue.computed(() => this.t(category, phrase, params));
|
||||
},
|
||||
t(category, phrase, params) {
|
||||
@@ -62,6 +63,11 @@ const phrasen = {
|
||||
|
||||
export default {
|
||||
install(app, options) {
|
||||
app.config.globalProperties.$p = phrasen;
|
||||
app.use(FhcApi, options?.fhcApi || undefined);
|
||||
app.config.globalProperties.$p = {
|
||||
t: phrasen.t,
|
||||
loadCategory: cat => phrasen.loadCategory.call(app, cat),
|
||||
t_ref: phrasen.t_ref
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user