Compare commits

..

2 Commits

12 changed files with 143 additions and 327 deletions
@@ -9,10 +9,9 @@ class Detailheader extends FHCAPI_Controller
public function __construct()
{
parent::__construct([
'getHeader' => self::PERM_LOGGED,
'getPersonAbteilung' => self::PERM_LOGGED,
'getLeitungOrg' => self::PERM_LOGGED,
'getSemesterStati' => self::PERM_LOGGED,
'getHeader' => ['vertrag/mitarbeiter:r'],
'getPersonAbteilung' => ['vertrag/mitarbeiter:r'],
'getLeitungOrg' => ['vertrag/mitarbeiter:r'],
]);
}
@@ -49,17 +48,6 @@ class Detailheader extends FHCAPI_Controller
$this->terminateWithSuccess(current($data));
}
public function getSemesterStati($prestudent_id)
{
$this->load->model('crm/Prestudentstatus_model', 'PrestudentstatusModel');
$result = $this->PrestudentstatusModel->getAllPrestudentstatiWithStudiensemester($prestudent_id);
$data = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($data);
}
}
@@ -144,7 +144,6 @@ class Student extends FHCAPI_Controller
. $this->PrestudentModel->escape($studiensemester_kurzbz)
. ") AS statusofsemester"
);
$this->PrestudentModel->addSelect($this->PrestudentModel->escape($studiensemester_kurzbz) . ' as query_studiensemester_kurzbz');
$this->PrestudentModel->addJoin('public.tbl_student s', 'prestudent_id', 'LEFT');
$this->PrestudentModel->addJoin('public.tbl_benutzer b', 'student_uid = uid', 'LEFT');
@@ -468,8 +468,6 @@ class Students extends FHCAPI_Controller
$this->PrestudentModel->addSelect("'' AS verband");
$this->PrestudentModel->addSelect("'' AS gruppe");
$this->addSelectPrioRel();
$query_studiensemester_kurzbz = $studiensemester_kurzbz ? $this->PrestudentModel->escape($studiensemester_kurzbz) : '\'NULL\'';
$this->PrestudentModel->addSelect($query_studiensemester_kurzbz . ' as query_studiensemester_kurzbz');
$this->addFilter($studiensemester_kurzbz);
@@ -590,7 +588,6 @@ class Students extends FHCAPI_Controller
$this->PrestudentModel->addSelect('v.verband');
$this->PrestudentModel->addSelect('v.gruppe');
$this->PrestudentModel->addSelect("'' AS priorisierung_relativ");
$this->PrestudentModel->addSelect($this->PrestudentModel->escape($studiensemester_kurzbz) . ' as query_studiensemester_kurzbz');
$where = [];
@@ -801,7 +798,6 @@ class Students extends FHCAPI_Controller
$this->PrestudentModel->addSelect("COALESCE(v.semester::text, CASE WHEN public.get_rolle_prestudent(tbl_prestudent.prestudent_id, NULL) IN ('Aufgenommener', 'Bewerber', 'Wartender', 'interessent') THEN public.get_absem_prestudent(tbl_prestudent.prestudent_id, NULL)::text ELSE ''::text END) AS semester", false);
$this->PrestudentModel->addSelect('v.verband');
$this->PrestudentModel->addSelect('v.gruppe');
$this->PrestudentModel->addSelect($this->PrestudentModel->escape($studiensemester_kurzbz) . ' as query_studiensemester_kurzbz');
//add status per semester
$this->PrestudentModel->addSelect(
-6
View File
@@ -34,10 +34,4 @@ export default {
url: 'api/frontend/v1/detailheader/detailheader/getLeitungOrg/' + oekurzbz,
};
},
getSemesterStati(prestudent_id){
return {
method: 'get',
url: 'api/frontend/v1/detailheader/detailheader/getSemesterStati/' + prestudent_id,
};
},
}
+82 -216
View File
@@ -1,13 +1,11 @@
import ApiDetailHeader from "../../api/factory/detailHeader.js";
import ApiHandleFoto from "../../api/factory/fotoHandling.js";
import ModalUploadFoto from "./Modal/UploadFoto.js";
import PvSkeleton from "../../../../index.ci.php/public/js/components/primevue/skeleton/skeleton.esm.min.js";
export default {
name: 'DetailHeader',
components: {
ModalUploadFoto,
PvSkeleton
ModalUploadFoto
},
props: {
headerData: {
@@ -40,14 +38,6 @@ export default {
'mitarbeiter',
].includes(value)
}
},
currentSemester: {
type: String,
default: ''
},
isLoading: { //if true, then parent isLoading
type: Boolean,
default: false
}
},
computed: {
@@ -70,7 +60,8 @@ export default {
},
hasTileUIDSlot() {
return !!this.$slots.uid
}
},
},
created(){
if (this.typeHeader === 'student') {
@@ -80,7 +71,7 @@ export default {
} else if (this.typeHeader === 'mitarbeiter') {
if (!this.person_id || !this.mitarbeiter_uid || !this.domain) {
throw new Error(
'[DetailHeader] "person_id", "mitarbeiter_uid", and "domain" are required.'
'[DetailHeader] "person_id", "mitarbeiter_uid", and "domain" are requried.'
)
}
this.loadHeaderData(this.person_id, this.mitarbeiter_uid);
@@ -95,26 +86,13 @@ export default {
},
deep: true,
},
headerData: {
handler(newVal) {
if (this.typeHeader === 'student' && newVal?.length) {
this.getSemesterStati(newVal[0].prestudent_id);
}
},
immediate: true
},
},
data(){
return{
headerDataMa: {},
departmentData: {},
leitungData: {},
isFetchingIssues: false,
noCurrentStatus: false,
semesterStatiLoading: false,
leitungOrgLoading: false,
departmentDataLoading: false,
headerDataMaLoading: false
isFetchingIssues: false
};
},
methods: {
@@ -130,40 +108,29 @@ export default {
});
},
getHeader(person_id) {
this.headerDataMaLoading = true;
return this.$api
.call(ApiDetailHeader.getHeader(person_id))
.then(result => {
this.headerDataMa = result.data;
})
.catch(this.$fhcAlert.handleSystemError)
.finally(() => {
this.headerDataMaLoading = false;
});
.catch(this.$fhcAlert.handleSystemError);
},
loadDepartmentData(mitarbeiter_uid) {
this.departmentDataLoading = true;
return this.$api
.call(ApiDetailHeader.getPersonAbteilung(mitarbeiter_uid))
.then(result => {
this.departmentData = result.data;
})
.catch(this.$fhcAlert.handleSystemError)
.finally(() => {
this.departmentDataLoading = false;
});
.catch(this.$fhcAlert.handleSystemError);
},
getLeitungOrg(oekurzbz){
this.leitungOrgLoading = true;
return this.$api
.call(ApiDetailHeader.getLeitungOrg(oekurzbz))
.then(result => {
this.leitungData = result.data;
})
.catch(this.$fhcAlert.handleSystemError)
.finally(() => {
this.leitungOrgLoading = false;
});
.catch(this.$fhcAlert.handleSystemError);
},
async goToLeitung() {
this.loadHeaderData(this.leitungData.person_id, this.leitungData.uid);
@@ -212,33 +179,6 @@ export default {
} else {
return 'data:image/jpeg;base64,' + foto;
}
},
getSemesterStati(prestudent_id){
this.semesterStatiLoading = true;
this.$api
.call(ApiDetailHeader.getSemesterStati(prestudent_id))
.then(result => {
this.semesterStati = result.data;
this.setNoCurrentStatus();
})
.catch(this.$fhcAlert.handleSystemError)
.finally(() => {
this.semesterStatiLoading = false;
});
},
setNoCurrentStatus() {
if(!Array.isArray(this.semesterStati))
{
this.noCurrentStatus = false;
}
if(!this.semesterStati.some(item => item.studiensemester_kurzbz === this.currentSemester)) {
this.noCurrentStatus = true;
}
else
{
this.noCurrentStatus = false;
}
}
},
template: `
@@ -260,6 +200,7 @@ export default {
</modal-upload-foto>
<template v-if="typeHeader==='student'">
<div
v-for="person in headerData"
:key="person.person_id"
@@ -295,100 +236,62 @@ export default {
<small class="text-muted">{{person.uid}}</small>
</div>
<div v-if="headerData.length == 1">
<div v-if="!isLoading" class="d-flex align-items-center gap-3">
<h2 class="h4">
{{headerData[0].titelpre}}
{{headerData[0].vorname}}
{{headerData[0].nachname}}
<span v-if="headerData[0].titelpost">, </span>
{{headerData[0].titelpost}}
</h2>
<h6 v-if="headerData[0].unruly" class="badge" :class="'bg-unruly rounded-0'"><strong>unruly</strong></h6>
</div>
<div v-else class="d-flex align-items-center gap-3">
<pv-skeleton width="15rem" height="2rem" borderRadius="16px"></pv-skeleton>
<h6 v-if="headerData[0].unruly" class="badge" :class="'bg-unruly rounded-0'"><strong>unruly</strong></h6>
</div>
<div v-if="headerData.length == 1">
<div class="d-flex align-items-center gap-3">
<h2 class="h4">
{{headerData[0].titelpre}}
{{headerData[0].vorname}}
{{headerData[0].nachname}}
<span v-if="headerData[0].titelpost">, </span>
{{headerData[0].titelpost}}
</h2>
<h6 v-if="headerData[0].unruly" class="badge" :class="'bg-unruly rounded-0'"><strong>unruly</strong></h6>
</div>
<h5 class="h6 d-flex align-items-center flex-wrap gap-1">
<strong class="text-muted">{{$p.t('lehre', 'studiengang')}} </strong>
<span v-if="!isLoading">
{{headerData[0].stg_bezeichnung}} ({{headerData[0].studiengang}})
</span>
<span v-else>
<pv-skeleton width="10rem"></pv-skeleton>
</span>
<template v-if="!semesterStatiLoading">
<strong v-if="headerData[0].semester != null" class="text-muted"> | {{$p.t('lehre', 'semester')}} </strong>
{{headerData[0].semester}}
<strong v-if="headerData[0].gruppe !== null && headerData[0].verband != ' '" class="text-muted"> | {{$p.t('lehre', 'verband')}}</strong>
{{headerData[0].verband}}
<strong v-if="headerData[0].gruppe !== null && headerData[0].gruppe != ' '" class="text-muted"> | {{$p.t('lehre', 'gruppe')}} </strong>
{{headerData[0].gruppe}}
</template>
<template v-else>
<strong class="text-muted"> | {{$p.t('lehre', 'semester')}} </strong>
<pv-skeleton size="1rem" class="mr-2"></pv-skeleton>
<strong class="text-muted"> | {{$p.t('lehre', 'verband')}}</strong>
<pv-skeleton size="1rem" class="mr-2"></pv-skeleton>
<strong class="text-muted"> | {{$p.t('lehre', 'gruppe')}} </strong>
<pv-skeleton size="1rem" class="mr-2"></pv-skeleton>
</template>
</h5>
<h5 class="h6">
<strong class="text-muted">{{$p.t('lehre', 'studiengang')}} </strong>
{{headerData[0].stg_bezeichnung}} ({{headerData[0].studiengang}})
<strong v-if="headerData[0].semester" class="text-muted"> | {{$p.t('lehre', 'semester')}} </strong>
{{headerData[0].semester}}
<strong v-if="headerData[0].verband" class="text-muted"> | {{$p.t('lehre', 'verband')}}</strong>
{{headerData[0].verband}}
<strong v-if="headerData[0].gruppe" class="text-muted"> | {{$p.t('lehre', 'gruppe')}} </strong>
{{headerData[0].gruppe}}
</h5>
<h5 class="h6 d-flex align-items-center flex-wrap gap-1">
<strong class="text-muted">Email </strong>
<span v-if="!isLoading">
<a :href="'mailto:'+headerData[0]?.mail_intern">{{headerData[0].mail_intern}}</a>
</span>
<span v-else>
<pv-skeleton width="10rem"></pv-skeleton>
</span>
<strong class="text-muted"> | Status </strong>
<span v-if="noCurrentStatus">
<strong class="text-danger">{{$p.t('lehre', 'textNoStatusInSem', { sem: currentSemester}) }}</strong>
</span>
<span v-else>
{{headerData[0].statusofsemester}}
</span>
</h5>
</div>
<div v-if="headerData.length == 1" class="col-md-1 d-flex flex-column align-items-end justify-content-start ms-auto">
<div class="d-flex py-1">
<div class="px-2" style="min-width: 100px;">
<slot name="issues"></slot>
</div>
<div v-if="hasTileGammaSlot" class="px-2" style="border-left: 1px solid #EEE">
<h4 class="mb-1 text-center"><slot name="titleGammaTile"></slot></h4>
<h6 class="text-muted d-flex align-items-center justify-content-center flex-wrap gap-1">
<pv-skeleton v-if="isLoading" width="4rem"></pv-skeleton>
<slot v-else name="valueGammaTile"></slot>
</h6>
</div>
<div v-if="hasTileBetaSlot" class="px-2" style="border-left: 1px solid #EEE">
<h4 class="mb-1 text-center"><slot name="titleBetaTile"></slot></h4>
<h6 class="text-muted d-flex align-items-center justify-content-center flex-wrap gap-1">
<pv-skeleton v-if="isLoading" width="4rem"></pv-skeleton>
<slot v-else name="valueBetaTile"></slot>
</h6>
</div>
<div v-if="hasTileAlphaSlot" class="px-2" style="border-left: 1px solid #EEE">
<h4 class="mb-1 text-center"><slot name="titleAlphaTile"></slot></h4>
<h6 class="text-muted d-flex align-items-center justify-content-center flex-wrap gap-1">
<pv-skeleton v-if="isLoading" width="4rem"></pv-skeleton>
<slot v-else name="valueAlphaTile"></slot>
</h6>
</div>
<div v-if="hasTileUIDSlot" class="px-2" style="border-left: 1px solid #EEE">
<h4 class="mb-1 text-center">UID</h4>
<h6 class="text-muted d-flex align-items-center justify-content-center flex-wrap gap-1">
<pv-skeleton v-if="isLoading" width="4rem"></pv-skeleton>
<slot v-else name="uid"></slot>
</h6>
<h5 class="h6">
<strong class="text-muted">Email </strong>
<span>
<a :href="'mailto:'+headerData[0]?.mail_intern">{{headerData[0].mail_intern}}</a>
</span>
<strong v-if="headerData[0].statusofsemester" class="text-muted"> | Status </strong>
{{headerData[0].statusofsemester}}
</h5>
</div>
<div v-if="headerData.length == 1" class="col-md-1 d-flex flex-column align-items-end justify-content-start ms-auto">
<div class="d-flex py-1">
<div class="px-2" style="min-width: 100px;">
<slot name="issues"></slot>
</div>
<div v-if="hasTileGammaSlot" class="px-2" style="border-left: 1px solid #EEE">
<h4 class="mb-1 text-center"><slot name="titleGammaTile"></slot></h4>
<h6 class="text-muted text-center"><slot name="valueGammaTile"></slot></h6>
</div>
<div v-if="hasTileBetaSlot" class="px-2" style="border-left: 1px solid #EEE">
<h4 class="mb-1 text-center"><slot name="titleBetaTile"></slot></h4>
<h6 class="text-muted text-center"><slot name="valueBetaTile"></slot></h6>
</div>
<div v-if="hasTileAlphaSlot" class="px-2" style="border-left: 1px solid #EEE">
<h4 class="mb-1 text-center"><slot name="titleAlphaTile"></slot></h4>
<h6 class="text-muted text-center"><slot name="valueAlphaTile"></slot></h6>
</div>
<div v-if="hasTileUIDSlot" class="px-2" style="border-left: 1px solid #EEE">
<h4 class="mb-1 text-center">UID</h4>
<h6 class="text-muted text-center"><slot name="uid"></slot></h6>
</div>
</div>
</div>
</div>
</template>
@@ -427,51 +330,27 @@ export default {
<!--show Ma-Details-->
<div class="col-md-9 text-nowrap mt-2">
<h4 v-if="!headerDataMaLoading">{{headerDataMa.titelpre}} {{headerDataMa.vorname}} {{headerDataMa.nachname}}<span v-if="headerDataMa?.titelpost">, </span> {{headerDataMa.titelpost}}</h4>
<h4 v-else><pv-skeleton width="15rem" height="2rem" borderRadius="16px"></pv-skeleton></h4>
<div class="d-flex align-items-center flex-wrap gap-1">
<strong class="text-muted">{{departmentData.organisationseinheittyp_kurzbz}}</strong>
<span v-if="!departmentDataLoading">
{{departmentData.bezeichnung}}
</span>
<span v-else>
<pv-skeleton width="12rem"></pv-skeleton>
</span>
<span v-if="leitungData.uid"> | </span>
<strong v-if="leitungData.uid" class="text-muted">Vorgesetzte*r </strong>
<span v-if="!leitungOrgLoading">
<a href="#" @click.prevent="goToLeitung">
{{leitungData.titelpre}} {{leitungData.vorname}} {{leitungData.nachname}}
<h4>{{headerDataMa.titelpre}} {{headerDataMa.vorname}} {{headerDataMa.nachname}}<span v-if="headerDataMa?.titelpost">, </span> {{headerDataMa.titelpost}}</h4>
<strong class="text-muted">{{departmentData.organisationseinheittyp_kurzbz}}</strong>
{{departmentData.bezeichnung}}
<span v-if="leitungData.uid"> | </span>
<strong v-if="leitungData.uid" class="text-muted">Vorgesetzte*r </strong>
<a href="#" @click.prevent="goToLeitung">
{{leitungData.titelpre}} {{leitungData.vorname}} {{leitungData.nachname}}
</a>
<p>
<strong class="text-muted">Email </strong>
<span v-if="headerDataMa && (headerDataMa.alias === undefined || headerDataMa.alias === null || headerDataMa.alias === '')">
<a :href="'mailto:' + mitarbeiter_uid + '@' + domain">
{{ mitarbeiter_uid }}@{{ domain }}
</a>
</span>
<span v-else>
<pv-skeleton width="5rem"></pv-skeleton>
<a :href="'mailto:'+headerDataMa?.alias+'@'+domain">{{headerDataMa.alias}}@{{domain}}</a>
</span>
</div>
<div class="d-flex align-items-center gap-2 flex-nowrap">
<div class="d-flex align-items-center gap-1">
<strong class="text-muted">Email</strong>
<template v-if="!headerDataMaLoading">
<a :href="'mailto:' + (headerDataMa?.alias || mitarbeiter_uid) + '@' + domain">
{{ (headerDataMa?.alias || mitarbeiter_uid) + '@' + domain }}
</a>
</template>
<pv-skeleton v-else width="10rem"></pv-skeleton>
</div>
<div v-if="headerDataMa?.telefonklappe" class="d-flex align-items-center gap-1">
<span>|</span>
<strong class="text-muted">DW</strong>
<template v-if="!headerDataMaLoading">
{{ headerDataMa.telefonklappe }}
</template>
<pv-skeleton v-else width="4rem"></pv-skeleton>
</div>
</div>
<span v-if="headerDataMa?.telefonklappe" class="mb-2"> | <strong class="text-muted">DW </strong>{{headerDataMa?.telefonklappe}}</span>
</p>
<slot name="tag"></slot>
</div>
<div class="col-md-1 d-flex flex-column align-items-end justify-content-start ms-auto">
@@ -481,33 +360,20 @@ export default {
</div>
<div v-if="hasTileGammaSlot" class="px-2" style="border-left: 1px solid #EEE">
<h4 class="mb-1 text-center"><slot name="titleGammaTile"></slot></h4>
<h6 class="text-muted d-flex align-items-center justify-content-center flex-wrap gap-1">
<pv-skeleton v-if="isLoading" width="4rem"></pv-skeleton>
<slot v-else name="valueGammaTile"></slot>
</h6>
<h6 class="text-muted text-center"><slot name="valueGammaTile"></slot></h6>
</div>
<div v-if="hasTileBetaSlot" class="px-2" style="border-left: 1px solid #EEE">
<h4 class="mb-1 text-center"><slot name="titleBetaTile"></slot></h4>
<h6 class="text-muted d-flex align-items-center justify-content-center flex-wrap gap-1">
<pv-skeleton v-if="isLoading" width="4rem"></pv-skeleton>
<slot v-else name="valueBetaTile"></slot>
</h6>
<h6 class="text-muted text-center"><slot name="valueBetaTile" :valueBetaTile="valueBetaTile"></slot></h6>
</div>
<div v-if="hasTileAlphaSlot" class="px-2" style="border-left: 1px solid #EEE">
<h4 class="mb-1 text-center"><slot name="titleAlphaTile"></slot></h4>
<h6 class="text-muted d-flex align-items-center justify-content-center flex-wrap gap-1">
<pv-skeleton v-if="isLoading" width="4rem"></pv-skeleton>
<slot v-else name="valueAlphaTile"></slot>
</h6>
<h6 class="text-muted text-center"><slot name="valueAlphaTile"></slot></h6>
</div>
<div v-if="hasTileUIDSlot" class="px-2" style="border-left: 1px solid #EEE">
<h4 class="mb-1 text-center">UID</h4>
<h6 class="text-muted d-flex align-items-center justify-content-center flex-wrap gap-1">
<pv-skeleton v-if="isLoading" width="4rem"></pv-skeleton>
<slot v-else name="uid"></slot>
</h6>
<h6 class="text-muted text-center"><slot name="uid"></slot></h6>
</div>
</div>
</div>
@@ -212,7 +212,6 @@ export default {
'url_studiengang': function (newVal, oldVal) {
if (newVal !== oldVal) {
this.checkUrlStudiengang();
this.$refs.stvList.clearSelection();
}
},
'url_mode': function () {
@@ -509,7 +508,7 @@ export default {
this.handlePersonUrl();
},
template: /* html */`
<div class="stv" :class="{ 'sidebar-collapsed': sidebarCollapsed }">
<div class="stv" :class="{ 'sidebar-collapsed': sidebarCollapsed }" data-cy="studentenverwaltung">
<header class="navbar navbar-expand-lg navbar-dark bg-dark flex-md-nowrap p-0 shadow">
<div class="col-md-4 col-lg-3 col-xl-2 d-flex align-items-center">
<button
@@ -633,14 +632,14 @@ export default {
</app-menu>
</div>
</aside>
<nav id="sidebarMenu" class="bg-light offcanvas offcanvas-start col-md p-md-0 h-100">
<nav id="sidebarMenu" class="bg-light offcanvas offcanvas-start col-md p-md-0 h-100" data-cy="stv-sidebar">
<div class="offcanvas-header justify-content-end px-1 d-md-none">
<button type="button" class="btn-close text-reset" data-bs-dismiss="offcanvas" :aria-label="$p.t('ui/schliessen')"></button>
</div>
<stv-verband :preselectedKey="studiengangKz ? '' + studiengangKz : null" :endpoint="verbandEndpoint" @select-verband="onSelectVerband" class="col" style="height:0%"></stv-verband>
<stv-studiensemester v-model:studiensemester-kurzbz="studiensemesterKurzbz" @update:studiensemester-kurzbz="studiensemesterChanged"></stv-studiensemester>
</nav>
<main class="col-md-8 ms-sm-auto col-lg-9 col-xl-10">
<main class="col-md-8 ms-sm-auto col-lg-9 col-xl-10" data-cy="stv-main">
<vertical-split>
<template #top>
<stv-list ref="stvList" v-model:selected="selected" :studiengang-kz="studiengangKz" :studiensemester-kurzbz="studiensemesterKurzbz" @filterActive="handleCustomFilter"></stv-list>
@@ -2,18 +2,12 @@ import FhcTabs from "../../Tabs.js";
import FhcHeader from "../../DetailHeader/DetailHeader.js";
import ApiStvApp from '../../../api/factory/stv/app.js';
import ApiStudent from '../../../api/factory/stv/students.js';
// TODO(chris): alt & title
// TODO(chris): phrasen
export default {
name: "DetailsPrestudent",
inject: {
currentSemester: {
from: 'currentSemester',
},
},
components: {
FhcTabs,
FhcHeader
@@ -21,8 +15,7 @@ export default {
data() {
return {
configStudent: {},
configStudents: {},
localStudent: null
configStudents: {}
};
},
props: {
@@ -47,9 +40,6 @@ export default {
}
return Object.fromEntries(Object.entries(this.configStudents).filter(([ , value ]) => !value.showOnlyWithUid && !value.showOnlyWithUid));
},
isLoading() {
return this.students === null; //null-> loading, [] -> empty, [...] -> data, necessary for skeleton in child
},
tile_PersId(){
let tile = this.students[0].person_id != null ? this.students[0].person_id : '-';
return tile;
@@ -67,21 +57,6 @@ export default {
'$p.user_language.value'(n, o) {
if (n !== o && o !== undefined)
this.loadConfig();
},
currentSemester(newVal) {
if (
Array.isArray(this.students) &&
this.students.length === 1 &&
newVal !== this.students[0].query_studiensemester_kurzbz
) {
this.reloadDataStudent();
}
else {
this.localStudent = null;
}
},
students() {
this.localStudent = null;
}
},
methods: {
@@ -103,20 +78,6 @@ export default {
if (this.$refs.tabs?.$refs?.current?.reload)
this.$refs.tabs.$refs.current.reload();
},
reloadDataStudent(){
this.localStudent = null;
const studentArr = this.students;
if (!studentArr || !studentArr.length) {
return;
}
this.$api
.call(ApiStudent.uid(studentArr[0].uid, this.currentSemester))
.then(result => {
this.localStudent = result.data;
});
},
reloadList() {
this.$emit('reload');
},
@@ -125,18 +86,16 @@ export default {
this.loadConfig();
},
template: `
<div class="stv-details h-100 d-flex flex-column">
<div class="stv-details h-100 d-flex flex-column" data-cy="stv-details">
<div v-if="!students?.length" class="justify-content-center d-flex h-100 align-items-center">
{{$p.t('ui', 'chooseStudent')}}
</div>
<div v-else-if="configStudent && configStudents" class="d-flex flex-column h-100">
<fhc-header
:headerData="localStudent || students"
:currentSemester="currentSemester"
:headerData="students"
typeHeader="student"
@reload="reloadList"
fotoEditable
:isLoading="isLoading"
>
<template #uid>{{students[0].uid}}</template>
<template #titleAlphaTile>PersID</template>
@@ -148,16 +107,27 @@ export default {
</fhc-header>
<fhc-tabs
v-if="students.length == 1"
ref="tabs"
ref="tabs"
data-cy="stv-details-tabs"
:useprimevue="true"
:modelValue="(Array.isArray(localStudent) && localStudent[0]) || students[0]"
:modelValue="students[0]"
:config="config"
:default="$route.params.tab"
style="flex: 1 1 0%; height: 0%"
@changed="reload"
>
</fhc-tabs>
<fhc-tabs v-else ref="tabs" :useprimevue="true" :modelValue="students" :config="config" :default="$route.params.tab" style="flex: 1 1 0%; height: 0%" @changed="reload"></fhc-tabs>
<fhc-tabs
v-else
ref="tabs"
data-cy="stv-details-tabs"
:useprimevue="true"
:modelValue="students"
:config="config"
:default="$route.params.tab"
style="flex: 1 1 0%; height: 0%"
@changed="reload">
</fhc-tabs>
</div>
<div v-else>
Loading...
@@ -13,7 +13,7 @@ export default {
}
},
template: `
<div class="stv-details-multistatus h-100">
<div class="stv-details-multistatus h-100" data-cy="stv-tab-multistatus">
<tbl-multi-status :model-value="modelValue" :config="config"></tbl-multi-status>
</div>
`
@@ -152,6 +152,7 @@ export default{
button.className = 'btn btn-outline-secondary btn-action';
button.innerHTML = '<i class="fa fa-forward"></i>';
button.title = this.$p.t('ui', 'btn_statusVorruecken');
button.setAttribute('data-cy', 'status-btn-advance');
button.addEventListener('click', () =>
this.actionAdvanceStatus(data.status_kurzbz, data.studiensemester_kurzbz, data.ausbildungssemester)
);
@@ -164,6 +165,7 @@ export default{
button.className = 'btn btn-outline-secondary btn-action';
button.innerHTML = '<i class="fa fa-check"></i>';
button.title = this.$p.t('ui', 'btn_confirmStatus');
button.setAttribute('data-cy', 'status-btn-confirm');
button.addEventListener('click', () =>
this.actionConfirmStatus(data.status_kurzbz, data.studiensemester_kurzbz, data.ausbildungssemester)
);
@@ -175,6 +177,7 @@ export default{
button.className = 'btn btn-outline-secondary btn-action';
button.innerHTML = '<i class="fa fa-edit"></i>';
button.title = this.$p.t('ui', 'btn_editStatus');
button.setAttribute('data-cy', 'status-btn-edit');
button.addEventListener('click', () =>
this.actionEditStatus(data.status_kurzbz, data.studiensemester_kurzbz, data.ausbildungssemester)
);
@@ -186,6 +189,7 @@ export default{
button.className = 'btn btn-outline-secondary btn-action';
button.innerHTML = '<i class="fa fa-xmark"></i>';
button.title = this.$p.t('ui', 'btn_deleteStatus');
button.setAttribute('data-cy', 'status-btn-delete');
button.addEventListener('click', () =>
this.actionDeleteStatus(data.status_kurzbz, data.studiensemester_kurzbz, data.ausbildungssemester)
);
@@ -204,6 +208,11 @@ export default{
{
row.getElement().classList.add('text-black','text-opacity-50','fst-italic');
}
// data-cy: unique per status entry for Cypress assertions
const stdsem = rowData.studiensemester_kurzbz ?? 'unknown';
const status = rowData.status_kurzbz ?? 'unknown';
const sem = rowData.ausbildungssemester ?? '0';
row.getElement().setAttribute('data-cy', `status-row-${stdsem}-${status}-${sem}`);
},
layout: 'fitDataStretchFrozen',
layoutColumnsOnNewData: false,
@@ -393,7 +402,7 @@ export default{
.catch(this.$fhcAlert.handleSystemError);
},
template: `
<div class="stv-multistatus h-100 pt-3">
<div class="stv-multistatus h-100 pt-3" data-cy="stv-multistatus">
<status-modal
ref="test"
:meldestichtag="new Date(dataMeldestichtag)"
@@ -405,6 +414,7 @@ export default{
<core-filter-cmpt
v-if="!this.modelValue.length"
ref="table"
data-cy="stv-multistatus-table"
:tabulator-options="tabulatorOptions"
:tabulator-events="tabulatorEvents"
table-only
@@ -142,6 +142,10 @@ export default {
row.getElement().classList.add('text-black','text-opacity-50','fst-italic');
}
row.getElement().draggable = true
// data-cy for Cypress e2e: prefer prestudent_id, fall back to uid or person_id
const d = row.getData();
const id = d.prestudent_id ?? d.uid ?? d.person_id ?? 'unknown';
row.getElement().setAttribute('data-cy', 'student-row-' + id);
},
ajaxRequestFunc: (url, config, params) => {
@@ -391,17 +395,15 @@ export default {
actionNewPrestudent() {
this.$refs.new.open();
},
rowSelectionChanged(data, rows, selected, deselected) {
rowSelectionChanged(data, rows) {
this.selectedcount = data.length;
if(selected.length > 0 || deselected.length > 0){
this.lastSelected = this.selected;
this.$emit('update:selected', data);
}
this.lastSelected = this.selected;
//for tags
this.selectedRows = this.$refs.table.tabulator.getSelectedRows();
this.selectedColumnValues = this.selectedRows.filter(row => row.getData().prestudent_id !== undefined && row.getData().prestudent_id).map(row => row.getData().prestudent_id);
this.$emit('update:selected', data);
},
autoSelectRows(data) {
if (Array.isArray(this.lastSelected) && this.lastSelected.length){
@@ -548,10 +550,6 @@ export default {
this.changeFocus(this.focusObj, el);
}
},
clearSelection(){
this.lastSelected = [];
this.$emit('update:selected',[]);
},
//methods tags
addedTag(addedTag)
{
@@ -606,11 +604,12 @@ export default {
// TODO(chris): focusin, focusout, keydown and tabindex should be in the filter component
// TODO(chris): filter component column chooser has no accessibilty features
template: `
<div class="stv-list h-100 pt-3">
<div class="stv-list h-100 pt-3" data-cy="stv-list">
<div
class="tabulator-container d-flex flex-column h-100"
:class="{'has-filter': filter.length}"
tabindex="0"
data-cy="stv-list-table-container"
@focusin="onFocus"
@keydown="onKeydown"
v-draggable:copyLink.capture="selectedDragObject"
@@ -61,6 +61,15 @@ export default {
},
noSemReloadNodes() {
return this.nodes.reduce(this.mapNodesToNoSemReloadNodes, []);
},
colPt() {
return {
rowToggler: ( options ) => {
return {
'data-cy': `tree-toggle-${options?.parent?.props?.node?.key ?? 'unknown'}`
}
}
}
}
},
watch: {
@@ -319,7 +328,7 @@ export default {
.catch(this.$fhcAlert.handleSystemError);
},
template: /* html */`
<div class="overflow-auto" tabindex="-1">
<div class="overflow-auto" tabindex="-1" data-cy="stv-verband-tree">
<pv-treetable
ref="tree"
class="stv-verband p-treetable-sm"
@@ -339,6 +348,7 @@ export default {
field="name"
expander
class="text-break"
:pt="colPt"
>
<template #header>
<div class="text-right">
@@ -349,6 +359,7 @@ export default {
v-model="filters['global']"
class="form-control ps-5"
placeholder="Search"
data-cy="verband-search"
>
</div>
</div>
@@ -358,6 +369,7 @@ export default {
v-if="['semester', 'verband', 'gruppe', 'gruppe_kurzbz'].some(key => node.data.hasOwnProperty(key))"
:data-tree-item-key="node.key"
:title="node.data.studiengang_kz"
:data-cy="'student-collection-'+node.key"
v-drag-click="() => toggleTreeNode(node)"
v-drop:link-strict.student-collection="(evt, students) => dropStudents(node, students)"
>
@@ -367,6 +379,7 @@ export default {
v-else
:data-tree-item-key="node.key"
:title="node.data.studiengang_kz"
:data-cy="'stg-node-label-'+node.key"
v-drag-click="() => toggleTreeNode(node)"
>
{{ node.data.name }}
@@ -383,6 +396,7 @@ export default {
v-if="favorites.on || favorites.list.length"
href="#"
@click.prevent="filterFav"
data-cy="favorite-icon-header"
>
<i
:class="favorites.on ? 'fa-solid' : 'fa-regular'"
@@ -398,6 +412,7 @@ export default {
data-link-fav-add
@click.prevent="markFav(node)"
@keydown.enter.stop.prevent="markFav(node)"
:data-cy="'favorite-icon-'+node.data.studiengang_kz"
>
<i
:class="favorites.list.includes(node.data.link + '') ? 'fa-solid' : 'fa-regular'"
-20
View File
@@ -57195,26 +57195,6 @@ I have been informed that I am under no obligation to consent to the transmissio
)
)
),
array(
'app' => 'core',
'category' => 'lehre',
'phrase' => 'textNoStatusInSem',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Kein Status im {sem}',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'No status in {sem}',
'description' => '',
'insertvon' => 'system'
)
)
),
);