[Vue3] Fixed pricelist
This commit is contained in:
parent
62aa627f0c
commit
5153f074b5
|
@ -13,10 +13,10 @@ declare namespace FG {
|
||||||
firstname: string;
|
firstname: string;
|
||||||
lastname: string;
|
lastname: string;
|
||||||
mail: string;
|
mail: string;
|
||||||
birthday?: Date;
|
birthday?: any;
|
||||||
roles: Array<string>;
|
roles: Array<string>;
|
||||||
permissions?: Array<string>;
|
permissions?: any;
|
||||||
avatar_url?: string;
|
avatar_url?: any;
|
||||||
}
|
}
|
||||||
type Permission = string;
|
type Permission = string;
|
||||||
interface Role {
|
interface Role {
|
||||||
|
@ -29,58 +29,41 @@ declare namespace FG {
|
||||||
time: Date;
|
time: Date;
|
||||||
amount: number;
|
amount: number;
|
||||||
reversal_id: number;
|
reversal_id: number;
|
||||||
sender_id?: string;
|
sender_id?: any;
|
||||||
receiver_id?: string;
|
receiver_id?: any;
|
||||||
author_id?: string;
|
author_id?: any;
|
||||||
original_id?: number;
|
original_id?: any;
|
||||||
}
|
}
|
||||||
interface Drink {
|
interface Drink {
|
||||||
id: number;
|
id: number;
|
||||||
article_id?: string;
|
|
||||||
package_size?: number;
|
|
||||||
name: string;
|
name: string;
|
||||||
volume?: number;
|
|
||||||
cost_price_pro_volume?: number;
|
|
||||||
cost_price_package_netto?: number;
|
|
||||||
tags?: Array<Tag>;
|
|
||||||
type?: DrinkType;
|
|
||||||
volumes: Array<DrinkPriceVolume>;
|
|
||||||
}
|
|
||||||
interface DrinkIngredient {
|
|
||||||
id: number;
|
|
||||||
volume: number;
|
volume: number;
|
||||||
drink_ingredient_id: number;
|
cost_price: number;
|
||||||
|
discount: number;
|
||||||
|
extra_charge?: any;
|
||||||
|
prices: Array<DrinkPrice>;
|
||||||
|
ingredients: Array<Ingredient>;
|
||||||
|
tags: Array<any>;
|
||||||
}
|
}
|
||||||
interface DrinkPrice {
|
interface DrinkPrice {
|
||||||
id: number;
|
|
||||||
price: number;
|
|
||||||
public: boolean;
|
|
||||||
description?: string;
|
|
||||||
}
|
|
||||||
interface DrinkPriceVolume {
|
|
||||||
id: number;
|
id: number;
|
||||||
volume: number;
|
volume: number;
|
||||||
min_prices: Array<MinPrices>;
|
price: number;
|
||||||
prices: Array<DrinkPrice>;
|
no_auto: boolean;
|
||||||
ingredients: Array<Ingredient>;
|
public: boolean;
|
||||||
|
description?: any;
|
||||||
|
round_step: number;
|
||||||
}
|
}
|
||||||
interface DrinkType {
|
interface DrinkType {
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
}
|
}
|
||||||
interface ExtraIngredient {
|
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
price: number;
|
|
||||||
}
|
|
||||||
interface Ingredient {
|
interface Ingredient {
|
||||||
id: number;
|
id: number;
|
||||||
drink_ingredient?: DrinkIngredient;
|
volume: number;
|
||||||
extra_ingredient?: ExtraIngredient;
|
drink_parent_id: number;
|
||||||
}
|
drink_ingredient_id: number;
|
||||||
interface MinPrices {
|
drink_ingredient?: any;
|
||||||
percentage: number;
|
|
||||||
price: number;
|
|
||||||
}
|
}
|
||||||
interface Tag {
|
interface Tag {
|
||||||
id: number;
|
id: number;
|
||||||
|
@ -90,7 +73,7 @@ declare namespace FG {
|
||||||
id: number;
|
id: number;
|
||||||
start: Date;
|
start: Date;
|
||||||
end: Date;
|
end: Date;
|
||||||
description?: string;
|
description?: any;
|
||||||
type: EventType;
|
type: EventType;
|
||||||
jobs: Array<Job>;
|
jobs: Array<Job>;
|
||||||
}
|
}
|
||||||
|
@ -101,7 +84,7 @@ declare namespace FG {
|
||||||
interface Job {
|
interface Job {
|
||||||
id: number;
|
id: number;
|
||||||
start: Date;
|
start: Date;
|
||||||
end?: Date;
|
end?: any;
|
||||||
comment: string;
|
comment: string;
|
||||||
type: JobType;
|
type: JobType;
|
||||||
services: Array<Service>;
|
services: Array<Service>;
|
||||||
|
|
|
@ -0,0 +1,162 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<q-card>
|
||||||
|
<q-card-section>
|
||||||
|
<div class="text-h4">Neues Getränk</div>
|
||||||
|
</q-card-section>
|
||||||
|
<q-form @submit="save">
|
||||||
|
<q-card-section>
|
||||||
|
<div class="text-h5">Getränkinformationen</div>
|
||||||
|
<div class="row">
|
||||||
|
<q-input
|
||||||
|
v-model="drink.name"
|
||||||
|
class="col-12 col-sm-6 q-px-sm q-py-md"
|
||||||
|
filled
|
||||||
|
label="Name"
|
||||||
|
/>
|
||||||
|
<q-input
|
||||||
|
v-model="drink.volume"
|
||||||
|
class="col-12 col-sm-6 q-px-sm q-py-md"
|
||||||
|
filled
|
||||||
|
label="Inhalt in Liter"
|
||||||
|
type="number"
|
||||||
|
step="0.01"
|
||||||
|
/>
|
||||||
|
<q-input
|
||||||
|
v-model="drink.cost_price"
|
||||||
|
class="col-12 col-sm-6 q-px-sm q-py-md"
|
||||||
|
filled
|
||||||
|
label="Einkaufspreis"
|
||||||
|
type="number"
|
||||||
|
step="0.01"
|
||||||
|
/>
|
||||||
|
<q-input
|
||||||
|
v-model="drink.discount"
|
||||||
|
class="col-12 col-sm-6 q-px-sm q-py-md"
|
||||||
|
filled
|
||||||
|
label="Aufschlag in Prozent"
|
||||||
|
type="number"
|
||||||
|
hint="Wenn nicht gesetzt wird default-wert genommen."
|
||||||
|
step="0.01"
|
||||||
|
/>
|
||||||
|
<q-input
|
||||||
|
v-model="drink.extra_charge"
|
||||||
|
class="col-12 col-sm-6 q-px-sm q-py-md"
|
||||||
|
filled
|
||||||
|
label="Extra Aufschlag in Euro"
|
||||||
|
type="number"
|
||||||
|
step="0.1"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<q-input class="col-12 col-sm-6 q-px-sm q-py-md" filled label="Tags" />
|
||||||
|
</div>
|
||||||
|
</q-card-section>
|
||||||
|
<q-card-section>
|
||||||
|
<div class="row justify-between">
|
||||||
|
<div class="text-h5">Preise</div>
|
||||||
|
<q-btn round icon="mdi-plus" color="primary" @click="addPrice" />
|
||||||
|
</div>
|
||||||
|
<q-card v-for="(price, index) in drink.prices" :key="index" class="q-ma-sm">
|
||||||
|
<div class="row">
|
||||||
|
<q-input
|
||||||
|
v-model="price.volume"
|
||||||
|
class="col-12 col-sm-6 q-px-sm q-py-md"
|
||||||
|
label="Inhalt in Liter"
|
||||||
|
filled
|
||||||
|
type="number"
|
||||||
|
step="0.01"
|
||||||
|
/>
|
||||||
|
<q-input
|
||||||
|
v-model="price.price"
|
||||||
|
class="col-12 col-sm-6 q-px-sm q-py-md"
|
||||||
|
label="Preis in €"
|
||||||
|
filled
|
||||||
|
:disable="price.no_auto"
|
||||||
|
type="number"
|
||||||
|
step="0.1"
|
||||||
|
/>
|
||||||
|
<q-toggle
|
||||||
|
v-model="price.no_auto"
|
||||||
|
class="col-12 col-sm-6 q-px-sm q-py-md"
|
||||||
|
label="Automatische Preiskalkulation"
|
||||||
|
color="primary"
|
||||||
|
/>
|
||||||
|
<q-input
|
||||||
|
v-model="price.round_step"
|
||||||
|
class="col-12 col-sm-6 q-px-sm q-py-md"
|
||||||
|
label="Rundungsschritt"
|
||||||
|
type="number"
|
||||||
|
filled
|
||||||
|
step="0.1"
|
||||||
|
/>
|
||||||
|
<q-toggle
|
||||||
|
v-model="price.public"
|
||||||
|
class="col-12 col-sm-6 q-px-sm q-py-md"
|
||||||
|
label="Öffentlich"
|
||||||
|
color="primary"
|
||||||
|
/>
|
||||||
|
<q-input
|
||||||
|
v-model="price.description"
|
||||||
|
class="col-12 col-sm-6 q-px-sm q-py-md"
|
||||||
|
label="Beschreibung"
|
||||||
|
filled
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</q-card>
|
||||||
|
</q-card-section>
|
||||||
|
<q-card-section>
|
||||||
|
<div class="row justify-between">
|
||||||
|
<div class="text-h5">Zutaten</div>
|
||||||
|
<q-btn round icon="mdi-plus" color="primary" />
|
||||||
|
</div>
|
||||||
|
</q-card-section>
|
||||||
|
<q-card-actions align="right">
|
||||||
|
<q-btn type="submit" label="Speichern" color="primary" />
|
||||||
|
</q-card-actions>
|
||||||
|
</q-form>
|
||||||
|
</q-card>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent, ref } from 'vue';
|
||||||
|
import { useStore } from 'vuex';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'Drink',
|
||||||
|
setup() {
|
||||||
|
const store = useStore();
|
||||||
|
const drink = ref({
|
||||||
|
name: '',
|
||||||
|
volume: '',
|
||||||
|
cost_price: '',
|
||||||
|
discount: '',
|
||||||
|
extra_charge: '',
|
||||||
|
prices: [],
|
||||||
|
ingredients: [],
|
||||||
|
});
|
||||||
|
const emptyPrice = {
|
||||||
|
volume: '',
|
||||||
|
price: '',
|
||||||
|
description: '',
|
||||||
|
no_auto: false,
|
||||||
|
round_step: '',
|
||||||
|
public: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
function addPrice() {
|
||||||
|
drink.value.prices.unshift({ ...emptyPrice });
|
||||||
|
}
|
||||||
|
function save() {
|
||||||
|
console.log(drink);
|
||||||
|
drink.value.prices.forEach((price: FG.DrinkPrice) => {
|
||||||
|
price.no_auto = !price.no_auto;
|
||||||
|
});
|
||||||
|
void store.dispatch('drink/createDrink', drink.value);
|
||||||
|
}
|
||||||
|
return { drink, addPrice, save };
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
|
@ -6,7 +6,7 @@
|
||||||
<div class="text-h6">Editere Getränkeart {{ actualDrinkType.name }}</div>
|
<div class="text-h6">Editere Getränkeart {{ actualDrinkType.name }}</div>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
<q-card-section>
|
<q-card-section>
|
||||||
<q-input dense label="name" filled v-model="newDrinkTypeName" />
|
<q-input v-model="newDrinkTypeName" dense label="name" filled />
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
<q-card-actions>
|
<q-card-actions>
|
||||||
<q-btn flat color="danger" label="Abbrechen" @click="discardChanges()" />
|
<q-btn flat color="danger" label="Abbrechen" @click="discardChanges()" />
|
||||||
|
@ -17,11 +17,11 @@
|
||||||
|
|
||||||
<q-page padding>
|
<q-page padding>
|
||||||
<q-table title="Getränkearten" :data="rows" :row-key="(row) => row.id" :columns="columns">
|
<q-table title="Getränkearten" :data="rows" :row-key="(row) => row.id" :columns="columns">
|
||||||
<template v-slot:top-right>
|
<template #top-right>
|
||||||
<q-input
|
<q-input
|
||||||
|
v-model="newDrinkType"
|
||||||
class="q-px-sm"
|
class="q-px-sm"
|
||||||
dense
|
dense
|
||||||
v-model="newDrinkType"
|
|
||||||
placeholder="Neue Getränkeart"
|
placeholder="Neue Getränkeart"
|
||||||
filled
|
filled
|
||||||
/>
|
/>
|
||||||
|
@ -29,7 +29,7 @@
|
||||||
<div></div>
|
<div></div>
|
||||||
<q-btn color="primary" icon="mdi-plus" label="Hinzufügen" @click="addType" />
|
<q-btn color="primary" icon="mdi-plus" label="Hinzufügen" @click="addType" />
|
||||||
</template>
|
</template>
|
||||||
<template v-slot:body-cell-actions="props">
|
<template #body-cell-actions="props">
|
||||||
<q-td :props="props" align="right" :auto-width="true">
|
<q-td :props="props" align="right" :auto-width="true">
|
||||||
<q-btn
|
<q-btn
|
||||||
round
|
round
|
||||||
|
@ -46,15 +46,14 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { computed, defineComponent, onBeforeMount, ref } from '@vue/composition-api';
|
import { computed, defineComponent, onBeforeMount, ref } from 'vue';
|
||||||
import { Store } from 'vuex';
|
import { useStore } from 'vuex';
|
||||||
import { StateInterface } from 'src/store';
|
|
||||||
import { DrinkInterface } from 'src/plugins/pricelist/store/drinks';
|
import { DrinkInterface } from 'src/plugins/pricelist/store/drinks';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'DrinkTypes',
|
name: 'DrinkTypes',
|
||||||
setup(_, { root }) {
|
setup() {
|
||||||
const store = <Store<StateInterface>>root.$store;
|
const store = useStore();
|
||||||
const state = <DrinkInterface>store.state.drink;
|
const state = <DrinkInterface>store.state.drink;
|
||||||
const newDrinkType = ref('');
|
const newDrinkType = ref('');
|
||||||
const newDrinkTypeName = ref('');
|
const newDrinkTypeName = ref('');
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<q-table title="Getränke" :columns="columns" :data="drinks" row-key="name">
|
<q-table title="Getränke" :columns="columns" :data="drinks" row-key="name">
|
||||||
<template v-slot:body-cell-prices="{ row: { prices } }">
|
<template #body-cell-prices="{ row: { prices } }">
|
||||||
<q-td>
|
<q-td>
|
||||||
<div v-for="price in prices" :key="price.id" class="row">
|
<div v-for="price in prices" :key="price.id" class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
{{ price.volume | setVolume }}
|
{{ setVolume(price.volume) }}
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
{{ price.price | setCurrency }}
|
{{ setCurrency(price.price) }}
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
{{ price.description }}
|
{{ price.description }}
|
||||||
|
@ -20,10 +20,11 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, onBeforeMount, ref } from '@vue/composition-api';
|
import { defineComponent, onBeforeMount, ref } from 'vue';
|
||||||
import { StateInterface } from 'src/store';
|
import { StateInterface } from 'src/store';
|
||||||
import { DrinkInterface } from '../store/drinks';
|
import { DrinkInterface } from '../store/drinks';
|
||||||
import { Store } from 'vuex';
|
import { useStore } from 'vuex';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'Pricelist',
|
name: 'Pricelist',
|
||||||
filters: {
|
filters: {
|
||||||
|
@ -37,8 +38,8 @@ export default defineComponent({
|
||||||
return `${price.toFixed(2)}€`;
|
return `${price.toFixed(2)}€`;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
setup(_, { root }) {
|
setup() {
|
||||||
const store = <Store<StateInterface>>root.$store;
|
const store = useStore();
|
||||||
const state = <DrinkInterface>store.state.drink;
|
const state = <DrinkInterface>store.state.drink;
|
||||||
const drinks = ref(state.drinks);
|
const drinks = ref(state.drinks);
|
||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
|
|
|
@ -1,44 +0,0 @@
|
||||||
<template>
|
|
||||||
<div>
|
|
||||||
<q-page padding v-if="checkMain">
|
|
||||||
<q-card>
|
|
||||||
<q-card-section>
|
|
||||||
<q-list v-for="(mainRoute, index) in mainRoutes" :key="'mainRoute' + index">
|
|
||||||
<essential-link
|
|
||||||
v-for="(route, index2) in mainRoute.children"
|
|
||||||
:key="'route' + index2"
|
|
||||||
:title="route.title"
|
|
||||||
:icon="route.icon"
|
|
||||||
:link="route.name"
|
|
||||||
:permissions="route.meta.permissions"
|
|
||||||
/>
|
|
||||||
</q-list>
|
|
||||||
</q-card-section>
|
|
||||||
</q-card>
|
|
||||||
</q-page>
|
|
||||||
<router-view />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { computed, defineComponent, onBeforeMount } from '@vue/composition-api';
|
|
||||||
import EssentialLink from 'src/components/navigation/EssentialLink.vue';
|
|
||||||
import mainRoutes from '../routes';
|
|
||||||
import store from '../store/altStore';
|
|
||||||
export default defineComponent({
|
|
||||||
// name: 'PageName'
|
|
||||||
components: { EssentialLink },
|
|
||||||
setup(_, { root }) {
|
|
||||||
const checkMain = computed(() => {
|
|
||||||
return root.$route.matched.length == 2;
|
|
||||||
});
|
|
||||||
onBeforeMount(() => {
|
|
||||||
store.actions.getDrinks();
|
|
||||||
store.actions.getExtraIngredients();
|
|
||||||
store.actions.getDrinkTypes();
|
|
||||||
});
|
|
||||||
|
|
||||||
return { checkMain, mainRoutes };
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<q-tabs v-model="tab" v-if="$q.screen.gt.sm">
|
<q-tabs v-if="$q.screen.gt.sm" v-model="tab">
|
||||||
<q-tab
|
<q-tab
|
||||||
v-for="(tabindex, index) in tabs"
|
v-for="(tabindex, index) in tabs"
|
||||||
:key="'tab' + index"
|
:key="'tab' + index"
|
||||||
|
@ -8,10 +8,10 @@
|
||||||
:label="tabindex.label"
|
:label="tabindex.label"
|
||||||
/>
|
/>
|
||||||
</q-tabs>
|
</q-tabs>
|
||||||
<div class="fit row justify-end" v-else>
|
<div v-else class="fit row justify-end">
|
||||||
<q-btn flat round icon="mdi-menu" @click="showDrawer = !showDrawer"></q-btn>
|
<q-btn flat round icon="mdi-menu" @click="showDrawer = !showDrawer"></q-btn>
|
||||||
</div>
|
</div>
|
||||||
<q-drawer side="right" v-model="showDrawer" @click="showDrawer = !showDrawer" behavior="mobile">
|
<q-drawer v-model="showDrawer" side="right" behavior="mobile" @click="showDrawer = !showDrawer">
|
||||||
<q-list v-model="tab">
|
<q-list v-model="tab">
|
||||||
<q-item
|
<q-item
|
||||||
v-for="(tabindex, index) in tabs"
|
v-for="(tabindex, index) in tabs"
|
||||||
|
@ -46,7 +46,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { computed, defineComponent, ref } from '@vue/composition-api';
|
import { computed, defineComponent, ref } from 'vue';
|
||||||
import { Screen } from 'quasar';
|
import { Screen } from 'quasar';
|
||||||
import DrinkTypes from 'src/plugins/pricelist/components/DrinkTypes.vue';
|
import DrinkTypes from 'src/plugins/pricelist/components/DrinkTypes.vue';
|
||||||
import CalculationTable from 'src/plugins/pricelist/components/CalculationTable.vue';
|
import CalculationTable from 'src/plugins/pricelist/components/CalculationTable.vue';
|
||||||
|
|
|
@ -3,29 +3,35 @@ const mainRoutes: FG_Plugin.PluginRouteConfig[] = [
|
||||||
{
|
{
|
||||||
title: 'Getränke',
|
title: 'Getränke',
|
||||||
icon: 'mdi-glass-mug-variant',
|
icon: 'mdi-glass-mug-variant',
|
||||||
|
route: {
|
||||||
path: 'drinks',
|
path: 'drinks',
|
||||||
name: 'drinks',
|
name: 'drinks',
|
||||||
component: () => import('../pages/MainPage.vue'),
|
redirect: { name: 'drinks-pricelist' },
|
||||||
meta: { permissions: ['user'] },
|
},
|
||||||
|
permissions: ['user'],
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
title: 'Preisliste',
|
title: 'Preisliste',
|
||||||
icon: 'mdi-cash-100',
|
icon: 'mdi-cash-100',
|
||||||
|
shortcut: true,
|
||||||
|
permissions: ['user'],
|
||||||
|
route: {
|
||||||
path: 'pricelist',
|
path: 'pricelist',
|
||||||
name: 'drinks-pricelist',
|
name: 'drinks-pricelist',
|
||||||
shortcut: true,
|
|
||||||
meta: { permissions: ['user'] },
|
|
||||||
component: () => import('../pages/Pricelist.vue'),
|
component: () => import('../pages/Pricelist.vue'),
|
||||||
},
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: 'Einstellungen',
|
title: 'Einstellungen',
|
||||||
icon: 'mdi-coffee-to-go',
|
icon: 'mdi-coffee-to-go',
|
||||||
|
shortcut: false,
|
||||||
|
permissions: ['pricelist_settings'],
|
||||||
|
route: {
|
||||||
path: 'settings',
|
path: 'settings',
|
||||||
name: 'drinks-settings',
|
name: 'drinks-settings',
|
||||||
shortcut: false,
|
|
||||||
meta: { permissions: ['users_edit_other'] },
|
|
||||||
component: () => import('../pages/Settings.vue'),
|
component: () => import('../pages/Settings.vue'),
|
||||||
},
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
Loading…
Reference in New Issue