release v2.0.0 #4

Merged
crimsen merged 481 commits from develop into master 2024-01-18 15:15:08 +00:00
79 changed files with 609 additions and 613 deletions
Showing only changes of commit 73f16d6cbb - Show all commits

View File

@ -7,6 +7,6 @@
import { defineComponent } from '@vue/composition-api';
export default defineComponent({
name: 'App'
name: 'App',
});
</script>

View File

@ -19,7 +19,7 @@ export const setBaseUrl = (url: string) => {
message: 'Serveraddresse gespeichert',
position: 'bottom',
caption: `${url}`,
color: 'positive'
color: 'positive',
});
setTimeout(() => {
window.location.reload();
@ -38,7 +38,7 @@ export default boot<Store<StateInterface>>(({ Vue, store, router }) => {
/***
* Intercept requests and insert Token if available
*/
axios.interceptors.request.use(config => {
axios.interceptors.request.use((config) => {
const session = store.state.session.currentSession;
if (session?.token) {
config.headers = { Authorization: 'Bearer ' + session.token };
@ -52,8 +52,8 @@ export default boot<Store<StateInterface>>(({ Vue, store, router }) => {
* - filter timeout or 502-504 --> backendOffline
*/
axios.interceptors.response.use(
response => response,
error => {
(response) => response,
(error) => {
if (error) {
const e = <AxiosError>error;
if (
@ -62,7 +62,7 @@ export default boot<Store<StateInterface>>(({ Vue, store, router }) => {
) {
return router.push({
name: 'offline',
query: { redirect: router.currentRoute.fullPath }
query: { redirect: router.currentRoute.fullPath },
});
} else if (e.response && e.response.status == 401) {
if (router.currentRoute.name !== 'login') return store.dispatch('session/clearCurrent');

View File

@ -8,6 +8,6 @@ export default boot((/* { app, router, Vue ... } */) => {
Loading.setDefaults({
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
spinner: DarkCircularProgress
spinner: DarkCircularProgress,
});
});

View File

@ -15,7 +15,7 @@ export default boot<Store<StateInterface>>(({ router, store }) => {
// Secured area (LOGIN REQUIRED)
// Check login is ok
if (!session || session.expires <= new Date()) {
store.dispatch('session/logout').catch(error => {
store.dispatch('session/logout').catch((error) => {
console.warn(error);
});
return;

View File

@ -9,6 +9,6 @@ export default boot((/* { app, router, Vue ... } */) => {
icon: 'mdi-alert-circle',
progress: true,
position: 'bottom',
actions: [{ icon: 'mdi-close', color: 'white' }]
actions: [{ icon: 'mdi-close', color: 'white' }],
});
});

View File

@ -12,7 +12,7 @@ const config = {
// Do not change required Modules !!
requiredModules: ['User'],
// here you can import plugins.
loadModules: ['Balance', 'Schedule', 'Pricelist']
loadModules: ['Balance', 'Schedule', 'Pricelist'],
};
// do not change anything here !!
@ -40,7 +40,7 @@ function combineRoutes(
source: FG_Plugin.PluginRouteConfig[],
mainPath: '/' | '/main' = '/'
): RouteConfig[] {
target.forEach(target => {
target.forEach((target) => {
if (target.path === mainPath) {
source.forEach((sourceMainConfig: FG_Plugin.PluginRouteConfig) => {
const targetMainConfig = target.children?.find((targetMainConfig: RouteConfig) => {
@ -48,7 +48,7 @@ function combineRoutes(
});
if (targetMainConfig) {
const sourceChildren: RouteConfig[] = [];
sourceMainConfig.children?.forEach(child => {
sourceMainConfig.children?.forEach((child) => {
sourceChildren.push(<RouteConfig>child);
});
if (targetMainConfig.children) {
@ -92,7 +92,7 @@ function combineMainLinks(
icon: sourcePluginChildLink.icon,
link: sourcePluginChildLink.name,
name: sourcePluginChildLink.name,
permissions: sourcePluginChildLink.meta?.permissions
permissions: sourcePluginChildLink.meta?.permissions,
});
});
} else {
@ -101,9 +101,9 @@ function combineMainLinks(
icon: source.icon,
link: source.name,
name: source.name,
permissions: source.meta?.permissions
permissions: source.meta?.permissions,
};
source.children?.forEach(child => {
source.children?.forEach((child) => {
if (mainLink.children === undefined) {
mainLink.children = [];
}
@ -112,7 +112,7 @@ function combineMainLinks(
icon: child.icon,
link: child.name,
name: child.name,
permissions: child.meta?.permissions
permissions: child.meta?.permissions,
});
});
target.push(mainLink);
@ -124,12 +124,12 @@ function loadShortCuts(
target: FG_Plugin.ShortCutLink[],
source: FG_Plugin.PluginRouteConfig[]
): FG_Plugin.ShortCutLink[] {
source.forEach(route => {
source.forEach((route) => {
if (route.shortcut) {
target.push(<FG_Plugin.ShortCutLink>{
link: route.name,
icon: route.icon,
permissions: route.meta?.permissions
permissions: route.meta?.permissions,
});
}
if (route.children) {
@ -148,14 +148,14 @@ function loadPlugin(
store: Store<any>,
router: VueRouter
): FG_Plugin.LoadedPlugins {
modules.forEach(requiredModule => {
const plugin = plugins.find(plugin => {
modules.forEach((requiredModule) => {
const plugin = plugins.find((plugin) => {
return plugin.name == requiredModule;
});
if (plugin) {
if (plugin.mainRoutes) {
loadedPlugins.routes = combineRoutes(loadedPlugins.routes, plugin.mainRoutes, '/main');
plugin.mainRoutes.forEach(route => {
plugin.mainRoutes.forEach((route) => {
loadedPlugins.mainLinks = combineMainLinks(loadedPlugins.mainLinks, route);
});
loadedPlugins.shortcuts = loadShortCuts(loadedPlugins.shortcuts, plugin.mainRoutes);
@ -165,7 +165,7 @@ function loadPlugin(
loadedPlugins.shortcutsOut = loadShortCuts(loadedPlugins.shortcutsOut, plugin.outRoutes);
}
if (plugin.widgets.length > 0) {
plugin.widgets.forEach(widget => (widget.name = plugin.name + '_' + widget.name));
plugin.widgets.forEach((widget) => (widget.name = plugin.name + '_' + widget.name));
Array.prototype.push.apply(loadedPlugins.widgets, plugin.widgets);
}
if (plugin.store) {
@ -175,11 +175,11 @@ function loadPlugin(
}
loadedPlugins.plugins.push({
name: plugin.name,
version: plugin.version
version: plugin.version,
});
} else {
console.exception(`Could not find required Plugin ${requiredModule}`);
router.push({ name: 'error' }).catch(e => {
router.push({ name: 'error' }).catch((e) => {
console.warn(e);
});
}
@ -213,7 +213,7 @@ export default boot<Store<StateInterface>>(({ Vue, router, store }) => {
mainLinks: [],
shortcuts: [],
shortcutsOut: [],
widgets: []
widgets: [],
};
// get all plugins
@ -225,7 +225,7 @@ export default boot<Store<StateInterface>>(({ Vue, router, store }) => {
// check dependencies
backendPromise
.then(backend => {
.then((backend) => {
console.log(backend);
if (backend) {
plugins.forEach((plugin: FG_Plugin.Plugin) => {
@ -237,7 +237,7 @@ export default boot<Store<StateInterface>>(({ Vue, router, store }) => {
)
) {
console.error(`Plugin ${plugin.name} need Plugin ${requiredModule}`);
router.push({ name: 'error' }).catch(e => {
router.push({ name: 'error' }).catch((e) => {
console.warn(e);
});
}
@ -247,7 +247,7 @@ export default boot<Store<StateInterface>>(({ Vue, router, store }) => {
console.error(
`Plugin ${plugin.name} need Plugin ${requiredBackendModule} in backend.`
);
router.push({ name: 'error' }).catch(err => {
router.push({ name: 'error' }).catch((err) => {
console.warn(err);
});
}
@ -255,7 +255,7 @@ export default boot<Store<StateInterface>>(({ Vue, router, store }) => {
});
}
})
.catch(e => {
.catch((e) => {
console.error(e);
});

View File

@ -27,26 +27,26 @@ export default defineComponent({
name: 'Developer',
props: {
pic: {
default: 'logo-dark.svg'
default: 'logo-dark.svg',
},
firstname: {
//required: true,
default: 'firstname'
default: 'firstname',
},
lastname: {
//required: true,
default: 'lastname'
default: 'lastname',
},
job: {
default: 'student'
default: 'student',
},
club: {
default: 'Studentenclub Wu5 e.V.'
default: 'Studentenclub Wu5 e.V.',
},
description: {
default:
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. '
}
}
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. ',
},
},
});
</script>

View File

@ -18,6 +18,6 @@
<script lang="ts">
import { defineComponent } from '@vue/composition-api';
export default defineComponent({
name: 'CircularProgress'
name: 'CircularProgress',
});
</script>

View File

@ -18,6 +18,6 @@
<script lang="ts">
import { defineComponent } from '@vue/composition-api';
export default defineComponent({
name: 'DarkCircularProgress'
name: 'DarkCircularProgress',
});
</script>

View File

@ -9,6 +9,6 @@ export default defineComponent({
name: 'EmptyParent',
setup() {
return {};
}
},
});
</script>

View File

@ -22,26 +22,26 @@ export default defineComponent({
props: {
title: {
type: String,
required: true
required: true,
},
caption: {
type: String,
default: ''
default: '',
},
link: {
type: String,
default: 'home'
default: 'home',
},
icon: {
type: String,
default: ''
default: '',
},
permissions: {
default: undefined
}
default: undefined,
},
},
setup(props, { root }) {
@ -59,6 +59,6 @@ export default defineComponent({
const isGranted = computed(() => hasPermissions(props.permissions || [], root.$store));
return { realTitle: title, isGranted };
}
},
});
</script>

View File

@ -11,19 +11,19 @@ export default defineComponent({
props: {
link: {
required: true,
type: String
type: String,
},
icon: {
required: true,
type: String
type: String,
},
permissions: {
default: undefined
}
default: undefined,
},
},
setup(props, { root }) {
const isGranted = computed(() => hasPermissions(props.permissions || [], root.$store));
return { isGranted };
}
},
});
</script>

View File

@ -50,21 +50,23 @@ export default defineComponent({
name: 'IsoDateInput',
props: {
value: {
required: true
required: true,
},
label: {},
readonly: {
default: false
default: false,
},
type: {
default: 'date',
validator: function(value: string) {
validator: function (value: string) {
return ['date', 'time', 'datetime'].indexOf(value) !== -1;
}
},
},
rules: {
default: () => { return [] }
}
default: () => {
return [];
},
},
},
setup(props: Props, { emit }: { emit: any }) {
function getDateTime() {
@ -185,7 +187,7 @@ export default defineComponent({
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const customRules = [
props.type == 'date' ? isDate : props.type == 'time' ? isTime : isDateTime,
...props.rules
...props.rules,
];
return {
@ -196,8 +198,8 @@ export default defineComponent({
customRules,
timeChanged,
placeholder,
dateTimeChanged
dateTimeChanged,
};
}
},
});
</script>

View File

@ -12,13 +12,13 @@
// to match your app's branding.
// Tip: Use the "Theme Builder" on Quasar's documentation website.
$primary : #1976D2;
$secondary : #26A69A;
$accent : #9C27B0;
$primary: #1976d2;
$secondary: #26a69a;
$accent: #9c27b0;
$dark : #1D1D1D;
$dark: #1d1d1d;
$positive : #21BA45;
$negative : #C10015;
$info : #31CCEC;
$warning : #F2C037;
$positive: #21ba45;
$negative: #c10015;
$info: #31ccec;
$warning: #f2c037;

View File

@ -42,27 +42,27 @@ declare namespace FG {
volume?: number;
cost_price_pro_volume?: number;
cost_price_package_netto?: number;
tags: Array<Tag>;
type: DrinkType;
tags?: Array<Tag>;
type?: DrinkType;
volumes: Array<DrinkPriceVolume>;
}
interface DrinkIngredient {
id: number;
volume: number;
drink_ingredient_id: number;
price: number;
}
interface DrinkPrice {
id: number;
price: number;
public: bool;
public: boolean;
description?: string;
}
interface DrinkPriceVolume {
id: number;
volume: number;
ingredients: Array<DrinkIngredient | ExtraIngredient>;
min_prices: Array<MinPrices>;
prices: Array<DrinkPrice>;
ingredients: Array<Ingredient>;
}
interface DrinkType {
id: number;
@ -75,9 +75,12 @@ declare namespace FG {
}
interface Ingredient {
id: number;
volume_id: number;
drink_ingredient: DrinkIngredient;
extra_ingredient: ExtraIngredient;
drink_ingredient?: DrinkIngredient;
extra_ingredient?: ExtraIngredient;
}
interface MinPrices {
percentage: number;
price: number;
}
interface Tag {
id: number;

View File

@ -12,20 +12,10 @@
content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width<% if (ctx.mode.cordova || ctx.mode.capacitor) { %>, viewport-fit=cover<% } %>"
/>
<link rel="icon" type="image/svg+xml" href="flaschengeist-logo.svg">
<link rel="icon" type="image/svg+xml" href="flaschengeist-logo.svg" />
<link rel="alternate icon" type="image/ico" href="favicon.ico" />
<link
rel="apple-touch-icon"
type="image/png"
sizes="128x128"
href="favicon-128x128.png"
/>
<link
rel="apple-touch-icon"
type="image/png"
sizes="256x256"
href="favicon-256x256.png"
/>
<link rel="apple-touch-icon" type="image/png" sizes="128x128" href="favicon-128x128.png" />
<link rel="apple-touch-icon" type="image/png" sizes="256x256" href="favicon-256x256.png" />
</head>
<body>

View File

@ -112,23 +112,23 @@ const links = [
name: 'about',
title: 'Über Flaschengeist',
link: 'about',
icon: 'mdi-information'
}
icon: 'mdi-information',
},
];
const shortcuts = [
{
link: 'about',
icon: 'mdi-information'
icon: 'mdi-information',
},
{
link: 'user',
icon: 'mdi-account'
icon: 'mdi-account',
},
{
link: 'user-plugin1',
icon: 'mdi-account-plus'
}
icon: 'mdi-account-plus',
},
];
declare module 'vue/types/vue' {
@ -146,7 +146,7 @@ export default defineComponent({
const leftDrawerOpen = ref(
computed({
get: () => (leftDrawer.value || Screen.gt.sm ? true : false),
set: (val: boolean) => (leftDrawer.value = val)
set: (val: boolean) => (leftDrawer.value = val),
})
);
const leftDrawerMini = ref(false);
@ -189,8 +189,8 @@ export default defineComponent({
links,
pluginChildLinks,
shortcuts,
logout
logout,
};
}
},
});
</script>

View File

@ -6,9 +6,7 @@
<q-avatar rounded>
<img src="flaschengeist-logo-white.svg" />
</q-avatar>
<span class="gt-xs">
Flaschengeist
</span>
<span class="gt-xs"> Flaschengeist </span>
</q-toolbar-title>
<div>
<short-cut-link
@ -49,6 +47,6 @@ import ShortCutLink from 'components/navigation/ShortCutLink.vue';
export default defineComponent({
name: 'OutLayout',
components: { ShortCutLink }
components: { ShortCutLink },
});
</script>

View File

@ -1,7 +1,7 @@
<template>
<q-page
padding
style="grid-auto-rows: 1fr;"
style="grid-auto-rows: 1fr"
class="fit row justify-around items-start q-col-gutter-sm"
>
<div v-for="(item, index) in widgets" :key="index" class="col-4 full-height col-sm-6 col-xs-12">
@ -21,14 +21,14 @@ export default defineComponent({
const widgets = ref<Array<AsyncComponentPromise>>([]);
onMounted(() => {
root.$flaschengeistPlugins.widgets.forEach(widget => {
root.$flaschengeistPlugins.widgets.forEach((widget) => {
if (hasPermissions(widget.permissions, root.$store)) widgets.value.push(widget.widget);
});
});
return {
widgets
widgets,
};
}
},
});
</script>

View File

@ -82,14 +82,14 @@ export default defineComponent({
function doLogin() {
Loading.show({
message: 'Du wirst angemeldet'
message: 'Du wirst angemeldet',
});
root.$store
.dispatch('session/login', {
userid: userid.value,
password: password.value
password: password.value,
})
.then(async finished => {
.then(async (finished) => {
await finished;
const x = root.$route.query['redirect'];
void root.$router.push(typeof x === 'string' ? { path: x } : mainRoute);
@ -103,7 +103,7 @@ export default defineComponent({
message: 'Benutzername oder Passwort sind falsch.',
timeout: 10000,
progress: true,
actions: [{ icon: 'mdi-close', color: 'white' }]
actions: [{ icon: 'mdi-close', color: 'white' }],
});
}
})
@ -120,13 +120,13 @@ export default defineComponent({
message: 'Der Benutzername darf nicht leer sein.',
timeout: 10000,
progress: true,
actions: [{ icon: 'mdi-close', color: 'white' }]
actions: [{ icon: 'mdi-close', color: 'white' }],
});
return;
}
void root.$store
.dispatch('session/requestPasswordReset', {
userid: userid.value
userid: userid.value,
})
.then(() => {
userid.value = '';
@ -138,7 +138,7 @@ export default defineComponent({
'Sollte der Benutzername korrekt und vorhanden sein, erhälst du jetzt eine E-Mail.',
timeout: 10000,
progress: true,
actions: [{ icon: 'mdi-close', color: 'white' }]
actions: [{ icon: 'mdi-close', color: 'white' }],
});
});
}
@ -152,8 +152,8 @@ export default defineComponent({
server,
changeUrl,
visible,
openServerSettings
openServerSettings,
};
}
},
});
</script>

View File

@ -3,7 +3,7 @@
<div>
<div>
<svg
style="max-width: 400px;"
style="max-width: 400px"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 292.761 292.761"
@ -25,9 +25,7 @@
</g>
</svg>
</div>
<div class="text-h2">
Der Admin is über's Kabel gestolpert!
</div>
<div class="text-h2">Der Admin is über's Kabel gestolpert!</div>
<div>
Aktuell kann der Backend Server nicht erreicht werden, wir versuchen es in
{{ reload }} Sekunden erneut.
@ -52,6 +50,6 @@ export default defineComponent({
}, 1000);
onUnmounted(() => clearInterval(ival));
return { reload };
}
},
});
</script>

View File

@ -3,7 +3,7 @@
<div>
<div>
<svg
style="max-width: 400px;"
style="max-width: 400px"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 292.761 292.761"
@ -25,9 +25,7 @@
</g>
</svg>
</div>
<div class="text-h2">
Der Admin war betrunken!!
</div>
<div class="text-h2">Der Admin war betrunken!!</div>
<div>
Einige Plugins konnten nicht geladen werden.<br />Sollte diese Seite jemals auftauchen,
kontaktiere einen nüchternen Admin.
@ -40,7 +38,7 @@
import { defineComponent } from '@vue/composition-api';
export default defineComponent({
name: 'PluginError.vue'
name: 'PluginError.vue',
});
</script>

View File

@ -46,7 +46,7 @@ export default defineComponent({
const rules = [
(val: string) =>
(val && val.length >= 8) || 'Das Passwort muss mindestens 8 Zeichen lang sein!'
(val && val.length >= 8) || 'Das Passwort muss mindestens 8 Zeichen lang sein!',
];
function doReset() {
@ -57,19 +57,19 @@ export default defineComponent({
message: 'Die Passwörter stimmen nicht überein!',
timeout: 10000,
progress: true,
actions: [{ icon: 'mdi-close', color: 'white' }]
actions: [{ icon: 'mdi-close', color: 'white' }],
});
password2.value = '';
return;
}
Loading.show({
message: 'Das Passwort wird zurückgesetzt'
message: 'Das Passwort wird zurückgesetzt',
});
root.$store
.dispatch('session/resetPassword', {
password: password.value,
token: root.$route.query.token
token: root.$route.query.token,
})
.catch((error: AxiosResponse) => {
if (error.status == 403) {
@ -79,7 +79,7 @@ export default defineComponent({
message: 'Der Link ist abgelaufen!',
timeout: 10000,
progress: true,
actions: [{ icon: 'mdi-close', color: 'white' }]
actions: [{ icon: 'mdi-close', color: 'white' }],
});
}
})
@ -90,6 +90,6 @@ export default defineComponent({
}
return { password, password2, doReset, rules };
}
},
});
</script>

View File

@ -12,11 +12,9 @@
/>
<div class="col-12 text-h4 text-center q-pa-sm">
Flaschengeist
<div class="text-caption">
Version 2.0.0
<div class="text-caption">Version 2.0.0</div>
</div>
</div>
<div class="col-12 text-center q-ma-sm" style="max-width: 600px;">
<div class="col-12 text-center q-ma-sm" style="max-width: 600px">
Flaschengeist ist ein dynamischen Managementsystem für Studentenclubs. Es ermöglicht unter
anderem die Mitgliederverwaltung, Dienstverwaltung, Arbeitsgruppenverwaltung und vieles
meher. Es kann fast alles ermöglich werden, wenn ein Plugin dafür geschrieben wird. Jeder
@ -25,9 +23,7 @@
</div>
<q-separator />
<div class="col-12 text-h6 q-pa-sm" v-if="$route.name == 'about'">
Geladene Plugins:
</div>
<div class="col-12 text-h6 q-pa-sm" v-if="$route.name == 'about'">Geladene Plugins:</div>
<div class="col-12 q-pa-sm" v-if="$route.name == 'about'">
<q-chip
v-for="(plugin, index) in $flaschengeistPlugins.plugins"
@ -43,9 +39,7 @@
</q-chip>
</div>
<q-separator />
<div class="col-12 text-h6 q-pa-sm">
Entwickler:
</div>
<div class="col-12 text-h6 q-pa-sm">Entwickler:</div>
<div class="fit row inline wrap justify-around items-start content-start">
<developer
@ -77,7 +71,7 @@ const developers = [
pic:
'https://scontent-frt3-2.xx.fbcdn.net/v/t1.0-9/31768724_1663023210401956_3834323197281435648_n.jpg?_nc_cat=109&_nc_sid=09cbfe&_nc_ohc=jWvUfn_xJ9YAX_oJ3CE&_nc_ht=scontent-frt3-2.xx&oh=15249378051f1e27f8b15122effb5c4a&oe=5FAC6A17',
description:
'Eigentlich wöllte ich jetzt hier echt viel hinschreiben. Aber ich habe keinen Plan was. Früher war ich einfach nur Tim G. und habe für andere den Kaffe geholt. Unter anderen für Ferdinand Thiessen.'
'Eigentlich wöllte ich jetzt hier echt viel hinschreiben. Aber ich habe keinen Plan was. Früher war ich einfach nur Tim G. und habe für andere den Kaffe geholt. Unter anderen für Ferdinand Thiessen.',
},
{
firstname: 'Ferdinand',
@ -87,7 +81,7 @@ const developers = [
'https://scontent-frx5-1.xx.fbcdn.net/v/t1.0-9/17022243_1418942461493397_9069541318944803902_n.jpg?_nc_cat=110&_nc_sid=174925&_nc_ohc=HjkSm8vcRW8AX8bTnJ8&_nc_ht=scontent-frx5-1.xx&oh=f09bd36525f3c6e55feaafb3b05b43d2&oe=5FAD432A',
job: 'Backend-Developer; Co-Maintainer',
description:
'Geiler Typ. Einfach mal so alles Aufgeräumt. Aufeinmal könnte man aus dem Code eine Dokumentation zaubern!'
'Geiler Typ. Einfach mal so alles Aufgeräumt. Aufeinmal könnte man aus dem Code eine Dokumentation zaubern!',
},
{
firstname: 'Dominik',
@ -96,14 +90,14 @@ const developers = [
job: 'Eigentlich Frontend-Developer',
description: 'Er findet sich langsam rein.',
pic:
'https://scontent-frt3-1.xx.fbcdn.net/v/t31.0-8/10363433_647611335326483_3447118968375865826_o.jpg?_nc_cat=104&_nc_sid=09cbfe&_nc_ohc=nWMgo-6Ih74AX_NiGUz&_nc_ht=scontent-frt3-1.xx&oh=f16d2edfe86f68d54900099087edb9c9&oe=5FAACFD4'
}
'https://scontent-frt3-1.xx.fbcdn.net/v/t31.0-8/10363433_647611335326483_3447118968375865826_o.jpg?_nc_cat=104&_nc_sid=09cbfe&_nc_ohc=nWMgo-6Ih74AX_NiGUz&_nc_ht=scontent-frt3-1.xx&oh=f16d2edfe86f68d54900099087edb9c9&oe=5FAACFD4',
},
];
export default defineComponent({
// name: 'PageName'
components: { Developer },
setup() {
return { developers };
}
},
});
</script>

View File

@ -1,6 +1,10 @@
<template>
<q-card>
<BalanceHeader @update:user="userUpdated" :showSelector="showSelector" @open-history="openHistory"/>
<BalanceHeader
@update:user="userUpdated"
:showSelector="showSelector"
@open-history="openHistory"
/>
<q-separator />
<q-card-section class="row q-col-gutter-md" v-if="shortCuts">
@ -73,7 +77,7 @@ export default defineComponent({
if (store.state.balance.transactions.length == 0)
// No transaction, load at most six since yesterday
void store.dispatch('balance/getTransactions', {
filter: { limit: 6, from: new Date(new Date().setDate(new Date().getDate() - 1)) }
filter: { limit: 6, from: new Date(new Date().setDate(new Date().getDate() - 1)) },
});
});
const store = <Store<StateInterfaceBalance>>root.$store;
@ -100,11 +104,11 @@ export default defineComponent({
function changeBalance(amount: number) {
store
.dispatch('balance/changeBalance', { amount: amount, user: user.value?.userid })
.catch(err => console.log(err));
.catch((err) => console.log(err));
}
function openHistory() {
emit('open-history')
emit('open-history');
}
return {
@ -118,8 +122,8 @@ export default defineComponent({
showSelector,
shortCuts,
userUpdated,
openHistory
openHistory,
};
}
},
});
</script>

View File

@ -51,6 +51,6 @@ export default defineComponent({
}
return { user, balance, isLocked, userUpdated, openHistory };
}
},
});
</script>

View File

@ -1,6 +1,10 @@
<template>
<q-card>
<BalanceHeader @update:user="senderUpdated" :showSelector="showSelector" @open-history="openHistory"/>
<BalanceHeader
@update:user="senderUpdated"
:showSelector="showSelector"
@open-history="openHistory"
/>
<q-separator />
<q-card-section class="row q-col-gutter-md items-center">
<div class="col-sm-4 col-xs-12">
@ -64,9 +68,9 @@ export default defineComponent({
.dispatch('balance/changeBalance', {
amount: amount.value,
sender: sender.value?.userid,
user: receiver.value?.userid
user: receiver.value?.userid,
})
.catch(err => console.log(err));
.catch((err) => console.log(err));
}
function openHistory() {
@ -82,8 +86,8 @@ export default defineComponent({
senderUpdated,
receiverUpdated,
sendDisabled,
openHistory
openHistory,
};
}
},
});
</script>

View File

@ -1,21 +1,16 @@
<template>
<div>
<div>
<q-card flat square>
<q-card-section class="row items-center justify-between" horizontal>
<div class="col-5 text-left q-px-sm">
<div
v-bind:class="{ 'text-negative': isNegative() }"
class="text-weight-bold text-h6"
>
<div v-bind:class="{ 'text-negative': isNegative() }" class="text-weight-bold text-h6">
<span v-if="isNegative()">-</span>{{ transaction.amount.toFixed(2) }}&#8239;
</div>
<div class="text-caption">{{ text }}</div>
<div class="text-caption">{{ timeStr }}</div>
</div>
<div class="col-5 q-px-sm text-center">
<div class="text-subtitle1" v-if="isReversed">
Storniert
</div>
<div class="text-subtitle1" v-if="isReversed">Storniert</div>
</div>
<div class="col-2 q-pr-sm" style="text-align: right">
<q-btn
@ -50,8 +45,8 @@ export default defineComponent({
props: {
transaction: {
type: Object,
required: true
}
required: true,
},
},
watch: { transaction: 'refreshText' },
setup(props: Props, { root, emit }) {
@ -70,7 +65,7 @@ export default defineComponent({
text.value = 'Anschreiben';
if (props.transaction.receiver_id !== null) {
const user = <FG.User>await store.dispatch('user/getUser', {
userid: props.transaction.receiver_id
userid: props.transaction.receiver_id,
});
text.value = `Gesendet an ${user.display_name}`;
}
@ -78,7 +73,7 @@ export default defineComponent({
text.value = 'Gutschrift';
if (props.transaction.sender_id !== null) {
const user = <FG.User>await store.dispatch('user/getUser', {
userid: props.transaction.sender_id
userid: props.transaction.sender_id,
});
text.value = `Bekommen von ${user.display_name}`;
}
@ -104,7 +99,7 @@ export default defineComponent({
.then(() => {
emit('update:transaction', props.transaction);
})
.catch(error => console.log(error));
.catch((error) => console.log(error));
}
const timeStr = computed(() => {
@ -114,6 +109,6 @@ export default defineComponent({
});
return { timeStr, reverse, isNegative, text, refreshText, canReverse, isReversed };
}
},
});
</script>

View File

@ -15,7 +15,7 @@ export default defineComponent({
name: 'BalanceWidget',
setup(_, { root }) {
onBeforeMount(() => {
store.dispatch('balance/getBalance').catch(err => {
store.dispatch('balance/getBalance').catch((err) => {
console.warn(err);
});
});
@ -29,6 +29,6 @@ export default defineComponent({
);
return { balance };
}
},
});
</script>

View File

@ -37,28 +37,28 @@ export default defineComponent({
field: 'userid',
required: true,
align: 'left',
sortable: true
sortable: true,
},
{
name: 'credit',
label: 'Haben',
field: 'credit',
format: (val: number) => val.toFixed(2)
format: (val: number) => val.toFixed(2),
},
{
name: 'debit',
label: 'Soll',
field: 'debit',
format: (val: number) => val.toFixed(2)
format: (val: number) => val.toFixed(2),
},
{
name: 'balance',
label: 'Kontostand',
format: (_: undefined, row: { debit: number; credit: number }) =>
(row.credit - row.debit).toFixed(2)
}
(row.credit - row.debit).toFixed(2),
},
];
return { rows, columns };
}
},
});
</script>

View File

@ -9,7 +9,15 @@
/>
</q-tabs>
<div class="fit row justify-end" v-else>
<q-btn flat round icon="mdi-menu" @click="showDrawer = !showDrawer; show = false" />
<q-btn
flat
round
icon="mdi-menu"
@click="
showDrawer = !showDrawer;
show = false;
"
/>
</div>
<q-drawer side="right" v-model="showDrawer" @click="showDrawer = !showDrawer" behavior="mobile">
<q-list v-model="tab" v-if="!$q.screen.gt.sm && !show">
@ -24,11 +32,7 @@
</q-item>
</q-list>
<q-list v-if="show">
<div
v-for="(transaction, index) in transactions"
v-bind:key="index"
class="col-sm-12"
>
<div v-for="(transaction, index) in transactions" v-bind:key="index" class="col-sm-12">
<!-- TODO: In Vue3 use v-model:transaction="..." -->
<Transaction :transaction.sync="transactions[index]" />
</div>
@ -42,10 +46,20 @@
animated
>
<q-tab-panel name="add" class="q-px-xs">
<BalanceAdd @open-history="showDrawer = !showDrawer; show = true"/>
<BalanceAdd
@open-history="
showDrawer = !showDrawer;
show = true;
"
/>
</q-tab-panel>
<q-tab-panel name="transfer" class="q-px-xs">
<BalanceTransfer @open-history="showDrawer = !showDrawer; show = true"/>
<BalanceTransfer
@open-history="
showDrawer = !showDrawer;
show = true;
"
/>
</q-tab-panel>
</q-tab-panels>
</q-page>
@ -68,18 +82,19 @@ export default defineComponent({
components: { BalanceAdd, BalanceTransfer, Transaction },
setup(_, { root }) {
const store = <Store<StateInterfaceBalance>>root.$store;
const now = new Date()
const now = new Date();
onMounted(() => {
void store.dispatch('balance/getTransactions', {filter: {from: new Date(now.getFullYear(), now.getMonth(), now.getDate())}})
})
const transactions = computed(() =>
{
const a =store.state.balance.transactions
.filter(t => t.original_id == undefined)
.filter(t => t.time > new Date(now.getFullYear(), now.getMonth(), now.getDate()))
.sort((a, b) => (a.time >= b.time ? -1 : 1))
console.log(a)
return a
void store.dispatch('balance/getTransactions', {
filter: { from: new Date(now.getFullYear(), now.getMonth(), now.getDate()) },
});
});
const transactions = computed(() => {
const a = store.state.balance.transactions
.filter((t) => t.original_id == undefined)
.filter((t) => t.time > new Date(now.getFullYear(), now.getMonth(), now.getDate()))
.sort((a, b) => (a.time >= b.time ? -1 : 1));
console.log(a);
return a;
});
const canAdd = () =>
@ -94,12 +109,12 @@ export default defineComponent({
...(canAdd() ? [{ name: 'add', label: 'Anschreiben' }] : []),
...(hasSomePermissions([PERMISSIONS.SEND, PERMISSIONS.SEND_OTHER], store)
? [{ name: 'transfer', label: 'Übertragen' }]
: [])
: []),
];
const drawer = ref<boolean>(false);
/* const showDrawer = computed({
/* const showDrawer = computed({
get: () => {
return !Screen.gt.sm && drawer.value;
},
@ -116,8 +131,8 @@ export default defineComponent({
tab,
tabs,
transactions,
show
show,
};
}
},
});
</script>

View File

@ -47,7 +47,7 @@ export default defineComponent({
void store.dispatch('user/getUsers').then(() =>
onRequest({
pagination: pagination.value,
filter: undefined
filter: undefined,
})
);
});
@ -60,7 +60,7 @@ export default defineComponent({
descending: false,
page: 1,
rowsPerPage: 3,
rowsNumber: 10
rowsNumber: 10,
});
interface PaginationInterface {
@ -85,8 +85,8 @@ export default defineComponent({
offset: startRow,
limit: fetchCount,
showCancelled: showCancelled.value,
showReversals: false
}
showReversals: false,
},
})
.then((result: TransactionsResponse) => {
// clear out existing data and add new
@ -114,7 +114,7 @@ export default defineComponent({
field: 'time',
required: true,
sortable: true,
format: (val: Date) => formatDateTime(new Date(val), true, true, true)
format: (val: Date) => formatDateTime(new Date(val), true, true, true),
},
{
name: 'type',
@ -128,7 +128,7 @@ export default defineComponent({
else return 'Gesendet an X';
}
}
}
},
},
{
name: 'text',
@ -142,27 +142,27 @@ export default defineComponent({
else return 'Gesendet an X';
}
}
}
},
},
{
name: 'amount',
label: 'Betrag',
field: 'amount',
format: (val: number) => `${val.toFixed(2)}`
format: (val: number) => `${val.toFixed(2)}`,
},
{
name: 'author_id',
label: 'Benutzer',
field: 'author_id',
format: (val: string) => {
const user = store.state.user.users.filter(x => x.userid == val);
const user = store.state.user.users.filter((x) => x.userid == val);
if (user.length > 0) return user[0].display_name;
else return val;
}
}
},
},
];
return { data, pagination, onRequest, loading, balance, columns, showCancelled };
}
},
});
</script>

View File

@ -15,7 +15,7 @@ const PERMISSIONS = {
// Can set limit for users
SET_LIMIT: 'balance_set_limit',
//Allow sending / sub while exceeding the set limit
EXCEED_LIMIT: 'balance_exceed_limit'
EXCEED_LIMIT: 'balance_exceed_limit',
};
export default PERMISSIONS;

View File

@ -16,9 +16,9 @@ const plugin: FG_Plugin.Plugin = {
priority: 0,
name: 'current',
permissions: ['balance_show'],
widget: () => import('./components/Widget.vue')
}
]
widget: () => import('./components/Widget.vue'),
},
],
};
export default plugin;

View File

@ -16,7 +16,7 @@ const mainRoutes: FG_Plugin.PluginRouteConfig[] = [
path: 'overview',
name: 'balance-view',
meta: { permissions: [permissions.SHOW] },
component: () => import('../pages/Overview.vue')
component: () => import('../pages/Overview.vue'),
},
{
title: 'Buchen',
@ -25,7 +25,7 @@ const mainRoutes: FG_Plugin.PluginRouteConfig[] = [
name: 'balance-change',
shortcut: true,
meta: { permissions: [permissions.DEBIT_OWN, permissions.SHOW] },
component: () => import('../pages/MainPage.vue')
component: () => import('../pages/MainPage.vue'),
},
{
title: 'Verwaltung',
@ -33,10 +33,10 @@ const mainRoutes: FG_Plugin.PluginRouteConfig[] = [
path: 'admin',
name: 'balance-admin',
meta: { permissions: [permissions.SET_LIMIT, permissions.SHOW_OTHER] },
component: () => import('../pages/Admin.vue')
}
]
}
component: () => import('../pages/Admin.vue'),
},
],
},
];
export default mainRoutes;

View File

@ -23,9 +23,7 @@
<q-btn label="neues Getränk" color="positive" icon-right="add">
<q-menu anchor="center middle" self="center middle">
<div class="q-pa-sm">
<div class="q-table__title q-pa-sm">
Neues Getränk
</div>
<div class="q-table__title q-pa-sm">Neues Getränk</div>
<div class="row">
<q-input
class="col-sm-4 col-xs-6 q-pa-sm"
@ -159,8 +157,8 @@
{{ drinks_props.row.volume ? `${drinks_props.row.volume} L` : 'o.A.' }}
<q-popup-edit
v-if="
!drinks_props.row.volumes.some(volume =>
volume.ingredients.some(ingredient => ingredient.drink_ingredient)
!drinks_props.row.volumes.some((volume) =>
volume.ingredients.some((ingredient) => ingredient.drink_ingredient)
)
"
v-model.number="drinks_props.row.volume"
@ -186,8 +184,8 @@
{{ drinks_props.row.package_size || 'o.A.' }}
<q-popup-edit
v-if="
!drinks_props.row.volumes.some(volume =>
volume.ingredients.some(ingredient => ingredient.drink_ingredient)
!drinks_props.row.volumes.some((volume) =>
volume.ingredients.some((ingredient) => ingredient.drink_ingredient)
)
"
v-model="drinks_props.row.package_size"
@ -214,8 +212,8 @@
}}
<q-popup-edit
v-if="
!drinks_props.row.volumes.some(volume =>
volume.ingredients.some(ingredient => ingredient.drink_ingredient)
!drinks_props.row.volumes.some((volume) =>
volume.ingredients.some((ingredient) => ingredient.drink_ingredient)
)
"
v-model="drinks_props.row.cost_price_package_netto"
@ -250,8 +248,8 @@
!!drinks_props.row.volume &&
!!drinks_props.row.package_size
) &&
!drinks_props.row.volumes.some(volume =>
volume.ingredients.some(ingredient => ingredient.drink_ingredient)
!drinks_props.row.volumes.some((volume) =>
volume.ingredients.some((ingredient) => ingredient.drink_ingredient)
)
"
v-model="drinks_props.row.cost_price_pro_volume.value"
@ -611,82 +609,82 @@ export default defineComponent({
{
name: 'name',
label: 'Getränkename',
field: 'name'
field: 'name',
},
{
name: 'article_id',
label: 'Artikelnummer',
field: 'article_id'
field: 'article_id',
},
{
name: 'drink_type',
label: 'Kategorie',
field: 'type',
format: (val: FG.DrinkType) => `${val.name}`
format: (val: FG.DrinkType) => `${val.name}`,
},
{
name: 'volume_package',
label: 'Inhalt in l des Gebinde',
field: 'volume'
field: 'volume',
},
{
name: 'package_size',
label: 'Gebindegröße',
field: 'package_size'
field: 'package_size',
},
{
name: 'cost_price_package_netto',
label: 'Preis Netto/Gebinde',
field: 'cost_price_package_netto',
format: (val: number | null) => (val ? `${val.toFixed(3)}` : '')
format: (val: number | null) => (val ? `${val.toFixed(3)}` : ''),
},
{
name: 'cost_price_pro_volume',
label: 'Preis mit 19%/Liter',
field: 'cost_price_pro_volume',
format: (val: number | null) => (val ? `${val.toFixed(3)}` : '')
format: (val: number | null) => (val ? `${val.toFixed(3)}` : ''),
},
{
name: 'volumes',
label: 'Preiskalkulation',
field: 'volumes'
}
field: 'volumes',
},
];
const column_calc = [
{
name: 'volume',
label: 'Abgabe in l',
field: 'volume',
format: (val: number) => `${val} L`
format: (val: number) => `${val} L`,
},
{
name: 'min_prices',
label: 'Minimal Preise',
field: 'min_prices'
field: 'min_prices',
},
{
name: 'prices',
label: 'Preise',
field: 'prices'
}
field: 'prices',
},
];
const column_prices = [
{
name: 'price',
label: 'Preis',
field: 'price',
format: (val: number) => `${val.toFixed(2)}`
format: (val: number) => `${val.toFixed(2)}`,
},
{
name: 'description',
label: 'Beschreibung',
field: 'description'
field: 'description',
},
{
name: 'public',
label: 'Öffentlich',
field: 'public'
}
field: 'public',
},
];
const visibleColumn = ref([
'name',
@ -701,7 +699,7 @@ export default defineComponent({
'prices',
'price',
'description',
'public'
'public',
]);
const emptyVolume: DrinkPriceVolume = {
id: -1,
@ -710,10 +708,10 @@ export default defineComponent({
min_prices: [
{ percentage: 100, price: null },
{ percentage: 250, price: null },
{ percentage: 300, price: null }
{ percentage: 300, price: null },
],
prices: [],
ingredients: []
ingredients: [],
};
const newVolume = ref<DrinkPriceVolume>(emptyVolume);
function addVolume(drink: Drink) {
@ -749,7 +747,7 @@ export default defineComponent({
cost_price_package_netto: undefined,
tags: [],
type: undefined,
volumes: []
volumes: [],
};
const newDrink = ref<FG.Drink>(emptyDrink);
@ -770,9 +768,9 @@ export default defineComponent({
}
return newDrink.value.cost_price_pro_volume;
},
set: val => {
set: (val) => {
newDrink.value.cost_price_pro_volume = val;
}
},
});
const drinkTypes = computed(() => store.state.drinkTypes);
@ -811,9 +809,9 @@ export default defineComponent({
cancelAddDrink,
updateDrink,
deleteDrink,
console
console,
};
}
},
});
</script>

View File

@ -9,12 +9,12 @@
<div class="col" v-if="ingredient.drink_ingredient">
<div class="full-width row justify-evenly q-py-xs">
<div class="col">
{{ ingredient.drink_ingredient.drink_ingredient.name }}
{{ get_drink_ingredient_name(ingredient.drink_ingredient.drink_ingredient_id) }}
<q-popup-edit
buttons
label-cancel="Abbrechen"
label-set="Speichern"
v-model="ingredient.drink_ingredient.drink_ingredient"
v-model="ingredient.drink_ingredient.drink_ingredient_id"
@save="updateIngredient(ingredient, volume)"
>
<q-select
@ -24,7 +24,10 @@
dense
:options="drinks"
option-label="name"
v-model="ingredient.drink_ingredient.drink_ingredient"
option-value="id"
v-model="ingredient.drink_ingredient.drink_ingredient_id"
emit-value
map-options
/>
</q-popup-edit>
</div>
@ -149,32 +152,32 @@ export default defineComponent({
props: {
ingredients: {
type: Array as () => Array<FG.Ingredient>,
required: true
required: true,
},
volume: {
type: Object as () => DrinkPriceVolume,
required: true
}
required: true,
},
},
setup() {
const emptyIngredient: FG.Ingredient = {
id: -1,
drink_ingredient: null,
extra_ingredient: null
drink_ingredient: undefined,
extra_ingredient: undefined,
};
const newIngredient = ref<FG.Drink | FG.ExtraIngredient>();
const newIngredientVolume = ref<number>(0);
function addIngredient(volume: DrinkPriceVolume) {
if ((<FG.Drink>newIngredient.value)?.volume) {
if ((<FG.Drink>newIngredient.value)?.volume && newIngredient.value) {
store.actions.setIngredient(
{
id: -1,
drink_ingredient: {
id: -1,
drink_ingredient: <FG.Drink>newIngredient.value,
volume: newIngredientVolume.value
drink_ingredient_id: newIngredient.value.id,
volume: newIngredientVolume.value,
},
extra_ingredient: null
extra_ingredient: undefined,
},
volume
);
@ -182,8 +185,8 @@ export default defineComponent({
store.actions.setIngredient(
{
id: -1,
drink_ingredient: null,
extra_ingredient: <FG.ExtraIngredient>newIngredient.value
drink_ingredient: undefined,
extra_ingredient: <FG.ExtraIngredient>newIngredient.value,
},
volume
);
@ -202,10 +205,16 @@ export default defineComponent({
store.actions.deleteIngredient(ingredient, volume);
}
const drinks = computed(() =>
store.state.drinks.filter(drink => !!drink.cost_price_pro_volume)
store.state.drinks.filter((drink) => {
return drink.cost_price_pro_volume.value;
})
);
const extra_ingredients = computed(() => store.state.extraIngredients);
function get_drink_ingredient_name(id: number) {
return store.state.drinks.find((a) => a.id === id)?.name;
}
return {
addIngredient,
drinks,
@ -214,9 +223,10 @@ export default defineComponent({
newIngredientVolume,
cancelAddIngredient,
updateIngredient,
deleteIngredient
deleteIngredient,
get_drink_ingredient_name,
};
}
},
});
</script>

View File

@ -146,27 +146,27 @@ export default defineComponent({
props: {
columns: {
type: Array,
required: true
required: true,
},
data: {
type: Array,
required: true
required: true,
},
row: {
type: Object as () => DrinkPriceVolume,
required: true
required: true,
},
visibleColumns: {
type: Array,
required: true
}
required: true,
},
},
setup(props) {
const emptyPrice = {
id: -1,
price: 0,
description: '',
public: true
public: true,
};
const newPrice = ref(emptyPrice);
function addPrice(volume: DrinkPriceVolume) {
@ -188,7 +188,7 @@ export default defineComponent({
}
const pagination = ref({
rowsPerPage: props.row.prices.length
rowsPerPage: props.row.prices.length,
});
return {
@ -198,9 +198,9 @@ export default defineComponent({
updatePrice,
deletePrice,
pagination,
console
console,
};
}
},
});
</script>

View File

@ -16,7 +16,7 @@
</q-dialog>
<q-page padding>
<q-table title="Getränkearten" :data="rows" :row-key="row => row.id" :columns="columns">
<q-table title="Getränkearten" :data="rows" :row-key="(row) => row.id" :columns="columns">
<template v-slot:top-right>
<q-input
class="q-px-sm"
@ -74,14 +74,14 @@ export default defineComponent({
label: 'Getränkeart',
field: 'name',
align: 'left',
sortable: true
sortable: true,
},
{
name: 'actions',
label: 'Aktionen',
field: 'actions',
align: 'right'
}
align: 'right',
},
];
function addType() {
@ -98,7 +98,7 @@ export default defineComponent({
void store
.dispatch('drink/changeDrinkTypeName', {
id: actualDrinkType.value.id,
name: newDrinkTypeName.value
name: newDrinkTypeName.value,
})
.finally(() => discardChanges());
}
@ -124,9 +124,9 @@ export default defineComponent({
actualDrinkType,
newDrinkTypeName,
discardChanges,
saveChanges
saveChanges,
};
}
},
});
</script>

View File

@ -26,7 +26,7 @@
</q-dialog>
<q-page padding>
<q-table title="Getränkearten" :data="rows" :row-key="row => row.id" :columns="columns">
<q-table title="Getränkearten" :data="rows" :row-key="(row) => row.id" :columns="columns">
<template v-slot:top-right>
<q-input
class="q-px-sm"
@ -71,7 +71,7 @@ export default defineComponent({
const emptyExtraIngredient: FG.ExtraIngredient = {
name: '',
price: 0,
id: -1
id: -1,
};
const newExtraIngredient = ref(emptyExtraIngredient);
const newDrinkTypeName = ref('');
@ -85,21 +85,21 @@ export default defineComponent({
label: 'Bezeichnung',
field: 'name',
align: 'left',
sortable: true
sortable: true,
},
{
name: 'price',
label: 'Preis',
field: 'price',
sortable: true,
format: (val: number) => `${val.toFixed(2)}`
format: (val: number) => `${val.toFixed(2)}`,
},
{
name: 'actions',
label: 'Aktionen',
field: 'actions',
align: 'right'
}
align: 'right',
},
];
function addExtraIngredient() {
@ -137,9 +137,9 @@ export default defineComponent({
editType,
actualExtraIngredient,
discardChanges,
saveChanges
saveChanges,
};
}
},
});
</script>

View File

@ -1,67 +1,62 @@
<template>
<div>
<q-table
title="Getränke"
:columns="columns"
:data="drinks"
row-key="name"
>
<template v-slot:body-cell-prices="{row: {prices}}">
<div>
<q-table title="Getränke" :columns="columns" :data="drinks" row-key="name">
<template v-slot:body-cell-prices="{ row: { prices } }">
<q-td>
<div v-for="price in prices" :key="price.id" class="row">
<div class="col">
{{price.volume | setVolume}}
{{ price.volume | setVolume }}
</div>
<div class="col">
{{price.price | setCurrency}}
{{ price.price | setCurrency }}
</div>
<div class="col">
{{price.description}}
{{ price.description }}
</div>
</div>
</q-td>
</template>
</q-table>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent, onBeforeMount, ref} from '@vue/composition-api';
import {StateInterface} from 'src/store';
import {DrinkInterface} from '../store/drinks';
import {Store} from 'vuex';
import { defineComponent, onBeforeMount, ref } from '@vue/composition-api';
import { StateInterface } from 'src/store';
import { DrinkInterface } from '../store/drinks';
import { Store } from 'vuex';
export default defineComponent({
name: 'Pricelist',
filters: {
setVolume(volume: number) {
if (volume*10 > 1) {
return `${volume}l`
if (volume * 10 > 1) {
return `${volume}l`;
}
return `${volume*100}cl`
return `${volume * 100}cl`;
},
setCurrency(price: number) {
return `${price.toFixed(2)}`
}
return `${price.toFixed(2)}`;
},
setup(_, {root}) {
},
setup(_, { root }) {
const store = <Store<StateInterface>>root.$store;
const state = <DrinkInterface>store.state.drink;
const drinks = ref(state.drinks)
const drinks = ref(state.drinks);
onBeforeMount(() => {
void store.dispatch('drink/getDrinks');
})
});
const columns = [
{
name: 'name',
label: 'Getränk',
field: 'name'
field: 'name',
},
{
name: 'prices',
label: 'Preise',
field: 'prices'
}
]
return {columns, drinks}
}
})
field: 'prices',
},
];
return { columns, drinks };
},
});
</script>

View File

@ -39,6 +39,6 @@ export default defineComponent({
});
return { checkMain, mainRoutes };
}
},
});
</script>

View File

@ -1,15 +1,13 @@
<template>
<Pricelist />
<Pricelist />
</template>
<script>
import Pricelist from '../components/Pricelist.vue'
import Pricelist from '../components/Pricelist.vue';
export default {
name: 'PricelistPage',
components: {Pricelist}
}
components: { Pricelist },
};
</script>
<style scoped>
</style>
<style scoped></style>

View File

@ -27,7 +27,7 @@
<q-page paddding class="fit row justify-center content-start items-start q-gutter-sm">
<q-tab-panels
v-model="tab"
style="background-color: transparent;"
style="background-color: transparent"
animated
class="q-ma-none q-pa-none fit row justify-center content-start items-start"
>
@ -68,19 +68,19 @@ export default defineComponent({
},
set: (val: boolean) => {
drawer.value = val;
}
},
});
const tabs: Tab[] = [
{ name: 'pricelist', label: 'Getränke' },
{ name: 'extra_ingredients', label: 'Zutaten' },
{ name: 'drink_types', label: 'Getränketypen' }
{ name: 'drink_types', label: 'Getränketypen' },
];
const tab = ref<string>('pricelist');
return { tabs, tab, showDrawer };
}
},
});
</script>

View File

@ -14,7 +14,7 @@ const state = reactive<{
extraIngredients: [],
});
interface MinPrice extends Omit<FG.DrinkMinPrice, 'price'> {
interface MinPrice extends Omit<FG.MinPrices, 'price'> {
price: WritableComputedRef<number> | null;
}
interface DrinkPriceVolume extends Omit<Omit<FG.DrinkPriceVolume, 'volume'>, 'min_prices'> {
@ -218,10 +218,10 @@ const actions = {
axios
.put(`pricelist/ingredients/${ingredient.id}`, ingredient)
.then((response: AxiosResponse<FG.Ingredient>) => {
const index = volume.ingredients.findIndex((a) => a.id === response.data.id);
/*const index = volume.ingredients.findIndex(a => a.id === response.data.id);
if (index > -1) {
volume.ingredients[index] = response.data;
}
}*/
})
.catch((err) => console.warn(err));
},
@ -337,7 +337,7 @@ function create_min_prices(drink: Drink, volume: DrinkPriceVolume, percentage: n
volume.ingredients.forEach((ingredient) => {
if (ingredient.drink_ingredient) {
const _drink = state.drinks.find(
(a) => a.id === ingredient.drink_ingredient?.drink_ingredient?.id
(a) => a.id === ingredient.drink_ingredient?.drink_ingredient_id
);
retVal += ingredient.drink_ingredient.volume * (_drink?.cost_price_pro_volume.value || 0);
}

View File

@ -1,5 +1,5 @@
<template>
<q-card class="row justify-center content-center" style="text-align: center;">
<q-card class="row justify-center content-center" style="text-align: center">
<q-card-section>
<div class="text-h6 col-12">Dienste diesen Monat: {{ jobs }}</div>
<div class="text-h6 col-12">Nächster Dienst: {{ nextJob | date }}</div>
@ -19,6 +19,6 @@ export default defineComponent({
const jobs = randomNumber(0, 5);
const nextJob = new Date(2021, randomNumber(1, 12), randomNumber(1, 31));
return { jobs, nextJob };
}
},
});
</script>

View File

@ -87,14 +87,14 @@ export default defineComponent({
end: undefined,
comment: '',
services: [],
required_services: 2
required_services: 2,
} as unknown) as FG.Job);
const event = ref<FG.Event>({
id: NaN,
start: new Date(),
description: '',
jobs: [Object.assign({}, newJob.value)]
jobs: [Object.assign({}, newJob.value)],
} as FG.Event);
onBeforeMount(() => {
@ -142,7 +142,7 @@ export default defineComponent({
console.log('Event:', event);
void store
.dispatch('schedule/addEvent', event.value)
.catch(error => {
.catch((error) => {
console.warn(error);
})
.then(() => {
@ -182,9 +182,9 @@ export default defineComponent({
setEnd,
setComment,
setJobType,
setRequired
setRequired,
};
}
},
});
</script>

View File

@ -76,14 +76,14 @@ export default defineComponent({
label: 'Veranstaltungstyp',
field: 'name',
align: 'left',
sortable: true
sortable: true,
},
{
name: 'actions',
label: 'Aktionen',
field: 'actions',
align: 'right'
}
align: 'right',
},
];
function addType() {
@ -101,7 +101,7 @@ export default defineComponent({
.dispatch('schedule/changeEventTypeName', {
id: actualEvent.value.id,
name: newEventName.value,
oldname: actualEvent.value.name
oldname: actualEvent.value.name,
})
.finally(() => {
discardChanges();
@ -128,9 +128,9 @@ export default defineComponent({
actualEvent,
newEventName,
discardChanges,
saveChanges
saveChanges,
};
}
},
});
</script>

View File

@ -19,7 +19,7 @@
:rules="[noValidDate, isAfterDate, notEmpty]"
/>
</q-card-section>
<q-card-section class=" row fit justify-start content-center items-center">
<q-card-section class="row fit justify-start content-center items-center">
<q-select
:key="refreshKey"
filled
@ -77,17 +77,17 @@ export default defineComponent({
components: { IsoDateInput },
props: {
job: {
required: true
required: true,
},
jobCanDelete: {
default: false
}
default: false,
},
},
watch: {
job: function() {
job: function () {
// this.type.name = this.type.name;
this.$props.job.type = this.$props.job.type;
}
},
},
setup(props: Props, { root, emit }) {
@ -157,9 +157,9 @@ export default defineComponent({
notEmpty,
noValidDate,
isAfterDate,
refreshKey
refreshKey,
};
}
},
});
</script>

View File

@ -73,14 +73,14 @@ export default defineComponent({
label: 'Name',
field: 'name',
align: 'left',
sortable: true
sortable: true,
},
{
name: 'actions',
label: 'Aktionen',
field: 'actions',
align: 'right'
}
align: 'right',
},
];
function addType() {
@ -121,9 +121,9 @@ export default defineComponent({
actualJob,
newJobName,
discardChanges,
saveChanges
saveChanges,
};
}
},
});
</script>

View File

@ -2,7 +2,7 @@
<q-page padding>
<q-card>
<template>
<div style="max-width: 1800px; width: 100%;">
<div style="max-width: 1800px; width: 100%">
<q-toolbar class="bg-primary text-white q-my-md shadow-2 items-center row justify-center">
<div class="row justify-center items-center">
<q-btn flat dense label="Prev" @click="calendarPrev" />
@ -41,7 +41,7 @@
toggle-color=""
:options="[
{ label: 'Tag', value: 'day-agenda' },
{ label: 'Woche', value: 'week-agenda' }
{ label: 'Woche', value: 'week-agenda' },
]"
/>
</q-toolbar>
@ -50,11 +50,11 @@
:view="calendarView"
:weekdays="[1, 2, 3, 4, 5, 6, 0]"
locale="de-de"
style="height: 100%; min-height: 400px;"
style="height: 100%; min-height: 400px"
ref="calendar"
>
<template #day-body="{ timestamp }" style="min-height: 200px;">
<template !v-if="getAgenda(timestamp)" style="min-height: 200px;"> </template>
<template #day-body="{ timestamp }" style="min-height: 200px">
<template !v-if="getAgenda(timestamp)" style="min-height: 200px"> </template>
<template v-for="agenda in getAgenda(timestamp)">
<eventslot :event="agenda" :key="agenda.id" />
</template>
@ -79,7 +79,7 @@ export default defineComponent({
name: 'AgendaView',
components: { Eventslot },
filters: {
toMonth: function(value: string) {
toMonth: function (value: string) {
if (value) {
return date.formatDate(new Date(value), 'MMMM', {
months: [
@ -94,16 +94,16 @@ export default defineComponent({
'September',
'Oktober',
'November',
'Dezember'
]
'Dezember',
],
});
}
},
toYear: function(value: string) {
toYear: function (value: string) {
if (value) {
return date.formatDate(new Date(value), 'YYYY');
}
}
},
},
setup(_, { root }) {
@ -117,12 +117,12 @@ export default defineComponent({
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
console.log('Hier Passiert was');
state.value.events
.filter(event => {
.filter((event) => {
const thisWeek = date.formatDate(new Date(selectedDate.value), 'w');
console.log(thisWeek, date.formatDate(event.start, 'w'));
return date.formatDate(event.start, 'w') == thisWeek;
})
.forEach(event => {
.forEach((event) => {
let day = event.start.getDay();
console.log('event', event, day, !agenda[day]);
if (!agenda[day]) {
@ -172,9 +172,9 @@ export default defineComponent({
updateProxy,
saveNewSelectedDate,
proxyDate,
calendarView
calendarView,
};
}
},
});
</script>

View File

@ -8,7 +8,7 @@
{{ event.type.name }}
</div>
<div v-if="event.description" class=" col text-weight-medium " style="font-size: 10px">
<div v-if="event.description" class="col text-weight-medium" style="font-size: 10px">
Info
{{ event.description }}
</div>
@ -29,14 +29,14 @@
<q-select
filled
v-model="job.services"
:option-label="opt => userDisplay(opt)"
:option-label="(opt) => userDisplay(opt)"
multiple
disable
use-chips
stack-label
label="Dienste"
class="col-auto q-px-xs"
style="font-size: 6px "
style="font-size: 6px"
counter
:max-values="job.required_services"
:key="refreshKey"
@ -81,15 +81,15 @@ export default defineComponent({
components: {},
props: {
event: {
required: true
}
required: true,
},
},
filters: {
formatToHour: function(value: Date) {
formatToHour: function (value: Date) {
if (value) {
return date.formatDate(value, 'HH:mm');
}
}
},
},
setup(props: Props, { root, emit }) {
@ -104,14 +104,14 @@ export default defineComponent({
refreshKey.value += 1;
}
onBeforeMount(() => {
store.dispatch('user/getUsers').catch(error => {
store.dispatch('user/getUsers').catch((error) => {
console.warn(error);
});
});
function isUserEnrolled(job: FG.Job) {
return (
job.services.filter(service => service.userid == state.currentUser?.userid).length >= 1
job.services.filter((service) => service.userid == state.currentUser?.userid).length >= 1
);
}
function jobFull(job: FG.Job) {
@ -119,7 +119,7 @@ export default defineComponent({
return job.services.length >= job.required_services;
}
function userDisplay(userid: string) {
return state.users.find(user => (user.userid = userid))?.display_name;
return state.users.find((user) => (user.userid = userid))?.display_name;
}
function enrollForJob(this: any, job: FG.Job) {
@ -127,16 +127,16 @@ export default defineComponent({
if (state.currentUser) {
const newService: FG.Service = {
userid: state.currentUser?.userid,
value: 1
value: 1,
};
const newUserService = { user: newService };
const UpdateInformation = {
eventId: <number>this.event.id,
JobId: job.id,
service: newUserService
service: newUserService,
};
void store.dispatch('schedule/updateEvent', UpdateInformation).catch(error => {
void store.dispatch('schedule/updateEvent', UpdateInformation).catch((error) => {
console.warn(error);
});
}
@ -147,16 +147,16 @@ export default defineComponent({
if (state.currentUser) {
const newService: FG.Service = {
userid: state.currentUser?.userid,
value: -1
value: -1,
};
const newUserService = { user: newService };
const UpdateInformation = {
eventId: <number>this.event.id,
JobId: job.id,
service: newUserService
service: newUserService,
};
void store.dispatch('schedule/updateEvent', UpdateInformation).catch(error => {
void store.dispatch('schedule/updateEvent', UpdateInformation).catch((error) => {
console.warn(error);
});
}
@ -173,9 +173,9 @@ export default defineComponent({
signOutFromJob,
jobFull,
userDisplay,
refresh
refresh,
};
}
},
});
</script>

View File

@ -43,7 +43,7 @@ export default defineComponent({
setLoadingBar(loading);
return { checkMain, mainRoutes };
}
},
});
</script>
<style scoped></style>

View File

@ -27,7 +27,7 @@
<q-page padding class="fit row justify-center content-start items-start q-gutter-sm">
<q-tab-panels
v-model="tab"
style="background-color: transparent;"
style="background-color: transparent"
class="q-ma-none q-pa-none fit row justify-center content-start items-start"
animated
>
@ -72,7 +72,7 @@ export default defineComponent({
const tabs: Tab[] = [
{ name: 'create', label: 'Veranstaltungen' },
{ name: 'eventtypes', label: 'Veranstaltungsarten' },
{ name: 'jobtypes', label: 'Dienstarten' }
{ name: 'jobtypes', label: 'Dienstarten' },
];
const drawer = ref<boolean>(false);
@ -83,7 +83,7 @@ export default defineComponent({
},
set: (val: boolean) => {
drawer.value = val;
}
},
});
const tab = ref<string>('create');
@ -92,8 +92,8 @@ export default defineComponent({
canEditRoles,
showDrawer,
tab,
tabs
tabs,
};
}
},
});
</script>

View File

@ -27,7 +27,7 @@
<q-page padding class="fit row justify-center content-start items-start q-gutter-sm">
<q-tab-panels
v-model="tab"
style="background-color: transparent;"
style="background-color: transparent"
class="q-ma-none q-pa-none fit row justify-center content-start items-start"
animated
>
@ -71,7 +71,7 @@ export default defineComponent({
}
const tabs: Tab[] = [
{ name: 'agendaView', label: 'Kalendar' }
{ name: 'agendaView', label: 'Kalendar' },
// { name: 'eventtypes', label: 'Veranstaltungsarten' },
// { name: 'jobtypes', label: 'Dienstarten' }
];
@ -84,7 +84,7 @@ export default defineComponent({
},
set: (val: boolean) => {
drawer.value = val;
}
},
});
const tab = ref<string>('agendaView');
@ -93,8 +93,8 @@ export default defineComponent({
canEditRoles,
showDrawer,
tab,
tabs
tabs,
};
}
},
});
</script>

View File

@ -8,5 +8,5 @@ export const PERMISSIONS = {
// Kann neue Nutzer hinzufügen
REGISTER: 'users_register',
// Kann Rollen löschen oder bearbeiten, z.b. Rechte hinzufügen etc
ROLES_EDIT: 'roles_edit'
ROLES_EDIT: 'roles_edit',
};

View File

@ -16,9 +16,9 @@ const plugin: FG_Plugin.Plugin = {
priority: 0,
name: 'stats',
permissions: [],
widget: () => import('./components/Widget.vue')
}
]
widget: () => import('./components/Widget.vue'),
},
],
};
export default plugin;

View File

@ -16,7 +16,7 @@ const mainRoutes: FG_Plugin.PluginRouteConfig[] = [
name: 'schedule-overview',
shortcut: true,
meta: { permissions: [] },
component: () => import('../pages/Overview.vue')
component: () => import('../pages/Overview.vue'),
},
{
title: 'Dienstverwaltung',
@ -25,7 +25,7 @@ const mainRoutes: FG_Plugin.PluginRouteConfig[] = [
name: 'schedule-management',
shortcut: false,
meta: { permissions: [] },
component: () => import('../pages/Management.vue')
component: () => import('../pages/Management.vue'),
},
{
title: 'Dienstanfragen',
@ -34,10 +34,10 @@ const mainRoutes: FG_Plugin.PluginRouteConfig[] = [
name: 'schedule-requests',
shortcut: false,
meta: { permissions: [] },
component: () => import('../pages/Requests.vue')
}
]
}
component: () => import('../pages/Requests.vue'),
},
],
},
];
export default mainRoutes;

View File

@ -22,7 +22,7 @@ export interface ScheduleInterface {
const state: ScheduleInterface = {
jobTypes: [],
eventTypes: [],
events: []
events: [],
};
interface Event {
@ -51,11 +51,11 @@ const mutations: MutationTree<ScheduleInterface> = {
state.jobTypes.unshift(jobType);
},
removeJobType(state, id: number) {
const index = state.jobTypes.findIndex(item => item.id == id);
const index = state.jobTypes.findIndex((item) => item.id == id);
state.jobTypes.splice(index, 1);
},
setJobType(state, jobType: JobType) {
const _jobtype = state.jobTypes.find(item => item.id == jobType.id);
const _jobtype = state.jobTypes.find((item) => item.id == jobType.id);
if (_jobtype) {
_jobtype.name = jobType.name;
}
@ -67,11 +67,11 @@ const mutations: MutationTree<ScheduleInterface> = {
state.eventTypes.unshift(eventType);
},
removeEventType(state, id: number) {
const index = state.eventTypes.findIndex(item => item.id == id);
const index = state.eventTypes.findIndex((item) => item.id == id);
state.eventTypes.splice(index, 1);
},
setEventType(state, eventType: EventType) {
const _eventtype = state.eventTypes.find(item => item.id == eventType.id);
const _eventtype = state.eventTypes.find((item) => item.id == eventType.id);
if (_eventtype) {
_eventtype.name = eventType.name;
}
@ -85,11 +85,11 @@ const mutations: MutationTree<ScheduleInterface> = {
updateEvent(state, event: FG.Event) {
/*let eventToChange = state.events.find(ev => ev.id == event.id);
eventToChange = event; */
const index = state.events.findIndex(ev => ev.id == event.id);
const index = state.events.findIndex((ev) => ev.id == event.id);
if (index > -1) {
state.events[index] = event;
}
}
},
};
const actions: ActionTree<ScheduleInterface, StateInterface> = {
@ -100,7 +100,7 @@ const actions: ActionTree<ScheduleInterface, StateInterface> = {
console.log('action:', response.data);
commit('setJobTypes', response.data);
})
.catch(err => {
.catch((err) => {
console.warn(err);
});
},
@ -111,7 +111,7 @@ const actions: ActionTree<ScheduleInterface, StateInterface> = {
.then((response: AxiosResponse<JobType>) => {
commit('addJobType', response.data);
})
.catch(err => {
.catch((err) => {
console.warn(err);
});
},
@ -122,7 +122,7 @@ const actions: ActionTree<ScheduleInterface, StateInterface> = {
.then(() => {
commit('removeJobType', data);
})
.catch(err => {
.catch((err) => {
console.warn(err);
});
},
@ -133,7 +133,7 @@ const actions: ActionTree<ScheduleInterface, StateInterface> = {
.then(() => {
commit('setJobType', jobtype);
})
.catch(err => {
.catch((err) => {
console.warn(err);
});
},
@ -145,7 +145,7 @@ const actions: ActionTree<ScheduleInterface, StateInterface> = {
console.log('action:', response.data);
commit('setEventTypes', response.data);
})
.catch(err => {
.catch((err) => {
console.warn(err);
});
},
@ -157,7 +157,7 @@ const actions: ActionTree<ScheduleInterface, StateInterface> = {
.then((response: AxiosResponse<EventType>) => {
commit('addEventType', response.data);
})
.catch(err => {
.catch((err) => {
console.warn(err);
});
},
@ -167,7 +167,7 @@ const actions: ActionTree<ScheduleInterface, StateInterface> = {
.then(() => {
commit('removeEventType', data);
})
.catch(err => {
.catch((err) => {
console.warn(err);
});
},
@ -177,7 +177,7 @@ const actions: ActionTree<ScheduleInterface, StateInterface> = {
.then(() => {
commit('setEventType', eventtype);
})
.catch(err => {
.catch((err) => {
console.warn(err);
});
},
@ -188,7 +188,7 @@ const actions: ActionTree<ScheduleInterface, StateInterface> = {
.then((response: AxiosResponse<Event>) => {
commit('addEvent', response.data);
})
.catch(err => {
.catch((err) => {
console.warn(err);
});
console.log('Events: ', state.events);
@ -206,7 +206,7 @@ const actions: ActionTree<ScheduleInterface, StateInterface> = {
response.data.start = new Date(response.data.start);
commit('updateEvent', response.data);
})
.catch(err => {
.catch((err) => {
console.warn(err);
});
},
@ -215,15 +215,15 @@ const actions: ActionTree<ScheduleInterface, StateInterface> = {
.get('/schedule/events')
.then((response: AxiosResponse<Event[]>) => {
console.log('action:', response.data);
response.data.forEach(event => {
response.data.forEach((event) => {
event.start = new Date(event.start);
});
commit('setEvents', response.data);
})
.catch(err => {
.catch((err) => {
console.warn(err);
});
}
},
};
const getters: GetterTree<ScheduleInterface, StateInterface> = {
jobTypes(state) {
@ -231,7 +231,7 @@ const getters: GetterTree<ScheduleInterface, StateInterface> = {
},
events(state) {
return state.events;
}
},
};
const schedule: Module<ScheduleInterface, StateInterface> = {
@ -239,7 +239,7 @@ const schedule: Module<ScheduleInterface, StateInterface> = {
state,
mutations,
actions,
getters
getters,
};
export default schedule;

View File

@ -1,9 +1,7 @@
<template>
<q-card class="12">
<q-card-section class="fit row justify-start content-center items-center">
<div class="col-xs-12 col-sm-6 text-center text-h6">
Neues Mitglied
</div>
<div class="col-xs-12 col-sm-6 text-center text-h6">Neues Mitglied</div>
</q-card-section>
<q-card-section>
<MainUserSettings :user="user" @update:user="setUser" :new-user="true" />
@ -27,15 +25,15 @@ export default defineComponent({
firstname: '',
lastname: '',
mail: '',
roles: []
roles: [],
});
function setUser(value: FG.User) {
store.dispatch('user/setUser', value).catch(error => {
store.dispatch('user/setUser', value).catch((error) => {
console.warn(error);
});
}
return { user, setUser };
}
},
});
</script>

View File

@ -1,9 +1,7 @@
<template>
<q-card class="col-12">
<q-card-section class="fit row justify-start content-center items-center">
<div class="col-xs-12 col-sm-6 text-center text-h6">
Benutzereinstellungen
</div>
<div class="col-xs-12 col-sm-6 text-center text-h6">Benutzereinstellungen</div>
<div class="col-xs-12 col-sm-6 q-pa-sm">
<UserSelector :user="user" @update:user="userUpdated" />
</div>
@ -33,7 +31,7 @@ export default defineComponent({
};
function updateUser(value: FG.User) {
store.dispatch('user/updateUser', value).catch(error => {
store.dispatch('user/updateUser', value).catch((error) => {
console.warn(error);
});
}
@ -41,9 +39,9 @@ export default defineComponent({
return {
user,
userUpdated,
updateUser
updateUser,
};
}
},
});
</script>

View File

@ -28,7 +28,7 @@ export default defineComponent({
const store = <Store<StateInterface>>root.$store;
onBeforeMount(() => {
store.dispatch('user/getUsers').catch(error => {
store.dispatch('user/getUsers').catch((error) => {
console.error(error);
});
});
@ -40,8 +40,8 @@ export default defineComponent({
return {
updated,
users
users,
};
}
},
});
</script>

View File

@ -1,9 +1,9 @@
<template>
<q-card style="text-align: center;">
<q-card style="text-align: center">
<q-card-section class="row justify-center content-stretch">
<div class="col-4">
<div style="width: 100%; padding-bottom: 100%; position: relative;">
<q-avatar style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;">
<div style="width: 100%; padding-bottom: 100%; position: relative">
<q-avatar style="position: absolute; top: 0; left: 0; width: 100%; height: 100%">
<img :src="avatarLink" />
</q-avatar>
</div>
@ -56,10 +56,10 @@ export default defineComponent({
const birthday = computed(() =>
store.state.user.users
.filter(userHasBirthday)
.filter(user => user.userid !== store.state.user.currentUser?.userid)
.filter((user) => user.userid !== store.state.user.currentUser?.userid)
);
return { avatarLink, name, hasBirthday, birthday };
}
},
});
</script>

View File

@ -124,17 +124,17 @@ export default defineComponent({
components: { IsoDateInput: IsoDateInput },
props: {
user: {
required: true
required: true,
},
newUser: {
default: false
}
default: false,
},
},
setup(props: Props, { root, emit }) {
const store = <Store<StateInterface>>root.$store;
onBeforeMount(() => {
store.dispatch('user/getRoles', false).catch(error => {
store.dispatch('user/getRoles', false).catch((error) => {
console.warn(error);
});
});
@ -148,7 +148,7 @@ export default defineComponent({
const oldUser = computed(() => {
if (isCurrentUser.value) return <FG.User>store.state.user.currentUser;
else
return store.state.user.users.filter(user => {
return store.state.user.users.filter((user) => {
user.userid === props.user?.userid;
})[0];
});
@ -161,12 +161,12 @@ export default defineComponent({
message: 'Datei zu groß oder keine gültige Bilddatei.',
timeout: 10000,
progress: true,
actions: [{ icon: 'mdi-close', color: 'white' }]
actions: [{ icon: 'mdi-close', color: 'white' }],
});
avatar.value = [];
}
const allRoles = computed(() => store.state.user.roles.map(role => role.name));
const allRoles = computed(() => store.state.user.roles.map((role) => role.name));
const password = ref('');
const new_password = ref('');
const new_password2 = ref('');
@ -175,11 +175,11 @@ export default defineComponent({
let changed = <FG.User>props.user;
if (typeof changed.birthday === 'string') changed.birthday = new Date(changed.birthday);
changed = Object.assign(changed, {
password: password.value
password: password.value,
});
if (new_password.value != '') {
changed = Object.assign(changed, {
new_password: new_password.value
new_password: new_password.value,
});
}
@ -189,7 +189,7 @@ export default defineComponent({
store
.dispatch('user/uploadAvatar', {
user: changed,
file: avatar.value
file: avatar.value,
})
.catch((response: Response) => {
if (response && response.status == 400) {
@ -247,8 +247,8 @@ export default defineComponent({
notEmpty,
isUseridUsed,
save,
reset
reset,
};
}
},
});
</script>

View File

@ -3,9 +3,7 @@
<q-card class="col-12">
<q-form @submit="save" @reset="reset">
<q-card-section class="fit row justify-start content-center items-center">
<span class="col-xs-12 col-sm-6 text-center text-h6">
Rollen und Berechtigungen
</span>
<span class="col-xs-12 col-sm-6 text-center text-h6"> Rollen und Berechtigungen </span>
<q-select
filled
use-input
@ -57,10 +55,10 @@ export default defineComponent({
const store = <Store<StateInterface>>root.$store;
onBeforeMount(() => {
store.dispatch('user/getRoles').catch(error => {
store.dispatch('user/getRoles').catch((error) => {
console.warn(error);
});
store.dispatch('user/getPermissions').catch(error => {
store.dispatch('user/getPermissions').catch((error) => {
console.warn(error);
});
});
@ -68,10 +66,10 @@ export default defineComponent({
const role = ref<FG.Role | null>(null);
const roles = computed(() => store.state.user.roles);
const permissions = computed(() =>
store.state.user.permissions.map(perm => {
store.state.user.permissions.map((perm) => {
return {
value: perm,
label: perm
label: perm,
};
})
);
@ -98,7 +96,7 @@ export default defineComponent({
role.value = {
id: rl.id,
name: rl.name,
permissions: Array.from(rl.permissions)
permissions: Array.from(rl.permissions),
};
}
@ -119,7 +117,7 @@ export default defineComponent({
function reset() {
if (role.value && role.value.id !== -1) {
const original = roles.value.find(value => value.name === role.value?.name);
const original = roles.value.find((value) => value.name === role.value?.name);
if (original) updateRole(original);
} else {
role.value = null;
@ -134,7 +132,7 @@ export default defineComponent({
store
.dispatch('user/deleteRole', role.value)
.then(() => (role.value = null))
.catch(error => console.warn(error));
.catch((error) => console.warn(error));
}
}
}
@ -150,8 +148,8 @@ export default defineComponent({
reset,
removeRole,
remove,
newRoleName
newRoleName,
};
}
},
});
</script>

View File

@ -54,8 +54,8 @@ export default defineComponent({
name: 'Sessions',
props: {
session: {
required: true
}
required: true,
},
},
setup(props: { session: FG.Session }, { root }) {
const store = <Store<StateInterface>>root.$store;
@ -87,7 +87,7 @@ export default defineComponent({
}
function deleteSession(token: string) {
store.dispatch('session/deleteSession', token).catch(error => {
store.dispatch('session/deleteSession', token).catch((error) => {
console.warn(error);
});
}
@ -108,7 +108,7 @@ export default defineComponent({
return (lifetime.value / (60 * 60 * 24)).toFixed(2);
}
},
set: val => {
set: (val) => {
if (val) {
switch (option.value) {
case options.value[0]:
@ -122,7 +122,7 @@ export default defineComponent({
break;
}
}
}
},
});
function edit(value: boolean) {
@ -135,7 +135,7 @@ export default defineComponent({
isEdit.value = false;
void store
.dispatch('session/updateSession', { lifetime: lifetime.value, token: props.session.token })
.catch(error => {
.catch((error) => {
console.log(error);
});
}
@ -151,8 +151,8 @@ export default defineComponent({
option,
lifetime,
computedLifetime,
save
save,
};
}
},
});
</script>

View File

@ -27,7 +27,7 @@
<q-page padding class="fit row justify-center content-start items-start q-gutter-sm">
<q-tab-panels
v-model="tab"
style="background-color: transparent;"
style="background-color: transparent"
class="q-ma-none q-pa-none fit row justify-center content-start items-start"
animated
>
@ -72,7 +72,7 @@ export default defineComponent({
const tabs: Tab[] = [
{ name: 'user', label: 'Mitglieder' },
{ name: 'newUser', label: 'Neues Mitglied' },
{ name: 'roles', label: 'Rollen' }
{ name: 'roles', label: 'Rollen' },
];
const drawer = ref<boolean>(false);
@ -83,7 +83,7 @@ export default defineComponent({
},
set: (val: boolean) => {
drawer.value = val;
}
},
});
const tab = ref<string>('user');
@ -92,8 +92,8 @@ export default defineComponent({
canEditRoles,
showDrawer,
tab,
tabs
tabs,
};
}
},
});
</script>

View File

@ -32,6 +32,6 @@ export default defineComponent({
return root.$route.matched.length == 2;
});
return { checkMain, mainRoutes };
}
},
});
</script>

View File

@ -28,7 +28,7 @@ export default defineComponent({
const store = <Store<StateInterface>>root.$store;
onBeforeMount(() => {
store.dispatch('session/getSessions').catch(error => {
store.dispatch('session/getSessions').catch((error) => {
console.warn(error);
});
});
@ -37,7 +37,7 @@ export default defineComponent({
const sessions = computed(() => store.state.session.sessions);
const loading = computed(() => store.state.session.loading || store.state.user.loading > 0);
function updateUser(value: FG.User) {
store.dispatch('user/updateUser', value).catch(error => {
store.dispatch('user/updateUser', value).catch((error) => {
console.warn(error);
});
}
@ -47,8 +47,8 @@ export default defineComponent({
return {
currentUser,
sessions,
updateUser
updateUser,
};
}
},
});
</script>

View File

@ -8,5 +8,5 @@ export const PERMISSIONS = {
// Kann neue Nutzer hinzufügen
REGISTER: 'users_register',
// Kann Rollen löschen oder bearbeiten, z.b. Rechte hinzufügen etc
ROLES_EDIT: 'roles_edit'
ROLES_EDIT: 'roles_edit',
};

View File

@ -16,16 +16,16 @@ const plugin: FG_Plugin.Plugin = {
Module<UserStateInterface, StateInterface> | Module<SessionInterface, StateInterface>
>([
['user', userStore],
['session', sessionsStore]
['session', sessionsStore],
]),
widgets: [
{
priority: 1,
name: 'greeting',
permissions: [],
widget: () => import('./components/Widget.vue')
}
]
widget: () => import('./components/Widget.vue'),
},
],
};
export default plugin;

View File

@ -15,7 +15,7 @@ const mainRoutes: FG_Plugin.PluginRouteConfig[] = [
name: 'user-settings',
shortcut: true,
meta: { permissions: ['user'] },
component: () => import('../pages/Settings.vue')
component: () => import('../pages/Settings.vue'),
},
{
title: 'Admin',
@ -24,10 +24,10 @@ const mainRoutes: FG_Plugin.PluginRouteConfig[] = [
name: 'admin-settings',
shortcut: false,
meta: { permissions: ['users_edit_other'] },
component: () => import('../pages/AdminSettings.vue')
}
]
}
component: () => import('../pages/AdminSettings.vue'),
},
],
},
];
export default mainRoutes;

View File

@ -27,7 +27,7 @@ const state: UserStateInterface = {
permissions: [],
currentUser: loadUserFromLocalStorage(),
currentPermissions: SessionStorage.getItem<FG.Permission[]>('currentPermissions') || [],
loading: 0
loading: 0,
};
const mutations: MutationTree<UserStateInterface> = {
@ -50,7 +50,7 @@ const mutations: MutationTree<UserStateInterface> = {
state.users = data;
},
setUser(state, data: FG.User) {
const index = state.users.findIndex(x => x.userid === data.userid);
const index = state.users.findIndex((x) => x.userid === data.userid);
if (index > -1) state.users[index] = data;
else state.users.push(data);
},
@ -61,7 +61,7 @@ const mutations: MutationTree<UserStateInterface> = {
state.roles.push(data);
},
updateRole(state, data: FG.Role) {
const idx = state.roles.findIndex(role => role.id === data.id);
const idx = state.roles.findIndex((role) => role.id === data.id);
if (idx >= 0) {
state.roles[idx].name = data.name;
state.roles[idx].permissions = data.permissions;
@ -73,7 +73,7 @@ const mutations: MutationTree<UserStateInterface> = {
setLoading(state, data = true) {
if (data) state.loading += 1;
else state.loading -= 1;
}
},
};
const actions: ActionTree<UserStateInterface, StateInterface> = {
@ -86,7 +86,7 @@ const actions: ActionTree<UserStateInterface, StateInterface> = {
commit('setCurrentUser', response.data);
commit('setCurrentPermissions', response.data.permissions);
})
.catch(err => {
.catch((err) => {
console.warn(err);
})
.finally(() => {
@ -102,12 +102,12 @@ const actions: ActionTree<UserStateInterface, StateInterface> = {
axios
.get('/users')
.then((response: AxiosResponse<FG.User[]>) => {
response.data.forEach(user => {
response.data.forEach((user) => {
if (user.birthday) user.birthday = new Date(user.birthday);
});
commit('setUsers', response.data);
})
.catch(err => {
.catch((err) => {
console.warn(err);
})
.finally(() => {
@ -124,7 +124,7 @@ const actions: ActionTree<UserStateInterface, StateInterface> = {
void dispatch('getCurrentUser');
else void dispatch('getUsers');
})
.catch(error => {
.catch((error) => {
console.log(error);
})
.finally(() => {
@ -139,8 +139,8 @@ const actions: ActionTree<UserStateInterface, StateInterface> = {
return axios
.post(`/users/${payload.user.userid}/avatar`, formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
'Content-Type': 'multipart/form-data',
},
})
.catch((error: AxiosError) => {
return Promise.reject(error.response);
@ -159,7 +159,7 @@ const actions: ActionTree<UserStateInterface, StateInterface> = {
void dispatch('getCurrentUser');
else void dispatch('getUsers');
})
.catch(error => {
.catch((error) => {
console.warn(error);
})
.finally(() => {
@ -210,7 +210,7 @@ const actions: ActionTree<UserStateInterface, StateInterface> = {
.then(() => {
commit(
'setRoles',
state.roles.filter(value => value.id !== data.id)
state.roles.filter((value) => value.id !== data.id)
);
})
.finally(() => {
@ -239,12 +239,12 @@ const actions: ActionTree<UserStateInterface, StateInterface> = {
} else {
return Promise.resolve(user);
}
}
},
};
const getters: GetterTree<UserStateInterface, StateInterface> = {
getUser: state => (userid: string) => {
const user = state.users.filter(usr => usr.userid === userid);
getUser: (state) => (userid: string) => {
const user = state.users.filter((usr) => usr.userid === userid);
return user.length > 0 ? user[0] : undefined;
},
currentUser({ currentUser }) {
@ -260,8 +260,8 @@ const getters: GetterTree<UserStateInterface, StateInterface> = {
return currentUser?.display_name;
},
roles({ roles }): string[] {
return roles.map(role => role.name).flat();
}
return roles.map((role) => role.name).flat();
},
};
const userStore: Module<UserStateInterface, StateInterface> = {
@ -269,7 +269,7 @@ const userStore: Module<UserStateInterface, StateInterface> = {
actions,
getters,
mutations,
state
state,
};
export default userStore;

View File

@ -14,10 +14,10 @@ export const Router: VueRouter = new VueRouter({
// quasar.conf.js -> build -> vueRouterMode
// quasar.conf.js -> build -> publicPath
mode: process.env.VUE_ROUTER_MODE,
base: process.env.VUE_ROUTER_BASE
base: process.env.VUE_ROUTER_BASE,
});
export default route<Store<StateInterface>>(function({ Vue }) {
export default route<Store<StateInterface>>(function ({ Vue }) {
Vue.use(VueRouter);
return Router;

View File

@ -9,19 +9,19 @@ const routes: RouteConfig[] = [
{
name: 'login',
path: 'login',
component: () => import('pages/Login.vue')
component: () => import('pages/Login.vue'),
},
{
name: 'password_reset',
path: 'reset',
component: () => import('pages/Reset.vue')
component: () => import('pages/Reset.vue'),
},
{
name: 'about_out',
path: 'about',
component: () => import('pages/about/About.vue')
}
]
component: () => import('pages/about/About.vue'),
},
],
},
{
path: '/main',
@ -33,32 +33,32 @@ const routes: RouteConfig[] = [
name: 'dashboard',
path: 'dashboard',
meta: { permissions: ['user'] },
component: () => import('pages/Dashboard.vue')
component: () => import('pages/Dashboard.vue'),
},
{
name: 'about',
path: 'about',
meta: { permissions: ['user'] },
component: () => import('pages/about/About.vue')
}
]
component: () => import('pages/about/About.vue'),
},
],
},
{
path: '/error',
name: 'error',
component: () => import('pages/PluginError.vue')
component: () => import('pages/PluginError.vue'),
},
{
path: '/offline',
name: 'offline',
component: () => import('pages/Offline.vue')
component: () => import('pages/Offline.vue'),
},
// Always leave this as last one,
// but you can also remove it
{
path: '*',
redirect: 'login'
}
redirect: 'login',
},
];
export default routes;

View File

@ -13,7 +13,7 @@ export interface StateInterface {
[key: string]: any;
}
export default store(function({ Vue }) {
export default store(function ({ Vue }) {
Vue.use(Vuex);
const Store = new Vuex.Store<StateInterface>({
@ -21,7 +21,7 @@ export default store(function({ Vue }) {
// enable strict mode (adds overhead!)
// for dev mode only
strict: !!process.env.DEV
strict: !!process.env.DEV,
});
return Store;

View File

@ -12,7 +12,7 @@ export function formatDateTime(
weekday: useWeekday ? 'long' : undefined,
hour: useTime ? '2-digit' : undefined,
minute: useTime ? '2-digit' : undefined,
second: useTime && useSeconds ? '2-digit' : undefined
second: useTime && useSeconds ? '2-digit' : undefined,
});
return dateTimeFormat.format(date);
}

View File

@ -2,7 +2,7 @@ import { watch, WatchSource } from '@vue/composition-api';
import { LoadingBar } from 'quasar';
function setLoadingBar(loading: WatchSource<boolean>) {
return watch<boolean>(loading, loading => {
return watch<boolean>(loading, (loading) => {
if (loading) LoadingBar.start(10000);
if (!loading) LoadingBar.stop();
});

View File

@ -7,10 +7,10 @@ export function hasPermission(permission: string, store: Store<StateInterface>)
export function hasPermissions(needed: string[], store: Store<StateInterface>) {
const permissions = store.state.user.currentPermissions;
return needed.every(value => permissions.includes(value));
return needed.every((value) => permissions.includes(value));
}
export function hasSomePermissions(needed: string[], store: Store<StateInterface>) {
const permissions = store.state.user.currentPermissions;
return needed.some(value => permissions.includes(value));
return needed.some((value) => permissions.includes(value));
}