Added Phases to Projects

This commit is contained in:
2024-02-15 22:49:09 +01:00
parent 2fc45b3ea0
commit 1a0b7288df
37 changed files with 2342 additions and 1483 deletions

View File

@@ -12,4 +12,4 @@ ENV NUXT_PORT=3000
EXPOSE 3000 EXPOSE 3000
ENTRYPOINT ["node", ".output/server/index.mjs"] ENTRYPOINT ["node", ".output/server/index.js"]

View File

@@ -12,7 +12,6 @@ const viewport = useViewport()
console.log('Breakpoint updated:', oldBreakpoint, '->', newBreakpoint) console.log('Breakpoint updated:', oldBreakpoint, '->', newBreakpoint)
})*/ })*/
dataStore.initializeData()
useHead({ useHead({
meta: [ meta: [
@@ -52,10 +51,7 @@ useSeoMeta({
width: auto; width: auto;
} }
#contentContainer {
width: 95vw;
height: 85vh;
}
.documentList { .documentList {
display: flex; display: flex;
@@ -103,4 +99,18 @@ useSeoMeta({
a:hover { a:hover {
color: #69c350 color: #69c350
} }
.table > div {
width: 78vw;
height: 90vh;
overflow: scroll !important;
-ms-overflow-style: none; /*!* IE and Edge *!*/
scrollbar-width: none; /*!* Firefox *!*/
}
.table > div::-webkit-scrollbar {
display: none;
}
</style> </style>

View File

@@ -99,7 +99,16 @@ const archiveDocument = () => {
:data="documentData.url" :data="documentData.url"
class="previewEmbed" class="previewEmbed"
type="application/pdf" type="application/pdf"
v-if="!documentData.tags.includes('Bild')"
/> />
<img
v-else
alt=""
:src="documentData.url"
/>
<UButton <UButton
@click="openDocument" @click="openDocument"
class="mt-3" class="mt-3"
@@ -141,6 +150,13 @@ const archiveDocument = () => {
class="h-full w-full" class="h-full w-full"
:data="documentData.url" :data="documentData.url"
type="application/pdf" type="application/pdf"
v-if="!documentData.tags.includes('Bild')"
/>
<img
class="h-full w-full"
:src="documentData.url"
alt=""
v-else
/> />
</UContainer> </UContainer>
@@ -159,7 +175,11 @@ const archiveDocument = () => {
Eingangsrechnung erstellen Eingangsrechnung erstellen
</UButton> </UButton>
</UButtonGroup> </UButtonGroup>
<br>
<a
:href="documentData.url"
target="_blank"
>In neuen Tab anzeigen</a>
<UFormGroup <UFormGroup
label="Tags ändern:" label="Tags ändern:"

View File

@@ -32,7 +32,7 @@ const uploadFiles = async () => {
let fileData = fileUploadFormData.value let fileData = fileUploadFormData.value
fileData[type] = elementId fileData[type] = elementId
await dataStore.uploadFiles(fileData, document.getElementById("fileUploadInput").files) await dataStore.uploadFiles(fileData, document.getElementById("fileUploadInput").files,true)
uploadModalOpen.value = false; uploadModalOpen.value = false;
uploadInProgress.value = false; uploadInProgress.value = false;
@@ -40,7 +40,7 @@ const uploadFiles = async () => {
</script> </script>
<template> <template>
<UModal <USlideover
v-model="uploadModalOpen" v-model="uploadModalOpen"
> >
<UCard :ui="{ ring: '', divide: 'divide-y divide-gray-100 dark:divide-gray-800' }"> <UCard :ui="{ ring: '', divide: 'divide-y divide-gray-100 dark:divide-gray-800' }">
@@ -66,6 +66,7 @@ const uploadFiles = async () => {
<UInput <UInput
type="file" type="file"
id="fileUploadInput" id="fileUploadInput"
multiple
/> />
</UFormGroup> </UFormGroup>
<UFormGroup <UFormGroup
@@ -78,7 +79,12 @@ const uploadFiles = async () => {
searchable-placeholder="Suchen..." searchable-placeholder="Suchen..."
:options="tags" :options="tags"
v-model="fileUploadFormData.tags" v-model="fileUploadFormData.tags"
/> >
<template #label>
<span v-if="fileUploadFormData.tags.length > 0">{{fileUploadFormData.tags.join(", ")}}</span>
<span v-else>Keine Tags ausgewählt</span>
</template>
</USelectMenu>
</UFormGroup> </UFormGroup>
<template #footer> <template #footer>
@@ -89,10 +95,11 @@ const uploadFiles = async () => {
</template> </template>
</UCard> </UCard>
</UModal> </USlideover>
<UButton <UButton
@click="openModal" @click="openModal"
icon="i-heroicons-arrow-up-tray"
> >
Hochladen Hochladen
</UButton> </UButton>

View File

@@ -10,6 +10,7 @@ const props = defineProps({
type: String type: String
} }
}) })
const { metaSymbol } = useShortcuts()
const dataStore = useDataStore() const dataStore = useDataStore()
const user = useSupabaseUser() const user = useSupabaseUser()
const supabase = useSupabaseClient() const supabase = useSupabaseClient()
@@ -34,6 +35,14 @@ const historyItems = computed(() => {
items = dataStore.historyItems.filter(i => i.incomingInvoice === elementId) items = dataStore.historyItems.filter(i => i.incomingInvoice === elementId)
} else if(type === "document") { } else if(type === "document") {
items = dataStore.historyItems.filter(i => i.document === elementId) items = dataStore.historyItems.filter(i => i.document === elementId)
} else if(type === "contact") {
items = dataStore.historyItems.filter(i => i.contact === elementId)
} else if(type === "contract") {
items = dataStore.historyItems.filter(i => i.contract === elementId)
} else if(type === "inventoryitem") {
items = dataStore.historyItems.filter(i => i.inventoryitem === elementId)
} else if(type === "product") {
items = dataStore.historyItems.filter(i => i.product === elementId)
} }
return items return items
@@ -59,6 +68,14 @@ const addHistoryItem = async () => {
addHistoryItemData.value.incomingInvoice = elementId addHistoryItemData.value.incomingInvoice = elementId
} else if(type === "document") { } else if(type === "document") {
addHistoryItemData.value.document = elementId addHistoryItemData.value.document = elementId
} else if(type === "contact") {
addHistoryItemData.value.contact = elementId
} else if(type === "contract") {
addHistoryItemData.value.contract = elementId
} else if(type === "inventoryitem") {
addHistoryItemData.value.inventoryitem = elementId
} else if(type === "product") {
addHistoryItemData.value.product = elementId
} }
@@ -102,56 +119,55 @@ const renderText = (text) => {
> >
<UTextarea <UTextarea
v-model="addHistoryItemData.text" v-model="addHistoryItemData.text"
@keyup.meta.enter="addHistoryItem"
/> />
<!-- <template #help>
<UKbd>{{metaSymbol}}</UKbd> <UKbd>Enter</UKbd> Speichern
</template>-->
</UFormGroup> </UFormGroup>
<template #footer> <template #footer>
<UButton @click="addHistoryItem">Hinzufügen</UButton> <UButton @click="addHistoryItem">Speichern</UButton>
</template> </template>
</UCard> </UCard>
</UModal> </UModal>
<UCard class="mt-5"> <Toolbar>
<template #header> <UButton
<InputGroup> @click="showAddHistoryItemModal = true"
<UButton
@click="showAddHistoryItemModal = true"
>
+ Eintrag
</UButton>
</InputGroup>
</template>
<div
v-if="historyItems.length > 0"
v-for="(item,index) in historyItems.slice().reverse()
"
> >
<UDivider + Eintrag
class="my-3" </UButton>
v-if="index !== 0" </Toolbar>
<div
v-if="historyItems.length > 0"
v-for="(item,index) in historyItems.slice().reverse()"
>
<UDivider
class="my-3"
v-if="index !== 0"
/>
<div class="flex items-center gap-3">
<UAvatar
v-if="!item.user"
:src="colorMode.value === 'light' ? '/spaces_hell.svg' : '/spaces.svg' "
/> />
<div class="flex items-center gap-3"> <UAvatar
<UAvatar :alt="dataStore.profiles.find(profile => profile.id === item.user).fullName"
v-if="!item.user" v-else
:src="colorMode.value === 'light' ? '/spaces_hell.svg' : '/spaces.svg' " />
/> <div>
<UAvatar <h3 v-if="item.user">{{dataStore.getProfileById(item.user) ? dataStore.getProfileById(item.user).fullName : ""}}</h3>
:alt="dataStore.profiles.find(profile => profile.id === item.user).fullName" <h3 v-else>Spaces Bot</h3>
v-else <span v-html="renderText(item.text)"/><br>
/> <span class="text-gray-500">{{dayjs(item.created_at).format("DD.MM.YY HH:mm")}}</span>
<div>
<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>
</div>
</div> </div>
</div> </div>
</UCard> </div>
</template> </template>
<style scoped> <style scoped>

View File

@@ -0,0 +1,14 @@
<script setup lang="ts">
</script>
<template>
<InputGroup>
<slot/>
</InputGroup>
<UDivider class="my-3"/>
</template>
<style scoped>
</style>

View File

@@ -6,13 +6,15 @@ const colorMode = useColorMode()
const userProfile = dataStore.getOwnProfile const userProfile = dataStore.getOwnProfile
const supabase = useSupabaseClient() const supabase = useSupabaseClient()
const router = useRouter() const router = useRouter()
const route = useRoute()
dataStore.initializeData((await supabase.auth.getUser()).data.user.id)
const isLight = computed({ const isLight = computed({
get () { get() {
return colorMode.value !== 'dark' return colorMode.value !== 'dark'
}, },
set () { set() {
colorMode.preference = colorMode.value === 'dark' ? 'light' : 'dark' colorMode.preference = colorMode.value === 'dark' ? 'light' : 'dark'
} }
}) })
@@ -52,12 +54,12 @@ const navLinks = [
label: "Belege", label: "Belege",
to: "/receipts", to: "/receipts",
icon: "i-heroicons-document-text" icon: "i-heroicons-document-text"
},/* },
{ {
label: "Bank", label: "Bank",
to: "/banking", to: "/banking",
icon: "i-heroicons-currency-euro" icon: "i-heroicons-currency-euro"
},*/ },
] ]
}, },
{ {
@@ -105,6 +107,11 @@ const navLinks = [
to: "/documents", to: "/documents",
icon: "i-heroicons-document" icon: "i-heroicons-document"
}, },
{
label: "E-Mail",
to: "/email",
icon: "i-heroicons-envelope"
},
] ]
},/* },/*
{ {
@@ -122,7 +129,7 @@ const navLinks = [
icon: "i-heroicons-clock" icon: "i-heroicons-clock"
}, },
{ {
label: "Stechuhr", label: "Anwesenheiten",
to: "/workingtimes", to: "/workingtimes",
icon: "i-heroicons-clock" icon: "i-heroicons-clock"
}, },
@@ -156,6 +163,10 @@ const navLinks = [
label: "Fahrzeuge", label: "Fahrzeuge",
to: "/vehicles", to: "/vehicles",
icon: "i-heroicons-truck" icon: "i-heroicons-truck"
}, {
label: "Inventar",
to: "/inventoryitems",
icon: "i-heroicons-puzzle-piece"
}, },
] ]
}, },
@@ -173,6 +184,11 @@ const userMenuItems = ref([
icon: "i-heroicons-cog-8-tooth", icon: "i-heroicons-cog-8-tooth",
to: "/settings/numberRanges" to: "/settings/numberRanges"
}, },
{
label: "Einstellungen",
icon: "i-heroicons-cog-8-tooth",
to: "/settings"
},
{ {
label: 'Benutzer', label: 'Benutzer',
icon: 'i-heroicons-user-group', icon: 'i-heroicons-user-group',
@@ -180,127 +196,255 @@ const userMenuItems = ref([
} }
]) ])
const links = [[{
label: 'Profil',
avatar: {
alt: userProfile ? userProfile.fullName : "XY"
}
},{
label: "Dashboard",
to: "/",
icon: "i-heroicons-home"
}], [{
label: "Aufgaben",
to: "/tasks",
icon: "i-heroicons-rectangle-stack"
},
{
label: "Plantafel",
to: "/calendar/timeline",
icon: "i-heroicons-calendar-days"
},
{
label: "Kalender",
to: "/calendar/grid",
icon: "i-heroicons-calendar-days"
},
{
label: "Dokumente",
to: "/documents",
icon: "i-heroicons-document"
},
{
label: "E-Mail",
to: "/email",
icon: "i-heroicons-envelope"
}],[{
label: "Kunden",
to: "/customers",
icon: "i-heroicons-user-group"
},
{
label: "Lieferanten",
to: "/vendors",
icon: "i-heroicons-truck"
},
{
label: "Ansprechpartner",
to: "/contacts",
icon: "i-heroicons-user-group"
}], [{
label: "Belege",
to: "/receipts",
icon: "i-heroicons-document-text"
},
{
label: "Bank",
to: "/banking",
icon: "i-heroicons-currency-euro"
}], [{
label: "Projekte",
to: "/projects",
icon: "i-heroicons-clipboard-document-check"
},
{
label: "Verträge",
to: "/contracts",
icon: "i-heroicons-clipboard-document"
},
{
label: "Objekte",
to: "/plants",
icon: "i-heroicons-clipboard-document"
}],[{
label: "Zeiterfassung",
to: "/employees/timetracking",
icon: "i-heroicons-clock"
},
{
label: "Anwesenheiten",
to: "/workingtimes",
icon: "i-heroicons-clock"
},
{
label: "Abwesenheiten",
to: "/absenceRequests",
icon: "i-heroicons-document-text"
}],[{
label: "Steuerung",
to: "/inventory",
icon: "i-heroicons-square-3-stack-3d"
},
{
label: "Artikelstamm",
to: "/products",
icon: "i-heroicons-puzzle-piece"
},
{
label: "Lagerplätze",
to: "/spaces",
icon: "i-heroicons-square-3-stack-3d"
},
{
label: "Fahrzeuge",
to: "/vehicles",
icon: "i-heroicons-truck"
}, {
label: "Inventar",
to: "/inventoryitems",
icon: "i-heroicons-puzzle-piece"
},]
]
</script> </script>
<template> <template>
<div v-if="dataStore.loaded"> <div v-if="dataStore.loaded" class="flex justify-center flex-row">
<UHeader :links="navLinks" :to="null"> <!-- <UHeader :links="navLinks" :to="null">
<template #logo> <template #logo>
<div id="logo"> <div id="logo">
<img <img
:src="!isLight ? '/spaces.svg' : '/spaces_hell.svg'" :src="!isLight ? '/spaces.svg' : '/spaces_hell.svg'"
alt="Logo" alt="Logo"
/> />
</div> </div>
</template> </template>
<template #panel> <template #panel>
<UNavigationTree :links="navLinks"/> <UNavigationTree :links="navLinks"/>
</template> </template>
<template #right> <template #right>
<GlobalSearch/> <GlobalSearch/>
<UButton <UButton
@click="showUserMenu = true" @click="showUserMenu = true"
variant="ghost" variant="ghost"
color="gray" color="gray"
> >
<UAvatar <UAvatar
:alt="userProfile ? userProfile.firstName + ' ' + userProfile.lastName : '' " :alt="userProfile ? userProfile.firstName + ' ' + userProfile.lastName : '' "
icon="i-heroicons-user-20-solid" icon="i-heroicons-user-20-solid"
:chip-color="dataStore.notifications.filter(item => !item.read).length > 0 ? 'primary' : null" :chip-color="dataStore.notifications.filter(item => !item.read).length > 0 ? 'primary' : null"
/> />
</UButton> </UButton>
<USlideover <USlideover
v-model="showUserMenu" v-model="showUserMenu"
> >
<UCard <UCard
class="h-full" class="h-full"
> >
<UDivider <div v-if="dataStore.getOwnProfile.tenants.length > 1">
class="my-3" <UDivider
label="Tenant" class="my-3"
/> label="Tenant"
/>
<USelectMenu <USelectMenu
:options="dataStore.getOwnProfile.tenants" :options="dataStore.getOwnProfile.tenants"
option-attribute="name" option-attribute="name"
value-attribute="id" value-attribute="id"
v-model="dataStore.currentTenant" v-model="dataStore.currentTenant"
@change="dataStore.changeTenant()" @change="dataStore.changeTenant()"
/> />
</div>
<UDivider
class="my-3"
label="Menü"
/>
<UVerticalNavigation
:links="userMenuItems"
/>
<!-- <UDivider
class="my-3"
label="Benachrichtigungen"
/>
<UAlert
class="mb-3"
v-for="(notification) in dataStore.notifications"
:color="!notification.read ? 'primary' : 'white'"
:variant="!notification.read ? 'outline' : 'soft'"
:description="notification.text"
:title="notification.title"
:close-button="!notification.read ? { icon: 'i-heroicons-x-mark-20-solid', color: 'gray', variant: 'link', padded: false } : null"
@close="async () => {
const {error} = await supabase.from('notifications').update({read:true}).eq('id', notification.id)
if(error) console.log(error)
dataStore.fetchNotifications()
}"
/>-->
<UDivider
<template #footer> class="my-3"
<InputGroup> label="Menü"
<UButton
:icon="!isLight ? 'i-heroicons-moon-20-solid' : 'i-heroicons-sun-20-solid'"
color="white"
variant="outline"
aria-label="Theme"
@click="isLight = !isLight"
/> />
<UButton
color="rose"
variant="outline"
@click="async () => {
showUserMenu = false
await supabase.auth.signOut()
await dataStore.clearStore()
await router.push('/login')
}" <UVerticalNavigation
> :links="userMenuItems"
Ausloggen />
</UButton>
</InputGroup>
</template> &lt;!&ndash; <UDivider
class="my-3"
label="Benachrichtigungen"
/>
</UCard> <UAlert
</USlideover> class="mb-3"
v-for="(notification) in dataStore.notifications"
:color="!notification.read ? 'primary' : 'white'"
:variant="!notification.read ? 'outline' : 'soft'"
:description="notification.text"
:title="notification.title"
:close-button="!notification.read ? { icon: 'i-heroicons-x-mark-20-solid', color: 'gray', variant: 'link', padded: false } : null"
@close="async () => {
const {error} = await supabase.from('notifications').update({read:true}).eq('id', notification.id)
if(error) console.log(error)
dataStore.fetchNotifications()
}"
/>&ndash;&gt;
<template #footer>
<InputGroup>
<UButton
:icon="!isLight ? 'i-heroicons-moon-20-solid' : 'i-heroicons-sun-20-solid'"
color="white"
variant="outline"
aria-label="Theme"
@click="isLight = !isLight"
/>
<UButton
color="rose"
variant="outline"
@click="async () => {
showUserMenu = false
await supabase.auth.signOut()
await dataStore.clearStore()
await router.push('/login')
}"
>
Ausloggen
</UButton>
</InputGroup>
</template>
</UCard>
</USlideover>
</template>
</UHeader>
<UDivider />-->
<div class="ml-2 mt-3" id="menuLeft">
<UVerticalNavigation
:links="links"
>
<template #avatar="{link}">
<UAvatar
v-if="link.avatar"
v-bind="link.avatar"
/>
</template>
</UVerticalNavigation>
</div>
</template>
</UHeader>
<UDivider />
<div class="m-3" id="contentContainer"> <div class="m-3" id="contentContainer">
<slot/> <slot id="content"/>
</div> </div>
</div> </div>
<div <div
@@ -317,5 +461,28 @@ const userMenuItems = ref([
</template> </template>
<style scoped> <style scoped>
#menuLeft {
height: 95vh;
width: 20vw;
overflow-y: scroll;
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
}
#menuLeft::-webkit-scrollbar {
display: none;
}
#contentContainer {
width: 77vw;
height: 95vh;
}
/* -ms-overflow-style: none; !* IE and Edge *!
scrollbar-width: none; !* Firefox *!
}
#contentContainer::-webkit-scrollbar {
display: none;
}*/
</style> </style>

View File

@@ -43,7 +43,7 @@
"@vicons/ionicons5": "^0.12.0", "@vicons/ionicons5": "^0.12.0",
"@vuepic/vue-datepicker": "^7.4.0", "@vuepic/vue-datepicker": "^7.4.0",
"@zip.js/zip.js": "^2.7.32", "@zip.js/zip.js": "^2.7.32",
"axios": "^1.6.2", "axios": "^1.6.7",
"base64-arraybuffer": "^1.0.2", "base64-arraybuffer": "^1.0.2",
"buffer": "^6.0.3", "buffer": "^6.0.3",
"client-oauth2": "^4.3.3", "client-oauth2": "^4.3.3",

View File

@@ -120,14 +120,6 @@ setupPage()
> >
Bearbeiten Bearbeiten
</UButton> </UButton>
<UButton
color="red"
class="ml-2"
disabled
>
Archivieren
</UButton>
<!-- TODO: Kunde archivieren -->
</template> </template>

View File

@@ -88,6 +88,7 @@ const calendarOptionsGrid = reactive({
nowIndicator: true, nowIndicator: true,
height: "80vh", height: "80vh",
selectable: true, selectable: true,
weekNumbers: true,
select: function(info) { select: function(info) {
console.log(info) console.log(info)
/*newEventData.value.resourceId = info.resource.id /*newEventData.value.resourceId = info.resource.id

View File

@@ -1,4 +1,6 @@
<script setup> <script setup>
import HistoryDisplay from "~/components/HistoryDisplay.vue";
definePageMeta({ definePageMeta({
middleware: "auth" middleware: "auth"
}) })
@@ -12,7 +14,7 @@ const id = ref(route.params.id ? route.params.id : null )
//Store //Store
const dataStore = useDataStore() const dataStore = useDataStore()
let currentContact = null let currentItem = null
@@ -25,10 +27,10 @@ const itemInfo = ref({
//Functions //Functions
const setupPage = () => { const setupPage = () => {
if(mode.value === "show" || mode.value === "edit"){ if(mode.value === "show" || mode.value === "edit"){
currentContact = dataStore.getContactById(Number(useRoute().params.id)) currentItem = dataStore.getContactById(Number(useRoute().params.id))
} }
if(mode.value === "edit") itemInfo.value = currentContact if(mode.value === "edit") itemInfo.value = currentItem
if(mode.value === "create") { if(mode.value === "create") {
let query = route.query let query = route.query
@@ -41,213 +43,199 @@ const setupPage = () => {
} }
const editCustomer = async () => { const editCustomer = async () => {
router.push(`/contacts/edit/${currentContact.id}`) router.push(`/contacts/edit/${currentItem.id}`)
setupPage() setupPage()
} }
const cancelEditorCreate = () => { const cancelEditorCreate = () => {
mode.value = "show" if(currentItem.value) {
itemInfo.value = { router.push(`/contacts/show/${currentItem.value.id}`)
id: 0, } else {
name: "", router.push(`/contacts`)
} }
} }
setupPage() setupPage()
</script> </script>
<template> <template>
<div> <h1
<UCard v-if="currentContact && mode == 'show'" > class="mb-3 font-bold text-2xl truncate"
<template #header> v-if="currentItem"
<UBadge >Ansprechpartner: {{currentItem.fullName}}</h1>
v-if="currentContact.active" <UTabs
> :items="[{label: 'Informationen'}, {label: 'Logbuch'}]"
Kontakt aktiv v-if="currentItem && mode == 'show'"
</UBadge> >
<UBadge <template #item="{item}">
v-else <UCard class="mt-5">
color="red" <div v-if="item.label === 'Informationen'">
> <Toolbar>
Kontakt inaktiv <UButton
</UBadge> v-if="mode == 'show' && currentItem.id"
{{currentContact.fullName}} @click="editCustomer"
</template> >
Bearbeiten
</UButton>
</Toolbar>
<InputGroup class="mb-3"> <UBadge
<UButton v-if="currentItem.active"
v-if="currentContact.customer" >
:to="`/customers/show/${currentContact.customer}`" Kontakt aktiv
> </UBadge>
Zum Kunden <UBadge
</UButton> v-else
<UButton color="red"
v-if="currentContact.vendor" >
:to="`/vendors/show/${currentContact.vendor}`" Kontakt inaktiv
> </UBadge>
Zum Lieferanten
</UButton>
</InputGroup>
<span v-if="currentContact.customer">Kunde: {{dataStore.customers.find(customer => customer.id === currentContact.customer) ? dataStore.customers.find(customer => customer.id === currentContact.customer).name : "" }}</span><br> <div class="text-wrap mt-3">
<span v-if="currentContact.vendor">Lieferant: {{dataStore.vendors.find(vendor => vendor.id === currentContact.vendor) ? dataStore.vendors.find(vendor => vendor.id === currentContact.vendor).name : ""}}</span><br> <p v-if="currentItem.customer">Kunde: <nuxt-link :to="`/customers/show/${currentItem.customer}`">{{dataStore.customers.find(customer => customer.id === currentItem.customer) ? dataStore.customers.find(customer => customer.id === currentItem.customer).name : "" }}</nuxt-link></p>
<p v-if="currentItem.vendor">Lieferant: <nuxt-link :to="`/vendors/show/${currentItem.vendor}`">{{dataStore.vendors.find(vendor => vendor.id === currentItem.vendor) ? dataStore.vendors.find(vendor => vendor.id === currentItem.vendor).name : ""}}</nuxt-link></p>
<span>E-Mail: {{currentContact.email}}</span><br>
<span>Mobil: {{currentContact.phoneMobile}}</span><br>
<span>Festnetz: {{currentContact.phoneHome}}</span><br>
<span>Rolle: {{currentContact.role}}</span>
<p>E-Mail: {{currentItem.email}}</p>
<DevOnly> <p>Mobil: {{currentItem.phoneMobile}}</p>
<UDivider <p>Festnetz: {{currentItem.phoneHome}}</p>
class="my-3" <p>Rolle: {{currentItem.role}}</p>
/> </div>
{{currentContact}}
</DevOnly>
<template #footer> </div>
<UButton <div v-else-if="item.label === 'Logbuch'">
v-if="mode == 'show' && currentContact.id" <HistoryDisplay
@click="editCustomer" type="contact"
> v-if="currentItem"
Bearbeiten :element-id="currentItem.id"
</UButton> />
<UButton </div>
color="red" </UCard>
class="ml-2" </template>
disabled </UTabs>
> <UCard v-else-if="mode == 'edit' || mode == 'create'" >
Archivieren <template #header>
</UButton> {{itemInfo.fullName}}
</template> </template>
<UFormGroup
label="Anrede:"
>
<UInput
v-model="itemInfo.salutation"
/>
</UFormGroup>
<UFormGroup
label="Vorname:"
>
<UInput
v-model="itemInfo.firstName"
/>
</UFormGroup>
<UFormGroup
label="Nachname:"
>
<UInput
v-model="itemInfo.lastName"
/>
</UFormGroup>
<UFormGroup
</UCard> label="Kunde:"
<UCard v-else-if="mode == 'edit' || mode == 'create'" > >
<template #header> <USelectMenu
{{itemInfo.fullName}}
</template>
<UFormGroup
label="Anrede:"
>
<UInput
v-model="itemInfo.salutation"
/>
</UFormGroup>
<UFormGroup
label="Vorname:"
>
<UInput
v-model="itemInfo.firstName"
/>
</UFormGroup>
<UFormGroup
label="Nachname:"
>
<UInput
v-model="itemInfo.lastName"
/>
</UFormGroup>
<UFormGroup
label="Kunde:"
>
<USelectMenu
v-model="itemInfo.customer" v-model="itemInfo.customer"
option-attribute="name" option-attribute="name"
value-attribute="id" value-attribute="id"
:options="dataStore.customers" :options="dataStore.customers"
searchable searchable
:search-attributes="['name']" :search-attributes="['name']"
>
<template #label>
{{dataStore.customers.find(customer => customer.id === itemInfo.customer) ? dataStore.customers.find(customer => customer.id === itemInfo.customer).name : "Kunde auswählen"}}
</template>
</USelectMenu>
</UFormGroup>
<UFormGroup
label="Lieferant:"
> >
<USelectMenu <template #label>
{{dataStore.customers.find(customer => customer.id === itemInfo.customer) ? dataStore.customers.find(customer => customer.id === itemInfo.customer).name : "Kunde auswählen"}}
</template>
</USelectMenu>
</UFormGroup>
<UFormGroup
label="Lieferant:"
>
<USelectMenu
v-model="itemInfo.vendor" v-model="itemInfo.vendor"
option-attribute="name" option-attribute="name"
value-attribute="id" value-attribute="id"
:options="dataStore.vendors" :options="dataStore.vendors"
searchable searchable
:search-attributes="['name']" :search-attributes="['name']"
> >
<template #label> <template #label>
{{dataStore.vendors.find(vendor => vendor.id === itemInfo.vendor) ? dataStore.vendors.find(vendor => vendor.id === itemInfo.vendor).name : "Lieferant auswählen"}} {{dataStore.vendors.find(vendor => vendor.id === itemInfo.vendor) ? dataStore.vendors.find(vendor => vendor.id === itemInfo.vendor).name : "Lieferant auswählen"}}
</template> </template>
</USelectMenu> </USelectMenu>
</UFormGroup> </UFormGroup>
<UFormGroup <UFormGroup
label="Kontakt aktiv:" label="Kontakt aktiv:"
> >
<UCheckbox <UCheckbox
v-model="itemInfo.active" v-model="itemInfo.active"
/> />
</UFormGroup> </UFormGroup>
<UFormGroup <UFormGroup
label="E-Mail:" label="E-Mail:"
> >
<UInput <UInput
v-model="itemInfo.email" v-model="itemInfo.email"
/> />
</UFormGroup> </UFormGroup>
<UFormGroup <UFormGroup
label="Mobil:" label="Mobil:"
> >
<UInput <UInput
v-model="itemInfo.phoneMobile" v-model="itemInfo.phoneMobile"
/> />
</UFormGroup> </UFormGroup>
<UFormGroup <UFormGroup
label="Festnetz:" label="Festnetz:"
> >
<UInput <UInput
v-model="itemInfo.phoneHome" v-model="itemInfo.phoneHome"
/> />
</UFormGroup> </UFormGroup>
<UFormGroup <UFormGroup
label="Rolle:" label="Rolle:"
> >
<UInput <UInput
v-model="itemInfo.role" v-model="itemInfo.role"
/> />
</UFormGroup> </UFormGroup>
<template #footer> <template #footer>
<UButton <UButton
v-if="mode == 'edit'" v-if="mode == 'edit'"
@click="dataStore.updateItem('contacts',{...itemInfo, fullName: `${itemInfo.firstName} ${itemInfo.lastName}`})" @click="dataStore.updateItem('contacts',{...itemInfo, fullName: `${itemInfo.firstName} ${itemInfo.lastName}`})"
> >
Speichern Speichern
</UButton> </UButton>
<UButton <UButton
v-else-if="mode == 'create'" v-else-if="mode == 'create'"
@click="dataStore.createNewItem('contacts',{...itemInfo, fullName: `${itemInfo.firstName} ${itemInfo.lastName}`})" @click="dataStore.createNewItem('contacts',{...itemInfo, fullName: `${itemInfo.firstName} ${itemInfo.lastName}`})"
> >
Erstellen Erstellen
</UButton> </UButton>
<UButton <UButton
@click="cancelEditorCreate" @click="cancelEditorCreate"
color="red" color="red"
class="ml-2" class="ml-2"
> >
Abbrechen Abbrechen
</UButton> </UButton>
</template> </template>
</UCard> </UCard>
</div>
</template> </template>
<style scoped> <style scoped>

View File

@@ -1,18 +1,15 @@
<template> <template>
<div id="main"> <Toolbar>
<!-- TODO: Kontakte erstellen und dem Kunden zuweisen --> <UButton @click="router.push(`/contacts/create/`)">+ Kontakt</UButton>
<InputGroup>
<UButton @click="router.push(`/contacts/create/`)">+ Kontakt</UButton>
<UInput
v-model="searchString"
placeholder="Suche..."
/>
</InputGroup>
<UInput
v-model="searchString"
placeholder="Suche..."
/>
</Toolbar>
<div class="table">
<UTable <UTable
:rows="filteredRows" :rows="filteredRows"
:columns="itemColumns" :columns="itemColumns"
@@ -26,8 +23,8 @@
{{dataStore.vendors.find(vendor => vendor.id === row.vendor) ? dataStore.vendors.find(vendor => vendor.id === row.vendor).name : ''}} {{dataStore.vendors.find(vendor => vendor.id === row.vendor) ? dataStore.vendors.find(vendor => vendor.id === row.vendor).name : ''}}
</template> </template>
</UTable> </UTable>
</div> </div>
</template> </template>
<script setup> <script setup>

View File

@@ -1,4 +1,6 @@
<script setup> <script setup>
import HistoryDisplay from "~/components/HistoryDisplay.vue";
definePageMeta({ definePageMeta({
middleware: "auth" middleware: "auth"
}) })
@@ -13,7 +15,7 @@ const id = ref(route.params.id ? route.params.id : null )
//Store //Store
const {customers, contracts } = storeToRefs(useDataStore()) const {customers, contracts } = storeToRefs(useDataStore())
let currentContract = null let currentItem = ref(null)
@@ -21,32 +23,37 @@ let currentContract = null
const mode = ref(route.params.mode || "show") const mode = ref(route.params.mode || "show")
const itemInfo = ref({ const itemInfo = ref({
name: "", name: "",
customer: 0, customer: null,
active: true active: true
}) })
//Functions //Functions
const setupPage = () => { const setupPage = () => {
if(mode.value === "show" || mode.value === "edit"){ if(mode.value === "show" || mode.value === "edit"){
currentContract = dataStore.getContractById(Number(useRoute().params.id)) currentItem.value = dataStore.getContractById(Number(useRoute().params.id))
} }
if(mode.value === "edit") itemInfo.value = currentContract if(mode.value === "edit") itemInfo.value = currentItem.value
if(mode.value === "create") {
let query = route.query
if(query.customer) itemInfo.value.customer = Number(query.customer)
}
} }
const editCustomer = async () => { const editCustomer = async () => {
router.push(`/contracts/edit/${currentContract.id}`) router.push(`/contracts/edit/${currentItem.value.id}`)
setupPage() setupPage()
} }
const cancelEditorCreate = () => { const cancelEditorCreate = () => {
mode.value = "show" if(currentItem.value) {
itemInfo.value = { router.push(`/contracts/show/${currentItem.value.id}`)
id: 0, } else {
name: "", router.push(`/contracts/`)
} }
} }
@@ -54,130 +61,136 @@ setupPage()
</script> </script>
<template> <template>
<div> <h1
<UCard v-if="currentContract && mode == 'show'" > class="text-center my-3 font-bold text-2xl"
<template #header> v-if="currentItem"
<UBadge >{{currentItem.name}}</h1>
v-if="currentContract.active" <UTabs
> v-if="currentItem && mode == 'show'"
Vertrag aktiv :items="[{label: 'Informationen'}, {label: 'Logbuch'}, {label: 'Dokumente'}]"
</UBadge> >
<UBadge <template #item="{item}">
v-else <UCard class="mt-5">
color="red" <div v-if="item.label === 'Informationen'">
> <Toolbar>
Vertrag gesperrt <UButton
</UBadge> v-if="mode == 'show' && currentItem.id"
{{currentContract.name}} @click="editCustomer"
</template> >
Bearbeiten
</UButton>
</Toolbar>
Kundennummer: {{dataStore.customers.find(customer => customer.id === currentContract.customer) ? dataStore.customers.find(customer => customer.id === currentContract.customer).name : ""}} <br> <UBadge
v-if="currentItem.active"
>
Vertrag aktiv
</UBadge>
<UBadge
v-else
color="red"
>
Vertrag gesperrt
</UBadge>
<UDivider <div class="text-wrap">
class="my-2" <p>Kundennummer: <nuxt-link :to="`/customers/show/${currentItem.customer}`">{{dataStore.getCustomerById(currentItem.customer).name}}</nuxt-link></p>
</div>
<UDivider
class="my-2"
/>
Beschreibung:<br>
{{currentItem.description}}<br>
</div>
<div v-else-if="item.label === 'Logbuch'">
<HistoryDisplay
type="contract"
v-if="currentItem"
:element-id="currentItem.id"
/>
</div>
<div v-else-if="item.label === 'Dokumente'">
<Toolbar>
<DocumentUpload
type="contract"
:element-id="currentItem.id"
/>
</Toolbar>
<DocumentList
:documents="dataStore.getDocumentsByContractId(currentItem.id)"
/>
</div>
</UCard>
</template>
</UTabs>
<UCard v-else-if="mode == 'edit' || mode == 'create'" >
<UFormGroup
label="Name:"
>
<UInput
v-model="itemInfo.name"
/> />
</UFormGroup>
Beschreibung:<br> <UFormGroup
{{currentContract.description}}<br> label="Kunde:"
>
<InputGroup> <USelectMenu
<DocumentUpload
type="contract"
:element-id="currentContract.id"
/>
</InputGroup>
<DocumentList
:documents="dataStore.getDocumentsByContractId(currentContract.id)"
/>
<DevOnly>
{{currentContract}}
</DevOnly>
<template #footer>
<UButton
v-if="mode == 'show' && currentContract.id"
@click="editCustomer"
>
Bearbeiten
</UButton>
</template>
</UCard>
<UCard v-else-if="mode == 'edit' || mode == 'create'" >
<template #header>
<UBadge>{{itemInfo.customerNumber}}</UBadge> {{itemInfo.name}}
</template>
<UFormGroup
label="Name:"
>
<UInput
v-model="itemInfo.name"
/>
</UFormGroup>
<UFormGroup
label="Kunde:"
>
<USelectMenu
v-model="itemInfo.customer" v-model="itemInfo.customer"
option-attribute="name" option-attribute="name"
value-attribute="id" value-attribute="id"
:options="customers" :options="customers"
searchable searchable
:search-attributes="['name']" :search-attributes="['name']"
>
<template #label>
{{dataStore.customers.find(customer => customer.id === itemInfo.customer) ? dataStore.customers.find(customer => customer.id === itemInfo.customer).name : itemInfo.customer}}
</template>
</USelectMenu>
</UFormGroup>
<UFormGroup
label="Vertrag aktiv:"
> >
<UCheckbox <template #label>
v-model="itemInfo.active" {{dataStore.getCustomerById(itemInfo.customer) ? dataStore.getCustomerById(itemInfo.customer).name : "Kein Kunde ausgewählt" }}
/> </template>
</UFormGroup> </USelectMenu>
<UFormGroup </UFormGroup>
label="Beschreibung:"
<UFormGroup
label="Vertrag aktiv:"
>
<UCheckbox
v-model="itemInfo.active"
/>
</UFormGroup>
<UFormGroup
label="Beschreibung:"
>
<UTextarea
v-model="itemInfo.description"
/>
</UFormGroup>
<template #footer>
<UButton
v-if="mode === 'edit'"
@click="dataStore.updateItem('contracts',itemInfo)"
> >
<UTextarea Speichern
v-model="itemInfo.description" </UButton>
/> <UButton
</UFormGroup> v-else-if="mode === 'create'"
@click="dataStore.createNewItem('contracts',itemInfo)"
>
Erstellen
</UButton>
<UButton
@click="cancelEditorCreate"
color="red"
class="ml-2"
>
Abbrechen
</UButton>
</template>
</UCard>
<template #footer>
<UButton
v-if="mode == 'edit'"
@click="dataStore.updateItem('contracts',itemInfo)"
>
Speichern
</UButton>
<UButton
v-else-if="mode == 'create'"
@click="dataStore.createNewItem('contracts',itemInfo)"
>
Erstellen
</UButton>
<UButton
@click="cancelEditorCreate"
color="red"
class="ml-2"
>
Abbrechen
</UButton>
</template>
</UCard>
</div>
</template> </template>
<style scoped> <style scoped>

View File

@@ -42,117 +42,151 @@ const editCustomer = async () => {
} }
const cancelEditorCreate = () => { const cancelEditorCreate = () => {
mode.value = "show" if(currentItem.value) {
itemInfo.value = { router.push(`/customers/show/${currentItem.value.id}`)
id: 0, } else {
name: "", router.push(`/customers`)
infoData: {}
} }
} }
setupPage() setupPage()
</script> </script>
<template> <template>
<UCard v-if="currentItem && mode == 'show'" > <h1
<template #header> class="mb-3 font-bold text-3xl truncate"
<UBadge v-if="currentItem "
v-if="currentItem.active" >Kunde: {{currentItem.name}}</h1>
> <UTabs
Kunde aktiv v-if="currentItem && mode == 'show'"
</UBadge> :items="[{label: 'Informationen'}, {label: 'Logbuch'}, {label: 'Projekte'},{label: 'Objekte'},{label: 'Verträge'}, {label: 'Ansprechpartner'}]"
<UBadge >
v-else <template #item="{item}">
color="red" <UCard class="mt-5">
> <div v-if="item.label === 'Informationen'">
Kunde gesperrt <Toolbar>
</UBadge> <UButton
{{currentItem.name}} v-if="mode == 'show' && currentItem.id"
@click="editCustomer"
>
Bearbeiten
</UButton>
</Toolbar>
<UBadge
v-if="currentItem.active"
>
Kunde aktiv
</UBadge>
<UBadge
v-else
color="red"
>
Kunde gesperrt
</UBadge>
<div class="text-wrap">
<p>Kundennummer: {{currentItem.customerNumber}}</p>
<p v-if="currentItem.infoData.street">Straße + Hausnummer: {{currentItem.infoData.street}}<br></p>
<p v-if="currentItem.infoData.zip && currentItem.infoData.city">PLZ + Ort: {{currentItem.infoData.zip}} {{currentItem.infoData.city}}<br></p>
<p v-if="currentItem.infoData.tel">Telefon: {{currentItem.infoData.tel}}<br></p>
<p v-if="currentItem.infoData.email">E-Mail: {{currentItem.infoData.email}}<br></p>
<p v-if="currentItem.infoData.web">Web: {{currentItem.infoData.web}}<br></p>
<p v-if="currentItem.infoData.ustid">USt-Id: {{currentItem.infoData.ustid}}<br></p>
<p>Notizen: {{currentItem.notes}}</p>
</div>
</div>
<div v-else-if="item.label === 'Logbuch'">
<HistoryDisplay
type="customer"
v-if="currentItem"
:element-id="currentItem.id"
/>
</div>
<div v-else-if="item.label === 'Projekte'">
<Toolbar>
<UButton
@click="router.push(`/projects/create?customer=${currentItem.id}`)"
>
+ Projekt
</UButton>
</Toolbar>
<UTable
:rows="dataStore.getProjectsByCustomerId(currentItem.id)"
@select="(row) => router.push(`/projects/show/${row.id}`)"
:columns="[{label: 'Name', key: 'name'},{label: 'Phase', key: 'phase'}]"
:empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Keine zugehörigen Projekte' }"
>
</UTable>
</div>
<div v-else-if="item.label === 'Objekte'">
<Toolbar>
<UButton
@click="router.push(`/plants/create?customer=${currentItem.id}`)"
>
+ Objekt
</UButton>
</Toolbar>
<UTable
:rows="dataStore.getPlantsByCustomerId(currentItem.id)"
@select="(row) => router.push(`/plants/show/${row.id}`)"
:columns="[{label: 'Name', key: 'name'}]"
:empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Keine zugehörigen Objekte' }"
>
</UTable>
</div>
<div v-else-if="item.label === 'Verträge'">
<Toolbar>
<UButton
@click="router.push(`/contracts/create?customer=${currentItem.id}`)"
>
+ Objekt
</UButton>
</Toolbar>
<UTable
:rows="dataStore.getContractsByCustomerId(currentItem.id)"
@select="(row) => router.push(`/contracts/show/${row.id}`)"
:columns="[{label: 'Name', key: 'name'},{label: 'Aktiv', key: 'active'}]"
:empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Keine zugehörigen Verträge' }"
>
</UTable>
</div>
<div v-else-if="item.label === 'Ansprechpartner'">
<Toolbar>
<UButton
@click="router.push(`/contacts/create?customer=${currentItem.id}`)"
>
+ Ansprechpartner
</UButton>
</Toolbar>
<UTable
:rows="dataStore.getContactsByCustomerId(currentItem.id)"
@select="(row) => router.push(`/contacts/show/${row.id}`)"
:columns="[{label: 'Anrede', key: 'salutation'},{label: 'Name', key: 'fullName'},{label: 'Rolle', key: 'role'}]"
:empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Keine zugehörigen Ansprechpartner' }"
>
</UTable>
</div>
</UCard>
</template> </template>
</UTabs>
<InputGroup>
<UButton
@click="router.push(`/projects/create?customer=${currentItem.id}`)"
>
+ Projekt
</UButton>
<UButton
@click="router.push(`/contacts/create?customer=${currentItem.id}`)"
>
+ Ansprechpartner
</UButton>
</InputGroup>
Kundennummer: {{currentItem.customerNumber}} <br> <UCard v-else-if="mode === 'edit' || mode === 'create'" >
<UDivider
class="my-2"
/>
Informationen:<br>
<div v-if="currentItem.infoData">
<span v-if="currentItem.infoData.street">Straße + Hausnummer: {{currentItem.infoData.street}}<br></span>
<span v-if="currentItem.infoData.zip && currentItem.infoData.city">PLZ + Ort: {{currentItem.infoData.zip}} {{currentItem.infoData.city}}<br></span>
<span v-if="currentItem.infoData.tel">Telefon: {{currentItem.infoData.tel}}<br></span>
<span v-if="currentItem.infoData.email">E-Mail: {{currentItem.infoData.email}}<br></span>
<span v-if="currentItem.infoData.web">Web: {{currentItem.infoData.web}}<br></span>
<span v-if="currentItem.infoData.ustid">USt-Id: {{currentItem.infoData.ustid}}<br></span>
</div>
<UDivider
class="my-2"
/>
Notizen:<br>
{{currentItem.notes}}<br>
<UDivider
class="my-2"
/>
Kontakte: <br>
<ul>
<li
v-for="contact in dataStore.getContactsByCustomerId(currentItem.id)"
>
<router-link :to="'/contacts/show/' + contact.id">{{contact.salutation}} {{contact.fullName}} - {{contact.role}}</router-link>
</li>
</ul>
<template #footer>
<UButton
v-if="mode == 'show' && currentItem.id"
@click="editCustomer"
>
Bearbeiten
</UButton>
<UButton
color="red"
class="ml-2"
disabled
>
Archivieren
</UButton>
<!-- TODO: Kunde archivieren -->
</template>
</UCard>
<UCard v-else-if="mode == 'edit' || mode == 'create'" >
<template #header v-if="mode === 'edit'"> <template #header v-if="mode === 'edit'">
<UBadge>{{itemInfo.customerNumber}}</UBadge>{{itemInfo.name}} <UBadge>{{itemInfo.customerNumber}}</UBadge>{{itemInfo.name}}
</template> </template>
<UFormGroup <UFormGroup
label="Name:" label="Name:"
> >
@@ -262,11 +296,7 @@ setupPage()
</UCard> </UCard>
<HistoryDisplay
type="customer"
v-if="currentItem"
:element-id="currentItem.id"
/>
</template> </template>
<style scoped> <style scoped>

View File

@@ -1,18 +1,15 @@
<template> <template>
<div id="main">
<!-- TODO: Kontakte erstellen und dem Kunden zuweisen -->
<div class="flex items-center gap-1">
<UButton @click="router.push(`/customers/create/`)">+ Kunde</UButton>
<UInput
v-model="searchString"
placeholder="Suche..."
/>
</div>
<Toolbar>
<UButton @click="router.push(`/customers/create/`)">+ Kunde</UButton>
<UInput
v-model="searchString"
placeholder="Suche..."
/>
</Toolbar>
<div class="table">
<UTable <UTable
:rows="filteredRows" :rows="filteredRows"
:columns="customerColumns" :columns="customerColumns"
@@ -20,7 +17,6 @@
:empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Noch keine Einträge' }" :empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Noch keine Einträge' }"
/> />
</div> </div>
</template> </template>

View File

@@ -74,8 +74,11 @@ const downloadSelected = async () => {
// Map the response to an array of objects containing the file name and blob // Map the response to an array of objects containing the file name and blob
const downloadedFiles = response.map((result, index) => { const downloadedFiles = response.map((result, index) => {
if (result.status === "fulfilled") { if (result.status === "fulfilled") {
console.log(files[index].split("/")[files[index].split("/").length -1])
return { return {
name: files[index], name: files[index].split("/")[files[index].split("/").length -1],
blob: result.value.data, blob: result.value.data,
}; };
} }
@@ -109,7 +112,7 @@ const downloadSelected = async () => {
<template> <template>
<div> <div>
<InputGroup> <Toolbar>
<UButton @click="uploadModalOpen = true">Hochladen</UButton> <UButton @click="uploadModalOpen = true">Hochladen</UButton>
<UButton <UButton
@click="downloadSelected" @click="downloadSelected"
@@ -127,8 +130,8 @@ const downloadSelected = async () => {
</USelectMenu> </USelectMenu>
</InputGroup> </Toolbar>
<div > <div class="scrollList">
<USlideover <USlideover
v-model="uploadModalOpen" v-model="uploadModalOpen"
> >

316
spaces/pages/email.vue Normal file
View File

@@ -0,0 +1,316 @@
<script setup>
import axios from 'axios'
const dataStore = useDataStore()
const accounts = ref([])
//accounts.value = dataStore.emailAccounts.map(i => { return { label: i.emailAddress, emailEngingeId: i.emailEngineId }})
const mailboxes = ref({})
const messages = ref([])
const selectedMailbox = ref("INBOX")
const selectedAccount = ref(null)
const selectedMessage = ref(null)
const setup = async () => {
accounts.value = dataStore.emailAccounts.map((i,index) => {
let item = { label: i.emailAddress, emailEngineId: i.emailEngineId }
if(index === 0) {
item.defaultOpen = true
}
return item
})
for await (const account of accounts.value) {
console.log(account.emailEngineId)
const {data,error} = await axios.get(`http://157.90.231.142:3000/v1/account/${account.emailEngineId}/mailboxes`, {headers: { 'Authorization': 'Bearer dadb572465fba648590f31557f68028a750b47b278d87c1773e8fd09670eec59'}})
console.log(data)
console.log(error)
mailboxes.value[account.emailEngineId] = data.mailboxes
}
}
const selectMailbox = async (account, mailbox) => {
selectedMailbox.value = mailbox
const {data,error} = await axios.get(`http://157.90.231.142:3000/v1/account/${account}/messages?path=${ mailbox.path}`, {headers: { 'Authorization': 'Bearer dadb572465fba648590f31557f68028a750b47b278d87c1773e8fd09670eec59'}})
console.log(data)
console.log(error)
messages.value = data.messages
selectedAccount.value = account
}
const messageHTML = ref(null)
const messageText = ref(null)
const selectMessage = async (account, message) => {
console.log(message)
selectedMessage.value = message
const {data,error} = await axios.get(`http://157.90.231.142:3000/v1/account/${account}/text/${message.text.id}`, {headers: { 'Authorization': 'Bearer dadb572465fba648590f31557f68028a750b47b278d87c1773e8fd09670eec59'}})
messageHTML.value = data.html
messageText.value = data.plain
}
const addFlags = async (account, message, flags) => {
console.log(flags)
const {data,error} = await axios({
method: "PUT",
url: `http://157.90.231.142:3000/v1/account/${account}/message/${message.id}`,
headers: { 'Authorization': 'Bearer dadb572465fba648590f31557f68028a750b47b278d87c1773e8fd09670eec59'},
data: {
flags: {
add: flags
}
}
})
console.log(data)
console.log(error)
}
const removeFlags = async (account, message, flags) => {
console.log(flags)
const {data,error} = await axios({
method: "PUT",
url: `http://157.90.231.142:3000/v1/account/${account}/message/${message.id}`,
headers: { 'Authorization': 'Bearer dadb572465fba648590f31557f68028a750b47b278d87c1773e8fd09670eec59'},
data: {
flags: {
delete: flags
}
}
})
console.log(data)
console.log(error)
}
const setSeen = async (seen,message) => {
if(seen) {
await addFlags(selectedAccount.value,message, ["\\Seen"])
await selectMailbox(selectedAccount.value, selectedMailbox.value)
} else {
await removeFlags(selectedAccount.value,message, ["\\Seen"])
await selectMailbox(selectedAccount.value, selectedMailbox.value)
}
}
const moveTo = async (destinationPath) => {
const {data,error} = await axios({
method: "PUT",
url: `http://157.90.231.142:3000/v1/account/${selectedAccount.value}/message/${selectedMessage.value.id}/move`,
headers: { 'Authorization': 'Bearer dadb572465fba648590f31557f68028a750b47b278d87c1773e8fd09670eec59'},
data: {
path: destinationPath
}
})
console.log(data)
console.log(error)
selectedMessage.value = null
messageHTML.value = null
messageText.value = null
selectMailbox(selectedAccount.value, selectedMailbox.value)
}
const downloadAttachment = async (attachment) => {
const {data,error} = await axios({
method: "GET",
url: `http://157.90.231.142:3000/v1/account/${selectedAccount.value}/attachment/${attachment.id}`,
headers: { 'Authorization': 'Bearer dadb572465fba648590f31557f68028a750b47b278d87c1773e8fd09670eec59'},
responseType: "blob"
})
const downloadURL = URL.createObjectURL(new Blob([data]))
const link = document.createElement('a')
link.href = downloadURL
link.setAttribute('download', attachment.filename)
document.body.appendChild(link)
link.click()
link.remove()
console.log(data)
console.log(error)
}
setup()
</script>
<template>
<div class="flex flex-row">
<div id="mailboxlist">
<UAccordion
:items="accounts"
>
<template #default="{ item, index, open }">
<UButton variant="soft" class="mt-3">
<span class="truncate">{{ item.label }}</span>
<template #trailing>
<UIcon
name="i-heroicons-chevron-right-20-solid"
class="w-5 h-5 ms-auto transform transition-transform duration-200"
:class="[open && 'rotate-90']"
/>
</template>
</UButton>
</template>
<template #item="{ item }">
<div
v-for="mailbox in mailboxes[item.emailEngineId]"
class="my-3"
>
<UButton
@click="selectMailbox(item.emailEngineId, mailbox)"
variant="outline"
>
<span v-if="mailbox.name === 'Trash'">Papierkorb</span>
<span v-else-if="mailbox.name === 'INBOX'">Eingang</span>
<span v-else-if="mailbox.name === 'Sent'">Gesendet</span>
<span v-else-if="mailbox.name === 'Drafts'">Entwürfe</span>
<span v-else-if="mailbox.name === 'spambucket'">Spam</span>
<span v-else>{{mailbox.name}}</span>
<UBadge v-if="mailbox.messages > 0">{{mailbox.messages}}</UBadge>
</UButton>
</div>
</template>
</UAccordion>
</div>
<UDivider orientation="vertical" class="maiLDivider"/>
<div id="maillist">
<div
v-for="message in messages"
v-if="messages.length > 0"
>
<div
:class="message === selectedMessage ? ['message','text-primary-500'] : ['message']"
@click="selectMessage(selectedAccount, message),
!message.flags.includes('\\Seen') ? setSeen(true,message) : null"
>
<UChip
position="top-left"
:show="!message.flags.includes('\\Seen')"
>
<h1>{{message.from.name ||message.from.address}}</h1>
</UChip>
<h3>{{message.subject}}</h3>
</div>
<UDivider class="my-3"/>
</div>
<div
v-else
>
Keine E-Mails in diesem Postfach
</div>
</div>
<UDivider orientation="vertical" class="maiLDivider"/>
<div id="mailcontent" v-if="selectedMessage">
<Toolbar>
<!--<UButton
@click="setup"
>Setup</UButton>
<UButton>+ Neu</UButton>
<UButton>Sync</UButton>
<UButton>Papierkorb</UButton>
<UButton>Weiterleiten</UButton>
<UButton>Antworten</UButton>-->
<UButton
@click="setSeen(false,selectedMessage)"
>
Als Ungelesen markieren
</UButton>
<UButton
@click="moveTo('INBOX.Trash')"
icon="i-heroicons-trash"
>
</UButton>
</Toolbar>
<UAlert
v-if="selectedMessage"
:title="attachment.filename"
v-for="attachment in selectedMessage.attachments"
class="my-3"
:actions="[{label: 'Download', click:() => {downloadAttachment(attachment)}}]"
>
</UAlert>
<iframe
v-if="messageHTML"
style="width: 100%; height: 100%"
:srcdoc="messageHTML">
</iframe>
<pre
class="text-wrap"
v-else-if="messageText">
{{messageText}}
</pre>
</div>
</div>
</template>
<style scoped>
.maiLDivider {
width: 5vw;
}
#mailboxlist {
width: 15vw;
height: 95vh;
overflow-y: scroll;
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
}
#mailboxlist::-webkit-scrollbar {
display: none;
}
#maillist {
width: 25vw;
height: 88vh;
overflow-y:scroll;
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
}
#maillist::-webkit-scrollbar {
display: none;
}
#mailcontent {
width: 55vw;
height: 88vh;
overflow-y:scroll;
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
}
#mailcontent::-webkit-scrollbar {
display: none;
}
.message {
//border: 1px solid #69c350;
margin-right: 1em;
padding: 0.5em;
}
.message:hover {
background-color: #69c350;
}
.message h1 {
font-weight: bold;
}
</style>

View File

@@ -1,6 +1,24 @@
<template> <template>
<div> <div class="cardHolder">
Offene Aufgaben: {{openTasks}}<br> <div class="card">
<h1 class="text-center text-4xl">Aufgaben</h1>
<p class="text-center text-6xl mt-5">{{openTasks}}</p>
</div><div class="card">
</div><div class="card">
</div><div class="card">
</div><div class="card">
</div><div class="card">
</div>
<br>
</div> </div>
</template> </template>
@@ -20,5 +38,16 @@ const user = useSupabaseUser()
</script> </script>
<style scoped> <style scoped>
.cardHolder {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
}
.card{
width: 22vw;
height: 40vh;
border: 1px solid white
}
</style> </style>

View File

@@ -0,0 +1,155 @@
<script setup>
import HistoryDisplay from "~/components/HistoryDisplay.vue";
definePageMeta({
middleware: "auth"
})
const dataStore = useDataStore()
const supabase = useSupabaseClient()
const route = useRoute()
const router = useRouter()
const toast = useToast()
const id = ref(route.params.id ? route.params.id : null )
let currentItem = ref(null)
//Working
const mode = ref(route.params.mode || "show")
const itemInfo = ref({
name: null,
description: null
})
//Functions
const setupPage = () => {
if(mode.value === "show" || mode.value === "edit"){
currentItem.value = dataStore.getInventoryItemById(Number(useRoute().params.id))
}
if(mode.value === "edit") itemInfo.value = currentItem.value
}
const editItem = async () => {
router.push(`/inventoryitems/edit/${currentItem.value.id}`)
setupPage()
}
const cancelEditorCreate = () => {
if(currentItem.value) {
router.push(`/inventoryitems/show/${currentItem.value.id}`)
} else {
router.push(`/inventoryitems`)
}
}
setupPage()
</script>
<template>
<h1
class="text-center my-3 font-bold text-2xl"
v-if="currentItem "
>{{currentItem.name}}</h1>
<UTabs
:items="[{label: 'Informationen'}, {label: 'Logbuch'}]"
v-if="currentItem && mode == 'show'"
>
<template #item="{item}">
<UCard class="mt-5">
<div v-if="item.label === 'Informationen'">
<Toolbar>
<UButton
v-if="mode === 'show' && currentItem.id"
@click="editItem"
>
Bearbeiten
</UButton>
</Toolbar>
<div class="text-wrap">
<p v-if="currentItem.currentSpace">Lagerplatz: {{dataStore.getSpaceById(currentItem.currentSpace).spaceNumber}} - {{dataStore.getSpaceById(currentItem.currentSpace).description}}</p>
<p>Beschreibung: {{currentItem.description}}</p>
</div>
</div>
<div v-else-if="item.label === 'Logbuch'">
<HistoryDisplay
type="inventoryitem"
v-if="currentItem"
:element-id="currentItem.id"
/>
</div>
</UCard>
</template>
</UTabs>
<UCard v-else-if="mode == 'edit' || mode == 'create'" >
<template #header v-if="mode === 'edit'">
{{itemInfo.name}}
</template>
<UFormGroup
label="Name:"
>
<UInput
v-model="itemInfo.name"
/>
</UFormGroup>
<UFormGroup
label="Lagerplatz:"
>
<USelectMenu
:options="dataStore.spaces"
v-model="itemInfo.currentSpace"
value-attribute="id"
>
<template #option="{option}">
<span class="truncate">{{option.spaceNumber}} - {{option.description}}</span>
</template>
<template #label>
<span v-if="itemInfo.currentSpace">{{dataStore.getSpaceById(itemInfo.currentSpace).spaceNumber }} - {{dataStore.getSpaceById(itemInfo.currentSpace).description}}</span>
<span v-else>Kein Lagerplatz ausgewählt</span>
</template>
</USelectMenu>
</UFormGroup>
<UFormGroup
label="Beschreibung:"
>
<UTextarea
v-model="itemInfo.description"
/>
</UFormGroup>
<template #footer>
<UButton
v-if="mode === 'edit'"
@click="dataStore.updateItem('inventoryitems',itemInfo)"
>
Speichern
</UButton>
<UButton
v-else-if="mode === 'create'"
@click="dataStore.createNewItem('inventoryitems',itemInfo)"
>
Erstellen
</UButton>
<UButton
@click="cancelEditorCreate"
color="red"
class="ml-2"
>
Abbrechen
</UButton>
</template>
</UCard>
</template>
<style scoped>
</style>

View File

@@ -0,0 +1,75 @@
<template>
<div>
<div class="flex items-center gap-1">
<UButton @click="router.push(`/inventoryitems/create/`)">+ Inventarartikel</UButton>
<UInput
v-model="searchString"
placeholder="Suche..."
/>
</div>
<UTable
:rows="filteredRows"
@select="selectItem"
:columns="itemColumns"
:empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Noch keine Einträge' }"
>
</UTable>
</div>
</template>
<script setup>
definePageMeta({
middleware: "auth"
})
const dataStore = useDataStore()
const supabase = useSupabaseClient()
const router = useRouter()
const itemColumns = [
{
key: "name",
label: "Name",
sortable: true
},
{
key: "description",
label: "Beschreibung",
sortable: true
}
]
const selectItem = (item) => {
console.log(item)
router.push(`/inventoryitems/show/${item.id} `)
}
const searchString = ref('')
const filteredRows = computed(() => {
if(!searchString.value) {
return dataStore.inventoryitems
}
return dataStore.inventoryitems.filter(product => {
return Object.values(product).some((value) => {
return String(value).toLowerCase().includes(searchString.value.toLowerCase())
})
})
})
</script>
<style scoped>
</style>

View File

@@ -38,16 +38,15 @@ const fields = [{
const onSubmit = async (data) => { const onSubmit = async (data) => {
const { error } = await supabase.auth.signInWithPassword({ const {error, data:{ user}} = await supabase.auth.signInWithPassword({
email: data.email, email: data.email,
password: data.password password: data.password
}) })
if(error) { if(error) {
console.log(error.toString()) console.log(error.toString())
alert(error.toString())
} else { } else {
console.log("Login Successful") console.log("Login Successful")
dataStore.changeTenant() dataStore.initializeData(user.id)
router.push("/") router.push("/")

View File

@@ -71,6 +71,7 @@ const calendarOptionsTimeline = reactive({
}, },
initialEvents: events, initialEvents: events,
selectable: true, selectable: true,
weekNumbers: true,
select: function (info) { select: function (info) {
//console.log(info) //console.log(info)
newEventData.value.resourceId = info.resource.id newEventData.value.resourceId = info.resource.id
@@ -97,7 +98,7 @@ const calendarOptionsTimeline = reactive({
slotDuration: {hours: 3}, slotDuration: {hours: 3},
slotMinTime: "06:00:00", slotMinTime: "06:00:00",
slotMaxTime: "21:00:00", slotMaxTime: "21:00:00",
/*duration: {days:7},*/ duration: {days:7},
buttonText: "Woche", buttonText: "Woche",
visibleRange: function(currentDate) { visibleRange: function(currentDate) {
// Generate a new date for manipulating in the next step // Generate a new date for manipulating in the next step

View File

@@ -2,6 +2,7 @@
import HistoryDisplay from "~/components/HistoryDisplay.vue"; import HistoryDisplay from "~/components/HistoryDisplay.vue";
import DocumentList from "~/components/DocumentList.vue"; import DocumentList from "~/components/DocumentList.vue";
import DocumentUpload from "~/components/DocumentUpload.vue"; import DocumentUpload from "~/components/DocumentUpload.vue";
import Toolbar from "~/components/Toolbar.vue";
definePageMeta({ definePageMeta({
middleware: "auth" middleware: "auth"
@@ -15,7 +16,7 @@ const toast = useToast()
const id = ref(route.params.id ? route.params.id : null ) const id = ref(route.params.id ? route.params.id : null )
const editor = useEditor({ const editor = useEditor({
content: "<p>I'm running Tiptap with Vue.js. 🎉</p>", content: "<p>Hier kann deine Projektdokumentation stehen</p>",
extensions: [TiptapStarterKit], extensions: [TiptapStarterKit],
}); });
@@ -28,6 +29,8 @@ const itemInfo = ref({})
const tabItems = [ const tabItems = [
{ {
label: "Informationen" label: "Informationen"
},{
label: "Logbuch"
},{ },{
label: "Projekte" label: "Projekte"
},{ },{
@@ -47,6 +50,11 @@ const setupPage = () => {
if(mode.value === "edit") itemInfo.value = currentItem.value if(mode.value === "edit") itemInfo.value = currentItem.value
if(mode.value === "create") {
let query = route.query
if(query.customer) itemInfo.value.customer = Number(query.customer)
}
} }
@@ -59,156 +67,178 @@ const editItem = async () => {
} }
const cancelEditorCreate = () => { const cancelEditorCreate = () => {
mode.value = "show" if(currentItem.value) {
itemInfo.value = { router.push(`/plants/show/${currentItem.value.id}`)
id: 0, } else {
infoData: {} router.push(`/plants`)
} }
} }
setupPage() setupPage()
</script> </script>
<template> <template>
<UCard v-if="currentItem && mode == 'show'"> <h1
class="mb-3 truncate font-bold text-2xl"
v-if="currentItem "
>Objekt: {{currentItem.name}}</h1>
<div v-if="currentItem && mode == 'show'">
<UTabs :items="tabItems">
<template #item="{item}">
<UCard class="mt-5">
<div v-if="item.label === 'Informationen'">
<Toolbar>
<UButton
v-if="mode == 'show' && currentItem.id"
@click="editItem"
>
Bearbeiten
</UButton>
</Toolbar>
<div class="text-wrap">
<p>Kunde: <nuxt-link :to="`/customers/show/${currentItem.customer}`">{{dataStore.getCustomerById(currentItem.customer).name}}</nuxt-link></p>
</div>
</div>
<div v-else-if="item.label === 'Logbuch'">
<HistoryDisplay
type="plant"
v-if="currentItem"
:element-id="currentItem.id"
/>
</div>
<div v-else-if="item.label === 'Projekte'">
<Toolbar>
<UButton
@click="router.push(`/projects/create?plant=${currentItem.id}`)"
>
+ Projekt
</UButton>
</Toolbar>
<UTable
:rows="dataStore.getProjectsByPlantId(currentItem.id)"
:columns="[{key: 'name', label: 'Name'}]"
@select="(row) => router.push(`/projects/show/${row.id}`)"
:empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Keine zugehörigen Projekte' }"
>
</UTable>
</div>
<div v-else-if="item.label === 'Aufgaben'">
<Toolbar>
<UButton
@click="router.push(`/tasks/create?plant=${currentItem.id}`)"
>
+ Aufgabe
</UButton>
</Toolbar>
<UTable
:rows="dataStore.getTasksByPlantId(currentItem.id)"
:empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Keine zugehörigen Aufgaben' }"
:columns="[{key: 'name', label: 'Name'},{key: 'categore', label: 'Kategorie'}]"
@select="(row) => router.push(`/tasks/show/${row.id}`)"
>
</UTable>
</div>
<div v-else-if="item.label === 'Dokumente'" class="space-y-3">
<Toolbar>
<DocumentUpload
type="plant"
:element-id="currentItem.id"
/>
</Toolbar>
<!-- <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/>
</div>
</UCard>
</template>
</UTabs>
</div>
<!-- <UCard v-if="currentItem && mode == 'show'">
<template #header> <template #header>
{{currentItem.name}} {{currentItem.name}}
</template> </template>
<UTabs :items="tabItems">
<template #item="{item}">
<div v-if="item.label === 'Informationen'">
{{currentItem}}
</div>
<div v-else-if="item.label === 'Projekte'">
<InputGroup>
<UButton
@click="router.push(`/projects/create?plant=${currentItem.id}`)"
>
+ Projekt
</UButton>
</InputGroup>
<UTable
:rows="dataStore.getProjectsByPlantId(currentItem.id)"
>
</UTable>
</div>
<div v-else-if="item.label === 'Aufgaben'">
<UTable
:rows="dataStore.getTasksByPlantId(currentItem.id)"
>
</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/>
</div>
</template>
</UTabs>
</UCard>-->
<template #footer>
<UButton
v-if="mode == 'show' && currentItem.id"
@click="editItem"
>
Bearbeiten
</UButton>
<UButton
color="red"
class="ml-2"
disabled
>
Archivieren
</UButton>
<!-- TODO: Kunde archivieren -->
</template>
</UCard>
<UCard v-else-if="mode === 'edit' || mode === 'create'"> <UCard v-else-if="mode === 'edit' || mode === 'create'">
<template #header v-if="mode === 'edit'"> <template #header v-if="mode === 'edit'">
{{itemInfo.name}} {{itemInfo.name}}
@@ -265,11 +295,7 @@ setupPage()
</UCard> </UCard>
<HistoryDisplay
type="plant"
v-if="currentItem"
:element-id="currentItem.id"
/>
</template> </template>
<style scoped> <style scoped>

View File

@@ -1,15 +1,14 @@
<template> <template>
<div id="main"> <Toolbar>
<InputGroup> <UButton @click="router.push(`/plants/create/`)">+ Objekt</UButton>
<UButton @click="router.push(`/plants/create/`)">+ Objekt</UButton>
<UInput
v-model="searchString"
placeholder="Suche..."
/>
</InputGroup>
<UInput
v-model="searchString"
placeholder="Suche..."
/>
</Toolbar>
<div class="table">
<UTable <UTable
:rows="filteredRows" :rows="filteredRows"
:columns="columns" :columns="columns"
@@ -20,8 +19,8 @@
{{dataStore.customers.find(customer => customer.id === row.customer) ? dataStore.customers.find(customer => customer.id === row.customer).name : "" }} {{dataStore.customers.find(customer => customer.id === row.customer) ? dataStore.customers.find(customer => customer.id === row.customer).name : "" }}
</template> </template>
</UTable> </UTable>
</div> </div>
</template> </template>
<script setup> <script setup>

View File

@@ -1,4 +1,8 @@
<script setup> <script setup>
import HistoryDisplay from "~/components/HistoryDisplay.vue";
import DocumentList from "~/components/DocumentList.vue";
import DocumentUpload from "~/components/DocumentUpload.vue";
definePageMeta({ definePageMeta({
middleware: "auth" middleware: "auth"
}) })
@@ -10,7 +14,7 @@ const router = useRouter()
const toast = useToast() const toast = useToast()
const id = ref(route.params.id ? route.params.id : null ) const id = ref(route.params.id ? route.params.id : null )
let currentProduct = null let currentItem = ref(null)
@@ -24,10 +28,10 @@ const itemInfo = ref({
//Functions //Functions
const setupPage = () => { const setupPage = () => {
if(mode.value === "show" || mode.value === "edit"){ if(mode.value === "show" || mode.value === "edit"){
currentProduct = dataStore.getProductById(Number(useRoute().params.id)) currentItem.value = dataStore.getProductById(Number(useRoute().params.id))
} }
if(mode.value === "edit") itemInfo.value = currentProduct if(mode.value === "edit") itemInfo.value = currentItem.value
@@ -35,7 +39,7 @@ const setupPage = () => {
const editItem = async () => { const editItem = async () => {
router.push(`/products/edit/${currentProduct.id}`) router.push(`/products/edit/${currentItem.value.id}`)
setupPage() setupPage()
} }
@@ -53,153 +57,164 @@ setupPage()
</script> </script>
<template> <template>
<div> <h1
<UCard v-if="currentProduct && mode == 'show'" > class="mb-3 truncate font-bold text-2xl"
<template #header> v-if="currentItem "
{{currentProduct.name}} >Artikel: {{currentItem.name}}</h1>
</template> <UTabs
:items="[{label: 'Informationen'},{label: 'Logbuch'},{label: 'Bestand'},{label: 'Dokumente'}]"
v-if="mode === 'show'"
>
<template #item="{item}">
<UCard class="mt-5">
<div
v-if="item.label === 'Informationen'"
>
<Toolbar>
<UButton
v-if="mode === 'show' && currentItem.id"
@click="editItem"
>
Bearbeiten
</UButton>
</Toolbar>
<UBadge
v-for="tag in currentItem.tags"
class="mr-2"
>
{{tag}}
</UBadge>
<UDivider
class="my-2"
/>
<span v-if="currentItem.purchasePrice">Einkaufspreis: {{Number(currentItem.purchasePrice).toFixed(2)}} <br></span>
<UBadge </div>
v-for="tag in currentProduct.tags" <div
class="mr-2" v-if="item.label === 'Logbuch'"
> >
{{tag}} <HistoryDisplay
</UBadge> type="product"
v-if="currentItem"
:element-id="currentItem.id"
/>
</div>
<div
v-if="item.label === 'Bestand'"
>
Bestand: {{dataStore.getStockByProductId(currentItem.id)}} {{dataStore.units.find(unit => unit.id === currentItem.unit) ? dataStore.units.find(unit => unit.id === currentItem.unit).name : ""}}
</div>
<div
v-if="item.label === 'Dokumente'"
>
<Toolbar>
<DocumentUpload
type="product"
:element-id="currentItem.id"
/>
</Toolbar>
<DocumentList :documents="dataStore.getDocumentsByProductId(currentItem.id)"/>
</div>
</UCard>
</template>
</UTabs>
<UCard v-else-if="mode == 'edit' || mode == 'create'" >
<template #header v-if="mode === 'edit'">
{{itemInfo.name}}
</template>
<UDivider <UFormGroup
class="my-2" label="Name:"
>
<UInput
v-model="itemInfo.name"
/> />
<span v-if="currentProduct.purchasePrice">Einkaufspreis: {{Number(currentProduct.purchasePrice).toFixed(2)}} <br></span> </UFormGroup>
Bestand: {{dataStore.getStockByProductId(currentProduct.id)}} {{dataStore.units.find(unit => unit.id === currentProduct.unit) ? dataStore.units.find(unit => unit.id === currentProduct.unit).name : ""}} <UFormGroup
label="Hersteller:"
<DevOnly> >
<UDivider <UInput
class="my-2" v-model="itemInfo.manufacturer"
/> />
</UFormGroup>
{{currentProduct}} <UFormGroup
</DevOnly> label="Einheit:"
>
<USelectMenu
<template #footer>
<UButton
v-if="mode === 'show' && currentProduct.id"
@click="editItem"
>
Bearbeiten
</UButton>
<UButton
color="red"
class="ml-2"
disabled
>
Archivieren
</UButton>
<!-- TODO: Produkt archivieren -->
</template>
</UCard>
<UCard v-else-if="mode == 'edit' || mode == 'create'" >
<template #header v-if="mode === 'edit'">
{{itemInfo.name}}
</template>
<UFormGroup
label="Name:"
>
<UInput
v-model="itemInfo.name"
/>
</UFormGroup>
<UFormGroup
label="Hersteller:"
>
<UInput
v-model="itemInfo.manufacturer"
/>
</UFormGroup>
<UFormGroup
label="Einheit:"
>
<USelectMenu
v-model="itemInfo.unit" v-model="itemInfo.unit"
:options="dataStore.units" :options="dataStore.units"
option-attribute="name" option-attribute="name"
value-attribute="id" value-attribute="id"
>
<template #label>
{{dataStore.units.find(unit => unit.id === itemInfo.unit) ? dataStore.units.find(unit => unit.id === itemInfo.unit).name : itemInfo.unit }}
</template>
</USelectMenu>
</UFormGroup>
<UFormGroup
label="Tags:"
> >
<USelectMenu <template #label>
{{dataStore.units.find(unit => unit.id === itemInfo.unit) ? dataStore.units.find(unit => unit.id === itemInfo.unit).name : itemInfo.unit }}
</template>
</USelectMenu>
</UFormGroup>
<UFormGroup
label="Tags:"
>
<USelectMenu
v-model="itemInfo.tags" v-model="itemInfo.tags"
:options="dataStore.ownTenant.tags.products" :options="dataStore.ownTenant.tags.products"
multiple multiple
/> />
</UFormGroup> </UFormGroup>
<UFormGroup <UFormGroup
label="EAN:" label="EAN:"
>
<UInput
v-model="itemInfo.ean"
/>
</UFormGroup>
<UFormGroup
label="Barcode:"
>
<UInput
v-model="itemInfo.barcode"
/>
</UFormGroup>
<UFormGroup
label="Einkaufspreis:"
>
<UInput
v-model="itemInfo.purchasePrice"
type="number"
steps="0.01"
> >
<UInput <template #trailing>
v-model="itemInfo.ean" <span class="text-gray-500 dark:text-gray-400 text-xs">EUR</span>
/> </template>
</UFormGroup> </UInput>
<UFormGroup </UFormGroup>
label="Barcode:"
>
<UInput
v-model="itemInfo.barcode"
/>
</UFormGroup>
<UFormGroup
label="Einkaufspreis:"
>
<UInput
v-model="itemInfo.purchasePrice"
type="number"
steps="0.01"
>
<template #trailing>
<span class="text-gray-500 dark:text-gray-400 text-xs">EUR</span>
</template>
</UInput>
</UFormGroup>
<template #footer> <template #footer>
<UButton <UButton
v-if="mode == 'edit'" v-if="mode == 'edit'"
@click="dataStore.updateItem('products',itemInfo)" @click="dataStore.updateItem('products',itemInfo)"
> >
Speichern Speichern
</UButton> </UButton>
<UButton <UButton
v-else-if="mode == 'create'" v-else-if="mode == 'create'"
@click="dataStore.createNewItem('products',itemInfo)" @click="dataStore.createNewItem('products',itemInfo)"
> >
Erstellen Erstellen
</UButton> </UButton>
<UButton <UButton
@click="cancelEditorCreate" @click="cancelEditorCreate"
color="red" color="red"
class="ml-2" class="ml-2"
> >
Abbrechen Abbrechen
</UButton> </UButton>
</template> </template>
</UCard> </UCard>
</div>
</template> </template>
<style scoped> <style scoped>

View File

@@ -1,22 +1,20 @@
<template> <template>
<div> <Toolbar>
<UButton @click="router.push(`/products/create/`)">+ Artikel</UButton>
<div class="flex items-center gap-1">
<UButton @click="router.push(`/products/create/`)">+ Artikel</UButton>
<UInput
v-model="searchString"
placeholder="Suche..."
/>
</div>
<UInput
v-model="searchString"
placeholder="Suche..."
/>
</Toolbar>
<div class="table">
<UTable <UTable
:rows="filteredRows" :rows="filteredRows"
:columns="itemColumns" :columns="itemColumns"
@select="selectItem" @select="selectItem"
:empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Noch keine Einträge' }" :empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Noch keine Einträge' }"
> >
<template #stock-data="{row}"> <template #stock-data="{row}">
{{`${dataStore.getStockByProductId(row.id)} ${(dataStore.units.find(unit => unit.id === row.unit) ? dataStore.units.find(unit => unit.id === row.unit).name : "")}`}} {{`${dataStore.getStockByProductId(row.id)} ${(dataStore.units.find(unit => unit.id === row.unit) ? dataStore.units.find(unit => unit.id === row.unit).name : "")}`}}
@@ -27,8 +25,8 @@
<template #tags-data="{row}"> <template #tags-data="{row}">
<UBadge <UBadge
v-if="row.tags.length > 0" v-if="row.tags.length > 0"
v-for="tag in row.tags" v-for="tag in row.tags"
class="mr-2" class="mr-2"
> >
{{tag}} {{tag}}
</UBadge> </UBadge>
@@ -38,9 +36,8 @@
{{dataStore.units.find(unit => unit.id === row.unit) ? dataStore.units.find(unit => unit.id === row.unit).name : row.unit}} {{dataStore.units.find(unit => unit.id === row.unit) ? dataStore.units.find(unit => unit.id === row.unit).name : row.unit}}
</template> </template>
</UTable> </UTable>
</div> </div>
</template> </template>
<script setup> <script setup>

View File

@@ -10,6 +10,7 @@ definePageMeta({
const dataStore = useDataStore() const dataStore = useDataStore()
const supabase = useSupabaseClient() const supabase = useSupabaseClient()
const user = useSupabaseUser()
const route = useRoute() const route = useRoute()
const router = useRouter() const router = useRouter()
const toast = useToast() const toast = useToast()
@@ -22,6 +23,10 @@ const tabItems = [
key: "information", key: "information",
label: "Informationen" label: "Informationen"
}, },
{
key: "historyDisplay",
label: "Logbuch"
},
{ {
key: "phases", key: "phases",
label: "Phasen" label: "Phasen"
@@ -68,22 +73,6 @@ const timeTableRows = [
}, },
] ]
const taskColumns = [
{
key: "name",
label: "Name"
},{
key: "description",
label: "Beschreibung"
},{
key: "categorie",
label: "Kategorie"
}, {
key: "user",
label: "Benutzer"
}
]
//Working //Working
@@ -91,7 +80,7 @@ const mode = ref(route.params.mode || "show")
const itemInfo = ref({ const itemInfo = ref({
name: "", name: "",
customer: 0, customer: 0,
users: [user.value.id]
}) })
const uploadModalOpen = ref(false) const uploadModalOpen = ref(false)
@@ -223,38 +212,50 @@ setupPage()
</script> </script>
<template> <template>
<UCard v-if="currentItem && mode == 'show'"> <h1
<template #header> class="mb-3 truncate font-bold text-2xl"
{{currentItem.name}} v-if="currentItem "
</template> >Projekt: {{currentItem.name}}</h1>
<UTabs :items="tabItems" class="w-full" v-if="currentItem && mode == 'show'">
<UTabs :items="tabItems" class="w-full"> <template #item="{ item }">
<template #item="{ item }"> <UCard class="mt-5">
<div v-if="item.key === 'information'"> <div v-if="item.key === 'information'">
<InputGroup> <Toolbar>
<UButton <UButton
@click="router.push(`/customers/show/${currentItem.customer}`)" @click="editItem"
class="mb-3"
> >
Zum Kunden Bearbeiten
</UButton> </UButton>
<UButton </Toolbar>
@click="router.push(`/plants/show/${currentItem.plant}`)"
class="mb-3"
>
Zum Objekt
</UButton>
</InputGroup>
Kunde: {{dataStore.getCustomerById(currentItem.customer).name}}<br>
Objekt: {{currentItem.plant ? dataStore.getPlantById(currentItem.plant).name : ""}}<br> <div class="text-wrap">
Notizen:<br> <p>Kunde: <nuxt-link :to="`/customers/show/${currentItem.customer}`">{{dataStore.getCustomerById(currentItem.customer).name}}</nuxt-link></p>
{{currentItem.notes}} <p>Objekt: <nuxt-link :to="`/plants/show/${currentItem.plant}`">{{currentItem.plant ? dataStore.getPlantById(currentItem.plant).name : ""}}</nuxt-link></p>
<p class="">Notizen: {{currentItem.notes}}</p>
</div>
<UDivider class="my-3"/>
<h1 class="font-bold text-lg my-3">Beteiligte Benutzer:</h1>
<UAlert
v-for="projectUser in currentItem.users"
:avatar="{ alt: dataStore.getProfileById(projectUser).fullName }"
:title="dataStore.getProfileById(projectUser).fullName"
class="mb-3"
/>
</div>
<div v-else-if="item.key === 'historyDisplay'">
<HistoryDisplay
type="project"
v-if="currentItem"
:element-id="currentItem.id"
/>
</div> </div>
<div v-if="item.key === 'phases'" class="space-y-3"> <div v-if="item.key === 'phases'" class="space-y-3">
<UFormGroup <UFormGroup
label="Vorlage laden" label="Vorlage laden"
v-if="currentItem.phases.length === 0" v-if="currentItem.phases.length === 0"
> >
<InputGroup> <InputGroup>
<USelectMenu <USelectMenu
@@ -276,38 +277,58 @@ setupPage()
<UAccordion <UAccordion
:items="currentItem.phases" :items="currentItem.phases"
> >
<template #item="{item}"> <template #default="{item,index,open}">
<InputGroup> <UButton
<UButton variant="ghost"
v-if="!item.active" :color="item.active ? 'primary' : 'white'"
@click="changeActivePhase(item)" class="mb-1"
> >
Phase aktivieren <template #leading>
</UButton> <div class="w-6 h-6 flex items-center justify-center -my-1">
<UIcon :name="item.icon" class="w-4 h-4 " />
</div>
</template>
<!-- <UButton> <span class="truncate"> {{item.label}}</span>
+ Phase
</UButton>--> <template #trailing>
</InputGroup> <UIcon
</template> name="i-heroicons-chevron-right-20-solid"
class="w-5 h-5 ms-auto transform transition-transform duration-200"
:class="[open && 'rotate-90']"
/>
</template>
</UButton>
</template>
<template #item="{item}">
<InputGroup>
<UButton
v-if="!item.active"
@click="changeActivePhase(item)"
>
Phase aktivieren
</UButton>
</InputGroup>
</template>
</UAccordion> </UAccordion>
</div> </div>
<div v-if="item.key === 'tasks'" class="space-y-3"> <div v-if="item.key === 'tasks'" class="space-y-3">
<InputGroup> <Toolbar>
<UButton <UButton
@click="router.push(`/tasks/create?project=${currentItem.id}`)" @click="router.push(`/tasks/create?project=${currentItem.id}`)"
> >
+ Aufgabe + Aufgabe
</UButton> </UButton>
</InputGroup> </Toolbar>
<UTable <UTable
:rows="dataStore.getTasksByProjectId(currentItem.id)" :rows="dataStore.getTasksByProjectId(currentItem.id)"
:columns="taskColumns" :columns="[{key: 'name',label: 'Name'},{key: 'categorie',label: 'Kategorie'},{key: 'user',label: 'Benutzer'}]"
@select="(row) => { @select="(row) => router.push(`/tasks/show/${row.id}`)"
router.push(`/tasks/show/${row.id}`) :empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Keine zugehörigen Aufgaben' }"
}"
> >
<template #user-data="{row}"> <template #user-data="{row}">
{{dataStore.profiles.find(i => i.id === row.user) ? dataStore.profiles.find(i => i.id === row.user).fullName : ""}} {{dataStore.profiles.find(i => i.id === row.user) ? dataStore.profiles.find(i => i.id === row.user).fullName : ""}}
@@ -315,63 +336,8 @@ setupPage()
</UTable> </UTable>
</div> </div>
<!--
<div v-else-if="item.key === 'forms'" class="space-y-3">
<UButton
@click="formModalOpen = true"
>
+ Formular
</UButton>
<UModal
v-model="formModalOpen"
>
<UCard>
<template #header>
Formular hinzufügen
</template>
<UFormGroup>
<USelectMenu
:options="forms"
option-attribute="name"
value-attribute="id"
v-model="newFormSubmissionData.formType"
/>
</UFormGroup>
<template #footer>
<UButton
@click="addNewFormSubmission"
>
Hinzufügen
</UButton>
</template>
</UCard>
</UModal>
<UAccordion :items="formSubmissionsComposed">
<template #item="{item}">
<p class="my-3">Formular Link: <a :href="'https://app.spaces.software/formSubmissions/' + item.id">{{'https://app.spaces.software/formSubmissions/' + item.id}}</a></p>
<div v-if="Object.keys(item.values).length == 0">
<p>Es wurden noch keine Daten über das Formular abgegeben</p>
</div>
<table v-else>
<tr v-for="key in Object.keys(item.values)">
<td>{{key}}</td>
<td>{{ item.values[key] }}</td>
</tr>
</table>
</template>
</UAccordion>
</div>
-->
<div v-else-if="item.key === 'documents'" class="space-y-3"> <div v-else-if="item.key === 'documents'" class="space-y-3">
<InputGroup> <Toolbar>
<DocumentUpload <DocumentUpload
type="project" type="project"
:element-id="currentItem.id" :element-id="currentItem.id"
@@ -386,68 +352,8 @@ setupPage()
> >
+ Rechnung + Rechnung
</UButton> </UButton>
</InputGroup> </Toolbar>
<!-- <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.getDocumentsByProjectId(currentItem.id)"/> <DocumentList :documents="dataStore.getDocumentsByProjectId(currentItem.id)"/>
@@ -476,32 +382,15 @@ setupPage()
</UTable> </UTable>
</div> </div>
<div v-else-if="item.key === 'events'" class="space-y-3"> <div v-else-if="item.key === 'events'" class="space-y-3">
{{dataStore.getEventsByProjectId(currentItem.id)}} {{dataStore.getEventsByProjectId(currentItem.id).length > 0 ? dataStore.getEventsByProjectId(currentItem.id) : "Keine Termine in für dieses Projekt"}}
</div> </div>
<!-- </UCard>
<div v-else-if="item.key === 'material'" class="space-y-3">
<p>Hier wird aktuell noch gearbeitet</p>
</div>
-->
</template>
</UTabs>
<template #footer>
<UButton
v-if="mode == 'show' && currentItem.id"
@click="editItem"
>
Bearbeiten
</UButton>
</template> </template>
</UTabs>
</UCard>
<UCard v-else-if="mode === 'edit' || mode === 'create'" > <UCard v-else-if="mode === 'edit' || mode === 'create'" >
<template #header v-if="mode === 'edit'"> <template #header v-if="mode === 'edit'">
{{itemInfo.name}} {{itemInfo.name}}
@@ -563,6 +452,23 @@ setupPage()
</template> </template>
</USelectMenu> </USelectMenu>
</UFormGroup> </UFormGroup>
<UFormGroup
label="Beteiligte Benutzer:"
>
<USelectMenu
v-model="itemInfo.users"
:options="dataStore.profiles"
option-attribute="fullName"
value-attribute="id"
searchable
multiple
:search-attributes="['fullName']"
>
<template #label>
{{itemInfo.users.length > 0 ? itemInfo.users.map(i => dataStore.getProfileById(i).fullName).join(", ") : "Kein Benutzer ausgewählt"}}
</template>
</USelectMenu>
</UFormGroup>
<UFormGroup <UFormGroup
label="Notizen:" label="Notizen:"
@@ -596,11 +502,7 @@ setupPage()
</UCard> </UCard>
<HistoryDisplay
type="project"
v-if="currentItem"
:element-id="currentItem.id"
/>
</template> </template>
<style scoped> <style scoped>

View File

@@ -14,23 +14,28 @@
</InputGroup> </InputGroup>
<div class="table">
<UTable
:rows="filteredRows"
@select="selectItem"
:columns="itemColumns"
:empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Noch keine Einträge' }"
>
<template #phase-data="{row}">
{{getActivePhaseLabel(row)}}
</template>
<template #customer-data="{row}">
{{dataStore.getCustomerById(row.customer) ? dataStore.getCustomerById(row.customer).name : ""}}
</template>
<template #plant-data="{row}">
{{dataStore.getPlantById(row.plant) ? dataStore.getPlantById(row.plant).name : ""}}
</template>
<template #users-data="{row}">
{{row.users.map(i => dataStore.getProfileById(i).fullName).join(", ")}}
</template>
</UTable>
</div>
<UTable
:rows="filteredRows"
@select="selectItem"
:columns="itemColumns"
:empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Noch keine Einträge' }"
>
<template #phase-data="{row}">
{{getActivePhaseLabel(row)}}
</template>
<template #customer-data="{row}">
{{dataStore.getCustomerById(row.customer) ? dataStore.getCustomerById(row.customer).name : ""}}
</template>
<template #plant-data="{row}">
{{dataStore.getPlantById(row.plant) ? dataStore.getPlantById(row.plant).name : ""}}
</template>
</UTable>
</template> </template>
<script setup> <script setup>
@@ -58,16 +63,21 @@ const itemColumns = [
key: "customer", key: "customer",
label: "Kunde", label: "Kunde",
sortable: true sortable: true
}, },/*
{ {
key: "notes", key: "notes",
label: "Notizen", label: "Notizen",
sortable: true sortable: true
}, },*/
{ {
key: "plant", key: "plant",
label: "Objekt", label: "Objekt",
sortable: true sortable: true
},
{
key: "users",
label: "Benutzer",
sortable: true
} }
] ]

View File

@@ -57,8 +57,10 @@
{{row.state}} {{row.state}}
</span> </span>
</template> </template>
<template #vendor-data="{row}"> <template #partner-data="{row}">
{{dataStore.vendors.find(vendor => vendor.id === row.vendor) ? dataStore.vendors.find(vendor => vendor.id === row.vendor).name : ''}} <span v-if="row.customer">{{dataStore.getCustomerById(row.customer) ? dataStore.getCustomerById(row.customer).name : ''}}</span>
<span v-else-if="row.vendor">{{dataStore.getVendorById(row.vendor) ? dataStore.getVendorById(row.vendor).name : ''}}</span>
</template> </template>
<template #reference-data="{row}"> <template #reference-data="{row}">
<span v-if="row.type === 'incomingInvoice'">{{row.reference}}</span> <span v-if="row.type === 'incomingInvoice'">{{row.reference}}</span>
@@ -111,8 +113,8 @@ const itemColumns = [
sortable: true sortable: true
}, },
{ {
key: 'vendor', key: 'partner',
label: "Lieferant", label: "Kunde / Lieferant",
sortable: true sortable: true
}, },
{ {

View File

@@ -0,0 +1,51 @@
<script setup>
const dataStore = useDataStore()
const items = [{
label: 'Projekte',
content: 'This is the content shown for Tab1'
}, {
label: 'E-Mail',
content: 'And, this is the content for Tab2'
}, {
label: 'Dokumente'
}]
</script>
<template>
<UTabs
:items="items"
>
<template #item="{item}">
<UCard class="mt-5 overflow-y-scroll scroll">
<div v-if="item.label === 'Projekte'">
<UDivider
label="Phasenvorlagen"
/>
</div>
<div v-else-if="item.label === 'Dokumente'">
<UDivider
label="Tags"
class="mb-3"
/>
<InputGroup>
<UBadge
v-for="tag in dataStore.ownTenant.tags.documents"
>
{{tag}}
</UBadge>
</InputGroup>
{{dataStore.ownTenant.tags}}
</div>
</UCard>
</template>
</UTabs>
</template>
<style scoped>
</style>

View File

@@ -94,117 +94,112 @@ setupPage()
</script> </script>
<template> <template>
<div> <h1
<DevOnly> class="mb-3 truncate font-bold text-2xl"
{{currentItem}} v-if="currentItem "
{{mode}} >Lagerplatz: {{currentItem.spaceNumber}}</h1>
</DevOnly> <UTabs
<UCard v-if="currentItem && mode == 'show'" > :items="[{label: 'Informationen'},{label: 'Logbuch'},{label: 'Bestand'}]"
<template #header> v-if="currentItem && mode == 'show'"
<UBadge>{{currentItem.spaceNumber}}</UBadge> {{currentItem.type}} >
</template> <template #item="{item}">
<UCard class="mt-5">
<div v-if="item.label === 'Informationen'">
<Toolbar>
<UButton
v-if="mode == 'show' && currentItem.id"
@click="editItem"
>
Bearbeiten
</UButton>
<UButton
v-if="mode == 'show' && currentItem.id"
@click="printSpaceLabel"
class="ml-2"
>
Label Drucken
</UButton>
</Toolbar>
{{currentItem.description}} <div class="truncate">
<span>Beschreibung: {{currentItem.description}}</span>
<UDivider </div>
class="my-2"
/>
<div v-if="spaceProducts.length > 0">
<p class="mt-5">Artikel in diesem Lagerplatz</p>
<table>
<tr>
<th>Artikel</th>
<th>Anzahl</th>
<th>Einheit</th>
</tr>
<tr v-for="product in spaceProducts">
<td>{{product.name}}</td>
<td>{{getSpaceProductCount(product.id)}}</td>
<td>{{dataStore.units.find(unit => unit.id === product.unit).name}}</td>
</tr>
</table>
</div>
<p v-else>Es befinden sich keine Artikel in diesem Lagerplatz</p>
</div>
<div v-else-if="item.label === 'Logbuch'">
<template #footer> </div>
<UButton <div v-else-if="item.label === 'Bestand'">
v-if="mode == 'show' && currentItem.id" <div v-if="spaceProducts.length > 0">
@click="editItem" <p class="mt-5">Artikel in diesem Lagerplatz</p>
>
Bearbeiten
</UButton>
<UButton
v-if="mode == 'show' && currentItem.id"
@click="printSpaceLabel"
class="ml-2"
>
Label Drucken
</UButton>
<UButton
color="red"
class="ml-2"
disabled
>
Archivieren
</UButton>
</template>
<table>
<tr>
<th class="text-left">Artikel</th>
<th>Anzahl</th>
<th>Einheit</th>
</tr>
<tr v-for="product in spaceProducts">
<td>{{product.name}}</td>
<td>{{getSpaceProductCount(product.id)}}</td>
<td>{{dataStore.units.find(unit => unit.id === product.unit).name}}</td>
</tr>
</table>
</div>
<p v-else>Es befinden sich keine Artikel in diesem Lagerplatz</p>
</div>
</UCard>
</template>
</UTabs>
<UCard v-else-if="mode === 'edit' || mode === 'create'" >
<template #header v-if="mode === 'edit'">
<UBadge>{{itemInfo.spaceNumber}}</UBadge>{{itemInfo.type}}
</template>
</UCard> <UFormGroup
<UCard v-else-if="mode === 'edit' || mode === 'create'" > label="Typ:"
<template #header v-if="mode === 'edit'"> >
<UBadge>{{itemInfo.spaceNumber}}</UBadge>{{itemInfo.type}} <USelectMenu
</template>
<UFormGroup
label="Typ:"
>
<USelectMenu
:options="spaceTypes" :options="spaceTypes"
v-model="itemInfo.type" v-model="itemInfo.type"
>
</USelectMenu>
</UFormGroup>
<UFormGroup
label="Beschreibung.:"
> >
<UTextarea
v-model="itemInfo.description" </USelectMenu>
/> </UFormGroup>
</UFormGroup> <UFormGroup
label="Beschreibung.:"
>
<UTextarea
v-model="itemInfo.description"
/>
</UFormGroup>
<template #footer> <template #footer>
<UButton <UButton
v-if="mode == 'edit'" v-if="mode == 'edit'"
@click="dataStore.updateItem('spaces',itemInfo)" @click="dataStore.updateItem('spaces',itemInfo)"
> >
Speichern Speichern
</UButton> </UButton>
<UButton <UButton
v-else-if="mode == 'create'" v-else-if="mode == 'create'"
@click="dataStore.createNewItem('spaces',itemInfo)" @click="dataStore.createNewItem('spaces',itemInfo)"
> >
Erstellen Erstellen
</UButton> </UButton>
<UButton <UButton
@click="cancelEditorCreate" @click="cancelEditorCreate"
color="red" color="red"
class="ml-2" class="ml-2"
> >
Abbrechen Abbrechen
</UButton> </UButton>
</template> </template>
</UCard> </UCard>
</div>
</template> </template>
<style scoped> <style scoped>

View File

@@ -1,27 +1,23 @@
<template> <template>
<div id="main"> <Toolbar>
<UButton @click="router.push(`/inventory/spaces/create/`)">+ Lagerplatz</UButton>
<div class="flex items-center gap-1">
<UButton @click="router.push(`/inventory/spaces/create/`)">+ Lagerplatz</UButton>
<UInput
v-model="searchString"
placeholder="Suche..."
/>
</div>
<UInput
v-model="searchString"
placeholder="Suche..."
/>
</Toolbar>
<div class="table">
<UTable <UTable
:rows="filteredRows" :rows="filteredRows"
:columns="itemColumns" :columns="itemColumns"
@select="selectItem" @select="selectItem"
:empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Noch keine Einträge' }" :empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Noch keine Einträge' }"
/> />
</div> </div>
</template> </template>
<script setup> <script setup>

View File

@@ -1,7 +1,7 @@
<template> <template>
<div id="main">
<InputGroup> <div>
<Toolbar>
<UButton @click="router.push(`/tasks/create`)">+ Aufgabe</UButton> <UButton @click="router.push(`/tasks/create`)">+ Aufgabe</UButton>
<UInput <UInput
@@ -13,37 +13,38 @@
label="Erledigte Anzeigen" label="Erledigte Anzeigen"
v-model="showDone" v-model="showDone"
/> />
</InputGroup> </Toolbar>
<div class="table">
<UTable <UTable
:rows="filteredRows" :rows="filteredRows"
:columns="columns" :columns="columns"
@select="selectItem" @select="selectItem"
:empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Noch keine Einträge' }" :empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Noch keine Einträge' }"
> >
<template #finish-data="{row}"> <template #finish-data="{row}">
<UButton <UButton
icon="i-heroicons-check" icon="i-heroicons-check"
variant="ghost" variant="ghost"
@click="markAsFinished(row)" @click="markAsFinished(row)"
/> />
</template> </template>
<template #created_at-data="{row}"> <template #created_at-data="{row}">
{{row.created_at ? dayjs(row.created_at).format("DD.MM.YY HH:mm") : ''}} {{row.created_at ? dayjs(row.created_at).format("DD.MM.YY HH:mm") : ''}}
</template> </template>
<template #user-data="{row}"> <template #user-data="{row}">
{{dataStore.profiles.find(i => i.id === row.user) ? dataStore.profiles.find(i => i.id === row.user).fullName : ""}} {{dataStore.profiles.find(i => i.id === row.user) ? dataStore.profiles.find(i => i.id === row.user).fullName : ""}}
</template> </template>
<template #project-data="{row}"> <template #project-data="{row}">
{{dataStore.projects.find(i => i.id === row.project) ? dataStore.projects.find(i => i.id === row.project).name : ""}} {{dataStore.projects.find(i => i.id === row.project) ? dataStore.projects.find(i => i.id === row.project).name : ""}}
</template> </template>
<template #customer-data="{row}"> <template #customer-data="{row}">
{{dataStore.customers.find(customer => customer.id === row.customer) ? dataStore.customers.find(customer => customer.id === row.customer).name : "" }} {{dataStore.customers.find(customer => customer.id === row.customer) ? dataStore.customers.find(customer => customer.id === row.customer).name : "" }}
</template> </template>
<template #plant-data="{row}"> <template #plant-data="{row}">
{{dataStore.getPlantById(row.plant) ? dataStore.getPlantById(row.plant).name : "" }} {{dataStore.getPlantById(row.plant) ? dataStore.getPlantById(row.plant).name : "" }}
</template> </template>
</UTable> </UTable>
</div>
</div> </div>
</template> </template>

View File

@@ -19,10 +19,12 @@ let currentItem = ref(null)
//Working //Working
const mode = ref(route.params.mode || "show") const mode = ref(route.params.mode || "show")
const itemInfo = ref({ const itemInfo = ref({
id: null,
name: "", name: "",
licensePlate: "", licensePlate: "",
type: "", type: "",
driver: null driver: null,
active: true
}) })
const tabItems = [{ const tabItems = [{
@@ -76,13 +78,12 @@ const editCustomer = async () => {
} }
const cancelEditorCreate = () => { const cancelEditorCreate = () => {
mode.value = "show" if(currentItem.value) {
itemInfo.value = { router.push(`/vehicles/show/${currentItem.value.id}`)
id: 0, } else {
name: "", router.push(`/vehicles`)
licensePlate: "",
type: ""
} }
} }
const updateItem = async () => { const updateItem = async () => {
@@ -135,6 +136,13 @@ setupPage()
<UTabs :items="tabItems"> <UTabs :items="tabItems">
<template #item="{item}"> <template #item="{item}">
<div v-if="item.label === 'Informationen'"> <div v-if="item.label === 'Informationen'">
<InputGroup class="mb-3">
<UButton
@click="editCustomer"
>
Bearbeiten
</UButton>
</InputGroup>
Typ: {{currentItem.type}} <br> Typ: {{currentItem.type}} <br>
Fahrer: {{dataStore.profiles.find(profile => profile.id === currentItem.driver) ? dataStore.profiles.find(profile => profile.id === currentItem.driver).fullName : 'Kein Fahrer gewählt'}} <br> Fahrer: {{dataStore.profiles.find(profile => profile.id === currentItem.driver) ? dataStore.profiles.find(profile => profile.id === currentItem.driver).fullName : 'Kein Fahrer gewählt'}} <br>
</div> </div>
@@ -175,22 +183,7 @@ setupPage()
<template #footer>
<UButton
v-if="mode == 'show' && currentItem.id"
@click="editCustomer"
>
Bearbeiten
</UButton>
<UButton
color="red"
class="ml-2"
disabled
>
Archivieren
</UButton>
<!-- TODO: Fahrzeug archivieren -->
</template>
@@ -229,7 +222,7 @@ setupPage()
> >
<USelectMenu <USelectMenu
v-model="itemInfo.driver" v-model="itemInfo.driver"
:options="dataStore.profiles" :options="[{id: null, fullName: 'Kein Fahrer'},...dataStore.profiles]"
option-attribute="fullName" option-attribute="fullName"
value-attribute="id" value-attribute="id"

View File

@@ -33,177 +33,178 @@ const setupPage = () => {
} }
const editItem = async () => { const editItem = async () => {
router.push(`/vendors/edit/${currentItem.id}`) router.push(`/vendors/edit/${currentItem.value.id}`)
setupPage() setupPage()
} }
const cancelEditorCreate = () => { const cancelEditorCreate = () => {
router.push(`/vendors/`) if(currentItem.value) {
router.push(`/vendors/show/${currentItem.value.id}`)
} else {
router.push(`/vendors`)
}
} }
setupPage() setupPage()
</script> </script>
<template> <template>
<div> <h1
<UCard v-if="currentItem && mode == 'show'" > class=" mb-3 font-bold text-2xl truncate"
<template #header> v-if="currentItem "
{{currentItem.name}} >Lieferant: {{currentItem.name}}</h1>
</template> <UTabs
:items="[{label: 'Informationen'},{label: 'Logbuch'},{label: 'Ansprechpartner'}]"
v-if="currentItem && mode == 'show'"
>
<template #item="{item}">
<UCard class="mt-5">
<div v-if="item.label === 'Informationen'">
<Toolbar>
<UButton
v-if="mode == 'show' && currentItem.id"
@click="editItem"
>
Bearbeiten
</UButton>
</Toolbar>
<InputGroup> <div v-if="currentItem.infoData" class="text-wrap">
<UButton <p v-if="currentItem.infoData.street">Straße + Hausnummer: {{currentItem.infoData.street}}</p>
@click="router.push(`/contacts/create?vendor=${currentItem.id}`)" <p v-if="currentItem.infoData.zip && currentItem.infoData.city">PLZ + Ort: {{currentItem.infoData.zip}} {{currentItem.infoData.city}}</p>
> <p v-if="currentItem.infoData.tel">Telefon: {{currentItem.infoData.tel}}</p>
+ Ansprechpartner <p v-if="currentItem.infoData.email">E-Mail: {{currentItem.infoData.email}}</p>
</UButton> <p v-if="currentItem.infoData.web">Web: {{currentItem.infoData.web}}</p>
</InputGroup> <p v-if="currentItem.infoData.ustid">USt-Id: {{currentItem.infoData.ustid}}</p>
</div>
</div>
<div v-else-if="item.label === 'Logbuch'">
<HistoryDisplay
type="vendor"
v-if="currentItem"
:element-id="currentItem.id"
/>
</div>
<div v-else-if="item.label === 'Ansprechpartner'">
<Toolbar>
<UButton
@click="router.push(`/contacts/create?vendor=${currentItem.id}`)"
>
+ Ansprechpartner
</UButton>
</Toolbar>
<UTable
:rows="dataStore.getContactsByVendorId(currentItem.id)"
@select="(row) => router.push(`/contacts/show/${row.id}`)"
:columns="[{label: 'Anrede', key: 'salutation'},{label: 'Name', key: 'fullName'},{label: 'Rolle', key: 'role'}]"
:empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Keine zugehörigen Ansprechpartner' }"
Information: <br>
<div v-if="currentItem.infoData">
<span v-if="currentItem.infoData.street">Straße + Hausnummer: {{currentItem.infoData.street}}<br></span>
<span v-if="currentItem.infoData.zip && currentItem.infoData.city">PLZ + Ort: {{currentItem.infoData.zip}} {{currentItem.infoData.city}}<br></span>
<span v-if="currentItem.infoData.tel">Telefon: {{currentItem.infoData.tel}}<br></span>
<span v-if="currentItem.infoData.email">E-Mail: {{currentItem.infoData.email}}<br></span>
<span v-if="currentItem.infoData.web">Web: {{currentItem.infoData.web}}<br></span>
<span v-if="currentItem.infoData.ustid">USt-Id: {{currentItem.infoData.ustid}}<br></span>
</div>
<UDivider class="my-3"/>
<div v-if="dataStore.getContactsByVendorId(currentItem.id).length > 0">
Kontakte: <br>
<ul>
<li
v-for="contact in dataStore.getContactsByVendorId(currentItem.id)"
> >
<router-link :to="'/contacts/show/' + contact.id">{{contact.salutation}} {{contact.fullName}} - {{contact.role}}</router-link>
</li>
</ul>
</div>
<template #footer> </UTable>
<UButton
v-if="mode == 'show' && currentItem.id" </div>
@click="editItem" </UCard>
> </template>
Bearbeiten </UTabs>
</UButton> <UCard v-else-if="mode === 'edit' || mode === 'create'" >
<UButton <template #header v-if="mode === 'edit'">
color="red" {{itemInfo.name}}
class="ml-2" </template>
disabled
> <UFormGroup
Archivieren label="Name:"
</UButton> >
</template> <UInput
v-model="itemInfo.name"
/>
</UFormGroup>
<UFormGroup
label="Lieferantennr.:"
>
<UInput
v-model="itemInfo.vendorNumber"
placeholder="Leer lassen für automatisch generierte Nummer"
/>
</UFormGroup>
<UFormGroup
label="Straße + Hausnummer"
>
<UInput
v-model="itemInfo.infoData.street"
/>
</UFormGroup>
<UFormGroup
label="Postleitzahl"
>
<UInput
v-model="itemInfo.infoData.zip"
/>
</UFormGroup>
<UFormGroup
label="Ort"
>
<UInput
v-model="itemInfo.infoData.city"
/>
</UFormGroup>
<UFormGroup
label="Telefon:"
>
<UInput
v-model="itemInfo.infoData.tel"
/>
</UFormGroup>
<UFormGroup
label="E-Mail:"
>
<UInput
v-model="itemInfo.infoData.email"
/>
</UFormGroup>
<UFormGroup
label="Webseite:"
>
<UInput
v-model="itemInfo.infoData.web"
/>
</UFormGroup>
<UFormGroup
label="USt-Id:"
>
<UInput
v-model="itemInfo.infoData.ustid"
/>
</UFormGroup>
<template #footer>
</UCard> <UButton
<UCard v-else-if="mode === 'edit' || mode === 'create'" > v-if="mode == 'edit'"
<template #header v-if="mode === 'edit'"> @click="dataStore.updateItem('vendors',itemInfo)"
{{itemInfo.name}}
</template>
<UFormGroup
label="Name:"
> >
<UInput Speichern
v-model="itemInfo.name" </UButton>
/> <UButton
</UFormGroup> v-else-if="mode == 'create'"
<UFormGroup @click="dataStore.createNewItem('vendors',itemInfo)"
label="Lieferantennr.:"
> >
<UInput Erstellen
v-model="itemInfo.vendorNumber" </UButton>
placeholder="Leer lassen für automatisch generierte Nummer" <UButton
/> @click="cancelEditorCreate"
</UFormGroup> color="red"
<UFormGroup class="ml-2"
label="Straße + Hausnummer"
> >
<UInput Abbrechen
v-model="itemInfo.infoData.street" </UButton>
/> </template>
</UFormGroup>
<UFormGroup
label="Postleitzahl"
>
<UInput
v-model="itemInfo.infoData.zip"
/>
</UFormGroup>
<UFormGroup
label="Ort"
>
<UInput
v-model="itemInfo.infoData.city"
/>
</UFormGroup>
<UFormGroup </UCard>
label="Telefon:"
>
<UInput
v-model="itemInfo.infoData.tel"
/>
</UFormGroup>
<UFormGroup
label="E-Mail:"
>
<UInput
v-model="itemInfo.infoData.email"
/>
</UFormGroup>
<UFormGroup
label="Webseite:"
>
<UInput
v-model="itemInfo.infoData.web"
/>
</UFormGroup>
<UFormGroup
label="USt-Id:"
>
<UInput
v-model="itemInfo.infoData.ustid"
/>
</UFormGroup>
<template #footer>
<UButton
v-if="mode == 'edit'"
@click="dataStore.updateItem('vendors',itemInfo)"
>
Speichern
</UButton>
<UButton
v-else-if="mode == 'create'"
@click="dataStore.createNewItem('vendors',itemInfo)"
>
Erstellen
</UButton>
<UButton
@click="cancelEditorCreate"
color="red"
class="ml-2"
>
Abbrechen
</UButton>
</template>
</UCard>
<HistoryDisplay
type="vendor"
v-if="currentItem"
:element-id="currentItem.id"
/>
</div>
</template> </template>
<style scoped> <style scoped>

View File

@@ -1,26 +1,23 @@
<template> <template>
<div id="main"> <Toolbar>
<!-- TODO: Kontakte erstellen und dem Lieferanten zuweisen --> <UButton @click="router.push(`/vendors/create/`)">+ Lieferant</UButton>
<div class="flex items-center gap-1">
<UButton @click="router.push(`/vendors/create/`)">+ Lieferant</UButton>
<UInput
v-model="searchString"
placeholder="Suche..."
/>
</div>
<UInput
v-model="searchString"
placeholder="Suche..."
/>
</Toolbar>
<div class="table">
<UTable <UTable
:rows="filteredRows" :rows="filteredRows"
:columns="itemColumns" :columns="itemColumns"
@select="selectItem" @select="selectItem"
:empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Noch keine Einträge' }" :empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Noch keine Einträge' }"
/> />
</div> </div>
</template> </template>
<script setup> <script setup>

View File

@@ -87,6 +87,11 @@ export const useDataStore = defineStore('data', () => {
incomingInvoices: { incomingInvoices: {
label: "Eingangsrechnungen", label: "Eingangsrechnungen",
labelSingle: "Eingangsrechnung" labelSingle: "Eingangsrechnung"
},
inventoryitems: {
label: "Inventarartikel",
labelSingle: "Inventarartikel",
redirect: true
} }
} }
@@ -151,12 +156,13 @@ export const useDataStore = defineStore('data', () => {
const accounts = ref([]) const accounts = ref([])
const taxTypes = ref([]) const taxTypes = ref([])
const plants = ref([]) const plants = ref([])
const inventoryItems = ref([]) const inventoryitems = ref([])
const chats = ref([]) const chats = ref([])
const messages = ref([]) const messages = ref([])
const createddocuments = ref([]) const createddocuments = ref([])
const workingtimes = ref([]) const workingtimes = ref([])
const phasesTemplates = ref([]) const phasesTemplates = ref([])
const emailAccounts = ref([])
const rights = ref({ const rights = ref({
@@ -217,13 +223,10 @@ export const useDataStore = defineStore('data', () => {
} }
]) ])
async function initializeData () { async function initializeData (userId) {
//console.log(user.value.id) let profile = (await supabase.from("profiles").select().eq("id",userId).single()).data
let profile = (await supabase.from("profiles").select().eq("id",user.value.id).single()).data
//console.log(profile) currentTenant.value = profile.tenant
currentTenant.value = profile.tenant//profiles.value.find(i => i.id === user.value.id).tenants[0].id
await fetchData() await fetchData()
@@ -273,6 +276,7 @@ export const useDataStore = defineStore('data', () => {
await fetchCreatedDocuments() await fetchCreatedDocuments()
await fetchWorkingTimes() await fetchWorkingTimes()
await fetchPhasesTemplates() await fetchPhasesTemplates()
await fetchEmailAccounts()
loaded.value = true loaded.value = true
} }
@@ -280,7 +284,7 @@ export const useDataStore = defineStore('data', () => {
console.log("Clear") console.log("Clear")
loaded.value = false loaded.value = false
ownTenant.value = {} ownTenant.value = {}
profiles.value= [] profiles.value = []
events.value= [] events.value= []
customers.value= [] customers.value= []
tasks.value= [] tasks.value= []
@@ -307,12 +311,13 @@ export const useDataStore = defineStore('data', () => {
accounts.value = [] accounts.value = []
taxTypes.value = [] taxTypes.value = []
plants.value = [] plants.value = []
inventoryItems.value = [] inventoryitems.value = []
chats.value = [] chats.value = []
messages.value = [] messages.value = []
createddocuments.value = [] createddocuments.value = []
workingtimes.value = [] workingtimes.value = []
phasesTemplates.value = [] phasesTemplates.value = []
emailAccounts.value = []
} }
function hasRight (right) { function hasRight (right) {
@@ -338,13 +343,13 @@ export const useDataStore = defineStore('data', () => {
(payload) => { (payload) => {
//console.log(payload) //console.log(payload)
if(payload.eventType === 'INSERT') { /*if(payload.eventType === 'INSERT') {
const c = payload.table + '.value.push(' + JSON.stringify(payload.new) + ')' const c = payload.table + '.value.push(' + JSON.stringify(payload.new) + ')'
eval(c) eval(c)
} else if(payload.eventType === 'UPDATE'){ } else if(payload.eventType === 'UPDATE'){
const c = payload.table + '.value[' + payload.table + '.value.findIndex(i => i.id === ' + JSON.stringify(payload.old.id) + ')] = ' + JSON.stringify(payload.new) const c = payload.table + '.value[' + payload.table + '.value.findIndex(i => i.id === ' + JSON.stringify(payload.old.id) + ')] = ' + JSON.stringify(payload.new)
eval(c) eval(c)
} }*/
} }
) )
.subscribe() .subscribe()
@@ -371,7 +376,7 @@ export const useDataStore = defineStore('data', () => {
if(supabaseError) { if(supabaseError) {
console.log(supabaseError) console.log(supabaseError)
} else if (supabaseData) { } else if (supabaseData) {
//await eval( dataType + '.value.push(' + JSON.stringify(...supabaseData) + ')') await eval( dataType + '.value.push(' + JSON.stringify(...supabaseData) + ')')
toast.add({title: `${dataTypes[dataType].labelSingle} hinzugefügt`}) toast.add({title: `${dataTypes[dataType].labelSingle} hinzugefügt`})
if(dataTypes[dataType].redirect) await router.push(`/${dataType}/show/${supabaseData[0].id}`) if(dataTypes[dataType].redirect) await router.push(`/${dataType}/show/${supabaseData[0].id}`)
return supabaseData return supabaseData
@@ -396,7 +401,7 @@ export const useDataStore = defineStore('data', () => {
} }
const uploadFiles = async (formData, files, upsert) => { const uploadFiles = async (formData, files, upsert) => {
console.log(files)
let documentsToInsert = [] let documentsToInsert = []
const uploadSingleFile = async (file) => { const uploadSingleFile = async (file) => {
@@ -436,11 +441,13 @@ export const useDataStore = defineStore('data', () => {
} else if( files.length > 1) { } else if( files.length > 1) {
for(let i = 0; i < files.length; i++){ for(let i = 0; i < files.length; i++){
uploadSingleFile(files[i]) await uploadSingleFile(files[i])
} }
} }
console.log(documentsToInsert)
const {data, error} = await supabase const {data, error} = await supabase
.from("documents") .from("documents")
.insert(documentsToInsert) .insert(documentsToInsert)
@@ -464,7 +471,7 @@ export const useDataStore = defineStore('data', () => {
} }
async function fetchProfiles () { async function fetchProfiles () {
profiles.value = (await supabase.from("profiles").select('* , tenants (id, name)')).data profiles.value = (await supabase.from("profiles").select('* , tenants (id, name)')/*.eq("tenant", currentTenant.value)*/.order("fullName")).data
} }
async function fetchBankAccounts () { async function fetchBankAccounts () {
bankAccounts.value = (await supabase.from("bankaccounts").select().eq('tenant', currentTenant.value)).data bankAccounts.value = (await supabase.from("bankaccounts").select().eq('tenant', currentTenant.value)).data
@@ -543,7 +550,7 @@ export const useDataStore = defineStore('data', () => {
plants.value = (await supabase.from("plants").select().eq('tenant', currentTenant.value)).data plants.value = (await supabase.from("plants").select().eq('tenant', currentTenant.value)).data
} }
async function fetchInventoryItems () { async function fetchInventoryItems () {
inventoryItems.value = (await supabase.from("inventoryitems").select().eq('tenant', currentTenant.value)).data inventoryitems.value = (await supabase.from("inventoryitems").select().eq('tenant', currentTenant.value)).data
} }
async function fetchChats() { async function fetchChats() {
chats.value = (await supabase.from("chats").select()).data chats.value = (await supabase.from("chats").select()).data
@@ -563,25 +570,35 @@ export const useDataStore = defineStore('data', () => {
phasesTemplates.value = (await supabase.from("phasesTemplates").select().eq('tenant', currentTenant.value).order('created_at', {ascending:true})).data phasesTemplates.value = (await supabase.from("phasesTemplates").select().eq('tenant', currentTenant.value).order('created_at', {ascending:true})).data
} }
async function fetchEmailAccounts() {
emailAccounts.value = (await supabase.from("emailAccounts").select().eq('tenant', currentTenant.value)).data
}
async function fetchDocuments () { async function fetchDocuments () {
let tempDocuments = (await supabase.from("documents").select().eq('tenant', currentTenant.value)).data let tempDocuments = (await supabase.from("documents").select().eq('tenant', currentTenant.value)).data
let paths = [] if(tempDocuments.length > 0){
tempDocuments.forEach(doc => { let paths = []
paths.push(doc.path) tempDocuments.forEach(doc => {
}) paths.push(doc.path)
})
const {data,error} = await supabase.storage.from('files').createSignedUrls(paths,3600) const {data,error} = await supabase.storage.from('files').createSignedUrls(paths,3600)
tempDocuments = tempDocuments.map((doc,index) => { tempDocuments = tempDocuments.map((doc,index) => {
return {
...doc,
url: data[index].signedUrl
}
})
documents.value = tempDocuments
} else {
documents.value = []
}
return {
...doc,
url: data[index].signedUrl
}
})
documents.value = tempDocuments
} }
async function addHistoryItem(text, user, elementId, resourceType) { async function addHistoryItem(text, user, elementId, resourceType) {
@@ -615,7 +632,8 @@ export const useDataStore = defineStore('data', () => {
}) })
const getOwnProfile = computed(() => { const getOwnProfile = computed(() => {
return profiles.value.find(profile => profile.id === user.value.id) return profiles.value.find(i => i.id === user.value.id)
}) })
const getMovementsBySpace = computed(() => (spaceId) => { const getMovementsBySpace = computed(() => (spaceId) => {
@@ -626,6 +644,18 @@ export const useDataStore = defineStore('data', () => {
return contacts.value.filter(item => item.customer === customerId) return contacts.value.filter(item => item.customer === customerId)
}) })
const getProjectsByCustomerId = computed(() => (customerId) => {
return projects.value.filter(item => item.customer === customerId)
})
const getPlantsByCustomerId = computed(() => (customerId) => {
return plants.value.filter(item => item.customer === customerId)
})
const getContractsByCustomerId = computed(() => (customerId) => {
return contracts.value.filter(item => item.customer === customerId)
})
const getContactsByVendorId = computed(() => (vendorId) => { const getContactsByVendorId = computed(() => (vendorId) => {
return contacts.value.filter(item => item.vendor === vendorId) return contacts.value.filter(item => item.vendor === vendorId)
}) })
@@ -646,6 +676,10 @@ export const useDataStore = defineStore('data', () => {
return documents.value.filter(item => item.vehicle === itemId && !item.tags.includes("Archiviert")) return documents.value.filter(item => item.vehicle === itemId && !item.tags.includes("Archiviert"))
}) })
const getDocumentsByProductId = computed(() => (itemId) => {
return documents.value.filter(item => item.product === itemId && !item.tags.includes("Archiviert"))
})
const getEventsByProjectId = computed(() => (projectId) => { const getEventsByProjectId = computed(() => (projectId) => {
return events.value.filter(item => item.project === projectId) return events.value.filter(item => item.project === projectId)
}) })
@@ -722,7 +756,7 @@ export const useDataStore = defineStore('data', () => {
id: `F-${vehicle.id}` id: `F-${vehicle.id}`
} }
}), }),
...inventoryItems.value.filter(i=> i.usePlanning).map(item => { ...inventoryitems.value.filter(i=> i.usePlanning).map(item => {
return { return {
type: 'Inventar', type: 'Inventar',
title: item.name, title: item.name,
@@ -903,6 +937,10 @@ export const useDataStore = defineStore('data', () => {
return createddocuments.value.find(item => item.id === documentId) return createddocuments.value.find(item => item.id === documentId)
}) })
const getInventoryItemById = computed(() => (itemId) => {
return inventoryitems.value.find(item => item.id === itemId)
})
const getProjectById = computed(() => (itemId) => { const getProjectById = computed(() => (itemId) => {
if(projects.value.find(i => i.id === itemId)) { if(projects.value.find(i => i.id === itemId)) {
let project = projects.value.find(project => project.id === itemId) let project = projects.value.find(project => project.id === itemId)
@@ -961,13 +999,15 @@ export const useDataStore = defineStore('data', () => {
accounts, accounts,
taxTypes, taxTypes,
plants, plants,
inventoryItems, inventoryitems,
chats, chats,
messages, messages,
createddocuments, createddocuments,
workingtimes, workingtimes,
phasesTemplates, phasesTemplates,
emailAccounts,
documentTypesForCreation, documentTypesForCreation,
//Functions //Functions
createNewItem, createNewItem,
updateItem, updateItem,
@@ -1008,11 +1048,15 @@ export const useDataStore = defineStore('data', () => {
getOwnProfile, getOwnProfile,
getMovementsBySpace, getMovementsBySpace,
getContactsByCustomerId, getContactsByCustomerId,
getProjectsByCustomerId,
getPlantsByCustomerId,
getContractsByCustomerId,
getContactsByVendorId, getContactsByVendorId,
getDocumentsByProjectId, getDocumentsByProjectId,
getDocumentsByPlantId, getDocumentsByPlantId,
getDocumentsByContractId, getDocumentsByContractId,
getDocumentsByVehicleId, getDocumentsByVehicleId,
getDocumentsByProductId,
getEventsByProjectId, getEventsByProjectId,
getTimesByProjectId, getTimesByProjectId,
getTasksByProjectId, getTasksByProjectId,
@@ -1045,7 +1089,8 @@ export const useDataStore = defineStore('data', () => {
getProfileById, getProfileById,
getAccountById, getAccountById,
getPlantById, getPlantById,
getCreatedDocumentById getCreatedDocumentById,
getInventoryItemById,
} }