diff --git a/frontend/src/views/CalendarView.vue b/frontend/src/views/CalendarView.vue
index 47a5a7b..32971f1 100644
--- a/frontend/src/views/CalendarView.vue
+++ b/frontend/src/views/CalendarView.vue
@@ -45,10 +45,22 @@
optionLabel="label" optionValue="value" placeholder="Alle Kalender"
showClear style="min-width: 180px" />
-
{{ filteredListEvents.length }} Termin(e)
+
+ |
+
+ |
Datum
|
@@ -61,7 +73,14 @@
-
+
+ |
+
+ |
{{ formatListDate(ev) }}
{{ formatListTime(ev) }}
@@ -80,7 +99,7 @@
|
- | Keine Termine gefunden. |
+ Keine Termine gefunden. |
@@ -337,6 +356,7 @@ import InputText from 'primevue/inputtext'
import Textarea from 'primevue/textarea'
import Select from 'primevue/select'
import SelectButton from 'primevue/selectbutton'
+import Checkbox from 'primevue/checkbox'
import FullCalendar from '@fullcalendar/vue3'
import dayGridPlugin from '@fullcalendar/daygrid'
import timeGridPlugin from '@fullcalendar/timegrid'
@@ -368,6 +388,57 @@ const listTo = ref('')
const listCalFilter = ref(null)
const listSort = ref('dtstart')
const listSortDir = ref('asc')
+const selectedListIds = ref([])
+
+const allListSelected = computed({
+ get: () => {
+ const writable = filteredListEvents.value.filter(e => e._cal?.permission !== 'read')
+ return writable.length > 0 && writable.every(e => selectedListIds.value.includes(e.id))
+ },
+ set: () => {},
+})
+
+function toggleAllListSelected() {
+ const writableIds = filteredListEvents.value
+ .filter(e => e._cal?.permission !== 'read').map(e => e.id)
+ const allSel = writableIds.length > 0 && writableIds.every(id => selectedListIds.value.includes(id))
+ if (allSel) {
+ selectedListIds.value = selectedListIds.value.filter(id => !writableIds.includes(id))
+ } else {
+ const set = new Set(selectedListIds.value)
+ writableIds.forEach(id => set.add(id))
+ selectedListIds.value = [...set]
+ }
+}
+
+function toggleListSelect(id, checked) {
+ if (checked) {
+ if (!selectedListIds.value.includes(id)) selectedListIds.value = [...selectedListIds.value, id]
+ } else {
+ selectedListIds.value = selectedListIds.value.filter(x => x !== id)
+ }
+}
+
+async function deleteSelectedListEvents() {
+ const ids = [...selectedListIds.value]
+ if (!ids.length) return
+ if (!confirm(`${ids.length} Termin(e) wirklich loeschen?`)) return
+ let ok = 0, fail = 0
+ for (const id of ids) {
+ try {
+ await apiClient.delete(`/events/${id}`)
+ ok++
+ } catch { fail++ }
+ }
+ selectedListIds.value = []
+ toast.add({
+ severity: fail ? 'warn' : 'success',
+ summary: `${ok} geloescht${fail ? `, ${fail} fehlgeschlagen` : ''}`,
+ life: 3000,
+ })
+ await loadListEvents()
+ refreshEvents()
+}
const listCalOptions = computed(() => calendars.value.map(c => ({ label: c.name, value: c.id })))
@@ -1117,6 +1188,10 @@ onUnmounted(() => {
.list-view { display: flex; flex-direction: column; gap: 0.75rem; }
.list-filters { display: flex; gap: 0.5rem; align-items: center; flex-wrap: wrap; }
.list-meta { font-size: 0.8rem; color: var(--p-text-muted-color); }
+.list-meta-row { display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex-wrap: wrap; }
+.list-bulk { display: flex; align-items: center; gap: 0.5rem; font-size: 0.85rem; }
+.col-check { width: 36px; }
+.list-row.selected { background: var(--p-primary-50); }
.list-table { width: 100%; border-collapse: collapse; font-size: 0.875rem; }
.list-table th { text-align: left; padding: 0.5rem; border-bottom: 2px solid var(--p-surface-200); font-weight: 600; user-select: none; }
.list-table th.sortable { cursor: pointer; }