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

View File

@@ -0,0 +1,106 @@
<script>
export default {
}
</script>
<template>
<div class="loading-container">
<div class="loading-main">
<h1>Lade...</h1>
<div class="dots-bars-6"></div>
</div>
</div>
</template>
<style scoped>
h1{
margin-bottom: 50px;
}
.loading-container {
position: fixed;
top: 0;
left: 0;
bottom: 0;
right: 0;
margin: 0;
background-color: rgba(0, 0, 0, 0.5);
width: 100%;
height: 100%;
z-index: 100;
align-items: center;
justify-content: center;
display: flex;
}
.loading-main{
display: flex;
justify-content: center;
align-items: center;
height: 50%;
width: 50%;
background-color: white;
border-radius: 20px;
flex-direction: column;
}
.dots-bars-6 {
width: 40px;
height: 20px;
--c:radial-gradient(farthest-side,currentColor 93%,#0000);
background:
var(--c) 0 0,
var(--c) 50% 0;
background-size:8px 8px;
background-repeat: no-repeat;
position: relative;
clip-path: inset(-200% -100% 0 0);
animation: db6-0 1.5s linear infinite;
}
.dots-bars-6:before {
content: "";
position: absolute;
width: 8px;
height: 12px;
background:currentColor;
left:-16px;
top:0;
animation:
db6-1 1.5s linear infinite,
db6-2 0.5s cubic-bezier(0,200,.8,200) infinite;
}
.dots-bars-6:after {
content: "";
position: absolute;
inset:0 0 auto auto;
width:8px;
height: 8px;
border-radius: 50%;
background:currentColor;
animation: db6-3 1.5s linear infinite;
}
@keyframes db6-0 {
0%,30% {background-position: 0 0 ,50% 0 }
33% {background-position: 0 100%,50% 0 }
41%,63% {background-position: 0 0 ,50% 0 }
66% {background-position: 0 0 ,50% 100%}
74%,100%{background-position: 0 0 ,50% 0 }
}
@keyframes db6-1 {
90% {transform:translateY(0)}
95% {transform:translateY(15px)}
100% {transform:translateY(15px);left:calc(100% - 8px)}
}
@keyframes db6-2 {
100% {top:-0.1px}
}
@keyframes db6-3 {
0%,80%,100% {transform:translate(0)}
90% {transform:translate(26px)}
}
</style>

View File

@@ -0,0 +1,161 @@
<script lang="js">
import RitzenbergenLib from "../../ritzenbergenlib.ts";
import Modal from "../Modal.vue";
export default {
props: {
ergebnisse: {
type: Array,
required: true,
},
maxspieltag: {
type: Number,
required: true,
},
tipps: {
type: Array,
required: true,
},
users: {
type: Array,
required: true,
},
},
data() {
return {
RitzenbergenLib,
showmodal: false,
modalindex: 0,
};
},
components: {
Modal,
},
methods: {
ps(heim, gast, ergebnisHeim, ergebnisGast) {
if(heim == ergebnisHeim && gast == ergebnisGast) {
return 3;
}
const tippDiff = heim - gast;
const ergebnisDiff = ergebnisHeim - ergebnisGast;
if(tippDiff === ergebnisDiff) {
return 2;
}
if(heim > gast && ergebnisHeim > ergebnisGast) {
return 1;
}
if(heim < gast && ergebnisHeim < ergebnisGast) {
return 1;
}
return 0;
},
},
};
</script>
<template>
<section class="buli-results scroll-x" id="buliresults-section">
<br /><br />
<h2>Paarungsergebnisse {{ maxspieltag }}. Spieltag</h2>
<Modal v-if="showmodal" @closemodal="showmodal = false">
<h1 class="detailansichtSchriftart">
Detailansicht {{ maxspieltag }}. Spieltag
</h1>
<h2 class="detailansichtSchriftart">
{{ ergebnisse[modalindex].paarung.heim }} -
{{ ergebnisse[modalindex].paarung.gast }}
</h2>
<h1>
{{ ergebnisse[modalindex].heim }} -
{{ ergebnisse[modalindex].gast }}
</h1>
<table class="detailansichtSchriftart">
<tbody>
<tr>
<td>Name</td>
<td>Tipp</td>
<td>Punkte</td>
<td>Gesamtpunktzahl</td>
</tr>
<tr
v-for="(tipp, i) in tipps.filter(
(tipp) =>
tipp.tipp.paarungsid ==
ergebnisse[modalindex].paarung.id
)"
:key="i"
>
<td>
{{
users.filter((user) => user.id == tipp.user)[0]
.username
}}
</td>
<td>{{ tipp.tipp.heim }} - {{ tipp.tipp.gast }}</td>
<td>{{ ps(tipp.tipp.heim, tipp.tipp.gast, ergebnisse[modalindex].heim, ergebnisse[modalindex].gast) }}</td>
<td>
{{
users.filter((user) => user.id == tipp.user)[0]
.points
}}
</td>
</tr>
</tbody>
</table>
</Modal>
<table>
<tbody>
<tr>
<td>Paarung</td>
<td>Ergebnis</td>
</tr>
<tr v-for="(ergebnis, i) in ergebnisse" :key="i">
<td
@click="
showmodal = true;
modalindex = i;
"
>
<span class="as-link">
<span class="teams">
<span class="team">
<img
:src="
RitzenbergenLib.RitzenbergenLib.api(
'/bulitipp/get-image.php?team=' +
ergebnis.paarung.heim
)
"
alt=""
/>
<p>{{ ergebnis.paarung.heim }}</p>
</span>
<span class="vs"></span>
<span class="team">
<p>{{ ergebnis.paarung.gast }}</p>
<img
:src="
RitzenbergenLib.RitzenbergenLib.api(
'/bulitipp/get-image.php?team=' +
ergebnis.paarung.gast
)
"
alt=""
/>
</span>
</span>
</span>
</td>
<td>
<p>{{ ergebnis.heim }} - {{ ergebnis.gast }}</p>
</td>
</tr>
</tbody>
</table>
</section>
</template>
<style scoped>
@import "../../assets/css/bulitipp2.css";
h1 {
text-align: center;
}
</style>

View File

@@ -0,0 +1,98 @@
<script lang="ts">
import ritzenbergenlib from '../../ritzenbergenlib';
import Modal from '../Modal.vue';
export default {
props: {
users: {
type: Array,
required: true
},
spieltag: {
type: Number,
required: true
},
results: {
type: Array,
required: true
},
tipps: {
type: Array,
required: true
}
},
computed: {
},
data(){
return {
modalOpen: false,
currentuser: null
}
},
components: {
Modal
},
methods: {
getById(results,paarungsid){
return results.find((result) => {
return result.paarung.id === paarungsid;
});
},
},
asyncComputed: {
spiele: {
get(){
if(this.spieltag==null) return;
if(this.currentuser==null) return;
return ritzenbergenlib.Spiel.fetchSpiele(this.spieltag-1, this.currentuser.id);
},
watch: ["spieltag","currentuser"],
default: []
}
}
}
</script>
<template>
<section class="rangliste" id="rangliste-sektion">
<br /><br />
<Modal v-if="modalOpen" @closemodal="modalOpen = false">
<h1 class="detailansichtSchriftart">Detailansicht für {{ currentuser.username }}, {{ spieltag }}. Spieltag</h1>
<table>
<tr>
<td>Tipps von {{ currentuser.username }}</td>
<td>Ergebnis</td>
<td>Tipp</td>
<td>Punkte</td>
</tr>
<tr v-for="(spiel,i) in spiele">
<td>{{ spiel.paarung.heim }} - {{ spiel.paarung.gast }}</td>
<td>{{ spiel.result[0] }} - {{ spiel.result[1] }}</td>
<td v-if="spiel.tipp!=null">{{ spiel.tipp[0] }} - {{ spiel.tipp[1] }}</td>
<td v-else>-</td>
<td>{{ spiel.calcPoints() }}</td>
</tr>
</table>
</Modal>
<h2>Rangliste</h2>
<table>
<tbody>
<tr>
<td>Platz</td>
<td>Name</td>
<td>Punkte</td>
</tr>
<tr v-for="(user, i) in users">
<td>{{ i+1 }}</td>
<td @click="modalOpen=true; currentuser=user">
<span class="as-link">{{ user.username }}</span>
</td>
<td>{{ user.points }}</td>
</tr>
</tbody>
</table>
</section>
</template>
<style scoped>
@import "../../assets/css/bulitipp2.css";
</style>

View File

@@ -0,0 +1,105 @@
<script lang="ts">
import ritzenbergenlib from "../../ritzenbergenlib";
import Modal from "../Modal.vue";
export default {
props: {
users: {
type: Array,
required: true,
},
ts: {
type: null,
required: true,
},
},
methods: {
closeModal(){
this.modalOpen=false;
},
openModal(spieltag, user){
this.modalOpen=true;
this.spieltag=spieltag;
this.user=user;
},
},
components: {
Modal,
},
data(){
return {
modalOpen: false,
spieltag: null,
user: null,
RitzenbergenLib: ritzenbergenlib.RitzenbergenLib
}
},
computed: {
},
asyncComputed: {
modalContent: {
get(): Array<ritzenbergenlib.Spiel>{
if(this.spieltag==undefined) return [];
return ritzenbergenlib.Spiel.fetchSpiele(this.spieltag,this.ts[this.spieltag][this.user].user.id);
},
default: []
}
}
};
</script>
<template>
<Modal v-if="modalOpen" @closemodal="closeModal"
><h1 class="detailansichtSchriftart">
Detailansicht für {{ ts[spieltag][user].user.username }},
{{ spieltag + 1 }}. Spieltag
</h1>
<table>
<tr>
<td>Tipp von {{ ts[spieltag][user].user.username }}</td>
<td>Ergebnis</td>
<td>Tipp</td>
<td>Punkte</td>
</tr>
<tr v-for="spiel in modalContent">
<td>{{ spiel.paarung.heim }} - {{ spiel.paarung.gast }}</td>
<td>{{ spiel.result[0] }} - {{ spiel.result[1] }}</td>
<td v-if="spiel.tipp!=null">{{ spiel.tipp[0] }} - {{ spiel.tipp[1] }}</td>
<td v-else> - </td>
<td>{{ spiel.calcPoints() }}</td>
</tr>
</table>
</Modal>
<section class="buli-table" id="buli-table">
<br /><br />
<h2>Punktetabelle</h2>
<table>
<tbody>
<tr>
<td>Tag</td>
<td v-for="spieltag in ts[0]">{{ spieltag.user.username }}</td>
</tr>
<tr v-for="(spieltag, i) in ts">
<td>{{ i + 1 }}</td>
<!-- Open BTN -->
<td
class="as-link"
v-for="(userpoints, j) in spieltag"
@click="openModal(i, j)"
>
{{ userpoints.tsPoints }}
</td>
</tr>
<tr>
<td>Summe</td>
<td v-for="user in users">{{ user.points }}</td>
</tr>
</tbody>
</table>
</section>
</template>
<style scoped>
@import "../../assets/css/bulitipp2.css";
</style>

View File

@@ -0,0 +1,229 @@
<script lang="ts">
import ritzenbergenlib from "../../ritzenbergenlib";
import "../../assets/css/bulitipp2.css";
export default {
props: {
token: {
type: String,
required: false,
},
},
data() {
return {
spieltag: "",
vmodelspieltag: "",
tipps: [
new ritzenbergenlib.Tipp(null, null, null),
new ritzenbergenlib.Tipp(null, null, null),
new ritzenbergenlib.Tipp(null, null, null),
new ritzenbergenlib.Tipp(null, null, null),
new ritzenbergenlib.Tipp(null, null, null),
new ritzenbergenlib.Tipp(null, null, null),
new ritzenbergenlib.Tipp(null, null, null),
new ritzenbergenlib.Tipp(null, null, null),
new ritzenbergenlib.Tipp(null, null, null)
],
disabled: false,
schongetippt: true
};
},
asyncComputed: {
userinfo: {
get() {
if (this.token == null) return null;
return fetch(
ritzenbergenlib.RitzenbergenLib.api(
"/bulitipp/userinfo.php?token=" + this.token
)
)
.then((response) => response.json())
.catch((error) => {
console.error("Error fetching user info:", error);
return null;
});
},
default: null,
},
paarungen: {
get() {
if (this.spieltag == null) return null;
return fetch(
ritzenbergenlib.RitzenbergenLib.api(
"/bulitipp/paarungen.php?spieltag=" + this.spieltag
)
)
.then((response) => response.json())
.then((response) => response.data)
.then((response) =>
response.map((el) => {
return new ritzenbergenlib.Paarung(el[0], el[1], el[2]);
})
);
},
default: null,
},
maxtippspieltag: {
get(){
return fetch(
ritzenbergenlib.RitzenbergenLib.api(
"/bulitipp/maxtippspieltag.php"
)
)
.then((response) => response.text())
.then((text)=> parseInt(text))
}
},
maxspieltag: {
get(){
return fetch(
ritzenbergenlib.RitzenbergenLib.api(
"/bulitipp/maxspieltag.php"
)
)
.then((response) => response.text())
.then((text)=> parseInt(text))
}
},
mintippspieltag: {
get(): number {
if(this.maxspieltag==34){
this.disabled = true;
return 1;
}else{
this.disabled = false;
return this.maxspieltag + 1;
}
},
watch: ["maxspieltag"]
},
tippupdater:{
get(){
const params = new URLSearchParams({
spieltag: this.spieltag.toString()
});
return fetch(
ritzenbergenlib.RitzenbergenLib.api(
"/bulitipp/tippsuser.php?" + params.toString()),
{
method: "GET",
headers: {
Authorization: "Bearer " + this.token,
},
}
)
.then((response) => response.json())
.then((response) => {
if (response.length > 0) {
return response.map((el:any) => {
if(el==null){
this.schongetippt = false;
return new ritzenbergenlib.Tipp(null, null, null);
}
this.schongetippt=true;
return new ritzenbergenlib.Tipp(
el.paarung,
el.score1,
el.score2
);
});
}
}).then(response=>{
this.tipps=response;
return response;
});
},
watch: ["spieltag"]
},
zeitzutippen: {
get(){
return fetch(
ritzenbergenlib.RitzenbergenLib.api(
"/bulitipp/zeitzutippen.php"
)
)
.then((response) => response.json());
}
}
},
emits: ["logout"],
methods: {
getTeamImage(team: string) {
return ritzenbergenlib.RitzenbergenLib.api(
"/bulitipp/get-image.php?team=" + team
);
},
async tippen(){
this.tipps.forEach((tipp, i) => {
tipp.paarung = this.paarungen[i];
});
const params = new URLSearchParams({
spieltag: this.spieltag.toString(),
tipps: JSON.stringify(this.tipps)
});
let result=await fetch(
ritzenbergenlib.RitzenbergenLib.api("/bulitipp/tippeintragen.php?"+params.toString()),
{
method: "GET",
headers: {
Authorization: "Bearer " + this.token,
},
}
);
this.spieltag = "";
}
},
};
</script>
<template>
<div>
<div v-if="(spieltag == '' || spieltag == null) && userinfo != null">
<h1>Moin {{ userinfo.username }}!</h1>
<br />
<h4 v-if="zeitzutippen!=null">Du hast noch <span v-if="zeitzutippen.days!=0">{{ zeitzutippen.days }} Tage und </span>{{ zeitzutippen.hours }} Stunden Zeit, den {{ zeitzutippen.spieltag }}. Spieltag zu tippen.</h4>
<br />
<div v-if="disabled">
<h3>Gerade kann nicht getippt werden.</h3><br>
</div>
<form @submit.prevent="spieltag = parseInt(vmodelspieltag)">
<input
type="number"
v-model="vmodelspieltag"
:placeholder="'Spieltag (max: '+maxtippspieltag+')'"
:min="mintippspieltag"
:max="maxtippspieltag"
required
:disabled="disabled"
/>
<input type="submit" value="Tippen" :disabled="disabled" />
<br /><br />
<input type="button" value="Ausloggen" @click="$emit('logout')" class="red-button" />
</form>
</div>
<div class="tippenEintragen" v-else>
<form @submit.prevent="tippen" id="mainform">
<span class="paarung" v-for="(paarung,i) in paarungen" :key="paarung.id">
<img :src="getTeamImage(paarung.heim)" alt="" />
<span class="team-name">{{ paarung.heim }}</span>
<input v-model="tipps[i].heim" type="number" min="0" class="score" required />
<span class="vs"></span>
<input v-model="tipps[i].gast" type="number" min="0" class="score" required />
<span class="team-name">{{ paarung.gast }}</span>
<img :src="getTeamImage(paarung.gast)" alt="" /><br />
</span>
<input type="submit" :value="schongetippt?'Tipps aktualisieren':'Tippen'" class="green-button"/>
<br /><br />
<input type="button" value="Abbrechen" @click="spieltag = ''" class="red-button" />
</form>
</div>
</div>
</template>
<style scoped>
img {
width: 30px;
}
</style>

View File

@@ -0,0 +1,40 @@
<script lang="ts">
import CryptoJS from 'crypto-js';
export default {
data() {
return {
kuerzel: "",
password: ""
}
},
methods: {
login(){
this.$emit("login", this.kuerzel, CryptoJS.SHA256(this.password).toString(CryptoJS.enc.Hex));
this.kuerzel="";
this.password="";
}
},
props: {
wrongpassword: {
type: Boolean,
default: false
}
},
emits: ["login"]
}
</script>
<template>
<div>
<h1>Einloggen</h1>
<form @submit.prevent="login">
<input type="text" placeholder="Kürzel" v-model="kuerzel" required />
<input type="password" placeholder="Passwort" v-model="password" required />
<input type="submit" value="Einloggen">
<div v-if="wrongpassword">
Falsches Passwort oder Kürzel! Bitte versuche es erneut.
</div>
</form>
</div>
</template>

View File

@@ -0,0 +1,72 @@
<script lang="ts">
import Modal from "../Modal.vue"
export default {
props: {
users: {
type: Array,
required: true
},
spieltag: {
type: Number,
required: false
},
tipps: {
type: Array,
required: true
},
paarungen: {
type: Array,
required: true
}
},
data(){
return {
currentuser: null,
modalOpen: false
}
},
components: {
Modal
}
}
</script>
<template>
<section class="uebersicht scroll-x">
<table>
<tbody>
<tr>
<td v-for="user in users" @click="currentuser=user; modalOpen=true">{{ user.kuerzel }}</td>
</tr>
<tr>
<td v-for="user in users" :style='{"color": user.hatgetippt()?"green":"red"}' @click="currentuser=user; modalOpen=true">{{ user.points }}</td>
</tr>
</tbody>
</table>
</section>
<Modal v-if="modalOpen" @closemodal="modalOpen=false">
<div v-if="spieltag!=undefined">
<h1>Detailansicht für {{ currentuser.username }}, {{ spieltag }}. Spieltag</h1>
<table>
<thead>
<tr>
<td>Paarung</td>
<td>Tipp von {{ currentuser.username }}</td>
</tr>
</thead>
<tbody>
<tr v-for="tipp, i in tipps.filter(t=>t.user==currentuser.id)">
<td>{{ paarungen[i].heim }} - {{ paarungen[i].gast }}</td>
<td>{{ tipp.tipp.heim }} - {{ tipp.tipp.gast }}</td>
</tr>
</tbody>
</table>
</div>
<div v-else>
<h1>Lade...</h1>
</div>
</Modal>
</template>
<style scoped>
@import "../../assets/css/bulitipp2.css";
</style>