Ersetzt ungültige UTable-Empty-Props durch einen gemeinsamen Empty-State-Slot, damit leere Tabellen keine Objekt-/JSON-Ausgabe mehr anzeigen.
166 lines
4.7 KiB
Vue
166 lines
4.7 KiB
Vue
<script setup>
|
|
const toast = useToast()
|
|
const router = useRouter()
|
|
const tempStore = useTempStore()
|
|
|
|
const loading = ref(true)
|
|
const savingCashbook = ref(false)
|
|
const createCashbookModalOpen = ref(false)
|
|
const cashbooks = ref([])
|
|
const searchString = ref(tempStore.searchStrings["cashbooks"] || "")
|
|
|
|
const newCashbook = reactive({
|
|
name: "",
|
|
datevNumber: "1000",
|
|
openingBalance: 0
|
|
})
|
|
|
|
const displayCurrency = (value) => `${Number(value || 0).toFixed(2).replace(".", ",")} €`
|
|
|
|
const templateColumns = [
|
|
{
|
|
key: "name",
|
|
label: "Bezeichnung"
|
|
},
|
|
{
|
|
key: "datevNumber",
|
|
label: "Kontennummer"
|
|
},
|
|
{
|
|
key: "balance",
|
|
label: "Anfangsbestand"
|
|
},
|
|
{
|
|
key: "syncedAt",
|
|
label: "Erstellt"
|
|
}
|
|
]
|
|
|
|
const filteredRows = computed(() => useSearch(searchString.value, cashbooks.value))
|
|
|
|
const clearSearchString = () => {
|
|
tempStore.clearSearchString("cashbooks")
|
|
searchString.value = ""
|
|
}
|
|
|
|
const loadCashbooks = async () => {
|
|
loading.value = true
|
|
cashbooks.value = await useNuxtApp().$api("/api/banking/cashbooks")
|
|
loading.value = false
|
|
}
|
|
|
|
const resetCreateForm = () => {
|
|
newCashbook.name = ""
|
|
newCashbook.datevNumber = "1000"
|
|
newCashbook.openingBalance = 0
|
|
}
|
|
|
|
const createCashbook = async () => {
|
|
if (!newCashbook.name || !newCashbook.datevNumber) {
|
|
toast.add({ title: "Bitte Bezeichnung und Kontennummer ausfüllen.", color: "warning" })
|
|
return
|
|
}
|
|
|
|
savingCashbook.value = true
|
|
try {
|
|
const created = await useNuxtApp().$api("/api/banking/cashbooks", {
|
|
method: "POST",
|
|
body: {
|
|
name: newCashbook.name,
|
|
datevNumber: newCashbook.datevNumber,
|
|
openingBalance: Number(newCashbook.openingBalance || 0)
|
|
}
|
|
})
|
|
toast.add({ title: "Barkasse erstellt." })
|
|
createCashbookModalOpen.value = false
|
|
resetCreateForm()
|
|
await loadCashbooks()
|
|
router.push(`/accounting/cashbooks/${created.id}`)
|
|
} finally {
|
|
savingCashbook.value = false
|
|
}
|
|
}
|
|
|
|
onMounted(loadCashbooks)
|
|
</script>
|
|
|
|
<template>
|
|
<UDashboardNavbar title="Kassenbücher" :badge="filteredRows.length">
|
|
<template #right>
|
|
<UInput
|
|
id="searchinput"
|
|
v-model="searchString"
|
|
icon="i-heroicons-magnifying-glass"
|
|
autocomplete="off"
|
|
placeholder="Suche..."
|
|
class="hidden lg:block"
|
|
@keydown.esc="$event.target.blur()"
|
|
@change="tempStore.modifySearchString('cashbooks', searchString)"
|
|
/>
|
|
<UButton
|
|
v-if="searchString.length > 0"
|
|
icon="i-heroicons-x-mark"
|
|
variant="outline"
|
|
color="error"
|
|
@click="clearSearchString"
|
|
/>
|
|
<UButton icon="i-heroicons-plus" @click="createCashbookModalOpen = true">
|
|
Barkasse
|
|
</UButton>
|
|
</template>
|
|
</UDashboardNavbar>
|
|
|
|
<UTable
|
|
:data="filteredRows"
|
|
:columns="normalizeTableColumns(templateColumns)"
|
|
:loading="loading"
|
|
class="w-full"
|
|
:ui="{ divide: 'divide-gray-200 dark:divide-gray-800' }"
|
|
:on-select="(row) => router.push(`/accounting/cashbooks/${row.original?.id || row.id}`)"
|
|
>
|
|
<template #datevNumber-cell="{ row }">
|
|
<span class="font-mono">{{ row.original.datevNumber }}</span>
|
|
</template>
|
|
<template #balance-cell="{ row }">
|
|
{{ displayCurrency(row.original.balance) }}
|
|
</template>
|
|
<template #syncedAt-cell="{ row }">
|
|
{{ row.original.createdAt ? new Date(row.original.createdAt).toLocaleDateString("de-DE") : "-" }}
|
|
</template>
|
|
<template #empty>
|
|
<TableEmptyState label="Keine Kassenbücher angelegt" icon="i-heroicons-banknotes" />
|
|
</template>
|
|
</UTable>
|
|
|
|
<UModal v-model:open="createCashbookModalOpen">
|
|
<template #content>
|
|
<UCard>
|
|
<template #header>
|
|
<div class="text-lg font-semibold">Barkasse anlegen</div>
|
|
</template>
|
|
|
|
<UForm :state="newCashbook" class="space-y-4" @submit.prevent="createCashbook">
|
|
<UFormField label="Bezeichnung">
|
|
<UInput v-model="newCashbook.name" placeholder="z. B. Hauptkasse" />
|
|
</UFormField>
|
|
<UFormField label="Kontennummer">
|
|
<UInput v-model="newCashbook.datevNumber" placeholder="1000" />
|
|
</UFormField>
|
|
<UFormField label="Anfangsbestand">
|
|
<UInput v-model="newCashbook.openingBalance" type="number" step="0.01" />
|
|
</UFormField>
|
|
|
|
<div class="flex justify-end gap-3 pt-2">
|
|
<UButton color="gray" variant="soft" @click="createCashbookModalOpen = false">
|
|
Abbrechen
|
|
</UButton>
|
|
<UButton type="submit" color="primary" :loading="savingCashbook">
|
|
Barkasse anlegen
|
|
</UButton>
|
|
</div>
|
|
</UForm>
|
|
</UCard>
|
|
</template>
|
|
</UModal>
|
|
</template>
|