student page redesign; wip mitarbeiter page + add new modal

This commit is contained in:
Johann Hoffmann
2025-09-04 17:38:32 +02:00
parent 5f1c7537fb
commit 49ca538381
8 changed files with 610 additions and 343 deletions
@@ -485,6 +485,7 @@ class Abgabe extends FHCAPI_Controller
$fixtermin = $_POST['fixtermin'];
$kurzbz = $_POST['kurzbz'];
$note = $_POST['note'];
$notiz = $_POST['notiz'];
$upload_allowed = $_POST['upload_allowed'];
$betreuer_person_id = $_POST['betreuer_person_id'];
@@ -506,6 +507,7 @@ class Abgabe extends FHCAPI_Controller
'datum' => $datum,
'kurzbz' => $kurzbz,
'note' => $note,
'notiz' => $notiz,
'upload_allowed' => $upload_allowed,
'insertvon' => getAuthUID(),
'insertamum' => date('Y-m-d H:i:s')
@@ -521,6 +523,7 @@ class Abgabe extends FHCAPI_Controller
'datum' => $datum,
'kurzbz' => $kurzbz,
'note' => $note,
'notiz' => $notiz,
'upload_allowed' => $upload_allowed,
'updatevon' => getAuthUID(),
'updateamum' => date('Y-m-d H:i:s')
@@ -169,6 +169,7 @@ class Projektarbeit_model extends DB_Model
campus.tbl_paabgabe.datum,
campus.tbl_paabgabe.note,
campus.tbl_paabgabe.upload_allowed,
campus.tbl_paabgabe.notiz,
campus.tbl_paabgabetyp.paabgabetyp_kurzbz,
campus.tbl_paabgabetyp.bezeichnung,
campus.tbl_paabgabe.abgabedatum,
+2 -1
View File
@@ -58,7 +58,8 @@ export default {
paabgabetyp_kurzbz: termin.bezeichnung.paabgabetyp_kurzbz,
datum: termin.datum,
note: termin.note_pk,
upload_allowed: termin.upload_allowed,
upload_allowed: !!termin.upload_allowed,
notiz: termin.notiz ?? '',
fixtermin: termin.fixtermin,
insertvon: termin.insertvon,
kurzbz: termin.kurzbz,
@@ -11,9 +11,12 @@ export const AbgabeMitarbeiterDetail = {
Checkbox: primevue.checkbox,
Dropdown: primevue.dropdown,
Textarea: primevue.textarea,
SpeedDial: primevue.speeddial,
Accordion: primevue.accordion,
AccordionTab: primevue.accordiontab,
VueDatePicker
},
inject: ['abgabeTypeOptions', 'allowedNotenOptions', 'turnitin_link', 'old_abgabe_beurteilung_link'],
inject: ['abgabeTypeOptions', 'allowedNotenOptions', 'turnitin_link', 'old_abgabe_beurteilung_link', 'isMobile'],
props: {
projektarbeit: {
type: Object,
@@ -24,10 +27,19 @@ export const AbgabeMitarbeiterDetail = {
return {
eidAkzeptiert: false,
enduploadTermin: null,
allActiveLanguages: FHC_JS_DATA_STORAGE_OBJECT.server_languages
allActiveLanguages: FHC_JS_DATA_STORAGE_OBJECT.server_languages,
speedDialItems: [{
label: "Create New",
icon: "pi pi-plus",
command: this.createNew
}],
newTermin: null
}
},
methods: {
createNew(){
console.log('create new')
},
openZusatzdatenModal(termin) {
},
@@ -39,24 +51,26 @@ export const AbgabeMitarbeiterDetail = {
this.$api.call(ApiAbgabe.postProjektarbeitAbgabe(termin)).then( (res) => {
if(res?.meta?.status == 'success') {
this.$fhcAlert.alertSuccess(this.$p.t('ui/gespeichert'))
if(paabgabe_id === -1) { // new abgabe has been inserted
termin.paabgabe_id = res?.data?.paabgabe_id
this.projektarbeit.abgabetermine.push({ // new abgatermin row
'paabgabe_id': -1,
'projektarbeit_id': this.projektarbeit.projektarbeit_id,
'fixtermin': false,
'kurzbz': '',
'datum': new Date().toISOString().split('T')[0],
'paabgabetyp_kurzbz': termin.paabgabetyp_kurzbz,
'note': this.allowedNotenOptions.find(opt => opt.note == termin.note?.note),
'upload_allowed': termin.upload_allowed,
'bezeichnung': this.abgabeTypeOptions.find(opt => opt.paabgabetyp_kurzbz === termin.paabgabetyp_kurzbz),
'abgabedatum': null,
'insertvon': this.viewData?.uid ?? '',
'allowedToSave': true,
'allowedToDelete': true
})
}
// if(paabgabe_id === -1) { // new abgabe has been inserted
// termin.paabgabe_id = res?.data?.paabgabe_id
// this.projektarbeit.abgabetermine.push({ // new abgatermin row
// 'paabgabe_id': -1,
// 'projektarbeit_id': this.projektarbeit.projektarbeit_id,
// 'fixtermin': false,
// 'kurzbz': '',
// 'datum': new Date().toISOString().split('T')[0],
// 'paabgabetyp_kurzbz': termin.paabgabetyp_kurzbz,
// 'note': this.allowedNotenOptions.find(opt => opt.note == termin.note?.note),
// 'upload_allowed': termin.upload_allowed,
// 'bezeichnung': this.abgabeTypeOptions.find(opt => opt.paabgabetyp_kurzbz === termin.paabgabetyp_kurzbz),
// 'abgabedatum': null,
// 'insertvon': this.viewData?.uid ?? '',
// 'allowedToSave': true,
// 'allowedToDelete': true
// })
// }
} else if(res?.meta?.status == 'error'){
this.$fhcAlert.alertError()
}
@@ -135,17 +149,6 @@ export const AbgabeMitarbeiterDetail = {
getNotenOptionLabel(option) {
return option.bezeichnung
},
formatDate(dateParam) {
const date = new Date(dateParam)
// handle missing leading 0
const padZero = (num) => String(num).padStart(2, '0');
const month = padZero(date.getMonth() + 1); // Months are zero-based
const day = padZero(date.getDate());
const year = date.getFullYear();
return `${day}.${month}.${year}`;
},
openStudentPage() {
const link = FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router
+ '/Cis/Abgabetool/Student/' + this.projektarbeit?.student_uid
@@ -159,6 +162,44 @@ export const AbgabeMitarbeiterDetail = {
const path = this.projektarbeit?.betreuerart_kurzbz == 'Zweitbegutachter' ? 'ProjektarbeitsbeurteilungZweitbegutachter' : 'ProjektarbeitsbeurteilungErstbegutachter'
const link = FHC_JS_DATA_STORAGE_OBJECT.app_root + 'index.ci.php/extensions/FHC-Core-Projektarbeitsbeurteilung/' + path
window.open(link, '_blank')
},
formatDate(dateParam) {
const date = new Date(dateParam)
// handle missing leading 0
const padZero = (num) => String(num).padStart(2, '0');
const month = padZero(date.getMonth() + 1); // Months are zero-based
const day = padZero(date.getDate());
const year = date.getFullYear();
return `${day}.${month}.${year}`;
},
getAccTabHeaderForTermin(termin) {
let tabTitle = ''
const datumFormatted = this.formatDate(termin.datum)
tabTitle += termin.bezeichnung?.bezeichnung + ' ' + datumFormatted
return tabTitle
},
openCreateNewAbgabeModal() {
if(!this.newTermin) {
this.newTermin = {
// 'paabgabe_id': -1,
// 'projektarbeit_id': this.projektarbeit.projektarbeit_id,
// 'fixtermin': false,
// 'kurzbz': '',
// 'datum': new Date().toISOString().split('T')[0],
// 'note': this.allowedNotenOptions.find(opt => opt.note == 9),
// 'upload_allowed': false,
// 'paabgabetyp_kurzbz': '',
// 'bezeichnung': '',
// 'abgabedatum': null,
// 'insertvon': this.viewData?.uid ?? ''
}
}
this.$refs.modalContainerCreateNewAbgabe.show()
}
},
computed: {
@@ -183,6 +224,12 @@ export const AbgabeMitarbeiterDetail = {
}
})
return qgatefound
},
getPageWrapperStyle() {
return 'position: relative; min-height: 100vh;'
},
getSpeedDialStyle() {
return 'position: absolute; right: 1rem; bottom: 1rem;'
}
},
created() {
@@ -192,8 +239,104 @@ export const AbgabeMitarbeiterDetail = {
},
template: `
<div v-if="projektarbeit" style="max-width: 95%">
<bs-modal ref="modalContainerCreateNewAbgabe" class="bootstrap-prompt" dialogClass="modal-lg">
<template v-slot:title>
<div>
{{ $p.t('abgabetool/c4neueAbgabe') }}
</div>
</template>
<template v-slot:default>
<div v-if="newTermin">
<div class="row">
<div class="col-4 col-md-3 fw-bold">{{$p.t('abgabetool/c4fixtermin')}}</div>
<div class="col-8 col-md-9">
<Checkbox
v-model="newTermin.fixtermin"
:binary="true"
:pt="{ root: { class: 'ml-auto' }}"
>
</Checkbox>
</div>
</div>
<div class="row mt-2">
<div class="col-4 col-md-3 fw-bold">{{$p.t('abgabetool/c4zieldatum')}}</div>
<div class="col-8 col-md-9">
<VueDatePicker
v-model="newTermin.datum"
:clearable="false"
:enable-time-picker="false"
:format="formatDate"
:text-input="true"
auto-apply>
</VueDatePicker>
</div>
</div>
<div class="row mt-2">
<div class="col-4 col-md-3 fw-bold">{{$p.t('abgabetool/c4abgabetyp')}}</div>
<div class="col-8 col-md-9">
<Dropdown
:style="{'width': '100%'}"
v-model="newTermin.bezeichnung"
:options="abgabeTypeOptions"
:optionLabel="getOptionLabelAbgabetyp">
</Dropdown>
</div>
</div>
<div class="row mt-2" v-if="newTermin.bezeichnung?.paabgabetyp_kurzbz === 'qualgate1' || newTermin.bezeichnung?.paabgabetyp_kurzbz === 'qualgate2'">
<div class="col-4 col-md-3 fw-bold">{{$p.t('abgabetool/c4note')}}</div>
<div class="col-8 col-md-9">
<Dropdown
:style="{'width': '100%'}"
v-model="newTermin.note"
:options="allowedNotenOptions"
:optionLabel="getNotenOptionLabel">
</Dropdown>
</div>
</div>
<div class="row mt-2" v-if="newTermin.bezeichnung?.paabgabetyp_kurzbz === 'qualgate1' || newTermin?.bezeichnung?.paabgabetyp_kurzbz === 'qualgate2'">
<div class="col-4 col-md-3 fw-bold">{{$p.t('abgabetool/c4upload_allowed')}}</div>
<div class="col-8 col-md-9">
<Checkbox
v-model="newTermin.upload_allowed"
:binary="true"
:pt="{ root: { class: 'ml-auto' }}"
>
</Checkbox>
</div>
</div>
<div class="row mt-2" v-if="newTermin.bezeichnung?.paabgabetyp_kurzbz === 'qualgate1' || newTermin.bezeichnung?.paabgabetyp_kurzbz === 'qualgate2'">
<div class="col-4 col-md-3 fw-bold">{{$p.t('abgabetool/c4notizQualGate')}}</div>
<div class="col-8 col-md-9">
<Textarea style="margin-bottom: 4px;" v-model="newTermin?.notiz" :rows=" isMobile ? 2 : 4" :cols=" isMobile ? 30 : 90"></Textarea>
</div>
</div>
<div class="row mt-2">
<div class="col-4 col-md-3 fw-bold">{{$p.t('abgabetool/c4abgabekurzbz')}}</div>
<div class="col-8 col-md-9">
<Textarea style="margin-bottom: 4px;" v-model="newTermin.kurzbz" :rows=" isMobile ? 2 : 4" :cols=" isMobile ? 30 : 90"></Textarea>
</div>
</div>
</div>
</template>
<template v-slot:footer>
</template>
</bs-modal>
<SpeedDial
@click="openCreateNewAbgabeModal"
:model="[]"
direction="up"
type="linear"
showIcon="pi pi-plus"
hideIcon="pi pi-plus"
:visible="true"
:style="getSpeedDialStyle"
/>
<div v-if="projektarbeit">
<h5>{{$p.t('abgabetool/c4abgabeMitarbeiterbereich')}}</h5>
<div class="row">
@@ -235,33 +378,26 @@ export const AbgabeMitarbeiterDetail = {
</div>
</div>
</div>
<div id="uploadWrapper">
<div class="row" style="margin-bottom: 12px;">
<div class="fw-bold" style="width: 100px">{{$p.t('abgabetool/c4fixtermin')}}</div>
<div class="row" style="max-width: calc(100% - 100px)">
<div class="col-2 fw-bold">{{$p.t('abgabetool/c4zieldatum')}}</div>
<div class="col-2 fw-bold">{{$p.t('abgabetool/c4abgabetyp')}}</div>
<div v-show="qualityGateTerminAvailable" class="col-2 fw-bold">{{$p.t('abgabetool/c4note')}}</div>
<div v-show="qualityGateTerminAvailable" class="col-1 fw-bold">{{$p.t('abgabetool/c4upload_allowed')}}</div>
<div class="col-2 fw-bold">{{$p.t('abgabetool/c4abgabekurzbz')}}</div>
<div class="col-1 fw-bold">{{$p.t('abgabetool/c4abgabedatum')}}</div>
<div class="col">
<Accordion :multiple="true" :activeIndex="[0]">
<template v-for="termin in this.projektarbeit?.abgabetermine">
<AccordionTab :header="getAccTabHeaderForTermin(termin)">
<div class="row">
<div class="col-4 col-md-3 fw-bold">{{$p.t('abgabetool/c4fixtermin')}}</div>
<div class="col-8 col-md-9">
<Checkbox
v-model="termin.fixtermin"
:binary="true"
:pt="{ root: { class: 'ml-auto' }}"
>
</Checkbox>
</div>
</div>
</div>
</div>
<div v-if="!projektarbeit?.abgabetermine?.length">keine Termine gefunden!</div>
<div class="row" v-for="termin in projektarbeit.abgabetermine">
<div style="width: 100px" class="d-flex justify-content-center align-items-center">
<i v-if="termin.fixtermin" class="fa-solid fa-2x fa-circle-check fhc-bullet-red"></i>
<i v-else="" class="fa-solid fa-2x fa-circle-xmark fhc-bullet-green"></i>
<!-- <p class="fhc-bullet" :class="{ 'fhc-bullet-red': termin.fixtermin, 'fhc-bullet-green': !termin.fixtermin }"></p>-->
</div>
<div class="row" style="max-width: calc(100% - 100px)">
<div class="col-2 d-flex justify-content-center align-items-center">
<div class="position-relative" :class="getDateStyle(termin)">
<div class="row mt-2">
<div class="col-4 col-md-3 fw-bold">{{$p.t('abgabetool/c4zieldatum')}}</div>
<div class="col-8 col-md-9">
<VueDatePicker
style="width: 95%;"
v-model="termin.datum"
:clearable="false"
:disabled="!termin.allowedToSave"
@@ -270,58 +406,175 @@ export const AbgabeMitarbeiterDetail = {
:text-input="true"
auto-apply>
</VueDatePicker>
<i class="position-absolute abgabe-zieldatum-overlay fa-solid fa-2x" :class="getDateStyle(termin, 'icon')"></i>
</div>
</div>
</div>
<div class="col-2 d-flex justify-content-center align-items-center">
<Dropdown
:style="{'width': '100%'}"
:disabled="!termin.allowedToSave"
v-model="termin.bezeichnung"
:options="abgabeTypeOptions"
:optionLabel="getOptionLabelAbgabetyp">
</Dropdown>
<div class="row mt-2">
<div class="col-4 col-md-3 fw-bold">{{$p.t('abgabetool/c4abgabetyp')}}</div>
<div class="col-8 col-md-9">
<Dropdown
:style="{'width': '100%'}"
:disabled="!termin.allowedToSave"
v-model="termin.bezeichnung"
:options="abgabeTypeOptions"
:optionLabel="getOptionLabelAbgabetyp">
</Dropdown>
</div>
</div>
<div v-if="qualityGateTerminAvailable || termin.bezeichnung?.paabgabetyp_kurzbz === 'qualgate1' || termin.bezeichnung?.paabgabetyp_kurzbz === 'qualgate2'" class="col-2 d-flex justify-content-center align-items-center">
<Dropdown
v-if="termin.bezeichnung?.paabgabetyp_kurzbz === 'qualgate1' || termin.bezeichnung?.paabgabetyp_kurzbz === 'qualgate2'"
:style="{'width': '100%'}"
v-model="termin.note"
:options="allowedNotenOptions"
:optionLabel="getNotenOptionLabel">
</Dropdown>
<div class="row mt-2" v-if="termin.bezeichnung?.paabgabetyp_kurzbz === 'qualgate1' || termin.bezeichnung?.paabgabetyp_kurzbz === 'qualgate2'">
<div class="col-4 col-md-3 fw-bold">{{$p.t('abgabetool/c4note')}}</div>
<div class="col-8 col-md-9">
<Dropdown
:style="{'width': '100%'}"
v-model="termin.note"
:options="allowedNotenOptions"
:optionLabel="getNotenOptionLabel">
</Dropdown>
</div>
</div>
<div v-if="qualityGateTerminAvailable || termin.bezeichnung?.paabgabetyp_kurzbz === 'qualgate1' || termin.bezeichnung?.paabgabetyp_kurzbz === 'qualgate2'" class="col-1 d-flex justify-content-center align-items-center">
<Checkbox
v-if="termin.bezeichnung?.paabgabetyp_kurzbz === 'qualgate1' || termin.bezeichnung?.paabgabetyp_kurzbz === 'qualgate2'"
v-model="termin.upload_allowed"
:binary="true"
:pt="{ root: { class: 'ml-auto' }}"
>
</Checkbox>
<div class="row mt-2" v-if="termin.bezeichnung?.paabgabetyp_kurzbz === 'qualgate1' || termin.bezeichnung?.paabgabetyp_kurzbz === 'qualgate2'">
<div class="col-4 col-md-3 fw-bold">{{$p.t('abgabetool/c4upload_allowed')}}</div>
<div class="col-8 col-md-9">
<Checkbox
v-model="termin.upload_allowed"
:binary="true"
:pt="{ root: { class: 'ml-auto' }}"
>
</Checkbox>
</div>
</div>
<div class="col-2 d-flex justify-content-center align-items-center">
<Textarea style="margin-bottom: 4px;" v-model="termin.kurzbz" rows="1" cols="20" :disabled="!termin.allowedToSave"></Textarea>
<div class="row mt-2" v-if="termin.bezeichnung?.paabgabetyp_kurzbz === 'qualgate1' || termin.bezeichnung?.paabgabetyp_kurzbz === 'qualgate2'">
<div class="col-4 col-md-3 fw-bold">{{$p.t('abgabetool/c4notizQualGate')}}</div>
<div class="col-8 col-md-9">
<Textarea style="margin-bottom: 4px;" v-model="termin.notiz" :rows=" isMobile ? 2 : 4" :cols=" isMobile ? 30 : 90" :disabled="!termin.allowedToSave"></Textarea>
</div>
</div>
<div class="col-1 d-flex justify-content-center align-items-center">
{{ termin.abgabedatum?.split("-").reverse().join(".") }}
<a v-if="termin?.abgabedatum" @click="downloadAbgabe(termin)" style="margin-left:4px; cursor: pointer;">
<i class="fa-solid fa-2x fa-file-pdf"></i>
</a>
<div class="row mt-2">
<div class="col-4 col-md-3 fw-bold">{{$p.t('abgabetool/c4abgabekurzbz')}}</div>
<div class="col-8 col-md-9">
<Textarea style="margin-bottom: 4px;" v-model="termin.kurzbz" :rows=" isMobile ? 2 : 4" :cols=" isMobile ? 30 : 90" :disabled="!termin.allowedToSave"></Textarea>
</div>
</div>
<div class="col-2 align-content-center">
<button v-if="termin.allowedToSave" style="max-height: 40px;" class="btn btn-primary border-0" @click="saveTermin(termin)">
{{ $p.t('abgabetool/c4save') }}
<i class="fa-solid fa-floppy-disk"></i>
</button>
<button v-if="termin.allowedToDelete && termin.paabgabe_id > 0" style="max-height: 40px;" class="btn btn-primary border-0" @click="deleteTermin(termin)">
{{ $p.t('abgabetool/c4delete') }}
<i class="fa-solid fa-trash"></i>
</button>
<div class="row mt-2">
<div class="col-4 col-md-3 fw-bold">{{$p.t('abgabetool/c4abgabedatum')}}</div>
<div class="col-8 col-md-9">
{{ termin.abgabedatum?.split("-").reverse().join(".") }}
<a v-if="termin?.abgabedatum" @click="downloadAbgabe(termin)" style="margin-left:4px; cursor: pointer;">
<i class="fa-solid fa-2x fa-file-pdf"></i>
</a>
</div>
</div>
</div>
</div>
</div>
<div class="row mt-2">
<div class="col-4 col-md-3 fw-bold">
<!-- TODO: row description? -->
</div>
<div class="col-8 col-md-9">
<div class="row">
<div class="col-4">
<button v-if="termin.allowedToSave" style="max-height: 40px;" class="btn btn-primary border-0" @click="saveTermin(termin)">
{{ $p.t('abgabetool/c4save') }}
<i class="fa-solid fa-floppy-disk"></i>
</button>
</div>
<div class="col-4">
<button v-if="termin.allowedToDelete && termin.paabgabe_id > 0" style="max-height: 40px;" class="btn btn-primary border-0" @click="deleteTermin(termin)">
{{ $p.t('abgabetool/c4delete') }}
<i class="fa-solid fa-trash"></i>
</button>
</div>
</div>
</div>
</div>
</AccordionTab>
</template>
</Accordion>
<!-- <div id="uploadWrapper">-->
<!-- <div class="row" style="margin-bottom: 12px;">-->
<!-- <div class="fw-bold" style="width: 100px">{{$p.t('abgabetool/c4fixtermin')}}</div>-->
<!-- <div class="row" style="max-width: calc(100% - 100px)">-->
<!-- <div class="col-2 fw-bold">{{$p.t('abgabetool/c4zieldatum')}}</div>-->
<!-- <div class="col-2 fw-bold">{{$p.t('abgabetool/c4abgabetyp')}}</div>-->
<!-- <div v-show="qualityGateTerminAvailable" class="col-2 fw-bold">{{$p.t('abgabetool/c4note')}}</div>-->
<!-- <div v-show="qualityGateTerminAvailable" class="col-1 fw-bold">{{$p.t('abgabetool/c4upload_allowed')}}</div>-->
<!-- <div class="col-2 fw-bold">{{$p.t('abgabetool/c4abgabekurzbz')}}</div>-->
<!-- <div class="col-1 fw-bold">{{$p.t('abgabetool/c4abgabedatum')}}</div>-->
<!-- <div class="col">-->
<!-- -->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- <div v-if="!projektarbeit?.abgabetermine?.length">keine Termine gefunden!</div>-->
<!-- <div class="row" v-for="termin in projektarbeit.abgabetermine">-->
<!-- <div style="width: 100px" class="d-flex justify-content-center align-items-center">-->
<!-- <i v-if="termin.fixtermin" class="fa-solid fa-2x fa-circle-check fhc-bullet-red"></i>-->
<!-- <i v-else="" class="fa-solid fa-2x fa-circle-xmark fhc-bullet-green"></i>-->
<!--&lt;!&ndash; <p class="fhc-bullet" :class="{ 'fhc-bullet-red': termin.fixtermin, 'fhc-bullet-green': !termin.fixtermin }"></p>&ndash;&gt;-->
<!-- </div>-->
<!-- <div class="row" style="max-width: calc(100% - 100px)">-->
<!-- <div class="col-2 d-flex justify-content-center align-items-center">-->
<!-- <div class="position-relative" :class="getDateStyle(termin)">-->
<!-- <VueDatePicker-->
<!-- style="width: 95%;"-->
<!-- v-model="termin.datum"-->
<!-- :clearable="false"-->
<!-- :disabled="!termin.allowedToSave"-->
<!-- :enable-time-picker="false"-->
<!-- :format="formatDate"-->
<!-- :text-input="true"-->
<!-- auto-apply>-->
<!-- </VueDatePicker>-->
<!-- <i class="position-absolute abgabe-zieldatum-overlay fa-solid fa-2x" :class="getDateStyle(termin, 'icon')"></i>-->
<!-- </div> -->
<!-- </div>-->
<!-- <div class="col-2 d-flex justify-content-center align-items-center">-->
<!-- <Dropdown -->
<!-- :style="{'width': '100%'}"-->
<!-- :disabled="!termin.allowedToSave"-->
<!-- v-model="termin.bezeichnung"-->
<!-- :options="abgabeTypeOptions"-->
<!-- :optionLabel="getOptionLabelAbgabetyp">-->
<!-- </Dropdown>-->
<!-- </div>-->
<!-- <div v-if="qualityGateTerminAvailable || termin.bezeichnung?.paabgabetyp_kurzbz === 'qualgate1' || termin.bezeichnung?.paabgabetyp_kurzbz === 'qualgate2'" class="col-2 d-flex justify-content-center align-items-center">-->
<!-- <Dropdown -->
<!-- v-if="termin.bezeichnung?.paabgabetyp_kurzbz === 'qualgate1' || termin.bezeichnung?.paabgabetyp_kurzbz === 'qualgate2'"-->
<!-- :style="{'width': '100%'}"-->
<!-- v-model="termin.note"-->
<!-- :options="allowedNotenOptions"-->
<!-- :optionLabel="getNotenOptionLabel">-->
<!-- </Dropdown>-->
<!-- </div>-->
<!-- <div v-if="qualityGateTerminAvailable || termin.bezeichnung?.paabgabetyp_kurzbz === 'qualgate1' || termin.bezeichnung?.paabgabetyp_kurzbz === 'qualgate2'" class="col-1 d-flex justify-content-center align-items-center">-->
<!-- <Checkbox -->
<!-- v-if="termin.bezeichnung?.paabgabetyp_kurzbz === 'qualgate1' || termin.bezeichnung?.paabgabetyp_kurzbz === 'qualgate2'"-->
<!-- v-model="termin.upload_allowed"-->
<!-- :binary="true" -->
<!-- :pt="{ root: { class: 'ml-auto' }}"-->
<!-- >-->
<!-- </Checkbox>-->
<!-- </div>-->
<!-- <div class="col-2 d-flex justify-content-center align-items-center">-->
<!-- <Textarea style="margin-bottom: 4px;" v-model="termin.kurzbz" rows="1" cols="20" :disabled="!termin.allowedToSave"></Textarea>-->
<!-- </div>-->
<!-- <div class="col-1 d-flex justify-content-center align-items-center">-->
<!-- {{ termin.abgabedatum?.split("-").reverse().join(".") }}-->
<!-- <a v-if="termin?.abgabedatum" @click="downloadAbgabe(termin)" style="margin-left:4px; cursor: pointer;">-->
<!-- <i class="fa-solid fa-2x fa-file-pdf"></i>-->
<!-- </a>-->
<!-- </div>-->
<!-- <div class="col-2 align-content-center">-->
<!-- <button v-if="termin.allowedToSave" style="max-height: 40px;" class="btn btn-primary border-0" @click="saveTermin(termin)">-->
<!-- {{ $p.t('abgabetool/c4save') }}-->
<!-- <i class="fa-solid fa-floppy-disk"></i>-->
<!-- </button>-->
<!-- <button v-if="termin.allowedToDelete && termin.paabgabe_id > 0" style="max-height: 40px;" class="btn btn-primary border-0" @click="deleteTermin(termin)">-->
<!-- {{ $p.t('abgabetool/c4delete') }}-->
<!-- <i class="fa-solid fa-trash"></i>-->
<!-- </button>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
</div>
`,
};
@@ -241,10 +241,9 @@ export const AbgabeStudentDetail = {
<p> {{projektarbeit?.titel}}</p>
</div>
<!-- TODO: arrange this properly in mobile view, left col is a bit tight and all-->
<Accordion ref="accordion" :multiple="true" :activeIndex="[0]">
<Accordion :multiple="true" :activeIndex="[0]">
<template v-for="termin in this.projektarbeit?.abgabetermine">
<AccordionTab :header="getAccTabHeaderForTermin(termin)" style="padding: 0px;" :pt="tabPassthroughStyle">
<AccordionTab :header="getAccTabHeaderForTermin(termin)" style="padding: 0px;">
<div class="row">
<div class="col-4 col-md-3 fw-bold">{{$p.t('abgabetool/c4fixtermin')}}</div>
@@ -205,21 +205,23 @@ export const AbgabetoolMitarbeiter = {
const pa = this.projektarbeiten?.retval?.find(projekarbeit => projekarbeit.projektarbeit_id == details.projektarbeit_id)
pa.abgabetermine = res.data[0].retval
pa.isCurrent = res.data[1]
pa.abgabetermine.push({ // new abgatermin row
'paabgabe_id': -1,
'projektarbeit_id': pa.projektarbeit_id,
'fixtermin': false,
'kurzbz': '',
'datum': new Date().toISOString().split('T')[0],
'note': this.allowedNotenOptions.find(opt => opt.note == 9),
'upload_allowed': false,
'paabgabetyp_kurzbz': '',
'bezeichnung': '',
'abgabedatum': null,
'insertvon': this.viewData?.uid ?? ''
})
// pa.abgabetermine.push({ // new abgatermin row
//
// 'paabgabe_id': -1,
// 'projektarbeit_id': pa.projektarbeit_id,
// 'fixtermin': false,
// 'kurzbz': '',
// 'datum': new Date().toISOString().split('T')[0],
// 'note': this.allowedNotenOptions.find(opt => opt.note == 9),
// 'upload_allowed': false,
// 'paabgabetyp_kurzbz': '',
// 'bezeichnung': '',
// 'abgabedatum': null,
// 'insertvon': this.viewData?.uid ?? ''
//
// })
pa.abgabetermine.forEach(termin => {
termin.note = this.allowedNotenOptions.find(opt => opt.note == termin.note)
termin.file = []
@@ -237,8 +239,6 @@ export const AbgabetoolMitarbeiter = {
this.selectedProjektarbeit = pa
this.$refs.modalContainerAbgabeDetail.show()
// this.$refs.verticalsplitthis.$refs.verticalsplit.showBoth()
})
},
@@ -459,54 +459,43 @@ export const AbgabetoolMitarbeiter = {
<!-- low max height on this vsplit wrapper to avoid padding scrolls, elements have their inherent height anyways -->
<div style="max-height:40vw;">
<!-- <vertical-split ref="verticalsplit"> -->
<!-- -->
<!-- <template #top>-->
<h2>{{$p.t('abgabetool/abgabetoolTitle')}}</h2>
<hr>
<core-filter-cmpt
:title="''"
@uuidDefined="handleUuidDefined"
ref="abgabeTable"
:newBtnShow="true"
:newBtnLabel="$p.t('abgabetool/neueTerminserie')"
:newBtnDisabled="!selectedData.length"
@click:new=openAddSeriesModal
:tabulator-options="abgabeTableOptions"
:tabulator-events="abgabeTableEventHandlers"
tableOnly
:sideMenu="false"
:useSelectionSpan="false"
>
<template #actions>
<button @click="toggleShowAll(!showAll)" role="button" class="btn btn-secondary ml-2">
<i v-show="!showAll" class="fa fa-eye"></i>
<i v-show="showAll" class="fa fa-eye-slash"></i>
{{ $p.t('abgabetool/showAll') }}
</button>
<button @click="showDeadlines" role="button" class="btn btn-secondary ml-2">
<i class="fa fa-hourglass-end"></i>
{{ $p.t('abgabetool/showDeadlines') }}
</button>
<div v-show="saving">
{{ $p.t('abgabetool/currentlySaving') }} <i class="fa-solid fa-spinner fa-pulse fa-3x"></i>
</div>
<div v-show="loading">
{{ $p.t('abgabetool/currentlyLoading') }} <i class="fa-solid fa-spinner fa-pulse fa-3x"></i>
</div>
</template>
</core-filter-cmpt>
<!-- </template>-->
<!-- <template #bottom>-->
<!-- <div v-show="selectedProjektarbeit" ref="selProj"> -->
<!-- <AbgabeDetail :projektarbeit="selectedProjektarbeit"></AbgabeDetail>-->
<!-- </div>-->
<!-- </template>-->
<!-- </vertical-split>-->
<h2>{{$p.t('abgabetool/abgabetoolTitle')}}</h2>
<hr>
<core-filter-cmpt
:title="''"
@uuidDefined="handleUuidDefined"
ref="abgabeTable"
:newBtnShow="true"
:newBtnLabel="$p.t('abgabetool/neueTerminserie')"
:newBtnDisabled="!selectedData.length"
@click:new=openAddSeriesModal
:tabulator-options="abgabeTableOptions"
:tabulator-events="abgabeTableEventHandlers"
tableOnly
:sideMenu="false"
:useSelectionSpan="false"
>
<template #actions>
<button @click="toggleShowAll(!showAll)" role="button" class="btn btn-secondary ml-2">
<i v-show="!showAll" class="fa fa-eye"></i>
<i v-show="showAll" class="fa fa-eye-slash"></i>
{{ $p.t('abgabetool/showAll') }}
</button>
<button @click="showDeadlines" role="button" class="btn btn-secondary ml-2">
<i class="fa fa-hourglass-end"></i>
{{ $p.t('abgabetool/showDeadlines') }}
</button>
<div v-show="saving">
{{ $p.t('abgabetool/currentlySaving') }} <i class="fa-solid fa-spinner fa-pulse fa-3x"></i>
</div>
<div v-show="loading">
{{ $p.t('abgabetool/currentlyLoading') }} <i class="fa-solid fa-spinner fa-pulse fa-3x"></i>
</div>
</template>
</core-filter-cmpt>
</div>
`,
@@ -1,4 +1,3 @@
import {CoreFilterCmpt} from "../../../components/filter/Filter.js";
import AbgabeDetail from "./AbgabeStudentDetail.js";
import VerticalSplit from "../../verticalsplit/verticalsplit.js";
import ApiAbgabe from '../../../api/factory/abgabe.js'
@@ -7,8 +6,9 @@ import BsModal from "../../Bootstrap/Modal.js";
export const AbgabetoolStudent = {
name: "AbgabetoolStudent",
components: {
Accordion: primevue.accordion,
AccordionTab: primevue.accordiontab,
BsModal,
CoreFilterCmpt,
AbgabeDetail,
VerticalSplit
},
@@ -34,117 +34,113 @@ export const AbgabetoolStudent = {
data() {
return {
notenOptions: null,
tabulatorUuid: Vue.ref(0),
domain: '',
student_uid: null,
detail: null,
projektarbeiten: null,
selectedProjektarbeit: null,
tableBuiltResolve: null,
tableBuiltPromise: null,
dataProcessedPromise: null,
dataProcessedResolve: null,
abgabeTableOptions: {
minHeight: 250,
index: 'projektarbeit_id',
layout: 'fitColumns',
responsiveLayout: "collapse",
placeholder: this.$p.t('global/noDataAvailable'),
columns: [
{
formatter:"responsiveCollapse",
width:30, minWidth:30, hozAlign:"center", resizable:false, headerSort:false
},
{
title: Vue.computed(() => this.$p.t('abgabetool/c4details')), field: 'details',
formatter: this.detailFormatter,
widthGrow: 1, tooltip: false
, responsive: 0, minWidth: 80
},
{
title: Vue.computed(() => this.$p.t('abgabetool/c4beurteilung')), field: 'beurteilung',
formatter: this.beurteilungFormatter,
widthGrow: 1, tooltip: false
, responsive: 0, minWidth: 80
},
{
title: Vue.computed(() => this.$p.t('abgabetool/c4sem')), field: 'sem',
formatter: this.centeredTextFormatter,
widthGrow: 1
, responsive: 5, minWidth: 120
},
{
title: Vue.computed(() => this.$p.t('abgabetool/c4stg')), field: 'stg',
formatter: this.centeredTextFormatter,
widthGrow: 1
, responsive: 6, minWidth: 120
},
{
title: Vue.computed(() => this.$p.t('abgabetool/c4kontakt')), field: 'mail',
formatter: this.mailFormatter,
widthGrow: 1
, responsive: 0, minWidth: 80
},
{
title: Vue.computed(() => this.$p.t('abgabetool/c4betreuer')), field: 'betreuer',
formatter: this.centeredTextFormatter,
widthGrow: 2
, responsive: 7, minWidth: 300
},
{
title: Vue.computed(() => this.$p.t('abgabetool/c4projekttyp')), field: 'typ',
formatter: this.centeredTextFormatter,
widthGrow: 1
, responsive: 8, minWidth: 200
},
{
title: Vue.computed(() => this.$p.t('abgabetool/c4titel')), field: 'titel',
formatter: this.centeredTextFormatter,
widthGrow: 8
, responsive: 1, minWidth: 420
}
],
persistence: false,
},
abgabeTableEventHandlers: [
{
event: "tableBuilt",
handler: async () => {
this.tableBuiltResolve()
}
},
{
event: "dataProcessed",
handler: async () => {
console.log('dataProcessed event')
this.dataProcessedResolve()
}
},
{
event: "cellClick",
handler: async (e, cell) => {
if(cell.getColumn().getField() === "details") {
const val = cell.getValue()
if(val.mode === 'detailTermine') {
this.setDetailComponent(cell.getValue())
} else if (val.mode === 'beurteilungDownload') {
const pdfExportLink = FHC_JS_DATA_STORAGE_OBJECT.app_root + 'cis/private/pdfExport.php?xml=projektarbeitsbeurteilung.xml.php&xsl=Projektbeurteilung&betreuerart_kurzbz='+val.betreuerart_kurzbz+'&projektarbeit_id='+val.projektarbeit_id+'&person_id=' + val.betreuer_person_id
// const pdfExportLink2 = FHC_JS_DATA_STORAGE_OBJECT.app_root + 'cis/private/lehre/projektbeurteilungDocumentExport.php?betreuerart_kurzbz='+val.betreuerart_kurzbz+'&projektarbeit_id='+val.projektarbeit_id+'&person_id=' + val.betreuer_person_id
window.open(pdfExportLink, '_blank')
}
} else if (cell.getColumn().getField() === "beurteilung") {
const val = cell.getValue()
if(val != '-') window.open(val, '_blank')
}
e.stopPropagation()
}
}
]};
// abgabeTableOptions: {
// minHeight: 250,
// index: 'projektarbeit_id',
// layout: 'fitColumns',
// responsiveLayout: "collapse",
// placeholder: this.$p.t('global/noDataAvailable'),
// columns: [
// {
// formatter:"responsiveCollapse",
// width:30, minWidth:30, hozAlign:"center", resizable:false, headerSort:false
// },
// {
// title: Vue.computed(() => this.$p.t('abgabetool/c4details')), field: 'details',
// formatter: this.detailFormatter,
// widthGrow: 1, tooltip: false
// , responsive: 0, minWidth: 80
// },
// {
// title: Vue.computed(() => this.$p.t('abgabetool/c4beurteilung')), field: 'beurteilung',
// formatter: this.beurteilungFormatter,
// widthGrow: 1, tooltip: false
// , responsive: 0, minWidth: 80
// },
// {
// title: Vue.computed(() => this.$p.t('abgabetool/c4sem')), field: 'sem',
// formatter: this.centeredTextFormatter,
// widthGrow: 1
// , responsive: 5, minWidth: 120
// },
// {
// title: Vue.computed(() => this.$p.t('abgabetool/c4stg')), field: 'stg',
// formatter: this.centeredTextFormatter,
// widthGrow: 1
// , responsive: 6, minWidth: 120
// },
// {
// title: Vue.computed(() => this.$p.t('abgabetool/c4kontakt')), field: 'mail',
// formatter: this.mailFormatter,
// widthGrow: 1
// , responsive: 0, minWidth: 80
// },
// {
// title: Vue.computed(() => this.$p.t('abgabetool/c4betreuer')), field: 'betreuer',
// formatter: this.centeredTextFormatter,
// widthGrow: 2
// , responsive: 7, minWidth: 300
// },
// {
// title: Vue.computed(() => this.$p.t('abgabetool/c4projekttyp')), field: 'typ',
// formatter: this.centeredTextFormatter,
// widthGrow: 1
// , responsive: 8, minWidth: 200
// },
// {
// title: Vue.computed(() => this.$p.t('abgabetool/c4titel')), field: 'titel',
// formatter: this.centeredTextFormatter,
// widthGrow: 8
// , responsive: 1, minWidth: 420
// }
// ],
// persistence: false,
// },
// abgabeTableEventHandlers: [
// {
// event: "tableBuilt",
// handler: async () => {
// this.tableBuiltResolve()
// }
// },
// {
// event: "dataProcessed",
// handler: async () => {
// console.log('dataProcessed event')
// this.dataProcessedResolve()
// }
// },
// {
// event: "cellClick",
// handler: async (e, cell) => {
//
// if(cell.getColumn().getField() === "details") {
// const val = cell.getValue()
//
// if(val.mode === 'detailTermine') {
// this.setDetailComponent(cell.getValue())
// } else if (val.mode === 'beurteilungDownload') {
// const pdfExportLink = FHC_JS_DATA_STORAGE_OBJECT.app_root + 'cis/private/pdfExport.php?xml=projektarbeitsbeurteilung.xml.php&xsl=Projektbeurteilung&betreuerart_kurzbz='+val.betreuerart_kurzbz+'&projektarbeit_id='+val.projektarbeit_id+'&person_id=' + val.betreuer_person_id
// // const pdfExportLink2 = FHC_JS_DATA_STORAGE_OBJECT.app_root + 'cis/private/lehre/projektbeurteilungDocumentExport.php?betreuerart_kurzbz='+val.betreuerart_kurzbz+'&projektarbeit_id='+val.projektarbeit_id+'&person_id=' + val.betreuer_person_id
// window.open(pdfExportLink, '_blank')
// }
//
// } else if (cell.getColumn().getField() === "beurteilung") {
// const val = cell.getValue()
//
// if(val != '-') window.open(val, '_blank')
// }
// e.stopPropagation()
//
// }
// }
// ]
};
},
methods: {
checkQualityGates(termine) {
@@ -195,7 +191,6 @@ export const AbgabetoolStudent = {
// this.$refs.verticalsplit.showBoth()
})
},
centeredTextFormatter(cell) {
const val = cell.getValue()
@@ -226,13 +221,6 @@ export const AbgabetoolStudent = {
'<a><i class="fa fa-file-pdf" style="color:#00649C"></i></a></div>'
} else return '-'
},
tableResolve(resolve) {
this.tableBuiltResolve = resolve
},
dataResolve(resolve) {
console.log('dataResolve')
this.dataProcessedResolve = resolve
},
buildMailToLink(projekt) {
if(projekt.mitarbeiter_uid) { // standard
return 'mailto:' + projekt.mitarbeiter_uid +'@'+ this.domain
@@ -244,10 +232,10 @@ export const AbgabetoolStudent = {
return abgabe.betreuerart_beschreibung + ': ' + (abgabe.btitelpre ? abgabe.btitelpre + ' ' : '') + abgabe.bvorname + ' ' + abgabe.bnachname + (abgabe.btitelpost ? ' ' + abgabe.btitelpost : '')
},
async setupData(data){
this.projektarbeiten = data[0]
// this.projektarbeiten = data[0]
this.domain = data[1]
this.student_uid = data[2]
const d = data[0]?.map(projekt => {
this.projektarbeiten = data[0]?.map(projekt => {
let mode = 'detailTermine'
if (projekt.babgeschickt || projekt.zweitbetreuer_abgeschickt) {
@@ -257,6 +245,7 @@ export const AbgabetoolStudent = {
}
return {
...projekt,
details: {
student_uid: this.student_uid,
projektarbeit_id: projekt.projektarbeit_id,
@@ -273,23 +262,6 @@ export const AbgabetoolStudent = {
titel: projekt.titel
}
})
// this.$refs.abgabeTable.tabulator.setColumns(this.abgabeTableOptions.columns)
this.$refs.abgabeTable.tabulator.setData(d);
await this.dataProcessedPromise
// TODO: proper event handling cleanup
// todo in general fix this nasty race condition
const t = this.$refs.abgabeTable.tabulator;
t.on("renderComplete", () => {
// only if container width is small enough to trigger collapse
if (t.element.offsetWidth < 600 || this.isMobile) {
t.setColumns(t.getColumnDefinitions());
t.redraw(true)
}
});
},
loadProjektarbeiten() {
@@ -306,33 +278,15 @@ export const AbgabetoolStudent = {
})
})
},
handleUuidDefined(uuid) {
this.tabulatorUuid = uuid
},
calcMaxTableHeight() {
const tableID = this.tabulatorUuid ? ('-' + this.tabulatorUuid) : ''
const tableDataSet = document.getElementById('filterTableDataset' + tableID);
if(!tableDataSet) return
const rect = tableDataSet.getBoundingClientRect();
this.abgabeTableOptions.height = window.visualViewport.height - rect.top - 100
this.$refs.abgabeTable.tabulator.setHeight(this.abgabeTableOptions.height)
},
async setupMounted() {
this.tableBuiltPromise = new Promise(this.tableResolve)
this.dataProcessedPromise = new Promise(this.dataResolve)
await this.tableBuiltPromise
// this.$refs.abgabeTable.tabulator.setColumns(this.abgabeTableOptions.columns)
this.loadProjektarbeiten()
// window.addEventListener("resize", this.redrawHandler);
// this.$refs.verticalsplit.collapseBottom()
},
redrawHandler() {
console.log('redrawHandler')
this.$refs.abgabeTable?.tabulator.setColumns(this.$refs.abgabeTable?.tabulator.getColumnDefinitions())
this.$refs.abgabeTable?.tabulator.redraw(true)
getAccTabHeaderForProjektarbeit(projektarbeit) {
let title = ''
title += projektarbeit.titel
return title
}
},
watch: {
@@ -355,9 +309,6 @@ export const AbgabetoolStudent = {
mounted() {
this.setupMounted()
},
unmounted() {
// window.removeEventListener("resize", this.redrawHandler);
},
template: `
<bs-modal ref="modalContainerAbgabeDetail" class="bootstrap-prompt"
@@ -375,16 +326,66 @@ export const AbgabetoolStudent = {
<h2>{{$p.t('abgabetool/abgabetoolTitle')}}</h2>
<hr>
<core-filter-cmpt
@uuidDefined="handleUuidDefined"
:title="''"
ref="abgabeTable"
:tabulator-options="abgabeTableOptions"
:tabulator-events="abgabeTableEventHandlers"
tableOnly
:sideMenu="false"
/>
<div v-if="projektarbeiten === null || projektarbeiten === []">
Keine Projektarbeiten gefunden!
</div>
<Accordion :multiple="true" :activeIndex="[0]">
<template v-for="projektarbeit in projektarbeiten">
<AccordionTab :header="getAccTabHeaderForProjektarbeit(projektarbeit)" style="padding: 0px;">
<div class="row">
<div class="col-4 col-md-3 fw-bold">{{$p.t('abgabetool/c4details')}}</div>
<div class="col-8 col-md-9">
<button @click="setDetailComponent(projektarbeit.details)" class="btn btn-primary">
Projektdetails öffnen <a><i class="fa fa-folder-open"></i></a>
</button>
</div>
</div>
<div class="row mt-2">
<div class="col-4 col-md-3 fw-bold">{{$p.t('abgabetool/c4beurteilung')}}</div>
<div class="col-8 col-md-9">
<a v-if="projektarbeit.beurteilung"><i class="fa fa-file-pdf" style="color:#00649C"></i></a>
<a v-else>Keine Beurteilung vorhanden</a>
</div>
</div>
<div class="row mt-2">
<div class="col-4 col-md-3 fw-bold">{{$p.t('abgabetool/c4sem')}}</div>
<div class="col-8 col-md-9">
{{ projektarbeit.sem }}
</div>
</div>
<div class="row mt-2">
<div class="col-4 col-md-3 fw-bold">{{$p.t('abgabetool/c4stg')}}</div>
<div class="col-8 col-md-9">
<div class="col-1 d-flex justify-content-start align-items-start">
{{ projektarbeit.stg }}
</div>
</div>
</div>
<div class="row mt-2">
<div class="col-4 col-md-3 fw-bold">{{$p.t('abgabetool/c4betreuer')}}</div>
<div class="col-8 col-md-9">
{{ projektarbeit.betreuer }}
</div>
</div>
<div class="row mt-2">
<div class="col-4 col-md-3 fw-bold">{{$p.t('abgabetool/c4projekttyp')}}</div>
<div class="col-8 col-md-9">
{{ projektarbeit.projekttypbezeichnung }}
</div>
</div>
<div class="row mt-2">
<div class="col-4 col-md-3 fw-bold">{{$p.t('abgabetool/c4titel')}}</div>
<div class="col-8 col-md-9">
{{ projektarbeit.titel }}
</div>
</div>
</AccordionTab>
</template>
</Accordion>
`,
};
+20
View File
@@ -42376,6 +42376,26 @@ array(
)
)
),
array(
'app' => 'core',
'category' => 'abgabetool',
'phrase' => 'c4notizQualGate',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => "Notizen Quality Gate",
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Notes Quality Gate',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'abgabetool',