mirror of
https://github.com/FH-Complete/FHC-Core.git
synced 2026-07-23 09:52:22 +00:00
intercept a tag clicks and attempt vue routing to avoid having to know about vue router configuration; routes include Stundenplan, MyLv;
This commit is contained in:
@@ -61,8 +61,7 @@ $route['api/v1/organisation/[O|o]rganisationseinheit/(:any)'] = 'api/v1/organisa
|
||||
$route['api/v1/ressource/[B|b]etriebsmittelperson/(:any)'] = 'api/v1/ressource/betriebsmittelperson2/$1';
|
||||
$route['api/v1/system/[S|s]prache/(:any)'] = 'api/v1/system/sprache2/$1';
|
||||
|
||||
$route['CisVue'] = 'CisVue/dashboard';
|
||||
$route['Cis/Stundenplan/(:any)'] = 'Cis/Stundenplan';
|
||||
$route['Cis/Stundenplan/(:any)?'] = 'Cis/Stundenplan/index/$1';
|
||||
|
||||
// load routes from extensions
|
||||
$subdir = 'application/config/extensions';
|
||||
|
||||
@@ -26,9 +26,12 @@ class MyLv extends Auth_Controller
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$this->load->view('Cis/MyLv');
|
||||
|
||||
// $this->load->view('Cis/CisRouterView');
|
||||
$viewData = array(
|
||||
|
||||
);
|
||||
|
||||
$this->load->view('CisRouterView/CisRouterView.php', ['viewData' => $viewData, 'route' => 'MyLv']);
|
||||
}
|
||||
|
||||
public function Info($studien_semester,$lvid)
|
||||
|
||||
@@ -23,8 +23,13 @@ class Stundenplan extends Auth_Controller
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function index()
|
||||
public function index($lv_id = null)
|
||||
{
|
||||
$this->load->view('Cis/Stundenplan');
|
||||
|
||||
$viewData = array(
|
||||
'lv_id' => $lv_id
|
||||
);
|
||||
|
||||
$this->load->view('CisRouterView/CisRouterView.php', ['viewData' => $viewData, 'route' => 'Stundenplan']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,6 @@ class Cis4 extends Auth_Controller
|
||||
'person_id' => $personData->person_id
|
||||
);
|
||||
|
||||
$this->load->view('CisRouterView/CisRouterView.php',['viewData' => $viewData]);
|
||||
$this->load->view('CisRouterView/CisRouterView.php',['viewData' => $viewData, 'route' => 'FhcDashboard']);
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
<?php
|
||||
$includesArray = array(
|
||||
'title' => 'MyLv',
|
||||
'primevue3' => true,
|
||||
'customJSModules' => ['public/js/apps/Cis/MyLv/Student.js'],
|
||||
'customCSSs' => ['public/css/components/MyLv.css']
|
||||
);
|
||||
|
||||
$this->load->view('templates/CISVUE-Header', $includesArray);
|
||||
?>
|
||||
|
||||
<div id="content">
|
||||
<mylv-student></mylv-student>
|
||||
</div>
|
||||
|
||||
<?php $this->load->view('templates/CISVUE-Footer', $includesArray); ?>
|
||||
@@ -1,16 +0,0 @@
|
||||
<?php
|
||||
$includesArray = array(
|
||||
'title' => 'Stundenplan',
|
||||
'primevue3' => true,
|
||||
'customJSModules' => ['public/js/apps/Cis/Stundenplan.js'],
|
||||
'customCSSs' => ['public/css/components/calendar.css']
|
||||
);
|
||||
|
||||
$this->load->view('templates/CISVUE-Header', $includesArray);
|
||||
?>
|
||||
|
||||
<div id="content">
|
||||
|
||||
</div>
|
||||
|
||||
<?php $this->load->view('templates/CISVUE-Footer', $includesArray); ?>
|
||||
@@ -12,7 +12,12 @@ $includesArray = array(
|
||||
'public/css/components/verticalsplit.css',
|
||||
'public/css/components/searchbar.css',
|
||||
'public/css/Fhc.css',
|
||||
'public/css/components/dashboard.css'
|
||||
'public/css/components/dashboard.css',
|
||||
'public/css/components/calendar.css',
|
||||
'public/css/components/MyLv.css',
|
||||
'public/css/components/FilterComponent.css',
|
||||
'public/css/components/Profil.css',
|
||||
'public/css/components/FormUnderline.css'
|
||||
),
|
||||
'customJSs' => array(
|
||||
'vendor/npm-asset/primevue/accordion/accordion.js',
|
||||
@@ -26,7 +31,7 @@ $includesArray = array(
|
||||
|
||||
$this->load->view('templates/CISVUE-Header', $includesArray);
|
||||
?>
|
||||
<div id="fhccontent">
|
||||
<div id="fhccontent" route=<?php echo $route ?>>
|
||||
<router-view view-data-string='<?php echo json_encode($viewData) ?>'></router-view>
|
||||
</div>
|
||||
<?php $this->load->view('templates/CISVUE-Footer', $includesArray); ?>
|
||||
@@ -28,43 +28,10 @@ const router = VueRouter.createRouter({
|
||||
|
||||
const app = Vue.createApp({
|
||||
name: 'CmsApp',
|
||||
data() {
|
||||
return {
|
||||
interceptHandler: this.intercept
|
||||
}
|
||||
},
|
||||
components: {
|
||||
CmsNews,
|
||||
CmsContent,
|
||||
},
|
||||
methods: {
|
||||
intercept(e) {
|
||||
// TODO: maybe a more sophisticated menu link click detection is possible?
|
||||
if (e.target.tagName === "A" && e.target.pathname?.includes(ciPath) && e.target.pathname.includes('Cms/content')) {
|
||||
const pathParts = e.target.pathname.split('/').filter(Boolean);
|
||||
const idString = pathParts[pathParts.length - 1];
|
||||
const content_id = idString && !isNaN(Number(idString)) ? idString : null; // only return id if it is a number string since the path might contain invalid elements
|
||||
|
||||
e.preventDefault() // prevents normal browser page load
|
||||
this.$router.push({
|
||||
name: 'Content',
|
||||
params: {
|
||||
content_id
|
||||
}
|
||||
})
|
||||
|
||||
} else if(e.target.tagName === "A" && e.target.pathname?.includes(ciPath) && e.target.pathname.includes('Cms/news')) {
|
||||
//handle news content
|
||||
|
||||
e.preventDefault() // prevents normal browser page load
|
||||
this.$router.push({
|
||||
name: 'News',
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
document.querySelectorAll("#cms [data-confirm]").forEach((el) => {
|
||||
el.addEventListener("click", (evt) => {
|
||||
@@ -88,16 +55,13 @@ const app = Vue.createApp({
|
||||
FHC_JS_DATA_STORAGE_OBJECT.app_root
|
||||
);
|
||||
});
|
||||
document.addEventListener("click", this.interceptHandler, {capture: true, passive: false})
|
||||
},
|
||||
unmounted() {
|
||||
document.removeEventListener('click', this.interceptHandler)
|
||||
}
|
||||
});
|
||||
|
||||
setScrollbarWidth();
|
||||
|
||||
app.use(router);
|
||||
window.cmsRouter = router;
|
||||
app.use(FhcApi);
|
||||
app.use(primevue.config.default, { zIndex: { overlay: 9999 } });
|
||||
app.use(Phrasen);
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
import MylvStudent from "../../../components/Cis/Mylv/Student.js";
|
||||
import Phrasen from "../../../plugin/Phrasen.js";
|
||||
import {setScrollbarWidth} from "../../../helpers/CssVarCalcHelpers";
|
||||
|
||||
const app = Vue.createApp({
|
||||
name: 'MyLvStudentApp',
|
||||
components: {
|
||||
MylvStudent
|
||||
}
|
||||
})
|
||||
|
||||
setScrollbarWidth();
|
||||
|
||||
app.use(Phrasen).mount('#content');
|
||||
@@ -1,167 +0,0 @@
|
||||
import FhcCalendar from "../../components/Calendar/Calendar.js";
|
||||
import Phrasen from "../../plugin/Phrasen.js";
|
||||
import CalendarDate from "../../composables/CalendarDate.js";
|
||||
import LvModal from "../../components/Cis/Mylv/LvModal.js";
|
||||
import LvInfo from "../../components/Cis/Mylv/LvInfo.js"
|
||||
import LvMenu from "../../components/Cis/Mylv/LvMenu.js"
|
||||
import Json from "../../helpers/Json.js"
|
||||
|
||||
|
||||
const app = Vue.createApp({
|
||||
name: 'StundenplanApp',
|
||||
data() {
|
||||
return {
|
||||
events: null,
|
||||
calendarDate: new CalendarDate(new Date()),
|
||||
currentlySelectedEvent: null,
|
||||
currentDay: new Date(),
|
||||
minimized: false,
|
||||
}
|
||||
},
|
||||
components: {
|
||||
FhcCalendar, LvModal, LvMenu, LvInfo
|
||||
},
|
||||
computed:{
|
||||
lv_id() { // computed so we can theoretically change path/lva selection and reload without page refresh
|
||||
const pathParts = window.location.pathname.split('/').filter(Boolean);
|
||||
const id = pathParts[pathParts.length - 1];
|
||||
return id && !isNaN(Number(id)) ? id : null; // only return id if it is a number string since the path might contain invalid elements
|
||||
},
|
||||
weekFirstDay: function () {
|
||||
return this.calendarDateToString(this.calendarDate.cdFirstDayOfWeek);
|
||||
},
|
||||
weekLastDay: function () {
|
||||
return this.calendarDateToString(this.calendarDate.cdLastDayOfWeek);
|
||||
},
|
||||
monthFirstDay: function () {
|
||||
return this.calendarDateToString(this.calendarDate.cdFirstDayOfCalendarMonth);
|
||||
},
|
||||
monthLastDay: function () {
|
||||
return this.calendarDateToString(this.calendarDate.cdLastDayOfCalendarMonth);
|
||||
},
|
||||
|
||||
},
|
||||
methods:{
|
||||
setSelectedEvent: function (event) {
|
||||
this.currentlySelectedEvent = event;
|
||||
},
|
||||
selectDay: function(day){
|
||||
this.currentDay = day;
|
||||
},
|
||||
showModal: function(event){
|
||||
this.currentlySelectedEvent = event;
|
||||
Vue.nextTick(() => {
|
||||
this.$refs.lvmodal.show();
|
||||
});
|
||||
},
|
||||
updateRange: function ({start,end}) {
|
||||
|
||||
let checkDate = (date) => {
|
||||
return date.m != this.calendarDate.m || date.y != this.calendarDate.y;
|
||||
}
|
||||
|
||||
// only load month data if the month or year has changed
|
||||
if (checkDate(new CalendarDate(start)) && checkDate(new CalendarDate(end))){
|
||||
// reset the events before querying the new events to activate the loading spinner
|
||||
this.events = null;
|
||||
this.calendarDate = new CalendarDate(end);
|
||||
Vue.nextTick(() => {
|
||||
this.loadEvents();
|
||||
});
|
||||
}
|
||||
},
|
||||
calendarDateToString: function (calendarDate) {
|
||||
return calendarDate instanceof CalendarDate ?
|
||||
[calendarDate.y, calendarDate.m + 1, calendarDate.d].join('-') :
|
||||
null;
|
||||
|
||||
},
|
||||
loadEvents: function(){
|
||||
Promise.allSettled([
|
||||
this.$fhcApi.factory.stundenplan.getStundenplan(this.monthFirstDay, this.monthLastDay, this.lv_id),
|
||||
this.$fhcApi.factory.stundenplan.getStundenplanReservierungen(this.monthFirstDay, this.monthLastDay)
|
||||
]).then((result) => {
|
||||
let promise_events = [];
|
||||
result.forEach((promise_result) => {
|
||||
if (promise_result.status === 'fulfilled' && promise_result.value.meta.status === "success") {
|
||||
|
||||
let data = promise_result.value.data;
|
||||
// adding additional information to the events
|
||||
if (data && data.forEach) {
|
||||
|
||||
data.forEach((el, i) => {
|
||||
el.id = i;
|
||||
if (el.type === 'reservierung') {
|
||||
el.color = '#' + (el.farbe || 'FFFFFF');
|
||||
} else {
|
||||
el.color = '#' + (el.farbe || 'CCCCCC');
|
||||
}
|
||||
|
||||
el.start = new Date(el.datum + ' ' + el.beginn);
|
||||
el.end = new Date(el.datum + ' ' + el.ende);
|
||||
|
||||
});
|
||||
}
|
||||
promise_events = promise_events.concat(data);
|
||||
}
|
||||
})
|
||||
this.events = promise_events;
|
||||
});
|
||||
},
|
||||
},
|
||||
created()
|
||||
{
|
||||
this.loadEvents();
|
||||
},
|
||||
template:/*html*/`
|
||||
<h2>{{$p.t('lehre/stundenplan')}}</h2>
|
||||
<hr>
|
||||
<lv-modal v-if="currentlySelectedEvent" :event="currentlySelectedEvent" ref="lvmodal" />
|
||||
<fhc-calendar @selectedEvent="setSelectedEvent" :initial-date="currentDay" @change:range="updateRange" :events="events" initial-mode="week" show-weeks @select:day="selectDay" v-model:minimized="minimized">
|
||||
<template #monthPage="{event,day,isSelected}">
|
||||
<span class="fhc-entry" :class="{'selectedEvent':isSelected}" style="color:white" :style="{'background-color': event.color}">
|
||||
{{event.topic}}
|
||||
</span>
|
||||
</template>
|
||||
<template #weekPage="{event,day,isSelected}">
|
||||
<div @click="showModal(event?.orig)" type="button" :class="{'selectedEvent':isSelected}"
|
||||
class="fhc-entry border border-secondary border d-flex flex-column align-items-center
|
||||
justify-content-evenly h-100" style="max-height: 75px; overflow: auto;">
|
||||
<span>{{event?.orig.topic}}</span>
|
||||
<span v-for="lektor in event?.orig.lektor">{{lektor.kurzbz}}</span>
|
||||
<span>{{event?.orig.ort_kurzbz}}</span>
|
||||
</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 ">
|
||||
<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>
|
||||
</div>
|
||||
</template>
|
||||
<template #pageMobilContent="{lvMenu}">
|
||||
<h3 >{{$p.t('lvinfo','lehrveranstaltungsinformationen')}}</h3>
|
||||
<div class="w-100">
|
||||
<lv-info :event="currentlySelectedEvent" />
|
||||
</div>
|
||||
<h3 >Lehrveranstaltungs Menu</h3>
|
||||
<lv-menu :containerStyles="['p-0']" :rowStyles="['m-0']" v-show="lvMenu" :menu="lvMenu" />
|
||||
</template>
|
||||
<template #pageMobilContentEmpty >
|
||||
<h3>Keine Lehrveranstaltungen</h3>
|
||||
</template>
|
||||
</fhc-calendar>
|
||||
`
|
||||
});
|
||||
app.use(Phrasen);
|
||||
app.component('json', Json);
|
||||
app.mount('#content');
|
||||
@@ -1,18 +0,0 @@
|
||||
import {CoreNavigationCmpt} from '../components/navigation/Navigation.js';
|
||||
import CoreDashboard from '../components/Dashboard/Dashboard.js';
|
||||
import FhcApi from '../../plugin/FhcApi.js';
|
||||
import Phrasen from '../../plugin/Phrasen.js';
|
||||
|
||||
const app = Vue.createApp({
|
||||
name: 'DashboardApp',
|
||||
data: () => ({
|
||||
appSideMenuEntries: {}
|
||||
}),
|
||||
components: {
|
||||
CoreNavigationCmpt,
|
||||
CoreDashboard
|
||||
}
|
||||
})
|
||||
app.use(FhcApi);
|
||||
app.use(Phrasen);
|
||||
app.mount('#main');
|
||||
+107
-49
@@ -1,61 +1,119 @@
|
||||
import FhcDashboard from '../../components/Dashboard/Dashboard.js';
|
||||
import FhcApi from '../../plugin/FhcApi.js';
|
||||
import Phrasen from '../../plugin/Phrasen.js';
|
||||
import { setScrollbarWidth } from "../../helpers/CssVarCalcHelpers";
|
||||
import {setScrollbarWidth} from "../../helpers/CssVarCalcHelpers";
|
||||
import Stundenplan from "../../components/Cis/Stundenplan/Stundenplan";
|
||||
import MylvStudent from "../../components/Cis/Mylv/Student";
|
||||
import Profil from "../../components/Cis/Profil/Profil";
|
||||
|
||||
|
||||
const ciPath = FHC_JS_DATA_STORAGE_OBJECT.app_root.replace(/(https:|)(^|\/\/)(.*?\/)/g, '') + FHC_JS_DATA_STORAGE_OBJECT.ci_router;
|
||||
|
||||
const router = VueRouter.createRouter({
|
||||
history: VueRouter.createWebHistory(`/${ciPath}`),
|
||||
routes: [
|
||||
{
|
||||
path: `/Cis/Stundenplan`,
|
||||
name: 'Stundenplan',
|
||||
component: Stundenplan,
|
||||
props: true
|
||||
},
|
||||
{
|
||||
path: `/`,
|
||||
name: 'FhcDashboard',
|
||||
component: FhcDashboard,
|
||||
props: {dashboard: 'CIS'},
|
||||
alias: ['/Cis4']
|
||||
},
|
||||
{
|
||||
path: '/:catchAll(.*)',
|
||||
redirect: { name: 'FhcDashboard'},
|
||||
props: true
|
||||
}
|
||||
]
|
||||
history: VueRouter.createWebHistory(`/${ciPath}`),
|
||||
routes: [
|
||||
// {
|
||||
// path: `/Cis/News`,
|
||||
// name: 'Profil',
|
||||
// component: Profil,
|
||||
// props: true
|
||||
// },
|
||||
// {
|
||||
// path: `/Cis/Profil`,
|
||||
// name: 'Profil',
|
||||
// component: Profil,
|
||||
// props: true
|
||||
// },
|
||||
{
|
||||
path: `/Cis/MyLv`,
|
||||
name: 'MyLv',
|
||||
component: MylvStudent,
|
||||
props: true
|
||||
},
|
||||
{
|
||||
path: `/Cis/Stundenplan/:lv_id?`,
|
||||
name: 'Stundenplan',
|
||||
component: Stundenplan
|
||||
},
|
||||
{
|
||||
path: `/`,
|
||||
name: 'FhcDashboard',
|
||||
component: FhcDashboard,
|
||||
props: {dashboard: 'CIS'}
|
||||
},
|
||||
{
|
||||
path: '/:catchAll(.*)',
|
||||
redirect: {name: 'FhcDashboard'},
|
||||
props: true
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
router.beforeEach((from, to) => {
|
||||
console.log('from', from)
|
||||
console.log('to', to)
|
||||
router.beforeEach((to, from) => {
|
||||
console.log('from', from)
|
||||
console.log('to', to)
|
||||
|
||||
})
|
||||
|
||||
router.beforeResolve(async to => {
|
||||
// TODO: check if necessary viewData params have been provided
|
||||
// if (to.meta.requiresCamera) {
|
||||
// try {
|
||||
// await askForCameraPermission()
|
||||
// } catch (error) {
|
||||
// if (error instanceof NotAllowedError) {
|
||||
// // ... handle the error and then cancel the navigation
|
||||
// return false
|
||||
// } else {
|
||||
// // unexpected error, cancel the navigation and pass the error to the global handler
|
||||
// throw error
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
})
|
||||
|
||||
const app = Vue.createApp({
|
||||
name: 'FhcApp',
|
||||
data: () => ({
|
||||
appSideMenuEntries: {}
|
||||
}),
|
||||
components: {
|
||||
FhcDashboard,
|
||||
Stundenplan
|
||||
},
|
||||
methods: {
|
||||
tryCis4Navigate(e) {
|
||||
this.$router.push({ name: e.detail });
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
window.addEventListener('fhcnavigate', this.tryCis4Navigate);
|
||||
this.$router.push({ name: 'FhcDashboard' });
|
||||
},
|
||||
beforeUnmount() {
|
||||
window.removeEventListener('fhcnavigate', this.tryCis4Navigate);
|
||||
},
|
||||
name: 'FhcApp',
|
||||
data: () => ({
|
||||
appSideMenuEntries: {}
|
||||
}),
|
||||
components: {},
|
||||
methods: {
|
||||
isInternalRoute(href) {
|
||||
const internalBase = window.location.origin
|
||||
return href.startsWith(internalBase);
|
||||
},
|
||||
handleClick(event) {
|
||||
const target = event.target.closest('a');
|
||||
// TODO: handle case of is internalRoute but not defined in vue router
|
||||
if (target && this.isInternalRoute(target.href)) {
|
||||
event.preventDefault(); // Prevent browser navigation
|
||||
const path = new URL(target.href).pathname
|
||||
const base = this.$router.options.history.base
|
||||
const route = path.replace(base, '') || '/'
|
||||
|
||||
this.$router.push(route);
|
||||
}
|
||||
},
|
||||
tryCis4Navigate(e) {
|
||||
this.$router.push({name: e.detail});
|
||||
},
|
||||
getInitialRoute() {
|
||||
const el = document.getElementById('fhccontent')
|
||||
const r = el?.getAttribute('route')
|
||||
if (r) return r
|
||||
return 'FhcDashboard'
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// window.addEventListener('beforeunload', this.beforeUnloadListener)
|
||||
document.addEventListener('click', this.handleClick);
|
||||
window.addEventListener('fhcnavigate', this.tryCis4Navigate);
|
||||
this.$router.push({name: this.getInitialRoute()});
|
||||
},
|
||||
beforeUnmount() {
|
||||
document.removeEventListener('click', this.handleClick);
|
||||
},
|
||||
});
|
||||
|
||||
setScrollbarWidth();
|
||||
@@ -63,10 +121,10 @@ app.use(router);
|
||||
window.fhcVueRouter = router
|
||||
app.use(FhcApi);
|
||||
app.use(primevue.config.default, {
|
||||
zIndex: {
|
||||
overlay: 9000,
|
||||
tooltip: 8000
|
||||
}
|
||||
zIndex: {
|
||||
overlay: 9000,
|
||||
tooltip: 8000
|
||||
}
|
||||
})
|
||||
app.use(Phrasen);
|
||||
app.mount('#fhccontent');
|
||||
@@ -2,12 +2,6 @@ import CisMenuEntry from "./Menu/Entry.js";
|
||||
import FhcSearchbar from "../searchbar/searchbar.js";
|
||||
import CisSprachen from "./Sprachen.js"
|
||||
|
||||
// TODO: maybe get this from global vue router variable
|
||||
const routeMap = [
|
||||
{ routeName: 'FhcDashboard', paths: ['', '/', 'Cis4']},
|
||||
{ routeName: 'Stundenplan', paths: ['Stundenplan']}
|
||||
]
|
||||
|
||||
export default {
|
||||
components: {
|
||||
CisMenuEntry,
|
||||
@@ -34,7 +28,6 @@ export default {
|
||||
},
|
||||
provide(){
|
||||
return{
|
||||
routeMap,
|
||||
setActiveEntry: this.setActiveEntry,
|
||||
addUrlCount: this.addUrlCount,
|
||||
makeParentContentActive: this.makeParentContentActive,
|
||||
|
||||
@@ -15,7 +15,7 @@ export default {
|
||||
urlCount:0,
|
||||
}
|
||||
},
|
||||
inject: ['makeParentContentActive', 'setActiveEntry','addUrlCount', 'routeMap'],
|
||||
inject: ['makeParentContentActive', 'setActiveEntry','addUrlCount'],
|
||||
watch:{
|
||||
highestMatchingUrlCount: function(newValue)
|
||||
{
|
||||
@@ -55,11 +55,8 @@ export default {
|
||||
this.makeParentContentActive(this.entry.content_id);
|
||||
}
|
||||
}
|
||||
// debugging helpers - console.log(this.entry.titel, newValue ? "open" : "close")
|
||||
|
||||
},
|
||||
},
|
||||
|
||||
computed: {
|
||||
active: function () {
|
||||
if (this.entry.menu_open){
|
||||
@@ -185,19 +182,7 @@ export default {
|
||||
{
|
||||
this.setActiveEntry(this.entry.content_id);
|
||||
}
|
||||
},
|
||||
handleClick(e) {
|
||||
// TODO: this needs to be done more resilient
|
||||
const linkParts = this.link.split('/')
|
||||
const routePath = linkParts.reverse()[0]
|
||||
const r = this.routeMap.find(route => route.paths.includes(routePath))
|
||||
if(window.fhcVueRouter && r) {
|
||||
const re = new CustomEvent("fhcnavigate", { detail: r.routeName })
|
||||
window.dispatchEvent(re)
|
||||
} else {
|
||||
location.href = this.link
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (this.$refs.children) {
|
||||
@@ -215,7 +200,9 @@ export default {
|
||||
<template v-else>
|
||||
<template v-if="hasChilds">
|
||||
<div class="btn-group w-100">
|
||||
<a :href="(entry.menu_open)?link:null" :target="target" @click="toggleCollapse"
|
||||
<a :target="target"
|
||||
:href="(entry.menu_open)?link:null"
|
||||
@click="toggleCollapse"
|
||||
:class="{
|
||||
'btn btn-default rounded-0 text-start': true,
|
||||
['btn-level-' + level]: true,
|
||||
@@ -236,8 +223,8 @@ export default {
|
||||
<cis-menu-entry :highestMatchingUrlCount="highestMatchingUrlCount" :activeContent="activeContent" v-for="child in entry.childs" :key="child" :entry="child" :level="level + 1"/>
|
||||
</ul>
|
||||
</template>
|
||||
<a v-else
|
||||
@click="handleClick"
|
||||
<a v-else
|
||||
:href="link"
|
||||
:target="target"
|
||||
:class="{
|
||||
'btn btn-default rounded-0 w-100 text-start': true,
|
||||
|
||||
@@ -155,8 +155,13 @@ export default {
|
||||
<div class="mx-4">
|
||||
<i :class="[menuItem.c4_icon2 ? menuItem.c4_icon2 : 'fa-solid fa-pen-to-square', !menuItem.c4_link ? 'unavailable' : null ]"></i>
|
||||
</div>
|
||||
<a class="text-decoration-none text-truncate" :id="'moodle_links_'+lehrveranstaltung_id" :class="{'link-dark':menuItem.c4_link, 'unavailable':!menuItem.c4_link, 'dropdown-toggle':menuItem.c4_moodle_links?.length }" :target="menuItem.c4_target" :href="c4_link(menuItem) ? c4_link(menuItem) : null">
|
||||
{{menuItem.name}}
|
||||
<a
|
||||
class="text-decoration-none text-truncate"
|
||||
:id="'moodle_links_'+lehrveranstaltung_id"
|
||||
:class="{'link-dark':menuItem.c4_link, 'unavailable':!menuItem.c4_link, 'dropdown-toggle':menuItem.c4_moodle_links?.length }"
|
||||
:target="menuItem.c4_target"
|
||||
:href="c4_link(menuItem) ? c4_link(menuItem) : null">
|
||||
{{menuItem.name}}
|
||||
</a>
|
||||
</div>
|
||||
<ul v-if="menuItem.c4_moodle_links?.length" class="dropdown-menu p-0" :aria-labelledby="'moodle_links_'+lehrveranstaltung_id">
|
||||
|
||||
@@ -0,0 +1,367 @@
|
||||
import StudentProfil from "./StudentProfil.js";
|
||||
import MitarbeiterProfil from "./MitarbeiterProfil.js";
|
||||
import ViewStudentProfil from "./StudentViewProfil.js";
|
||||
import ViewMitarbeiterProfil from "./MitarbeiterViewProfil.js";
|
||||
import Loading from "../../Loader.js";
|
||||
|
||||
Vue.$collapseFormatter = function (data) {
|
||||
//data - an array of objects containing the column title and value for each cell
|
||||
var container = document.createElement("div");
|
||||
container.classList.add("tabulator-collapsed-row");
|
||||
container.classList.add("text-break");
|
||||
|
||||
var list = document.createElement("div");
|
||||
list.classList.add("row");
|
||||
|
||||
container.appendChild(list);
|
||||
|
||||
data.forEach(function (col) {
|
||||
let item = document.createElement("div");
|
||||
item.classList.add("col-6");
|
||||
let item2 = document.createElement("div");
|
||||
item2.classList.add("col-6");
|
||||
|
||||
item.innerHTML = "<strong>" + col.title + "</strong>";
|
||||
item2.innerHTML = col.value ? col.value : "-";
|
||||
|
||||
list.appendChild(item);
|
||||
list.appendChild(item2);
|
||||
});
|
||||
|
||||
return Object.keys(data).length ? container : "";
|
||||
};
|
||||
|
||||
export const Profil = {
|
||||
name: 'Profil',
|
||||
components: {
|
||||
StudentProfil,
|
||||
MitarbeiterProfil,
|
||||
ViewStudentProfil,
|
||||
ViewMitarbeiterProfil,
|
||||
Loading,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
//? loading property is used for showing/hiding the loading modal
|
||||
loading: false,
|
||||
profilUpdateStates: null,
|
||||
profilUpdateTopic: null,
|
||||
view: null,
|
||||
data: null,
|
||||
// notfound is null by default, but contains an UID if no user exists with that UID
|
||||
notFoundUID: null,
|
||||
};
|
||||
},
|
||||
provide() {
|
||||
return {
|
||||
profilUpdateStates: Vue.computed(() =>
|
||||
this.profilUpdateStates ? this.profilUpdateStates : false
|
||||
),
|
||||
profilUpdateTopic: Vue.computed(() =>
|
||||
this.profilUpdateTopic ? this.profilUpdateTopic : false
|
||||
),
|
||||
setLoading: (newValue) => {
|
||||
this.loading = newValue;
|
||||
},
|
||||
getZustellkontakteCount: this.zustellKontakteCount,
|
||||
getZustelladressenCount: this.zustellAdressenCount,
|
||||
collapseFunction: (e, column) => {
|
||||
//* check if property doesn't exist already and add it to the reactive this properties
|
||||
if (this[e.target.id] === undefined) {
|
||||
this[e.target.id] = true;
|
||||
}
|
||||
this[e.target.id] = !this[e.target.id];
|
||||
|
||||
//* gets all event icons of the different rows to use the onClick event later
|
||||
let allClickableIcons = column._column.cells.map((row) => {
|
||||
return row.element.children[0];
|
||||
});
|
||||
|
||||
//* changes the icon that shows or hides all the collapsed columns
|
||||
//* if the replace function does not find the class to replace, it just simply returns false
|
||||
if (this[e.target.id]) {
|
||||
e.target.classList.replace("fa-angle-up", "fa-angle-down");
|
||||
} else {
|
||||
e.target.classList.replace("fa-angle-down", "fa-angle-up");
|
||||
}
|
||||
|
||||
//* changes the icon for every collapsed column to open or closed
|
||||
if (this[e.target.id]) {
|
||||
allClickableIcons
|
||||
.filter((column) => {
|
||||
return !column.classList.contains("open");
|
||||
})
|
||||
.forEach((col) => {
|
||||
col.click();
|
||||
});
|
||||
} else {
|
||||
allClickableIcons
|
||||
.filter((column) => {
|
||||
return column.classList.contains("open");
|
||||
})
|
||||
.forEach((col) => {
|
||||
col.click();
|
||||
});
|
||||
}
|
||||
},
|
||||
sortProfilUpdates: (ele1, ele2) => {
|
||||
let result = 0;
|
||||
if (ele1.status === "pending") {
|
||||
result = -1;
|
||||
} else if (ele1.status === "accepted") {
|
||||
result = ele2.status === "rejected" ? -1 : 1;
|
||||
} else {
|
||||
result = 1;
|
||||
}
|
||||
//? if they have the same status the insert date is used for ordering
|
||||
if (ele1.status === ele2.status) {
|
||||
result =
|
||||
new Date(ele2.insertamum.split(".").reverse().join("-")) -
|
||||
new Date(ele1.insertamum.split(".").reverse().join("-"));
|
||||
}
|
||||
return result;
|
||||
},
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
zustellAdressenCount() {
|
||||
if (!this.data || !this.data.adressen) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let adressenArray = [];
|
||||
if (this.data.profilUpdates?.length) {
|
||||
adressenArray = adressenArray.concat(
|
||||
this.data.profilUpdates
|
||||
.filter((update) => {
|
||||
return update.requested_change.zustelladresse;
|
||||
})
|
||||
.map((adresse) => {
|
||||
return adresse.requested_change.adresse_id;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
!this.data.profilUpdates?.length ||
|
||||
!this.data.adressen
|
||||
.filter((adresse) => adresse.zustelladresse)
|
||||
.every((adresse) =>
|
||||
this.data.profilUpdates.some(
|
||||
(update) =>
|
||||
update.requested_change.adresse_id == adresse.adresse_id
|
||||
)
|
||||
)
|
||||
) {
|
||||
adressenArray = adressenArray.concat(
|
||||
this.data.adressen
|
||||
.filter((adresse) => {
|
||||
return adresse.zustelladresse;
|
||||
})
|
||||
.map((adr) => {
|
||||
return adr.adresse_id;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return [...new Set(adressenArray)];
|
||||
|
||||
},
|
||||
zustellKontakteCount() {
|
||||
if (!this.data || !this.data.kontakte) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let kontakteArray = [];
|
||||
|
||||
if (this.data.profilUpdates?.length) {
|
||||
kontakteArray = kontakteArray.concat(
|
||||
this.data.profilUpdates
|
||||
.filter((update) => {
|
||||
return update.requested_change.zustellung;
|
||||
})
|
||||
.map((kontant) => {
|
||||
return kontant.requested_change.kontakt_id;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
!this.data.profilUpdates?.length ||
|
||||
!this.data.kontakte
|
||||
.filter((kontakt) => kontakt.zustellung)
|
||||
.every((kontakt) =>
|
||||
this.data.profilUpdates.some(
|
||||
(update) =>
|
||||
update.requested_change.kontakt_id == kontakt.kontakt_id
|
||||
)
|
||||
)
|
||||
) {
|
||||
kontakteArray = kontakteArray.concat(
|
||||
this.data.kontakte
|
||||
.filter((kontakt) => {
|
||||
return kontakt.zustellung;
|
||||
})
|
||||
.map((kon) => {
|
||||
return kon.kontakt_id;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return [...new Set(kontakteArray)];
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
filteredEditData() {
|
||||
if (!this.data) {
|
||||
return;
|
||||
}
|
||||
|
||||
return {
|
||||
view: null,
|
||||
data: {
|
||||
Personen_Informationen: {
|
||||
title: this.$p.t("profil", "personenInformationen"),
|
||||
topic: "Personen_informationen",
|
||||
view: null,
|
||||
data: {
|
||||
vorname: {
|
||||
title: this.$p.t("person", "vorname"),
|
||||
topic: this.profilUpdateTopic?.["Vorname"],
|
||||
view: "TextInputDokument",
|
||||
withFiles: true,
|
||||
data: {
|
||||
titel: "vorname",
|
||||
value: this.data.vorname,
|
||||
},
|
||||
},
|
||||
nachname: {
|
||||
title: this.$p.t("person", "nachname"),
|
||||
topic: this.profilUpdateTopic?.["Nachname"],
|
||||
view: "TextInputDokument",
|
||||
withFiles: true,
|
||||
data: {
|
||||
titel: "nachname",
|
||||
value: this.data.nachname,
|
||||
},
|
||||
},
|
||||
titel: {
|
||||
title: this.$p.t("global", "titel"),
|
||||
topic: this.profilUpdateTopic?.["Titel"],
|
||||
view: "TextInputDokument",
|
||||
withFiles: true,
|
||||
data: {
|
||||
titel: "titel",
|
||||
value: this.data.titel,
|
||||
},
|
||||
},
|
||||
postnomen: {
|
||||
title: this.$p.t("profil", "postnomen"),
|
||||
topic: this.profilUpdateTopic?.["Postnomen"],
|
||||
view: "TextInputDokument",
|
||||
withFiles: true,
|
||||
data: {
|
||||
titel: "postnomen",
|
||||
value: this.data.postnomen,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Private_Kontakte: {
|
||||
title: this.$p.t("profil", "privateKontakte"),
|
||||
topic: this.profilUpdateTopic?.["Private Kontakte"],
|
||||
data: this.data.kontakte
|
||||
?.filter((item) => {
|
||||
// excludes all contacts that are already used in pending profil update requests
|
||||
return !this.data.profilUpdates?.some(
|
||||
(update) =>
|
||||
update.status === this.profilUpdateStates["Pending"] &&
|
||||
update.requested_change?.kontakt_id === item.kontakt_id
|
||||
);
|
||||
})
|
||||
.map((kontakt) => {
|
||||
return {
|
||||
listview: "Kontakt",
|
||||
view: "EditKontakt",
|
||||
data: kontakt,
|
||||
};
|
||||
}),
|
||||
},
|
||||
Private_Adressen: {
|
||||
title: this.$p.t("profil", "privateAdressen"),
|
||||
topic: this.profilUpdateTopic?.["Private Adressen"],
|
||||
data: this.data.adressen
|
||||
?.filter((item) => {
|
||||
return !this.data.profilUpdates?.some((update) => {
|
||||
return (
|
||||
update.status === this.profilUpdateStates["Pending"] &&
|
||||
update.requested_change?.adresse_id == item.adresse_id
|
||||
);
|
||||
});
|
||||
})
|
||||
.map((adresse) => {
|
||||
return {
|
||||
listview: "Adresse",
|
||||
view: "EditAdresse",
|
||||
data: adresse,
|
||||
};
|
||||
}),
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
loading: function (newValue) {
|
||||
if (newValue) {
|
||||
this.$refs.loadingModalRef.show();
|
||||
} else {
|
||||
this.$refs.loadingModalRef.hide();
|
||||
}
|
||||
},
|
||||
},
|
||||
async created() {
|
||||
// fetch profilUpdateStates to provide them to children components
|
||||
|
||||
await this.$fhcApi.factory.profilUpdate.getStatus()
|
||||
.then((response) => {
|
||||
this.profilUpdateStates = response.data;
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
});
|
||||
|
||||
this.$fhcApi.factory.profilUpdate.getTopic()
|
||||
.then((response) => {
|
||||
this.profilUpdateTopic = response.data;
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
});
|
||||
|
||||
//? uid contains the last part of the uri
|
||||
let uid = location.pathname.split("/").pop();
|
||||
|
||||
this.$fhcApi.factory.profil.getView(uid).then((res) => {
|
||||
if (!res.data) {
|
||||
this.notFoundUID = uid;
|
||||
} else {
|
||||
this.view = res.data?.view;
|
||||
this.data = res.data?.data;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
template: `
|
||||
<div>
|
||||
<div v-if="notFoundUID">
|
||||
<h3>Es wurde keine Person mit der UID {{this.notFoundUID}} gefunden</h3>
|
||||
</div>
|
||||
<div v-else>
|
||||
<loading ref="loadingModalRef" :timeout="0"></loading>
|
||||
<component :is="view" :data="data" :editData="filteredEditData" ></component>
|
||||
</div>
|
||||
</div>`,
|
||||
}
|
||||
|
||||
export default Profil
|
||||
@@ -13,8 +13,12 @@ export const Stundenplan = {
|
||||
currentlySelectedEvent: null,
|
||||
currentDay: new Date(),
|
||||
minimized: false,
|
||||
viewData: JSON.parse(this.viewDataString ?? '{}'),
|
||||
}
|
||||
},
|
||||
props: [
|
||||
"viewDataString"
|
||||
],
|
||||
components: {
|
||||
FhcCalendar, LvModal, LvMenu, LvInfo
|
||||
},
|
||||
@@ -75,7 +79,7 @@ export const Stundenplan = {
|
||||
},
|
||||
loadEvents: function(){
|
||||
Promise.allSettled([
|
||||
this.$fhcApi.factory.stundenplan.getStundenplan(this.monthFirstDay, this.monthLastDay, this.lv_id),
|
||||
this.$fhcApi.factory.stundenplan.getStundenplan(this.monthFirstDay, this.monthLastDay, this.viewData.lv_id),
|
||||
this.$fhcApi.factory.stundenplan.getStundenplanReservierungen(this.monthFirstDay, this.monthLastDay)
|
||||
]).then((result) => {
|
||||
let promise_events = [];
|
||||
|
||||
Reference in New Issue
Block a user