AdminPanel erste Funktionen hinzugefügt (Formulare)
This commit is contained in:
@@ -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)
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
36
src/components/admin/AdminNavbar.vue
Normal file
36
src/components/admin/AdminNavbar.vue
Normal 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>
|
||||||
64
src/components/admin/InputP.vue
Normal file
64
src/components/admin/InputP.vue
Normal 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>
|
||||||
@@ -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),
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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") },
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -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"/>
|
||||||
|
|||||||
12
src/views/adminpanel/Events.vue
Normal file
12
src/views/adminpanel/Events.vue
Normal 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>
|
||||||
208
src/views/adminpanel/Formulare.vue
Normal file
208
src/views/adminpanel/Formulare.vue
Normal 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>
|
||||||
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user