Fix
This commit is contained in:
@@ -1,4 +1,6 @@
|
|||||||
<script setup >
|
<script setup>
|
||||||
|
// Falls useDropZone nicht auto-importiert wird:
|
||||||
|
// import { useDropZone } from '@vueuse/core'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
fileData: {
|
fileData: {
|
||||||
@@ -12,11 +14,35 @@ const props = defineProps({
|
|||||||
const emit = defineEmits(["uploadFinished"])
|
const emit = defineEmits(["uploadFinished"])
|
||||||
|
|
||||||
const modal = useModal()
|
const modal = useModal()
|
||||||
const profileStore = useProfileStore()
|
// const profileStore = useProfileStore() // Wird im Snippet nicht genutzt, aber ich lasse es drin
|
||||||
|
|
||||||
const uploadInProgress = ref(false)
|
const uploadInProgress = ref(false)
|
||||||
const availableFiletypes = ref([])
|
const availableFiletypes = ref([])
|
||||||
|
|
||||||
|
// 1. State für die Dateien und die Dropzone Referenz
|
||||||
|
const selectedFiles = ref([])
|
||||||
|
const dropZoneRef = ref(null)
|
||||||
|
|
||||||
|
// 2. Setup der Dropzone
|
||||||
|
const onDrop = (files) => {
|
||||||
|
// Wenn Dateien gedroppt werden, speichern wir sie
|
||||||
|
// files ist hier meist ein Array, wir stellen sicher, dass es passt
|
||||||
|
selectedFiles.value = files || []
|
||||||
|
}
|
||||||
|
|
||||||
|
const { isOverDropZone } = useDropZone(dropZoneRef, {
|
||||||
|
onDrop,
|
||||||
|
// Verhindert, dass der Browser das Bild einfach öffnet
|
||||||
|
preventDefaultForDrop: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
// 3. Handler für den klassischen Datei-Input Klick
|
||||||
|
const onFileInputChange = (e) => {
|
||||||
|
if (e.target.files) {
|
||||||
|
selectedFiles.value = Array.from(e.target.files)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const setup = async () => {
|
const setup = async () => {
|
||||||
availableFiletypes.value = await useEntities("filetags").select()
|
availableFiletypes.value = await useEntities("filetags").select()
|
||||||
}
|
}
|
||||||
@@ -24,81 +50,112 @@ const setup = async () => {
|
|||||||
setup()
|
setup()
|
||||||
|
|
||||||
const uploadFiles = async () => {
|
const uploadFiles = async () => {
|
||||||
|
// Validierung: Keine Dateien ausgewählt
|
||||||
|
if (!selectedFiles.value || selectedFiles.value.length === 0) {
|
||||||
|
alert("Bitte wählen Sie zuerst Dateien aus.") // Oder eine schönere Toast Notification
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
uploadInProgress.value = true;
|
uploadInProgress.value = true;
|
||||||
|
|
||||||
let fileData = props.fileData
|
let fileData = props.fileData
|
||||||
delete fileData.typeEnabled
|
delete fileData.typeEnabled
|
||||||
|
|
||||||
|
// 4. Hier nutzen wir nun selectedFiles.value statt document.getElementById
|
||||||
|
await useFiles().uploadFiles(fileData, selectedFiles.value, [], true)
|
||||||
await useFiles().uploadFiles(fileData, document.getElementById("fileUploadInput").files,[],true)
|
|
||||||
|
|
||||||
uploadInProgress.value = false;
|
uploadInProgress.value = false;
|
||||||
emit("uploadFinished")
|
emit("uploadFinished")
|
||||||
modal.close()
|
modal.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper Funktion um Dateinamen anzuzeigen (da das Input Feld leer bleibt beim Droppen)
|
||||||
|
const fileNames = computed(() => {
|
||||||
|
if (!selectedFiles.value.length) return ''
|
||||||
|
return selectedFiles.value.map(f => f.name).join(', ')
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<UModal>
|
<UModal>
|
||||||
<UCard :ui="{ body: { base: 'flex-1' }, ring: '', divide: 'divide-y divide-gray-100 dark:divide-gray-800' }">
|
<div ref="dropZoneRef" class="relative h-full flex flex-col">
|
||||||
<template #header>
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<h3 class="text-base font-semibold leading-6 text-gray-900 dark:text-white">
|
|
||||||
Datei hochladen
|
|
||||||
</h3>
|
|
||||||
<UButton
|
|
||||||
color="gray"
|
|
||||||
variant="ghost"
|
|
||||||
icon="i-heroicons-x-mark-20-solid"
|
|
||||||
class="-my-1"
|
|
||||||
@click="modal.close()"
|
|
||||||
:disabled="uploadInProgress"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<UFormGroup
|
<div
|
||||||
label="Datei:"
|
v-if="isOverDropZone"
|
||||||
|
class="absolute inset-0 z-50 flex items-center justify-center bg-primary-500/10 border-2 border-primary-500 border-dashed rounded-lg backdrop-blur-sm transition-all"
|
||||||
>
|
>
|
||||||
<UInput
|
<span class="text-xl font-bold text-primary-600 bg-white/80 px-4 py-2 rounded shadow-sm">
|
||||||
type="file"
|
Dateien hier ablegen
|
||||||
id="fileUploadInput"
|
</span>
|
||||||
multiple
|
</div>
|
||||||
accept="image/jpeg, image/png, image/gif, application/pdf"
|
|
||||||
/>
|
<UCard :ui="{ body: { base: 'flex-1' }, ring: '', divide: 'divide-y divide-gray-100 dark:divide-gray-800' }">
|
||||||
</UFormGroup>
|
<template #header>
|
||||||
<UFormGroup
|
<div class="flex items-center justify-between">
|
||||||
label="Typ:"
|
<h3 class="text-base font-semibold leading-6 text-gray-900 dark:text-white">
|
||||||
class="mt-3"
|
Datei hochladen
|
||||||
>
|
</h3>
|
||||||
<USelectMenu
|
<UButton
|
||||||
option-attribute="name"
|
color="gray"
|
||||||
value-attribute="id"
|
variant="ghost"
|
||||||
searchable
|
icon="i-heroicons-x-mark-20-solid"
|
||||||
searchable-placeholder="Suchen..."
|
class="-my-1"
|
||||||
:options="availableFiletypes"
|
@click="modal.close()"
|
||||||
v-model="props.fileData.type"
|
:disabled="uploadInProgress"
|
||||||
:disabled="!props.fileData.typeEnabled"
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<UFormGroup
|
||||||
|
label="Datei:"
|
||||||
|
:help="selectedFiles.length > 0 ? `${selectedFiles.length} Datei(en) ausgewählt` : 'Ziehen Sie Dateien hierher oder klicken Sie'"
|
||||||
>
|
>
|
||||||
<template #label>
|
<UInput
|
||||||
<span v-if="availableFiletypes.find(x => x.id === props.fileData.type)">{{availableFiletypes.find(x => x.id === props.fileData.type).name}}</span>
|
v-if="selectedFiles.length === 0"
|
||||||
<span v-else>Keine Typ ausgewählt</span>
|
type="file"
|
||||||
</template>
|
id="fileUploadInput"
|
||||||
</USelectMenu>
|
multiple
|
||||||
</UFormGroup>
|
accept="image/jpeg, image/png, image/gif, application/pdf"
|
||||||
|
@change="onFileInputChange"
|
||||||
|
/>
|
||||||
|
|
||||||
<template #footer>
|
<div v-if="selectedFiles.length > 0" class="mt-2 text-sm text-gray-500">
|
||||||
<UButton
|
Ausgewählt: <span class="font-medium text-gray-700 dark:text-gray-300">{{ fileNames }}</span>
|
||||||
@click="uploadFiles"
|
</div>
|
||||||
:loading="uploadInProgress"
|
</UFormGroup>
|
||||||
:disabled="uploadInProgress"
|
|
||||||
>Hochladen</UButton>
|
<UFormGroup
|
||||||
</template>
|
label="Typ:"
|
||||||
</UCard>
|
class="mt-3"
|
||||||
|
>
|
||||||
|
<USelectMenu
|
||||||
|
option-attribute="name"
|
||||||
|
value-attribute="id"
|
||||||
|
searchable
|
||||||
|
searchable-placeholder="Suchen..."
|
||||||
|
:options="availableFiletypes"
|
||||||
|
v-model="props.fileData.type"
|
||||||
|
:disabled="!props.fileData.typeEnabled"
|
||||||
|
>
|
||||||
|
<template #label>
|
||||||
|
<span v-if="availableFiletypes.find(x => x.id === props.fileData.type)">{{availableFiletypes.find(x => x.id === props.fileData.type).name}}</span>
|
||||||
|
<span v-else>Kein Typ ausgewählt</span>
|
||||||
|
</template>
|
||||||
|
</USelectMenu>
|
||||||
|
</UFormGroup>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<UButton
|
||||||
|
@click="uploadFiles"
|
||||||
|
:loading="uploadInProgress"
|
||||||
|
:disabled="uploadInProgress || selectedFiles.length === 0"
|
||||||
|
>Hochladen</UButton>
|
||||||
|
</template>
|
||||||
|
</UCard>
|
||||||
|
</div>
|
||||||
</UModal>
|
</UModal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
/* Optional: Animationen für das Overlay */
|
||||||
</style>
|
</style>
|
||||||
@@ -9,6 +9,7 @@ const props = defineProps({
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
<span v-if="props.row.infoData.streetNumber">{{props.row.infoData.streetNumber}},</span>
|
||||||
<span v-if="props.row.infoData.street">{{props.row.infoData.street}},</span>
|
<span v-if="props.row.infoData.street">{{props.row.infoData.street}},</span>
|
||||||
<span v-if="props.row.infoData.special">{{props.row.infoData.special}},</span>
|
<span v-if="props.row.infoData.special">{{props.row.infoData.special}},</span>
|
||||||
<span v-if="props.row.infoData.zip">{{props.row.infoData.zip}},</span>
|
<span v-if="props.row.infoData.zip">{{props.row.infoData.zip}},</span>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ export default defineNuxtConfig({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
modules: ['@pinia/nuxt', '@nuxt/ui', '@nuxtjs/supabase', "nuxt-editorjs", '@nuxtjs/fontaine', 'nuxt-viewport', 'nuxt-tiptap-editor', '@nuxtjs/leaflet'],
|
modules: ['@pinia/nuxt', '@nuxt/ui', '@nuxtjs/supabase', "nuxt-editorjs", '@nuxtjs/fontaine', 'nuxt-viewport', 'nuxt-tiptap-editor', '@nuxtjs/leaflet', '@vueuse/nuxt'],
|
||||||
|
|
||||||
ssr: false,
|
ssr: false,
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,8 @@
|
|||||||
"@capacitor/cli": "^7.0.0",
|
"@capacitor/cli": "^7.0.0",
|
||||||
"@nuxtjs/leaflet": "^1.2.3",
|
"@nuxtjs/leaflet": "^1.2.3",
|
||||||
"@nuxtjs/supabase": "^1.1.4",
|
"@nuxtjs/supabase": "^1.1.4",
|
||||||
|
"@vueuse/core": "^14.1.0",
|
||||||
|
"@vueuse/nuxt": "^14.1.0",
|
||||||
"nuxt": "^3.14.1592",
|
"nuxt": "^3.14.1592",
|
||||||
"nuxt-tiptap-editor": "^1.2.0",
|
"nuxt-tiptap-editor": "^1.2.0",
|
||||||
"vue": "^3.5.13",
|
"vue": "^3.5.13",
|
||||||
@@ -87,4 +89,4 @@
|
|||||||
"zod": "^3.25.76",
|
"zod": "^3.25.76",
|
||||||
"zpl-renderer-js": "^2.0.2"
|
"zpl-renderer-js": "^2.0.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ const clearSearchString = () => {
|
|||||||
searchString.value = ''
|
searchString.value = ''
|
||||||
}
|
}
|
||||||
|
|
||||||
const filterAccount = ref(bankaccounts || [])
|
const filterAccount = ref(bankaccounts.value || [])
|
||||||
|
|
||||||
const displayCurrency = (value, currency = "€") => {
|
const displayCurrency = (value, currency = "€") => {
|
||||||
return `${Number(value).toFixed(2).replace(".",",")} ${currency}`
|
return `${Number(value).toFixed(2).replace(".",",")} ${currency}`
|
||||||
@@ -150,7 +150,7 @@ setupPage()
|
|||||||
</USelectMenu>
|
</USelectMenu>
|
||||||
</template>
|
</template>
|
||||||
<template #right>
|
<template #right>
|
||||||
<USelectMenu
|
<!-- <USelectMenu
|
||||||
v-model="selectedColumns"
|
v-model="selectedColumns"
|
||||||
icon="i-heroicons-adjustments-horizontal-solid"
|
icon="i-heroicons-adjustments-horizontal-solid"
|
||||||
:options="templateColumns"
|
:options="templateColumns"
|
||||||
@@ -162,7 +162,7 @@ setupPage()
|
|||||||
<template #label>
|
<template #label>
|
||||||
Spalten
|
Spalten
|
||||||
</template>
|
</template>
|
||||||
</USelectMenu>
|
</USelectMenu>-->
|
||||||
<USelectMenu
|
<USelectMenu
|
||||||
icon="i-heroicons-adjustments-horizontal-solid"
|
icon="i-heroicons-adjustments-horizontal-solid"
|
||||||
multiple
|
multiple
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ defineShortcuts({
|
|||||||
})
|
})
|
||||||
|
|
||||||
const dataStore = useDataStore()
|
const dataStore = useDataStore()
|
||||||
const profileStore = useProfileStore()
|
const tempStore = useTempStore()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const mode = ref(route.params.mode || "show")
|
const mode = ref(route.params.mode || "show")
|
||||||
@@ -177,7 +177,14 @@ const removeAllocation = async (allocationId) => {
|
|||||||
await setup()
|
await setup()
|
||||||
}
|
}
|
||||||
|
|
||||||
const searchString = ref("")
|
const searchString = ref(tempStore.searchStrings["bankstatementsedit"] ||'')
|
||||||
|
|
||||||
|
const clearSearchString = () => {
|
||||||
|
searchString.value = ''
|
||||||
|
tempStore.clearSearchString("bankstatementsedit")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
const filteredDocuments = computed(() => {
|
const filteredDocuments = computed(() => {
|
||||||
|
|
||||||
|
|
||||||
@@ -546,7 +553,15 @@ const archiveStatement = async () => {
|
|||||||
class="mr-3 mt-3"
|
class="mr-3 mt-3"
|
||||||
@click="removeAllocation(item.id)"
|
@click="removeAllocation(item.id)"
|
||||||
/>
|
/>
|
||||||
|
<UButton
|
||||||
|
icon="i-heroicons-eye"
|
||||||
|
variant="outline"
|
||||||
|
color="primary"
|
||||||
|
class="mr-3 mt-3"
|
||||||
|
@click="navigateTo(`/createDocument/show/${item.createddocument}`)"
|
||||||
|
/>
|
||||||
</UCard>
|
</UCard>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -780,6 +795,7 @@ const archiveStatement = async () => {
|
|||||||
placeholder="Suche..."
|
placeholder="Suche..."
|
||||||
class="hidden lg:block w-full mr-1"
|
class="hidden lg:block w-full mr-1"
|
||||||
@keydown.esc="$event.target.blur()"
|
@keydown.esc="$event.target.blur()"
|
||||||
|
@change="tempStore.modifySearchString('bankstatementsedit',searchString)"
|
||||||
>
|
>
|
||||||
<template #trailing>
|
<template #trailing>
|
||||||
<UKbd value="/" />
|
<UKbd value="/" />
|
||||||
@@ -789,7 +805,7 @@ const archiveStatement = async () => {
|
|||||||
variant="outline"
|
variant="outline"
|
||||||
icon="i-heroicons-x-mark"
|
icon="i-heroicons-x-mark"
|
||||||
color="rose"
|
color="rose"
|
||||||
@click="searchString = ''"
|
@click="clearSearchString"
|
||||||
/>
|
/>
|
||||||
</InputGroup>
|
</InputGroup>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,26 +1,26 @@
|
|||||||
<template>
|
<template>
|
||||||
<UDashboardNavbar title="Ausgangsbelege" :badge="filteredRows.length">
|
<UDashboardNavbar :badge="filteredRows.length" title="Ausgangsbelege">
|
||||||
<template #right>
|
<template #right>
|
||||||
<UInput
|
<UInput
|
||||||
id="searchinput"
|
id="searchinput"
|
||||||
v-model="searchString"
|
v-model="searchString"
|
||||||
icon="i-heroicons-funnel"
|
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
placeholder="Suche..."
|
|
||||||
class="hidden lg:block"
|
class="hidden lg:block"
|
||||||
@keydown.esc="$event.target.blur()"
|
icon="i-heroicons-funnel"
|
||||||
|
placeholder="Suche..."
|
||||||
@change="tempStore.modifySearchString('createddocuments',searchString)"
|
@change="tempStore.modifySearchString('createddocuments',searchString)"
|
||||||
|
@keydown.esc="$event.target.blur()"
|
||||||
>
|
>
|
||||||
<template #trailing>
|
<template #trailing>
|
||||||
<UKbd value="/" />
|
<UKbd value="/"/>
|
||||||
</template>
|
</template>
|
||||||
</UInput>
|
</UInput>
|
||||||
<UButton
|
<UButton
|
||||||
|
v-if="searchString.length > 0"
|
||||||
|
color="rose"
|
||||||
icon="i-heroicons-x-mark"
|
icon="i-heroicons-x-mark"
|
||||||
variant="outline"
|
variant="outline"
|
||||||
color="rose"
|
|
||||||
@click="clearSearchString()"
|
@click="clearSearchString()"
|
||||||
v-if="searchString.length > 0"
|
|
||||||
/>
|
/>
|
||||||
<UButton
|
<UButton
|
||||||
@click="router.push(`/createDocument/edit`)"
|
@click="router.push(`/createDocument/edit`)"
|
||||||
@@ -33,27 +33,27 @@
|
|||||||
|
|
||||||
|
|
||||||
<template #right>
|
<template #right>
|
||||||
<USelectMenu
|
<!-- <USelectMenu
|
||||||
v-model="selectedColumns"
|
v-model="selectedColumns"
|
||||||
icon="i-heroicons-adjustments-horizontal-solid"
|
|
||||||
:options="templateColumns"
|
:options="templateColumns"
|
||||||
multiple
|
|
||||||
class="hidden lg:block"
|
|
||||||
by="key"
|
by="key"
|
||||||
|
class="hidden lg:block"
|
||||||
|
icon="i-heroicons-adjustments-horizontal-solid"
|
||||||
|
multiple
|
||||||
@change="tempStore.modifyColumns('createddocuments',selectedColumns)"
|
@change="tempStore.modifyColumns('createddocuments',selectedColumns)"
|
||||||
>
|
>
|
||||||
<template #label>
|
<template #label>
|
||||||
Spalten
|
Spalten
|
||||||
</template>
|
</template>
|
||||||
</USelectMenu>
|
</USelectMenu>-->
|
||||||
<USelectMenu
|
<USelectMenu
|
||||||
v-if="selectableFilters.length > 0"
|
v-if="selectableFilters.length > 0"
|
||||||
|
v-model="selectedFilters"
|
||||||
|
:color="selectedFilters.length > 0 ? 'primary' : 'white'"
|
||||||
|
:options="selectableFilters"
|
||||||
|
:ui-menu="{ width: 'min-w-max' }"
|
||||||
icon="i-heroicons-adjustments-horizontal-solid"
|
icon="i-heroicons-adjustments-horizontal-solid"
|
||||||
multiple
|
multiple
|
||||||
v-model="selectedFilters"
|
|
||||||
:options="selectableFilters"
|
|
||||||
:color="selectedFilters.length > 0 ? 'primary' : 'white'"
|
|
||||||
:ui-menu="{ width: 'min-w-max' }"
|
|
||||||
>
|
>
|
||||||
<template #label>
|
<template #label>
|
||||||
Filter
|
Filter
|
||||||
@@ -63,36 +63,36 @@
|
|||||||
</UDashboardToolbar>
|
</UDashboardToolbar>
|
||||||
<UTabs :items="selectedTypes" class="m-3">
|
<UTabs :items="selectedTypes" class="m-3">
|
||||||
<template #default="{item}">
|
<template #default="{item}">
|
||||||
{{item.label}}
|
{{ item.label }}
|
||||||
<UBadge
|
<UBadge
|
||||||
variant="outline"
|
|
||||||
class="ml-2"
|
class="ml-2"
|
||||||
|
variant="outline"
|
||||||
>
|
>
|
||||||
{{filteredRows.filter(i => item.key === 'invoices' ? ['invoices','advanceInvoices','cancellationInvoices'].includes(i.type) : item.key === i.type).length}}
|
{{ filteredRows.filter(i => item.key === 'invoices' ? ['invoices', 'advanceInvoices', 'cancellationInvoices'].includes(i.type) : item.key === i.type).length }}
|
||||||
</UBadge>
|
</UBadge>
|
||||||
</template>
|
</template>
|
||||||
<template #item="{item}">
|
<template #item="{item}">
|
||||||
<div style="height: 80vh; overflow-y: scroll">
|
<div style="height: 80vh; overflow-y: scroll">
|
||||||
<UTable
|
<UTable
|
||||||
:rows="filteredRows.filter(i => item.key === 'invoices' ? ['invoices','advanceInvoices','cancellationInvoices'].includes(i.type) : item.key === i.type)"
|
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
class="w-full"
|
|
||||||
:ui="{ divide: 'divide-gray-200 dark:divide-gray-800' }"
|
|
||||||
@select="selectItem"
|
|
||||||
:empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Keine Belege anzuzeigen' }"
|
:empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Keine Belege anzuzeigen' }"
|
||||||
|
:rows="filteredRows.filter(i => item.key === 'invoices' ? ['invoices','advanceInvoices','cancellationInvoices'].includes(i.type) : item.key === i.type)"
|
||||||
|
:ui="{ divide: 'divide-gray-200 dark:divide-gray-800' }"
|
||||||
|
class="w-full"
|
||||||
|
@select="selectItem"
|
||||||
>
|
>
|
||||||
<template #type-data="{row}">
|
<template #type-data="{row}">
|
||||||
{{dataStore.documentTypesForCreation[row.type].labelSingle}}
|
{{ dataStore.documentTypesForCreation[row.type].labelSingle }}
|
||||||
<!--
|
<!--
|
||||||
<span v-if="row.type === 'cancellationInvoices'"> zu {{row.linkedDocument.documentNumber}}</span>
|
<span v-if="row.type === 'cancellationInvoices'"> zu {{row.linkedDocument.documentNumber}}</span>
|
||||||
-->
|
-->
|
||||||
</template>
|
</template>
|
||||||
<template #state-data="{row}">
|
<template #state-data="{row}">
|
||||||
<span
|
<span
|
||||||
v-if="row.state === 'Entwurf'"
|
v-if="row.state === 'Entwurf'"
|
||||||
class="text-rose-500"
|
class="text-rose-500"
|
||||||
>
|
>
|
||||||
{{row.state}}
|
{{ row.state }}
|
||||||
</span>
|
</span>
|
||||||
<!-- <span
|
<!-- <span
|
||||||
v-if="row.state === 'Gebucht'"
|
v-if="row.state === 'Gebucht'"
|
||||||
@@ -104,49 +104,56 @@
|
|||||||
v-if="row.state === 'Gebucht' && !items.find(i => i.createddocument && i.createddocument.id === row.id)"
|
v-if="row.state === 'Gebucht' && !items.find(i => i.createddocument && i.createddocument.id === row.id)"
|
||||||
class="text-primary-500"
|
class="text-primary-500"
|
||||||
>
|
>
|
||||||
{{row.state}}
|
{{ row.state }}
|
||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
v-else-if="row.state === 'Gebucht' && items.find(i => i.createddocument && i.createddocument.id === row.id && i.type === 'cancellationInvoices') && ['invoices','advanceInvoices'].includes(row.type)"
|
v-else-if="row.state === 'Gebucht' && items.find(i => i.createddocument && i.createddocument.id === row.id && i.type === 'cancellationInvoices') && ['invoices','advanceInvoices'].includes(row.type)"
|
||||||
class="text-cyan-500"
|
class="text-cyan-500"
|
||||||
>
|
>
|
||||||
Storniert mit {{items.find(i => i.createddocument && i.createddocument.id === row.id).documentNumber}}
|
Storniert mit {{ items.find(i => i.createddocument && i.createddocument.id === row.id).documentNumber }}
|
||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
v-else-if="row.state === 'Gebucht'"
|
v-else-if="row.state === 'Gebucht'"
|
||||||
class="text-primary-500"
|
class="text-primary-500"
|
||||||
>
|
>
|
||||||
{{row.state}}
|
{{ row.state }}
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<template #partner-data="{row}">
|
<template #partner-data="{row}">
|
||||||
<span v-if="row.customer && row.customer.name.length <21">{{row.customer ? row.customer.name : ""}}</span>
|
<span v-if="row.customer && row.customer.name.length <21">{{ row.customer ? row.customer.name : "" }}</span>
|
||||||
<UTooltip v-else-if="row.customer && row.customer.name.length > 20" :text="row.customer.name">
|
<UTooltip v-else-if="row.customer && row.customer.name.length > 20" :text="row.customer.name">
|
||||||
{{row.customer.name.substring(0,20)}}...
|
{{ row.customer.name.substring(0, 20) }}...
|
||||||
</UTooltip>
|
</UTooltip>
|
||||||
</template>
|
</template>
|
||||||
<template #reference-data="{row}">
|
<template #reference-data="{row}">
|
||||||
<span v-if="row === filteredRows[selectedItem]" class="text-primary-500 font-bold">{{row.documentNumber}}</span>
|
<span v-if="row === filteredRows[selectedItem]"
|
||||||
<span v-else>{{row.documentNumber}}</span>
|
class="text-primary-500 font-bold">{{ row.documentNumber }}</span>
|
||||||
|
<span v-else>{{ row.documentNumber }}</span>
|
||||||
</template>
|
</template>
|
||||||
<template #date-data="{row}">
|
<template #date-data="{row}">
|
||||||
<span v-if="row.date">{{row.date ? dayjs(row.date).format("DD.MM.YY") : ''}}</span>
|
<span v-if="row.date">{{ row.date ? dayjs(row.date).format("DD.MM.YY") : '' }}</span>
|
||||||
<span v-if="row.documentDate">{{row.documentDate ? dayjs(row.documentDate).format("DD.MM.YY") : ''}}</span>
|
<span
|
||||||
|
v-if="row.documentDate">{{ row.documentDate ? dayjs(row.documentDate).format("DD.MM.YY") : '' }}</span>
|
||||||
</template>
|
</template>
|
||||||
<template #dueDate-data="{row}">
|
<template #dueDate-data="{row}">
|
||||||
<span v-if="row.state === 'Gebucht' && row.paymentDays && ['invoices','advanceInvoices'].includes(row.type) && !items.find(i => i.linkedDocument && i.linkedDocument.id === row.id)" :class="dayjs(row.documentDate).add(row.paymentDays,'day').diff(dayjs()) <= 0 && !isPaid(row) ? ['text-rose-500'] : '' ">{{row.documentDate ? dayjs(row.documentDate).add(row.paymentDays,'day').format("DD.MM.YY") : ''}}</span>
|
<span
|
||||||
|
v-if="row.state === 'Gebucht' && row.paymentDays && ['invoices','advanceInvoices'].includes(row.type) && !items.find(i => i.linkedDocument && i.linkedDocument.id === row.id)"
|
||||||
|
:class="dayjs(row.documentDate).add(row.paymentDays,'day').diff(dayjs()) <= 0 && !isPaid(row) ? ['text-rose-500'] : '' ">{{ row.documentDate ? dayjs(row.documentDate).add(row.paymentDays, 'day').format("DD.MM.YY") : '' }}</span>
|
||||||
</template>
|
</template>
|
||||||
<template #paid-data="{row}">
|
<template #paid-data="{row}">
|
||||||
<div v-if="(row.type === 'invoices' ||row.type === 'advanceInvoices') && row.state === 'Gebucht' && !items.find(i => i.linkedDocument && i.linkedDocument.id === row.id)">
|
<div
|
||||||
|
v-if="(row.type === 'invoices' ||row.type === 'advanceInvoices') && row.state === 'Gebucht' && !items.find(i => i.linkedDocument && i.linkedDocument.id === row.id)">
|
||||||
<span v-if="useSum().getIsPaid(row,items)" class="text-primary-500">Bezahlt</span>
|
<span v-if="useSum().getIsPaid(row,items)" class="text-primary-500">Bezahlt</span>
|
||||||
<span v-else class="text-rose-600">Offen</span>
|
<span v-else class="text-rose-600">Offen</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #amount-data="{row}">
|
<template #amount-data="{row}">
|
||||||
<span v-if="row.type !== 'deliveryNotes'">{{displayCurrency(useSum().getCreatedDocumentSum(row,items))}}</span>
|
<span
|
||||||
|
v-if="row.type !== 'deliveryNotes'">{{ displayCurrency(useSum().getCreatedDocumentSum(row, items)) }}</span>
|
||||||
</template>
|
</template>
|
||||||
<template #amountOpen-data="{row}">
|
<template #amountOpen-data="{row}">
|
||||||
<span v-if="!['deliveryNotes','cancellationInvoices','quotes','confirmationOrders'].includes(row.type) && row.state !== 'Entwurf' && !useSum().getIsPaid(row,items) && !items.find(i => i.linkedDocument && i.linkedDocument.id === row.id) ">{{displayCurrency(useSum().getCreatedDocumentSum(row, items) - row.statementallocations.reduce((n,{amount}) => n + amount, 0))}}</span>
|
<span
|
||||||
|
v-if="!['deliveryNotes','cancellationInvoices','quotes','confirmationOrders'].includes(row.type) && row.state !== 'Entwurf' && !useSum().getIsPaid(row,items) && !items.find(i => i.linkedDocument && i.linkedDocument.id === row.id) ">{{ displayCurrency(useSum().getCreatedDocumentSum(row, items) - row.statementallocations.reduce((n, {amount}) => n + amount, 0)) }}</span>
|
||||||
</template>
|
</template>
|
||||||
</UTable>
|
</UTable>
|
||||||
</div>
|
</div>
|
||||||
@@ -175,14 +182,14 @@ defineShortcuts({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
'arrowdown': () => {
|
'arrowdown': () => {
|
||||||
if(selectedItem.value < filteredRows.value.length - 1) {
|
if (selectedItem.value < filteredRows.value.length - 1) {
|
||||||
selectedItem.value += 1
|
selectedItem.value += 1
|
||||||
} else {
|
} else {
|
||||||
selectedItem.value = 0
|
selectedItem.value = 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'arrowup': () => {
|
'arrowup': () => {
|
||||||
if(selectedItem.value === 0) {
|
if (selectedItem.value === 0) {
|
||||||
selectedItem.value = filteredRows.value.length - 1
|
selectedItem.value = filteredRows.value.length - 1
|
||||||
} else {
|
} else {
|
||||||
selectedItem.value -= 1
|
selectedItem.value -= 1
|
||||||
@@ -202,7 +209,7 @@ const selectedItem = ref(0)
|
|||||||
|
|
||||||
|
|
||||||
const setupPage = async () => {
|
const setupPage = async () => {
|
||||||
items.value = (await useEntities("createddocuments").select("*, customer(id,name), statementallocations(id,amount),linkedDocument(*)","documentNumber",true, true))
|
items.value = (await useEntities("createddocuments").select("*, customer(id,name), statementallocations(id,amount),linkedDocument(*)", "documentNumber", true, true))
|
||||||
}
|
}
|
||||||
|
|
||||||
setupPage()
|
setupPage()
|
||||||
@@ -309,7 +316,7 @@ const filteredRows = computed(() => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
if(selectedFilters.value.length > 0) {
|
if (selectedFilters.value.length > 0) {
|
||||||
selectedFilters.value.forEach(filterName => {
|
selectedFilters.value.forEach(filterName => {
|
||||||
let filter = dataType.filters.find(i => i.name === filterName)
|
let filter = dataType.filters.find(i => i.name === filterName)
|
||||||
tempItems = tempItems.filter(filter.filterFunction)
|
tempItems = tempItems.filter(filter.filterFunction)
|
||||||
@@ -317,7 +324,6 @@ const filteredRows = computed(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
tempItems = useSearch(searchString.value, tempItems)
|
tempItems = useSearch(searchString.value, tempItems)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<UDashboardNavbar title="Serienrechnungen" :badge="filteredRows.length">
|
<UDashboardNavbar title="Serienrechnungen" :badge="filteredRows.length">
|
||||||
<template #right>
|
<template #right>
|
||||||
@@ -25,7 +23,7 @@
|
|||||||
</UDashboardNavbar>
|
</UDashboardNavbar>
|
||||||
<UDashboardToolbar>
|
<UDashboardToolbar>
|
||||||
<template #right>
|
<template #right>
|
||||||
<USelectMenu
|
<!-- <USelectMenu
|
||||||
v-model="selectedColumns"
|
v-model="selectedColumns"
|
||||||
icon="i-heroicons-adjustments-horizontal-solid"
|
icon="i-heroicons-adjustments-horizontal-solid"
|
||||||
:options="templateColumns"
|
:options="templateColumns"
|
||||||
@@ -36,7 +34,7 @@
|
|||||||
<template #label>
|
<template #label>
|
||||||
Spalten
|
Spalten
|
||||||
</template>
|
</template>
|
||||||
</USelectMenu>
|
</USelectMenu>-->
|
||||||
<USelectMenu
|
<USelectMenu
|
||||||
v-model="selectedFilters"
|
v-model="selectedFilters"
|
||||||
icon="i-heroicons-adjustments-horizontal-solid"
|
icon="i-heroicons-adjustments-horizontal-solid"
|
||||||
|
|||||||
@@ -364,33 +364,67 @@ const clearSearchString = () => {
|
|||||||
variant="outline"
|
variant="outline"
|
||||||
v-if="Object.keys(selectedFiles).find(i => selectedFiles[i] === true)"
|
v-if="Object.keys(selectedFiles).find(i => selectedFiles[i] === true)"
|
||||||
>Herunterladen</UButton>
|
>Herunterladen</UButton>
|
||||||
<UModal
|
<UModal v-model="createFolderModalOpen">
|
||||||
v-model="createFolderModalOpen"
|
<UCard :ui="{ body: { base: 'space-y-4' } }">
|
||||||
>
|
|
||||||
<UCard>
|
|
||||||
<template #header>
|
<template #header>
|
||||||
Ordner Erstellen
|
<div class="flex items-center justify-between">
|
||||||
</template>
|
<h3 class="text-base font-semibold leading-6 text-gray-900 dark:text-white">
|
||||||
|
Ordner Erstellen
|
||||||
|
</h3>
|
||||||
|
<UButton color="gray" variant="ghost" icon="i-heroicons-x-mark-20-solid" class="-my-1" @click="createFolderModalOpen = false" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<UFormGroup label="Name des Ordners" required>
|
||||||
|
<UInput
|
||||||
|
v-model="createFolderData.name"
|
||||||
|
placeholder="z.B. Rechnungen 2024"
|
||||||
|
autofocus
|
||||||
|
/>
|
||||||
|
</UFormGroup>
|
||||||
|
|
||||||
|
<UFormGroup
|
||||||
<UFormGroup
|
label="Standard Dateityp"
|
||||||
label="Ordner erstellen"
|
>
|
||||||
|
<USelectMenu
|
||||||
|
v-model="createFolderData.standardFiletype"
|
||||||
|
:options="filetags"
|
||||||
|
option-attribute="name"
|
||||||
|
value-attribute="id"
|
||||||
|
searchable
|
||||||
|
searchable-placeholder="Typ suchen..."
|
||||||
|
placeholder="Kein Standard-Typ"
|
||||||
|
clear-search-on-close
|
||||||
>
|
>
|
||||||
<UInput
|
<template #label>
|
||||||
v-model="createFolderData.name"
|
<span v-if="createFolderData.standardFiletype">
|
||||||
|
{{ filetags.find(t => t.id === createFolderData.standardFiletype)?.name }}
|
||||||
|
</span>
|
||||||
|
<span v-else class="text-gray-400">Kein Typ ausgewählt</span>
|
||||||
|
</template>
|
||||||
|
</USelectMenu>
|
||||||
|
</UFormGroup>
|
||||||
|
|
||||||
|
<div v-if="createFolderData.standardFiletype">
|
||||||
|
<UCheckbox
|
||||||
|
v-model="createFolderData.standardFiletypeIsOptional"
|
||||||
|
name="isOptional"
|
||||||
|
label="Dateityp ist optional"
|
||||||
|
help="Wenn deaktiviert, MUSS der Nutzer beim Upload diesen Typ verwenden."
|
||||||
/>
|
/>
|
||||||
</UFormGroup>
|
</div>
|
||||||
|
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<UButton
|
<div class="flex justify-end gap-2">
|
||||||
@click="createFolder"
|
<UButton color="gray" variant="ghost" @click="createFolderModalOpen = false">
|
||||||
>
|
Abbrechen
|
||||||
Erstellen
|
</UButton>
|
||||||
</UButton>
|
<UButton @click="createFolder" :disabled="!createFolderData.name">
|
||||||
|
Erstellen
|
||||||
|
</UButton>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</UCard>
|
</UCard>
|
||||||
|
|
||||||
</UModal>
|
</UModal>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
@@ -429,8 +463,8 @@ const clearSearchString = () => {
|
|||||||
|
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<span v-if="entry.type === 'file'" class="text-xl">{{dayjs(documents.find(i => i.id === entry.id).created_at).format("DD.MM.YY HH:mm")}}</span>
|
<span v-if="entry.type === 'file'" class="text-xl">{{dayjs(documents.find(i => i.id === entry.id).createdAt).format("DD.MM.YY HH:mm")}}</span>
|
||||||
<span v-if="entry.type === 'folder'" class="text-xl">{{dayjs(currentFolders.find(i => i.id === entry.id).created_at).format("DD.MM.YY HH:mm")}}</span>
|
<span v-if="entry.type === 'folder'" class="text-xl">{{dayjs(currentFolders.find(i => i.id === entry.id).createdAt).format("DD.MM.YY HH:mm")}}</span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
Reference in New Issue
Block a user