172 lines
4.5 KiB
Vue
172 lines
4.5 KiB
Vue
<script setup>
|
|
|
|
import { v4 as uuidv4 } from 'uuid';
|
|
|
|
const props = defineProps({
|
|
item: {
|
|
type: Object,
|
|
required: true
|
|
}
|
|
})
|
|
|
|
const hourrates = ref([])
|
|
const units = ref([])
|
|
|
|
const hourrateSearchInput = {
|
|
placeholder: 'Stundensatz suchen...'
|
|
}
|
|
|
|
const setup = async () => {
|
|
hourrates.value = await useEntities("hourrates").select()
|
|
units.value = await useEntities("units").selectSpecial()
|
|
}
|
|
|
|
setup()
|
|
|
|
const addRowToPersonalComposition = () => {
|
|
|
|
if(!props.item.personalComposition) props.item.personalComposition = []
|
|
|
|
props.item.personalComposition.push({
|
|
id: uuidv4(),
|
|
unit: 6,
|
|
quantity: 1,
|
|
price: 0,
|
|
name: "Standard"
|
|
})
|
|
calculateTotalPersonalPrice()
|
|
}
|
|
|
|
const removeRowFromPersonalComposition = (id) => {
|
|
props.item.personalComposition = props.item.personalComposition.filter((item) => item.id !== id)
|
|
calculateTotalPersonalPrice()
|
|
}
|
|
|
|
const calculateTotalPersonalPrice = () => {
|
|
let total = 0
|
|
|
|
props.item.personalComposition.forEach((item) => {
|
|
let rowSum = item.quantity * item.price
|
|
total += rowSum
|
|
})
|
|
|
|
props.item.sellingPriceComposed.worker = Number(total.toFixed(2))
|
|
props.item.sellingPriceComposed.total = Number((props.item.sellingPriceComposed.worker + props.item.sellingPriceComposed.material).toFixed(2))
|
|
}
|
|
|
|
const setRowData = (row) => {
|
|
let hourrate = hourrates.value.find(i => i.id === row.hourrate)
|
|
|
|
row.purchasePrice = hourrate.purchasePrice
|
|
row.price = hourrate.sellingPrice
|
|
|
|
calculateTotalPersonalPrice()
|
|
}
|
|
|
|
</script>
|
|
|
|
<template>
|
|
<UCard class="w-full">
|
|
<UButton
|
|
@click="addRowToPersonalComposition"
|
|
>
|
|
+ Stundensatz
|
|
</UButton>
|
|
|
|
<div class="mt-3 overflow-x-auto">
|
|
<table class="w-full min-w-[52rem] table-fixed">
|
|
<thead>
|
|
<tr class="border-b border-gray-200 dark:border-gray-800">
|
|
<th class="px-2 py-2 text-left font-medium">Name</th>
|
|
<th class="px-2 py-2 text-left font-medium">Menge</th>
|
|
<th class="px-2 py-2 text-left font-medium">Einheit</th>
|
|
<th class="px-2 py-2 text-left font-medium">Einkaufspreis</th>
|
|
<th class="px-2 py-2 text-left font-medium">Verkaufspreis</th>
|
|
<th class="w-12 px-2 py-2"></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr
|
|
v-for="row in props.item.personalComposition"
|
|
:key="row.id"
|
|
class="border-b border-gray-100 align-top dark:border-gray-800"
|
|
>
|
|
<td class="px-2 py-2">
|
|
<USelectMenu
|
|
class="w-full"
|
|
:items="hourrates"
|
|
label-key="name"
|
|
value-key="id"
|
|
:search-input="hourrateSearchInput"
|
|
:filter-fields="['name']"
|
|
v-model="row.hourrate"
|
|
:color="row.hourrate ? 'primary' : 'error'"
|
|
@update:model-value="setRowData(row)"
|
|
>
|
|
<template #default>
|
|
{{ hourrates.find(i => i.id === row.hourrate)?.name || 'Kein Stundensatz ausgewählt' }}
|
|
</template>
|
|
</USelectMenu>
|
|
</td>
|
|
<td class="px-2 py-2">
|
|
<UInput
|
|
class="w-full"
|
|
type="number"
|
|
v-model="row.quantity"
|
|
:step="units.find(i => i.id === row.unit) ? units.find(i => i.id === row.unit).step : 1"
|
|
@change="calculateTotalPersonalPrice"
|
|
/>
|
|
</td>
|
|
<td class="px-2 py-2">
|
|
<USelectMenu
|
|
class="w-full"
|
|
:items="units"
|
|
disabled
|
|
label-key="name"
|
|
value-key="id"
|
|
v-model="row.unit"
|
|
>
|
|
<template #default>
|
|
{{ units.find(i => i.id === row.unit)?.name || 'Einheit' }}
|
|
</template>
|
|
</USelectMenu>
|
|
</td>
|
|
<td class="px-2 py-2">
|
|
<UInput
|
|
class="w-full"
|
|
type="number"
|
|
v-model="row.purchasePrice"
|
|
step="0.01"
|
|
@change="calculateTotalPersonalPrice"
|
|
/>
|
|
</td>
|
|
<td class="px-2 py-2">
|
|
<UInput
|
|
class="w-full"
|
|
type="number"
|
|
v-model="row.price"
|
|
step="0.01"
|
|
@change="calculateTotalPersonalPrice"
|
|
/>
|
|
</td>
|
|
<td class="px-2 py-2">
|
|
<UButton
|
|
icon="i-heroicons-x-mark"
|
|
@click="removeRowFromPersonalComposition(row.id)"
|
|
variant="outline"
|
|
color="error"
|
|
/>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</UCard>
|
|
</template>
|
|
|
|
<style scoped>
|
|
td {
|
|
margin-bottom: 0.5em;
|
|
}
|
|
</style>
|