[pricelist] add pricelist as list

This commit is contained in:
Tim Gröger 2021-04-15 22:04:33 +02:00
parent 479dfd658a
commit 8ee5c891a5
6 changed files with 301 additions and 9 deletions

View File

@ -13,6 +13,7 @@
<template #top-right> <template #top-right>
<div class="row justify-end q-gutter-sm"> <div class="row justify-end q-gutter-sm">
<search-input v-model="search" :keys="search_keys" /> <search-input v-model="search" :keys="search_keys" />
<slot></slot>
<q-btn v-if="!public && !nodetails" label="Aufpreise"> <q-btn v-if="!public && !nodetails" label="Aufpreise">
<q-menu anchor="center middle" self="center middle"> <q-menu anchor="center middle" self="center middle">
<min-price-setting /> <min-price-setting />

View File

@ -0,0 +1,206 @@
<template>
<q-table
title="Preisliste"
:columns="columns"
:rows="drinks"
:visible-columns="visibleColumns"
:filter="search"
:filter-method="filter"
dense
>
<template #top-right>
<div class="row justify-end q-gutter-sm">
<search-input v-model="search" :keys="options" />
<q-select
v-model="visibleColumns"
multiple
filled
dense
options-dense
display-value="Sichtbarkeit"
emit-value
map-options
:options="options"
option-value="name"
options-cover
/>
<slot></slot>
</div>
</template>
<template #body-cell-tags="props">
<q-td :props="props">
<q-badge
v-for="tag in props.row.tags"
:key="`${props.row.id}-${tag.id}`"
class="text-caption"
rounded
:style="`background-color: ${tag.color}`"
>
{{ tag.name }}
</q-badge>
</q-td>
</template>
<template #body-cell-public="props">
<q-td :props="props">
<q-toggle
v-model="props.row.public"
disable
checked-icon="mdi-earth"
unchecked-icon="mdi-earth-off"
/>
</q-td>
</template>
</q-table>
</template>
<script lang="ts">
import { computed, defineComponent, onBeforeMount, ref } from 'vue';
import { usePricelistStore } from '../store';
import { useMainStore } from 'src/stores';
import { Search, filter } from 'src/plugins/pricelist/utils/filter';
import SearchInput from 'src/plugins/pricelist/components/SearchInput.vue';
export default defineComponent({
name: 'Pricelist',
components: { SearchInput },
props: {
public: {
type: Boolean,
default: false,
},
},
setup(props) {
const store = usePricelistStore();
const user = ref('');
onBeforeMount(() => {
if (!props.public) {
user.value = useMainStore().currentUser.userid;
void store.getPriceCalcColumn(user.value);
} else {
user.value = '';
}
});
const columns = [
{
name: 'name',
label: 'Name',
field: 'name',
sortable: true,
filterable: true,
},
{
name: 'type',
label: 'Kategorie',
field: 'type',
sortable: true,
filterable: true,
format: (val: FG.DrinkType) => val.name,
},
{
name: 'tags',
label: 'Tags',
field: 'tags',
filterable: true,
format: (val: Array<FG.Tag>) => {
let retVal = '';
val.forEach((tag, index) => {
if (index >= val.length - 1 && index > 0) {
retVal += ', ';
}
retVal += tag.name;
});
return retVal;
},
},
{
name: 'volume',
label: 'Inhalt',
field: 'volume',
filterable: true,
sortable: true,
format: (val: number) => `${val.toFixed(3)}L`,
},
{
name: 'price',
label: 'Preis',
field: 'price',
sortable: true,
filterable: true,
format: (val: number) => `${val.toFixed(2)}`,
},
{
name: 'public',
label: 'Öffentlich',
field: 'public',
format: (val: boolean) => (val ? 'Öffentlich' : 'nicht Öffentlich'),
},
{
name: 'description',
label: 'Beschreibung',
field: 'description',
filterable: true,
},
];
const _options = computed(() => {
const retVal: Array<{ name: string; label: string; field: string }> = [];
columns.forEach((col) => {
if (props.public) {
if (col.name !== 'public') {
retVal.push(col);
}
} else {
retVal.push(col);
}
});
return retVal;
});
const _colums = computed<Array<string>>(() => {
const retVal: Array<string> = [];
columns.forEach((col) => {
if (props.public) {
if (col.name !== 'public') {
retVal.push(col.name);
}
} else {
retVal.push(col.name);
}
});
return retVal;
});
const _visibleColumns = ref(_colums.value);
const visibleColumns = computed({
get: () => (props.public ? _visibleColumns.value : store.pricecalc_columns),
set: (val) => {
if (!props.public) {
void store.updatePriceCalcColumn(user.value, val);
} else {
_visibleColumns.value = val;
}
},
});
const search = ref<Search>({
value: '',
key: '',
label: '',
});
return {
drinks: computed(() => store.pricelist),
columns,
visibleColumns,
options: _options,
search,
filter,
};
},
});
</script>
<style scoped></style>

View File

@ -1,14 +1,32 @@
<template> <template>
<calculation-table nodetails /> <calculation-table v-if="!list" nodetails>
<q-btn icon="mdi-view-list" round @click="list = !list">
<q-tooltip> Zur Listenansicht wechseln </q-tooltip>
</q-btn>
</calculation-table>
<pricelist v-if="list">
<q-btn icon="mdi-cards-variant" round @click="list = !list">
<q-tooltip> Zur Kartenansicht wechseln </q-tooltip>
</q-btn>
</pricelist>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent } from 'vue'; import { defineComponent, onBeforeMount, ref } from 'vue';
import CalculationTable from '../components/CalculationTable.vue'; import CalculationTable from '../components/CalculationTable.vue';
import Pricelist from 'src/plugins/pricelist/components/Pricelist.vue';
import { usePricelistStore } from 'src/plugins/pricelist/store';
export default defineComponent({ export default defineComponent({
name: 'InnerPricelist', name: 'InnerPricelist',
components: { CalculationTable }, components: { Pricelist, CalculationTable },
setup() { setup() {
return {}; const store = usePricelistStore();
onBeforeMount(() => {
void store.getDrinks();
});
const list = ref(false);
return { list };
}, },
}); });
</script> </script>

View File

@ -1,13 +1,36 @@
<template> <template>
<calculation-table public /> <calculation-table v-if="!list" public>
<q-btn icon="mdi-view-list" round @click="list = !list">
<q-tooltip> Zur Listenansicht wechseln </q-tooltip>
</q-btn>
</calculation-table>
<pricelist v-if="list" public>
<q-btn icon="mdi-cards-variant" round @click="list = !list">
<q-tooltip> Zur Kartenansicht wechseln </q-tooltip>
</q-btn>
</pricelist>
</template> </template>
<script> <script>
import { defineComponent } from 'vue';
import CalculationTable from '../components/CalculationTable.vue'; import CalculationTable from '../components/CalculationTable.vue';
export default { import Pricelist from '../components/Pricelist.vue';
import { usePricelistStore } from '../store';
import { onBeforeMount, ref } from 'vue';
export default defineComponent({
name: 'OuterPricelist', name: 'OuterPricelist',
components: { CalculationTable }, components: { Pricelist, CalculationTable },
}; setup() {
const store = usePricelistStore();
onBeforeMount(() => {
void store.getDrinks();
});
const list = ref(false);
return { list };
},
});
</script> </script>
<style scoped></style> <style scoped></style>

View File

@ -94,7 +94,11 @@ export default defineComponent({
const _tabs: Tab[] = [ const _tabs: Tab[] = [
{ name: 'pricelist', label: 'Getränke', permissions: ['drink_edit'] }, { name: 'pricelist', label: 'Getränke', permissions: ['drink_edit'] },
{ name: 'extra_ingredients', label: 'Zutaten', permissions: ['edit_ingredients', 'delete_ingredients'] }, {
name: 'extra_ingredients',
label: 'Zutaten',
permissions: ['edit_ingredients', 'delete_ingredients'],
},
{ {
name: 'drink_types', name: 'drink_types',
label: 'Getränketypen', label: 'Getränketypen',

View File

@ -17,6 +17,16 @@ interface Drink extends Omit<Omit<FG.Drink, 'cost_per_volume'>, 'volumes'> {
_cost_per_volume?: number; _cost_per_volume?: number;
} }
interface Pricelist {
name: string;
type: FG.DrinkType;
tags: Array<FG.Tag>;
volume: number;
price: number;
public: boolean;
description: string;
}
class DrinkPriceVolume implements DrinkPriceVolume { class DrinkPriceVolume implements DrinkPriceVolume {
constructor({ id, volume, prices, ingredients }: FG.DrinkPriceVolume) { constructor({ id, volume, prices, ingredients }: FG.DrinkPriceVolume) {
this.id = id; this.id = id;
@ -67,6 +77,7 @@ export const usePricelistStore = defineStore({
extraIngredients: [] as Array<FG.ExtraIngredient>, extraIngredients: [] as Array<FG.ExtraIngredient>,
min_prices: [] as Array<number>, min_prices: [] as Array<number>,
tags: [] as Array<FG.Tag>, tags: [] as Array<FG.Tag>,
pricecalc_columns: [] as Array<string>,
}), }),
actions: { actions: {
@ -244,6 +255,35 @@ export const usePricelistStore = defineStore({
this.tags.splice(index, 1); this.tags.splice(index, 1);
} }
}, },
async getPriceCalcColumn(userid: string) {
const { data } = await api.get<Array<string>>(`pricelist/users/${userid}/pricecalc_columns`);
this.pricecalc_columns = data;
},
async updatePriceCalcColumn(userid: string, data: Array<string>) {
await api.put<Array<string>>(`pricelist/users/${userid}/pricecalc_columns`, data);
this.pricecalc_columns = data;
},
},
getters: {
pricelist() {
const retVal: Array<Pricelist> = [];
this.drinks.forEach((drink) => {
drink.volumes.forEach((volume) => {
volume.prices.forEach((price) => {
retVal.push({
name: drink.name,
type: <FG.DrinkType>drink.type,
tags: <Array<FG.Tag>>drink.tags,
volume: <number>volume.volume,
price: price.price,
public: price.public,
description: <string>price.description,
});
});
});
});
return retVal;
},
}, },
}); });