Ersetzt ungültige UTable-Empty-Props durch einen gemeinsamen Empty-State-Slot, damit leere Tabellen keine Objekt-/JSON-Ausgabe mehr anzeigen.
283 lines
8.6 KiB
Vue
283 lines
8.6 KiB
Vue
<script setup lang="ts">
|
|
import { ref, computed } from "vue"
|
|
import dayjs from "dayjs"
|
|
import { CalendarDate, parseDate } from "@internationalized/date"
|
|
|
|
// --- Helper für Schnellauswahl ---
|
|
|
|
// Setzt ein spezifisches Quartal (Q1-Q4), optional mit Jahresangabe
|
|
const setQuarter = (quarter: number, year: number = dayjs().year()) => {
|
|
const startMonth = (quarter - 1) * 3 // Q1=0 (Jan), Q2=3 (Apr), etc.
|
|
|
|
// .toDate() ist wichtig für den DatePicker
|
|
createExportData.value.start_date = dayjs().year(year).month(startMonth).startOf('month').toDate()
|
|
createExportData.value.end_date = dayjs().year(year).month(startMonth + 2).endOf('month').toDate()
|
|
}
|
|
|
|
// Berechnet automatisch das vorherige Quartal (inkl. Jahreswechsel, falls wir in Q1 sind)
|
|
const setLastQuarter = () => {
|
|
const currentMonth = dayjs().month() // 0 bis 11
|
|
const currentQuarter = Math.floor(currentMonth / 3) + 1 // 1 bis 4
|
|
|
|
if (currentQuarter === 1) {
|
|
// Wenn wir in Q1 sind, ist das letzte Quartal Q4 des Vorjahres
|
|
setQuarter(4, dayjs().year() - 1)
|
|
} else {
|
|
// Sonst einfach das vorherige Quartal im aktuellen Jahr
|
|
setQuarter(currentQuarter - 1)
|
|
}
|
|
}
|
|
|
|
const setMonthPreset = (type: 'current' | 'last') => {
|
|
let date = dayjs()
|
|
if (type === 'last') {
|
|
date = date.subtract(1, 'month')
|
|
}
|
|
|
|
createExportData.value.start_date = date.startOf('month').toDate()
|
|
createExportData.value.end_date = date.endOf('month').toDate()
|
|
}
|
|
// ---------------------------------
|
|
|
|
const exports = ref([])
|
|
|
|
// Filtert die Exporte: Nur Einträge, deren valid_until nach dem jetzigen Zeitpunkt liegt
|
|
const filteredExports = computed(() => {
|
|
const now = dayjs()
|
|
return exports.value.filter(row => {
|
|
if (!row.valid_until) return true // Falls kein Ablaufdatum gesetzt ist, anzeigen
|
|
return dayjs(row.valid_until).isAfter(now)
|
|
})
|
|
})
|
|
|
|
const auth = useAuthStore()
|
|
const toast = useToast()
|
|
const router = useRouter()
|
|
|
|
const setupPage = async () => {
|
|
exports.value = await useNuxtApp().$api("/api/exports",{
|
|
method: "GET"
|
|
})
|
|
}
|
|
|
|
setupPage()
|
|
|
|
function downloadFile(row) {
|
|
const a = document.createElement("a")
|
|
a.href = row.url
|
|
a.download = row.file_path.split("/").pop()
|
|
document.body.appendChild(a)
|
|
a.click()
|
|
document.body.removeChild(a)
|
|
}
|
|
|
|
const showCreateExportModal = ref(false)
|
|
const createExportData = ref({
|
|
start_date: null,
|
|
end_date: null,
|
|
beraternr:null,
|
|
mandantennr: null
|
|
})
|
|
|
|
const toCalendarDate = (value: Date | string | null) => {
|
|
if (!value) return null
|
|
|
|
const parsed = dayjs(value)
|
|
if (!parsed.isValid()) return null
|
|
|
|
try {
|
|
return parseDate(parsed.format("YYYY-MM-DD"))
|
|
} catch {
|
|
return null
|
|
}
|
|
}
|
|
|
|
const fromCalendarDate = (value: CalendarDate | null, boundary: "start" | "end") => {
|
|
if (!value) return null
|
|
|
|
const date = dayjs(value.toString())
|
|
return boundary === "start" ? date.startOf("day").toDate() : date.endOf("day").toDate()
|
|
}
|
|
|
|
const startDateValue = computed({
|
|
get: () => toCalendarDate(createExportData.value.start_date),
|
|
set: (value) => {
|
|
createExportData.value.start_date = fromCalendarDate(value, "start")
|
|
}
|
|
})
|
|
|
|
const endDateValue = computed({
|
|
get: () => toCalendarDate(createExportData.value.end_date),
|
|
set: (value) => {
|
|
createExportData.value.end_date = fromCalendarDate(value, "end")
|
|
}
|
|
})
|
|
|
|
const createExport = async () => {
|
|
const res = await useNuxtApp().$api("/api/exports/datev",{
|
|
method: "POST",
|
|
body: createExportData.value
|
|
})
|
|
|
|
showCreateExportModal.value = false
|
|
|
|
if(res.success) {
|
|
toast.add({title: "Export wird erstellt. Sie erhalten eine Benachrichtigung sobald es soweit ist."})
|
|
} else {
|
|
toast.add({title: "Es gab einen Fehler beim erstellen", color: "error"})
|
|
}
|
|
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<UDashboardNavbar
|
|
title="Exporte"
|
|
>
|
|
<template #right>
|
|
<UButton
|
|
@click="showCreateExportModal = true"
|
|
>+ DATEV</UButton>
|
|
<UButton
|
|
@click="router.push('/export/create/sepa')"
|
|
>+ SEPA</UButton>
|
|
</template>
|
|
</UDashboardNavbar>
|
|
|
|
<UTable
|
|
:data="filteredExports"
|
|
:columns="normalizeTableColumns([
|
|
{ key: 'created_at', label: 'Erstellt am' },
|
|
{ key: 'start_date', label: 'Start' },
|
|
{ key: 'end_date', label: 'Ende' },
|
|
{ key: 'valid_until', label: 'Gültig bis' },
|
|
{ key: 'type', label: 'Typ' },
|
|
{ key: 'download', label: 'Download' },
|
|
])"
|
|
>
|
|
<template #created_at-cell="{row}">
|
|
{{dayjs(row.original.created_at).format("DD.MM.YYYY HH:mm")}}
|
|
</template>
|
|
<template #start_date-cell="{row}">
|
|
{{dayjs(row.original.start_date).format("DD.MM.YYYY HH:mm")}}
|
|
</template>
|
|
<template #end_date-cell="{row}">
|
|
{{dayjs(row.original.end_date).format("DD.MM.YYYY HH:mm")}}
|
|
</template>
|
|
<template #valid_until-cell="{row}">
|
|
{{dayjs(row.original.valid_until).format("DD.MM.YYYY HH:mm")}}
|
|
</template>
|
|
<template #download-cell="{row}">
|
|
<UButton @click="downloadFile(row.original)">Download</UButton>
|
|
</template>
|
|
<template #empty>
|
|
<TableEmptyState label="Keine Exporte anzuzeigen" />
|
|
</template>
|
|
</UTable>
|
|
|
|
<UModal v-model:open="showCreateExportModal">
|
|
<template #content>
|
|
<UCard>
|
|
<template #header>
|
|
Export erstellen
|
|
</template>
|
|
|
|
<div class="mb-6 p-3 bg-gray-50 dark:bg-gray-800 rounded-lg border border-gray-100 dark:border-gray-700">
|
|
<div class="text-xs font-semibold text-gray-500 uppercase tracking-wider mb-2">Schnellauswahl</div>
|
|
|
|
<div class="flex flex-col gap-3">
|
|
<div class="flex gap-2 items-center">
|
|
<span class="text-xs text-gray-400 w-16">Monat:</span>
|
|
<UButton size="2xs" color="white" variant="solid" @click="setMonthPreset('last')">Letzter</UButton>
|
|
<UButton size="2xs" color="white" variant="solid" @click="setMonthPreset('current')">Aktuell</UButton>
|
|
</div>
|
|
|
|
<div class="flex gap-2 items-center">
|
|
<span class="text-xs text-gray-400 w-16">Quartal:</span>
|
|
|
|
<UButton
|
|
size="2xs"
|
|
color="white"
|
|
variant="solid"
|
|
@click="setLastQuarter()"
|
|
class="mr-2 border-r border-gray-200 dark:border-gray-600 pr-3"
|
|
>
|
|
Letztes
|
|
</UButton>
|
|
|
|
<UButton
|
|
v-for="q in 4"
|
|
:key="q"
|
|
size="2xs"
|
|
color="white"
|
|
variant="solid"
|
|
@click="setQuarter(q)"
|
|
>
|
|
Q{{ q }}
|
|
</UButton>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="flex gap-4">
|
|
<UFormField label="Start:" class="flex-1">
|
|
<UPopover>
|
|
<UButton
|
|
icon="i-heroicons-calendar-days-20-solid"
|
|
:label="createExportData.start_date ? dayjs(createExportData.start_date).format('DD.MM.YYYY') : 'Datum auswählen'"
|
|
variant="outline"
|
|
color="neutral"
|
|
class="w-full justify-start"
|
|
/>
|
|
<template #content>
|
|
<div class="p-2">
|
|
<UCalendar v-model="startDateValue" />
|
|
<div class="flex justify-end border-t border-default pt-2">
|
|
<UButton color="neutral" variant="ghost" size="sm" @click="createExportData.start_date = dayjs().startOf('day').toDate()">
|
|
Heute
|
|
</UButton>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</UPopover>
|
|
</UFormField>
|
|
|
|
<UFormField label="Ende:" class="flex-1">
|
|
<UPopover>
|
|
<UButton
|
|
icon="i-heroicons-calendar-days-20-solid"
|
|
:label="createExportData.end_date ? dayjs(createExportData.end_date).format('DD.MM.YYYY') : 'Datum auswählen'"
|
|
variant="outline"
|
|
color="neutral"
|
|
class="w-full justify-start"
|
|
/>
|
|
<template #content>
|
|
<div class="p-2">
|
|
<UCalendar v-model="endDateValue" />
|
|
<div class="flex justify-end border-t border-default pt-2">
|
|
<UButton color="neutral" variant="ghost" size="sm" @click="createExportData.end_date = dayjs().endOf('day').toDate()">
|
|
Heute
|
|
</UButton>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</UPopover>
|
|
</UFormField>
|
|
</div>
|
|
|
|
<template #footer>
|
|
<div class="flex justify-end">
|
|
<UButton @click="createExport">
|
|
Erstellen
|
|
</UButton>
|
|
</div>
|
|
</template>
|
|
|
|
</UCard>
|
|
</template>
|
|
</UModal>
|
|
|
|
</template>
|
|
|
|
<style scoped>
|
|
</style>
|