<template> <q-carousel v-model="volume" transition-prev="slide-right" transition-next="slide-left" animated swipeable control-color="primary" arrows :keep-alive="false" > <q-carousel-slide v-for="volume in volumes" :key="volume.id" :name="volume.id"> <div class="full-width row"> <q-input v-model.number="volume._volume" class="q-pa-sm col-10" :outlined="!editable || !volume_can_edit" :filled="editable && volume_can_edit" :readonly="!editable || !volume_can_edit" dense label="Inhalt" mask="#.###" fill-mask="0" suffix="L" min="0" step="0.001" @update:model-value="updateVolume(volume)" /> <div v-if="deleteable && editable" class="q-pa-sm col-2 text-right"> <q-btn round icon="mdi-delete" size="sm" color="negative" @click="deleteVolume"> <q-tooltip> Abgabe entfernen </q-tooltip> </q-btn> </div> </div> <div v-if="!public && !nodetails" class="full-width row q-gutter-sm q-pa-sm justify-around"> <div v-for="(min_price, index) in volume.min_prices" :key="index"> <q-badge class="text-body1" color="primary"> {{ min_price.percentage }}% </q-badge> <div class="text-body1">{{ min_price.price.toFixed(3) }}€</div> </div> </div> <div class="q-pa-sm"> <div v-for="(price, index) in volume.prices" :key="price.id"> <div class="fit row justify-around q-py-sm"> <div v-if="!editable" class="text-body1 col-3">{{ price.price.toFixed(2) }}€</div> <q-input v-else v-model.number="price.price" class="col-3" type="number" min="0" step="0.01" suffix="€" filled dense label="Preis" @update:model-value="change" /> <div class="text-body1 col-2"> <q-toggle v-model="price.public" :disable="!editable" checked-icon="mdi-earth" unchecked-icon="mdi-earth-off" @update:model-value="change" /> </div> <div v-if="!editable" class="text-body1 col-5"> {{ price.description }} </div> <q-input v-else v-model="price.description" class="col-5" filled dense label="Beschreibung" @update:model-value="change" /> <div v-if="editable" class="col-1"> <q-btn round icon="mdi-delete" color="negative" size="xs" @click="deletePrice(price)"> <q-tooltip> Preis entfernen </q-tooltip> </q-btn> </div> </div> <q-separator v-if="index < volume.prices.length - 1" /> </div> <div v-if="editable" class="full-width row justify-end text-right"> <q-btn round icon="mdi-plus" size="sm" color="primary"> <q-tooltip> Preis hinzufügen </q-tooltip> <q-menu anchor="center middle" self="center middle"> <new-price @save="addPrice" /> </q-menu> </q-btn> </div> </div> <div class="q-pa-sm"> <ingredients v-if="!public && !cost_per_volume" v-model="volume.ingredients" :editable="editable" @update="updateVolume(volume)" @delete-ingredient="deleteIngredient" /> </div> </q-carousel-slide> </q-carousel> <div class="full-width row justify-center q-pa-sm"> <div class="q-px-sm"> <q-btn-toggle v-model="volume" :options="options" /> </div> <div v-if="editable" class="q-px-sm"> <q-btn class="q-px-sm" round icon="mdi-plus" color="primary" size="sm" @click="newVolume"> <q-tooltip> Abgabe hinzufügen </q-tooltip> </q-btn> </div> </div> </template> <script lang="ts"> import { computed, defineComponent, PropType, ref, onBeforeMount } from 'vue'; import { DrinkPriceVolume } from 'src/plugins/pricelist/store'; import Ingredients from 'src/plugins/pricelist/components/CalculationTable/Ingredients.vue'; import NewPrice from 'src/plugins/pricelist/components/CalculationTable/NewPrice.vue'; import { calc_volume, clone } from '../../utils/utils'; export default defineComponent({ name: 'DrinkPriceVolume', components: { Ingredients, NewPrice }, props: { modelValue: { type: Array as PropType<Array<DrinkPriceVolume>>, required: true, }, cost_per_volume: { type: undefined }, editable: { type: Boolean, default: false, }, public: { type: Boolean, default: false, }, nodetails: { type: Boolean, default: false, }, }, emits: { 'update:modelValue': (val: Array<DrinkPriceVolume>) => val, update: (val: number) => val, 'delete-volume': (val: DrinkPriceVolume) => val, 'delete-price': (val: FG.DrinkPrice) => val, 'delete-ingredient': (val: FG.Ingredient) => val, }, setup(props, { emit }) { onBeforeMount(() => { //volumes.value = <Array<DrinkPriceVolume>>JSON.parse(JSON.stringify(props.modelValue)); volumes.value = clone(props.modelValue); }); const volumes = ref<Array<DrinkPriceVolume>>([]); const _volume = ref<number | undefined>(); const volume = computed<number | undefined>({ get: () => { if (_volume.value !== undefined) { return _volume.value; } if (volumes.value.length > 0) { return volumes.value[0].id; } return undefined; }, set: (val: number | undefined) => (_volume.value = val), }); const edit_volume = computed(() => { return volumes.value.find((a) => a.id === volume.value); }); const options = computed<Array<{ label: string; value: number }>>(() => { const retVal: Array<{ label: string; value: number }> = []; volumes.value.forEach((volume: DrinkPriceVolume) => { retVal.push({ label: `${(<number>volume.volume).toFixed(3)}L`, value: volume.id }); }); return retVal; }); function updateVolume(_volume: DrinkPriceVolume) { const index = volumes.value.findIndex((a) => a.id === _volume.id); if (index > -1) { volumes.value[index].volume = calc_volume(_volume); } change(); setTimeout(() => { emit('update', index); }, 50); } const volume_can_edit = computed(() => { if (edit_volume.value) { return !edit_volume.value.ingredients.some((ingredient) => ingredient.drink_ingredient); } return true; }); const newVolumeId = ref(-1); function newVolume() { const new_volume: DrinkPriceVolume = { id: newVolumeId.value, _volume: 0, volume: 0, prices: [], ingredients: [], min_prices: [], }; newVolumeId.value--; volumes.value.push(new_volume); change(); _volume.value = volumes.value[volumes.value.length - 1].id; } function deleteVolume() { if (edit_volume.value) { if (edit_volume.value.id > 0) { emit('delete-volume', edit_volume.value); } const index = volumes.value.findIndex((a) => a.id === edit_volume.value?.id); if (index > -1) { _volume.value = volumes.value[0].id; volumes.value.splice(index, 1); } } } const deleteable = computed(() => { if (edit_volume.value) { const has_ingredients = edit_volume.value.ingredients.length > 0; const has_prices = edit_volume.value.prices.length > 0; return !(has_ingredients || has_prices); } return true; }); function addPrice(price: FG.DrinkPrice) { if (edit_volume.value) { edit_volume.value.prices.push(price); change(); } } function deletePrice(price: FG.DrinkPrice) { if (edit_volume.value) { const index = edit_volume.value.prices.findIndex((a) => a.id === price.id); if (index > -1) { if (edit_volume.value.prices[index].id > 0) { emit('delete-price', edit_volume.value.prices[index]); change(); } edit_volume.value.prices.splice(index, 1); } } } function deleteIngredient(ingredient: FG.Ingredient) { emit('delete-ingredient', ingredient); } function change() { emit('update:modelValue', volumes.value); } return { volumes, volume, options, updateVolume, volume_can_edit, newVolume, deleteable, addPrice, deletePrice, deleteVolume, deleteIngredient, change, }; }, }); </script> <style scoped></style>