2. Zwischenstand
All checks were successful
Build and Push Docker Images / build-backend (push) Successful in 15s
Build and Push Docker Images / build-frontend (push) Successful in 2m43s

This commit is contained in:
2026-03-21 22:56:56 +01:00
parent 68b2cbb0ee
commit 03bcc1a939
56 changed files with 1289 additions and 1302 deletions

View File

@@ -281,30 +281,30 @@ const moveFile = async () => {
<USeparator class="my-3" label="Datei zuweisen"/>
<UFormGroup
<UFormField
label="Resource auswählen"
>
<USelectMenu
:options="resourceOptions"
:items="resourceOptions"
v-model="resourceToAssign"
value-attribute="value"
option-attribute="label"
value-key="value"
label-key="label"
@change="getItemsBySelectedResource"
>
</USelectMenu>
</UFormGroup>
<UFormGroup
</UFormField>
<UFormField
label="Eintrag auswählen:"
>
<USelectMenu
:options="itemOptions"
:items="itemOptions"
v-model="idToAssign"
:option-attribute="resourceOptions.find(i => i.value === resourceToAssign)? resourceOptions.find(i => i.value === resourceToAssign).optionAttr : 'name'"
value-attribute="id"
:label-key="resourceOptions.find(i => i.value === resourceToAssign)? resourceOptions.find(i => i.value === resourceToAssign).optionAttr : 'name'"
value-key="id"
@change="updateDocumentAssignment"
></USelectMenu>
</UFormGroup>
</UFormField>
@@ -314,9 +314,9 @@ const moveFile = async () => {
<USelectMenu
class="flex-auto"
v-model="folderToMoveTo"
value-attribute="id"
option-attribute="name"
:options="folders"
value-key="id"
label-key="name"
:items="folders"
/>
<UButton
@click="moveFile"
@@ -331,9 +331,9 @@ const moveFile = async () => {
<USelectMenu
class="flex-auto"
v-model="props.documentData.type"
value-attribute="id"
option-attribute="name"
:options="filetypes"
value-key="id"
label-key="name"
:items="filetypes"
@change="updateDocument"
/>
</InputGroup>
@@ -343,9 +343,9 @@ const moveFile = async () => {
<USelectMenu
class="flex-auto"
v-model="props.documentData.documentbox"
value-attribute="id"
option-attribute="key"
:options="documentboxes"
value-key="id"
label-key="key"
:items="documentboxes"
@change="updateDocument"
/>
</InputGroup>

View File

@@ -107,7 +107,7 @@ const fileNames = computed(() => {
</div>
</template>
<UFormGroup
<UFormField
label="Datei:"
:help="selectedFiles.length > 0 ? `${selectedFiles.length} Datei(en) ausgewählt` : 'Ziehen Sie Dateien hierher oder klicken Sie'"
>
@@ -123,9 +123,9 @@ const fileNames = computed(() => {
<div v-if="selectedFiles.length > 0" class="mt-2 text-sm text-gray-500">
Ausgewählt: <span class="font-medium text-gray-700 dark:text-gray-300">{{ fileNames }}</span>
</div>
</UFormGroup>
</UFormField>
<UFormGroup
<UFormField
label="Typ:"
class="mt-3"
>
@@ -143,7 +143,7 @@ const fileNames = computed(() => {
<span v-else>Kein Typ ausgewählt</span>
</template>
</USelectMenu>
</UFormGroup>
</UFormField>
<template #footer>
<UButton

View File

@@ -155,15 +155,15 @@ const filteredRows = computed(() => {
<USelectMenu
v-model="selectedColumns"
icon="i-heroicons-adjustments-horizontal-solid"
:options="dataType.templateColumns.filter(i => !i.disabledInTable)"
:items="dataType.templateColumns.filter(i => !i.disabledInTable)"
multiple
class="hidden lg:block"
by="key"
:color="selectedColumns.length !== dataType.templateColumns.filter(i => !i.disabledInTable).length ? 'primary' : 'white'"
:ui-menu="{ width: 'min-w-max' }"
:content="{ width: 'min-w-max' }"
@change="tempStore.modifyColumns(type,selectedColumns)"
>
<template>
<template #default>
Spalten
</template>
</USelectMenu>
@@ -172,11 +172,11 @@ const filteredRows = computed(() => {
icon="i-heroicons-adjustments-horizontal-solid"
multiple
v-model="selectedFilters"
:options="selectableFilters"
:items="selectableFilters"
:color="selectedFilters.length > 0 ? 'primary' : 'white'"
:ui-menu="{ width: 'min-w-max' }"
:content="{ width: 'min-w-max' }"
>
<template #label>
<template #default>
Filter
</template>
</USelectMenu>

View File

@@ -28,14 +28,16 @@ defineShortcuts({
router.back()
},
'arrowleft': () => {
if(openTab.value > 0){
openTab.value -= 1
const currentIndex = Number(openTab.value)
if(currentIndex > 0){
openTab.value = String(currentIndex - 1)
router.push(`${router.currentRoute.value.path}?tabIndex=${openTab.value}`)
}
},
'arrowright': () => {
if(openTab.value < dataType.showTabs.length - 1) {
openTab.value += 1
const currentIndex = Number(openTab.value)
if(currentIndex < dataType.showTabs.length - 1) {
openTab.value = String(currentIndex + 1)
router.push(`${router.currentRoute.value.path}?tabIndex=${openTab.value}`)
}
},
@@ -51,7 +53,7 @@ const auth = useAuthStore()
const dataType = dataStore.dataTypes[type]
const openTab = ref(route.query.tabIndex || 0)
const openTab = ref(String(route.query.tabIndex || 0))
@@ -97,7 +99,8 @@ const getAvailableQueryStringData = (keys) => {
}
const onTabChange = (index) => {
router.push(`${router.currentRoute.value.path}?tabIndex=${index}`)
openTab.value = String(index)
router.push(`${router.currentRoute.value.path}?tabIndex=${openTab.value}`)
}
const changePinned = async () => {
@@ -255,9 +258,9 @@ const openCustomerInventoryLabelPrint = () => {
v-if="props.item.id && platform !== 'mobile'"
class="p-5"
v-model="openTab"
@change="onTabChange"
@update:model-value="onTabChange"
>
<template #item="{item:tab}">
<template #content="{item:tab}">
<div v-if="tab.label === 'Informationen'" class="flex flex-row">
<EntityShowSubInformation

View File

@@ -96,15 +96,15 @@ setup()
<USelectMenu
v-model="selectedColumns"
icon="i-heroicons-adjustments-horizontal-solid"
:options="dataType.templateColumns.filter(i => !i.disabledInTable)"
:items="dataType.templateColumns.filter(i => !i.disabledInTable)"
multiple
class="hidden lg:block"
by="key"
:color="selectedColumns.length !== dataType.templateColumns.filter(i => !i.disabledInTable).length ? 'primary' : 'white'"
:ui-menu="{ width: 'min-w-max' }"
:content="{ width: 'min-w-max' }"
@change="tempStore.modifyColumns(type,selectedColumns)"
>
<template #label>
<template #default>
Spalten
</template>
</USelectMenu>

View File

@@ -181,49 +181,51 @@ const selectItem = (item) => {
</UButton>
<UModal
prevent-close
v-model="showFinalInvoiceConfig"
v-model:open="showFinalInvoiceConfig"
>
<UCard>
<template #header>
<div class="flex items-center justify-between">
<h3 class="text-base font-semibold leading-6 text-gray-900 dark:text-white">
Schlussrechnung konfigurieren
</h3>
<UButton color="gray" variant="ghost" icon="i-heroicons-x-mark-20-solid" class="-my-1" @click="isOpen = false" />
</div>
</template>
<template #content>
<UCard>
<template #header>
<div class="flex items-center justify-between">
<h3 class="text-base font-semibold leading-6 text-gray-900 dark:text-white">
Schlussrechnung konfigurieren
</h3>
<UButton color="gray" variant="ghost" icon="i-heroicons-x-mark-20-solid" class="-my-1" @click="showFinalInvoiceConfig = false" />
</div>
</template>
<UFormGroup
label="Rechnungsvorlage"
>
<USelectMenu
:options="props.item.createddocuments.filter(i => ['confirmationOrders','quotes'].includes(i.type))"
value-attribute="id"
option-attribute="documentNumber"
v-model="referenceDocument"
/>
</UFormGroup>
<UFormGroup
label="Abschlagsrechnungen"
>
<USelectMenu
:options="props.item.createddocuments.filter(i => ['advanceInvoices'].includes(i.type))"
multiple
value-attribute="id"
option-attribute="documentNumber"
v-model="advanceInvoicesToAdd"
/>
</UFormGroup>
<template #footer>
<UButton
@click="invoiceAdvanceInvoices"
<UFormField
label="Rechnungsvorlage"
>
Weiter
</UButton>
</template>
</UCard>
<USelectMenu
:items="props.item.createddocuments.filter(i => ['confirmationOrders','quotes'].includes(i.type))"
value-key="id"
label-key="documentNumber"
v-model="referenceDocument"
/>
</UFormField>
<UFormField
label="Abschlagsrechnungen"
>
<USelectMenu
:items="props.item.createddocuments.filter(i => ['advanceInvoices'].includes(i.type))"
multiple
value-key="id"
label-key="documentNumber"
v-model="advanceInvoicesToAdd"
/>
</UFormField>
<template #footer>
<UButton
@click="invoiceAdvanceInvoices"
>
Weiter
</UButton>
</template>
</UCard>
</template>
</UModal>
<UButton
@click="router.push(`/createDocument/edit/?${getAvailableQueryStringData({type: 'invoices'})}`)"
@@ -235,13 +237,13 @@ const selectItem = (item) => {
<USelectMenu
v-model="selectedColumns"
icon="i-heroicons-adjustments-horizontal-solid"
:options="templateColumns"
:items="templateColumns"
multiple
class="hidden lg:block"
by="key"
@change="tempStore.modifyColumns('createddocuments',selectedColumns)"
>
<template #label>
<template #default>
Spalten
</template>
</USelectMenu>
@@ -252,31 +254,31 @@ const selectItem = (item) => {
:columns="normalizeTableColumns(columns)"
class="w-full"
:ui="{ divide: 'divide-gray-200 dark:divide-gray-800' }"
@select="selectItem"
:empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Keine Belege anzuzeigen' }"
:on-select="(row) => selectItem(row.original)"
:empty="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Keine Belege anzuzeigen' }"
style="height: 70vh"
>
<template #type-data="{row}">
{{dataStore.documentTypesForCreation[row.type].labelSingle}}
<template #type-cell="{ row }">
{{ dataStore.documentTypesForCreation[row.original.type].labelSingle }}
</template>
<template #state-data="{row}">
<template #state-cell="{ row }">
<span
v-if="row.state === 'Entwurf'"
class="text-rose-500"
v-if="row.original.state === 'Entwurf'"
class="text-error-500"
>
{{row.state}}
{{ row.original.state }}
</span>
<span
v-if="row.state === 'Gebucht'"
v-if="row.original.state === 'Gebucht'"
class="text-cyan-500"
>
{{row.state}}
{{ row.original.state }}
</span>
<span
v-if="row.state === 'Abgeschlossen'"
v-if="row.original.state === 'Abgeschlossen'"
class="text-primary-500"
>
{{row.state}}
{{ row.original.state }}
</span>
</template>
<!-- <template #paid-data="{row}">
@@ -285,19 +287,19 @@ const selectItem = (item) => {
<span v-else class="text-rose-600">Offen</span>
</div>
</template>-->
<template #reference-data="{row}">
<span v-if="row === props.item.createddocuments[selectedItem]" class="text-primary-500 font-bold">{{row.documentNumber}}</span>
<span v-else>{{row.documentNumber}}</span>
<template #reference-cell="{ row }">
<span v-if="row.original === props.item.createddocuments[selectedItem]" class="text-primary-500 font-bold">{{ row.original.documentNumber }}</span>
<span v-else>{{ row.original.documentNumber }}</span>
</template>
<template #date-data="{row}">
<span v-if="row.date">{{row.date ? dayjs(row.date).format("DD.MM.YY") : ''}}</span>
<span v-if="row.documentDate">{{row.documentDate ? dayjs(row.documentDate).format("DD.MM.YY") : ''}}</span>
<template #date-cell="{ row }">
<span v-if="row.original.date">{{ row.original.date ? dayjs(row.original.date).format("DD.MM.YY") : '' }}</span>
<span v-if="row.original.documentDate">{{ row.original.documentDate ? dayjs(row.original.documentDate).format("DD.MM.YY") : '' }}</span>
</template>
<template #dueDate-data="{row}">
<span v-if="row.paymentDays && ['invoices','advanceInvoices'].includes(row.type)" >{{row.documentDate ? dayjs(row.documentDate).add(row.paymentDays,'day').format("DD.MM.YY") : ''}}</span>
<template #dueDate-cell="{ row }">
<span v-if="row.original.paymentDays && ['invoices','advanceInvoices'].includes(row.original.type)">{{ row.original.documentDate ? dayjs(row.original.documentDate).add(row.original.paymentDays,'day').format("DD.MM.YY") : '' }}</span>
</template>
<template #amount-data="{row}">
<span v-if="row.type !== 'deliveryNotes'">{{useCurrency(useSum().getCreatedDocumentSum(row, createddocuments))}}</span>
<template #amount-cell="{ row }">
<span v-if="row.original.type !== 'deliveryNotes'">{{ useCurrency(useSum().getCreatedDocumentSum(row.original, createddocuments)) }}</span>
</template>
</UTable>

View File

@@ -95,40 +95,42 @@ function isImage(file) {
<!-- 📱 PDF / IMG Viewer Slideover -->
<UModal v-model:open="showViewer" side="bottom" class="h-[100dvh]" fullscreen>
<!-- Header -->
<div class="p-4 border-b flex justify-between items-center flex-shrink-0">
<h3 class="font-bold truncate max-w-[70vw]">{{ activeFile?.path?.split("/").pop() }}</h3>
<UButton icon="i-heroicons-x-mark" variant="ghost" @click="closeViewer" />
</div>
<!-- Content -->
<div class="flex-1 overflow-y-auto m-2">
<!-- PDF -->
<div v-if="activeFile && isPdf(activeFile)" class="h-full">
<PDFViewer
:no-controls="true"
:file-id="activeFile.id"
location="fileviewer-mobile"
class="h-full"
/>
<template #content>
<!-- Header -->
<div class="p-4 border-b flex justify-between items-center flex-shrink-0">
<h3 class="font-bold truncate max-w-[70vw]">{{ activeFile?.path?.split("/").pop() }}</h3>
<UButton icon="i-heroicons-x-mark" variant="ghost" @click="closeViewer" />
</div>
<!-- IMAGE -->
<div
v-else-if="activeFile && isImage(activeFile)"
class="p-4 flex justify-center"
>
<img
:src="activeFile.url"
class="max-w-full max-h-[80vh] rounded-lg shadow"
<!-- Content -->
<div class="flex-1 overflow-y-auto m-2">
<!-- PDF -->
<div v-if="activeFile && isPdf(activeFile)" class="h-full">
<PDFViewer
:no-controls="true"
:file-id="activeFile.id"
location="fileviewer-mobile"
class="h-full"
/>
</div>
<!-- IMAGE -->
<div
v-else-if="activeFile && isImage(activeFile)"
class="p-4 flex justify-center"
>
<img
:src="activeFile.url"
class="max-w-full max-h-[80vh] rounded-lg shadow"
/>
</div>
<UAlert
v-else
title="Nicht unterstützter Dateityp"
icon="i-heroicons-exclamation-triangle"
/>
</div>
<UAlert
v-else
title="Nicht unterstützter Dateityp"
icon="i-heroicons-exclamation-triangle"
/>
</div>
</template>
</UModal>
</template>

View File

@@ -79,19 +79,19 @@ const renderedAllocations = computed(() => {
v-if="props.item.statementallocations"
:data="renderedAllocations"
:columns="normalizeTableColumns([{key:'amount', label:'Betrag'},{key:'date', label:'Datum'},{key:'partner', label:'Partner'},{key:'description', label:'Beschreibung'}])"
@select="(i) => selectAllocation(i)"
:empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Keine Buchungen anzuzeigen' }"
:on-select="(i) => selectAllocation(i)"
:empty="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Keine Buchungen anzuzeigen' }"
>
<template #amount-data="{row}">
<span class="text-right text-rose-600" v-if="row.amount < 0 || row.color === 'red'">{{useCurrency(row.amount)}}</span>
<span class="text-right text-primary-500" v-else-if="row.amount > 0 || row.color === 'green'">{{useCurrency(row.amount)}}</span>
<span v-else>{{useCurrency(row.amount)}}</span>
<template #amount-cell="{row}">
<span class="text-right text-rose-600" v-if="row.original.amount < 0 || row.original.color === 'red'">{{useCurrency(row.original.amount)}}</span>
<span class="text-right text-primary-500" v-else-if="row.original.amount > 0 || row.original.color === 'green'">{{useCurrency(row.original.amount)}}</span>
<span v-else>{{useCurrency(row.original.amount)}}</span>
</template>
<template #date-data="{row}">
{{row.date ? dayjs(row.date).format('DD.MM.YYYY') : ''}}
<template #date-cell="{row}">
{{row.original.date ? dayjs(row.original.date).format('DD.MM.YYYY') : ''}}
</template>
<template #description-data="{row}">
{{row.description ? row.description : ''}}
<template #description-cell="{row}">
{{row.original.description ? row.original.description : ''}}
</template>
</UTable>
</UCard>

View File

@@ -69,38 +69,38 @@ const columns = [
class="mt-3"
:columns="normalizeTableColumns(columns)"
:data="props.item.times"
:empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Noch keine Einträge' }"
:empty="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Noch keine Einträge' }"
>
<template #state-data="{row}">
<template #state-cell="{ row }">
<span
v-if="row.state === 'Entwurf'"
class="text-rose-500"
>{{row.state}}</span>
v-if="row.original.state === 'Entwurf'"
class="text-error-500"
>{{ row.original.state }}</span>
<span
v-if="row.state === 'Eingereicht'"
v-if="row.original.state === 'Eingereicht'"
class="text-cyan-500"
>{{row.state}}</span>
>{{ row.original.state }}</span>
<span
v-if="row.state === 'Bestätigt'"
v-if="row.original.state === 'Bestätigt'"
class="text-primary-500"
>{{row.state}}</span>
>{{ row.original.state }}</span>
</template>
<template #user-data="{row}">
{{row.profile ? row.profile.fullName : "" }}
<template #user-cell="{ row }">
{{ row.original.profile ? row.original.profile.fullName : "" }}
</template>
<template #startDate-data="{row}">
{{dayjs(row.startDate).format("DD.MM.YY HH:mm")}}
<template #startDate-cell="{ row }">
{{ dayjs(row.original.startDate).format("DD.MM.YY HH:mm") }}
</template>
<template #endDate-data="{row}">
{{dayjs(row.endDate).format("DD.MM.YY HH:mm")}}
<template #endDate-cell="{ row }">
{{ dayjs(row.original.endDate).format("DD.MM.YY HH:mm") }}
</template>
<template #duration-data="{row}">
{{Math.floor(dayjs(row.endDate).diff(row.startDate, "minutes")/60)}}:{{String(dayjs(row.endDate).diff(row.startDate, "minutes") % 60).padStart(2,"0")}} h
<template #duration-cell="{ row }">
{{ Math.floor(dayjs(row.original.endDate).diff(row.original.startDate, "minutes") / 60) }}:{{ String(dayjs(row.original.endDate).diff(row.original.startDate, "minutes") % 60).padStart(2,"0") }} h
</template>
<template #project-data="{row}">
{{row.project ? row.project.name : "" }}
<template #project-cell="{ row }">
{{ row.original.project ? row.original.project.name : "" }}
</template>
</UTable>
</UCard>

View File

@@ -123,7 +123,7 @@ function onSelect (option) {
/>
<UModal
v-model="showCommandPalette"
v-model:open="showCommandPalette"
>
<template #content>
<UCommandPalette

View File

@@ -270,29 +270,29 @@ watch(isHelpSlideoverOpen, async (isOpen) => {
@submit="addContactRequest"
@reset="resetContactRequest"
>
&lt;!&ndash; <UFormGroup
&lt;!&ndash; <UFormField
label="Art:"
>
<USelectMenu
:options="['Hilfe','Software Problem / Bug','Funktionsanfrage','Kontakt','Sonstiges']"
v-model="contactRequestData.contactType"
/>
</UFormGroup>&ndash;&gt;
<UFormGroup
</UFormField>&ndash;&gt;
<UFormField
label="Titel:"
>
<UInput
v-model="contactRequestData.title"
/>
</UFormGroup>
<UFormGroup
</UFormField>
<UFormField
label="Nachricht:"
>
<UTextarea
v-model="contactRequestData.message"
rows="6"
/>
</UFormGroup>
</UFormField>
<InputGroup class="mt-3">
<UButton
type="submit"

View File

@@ -76,7 +76,7 @@ const renderText = (text) => {
<template>
<UModal
v-model="showAddHistoryItemModal"
v-model:open="showAddHistoryItemModal"
>
<template #content>
@@ -90,7 +90,7 @@ const renderText = (text) => {
</div>
</template>
<UFormGroup
<UFormField
label="Text:"
>
<UTextarea
@@ -102,7 +102,7 @@ const renderText = (text) => {
<UKbd>{{metaSymbol}}</UKbd> <UKbd>Enter</UKbd> Speichern
</template>-->
</UFormGroup>
</UFormField>
<template #footer>

View File

@@ -322,6 +322,21 @@ const links = computed(() => {
to: "/historyitems",
icon: "i-heroicons-book-open"
} : null,
...(has("projects") && featureEnabled("projects")) ? [{
label: "Projekte",
to: "/standardEntity/projects",
icon: "i-heroicons-clipboard-document-check"
}] : [],
...(has("contracts") && featureEnabled("contracts")) ? [{
label: "Verträge",
to: "/standardEntity/contracts",
icon: "i-heroicons-clipboard-document"
}] : [],
...(has("plants") && featureEnabled("plants")) ? [{
label: "Objekte",
to: "/standardEntity/plants",
icon: "i-heroicons-clipboard-document"
}] : [],
...(visibleOrganisationChildren.length > 0 ? [{
label: "Organisation",
icon: "i-heroicons-rectangle-stack",
@@ -371,21 +386,7 @@ const links = computed(() => {
children: visibleMasterDataChildren
}] : []),
...(has("projects") && featureEnabled("projects")) ? [{
label: "Projekte",
to: "/standardEntity/projects",
icon: "i-heroicons-clipboard-document-check"
}] : [],
...(has("contracts") && featureEnabled("contracts")) ? [{
label: "Verträge",
to: "/standardEntity/contracts",
icon: "i-heroicons-clipboard-document"
}] : [],
...(has("plants") && featureEnabled("plants")) ? [{
label: "Objekte",
to: "/standardEntity/plants",
icon: "i-heroicons-clipboard-document"
}] : [],
...(visibleSettingsChildren.length > 0 ? [{
label: "Einstellungen",
defaultOpen: false,

View File

@@ -119,7 +119,7 @@ const setDeliveryDateToToday = () => {
<div class="space-y-5">
<UFormGroup
<UFormField
label="Datum der Ausführung"
:error="errors.deliveryDate"
required
@@ -134,9 +134,9 @@ const setDeliveryDateToToday = () => {
/>
<UButton color="gray" variant="soft" size="lg" label="Heute" @click="setDeliveryDateToToday" />
</div>
</UFormGroup>
</UFormField>
<UFormGroup
<UFormField
v-if="!context?.meta?.defaultProfileId && data?.profiles?.length > 0"
label="Mitarbeiter"
:error="errors.profile"
@@ -144,16 +144,16 @@ const setDeliveryDateToToday = () => {
>
<USelectMenu
v-model="form.profile"
:options="data.profiles"
option-attribute="fullName"
value-attribute="id"
:items="data.profiles"
label-key="fullName"
value-key="id"
placeholder="Name auswählen..."
searchable
size="lg"
/>
</UFormGroup>
</UFormField>
<UFormGroup
<UFormField
v-if="data?.projects?.length > 0"
:label="config.ui?.labels?.project || 'Projekt / Auftrag'"
:error="errors.project"
@@ -161,16 +161,16 @@ const setDeliveryDateToToday = () => {
>
<USelectMenu
v-model="form.project"
:options="data.projects"
option-attribute="name"
value-attribute="id"
:items="data.projects"
label-key="name"
value-key="id"
placeholder="Wählen..."
searchable
size="lg"
/>
</UFormGroup>
</UFormField>
<UFormGroup
<UFormField
v-if="data?.services?.length > 0"
:label="config?.ui?.labels?.service || 'Tätigkeit'"
:error="errors.service"
@@ -178,16 +178,16 @@ const setDeliveryDateToToday = () => {
>
<USelectMenu
v-model="form.service"
:options="data.services"
option-attribute="name"
value-attribute="id"
:items="data.services"
label-key="name"
value-key="id"
placeholder="Wählen..."
searchable
size="lg"
/>
</UFormGroup>
</UFormField>
<UFormGroup
<UFormField
label="Menge / Dauer"
:error="errors.quantity"
required
@@ -203,9 +203,9 @@ const setDeliveryDateToToday = () => {
<span class="text-gray-500 text-sm pr-2">{{ currentUnit }}</span>
</template>
</UInput>
</UFormGroup>
</UFormField>
<UFormGroup
<UFormField
v-if="config?.features?.agriculture?.showDieselUsage"
label="Dieselverbrauch"
:error="errors.diesel"
@@ -216,11 +216,11 @@ const setDeliveryDateToToday = () => {
<span class="text-gray-500 text-xs">Liter</span>
</template>
</UInput>
</UFormGroup>
</UFormField>
<UFormGroup :label="config?.ui?.labels?.description || 'Notiz / Vorkommnisse'">
<UFormField :label="config?.ui?.labels?.description || 'Notiz / Vorkommnisse'">
<UTextarea v-model="form.description" :rows="3" placeholder="Optional..." />
</UFormGroup>
</UFormField>
</div>

View File

@@ -1,55 +1,44 @@
<script setup>
const { isHelpSlideoverOpen } = useDashboard()
const auth = useAuthStore()
const items = computed(() => [
[{
slot: 'account',
label: '',
disabled: true
}], [/*{
label: 'Mein Profil',
icon: 'i-heroicons-user',
to: `/profiles/show/${profileStore.activeProfile.id}`
},*/{
label: 'Passwort ändern',
const userItems = computed(() => [[
{
label: 'Passwort aendern',
icon: 'i-heroicons-shield-check',
to: `/password-change`
},{
to: '/password-change'
},
{
label: 'Abmelden',
icon: 'i-heroicons-arrow-left-on-rectangle',
click: async () => {
onSelect: async () => {
await auth.logout()
}
}]
])
}
]])
</script>
<template>
<UDropdown mode="hover" :items="items" :ui="{ width: 'w-full', item: { disabled: 'cursor-text select-text' } }" :popper="{ strategy: 'absolute', placement: 'top' }" class="w-full">
<template #default="slotProps">
<UButton color="gray" variant="ghost" class="w-full" :label="auth.user.email" :class="[slotProps?.open && 'bg-gray-50 dark:bg-gray-800']">
<!-- <template #leading>
<UAvatar :alt="auth.user.email" size="xs" />
</template>-->
<UDropdownMenu
:items="userItems"
:content="{ align: 'start', side: 'top', sideOffset: 8 }"
:ui="{ content: 'w-[var(--reka-dropdown-menu-trigger-width)] max-w-[var(--reka-dropdown-menu-trigger-width)]' }"
class="block w-full"
>
<template #default="{ open }">
<UButton
color="gray"
variant="ghost"
class="w-full min-w-0 justify-start gap-2 rounded-lg px-2.5 py-2 text-left"
:class="[open && 'bg-gray-100 dark:bg-gray-800']"
>
<span class="min-w-0 flex-1 truncate font-medium text-gray-900 dark:text-white">
{{ auth.user.email }}
</span>
<template #trailing>
<UIcon name="i-heroicons-ellipsis-vertical" class="w-5 h-5 ml-auto" />
<UIcon name="i-heroicons-ellipsis-vertical" class="h-5 w-5 shrink-0" />
</template>
</UButton>
</template>
<template #account>
<div class="text-left">
<p>
Angemeldet als
</p>
<p class="truncate font-medium text-gray-900 dark:text-white">
{{auth.user.email}}
</p>
</div>
</template>
</UDropdown>
</UDropdownMenu>
</template>

View File

@@ -73,7 +73,7 @@ const startImport = () => {
Erstelltes Dokument Kopieren
</template>
<UFormGroup
<UFormField
label="Dokumententyp:"
class="mb-3"
>
@@ -85,7 +85,7 @@ const startImport = () => {
>
</USelectMenu>
</UFormGroup>
</UFormField>
<UCheckbox
v-for="key in Object.keys(optionsToImport).filter(i => documentTypeToUse !== props.type ? !['startText','endText'].includes(i) : true)"
v-model="optionsToImport[key]"

View File

@@ -25,7 +25,7 @@ setupPage()
v-if="openTasks.length > 0"
:data="openTasks"
:columns="normalizeTableColumns([{key:'name',label:'Name'},{key:'categorie',label:'Kategorie'}])"
@select="(i) => router.push(`/tasks/show/${i.id}`)"
:on-select="(i) => router.push(`/tasks/show/${i.id}`)"
/>
<div v-else>
<p class="text-center font-bold">Keine offenen Aufgaben</p>

View File

@@ -53,15 +53,15 @@ const stopStartedTime = async () => {
<p>Start: {{dayjs(runningTimeInfo.started_at).format("HH:mm")}}</p>
<p>Dauer: {{dayjs().diff(dayjs(runningTimeInfo.started_at),'minutes') > 59 ? `${Math.floor(dayjs().diff(dayjs(runningTimeInfo.started_at),'minutes') / 60)}:${dayjs().diff(dayjs(runningTimeInfo.started_at),'minutes') % 60} h` : dayjs().diff(dayjs(runningTimeInfo.started_at),'minutes') + ' min' }}</p>
<UFormGroup
<UFormField
class="mt-2"
label="Notizen:"
>
<UTextarea
v-model="runningTimeInfo.notes"
/>
</UFormGroup>
<UFormGroup
</UFormField>
<UFormField
class="mt-2"
label="Projekt:"
>
@@ -74,7 +74,7 @@ const stopStartedTime = async () => {
value-attribute="id"
option-attribute="name"
/>
</UFormGroup>
</UFormField>
<UButton
class="mt-3"
@click="stopStartedTime"

View File

@@ -49,14 +49,14 @@ const stopStartedTime = async () => {
<p>Start: {{dayjs(runningTimeInfo.started_at).format("HH:mm")}}</p>
<p>Dauer: {{dayjs().diff(dayjs(runningTimeInfo.started_at),'minutes') > 59 ? `${Math.floor(dayjs().diff(dayjs(runningTimeInfo.started_at),'minutes') / 60)}:${dayjs().diff(dayjs(runningTimeInfo.started_at),'minutes') % 60} h` : dayjs().diff(dayjs(runningTimeInfo.started_at),'minutes') + ' min' }}</p>
<UFormGroup
<UFormField
class="mt-2"
label="Notizen:"
>
<UTextarea
v-model="runningTimeInfo.notes"
/>
</UFormGroup>
</UFormField>
<UButton
class="mt-3"
@click="stopStartedTime"

View File

@@ -47,14 +47,14 @@ async function handlePrint() {
{{labelPrinter.printProgress}}
<UFormGroup label="Breite">
<UFormField label="Breite">
<UInput v-model="labelWidth"><template #trailing>mm</template></UInput>
</UFormGroup>
<UFormGroup label="Höhe">
</UFormField>
<UFormField label="Höhe">
<UInput v-model="labelHeight"><template #trailing>mm</template></UInput>
</UFormGroup>
<UFormGroup label="ZPL">
</UFormField>
<UFormField label="ZPL">
<UTextarea v-model="zpl" rows="6" />
</UFormGroup>
</UFormField>
</UCard>
</template>

View File

@@ -99,16 +99,18 @@
</div>
<UModal v-model:open="isCreateModalOpen">
<div class="p-5">
<h3 class="font-bold mb-4">Neue Seite</h3>
<form @submit.prevent="createPage">
<UInput v-model="newTitle" placeholder="Titel..." autofocus />
<div class="mt-4 flex justify-end gap-2">
<UButton color="gray" variant="ghost" @click="isCreateModalOpen = false">Abbrechen</UButton>
<UButton type="submit" color="primary" :loading="isCreating">Erstellen</UButton>
</div>
</form>
</div>
<template #content>
<div class="p-5">
<h3 class="font-bold mb-4">Neue Seite</h3>
<form @submit.prevent="createPage">
<UInput v-model="newTitle" placeholder="Titel..." autofocus />
<div class="mt-4 flex justify-end gap-2">
<UButton color="gray" variant="ghost" @click="isCreateModalOpen = false">Abbrechen</UButton>
<UButton type="submit" color="primary" :loading="isCreating">Erstellen</UButton>
</div>
</form>
</div>
</template>
</UModal>
</div>
@@ -163,7 +165,7 @@ async function selectPage(id: string) {
const data = await $api(`/api/wiki/${id}`, { method: 'GET' })
selectedPage.value = data
} catch (e) {
toast.add({ title: 'Fehler beim Laden', color: 'red' })
toast.add({ title: 'Fehler beim Laden', color: 'error' })
} finally {
loadingContent.value = false
}