This commit is contained in:
2024-10-18 08:58:11 +02:00
parent 8dbf43b672
commit a905b1f966
9 changed files with 165 additions and 70 deletions

18
composables/useSort.js Normal file
View File

@@ -0,0 +1,18 @@
export const useSort = (items,column,direction) => {
if(!searchString) {
return items
}
return items.filter(i => JSON.stringify(i).toLowerCase().includes(searchString.toLowerCase()))
}

View File

@@ -102,7 +102,7 @@ export const useCreateWorkingTimesPdf = async (input,backgroundSourceBuffer) =>
y: getCoordinatesForPDFLib(20,70,pages[pageCounter -1]).y, y: getCoordinatesForPDFLib(20,70,pages[pageCounter -1]).y,
size: 10, size: 10,
}) })
pages[pageCounter - 1].drawText(`Bestätigt: ${Math.floor(input.sumWorkingMinutesApproved/60)}:${String(input.sumWorkingMinutesApproved % 60).padStart(2,"0")} Std`,{ /*pages[pageCounter - 1].drawText(`Bestätigt: ${Math.floor(input.sumWorkingMinutesApproved/60)}:${String(input.sumWorkingMinutesApproved % 60).padStart(2,"0")} Std`,{
x: getCoordinatesForPDFLib(20,75,pages[pageCounter -1]).x, x: getCoordinatesForPDFLib(20,75,pages[pageCounter -1]).x,
y: getCoordinatesForPDFLib(20,75,pages[pageCounter -1]).y, y: getCoordinatesForPDFLib(20,75,pages[pageCounter -1]).y,
size: 10, size: 10,
@@ -149,10 +149,10 @@ export const useCreateWorkingTimesPdf = async (input,backgroundSourceBuffer) =>
x: getCoordinatesForPDFLib(100,110,pages[pageCounter -1]).x, x: getCoordinatesForPDFLib(100,110,pages[pageCounter -1]).x,
y: getCoordinatesForPDFLib(100,110,pages[pageCounter -1]).y, y: getCoordinatesForPDFLib(100,110,pages[pageCounter -1]).y,
size: 10, size: 10,
}) })*/
let rowHeight = 115 let rowHeight = 85
input.times.forEach(time => { input.times.forEach(time => {
pages[pageCounter - 1].drawText(`${dayjs(time.startDate).format("HH:mm DD.MM.YY")}`,{ pages[pageCounter - 1].drawText(`${dayjs(time.startDate).format("HH:mm DD.MM.YY")}`,{
@@ -161,7 +161,7 @@ export const useCreateWorkingTimesPdf = async (input,backgroundSourceBuffer) =>
size: 10, size: 10,
}) })
pages[pageCounter - 1].drawText(`${dayjs(time.startDate).format("HH:mm DD.MM.YY")}`,{ pages[pageCounter - 1].drawText(`${dayjs(time.endDate).format("HH:mm DD.MM.YY")}`,{
x: getCoordinatesForPDFLib(60,rowHeight,pages[pageCounter -1]).x, x: getCoordinatesForPDFLib(60,rowHeight,pages[pageCounter -1]).x,
y: getCoordinatesForPDFLib(60,rowHeight,pages[pageCounter -1]).y, y: getCoordinatesForPDFLib(60,rowHeight,pages[pageCounter -1]).y,
size: 10, size: 10,

View File

@@ -102,7 +102,7 @@
<span v-if="row.documentDate">{{row.documentDate ? dayjs(row.documentDate).format("DD.MM.YY") : ''}}</span> <span v-if="row.documentDate">{{row.documentDate ? dayjs(row.documentDate).format("DD.MM.YY") : ''}}</span>
</template> </template>
<template #dueDate-data="{row}"> <template #dueDate-data="{row}">
<span :class="dayjs(row.dueDate).diff(dayjs()) <= 0 ? ['text-rose-500'] : '' ">{{row.dueDate ? dayjs(row.dueDate).format("DD.MM.YY") : ''}}</span> <span v-if="row.paymentDays && ['invoices','advanceInvoices'].includes(row.type)" :class="dayjs(row.documentDate).add(row.paymentDays,'day').diff(dayjs()) <= 0 && !isPaid(row) ? ['text-rose-500'] : '' ">{{row.documentDate ? dayjs(row.documentDate).add(row.paymentDays,'day').format("DD.MM.YY") : ''}}</span>
</template> </template>
<template #paid-data="{row}"> <template #paid-data="{row}">
<div v-if="row.type === 'invoices' ||row.type === 'advanceInvoices'"> <div v-if="row.type === 'invoices' ||row.type === 'advanceInvoices'">
@@ -179,7 +179,7 @@ const templateColumns = [
sortable: true sortable: true
},{ },{
key: 'state', key: 'state',
label: "Status.", label: "Status",
sortable: true sortable: true
}, },
{ {
@@ -199,14 +199,14 @@ const templateColumns = [
}, },
{ {
key: "paid", key: "paid",
label: "Bezahlt:", label: "Bezahlt",
sortable: true sortable: true
}, },
{ {
key: "dueDate", key: "dueDate",
label: "Fällig:", label: "Fällig",
sortable: true sortable: true
}, }
] ]
const selectedColumns = ref(templateColumns) const selectedColumns = ref(templateColumns)
const columns = computed(() => templateColumns.filter((column) => selectedColumns.value.includes(column))) const columns = computed(() => templateColumns.filter((column) => selectedColumns.value.includes(column)))

View File

@@ -304,6 +304,19 @@ setupPage()
v-model="itemInfo.barcode" v-model="itemInfo.barcode"
/> />
</UFormGroup>--> </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>
<UFormGroup <UFormGroup
label="Verkaufspreis:" label="Verkaufspreis:"
> >

View File

@@ -1,4 +1,5 @@
<script setup> <script setup>
import axios from "axios"
import HistoryDisplay from "~/components/HistoryDisplay.vue"; import HistoryDisplay from "~/components/HistoryDisplay.vue";
import dayjs from "dayjs"; import dayjs from "dayjs";
import customParseFormat from "dayjs/plugin/customParseFormat"; import customParseFormat from "dayjs/plugin/customParseFormat";

View File

@@ -0,0 +1,29 @@
<script setup>
const dataStore = useDataStore()
const setupPage = async () => {
console.log()
}
</script>
<template>
<UDashboardNavbar
title="Eigene Felder"
>
</UDashboardNavbar>
{{dataStore.ownTenant.ownFields}}
</template>
<style scoped>
</style>

View File

@@ -17,12 +17,19 @@ dayjs.extend(isSameOrBefore)
const dataStore = useDataStore() const dataStore = useDataStore()
const supabase = useSupabaseClient() const supabase = useSupabaseClient()
const route = useRoute() const route = useRoute()
const router = useRouter()
const itemInfo = ref({}) const itemInfo = ref({})
const oldItemInfo = ref({}) const oldItemInfo = ref({})
const setupPage = () => {
const workingtimes = ref([])
const setupPage = async () => {
if(route.params.id) itemInfo.value = dataStore.getProfileById(route.params.id) if(route.params.id) itemInfo.value = dataStore.getProfileById(route.params.id)
if(itemInfo.value.id) oldItemInfo.value = JSON.parse(JSON.stringify(itemInfo.value)) if(itemInfo.value.id) oldItemInfo.value = JSON.parse(JSON.stringify(itemInfo.value))
workingtimes.value = (await supabase.from("workingtimes").select().eq("profile",itemInfo.value.id).order("startDate",{ascending:false})).data
} }
const selectedPresetRange = ref("Dieser Monat") const selectedPresetRange = ref("Dieser Monat")
@@ -58,11 +65,12 @@ const changeRange = () => {
selectedStartDay.value = dayjs().subtract(subtract,selector === "isoWeek" ? "week" : selector).startOf(selector).format("YYYY-MM-DD") selectedStartDay.value = dayjs().subtract(subtract,selector === "isoWeek" ? "week" : selector).startOf(selector).format("YYYY-MM-DD")
selectedEndDay.value = dayjs().subtract(subtract,selector === "isoWeek" ? "week" : selector).endOf(selector).format("YYYY-MM-DD") selectedEndDay.value = dayjs().subtract(subtract,selector === "isoWeek" ? "week" : selector).endOf(selector).format("YYYY-MM-DD")
openTab.value = 0
} }
const workingTimeInfo = computed(() => { const workingTimeInfo = computed(() => {
let times = dataStore.getWorkingTimesByProfileId(route.params.id) let times = workingtimes.value
//times = times.filter(i => dayjs(i.date).isBetween(dayjs(selectedStartDay.value).subtract(1,"days"),selectedEndDay.value,'day') && i.end) //times = times.filter(i => dayjs(i.date).isBetween(dayjs(selectedStartDay.value).subtract(1,"days"),selectedEndDay.value,'day') && i.end)
times = times.filter(i => dayjs(i.startDate).isSameOrAfter(selectedStartDay.value) && dayjs(i.endDate).isSameOrBefore(selectedEndDay.value)) times = times.filter(i => dayjs(i.startDate).isSameOrAfter(selectedStartDay.value) && dayjs(i.endDate).isSameOrBefore(selectedEndDay.value))
@@ -133,6 +141,12 @@ const generateEvaluation = async () => {
await generateDocument() await generateDocument()
} }
const openTab = ref(0)
const onTabChange = async (index) => {
if(index === 1) {
await generateEvaluation()
}
}
setupPage() setupPage()
@@ -208,7 +222,7 @@ changeRange()
/> />
<template #panel="{ close }"> <template #panel="{ close }">
<LazyDatePicker v-model="selectedStartDay" @close="changeRange" /> <LazyDatePicker v-model="selectedStartDay" @close="openTab = 0" />
</template> </template>
</UPopover> </UPopover>
</UFormGroup> </UFormGroup>
@@ -220,42 +234,46 @@ changeRange()
/> />
<template #panel="{ close }"> <template #panel="{ close }">
<LazyDatePicker v-model="selectedEndDay" @close="changeRange" /> <LazyDatePicker v-model="selectedEndDay" @close="openTab = 0" />
</template> </template>
</UPopover> </UPopover>
</UFormGroup> </UFormGroup>
</template> </template>
<template #right>
<UButton
@click="generateEvaluation"
>
Bericht erstellen
</UButton>
</template>
</UDashboardToolbar> </UDashboardToolbar>
<UTabs <UTabs
:items="[{label: 'Information'},{label: 'Bericht'}]" :items="[{label: 'Information'},{label: 'Bericht'}]"
class="p-5 h-100" class="p-5 h-100"
@change="onTabChange"
v-model="openTab"
> >
<template #item="{item}"> <template #item="{item}">
<div v-if="item.label === 'Information'"> <div v-if="item.label === 'Information'">
<div class="truncate p-5"> <UCard class="truncate my-5">
<template #header>
Zusammenfassung
</template>
<p>Eingreicht: {{Math.floor(workingTimeInfo.sumWorkingMinutesEingereicht/60)}}:{{String(workingTimeInfo.sumWorkingMinutesEingereicht % 60).padStart(2,"0")}} h</p> <p>Eingreicht: {{Math.floor(workingTimeInfo.sumWorkingMinutesEingereicht/60)}}:{{String(workingTimeInfo.sumWorkingMinutesEingereicht % 60).padStart(2,"0")}} h</p>
<p>Bestätigt: {{Math.floor(workingTimeInfo.sumWorkingMinutesApproved/60)}}:{{String(workingTimeInfo.sumWorkingMinutesApproved % 60).padStart(2,"0")}} h</p> <p>Bestätigt: {{Math.floor(workingTimeInfo.sumWorkingMinutesApproved/60)}}:{{String(workingTimeInfo.sumWorkingMinutesApproved % 60).padStart(2,"0")}} h</p>
<p>Soll Stunden: {{workingTimeInfo.monthlyWorkingHours}} h</p> <p>Soll Stunden: {{workingTimeInfo.monthlyWorkingHours}} h</p>
<p>Abwesend: </p> <!-- <p>Abwesend: </p>
<p>Ausgleich:</p>
<p>Ausgleich:</p>
-->
<p>Inoffizielles Saldo: {{workingTimeInfo.saldoInOfficial}} h</p> <p>Inoffizielles Saldo: {{workingTimeInfo.saldoInOfficial}} h</p>
<p>Saldo: {{workingTimeInfo.saldo}} h</p> <p>Saldo: {{workingTimeInfo.saldo}} h</p>
</div> </UCard>
<div style="overflow-y: scroll; height: 45vh">
<UTable <UTable
:rows="dataStore.getWorkingTimesByProfileId(itemInfo.id)" :rows="workingTimeInfo.times"
:columns="[ @select="(row) => router.push(`/workingtimes/edit/${row.id}`)"
:columns="[
{ {
key: 'state', key: 'state',
label: 'Status' label: 'Status'
}, {
key: 'approved',
label: 'Genehmigt'
}, { }, {
key: 'start', key: 'start',
label: 'Start' label: 'Start'
@@ -270,26 +288,34 @@ changeRange()
label: 'Notizen' label: 'Notizen'
} }
]" ]"
> >
<template #profile-data="{row}"> <template #profile-data="{row}">
{{dataStore.profiles.find(profile => profile.id === row.profile) ? dataStore.profiles.find(profile => profile.id === row.profile).fullName : row.profile }} {{dataStore.profiles.find(profile => profile.id === row.profile) ? dataStore.profiles.find(profile => profile.id === row.profile).fullName : row.profile }}
</template> </template>
<template #approved-data="{row}">
<span v-if="row.approved" class="text-primary-500">Ja</span>
<span v-else class="text-rose-600">Nein</span>
</template>
<template #start-data="{row}">
{{dayjs(row.startDate).format("HH:mm DD.MM.YY")}} Uhr
</template>
<template #end-data="{row}">
{{dayjs(row.endDate).format("HH:mm DD.MM.YY")}} Uhr
</template>
<template #duration-data="{row}">
{{getDuration(row).composed}}
</template>
</UTable>
</div>
<template #start-data="{row}">
{{dayjs(row.startDate).format("HH:mm DD.MM.YY")}} Uhr
</template>
<template #end-data="{row}">
{{dayjs(row.endDate).format("HH:mm DD.MM.YY")}} Uhr
</template>
<template #duration-data="{row}">
{{getDuration(row).composed}}
</template>
</UTable>
</div> </div>
<div v-else-if="item.label === 'Bericht'"> <div v-else-if="item.label === 'Bericht'">
<UProgress animation="carousel" v-if="!showDocument"/>
<object <object
:data="uri" :data="uri"
v-if="showDocument" v-else
type="application/pdf" type="application/pdf"
class="w-full previewDocument" class="w-full previewDocument"
/> />

View File

@@ -24,10 +24,22 @@ const timeInfo = ref({
const filterUser = ref(dataStore.activeProfile.id || "") const filterUser = ref(dataStore.activeProfile.id || "")
const workingtimes = ref([])
const setupPage = async () => {
workingtimes.value = (await supabase.from("workingtimes").select().eq("profile",filterUser.value).order("startDate",{ascending: false})).data
}
setupPage()
const filteredRows = computed(() => { const filteredRows = computed(() => {
let times = dataStore.workingtimes let times = workingtimes.value
times = times.filter(i => i.profile === filterUser.value) times = times.filter(i => i.profile === filterUser.value)
@@ -61,6 +73,11 @@ const columns = [
label: "Status", label: "Status",
sortable:true sortable:true
}, },
{
key: "approved",
label: "Genehmigt",
sortable:true
},
{ {
key: "profile", key: "profile",
label: "Mitarbeiter", label: "Mitarbeiter",
@@ -181,6 +198,7 @@ const getDuration = (time) => {
option-attribute="fullName" option-attribute="fullName"
value-attribute="id" value-attribute="id"
v-model="filterUser" v-model="filterUser"
@change="setupPage"
> >
<template #label> <template #label>
{{dataStore.getProfileById(filterUser) ? dataStore.getProfileById(filterUser).fullName : "Kein Benutzer ausgewählt"}} {{dataStore.getProfileById(filterUser) ? dataStore.getProfileById(filterUser).fullName : "Kein Benutzer ausgewählt"}}
@@ -222,41 +240,29 @@ const getDuration = (time) => {
</UAlert> </UAlert>
</div> </div>
<UTable <UTable
class="mt-3" class="mt-3"
:columns="columns" :columns="columns"
:rows="filteredRows" :rows="filteredRows"
: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' }"
@select="(row) => { @select="(row) => {
router.push(`/workingtimes/edit/${row.id}`) router.push(`/workingtimes/edit/${row.id}`)}"
/*configTimeMode = '[mode]';
itemInfo = row;
showConfigTimeModal = true*/}"
> >
<!-- <template #state-data="{row}"> <template #expand="{ row }">
<span <div class="p-4">
v-if="row.state === 'Entwurf'" <pre>{{ row }}</pre>
class="text-rose-500" </div>
>{{row.state}}</span> </template>
<span
v-if="row.state === 'Eingereicht'"
class="text-cyan-500"
>{{row.state}}</span>
<span
v-if="row.state === 'Bestätigt'"
class="text-primary-500"
>{{row.state}}</span>
</template>-->
<template #profile-data="{row}"> <template #profile-data="{row}">
{{dataStore.profiles.find(profile => profile.id === row.profile) ? dataStore.profiles.find(profile => profile.id === row.profile).fullName : row.profile }} {{dataStore.profiles.find(profile => profile.id === row.profile) ? dataStore.profiles.find(profile => profile.id === row.profile).fullName : row.profile }}
</template> </template>
<template #approved-data="{row}">
<span v-if="row.approved" class="text-primary-500">Ja</span>
<span v-else class="text-rose-600">Nein</span>
</template>
<template #date-data="{row}"> <template #date-data="{row}">
{{dayjs(row.startDate).format("DD.MM.YYYY")}} {{dayjs(row.startDate).format("DD.MM.YYYY")}}
</template> </template>
<template #startDate-data="{row}"> <template #startDate-data="{row}">
{{dayjs(row.startDate).format("HH:mm")}} Uhr {{dayjs(row.startDate).format("HH:mm")}} Uhr
</template> </template>

View File

@@ -123,7 +123,9 @@ export const useDataStore = defineStore('data', () => {
}, },
workingtimes: { workingtimes: {
label: "Anwesenheiten", label: "Anwesenheiten",
labelSingle: "Anwesenheit" labelSingle: "Anwesenheit",
redirect: true,
redirectToList: true
}, },
texttemplates: { texttemplates: {
label: "Textvorlagen", label: "Textvorlagen",
@@ -887,7 +889,7 @@ export const useDataStore = defineStore('data', () => {
//await eval(dataType + '.value[' + dataType + '.value.findIndex(i => i.id === ' + JSON.stringify(data.id) + ')] = ' + JSON.stringify(supabaseData[0])) //await eval(dataType + '.value[' + dataType + '.value.findIndex(i => i.id === ' + JSON.stringify(data.id) + ')] = ' + JSON.stringify(supabaseData[0]))
if(dataType === 'profiles') await fetchProfiles() if(dataType === 'profiles') await fetchProfiles()
toast.add({title: `${dataTypes[dataType].labelSingle} gespeichert`}) toast.add({title: `${dataTypes[dataType].labelSingle} gespeichert`})
if(dataTypes[dataType].redirect) await router.push(`/${dataType}/show/${data.id}`) if(dataTypes[dataType].redirect) await router.push(dataTypes[dataType].redirectToList ? `/${dataType}` : `/${dataType}/show/${data.id}`)
return supabaseData return supabaseData
} }
} }
@@ -1244,7 +1246,7 @@ export const useDataStore = defineStore('data', () => {
}) })
const getTextTemplatesByDocumentType = computed(() => (documentType) => { const getTextTemplatesByDocumentType = computed(() => (documentType) => {
console.log(documentType) //console.log(documentType)
let type = "" let type = ""
if(documentType === "serialInvoices") { if(documentType === "serialInvoices") {
@@ -1253,7 +1255,7 @@ export const useDataStore = defineStore('data', () => {
type = documentType type = documentType
} }
console.log(type) //console.log(type)
return texttemplates.value.filter(i => i.documentType === type) return texttemplates.value.filter(i => i.documentType === type)
}) })