Merge branch 'feature-25999/C4_cleanup' of github.com:FH-Complete/FHC-Core into feature-25999/C4_cleanup

This commit is contained in:
SimonGschnell
2024-11-19 12:51:50 +01:00
16 changed files with 139 additions and 95 deletions
@@ -71,11 +71,16 @@ class Documents extends Auth_Controller
]);
$stgs = [];
$stsemArray = [];
$buchungstypen = implode('\',\'', defined("CIS_DOKUMENTE_STUDIENBEITRAG_TYPEN") ? unserialize(CIS_DOKUMENTE_STUDIENBEITRAG_TYPEN) : []);
$person_ids = [];
foreach ($stati as $status) {
$person_ids[] = $status->person_id;
if(!in_array($status->studiensemester_kurzbz, $stsemArray)) {
$stsemArray[] = $status->studiensemester_kurzbz;
}
if (!isset($stgs[$status->studiengang_kz])) {
$stg = $this->StudiengangModel->load($status->studiengang_kz);
if (isError($stg))
@@ -122,6 +127,7 @@ class Documents extends Auth_Controller
$this->load->view('Cis/Documents', [
'stsemArray' => $stsemArray,
'stgs' => $stgs,
'uid' => $uid,
'studienbuchblatt' => defined('CIS_DOKUMENTE_STUDIENBUCHLBATT_DRUCKEN') && CIS_DOKUMENTE_STUDIENBUCHLBATT_DRUCKEN,
-1
View File
@@ -104,7 +104,6 @@ $this->load->view('templates/CISVUE-Header', $includesArray);
<?php } ?>
<div class="col-auto">
<select class="form-select" @input="changeFilter('studienerfolgsbestaetigungtable', 'Stsem', $event)">
<option value="">Alle</option>
<option value="<?= $this->p->t('tools', 'alleStudiensemester'); ?>"><?= $this->p->t('tools', 'alleStudiensemester'); ?></option>
<?php foreach ($stsemArray as $sem) { ?>
<option value="<?= $sem; ?>">
@@ -36,7 +36,6 @@ if (!isset($menu)) {
logo-url="<?= base_url('/public/images/logo-300x160.png'); ?>"
avatar-url="<?= site_url('Cis/Pub/bild/person/' . getAuthPersonId()); ?>"
logout-url="<?= site_url('Cis/Auth/logout'); ?>"
:selectedtypes="selectedtypes"
:searchbaroptions="searchbaroptions"
:searchfunction="searchfunction"
:menu="<?= htmlspecialchars(json_encode(array_values($menu)), ENT_QUOTES, 'UTF-8') ?>"
+5
View File
@@ -17,6 +17,11 @@
height: 100%;
}
.widgets-news img
{
max-width: 100%;
}
.widgets-news .card-body{
overflow: hidden;
}
+28 -21
View File
@@ -13,12 +13,8 @@ const app = Vue.createApp({
},
data: function() {
return {
selectedtypes:[
"mitarbeiter",
"raum",
"organisationunit"
],
searchbaroptions: {
cssclass: "",
types: [
"mitarbeiter",
"raum",
@@ -38,26 +34,41 @@ const app = Vue.createApp({
},
raum: {
defaultaction: {
type: "function",
type: "link",
action: function(data) {
alert('raum defaultaction ' + JSON.stringify(data));
const link= FHC_JS_DATA_STORAGE_OBJECT.app_root +
FHC_JS_DATA_STORAGE_OBJECT.ci_router +
'/CisVue/Cms/content/' + data.content_id;
return link;
}
},
childactions: [
{
label: "Raumübersicht",
icon: "fas fa-info-circle",
type: "link",
action: function(data) {
return data.infolink;
}
},
{
label: "Raumreservierung",
label: "LV-Plan",
icon: "fas fa-bookmark",
type: "link",
action: function(data) {
return data.booklink;
const link = FHC_JS_DATA_STORAGE_OBJECT.app_root +
FHC_JS_DATA_STORAGE_OBJECT.ci_router +
'/CisVue/Cms/getRoomInformation/' + data.ort_kurzbz;
return link;
}
},
{
label: "Rauminformation",
icon: "fas fa-info-circle",
type: "link",
renderif: function(data) {
if(data.content_id === "N/A"){
return false;
}
return true;
},
action: function(data) {
const link= FHC_JS_DATA_STORAGE_OBJECT.app_root +
FHC_JS_DATA_STORAGE_OBJECT.ci_router +
'/CisVue/Cms/content/' + data.content_id;
return link;
}
},
]
@@ -79,10 +90,6 @@ const app = Vue.createApp({
searchfunction: function(searchsettings) {
return Vue.$fhcapi.Search.search(searchsettings);
},
updatesearchtypes: function(newValues){
this.selectedtypes= newValues;
},
}
});
app.use(FhcApi);
+4 -7
View File
@@ -1,14 +1,8 @@
// import Phrasen from '../../mixins/Phrasen.js';
import Phrasen from '../../plugin/Phrasen.js';
//import {TabulatorFull as Tabulator} from '../../../../vendor/olifolkerd/tabulator5/dist/js/tabulator_esm.min.js';
//import CssLib from '../../helpers/CssLib.js';
//CssLib.import('../../vendor/olifolkerd/tabulator5/dist/css/tabulator_bootstrap5.min.css');
import {setScrollbarWidth} from "../../helpers/CssVarCalcHelpers";
const app = Vue.createApp({
name: 'DocumentsApp',
// mixins: [
// Phrasen
// ],
data() {
return {
inscriptiontable: null,
@@ -92,5 +86,8 @@ const app = Vue.createApp({
});
}
});
setScrollbarWidth();
app.use(Phrasen, {reload: true});
app.mount('#content');
+1 -1
View File
@@ -123,7 +123,7 @@ export default {
<button id="nav-main-btn" class="navbar-toggler" type="button" data-bs-toggle="offcanvas" data-bs-target="#nav-main" aria-controls="nav-main" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<fhc-searchbar @showSettings="toggleCollapsibles" ref="searchbar" id="nav-search" class="fhc-searchbar w-100" :searchoptions="searchbaroptions" :searchfunction="searchfunction" :selectedtypes="selectedtypes"></fhc-searchbar>
<fhc-searchbar @showSettings="toggleCollapsibles" ref="searchbar" id="nav-search" class="fhc-searchbar w-100" :searchoptions="searchbaroptions" :searchfunction="searchfunction"></fhc-searchbar>
<a id="nav-logo" class="d-none d-lg-block" :href="rootUrl">
<img :src="logoUrl" alt="Logo">
</a>
+10 -2
View File
@@ -19,7 +19,9 @@ export default {
"change",
"remove",
"dragstart",
"resizestart"
"resizestart",
"configOpened",
"configClosed"
],
props: [
"id",
@@ -41,6 +43,12 @@ export default {
},
},
methods: {
handleShowBsModal() {
this.$emit('configOpened')
},
handleHideBsModal() {
this.$emit('configClosed')
},
mouseDown(e) {
this.target = e.target;
},
@@ -120,7 +128,7 @@ export default {
<component :is="component" v-model:shared-data="sharedData" :config="arguments" :width="width" :height="height" @setConfig="setConfig" @change="changeConfigManually"></component>
</div>
<div v-else class="card-body overflow-hidden text-center d-flex flex-column justify-content-center"><i class="fa-solid fa-spinner fa-pulse fa-3x"></i></div>
<bs-modal v-if="hasConfig" ref="config">
<bs-modal v-if="hasConfig" ref="config" @hideBsModal="handleHideBsModal" @showBsModal="handleShowBsModal">
<template v-slot:title>
{{ widget ? 'Config for ' + widget.setup.name : '' }}
</template>
+11 -2
View File
@@ -26,6 +26,7 @@ export default {
],
data() {
return {
configOpened: false,
gridWidth: 1,
gridHeight: null,
editMode: this.adminMode
@@ -91,6 +92,12 @@ export default {
},
},
methods: {
handleConfigOpened() {
this.configOpened = true
},
handleConfigClosed() {
this.configOpened = false
},
checkResizeLimit(item, w, h) {
// NOTE(chris): widgets needs to be loaded for this to work
let widget = CachedWidgetLoader.getWidget(item.widget);
@@ -180,7 +187,7 @@ export default {
<span >{{$p.t('ui/section' + name)}}</span>
<button style="margin-left: 8px;" class="btn" @click="editMode = !editMode"><i class="fa-solid fa-gear"></i></button>
</h3>
<drop-grid v-model:cols="gridWidth" :items="items" :placeholders="items_placeholders" :active="editMode" :resize-limit="checkResizeLimit" :margin-for-extra-row=".01" @rearrange-items="updatePositions" @gridHeight="gridHeight=$event" >
<drop-grid v-model:cols="gridWidth" :items="items" :placeholders="items_placeholders" :active="editMode && !configOpened" :resize-limit="checkResizeLimit" :margin-for-extra-row=".01" @rearrange-items="updatePositions" @gridHeight="gridHeight=$event" >
<template #default="item" #default>
<dashboard-item v-if="!item.placeholder"
@@ -193,7 +200,9 @@ export default {
:hidden="item.hidden"
:editMode="editMode"
@change="saveConfig($event, item)"
@remove="removeWidget(item, $event)">
@remove="removeWidget(item, $event)"
@config-opened="handleConfigOpened"
@config-closed="handleConfigClosed">
</dashboard-item>
<div v-else class="empty-tile-hover" @click="$emit('widgetAdd', name, { widget: 1, config: {}, place: {[gridWidth]: {x:item.x,y:item.y,w:1,h:1}}, custom: 1 })"></div>
+3 -5
View File
@@ -87,12 +87,10 @@ export default {
</div>
</div>
<div v-else class="h-100" :class="'row row-cols-' + width">
<div v-else class="h-100" :class="'row row-cols-' + width">
<div class="h-100" v-for="news in newsList" :key="news.id">
<div class="news-content h-100" :style="'--news-widget-height: '+height" ref="htmlContent" v-html="news.content_obj.content"></div>
</div>
<div class="news-content h-100" :style="'--news-widget-height: '+height" ref="htmlContent" v-html="news.content_obj.content"></div>
</div>
</div>
</div>
</div>`,
@@ -34,6 +34,7 @@ export default {
const currentCalendarDate = new CalendarDate(this.currentDay)
const mapArr = currentCalendarDate.nextSevenDays.map((d) => [new CalendarDate(d), []])
// return map of key => calendar date of next 7 days & values the respective events on that date
return new Map((this.events || []).filter(evt => evt.start >= this.currentDay).reduce((acc, cur) => {
const date = new CalendarDate(new Date(cur.datum))
const arr = acc.find(el => el[0].compare(date))
@@ -188,6 +189,7 @@ export default {
<div class="dashboard-widget-stundenplan d-flex flex-column h-100">
<lv-modal v-if="selectedEvent" ref="lvmodal" :event="selectedEvent" />
<content-modal :contentID="roomInfoContentID" :ort_kurzbz="" dialogClass="modal-lg" ref="contentModal"/>
<header><b>{{ $p.t('lehre/stundenplan') }}</b></header>
<fhc-calendar @change:range="updateRange" :initial-date="currentDay" class="border-0" class-header="p-0" @select:day="selectDay" v-model:minimized="minimized" :events="events" no-week-view :show-weeks="false" >
<template #minimizedPage >
<div class="flex-grow-1" style="overflow-y: auto; overflow-x: hidden">
@@ -201,12 +203,15 @@ export default {
<div role="button" @click="showLvUebersicht(evt)" v-for="evt in value" :key="evt.id" class="list-group-item small" :style="getEventStyle(evt)">
<b>{{evt.topic}}</b>
<br>
<small class="d-flex w-100 justify-content-between">
<small v-if="evt.ort_kurzbz" class="d-flex w-100 justify-content-between">
<!-- event modifier stop to prevent opening the modal for the lv Uebersicht when clicking on the ort_kurzbz -->
<span @click.stop="showRoomInfoModal(evt.ort_kurzbz)" style="text-decoration:underline" type="button">{{evt.ort_kurzbz}}</span>
<span>{{evt.start.toLocaleTimeString(undefined, {hour:'numeric',minute:'numeric'})}}-{{evt.end.toLocaleTimeString(undefined, {hour:'numeric',minute:'numeric'})}}</span>
</small>
</div>
<div v-if="!value.length" class="list-group-item small text-center">
{{ p.t('lehre/noLvFound') }}
</div>
</template>
<div v-else class="d-flex h-100 justify-content-center align-items-center fst-italic text-center">
{{ p.t('lehre/noLvFound') }}
+17 -5
View File
@@ -13,10 +13,15 @@ export default {
},
emits: [ 'actionexecuted' ],
template: `
<a :class="this.cssclass" :href="this.getactionhref()"
@click="(this.action.type === 'function') ? this.execaction() : null">
<slot>Action</slot>
</a>
<template v-if="this.renderif()">
<a :class="this.cssclass" :href="this.getactionhref()"
@click="(this.action.type === 'function') ? this.execaction() : null">
<slot>Action</slot>
</a>
</template>
<template v-else>
<slot>Action</slot>
</template>
`,
methods: {
getactionhref: function() {
@@ -26,6 +31,13 @@ export default {
execaction: function() {
this.action.action(this.res);
this.$emit('actionexecuted');
}
},
renderif: function() {
if(this.action?.renderif === undefined) {
return true;
}
return this.action.renderif(this.res);
}
}
};
+11 -2
View File
@@ -8,12 +8,14 @@ export default {
emits: [ 'actionexecuted' ],
template: `
<ul class="searchbar_actions" v-if="this.actions.length > 0">
<li v-for="(action, index) in this.actions" :key="action.label">
<template v-for="(action, index) in this.actions" :key="action.label">
<li v-if="this.renderif(action)">
<action :res="this.res" :action="action" :cssclass="'btn btn-primary btn-sm'" @actionexecuted="$emit('actionexecuted')">
<i v-if="this.hasicon(index)" :class="this.geticonclass(index)"></i>
<span class="p-2">{{ action.label }}</span>
</action>
</li>
</template>
</ul>
<div class="mb-3" v-else=""></div>
`,
@@ -23,6 +25,13 @@ export default {
},
geticonclass: function(index) {
return this.actions[index].icon;
}
},
renderif: function(action) {
if(action?.renderif === undefined) {
return true;
}
return action.renderif(this.res);
}
}
};
-9
View File
@@ -7,15 +7,6 @@ export default {
action: action,
actions: actions
},
created(){
//! this should be the default action for a raum
this.actions.defaultaction = {
type: "link",
action: function(data) {
return FHC_JS_DATA_STORAGE_OBJECT.app_root+'cms/content.php?content_id='+data.content_id;
}
};
},
emits: [ 'actionexecuted' ],
template: /*html*/`
<div class="searchbar_result searchbar_raum">
+17 -38
View File
@@ -6,7 +6,7 @@ import student from "./student.js";
import prestudent from "./prestudent.js";
export default {
props: [ "searchoptions", "searchfunction","selectedtypes" ],
props: [ "searchoptions", "searchfunction" ],
emits: ['showSettings'],
data: function() {
return {
@@ -33,7 +33,7 @@ export default {
prestudent: prestudent
},
template: /*html*/`
<form ref="searchform" class="d-flex me-3" action="javascript:void(0);"
<form ref="searchform" class="d-flex me-3" :class="searchoptions.cssclass" action="javascript:void(0);"
@focusin="this.searchfocusin" @focusout="this.searchfocusout">
<div class="h-100 input-group me-2 bg-white">
@@ -55,9 +55,9 @@ export default {
<person v-if="res.type === 'person'" :res="res" :actions="this.searchoptions.actions.person" @actionexecuted="this.hideresult"></person>
<student v-else-if="res.type === 'student'" :res="res" :actions="this.searchoptions.actions.student" @actionexecuted="this.hideresult"></student>
<prestudent v-else-if="res.type === 'prestudent'" :res="res" :actions="this.searchoptions.actions.prestudent" @actionexecuted="this.hideresult"></prestudent>
<employee v-else-if="res.type === 'mitarbeiter'" :res="res" :actions="this.searchoptions.actions.employee" @actionexecuted="this.hideresult"></employee>
<employee v-else-if="res.type === 'mitarbeiter' || res.type === 'mitarbeiter_ohne_zuordnung'" :res="res" :actions="this.searchoptions.actions.employee" @actionexecuted="this.hideresult"></employee>
<organisationunit v-else-if="res.type === 'organisationunit'" :res="res" :actions="this.searchoptions.actions.organisationunit" @actionexecuted="this.hideresult"></organisationunit>
<raum v-else-if="res.type === 'raum'" :res="res" :actions="getActionsForRoom(res)" @actionexecuted="this.hideresult"></raum>
<raum v-else-if="res.type === 'raum'" :res="res" :actions="this.searchoptions.actions.raum" @actionexecuted="this.hideresult"></raum>
<div v-else="">Unbekannter Ergebnistyp: '{{ res.type }}'.</div>
</template>
</div>
@@ -78,7 +78,7 @@ export default {
</form>
`,
watch:{
'searchsettings.types'(newValue){
'searchsettings.types': function (newValue){
this.search();
},
},
@@ -92,36 +92,10 @@ export default {
});
},
methods: {
getActionsForRoom: function(res){
res.booklink= FHC_JS_DATA_STORAGE_OBJECT.app_root +
FHC_JS_DATA_STORAGE_OBJECT.ci_router +
`/CisVue/Cms/getRoomInformation/${res.ort_kurzbz}`;
if(res.content_id !=="N/A"){
res.infolink= FHC_JS_DATA_STORAGE_OBJECT.app_root +
FHC_JS_DATA_STORAGE_OBJECT.ci_router +
`/CisVue/Cms/content/${res.content_id}`;
}
let child = this.searchoptions.actions.raum.childactions.filter((child)=>{
if(child.label =="Rauminformation" && res.content_id =="N/A"){
return false;
}
return true;
});
let computedActions = {
childactions:child,
defaultaction:this.searchoptions.actions.raum.defaultaction
}
return computedActions;
},
updateSearchOptions: function() {
this.searchsettings.types = [];
for( const idx in this.selectedtypes ) {
this.searchsettings.types.push(this.selectedtypes[idx]);
for( const idx in this.searchoptions.types ) {
this.searchsettings.types.push(this.searchoptions.types[idx]);
}
},
calcSearchResultExtent: function() {
@@ -135,7 +109,7 @@ export default {
if( this.searchtimer !== null ) {
clearTimeout(this.searchtimer);
}
if( this.searchsettings.searchstr.length >= 3 ) {
if( this.searchsettings.searchstr.length >= 2 ) {
this.calcSearchResultExtent();
this.searchtimer = setTimeout(
this.callsearchapi,
@@ -145,11 +119,16 @@ export default {
this.showresult = false;
}
},
callsearchapi: function() {
callsearchapi: function() {
this.error = null;
this.searchresult.splice(0,this.searchresult.length);
this.searchresult.splice(0, this.searchresult.length);
this.searching = true;
this.showsearchresult();
this.showsearchresult();
if(this.searchsettings.types.length === 0) {
this.error = 'Kein Ergebnistyp ausgewählt. Bitte mindestens einen Ergebnistyp auswählen.';
this.searching = false;
return;
}
this.searchfunction(this.searchsettings)
.then(response=>{
if( response.data?.error === 1 ) {
@@ -177,7 +156,7 @@ export default {
window.removeEventListener('resize', this.calcSearchResultExtent);
},
showsearchresult: function() {
if( this.searchsettings.searchstr.length >= 3 ) {
if( this.searchsettings.searchstr.length >= 2 ) {
this.showresult = true;
window.addEventListener('resize', this.calcSearchResultExtent);
}
+20
View File
@@ -37116,6 +37116,26 @@ array(
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'lehre',
'phrase' => 'stundenplan',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Stundenplan',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Timetable',
'description' => '',
'insertvon' => 'system'
)
)
)
// CIS4 phrases from legacy code end
);