inital commit
This commit is contained in:
207
src/content/admin/AdminMenuManagement.vue
Normal file
207
src/content/admin/AdminMenuManagement.vue
Normal file
@@ -0,0 +1,207 @@
|
||||
<template>
|
||||
<div class="admin-menu-management">
|
||||
<h2>Menüverwaltung</h2>
|
||||
<div>
|
||||
<h3>Neuen Menüpunkt hinzufügen</h3>
|
||||
<form @submit.prevent="addMenuItem">
|
||||
<label for="name">Name:</label>
|
||||
<input type="text" v-model="newItem.name" required />
|
||||
|
||||
<label for="link">Link:</label>
|
||||
<input type="text" v-model="newItem.link" required />
|
||||
|
||||
<label for="component">Component:</label>
|
||||
<input type="text" v-model="newItem.component" required />
|
||||
|
||||
<label for="showInMenu">Im Menü anzeigen:</label>
|
||||
<input type="checkbox" v-model="newItem.showInMenu" />
|
||||
|
||||
<label for="requiresAuth">Authentifizierung erforderlich:</label>
|
||||
<input type="checkbox" v-model="newItem.requiresAuth" />
|
||||
|
||||
<label for="image">Bild:</label>
|
||||
<input type="text" v-model="newItem.image" />
|
||||
|
||||
<label for="parentId">Eltern-Menüpunkt:</label>
|
||||
<select v-model="newItem.parentId">
|
||||
<option :value="null">Kein Eltern-Menüpunkt</option>
|
||||
<option v-for="item in menuItems" :key="item.id" :value="item.id">
|
||||
{{ item.name }}
|
||||
</option>
|
||||
</select>
|
||||
|
||||
<button type="submit">Hinzufügen</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3>Menüpunkte bearbeiten</h3>
|
||||
<ul>
|
||||
<li v-for="item in menuItems" :key="item.id">
|
||||
{{ item.name }}
|
||||
<button @click="editMenuItem(item)">Bearbeiten</button>
|
||||
<button @click="deleteMenuItem(item.id)">Löschen</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div v-if="editingItem">
|
||||
<h3>Menüpunkt bearbeiten</h3>
|
||||
<form @submit.prevent="updateMenuItem">
|
||||
<label for="editName">Name:</label>
|
||||
<input type="text" v-model="editingItem.name" required />
|
||||
|
||||
<label for="editLink">Link:</label>
|
||||
<input type="text" v-model="editingItem.link" required />
|
||||
|
||||
<label for="editComponent">Component:</label>
|
||||
<input type="text" v-model="editingItem.component" required />
|
||||
|
||||
<label for="editShowInMenu">Im Menü anzeigen:</label>
|
||||
<input type="checkbox" v-model="editingItem.showInMenu" />
|
||||
|
||||
<label for="editRequiresAuth">Authentifizierung erforderlich:</label>
|
||||
<input type="checkbox" v-model="editingItem.requiresAuth" />
|
||||
|
||||
<label for="editImage">Bild:</label>
|
||||
<input type="text" v-model="editingItem.image" />
|
||||
|
||||
<label for="editParentId">Eltern-Menüpunkt:</label>
|
||||
<select v-model="editingItem.parentId">
|
||||
<option :value="null">Kein Eltern-Menüpunkt</option>
|
||||
<option v-for="item in menuItems" :key="item.id" :value="item.id">
|
||||
{{ item.name }}
|
||||
</option>
|
||||
</select>
|
||||
|
||||
<button type="submit">Aktualisieren</button>
|
||||
<button @click="cancelEdit">Abbrechen</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { mapState, mapActions } from 'vuex';
|
||||
|
||||
export default {
|
||||
name: 'AdminMenuManagement',
|
||||
data() {
|
||||
return {
|
||||
newItem: {
|
||||
name: '',
|
||||
link: '',
|
||||
component: '',
|
||||
showInMenu: false,
|
||||
requiresAuth: false,
|
||||
image: '',
|
||||
parentId: null
|
||||
},
|
||||
editingItem: null
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState(['menuData']),
|
||||
menuItems() {
|
||||
return this.menuData;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions(['loadMenuData']),
|
||||
async addMenuItem() {
|
||||
this.menuData.push(this.newItem);
|
||||
await this.saveMenuData();
|
||||
this.resetNewItem();
|
||||
},
|
||||
editMenuItem(item) {
|
||||
this.editingItem = { ...item };
|
||||
},
|
||||
async updateMenuItem() {
|
||||
const index = this.menuData.findIndex(item => item.id === this.editingItem.id);
|
||||
if (index !== -1) {
|
||||
this.menuData.splice(index, 1, this.editingItem);
|
||||
await this.saveMenuData();
|
||||
this.cancelEdit();
|
||||
}
|
||||
},
|
||||
async deleteMenuItem(id) {
|
||||
this.menuData = this.menuData.filter(item => item.id !== id);
|
||||
await this.saveMenuData();
|
||||
},
|
||||
cancelEdit() {
|
||||
this.editingItem = null;
|
||||
},
|
||||
resetNewItem() {
|
||||
this.newItem = {
|
||||
name: '',
|
||||
link: '',
|
||||
component: '',
|
||||
showInMenu: false,
|
||||
requiresAuth: false,
|
||||
image: '',
|
||||
parentId: null
|
||||
};
|
||||
},
|
||||
async saveMenuData() {
|
||||
try {
|
||||
await fetch('http://localhost:3000/api/menu-data', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(this.menuData)
|
||||
});
|
||||
await this.loadMenuData();
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Speichern der Menü-Daten:', error);
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadMenuData();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.admin-menu-management {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
form {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
form label {
|
||||
display: block;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
form input,
|
||||
form select {
|
||||
width: 100%;
|
||||
padding: 5px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
button {
|
||||
margin-top: 10px;
|
||||
padding: 5px 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
li {
|
||||
margin: 10px 0;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
li button {
|
||||
margin-left: 10px;
|
||||
}
|
||||
</style>
|
||||
|
||||
12
src/content/admin/AdminWorshipService.vue
Normal file
12
src/content/admin/AdminWorshipService.vue
Normal file
@@ -0,0 +1,12 @@
|
||||
<template>
|
||||
<div>
|
||||
<h2></h2>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'AdminWorshipService',
|
||||
};
|
||||
</script>
|
||||
|
||||
83
src/content/admin/ContactPersonManagement.vue
Normal file
83
src/content/admin/ContactPersonManagement.vue
Normal file
@@ -0,0 +1,83 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>Kontaktpersonen Verwaltung</h1>
|
||||
<ContactPersonForm
|
||||
:contactPerson="selectedContactPerson"
|
||||
:positions="positions"
|
||||
@contactPersonSaved="fetchContactPersons"
|
||||
/>
|
||||
<ul>
|
||||
<li v-for="contactPerson in contactPersons" :key="contactPerson.id" @click="selectContactPerson(contactPerson)">
|
||||
{{ contactPerson.name }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios';
|
||||
import ContactPersonForm from '../../components/ContactPersonForm.vue';
|
||||
|
||||
export default {
|
||||
name: 'ContactPersonManagement',
|
||||
components: {
|
||||
ContactPersonForm
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
contactPersons: [],
|
||||
selectedContactPerson: {
|
||||
name: '',
|
||||
phone: '',
|
||||
street: '',
|
||||
zipcode: '',
|
||||
city: '',
|
||||
email: '',
|
||||
positions: []
|
||||
},
|
||||
positions: []
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.fetchContactPersons();
|
||||
this.fetchPositions();
|
||||
},
|
||||
methods: {
|
||||
async fetchContactPersons() {
|
||||
try {
|
||||
const response = await axios.get('http://localhost:3000/api/contact-persons');
|
||||
this.contactPersons = response.data;
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Abrufen der Kontaktpersonen:', error);
|
||||
}
|
||||
},
|
||||
async fetchPositions() {
|
||||
try {
|
||||
const response = await axios.get('http://localhost:3000/api/positions');
|
||||
this.positions = response.data;
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Abrufen der Positionen:', error);
|
||||
}
|
||||
},
|
||||
selectContactPerson(contactPerson) {
|
||||
this.selectedContactPerson = contactPerson;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
ul {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
}
|
||||
li {
|
||||
cursor: pointer;
|
||||
padding: 5px;
|
||||
margin: 5px 0;
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
li:hover {
|
||||
background-color: #e0e0e0;
|
||||
}
|
||||
</style>
|
||||
202
src/content/admin/EditPagesComponent.vue
Normal file
202
src/content/admin/EditPagesComponent.vue
Normal file
@@ -0,0 +1,202 @@
|
||||
<template>
|
||||
<div class="edit-pages">
|
||||
<h2>Webseiten bearbeiten</h2>
|
||||
<div>
|
||||
<label for="page-select">Wähle eine Seite:</label>
|
||||
<select id="page-select" v-model="selectedPage" @change="loadPageContent">
|
||||
<option v-for="page in pages" :key="page.link" :value="page.link">{{ page.name }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="toolbar">
|
||||
<button @click="editor.chain().focus().toggleHeading({ level: 1 }).run()">H1</button>
|
||||
<button @click="editor.chain().focus().toggleHeading({ level: 2 }).run()">H2</button>
|
||||
<button @click="editor.chain().focus().toggleHeading({ level: 3 }).run()">H3</button>
|
||||
<button @click="editor.chain().focus().toggleBold().run()">Fett</button>
|
||||
<button @click="editor.chain().focus().toggleItalic().run()">Kursiv</button>
|
||||
<button @click="editor.chain().focus().toggleUnderline().run()">Unterstrichen</button>
|
||||
<button @click="editor.chain().focus().toggleStrike().run()">Durchgestrichen</button>
|
||||
<button
|
||||
@click="editor.chain().focus().insertTable({ rows: 3, cols: 3, withHeaderRow: true }).run()">Tabelle</button>
|
||||
<button @click="editor.chain().focus().toggleBulletList().run()">Liste</button>
|
||||
<button @click="editor.chain().focus().toggleOrderedList().run()">Nummerierte Liste</button>
|
||||
</div>
|
||||
<div class="table-toolbar">
|
||||
<button @click="editor.chain().focus().addColumnBefore().run()">Spalte davor einfügen</button>
|
||||
<button @click="editor.chain().focus().addColumnAfter().run()">Spalte danach einfügen</button>
|
||||
<button @click="editor.chain().focus().addRowBefore().run()">Zeile davor einfügen</button>
|
||||
<button @click="editor.chain().focus().addRowAfter().run()">Zeile danach einfügen</button>
|
||||
<button @click="editor.chain().focus().deleteColumn().run()">Spalte löschen</button>
|
||||
<button @click="editor.chain().focus().deleteRow().run()">Zeile löschen</button>
|
||||
<button @click="editor.chain().focus().toggleHeaderColumn().run()">Header-Spalte umschalten</button>
|
||||
<button @click="editor.chain().focus().toggleHeaderRow().run()">Header-Zeile umschalten</button>
|
||||
<button @click="editor.chain().focus().toggleHeaderCell().run()">Header-Zelle umschalten</button>
|
||||
</div>
|
||||
<div class="additional-toolbar">
|
||||
<button>Events</button>
|
||||
<button>Kontaktpersonen</button>
|
||||
<button>Institutionen</button>
|
||||
<button>Gottesdienste</button>
|
||||
</div>
|
||||
<div :class="['htmleditor']">
|
||||
<EditorContent :editor="editor" />
|
||||
</div>
|
||||
<button @click="savePageContent">Speichern</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref, computed, onMounted } from 'vue';
|
||||
import { useStore } from 'vuex';
|
||||
import axios from '../../axios';
|
||||
import { EditorContent, useEditor } from '@tiptap/vue-3';
|
||||
import StarterKit from '@tiptap/starter-kit';
|
||||
import Table from '@tiptap/extension-table';
|
||||
import TableRow from '@tiptap/extension-table-row';
|
||||
import Bold from '@tiptap/extension-bold';
|
||||
import Italic from '@tiptap/extension-italic';
|
||||
import Underline from '@tiptap/extension-underline';
|
||||
import Strike from '@tiptap/extension-strike';
|
||||
import BulletList from '@tiptap/extension-bullet-list';
|
||||
import OrderedList from '@tiptap/extension-ordered-list';
|
||||
import Heading from '@tiptap/extension-heading';
|
||||
import { CustomTableCell, CustomTableHeader } from '../../extensions/CustomTableCell'; // Importiere die angepasste Erweiterung
|
||||
|
||||
export default {
|
||||
name: 'EditPagesComponent',
|
||||
components: {
|
||||
EditorContent,
|
||||
},
|
||||
setup() {
|
||||
const store = useStore();
|
||||
const pages = ref([]);
|
||||
const selectedPage = ref('');
|
||||
const pageHtmlContent = computed(() => store.state.pageContent);
|
||||
|
||||
const editor = useEditor({
|
||||
extensions: [
|
||||
StarterKit,
|
||||
Table.configure({
|
||||
resizable: true,
|
||||
}),
|
||||
TableRow,
|
||||
CustomTableCell,
|
||||
CustomTableHeader,
|
||||
Bold,
|
||||
Italic,
|
||||
Underline,
|
||||
Strike,
|
||||
BulletList,
|
||||
OrderedList,
|
||||
Heading.configure({
|
||||
levels: [1, 2, 3],
|
||||
}),
|
||||
],
|
||||
content: '',
|
||||
onUpdate: ({ editor }) => {
|
||||
store.commit('UPDATE_PAGE_CONTENT', editor.getHTML());
|
||||
},
|
||||
});
|
||||
|
||||
const fetchPages = async () => {
|
||||
try {
|
||||
const response = await axios.get('http://localhost:3000/api/menu-data');
|
||||
pages.value = response.data;
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Abrufen der Seiten:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const loadPageContent = async () => {
|
||||
try {
|
||||
await store.dispatch('loadPageContent', selectedPage.value);
|
||||
const content = store.getters.pageContent;
|
||||
|
||||
const setEditorContent = () => {
|
||||
if (editor.value && editor.value.commands) {
|
||||
editor.value.commands.setContent(content, false);
|
||||
} else {
|
||||
setTimeout(setEditorContent, 100); // Try again after 100ms if not ready
|
||||
}
|
||||
};
|
||||
|
||||
setEditorContent();
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Laden des Seiteninhalts:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const savePageContent = async () => {
|
||||
try {
|
||||
const selectedPageName = pages.value.find(page => page.link === selectedPage.value)?.name || '';
|
||||
if (!selectedPageName) {
|
||||
return;
|
||||
}
|
||||
|
||||
const contentToSave = editor.value.getHTML();
|
||||
store.commit('SET_PAGE_CONTENT', contentToSave);
|
||||
|
||||
await store.dispatch('savePageContent', {
|
||||
link: selectedPage.value,
|
||||
name: selectedPageName,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Speichern des Seiteninhalts:', error);
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(fetchPages);
|
||||
|
||||
return {
|
||||
pages,
|
||||
selectedPage,
|
||||
editor,
|
||||
loadPageContent,
|
||||
savePageContent,
|
||||
pageHtmlContent,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.edit-pages {
|
||||
width: 100%;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
#page-select {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.toolbar {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.toolbar button {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.table-toolbar {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.table-toolbar button {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.additional-toolbar {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.additional-toolbar button {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.ql-container {
|
||||
background-color: #fff !important;
|
||||
}
|
||||
|
||||
.ql-editor {
|
||||
background-color: #fff !important;
|
||||
}
|
||||
</style>
|
||||
144
src/content/admin/EventManagement.vue
Normal file
144
src/content/admin/EventManagement.vue
Normal file
@@ -0,0 +1,144 @@
|
||||
<template>
|
||||
<div class="event-management">
|
||||
<h2>Veranstaltungen</h2>
|
||||
<button @click="createEvent">Neue Veranstaltung</button>
|
||||
<EventForm v-if="showForm"
|
||||
:event="selectedEvent"
|
||||
:institutions="institutions"
|
||||
:eventPlaces="eventPlaces"
|
||||
:contactPersons="contactPersons"
|
||||
@saved="handleEventSaved"
|
||||
@cancelled="handleEventCancelled" />
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Typ</th>
|
||||
<th>Datum</th>
|
||||
<th>Uhrzeit</th>
|
||||
<th>Wochentag</th>
|
||||
<th>Beschreibung</th>
|
||||
<th>Aktionen</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="event in events" :key="event.id">
|
||||
<td>{{ event.name }}</td>
|
||||
<td>{{ getEventTypeCaption(event.eventTypeId) }}</td>
|
||||
<td>{{ event.date }}</td>
|
||||
<td>{{ formatTime(event.time) }}<span v-if="event.endTime"> - {{ formatTime(event.endTime) }}</span></td>
|
||||
<td>{{ getWeekdayName(event.dayOfWeek) }}</td>
|
||||
<td>{{ event.description }}</td>
|
||||
<td>
|
||||
<button @click="editEvent(event)">Bearbeiten</button>
|
||||
<button @click="deleteEvent(event.id)">Löschen</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios';
|
||||
import EventForm from '@/components/EventForm.vue';
|
||||
import { formatTime } from '../../utils/strings';
|
||||
|
||||
export default {
|
||||
components: { EventForm },
|
||||
data() {
|
||||
return {
|
||||
events: [],
|
||||
institutions: [],
|
||||
eventPlaces: [],
|
||||
contactPersons: [],
|
||||
eventTypes: [],
|
||||
selectedEvent: null,
|
||||
showForm: false,
|
||||
};
|
||||
},
|
||||
async created() {
|
||||
await this.fetchData();
|
||||
},
|
||||
methods: {
|
||||
formatTime,
|
||||
async fetchData() {
|
||||
try {
|
||||
const [eventResponse, institutionResponse, eventPlaceResponse, contactPersonResponse, eventTypeResponse] = await Promise.all([
|
||||
axios.get('http://localhost:3000/api/events'),
|
||||
axios.get('http://localhost:3000/api/institutions'),
|
||||
axios.get('http://localhost:3000/api/event-places'),
|
||||
axios.get('http://localhost:3000/api/contact-persons'),
|
||||
axios.get('http://localhost:3000/api/event-types')
|
||||
]);
|
||||
|
||||
this.events = eventResponse.data;
|
||||
this.institutions = institutionResponse.data;
|
||||
this.eventPlaces = eventPlaceResponse.data;
|
||||
this.contactPersons = contactPersonResponse.data;
|
||||
this.eventTypes = eventTypeResponse.data;
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Abrufen der Daten:', error);
|
||||
}
|
||||
},
|
||||
createEvent() {
|
||||
this.selectedEvent = {};
|
||||
this.showForm = true;
|
||||
},
|
||||
editEvent(event) {
|
||||
this.selectedEvent = { ...event };
|
||||
this.showForm = true;
|
||||
},
|
||||
async deleteEvent(id) {
|
||||
try {
|
||||
await axios.delete(`http://localhost:3000/api/events/${id}`);
|
||||
this.fetchData();
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Löschen der Veranstaltung:', error);
|
||||
}
|
||||
},
|
||||
handleEventSaved() {
|
||||
this.showForm = false;
|
||||
this.fetchData();
|
||||
},
|
||||
handleEventCancelled() {
|
||||
this.showForm = false;
|
||||
},
|
||||
getEventTypeCaption(eventTypeId) {
|
||||
const eventType = this.eventTypes.find(type => type.id === eventTypeId);
|
||||
return eventType ? eventType.caption : 'Unbekannt';
|
||||
},
|
||||
getWeekdayName(dayOfWeek) {
|
||||
const weekdays = ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'];
|
||||
return weekdays[dayOfWeek - 1];
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.event-management {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
th,
|
||||
td {
|
||||
border: 1px solid #ddd;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
th {
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
|
||||
button {
|
||||
margin: 5px;
|
||||
}
|
||||
</style>
|
||||
147
src/content/admin/EventPlacesManagement.vue
Normal file
147
src/content/admin/EventPlacesManagement.vue
Normal file
@@ -0,0 +1,147 @@
|
||||
<template>
|
||||
<div class="event-places-management">
|
||||
<h2>Veranstaltungsorte verwalten</h2>
|
||||
<form @submit.prevent="addEventPlace">
|
||||
<label for="name">Name:</label>
|
||||
<input type="text" id="name" v-model="newEventPlace.name" placeholder="Name" required>
|
||||
<label for="street">Straße:</label>
|
||||
<input type="text" id="street" v-model="newEventPlace.street" placeholder="Straße" required>
|
||||
<label for="zipcode">PLZ:</label>
|
||||
<input type="text" id="zipcode" v-model="newEventPlace.zipcode" placeholder="PLZ" required>
|
||||
<label for="city">Stadt:</label>
|
||||
<input type="text" id="city" v-model="newEventPlace.city" placeholder="Stadt" required>
|
||||
<label for="backgroundColor">Hintergrundfarbe:</label>
|
||||
<input type="color" id="backgroundColor" v-model="newEventPlace.backgroundColor">
|
||||
<button type="submit">Speichern</button>
|
||||
<button type="button" v-if="editMode" @click="resetForm">Neuen Veranstaltungsort erstellen</button>
|
||||
</form>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Bearbeiten</th>
|
||||
<th>Löschen</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="eventPlace in eventPlaces" :key="eventPlace.id">
|
||||
<td>{{ eventPlace.name }}</td>
|
||||
<td><button @click="editEventPlace(eventPlace)">Bearbeiten</button></td>
|
||||
<td><button @click="deleteEventPlace(eventPlace.id)">Löschen</button></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
eventPlaces: [],
|
||||
newEventPlace: {
|
||||
name: '',
|
||||
street: '',
|
||||
zipcode: '',
|
||||
city: '',
|
||||
backgroundColor: '#ffffff'
|
||||
},
|
||||
editMode: false,
|
||||
editId: null
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
async fetchEventPlaces() {
|
||||
const response = await axios.get('http://localhost:3000/api/event-places');
|
||||
this.eventPlaces = response.data;
|
||||
},
|
||||
async addEventPlace() {
|
||||
if (this.editMode) {
|
||||
await axios.put(`http://localhost:3000/api/event-places/${this.editId}`, this.newEventPlace);
|
||||
} else {
|
||||
const response = await axios.post('http://localhost:3000/api/event-places', this.newEventPlace);
|
||||
this.eventPlaces.push(response.data);
|
||||
}
|
||||
this.resetForm();
|
||||
await this.fetchEventPlaces();
|
||||
},
|
||||
async updateEventPlace(eventPlace) {
|
||||
await axios.put(`http://localhost:3000/api/event-places/${eventPlace.id}`, eventPlace);
|
||||
this.fetchEventPlaces(); // Refresh the list
|
||||
},
|
||||
async deleteEventPlace(id) {
|
||||
await axios.delete(`http://localhost:3000/api/event-places/${id}`);
|
||||
this.fetchEventPlaces(); // Refresh the list
|
||||
},
|
||||
editEventPlace(eventPlace) {
|
||||
this.newEventPlace = { ...eventPlace };
|
||||
this.editMode = true;
|
||||
this.editId = eventPlace.id;
|
||||
},
|
||||
resetForm() {
|
||||
this.newEventPlace = {
|
||||
name: '',
|
||||
street: '',
|
||||
zipcode: '',
|
||||
city: '',
|
||||
backgroundColor: '#ffffff'
|
||||
};
|
||||
this.editMode = false;
|
||||
this.editId = null;
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.fetchEventPlaces();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.event-places-management {
|
||||
max-width: 600px;
|
||||
margin: auto;
|
||||
padding: 20px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
label {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
input {
|
||||
margin-top: 5px;
|
||||
margin-bottom: 10px;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
button {
|
||||
margin-top: 10px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
th, td {
|
||||
border: 1px solid #ccc;
|
||||
padding: 10px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
th {
|
||||
background-color: #f4f4f4;
|
||||
}
|
||||
</style>
|
||||
132
src/content/admin/EventTypesManagement.vue
Normal file
132
src/content/admin/EventTypesManagement.vue
Normal file
@@ -0,0 +1,132 @@
|
||||
<template>
|
||||
<div class="event-types-management">
|
||||
<h2>Event-Typen Verwaltung</h2>
|
||||
<form @submit.prevent="saveEventType">
|
||||
<label for="newEventType">Event-Typ:</label>
|
||||
<input type="text" id="newEventType" v-model="eventTypeData.caption" placeholder="Event-Typ" required>
|
||||
<button type="submit">{{ editMode ? 'Aktualisieren' : 'Hinzufügen' }}</button>
|
||||
<button type="button" v-if="editMode" @click="resetForm">Abbrechen</button>
|
||||
</form>
|
||||
|
||||
<table>
|
||||
<tr v-for="eventType in eventTypes" :key="eventType.id">
|
||||
<td>{{ eventType.caption }}</td>
|
||||
<td><button @click="editEventType(eventType)">Bearbeiten</button></td>
|
||||
<td><button @click="deleteEventType(eventType.id)">Löschen</button></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
eventTypes: [],
|
||||
eventTypeData: {
|
||||
caption: ''
|
||||
},
|
||||
editMode: false,
|
||||
editId: null
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
async fetchEventTypes() {
|
||||
try {
|
||||
const response = await axios.get('http://localhost:3000/api/event-types');
|
||||
this.eventTypes = response.data;
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Abrufen der Event-Typen:', error);
|
||||
}
|
||||
},
|
||||
async saveEventType() {
|
||||
try {
|
||||
if (this.editMode) {
|
||||
await axios.put(`http://localhost:3000/api/event-types/${this.editId}`, this.eventTypeData);
|
||||
} else {
|
||||
const response = await axios.post('http://localhost:3000/api/event-types', this.eventTypeData);
|
||||
this.eventTypes.push(response.data);
|
||||
}
|
||||
this.resetForm();
|
||||
await this.fetchEventTypes();
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Speichern des Event-Typs:', error);
|
||||
}
|
||||
},
|
||||
editEventType(eventType) {
|
||||
this.eventTypeData = { ...eventType };
|
||||
this.editMode = true;
|
||||
this.editId = eventType.id;
|
||||
},
|
||||
async deleteEventType(id) {
|
||||
try {
|
||||
await axios.delete(`http://localhost:3000/api/event-types/${id}`);
|
||||
await this.fetchEventTypes();
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Löschen des Event-Typs:', error);
|
||||
}
|
||||
},
|
||||
resetForm() {
|
||||
this.eventTypeData = {
|
||||
caption: ''
|
||||
};
|
||||
this.editMode = false;
|
||||
this.editId = null;
|
||||
}
|
||||
},
|
||||
async created() {
|
||||
await this.fetchEventTypes();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@import 'vue-multiselect/dist/vue-multiselect.css';
|
||||
|
||||
.event-types-management {
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
label {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
input {
|
||||
margin-top: 10px;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
button {
|
||||
margin-top: 20px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
ul {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
li {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 10px;
|
||||
border-bottom: 1px solid rgba(224, 224, 224, 0.9);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
button {
|
||||
margin-left: 10px;
|
||||
}
|
||||
</style>
|
||||
|
||||
19
src/content/admin/IndexContent.vue
Normal file
19
src/content/admin/IndexContent.vue
Normal file
@@ -0,0 +1,19 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>Administration</h1>
|
||||
<p>Hier kommt eine Navigation hin.</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'DefaultComponent'
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
div {
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
||||
|
||||
189
src/content/admin/InstitutionManagement.vue
Normal file
189
src/content/admin/InstitutionManagement.vue
Normal file
@@ -0,0 +1,189 @@
|
||||
<template>
|
||||
<div class="institution-management">
|
||||
<h2>Institutionenverwaltung</h2>
|
||||
<form @submit.prevent="saveInstitution">
|
||||
<label for="name">Name:</label>
|
||||
<input type="text" id="name" v-model="institutionData.name" required>
|
||||
|
||||
<label for="street">Straße:</label>
|
||||
<input type="text" id="street" v-model="institutionData.street">
|
||||
|
||||
<label for="zipcode">PLZ:</label>
|
||||
<input type="text" id="zipcode" v-model="institutionData.zipcode">
|
||||
|
||||
<label for="city">Stadt:</label>
|
||||
<input type="text" id="city" v-model="institutionData.city">
|
||||
|
||||
<label for="phone">Telefon:</label>
|
||||
<input type="text" id="phone" v-model="institutionData.phone">
|
||||
|
||||
<label for="fax">Fax:</label>
|
||||
<input type="text" id="fax" v-model="institutionData.fax">
|
||||
|
||||
<label for="email">Email:</label>
|
||||
<input type="email" id="email" v-model="institutionData.email">
|
||||
|
||||
<button type="submit">Speichern</button>
|
||||
<button type="button" @click="resetForm" v-if="editMode">Neue Institution erstellen</button>
|
||||
</form>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Bearbeiten</th>
|
||||
<th>Löschen</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="institution in institutions" :key="institution.id">
|
||||
<td>{{ institution.name }}</td>
|
||||
<td><button @click="editInstitution(institution)">Bearbeiten</button></td>
|
||||
<td><button @click="deleteInstitution(institution.id)">Löschen</button></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios';
|
||||
|
||||
export default {
|
||||
name: 'InstitutionManagement',
|
||||
data() {
|
||||
return {
|
||||
institutions: [],
|
||||
contactPersons: [],
|
||||
institutionData: {
|
||||
name: '',
|
||||
street: '',
|
||||
zipcode: '',
|
||||
city: '',
|
||||
phone: '',
|
||||
fax: '',
|
||||
email: ''
|
||||
},
|
||||
selectedInstitution: null,
|
||||
showForm: false,
|
||||
editMode: false,
|
||||
editId: null
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.fetchInstitutions();
|
||||
this.fetchContactPersons();
|
||||
},
|
||||
methods: {
|
||||
async fetchInstitutions() {
|
||||
try {
|
||||
const response = await axios.get('http://localhost:3000/api/institutions');
|
||||
this.institutions = response.data;
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Abrufen der Institutionen:', error);
|
||||
}
|
||||
},
|
||||
async fetchContactPersons() {
|
||||
try {
|
||||
const response = await axios.get('http://localhost:3000/api/contact-persons');
|
||||
this.contactPersons = response.data;
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Abrufen der Kontaktpersonen:', error);
|
||||
}
|
||||
},
|
||||
async saveInstitution() {
|
||||
try {
|
||||
if (this.editMode) {
|
||||
await axios.put(`http://localhost:3000/api/institutions/${this.editId}`, this.institutionData);
|
||||
} else {
|
||||
const response = await axios.post('http://localhost:3000/api/institutions', this.institutionData);
|
||||
this.institutions.push(response.data);
|
||||
}
|
||||
this.resetForm();
|
||||
await this.fetchInstitutions();
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Speichern der Institution:', error);
|
||||
}
|
||||
},
|
||||
editInstitution(institution) {
|
||||
this.institutionData = { ...institution };
|
||||
this.editMode = true;
|
||||
this.editId = institution.id;
|
||||
this.showForm = true;
|
||||
},
|
||||
async deleteInstitution(id) {
|
||||
try {
|
||||
await axios.delete(`http://localhost:3000/api/institutions/${id}`);
|
||||
this.fetchInstitutions();
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Löschen der Institution:', error);
|
||||
}
|
||||
},
|
||||
resetForm() {
|
||||
this.institutionData = {
|
||||
name: '',
|
||||
street: '',
|
||||
zipcode: '',
|
||||
city: '',
|
||||
phone: '',
|
||||
fax: '',
|
||||
email: ''
|
||||
};
|
||||
this.editMode = false;
|
||||
this.editId = null;
|
||||
this.showForm = false;
|
||||
},
|
||||
showCreateForm() {
|
||||
this.resetForm();
|
||||
this.showForm = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.institution-management {
|
||||
max-width: 600px;
|
||||
margin: auto;
|
||||
padding: 20px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
label {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
input {
|
||||
margin-top: 5px;
|
||||
margin-bottom: 10px;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
button {
|
||||
margin-top: 10px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
th, td {
|
||||
border: 1px solid #ccc;
|
||||
padding: 10px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
th {
|
||||
background-color: #f4f4f4;
|
||||
}
|
||||
</style>
|
||||
35
src/content/admin/PagePreviewComponent.vue
Normal file
35
src/content/admin/PagePreviewComponent.vue
Normal file
@@ -0,0 +1,35 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="previewinfo">Dies ist eine Vorschau.</div>
|
||||
<div v-html="content"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { computed } from 'vue';
|
||||
import { useStore } from 'vuex';
|
||||
|
||||
export default {
|
||||
name: 'PagePreview',
|
||||
setup() {
|
||||
const store = useStore();
|
||||
const content = computed(() => store.state.pageContent);
|
||||
|
||||
return {
|
||||
content,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.previewinfo {
|
||||
background-color: black;
|
||||
color: #d00000;
|
||||
position: absolute;
|
||||
top: 93px;
|
||||
left: 0;
|
||||
padding: 2px 10px;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
131
src/content/admin/PositionManagement.vue
Normal file
131
src/content/admin/PositionManagement.vue
Normal file
@@ -0,0 +1,131 @@
|
||||
<template>
|
||||
<div class="position-management">
|
||||
<h2>Verwalten der Rollen</h2>
|
||||
<form @submit.prevent="addPosition">
|
||||
<label for="caption">Rollenbezeichnung:</label>
|
||||
<input type="text" id="caption" v-model="newPosition.caption" placeholder="Rollenbezeichnung" required>
|
||||
<button type="submit">Speichern</button>
|
||||
<button type="button" v-if="editMode" @click="resetForm">Neue Rolle erstellen</button>
|
||||
</form>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Rollenbezeichnung</th>
|
||||
<th>Bearbeiten</th>
|
||||
<th>Löschen</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="position in positions" :key="position.id">
|
||||
<td>{{ position.caption }}</td>
|
||||
<td><button @click="editPosition(position)">Bearbeiten</button></td>
|
||||
<td><button @click="deletePosition(position.id)">Löschen</button></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
positions: [],
|
||||
newPosition: {
|
||||
caption: ''
|
||||
},
|
||||
editMode: false,
|
||||
editId: null
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
async fetchPositions() {
|
||||
const response = await axios.get('http://localhost:3000/api/positions');
|
||||
this.positions = response.data;
|
||||
},
|
||||
async addPosition() {
|
||||
if (this.editMode) {
|
||||
await axios.put(`http://localhost:3000/api/positions/${this.editId}`, this.newPosition);
|
||||
} else {
|
||||
const response = await axios.post('http://localhost:3000/api/positions', this.newPosition);
|
||||
this.positions.push(response.data);
|
||||
}
|
||||
this.resetForm();
|
||||
await this.fetchPositions();
|
||||
},
|
||||
async updatePosition(position) {
|
||||
await axios.put(`http://localhost:3000/api/positions/${position.id}`, position);
|
||||
this.fetchPositions(); // Refresh the list
|
||||
},
|
||||
async deletePosition(id) {
|
||||
await axios.delete(`http://localhost:3000/api/positions/${id}`);
|
||||
this.fetchPositions(); // Refresh the list
|
||||
},
|
||||
editPosition(position) {
|
||||
this.newPosition = { ...position };
|
||||
this.editMode = true;
|
||||
this.editId = position.id;
|
||||
},
|
||||
resetForm() {
|
||||
this.newPosition = {
|
||||
caption: ''
|
||||
};
|
||||
this.editMode = false;
|
||||
this.editId = null;
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.fetchPositions();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.position-management {
|
||||
max-width: 600px;
|
||||
margin: auto;
|
||||
padding: 20px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
label {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
input {
|
||||
margin-top: 5px;
|
||||
margin-bottom: 10px;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
button {
|
||||
margin-top: 10px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
th, td {
|
||||
border: 1px solid #ccc;
|
||||
padding: 10px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
th {
|
||||
background-color: #f4f4f4;
|
||||
}
|
||||
</style>
|
||||
228
src/content/admin/WorshipManagement.vue
Normal file
228
src/content/admin/WorshipManagement.vue
Normal file
@@ -0,0 +1,228 @@
|
||||
<template>
|
||||
<div class="worship-management">
|
||||
<h2>Gottesdienst Verwaltung</h2>
|
||||
<form @submit.prevent="saveWorship">
|
||||
<label for="eventPlaceId">Veranstaltungsort:</label>
|
||||
<multiselect v-model="selectedEventPlace" :options="eventPlaces" label="name" track-by="id"
|
||||
placeholder="Veranstaltungsort wählen"></multiselect>
|
||||
|
||||
<label for="date">Datum:</label>
|
||||
<input type="date" id="date" v-model="worshipData.date" required>
|
||||
|
||||
<label for="time">Uhrzeit:</label>
|
||||
<input type="time" id="time" v-model="worshipData.time" required>
|
||||
|
||||
<label for="title">Titel:</label>
|
||||
<input type="text" id="title" v-model="worshipData.title" required>
|
||||
|
||||
<label for="organizer">Gestalter:</label>
|
||||
<input type="text" id="organizer" v-model="worshipData.organizer">
|
||||
|
||||
<label for="collection">Kollekte:</label>
|
||||
<input type="text" id="collection" v-model="worshipData.collection">
|
||||
|
||||
<label for="address">Adresse:</label>
|
||||
<input type="text" id="address" v-model="worshipData.address">
|
||||
|
||||
<label for="selfInformation">Selbstinformation:</label>
|
||||
<input type="checkbox" id="selfInformation" v-model="worshipData.selfInformation">
|
||||
|
||||
<label for="highlightTime">Uhrzeit hervorheben:</label>
|
||||
<input type="checkbox" id="highlightTime" v-model="worshipData.highlightTime">
|
||||
|
||||
<label for="neighborInvitation">Einladung zum Nachbarschaftsraum:</label>
|
||||
<input type="checkbox" id="neighborInvitation" v-model="worshipData.neighborInvitation">
|
||||
|
||||
<label for="introLine">Einleitungszeile:</label>
|
||||
<input type="text" id="introLine" v-model="worshipData.introLine">
|
||||
|
||||
<button type="submit">Speichern</button>
|
||||
<button type="button" @click="resetForm">Neuer Gottesdienst</button>
|
||||
</form>
|
||||
|
||||
<ul>
|
||||
<li v-for="worship in worships" :key="worship.id">
|
||||
<span>{{ worship.title }} - {{ formatDate(worship.date) }}, {{ formatTime(worship.time) }}</span>
|
||||
<button @click="editWorship(worship)">Bearbeiten</button>
|
||||
<button @click="deleteWorship(worship.id)">Löschen</button>
|
||||
<div class="tooltip">{{ getEventPlaceName(worship.eventPlaceId) }}</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios';
|
||||
import Multiselect from 'vue-multiselect';
|
||||
import { formatTime, formatDate } from '../../utils/strings'; // Importieren der Methode
|
||||
|
||||
export default {
|
||||
name: 'WorshipManagement',
|
||||
components: { Multiselect },
|
||||
data() {
|
||||
return {
|
||||
worships: [],
|
||||
eventPlaces: [],
|
||||
worshipData: {
|
||||
eventPlaceId: null,
|
||||
date: '',
|
||||
time: '',
|
||||
title: '',
|
||||
organizer: '',
|
||||
collection: '',
|
||||
address: '',
|
||||
selfInformation: false,
|
||||
highlightTime: false,
|
||||
neighborInvitation: false,
|
||||
introLine: ''
|
||||
},
|
||||
selectedEventPlace: null,
|
||||
editMode: false,
|
||||
editId: null
|
||||
};
|
||||
},
|
||||
async created() {
|
||||
await this.fetchEventPlaces();
|
||||
await this.fetchWorships();
|
||||
},
|
||||
methods: {
|
||||
formatTime,
|
||||
formatDate,
|
||||
async fetchWorships() {
|
||||
try {
|
||||
const response = await axios.get('http://localhost:3000/api/worships');
|
||||
this.worships = response.data;
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Abrufen der Gottesdienste:', error);
|
||||
}
|
||||
},
|
||||
async fetchEventPlaces() {
|
||||
try {
|
||||
const response = await axios.get('http://localhost:3000/api/event-places');
|
||||
this.eventPlaces = response.data;
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Abrufen der Veranstaltungsorte:', error);
|
||||
}
|
||||
},
|
||||
async saveWorship() {
|
||||
try {
|
||||
const payload = {
|
||||
...this.worshipData,
|
||||
eventPlaceId: this.selectedEventPlace ? this.selectedEventPlace.id : null
|
||||
};
|
||||
|
||||
if (this.editMode) {
|
||||
await axios.put(`http://localhost:3000/api/worships/${this.editId}`, payload);
|
||||
} else {
|
||||
await axios.post('http://localhost:3000/api/worships', payload);
|
||||
}
|
||||
|
||||
this.resetForm();
|
||||
await this.fetchWorships();
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Speichern des Gottesdienstes:', error);
|
||||
}
|
||||
},
|
||||
editWorship(worship) {
|
||||
this.worshipData = { ...worship };
|
||||
this.selectedEventPlace = this.eventPlaces.find(ep => ep.id === worship.eventPlaceId);
|
||||
this.editMode = true;
|
||||
this.editId = worship.id;
|
||||
},
|
||||
async deleteWorship(id) {
|
||||
try {
|
||||
await axios.delete(`http://localhost:3000/api/worships/${id}`);
|
||||
await this.fetchWorships();
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Löschen des Gottesdienstes:', error);
|
||||
}
|
||||
},
|
||||
resetForm() {
|
||||
this.worshipData = {
|
||||
eventPlaceId: null,
|
||||
date: '',
|
||||
time: '',
|
||||
title: '',
|
||||
organizer: '',
|
||||
collection: '',
|
||||
address: '',
|
||||
selfInformation: false,
|
||||
highlightTime: false,
|
||||
neighborInvitation: false,
|
||||
introLine: ''
|
||||
};
|
||||
this.selectedEventPlace = null;
|
||||
this.editMode = false;
|
||||
this.editId = null;
|
||||
},
|
||||
getEventPlaceName(eventPlaceId) {
|
||||
const place = this.eventPlaces.find(place => place.id === eventPlaceId);
|
||||
return place ? place.name : 'Unbekannter Ort';
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@import 'vue-multiselect/dist/vue-multiselect.css';
|
||||
|
||||
.worship-management {
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
label {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
button {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
ul {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
li {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 10px;
|
||||
border-bottom: 1px solid rgba(224, 224, 224, 0.9);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
button {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.tooltip {
|
||||
visibility: hidden;
|
||||
width: auto;
|
||||
background-color: rgba(224, 224, 224, 0.6);
|
||||
color: #000;
|
||||
text-align: center;
|
||||
padding: 5px 0;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
bottom: 75%;
|
||||
left: 50%;
|
||||
margin-left: -100px;
|
||||
padding: 5px;
|
||||
border: 1px solid #000;
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
|
||||
li:hover .tooltip {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user