Compare commits

...

8 Commits

19 changed files with 179 additions and 143 deletions

View File

@ -44,7 +44,7 @@ module.exports = {
// https://github.com/prettier/eslint-config-prettier#installation // https://github.com/prettier/eslint-config-prettier#installation
// usage with Prettier, provided by 'eslint-config-prettier'. // usage with Prettier, provided by 'eslint-config-prettier'.
'prettier', //'plugin:prettier/recommended' 'plugin:prettier/recommended',
], ],
plugins: [ plugins: [
@ -54,10 +54,6 @@ module.exports = {
// https://eslint.vuejs.org/user-guide/#why-doesn-t-it-work-on-vue-file // https://eslint.vuejs.org/user-guide/#why-doesn-t-it-work-on-vue-file
// required to lint *.vue files // required to lint *.vue files
'vue', 'vue',
// https://github.com/typescript-eslint/typescript-eslint/issues/389#issuecomment-509292674
// Prettier has not been included as plugin to avoid performance impact
// add it as an extension for your IDE
], ],
// add your custom rules here // add your custom rules here
@ -65,9 +61,10 @@ module.exports = {
'prefer-promise-reject-errors': 'off', 'prefer-promise-reject-errors': 'off',
// TypeScript // TypeScript
quotes: ['warn', 'single', { avoidEscape: true }], quotes: ['error', 'single', { avoidEscape: true }],
'@typescript-eslint/explicit-function-return-type': 'off', '@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off', '@typescript-eslint/explicit-module-boundary-types': 'off',
'vue/multi-word-component-names': 'off',
// allow debugger during development only // allow debugger during development only
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',

1
.gitignore vendored
View File

@ -2,4 +2,5 @@ node_modules
yarn-error.log yarn-error.log
# No need for sharing this # No need for sharing this
yarn.lock yarn.lock
.idea

1
.npmignore Normal file
View File

@ -0,0 +1 @@
.woodpecker/

14
.woodpecker/.deploy.yml Normal file
View File

@ -0,0 +1,14 @@
pipeline:
deploy:
when:
event: tag
tag: v*
image: node:lts-alpine
commands:
- echo "//registry.npmjs.org/:_authToken=$NODE_AUTH_TOKEN" > .npmrc
- yarn publish --non-interactive
secrets: [ node_auth_token ]
depends_on:
- lint

9
.woodpecker/.lint.yml Normal file
View File

@ -0,0 +1,9 @@
pipeline:
lint:
when:
branch: [main, develop]
image: node:lts-alpine
commands:
- yarn install
- yarn lint

View File

@ -1,4 +1,5 @@
# Flaschengeist `pricelist` fontend-plugin # Flaschengeist `pricelist` fontend-plugin
![status-badge](https://ci.os-sc.org/api/badges/Flaschengeist/flaschengeist-pricelist/status.svg)
This package provides the [Flaschengeist](https://flaschengeist.dev/Flaschengeist/flaschengeist) frontend for the pricelist plugin (build and manage drinks, show pricelist and calculate prices). This package provides the [Flaschengeist](https://flaschengeist.dev/Flaschengeist/flaschengeist) frontend for the pricelist plugin (build and manage drinks, show pricelist and calculate prices).

View File

@ -1,6 +1,6 @@
{ {
"license": "MIT", "license": "MIT",
"version": "1.0.0-alpha.3", "version": "1.0.0-alpha.5",
"name": "@flaschengeist/pricelist", "name": "@flaschengeist/pricelist",
"author": "Tim Gröger <flaschengeist@wu5.de>", "author": "Tim Gröger <flaschengeist@wu5.de>",
"homepage": "https://flaschengeist.dev/Flaschengeist", "homepage": "https://flaschengeist.dev/Flaschengeist",
@ -19,24 +19,25 @@
"lint": "eslint --ext .js,.ts,.vue ./src" "lint": "eslint --ext .js,.ts,.vue ./src"
}, },
"dependencies": { "dependencies": {
"vuedraggable": "^4.0.1" "vuedraggable": "^4.1.0"
}, },
"devDependencies": { "devDependencies": {
"@flaschengeist/types": "^1.0.0-alpha.5", "@flaschengeist/types": "^1.0.0-alpha.10",
"@quasar/app": "^3.2.0", "@quasar/app": "^3.2.4",
"@typescript-eslint/eslint-plugin": "^5.3.1", "@typescript-eslint/eslint-plugin": "^5.5.0",
"@typescript-eslint/parser": "^5.3.1", "@typescript-eslint/parser": "^5.5.0",
"eslint": "^8.2.0", "eslint": "^8.2.0",
"eslint-config-prettier": "^8.3.0", "eslint-config-prettier": "^8.3.0",
"eslint-plugin-vue": "^8.0.3", "eslint-plugin-prettier": "^4.0.0",
"pinia": "^2.0.3", "eslint-plugin-vue": "^8.1.1",
"prettier": "^2.4.1", "pinia": "^2.0.6",
"quasar": "^2.3.0", "prettier": "^2.5.1",
"typescript": "^4.4.4" "quasar": "^2.3.3",
"typescript": "^4.5.2"
}, },
"peerDependencies": { "peerDependencies": {
"@flaschengeist/api": "^1.0.0-alpha.2", "@flaschengeist/api": "^1.0.0-alpha.7",
"@flaschengeist/users": "^1.0.0-alpha.1" "@flaschengeist/users": "^1.0.0-alpha.3"
}, },
"prettier": { "prettier": {
"singleQuote": true, "singleQuote": true,

4
src/api.d.ts vendored
View File

@ -23,13 +23,13 @@ declare namespace FG {
interface DrinkPrice { interface DrinkPrice {
id: number; id: number;
price: number; price: number;
volume: Array<DrinkPriceVolume>; volume?: DrinkPriceVolume;
public: boolean; public: boolean;
description?: string; description?: string;
} }
interface DrinkPriceVolume { interface DrinkPriceVolume {
id: number; id: number;
drink: Array<Drink>; drink?: Drink;
volume: number; volume: number;
min_prices: Array<MinPrices>; min_prices: Array<MinPrices>;
prices: Array<DrinkPrice>; prices: Array<DrinkPrice>;

View File

@ -38,7 +38,12 @@
<template #item="props"> <template #item="props">
<div class="q-pa-xs col-xs-12 col-sm-6 col-md-4"> <div class="q-pa-xs col-xs-12 col-sm-6 col-md-4">
<q-card> <q-card>
<q-img v-if="showPic" style="max-height: 256px" :src="image(props.row.id)"> <q-img
v-if="showPic && props.row.has_image"
style="max-height: 256px"
:src="image(props.row.id)"
fit="contain"
>
<div <div
v-if="!public && !nodetails && editable" v-if="!public && !nodetails && editable"
class="absolute-top-right justify-end" class="absolute-top-right justify-end"
@ -83,6 +88,33 @@
</div> </div>
</template> </template>
</q-img> </q-img>
<q-img
v-if="showPic && !props.row.has_image"
class="bg-white"
style="max-height: 256px"
src="no-image.svg"
>
<div
v-if="!public && !nodetails && editable"
class="absolute-top-right justify-end"
style="background-color: transparent"
>
<q-btn
round
icon="mdi-pencil"
style="background-color: rgba(0, 0, 0, 0.5)"
@click="editDrink = props.row"
/>
</div>
<div class="absolute-bottom-right justify-end">
<div class="text-subtitle1 text-right">
{{ props.row.name }}
</div>
<div class="text-caption text-right">
{{ props.row.type.name }}
</div>
</div>
</q-img>
<q-card-section v-if="!showPic"> <q-card-section v-if="!showPic">
<div class="row"> <div class="row">
<div class="col"> <div class="col">
@ -191,8 +223,8 @@ import { filter, Search } from '../utils/filter';
import SearchInput from './SearchInput.vue'; import SearchInput from './SearchInput.vue';
import DrinkModify from './DrinkModify.vue'; import DrinkModify from './DrinkModify.vue';
import { DeleteObjects } from '../utils/utils'; import { DeleteObjects } from '../utils/utils';
import { setNewImage, getNewImage } from '../utils/image';
import { PERMISSIONS } from '../permissions'; import { PERMISSIONS } from '../permissions';
import { sort } from '../utils/sort';
import { Notify } from 'quasar'; import { Notify } from 'quasar';
export default defineComponent({ export default defineComponent({
@ -222,7 +254,7 @@ export default defineComponent({
onBeforeMount(() => { onBeforeMount(() => {
//void store.getDrinks(); //void store.getDrinks();
onRequest({ void onRequest({
pagination: pagination.value, pagination: pagination.value,
filter: undefined, filter: undefined,
}); });
@ -237,8 +269,6 @@ export default defineComponent({
name: 'name', name: 'name',
label: 'Name', label: 'Name',
field: 'name', field: 'name',
sortable: true,
sort,
filterable: true, filterable: true,
public: true, public: true,
}, },
@ -248,8 +278,6 @@ export default defineComponent({
label: 'Kategorie', label: 'Kategorie',
field: 'type', field: 'type',
format: (val: FG.DrinkType) => `${val.name}`, format: (val: FG.DrinkType) => `${val.name}`,
sortable: true,
sort: (a: FG.DrinkType, b: FG.DrinkType) => sort(a.name, b.name),
filterable: true, filterable: true,
public: true, public: true,
}, },
@ -275,7 +303,6 @@ export default defineComponent({
label: 'Artikelnummer', label: 'Artikelnummer',
field: 'article_id', field: 'article_id',
sortable: true, sortable: true,
sort,
filterable: true, filterable: true,
public: false, public: false,
}, },
@ -284,7 +311,6 @@ export default defineComponent({
label: 'Inhalt in l des Gebinde', label: 'Inhalt in l des Gebinde',
field: 'volume', field: 'volume',
sortable: true, sortable: true,
sort,
public: false, public: false,
}, },
{ {
@ -292,7 +318,6 @@ export default defineComponent({
label: 'Gebindegröße', label: 'Gebindegröße',
field: 'package_size', field: 'package_size',
sortable: true, sortable: true,
sort,
public: false, public: false,
}, },
{ {
@ -301,7 +326,6 @@ export default defineComponent({
field: 'cost_per_package', field: 'cost_per_package',
format: (val: number | null) => (val ? `${val.toFixed(3)}` : ''), format: (val: number | null) => (val ? `${val.toFixed(3)}` : ''),
sortable: true, sortable: true,
sort,
public: false, public: false,
}, },
{ {
@ -310,7 +334,6 @@ export default defineComponent({
field: 'cost_per_volume', field: 'cost_per_volume',
format: (val: number | null) => (val ? `${val.toFixed(3)}` : ''), format: (val: number | null) => (val ? `${val.toFixed(3)}` : ''),
sortable: true, sortable: true,
sort: (a: ComputedRef, b: ComputedRef) => sort(a.value, b.value),
}, },
{ {
name: 'volumes', name: 'volumes',
@ -439,12 +462,12 @@ export default defineComponent({
void store.updateDrink(drink); void store.updateDrink(drink);
} }
async function deleteDrink() { function deleteDrink() {
if (editDrink.value) { if (editDrink.value) {
await store.deleteDrink(editDrink.value); store.deleteDrink(editDrink.value);
} }
editDrink.value = undefined; editDrink.value = undefined;
onRequest({ pagination: pagination.value, filter: search.value }); void onRequest({ pagination: pagination.value, filter: search.value });
} }
const showNewDrink = ref(false); const showNewDrink = ref(false);
@ -532,12 +555,15 @@ export default defineComponent({
editDrink.value.id = _drink.id; editDrink.value.id = _drink.id;
} }
} }
if (drinkPic instanceof File) { if (drinkPic instanceof File && drinkPic.name) {
await savePicture(drinkPic); await savePicture(drinkPic);
if (drink.id > 0) {
setNewImage(drink.id);
}
} }
editDrink.value = undefined; editDrink.value = undefined;
notLoading.value = true; notLoading.value = true;
onRequest({ pagination: pagination.value, filter: search.value }); void onRequest({ pagination: pagination.value, filter: search.value });
} }
function get_volumes(drink_id: number) { function get_volumes(drink_id: number) {
@ -546,17 +572,14 @@ export default defineComponent({
const notLoading = ref(true); const notLoading = ref(true);
const imageloading = ref<Array<{ id: number; loading: boolean }>>([]);
function getImageLoading(id: number) {
const loading = imageloading.value.find((a) => a.id === id);
if (loading) {
return loading.loading;
}
return false;
}
function image(id: number | undefined) { function image(id: number | undefined) {
if (id) { if (id) {
const _newImage = getNewImage(id);
if (_newImage) {
return `${
api.defaults.baseURL || ''
}/pricelist/drinks/${id}/picture?thumbnail?t=${_newImage.lastModified.toString()}`;
}
return `${api.defaults.baseURL || ''}/pricelist/drinks/${id}/picture?thumbnail`; return `${api.defaults.baseURL || ''}/pricelist/drinks/${id}/picture?thumbnail`;
} }
return 'no-image.svg'; return 'no-image.svg';
@ -585,7 +608,6 @@ export default defineComponent({
editing_drink, editing_drink,
get_volumes, get_volumes,
notLoading, notLoading,
getImageLoading,
newDrink, newDrink,
hasPermission, hasPermission,
PERMISSIONS, PERMISSIONS,

View File

@ -203,7 +203,7 @@ export default defineComponent({
id: -1, id: -1,
ingredient_id: newIngredient.value.id, ingredient_id: newIngredient.value.id,
volume: newIngredientVolume.value, volume: newIngredientVolume.value,
cost_per_volume: newIngredient.value.cost_per_volume, cost_per_volume: <number>(<FG.Drink>newIngredient.value).cost_per_volume,
name: newIngredient.value.name, name: newIngredient.value.name,
}, },
extra_ingredient: undefined, extra_ingredient: undefined,
@ -243,17 +243,11 @@ export default defineComponent({
emit('update:modelValue', unref(edit_ingredients)); emit('update:modelValue', unref(edit_ingredients));
update(); update();
} }
//const drinks = computed(() =>
// store.drinks.filter((drink) => {
// console.log('computed drinks', drink.name, drink.cost_per_volume);
// return drink.cost_per_volume;
// })
//);
const drinks = ref<Array<Drink>>([]); const drinks = ref<Array<Drink>>([]);
const _extra_ingredients = computed(() => store.extraIngredients); const _extra_ingredients = computed(() => store.extraIngredients);
const extra_ingredients = ref(_extra_ingredients.value); const extra_ingredients = ref(_extra_ingredients.value);
async function filter_drinks(val, update) { async function filter_drinks(val: string, update: (a: () => void) => void) {
let result = <Array<Drink>>[]; let result = <Array<Drink>>[];
if (val === '') { if (val === '') {
result = await store.getDrinks_no_store({ limit: 5, ingredient: true }); result = await store.getDrinks_no_store({ limit: 5, ingredient: true });
@ -269,7 +263,7 @@ export default defineComponent({
drinks.value = result; drinks.value = result;
}); });
} }
function filter_extra_ingredients(val, update) { function filter_extra_ingredients(val: string, update: (a: () => void) => void) {
if (val === '') { if (val === '') {
update(() => { update(() => {
extra_ingredients.value = _extra_ingredients.value; extra_ingredients.value = _extra_ingredients.value;
@ -283,7 +277,7 @@ export default defineComponent({
} }
} }
async function filter(val, update) { async function filter(val: string, update: () => void) {
await filter_drinks(val, update); await filter_drinks(val, update);
filter_extra_ingredients(val, update); filter_extra_ingredients(val, update);
} }

View File

@ -24,26 +24,28 @@
</div> </div>
</q-card-section> </q-card-section>
<q-card-section> <q-card-section>
<q-img :src="image" style="max-height: 256px" fit="contain" />
<div class="full-width row"> <div class="full-width row">
<div class="col-10 q-pa-sm"> <div class="col-10 q-pa-sm">
<q-file <q-file
v-model="drinkPic" v-model="drinkPic"
filled filled
clearable :clearable="drinkPic.name != ''"
dense dense
accept=".jpg, .jpeg, .png, image/*"
@update:model-value="imagePreview" @update:model-value="imagePreview"
@clear="imgsrc = undefined" @clear="clear"
> >
<template #prepend> <template #file>
<q-icon name="mdi-image" /> <q-img :src="image" style="max-height: 256px" fit="contain" />
</template> </template>
</q-file> </q-file>
</div> </div>
<div class="col-2 q-pa-sm text-right"> <div class="column justify-center">
<q-btn round icon="mdi-delete" color="negative" size="sm" @click="delete_pic"> <div class="col-2 q-pa-sm">
<q-tooltip> Bild entfernen </q-tooltip> <q-btn round icon="mdi-delete" color="negative" size="sm" @click="delete_pic">
</q-btn> <q-tooltip> Bild entfernen </q-tooltip>
</q-btn>
</div>
</div> </div>
</div> </div>
</q-card-section> </q-card-section>
@ -138,13 +140,15 @@
</q-card-section> </q-card-section>
<q-card-actions class="justify-around"> <q-card-actions class="justify-around">
<q-btn label="Abbrechen" @click="cancel" /> <q-btn label="Abbrechen" @click="cancel" />
<q-btn v-if="can_delete" label="Löschen" color="negative" @click="delete_drink" /> <!--<q-btn v-if="can_delete" label="Löschen" color="negative" @click="delete_drink" />-->
<q-btn label="Löschen" color="negative" @click="delete_drink" />
<q-btn label="Speichern" color="primary" @click="save" /> <q-btn label="Speichern" color="primary" @click="save" />
</q-card-actions> </q-card-actions>
</q-card> </q-card>
</template> </template>
<script lang="ts"> <script lang="ts">
import { clone, calc_min_prices, DeleteObjects, calc_cost_per_volume } from '../utils/utils'; import { clone, calc_min_prices, DeleteObjects, calc_cost_per_volume } from '../utils/utils';
import { getNewImage } from '../utils/image';
import { defineComponent, PropType, ref, onBeforeMount, computed } from 'vue'; import { defineComponent, PropType, ref, onBeforeMount, computed } from 'vue';
import DrinkPriceVolumes from './CalculationTable/DrinkPriceVolumes.vue'; import DrinkPriceVolumes from './CalculationTable/DrinkPriceVolumes.vue';
import BuildManual from '../components/CalculationTable/BuildManual.vue'; import BuildManual from '../components/CalculationTable/BuildManual.vue';
@ -239,7 +243,7 @@ export default defineComponent({
edit_drink.value?.receipt?.splice(event, 1); edit_drink.value?.receipt?.splice(event, 1);
} }
const drinkPic = ref(); const drinkPic = ref<File>(new File([], '', {}));
const imgsrc = ref(); const imgsrc = ref();
const deletePic = ref(false); const deletePic = ref(false);
@ -247,7 +251,7 @@ export default defineComponent({
function delete_pic() { function delete_pic() {
deletePic.value = true; deletePic.value = true;
imgsrc.value = undefined; imgsrc.value = undefined;
drinkPic.value = undefined; drinkPic.value = new File([], '', {});
if (edit_drink.value) { if (edit_drink.value) {
edit_drink.value.has_image = false; edit_drink.value.has_image = false;
} }
@ -266,15 +270,23 @@ export default defineComponent({
} }
const image = computed(() => { const image = computed(() => {
console.log(imgsrc.value, deletePic.value, edit_drink.value) console.log(imgsrc.value, deletePic.value, edit_drink.value);
if (deletePic.value) {
return 'no-image.svg';
}
if (imgsrc.value) { if (imgsrc.value) {
return <string>imgsrc.value; return <string>imgsrc.value;
} }
if (deletePic.value && !imgsrc.value) {
return 'no-image.svg';
}
if (edit_drink.value?.has_image) { if (edit_drink.value?.has_image) {
return `${api.defaults.baseURL || ''}/pricelist/drinks/${edit_drink.value.id}/picture?thumbnail`; const _image = getNewImage(edit_drink.value?.id);
if (_image) {
return `${api.defaults.baseURL || ''}/pricelist/drinks/${
edit_drink.value.id
}/picture?thumbnail?t=${_image.lastModified.toString()}`;
}
return `${api.defaults.baseURL || ''}/pricelist/drinks/${
edit_drink.value.id
}/picture?thumbnail`;
} }
return 'no-image.svg'; return 'no-image.svg';
}); });
@ -323,6 +335,11 @@ export default defineComponent({
edit_volumes.value?.some((a) => a.ingredients.length > 0) edit_volumes.value?.some((a) => a.ingredients.length > 0)
); );
function clear(val: File) {
drinkPic.value = new File([], '', {});
imgsrc.value = undefined;
}
return { return {
edit_drink, edit_drink,
save, save,
@ -349,6 +366,7 @@ export default defineComponent({
hasIngredients, hasIngredients,
hasPermission, hasPermission,
PERMISSIONS, PERMISSIONS,
clear,
}; };
}, },
}); });

View File

@ -82,7 +82,7 @@ import SearchInput from '../components/SearchInput.vue';
import { usePricelistStore, Order } from '../store'; import { usePricelistStore, Order } from '../store';
import { useMainStore } from '@flaschengeist/api'; import { useMainStore } from '@flaschengeist/api';
import { Search, filter } from '../utils/filter'; import { Search, filter } from '../utils/filter';
import drag from 'vuedraggable'; import draggableComponent from 'vuedraggable';
interface Row { interface Row {
name: string; name: string;
@ -96,7 +96,7 @@ interface Row {
export default defineComponent({ export default defineComponent({
name: 'Pricelist', name: 'Pricelist',
components: { SearchInput, drag: <ComponentPublicInstance>drag }, components: { SearchInput, drag: draggableComponent },
props: { props: {
public: { public: {
type: Boolean, type: Boolean,
@ -115,7 +115,7 @@ export default defineComponent({
} else { } else {
user.value = ''; user.value = '';
} }
onRequest({ pagination: pagination.value, filter: { limit: 10 } }); void onRequest({ pagination: pagination.value });
}); });
const _order = ref<Array<Order>>([ const _order = ref<Array<Order>>([
@ -174,7 +174,7 @@ export default defineComponent({
label: 'Name', label: 'Name',
//field: 'name', //field: 'name',
field: 'volume', field: 'volume',
format: (val: FG.DrinkPriceVolume) => val.drink.name, format: (val: FG.DrinkPriceVolume) => <string>val.drink?.name,
sortable: true, sortable: true,
filterable: true, filterable: true,
align: 'left', align: 'left',
@ -186,7 +186,7 @@ export default defineComponent({
field: 'volume', field: 'volume',
sortable: true, sortable: true,
filterable: true, filterable: true,
format: (val: FG.DrinkPriceVolume) => val.drink.type.name, format: (val: FG.DrinkPriceVolume) => <string>val.drink?.type?.name,
}, },
{ {
name: 'tags', name: 'tags',
@ -197,8 +197,8 @@ export default defineComponent({
format: (val: FG.DrinkPriceVolume) => { format: (val: FG.DrinkPriceVolume) => {
let retVal = ''; let retVal = '';
val.drink.tags.forEach((tag, index) => { val.drink?.tags?.forEach((tag, index) => {
if (index >= val.length - 1 && index > 0) { if (index >= (<Array<FG.Tag>>val.drink?.tags).length - 1 && index > 0) {
retVal += ', '; retVal += ', ';
} }
retVal += tag.name; retVal += tag.name;

View File

@ -1,13 +1,12 @@
import { innerRoutes, outerRoutes } from './routes'; import { innerRoutes, outerRoutes } from './routes';
import { FG_Plugin } from '@flaschengeist/typings'; import { FG_Plugin } from '@flaschengeist/types';
const plugin: FG_Plugin.Plugin = { const plugin: FG_Plugin.Plugin = {
id: 'pricelist', id: 'pricelist',
name: 'Pricelist', name: 'Pricelist',
innerRoutes, innerRoutes,
outerRoutes, outerRoutes,
requiredModules: [], requiredModules: [['pricelist']],
requiredBackendModules: ['pricelist'],
version: '0.0.1', version: '0.0.1',
widgets: [], widgets: [],
}; };

View File

@ -39,7 +39,7 @@ export default defineComponent({
void store.get_min_prices().finally(() => { void store.get_min_prices().finally(() => {
volume.value.min_prices = calc_min_prices(volume.value, undefined, store.min_prices); volume.value.min_prices = calc_min_prices(volume.value, undefined, store.min_prices);
}); });
void store.getDrinks(); void store.getDrinks({ limit: 10 });
void store.getDrinkTypes(); void store.getDrinkTypes();
void store.getExtraIngredients(); void store.getExtraIngredients();
}); });

View File

@ -25,7 +25,7 @@ export default defineComponent({
const mainStore = useMainStore(); const mainStore = useMainStore();
onBeforeMount(() => { onBeforeMount(() => {
void store.getDrinks(); void store.getDrinks({ limit: 10 });
void store.getPriceListView(mainStore.currentUser.userid); void store.getPriceListView(mainStore.currentUser.userid);
}); });

View File

@ -71,10 +71,8 @@ export default defineComponent({
setup() { setup() {
const store = usePricelistStore(); const store = usePricelistStore();
onBeforeMount(() => { onBeforeMount(() => {
//void store.getDrinks(); void onRequest({
onRequest({
pagination: pagination.value, pagination: pagination.value,
filter: { limit: 10, receipt: true },
}); });
}); });
const drinks = computed( const drinks = computed(
@ -192,8 +190,8 @@ export default defineComponent({
offset: startRow, offset: startRow,
limit: fetchCount, limit: fetchCount,
descending, descending,
search_name: props.filter.value, search_name: props.filter?.value,
search_key: props.filter.key, search_key: props.filter?.key,
receipt: true, receipt: true,
}); });
pagination.value.page = page; pagination.value.page = page;

View File

@ -77,7 +77,7 @@ export default defineComponent({
.catch((err) => console.log(err)); .catch((err) => console.log(err));
void store.getTags(); void store.getTags();
void store.getDrinkTypes(); void store.getDrinkTypes();
void store.getDrinks(); void store.getDrinks({ limit: 10 });
void store.get_min_prices(); void store.get_min_prices();
}); });

View File

@ -14,16 +14,6 @@ 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;
@ -149,9 +139,12 @@ export const usePricelistStore = defineStore({
}) { }) {
if (!filter) filter = { limit: 10 }; if (!filter) filter = { limit: 10 };
console.log('filter_api', filter); console.log('filter_api', filter);
const { data } = await api.get<Array<FG.Drink>>('pricelist/drinks', { const { data } = await api.get<{ drinks: Array<FG.Drink>; count: number }>(
params: filter, 'pricelist/drinks',
}); {
params: filter,
}
);
this.drinks = []; this.drinks = [];
data.drinks.forEach((drink) => { data.drinks.forEach((drink) => {
const _drink = new Drink(drink); const _drink = new Drink(drink);
@ -187,7 +180,7 @@ export const usePricelistStore = defineStore({
params: filter, params: filter,
} }
); );
const drinks = []; const drinks: Array<Drink> = [];
data.drinks.forEach((drink) => { data.drinks.forEach((drink) => {
const _drink = new Drink(drink); const _drink = new Drink(drink);
drink.volumes.forEach((volume) => { drink.volumes.forEach((volume) => {
@ -266,7 +259,9 @@ export const usePricelistStore = defineStore({
_ingredient.drink_ingredient && _ingredient.drink_ingredient &&
_ingredient.drink_ingredient.ingredient_id === drink.id _ingredient.drink_ingredient.ingredient_id === drink.id
) { ) {
_ingredient.drink_ingredient.cost_per_volume = drink.cost_per_volume; if (drink.cost_per_volume != null) {
_ingredient.drink_ingredient.cost_per_volume = drink.cost_per_volume;
}
_ingredient.drink_ingredient.name = drink.name; _ingredient.drink_ingredient.name = drink.name;
} }
}); });
@ -360,41 +355,7 @@ export const usePricelistStore = defineStore({
this.pricelist_columns_order = data; this.pricelist_columns_order = data;
}, },
}, },
getters: { 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;
},*/
computed_pricelist() {
const retVal: Array<Pricelist> = [];
this.pricelist.forEach((price) => {
retVal.push({
name: price.volume.drink.name,
type: <FG.DrinkType>price.volume.drink.type,
tags: <Array<FG.Tag>>price.volume.drink.tags,
volume: <number>price.volume.volume,
public: price.public,
price: price.price,
description: <string>price.description,
});
});
},
},
}); });
export { DrinkPriceVolume, Drink, Order }; export { DrinkPriceVolume, Drink, Order };

20
src/utils/image.ts Normal file
View File

@ -0,0 +1,20 @@
import { ref } from 'vue';
const newImage = ref<Array<{ id: number; lastModified: Date }>>([]);
export function getNewImage(id: number) {
const image = newImage.value.find((a) => a.id === id);
if (image) {
return image;
}
return null;
}
export function setNewImage(id: number) {
const image = newImage.value.find((a) => a.id === id);
if (image) {
image.lastModified = new Date();
} else {
newImage.value.push({ id, lastModified: new Date() });
}
}