Dashboard-Ladezeit durch geteilte Datenabfragen optimiert
This commit is contained in:
@@ -11,6 +11,7 @@ import {
|
||||
} from "~/composables/useDepreciation"
|
||||
|
||||
const loading = ref(true)
|
||||
const { loadCoreData } = useDashboardData()
|
||||
const summary = ref({
|
||||
label: "",
|
||||
income: 0,
|
||||
@@ -47,11 +48,11 @@ const loadSummary = async () => {
|
||||
end: dayjs().endOf("month")
|
||||
}
|
||||
|
||||
const [docs, incoming, allocations] = await Promise.all([
|
||||
useEntities("createddocuments").select(),
|
||||
useEntities("incominginvoices").select(),
|
||||
const [coreData, allocations] = await Promise.all([
|
||||
loadCoreData(),
|
||||
useEntities("statementallocations").select("*, bankstatement(*)")
|
||||
])
|
||||
const { createdDocuments: docs, incomingInvoices: incoming } = coreData
|
||||
|
||||
const outputDocs = (docs || []).filter((doc: any) => {
|
||||
if (!isRelevantOutputDocument(doc)) {
|
||||
|
||||
@@ -17,6 +17,7 @@ const props = defineProps({
|
||||
})
|
||||
|
||||
const tempStore = useTempStore()
|
||||
const { loadCoreData } = useDashboardData()
|
||||
const isMounted = ref(false)
|
||||
|
||||
const amountMode = ref("net")
|
||||
@@ -82,10 +83,7 @@ watch([amountMode, granularity, selectedYear, selectedMonth], () => {
|
||||
})
|
||||
|
||||
const loadData = async () => {
|
||||
const [docs, incoming] = await Promise.all([
|
||||
useEntities("createddocuments").select(),
|
||||
useEntities("incominginvoices").select()
|
||||
])
|
||||
const { createdDocuments: docs, incomingInvoices: incoming } = await loadCoreData()
|
||||
|
||||
incomeDocuments.value = (docs || []).filter((item) => item.state === "Gebucht" && ["invoices", "advanceInvoices", "cancellationInvoices"].includes(item.type))
|
||||
expenseInvoices.value = (incoming || []).filter((item) => item.state === "Gebucht" && item.date)
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
dayjs.extend(customParseFormat)
|
||||
|
||||
const auth = useAuthStore()
|
||||
const { loadCoreData } = useDashboardData()
|
||||
|
||||
const loading = ref(true)
|
||||
const summary = ref({
|
||||
@@ -39,10 +40,7 @@ const loadSummary = async () => {
|
||||
const periodType = normalizeTaxEvaluationPeriod(auth.activeTenantData?.taxEvaluationPeriod)
|
||||
const bounds = getTaxEvaluationPeriodBounds(dayjs(), periodType)
|
||||
|
||||
const [docs, incoming] = await Promise.all([
|
||||
useEntities("createddocuments").select(),
|
||||
useEntities("incominginvoices").select()
|
||||
])
|
||||
const { createdDocuments: docs, incomingInvoices: incoming } = await loadCoreData()
|
||||
|
||||
const outputDocs = (docs || []).filter((doc: any) => {
|
||||
if (doc?.state !== "Gebucht") return false
|
||||
|
||||
54
frontend/composables/useDashboardData.ts
Normal file
54
frontend/composables/useDashboardData.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
type DashboardCoreData = {
|
||||
createdDocuments: any[]
|
||||
incomingInvoices: any[]
|
||||
}
|
||||
|
||||
const CACHE_TTL_MS = 30_000
|
||||
|
||||
type DashboardCacheEntry = {
|
||||
cachedAt: number
|
||||
data: DashboardCoreData | null
|
||||
pendingRequest: Promise<DashboardCoreData> | null
|
||||
}
|
||||
|
||||
const tenantCaches = new Map<string, DashboardCacheEntry>()
|
||||
|
||||
/**
|
||||
* Bündelt die großen, von mehreren Dashboard-Karten benötigten Abfragen.
|
||||
* So werden identische Requests beim parallelen Mounten nur einmal ausgeführt.
|
||||
*/
|
||||
export const useDashboardData = () => {
|
||||
const auth = useAuthStore()
|
||||
|
||||
const getTenantKey = () => String(auth.activeTenant || auth.activeTenantData?.id || "default")
|
||||
|
||||
const loadCoreData = async (force = false): Promise<DashboardCoreData> => {
|
||||
const tenantKey = getTenantKey()
|
||||
const cache = tenantCaches.get(tenantKey) || { cachedAt: 0, data: null, pendingRequest: null }
|
||||
tenantCaches.set(tenantKey, cache)
|
||||
const cacheIsFresh = cache.data && Date.now() - cache.cachedAt < CACHE_TTL_MS
|
||||
|
||||
if (!force && cacheIsFresh) return cache.data
|
||||
if (!force && cache.pendingRequest) return cache.pendingRequest
|
||||
|
||||
cache.pendingRequest = Promise.all([
|
||||
useEntities("createddocuments").select(),
|
||||
useEntities("incominginvoices").select()
|
||||
])
|
||||
.then(([createdDocuments, incomingInvoices]) => {
|
||||
cache.data = {
|
||||
createdDocuments: createdDocuments || [],
|
||||
incomingInvoices: incomingInvoices || []
|
||||
}
|
||||
cache.cachedAt = Date.now()
|
||||
return cache.data
|
||||
})
|
||||
.finally(() => {
|
||||
cache.pendingRequest = null
|
||||
})
|
||||
|
||||
return cache.pendingRequest
|
||||
}
|
||||
|
||||
return { loadCoreData }
|
||||
}
|
||||
@@ -2,13 +2,13 @@
|
||||
import { setPageLayout } from "#app"
|
||||
import "gridstack/dist/gridstack.min.css"
|
||||
|
||||
import DisplayIncomeAndExpenditure from "~/components/displayIncomeAndExpenditure.vue"
|
||||
import DisplayOpenBalances from "~/components/displayOpenBalances.vue"
|
||||
import DisplayBankaccounts from "~/components/displayBankaccounts.vue"
|
||||
import DisplayProjectsInPhases from "~/components/displayProjectsInPhases.vue"
|
||||
import DisplayOpenTasks from "~/components/displayOpenTasks.vue"
|
||||
import DisplayTaxSummary from "~/components/displayTaxSummary.vue"
|
||||
import DisplayBWASummary from "~/components/displayBWASummary.vue"
|
||||
const DisplayIncomeAndExpenditure = defineAsyncComponent(() => import("~/components/displayIncomeAndExpenditure.vue"))
|
||||
const DisplayOpenBalances = defineAsyncComponent(() => import("~/components/displayOpenBalances.vue"))
|
||||
const DisplayBankaccounts = defineAsyncComponent(() => import("~/components/displayBankaccounts.vue"))
|
||||
const DisplayProjectsInPhases = defineAsyncComponent(() => import("~/components/displayProjectsInPhases.vue"))
|
||||
const DisplayOpenTasks = defineAsyncComponent(() => import("~/components/displayOpenTasks.vue"))
|
||||
const DisplayTaxSummary = defineAsyncComponent(() => import("~/components/displayTaxSummary.vue"))
|
||||
const DisplayBWASummary = defineAsyncComponent(() => import("~/components/displayBWASummary.vue"))
|
||||
|
||||
setPageLayout("default")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user