Many Changes
This commit is contained in:
@@ -70,17 +70,17 @@ const cancelEditorCreate = () => {
|
||||
}
|
||||
}
|
||||
|
||||
const updateCustomer = async () => {
|
||||
const updateItem = async () => {
|
||||
const {error} = await supabase
|
||||
.from("contacts")
|
||||
.update(itemInfo.value)
|
||||
.eq('id',itemInfo.value.id)
|
||||
console.log(error)
|
||||
mode.value = "show"
|
||||
itemInfo.value = {
|
||||
id: 0,
|
||||
name: "",
|
||||
|
||||
if(error) {
|
||||
console.log(error)
|
||||
}
|
||||
|
||||
router.push(`/contacts/show/${currentContact.id}`)
|
||||
toast.add({title: "Kontakt erfolgreich gespeichert"})
|
||||
dataStore.fetchContacts()
|
||||
}
|
||||
@@ -261,7 +261,7 @@ setupPage()
|
||||
<template #footer>
|
||||
<UButton
|
||||
v-if="mode == 'edit'"
|
||||
@click="updateCustomer"
|
||||
@click="updateItem"
|
||||
>
|
||||
Speichern
|
||||
</UButton>
|
||||
|
||||
@@ -71,17 +71,16 @@ const cancelEditorCreate = () => {
|
||||
}
|
||||
}
|
||||
|
||||
const updateCustomer = async () => {
|
||||
const updateItem = async () => {
|
||||
const {error} = await supabase
|
||||
.from("contracts")
|
||||
.update(itemInfo.value)
|
||||
.eq('id',itemInfo.value.id)
|
||||
console.log(error)
|
||||
mode.value = "show"
|
||||
itemInfo.value = {
|
||||
id: 0,
|
||||
name: "",
|
||||
if(error) {
|
||||
console.log(error)
|
||||
}
|
||||
|
||||
router.push(`/contracts/show/${currentContract.id}`)
|
||||
toast.add({title: "Vertrag erfolgreich gespeichert"})
|
||||
dataStore.fetchContracts()
|
||||
}
|
||||
@@ -192,7 +191,7 @@ setupPage()
|
||||
<template #footer>
|
||||
<UButton
|
||||
v-if="mode == 'edit'"
|
||||
@click="updateCustomer"
|
||||
@click="updateItem"
|
||||
>
|
||||
Speichern
|
||||
</UButton>
|
||||
|
||||
@@ -81,14 +81,12 @@ const updateCustomer = async () => {
|
||||
.from("customers")
|
||||
.update(customerInfo.value)
|
||||
.eq('id',customerInfo.value.id)
|
||||
console.log(error)
|
||||
mode.value = "show"
|
||||
customerInfo.value = {
|
||||
id: 0,
|
||||
name: "",
|
||||
infoData: {}
|
||||
|
||||
if(error) {
|
||||
console.log(error)
|
||||
}
|
||||
toast.add({title: "Kunde erfolgreich gespeichert"})
|
||||
router.push(`/customers/show/${currentCustomer.id}`)
|
||||
dataStore.fetchCustomers()
|
||||
}
|
||||
|
||||
@@ -121,7 +119,14 @@ setupPage()
|
||||
/>
|
||||
|
||||
Informationen:<br>
|
||||
{{currentCustomer.infoData}}<br>
|
||||
<div v-if="currentCustomer.infoData">
|
||||
<span v-if="currentCustomer.infoData.street">Straße + Hausnummer: {{currentCustomer.infoData.street}}<br></span>
|
||||
<span v-if="currentCustomer.infoData.zip && currentCustomer.infoData.city">PLZ + Ort: {{currentCustomer.infoData.zip}} {{currentCustomer.infoData.city}}<br></span>
|
||||
<span v-if="currentCustomer.infoData.tel">Telefon: {{currentCustomer.infoData.tel}}<br></span>
|
||||
<span v-if="currentCustomer.infoData.email">E-Mail: {{currentCustomer.infoData.email}}<br></span>
|
||||
<span v-if="currentCustomer.infoData.web">Web: {{currentCustomer.infoData.web}}<br></span>
|
||||
<span v-if="currentCustomer.infoData.ustid">USt-Id: {{currentCustomer.infoData.ustid}}<br></span>
|
||||
</div>
|
||||
|
||||
<UDivider
|
||||
class="my-2"
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
<script setup>
|
||||
import { BlobReader, BlobWriter, ZipWriter } from "@zip.js/zip.js";
|
||||
|
||||
const downloadFolder = async (folder) => {
|
||||
const supabaseClient = useSupabaseClient();
|
||||
|
||||
const bucket = "documents";
|
||||
|
||||
// Get a list of all the files in the path /my-bucket/images
|
||||
/*const { data: files, error } = await supabaseClient.storage
|
||||
.from(bucket)
|
||||
.list(folder);
|
||||
|
||||
if (error) {
|
||||
throw error;
|
||||
}*/
|
||||
|
||||
let files = [
|
||||
"1/Eingang/Rechnung_VRB170A0249604_2023-12-06.pdf"
|
||||
]
|
||||
|
||||
console.log(files)
|
||||
|
||||
// If there are no files in the folder, throw an error
|
||||
if (!files || !files.length) {
|
||||
throw new Error("No files to download");
|
||||
}
|
||||
|
||||
const promises = [];
|
||||
|
||||
// Download each file in the folder
|
||||
files.forEach((file) => {
|
||||
promises.push(
|
||||
supabaseClient.storage.from(bucket).download(`${file}`)
|
||||
);
|
||||
});
|
||||
|
||||
// Wait for all the files to download
|
||||
const response = await Promise.allSettled(promises);
|
||||
|
||||
// Map the response to an array of objects containing the file name and blob
|
||||
const downloadedFiles = response.map((result, index) => {
|
||||
if (result.status === "fulfilled") {
|
||||
return {
|
||||
name: files[index],
|
||||
blob: result.value.data,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
// Create a new zip file
|
||||
const zipFileWriter = new BlobWriter("application/zip");
|
||||
const zipWriter = new ZipWriter(zipFileWriter, { bufferedWrite: true });
|
||||
|
||||
// Add each file to the zip file
|
||||
downloadedFiles.forEach((downloadedFile) => {
|
||||
if (downloadedFile) {
|
||||
zipWriter.add(downloadedFile.name, new BlobReader(downloadedFile.blob));
|
||||
}
|
||||
});
|
||||
|
||||
// Download the zip file
|
||||
const url = URL.createObjectURL(await zipWriter.close());
|
||||
const link = document.createElement("a");
|
||||
|
||||
link.href = url;
|
||||
link.setAttribute("download", "documents.zip");
|
||||
|
||||
document.body.appendChild(link);
|
||||
|
||||
link.click();
|
||||
}
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<UButton
|
||||
@click="downloadFolder('1/Eingang')"
|
||||
>
|
||||
Download
|
||||
</UButton>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
256
spaces/pages/employees/absenceRequests/[mode]/[[id]].vue
Normal file
256
spaces/pages/employees/absenceRequests/[mode]/[[id]].vue
Normal file
@@ -0,0 +1,256 @@
|
||||
<script setup>
|
||||
import dayjs from "dayjs";
|
||||
|
||||
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 = null
|
||||
|
||||
//Working
|
||||
const mode = ref(route.params.mode || "show")
|
||||
const itemInfo = ref({
|
||||
approved: null
|
||||
})
|
||||
const states = ["Offen","Genehmigt", "Abgelehnt"]
|
||||
|
||||
const absenceReasons = [
|
||||
"Elternzeit",
|
||||
"Kind krank - Kinderbetreuung",
|
||||
"Krankheit",
|
||||
"Krankheit 1 Tag (mit Attest)",
|
||||
"Krankheit ab 2. Tag (mit Attest)",
|
||||
"Mutterschutz",
|
||||
"Sonderurlaub (bezahlt)",
|
||||
"Überstundenausgleich",
|
||||
"Unbezahlter Urlaub",
|
||||
"Urlaub"
|
||||
]
|
||||
|
||||
//Functions
|
||||
const setupPage = () => {
|
||||
if(mode.value === "show" || mode.value === "edit"){
|
||||
currentItem = dataStore.getAbsenceRequestById(Number(useRoute().params.id))
|
||||
}
|
||||
|
||||
if(mode.value === "edit") itemInfo.value = currentItem
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
const createItem = async () => {
|
||||
const {data,error} = await supabase
|
||||
.from("absenceRequests")
|
||||
.insert([itemInfo.value])
|
||||
.select()
|
||||
|
||||
if(error) {
|
||||
console.log(error)
|
||||
} else {
|
||||
mode.value = "show"
|
||||
itemInfo.value = {
|
||||
id: 0,
|
||||
}
|
||||
toast.add({title: "Abwesenheit erfolgreich erstellt"})
|
||||
await dataStore.fetchAbsenceRequests()
|
||||
router.push(`/employees/absenceRequests/show/${data[0].id}`)
|
||||
setupPage()
|
||||
}
|
||||
}
|
||||
|
||||
const editItem = async () => {
|
||||
router.push(`/employees/absenceRequests/edit/${currentItem.id}`)
|
||||
setupPage()
|
||||
}
|
||||
|
||||
const cancelEditorCreate = () => {
|
||||
mode.value = "show"
|
||||
itemInfo.value = {
|
||||
id: 0,
|
||||
infoData: {}
|
||||
}
|
||||
}
|
||||
|
||||
const updateItem = async () => {
|
||||
const {error} = await supabase
|
||||
.from("absenceRequests")
|
||||
.update(itemInfo.value)
|
||||
.eq('id',itemInfo.value.id)
|
||||
|
||||
if(error) {
|
||||
console.log(error)
|
||||
}
|
||||
|
||||
|
||||
router.push(`/employees/absenceRequests/show/${currentItem.id}`)
|
||||
toast.add({title: "Abwesenheit erfolgreich gespeichert"})
|
||||
dataStore.fetchAbsenceRequests()
|
||||
}
|
||||
|
||||
|
||||
|
||||
setupPage()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<UCard v-if="currentItem && mode == 'show'" >
|
||||
<template #header>
|
||||
<UBadge
|
||||
v-if="currentItem.approved === 'Offen'"
|
||||
color="blue"
|
||||
>{{currentItem.approved}}</UBadge>
|
||||
<UBadge
|
||||
v-else-if="currentItem.approved === 'Genehmigt'"
|
||||
color="primary"
|
||||
>{{currentItem.approved}}</UBadge>
|
||||
<UBadge
|
||||
v-else-if="currentItem.approved === 'Abgelehnt'"
|
||||
color="rose"
|
||||
>{{currentItem.approved}}</UBadge>
|
||||
|
||||
|
||||
|
||||
{{currentItem.reason}}
|
||||
</template>
|
||||
|
||||
<span>Mitarbeiter: {{dataStore.profiles.find(item => item.id === currentItem.user) ? dataStore.profiles.find(item => item.id === currentItem.user).fullName : ""}}<br></span>
|
||||
<span>Start: {{dayjs(currentItem.start).format("DD.MM.YYYY")}}<br></span>
|
||||
<span>Ende: {{dayjs(currentItem.end).format("DD.MM.YYYY")}}<br></span>
|
||||
|
||||
Notizen:<br>
|
||||
{{currentItem.note}}<br>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<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'" >
|
||||
<template #header v-if="mode === 'edit'">
|
||||
{{itemInfo.reason}}
|
||||
</template>
|
||||
|
||||
<UFormGroup
|
||||
label="Status:"
|
||||
>
|
||||
<USelectMenu
|
||||
v-model="itemInfo.approved"
|
||||
:options="states"
|
||||
option-attribute="label"
|
||||
value-attribute="value"
|
||||
/>
|
||||
</UFormGroup>
|
||||
|
||||
<UFormGroup
|
||||
label="Grund:"
|
||||
>
|
||||
<USelectMenu
|
||||
v-model="itemInfo.reason"
|
||||
:options="absenceReasons"
|
||||
/>
|
||||
</UFormGroup>
|
||||
|
||||
<UFormGroup
|
||||
label="Mitarbeiter:"
|
||||
>
|
||||
<USelectMenu
|
||||
v-model="itemInfo.user"
|
||||
:options="dataStore.profiles"
|
||||
option-attribute="fullName"
|
||||
value-attribute="id"
|
||||
searchable
|
||||
:search-attributes="['fullName']"
|
||||
>
|
||||
<template #label>
|
||||
{{dataStore.profiles.find(item => item.id === itemInfo.user) ? dataStore.profiles.find(item => item.id === itemInfo.user).fullName : "Mitarbeiter auswählen"}}
|
||||
</template>
|
||||
</USelectMenu>
|
||||
</UFormGroup>
|
||||
|
||||
<UFormGroup label="Start:">
|
||||
<UPopover :popper="{ placement: 'bottom-start' }">
|
||||
<UButton icon="i-heroicons-calendar-days-20-solid" :label="itemInfo.start ? dayjs(itemInfo.start).format('DD.MM.YYYY') : 'Datum auswählen'" />
|
||||
|
||||
<template #panel="{ close }">
|
||||
<LazyDatePicker v-model="itemInfo.start" @close="close" />
|
||||
</template>
|
||||
</UPopover>
|
||||
</UFormGroup>
|
||||
|
||||
<UFormGroup label="Ende:">
|
||||
<UPopover :popper="{ placement: 'bottom-start' }">
|
||||
<UButton icon="i-heroicons-calendar-days-20-solid" :label="itemInfo.end ? dayjs(itemInfo.end).format('DD.MM.YYYY') : 'Datum auswählen'" />
|
||||
|
||||
<template #panel="{ close }">
|
||||
<LazyDatePicker v-model="itemInfo.end" @close="close" />
|
||||
</template>
|
||||
</UPopover>
|
||||
</UFormGroup>
|
||||
|
||||
|
||||
<UFormGroup
|
||||
label="Notizen:"
|
||||
>
|
||||
<UTextarea
|
||||
v-model="itemInfo.note"
|
||||
/>
|
||||
</UFormGroup>
|
||||
|
||||
|
||||
<template #footer>
|
||||
<UButton
|
||||
v-if="mode == 'edit'"
|
||||
@click="updateItem"
|
||||
>
|
||||
Speichern
|
||||
</UButton>
|
||||
<UButton
|
||||
v-else-if="mode == 'create'"
|
||||
@click="createItem"
|
||||
>
|
||||
Erstellen
|
||||
</UButton>
|
||||
<UButton
|
||||
@click="cancelEditorCreate"
|
||||
color="red"
|
||||
class="ml-2"
|
||||
>
|
||||
Abbrechen
|
||||
</UButton>
|
||||
</template>
|
||||
|
||||
</UCard>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
84
spaces/pages/employees/absenceRequests/index.vue
Normal file
84
spaces/pages/employees/absenceRequests/index.vue
Normal file
@@ -0,0 +1,84 @@
|
||||
<template>
|
||||
<div id="main">
|
||||
|
||||
<UButton @click="router.push(`/employees/absenceRequests/create/`)">+ Abwesenheit</UButton>
|
||||
|
||||
<UTable
|
||||
:rows="dataStore.absenceRequests"
|
||||
:columns="columns"
|
||||
@select="selectItem"
|
||||
:empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Noch keine Einträge' }"
|
||||
>
|
||||
<template #approved-data="{row}">
|
||||
<span v-if="!row.approved">
|
||||
Genehmigung offen
|
||||
</span>
|
||||
<span
|
||||
v-else-if="row.approved"
|
||||
class="text-primary"
|
||||
>
|
||||
Genemigt
|
||||
</span>
|
||||
<span
|
||||
v-else
|
||||
class="text-rose"
|
||||
>
|
||||
Abgelehnt
|
||||
</span>
|
||||
</template>
|
||||
<template #user-data="{row}">
|
||||
{{dataStore.profiles.find(profile => profile.id === row.user) ? dataStore.profiles.find(profile => profile.id === row.user).fullName : ""}}
|
||||
</template>
|
||||
</UTable>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
||||
definePageMeta({
|
||||
middleware: "auth"
|
||||
})
|
||||
|
||||
const dataStore = useDataStore()
|
||||
const router = useRouter()
|
||||
const mode = ref("show")
|
||||
|
||||
const columns = [
|
||||
{
|
||||
key: "approved",
|
||||
label: "Genehmigt",
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
key: "user",
|
||||
label: "Mitarbeiter",
|
||||
sortable: true
|
||||
},{
|
||||
key: "reason",
|
||||
label: "Grund",
|
||||
sortable: true
|
||||
},{
|
||||
key: "start",
|
||||
label: "Start",
|
||||
sortable: true
|
||||
},{
|
||||
key: "end",
|
||||
label: "Ende",
|
||||
sortable: true
|
||||
},{
|
||||
key: "note",
|
||||
label: "Notizen",
|
||||
sortable: true
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
const selectItem = (item) => {
|
||||
router.push(`/employees/absenceRequests/show/${item.id} `)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -3,60 +3,71 @@ definePageMeta({
|
||||
middleware: "auth"
|
||||
})
|
||||
|
||||
|
||||
const dataStore = useDataStore()
|
||||
const supabase = useSupabaseClient()
|
||||
|
||||
const {spaces, movements, products} = storeToRefs(useDataStore())
|
||||
|
||||
|
||||
const searchinput = ref("")
|
||||
const mode = ref("")
|
||||
|
||||
const router = useRouter()
|
||||
const mode = ref("incoming")
|
||||
const toast = useToast()
|
||||
const showReader = ref(false)
|
||||
|
||||
const inventoryChangeData = ref({
|
||||
productId: "",
|
||||
spaceId: "",
|
||||
quantity: 0
|
||||
quantity: 1
|
||||
})
|
||||
|
||||
const createMovement = async () => {
|
||||
if(mode.value === 'incoming'){
|
||||
//await create('movements', inventoryChangeData.value)
|
||||
|
||||
const {data,error} = await supabase
|
||||
.from("movements")
|
||||
.insert([inventoryChangeData.value])
|
||||
.select()
|
||||
if(mode.value === '' || !checkSpaceId(inventoryChangeData.value.spaceId) || !checkArticle(inventoryChangeData.value.productId)){
|
||||
|
||||
console.log(error)
|
||||
} else {
|
||||
if(mode.value === 'incoming'){
|
||||
|
||||
const {error} = await supabase
|
||||
.from("movements")
|
||||
.insert([inventoryChangeData.value])
|
||||
.select()
|
||||
if(error) console.log(error)
|
||||
|
||||
|
||||
} else if (mode.value === 'outgoing'){
|
||||
inventoryChangeData.value.quantity *= -1
|
||||
//await create('movements', inventoryChangeData.value)
|
||||
} else if (mode.value === 'outgoing'){
|
||||
inventoryChangeData.value.quantity *= -1
|
||||
|
||||
const {data,error} = await supabase
|
||||
.from("movements")
|
||||
.insert([inventoryChangeData.value])
|
||||
.select()
|
||||
const {error} = await supabase
|
||||
.from("movements")
|
||||
.insert([inventoryChangeData.value])
|
||||
.select()
|
||||
if(error) console.log(error)
|
||||
} else if (mode.value === 'change'){}
|
||||
|
||||
console.log(error)
|
||||
} else if (mode.value === 'change'){}
|
||||
|
||||
inventoryChangeData.value = {
|
||||
productId: 0,
|
||||
spaceId: 0,
|
||||
quantity: 0
|
||||
inventoryChangeData.value = {
|
||||
productId: "",
|
||||
spaceId: "",
|
||||
quantity: 1
|
||||
}
|
||||
|
||||
|
||||
dataStore.fetchMovements()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
defineShortcuts({
|
||||
meta_enter: {
|
||||
usingInput: true,
|
||||
handler: () => {
|
||||
createMovement()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
function checkArticle(productId) {
|
||||
return products.value.filter(product =>product.ean === productId).length > 0;
|
||||
return dataStore.products.filter(product =>product.id === productId).length > 0;
|
||||
}
|
||||
function checkSpaceId(spaceId) {
|
||||
return spaces.value.filter(space => Number(space.spaceNumber) === Number(spaceId)).length > 0;
|
||||
return dataStore.spaces.filter(space => space.id === spaceId).length > 0;
|
||||
}
|
||||
|
||||
function changeFocusToSpaceId() {
|
||||
@@ -73,42 +84,66 @@ function changeFocusToQuantity() {
|
||||
<div id="main">
|
||||
|
||||
<div class="my-3">
|
||||
<UButton @click="mode = 'incoming'" class="ml-3" >Wareneingang</UButton>
|
||||
<UButton @click="mode = 'outgoing'" class="ml-1">Warenausgang</UButton>
|
||||
<UButton @click="mode = 'change'" class="ml-1" disabled>Umlagern</UButton>
|
||||
<UButton
|
||||
@click="mode = 'incoming'"
|
||||
class="ml-3"
|
||||
:variant="mode === 'incoming' ? 'solid' : 'outline'"
|
||||
>Wareneingang</UButton>
|
||||
<UButton
|
||||
@click="mode = 'outgoing'"
|
||||
class="ml-1"
|
||||
:variant="mode === 'outgoing' ? 'solid' : 'outline'"
|
||||
>Warenausgang</UButton>
|
||||
<!-- <UButton
|
||||
@click="mode = 'change'"
|
||||
class="ml-1"
|
||||
disabled
|
||||
:variant="mode === 'change' ? 'solid' : 'outline'"
|
||||
>Umlagern</UButton>-->
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<UFormGroup
|
||||
label="Artikel:"
|
||||
class="mt-3 w-80"
|
||||
>
|
||||
<UInput
|
||||
<USelectMenu
|
||||
:options="dataStore.products"
|
||||
option-attribute="name"
|
||||
value-attribute="id"
|
||||
variant="outline"
|
||||
searchable
|
||||
:search-attributes="['name','ean', 'barcode']"
|
||||
:color="checkArticle(inventoryChangeData.productId) ? 'primary' : 'rose'"
|
||||
v-model="inventoryChangeData.productId"
|
||||
v-on:keyup.enter="changeFocusToSpaceId"
|
||||
/>
|
||||
v-on:select="changeFocusToSpaceId"
|
||||
>
|
||||
<template #label>
|
||||
{{dataStore.products.find(product => product.id === inventoryChangeData.productId) ? dataStore.products.find(product => product.id === inventoryChangeData.productId).name : "Bitte Artikel auswählen"}}
|
||||
</template>
|
||||
</USelectMenu>
|
||||
</UFormGroup>
|
||||
|
||||
<UFormGroup
|
||||
label="Lagerplatz:"
|
||||
class="mt-3 w-80"
|
||||
><!--.map(space => {return {id: space.id, name: space.spaceNumber}}-->
|
||||
<!-- <USelectMenu
|
||||
:options="spaces"
|
||||
>
|
||||
<USelectMenu
|
||||
:options="dataStore.spaces"
|
||||
searchable
|
||||
option-attribute="spaceNumber"
|
||||
option-attribute="description"
|
||||
:color="checkSpaceId(inventoryChangeData.spaceId) ? 'primary' : 'rose'"
|
||||
v-model="inventoryChangeData.spaceId"
|
||||
v-on:select="changeFocusToQuantity"
|
||||
value-attribute="id"
|
||||
/>-->
|
||||
<UInput
|
||||
v-model="inventoryChangeData.spaceId"
|
||||
:color="checkSpaceId(inventoryChangeData.spaceId) ? 'primary' : 'rose'"
|
||||
id="spaceIdInput"
|
||||
v-on:keyup.enter="changeFocusToQuantity"
|
||||
/>
|
||||
>
|
||||
<template #label>
|
||||
{{dataStore.spaces.find(space => space.id === inventoryChangeData.spaceId) ? dataStore.spaces.find(space => space.id === inventoryChangeData.spaceId).description : "Kein Lagerplatz ausgewählt"}}
|
||||
</template>
|
||||
</USelectMenu>
|
||||
</UFormGroup>
|
||||
|
||||
<UFormGroup
|
||||
|
||||
@@ -5,7 +5,7 @@ definePageMeta({
|
||||
middleware: "auth"
|
||||
})
|
||||
|
||||
//
|
||||
const dataStore = useDataStore()
|
||||
const supabase = useSupabaseClient()
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
@@ -13,9 +13,6 @@ const toast = useToast()
|
||||
const id = ref(route.params.id ? route.params.id : null )
|
||||
const numberRange = useNumberRange("spaces")
|
||||
|
||||
//Store
|
||||
const {spaces,movements,products,units,ownTenant, numberRanges} = storeToRefs(useDataStore())
|
||||
const {fetchSpaces, getSpaceById, movementsBySpace, getProductById, fetchNumberRanges} = useDataStore()
|
||||
|
||||
|
||||
let currentItem = ref(null)
|
||||
@@ -26,7 +23,7 @@ const mode = ref(route.params.mode || "show")
|
||||
const itemInfo = ref({
|
||||
spaceNumber: ""
|
||||
})
|
||||
const spaceTypes = ["Regalplatz", "Kiste", "Palettenplatz"]
|
||||
const spaceTypes = ["Regalplatz", "Kiste", "Palettenplatz", "Sonstiges"]
|
||||
const spaceProducts = ref([])
|
||||
const spaceMovements = ref([])
|
||||
|
||||
@@ -34,12 +31,12 @@ const spaceMovements = ref([])
|
||||
const setupPage = async () => {
|
||||
console.log("Called Setup")
|
||||
if(mode.value === "show" || mode.value === "edit"){
|
||||
currentItem.value = await getSpaceById(Number(useRoute().params.id))
|
||||
currentItem.value = await dataStore.getSpaceById(Number(useRoute().params.id))
|
||||
|
||||
spaceMovements.value = await movementsBySpace(currentItem.value.id)
|
||||
spaceMovements.value = await dataStore.getMovementsBySpace(currentItem.value.id)
|
||||
spaceProducts.value = []
|
||||
spaceMovements.value.forEach(movement => {
|
||||
if(spaceProducts.value.filter(product => product.id === movement.productId).length === 0) spaceProducts.value.push(getProductById(movement.productId))
|
||||
if(spaceProducts.value.filter(product => product.id === movement.productId).length === 0) spaceProducts.value.push(dataStore.getProductById(movement.productId))
|
||||
})
|
||||
|
||||
}
|
||||
@@ -63,7 +60,7 @@ const createItem = async () => {
|
||||
console.log(data[0])
|
||||
mode.value = "show"
|
||||
toast.add({title: "Lagerplatz erfolgreich erstellt"})
|
||||
await fetchSpaces()
|
||||
await dataStore.fetchSpaces()
|
||||
router.push(`/inventory/spaces/show/${data[0].id}`)
|
||||
|
||||
|
||||
@@ -93,7 +90,7 @@ const updateItem = async () => {
|
||||
mode.value = "show"
|
||||
itemInfo.value = {}
|
||||
toast.add({title: "Lagerplatz erfolgreich gespeichert"})
|
||||
fetchSpaces()
|
||||
dataStore.fetchSpaces()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,7 +108,7 @@ const printSpaceLabel = async () => {
|
||||
|
||||
|
||||
axios
|
||||
.post(`http://${ownTenant.value.labelPrinterIp}/pstprnt`, `^XA^FO10,20^BCN,100^FD${currentItem.value.spaceNumber}^XZ` )
|
||||
.post(`http://${dataStore.ownTenant.value.labelPrinterIp}/pstprnt`, `^XA^FO10,20^BCN,100^FD${currentItem.value.spaceNumber}^XZ` )
|
||||
.then(console.log)
|
||||
.catch(console.log)
|
||||
}
|
||||
@@ -149,7 +146,7 @@ setupPage()
|
||||
<tr v-for="product in spaceProducts">
|
||||
<td>{{product.name}}</td>
|
||||
<td>{{getSpaceProductCount(product.id)}}</td>
|
||||
<td>{{units.find(unit => unit.id === product.unit).name}}</td>
|
||||
<td>{{dataStore.units.find(unit => unit.id === product.unit).name}}</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
@@ -72,12 +72,13 @@ const updateItem = async () => {
|
||||
.from("jobs")
|
||||
.update(itemInfo.value)
|
||||
.eq('id',itemInfo.value.id)
|
||||
console.log(error)
|
||||
mode.value = "show"
|
||||
itemInfo.value = {
|
||||
id: 0,
|
||||
title: ""
|
||||
|
||||
if(error) {
|
||||
console.log(error)
|
||||
}
|
||||
|
||||
|
||||
router.push(`/jobs/show/${currentItem.id}`)
|
||||
toast.add({title: "Job erfolgreich gespeichert"})
|
||||
dataStore.fetchJobs()
|
||||
}
|
||||
|
||||
@@ -8,7 +8,11 @@
|
||||
:columns="columns"
|
||||
@select="selectJob"
|
||||
:empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Noch keine Einträge' }"
|
||||
/>
|
||||
>
|
||||
<template #customer-data="{row}">
|
||||
{{dataStore.customers.find(customer => customer.id === row.customer) ? dataStore.customers.find(customer => customer.id === row.customer).name : "" }}
|
||||
</template>
|
||||
</UTable>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -4,6 +4,7 @@ import resourceTimelinePlugin from '@fullcalendar/resource-timeline'
|
||||
import deLocale from '@fullcalendar/core/locales/de'
|
||||
import interactionPlugin from '@fullcalendar/interaction'
|
||||
import listPlugin from '@fullcalendar/list';
|
||||
import dayjs from "dayjs";
|
||||
|
||||
|
||||
const viewport = useViewport()
|
||||
@@ -19,6 +20,7 @@ const eventTypes = dataStore.getEventTypes
|
||||
const events = dataStore.getEvents
|
||||
|
||||
const openNewEventModal = ref(false)
|
||||
const showEventModal = ref(false)
|
||||
const newEventData = ref({
|
||||
resourceId: "",
|
||||
resourceType: "",
|
||||
@@ -27,6 +29,9 @@ const newEventData = ref({
|
||||
start: "",
|
||||
end: null
|
||||
})
|
||||
|
||||
const selectedEvent = ref({})
|
||||
|
||||
const createEvent = async () => {
|
||||
const {data,error} = await supabase
|
||||
.from("events")
|
||||
@@ -76,6 +81,9 @@ const calendarOptionsTimeline = reactive({
|
||||
openNewEventModal.value = true
|
||||
},
|
||||
eventClick: function (info){
|
||||
selectedEvent.value = info.event
|
||||
showEventModal.value = true
|
||||
|
||||
console.log(info)
|
||||
},
|
||||
resourceGroupField: "type",
|
||||
@@ -153,7 +161,28 @@ const calendarOptionsTimeline = reactive({
|
||||
|
||||
</UCard>
|
||||
</UModal>
|
||||
<UModal
|
||||
v-model="showEventModal"
|
||||
>
|
||||
<UCard>
|
||||
<template #header>
|
||||
{{selectedEvent.title}}
|
||||
</template>
|
||||
|
||||
Start: {{dayjs(selectedEvent.startStr).format("DD.MM.YYYY HH:mm")}}<br>
|
||||
Ende: {{dayjs(selectedEvent.endStr).format("DD.MM.YYYY HH:mm")}}
|
||||
|
||||
<DevOnly>
|
||||
<UDivider class="my-3"/>
|
||||
{{selectedEvent}}
|
||||
</DevOnly>
|
||||
|
||||
|
||||
|
||||
</UCard>
|
||||
|
||||
|
||||
</UModal>
|
||||
<div v-if="viewport.isLessThan('tablet')">
|
||||
<FullCalendar
|
||||
:options="calendarOptionsList"
|
||||
|
||||
@@ -107,10 +107,12 @@ setupPage()
|
||||
{{tag}}
|
||||
</UBadge>
|
||||
|
||||
|
||||
|
||||
<UDivider
|
||||
class="my-2"
|
||||
/>
|
||||
|
||||
<span v-if="currentProduct.purchasePrice">Einkaufspreis: {{Number(currentProduct.purchasePrice).toFixed(2)}} €<br></span>
|
||||
Bestand: {{dataStore.getStockByProductId(currentProduct.id)}} {{dataStore.units.find(unit => unit.id === currentProduct.unit) ? dataStore.units.find(unit => unit.id === currentProduct.unit).name : ""}}
|
||||
|
||||
<DevOnly>
|
||||
@@ -193,6 +195,26 @@ setupPage()
|
||||
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"
|
||||
>
|
||||
<template #trailing>
|
||||
<span class="text-gray-500 dark:text-gray-400 text-xs">EUR</span>
|
||||
</template>
|
||||
</UInput>
|
||||
</UFormGroup>
|
||||
|
||||
|
||||
<template #footer>
|
||||
|
||||
@@ -18,6 +18,12 @@
|
||||
@select="selectItem"
|
||||
:empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Noch keine Einträge' }"
|
||||
>
|
||||
<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 : "")}`}}
|
||||
</template>
|
||||
<template #purchasePrice-data="{row}">
|
||||
{{row.purchasePrice ? Number(row.purchasePrice).toFixed(2) + " €" : ""}}
|
||||
</template>
|
||||
<template #tags-data="{row}">
|
||||
<UBadge
|
||||
v-if="row.tags.length > 0"
|
||||
@@ -48,24 +54,33 @@ const router = useRouter()
|
||||
|
||||
const itemColumns = [
|
||||
{
|
||||
key: "id",
|
||||
label: "Id"
|
||||
key: "stock",
|
||||
label: "Bestand"
|
||||
},
|
||||
{
|
||||
key: "name",
|
||||
label: "Name"
|
||||
label: "Name",
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
key: "manufacturer",
|
||||
label: "Hersteller",
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
key: "unit",
|
||||
label: "Einheit"
|
||||
label: "Einheit",
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
key: "purchasePrice",
|
||||
label: "Einkaufspreis",
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
key: "tags",
|
||||
label: "Tags"
|
||||
label: "Tags",
|
||||
sortable: true
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
@@ -8,10 +8,16 @@ import * as dayjs from 'dayjs'
|
||||
const supabase = useSupabaseClient()
|
||||
const user = useSupabaseUser()
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const dataStore = useDataStore()
|
||||
|
||||
|
||||
const {getProjectById, getFormSubmitsWithLabelProp, getTimesByProjectId, getDocumentTags, getDocumentsByProjectId, fetchDocuments} = useDataStore()
|
||||
const {forms, formSubmits, times, profiles,documents} = storeToRefs(useDataStore())
|
||||
|
||||
|
||||
|
||||
|
||||
fetchDocuments()
|
||||
const currentProject = getProjectById(Number(route.params.id))
|
||||
|
||||
@@ -74,6 +80,9 @@ const tabItems = [
|
||||
{
|
||||
key: "phases",
|
||||
label: "Phasen"
|
||||
},{
|
||||
key: "tasks",
|
||||
label: "Aufgaben"
|
||||
},{
|
||||
key: "forms",
|
||||
label: "Formulare"
|
||||
@@ -235,6 +244,17 @@ const phaseInfo = ref({
|
||||
</a>
|
||||
</div>-->
|
||||
|
||||
</div>
|
||||
<div v-if="item.key === 'tasks'" class="space-y-3">
|
||||
<UTable
|
||||
:rows="dataStore.getTasksByProjectId(currentProject.id)"
|
||||
@select="(row) => {
|
||||
router.push(`/tasks/show/${row.id}`)
|
||||
}"
|
||||
>
|
||||
|
||||
</UTable>
|
||||
|
||||
</div>
|
||||
<div v-else-if="item.key === 'forms'" class="space-y-3">
|
||||
<UButton
|
||||
|
||||
@@ -31,6 +31,9 @@ const resources = {
|
||||
vendors: {
|
||||
label: "Lieferanten"
|
||||
},
|
||||
products: {
|
||||
label: "Artikel"
|
||||
},
|
||||
spaces: {
|
||||
label: "Lagerplätze"
|
||||
}
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
definePageMeta({
|
||||
middleware: "auth"
|
||||
})
|
||||
const dataStore = useDataStore()
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
{{dataStore.profiles}}
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
206
spaces/pages/settings/users/[mode]/[[id]].vue
Normal file
206
spaces/pages/settings/users/[mode]/[[id]].vue
Normal file
@@ -0,0 +1,206 @@
|
||||
<script setup>
|
||||
definePageMeta({
|
||||
middleware: "auth"
|
||||
})
|
||||
|
||||
|
||||
//TODO: Build User Page
|
||||
|
||||
|
||||
|
||||
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 = null
|
||||
|
||||
//Working
|
||||
const mode = ref(route.params.mode || "show")
|
||||
const itemInfo = ref({})
|
||||
|
||||
//Functions
|
||||
const setupPage = () => {
|
||||
if(mode.value === "show" || mode.value === "edit"){
|
||||
currentItem = dataStore.getProfileById(useRoute().params.id)
|
||||
}
|
||||
|
||||
if(mode.value === "edit") itemInfo.value = currentItem
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/*const createItem = async () => {
|
||||
const {data,error} = await supabase
|
||||
.from("profiles")
|
||||
.insert([itemInfo.value])
|
||||
.select()
|
||||
|
||||
if(error) {
|
||||
console.log(error)
|
||||
} else {
|
||||
mode.value = "show"
|
||||
itemInfo.value = {
|
||||
id: 0,
|
||||
title: "",
|
||||
}
|
||||
toast.add({title: "Job erfolgreich erstellt"})
|
||||
await dataStore.fetchJobs()
|
||||
router.push(`/jobs/show/${data[0].id}`)
|
||||
setupPage()
|
||||
}
|
||||
}*/
|
||||
|
||||
const editItem = async () => {
|
||||
router.push(`/users/edit/${currentItem.id}`)
|
||||
setupPage()
|
||||
}
|
||||
|
||||
const cancelEditorCreate = () => {
|
||||
mode.value = "show"
|
||||
itemInfo.value = {
|
||||
id: 0,
|
||||
infoData: {}
|
||||
}
|
||||
}
|
||||
|
||||
const updateItem = async () => {
|
||||
const {error} = await supabase
|
||||
.from("jobs")
|
||||
.update(itemInfo.value)
|
||||
.eq('id',itemInfo.value.id)
|
||||
|
||||
if(error) {
|
||||
console.log(error)
|
||||
}
|
||||
|
||||
|
||||
router.push(`/jobs/show/${currentItem.id}`)
|
||||
toast.add({title: "Job erfolgreich gespeichert"})
|
||||
dataStore.fetchJobs()
|
||||
}
|
||||
|
||||
|
||||
|
||||
setupPage()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<UCard v-if="currentItem && mode == 'show'" >
|
||||
<template #header>
|
||||
<UBadge>
|
||||
{{currentItem.state}}
|
||||
</UBadge>
|
||||
|
||||
{{currentItem.title}}
|
||||
</template>
|
||||
|
||||
Beschreibung:<br>
|
||||
{{currentItem.description}}<br>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<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'" >
|
||||
<template #header>
|
||||
{{itemInfo.title}}
|
||||
</template>
|
||||
|
||||
<UFormGroup
|
||||
label="Titel:"
|
||||
>
|
||||
<UInput
|
||||
v-model="itemInfo.title"
|
||||
/>
|
||||
</UFormGroup>
|
||||
|
||||
<UFormGroup
|
||||
label="Status:"
|
||||
>
|
||||
<USelectMenu
|
||||
v-model="itemInfo.state"
|
||||
:options="states"
|
||||
/>
|
||||
</UFormGroup>
|
||||
|
||||
<UFormGroup
|
||||
label="Kundennummer:"
|
||||
>
|
||||
<USelectMenu
|
||||
v-model="itemInfo.customer"
|
||||
:options="dataStore.customers"
|
||||
option-attribute="name"
|
||||
value-attribute="id"
|
||||
searchable
|
||||
: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="Beschreibung:"
|
||||
>
|
||||
<UTextarea
|
||||
v-model="itemInfo.description"
|
||||
/>
|
||||
</UFormGroup>
|
||||
|
||||
|
||||
<template #footer>
|
||||
<UButton
|
||||
v-if="mode == 'edit'"
|
||||
@click="updateItem"
|
||||
>
|
||||
Speichern
|
||||
</UButton>
|
||||
<UButton
|
||||
v-else-if="mode == 'create'"
|
||||
@click="createItem"
|
||||
>
|
||||
Erstellen
|
||||
</UButton>
|
||||
<UButton
|
||||
@click="cancelEditorCreate"
|
||||
color="red"
|
||||
class="ml-2"
|
||||
>
|
||||
Abbrechen
|
||||
</UButton>
|
||||
</template>
|
||||
|
||||
</UCard>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
51
spaces/pages/settings/users/index.vue
Normal file
51
spaces/pages/settings/users/index.vue
Normal file
@@ -0,0 +1,51 @@
|
||||
<script setup lang="ts">
|
||||
definePageMeta({
|
||||
middleware: "auth"
|
||||
})
|
||||
const dataStore = useDataStore()
|
||||
const router = useRouter()
|
||||
|
||||
const columns = [
|
||||
{
|
||||
key:"id",
|
||||
label: "Id"
|
||||
},
|
||||
{
|
||||
key:"firstName",
|
||||
label: "Vorname:",
|
||||
},
|
||||
{
|
||||
key: "lastName",
|
||||
label: "Nachname:"
|
||||
},
|
||||
{
|
||||
key: "username",
|
||||
label: "Benutzername"
|
||||
},
|
||||
{
|
||||
key: "role",
|
||||
label: "Rolle"
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
<UTable
|
||||
:rows="dataStore.profiles"
|
||||
:columns="columns"
|
||||
@select="(item) => router.push(`/settings/users/show/${item.id}`)"
|
||||
>
|
||||
|
||||
</UTable>
|
||||
|
||||
<DevOnly>
|
||||
{{dataStore.profiles}}
|
||||
</DevOnly>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -45,8 +45,7 @@
|
||||
:options="dataStore.profiles"
|
||||
value-attribute="id"
|
||||
option-attribute="fullName"
|
||||
v-model="createTaskData.users"
|
||||
multiple
|
||||
v-model="createTaskData.user"
|
||||
/>
|
||||
</UFormGroup>
|
||||
|
||||
@@ -87,6 +86,19 @@
|
||||
v-model="taskData.categorie"
|
||||
/>
|
||||
</UFormGroup>
|
||||
<UFormGroup
|
||||
label="Projekt:"
|
||||
>
|
||||
<USelectMenu
|
||||
:options="dataStore.projects"
|
||||
@change="updateTask"
|
||||
v-model="taskData.project"
|
||||
option-attribute="name"
|
||||
value-attribute="id"
|
||||
searchable
|
||||
:search-attributes="['name']"
|
||||
/>
|
||||
</UFormGroup>
|
||||
|
||||
<UFormGroup
|
||||
label="Benutzer ändern:"
|
||||
@@ -134,6 +146,9 @@
|
||||
<template #user-data="{row}">
|
||||
{{dataStore.profiles.find(profile => profile.id === row.user ) ? dataStore.profiles.find(profile => profile.id === row.user ).fullName : row.user}}
|
||||
</template>
|
||||
<template #project-data="{row}">
|
||||
{{dataStore.projects.find(item => item.id === row.project) ? dataStore.projects.find(item => item.id === row.project).name : "" }}
|
||||
</template>
|
||||
</UTable>
|
||||
|
||||
|
||||
@@ -179,6 +194,11 @@ const taskColumns = [
|
||||
key:"categorie",
|
||||
label: "Kategorie:",
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
key:"project",
|
||||
label: "Projekt:",
|
||||
sortable: true
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ const cancelEditorCreate = () => {
|
||||
}
|
||||
}
|
||||
|
||||
const updateCustomer = async () => {
|
||||
const updateItem = async () => {
|
||||
const {error} = await supabase
|
||||
.from("vehicles")
|
||||
.update(itemInfo.value)
|
||||
@@ -80,13 +80,8 @@ const updateCustomer = async () => {
|
||||
if(error) {
|
||||
console.log(error)
|
||||
} else {
|
||||
mode.value = "show"
|
||||
itemInfo.value = {
|
||||
id: 0,
|
||||
name: "",
|
||||
licensePlate: "",
|
||||
type: ""
|
||||
}
|
||||
|
||||
router.push(`/vehicles/show/${currentItem.id}`)
|
||||
toast.add({title: "Fahrzeug erfolgreich gespeichert"})
|
||||
dataStore.fetchVehicles()
|
||||
}
|
||||
@@ -187,7 +182,7 @@ setupPage()
|
||||
<template #footer>
|
||||
<UButton
|
||||
v-if="mode == 'edit'"
|
||||
@click="updateCustomer"
|
||||
@click="updateItem"
|
||||
>
|
||||
Speichern
|
||||
</UButton>
|
||||
|
||||
@@ -69,6 +69,97 @@
|
||||
/>
|
||||
</UFormGroup>
|
||||
|
||||
<div
|
||||
class="my-3"
|
||||
v-for="(item,index) in itemInfo.accounts"
|
||||
>
|
||||
|
||||
<UFormGroup
|
||||
label="Kategorie"
|
||||
class=" mb-3"
|
||||
>
|
||||
<USelectMenu
|
||||
:options="dataStore.accounts"
|
||||
option-attribute="label"
|
||||
value-attribute="id"
|
||||
searchable
|
||||
:search-attributes="['label']"
|
||||
searchable-placeholder="Suche..."
|
||||
v-model="item.account"
|
||||
>
|
||||
<template #label>
|
||||
{{dataStore.accounts.find(account => account.id === item.account) ? dataStore.accounts.find(account => account.id === item.account).label : "Keine Kategorie ausgewählt" }}
|
||||
</template>
|
||||
|
||||
</USelectMenu>
|
||||
</UFormGroup>
|
||||
|
||||
<InputGroup>
|
||||
<UFormGroup
|
||||
label="Steuer"
|
||||
class="w-32"
|
||||
:help="`Betrag: ${String(item.amountTax).replace('.',',')} €`"
|
||||
>
|
||||
<USelectMenu
|
||||
:options="[19,7,0]"
|
||||
v-model="item.taxType"
|
||||
>
|
||||
<template #label>
|
||||
{{item.taxType}} %
|
||||
</template>
|
||||
</USelectMenu>
|
||||
</UFormGroup>
|
||||
<UFormGroup
|
||||
label="Gesamtbetrag exkl. Steuer in EUR"
|
||||
class="flex-auto"
|
||||
:help="`Betrag inkl. Steuern: ${String(Number(calculateWithTax(item)) + Number(item.amountNet)).replace('.',',')} €` "
|
||||
|
||||
>
|
||||
<UInput
|
||||
type="number"
|
||||
step="0.01"
|
||||
v-model="item.amountNet"
|
||||
>
|
||||
<template #trailing>
|
||||
<span class="text-gray-500 dark:text-gray-400 text-xs">EUR</span>
|
||||
</template>
|
||||
</UInput>
|
||||
</UFormGroup>
|
||||
|
||||
|
||||
</InputGroup>
|
||||
|
||||
<UButton
|
||||
class="mt-3"
|
||||
@click="itemInfo.accounts = [...itemInfo.accounts.slice(0,index+1),{account:null, amountNet: null, amountTax:null, taxType: null} , ...itemInfo.accounts.slice(index+1)]"
|
||||
>
|
||||
Position hinzufügen
|
||||
</UButton>
|
||||
<UButton
|
||||
v-if="index !== 0"
|
||||
class="mt-3"
|
||||
variant="ghost"
|
||||
color="rose"
|
||||
@click="itemInfo.accounts = itemInfo.accounts.filter((account,itemIndex) => itemIndex !== index)"
|
||||
>
|
||||
Position entfernen
|
||||
</UButton>
|
||||
</div>
|
||||
|
||||
|
||||
<!--
|
||||
<UFormGroup label="Kategorie:" required>
|
||||
<USelectMenu
|
||||
:options="dataStore.accounts"
|
||||
option-attribute="label"
|
||||
value-attribute="number"
|
||||
searchable
|
||||
:search-attributes="['label']"
|
||||
v-model="itemInfo.account"
|
||||
>
|
||||
|
||||
</USelectMenu>
|
||||
</UFormGroup>
|
||||
<UFormGroup label="Betrag:" required>
|
||||
<UInput
|
||||
type="number"
|
||||
@@ -79,7 +170,7 @@
|
||||
<span class="text-gray-500 dark:text-gray-400 text-xs">EUR</span>
|
||||
</template>
|
||||
</UInput>
|
||||
</UFormGroup>
|
||||
</UFormGroup>-->
|
||||
|
||||
<InputGroup class="mt-3">
|
||||
<UButton
|
||||
@@ -117,6 +208,48 @@ let currentDocument = ref(null)
|
||||
//Working
|
||||
const mode = ref(route.params.mode || "show")
|
||||
|
||||
const types = [
|
||||
{
|
||||
number: "3200",
|
||||
label: "Wareneinkauf",
|
||||
description: "Der Einkauf von Produkten umfasst auch die Kosten für die Bearbeitung/Verarbeitung und den Handel"
|
||||
},{
|
||||
number: "3000",
|
||||
label: "Materialeinkauf",
|
||||
description: "Hierzu gehören sämtliche Kosten, die im Rahmen der Produktion für Roh, Hilfs- und Betriebsstoffe anfallen."
|
||||
},{
|
||||
number: "3800",
|
||||
label: "Bezugsnebenkosten",
|
||||
description: "Dazu zählen alle Beschaffungskosten für Material und Waren bzw. Produkte"
|
||||
},{
|
||||
number: "4930",
|
||||
label: "Bürobedarf",
|
||||
description: ""
|
||||
},{
|
||||
number: "4964",
|
||||
label: "Lizenzen und Konzessionen",
|
||||
description: ""
|
||||
},{
|
||||
number: "4925",
|
||||
label: "Internet",
|
||||
description: ""
|
||||
},{
|
||||
number: "4920",
|
||||
label: "Telekommunikation",
|
||||
description: ""
|
||||
},{
|
||||
number: "4530",
|
||||
label: "Kraftstoff/Ladestrom",
|
||||
description: ""
|
||||
},{
|
||||
number: "4969",
|
||||
label: "Müllgebühren",
|
||||
description: ""
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
|
||||
|
||||
//Functions
|
||||
const setupPage = async () => {
|
||||
@@ -139,9 +272,24 @@ const itemInfo = ref({
|
||||
dueDate: null,
|
||||
paymentType: "",
|
||||
description: "",
|
||||
state: "Entwurf"
|
||||
state: "Entwurf",
|
||||
accounts: [
|
||||
{
|
||||
account: null,
|
||||
amountNet: null,
|
||||
amountTax: null,
|
||||
taxType: null
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
const calculateWithTax = (item) => {
|
||||
item.amountTax = Number((item.amountNet / 100 * Number(item.taxType)).toFixed(2))
|
||||
|
||||
return item.amountTax
|
||||
}
|
||||
|
||||
|
||||
const updateItem = async () => {
|
||||
const {error} = await supabase
|
||||
.from("vendorInvoices")
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
{{row.dueDate ? dayjs(row.dueDate).format("DD.MM.YY") : ''}}
|
||||
</template>
|
||||
<template #amount-data="{row}">
|
||||
{{row.amount ? row.amount.toFixed(2) + ' €' : ''}}
|
||||
{{getRowAmount(row) === 0 ? '' : `${getRowAmount(row)} €`}}
|
||||
</template>
|
||||
</UTable>
|
||||
|
||||
@@ -101,6 +101,17 @@ const selectItem = (item) => {
|
||||
router.push(`/vendorinvoices/edit/${item.id} `)
|
||||
}
|
||||
|
||||
const getRowAmount = (row) => {
|
||||
let amount = 0
|
||||
|
||||
row.accounts.forEach(account => {
|
||||
amount += account.amountNet
|
||||
amount += account.amountTax
|
||||
})
|
||||
|
||||
return amount
|
||||
}
|
||||
|
||||
|
||||
const searchString = ref('')
|
||||
|
||||
|
||||
96
spaces/pages/vendors/[mode]/[[id]].vue
vendored
96
spaces/pages/vendors/[mode]/[[id]].vue
vendored
@@ -1,4 +1,6 @@
|
||||
<script setup>
|
||||
import HistoryDisplay from "~/components/HistoryDisplay.vue";
|
||||
|
||||
definePageMeta({
|
||||
middleware: "auth"
|
||||
})
|
||||
@@ -9,6 +11,7 @@ const route = useRoute()
|
||||
const router = useRouter()
|
||||
const toast = useToast()
|
||||
const id = ref(route.params.id ? route.params.id : null )
|
||||
const numberRange = useNumberRange("vendors")
|
||||
|
||||
let currentItem = null
|
||||
|
||||
@@ -16,7 +19,9 @@ let currentItem = null
|
||||
|
||||
//Working
|
||||
const mode = ref(route.params.mode || "show")
|
||||
const itemInfo = ref({})
|
||||
const itemInfo = ref({
|
||||
infoData: {}
|
||||
})
|
||||
|
||||
//Functions
|
||||
const setupPage = () => {
|
||||
@@ -31,6 +36,9 @@ const setupPage = () => {
|
||||
}
|
||||
|
||||
const createItem = async () => {
|
||||
|
||||
if(!itemInfo.value.vendorNumber) itemInfo.value.vendorNumber = await numberRange.useNextNumber()
|
||||
|
||||
const {data,error} = await supabase
|
||||
.from("vendors")
|
||||
.insert([itemInfo.value])
|
||||
@@ -66,9 +74,8 @@ const updateItem = async () => {
|
||||
if(error) {
|
||||
console.log(error)
|
||||
} else {
|
||||
mode.value = "show"
|
||||
itemInfo.value = {}
|
||||
toast.add({title: "Lieferant erfolgreich gespeichert"})
|
||||
router.push(`/vendors/show/${currentItem.id}`)
|
||||
dataStore.fetchVendors()
|
||||
}
|
||||
|
||||
@@ -87,9 +94,29 @@ setupPage()
|
||||
{{currentItem.name}}
|
||||
</template>
|
||||
|
||||
{{currentItem}}
|
||||
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>
|
||||
<UButton
|
||||
@@ -110,8 +137,8 @@ setupPage()
|
||||
|
||||
|
||||
</UCard>
|
||||
<UCard v-else-if="mode == 'edit' || mode == 'create'" >
|
||||
<template #header>
|
||||
<UCard v-else-if="mode === 'edit' || mode === 'create'" >
|
||||
<template #header v-if="mode === 'edit'">
|
||||
{{itemInfo.name}}
|
||||
</template>
|
||||
|
||||
@@ -127,6 +154,57 @@ setupPage()
|
||||
>
|
||||
<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>
|
||||
|
||||
@@ -154,6 +232,12 @@ setupPage()
|
||||
</template>
|
||||
|
||||
</UCard>
|
||||
|
||||
<HistoryDisplay
|
||||
type="vendor"
|
||||
v-if="currentItem"
|
||||
:element-id="currentItem.id"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user