This commit is contained in:
2026-04-26 22:02:24 +02:00
commit 73442783b7
1470 changed files with 43422 additions and 0 deletions

286
app/pages/Bildschau.vue Normal file
View File

@@ -0,0 +1,286 @@
<script lang="ts">
import MyFooter from "../components/MyFooter.vue"; // Geändert von Footer auf MyFooter
import Navbar from "../components/Navbar.vue";
import RitzenbergenLib from "../ritzenbergenlib";
import $ from "jquery";
export default {
components: {
Navbar,
MyFooter, // Geändert von Footer auf MyFooter
},
data() {
return {
bild: parseInt(<string>this.$route.params.bild),
ev: this.$route.params.ev,
jahr: this.$route.params.jahr,
RitzenbergenLib: RitzenbergenLib.RitzenbergenLib,
username: "",
kommentar: "",
reloader: false
};
},
asyncComputed: {
kommentare: {
get() {
const url = new URL(
RitzenbergenLib.RitzenbergenLib.api(
"/galerie/get_kommentare.php"
)
);
url.searchParams.append("ev", this.ev);
url.searchParams.append("jahr", this.jahr);
url.searchParams.append("bild", this.bild);
return fetch(url, {
method: "GET",
}).then((response) => response.json());
},
default: null,
watch: ["bild", "ev", "jahr","reloader"],
},
},
computed: {
bilder() {
let result: any[] = [];
$.ajax(
RitzenbergenLib.RitzenbergenLib.api("/galerie/get_bilder.php"),
{
async: false,
success(data: string) {
result = JSON.parse(data);
},
method: "GET",
data: {
ev: this.ev,
jahr: this.jahr,
},
}
);
return result;
},
},
methods: {
kommentarsubmit() {
const url = new URL(
RitzenbergenLib.RitzenbergenLib.api(
"/galerie/submit_kommentar.php"
)
);
url.searchParams.append("ev", this.ev);
url.searchParams.append("jahr", this.jahr);
url.searchParams.append("username", this.username);
url.searchParams.append("kommentar", this.kommentar);
url.searchParams.append("bild", this.bild);
fetch(url, {
method: "GET",
}).then(() => {
this.username = "";
this.kommentar = "";
this.reloader=!this.reloader;
window.alert("Kommentar wurde abgeschickt!");
});
},
},
};
</script>
<template>
<Navbar />
<div class="main">
<section class="flex-card-wrapper">
<article
class="flex-card-container lazy-loading"
:class="{
active: bild == i,
unactive: bild == i - 1 || bild == i + 1,
}"
:style="{
backgroundImage:
'url(' + RitzenbergenLib.get_img(bildel) + ')',
}"
v-for="(bildel, i) in bilder"
:key="i"
@click="bild = i"
></article>
</section>
<br /><br />
<div class="kommentare">
<div v-if="kommentare == null">Lade Kommentare...</div>
<div v-else-if="kommentare.length == 0">
Es gibt noch keine Kommentare.
</div>
<div v-else>
<div
v-for="(kommentar, i) in kommentare"
:key="i"
class="kommentar"
>
<strong class="roboto-medium">{{
kommentar.username
}}</strong
>: {{ kommentar.kommentar }}
</div>
</div>
</div>
<form class="formular" method="post" @submit.prevent="kommentarsubmit">
<input
class="username-input"
type="text"
name="username"
placeholder="Name"
maxlength="32"
required
v-model="username"
/>
<br />
<input
class="kommentar-input"
type="text"
name="kommentar"
placeholder="Kommentar"
maxlength="1024"
required
v-model="kommentar"
/>
<input class="absenden-button" type="submit" value="Absenden" />
</form>
</div>
<br /><br />
<MyFooter></MyFooter>
</template>
<style scoped lang="scss">
@import "../assets/bildschau/style.sass";
.roboto-thin {
font-family: "Roboto", sans-serif;
font-weight: 100;
font-style: normal;
}
.roboto-light {
font-family: "Roboto", sans-serif;
font-weight: 300;
font-style: normal;
}
.roboto-regular {
font-family: "Roboto", sans-serif;
font-weight: 400;
font-style: normal;
}
.roboto-medium {
font-family: "Roboto", sans-serif;
font-weight: 500;
font-style: normal;
}
.roboto-bold {
font-family: "Roboto", sans-serif;
font-weight: 700;
font-style: normal;
}
.roboto-black {
font-family: "Roboto", sans-serif;
font-weight: 900;
font-style: normal;
}
.roboto-thin-italic {
font-family: "Roboto", sans-serif;
font-weight: 100;
font-style: italic;
}
.roboto-light-italic {
font-family: "Roboto", sans-serif;
font-weight: 300;
font-style: italic;
}
.roboto-regular-italic {
font-family: "Roboto", sans-serif;
font-weight: 400;
font-style: italic;
}
.roboto-medium-italic {
font-family: "Roboto", sans-serif;
font-weight: 500;
font-style: italic;
}
.roboto-bold-italic {
font-family: "Roboto", sans-serif;
font-weight: 700;
font-style: italic;
}
.roboto-black-italic {
font-family: "Roboto", sans-serif;
font-weight: 900;
font-style: italic;
}
.kommentare {
flex-direction: column;
margin: 10px;
width: 80%;
text-align: center;
font-family: "Roboto", sans-serif;
}
.formular {
display: left;
flex-direction: row;
align-items: left;
margin: 10px;
border-radius: 5px;
}
.username-input,
.kommentar-input {
width: 100%;
margin-bottom: 10px;
padding: 10px;
border: 1px solid #ddd;
align-items: left;
border-radius: 3px;
}
.absenden-button {
background-color: #0073b7;
color: white;
padding: 10px 20px;
border: 1px solid #0073b7;
border-radius: 5px;
cursor: pointer;
}
.absenden-button:hover {
background-color: #00578b;
}
@media (max-width: 768px) {
.kommentare {
flex-direction: column;
}
.username-input,
.kommentar-input {
width: 50%;
margin-bottom: 10px;
padding: 10px;
border: 1px solid #ddd;
border-radius: 3px;
}
}
.main {
margin-top: 150px;
}
</style>

159
app/pages/Bildvorschau.vue Normal file
View File

@@ -0,0 +1,159 @@
<script lang="ts">
import { RouterLink } from "vue-router";
import Navbar from "../components/Navbar.vue";
import RitzenbergenLib from "../ritzenbergenlib";
import Footer from "../components/MyFooter.vue";
import $ from "jquery";
export default {
data() {
return {
ev: this.$route.params.ev,
jahr: this.$route.params.jahr,
RitzenbergenLib: RitzenbergenLib.RitzenbergenLib,
};
},
computed: {
bilder() {
let result: any[] = [];
$.ajax(RitzenbergenLib.RitzenbergenLib.api("/galerie/get_bilder.php"),{
async: false,
success(data: string) {
result=JSON.parse(data);
},
method: "GET",
data: {
ev: this.ev,
jahr: this.jahr
}
});
return result;
},
bildersplitted() {
let result: any[] = [];
this.bilder.forEach((element, i) => {
if (i % 5 == 0) {
result.push([]);
}
result[result.length - 1].push(element);
});
return result;
},
einereihe() {
return this.bilder.length <= 5;
},
},
components: {
RouterLink,
Navbar,
Footer,
},
methods: {
capitalizeFirstLetter(str: string) {
return str.charAt(0).toUpperCase() + str.slice(1);
},
},
};
</script>
<template>
<Navbar />
<section class="galerie-section">
<div class="galerie-container">
<h2>{{ capitalizeFirstLetter(ev) }} {{ jahr }}</h2>
Vorschaubilder <br />
{{ bilder.length }} Bilder
<table>
<tbody>
<tr v-for="row, i in bildersplitted">
<td v-for="column, j in row">
<RouterLink :to="jahr+'/'+(i*5+j).toString()"
><img :src="RitzenbergenLib.get_img(column)" alt="Vorschaubild"
/></RouterLink>
</td>
</tr>
</tbody>
</table>
</div>
</section>
<div class="platzhalter" v-if="einereihe"></div>
<Footer></Footer>
</template>
<style scoped>
.galerie-container {
width: 80%; /* Breite der Galerie anpassen */
margin: 0 auto; /* Galerie in der Mitte ausrichten */
}
table {
width: 100%; /* Tabelle über die gesamte Breite des Containers */
border-collapse: collapse; /* Zellränder entfernen */
}
th,
td {
padding: 20px; /* Abstand zwischen Bild und Rand der Zelle */
text-align: center; /* Text in der Mitte ausrichten */
}
img {
width: 70%; /* Breite der Vorschaufotos */
height: auto; /* Automatisches Seitenverhältnis bewahren */
margin: 0 auto; /* Bild in der Mitte der Zelle ausrichten */
border-radius: 15px;
}
@media (max-width: 768px) {
/* Smartphones (ca. Portrait-Modus) */
table {
width: 100%; /* Galerie über die gesamte Breite */
}
tr {
display: flex; /* Bilder in einer Reihe anordnen */
flex-wrap: wrap; /* Zeilenumbruch aktivieren */
}
td {
flex: 1 0 50%; /* Zellenbreite gleichmäßig aufteilen */
padding: 10px; /* Randabstand verringern */
}
img {
width: 100%; /* Bilder über die gesamte Zellenbreite */
height: auto; /* Seitenverhältnis bewahren */
margin: 0; /* Bildränder entfernen */
}
}
@media (min-width: 769px) and (max-width: 1024px) {
/* Tablets (ca. Portrait-Modus) */
table {
width: 80%; /* Galerie etwas schmaler */
}
tr {
display: flex; /* Bilder in 3 Reihen anordnen */
flex-wrap: wrap;
}
td {
flex: 1 0 33%; /* Zellenbreite gleichmäßig aufteilen */
padding: 15px; /* Randabstand etwas erhöhen */
}
img {
width: 100%; /* Bilder über die gesamte Zellenbreite */
height: auto; /* Seitenverhältnis bewahren */
margin: 0; /* Bildränder entfernen */
}
}
.galerie-section {
margin-top: 150px;
margin-bottom: 150px;
}
.platzhalter {
height: 150px;
}
</style>

290
app/pages/Bulitipp.vue Normal file
View File

@@ -0,0 +1,290 @@
<script lang="js">
import Navbar from "../components/Navbar.vue";
import MyFooter from "../components/MyFooter.vue";
import Modal from "../components/Modal.vue";
import Uebersicht from "../components/bulitipp/Uebersicht.vue";
import Rangliste from "../components/bulitipp/Rangliste.vue";
import Paarungsergebnisse from "../components/bulitipp/Paarungsergebnisse.vue";
import Tabelle from "../components/bulitipp/Tabelle.vue";
import RitzenbergenLib from "../ritzenbergenlib.ts";
import SpieltagSumme from "../ritzenbergenlib.ts";
import Loading from "../components/bulitipp/Loading.vue";
import $ from "jquery";
import Tippen from "../components/bulitipp/Tippen.vue";
import TippenEinloggen from "../components/bulitipp/TippenEinloggen.vue";
export default {
components: {
Navbar,
MyFooter,
Modal,
Uebersicht,
Rangliste,
Paarungsergebnisse,
Tabelle,
Loading,
Tippen,
TippenEinloggen
},
created(){
RitzenbergenLib.RitzenbergenLib.checkInternetConnection().then((result)=>{
if(!result) this.$router.push("/");
});
},
asyncComputed: {
users: {
get(){
return fetch(RitzenbergenLib.RitzenbergenLib.api("/bulitipp/get-users.php"))
.then((response) => response.json())
.then((result2) => {
if(result2.reload) this.update();
return result2.data;
})
.then((result) => {
result.forEach((user, i) => {
let sum = 0;
this.ts.forEach((spieltag) => {
let points = spieltag.find((element) => {
return element.user.id === user.id;
});
sum += points.tsPoints;
});
user.points = sum;
});
return result;
})
.then((result) => {
return result.map(el => new RitzenbergenLib.User(el.name,el.kuerzel, el.points, el.id));
})
//.then((result)=>result.filter((el)=>(el.points>0&&maxspieltag>=2)))
.catch((error) => {
return null;
});
},
default: [],
watch: ["ts"]
},
ts: {
get() {
return fetch(RitzenbergenLib.RitzenbergenLib.api("/bulitipp/ts.php"))
.then((response) => response.json())
.then((result2) => {
if(result2.reload) this.update();
return result2.data;
})
.then((result)=>{
result.map(element => element.map((element) => {
element.user=new RitzenbergenLib.User(element.user.name, element.user.kuerzel,0, element.user.id);
return element;
}));
return result;
})
.then((result)=>result.map((el) => el.map((el)=> new RitzenbergenLib.SpieltagSumme(el.user,el.points))));
},
default: []
},
saison:{
get(){
return fetch(RitzenbergenLib.RitzenbergenLib.api("/bulitipp/saison.php"))
.then((response) => response.text())
.then((result)=> parseInt(result));
},
default: ""
},
maxspieltag: {
get(){
return fetch(RitzenbergenLib.RitzenbergenLib.api("/bulitipp/maxspieltag.php"))
.then((response) => response.text())
.then((result)=> parseInt(result));
}
},
paarungen: {
get(){
const params = new URLSearchParams({
spieltag: this.maxspieltag
});
return fetch(RitzenbergenLib.RitzenbergenLib.api("/bulitipp/paarungen.php?"+params.toString()))
.then((response) => response.json())
.then((result2) => {
if(result2.reload) this.update();
return result2.data;
})
.then((result) => {
return result.map(el => new RitzenbergenLib.Paarung(el[0],el[1],el[2]));
})
.catch((error) => {
return null;
});
},
watch: ["maxspieltag"],
default: [new RitzenbergenLib.Paarung("Lade...","Lade..."),new RitzenbergenLib.Paarung("Lade...","Lade..."),new RitzenbergenLib.Paarung("Lade...","Lade..."),new RitzenbergenLib.Paarung("Lade...","Lade..."),new RitzenbergenLib.Paarung("Lade...","Lade..."),new RitzenbergenLib.Paarung("Lade...","Lade..."),new RitzenbergenLib.Paarung("Lade...","Lade..."),new RitzenbergenLib.Paarung("Lade...","Lade..."),new RitzenbergenLib.Paarung("Lade...","Lade...")]
},
ergebnisse: {
get(){
return fetch(RitzenbergenLib.RitzenbergenLib.api("/bulitipp/ergebnisse.php"))
.then((response) => response.json())
.then((result2) => {
if(result2.reload) this.update();
return result2.data;
})
.then((result) => {
return result.map((el,i) => new RitzenbergenLib.Ergebnis(this.paarungen[i],el[0],el[1]));
})
},
watch: ["paarungen"]
},
tipps: {
get(){
return fetch(RitzenbergenLib.RitzenbergenLib.api("/bulitipp/tipps.php?spieltag="+this.maxspieltag))
.then((response) => response.json())
.then(response => response.data);
},
watch: ["maxspieltag"],
default: []
},
token: {
get(){
return fetch(RitzenbergenLib.RitzenbergenLib.api("/bulitipp/login.php?kuerzel="+this.kuerzel+"&password="+this.password))
.then((response)=>response.text())
.then((response)=>response=="Benutzer nicht gefunden"?null:response)
.then((response)=>{
if(response == "Falsches Passwort") {
this.wrongpassword = true;
return null;
} else {
this.wrongpassword = false;
return response;
}
});
},
default: null,
watch: ["kuerzel", "password"],
}
},
computed: {
sortedUsers() {
if(this.users instanceof Array) return [...this.users].sort((a, b) => b.points - a.points);
},
loading(){
return this.$asyncComputed.users.updating || this.$asyncComputed.ts.updating;
},
},
methods: {
gs(i) {
let result = 0;
this.spieltage[i].forEach((element) => {
result += element;
});
return result;
},
update(){
location.reload();
},
login(kuerzel, password){
console.log("Login");
this.kuerzel = kuerzel;
this.password = password;
},
logout(){
this.token=null;
this.kuerzel = "";
this.password = "";
this.wrongpassword = false;
},
filterUsers(users){
return users.filter((el)=>el.points>0&&this.maxspieltag>=2);
}
},
data(){
return {
tippenoffen: false,
debug: false,
amtippen: false,
kuerzel: "",
password: "",
wrongpassword: false
}
}
};
</script>
<template>
<Loading v-show="loading && !debug" />
<Navbar buttontext="Tippen" @clickbtn="tippenoffen = true" />
<section
class="header16 cid-u6k7q0xIhk bulitipp mbr-fullscreen mbr-parallax-background"
id="hero-17-u6k7q0xIhk"
>
<div
class="mbr-overlay"
style="opacity: 0.3; background-color: rgb(0, 0, 0)"
></div>
<div class="container-fluid">
<div class="row">
<div class="content-wrap col-12 col-md-10">
<h1
class="mbr-section-title mbr-fonts-style mbr-white mb-4 display-1"
>
<strong>Willkommen im Bundesliga Tippspiel</strong>
</h1>
<p
class="mbr-fonts-style mbr-text mbr-white mb-4 display-7"
>
Saison {{ saison }}/{{ saison + 1 }}
</p>
<br /><br />
</div>
</div>
</div>
</section>
<Modal v-show="tippenoffen" @closemodal="tippenoffen = false">
<Tippen v-show="token != null" :token="token" @logout="logout" />
<TippenEinloggen
v-show="token == null"
@login="login"
:wrongpassword="wrongpassword"
/>
</Modal>
<Uebersicht
:paarungen="paarungen"
:tipps="tipps"
:users="filterUsers(users)"
:spieltag="maxspieltag"
/>
<!-- Rangliste -->
<Rangliste
:users="filterUsers(sortedUsers)"
:spieltag="maxspieltag"
:tipps="tipps"
:results="ergebnisse"
/>
<!-- Paarungsergebnisse -->
<Paarungsergebnisse :ergebnisse="ergebnisse" :maxspieltag="maxspieltag" :users="users" :tipps="tipps" />
<!-- Punktetabelle -->
<Tabelle :users="users" :ts="ts" />
<br />
<br />
<br />
<MyFooter />
</template>
<style scoped>
@import "../assets/css/bulitipp2.css";
#hero-17-u6k7q0xIhk {
margin-bottom: 100px;
}
</style>

164
app/pages/Galerie.vue Normal file
View File

@@ -0,0 +1,164 @@
<script lang="js">
import Navbar from "../components/Navbar.vue";
import Embla from "../components/Embla.vue";
import RitzenbergenLib from "../ritzenbergenlib.ts";
import MyFooter from "../components/MyFooter.vue"; // Geändert von Footer auf MyFooter
import $ from "jquery";
export default {
components: {
Navbar,
Embla,
MyFooter, // Geändert von Footer auf MyFooter
},
computed: {
events() {
let erntefeste = this.get_jahre("erntefest");
let osterfeuer = this.get_jahre("osterfeuer");
let doppelkopf = this.get_jahre("doppelkopf");
let fussball = this.get_jahre("fussball");
if(erntefeste==undefined) return [];
let result = [
{
src: erntefeste.map((erntefest) =>
RitzenbergenLib.RitzenbergenLib.api(
"randomimage.php?path=/erntefest/" +
erntefest +
"&recursive=1&tn=1&text=" +
erntefest +
"&color=white"
)
),
title: "Erntefeste",
ev: "erntefest",
},
{
src: osterfeuer.map((osterfeuer) =>
RitzenbergenLib.RitzenbergenLib.api(
"randomimage.php?path=/osterfeuer/" +
osterfeuer +
"&recursive=1&tn=1&text=" +
osterfeuer +
"&color=white"
)
),
title: "Osterfeuer",
ev: "osterfeuer",
},
{
src: doppelkopf.map((doppelkopf) =>
RitzenbergenLib.RitzenbergenLib.api(
"randomimage.php?path=/doppelkopf/" +
doppelkopf +
"&recursive=1&tn=1&text=" +
doppelkopf +
"&color=white"
)
),
title: "Doppelkopf",
ev: "doppelkopf",
},
{
src: fussball.map((fussball) =>
RitzenbergenLib.RitzenbergenLib.api(
"randomimage.php?path=/fussball/" +
fussball +
"&recursive=1&tn=1&text=" +
fussball +
"&color=white"
)
),
title: "Fußballturniere",
ev: "fussball",
},
];
return result.map((ev) => {
let jahre = this.get_jahre(ev.ev);
ev.links = jahre.map((jahr) => {
return "/bild/" + ev.ev + "/" + jahr;
});
return ev;
});
},
},
methods: {
get_jahre(event) {
let result;
$.ajax(RitzenbergenLib.RitzenbergenLib.api("/galerie/get_jahre.php"), {
success(data) {
result = JSON.parse(data);
},
async: false,
data: { event },
});
return result;
},
},
mounted(){
if(this.$route.params.ev){
let ev = this.$route.params.ev;
if(this.$refs[ev]) this.$refs[ev][0].scrollIntoView();
this.$router.push("/galerie");
}
}
};
</script>
<template>
<Navbar :links="[
{ title: 'Erntefest', link: '/galerie/erntefest' },
{ title: 'Osterfeuer', link: '/galerie/osterfeuer' },
{ title: 'Doppelkopf', link: '/galerie/doppelkopf' },
{ title: 'Fußballturniere', link: '/galerie/fussball' },
]" />
<br />
<br />
<br />
<br />
<br />
<br />
<section class="article12 cid-u6k7q0yKNv" id="about-us-12-u6k7q0yKNv">
<div class="container">
<div class="row justify-content-center">
<div class="col-md-12 col-lg-10">
<h3 class="mbr-section-title mbr-fonts-style mb-4 mt-0 display-2">
<strong>Willkommen in der Galerie</strong>
</h3>
<p class="mbr-text mbr-fonts-style display-7">
In unserem Fotoalbum findest du chronisch geordnete Bilder
verschiedener Veranstaltungen aus den letzten Jahrzehnten. Einfach
auf ein Bild mit einer Jahreszahl raufklicken.
</p>
</div>
</div>
</div>
</section>
<br /><br />
<section
class="slider4 mbr-embla cid-u6k7q0yLdW"
:ref="event.ev"
v-for="event in events"
>
<div class="container-fluid">
<div class="row">
<h4
class="mbr-section-title mbr-fonts-style align-center mb-0 display-2"
>
<strong>{{ event.title }}</strong>
</h4>
<div class="col-12">
<br />
<Embla :src="event.src" :links="event.links" />
</div>
</div>
</div>
<br /><br /><br />
</section>
<h1 v-if="events.length==0">Keine Internetverbindung!</h1>
<br /><br /><br />
<MyFooter />
</template>
<style scoped></style>

View File

@@ -0,0 +1,51 @@
<script lang="ts" setup>
import Navbar from "../../components/Navbar.vue";
import { ref } from "vue";
import { useRouter } from 'vue-router'
import RitzenbergenLib from "../../ritzenbergenlib.ts";
const router = useRouter()
RitzenbergenLib.RitzenbergenLib.checkInternetConnection().then((result)=>{
if(!result) router.push("/");
});
async function login(){
const url=new URL(RitzenbergenLib.RitzenbergenLib.api("/admin/login.php"));
url.searchParams.append("username",username.value);
url.searchParams.append("password",password.value);
const token=await fetch(url)
.then((result)=>result.json())
.then((result)=>{
if(result.success) return result.token;
else{
window.alert(result.error);
return "";
}
});
if(token!="") router.push({ name: "adminpanel-main", params: { token } })
}
const username=ref("");
const password=ref("");
</script>
<template>
<br>
<br>
<br>
<br>
<br>
<h1>Admin Panel</h1>
<Navbar/>
<form @submit.prevent="login()">
<input type="text" placeholder="Benutzername" v-model="username"/>
<input type="password" placeholder="Passwort" v-model="password"/>
<input type="submit" value="Login"/>
</form>
</template>
<style scoped></style>

View File

@@ -0,0 +1,128 @@
<script lang="ts" setup>
import AdminNavbar from "../../components/admin/AdminNavbar.vue";
import { useRoute } from "vue-router";
import { ref } from "vue";
import RitzenbergenLib from "../../ritzenbergenlib.ts";
import InputP from "../../components/admin/InputP.vue";
const route = useRoute();
const token = ref(route.params.token);
async function submit(myevent) {
const url = new URL(
RitzenbergenLib.RitzenbergenLib.api("/admin/events/editEvent.php")
);
return fetch(url, {
headers: {
Authorization: "Bearer " + token.value,
},
body: JSON.stringify(myevent),
method: "POST"
});
}
const events = ref([]);
async function getEvents() {
return fetch(RitzenbergenLib.RitzenbergenLib.api("/get_events.php"))
.then((res) => res.json())
.then((res) => {
events.value = res;
console.log(events.value);
return res;
});
}
getEvents();
</script>
<template>
<AdminNavbar />
<br />
<br />
<br />
<br />
<br />
<h1>Events</h1>
<table>
<thead>
<tr>
<td>Name</td>
<td>Datum</td>
<td>Typ</td>
<td>Inhalt</td>
<td>Link</td>
<td>Foto</td>
<td>Minitext</td>
<td>Formular</td>
<td></td>
</tr>
</thead>
<tbody>
<tr v-for="event in events" :key="event.id">
<td>
<InputP
v-model="event.eventname"
:nullable="false"
inputtype="text"
/>
</td>
<td>
<InputP
v-model="event.datum"
:nullable="false"
inputtype="date"
/>
</td>
<td>
<select v-model="event.type">
<option value="link">Link</option>
<option value="markdown">Markdown</option>
<option value="dlink">Download-Link</option>
<option value="html">HTML</option>
<option value="fotos">Fotos</option>
</select>
</td>
<td>
<textarea v-model="event.content"></textarea>
</td>
<td>
<InputP
v-model="event.link"
:nullable="true"
inputtype="text"
/>
</td>
<td>
<InputP
v-model="event.foto"
:nullable="false"
inputtype="text"
/>
</td>
<td>
<InputP
v-model="event.minitext"
:nullable="false"
inputtype="text"
/>
</td>
<td>
<select v-model="event.formular">
<option :value="null"></option>
<option :value="1">testformular-2</option>
</select>
</td>
<td>
<button @click="submit(event)">Speichern</button>
</td>
</tr>
</tbody>
</table>
</template>
<style scoped lang="scss">
@import "../../assets/css/bulitipp2.css";
h1 {
text-align: center;
}
</style>

View File

@@ -0,0 +1,280 @@
<script setup lang="ts">
import { useRoute } from "vue-router";
import { ref } from "vue";
import AdminNavbar from "../../components/admin/AdminNavbar.vue";
import RitzenbergenLib from "../../ritzenbergenlib.ts";
import InputP from "../../components/admin/InputP.vue";
import FormResults from "../../components/FormResults.vue";
const route = useRoute();
const token = ref(route.params.token);
const formulare: RitzenbergenLib.Formular[] = ref([]);
RitzenbergenLib.Formular.getForms().then(
(result) => (formulare.value = result)
);
async function saveForm(form) {
return fetch(RitzenbergenLib.RitzenbergenLib.api("/admin/formulare/updateForm.php"),{
method: "POST",
body: JSON.stringify(form),
headers: {
"Content-Type":"application/json",
"Authorization":"Bearer "+token.value
}
})
}
async function deleteForm(form){
const url=new URL(RitzenbergenLib.RitzenbergenLib.api("/admin/formulare/deleteForm.php"));
url.searchParams.set("id",form.id);
return fetch(url,{
headers: {
"Authorization":"Bearer "+token.value
}
})
.then((response) => {
if (response.ok)
RitzenbergenLib.Formular.getForms().then(
(result) => (formulare.value = result)
);
return response;
})
}
function filterType(type: string) {
if (type in ["radio", "checkbox"]) return "text";
return type;
}
async function newForm() {
return fetch(RitzenbergenLib.RitzenbergenLib.api("/admin/formulare/newForm.php"),{
headers: {
"Authorization":"Bearer "+token.value
}
})
.then((response) => {
if (response.ok)
RitzenbergenLib.Formular.getForms().then(
(result) => (formulare.value = result)
);
return response;
})
.then((response) => response.json());
}
</script>
<template>
<AdminNavbar />
<br />
<br />
<br />
<br />
<br />
<h1>Formulare</h1>
<div class="formeditor">
<form
@submit.prevent="saveForm(form)"
v-for="(form, i) in formulare"
:key="i"
>
<input type="text" placeholder="Name" v-model="form.name"/><br>
<input type="text" placeholder="Minitext (Ergebnisse anzeigen-Button)" v-model="form.minitext"/><br>
<label for="publicCheckbox">Ergebnisse veröffentlichen</label>
<input type="checkbox" id="publicCheckbox" v-model="form.ispublic"/><br>
<label for="multipleCheckbox">Mehrfacheinträge zulassen</label>
<input type="checkbox" id="multipleCheckbox" v-model="form.multiple"/><br>
*: Muss gesetzt werden
<table>
<thead>
<tr>
<td>ID</td>
<td>Name *</td>
<td>Display-Name</td>
<td>Value *</td>
<td>Display-Value</td>
<td>Placeholder</td>
<td>Type *</td>
<td>Title (Hover)</td>
<td>Required *</td>
<td>Max. Länge</td>
<td>Minimum</td>
<td>Maximum</td>
<td>Checked (für Checkbox und Radio)</td>
</tr>
</thead>
<tbody>
<tr v-for="(field, j) in form.fields" :key="j">
<td>{{ field.id }}</td>
<td>
<InputP
inputtype="text"
:nullable="false"
v-model="field.name"
/>
</td>
<td>
<InputP
inputtype="text"
:nullable="true"
v-model="field.displayname"
/>
</td>
<td>
<InputP
:inputtype="filterType(field.type)"
:nullable="false"
v-model="field.value"
/>
</td>
<td>
<InputP
inputtype="text"
:nullable="true"
v-model="field.displayvalue"
/>
</td>
<td>
<InputP
inputtype="text"
:nullable="true"
v-model="field.placeholder"
/>
</td>
<td>
<select v-model="field.type">
<option value="text">Text</option>
<option value="number">Zahl</option>
<option value="range">Schieberegler</option>
<option value="date">Datum</option>
<option value="time">Zeit</option>
<option value="checkbox">Checkbox</option>
<option value="radio">Radio Button</option>
<option value="color">Farbe</option>
<option value="textarea">
Mehrzeiliger Text
</option>
</select>
</td>
<td>
<InputP
inputtype="text"
:nullable="true"
v-model="field.title"
/>
</td>
<td>
<InputP
inputtype="checkbox"
:nullable="false"
v-model="field.required"
/>
</td>
<td>
<InputP
inputtype="number"
:nullable="true"
v-model="field.maxlength"
/>
</td>
<td>
<InputP
inputtype="number"
:nullable="true"
v-model="field.min"
/>
</td>
<td>
<InputP
inputtype="number"
:nullable="true"
v-model="field.max"
/>
</td>
<td>
<InputP
inputtype="checkbox"
:nullable="true"
v-model="field.checked"
/>
</td>
</tr>
<tr>
<td>
<button
@click="
form.fields.push(
new RitzenbergenLib.Field()
)
"
>
Neu
</button>
</td>
</tr>
</tbody>
</table>
<br />
<input class="saveBtn" type="submit" value="Speichern" />
<br />
<input class="deleteBtn" type="button" value="Löschen (Doppelklick)" @dblclick="deleteForm(form)" />
</form>
<button class="newFormBtn deleteBtn" @click="newForm">Neues Formular</button>
<br>
<br>
</div>
<div class="formresults">
<FormResults v-for="form in formulare.filter((el)=>el!=undefined)" :key="form" :form="form" :token="token"/>
</div>
</template>
<style lang="scss" scoped>
@import "../../assets/css/bulitipp2.css";
thead tr td {
background-color: #efefef;
}
.saveBtn {
margin-left: 20%;
margin-right: 20%;
}
label, p, i, h1, h2 {
text-align: center;
}
.formresults{
overflow: scroll;
}
input{
max-width: 300px;
}
form {
display: flex;
align-items: center;
justify-content: center;
border: 3px solid black;
border-radius: 10px;
margin: 20px;
padding: 30px;
}
.deleteBtn {
padding: 12px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.3s ease;
text-align: center;
background-color: #cc0000;
color: white;
}
.deleteBtn:hover{
background-color: #aa0000;
}
.newFormBtn{
background-color: #0000ff;
}
.newFormBtn:hover{
background-color: #0000aa;
}
.formeditor {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
}
</style>

View File

@@ -0,0 +1,20 @@
<script lang="ts" setup>
import { useRoute } from 'vue-router'
import { ref } from "vue";
import AdminPanelLib from "../../adminpanellib.ts";
import AdminNavbar from "../../components/admin/AdminNavbar.vue";
const route = useRoute();
const token=ref(route.params.token);
const userinfo=ref({})
AdminPanelLib.AdminPanelLib.getUserInfo(token.value).then((result)=>userinfo.value=result);
</script>
<template>
<AdminNavbar/>
<h1>Admin Panel</h1>
<h2>Moin {{ userinfo.username }}!</h2>
</template>

97
app/pages/index.vue Normal file
View File

@@ -0,0 +1,97 @@
<script lang="ts" setup>
import Navbar from "../components/Navbar.vue";
import Modal from "../components/Modal.vue";
import Embla from "../components/Embla.vue";
import Umgebung from "../components/startseite/Umgebung.vue";
import MyFooter from "../components/MyFooter.vue"; // Geändert von Footer auf MyFooter
import RitzenbergenLib from "../ritzenbergenlib";
import WillkommenText from "../components/startseite/WillkommenText.vue";
import Bilderbuch from "../components/startseite/Bilderbuch.vue";
import Forms from "../components/startseite/Forms.vue";
import Events from "../components/startseite/Events.vue";
import Willkommen from "../components/startseite/Willkommen.vue";
import { ref } from "vue";
const images=ref([]);
async function loadImage(path: string) {
try{
const response = await fetch(RitzenbergenLib.RitzenbergenLib.api(path), {
headers: {
"Accept":"image/png"
}
});
if(!response.ok) return false;
const blob = await response.blob();
return URL.createObjectURL(blob);
}catch(e){
console.warn(e);
}
}
// loadImage("randomimage.php?path=/doppelkopf&recursive=1&tn=1&color=white&text=Doppelkopf&size=3").then((url)=>{
// images.value[0]=url;
// });
// loadImage("randomimage.php?path=/erntefest&recursive=1&tn=1&color=white&text=Erntefest&size=3").then((url)=>{
// images.value[1]=url;
// });
// loadImage("randomimage.php?path=/fussball&recursive=1&tn=1&color=white&text=Fußballturnier&size=3").then((url)=>{
// images.value[2]=url;
// });
// loadImage("randomimage.php?path=/osterfeuer&recursive=1&tn=1&color=white&text=Osterfeuer&size=3").then((url)=>{
// images.value[3]=url;
// });
</script>
<template>
<!-- Startseite -->
<Navbar />
<Willkommen/>
<Events style="margin-top: 120px;"/>
<Forms/>
<!-- <Bilderbuch/> -->
<!-- <section class="slider4 mbr-embla cid-u6k7q0yLdW" id="gallery-13-u6k7q0yLdW" v-if="images[0]">
<div class="container-fluid">
<div class="row">
<div class="col-12">
<Embla :src="images"
:links='[
"/galerie/erntefest",
"/galerie/osterfeuer",
"/galerie/doppelkopf",
"/galerie/fussball",
""
]'
/>
</div>
</div>
</div>
</section>
<WillkommenText ref="willkommen"/>
<br>
<br> -->
<Umgebung ref="umgebung" />
<MyFooter ref="footer" />
</template>
<style lang="css" scoped></style>