Init
This commit is contained in:
commit
f90fdc0598
99 changed files with 15260 additions and 0 deletions
25
frontend/src/components/Tables/OrderAmountChange.vue
Normal file
25
frontend/src/components/Tables/OrderAmountChange.vue
Normal file
|
@ -0,0 +1,25 @@
|
|||
<template>
|
||||
<div class="flex align-items-center">
|
||||
<div @click="!isDisabled && $emit('decrementOrder')" :style="{ color: isDisabled ? 'grey' : 'red' }" style="cursor: pointer">
|
||||
<i class="pi pi-minus"></i>
|
||||
</div>
|
||||
<div class="mx-2 font-bold">{{ order.order_count }}</div>
|
||||
<div @click="!isDisabled && $emit('incrementOrder')" :style="{ color: isDisabled ? 'grey' : 'green' }" style="cursor: pointer">
|
||||
<i class="pi pi-plus"></i>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType } from "vue";
|
||||
import { service_Order } from "@/services/openapi";
|
||||
|
||||
export default defineComponent({
|
||||
name: "OrderAmountChange",
|
||||
props: {
|
||||
order: { type: Object as PropType<service_Order>, required: true },
|
||||
isDisabled: { type: Boolean, default: false },
|
||||
},
|
||||
emits: ["incrementOrder", "decrementOrder"],
|
||||
});
|
||||
</script>
|
48
frontend/src/components/Tables/OverviewPerType.vue
Normal file
48
frontend/src/components/Tables/OverviewPerType.vue
Normal file
|
@ -0,0 +1,48 @@
|
|||
<template>
|
||||
<div>
|
||||
<BaseToolbar :title="generalItemTypeString(type)" :icon="generalItemTypeIcon(type)" @click="$emit('openModal', type)" btnIcon="plus" />
|
||||
<div class="grid">
|
||||
<TableOrderCard v-for="order in OrdersForType" v-bind:key="order.id" :order="order">
|
||||
<div class="flex align-items-end">
|
||||
<OrderAmountChange :order="order" :isDisabled="isLoading" @incrementOrder="incrementOrder(order)" @decrementOrder="decrementOrder(order)" />
|
||||
</div>
|
||||
</TableOrderCard>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, inject, PropType, ref } from "vue";
|
||||
import { OrdersService, service_Order } from "@/services/openapi";
|
||||
import { convertToEur, generalItemTypeString, generalItemTypeIcon } from "@/utils";
|
||||
import BaseToolbar from "@/components/UI/BaseToolbar.vue";
|
||||
import TableOrderCard from "@/components/Tables/TableOrderCard.vue";
|
||||
import OrderAmountChange from "@/components/Tables/OrderAmountChange.vue";
|
||||
import { loading } from "@/keys";
|
||||
|
||||
export default defineComponent({
|
||||
name: "OverviewPerType",
|
||||
components: { TableOrderCard, BaseToolbar, OrderAmountChange },
|
||||
props: {
|
||||
orders: { type: Array as PropType<service_Order[]>, default: () => [] },
|
||||
type: { type: Array as PropType<number[]>, required: true },
|
||||
},
|
||||
emits: ["openModal", "getData"],
|
||||
setup(props, { emit }) {
|
||||
const OrdersForType = computed(() => props.orders.filter((order) => props.type.includes(order.order_item.item_type)));
|
||||
const isLoading = inject(loading, ref(false));
|
||||
|
||||
function incrementOrder(order: service_Order) {
|
||||
isLoading.value = true;
|
||||
OrdersService.postOrders(order.order_item_id, order.table_id).finally(() => emit("getData"));
|
||||
}
|
||||
|
||||
function decrementOrder(order: service_Order) {
|
||||
isLoading.value = true;
|
||||
OrdersService.deleteOrders(order.order_item_id, order.table_id).finally(() => emit("getData"));
|
||||
}
|
||||
|
||||
return { OrdersForType, isLoading, convertToEur, incrementOrder, decrementOrder, generalItemTypeIcon, generalItemTypeString };
|
||||
},
|
||||
});
|
||||
</script>
|
48
frontend/src/components/Tables/TableCard.vue
Normal file
48
frontend/src/components/Tables/TableCard.vue
Normal file
|
@ -0,0 +1,48 @@
|
|||
<template>
|
||||
<SmallCard bgColor="a" :to="'/tables/' + table.id">
|
||||
<template #description>Tisch {{ table.id }}</template>
|
||||
<template #badge>{{ since }}</template>
|
||||
<template #right>
|
||||
<div class="flex align-items-end">
|
||||
<TheBadge v-if="table.order_count" class="topRight">{{ table.order_count }}</TheBadge>
|
||||
<div v-if="table.total" class="font-bold">{{ convertToEur(table.total) }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</SmallCard>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, onMounted, onUnmounted, PropType, ref } from "vue";
|
||||
import { service_Table } from "@/services/openapi";
|
||||
import moment from "moment";
|
||||
import { convertToEur, getCurrentTimeSince } from "@/utils";
|
||||
import TheBadge from "@/components/UI/TheBadge.vue";
|
||||
import SmallCard from "@/components/UI/SmallCard.vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "TableCard",
|
||||
components: { TheBadge, SmallCard },
|
||||
props: { table: { type: Object as PropType<service_Table>, required: true } },
|
||||
setup(props) {
|
||||
moment.locale("de");
|
||||
// eslint-disable-next-line
|
||||
let ticker: any;
|
||||
const since = ref(getCurrentTimeSince(props.table.updated_at));
|
||||
onMounted(() => {
|
||||
ticker = setInterval(() => {
|
||||
since.value = getCurrentTimeSince(props.table.updated_at);
|
||||
}, 1000);
|
||||
});
|
||||
onUnmounted(() => ticker && clearInterval(ticker));
|
||||
return { since, convertToEur };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.topRight {
|
||||
position: absolute;
|
||||
top: -0.2rem;
|
||||
right: 0.3rem;
|
||||
}
|
||||
</style>
|
30
frontend/src/components/Tables/TableOrderCard.vue
Normal file
30
frontend/src/components/Tables/TableOrderCard.vue
Normal file
|
@ -0,0 +1,30 @@
|
|||
<template>
|
||||
<SmallCard bgColor="d" :badgeTwo="order.total !== order.order_item.price">
|
||||
<template #description>{{ order.order_item.description }}</template>
|
||||
<template #badgeOne>{{ convertToEur(order.order_item.price) }}</template>
|
||||
<template #badgeTwo>{{ convertToEur(order.total) }}</template>
|
||||
<template #right>
|
||||
<slot></slot>
|
||||
</template>
|
||||
</SmallCard>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, PropType } from "vue";
|
||||
import { service_Order, types_ItemType } from "@/services/openapi";
|
||||
import { convertToEur } from "@/utils";
|
||||
import SmallCard from "@/components/UI/SmallCard.vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "TableOrderCard",
|
||||
components: { SmallCard },
|
||||
props: {
|
||||
order: { type: Object as PropType<service_Order>, required: true },
|
||||
},
|
||||
emits: ["decrementOrder", "incrementOrder"],
|
||||
setup(props) {
|
||||
const showTotal = computed(() => props.order.order_item.price !== props.order.total);
|
||||
return { convertToEur, types_ItemType, showTotal };
|
||||
},
|
||||
});
|
||||
</script>
|
172
frontend/src/components/Tables/TableOverview.vue
Normal file
172
frontend/src/components/Tables/TableOverview.vue
Normal file
|
@ -0,0 +1,172 @@
|
|||
<template>
|
||||
<BaseCard>
|
||||
<Transition>
|
||||
<WaveSpinner v-if="initialLoading" />
|
||||
<div v-else>
|
||||
<OverviewPerType :type="[types_ItemType.Food]" :orders="orders" @getData="getData" @openModal="(t) => addBeverage(t)" />
|
||||
<OverviewPerType :type="[types_ItemType.ColdDrink, types_ItemType.HotDrink]" :orders="orders" @getData="getData" @openModal="(t) => addBeverage(t)" />
|
||||
<div class="h-4rem"></div>
|
||||
|
||||
<BottomNavigation>
|
||||
<template #left>
|
||||
<router-link :to="{ name: 'Tables' }" class="no-underline">
|
||||
<Button :disabled="isLoading" icon="pi pi-arrow-left" class="p-button-rounded" />
|
||||
</router-link>
|
||||
</template>
|
||||
<template #middle>
|
||||
<div class="flex flex-column align-items-center">
|
||||
<div class="text-sm">Tisch {{ table }}</div>
|
||||
<div class="font-bold">{{ convertToEur(total) }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #right>
|
||||
<router-link
|
||||
:style="{ cursor: isLoading || orders.length === 0 ? 'default' : 'pointer' }"
|
||||
:to="{ name: isLoading || orders.length === 0 ? 'TableDetail' : 'Checkout' }"
|
||||
class="no-underline"
|
||||
>
|
||||
<Button :disabled="isLoading || orders.length === 0" icon="pi pi-money-bill" class="p-button-danger p-button-rounded" />
|
||||
</router-link>
|
||||
</template>
|
||||
</BottomNavigation>
|
||||
</div>
|
||||
</Transition>
|
||||
|
||||
<Sidebar v-model:visible="newOrderModal" :baseZIndex="10000" position="full">
|
||||
<div class="p-fluid">
|
||||
<Listbox
|
||||
v-model="selected"
|
||||
:options="options"
|
||||
:filter="true"
|
||||
optionLabel="description"
|
||||
dataKey="id"
|
||||
optionValue="id"
|
||||
listStyle="max-height:65vh"
|
||||
filterPlaceholder="Suchen"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex justify-content-end mt-4">
|
||||
<Button :loading="isLoading" label="Speichern" icon="pi pi-check" class="p-button p-button-success mr-3" @click="postOrder" />
|
||||
</div>
|
||||
</Sidebar>
|
||||
</BaseCard>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, provide, ref } from "vue";
|
||||
import BaseCard from "@/components/UI/BaseCard.vue";
|
||||
import { useStore } from "vuex";
|
||||
import { OrdersService, service_Order, service_OrderItem, types_ItemType } from "@/services/openapi";
|
||||
import BottomNavigation from "@/components/UI/BottomNavigation.vue";
|
||||
import Button from "primevue/button";
|
||||
import { convertToEur } from "@/utils";
|
||||
import WaveSpinner from "@/components/UI/WaveSpinner.vue";
|
||||
import Sidebar from "primevue/sidebar";
|
||||
import Listbox from "primevue/listbox";
|
||||
import OverviewPerType from "@/components/Tables/OverviewPerType.vue";
|
||||
import { loading } from "@/keys";
|
||||
|
||||
export default defineComponent({
|
||||
name: "TableOverview",
|
||||
// eslint-disable-next-line
|
||||
components: { OverviewPerType, WaveSpinner, BottomNavigation, BaseCard, Button, Sidebar, Listbox },
|
||||
props: { id: { type: String, default: "0" } },
|
||||
setup(props) {
|
||||
const initialLoading = ref(false);
|
||||
const isLoading = ref(false);
|
||||
provide(loading, isLoading);
|
||||
const newOrderModal = ref(false);
|
||||
const store = useStore();
|
||||
const selectedOrder = ref();
|
||||
const table = computed(() => parseInt(props.id));
|
||||
const total = ref(0);
|
||||
const orderItems = computed(() => store.getters.getOrderItems);
|
||||
const options = ref();
|
||||
const orders = ref<service_Order[]>([]);
|
||||
|
||||
store.dispatch("getAllOrderItems");
|
||||
|
||||
getData(true);
|
||||
function getData(initial = false) {
|
||||
initial && (initialLoading.value = true);
|
||||
OrdersService.getOrders(table.value, true)
|
||||
.then((res) => (orders.value = res))
|
||||
.finally(() => {
|
||||
updateTotal();
|
||||
resetValues();
|
||||
});
|
||||
}
|
||||
|
||||
function resetValues() {
|
||||
newOrderModal.value = false;
|
||||
selectedOrder.value = undefined;
|
||||
isLoading.value = false;
|
||||
initialLoading.value = false;
|
||||
}
|
||||
|
||||
function updateTotal() {
|
||||
let temp = 0;
|
||||
orders.value.forEach((order) => (temp += order.total));
|
||||
total.value = temp;
|
||||
}
|
||||
|
||||
function addBeverage(itemType: types_ItemType[]) {
|
||||
newOrderModal.value = true;
|
||||
options.value = [];
|
||||
itemType.forEach((type) => {
|
||||
options.value = options.value.concat(orderItems.value.get(type));
|
||||
});
|
||||
options.value.sort((a: service_OrderItem, b: service_OrderItem) => {
|
||||
const x = a.description.toLowerCase();
|
||||
const y = b.description.toLowerCase();
|
||||
if (x < y) return -1;
|
||||
if (x > y) return 1;
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
function postOrder() {
|
||||
isLoading.value = true;
|
||||
if (selectedOrder.value) {
|
||||
OrdersService.postOrders(selectedOrder.value, table.value).finally(() => getData());
|
||||
} else isLoading.value = false;
|
||||
}
|
||||
|
||||
return {
|
||||
initialLoading,
|
||||
isLoading,
|
||||
newOrderModal,
|
||||
selected: selectedOrder,
|
||||
options,
|
||||
table,
|
||||
total,
|
||||
convertToEur,
|
||||
addBeverage,
|
||||
types_ItemType,
|
||||
postOrder,
|
||||
orders,
|
||||
getData,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.v-enter-active {
|
||||
transition: opacity 0.2s ease-in;
|
||||
}
|
||||
.v-enter-from {
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style>
|
||||
.p-sidebar-content {
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.p-listbox {
|
||||
border: 0 !important;
|
||||
}
|
||||
</style>
|
Loading…
Add table
Add a link
Reference in a new issue