feature(Calendar Moodle): adds and modifies the week and day view for moodle events

This commit is contained in:
SimonGschnell
2025-02-19 14:52:51 +01:00
parent 5cb09c8e7b
commit 40f64cc979
8 changed files with 195 additions and 98 deletions
+2 -2
View File
@@ -247,8 +247,8 @@ export default {
<template #dayPage="{event,day,mobile}">
<slot name="dayPage" :event="event" :day="day" :mobile="mobile"></slot>
</template>
<template #pageMobilContent="{lvMenu}">
<slot name="pageMobilContent" :lvMenu="lvMenu"></slot>
<template #pageMobilContent="{lvMenu, event}">
<slot name="pageMobilContent" :lvMenu="lvMenu" :event="event"></slot>
</template>
<template #pageMobilContentEmpty>
<slot name="pageMobilContentEmpty" ></slot>
+2 -2
View File
@@ -50,8 +50,8 @@ export default {
<template #dayPage="{event,day,mobile}">
<slot name="dayPage" :event="event" :day="day" :mobile="mobile" ></slot>
</template>
<template #pageMobilContent="{lvMenu}">
<slot name="pageMobilContent" :lvMenu="lvMenu" ></slot>
<template #pageMobilContent="{lvMenu, event}">
<slot name="pageMobilContent" :lvMenu="lvMenu" :event="event" ></slot>
</template>
<template #pageMobilContentEmpty>
<slot name="pageMobilContentEmpty" ></slot>
+31 -6
View File
@@ -93,6 +93,16 @@ export default {
}
},
computed: {
allDayEvents() {
let allDayEvents = {};
for (let day in this.events) {
const filteredAllDayEvents = this.events[day].filter(event => event.allDayEvent);
if (filteredAllDayEvents.length > 0) {
allDayEvents[day] = filteredAllDayEvents;
}
};
return allDayEvents;
},
overlayStyle() {
return {
'background-color': '#F5E9D7',
@@ -183,6 +193,7 @@ export default {
let d = {events: [], lanes: 1};
if (this.events[key]) {
this.events[key].forEach(evt => {
if (evt.allDayEvent) return;
let event = {
orig: evt,
lane: 1,
@@ -282,7 +293,7 @@ export default {
}
},
eventClick(evt) {
let event = evt.orig;
let event = evt.orig || evt;
this.setSelectedEvent(event);
this.$emit('input', event);
},
@@ -374,18 +385,32 @@ export default {
<div class="hours">
<div v-for="hour in hours" style="min-height:100px" :key="hour" class="text-muted text-end small" :ref="'hour' + hour">{{hour}}:00</div>
</div>
<div v-for="day in eventsPerDayAndHour" :key="day" class=" day border-start" :style="dayGridStyle(day)">
<div v-for="(day,dayindex) in eventsPerDayAndHour" :key="day" class=" day border-start" :style="dayGridStyle(day)">
<div class="position-absolute w-100" style="top:0; bottom:0;">
<div class="position-sticky d-grid " style="top:0;" v-for="(events,_day) in allDayEvents" :key="day">
<div v-if="dayindex == _day" v-for="event in events" :key="event" @click.prevent="eventClick(event)"
:selected="event == selectedEvent"
:style="{'background-color': event?.color, 'z-index':2, 'margin-bottom':'1px'}"
class="small rounded overflow-hidden fhc-entry"
v-contrast
>
<slot class="p-1" name="dayPage" :event="event" :day="day">
<p>this is a placeholder which means that no template was passed to the Calendar Page slot</p>
</slot>
</div>
</div>
</div>
<div v-if="lookingAtToday && !noEventsCondition" :style="overlayStyle"></div>
<div v-for="event in day.events" :key="event" :style="eventGridStyle(day,event)" v-contrast :selected="event.orig == selectedEvent" class="fhc-entry mx-2 small rounded overflow-hidden " >
<!-- desktop version of the page template, parent receives slotProp mobile = false -->
<div class="d-none d-xl-block h-100 " @click.prevent="eventClick(event)">
<slot name="dayPage" :event="event" :day="day" :mobile="false">
<slot name="dayPage" :event="event.orig" :day="day" :mobile="false">
<p>this is a slot placeholder</p>
</slot>
</div>
<!-- mobile version of the page template, parent receives slotProp mobile = true -->
<div class="d-block d-xl-none h-100" @click.prevent="eventClick(event)">
<slot name="dayPage" :event="event" :day="day" :mobile="true">
<slot name="dayPage" :event="event.orig" :day="day" :mobile="true">
<p>this is a slot placeholder</p>
</slot>
</div>
@@ -401,8 +426,8 @@ export default {
<div class="d-xl-block col-xl-6 p-4 d-none" style="max-height: 100%">
<div style="z-index:0; max-height: 100%" class="sticky-top d-flex justify-content-center align-items-center flex-column">
<div style="max-height: 100%; overflow-y:auto;" class="w-100">
<template v-if="selectedEvent && lvMenu">
<slot name="pageMobilContent" :lvMenu="lvMenu" >
<template v-if="selectedEvent ">
<slot name="pageMobilContent" :event="selectedEvent" :lvMenu="lvMenu" >
<p>this is a slot placeholder</p>
</slot>
</template>
+3 -3
View File
@@ -365,11 +365,11 @@ export default {
</div>
<div v-for="(day,dayindex) in eventsPerDayAndHour" :key="day" class=" day border-start position-relative" :style="dayGridStyle(day)">
<div class="position-absolute w-100" style="top:0; bottom:0;">
<div class="position-sticky d-grid gap-1" style="top:44px;" v-for="(events,_day) in allDayEvents" :key="day">
<div class="position-sticky d-grid " style="top:44px;" v-for="(events,_day) in allDayEvents" :key="day">
<div v-if="dayindex == _day" v-for="event in events" :key="event" @click.prevent="weekPageClick(event, _day)"
:selected="event == selectedEvent"
:style="{'background-color': event?.color, 'z-index':2}"
class="small rounded overflow-hidden fhc-entry "
:style="{'background-color': event?.color, 'z-index':2, 'margin-bottom':'1px'}"
class="small rounded overflow-hidden fhc-entry"
v-contrast
>
<slot class="p-1" name="weekPage" :event="event" :day="day">
+77 -50
View File
@@ -1,6 +1,5 @@
import { numberPadding, formatDate } from "../../../helpers/DateHelpers.js"
export default {
props: {
event: Object,
@@ -11,17 +10,23 @@ export default {
}
},
computed: {
lektorenLinks: function(){
LV_TYPES: function () {
return {
lehreinheit: "lehreinheit",
reservierung: "reservierung",
moodle: "moodle",
};
},
lektorenLinks: function () {
if (!this.event || !Array.isArray(this.event.lektor) || !this.event.lektor.length) return "a";
let lektorenLinks ={};
this.event.lektor.forEach((lektor)=>{
let lektorenLinks = {};
this.event.lektor.forEach((lektor) => {
lektorenLinks[lektor.kurzbz] = FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + `/Cis/Profil/View/${lektor.mitarbeiter_uid}`;
})
return lektorenLinks;
},
getOrtContentLink: function()
{
getOrtContentLink: function () {
if (!this.event || !this.event.ort_content_id) return "a";
return FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + `/CisVue/Cms/content/${this.event.ort_content_id}`
@@ -61,52 +66,74 @@ export default {
<td>{{methodFormatDate(event.datum)}}</td>
</tr>
<tr>
<th>{{
$p.t('global','raum')?
$p.t('global','raum')+':'
:''
}}</th>
<td>
<a v-if="event.ort_content_id" :href="getOrtContentLink"><i class="fa fa-arrow-up-right-from-square me-1" style="color:#00649C"></i></a>
{{event.ort_kurzbz}}
</td>
<template v-if="event.type == LV_TYPES.moodle">
<th>{{$p.t('global','aktivitaet')}}:</th>
<td>{{event?.assignment}}</td>
</template>
<template v-else>
<th>{{
$p.t('global','raum')?
$p.t('global','raum')+':'
:''
}}</th>
<td>
<a v-if="event.ort_content_id" :href="getOrtContentLink"><i class="fa fa-arrow-up-right-from-square me-1" style="color:#00649C"></i></a>
{{event.ort_kurzbz}}
</td>
</template>
</tr>
<template v-if="event.type != LV_TYPES.moodle">
<tr>
<th>{{
$p.t('lehre','lehrveranstaltung')?
$p.t('lehre','lehrveranstaltung')+':'
:''
}}</th>
<td>{{'('+event.lehrform+') ' + event.lehrfach_bez}}</td>
</tr>
</template>
<template v-if="event.type != LV_TYPES.moodle">
<tr>
<th>{{
$p.t('lehre','lektor')?
$p.t('lehre','lektor')+':'
:''
}}</th>
<td>
<div v-for="lektor in event.lektor" class="d-block">
<a v-if="lektorenLinks[lektor.kurzbz]" :href="lektorenLinks[lektor.kurzbz]"><i class="fa fa-arrow-up-right-from-square me-1" style="color:#00649C"></i></a>
{{lektor.kurzbz}}
</div>
</td>
</tr>
</template>
<tr>
<template v-if="event.type == LV_TYPES.moodle">
<th>{{$p.t('global','typ')}}:</th>
<td>{{event?.purpose}}</td>
</template>
<template v-else>
<th>{{
$p.t('ui','zeitraum')?
$p.t('ui','zeitraum')+':'
:''
}}</th>
<td>{{start_time + ' - ' + end_time}}</td>
</template>
</tr>
<tr>
<th>{{
$p.t('lehre','lehrveranstaltung')?
$p.t('lehre','lehrveranstaltung')+':'
:''
}}</th>
<td>{{'('+event.lehrform+') ' + event.lehrfach_bez}}</td>
</tr>
<tr>
<th>{{
$p.t('lehre','lektor')?
$p.t('lehre','lektor')+':'
:''
}}</th>
<td>
<div v-for="lektor in event.lektor" class="d-block">
<a v-if="lektorenLinks[lektor.kurzbz]" :href="lektorenLinks[lektor.kurzbz]"><i class="fa fa-arrow-up-right-from-square me-1" style="color:#00649C"></i></a>
{{lektor.kurzbz}}
</div>
</td>
</tr>
<tr>
<th>{{
$p.t('ui','zeitraum')?
$p.t('ui','zeitraum')+':'
:''
}}</th>
<td>{{start_time + ' - ' + end_time}}</td>
</tr>
<tr>
<th>{{
$p.t('lehre','organisationseinheit')?
$p.t('lehre','organisationseinheit')+':'
:''
}}</th>
<td>{{event.organisationseinheit}}</td>
<template v-if="event.type == LV_TYPES.moodle">
<th>{{$p.t('fristenmanagement','frist')}}:</th>
<td>{{start_time}}</td>
</template>
<template v-else>
<th>{{
$p.t('lehre','organisationseinheit')?
$p.t('lehre','organisationseinheit')+':'
:''
}}</th>
<td>{{event.organisationseinheit}}</td>
</template>
</tr>
</tbody>
</table>
+10 -2
View File
@@ -70,11 +70,19 @@ export default {
template: /*html*/ `
<bs-modal ref="modalContainer" @showBsModal="onModalShow" @hideBsModal="onModalHide" v-bind="$props" :bodyClass="''" dialogClass='modal-lg' class="bootstrap-alert" backdrop="false" >
<template v-slot:title>
<template v-if="event.titel">{{ event.titel + ' - ' + event.lehrfach_bez + ' [' + event.ort_kurzbz+']'}}</template>
<template v-if="event?.type=='moodle'">{{event.titel}}</template>
<template v-else-if="event.titel">{{ event.titel + ' - ' + event.lehrfach_bez + ' [' + event.ort_kurzbz+']'}}</template>
<template v-else>{{ event.lehrfach_bez + ' [' + event.ort_kurzbz+']'}}</template>
</template>
<template v-slot:default>
<h3 >{{$p.t('lvinfo','lehrveranstaltungsinformationen')}}</h3>
<h3>
<template v-if="event?.type =='moodle'">
{{$p.t('lvinfo','Moodleinformationen')}}
</template>
<template v-else>
{{$p.t('lvinfo','lehrveranstaltungsinformationen')}}
</template>
</h3>
<lv-info :event="event"></lv-info>
<template v-if="showMenu && this.menu">
<h3 >Lehrveranstaltungs Menu</h3>
@@ -154,23 +154,28 @@ export const Stundenplan = {
let date_end = Math.floor(new Date(end_date).getTime() / 1000);
return this.$fhcApi.factory.stundenplan.getMoodleEventsByUserid('io23m005', date_start, date_end).then((response) => response.events).then(events => {
let data =events.map(event =>{
const start_date = new Date(event.timestart * 1000);
const formatted_year = Intl.DateTimeFormat(this.$p.user_locale, { year: 'numeric' }).format(start_date);
const formatted_month = Intl.DateTimeFormat(this.$p.user_locale, { month: '2-digit' }).format(start_date);
const formatted_day = Intl.DateTimeFormat(this.$p.user_locale, { year: '2-digit' }).format(start_date);
const formatted_date = `${formatted_year}-${formatted_month}-${formatted_day}`;
const event_start_date = new Date(Number(event.timestart) * 1000);
const event_end_date = new Date(((Number(event.timestart) + Number(event.timeduration)) * 1000));
const formatted_date = `${event_start_date.getFullYear()}-${event_start_date.getMonth()+1}-${event_start_date.getDate()}`;
// to get the same date and time as in moodle, we use the default UTC time zone
const formatted_start_time = event_start_date.toLocaleTimeString(this.$p.user_locale, {hour:'2-digit',minute:'2-digit', second:'2-digit',hour12:false, timeZone:'UTC'});
const formatted_end_time = event_end_date.toLocaleTimeString(this.$p.user_locale, { hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false, timeZone: 'UTC' });
return {
type:'moodle',
beginn: "14:00:00",
ende: "15:00:00",
beginn: formatted_start_time,
ende: formatted_end_time,
allDayEvent: true,
datum: formatted_date,
topic: event.activityname,
purpose: event.purpose,
assignment: event.activityname,
topic: event.activitystr,
lektor:[],
gruppe:[],
ort_kurzbz: event.location,
lehreinheit_id:0,
titel: event.activitystr,
//moodle idnumber entspricht der course id number die man den Kurs in Moodle vergeben kann
lehreinheit_id:event.lehreinheitsNummber??null,
titel: event.course.fullname,
lehrfach:'',
lehrform:'',
lehrfach_bez:'',
@@ -233,7 +238,7 @@ export const Stundenplan = {
</div>
<div v-if="event.type=='moodle'" class="d-flex small w-100" >
<span >moodle:</span>
<span class="flex-grow-1 text-center">{{event.titel}}</span>
<span class="flex-grow-1 text-center">{{event.topic}}</span>
</div>
<div v-else class="d-flex flex-column flex-grow-1 align-items-center small">
<span>{{event.topic}}</span>
@@ -243,34 +248,46 @@ export const Stundenplan = {
</div>
</template>
<template #dayPage="{event,day,mobile}">
<div @click="mobile? showModal(event?.orig):null" type="button" class="fhc-entry border border-secondary border row m-0 h-100 justify-content-center align-items-center text-center">
<div class="col-auto" v-if="event?.orig?.beginn && event?.orig?.ende" >
<div class="d-flex flex-column p-4 border-end border-secondary">
<span class="small">{{convertTime(event.orig.beginn.split(":"))}}</span>
<span class="small">{{convertTime(event.orig.ende.split(":"))}}</span>
<div @click="mobile? showModal(event):null" type="button" class="fhc-entry border border-secondary border m-0 h-100 text-center">
<template v-if="event.type=='moodle'">
<div class="d-flex align-items-center w-100" >
<span class="p-2">moodle:</span>
<span class="flex-grow-1 text-center">{{event.topic}}</span>
</div>
</div>
<div class="col ">
<p>Lehrveranstaltung:</p>
<p class="m-0">{{event?.orig.topic}}</p>
</div>
<div class="col ">
<p>Lektor:</p>
<p class="m-0" v-for="lektor in event?.orig.lektor">{{lektor.kurzbz}}</p>
</div>
<div class="col ">
<p>Ort: </p>
<p class="m-0">{{event?.orig.ort_kurzbz}}</p>
</div>
</template>
<template v-else>
<div class="row justify-content-center align-items-center">
<div class="col-auto" v-if="!event.allDayEvent && event?.beginn && event?.ende" >
<div class="d-flex flex-column p-4 border-end border-secondary">
<span class="small">{{convertTime(event.beginn.split(":"))}}</span>
<span class="small">{{convertTime(event.ende.split(":"))}}</span>
</div>
</div>
<div class="col ">
<p>Lehrveranstaltung:</p>
<p class="m-0">{{event?.topic}}</p>
</div>
<div class="col ">
<p>Lektor:</p>
<p class="m-0" v-for="lektor in event?.lektor">{{lektor.kurzbz}}</p>
</div>
<div class="col ">
<p>Ort: </p>
<p class="m-0">{{event?.ort_kurzbz}}</p>
</div>
</div>
</template>
</div>
</template>
<template #pageMobilContent="{lvMenu}">
<template #pageMobilContent="{lvMenu, event}">
<h3 >{{$p.t('lvinfo','lehrveranstaltungsinformationen')}}</h3>
<div class="w-100">
<lv-info :event="currentlySelectedEvent" />
<lv-info :event="event" />
</div>
<h3 >Lehrveranstaltungs Menu</h3>
<lv-menu :containerStyles="['p-0']" :rowStyles="['m-0']" v-show="lvMenu" :menu="lvMenu" />
<template v-if="event.type != 'moodle'">
<h3 >Lehrveranstaltungs Menu</h3>
<lv-menu :containerStyles="['p-0']" :rowStyles="['m-0']" v-show="lvMenu" :menu="lvMenu" />
</template>
</template>
<template #pageMobilContentEmpty >
<h3>Keine Lehrveranstaltungen</h3>
+20
View File
@@ -20164,6 +20164,26 @@ array(
)
)
),
array(
'app' => 'core',
'category' => 'lvinfo',
'phrase' => 'Moodleinformationen',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => "Moodle Informationen",
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => "Moodle Information",
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'lehre',