mirror of
https://github.com/FH-Complete/FHC-Core.git
synced 2026-07-25 08:34:29 +00:00
gui fuer kalender sync hinzugefuegt und syncjob angepasst
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* Copyright (C) 2026 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 {
|
||||
getSyncs(studiensemester_kurzbz) {
|
||||
return {
|
||||
method: 'get',
|
||||
url: 'api/frontend/v1/tempus/KalenderSync/getSyncs',
|
||||
params: { studiensemester_kurzbz }
|
||||
};
|
||||
},
|
||||
loadSync(kalender_syncstatus_id) {
|
||||
return {
|
||||
method: 'get',
|
||||
url: 'api/frontend/v1/tempus/KalenderSync/loadSync',
|
||||
params: { kalender_syncstatus_id }
|
||||
};
|
||||
},
|
||||
getSyncStatus() {
|
||||
return {
|
||||
method: 'get',
|
||||
url: 'api/frontend/v1/tempus/KalenderSync/getSyncStatus',
|
||||
};
|
||||
},
|
||||
add(formData) {
|
||||
return {
|
||||
method: 'post',
|
||||
url: 'api/frontend/v1/tempus/KalenderSync/add',
|
||||
params: { formData }
|
||||
};
|
||||
},
|
||||
delete(kalender_syncstatus_id) {
|
||||
return {
|
||||
method: 'post',
|
||||
url: 'api/frontend/v1/tempus/KalenderSync/delete',
|
||||
params: { kalender_syncstatus_id }
|
||||
};
|
||||
},
|
||||
start(formData) {
|
||||
return {
|
||||
method: 'post',
|
||||
url: 'api/frontend/v1/tempus/KalenderSync/start',
|
||||
params: { formData }
|
||||
};
|
||||
},
|
||||
updateSync(formData) {
|
||||
return {
|
||||
method: 'post',
|
||||
url: 'api/frontend/v1/tempus/KalenderSync/updateSync',
|
||||
params: { formData }
|
||||
};
|
||||
},
|
||||
getStudienplan(oe_kurzbz, studiensemester_kurzbz, ausbildungssemester) {
|
||||
return {
|
||||
method: 'get',
|
||||
url: 'api/frontend/v1/tempus/KalenderSync/getStudienplan',
|
||||
params: { oe_kurzbz, studiensemester_kurzbz, ausbildungssemester }
|
||||
};
|
||||
},
|
||||
|
||||
getMaxSemester(studiengang_kzs) {
|
||||
return {
|
||||
method: 'post',
|
||||
url: 'api/frontend/v1/stv/status/getMaxSemester/',
|
||||
params: { studiengang_kzs }
|
||||
};
|
||||
},
|
||||
|
||||
};
|
||||
@@ -16,6 +16,7 @@
|
||||
*/
|
||||
|
||||
import FhcTempus from "../components/Tempus/Tempus.js";
|
||||
import FhcTempusSync from "../components/Tempus/TempusSync.js";
|
||||
|
||||
import Phrasen from "../plugins/Phrasen.js";
|
||||
import {capitalize} from "../helpers/StringHelpers.js";
|
||||
@@ -27,6 +28,7 @@ const router = VueRouter.createRouter({
|
||||
history: VueRouter.createWebHistory(),
|
||||
routes: [
|
||||
{ path: `/${ciPath}/Tempus`, component: FhcTempus },
|
||||
{ path: `/${ciPath}/Tempus/sync`, component: FhcTempusSync },
|
||||
]
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,340 @@
|
||||
import BsModal from '../Bootstrap/Modal.js';
|
||||
import CoreForm from '../Form/Form.js';
|
||||
import FormValidation from '../Form/Validation.js';
|
||||
import FormInput from '../Form/Input.js';
|
||||
|
||||
import ApiTempusSync from '../../api/factory/tempus/sync.js';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
BsModal,
|
||||
CoreForm,
|
||||
FormValidation,
|
||||
FormInput
|
||||
},
|
||||
props: {
|
||||
config: Object,
|
||||
stsem_kurzbz: String
|
||||
},
|
||||
emits: [
|
||||
'saved'
|
||||
],
|
||||
data() {
|
||||
return {
|
||||
mode: 'new',
|
||||
formData: {},
|
||||
studienplaene: [],
|
||||
max_semester: null,
|
||||
syncStati: []
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
semester() {
|
||||
if (!this.max_semester)
|
||||
return [];
|
||||
|
||||
return Array.from({length: this.max_semester}, (_, index) => index);
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
'formData.oe_kurzbz'(newOrganisation) {
|
||||
if (!newOrganisation) {
|
||||
this.max_semester = null;
|
||||
this.studienplaene = [];
|
||||
return;
|
||||
}
|
||||
|
||||
let filtered_org = this.config.organisationen.filter(org => org.oe_kurzbz === newOrganisation)[0];
|
||||
|
||||
if (filtered_org && filtered_org.studiengang_kz)
|
||||
this.getSemester(filtered_org.studiengang_kz);
|
||||
else
|
||||
this.max_semester = null;
|
||||
|
||||
this.getStudienplan();
|
||||
},
|
||||
'formData.studiensemester_kurzbz'() {
|
||||
this.getStudienplan();
|
||||
},
|
||||
'formData.ausbildungssemester'() {
|
||||
this.getStudienplan();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
openNew() {
|
||||
this.$refs.modal.hide();
|
||||
|
||||
this.mode = 'new';
|
||||
this.max_semester = null;
|
||||
this.studienplaene = [];
|
||||
this.formData = {
|
||||
oe_kurzbz: null,
|
||||
studiensemester_kurzbz: this.stsem_kurzbz ?? null,
|
||||
datum_bis: null,
|
||||
studienplan_id: null,
|
||||
ausbildungssemester: null,
|
||||
sync_status_kurzbz: null,
|
||||
mail: false
|
||||
};
|
||||
|
||||
this.$refs.form.clearValidation()
|
||||
this.$refs.modal.show()
|
||||
},
|
||||
openEdit(entry) {
|
||||
if (!entry || entry.kalender_syncstatus_id === undefined || entry.kalender_syncstatus_id === null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.$refs.modal.hide();
|
||||
this.mode = 'edit';
|
||||
|
||||
this.$api
|
||||
.call(ApiTempusSync.loadSync(entry.kalender_syncstatus_id))
|
||||
.then(result => {
|
||||
this.formData = result.data;
|
||||
return this.$refs.form.clearValidation();
|
||||
})
|
||||
.then(() => this.$refs.modal.show())
|
||||
.catch(this.$fhcAlert.handleSystemError);
|
||||
},
|
||||
|
||||
openStart() {
|
||||
this.$refs.modal.hide();
|
||||
|
||||
this.mode = 'start';
|
||||
this.max_semester = null;
|
||||
this.studienplaene = [];
|
||||
this.formData = {
|
||||
oe_kurzbz: null,
|
||||
studiensemester_kurzbz: this.stsem_kurzbz ?? null,
|
||||
datum_bis: null,
|
||||
sync_status_kurzbz: null,
|
||||
studienplan_id: null,
|
||||
ausbildungssemester: null,
|
||||
mail: false
|
||||
};
|
||||
|
||||
this.$refs.form.clearValidation()
|
||||
this.$refs.modal.show()
|
||||
},
|
||||
getSemester(stg_kz) {
|
||||
this.$api.call(ApiTempusSync.getMaxSemester([stg_kz]))
|
||||
.then(response => response.data)
|
||||
.then(response => {
|
||||
this.max_semester = response;
|
||||
|
||||
let found = this.semester.filter(semester => semester === this.formData.ausbildungssemester);
|
||||
if (found.length === 0)
|
||||
this.formData.ausbildungssemester = null;
|
||||
})
|
||||
.catch(error => {
|
||||
this.$fhcAlert.handleSystemError(error);
|
||||
});
|
||||
},
|
||||
getStudienplan() {
|
||||
if (!this.formData.oe_kurzbz || !this.formData.studiensemester_kurzbz) {
|
||||
this.studienplaene = [];
|
||||
return;
|
||||
}
|
||||
|
||||
this.$api.call(ApiTempusSync.getStudienplan(
|
||||
this.formData.oe_kurzbz,
|
||||
this.formData.studiensemester_kurzbz,
|
||||
this.formData.ausbildungssemester ?? null
|
||||
))
|
||||
.then(response => response.data)
|
||||
.then(response => {
|
||||
this.studienplaene = response;
|
||||
let found = this.studienplaene.filter(plan => plan.studienplan_id === this.formData.studienplan_id);
|
||||
if (found.length === 0)
|
||||
this.formData.studienplan_id = null;
|
||||
})
|
||||
.catch(error => {
|
||||
this.$fhcAlert.handleSystemError(error);
|
||||
});
|
||||
},
|
||||
save() {
|
||||
if (this.mode === 'start')
|
||||
this.start();
|
||||
else if (this.mode === 'new')
|
||||
this.insert();
|
||||
else
|
||||
this.update();
|
||||
},
|
||||
insert() {
|
||||
this.$refs.form
|
||||
.call(ApiTempusSync.add(this.formData))
|
||||
.then(() => {
|
||||
this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSave'));
|
||||
this.$emit('saved');
|
||||
this.$refs.modal.hide();
|
||||
})
|
||||
.catch(this.$fhcAlert.handleSystemError);
|
||||
},
|
||||
update() {
|
||||
this.$refs.form
|
||||
.call(ApiTempusSync.updateSync(this.formData))
|
||||
.then(() => {
|
||||
this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSave'));
|
||||
this.$emit('saved');
|
||||
this.$refs.modal.hide();
|
||||
})
|
||||
.catch(this.$fhcAlert.handleSystemError);
|
||||
},
|
||||
start() {
|
||||
this.$refs.form
|
||||
.call(ApiTempusSync.start(this.formData))
|
||||
.then(() => {
|
||||
this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSave'));
|
||||
this.$emit('saved');
|
||||
this.$refs.modal.hide();
|
||||
})
|
||||
.catch(this.$fhcAlert.handleSystemError);
|
||||
}
|
||||
},
|
||||
created() {
|
||||
console.log(this.config)
|
||||
this.$api
|
||||
.call(ApiTempusSync.getSyncStatus())
|
||||
.then(result => this.syncStati = result.data)
|
||||
.catch(error => this.$fhcAlert.handleSystemError(error));
|
||||
},
|
||||
template: `
|
||||
<bs-modal ref="modal" >
|
||||
<template #title>
|
||||
<template v-if="mode === 'new'">{{ $p.t('lehre', 'tempus_sync_new') }}</template>
|
||||
<template v-else-if="mode === 'edit'">{{ $p.t('lehre', 'tempus_sync_edit') }}</template>
|
||||
<template v-else>{{ $p.t('lehre', 'tempus_sync_start') }}</template>
|
||||
</template>
|
||||
|
||||
<core-form ref="form">
|
||||
<form-validation></form-validation>
|
||||
|
||||
<form-input
|
||||
container-class="mb-3"
|
||||
type="select"
|
||||
v-model="formData.oe_kurzbz"
|
||||
name="oe_kurzbz"
|
||||
:label="$p.t('lehre/organisationseinheit')"
|
||||
required
|
||||
>
|
||||
<option
|
||||
v-for="organisation in config.organisationen"
|
||||
:key="organisation.oe_kurzbz"
|
||||
:value="organisation.oe_kurzbz"
|
||||
>
|
||||
{{ organisation.typ.toUpperCase() }}{{ organisation.kurzbz.toUpperCase() }} ({{ organisation.kurzbzlang }})
|
||||
</option>
|
||||
</form-input>
|
||||
|
||||
<form-input
|
||||
container-class="mb-3"
|
||||
type="select"
|
||||
v-model="formData.studiensemester_kurzbz"
|
||||
name="studiensemester_kurzbz"
|
||||
:label="$p.t('lehre/studiensemester')"
|
||||
required
|
||||
>
|
||||
<option
|
||||
v-for="studiensemester in config.studiensemestern"
|
||||
:key="studiensemester.studiensemester_kurzbz"
|
||||
:value="studiensemester.studiensemester_kurzbz"
|
||||
>
|
||||
{{ studiensemester.studiensemester_kurzbz }}
|
||||
</option>
|
||||
</form-input>
|
||||
|
||||
<form-input
|
||||
container-class="mb-3"
|
||||
type="select"
|
||||
v-model="formData.ausbildungssemester"
|
||||
name="ausbildungssemester"
|
||||
:label="$p.t('lehre/ausbildungssemester')"
|
||||
:disabled="!max_semester"
|
||||
>
|
||||
<option :value="null">-- {{ $p.t('fehlermonitoring', 'keineAuswahl') }} --</option>
|
||||
<option
|
||||
v-for="number in semester"
|
||||
:key="number"
|
||||
:value="number"
|
||||
>
|
||||
{{ number }}
|
||||
</option>
|
||||
</form-input>
|
||||
|
||||
<form-input
|
||||
container-class="mb-3"
|
||||
type="select"
|
||||
v-model="formData.studienplan_id"
|
||||
name="studienplan_id"
|
||||
:label="$p.t('lehre/studienplan')"
|
||||
:disabled="!studienplaene.length"
|
||||
>
|
||||
<option :value="null">-- {{ $p.t('fehlermonitoring', 'keineAuswahl') }} --</option>
|
||||
<option
|
||||
v-for="plan in studienplaene"
|
||||
:key="plan.studienplan_id"
|
||||
:value="plan.studienplan_id"
|
||||
>
|
||||
{{ plan.bezeichnung }}-{{plan.orgform_kurzbz}}
|
||||
</option>
|
||||
</form-input>
|
||||
|
||||
<form-input
|
||||
container-class="mb-3"
|
||||
type="DatePicker"
|
||||
v-model="formData.datum_bis"
|
||||
name="datum_bis"
|
||||
:label="$p.t('ui/dateTo')"
|
||||
auto-apply
|
||||
:enable-time-picker="false"
|
||||
text-input
|
||||
format="dd.MM.yyyy"
|
||||
preview-format="dd.MM.yyyy"
|
||||
:teleport="true"
|
||||
>
|
||||
</form-input>
|
||||
|
||||
<form-input
|
||||
|
||||
container-class="mb-3"
|
||||
type="select"
|
||||
v-model="formData.sync_status_kurzbz"
|
||||
name="sync_status_kurzbz"
|
||||
:label="$p.t('global/status')"
|
||||
>
|
||||
<option :value="null">-- {{ $p.t('fehlermonitoring', 'keineAuswahl') }} --</option>
|
||||
<option
|
||||
v-for="status in syncStati"
|
||||
:key="status.status_kurzbz"
|
||||
:value="status.status_kurzbz"
|
||||
>
|
||||
{{ status.bezeichnung }}
|
||||
</option>
|
||||
</form-input>
|
||||
|
||||
<form-input
|
||||
container-class="mb-3"
|
||||
type="checkbox"
|
||||
v-model="formData.mail"
|
||||
name="mail"
|
||||
:label="$p.t('lehre/mail_benachrichtigung')"
|
||||
>
|
||||
</form-input>
|
||||
|
||||
</core-form>
|
||||
|
||||
<template #footer>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-primary"
|
||||
@click="save"
|
||||
>
|
||||
<template v-if="mode === 'start'">{{ $p.t('global', 'jetztStarten') }}</template>
|
||||
<template v-else>{{ $p.t('ui', 'ok') }}</template>
|
||||
</button>
|
||||
</template>
|
||||
</bs-modal>`
|
||||
};
|
||||
@@ -0,0 +1,196 @@
|
||||
import {CoreFilterCmpt} from '../filter/Filter.js';
|
||||
import {CoreNavigationCmpt} from '../navigation/Navigation.js';
|
||||
import FormInput from "../Form/Input.js";
|
||||
|
||||
import CoreBaseLayout from '../../components/layout/BaseLayout.js';
|
||||
import ApiTempusSync from '../../api/factory/tempus/sync.js';
|
||||
import TempusSyncModal from './Modal.js';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
config: Object,
|
||||
defaultSemester: String
|
||||
},
|
||||
components: {
|
||||
CoreFilterCmpt,
|
||||
CoreBaseLayout,
|
||||
CoreNavigationCmpt,
|
||||
FormInput,
|
||||
TempusSyncModal
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
studiensemester_kurzbz: this.defaultSemester ?? null
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
studiensemester_kurzbz()
|
||||
{
|
||||
this.reloadTable();
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
tabulatorOptions() {
|
||||
return {
|
||||
index: "kalender_syncstatus_id",
|
||||
ajaxURL: 'dummy',
|
||||
ajaxRequestFunc: () => this.$api.call(ApiTempusSync.getSyncs(this.studiensemester_kurzbz)),
|
||||
ajaxResponse: (url, params, response) => {
|
||||
return response.data || [];
|
||||
},
|
||||
layout: 'fitDataStretch',
|
||||
placeholder: "Keine Daten verfügbar",
|
||||
persistenceID: "2026_07_21_tempus_sync_v1",
|
||||
locale: true,
|
||||
columns: [
|
||||
{
|
||||
formatter: 'rowSelection',
|
||||
titleFormatter: 'rowSelection',
|
||||
headerSort: false,
|
||||
width: 40
|
||||
},
|
||||
{titlePhrase: 'lehre/organisationseinheit', field: 'oebezeichnung'},
|
||||
{titlePhrase: 'lehre/studiensemester', field: 'studiensemester_kurzbz'},
|
||||
{titlePhrase: 'lehre/bis_title', field: 'datum_bis',
|
||||
formatter: (cell) => {
|
||||
const value = cell.getValue();
|
||||
if (!value) return ''
|
||||
const date = luxon.DateTime.fromSQL(value)
|
||||
return date.isValid ? date.toFormat('dd.MM.yyyy') : value
|
||||
},
|
||||
minWidth: 100
|
||||
},
|
||||
{titlePhrase: 'lehre/studienplan', field: 'studienplanbezeichnung', minWidth: 200},
|
||||
{titlePhrase: 'lehre/ausbildungssemester', field: 'ausbildungssemester'},
|
||||
{titlePhrase: 'global/status', field: 'sync_status_kurzbz'},
|
||||
{titlePhrase: 'lehre/mail_benachrichtigung', field: 'mail', formatter: 'tickCross', hozAlign: 'center', minWidth: 80},
|
||||
{titlePhrase:'global/insertamum', field: 'insertamum',
|
||||
formatter: (cell) => {
|
||||
const value = cell.getValue();
|
||||
if (!value) return ''
|
||||
const date = luxon.DateTime.fromSQL(value)
|
||||
return date.isValid ? date.toFormat('dd.MM.yyyy HH:mm') : value
|
||||
},
|
||||
visible: false
|
||||
},
|
||||
{titlePhrase: 'global/insertvon', field: 'insertvon', visible: false},
|
||||
{titlePhrase: 'global/updateamum', field: 'updateamum',
|
||||
formatter: (cell) => {
|
||||
const value = cell.getValue();
|
||||
if (!value) return ''
|
||||
const date = luxon.DateTime.fromSQL(value)
|
||||
return date.isValid ? date.toFormat('dd.MM.yyyy HH:mm') : value
|
||||
},
|
||||
visible: false
|
||||
},
|
||||
{titlePhrase: 'global/updatevon', field: 'updatevon', visible: false},
|
||||
{
|
||||
titlePhrase: 'global/aktionen',
|
||||
field: 'actions',
|
||||
headerSort: false,
|
||||
hozAlign: 'center',
|
||||
width: 120,
|
||||
formatter: (cell) => {
|
||||
let container = document.createElement('div');
|
||||
container.className = "d-flex gap-2";
|
||||
let button = document.createElement('button');
|
||||
button.className = 'btn btn-outline-secondary';
|
||||
button.innerHTML = '<i class="fa fa-edit"></i>';
|
||||
button.addEventListener('click', () =>
|
||||
this.$refs.syncModal.openEdit(cell.getRow().getData())
|
||||
);
|
||||
|
||||
container.append(button);
|
||||
|
||||
button = document.createElement('button');
|
||||
button.className = 'btn btn-outline-secondary';
|
||||
button.innerHTML = '<i class="fa fa-trash"></i>';
|
||||
button.addEventListener('click', evt => {
|
||||
evt.stopPropagation();
|
||||
this.$fhcAlert
|
||||
.confirmDelete()
|
||||
.then(result => result ? cell.getData().kalender_syncstatus_id : Promise.reject({handled:true}))
|
||||
.then(kalender_syncstatus_id => this.$api.call(ApiTempusSync.delete(kalender_syncstatus_id)))
|
||||
.then(() => {
|
||||
this.reloadTable();
|
||||
})
|
||||
.catch(this.$fhcAlert.handleSystemError);
|
||||
});
|
||||
container.append(button);
|
||||
|
||||
return container;
|
||||
}
|
||||
}
|
||||
],
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
openNewModal()
|
||||
{
|
||||
this.$refs.syncModal.openNew();
|
||||
},
|
||||
reloadTable()
|
||||
{
|
||||
this.$refs.syncTable.reloadTable();
|
||||
},
|
||||
openStartModal()
|
||||
{
|
||||
this.$refs.syncModal.openStart();
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<core-navigation-cmpt></core-navigation-cmpt>
|
||||
<core-base-layout>
|
||||
<template #main>
|
||||
|
||||
<core-filter-cmpt
|
||||
ref="syncTable"
|
||||
:tabulator-options="tabulatorOptions"
|
||||
:table-only=true
|
||||
:side-menu="false"
|
||||
:reload="true"
|
||||
:useSelectionSpan="false"
|
||||
new-btn-label="Hinzufügen"
|
||||
new-btn-show
|
||||
@click:new="openNewModal">
|
||||
|
||||
<template #actions>
|
||||
<form-input
|
||||
type="select"
|
||||
v-model="studiensemester_kurzbz"
|
||||
name="studiensemester_kurzbz"
|
||||
>
|
||||
<option :value="null" disabled>-- {{ $p.t('lehre', 'studiensemester') }} --</option>
|
||||
<option
|
||||
v-for="studiensemester in config.studiensemestern"
|
||||
:key="studiensemester.studiensemester_kurzbz"
|
||||
:value="studiensemester.studiensemester_kurzbz"
|
||||
>
|
||||
{{ studiensemester.studiensemester_kurzbz }}
|
||||
</option>
|
||||
</form-input>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-outline-secondary"
|
||||
@click="openStartModal"
|
||||
>
|
||||
{{ $p.t('global', 'jetztStarten') }}
|
||||
</button>
|
||||
</template>
|
||||
|
||||
</core-filter-cmpt>
|
||||
|
||||
<tempus-sync-modal
|
||||
ref="syncModal"
|
||||
:config="config"
|
||||
:stsem_kurzbz="studiensemester_kurzbz"
|
||||
@saved="reloadTable"
|
||||
>
|
||||
</tempus-sync-modal>
|
||||
</template>
|
||||
</core-base-layout>
|
||||
|
||||
`
|
||||
};
|
||||
Reference in New Issue
Block a user