Erse Version des Lehrerinfobildschirms mit Vertretungsplan und News

This commit is contained in:
Daniel Spittank 2021-11-14 17:36:06 +01:00
parent c713629edf
commit 209454e313
12 changed files with 498 additions and 49 deletions

View file

@ -1,5 +1,17 @@
<template>
<div id="app">
<v-app>
<router-view/>
</div>
</template>
</v-app>
</template>
<style>
* {
-webkit-touch-callout: none; /* iOS Safari */
-webkit-user-select: none; /* Safari */
-khtml-user-select: none; /* Konqueror HTML */
-moz-user-select: none; /* Old versions of Firefox */
-ms-user-select: none; /* Internet Explorer/Edge */
user-select: none; /* Non-prefixed version, currently
supported by Chrome, Edge, Opera and Firefox */
}
</style>

View file

@ -1,5 +1,5 @@
<template>
<div class="about">
<div class="HomeScreen">
<h1>SISSy Sedan Informations- und Stundenplansystem</h1>
<router-link to="/">Home</router-link> |
<router-link to="/ids">Infodisplay Schüler</router-link>|

View file

@ -0,0 +1,86 @@
<template>
<div id="newsreader">
<v-carousel v-model="newsitem"
cycle
interval="10000"
progress
progress-color="indigo"
height="400"
hide-delimiters
:show-arrows="false"
>
<v-carousel-item
v-for="(item, i) in items"
:key="i"
>
<v-card
flat
height="100%"
>
<v-card-title>{{ item.title }}</v-card-title>
<v-card-text class="news-text" v-html="item.text"></v-card-text>
</v-card>
</v-carousel-item>
</v-carousel>
<v-toolbar
flat
rounded="lg"
>
<v-btn @click="newsitem--" rounded><v-icon>mdi-chevron-left</v-icon></v-btn>
<v-spacer></v-spacer>
<v-btn @click="newsitem++" rounded><v-icon>mdi-chevron-right</v-icon></v-btn>
</v-toolbar>
</div>
</template>
<script>
export default {
name: 'Newsreader',
data() {
return {
items: [],
newsitem: 0,
};
},
props: {
feedUrls: Array
},
methods: {
reload() {
// items zurücksetzen
this.items = []
// items laden
for (var i = 0; i < this.feedUrls.length; i++) {
fetch(this.feedUrls[i])
.then(response => response.text())
.then(str => new window.DOMParser().parseFromString(str, 'text/xml'))
.then(data => {
const elements = data.querySelectorAll('item');
elements.forEach(el => {
// item bauen
const item = {
'title': el.querySelector('title').innerHTML.replace(/<!-*\[CDATA\[([\s\S]*)\]\]>/, '$1'),
'text': el.querySelector('description').innerHTML.replace(/<!-*\[CDATA[^<]*([\s\S]*)\]\]>/, '$1'),
'date': el.querySelector('pubDate').innerHTML,
'feedUrl': this.feedUrls[i]
}
// Links entfernen (TODO: Link-Handler einbauen)
item.text = item.text.replace(/<a[^>]*href=["']*([^'"]*)[^>]*>([^<]*)<\/a>/g, '$2')
// item auf Array pushen
this.items.push(item)
})
})
.catch(error => console.error(error))
}
},
},
created() {this.reload()}
}
</script>
<style>
div.news-text {
height: calc(100% - 6px);
overflow-y: auto;
}
</style>

View file

@ -0,0 +1,239 @@
<template>
<div id="vertretungsplan">
<v-data-table
:headers="headers"
:fixed-header="true"
class="overflow-y-auto"
height="85vh"
:items="vp"
:items-per-page="10000"
item-key="nr"
sort-by="stunde"
group-by="lehrkraft_vertretung"
flat
hide-default-footer
:expanded.sync="expanded"
:single-expand="true"
>
<!-- Titelzeile -->
<template v-slot:top>
<v-toolbar
flat
>
<v-toolbar-title>Vertretungsplan für den </v-toolbar-title>
&nbsp;
<v-menu
v-model="datepicker"
:close-on-content-click="false"
:nudge-right="40"
transition="scale-transition"
offset-y
min-width="auto"
>
<template v-slot:activator="{ on, attrs }">
<v-btn
v-bind="attrs"
v-on="on"
rounded
:class="(today) ? '' : 'red'"
><v-icon :color="(today) ? '' : 'white'">mdi-calendar</v-icon><span :class="(today) ? '' : 'white--text'">{{ vpDatum.getDate() }}.{{ vpDatum.getMonth() + 1 }}.{{ vpDatum.getFullYear() }}</span></v-btn>
</template>
<v-date-picker
v-model="neuesDatum"
@input="datepicker = false"
></v-date-picker>
</v-menu>
<v-spacer></v-spacer>
</v-toolbar>
</template>
<!-- Kopfzeile für Gruppen -->
<template v-slot:group.header="{ group, headers, isOpen, toggle }">
<td :colspan="headers.length">
<v-btn @click="toggle" v-if="isOpen"><v-icon color="grey">mdi-account</v-icon>{{ group }}</v-btn>
<v-btn @click="toggle" v-if="!isOpen"><v-icon color="grey">mdi-account-outline</v-icon>{{ group }}</v-btn>
</td>
</template>
<!-- Darstellung des Datumsfelds -->
<template v-slot:item.datum></template>
<template v-slot:header.datum></template>
<!-- Darstellung der Vertretungsart -->
<template v-slot:item.art_vertretung="{ item }">
{{ vertretungsart(item.art_vertretung) }}
</template>
<!-- Button für Anmerkungen -->
<template v-slot:item.expand="{ item }">
<v-btn @click="expanded = [item]" v-if="item.anmerkung !== '' && !expanded.includes(item)"><v-icon>mdi-comment-plus</v-icon></v-btn>
<v-btn @click="expanded = []" v-if="item.anmerkung !== '' && expanded.includes(item)"><v-icon>mdi-comment-minus</v-icon></v-btn>
</template>
<!-- Anmerkungen -->
<template v-slot:expanded-item="{ headers, item }">
<td :colspan="headers.length" v-if="item.anmerkung !== ''">
<pre>{{item.anmerkung}}</pre>
</td>
</template>
</v-data-table>
</div>
</template>
<script>
var vertretungsarten = {
'T': 'verlegt',
'F': 'verlegt von',
'W': 'Tausch',
'S': 'Betreuung',
'A': 'Sondereinsatz',
'C': 'Entfall',
'L': 'Freisetzung',
'P': 'Teil_vertretung',
'R': 'Raumvertretung',
'B': 'Pausenaufsicht',
'~': 'Lehrertausch',
'E': 'Klausur',
'': 'Vertretung'
}
export default {
name: 'Vertretungsplan',
data() {
return {
vp: [],
headers: [
{
text: 'Datum',
value: 'datum',
sortable: false,
width: 0,
// nur ausgewähltes Datum
filter: value => {
if (value !== this.datumIso) {
return false
} else {
return true
}
}
},
{
text: 'Stunde',
value: 'stunde',
sortable: false
},
{
text: 'Durch',
value: 'lehrkraft_vertretung',
sortable: false
},
{
text: 'Klasse(n)',
value: 'klassen',
sortable: false
},
{
text: 'Fach (neu)',
value: 'fach_vertretung',
sortable: false
},
{
text: 'Raum (neu)',
value: 'raum_vertretung',
sortable: false
},
{
text: 'Für',
value: 'lehrkraft',
sortable: false
},
{
text: 'Fach',
value: 'fach',
sortable: false
},
{
text: 'Raum',
value: 'raum',
sortable: false
},
{
text: 'Durch',
value: 'lehrkraft_vertretung',
sortable: false,
// nur Zeilen mit Vertreter
filter: value => {
if (value === '') {
return false
} else {
return true
}
}
},
{
text: 'Art',
value: 'art_vertretung',
sortable: false
},
{
text: 'Anmerkung',
value: 'expand',
sortable: false,
align: 'end'
},
],
expanded:[],
datepicker: false,
vpDatum: new Date()
};
},
props: {
vpUrl: String, // URL der GPU014,
startDatum: Date
},
computed: {
datumIso () {
return this.vpDatum.getFullYear() + "" + (this.vpDatum.getMonth() + 1) + "" + this.vpDatum.getDate()
},
neuesDatum: {
get: function () {
return this.vpDatum.toISOString().substr(0, 10)
},
set: function (val) {
this.vpDatum = new Date(val)
}
},
today () {
var d = new Date()
return d.toDateString() === this.vpDatum.toDateString()
}
},
methods: {
async reload () {
// Feldnamen definieren
const vpHeader = 'nr,datum,stunde,absenznr,id_unterricht,lehrkraft,lehrkraft_vertretung,fach,fach_statistik_id,fach_vertretung,fach_vertretung_statistik_id,raum,raum_vertretung,statistik_id,klassen,absenzgrund,anmerkung,art,klassen_vertretung,art_vertretung,letzte_aenderung,extra\n'
// Abrufen
const res = await fetch(this.vpUrl)
// Text extrahieren und Feldnamen hinzufügen
const vpText = vpHeader + await res.text()
// Parsen und Array in Daten ablegen
this.vp = this.$papa.parse(vpText, {'header': 'true', 'skipEmptyLines': 'greedy'}).data
},
vertretungsart (code) {
return vertretungsarten[code]
},
},
created () {
// Startdatum festlegen
if (typeof this.startDatum !== 'undefined') this.vpDatum = this.startDatum
// Vertretungsplan neu laden
this.reload()
}
}
</script>
<style>
div.news-text {
height: calc(100% - 6px);
overflow-y: auto;
}
</style>

View file

@ -1,7 +1,11 @@
import '@mdi/font/css/materialdesignicons.css' // Ensure you are using css-loader
import Vue from 'vue';
import Vuetify from 'vuetify/lib/framework';
Vue.use(Vuetify);
export default new Vuetify({
icons: {
iconfont: 'mdi'
},
});

View file

@ -1,6 +1,9 @@
import Vue from 'vue'
import VueRouter from 'vue-router'
import VuePapaParse from 'vue-papa-parse'
Vue.use(VuePapaParse)
Vue.use(VueRouter)
const routes = [

View file

@ -1,37 +1,110 @@
<template>
<div class="ids">
<v-app-bar
app
color="indigo"
dark
>
<v-img
alt="Logo"
class="shrink mr-2"
contain
src="@/assets/logo.svg"
transition="scale-transition"
width="40"
/>
<v-spacer></v-spacer>
<v-tabs>
<v-tab
v-for="link in links"
:key="link"
>
{{ link }}
</v-tab>
</v-tabs>
<v-app>
<v-navigation-drawer app>
<!-- -->
</v-navigation-drawer>
<v-app-bar app>
<!-- -->
</v-app-bar>
<!-- Sizes your content based upon application components -->
<v-main>
<!-- Provides the application the proper gutter -->
<v-container fluid>
<!-- If using vue-router -->
<router-view></router-view>
<v-row dense>
<v-col
cols="8"
>
<v-sheet
min-height="70vh"
rounded="lg"
elevation="2"
>
<Vertretungsplan
vpUrl="/stundenplan/proxy.php?file=G014"
:startDatum="startDatum"
/>
</v-sheet>
</v-col>
<v-col
cols="4"
>
<v-sheet
rounded="lg"
min-height="268"
elevation="2"
>
<Newsreader
:feedUrls="['/stundenplan/proxy.php?file=rsslul', '/stundenplan/proxy.php?file=rsssul']"
/>
</v-sheet>
<!--
<v-sheet
rounded="lg"
min-height="268"
elevation="2"
>
</v-sheet> -->
</v-col>
</v-row>
</v-container>
</v-main>
<v-footer app>
<!-- -->
</v-footer>
</v-app>
</div>
</template>
<script>
import Newsreader from '@/components/Newsreader'
import Vertretungsplan from '@/components/Vertretungsplan'
export default {
name: 'InfodisplayLehrer',
data: () => ({
links: [
'Vertretungsplan',
'Stundenpläne'
],
startDatum: new Date()
}),
props: {
msg: String
},
components: {
Newsreader,
Vertretungsplan
},
created: function () {
if (this.startDatum.getDay() === 6) {
// Samstag => Montag
this.startDatum.setDate(this.startDatum.getDate() + 2)
} else if (this.startDatum.getDay() === 0) {
// Sonntag => Montag
this.startDatum.setDate(this.startDatum.getDate() + 1)
}
}
}
</script>
</script>

View file

@ -1,5 +1,5 @@
<template>
<div class="hello">
<div class="ids grey lighten-3">
<h1>Schueler</h1>
{{ msg }}
</div>
@ -13,3 +13,9 @@ export default {
}
}
</script>
<style>
div.ids {
height: 100%;
}
</style>