Compare commits

..

7 Commits

Author SHA1 Message Date
ma0068 e23cadf39d use new api for getUri 2026-03-25 15:04:02 +01:00
ma0068 9b1774fabe refactor deprecated functions of LvUebersicht 2026-03-25 13:23:53 +01:00
ma0068 2112506832 refactor function deleteFile and delete comment 2026-03-25 10:37:24 +01:00
ma0068 bea4e2cf34 update comments 2026-03-24 14:05:26 +01:00
ma0068 b0da4e7dc5 update comments for notiz factory 2026-03-24 13:57:39 +01:00
Harald Bamberger 9e6c15a10d Merge branch 'bug-76010/StudVW_Archivieren_Ausbildungsvertrag_Aufgenommene' 2026-03-19 15:41:44 +01:00
ma0068 7603f8f12b Bugfix: use null instead of empty string, provide kuerzel 2026-03-18 14:32:09 +01:00
13 changed files with 150 additions and 359 deletions
@@ -220,7 +220,7 @@ class Documents extends FHCAPI_Controller
'gedruckt' => true,
'insertamum' => date('c'),
'insertvon' => getAuthUID(),
'uid' => $this->input->post_get('uid') ?: '',
'uid' => $this->input->post_get('uid') ?: null,
'archiv' => true,
'signiert' => !!$sign_user,
'stud_selfservice' => $vorlage->stud_selfservice
@@ -334,6 +334,7 @@ class Documents extends FHCAPI_Controller
if ($prestudent_id) {
$this->load->model('crm/prestudent_model', 'PrestudentModel');
$this->PrestudentModel->addJoin('public.tbl_studiengang', 'studiengang_kz', 'LEFT');
$this->PrestudentModel->addSelect('tbl_prestudent.*, UPPER(typ || kurzbz) AS kuerzel');
$result = $this->PrestudentModel->load($prestudent_id);
$prestudent = current($this->getDataOrTerminateWithError($result));
@@ -305,23 +305,4 @@
/* If you use hover rows, you need to ensure the sticky cell matches the hover color */
#abgabetable .tabulator-row:hover .tabulator-cell.sticky-col {
background-color: #ccc; /* Match your existing hover color */
}
.tabulator-cell {
container-type: inline-size;
}
.tabulator-col-title {
container-type: inline-size;
}
@container (max-width: 100px) {
.full-text {
display: none !important;
}
.short-text {
display: inline-block !important;
width: 100%;
}
}
+38
View File
@@ -0,0 +1,38 @@
/**
* 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 {
getAllStudienSemester(studiensemester, studiengang, semester, studienplan) {
return {
method: 'get',
url: 'api/frontend/v1/Studium/getStudienAllSemester/',
params: {studiensemester, studiengang, semester, studienplan}
};
},
getLvPlanForStudiensemester(studiensemester, lvid) {
return {
method: 'get',
url: '/api/frontend/v1/LvPlan/getLvPlanForStudiensemester/'+ studiensemester + '/' + lvid
};
},
getLvEvaluierungInfo(studiensemester_kurzbz, lvid) {
return {
method: 'get',
url: 'api/frontend/v1/Studium/getLvEvaluierungInfo/' + studiensemester_kurzbz + '/' + lvid
};
},
}
-1
View File
@@ -60,7 +60,6 @@ export default {
};
},
deleteFile(akte_id){
console.log("in deleteFile " + akte_id);
return {
method: 'post',
url: 'api/frontend/v1/stv/dokumente/deleteAkte/' + akte_id,
@@ -656,7 +656,6 @@ export const AbgabeMitarbeiterDetail = {
:enable-time-picker="false"
locale="de"
format="dd.MM.yyyy"
model-type="yyyy-MM-dd"
:text-input="true"
auto-apply>
</VueDatePicker>
@@ -807,7 +806,6 @@ export const AbgabeMitarbeiterDetail = {
:enable-time-picker="false"
locale="de"
format="dd.MM.yyyy"
model-type="yyyy-MM-dd"
:text-input="true"
auto-apply>
</VueDatePicker>
@@ -876,7 +874,6 @@ export const AbgabeMitarbeiterDetail = {
:disabled="true"
locale="de"
format="dd.MM.yyyy"
model-type="yyyy-MM-dd"
>
</VueDatePicker>
</div>
@@ -53,9 +53,7 @@ export const AbgabetoolAssistenz = {
},
data() {
return {
count: 0,
filteredcount: 0,
selectedcount: 0,
tableData: null,
studiensemesterOptions: null,
allSem: null,
curSem: null,
@@ -85,7 +83,7 @@ export const AbgabetoolAssistenz = {
allowedNotenOptions: null,
notenOptionsNonFinal: null,
serienTermin: Vue.reactive({
datum: new Date().toISOString().split('T')[0],
datum: new Date(),
bezeichnung: {
paabgabetyp_kurzbz: 'zwischen',
bezeichnung: 'Zwischenabgabe'
@@ -187,69 +185,45 @@ export const AbgabetoolAssistenz = {
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4vorname'))), field: 'student_vorname', headerFilter: true, formatter: this.centeredTextFormatter,widthGrow: 1},
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4nachname'))), field: 'student_nachname', headerFilter: true, formatter: this.centeredTextFormatter, widthGrow: 1},
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4studstatus'))), field: 'studienstatus', headerFilter: true, formatter: this.centeredTextFormatter,widthGrow: 1},
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4orgformv2'))), field: 'orgform', headerFilter: true, formatter: this.centeredTextFormatter,widthGrow: 1},
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4orgform'))), field: 'orgform', headerFilter: true, formatter: this.centeredTextFormatter,widthGrow: 1},
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4projekttyp'))), field: 'projekttyp_kurzbz', formatter: this.centeredTextFormatter, widthGrow: 1},
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4stg'))), field: 'stg', headerFilter: true, formatter: this.centeredTextFormatter, widthGrow: 1},
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4note'))), field: 'note_bez', headerFilter: true,
formatter: this.centeredTextFormatter, widthGrow: 1},
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4sem'))), field: 'studiensemester_kurzbz', headerFilter: true, formatter: this.centeredTextFormatter, widthGrow: 1},
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4titel'))), field: 'titel', headerFilter: true, formatter: this.centeredTextFormatter, widthGrow: 1},
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4erstbetreuerv2'))), field: 'erstbetreuer', headerFilter: true, formatter: this.centeredTextFormatter, widthGrow: 1, visible: false},
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4erstbetreuerv2'))), field: 'erstbetreuer', headerFilter: true, formatter: this.centeredTextFormatter, widthGrow: 1},
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4erstbetreuerTitelPre'))), field: 'betreuer_titelpre', headerFilter: true, formatter: this.centeredTextFormatter, widthGrow: 1, visible: false},
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4erstbetreuerVorname'))), field: 'betreuer_vorname', headerFilter: true, formatter: this.centeredTextFormatter, widthGrow: 1, visible: true},
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4erstbetreuerNachname'))), field: 'betreuer_nachname', headerFilter: true, formatter: this.centeredTextFormatter, widthGrow: 1, visible: true},
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4erstbetreuerVorname'))), field: 'betreuer_vorname', headerFilter: true, formatter: this.centeredTextFormatter, widthGrow: 1, visible: false},
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4erstbetreuerNachname'))), field: 'betreuer_nachname', headerFilter: true, formatter: this.centeredTextFormatter, widthGrow: 1, visible: false},
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4erstbetreuerTitelPost'))), field: 'betreuer_titelpost', headerFilter: true, formatter: this.centeredTextFormatter, widthGrow: 1, visible: false},
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4zweitbetreuerv2'))), field: 'zweitbetreuer', headerFilter: true, formatter: this.centeredTextFormatter, widthGrow: 1, visible: false},
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4zweitbetreuerv2'))), field: 'zweitbetreuer', headerFilter: true, formatter: this.centeredTextFormatter, widthGrow: 1},
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4zweitbetreuerTitelPre'))), field: 'zweitbetreuer_titelpre', headerFilter: true, formatter: this.centeredTextFormatter, widthGrow: 1, visible: false},
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4zweitbetreuerVorname'))), field: 'zweitbetreuer_vorname', headerFilter: true, formatter: this.centeredTextFormatter, widthGrow: 1, visible: true},
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4zweitbetreuerNachname'))), field: 'zweitbetreuer_nachname', headerFilter: true, formatter: this.centeredTextFormatter, widthGrow: 1, visible: true},
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4zweitbetreuerVorname'))), field: 'zweitbetreuer_vorname', headerFilter: true, formatter: this.centeredTextFormatter, widthGrow: 1, visible: false},
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4zweitbetreuerNachname'))), field: 'zweitbetreuer_nachname', headerFilter: true, formatter: this.centeredTextFormatter, widthGrow: 1, visible: false},
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4zweitbetreuerTitelPost'))), field: 'zweitbetreuer_titelpost', headerFilter: true, formatter: this.centeredTextFormatter, widthGrow: 1, visible: false},
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4prevAbgabetermin'))),
headerFilter: dateFilter,
headerFilterFunc: this.headerFilterTerminCol,
sorter: this.sortFuncTerminCol,
tooltip: this.toolTipFuncPrevTermin,
field: 'prevTermin', formatter: this.abgabterminFormatter, widthGrow: 1, width: 250},
field: 'prevTermin', formatter: this.abgabterminFormatter, widthGrow: 1, width: 250, tooltip: false},
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4nextAbgabetermin'))), field: 'nextTermin',
headerFilter: dateFilter,
headerFilterFunc: this.headerFilterTerminCol,
sorter: this.sortFuncTerminCol,
tooltip: this.toolTipFuncNextTermin,
formatter: this.abgabterminFormatter, widthGrow: 1, width: 250},
formatter: this.abgabterminFormatter, widthGrow: 1, width: 250, tooltip: false},
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4qgate1Status'))),
headerFilter: 'list',
headerFilterParams: { valuesLookup: this.getQGateStatusList },
field: 'qgate1Status',
formatter: this.centeredTextFormatter,
titleFormatter: this.shortLongTitleFormatter,
titleFormatterParams: {
shortForm: 'QG1'
},
widthGrow: 1, width: 220,
tooltip: (e, cell) => {
const data = cell.getData();
return data.qgate1Status
}
},
field: 'qgate1Status', formatter: this.centeredTextFormatter, widthGrow: 1, width: 220, tooltip: false},
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4qgate2Status'))),
headerFilter: 'list',
headerFilterParams: { valuesLookup: this.getQGateStatusList },
field: 'qgate2Status',
formatter: this.centeredTextFormatter,
titleFormatter: this.shortLongTitleFormatter,
titleFormatterParams: {
shortForm: 'QG2'
},
widthGrow: 1, width: 220,
tooltip: (e, cell) => {
const data = cell.getData();
return data.qgate2Status
}
},
field: 'qgate2Status', formatter: this.centeredTextFormatter, widthGrow: 1, width: 220, tooltip: false},
],
persistence: false,
persistenceID: "abgabetool_2026_03_16"
@@ -268,71 +242,11 @@ export const AbgabetoolAssistenz = {
})
this.selectedData = data
this.selectedcount = data.length;
}
},
{
event: 'dataFiltered',
handler: (filters, rows) => this.filteredcount = rows.length
}
]};
},
methods: {
shortLongTitleFormatter(cell, formatterParams, onRendered) {
const longForm = cell.getValue()
const shortForm = formatterParams?.shortForm
if(longForm && shortForm) {
return `<span class="full-text" style="max-width: 100%; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; margin: 0px;">
${longForm}
</span>
<span class="short-text" style="font-weight: bold; display: none;">
${shortForm}
</span>`
} else {
return `<span class="full-text" style="max-width: 100%; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; margin: 0px;">
${longForm}
</span>`
}
},
toolTipFuncPrevTermin(e, cell, onRendered) {
const data = cell.getData();
return this.mapDateStyleToTabulatorTooltip(data.prevTermin.dateStyle);
},
toolTipFuncNextTermin(e, cell, onRendered) {
const data = cell.getData();
return this.mapDateStyleToTabulatorTooltip(data.nextTermin.dateStyle);
},
mapDateStyleToTabulatorTooltip(dateStyleString) {
switch(dateStyleString) {
case 'bestanden':
return this.$p.t('abgabetool/c4tooltipBestanden')
break;
case 'nichtbestanden':
return this.$p.t('abgabetool/c4tooltipNichtBestanden')
break;
case 'beurteilungerforderlich':
return this.$p.t('abgabetool/c4tooltipBeurteilungerforderlich')
break;
case 'verspaetet':
return this.$p.t('abgabetool/c4tooltipVerspaetet')
break;
case 'abgegeben':
return this.$p.t('abgabetool/c4tooltipAbgegeben')
break;
case 'verpasst':
return this.$p.t('abgabetool/c4tooltipVerpasst')
break;
case 'abzugeben':
return this.$p.t('abgabetool/c4tooltipAbzugeben')
break;
case 'standard':
return this.$p.t('abgabetool/c4tooltipStandardv2')
break;
default: return ''
}
},
handlePaUpdated(projektarbeit) {
this.checkAbgabetermineProjektarbeit(projektarbeit)
this.$refs.abgabeTable.tabulator.redraw(true)
@@ -514,32 +428,6 @@ export const AbgabetoolAssistenz = {
projekt.qgate2StatusRank = 1
}
})
// set shorthand statuscode once real status has been determined
projekt.qgate1StatusShort = this.mapRankToShortStatus(projekt.qgate1StatusRank)
projekt.qgate2StatusShort = this.mapRankToShortStatus(projekt.qgate2StatusRank)
},
mapRankToShortStatus(rank) {
switch(rank){
case 0: // kein termin vorhanden
return '--'
break;
case 1: // noch nicht stattgefunden
return 'o'
break;
case 2: // noch nicht abgegeben
return '?'
break;
case 3: // noch nicht benotet
return '~'
break;
case 4: // negativ benotet
return '-'
break;
case 5: // positiv benotet
return '+'
break;
}
},
getItemBezeichnung(item){
if(!item.bezeichnung) return ''
@@ -832,7 +720,7 @@ export const AbgabetoolAssistenz = {
this.saving = true
this.serienTermin.fixtermin = !this.serienTermin.invertedFixtermin
this.$api.call(ApiAbgabe.postSerientermin(
this.serienTermin.datum,
this.serienTermin.datum.toISOString(),
this.serienTermin.bezeichnung.paabgabetyp_kurzbz,
this.serienTermin.bezeichnung.bezeichnung,
this.serienTermin.kurzbz,
@@ -1013,37 +901,37 @@ export const AbgabetoolAssistenz = {
this.$refs.drawer.show()
},
centeredTextFormatter(cell) {
const longForm = cell.getValue()
if(!longForm) return
const data = cell.getData()
const entry = Object.entries(data).find(entry => entry[1] == longForm)
const val = cell.getValue()
if(!val) return
// shortFormKey must have same keyname as longForm but with 'Short' appended
const shortForm = data[entry[0]+'Short']
if(shortForm && longForm) {
return `<div style="display: flex; justify-content: start; align-items: center; height: 100%; width: 100%;">
<span class="full-text" style="max-width: 100%; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; margin: 0px;">
${longForm}
</span>
<span class="short-text" style="font-weight: bold; display: none;">
${shortForm}
</span>
</div>`;
} else {
return '<div style="display: flex; justify-content: start; align-items: center; height: 100%">' +
'<p style="max-width: 100%; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; margin: 0px;">'+longForm+'</p></div>'
}
return '<div style="display: flex; justify-content: center; align-items: center; height: 100%">' +
'<p style="max-width: 100%; overflow-wrap: break-word; word-break: break-word; white-space: normal; margin: 0px; text-align: center">'+val+'</p></div>'
},
detailFormatter(cell) {
return '<div style="display: flex; justify-content: start; align-items: center; height: 100%">' +
return '<div style="display: flex; justify-content: center; align-items: center; height: 100%">' +
'<a><i class="fa fa-folder-open" style="color:#00649C"></i></a></div>'
},
mailFormatter(cell) {
const val = cell.getValue()
return '<div style="display: flex; justify-content: center; align-items: center; height: 100%">' +
'<a href='+val+'><i class="fa fa-envelope" style="color:#00649C"></i></a></div>'
},
timelineFormatter() {
return '<div style="display: flex; justify-content: center; align-items: center; height: 100%">' +
'<a><i class="fa fa-timeline" style="color:#00649C"></i></a></div>'
},
beurteilungFormatter(cell) {
const val = cell.getValue()
if(val) {
return '<div style="display: flex; justify-content: center; align-items: center; height: 100%">' +
'<a><i class="fa fa-file-pdf" style="color:#00649C"></i></a></div>'
} else return '-'
},
pkzTextFormatter(cell) {
const val = cell.getValue()
return '<div style="display: flex; justify-content: start; align-items: center; height: 100%">' +
'<a style="max-width: 100%; text-overflow: ellipsis; overflow: hidden; white-space: nowrap;">'+val+'</a></div>'
return '<div style="display: flex; justify-content: center; align-items: center; height: 100%">' +
'<a style="max-width: 100%; word-wrap: break-word; white-space: normal;">'+val+'</a></div>'
},
abgabterminFormatter(cell) {
const val = cell.getValue()
@@ -1080,14 +968,14 @@ export const AbgabetoolAssistenz = {
const bezeichnung = val.bezeichnung?.bezeichnung ?? val.bezeichnung
return '<div style="display: flex; height: 100%">' +
'<div class=' + val.dateStyle + "-header" + ' style="min-width:48px; height: 100%; padding: 0px; display: flex; align-items: center; justify-content: center;">' +
'<div class=' + val.dateStyle + "-header" + ' style="width:48px; height: 100%; padding: 0px; display: flex; align-items: center; justify-content: center;">' +
icon +
'</div>' +
'<div style="margin-left: 4px;">' +
'<p style="max-width: 100%; text-overflow: ellipsis; overflow: hidden; white-space: nowrap;">'+bezeichnung+' - '+ this.formatDate(val.datum)+'</p>' +
'<p style="max-width: 100%; word-wrap: break-word; white-space: normal;">'+bezeichnung+' - '+ this.formatDate(val.datum)+'</p>' +
'</div>'+
'</div>'
} else {
return ''
}
@@ -1113,14 +1001,14 @@ export const AbgabetoolAssistenz = {
return projekt.zweitbetreuer_full_name ?? ''
},
async setupData(data){
this.projektarbeiten = data[0]
this.domain = data[1]
this.projektarbeiten = this.mapProjekteToTableData(data[0])
this.count = this.projektarbeiten.length
this.tableData = this.mapProjekteToTableData(this.projektarbeiten)
await this.tableBuiltPromise
this.$refs.abgabeTable.tabulator.setData(this.projektarbeiten);
this.$refs.abgabeTable.tabulator.setData(this.tableData);
},
loadProjektarbeiten(all = false, callback) {
this.loading = true
@@ -1174,17 +1062,6 @@ export const AbgabetoolAssistenz = {
},
},
computed: {
countsToHTML() {
return this.$p.t('global/ausgewaehlt')
+ ': <strong>' + (this.selectedcount || 0) + '</strong>'
+ ' | '
+ this.$p.t('global/gefiltert')
+ ': '
+ '<strong>' + (this.filteredcount || 0) + '</strong>'
+ ' | '
+ this.$p.t('global/gesamt')
+ ': <strong>' + (this.count || 0) + '</strong>';
},
emailItems() {
const menu = []
@@ -1385,7 +1262,6 @@ export const AbgabetoolAssistenz = {
:clearable="false"
locale="de"
format="dd.MM.yyyy"
model-type="yyyy-MM-dd"
:enable-time-picker="false"
:text-input="true"
auto-apply>
@@ -1604,7 +1480,6 @@ export const AbgabetoolAssistenz = {
:title="''"
@uuidDefined="handleUuidDefined"
ref="abgabeTable"
:description="countsToHTML"
:newBtnShow="true"
:newBtnLabel="$p.t('abgabetool/neueTerminserie')"
:newBtnDisabled="!selectedData.length"
@@ -43,6 +43,7 @@ export const AbgabetoolMitarbeiter = {
},
data() {
return {
tableData: null,
abgabetypenBetreuer: null,
detailIsFullscreen: false,
phrasenPromise: null,
@@ -57,7 +58,7 @@ export const AbgabetoolMitarbeiter = {
allowedNotenOptions: null,
notenOptionsNonFinal: null,
serienTermin: Vue.reactive({
datum: new Date().toISOString().split('T')[0],
datum: new Date(),
bezeichnung: {
paabgabetyp_kurzbz: 'zwischen',
bezeichnung: 'Zwischenabgabe'
@@ -152,40 +153,20 @@ export const AbgabetoolMitarbeiter = {
headerFilter: dateFilter,
headerFilterFunc: this.headerFilterTerminCol,
sorter: this.sortFuncTerminCol,
tooltip: this.toolTipFuncPrevTermin,
formatter: this.abgabterminFormatter, widthGrow: 1, width: 250},
formatter: this.abgabterminFormatter, widthGrow: 1, width: 250, tooltip: false},
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4nextAbgabetermin'))), field: 'nextTermin',
headerFilter: dateFilter,
headerFilterFunc: this.headerFilterTerminCol,
sorter: this.sortFuncTerminCol,
tooltip: this.toolTipFuncNextTermin,
formatter: this.abgabterminFormatter, widthGrow: 1, width: 250},
formatter: this.abgabterminFormatter, widthGrow: 1, width: 250, tooltip: false},
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4qgate1Status'))),
headerFilter: 'list',
headerFilterParams: { valuesLookup: this.getQGateStatusList },
titleFormatter: this.shortLongTitleFormatter,
titleFormatterParams: {
shortForm: 'QG1'
},
field: 'qgate1Status', formatter: this.centeredTextFormatter, widthGrow: 1, width: 220,
tooltip: (e, cell) => {
const data = cell.getData();
return data.qgate1Status
}
},
headerFilterParams: { valuesLookup: this.getQGateStatusList },
field: 'qgate1Status', formatter: this.centeredTextFormatter, widthGrow: 1, width: 220, tooltip: false},
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4qgate2Status'))),
headerFilter: 'list',
headerFilterParams: { valuesLookup: this.getQGateStatusList },
titleFormatter: this.shortLongTitleFormatter,
titleFormatterParams: {
shortForm: 'QG2'
},
field: 'qgate2Status', formatter: this.centeredTextFormatter, widthGrow: 1, width: 220,
tooltip: (e, cell) => {
const data = cell.getData();
return data.qgate2Status
}
}
headerFilterParams: { valuesLookup: this.getQGateStatusList },
field: 'qgate2Status', formatter: this.centeredTextFormatter, widthGrow: 1, width: 220, tooltip: false}
],
persistence: false,
persistenceID: 'abgabeTableBetreuer2026-02-26'
@@ -224,61 +205,6 @@ export const AbgabetoolMitarbeiter = {
]};
},
methods: {
shortLongTitleFormatter(cell, formatterParams, onRendered) {
const longForm = cell.getValue()
const shortForm = formatterParams?.shortForm
if(longForm && shortForm) {
return `<span class="full-text" style="max-width: 100%; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; margin: 0px;">
${longForm}
</span>
<span class="short-text" style="font-weight: bold; display: none;">
${shortForm}
</span>`
} else {
return `<span class="full-text" style="max-width: 100%; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; margin: 0px;">
${longForm}
</span>`
}
},
toolTipFuncPrevTermin(e, cell, onRendered) {
const data = cell.getData();
return this.mapDateStyleToTabulatorTooltip(data.prevTermin.dateStyle);
},
toolTipFuncNextTermin(e, cell, onRendered) {
const data = cell.getData();
return this.mapDateStyleToTabulatorTooltip(data.nextTermin.dateStyle);
},
mapDateStyleToTabulatorTooltip(dateStyleString) {
switch(dateStyleString) {
case 'bestanden':
return this.$p.t('abgabetool/c4tooltipBestanden')
break;
case 'nichtbestanden':
return this.$p.t('abgabetool/c4tooltipNichtBestanden')
break;
case 'beurteilungerforderlich':
return this.$p.t('abgabetool/c4tooltipBeurteilungerforderlich')
break;
case 'verspaetet':
return this.$p.t('abgabetool/c4tooltipVerspaetet')
break;
case 'abgegeben':
return this.$p.t('abgabetool/c4tooltipAbgegeben')
break;
case 'verpasst':
return this.$p.t('abgabetool/c4tooltipVerpasst')
break;
case 'abzugeben':
return this.$p.t('abgabetool/c4tooltipAbzugeben')
break;
case 'standard':
return this.$p.t('abgabetool/c4tooltipStandardv2')
break;
default: return ''
}
},
handlePaUpdated(projektarbeit) {
this.checkAbgabetermineProjektarbeit(projektarbeit)
this.$refs.abgabeTable.tabulator.redraw(true)
@@ -525,32 +451,6 @@ export const AbgabetoolMitarbeiter = {
projekt.qgate2StatusRank = 1
}
})
// set shorthand statuscode once real status has been determined
projekt.qgate1StatusShort = this.mapRankToShortStatus(projekt.qgate1StatusRank)
projekt.qgate2StatusShort = this.mapRankToShortStatus(projekt.qgate2StatusRank)
},
mapRankToShortStatus(rank) {
switch(rank){
case 0: // kein termin vorhanden
return '--'
break;
case 1: // noch nicht stattgefunden
return 'o'
break;
case 2: // noch nicht abgegeben
return '?'
break;
case 3: // noch nicht benotet
return '~'
break;
case 4: // negativ benotet
return '-'
break;
case 5: // positiv benotet
return '+'
break;
}
},
checkAbgabetermineProjektarbeit(projekt) {
const now = luxon.DateTime.now()
@@ -617,11 +517,11 @@ export const AbgabetoolMitarbeiter = {
const bezeichnung = val.bezeichnung?.bezeichnung ?? val.bezeichnung
return '<div style="display: flex; height: 100%">' +
'<div class=' + val.dateStyle + "-header" + ' style="min-width:48px; height: 100%; padding: 0px; display: flex; align-items: center; justify-content: center;">' +
icon +
'<div class=' + val.dateStyle + "-header" + ' style="width:48px; height: 100%; padding: 0px; display: flex; align-items: center; justify-content: center;">' +
icon +
'</div>' +
'<div style="margin-left: 4px;">' +
'<p style="max-width: 100%; text-overflow: ellipsis; overflow: hidden; white-space: nowrap;">'+bezeichnung+' - '+ this.formatDate(val.datum)+'</p>' +
'<p style="max-width: 100%; word-wrap: break-word; white-space: normal;">'+bezeichnung+' - '+ this.formatDate(val.datum)+'</p>' +
'</div>'+
'</div>'
@@ -712,7 +612,7 @@ export const AbgabetoolMitarbeiter = {
addSeries() {
this.saving = true
this.$api.call(ApiAbgabe.postSerientermin(
this.serienTermin.datum,
this.serienTermin.datum.toISOString(),
this.serienTermin.bezeichnung.paabgabetyp_kurzbz,
this.serienTermin.bezeichnung.bezeichnung,
this.serienTermin.kurzbz,
@@ -827,37 +727,28 @@ export const AbgabetoolMitarbeiter = {
},
centeredTextFormatter(cell) {
const longForm = cell.getValue()
if(!longForm) return
const data = cell.getData()
const entry = Object.entries(data).find(entry => entry[1] == longForm)
// shortFormKey must have same keyname as longForm but with 'Short' appended
const shortForm = data[entry[0]+'Short']
if(shortForm && longForm) {
return `<div style="display: flex; justify-content: start; align-items: center; height: 100%; width: 100%;">
<span class="full-text" style="max-width: 100%; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; margin: 0px;">
${longForm}
</span>
<span class="short-text" style="font-weight: bold; display: none;">
${shortForm}
</span>
</div>`;
} else {
return '<div style="display: flex; justify-content: start; align-items: center; height: 100%">' +
'<p style="max-width: 100%; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; margin: 0px;">'+longForm+'</p></div>'
}
const val = cell.getValue()
if(!val) return
return '<div style="display: flex; justify-content: center; align-items: center; height: 100%">' +
'<p style="max-width: 100%; width: 100%; overflow-wrap: break-word; word-break: break-word; white-space: normal; margin: 0px; text-align: center">'+val+'</p></div>'
},
detailFormatter(cell) {
return '<div style="display: flex; justify-content: start; align-items: center; height: 100%">' +
return '<div style="display: flex; justify-content: center; align-items: center; height: 100%">' +
'<a><i class="fa fa-folder-open" style="color:#00649C"></i></a></div>'
},
beurteilungFormatter(cell) {
const val = cell.getValue()
if(val) {
return '<div style="display: flex; justify-content: center; align-items: center; height: 100%">' +
'<a><i class="fa fa-file-pdf" style="color:#00649C"></i></a></div>'
} else return '-'
},
pkzTextFormatter(cell) {
const val = cell.getValue()
return '<div style="display: flex; justify-content: start; align-items: center; height: 100%">' +
'<a style="max-width: 100%; text-overflow: ellipsis; overflow: hidden; white-space: nowrap;">'+val+'</a></div>'
return '<div style="display: flex; justify-content: center; align-items: center; height: 100%">' +
'<a style="max-width: 100%; word-wrap: break-word; white-space: normal;">'+val+'</a></div>'
},
tableResolve(resolve) {
this.tableBuiltResolve = resolve
@@ -874,9 +765,10 @@ export const AbgabetoolMitarbeiter = {
setupData(data){
this.projektarbeiten = data[0]
this.domain = data[1]
this.projektarbeiten = data[0]?.retval?.map(projekt => {
this.tableData = data[0]?.retval?.map(projekt => {
this.checkAbgabetermineProjektarbeit(projekt)
projekt.selectable = projekt.betreuerart_kurzbz !== 'Zweitbegutachter'
@@ -897,7 +789,7 @@ export const AbgabetoolMitarbeiter = {
})
this.$refs.abgabeTable.tabulator.setColumns(this.abgabeTableOptions.columns)
this.$refs.abgabeTable.tabulator.setData(this.projektarbeiten);
this.$refs.abgabeTable.tabulator.setData(this.tableData);
},
loadProjektarbeiten(all = false, callback) {
this.$api.call(ApiAbgabe.getMitarbeiterProjektarbeiten(all))
@@ -1043,7 +935,6 @@ export const AbgabetoolMitarbeiter = {
:enable-time-picker="false"
locale="de"
format="dd.MM.yyyy"
model-type="yyyy-MM-dd"
:text-input="true"
auto-apply>
</VueDatePicker>
@@ -2,6 +2,7 @@ import BsModal from "../../Bootstrap/Modal.js";
import LvMenu from "./LvMenu.js";
import ApiAddons from '../../../api/factory/addons.js';
import ApiCisStudium from '../../../api/factory/cis/studium.js';
export default {
@@ -63,7 +64,8 @@ export default {
// check lv evaluierung info
if (this.studium_studiensemester) {
this.$fhcApi.factory.studium.getLvEvaluierungInfo(this.studium_studiensemester, this.event.lehreinheit_id ?? this.event.lehrveranstaltung_id)
this.$api
.call(ApiCisStudium.getLvEvaluierungInfo(this.studium_studiensemester, this.event.lehreinheit_id ?? this.event.lehrveranstaltung_id))
.then(data => data.data)
.then(res => {
this.lvEvaluierungMessage = res.message;
@@ -72,7 +74,8 @@ export default {
// check if the lv has lvplan entries for this studiensemester
if (this.studiensemester && this.event) {
return this.$fhcApi.factory.studium.getLvPlanForStudiensemester(this.studiensemester, this.event.lehreinheit_id ?? this.event.lehrveranstaltung_id)
return this.$api
.call(ApiCisStudium.getLvPlanForStudiensemester(this.studiensemester, this.event.lehreinheit_id ?? this.event.lehrveranstaltung_id))
.then(data => data.data)
.then(res => {
if (Array.isArray(res) && res.length > 0) {
+16 -11
View File
@@ -1,4 +1,5 @@
import LvUebersicht from "../Mylv/LvUebersicht.js";
import ApiCisStudium from '../../../api/factory/cis/studium.js';
export default {
@@ -97,28 +98,32 @@ export default {
return value;
},
changeSelectedStudienSemester(studiensemester_kurzbz) {
this.$fhcApi.factory.studium.getAllStudienSemester(studiensemester_kurzbz, this.selectedStudiengang, this.selectedSemester, this.selectedStudienordnung)
return this.$api
.call(ApiCisStudium.getAllStudienSemester(studiensemester_kurzbz, this.selectedStudiengang, this.selectedSemester, this.selectedStudienordnung))
.then(data => data.data)
.then(res => {
this.extractPropertyValues(res);
})
},
changeSelectedStudienGang(studiengang_kz) {
this.$fhcApi.factory.studium.getAllStudienSemester(this.selectedStudiensemester, studiengang_kz, this.selectedSemester, this.selectedStudienordnung)
return this.$api
.call(ApiCisStudium.getAllStudienSemester(this.selectedStudiensemester, studiengang_kz, this.selectedSemester, this.selectedStudienordnung))
.then(data => data.data)
.then(res => {
this.extractPropertyValues(res);
})
},
changeSelectedSemester(semester) {
this.$fhcApi.factory.studium.getAllStudienSemester(this.selectedStudiensemester, this.selectedStudiengang, semester, this.selectedStudienordnung)
return this.$api
.call(ApiCisStudium.getAllStudienSemester(this.selectedStudiensemester, this.selectedStudiengang, semester, this.selectedStudienordnung))
.then(data => data.data)
.then(res => {
this.extractPropertyValues(res);
})
},
changeSelectedStudienPlan(studienplan_id) {
this.$fhcApi.factory.studium.getAllStudienSemester(this.selectedStudiensemester, this.selectedStudiengang, this.selectedSemester, studienplan_id)
return this.$api
.call(ApiCisStudium.getAllStudienSemester(this.selectedStudiensemester, this.selectedStudiengang, this.selectedSemester, studienplan_id))
.then(data => data.data)
.then(res => {
this.extractPropertyValues(res);
@@ -209,7 +214,7 @@ export default {
default:
return `${studiensemester}`;
}
}
},
},
computed:{
@@ -256,12 +261,12 @@ export default {
const studienordnung = JSON.parse(this.getDataFromLocalStorage("studienordnung")) ?? undefined;
// only fetch default data if no data is stored in the local storage
this.$fhcApi.factory.studium.getAllStudienSemester(studiensemester, studiengang, semester, studienordnung)
.then(data => data.data)
.then(res => {
this.extractPropertyValues(res);
})
this.$api
.call(ApiCisStudium.getAllStudienSemester(studiensemester, studiengang, semester, studienordnung))
.then(data => data.data)
.then(res => {
this.extractPropertyValues(res);
})
},
template: `
@@ -306,7 +306,8 @@ export default {
});
},
deleteFile(akte_id){
return this.$fhcApi.factory.stv.documents.deleteFile(akte_id)
return this.$api
.call(ApiStvDocuments.deleteFile(akte_id))
.then(response => {
this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successDelete'));
})
@@ -18,7 +18,7 @@ export default {
template: `
<div class="stv-details-notizen h-100 pb-3">
<!-- Test Version classicFas for enter with one click vs popupModal-->
<!-- Test Version popupModal-->
<core-notiz
class="overflow-hidden"
:endpoint="endpoint"
@@ -32,15 +32,15 @@ export default {
@reload="$emit('update:suffix')"
tabulator-persistence-id="stv-notiz-20260217"
>
</core-notiz>
</core-notiz>
<!--
---------------------------------------------------------------------------------------------
-------------------- DESCRIPTION FOR PARAMETER PROPS ----------------------------------------
---------------------------------------------------------------------------------------------
endpoint: for corecontroller: eg: :endpoint="$fhcApi.factory.notiz.person"
(...prestudent, ...mitarbeiter, ...bestellung, ...lehreinheit, ...projekt, ...projektphase, ...projekttask, ...anrechnung)
endpoints for coreControllers: prestudent, mitarbeiter, bestellung, lehreinheit, projekt, projektphase, projekttask, anrechnung
import ApiNotiz[...] from '../../../../api/factory/notiz/[...].js';
for extensions: write own controller extending core NotizController
@@ -58,7 +58,7 @@ showDocument: if true: section with documentHandling will be displayed
showTinyMCE: if true: section with WYSIWYG Editor for Text will be displayed
visibleColumns: list, which fields shoult be showed as default in filter component
visibleColumns: list, which fields should be shown as default in filter component
fullVersion: :visibleColumns="['titel','text','bearbeiter','verfasser','von','bis','dokumente','erledigt','notiz_id','notizzuordnung_id','id','lastupdate']"
@@ -76,7 +76,7 @@ visibleColumns: list, which fields shoult be showed as default in filter compone
---------------------------------------------------------------------------------------------
<core-notiz
:endpoint="$fhcApi.factory.notiz.mitarbeiter"
:endpoint="endpoint"
ref="formc"
type-id="uid"
:id= "'ma0068'"
@@ -89,7 +89,7 @@ visibleColumns: list, which fields shoult be showed as default in filter compone
</core-notiz>
<core-notiz
:endpoint="$fhcApi.factory.notiz.prestudent"
:endpoint="endpoint"
ref="formc"
type-id="prestudent_id"
:id="modelValue.prestudent_id"
@@ -102,7 +102,7 @@ visibleColumns: list, which fields shoult be showed as default in filter compone
</core-notiz>
<core-notiz
:endpoint="$fhcApi.factory.notiz.projekt"
:endpoint="endpoint"
ref="formc"
type-id="projekt_kurzbz"
:id="'EA74'"
+1 -1
View File
@@ -52,7 +52,7 @@ export default {
let url = this.res.content_url;
if (url.substr(0, 16) == '../index.ci.php/')
url = this.$fhcApi.getUri(url.substr(16));
url = this.$api.getUri(url.substr(16));
else if (url.substr(0, 3) == '../')
url = FHC_JS_DATA_STORAGE_OBJECT.app_root.replace(/\/+$/, '') + url.substr(2);
return '<a href="' + url + '">' + url + '</a>';
+4 -4
View File
@@ -41761,7 +41761,7 @@ array(
array(
'app' => 'core',
'category' => 'abgabetool',
'phrase' => 'c4fehlerAktualitaetProjektarbeit',
'phrase' => 'c4fehlerAktualitaetProjektarbeit ',
'insertvon' => 'system',
'phrases' => array(
array(
@@ -43767,18 +43767,18 @@ array(
array(
'app' => 'core',
'category' => 'abgabetool',
'phrase' => 'c4orgformv2',
'phrase' => 'c4orgform',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => "Organisationsform",
'text' => "Organisationseinheit",
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => "organization form",
'text' => "organization unit",
'description' => '',
'insertvon' => 'system'
)