Merge branch 'dev' into beta
This commit is contained in:
@@ -42,7 +42,7 @@ const showFile = (file) => {
|
||||
<iframe
|
||||
:src="`${documentData.url}#toolbar=0&navpanes=0&scrollbar=0`"
|
||||
class="previewEmbed"
|
||||
v-if="documentData.path.includes('pdf')"
|
||||
v-if="documentData.path.toLowerCase().includes('pdf')"
|
||||
loading="lazy"
|
||||
/>
|
||||
<img
|
||||
|
||||
@@ -24,6 +24,7 @@ const emit = defineEmits(["updateNeeded"])
|
||||
const folders = ref([])
|
||||
|
||||
const filetypes = ref([])
|
||||
const documentboxes = ref([])
|
||||
|
||||
const setup = async () => {
|
||||
const {data} = await supabase.from("folders").select().eq("tenant",useProfileStore().currentTenant)
|
||||
@@ -55,6 +56,7 @@ const setup = async () => {
|
||||
})
|
||||
|
||||
filetypes.value = await useSupabaseSelect("filetags")
|
||||
documentboxes.value = await useSupabaseSelect("documentboxes")
|
||||
}
|
||||
|
||||
setup()
|
||||
@@ -180,7 +182,7 @@ const moveFile = async () => {
|
||||
|
||||
<template>
|
||||
<UModal fullscreen >
|
||||
<UCard :ui="{ body: { base: 'flex-1' }, ring: '', divide: 'divide-y divide-gray-100 dark:divide-gray-800' }">
|
||||
<UCard :ui="{ body: { base: 'flex-1' }, ring: '', divide: 'divide-y divide-gray-100 dark:divide-gray-800' }" class="h-full">
|
||||
<template #header>
|
||||
<div class="flex flex-row justify-between">
|
||||
<div class="flex items-center gap-2">
|
||||
@@ -200,7 +202,7 @@ const moveFile = async () => {
|
||||
class="bigPreview"
|
||||
:data="`${props.documentData.url}#toolbar=0&navpanes=0&scrollbar=0`"
|
||||
type="application/pdf"
|
||||
v-if="props.documentData.path.includes('pdf')"
|
||||
v-if="props.documentData.path.toLowerCase().includes('pdf')"
|
||||
|
||||
/>
|
||||
<img
|
||||
@@ -371,6 +373,18 @@ const moveFile = async () => {
|
||||
@change="updateDocument"
|
||||
/>
|
||||
</InputGroup>
|
||||
<UDivider class="my-5">Dokumentenbox</UDivider>
|
||||
|
||||
<InputGroup class="w-full">
|
||||
<USelectMenu
|
||||
class="flex-auto"
|
||||
v-model="props.documentData.documentbox"
|
||||
value-attribute="id"
|
||||
option-attribute="key"
|
||||
:options="documentboxes"
|
||||
@change="updateDocument"
|
||||
/>
|
||||
</InputGroup>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<script setup >
|
||||
|
||||
import DocumentUploadModal from "~/components/DocumentUploadModal.vue";
|
||||
|
||||
const props = defineProps({
|
||||
type: {
|
||||
type: String
|
||||
@@ -13,103 +15,20 @@ const {type, elementId} = props
|
||||
|
||||
const emit = defineEmits(["uploadFinished"])
|
||||
|
||||
const dataStore = useDataStore()
|
||||
const profileStore = useProfileStore()
|
||||
|
||||
const uploadModalOpen = ref(false)
|
||||
const uploadInProgress = ref(false)
|
||||
const fileUploadFormData = ref({
|
||||
project: null,
|
||||
tenant: profileStore.currentTenant
|
||||
})
|
||||
const availableTags = ref([])
|
||||
const selectedTags = ref([])
|
||||
const setup = async () => {
|
||||
availableTags.value = await useSupabaseSelect("filetags")
|
||||
}
|
||||
|
||||
setup()
|
||||
|
||||
const modal = useModal()
|
||||
|
||||
const openModal = () => {
|
||||
uploadModalOpen.value = true
|
||||
}
|
||||
let fileProps = {folder: null, type: null, typeEnabled: true}
|
||||
|
||||
const uploadFiles = async () => {
|
||||
uploadInProgress.value = true;
|
||||
fileProps[props.type] = props.elementId
|
||||
|
||||
let fileData = fileUploadFormData.value
|
||||
fileData[type] = elementId
|
||||
console.log(fileProps)
|
||||
|
||||
await useFiles().uploadFiles(fileData, document.getElementById("fileUploadInput").files,selectedTags.value,true)
|
||||
|
||||
uploadModalOpen.value = false;
|
||||
uploadInProgress.value = false;
|
||||
emit("uploadFinished")
|
||||
modal.open(DocumentUploadModal,{fileData: fileProps, onUploadFinished: () => emit("uploadFinished")})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<USlideover
|
||||
v-model="uploadModalOpen"
|
||||
>
|
||||
<UCard :ui="{ ring: '', divide: 'divide-y divide-gray-100 dark:divide-gray-800' }" class="h-full">
|
||||
<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="uploadModalOpen = false"
|
||||
:disabled="uploadInProgress"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<UFormGroup
|
||||
label="Datei:"
|
||||
>
|
||||
<UInput
|
||||
type="file"
|
||||
id="fileUploadInput"
|
||||
multiple
|
||||
accept="image/jpeg, image/png, image/gif, application/pdf"
|
||||
/>
|
||||
</UFormGroup>
|
||||
<UFormGroup
|
||||
label="Tags:"
|
||||
class="mt-3"
|
||||
>
|
||||
<USelectMenu
|
||||
multiple
|
||||
option-attribute="name"
|
||||
value-attribute="id"
|
||||
searchable
|
||||
searchable-placeholder="Suchen..."
|
||||
:options="availableTags"
|
||||
v-model="selectedTags"
|
||||
>
|
||||
<template #label>
|
||||
<span v-if="selectedTags.length > 0">{{selectedTags.map(i => availableTags.find(x => x.id === i).name).join(", ")}}</span>
|
||||
<span v-else>Keine Tags ausgewählt</span>
|
||||
</template>
|
||||
</USelectMenu>
|
||||
</UFormGroup>
|
||||
|
||||
<template #footer>
|
||||
<UButton
|
||||
@click="uploadFiles"
|
||||
:loading="uploadInProgress"
|
||||
>Hochladen</UButton>
|
||||
</template>
|
||||
|
||||
</UCard>
|
||||
</USlideover>
|
||||
|
||||
<UButton
|
||||
@click="openModal"
|
||||
icon="i-heroicons-arrow-up-tray"
|
||||
|
||||
@@ -38,12 +38,13 @@ defineShortcuts({
|
||||
const emit = defineEmits(["updateNeeded"])
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const dataStore = useDataStore()
|
||||
const modal = useModal()
|
||||
|
||||
const dataType = dataStore.dataTypes[type]
|
||||
|
||||
const openTab = ref(0)
|
||||
const openTab = ref(route.query.tabIndex || 0)
|
||||
|
||||
|
||||
|
||||
@@ -88,6 +89,10 @@ const getAvailableQueryStringData = (keys) => {
|
||||
|
||||
}
|
||||
|
||||
const onTabChange = (index) => {
|
||||
router.push(`${router.currentRoute.value.path}?tabIndex=${index}`)
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -188,6 +193,7 @@ const getAvailableQueryStringData = (keys) => {
|
||||
v-if="props.item.id && platform !== 'mobile'"
|
||||
class="p-5"
|
||||
v-model="openTab"
|
||||
@change="onTabChange"
|
||||
>
|
||||
<template #item="{item:tab}">
|
||||
<div v-if="tab.label === 'Informationen'" class="flex flex-row">
|
||||
|
||||
@@ -46,7 +46,7 @@ setup()
|
||||
</template>
|
||||
<Toolbar>
|
||||
<DocumentUpload
|
||||
:type="props.type.substring(0,props.type.length-1)"
|
||||
:type="props.topLevelType.substring(0,props.topLevelType.length-1)"
|
||||
:element-id="props.item.id"
|
||||
@uploadFinished="emit('updateNeeded')"
|
||||
/>
|
||||
|
||||
@@ -27,8 +27,9 @@ const dataType = dataStore.dataTypes[props.topLevelType]
|
||||
<template>
|
||||
<UCard class="mt-5 scroll" :style="props.platform !== 'mobile' ? 'height: 80vh' : ''">
|
||||
<HistoryDisplay
|
||||
:type="props.topLevelType.substring(0,props.topLevelType.length-1)"
|
||||
v-if="props.item.id"
|
||||
:type="dataType.historyItemHolder"
|
||||
v-if="props
|
||||
.item.id"
|
||||
:element-id="props.item.id"
|
||||
render-headline
|
||||
/>
|
||||
|
||||
@@ -54,10 +54,26 @@ const links = computed(() => {
|
||||
to: "/standardEntity/events",
|
||||
icon: "i-heroicons-calendar-days"
|
||||
}] : [],
|
||||
/*{
|
||||
label: "Dateien",
|
||||
to: "/files",
|
||||
icon: "i-heroicons-document"
|
||||
},*/
|
||||
]
|
||||
},
|
||||
{
|
||||
label: "Dokumente",
|
||||
icon: "i-heroicons-rectangle-stack",
|
||||
defaultOpen: false,
|
||||
children: [
|
||||
{
|
||||
label: "Dateien",
|
||||
to: "/files",
|
||||
icon: "i-heroicons-document"
|
||||
},{
|
||||
label: "Boxen",
|
||||
to: "/standardEntity/documentboxes",
|
||||
icon: "i-heroicons-archive-box"
|
||||
},
|
||||
]
|
||||
},
|
||||
|
||||
@@ -246,6 +246,18 @@ export const useRole = () => {
|
||||
label: "Buchungskonten erstellen",
|
||||
parent: "ownaccounts"
|
||||
},
|
||||
documentboxes: {
|
||||
label: "Dokuemntenboxen",
|
||||
showToAllUsers: false
|
||||
},
|
||||
"documentboxes-viewAll": {
|
||||
label: "Alle Dokuemntenboxen einsehen",
|
||||
parent: "documentboxesx"
|
||||
},
|
||||
"documentboxes-create": {
|
||||
label: "Dokuemntenboxen erstellen",
|
||||
parent: "documentboxes"
|
||||
},
|
||||
"inventory": {
|
||||
label: "Lager",
|
||||
},
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script setup>
|
||||
|
||||
import dayjs from "dayjs";
|
||||
import {useSupabaseSelect} from "~/composables/useSupabase.js";
|
||||
|
||||
const supabase = useSupabaseClient()
|
||||
const route = useRoute()
|
||||
@@ -8,21 +9,57 @@ const router = useRouter()
|
||||
const profileStore = useProfileStore()
|
||||
|
||||
const itemInfo = ref(null)
|
||||
const statementallocations = ref(null)
|
||||
const statementallocations = ref([])
|
||||
const incominginvoices = ref([])
|
||||
|
||||
const setup = async () => {
|
||||
itemInfo.value = (await supabase.from("accounts").select("*").eq("id",route.params.id).single()).data
|
||||
statementallocations.value = (await supabase.from("statementallocations").select("*, bs_id(*)").eq("account", route.params.id).eq("tenant",profileStore.currentTenant).order("created_at",{ascending: true})).data
|
||||
incominginvoices.value = (await useSupabaseSelect("incominginvoices", "*, vendor(*)")).filter(i => i.accounts.find(x => x.account == route.params.id))
|
||||
}
|
||||
|
||||
setup()
|
||||
|
||||
const selectAllocation = (allocation) => {
|
||||
if(allocation.bs_id) {
|
||||
if(allocation.type === "statementallocation") {
|
||||
router.push(`/banking/statements/edit/${allocation.bs_id.id}`)
|
||||
} else if(allocation.type === "incominginvoice") {
|
||||
router.push(`/incominginvoices/show/${allocation.incominginvoiceid}`)
|
||||
}
|
||||
}
|
||||
|
||||
const renderedAllocations = computed(() => {
|
||||
|
||||
let tempstatementallocations = statementallocations.value.map(i => {
|
||||
return {
|
||||
...i,
|
||||
type: "statementallocation",
|
||||
date: i.bs_id.date,
|
||||
partner: i.bs_id ? (i.bs_id.debName ? i.bs_id.debName : (i.bs_id.credName ? i.bs_id.credName : '')) : ''
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
let incominginvoicesallocations = []
|
||||
|
||||
incominginvoices.value.forEach(i => {
|
||||
|
||||
incominginvoicesallocations.push(...i.accounts.filter(x => x.account == route.params.id).map(x => {
|
||||
return {
|
||||
...x,
|
||||
incominginvoiceid: i.id,
|
||||
type: "incominginvoice",
|
||||
amount: x.amountGross ? x.amountGross : x.amountNet,
|
||||
date: i.date,
|
||||
partner: i.vendor.name,
|
||||
description: i.description,
|
||||
color: i.expense ? "red" : "green"
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
return [...tempstatementallocations, ... incominginvoicesallocations]
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
@@ -76,21 +113,18 @@ const selectAllocation = (allocation) => {
|
||||
<UCard class="mt-5" v-if="item.label === 'Buchungen'">
|
||||
<UTable
|
||||
v-if="statementallocations"
|
||||
:rows="statementallocations"
|
||||
:rows="renderedAllocations"
|
||||
:columns="[{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' }"
|
||||
>
|
||||
<template #amount-data="{row}">
|
||||
<span class="text-right text-rose-600" v-if="row.amount < 0">{{useCurrency(row.amount)}}</span>
|
||||
<span class="text-right text-primary-500" v-else-if="row.amount > 0">{{useCurrency(row.amount)}}</span>
|
||||
<span class="text-right text-rose-600" v-if="row.amount < 0 || row.color === 'red'">{{useCurrency(row.amount)}}</span>
|
||||
<span class="text-right text-primary-500" v-else-if="row.amount > 0 || row.color === 'green'">{{useCurrency(row.amount)}}</span>
|
||||
<span v-else>{{useCurrency(row.amount)}}</span>
|
||||
</template>
|
||||
<template #date-data="{row}">
|
||||
{{row.bs_id ? dayjs(row.bs_id.date).format('DD.MM.YYYY') : ''}}
|
||||
</template>
|
||||
<template #partner-data="{row}">
|
||||
{{row.bs_id ? (row.bs_id.debName ? row.bs_id.debName : (row.bs_id.credName ? row.bs_id.credName : '')) : ''}}
|
||||
{{row.date ? dayjs(row.date).format('DD.MM.YYYY') : ''}}
|
||||
</template>
|
||||
<template #description-data="{row}">
|
||||
{{row.description ? row.description : ''}}
|
||||
|
||||
@@ -56,7 +56,6 @@ const profileStore = useProfileStore()
|
||||
const supabase = useSupabaseClient()
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const slideover = useSlideover()
|
||||
const modal = useModal()
|
||||
|
||||
dataStore.fetchDocuments()
|
||||
@@ -73,8 +72,6 @@ const fileUploadFormData = ref({
|
||||
|
||||
const files = useFiles()
|
||||
|
||||
let tags = dataStore.getDocumentTags
|
||||
|
||||
const displayMode = ref("list")
|
||||
const displayModes = ref([{label: 'Liste',key:'list', icon: 'i-heroicons-list-bullet'},{label: 'Kacheln',key:'rectangles', icon: 'i-heroicons-squares-2x2'}])
|
||||
|
||||
@@ -107,8 +104,9 @@ const setupPage = async () => {
|
||||
|
||||
const dropZone = document.getElementById("drop_zone")
|
||||
dropZone.ondragover = function (event) {
|
||||
console.log(event)
|
||||
isDragTarget.value = true
|
||||
modal.open(DocumentUploadModal,{fileData: {folder: currentFolder.value.id, type: currentFolder.value.standardFiletype, typeEnabled: currentFolder.value.standardFiletypeIsOptional}, onUploadFinished: () => {
|
||||
setupPage()
|
||||
}})
|
||||
event.preventDefault()
|
||||
}
|
||||
|
||||
@@ -120,9 +118,6 @@ const setupPage = async () => {
|
||||
console.log("files dropped")
|
||||
event.preventDefault()
|
||||
|
||||
await uploadFiles(event.dataTransfer.files)
|
||||
isDragTarget.value = false
|
||||
setupPage()
|
||||
}
|
||||
|
||||
|
||||
@@ -230,23 +225,6 @@ const createFolder = async () => {
|
||||
|
||||
}
|
||||
|
||||
const uploadFiles = async (files) => {
|
||||
uploadInProgress.value = true;
|
||||
|
||||
if(files) {
|
||||
//await dataStore.uploadFiles({tags: ["Ablage"],tenant: profileStore.currentTenant,folder: currentFolder.value.id}, files, true)
|
||||
await dataStore.uploadFiles({tags: ["Ablage"],tenant: profileStore.currentTenant}, files, true)
|
||||
|
||||
} else {
|
||||
await dataStore.uploadFiles(fileUploadFormData.value, document.getElementById("fileUploadInput").files, true)
|
||||
|
||||
}
|
||||
|
||||
|
||||
uploadModalOpen.value = false;
|
||||
uploadInProgress.value = false;
|
||||
}
|
||||
|
||||
const downloadSelected = async () => {
|
||||
const bucket = "filesdev";
|
||||
|
||||
@@ -352,9 +330,7 @@ const selectAll = () => {
|
||||
|
||||
<UDashboardNavbar
|
||||
title="Dateien"
|
||||
>
|
||||
|
||||
</UDashboardNavbar>
|
||||
></UDashboardNavbar>
|
||||
<UDashboardToolbar>
|
||||
<template #left>
|
||||
<UBreadcrumb
|
||||
@@ -375,7 +351,7 @@ const selectAll = () => {
|
||||
</USelectMenu>
|
||||
|
||||
|
||||
<UButton @click="modal.open(DocumentUploadModal,{fileData: {folder: currentFolder.id, type: currentFolder.standardFiletype, typeEnabled: currentFolder.standardFiletypeIsOptional}})">+ Datei</UButton>
|
||||
<UButton @click="modal.open(DocumentUploadModal,{fileData: {folder: currentFolder.id, type: currentFolder.standardFiletype, typeEnabled: currentFolder.standardFiletypeIsOptional}, onUploadFinished: () => {setupPage()}})">+ Datei</UButton>
|
||||
<UButton
|
||||
@click="createFolderModalOpen = true"
|
||||
variant="outline"
|
||||
@@ -419,7 +395,7 @@ const selectAll = () => {
|
||||
</UDashboardToolbar>
|
||||
<div id="drop_zone" class="h-full scrollList" >
|
||||
<div v-if="loaded">
|
||||
<UDashboardPanelContent v-if="!isDragTarget" >
|
||||
<UDashboardPanelContent>
|
||||
<div v-if="displayMode === 'list'">
|
||||
<table class="w-full">
|
||||
<thead>
|
||||
@@ -498,70 +474,10 @@ const selectAll = () => {
|
||||
/>
|
||||
</div>
|
||||
</UDashboardPanelContent>
|
||||
<UCard
|
||||
class=" m-5"
|
||||
v-else>
|
||||
<template #header>
|
||||
<p class="mx-auto">Dateien zum hochladen hierher ziehen</p>
|
||||
|
||||
</template>
|
||||
</UCard>
|
||||
</div>
|
||||
<UProgress animation="carousel" v-else class="w-5/6 mx-auto mt-5"/>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<USlideover
|
||||
v-model="uploadModalOpen"
|
||||
>
|
||||
|
||||
<UCard class="flex flex-col flex-1" :ui="{ body: { base: 'flex-1' }, ring: '', divide: 'divide-y divide-gray-100 dark:divide-gray-800' }">
|
||||
<template #header>
|
||||
Datei Hochladen
|
||||
</template>
|
||||
|
||||
<div class="h-full">
|
||||
<UFormGroup
|
||||
label="Datei:"
|
||||
>
|
||||
<UInput
|
||||
type="file"
|
||||
id="fileUploadInput"
|
||||
multiple
|
||||
/>
|
||||
</UFormGroup>
|
||||
|
||||
<UFormGroup
|
||||
label="Tags:"
|
||||
class="mt-3"
|
||||
>
|
||||
<USelectMenu
|
||||
multiple
|
||||
searchable
|
||||
searchable-placeholder="Suchen..."
|
||||
option-attribute="name"
|
||||
value-attribute="id"
|
||||
:options="filetags"
|
||||
v-model="fileUploadFormData.tags"
|
||||
/>
|
||||
</UFormGroup>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<UButton
|
||||
v-if="!uploadInProgress"
|
||||
class="mt-3"
|
||||
@click="uploadFiles"
|
||||
>Hochladen</UButton>
|
||||
<UProgress
|
||||
v-else
|
||||
animation="carousel"
|
||||
/>
|
||||
</template>
|
||||
</UCard>
|
||||
</USlideover>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -1528,6 +1528,69 @@ export const useDataStore = defineStore('data', () => {
|
||||
}
|
||||
]
|
||||
},
|
||||
documentboxes: {
|
||||
isArchivable: true,
|
||||
label: "Dokumentenboxen",
|
||||
labelSingle: "Dokumentenbox",
|
||||
isStandardEntity: true,
|
||||
supabaseSelectWithInformation: "*, space(*), files(*)",
|
||||
redirect: true,
|
||||
numberRangeHolder: "key",
|
||||
historyItemHolder: "documentbox",
|
||||
inputColumns: [
|
||||
"Allgemeines",
|
||||
],
|
||||
filters:[{
|
||||
name: "Archivierte ausblenden",
|
||||
default: true,
|
||||
"filterFunction": function (row) {
|
||||
if(!row.archived) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}],
|
||||
templateColumns: [
|
||||
{
|
||||
key: "space",
|
||||
label: "Aktueller Lagerplatz",
|
||||
inputType: "select",
|
||||
selectDataType: "spaces",
|
||||
selectOptionAttribute: "name",
|
||||
selectSearchAttributes: ['name'],
|
||||
inputColumn: "Allgemeines",
|
||||
component: space
|
||||
},
|
||||
{
|
||||
key: "key",
|
||||
label: "Nummer",
|
||||
inputType: "text",
|
||||
inputIsNumberRange: true,
|
||||
inputColumn: "Allgemeines",
|
||||
title: true,
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
key: "profiles",
|
||||
label: "Berechtigte Benutzer",
|
||||
inputType: "select",
|
||||
selectDataType: "profiles",
|
||||
selectOptionAttribute: "fullName",
|
||||
selectSearchAttributes: ['fullName'],
|
||||
selectMultiple: true,
|
||||
component: profiles
|
||||
},
|
||||
|
||||
],
|
||||
showTabs: [
|
||||
{
|
||||
label: 'Informationen',
|
||||
}, {
|
||||
label: 'Dateien',
|
||||
}
|
||||
]
|
||||
},
|
||||
services: {
|
||||
isArchivable: true,
|
||||
label: "Leistungen",
|
||||
|
||||
Reference in New Issue
Block a user