Files
FEDEO/frontend/components/EntityEdit.vue
florianfederspiel 189a52b3cd
Some checks failed
Build and Push Docker Images / build-backend (push) Failing after 1m25s
Build and Push Docker Images / build-frontend (push) Failing after 38s
Added IBAN Saving, Automatic Saving, added Mitglieder
2026-02-16 12:40:07 +01:00

823 lines
36 KiB
Vue

<script setup>
import dayjs from "dayjs";
import MaterialComposing from "~/components/materialComposing.vue";
import PersonalComposing from "~/components/personalComposing.vue";
const props = defineProps({
type: {
required: true,
type: String
},
mode: {
required: true,
type: String
},
createQuery: {
type: Object
},
item: {
required: true,
type: Object
},
inModal: {
type: Boolean,
},
platform: {
type: String,
}
})
const emit = defineEmits(["returnData"])
const {type} = props
defineShortcuts({
'backspace': () => {
router.push(`/${type}`)
},
'arrowleft': () => {
if(openTab.value > 0){
openTab.value -= 1
}
},
'arrowright': () => {
if(openTab.value < 3) {
openTab.value += 1
}
},
})
const router = useRouter()
const route = useRoute()
const dataStore = useDataStore()
const modal = useModal()
const dataType = dataStore.dataTypes[type]
const openTab = ref(0)
const item = ref(JSON.parse(props.item))
// console.log(item.value)
const oldItem = ref(null)
const generateOldItemData = () => {
oldItem.value = JSON.parse(props.item)
}
generateOldItemData()
// --- ÄNDERUNG START: Computed Property statt Watcher/Function ---
// Dies berechnet den Status automatisch neu, egal woher die Daten kommen (Init oder User-Eingabe)
const saveAllowed = computed(() => {
if (!item.value) return false
const isFilledValue = (value) => {
if (Array.isArray(value)) return value.length > 0
if (typeof value === "string") return value.trim().length > 0
return value !== null && value !== undefined && value !== false
}
let allowedCount = 0
// Nur Input-Felder berücksichtigen
const relevantColumns = dataType.templateColumns.filter(i => {
if (!i.inputType) return false
if (i.showFunction && !i.showFunction(item.value)) return false
if (i.disabledFunction && i.disabledFunction(item.value)) return false
return true
})
relevantColumns.forEach(datapoint => {
if(datapoint.required) {
if(datapoint.key.includes(".")){
const [parentKey, childKey] = datapoint.key.split('.')
// Prüfung: Existiert Parent UND ist Child "truthy" (nicht null/undefined/empty)
if(item.value[parentKey] && isFilledValue(item.value[parentKey][childKey])) {
allowedCount += 1
}
} else {
if(isFilledValue(item.value[datapoint.key])) {
allowedCount += 1
}
}
} else {
// Wenn nicht required, zählt es immer als "erlaubt"
allowedCount += 1
}
})
return allowedCount >= relevantColumns.length
})
// --- ÄNDERUNG ENDE ---
const setupCreate = () => {
dataType.templateColumns.forEach(datapoint => {
if(datapoint.key.includes(".")){
!item.value[datapoint.key.split(".")[0]] ? item.value[datapoint.key.split(".")[0]] = {} : null
}
if(datapoint.inputType === "editor") {
if(datapoint.key.includes(".")){
item.value[datapoint.key.split(".")[0]][datapoint.key.split(".")[1]] = {}
} else {
item.value[datapoint.key] = {}
}
}
})
}
setupCreate()
const setupQuery = () => {
console.log("setupQuery")
console.log(props.mode)
if(props.mode === "create" && (route.query || props.createQuery)) {
let data = !props.inModal ? route.query : props.createQuery
Object.keys(data).forEach(key => {
if (dataType.templateColumns.find(i => i.key === key)) {
if (["customer", "contract", "plant", "contact", "project"].includes(key)) {
item.value[key] = Number(data[key])
} else {
item.value[key] = data[key]
}
} else if (key === "resources") {
/*item.value[key] = data[key]*/
JSON.parse(data[key]).forEach(async (i) => {
console.log(i)
let type = i.substring(0, 1)
let id = i.substring(2, i.length)
console.log(type)
console.log(id)
let holder = ""
if (type === "P") {
holder = "profiles"
} else if (type === "F") {
holder = "vehicles"
id = Number(id)
} else if (type === "I") {
holder = "inventoryitems"
id = Number(id)
} else if (type === "G") {
holder = "inventoryitemgroups"
}
if (typeof item.value[holder] === "object") {
item.value[holder].push(id)
} else {
item.value[holder] = [id]
}
})
}
})
// calcSaveAllowed() -> Entfernt, da computed automatisch reagiert
}
}
setupQuery()
const loadedOptions = ref({})
const loadOptions = async () => {
let optionsToLoad = dataType.templateColumns.filter(i => i.selectDataType).map(i => {
return {
option: i.selectDataType,
key: i.key
}
})
for await(const option of optionsToLoad) {
if (option.option === "countrys") {
loadedOptions.value[option.option] = useEntities("countrys").selectSpecial()
} else if (option.option === "units") {
loadedOptions.value[option.option] = useEntities("units").selectSpecial()
} else {
loadedOptions.value[option.option] = (await useEntities(option.option).select())
if (dataType.templateColumns.find(x => x.key === option.key).selectDataTypeFilter) {
loadedOptions.value[option.option] = loadedOptions.value[option.option].filter(i => dataType.templateColumns.find(x => x.key === option.key).selectDataTypeFilter(i, item))
}
}
}
}
loadOptions()
const contentChanged = (content, datapoint) => {
if (datapoint.key.includes(".")) {
item.value[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]].html = content.html
item.value[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]].text = content.text
item.value[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]].json = content.json
} else {
item.value[datapoint.key].html = content.html
item.value[datapoint.key].text = content.text
item.value[datapoint.key].json = content.json
}
}
const createItem = async () => {
let ret = null
if (props.inModal) {
ret = await useEntities(type).create(item.value, true)
} else {
ret = await useEntities(type).create(item.value)//dataStore.createNewItem(type,item.value)
}
emit('returnData', ret)
modal.close()
}
const updateItem = async () => {
let ret = null
if (props.inModal) {
ret = await useEntities(type).update(item.value.id, item.value, true)
emit('returnData', ret)
modal.close()
} else {
ret = await useEntities(type).update(item.value.id, item.value)
emit('returnData', ret)
}
}
</script>
<template>
<UDashboardNavbar
v-if="!props.inModal"
:ui="{center: 'flex items-stretch gap-1.5 min-w-0'}"
>
<template #toggle>
<div v-if="platform === 'mobile'"></div>
</template>
<template #left>
<UButton
icon="i-heroicons-chevron-left"
variant="outline"
@click="router.back()"
>
</UButton>
</template>
<template #center>
<h1
v-if="item"
:class="['text-xl','font-medium', 'text-center']"
>{{ item.id ? `${dataType.labelSingle} bearbeiten` : `${dataType.labelSingle} erstellen` }}</h1>
</template>
<template #right>
<ArchiveButton
color="rose"
v-if="platform !== 'mobile'"
variant="outline"
:type="type"
@confirmed="useEntities(type).archive(item.id)"
/>
<UButton
v-if="item.id"
@click="updateItem"
:disabled="!saveAllowed"
>
Speichern
</UButton>
<UButton
v-else
@click="createItem"
:disabled="!saveAllowed"
>
Erstellen
</UButton>
<UButton
@click="router.push(item.id ? `/standardEntity/${type}/show/${item.id}` : `/standardEntity/${type}`)"
color="red"
class="ml-1"
>
Abbrechen
</UButton>
</template>
</UDashboardNavbar>
<UDashboardNavbar
v-else
:ui="{center: 'flex items-stretch gap-1.5 min-w-0'}"
>
<template #center>
<h1
v-if="item"
:class="['text-xl','font-medium']"
>{{ item.id ? `${dataType.labelSingle} bearbeiten` : `${dataType.labelSingle} erstellen` }}</h1>
</template>
<template #right>
<UButton
v-if="item.id"
@click="updateItem"
:disabled="!saveAllowed"
>
Speichern
</UButton>
<UButton
v-else
@click="createItem"
:disabled="!saveAllowed"
>
Erstellen
</UButton>
<UButton
@click="modal.close()"
color="red"
class="ml-2"
icon="i-heroicons-x-mark"
variant="outline"
/>
</template>
</UDashboardNavbar>
<UDashboardPanelContent>
<UForm
class="p-5"
>
<div :class="platform === 'mobile' ?['flex','flex-col'] : ['flex','flex-row']">
<div
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>
<div
v-for="datapoint in dataType.templateColumns.filter(i => i.inputType && i.inputColumn === columnName)"
>
<UFormGroup
v-if="(datapoint.showFunction ? datapoint.showFunction(item) : true)"
:label="datapoint.label"
>
<template #help>
<component
v-if="datapoint.helpComponent"
:is="datapoint.helpComponent"
:item="item"
/>
</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'"
class="flex-auto"
@change="datapoint.inputChangeFunction ? datapoint.inputChangeFunction(item,loadedOptions) : null"
v-if="['text','number'].includes(datapoint.inputType)"
v-model="item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]]"
:disabled="datapoint.disabledFunction ? datapoint.disabledFunction(item) : false"
:type="datapoint.inputType"
:placeholder="datapoint.inputIsNumberRange ? 'Leer lassen für automatisch generierte Nummer' : ''"
>
<template #trailing v-if="datapoint.inputTrailing">
<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'"
@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'"
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"
:multiple="datapoint.selectMultiple"
>
<template #empty>
Keine Optionen verfügbar
</template>
</USelectMenu>
<UTextarea
:color="datapoint.required ? (item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]] ? 'primary' : 'rose') : 'white'"
class="flex-auto"
@change="datapoint.inputChangeFunction ? datapoint.inputChangeFunction(item,loadedOptions) : null"
v-else-if="datapoint.inputType === 'textarea'"
v-model="item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]]"
:disabled="datapoint.disabledFunction ? datapoint.disabledFunction(item) : false"
rows="4"
/>
<UPopover :popper="{ placement: 'bottom-start' }" v-else-if="datapoint.inputType === 'date'">
<UButton
:color="datapoint.required ? (item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]] ? 'primary' : 'rose') : '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"
:disabled="datapoint.disabledFunction ? datapoint.disabledFunction(item) : false"
/>
<template #panel="{ close }">
<LazyDatePicker
@change="datapoint.inputChangeFunction ? datapoint.inputChangeFunction(item,loadedOptions) : null"
v-model="item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]]" @close="close"
:disabled="datapoint.disabledFunction ? datapoint.disabledFunction(item) : false"
/>
</template>
</UPopover>
<UPopover :popper="{ placement: 'bottom-start' }" v-else-if="datapoint.inputType === 'datetime'">
<UButton
:color="datapoint.required ? (item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]] ? 'primary' : 'rose') : '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"
:disabled="datapoint.disabledFunction ? datapoint.disabledFunction(item) : false"
/>
<template #panel="{ close }">
<LazyDatePicker
@change="datapoint.inputChangeFunction ? datapoint.inputChangeFunction(item,loadedOptions) : null"
v-model="item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]]" @close="close"
:disabled="datapoint.disabledFunction ? datapoint.disabledFunction(item) : false"
mode="datetime"
/>
</template>
</UPopover>
<BankAccountAssignInput
v-else-if="datapoint.inputType === 'bankaccountassign'"
v-model="item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]]"
:disabled="datapoint.disabledFunction ? datapoint.disabledFunction(item) : false"
/>
<Tiptap
v-else-if="datapoint.inputType === 'editor'"
@updateContent="(i) => contentChanged(i,datapoint)"
:preloadedContent="item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]].html"
/>
<UButton
v-if="['text','number','select','date','datetime','textarea'].includes(datapoint.inputType)"
@click="item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]] = null"
variant="outline"
color="white"
icon="i-heroicons-x-mark"
/>
</InputGroup>
<InputGroup class="w-full" v-else>
<UInput
class="flex-auto"
:color="datapoint.required ? (item[datapoint.key] ? 'primary' : 'rose') : 'white'"
@change="datapoint.inputChangeFunction ? datapoint.inputChangeFunction(item,loadedOptions) : null"
v-if="['text','number'].includes(datapoint.inputType)"
v-model="item[datapoint.key]"
:disabled="datapoint.disabledFunction ? datapoint.disabledFunction(item) : false"
:type="datapoint.inputType"
:placeholder="datapoint.inputIsNumberRange ? 'Leer lassen für automatisch generierte Nummer' : ''"
>
<template #trailing v-if="datapoint.inputTrailing">
{{ datapoint.inputTrailing }}
</template>
</UInput>
<UToggle
:color="datapoint.required ? (item[datapoint.key] ? 'primary' : 'rose') : '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'"
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"
:multiple="datapoint.selectMultiple"
searchable-placeholder="Suche..."
>
<template #empty>
Keine Optionen verfügbar
</template>
</USelectMenu>
<UTextarea
:color="datapoint.required ? (item[datapoint.key] ? 'primary' : 'rose') : 'white'"
class="flex-auto"
@change="datapoint.inputChangeFunction ? datapoint.inputChangeFunction(item,loadedOptions) : null"
v-else-if="datapoint.inputType === 'textarea'"
v-model="item[datapoint.key]"
:disabled="datapoint.disabledFunction ? datapoint.disabledFunction(item) : false"
rows="4"
/>
<UPopover :popper="{ placement: 'bottom-start' }" v-else-if="datapoint.inputType === 'date'">
<UButton
:color="datapoint.required ? (item[datapoint.key] ? 'primary' : 'rose') : '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 }">
<LazyDatePicker
@change="datapoint.inputChangeFunction ? datapoint.inputChangeFunction(item,loadedOptions) : null"
v-model="item[datapoint.key]" @close="close"
:disabled="datapoint.disabledFunction ? datapoint.disabledFunction(item) : false"
/>
</template>
</UPopover>
<UPopover :popper="{ placement: 'bottom-start' }" v-else-if="datapoint.inputType === 'datetime'">
<UButton
:color="datapoint.required ? (item[datapoint.key] ? 'primary' : 'rose') : '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 }">
<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"
/>
</template>
</UPopover>
<BankAccountAssignInput
v-else-if="datapoint.inputType === 'bankaccountassign'"
v-model="item[datapoint.key]"
:disabled="datapoint.disabledFunction ? datapoint.disabledFunction(item) : false"
/>
<Tiptap
v-else-if="datapoint.inputType === 'editor'"
@updateContent="(i) => contentChanged(i,datapoint)"
:preloadedContent="item[datapoint.key].html"
/>
<MaterialComposing
v-else-if="datapoint.inputType === 'materialComposing'"
:item="item"
/>
<PersonalComposing
v-else-if="datapoint.inputType === 'personalComposing'"
:item="item"
/>
<UButton
v-if="['text','number','select','date','datetime','textarea'].includes(datapoint.inputType)"
@click="item[datapoint.key] = null"
variant="outline"
color="white"
icon="i-heroicons-x-mark"
/>
</InputGroup>
</UFormGroup>
</div>
</div>
</div>
<UFormGroup
v-for="datapoint in dataType.templateColumns.filter(i => i.inputType && !i.inputColumn)"
:label="datapoint.label"
>
<template #help>
<component
v-if="datapoint.helpComponent"
:is="datapoint.helpComponent"
:item="item"
/>
</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'"
class="flex-auto"
@change="datapoint.inputChangeFunction ? datapoint.inputChangeFunction(item,loadedOptions) : null"
v-if="['text','number'].includes(datapoint.inputType)"
v-model="item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]]"
:disabled="datapoint.disabledFunction ? datapoint.disabledFunction(item) : false"
:type="datapoint.inputType"
:placeholder="datapoint.inputIsNumberRange ? 'Leer lassen für automatisch generierte Nummer' : ''"
>
<template #trailing v-if="datapoint.inputTrailing">
<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'"
@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'"
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"
:multiple="datapoint.selectMultiple"
>
<template #empty>
Keine Optionen verfügbar
</template>
</USelectMenu>
<UTextarea
:color="datapoint.required ? (item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]] ? 'primary' : 'rose') : 'white'"
class="flex-auto"
@change="datapoint.inputChangeFunction ? datapoint.inputChangeFunction(item,loadedOptions) : null"
v-else-if="datapoint.inputType === 'textarea'"
v-model="item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]]"
:disabled="datapoint.disabledFunction ? datapoint.disabledFunction(item) : false"
rows="4"
/>
<UPopover :popper="{ placement: 'bottom-start' }" v-else-if="datapoint.inputType === 'date'">
<UButton
:color="datapoint.required ? (item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]] ? 'primary' : 'rose') : '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"
:disabled="datapoint.disabledFunction ? datapoint.disabledFunction(item) : false"
/>
<template #panel="{ close }">
<LazyDatePicker
@change="datapoint.inputChangeFunction ? datapoint.inputChangeFunction(item,loadedOptions) : null"
v-model="item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]]" @close="close"
:disabled="datapoint.disabledFunction ? datapoint.disabledFunction(item) : false"
/>
</template>
</UPopover>
<UPopover :popper="{ placement: 'bottom-start' }" v-else-if="datapoint.inputType === 'datetime'">
<UButton
:color="datapoint.required ? (item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]] ? 'primary' : 'rose') : '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"
:disabled="datapoint.disabledFunction ? datapoint.disabledFunction(item) : false"
/>
<template #panel="{ close }">
<LazyDatePicker
@change="datapoint.inputChangeFunction ? datapoint.inputChangeFunction(item,loadedOptions) : null"
v-model="item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]]" @close="close"
:disabled="datapoint.disabledFunction ? datapoint.disabledFunction(item) : false"
mode="datetime"
/>
</template>
</UPopover>
<BankAccountAssignInput
v-else-if="datapoint.inputType === 'bankaccountassign'"
v-model="item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]]"
:disabled="datapoint.disabledFunction ? datapoint.disabledFunction(item) : false"
/>
<Tiptap
v-else-if="datapoint.inputType === 'editor'"
@updateContent="(i) => contentChanged(i,datapoint)"
:preloadedContent="item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]].html"
/>
<UButton
v-if="['text','number','select','date','datetime','textarea'].includes(datapoint.inputType)"
@click="item[datapoint.key.split('.')[0]][datapoint.key.split('.')[1]] = null"
variant="outline"
color="white"
icon="i-heroicons-x-mark"
/>
</InputGroup>
<InputGroup class="w-full" v-else>
<UInput
class="flex-auto"
:color="datapoint.required ? (item[datapoint.key] ? 'primary' : 'rose') : 'white'"
@change="datapoint.inputChangeFunction ? datapoint.inputChangeFunction(item,loadedOptions) : null"
v-if="['text','number'].includes(datapoint.inputType)"
v-model="item[datapoint.key]"
:disabled="datapoint.disabledFunction ? datapoint.disabledFunction(item) : false"
:type="datapoint.inputType"
:placeholder="datapoint.inputIsNumberRange ? 'Leer lassen für automatisch generierte Nummer' : ''"
>
<template #trailing v-if="datapoint.inputTrailing">
{{ datapoint.inputTrailing }}
</template>
</UInput>
<UToggle
:color="datapoint.required ? (item[datapoint.key] ? 'primary' : 'rose') : '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'"
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"
:multiple="datapoint.selectMultiple"
searchable-placeholder="Suche..."
>
<template #empty>
Keine Optionen verfügbar
</template>
</USelectMenu>
<UTextarea
:color="datapoint.required ? (item[datapoint.key] ? 'primary' : 'rose') : 'white'"
class="flex-auto"
@change="datapoint.inputChangeFunction ? datapoint.inputChangeFunction(item,loadedOptions) : null"
v-else-if="datapoint.inputType === 'textarea'"
v-model="item[datapoint.key]"
:disabled="datapoint.disabledFunction ? datapoint.disabledFunction(item) : false"
rows="4"
/>
<UPopover :popper="{ placement: 'bottom-start' }" v-else-if="datapoint.inputType === 'date'">
<UButton
:color="datapoint.required ? (item[datapoint.key] ? 'primary' : 'rose') : '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 }">
<LazyDatePicker
@change="datapoint.inputChangeFunction ? datapoint.inputChangeFunction(item,loadedOptions) : null"
v-model="item[datapoint.key]" @close="close"
:disabled="datapoint.disabledFunction ? datapoint.disabledFunction(item) : false"
/>
</template>
</UPopover>
<UPopover :popper="{ placement: 'bottom-start' }" v-else-if="datapoint.inputType === 'datetime'">
<UButton
:color="datapoint.required ? (item[datapoint.key] ? 'primary' : 'rose') : '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 }">
<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"
/>
</template>
</UPopover>
<BankAccountAssignInput
v-else-if="datapoint.inputType === 'bankaccountassign'"
v-model="item[datapoint.key]"
:disabled="datapoint.disabledFunction ? datapoint.disabledFunction(item) : false"
/>
<Tiptap
v-else-if="datapoint.inputType === 'editor'"
@updateContent="(i) => contentChanged(i,datapoint)"
:preloadedContent="item[datapoint.key].html"
/>
<MaterialComposing
v-else-if="datapoint.inputType === 'materialComposing'"
:item="item"
/>
<PersonalComposing
v-else-if="datapoint.inputType === 'personalComposing'"
:item="item"
/>
<UButton
v-if="['text','number','select','date','datetime','textarea'].includes(datapoint.inputType)"
@click="item[datapoint.key] = null"
variant="outline"
color="white"
icon="i-heroicons-x-mark"
/>
</InputGroup>
</UFormGroup>
</UForm>
</UDashboardPanelContent>
</template>
<style scoped>
td {
border-bottom: 1px solid lightgrey;
vertical-align: top;
padding-bottom: 0.15em;
padding-top: 0.15em;
}
</style>