release v2.0.0 #4
|
@ -132,5 +132,6 @@ declare namespace FG {
|
||||||
interface Tag {
|
interface Tag {
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
|
color: string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,26 +123,6 @@
|
||||||
/>
|
/>
|
||||||
</q-popup-edit>
|
</q-popup-edit>
|
||||||
</q-td>
|
</q-td>
|
||||||
<q-td key="article_id" :props="drinks_props">
|
|
||||||
{{ drinks_props.row.article_id || 'o.A.' }}
|
|
||||||
<q-popup-edit
|
|
||||||
v-slot="scope"
|
|
||||||
v-model="drinks_props.row.article_id"
|
|
||||||
buttons
|
|
||||||
label-cancel="Abbrechen"
|
|
||||||
label-set="Speichern"
|
|
||||||
@update:modelValue="updateDrink(drinks_props.row)"
|
|
||||||
>
|
|
||||||
<q-input
|
|
||||||
v-model="scope.value"
|
|
||||||
filled
|
|
||||||
dense
|
|
||||||
autofocus
|
|
||||||
clearable
|
|
||||||
@keyup.enter="scope.set"
|
|
||||||
/>
|
|
||||||
</q-popup-edit>
|
|
||||||
</q-td>
|
|
||||||
<q-td key="drink_type" :props="drinks_props">
|
<q-td key="drink_type" :props="drinks_props">
|
||||||
{{ drinks_props.row.type.name }}
|
{{ drinks_props.row.type.name }}
|
||||||
<q-popup-edit
|
<q-popup-edit
|
||||||
|
@ -165,6 +145,79 @@
|
||||||
/>
|
/>
|
||||||
</q-popup-edit>
|
</q-popup-edit>
|
||||||
</q-td>
|
</q-td>
|
||||||
|
<q-td key="tags" :props="drinks_props">
|
||||||
|
<q-badge
|
||||||
|
v-for="tag in drinks_props.row.tags"
|
||||||
|
:key="`${drinks_props.row.id}-${tag.id}`"
|
||||||
|
class="q-ma-xs"
|
||||||
|
rounded
|
||||||
|
:style="`background-color: ${tag.color}`"
|
||||||
|
>
|
||||||
|
{{ tag.name }}
|
||||||
|
</q-badge>
|
||||||
|
<q-popup-edit
|
||||||
|
v-model="drinks_props.row.tags"
|
||||||
|
buttons
|
||||||
|
label-cancel="Abbrechen"
|
||||||
|
label-set="Speichern"
|
||||||
|
@update:modelValue="updateDrink(drinks_props.row)"
|
||||||
|
>
|
||||||
|
<template #default="scope">
|
||||||
|
<q-select
|
||||||
|
v-model="scope.value"
|
||||||
|
multiple
|
||||||
|
:options="tags"
|
||||||
|
label="Tags"
|
||||||
|
option-label="name"
|
||||||
|
filled
|
||||||
|
>
|
||||||
|
<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>
|
||||||
|
</template>
|
||||||
|
</q-popup-edit>
|
||||||
|
</q-td>
|
||||||
|
<q-td key="article_id" :props="drinks_props">
|
||||||
|
{{ drinks_props.row.article_id || 'o.A.' }}
|
||||||
|
<q-popup-edit
|
||||||
|
v-slot="scope"
|
||||||
|
v-model="drinks_props.row.article_id"
|
||||||
|
buttons
|
||||||
|
label-cancel="Abbrechen"
|
||||||
|
label-set="Speichern"
|
||||||
|
@update:modelValue="updateDrink(drinks_props.row)"
|
||||||
|
>
|
||||||
|
<q-input
|
||||||
|
v-model="scope.value"
|
||||||
|
filled
|
||||||
|
dense
|
||||||
|
autofocus
|
||||||
|
clearable
|
||||||
|
@keyup.enter="scope.set"
|
||||||
|
/>
|
||||||
|
</q-popup-edit>
|
||||||
|
</q-td>
|
||||||
<q-td key="volume_package" :props="drinks_props">
|
<q-td key="volume_package" :props="drinks_props">
|
||||||
{{ drinks_props.row.volume ? `${drinks_props.row.volume} L` : 'o.A.' }}
|
{{ drinks_props.row.volume ? `${drinks_props.row.volume} L` : 'o.A.' }}
|
||||||
<q-popup-edit
|
<q-popup-edit
|
||||||
|
@ -347,7 +400,8 @@ export default defineComponent({
|
||||||
const store = usePricelistStore();
|
const store = usePricelistStore();
|
||||||
|
|
||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
void store.getDrinkTypes();
|
void store.getDrinkTypes(true);
|
||||||
|
void store.getTags();
|
||||||
void store.getExtraIngredients();
|
void store.getExtraIngredients();
|
||||||
void store.get_min_prices();
|
void store.get_min_prices();
|
||||||
store.getPriceCalcColumn(user);
|
store.getPriceCalcColumn(user);
|
||||||
|
@ -367,13 +421,7 @@ export default defineComponent({
|
||||||
sortable: true,
|
sortable: true,
|
||||||
sort,
|
sort,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: 'article_id',
|
|
||||||
label: 'Artikelnummer',
|
|
||||||
field: 'article_id',
|
|
||||||
sortable: true,
|
|
||||||
sort,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: 'drink_type',
|
name: 'drink_type',
|
||||||
label: 'Kategorie',
|
label: 'Kategorie',
|
||||||
|
@ -382,6 +430,28 @@ export default defineComponent({
|
||||||
sortable: true,
|
sortable: true,
|
||||||
sort: (a: FG.DrinkType, b: FG.DrinkType) => sort(a.name, b.name),
|
sort: (a: FG.DrinkType, b: FG.DrinkType) => sort(a.name, b.name),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'tags',
|
||||||
|
label: 'Tags',
|
||||||
|
field: 'tags',
|
||||||
|
format: (val: Array<FG.Tag>) => {
|
||||||
|
let retVal = '';
|
||||||
|
val.forEach((tag, index) => {
|
||||||
|
if (index > 0) {
|
||||||
|
retVal += ', ';
|
||||||
|
}
|
||||||
|
retVal += tag.name;
|
||||||
|
});
|
||||||
|
return retVal;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'article_id',
|
||||||
|
label: 'Artikelnummer',
|
||||||
|
field: 'article_id',
|
||||||
|
sortable: true,
|
||||||
|
sort,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'volume_package',
|
name: 'volume_package',
|
||||||
label: 'Inhalt in l des Gebinde',
|
label: 'Inhalt in l des Gebinde',
|
||||||
|
@ -547,6 +617,7 @@ export default defineComponent({
|
||||||
console,
|
console,
|
||||||
search,
|
search,
|
||||||
filter,
|
filter,
|
||||||
|
tags: computed(() => store.tags),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -60,7 +60,6 @@ export default defineComponent({
|
||||||
const actualDrinkType = ref(emptyDrinkType);
|
const actualDrinkType = ref(emptyDrinkType);
|
||||||
|
|
||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
console.log(store);
|
|
||||||
void store.getDrinkTypes();
|
void store.getDrinkTypes();
|
||||||
});
|
});
|
||||||
const rows = computed(() => store.drinkTypes);
|
const rows = computed(() => store.drinkTypes);
|
||||||
|
|
|
@ -31,6 +31,19 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</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="q-ma-xs"
|
||||||
|
rounded
|
||||||
|
:style="`background-color: ${tag.color}`"
|
||||||
|
>
|
||||||
|
{{ tag.name }}
|
||||||
|
</q-badge>
|
||||||
|
</q-td>
|
||||||
|
</template>
|
||||||
<template #body-cell-volumes="props">
|
<template #body-cell-volumes="props">
|
||||||
<q-td :props="props">
|
<q-td :props="props">
|
||||||
<q-table
|
<q-table
|
||||||
|
@ -150,6 +163,22 @@ export default defineComponent({
|
||||||
sortable: true,
|
sortable: true,
|
||||||
sort: (a: FG.DrinkType, b: FG.DrinkType) => sort(a.name, b.name),
|
sort: (a: FG.DrinkType, b: FG.DrinkType) => sort(a.name, b.name),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'tags',
|
||||||
|
label: 'Tags',
|
||||||
|
field: 'tags',
|
||||||
|
format: (val: Array<FG.Tag>) => {
|
||||||
|
let retVal = '';
|
||||||
|
val.forEach((tag, index) => {
|
||||||
|
if (index > 0) {
|
||||||
|
retVal += ', ';
|
||||||
|
}
|
||||||
|
retVal += tag.name;
|
||||||
|
});
|
||||||
|
return retVal;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
name: 'volumes',
|
name: 'volumes',
|
||||||
label: 'Preise',
|
label: 'Preise',
|
||||||
|
|
|
@ -0,0 +1,166 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<q-page padding>
|
||||||
|
<q-table title="Tags" :rows="rows" :row-key="(row) => row.id" :columns="columns">
|
||||||
|
<template #top-right>
|
||||||
|
<q-btn color="primary" icon="mdi-plus" label="Hinzufügen">
|
||||||
|
<q-menu v-model="popup" anchor="center middle" self="center middle" persistent>
|
||||||
|
<div>
|
||||||
|
<q-input
|
||||||
|
v-model="newTag.name"
|
||||||
|
filled
|
||||||
|
dense
|
||||||
|
label="Name"
|
||||||
|
class="q-pa-sm"
|
||||||
|
:rule="[notExists]"
|
||||||
|
/>
|
||||||
|
<q-color
|
||||||
|
:model-value="newTag.color"
|
||||||
|
class="q-pa-sm"
|
||||||
|
@change="
|
||||||
|
(val) => {
|
||||||
|
newTag.color = val;
|
||||||
|
}
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
<div class="row q-gutter-sm justify-around">
|
||||||
|
<q-btn v-close-popup label="Abbrechen" />
|
||||||
|
<q-btn label="Speichern" color="primary" @click="save" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</q-menu>
|
||||||
|
</q-btn>
|
||||||
|
</template>
|
||||||
|
<template #header="props">
|
||||||
|
<q-tr :props="props">
|
||||||
|
<q-th v-for="col in props.cols" :key="col.name" :props="props">
|
||||||
|
{{ col.label }}
|
||||||
|
</q-th>
|
||||||
|
<q-th auto-width />
|
||||||
|
</q-tr>
|
||||||
|
</template>
|
||||||
|
<template #body="props">
|
||||||
|
<q-tr :props="props">
|
||||||
|
<q-td key="name" :props="props">
|
||||||
|
{{ props.row.name }}
|
||||||
|
<q-popup-edit
|
||||||
|
v-model="props.row.name"
|
||||||
|
buttons
|
||||||
|
label-cancel="Abbrechen"
|
||||||
|
label-set="Speichern"
|
||||||
|
@update:modelValue="updateTag(props.row)"
|
||||||
|
>
|
||||||
|
<template #default="scope">
|
||||||
|
<div class="fit row justify-around">
|
||||||
|
<q-input v-model="scope.value" :rules="[notExists]" dense filled />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</q-popup-edit>
|
||||||
|
</q-td>
|
||||||
|
<q-td key="color" :props="props">
|
||||||
|
<div class="full-width row q-gutter-sm justify-end items-center">
|
||||||
|
<div>
|
||||||
|
{{ props.row.color }}
|
||||||
|
</div>
|
||||||
|
<div class="color-box" :style="`background-color: ${props.row.color};`"> </div>
|
||||||
|
</div>
|
||||||
|
<q-popup-edit
|
||||||
|
v-model="props.row.color"
|
||||||
|
buttons
|
||||||
|
label-cancel="Abbrechen"
|
||||||
|
label-set="Speichern"
|
||||||
|
@update:modelValue="updateTag(props.row)"
|
||||||
|
>
|
||||||
|
<template #default="slot">
|
||||||
|
<div class="fit row justify-around">
|
||||||
|
<q-color :model-value="slot.value" @change="(val) => (slot.value = val)" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</q-popup-edit>
|
||||||
|
</q-td>
|
||||||
|
<q-td>
|
||||||
|
<q-btn
|
||||||
|
icon="mdi-delete"
|
||||||
|
color="negative"
|
||||||
|
round
|
||||||
|
size="sm"
|
||||||
|
@click="deleteTag(props.row)"
|
||||||
|
/>
|
||||||
|
</q-td>
|
||||||
|
</q-tr>
|
||||||
|
</template>
|
||||||
|
</q-table>
|
||||||
|
</q-page>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent, ref, onBeforeMount, computed } from 'vue';
|
||||||
|
import { usePricelistStore } from '../store';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'Tags',
|
||||||
|
setup() {
|
||||||
|
const store = usePricelistStore();
|
||||||
|
onBeforeMount(() => {
|
||||||
|
void store.getTags();
|
||||||
|
});
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
name: 'name',
|
||||||
|
label: 'Name',
|
||||||
|
field: 'name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'color',
|
||||||
|
label: 'Farbe',
|
||||||
|
field: 'color',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const rows = computed(() => store.tags);
|
||||||
|
const emptyTag = {
|
||||||
|
id: -1,
|
||||||
|
color: '#1976d2',
|
||||||
|
name: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
async function save() {
|
||||||
|
await store.setTag(newTag.value);
|
||||||
|
popup.value = false;
|
||||||
|
newTag.value = emptyTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
const newTag = ref(emptyTag);
|
||||||
|
const popup = ref(false);
|
||||||
|
function notExists(val: string) {
|
||||||
|
const index = store.tags.findIndex((a) => a.name === val);
|
||||||
|
if (index > -1) {
|
||||||
|
return 'Tag existiert bereits.';
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
columns,
|
||||||
|
rows,
|
||||||
|
newTag,
|
||||||
|
popup,
|
||||||
|
save,
|
||||||
|
updateTag: store.updateTag,
|
||||||
|
notExists,
|
||||||
|
deleteTag: store.deleteTag,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.color-box {
|
||||||
|
min-width: 28px;
|
||||||
|
min-heigh: 28px;
|
||||||
|
max-width: 28px;
|
||||||
|
max-height: 28px;
|
||||||
|
border-width: 1px;
|
||||||
|
border-color: black;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -23,10 +23,26 @@
|
||||||
"
|
"
|
||||||
placeholder-src="no-image.svg"
|
placeholder-src="no-image.svg"
|
||||||
>
|
>
|
||||||
<div class="absolute-bottom-right text-subtitle2">
|
<div class="absolute-bottom-right justify-end">
|
||||||
{{ props.row.name }}
|
<div class="text-subtitle1 text-right">
|
||||||
|
{{ props.row.name }}
|
||||||
|
</div>
|
||||||
|
<div class="text-caption text-right">
|
||||||
|
{{ props.row.type.name }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</q-img>
|
</q-img>
|
||||||
|
<q-card-section>
|
||||||
|
<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-card-section>
|
||||||
<build-manual-volume :volumes="props.row.volumes" />
|
<build-manual-volume :volumes="props.row.volumes" />
|
||||||
<q-card-section>
|
<q-card-section>
|
||||||
<div class="text-h6">Anleitung</div>
|
<div class="text-h6">Anleitung</div>
|
||||||
|
|
|
@ -40,6 +40,9 @@
|
||||||
<q-tab-panel name="drink_types">
|
<q-tab-panel name="drink_types">
|
||||||
<drink-types />
|
<drink-types />
|
||||||
</q-tab-panel>
|
</q-tab-panel>
|
||||||
|
<q-tab-panel name="tags">
|
||||||
|
<tags />
|
||||||
|
</q-tab-panel>
|
||||||
</q-tab-panels>
|
</q-tab-panels>
|
||||||
</q-page>
|
</q-page>
|
||||||
</div>
|
</div>
|
||||||
|
@ -51,11 +54,12 @@ 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';
|
||||||
import ExtraIngredients from 'src/plugins/pricelist/components/ExtraIngredients.vue';
|
import ExtraIngredients from 'src/plugins/pricelist/components/ExtraIngredients.vue';
|
||||||
|
import Tags from '../components/Tags.vue';
|
||||||
import { usePricelistStore } from 'src/plugins/pricelist/store';
|
import { usePricelistStore } from 'src/plugins/pricelist/store';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'Settings',
|
name: 'Settings',
|
||||||
components: { ExtraIngredients, DrinkTypes, CalculationTable },
|
components: { ExtraIngredients, DrinkTypes, CalculationTable, Tags },
|
||||||
setup() {
|
setup() {
|
||||||
interface Tab {
|
interface Tab {
|
||||||
name: string;
|
name: string;
|
||||||
|
@ -89,6 +93,7 @@ export default defineComponent({
|
||||||
{ name: 'pricelist', label: 'Getränke' },
|
{ name: 'pricelist', label: 'Getränke' },
|
||||||
{ name: 'extra_ingredients', label: 'Zutaten' },
|
{ name: 'extra_ingredients', label: 'Zutaten' },
|
||||||
{ name: 'drink_types', label: 'Getränketypen' },
|
{ name: 'drink_types', label: 'Getränketypen' },
|
||||||
|
{ name: 'tags', label: 'Tags' },
|
||||||
];
|
];
|
||||||
|
|
||||||
const tab = ref<string>('pricelist');
|
const tab = ref<string>('pricelist');
|
||||||
|
|
|
@ -96,6 +96,7 @@ export const usePricelistStore = defineStore({
|
||||||
extraIngredients: [] as Array<FG.ExtraIngredient>,
|
extraIngredients: [] as Array<FG.ExtraIngredient>,
|
||||||
pricecalc_columns: [] as Array<string>,
|
pricecalc_columns: [] as Array<string>,
|
||||||
min_prices: [] as Array<number>,
|
min_prices: [] as Array<number>,
|
||||||
|
tags: [] as Array<FG.Tag>,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
|
@ -319,6 +320,28 @@ export const usePricelistStore = defineStore({
|
||||||
await api.delete(`pricelist/drinks/${drink.id}/picture`);
|
await api.delete(`pricelist/drinks/${drink.id}/picture`);
|
||||||
drink.uuid = '';
|
drink.uuid = '';
|
||||||
},
|
},
|
||||||
|
async getTags() {
|
||||||
|
const { data } = await api.get<Array<FG.Tag>>('/pricelist/tags');
|
||||||
|
this.tags = data;
|
||||||
|
},
|
||||||
|
async setTag(tag: FG.Tag) {
|
||||||
|
const { data } = await api.post<FG.Tag>('/pricelist/tags', tag);
|
||||||
|
this.tags.push(data);
|
||||||
|
},
|
||||||
|
async updateTag(tag: FG.Tag) {
|
||||||
|
const { data } = await api.put<FG.Tag>(`/pricelist/tags/${tag.id}`, tag);
|
||||||
|
const index = this.tags.findIndex((a) => a.id === data.id);
|
||||||
|
if (index > -1) {
|
||||||
|
this.tags[index] = data;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async deleteTag(tag: FG.Tag) {
|
||||||
|
await api.delete(`/pricelist/tags/${tag.id}`);
|
||||||
|
const index = this.tags.findIndex((a) => a.id === tag.id);
|
||||||
|
if (index > -1) {
|
||||||
|
this.tags.splice(index, 1);
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue