<template> <q-table title="Preisliste" :columns="columns" :rows="drinks" :visible-columns="visibleColumns" :filter="search" :filter-method="filter" dense :pagination="pagination" :fullscreen="fullscreen" > <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 /> <q-btn round icon="mdi-backburger"> <q-tooltip anchor='top middle' self='bottom middle'> Reihenfolge ändern </q-tooltip> <q-menu anchor="bottom middle" self="top middle"> <drag v-model="order" class="q-list" ghost-class="ghost" group="people" item-key="id"> <template #item="{ element }"> <q-item> <q-item-section> {{ element.label }} </q-item-section> </q-item> </template> </drag> </q-menu> </q-btn> <slot></slot> <q-btn round :icon="fullscreen ? 'mdi-fullscreen-exit' : 'mdi-fullscreen'" @click="fullscreen = !fullscreen" /> </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, ComponentPublicInstance } from 'vue'; import SearchInput from '../components/SearchInput.vue'; import { usePricelistStore, Order } from '../store'; import { useMainStore } from '@flaschengeist/api'; import { Search, filter } from '../utils/filter'; import drag from 'vuedraggable'; interface Row { name: string; label: string; field: string; sortable?: boolean; filterable?: boolean; format?: (val: never) => string; align?: string; } export default defineComponent({ name: 'Pricelist', components: { SearchInput, drag: <ComponentPublicInstance>drag }, 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.getPriceListColumnOrder(user.value); void store.getDrinks(); void store.getPriceCalcColumn(user.value); } else { user.value = ''; } }); const _order = ref<Array<Order>>([ { name: 'name', label: 'Name', }, { name: 'type', label: 'Kategorie', }, { name: 'tags', label: 'Tags', }, { name: 'volume', label: 'Inhalt', }, { name: 'price', label: 'Preis', }, { name: 'public', label: 'Öffentlich', }, { name: 'description', label: 'Beschreibung', }, ]); const order = computed<Array<Order>>({ get: () => { if (props.public) { return _order.value; } if (store.pricelist_columns_order.length === 0) { return _order.value; } return store.pricelist_columns_order; }, set: (val: Array<Order>) => { if (!props.public) { void store.updatePriceListColumnOrder(user.value, val); } else { _order.value = val; } }, }); const _columns: Array<Row> = [ { name: 'name', label: 'Name', field: 'name', sortable: true, filterable: true, align: 'left', }, { 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 columns = computed(() => { const retVal: Array<Row> = []; if (order.value) { order.value.forEach((col) => { const _col = _columns.find((a) => a.name === col.name); if (_col) { retVal.push(_col); } }); retVal.forEach((element, index) => { element.align = 'right'; if (index === 0) { element.align = 'left'; } }); return retVal; } return _columns; }); const _options = computed(() => { const retVal: Array<{ name: string; label: string; field: string }> = []; columns.value.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.value.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: '', }); const pagination = ref({ sortBy: 'name', rowsPerPage: 10, }); const fullscreen = ref(false); return { drinks: computed(() => store.pricelist), columns, order, visibleColumns, options: _options, search, filter, pagination, fullscreen, }; }, }); </script> <style scoped lang="sass"> .ghost opacity: 0.5 background: $accent </style>