AdminPanel erste Funktionen hinzugefügt (Formulare)

This commit is contained in:
R40fendt
2026-01-04 17:58:58 +01:00
parent b94e84ff62
commit f5946b0429
10 changed files with 349 additions and 8 deletions

View File

@@ -8,4 +8,5 @@ Bei der Migration beachten:
- addhit URL in der index.html anpassen - addhit URL in der index.html anpassen
- Event-Datenbank anpassen - Event-Datenbank anpassen
- Neue Formulartabelle - Neue Formulartabelle
- ritzenbergenlib.ts anpassen - .env.production anpassen
- Salt ändern (secret.php in der API)

View File

@@ -1,5 +1,10 @@
import RitzenbergenLib from "./ritzenbergenlib"; import RitzenbergenLib from "./ritzenbergenlib";
import { useRouter } from "vue-router";
class AdminPanelLib { class AdminPanelLib {
router=useRouter();
static async getUserInfo(token:string){ static async getUserInfo(token:string){
const url=new URL(RitzenbergenLib.RitzenbergenLib.api("/admin/userinfo.php")); const url=new URL(RitzenbergenLib.RitzenbergenLib.api("/admin/userinfo.php"));
return fetch(url.toString(), { return fetch(url.toString(), {
@@ -7,7 +12,15 @@ class AdminPanelLib {
"Authorization": "Bearer "+token "Authorization": "Bearer "+token
}, },
}) })
.then((response)=>response.json()); .then((response)=>response.json())
.then((response)=>{
if(response.error){
window.alert(response.error);
return false;
}else{
return response;
}
});
} }
} }

View File

@@ -0,0 +1,36 @@
<script setup lang="ts">
import { useRoute, useRouter } from 'vue-router'
import { ref } from "vue";
import AdminPanelLib from "../../adminpanellib.ts";
import Navbar from "../Navbar.vue";
const route = useRoute();
const router = useRouter();
const token=ref(route.params.token);
const userinfo=ref({})
AdminPanelLib.AdminPanelLib.getUserInfo(token.value)
.then((result)=>{
if(result) return result;
else router.push({"path":"/adminpanel/login"});
})
.then((result)=>userinfo.value=result);
const links=[
{ "title":"Startseite", "link":"/adminpanel/"+token.value },
{ "title":"Formulare", "link":"/adminpanel/"+token.value+"/formulare" },
{ "title":"Events", "link":"/adminpanel/"+token.value+"/events" }
]
function logout(){
router.push({"path":"/adminpanel/login"});
}
</script>
<template>
<Navbar :links="links" buttontext="Abmelden" @clickbtn="logout"/>
</template>
<style scoped lang="scss">
</style>

View File

@@ -0,0 +1,64 @@
<script setup lang="ts">
import { ref, defineProps, computed } from "vue";
const props = defineProps({
modelValue: {
type: [String,Boolean,Number],
default: null,
},
nullable: {
type: Boolean,
default: false,
},
inputtype: {
type: String,
default: "text",
required: false
}
});
const firstValue = props.modelValue;
const isNull = ref(firstValue == null);
const emit = defineEmits(["update:modelValue", "isNull"]);
const value = computed({
get: () => props.modelValue,
set: (v) => {
emit("update:modelValue", v);
},
});
if(value.value==null && props.nullable==false){
isNull.value=false;
value.value="";
}
const editing = ref(false);
</script>
<template>
<form v-if="editing" @submit.prevent="editing = false">
<input
:type="props.inputtype"
:placeholder="firstValue"
v-model="value"
v-if="!isNull"
/>
<label for="nullCheckbox" v-if="nullable">Null: </label>
<input
id="nullCheckbox"
type="checkbox"
v-if="nullable"
@change="value=isNull?null:value"
v-model="isNull"
/>
<input type="submit" value="Speichern" />
</form>
<i v-else-if="value=='' && !isNull && props.inputtype!='checkbox'" @dblclick="editing=true">EMPTY</i>
<p v-else-if="!isNull" @dblclick="editing = true">{{ value }}</p>
<i v-else @dblclick="editing = true">NULL</i>
</template>
<style lang="scss" scoped>
</style>

View File

@@ -185,8 +185,8 @@ class Formular {
el.id, el.id,
el.name, el.name,
el.minitext, el.minitext,
el.public, el.public==null?null:(el.public==1?true:false),
el.multiple el.multiple==null?null:(el.multiple==1?true:false)
) )
) )
); );
@@ -212,12 +212,12 @@ class Formular {
displayvalue: el.displayvalue, displayvalue: el.displayvalue,
placeholder: el.placeholder, placeholder: el.placeholder,
title: el.title, title: el.title,
required: el.required == 1, required: el.required==null?null:(el.required==1?true:false),
maxlength: el.maxlength, maxlength: el.maxlength,
min: el.min, min: el.min,
max: el.max, max: el.max,
multiple: el.multiple == 1, multiple: el.multiple==null?null:(el.multiple==1?true:false),
checked: el.checked == 1, checked: el.checked==null?null:(el.checked==1?true:false),
}) })
) )
); );

View File

@@ -16,6 +16,8 @@ const routes = [
{ path: "/bulitipp/tippen", component: () => import("../views/Bulitipp.vue") }, { path: "/bulitipp/tippen", component: () => import("../views/Bulitipp.vue") },
{ path: "/adminpanel/login", component: () => import("../views/adminpanel/AdminPanelLogin.vue") }, { path: "/adminpanel/login", component: () => import("../views/adminpanel/AdminPanelLogin.vue") },
{ path: "/adminpanel/:token", component: () => import("../views/adminpanel/Main.vue"), name: "adminpanel-main" }, { path: "/adminpanel/:token", component: () => import("../views/adminpanel/Main.vue"), name: "adminpanel-main" },
{ path: "/adminpanel/:token/events", component: () => import("../views/adminpanel/Events.vue"), name: "adminpanel-events" },
{ path: "/adminpanel/:token/formulare", component: () => import("../views/adminpanel/Formulare.vue"), name: "adminpanel-formulare" },
{ path: "/adminpanel", component: () => import("../views/adminpanel/Main.vue") }, { path: "/adminpanel", component: () => import("../views/adminpanel/Main.vue") },
] ]

View File

@@ -25,6 +25,7 @@
const username=ref(""); const username=ref("");
const password=ref(""); const password=ref("");
</script> </script>
<template> <template>
<br> <br>
@@ -32,7 +33,7 @@
<br> <br>
<br> <br>
<br> <br>
<h1>Test</h1> <h1>Admin Panel</h1>
<Navbar/> <Navbar/>
<form @submit.prevent="login()"> <form @submit.prevent="login()">
<input type="text" placeholder="Benutzername" v-model="username"/> <input type="text" placeholder="Benutzername" v-model="username"/>

View File

@@ -0,0 +1,12 @@
<script lang="ts" setup>
import AdminNavbar from "../../components/admin/AdminNavbar.vue";
</script>
<template>
<AdminNavbar/>
<h1>Events</h1>
</template>
<style scoped lang="scss">
</style>

View File

@@ -0,0 +1,208 @@
<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";
const route = useRoute();
const token = ref(route.params.token);
const formulare: RitzenbergenLib.Formular[] = ref([]);
RitzenbergenLib.Formular.getForms().then(
(result) => (formulare.value = result)
);
function saveForm(form) {
console.log(form);
}
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 />
<h1>Formulare</h1>
<div>
<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 />
<br />
</form>
<button class="saveBtn" @click="newForm">Neues Formular</button>
</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 {
text-align: center;
}
</style>

View File

@@ -2,6 +2,7 @@
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
import { ref } from "vue"; import { ref } from "vue";
import AdminPanelLib from "../../adminpanellib.ts"; import AdminPanelLib from "../../adminpanellib.ts";
import AdminNavbar from "../../components/admin/AdminNavbar.vue";
const route = useRoute(); const route = useRoute();
@@ -9,8 +10,11 @@
const userinfo=ref({}) const userinfo=ref({})
AdminPanelLib.AdminPanelLib.getUserInfo(token.value).then((result)=>userinfo.value=result); AdminPanelLib.AdminPanelLib.getUserInfo(token.value).then((result)=>userinfo.value=result);
</script> </script>
<template> <template>
<AdminNavbar/>
<h1>Admin Panel</h1> <h1>Admin Panel</h1>
<h2>Moin {{ userinfo.username }}!</h2> <h2>Moin {{ userinfo.username }}!</h2>
</template> </template>