flaschengeist-pricelist/src/components/Pricelist.vue

375 lines
9.3 KiB
Vue
Raw Normal View History

<template>
<q-table
title="Preisliste"
:columns="columns"
:rows="drinks"
:visible-columns="visibleColumns"
:filter="search"
dense
v-model:pagination="pagination"
:fullscreen="fullscreen"
@request="onRequest"
>
<!--
:filter-method="filter"-->
<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">
2021-11-12 09:44:18 +00:00
<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.getPriceCalcColumn(user.value);
} else {
user.value = '';
}
onRequest({ pagination: pagination.value, filter: { limit: 10 } });
});
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',
field: 'volume',
format: (val: FG.DrinkPriceVolume) => val.drink.name,
sortable: true,
filterable: true,
align: 'left',
},
{
name: 'type',
label: 'Kategorie',
//field: 'type',
field: 'volume',
sortable: true,
filterable: true,
format: (val: FG.DrinkPriceVolume) => val.drink.type.name,
},
{
name: 'tags',
label: 'Tags',
//field: 'tags',
field: 'volume',
filterable: true,
format: (val: FG.DrinkPriceVolume) => {
let retVal = '';
val.drink.tags.forEach((tag, index) => {
if (index >= val.length - 1 && index > 0) {
retVal += ', ';
}
retVal += tag.name;
});
return retVal;
},
},
{
name: 'volume',
label: 'Inhalt',
//field: 'volume',
field: 'volume',
filterable: true,
sortable: true,
format: (val: FG.DrinkPriceVolume) => `${val.volume.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: '',
});
interface PaginationInterface {
sortBy: string;
descending: boolean;
page: number;
rowsPerPage: number;
rowsNumber: number;
}
async function onRequest(props: { pagination: PaginationInterface; filter?: Search }) {
const { page, rowsPerPage, sortBy, descending } = props.pagination;
loading.value = true;
//console.log('search_keys', search_keys);
const fetchCount = rowsPerPage === 0 ? pagination.value.rowsNumber : rowsPerPage;
const startRow = (page - 1) * rowsPerPage;
console.log('descending', descending);
try {
const result = await store.getPricelist({
offset: startRow,
limit: fetchCount,
descending: descending ? true : undefined,
search_name: props.filter?.value,
search_key: props.filter?.key,
sortBy: sortBy,
});
pagination.value.page = page;
pagination.value.rowsPerPage = rowsPerPage;
pagination.value.sortBy = sortBy;
pagination.value.descending = descending;
console.log('result', result);
if (result) pagination.value.rowsNumber = result;
} catch (error) {
console.warn(error);
}
loading.value = false;
}
const loading = ref(false);
const pagination = ref({
sortBy: 'name',
rowsPerPage: 10,
rowsNumber: 10,
descending: false,
page: 1,
});
const fullscreen = ref(false);
return {
drinks: computed(() => store.pricelist),
columns,
order,
visibleColumns,
options: _options,
search,
filter,
pagination,
fullscreen,
loading,
onRequest,
};
},
});
</script>
<style scoped lang="sass">
.ghost
opacity: 0.5
background: $accent
</style>