Zwischenstand
This commit is contained in:
@@ -47,6 +47,7 @@ useSeoMeta({
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UApp>
|
||||
<div class="safearea">
|
||||
<NuxtLayout>
|
||||
<NuxtPage/>
|
||||
@@ -55,6 +56,7 @@ useSeoMeta({
|
||||
<USlideovers />
|
||||
<UModals/>
|
||||
</div>
|
||||
</UApp>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ const emitConfirm = () => {
|
||||
Archivieren
|
||||
</UButton>
|
||||
<UModal v-model:open="showModal">
|
||||
<template #content>
|
||||
<UCard>
|
||||
<template #header>
|
||||
<span class="text-md font-bold">Archivieren bestätigen</span>
|
||||
@@ -57,7 +58,7 @@ const emitConfirm = () => {
|
||||
<UButton
|
||||
@click="emitConfirm"
|
||||
class="ml-2"
|
||||
color="rose"
|
||||
color="error"
|
||||
>
|
||||
Archivieren
|
||||
</UButton>
|
||||
@@ -66,6 +67,7 @@ const emitConfirm = () => {
|
||||
</div>
|
||||
</template>
|
||||
</UCard>
|
||||
</template>
|
||||
</UModal>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ const assignByIban = async () => {
|
||||
|
||||
const match = accounts.value.find((a) => normalizeIban(a.iban) === search)
|
||||
if (!match) {
|
||||
toast.add({ title: "Kein Bankkonto mit dieser IBAN gefunden.", color: "rose" })
|
||||
toast.add({ title: "Kein Bankkonto mit dieser IBAN gefunden.", color: "error" })
|
||||
return
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ const removeAssigned = (id) => {
|
||||
|
||||
const createAndAssign = async () => {
|
||||
if (!createPayload.value.iban || !createPayload.value.bic || !createPayload.value.bankName) {
|
||||
toast.add({ title: "IBAN, BIC und Bankinstitut sind Pflichtfelder.", color: "rose" })
|
||||
toast.add({ title: "IBAN, BIC und Bankinstitut sind Pflichtfelder.", color: "error" })
|
||||
return
|
||||
}
|
||||
|
||||
@@ -141,10 +141,11 @@ loadAccounts()
|
||||
</div>
|
||||
|
||||
<UModal v-model:open="showCreate">
|
||||
<template #content>
|
||||
<UCard>
|
||||
<template #header>Neue Bankverbindung erstellen</template>
|
||||
<div class="space-y-3">
|
||||
<UFormGroup label="IBAN">
|
||||
<UFormField label="IBAN">
|
||||
<InputGroup>
|
||||
<UInput
|
||||
v-model="createPayload.iban"
|
||||
@@ -160,16 +161,16 @@ loadAccounts()
|
||||
Ermitteln
|
||||
</UButton>
|
||||
</InputGroup>
|
||||
</UFormGroup>
|
||||
<UFormGroup label="BIC">
|
||||
</UFormField>
|
||||
<UFormField label="BIC">
|
||||
<UInput v-model="createPayload.bic" />
|
||||
</UFormGroup>
|
||||
<UFormGroup label="Bankinstitut">
|
||||
</UFormField>
|
||||
<UFormField label="Bankinstitut">
|
||||
<UInput v-model="createPayload.bankName" />
|
||||
</UFormGroup>
|
||||
<UFormGroup label="Beschreibung (optional)">
|
||||
</UFormField>
|
||||
<UFormField label="Beschreibung (optional)">
|
||||
<UInput v-model="createPayload.description" />
|
||||
</UFormGroup>
|
||||
</UFormField>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="flex justify-end gap-2">
|
||||
@@ -178,5 +179,6 @@ loadAccounts()
|
||||
</div>
|
||||
</template>
|
||||
</UCard>
|
||||
</template>
|
||||
</UModal>
|
||||
</template>
|
||||
|
||||
@@ -50,7 +50,7 @@ const emitConfirm = () => {
|
||||
<UButton
|
||||
@click="emitConfirm"
|
||||
class="ml-2"
|
||||
color="rose"
|
||||
color="error"
|
||||
>
|
||||
Archivieren
|
||||
</UButton>
|
||||
|
||||
@@ -51,8 +51,8 @@
|
||||
<div class="grid grid-cols-4 gap-2">
|
||||
<UTooltip text="Brutto (+19%)"><UButton color="green" variant="soft" block size="xs" @click="applyTax(19)">+19%</UButton></UTooltip>
|
||||
<UTooltip text="Brutto (+7%)"><UButton color="green" variant="soft" block size="xs" @click="applyTax(7)">+7%</UButton></UTooltip>
|
||||
<UTooltip text="Netto (-19%)"><UButton color="rose" variant="soft" block size="xs" @click="removeTax(19)">-19%</UButton></UTooltip>
|
||||
<UTooltip text="Netto (-7%)"><UButton color="rose" variant="soft" block size="xs" @click="removeTax(7)">-7%</UButton></UTooltip>
|
||||
<UTooltip text="Netto (-19%)"><UButton color="error" variant="soft" block size="xs" @click="removeTax(19)">-19%</UButton></UTooltip>
|
||||
<UTooltip text="Netto (-7%)"><UButton color="error" variant="soft" block size="xs" @click="removeTax(7)">-7%</UButton></UTooltip>
|
||||
|
||||
<UTooltip text="Löschen"><UButton color="gray" variant="ghost" block @click="clear">C</UButton></UTooltip>
|
||||
<UTooltip text="Speicher +"><UButton color="gray" variant="ghost" block @click="addToSum">M+</UButton></UTooltip>
|
||||
|
||||
@@ -187,7 +187,7 @@ const moveFile = async () => {
|
||||
<div class="w-2/3 p-5" v-if="!false">
|
||||
<UButtonGroup>
|
||||
<ArchiveButton
|
||||
color="rose"
|
||||
color="error"
|
||||
variant="outline"
|
||||
type="files"
|
||||
@confirmed="archiveDocument"
|
||||
@@ -203,7 +203,7 @@ const moveFile = async () => {
|
||||
</UButton>
|
||||
</UButtonGroup>
|
||||
|
||||
<UDivider>Zuweisungen</UDivider>
|
||||
<USeparator label="Zuweisungen"/>
|
||||
<table class="w-full">
|
||||
<tr v-if="props.documentData.project">
|
||||
<td>Projekt</td>
|
||||
@@ -279,7 +279,7 @@ const moveFile = async () => {
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<UDivider class="my-3">Datei zuweisen</UDivider>
|
||||
<USeparator class="my-3" label="Datei zuweisen"/>
|
||||
|
||||
<UFormGroup
|
||||
label="Resource auswählen"
|
||||
@@ -308,7 +308,7 @@ const moveFile = async () => {
|
||||
|
||||
|
||||
|
||||
<UDivider class="my-5">Datei verschieben</UDivider>
|
||||
<USeparator class="my-5" label="Datei verschieben"/>
|
||||
|
||||
<InputGroup class="w-full">
|
||||
<USelectMenu
|
||||
@@ -325,7 +325,7 @@ const moveFile = async () => {
|
||||
>Verschieben</UButton>
|
||||
</InputGroup>
|
||||
|
||||
<UDivider class="my-5">Dateityp</UDivider>
|
||||
<USeparator class="my-5" label="Dateityp"/>
|
||||
|
||||
<InputGroup class="w-full">
|
||||
<USelectMenu
|
||||
@@ -337,7 +337,7 @@ const moveFile = async () => {
|
||||
@change="updateDocument"
|
||||
/>
|
||||
</InputGroup>
|
||||
<UDivider class="my-5">Dokumentenbox</UDivider>
|
||||
<USeparator class="my-5" label="Dokumentenbox" />
|
||||
|
||||
<InputGroup class="w-full">
|
||||
<USelectMenu
|
||||
|
||||
@@ -211,6 +211,22 @@ const contentChanged = (content, datapoint) => {
|
||||
}
|
||||
}
|
||||
|
||||
const getSelectItems = (datapoint) => {
|
||||
return datapoint.selectManualOptions || loadedOptions.value[datapoint.selectDataType] || []
|
||||
}
|
||||
|
||||
const getSelectValueKey = (datapoint) => {
|
||||
return datapoint.selectValueAttribute || 'id'
|
||||
}
|
||||
|
||||
const getSelectLabelKey = (datapoint) => {
|
||||
return datapoint.selectOptionAttribute || 'label'
|
||||
}
|
||||
|
||||
const getSelectSearchInput = (datapoint) => {
|
||||
return datapoint.selectSearchAttributes ? { placeholder: 'Suche...' } : false
|
||||
}
|
||||
|
||||
|
||||
const createItem = async () => {
|
||||
let ret = null
|
||||
@@ -264,7 +280,7 @@ const updateItem = async () => {
|
||||
</template>
|
||||
<template #right>
|
||||
<ArchiveButton
|
||||
color="rose"
|
||||
color="error"
|
||||
v-if="platform !== 'mobile'"
|
||||
variant="outline"
|
||||
:type="type"
|
||||
@@ -336,12 +352,12 @@ const updateItem = async () => {
|
||||
v-for="(columnName,index) in dataType.inputColumns"
|
||||
:class="platform === 'mobile' ? ['w-full'] : [`w-1/${dataType.inputColumns.length}`, ... index < dataType.inputColumns.length -1 ? ['mr-5'] : []]"
|
||||
>
|
||||
<UDivider>{{ columnName }}</UDivider>
|
||||
<USeparator :label="columnName"/>
|
||||
|
||||
<div
|
||||
v-for="datapoint in dataType.templateColumns.filter(i => i.inputType && i.inputColumn === columnName)"
|
||||
>
|
||||
<UFormGroup
|
||||
<UFormField
|
||||
v-if="(datapoint.showFunction ? datapoint.showFunction(item) : true)"
|
||||
:label="datapoint.label"
|
||||
>
|
||||
@@ -354,7 +370,7 @@ const updateItem = async () => {
|
||||
</template>
|
||||
<InputGroup class="w-full" v-if="datapoint.key.includes('.')">
|
||||
<UInput
|
||||
:color="datapoint.required ? (item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]] ? 'primary' : 'rose') : 'white'"
|
||||
:color="datapoint.required ? (item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]] ? 'primary' : 'error') : 'white'"
|
||||
class="flex-auto"
|
||||
@change="datapoint.inputChangeFunction ? datapoint.inputChangeFunction(item,loadedOptions) : null"
|
||||
v-if="['text','number'].includes(datapoint.inputType)"
|
||||
@@ -367,25 +383,25 @@ const updateItem = async () => {
|
||||
<span class="text-gray-500 dark:text-gray-400 text-xs">{{ datapoint.inputTrailing }}</span>
|
||||
</template>
|
||||
</UInput>
|
||||
<UToggle
|
||||
:color="datapoint.required ? (item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]] ? 'primary' : 'rose') : 'primary'"
|
||||
<USwitch
|
||||
:color="datapoint.required ? (item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]] ? 'primary' : 'error') : 'primary'"
|
||||
@change="datapoint.inputChangeFunction ? datapoint.inputChangeFunction(item,loadedOptions) : null"
|
||||
v-else-if="datapoint.inputType === 'bool'"
|
||||
v-model="item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]]"
|
||||
:disabled="datapoint.disabledFunction ? datapoint.disabledFunction(item) : false"
|
||||
/>
|
||||
<USelectMenu
|
||||
:color="datapoint.required ? (item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]] ? 'primary' : 'rose') : 'white'"
|
||||
:color="datapoint.required ? (item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]] ? 'primary' : 'error') : 'white'"
|
||||
class="flex-auto"
|
||||
@change="datapoint.inputChangeFunction ? datapoint.inputChangeFunction(item,loadedOptions) : null"
|
||||
v-else-if="datapoint.inputType === 'select'"
|
||||
v-model="item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]]"
|
||||
:disabled="datapoint.disabledFunction ? datapoint.disabledFunction(item) : false"
|
||||
:option-attribute="datapoint.selectOptionAttribute"
|
||||
:value-attribute="datapoint.selectValueAttribute || 'id'"
|
||||
:options="datapoint.selectManualOptions || loadedOptions[datapoint.selectDataType]"
|
||||
:searchable="datapoint.selectSearchAttributes"
|
||||
:search-attributes="datapoint.selectSearchAttributes"
|
||||
:items="getSelectItems(datapoint)"
|
||||
:label-key="getSelectLabelKey(datapoint)"
|
||||
:value-key="getSelectValueKey(datapoint)"
|
||||
:search-input="getSelectSearchInput(datapoint)"
|
||||
:filter-fields="datapoint.selectSearchAttributes"
|
||||
:multiple="datapoint.selectMultiple"
|
||||
>
|
||||
<template #empty>
|
||||
@@ -393,7 +409,7 @@ const updateItem = async () => {
|
||||
</template>
|
||||
</USelectMenu>
|
||||
<UTextarea
|
||||
:color="datapoint.required ? (item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]] ? 'primary' : 'rose') : 'white'"
|
||||
:color="datapoint.required ? (item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]] ? 'primary' : 'error') : 'white'"
|
||||
class="flex-auto"
|
||||
@change="datapoint.inputChangeFunction ? datapoint.inputChangeFunction(item,loadedOptions) : null"
|
||||
v-else-if="datapoint.inputType === 'textarea'"
|
||||
@@ -401,9 +417,9 @@ const updateItem = async () => {
|
||||
:disabled="datapoint.disabledFunction ? datapoint.disabledFunction(item) : false"
|
||||
rows="4"
|
||||
/>
|
||||
<UPopover :popper="{ placement: 'bottom-start' }" v-else-if="datapoint.inputType === 'date'">
|
||||
<UPopover :content="{ side: 'bottom', align: 'start' }" v-else-if="datapoint.inputType === 'date'">
|
||||
<UButton
|
||||
:color="datapoint.required ? (item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]] ? 'primary' : 'rose') : 'white'"
|
||||
:color="datapoint.required ? (item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]] ? 'primary' : 'error') : 'white'"
|
||||
icon="i-heroicons-calendar-days-20-solid"
|
||||
:label="item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]] ? dayjs(item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]]).format('DD.MM.YYYY') : 'Datum auswählen'"
|
||||
variant="outline"
|
||||
@@ -411,17 +427,17 @@ const updateItem = async () => {
|
||||
|
||||
/>
|
||||
|
||||
<template #panel="{ close }">
|
||||
<template #content>
|
||||
<LazyDatePicker
|
||||
@change="datapoint.inputChangeFunction ? datapoint.inputChangeFunction(item,loadedOptions) : null"
|
||||
v-model="item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]]" @close="close"
|
||||
v-model="item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]]"
|
||||
:disabled="datapoint.disabledFunction ? datapoint.disabledFunction(item) : false"
|
||||
/>
|
||||
</template>
|
||||
</UPopover>
|
||||
<UPopover :popper="{ placement: 'bottom-start' }" v-else-if="datapoint.inputType === 'datetime'">
|
||||
<UPopover :content="{ side: 'bottom', align: 'start' }" v-else-if="datapoint.inputType === 'datetime'">
|
||||
<UButton
|
||||
:color="datapoint.required ? (item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]] ? 'primary' : 'rose') : 'white'"
|
||||
:color="datapoint.required ? (item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]] ? 'primary' : 'error') : 'white'"
|
||||
icon="i-heroicons-calendar-days-20-solid"
|
||||
:label="item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]] ? dayjs(item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]]).format('DD.MM.YY HH:mm') : 'Datum auswählen'"
|
||||
variant="outline"
|
||||
@@ -429,10 +445,10 @@ const updateItem = async () => {
|
||||
|
||||
/>
|
||||
|
||||
<template #panel="{ close }">
|
||||
<template #content>
|
||||
<LazyDatePicker
|
||||
@change="datapoint.inputChangeFunction ? datapoint.inputChangeFunction(item,loadedOptions) : null"
|
||||
v-model="item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]]" @close="close"
|
||||
v-model="item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]]"
|
||||
:disabled="datapoint.disabledFunction ? datapoint.disabledFunction(item) : false"
|
||||
mode="datetime"
|
||||
/>
|
||||
@@ -460,7 +476,7 @@ const updateItem = async () => {
|
||||
<InputGroup class="w-full" v-else>
|
||||
<UInput
|
||||
class="flex-auto"
|
||||
:color="datapoint.required ? (item[datapoint.key] ? 'primary' : 'rose') : 'white'"
|
||||
:color="datapoint.required ? (item[datapoint.key] ? 'primary' : 'error') : 'white'"
|
||||
@change="datapoint.inputChangeFunction ? datapoint.inputChangeFunction(item,loadedOptions) : null"
|
||||
v-if="['text','number'].includes(datapoint.inputType)"
|
||||
v-model="item[datapoint.key]"
|
||||
@@ -472,34 +488,33 @@ const updateItem = async () => {
|
||||
{{ datapoint.inputTrailing }}
|
||||
</template>
|
||||
</UInput>
|
||||
<UToggle
|
||||
:color="datapoint.required ? (item[datapoint.key] ? 'primary' : 'rose') : 'primary'"
|
||||
<USwitch
|
||||
:color="datapoint.required ? (item[datapoint.key] ? 'primary' : 'error') : 'primary'"
|
||||
@change="datapoint.inputChangeFunction ? datapoint.inputChangeFunction(item,loadedOptions) : null"
|
||||
v-else-if="datapoint.inputType === 'bool'"
|
||||
v-model="item[datapoint.key]"
|
||||
:disabled="datapoint.disabledFunction ? datapoint.disabledFunction(item) : false"
|
||||
/>
|
||||
<USelectMenu
|
||||
:color="datapoint.required ? (item[datapoint.key] ? 'primary' : 'rose') : 'white'"
|
||||
:color="datapoint.required ? (item[datapoint.key] ? 'primary' : 'error') : 'white'"
|
||||
class="flex-auto"
|
||||
@change="datapoint.inputChangeFunction ? datapoint.inputChangeFunction(item,loadedOptions) : null"
|
||||
v-else-if="datapoint.inputType === 'select'"
|
||||
v-model="item[datapoint.key]"
|
||||
:disabled="datapoint.disabledFunction ? datapoint.disabledFunction(item) : false"
|
||||
:option-attribute="datapoint.selectOptionAttribute"
|
||||
:value-attribute="datapoint.selectValueAttribute || 'id'"
|
||||
:options="datapoint.selectManualOptions || loadedOptions[datapoint.selectDataType]"
|
||||
:searchable="datapoint.selectSearchAttributes"
|
||||
:search-attributes="datapoint.selectSearchAttributes"
|
||||
:items="getSelectItems(datapoint)"
|
||||
:label-key="getSelectLabelKey(datapoint)"
|
||||
:value-key="getSelectValueKey(datapoint)"
|
||||
:search-input="getSelectSearchInput(datapoint)"
|
||||
:filter-fields="datapoint.selectSearchAttributes"
|
||||
:multiple="datapoint.selectMultiple"
|
||||
searchable-placeholder="Suche..."
|
||||
>
|
||||
<template #empty>
|
||||
Keine Optionen verfügbar
|
||||
</template>
|
||||
</USelectMenu>
|
||||
<UTextarea
|
||||
:color="datapoint.required ? (item[datapoint.key] ? 'primary' : 'rose') : 'white'"
|
||||
:color="datapoint.required ? (item[datapoint.key] ? 'primary' : 'error') : 'white'"
|
||||
class="flex-auto"
|
||||
@change="datapoint.inputChangeFunction ? datapoint.inputChangeFunction(item,loadedOptions) : null"
|
||||
v-else-if="datapoint.inputType === 'textarea'"
|
||||
@@ -507,37 +522,36 @@ const updateItem = async () => {
|
||||
:disabled="datapoint.disabledFunction ? datapoint.disabledFunction(item) : false"
|
||||
rows="4"
|
||||
/>
|
||||
<UPopover :popper="{ placement: 'bottom-start' }" v-else-if="datapoint.inputType === 'date'">
|
||||
<UPopover :content="{ side: 'bottom', align: 'start' }" v-else-if="datapoint.inputType === 'date'">
|
||||
<UButton
|
||||
:color="datapoint.required ? (item[datapoint.key] ? 'primary' : 'rose') : 'white'"
|
||||
:color="datapoint.required ? (item[datapoint.key] ? 'primary' : 'error') : 'white'"
|
||||
icon="i-heroicons-calendar-days-20-solid"
|
||||
:label="item[datapoint.key] ? dayjs(item[datapoint.key]).format('DD.MM.YYYY') : 'Datum auswählen'"
|
||||
variant="outline"
|
||||
:disabled="datapoint.disabledFunction ? datapoint.disabledFunction(item) : false"
|
||||
/>
|
||||
|
||||
<template #panel="{ close }">
|
||||
<template #content>
|
||||
<LazyDatePicker
|
||||
@change="datapoint.inputChangeFunction ? datapoint.inputChangeFunction(item,loadedOptions) : null"
|
||||
v-model="item[datapoint.key]" @close="close"
|
||||
v-model="item[datapoint.key]"
|
||||
:disabled="datapoint.disabledFunction ? datapoint.disabledFunction(item) : false"
|
||||
/>
|
||||
</template>
|
||||
</UPopover>
|
||||
<UPopover :popper="{ placement: 'bottom-start' }" v-else-if="datapoint.inputType === 'datetime'">
|
||||
<UPopover :content="{ side: 'bottom', align: 'start' }" v-else-if="datapoint.inputType === 'datetime'">
|
||||
<UButton
|
||||
:color="datapoint.required ? (item[datapoint.key] ? 'primary' : 'rose') : 'white'"
|
||||
:color="datapoint.required ? (item[datapoint.key] ? 'primary' : 'error') : 'white'"
|
||||
icon="i-heroicons-calendar-days-20-solid"
|
||||
:label="item[datapoint.key] ? dayjs(item[datapoint.key]).format('DD.MM.YY HH:mm') : 'Datum auswählen'"
|
||||
variant="outline"
|
||||
:disabled="datapoint.disabledFunction ? datapoint.disabledFunction(item) : false"
|
||||
/>
|
||||
|
||||
<template #panel="{ close }">
|
||||
<template #content>
|
||||
<LazyDatePicker
|
||||
@change="datapoint.inputChangeFunction ? datapoint.inputChangeFunction(item,loadedOptions) : null"
|
||||
v-model="item[datapoint.key]"
|
||||
@close="close"
|
||||
:disabled="datapoint.disabledFunction ? datapoint.disabledFunction(item) : false"
|
||||
mode="datetime"
|
||||
/>
|
||||
@@ -572,11 +586,11 @@ const updateItem = async () => {
|
||||
icon="i-heroicons-x-mark"
|
||||
/>
|
||||
</InputGroup>
|
||||
</UFormGroup>
|
||||
</UFormField>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<UFormGroup
|
||||
<UFormField
|
||||
v-for="datapoint in dataType.templateColumns.filter(i => i.inputType && !i.inputColumn)"
|
||||
:label="datapoint.label"
|
||||
>
|
||||
@@ -589,7 +603,7 @@ const updateItem = async () => {
|
||||
</template>
|
||||
<InputGroup class="w-full" v-if="datapoint.key.includes('.')">
|
||||
<UInput
|
||||
:color="datapoint.required ? (item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]] ? 'primary' : 'rose') : 'white'"
|
||||
:color="datapoint.required ? (item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]] ? 'primary' : 'error') : 'white'"
|
||||
class="flex-auto"
|
||||
@change="datapoint.inputChangeFunction ? datapoint.inputChangeFunction(item,loadedOptions) : null"
|
||||
v-if="['text','number'].includes(datapoint.inputType)"
|
||||
@@ -602,25 +616,25 @@ const updateItem = async () => {
|
||||
<span class="text-gray-500 dark:text-gray-400 text-xs">{{ datapoint.inputTrailing }}</span>
|
||||
</template>
|
||||
</UInput>
|
||||
<UToggle
|
||||
:color="datapoint.required ? (item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]] ? 'primary' : 'rose') : 'primary'"
|
||||
<USwitch
|
||||
:color="datapoint.required ? (item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]] ? 'primary' : 'error') : 'primary'"
|
||||
@change="datapoint.inputChangeFunction ? datapoint.inputChangeFunction(item,loadedOptions) : null"
|
||||
v-else-if="datapoint.inputType === 'bool'"
|
||||
v-model="item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]]"
|
||||
:disabled="datapoint.disabledFunction ? datapoint.disabledFunction(item) : false"
|
||||
/>
|
||||
<USelectMenu
|
||||
:color="datapoint.required ? (item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]] ? 'primary' : 'rose') : 'white'"
|
||||
:color="datapoint.required ? (item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]] ? 'primary' : 'error') : 'white'"
|
||||
class="flex-auto"
|
||||
@change="datapoint.inputChangeFunction ? datapoint.inputChangeFunction(item,loadedOptions) : null"
|
||||
v-else-if="datapoint.inputType === 'select'"
|
||||
v-model="item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]]"
|
||||
:disabled="datapoint.disabledFunction ? datapoint.disabledFunction(item) : false"
|
||||
:option-attribute="datapoint.selectOptionAttribute"
|
||||
:value-attribute="datapoint.selectValueAttribute || 'id'"
|
||||
:options="datapoint.selectManualOptions || loadedOptions[datapoint.selectDataType]"
|
||||
:searchable="datapoint.selectSearchAttributes"
|
||||
:search-attributes="datapoint.selectSearchAttributes"
|
||||
:items="getSelectItems(datapoint)"
|
||||
:label-key="getSelectLabelKey(datapoint)"
|
||||
:value-key="getSelectValueKey(datapoint)"
|
||||
:search-input="getSelectSearchInput(datapoint)"
|
||||
:filter-fields="datapoint.selectSearchAttributes"
|
||||
:multiple="datapoint.selectMultiple"
|
||||
>
|
||||
<template #empty>
|
||||
@@ -628,7 +642,7 @@ const updateItem = async () => {
|
||||
</template>
|
||||
</USelectMenu>
|
||||
<UTextarea
|
||||
:color="datapoint.required ? (item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]] ? 'primary' : 'rose') : 'white'"
|
||||
:color="datapoint.required ? (item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]] ? 'primary' : 'error') : 'white'"
|
||||
class="flex-auto"
|
||||
@change="datapoint.inputChangeFunction ? datapoint.inputChangeFunction(item,loadedOptions) : null"
|
||||
v-else-if="datapoint.inputType === 'textarea'"
|
||||
@@ -636,9 +650,9 @@ const updateItem = async () => {
|
||||
:disabled="datapoint.disabledFunction ? datapoint.disabledFunction(item) : false"
|
||||
rows="4"
|
||||
/>
|
||||
<UPopover :popper="{ placement: 'bottom-start' }" v-else-if="datapoint.inputType === 'date'">
|
||||
<UPopover :content="{ side: 'bottom', align: 'start' }" v-else-if="datapoint.inputType === 'date'">
|
||||
<UButton
|
||||
:color="datapoint.required ? (item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]] ? 'primary' : 'rose') : 'white'"
|
||||
:color="datapoint.required ? (item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]] ? 'primary' : 'error') : 'white'"
|
||||
icon="i-heroicons-calendar-days-20-solid"
|
||||
:label="item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]] ? dayjs(item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]]).format('DD.MM.YYYY') : 'Datum auswählen'"
|
||||
variant="outline"
|
||||
@@ -646,17 +660,17 @@ const updateItem = async () => {
|
||||
|
||||
/>
|
||||
|
||||
<template #panel="{ close }">
|
||||
<template #content>
|
||||
<LazyDatePicker
|
||||
@change="datapoint.inputChangeFunction ? datapoint.inputChangeFunction(item,loadedOptions) : null"
|
||||
v-model="item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]]" @close="close"
|
||||
v-model="item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]]"
|
||||
:disabled="datapoint.disabledFunction ? datapoint.disabledFunction(item) : false"
|
||||
/>
|
||||
</template>
|
||||
</UPopover>
|
||||
<UPopover :popper="{ placement: 'bottom-start' }" v-else-if="datapoint.inputType === 'datetime'">
|
||||
<UPopover :content="{ side: 'bottom', align: 'start' }" v-else-if="datapoint.inputType === 'datetime'">
|
||||
<UButton
|
||||
:color="datapoint.required ? (item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]] ? 'primary' : 'rose') : 'white'"
|
||||
:color="datapoint.required ? (item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]] ? 'primary' : 'error') : 'white'"
|
||||
icon="i-heroicons-calendar-days-20-solid"
|
||||
:label="item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]] ? dayjs(item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]]).format('DD.MM.YY HH:mm') : 'Datum auswählen'"
|
||||
variant="outline"
|
||||
@@ -664,10 +678,10 @@ const updateItem = async () => {
|
||||
|
||||
/>
|
||||
|
||||
<template #panel="{ close }">
|
||||
<template #content>
|
||||
<LazyDatePicker
|
||||
@change="datapoint.inputChangeFunction ? datapoint.inputChangeFunction(item,loadedOptions) : null"
|
||||
v-model="item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]]" @close="close"
|
||||
v-model="item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]]"
|
||||
:disabled="datapoint.disabledFunction ? datapoint.disabledFunction(item) : false"
|
||||
mode="datetime"
|
||||
/>
|
||||
@@ -695,7 +709,7 @@ const updateItem = async () => {
|
||||
<InputGroup class="w-full" v-else>
|
||||
<UInput
|
||||
class="flex-auto"
|
||||
:color="datapoint.required ? (item[datapoint.key] ? 'primary' : 'rose') : 'white'"
|
||||
:color="datapoint.required ? (item[datapoint.key] ? 'primary' : 'error') : 'white'"
|
||||
@change="datapoint.inputChangeFunction ? datapoint.inputChangeFunction(item,loadedOptions) : null"
|
||||
v-if="['text','number'].includes(datapoint.inputType)"
|
||||
v-model="item[datapoint.key]"
|
||||
@@ -707,34 +721,33 @@ const updateItem = async () => {
|
||||
{{ datapoint.inputTrailing }}
|
||||
</template>
|
||||
</UInput>
|
||||
<UToggle
|
||||
:color="datapoint.required ? (item[datapoint.key] ? 'primary' : 'rose') : 'primary'"
|
||||
<USwitch
|
||||
:color="datapoint.required ? (item[datapoint.key] ? 'primary' : 'error') : 'primary'"
|
||||
@change="datapoint.inputChangeFunction ? datapoint.inputChangeFunction(item,loadedOptions) : null"
|
||||
v-else-if="datapoint.inputType === 'bool'"
|
||||
v-model="item[datapoint.key]"
|
||||
:disabled="datapoint.disabledFunction ? datapoint.disabledFunction(item) : false"
|
||||
/>
|
||||
<USelectMenu
|
||||
:color="datapoint.required ? (item[datapoint.key] ? 'primary' : 'rose') : 'white'"
|
||||
:color="datapoint.required ? (item[datapoint.key] ? 'primary' : 'error') : 'white'"
|
||||
class="flex-auto"
|
||||
@change="datapoint.inputChangeFunction ? datapoint.inputChangeFunction(item,loadedOptions) : null"
|
||||
v-else-if="datapoint.inputType === 'select'"
|
||||
v-model="item[datapoint.key]"
|
||||
:disabled="datapoint.disabledFunction ? datapoint.disabledFunction(item) : false"
|
||||
:option-attribute="datapoint.selectOptionAttribute"
|
||||
:value-attribute="datapoint.selectValueAttribute || 'id'"
|
||||
:options="datapoint.selectManualOptions || loadedOptions[datapoint.selectDataType]"
|
||||
:searchable="datapoint.selectSearchAttributes"
|
||||
:search-attributes="datapoint.selectSearchAttributes"
|
||||
:items="getSelectItems(datapoint)"
|
||||
:label-key="getSelectLabelKey(datapoint)"
|
||||
:value-key="getSelectValueKey(datapoint)"
|
||||
:search-input="getSelectSearchInput(datapoint)"
|
||||
:filter-fields="datapoint.selectSearchAttributes"
|
||||
:multiple="datapoint.selectMultiple"
|
||||
searchable-placeholder="Suche..."
|
||||
>
|
||||
<template #empty>
|
||||
Keine Optionen verfügbar
|
||||
</template>
|
||||
</USelectMenu>
|
||||
<UTextarea
|
||||
:color="datapoint.required ? (item[datapoint.key] ? 'primary' : 'rose') : 'white'"
|
||||
:color="datapoint.required ? (item[datapoint.key] ? 'primary' : 'error') : 'white'"
|
||||
class="flex-auto"
|
||||
@change="datapoint.inputChangeFunction ? datapoint.inputChangeFunction(item,loadedOptions) : null"
|
||||
v-else-if="datapoint.inputType === 'textarea'"
|
||||
@@ -742,37 +755,36 @@ const updateItem = async () => {
|
||||
:disabled="datapoint.disabledFunction ? datapoint.disabledFunction(item) : false"
|
||||
rows="4"
|
||||
/>
|
||||
<UPopover :popper="{ placement: 'bottom-start' }" v-else-if="datapoint.inputType === 'date'">
|
||||
<UPopover :content="{ side: 'bottom', align: 'start' }" v-else-if="datapoint.inputType === 'date'">
|
||||
<UButton
|
||||
:color="datapoint.required ? (item[datapoint.key] ? 'primary' : 'rose') : 'white'"
|
||||
:color="datapoint.required ? (item[datapoint.key] ? 'primary' : 'error') : 'white'"
|
||||
icon="i-heroicons-calendar-days-20-solid"
|
||||
:label="item[datapoint.key] ? dayjs(item[datapoint.key]).format('DD.MM.YYYY') : 'Datum auswählen'"
|
||||
variant="outline"
|
||||
:disabled="datapoint.disabledFunction ? datapoint.disabledFunction(item) : false"
|
||||
/>
|
||||
|
||||
<template #panel="{ close }">
|
||||
<template #content>
|
||||
<LazyDatePicker
|
||||
@change="datapoint.inputChangeFunction ? datapoint.inputChangeFunction(item,loadedOptions) : null"
|
||||
v-model="item[datapoint.key]" @close="close"
|
||||
v-model="item[datapoint.key]"
|
||||
:disabled="datapoint.disabledFunction ? datapoint.disabledFunction(item) : false"
|
||||
/>
|
||||
</template>
|
||||
</UPopover>
|
||||
<UPopover :popper="{ placement: 'bottom-start' }" v-else-if="datapoint.inputType === 'datetime'">
|
||||
<UPopover :content="{ side: 'bottom', align: 'start' }" v-else-if="datapoint.inputType === 'datetime'">
|
||||
<UButton
|
||||
:color="datapoint.required ? (item[datapoint.key] ? 'primary' : 'rose') : 'white'"
|
||||
:color="datapoint.required ? (item[datapoint.key] ? 'primary' : 'error') : 'white'"
|
||||
icon="i-heroicons-calendar-days-20-solid"
|
||||
:label="item[datapoint.key] ? dayjs(item[datapoint.key]).format('DD.MM.YY HH:mm') : 'Datum auswählen'"
|
||||
variant="outline"
|
||||
:disabled="datapoint.disabledFunction ? datapoint.disabledFunction(item) : false"
|
||||
/>
|
||||
|
||||
<template #panel="{ close }">
|
||||
<template #content>
|
||||
<LazyDatePicker
|
||||
@change="datapoint.inputChangeFunction ? datapoint.inputChangeFunction(item,loadedOptions) : null"
|
||||
v-model="item[datapoint.key]"
|
||||
@close="close"
|
||||
:disabled="datapoint.disabledFunction ? datapoint.disabledFunction(item) : false"
|
||||
mode="datetime"
|
||||
/>
|
||||
@@ -807,7 +819,7 @@ const updateItem = async () => {
|
||||
icon="i-heroicons-x-mark"
|
||||
/>
|
||||
</InputGroup>
|
||||
</UFormGroup>
|
||||
</UFormField>
|
||||
</UForm>
|
||||
</UDashboardPanelContent>
|
||||
</template>
|
||||
|
||||
@@ -110,12 +110,6 @@ const filteredRows = computed(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FloatingActionButton
|
||||
:label="`+ ${dataType.labelSingle}`"
|
||||
variant="outline"
|
||||
v-if="platform === 'mobile'"
|
||||
@click="router.push(`/standardEntity/${type}/create`)"
|
||||
/>
|
||||
<UDashboardNavbar :title="dataType.label" :badge="filteredRows.length">
|
||||
<template #toggle>
|
||||
<div v-if="platform === 'mobile'"></div>
|
||||
@@ -138,7 +132,7 @@ const filteredRows = computed(() => {
|
||||
<UButton
|
||||
icon="i-heroicons-x-mark"
|
||||
variant="outline"
|
||||
color="rose"
|
||||
color="error"
|
||||
@click="clearSearchString()"
|
||||
v-if="searchString.length > 0"
|
||||
/>
|
||||
@@ -169,7 +163,7 @@ const filteredRows = computed(() => {
|
||||
:ui-menu="{ width: 'min-w-max' }"
|
||||
@change="tempStore.modifyColumns(type,selectedColumns)"
|
||||
>
|
||||
<template #label>
|
||||
<template>
|
||||
Spalten
|
||||
</template>
|
||||
</USelectMenu>
|
||||
|
||||
@@ -248,7 +248,7 @@ const selectItem = (item) => {
|
||||
</template>
|
||||
</Toolbar>
|
||||
<UTable
|
||||
:rows="props.item.createddocuments.filter(i => !i.archived)"
|
||||
:data="props.item.createddocuments.filter(i => !i.archived)"
|
||||
:columns="normalizeTableColumns(columns)"
|
||||
class="w-full"
|
||||
:ui="{ divide: 'divide-gray-200 dark:divide-gray-800' }"
|
||||
|
||||
@@ -65,7 +65,7 @@ const renderDatapointValue = (datapoint) => {
|
||||
</template>
|
||||
<UAlert
|
||||
v-if="props.item.archived"
|
||||
color="rose"
|
||||
color="error"
|
||||
variant="outline"
|
||||
:title="`${dataType.labelSingle} archiviert`"
|
||||
icon="i-heroicons-archive-box"
|
||||
|
||||
@@ -77,7 +77,7 @@ const renderedAllocations = computed(() => {
|
||||
<UCard class="mt-5">
|
||||
<UTable
|
||||
v-if="props.item.statementallocations"
|
||||
:rows="renderedAllocations"
|
||||
: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' }"
|
||||
|
||||
@@ -68,7 +68,7 @@ const columns = [
|
||||
<UTable
|
||||
class="mt-3"
|
||||
:columns="normalizeTableColumns(columns)"
|
||||
:rows="props.item.times"
|
||||
:data="props.item.times"
|
||||
:empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Noch keine Einträge' }"
|
||||
>
|
||||
<template #state-data="{row}">
|
||||
|
||||
@@ -58,76 +58,100 @@
|
||||
const dataType = dataStore.dataTypes[props.type]
|
||||
|
||||
const selectedItem = ref(0)
|
||||
const sort = ref({
|
||||
column: dataType.sortColumn || "date",
|
||||
direction: 'desc'
|
||||
})
|
||||
const sorting = ref([{
|
||||
id: dataType.sortColumn || "date",
|
||||
desc: true
|
||||
}])
|
||||
const normalizedColumns = computed(() => normalizeTableColumns(props.columns))
|
||||
const truncateValue = (value, maxLength) => {
|
||||
if (value === null || value === undefined || value === '') {
|
||||
return '\u00A0'
|
||||
}
|
||||
|
||||
const stringValue = String(value)
|
||||
if (!maxLength || stringValue.length <= maxLength) {
|
||||
return stringValue
|
||||
}
|
||||
|
||||
return `${stringValue.substring(0, maxLength)}...`
|
||||
}
|
||||
const handleSortChange = (value) => {
|
||||
const nextSort = Array.isArray(value) ? value[0] : undefined
|
||||
|
||||
if (!nextSort?.id) {
|
||||
return
|
||||
}
|
||||
|
||||
emit('sort', {
|
||||
sort_column: nextSort.id,
|
||||
sort_direction: nextSort.desc ? 'desc' : 'asc'
|
||||
})
|
||||
}
|
||||
const handleSelect = (row) => {
|
||||
router.push(getShowRoute(props.type, row.original.id))
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UTable
|
||||
:loading="props.loading"
|
||||
:loading-state="{ icon: 'i-heroicons-arrow-path-20-solid', label: 'Loading...' }"
|
||||
sort-mode="manual"
|
||||
v-model:sort="sort"
|
||||
@update:sort="emit('sort',{sort_column: sort.column, sort_direction: sort.direction})"
|
||||
v-model:sorting="sorting"
|
||||
@update:sorting="handleSortChange"
|
||||
v-if="dataType && columns"
|
||||
:rows="props.rows"
|
||||
:data="props.rows"
|
||||
:columns="normalizedColumns"
|
||||
class="w-full"
|
||||
:ui="{ divide: 'divide-gray-200 dark:divide-gray-800' }"
|
||||
@select="(i) => router.push(getShowRoute(type, i.id))"
|
||||
:empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: `Keine ${dataType.label} anzuzeigen` }"
|
||||
:on-select="handleSelect"
|
||||
:empty="`Keine ${dataType.label} anzuzeigen`"
|
||||
>
|
||||
<!-- <template
|
||||
v-for="column in dataType.templateColumns.filter(i => !i.disabledInTable)"
|
||||
v-slot:[`${column.key}-header`]="{row}">
|
||||
<span class="text-nowrap">{{column.label}}</span>
|
||||
</template>-->
|
||||
<template #name-data="{row}">
|
||||
<template #name-cell="{ row }">
|
||||
<span
|
||||
v-if="row.id === props.rows[selectedItem].id"
|
||||
class="text-primary-500 font-bold">
|
||||
<UTooltip
|
||||
:text="row.name"
|
||||
v-if="row.original.id === props.rows[selectedItem]?.id"
|
||||
class="block truncate text-primary-500 font-bold"
|
||||
>
|
||||
{{dataType.templateColumns.find(i => i.key === "name").maxLength ? (row.name.length > dataType.templateColumns.find(i => i.key === "name").maxLength ? `${row.name.substring(0,dataType.templateColumns.find(i => i.key === "name").maxLength)}...` : row.name ) : row.name}}
|
||||
<UTooltip :text="row.original.name">
|
||||
<span class="block truncate">
|
||||
{{ truncateValue(row.original.name, dataType.templateColumns.find(i => i.key === "name")?.maxLength) }}
|
||||
</span>
|
||||
</UTooltip> </span>
|
||||
<span v-else>
|
||||
<UTooltip
|
||||
:text="row.name"
|
||||
>
|
||||
{{dataType.templateColumns.find(i => i.key === "name").maxLength ? (row.name.length > dataType.templateColumns.find(i => i.key === "name").maxLength ? `${row.name.substring(0,dataType.templateColumns.find(i => i.key === "name").maxLength)}...` : row.name ) : row.name}}
|
||||
<span v-else class="block truncate">
|
||||
<UTooltip :text="row.original.name">
|
||||
<span class="block truncate">
|
||||
{{ truncateValue(row.original.name, dataType.templateColumns.find(i => i.key === "name")?.maxLength) }}
|
||||
</span>
|
||||
</UTooltip>
|
||||
</span>
|
||||
</template>
|
||||
<template #fullName-data="{row}">
|
||||
<template #fullName-cell="{ row }">
|
||||
<span
|
||||
v-if="row.id === props.rows[selectedItem].id"
|
||||
class="text-primary-500 font-bold">{{row.fullName}}
|
||||
v-if="row.original.id === props.rows[selectedItem]?.id"
|
||||
class="block truncate text-primary-500 font-bold">{{ row.original.fullName }}
|
||||
</span>
|
||||
<span v-else>
|
||||
{{row.fullName}}
|
||||
<span v-else class="block truncate">
|
||||
{{ row.original.fullName }}
|
||||
</span>
|
||||
</template>
|
||||
<template #licensePlate-data="{row}">
|
||||
<template #licensePlate-cell="{ row }">
|
||||
<span
|
||||
v-if="row.id === props.rows[selectedItem].id"
|
||||
class="text-primary-500 font-bold">{{row.licensePlate}}
|
||||
v-if="row.original.id === props.rows[selectedItem]?.id"
|
||||
class="block truncate text-primary-500 font-bold">{{ row.original.licensePlate }}
|
||||
</span>
|
||||
<span v-else>
|
||||
{{row.licensePlate}}
|
||||
<span v-else class="block truncate">
|
||||
{{ row.original.licensePlate }}
|
||||
</span>
|
||||
</template>
|
||||
<template
|
||||
v-for="column in dataType.templateColumns.filter(i => i.key !== 'name' && i.key !== 'fullName' && i.key !== 'licensePlate' && !i.disabledInTable)"
|
||||
v-slot:[`${column.key}-data`]="{row}">
|
||||
<component v-if="column.component" :is="column.component" :row="row"></component>
|
||||
<span v-else-if="row[column.key]">
|
||||
<UTooltip :text="row[column.key]">
|
||||
{{row[column.key] ? `${column.maxLength ? (row[column.key].length > column.maxLength ? `${row[column.key].substring(0,column.maxLength)}...` : row[column.key]) : row[column.key]} ${column.unit ? column.unit : ''}`: ''}}
|
||||
v-slot:[`${column.key}-cell`]="{ row }">
|
||||
<component v-if="column.component" :is="column.component" :row="row.original"></component>
|
||||
<span v-else-if="row.original[column.key]" class="block truncate">
|
||||
<UTooltip :text="String(row.original[column.key])">
|
||||
<span class="block truncate">
|
||||
{{ `${truncateValue(row.original[column.key], column.maxLength)}${column.unit ? ` ${column.unit}` : ''}` }}
|
||||
</span>
|
||||
</UTooltip>
|
||||
</span>
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
|
||||
<!-- <UTable
|
||||
v-if="dataType && columns"
|
||||
:rows="props.rows"
|
||||
:data="props.rows"
|
||||
:columns="props.columns"
|
||||
class="w-full"
|
||||
:ui="{ divide: 'divide-gray-200 dark:divide-gray-800' }"
|
||||
|
||||
@@ -132,7 +132,7 @@ const addContactRequest = async () => {
|
||||
toast.add({title: "Anfrage erfolgreich erstellt"})
|
||||
resetContactRequest()
|
||||
} else {
|
||||
toast.add({title: "Anfrage konnte nicht erstellt werden",color:"rose"})
|
||||
toast.add({title: "Anfrage konnte nicht erstellt werden",color:"error"})
|
||||
}
|
||||
loadingContactRequest.value = false
|
||||
}
|
||||
@@ -302,7 +302,7 @@ watch(isHelpSlideoverOpen, async (isOpen) => {
|
||||
</UButton>
|
||||
<UButton
|
||||
type="reset"
|
||||
color="rose"
|
||||
color="error"
|
||||
variant="outline"
|
||||
:disabled="!contactRequestData.title && !contactRequestData.message"
|
||||
>
|
||||
|
||||
@@ -129,7 +129,7 @@ const renderText = (text) => {
|
||||
+ Eintrag
|
||||
</UButton>
|
||||
</div>
|
||||
<UDivider class="my-3"/>
|
||||
<USeparator class="my-3"/>
|
||||
</div>
|
||||
|
||||
<!-- ITEM LIST -->
|
||||
@@ -138,7 +138,7 @@ const renderText = (text) => {
|
||||
v-if="items.length > 0"
|
||||
v-for="(item,index) in items.slice().reverse()"
|
||||
>
|
||||
<UDivider
|
||||
<USeparator
|
||||
class="my-3"
|
||||
v-if="index !== 0"
|
||||
/>
|
||||
|
||||
@@ -86,7 +86,7 @@ defineShortcuts({
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<UDivider />
|
||||
<USeparator />
|
||||
</div>
|
||||
</UDashboardPanelContent>
|
||||
</template>
|
||||
@@ -34,7 +34,7 @@ defineProps({
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<UDivider class="my-5" />
|
||||
<USeparator class="my-5" />
|
||||
|
||||
<div class="flex-1">
|
||||
<p class="text-lg">
|
||||
@@ -42,7 +42,7 @@ defineProps({
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<UDivider class="my-5" />
|
||||
<USeparator class="my-5" />
|
||||
|
||||
<form @submit.prevent>
|
||||
<UTextarea color="gray" required size="xl" :rows="5" :placeholder="`Reply to ${mail.from.name}`">
|
||||
|
||||
@@ -116,7 +116,7 @@ async function onSubmit(event: FormSubmitEvent<any>) {
|
||||
emit('saved')
|
||||
isOpen.value = false
|
||||
} catch (error: any) {
|
||||
toast.add({ title: 'Fehler', description: error.message, color: 'red' })
|
||||
toast.add({ title: 'Fehler', description: error.message, color: 'error' })
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
@@ -125,6 +125,7 @@ async function onSubmit(event: FormSubmitEvent<any>) {
|
||||
|
||||
<template>
|
||||
<UModal v-model:open="isOpen">
|
||||
<template #content>
|
||||
<UCard :ui="{ ring: '', divide: 'divide-y divide-gray-100 dark:divide-gray-800' }">
|
||||
<template #header>
|
||||
<div class="flex items-center justify-between">
|
||||
@@ -136,39 +137,43 @@ async function onSubmit(event: FormSubmitEvent<any>) {
|
||||
</template>
|
||||
|
||||
<UForm :schema="schema" :state="state" class="space-y-4" @submit="onSubmit">
|
||||
|
||||
<UFormGroup label="Typ" name="type">
|
||||
<USelectMenu v-model="state.type" :options="types" value-attribute="value" option-attribute="label" />
|
||||
</UFormGroup>
|
||||
<UFormField label="Typ" name="type">
|
||||
<USelectMenu
|
||||
v-model="state.type"
|
||||
:items="types"
|
||||
value-key="value"
|
||||
label-key="label"
|
||||
/>
|
||||
</UFormField>
|
||||
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<UFormGroup label="Start Datum" name="start_date">
|
||||
<UFormField label="Start Datum" name="start_date">
|
||||
<div class="flex items-center gap-2">
|
||||
<UInput type="date" v-model="state.start_date" class="flex-1" />
|
||||
<UButton color="gray" variant="soft" label="Heute" @click="setDateFieldToToday('start_date')" />
|
||||
</div>
|
||||
</UFormGroup>
|
||||
<UFormGroup label="Start Zeit" name="start_time">
|
||||
</UFormField>
|
||||
<UFormField label="Start Zeit" name="start_time">
|
||||
<UInput type="time" v-model="state.start_time" />
|
||||
</UFormGroup>
|
||||
</UFormField>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<UFormGroup label="Ende Datum" name="end_date">
|
||||
<UFormField label="Ende Datum" name="end_date">
|
||||
<div class="flex items-center gap-2">
|
||||
<UInput type="date" v-model="state.end_date" class="flex-1" />
|
||||
<UButton color="gray" variant="soft" label="Heute" @click="setDateFieldToToday('end_date')" />
|
||||
</div>
|
||||
</UFormGroup>
|
||||
<UFormGroup label="Ende Zeit" name="end_time">
|
||||
</UFormField>
|
||||
<UFormField label="Ende Zeit" name="end_time">
|
||||
<UInput type="time" v-model="state.end_time" />
|
||||
</UFormGroup>
|
||||
</UFormField>
|
||||
</div>
|
||||
<p class="text-xs text-gray-500 -mt-2">Leer lassen, wenn die Zeit noch läuft.</p>
|
||||
|
||||
<UFormGroup label="Beschreibung / Notiz" name="description">
|
||||
<UFormField label="Beschreibung / Notiz" name="description">
|
||||
<UTextarea v-model="state.description" placeholder="Was wurde gemacht?" />
|
||||
</UFormGroup>
|
||||
</UFormField>
|
||||
|
||||
<div class="flex justify-end gap-2 pt-4">
|
||||
<UButton label="Abbrechen" color="gray" variant="ghost" @click="isOpen = false" />
|
||||
@@ -176,5 +181,6 @@ async function onSubmit(event: FormSubmitEvent<any>) {
|
||||
</div>
|
||||
</UForm>
|
||||
</UCard>
|
||||
</template>
|
||||
</UModal>
|
||||
</template>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<slot name="right"/>
|
||||
</InputGroup>
|
||||
</div>
|
||||
<UDivider class="my-3"/>
|
||||
<USeparator class="my-3"/>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
27
frontend/components/UDashboardPanelContent.vue
Normal file
27
frontend/components/UDashboardPanelContent.vue
Normal file
@@ -0,0 +1,27 @@
|
||||
<script setup>
|
||||
defineOptions({
|
||||
inheritAttrs: false
|
||||
})
|
||||
|
||||
const props = defineProps({
|
||||
as: {
|
||||
type: [String, Object],
|
||||
default: 'div'
|
||||
}
|
||||
})
|
||||
|
||||
const attrs = useAttrs()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<component
|
||||
:is="props.as"
|
||||
v-bind="attrs"
|
||||
:class="[
|
||||
'min-h-0 flex-1 overflow-y-auto px-4 py-4 sm:px-6 sm:py-5',
|
||||
attrs.class
|
||||
]"
|
||||
>
|
||||
<slot />
|
||||
</component>
|
||||
</template>
|
||||
@@ -243,26 +243,26 @@ loadData()
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
<USelectMenu
|
||||
v-model="granularity"
|
||||
:options="granularityOptions"
|
||||
value-attribute="value"
|
||||
option-attribute="label"
|
||||
:items="granularityOptions"
|
||||
value-key="value"
|
||||
label-key="label"
|
||||
class="w-28"
|
||||
/>
|
||||
|
||||
<USelectMenu
|
||||
v-model="selectedYear"
|
||||
:options="yearOptions"
|
||||
value-attribute="value"
|
||||
option-attribute="label"
|
||||
:items="yearOptions"
|
||||
value-key="value"
|
||||
label-key="label"
|
||||
class="w-24"
|
||||
/>
|
||||
|
||||
<USelectMenu
|
||||
v-if="granularity === 'month'"
|
||||
v-model="selectedMonth"
|
||||
:options="monthOptions"
|
||||
value-attribute="value"
|
||||
option-attribute="label"
|
||||
:items="monthOptions"
|
||||
value-key="value"
|
||||
label-key="label"
|
||||
class="w-36"
|
||||
/>
|
||||
</div>
|
||||
@@ -288,26 +288,26 @@ loadData()
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
<USelectMenu
|
||||
v-model="granularity"
|
||||
:options="granularityOptions"
|
||||
value-attribute="value"
|
||||
option-attribute="label"
|
||||
:items="granularityOptions"
|
||||
value-key="value"
|
||||
label-key="label"
|
||||
class="w-28"
|
||||
/>
|
||||
|
||||
<USelectMenu
|
||||
v-model="selectedYear"
|
||||
:options="yearOptions"
|
||||
value-attribute="value"
|
||||
option-attribute="label"
|
||||
:items="yearOptions"
|
||||
value-key="value"
|
||||
label-key="label"
|
||||
class="w-24"
|
||||
/>
|
||||
|
||||
<USelectMenu
|
||||
v-if="granularity === 'month'"
|
||||
v-model="selectedMonth"
|
||||
:options="monthOptions"
|
||||
value-attribute="value"
|
||||
option-attribute="label"
|
||||
:items="monthOptions"
|
||||
value-key="value"
|
||||
label-key="label"
|
||||
class="w-36"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -23,7 +23,7 @@ setupPage()
|
||||
<template>
|
||||
<UTable
|
||||
v-if="openTasks.length > 0"
|
||||
:rows="openTasks"
|
||||
:data="openTasks"
|
||||
:columns="normalizeTableColumns([{key:'name',label:'Name'},{key:'categorie',label:'Kategorie'}])"
|
||||
@select="(i) => router.push(`/tasks/show/${i.id}`)"
|
||||
/>
|
||||
|
||||
@@ -29,7 +29,7 @@ const startTime = async () => {
|
||||
await setupPage()
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
toast.add({title: "Fehler beim starten der Projektzeit",color:"rose"})
|
||||
toast.add({title: "Fehler beim starten der Projektzeit",color:"error"})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ const stopStartedTime = async () => {
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
let errorId = await useError().logError(`${JSON.stringify(error)}`)
|
||||
toast.add({title: errorId ? `Fehler beim stoppen der Projektzeit (Fehler ID: ${errorId})` : `Fehler beim stoppen der Projektzeit`,color:"rose"})
|
||||
toast.add({title: errorId ? `Fehler beim stoppen der Projektzeit (Fehler ID: ${errorId})` : `Fehler beim stoppen der Projektzeit`,color:"error"})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ const startTime = async () => {
|
||||
await setupPage()
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
toast.add({title: "Fehler beim starten der Zeit",color:"rose"})
|
||||
toast.add({title: "Fehler beim starten der Zeit",color:"error"})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ const stopStartedTime = async () => {
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
let errorId = await useError().logError(`${JSON.stringify(error)}`)
|
||||
toast.add({title: errorId ? `Fehler beim stoppen der Anwesenheit (Fehler ID: ${errorId})` : `Fehler beim stoppen der Anwesenheit`,color:"rose"})
|
||||
toast.add({title: errorId ? `Fehler beim stoppen der Anwesenheit (Fehler ID: ${errorId})` : `Fehler beim stoppen der Anwesenheit`,color:"error"})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,10 @@ const props = defineProps({
|
||||
const products = ref([])
|
||||
const units = ref([])
|
||||
|
||||
const productSearchInput = {
|
||||
placeholder: 'Artikel suchen...'
|
||||
}
|
||||
|
||||
const setup = async () => {
|
||||
products.value = await useEntities("products").select()
|
||||
units.value = await useEntities("units").selectSpecial()
|
||||
@@ -80,16 +84,16 @@ const setRowData = (row) => {
|
||||
>
|
||||
<td>
|
||||
<USelectMenu
|
||||
searchable
|
||||
:search-attributes="['name']"
|
||||
:options="products"
|
||||
value-attribute="id"
|
||||
option-attribute="name"
|
||||
:items="products"
|
||||
label-key="name"
|
||||
value-key="id"
|
||||
:search-input="productSearchInput"
|
||||
:filter-fields="['name']"
|
||||
v-model="product.product"
|
||||
:color="product.product ? 'primary' : 'rose'"
|
||||
:color="product.product ? 'primary' : 'error'"
|
||||
@change="setRowData(product)"
|
||||
>
|
||||
<template #label>
|
||||
<template #default>
|
||||
{{products.find(i => i.id === product.product) ? products.find(i => i.id === product.product).name : 'Kein Artikel ausgewählt'}}
|
||||
</template>
|
||||
</USelectMenu>
|
||||
@@ -104,9 +108,9 @@ const setRowData = (row) => {
|
||||
</td>
|
||||
<td>
|
||||
<USelectMenu
|
||||
:options="units"
|
||||
value-attribute="id"
|
||||
option-attribute="name"
|
||||
:items="units"
|
||||
label-key="name"
|
||||
value-key="id"
|
||||
v-model="product.unit"
|
||||
></USelectMenu>
|
||||
</td>
|
||||
@@ -123,7 +127,7 @@ const setRowData = (row) => {
|
||||
icon="i-heroicons-x-mark"
|
||||
@click="removeProductFromMaterialComposition(product.id)"
|
||||
variant="outline"
|
||||
color="rose"
|
||||
color="error"
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -12,6 +12,10 @@ const props = defineProps({
|
||||
const hourrates = ref([])
|
||||
const units = ref([])
|
||||
|
||||
const hourrateSearchInput = {
|
||||
placeholder: 'Stundensatz suchen...'
|
||||
}
|
||||
|
||||
const setup = async () => {
|
||||
hourrates.value = await useEntities("hourrates").select()
|
||||
units.value = await useEntities("units").selectSpecial()
|
||||
@@ -82,13 +86,13 @@ const setRowData = (row) => {
|
||||
>
|
||||
<td>
|
||||
<USelectMenu
|
||||
searchable
|
||||
:search-attributes="['name']"
|
||||
:options="hourrates"
|
||||
value-attribute="id"
|
||||
option-attribute="name"
|
||||
:items="hourrates"
|
||||
label-key="name"
|
||||
value-key="id"
|
||||
:search-input="hourrateSearchInput"
|
||||
:filter-fields="['name']"
|
||||
v-model="row.hourrate"
|
||||
:color="row.hourrate ? 'primary' : 'rose'"
|
||||
:color="row.hourrate ? 'primary' : 'error'"
|
||||
@change="setRowData(row)"
|
||||
>
|
||||
<!-- <template #label>
|
||||
@@ -106,10 +110,10 @@ const setRowData = (row) => {
|
||||
</td>
|
||||
<td>
|
||||
<USelectMenu
|
||||
:options="units"
|
||||
:items="units"
|
||||
disabled
|
||||
value-attribute="id"
|
||||
option-attribute="name"
|
||||
label-key="name"
|
||||
value-key="id"
|
||||
v-model="row.unit"
|
||||
></USelectMenu>
|
||||
</td>
|
||||
@@ -134,7 +138,7 @@ const setRowData = (row) => {
|
||||
icon="i-heroicons-x-mark"
|
||||
@click="removeRowFromPersonalComposition(row.id)"
|
||||
variant="outline"
|
||||
color="rose"
|
||||
color="error"
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
35
frontend/composables/useModal.ts
Normal file
35
frontend/composables/useModal.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
type ModalComponent = any
|
||||
type ModalProps = Record<string, any> | undefined
|
||||
|
||||
const modalStack = useState<any[]>('__fed_modal_stack__', () => [])
|
||||
|
||||
export const useModal = () => {
|
||||
const overlay = useOverlay()
|
||||
|
||||
const open = (component: ModalComponent, props?: ModalProps) => {
|
||||
const instance = overlay.create(component, { props, destroyOnClose: true })
|
||||
modalStack.value.push(instance)
|
||||
|
||||
const result = instance.open(props)
|
||||
result.finally(() => {
|
||||
modalStack.value = modalStack.value.filter((entry) => entry.id !== instance.id)
|
||||
})
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
const close = (value?: any) => {
|
||||
const current = modalStack.value[modalStack.value.length - 1]
|
||||
|
||||
if (!current) {
|
||||
return
|
||||
}
|
||||
|
||||
current.close(value)
|
||||
}
|
||||
|
||||
return {
|
||||
open,
|
||||
close
|
||||
}
|
||||
}
|
||||
@@ -248,7 +248,7 @@ onMounted(() => {
|
||||
<TenantDropdown class="min-w-0 w-full max-w-sm" />
|
||||
</div>-->
|
||||
|
||||
<UDashboardGroup class="flex min-h-0 flex-1 flex-col overflow-hidden">
|
||||
<UDashboardGroup class="flex min-h-0 flex-1 overflow-hidden">
|
||||
|
||||
|
||||
<UDashboardSidebar
|
||||
@@ -298,7 +298,7 @@ onMounted(() => {
|
||||
</UButton>
|
||||
</div>
|
||||
|
||||
<UDivider class="sticky bottom-0 w-full"/>
|
||||
<USeparator class="sticky bottom-0 w-full"/>
|
||||
<UserDropdown style="margin-bottom: env(safe-area-inset-bottom, 10px) !important;" class="w-full"/>
|
||||
</div>
|
||||
</template>
|
||||
@@ -345,7 +345,7 @@ onMounted(() => {
|
||||
</div>
|
||||
<UButton
|
||||
variant="outline"
|
||||
color="rose"
|
||||
color="error"
|
||||
@click="auth.logout()"
|
||||
>Abmelden
|
||||
</UButton>
|
||||
|
||||
@@ -254,7 +254,7 @@ onMounted(loadData)
|
||||
|
||||
<UTable
|
||||
:columns="normalizeTableColumns(columns)"
|
||||
:rows="periods"
|
||||
:data="periods"
|
||||
:loading="loading"
|
||||
:empty-state="{ icon: 'i-heroicons-calculator', label: 'Keine Daten für die USt-Auswertung vorhanden' }"
|
||||
>
|
||||
|
||||
@@ -158,7 +158,7 @@ setupPage()
|
||||
<UButton
|
||||
icon="i-heroicons-x-mark"
|
||||
variant="outline"
|
||||
color="rose"
|
||||
color="error"
|
||||
@click="clearSearchString()"
|
||||
v-if="searchString.length > 0"
|
||||
/>
|
||||
@@ -194,7 +194,7 @@ setupPage()
|
||||
</template>
|
||||
</UDashboardToolbar>
|
||||
<UTable
|
||||
:rows="filteredRows"
|
||||
:data="filteredRows"
|
||||
:columns="normalizeTableColumns(columns)"
|
||||
class="w-full"
|
||||
:ui="{ divide: 'divide-gray-200 dark:divide-gray-800' }"
|
||||
|
||||
@@ -137,7 +137,7 @@ const saldo = computed(() => {
|
||||
<UCard class="mt-5" v-if="item.label === 'Buchungen'">
|
||||
<UTable
|
||||
v-if="statementallocations"
|
||||
:rows="renderedAllocations"
|
||||
: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' }"
|
||||
|
||||
@@ -504,7 +504,7 @@ onMounted(() => {
|
||||
placeholder="Konten"
|
||||
class="w-48"
|
||||
/>
|
||||
<UDivider orientation="vertical" class="h-6"/>
|
||||
<USeparator orientation="vertical" class="h-6"/>
|
||||
<div class="flex items-center gap-2">
|
||||
<USelectMenu
|
||||
v-model="selectedPeriod"
|
||||
@@ -633,7 +633,7 @@ onMounted(() => {
|
||||
</div>
|
||||
<div class="mt-2 flex flex-wrap gap-1">
|
||||
<UBadge v-if="entry.suggestions?.topDocument" size="xs" color="emerald" variant="subtle">Rechnung</UBadge>
|
||||
<UBadge v-if="entry.suggestions?.topIncomingInvoice" size="xs" color="rose" variant="subtle">Eingangsbeleg</UBadge>
|
||||
<UBadge v-if="entry.suggestions?.topIncomingInvoice" size="xs" color="error" variant="subtle">Eingangsbeleg</UBadge>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -690,7 +690,7 @@ onMounted(() => {
|
||||
</UBadge>
|
||||
</div>
|
||||
</div>
|
||||
<UButton size="sm" color="rose" @click="handleAssignIncomingInvoice(selectedSuggestionRow.row, selectedSuggestionRow.suggestions.topIncomingInvoice, $event)">
|
||||
<UButton size="sm" color="error" @click="handleAssignIncomingInvoice(selectedSuggestionRow.row, selectedSuggestionRow.suggestions.topIncomingInvoice, $event)">
|
||||
Zuweisen
|
||||
</UButton>
|
||||
<UButton size="sm" color="gray" variant="ghost" @click="dismissSuggestion(selectedSuggestionRow.row, selectedSuggestionRow.suggestions.topIncomingInvoice.suggestionKey, $event)">
|
||||
|
||||
@@ -438,7 +438,7 @@ setup()
|
||||
<UBadge v-else color="amber" variant="subtle">Offen</UBadge>
|
||||
</template>
|
||||
<template #right>
|
||||
<ArchiveButton color="rose" variant="outline" type="bankstatements" @confirmed="archiveStatement"/>
|
||||
<ArchiveButton color="error" variant="outline" type="bankstatements" @confirmed="archiveStatement"/>
|
||||
</template>
|
||||
</UDashboardNavbar>
|
||||
|
||||
@@ -552,7 +552,7 @@ setup()
|
||||
<div class="font-mono text-sm font-semibold">{{ displayCurrency(item.amount) }}</div>
|
||||
<UButton
|
||||
icon="i-heroicons-trash"
|
||||
color="rose"
|
||||
color="error"
|
||||
variant="ghost"
|
||||
size="xs"
|
||||
class="opacity-0 group-hover:opacity-100 transition-opacity"
|
||||
@@ -747,7 +747,7 @@ setup()
|
||||
</div>
|
||||
<UButton
|
||||
size="xs"
|
||||
color="rose"
|
||||
color="error"
|
||||
@click="saveAllocation({incominginvoice: invoice.id, bankstatement: itemInfo.id, amount: Number(Math.abs(getInvoiceSum(invoice,true)) > Math.abs(manualAllocationSum) ? manualAllocationSum : getInvoiceSum(invoice,true)), description: allocationDescription || 'Automatischer Vorschlag'})"
|
||||
>
|
||||
Beleg zuweisen
|
||||
@@ -867,7 +867,7 @@ setup()
|
||||
v-if="!itemInfo.statementallocations.find(i => i.incominginvoice === item.id)"
|
||||
icon="i-heroicons-check"
|
||||
size="sm"
|
||||
color="rose"
|
||||
color="error"
|
||||
variant="soft"
|
||||
@click="saveAllocation({incominginvoice: item.id, bankstatement: itemInfo.id, amount: Number(Math.abs(getInvoiceSum(item,true)) > Math.abs(manualAllocationSum) ? manualAllocationSum : getInvoiceSum(item,true)), description: allocationDescription})"
|
||||
/>
|
||||
|
||||
@@ -1609,7 +1609,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
</template>
|
||||
<template #right>
|
||||
<ArchiveButton
|
||||
color="rose"
|
||||
color="error"
|
||||
type="createddocuments"
|
||||
v-if="itemInfo.state === 'Entwurf' || itemInfo.type === 'serialInvoices'"
|
||||
variant="outline"
|
||||
@@ -1646,7 +1646,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
<UAlert
|
||||
class="my-5"
|
||||
title="Vorhandene Probleme und Informationen:"
|
||||
:color="findDocumentErrors.filter(i => i.type === 'breaking').length > 0 ? 'rose' : 'white'"
|
||||
:color="findDocumentErrors.filter(i => i.type === 'breaking').length > 0 ? 'error' : 'white'"
|
||||
variant="outline"
|
||||
v-if="findDocumentErrors.length > 0"
|
||||
>
|
||||
@@ -1761,7 +1761,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
searchable-placeholder="Suche..."
|
||||
:search-attributes="['name']"
|
||||
class="w-full"
|
||||
:color="itemInfo.letterhead ? 'primary' : 'rose'"
|
||||
:color="itemInfo.letterhead ? 'primary' : 'error'"
|
||||
>
|
||||
<template #label>
|
||||
{{ itemInfo.letterhead ? letterheads.find(i => i.id === itemInfo.letterhead).name : "Kein Briefpapier gewählt" }}
|
||||
@@ -1788,7 +1788,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
{{ option.name }}{{ option.nameAddition }}
|
||||
</template>
|
||||
<UButton
|
||||
:color="itemInfo.customer ? 'primary' : 'rose'"
|
||||
:color="itemInfo.customer ? 'primary' : 'error'"
|
||||
variant="outline"
|
||||
class="w-full"
|
||||
>
|
||||
@@ -1902,7 +1902,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
>Kontakt</UButton>-->
|
||||
<UButton
|
||||
variant="outline"
|
||||
color="rose"
|
||||
color="error"
|
||||
v-if="itemInfo.contact"
|
||||
icon="i-heroicons-x-mark"
|
||||
@click="itemInfo.contact = null"
|
||||
@@ -1923,7 +1923,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
<UInput
|
||||
v-model="itemInfo.address.street"
|
||||
:placeholder="itemInfo.customer ? customers.find(i => i.id === itemInfo.customer).infoData.street : 'Straße + Hausnummer'"
|
||||
:color="itemInfo.address.street ? 'primary' : 'rose'"
|
||||
:color="itemInfo.address.street ? 'primary' : 'error'"
|
||||
/>
|
||||
<UInput
|
||||
v-model="itemInfo.address.special"
|
||||
@@ -1940,13 +1940,13 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
@input="sanitizeAddressZipInput"
|
||||
@change="checkAddressZip"
|
||||
:placeholder="itemInfo.customer ? customers.find(i => i.id === itemInfo.customer).infoData.zip : 'PLZ'"
|
||||
:color="itemInfo.address.zip ? 'primary' : 'rose'"
|
||||
:color="itemInfo.address.zip ? 'primary' : 'error'"
|
||||
/>
|
||||
<UInput
|
||||
class="flex-auto"
|
||||
v-model="itemInfo.address.city"
|
||||
:placeholder="itemInfo.customer ? customers.find(i => i.id === itemInfo.customer).infoData.city : 'Ort'"
|
||||
:color="itemInfo.address.city ? 'primary' : 'rose'"
|
||||
:color="itemInfo.address.city ? 'primary' : 'error'"
|
||||
/>
|
||||
</InputGroup>
|
||||
</UFormGroup>
|
||||
@@ -2132,7 +2132,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
</USelectMenu>
|
||||
<UButton
|
||||
variant="outline"
|
||||
color="rose"
|
||||
color="error"
|
||||
v-if="itemInfo.plant"
|
||||
icon="i-heroicons-x-mark"
|
||||
@click="itemInfo.plant = null"
|
||||
@@ -2171,7 +2171,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
</USelectMenu>
|
||||
<UButton
|
||||
variant="outline"
|
||||
color="rose"
|
||||
color="error"
|
||||
v-if="itemInfo.project"
|
||||
icon="i-heroicons-x-mark"
|
||||
@click="itemInfo.project = null"
|
||||
@@ -2210,7 +2210,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
</USelectMenu>
|
||||
<UButton
|
||||
variant="outline"
|
||||
color="rose"
|
||||
color="error"
|
||||
v-if="itemInfo.contract"
|
||||
icon="i-heroicons-x-mark"
|
||||
@click="itemInfo.contract = null"
|
||||
@@ -2229,9 +2229,9 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
</InputGroup>
|
||||
|
||||
<div v-if="itemInfo.type === 'serialInvoices'" class="mb-5">
|
||||
<UDivider class="mt-5 mb-3">
|
||||
<USeparator class="mt-5 mb-3">
|
||||
Einstellungen für die Serienrechnung
|
||||
</UDivider>
|
||||
</USeparator>
|
||||
|
||||
<div class="flex flex-row">
|
||||
<div class="w-1/3">
|
||||
@@ -2301,7 +2301,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
|
||||
</div>
|
||||
|
||||
<UDivider
|
||||
<USeparator
|
||||
class="my-3"
|
||||
/>
|
||||
|
||||
@@ -2317,7 +2317,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
<UInput v-model="itemInfo.description"/>
|
||||
</UFormGroup>
|
||||
|
||||
<UDivider
|
||||
<USeparator
|
||||
class="my-3"
|
||||
/>
|
||||
|
||||
@@ -2350,7 +2350,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
</UFormGroup>
|
||||
|
||||
|
||||
<UDivider
|
||||
<USeparator
|
||||
class="my-3"
|
||||
/>
|
||||
|
||||
@@ -2389,7 +2389,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
v-if="row.mode === 'pagebreak'"
|
||||
colspan="7"
|
||||
>
|
||||
<UDivider/>
|
||||
<USeparator/>
|
||||
</td>
|
||||
<td
|
||||
v-if="row.mode === 'text'"
|
||||
@@ -2429,7 +2429,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
:disabled="itemInfo.type === 'cancellationInvoices'"
|
||||
class="w-60"
|
||||
:options="products"
|
||||
:color="row.product ? 'primary' : 'rose'"
|
||||
:color="row.product ? 'primary' : 'error'"
|
||||
option-attribute="name"
|
||||
value-attribute="id"
|
||||
searchable
|
||||
@@ -2501,7 +2501,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
:disabled="itemInfo.type === 'cancellationInvoices'"
|
||||
class="w-60"
|
||||
:options="services"
|
||||
:color="row.service ? 'primary' : 'rose'"
|
||||
:color="row.service ? 'primary' : 'error'"
|
||||
option-attribute="name"
|
||||
value-attribute="id"
|
||||
searchable
|
||||
@@ -2942,7 +2942,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
<UButton
|
||||
:disabled="itemInfo.type === 'cancellationInvoices'"
|
||||
variant="ghost"
|
||||
color="rose"
|
||||
color="error"
|
||||
icon="i-heroicons-x-mark-16-solid"
|
||||
@click="removePosition(row.id)"
|
||||
/>
|
||||
@@ -2954,7 +2954,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
<UAlert
|
||||
v-else
|
||||
title="Keine Positionen hinzugefügt"
|
||||
color="rose"
|
||||
color="error"
|
||||
variant="outline"
|
||||
icon="i-heroicons-light-bulb"
|
||||
></UAlert>
|
||||
@@ -3004,12 +3004,12 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
</UButton>
|
||||
</InputGroup>
|
||||
|
||||
<!-- <UDivider
|
||||
<!-- <USeparator
|
||||
class="mt-5 mb-3"
|
||||
v-if="openAdvanceInvoices.length > 0 || itemInfo.usedAdvanceInvoices.length > 0"
|
||||
>
|
||||
Noch nicht abgerechnete Abschlagsrechnungen
|
||||
</UDivider>
|
||||
</USeparator>
|
||||
|
||||
<div
|
||||
v-for="advanceInvoice in openAdvanceInvoices"
|
||||
@@ -3029,7 +3029,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
<UButton
|
||||
@click="itemInfo.usedAdvanceInvoices = itemInfo.usedAdvanceInvoices.filter(i => i !== advanceInvoice.id)"
|
||||
:disabled="!itemInfo.usedAdvanceInvoices.includes(advanceInvoice.id)"
|
||||
color="rose"
|
||||
color="error"
|
||||
variant="outline"
|
||||
>
|
||||
X
|
||||
@@ -3037,7 +3037,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
</InputGroup>
|
||||
</div>-->
|
||||
|
||||
<UDivider class="my-3" v-if="Object.keys(documentTotal.titleSums).length > 0">Überschriften</UDivider>
|
||||
<USeparator class="my-3" v-if="Object.keys(documentTotal.titleSums).length > 0" label="Überschriften"/>
|
||||
|
||||
<table>
|
||||
<tr v-for="sumKey in Object.keys(documentTotal.titleSums) ">
|
||||
@@ -3046,7 +3046,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<UDivider class="my-3" v-if="itemInfo.rows.length > 0">Auswertung & Gesamt</UDivider>
|
||||
<USeparator class="my-3" v-if="itemInfo.rows.length > 0" label="Auswertung & Gesamt"/>
|
||||
|
||||
|
||||
<div class="w-full flex justify-between" v-if="itemInfo.type !== 'deliveryNotes'">
|
||||
@@ -3112,9 +3112,9 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- <UDivider
|
||||
<!-- <USeparator
|
||||
class="my-3"
|
||||
>Auswertung</UDivider>
|
||||
>Auswertung</USeparator>
|
||||
|
||||
<div class="w-full flex justify-end">
|
||||
<table class="w-1/3">
|
||||
@@ -3151,7 +3151,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
|
||||
|
||||
|
||||
<UDivider
|
||||
<USeparator
|
||||
class="my-3"
|
||||
/>
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
</UInput>
|
||||
<UButton
|
||||
v-if="searchString.length > 0"
|
||||
color="rose"
|
||||
color="error"
|
||||
icon="i-heroicons-x-mark"
|
||||
variant="outline"
|
||||
@click="clearSearchString()"
|
||||
@@ -60,7 +60,7 @@
|
||||
<UTable
|
||||
:columns="normalizeTableColumns(getColumnsForTab(item.key))"
|
||||
:empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Keine Belege anzuzeigen' }"
|
||||
:rows="getRowsForTab(item.key)"
|
||||
:data="getRowsForTab(item.key)"
|
||||
:ui="{ divide: 'divide-gray-200 dark:divide-gray-800' }"
|
||||
class="w-full"
|
||||
@select="selectItem"
|
||||
|
||||
@@ -93,7 +93,7 @@
|
||||
</div>
|
||||
|
||||
<UTable
|
||||
:rows="filteredRows"
|
||||
:data="filteredRows"
|
||||
:columns="normalizeTableColumns(columns)"
|
||||
class="w-full"
|
||||
:ui="{ divide: 'divide-gray-200 dark:divide-gray-800' }"
|
||||
@@ -158,7 +158,7 @@
|
||||
</div>
|
||||
</UFormGroup>
|
||||
|
||||
<UDivider label="Vorlagen auswählen" />
|
||||
<USeparator label="Vorlagen auswählen" />
|
||||
|
||||
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-3">
|
||||
<div class="flex flex-col sm:flex-row gap-2 w-full sm:w-auto">
|
||||
@@ -204,7 +204,7 @@
|
||||
<div class="max-h-96 overflow-y-auto border border-gray-200 dark:border-gray-800 rounded-md">
|
||||
<UTable
|
||||
v-model="selectedExecutionRows"
|
||||
:rows="filteredExecutionList"
|
||||
:data="filteredExecutionList"
|
||||
:columns="normalizeTableColumns(executionColumns)"
|
||||
:ui="{ th: { base: 'whitespace-nowrap' } }"
|
||||
>
|
||||
|
||||
@@ -94,7 +94,7 @@ const openBankstatements = () => {
|
||||
<UButton
|
||||
@click="router.push(`/createDocument/edit/?createddocument=${itemInfo.id}&loadMode=storno`)"
|
||||
variant="outline"
|
||||
color="rose"
|
||||
color="error"
|
||||
:disabled="links.find(i => i.type === 'cancellationInvoices')"
|
||||
>
|
||||
Stornieren
|
||||
|
||||
@@ -162,7 +162,7 @@ const sendEmail = async () => {
|
||||
|
||||
|
||||
if(!res.success) {
|
||||
toast.add({title: "Fehler beim Absenden der E-Mail", color: "rose"})
|
||||
toast.add({title: "Fehler beim Absenden der E-Mail", color: "error"})
|
||||
|
||||
} else {
|
||||
navigateTo("/")
|
||||
@@ -220,7 +220,7 @@ const sendEmail = async () => {
|
||||
v-model="emailData.account"
|
||||
/>
|
||||
</UFormGroup>
|
||||
<UDivider class="my-3"/>
|
||||
<USeparator class="my-3"/>
|
||||
<UFormGroup
|
||||
label="Empfänger"
|
||||
>
|
||||
@@ -255,7 +255,7 @@ const sendEmail = async () => {
|
||||
/>
|
||||
</UFormGroup>
|
||||
</div>
|
||||
<UDivider class="my-3"/>
|
||||
<USeparator class="my-3"/>
|
||||
<div id="parentAttachments" class="flex flex-col justify-center mt-3">
|
||||
<span class="font-medium mb-2 text-xl">Anhänge</span>
|
||||
<!-- <UIcon
|
||||
|
||||
@@ -39,7 +39,7 @@ const createExport = async () => {
|
||||
:loading="true"
|
||||
v-model="selected"
|
||||
:loading-state="{ icon: 'i-heroicons-arrow-path-20-solid', label: 'Loading...' }"
|
||||
:rows="createddocuments" />
|
||||
:data="createddocuments" />
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -89,7 +89,7 @@ const createExport = async () => {
|
||||
if(res.success) {
|
||||
toast.add({title: "Export wird erstellt. Sie erhalten eine Benachrichtigung sobald es soweit ist."})
|
||||
} else {
|
||||
toast.add({title: "Es gab einen Fehler beim erstellen", color: "rose"})
|
||||
toast.add({title: "Es gab einen Fehler beim erstellen", color: "error"})
|
||||
}
|
||||
|
||||
}
|
||||
@@ -110,7 +110,7 @@ const createExport = async () => {
|
||||
</UDashboardNavbar>
|
||||
|
||||
<UTable
|
||||
:rows="filteredExports"
|
||||
:data="filteredExports"
|
||||
:columns="normalizeTableColumns([
|
||||
{ key: 'created_at', label: 'Erstellt am' },
|
||||
{ key: 'start_date', label: 'Start' },
|
||||
|
||||
@@ -157,7 +157,7 @@ const updateIncomingInvoice = async (setBooked = false) => {
|
||||
toast.add({
|
||||
title: "Buchen nicht möglich",
|
||||
description: "Bitte beheben Sie zuerst die rot markierten Pflichtfehler.",
|
||||
color: "rose"
|
||||
color: "error"
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -220,7 +220,7 @@ const hasBlockingIncomingInvoiceErrors = computed(() => blockingIncomingInvoiceE
|
||||
<template #right>
|
||||
<ArchiveButton
|
||||
v-if="mode !== 'show'"
|
||||
color="rose"
|
||||
color="error"
|
||||
variant="outline"
|
||||
type="incominginvoices"
|
||||
@confirmed="useEntities('incominginvoices').archive(route.params.id)"
|
||||
@@ -286,7 +286,7 @@ const hasBlockingIncomingInvoiceErrors = computed(() => blockingIncomingInvoiceE
|
||||
<UAlert
|
||||
v-if="findIncomingInvoiceErrors.length > 0"
|
||||
title="Prüfung erforderlich"
|
||||
:color="hasBlockingIncomingInvoiceErrors ? 'rose' : 'orange'"
|
||||
:color="hasBlockingIncomingInvoiceErrors ? 'error' : 'orange'"
|
||||
variant="soft"
|
||||
icon="i-heroicons-exclamation-triangle"
|
||||
>
|
||||
@@ -323,7 +323,7 @@ const hasBlockingIncomingInvoiceErrors = computed(() => blockingIncomingInvoiceE
|
||||
<div class="flex justify-between items-center">
|
||||
<h3 class="font-semibold">Stammdaten</h3>
|
||||
<div class="flex bg-gray-100 dark:bg-gray-800 p-1 rounded-lg">
|
||||
<UButton size="xs" :variant="itemInfo.expense ? 'solid' : 'ghost'" color="rose" @click="itemInfo.expense = true" :disabled="mode === 'show'">Ausgabe</UButton>
|
||||
<UButton size="xs" :variant="itemInfo.expense ? 'solid' : 'ghost'" color="error" @click="itemInfo.expense = true" :disabled="mode === 'show'">Ausgabe</UButton>
|
||||
<UButton size="xs" :variant="!itemInfo.expense ? 'solid' : 'ghost'" color="emerald" @click="itemInfo.expense = false" :disabled="mode === 'show'">Einnahme</UButton>
|
||||
</div>
|
||||
</div>
|
||||
@@ -354,7 +354,7 @@ const hasBlockingIncomingInvoiceErrors = computed(() => blockingIncomingInvoiceE
|
||||
v-if="mode !== 'show'"
|
||||
icon="i-heroicons-x-mark"
|
||||
variant="outline"
|
||||
color="rose"
|
||||
color="error"
|
||||
:disabled="!itemInfo.vendor"
|
||||
@click="itemInfo.vendor = null"
|
||||
/>
|
||||
@@ -419,7 +419,7 @@ const hasBlockingIncomingInvoiceErrors = computed(() => blockingIncomingInvoiceE
|
||||
<UButton
|
||||
v-if="itemInfo.accounts.length > 1 && mode !== 'show'"
|
||||
icon="i-heroicons-trash"
|
||||
color="rose"
|
||||
color="error"
|
||||
variant="ghost"
|
||||
size="xs"
|
||||
class="absolute top-2 right-2"
|
||||
|
||||
@@ -191,7 +191,7 @@ const selectIncomingInvoice = (invoice) => {
|
||||
<UButton
|
||||
icon="i-heroicons-x-mark"
|
||||
variant="outline"
|
||||
color="rose"
|
||||
color="error"
|
||||
@click="clearSearchString()"
|
||||
v-if="searchString.length > 0"
|
||||
/>
|
||||
@@ -250,7 +250,7 @@ const selectIncomingInvoice = (invoice) => {
|
||||
v-model:sort="sort"
|
||||
sort-mode="manual"
|
||||
@update:sort="setupPage"
|
||||
:rows="filteredRows.filter(i => item.label === 'Gebucht' ? i.state === 'Gebucht' : i.state !== 'Gebucht' )"
|
||||
:data="filteredRows.filter(i => item.label === 'Gebucht' ? i.state === 'Gebucht' : i.state !== 'Gebucht' )"
|
||||
:columns="normalizeTableColumns(columns)"
|
||||
class="w-full"
|
||||
:ui="{ divide: 'divide-gray-200 dark:divide-gray-800' }"
|
||||
|
||||
@@ -16,7 +16,7 @@ const doLogin = async (data:any) => {
|
||||
await router.push("/")
|
||||
|
||||
} catch (err: any) {
|
||||
toast.add({title:"Zugangsdaten falsch. Bitte überprüfen Sie Ihre Eingaben",color:"rose"})
|
||||
toast.add({title:"Zugangsdaten falsch. Bitte überprüfen Sie Ihre Eingaben",color:"error"})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -423,7 +423,7 @@ onMounted(() => {
|
||||
Urlaub
|
||||
</UButton>
|
||||
<UButton
|
||||
color="rose"
|
||||
color="error"
|
||||
variant="soft"
|
||||
icon="i-heroicons-heart"
|
||||
@click="openAbsenceModal('sick')"
|
||||
|
||||
@@ -24,7 +24,7 @@ const doChange = async (data:any) => {
|
||||
await auth.logout()
|
||||
return navigateTo("/login")
|
||||
} catch (err: any) {
|
||||
toast.add({title:"Es gab ein Problem beim ändern",color:"rose"})
|
||||
toast.add({title:"Es gab ein Problem beim ändern",color:"error"})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -22,7 +22,7 @@ const doReset = async (data:any) => {
|
||||
toast.add({title:"Zurücksetzen erfolgreich"})
|
||||
return navigateTo("/login")
|
||||
} catch (err: any) {
|
||||
toast.add({title:"Problem beim zurücksetzen",color:"rose"})
|
||||
toast.add({title:"Problem beim zurücksetzen",color:"error"})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -152,7 +152,7 @@ const addPhase = () => {
|
||||
|
||||
<UForm v-else-if="mode === 'edit' || mode === 'create'">
|
||||
<UAlert
|
||||
color="rose"
|
||||
color="error"
|
||||
variant="outline"
|
||||
class="mb-5"
|
||||
v-if="mode === 'edit'"
|
||||
@@ -167,9 +167,9 @@ const addPhase = () => {
|
||||
/>
|
||||
</UFormGroup>
|
||||
|
||||
<UDivider class="mt-5">
|
||||
<USeparator class="mt-5">
|
||||
Initiale Phasen
|
||||
</UDivider>
|
||||
</USeparator>
|
||||
<UButton
|
||||
class="mt-3"
|
||||
@click="addPhase"
|
||||
@@ -284,7 +284,7 @@ const addPhase = () => {
|
||||
<UButton
|
||||
class="my-2 ml-2"
|
||||
variant="outline"
|
||||
color="rose"
|
||||
color="error"
|
||||
@click="itemInfo.initialPhases = itemInfo.initialPhases.filter(i => i !== phase)"
|
||||
>X</UButton>
|
||||
</td>
|
||||
|
||||
@@ -87,7 +87,7 @@ const filteredRows = computed(() => {
|
||||
</UDashboardNavbar>
|
||||
|
||||
<UTable
|
||||
:rows="filteredRows"
|
||||
:data="filteredRows"
|
||||
:columns="normalizeTableColumns(columns)"
|
||||
class="w-full"
|
||||
:ui="{ divide: 'divide-gray-200 dark:divide-gray-800' }"
|
||||
|
||||
@@ -492,7 +492,7 @@ onMounted(async () => {
|
||||
<div class="admin-scroll">
|
||||
<UTable
|
||||
v-if="!loading"
|
||||
:rows="userTableRows"
|
||||
:data="userTableRows"
|
||||
:columns="normalizedUserTableColumns"
|
||||
@select="selectUser"
|
||||
/>
|
||||
@@ -565,7 +565,7 @@ onMounted(async () => {
|
||||
</UForm>
|
||||
|
||||
<div>
|
||||
<UDivider label="Rollen pro Tenant" class="mb-4" />
|
||||
<USeparator label="Rollen pro Tenant" class="mb-4" />
|
||||
|
||||
<div
|
||||
v-if="userForm.tenant_ids.length"
|
||||
@@ -627,7 +627,7 @@ onMounted(async () => {
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<UDivider label="Profile im System" class="mb-4" />
|
||||
<USeparator label="Profile im System" class="mb-4" />
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<UBadge
|
||||
v-for="profile in userForm.profiles"
|
||||
@@ -674,7 +674,7 @@ onMounted(async () => {
|
||||
<div class="admin-scroll">
|
||||
<UTable
|
||||
v-if="!loading"
|
||||
:rows="tenantTableRows"
|
||||
:data="tenantTableRows"
|
||||
:columns="normalizedTenantTableColumns"
|
||||
@select="selectTenant"
|
||||
/>
|
||||
@@ -711,7 +711,7 @@ onMounted(async () => {
|
||||
</UForm>
|
||||
|
||||
<div>
|
||||
<UDivider label="Zugeordnete Benutzer" class="mb-4" />
|
||||
<USeparator label="Zugeordnete Benutzer" class="mb-4" />
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<UBadge
|
||||
v-for="user in getUsersForTenant(tenantForm.id)"
|
||||
|
||||
@@ -68,7 +68,7 @@ const addAccount = async (account) => {
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
toast.add({title: "Es gab einen Fehler beim Hinzufügen des Accounts", color:"rose"})
|
||||
toast.add({title: "Es gab einen Fehler beim Hinzufügen des Accounts", color:"error"})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ const updateAccount = async (account) => {
|
||||
setupPage()
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
toast.add({title: "Es gab einen Fehler beim Aktualisieren des Accounts", color:"rose"})
|
||||
toast.add({title: "Es gab einen Fehler beim Aktualisieren des Accounts", color:"error"})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,7 +141,7 @@ setupPage()
|
||||
v-else-if="showAlert && !bankData.id"
|
||||
title="Bank nicht gefunden"
|
||||
icon="i-heroicons-x-circle"
|
||||
color="rose"
|
||||
color="error"
|
||||
variant="outline"
|
||||
class="mt-3"
|
||||
/>
|
||||
@@ -180,7 +180,7 @@ setupPage()
|
||||
</UModal>
|
||||
|
||||
<UTable
|
||||
:rows="bankaccounts"
|
||||
:data="bankaccounts"
|
||||
:columns="normalizeTableColumns([
|
||||
{
|
||||
key: 'expired',
|
||||
|
||||
@@ -75,7 +75,7 @@ const saveAccount = async () => {
|
||||
/>
|
||||
</UFormGroup>
|
||||
|
||||
<UDivider> IMAP </UDivider>
|
||||
<USeparator label="IMAP"/>
|
||||
|
||||
<UFormGroup
|
||||
label="IMAP Host"
|
||||
@@ -102,7 +102,7 @@ const saveAccount = async () => {
|
||||
/>
|
||||
</UFormGroup>
|
||||
|
||||
<UDivider> SMTP </UDivider>
|
||||
<USeparator label="SMTP"/>
|
||||
|
||||
<UFormGroup
|
||||
label="SMTP Host"
|
||||
|
||||
@@ -82,7 +82,7 @@ const columns = computed(() => templateColumns.filter((column) => selectedColumn
|
||||
</template>
|
||||
</UDashboardNavbar>
|
||||
<UTable
|
||||
:rows="items"
|
||||
:data="items"
|
||||
:columns="normalizeTableColumns(columns)"
|
||||
class="w-full"
|
||||
@select="(i) => navigateTo(`/settings/emailaccounts/edit/${i.id}`)"
|
||||
|
||||
@@ -41,7 +41,7 @@ const isLight = computed({
|
||||
<UCard class="mt-5">
|
||||
<div v-if="item.label === 'Profil'">
|
||||
|
||||
<UDivider
|
||||
<USeparator
|
||||
class="my-3"
|
||||
label="Profil"
|
||||
/>
|
||||
@@ -58,12 +58,12 @@ const isLight = computed({
|
||||
|
||||
</div>
|
||||
<div v-else-if="item.label === 'Projekte'">
|
||||
<UDivider
|
||||
<USeparator
|
||||
label="Phasenvorlagen"
|
||||
/>
|
||||
</div>
|
||||
<div v-else-if="item.label === 'Dokumente'">
|
||||
<UDivider
|
||||
<USeparator
|
||||
label="Tags"
|
||||
class="mb-3"
|
||||
/>
|
||||
|
||||
@@ -80,7 +80,7 @@ const updateNumberRanges = async (range) => {
|
||||
<UDashboardToolbar>
|
||||
<UAlert
|
||||
title="Änderungen an diesen Werten betreffen nur neu Erstellte Einträge."
|
||||
color="rose"
|
||||
color="error"
|
||||
variant="outline"
|
||||
icon="i-heroicons-exclamation-triangle"
|
||||
/>
|
||||
|
||||
@@ -258,7 +258,7 @@ setupPage()
|
||||
<UAlert
|
||||
title="Funktionen ausblenden"
|
||||
description="Nur Funktionen mit gesetztem Haken sind im Unternehmen verfügbar. Diese Einstellungen gelten für alle Mitarbeiter und sind unabhängig von Berechtigungen."
|
||||
color="rose"
|
||||
color="error"
|
||||
variant="outline"
|
||||
class="mb-5"
|
||||
/>
|
||||
|
||||
@@ -49,7 +49,7 @@ const refreshData = async () => {
|
||||
// select() filtert bereits archivierte Einträge, wenn dataType.isArchivable true ist
|
||||
texttemplates.value = await select()
|
||||
} catch (e) {
|
||||
toast.add({ title: 'Fehler beim Laden', description: e.message, color: 'rose' })
|
||||
toast.add({ title: 'Fehler beim Laden', description: e.message, color: 'error' })
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
@@ -93,7 +93,7 @@ const handleCreate = async () => {
|
||||
editTemplateModalOpen.value = false
|
||||
await refreshData()
|
||||
} catch (e) {
|
||||
toast.add({ title: 'Fehler', description: 'Konnte nicht erstellt werden.', color: 'rose' })
|
||||
toast.add({ title: 'Fehler', description: 'Konnte nicht erstellt werden.', color: 'error' })
|
||||
} finally {
|
||||
isSaving.value = false
|
||||
}
|
||||
@@ -109,7 +109,7 @@ const handleUpdate = async () => {
|
||||
editTemplateModalOpen.value = false
|
||||
await refreshData()
|
||||
} catch (e) {
|
||||
toast.add({title: 'Fehler', description: 'Konnte nicht gespeichert werden.', color: 'rose'})
|
||||
toast.add({title: 'Fehler', description: 'Konnte nicht gespeichert werden.', color: 'error'})
|
||||
} finally {
|
||||
isSaving.value = false
|
||||
}
|
||||
@@ -122,7 +122,7 @@ const handleArchive = async (row) => {
|
||||
|
||||
await refreshData()
|
||||
} catch (e) {
|
||||
toast.add({title: 'Fehler', description: 'Konnte nicht archiviert werden.', color: 'rose'})
|
||||
toast.add({title: 'Fehler', description: 'Konnte nicht archiviert werden.', color: 'error'})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,7 +160,7 @@ const getDocLabel = (type) => {
|
||||
|
||||
<UTable
|
||||
class="mt-3"
|
||||
:rows="texttemplates"
|
||||
:data="texttemplates"
|
||||
:loading="loading"
|
||||
v-model:expand="expand"
|
||||
:empty-state="{ icon: 'i-heroicons-document-text', label: 'Keine Textvorlagen gefunden' }"
|
||||
@@ -212,7 +212,7 @@ const getDocLabel = (type) => {
|
||||
|
||||
<div class="flex justify-end gap-3">
|
||||
<ButtonWithConfirm
|
||||
color="rose"
|
||||
color="error"
|
||||
variant="soft"
|
||||
icon="i-heroicons-archive-box"
|
||||
@confirmed="handleArchive(row)"
|
||||
|
||||
@@ -179,7 +179,7 @@ onMounted(fetchProfile)
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<UDivider label="Persönliche Daten" />
|
||||
<USeparator label="Persönliche Daten" />
|
||||
|
||||
<UForm :state="profile" @submit.prevent="saveProfile" class="grid grid-cols-1 md:grid-cols-2 gap-6 mt-4">
|
||||
<UFormGroup label="Vorname">
|
||||
@@ -211,7 +211,7 @@ onMounted(fetchProfile)
|
||||
</UForm>
|
||||
</UCard>
|
||||
<UCard v-if="!pending && profile" class="mt-3">
|
||||
<UDivider label="Vertragsinformationen" />
|
||||
<USeparator label="Vertragsinformationen" />
|
||||
|
||||
<UForm :state="profile" @submit.prevent="saveProfile" class="grid grid-cols-1 md:grid-cols-2 gap-6 mt-4">
|
||||
<UFormGroup label="Vertragsart">
|
||||
@@ -256,7 +256,7 @@ onMounted(fetchProfile)
|
||||
</UCard>
|
||||
|
||||
<UCard v-if="!pending && profile" class="mt-3">
|
||||
<UDivider label="Adresse & Standort" />
|
||||
<USeparator label="Adresse & Standort" />
|
||||
|
||||
<UForm :state="profile" @submit.prevent="saveProfile" class="grid grid-cols-1 md:grid-cols-2 gap-6 mt-4">
|
||||
<UFormGroup label="Straße und Hausnummer">
|
||||
@@ -285,7 +285,7 @@ onMounted(fetchProfile)
|
||||
|
||||
|
||||
<UCard v-if="!pending && profile" class="mt-3">
|
||||
<UDivider label="Wöchentliche Arbeitsstunden" />
|
||||
<USeparator label="Wöchentliche Arbeitsstunden" />
|
||||
|
||||
<div class="mt-4 grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
<div
|
||||
@@ -313,7 +313,7 @@ onMounted(fetchProfile)
|
||||
</UCard>
|
||||
|
||||
<UCard v-if="!pending && profile" class="mt-3">
|
||||
<UDivider label="Sonstiges" />
|
||||
<USeparator label="Sonstiges" />
|
||||
<UForm :state="profile" @submit.prevent="saveProfile" class="grid grid-cols-1 md:grid-cols-2 gap-6 mt-4">
|
||||
<UFormGroup label="Kleidergröße (Oberteil)">
|
||||
<UInput v-model="profile.clothing_size_top" />
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
</template>
|
||||
</UDashboardNavbar>
|
||||
<UTable
|
||||
:rows="items"
|
||||
:data="items"
|
||||
:columns="normalizeTableColumns(columns)"
|
||||
@select="(i) => navigateTo(`/staff/profiles/${i.id}`)"
|
||||
>
|
||||
|
||||
@@ -29,7 +29,16 @@ const platformIsNative = ref(false)
|
||||
const selectedPresetRange = ref("Dieser Monat bis heute")
|
||||
const selectedStartDay = ref("")
|
||||
const selectedEndDay = ref("")
|
||||
const openTab = ref(0)
|
||||
const openTab = ref("0")
|
||||
const presetRangeItems = [
|
||||
'Dieser Monat bis heute',
|
||||
'Diese Woche',
|
||||
'Dieser Monat',
|
||||
'Dieses Jahr',
|
||||
'Letzte Woche',
|
||||
'Letzter Monat',
|
||||
'Letztes Jahr'
|
||||
]
|
||||
|
||||
const showDocument = ref(false)
|
||||
const uri = ref("")
|
||||
@@ -131,7 +140,7 @@ async function loadWorkingTimeInfo() {
|
||||
|
||||
workingTimeInfo.value = data;
|
||||
|
||||
openTab.value = 0
|
||||
openTab.value = "0"
|
||||
}
|
||||
|
||||
// 📄 PDF generieren
|
||||
@@ -172,12 +181,12 @@ async function saveFile() {
|
||||
toast.add({title:"Auswertung erfolgreich gespeichert"})
|
||||
fileSaved.value = true
|
||||
} catch (error) {
|
||||
toast.add({title:"Fehler beim Speichern der Auswertung", color: "rose"})
|
||||
toast.add({title:"Fehler beim Speichern der Auswertung", color: "error"})
|
||||
}
|
||||
}
|
||||
|
||||
async function onTabChange(index: number) {
|
||||
if (index === 1) await generateDocument()
|
||||
async function onTabChange(index: string | number) {
|
||||
if (String(index) === "1") await generateDocument()
|
||||
}
|
||||
|
||||
// Initialisierung
|
||||
@@ -204,52 +213,44 @@ await setupPage()
|
||||
</template>
|
||||
</UDashboardNavbar>
|
||||
|
||||
<UDashboardToolbar>
|
||||
<UDashboardToolbar class="py-3">
|
||||
<template #left>
|
||||
<UFormGroup label="Zeitraum:">
|
||||
<UFormField label="Zeitraum:">
|
||||
<USelectMenu
|
||||
:options="[
|
||||
'Dieser Monat bis heute',
|
||||
'Diese Woche',
|
||||
'Dieser Monat',
|
||||
'Dieses Jahr',
|
||||
'Letzte Woche',
|
||||
'Letzter Monat',
|
||||
'Letztes Jahr'
|
||||
]"
|
||||
:items="presetRangeItems"
|
||||
v-model="selectedPresetRange"
|
||||
@change="changeRange"
|
||||
/>
|
||||
</UFormGroup>
|
||||
</UFormField>
|
||||
|
||||
<UFormGroup label="Start:">
|
||||
<UPopover :popper="{ placement: 'bottom-start' }">
|
||||
<UFormField label="Start:">
|
||||
<UPopover :content="{ side: 'bottom', align: 'start' }">
|
||||
<UButton
|
||||
icon="i-heroicons-calendar-days-20-solid"
|
||||
:label="selectedStartDay ? $dayjs(selectedStartDay).format('DD.MM.YYYY') : 'Datum wählen'"
|
||||
/>
|
||||
<template #panel="{ close }">
|
||||
<template #content>
|
||||
<LazyDatePicker v-model="selectedStartDay" @close="loadWorkingTimeInfo" />
|
||||
</template>
|
||||
</UPopover>
|
||||
</UFormGroup>
|
||||
</UFormField>
|
||||
|
||||
<UFormGroup label="Ende:">
|
||||
<UPopover :popper="{ placement: 'bottom-start' }">
|
||||
<UFormField label="Ende:">
|
||||
<UPopover :content="{ side: 'bottom', align: 'start' }">
|
||||
<UButton
|
||||
icon="i-heroicons-calendar-days-20-solid"
|
||||
:label="selectedEndDay ? $dayjs(selectedEndDay).format('DD.MM.YYYY') : 'Datum wählen'"
|
||||
/>
|
||||
<template #panel="{ close }">
|
||||
<template #content>
|
||||
<LazyDatePicker v-model="selectedEndDay" @close="loadWorkingTimeInfo" />
|
||||
</template>
|
||||
</UPopover>
|
||||
</UFormGroup>
|
||||
</UFormField>
|
||||
</template>
|
||||
<template #right>
|
||||
<UTooltip
|
||||
:text="fileSaved ? 'Bericht bereits gespeichert' : 'Bericht speichern'"
|
||||
v-if="openTab === 1 && uri"
|
||||
v-if="openTab === '1' && uri"
|
||||
>
|
||||
<UButton
|
||||
icon="i-mdi-content-save"
|
||||
@@ -265,9 +266,9 @@ await setupPage()
|
||||
<UTabs
|
||||
:items="[{ label: 'Information' }, { label: 'Bericht' }]"
|
||||
v-model="openTab"
|
||||
@change="onTabChange"
|
||||
@update:model-value="onTabChange"
|
||||
>
|
||||
<template #item="{ item }">
|
||||
<template #content="{ item }">
|
||||
<div v-if="item.label === 'Information'">
|
||||
|
||||
<UCard v-if="workingTimeInfo && workingTimeInfo.summary" class="my-5">
|
||||
@@ -294,8 +295,8 @@ await setupPage()
|
||||
<UDashboardPanel>
|
||||
<UTable
|
||||
v-if="workingTimeInfo"
|
||||
:rows="workingTimeInfo.spans"
|
||||
:empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Keine Anwesenheiten' }"
|
||||
:data="workingTimeInfo.spans"
|
||||
:empty="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Keine Anwesenheiten' }"
|
||||
:columns="normalizeTableColumns([
|
||||
{ key: 'status', label: 'Status' },
|
||||
{ key: 'startedAt', label: 'Start' },
|
||||
@@ -303,30 +304,30 @@ await setupPage()
|
||||
{ key: 'duration', label: 'Dauer' },
|
||||
{ key: 'type', label: 'Typ' }
|
||||
])"
|
||||
@select="(row) => router.push(`/workingtimes/edit/${row.sourceEventIds[0]}`)"
|
||||
:on-select="(row) => router.push(`/workingtimes/edit/${row.original.sourceEventIds[0]}`)"
|
||||
>
|
||||
<template #status-data="{row}">
|
||||
<span v-if="row.status === 'approved'" class="text-primary-500">Genehmigt</span>
|
||||
<span v-else-if="row.status === 'submitted'" class="text-cyan-500">Eingereicht</span>
|
||||
<span v-else-if="row.status === 'factual'" class="text-gray-500">Faktisch</span>
|
||||
<span v-else-if="row.status === 'draft'" class="text-red-500">Entwurf</span>
|
||||
<span v-else>{{ row.status }}</span>
|
||||
<template #status-cell="{ row }">
|
||||
<span v-if="row.original.status === 'approved'" class="text-primary-500">Genehmigt</span>
|
||||
<span v-else-if="row.original.status === 'submitted'" class="text-cyan-500">Eingereicht</span>
|
||||
<span v-else-if="row.original.status === 'factual'" class="text-gray-500">Faktisch</span>
|
||||
<span v-else-if="row.original.status === 'draft'" class="text-error-500">Entwurf</span>
|
||||
<span v-else>{{ row.original.status }}</span>
|
||||
</template>
|
||||
|
||||
<template #startedAt-data="{ row }">
|
||||
{{ $dayjs(row.startedAt).format('HH:mm DD.MM.YY') }} Uhr
|
||||
<template #startedAt-cell="{ row }">
|
||||
{{ $dayjs(row.original.startedAt).format('HH:mm DD.MM.YY') }} Uhr
|
||||
</template>
|
||||
|
||||
<template #endedAt-data="{ row }">
|
||||
{{ $dayjs(row.endedAt).format('HH:mm DD.MM.YY') }} Uhr
|
||||
<template #endedAt-cell="{ row }">
|
||||
{{ $dayjs(row.original.endedAt).format('HH:mm DD.MM.YY') }} Uhr
|
||||
</template>
|
||||
|
||||
<template #duration-data="{ row }">
|
||||
{{ formatSpanDuration(row.startedAt, row.endedAt) }}
|
||||
<template #duration-cell="{ row }">
|
||||
{{ formatSpanDuration(row.original.startedAt, row.original.endedAt) }}
|
||||
</template>
|
||||
|
||||
<template #type-data="{ row }">
|
||||
{{ row.type.charAt(0).toUpperCase() + row.type.slice(1).replace('_', ' ') }}
|
||||
<template #type-cell="{ row }">
|
||||
{{ row.original.type.charAt(0).toUpperCase() + row.original.type.slice(1).replace('_', ' ') }}
|
||||
</template>
|
||||
</UTable>
|
||||
</UDashboardPanel>
|
||||
@@ -360,15 +361,7 @@ await setupPage()
|
||||
<div class="p-4 space-y-4 border-b bg-white dark:bg-gray-900">
|
||||
<USelectMenu
|
||||
v-model="selectedPresetRange"
|
||||
:options="[
|
||||
'Dieser Monat bis heute',
|
||||
'Diese Woche',
|
||||
'Dieser Monat',
|
||||
'Dieses Jahr',
|
||||
'Letzte Woche',
|
||||
'Letzter Monat',
|
||||
'Letztes Jahr'
|
||||
]"
|
||||
:items="presetRangeItems"
|
||||
@change="changeRange"
|
||||
placeholder="Zeitraum wählen"
|
||||
class="w-full"
|
||||
@@ -377,13 +370,13 @@ await setupPage()
|
||||
<div class="grid grid-cols-2 gap-3">
|
||||
<div>
|
||||
<p class="text-xs text-gray-500 mb-1">Start</p>
|
||||
<UPopover :popper="{ placement: 'bottom-start' }">
|
||||
<UPopover :content="{ side: 'bottom', align: 'start' }">
|
||||
<UButton
|
||||
icon="i-heroicons-calendar"
|
||||
class="w-full"
|
||||
:label="$dayjs(selectedStartDay).format('DD.MM.YYYY')"
|
||||
/>
|
||||
<template #panel>
|
||||
<template #content>
|
||||
<LazyDatePicker v-model="selectedStartDay" @close="loadWorkingTimeInfo" />
|
||||
</template>
|
||||
</UPopover>
|
||||
@@ -391,13 +384,13 @@ await setupPage()
|
||||
|
||||
<div>
|
||||
<p class="text-xs text-gray-500 mb-1">Ende</p>
|
||||
<UPopover :popper="{ placement: 'bottom-start' }">
|
||||
<UPopover :content="{ side: 'bottom', align: 'start' }">
|
||||
<UButton
|
||||
icon="i-heroicons-calendar"
|
||||
class="w-full"
|
||||
:label="$dayjs(selectedEndDay).format('DD.MM.YYYY')"
|
||||
/>
|
||||
<template #panel>
|
||||
<template #content>
|
||||
<LazyDatePicker v-model="selectedEndDay" @close="loadWorkingTimeInfo" />
|
||||
</template>
|
||||
</UPopover>
|
||||
@@ -408,11 +401,10 @@ await setupPage()
|
||||
<UTabs
|
||||
:items="[{ label: 'Information' }, { label: 'Bericht' }]"
|
||||
v-model="openTab"
|
||||
@change="onTabChange"
|
||||
@update:model-value="onTabChange"
|
||||
class="mt-3 mx-3"
|
||||
>
|
||||
<template #item="{ item }">
|
||||
|
||||
<template #content="{ item }">
|
||||
<div v-if="item.label === 'Information'" class="space-y-4">
|
||||
|
||||
<UCard v-if="workingTimeInfo && workingTimeInfo.summary" class="mt-3">
|
||||
@@ -459,7 +451,7 @@ await setupPage()
|
||||
|
||||
<div v-else-if="item.label === 'Bericht'">
|
||||
<UButton
|
||||
v-if="uri && !fileSaved"
|
||||
v-if="openTab === '1' && uri && !fileSaved"
|
||||
icon="i-mdi-content-save"
|
||||
color="primary"
|
||||
class="w-full mb-3"
|
||||
|
||||
@@ -32,6 +32,10 @@ const rejectReason = ref("")
|
||||
const users = ref([])
|
||||
const selectedUser = ref(auth.user.id)
|
||||
const canViewAll = computed(() => auth.permissions.includes('staff.time.read_all'))
|
||||
const userItems = computed(() => users.value.map(u => ({
|
||||
label: u.full_name || u.email,
|
||||
value: u.user_id
|
||||
})))
|
||||
|
||||
// DATA
|
||||
const entries = ref([])
|
||||
@@ -61,7 +65,7 @@ const typeLabel = {
|
||||
const typeColor = {
|
||||
work: "gray",
|
||||
vacation: "yellow",
|
||||
sick: "rose",
|
||||
sick: "error",
|
||||
holiday: "blue",
|
||||
other: "gray"
|
||||
}
|
||||
@@ -130,7 +134,7 @@ async function confirmReject() {
|
||||
showRejectModal.value = false
|
||||
await load()
|
||||
} catch (e) {
|
||||
toast.add({ title: 'Fehler beim Ablehnen', description: e.message, color: 'red' })
|
||||
toast.add({ title: 'Fehler beim Ablehnen', description: e.message, color: 'error' })
|
||||
} finally {
|
||||
loading.value = false
|
||||
entryToReject.value = null
|
||||
@@ -167,10 +171,10 @@ onMounted(async () => {
|
||||
<div v-if="canViewAll" class="flex items-center gap-2">
|
||||
<USelectMenu
|
||||
v-model="selectedUser"
|
||||
:options="users.map(u => ({ label: u.full_name || u.email, value: u.user_id }))"
|
||||
:items="userItems"
|
||||
placeholder="Benutzer auswählen"
|
||||
value-attribute="value"
|
||||
option-attribute="label"
|
||||
value-key="value"
|
||||
label-key="label"
|
||||
class="min-w-[220px]"
|
||||
:clearable="false"
|
||||
/>
|
||||
@@ -211,11 +215,11 @@ onMounted(async () => {
|
||||
</div>
|
||||
|
||||
<template v-if="isViewingSelf">
|
||||
<UButton v-if="active" color="red" icon="i-heroicons-stop" :loading="loading" label="Stoppen" @click="handleStop" />
|
||||
<UButton v-if="active" color="error" icon="i-heroicons-stop" :loading="loading" label="Stoppen" @click="handleStop" />
|
||||
<UButton v-else color="green" icon="i-heroicons-play" :loading="loading" label="Starten" @click="handleStart" />
|
||||
</template>
|
||||
<template v-else-if="active && canViewAll">
|
||||
<UButton color="red" variant="soft" icon="i-heroicons-stop" :loading="loading" label="Mitarbeiter stoppen" @click="handleStop" />
|
||||
<UButton color="error" variant="soft" icon="i-heroicons-stop" :loading="loading" label="Mitarbeiter stoppen" @click="handleStop" />
|
||||
</template>
|
||||
|
||||
<UButton color="gray" variant="solid" icon="i-heroicons-plus" label="Erfassen" @click="() => { entryToEdit = null; showEditModal = true }" />
|
||||
@@ -227,7 +231,7 @@ onMounted(async () => {
|
||||
|
||||
<UCard v-if="view === 'list'" :ui="{ body: { padding: 'p-0 sm:p-0' } }">
|
||||
<UTable
|
||||
:rows="entries"
|
||||
:data="entries"
|
||||
:columns="normalizeTableColumns([
|
||||
{ key: 'actions', label: 'Aktionen', class: 'w-32' },
|
||||
{ key: 'state', label: 'Status' },
|
||||
@@ -237,49 +241,49 @@ onMounted(async () => {
|
||||
{ key: 'type', label: 'Typ' },
|
||||
{ key: 'description', label: 'Beschreibung' },
|
||||
])"
|
||||
:empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Keine Zeiten anzuzeigen' }"
|
||||
:empty="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Keine Zeiten anzuzeigen' }"
|
||||
>
|
||||
<template #state-data="{ row }">
|
||||
<UBadge v-if="row.state === 'approved'" color="green" variant="subtle">Genehmigt</UBadge>
|
||||
<UBadge v-else-if="row.state === 'submitted'" color="cyan" variant="subtle">Eingereicht</UBadge>
|
||||
<UBadge v-else-if="row.state === 'rejected'" color="red" variant="subtle">Abgelehnt</UBadge>
|
||||
<template #state-cell="{ row }">
|
||||
<UBadge v-if="row.original.state === 'approved'" color="green" variant="subtle">Genehmigt</UBadge>
|
||||
<UBadge v-else-if="row.original.state === 'submitted'" color="cyan" variant="subtle">Eingereicht</UBadge>
|
||||
<UBadge v-else-if="row.original.state === 'rejected'" color="error" variant="subtle">Abgelehnt</UBadge>
|
||||
<UBadge v-else color="gray" variant="subtle">Entwurf</UBadge>
|
||||
</template>
|
||||
<template #type-data="{ row }">
|
||||
<UBadge :color="typeColor[row.type] || 'gray'" variant="soft">{{ typeLabel[row.type] || row.type }}</UBadge>
|
||||
<template #type-cell="{ row }">
|
||||
<UBadge :color="typeColor[row.original.type] || 'gray'" variant="soft">{{ typeLabel[row.original.type] || row.original.type }}</UBadge>
|
||||
</template>
|
||||
<template #started_at-data="{ row }">
|
||||
<span v-if="['vacation','sick'].includes(row.type)">{{ useNuxtApp().$dayjs(row.started_at).format("DD.MM.YY") }}</span>
|
||||
<span v-else>{{ useNuxtApp().$dayjs(row.started_at).format("DD.MM.YY HH:mm") }}</span>
|
||||
<template #started_at-cell="{ row }">
|
||||
<span v-if="['vacation','sick'].includes(row.original.type)">{{ useNuxtApp().$dayjs(row.original.started_at).format("DD.MM.YY") }}</span>
|
||||
<span v-else>{{ useNuxtApp().$dayjs(row.original.started_at).format("DD.MM.YY HH:mm") }}</span>
|
||||
</template>
|
||||
<template #stopped_at-data="{ row }">
|
||||
<span v-if="!row.stopped_at" class="text-primary-500 font-medium animate-pulse">läuft...</span>
|
||||
<span v-else-if="['vacation','sick'].includes(row.type)">{{ useNuxtApp().$dayjs(row.stopped_at).format("DD.MM.YY") }}</span>
|
||||
<span v-else>{{ useNuxtApp().$dayjs(row.stopped_at).format("DD.MM.YY HH:mm") }}</span>
|
||||
<template #stopped_at-cell="{ row }">
|
||||
<span v-if="!row.original.stopped_at" class="text-primary-500 font-medium animate-pulse">läuft...</span>
|
||||
<span v-else-if="['vacation','sick'].includes(row.original.type)">{{ useNuxtApp().$dayjs(row.original.stopped_at).format("DD.MM.YY") }}</span>
|
||||
<span v-else>{{ useNuxtApp().$dayjs(row.original.stopped_at).format("DD.MM.YY HH:mm") }}</span>
|
||||
</template>
|
||||
<template #duration_minutes-data="{ row }">
|
||||
{{ row.duration_minutes ? useFormatDuration(row.duration_minutes) : "-" }}
|
||||
<template #duration_minutes-cell="{ row }">
|
||||
{{ row.original.duration_minutes ? useFormatDuration(row.original.duration_minutes) : "-" }}
|
||||
</template>
|
||||
<template #actions-data="{ row }">
|
||||
<template #actions-cell="{ row }">
|
||||
<div class="flex items-center gap-1">
|
||||
<UTooltip text="Einreichen" v-if="(row.state === 'draft' || row.state === 'factual') && row.stopped_at">
|
||||
<UButton size="xs" color="cyan" variant="ghost" icon="i-heroicons-paper-airplane" @click="handleSubmit(row)" :loading="loading" />
|
||||
<UTooltip text="Einreichen" v-if="(row.original.state === 'draft' || row.original.state === 'factual') && row.original.stopped_at">
|
||||
<UButton size="xs" color="cyan" variant="ghost" icon="i-heroicons-paper-airplane" @click="handleSubmit(row.original)" :loading="loading" />
|
||||
</UTooltip>
|
||||
<UTooltip text="Genehmigen" v-if="row.state === 'submitted' && canViewAll">
|
||||
<UButton size="xs" color="green" variant="ghost" icon="i-heroicons-check" @click="handleApprove(row)" :loading="loading" />
|
||||
<UTooltip text="Genehmigen" v-if="row.original.state === 'submitted' && canViewAll">
|
||||
<UButton size="xs" color="green" variant="ghost" icon="i-heroicons-check" @click="handleApprove(row.original)" :loading="loading" />
|
||||
</UTooltip>
|
||||
<UTooltip text="Ablehnen" v-if="(row.state === 'submitted' || row.state === 'approved') && canViewAll">
|
||||
<UButton size="xs" color="red" variant="ghost" icon="i-heroicons-x-mark" @click="openRejectModal(row)" :loading="loading" />
|
||||
<UTooltip text="Ablehnen" v-if="(row.original.state === 'submitted' || row.original.state === 'approved') && canViewAll">
|
||||
<UButton size="xs" color="error" variant="ghost" icon="i-heroicons-x-mark" @click="openRejectModal(row.original)" :loading="loading" />
|
||||
</UTooltip>
|
||||
<UTooltip text="Bearbeiten" v-if="['draft', 'factual', 'submitted'].includes(row.state)">
|
||||
<UButton size="xs" color="gray" variant="ghost" icon="i-heroicons-pencil-square" @click="handleEdit(row)" />
|
||||
<UTooltip text="Bearbeiten" v-if="['draft', 'factual', 'submitted'].includes(row.original.state)">
|
||||
<UButton size="xs" color="gray" variant="ghost" icon="i-heroicons-pencil-square" @click="handleEdit(row.original)" />
|
||||
</UTooltip>
|
||||
</div>
|
||||
</template>
|
||||
<template #description-data="{ row }">
|
||||
<span v-if="row.type === 'vacation'">{{row.vacation_reason}}</span>
|
||||
<span v-else-if="row.type === 'sick'">{{row.sick_reason}}</span>
|
||||
<span v-else>{{row.description}}</span>
|
||||
<template #description-cell="{ row }">
|
||||
<span v-if="row.original.type === 'vacation'">{{ row.original.vacation_reason }}</span>
|
||||
<span v-else-if="row.original.type === 'sick'">{{ row.original.sick_reason }}</span>
|
||||
<span v-else>{{ row.original.description }}</span>
|
||||
</template>
|
||||
</UTable>
|
||||
</UCard>
|
||||
@@ -334,7 +338,7 @@ onMounted(async () => {
|
||||
|
||||
<UBadge v-if="entry.state === 'approved'" color="green" size="xs" variant="solid">Genehmigt</UBadge>
|
||||
<UBadge v-else-if="entry.state === 'submitted'" color="cyan" size="xs" variant="solid">Eingereicht</UBadge>
|
||||
<UBadge v-else-if="entry.state === 'rejected'" color="red" size="xs" variant="solid">Abgelehnt</UBadge>
|
||||
<UBadge v-else-if="entry.state === 'rejected'" color="error" size="xs" variant="solid">Abgelehnt</UBadge>
|
||||
<UBadge v-else color="gray" size="xs" variant="subtle">Entwurf</UBadge>
|
||||
</div>
|
||||
</div>
|
||||
@@ -363,7 +367,7 @@ onMounted(async () => {
|
||||
|
||||
<UButton
|
||||
v-if="(entry.state === 'submitted' || entry.state === 'approved') && canViewAll"
|
||||
size="xs" color="red" variant="ghost" icon="i-heroicons-x-mark" label="Ablehnen"
|
||||
size="xs" color="error" variant="ghost" icon="i-heroicons-x-mark" label="Ablehnen"
|
||||
@click="openRejectModal(entry)" :loading="loading"
|
||||
/>
|
||||
|
||||
@@ -403,7 +407,7 @@ onMounted(async () => {
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<template v-if="isViewingSelf">
|
||||
<UButton v-if="active" color="red" icon="i-heroicons-stop" :loading="loading" @click="handleStop" />
|
||||
<UButton v-if="active" color="error" icon="i-heroicons-stop" :loading="loading" @click="handleStop" />
|
||||
<UButton v-else color="green" icon="i-heroicons-play" :loading="loading" @click="handleStart" />
|
||||
</template>
|
||||
</div>
|
||||
@@ -422,7 +426,7 @@ onMounted(async () => {
|
||||
</div>
|
||||
<UBadge v-if="row.state === 'approved'" color="green">Genehmigt</UBadge>
|
||||
<UBadge v-else-if="row.state === 'submitted'" color="cyan">Eingereicht</UBadge>
|
||||
<UBadge v-else-if="row.state === 'rejected'" color="red">Abgelehnt</UBadge>
|
||||
<UBadge v-else-if="row.state === 'rejected'" color="error">Abgelehnt</UBadge>
|
||||
<UBadge v-else color="gray">Entwurf</UBadge>
|
||||
</div>
|
||||
<p class="text-sm text-gray-500 mt-1">Start: {{ useNuxtApp().$dayjs(row.started_at).format('DD.MM.YY HH:mm') }}</p>
|
||||
@@ -445,6 +449,7 @@ onMounted(async () => {
|
||||
/>
|
||||
|
||||
<UModal v-model:open="showRejectModal">
|
||||
<template #content>
|
||||
<UCard :ui="{ ring: '', divide: 'divide-y divide-gray-100 dark:divide-gray-800' }">
|
||||
<template #header>
|
||||
<div class="flex items-center justify-between">
|
||||
@@ -458,16 +463,17 @@ onMounted(async () => {
|
||||
<p class="text-sm text-gray-500">
|
||||
Der Eintrag wird als "Rejected" markiert und nicht mehr zur Arbeitszeit gezählt.
|
||||
</p>
|
||||
<UFormGroup label="Grund (optional)" name="reason">
|
||||
<UFormField label="Grund (optional)" name="reason">
|
||||
<UTextarea v-model="rejectReason" placeholder="Falsche Buchung, Doppelt, etc." autofocus />
|
||||
</UFormGroup>
|
||||
</UFormField>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="flex justify-end gap-2">
|
||||
<UButton color="gray" variant="soft" @click="showRejectModal = false">Abbrechen</UButton>
|
||||
<UButton color="red" :loading="loading" @click="confirmReject">Bestätigen</UButton>
|
||||
<UButton color="error" :loading="loading" @click="confirmReject">Bestätigen</UButton>
|
||||
</div>
|
||||
</template>
|
||||
</UCard>
|
||||
</template>
|
||||
</UModal>
|
||||
</template>
|
||||
|
||||
@@ -73,6 +73,24 @@ const sort = ref({
|
||||
column: dataType.sortColumn || "created_at",
|
||||
direction: 'desc'
|
||||
})
|
||||
const sorting = computed({
|
||||
get: () => [{
|
||||
id: sort.value.column,
|
||||
desc: sort.value.direction === 'desc'
|
||||
}],
|
||||
set: (value) => {
|
||||
const nextSort = Array.isArray(value) ? value[0] : undefined
|
||||
if (!nextSort?.id) {
|
||||
return
|
||||
}
|
||||
|
||||
sort.value = {
|
||||
column: nextSort.id,
|
||||
direction: nextSort.desc ? 'desc' : 'asc'
|
||||
}
|
||||
setupPage()
|
||||
}
|
||||
})
|
||||
|
||||
const columnsToFilter = ref({})
|
||||
|
||||
@@ -282,6 +300,19 @@ const handleFilterChange = async (action,column) => {
|
||||
setupPage()
|
||||
}
|
||||
|
||||
const truncateValue = (value, maxLength) => {
|
||||
if (value === null || value === undefined || value === '') {
|
||||
return '\u00A0'
|
||||
}
|
||||
|
||||
const stringValue = String(value)
|
||||
if (!maxLength || stringValue.length <= maxLength) {
|
||||
return stringValue
|
||||
}
|
||||
|
||||
return `${stringValue.substring(0, maxLength)}...`
|
||||
}
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
@@ -313,7 +344,7 @@ const handleFilterChange = async (action,column) => {
|
||||
<UButton
|
||||
icon="i-heroicons-x-mark"
|
||||
variant="outline"
|
||||
color="rose"
|
||||
color="error"
|
||||
@click="clearSearchString()"
|
||||
|
||||
/>
|
||||
@@ -336,10 +367,10 @@ const handleFilterChange = async (action,column) => {
|
||||
<template #left>
|
||||
<UTooltip :text="`${dataType.label} pro Seite`">
|
||||
<USelectMenu
|
||||
:options="[{value:10},{value:15, disabled: itemsMeta.total < 15},{value:25, disabled: itemsMeta.total < 25},{value:50, disabled: itemsMeta.total < 50},{value:100, disabled: itemsMeta.total < 100},{value:250, disabled: itemsMeta.total < 250}]"
|
||||
:items="[{value:10},{value:15, disabled: itemsMeta.total < 15},{value:25, disabled: itemsMeta.total < 25},{value:50, disabled: itemsMeta.total < 50},{value:100, disabled: itemsMeta.total < 100},{value:250, disabled: itemsMeta.total < 250}]"
|
||||
v-model="pageLimit"
|
||||
value-attribute="value"
|
||||
option-attribute="value"
|
||||
value-key="value"
|
||||
label-key="value"
|
||||
@change="setupPage"
|
||||
/>
|
||||
</UTooltip>
|
||||
@@ -363,15 +394,15 @@ const handleFilterChange = async (action,column) => {
|
||||
<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>
|
||||
@@ -382,18 +413,15 @@ const handleFilterChange = async (action,column) => {
|
||||
<div v-if="!platformIsNative">
|
||||
<UTable
|
||||
:loading="loading"
|
||||
:loading-state="{ icon: 'i-heroicons-arrow-path-20-solid', label: 'Loading...' }"
|
||||
sort-mode="manual"
|
||||
v-model:sort="sort"
|
||||
@update:sort="setupPage"
|
||||
v-model:sorting="sorting"
|
||||
v-if="dataType && columns && items.length > 0 && !loading"
|
||||
:rows="items"
|
||||
:data="items"
|
||||
:columns="normalizeTableColumns(columns)"
|
||||
class="w-full"
|
||||
style="height: 85dvh"
|
||||
:ui="{ divide: 'divide-gray-200 dark:divide-gray-800' }"
|
||||
@select="(i) => router.push(`/standardEntity/${type}/show/${i.id}`) "
|
||||
:empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: `Keine ${dataType.label} anzuzeigen` }"
|
||||
:on-select="(row) => router.push(`/standardEntity/${type}/show/${row.original.id}`)"
|
||||
:empty="`Keine ${dataType.label} anzuzeigen`"
|
||||
>
|
||||
<template
|
||||
v-for="column in dataType.templateColumns.filter(i => !i.disabledInTable)"
|
||||
@@ -414,15 +442,14 @@ const handleFilterChange = async (action,column) => {
|
||||
:text="!columnsToFilter[column.key]?.length > 0 ? `Keine Einträge für ${column.label} verfügbar` : `${column.label} Spalte nach Einträgen filtern`"
|
||||
>
|
||||
<USelectMenu
|
||||
:options="itemsMeta?.distinctValues?.[column.key]"
|
||||
:items="(itemsMeta?.distinctValues?.[column.key] || []).map(value => ({ label: value, value }))"
|
||||
v-model="columnsToFilter[column.key]"
|
||||
multiple
|
||||
@change="handleFilterChange('change', column.key)"
|
||||
searchable
|
||||
searchable-placeholder="Suche..."
|
||||
:search-attributes="[column.key]"
|
||||
:ui-menu="{ width: 'min-w-max' }"
|
||||
clear-search-on-close
|
||||
:search-input="{ placeholder: 'Suche...' }"
|
||||
value-key="value"
|
||||
label-key="label"
|
||||
:content="{ width: 'min-w-max' }"
|
||||
>
|
||||
|
||||
<template #empty>
|
||||
@@ -458,7 +485,7 @@ const handleFilterChange = async (action,column) => {
|
||||
<UButton
|
||||
@click="handleFilterChange('reset',column.key)"
|
||||
variant="outline"
|
||||
color="rose"
|
||||
color="error"
|
||||
>
|
||||
X
|
||||
</UButton>
|
||||
@@ -468,48 +495,54 @@ const handleFilterChange = async (action,column) => {
|
||||
</InputGroup>
|
||||
|
||||
</template>
|
||||
<template #name-data="{row}">
|
||||
<template #name-cell="{row}">
|
||||
<span
|
||||
v-if="row.id === items[selectedItem].id"
|
||||
class="text-primary-500 font-bold">
|
||||
v-if="row.original.id === items[selectedItem]?.id"
|
||||
class="block truncate text-primary-500 font-bold">
|
||||
<UTooltip
|
||||
:text="row.name"
|
||||
:text="row.original.name"
|
||||
>
|
||||
{{dataType.templateColumns.find(i => i.key === "name").maxLength ? (row.name.length > dataType.templateColumns.find(i => i.key === "name").maxLength ? `${row.name.substring(0,dataType.templateColumns.find(i => i.key === "name").maxLength)}...` : row.name ) : row.name}}
|
||||
<span class="block truncate">
|
||||
{{ truncateValue(row.original.name, dataType.templateColumns.find(i => i.key === "name")?.maxLength) }}
|
||||
</span>
|
||||
</UTooltip> </span>
|
||||
<span v-else>
|
||||
<span v-else class="block truncate">
|
||||
<UTooltip
|
||||
:text="row.name"
|
||||
:text="row.original.name"
|
||||
>
|
||||
{{dataType.templateColumns.find(i => i.key === "name").maxLength ? (row.name.length > dataType.templateColumns.find(i => i.key === "name").maxLength ? `${row.name.substring(0,dataType.templateColumns.find(i => i.key === "name").maxLength)}...` : row.name ) : row.name}}
|
||||
<span class="block truncate">
|
||||
{{ truncateValue(row.original.name, dataType.templateColumns.find(i => i.key === "name")?.maxLength) }}
|
||||
</span>
|
||||
</UTooltip>
|
||||
</span>
|
||||
</template>
|
||||
<template #fullName-data="{row}">
|
||||
<template #fullName-cell="{row}">
|
||||
<span
|
||||
v-if="row.id === items[selectedItem].id"
|
||||
class="text-primary-500 font-bold">{{row.fullName}}
|
||||
v-if="row.original.id === items[selectedItem]?.id"
|
||||
class="block truncate text-primary-500 font-bold">{{ row.original.fullName }}
|
||||
</span>
|
||||
<span v-else>
|
||||
{{row.fullName}}
|
||||
<span v-else class="block truncate">
|
||||
{{ row.original.fullName }}
|
||||
</span>
|
||||
</template>
|
||||
<template #licensePlate-data="{row}">
|
||||
<template #licensePlate-cell="{row}">
|
||||
<span
|
||||
v-if="row.id === items[selectedItem].id"
|
||||
class="text-primary-500 font-bold">{{row.licensePlate}}
|
||||
v-if="row.original.id === items[selectedItem]?.id"
|
||||
class="block truncate text-primary-500 font-bold">{{ row.original.licensePlate }}
|
||||
</span>
|
||||
<span v-else>
|
||||
{{row.licensePlate}}
|
||||
<span v-else class="block truncate">
|
||||
{{ row.original.licensePlate }}
|
||||
</span>
|
||||
</template>
|
||||
<template
|
||||
v-for="column in dataType.templateColumns.filter(i => i.key !== 'name' && i.key !== 'fullName' && i.key !== 'licensePlate' && !i.disabledInTable)"
|
||||
v-slot:[`${column.key}-data`]="{row}">
|
||||
<component v-if="column.component" :is="column.component" :row="row"></component>
|
||||
<span v-else-if="row[column.key]">
|
||||
<UTooltip :text="row[column.key]">
|
||||
{{row[column.key] ? `${column.maxLength ? (row[column.key].length > column.maxLength ? `${row[column.key].substring(0,column.maxLength)}...` : row[column.key]) : row[column.key]} ${column.unit ? column.unit : ''}`: ''}}
|
||||
v-slot:[`${column.key}-cell`]="{row}">
|
||||
<component v-if="column.component" :is="column.component" :row="row.original"></component>
|
||||
<span v-else-if="row.original[column.key]" class="block truncate">
|
||||
<UTooltip :text="String(row.original[column.key])">
|
||||
<span class="block truncate">
|
||||
{{ `${truncateValue(row.original[column.key], column.maxLength)}${column.unit ? ` ${column.unit}` : ''}` }}
|
||||
</span>
|
||||
</UTooltip>
|
||||
</span>
|
||||
|
||||
@@ -550,7 +583,7 @@ const handleFilterChange = async (action,column) => {
|
||||
v-if="searchString.length > 0"
|
||||
icon="i-heroicons-x-mark"
|
||||
variant="ghost"
|
||||
color="rose"
|
||||
color="error"
|
||||
@click="clearSearchString()"
|
||||
|
||||
/>
|
||||
@@ -687,7 +720,7 @@ const handleFilterChange = async (action,column) => {
|
||||
"
|
||||
>
|
||||
<UButton
|
||||
color="rose"
|
||||
color="error"
|
||||
variant="outline"
|
||||
class="flex-1"
|
||||
@click="resetMobileFilters"
|
||||
|
||||
@@ -72,7 +72,7 @@ const filteredRows = computed(() => {
|
||||
</template>
|
||||
</UDashboardToolbar>
|
||||
<UTable
|
||||
:rows="filteredRows"
|
||||
:data="filteredRows"
|
||||
:empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: `Keine Tickets anzuzeigen` }"
|
||||
@select="(i) => router.push(`/support/${i.id}`)"
|
||||
:columns="normalizeTableColumns([{key:'created_at',label:'Datum'}, ...profileStore.currentTenant === 5 ? [{key:'tenant',label:'Tenant'}] : [],{key:'status',label:'Status'},{key:'title',label:'Titel'},{key:'created_by',label:'Ersteller'},{key:'ticketmessages',label:'Nachrichten'}])"
|
||||
|
||||
@@ -458,7 +458,7 @@ onMounted(async () => {
|
||||
</div>
|
||||
<UTable
|
||||
v-else-if="filteredTasks.length"
|
||||
:rows="filteredTasks"
|
||||
:data="filteredTasks"
|
||||
:columns="normalizedListColumns"
|
||||
@select="(task) => openTaskViaRoute(task)"
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user