Passt Kassenbuch Ansicht an

Kassenbücher werden nun zuerst tabellarisch angezeigt. Das Erstellen einer Barkasse erfolgt über ein Modal und einzelne Kassenbücher öffnen sich über eine Detailseite.
This commit is contained in:
2026-05-11 17:25:44 +02:00
parent e60188f043
commit d4c39d7d44
2 changed files with 182 additions and 101 deletions

View File

@@ -0,0 +1,165 @@
<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>
<UDashboardPanelContent>
<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}`)"
:empty="{ icon: 'i-heroicons-banknotes', label: 'Keine Kassenbücher angelegt' }"
>
<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>
</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>
</UDashboardPanelContent>
</template>