Added Calculator

This commit is contained in:
2026-01-15 19:08:26 +01:00
parent 5edc90bd4d
commit 9b3f48defe
4 changed files with 457 additions and 286 deletions

View File

@@ -1,21 +1,20 @@
<script setup>
import MainNav from "~/components/MainNav.vue";
import dayjs from "dayjs";
import GlobalMessages from "~/components/GlobalMessages.vue";
import TenantDropdown from "~/components/TenantDropdown.vue";
import LabelPrinterButton from "~/components/LabelPrinterButton.vue";
import {useCalculatorStore} from '~/stores/calculator'
const dataStore = useDataStore()
const colorMode = useColorMode()
const { isHelpSlideoverOpen } = useDashboard()
const {isHelpSlideoverOpen} = useDashboard()
const router = useRouter()
const route = useRoute()
const auth = useAuthStore()
const labelPrinter = useLabelPrinterStore()
const calculatorStore = useCalculatorStore()
const month = dayjs().format("MM")
@@ -24,91 +23,108 @@ const actions = [
id: 'new-customer',
label: 'Kunde hinzufügen',
icon: 'i-heroicons-user-group',
to: "/customers/create" ,
to: "/customers/create",
},
{
id: 'new-vendor',
label: 'Lieferant hinzufügen',
icon: 'i-heroicons-truck',
to: "/vendors/create" ,
to: "/vendors/create",
},
{
id: 'new-contact',
label: 'Ansprechpartner hinzufügen',
icon: 'i-heroicons-user-group',
to: "/contacts/create" ,
to: "/contacts/create",
},
{
id: 'new-task',
label: 'Aufgabe hinzufügen',
icon: 'i-heroicons-rectangle-stack',
to: "/tasks/create" ,
to: "/tasks/create",
},
{
id: 'new-plant',
label: 'Objekt hinzufügen',
icon: 'i-heroicons-clipboard-document',
to: "/plants/create" ,
to: "/plants/create",
},
{
id: 'new-product',
label: 'Artikel hinzufügen',
icon: 'i-heroicons-puzzle-piece',
to: "/products/create" ,
to: "/products/create",
},
{
id: 'new-project',
label: 'Projekt hinzufügen',
icon: 'i-heroicons-clipboard-document-check',
to: "/projects/create" ,
to: "/projects/create",
}
]
const groups = computed(() => [
{
key: 'actions',
commands: actions
},{
key: "customers",
label: "Kunden",
commands: dataStore.customers.map(item => { return {id: item.id, label: item.name, to: `/customers/show/${item.id}`}})
},{
key: "vendors",
label: "Lieferanten",
commands: dataStore.vendors.map(item => { return {id: item.id, label: item.name, to: `/vendors/show/${item.id}`}})
},{
key: "contacts",
label: "Ansprechpartner",
commands: dataStore.contacts.map(item => { return {id: item.id, label: item.fullName, to: `/contacts/show/${item.id}`}})
},{
key: "products",
label: "Artikel",
commands: dataStore.products.map(item => { return {id: item.id, label: item.name, to: `/products/show/${item.id}`}})
},{
key: "tasks",
label: "Aufgaben",
commands: dataStore.tasks.map(item => { return {id: item.id, label: item.name, to: `/tasks/show/${item.id}`}})
},{
key: "plants",
label: "Objekte",
commands: dataStore.plants.map(item => { return {id: item.id, label: item.name, to: `/plants/show/${item.id}`}})
},{
key: "projects",
label: "Projekte",
commands: dataStore.projects.map(item => { return {id: item.id, label: item.name, to: `/projects/show/${item.id}`}})
}
].filter(Boolean))
const footerLinks = [
/*{
label: 'Invite people',
icon: 'i-heroicons-plus',
to: '/settings/members'
}, */{
label: 'Hilfe & Info',
icon: 'i-heroicons-question-mark-circle',
click: () => isHelpSlideoverOpen.value = true
}]
{
key: 'actions',
commands: actions
}, {
key: "customers",
label: "Kunden",
commands: dataStore.customers.map(item => {
return {id: item.id, label: item.name, to: `/customers/show/${item.id}`}
})
}, {
key: "vendors",
label: "Lieferanten",
commands: dataStore.vendors.map(item => {
return {id: item.id, label: item.name, to: `/vendors/show/${item.id}`}
})
}, {
key: "contacts",
label: "Ansprechpartner",
commands: dataStore.contacts.map(item => {
return {id: item.id, label: item.fullName, to: `/contacts/show/${item.id}`}
})
}, {
key: "products",
label: "Artikel",
commands: dataStore.products.map(item => {
return {id: item.id, label: item.name, to: `/products/show/${item.id}`}
})
}, {
key: "tasks",
label: "Aufgaben",
commands: dataStore.tasks.map(item => {
return {id: item.id, label: item.name, to: `/tasks/show/${item.id}`}
})
}, {
key: "plants",
label: "Objekte",
commands: dataStore.plants.map(item => {
return {id: item.id, label: item.name, to: `/plants/show/${item.id}`}
})
}, {
key: "projects",
label: "Projekte",
commands: dataStore.projects.map(item => {
return {id: item.id, label: item.name, to: `/projects/show/${item.id}`}
})
}
].filter(Boolean))
// --- Footer Links nutzen jetzt den zentralen Calculator Store ---
const footerLinks = computed(() => [
{
label: 'Taschenrechner',
icon: 'i-heroicons-calculator',
click: () => calculatorStore.toggle()
},
{
label: 'Hilfe & Info',
icon: 'i-heroicons-question-mark-circle',
click: () => isHelpSlideoverOpen.value = true
}
])
</script>
@@ -130,24 +146,24 @@ const footerLinks = [
v-else
/>
<div class="flex justify-center mb-6">
<UIcon name="i-heroicons-exclamation-triangle-solid" class="w-16 h-16 text-yellow-500" />
<UIcon name="i-heroicons-exclamation-triangle-solid" class="w-16 h-16 text-yellow-500"/>
</div>
<h1 class="text-2xl font-bold text-gray-900 dark:text-white mb-4">
Wartungsarbeiten
</h1>
<p class="text-gray-600 dark:text-gray-300 mb-8">
Dieser FEDEO Mandant wird derzeit gewartet. Bitte versuche es in einigen Minuten erneut oder verwende einen anderen Mandanten.
Dieser FEDEO Mandant wird derzeit gewartet. Bitte versuche es in einigen Minuten erneut oder verwende einen
anderen Mandanten.
</p>
<div class="mx-auto text-left flex flex-row justify-between my-3" v-for="tenant in auth.tenants">
{{tenant.name}}
{{ tenant.name }}
<UButton
:disabled="tenant.locked"
@click="auth.switchTenant(tenant.id)"
>Wählen</UButton>
>Wählen
</UButton>
</div>
</UCard>
</UContainer>
</div>
@@ -167,7 +183,7 @@ const footerLinks = [
v-else
/>
<div class="flex justify-center mb-6">
<UIcon name="i-heroicons-exclamation-triangle-solid" class="w-16 h-16 text-yellow-500" />
<UIcon name="i-heroicons-exclamation-triangle-solid" class="w-16 h-16 text-yellow-500"/>
</div>
<h1 class="text-2xl font-bold text-gray-900 dark:text-white mb-4">
@@ -176,8 +192,6 @@ const footerLinks = [
<p class="text-gray-600 dark:text-gray-300 mb-8">
FEDEO wird derzeit gewartet. Bitte versuche es in einigen Minuten erneut.
</p>
</UCard>
</UContainer>
</div>
@@ -197,32 +211,33 @@ const footerLinks = [
v-else
/>
<div class="flex justify-center mb-6">
<UIcon name="i-heroicons-credit-card" class="w-16 h-16 text-red-600" />
<UIcon name="i-heroicons-credit-card" class="w-16 h-16 text-red-600"/>
</div>
<h1 class="text-2xl font-bold text-gray-900 dark:text-white mb-4">
Kein Aktives Abonnement für diesen Mandant.
</h1>
<p class="text-gray-600 dark:text-gray-300 mb-8">
Bitte wenden Sie sich an den FEDEO Support um ein Abonnement zu erhalten oder verwenden Sie einen anderen Mandanten.
Bitte wenden Sie sich an den FEDEO Support um ein Abonnement zu erhalten oder verwenden Sie einen anderen
Mandanten.
</p>
<div class="mx-auto text-left flex flex-row justify-between my-3" v-for="tenant in auth.tenants">
{{tenant.name}}
{{ tenant.name }}
<UButton
:disabled="tenant.locked"
@click="auth.switchTenant(tenant.id)"
>Wählen</UButton>
>Wählen
</UButton>
</div>
</UCard>
</UContainer>
</div>
<UDashboardLayout class="safearea" v-else >
<UDashboardLayout class="safearea" v-else>
<UDashboardPanel :width="250" :resizable="{ min: 200, max: 300 }" collapsible>
<UDashboardNavbar style="margin-top: env(safe-area-inset-top, 10px) !important;" :class="['!border-transparent']" :ui="{ left: 'flex-1' }">
<UDashboardNavbar style="margin-top: env(safe-area-inset-top, 10px) !important;"
:class="['!border-transparent']" :ui="{ left: 'flex-1' }">
<template #left>
<TenantDropdown class="w-full" />
<TenantDropdown class="w-full"/>
</template>
</UDashboardNavbar>
@@ -230,24 +245,17 @@ const footerLinks = [
<MainNav/>
<div class="flex-1" />
<div class="flex-1"/>
<template #footer>
<div class="flex flex-col gap-3 w-full">
<UColorModeButton />
<UColorModeButton/>
<LabelPrinterButton/>
<UDashboardSidebarLinks :links="footerLinks"/>
<!-- Footer Links -->
<UDashboardSidebarLinks :links="footerLinks" />
<UDivider class="sticky bottom-0" />
<UDivider class="sticky bottom-0"/>
<UserDropdown style="margin-bottom: env(safe-area-inset-bottom, 10px) !important;"/>
</div>
</template>
@@ -256,14 +264,14 @@ const footerLinks = [
<UDashboardPage>
<UDashboardPanel grow>
<slot />
<slot/>
</UDashboardPanel>
</UDashboardPage>
<HelpSlideover/>
<Calculator v-if="calculatorStore.isOpen"/>
</UDashboardLayout>
</div>
@@ -278,37 +286,32 @@ const footerLinks = [
v-if="month === '12'"
/>
<UColorModeImage
light="/Logo.png"
dark="/Logo_Dark.png"
class="w-1/3 mx-auto my-10"
v-else
light="/Logo.png"
dark="/Logo_Dark.png"
class="w-1/3 mx-auto my-10"
v-else
/>
<div v-if="!auth.activeTenant" class="w-1/2 mx-auto text-center">
<!-- Tenant Selection -->
<h3 class="text-center font-bold text-2xl mb-5">Kein Aktiver Mandant. Bitte wählen Sie ein Mandant.</h3>
<div class="mx-auto w-1/2 flex flex-row justify-between my-3" v-for="tenant in auth.tenants">
<span class="text-left">{{tenant.name}}</span>
<UButton
@click="auth.switchTenant(tenant.id)"
>Wählen</UButton>
</div>
<h3 class="text-center font-bold text-2xl mb-5">Kein Aktiver Mandant. Bitte wählen Sie ein Mandant.</h3>
<div class="mx-auto w-1/2 flex flex-row justify-between my-3" v-for="tenant in auth.tenants">
<span class="text-left">{{ tenant.name }}</span>
<UButton
variant="outline"
color="rose"
@click="auth.switchTenant(tenant.id)"
>Wählen
</UButton>
</div>
<UButton
variant="outline"
color="rose"
@click="auth.logout()"
>Abmelden</UButton>
>Abmelden
</UButton>
</div>
<div v-else>
<UProgress animation="carousel" class="w-3/4 mx-auto mt-10" />
<UProgress animation="carousel" class="w-3/4 mx-auto mt-10"/>
</div>
</div>
</template>
<style scoped>
</style>
</template>