Changes in Document Creation, Calendar, Notifications, Settings

This commit is contained in:
2024-03-04 20:26:30 +01:00
parent 8e69cda09b
commit 8f444bd917
12 changed files with 315 additions and 71 deletions

View File

@@ -4,12 +4,12 @@ import type { Notification } from '~/types'
const { isNotificationsSlideoverOpen } = useDashboard() const { isNotificationsSlideoverOpen } = useDashboard()
const { data: notifications } = await useFetch<Notification[]>('/api/notifications') //const { data: notifications } = await useFetch<Notification[]>('/api/notifications')
</script> </script>
<template> <template>
<UDashboardSlideover v-model="isNotificationsSlideoverOpen" title="Notifications"> <UDashboardSlideover v-model="isNotificationsSlideoverOpen" title="Notifications">
<NuxtLink v-for="notification in notifications" :key="notification.id" :to="`/inbox?id=${notification.id}`" class="p-3 rounded-md hover:bg-gray-50 dark:hover:bg-gray-800/50 cursor-pointer flex items-center gap-3 relative"> <!-- <NuxtLink v-for="notification in notifications" :key="notification.id" :to="`/inbox?id=${notification.id}`" class="p-3 rounded-md hover:bg-gray-50 dark:hover:bg-gray-800/50 cursor-pointer flex items-center gap-3 relative">
<UChip color="red" :show="!!notification.unread" inset> <UChip color="red" :show="!!notification.unread" inset>
<UAvatar v-bind="notification.sender.avatar" :alt="notification.sender.name" size="md" /> <UAvatar v-bind="notification.sender.avatar" :alt="notification.sender.name" size="md" />
</UChip> </UChip>
@@ -24,6 +24,6 @@ const { data: notifications } = await useFetch<Notification[]>('/api/notificatio
{{ notification.body }} {{ notification.body }}
</p> </p>
</div> </div>
</NuxtLink> </NuxtLink>-->
</UDashboardSlideover> </UDashboardSlideover>
</template> </template>

View File

@@ -12,7 +12,7 @@ const _useDashboard = () => {
'g-u': () => router.push('/users'), 'g-u': () => router.push('/users'),
'g-s': () => router.push('/settings'), 'g-s': () => router.push('/settings'),
'?': () => isHelpSlideoverOpen.value = true, '?': () => isHelpSlideoverOpen.value = true,
n: () => isNotificationsSlideoverOpen.value = true n: () => isNotificationsSlideoverOpen.value = !isNotificationsSlideoverOpen.value
}) })
watch(() => route.fullPath, () => { watch(() => route.fullPath, () => {

View File

@@ -593,9 +593,9 @@ export const useCreatePdf = async (invoiceData,backgroundSourceBuffer) => {
invoiceData.rows.forEach((row,index) => { invoiceData.rows.forEach((row,index) => {
if(row.mode === 'free' || row.mode === 'normal'){ if(row.mode !== 'pagebreak'){
pages[pageCounter - 1].drawText(row.pos, { pages[pageCounter - 1].drawText(String(row.pos), {
...getCoordinatesForPDFLib(21,rowHeight, page1), ...getCoordinatesForPDFLib(21,rowHeight, page1),
size:10, size:10,
color:rgb(0,0,0), color:rgb(0,0,0),
@@ -667,7 +667,13 @@ export const useCreatePdf = async (invoiceData,backgroundSourceBuffer) => {
}) })
} }
if(row.description) {
rowHeight += 24
} else {
rowHeight += 14 rowHeight += 14
}
pageIndex += 1 pageIndex += 1

View File

@@ -320,6 +320,18 @@ let links = [
to: "/plants", to: "/plants",
icon: "i-heroicons-clipboard-document" icon: "i-heroicons-clipboard-document"
}, },
{
label: "Einstellungen",
defaultOpen: false,
icon: "i-heroicons-cog-8-tooth",
children: [
{
label: "Nummernkreise",
to: "/settings/numberRanges",
icon: "i-heroicons-clipboard-document-list"
}
]
},
] ]
const actions = [ const actions = [

View File

@@ -13,6 +13,7 @@ definePageMeta({
//Config //Config
const route = useRoute() const route = useRoute()
const router = useRouter()
const mode = ref(route.params.mode || "grid") const mode = ref(route.params.mode || "grid")
const supabase = useSupabaseClient() const supabase = useSupabaseClient()
const dataStore = useDataStore() const dataStore = useDataStore()
@@ -102,7 +103,10 @@ const calendarOptionsGrid = reactive({
newEventData.value.start = info.startStr newEventData.value.start = info.startStr
newEventData.value.end = info.endStr newEventData.value.end = info.endStr
showNewEventModal.value = true //showNewEventModal.value = true
router.push(`/calendar/edit/?start=${info.startStr}&end=${info.endStr}&source=grid`)
}, },
eventClick: function (info){ eventClick: function (info){
selectedEvent.value = info.event selectedEvent.value = info.event
@@ -138,7 +142,9 @@ const calendarOptionsTimeline = reactive({
newEventData.value.end = info.endStr newEventData.value.end = info.endStr
console.log(newEventData.value) console.log(newEventData.value)
convertResourceIds() convertResourceIds()
showNewEventModal.value = true //showNewEventModal.value = true
router.push(`/calendar/edit/?start=${info.startStr}&end=${info.endStr}&resources=${JSON.stringify([info.resource.id])}&source=timeline`)
}, },
eventClick: function (info){ eventClick: function (info){
selectedEvent.value = info.event selectedEvent.value = info.event

View File

@@ -0,0 +1,118 @@
<script setup>
const route = useRoute()
const router = useRouter()
const dataStore = useDataStore()
const itemInfo = ref({
resources: []
})
const setupPage = () => {
if(route.query.start) itemInfo.value.start = route.query.start.replace(" ", "+")
if(route.query.end) itemInfo.value.end = route.query.end.replace(" ", "+")
if(route.query.resources) itemInfo.value.resources = JSON.parse(route.query.resources)
if(route.query.project) itemInfo.value.project = route.query.project
}
setupPage()
</script>
<template>
<UDashboardNavbar title="Neuen Termin erstellen">
<template #right>
<UButton
color="rose"
@click="router.push(`/calendar/${route.query.source}`)"
>
Abbrechen
</UButton>
<UButton
@click="dataStore.createNewItem('events',itemInfo)"
>
Erstellen
</UButton>
</template>
</UDashboardNavbar>
<!-- <UDashboardToolbar>
</UDashboardToolbar>-->
<UForm class="p-5">
<UFormGroup
label="Resource:"
>
<USelectMenu
v-model="itemInfo.resources"
:options="dataStore.getResources"
option-attribute="title"
value-attribute="id"
multiple
@change=""
>
<template #label>
<span v-if="itemInfo.resources.length == 0">Keine Ressourcen ausgewählt</span>
<span v-else >{{ itemInfo.resources.length }} ausgewählt</span>
</template>
</USelectMenu>
</UFormGroup>
<UFormGroup
label="Titel:"
>
<UInput
v-model="itemInfo.title"
/>
</UFormGroup>
<UFormGroup
label="Projekt:"
>
<USelectMenu
v-model="itemInfo.project"
:options="dataStore.projects"
option-attribute="name"
value-attribute="id"
searchable
searchable-placeholder="Suche..."
:search-attributes="['name']"
>
<template #label>
{{dataStore.getProjectById(itemInfo.project) ? dataStore.getProjectById(itemInfo.project).name : "Kein Projekt ausgewählt"}}
</template>
</USelectMenu>
</UFormGroup>
<UFormGroup
label="Typ:"
>
<USelectMenu
v-model="itemInfo.type"
:options="dataStore.getEventTypes"
option-attribute="label"
value-attribute="label"
>
</USelectMenu>
</UFormGroup>
<UFormGroup
label="Start:"
>
<UInput
v-model="itemInfo.start"
/>
</UFormGroup>
<UFormGroup
label="Ende:"
>
<UInput
v-model="itemInfo.end"
/>
</UFormGroup>
</UForm>
</template>
<style scoped>
</style>

View File

@@ -61,6 +61,9 @@ const tabItems = computed(() => {
const setupPage = () => { const setupPage = () => {
if(route.params) { if(route.params) {
if(route.params.id) itemInfo.value = dataStore.getCreatedDocumentById(Number(route.params.id)) if(route.params.id) itemInfo.value = dataStore.getCreatedDocumentById(Number(route.params.id))
if(!itemInfo.value.deliveryDateType) itemInfo.value.deliveryDateType = "Lieferdatum"
} }
if(route.query) { if(route.query) {
@@ -165,6 +168,18 @@ const addPosition = (mode) => {
} }
const editRowDescription = (row) => {
rowToEdit.value = row.description
showEditRowDescription.value = true
}
const showEditRowDescription = ref(false)
const rowToEdit = ref("")
const saveRowDescription = () => {
}
const removePosition = (id) => { const removePosition = (id) => {
let rows = itemInfo.value.rows.filter(row => row.id !== id) let rows = itemInfo.value.rows.filter(row => row.id !== id)
/*rows = rows.sort((a,b) => a.pos - b.pos) /*rows = rows.sort((a,b) => a.pos - b.pos)
@@ -185,7 +200,7 @@ const documentTotal = computed(() => {
let totalGross = 0 let totalGross = 0
itemInfo.value.rows.forEach(row => { itemInfo.value.rows.forEach(row => {
if(row.mode === 'free' || row.mode === 'normal'){ if(row.mode !== 'pagebreak'){
console.log(row) console.log(row)
let rowPrice = Number(Number(row.quantity) * Number(row.price) * (1 - Number(row.discountPercent) /100) ).toFixed(2) let rowPrice = Number(Number(row.quantity) * Number(row.price) * (1 - Number(row.discountPercent) /100) ).toFixed(2)
console.log(rowPrice) console.log(rowPrice)
@@ -222,8 +237,9 @@ const getDocumentData = () => {
let unit = dataStore.units.find(i => i.id === row.unit) let unit = dataStore.units.find(i => i.id === row.unit)
if(row.mode === 'free' || row.mode === 'normal') { if(row.mode !== 'pagebreak') {
if(row.mode === 'normal') row.text = dataStore.getProductById(row.product).name if(row.mode === 'normal') row.text = dataStore.getProductById(row.product).name
if(row.mode === 'service') row.text = dataStore.getServiceById(row.service).name
return { return {
...row, ...row,
@@ -323,6 +339,7 @@ const saveDocument = async () => {
project: itemInfo.value.project, project: itemInfo.value.project,
documentNumber: itemInfo.value.documentNumber, documentNumber: itemInfo.value.documentNumber,
documentDate: itemInfo.value.documentDate, documentDate: itemInfo.value.documentDate,
deliveryDateType: itemInfo.value.deliveryDateType,
info: { info: {
}, },
@@ -595,6 +612,7 @@ setupPage()
<UFormGroup <UFormGroup
label="Projekt:" label="Projekt:"
> >
<InputGroup>
<USelectMenu <USelectMenu
:options="dataStore.projects" :options="dataStore.projects"
v-model="itemInfo.project" v-model="itemInfo.project"
@@ -603,6 +621,7 @@ setupPage()
searchable searchable
searchable-placeholder="Suche..." searchable-placeholder="Suche..."
:search-attributes="['name']" :search-attributes="['name']"
class="w-full"
> >
<template #label> <template #label>
{{dataStore.getProjectById(itemInfo.project) ? dataStore.getProjectById(itemInfo.project).name : "Kein Projekt ausgewählt"}} {{dataStore.getProjectById(itemInfo.project) ? dataStore.getProjectById(itemInfo.project).name : "Kein Projekt ausgewählt"}}
@@ -611,6 +630,13 @@ setupPage()
{{dataStore.getCustomerById(project.customer).name}} - {{project.name}} {{dataStore.getCustomerById(project.customer).name}} - {{project.name}}
</template> </template>
</USelectMenu> </USelectMenu>
<UButton
variant="outline"
v-if="itemInfo.project"
icon="i-heroicons-arrow-right-end-on-rectangle"
>Projekt</UButton>
</InputGroup>
</UFormGroup> </UFormGroup>
</div> </div>
@@ -674,12 +700,13 @@ setupPage()
<tr> <tr>
<th></th> <th></th>
<th>Pos.</th> <th>Pos.</th>
<th>Produkt / Leistung</th> <th>Name</th>
<th>Menge</th> <th>Menge</th>
<th>Einheit</th> <th>Einheit</th>
<th>Preis</th> <th>Preis</th>
<th>Steuer</th> <th>Steuer</th>
<th>Rabatt</th> <th>Rabatt</th>
<th>Beschreibung</th>
<th>Gesamt</th> <th>Gesamt</th>
</tr> </tr>
</thead> </thead>
@@ -704,7 +731,7 @@ setupPage()
</td> </td>
<td <td
v-if="row.mode === 'pagebreak'" v-if="row.mode === 'pagebreak'"
colspan="8" colspan="9"
> >
<UDivider/> <UDivider/>
</td> </td>
@@ -788,6 +815,7 @@ setupPage()
</USelectMenu> </USelectMenu>
</td> </td>
<td <td
class="w-40"
v-if="row.mode !== 'pagebreak'" v-if="row.mode !== 'pagebreak'"
> >
<UInput <UInput
@@ -833,6 +861,37 @@ setupPage()
</template> </template>
</UInput> </UInput>
</td> </td>
<td
class="w-40"
v-if="row.mode !== 'pagebreak'"
>
<UButton
icon="i-heroicons-document-text"
@click="showEditRowDescription = true"
/>
<UModal v-model="showEditRowDescription">
<UCard>
<template #header>
Beschreibung bearbeiten
</template>
<UTextarea
v-model="row.description"
>
</UTextarea>
<template #footer>
<UButton
@click="showEditRowDescription = false"
>
Speichern
</UButton>
</template>
</UCard>
</UModal>
</td>
<td <td
v-if="row.mode !== 'pagebreak'" v-if="row.mode !== 'pagebreak'"
> >

View File

@@ -18,24 +18,38 @@ setupPage()
</script> </script>
<template> <template>
<UDashboardNavbar
title="Erstelltes Dokument anzeigen"
>
<InputGroup> </UDashboardNavbar>
<UDashboardToolbar>
<template #left>
<UButton <UButton
@click="router.push(`/createDocument/edit/${itemInfo.id}`)" @click="router.push(`/createDocument/edit/${itemInfo.id}`)"
> >
Bearbeiten Bearbeiten
</UButton> </UButton>
</InputGroup> <UButton
<DevOnly> :to="dataStore.documents.find(i => i.createdDocument === itemInfo.id) ? dataStore.documents.find(i => i.createdDocument === itemInfo.id).url : ''"
{{itemInfo}} target="_blank"
</DevOnly> >In neuen Tab anzeigen</UButton>
</template>
</UDashboardToolbar>
<object
:data="dataStore.documents.find(i => i.createdDocument === itemInfo.id) ? dataStore.documents.find(i => i.createdDocument === itemInfo.id).url : ''"
<DocumentDisplay class="h-full"
:document-data="dataStore.documents.find(i => i.createdDocument === itemInfo.id)"
/> />
<!-- <DocumentDisplay
:document-data="dataStore.documents.find(i => i.createdDocument === itemInfo.id)"
/>-->
</template> </template>
<style scoped> <style scoped>

View File

@@ -187,10 +187,10 @@ setupPage()
/> />
</UFormGroup> </UFormGroup>
<UFormGroup <UFormGroup
label="Einkaufspreis:" label="Verkaufspreis:"
> >
<UInput <UInput
v-model="itemInfo.purchasePrice" v-model="itemInfo.sellingPrice"
type="number" type="number"
steps="0.01" steps="0.01"
> >

View File

@@ -339,6 +339,35 @@ setupPage()
</UButton> </UButton>
</Toolbar> </Toolbar>
<UTable
:rows="dataStore.getCreatedDocumentsByProject(currentItem.id)"
:columns="[
{
label: 'Typ',
key: 'type'
}, {
label: 'Status',
key: 'state'
}, {
label: 'Dokumentennummer',
key: 'documentNumber'
}, {
label: 'Ansprechpartner',
key: 'createdBy'
}
]"
@select="(row) => row.state === 'Entwurf' ? router.push(`/createDocument/edit/${row.id}`) : router.push(`/createDocument/show/${row.id}`)"
>
<template #type-data="{row}">
<span v-if="row.type === 'invoices'">Rechnung</span>
<span v-if="row.type === 'quotes'">Angebot</span>
<span v-if="row.type === 'deliveryNotes'">Lieferschein</span>
</template>
<template #createdBy-data="{row}">
{{dataStore.getProfileById(row.createdBy).fullName}}
</template>
</UTable>
<DocumentList :documents="dataStore.getDocumentsByProjectId(currentItem.id)"/> <DocumentList :documents="dataStore.getDocumentsByProjectId(currentItem.id)"/>

View File

@@ -56,19 +56,14 @@ const updateNumberRange = async (range) => {
</script> </script>
<template> <template>
<UModal <UDashboardToolbar>
v-model="showAddModal"
>
</UModal>
<UAlert <UAlert
title="Änderungen an diesen Werten betreffen nur neu Erstellte Einträge." title="Änderungen an diesen Werten betreffen nur neu Erstellte Einträge."
color="rose" color="rose"
variant="outline" variant="outline"
icon="i-heroicons-exclamation-triangle" icon="i-heroicons-exclamation-triangle"
/> />
</UDashboardToolbar>
<UTable <UTable
:rows="dataStore.numberRanges" :rows="dataStore.numberRanges"
@@ -96,10 +91,6 @@ const updateNumberRange = async (range) => {
/> />
</template> </template>
</UTable> </UTable>
<DevOnly>
{{dataStore.numberRanges}}
</DevOnly>
</template> </template>
<style scoped> <style scoped>

View File

@@ -98,6 +98,10 @@ export const useDataStore = defineStore('data', () => {
labelSingle: "Leistung", labelSingle: "Leistung",
redirect: true redirect: true
}, },
events: {
label: "Termine",
labelSingle: "Termin"
},
} }
const documentTypesForCreation = ref({ const documentTypesForCreation = ref({
@@ -461,7 +465,7 @@ export const useDataStore = defineStore('data', () => {
} else if (data) { } else if (data) {
const returnPath = data.path const returnPath = data.path
documentsToInsert.push({...formData, path: returnPath}) documentsToInsert.push({...formData, path: returnPath, tenant: currentTenant.value})
} }
console.log(data) console.log(data)
@@ -766,6 +770,10 @@ export const useDataStore = defineStore('data', () => {
return texttemplates.value.filter(i => i.documentType === documentType) return texttemplates.value.filter(i => i.documentType === documentType)
}) })
const getCreatedDocumentsByProject = computed(() => (project) => {
return createddocuments.value.filter(i => i.project === project)
})
const getStockByProductId = computed(() => (productId) => { const getStockByProductId = computed(() => (productId) => {
let productMovements = movements.value.filter(movement => movement.productId === productId) let productMovements = movements.value.filter(movement => movement.productId === productId)
@@ -1127,6 +1135,7 @@ export const useDataStore = defineStore('data', () => {
getMovementsBySpaceId, getMovementsBySpaceId,
getMessagesByChatId, getMessagesByChatId,
getTextTemplatesByDocumentType, getTextTemplatesByDocumentType,
getCreatedDocumentsByProject,
getStockByProductId, getStockByProductId,
getIncomingInvoicesByVehicleId, getIncomingInvoicesByVehicleId,
getEventTypes, getEventTypes,