Many Changes

This commit is contained in:
2024-02-01 21:00:59 +01:00
parent fe74e7d91b
commit 34d1eb9c71
18 changed files with 493 additions and 374 deletions

View File

@@ -1,50 +1,19 @@
<script setup>
import GlobalSearch from "~/components/GlobalSearch.vue";
const supabase = useSupabaseClient()
const user = useSupabaseUser()
//console.log(user.value)
const route = useRoute()
const tenants = (await supabase.from("tenants").select()).data
const dataStore = useDataStore()
//console.log(userProfile)
const viewport = useViewport()
watch(viewport.breakpoint, (newBreakpoint, oldBreakpoint) => {
/*watch(viewport.breakpoint, (newBreakpoint, oldBreakpoint) => {
console.log('Breakpoint updated:', oldBreakpoint, '->', newBreakpoint)
})
})*/
dataStore.initializeData()
const linksForBreadcrumbs = ref([])
//const userTenant = ref({})
//if(user) userTenant.value = tenants.find(tenant => tenant.id === user.value.app_metadata.tenant)
useHead({
meta: [
{ name: 'viewport', content: 'width=device-width, initial-scale=1' }
@@ -62,47 +31,6 @@ useSeoMeta({
twitterCard: 'summary_large_image'
})
const items = [
[{
label: user.value ? user.value.email : "",
slot: 'account',
disabled: true
}], [{
label: 'Externe Geräte',
icon: 'i-heroicons-cog-8-tooth',
to: "/settings/externalDevices"
},{
label: 'Nummernkreise',
icon: 'i-heroicons-cog-8-tooth',
to: "/settings/numberRanges"
},{
label: 'Benutzer',
icon: 'i-heroicons-user-group',
to: "/settings/users"
}], /*[{
label: 'Documentation',
icon: 'i-heroicons-book-open'
}, {
label: 'Changelog',
icon: 'i-heroicons-megaphone'
}, {
label: 'Status',
icon: 'i-heroicons-signal'
}],*/ [{
label: 'Ausloggen',
icon: 'i-heroicons-arrow-left-on-rectangle',
click: async () => {
await supabase.auth.signOut()
await dataStore.clearStore()
await router.push("/login")
}
}]
]
</script>
<template>
@@ -110,62 +38,10 @@ const items = [
<NuxtLayout>
<NuxtPage/>
</NuxtLayout>
<!-- <UFooter>
<template #left>
<p class="text-gray-500 dark:text-gray-400 text-sm">
Copyright © 2023-{{ new Date().getFullYear() }} <NuxtLink class="hover:underline" to="https://federspiel.tech" target="_blank">
Federspiel Technolog UG haftungsbeschränkt
</NuxtLink>
</p>
</template>
<template #right>
</template>
</UFooter>-->
<UNotifications/>
<VitePwaManifest/>
<!-- <UCard id="page">
<template #header>
<div id="menu">
<router-link
v-for="link in navLinks"
:to="link.to"
class="mr-2"
>
<UButton>{{link.label}}</UButton>
</router-link>
&lt;!&ndash;<router-link to="/customers" class="mr-2"><UButton>Kunden</UButton></router-link>
<router-link to="/projects" class="mr-2"><UButton>Projekte</UButton></router-link>
-
<router-link to="/receipts" class="mr-2"><UButton>Eingangsrechnungen</UButton></router-link>
<router-link to="/timetracking" class="mr-2"><UButton>Zeiterfassung</UButton></router-link>
<router-link to="/products" class="mr-2"><UButton>Artikel</UButton></router-link>
<router-link to="/documents" class="mr-2"><UButton>Dokumente</UButton></router-link>
<router-link to="/inventory" class="mr-2"><UButton>Inventar</UButton></router-link>&ndash;&gt;
<UDropdown :items="userDropdownItems" :popper="{placement: 'bottom-start'}">
<UButton color="white" label="Benutzer" trailing-icon="i-heroicons-chevron-down-20-solid" />
</UDropdown>
</div>
<UBreadcrumb
class="my-3"
:links="linksForBreadcrumbs"
/>
</template>
<NuxtPage
v-if="loaded"
/>
<div
v-else
>
<UProgress animation="carousel" />
</div>
</UCard>-->
</template>

View File

@@ -5,7 +5,7 @@ const supabase = useSupabaseClient()
const dataStore = useDataStore()
const router = useRouter()
const props = defineProps({
document: {
documentData: {
type: Object,
required: true
},
@@ -13,9 +13,10 @@ const props = defineProps({
type: Boolean,
required: false,
}
})
const {document, openShowModal:openShowModalProp } = props;
let {documentData, openShowModal:openShowModalProp } = props;
const tags = dataStore.getDocumentTags
const openShowModal = ref(false)
@@ -27,7 +28,7 @@ const openDocument = async () => {
const updateDocument = async () => {
const {url, ...objData} = document
const {url, ...objData} = documentData
delete objData.url
const {data,error} = await supabase
@@ -50,7 +51,7 @@ const createVendorInvoice = async () => {
const {data:vendorInvoiceData,error:vendorInvoiceError} = await supabase
.from("incomingInvoices")
.insert([{
document: document.id,
document: documentData.id,
}])
.select()
if(vendorInvoiceError) {
@@ -62,7 +63,7 @@ const createVendorInvoice = async () => {
.update({
vendorInvoice: vendorInvoiceData[0].id
})
.eq('id',document.id)
.eq('id',documentData.id)
.select()
if(documentError) {
@@ -84,16 +85,18 @@ const createVendorInvoice = async () => {
const archiveDocument = () => {
document.tags = ["Archiviert"]
documentData.tags = ["Archiviert"]
updateDocument()
}
</script>
<template>
<div class="documentListItem">
<object
:data="document.url"
:data="documentData.url"
class="previewEmbed"
type="application/pdf"
/>
@@ -104,22 +107,21 @@ const archiveDocument = () => {
<UIcon name="i-heroicons-eye-solid" />
</UButton>
<UToggle
v-model="document.selected"
v-model="documentData.selected"
class="ml-2"
/>
<br>
<UBadge
v-if="document.vendorInvoice"
>{{dataStore.incomingInvoices.find(item => item.id === document.vendorInvoice) ? dataStore.incomingInvoices.find(item => item.id === document.vendorInvoice).reference : ''}}</UBadge>
v-if="documentData.vendorInvoice"
>{{dataStore.incomingInvoices.find(item => item.id === documentData.vendorInvoice) ? dataStore.incomingInvoices.find(item => item.id === documentData.vendorInvoice).reference : ''}}</UBadge>
<UBadge
v-if="document.inDatev"
v-if="documentData.inDatev"
>DATEV</UBadge>
{{documentData}}
</div>
<!-- Slideovers -->
<USlideover
v-model="openShowModal"
fullscreen
@@ -128,7 +130,7 @@ const archiveDocument = () => {
<template #header>
<div class="flex items-center gap-2">
<UBadge
v-for="tag in document.tags"
v-for="tag in documentData.tags"
>
{{tag}}
</UBadge>
@@ -138,12 +140,13 @@ const archiveDocument = () => {
<UContainer class="h-full" :ui="{padding: 'px-1 sm:px-1 lg:px-1'}">
<object
class="h-full w-full"
:data="document.url"
:data="documentData.url"
type="application/pdf"
/>
</UContainer>
<template #footer>
<UButtonGroup>
<UButton
@click="archiveDocument"
@@ -151,7 +154,7 @@ const archiveDocument = () => {
Archivieren
</UButton>
<UButton
v-if="document.tags.includes('Eingangsrechnung')"
v-if="documentData.tags.includes('Eingangsrechnung')"
@click="createVendorInvoice"
>
Eingangsrechnung erstellen
@@ -164,12 +167,12 @@ const archiveDocument = () => {
>
<USelectMenu
:options="tags"
v-model="document.tags"
v-model="documentData.tags"
@close="updateDocument"
multiple
>
<template #label>
{{document.tags.length}} ausgewählt
{{documentData.tags.length}} ausgewählt
</template>
</USelectMenu>
</UFormGroup>
@@ -181,13 +184,13 @@ const archiveDocument = () => {
:options="dataStore.projects"
option-attribute="name"
value-attribute="id"
v-model="document.project"
v-model="documentData.project"
@change="updateDocument"
searchable
:search-attributes="['name']"
>
<template #label>
{{dataStore.projects.find(item => item.id === document.project) ? dataStore.projects.find(item => item.id === document.project).name : "Kein Projekt ausgewählt" }}
{{dataStore.projects.find(item => item.id === documentData.project) ? dataStore.projects.find(item => item.id === documentData.project).name : "Kein Projekt ausgewählt" }}
</template>
</USelectMenu>
</UFormGroup>
@@ -199,13 +202,13 @@ const archiveDocument = () => {
:options="dataStore.customers"
option-attribute="name"
value-attribute="id"
v-model="document.customer"
v-model="documentData.customer"
@change="updateDocument"
searchable
:search-attributes="['name']"
>
<template #label>
{{dataStore.customers.find(item => item.id === document.customer) ? dataStore.customers.find(item => item.id === document.customer).name : "Kein Kunde ausgewählt" }}
{{dataStore.customers.find(item => item.id === documentData.customer) ? dataStore.customers.find(item => item.id === documentData.customer).name : "Kein Kunde ausgewählt" }}
</template>
</USelectMenu>
</UFormGroup>

View File

@@ -0,0 +1,37 @@
<script setup>
const props = defineProps({
documents: {
type: Array,
required:true
}
})
const dataStore = useDataStore()
</script>
<template>
<div class="documentList">
<DocumentDisplay
v-for="item in documents"
:document-data="item"
:key="item.id"
/>
</div>
</template>
<style scoped>
.documentList {
display: flex;
flex-direction: row;
flex-wrap: wrap;
overflow-y: scroll;
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
}
.documentList::-webkit-scrollbar {
display: none;
}
</style>

View File

@@ -0,0 +1,103 @@
<script setup >
const props = defineProps({
type: {
type: String
},
elementId: {
type: String
}
})
const {type, elementId} = props
const dataStore = useDataStore()
const tags = dataStore.getDocumentTags
const uploadModalOpen = ref(false)
const uploadInProgress = ref(false)
const fileUploadFormData = ref({
tags: ["Dokument"],
project: null
})
const openModal = () => {
console.log("Oepn")
uploadModalOpen.value = true
}
const uploadFiles = async () => {
uploadInProgress.value = true;
let fileData = fileUploadFormData.value
fileData[type] = elementId
await dataStore.uploadFiles(fileData, document.getElementById("fileUploadInput").files)
uploadModalOpen.value = false;
uploadInProgress.value = false;
}
</script>
<template>
<UModal
v-model="uploadModalOpen"
>
<UCard :ui="{ ring: '', divide: 'divide-y divide-gray-100 dark:divide-gray-800' }">
<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"
/>
</UFormGroup>
<UFormGroup
label="Tags:"
class="mt-3"
>
<USelectMenu
multiple
searchable
searchable-placeholder="Suchen..."
:options="tags"
v-model="fileUploadFormData.tags"
/>
</UFormGroup>
<template #footer>
<UButton
@click="uploadFiles"
:loading="uploadInProgress"
>Hochladen</UButton>
</template>
</UCard>
</UModal>
<UButton
@click="openModal"
>
Hochladen
</UButton>
</template>
<style scoped>
</style>

View File

@@ -36,7 +36,7 @@ const historyItems = computed(() => {
items = dataStore.historyItems.filter(i => i.document === elementId)
}
return items.reverse()
return items
})
const addHistoryItemData = ref({
@@ -63,7 +63,7 @@ const addHistoryItem = async () => {
const {data,error} = await supabase
.from("historyItems")
.from("historyitems")
.insert([addHistoryItemData.value])
.select()
@@ -139,10 +139,10 @@ const renderText = (text) => {
v-else
/>
<div>
<h3 v-if="item.user">{{dataStore.profiles.find(profile => profile.id === item.user) ? dataStore.profiles.find(profile => profile.id === item.user).fullName : ""}}</h3>
<h3 v-if="item.user">{{dataStore.getProfileById(item.user) ? dataStore.getProfileById(item.user).fullName : ""}}</h3>
<h3 v-else>Spaces Bot</h3>
<span v-html="renderText(item.text)"/><br>
<span class="text-gray-500">{{dayjs(item.created_at).format("DD:MM:YY HH:mm")}}</span>
<span class="text-gray-500">{{dayjs(item.created_at).format("DD.MM.YY HH:mm")}}</span>
</div>
</div>

View File

@@ -201,60 +201,8 @@ const userMenuItems = ref([
<template #right>
<!-- <ClientOnly>
<UButton
:icon="!isLight ? 'i-heroicons-moon-20-solid' : 'i-heroicons-sun-20-solid'"
color="gray"
variant="ghost"
aria-label="Theme"
@click="isLight = !isLight"
/>
<template #fallback>
<div class="w-8 h-8" />
</template>
</ClientOnly>-->
<GlobalSearch/>
<!-- <UPopover :popper="{placement: 'bottom-start'}">
<ClientOnly>
<UChip
:show="dataStore.notifications.filter(notification => !notification.read).length > 0"
inset
>
<UButton
icon="i-heroicons-envelope-20-solid"
variant="ghost"
color="gray"
class="mx-2"
/>
</UChip>
<template #fallback>
<div class="w-8 h-8" />
</template>
</ClientOnly>
<template #panel>
<div class="w-60 p-3">
<UAlert
class="mb-3"
v-for="(notification,index) in dataStore.notifications"
:color="!notification.read ? 'primary' : 'grey'"
variant="outline"
:description="notification.text"
:title="notification.title"
/>
</div>
</template>
</UPopover>-->
<UButton
@click="showUserMenu = true"
variant="ghost"
@@ -347,29 +295,7 @@ const userMenuItems = ref([
</UCard>
</USlideover>
<!-- <UDropdown :items="items" :ui="{ item: { disabled: 'cursor-text select-text' } }" :popper="{ placement: 'bottom-start' }">
<UAvatar
:alt="userProfile ? userProfile.firstName + ' ' + userProfile.lastName : '' "
icon="i-heroicons-user-20-solid"
/>
<template #account="{ item }">
<div class="text-left">
<p>
Eingeloggt als
</p>
<p class="truncate font-medium text-gray-900 dark:text-white">
{{ item.label }}
</p>
</div>
</template>
<template #item="{ item }">
<span class="truncate">{{ item.label }}</span>
<UIcon :name="item.icon" class="flex-shrink-0 h-4 w-4 text-gray-400 dark:text-gray-500 ms-auto" />
</template>
</UDropdown>-->
</template>
</UHeader>
<UDivider />
@@ -381,8 +307,12 @@ const userMenuItems = ref([
v-else
class="flex-col mx-auto my-auto mt-10 w-3/4"
>
<img src="/spaces.svg" class="w-1/3 mx-auto"/>
<UProgress animation="carousel" class=" " />
<img
:src="!isLight ? '/spaces.svg' : '/spaces_hell.svg'"
alt="Logo"
class="w-1/3 mx-auto"
/>
<UProgress animation="carousel"/>
</div>
</template>

View File

@@ -44,6 +44,7 @@
"@vuepic/vue-datepicker": "^7.4.0",
"@zip.js/zip.js": "^2.7.32",
"axios": "^1.6.2",
"base64-arraybuffer": "^1.0.2",
"buffer": "^6.0.3",
"client-oauth2": "^4.3.3",
"dayjs": "^1.11.10",

View File

@@ -3,7 +3,9 @@ import dayjs from "dayjs"
const dataStore = useDataStore()
const user = useSupabaseUser()
const route = useRoute()
const router = useRouter()
const supabase = useSupabaseClient()
import {decode} from 'base64-arraybuffer'
@@ -35,10 +37,8 @@ const itemInfo = ref({
createdBy: user.value.id,
title: null,
description: null,
startText: "Sehr geehrte Frau Sindern,\n" +
"wir bedanken uns für Ihr entgegengebrachtes Vertrauen und Ihren Auftrag und stellen Ihnen\n" +
"folgende Positionen in Rechnung: ",
endText: "Bitte überweisen Sie den Rechnungsbetrag unter Angabe der Rechnungsnummer im Verwendungszweck innerhalb von 10 Tagen auf das unten angegebene Konto. Wir bedanken uns für das entgegengebrachte Vertrauen und freuen uns auf eine weitere gute Zusammenarbeit.",
startText: null,
endText: null,
rows: [
]
@@ -257,19 +257,58 @@ const saveDocument = async () => {
rows: itemInfo.value.rows
}
let data = null
if(route.params.id) {
await dataStore.updateItem("createdDocuments", {...createData, id: itemInfo.value.id})
data = await dataStore.updateItem("createddocuments", {...createData, id: itemInfo.value.id})
} else {
await dataStore.createNewItem("createdDocuments", createData)
data = await dataStore.createNewItem("createddocuments", createData)
}
await router.push(`/createDocument/edit/${data[0].id}`)
}
const closeDocument = () => {
generateDocument()
console.log(uri)
const closeDocument = async () => {
await saveDocument()
await generateDocument()
let fileData = {
tags: [],
project: null
}
fileData.project = itemInfo.value.project
fileData.createdDocument = itemInfo.value.id
fileData.tags.push(dataStore.documentTypesForCreation[itemInfo.value.type].labelSingle)
function dataURLtoFile(dataurl, filename) {
var arr = dataurl.split(","),
mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[arr.length - 1]),
n = bstr.length,
u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], filename, { type: mime });
}
let file = dataURLtoFile(uri.value, `${itemInfo.value.documentNumber}.pdf`)
await dataStore.uploadFiles(fileData, [file], true)
//console.log(uri)
}

View File

@@ -38,55 +38,12 @@ const filteredDocuments = computed(() => {
})
const uploadFiles = async () => {
const uploadSingleFile = async (file) => {
uploadInProgress.value = true;
const {data, error} = await supabase
.storage
.from("files")
.upload(`${user.value.app_metadata.tenant}/${file.name}`, file)
if (error) {
console.log(error)
} else if (data) {
const returnPath = data.path
if (error) {
} else {
const files = (await supabase.storage.from('files').list(`${user.value.app_metadata.tenant}/`, {
limit: 100,
offset: 0,
sortBy: {column: 'name', order: 'asc'}
})).data
fileUploadFormData.value.path = returnPath
const {data, error} = await supabase
.from("documents")
.insert([fileUploadFormData.value])
.select()
if(error) console.log(error)
}
}
}
uploadInProgress.value = true
let files = document.getElementById("fileUploadInput").files
if(files.length === 1) {
await uploadSingleFile(files[0])
} else if( files.length > 1) {
for(let i = 0; i < files.length; i++){
uploadSingleFile(files[i])
}
}
await dataStore.uploadFiles(fileUploadFormData.value, document.getElementById("fileUploadInput").files)
uploadModalOpen.value = false;
uploadInProgress.value = false;
dataStore.fetchDocuments()
}
const downloadSelected = async () => {
@@ -152,7 +109,7 @@ const downloadSelected = async () => {
<template>
<div>
<div class="flex items-center gap-2">
<InputGroup>
<UButton @click="uploadModalOpen = true">Hochladen</UButton>
<UButton
@click="downloadSelected"
@@ -170,7 +127,7 @@ const downloadSelected = async () => {
</USelectMenu>
</div>
</InputGroup>
<div >
<USlideover
v-model="uploadModalOpen"
@@ -219,13 +176,9 @@ const downloadSelected = async () => {
</template>
</UCard>
</USlideover>
<div class="documentList" >
<DocumentDisplay
:document="i"
:key="i.id"
v-for="i in filteredDocuments"
/>
</div>
<DocumentList
:documents="filteredDocuments"
/>
</div>
</div>

View File

@@ -7,7 +7,18 @@ definePageMeta({
const supabase = useSupabaseClient()
const user = useSupabaseUser()
const router = useRouter()
const {fetchData} = useDataStore()
const colorMode = useColorMode()
const dataStore = useDataStore()
const isLight = computed({
get () {
return colorMode.value !== 'dark'
},
set () {
colorMode.preference = colorMode.value === 'dark' ? 'light' : 'dark'
}
})
const email = ref("")
const password = ref("")
@@ -36,7 +47,7 @@ const onSubmit = async (data) => {
alert(error.toString())
} else {
console.log("Login Successful")
fetchData()
dataStore.changeTenant()
router.push("/")
@@ -74,11 +85,16 @@ const onSubmit = async (data) => {
</div>-->
<UCard class="max-w-sm w-full mx-auto mt-5">
<img
:src="!isLight ? '/spaces.svg' : '/spaces_hell.svg'"
alt="Logo"
class="w-full mx-auto"
/>
<UAuthForm
title="Login"
description="Geben Sie Ihre Anmeldedaten ein um Zugriff auf Ihren Account zu bekommen"
align="bottom"
icon="i-heroicons-user-circle"
:fields="fields"
:loading="false"
@submit="onSubmit"

View File

@@ -1,5 +1,7 @@
<script setup>
import HistoryDisplay from "~/components/HistoryDisplay.vue";
import DocumentList from "~/components/DocumentList.vue";
import DocumentUpload from "~/components/DocumentUpload.vue";
definePageMeta({
middleware: "auth"
@@ -17,7 +19,7 @@ const editor = useEditor({
extensions: [TiptapStarterKit],
});
let currentItem = null
let currentItem = ref(null)
//Working
const mode = ref(route.params.mode || "show")
@@ -30,6 +32,8 @@ const tabItems = [
label: "Projekte"
},{
label: "Aufgaben"
},{
label: "Dokumente"
},{
label: "Dokumentation"
}
@@ -38,10 +42,10 @@ const tabItems = [
//Functions
const setupPage = () => {
if(mode.value === "show" || mode.value === "edit"){
currentItem = dataStore.getPlantById(Number(useRoute().params.id))
currentItem.value = dataStore.getPlantById(Number(useRoute().params.id))
}
if(mode.value === "edit") itemInfo.value = currentItem
if(mode.value === "edit") itemInfo.value = currentItem.value
@@ -50,7 +54,7 @@ const setupPage = () => {
const editItem = async () => {
router.push(`/plants/edit/${currentItem.id}`)
await router.push(`/plants/edit/${currentItem.value.id}`)
setupPage()
}
@@ -100,6 +104,78 @@ setupPage()
</UTable>
</div>
<div v-else-if="item.label === 'Dokumente'" class="space-y-3">
<InputGroup>
<DocumentUpload
type="plant"
:element-id="currentItem.id"
/>
</InputGroup>
<!-- <UModal
v-model="uploadModalOpen"
>
<UCard class="p-4">
<template #header>
Datei hochladen
</template>
<UFormGroup
label="Datei:"
>
<UInput
type="file"
id="fileUploadInput"
/>
</UFormGroup>
&lt;!&ndash; <UFormGroup
label="Name:"
class="mt-3"
>
<UInput
v-model="fileUploadFormData.name"
/>
</UFormGroup>&ndash;&gt;
<UFormGroup
label="Tags:"
class="mt-3"
>
<USelectMenu
multiple
searchable
searchable-placeholder="Suchen..."
:options="tags"
v-model="fileUploadFormData.tags"
/>
</UFormGroup>
&lt;!&ndash;<UFormGroup
label="Ordner:"
class="mt-3"
>
<USelectMenu
:options="folders"
v-model="fileUploadFormData.folder"
value-attribute="label"
/>
</UFormGroup>&ndash;&gt;
<template #footer>
<UButton
class="mt-3"
@click="uploadFiles"
>Hochladen</UButton>
</template>
</UCard>
</UModal>-->
<DocumentList :documents="dataStore.getDocumentsByPlantId(currentItem.id)"/>
</div>
<div v-if="item.label === 'Dokumentation'">
<Editor/>

View File

@@ -1,6 +1,8 @@
<script setup>
import dayjs from "dayjs";
import HistoryDisplay from "~/components/HistoryDisplay.vue";
import DocumentUpload from "~/components/DocumentUpload.vue";
import DocumentList from "~/components/DocumentList.vue";
definePageMeta({
middleware: "auth"
@@ -94,10 +96,7 @@ const itemInfo = ref({
const uploadModalOpen = ref(false)
const fileUploadFormData = ref({
tags: ["Dokument"],
folder: "Projekte",
usedInResource: {
type: "Projekt",
}
project: null
})
const tags = dataStore.getDocumentTags
@@ -153,39 +152,13 @@ const updateItem = async () => {
dataStore.fetchProjects()
}
const uploadFile = async () => {
const file = document.getElementById("fileUploadInput").files[0]
const uploadFiles = async () => {
//uploadInProgress.value = true;
const {data,error} = await supabase
.storage
.from("documents")
.upload(`${user.value.app_metadata.tenant}/${fileUploadFormData.value.folder}/${currentProject.id}/${file.name}`,file)
console.log(data)
const returnPath = data.path
if(error) {
} else {
console.log(returnPath)
const files = (await supabase.storage.from('documents').list(`${user.value.app_metadata.tenant}/${fileUploadFormData.value.folder}/${currentProject.id}/`, {limit: 100, offset: 0, sortBy: { column: 'name', order: 'asc' }})).data
console.log(files)
const fileId = files.find(temp => returnPath.includes(temp.name)).id
fileUploadFormData.value.object = fileId
fileUploadFormData.value.path = returnPath
fileUploadFormData.value.usedInResource.id = currentProject.id
console.log(fileUploadFormData.value)
const {data,error} = await supabase
.from("documents")
.insert([fileUploadFormData.value])
.select()
console.log(data)
console.log(error)
}
await dataStore.uploadFiles({...fileUploadFormData.value, project: currentItem.value.id}, document.getElementById("fileUploadInput").files)
uploadModalOpen.value = false;
//uploadInProgress.value = false;
}
@@ -195,7 +168,7 @@ const projectHours = () => {
hours += Number(dayjs(item.end).diff(item.start,'hour',true).toFixed(2))
})
return hours
return hours.toFixed(2)
}
@@ -256,6 +229,7 @@ setupPage()
</div>
<!--
<div v-else-if="item.key === 'forms'" class="space-y-3">
<UButton
@click="formModalOpen = true"
@@ -308,13 +282,13 @@ setupPage()
</template>
</UAccordion>
</div>
-->
<div v-else-if="item.key === 'documents'" class="space-y-3">
<InputGroup>
<UButton
@click="uploadModalOpen = true"
>
Hochladen
</UButton>
<DocumentUpload
type="project"
:element-id="currentItem.id"
/>
<UButton
@click="router.push(`/createDocument/edit?project=${currentItem.id}&type=quotes&customer=${currentItem.customer}`)"
>
@@ -327,7 +301,7 @@ setupPage()
</UButton>
</InputGroup>
<UModal
<!-- <UModal
v-model="uploadModalOpen"
>
<UCard class="p-4">
@@ -344,14 +318,14 @@ setupPage()
id="fileUploadInput"
/>
</UFormGroup>
<!-- <UFormGroup
&lt;!&ndash; <UFormGroup
label="Name:"
class="mt-3"
>
<UInput
v-model="fileUploadFormData.name"
/>
</UFormGroup>-->
</UFormGroup>&ndash;&gt;
<UFormGroup
label="Tags:"
class="mt-3"
@@ -364,7 +338,7 @@ setupPage()
v-model="fileUploadFormData.tags"
/>
</UFormGroup>
<!--<UFormGroup
&lt;!&ndash;<UFormGroup
label="Ordner:"
class="mt-3"
>
@@ -374,27 +348,22 @@ setupPage()
value-attribute="label"
/>
</UFormGroup>-->
</UFormGroup>&ndash;&gt;
<template #footer>
<UButton
class="mt-3"
@click="uploadFile"
@click="uploadFiles"
>Hochladen</UButton>
</template>
</UCard>
</UModal>
</UModal>-->
<DocumentList :documents="dataStore.getDocumentsByProjectId(currentItem.id)"/>
<div class="documentList">
<DocumentDisplay
v-for="document in dataStore.getDocumentsByProjectId(currentItem.id)"
:document="document"
/>
</div>
</div>
<div v-else-if="item.key === 'timetracking'" class="space-y-3">

View File

@@ -1,8 +1,18 @@
<template>
<div id="main">
<div class="flex items-center gap-1">
<InputGroup>
<UButton @click="router.push(`/incominginvoices/create/`)">+ Eingangsrechnung</UButton>
<UButton
@click="router.push(`/createDocument/edit?type=quotes`)"
>
+ Angebot
</UButton>
<UButton
@click="router.push(`/createDocument/edit?type=invoices`)"
>
+ Rechnung
</UButton>
<UInput
v-model="searchString"
@@ -13,7 +23,7 @@
v-model="showDrafts"
label="Entwürfe Anzeigen"
/>
</div>
</InputGroup>
@@ -172,9 +182,9 @@ const searchString = ref('')
const showDrafts = ref(false)
const filteredRows = computed(() => {
let items = [...dataStore.incomingInvoices.map(i => {return {...i, type: "incomingInvoice"}}),...dataStore.createdDocuments]
let items = [...dataStore.incomingInvoices.map(i => {return {...i, type: "incomingInvoice"}}),...dataStore.createddocuments]
console.log(dataStore.createdDocuments)
console.log(dataStore.createddocuments)
if(showDrafts.value === true) {
items = items.filter(i => i.state === "Entwurf")

View File

@@ -19,11 +19,10 @@ let currentItem = ref(null)
//Working
const mode = ref(route.params.mode || "show")
const itemInfo = ref({
id: 0,
name: "",
licensePlate: "",
type: "",
driver: ""
driver: null
})
const tabItems = [{

View File

@@ -80,7 +80,7 @@ export const useDataStore = defineStore('data', () => {
label: "Benutzer",
labelSingle: "Benutzer"
},
createdDocuments: {
createddocuments: {
label: "Dokumente",
labelSingle: "Dokument"
},
@@ -154,7 +154,7 @@ export const useDataStore = defineStore('data', () => {
const inventoryItems = ref([])
const chats = ref([])
const messages = ref([])
const createdDocuments = ref([])
const createddocuments = ref([])
async function initializeData () {
await fetchProfiles()
@@ -176,7 +176,7 @@ export const useDataStore = defineStore('data', () => {
async function fetchData () {
await fetchProfiles()
fetchDocuments()
await fetchDocuments()
await fetchOwnTenant()
await fetchEvents()
await fetchTasks()
@@ -189,7 +189,6 @@ export const useDataStore = defineStore('data', () => {
await fetchFormSubmits()
await fetchProducts()
await fetchUnits()
//await fetchDocuments()
await fetchMovements()
await fetchSpaces()
await fetchVehicles()
@@ -245,7 +244,7 @@ export const useDataStore = defineStore('data', () => {
inventoryItems.value = []
chats.value = []
messages.value = []
createdDocuments.value = []
createddocuments.value = []
}
//Realtime Update
@@ -278,7 +277,7 @@ export const useDataStore = defineStore('data', () => {
const numberRange = useNumberRange(dataType)
data[dataTypes[dataType].numberRangeHolder] = await numberRange.useNextNumber()
} else if(dataType === "createdDocuments") {
} else if(dataType === "createddocuments") {
console.log(data.type)
const numberRange = useNumberRange(data.type)
data.documentNumber = await numberRange.useNextNumber()
@@ -296,6 +295,7 @@ export const useDataStore = defineStore('data', () => {
await eval( dataType + '.value.push(' + JSON.stringify(...supabaseData) + ')')
toast.add({title: `${dataTypes[dataType].labelSingle} hinzugefügt`})
if(dataTypes[dataType].redirect) await router.push(`/${dataType}/show/${supabaseData[0].id}`)
return supabaseData
}
}
@@ -312,8 +312,72 @@ export const useDataStore = defineStore('data', () => {
await eval(dataType + '.value[' + dataType + '.value.findIndex(i => i.id === ' + JSON.stringify(data.id) + ')] = ' + JSON.stringify(supabaseData[0]))
toast.add({title: `${dataTypes[dataType].labelSingle} gespeichert`})
if(dataTypes[dataType].redirect) await router.push(`/${dataType}/show/${supabaseData[0].id}`)
return supabaseData
}
}
const uploadFiles = async (formData, files, upsert) => {
let documentsToInsert = []
const uploadSingleFile = async (file) => {
const {data, error} = await supabase
.storage
.from("files")
.upload(`${currentTenant.value}/${file.name}`, file, {upsert})
if (error) {
console.log(error)
console.log(error.statusCode)
if(error.statusCode === '400') {
console.log("is 400")
toast.add({title: "Hochladen fehlgeschlagen", description: "Die Datei enthält ungültige Zeichen", icon: "i-heroicons-x-circle", color: "rose", timeout: 10000})
} else if(error.statusCode === '409') {
console.log("is 409")
toast.add({title: "Hochladen fehlgeschlagen", description: "Es existiert bereits eine Datei mit diesem Namen", icon: "i-heroicons-x-circle", color: "rose", timeout: 10000})
} else {
toast.add({title: "Hochladen fehlgeschlagen", icon: "i-heroicons-x-circle", color: "rose", timeout: 10000})
}
} else if (data) {
const returnPath = data.path
documentsToInsert.push({...formData, path: returnPath})
}
}
//uploadInProgress.value = true
if(files.length === 1) {
await uploadSingleFile(files[0])
} else if( files.length > 1) {
for(let i = 0; i < files.length; i++){
uploadSingleFile(files[i])
}
}
const {data, error} = await supabase
.from("documents")
.insert(documentsToInsert)
.select()
if(error) console.log(error)
else {
console.log(data)
fetchDocuments()
//documents.value.push(...data)
}
//uploadModalOpen.value = false;
//uploadInProgress.value = false;
}
async function fetchOwnTenant () {
@@ -409,21 +473,28 @@ export const useDataStore = defineStore('data', () => {
messages.value = (await supabase.from("messages").select().eq('tenant', currentTenant.value).order('created_at', {ascending:true})).data
}
async function fetchCreatedDocuments() {
createdDocuments.value = (await supabase.from("createddocuments").select().eq('tenant', currentTenant.value).order('created_at', {ascending:true})).data
createddocuments.value = (await supabase.from("createddocuments").select().eq('tenant', currentTenant.value).order('created_at', {ascending:true})).data
}
async function fetchDocuments () {
let tempDocuments = (await supabase.from("documents").select().eq('tenant', currentTenant.value)).data
if(tempDocuments.length > 0) {
for(const [index,doc] of tempDocuments.entries()){
// @ts-ignore
tempDocuments[index].url = (await supabase.storage.from('files').createSignedUrl(doc.path, 60 * 60)).data.signedUrl
let paths = []
tempDocuments.forEach(doc => {
paths.push(doc.path)
})
const {data,error} = await supabase.storage.from('files').createSignedUrls(paths,3600)
tempDocuments = tempDocuments.map((doc,index) => {
return {
...doc,
url: data[index].signedUrl
}
}
})
documents.value = tempDocuments
}
async function addHistoryItem(text, user, elementId, resourceType) {
@@ -473,7 +544,11 @@ export const useDataStore = defineStore('data', () => {
})
const getDocumentsByProjectId = computed(() => (projectId) => {
return documents.value.filter(item => item.project === projectId)
return documents.value.filter(item => item.project === projectId && !item.tags.includes("Archiviert"))
})
const getDocumentsByPlantId = computed(() => (itemId) => {
return documents.value.filter(item => item.plant === itemId && !item.tags.includes("Archiviert"))
})
const getEventsByProjectId = computed(() => (projectId) => {
@@ -730,7 +805,7 @@ export const useDataStore = defineStore('data', () => {
})
const getCreatedDocumentById = computed(() => (documentId) => {
return createdDocuments.value.find(item => item.id === documentId)
return createddocuments.value.find(item => item.id === documentId)
})
const getProjectById = computed(() => (itemId) => {
@@ -760,6 +835,8 @@ export const useDataStore = defineStore('data', () => {
ownTenant,
initializeData,
changeTenant,
uploadFiles,
//Data
profiles,
@@ -792,7 +869,7 @@ export const useDataStore = defineStore('data', () => {
inventoryItems,
chats,
messages,
createdDocuments,
createddocuments,
documentTypesForCreation,
//Functions
createNewItem,
@@ -836,6 +913,7 @@ export const useDataStore = defineStore('data', () => {
getContactsByCustomerId,
getContactsByVendorId,
getDocumentsByProjectId,
getDocumentsByPlantId,
getEventsByProjectId,
getTimesByProjectId,
getTasksByProjectId,