Merge branch 'cis40_2026-05_ma_rc_83533-mylv-rework' into cis40_2026-09_ma_rc

This commit is contained in:
adisposkofh
2026-10-09 11:22:47 +02:00
14 changed files with 1337 additions and 93 deletions
@@ -0,0 +1,81 @@
<?php
/**
* 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/>.
*/
if (! defined('BASEPATH')) exit('No direct script access allowed');
class Betreuungen extends FHCAPI_Controller
{
/**
* Object initialization
*/
public function __construct()
{
parent::__construct([
'getBetreuungen' => self::PERM_LOGGED,
]);
}
//------------------------------------------------------------------------------------------------------------------
// Public methods
public function getBetreuungen()
{
$semester = $this->input->get("semester");
if (!$semester) $this->terminateWithError("Missing parameters!");
$personId = getAuthPersonId();
$betreuungenQuery = "SELECT
tbl_lehrveranstaltung.bezeichnung,
tbl_projektarbeit.titel,
(SELECT nachname || ' ' || (CASE WHEN wahlname IS NOT NULL THEN wahlname ELSE vorname END)
FROM public.tbl_benutzer
JOIN public.tbl_person USING(person_id)
WHERE uid=student_uid)
as name,
(SELECT uid
FROM public.tbl_benutzer
WHERE uid=student_uid)
as uid,
tbl_lehrveranstaltung.studiengang_kz,
tbl_lehrveranstaltung.semester,
tbl_studiengang.kurzbzlang as studiengang,
tbl_studiengang.email,
tbl_betreuerart.beschreibung AS beutreuerart_beschreibung,
tbl_projektbetreuer.stunden
FROM
lehre.tbl_lehrveranstaltung, lehre.tbl_projektarbeit, lehre.tbl_projektbetreuer, public.tbl_studiengang, lehre.tbl_betreuerart
WHERE
tbl_lehrveranstaltung.lehrveranstaltung_id=tbl_projektarbeit.lehrveranstaltung_id AND
tbl_projektarbeit.studiensemester_kurzbz = '$semester' AND
tbl_projektarbeit.projektarbeit_id = tbl_projektbetreuer.projektarbeit_id AND
tbl_lehrveranstaltung.studiengang_kz = tbl_studiengang.studiengang_kz AND
tbl_projektbetreuer.betreuerart_kurzbz = tbl_betreuerart.betreuerart_kurzbz AND
tbl_projektbetreuer.person_id = '$personId'";
$this->addMeta("query", $betreuungenQuery);
$this->load->model('education/Lehrveranstaltung_model', 'LehrveranstaltungModel');
$result = $this->LehrveranstaltungModel->execReadOnlyQuery($betreuungenQuery);
$result = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($result);
}
}
@@ -19,7 +19,8 @@ class Lehreinheit extends FHCAPI_Controller
'getLehrfach' => ['admin:r', 'assistenz:r'],
'getSprache' => ['admin:r', 'assistenz:r'],
'getRaumtyp' => ['admin:r', 'assistenz:r'],
'getLehrform' => ['admin:r', 'assistenz:r']
'getLehrform' => ['admin:r', 'assistenz:r'],
'getLehreinheitenBySemester' => self::PERM_LOGGED,
]);
$this->_ci = &get_instance();
@@ -438,6 +439,27 @@ class Lehreinheit extends FHCAPI_Controller
$this->terminateWithSuccess($this->p->t('global', 'gespeichert'));
}
public function getLehreinheitenBySemester()
{
$semester = $this->input->get('semester');
$lehreinheiten = $this->LehreinheitModel->getLehrenheitenBySemester(getAuthUID(), $semester);
$lehreinheiten = $this->getDataOrTerminateWithError($lehreinheiten);
foreach ($lehreinheiten as $lehreinheit) {
$groups = $this->LehreinheitModel->getGroupsByLehreinheit($lehreinheit->lehreinheit_id);
$groups = $this->getDataOrTerminateWithError($groups);
$stgKurzbz = $lehreinheit->stg_kurzbz;
$lehreinheit->groups = array_map(
function ($group) use ($stgKurzbz) {
return $group->gruppe_kurzbz ?? $stgKurzbz . "-" . $group->semester . $group->verband . $group->gruppe;
},
$groups
);
}
$this->terminateWithSuccess($lehreinheiten);
}
private function checkPermission($lehreinheit_id)
{
@@ -862,4 +862,47 @@ EOSQL;
return $this->execQuery($query, [$lva_id, $sem_kurzbz, $ma_uid]);
}
public function getLehrenheitenBySemester($uid, $semester)
{
$query = "SELECT
tbl_lehreinheit.lehreinheit_id,
lehrfach.kurzbz as lehrfach,
tbl_lehreinheit.lehrform_kurzbz as lehrform,
tbl_lehrveranstaltung.bezeichnung as lv_bezeichnung,
(SELECT kurzbz FROM public.tbl_mitarbeiter
WHERE mitarbeiter_uid=tbl_lehreinheitmitarbeiter.mitarbeiter_uid) as lektor,
UPPER(tbl_studiengang.typ::varchar(1) || tbl_studiengang.kurzbz) as stg_kurzbz,
tbl_lehrveranstaltung.semester as lv_semester,
tbl_lehreinheit.raumtyp,
tbl_lehreinheit.raumtypalternativ,
tbl_lehreinheit.stundenblockung,
tbl_lehreinheit.wochenrythmus,
tbl_lehreinheitmitarbeiter.semesterstunden as semesterstunden,
tbl_lehreinheit.start_kw,
lvangebot.anmeldefenster_start,
lvangebot.anmeldefenster_ende,
tbl_lehrveranstaltung.lehrveranstaltung_id
FROM
lehre.tbl_lehreinheit JOIN lehre.tbl_lehreinheitmitarbeiter USING(lehreinheit_id)
JOIN lehre.tbl_lehrveranstaltung USING(lehrveranstaltung_id)
JOIN public.tbl_studiengang USING(studiengang_kz)
JOIN lehre.tbl_lehrveranstaltung as lehrfach ON(tbl_lehreinheit.lehrfach_id=lehrfach.lehrveranstaltung_id)
LEFT JOIN lehre.tbl_lvangebot as lvangebot ON(tbl_lehrveranstaltung.lehrveranstaltung_id=lvangebot.lehrveranstaltung_id)
WHERE
tbl_lehreinheit.studiensemester_kurzbz = '$semester'
AND mitarbeiter_uid = '$uid'
ORDER BY stg_kurzbz,lv_semester,lv_bezeichnung";
return $this->execReadOnlyQuery($query);
}
public function getGroupsByLehreinheit($lehreinheitId)
{
$query = "SELECT *
FROM lehre.tbl_lehreinheitgruppe
WHERE lehreinheit_id='$lehreinheitId'";
return $this->execReadOnlyQuery($query);
}
}
+28
View File
@@ -0,0 +1,28 @@
/**
* 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 {
getBetreuungen(semester) {
return {
method: 'get',
url: '/api/frontend/v1/lv/Betreuungen/getBetreuungen',
params: {
semester
},
};
},
};
+28
View File
@@ -0,0 +1,28 @@
/**
* 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 {
getLehreinheitenBySemester(semester) {
return {
method: 'get',
url: '/api/frontend/v1/lv/Lehreinheit/getLehreinheitenBySemester',
params: {
semester
},
};
},
};
@@ -1,5 +1,5 @@
import Phrasen from "../../../../../mixins/Phrasen.js";
import ApiLehre from "../../../../../api/factory/lehre.js";
import Phrasen from "../../../mixins/Phrasen.js";
import ApiLehre from "../../../api/factory/lehre.js";
export default {
mixins: [
@@ -0,0 +1,226 @@
import { CoreFilterCmpt } from "../../filter/Filter.js";
import ApiLehreinheit from "../../../api/factory/lehreinheit.js";
export default {
name: "Lehreinheiten",
components: {
CoreFilterCmpt,
},
props: {
semester: null | String,
},
data() {
return {
lehreinheiten: [],
isFetchingLehreinheiten: false,
lehreinheitTableOptions: {
layout: "fitColumns",
columns: [
{
titlePhrase: "lehreinheiten/inputGrades",
title: "placeholder",
field: "inputGrades",
widthGrow: 2,
formatter: () => {
return '<i class="fa-solid fa-up-right-from-square"></i>';
},
hozAlign: "center",
cellClick: (event, cell) => {
window.open(
FHC_JS_DATA_STORAGE_OBJECT.app_root +
FHC_JS_DATA_STORAGE_OBJECT.ci_router +
"/Cis/Compat/legacy/cis/private/lehre/benotungstool/lvgesamtnoteverwalten.php?lvid=" +
cell._cell.row.data.lvId +
"&stsem=" +
this.$props.semester,
"_blank",
);
},
},
{
title: "ID",
field: "lehreinheitId",
widthGrow: 2,
},
{
titlePhrase: "lehreinheiten/subject",
title: "placeholder",
field: "subject",
widthGrow: 2,
},
{
titlePhrase: "lehreinheiten/lehrform",
title: "placeholder",
field: "lehrform",
widthGrow: 2,
},
{
titlePhrase: "lehreinheiten/title",
title: "placeholder",
field: "title",
widthGrow: 3,
},
{
titlePhrase: "lehreinheiten/lector",
title: "placeholder",
field: "lector",
widthGrow: 2,
},
{
titlePhrase: "lehreinheiten/dp",
title: "placeholder",
field: "stg",
widthGrow: 2,
},
{
titlePhrase: "lehreinheiten/sem",
title: "placeholder",
field: "semester",
widthGrow: 1,
},
{
titlePhrase: "lehreinheiten/groups",
title: "placeholder",
field: "groups",
widthGrow: 2,
formatter: "textarea",
},
{
titlePhrase: "lehreinheiten/room",
title: "placeholder",
field: "room",
widthGrow: 3,
},
{
titlePhrase: "lehreinheiten/alt",
title: "placeholder",
field: "alternativeRoom",
widthGrow: 3,
},
{
titlePhrase: "lehreinheiten/block",
title: "placeholder",
field: "block",
widthGrow: 1,
},
{
titlePhrase: "lehreinheiten/wr",
title: "placeholder",
field: "weeklyRhythm",
widthGrow: 1,
},
{
titlePhrase: "lehreinheiten/hrs",
title: "placeholder",
field: "hours",
widthGrow: 1,
bottomCalc: "sum",
bottomCalcParams: { precision: 2 },
},
{
titlePhrase: "lehreinheiten/cw",
title: "placeholder",
field: "cw",
widthGrow: 1,
},
{
titlePhrase: "lehreinheiten/registrationWindowStart",
title: "placeholder",
field: "registrationWindowStart",
widthGrow: 2,
},
{
titlePhrase: "lehreinheiten/registrationWindowEnd",
title: "placeholder",
field: "registrationWindowEnd",
widthGrow: 2,
},
],
locale: true,
persistence: false,
persistenceID: "supervisorTable",
},
};
},
watch: {
semester() {
this.getLehreinheiten();
},
},
methods: {
async getLehreinheiten() {
if (!this.$props.semester?.length) return;
this.lehreinheiten = [];
this.isFetchingLehreinheiten = true;
const lehreinheitenResponse = await this.$api.call(
ApiLehreinheit.getLehreinheitenBySemester(this.$props.semester),
);
if (lehreinheitenResponse.meta.status === "success") {
this.lehreinheiten = lehreinheitenResponse.data.map(
(lehreinheitData) => {
return {
lehreinheitId: lehreinheitData.lehreinheit_id,
lvId: lehreinheitData.lehrveranstaltung_id,
subject: lehreinheitData.lehrfach,
lehrform: lehreinheitData.lehrform,
title: lehreinheitData.lv_bezeichnung,
lector: lehreinheitData.lektor,
stg: lehreinheitData.stg_kurzbz,
semester: lehreinheitData.lv_semester,
groups: lehreinheitData.groups?.join("\n"),
room: lehreinheitData.raumtyp,
alternativeRoom: lehreinheitData.raumtypalternativ,
block: lehreinheitData.stundenblockung,
weeklyRhythm: lehreinheitData.wochenrythmus,
hours: lehreinheitData.semesterstunden,
cw: lehreinheitData.start_kw,
registrationWindowStart:
lehreinheitData.anmeldefenster_start,
registrationWindowEnd:
lehreinheitData.anmeldefenster_ende,
};
},
);
}
this.setTableData();
this.isFetchingLehreinheiten = false;
},
handleTableBuilt() {
this.setTableData();
},
setTableData() {
if (this.$refs.lehreinheitenTable && this.lehreinheiten?.length) {
this.$refs.lehreinheitenTable.tabulator.setData(
this.lehreinheiten,
);
}
},
},
mounted() {
this.getLehreinheiten();
},
template: /*html*/ `
<div>
<div v-if="isFetchingLehreinheiten" class="d-flex flex-row justify-content-center pt-3">
<i class="fa-solid fa-spinner fa-pulse fa-3x"></i>
</div>
<div v-else-if="lehreinheiten?.length">
<h5>{{ lehreinheiten.length + " " + $p.t("mylv/lehreinheiten") }}</h5>
<core-filter-cmpt
@tableBuilt="handleTableBuilt()"
ref="lehreinheitenTable"
tableOnly
:tabulator-options="lehreinheitTableOptions"
:sideMenu="false"
/>
</div>
<div v-else class="d-flex flex-row justify-content-center pt-3">
<h4>No teaching units found!</h4>
</div>
</div>
`,
};
+61
View File
@@ -0,0 +1,61 @@
import MylvSemesterCards from "./Semester.js";
import MylvTable from "./Table.js";
import MylvSemesterStudiengangAverageGrade from "./AverageGrade.js";
export default {
name: "Lvs",
components: {
MylvSemesterCards,
MylvTable,
MylvSemesterStudiengangAverageGrade,
},
inject: ['isStudent'],
props: ["current"],
data() {
return {
mode: localStorage.getItem('myLvaDefaultMode') ?? 'cards'
};
},
methods: {
selectMode(mode) {
localStorage.setItem('myLvaDefaultMode', mode)
this.mode = mode
},
},
template: /*html*/ `
<div class="d-flex flex-column gap-3">
<div class="d-flex flex-row justify-content-center gap-2">
<button
type="button"
class="btn btn-outline-secondary"
:class="{active: mode === 'cards'}"
@click="selectMode('cards')"
>
<i class="fa fa-grip"></i>
</button>
<button
type="button"
class="btn btn-outline-secondary"
:class="{active: mode === 'table'}"
@click="selectMode('table')"
>
<i class="fa fa-table"></i>
</button>
</div>
<mylv-semester-cards v-if="mode == 'cards'" v-bind="$props.current">
<template #averageGrade v-if="isStudent && $props.current.semester">
<mylv-semester-studiengang-average-grade
:semesterInfo="$props.current.semester"
/>
</template>
</mylv-semester-cards>
<mylv-table v-else-if="mode == 'table'" v-bind="$props.current">
<template #averageGrade v-if="isStudent && $props.current.semester">
<mylv-semester-studiengang-average-grade
:semesterInfo="$props.current.semester"
/>
</template>
</mylv-table>
</div>
`,
}
+51 -48
View File
@@ -1,15 +1,15 @@
import MylvSemesterCards from "./Semester.js";
import MylvTable from "./Table.js";
import ApiAddons from "../../../api/factory/addons.js"
import Lvs from "./Lvs.js";
import Lehreinheiten from "./Lehreinheiten.js";
import Supervisor from "./Supervisor.js";
// TODO(chris): phrase: global/studiensemester_auswaehlen
// TODO(chris): phrase: next & prev +aria-label
import ApiAddons from "../../../api/factory/addons.js"
export default {
name: 'MyLv',
components: {
MylvSemesterCards,
MylvTable
Lvs,
Lehreinheiten,
Supervisor,
},
data: () => {
return {
@@ -17,7 +17,8 @@ export default {
studiensemester: null,
lvs: {},
currentSemester: null,
mode: localStorage.getItem('myLvaDefaultMode') ?? 'cards'
modes: ["lvs", "lehreinheiten", "supervision", "all"],
selectedMode: "lvs"
};
},
provide() {
@@ -91,13 +92,22 @@ export default {
},
currentIsLast() {
return this.studiensemester[this.studiensemester.length-1].studiensemester_kurzbz == this.currentSemester;
}
},
},
watch: {
isMitarbeiter() {
if (this.isMitarbeiter) {
const lastSelectedMode = window.localStorage.getItem("cis4-mylv-lastSelectedMode");
if (this.modes.includes(lastSelectedMode)) {
this.selectedMode = lastSelectedMode;
}
}
},
selectedMode(mode) {
window.localStorage.setItem("cis4-mylv-lastSelectedMode", mode);
},
},
methods: {
clickMode(evt, mode) {
localStorage.setItem('myLvaDefaultMode', mode)
this.mode = mode
},
prevSem() {
this.$refs.studiensemester.selectedIndex--;
this.$refs.studiensemester.dispatchEvent(new Event('change', { bubbles: true }));
@@ -126,7 +136,7 @@ export default {
next();
},
template: `
template: /*html*/ `
<div>
<h2>{{$p.t('lehre/myLV')}}</h2>
<hr>
@@ -135,48 +145,41 @@ export default {
<div class="col-auto d-none">
<label class="col-form-label">{{$p.t('lehre/studiensemester')}}</label>
</div>
<div class="col-auto">
<div class="input-group">
<button :aria-label="$p.t('lehre','previousStudSemester')" v-tooltip.top="{showDelay:1000, value:$p.t('lehre','previousStudSemester')}" class="btn btn-outline-secondary" type="button" :disabled="currentIsFirst" @click="prevSem">
<i class="fa fa-caret-left" aria-hidden="true"></i>
</button>
<select ref="studiensemester" v-model="currentSemester" class="form-select" :aria-label="$p.t('global/studiensemester_auswaehlen')" @change="updateRouter($event.target.value)">
<option v-for="semester in studiensemester" :key="semester.studiensemester_kurzbz">{{semester.studiensemester_kurzbz}}</option>
<div class="d-flex flex-column flex-md-row justify-content-center gap-2">
<div>
<div class="input-group">
<button :aria-label="$p.t('lehre','previousStudSemester')" v-tooltip.top="{showDelay:1000, value:$p.t('lehre','previousStudSemester')}" class="btn btn-outline-secondary" type="button" :disabled="currentIsFirst" @click="prevSem">
<i class="fa fa-caret-left" aria-hidden="true"></i>
</button>
<select ref="studiensemester" v-model="currentSemester" class="form-select" :aria-label="$p.t('global/studiensemester_auswaehlen')" @change="updateRouter($event.target.value)">
<option v-for="semester in studiensemester" :key="semester.studiensemester_kurzbz">{{semester.studiensemester_kurzbz}}</option>
</select>
<button class="btn btn-outline-secondary" :aria-label="$p.t('lehre','nextStudSemester')" v-tooltip.top="{showDelay:1000, value:$p.t('lehre','nextStudSemester')}" type="button" :disabled="currentIsLast" @click="nextSem">
<i class="fa fa-caret-right" aria-hidden="true"></i>
</button>
</div>
</div>
<div v-if="isMitarbeiter">
<select v-model="selectedMode" class="form-select" :aria-label="'mode selector placeholder'">
<option v-for="mode in modes" :key="mode" :value="mode"> {{ $p.t("mylv/" + mode) }} </option>
</select>
<button class="btn btn-outline-secondary" :aria-label="$p.t('lehre','nextStudSemester')" v-tooltip.top="{showDelay:1000, value:$p.t('lehre','nextStudSemester')}" type="button" :disabled="currentIsLast" @click="nextSem">
<i class="fa fa-caret-right" aria-hidden="true"></i>
</button>
</div>
</div>
<div class=" col-auto my-lva-modes">
<div class="d-flex gap-1 justify-content-end" role="group">
<button
type="button"
class="btn btn-outline-secondary"
:class="{active: mode === 'cards'}"
@click="clickMode($event, 'cards')"
>
<i class="fa fa-grip"></i>
</button>
<button
type="button"
class="btn btn-outline-secondary"
:class="{active: mode === 'table'}"
@click="clickMode($event, 'table')"
>
<i class="fa fa-table"></i>
</button>
</div>
<div class="pt-4">
<lvs v-if="selectedMode === 'lvs' || selectedMode === 'all'" :current="current" />
<hr v-if="selectedMode === 'all'">
<lehreinheiten v-if="selectedMode === 'lehreinheiten' || selectedMode === 'all'" :semester="currentSemester" />
<hr v-if="selectedMode === 'all'">
<supervisor v-if="selectedMode === 'supervision' || selectedMode === 'all'" :semester="currentSemester" />
</div>
</div>
<div class="alert alert-danger" role="alert" v-else>
<div v-else class="alert alert-danger" role="alert">
{{$p.t('lehre/noLvFound')}}
</div>
<mylv-semester-cards v-if="mode == 'cards'" v-bind="current"/>
<mylv-table v-else-if="mode == 'table'" v-bind="current"/>
</div>
<div class="mylv text-center" v-else>
<i class="fa-solid fa-spinner fa-pulse fa-3x"></i>
</div>
</div>`
};
</div>
`,
}
+12 -2
View File
@@ -37,9 +37,19 @@ export default {
return this.lvs.filter(lv => lv.studiengang_kz == studiengang.studiengang_kz && lv.semester == studiengang.semester);
}
},
template: `
template: /*html*/ `
<div class="mylv-semester" v-if="ready">
<mylv-semester-studiengang v-for="studiengang in studiengaenge" :key="studiengang.studiengang_kz" v-bind="studiengang" :lvs="lvsForStudiengang(studiengang)" :semesterInfo="$props.semester" />
<mylv-semester-studiengang
v-for="studiengang in studiengaenge"
:key="studiengang.studiengang_kz"
v-bind="studiengang"
:lvs="lvsForStudiengang(studiengang)"
:semesterInfo="$props.semester"
>
<template #averageGrade>
<slot name="averageGrade"></slot>
</template>
</mylv-semester-studiengang>
</div>
<div class="mylv-semester text-center" v-else>
<i class="fa-solid fa-spinner fa-pulse fa-3x"></i>
@@ -1,5 +1,4 @@
import MylvSemesterStudiengangLv from "./Studiengang/Lv.js";
import MylvSemesterStudiengangAverageGrade from "./Studiengang/AverageGrade.js";
import Phrasen from "../../../../mixins/Phrasen.js";
import ApiAuthinfo from '../../../../api/factory/authinfo.js';
@@ -8,7 +7,6 @@ export default {
name: 'Studiengang',
components: {
MylvSemesterStudiengangLv,
MylvSemesterStudiengangAverageGrade
},
mixins: [
Phrasen
@@ -21,11 +19,6 @@ export default {
lvs: Array,
sg_bezeichnung_eng: String
},
data() {
return {
isAverageGradeDisplayed: false,
}
},
computed: {
lehrveranstaltungen() {
return [... new Map(
@@ -41,16 +34,8 @@ export default {
note(lv) {
return lv.benotung ? lv.znote || lv.lvnote || null : null;
},
async checkIfAverageGradeIsDisplayed() {
const authInfoResponse = await this.$api.call(ApiAuthinfo.getAuthInfo());
const authInfo = authInfoResponse.data;
this.isAverageGradeDisplayed = !!authInfo.isStudent;
},
},
created() {
this.checkIfAverageGradeIsDisplayed();
},
template: `
template: /*html*/ `
<div class="card mb-3">
<div class="card-body">
<h4 class="card-title mb-3">{{$p.user_language.value === 'English' ? sg_bezeichnung_eng : bezeichnung}} - {{kuerzel}}
@@ -61,7 +46,7 @@ export default {
<mylv-semester-studiengang-lv v-bind="lv" class="text-center h-100"></mylv-semester-studiengang-lv>
</div>
</div>
<mylv-semester-studiengang-average-grade v-if="isAverageGradeDisplayed" :semesterInfo="$props.semesterInfo" />
<slot name="averageGrade"></slot>
</div>
</div>`
};
+147
View File
@@ -0,0 +1,147 @@
import { CoreFilterCmpt } from "../../../components/filter/Filter.js";
import ApiBetreuungen from "../../../api/factory/betreuungen.js";
export default {
name: "Supervisor",
components: {
CoreFilterCmpt,
},
props: {
semester: null | String,
},
data() {
return {
students: [],
isFetchingStudents: false,
supervisorTableOptions: {
layout: "fitColumns",
columns: [
{
titlePhrase: "betreuungen/studiengang",
title: "placeholder",
field: "studiengang",
widthGrow: 1,
formatter: "link",
formatterParams: {
target: "_blank",
url: (cell) => {
return "mailto:" + cell._cell.row.data.email;
},
},
},
{
titlePhrase: "betreuungen/semester",
title: "placeholder",
field: "semester",
widthGrow: 1,
},
{
titlePhrase: "betreuungen/stunden",
title: "placeholder",
field: "stunden",
widthGrow: 1,
bottomCalc: "sum",
bottomCalcParams: { precision: 2 },
},
{
titlePhrase: "betreuungen/lvBezeichnung",
title: "placeholder",
field: "bezeichnung",
widthGrow: 3,
},
{
titlePhrase: "betreuungen/student",
title: "placeholder",
field: "name",
widthGrow: 3,
formatter: "link",
formatterParams: {
target: "_blank",
url: (cell) => {
return this.$router.resolve({
name: "ProfilView",
params: { uid: cell._cell.row.data.uid },
}).href;
},
},
},
{
titlePhrase: "betreuungen/betreuungsart",
title: "placeholder",
field: "beutreuerart_beschreibung",
widthGrow: 3,
},
{
titlePhrase: "betreuungen/titelProjektarbeit",
title: "placeholder",
field: "titel",
widthGrow: 6,
},
],
locale: true,
persistence: false,
persistenceID: "supervisorTable",
},
};
},
watch: {
semester() {
this.getStudents();
},
},
methods: {
async getStudents() {
if (!this.$props.semester?.length) return;
this.students = [];
this.isFetchingStudents = true;
const studentsResponse = await this.$api.call(
ApiBetreuungen.getBetreuungen(this.$props.semester),
);
if (studentsResponse.meta.status === "success") {
this.students = studentsResponse.data.map((studentData) => {
studentData.stunden = parseFloat(
studentData.stunden,
).toFixed(2);
return { ...studentData };
});
this.setTableData();
}
this.isFetchingStudents = false;
},
handleTableBuilt() {
this.setTableData();
},
setTableData() {
if (this.$refs.supervisorTable && this.students?.length) {
this.$refs.supervisorTable.tabulator.setData(this.students);
}
},
},
mounted() {
this.getStudents();
},
template: /*html*/ `
<div>
<div v-if="isFetchingStudents" class="d-flex flex-row justify-content-center pt-3">
<i class="fa-solid fa-spinner fa-pulse fa-3x"></i>
</div>
<div v-else-if="students?.length">
<h5>{{ students.length + " " + $p.t("mylv/supervised_students") }}</h5>
<core-filter-cmpt
@tableBuilt="handleTableBuilt()"
ref="supervisorTable"
tableOnly
:tabulator-options="supervisorTableOptions"
:sideMenu="false"
/>
</div>
<div v-else class="d-flex flex-row justify-content-center pt-3">
<h4>{{ $p.t("mylv/no_supervised") }}</h4>
</div>
</div>
`,
};
+27 -23
View File
@@ -22,21 +22,22 @@ export default {
layout: 'fitDataStretch',
placeholder: this.$p.t('global/noDataAvailable'),
columns: [
{title: Vue.computed(() => this.$capitalize(this.$p.t('lehre/studiengang'))), field: 'sg_bezeichnung', widthGrow: 1},
{title: Vue.computed(() => this.$capitalize(this.$p.t('global/bezeichnung'))), field: 'bezeichnung', widthGrow: 2},
{title: Vue.computed(() => this.$capitalize(this.$p.t('lehre/orgform'))), field: 'orgform_kurzbz', widthGrow: 1},
{title: Vue.computed(() => this.$capitalize(this.$p.t('lehre/kurzbz'))), field: 'studiengang_kuerzel', widthGrow: 1},
{title: Vue.computed(() => this.$capitalize(this.$p.t('lehre/semesterstunden'))), field: 'semesterstunden',
{titlePhrase: 'lehre/studiengang', title: 'placeholder', field: 'sg_bezeichnung', widthGrow: 1},
{titlePhrase: 'global/bezeichnung', title: 'placeholder', field: 'bezeichnung', widthGrow: 2},
{titlePhrase: 'lehre/orgform', title: 'placeholder', field: 'orgform_kurzbz', widthGrow: 1},
{titlePhrase: 'lehre/kurzbz', title: 'placeholder', field: 'studiengang_kuerzel', widthGrow: 1},
{titlePhrase: 'lehre/semesterstunden', title: 'placeholder', field: 'semesterstunden',
bottomCalc: this.semesterstundenCalc, widthGrow: 1, visible: false},
{title: Vue.computed(() => this.$capitalize(this.$p.t('global/actions'))), headerSort: false,
field: 'menu', formatter: this.actionFormatter, widthGrow: 1, tooltip: this.spoofingFunc}
],
persistence: false,
persistenceID: "mylv_2026_04_17"
persistenceID: "mylv_2026_04_17",
locale: true,
},
mylvTableEventHandlers: [
]
],
}
},
computed: {
@@ -324,22 +325,25 @@ export default {
deep: true
}
},
template: `
<div class="mylv-semester-table" v-if="ready">
<core-filter-cmpt
v-if="phrasenResolved"
@uuidDefined="handleUuidDefined"
:title="''"
ref="mylvTable"
:tabulator-options="mylvTableOptions"
:tabulator-events="mylvTableEventHandlers"
@tableBuilt="handleTableBuilt"
tableOnly
:sideMenu="false"
/>
</div>
<div v-if="tabulatorUuid === null" class="text-center d-flex justify-content-center align-items-center h-100" >
<i class="fa-solid fa-spinner fa-pulse fa-3x"></i>
template: /*html*/ `
<div class="d-flex flex-column gap-3">
<div class="mylv-semester-table" v-if="ready">
<core-filter-cmpt
v-if="phrasenResolved"
@uuidDefined="handleUuidDefined"
:title="''"
ref="mylvTable"
:tabulator-options="mylvTableOptions"
:tabulator-events="mylvTableEventHandlers"
@tableBuilt="handleTableBuilt"
tableOnly
:sideMenu="false"
/>
</div>
<div v-if="tabulatorUuid === null" class="text-center d-flex justify-content-center align-items-center h-100" >
<i class="fa-solid fa-spinner fa-pulse fa-3x"></i>
</div>
<slot name="averageGrade"></slot>
</div>
`
};
+606
View File
@@ -67193,6 +67193,612 @@ I have been informed that I am under no obligation to consent to the transmissio
)
)
),
// BETREUUNGEN PHRASES START
array(
'app' => 'core',
'category' => 'betreuungen',
'phrase' => 'studiengang',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Stg',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'DP',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'betreuungen',
'phrase' => 'semester',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Sem',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Sem',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'betreuungen',
'phrase' => 'stunden',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Std',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Hrs',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'betreuungen',
'phrase' => 'lvBezeichnung',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'LV Bezeichnung',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Course title',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'betreuungen',
'phrase' => 'student',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Student/in',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Student',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'betreuungen',
'phrase' => 'betreuungsart',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Betreuungsart',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Supervision type',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'betreuungen',
'phrase' => 'titelProjektarbeit',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Titel der Projektarbeit',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Project title',
'description' => '',
'insertvon' => 'system'
)
)
),
// BETREUUNGEN PHRASES END
// LEHREINHEITEN PHRASES END
array(
'app' => 'core',
'category' => 'lehreinheiten',
'phrase' => 'inputGrades',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Noten eintragen',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Input grades',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'lehreinheiten',
'phrase' => 'subject',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Lehrfach',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Subject',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'lehreinheiten',
'phrase' => 'lehrform',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Lehrform',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Course Type',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'lehreinheiten',
'phrase' => 'title',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'LV Bezeichnung',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Course Title',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'lehreinheiten',
'phrase' => 'lector',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Lektor/in',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Lector',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'lehreinheiten',
'phrase' => 'dp',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Stg',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'DP',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'lehreinheiten',
'phrase' => 'sem',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Sem',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Sem',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'lehreinheiten',
'phrase' => 'groups',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Gruppen',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Groups',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'lehreinheiten',
'phrase' => 'room',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Raumtyp',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Room',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'lehreinheiten',
'phrase' => 'alt',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Alternativ',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Alternative',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'lehreinheiten',
'phrase' => 'block',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Block',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Block',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'lehreinheiten',
'phrase' => 'wr',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'WR',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'WR',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'lehreinheiten',
'phrase' => 'hrs',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Std',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Hrs',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'lehreinheiten',
'phrase' => 'cw',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'KW',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'CW',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'lehreinheiten',
'phrase' => 'registrationWindowStart',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Anm. von',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Registration Start',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'lehreinheiten',
'phrase' => 'registrationWindowEnd',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Anm. bis',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Registration End',
'description' => '',
'insertvon' => 'system'
)
)
),
// LEHREINHEITEN PHRASES END
// MYLV PHRASES START
array(
'app' => 'core',
'category' => 'mylv',
'phrase' => 'lvs',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'LVs',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Course programs',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'mylv',
'phrase' => 'lehreinheiten',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Lehreinheiten',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Teaching units',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'mylv',
'phrase' => 'supervision',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Betreuungen',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Supervision',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'mylv',
'phrase' => 'all',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Alles zeigen',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Show all',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'mylv',
'phrase' => 'supervised_students',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Betreute Studierende',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Supervised students',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'mylv',
'phrase' => 'no_supervised',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Keine Betreute Studierende gefunden!',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'No supervised students found!',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'mylv',
'phrase' => 'no_lehreinheiten',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Keine Lehreinheiten gefunden!',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'No teaching units found!',
'description' => '',
'insertvon' => 'system'
)
)
),
// MYLV PHRASES END
);