4. Zwischenstand
This commit is contained in:
@@ -136,30 +136,37 @@ const links = computed(() => {
|
|||||||
to: "/incomingInvoices",
|
to: "/incomingInvoices",
|
||||||
icon: "i-heroicons-document-text",
|
icon: "i-heroicons-document-text",
|
||||||
} : null,
|
} : null,
|
||||||
(featureEnabled("createDocument") || featureEnabled("incomingInvoices")) ? {
|
((featureEnabled("createDocument") || featureEnabled("incomingInvoices")) || featureEnabled("accounts") || featureEnabled("ownaccounts") || featureEnabled("costcentres")) ? {
|
||||||
label: "USt-Auswertung",
|
label: "Auswertungen",
|
||||||
to: "/accounting/tax",
|
icon: "i-heroicons-chart-pie",
|
||||||
icon: "i-heroicons-calculator",
|
defaultOpen: false,
|
||||||
} : null,
|
children: visibleItems([
|
||||||
(featureEnabled("createDocument") || featureEnabled("incomingInvoices") || featureEnabled("accounts") || featureEnabled("ownaccounts")) ? {
|
(featureEnabled("createDocument") || featureEnabled("incomingInvoices")) ? {
|
||||||
label: "BWA",
|
label: "USt",
|
||||||
to: "/accounting/bwa",
|
to: "/accounting/tax",
|
||||||
icon: "i-heroicons-chart-bar-square",
|
icon: "i-heroicons-calculator",
|
||||||
} : null,
|
} : null,
|
||||||
featureEnabled("costcentres") ? {
|
(featureEnabled("createDocument") || featureEnabled("incomingInvoices") || featureEnabled("accounts") || featureEnabled("ownaccounts")) ? {
|
||||||
label: "Kostenstellen",
|
label: "BWA",
|
||||||
to: "/standardEntity/costcentres",
|
to: "/accounting/bwa",
|
||||||
icon: "i-heroicons-document-currency-euro"
|
icon: "i-heroicons-chart-bar-square",
|
||||||
} : null,
|
} : null,
|
||||||
featureEnabled("accounts") ? {
|
featureEnabled("costcentres") ? {
|
||||||
label: "Buchungskonten",
|
label: "Kostenstellen",
|
||||||
to: "/accounts",
|
to: "/standardEntity/costcentres",
|
||||||
icon: "i-heroicons-document-text",
|
icon: "i-heroicons-document-currency-euro"
|
||||||
} : null,
|
} : null,
|
||||||
featureEnabled("ownaccounts") ? {
|
featureEnabled("accounts") ? {
|
||||||
label: "zusätzliche Buchungskonten",
|
label: "Buchungskonten",
|
||||||
to: "/standardEntity/ownaccounts",
|
to: "/accounts",
|
||||||
icon: "i-heroicons-document-text"
|
icon: "i-heroicons-document-text",
|
||||||
|
} : null,
|
||||||
|
featureEnabled("ownaccounts") ? {
|
||||||
|
label: "Zusätzliche Buchungskonten",
|
||||||
|
to: "/standardEntity/ownaccounts",
|
||||||
|
icon: "i-heroicons-document-text"
|
||||||
|
} : null,
|
||||||
|
])
|
||||||
} : null,
|
} : null,
|
||||||
featureEnabled("banking") ? {
|
featureEnabled("banking") ? {
|
||||||
label: "Bank",
|
label: "Bank",
|
||||||
@@ -401,31 +408,31 @@ const links = computed(() => {
|
|||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const mapNavItem = (item, valuePrefix = "item") => {
|
||||||
|
const children = Array.isArray(item.children)
|
||||||
|
? item.children
|
||||||
|
.filter(Boolean)
|
||||||
|
.map((child, index) => mapNavItem(child, `${valuePrefix}-${index}`))
|
||||||
|
: undefined
|
||||||
|
|
||||||
|
const active = item.active || isRouteActive(item.to) || Boolean(children?.some(child => child.active))
|
||||||
|
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
children,
|
||||||
|
value: item.id || item.label || valuePrefix,
|
||||||
|
defaultOpen: item.defaultOpen || active,
|
||||||
|
active,
|
||||||
|
tooltip: true,
|
||||||
|
popover: true,
|
||||||
|
trailingIcon: children?.length ? undefined : ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const navItems = computed(() =>
|
const navItems = computed(() =>
|
||||||
links.value
|
links.value
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.map((item, index) => {
|
.map((item, index) => mapNavItem(item, String(index)))
|
||||||
const children = Array.isArray(item.children)
|
|
||||||
? item.children.map((child, childIndex) => ({
|
|
||||||
...child,
|
|
||||||
value: child.id || child.label || `${index}-${childIndex}`,
|
|
||||||
active: isRouteActive(child.to)
|
|
||||||
}))
|
|
||||||
: undefined
|
|
||||||
|
|
||||||
const active = item.active || isRouteActive(item.to) || Boolean(children?.some(child => child.active))
|
|
||||||
|
|
||||||
return {
|
|
||||||
...item,
|
|
||||||
children,
|
|
||||||
value: item.id || item.label || String(index),
|
|
||||||
defaultOpen: item.defaultOpen || active,
|
|
||||||
active,
|
|
||||||
tooltip: true,
|
|
||||||
popover: true,
|
|
||||||
trailingIcon: children?.length ? undefined : ''
|
|
||||||
}
|
|
||||||
})
|
|
||||||
)
|
)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
221
frontend/components/displayBWASummary.vue
Normal file
221
frontend/components/displayBWASummary.vue
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import dayjs from "dayjs"
|
||||||
|
import {
|
||||||
|
getCreatedDocumentTaxBreakdown,
|
||||||
|
getIncomingInvoiceTaxBreakdown
|
||||||
|
} from "~/composables/useTaxEvaluation"
|
||||||
|
|
||||||
|
const loading = ref(true)
|
||||||
|
const summary = ref({
|
||||||
|
label: "",
|
||||||
|
income: 0,
|
||||||
|
expenses: 0,
|
||||||
|
result: 0,
|
||||||
|
taxBalance: 0,
|
||||||
|
incomeCount: 0,
|
||||||
|
expenseCount: 0
|
||||||
|
})
|
||||||
|
|
||||||
|
const formatCurrency = (value: number) => {
|
||||||
|
return new Intl.NumberFormat("de-DE", {
|
||||||
|
style: "currency",
|
||||||
|
currency: "EUR"
|
||||||
|
}).format(Number(value || 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
const isRelevantOutputDocument = (doc: any) => {
|
||||||
|
return doc?.state === "Gebucht" && ["invoices", "advanceInvoices", "cancellationInvoices"].includes(doc?.type)
|
||||||
|
}
|
||||||
|
|
||||||
|
const isRelevantInputInvoice = (invoice: any) => {
|
||||||
|
return invoice?.state === "Gebucht" && !!invoice?.date
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadSummary = async () => {
|
||||||
|
loading.value = true
|
||||||
|
|
||||||
|
try {
|
||||||
|
const bounds = {
|
||||||
|
start: dayjs().startOf("month"),
|
||||||
|
end: dayjs().endOf("month")
|
||||||
|
}
|
||||||
|
|
||||||
|
const [docs, incoming, allocations] = await Promise.all([
|
||||||
|
useEntities("createddocuments").select(),
|
||||||
|
useEntities("incominginvoices").select(),
|
||||||
|
useEntities("statementallocations").select("*, bankstatement(*)")
|
||||||
|
])
|
||||||
|
|
||||||
|
const outputDocs = (docs || []).filter((doc: any) => {
|
||||||
|
if (!isRelevantOutputDocument(doc)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const date = dayjs(doc.documentDate)
|
||||||
|
return date.isValid() && !date.isBefore(bounds.start, "day") && !date.isAfter(bounds.end, "day")
|
||||||
|
})
|
||||||
|
|
||||||
|
const inputDocs = (incoming || []).filter((invoice: any) => {
|
||||||
|
if (!isRelevantInputInvoice(invoice)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const date = dayjs(invoice.date)
|
||||||
|
return date.isValid() && !date.isBefore(bounds.start, "day") && !date.isAfter(bounds.end, "day")
|
||||||
|
})
|
||||||
|
|
||||||
|
const directExpenses = (allocations || []).filter((allocation: any) => {
|
||||||
|
if (allocation?.account === null || typeof allocation?.account === "undefined") {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const statementDate = allocation?.bankstatement?.date || allocation?.bankstatement?.valueDate || allocation?.date || allocation?.created_at
|
||||||
|
const date = dayjs(statementDate)
|
||||||
|
const amount = Number(allocation?.amount || 0)
|
||||||
|
|
||||||
|
return amount < 0 && date.isValid() && !date.isBefore(bounds.start, "day") && !date.isAfter(bounds.end, "day")
|
||||||
|
})
|
||||||
|
|
||||||
|
const income = outputDocs.reduce((sum: number, doc: any) => {
|
||||||
|
return sum + (doc.rows || []).reduce((rowSum: number, row: any) => {
|
||||||
|
if (!row || ["pagebreak", "title", "text"].includes(row.mode)) {
|
||||||
|
return rowSum
|
||||||
|
}
|
||||||
|
|
||||||
|
const quantity = Number(row.quantity || 0)
|
||||||
|
const price = Number(row.price || 0)
|
||||||
|
const discountPercent = Number(row.discountPercent || 0)
|
||||||
|
|
||||||
|
return rowSum + (quantity * price * (1 - discountPercent / 100))
|
||||||
|
}, 0)
|
||||||
|
}, 0)
|
||||||
|
|
||||||
|
const invoiceExpenses = inputDocs.reduce((sum: number, invoice: any) => {
|
||||||
|
return sum + (invoice.accounts || []).reduce((accountSum: number, account: any) => accountSum + Number(account.amountNet || 0), 0)
|
||||||
|
}, 0)
|
||||||
|
|
||||||
|
const directAccountExpenses = directExpenses.reduce((sum: number, allocation: any) => {
|
||||||
|
return sum + Math.abs(Number(allocation.amount || 0))
|
||||||
|
}, 0)
|
||||||
|
|
||||||
|
const outputTax = outputDocs.reduce((sum: number, doc: any) => {
|
||||||
|
const breakdown = getCreatedDocumentTaxBreakdown(doc)
|
||||||
|
return sum + breakdown.tax19 + breakdown.tax7
|
||||||
|
}, 0)
|
||||||
|
|
||||||
|
const inputTax = inputDocs.reduce((sum: number, invoice: any) => {
|
||||||
|
const breakdown = getIncomingInvoiceTaxBreakdown(invoice)
|
||||||
|
return sum + breakdown.tax19 + breakdown.tax7
|
||||||
|
}, 0)
|
||||||
|
|
||||||
|
const expenses = invoiceExpenses + directAccountExpenses
|
||||||
|
|
||||||
|
summary.value = {
|
||||||
|
label: dayjs().format("MMMM YYYY"),
|
||||||
|
income: Number(income.toFixed(2)),
|
||||||
|
expenses: Number(expenses.toFixed(2)),
|
||||||
|
result: Number((income - expenses).toFixed(2)),
|
||||||
|
taxBalance: Number((outputTax - inputTax).toFixed(2)),
|
||||||
|
incomeCount: outputDocs.length,
|
||||||
|
expenseCount: inputDocs.length + directExpenses.length
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(loadSummary)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="space-y-3">
|
||||||
|
<div class="bwa-summary-top">
|
||||||
|
<div>
|
||||||
|
<p class="bwa-summary-period">{{ summary.label }}</p>
|
||||||
|
<p class="bwa-summary-range">Aktueller Monat</p>
|
||||||
|
</div>
|
||||||
|
<UButton
|
||||||
|
size="xs"
|
||||||
|
variant="soft"
|
||||||
|
color="gray"
|
||||||
|
icon="i-heroicons-arrow-top-right-on-square"
|
||||||
|
@click="navigateTo('/accounting/bwa')"
|
||||||
|
>
|
||||||
|
Details
|
||||||
|
</UButton>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bwa-summary-row">
|
||||||
|
<span class="bwa-summary-label">Einnahmen</span>
|
||||||
|
<span class="bwa-summary-value text-primary-500">
|
||||||
|
{{ loading ? "..." : formatCurrency(summary.income) }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bwa-summary-row">
|
||||||
|
<span class="bwa-summary-label">Ausgaben</span>
|
||||||
|
<span class="bwa-summary-value text-error">
|
||||||
|
{{ loading ? "..." : formatCurrency(summary.expenses) }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bwa-summary-row">
|
||||||
|
<span class="bwa-summary-label">Ergebnis</span>
|
||||||
|
<span class="bwa-summary-value" :class="summary.result >= 0 ? 'text-primary-500' : 'text-error'">
|
||||||
|
{{ loading ? "..." : formatCurrency(summary.result) }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bwa-summary-meta">
|
||||||
|
{{ summary.incomeCount }} Einnahmenbelege | {{ summary.expenseCount }} Ausgabenbelege | USt-Saldo {{ formatCurrency(summary.taxBalance) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.bwa-summary-top {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 0.75rem;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bwa-summary-period {
|
||||||
|
margin: 0;
|
||||||
|
font-weight: 700;
|
||||||
|
color: rgb(17 24 39);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bwa-summary-range,
|
||||||
|
.bwa-summary-meta {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
color: rgb(107 114 128);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bwa-summary-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(0, 1fr) auto;
|
||||||
|
gap: 0.75rem;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bwa-summary-label {
|
||||||
|
color: rgb(55 65 81);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bwa-summary-value {
|
||||||
|
font-weight: 700;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.dark) .bwa-summary-period {
|
||||||
|
color: rgb(243 244 246);
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.dark) .bwa-summary-range,
|
||||||
|
:deep(.dark) .bwa-summary-meta,
|
||||||
|
:deep(.dark) .bwa-summary-label {
|
||||||
|
color: rgb(156 163 175);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -34,21 +34,21 @@ const monthItems = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
const accountColumns = [
|
const accountColumns = [
|
||||||
{ accessorKey: "number", header: "Nummer" },
|
{ accessorKey: "gross", header: "Brutto" },
|
||||||
{ accessorKey: "label", header: "Konto" },
|
|
||||||
{ accessorKey: "bookings", header: "Buchungen" },
|
|
||||||
{ accessorKey: "net", header: "Netto" },
|
{ accessorKey: "net", header: "Netto" },
|
||||||
{ accessorKey: "tax", header: "Steuer" },
|
{ accessorKey: "tax", header: "Steuer" },
|
||||||
{ accessorKey: "gross", header: "Brutto" }
|
{ accessorKey: "number", header: "Nummer" },
|
||||||
|
{ accessorKey: "label", header: "Konto" },
|
||||||
|
{ accessorKey: "bookings", header: "Buchungen" }
|
||||||
]
|
]
|
||||||
|
|
||||||
const ownAccountColumns = [
|
const ownAccountColumns = [
|
||||||
|
{ accessorKey: "balance", header: "Saldo" },
|
||||||
|
{ accessorKey: "expenses", header: "Ausgaben" },
|
||||||
|
{ accessorKey: "income", header: "Einnahmen" },
|
||||||
{ accessorKey: "number", header: "Nummer" },
|
{ accessorKey: "number", header: "Nummer" },
|
||||||
{ accessorKey: "label", header: "Konto" },
|
{ accessorKey: "label", header: "Konto" },
|
||||||
{ accessorKey: "bookings", header: "Buchungen" },
|
{ accessorKey: "bookings", header: "Buchungen" }
|
||||||
{ accessorKey: "income", header: "Einnahmen" },
|
|
||||||
{ accessorKey: "expenses", header: "Ausgaben" },
|
|
||||||
{ accessorKey: "balance", header: "Saldo" }
|
|
||||||
]
|
]
|
||||||
|
|
||||||
const isRelevantOutputDocument = (doc: any) => {
|
const isRelevantOutputDocument = (doc: any) => {
|
||||||
@@ -148,18 +148,36 @@ const filteredStatementAllocations = computed(() => {
|
|||||||
return statementAllocations.value.filter((allocation) => matchesSelectedPeriod(getStatementDate(allocation)))
|
return statementAllocations.value.filter((allocation) => matchesSelectedPeriod(getStatementDate(allocation)))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const filteredAccountStatementAllocations = computed(() => {
|
||||||
|
return filteredStatementAllocations.value.filter((allocation) => allocation.account !== null && allocation.account !== undefined)
|
||||||
|
})
|
||||||
|
|
||||||
const incomeTotal = computed(() => {
|
const incomeTotal = computed(() => {
|
||||||
return Number(filteredDocuments.value.reduce((sum, doc) => sum + computeDocumentNet(doc), 0).toFixed(2))
|
return Number(filteredDocuments.value.reduce((sum, doc) => sum + computeDocumentNet(doc), 0).toFixed(2))
|
||||||
})
|
})
|
||||||
|
|
||||||
const expenseNetTotal = computed(() => {
|
const expenseNetTotal = computed(() => {
|
||||||
return Number(filteredIncomingInvoices.value.reduce((sum, invoice) => {
|
const invoiceExpenses = filteredIncomingInvoices.value.reduce((sum, invoice) => {
|
||||||
return sum + (invoice.accounts || []).reduce((accountSum: number, account: any) => accountSum + Number(account.amountNet || 0), 0)
|
return sum + (invoice.accounts || []).reduce((accountSum: number, account: any) => accountSum + Number(account.amountNet || 0), 0)
|
||||||
}, 0).toFixed(2))
|
}, 0)
|
||||||
|
|
||||||
|
const directAccountExpenses = filteredAccountStatementAllocations.value.reduce((sum, allocation) => {
|
||||||
|
const amount = Number(allocation.amount || 0)
|
||||||
|
return amount < 0 ? sum + Math.abs(amount) : sum
|
||||||
|
}, 0)
|
||||||
|
|
||||||
|
return Number((invoiceExpenses + directAccountExpenses).toFixed(2))
|
||||||
})
|
})
|
||||||
|
|
||||||
const expenseGrossTotal = computed(() => {
|
const expenseGrossTotal = computed(() => {
|
||||||
return Number(filteredIncomingInvoices.value.reduce((sum, invoice) => sum + computeIncomingInvoiceGross(invoice), 0).toFixed(2))
|
const invoiceExpenses = filteredIncomingInvoices.value.reduce((sum, invoice) => sum + computeIncomingInvoiceGross(invoice), 0)
|
||||||
|
|
||||||
|
const directAccountExpenses = filteredAccountStatementAllocations.value.reduce((sum, allocation) => {
|
||||||
|
const amount = Number(allocation.amount || 0)
|
||||||
|
return amount < 0 ? sum + Math.abs(amount) : sum
|
||||||
|
}, 0)
|
||||||
|
|
||||||
|
return Number((invoiceExpenses + directAccountExpenses).toFixed(2))
|
||||||
})
|
})
|
||||||
|
|
||||||
const taxSummary = computed(() => {
|
const taxSummary = computed(() => {
|
||||||
@@ -201,14 +219,42 @@ const operatingResult = computed(() => {
|
|||||||
return Number((incomeTotal.value - expenseNetTotal.value).toFixed(2))
|
return Number((incomeTotal.value - expenseNetTotal.value).toFixed(2))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const incomeDocumentCount = computed(() => filteredDocuments.value.length)
|
||||||
|
const expenseDocumentCount = computed(() => {
|
||||||
|
return filteredIncomingInvoices.value.length + filteredAccountStatementAllocations.value.length
|
||||||
|
})
|
||||||
|
|
||||||
const accountRows = computed(() => {
|
const accountRows = computed(() => {
|
||||||
return accounts.value
|
return accounts.value
|
||||||
.map((account) => {
|
.map((account) => {
|
||||||
const bookings = filteredIncomingInvoices.value.flatMap((invoice) => {
|
const invoiceBookings = filteredIncomingInvoices.value.flatMap((invoice) => {
|
||||||
return (invoice.accounts || [])
|
return (invoice.accounts || [])
|
||||||
.filter((invoiceAccount: any) => sameId(invoiceAccount.account?.id || invoiceAccount.account, account.id))
|
.filter((invoiceAccount: any) => sameId(invoiceAccount.account?.id || invoiceAccount.account, account.id))
|
||||||
|
.map((invoiceAccount: any) => ({
|
||||||
|
type: "incominginvoice",
|
||||||
|
amountNet: Number(invoiceAccount.amountNet || 0),
|
||||||
|
amountTax: Number(invoiceAccount.amountTax || 0),
|
||||||
|
amountGross: Number.isFinite(Number(invoiceAccount.amountGross))
|
||||||
|
? Number(invoiceAccount.amountGross)
|
||||||
|
: Number(invoiceAccount.amountNet || 0) + Number(invoiceAccount.amountTax || 0)
|
||||||
|
}))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const directBookings = filteredAccountStatementAllocations.value
|
||||||
|
.filter((allocation) => sameId(allocation.account?.id || allocation.account, account.id))
|
||||||
|
.map((allocation) => {
|
||||||
|
const amount = Number(allocation.amount || 0)
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: "statementallocation",
|
||||||
|
amountNet: amount,
|
||||||
|
amountTax: 0,
|
||||||
|
amountGross: amount
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const bookings = [...invoiceBookings, ...directBookings]
|
||||||
|
|
||||||
if (bookings.length === 0) {
|
if (bookings.length === 0) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
@@ -231,7 +277,7 @@ const accountRows = computed(() => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.sort((left: any, right: any) => Number(right.gross) - Number(left.gross))
|
.sort((left: any, right: any) => Math.abs(Number(right.gross)) - Math.abs(Number(left.gross)))
|
||||||
})
|
})
|
||||||
|
|
||||||
const ownAccountRows = computed(() => {
|
const ownAccountRows = computed(() => {
|
||||||
@@ -315,16 +361,7 @@ onMounted(setupPage)
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<UDashboardNavbar title="BWA">
|
<UDashboardNavbar title="BWA">
|
||||||
<template #right>
|
|
||||||
<UButton
|
|
||||||
icon="i-heroicons-arrow-path"
|
|
||||||
variant="outline"
|
|
||||||
:loading="loading"
|
|
||||||
@click="setupPage"
|
|
||||||
>
|
|
||||||
Aktualisieren
|
|
||||||
</UButton>
|
|
||||||
</template>
|
|
||||||
</UDashboardNavbar>
|
</UDashboardNavbar>
|
||||||
|
|
||||||
<UDashboardPanelContent class="min-w-0 space-y-6 overflow-x-hidden overflow-y-auto p-4 md:p-6">
|
<UDashboardPanelContent class="min-w-0 space-y-6 overflow-x-hidden overflow-y-auto p-4 md:p-6">
|
||||||
@@ -350,103 +387,121 @@ onMounted(setupPage)
|
|||||||
</UFormField>
|
</UFormField>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="grid min-w-0 gap-4 md:grid-cols-2 xl:grid-cols-4">
|
<div class="grid min-w-0 gap-4 md:grid-cols-2 xl:grid-cols-4">
|
||||||
<UCard class="min-w-0">
|
<UCard class="min-w-0">
|
||||||
<div class="text-sm text-gray-500 dark:text-gray-400">Einnahmen netto</div>
|
<div class="text-sm text-gray-500 dark:text-gray-400">Einnahmen netto</div>
|
||||||
<div class="mt-2 text-2xl font-semibold">{{ useCurrency(incomeTotal) }}</div>
|
<div class="mt-2 text-2xl font-semibold">{{ useCurrency(incomeTotal) }}</div>
|
||||||
<div class="mt-2 text-sm text-gray-500 dark:text-gray-400">
|
<div class="mt-2 text-sm text-gray-500 dark:text-gray-400">
|
||||||
{{ filteredDocuments.length }} gebuchte Ausgangsbelege
|
{{ incomeDocumentCount }} gebuchte Ausgangsbelege
|
||||||
</div>
|
</div>
|
||||||
</UCard>
|
</UCard>
|
||||||
|
|
||||||
<UCard class="min-w-0">
|
<UCard class="min-w-0">
|
||||||
<div class="text-sm text-gray-500 dark:text-gray-400">Ausgaben netto</div>
|
<div class="text-sm text-gray-500 dark:text-gray-400">Ausgaben netto</div>
|
||||||
<div class="mt-2 text-2xl font-semibold">{{ useCurrency(expenseNetTotal) }}</div>
|
<div class="mt-2 text-2xl font-semibold">{{ useCurrency(expenseNetTotal) }}</div>
|
||||||
<div class="mt-2 text-sm text-gray-500 dark:text-gray-400">
|
<div class="mt-2 text-sm text-gray-500 dark:text-gray-400">
|
||||||
Brutto: {{ useCurrency(expenseGrossTotal) }}
|
Brutto: {{ useCurrency(expenseGrossTotal) }}
|
||||||
</div>
|
</div>
|
||||||
</UCard>
|
</UCard>
|
||||||
|
|
||||||
<UCard class="min-w-0">
|
<UCard class="min-w-0">
|
||||||
<div class="text-sm text-gray-500 dark:text-gray-400">Betriebsergebnis</div>
|
<div class="text-sm text-gray-500 dark:text-gray-400">Einnahmen Belege</div>
|
||||||
<div class="mt-2 text-2xl font-semibold" :class="operatingResult >= 0 ? 'text-primary-500' : 'text-error'">
|
<div class="mt-2 text-2xl font-semibold">{{ incomeDocumentCount }}</div>
|
||||||
{{ useCurrency(operatingResult) }}
|
<div class="mt-2 text-sm text-gray-500 dark:text-gray-400">
|
||||||
</div>
|
Ausgangsbelege im Zeitraum
|
||||||
<div class="mt-2 text-sm text-gray-500 dark:text-gray-400">
|
</div>
|
||||||
Einnahmen minus Ausgaben netto
|
</UCard>
|
||||||
</div>
|
|
||||||
</UCard>
|
|
||||||
|
|
||||||
<UCard class="min-w-0">
|
<UCard class="min-w-0">
|
||||||
<div class="text-sm text-gray-500 dark:text-gray-400">USt-Saldo</div>
|
<div class="text-sm text-gray-500 dark:text-gray-400">Ausgaben Belege</div>
|
||||||
<div class="mt-2 text-2xl font-semibold" :class="taxSummary.balance >= 0 ? 'text-amber-600 dark:text-amber-400' : 'text-primary-500'">
|
<div class="mt-2 text-2xl font-semibold">{{ expenseDocumentCount }}</div>
|
||||||
{{ useCurrency(taxSummary.balance) }}
|
<div class="mt-2 text-sm text-gray-500 dark:text-gray-400">
|
||||||
</div>
|
Eingangsbelege plus direkte Buchungen
|
||||||
<div class="mt-2 text-sm text-gray-500 dark:text-gray-400">
|
</div>
|
||||||
USt {{ useCurrency(taxSummary.outputTax) }} | Vorsteuer {{ useCurrency(taxSummary.inputTax) }}
|
</UCard>
|
||||||
</div>
|
</div>
|
||||||
</UCard>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="grid min-w-0 gap-4 xl:grid-cols-2">
|
<div class="grid min-w-0 gap-4 md:grid-cols-2">
|
||||||
<UCard class="min-w-0">
|
<UCard class="min-w-0">
|
||||||
<template #header>
|
<div class="text-sm text-gray-500 dark:text-gray-400">Betriebsergebnis</div>
|
||||||
<div class="font-semibold">USt-Details</div>
|
<div class="mt-2 text-2xl font-semibold" :class="operatingResult >= 0 ? 'text-primary-500' : 'text-error'">
|
||||||
</template>
|
{{ useCurrency(operatingResult) }}
|
||||||
|
</div>
|
||||||
|
<div class="mt-2 text-sm text-gray-500 dark:text-gray-400">
|
||||||
|
Einnahmen minus Ausgaben netto
|
||||||
|
</div>
|
||||||
|
</UCard>
|
||||||
|
|
||||||
<div class="space-y-3 text-sm">
|
<UCard class="min-w-0">
|
||||||
<div class="flex items-center justify-between">
|
<div class="text-sm text-gray-500 dark:text-gray-400">USt-Saldo</div>
|
||||||
<span>Netto 19% Ausgangsbelege</span>
|
<div class="mt-2 text-2xl font-semibold" :class="taxSummary.balance >= 0 ? 'text-amber-600 dark:text-amber-400' : 'text-primary-500'">
|
||||||
<span>{{ useCurrency(taxSummary.output.net19) }}</span>
|
{{ useCurrency(taxSummary.balance) }}
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center justify-between">
|
<div class="mt-2 text-sm text-gray-500 dark:text-gray-400">
|
||||||
<span>USt 19%</span>
|
USt {{ useCurrency(taxSummary.outputTax) }} | Vorsteuer {{ useCurrency(taxSummary.inputTax) }}
|
||||||
<span>{{ useCurrency(taxSummary.output.tax19) }}</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center justify-between">
|
</UCard>
|
||||||
<span>Netto 7% Ausgangsbelege</span>
|
</div>
|
||||||
<span>{{ useCurrency(taxSummary.output.net7) }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<span>USt 7%</span>
|
|
||||||
<span>{{ useCurrency(taxSummary.output.tax7) }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<span>Steuerfrei</span>
|
|
||||||
<span>{{ useCurrency(taxSummary.output.net0 + taxSummary.input.net0) }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</UCard>
|
|
||||||
|
|
||||||
<UCard class="min-w-0">
|
<div class="grid min-w-0 gap-4 xl:grid-cols-2">
|
||||||
<template #header>
|
<UCard class="min-w-0">
|
||||||
<div class="font-semibold">Vorsteuer-Details</div>
|
<template #header>
|
||||||
</template>
|
<div class="font-semibold">USt-Details</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<div class="space-y-3 text-sm">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<span>Netto 19% Ausgangsbelege</span>
|
||||||
|
<span>{{ useCurrency(taxSummary.output.net19) }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<span>USt 19%</span>
|
||||||
|
<span>{{ useCurrency(taxSummary.output.tax19) }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<span>Netto 7% Ausgangsbelege</span>
|
||||||
|
<span>{{ useCurrency(taxSummary.output.net7) }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<span>USt 7%</span>
|
||||||
|
<span>{{ useCurrency(taxSummary.output.tax7) }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<span>Steuerfrei</span>
|
||||||
|
<span>{{ useCurrency(taxSummary.output.net0 + taxSummary.input.net0) }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</UCard>
|
||||||
|
|
||||||
<div class="space-y-3 text-sm">
|
<UCard class="min-w-0">
|
||||||
<div class="flex items-center justify-between">
|
<template #header>
|
||||||
<span>Netto 19% Eingangsbelege</span>
|
<div class="font-semibold">Vorsteuer-Details</div>
|
||||||
<span>{{ useCurrency(taxSummary.input.net19) }}</span>
|
</template>
|
||||||
|
|
||||||
|
<div class="space-y-3 text-sm">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<span>Netto 19% Eingangsbelege</span>
|
||||||
|
<span>{{ useCurrency(taxSummary.input.net19) }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<span>Vorsteuer 19%</span>
|
||||||
|
<span>{{ useCurrency(taxSummary.input.tax19) }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<span>Netto 7% Eingangsbelege</span>
|
||||||
|
<span>{{ useCurrency(taxSummary.input.net7) }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<span>Vorsteuer 7%</span>
|
||||||
|
<span>{{ useCurrency(taxSummary.input.tax7) }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<span>Steuerfrei</span>
|
||||||
|
<span>{{ useCurrency(taxSummary.input.net0) }}</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center justify-between">
|
</UCard>
|
||||||
<span>Vorsteuer 19%</span>
|
</div>
|
||||||
<span>{{ useCurrency(taxSummary.input.tax19) }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<span>Netto 7% Eingangsbelege</span>
|
|
||||||
<span>{{ useCurrency(taxSummary.input.net7) }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<span>Vorsteuer 7%</span>
|
|
||||||
<span>{{ useCurrency(taxSummary.input.tax7) }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<span>Steuerfrei</span>
|
|
||||||
<span>{{ useCurrency(taxSummary.input.net0) }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</UCard>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="grid min-w-0 gap-4 xl:grid-cols-2">
|
<div class="grid min-w-0 gap-4 xl:grid-cols-2">
|
||||||
<UCard class="min-w-0">
|
<UCard class="min-w-0">
|
||||||
|
|||||||
@@ -126,164 +126,162 @@ onMounted(loadData)
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<UDashboardNavbar title="USt-Auswertung">
|
||||||
<UDashboardNavbar title="USt-Auswertung">
|
<template #right>
|
||||||
<template #right>
|
<UButton
|
||||||
<UButton
|
icon="i-heroicons-arrow-path"
|
||||||
icon="i-heroicons-arrow-path"
|
variant="outline"
|
||||||
variant="outline"
|
@click="loadData"
|
||||||
@click="loadData"
|
:loading="loading"
|
||||||
:loading="loading"
|
>
|
||||||
|
Aktualisieren
|
||||||
|
</UButton>
|
||||||
|
</template>
|
||||||
|
</UDashboardNavbar>
|
||||||
|
|
||||||
|
<UDashboardPanelContent class="p-4 md:p-6">
|
||||||
|
<div class="mb-6 flex flex-col gap-2">
|
||||||
|
<h2 class="text-lg font-semibold text-gray-900 dark:text-white">
|
||||||
|
Aktueller Zeitraum: {{ currentPeriod?.label }}
|
||||||
|
</h2>
|
||||||
|
<p class="text-sm text-gray-500 dark:text-gray-400">
|
||||||
|
Intervall: {{ periodType === "monthly" ? "monatlich" : periodType === "quarterly" ? "quartalsweise" : "jährlich" }}.
|
||||||
|
Berücksichtigt werden gebuchte Ausgangsrechnungen, Abschlags- und Stornorechnungen sowie gebuchte Eingangsbelege mit Datum.
|
||||||
|
</p>
|
||||||
|
<p v-if="currentPeriod" class="text-sm text-gray-500 dark:text-gray-400">
|
||||||
|
{{ currentPeriod.range }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="currentPeriod" class="grid gap-4 md:grid-cols-3">
|
||||||
|
<UCard>
|
||||||
|
<div class="text-sm text-gray-500 dark:text-gray-400">Berechnete USt</div>
|
||||||
|
<div class="mt-2 text-2xl font-semibold text-gray-900 dark:text-white">
|
||||||
|
{{ formatCurrency(currentPeriod.outputTax) }}
|
||||||
|
</div>
|
||||||
|
<div class="mt-3 text-sm text-gray-500 dark:text-gray-400">
|
||||||
|
19%: {{ formatCurrency(currentPeriod.output.tax19) }} | 7%: {{ formatCurrency(currentPeriod.output.tax7) }}
|
||||||
|
</div>
|
||||||
|
</UCard>
|
||||||
|
|
||||||
|
<UCard>
|
||||||
|
<div class="text-sm text-gray-500 dark:text-gray-400">Vorsteuer</div>
|
||||||
|
<div class="mt-2 text-2xl font-semibold text-gray-900 dark:text-white">
|
||||||
|
{{ formatCurrency(currentPeriod.inputTax) }}
|
||||||
|
</div>
|
||||||
|
<div class="mt-3 text-sm text-gray-500 dark:text-gray-400">
|
||||||
|
19%: {{ formatCurrency(currentPeriod.input.tax19) }} | 7%: {{ formatCurrency(currentPeriod.input.tax7) }}
|
||||||
|
</div>
|
||||||
|
</UCard>
|
||||||
|
|
||||||
|
<UCard>
|
||||||
|
<div class="text-sm text-gray-500 dark:text-gray-400">Verrechnetes Ergebnis</div>
|
||||||
|
<div
|
||||||
|
class="mt-2 text-2xl font-semibold"
|
||||||
|
:class="currentPeriod.balance >= 0 ? 'text-amber-600 dark:text-amber-400' : 'text-emerald-600 dark:text-emerald-400'"
|
||||||
>
|
>
|
||||||
Aktualisieren
|
{{ formatCurrency(currentPeriod.balance) }}
|
||||||
</UButton>
|
</div>
|
||||||
</template>
|
<div class="mt-3 text-sm text-gray-500 dark:text-gray-400">
|
||||||
</UDashboardNavbar>
|
{{ currentPeriod.outputCount }} Ausgangsbelege | {{ currentPeriod.inputCount }} Eingangsbelege
|
||||||
|
</div>
|
||||||
|
</UCard>
|
||||||
|
</div>
|
||||||
|
|
||||||
<UDashboardPanelContent class="p-4 md:p-6">
|
<div v-if="currentPeriod" class="mt-6 grid gap-4 xl:grid-cols-2">
|
||||||
<div class="mb-6 flex flex-col gap-2">
|
<UCard>
|
||||||
<h2 class="text-lg font-semibold text-gray-900 dark:text-white">
|
|
||||||
Aktueller Zeitraum: {{ currentPeriod?.label }}
|
|
||||||
</h2>
|
|
||||||
<p class="text-sm text-gray-500 dark:text-gray-400">
|
|
||||||
Intervall: {{ periodType === "monthly" ? "monatlich" : periodType === "quarterly" ? "quartalsweise" : "jährlich" }}.
|
|
||||||
Berücksichtigt werden gebuchte Ausgangsrechnungen, Abschlags- und Stornorechnungen sowie gebuchte Eingangsbelege mit Datum.
|
|
||||||
</p>
|
|
||||||
<p v-if="currentPeriod" class="text-sm text-gray-500 dark:text-gray-400">
|
|
||||||
{{ currentPeriod.range }}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-if="currentPeriod" class="grid gap-4 md:grid-cols-3">
|
|
||||||
<UCard>
|
|
||||||
<div class="text-sm text-gray-500 dark:text-gray-400">Berechnete USt</div>
|
|
||||||
<div class="mt-2 text-2xl font-semibold text-gray-900 dark:text-white">
|
|
||||||
{{ formatCurrency(currentPeriod.outputTax) }}
|
|
||||||
</div>
|
|
||||||
<div class="mt-3 text-sm text-gray-500 dark:text-gray-400">
|
|
||||||
19%: {{ formatCurrency(currentPeriod.output.tax19) }} | 7%: {{ formatCurrency(currentPeriod.output.tax7) }}
|
|
||||||
</div>
|
|
||||||
</UCard>
|
|
||||||
|
|
||||||
<UCard>
|
|
||||||
<div class="text-sm text-gray-500 dark:text-gray-400">Vorsteuer</div>
|
|
||||||
<div class="mt-2 text-2xl font-semibold text-gray-900 dark:text-white">
|
|
||||||
{{ formatCurrency(currentPeriod.inputTax) }}
|
|
||||||
</div>
|
|
||||||
<div class="mt-3 text-sm text-gray-500 dark:text-gray-400">
|
|
||||||
19%: {{ formatCurrency(currentPeriod.input.tax19) }} | 7%: {{ formatCurrency(currentPeriod.input.tax7) }}
|
|
||||||
</div>
|
|
||||||
</UCard>
|
|
||||||
|
|
||||||
<UCard>
|
|
||||||
<div class="text-sm text-gray-500 dark:text-gray-400">Verrechnetes Ergebnis</div>
|
|
||||||
<div
|
|
||||||
class="mt-2 text-2xl font-semibold"
|
|
||||||
:class="currentPeriod.balance >= 0 ? 'text-amber-600 dark:text-amber-400' : 'text-emerald-600 dark:text-emerald-400'"
|
|
||||||
>
|
|
||||||
{{ formatCurrency(currentPeriod.balance) }}
|
|
||||||
</div>
|
|
||||||
<div class="mt-3 text-sm text-gray-500 dark:text-gray-400">
|
|
||||||
{{ currentPeriod.outputCount }} Ausgangsbelege | {{ currentPeriod.inputCount }} Eingangsbelege
|
|
||||||
</div>
|
|
||||||
</UCard>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-if="currentPeriod" class="mt-6 grid gap-4 xl:grid-cols-2">
|
|
||||||
<UCard>
|
|
||||||
<template #header>
|
|
||||||
<div class="font-semibold">Ausgangsrechnungen</div>
|
|
||||||
</template>
|
|
||||||
<div class="space-y-3 text-sm">
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<span>Netto 19%</span>
|
|
||||||
<span>{{ formatCurrency(currentPeriod.output.net19) }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<span>USt 19%</span>
|
|
||||||
<span>{{ formatCurrency(currentPeriod.output.tax19) }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<span>Netto 7%</span>
|
|
||||||
<span>{{ formatCurrency(currentPeriod.output.net7) }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<span>USt 7%</span>
|
|
||||||
<span>{{ formatCurrency(currentPeriod.output.tax7) }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<span>Netto 0%</span>
|
|
||||||
<span>{{ formatCurrency(currentPeriod.output.net0) }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</UCard>
|
|
||||||
|
|
||||||
<UCard>
|
|
||||||
<template #header>
|
|
||||||
<div class="font-semibold">Eingangsbelege</div>
|
|
||||||
</template>
|
|
||||||
<div class="space-y-3 text-sm">
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<span>Netto 19%</span>
|
|
||||||
<span>{{ formatCurrency(currentPeriod.input.net19) }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<span>Vorsteuer 19%</span>
|
|
||||||
<span>{{ formatCurrency(currentPeriod.input.tax19) }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<span>Netto 7%</span>
|
|
||||||
<span>{{ formatCurrency(currentPeriod.input.net7) }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<span>Vorsteuer 7%</span>
|
|
||||||
<span>{{ formatCurrency(currentPeriod.input.tax7) }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<span>Netto 0%</span>
|
|
||||||
<span>{{ formatCurrency(currentPeriod.input.net0) }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</UCard>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<UCard class="mt-6">
|
|
||||||
<template #header>
|
<template #header>
|
||||||
<div class="font-semibold">Aktueller und vorherige Zeiträume</div>
|
<div class="font-semibold">Ausgangsrechnungen</div>
|
||||||
|
</template>
|
||||||
|
<div class="space-y-3 text-sm">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<span>Netto 19%</span>
|
||||||
|
<span>{{ formatCurrency(currentPeriod.output.net19) }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<span>USt 19%</span>
|
||||||
|
<span>{{ formatCurrency(currentPeriod.output.tax19) }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<span>Netto 7%</span>
|
||||||
|
<span>{{ formatCurrency(currentPeriod.output.net7) }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<span>USt 7%</span>
|
||||||
|
<span>{{ formatCurrency(currentPeriod.output.tax7) }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<span>Netto 0%</span>
|
||||||
|
<span>{{ formatCurrency(currentPeriod.output.net0) }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</UCard>
|
||||||
|
|
||||||
|
<UCard>
|
||||||
|
<template #header>
|
||||||
|
<div class="font-semibold">Eingangsbelege</div>
|
||||||
|
</template>
|
||||||
|
<div class="space-y-3 text-sm">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<span>Netto 19%</span>
|
||||||
|
<span>{{ formatCurrency(currentPeriod.input.net19) }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<span>Vorsteuer 19%</span>
|
||||||
|
<span>{{ formatCurrency(currentPeriod.input.tax19) }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<span>Netto 7%</span>
|
||||||
|
<span>{{ formatCurrency(currentPeriod.input.net7) }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<span>Vorsteuer 7%</span>
|
||||||
|
<span>{{ formatCurrency(currentPeriod.input.tax7) }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<span>Netto 0%</span>
|
||||||
|
<span>{{ formatCurrency(currentPeriod.input.net0) }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</UCard>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<UCard class="mt-6">
|
||||||
|
<template #header>
|
||||||
|
<div class="font-semibold">Aktueller und vorherige Zeiträume</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<UTable
|
||||||
|
:columns="normalizeTableColumns(columns)"
|
||||||
|
:data="periods"
|
||||||
|
:loading="loading"
|
||||||
|
:empty="{ icon: 'i-heroicons-calculator', label: 'Keine Daten für die USt-Auswertung vorhanden' }"
|
||||||
|
>
|
||||||
|
<template #label-cell="{ row }">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span>{{ row.original.label }}</span>
|
||||||
|
<UBadge v-if="row.original.isCurrent" color="primary" variant="soft">Aktuell</UBadge>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<UTable
|
<template #outputTax-cell="{ row }">
|
||||||
:columns="normalizeTableColumns(columns)"
|
{{ formatCurrency(row.original.outputTax) }}
|
||||||
:data="periods"
|
</template>
|
||||||
:loading="loading"
|
|
||||||
:empty="{ icon: 'i-heroicons-calculator', label: 'Keine Daten für die USt-Auswertung vorhanden' }"
|
|
||||||
>
|
|
||||||
<template #label-cell="{ row }">
|
|
||||||
<div class="flex items-center gap-2">
|
|
||||||
<span>{{ row.original.label }}</span>
|
|
||||||
<UBadge v-if="row.original.isCurrent" color="primary" variant="soft">Aktuell</UBadge>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #outputTax-cell="{ row }">
|
<template #inputTax-cell="{ row }">
|
||||||
{{ formatCurrency(row.original.outputTax) }}
|
{{ formatCurrency(row.original.inputTax) }}
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #inputTax-cell="{ row }">
|
<template #balance-cell="{ row }">
|
||||||
{{ formatCurrency(row.original.inputTax) }}
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #balance-cell="{ row }">
|
|
||||||
<span :class="row.original.balance >= 0 ? 'text-amber-600 dark:text-amber-400 font-medium' : 'text-emerald-600 dark:text-emerald-400 font-medium'">
|
<span :class="row.original.balance >= 0 ? 'text-amber-600 dark:text-amber-400 font-medium' : 'text-emerald-600 dark:text-emerald-400 font-medium'">
|
||||||
{{ formatCurrency(row.original.balance) }}
|
{{ formatCurrency(row.original.balance) }}
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #documents-cell="{ row }">
|
<template #documents-cell="{ row }">
|
||||||
{{ row.original.outputCount }} / {{ row.original.inputCount }}
|
{{ row.original.outputCount }} / {{ row.original.inputCount }}
|
||||||
</template>
|
</template>
|
||||||
</UTable>
|
</UTable>
|
||||||
</UCard>
|
</UCard>
|
||||||
</UDashboardPanelContent>
|
</UDashboardPanelContent>
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -86,7 +86,8 @@ const documentTypeItems = computed(() => Object.keys(dataStore.documentTypesForC
|
|||||||
const taxTypeItems = [
|
const taxTypeItems = [
|
||||||
{ key: 'Standard', label: 'Standard' },
|
{ key: 'Standard', label: 'Standard' },
|
||||||
{ key: '13b UStG', label: '13b UStG' },
|
{ key: '13b UStG', label: '13b UStG' },
|
||||||
{ key: '19 UStG', label: '19 UStG Kleinunternehmer' }
|
{ key: '19 UStG', label: '19 UStG Kleinunternehmer' },
|
||||||
|
{ key: '12.3 UStG', label: '12.3 UStG' }
|
||||||
]
|
]
|
||||||
const deliveryDateTypeItems = ['Lieferdatum', 'Lieferzeitraum', 'Leistungsdatum', 'Leistungszeitraum', 'Kein Lieferdatum anzeigen']
|
const deliveryDateTypeItems = ['Lieferdatum', 'Lieferzeitraum', 'Leistungsdatum', 'Leistungszeitraum', 'Kein Lieferdatum anzeigen']
|
||||||
const paymentTypeItems = [
|
const paymentTypeItems = [
|
||||||
@@ -115,6 +116,11 @@ const formatNumberLikeValue = (value) => {
|
|||||||
return '-'
|
return '-'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const normalizeTaxTypeValue = (value) => {
|
||||||
|
const normalized = typeof value === "string" ? value.trim() : value
|
||||||
|
return taxTypeItems.find((item) => item.key === normalized)?.key || "Standard"
|
||||||
|
}
|
||||||
|
|
||||||
const getCalendarValue = (value) => {
|
const getCalendarValue = (value) => {
|
||||||
if (!value) return undefined
|
if (!value) return undefined
|
||||||
|
|
||||||
@@ -174,6 +180,7 @@ const setupPage = async () => {
|
|||||||
if (route.params.id) {
|
if (route.params.id) {
|
||||||
console.log(route.params)
|
console.log(route.params)
|
||||||
itemInfo.value = await useEntities("createddocuments").selectSingle(route.params.id,'',false)
|
itemInfo.value = await useEntities("createddocuments").selectSingle(route.params.id,'',false)
|
||||||
|
itemInfo.value.taxType = normalizeTaxTypeValue(itemInfo.value.taxType)
|
||||||
await setContactPersonData()
|
await setContactPersonData()
|
||||||
checkCompatibilityWithInputPrice()
|
checkCompatibilityWithInputPrice()
|
||||||
}
|
}
|
||||||
@@ -357,7 +364,7 @@ const setupPage = async () => {
|
|||||||
console.log(optionsToImport)
|
console.log(optionsToImport)
|
||||||
console.log(linkedDocument)
|
console.log(linkedDocument)
|
||||||
|
|
||||||
if (optionsToImport.taxType) itemInfo.value.taxType = linkedDocument.taxType
|
if (optionsToImport.taxType) itemInfo.value.taxType = normalizeTaxTypeValue(linkedDocument.taxType)
|
||||||
if (optionsToImport.customer) itemInfo.value.customer = linkedDocument.customer
|
if (optionsToImport.customer) itemInfo.value.customer = linkedDocument.customer
|
||||||
if (optionsToImport.letterhead) itemInfo.value.letterhead = linkedDocument.letterhead
|
if (optionsToImport.letterhead) itemInfo.value.letterhead = linkedDocument.letterhead
|
||||||
if (optionsToImport.contact) itemInfo.value.contact = linkedDocument.contact
|
if (optionsToImport.contact) itemInfo.value.contact = linkedDocument.contact
|
||||||
@@ -382,7 +389,7 @@ const setupPage = async () => {
|
|||||||
|
|
||||||
if (process.dev) console.log(linkedDocument)
|
if (process.dev) console.log(linkedDocument)
|
||||||
|
|
||||||
itemInfo.value.taxType = linkedDocument.taxType
|
itemInfo.value.taxType = normalizeTaxTypeValue(linkedDocument.taxType)
|
||||||
itemInfo.value.customer = linkedDocument.customer
|
itemInfo.value.customer = linkedDocument.customer
|
||||||
await setCustomerData(null, true)
|
await setCustomerData(null, true)
|
||||||
itemInfo.value.letterhead = linkedDocument.letterhead
|
itemInfo.value.letterhead = linkedDocument.letterhead
|
||||||
@@ -545,7 +552,7 @@ const setCustomerData = async (customerId, loadOnlyAdress = false) => {
|
|||||||
if (!loadOnlyAdress && customer.customPaymentDays) itemInfo.value.paymentDays = customer.customPaymentDays
|
if (!loadOnlyAdress && customer.customPaymentDays) itemInfo.value.paymentDays = customer.customPaymentDays
|
||||||
if (!loadOnlyAdress && customer.custom_payment_type) itemInfo.value.payment_type = customer.custom_payment_type
|
if (!loadOnlyAdress && customer.custom_payment_type) itemInfo.value.payment_type = customer.custom_payment_type
|
||||||
if (!loadOnlyAdress) {
|
if (!loadOnlyAdress) {
|
||||||
itemInfo.value.taxType = customer.customTaxType || "Standard"
|
itemInfo.value.taxType = normalizeTaxTypeValue(customer.customTaxType)
|
||||||
setTaxType()
|
setTaxType()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1459,7 +1466,7 @@ const saveDocument = async (state, resetup = false) => {
|
|||||||
|
|
||||||
let createData = {
|
let createData = {
|
||||||
type: itemInfo.value.type,
|
type: itemInfo.value.type,
|
||||||
taxType: ['invoices', 'cancellationInvoices', 'advanceInvoices', 'qoutes', 'confirmationOrders'].includes(itemInfo.value.type) ? itemInfo.value.taxType : null,
|
taxType: ['invoices', 'cancellationInvoices', 'advanceInvoices', 'quotes', 'confirmationOrders'].includes(itemInfo.value.type) ? normalizeTaxTypeValue(itemInfo.value.taxType) : null,
|
||||||
state: itemInfo.value.state || "Entwurf",
|
state: itemInfo.value.state || "Entwurf",
|
||||||
customer: itemInfo.value.customer,
|
customer: itemInfo.value.customer,
|
||||||
contact: itemInfo.value.contact,
|
contact: itemInfo.value.contact,
|
||||||
|
|||||||
@@ -246,7 +246,15 @@ const types = computed(() => {
|
|||||||
return templateTypes.filter((type) => selectedTypes.value.find(i => i.key === type.key))
|
return templateTypes.filter((type) => selectedTypes.value.find(i => i.key === type.key))
|
||||||
})
|
})
|
||||||
|
|
||||||
const selectItem = (item) => {
|
const unwrapSelectedRow = (itemLike) => itemLike?.original || itemLike
|
||||||
|
|
||||||
|
const selectItem = (itemLike) => {
|
||||||
|
const item = unwrapSelectedRow(itemLike)
|
||||||
|
|
||||||
|
if (!item?.id) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (item.state === "Entwurf") {
|
if (item.state === "Entwurf") {
|
||||||
router.push(`/createDocument/edit/${item.id}`)
|
router.push(`/createDocument/edit/${item.id}`)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import DisplayBankaccounts from "~/components/displayBankaccounts.vue"
|
|||||||
import DisplayProjectsInPhases from "~/components/displayProjectsInPhases.vue"
|
import DisplayProjectsInPhases from "~/components/displayProjectsInPhases.vue"
|
||||||
import DisplayOpenTasks from "~/components/displayOpenTasks.vue"
|
import DisplayOpenTasks from "~/components/displayOpenTasks.vue"
|
||||||
import DisplayTaxSummary from "~/components/displayTaxSummary.vue"
|
import DisplayTaxSummary from "~/components/displayTaxSummary.vue"
|
||||||
|
import DisplayBWASummary from "~/components/displayBWASummary.vue"
|
||||||
|
|
||||||
setPageLayout("default")
|
setPageLayout("default")
|
||||||
|
|
||||||
@@ -78,6 +79,15 @@ const DASHBOARD_WIDGETS = [
|
|||||||
defaultLayout: { x: 4, y: 7, w: 4, h: 3 },
|
defaultLayout: { x: 4, y: 7, w: 4, h: 3 },
|
||||||
minW: 3,
|
minW: 3,
|
||||||
minH: 3
|
minH: 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "bwa-summary",
|
||||||
|
title: "BWA aktuell",
|
||||||
|
description: "Einnahmen, Ausgaben und Ergebnis des aktuellen Monats",
|
||||||
|
component: markRaw(DisplayBWASummary),
|
||||||
|
defaultLayout: { x: 8, y: 7, w: 4, h: 3 },
|
||||||
|
minW: 3,
|
||||||
|
minH: 3
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -348,160 +358,158 @@ onBeforeUnmount(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<UDashboardNavbar title="Home">
|
||||||
<UDashboardNavbar title="Home">
|
<template #right>
|
||||||
<template #right>
|
<div class="flex items-center gap-2">
|
||||||
<div class="flex items-center gap-2">
|
<UButton
|
||||||
<UButton
|
|
||||||
:icon="isEditMode ? 'i-heroicons-check' : 'i-heroicons-pencil-square'"
|
:icon="isEditMode ? 'i-heroicons-check' : 'i-heroicons-pencil-square'"
|
||||||
:color="isEditMode ? 'primary' : 'gray'"
|
:color="isEditMode ? 'primary' : 'gray'"
|
||||||
:variant="isEditMode ? 'solid' : 'ghost'"
|
:variant="isEditMode ? 'solid' : 'ghost'"
|
||||||
@click="toggleEditMode"
|
@click="toggleEditMode"
|
||||||
>
|
>
|
||||||
{{ isEditMode ? "Bearbeitung beenden" : "Dashboard bearbeiten" }}
|
{{ isEditMode ? "Bearbeitung beenden" : "Dashboard bearbeiten" }}
|
||||||
</UButton>
|
</UButton>
|
||||||
<UButton
|
<UButton
|
||||||
v-if="isEditMode && hiddenWidgets.length > 0"
|
v-if="isEditMode && hiddenWidgets.length > 0"
|
||||||
icon="i-heroicons-plus"
|
icon="i-heroicons-plus"
|
||||||
color="white"
|
color="white"
|
||||||
variant="soft"
|
variant="soft"
|
||||||
@click="manageCardsOpen = true"
|
@click="manageCardsOpen = true"
|
||||||
>
|
>
|
||||||
Karte hinzufügen
|
Karte hinzufügen
|
||||||
</UButton>
|
</UButton>
|
||||||
<UButton
|
<UButton
|
||||||
v-if="isEditMode"
|
v-if="isEditMode"
|
||||||
icon="i-heroicons-squares-2x2"
|
icon="i-heroicons-squares-2x2"
|
||||||
color="gray"
|
color="gray"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
@click="manageCardsOpen = true"
|
@click="manageCardsOpen = true"
|
||||||
>
|
>
|
||||||
Karten verwalten
|
Karten verwalten
|
||||||
</UButton>
|
</UButton>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</UDashboardNavbar>
|
</UDashboardNavbar>
|
||||||
|
|
||||||
<div v-if="visibleWidgets.length > 0" ref="gridElement" class="grid-stack dashboard-grid overflow-y-auto">
|
<div v-if="visibleWidgets.length > 0" ref="gridElement" class="grid-stack dashboard-grid overflow-y-auto">
|
||||||
<div
|
<div
|
||||||
v-for="widget in visibleWidgets"
|
v-for="widget in visibleWidgets"
|
||||||
:key="widget.id"
|
:key="widget.id"
|
||||||
:class="['grid-stack-item', isEditMode ? 'dashboard-widget-editing' : '']"
|
:class="['grid-stack-item', isEditMode ? 'dashboard-widget-editing' : '']"
|
||||||
:data-widget-id="widget.id"
|
:data-widget-id="widget.id"
|
||||||
:gs-x="widget.x"
|
:gs-x="widget.x"
|
||||||
:gs-y="widget.y"
|
:gs-y="widget.y"
|
||||||
:gs-w="widget.w"
|
:gs-w="widget.w"
|
||||||
:gs-h="widget.h"
|
:gs-h="widget.h"
|
||||||
:gs-min-w="widget.minW"
|
:gs-min-w="widget.minW"
|
||||||
:gs-min-h="widget.minH"
|
:gs-min-h="widget.minH"
|
||||||
>
|
>
|
||||||
<div class="grid-stack-item-content dashboard-grid-item">
|
<div class="grid-stack-item-content dashboard-grid-item">
|
||||||
<div class="dashboard-widget-card border border-gray-200 dark:border-gray-800">
|
<div class="dashboard-widget-card border border-gray-200 dark:border-gray-800">
|
||||||
<div class="dashboard-widget-header border-b border-gray-200 dark:border-gray-800">
|
<div class="dashboard-widget-header border-b border-gray-200 dark:border-gray-800">
|
||||||
<div class="flex items-start justify-between gap-3">
|
<div class="flex items-start justify-between gap-3">
|
||||||
<div class="min-w-0">
|
<div class="min-w-0">
|
||||||
<div :class="['dashboard-widget-drag-handle font-semibold', isEditMode ? 'cursor-move' : 'cursor-default']">
|
<div :class="['dashboard-widget-drag-handle font-semibold', isEditMode ? 'cursor-move' : 'cursor-default']">
|
||||||
{{ widget.title }}
|
{{ widget.title }}
|
||||||
</div>
|
|
||||||
<p class="mt-1 text-sm">
|
|
||||||
{{ widget.description }}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div class="dashboard-widget-header-actions">
|
|
||||||
<div :id="`dashboard-widget-header-actions-${widget.id}`" class="dashboard-widget-header-target" />
|
|
||||||
<UButtonGroup v-if="isEditMode" size="xs">
|
|
||||||
<UButton
|
|
||||||
color="gray"
|
|
||||||
variant="soft"
|
|
||||||
icon="i-heroicons-arrows-pointing-out"
|
|
||||||
class="dashboard-widget-drag-handle"
|
|
||||||
/>
|
|
||||||
<UButton
|
|
||||||
color="gray"
|
|
||||||
variant="soft"
|
|
||||||
icon="i-heroicons-x-mark"
|
|
||||||
:disabled="visibleWidgets.length <= 1"
|
|
||||||
@click="removeWidget(widget.id)"
|
|
||||||
/>
|
|
||||||
</UButtonGroup>
|
|
||||||
</div>
|
</div>
|
||||||
|
<p class="mt-1 text-sm">
|
||||||
|
{{ widget.description }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="dashboard-widget-header-actions">
|
||||||
|
<div :id="`dashboard-widget-header-actions-${widget.id}`" class="dashboard-widget-header-target" />
|
||||||
|
<UButtonGroup v-if="isEditMode" size="xs">
|
||||||
|
<UButton
|
||||||
|
color="gray"
|
||||||
|
variant="soft"
|
||||||
|
icon="i-heroicons-arrows-pointing-out"
|
||||||
|
class="dashboard-widget-drag-handle"
|
||||||
|
/>
|
||||||
|
<UButton
|
||||||
|
color="gray"
|
||||||
|
variant="soft"
|
||||||
|
icon="i-heroicons-x-mark"
|
||||||
|
:disabled="visibleWidgets.length <= 1"
|
||||||
|
@click="removeWidget(widget.id)"
|
||||||
|
/>
|
||||||
|
</UButtonGroup>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="dashboard-widget-body">
|
</div>
|
||||||
<component
|
<div class="dashboard-widget-body">
|
||||||
:is="widget.component"
|
<component
|
||||||
v-bind="widget.id === 'income-expense'
|
:is="widget.component"
|
||||||
|
v-bind="widget.id === 'income-expense'
|
||||||
? { headerTarget: `#dashboard-widget-header-actions-${widget.id}` }
|
? { headerTarget: `#dashboard-widget-header-actions-${widget.id}` }
|
||||||
: {}"
|
: {}"
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div v-else class="rounded-xl border border-dashed border-gray-300 dark:border-gray-700 p-10 text-center">
|
<div v-else class="rounded-xl border border-dashed border-gray-300 dark:border-gray-700 p-10 text-center">
|
||||||
<p class="text-sm">
|
<p class="text-sm">
|
||||||
Es sind aktuell keine Dashboard-Karten sichtbar.
|
Es sind aktuell keine Dashboard-Karten sichtbar.
|
||||||
</p>
|
</p>
|
||||||
<UButton v-if="isEditMode" class="mt-4" icon="i-heroicons-plus" @click="manageCardsOpen = true">
|
<UButton v-if="isEditMode" class="mt-4" icon="i-heroicons-plus" @click="manageCardsOpen = true">
|
||||||
Karte hinzufügen
|
Karte hinzufügen
|
||||||
</UButton>
|
</UButton>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<UModal v-model:open="manageCardsOpen">
|
<UModal v-model:open="manageCardsOpen">
|
||||||
<template #content>
|
<template #content>
|
||||||
<UCard>
|
<UCard>
|
||||||
<template #header>
|
<template #header>
|
||||||
<div class="flex items-center justify-between gap-3">
|
<div class="flex items-center justify-between gap-3">
|
||||||
<div>
|
<div>
|
||||||
<h2 class="font-semibold">Dashboard-Karten</h2>
|
<h2 class="font-semibold">Dashboard-Karten</h2>
|
||||||
<p class="text-sm">
|
<p class="text-sm">
|
||||||
Karten ein- oder ausblenden und bei Bedarf auf das Standardlayout zurücksetzen.
|
Karten ein- oder ausblenden und bei Bedarf auf das Standardlayout zurücksetzen.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
|
||||||
<UButton color="gray" variant="ghost" icon="i-heroicons-arrow-path" @click="resetDashboard">
|
|
||||||
Zurücksetzen
|
|
||||||
</UButton>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
<UButton color="gray" variant="ghost" icon="i-heroicons-arrow-path" @click="resetDashboard">
|
||||||
|
Zurücksetzen
|
||||||
|
</UButton>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
<div class="space-y-3">
|
<div class="space-y-3">
|
||||||
<div
|
<div
|
||||||
v-for="definition in DASHBOARD_WIDGETS"
|
v-for="definition in DASHBOARD_WIDGETS"
|
||||||
:key="definition.id"
|
:key="definition.id"
|
||||||
class="flex items-center justify-between gap-3 rounded-lg border border-gray-200 dark:border-gray-800 px-4 py-3"
|
class="flex items-center justify-between gap-3 rounded-lg border border-gray-200 dark:border-gray-800 px-4 py-3"
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<p class="font-medium">{{ definition.title }}</p>
|
<p class="font-medium">{{ definition.title }}</p>
|
||||||
<p class="text-sm">{{ definition.description }}</p>
|
<p class="text-sm">{{ definition.description }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<UButton
|
<UButton
|
||||||
v-if="getWidgetLayout(definition.id)?.visible"
|
v-if="getWidgetLayout(definition.id)?.visible"
|
||||||
color="gray"
|
color="gray"
|
||||||
variant="soft"
|
variant="soft"
|
||||||
icon="i-heroicons-minus"
|
icon="i-heroicons-minus"
|
||||||
:disabled="visibleWidgets.length <= 1"
|
:disabled="visibleWidgets.length <= 1"
|
||||||
@click="removeWidget(definition.id)"
|
@click="removeWidget(definition.id)"
|
||||||
>
|
>
|
||||||
Entfernen
|
Entfernen
|
||||||
</UButton>
|
</UButton>
|
||||||
<UButton
|
<UButton
|
||||||
v-else
|
v-else
|
||||||
color="primary"
|
color="primary"
|
||||||
variant="soft"
|
variant="soft"
|
||||||
icon="i-heroicons-plus"
|
icon="i-heroicons-plus"
|
||||||
@click="addWidget(definition.id)"
|
@click="addWidget(definition.id)"
|
||||||
>
|
>
|
||||||
Hinzufügen
|
Hinzufügen
|
||||||
</UButton>
|
</UButton>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</UCard>
|
</div>
|
||||||
</template>
|
</UCard>
|
||||||
</UModal>
|
</template>
|
||||||
</div>
|
</UModal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
Reference in New Issue
Block a user