Optimiere das Worship Management-Formular: Entferne redundante Codeabschnitte, verbessere die Benutzeroberfläche durch Anpassungen der Abstände und Padding-Werte, und vereinheitliche die Struktur der Eingabefelder. Füge eine neue Auswahl für das Jahr hinzu, um die liturgischen Daten zu laden.

This commit is contained in:
Torsten Schulz (local)
2025-10-07 17:22:39 +02:00
parent 459dd3168a
commit 5e4471a936

View File

@@ -1,36 +1,29 @@
<template> <template>
<div class="worship-management"> <div class="worship-management">
<h2>Gottesdienst Verwaltung</h2> <h2>Gottesdienst Verwaltung</h2>
<div class="liturgical-loader">
<select v-model="selectedYear" class="year-select">
<option v-for="year in availableYears" :key="year" :value="year">{{ year }}</option>
</select>
<button type="button" @click="loadLiturgicalYear" class="load-year-button" :disabled="isLoading">
{{ isLoading ? 'Lade...' : 'Kirchenjahr laden' }}
</button>
</div>
<form @submit.prevent="saveWorship"> <form @submit.prevent="saveWorship">
<label for="eventPlaceId">Veranstaltungsort:</label> <label for="eventPlaceId">Veranstaltungsort:</label>
<multiselect v-model="selectedEventPlace" :options="eventPlaces" label="name" track-by="id" <multiselect v-model="selectedEventPlace" :options="eventPlaces" label="name" track-by="id"
placeholder="Veranstaltungsort wählen"></multiselect> placeholder="Veranstaltungsort wählen"></multiselect>
<label for="date">Datum:</label>
<input type="date" id="date" v-model="worshipData.date" required @change="updateDayNameFromDate">
<label for="dayName">Name des Tags:</label> <label for="dayName">Name des Tags:</label>
<div class="liturgical-day-section"> <div class="liturgical-day-section">
<multiselect <multiselect v-model="selectedDayName" :options="dayNameOptions" :multiple="false" :taggable="true"
v-model="selectedDayName" @tag="addDayNameTag" placeholder="Tag-Name wählen oder eingeben" label="name" track-by="name">
:options="dayNameOptions"
:multiple="false"
:taggable="true"
@tag="addDayNameTag"
placeholder="Tag-Name wählen oder eingeben"
label="name"
track-by="name">
</multiselect> </multiselect>
<div class="liturgical-loader">
<select v-model="selectedYear" class="year-select">
<option v-for="year in availableYears" :key="year" :value="year">{{ year }}</option>
</select>
<button type="button" @click="loadLiturgicalYear" class="load-year-button" :disabled="isLoading">
{{ isLoading ? 'Lade...' : 'Kirchenjahr laden' }}
</button>
</div>
</div> </div>
<label for="date">Datum:</label>
<input type="date" id="date" v-model="worshipData.date" required @change="updateDayNameFromDate">
<label for="time">Uhrzeit:</label> <label for="time">Uhrzeit:</label>
<input type="time" id="time" v-model="worshipData.time" required> <input type="time" id="time" v-model="worshipData.time" required>
@@ -38,27 +31,13 @@
<input type="text" id="title" v-model="worshipData.title" required> <input type="text" id="title" v-model="worshipData.title" required>
<label for="organizer">Gestalter:</label> <label for="organizer">Gestalter:</label>
<multiselect <multiselect v-model="selectedOrganizers" :options="organizerOptions" :multiple="true" :taggable="true"
v-model="selectedOrganizers" @tag="addOrganizerTag" placeholder="Gestalter wählen oder neu eingeben" label="name" track-by="name">
:options="organizerOptions"
:multiple="true"
:taggable="true"
@tag="addOrganizerTag"
placeholder="Gestalter wählen oder neu eingeben"
label="name"
track-by="name">
</multiselect> </multiselect>
<label for="sacristanService">Küsterdienst:</label> <label for="sacristanService">Küsterdienst:</label>
<multiselect <multiselect v-model="selectedSacristans" :options="sacristanOptions" :multiple="true" :taggable="true"
v-model="selectedSacristans" @tag="addSacristanTag" placeholder="Küsterdienst wählen oder neu eingeben" label="name" track-by="name">
:options="sacristanOptions"
:multiple="true"
:taggable="true"
@tag="addSacristanTag"
placeholder="Küsterdienst wählen oder neu eingeben"
label="name"
track-by="name">
</multiselect> </multiselect>
<label for="collection">Kollekte:</label> <label for="collection">Kollekte:</label>
@@ -84,17 +63,9 @@
</form> </form>
<div class="filter-section"> <div class="filter-section">
<input <input v-model="searchDate" type="date" class="search-input" placeholder="Nach Datum suchen..." />
v-model="searchDate"
type="date"
class="search-input"
placeholder="Nach Datum suchen..."
/>
<label class="checkbox-label"> <label class="checkbox-label">
<input <input v-model="showPastWorships" type="checkbox" />
v-model="showPastWorships"
type="checkbox"
/>
Vergangene Gottesdienste anzeigen Vergangene Gottesdienste anzeigen
</label> </label>
<button v-if="searchDate" @click="clearSearch" type="button" class="clear-button"> <button v-if="searchDate" @click="clearSearch" type="button" class="clear-button">
@@ -103,7 +74,8 @@
</div> </div>
<ul> <ul>
<li v-for="worship in filteredWorships" :key="worship.id" :class="dateIsLowerCurrentDate(worship.date) ? 'old-items' : ''"> <li v-for="worship in filteredWorships" :key="worship.id"
:class="dateIsLowerCurrentDate(worship.date) ? 'old-items' : ''">
<span>{{ worship.title }} - {{ formatDate(worship.date) }}, {{ formatTime(worship.time) }}</span> <span>{{ worship.title }} - {{ formatDate(worship.date) }}, {{ formatTime(worship.time) }}</span>
<button @click="editWorship(worship)">Bearbeiten</button> <button @click="editWorship(worship)">Bearbeiten</button>
<button @click="deleteWorship(worship.id)">Löschen</button> <button @click="deleteWorship(worship.id)">Löschen</button>
@@ -168,7 +140,7 @@ export default {
if (!this.showPastWorships) { if (!this.showPastWorships) {
const today = new Date(); const today = new Date();
today.setHours(0, 0, 0, 0); today.setHours(0, 0, 0, 0);
filtered = filtered.filter(worship => { filtered = filtered.filter(worship => {
if (worship.date) { if (worship.date) {
const worshipDate = new Date(worship.date); const worshipDate = new Date(worship.date);
@@ -183,7 +155,7 @@ export default {
if (this.searchDate) { if (this.searchDate) {
const searchDateObj = new Date(this.searchDate); const searchDateObj = new Date(this.searchDate);
searchDateObj.setHours(0, 0, 0, 0); searchDateObj.setHours(0, 0, 0, 0);
filtered = filtered.filter(worship => { filtered = filtered.filter(worship => {
if (worship.date) { if (worship.date) {
const worshipDate = new Date(worship.date); const worshipDate = new Date(worship.date);
@@ -243,20 +215,20 @@ export default {
try { try {
const response = await axios.get('/liturgical-days'); const response = await axios.get('/liturgical-days');
this.liturgicalDays = response.data; this.liturgicalDays = response.data;
// Nur zukünftige Tage anzeigen // Nur zukünftige Tage anzeigen
const today = new Date(); const today = new Date();
today.setHours(0, 0, 0, 0); today.setHours(0, 0, 0, 0);
const futureDays = response.data.filter(day => { const futureDays = response.data.filter(day => {
const dayDate = new Date(day.date); const dayDate = new Date(day.date);
dayDate.setHours(0, 0, 0, 0); dayDate.setHours(0, 0, 0, 0);
return dayDate >= today; return dayDate >= today;
}); });
// Sortiere nach Datum // Sortiere nach Datum
futureDays.sort((a, b) => new Date(a.date) - new Date(b.date)); futureDays.sort((a, b) => new Date(a.date) - new Date(b.date));
// Erstelle Optionen mit Datum und Name: "30.11.2025 - 1. Advent" // Erstelle Optionen mit Datum und Name: "30.11.2025 - 1. Advent"
this.dayNameOptions = futureDays.map(day => { this.dayNameOptions = futureDays.map(day => {
const date = new Date(day.date); const date = new Date(day.date);
@@ -280,7 +252,7 @@ export default {
alert('Bitte wählen Sie ein Jahr aus'); alert('Bitte wählen Sie ein Jahr aus');
return; return;
} }
this.isLoading = true; this.isLoading = true;
try { try {
const response = await axios.post('/liturgical-days/load-year', { const response = await axios.post('/liturgical-days/load-year', {
@@ -303,20 +275,20 @@ export default {
if (!this.worshipData.date) { if (!this.worshipData.date) {
return; return;
} }
// Setze Flag, um Endlosschleife zu vermeiden // Setze Flag, um Endlosschleife zu vermeiden
this.isUpdatingFromDate = true; this.isUpdatingFromDate = true;
// Normalisiere das Datum (HTML input gibt YYYY-MM-DD zurück) // Normalisiere das Datum (HTML input gibt YYYY-MM-DD zurück)
const selectedDate = this.worshipData.date; const selectedDate = this.worshipData.date;
// Finde liturgischen Tag für das gewählte Datum // Finde liturgischen Tag für das gewählte Datum
const liturgicalDay = this.liturgicalDays.find(day => { const liturgicalDay = this.liturgicalDays.find(day => {
// Vergleiche nur das Datum (ignoriere mögliche Zeitstempel) // Vergleiche nur das Datum (ignoriere mögliche Zeitstempel)
const dayDate = typeof day.date === 'string' ? day.date : day.date.split('T')[0]; const dayDate = typeof day.date === 'string' ? day.date : day.date.split('T')[0];
return dayDate === selectedDate; return dayDate === selectedDate;
}); });
if (liturgicalDay) { if (liturgicalDay) {
// Finde die passende Option mit formatiertem Datum // Finde die passende Option mit formatiertem Datum
const option = this.dayNameOptions.find(opt => opt.date === selectedDate); const option = this.dayNameOptions.find(opt => opt.date === selectedDate);
@@ -328,7 +300,7 @@ export default {
} else { } else {
console.log('Kein liturgischer Tag gefunden für:', selectedDate); console.log('Kein liturgischer Tag gefunden für:', selectedDate);
} }
// Reset Flag nach kurzer Verzögerung // Reset Flag nach kurzer Verzögerung
this.$nextTick(() => { this.$nextTick(() => {
this.isUpdatingFromDate = false; this.isUpdatingFromDate = false;
@@ -338,7 +310,7 @@ export default {
if (!this.selectedDayName || !this.selectedDayName.date) { if (!this.selectedDayName || !this.selectedDayName.date) {
return; return;
} }
// Das Datum ist bereits in der Option enthalten // Das Datum ist bereits in der Option enthalten
this.worshipData.date = this.selectedDayName.date; this.worshipData.date = this.selectedDayName.date;
this.worshipData.dayName = this.selectedDayName.dayName; this.worshipData.dayName = this.selectedDayName.dayName;
@@ -373,25 +345,25 @@ export default {
this.worshipData.time = formatTime(worship.time); this.worshipData.time = formatTime(worship.time);
console.log(this.worshipData); console.log(this.worshipData);
this.selectedEventPlace = this.eventPlaces.find(ep => ep.id === worship.eventPlaceId); this.selectedEventPlace = this.eventPlaces.find(ep => ep.id === worship.eventPlaceId);
// Konvertiere kommaseparierte Strings zu Arrays für Multiselect // Konvertiere kommaseparierte Strings zu Arrays für Multiselect
this.selectedOrganizers = worship.organizer this.selectedOrganizers = worship.organizer
? worship.organizer.split(',').map(org => ({ name: org.trim() })) ? worship.organizer.split(',').map(org => ({ name: org.trim() }))
: []; : [];
this.selectedSacristans = worship.sacristanService this.selectedSacristans = worship.sacristanService
? worship.sacristanService.split(',').map(sac => ({ name: sac.trim() })) ? worship.sacristanService.split(',').map(sac => ({ name: sac.trim() }))
: []; : [];
// Setze dayName - finde die passende Option // Setze dayName - finde die passende Option
if (worship.dayName) { if (worship.dayName) {
const option = this.dayNameOptions.find(opt => const option = this.dayNameOptions.find(opt =>
opt.dayName === worship.dayName && opt.date === this.worshipData.date opt.dayName === worship.dayName && opt.date === this.worshipData.date
); );
this.selectedDayName = option || null; this.selectedDayName = option || null;
} else { } else {
this.selectedDayName = null; this.selectedDayName = null;
} }
this.editMode = true; this.editMode = true;
this.editId = worship.id; this.editId = worship.id;
}, },
@@ -449,7 +421,7 @@ export default {
}, },
addDayNameTag(newTag) { addDayNameTag(newTag) {
// Wenn manuell ein Tag eingegeben wird, ohne Datum // Wenn manuell ein Tag eingegeben wird, ohne Datum
const tag = { const tag = {
name: newTag, name: newTag,
dayName: newTag, dayName: newTag,
date: this.worshipData.date || null date: this.worshipData.date || null
@@ -475,35 +447,41 @@ export default {
form { form {
display: grid; display: grid;
grid-template-columns: 180px 1fr; grid-template-columns: 180px 1fr;
gap: 15px 20px; gap: 8px 20px;
align-items: start; align-items: start;
} }
form > label { form>label {
margin: 0; margin: 0;
padding-top: 8px; padding-top: 6px;
text-align: right; text-align: right;
font-weight: 500; font-weight: 500;
} }
form > input[type="text"], form>input[type="text"],
form > input[type="date"], form>input[type="date"],
form > input[type="time"], form>input[type="time"] {
form > .multiselect, width: 100%;
form > .liturgical-day-section { max-width: 500px;
padding: 6px 10px;
font-size: 14px;
}
form>.multiselect,
form>.liturgical-day-section {
width: 100%; width: 100%;
max-width: 500px; max-width: 500px;
} }
form > input[type="checkbox"] { form>input[type="checkbox"] {
justify-self: start; justify-self: start;
margin-top: 8px; margin-top: 6px;
} }
form > button { form>button {
grid-column: 1 / -1; grid-column: 1 / -1;
justify-self: start; justify-self: start;
margin-top: 10px; margin-top: 8px;
} }
.filter-section { .filter-section {
@@ -563,18 +541,18 @@ form > button {
.liturgical-day-section { .liturgical-day-section {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 10px; gap: 6px;
max-width: 500px; max-width: 500px;
} }
.liturgical-loader { .liturgical-loader {
display: flex; display: flex;
gap: 10px; gap: 8px;
align-items: center; align-items: center;
} }
.year-select { .year-select {
padding: 8px 12px; padding: 6px 10px;
border: 1px solid #ddd; border: 1px solid #ddd;
border-radius: 4px; border-radius: 4px;
font-size: 14px; font-size: 14px;
@@ -588,7 +566,7 @@ form > button {
} }
.load-year-button { .load-year-button {
padding: 8px 16px; padding: 6px 12px;
background-color: #2196F3; background-color: #2196F3;
color: white; color: white;
border: none; border: none;
@@ -596,6 +574,7 @@ form > button {
cursor: pointer; cursor: pointer;
white-space: nowrap; white-space: nowrap;
margin: 0; margin: 0;
font-size: 14px;
} }
.load-year-button:hover:not(:disabled) { .load-year-button:hover:not(:disabled) {
@@ -647,7 +626,7 @@ li:hover .tooltip {
opacity: 1; opacity: 1;
} }
li > span { li>span {
flex: 1; flex: 1;
} }