Die Kassenbuch-Listenansicht rendert die DashboardNavbar nun wie andere Listenseiten direkt oben. Die Detailansicht nutzt dieselbe Struktur und hält den Inhalt im PanelContent.
164 lines
4.6 KiB
Vue
164 lines
4.6 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}`)"
|
|
: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>
|
|
</template>
|