flaschengeist-pricelist/src/components/DrinkModify.vue

359 lines
9.9 KiB
Vue

<template>
<q-card>
<q-card-section>
<div class="text-h6">Getränk Bearbeiten</div>
</q-card-section>
<q-card-section>
<div class="full-width row">
<q-input
v-model="edit_drink.name"
class="col-xs-12 col-sm-6 q-pa-sm"
filled
label="Name"
dense
/>
<q-select
v-model="edit_drink.type"
class="col-xs-12 col-sm-6 q-pa-sm"
filled
label="Kategorie"
dense
:options="types"
option-label="name"
/>
</div>
</q-card-section>
<q-card-section>
<q-img :src="image" style="max-height: 256px" fit="contain" />
<div class="full-width row">
<div class="col-10 q-pa-sm">
<q-file
v-model="drinkPic"
filled
clearable
dense
@update:model-value="imagePreview"
@clear="imgsrc = undefined"
>
<template #prepend>
<q-icon name="mdi-image" />
</template>
</q-file>
</div>
<div class="col-2 q-pa-sm text-right">
<q-btn round icon="mdi-delete" color="negative" size="sm" @click="delete_pic">
<q-tooltip> Bild entfernen </q-tooltip>
</q-btn>
</div>
</div>
</q-card-section>
<q-card-section>
<q-select
v-model="edit_drink.tags"
multiple
:options="tags"
label="Tags"
option-label="name"
filled
dense
>
<template #selected-item="item">
<q-chip
removable
:tabindex="item.tabindex"
:style="`background-color: ${item.opt.color}`"
@remove="item.removeAtIndex(item.index)"
>
{{ item.opt.name }}
</q-chip>
</template>
<template #option="item">
<q-item v-bind="item.itemProps" v-on="item.itemEvents">
<q-chip :style="`background-color: ${item.opt.color}`">
<q-avatar v-if="item.selected" icon="mdi-check" color="positive" text-color="white" />
{{ item.opt.name }}
</q-chip>
</q-item>
</template>
</q-select>
</q-card-section>
<q-card-section>
<div class="fit row">
<q-input
v-model="edit_drink.article_id"
class="col-xs-12 col-sm-6 q-pa-sm"
filled
label="Artikelnummer"
dense
/>
<q-input
v-model="edit_drink.volume"
class="col-xs-12 col-sm-6 q-pa-sm"
filled
label="Inhalt"
dense
suffix="L"
/>
<q-input
v-model="edit_drink.package_size"
class="col-xs-12 col-sm-6 q-pa-sm"
filled
label="Gebindegröße"
dense
/>
<q-input
v-model="edit_drink.cost_per_package"
class="col-xs-12 col-sm-6 q-pa-sm"
filled
label="Preis Gebinde"
suffix="€"
dense
/>
<q-input
v-model="cost_per_volume"
class="col-xs-12 col-sm-6 q-pa-sm q-pb-lg"
:outlined="auto_cost_per_volume || hasIngredients"
:filled="!auto_cost_per_volume && !hasIngredients"
:readonly="auto_cost_per_volume || hasIngredients"
label="Preis pro L"
hint="Inkl. 19% Mehrwertsteuer"
suffix="€"
dense
/>
</div>
</q-card-section>
<q-card-section :key="key">
<drink-price-volumes
v-model="edit_volumes"
:cost-per-volume="cost_per_volume"
:editable="hasPermission(PERMISSIONS.EDIT_VOLUME)"
@update="updateVolume"
@delete-volume="deleteVolume"
@delete-price="deletePrice"
@delete-ingredient="deleteIngredient"
/>
</q-card-section>
<q-card-section>
<build-manual :steps="edit_drink.receipt" @deleteStep="deleteStep" @addStep="addStep" />
</q-card-section>
<q-card-actions class="justify-around">
<q-btn label="Abbrechen" @click="cancel" />
<!--<q-btn v-if="can_delete" label="Löschen" color="negative" @click="delete_drink" />-->
<q-btn label="Löschen" color="negative" @click="delete_drink" />
<q-btn label="Speichern" color="primary" @click="save" />
</q-card-actions>
</q-card>
</template>
<script lang="ts">
import { clone, calc_min_prices, DeleteObjects, calc_cost_per_volume } from '../utils/utils';
import { defineComponent, PropType, ref, onBeforeMount, computed } from 'vue';
import DrinkPriceVolumes from './CalculationTable/DrinkPriceVolumes.vue';
import BuildManual from '../components/CalculationTable/BuildManual.vue';
import { Drink, DrinkPriceVolume, usePricelistStore } from '../store';
import { api, hasPermission } from '@flaschengeist/api';
import { PERMISSIONS } from '../permissions';
export default defineComponent({
name: 'DrinkModify',
components: { BuildManual, DrinkPriceVolumes },
props: {
drink: {
type: Object as PropType<Drink>,
required: true,
},
},
emits: {
save: (
drink: Drink,
toDeleteObjects: DeleteObjects,
drinkPic: File | undefined,
deletePic: boolean
) => (drink && toDeleteObjects) || drinkPic || deletePic,
delete: () => true,
cancel: () => true,
},
setup(props, { emit }) {
onBeforeMount(() => {
//edit_drink.value = <Drink>JSON.parse(JSON.stringify(props.drink));
edit_volumes.value = clone(props.drink.volumes);
});
const key = ref(0);
const store = usePricelistStore();
const toDeleteObjects = ref<DeleteObjects>({
prices: [],
volumes: [],
ingredients: [],
});
const edit_drink = ref<Drink>(clone(props.drink));
const edit_volumes = ref<Array<DrinkPriceVolume>>([]);
function save() {
(<Drink>edit_drink.value).volumes = edit_volumes.value;
edit_drink.value.cost_per_volume = calc_cost_per_volume(edit_drink.value);
edit_drink.value._cost_per_volume = edit_drink.value.cost_per_volume;
emit('save', <Drink>edit_drink.value, toDeleteObjects.value, drinkPic.value, deletePic.value);
}
function cancel() {
emit('cancel');
}
function updateVolume(index: number) {
if (index > -1 && edit_volumes.value) {
edit_volumes.value[index].min_prices = calc_min_prices(
edit_volumes.value[index],
//edit_drink.value.cost_per_volume,
cost_per_volume.value,
store.min_prices
);
}
}
function updateVolumes() {
setTimeout(() => {
edit_volumes.value?.forEach((_, index) => {
updateVolume(index);
});
key.value++;
}, 50);
}
function deletePrice(price: FG.DrinkPrice) {
toDeleteObjects.value.prices.push(price);
}
function deleteVolume(volume: DrinkPriceVolume) {
toDeleteObjects.value.volumes.push(volume);
}
function deleteIngredient(ingredient: FG.Ingredient) {
toDeleteObjects.value.ingredients.push(ingredient);
}
function addStep(event: string) {
edit_drink.value?.receipt?.push(event);
}
function deleteStep(event: number) {
edit_drink.value?.receipt?.splice(event, 1);
}
const drinkPic = ref();
const imgsrc = ref();
const deletePic = ref(false);
function delete_pic() {
deletePic.value = true;
imgsrc.value = undefined;
drinkPic.value = undefined;
if (edit_drink.value) {
edit_drink.value.has_image = false;
}
}
function imagePreview() {
if (drinkPic.value && drinkPic.value instanceof File) {
let reader = new FileReader();
reader.onload = (e) => {
imgsrc.value = e.target?.result;
};
reader.readAsDataURL(drinkPic.value);
}
}
const image = computed(() => {
console.log(imgsrc.value, deletePic.value, edit_drink.value);
if (deletePic.value) {
return 'no-image.svg';
}
if (imgsrc.value) {
return <string>imgsrc.value;
}
if (edit_drink.value?.has_image) {
return `${api.defaults.baseURL || ''}/pricelist/drinks/${
edit_drink.value.id
}/picture?thumbnail?t=${new Date()}`;
}
return 'no-image.svg';
});
const can_delete = computed(() => {
if (edit_drink.value) {
if (edit_drink.value.id < 0) {
return false;
}
const _edit_drink = edit_drink.value;
const test = _edit_drink.volumes ? _edit_drink.volumes.length === 0 : true;
console.log(test);
return test;
}
return false;
});
function delete_drink() {
emit('delete');
}
const auto_cost_per_volume = computed(
() =>
!!(
edit_drink.value?.cost_per_package &&
edit_drink.value?.package_size &&
edit_drink.value?.volume
)
);
const cost_per_volume = computed({
get: () => {
let retVal: number;
if (auto_cost_per_volume.value) {
retVal = <number>calc_cost_per_volume(<Drink>edit_drink.value);
} else {
retVal = <number>(<Drink>edit_drink.value).cost_per_volume;
}
updateVolumes();
return retVal;
},
set: (val: number) => ((<Drink>edit_drink.value).cost_per_volume = val),
});
const hasIngredients = computed(() =>
edit_volumes.value?.some((a) => a.ingredients.length > 0)
);
return {
edit_drink,
save,
cancel,
updateVolume,
deletePrice,
deleteIngredient,
deleteVolume,
addStep,
deleteStep,
tags: computed(() => store.tags),
image,
imgsrc,
drinkPic,
imagePreview,
delete_pic,
types: computed(() => store.drinkTypes),
can_delete,
delete_drink,
auto_cost_per_volume,
cost_per_volume,
edit_volumes,
key,
hasIngredients,
hasPermission,
PERMISSIONS,
};
},
});
</script>