WIP Abgabetool Mitarbeiter DetailComponent

This commit is contained in:
Johann Hoffmann
2025-04-23 13:59:31 +02:00
parent 91910ef538
commit e28067259b
12 changed files with 853 additions and 22 deletions
+26 -3
View File
@@ -13,8 +13,10 @@ class Abgabetool extends Auth_Controller
public function __construct()
{
parent::__construct([
'index' => ['basis/cis:r'],
'getStudentProjektarbeitAbgabeFile' => ['basis/cis:r']
'index' => self::PERM_LOGGED,
'getStudentProjektarbeitAbgabeFile' => self::PERM_LOGGED,
'Mitarbeiter' => self::PERM_LOGGED,
'Student' => self::PERM_LOGGED
]);
}
@@ -33,7 +35,28 @@ class Abgabetool extends Auth_Controller
$this->load->view('CisRouterView/CisRouterView.php', ['viewData' => $viewData, 'route' => 'Abgabetool']);
}
public function Student()
{
$viewData = array(
'uid'=>getAuthUID(),
);
$this->load->view('CisRouterView/CisRouterView.php', ['viewData' => $viewData, 'route' => 'Abgabetool']);
}
public function Mitarbeiter()
{
$viewData = array(
'uid'=>getAuthUID(),
);
$this->load->view('CisRouterView/CisRouterView.php', ['viewData' => $viewData, 'route' => 'Abgabetool']);
}
public function getStudentProjektarbeitAbgabeFile()
{
$this->_ci =& get_instance();
@@ -42,7 +42,8 @@ class Lehre extends FHCAPI_Controller
'getStudentProjektarbeiten' => self::PERM_LOGGED, // TODO: abgabetool berechtigung?
'getStudentProjektabgaben' => self::PERM_LOGGED,
'postStudentProjektarbeitZwischenabgabe' => self::PERM_LOGGED,
'postStudentProjektarbeitEndupload' => self::PERM_LOGGED
'postStudentProjektarbeitEndupload' => self::PERM_LOGGED,
'getMitarbeiterProjektarbeiten' => self::PERM_LOGGED
]);
$this->load->library('PhrasesLib');
@@ -443,5 +444,34 @@ class Lehre extends FHCAPI_Controller
}
}
}
public function getMitarbeiterProjektarbeiten() {
$this->load->model('education/Projektarbeit_model', 'ProjektarbeitModel');
// if (!isset($uid) || isEmptyString($uid))
// $this->terminateWithError($this->p->t('global', 'wrongParameters'), 'general');
$boolParamStr = $this->input->get('showall');
$trueStrings = ['true', '1'];
$falseStrings = ['false', '0'];
// Handle missing or invalid parameter
if ($boolParamStr === null) {
$this->terminateWithError($this->p->t('global', 'wrongParameters'), 'general');
}
$boolParamStrLower = strtolower($boolParamStr);
if (in_array($boolParamStrLower, $trueStrings, true)) {
$showAllBool = true;
} elseif (in_array($boolParamStrLower, $falseStrings, true)) {
$showAllBool = false;
} else {
// $this->terminateWithError($this->p->t('global', 'wrongParameters'), 'general');
}
$projektarbeiten = $this->ProjektarbeitModel->getMitarbeiterProjektarbeiten(getAuthUID(), $showAllBool);
$this->terminateWithSuccess(array($projektarbeiten, DOMAIN));
}
}
@@ -211,4 +211,34 @@ class Projektarbeit_model extends DB_Model
return $this->execReadOnlyQuery($qry, array($studentUID, $maUID));
}
public function getMitarbeiterProjektarbeiten($uid, $showAll){
$qry = "SELECT
*
FROM
(SELECT tbl_person.vorname, tbl_person.nachname, tbl_studiengang.typ, tbl_studiengang.kurzbz,
tbl_projektarbeit.projekttyp_kurzbz, tbl_projekttyp.bezeichnung, tbl_projektarbeit.titel, tbl_projektarbeit.projektarbeit_id,
tbl_projektbetreuer.betreuerart_kurzbz, tbl_betreuerart.beschreibung AS betreuerart_beschreibung,
tbl_benutzer.uid, tbl_student.matrikelnr, tbl_lehreinheit.studiensemester_kurzbz
FROM lehre.tbl_projektarbeit
LEFT JOIN lehre.tbl_projektbetreuer using(projektarbeit_id)
LEFT JOIN lehre.tbl_betreuerart using(betreuerart_kurzbz)
LEFT JOIN public.tbl_benutzer on(uid=student_uid)
LEFT JOIN public.tbl_student on(public.tbl_benutzer.uid=public.tbl_student.student_uid)
LEFT JOIN public.tbl_person on(tbl_benutzer.person_id=tbl_person.person_id)
LEFT JOIN lehre.tbl_lehreinheit using(lehreinheit_id)
LEFT JOIN lehre.tbl_lehrveranstaltung using(lehrveranstaltung_id)
LEFT JOIN public.tbl_studiengang on(lehre.tbl_lehrveranstaltung.studiengang_kz=public.tbl_studiengang.studiengang_kz)
LEFT JOIN lehre.tbl_projekttyp USING (projekttyp_kurzbz)
WHERE (projekttyp_kurzbz='Bachelor' OR projekttyp_kurzbz='Diplom')
AND tbl_projektbetreuer.person_id IN (SELECT person_id FROM public.tbl_benutzer
WHERE public.tbl_benutzer.person_id=lehre.tbl_projektbetreuer.person_id
AND public.tbl_benutzer.uid= ? )
".($showAll?'':' AND public.tbl_benutzer.aktiv AND lehre.tbl_projektarbeit.note IS NULL ')."
AND betreuerart_kurzbz IN ('Betreuer', 'Begutachter', 'Erstbegutachter', 'Zweitbegutachter', 'Erstbetreuer', 'Senatsvorsitz', 'Senatsmitglied')
ORDER BY tbl_projektarbeit.projektarbeit_id, betreuerart_kurzbz desc) as xy
ORDER BY nachname;";
return $this->execReadOnlyQuery($qry, array($uid));
}
}
+6
View File
@@ -48,5 +48,11 @@ export default {
const url = `/Cis/Abgabetool/getStudentProjektarbeitAbgabeFile?paabgabe_id=${paabgabe_id}&student_uid=${student_uid}`;
window.location = FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + url
},
getMitarbeiterProjektarbeiten(uid, all) {
return this.$fhcApi.get(
`/api/frontend/v1/Lehre/getMitarbeiterProjektarbeiten?showall=${all}`
, {}
);
}
}
+11 -6
View File
@@ -11,7 +11,8 @@ import CmsNews from "../../components/Cis/Cms/News.js";
import CmsContent from "../../components/Cis/Cms/Content.js";
import Info from "../../components/Cis/Mylv/Semester/Studiengang/Lv/Info.js";
import RoomInformation, { DEFAULT_MODE_RAUMINFO } from "../../components/Cis/Mylv/RoomInformation.js";
import Abgabetool from "../../components/Cis/Abgabetool/Abgabetool";
import AbgabetoolStudent from "../../components/Cis/Abgabetool/AbgabetoolStudent.js";
import AbgabetoolMitarbeiter from "../../components/Cis/Abgabetool/AbgabetoolMitarbeiter.js";
const ciPath = FHC_JS_DATA_STORAGE_OBJECT.app_root.replace(/(https:|)(^|\/\/)(.*?\/)/g, '') + FHC_JS_DATA_STORAGE_OBJECT.ci_router;
@@ -31,9 +32,15 @@ const router = VueRouter.createRouter({
props: true
},
{
path: `/Cis/Abgabetool`,
name: 'Abgabetool',
component: Abgabetool,
path: `/Cis/Abgabetool/Student`,
name: 'AbgabetoolStudent',
component: AbgabetoolStudent,
props: true
},
{
path: `/Cis/Abgabetool/Mitarbeiter`,
name: 'AbgabetoolMitarbeiter',
component: AbgabetoolMitarbeiter,
props: true
},
{
@@ -211,8 +218,6 @@ const router = VueRouter.createRouter({
]
})
const app = Vue.createApp({
name: 'FhcApp',
data: () => ({
@@ -0,0 +1,286 @@
import BsModal from '../../Bootstrap/Modal.js';
const today = new Date()
export const AbgabeMitarbeiterDetail = {
name: "AbgabeMitarbeiterDetail",
components: {
BsModal,
InputNumber: primevue.inputnumber,
Checkbox: primevue.checkbox,
Dropdown: primevue.dropdown,
Textarea: primevue.textarea
},
props: {
projektarbeit: {
type: Object,
default: null
}
},
data() {
return {
eidAkzeptiert: false,
enduploadTermin: null,
allActiveLanguages: FHC_JS_DATA_STORAGE_OBJECT.server_languages,
form: Vue.reactive({
sprache: '',
abstract: '',
abstract_en: '',
schlagwoerter: '',
schlagwoerter_en: '',
kontrollschlagwoerter: '',
seitenanzahl: 1,
})
}
},
methods: {
openZusatzdatenModal(termin) {
},
save(termin) {
// TODO: api speichern termin
},
delete(termin) {
// TODO: api delete termin
},
validate: function(termin) {
if(!termin.file.length) {
this.$fhcAlert.alertWarning(this.$p.t('global/warningChooseFile'));
return false
}
return true;
},
downloadAbgabe(termin) {
this.$fhcApi.factory.lehre.getStudentProjektarbeitAbgabeFile(termin.paabgabe_id, this.projektarbeit.student_uid)
},
dateDiffInDays(datum, today){
const oneDayMs = 1000 * 60 * 60 * 24
return Math.round((new Date(datum) - new Date(today)) / oneDayMs)
},
getDateStyle(termin) {
const datum = new Date(termin.datum)
const abgabedatum = new Date(termin.abgabedatum)
// todo: rework styling but keep the color pattern logic
// https://wiki.fhcomplete.info/doku.php?id=cis:abgabetool_fuer_studierende
let color = 'white'
let fontColor = 'black'
if (termin.abgabedatum === null) {
if(datum < today) {
color = 'red'
fontColor = 'white'
} else if (datum > today && this.dateDiffInDays(datum, today) <= 12) {
color = 'yellow'
}
} else if(abgabedatum > datum) {
color = 'pink' // aka "hellrot"
fontColor = 'white'
} else {
color = 'green'
}
return 'font-color: ' + fontColor + '; background-color: ' + color
},
openBeurteilungLink(link) {
window.open(link, '_blank')
},
getOptionLabel(option) {
return option.sprache
}
},
watch: {
projektarbeit(newVal) {
// default select german if projektarbeit sprache was null
this.form.sprache = newVal.sprache ? this.allActiveLanguages.find(lang => lang.sprache == newVal.sprache) : this.allActiveLanguages.find(lang => lang.sprache == 'German')
this.form.abstract = newVal.abstract
this.form.abstract_en = newVal.abstract_en
this.form.schlagwoerter = newVal.schlagwoerter
this.form.schlagwoerter_en = newVal.schlagwoerter_en
this.form.kontrollschlagwoerter = newVal.kontrollschlagwoerter
this.form.seitenanzahl = newVal.seitenanzahl
}
},
computed: {
getEid() {
return this.$p.t('abgabetool/c4eidesstattlicheErklaerung')
},
getEnduploadErlaubt() {
return !this.eidAkzeptiert
}
},
created() {
},
mounted() {
},
template: `
<div v-if="projektarbeit">
<h5>{{$p.t('abgabetool/c4abgabeMitarbeiterbereich')}}</h5>
<div class="row">
<p> {{projektarbeit?.student}}</p>
<p> {{projektarbeit?.titel}}</p>
<p v-if="projektarbeit?.zweitbegutachter"> {{projektarbeit?.zweitbegutachter}}</p>
</div>
<div id="uploadWrapper">
<div class="row" style="margin-bottom: 12px;">
<div style="width: 100px">{{$p.t('abgabetool/c4fixtermin')}}</div>
<div class="col-1">{{$p.t('abgabetool/c4zieldatum')}}</div>
<div class="col-1">{{$p.t('abgabetool/c4abgabetyp')}}</div>
<div class="col-2">{{$p.t('abgabetool/c4abgabekurzbz')}}</div>
<div class="col-1">{{$p.t('abgabetool/c4abgabedatum')}}</div>
<div class="col">
</div>
</div>
<!-- TODO: show some nothing found placeholder when abgabetermine are empty -->
<div class="row" v-for="termin in projektarbeit.abgabetermine">
<div style="width: 100px" class="d-flex justify-content-center align-items-center">
<p class="fhc-bullet" :class="{ 'fhc-bullet-red': termin.fixtermin, 'fhc-bullet-green': !termin.fixtermin }"></p>
</div>
<div class="col-1 d-flex justify-content-center align-items-center">
<div :style="getDateStyle(termin)">
<!-- TODO: date input-->
{{ termin.datum?.split("-").reverse().join(".") }}
</div>
</div>
<div class="col-1 d-flex justify-content-center align-items-center">
<!-- TODO: type dropdown select -->
{{ termin.bezeichnung }}
</div>
<div class="col-2 d-flex justify-content-center align-items-center">
<!-- TODO: abgabe kurzbz input -->
{{ termin.kurzbz }}
</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-file-pdf"></i>
</a>
</div>
<div class="col-6">
<div class="row">
<div class="col-3">
<button class="btn btn-primary border-0" @click="save(termin)" :disabled="!termin.allowedToUpload">
Speichern
<i style="margin-left: 8px" class="fa-solid fa-floppy-disk"></i>
</button>
</div>
<div class="col-3">
<button class="btn btn-primary border-0" @click="delete(termin)" :disabled="!termin.allowedToUpload">
Löschen
<i style="margin-left: 8px" class="fa-solid fa-trash"></i>
</button>
</div>
<div v-if="termin.endupload && hasFile" class="col-3">
<button class="btn btn-primary border-0" @click="openZusatzdatenModal(termin)" :disabled="!termin.allowedToUpload">
Löschen
<i style="margin-left: 8px" class="fa-solid fa-trash"></i>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
<bs-modal ref="modalContainerEnduploadZusatzdaten" class="bootstrap-prompt" dialogClass="modal-lg">
<template v-slot:title>
<div>
{{$p.t('abgabetool/c4enduploadZusatzdaten')}}
</div>
<div class="row mb-3 align-items-center">
<p class="ml-4 mr-4">Student UID: {{ projektarbeit?.student_uid}}</p>
</div>
<div class="row mb-3 align-items-center">
<p class="ml-4 mr-4">Titel: {{ projektarbeit?.titel }}</p>
</div>
</template>
<template v-slot:default>
<div class="row mb-3 align-items-center">
<div class="row">{{$p.t('abgabetool/c4Sprache')}}</div>
<div class="row">
<Dropdown
:style="{'width': '100%'}"
v-model="form.sprache"
:options="allActiveLanguages"
:optionLabel="getOptionLabel">
</Dropdown>
</div>
</div>
<div class="row mb-3 align-items-center">
<div class="row">Kontrollierte Schlagwörter</div>
<div class="row">
<Textarea v-model="form.kontrollschlagwoerter"></Textarea>
</div>
</div>
<div class="row mb-3 align-items-center">
<div class="row">{{$p.t('abgabetool/c4schlagwoerterGer')}}</div>
<div class="row">
<Textarea v-model="form.schlagwoerter"></Textarea>
</div>
</div>
<div class="row mb-3 align-items-center">
<div class="row">{{$p.t('abgabetool/c4schlagwoerterEng')}}</div>
<div class="row">
<Textarea v-model="form.schlagwoerter_en"></Textarea>
</div>
</div>
<div class="row mb-3 align-items-center">
<div class="row">{{$p.t('abgabetool/c4abstractGer')}}</div>
<div class="row">
<Textarea v-model="form.abstract" rows="10"></Textarea>
</div>
</div>
<div class="row mb-3 align-items-center">
<div class="row">{{$p.t('abgabetool/c4abstractEng')}}</div>
<div class="row">
<Textarea v-model="form.abstract_en" rows="10"></Textarea>
</div>
</div>
<div class="row mb-3 align-items-center">
<div class="row">{{$p.t('abgabetool/c4seitenanzahl')}}</div>
<div class="row">
<InputNumber
v-model="form.seitenanzahl"
inputId="seitenanzahlInput" :min="1" :max="100000">
</InputNumber>
</div>
</div>
<div v-if="projektarbeit">
<div v-html="getEid"></div>
<div class="row">
<div class="col-9"></div>
<div class="col-2"><p>{{ $p.t('abgabetool/c4gelesenUndAkzeptiert') }}</p></div>
<div class="col-1">
<Checkbox
v-model="eidAkzeptiert"
:binary="true"
:pt="{ root: { class: 'ml-auto' }}"
>
</Checkbox>
</div>
</div>
</div>
</template>
<template v-slot:footer>
<button class="btn btn-primary" :disabled="getEnduploadErlaubt" @click="triggerEndupload">{{$p.t('ui/hochladen')}}</button>
</template>
</bs-modal>
`,
};
export default AbgabeMitarbeiterDetail;
@@ -2,8 +2,8 @@ import Upload from '../../../components/Form/Upload/Dms.js';
import BsModal from '../../Bootstrap/Modal.js';
const today = new Date()
export const AbgabeDetail = {
name: "AbgabeDetail",
export const AbgabeStudentDetail = {
name: "AbgabeStudentDetail",
components: {
Upload,
BsModal,
@@ -210,7 +210,7 @@ export const AbgabeDetail = {
<div class="col-2 d-flex justify-content-center align-items-center">{{ termin.kurzbz }}</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="cursor: pointer;">
<a v-if="termin?.abgabedatum" @click="downloadAbgabe(termin)" style="margin-left:4px; cursor: pointer;">
<i class="fa-solid fa-file-pdf"></i>
</a>
</div>
@@ -335,4 +335,4 @@ export const AbgabeDetail = {
`,
};
export default AbgabeDetail;
export default AbgabeStudentDetail;
@@ -0,0 +1,326 @@
import {CoreFilterCmpt} from "../../../components/filter/Filter.js";
import AbgabeDetail from "./AbgabeMitarbeiterDetail.js";
import VerticalSplit from "../../verticalsplit/verticalsplit.js"
export const AbgabetoolMitarbeiter = {
name: "AbgabetoolMitarbeiter",
components: {
CoreFilterCmpt,
AbgabeDetail,
VerticalSplit
},
props: {
viewData: {
type: Object,
required: true,
default: () => ({name: '', uid: ''}),
validator(value) {
return value && value.name && value.uid
}
}
},
data() {
return {
showAll: false,
tabulatorUuid: Vue.ref(0),
selectedData: [],
domain: '',
student_uid: null,
detail: null,
detailOffset: 0,
projektarbeiten: null,
selectedProjektarbeit: null,
tableBuiltResolve: null,
tableBuiltPromise: null,
abgabeTableOptions: {
height: 300,
index: 'projektarbeit_id',
layout: 'fitDataStretch',
placeholder: this.$p.t('global/noDataAvailable'),
selectable: true,
columns: [
{
formatter: 'rowSelection',
titleFormatter: 'rowSelection',
titleFormatterParams: {
rowRange: "active" // Only toggle the values of the active filtered rows
},
hozAlign:"center",
headerSort: false,
frozen: true,
width: 70
},
{title: Vue.computed(() => this.$p.t('abgabetool/c4details')), field: 'details', formatter: this.detailFormatter, widthGrow: 1, tooltip: false},
{title: Vue.computed(() => this.$p.t('abgabetool/c4personenkennzeichen')), field: 'pkz', formatter: this.pkzTextFormatter, widthGrow: 1, tooltip: false},
{title: Vue.computed(() => this.$p.t('abgabetool/c4kontakt')), field: 'mail', formatter: this.mailFormatter, widthGrow: 1, tooltip: false},
{title: Vue.computed(() => this.$p.t('abgabetool/c4vorname')), field: 'vorname', formatter: this.centeredTextFormatter, widthGrow: 1},
{title: Vue.computed(() => this.$p.t('abgabetool/c4nachname')), field: 'nachname', formatter: this.centeredTextFormatter, widthGrow: 1},
{title: Vue.computed(() => this.$p.t('abgabetool/c4projekttyp')), field: 'projekttyp_kurzbz', formatter: this.centeredTextFormatter, widthGrow: 1},
{title: Vue.computed(() => this.$p.t('abgabetool/c4stg')), field: 'stg', formatter: this.centeredTextFormatter, widthGrow: 2},
{title: Vue.computed(() => this.$p.t('abgabetool/c4sem')), field: 'studiensemester_kurzbz', formatter: this.centeredTextFormatter, widthGrow: 1},
{title: Vue.computed(() => this.$p.t('abgabetool/c4titel')), field: 'titel', formatter: this.centeredTextFormatter, maxWidth: 500, widthGrow: 8},
{title: Vue.computed(() => this.$p.t('abgabetool/c4beteuerart')), field: 'betreuerart_beschreibung',formatter: this.centeredTextFormatter, widthGrow: 8}
],
persistence: false,
},
abgabeTableEventHandlers: [{
event: "tableBuilt",
handler: async () => {
this.tableBuiltResolve()
}
},
{
event: "cellClick",
handler: async (e, cell) => {
debugger
if(cell.getColumn().getField() === "details") {
this.setDetailComponent(cell.getValue())
}
e.stopPropagation()
}
},
{
event: "rowClick",
handler: async (e, row) => {
debugger
e.stopPropagation()
}
},
{
event: "rowSelected",
handler: async (row) => {
debugger
}
},
{
event: "rowSelectionChanged",
handler: async(data) => {
this.selectedData = data
}
}
]};
},
methods: {
showDeadlines(){
// TODO: open seperate view in new window containing all future deadlines for the employee
},
toggleShowAll(showall) {
this.showAll = showall
this.loadProjektarbeiten(showall, () => { this.$refs.abgabeTable?.tabulator.redraw(true) })
},
addSeries() {
},
isPastDate(date) {
return new Date(date) < new Date(Date.now())
},
setDetailComponent(details){
debugger
this.loadAbgaben(details).then((res)=> {
debugger
const pa = this.projektarbeiten?.retval?.find(projekarbeit => projekarbeit.projektarbeit_id == details.projektarbeit_id)
pa.abgabetermine = res.data.retval
pa.abgabetermine.forEach(termin => {
termin.file = []
termin.allowedToUpload = true
// TODO: fixtermin logic?
if(termin.bezeichnung == 'Endupload' && this.isPastDate(termin.datum)) {
// termin.allowedToUpload = false
} else {
// termin.allowedToUpload = true
}
})
pa.betreuer = this.buildBetreuer(pa)
pa.student_uid = details.student_uid
pa.student = `${pa.vorname} ${pa.nachname}`
this.selectedProjektarbeit = pa
Vue.nextTick(()=>{
this.$refs.verticalsplit.showBoth()
})
})
},
centeredTextFormatter(cell) {
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: 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>'
},
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: center; align-items: center; height: 100%">' +
'<p style="max-width: 100%; word-wrap: break-word; white-space: normal;">'+val+'</p></div>'
},
tableResolve(resolve) {
this.tableBuiltResolve = resolve
},
buildMailToLink(abgabe) {
return 'mailto:' + abgabe.uid +'@'+ this.domain
},
buildPKZ(projekt) {
return `${projekt.uid} / ${projekt.matrikelnr}`
},
buildStg(projekt) {
return (projekt.typ + projekt.kurzbz)?.toUpperCase()
},
buildBetreuer(abgabe) {
return abgabe.betreuerart_beschreibung + ': ' + (abgabe.btitelpre ? abgabe.btitelpre + ' ' : '') + abgabe.bvorname + ' ' + abgabe.bnachname + (abgabe.btitelpost ? ' ' + abgabe.btitelpost : '')
},
setupData(data){
this.projektarbeiten = data[0]
this.domain = data[1]
const d = data[0]?.retval?.map(projekt => {
let mode = 'detailTermine'
return {
...projekt,
details: {
student_uid: projekt.uid,
projektarbeit_id: projekt.projektarbeit_id,
},
pkz: this.buildPKZ(projekt),
beurteilung: projekt.beurteilungLink ?? null,
sem: projekt.studiensemester_kurzbz,
stg: this.buildStg(projekt),
mail: this.buildMailToLink(projekt),
typ: projekt.projekttyp_kurzbz,
titel: projekt.titel
}
})
this.$refs.abgabeTable.tabulator.setColumns(this.abgabeTableOptions.columns)
this.$refs.abgabeTable.tabulator.setData(d);
},
loadProjektarbeiten(all = false, callback) {
this.$fhcApi.factory.lehre.getMitarbeiterProjektarbeiten(this.viewData?.uid ?? null, all)
.then(res => {
if(res?.data) this.setupData(res.data)
}).finally(() => {
if(callback) {
callback()
}
})
},
loadAbgaben(details) {
return new Promise((resolve) => {
this.$fhcApi.factory.lehre.getStudentProjektabgaben(details)
.then(res => {
resolve(res)
})
})
},
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
this.$refs.abgabeTable.tabulator.setHeight(this.abgabeTableOptions.height)
},
async setupMounted() {
this.tableBuiltPromise = new Promise(this.tableResolve)
await this.tableBuiltPromise
this.loadProjektarbeiten()
this.$refs.verticalsplit.collapseBottom()
this.calcMaxTableHeight()
}
},
watch: {
},
computed: {
},
created() {
},
mounted() {
this.setupMounted()
},
template: `
<div class="h-100">
<h2>{{$p.t('abgabetool/abgabetoolTitle')}}</h2>
<hr>
<vertical-split ref="verticalsplit">
<template #top>
<core-filter-cmpt
:title="''"
@uuidDefined="handleUuidDefined"
ref="abgabeTable"
:newBtnShow="true"
:newBtnLabel="$p.t('global/neueTerminserie')"
:newBtnDisabled="!selectedData.length"
@click:new=addSeries
: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>
</template>
</core-filter-cmpt>
</template>
<template #bottom>
<div v-show="selectedProjektarbeit" ref="selProj">
<AbgabeDetail :projektarbeit="selectedProjektarbeit"></AbgabeDetail>
</div>
</template>
</vertical-split>
</div>
`,
};
export default AbgabetoolMitarbeiter;
@@ -1,8 +1,8 @@
import {CoreFilterCmpt} from "../../../components/filter/Filter.js";
import AbgabeDetail from "./AbgabeDetail";
import AbgabeDetail from "./AbgabeStudentDetail.js";
export const Abgabetool = {
name: "Abgabetool",
export const AbgabetoolStudent = {
name: "AbgabetoolStudent",
components: {
VueDatePicker,
CoreFilterCmpt,
@@ -33,8 +33,8 @@ export const Abgabetool = {
layout: 'fitColumns',
placeholder: this.$p.t('global/noDataAvailable'),
columns: [
{title: Vue.computed(() => this.$p.t('abgabetool/c4details')), formatter: this.detailFormatter, field: 'details', widthGrow: 1, tooltip: false},
{title: Vue.computed(() => this.$p.t('abgabetool/c4beurteilung')), formatter: this.beurteilungFormatter, field: 'beurteilung', widthGrow: 1, tooltip: false},
{title: Vue.computed(() => this.$p.t('abgabetool/c4details')), field: 'details', formatter: this.detailFormatter, widthGrow: 1, tooltip: false},
{title: Vue.computed(() => this.$p.t('abgabetool/c4beurteilung')), field: 'beurteilung', formatter: this.beurteilungFormatter, widthGrow: 1, tooltip: false},
{title: Vue.computed(() => this.$p.t('abgabetool/c4sem')), field: 'sem', formatter: this.centeredTextFormatter, widthGrow: 1},
{title: Vue.computed(() => this.$p.t('abgabetool/c4stg')), field: 'stg', formatter: this.centeredTextFormatter, widthGrow: 1},
{title: Vue.computed(() => this.$p.t('abgabetool/c4kontakt')), field: 'mail', formatter: this.mailFormatter, widthGrow: 1},
@@ -233,4 +233,4 @@ export const Abgabetool = {
`,
};
export default Abgabetool;
export default AbgabetoolStudent;
+6 -2
View File
@@ -74,7 +74,11 @@ export const CoreFilterCmpt = {
// TODO soll im master kommen?
idField: String,
parentIdField: String,
countOnly: Boolean
countOnly: Boolean,
useSelectionSpan: {
type: Boolean,
default: true
}
},
data: function() {
return {
@@ -613,7 +617,7 @@ export const CoreFilterCmpt = {
<button v-if="reload" class="btn btn-outline-secondary" aria-label="Reload" @click="reloadTable">
<span class="fa-solid fa-rotate-right" aria-hidden="true"></span>
</button>
<span v-if="$slots.actions && tabulatorHasSelector">
<span v-if="$slots.actions && tabulatorHasSelector && useSelectionSpan">
<span v-if="countOnly">{{ selectedData.length }} ausgewählt</span>
<span v-else> Mit {{ selectedData.length }} ausgewählten:</span>
</span>
@@ -1,4 +1,5 @@
export default {
name: 'VerticalSplit',
data: function() {
return {
availHeight: 0,
+120
View File
@@ -38177,6 +38177,126 @@ array(
)
)
),
array(
'app' => 'core',
'category' => 'abgabetool',
'phrase' => 'c4personenkennzeichen',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => "Personenkennzeichen",
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => "Personal identity number",
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'abgabetool',
'phrase' => 'c4vorname',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => "Vorname",
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => "First Name",
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'abgabetool',
'phrase' => 'c4nachname',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => "Nachname",
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Last Name',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'abgabetool',
'phrase' => 'c4betreuerart',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => "Betreuerart",
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Supervisor type',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'abgabetool',
'phrase' => 'showAll',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => "Alle anzeigen",
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Show All',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'abgabetool',
'phrase' => 'showDeadlines',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => "Deadlines anzeigen",
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Show Deadlines',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'abgabetool',