Merge branch 'master' into feature-69516/studvw_verbandsbaum_zu_ausklappbar_machen

This commit is contained in:
ma0068
2026-02-02 16:48:02 +01:00
88 changed files with 3915 additions and 955 deletions
+17 -27
View File
@@ -38,16 +38,18 @@ export default {
url: 'api/frontend/v1/messages/messages/getMsgVarsLoggedInUser/'
};
},
getMessageVarsPerson(userParams){
getMessageVarsPerson(ids, type_id){
return {
method: 'post',
url: 'api/frontend/v1/messages/messages/getMessageVarsPerson/' + userParams.id + '/' + userParams.type_id
url: 'api/frontend/v1/messages/messages/getMessageVarsPerson/' + type_id,
params: {ids}
};
},
getMsgVarsPrestudent(userParams){
getMsgVarsPrestudent(ids, type_id){
return {
method: 'post',
url: 'api/frontend/v1/messages/messages/getMsgVarsPrestudent/' + userParams.id + '/' + userParams.type_id
url: 'api/frontend/v1/messages/messages/getMsgVarsPrestudent/' + type_id,
params: {ids}
};
},
getPersonId(params){
@@ -56,28 +58,23 @@ export default {
url: 'api/frontend/v1/messages/messages/getPersonId/' + params.id + '/' + params.type_id
};
},
getUid(userParams){
return {
method: 'get',
url: 'api/frontend/v1/messages/messages/getUid/' + userParams.id + '/' + userParams.type_id
};
},
getDataVorlage(vorlage_kurzbz){
return {
method: 'get',
url: 'api/frontend/v1/messages/messages/getDataVorlage/' + vorlage_kurzbz
};
},
getNameOfDefaultRecipient(params){
return {
method: 'get',
url: 'api/frontend/v1/messages/messages/getNameOfDefaultRecipient/' + params.id + '/' + params.type_id
};
},
getPreviewText(userParams, params){
getNameOfDefaultRecipients(ids, type_id){
return {
method: 'post',
url: 'api/frontend/v1/messages/messages/getPreviewText/' + userParams.id + '/' + userParams.type_id,
url: 'api/frontend/v1/messages/messages/getNameOfDefaultRecipients/' + type_id,
params: {ids}
};
},
getPreviewText(type_id, params){
return {
method: 'post',
url: 'api/frontend/v1/messages/messages/getPreviewText/' + type_id,
params
};
},
@@ -87,17 +84,10 @@ export default {
url: 'api/frontend/v1/messages/messages/getReplyData/' + messageId
};
},
sendMessageFromModalContext(id, params) {
sendMessage(type_id, params) {
return {
method: 'post',
url: 'api/frontend/v1/messages/messages/sendMessage/' + id,
params
};
},
sendMessage(id, params) {
return {
method: 'post',
url: 'api/frontend/v1/messages/messages/sendMessage/' + id,
url: 'api/frontend/v1/messages/messages/sendMessage/' + type_id,
params
};
},
+11
View File
@@ -0,0 +1,11 @@
export default {
getStudienplaeneBySemester(studiengang_kz, studiensemester_kurzbz, ausbildungssemester, orgform_kurzbz)
{
return {
method: 'get',
url: 'api/frontend/v1/organisation/studienplan/getBySemester',
params: { studiengang_kz, studiensemester_kurzbz, ausbildungssemester, orgform_kurzbz },
};
}
}
+11
View File
@@ -0,0 +1,11 @@
export default {
getAll(order = null, start = null)
{
return {
method: 'get',
url: 'api/frontend/v1/organisation/studiensemester/getAll',
params: { order, start }
};
}
}
+1 -1
View File
@@ -101,7 +101,7 @@ export default {
deleteMobilityPurpose(params) {
return {
method: 'post',
url: 'api/frontend/v1/stv/mobility/deleteMobilityPurpose/',
url: 'api/frontend/v1/stv/mobility/deleteMobilityPurpose/' + params.bisio_id,
params
};
},
@@ -49,6 +49,12 @@ export default {
url: 'api/frontend/v1/stv/projektarbeit/getNoten'
};
},
getStudiensemester() {
return {
method: 'get',
url: 'api/frontend/v1/stv/projektarbeit/getStudiensemester'
};
},
loadProjektarbeit(projektarbeit_id) {
return {
method: 'get',
+2 -2
View File
@@ -60,10 +60,10 @@ export default {
url: 'api/frontend/v1/stv/students/' + relative_path
};
},
check(params) {
getPerson(params) {
return {
method: 'post',
url: 'api/frontend/v1/stv/student/check',
url: 'api/frontend/v1/stv/student/getPerson',
params
};
},
+4 -3
View File
@@ -1,14 +1,15 @@
import NewMessage from "../components/Messages/Details/NewMessage/NewDiv.js";
import Phrasen from "../plugin/Phrasen.js";
import Phrasen from "../plugins/Phrasen.js";
const ciPath = FHC_JS_DATA_STORAGE_OBJECT.app_root.replace(/(https:|)(^|\/\/)(.*?\/)/g, '') + FHC_JS_DATA_STORAGE_OBJECT.ci_router;
const router = VueRouter.createRouter({
history: VueRouter.createWebHistory(),
routes: [
{ path: `/${ciPath}/NeueNachricht/:id/:typeId`, component: NewMessage },
{ path: `/${ciPath}/NeueNachricht/:id/:typeId/:messageId`, component: NewMessage },
{ path: `/${ciPath}/NeueNachricht`, component: NewMessage, props: true },
{ path: `/${ciPath}/NeueNachricht/:id/:typeId`, component: NewMessage, props: true },
{ path: `/${ciPath}/NeueNachricht/:id/:typeId/:messageId`, component: NewMessage, props: true },
]
});
-6
View File
@@ -8,12 +8,6 @@ export const FhcChart = {
},
template: `
<div style="width:100%;height:100%;overflow:auto">
<div role="group" aria-label="Chart Modus">
<Button :class="(chartOptions.chart.type === 'pie' ? 'active ' : '') + 'btn btn-outline-secondary'" style="width: 48px;" @click="chartOptions.chart.type='pie'"><i class="fa-solid fa-chart-pie"></i></Button>
<Button :class="(chartOptions.chart.type === 'bar' ? 'active ' : '') + 'btn btn-outline-secondary'" style="width: 48px;" @click="chartOptions.chart.type='bar'"><i class="fa-solid fa-chart-bar"></i></Button>
<Button :class="(chartOptions.chart.type === 'column' ? 'active ' : '') + 'btn btn-outline-secondary'" style="width: 48px;" @click="chartOptions.chart.type='column'"><i class="fa-solid fa-chart-simple"></i></Button>
<Button :class="(chartOptions.chart.type === 'line' ? 'active ' : '') + 'btn btn-outline-secondary'" style="width: 48px;" @click="chartOptions.chart.type='line'"><i class="fa-solid fa-chart-line"></i></Button>
</div>
<figure>
<highcharts class="chart" :options="chartOptions"></highcharts>
</figure>
@@ -46,7 +46,6 @@ export default {
loading: false,
filter: "Pending",
profil_update_id: Number(this.id),
};
},
computed: {
@@ -60,6 +59,10 @@ export default {
},
profilUpdateOptions: function () {
return {
persistence: {
columns: ["width", "visible", "frozen"],
},
persistenceID: 'cis-profilupdate-2025121702',
ajaxURL: 'dummy',
ajaxRequestFunc: (url, config, params) => {
return this.$api.call(ApiProfilUpdate.getProfilUpdateWithPermission(params.filter));
@@ -205,7 +208,7 @@ export default {
//responsive:0,
},
{
title: this.$p.t("lehre", "studiengang") + ' (' + this.$p.t("profil", "studentIn") + ')',
title: this.$p.t("profil", "stg_short") + ' (' + this.$p.t("profil", "studentIn") + ')',
field: "studiengang",
minWidth: 50,
resizable: true,
@@ -213,8 +216,14 @@ export default {
headerFilterParams: {valuesLookup:true, listOnEmpty:true, autocomplete:true, sort:"asc"},
//responsive:0,
},
{
title: this.$p.t("lehre", "organisationsform") + ' (' + this.$p.t("profil", "studentIn") + ')',
{
title: this.$p.t("profil", "sem_short") + ' (' + this.$p.t("profil", "studentIn") + ')',
field: "semester",
headerFilter: "list",
headerFilterParams: {valuesLookup:true, listOnEmpty:true, autocomplete:true, sort:"asc"}
},
{
title: this.$p.t("profil", "orgform_short") + ' (' + this.$p.t("profil", "studentIn") + ')',
field: "orgform",
minWidth: 50,
resizable: true,
@@ -222,8 +231,8 @@ export default {
headerFilterParams: {valuesLookup:true, listOnEmpty:true, autocomplete:true, sort:"asc"},
//responsive:0,
},
{
title: this.$p.t("lehre", "organisationseinheit") + ' (' + this.$p.t("profil", "mitarbeiterIn") + ')',
{
title: this.$p.t("profil", "orgeinheit_short") + ' (' + this.$p.t("profil", "mitarbeiterIn") + ')',
field: "oezuordnung",
minWidth: 200,
resizable: true,
@@ -231,7 +240,7 @@ export default {
headerFilterParams: {valuesLookup:true, listOnEmpty:true, autocomplete:true, sort:"asc"},
//responsive:0,
},
{
{
title: this.$p.t("profilUpdate", "Topic"),
field: "topic",
resizable: true,
@@ -240,7 +249,7 @@ export default {
headerFilterParams: {valuesLookup:true, listOnEmpty:true, autocomplete:true, sort:"asc"},
//responsive:0,
},
{
{
title: this.$p.t("profilUpdate", "insertamum"),
field: "insertamum_iso",
resizable: true,
@@ -251,7 +260,7 @@ export default {
formatterParams: this.datetimeFormatterParams(),
//responsive:0,
},
{
{
title: this.$p.t("profilUpdate", "Status"),
field: "status_translated",
hozAlign: "center",
@@ -273,7 +282,6 @@ export default {
}
return `<div class='row justify-content-center'><div class='col-2'><i class='${iconClasses}'></i></div> <div class='col-4'><span>${cell.getValue()}</span></div></div>`;
},
resizable: true,
minWidth: 200,
//responsive:0,
@@ -309,7 +317,6 @@ export default {
],
};
}
},
methods: {
denyProfilUpdate: function (data) {
@@ -351,7 +358,6 @@ export default {
this.showModal = false;
this.modalData = null;
},
showAcceptDenyModal(value) {
this.modalData = value;
if (!this.modalData) {
@@ -364,7 +370,6 @@ export default {
this.$refs.AcceptDenyModal.show();
});
},
updateData: function (event) {
this.$refs.UpdatesTable.tabulator.setData();
//? store the selected view in the session storage of the browser
@@ -415,22 +420,30 @@ export default {
},
template: /*html*/ `
<div>
<accept-deny-update :title="$p.t('profilUpdate','profilUpdateRequest')" v-if="showModal" ref="AcceptDenyModal" @hideBsModal="hideAcceptDenyModal" :value="JSON.parse(JSON.stringify(modalData))" :setLoading="setLoading" ></accept-deny-update>
<div class="form-underline flex-fill ">
<div class="form-underline-titel">{{$p.t('ui','anzeigen')}} </div>
<select class="mb-4 form-select" v-model="filter" @change="updateData" aria-label="Profil updates display selection">
<option :selected="true" :value="profilUpdateStates['Pending']" >{{$p.t('profilUpdate','pendingRequests')}}</option>
<option :value="profilUpdateStates['Accepted']">{{$p.t('profilUpdate','acceptedRequests')}}</option>
<option :value="profilUpdateStates['Rejected']">{{$p.t('profilUpdate','rejectedRequests')}}</option>
<option :value="'Alle'">{{$p.t('profilUpdate','allRequests')}}</option>
</select>
</div>
<loading ref="loadingModalRef" :timeout="0"></loading>
<core-filter-cmpt v-if="profilUpdateStates && categoryLoaded" :title="$p.t('profilUpdate','profilUpdateRequests')" ref="UpdatesTable" :tabulatorEvents="profilUpdateEvents" :tabulator-options="profilUpdateOptions" tableOnly :sideMenu="false" />
<accept-deny-update :title="$p.t('profilUpdate','profilUpdateRequest')" v-if="showModal" ref="AcceptDenyModal" @hideBsModal="hideAcceptDenyModal" :value="JSON.parse(JSON.stringify(modalData))" :setLoading="setLoading" ></accept-deny-update>
<h3>{{$p.t('profilUpdate', 'profilUpdateRequests')}}</h3>
<loading ref="loadingModalRef" :timeout="0"></loading>
</div>`,
<core-filter-cmpt
v-if="profilUpdateStates && categoryLoaded"
ref="UpdatesTable"
:tabulatorEvents="profilUpdateEvents"
:tabulator-options="profilUpdateOptions"
table-only
:sideMenu="false">
<template #actions>
<div style="width: 94vw;" class="d-flex justify-content-end">
<div>
<select class="mb-4 form-select" v-model="filter" @change="updateData" aria-label="Profil updates display selection">
<option :selected="true" :value="profilUpdateStates['Pending']" >{{$p.t('profilUpdate','pendingRequests')}}</option>
<option :value="profilUpdateStates['Accepted']">{{$p.t('profilUpdate','acceptedRequests')}}</option>
<option :value="profilUpdateStates['Rejected']">{{$p.t('profilUpdate','rejectedRequests')}}</option>
<option :value="'Alle'">{{$p.t('profilUpdate','allRequests')}}</option>
</select>
</div>
</div>
</template>
</core-filter-cmpt>
</div>`,
};
+1
View File
@@ -280,6 +280,7 @@ export default {
<template #chip="data"><slot name="chip" v-bind="data"></slot></template>
<template #header="data"><slot name="header" v-bind="data"></slot></template>
<template #footer="data"><slot name="footer" v-bind="data"></slot></template>
<template #selectedItem="data"><slot name="selectedItem" v-bind="data"></slot></template>
<template #option="data"><slot name="option" v-bind="data"></slot></template>
<template #optiongroup="data"><slot name="optiongroup" v-bind="data"></slot></template>
<template #content="data"><slot name="content" v-bind="data"></slot></template>
@@ -4,6 +4,8 @@ import FormInput from '../../../Form/Input.js';
import ListBox from "../../../../../../index.ci.php/public/js/components/primevue/listbox/listbox.esm.min.js";
import DropdownComponent from "../../../VorlagenDropdown/VorlagenDropdown.js";
import ApiMessages from '../../../../api/factory/messages/messages.js';
export default {
name: "ModalNewMessages",
components: {
@@ -14,13 +16,9 @@ export default {
ListBox
},
props: {
endpoint: {
type: Object,
required: true
},
typeId: String,
id: {
type: [Number, String],
type: Array,
required: true
},
messageId: {
@@ -43,6 +41,8 @@ export default {
vorlagen: [],
recipientsArray: [],
defaultRecipient: null,
defaultRecipients: [],
defaultRecipientString: null,
editor: null,
fieldsUser: [],
fieldsPerson: [],
@@ -56,7 +56,6 @@ export default {
previewText: null,
previewBody: "",
replyData: null,
uid: null,
}
},
methods: {
@@ -111,34 +110,28 @@ export default {
},
sendMessage() {
const data = new FormData();
const params = {
id: this.id,
type_id: this.typeId
};
const merged = {
...this.formData,
...params
};
data.append('data', JSON.stringify(merged));
data.append('data', JSON.stringify(this.formData));
data.append('ids', JSON.stringify(this.id));
return this.$refs.formMessage
.call(this.endpoint.sendMessageFromModalContext(this.uid, data))
.call(ApiMessages.sendMessage(this.typeId, data))
.then(response => {
this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSent'));
this.hideModal('modalNewMessage');
this.resetForm();
}).catch(this.$fhcAlert.handleSystemError)
.finally(() => {
//this.resetForm();
//closeModal
//closewindwo
//just emit if no multitasking
if(this.id.length == 1){
this.$emit('reloadTable');
}
}
);
},
getDataVorlage(vorlage_kurzbz){
return this.$api
.call(this.endpoint.getDataVorlage(vorlage_kurzbz))
.call(ApiMessages.getDataVorlage(vorlage_kurzbz))
.then(response => {
this.formData.body = response.data.text;
this.formData.subject = response.data.subject;
@@ -146,17 +139,17 @@ export default {
},
getPreviewText(){
const data = new FormData();
data.append('data', JSON.stringify(this.formData.body));
data.append('ids', JSON.stringify(this.id));
return this.$api
.call(this.endpoint.getPreviewText({
id: this.id,
type_id: this.typeId}, data))
.call(ApiMessages.getPreviewText(
this.typeId, data))
.then(response => {
this.previewText = response.data;
const previews = response.data;
this.previewText = previews[this.defaultRecipient];
}).catch(this.$fhcAlert.handleSystemError)
.finally(() => {
//this.resetForm();
//closeModal
//closewindwo
});
@@ -171,7 +164,7 @@ export default {
this.editor.save();
} else {
console.error("Editor instance is not available.");
console.error(this.$p.t('messages', 'errorEditorNotAvailable'));
}
},
resetForm(){
@@ -180,6 +173,7 @@ export default {
body: null,
subject: null,
};
this.$emit('resetMessageId');
if (this.editor) {
@@ -201,18 +195,6 @@ export default {
this.previewBody = this.previewText;
});
},
getUid(id, typeId){
const params = {
id: id,
type_id: typeId
};
this.$api
.call(this.endpoint.getUid(params))
.then(result => {
this.uid = result.data;
})
.catch(this.$fhcAlert.handleSystemError);
},
show(){
this.$refs.modalNewMessage.show();
},
@@ -245,7 +227,7 @@ export default {
if (!newMessageId) return;
try {
const result = await this.$api.call(this.endpoint.getReplyData(newMessageId));
const result = await this.$api.call(ApiMessages.getReplyData(newMessageId));
this.replyData = result.data;
if (this.replyData.length > 0) {
@@ -260,15 +242,9 @@ export default {
}
},
created(){
this.getUid(this.id, this.typeId);
if(this.typeId == 'person_id' || this.typeId == 'mitarbeiter_uid'){
const params = {
id: this.id,
type_id: this.typeId
};
this.$api
.call(this.endpoint.getMessageVarsPerson(params))
.call(ApiMessages.getMessageVarsPerson(this.id, this.typeId))
.then(result => {
this.fieldsPerson = result.data;
const person = this.fieldsPerson[0];
@@ -281,12 +257,8 @@ export default {
}
if(this.typeId == 'prestudent_id' || this.typeId == 'uid'){
const params = {
id: this.id,
type_id: this.typeId
};
this.$api
.call(this.endpoint.getMsgVarsPrestudent(params))
.call(ApiMessages.getMsgVarsPrestudent(this.id, this.typeId))
.then(result => {
this.fieldsPrestudent = result.data;
const prestudent = this.fieldsPrestudent[0];
@@ -299,7 +271,7 @@ export default {
}
this.$api
.call(this.endpoint.getMsgVarsLoggedInUser())
.call(ApiMessages.getMsgVarsLoggedInUser())
.then(result => {
this.fieldsUser = result.data;
const user = this.fieldsUser;
@@ -311,21 +283,18 @@ export default {
.catch(this.$fhcAlert.handleSystemError);
this.$api
.call(this.endpoint.getNameOfDefaultRecipient({
id: this.id,
type_id: this.typeId}))
.call(ApiMessages.getNameOfDefaultRecipients(this.id, this.typeId))
.then(result => {
this.defaultRecipient = result.data;
this.recipientsArray.push({
'uid': this.uid,
'details': this.defaultRecipient});
this.defaultRecipients = result.data;
this.defaultRecipientString = Object.values(this.defaultRecipients).join("; ");
})
.catch(this.$fhcAlert.handleSystemError);
//case of reply
if(this.messageId) {
this.$api
.call(this.endpoint.getReplyData(this.messageId))
.call(ApiMessages.getReplyData(this.messageId))
.then(result => {
this.replyData = result.data;
this.formData.subject = this.replyData[0].replySubject;
@@ -381,7 +350,7 @@ export default {
type="text"
name="recipient"
:label="$p.t('messages/recipient')"
v-model="defaultRecipient"
v-model="defaultRecipientString"
disabled
>
</form-input>
@@ -502,17 +471,17 @@ export default {
>
<option :value="null">{{ $p.t('messages', 'recipient') }}...</option>
<option
v-for="recipient in recipientsArray"
:key="recipient.uid"
:value="recipient.uid"
>{{recipient.details}}
v-for="(name, id) in defaultRecipients"
:key="id"
:value="Number(id)"
> {{name}}
</option>
</form-input>
</div>
<div class="col-md-2 mt-4">
<br>
<button type="button" class="btn btn-secondary" @click="showPreview()">{{ $p.t('ui', 'btnAktualisieren') }}</button>
<button type="button" class="btn btn-secondary" @click="showPreview(defaultRecipient)">{{ $p.t('ui', 'btnAktualisieren') }}</button>
</div>
</form-form>
@@ -2,6 +2,7 @@ import FormForm from '../../../Form/Form.js';
import FormInput from '../../../Form/Input.js';
import ListBox from "../../../../../../index.ci.php/public/js/components/primevue/listbox/listbox.esm.min.js";
import DropdownComponent from '../../../VorlagenDropdown/VorlagenDropdown.js';
import ApiMessages from "../../../../api/factory/messages/messages.js"; //props not working with route
export default {
name: "ComponentNewMessages",
@@ -12,33 +13,17 @@ export default {
DropdownComponent,
},
props: {
endpoint: {
type: Object,
required: true
},
openMode: String,
tempTypeId: String,
tempId: {
type: [Number, String],
typeId: String,
id: {
type: Array,
required: false
},
tempMessageId: {
messageId: {
type: Number,
required: false,
}
},
computed: {
//params with routes for new tab and new window AND props for inSamePage
id(){
return this.$props.tempId || this.$route.params.id;
},
typeId(){
return this.$props.tempTypeId || this.$route.params.typeId;
},
messageId(){
return this.$props.tempMessageId ||this.$route.params.messageId;
}
},
data(){
return {
formData: {
@@ -53,6 +38,8 @@ export default {
vorlagen: [],
recipientsArray: [],
defaultRecipient: null,
defaultRecipients: [],
defaultRecipientString: null,
editor: null,
isVisible: false,
fieldsUser: [],
@@ -67,8 +54,7 @@ export default {
previewText: null,
previewBody: "",
replyData: null,
uid: null,
messageSent: false
messageSent: false,
}
},
methods: {
@@ -106,19 +92,11 @@ export default {
},
sendMessage() {
const data = new FormData();
data.append('data', JSON.stringify(this.formData));
data.append('ids', JSON.stringify(this.id));
const params = {
id: this.id,
type_id: this.typeId
};
const merged = {
...this.formData,
...params
};
data.append('data', JSON.stringify(merged));
return this.$api
.call(this.endpoint.sendMessage(this.uid, data))
.call(ApiMessages.sendMessage(this.typeId, data))
.then(response => {
this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSent'));
this.hideTemplate();
@@ -126,11 +104,7 @@ export default {
this.messageSent = true;
}).catch(this.$fhcAlert.handleSystemError)
.finally(() => {
//TODO(Manu) hier route definieren für openmode in Tab, Page?
// ist kein child sondern mit route aufgerufen
//würde allerdings neues fenster aktualisiert öffnen, altes bleibt ohne reload gleich
//Reload vorheriges tab???
if(this.openMode == "inSamePage"){
if(this.openMode == "inSamePage" && this.id.length == 1 ){
this.$emit('reloadTable');
}
}
@@ -138,25 +112,29 @@ export default {
},
getDataVorlage(vorlage_kurzbz){
return this.$api
.call(this.endpoint.getDataVorlage(vorlage_kurzbz))
.call(ApiMessages.getDataVorlage(vorlage_kurzbz))
.then(response => {
this.formData.body = response.data.text;
this.formData.subject = response.data.subject;
}).catch(this.$fhcAlert.handleSystemError);
},
getPreviewText(id, typeId){
getPreviewText(){
console.log("subj" + this.formData.subject);
const data = new FormData();
data.append('data', JSON.stringify(this.formData.body));
data.append('ids', JSON.stringify(this.id));
console.log("subj" + this.formData.subject);
return this.$api
.call(this.endpoint.getPreviewText({
id: this.id,
type_id: this.typeId}, data))
.call(ApiMessages.getPreviewText(
this.typeId, data))
.then(response => {
this.previewText = response.data;
const previews = response.data;
this.previewText = previews[this.defaultRecipient];
}).catch(this.$fhcAlert.handleSystemError)
.finally(() => {
//this.resetForm();
});
},
insertVariable(selectedItem){
@@ -169,7 +147,7 @@ export default {
this.editor.save();
} else {
console.error("Editor instance is not available.");
console.error(this.$p.t('messages', 'errorEditorNotAvailable'));
}
},
resetForm(){
@@ -177,11 +155,13 @@ export default {
vorlage_kurzbz: null,
body: null,
subject: null,
recipient: null,
selectedValue: null
};
if (this.editor) {
this.editor.setContent("");
}
this.$refs.dropdownComp.setValue(null);
// this.$refs.dropdownComp.setValue(null);
this.previewBody = null;
@@ -199,23 +179,25 @@ export default {
this.isVisible = false;
},
showTemplate(){
if (this.openMode == "inSamePage")
if (this.openMode == "inSamePage") {
this.isVisible = true;
//to enable send newMessage after sentMessage
this.messageSent = false;
}
},
showPreview(id, typeId){
this.getPreviewText(id, typeId).then(() => {
showPreview(){
this.getPreviewText().then(() => {
this.previewBody = this.previewText;
});
},
getUid(id, typeId){
const params = {
id: id,
type_id: typeId
};
loadReplyData(messageId){
this.$api
.call(this.endpoint.getUid(params))
.call(ApiMessages.getReplyData(messageId))
.then(result => {
this.uid = result.data;
this.replyData = result.data;
this.formData.subject = this.replyData[0].replySubject;
this.formData.body = this.replyData[0].replyBody;
this.formData.relationmessage_id = messageId;
})
.catch(this.$fhcAlert.handleSystemError);
}
@@ -242,38 +224,43 @@ export default {
},
},
created(){
this.getUid(this.id, this.typeId);
const missingparamsmsgs = [];
if(!this.typeId)
{
missingparamsmsgs.push(this.$p.t('messages', 'errorMissingOrInvalidParameterRecipientTypeId'));
}
if (['person_id', 'mitarbeiter_uid'].includes(this.typeId)){
const params = {
id: this.id,
type_id: this.typeId
};
if(!this.id || this.id.length < 1)
{
missingparamsmsgs.push(this.$p.t('messages', 'errorMissingOrInvalidParameterRecipientIds'));
}
this.$api
.call(this.endpoint.getMessageVarsPerson(params))
.then(result => {
this.fieldsPerson = result.data;
const person = this.fieldsPerson[0];
this.itemsPerson = Object.entries(person).map(([key, value]) => ({
label: key.toLowerCase(),
value: '{' + key.toLowerCase() + '}'
}));
})
.catch(this.$fhcAlert.handleSystemError);
}
if(missingparamsmsgs.length > 0)
{
this.$fhcAlert.alertMultiple(missingparamsmsgs, 'warn', 'Warning', true);
return;
}
if (['prestudent_id', 'uid'].includes(this.typeId)){
const params = {
id: this.id,
type_id: this.typeId
};
if(this.typeId == 'person_id' || this.typeId == 'mitarbeiter_uid'){
this.$api
.call(this.endpoint.getMsgVarsPrestudent(params))
.call(ApiMessages.getMessageVarsPerson(this.id, this.typeId))
.then(result => {
this.fieldsPerson = result.data;
const person = this.fieldsPerson[0];
this.itemsPerson = Object.entries(person).map(([key, value]) => ({
label: key.toLowerCase(),
value: '{' + key.toLowerCase() + '}'
}));
})
.catch(this.$fhcAlert.handleSystemError);
}
if(this.typeId == 'prestudent_id' || this.typeId == 'uid'){
this.$api
.call(ApiMessages.getMsgVarsPrestudent(this.id, this.typeId))
.then(result => {
this.fieldsPrestudent = result.data;
const prestudent = this.fieldsPrestudent[0];
this.itemsPrestudent = Object.entries(prestudent).map(([key, value]) => ({
label: key.toLowerCase(),
value: '{' + key.toLowerCase() + '}'
@@ -283,7 +270,7 @@ export default {
}
this.$api
.call(this.endpoint.getMsgVarsLoggedInUser())
.call(ApiMessages.getMsgVarsLoggedInUser())
.then(result => {
this.fieldsUser = result.data;
const user = this.fieldsUser;
@@ -295,28 +282,26 @@ export default {
.catch(this.$fhcAlert.handleSystemError);
this.$api
.call(this.endpoint.getNameOfDefaultRecipient({
id: this.id,
type_id: this.typeId}))
.call(ApiMessages.getNameOfDefaultRecipients(this.id, this.typeId))
.then(result => {
this.defaultRecipient = result.data;
this.recipientsArray.push({
'uid': this.uid,
'details': this.defaultRecipient});
this.defaultRecipients = result.data;
this.defaultRecipientString = Object.values(this.defaultRecipients).join("; ");
})
.catch(this.$fhcAlert.handleSystemError);
//case of reply
if(this.messageId != null) {
this.$api
.call(this.endpoint.getReplyData(this.messageId))
this.loadReplyData(this.messageId);
/* this.$api
.call(ApiMessages.getReplyData(this.messageId))
.then(result => {
this.replyData = result.data;
this.formData.subject = this.replyData[0].replySubject;
this.formData.body = this.replyData[0].replyBody;
this.formData.relationmessage_id = this.messageId;
})
.catch(this.$fhcAlert.handleSystemError);
.catch(this.$fhcAlert.handleSystemError);*/
}
},
@@ -330,7 +315,7 @@ export default {
<div class="messages-detail-newmessage-newdiv">
<!--new page-->
<div v-if="!messageSent" class="overflow-auto m-3">
<div v-if="!messageSent" ref="divNewMessage" class="overflow-auto m-3">
<h4>{{ $p.t('messages', 'neueNachricht') }}</h4>
<div class="row">
@@ -343,7 +328,7 @@ export default {
type="text"
name="recipient"
:label="$p.t('messages/recipient')"
v-model="defaultRecipient"
v-model="defaultRecipientString"
disabled
>
</form-input>
@@ -472,18 +457,18 @@ export default {
v-model="defaultRecipient"
>
<option :value="null">{{ $p.t('messages', 'recipient') }}...</option>
<option
v-for="recipient in recipientsArray"
:key="recipient.uid"
:value="recipient.uid"
>{{recipient.details}}
<option
v-for="(name, id) in defaultRecipients"
:key="id"
:value="Number(id)"
> {{name}}
</option>
</form-input>
</div>
<div class="col-md-2 mt-4">
<br>
<button type="button" class="btn btn-secondary" @click="showPreview(id, typeId)">{{ $p.t('ui', 'btnAktualisieren') }}</button>
<button type="button" class="btn btn-secondary" @click="showPreview(defaultRecipient)">{{ $p.t('ui', 'btnAktualisieren') }}</button>
</div>
</form-form>
@@ -1,6 +1,8 @@
import {CoreFilterCmpt} from "../../filter/Filter.js";
import FormForm from '../../Form/Form.js';
import ApiMessages from "../../../api/factory/messages/messages.js"
export default {
name: "TableMessages",
components: {
@@ -13,13 +15,9 @@ export default {
},
},
props: {
endpoint: {
type: Object,
required: true
},
typeId: String,
id: {
type: [Number, String],
type: Array,
required: true
},
messageLayout: String,
@@ -38,12 +36,13 @@ export default {
},
ajaxResponse: (url, params, response) => this.buildTreemap(response),
columns: [
{title: "subject", field: "subject"},
{title: "body", field: "body", formatter: "html", visible: false},
{title: "message_id", field: "message_id", visible: false},
{title: "subject", field: "subject", headerFilter: true},
{title: "body", field: "body", formatter: "html", visible: false, headerFilter: true},
{title: "message_id", field: "message_id", visible: false, headerFilter: true},
{
title: "Datum",
field: "insertamum",
headerFilter: true,
formatter: function (cell) {
const dateStr = cell.getValue();
const date = new Date(dateStr); // Convert to Date object
@@ -55,16 +54,28 @@ export default {
minute: "2-digit",
hour12: false
});
},
headerFilterFunc(headerValue, rowValue) {
const matches = headerValue.match(/^(([0-9]{2})\.)?([0-9]{2})\.([0-9]{4})?$/);
let comparestr = headerValue;
if(matches !== null) {
const year = (matches[4] !== undefined) ? matches[4] : '';
const month = matches[3];
const day = (matches[2] !== undefined) ? matches[2] : '';
comparestr = year + '-' + month + '-' + day;
}
return rowValue.match(comparestr);
}
},
{title: "sender", field: "sender"},
{title: "recipient", field: "recipient"},
{title: "senderId", field: "sender_id"},
{title: "recipientId", field: "recipient_id"},
{title: "Relationmessage ID", field: "relationmessage_id"},
{title: "sender", field: "sender", headerFilter: true},
{title: "recipient", field: "recipient", headerFilter: true},
{title: "senderId", field: "sender_id", headerFilter: true},
{title: "recipientId", field: "recipient_id", headerFilter: true},
{title: "Relationmessage ID", field: "relationmessage_id", headerFilter: true},
{
title: "Status",
field: "status",
headerFilter: true,
formatterParams: [
"unread",
"read",
@@ -73,11 +84,12 @@ export default {
],
formatter: (cell, formatterParams) => {
return formatterParams[cell.getValue()];
}
},
},
{
title: "letzte Änderung",
field: "statusdatum",
headerFilter: true,
formatter: function (cell) {
const dateStr = cell.getValue();
const date = new Date(dateStr); // Convert to Date object
@@ -89,6 +101,17 @@ export default {
minute: "2-digit",
hour12: false
});
},
headerFilterFunc(headerValue, rowValue) {
const matches = headerValue.match(/^(([0-9]{2})\.)?([0-9]{2})\.([0-9]{4})?$/);
let comparestr = headerValue;
if(matches !== null) {
const year = (matches[4] !== undefined) ? matches[4] : '';
const month = matches[3];
const day = (matches[2] !== undefined) ? matches[2] : '';
comparestr = year + '-' + month + '-' + day;
}
return rowValue.match(comparestr);
}
},
{
@@ -256,7 +279,7 @@ export default {
},
deleteMessage(message_id){
return this.$api
.call(this.endpoint.deleteMessage(message_id))
.call(ApiMessages.deleteMessage(message_id))
.then(response => {
this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successDelete'));
}).catch(this.$fhcAlert.handleSystemError)
@@ -322,7 +345,7 @@ export default {
},
loadAjaxCall(url, config, params){
return this.$api.call(
this.endpoint.getMessages(params)
ApiMessages.getMessages(params)
);
}
},
@@ -347,13 +370,13 @@ export default {
});*/
},
created(){
if(this.typeId != 'person_id') {
if(this.typeId != 'person_id' && Array.isArray(this.id) && this.id.length === 1) {
const params = {
id: this.id,
type_id: this.typeId
};
this.$api
.call(this.endpoint.getPersonId(params))
.call(ApiMessages.getPersonId(params))
.then(result => {
this.personId = result.data;
})
+55 -30
View File
@@ -14,10 +14,6 @@ export default {
}
},
props: {
endpoint: {
type: Object,
required: true
},
typeId: {
type: String,
required: true,
@@ -31,7 +27,7 @@ export default {
}
},
id: {
type: [Number, String],
type: Array,
required: true
},
showTable: Boolean,
@@ -65,6 +61,9 @@ export default {
}
},
methods: {
getControllerUrl() {
return FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + '/NeueNachricht';
},
reloadTable(){
this.$refs.templateTableMessage.reload();
},
@@ -77,44 +76,65 @@ export default {
this.openInNewTab(id, typeId, messageId);
}
else if (this.openMode == "modal"){
if(!messageId)
this.$refs.modalMsg.resetForm();
this.$refs.modalMsg.show();
}
else if (this.openMode == "inSamePage"){
console.log("in same Page");
this.isVisibleDiv = true;
if(messageId)
this.$refs.templateNewDivMessage.loadReplyData(messageId);
else
this.$refs.templateNewDivMessage.resetForm();
this.$refs.templateNewDivMessage.showTemplate();
}
else
console.log("no valid openMode");
},
openInNewTab(id, typeId, messageId= null){
openInNewTab(id, typeId, messageId=null){
if(id.length > 1)
{
this.$refs['newMsgForm'].submit();
return;
}
let path = FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router;
let path = this.getControllerUrl();
if (messageId){
path += "/NeueNachricht/" + id + "/" + typeId + "/" + messageId;
path += "/" + encodeURIComponent(id) + "/" + encodeURIComponent(typeId) + "/" + encodeURIComponent(messageId);
}
else {
path += "/NeueNachricht/" + id + "/" + typeId;
path += "/" + encodeURIComponent(id) + "/" + encodeURIComponent(typeId);
}
const newTab = window.open(path, "_blank");
},
openInNewWindow(id, typeId, messageId){
let path = FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router;
if (messageId){
path += "/NeueNachricht/" + id + "/" + typeId + "/" + messageId;
}
else {
path += "/NeueNachricht/" + id + "/" + typeId;
}
const width = Math.round(window.innerWidth * 0.75);
const height = Math.round(window.innerHeight * 0.75);
const left = Math.round((window.innerWidth - width) / 2);
const top = Math.round((window.innerHeight - height) / 2);
if(id.length > 1)
{
const newWindow = window.open('', "NewMsgWindow", `width=${width},height=${height},left=${left},top=${top}`);
this.$refs['newMsgForm'].submit();
return;
}
let path = this.getControllerUrl();
if (messageId){
path += "/" + encodeURIComponent(id) + "/" + encodeURIComponent(typeId) + "/" + encodeURIComponent(messageId);
}
else {
path += "/" + encodeURIComponent(id) + "/" + encodeURIComponent(typeId);
}
const newWindow = window.open(path, "_blank", `width=${width},height=${height},left=${left},top=${top}`);
},
resetMessageId(){
@@ -124,13 +144,21 @@ export default {
},
template: `
<div class="core-messages h-100 pb-3">
<!-- TODO(bh) set target _self for debugging post but _blank for newTab -->
<form ref="newMsgForm"
method="post"
:action="getControllerUrl()"
:target="(openMode === 'window') ? 'NewMsgWindow' : '_blank'"
>
<input type="hidden" name="typeid" :value="typeId">
<input type="hidden" name="ids" :value="id">
</form>
<message-modal
ref="modalMsg"
:type-id="typeId"
:id="id"
:message-id="messageId"
:endpoint="endpoint"
:openMode="openMode"
@reloadTable="reloadTable"
@resetMessageId="resetMessageId"
@@ -138,26 +166,23 @@ export default {
</message-modal>
<!--in same page-->
<div v-if="isVisibleDiv" class="overflow-auto m-3" style="max-height: 500px; border: 1px solid #ccc;">
<div v-show="isVisibleDiv" class="overflow-auto m-3" style="max-height: 500px; border: 1px solid #ccc;">
<form-only
ref="templateNewMessage"
:temp-type-id="typeId"
:temp-id="id"
:temp-message-id="messageId"
:endpoint="endpoint"
ref="templateNewDivMessage"
:type-id="typeId"
:id="id"
:message-id="messageId"
:openMode="openMode"
@reloadTable="reloadTable"
>
</form-only>
</div>
<div v-if="showTable">
<div v-if="showTable && id.length==1">
<table-messages
ref="templateTableMessage"
:type-id="typeId"
:id="id"
:endpoint="endpoint"
:messageLayout="messageLayout"
:openMode="openMode"
@newMessage="handleMessage"
+14 -2
View File
@@ -42,7 +42,11 @@ export default {
showErweitert: Boolean,
showDocument: Boolean,
showTinyMce: Boolean,
visibleColumns: Array
visibleColumns: Array,
tabulatorPersistenceId: {
type: String,
default: 'core-notiz'
}
},
data() {
return {
@@ -179,7 +183,15 @@ export default {
//responsiveLayout: "collapse",
maxHeight: '200px',
index: 'notiz_id',
persistenceID: 'core-notiz'
persistenceID: this.tabulatorPersistenceId,
persistence: {
sort: false,
columns: ["width", "visible", "frozen"],
filter: false,
headerFilter: false,
group: false,
page: false,
}
},
tabulatorEvents: [
{
@@ -192,7 +192,15 @@ export default {
<option value="textLong_plageat">{{$p.t('studierendenantrag', 'dropdown_plageat')}}
</option>
<option value="textLong_MissingZgv">{{$p.t('studierendenantrag', 'dropdown_MissingZgv')}}
</option>
</option>
<option value="textLong_Studienwechsel">{{$p.t('studierendenantrag', 'dropdown_Studienwechsel')}}
</option>
<option value="textLong_Studienabbruch_allgemein">{{$p.t('studierendenantrag', 'dropdown_Studienabbruch_allgemein')}}
</option>
<option value="textLong_vsCodeOfConduct">{{$p.t('studierendenantrag', 'dropdown_vsCodeOfConduct')}}
</option>
<option value="textLong_additionalReason">{{$p.t('studierendenantrag', 'dropdown_additionalReason')}}
</option>
<!--
<option value="textLong_unruly">{{$p.t('studierendenantrag', 'dropdown_unruly')}}
</option>
@@ -84,7 +84,12 @@ export default {
configShowAufnahmegruppen: this.config.showAufnahmegruppen,
configAllowUebernahmePunkte: this.config.allowUebernahmePunkte,
configUseReihungstestPunkte: this.config.useReihungstestPunkte,
appConfig: Vue.computed(() => this.appconfig)
appConfig: Vue.computed(() => this.appconfig),
hasZGVBakkPermission: this.permissions['student/editBakkZgv'],
hasZGVMasterPermission: this.permissions['student/editMakkZgv'],
hasZGVDoctorPermission: this.permissions['student/editDokZgv'],
hasBismeldenPermission: this.permissions['student/editBismelden'],
}
},
data() {
@@ -438,11 +438,9 @@ export default {
if (this.stgInfo.typ === 'b') {
this.formData.pruefungstyp_kurzbz = 'Bachelor';
this.formData.protokoll = this.$p.t('abschlusspruefung', 'pruefungsnotizenMaster');
}
if (this.stgInfo.typ === 'd' || this.stgInfo === 'm') {
this.formData.pruefungstyp_kurzbz = 'Diplom';
this.formData.protokoll = this.$p.t('abschlusspruefung', 'pruefungsnotizenMaster');
}
if (this.stgInfo.typ === 'lg') {
this.formData.pruefungstyp_kurzbz = 'lgabschluss';
@@ -759,6 +757,7 @@ export default {
:label="$p.t('global', 'datum')"
type="DatePicker"
v-model="formData.datum"
model-type="yyyy-MM-dd"
auto-apply
:enable-time-picker="false"
text-input
@@ -783,6 +782,7 @@ export default {
:label="$p.t('abschlusspruefung', 'sponsion')"
type="DatePicker"
v-model="formData.sponsion"
model-type="yyyy-MM-dd"
auto-apply
:enable-time-picker="false"
text-input
@@ -1,5 +1,5 @@
import CoreMessages from "../../../Messages/Messages.js";
import ApiMessages from "../../../../api/factory/messages/messages.js";
//import ApiMessages from "../../../../api/factory/messages/messages.js";
export default {
name: "TabMessages",
@@ -11,29 +11,50 @@ export default {
},
data(){
return {
endpoint: ApiMessages
//endpoint: ApiMessages
};
},
computed: {
prestudent_ids() {
if (this.modelValue.prestudent_id)
{
return [this.modelValue.prestudent_id];
}
return this.modelValue.map(e => e.prestudent_id);
},
person_ids() {
if (this.modelValue.person_id)
{
return [this.modelValue.person_id];
}
return this.modelValue.map(e => e.person_id);
},
},
template: `
<div class="stv-details-messages h-100 pb-3 overflow-hidden">
<template v-if="modelValue.prestudent_id">
<core-messages
ref="formc"
:endpoint="endpoint"
type-id="prestudent_id"
:id="modelValue.prestudent_id"
messageLayout="twoColumnsTableLeft"
open-mode="modal"
show-table
>
</core-messages>
</template>
<template v-else>
<h3><strong>No valid prestudent_id!</strong></h3>
<p>{{modelValue.anmerkungen}}</p>
</template>
<template v-if="prestudent_ids">
<core-messages
ref="formc"
type-id="prestudent_id"
:id="prestudent_ids"
messageLayout="twoColumnsTableLeft"
open-mode="modal"
show-table
>
</core-messages>
</template>
<template v-else >
<core-messages
ref="formc"
type-id="person_id"
:id="person_ids"
messageLayout="twoColumnsTableLeft"
open-mode="modal"
show-table
>
</core-messages>
</template>
</div>
`
};
@@ -169,6 +169,11 @@ export default {
{
this.localData.push(newEntry);
// reload tabulator mit tabulator method
if (this.$refs.table?.tabulator) {
this.$refs.table.tabulator.replaceData(this.localData);
}
this.$emit('setMobilityPurposeToNewMobility', {
zweck_code: this.formData.zweck_code,
});
@@ -198,7 +203,6 @@ export default {
<br>
<div class="override_filtercmpt_actions_style">
<core-filter-cmpt
ref="table"
:tabulator-options="tabulatorOptions"
@@ -157,6 +157,11 @@ export default {
{
this.localData.push(newEntry);
// reload tabulator mit tabulator method
if (this.$refs.table?.tabulator) {
this.$refs.table.tabulator.replaceData(this.localData);
}
this.$emit('setMobilitySupportToNewMobility', {
aufenthaltfoerderung_code: this.formData.aufenthaltfoerderung_code,
});
@@ -7,10 +7,14 @@ export default {
},
props: {
modelValue: Object,
config: {
type: Object,
default: {}
}
},
template: `
<div class="stv-details-multistatus h-100">
<tbl-multi-status :model-value="modelValue"></tbl-multi-status>
<tbl-multi-status :model-value="modelValue" :config="config"></tbl-multi-status>
</div>
`
}
@@ -31,6 +31,7 @@ export default {
show-tiny-mce
:visibleColumns="['titel','text','verfasser','bearbeiter','dokumente']"
@reload="$emit('update:suffix')"
tabulator-persistence-id="stv-notiz-2026011301"
>
</core-notiz>
@@ -30,6 +30,22 @@ export default {
from: 'hasAdminPermission',
default: false
},
hasZGVBakkPermission: {
from: 'hasZGVBakkPermission',
default: []
},
hasZGVMasterPermission: {
from: 'hasZGVMasterPermission',
default: []
},
hasZGVDoctorPermission: {
from: 'hasZGVDoctorPermission',
default: []
},
hasBismeldenPermission: {
from: 'hasBismeldenPermission',
default: false
},
currentSemester: {
from: 'currentSemester',
required: true
@@ -73,6 +89,15 @@ export default {
computed: {
deltaLength() {
return Object.keys(this.deltaArray).length;
},
disableZgvBakk: function() {
return !this.hasZGVBakkPermission.includes(this.modelValue.studiengang_kz.toString());
},
disableZgvMaster: function() {
return !this.hasZGVMasterPermission.includes(this.modelValue.studiengang_kz.toString());
},
disableZgvDoctor: function() {
return !this.hasZGVDoctorPermission.includes(this.modelValue.studiengang_kz.toString());
}
},
watch: {
@@ -106,7 +131,7 @@ export default {
},
methods: {
loadPrestudent() {
async loadPrestudent() {
return this.$api
.call(ApiStvPrestudent.get(this.modelValue.prestudent_id, this.currentSemester))
.then(result => result.data)
@@ -154,8 +179,8 @@ export default {
)
},
},
created() {
this.loadPrestudent();
async created() {
await this.loadPrestudent();
this.$api
.call(ApiStvPrestudent.getBezeichnungZGV())
.then(result => result.data)
@@ -273,6 +298,7 @@ export default {
dropdown
name="zgv_code"
@complete="filterZgvs"
:disabled="disableZgvBakk"
>
<template #option="slotProps">
<div
@@ -336,6 +362,7 @@ export default {
dropdown
name="zgvmas_code"
@complete="filterMasterZgvs"
:disabled="disableZgvMaster"
>
<template #option="slotProps">
<div
@@ -400,6 +427,7 @@ export default {
dropdown
name="zgvdoktor_code"
@complete="filterDoktorZgvs"
:disabled="disableZgvDoctor"
>
<template #option="slotProps">
<div
@@ -601,6 +629,7 @@ export default {
type="checkbox"
v-model="data.bismelden"
name="bismelden"
:disabled="!hasBismeldenPermission"
>
</form-input>
</div>
@@ -51,7 +51,8 @@ export default{
}
},
props: {
modelValue: Object
modelValue: Object,
config: Object,
},
data() {
return {
@@ -175,15 +176,18 @@ export default{
const data = cell.getData();
let button = document.createElement('button');
button.className = 'btn btn-outline-secondary btn-action';
button.innerHTML = '<i class="fa fa-forward"></i>';
button.title = this.$p.t('ui', 'btn_statusVorruecken');
button.addEventListener('click', () =>
this.actionAdvanceStatus(data.status_kurzbz, data.studiensemester_kurzbz, data.ausbildungssemester)
);
if (!['Student', 'Diplomand', 'Unterbrecher'].includes(data.status_kurzbz))
button.disabled = true;
container.append(button);
if (this.config?.showStatusVorruecken !== false)
{
button.className = 'btn btn-outline-secondary btn-action';
button.innerHTML = '<i class="fa fa-forward"></i>';
button.title = this.$p.t('ui', 'btn_statusVorruecken');
button.addEventListener('click', () =>
this.actionAdvanceStatus(data.status_kurzbz, data.studiensemester_kurzbz, data.ausbildungssemester)
);
if (!['Student', 'Diplomand', 'Unterbrecher'].includes(data.status_kurzbz))
button.disabled = true;
container.append(button);
}
button = document.createElement('button');
button.className = 'btn btn-outline-secondary btn-action';
@@ -203,8 +207,8 @@ export default{
button.addEventListener('click', () =>
this.actionEditStatus(data.status_kurzbz, data.studiensemester_kurzbz, data.ausbildungssemester)
);
if (this.dataMeldestichtag && this.dataMeldestichtag > data.datum && !this.hasPermissionToSkipStatusCheck)
button.disabled = true;
/* if (this.dataMeldestichtag && this.dataMeldestichtag > data.datum && !this.hasPermissionToSkipStatusCheck)
button.disabled = true;*/
container.append(button);
button = document.createElement('button');
@@ -69,10 +69,13 @@ export default {
final: true,
anmerkung: null
},
studiensemester: null,
arrTypen: [],
arrFirmen: [],
arrLvs: [],
arrNoten: [],
arrStudiensemester: [],
additional_lehrveranstaltung_id: null,
filteredFirmen: [],
abortController: {
firma: null
@@ -103,7 +106,11 @@ export default {
this.formData.anmerkung = null;
this.$refs.formDetails.clearValidation();
},
getFormData(statusNew, studiensemester_kurzbz, additional_lehrveranstaltung_id) {
getFormData(newProjektarbeit, studiensemester_kurzbz, additional_lehrveranstaltung_id) {
this.additional_lehrveranstaltung_id = additional_lehrveranstaltung_id;
this.studiensemester = studiensemester_kurzbz || this.defaultSemester;
this.newProjektarbeit = newProjektarbeit;
this.$api
.call(ApiStvProjektarbeit.getTypenProjektarbeit())
@@ -112,18 +119,7 @@ export default {
})
.catch(this.$fhcAlert.handleSystemError);
this.$api
.call(ApiStvProjektarbeit.getLehrveranstaltungen(
this.student.uid,
statusNew ? this.student.studiengang_kz : null,
studiensemester_kurzbz ?? this.defaultSemester,
additional_lehrveranstaltung_id
))
.then(result => {
this.arrLvs = result.data
}
)
.catch(this.$fhcAlert.handleSystemError);
this.getLehrveranstaltungen();
this.$api
.call(ApiStvProjektarbeit.getNoten())
@@ -132,7 +128,14 @@ export default {
})
.catch(this.$fhcAlert.handleSystemError);
if (statusNew) this.resetForm();
this.$api
.call(ApiStvProjektarbeit.getStudiensemester())
.then(result => {
this.arrStudiensemester = result.data;
})
.catch(this.$fhcAlert.handleSystemError);
if (this.newProjektarbeit) this.resetForm();
},
loadProjektarbeit(projektarbeit_id) {
@@ -178,9 +181,30 @@ export default {
this.filteredFirmen = result.data;
});
},
getLehrveranstaltungen() {
return this.$api
.call(ApiStvProjektarbeit.getLehrveranstaltungen(
this.student.uid,
this.newProjektarbeit ? this.student.studiengang_kz : null,
this.studiensemester,
this.additional_lehrveranstaltung_id
))
.then(result => {
this.arrLvs = result.data
}
)
.catch(this.$fhcAlert.handleSystemError);
},
lvChanged(event) {
this.formData.lehreinheit_id = null;
},
studiensemesterChanged() {
this.formData.lehreinheit_id = null;
this.getLehrveranstaltungen();
},
gesperrtBisChanged(newSperrdatum) {
this.formData.freigegeben = newSperrdatum == null || newSperrdatum == '';
},
// enrich and modify data before sending
getPreparedFormData() {
let preparedFormData = JSON.parse(JSON.stringify(this.formData)); // deep copy
@@ -281,7 +305,7 @@ export default {
<div class="row mb-3">
<form-input
container-class="stv-details-projektarbeit-lv"
container-class="stv-details-projektarbeit-lv col-10"
:label="$p.t('projektarbeit', 'lehrveranstaltung')"
type="select"
v-model="formData.lehrveranstaltung_id"
@@ -297,6 +321,23 @@ export default {
{{lv.bezeichnung + (lv.orgform_kurzbz ? ' ' + lv.orgform_kurzbz : '') + ' (' + lv.semester + ' Sem) ID: ' + lv.lehrveranstaltung_id}}
</option>
</form-input>
<form-input
container-class="col-2"
:label="$p.t('lehre', 'studiensemester')"
type="select"
v-model="studiensemester"
name="studiensemester"
@change="studiensemesterChanged"
>
<option :value="null"> -- {{$p.t('fehlermonitoring', 'keineAuswahl')}} -- </option>
<option
v-for="sem in arrStudiensemester"
:key="sem.studiensemester_kurzbz"
:value="sem.studiensemester_kurzbz"
>
{{sem.studiensemester_kurzbz}}
</option>
</form-input>
</div>
<div class="row mb-3">
@@ -362,6 +403,7 @@ export default {
format="dd.MM.yyyy"
model-type="yyyy-MM-dd"
name="gesperrtbis"
@update:model-value="gesperrtBisChanged"
>
</form-input>
<div class="col-4">
@@ -47,16 +47,25 @@ export default {
{
event: 'tableBuilt',
handler: async() => {
await this.$p.loadCategory(['global', 'person', 'stv', 'ui', 'projektarbeit']);
await this.$p.loadCategory(['global', 'person', 'lehre', 'stv', 'ui', 'projektarbeit']);
let cm = this.$refs.table.tabulator.columnManager;
cm.getColumnByField('projekttyp_kurzbz').component.updateDefinition({
title: this.$p.t('projektarbeit', 'typ_kurzbz')
});
cm.getColumnByField('bezeichnung').component.updateDefinition({
title: this.$p.t('projektarbeit', 'typ')
});
cm.getColumnByField('studiensemester_kurzbz').component.updateDefinition({
title: this.$p.t('lehre', 'studiensemester')
});
cm.getColumnByField('titel').component.updateDefinition({
title: this.$p.t('projektarbeit', 'titel')
});
cm.getColumnByField('note').component.updateDefinition({
title: this.$p.t('projektarbeit', 'gesamtnote')
});
cm.getColumnByField('beginn').component.updateDefinition({
title: this.$p.t('projektarbeit', 'beginn')
});
@@ -78,6 +87,12 @@ export default {
cm.getColumnByField('firma_id').component.updateDefinition({
title: this.$p.t('projektarbeit', 'firmaId')
});
cm.getColumnByField('abgabedatum').component.updateDefinition({
title: this.$p.t('projektarbeit', 'abgabeEndupload')
});
cm.getColumnByField('actions').component.updateDefinition({
title: this.$p.t('global', 'aktionen')
});
}
},
],
@@ -101,6 +116,7 @@ export default {
{title: "Typ Kurzbz", field: "projekttyp_kurzbz", visible: false},
{title: "Studiensemester", field: "studiensemester_kurzbz"},
{title: "Titel", field: "titel"},
{title: "Gesamtnote", field: "note"},
{
title: "Abgabe Enduplad",
field: "abgabedatum",
@@ -183,6 +199,7 @@ export default {
{title: "Anmerkung", field: "anmerkung", visible: false},
{title: "Lehreinheit ID", field: "lehreinheit_id", visible: false},
{title: "Student UID", field: "student_uid", visible: false},
{title: "Projektbetreuer", field: "projektbetreuer"},
{
title:"Final",
field:"final",
@@ -258,7 +275,7 @@ export default {
this.statusNew = true;
this.editedProjektarbeit = null;
this.toggleMenu('details');
this.$refs.projektarbeitDetails.getFormData(this.statusNew);
this.$refs.projektarbeitDetails.getFormData(this.statusNew, null, null);
this.$refs.projektarbeitModal.show();
},
actionEditProjektarbeit() {
@@ -388,7 +405,7 @@ export default {
<div class="tab-pane fade show" :class="activeTab == 'betreuer' ? 'active' : ''" id="betreuer" role="tabpanel" aria-labelledby="betreuer-tab">
<div class="row">
<div class="col-12">
<projektbetreuer ref="projektbetreuer" :config="config"></projektbetreuer>
<projektbetreuer ref="projektbetreuer" :config="config" @betreuer-saved="reload"></projektbetreuer>
</div>
</div>
</div>
@@ -20,6 +20,7 @@ export default {
Contact,
Vertrag
},
emits: ['betreuerSaved'],
provide() {
return {
configShowVertragsdetails: this.config.showVertragsdetails
@@ -115,7 +116,7 @@ export default {
frozen: true
},
],
layout: 'fitDataStretchFrozen',
layout: 'fitData',
layoutColumnsOnNewData: false,
height: 'auto',
minHeight: '100',
@@ -125,13 +126,49 @@ export default {
persistence:{
columns: true, //persist column layout
},
persistenceID: 'stv-details-projektbetreuer-2025112401'
persistenceID: 'stv-details-projektbetreuer-2025121201'
},
tabulatorEvents: [
{
event: 'tableBuilt',
handler: async() => {
await this.$p.loadCategory(['global', 'person', 'stv', 'projektarbeit', 'ui']);
await this.$p.loadCategory(['global', 'person', 'lehre', 'stv', 'projektarbeit', 'ui']);
let cm = this.$refs.projektbetreuerTable.tabulator.columnManager;
cm.getColumnByField('nachname').component.updateDefinition({
title: this.$p.t('person', 'nachname')
});
cm.getColumnByField('vorname').component.updateDefinition({
title: this.$p.t('person', 'vorname')
});
cm.getColumnByField('note').component.updateDefinition({
title: this.$p.t('projektarbeit', 'note')
});
cm.getColumnByField('punkte').component.updateDefinition({
title: this.$p.t('projektarbeit', 'punkte')
});
cm.getColumnByField('stunden').component.updateDefinition({
title: this.$p.t('projektarbeit', 'stunden')
});
cm.getColumnByField('stundensatz').component.updateDefinition({
title: this.$p.t('projektarbeit', 'stundensatz')
});
cm.getColumnByField('betreuerart_kurzbz').component.updateDefinition({
title: this.$p.t('projektarbeit', 'betreuerart_kurzbz')
});
cm.getColumnByField('person_id').component.updateDefinition({
title: this.$p.t('person', 'person_id')
});
cm.getColumnByField('vertrag_id').component.updateDefinition({
title: this.$p.t('projektarbeit', 'vertrag_id')
});
cm.getColumnByField('projektarbeit_id').component.updateDefinition({
title: this.$p.t('projektarbeit', 'projektarbeit_id')
});
cm.getColumnByField('actions').component.updateDefinition({
title: this.$p.t('global', 'actions')
});
// Force layout recalculation for handling overflow text
this.$refs.projektbetreuerTable.tabulator.redraw(true);
@@ -152,6 +189,7 @@ export default {
stunden: null,
stundensatz: null
},
defaultStundensatz: null,
newMode: false,
editMode: false,
initialFormData: null,
@@ -171,53 +209,49 @@ export default {
},
methods: {
actionNewProjektbetreuer() {
this.resetForm();
this.newMode = !this.newMode;
this.editMode = false;
this.resetForm();
this.defaultStundensatz = this.config.defaultProjektbetreuerStundensatz;
this.captureFormData();
},
actionEditProjektbetreuer(projektarbeit_id, person_id, betreuerart_kurzbz) {
this.editMode = true;
this.newMode = false;
this.$api
.call(ApiStvProjektbetreuer.getDefaultStundensaetze(person_id, this.studiensemester_kurzbz))
.then(result => {
this.resetForm();
this.resetForm();
this.getDefaultStundensaetze(person_id).finally(() => {
// get betreuer from tabulator list
let projektbetreuerListe = this.$refs.projektbetreuerTable.tabulator.getData();
const idx = projektbetreuerListe.findIndex(
betr =>
betr.person_id === person_id &&
betr.projektarbeit_id === projektarbeit_id &&
betr.betreuerart_kurzbz === betreuerart_kurzbz
);
// get betreuer from tabulator list
let projektbetreuerListe = this.$refs.projektbetreuerTable.tabulator.getData();
const idx = projektbetreuerListe.findIndex(
betr =>
betr.person_id === person_id &&
betr.projektarbeit_id === projektarbeit_id &&
betr.betreuerart_kurzbz === betreuerart_kurzbz
);
if (idx >= 0) { // if betreuer found
if (idx >= 0) { // if betreuer found
// set currently edited betreuer (deep copy)
this.formData = JSON.parse(JSON.stringify(projektbetreuerListe[idx]));
// set currently edited betreuer (deep copy)
this.formData = JSON.parse(JSON.stringify(projektbetreuerListe[idx]));
// set download link
if (this.formData.beurteilungDownloadLink !== null) this.beurteilungDownloadLink = this.formData.beurteilungDownloadLink;
// set download link
if (this.formData.beurteilungDownloadLink !== null) this.beurteilungDownloadLink = this.formData.beurteilungDownloadLink;
// set betreuer for autocomplete field
this.autocompleteSelectedBetreuer = {
person_id: this.formData.person_id,
name: this.formData.name,
vorname: this.formData.vorname,
nachname: this.formData.nachname,
vertrag_id: this.formData.vertrag_id
};
}
// set betreuer for autocomplete field
this.autocompleteSelectedBetreuer = {
person_id: this.formData.person_id,
name: this.formData.name,
vorname: this.formData.vorname,
nachname: this.formData.nachname,
vertrag_id: this.formData.vertrag_id
};
}
// set default stundensatz (if no other is set yet)
if (this.formData.stundensatz == null) this.formData.stundensatz = result.data;
// capture initial form data for detecting changes
this.captureFormData();
});
// capture initial form data for detecting changes
this.captureFormData();
})
.catch(this.$fhcAlert.handleSystemError);
},
actionDeleteProjektbetreuer(betreuer_id, projektarbeit_id, person_id, betreuerart_kurzbz) {
this.$fhcAlert
@@ -239,6 +273,7 @@ export default {
// default Stundensätze from config
this.defaultFormDataValues.stunden = this.getDefaultStunden(projekttyp_kurzbz);
this.defaultFormDataValues.stundensatz = this.config.defaultProjektbetreuerStundensatz;
this.defaultStundensatz = this.config.defaultProjektbetreuerStundensatz;
// get other initial data
this.$api
@@ -271,7 +306,7 @@ export default {
})
.catch(this.$fhcAlert.handleSystemError);
} else {
this.emptyBetreuer();
this.emptyBetreuerList();
}
},
saveProjektbetreuer() {
@@ -282,6 +317,7 @@ export default {
this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSave'));
this.getProjektbetreuer(this.projektarbeit_id, this.studiensemester_kurzbz);
this.resetModes();
this.$emit('betreuerSaved');
})
.catch(this.$fhcAlert.handleSystemError);
},
@@ -297,11 +333,12 @@ export default {
this.filteredBetreuer = result.data;
});
},
emptyBetreuer() {
emptyBetreuerList() {
this.$refs.projektbetreuerTable.tabulator.clearData();
},
resetForm() {
this.formData = this.getDefaultFormData();
const defaultFormData = this.getDefaultFormData();
this.formData = defaultFormData;
if (this.beurteilungDownloadLink !== null) this.beurteilungDownloadLink = '';
this.autocompleteSelectedBetreuer = null;
this.initialFormData = null;
@@ -360,28 +397,24 @@ export default {
},
setDefaultStunden(projekttyp_kurzbz) {
this.projekttyp_kurzbz = projekttyp_kurzbz;
// if form data has not already been modified by user, set the default stunden
if (!this.formDataModified()) {
// set default stunden if not in edit mode (so hours of editen person are not overwritten)
if (!this.editMode)
{
let defaultStunden = this.getDefaultStunden(projekttyp_kurzbz);
// adapt initial form data so it does not count as modified
if (this.initialFormData) this.initialFormData.stunden = defaultStunden;
// set default Stunden
this.formData.stunden = defaultStunden;
}
},
// check if form data has been modified since initial data has been captured
formDataModified() {
if (this.autocompleteSelectedBetreuer != null) return true;
for (const prop in this.initialFormData) {
if (typeof this.formData[prop] == 'undefined') return true;
if (this.formData[prop] != this.initialFormData[prop]) return true;
}
return false;
getDefaultStundensaetze(person_id) {
return this.$api
.call(ApiStvProjektbetreuer.getDefaultStundensaetze(person_id, this.studiensemester_kurzbz))
.then(result => {
// set default stundensatz (if no other is set yet)
this.defaultStundensatz = result.data;
this.formData.stundensatz = result.data;
})
.catch(this.$fhcAlert.handleSystemError);
},
actionNewPerson() {
this.$refs.newPersonModal.reset();
this.$refs.newPersonModal.open();
},
actionKontaktdatenBearbeiten() {
@@ -395,12 +428,16 @@ export default {
.then(response => {
// set the new person in Betreuer autocomplete field
this.autocompleteSelectedBetreuer = response.data;
this.getDefaultStundensaetze(this.autocompleteSelectedBetreuer.person_id);
})
.catch(this.$fhcAlert.handleSystemError)
},
// disable fields which are dependent on Vertrag status
disableVertragFields(statusAkzeptiert) {
this.vertragFieldsDisabled = statusAkzeptiert;
},
onBetreuerSelected(ev) {
this.getDefaultStundensaetze(ev.value.person_id);
}
},
template: `
@@ -422,7 +459,7 @@ export default {
>
</core-filter-cmpt>
<form-form ref="formProjektbetreuer" v-show="betreuerFormOpened" @submit.prevent>
<form-form ref="formProjektbetreuer" v-show="betreuerFormOpened" class="mt-3" @submit.prevent >
<div class="row mb-3">
<form-input
container-class="stv-details-projektarbeit-betreuer"
@@ -433,6 +470,8 @@ export default {
name="person_id"
:suggestions="filteredBetreuer"
@complete="searchBetreuer"
@item-select="onBetreuerSelected"
@option-select="onBetreuerSelected"
:min-length="3"
:disabled="vertragFieldsDisabled"
>
@@ -502,7 +541,7 @@ export default {
container-class="stv-details-projektarbeit-stundensatz"
type="text"
name="stundensatz"
:label="$p.t('projektarbeit', 'stundensatz')"
:label="$p.t('projektarbeit', 'stundensatz') + (defaultStundensatz ? ' (Default ' + defaultStundensatz + ')' : '')"
:disabled="vertragFieldsDisabled"
v-model="formData.stundensatz"
>
@@ -91,7 +91,15 @@ export default{
layoutColumnsOnNewData: false,
height: 'auto',
index: 'pruefung_id',
persistenceID: 'stv-details-pruefung-list-2025112402'
persistenceID: 'stv-details-pruefung-list-2026012701',
persistence: {
sort: false,
columns: ["width", "visible", "frozen"],
filter: false,
headerFilter: false,
group: false,
page: false
}
},
tabulatorEvents: [
{
@@ -185,24 +185,10 @@ export default{
.then(result => this.statusgruende = result.data)
.catch(this.$fhcAlert.handleSystemError);
//TODO(Manu) check why it is/was hard coded
this.$api
.call(ApiStvStatus.getStati())
.then(result => this.stati = result.data)
.catch(this.$fhcAlert.handleSystemError);
/* this.stati = [
{ status_kurzbz: 'Interessent', bezeichnung: 'Interessent'},
{ status_kurzbz: 'Bewerber', bezeichnung: 'Bewerber'},
{ status_kurzbz: 'Aufgenommener', bezeichnung: 'Aufgenommener'},
{ status_kurzbz: 'Student', bezeichnung: 'Student'},
{ status_kurzbz: 'Unterbrecher', bezeichnung: 'Unterbrecher'},
{ status_kurzbz: 'Diplomand', bezeichnung: 'Diplomand'},
{ status_kurzbz: 'Incoming', bezeichnung: 'Incoming'},
{ status_kurzbz: 'Absolvent', bezeichnung: 'Absolvent'},
{ status_kurzbz: 'Abbrecher', bezeichnung: 'Abbrecher'},
{ status_kurzbz: 'Abgewiesener', bezeichnung: 'Abgewiesener'},
{ status_kurzbz: 'Wartender', bezeichnung: 'Wartender'}
];*/
},
template: `
<bs-modal class="stv-status-modal" ref="modal" dialog-class="modal-dialog-scrollable">
@@ -220,7 +206,7 @@ export default{
<p v-if="bisLocked && isStatusBeforeStudent">
<b>{{$p.t('bismeldestichtag', 'info_MeldestichtagStatusgrundSemester')}}</b>
</p>
<form-input
container-class="mb-3"
type="select"
@@ -353,7 +339,6 @@ export default{
v-model="formData.anmerkung"
name="anmerkung"
:label="$p.t('global/anmerkung')"
:disabled="bisLocked"
>
</form-input>
<form-input
@@ -495,9 +495,7 @@ export default {
:side-menu="false"
reload
:download="downloadConfig"
` + /* TODO(chris): Ausgeblendet für Testing
new-btn-show
*/`
:new-btn-label="$p.t('stv/action_new')"
@click:new="actionNewPrestudent"
@table-built="translateTabulator"
@@ -6,13 +6,18 @@ import FormInput from '../../../Form/Input.js';
import accessibility from '../../../../directives/accessibility.js';
import ApiStvStudents from '../../../../api/factory/stv/students.js';
import ApiStvAddress from '../../../../api/factory/stv/kontakt/address.js';
import ApiStudiensemester from '../../../../api/factory/studiensemester.js';
import ApiStudienplan from '../../../../api/factory/studienplan.js';
var _uuid = 0;
const FORMDATA_DEFAULT = {
address: {
func: 1,
checked: true,
nation: 'A'
},
vorname: '',
nachname: '',
geburtsnation: 'A',
staatsbuergerschaft: 'A',
ausbildungssemester: 1,
@@ -35,14 +40,14 @@ export default {
],
emits: ['saved'],
props: {
personOnly: Boolean,
personOnly: Boolean,
studiengangKz: Number,
studiensemesterKurzbz: String
},
data() {
return {
places: [],
formData: FORMDATA_DEFAULT,
formData: null,
suggestions: {},
person: null,
semester: [],
@@ -60,7 +65,7 @@ export default {
return this.formData;
},
orte() {
return this.places.filter(ort => ort.name == this.formData.address.gemeinde);
return this.places.filter(ort => ort.name == this.formData?.address.gemeinde);
},
gemeinden() {
return Object.values(this.places.reduce((res,place) => {
@@ -70,7 +75,7 @@ export default {
},
formDataStg: {
get() {
return this.formData.studiengang_kz !== undefined ? this.formData.studiengang_kz : this.studiengangKz;
return this.formData?.studiengang_kz !== undefined ? this.formData?.studiengang_kz : this.studiengangKz;
},
set(v) {
this.formData.studiengang_kz = v;
@@ -78,7 +83,7 @@ export default {
},
formDataSem: {
get() {
return this.formData.studiensemester_kurzbz !== undefined ? this.formData.studiensemester_kurzbz : this.studiensemesterKurzbz;
return this.formData?.studiensemester_kurzbz !== undefined ? this.formData?.studiensemester_kurzbz : this.studiensemesterKurzbz;
},
set(v) {
this.formData.studiensemester_kurzbz = v;
@@ -98,10 +103,10 @@ export default {
this.$refs.modal.show();
},
reset() {
this.formData = FORMDATA_DEFAULT;
this.formData = JSON.parse(JSON.stringify(FORMDATA_DEFAULT));
this.person = null;
this.suggestions = [];
this.$refs.form.clearValidation();
if (this.$refs.form) this.$refs.form.clearValidation();
},
loadSuggestions() {
if (this.abortController.suggestions)
@@ -112,10 +117,10 @@ export default {
this.abortController.suggestions = new AbortController();
this.$api
.call(ApiStvStudents.check({
vorname: this.formData.vorname,
nachname: this.formData.nachname,
gebdatum: this.formData.gebdatum
.call(ApiStvStudents.getPerson({
vorname: this.formData?.vorname,
nachname: this.formData?.nachname,
gebdatum: this.formData?.gebdatum
}), {
signal: this.abortController.suggestions.signal
})
@@ -134,41 +139,40 @@ export default {
loadPlaces() {
if (this.abortController.places)
this.abortController.places.abort();
if (this.formData.address.nation != 'A' || !this.formData.address.plz)
if (this.formData?.address?.nation != 'A' || !this?.formData?.address?.plz)
return;
this.abortController.places = new AbortController();
this.$refs.form
.get(
'api/frontend/v1/stv/address/getPlaces/' + this.formData.address.plz,
undefined,
{
signal: this.abortController.places.signal
}
)
.then(result => {
this.places = result.data
})
.catch(error => {
if (error.code != "ERR_CANCELED")
window.setTimeout(this.loadPlaces, 100);
else
this.$fhcAlert.handleSystemError(error);
});
this.$refs.form.call(
ApiStvAddress.getPlaces(this.formData?.address.plz)
//~ undefined,
//~ {
//~ signal: this.abortController.places.signal
//~ }
)
.then(result => {
this.places = result.data
})
.catch(error => {
if (error.code != "ERR_CANCELED")
window.setTimeout(this.loadPlaces, 100);
else
this.$fhcAlert.handleSystemError(error);
});
},
loadStudienplaene() {
if (this.formDataStg)
CoreRESTClient
.post('components/stv/studienplan/get', {
studiengang_kz: this.formDataStg,
studiensemester_kurzbz: this.formDataSem,
ausbildungssemester: this.formData.ausbildungssemester,
orgform_kurzbz: this.formData.orgform_kurzbz
})
.then(result => CoreRESTClient.getData(result.data) || [])
if (this.formDataStg) {
this.$api
.call(ApiStudienplan.getStudienplaeneBySemester(
this.formDataStg,
this.formDataSem,
this.formData?.ausbildungssemester,
this.formData?.orgform_kurzbz
))
.then(result => result.data || [])
.then(result => {
this.studienplaene = result;
if (this.formData.studienplan_id !== '' && !this.studienplaene.filter(plan => plan.studienplan_id == this.formData.studienplan_id).length)
if (this.formData?.studienplan_id !== '' && !this.studienplaene.filter(plan => plan.studienplan_id == this.formData?.studienplan_id).length)
this.formData.studienplan_id = '';
})
.catch(error => {
@@ -179,12 +183,13 @@ export default {
if (error.code != "ERR_CANCELED")
window.setTimeout(this.loadStudienplaene, 100);
})
}
},
changeAddressNation(e) {
if (this.formData['geburtsnation'] == this.formData['address']['nation'])
this.formData['geburtsnation'] = e.target.value;
if (this.formData['staatsbuergerschaft'] == this.formData['address']['nation'])
this.formData['staatsbuergerschaft'] = e.target.value;
if (this.formData.geburtsnation == this.formData?.address.nation)
this.formData.geburtsnation = e.target.value;
if (this.formData.staatsbuergerschaft == this.formData?.address.nation)
this.formData.staatsbuergerschaft = e.target.value;
this.loadPlaces();
},
send(e) {
@@ -213,29 +218,38 @@ export default {
setPerson(suggestion)
{
this.person = suggestion;
this.formData.address.func = -1;
this.formData.address.checked = false;
},
dateFormatter(val)
{
if (!val)
return '';
let date = new Date(val);
return date.toLocaleDateString('de-AT', {
"day": "2-digit",
"month": "2-digit",
"year": "numeric"
});
}
},
created() {
this.uuid = _uuid++;
CoreRESTClient
.get('components/stv/Studiensemester')
.then(result => CoreRESTClient.getData(result.data) || [])
.then(result => {
this.semester = result;
})
.catch(this.$fhcAlert.handleSystemError);
this.reset();
this.$api.call(ApiStudiensemester.getAll())
.then(result => result.data || [])
.then(result => {
this.semester = result;
})
.catch(this.$fhcAlert.handleSystemError);
},
template: `
<fhc-form ref="form" class="stv-list-new" @submit.prevent="send">
<bs-modal ref="modal" dialog-class="modal-lg modal-dialog-scrollable" @hidden-bs-modal="reset">
<bs-modal ref="modal" dialog-class="modal-lg modal-dialog-scrollable" style="min-height: 500px" @hidden-bs-modal="reset">
<template #title>
{{ personOnly ? $p.t('person', 'personAnlegen') : $p.t('lehre', 'interessentAnlegen') }}
</template>
<template #default>
<form-validation></form-validation>
<template v-if="person === null">
<div class="row">
<div class="col-sm-4 mb-3">
@@ -275,16 +289,25 @@ export default {
@update:model-value="loadSuggestions"
text-input
auto-apply
no-today
no-today
:enable-time-picker="false"
format="dd.MM.yyyy"
:teleport="true"
>
</form-input>
</div>
</div>
<!-- TODO(chris): more details -->
<table class="table caption-top table-striped table-hover">
<table class="table caption-top table-striped table-hover" >
<caption>{{ $p.t('person', 'personExistiertPruefung') }}</caption>
<thead v-if="suggestions?.length">
<th>{{ $p.t('person', 'nachname') }}</th>
<th>{{ $p.t('person', 'vorname') }}</th>
<th>{{ $p.t('person', 'weitereVornamen') }}</th>
<th>{{ $p.t('person', 'geburtsdatum') }}</th>
<th>{{ $p.t('person', 'geschlecht') }}</th>
<th>{{ $p.t('person', 'adresse') }}</th>
<th>Status</th>
</thead>
<tbody>
<tr
v-for="(suggestion, index) in suggestions"
@@ -293,8 +316,21 @@ export default {
@click="(index == 2) ? suggestions.shift() : setPerson(suggestion)"
v-accessibility:tab.vertical
>
<td>{{suggestion.vorname + ' ' + suggestion.nachname}}</td>
<td></td>
<td>{{ suggestion.nachname }}</td>
<td>{{ suggestion.vorname }}</td>
<td>{{ suggestion.vornamen }}</td>
<td>{{ dateFormatter(suggestion.gebdatum) }}</td>
<td>{{ suggestion.geschlecht_bezeichnung }}</td>
<td>
<div v-for="adresse in suggestion.adressen">
{{ (adresse.plz ?? '') + (adresse.plz && adresse.ort ? ' ' : '') + (adresse.ort ?? '') + (adresse.ort && adresse.strasse ? ', ' : '') + (adresse.strasse ?? '') }}
</div>
</td>
<td>
<div v-for="status in suggestion.status">
{{ status.status_kurzbz + " " + status.studiengang_kuerzel }}
</div>
</td>
</tr>
</tbody>
</table>
@@ -418,23 +454,22 @@ export default {
</form-input>
</div>
</div>
<div class="row">
<div class="col-sm-6 mb-3">
<form-input
type="select"
id="stv-list-new-address-func"
name="address[func]"
v-model="formData['address']['func']"
:label="$p.t('person', 'adresseHinzufuegen')"
type="checkbox"
id="stv-new-adresse"
name="adresseChecked"
v-model="formData['address']['checked']"
value="true"
>
<option value="-1" v-if="person">{{ $p.t('person', 'bestehendeAdresseUeberschreiben') }}</option>
<option value="1">{{ $p.t('person', 'adresseHinzufuegen') }}</option>
<option value="0">{{ $p.t('person', 'adresseNichtAnlegen') }}</option>
</form-input>
</div>
</div>
<fieldset v-if="formData['address']['func'] != 0">
<fieldset v-if="formData['address']['checked']">
<hr>
<legend>Adresse</legend>
<div class="row">
<div class="col-sm-4 mb-3">
@@ -519,6 +554,7 @@ export default {
</form-input>
</div>
</div>
<hr>
</fieldset>
<div class="row">
@@ -644,7 +680,7 @@ export default {
name="ausbildungssemester"
v-model="formData['ausbildungssemester']"
:disabled="formData['incoming']"
@input="loadStudienplaene"
@change="loadStudienplaene"
>
<option v-for="sem in Array.from({length:8}).map((u,i) => i+1)" :key="sem" :value="sem">{{sem}}. Semester</option>
</form-input>
@@ -658,7 +694,7 @@ export default {
id="stv-list-new-orgform_kurzbz"
name="orgform_kurzbz"
v-model="formData['orgform_kurzbz']"
@input="loadStudienplaene"
@change="loadStudienplaene"
>
<option value="">-- keine Auswahl --</option>
<option v-for="orgform in lists.orgforms" :key="orgform.orgform_kurzbz" :value="orgform.orgform_kurzbz">{{orgform.bezeichnung}}</option>
@@ -679,7 +715,7 @@ export default {
</div>
<div class="row">
<div class="col-10 mb-3">
<div class="form-check">
<div>
<form-input
label="Incoming"
type="checkbox"
@@ -696,7 +732,7 @@ export default {
</template>
</template>
<template #footer>
<button v-if="person !== null" type="button" class="btn btn-secondary" @click="person = null; formData.address.func = 1;"><i class="fa fa-chevron-left"></i>{{ $p.t('ui', 'zurueck') }}</button>
<button v-if="person !== null" type="button" class="btn btn-secondary" @click="person = null; formData.address.checked = true;"><i class="fa fa-chevron-left"></i>{{ $p.t('ui', 'zurueck') }}</button>
<button type="submit" class="btn btn-primary">{{ person === null || personOnly ? $p.t('person', 'personAnlegen') : $p.t('lehre', 'interessentAnlegen') }}</button>
</template>
</bs-modal>
@@ -13,7 +13,7 @@ function parseFilterExpression(expression)
andParts.forEach(term => {
const comparisonMatch = term.match(/^(<=|>=|<|>|=|!=)\s*(\d+(?:[.,]\d+)?)$/);
const comparisonMatch = term.match(/^(<=|>=|<|>|=|!=)\s*(-?\d+(?:[.,]\d+)?)$/);
if (comparisonMatch)
{