Merge branch 'release/1.0'

This commit is contained in:
Tim Gröger 2020-08-06 11:41:28 +02:00
commit aaf2a3ecca
68 changed files with 14158 additions and 2613 deletions

4
.prettierrc.js Normal file
View File

@ -0,0 +1,4 @@
module.exports = {
singleQuote: true,
semi: false
}

21
cert/server.crt Normal file
View File

@ -0,0 +1,21 @@
-----BEGIN CERTIFICATE-----
MIIDazCCAlOgAwIBAgIJAJGH2ozWvd1RMA0GCSqGSIb3DQEBCwUAMFMxCzAJBgNV
BAYTAkRFMQ8wDQYDVQQIDAZTYXhvbnkxEDAOBgNVBAcMB0RyZXNkZW4xITAfBgNV
BAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMDAxMTcwOTA0MDFaFw0z
MDAxMDQwOTA0MDFaMEQxCzAJBgNVBAYTAkRFMQ8wDQYDVQQIDAZTYXhvbnkxEDAO
BgNVBAcMB0RyZXNkZW4xEjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcN
AQEBBQADggEPADCCAQoCggEBALlkr1UOQypLKicESRnse52d5mAX9MjZQpH0/Y5u
V5WxpPSasmOpt4MRj5MWTfTK2ukj/jLtPAMsggUh7wMXb1uytHj7T5mtiahXBM0H
1sUi2nScXR6doQZlmqKWDGrVS7WHULM01WhirsnxI8S8e6Evpk4F5/RafKA8FgYI
Ongg6S1B16+7T0e/FnILoMjKr1jpgzXnVkPFIneu/qVevSNco5/aw+bc6sjeS/ZA
65dXFGpDlw0lPRHLT5/CgNyMyiLYov7KwMycZw7uxa1ynO+73tqe5tvO/DiMpAPJ
EkrSz/StYBsGJxDhwq5RT31tHVtHhTf0rk1BmaoQJ0Aq7iECAwEAAaNRME8wHwYD
VR0jBBgwFoAUt8P5gBfN9hCUAiWhtPH5fTWnctAwCQYDVR0TBAIwADALBgNVHQ8E
BAMCBPAwFAYDVR0RBA0wC4IJbG9jYWxob3N0MA0GCSqGSIb3DQEBCwUAA4IBAQCD
fBByVq8AbV1DMrY+MElb/nZA5/cuGnUpBpjSlk5OnYHWtywuQk6veiiJ0S2fNfqf
RzwOFuZDHKmIcH0574VssLfUynMKP3w3xb2ZNic3AxAdhzZ6LXLx6+qF5tYcL7oC
UWmj5Mo9SkX5HZLEGamQlVyGOGKNatxep4liyoSeKXr0AOHYfB4AkDhVZn7yQc/v
But42fLBg4mE+rk4UBYOHA4XdoFwqgTCNZq2RxKzvG9LIcok6lOc6gDnfTsH8GqE
byGpfIIQAXF8aftCm4dGXxtzMh8C5d0t2Ell9g+Rr8i/enebT2nJ9B9ptldDjhcZ
7I0ywGsXwrh0EwFsX74/
-----END CERTIFICATE-----

28
cert/server.key Normal file
View File

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC5ZK9VDkMqSyon
BEkZ7HudneZgF/TI2UKR9P2ObleVsaT0mrJjqbeDEY+TFk30ytrpI/4y7TwDLIIF
Ie8DF29bsrR4+0+ZrYmoVwTNB9bFItp0nF0enaEGZZqilgxq1Uu1h1CzNNVoYq7J
8SPEvHuhL6ZOBef0WnygPBYGCDp4IOktQdevu09HvxZyC6DIyq9Y6YM151ZDxSJ3
rv6lXr0jXKOf2sPm3OrI3kv2QOuXVxRqQ5cNJT0Ry0+fwoDcjMoi2KL+ysDMnGcO
7sWtcpzvu97anubbzvw4jKQDyRJK0s/0rWAbBicQ4cKuUU99bR1bR4U39K5NQZmq
ECdAKu4hAgMBAAECggEABoMQ3Y34sf2d52zxHGYAGZM4SlvND1kCS5otZdleXjW1
M5pTdci6V3JAdswrxNNzSQkonqVSnFHt5zw/5v3lvXTTfgRl0WIVGcKkuobx9k65
Gat8YdzrkQv0mI1otj/zvtaX8ROEA3yj4xgDR5/PP+QqlUcD1MNw6TfzFhcn5pxB
/RDPmvarMhzMdDW60Uub6Z7e/kVPuXWrW4bDyULd1d1NoSibnFZi+vGY0Lc1ctDW
2Vl7A8RFTcQi6Cjx/FwgPGJTBE4UMjIBO3wnoPQBMrsSxeGhcarerqIlEafgT4XN
p9BMtRyaXE7TTb1BXc35ZYNJLDLJKQxABhrEHtFreQKBgQDpiGwuKAFK8BLPlbAx
zkShhKd9fhlwm2bfRv3cojPQZsxn0BjefmtrISbKCD79Ivyn7TnOyYAoKAxdp2q9
wtz94aAXV2lfhUw2lhcb/aw4sXuY/s1XnVyoglOO8pYRCUN0o80pKuWFsaDyy/uL
LhINff1oMNCa7vmMdu8Ccz0o/wKBgQDLOqdTQhSFs4f1yhlDDH3pqT6eKvtFNeRJ
usxYDnAyRXHRqwhQ86z1nBZIgwXqq7PfO9V5Y/l6/2HmmA2ufjS8aBTNpCUMuvJk
y98Z4hTjKRdnVlMUjHq9ahCixJVQ8pcCnWRFdeAwSKhHQiJEFLYeYOIrUeCIYJI4
FiCshSPI3wKBgGU0ErWZ7p18FprRIs8itYlNhIwUxo+POPCPwloIDO5GblSa0Pwy
yvhdIIMzOaDXtahMXN3pYtmEKX+4msBrnvuC+K7E2cxkZtfNCWy+7RCQkaCG45QR
hOMdv3pWVIRDgHEevz0U8uySQs6VaYgySe6A5/1sEiriX1DpBcEJEbsfAoGAKUCb
rGvSbJ1XsM24OQL1IBQJsON6o77fuxOe3RT5M0sjYnL8OipsZmKrp0ZpUgxOc7ba
i0x+3LewMLWWuV/G5qOd7WwvVRkxkMJNZByfLskthf1g2d/2HjLEc7XBtW+4tYAr
VWoq+sIU3noPKJCnsxzpa++vyx8HLzlWoo5YCDMCgYBJvGH2zMgInlQNO/2XY5nl
E53EZMex+RDq8Wzr4tRM3IrCGc2t8WKEQ/9teKNH0tg9xib0vhqqmiGl1xNfqJVo
ePJyfgFabeUx9goG3mgTdV9woSRlBJso62dM0DAC/jsJoHnVzgokysR4/BfW9Da+
AYTxRZSNbfmsTHawXqG8Fw==
-----END PRIVATE KEY-----

4784
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -8,28 +8,33 @@
"lint": "vue-cli-service lint"
},
"dependencies": {
"core-js": "^3.4.3",
"@mdi/font": "^4.9.95",
"@mdi/js": "^4.9.95",
"core-js": "^3.6.5",
"vue": "^2.6.10",
"vue-router": "^3.1.3",
"vuetify": "^2.1.0",
"vuex": "^3.1.2"
"vue-router": "^3.2.0",
"vuetify": "^2.2.29",
"vuex": "^3.4.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "^4.1.0",
"@vue/cli-plugin-eslint": "^4.1.0",
"@vue/cli-plugin-router": "^4.1.1",
"@vue/cli-plugin-vuex": "^4.1.1",
"@vue/cli-service": "^4.1.0",
"axios": "^0.19.0",
"babel-eslint": "^10.0.3",
"@vue/cli-plugin-babel": "^4.3.1",
"@vue/cli-plugin-eslint": "^4.3.1",
"@vue/cli-plugin-router": "^4.3.1",
"@vue/cli-plugin-vuex": "^4.3.1",
"@vue/cli-service": "^4.3.1",
"@vue/eslint-config-prettier": "^6.0.0",
"axios": "^0.19.2",
"babel-eslint": "^10.1.0",
"eslint": "^5.16.0",
"eslint-plugin-prettier": "^3.1.3",
"eslint-plugin-vue": "^5.0.0",
"material-design-icons-iconfont": "^5.0.1",
"sass": "^1.19.0",
"sass-loader": "^8.0.0",
"vue-cli-plugin-vuetify": "^2.0.2",
"prettier": "^1.19.1",
"sass": "^1.26.5",
"sass-loader": "^8.0.2",
"vue-cli-plugin-vuetify": "^2.0.5",
"vue-template-compiler": "^2.6.10",
"vuetify-loader": "^1.3.0"
"vuetify-loader": "^1.4.4"
},
"eslintConfig": {
"root": true,
@ -38,9 +43,13 @@
},
"extends": [
"plugin:vue/essential",
"plugin:prettier/recommended",
"@vue/prettier",
"eslint:recommended"
],
"rules": {},
"rules": {
"no-console": "off"
},
"parserOptions": {
"parser": "babel-eslint"
}

View File

@ -1,11 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<html lang="de">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title>newgruecht-vue</title>
<link rel="icon" href="<%= BASE_URL %>wuicon.ico">
<title>Flaschengeist</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@mdi/font@latest/css/materialdesignicons.min.css">
</head>

BIN
public/wuicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -1,19 +1,232 @@
<template>
<v-app>
<router-view/>
<TitleBar />
<router-view />
<v-footer app>
<span class="px-4 d-none d-sm-flex"
>&copy; {{ new Date().getFullYear() }}
<v-btn x-small text class="text-none subtitle-1" href="https://wu5.de">
Studentenclub Wu5 e.V.
</v-btn>
</span>
<span>
<v-btn text x-small href="https://wu5.de/impressum">
Impressum
</v-btn>
<v-btn text x-small href="https://wu5.de/datenschutz">
Datenschutzerklärung
</v-btn>
<v-btn
text
x-small
v-if="isLoggedIn"
href="https://groeger-clan.duckdns.org/redmine/projects/geruecht/issues/new"
>
Bugs?
</v-btn>
</span>
<v-spacer />
<div v-if="isLoggedIn && !change" :key="render">
<v-hover
v-slot:default="{ hover }"
open-delay="200"
close-delay="200"
class="d-none d-sm-flex"
>
<v-sheet
:elevation="hover ? 16 : 0"
color="#f5f5f5"
@click="change = !change"
>{{ calcTime }}</v-sheet
>
</v-hover>
<v-hover
v-slot:default="{ hover }"
open-delay="200"
close-delay="200"
class="d-flex d-sm-none"
>
<v-sheet
:elevation="hover ? 16 : 0"
color="#f5f5f5"
@click="change = !change"
>{{ calcTimeLittle }}</v-sheet
>
</v-hover>
</div>
<v-dialog v-model="change" max-width="300">
<v-card>
<v-card-title>
Zeit bis zum Logout ändern
</v-card-title>
<v-card-text>
<v-combobox
solo
:items="lifeTimes"
item-text="text"
item-value="value"
v-model="selectLifeTime"
return-object
/>
</v-card-text>
<v-card-actions>
<v-spacer />
<v-btn text @click="change = false">Abbrechen</v-btn>
<v-btn color="primary" text @click="save()">Speichern</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</v-footer>
</v-app>
</template>
<script>
import TitleBar from './components/TitleBar'
import { mapGetters, mapActions } from 'vuex'
export default {
name: 'App',
components: {
},
components: { TitleBar },
data: () => ({
//
render: 0,
timer: null,
change: false,
selectLifeTime: { text: '30 Minuten', value: 1800 },
lifeTimes: [
{
text: '5 Minuten',
value: 300
},
{
text: '10 Minuten',
value: 600
},
{
text: '15 Minuten',
value: 900
},
{
text: '30 Minuten',
value: 1800
},
{
text: '1 Stunde',
value: 3600
},
{
text: '2 Stunden',
value: 7200
},
{
text: '3 Stunden',
value: 10800
},
{
text: '1 Tag',
value: 86400
},
{
text: '2 Tage',
value: 172800
},
{
text: '1 Woche',
value: 604800
},
{
text: '1 Monat',
value: 2678400
}
]
}),
};
created() {
if (this.isLoggedIn) {
this.getLifeTime()
}
this.timer = setInterval(this.test, 1000)
},
methods: {
...mapActions(['setLifeTime', 'saveLifeTime', 'logout', 'getLifeTime']),
test() {
if (this.isLoggedIn) {
if (this.lifeTime == 0) this.logout()
this.setLifeTime(this.lifeTime - 1)
}
},
save() {
this.saveLifeTime(this.selectLifeTime.value)
this.change = false
}
},
computed: {
...mapGetters(['isLoggedIn', 'lifeTime', 'getMinute', 'getSeconds']),
calcTime() {
var minutes = this.lifeTime / 60
var seconds = this.lifeTime % 60
var minutesString =
minutes < 10 ? '0' + Math.floor(minutes % 60) : Math.floor(minutes % 60)
var secondsString =
seconds < 10 ? '0' + Math.floor(seconds) : Math.floor(seconds)
if (minutes > 60) {
var hours = minutes / 60
if (hours > 24) {
var days = hours / 24
var now = new Date()
var dayMonth = new Date(
now.getFullYear(),
now.getMonth() + 1,
0
).getDate()
if (days >= dayMonth) {
return Math.floor(days / dayMonth) + ' Monate bis zum Logout'
} else {
return Math.floor(days) + ' Tage bis zum Logout'
}
} else {
return (
Math.floor(hours) +
':' +
minutesString +
':' +
secondsString +
' Stunden bis zum Logout'
)
}
} else {
return minutesString + ':' + secondsString + ' Minuten bis zum Logout'
}
},
calcTimeLittle() {
var minutes = this.lifeTime / 60
var seconds = this.lifeTime % 60
var minutesString =
minutes < 10 ? '0' + Math.floor(minutes % 60) : Math.floor(minutes % 60)
var secondsString =
seconds < 10 ? '0' + Math.floor(seconds) : Math.floor(seconds)
if (minutes > 60) {
var hours = minutes / 60
if (hours > 24) {
var days = hours / 24
var now = new Date()
var dayMonth = new Date(
now.getFullYear(),
now.getMonth() + 1,
0
).getDate()
if (days >= dayMonth) {
return Math.floor(days / dayMonth) + 'M'
} else {
return Math.floor(days) + 'D'
}
} else {
return Math.floor(hours) + ':' + minutesString + ':' + secondsString
}
} else {
return minutesString + ':' + secondsString
}
}
},
beforeDestroy() {
clearInterval(this.timer)
}
}
</script>

BIN
src/assets/logo-64.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@ -0,0 +1,40 @@
<template>
<div>
<v-snackbar :timeout="0" color="error" :value="visible" top>
<v-list color="error" dense>
<v-list-item v-for="(error, index) in errors" :key="index" dense>
<v-list-item-title class="caption" style="color: white;">
{{error.message}}
</v-list-item-title>
</v-list-item>
</v-list>
<v-btn icon color="white" @click="deleteErrors">
<v-icon>
mdi-close
</v-icon>
</v-btn>
</v-snackbar>
</div>
</template>
<script>
import { mapGetters, mapActions } from 'vuex'
export default {
name: "ConnectionError",
methods: {
...mapActions({
deleteErrors: 'connectionError/deleteErrors'
})
},
computed: {
...mapGetters({
errors: 'connectionError/errors',
visible: 'connectionError/visible'
})
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,48 @@
<template>
<v-bottom-sheet persistent v-model="show" hide-overlay>
<v-card>
<v-card-title>
Cookie und Local Storage Hinweis
</v-card-title>
<v-card-text>
Diese Webseite benutzt den Local Storage. Dabei werden Daten in ihm
gespeichert, welche notwendig sind um sich einzuloggen und eingeloggt zu
bleiben. Außerdem sind diese Daten notwendig um mit dem Server zu
kommunizieren. Dabei wird ein Key 'user' angelegt, in welchem ein
Accesstoken, Benutzername, sowie der Name des Benutzers und deren Rechte
gespeichert. Dazu kommt ein Key 'cookie:accepted', falls sie diesem
zustimmen. Diese Daten bleiben solange erhalten bis Sie sich ausloggen
oder der Accesstoken abgelaufen ist und Sie ausgeloggt werden.
</v-card-text>
<v-card-actions>
<v-spacer />
<v-btn text @click="disableNotification()">Ablehnen</v-btn>
<v-btn text color="primary" @click="acceptNotification()">Akzeptieren</v-btn>
</v-card-actions>
</v-card>
</v-bottom-sheet>
</template>
<script>
import { mapGetters, mapActions } from 'vuex'
export default {
name: 'CookieNotification',
methods: {
...mapActions(['acceptNotification', 'disableNotification', 'getCookieAccepted'])
},
created() {
this.getCookieAccepted()
},
computed: {
...mapGetters({
model: 'cookieNotification',
cookie: 'cookieAccepted'
}),
show() {
return !this.cookie ? this.model : false
}
}
}
</script>
<style scoped></style>

View File

@ -0,0 +1,146 @@
<template>
<v-content>
<v-container class="fill-height" fluid>
<v-row align="center" justify="center">
<v-col cols="12" sm="8" md="4">
<v-card class="elevation-12">
<v-toolbar color="blue accent-4" dark flat dense>
<v-toolbar-title>Password vergessen</v-toolbar-title>
<v-spacer />
</v-toolbar>
<v-card-text>
<v-form lazy-validation ref="reset">
<v-text-field
label="E-Mail oder Nutzername"
v-model="input"
hint="Hier bitte deinen Nutzernamen oder deine E-Mail angeben. Sollte eins der beiden Daten gefunden werden, wird an deine hinterlegte E-Mail ein Password zum Zurücksetzen gesendet."
persistent-hint
:prepend-icon="prependIcon"
required
:rules="[notEmpty, isMail ? email : true]"
@keyup.enter="resetPassword()"
>
</v-text-field>
</v-form>
</v-card-text>
<v-card-actions>
<v-spacer />
<v-btn
color="primary"
@click="resetPassword()"
@submit.prevent="resetPassword()"
>
Zurücksetzen
</v-btn>
</v-card-actions>
</v-card>
</v-col>
</v-row>
</v-container>
<v-snackbar bottom :timeout="0" :value="response.value" :color="response.error? 'error' : 'success'">
{{ response.message }}
<v-btn icon @click="response.value = false">
<v-icon color="white">
mdi-close
</v-icon>
</v-btn>
</v-snackbar>
</v-content>
</template>
<script>
import axios from 'axios'
import url from '@/plugins/routes'
export default {
name: 'ResetPassword',
data() {
return {
input: '',
response: {
error: false,
value: false,
message: null
},
defaultResponse: {
error: false,
value: false,
message: null
},
notEmpty: data => {
return data ? true : 'Darf nicht leer sein.'
},
email: value => {
if (value.length > 0) {
const pattern = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
return pattern.test(value) || 'keine gültige E-Mail'
}
return true
}
}
},
methods: {
resetPassword() {
if (this.$refs.reset.validate()) {
console.log(this.input, this.isMail)
if (this.isMail) {
axios
.post(url.resetPassword, { mail: this.input })
.then(data => {
console.log(data)
this.setMessage(data.data.mail, false)
})
.catch(error => {
console.log(error)
this.setMessage(error, true)
})
.finally(() => {
this.$refs.reset.reset()
})
} else {
axios
.post(url.resetPassword, { username: this.input })
.then(data => {
console.log(data)
this.setMessage(data.data.mail, false)
})
.catch(error => {
console.log(error)
this.setMessage(error, true)
})
.finally(() => {
this.$refs.reset.reset()
})
}
}
},
setMessage(mail, error) {
if (error) {
this.response.error = true
this.response.value = true
this.response.message =
'Es ist ein Fehler aufgetreten. Wende dich an einen Administrator oder probiere es erneut.'
} else {
this.response.error = false
this.response.value = true
this.response.message = `Es wurde ein neues Password an ${mail} versendet`
}
}
},
computed: {
prependIcon() {
if (this.input) {
return this.input.includes('@') ? 'mdi-email' : 'mdi-account'
}
return 'mdi-account'
},
isMail() {
if (this.input) {
return this.input.includes('@')
}
return false
}
}
}
</script>
<style scoped></style>

View File

@ -1,46 +1,94 @@
<template>
<div>
<v-app-bar
app
flat
clipped-left
absolute
clipped-right
color="blue accent-4"
class="elevation-4"
dark>
<v-btn icon>
<v-img src="@/assets/logo-big.png" contain height="40"></v-img>
</v-btn>
<v-toolbar-title>WU5-Dashboard</v-toolbar-title>
<v-spacer/>
<v-btn icon v-if="isFinanzer">
<v-icon>local_bar</v-icon>
</v-btn>
<v-btn v-if="isLoggedIn" @click="logout">Logout</v-btn>
dark
dense
>
<v-btn icon @click="reload()">
<v-img src="@/assets/logo-64.png" contain height="40"></v-img>
</v-btn>
<v-toolbar-title>Flaschengeist</v-toolbar-title>
<v-spacer/>
<v-btn icon v-if="getRouteName == 'resetPassword'" @click="goTo('login')">
<v-icon>
mdi-home
</v-icon>
</v-btn>
<v-btn icon v-if="getRouteName == 'priceListNoLogin'" @click="goBack()">
<v-icon>
{{ back }}
</v-icon>
</v-btn>
<v-btn icon v-if="isFinanzer" :disabled="locked" @click="goTo('overview')">
<v-icon>{{ attach_money }}</v-icon>
</v-btn>
<v-btn icon v-if="isGastro" :disabled="locked" @click="goTo('gastroPricelist')">
<v-icon>{{ gastro }}</v-icon>
</v-btn>
<v-btn icon v-if="isBar" @click="goTo('geruecht')">
<v-icon>{{ local_bar }}</v-icon>
</v-btn>
<v-btn icon v-if="isUser" :disabled="locked" @click="goTo('add')">
<v-icon>{{ person }}</v-icon>
</v-btn>
<v-btn icon @click="goTo('priceListNoLogin')">
<v-icon>{{ list }}</v-icon>
</v-btn>
</v-app-bar>
<ConnectionError/>
</div>
</template>
<script>
import {mapActions} from "vuex";
import { mapActions, mapGetters } from 'vuex'
import {
mdiCurrencyEur,
mdiGlassCocktail,
mdiAccount,
mdiFileMultiple,
mdiFoodForkDrink,
mdiArrowLeftBoldCircle
} from '@mdi/js'
import ConnectionError from "@/components/ConnectionError";
export default {
name: "TitleBar",
computed: {
isFinanzer() {
return this.$store.getters.getGroup === 'moneymaster' ? true : false
},
isLoggedIn() {
return this.$store.getters.getToken
}
},
methods: {
...mapActions([
'logout'
])
}
export default {
name: 'TitleBar',
components: {ConnectionError},
data() {
return {
attach_money: mdiCurrencyEur,
local_bar: mdiGlassCocktail,
person: mdiAccount,
list: mdiFileMultiple,
gastro: mdiFoodForkDrink,
back: mdiArrowLeftBoldCircle
}
},
computed: {
...mapGetters(['isBar', 'isFinanzer', 'isUser', 'isLoggedIn', 'isGastro']),
...mapGetters({locked: 'barUsers/locked'}),
getRouteName() {
return this.$route.name
}
},
methods: {
...mapActions(['logout']),
reload() {
location.reload()
},
goTo(name) {
this.$router.push({name: name})
},
goBack() {
window.history.length > 1 ? this.$router.go(-1) : this.$router.push({name: 'main'})
},
}
}
</script>
<style scoped>
</style>
<style scoped></style>

View File

@ -0,0 +1,26 @@
<template>
<v-list>
<v-list-item link :to="{name: 'geruecht'}">
<v-list-item-icon>
<v-icon>{{ glass_mug_variant }}</v-icon>
</v-list-item-icon>
<v-list-item-title>
Geruecht
</v-list-item-title>
</v-list-item>
</v-list>
</template>
<script>
import { mdiGlassMugVariant } from '@mdi/js'
export default {
name: 'BarNavigation',
data() {
return {
glass_mug_variant: mdiGlassMugVariant
}
}
}
</script>
<style scoped></style>

View File

@ -1,58 +1,594 @@
<template>
<v-content>
<div>
<v-dialog v-model="checkValidate" max-width="290">
<v-card>
<v-card-title>
Willst du wirklich??
</v-card-title>
<v-card-text v-if="stornoMessage">
Willst du wirklich den Betrag
{{ (stornoMessage.amount / 100).toFixed(2) }} von
{{ stornoMessage.user.firstname }}
{{ stornoMessage.user.lastname }} stornieren?
</v-card-text>
<v-card-actions>
<v-spacer />
<v-btn text @click="cancelStorno">Abbrechen</v-btn>
<v-btn text @click="acceptStorno">Stornieren</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<v-dialog v-model="dialog" max-width="290">
<v-card>
<v-card-title class="headline"
>Transaktion ist länger als 1 Minute her!</v-card-title
>
<v-card-text>
Da die Transaktion länger als 1 Minuter her ist, kann eine Stornierung
nicht durchgeführt werden. Wende dich bitte an den Finanzer.
</v-card-text>
<v-card-actions>
<v-spacer />
<v-btn text @click="dialog = false">
Verstanden
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<v-dialog
v-if="overLimitUser"
v-model="overLimitUser"
max-width="290"
persistent
>
<v-card>
<v-card-title>Warnung</v-card-title>
<v-card-text>
{{ overLimitUser.firstname }} {{ overLimitUser.lastname }} übersteigt
das Anschreibelimit von
{{ (overLimitUser.limit / 100).toFixed(2) }} . Danach kann dieses
Mitglied nichts mehr anschreiben. Will er das wirklich?
</v-card-text>
<v-card-actions>
<v-spacer />
<v-btn text @click="cancel()">Abbrechen</v-btn>
<v-btn text @click="continueAdd(overLimitUser)">Anschreiben</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<v-dialog
v-if="overOverLimit"
v-model="overOverLimit"
max-width="290"
persistent
>
<v-card>
<v-card-title>Anschreiben nicht möglich</v-card-title>
<v-card-text>
{{ overOverLimit.firstname }}
{{ overOverLimit.lastname }} überschreitet das Anschreibelimit zuviel.
Das Anschreiben wurde daher gestoppt und zurückgesetzt.
</v-card-text>
<v-card-actions>
<v-btn text @click="overOverLimit = null">Verstanden</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<v-progress-linear v-if="loading && users.length !== 0" indeterminate />
<v-container>
<AddAmountSkeleton v-if="loading && users.length === 0" />
</v-container>
<v-navigation-drawer v-model="menu" right app clipped>
<v-list-item-group :key="componentRenderer">
<v-list-item inactive>
<v-list-item-title class="headline">
Verlauf
</v-list-item-title>
</v-list-item>
<v-divider />
<div
v-for="message in messages"
three-line
:key="messages.indexOf(message)"
>
<v-list-item three-line inactive @click="storno(message)">
<v-list-item-content>
<v-progress-linear indeterminate v-if="message.loading" />
<v-list-item-title>{{ now(message.date) }}</v-list-item-title>
<v-list-item-subtitle>{{
createMessage(message)
}}</v-list-item-subtitle>
<v-list-item-subtitle class="red--text" v-if="message.storno">
STORNIERT!!!
</v-list-item-subtitle>
<v-list-item-subtitle class="red--text" v-else-if="message.error">
ERROR!
</v-list-item-subtitle>
<v-list-item-action-text v-if="under5minutes(message.date)"
>Klicken um zu Stornieren
</v-list-item-action-text>
</v-list-item-content>
</v-list-item>
</div>
</v-list-item-group>
</v-navigation-drawer>
<div v-for="user in users" :key="users.indexOf(user)">
<div v-if="isFiltered(user) && calcLastSeen(user)">
<v-container>
<v-card raised shaped>
<v-container>
<v-row>
<v-col align-self="center">
<v-container>
<v-btn>Col 1</v-btn>
</v-container>
</v-col>
<v-row>
<v-col>
<v-row>
<v-container>
<v-btn>Col 2.1.1</v-btn>
</v-container>
</v-row>
<v-row>
<v-container>
<v-btn>Col 2.1.2</v-btn>
</v-container>
</v-row>
<v-card :loading="user.loading">
<v-card-title>
<v-list-item-title class="title"
>{{ user.firstname }} {{ user.lastname }}</v-list-item-title
>
</v-card-title>
<v-card-subtitle v-if="user.limit + user.amount > 0">
Nur noch {{ ((user.limit + user.amount) / 100).toFixed(2) }}
übrig!!
</v-card-subtitle>
<v-card-text>
<v-row v-if="!user.locked">
<v-col cols="10">
<v-row>
<v-col cols="6" xs="5" sm="4">
<v-btn
class="creditBtn"
block
@click="addingAmount(user, 200)"
:color="color"
:disabled="user.locked"
>2
</v-btn>
</v-col>
<v-col cols="6" xs="5" sm="4">
<v-btn
class="creditBtn"
block
@click="addingAmount(user, 100)"
:color="color"
:disabled="user.locked"
>1
</v-btn>
</v-col>
<v-col cols="6" xs="5" sm="4">
<v-btn
class="creditBtn"
block
@click="addingAmount(user, 50)"
:color="color"
:disabled="user.locked"
>0,50
</v-btn>
</v-col>
<v-col cols="6" xs="5" sm="4">
<v-btn
class="creditBtn"
block
@click="addingAmount(user, 40)"
:color="color"
:disabled="user.locked"
>0,40
</v-btn>
</v-col>
<v-col cols="6" xs="5" sm="4">
<v-btn
class="creditBtn"
block
@click="addingAmount(user, 20)"
:color="color"
:disabled="user.locked"
>0,20
</v-btn>
</v-col>
<v-col cols="6" xs="5" sm="4">
<v-btn
class="creditBtn"
block
@click="addingAmount(user, 10)"
:color="color"
:disabled="user.locked"
>0,10
</v-btn>
</v-col>
<v-col cols="8">
<v-text-field
outlined
type="number"
v-model="user.value"
label="Benutzerdefinierter Betrag"
:disabled="user.locked"
></v-text-field>
</v-col>
<v-col cols="4">
<v-btn
fab
:color="color"
@click="addAmountMore(user)"
:disabled="user.locked"
>
<v-icon>{{ plus }}</v-icon>
</v-btn>
</v-col>
</v-row>
</v-col>
<v-col>
<v-row>
<v-btn>Col 2.2.1</v-btn>
</v-row>
<v-row>
<v-btn>Col 2.2.2</v-btn>
</v-row>
<v-col align-self="center">
<v-row>
<v-list-item>
<v-list-item-content class="text-center">
<v-list-item-action-text :class="getColor(user.type)"
>{{ (user.amount / 100).toFixed(2) }}
</v-list-item-action-text>
<v-list-item-action-text v-if="user.toSetAmount">
- {{ (user.toSetAmount / 100).toFixed(2) }}
</v-list-item-action-text>
</v-list-item-content>
</v-list-item>
</v-row>
</v-col>
<v-col>
<v-row>
<v-btn>Col 2.3.1</v-btn>
</v-row>
<v-row>
<v-btn>Col 2.3.2</v-btn>
</v-row>
</v-row>
<v-row>
<v-col class="hidden-sm-and-down" cols="80">
<v-alert v-if="user.locked" type="error"
>{{ user.firstname }} darf nicht mehr anschreiben.
{{ user.firstname }} sollte sich lieber mal beim Finanzer
melden.
</v-alert>
</v-col>
</v-row>
<v-col><v-btn>Col 3</v-btn></v-col>
</v-row>
</v-container>
</v-card>
<v-col align-self="center" v-if="user.locked">
<v-row>
<v-list-item>
<v-list-item-content class="text-center">
<v-list-item-action-text :class="getColor(user.type)"
>{{ (user.amount / 100).toFixed(2) }}
</v-list-item-action-text>
</v-list-item-content>
</v-list-item>
</v-row>
</v-col>
</v-row>
</v-card-text>
</v-card>
<v-snackbar
:color="
messages.length > 0
? messages[0].error
? 'error'
: 'success'
: 'success'
"
bottom
:timeout="0"
:multi-line="true"
:value="messages.length > 0 ? messages[0].visible : test"
vertical
>
<v-list-item
v-for="message in messages"
:key="messages.indexOf(message)"
:style="
message.error
? 'background-color: #FF5252;'
: 'background-color: #4CAF50;'
"
v-show="message.visible"
>
<v-list-item-content>
<v-list-item-title style="color: white">
{{ createMessage(message) }}
</v-list-item-title>
</v-list-item-content>
<v-list-item-action v-if="message.error">
<v-btn icon @click="message.visible = false">
<v-icon color="white">
mdi-close
</v-icon>
</v-btn>
</v-list-item-action>
</v-list-item>
</v-snackbar>
</v-container>
</v-content>
</div>
</div>
</div>
</template>
<script>
export default {
name: "CreditLists"
import { mapGetters, mapActions } from 'vuex'
import { mdiPlus } from '@mdi/js'
import AddAmountSkeleton from '../user/Skeleton/AddAmountSkeleton'
export default {
name: 'CreditLists',
components: { AddAmountSkeleton },
props: {},
data() {
return {
plus: mdiPlus,
value: null,
color: 'green accent-4',
menu: true,
dialog: false,
componentRenderer: 0,
timer: '',
stornoMessage: null,
checkValidate: false,
test: null,
overLimitUser: null,
overOverLimit: null
}
},
created() {
this.menu = this.menu_from_store
this.getUsers()
this.timer = setInterval(this.forceRender, 1000)
},
methods: {
...mapActions({
addAmount: 'barUsers/addAmount',
getUsers: 'barUsers/getUsers',
deactivate: 'barUsers/deactivateMenu',
commitStorno: 'barUsers/storno'
}),
continueAdd(user) {
this.overLimitUser = null
user.checkedOverLimit = true
if (user.value) {
this.addAmount({
username: user.username,
amount: Math.round(Math.abs(user.value * 100)),
user: user
})
setTimeout(() => {
user.value = null
user.toSetAmount = null
}, 300)
} else {
user.timeout = setTimeout(() => {
this.addAmount({
username: user.username,
amount: user.toSetAmount,
user: user
})
setTimeout(() => {
user.toSetAmount = null
}, 300)
}, 2000)
}
},
cancel() {
this.overLimitUser.toSetAmount = null
this.overLimitUser.value = null
this.overLimitUser = null
},
checkOverLimitIsValid(user) {
console.log(user)
if (user.toSetAmount && user.autoLock) {
if (
Math.abs(user.amount - Number.parseInt(user.toSetAmount)) >
user.limit + 500
) {
this.overOverLimit = user
user.toSetAmount = null
user.value = null
return false
}
}
return true
},
checkOverLimit(user) {
if (user.toSetAmount) {
if (Math.abs(user.amount - user.toSetAmount) > user.limit) {
return user.checkedOverLimit ? false : true
}
}
return false
},
addingAmount(user, amount) {
clearTimeout(user.timeout)
user.toSetAmount = user.toSetAmount ? user.toSetAmount + amount : amount
if (this.checkOverLimitIsValid(user)) {
if (this.checkOverLimit(user) && user.autoLock) {
this.overLimitUser = user
} else {
user.timeout = setTimeout(() => {
this.addAmount({
username: user.username,
amount: user.toSetAmount,
user: user
})
setTimeout(() => {
user.toSetAmount = null
}, 300)
}, 2000)
}
}
},
forceRender() {
this.componentRenderer += 1
},
getColor(type) {
return type === 'credit' ? 'title green--text' : 'title red--text'
},
isFiltered(user) {
try {
var filters = this.filter.split(' ')
if (filters.length === 1) {
if (
user.firstname.toLowerCase().includes(filters[0].toLowerCase()) ||
user.lastname.toLowerCase().includes(filters[0].toLowerCase())
) {
return true
}
} else if (filters.length > 1) {
if (
user.firstname.toLowerCase().includes(filters[0].toLowerCase()) &&
user.lastname.toLowerCase().includes(filters[1].toLowerCase())
) {
return true
}
}
return false
} catch (e) {
return true
}
},
addAmountMore(user) {
user.toSetAmount = user.toSetAmount
? user.toSetAmount + Math.round(Math.abs(user.value * 100))
: Math.round(Math.abs(user.value * 100))
if (this.checkOverLimitIsValid(user)) {
if (this.checkOverLimit(user) && user.autoLock) {
this.overLimitUser = user
} else {
this.addAmount({
username: user.username,
amount: Math.round(Math.abs(user.value * 100)),
user: user
})
setTimeout(() => {
user.value = null
user.toSetAmount = null
}, 300)
}
}
},
storno(message) {
if (!message.error) {
if (!this.under5minutes(message.date)) this.dialog = true
else {
this.checkValidate = true
this.stornoMessage = message
}
}
},
acceptStorno() {
this.commitStorno({
username: this.stornoMessage.user.username,
amount: this.stornoMessage.amount,
date: this.stornoMessage.date
})
setTimeout(() => {
this.cancelStorno()
}, 300)
},
cancelStorno() {
this.stornoMessage = null
this.checkValidate = null
},
createMessage(message) {
var text = ''
if (message.error) {
text =
'ERROR: Konnte ' +
(message.amount / 100).toFixed(2) +
'€ nicht zu ' +
message.user.firstname +
' ' +
message.user.lastname +
' hinzufügen.'
} else {
text =
'' +
(message.amount / 100).toFixed(2) +
'€ wurde zu ' +
message.user.firstname +
' ' +
message.user.lastname +
' hinzugefügt.'
}
return text
},
calcLastSeen(user) {
if (user.last_seen) {
let date = new Date()
if ((date - user.last_seen) / 1000 / 60 / 60 < 72) {
return true
}
}
return false
}
},
computed: {
...mapGetters({
users: 'barUsers/users',
filter: 'barUsers/filter',
loading: 'barUsers/usersLoading',
messages: 'barUsers/messages',
menu_from_store: 'barUsers/menu'
}),
under5minutes() {
return now => {
var actual = new Date()
return actual - now < 60000
}
},
now() {
return now => {
var actual = new Date()
var zero = new Date(0)
var date = new Date(actual - now)
if (date.getFullYear() === zero.getFullYear()) {
if (date.getMonth() === zero.getMonth()) {
if (date.getDate() === zero.getDate()) {
if (date.getHours() === zero.getDate()) {
if (date.getMinutes() < 1) {
return 'vor ' + date.getSeconds() + ' Sekunden'
} else if (date.getMinutes() < 10) {
return 'vor ' + date.getMinutes() + ' Minuten'
} else {
return (
(now.getHours() < 10 ? '0' : '') +
now.getHours() +
':' +
(now.getMinutes() < 10 ? '0' : '') +
now.getMinutes()
)
}
} else {
return (
(now.getHours() < 10 ? '0' : '') +
now.getHours() +
':' +
(now.getMinutes() < 10 ? '0' : '') +
now.getMinutes()
)
}
}
}
}
return (
now.getDate() +
'.' +
now.getMonth() +
'.' +
now.getFullYear() +
' ' +
(now.getHours() < 10 ? '0' : '') +
now.getHours() +
':' +
(now.getMinutes() < 10 ? '0' : '') +
now.getMinutes()
)
}
}
},
watch: {
menu(newValue) {
if (!newValue) this.deactivate()
},
menu_from_store() {
this.menu = this.menu_from_store
}
},
beforeDestroy() {
clearInterval(this.timer)
}
}
</script>
<style scoped>
.creditBtn {
margin: 2px;
}
</style>

View File

@ -0,0 +1,132 @@
<template>
<div>
<v-toolbar>
<v-spacer />
<v-toolbar-items>
<v-autocomplete
outlined
return-object
v-model="user"
style="margin-top: 3px"
placeholder="Suche Person"
:items="allUsers"
item-text="fullName"
full-width
:loading="loading"
:search-input.sync="filter"
clearable
>
<template v-slot:prepend-inner>
<v-icon>{{ search_person }}</v-icon>
</template>
<template v-slot:item="data">
<v-list-item-icon v-if="getLocked(data.item)">
<v-icon>mdi-alert</v-icon>
</v-list-item-icon>
<v-list-item-content>
{{data.item.fullName}}
<v-spacer/>
{{(getCredit(data.item)/100).toFixed(2)}}
</v-list-item-content>
</template>
</v-autocomplete>
<v-btn text @click="addUser">Hinzufügen</v-btn>
<v-btn v-if="!locked" text @click="lock">Sperren</v-btn>
<v-btn v-else text @click="overlay = true">Entsperren</v-btn>
<v-btn @click="clickMenu" icon>
<v-icon>{{ menuIcon }}</v-icon>
</v-btn>
</v-toolbar-items>
</v-toolbar>
<v-dialog v-model="overlay">
<v-card>
<v-card-title>Entsperre Baransicht</v-card-title>
<v-card-text>
<v-text-field outlined type="password" label="Passwort" v-model="password"></v-text-field>
</v-card-text>
<v-card-actions>
<v-spacer/>
<v-btn text @click="overlay = false">Abbrechen</v-btn>
<v-btn text @click="doUnlock">Entsperren</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</div>
</template>
<script>
import { mapGetters, mapActions } from 'vuex'
import { mdiAccountSearch, mdiMenu, mdiAlert } from '@mdi/js'
export default {
name: 'SearchBar',
props: {},
data() {
return {
user: null,
filter: '',
search_person: mdiAccountSearch,
menuIcon: mdiMenu,
alert: mdiAlert,
overlay: false,
password: ''
}
},
created() {
this.getAllUsers()
this.getLocked()
},
methods: {
...mapActions({
getAllUsers: 'barUsers/getAllUsers',
addCreditList: 'barUsers/addCreditList',
setFilter: 'barUsers/setFilter',
activateMenu: 'barUsers/activateMenu',
deactivateMenu: 'barUsers/deactivateMenu',
lock: 'barUsers/setLocked',
unlock: 'barUsers/unlock',
getLocked: 'barUsers/getLocked'
}),
addUser() {
this.addCreditList(this.user)
},
clickMenu() {
if (this.menu) this.deactivateMenu()
else this.activateMenu()
},
doUnlock() {
this.unlock(this.password)
this.password = ''
this.overlay = false
},
getCredit(user) {
let retUser = this.users.find(item => {
return item.username === user.username
})
return retUser ? retUser.amount : 0
},
getLocked(user) {
let retUser = this.users.find(item => {
return item.username === user.username
})
return retUser ? retUser.locked : false
}
},
computed: {
...mapGetters({
allUsers: 'barUsers/allUsers',
users: 'barUsers/users',
loading: 'barUsers/allUsersLoading',
menu: 'barUsers/menu',
locked: 'barUsers/locked'
})
},
watch: {
filter(val) {
this.setFilter(val)
}
}
}
</script>
<style scoped></style>

View File

@ -0,0 +1,49 @@
<template>
<div>
<v-list>
<v-list-item class="title" link :to="{name: 'overview'}">
<v-list-item-icon>
<v-icon>{{home}}</v-icon>
</v-list-item-icon>
<v-list-item-title>Gesamtübersicht</v-list-item-title>
</v-list-item>
</v-list>
<v-divider />
<v-list>
<div v-for="user in users" v-bind:key="users.indexOf(user)">
<v-list-item
:to="{ name: 'activeUser', params: { id: user.username } }"
link
>
<v-list-item-title
>{{ user.lastname }}, {{ user.firstname }}</v-list-item-title
>
</v-list-item>
</div>
<v-list-item>
<v-progress-circular indeterminate color="grey" v-if="loading" />
</v-list-item>
</v-list>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
import {mdiHome} from '@mdi/js'
export default {
name: 'FinanzerNavigation',
data () {
return {
home: mdiHome
}
},
computed: {
...mapGetters({
users: 'finanzerUsers/users',
loading: 'finanzerUsers/usersLoading'
})
}
}
</script>
<style scoped></style>

View File

@ -1,16 +1,400 @@
<template>
<v-data-table></v-data-table>
<v-content>
<v-toolbar tile>
<v-toolbar-title>Gesamtübersicht</v-toolbar-title>
<v-spacer />
<v-toolbar-items>
<v-btn text icon @click="countYear(false)">
<v-icon>{{keyboard_arrow_left}}</v-icon>
</v-btn>
<v-list-item>
<v-list-item-title class="title">{{ year }}</v-list-item-title>
</v-list-item>
<v-btn text icon @click="countYear(true)" :disabled="isActualYear">
<v-icon>{{keyboard_arrow_right}}</v-icon>
</v-btn>
</v-toolbar-items>
<v-spacer />
<v-toolbar-items>
<v-btn text @click="sendMails">Emails senden</v-btn>
<v-autocomplete
outlined
return-object
v-model="user"
style="margin-top: 3px"
placeholder="Suche Person"
:items="allUsers"
item-text="fullName"
full-width
:loading="allUsersLoading"
:search-input.sync="filter"
@change="addToUser(user)"
>
<template v-slot:prepend-inner>
<v-icon>{{search_person}}</v-icon>
</template>
</v-autocomplete>
</v-toolbar-items>
</v-toolbar>
<v-expand-transition>
<v-card style="margin-top: 3px" v-show="errorMails">
<v-row>
<v-spacer />
<v-btn
text
icon
style="margin-right: 5px"
@click="errorExpand ? (errorExpand = false) : (errorExpand = true)"
>
<v-icon :class="isExpand(errorExpand)" dense>$expand</v-icon>
</v-btn>
</v-row>
<v-expand-transition>
<div v-show="errorExpand">
<v-alert
v-for="error in errorMails"
:key="errorMails.indexOf(error)"
dense
:type="computeError(error.error)"
>{{ errorMessage(error) }}</v-alert
>
</div>
</v-expand-transition>
</v-card>
</v-expand-transition>
<v-progress-linear v-if="loading && users.length !== 0" indeterminate />
<TableSkeleton v-if="loading && users.length === 0" />
<div v-for="user in users" :key="users.indexOf(user)">
<v-card
v-if="user.creditList[year] && isFiltered(user)"
style="margin-top: 3px"
:loading="user.loading"
>
<v-card-title>
{{ user.lastname }}, {{ user.firstname }}
</v-card-title>
<Table v-bind:user="user" v-bind:year="year" />
<v-container fluid>
<v-row align="start" align-content="start">
<v-col>
<v-row>
<v-col>
<v-label>Vorjahr:</v-label>
</v-col>
<v-col>
<v-chip
outlined
:text-color="getLastColor(user.creditList[year][1].last)"
>{{
(user.creditList[year][1].last / 100).toFixed(2)
}}</v-chip
>
</v-col>
</v-row>
<v-row>
<v-col>
<v-label>Gesamt:</v-label>
</v-col>
<v-col>
<v-chip
outlined
x-large
:text-color="
getLastColor(
getAllSum(
user.creditList[year][2].sum,
user.creditList[year][1].last
)
)
"
>
{{
(
getAllSum(
user.creditList[year][2].sum,
user.creditList[year][1].last
) / 100
).toFixed(2)
}}
</v-chip>
</v-col>
</v-row>
</v-col>
<v-col align-self="center">
<v-row>
<v-col>
<v-label>Status:</v-label>
</v-col>
<v-col>
<v-chip outlined :text-color="getLockedColor(user.locked)">{{
user.locked ? 'Gesperrt' : 'nicht Gesperrt'
}}</v-chip>
</v-col>
</v-row>
<v-card outlined>
<v-row>
<v-card-title class="subtitle-2"
>Geld transferieren</v-card-title
>
<v-spacer />
<v-btn
text
icon
style="margin-right: 5px"
@click="setExpand(user)"
>
<v-icon :class="isExpand(user.expand)" dense
>$expand</v-icon
>
</v-btn>
</v-row>
<v-expand-transition>
<v-card-text v-show="user.expand">
<v-form style="margin-left: 15px; margin-right: 15px">
<v-row>
<v-col>
<v-text-field
:rules="[isNumber]"
label="Betrag"
v-model="amount"
></v-text-field>
</v-col>
<v-col>
<v-select
return-object
v-model="type"
label="Typ"
:items="[
{ value: 'amount', text: 'Schulden' },
{ value: 'credit', text: 'Guthaben' }
]"
item-text="text"
item-value="value"
></v-select>
</v-col>
</v-row>
<v-row>
<v-col>
<v-select
return-object
v-model="selectedYear"
label="Jahr"
:items="years"
item-text="text"
item-value="value"
></v-select>
</v-col>
<v-col>
<v-select
return-object
v-model="selectedMonth"
label="Monat"
:items="months"
item-text="text"
item-value="value"
></v-select>
</v-col>
</v-row>
</v-form>
<v-btn block @click="add(user)">Hinzufügen</v-btn>
</v-card-text>
</v-expand-transition>
</v-card>
</v-col>
</v-row>
</v-container>
</v-card>
</div>
</v-content>
</template>
<script>
export default {
name: "Overview",
props: {
year: null
}
import Table from './Table'
import { mapGetters, mapActions } from 'vuex'
import TableSkeleton from './Skeleton/TableSkeleton'
import {mdiChevronLeft, mdiChevronRight, mdiAccountSearch} from '@mdi/js'
export default {
name: 'Overview',
components: { TableSkeleton, Table },
props: {},
data() {
return {
keyboard_arrow_left: mdiChevronLeft,
keyboard_arrow_right: mdiChevronRight,
search_person: mdiAccountSearch,
errorExpand: false,
filter: '',
user: null,
amount: null,
isNumber: value => !isNaN(value) || 'Betrag muss eine Zahl sein.',
type: { value: 'credit', text: 'Guthaben' },
selectedYear: {
value: new Date().getFullYear(),
text: new Date().getFullYear()
},
selectedMonth: {
value: new Date().getMonth() + 1,
text: [
'Januar',
'Februar',
'März',
'April',
'Mai',
'Juni',
'Juli',
'August',
'September',
'Oktober',
'November',
'Dezember'
][new Date().getMonth()]
}
}
},
created() {},
methods: {
...mapActions({
createYears: 'finanzerUsers/createYears',
addAmount: 'finanzerUsers/addAmount',
addCredit: 'finanzerUsers/addCredit',
countYear: 'finanzerUsers/countYear',
sendMails: 'finanzerUsers/sendMails',
addUser: 'finanzerUsers/addUser'
}),
async getData(promise) {
return await promise
},
getLastColor(value) {
return value < 0 ? 'red' : 'green'
},
getAllSum(sum, lastYear) {
return lastYear + sum
},
getLockedColor(value) {
return value ? 'red' : 'green'
},
computeError(error) {
if (error) return 'error'
else return 'success'
},
errorMessage(error) {
if (error.error)
return (
'Konnte Email an ' +
error.user.firstname +
' ' +
error.user.lastname +
' nicht senden!'
)
else
return (
'Email wurde an ' +
error.user.firstname +
' ' +
error.user.lastname +
' versandt.'
)
},
setExpand(user) {
user.expand ? (user.expand = false) : (user.expand = true)
},
isExpand(value) {
return value ? 'rotate' : ''
},
// eslint-disable-next-line no-unused-vars
add(user) {
if (this.type.value === 'amount') {
this.addAmount({
user: user,
amount: this.amount,
year: this.selectedYear.value,
month: this.selectedMonth.value
})
}
if (this.type.value === 'credit') {
this.addCredit({
user: user,
credit: this.amount,
year: this.selectedYear.value,
month: this.selectedMonth.value
})
}
this.createDefault(
this.amount,
this.type,
this.selectedYear,
this.selectedMonth
)
},
isFiltered(user) {
try {
var filters = this.filter.split(' ')
for (var filter in filters) {
if (
user.firstname.toLowerCase().includes(filters[filter].toLowerCase()) ||
user.lastname.toLowerCase().includes(filters[filter].toLowerCase())
) {
return true
}
}
return false
} catch (e) {
return true
}
},
addToUser(user) {
this.addUser(user)
this.$router.push({name: 'activeUser', params: {id: user.username}})
},
createDefault() {
this.amount = null
this.type = { value: 'credit', text: 'Guthaben' }
this.selectedYear = {
value: new Date().getFullYear(),
text: new Date().getFullYear()
}
this.selectedMonth = {
value: new Date().getMonth() + 1,
text: [
'Januar',
'Februar',
'März',
'April',
'Mai',
'Juni',
'Juli',
'August',
'September',
'Oktober',
'November',
'Dezember'
][new Date().getMonth()]
}
}
},
computed: {
isActualYear() {
return this.year === new Date().getFullYear()
},
...mapGetters({
users: 'finanzerUsers/users',
allUsers: 'finanzerUsers/allUsers',
errorMails: 'finanzerUsers/errorMails',
year: 'finanzerUsers/year',
years: 'finanzerUsers/years',
months: 'finanzerUsers/months',
loading: 'finanzerUsers/usersLoading',
allUsersLoading: 'finanzerUsers/allUsersLoading'
})
}
}
</script>
<style scoped>
.rotate {
transform: rotate(180deg);
}
</style>

View File

@ -0,0 +1,60 @@
<template>
<div>
<v-card style="margin-top: 3px">
<v-card-title>
<v-skeleton-loader type="heading" />
</v-card-title>
<v-container>
<v-skeleton-loader type="table-thead"/>
<v-skeleton-loader type="table-row-divider@3"/>
</v-container>
<v-container fluid>
<v-row align="start" align-content="start">
<v-col>
<v-row>
<v-col>
<v-skeleton-loader type="chip" />
</v-col>
<v-col>
<v-skeleton-loader type="chip" />
</v-col>
</v-row>
<v-row>
<v-col>
<v-skeleton-loader type="chip"/>
</v-col>
<v-col>
<v-skeleton-loader type="chip" />
</v-col>
</v-row>
</v-col>
<v-col align-self="center">
<v-row>
<v-col>
<v-skeleton-loader type="chip" />
</v-col>
<v-col>
<v-skeleton-loader type="chip" />
</v-col>
</v-row>
<v-card outlined>
<v-row>
<v-card-title>
<v-skeleton-loader style="margin: 3px; margin-left: 10px" type="chip"/>
</v-card-title>
</v-row>
</v-card>
</v-col>
</v-row>
</v-container>
</v-card>
</div>
</template>
<script>
export default {
name: 'TableSkeleton'
}
</script>
<style scoped></style>

View File

@ -0,0 +1,82 @@
<template>
<div>
<v-toolbar tile>
<v-toolbar-title>
<v-row>
<v-col>
<v-skeleton-loader type="chip" />
</v-col>
<v-col>
<v-skeleton-loader type="chip" />
</v-col>
</v-row>
</v-toolbar-title>
<v-spacer />
<v-toolbar-items>
<v-skeleton-loader type="button" />
</v-toolbar-items>
</v-toolbar>
<v-card style="margin-top: 3px;">
<v-card-title><v-skeleton-loader type="heading"/></v-card-title>
<v-card-text>
<v-form style="margin-left: 15px; margin-right: 15px">
<v-row>
<v-col>
<v-skeleton-loader type="chip" />
</v-col>
<v-col>
<v-skeleton-loader type="chip" />
</v-col>
<v-col>
<v-skeleton-loader type="button" />
</v-col>
</v-row>
<v-divider style="margin-bottom: 15px;" />
<v-row>
<v-col>
<v-skeleton-loader type="chip" />
</v-col>
<v-col>
<v-skeleton-loader type="chip" />
</v-col>
</v-row>
<v-row>
<v-skeleton-loader type="button" />
</v-row>
</v-form>
</v-card-text>
</v-card>
<v-card style="margin-top: 3px;">
<v-card-title><v-skeleton-loader type="chip"/></v-card-title>
<v-card-text>
<v-form style="margin-left: 15px; margin-right: 15px">
<v-row>
<v-col>
<v-skeleton-loader type="chip" />
</v-col>
<v-col>
<v-skeleton-loader type="chip" />
</v-col>
</v-row>
<v-row>
<v-col>
<v-skeleton-loader type="chip" />
</v-col>
<v-col>
<v-skeleton-loader type="chip" />
</v-col>
</v-row>
</v-form>
<v-skeleton-loader type="button" />
</v-card-text>
</v-card>
</div>
</template>
<script>
export default {
name: 'UserSkeleton'
}
</script>
<style scoped></style>

View File

@ -0,0 +1,125 @@
<template>
<v-data-table dense :headers="headers" :items="user.creditList[year]" :hide-default-footer="true">
<template v-slot:item.jan_amount="{ item }">
<v-chip outlined :text-color="getColor(item, item.jan_amount)">
{{(item.jan_amount /
100).toFixed(2)}}
</v-chip>
</template>
<template v-slot:item.feb_amount="{ item }">
<v-chip outlined :text-color="getColor(item, item.feb_amount)">
{{(item.feb_amount /
100).toFixed(2)}}
</v-chip>
</template>
<template v-slot:item.maer_amount="{ item }">
<v-chip outlined :text-color="getColor(item, item.maer_amount)">
{{(item.maer_amount /
100).toFixed(2)}}
</v-chip>
</template>
<template v-slot:item.apr_amount="{ item }">
<v-chip outlined :text-color="getColor(item, item.apr_amount)">
{{(item.apr_amount /
100).toFixed(2)}}
</v-chip>
</template>
<template v-slot:item.mai_amount="{ item }">
<v-chip outlined :text-color="getColor(item, item.mai_amount)">
{{(item.mai_amount /
100).toFixed(2)}}
</v-chip>
</template>
<template v-slot:item.jun_amount="{ item }">
<v-chip outlined :text-color="getColor(item, item.jun_amount)">
{{(item.jun_amount /
100).toFixed(2)}}
</v-chip>
</template>
<template v-slot:item.jul_amount="{ item }">
<v-chip outlined :text-color="getColor(item, item.jul_amount)">
{{(item.jul_amount /
100).toFixed(2)}}
</v-chip>
</template>
<template v-slot:item.aug_amount="{ item }">
<v-chip outlined :text-color="getColor(item, item.aug_amount)">
{{(item.aug_amount /
100).toFixed(2)}}
</v-chip>
</template>
<template v-slot:item.sep_amount="{ item }">
<v-chip outlined :text-color="getColor(item, item.sep_amount)">
{{(item.sep_amount /
100).toFixed(2)}}
</v-chip>
</template>
<template v-slot:item.okt_amount="{ item }">
<v-chip outlined :text-color="getColor(item, item.okt_amount)">
{{(item.okt_amount /
100).toFixed(2)}}
</v-chip>
</template>
<template v-slot:item.nov_amount="{ item }">
<v-chip outlined :text-color="getColor(item, item.nov_amount)">
{{(item.nov_amount /
100).toFixed(2)}}
</v-chip>
</template>
<template v-slot:item.dez_amount="{ item }">
<v-chip outlined :text-color="getColor(item, item.dez_amount)">
{{(item.dez_amount /
100).toFixed(2)}}
</v-chip>
</template>
<template v-slot:item.sum="{ item }">
<v-chip outlined :text-color="getColor(item, item.sum)">{{(item.sum / 100).toFixed(2)}}</v-chip>
</template>
</v-data-table>
</template>
<script>
export default {
name: 'Table',
props: {
user: Object,
year: Number
},
data() {
return {
headers: [
{
text: 'Schulden / Guthaben',
align: 'left',
sortable: false,
value: 'type'
},
{ text: 'Januar in EUR', value: 'jan_amount' },
{ text: 'Februar in EUR', value: 'feb_amount' },
{ text: 'März in EUR', value: 'maer_amount' },
{ text: 'April in EUR', value: 'apr_amount' },
{ text: 'Mai in EUR', value: 'mai_amount' },
{ text: 'Juni in EUR', value: 'jun_amount' },
{ text: 'Juli in EUR', value: 'jul_amount' },
{ text: 'August in EUR', value: 'aug_amount' },
{ text: 'September in EUR', value: 'sep_amount' },
{ text: 'Oktober in EUR', value: 'okt_amount' },
{ text: 'November in EUR', value: 'nov_amount' },
{ text: 'Dezember in EUR', value: 'dez_amount' },
{ text: 'Summe in EUR', value: 'sum' }
]
}
},
methods: {
getColor(item, value) {
if (item.type === 'Summe') {
return value < 0 ? 'red' : 'green'
}
return item.type === 'Guthaben' ? 'green' : 'red'
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,363 @@
<template>
<div>
<v-content v-if="loading" >
<UserSkeleton />
</v-content>
<v-content v-if="activeUser">
<v-toolbar tile>
<v-toolbar-title
>{{ activeUser.lastname }},
{{ activeUser.firstname }}</v-toolbar-title
>
<v-spacer />
<v-toolbar-items>
<v-btn @click="sendMail({ username: activeUser.username })" text
>Email senden</v-btn
>
</v-toolbar-items>
</v-toolbar>
<v-progress-linear v-if="activeUser.loading" indeterminate />
<v-expand-transition>
<v-card style="margin-top: 3px" v-show="errorMail">
<v-alert dense :type="computeError(errorMail)">
{{ errorMessage(errorMail) }}
</v-alert>
</v-card>
</v-expand-transition>
<v-card style="margin-top: 3px;">
<v-card-title>Konfiguration</v-card-title>
<v-card-text>
<v-form style="margin-left: 15px; margin-right: 15px">
<v-row>
<v-col>
<v-label>Status:</v-label>
</v-col>
<v-col>
<v-chip outlined :text-color="getLockedColor(activeUser.locked)"
>{{ activeUser.locked ? 'Gesperrt' : 'nicht Gesperrt' }}
</v-chip>
</v-col>
<v-col>
<v-btn
@click="
doLock({ user: activeUser, locked: !activeUser.locked })
"
>{{ activeUser.locked ? 'Entperren' : 'Sperren' }}
</v-btn>
</v-col>
</v-row>
<v-divider style="margin-bottom: 15px;" />
<v-row>
<v-col>
<v-text-field
:rules="[isNumber]"
label="Betrag des Sperrlimits in € (EURO)"
v-model="limit"
></v-text-field>
</v-col>
<v-col>
<v-select
return-object
v-model="autoLock"
label="Automatische Sperre"
:items="[
{ value: true, text: 'Aktiviert' },
{ value: false, text: 'Deaktiviert' }
]"
item-text="text"
item-value="value"
/>
</v-col>
</v-row>
<v-row>
<v-btn
block
@click="
saveConfig({
user: activeUser,
limit: limit,
autoLock: autoLock.value
})
"
>Speichern
</v-btn>
</v-row>
</v-form>
</v-card-text>
</v-card>
<v-card style="margin-top: 3px;">
<v-card-title>Geld transferieren</v-card-title>
<v-card-text>
<v-form style="margin-left: 15px; margin-right: 15px">
<v-row>
<v-col>
<v-text-field
:rules="[isNumber]"
label="Betrag"
v-model="amount"
></v-text-field>
</v-col>
<v-col>
<v-select
return-object
v-model="type"
label="Typ"
:items="[
{ value: 'amount', text: 'Schulden' },
{ value: 'credit', text: 'Guthaben' }
]"
item-text="text"
item-value="value"
></v-select>
</v-col>
</v-row>
<v-row>
<v-col>
<v-select
return-object
v-model="selectedYear"
label="Jahr"
:items="selectYears"
item-text="text"
item-value="value"
></v-select>
</v-col>
<v-col>
<v-select
return-object
v-model="selectedMonth"
label="Monat"
:items="months"
item-text="text"
item-value="value"
></v-select>
</v-col>
</v-row>
</v-form>
<v-btn block @click="add">Hinzufügen</v-btn>
</v-card-text>
</v-card>
<div v-for="year in years" :key="years.indexOf(year)">
<v-card style="margin-top: 3px;">
<v-card-title>{{ year }}</v-card-title>
<Table v-bind:user="activeUser" v-bind:year="year" />
<v-container fluid>
<v-col>
<v-row>
<v-col>
<v-label>Vorjahr:</v-label>
</v-col>
<v-col>
<v-chip
outlined
:text-color="
getLastColor(activeUser.creditList[year][1].last)
"
>
{{ (activeUser.creditList[year][1].last / 100).toFixed(2) }}
</v-chip>
</v-col>
<v-col>
<v-label>Gesamt:</v-label>
</v-col>
<v-col>
<v-chip
outlined
x-large
:text-color="
getLastColor(
getAllSum(
activeUser.creditList[year][2].sum,
activeUser.creditList[year][1].last
)
)
"
>
{{
(
getAllSum(
activeUser.creditList[year][2].sum,
activeUser.creditList[year][1].last
) / 100
).toFixed(2)
}}
</v-chip>
</v-col>
</v-row>
</v-col>
</v-container>
</v-card>
</div>
</v-content>
</div>
</template>
<script>
import Table from './Table'
import { mapGetters, mapActions } from 'vuex'
import UserSkeleton from "./Skeleton/UserSkeleton";
export default {
name: 'User',
props: {
id: String
},
components: {UserSkeleton, Table },
data() {
return {
isNumber: value => !isNaN(value) || 'Betrag muss eine Zahl sein.',
limit: null,
autoLock: null,
amount: null,
type: { value: 'credit', text: 'Guthaben' },
selectedYear: {
value: new Date().getFullYear(),
text: new Date().getFullYear()
},
selectedMonth: {
value: new Date().getMonth() + 1,
text: [
'Januar',
'Februar',
'März',
'April',
'Mai',
'Juni',
'Juli',
'August',
'September',
'Oktober',
'November',
'Dezember'
][new Date().getMonth()]
}
}
},
created() {
this.setActiveUser(this.$route.params.id)
},
methods: {
...mapActions({
addAmount: 'finanzerUsers/addAmount',
addCredit: 'finanzerUsers/addCredit',
sendMail: 'finanzerUsers/sendMail',
doLock: 'finanzerUsers/doLock',
saveConfig: 'finanzerUsers/saveConfig',
setActiveUser: 'finanzerUsers/setActiveUser'
}),
getLastColor(value) {
return value < 0 ? 'red' : 'green'
},
getAllSum(sum, lastYear) {
return lastYear + sum
},
getLockedColor(value) {
return value ? 'red' : 'green'
},
add() {
if (this.type.value === 'amount') {
this.addAmount({
user: this.activeUser,
amount: this.amount,
year: this.selectedYear.value,
month: this.selectedMonth.value
})
}
if (this.type.value === 'credit') {
this.addCredit({
user: this.activeUser,
credit: this.amount,
year: this.selectedYear.value,
month: this.selectedMonth.value
})
}
this.createDefault()
},
createDefault() {
// eslint-disable-next-line no-unused-vars
let year = new Date().getFullYear()
// eslint-disable-next-line no-unused-vars
let month = new Date().getMonth()
this.amount = null
this.type = { value: 'credit', text: 'Guthaben' }
this.selectedYear = {
value: new Date().getFullYear(),
text: new Date().getFullYear()
}
this.selectedMonth = {
value: new Date().getMonth() + 1,
text: [
'Januar',
'Februar',
'März',
'April',
'Mai',
'Juni',
'Juli',
'August',
'September',
'Oktober',
'November',
'Dezember'
][new Date().getMonth()]
}
},
computeError(error) {
if (error) {
if (error.error) return 'error'
else return 'success'
}
},
errorMessage(error) {
if (error) {
if (error.error)
return (
'Konnte Email an ' +
error.user.firstname +
' ' +
error.user.lastname +
' nicht senden!'
)
else
return (
'Email wurde an ' +
error.user.firstname +
' ' +
error.user.lastname +
' versandt.'
)
}
}
},
computed: {
years() {
let years = []
for (let year in this.activeUser.creditList) {
years.unshift(parseInt(year))
}
return years
},
...mapGetters({
activeUser: 'finanzerUsers/activeUser',
errorMail: 'finanzerUsers/errorMail',
months: 'finanzerUsers/months',
selectYears: 'finanzerUsers/selectYears',
loading: 'finanzerUsers/addUserLoading'
})
},
watch: {
activeUser(newVal) {
this.limit = (newVal.limit / 100).toFixed(2)
this.autoLock = {
value: newVal.autoLock,
text: newVal.autoLock ? 'Aktiviert' : 'Deaktiviert'
}
},
id(newVal) {
this.setActiveUser(newVal)
}
}
}
</script>
<style scoped></style>

View File

@ -0,0 +1,28 @@
<template>
<v-list>
<v-list-item class="title" link :to="{name: 'gastroPricelist'}">
<v-list-item-icon>
<v-icon>{{list}}</v-icon>
</v-list-item-icon>
<v-list-item-title>
Preisliste
</v-list-item-title>
</v-list-item>
</v-list>
</template>
<script>
import { mdiFileMultiple } from '@mdi/js'
export default {
name: "GastroNavigation",
data() {
return {
list: mdiFileMultiple
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,497 @@
<template>
<div>
<v-data-table
:headers="headers"
:items="priceList"
:search="search"
:loading="priceListLoading || typesLoading"
>
<template v-slot:top>
<v-toolbar flat color="white">
<v-toolbar-title>Preisliste</v-toolbar-title>
<v-spacer></v-spacer>
<v-text-field
v-model="search"
label="Suche Getränk"
single-line
hide-details
>
<template v-slot:append>
<v-icon>{{ searchIcon }}</v-icon>
</template>
</v-text-field>
<v-dialog v-model="dialog" v-if="isGastro && isGastroPage">
<template v-slot:activator="{ on }">
<v-btn
fab
x-small
color="primary"
class="mb-2"
v-on="on"
style="margin: 5px"
>
<v-icon>{{ plus }}</v-icon>
</v-btn>
</template>
<v-card>
<v-card-title>
<span class="headline">{{ formTitle }}</span>
</v-card-title>
<v-card-text>
<v-container>
<v-row>
<v-col cols="12" sm="6" md="4">
<v-text-field
v-model="editedItem.name"
label="Name"
outlined
></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="4">
<v-autocomplete
return-object
v-model="editedItem.type"
label="Kategorie"
item-text="name"
item-value="id"
:items="types"
outlined
:search-input.sync="searchType"
no-data-text="Kategorie nicht vorhanden."
>
<template v-slot:append-item>
<v-list-item v-if="!inType(searchType)">
<v-list-item-title>
{{ searchType }}
</v-list-item-title>
<v-btn
dark
x-small
color="blue darken-1"
@click="addType()"
:disabled="inType(searchType)"
fab
>
<v-icon>
{{ plus }}
</v-icon>
</v-btn>
</v-list-item>
</template>
</v-autocomplete>
</v-col>
<v-col cols="12" sm="6" md="4">
<v-text-field
v-model="editedItem.price"
label="Preis in €"
outlined
></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="4">
<v-text-field
v-model="editedItem.price_big"
label="Preis groß in €"
outlined
></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="4">
<v-text-field
v-model="editedItem.price_club"
label="Preis Club in €"
outlined
></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="4">
<v-text-field
v-model="editedItem.price_club_big"
label="Preis Club groß in €"
outlined
></v-text-field>
</v-col>
<v-col col="12" sm="6" md="4">
<v-text-field
v-model="editedItem.premium"
label="Aufpreis in €"
outlined
/>
</v-col>
<v-col cols="12" sm="6" md="4">
<v-text-field
v-model="editedItem.premium_club"
label="Aufpreis Club in €"
outlined
/>
</v-col>
<v-col cols="12" sm="6" md="4">
<v-text-field
v-model="editedItem.price_extern_club"
label="Preis extern Club in €"
outlined
/>
</v-col>
</v-row>
</v-container>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="blue darken-1" text @click="close"
>Abbrechen</v-btn
>
<v-btn color="blue darken-1" text @click="save"
>Speichern</v-btn
>
</v-card-actions>
</v-card>
</v-dialog>
</v-toolbar>
</template>
<template v-slot:item.type="{ item }">
{{ computeType(item.type) }}
</template>
<template v-slot:item.price="{ item }">
{{ item.price ? (item.price / 100).toFixed(2) : '' }}
</template>
<template v-slot:item.price_big="{ item }">
{{ item.price_big ? (item.price_big / 100).toFixed(2) : '' }}
</template>
<template v-slot:item.price_club="{ item }">
{{
item.name.toLowerCase() == 'long island ice tea'.toLowerCase()
? 'Ein Klubmitglied bestellt keinen Long Island Icetea'
: item.price_club
? (item.price_club / 100).toFixed(2)
: ''
}}
</template>
<template v-slot:item.price_club_big="{ item }">
{{ item.price_club_big ? (item.price_club_big / 100).toFixed(2) : '' }}
</template>
<template v-slot:item.premium="{ item }">
{{ item.premium ? (item.premium / 100).toFixed(2) : '' }}
</template>
<template v-slot:item.premium_club="{ item }">
{{ item.premium_club ? (item.premium_club / 100).toFixed(2) : '' }}
</template>
<template v-slot:item.price_extern_club="{ item }">
{{
item.price_extern_club
? (item.price_extern_club / 100).toFixed(2)
: ''
}}
</template>
<template v-slot:item.action="{ item }">
<v-icon small class="mr-2" @click="editItem(item)">
{{ editIcon }}
</v-icon>
<v-icon small @click="deleteItem(item)">
{{ deleteIcon }}
</v-icon>
</template>
</v-data-table>
<v-card tile v-if="isGastro && isGastroPage" :loading="typesLoading">
<v-card-title>
Kategorien
<v-spacer />
<v-btn fab x-small @click="dialogType = true" color="primary">
<v-icon>{{ plus }}</v-icon>
</v-btn>
</v-card-title>
<v-card-text>
<div tile v-for="type in types" :key="type.id">
<v-card tile>
<v-card-text class="black--text">
<v-row class="ml-3 mr-3">
{{ type.name }}
<v-spacer />
<v-btn icon @click="editType(type)">
<v-icon>
{{ editIcon }}
</v-icon>
</v-btn>
<v-btn icon @click="deleteType(type)">
<v-icon>
{{ deleteIcon }}
</v-icon>
</v-btn>
</v-row>
</v-card-text>
</v-card>
</div>
</v-card-text>
<v-dialog v-model="dialogType">
<v-card>
<v-card-title>
{{ dialogTypeTitle }}
</v-card-title>
<v-card-text>
<v-container>
<v-text-field
v-model="editedType.name"
outlined
label="Name der Kategorie"
/>
</v-container>
</v-card-text>
<v-card-actions>
<v-spacer />
<v-btn text color="blue darken-1" @click="closeType()">
Abbrechen
</v-btn>
<v-btn
text
color="blue darken-1"
@click="saveType()"
:disabled="inType(editedType.name)"
>
Speichern
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</v-card>
</div>
</template>
<script>
import { mapGetters, mapActions } from 'vuex'
import { mdiMagnify, mdiPlus, mdiPencil, mdiDelete } from '@mdi/js'
export default {
name: 'PriceList',
data() {
return {
editIcon: mdiPencil,
deleteIcon: mdiDelete,
searchIcon: mdiMagnify,
plus: mdiPlus,
searchType: null,
search: null,
dialog: null,
dialogType: null,
editedIndex: -1,
headers: [
{
text: 'Name',
value: 'name'
},
{
text: 'Kategorie',
value: 'type'
},
{
text: 'Preis in €',
value: 'price'
},
{
text: 'Preis groß in €',
value: 'price_big'
},
{
text: 'Preis Club in €',
value: 'price_club'
},
{
text: 'Preis groß Club in €',
value: 'price_club_big'
},
{
text: 'Aufpreis in €',
value: 'premium'
},
{
text: 'Aufpreis Club in €',
value: 'premium_club'
},
{
text: 'Preis Club extern in €',
value: 'price_extern_club'
}
],
editedItem: {
name: null,
type: { id: -1, name: null },
price: null,
price_big: null,
price_club: null,
price_club_big: null,
premium: null,
premium_club: null,
price_extern_club: null
},
defaultItem: {
name: null,
type: { id: -1, name: null },
price: null,
price_big: null,
price_club: null,
price_club_big: null,
premium: null,
premium_club: null,
price_extern_club: null
},
editedType: {
id: -1,
name: null
},
defaultType: {
id: -1,
name: null
}
}
},
methods: {
...mapActions({
getPriceList: 'priceList/getPriceList',
getTypes: 'priceList/getTypes',
setDrink: 'priceList/setDrink',
updateDrink: 'priceList/updateDrink',
deleteDrink: 'priceList/deleteDrink',
setDrinkType: 'priceList/setDrinkType',
updateDrinkType: 'priceList/updateDrinkType',
deleteDrinkType: 'priceList/deleteDrinkType'
}),
editType(item) {
this.editedType = Object.assign({}, item)
this.dialogType = true
},
closeType() {
this.dialogType = false
setTimeout(() => {
this.editedType = Object.assign({}, this.defaultType)
}, 300)
},
saveType() {
this.editedType.id === -1
? this.setDrinkType(this.editedType)
: this.updateDrinkType(this.editedType)
this.closeType()
},
deleteType(item) {
confirm('Bist du sicher, dass du diese Kategorie entfernen willst?') &&
this.deleteDrinkType({ id: item.id })
},
addType() {
this.setDrinkType({ name: this.searchType })
},
close() {
this.dialog = false
setTimeout(() => {
this.editedItem = Object.assign({}, this.defaultItem)
this.editedIndex = -1
}, 300)
},
editItem(item) {
this.editedIndex = item.id
this.editedItem = Object.assign({}, item)
for (let i in this.editedItem) {
this.editedItem[i] = isNaN(this.editedItem[i])
? this.editedItem[i]
: this.editedItem[i] == null || this.editedItem[i] == 0
? null
: (this.editedItem[i] / 100).toFixed(2)
}
this.editedItem.type = Object.assign(
{},
this.types.find(a => a.id == item.type)
)
this.dialog = true
},
deleteItem(item) {
confirm('Bist du sicher, dass die dieses Getränk entfernen wills?') &&
this.deleteDrink({ id: item.id })
},
save() {
var drink = {
id: this.editedIndex,
name: this.editedItem.name,
type: this.editedItem.type.id,
price: !isNaN(this.editedItem.price)
? this.editedItem.price * 100
: null,
price_big: !isNaN(this.editedItem.price_big)
? this.editedItem.price_big * 100
: null,
price_club: !isNaN(this.editedItem.price_club)
? this.editedItem.price_club * 100
: null,
price_club_big: !isNaN(this.editedItem.price_club_big)
? this.editedItem.price_club_big * 100
: null,
premium: !isNaN(this.editedItem.premium)
? this.editedItem.premium * 100
: null,
premium_club: !isNaN(this.editedItem.premium_club)
? this.editedItem.premium_club * 100
: null,
price_extern_club: !isNaN(this.editedItem.price_extern_club)
? this.editedItem.price_extern_club * 100
: null
}
drink.id === -1 ? this.setDrink(drink) : this.updateDrink(drink)
this.editedItem = Object.assign({}, this.defaultItem)
this.close()
}
},
computed: {
...mapGetters({
priceList: 'priceList/priceList',
types: 'priceList/types',
priceListLoading: 'priceList/priceListLoading',
typesLoading: 'priceList/typesLoading',
isGastro: 'isGastro'
}),
isGastroPage() {
return this.$route.name === 'gastroPricelist'
},
formTitle() {
return this.editedIndex === -1 ? 'Neues Getränk' : 'Bearbeite Getränk'
},
inType() {
return text => {
return !!this.types.find(a => {
if (a.name === null || text === null) {
return true
} else {
return a.name.toLowerCase() === text.toLowerCase()
}
})
}
},
dialogTypeTitle() {
return this.editedType.id === -1
? 'Neue Kategorie'
: 'Bearbeite Kategorie'
},
computeType() {
return id => {
const type = this.types.find(a => {
return a.id === id
})
return type ? type.name : null
}
}
},
created() {
this.getPriceList()
this.getTypes()
if (this.isGastro && this.isGastroPage) {
this.headers.push({
text: 'Aktion',
value: 'action',
sortable: false,
filterable: false
})
}
console.log(this.$route)
},
watch: {
dialog(val) {
val || this.close()
}
}
}
</script>
<style scoped></style>

View File

@ -0,0 +1,497 @@
<template>
<v-container>
<v-dialog v-model="checkValidate" max-width="290">
<v-card>
<v-card-title>
Willst du wirklich??
</v-card-title>
<v-card-text v-if="stornoMessage">
Willst du wirklich den Betrag
{{ (stornoMessage.amount / 100).toFixed(2) }} von
{{ stornoMessage.user.firstname }}
{{ stornoMessage.user.lastname }} stornieren?
</v-card-text>
<v-card-actions>
<v-spacer />
<v-btn text @click="cancelStorno">Abbrechen</v-btn>
<v-btn text @click="acceptStorno">Stornieren</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<v-dialog v-model="dialog" max-width="290">
<v-card>
<v-card-title class="headline"
>Transaktion ist länger als 15 Sekunden her!</v-card-title
>
<v-card-text>
Da die Transaktion länger als 15 Sekunden her ist, kann eine
Stornierung nicht durchgeführt werden. Wende dich bitte an den
Finanzer.
</v-card-text>
<v-card-actions>
<v-spacer />
<v-btn text @click="dialog = false">
Verstanden
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<v-dialog
v-if="overLimitUser"
v-model="overLimitUser"
max-width="290"
persistent
>
<v-card>
<v-card-title>Warnung</v-card-title>
<v-card-text>
{{ overLimitUser.firstname }} {{ overLimitUser.lastname }} übersteigt
das Anschreibelimit von
{{ (overLimitUser.limit / 100).toFixed(2) }} . Danach kann dieses
Mitglied nichts mehr anschreiben. Will er das wirklich?
</v-card-text>
<v-card-actions>
<v-spacer />
<v-btn text @click="cancel()">Abbrechen</v-btn>
<v-btn text @click="continueAdd(overLimitUser)">Anschreiben</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<v-dialog v-if="overOverLimit" v-model="overOverLimit" max-width="290" persistent>
<v-card>
<v-card-title>Anschreiben nicht möglich</v-card-title>
<v-card-text>
{{ overOverLimit.firstname }}
{{ overOverLimit.lastname }} überschreitet das Anschreibelimit zuviel.
Das Anschreiben wurde daher gestoppt und zurückgesetzt.
</v-card-text>
<v-card-actions>
<v-btn text @click="overOverLimit = null">Verstanden</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<AddAmountSkeleton v-if="loading" />
<v-navigation-drawer v-model="menu" right app clipped>
<v-list-item-group :key="componentRenderer">
<v-list-item inactive>
<v-list-item-title class="headline">
Verlauf
</v-list-item-title>
</v-list-item>
<v-divider />
<div
v-for="message in messages"
three-line
:key="messages.indexOf(message)"
>
<div v-if="message">
<v-list-item three-line inactive @click="storno(message)">
<v-list-item-content>
<v-progress-linear indeterminate v-if="message.loading" />
<v-list-item-title>{{ now(message.date) }}</v-list-item-title>
<v-list-item-subtitle>
{{ createSum(message) }} {{ createMessage(message) }}
</v-list-item-subtitle>
<v-list-item-subtitle class="red--text" v-if="message.storno"
>STORNIERT!!!
</v-list-item-subtitle>
<v-list-item-subtitle class="red--text" v-else-if="message.error">
ERROR!
</v-list-item-subtitle>
<v-list-item-action-text v-if="under5minutes(message.date) && !message.error"
>Klicken um zu Stornieren
</v-list-item-action-text>
</v-list-item-content>
</v-list-item>
</div>
</div>
</v-list-item-group>
</v-navigation-drawer>
<v-card v-if="!loading" :loading="addLoading">
<v-card-title>
{{ user.firstname }} {{ user.lastname }}
<v-spacer />
<v-btn @click="menu = !menu" icon>
<v-icon>{{ menuIcon }}</v-icon>
</v-btn>
</v-card-title>
<v-card-subtitle v-if="user.limit + getAllSum() > 0">
Nur noch {{ ((user.limit + getAllSum()) / 100).toFixed(2) }}
übrig!!
</v-card-subtitle>
<v-card-text>
<v-row>
<v-col cols="10">
<v-row>
<v-col cols="6" sm="4">
<v-btn
class="creditBtn"
block
@click="addingAmount(200)"
:color="color"
:disabled="user.locked"
>2 </v-btn
>
</v-col>
<v-col cols="6" sm="4">
<v-btn
class="creditBtn"
block
@click="addingAmount(100)"
:color="color"
:disabled="user.locked"
>1 </v-btn
>
</v-col>
<v-col cols="6" sm="4">
<v-btn
class="creditBtn"
block
@click="addingAmount(50)"
:color="color"
:disabled="user.locked"
>0,50 </v-btn
>
</v-col>
<v-col cols="6" sm="4">
<v-btn
class="creditBtn"
block
@click="addingAmount(40)"
:color="color"
:disabled="user.locked"
>0,40 </v-btn
>
</v-col>
<v-col cols="6" sm="4">
<v-btn
class="creditBtn"
block
@click="addingAmount(20)"
:color="color"
:disabled="user.locked"
>0,20 </v-btn
>
</v-col>
<v-col cols="6" sm="4">
<v-btn
class="creditBtn"
block
@click="addingAmount(10)"
:color="color"
:disabled="user.locked"
>0,10 </v-btn
>
</v-col>
<v-col cols="8">
<v-text-field
outlined
type="number"
v-model="value"
label="Benutzerdefinierter Betrag"
:disabled="user.locked"
></v-text-field>
</v-col>
<v-col cols="4">
<v-btn
fab
:color="color"
@click="addAmountMore()"
:disabled="user.locked"
>
<v-icon>{{ plus }}</v-icon>
</v-btn>
</v-col>
</v-row>
</v-col>
<v-col align-self="center">
<v-row>
<v-list-item>
<v-list-item-content class="text-center">
<v-list-item-action-text :class="getColor(getAllSum())"
>{{ (getAllSum() / 100).toFixed(2) }}
</v-list-item-action-text>
<v-list-item-action-text v-if="toSetAmount">
- {{ (toSetAmount / 100).toFixed(2) }}
</v-list-item-action-text>
</v-list-item-content>
</v-list-item>
</v-row>
</v-col>
</v-row>
<v-alert v-if="user.locked" type="error"
>{{ user.firstname }} darf nicht mehr anschreiben.
{{ user.firstname }} sollte sich lieber mal beim Finanzer
melden.</v-alert
>
</v-card-text>
</v-card>
<v-snackbar
v-for="message in messages"
:key="messages.indexOf(message)"
:color="message.error ? 'error' : 'success'"
bottom
:timeout="0"
:multi-line="true"
v-model="message.visible"
vertical
>
<div class="title">
<p style="font-size: 5em; margin: 20px">{{ createSum(message) }}</p>
{{ createMessage(message) }}
</div>
<div>
{{ now(message.date) }}
</div>
<v-btn color="white" icon @click="message.visible = false">
<v-icon>
{{ close }}
</v-icon>
</v-btn>
</v-snackbar>
<ConnectionError/>
</v-container>
</template>
<script>
import { mapGetters, mapActions } from 'vuex'
// eslint-disable-next-line no-unused-vars
import { mdiMenu, mdiPlus, mdiClose } from '@mdi/js'
import AddAmountSkeleton from './Skeleton/AddAmountSkeleton'
import ConnectionError from "@/components/ConnectionError";
export default {
name: 'AddAmount',
components: {ConnectionError, AddAmountSkeleton },
data() {
return {
color: 'green accent-4',
value: null,
plus: mdiPlus,
menu: false,
dialog: false,
componentRenderer: 0,
timer: '',
menuIcon: mdiMenu,
close: mdiClose,
checkValidate: false,
stornoMessage: null,
timeout: null,
toSetAmount: null,
overLimitUser: null,
overOverLimit: null,
}
},
created() {
this.timer = setInterval(this.forceRender, 1000)
},
methods: {
...mapActions({
addAmount: 'user/addAmount',
commitStorno: 'user/storno'
}),
continueAdd(user) {
this.overLimitUser = null
user.checkedOverLimit = true
if (this.value) {
this.addAmount(Math.round(Math.abs(this.value * 100)))
setTimeout(() => {
this.value = null
this.toSetAmount = null
}, 300)
} else {
user.timeout = setTimeout(() => {
this.addAmount(this.toSetAmount)
setTimeout(() => {
this.toSetAmount = null
}, 300)
}, 2000)
}
},
cancel() {
this.toSetAmount = null
this.value = null
this.overLimitUser = null
},
checkOverLimitIsValid(user) {
if (this.toSetAmount && user.autoLock) {
if (Math.abs(this.getAllSum() - Number.parseInt(this.toSetAmount)) > user.limit + 500) {
this.overOverLimit = user
this.toSetAmount = null
this.value = null
return false
}
}
return true
},
checkOverLimit(user) {
if (this.toSetAmount) {
if (Math.abs( this.getAllSum() - this.toSetAmount) > user.limit) {
return user.checkedOverLimit ? false : true
}
}
return false
},
addingAmount(amount) {
clearTimeout(this.timeout)
this.toSetAmount = this.toSetAmount ? this.toSetAmount + amount : amount
if (this.checkOverLimitIsValid(this.user)) {
if (this.checkOverLimit(this.user) && this.user.autoLock) {
this.overLimitUser = this.user
} else {
this.timeout = setTimeout(() => {
this.addAmount(this.toSetAmount)
setTimeout(() => {
this.toSetAmount = null
}, 300)
}, 2000)
}
}
},
forceRender() {
this.componentRenderer += 1
},
getColor(value) {
return value >= 0 ? 'title green--text' : 'title red--text'
},
getAllSum() {
if (this.user)
return (
this.user.creditList[this.year][2].sum +
this.user.creditList[this.year][1].last
)
return 0
},
storno(message) {
if (!message.error) {
if (!this.under5minutes(message.date)) this.dialog = true
else {
this.checkValidate = true
this.stornoMessage = message
}
}
},
acceptStorno() {
this.commitStorno({
amount: this.stornoMessage.amount,
date: this.stornoMessage.date
})
setTimeout(() => {
this.cancelStorno()
}, 300)
},
cancelStorno() {
this.stornoMessage = null
this.checkValidate = null
},
addAmountMore() {
this.toSetAmount = this.toSetAmount
? this.toSetAmount + Math.round(Math.abs(this.value * 100))
: Math.round(Math.abs(this.value * 100))
if (this.checkOverLimitIsValid(this.user)) {
if (this.checkOverLimit(this.user) && this.user.autoLock) {
this.overLimitUser = this.user
}
else {
this.addAmount(Math.abs(this.value * 100))
setTimeout(() => {
this.value = null
}, 300)
}
}
},
createSum(message) {
var text = '' + (message.amount / 100).toFixed(2) + '€'
return text
},
createMessage(message) {
var text = ''
if (message.error) {
text =
' konnten nicht zu ' +
message.user.firstname +
' ' +
message.user.lastname +
' hinzufügen.'
} else {
text =
' wurde zu ' +
message.user.firstname +
' ' +
message.user.lastname +
' hinzugefügt.'
}
return text
}
},
computed: {
...mapGetters({
user: 'user/user',
year: 'user/year',
loading: 'user/loading',
addLoading: 'user/addLoading',
messages: 'user/messages'
}),
under5minutes() {
return now => {
var actual = new Date()
return actual - now < 15000
}
},
now() {
return now => {
var actual = new Date()
var zero = new Date(0)
var date = new Date(actual - now)
if (date.getFullYear() === zero.getFullYear()) {
if (date.getMonth() === zero.getMonth()) {
if (date.getDate() === zero.getDate()) {
if (date.getHours() === zero.getDate()) {
if (date.getMinutes() < 1) {
return 'vor ' + date.getSeconds() + ' Sekunden'
} else if (date.getMinutes() < 10) {
return 'vor ' + date.getMinutes() + ' Minuten'
} else {
return (
(now.getHours() < 10 ? '0' : '') +
now.getHours() +
':' +
(now.getMinutes() < 10 ? '0' : '') +
now.getMinutes()
)
}
} else {
return (
(now.getHours() < 10 ? '0' : '') +
now.getHours() +
':' +
(now.getMinutes() < 10 ? '0' : '') +
now.getMinutes()
)
}
}
}
}
return (
now.getDate() +
'.' +
now.getMonth() +
'.' +
now.getFullYear() +
' ' +
(now.getHours() < 10 ? '0' : '') +
now.getHours() +
':' +
(now.getMinutes() < 10 ? '0' : '') +
now.getMinutes()
)
}
}
},
beforeDestroy() {
clearInterval(this.timer)
}
}
</script>
<style scoped></style>

View File

@ -0,0 +1,458 @@
<template>
<div>
<v-card v-if="user" :loading="loading" style="margin-top: 3px">
<v-card-title>{{ user.firstname }} {{ user.lastname }}</v-card-title>
<v-card-text>
<v-row>
<v-col cols="12" sm="6">
<v-text-field
outlined
label="Vornamen"
:placeholder="user.firstname"
v-model="firstname"
readonly
/>
</v-col>
<v-col cols="12" sm="6">
<v-text-field
outlined
label="Nachname"
:placeholder="user.lastname"
v-model="lastname"
readonly
/>
</v-col>
</v-row>
<v-row>
<v-col cols="12" sm="6">
<v-text-field
outlined
label="Benutzername"
:placeholder="user.username"
v-model="username"
readonly
></v-text-field>
</v-col>
<v-col cols="12" sm="6">
<v-text-field
ref="mail"
outlined
label="E-Mail"
:placeholder="user.mail"
v-model="mail"
readonly
></v-text-field>
</v-col>
</v-row>
<v-row>
<v-col cols="12" sm="6">
<v-text-field
outlined
label="neues Password"
type="password"
v-model="password"
/>
</v-col>
<v-col cols="12" sm="6">
<v-form ref="newPassword">
<v-text-field
ref="password"
v-model="controlPassword"
outlined
label="neues Password bestätigen"
type="password"
:disabled="!password"
:rules="[equal_password]"
/>
</v-form>
</v-col>
</v-row>
<v-divider />
<v-row>
<v-col cols="12" sm="4">
<v-text-field
outlined
label="Sperrlimit"
readonly
:value="(user.limit / 100).toFixed(2).toString() + '€'"
/>
</v-col>
<v-col cols="12" sm="4">
<v-combobox
outlined
label="Sperrstatus"
v-model="lock"
append-icon
readonly
>
<template v-slot:selection="data">
<v-chip :color="lockColor">
{{ data.item }}
</v-chip>
</template>
</v-combobox>
</v-col>
<v-col cols="12" sm="4">
<v-combobox
outlined
label="Autosperre"
v-model="autoLock"
readonly
append-icon
>
<template v-slot:selection="data">
<v-chip :color="autoLockColor">
{{ data.item }}
</v-chip>
</template>
</v-combobox>
</v-col>
</v-row>
<v-row>
<v-col v-bind:class="{ fulllineText: isFulllineText }">
<v-combobox
outlined
multiple
label="Gruppen"
readonly
v-model="user.group"
append-icon
>
<template v-slot:selection="data">
<v-icon class="ma-2">{{
data.item === 'user'
? person
: data.item === 'bar'
? bar
: data.item === 'moneymaster'
? finanzer
: data.item === 'gastro'
? gastro
: ''
}}</v-icon>
</template>
</v-combobox>
</v-col>
<v-col v-bind:class="{ fulllineText: isFulllineText }">
<v-text-field
outlined
:value="computeStatus"
readonly
label="Mitgliedsstatus"
/>
</v-col>
<v-col v-bind:class="{ fulllineText: isFulllineText }">
<v-text-field
outlined
:value="user.voting ? 'ja' : 'nein'"
readonly
label="Stimmrecht"
/>
</v-col>
</v-row>
<v-row>
<v-col v-bind:class="{ fulllineText: isFulllineText }">
<v-combobox
chips
outlined
multiple
label="Arbeitsgruppen"
readonly
v-model="user.workgroups"
item-value="id"
item-text="name"
append-icon
>
<template v-slot:selection="data">
<v-chip>{{ data.item.name }}</v-chip>
</template>
</v-combobox>
</v-col>
</v-row>
<div class="subtitle-1">
Gespeicherte Sessions
</div>
<v-card v-for="token in tokens" :key="token.id" outlined>
<v-card-text>
<v-row>
<v-col>
<v-col>
Betriebssystem
</v-col>
<v-col>
<v-icon>
{{
token.platform === 'macos' || token.platform === 'iphone'
? apple
: token.platform === 'windows'
? windows
: token.platform === 'android'
? android
: token.platform === 'linux'
? linux
: token.platfrom
}}
</v-icon>
<v-icon
v-if="
token.platform === 'macos' || token.platform === 'iphone'
"
>
{{ token.platform === 'macos' ? mac : iphone }}
</v-icon>
</v-col>
</v-col>
<v-col>
<v-col>
Browser
</v-col>
<v-col>
<v-icon>
{{
token.browser === 'chrome'
? chrome
: token.browser === 'firefox'
? firefox
: token.browser === 'opera'
? opera
: token.browser === 'safari'
? safari
: token.browser === 'msie'
? msie
: token.browser
}}
</v-icon>
</v-col>
</v-col>
<v-col>
<v-col>
Letzte Aktualisierung
</v-col>
<v-col>
{{ token.timestamp.day }}.{{ token.timestamp.month }}.{{
token.timestamp.year
}}
um
{{
10 > token.timestamp.hour
? '0' + String(token.timestamp.hour)
: token.timestamp.hour
}}:{{
10 > token.timestamp.minute
? '0' + String(token.timestamp.minute)
: token.timestamp.minute
}}:{{
10 > token.timestamp.second
? '0' + String(token.timestamp.second)
: token.timestamp.second
}}</v-col
>
</v-col>
<v-col>
<v-col>
Lebenszeit
</v-col>
<v-col>
{{ calcLifefime(token.lifetime) }}
</v-col>
</v-col>
<v-col class="text-right">
<v-btn icon @click="deleteToken(token)">
<v-icon>
{{ trashCan }}
</v-icon>
</v-btn>
</v-col>
</v-row>
</v-card-text>
</v-card>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-form ref="acceptedPasswordTest">
<v-text-field
outlined
label="Passwort"
v-model="acceptedPassword"
type="password"
ref="acceptedPassword"
:rules="[empty_password]"
></v-text-field>
</v-form>
<v-btn text color="primary" @click="save">Speichern</v-btn>
</v-card-actions>
<v-snackbar
v-if="error ? error.value : false"
:color="error ? (error.error ? 'error' : 'success') : ''"
:value="error"
v-model="error"
:timeout="0"
>
{{ error ? error.value : null }}
</v-snackbar>
</v-card>
</div>
</template>
<script>
import {
mdiAccount,
mdiGlassCocktail,
mdiCurrencyEur,
mdiFoodForkDrink,
mdiApple,
mdiGoogleChrome,
mdiFirefox,
mdiOpera,
mdiInternetExplorer,
mdiAppleSafari,
mdiLaptopMac,
mdiCellphoneIphone,
mdiTrashCan,
mdiAndroid,
mdiWindows,
mdiLinux
} from '@mdi/js'
import { mapGetters, mapActions } from 'vuex'
export default {
name: 'Config',
data() {
return {
apple: mdiApple,
mac: mdiLaptopMac,
iphone: mdiCellphoneIphone,
android: mdiAndroid,
windows: mdiWindows,
linux: mdiLinux,
chrome: mdiGoogleChrome,
firefox: mdiFirefox,
opera: mdiOpera,
msie: mdiInternetExplorer,
safari: mdiAppleSafari,
person: mdiAccount,
bar: mdiGlassCocktail,
finanzer: mdiCurrencyEur,
gastro: mdiFoodForkDrink,
username: null,
mail: null,
firstname: null,
lastname: null,
password: null,
controlPassword: null,
trashCan: mdiTrashCan,
isFulllineText: false,
acceptedPassword: null,
passError: null,
equal_password: value =>
this.password === value || 'Passwörter sind nicht identisch.',
email: value => {
if (value.length > 0) {
const pattern = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
return pattern.test(value) || 'keine gültige E-Mail'
}
return true
},
empty_password: data => {
return !!data || 'Password wird bentögigt'
}
}
},
mounted() {
this.$nextTick(function() {
window.addEventListener('resize', this.getWindowWidth)
this.getWindowWidth()
})
},
methods: {
...mapActions({
saveConfig: 'user/saveConfig',
getStatus: 'user/getStatus',
getTokens: 'user/getTokens',
deleteToken: 'user/deleteToken'
}),
getWindowWidth() {
this.isFulllineText = document.documentElement.clientWidth <= 600
},
save() {
let user = {}
if (this.firstname) user.firstname = this.firstname
if (this.lastname) user.lastname = this.lastname
if (this.username) user.username = this.username
if (this.$refs.mail.validate()) {
if (this.mail) user.mail = this.mail
}
if (this.$refs.newPassword.validate()) {
if (this.password) user.password = this.password
} else {
return
}
console.log(this.$refs.acceptedPasswordTest.validate())
if (this.$refs.acceptedPasswordTest.validate()) {
this.saveConfig({
oldUsername: user.username,
...user,
acceptedPassword: this.acceptedPassword
})
this.$refs.acceptedPassword.reset()
} else {
this.passError = 'Du musst dein Password eingeben'
}
this.password = null
this.controlPassword = null
},
calcLifefime(time) {
if (time < 60) return String(time) + 'Sekunden'
time = Math.round(time / 60)
if (time < 60) return String(time) + 'Minuten'
time = Math.round(time / 60)
if (time < 24) return String(time) + 'Stunden'
time = Math.round(time / 24)
if (time < 7) return String(time) + 'Tage'
time = Math.round(time / 7)
if (time < 30) return String(time) + 'Wochen'
time = Math.round(time / 30)
if (time < 12) return String(time) + 'Monate'
time = Math.round(time / 12)
return String(time) + 'Jahre'
}
},
computed: {
...mapGetters({
user: 'user/user',
error: 'user/error',
loading: 'user/loading',
status: 'user/status',
tokens: 'user/tokens'
}),
lock() {
return this.user.locked ? 'gesperrt' : 'nicht gesperrt'
},
lockColor() {
return this.user.locked ? 'red' : 'green'
},
autoLock() {
return this.user.autoLock ? 'aktiviert' : 'deaktiviert'
},
autoLockColor() {
return this.user.autoLock ? 'green' : 'red'
},
computeStatus() {
try {
return this.status.find(a => a.id == this.user.statusgroup).name
} catch (e) {
return null
}
}
},
created() {
this.getStatus()
this.getTokens()
}
}
</script>
<style scoped>
.fulllineText {
flex-basis: unset;
}
</style>

View File

@ -0,0 +1,116 @@
<template>
<div>
<v-toolbar>
<v-toolbar-title>Gesamtübersicht</v-toolbar-title>
<v-spacer />
<v-toolbar-items>
<v-text-field
v-model="filter"
style="margin-top: 3px"
outlined
type="number"
:rules="[isNumber]"
>
<template v-slot:append>
<v-icon>{{magnify}}</v-icon>
</template>
</v-text-field>
</v-toolbar-items>
</v-toolbar>
<CreditOverviewSkeleton v-if="loading" />
<div v-for="year in years" :key="years.indexOf(year)">
<v-card style="margin-top: 3px" v-if="isFiltered(year)">
<v-card-title>{{ year }}</v-card-title>
<Table v-bind:user="user" v-bind:year="year" />
<v-container fluid>
<v-col>
<v-row>
<v-col>
<v-label>Vorjahr:</v-label>
</v-col>
<v-col>
<v-chip
outlined
:text-color="getLastColor(user.creditList[year][1].last)"
>{{ (user.creditList[year][1].last / 100).toFixed(2) }}
</v-chip>
</v-col>
<v-col>
<v-label>Gesamt:</v-label>
</v-col>
<v-col>
<v-chip
outlined
x-large
:text-color="
getLastColor(
getAllSum(
user.creditList[year][2].sum,
user.creditList[year][1].last
)
)
"
>
{{
(
getAllSum(
user.creditList[year][2].sum,
user.creditList[year][1].last
) / 100
).toFixed(2)
}}
</v-chip>
</v-col>
</v-row>
</v-col>
</v-container>
</v-card>
</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
import Table from '../finanzer/Table'
import CreditOverviewSkeleton from './Skeleton/CreditOverviewSkeleton'
import { mdiMagnify } from '@mdi/js'
export default {
name: 'CreditOverview',
components: { CreditOverviewSkeleton, Table },
data() {
return {
isNumber: value => Number.isInteger(parseInt(value === '' ? 0 : value)) || "Muss eine Zahl sein.",
filter: '',
magnify: mdiMagnify
}
},
methods: {
getLastColor(value) {
return value < 0 ? 'red' : 'green'
},
getAllSum(sum, lastYear) {
return lastYear + sum
},
isFiltered(value) {
return value.toString().includes(this.filter)
}
},
computed: {
...mapGetters({
user: 'user/user',
loading: 'user/loading'
}),
years() {
let years = []
if (this.user) {
for (let year in this.user.creditList) {
years.unshift(parseInt(year))
}
}
return years
}
}
}
</script>
<style scoped></style>

View File

@ -0,0 +1,208 @@
<template>
<div>
<v-card tile :loading="jobInvitesLoading">
<v-card-title>
Eingehende Einladungen
</v-card-title>
<v-card-text>
<v-expansion-panels>
<v-expansion-panel
v-for="jobInvite in jobInvitesToMe"
:key="jobInvite.id"
@click.once="seenJobIvnite(jobInvite)"
>
<v-expansion-panel-header>
<div>
{{ jobInvite.on_date.getDate() }}.{{
jobInvite.on_date.getMonth() + 1
}}.{{ jobInvite.on_date.getFullYear() }} von
<v-badge dot :value="!jobInvite.watched" color="red">
{{ jobInvite.from_user.firstname }}
{{ jobInvite.from_user.lastname }}
</v-badge>
</div>
<v-row class="text-right" style="margin-right: 5px">
<v-col>
<v-progress-circular
indeterminate
v-if="jobInvitesLoading"
></v-progress-circular>
</v-col>
<v-col>
<v-icon color="green" v-show="userInWorker(jobInvite)">
{{ check }}
</v-icon>
</v-col>
</v-row>
</v-expansion-panel-header>
<v-expansion-panel-content :eager="true">
<v-row class="text-right">
<v-col>
<v-btn icon @click="updatingJobInvite(jobInvite)">
<v-icon>
{{ jobInvite.watched ? seen : notSeen }}
</v-icon>
</v-btn>
</v-col>
</v-row>
<Day
:day="jobInvite.day"
:long="true"
:loading="jobInvite.day.loading"
@addingJob="addingJob(jobInvite, $event)"
@deletingJob="deletingJob(jobInvite, $event)"
@sendInvites="setJobInvites"
@sendRequests="setJobRequests"
@deleteJobInvite="deleteInvite"
@deleteJobRequest="deleteRequest"
/>
</v-expansion-panel-content>
</v-expansion-panel>
</v-expansion-panels>
</v-card-text>
</v-card>
<v-card tile :loading="jobInvitesLoading">
<v-card-title>
Versendete Einladungen
</v-card-title>
<v-card-text>
<v-expansion-panels>
<v-expansion-panel
v-for="jobInvite in jobInvitesFromMe"
:key="jobInvite.id"
@click.once="seenJobIvnite(jobInvite)"
>
<v-expansion-panel-header>
<div>
{{ jobInvite.on_date.getDate() }}.{{
jobInvite.on_date.getMonth() + 1
}}.{{ jobInvite.on_date.getFullYear() }} an
<v-badge :value="jobInvite.watched" icon="mdi-eye" color="grey" inline>
{{ jobInvite.to_user.firstname }}
{{ jobInvite.to_user.lastname }}
</v-badge>
</div>
<v-row class="text-right" style="margin-right: 5px">
<v-col>
<v-progress-circular
indeterminate
v-if="jobInvitesLoading"
></v-progress-circular>
</v-col>
<v-col>
<v-icon color="green" v-show="userInWorker(jobInvite)">
{{ check }}
</v-icon>
</v-col>
</v-row>
</v-expansion-panel-header>
<v-expansion-panel-content :eager="true">
<v-row class="text-right">
<v-col>
<v-btn icon @click="deleteInvite(jobInvite)">
<v-icon>
{{trashCan}}
</v-icon>
</v-btn>
</v-col>
</v-row>
<Day
:day="jobInvite.day"
:long="true"
:loading="jobInvite.day.loading"
@addingJob="addingJob(jobInvite, $event)"
@deletingJob="deletingJob(jobInvite, $event)"
@sendInvites="setJobInvites"
@sendRequests="setJobRequests"
@deleteJobInvite="deleteInvite"
@deleteJobRequest="deleteRequest"
/>
</v-expansion-panel-content>
</v-expansion-panel>
</v-expansion-panels>
</v-card-text>
</v-card>
</div>
</template>
<script>
import { mapActions, mapGetters } from 'vuex'
import { mdiEyeOff, mdiEyeCheck, mdiCheck, mdiTrashCan } from '@mdi/js'
import Day from '@/components/user/Jobs/Day'
export default {
name: 'JobInvites',
components: { Day },
data() {
return {
notSeen: mdiEyeOff,
seen: mdiEyeCheck,
check: mdiCheck,
trashCan: mdiTrashCan,
showNotSeen: false,
showSeen: false,
update: 0
}
},
methods: {
...mapActions({
getJobInvites: 'jobInvites/getJobInvites',
addJob: 'jobInvites/addJob',
setJobInvites: 'jobInvites/setJobInvites',
updateJobInviteToMe: 'jobInvites/updateJobInviteToMe',
deleteJob: 'jobInvites/deleteJob',
setJobRequests: 'jobRequests/setJobRequests',
deleteInvite: 'jobInvites/deleteJobInviteFromMe',
deleteRequest: 'jobRequests/deleteJobRequestFromMe'
}),
forceRender() {
setTimeout(() => {
this.update += 0
}, 500)
},
updatingJobInvite(jobInvite) {
jobInvite.watched = !jobInvite.watched
this.updateJobInviteToMe(jobInvite)
},
seenJobIvnite(jobInvite) {
if (!jobInvite.watched) {
jobInvite.watched = true
this.updateJobInviteToMe(jobInvite)
}
},
addingJob(jobInvite, event) {
this.seenJobIvnite(jobInvite)
this.addJob(event)
this.forceRender()
},
deletingJob(jobInvite, event) {
this.seenJobIvnite(jobInvite)
this.deleteJob(event)
this.forceRender()
},
userInWorker(jobinvite) {
var jobkinddate = jobinvite.day.jobkinddate.find(item => {
return item.worker.find(workeritem => {
return workeritem.id === jobinvite.to_user.id
})
})
return !!jobkinddate
}
},
computed: {
...mapGetters({
jobInvitesFromMe: 'jobInvites/jobInvitesFromMe',
jobInvitesToMe: 'jobInvites/jobInvitesToMe',
jobInvitesLoading: 'jobInvites/jobInvitesLoading',
activeUser: 'user/user'
})
},
created() {
setTimeout(() => {
this.getJobInvites(new Date())
}, 200)
}
}
</script>
<style scoped></style>

View File

@ -0,0 +1,224 @@
<template>
<div>
<v-card tile :loading="jobRequestsLoading">
<v-card-title>
Eingehende Anfragen
</v-card-title>
<v-card-text>
<v-expansion-panels>
<v-expansion-panel
v-for="(jobrequest, index) in jobRequestsToMe"
:key="index"
>
<v-expansion-panel-header @click.once="seenJobRequest(jobrequest)">
<div>
{{ jobrequest.on_date.getDate() }}.{{
jobrequest.on_date.getMonth() + 1
}}.{{ jobrequest.on_date.getFullYear() }} von
<v-badge dot :value="!jobrequest.watched" color="red">
{{ jobrequest.from_user.firstname }}
{{ jobrequest.from_user.lastname }}
</v-badge>
</div>
<v-row class="text-right" style="margin-right: 5px">
<v-col>
<v-progress-circular
indeterminate
v-if="jobRequestsLoading"
></v-progress-circular>
</v-col>
<v-col>
<v-icon color="green" v-show="userInWorker(jobrequest)">
{{ check }}
</v-icon>
</v-col>
</v-row>
</v-expansion-panel-header>
<v-expansion-panel-content>
<v-row class="text-right">
<v-col>
<v-btn icon @click="updatingSeenJobRequest(jobrequest)">
<v-icon>
{{ jobrequest.watched ? seen : notSeen }}
</v-icon>
</v-btn>
</v-col>
</v-row>
<Day
:day="jobrequest.day"
:long="true"
@sendRequests="sendingJobRequests(jobrequest, $event)"
@addingJob="addJob"
@deletingJob="deleteJob"
@sendInvites="setJobInvites"
@deleteJobInvite="deleteInvite"
@deleteJobRequest="deleteJobRequestFromMe"
/>
<v-row class="text-right">
<v-col>
<v-btn
v-show="!jobrequest.answered"
text
@click="updatingAcceptedJobRequest(jobrequest)"
>Annehmen</v-btn
>
<div v-show="jobrequest.answered && !jobrequest.accepted">
Dieser Dienst wurde schon übertragen.
</div>
</v-col>
</v-row>
</v-expansion-panel-content>
</v-expansion-panel>
</v-expansion-panels>
</v-card-text>
</v-card>
<v-card tile :loading="jobRequestsLoading">
<v-card-title>
Ausgehende Anfragen
</v-card-title>
<v-card-text>
<v-expansion-panels>
<v-expansion-panel
v-for="(jobrequest, index) in jobRequestsFromMe"
:key="index"
>
<v-expansion-panel-header>
<div>
{{ jobrequest.on_date.getDate() }}.{{
jobrequest.on_date.getMonth() + 1
}}.{{ jobrequest.on_date.getFullYear() }} an
<v-badge :value="jobrequest.watched" icon="mdi-eye" color="grey" inline>
{{ jobrequest.to_user.firstname }}
{{ jobrequest.to_user.lastname }}
</v-badge>
</div>
<v-row class="text-right" style="margin-right: 5px">
<v-col>
<v-progress-circular
indeterminate
v-if="jobRequestsLoading"
></v-progress-circular>
</v-col>
<v-col>
<v-icon color="green" v-show="jobrequest.accepted">
{{ check }}
</v-icon>
</v-col>
</v-row>
</v-expansion-panel-header>
<v-expansion-panel-content>
<v-row class="text-right">
<v-col>
<v-btn icon @click="deleteJobRequestFromMe(jobrequest)">
<v-icon>
{{trashCan}}
</v-icon>
</v-btn>
</v-col>
</v-row>
<Day
:day="jobrequest.day"
:long="true"
@sendRequests="sendingJobRequests(jobrequest, $event)"
@addingJob="addJob"
@deletingJob="deleteJob"
@sendInvites="setJobInvites"
@deleteJobInvite="deleteInvite"
@deleteJobRequest="deleteJobRequestFromMe"
/>
</v-expansion-panel-content>
</v-expansion-panel>
</v-expansion-panels>
</v-card-text>
</v-card>
</div>
</template>
<script>
import { mapGetters, mapActions } from 'vuex'
import { mdiEyeOff, mdiEyeCheck, mdiCheck, mdiTrashCan } from '@mdi/js'
import Day from '@/components/user/Jobs/Day'
export default {
name: 'JobTransfer',
components: { Day },
props: {},
data() {
return {
notSeen: mdiEyeOff,
seen: mdiEyeCheck,
check: mdiCheck,
trashCan: mdiTrashCan,
}
},
methods: {
...mapActions({
getJobRequests: 'jobRequests/getJobRequests',
updateJobRequestToMe: 'jobRequests/updateJobRequestToMe',
setJobRequests: 'jobRequests/setJobRequests',
deleteJobRequestFromMe: 'jobRequests/deleteJobRequestFromMe',
deleteInvite: 'jobInvites/deleteJobInviteFromMe',
getJobInvites: 'jobInvites/getJobInvites',
addJob: 'jobInvites/addJob',
setJobInvites: 'jobInvites/setJobInvites',
updateJobInviteToMe: 'jobInvites/updateJobInviteToMe',
deleteJob: 'jobInvites/deleteJob',
}),
updatingAcceptedJobRequest(jobRequest) {
jobRequest.accepted = true
jobRequest.answered = true
this.updateJobRequestToMe({ ...jobRequest })
setTimeout(() => {
this.getJobRequests(), 200
})
},
updatingSeenJobRequest(jobRequest) {
jobRequest.watched = !jobRequest.watched
this.updateJobRequestToMe({ ...jobRequest })
},
seenJobRequest(jobRequest) {
if (!jobRequest.watched) {
jobRequest.watched = true
this.updateJobRequestToMe(jobRequest)
}
},
userInWorker(jobrequest) {
var jobkinddate = jobrequest.day.jobkinddate.find(item => {
return item.worker.find(workeritem => {
return workeritem.id === this.activeUser.id
})
})
return !!jobkinddate
},
sendingJobRequests(jobrequest, event) {
this.seenJobRequest(jobrequest)
this.setJobRequests(event)
}
},
computed: {
...mapGetters({
jobRequestsToMe: 'jobRequests/jobRequestsToMe',
jobRequestsFromMe: 'jobRequests/jobRequestsFromMe',
jobRequestsLoading: 'jobRequests/jobRequestsLoading',
loading: 'user/loading',
activeUser: 'user/user'
})
},
created() {
if (!this.loading) {
this.getJobRequests()
}
},
watch: {
loading(newValue) {
if (!newValue) {
this.getJobRequests()
}
},
jobRequestsLoading(newValue, oldValue) {
console.log(newValue, oldValue)
}
}
}
</script>
<style scoped></style>

View File

@ -0,0 +1,192 @@
<template>
<div>
<v-toolbar>
<v-toolbar-title>Dienstübersicht</v-toolbar-title>
<v-spacer />
<v-toolbar-items>
<v-btn
text
icon
:to="{
name: 'userJobs',
params: { year: date.getFullYear(), month: date.getMonth() }
}"
>
<v-icon>{{ keyboard_arrow_left }}</v-icon>
</v-btn>
<v-list-item>
<v-list-item-title class="title">
{{ monthArray[date.getMonth()] }}
{{ date.getFullYear() }}
</v-list-item-title>
</v-list-item>
<v-btn
text
icon
:to="{
name: 'userJobs',
params: { year: date.getFullYear(), month: date.getMonth() + 2 }
}"
>
<v-icon>{{ keyboard_arrow_right }}</v-icon>
</v-btn>
</v-toolbar-items>
<v-spacer />
</v-toolbar>
<v-card v-for="week in month" :key="month.indexOf(week)" flat tile>
<v-card-title class="subtitle-1 font-weight-bold">
Woche vom {{ week.startDate.getDate() }}.{{
week.startDate.getMonth() + 1
}}.{{ week.startDate.getFullYear() }} bis
{{ week.endDate.getDate() }}.{{ week.endDate.getMonth() + 1 }}.{{
week.endDate.getFullYear()
}}
</v-card-title>
<v-card-text>
<v-row justify="start" align="start">
<div v-for="day in week.days" :key="day.id">
<v-col cols="12">
<Day
:day="day"
:long="false"
@addingJob="addJob"
@sendInvites="setJobInvites"
@deletingJob="deleteJob"
@sendRequests="setJobRequests"
@deleteJobInvite="deleteInvite"
@deleteJobRequest="deleteRequest"
/>
</v-col>
</div>
</v-row>
</v-card-text>
</v-card>
</div>
</template>
<script>
import { mdiChevronLeft, mdiChevronRight } from '@mdi/js'
import { mapGetters, mapActions } from 'vuex'
import Day from '@/components/user/Jobs/Day'
export default {
name: 'Jobs',
components: { Day },
data() {
return {
keyboard_arrow_left: mdiChevronLeft,
keyboard_arrow_right: mdiChevronRight,
date: new Date(this.$route.params.year, this.$route.params.month - 1, 1),
monthArray: [
'Januar',
'Februar',
'März',
'April',
'Mai',
'Juni',
'Juli',
'August',
'September',
'Oktober',
'November',
'Dezember'
]
}
},
created() {
this.getActiveUser()
this.getAllJobKinds()
this.createMonth(this.date)
this.getDBUsers()
this.getUsers({
from_date: {
year: this.startDate.getFullYear(),
month: this.startDate.getMonth() + 1,
day: this.startDate.getDate()
},
to_date: {
year: this.endDate.getFullYear(),
month: this.endDate.getMonth() + 1,
day: this.endDate.getDate()
}
})
},
methods: {
...mapActions({
getActiveUser: 'user/getUser',
createMonth: 'jobs/createMonth',
getUsers: 'jobs/getUsers',
getDBUsers: 'usermanager/getUsers',
getAllJobKinds: 'jkm/getAllJobKinds',
addJob: 'jobs/addJob',
deleteJob: 'jobs/deleteJob',
setJobInvites: 'jobInvites/setJobInvites',
getJobInvites: 'jobInvites/getJobInvites',
getJobRequests: 'jobRequests/getJobRequests',
setJobRequests: 'jobRequests/setJobRequests',
deleteInvite: 'jobInvites/deleteJobInviteFromMe',
deleteRequest: 'jobRequests/deleteJobRequestFromMe'
}),
changeMonth(value) {
if (value === -1) {
this.date = new Date(this.date.getFullYear(), this.date.getMonth() - 1)
} else {
this.date = new Date(this.date.getFullYear(), this.date.getMonth() + 1)
}
this.createMonth(this.date)
this.getUsers({
from_date: {
year: this.startDate.getFullYear(),
month: this.startDate.getMonth() + 1,
day: this.startDate.getDate()
},
to_date: {
year: this.endDate.getFullYear(),
month: this.endDate.getMonth() + 1,
day: this.endDate.getDate()
}
})
}
},
computed: {
...mapGetters({
month: 'jobs/month',
startDate: 'jobs/getStartDate',
endDate: 'jobs/getEndDate',
loading: 'user/loading'
})
},
watch: {
$route() {
this.getActiveUser()
this.date = new Date(
this.$route.params.year,
this.$route.params.month - 1,
1
)
this.getAllJobKinds()
this.createMonth(this.date)
this.getDBUsers()
this.getUsers({
from_date: {
year: this.startDate.getFullYear(),
month: this.startDate.getMonth() + 1,
day: this.startDate.getDate()
},
to_date: {
year: this.endDate.getFullYear(),
month: this.endDate.getMonth() + 1,
day: this.endDate.getDate()
}
})
},
loading(newValue) {
if (!newValue) {
this.getJobInvites()
this.getJobRequests()
}
}
}
}
</script>
<style scoped></style>

View File

@ -0,0 +1,438 @@
<template>
<div v-if="day">
<v-card :color="color(day)" :max-width="long ? '' : '20em'">
<v-card-title v-if="day.date" class="subtitle-1 font-weight-bold">
{{ name }} den {{ day.date.getDate() }}.{{ day.date.getMonth() + 1 }}.{{
day.date.getFullYear()
}}
</v-card-title>
<v-card-text>
<v-expand-transition>
<v-row align="center" justify="center" v-if="day.loading">
<v-progress-circular indeterminate color="grey" />
</v-row>
</v-expand-transition>
<v-expand-transition>
<div v-show="!day.loading">
<div
v-for="(jobkinddateitem, index) in day.jobkinddate"
:key="index"
>
<div class="title black--text text-sm-center">
{{ jobkinddateitem.job_kind.name }}
</div>
<v-combobox
multiple
filled
disabled
readonly
:counter="jobkinddateitem.maxpersons"
v-model="jobkinddateitem.worker"
:item-text="item => item.firstname + ' ' + item.lastname"
item-value="username"
chips
append-icon=""
>
<template v-slot:selection="data">
<v-chip
>{{ data.item.firstname }} {{ data.item.lastname }}</v-chip
>
</template>
</v-combobox>
</div>
</div>
</v-expand-transition>
</v-card-text>
<v-card-actions class="text--secondary" v-if="!day.loading" :key="update">
<v-spacer />
<v-menu
v-model="menu"
open-on-hover
close-on-click
close-on-content-click
offset-y
>
<template v-slot:activator="{ on }">
<v-btn
text
v-on="on"
v-show="filterAddJob.length > 0 && !userInWorker() && !day.locked"
>
Eintragen
</v-btn>
</template>
<v-list>
<v-list-item
v-for="(jobkinddateitem, index) in filterAddJob"
:key="index"
@click="addingJob(jobkinddateitem)"
>
<v-list-item-title>
{{ jobkinddateitem.job_kind.name }}
</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
<v-menu v-model="menu_invite" :close-on-content-click="false" offset-y>
<template v-slot:activator="{ on }">
<v-btn
v-show="
jobkindWithSpace.length !== 0 && !day.locked && userInWorker()
"
text
v-on="on"
>Einladen</v-btn
>
</template>
<v-card :loading="jobInvitesLoading">
<v-card-title>
Einladungen
</v-card-title>
<v-card-text>
<v-div
bottom
v-for="(invite, index) in getInvites(day.date)"
:key="index"
>
<v-chip style="margin: 5px">
{{ invite.to_user.firstname }}
{{ invite.to_user.lastname }}
</v-chip>
</v-div>
<v-divider style="margin-bottom: 5px" />
<v-autocomplete
v-model="job_invites"
label="Einladungen senden an"
return-object
multiple
filled
:item-text="item => item.firstname + ' ' + item.lastname"
item-value="id"
chips
deletable-chips
:items="filteredDBUsers()"
>
</v-autocomplete>
</v-card-text>
<v-card-actions>
<v-spacer />
<v-btn
text
:disabled="job_invites.length === 0"
@click="sendInvites()"
>
{{ job_invites.length >= 1 ? 'Einladungen' : 'Einladung' }}
senden
</v-btn>
</v-card-actions>
</v-card>
</v-menu>
<v-menu
v-model="menu_request"
:close-on-content-click="false"
offset-y
v-if="day.locked && userInWorker()"
>
<template v-slot:activator="{ on }">
<v-btn v-show="day.locked && userInWorker()" text v-on="on">
Abgeben
</v-btn>
</template>
<v-card :loading="jobRequestsLoading">
<v-card-title>
Dienstabgabenanfrage
</v-card-title>
<v-card-text>
<div v-if="jobRequestsLoading">
<v-progress-circular indeterminate />
</div>
<div v-if="!jobRequestsLoading">
<v-div
bottom
v-for="(request, index) in getRequests(day.date)"
:key="index"
>
<v-chip style="margin: 5px">
{{ request.to_user.firstname }}
{{ request.to_user.lastname }}
</v-chip>
</v-div>
</div>
<v-divider style="margin-bottom: 5px" />
<v-autocomplete
v-model="job_requests"
label="Anfragen senden an"
return-object
multiple
filled
:item-text="item => item.firstname + ' ' + item.lastname"
item-value="id"
chips
deletable-chips
:items="filteredDBUsersWithJobKind()"
>
</v-autocomplete>
</v-card-text>
<v-card-actions>
<v-spacer />
<v-btn text @click="sendRequests()">
Anfragen
</v-btn>
</v-card-actions>
</v-card>
</v-menu>
<v-btn
v-show="!day.locked && userInWorker()"
text
@click="deletingJob()"
>Austragen</v-btn
>
</v-card-actions>
</v-card>
</div>
</template>
<script>
import { mapGetters, mapActions } from 'vuex'
import { mdiAccountPlus } from '@mdi/js'
export default {
name: 'Day',
props: {
day: Object,
long: Boolean,
loading: Boolean
},
data() {
return {
account_add: mdiAccountPlus,
searchInput: null,
requestUser: null,
menu: false,
menu_invite: false,
menu_request: false,
update: 0,
job_invites: [],
job_requests: []
}
},
created() {
//setInterval(() => {console.log(this.day.loading)},100)
},
methods: {
...mapActions({}),
sendInvites() {
var sendData = []
this.job_invites.forEach(item => {
sendData.push({
from_user: this.activeUser,
to_user: item,
date: {
year: this.day.date.getFullYear(),
month: this.day.date.getMonth() + 1,
day: this.day.date.getDate()
}
})
})
this.$emit('sendInvites', sendData)
setTimeout(() => {
this.job_invites = []
}, 200)
this.menu_invite = false
},
sendRequests() {
var sendData = []
this.job_requests.forEach(item => {
sendData.push({
from_user: this.activeUser,
to_user: item,
date: {
year: this.day.date.getFullYear(),
month: this.day.date.getMonth() + 1,
day: this.day.date.getDate()
},
job_kind: this.getJob_Kind()
})
})
this.$emit('sendRequests', sendData)
setTimeout(() => {
this.job_requests = []
}, 200)
this.menu_request = false
},
color: day => {
if (day) {
if (day.date.getDay() === 0 || day.date.getDay() === 1) {
return 'grey lighten-4'
} else {
var retVal = 'yellow'
retVal = 'light-green'
for (var jobkind in day.jobkinddate) {
if (
day.jobkinddate[jobkind].worker.length >=
day.jobkinddate[jobkind].maxpersons
)
retVal = 'light-green'
else return 'yellow'
}
return retVal
}
} else {
return 'grey lighten-4'
}
},
user(worker) {
return worker.username === this.activeUser.username
},
addingJob(jobkinddateitem) {
this.$emit('addingJob', {
year: this.day.date.getFullYear(),
month: this.day.date.getMonth() + 1,
day: this.day.date.getDate(),
job_kind: jobkinddateitem.job_kind
})
this.menu = false
setTimeout(() => {
this.update += 1
}, 200)
},
deletingJob() {
this.$emit('deletingJob', {
year: this.day.date.getFullYear(),
month: this.day.date.getMonth() + 1,
day: this.day.date.getDate()
})
setTimeout(() => {
this.update += 1
})
},
userInWorker() {
var jobkinddate = this.day.jobkinddate.find(item => {
return item.worker.find(workeritem => {
return workeritem.id === this.activeUser.id
})
})
return !!jobkinddate
},
deletingInvite(jobInvite) {
let sendData = { ...jobInvite }
sendData.on_date = {
year: sendData.on_date.getFullYear(),
month: sendData.on_date.getMonth() + 1,
day: sendData.on_date.getDate()
}
this.$emit('deleteJobInvite', sendData)
},
deletingRequest(jobRequest) {
let sendData = { ...jobRequest }
sendData.on_date = {
year: sendData.on_date.getFullYear(),
month: sendData.on_date.getMonth() + 1,
day: sendData.on_date.getDate()
}
this.$emit('deleteJobRequest', sendData)
this.menu_request = false
setTimeout(() => {
this.menu_request = true
}, 200)
},
getJob_Kind() {
var jobkinddate = this.day.jobkinddate.find(item => {
return item.worker.find(user => {
return this.activeUser.id === user.id
})
})
return jobkinddate.job_kind
},
filteredDBUsersWithJobKind() {
var retVal = this.filteredDBUsers()
var job_kind = this.getJob_Kind()
retVal = retVal.filter(user => {
if (job_kind.workgroup ? job_kind.workgroup.if === null : true) {
return true
} else {
if (user.workgroups ? user.workgroups.length > 0 : false) {
return user.workgroups.find(wg => {
return wg.id === job_kind.workgroup.id
})
}
}
return false
})
return retVal
},
filteredDBUsers() {
var retVal = this.allUsers.filter(user => {
var test = this.day.jobkinddate.find(item => {
return item.worker.find(workeritem => {
return workeritem.id === user.id
})
})
return !test
})
retVal = retVal.filter(user => {
let getedDay = this.getDay(this.day.date)
let test = getedDay
? getedDay.find(day => {
return day.to_user.id === user.id
})
: false
return !test
})
return retVal
}
},
computed: {
...mapGetters({
activeUser: 'user/user',
allUsers: 'usermanager/users',
getDay: 'jobInvites/getDayFromMe',
getInvites: 'jobInvites/getDayWorkerFromMe',
getRequests: 'jobRequests/getDayWorkerFromMe',
jobInvitesLoading: 'jobInvites/jobInvitesLoading',
jobRequestsLoading: 'jobRequests/jobRequestsLoading'
}),
jobkindWithSpace() {
var retVal = this.day.jobkinddate.filter(item => {
if (item.maxpersons <= item.worker.length) return false
else return true
})
return retVal
},
filterAddJob() {
var retVal = this.day.jobkinddate.filter(item => {
if (item.maxpersons <= item.worker.length) {
return false
}
if (!item.job_kind.workgroup) {
return true
} else {
if (this.activeUser.workgroups) {
return this.activeUser.workgroups.find(workgroup => {
return workgroup.id === item.job_kind.workgroup.id
})
}
}
})
return retVal
},
name() {
const name = this.day.date.getDay()
if (name === 0) return 'Sonntag'
else if (name === 1) return 'Montag'
else if (name === 2) return 'Dienstag'
else if (name === 3) return 'Mittwoch'
else if (name == 4) return 'Donnerstag'
else if (name === 5) return 'Freitag'
else return 'Samstag'
},
dayLoading() {
return this.loading
}
}
}
</script>
<style scoped></style>

View File

@ -0,0 +1,55 @@
<template>
<div>
<v-bottom-navigation v-model="bottom_nav">
<v-btn :to="{ name: 'jobRequests', params: { kind: 'jobInvites' } }">
<v-badge color="red" :content="newsInvite" :value="newsInvite !== 0">
Diensteinladungen
</v-badge>
</v-btn>
<v-btn :to="{ name: 'jobRequests', params: { kind: 'jobTransfer' } }">
<v-badge color="red" :content="newsRequest" :value="newsRequest !== 0">Dienstübertragung</v-badge>
</v-btn>
</v-bottom-navigation>
<JobInvites v-if="kind === 'jobInvites'"></JobInvites>
<JobTransfer v-if="kind === 'jobTransfer'"></JobTransfer>
</div>
</template>
<script>
import JobInvites from '@/components/user/JobRequests/JobInvites'
import JobTransfer from '@/components/user/JobRequests/JobTransfer'
import { mapActions, mapGetters } from 'vuex'
export default {
name: 'JobsRequest',
components: { JobTransfer, JobInvites },
data() {
return {
bottom_nav: true,
kind: this.$route.params.kind
}
},
methods: {
...mapActions({
getUser: 'user/getUser',
getDBUsers: 'usermanager/getUsers',
})
},
computed: {
...mapGetters({
newsInvite: 'jobInvites/news',
newsRequest: 'jobRequests/news'
})
},
created() {
this.getUser()
this.getDBUsers()
},
watch: {
$route() {
this.kind = this.$route.params.kind
}
}
}
</script>
<style scoped></style>

View File

@ -0,0 +1,50 @@
<template>
<v-card>
<v-card-title>
<v-skeleton-loader type="heading" />
</v-card-title>
<v-card-text>
<v-row>
<v-col cols="10">
<v-row>
<v-col>
<v-skeleton-loader type="button" />
</v-col>
<v-col>
<v-skeleton-loader type="button" />
</v-col>
<v-col>
<v-skeleton-loader type="button" />
</v-col>
</v-row>
<v-row>
<v-col>
<v-skeleton-loader type="button" />
</v-col>
<v-col>
<v-skeleton-loader type="button" />
</v-col>
<v-col>
<v-skeleton-loader type="button" />
</v-col>
</v-row>
</v-col>
<v-col align-self="center">
<v-row>
<v-list-item>
<v-skeleton-loader type="chip" />
</v-list-item>
</v-row>
</v-col>
</v-row>
</v-card-text>
</v-card>
</template>
<script>
export default {
name: 'AddAmountSkeleton'
}
</script>
<style scoped></style>

View File

@ -0,0 +1,35 @@
<template>
<v-card style="margin-top: 3px">
<v-card-title><v-skeleton-loader type="heading"/></v-card-title>
<v-container>
<v-skeleton-loader type="table-thead" />
<v-skeleton-loader type="table-row-divider@3" />
</v-container>
<v-container fluid>
<v-col>
<v-row>
<v-col>
<v-skeleton-loader type="chip" />
</v-col>
<v-col>
<v-skeleton-loader type="chip" />
</v-col>
<v-col>
<v-skeleton-loader type="chip" />
</v-col>
<v-col>
<v-skeleton-loader type="chip" />
</v-col>
</v-row>
</v-col>
</v-container>
</v-card>
</template>
<script>
export default {
name: 'CreditOverviewSkeleton'
}
</script>
<style scoped></style>

View File

@ -0,0 +1,109 @@
<template>
<v-list>
<v-list-item link to="/main/user/add">
<v-list-item-icon>
<v-icon>{{ account }}</v-icon>
</v-list-item-icon>
<v-list-item-title>
Home
</v-list-item-title>
</v-list-item>
<v-list-item link :to="{ name: 'userOverview' }">
<v-list-item-icon>
<v-icon>{{ bank }}</v-icon>
</v-list-item-icon>
<v-list-item-title>Finanzübersicht</v-list-item-title>
</v-list-item>
<v-list-item
link
:to="{
name: 'userJobs',
params: {
year: new Date().getFullYear(),
month: new Date().getMonth() + 1
}
}"
>
<v-list-item-icon>
<v-icon>
{{ briefcase }}
</v-icon>
</v-list-item-icon>
<v-list-item-title>Dienstübersicht</v-list-item-title>
</v-list-item>
<v-list-item
link
:to="{ name: 'jobRequests', params: { kind: 'jobInvites' } }"
>
<v-list-item-icon>
<v-badge overlap color="red" :content="news" :value="news !== 0">
<v-icon>
{{ switchAccount }}
</v-icon>
</v-badge>
</v-list-item-icon>
<v-list-item-title>Dienstanfragen</v-list-item-title>
</v-list-item>
<v-list-item link :to="{ name: 'userConfig' }">
<v-list-item-icon>
<v-icon>{{ account_card_details }}</v-icon>
</v-list-item-icon>
<v-list-item-title>Einstellung</v-list-item-title>
</v-list-item>
</v-list>
</template>
<script>
import {
mdiAccountCardDetails,
mdiHome,
mdiBank,
mdiBriefcase,
mdiAccountSwitch
} from '@mdi/js'
import { mapGetters, mapActions } from 'vuex'
export default {
name: 'UserNavigation',
data() {
return {
account_card_details: mdiAccountCardDetails,
account: mdiHome,
bank: mdiBank,
briefcase: mdiBriefcase,
switchAccount: mdiAccountSwitch
}
},
methods: {
...mapActions({
getJobInvites: 'jobInvites/getJobInvites',
getJobRequests: 'jobRequests/getJobRequests',
getUser: 'user/getUser'
})
},
computed: {
...mapGetters({
newsInvite: 'jobInvites/news',
newsRequest: 'jobRequests/news',
loading: 'user/loading'
}),
news() {
return this.newsInvite + this.newsRequest
}
},
created() {
this.getUser()
},
watch: {
loading(newValue) {
if (!newValue) {
this.getJobInvites()
this.getJobRequests()
}
}
}
}
</script>
<style scoped></style>

View File

@ -0,0 +1,171 @@
<template>
<div>
<v-data-table
:items="jobkinds"
:headers="header"
:loading="jobkindsLoading || workgroupsLoading"
:search="search"
>
<template v-slot:top>
<v-toolbar flat color="white">
<v-toolbar-title>
Dienstarten
</v-toolbar-title>
<v-spacer />
<v-text-field
v-model="search"
label="Suche Dienstart"
single-line
hide-details
>
<template v-slot:append>
<v-icon>{{ searchIcon }}</v-icon>
</template>
</v-text-field>
<v-btn fab small color="primary" @click="add()">
<v-icon>{{ plusIcon }}</v-icon>
</v-btn>
</v-toolbar>
</template>
<template v-slot:item.workgroup="{ item }">
{{ item.workgroup === null ? 'Alle' : item.workgroup.name }}
</template>
<template v-slot:item.actions="{item}">
<v-icon x-small @click="editJobKind(item)">{{editIcon}}</v-icon>
<v-icon x-small @click="deleteJobKind(item)">{{deleteIcon}}</v-icon>
</template>
</v-data-table>
<v-dialog v-model="dialog">
<v-card>
<v-card-title>
{{ title }}
</v-card-title>
<v-card-text>
<v-row>
<v-col>
<v-text-field outlined label="Name" v-model="editedItem.name" />
</v-col>
<v-col>
<v-autocomplete
outlined
return-object
label="Arbeitsgruppe"
v-model="editedItem.workgroup"
item-text="name"
item-value="id"
:items="[...workgroups, { id: -1, name: 'Alle' }]"
/>
</v-col>
</v-row>
</v-card-text>
<v-card-actions>
<v-spacer />
<v-btn text color="primary" @click="close()">Abbrechen</v-btn>
<v-btn text color="primary" @click="save()">Speichern</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</div>
</template>
<script>
import { mapGetters, mapActions } from 'vuex'
import { mdiPencil, mdiDelete, mdiPlus, mdiMagnify } from '@mdi/js'
export default {
name: 'JobKindManager',
data() {
return {
search: null,
editIcon: mdiPencil,
deleteIcon: mdiDelete,
plusIcon: mdiPlus,
searchIcon: mdiMagnify,
dialog: false,
header: [
{ text: 'Name', value: 'name' },
{ text: 'Zugewiesene Arbeitsgruppe', value: 'workgroup' },
{
text: 'Aktionen',
value: 'actions',
filterable: false,
sortable: false
}
],
editedItem: {
id: -1,
name: null,
workgroup: {
id: -1,
name: null
}
},
defaultItem: {
id: -1,
name: null,
workgroup: {
id: -1,
name: null
}
}
}
},
methods: {
...mapActions({
getAllJobKinds: 'jkm/getAllJobKinds',
addingJobKind: 'jkm/addJobKind',
updateJobKind: 'jkm/updateJobKind',
deletingJobKind: 'jkm/deleteJobKind',
getAllWorkgroups: 'wm/getAllWorkgroups'
}),
add() {
this.dialog = true
},
editJobKind(jobkind) {
this.dialog = true
this.editedItem = Object.assign({}, jobkind)
if (this.editedItem.workgroup === null) {
this.editedItem.workgroup = Object.assign({}, this.defaultItem.workgroup)
}
},
deleteJobKind(jobkind) {
confirm('Willst du diese Dienstart wirklich löschen') &&
this.deletingJobKind(jobkind)
this.close()
},
close() {
setTimeout(() => {
this.editedItem = Object.assign({}, this.defaultItem)
this.dialog = false
}, 200)
},
save() {
if (this.editedItem.workgroup.id === -1)
this.editedItem.workgroup = null
this.editedItem.id === -1
? this.addingJobKind(this.editedItem)
: this.updateJobKind(this.editedItem)
this.close()
}
},
computed: {
...mapGetters({
jobkinds: 'jkm/jobkinds',
jobkindsLoading: 'jkm/jobkindsLoading',
workgroups: 'wm/workgroups',
workgroupsLoading: 'wm/workgroupLoading'
}),
title() {
return this.editedItem.id === -1
? 'Neue Dienstart erstellen'
: 'Dienstart bearbeiten'
}
},
created() {
this.getAllJobKinds()
this.getAllWorkgroups()
console.log(this.jobkinds)
}
}
</script>
<style scoped></style>

View File

@ -0,0 +1,52 @@
<template>
<v-list>
<v-list-item link :to="{name: 'serviceManagement', params: {year: new Date().getFullYear(), month: new Date().getMonth() + 1}}"> <v-list-item-icon>
<v-icon>{{ work }}</v-icon>
</v-list-item-icon>
<v-list-item-title>
Dienstverwaltung
</v-list-item-title>
</v-list-item>
<v-list-item link :to="{name: 'userManager'}">
<v-list-item-icon>
<v-icon>{{list}}</v-icon>
</v-list-item-icon>
<v-list-item-title>
Benutzerliste
</v-list-item-title>
</v-list-item>
<v-list-item link :to="{name: 'workgroupManagement'}">
<v-list-item-icon>
<v-icon>{{group}}</v-icon>
</v-list-item-icon>
<v-list-item-title>
Arbeitsgruppen
</v-list-item-title>
</v-list-item>
<v-list-item link :to="{name: 'jobkindManagement'}">
<v-list-item-icon>
<v-icon>{{jobs}}</v-icon>
</v-list-item-icon>
<v-list-item-title>
Dienstarten
</v-list-item-title>
</v-list-item>
</v-list>
</template>
<script>
import { mdiBriefcase, mdiAccountMultiple, mdiAccountGroup, mdiAccountNetwork } from '@mdi/js'
export default {
name: 'ManagementNavigation',
data() {
return {
work: mdiBriefcase,
list: mdiAccountMultiple,
group: mdiAccountGroup,
jobs: mdiAccountNetwork
}
}
}
</script>
<style scoped></style>

View File

@ -0,0 +1,169 @@
<template>
<div>
<v-toolbar>
<v-toolbar-title>Dienstverwaltung</v-toolbar-title>
<v-spacer />
<v-toolbar-items>
<v-btn text icon :to="{name: 'serviceManagement', params: {year: date.getFullYear(), month: date.getMonth()}}">
<v-icon>{{ keyboard_arrow_left }}</v-icon>
</v-btn>
<v-list-item>
<v-list-item-title class="title">
{{ monthArray[date.getMonth()] }}
{{ date.getFullYear() }}
</v-list-item-title>
</v-list-item>
<v-btn text icon :to="{name: 'serviceManagement', params: {year: date.getFullYear(), month: date.getMonth() + 2}}">
<v-icon>{{ keyboard_arrow_right }}</v-icon>
</v-btn>
</v-toolbar-items>
<v-spacer />
<v-toolbar-items>
<v-btn text @click="lockDays(true)">Monat sperren</v-btn>
<v-btn text @click="lockDays(false)">Monat freigeben</v-btn>
</v-toolbar-items>
</v-toolbar>
<v-card v-for="week in month" :key="month.indexOf(week)" tile flat>
<v-card-title class="subtitle-1 font-weight-bold">
Woche vom {{ week.startDate.getDate() }}.{{
week.startDate.getMonth() + 1
}}.{{ week.startDate.getFullYear() }} bis
{{ week.endDate.getDate() }}.{{ week.endDate.getMonth() + 1 }}.{{
week.endDate.getFullYear()
}}
</v-card-title>
<v-card-text>
<v-row justify="start" align="start">
<div v-for="day in week.days" :key="day.id">
<v-col>
<Day v-bind:day="day" />
</v-col>
</div>
</v-row>
</v-card-text>
</v-card>
</div>
</template>
<script>
import { mapGetters, mapActions } from 'vuex'
import { mdiChevronLeft, mdiChevronRight } from '@mdi/js'
import Day from './ServiceManagementComponents/Day'
export default {
name: 'ServiceManagement',
components: { Day },
data() {
return {
keyboard_arrow_left: mdiChevronLeft,
keyboard_arrow_right: mdiChevronRight,
id: 0,
date: new Date(this.$route.params.year, this.$route.params.month -1, 1),
monthArray: [
'Januar',
'Februar',
'März',
'April',
'Mai',
'Juni',
'Juli',
'August',
'September',
'Oktober',
'November',
'Dezember'
]
}
},
created() {
this.getAllJobKinds()
this.createMonth(this.date)
this.getAllUsers()
this.getDBUsers()
this.getUsers({
from_date: {
year: this.startDate.getFullYear(),
month: this.startDate.getMonth() + 1,
day: this.startDate.getDate()
},
to_date: {
year: this.endDate.getFullYear(),
month: this.endDate.getMonth() + 1,
day: this.endDate.getDate()
}
})
},
methods: {
...mapActions({
createMonth: 'sm/createMonth',
getAllUsers: 'sm/getAllUsers',
getUsers: 'sm/getUsers',
lockDay: 'sm/lockDay',
getDBUsers: 'usermanager/getUsersWithExtern',
getAllJobKinds: 'jkm/getAllJobKinds',
}),
changeMonth(value) {
if (value === -1) {
this.date = new Date(this.date.getFullYear(), this.date.getMonth() - 1)
} else {
this.date = new Date(this.date.getFullYear(), this.date.getMonth() + 1)
}
this.createMonth(this.date)
this.getUsers({
from_date: {
year: this.startDate.getFullYear(),
month: this.startDate.getMonth() + 1,
day: this.startDate.getDate()
},
to_date: {
year: this.endDate.getFullYear(),
month: this.endDate.getMonth() + 1,
day: this.endDate.getDate()
}
})
},
lockDays(value) {
for (var week in this.month) {
for (var dayint in this.month[week].days) {
var day = this.month[week].days[dayint]
this.lockDay({
year: day.date.getFullYear(),
month: day.date.getMonth() + 1,
day: day.date.getDate(),
locked: value
})
}
}
}
},
computed: {
...mapGetters({
month: 'sm/month',
startDate: 'sm/getStartDate',
endDate: 'sm/getEndDate'
})
},
watch: {
$route() {
this.date = new Date(this.$route.params.year, this.$route.params.month - 1, 1)
this.getAllJobKinds()
this.createMonth(this.date)
this.getAllUsers()
this.getDBUsers()
this.getUsers({
from_date: {
year: this.startDate.getFullYear(),
month: this.startDate.getMonth() + 1,
day: this.startDate.getDate()
},
to_date: {
year: this.endDate.getFullYear(),
month: this.endDate.getMonth() + 1,
day: this.endDate.getDate()
}
})
}
}
}
</script>
<style scoped></style>

View File

@ -0,0 +1,518 @@
<template>
<div v-if="day">
<v-card :color="color(day)" max-width="20em">
<v-card-title v-if="day.date" class="subtitle-1 font-weight-bold">
{{ day.name }} {{ day.date.getDate() }}.{{ day.date.getMonth() + 1 }}.{{
day.date.getFullYear()
}}
<v-spacer />
<v-btn icon small @click="dialog = true">
<v-icon>{{ menuIcon }}</v-icon>
</v-btn>
</v-card-title>
<v-card-text>
<v-expand-transition>
<v-row align="center" justify="center" v-if="day.loading">
<v-progress-circular indeterminate color="grey" />
</v-row>
</v-expand-transition>
<div v-for="(jobkinddateitem, index) in day.jobkinddate" :key="index">
<div
v-if="
jobkinddateitem.job_kind
? jobkinddateitem.job_kind.id !== 0
: false
"
>
<v-expand-transition>
<div v-show="!day.loading">
<v-autocomplete
chips
return-object
multiple
:counter="jobkinddateitem.maxpersons"
v-model="jobkinddateitem.worker"
:items="filterUser(jobkinddateitem.job_kind)"
:item-text="item => item.firstname + ' ' + item.lastname"
:label="jobkinddateitem.job_kind.name"
filled
color="green"
@blur="focused = false"
@focus="focused = true"
:key="update"
@change="forceRenderer(jobkinddateitem)"
>
<template v-slot:prepend-inner>
<v-icon>{{ account_add }}</v-icon>
</template>
<template v-slot:selection="data">
<v-chip
v-bind="data.attrs"
:input-value="data.selected"
close
@click="data.select"
@click:close="remove(jobkinddateitem, data.item)"
>{{ data.item.firstname }} {{ data.item.lastname }}
</v-chip>
</template>
</v-autocomplete>
</div>
</v-expand-transition>
</div>
</div>
</v-card-text>
<v-card-actions v-if="!day.loading">
<v-chip class="text-uppercase" :color="lockedColor">{{
lockedText
}}</v-chip>
<v-spacer />
<v-btn text @click="lock">{{ lockedTextBtn }}</v-btn>
</v-card-actions>
</v-card>
<v-dialog v-model="dialog">
<v-card>
<v-card-title>
Bearbeite Tag
</v-card-title>
<v-card-text>
<div>
<v-row v-if="!isBarDienstIn">
<v-col cols="8">
<v-text-field readonly outlined value="Bardienst" />
</v-col>
<v-col cols="2">
<v-text-field
outlined
label="Maximale Personen"
type="number"
v-model="maxpersons"
@change="createBarJobKindDate(maxpersons)"
/>
</v-col>
<v-col cols="2"> </v-col>
</v-row>
<v-row
v-for="(jobkinddateitem, index) in day.jobkinddate"
:key="index"
>
<v-col cols="8">
<v-text-field
v-if="!jobkinddateitem.new"
readonly
outlined
:value="jobkinddateitem.job_kind.name"
/>
<v-autocomplete
v-else
outlined
:items="filterJobKinds(jobkinddateitem, index)"
:rules="rules"
item-text="name"
item-value="id"
v-model="jobkinddateitem.job_kind"
return-object
></v-autocomplete>
</v-col>
<v-col cols="2">
<v-text-field
outlined
label="Maximale Personen"
type="number"
v-model="jobkinddateitem.maxpersons"
/>
</v-col>
<v-col cols="2">
<div v-if="jobkinddateitem.job_kind !== null">
<div v-if="jobkinddateitem.job_kind.id !== 1">
<v-btn
v-if="jobkinddateitem.id === 0"
fab
x-small
color="green"
@click="undoDelteJobKindDate(index)"
>
<v-icon>{{ plusIcon }}</v-icon>
</v-btn>
<v-btn
v-else
fab
x-small
color="red"
@click="deleteJobKindDate(index)"
>
<v-icon>{{ minusIcon }}</v-icon>
</v-btn>
</div>
</div>
<div v-else>
<v-btn
v-if="jobkinddateitem.id === 0"
fab
x-small
color="green"
@click="undoDelteJobKindDate(index)"
>
<v-icon>{{ plusIcon }}</v-icon>
</v-btn>
<v-btn
v-else
fab
x-small
color="red"
@click="deleteJobKindDate(index)"
>
<v-icon>{{ minusIcon }}</v-icon>
</v-btn>
</div>
</v-col>
<v-row v-if="jobkinddateitem.id === 0">
<v-col>
<v-alert dense type="info"
>{{ jobkinddateitem.job_kind.name }} wird beim Speichern
gelöscht.</v-alert
>
</v-col>
</v-row>
</v-row>
</div>
<v-row>
<v-spacer />
<v-btn
fab
small
color="green darken-1"
@click="addJobKindDate()"
:disabled="disableAddBtn"
>
<v-icon>{{ plusIcon }}</v-icon>
</v-btn>
</v-row>
</v-card-text>
<v-card-actions>
<v-spacer />
<v-btn text color="primary" @click="dialog = false">
Abbrechen
</v-btn>
<v-btn text color="primary" @click="saveJobKind()">
Speichern
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</div>
</template>
<script>
import { mapGetters, mapActions } from 'vuex'
import { mdiAccountPlus, mdiDotsVertical, mdiPlus, mdiMinus } from '@mdi/js'
export default {
name: 'Day',
props: {
day: Object
},
data() {
return {
account_add: mdiAccountPlus,
menuIcon: mdiDotsVertical,
plusIcon: mdiPlus,
minusIcon: mdiMinus,
searchInput: null,
focused: false,
dialog: false,
update: 0,
maxpersons: 2,
rules: [
data => {
if (data === null) return false
var list = this.day.jobkinddate.filter(a => {
if (a.job_kind === null) return false
else {
return a.job_kind.id === data.id
}
})
return list.length > 1 ? data.name + 'ist schon vorhanden' : false
}
],
backup: null
}
},
created() {
this.setLoading(this.day.date)
},
methods: {
...mapActions({
addUser: 'sm/addUser',
deleteUser: 'sm/deleteUser',
setLoading: 'sm/setDayLoading',
setNotLoading: 'sm/setDayNotLoading',
lockDay: 'sm/lockDay',
updateJobKindDate: 'sm/updateJobKindDate'
}),
forceRenderer(jobkind) {
this.update += 1
if (jobkind.backupWorker !== jobkind.worker && this.focused) {
let addedUser = null
for (let user in jobkind.worker) {
if (!jobkind.backupWorker.includes(jobkind.worker[user])) {
addedUser = jobkind.worker[user]
this.addUser({
date: this.day.date.getTime() / 1000,
user: addedUser,
year: this.day.date.getFullYear(),
month: this.day.date.getMonth() + 1,
day: this.day.date.getDate(),
job_kind: jobkind.job_kind
})
}
}
let deletedUser = null
for (let user in jobkind.backupWorker) {
if (!jobkind.worker.includes(jobkind.backupWorker[user])) {
deletedUser = jobkind.backupWorker[user]
this.deleteUser({
startdatetime: this.day.date,
date: this.day.date.getTime() / 1000,
user: deletedUser,
year: this.day.date.getFullYear(),
month: this.day.date.getMonth() + 1,
day: this.day.date.getDate()
})
}
}
}
jobkind.backupWorker = [...jobkind.worker]
},
// eslint-disable-next-line no-unused-vars
remove(jobkind, deletedUser) {
jobkind.worker.indexOf()
const obj = jobkind.worker.find(a => {
return a.username === deletedUser.username
})
const index = jobkind.worker.indexOf(obj)
if (index >= 0) jobkind.worker.splice(index, 1)
this.forceRenderer(jobkind)
},
color(day) {
if (day) {
if (day.date.getDay() === 0 || day.date.getDay() === 1) {
return 'grey lighten-4'
} else {
var retVal = 'yellow'
retVal = 'light-green'
for (var jobkind in day.jobkinddate) {
if (
day.jobkinddate[jobkind].worker.length >=
day.jobkinddate[jobkind].maxpersons
)
retVal = 'light-green'
else return 'yellow'
}
return retVal
}
} else {
return 'grey lighten-4'
}
},
lock() {
this.lockDay({
year: this.day.date.getFullYear(),
month: this.day.date.getMonth() + 1,
day: this.day.date.getDate(),
locked: !this.day.locked
})
},
createBarJobKindDate(maxpersons) {
this.day.jobkinddate.push({
id: -1,
job_kind: Object.assign(
{},
this.jobkinds.find(a => {
return a.id === 1
})
),
maxpersons: maxpersons,
daydate: {
year: this.day.date.getFullYear(),
month: this.day.date.getMonth() + 1,
day: this.day.date.getDate()
},
worker: [],
backupWorker: []
})
},
addJobKindDate() {
this.day.jobkinddate.push({
id: -1,
job_kind: null,
maxpersons: 2,
new: true,
daydate: {
year: this.day.date.getFullYear(),
month: this.day.date.getMonth() + 1,
day: this.day.date.getDate()
},
worker: [],
backupWorker: []
})
},
mop(jobkind) {
console.log(jobkind.worker)
},
deleteJobKindDate(index) {
if (this.day.jobkinddate[index].id === -1) {
this.day.jobkinddate.splice(index, 1)
} else {
this.day.jobkinddate[index].backupid = this.day.jobkinddate[index].id
this.day.jobkinddate[index].id = 0
}
},
undoDelteJobKindDate(index) {
this.day.jobkinddate[index].id = this.day.jobkinddate[index].backupid
},
saveJobKind() {
this.updateJobKindDate({
data: this.day.jobkinddate,
date: this.day.date
})
this.dialog = false
},
filterUser(jobkind) {
var filtered = this.dbUsers.filter(user => {
var userInOther = this.day.jobkinddate.find(item => {
if (item.job_kind === null) {
return false
}
if (item.job_kind.id === jobkind.id) {
return false
}
return item.worker.find(work => {
return work.id === user.id
})
})
if (userInOther) {
return false
}
if (jobkind.id === 1 || !jobkind.workgroup) {
return true
} else {
if (user.workgroups ? user.workgroups.length > 0 : false) {
return user.workgroups.find(wg => {
return wg.id === jobkind.workgroup.id
})
} else {
return false
}
}
})
return filtered
},
// eslint-disable-next-line no-unused-vars
filterJobKinds(jobkinddateitem, index) {
var retVal = this.jobkinds.filter(jobkind => {
return jobkind.id !== 1
})
retVal = retVal.filter(jobkind => {
return !this.day.jobkinddate.find(item => {
if (item.job_kind === jobkinddateitem.job_kind) {
return false
} else {
if (item.job_kind !== null && jobkind !== null)
if (item.job_kind.id === jobkind.id) return true
}
return false
})
})
return retVal
}
},
computed: {
...mapGetters({
allUsers: 'sm/allUsers',
dbUsers: 'usermanager/users',
disabled: 'sm/disabled',
jobkinds: 'jkm/jobkinds'
}),
worker() {
return this.day.worker
},
tada() {
return this.day.jobkinddate
},
lockedColor() {
return this.day.locked ? 'red' : 'green'
},
lockedText() {
return this.day.locked ? 'gesperrt' : 'frei'
},
lockedTextBtn() {
return this.day.locked ? 'freigeben' : 'sperren'
},
isBarDienstIn() {
for (var jobkinddate in this.day.jobkinddate) {
if (!(this.day.jobkinddate[jobkinddate].job_kind === null))
if (this.day.jobkinddate[jobkinddate].job_kind.id === 1) return true
}
return false
},
existJobKinds() {
var retVal = [...this.jobkinds]
retVal.splice(
retVal.findIndex(a => {
return a.id === 1
}),
1
)
return retVal
},
disableAddBtn() {
var barset = this.isBarDienstIn ? 0 : 1
return this.day.jobkinddate.length === this.jobkinds.length - barset
}
},
watch: {
worker(newValue, oldValue) {
if (oldValue !== newValue && this.focused) {
let addedUser = null
for (let user in newValue) {
if (!oldValue.includes(newValue[user])) {
addedUser = newValue[user]
this.addUser({
date: this.day.date.getTime() / 1000,
user: addedUser,
year: this.day.date.getFullYear(),
month: this.day.date.getMonth() + 1,
day: this.day.date.getDate()
})
}
}
let deletedUser = null
for (let user in oldValue) {
if (!newValue.includes(oldValue[user])) {
deletedUser = oldValue[user]
this.deleteUser({
startdatetime: this.day.date,
date: this.day.date.getTime() / 1000,
user: deletedUser,
year: this.day.date.getFullYear(),
month: this.day.date.getMonth() + 1,
day: this.day.date.getDate()
})
}
}
}
},
dialog(newValue) {
if (newValue) {
this.backup = [...this.day.jobkinddate]
} else {
this.day.jobkinddate = [...this.backup]
this.backup = []
}
}
}
}
</script>
<style scoped></style>

View File

@ -0,0 +1,320 @@
<template>
<div>
<v-dialog v-model="editUser">
<v-card>
<v-card-title>
{{
this.editedItem.firstname +
' ' +
this.editedItem.lastname +
' bearbeiten'
}}
</v-card-title>
<v-card-text>
<v-container>
<v-row>
<v-col>
<v-autocomplete
v-model="editedItem.statusgroup"
label="Status"
outlined
:items="status"
item-value="id"
item-text="name"
return-object
@change="clickItem(editedItem.statusgroup)"
>
</v-autocomplete>
</v-col>
<v-col>
<v-autocomplete
v-model="editedItem.voting"
label="Stimmrecht"
outlined
:items="[
{ value: true, text: 'ja' },
{ value: false, text: 'nein' }
]"
item-text="text"
item-value="value"
:disabled="disableVoting"
return-object
/>
</v-col>
</v-row>
<v-row>
<v-col>
<v-autocomplete
chips
multiple
v-model="editedItem.workgroups"
label="AG's"
outlined
:items="workgroups"
item-value="id"
item-text="name"
return-object
></v-autocomplete>
</v-col>
</v-row>
</v-container>
</v-card-text>
<v-card-actions>
<v-spacer />
<v-btn color="primary" text @click="close()">Abbrechen</v-btn>
<v-btn color="primary" text @click="save()">Speichern</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<v-data-table
:headers="header"
:items="users"
:search="search"
:loading="usersLoading || statusLoading"
:items-per-page="100"
>
<template v-slot:top>
<v-toolbar flat color="white">
<v-toolbar-title>Mitgliederliste</v-toolbar-title>
<v-spacer></v-spacer>
<v-text-field
v-model="search"
label="Sucher Mitglied"
single-line
hide-details
>
<template v-slot:append>
<v-icon>{{ searchIcon }}</v-icon>
</template>
</v-text-field>
</v-toolbar>
</template>
<template v-slot:item.workgroups="{ item }">
<div>
<v-chip v-for="group in item.workgroups" :key="group.id" x-small>
{{ group.name }}
</v-chip>
</div>
</template>
<template v-slot:item.statusgroup="{ item }">
{{ computeStatus(item.statusgroup) }}
</template>
<template v-slot:item.voting="{ item }">
<v-chip small :color="item.voting ? 'green' : 'red'">
{{ item.voting ? 'ja' : 'nein' }}
</v-chip>
</template>
<template v-slot:item.actions="{ item }">
<v-icon small @click="editItem(item)">{{ editIcon }}</v-icon>
</template>
</v-data-table>
<v-divider />
<v-card>
<v-card-text>
<v-container>
<v-row>
<v-col v-bind:class="{ fulllineText: isFulllineText }">
<v-text-field
outlined
:value="users.length"
label="Anzahl aller Mitglieder"
readonly
/>
</v-col>
<v-col v-bind:class="{ fulllineText: isFulllineText }">
<v-text-field
outlined
:value="allActiveUsers"
label="Anzahl aller aktiven Mitglieder"
readonly
/>
</v-col>
<v-col v-bind:class="{ fulllineText: isFulllineText }">
<v-text-field
outlined
:value="allVotings"
label="Anzahl aller Stimmberechtigten"
readonly
/>
</v-col>
</v-row>
</v-container>
</v-card-text>
</v-card>
</div>
</template>
<script>
import { mdiPencil, mdiMagnify } from '@mdi/js'
import { mapActions, mapGetters } from 'vuex'
export default {
name: 'UserManager',
data() {
return {
editIcon: mdiPencil,
searchIcon: mdiMagnify,
isFulllineText: false,
editUser: false,
disableVoting: null,
search: null,
header: [
{ text: 'Nachname', value: 'lastname' },
{ text: 'Vorname(n)', value: 'firstname' },
{ text: "AG's", value: 'workgroups' },
{ text: 'Status', value: 'statusgroup' },
{ text: 'Stimmrecht', value: 'voting' },
{
text: 'Aktionen',
value: 'actions',
sortable: false,
filterable: false
}
],
editedItem: {
id: -1,
firstname: null,
lastname: null,
username: null,
workgroups: [],
statusgroup: {
id: -1,
name: null
},
voting: {
value: false,
text: 'nein'
}
},
defaultItem: {
id: -1,
username: null,
workgroups: [],
statusgroup: {
id: -1,
name: null
},
voting: {
value: false,
text: 'nein'
}
}
}
},
mounted() {
this.$nextTick(function() {
window.addEventListener('resize', this.getWindowWidth)
this.getWindowWidth()
})
},
methods: {
...mapActions({
getUsers: 'usermanager/getUsers',
getStatus: 'usermanager/getStatus',
updateStatusUser: 'usermanager/updateStatusUser',
updateVoting: 'usermanager/updateVoting',
updateWorkgroups: 'usermanager/updateWorkgroups',
getAllWorkgroups: 'wm/getAllWorkgroups'
}),
getWindowWidth() {
this.isFulllineText = document.documentElement.clientWidth <= 750
},
close() {
this.editUser = false
setTimeout(() => {
this.editedItem = Object.assign({}, this.defaultItem)
}, 300)
},
editItem(item) {
this.editedItem = Object.assign({}, item)
this.editedItem.statusgroup = Object.assign(
{},
this.status.find(a => a.id == item.statusgroup)
)
this.editedItem.voting = Object.assign(
{},
item.voting
? { value: true, text: 'ja' }
: { value: false, text: 'nein' }
)
this.clickItem(this.editedItem.statusgroup)
this.editUser = true
},
clickItem(item) {
switch (item.id) {
case 1:
this.editedItem.voting = { value: true, text: 'ja' }
this.disableVoting = true
break
case 2:
this.disableVoting = false
break
case 3:
this.disableVoting = true
this.editedItem.voting = { value: false, text: 'nein' }
break
case 4:
this.editedItem.voting = { value: false, text: 'nein' }
this.disableVoting = true
break
case 5:
this.editedItem.voting = { value: false, text: 'nein' }
this.disableVoting = true
break
}
},
save() {
this.updateStatusUser({
username: this.editedItem.username,
status: this.editedItem.statusgroup
})
this.updateVoting({
username: this.editedItem.username,
voting: this.editedItem.voting.value
})
this.updateWorkgroups(this.editedItem)
this.close()
}
},
computed: {
...mapGetters({
users: 'usermanager/users',
status: 'usermanager/status',
usersLoading: 'usermanager/usersLoading',
statusLoading: 'usermanager/statusLoading',
workgroups: 'wm/workgroups'
}),
computeStatus() {
return id => {
let status = this.status.find(a => {
return a.id === id
})
return status ? status.name : null
}
},
allVotings() {
return this.users.filter(a => {
return a.voting
}).length
},
allActiveUsers() {
return this.users.filter(a => {
return a.statusgroup === 1
}).length
}
},
created() {
this.getUsers()
this.getStatus()
this.getAllWorkgroups()
}
}
</script>
<style scoped>
.fulllineText {
flex-basis: unset;
}
</style>

View File

@ -0,0 +1,190 @@
<template>
<div>
<v-data-table
:headers="header"
:items="workgroups"
:loading="workgroupLoading"
:search="search"
>
<template v-slot:top>
<v-toolbar flat color="white">
<v-toolbar-title>Arbeitsgruppen</v-toolbar-title>
<v-spacer> </v-spacer>
<v-text-field
v-model="search"
label="Suche Arbeitsgrupp"
single-line
hide-details
>
<template v-slot:append>
<v-icon>{{ searchIcon }}</v-icon>
</template>
</v-text-field>
<v-dialog v-model="dialog">
<template v-slot:activator="{ on }">
<v-btn
fab
x-small
color="primary"
class="mb-2"
v-on="on"
style="margin: 5px"
>
<v-icon>
{{ plusIcon }}
</v-icon>
</v-btn>
</template>
<v-card>
<v-card-title>
<span class="headline">{{ formTitle }}</span>
</v-card-title>
<v-card-text>
<v-container>
<v-text-field
v-model="editedItem.name"
label="Name"
outlined
></v-text-field>
<v-autocomplete
v-model="editedItem.boss"
label="AG-Leiter"
:items="users"
:item-text="item => item.firstname + ' ' + item.lastname"
item-value="username"
:loading="usersLoading"
outlined
return-object
>
</v-autocomplete>
</v-container>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="blue darken-1" text @click="close"
>Abbreche</v-btn
>
<v-btn color="blue darken-1" text @click="save"
>Speichern</v-btn
>
</v-card-actions>
</v-card>
</v-dialog>
</v-toolbar>
</template>
<template v-slot:item.boss="{ item }">
<div v-if="item.boss != null">
{{ item.boss.firstname }} {{ item.boss.lastname }}
</div>
</template>
<template v-slot:item.actions="{ item }">
<v-icon small class="mr-2" @click="editItem(item)">
{{ editIcon }}
</v-icon>
<v-icon small class="mr-2" @click="deleteItem(item)">
{{ deleteIcon }}
</v-icon>
</template>
</v-data-table>
</div>
</template>
<script>
import { mdiPencil, mdiMagnify, mdiDelete, mdiPlus } from '@mdi/js'
import { mapActions, mapGetters } from 'vuex'
export default {
name: 'WorkgroupManagement',
data() {
return {
editIcon: mdiPencil,
searchIcon: mdiMagnify,
deleteIcon: mdiDelete,
plusIcon: mdiPlus,
search: null,
dialog: false,
header: [
{ text: 'AG-Name', value: 'name' },
{ text: 'AG-Leiter', value: 'boss' },
{
text: 'Aktionen',
value: 'actions',
sortable: false,
filterable: false
}
],
editedItem: {
id: -1,
username: null,
boss: {
username: null,
firstname: null,
lastname: null
}
},
defaultItem: {
id: -1,
username: null,
boss: {
name: null,
firstname: null,
lastname: null
}
},
editedIndex: -1
}
},
methods: {
...mapActions({
getAllWorkgroups: 'wm/getAllWorkgroups',
setWorkgroup: 'wm/setWorkgroup',
updateWorkgroup: 'wm/updateWorkgroup',
getAllUsers: 'usermanager/getUsers',
deleteWorkgroup: 'wm/deleteWorkgroup'
}),
editItem(item) {
this.editedIndex = item.id
this.editedItem = Object.assign({}, item)
this.dialog = true
},
save() {
this.editedItem.id === -1
? this.setWorkgroup(this.editedItem)
: this.updateWorkgroup(this.editedItem)
this.editedItem = Object.assign({}, this.defaultItem)
this.close()
},
close() {
this.dialog = false
setTimeout(() => {
this.editedItem = Object.assign({}, this.defaultItem)
this.editedIndex = -1
}, 300)
},
deleteItem(item) {
confirm(
'Bist du sicher, dass du diese Arbeitsgruppe entfernen willst?'
) && this.deleteWorkgroup(item)
}
},
computed: {
...mapGetters({
workgroupLoading: 'wm/workgroupLoading',
workgroups: 'wm/workgroups',
users: 'usermanager/users',
usersLoading: 'usermanager/usersLoading'
}),
formTitle() {
return this.editedIndex === -1
? 'Neue Arbeitsgruppe'
: 'Bearbeite Arbeitsgruppe'
}
},
created() {
this.getAllWorkgroups()
this.getAllUsers()
console.log(this.users)
}
}
</script>
<style scoped></style>

View File

@ -2,7 +2,7 @@ import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import vuetify from './plugins/vuetify';
import vuetify from './plugins/vuetify'
Vue.config.productionTip = false

95
src/plugins/routes.js Normal file
View File

@ -0,0 +1,95 @@
//const main = 'https://192.168.5.128:5000/'
const main = 'http://localhost:5000/'
//const main = 'http://192.168.5.118:5000/'
//const main = 'https://groeger-clan.duckdns.org:5000/'
//const main = 'https://flaschengeist.wu5.de:5000/'
const url = {
login: main + 'login',
logout: main + 'logout',
getUsers: main + 'getUsers',
pricelist: main + 'pricelist',
getTypes: main + 'drinkTypes',
getFinanzerMain: main + 'getFinanzerMain',
bar: main + 'bar',
barGetUser: main + 'barGetUser',
barAddAmount: main + 'baradd',
finanzerAddAmount: main + 'finanzerAddAmount',
finanzerAddCredit: main + 'finanzerAddCredit',
searchUser: main + 'search',
getAllUser: main + 'barGetUsers',
lockUser: main + 'finanzerLock',
finanzerSetConfig: main + 'finanzerSetConfig',
finanzerAddUser: main + 'finanzerAddUser',
finanzerSendAllMail: main + 'finanzerSendAllMail',
finanzerSendOneMail: main + 'finanzerSendOneMail',
userMain: main + 'user/main',
userAddAmount: main + 'user/addAmount',
saveLifeTime: main + 'saveLifeTime',
getLifeTime: main + 'getLifeTime',
resetPassword: main + 'passwordReset',
vorstand: {
sm: {
addUser: main + 'sm/addUser',
deleteUser: main + 'sm/deleteUser',
getUser: main + 'sm/getUser',
getUsers: main + 'user/jobs',
lockDay: main + 'sm/lockDay',
searchUser: main + 'sm/searchWithExtern',
jobkind: main + 'sm/JobKind',
getAllJobKindsbKinds: main + 'sm/getAllJobKinds',
getJobKind: main + 'sm/getJobKind',
deleteJobKind: main + 'sm/deleteJobKind',
updateJobKindDates: main + 'jk/JobKindDate',
getJobKindDates: main + 'jk/JobKindDate'
},
um: {
setStatus: main + 'um/setStatus',
updateStatus: main + 'um/updateStatus',
deleteStatus: main + 'um/deleteStatus',
updateStatusUser: main + 'um/updateStatusUser',
updateVoting: main + 'um/updateVoting',
updateWorkgroups: main + 'um/updateWorkgroups'
},
wm: {
workgroup: main + 'wgm/workgroup',
getWorkgroup: main + 'wgm/getWorkgroup',
getAllWorkgroups: main + 'wgm/getAllWorkgroups',
deleteWorkgroup: main + 'wgm/deleteWorkgroup'
}
},
user: {
config: main + 'user/saveConfig',
job: main + 'user/job',
jobs: main + 'user/jobs',
addJob: main + 'user/addJob',
getJobOnDates: main + 'user/jobsOnDates',
deleteJob: main + 'user/deleteJob',
getJobInvites: main + 'user/getJobInvites',
setJobInvites: main + 'user/JobInvites',
deletJobInvite: main + 'user/deleteJobInvite',
getJobRequests: main + 'user/getJobRequests',
setJobRequests: main + 'user/JobRequests',
deletJobRequest: main + 'user/deleteJobRequest',
storno: main + 'user/storno',
getAllStatus: main + 'getAllStatus',
getStatus: main + 'getStatus',
valid: main + 'valid',
getAccessTokens: main + 'user/getAccessTokens'
},
barU: {
storno: main + 'bar/storno',
lock: main + 'bar/lock',
addUser: main + 'bar/addUser'
},
gastro: {
setDrink: main + 'gastro/setDrink',
updateDrink: main + 'gastro/updateDrink',
deleteDrink: main + 'gastro/deleteDrink',
setType: main + 'gastro/setDrinkType',
updateType: main + 'gastro/updateDrinkType',
deleteType: main + 'gastro/deleteDrinkType'
}
}
export default url

View File

@ -1,11 +1,10 @@
import Vue from 'vue';
import Vuetify from 'vuetify/lib';
import 'material-design-icons-iconfont'
import Vue from 'vue'
import Vuetify from 'vuetify/lib'
Vue.use(Vuetify);
Vue.use(Vuetify)
export default new Vuetify({
icons: {
iconfont: 'md',
}
});
icons: {
iconfont: 'mdiSvg'
}
})

View File

@ -1,36 +1,170 @@
import Vue from 'vue'
import VueRouter from 'vue-router'
import FinanzerView from "@/views/FinanzerView";
import Login from "@/views/Login";
import store from "@/store/index";
import BarView from "@/views/BarView";
import FinanzerView from '@/views/FinanzerView'
import Login from '@/views/Login'
import store from '@/store/index'
import GeruechteView from '../views/contents/GeruechteView'
import AddAmount from '../components/user/AddAmount'
import CreditOverview from '../components/user/CreditOverview'
import MainView from '../views/MainView'
import UserView from '../views/UserView'
import BarView from '../views/BarView'
import UserNavigation from '../components/user/UserNavigation'
import BarNavigation from '../components/baruser/BarNavigation'
import FinanzerNavigation from '../components/finanzer/FinanzerNavigation'
import Overview from '../components/finanzer/Overview'
import User from '../components/finanzer/User'
import ServiceManagement from '../components/vorstand/ServiceManagement'
import Config from '@/components/user/Config'
import Jobs from '@/components/user/Jobs'
import PriceList from '@/components/pricelist/PriceList'
import ManagementNavigation from '@/components/vorstand/ManagementNavigation'
import GastroNavigation from '@/components/gastro/GastroNavigation'
import PriceListView from '@/views/contents/PriceListView'
import UserManager from '@/components/vorstand/UserManager'
import WorkgroupManagement from '@/components/vorstand/WorkgroupManagement'
import JobKindManager from '@/components/vorstand/JobKindManager'
import JobsRequest from '@/components/user/JobsRequest'
import ResetPassword from '@/components/ResetPassword'
Vue.use(VueRouter)
const routes = [
const rootPath = ''
const routes = [
{
path: "/login",
name: "login",
path: rootPath + '/resetPassword',
name: 'resetPassword',
component: ResetPassword
},
{
path: rootPath + '/cookies',
name: 'cookies'
},
{
path: rootPath + '/pricelist',
name: 'priceListNoLogin',
component: PriceListView
},
{
path: rootPath + '/login',
name: 'login',
component: Login
},
{
path: "/finanzer",
name: "finanzer",
component: FinanzerView
},
{
path: "/bar",
name: "bar",
component: BarView
path: rootPath + '/main',
name: 'main',
component: MainView,
children: [
{
path: 'management',
name: 'management',
components: { nav: ManagementNavigation, default: BarView },
children: [
{
name: 'serviceManagement',
path: 'servicemanagement/:year/:month',
component: ServiceManagement
},
{
path: 'usermanager',
name: 'userManager',
component: UserManager
},
{
path: 'workgroupmanagement',
name: 'workgroupManagement',
component: WorkgroupManagement
},
{
path: 'jobkindmanagement',
name: 'jobkindManagement',
component: JobKindManager
}
]
},
{
path: 'user',
name: 'user',
components: { nav: UserNavigation, default: UserView },
children: [
{
path: 'add',
name: 'add',
component: AddAmount
},
{
path: 'overview',
name: 'userOverview',
component: CreditOverview
},
{
path: 'config',
name: 'userConfig',
component: Config
},
{
path: 'jobs/:year/:month',
name: 'userJobs',
component: Jobs
},
{
path: 'jobRequests/:kind',
name: 'jobRequests',
component: JobsRequest
}
]
},
{
path: 'bar',
name: 'bar',
components: { nav: BarNavigation, default: BarView },
children: [
{
path: 'geruecht',
name: 'geruecht',
component: GeruechteView
}
]
},
{
path: 'finanzer',
name: 'finanzer',
components: { default: FinanzerView, nav: FinanzerNavigation },
children: [
{
path: 'overview',
name: 'overview',
component: Overview
},
{
path: 'user/:id',
name: 'activeUser',
props: true,
component: User
}
]
},
{
path: 'gastro',
name: 'gastro',
components: { nav: GastroNavigation, default: BarView },
children: [
{
path: 'pricelist',
name: 'gastroPricelist',
component: PriceList
}
]
}
]
},
{
path: '*',
redirect: {
name: "login"
name: 'login'
}
},
}
]
const router = new VueRouter({
@ -40,18 +174,51 @@ const router = new VueRouter({
})
router.beforeEach((to, from, next) => {
store.dispatch('fetchAccessToken');
if (to.fullPath === '/finanzer') {
if (!store.state.user.accessToken) {
next('/login')
store.dispatch('fetchAccessToken')
if (to.name === 'main') {
if (
to.name === 'finanzer' ||
to.name === 'overview' ||
to.name === 'activeUser'
) {
if (!store.state.login.user.group.includes('moneymaster')) {
next({ name: 'login' })
}
}
if (to.name === 'bar' || to.name === 'geruecht') {
if (!store.state.login.user.group.includes('bar')) {
next({ name: 'login' })
}
}
if (
to.name === 'user' ||
to.name === 'userOverview' ||
to.name === 'userConfig' ||
to.name === 'userJobs' ||
to.name === 'jobRequests'
) {
if (!store.state.login.user.group.includes('user')) {
next({ name: 'login' })
}
}
if (!store.state.login.user.accessToken) {
next({ name: 'login' })
}
}
if (to.fullPath === '/login') {
if (store.state.user.accessToken) {
next('/finanzer')
if (to.name === 'login') {
if (store.state.login.user.accessToken) {
if (store.state.login.user.group.includes('moneymaster')) {
next({ name: 'overview' })
} else if (store.state.login.user.group.includes('bar')) {
next({ name: 'geruecht' })
} else if (store.state.login.user.group.includes('user')) {
next({ name: 'add' })
} else if (store.state.login.user.group.includes('extern')) {
next({ name: 'main' })
}
}
}
next();
});
next()
})
export default router

View File

@ -1,97 +1,35 @@
import Vue from 'vue'
import Vuex from 'vuex'
import router from "@/router";
import axios from 'axios'
import login from './modules/login'
import finanzerUsers from './modules/finanzerUsers'
import barUsers from '@/store/modules/barUsers'
import user from '@/store/modules/user'
import sm from '@/store/modules/serviceManagement'
import jobs from '@/store/modules/jobs'
import priceList from '@/store/modules/pricelist'
import usermanager from '@/store/modules/userManager'
import wm from '@/store/modules/workgroupManagement'
import jkm from '@/store/modules/jobkindManager'
import jobInvites from '@/store/modules/jobInvites'
import jobRequests from '@/store/modules/jobRequests'
import connectionError from '@/store/modules/connectionError'
Vue.use(Vuex)
const url = 'http://localhost:5000/'
export default new Vuex.Store({
state: {
user: {
username: null,
accessToken: null,
group: null
},
loggingIn: false,
loginError: null
},
mutations: {
loginStart: state => state.loggingIn = true,
loginStop (state, errorMessage){
state.loggingIn = false;
state.loginError = errorMessage;
},
updateAccessToken (state, data) {
// eslint-disable-next-line no-console
if (typeof(data) === typeof("")) {
data = JSON.parse(data)
}
// eslint-disable-next-line no-console
console.log("updateAccessToken data:", typeof (data), data)
if (data === null || data === undefined) {
state.user.username = null;
state.user.accessToken = null;
state.user.group = null;
} else {
this.state.user.username = data.username;
state.user.accessToken = data.accessToken;
state.user.group = data.group;
// eslint-disable-next-line no-console
console.log("state: ", state.user)
}
},
logout (state) {
state.user.accessToken = null;
state.user.username = null;
state.user.group = null;
}
},
actions: {
doLogin({ commit }, loginData) {
// eslint-disable-next-line no-console
console.log("loginData:", loginData)
commit('loginStart');
axios.post(url+'login', {...loginData})
.then(response => {
localStorage.setItem('user', JSON.stringify({ username: response.data.username, accessToken: response.data.token, group: response.data.group}));
commit('loginStop', null);
commit('updateAccessToken', response.data)
if (this.state.user.group === 'moneymaster') {
router.push('/finanzer');
}
if (this.state.user.group === 'bar') {
router.push('/bar')
}
})
.catch(error => {
commit('loginStop', error.response.data.error)
commit('updateAccessToken', {username: null, accessToken: null, group: null})
})
},
fetchAccessToken({ commit }) {
// eslint-disable-next-line no-console
console.log("localStorage: ", localStorage.getItem('user'))
commit('updateAccessToken', localStorage.getItem('user'))
},
logout({ commit }) {
localStorage.removeItem('user');
commit('logout');
router.push('/login');
},
resetLoginError({ commit }) {
commit("loginStop")
}
},
modules: {
},
getters: {
getGroup: state => {
return state.user.group
},
getToken: state => {
return state.user.accessToken
}
login,
finanzerUsers,
barUsers,
user,
sm,
jobs,
priceList,
usermanager,
wm,
jkm,
jobInvites,
jobRequests,
connectionError
}
})

View File

@ -0,0 +1,411 @@
import axios from 'axios'
import url from '@/plugins/routes'
const timeout = 5000
const state = {
users: [],
allUsers: [],
filter: '',
usersLoading: false,
allUsersLoading: false,
messages: [],
menu: false,
locked: false
}
const mutations = {
setAllUsers: (state, users) => {
state.allUsers = []
state.allUsers = users
for (let i = 0; i < state.allUsers.length; i++) {
state.allUsers[i].fullName =
state.allUsers[i].firstname + ' ' + state.allUsers[i].lastname
}
},
setUsers: (state, users) => {
for (let user in users) {
let existuser = state.users.find(a => {
return user === a.username
})
if (users[user].last_seen != null || users[user].last_seen != undefined) {
users[user].last_seen = new Date(
users[user].last_seen.year,
users[user].last_seen.month - 1,
users[user].last_seen.day,
users[user].last_seen.hour,
users[user].last_seen.minute,
users[user].last_seen.second
)
}
if (existuser) {
existuser.sername = users[user].username
existuser.firstname = users[user].firstname
existuser.lastname = users[user].lastname
existuser.locked = users[user].locked
existuser.amount = users[user].amount
existuser.type = users[user].type
existuser.limit = users[user].limit
existuser.last_seen = users[user].last_seen
existuser.autoLock = users[user].autoLock
? users[user].autoLock
: existuser.autoLock
} else {
state.users.push({
username: users[user].username,
firstname: users[user].firstname,
lastname: users[user].lastname,
locked: users[user].locked,
amount: users[user].amount,
type: users[user].type,
loading: false,
limit: users[user].limit,
last_seen: users[user].last_seen,
autoLock: users[user].autoLock
})
}
}
mutations.sortUsers(state)
},
updateUser: (state, data) => {
let index = state.users.indexOf(
state.users.find(a => {
return a.username === data.username
})
)
if (data.loading !== undefined) state.users[index].loading = data.loading
if (data.last_seen !== undefined)
state.users[index].last_seen = data.last_seen
},
sortUsers: state => {
state.users = state.users.sort((a, b) => {
if (a.lastname > b.lastname) return 1
if (a.lastname < b.lastname) return -1
if (a.firstname > b.firstname) return 1
if (a.firstname < b.firstname) return -1
return 0
})
},
setFilter: (state, filter) => {
state.filter = filter
},
setUsersLoading: (state, value) => {
state.usersLoading = value
},
setAllUsersLoading: (state, value) => {
state.allUsersLoading = value
},
addMessage: (state, data) => {
var message = null
if (state.messages.length > 0) {
if (
state.messages[0].user.username === data.user.username &&
!data.error
) {
message = state.messages[0]
if ((new Date() - state.messages[0].date) / 1000 < 2) {
clearTimeout(message.timeout)
message.amount = message.amount + data.amount
message.visible = true
message.date = new Date()
message.timeout = setTimeout(() => {
if (!message.error) {
message.visible = false
}
}, 5000)
return
} else {
message.visible = false
}
}
}
let message2 = {
user: data.user,
error: data.error,
storno: false,
loading: false,
visible: true,
amount: data.amount,
date: new Date(),
timeout: setTimeout(() => {
if (!message2.error) {
message2.visible = false
}
}, 5000)
}
state.messages.unshift(message2)
},
updateMessage: (state, data) => {
var message = state.messages.find(msg => {
return msg.date - data.date === 0 ? true : false
})
if (message) {
if (data.storno !== undefined) message.storno = data.storno
if (data.loading !== undefined) message.loading = data.loading
}
},
setMenu: (state, value) => {
state.menu = value
},
setLocked: (satet, value) => {
state.locked = value
}
}
const actions = {
// eslint-disable-next-line no-unused-vars
async getUsers({ commit, rootState, dispatch }) {
commit('setUsersLoading', true)
try {
const response = await axios.get(url.bar, {
headers: { Token: rootState.login.user.accessToken },
timeout
})
commit('setUsers', response.data)
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (e.response)
if (e.response.status === 401) {
dispatch('getLifeTime', null, { root: true })
location.reload()
}
}
commit('setUsersLoading', false)
},
async addAmount({ commit, rootState, dispatch }, data) {
try {
commit('updateUser', { username: data.username, loading: true })
} catch (e) {
//error
}
try {
const response = await axios.post(
url.barAddAmount,
{ userId: data.username, amount: data.amount },
{ headers: { Token: rootState.login.user.accessToken }, timeout }
)
commit('setUsers', { [response.data.username]: response.data })
commit('addMessage', {
user: data.user,
amount: data.amount,
error: false
})
dispatch('getLifeTime', null, { root: true })
} catch (e) {
console.log(typeof e)
for (const [key, value] of Object.entries(e)) {
console.log(`${key}: ${value}`)
}
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
commit('addMessage', {
user: data.user,
amount: data.amount,
error: true
})
if (e.response)
if (e.response.status === 401) {
dispatch('getLifeTime', null, { root: true })
location.reload()
}
}
try {
commit('updateUser', { username: data.username, loading: false })
} catch (e) {
//error
}
},
async addCreditList({ commit, rootState, dispatch }, data) {
try {
commit('updateUser', { username: data.username, loading: true })
} catch (e) {
//error
}
try {
const response = await axios.post(
url.barGetUser,
{ userId: data.username },
{ headers: { Token: rootState.login.user.accessToken }, timeout }
)
commit('setUsers', { [response.data.username]: response.data })
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (e.response)
if (e.response.status === 401) {
dispatch('getLifeTime', null, { root: true })
location.reload()
}
}
try {
commit('updateUser', {
username: data.username,
loading: false,
last_seen: new Date()
})
} catch {
// error
}
},
async getAllUsers({ commit, rootState, dispatch }) {
commit('setAllUsersLoading', true)
try {
const response = await axios.get(url.searchUser, {
headers: { Token: rootState.login.user.accessToken },
timeout
})
commit('setAllUsers', response.data)
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (e.response)
if (e.response.data === 401) {
dispatch('getLifeTime', null, { root: true })
location.reload()
}
}
commit('setAllUsersLoading', false)
},
async storno({ commit, rootState, dispatch }, data) {
commit('updateMessage', { date: data.date, loading: true })
try {
const response = await axios.post(
url.barU.storno,
{
userId: data.username,
amount: data.amount
},
{ headers: { Token: rootState.login.user.accessToken }, timeout }
)
commit('setUsers', { [response.data.username]: response.data })
commit('updateMessage', { date: data.date, storno: true })
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (e.response)
if (e.response.status === 401) {
dispatch('getLifeTime', null, { root: true })
location.reload()
}
}
commit('updateMessage', { date: data.date, loading: false })
},
async getLocked({ commit, rootState, dispatch }) {
try {
const response = await axios.get(url.barU.lock, {
headers: { Token: rootState.login.user.accessToken },
timeout
})
commit('setLocked', response.data.value)
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (e.response)
if (e.response.status === 401) {
dispatch('getLifeTime', null, { root: true })
location.reload()
}
}
},
async setLocked({ commit, rootState, dispatch }) {
try {
const response = await axios.post(
url.barU.lock,
{ value: true },
{ headers: { Token: rootState.login.user.accessToken }, timeout }
)
commit('setLocked', response.data.value)
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (e.response)
if (e.response.status === 401) {
dispatch('getLifeTime', null, { root: true })
location.reload()
}
}
},
async unlock({ commit, rootState, dispatch }, password) {
try {
const valid = await axios.post(
url.user.valid,
{ password: password },
{ headers: { Token: rootState.login.user.accessToken }, timeout }
)
if (valid.data.ok === 'ok') {
const response = await axios.post(
url.barU.lock,
{ value: false },
{ headers: { Token: rootState.login.user.accessToken } }
)
commit('setLocked', response.data.value)
}
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (e.response)
if (e.response.status === 401) {
dispatch('getLifeTime', null, { root: true })
location.reload()
}
}
},
setLockStatus({ commit }, status) {
commit('setLocked', status)
},
setFilter({ commit }, data) {
commit('setFilter', data)
},
activateMenu({ commit }) {
commit('setMenu', true)
},
deactivateMenu({ commit }) {
commit('setMenu', false)
}
}
const getters = {
users: state => {
return state.users
},
allUsers: state => {
return state.allUsers
},
filter: state => {
return state.filter
},
usersLoading: state => {
return state.usersLoading
},
allUsersLoading: state => {
return state.allUsersLoading
},
messages: state => {
return state.messages
},
menu: state => {
return state.menu
},
locked: state => {
return state.locked
}
}
export default {
namespaced: true,
state,
mutations,
actions,
getters
}

View File

@ -0,0 +1,43 @@
const state = {
errors: []
}
const mutations = {
addError: state => {
state.errors.push({
message: 'Connection Error: Server nicht verfügbar!',
visible: true
})
},
deleteErrors: state => {
state.errors = []
}
}
const actions = {
addError: ({ commit }) => {
commit('addError')
},
deleteErrors: ({ commit }) => {
commit('deleteErrors')
}
}
const getters = {
errors: state => {
return state.errors
},
visible: state => {
return state.errors.find(error => {
return error.visible
})
}
}
export default {
namespaced: true,
state,
mutations,
actions,
getters
}

View File

@ -0,0 +1,512 @@
import axios from 'axios'
// eslint-disable-next-line no-unused-vars
import url from '@/plugins/routes'
const timeout = 15000
const state = {
users: [],
activeUser: '',
allUsers: [],
user: null,
errorMails: null,
errorMail: null,
year: new Date().getFullYear(),
years: [],
months: [
{ value: 1, text: 'Januar' },
{ value: 2, text: 'Februar' },
{ value: 3, text: 'März' },
{ value: 4, text: 'April' },
{ value: 5, text: 'Mai' },
{ value: 6, text: 'Juni' },
{ value: 7, text: 'Juli' },
{ value: 8, text: 'August' },
{ value: 9, text: 'September' },
{ value: 10, text: 'Oktober' },
{ value: 11, text: 'November' },
{ value: 12, text: 'Dezember' }
],
allUsersLoading: false,
usersLoading: false,
emailLoading: false,
addUserLoading: false
}
const mutations = {
setAllUsers: (state, users) => {
state.allUsers = []
state.allUsers = users
for (let i = 0; i < state.allUsers.length; i++) {
state.allUsers[i].fullName =
state.allUsers[i].firstname + ' ' + state.allUsers[i].lastname
}
},
setActiveUser: (state, username) => {
state.activeUser = username
},
setUsers: (state, users) => {
for (let user in users) {
let list = {}
for (let creditList in users[user]['creditList']) {
let amount = mutations.createAmount(
users[user]['creditList'][creditList]
)
let credit = mutations.createCredit(
users[user]['creditList'][creditList]
)
let sum = mutations.createSum(credit, amount)
list[creditList] = [{ ...credit }, { ...amount }, { ...sum }]
}
let existUser = state.users.find(a => {
return a.username === user
})
if (existUser) {
existUser.username = users[user].username
existUser.firstname = users[user].firstname
existUser.lastname = users[user].lastname
existUser.limit = users[user].limit
existUser.locked = users[user].locked
existUser.autoLock = users[user].autoLock
existUser.creditList = list
} else {
state.users.push({
username: users[user].username,
firstname: users[user].firstname,
lastname: users[user].lastname,
limit: users[user].limit,
locked: users[user].locked,
autoLock: users[user].autoLock,
creditList: list,
expand: false,
loading: false
})
}
}
mutations.sortUsers(state)
},
createAmount(creditList) {
let amount = {
type: 'Schulden',
jan_amount: 0 - creditList.jan.depts,
feb_amount: 0 - creditList.feb.depts,
maer_amount: 0 - creditList.maer.depts,
apr_amount: 0 - creditList.apr.depts,
mai_amount: 0 - creditList.mai.depts,
jun_amount: 0 - creditList.jun.depts,
jul_amount: 0 - creditList.jul.depts,
aug_amount: 0 - creditList.aug.depts,
sep_amount: 0 - creditList.sep.depts,
okt_amount: 0 - creditList.okt.depts,
nov_amount: 0 - creditList.nov.depts,
dez_amount: 0 - creditList.dez.depts,
last: 0 - creditList['last']
}
amount.sum =
amount.jan_amount +
amount.feb_amount +
amount.maer_amount +
amount.apr_amount +
amount.mai_amount +
amount.jun_amount +
amount.jul_amount +
amount.aug_amount +
amount.sep_amount +
amount.okt_amount +
amount.nov_amount +
amount.dez_amount
return amount
},
createCredit(creditList) {
let credit = {
type: 'Guthaben',
jan_amount: creditList.jan.credit,
feb_amount: creditList.feb.credit,
maer_amount: creditList.maer.credit,
apr_amount: creditList.apr.credit,
mai_amount: creditList.mai.credit,
jun_amount: creditList.jun.credit,
jul_amount: creditList.jul.credit,
aug_amount: creditList.aug.credit,
sep_amount: creditList.sep.credit,
okt_amount: creditList.okt.credit,
nov_amount: creditList.nov.credit,
dez_amount: creditList.dez.credit
}
credit.sum =
credit.jan_amount +
credit.feb_amount +
credit.maer_amount +
credit.apr_amount +
credit.mai_amount +
credit.jun_amount +
credit.jul_amount +
credit.aug_amount +
credit.sep_amount +
credit.okt_amount +
credit.nov_amount +
credit.dez_amount
return credit
},
createSum(credit, amount) {
let sum = {
type: 'Summe',
jan_amount: credit.jan_amount + amount.jan_amount,
feb_amount: credit.feb_amount + amount.feb_amount,
maer_amount: credit.maer_amount + amount.maer_amount,
apr_amount: credit.apr_amount + amount.apr_amount,
mai_amount: credit.mai_amount + amount.mai_amount,
jun_amount: credit.jun_amount + amount.jun_amount,
jul_amount: credit.jul_amount + amount.jul_amount,
aug_amount: credit.aug_amount + amount.aug_amount,
sep_amount: credit.sep_amount + amount.sep_amount,
okt_amount: credit.okt_amount + amount.okt_amount,
nov_amount: credit.nov_amount + amount.nov_amount,
dez_amount: credit.dez_amount + amount.dez_amount
}
sum.sum =
sum.jan_amount +
sum.feb_amount +
sum.maer_amount +
sum.apr_amount +
sum.mai_amount +
sum.jun_amount +
sum.jul_amount +
sum.aug_amount +
sum.sep_amount +
sum.okt_amount +
sum.nov_amount +
sum.dez_amount
return sum
},
sortUsers: state => {
state.users = state.users.sort((a, b) => {
if (a.locked && b.locked) {
if (a.lastname > b.lastname) return 1
if (a.lastname < b.lastname) return -1
if (a.firstname > b.firstname) return 1
if (a.firstname < b.firstname) return -1
return 0
}
if (a.locked) return -1
if (b.locked) return 1
if (a.lastname > b.lastname) return 1
if (a.lastname < b.lastname) return -1
if (a.firstname > b.firstname) return 1
if (a.firstname < b.firstname) return -1
return 0
})
},
updateUsers: (state, data) => {
let index = state.users.indexOf(
state.users.find(a => {
return a.username === data.username
})
)
if (data.creditLists !== undefined) {
let list = {}
for (let creditList in data.creditLists) {
let amount = mutations.createAmount(data.creditLists[creditList])
let credit = mutations.createCredit(data.creditLists[creditList])
let sum = mutations.createSum(credit, amount)
list[creditList] = [{ ...credit }, { ...amount }, { ...sum }]
}
state.users[index].creditList = list
}
if (data.locked !== undefined) state.users[index].locked = data.locked
if (data.limit !== undefined) state.users[index].limit = data.limit
if (data.autoLock !== undefined) state.users[index].autoLock = data.autoLock
if (data.loading !== undefined) state.users[index].loading = data.loading
},
setMails: (state, data) => {
state.errorMails = data
},
setMail: (state, data) => {
state.errorMail = data
},
setYears: state => {
for (let year = new Date().getFullYear(); year >= 2000; year--) {
state.years.push({ value: year, text: year })
}
},
setYear: (state, value) => {
if (value) state.year++
else state.year--
},
setAllUsersLoading: (state, value) => {
state.allUsersLoading = value
},
setUsersLoading: (state, value) => {
state.usersLoading = value
},
setEMailLoading: (state, value) => {
state.emailLoading = value
},
setAddUserLoading: (state, value) => {
state.addUserLoading = value
}
}
const actions = {
// eslint-disable-next-line no-unused-vars
async getAllUsers({ commit, rootState, dispatch }) {
commit('setAllUsersLoading', true)
try {
const response = await axios.get(url.searchUser, {
headers: { Token: rootState.login.user.accessToken },
timeout
})
commit('setAllUsers', response.data)
dispatch('getLifeTime', null, { root: true })
} catch (err) {
if (err.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (err.response)
if (err.response.status === 401)
dispatch('logout', null, { root: true })
}
commit('setAllUsersLoading', false)
},
async getUsers({ commit, rootState, dispatch }) {
commit('setUsersLoading', true)
try {
const response = await axios.get(url.getFinanzerMain, {
headers: { Token: rootState.login.user.accessToken },
timeout
})
commit('setUsers', response.data)
dispatch('getLifeTime', null, { root: true })
} catch (err) {
if (err.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (err.response)
if (err.response.status === 401)
dispatch('logout', null, { root: true })
}
commit('setUsersLoading', false)
},
setActiveUser({ commit }, username) {
commit('setActiveUser', username)
},
async addAmount({ commit, rootState, dispatch }, data) {
commit('updateUsers', { username: data.user.username, loading: true })
try {
const response = await axios.post(
url.finanzerAddAmount,
{
userId: data.user.username,
amount: data.amount * 100,
year: data.year,
month: data.month
},
{ headers: { Token: rootState.login.user.accessToken }, timeout }
)
const creditLists = { ...response.data }
delete creditLists.locked
commit('updateUsers', {
creditLists: creditLists,
locked: response.data.locked,
username: data.user.username
})
dispatch('getLifeTime', null, { root: true })
} catch (err) {
if (err.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (err.response)
if (err.response.status === 401)
dispatch('logout', null, { root: true })
}
commit('updateUsers', { username: data.user.username, loading: false })
},
async addCredit({ commit, rootState, dispatch }, data) {
commit('updateUsers', { username: data.user.username, loading: true })
try {
const response = await axios.post(
url.finanzerAddCredit,
{
userId: data.user.username,
credit: data.credit * 100,
year: data.year,
month: data.month
},
{ headers: { Token: rootState.login.user.accessToken }, timeout }
)
const creditLists = { ...response.data }
delete creditLists.locked
commit('updateUsers', {
creditLists: creditLists,
locked: response.data.locked,
username: data.user.username
})
dispatch('getLifeTime', null, { root: true })
} catch (err) {
if (err.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (err.response)
if (err.response.status === 401)
dispatch('logout', null, { root: true })
}
commit('updateUsers', { username: data.user.username, loading: false })
},
async doLock({ commit, rootState, dispatch }, data) {
commit('updateUsers', { username: data.user.username, loading: true })
try {
const response = await axios.post(
url.lockUser,
{ userId: data.user.username, locked: data.locked },
{ headers: { Token: rootState.login.user.accessToken }, timeout }
)
commit('updateUsers', response.data)
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
commit('updateUsers', { username: data.user.username, loading: false })
},
async saveConfig({ commit, rootState, dispatch }, data) {
commit('updateUsers', { username: data.user.username, loading: true })
try {
const response = await axios.post(
url.finanzerSetConfig,
{
userId: data.user.username,
limit: data.limit * 100,
autoLock: data.autoLock
},
{ headers: { Token: rootState.login.user.accessToken }, timeout }
)
commit('updateUsers', response.data)
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
commit('updateUsers', { username: data.user.username, loading: false })
},
async addUser({ commit, rootState, dispatch }, data) {
commit('setAddUserLoading', true)
try {
const response = await axios.post(
url.finanzerAddUser,
{ userId: data.username },
{ headers: { Token: rootState.login.user.accessToken }, timeout }
)
commit('setUsers', response.data)
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
commit('setAddUserLoading', false)
},
async sendMails({ commit, rootState, dispatch }) {
commit('setEMailLoading', true)
try {
const response = await axios.get(url.finanzerSendAllMail, {
headers: { Token: rootState.login.user.accessToken },
timeout: 60000
})
commit('setMails', response.data)
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
commit('setEMailLoading', false)
},
async sendMail({ commit, rootState, dispatch }, data) {
commit('updateUsers', { username: data.username, loading: true })
try {
const response = await axios.post(
url.finanzerSendOneMail,
{ userId: data.username },
{ headers: { Token: rootState.login.user.accessToken }, timeout }
)
commit('setMail', response.data)
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
commit('updateUsers', { username: data.username, loading: false })
},
createYears({ commit }) {
commit('setYears')
return 'hallo'
},
countYear({ commit }, value) {
commit('setYear', value)
}
}
const getters = {
users: state => {
return state.users
},
activeUser: state => {
return state.users.find(user => {
return user.username === state.activeUser
})
},
allUsers: state => {
return state.allUsers
},
user: state => {
return state.user
},
errorMails: state => {
return state.errorMails
},
errorMail: state => {
return state.errorMail
},
years: state => {
return state.years
},
selectYears: state => {
return state.years
},
year: state => {
return state.year
},
months: state => {
return state.months
},
allUsersLoading: state => {
return state.allUsersLoading
},
usersLoading: state => {
return state.usersLoading
},
addUserLoading: state => {
return state.addUserLoading
}
}
export default {
namespaced: true,
state,
mutations,
actions,
getters
}

View File

@ -0,0 +1,437 @@
import axios from 'axios'
import url from '@/plugins/routes'
const timeout = 20000
const state = {
jobInvitesFromMe: [],
jobInvitesToMe: [],
jobInvitesLoading: false
}
const mutations = {
setJobInvitesFromMe: (state, jobInvites) => {
state.jobInvitesFromMe = jobInvites
state.jobInvitesFromMe.forEach(item => {
item.on_date = new Date(
item.on_date.year,
item.on_date.month - 1,
item.on_date.day
)
item.day = {
date: new Date(),
worker: [],
loading: false,
locked: false,
jobkinddate: []
}
})
},
setJobInvitesToMe: (state, jobInvites) => {
state.jobInvitesToMe = jobInvites
state.jobInvitesToMe.forEach(item => {
item.on_date = new Date(
item.on_date.year,
item.on_date.month - 1,
item.on_date.day
)
item.day = {
date: new Date(),
worker: [],
loading: false,
locked: false,
jobkinddate: []
}
})
},
setJobInvitesLoading: (state, value) => {
state.jobInvitesLoading = value
},
updateJobInviteToMe: (state, jobInvite) => {
state.jobInvitesToMe.forEach(item => {
if (item.id === jobInvite.id) {
item.watched = jobInvite.watched
}
})
},
updateMonthWorker: (state, { workers, date, getters, from_me }) => {
let mop
if (from_me) {
mop = getters.getDayFromMe(date)
} else {
mop = getters.getDayToMe(date)
}
mop.forEach(a => {
let day = a.day
day.jobkinddate.forEach(item => {
var filtered = workers.filter(worker => {
return item.job_kind.id === (worker.job_kind ? worker.job_kind.id : 1)
})
var filteredWorkers = []
filtered.forEach(item => {
filteredWorkers.push(item.user)
})
filteredWorkers.forEach(worker => {
if (
!item.worker.find(a => {
return a.id === worker.id
})
) {
item.worker.push(worker)
}
})
item.worker.forEach(worker => {
if (
!filteredWorkers.find(a => {
return a.id === worker.id
})
) {
item.worker.splice(item.worker.indexOf(worker), 1)
}
})
})
})
},
updateMonthLocked: (state, { locked, date, getters, from_me }) => {
let mop
if (from_me) {
mop = getters.getDayFromMe(date)
} else {
mop = getters.getDayToMe(date)
}
mop.forEach(a => {
let day = a.day
day.locked = !!locked
})
},
updateMonthJobkind: (state, { data, date, getters, from_me }) => {
let mop
if (from_me) {
mop = getters.getDayFromMe(date)
} else {
mop = getters.getDayToMe(date)
}
mop.forEach(a => {
let day = a.day
day.date = date
var backup = []
for (let jobkind in day.jobkinddate) {
if (day.jobkinddate[jobkind].worker !== undefined) {
backup.push({
id: day.jobkinddate[jobkind].job_kind.id,
worker: day.jobkinddate[jobkind].worker,
backupWorker: day.jobkinddate[jobkind].backupWorker
})
} else {
backup.push({
id: day.jobkinddate[jobkind].job_kind.id,
worker: [],
backupWorker: []
})
}
}
day.jobkinddate = [...data]
var test = day.jobkinddate.find(jobkind => {
return jobkind.job_kind.id === 1
})
if (!test) {
day.jobkinddate.push({
id: -1,
job_kind: { id: 1, name: 'Bardienst' },
maxpersons: 2,
daydate: {
year: date.getFullYear(),
month: date.getMonth() + 1,
day: date.getDate()
},
worker: [],
backupWorker: []
})
}
for (var jobkind in day.jobkinddate) {
var worker = backup.find(item => {
return item.id === day.jobkinddate[jobkind].job_kind.id
})
day.jobkinddate[jobkind].worker = worker ? worker.worker : []
day.jobkinddate[jobkind].backupWorker = worker
? worker.backupWorker
: []
}
})
},
setDayLoading: (state, { getters, date, value }) => {
let day = getters.getDayToMe(date)
day.forEach(a => {
a.day.loading = value
console.log('day', value ? 'loading' : 'not loading', day, a.day.loading)
})
},
deleteJobInviteFromMe: (state, jobinvite) => {
var item = state.jobInvitesFromMe.find(item => {
return item.id === jobinvite.id
})
state.jobInvitesFromMe.splice(state.jobInvitesFromMe.indexOf(item), 1)
}
}
const actions = {
async getJobInvites({ commit, dispatch, rootState, getters }) {
try {
commit('setJobInvitesLoading', true)
const date = new Date()
const from_me = await axios.post(
url.user.getJobInvites,
{
from_user: rootState.user.user,
date: {
year: date.getFullYear(),
month: date.getMonth() + 1,
day: date.getDate()
}
},
{ headers: { Token: rootState.login.user.accessToken }, timeout }
)
const workers_from_me = await axios.post(
url.user.getJobOnDates,
from_me.data,
{ headers: { Token: rootState.login.user.accessToken }, timeout }
)
commit('setJobInvitesFromMe', from_me.data)
workers_from_me.data.forEach(item => {
var date = new Date(
item.day.date.year,
item.day.date.month - 1,
item.day.date.day
)
commit('updateMonthJobkind', {
data: item.jobkinddate,
date,
getters,
from_me: true
})
commit('updateMonthWorker', {
workers: item.worker,
date,
getters,
from_me: true
})
commit('updateMonthLocked', {
locked: item.day.locked,
date,
getters,
from_me: true
})
})
const to_me = await axios.post(
url.user.getJobInvites,
{
to_user: rootState.user.user,
date: {
year: date.getFullYear(),
month: date.getMonth() + 1,
day: date.getDate()
}
},
{ headers: { Token: rootState.login.user.accessToken }, timeout }
)
const workers_to_me = await axios.post(
url.user.getJobOnDates,
to_me.data,
{ headers: { Token: rootState.login.user.accessToken }, timeout }
)
commit('setJobInvitesToMe', to_me.data)
workers_to_me.data.forEach(item => {
var date = new Date(
item.day.date.year,
item.day.date.month - 1,
item.day.date.day
)
commit('updateMonthJobkind', {
data: item.jobkinddate,
date,
getters,
from_me: false
})
commit('updateMonthWorker', {
workers: item.worker,
date,
getters,
from_me: false
})
commit('updateMonthLocked', {
locked: item.day.locked,
date,
getters,
from_me: false
})
})
commit('setJobInvitesLoading', false)
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
},
async setJobInvites({ commit, dispatch, rootState }, data) {
try {
commit('setJobInvitesLoading', true)
const response = await axios.put(url.user.setJobInvites, data, {
headers: { Token: rootState.login.user.accessToken },
timeout
})
commit('setJobInvitesFromMe', response.data)
commit('setJobInvitesLoading', false)
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
},
async addJob({ commit, rootState, dispatch, getters }, data) {
var date = new Date(data.year, data.month - 1, data.day)
commit('setDayLoading', { date, getters, value: true })
try {
commit('setJobInvitesLoading', true)
const response = await axios.post(
url.user.addJob,
{ ...data },
{
headers: { Token: rootState.login.user.accessToken },
timeout
}
)
commit('updateMonthWorker', {
workers: [...response.data],
date: new Date(data.year, data.month - 1, data.day),
getters,
from_me: false
})
commit('setDayLoading', { date, getters, value: false })
dispatch('getLifeTime', null, { root: true })
commit('setJobInvitesLoading', false)
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
},
async deleteJob({ commit, rootState, dispatch, getters }, data) {
var date = new Date(data.year, data.month - 1, data.day)
commit('setDayLoading', { date, getters, value: true })
commit('setJobInvitesLoading', true)
try {
const response = await axios.post(
url.user.deleteJob,
{ ...data },
{
headers: { Token: rootState.login.user.accessToken },
timeout
}
)
console.log(response.data)
commit('updateMonthWorker', {
workers: [...response.data],
date: new Date(data.year, data.month - 1, data.day),
getters
})
commit('setDayLoading', { date, getters, value: false })
dispatch('getLifeTime', null, { root: true })
commit('setJobInvitesLoading', false)
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
},
async updateJobInviteToMe({ commit, rootState, dispatch }, data) {
try {
commit('setJobInvitesLoading', true)
const response = await axios.post(url.user.setJobInvites, data, {
headers: { Token: rootState.login.user.accessToken },
timeout
})
commit('updateJobInviteToMe', response.data)
dispatch('getLifeTime', null, { root: true })
commit('setJobInvitesLoading', false)
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
},
async deleteJobInviteFromMe({ commit, rootState, dispatch }, data) {
try {
commit('setJobInvitesLoading', true)
await axios.post(url.user.deletJobInvite, data, {
headers: { Token: rootState.login.user.accessToken },
timeout
})
commit('deleteJobInviteFromMe', data)
commit('setJobInvitesLoading', false)
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
}
}
const getters = {
jobInvitesFromMe: state => {
return state.jobInvitesFromMe
},
jobInvitesToMe: state => {
return state.jobInvitesToMe
},
jobInvitesLoading: state => {
return state.jobInvitesLoading
},
getDayToMe: state => {
return date => {
return state.jobInvitesToMe.filter(item => {
return item.on_date - date === 0
})
}
},
getDayFromMe: state => {
return date => {
return state.jobInvitesFromMe.filter(item => {
return item.on_date - date === 0
})
}
},
getDayWorkerFromMe: state => {
return date => {
return state.jobInvitesFromMe.filter(jobInvite => {
return jobInvite.on_date - date === 0
})
}
},
news: state => {
var test = state.jobInvitesToMe.filter(item => {
return !item.watched
})
return test.length
}
}
export default {
namespaced: true,
state,
mutations,
actions,
getters
}

View File

@ -0,0 +1,387 @@
import axios from 'axios'
import url from '@/plugins/routes'
const timeout = 20000
const state = {
jobRequestsFromMe: [],
jobRequestsToMe: [],
jobRequestsLoading: false
}
const mutations = {
setJobRequestsFromMe: (state, jobRequests) => {
state.jobRequestsFromMe = jobRequests
state.jobRequestsFromMe.forEach(item => {
item.on_date = new Date(
item.on_date.year,
item.on_date.month - 1,
item.on_date.day
)
item.day = {
date: new Date(),
worker: [],
loading: false,
locked: false,
jobkinddate: []
}
})
},
setJobRequestsToMe: (state, jobRequests) => {
state.jobRequestsToMe = jobRequests
state.jobRequestsToMe.forEach(item => {
item.on_date = new Date(
item.on_date.year,
item.on_date.month - 1,
item.on_date.day
)
item.day = {
date: new Date(),
worker: [],
loading: false,
locked: false,
jobkinddate: []
}
})
},
setJobRequestsLoading: (state, value) => {
state.jobRequestsLoading = value
},
updateJobRequestToMe: (state, jobRequest) => {
state.jobRequestsToMe.forEach(item => {
if (item.id === jobRequest.id) {
item.watched = jobRequest.watched
item.accepted = jobRequest.accepted
}
})
},
updateMonthWorker: (state, { workers, date, getters, from_me }) => {
let mop
if (from_me) {
mop = getters.getDayFromMe(date)
} else {
mop = getters.getDayToMe(date)
}
mop.forEach(a => {
let day = a.day
day.jobkinddate.forEach(item => {
var filtered = workers.filter(worker => {
return item.job_kind.id === (worker.job_kind ? worker.job_kind.id : 1)
})
var filteredWorkers = []
filtered.forEach(item => {
filteredWorkers.push(item.user)
})
filteredWorkers.forEach(worker => {
if (
!item.worker.find(a => {
return a.id === worker.id
})
) {
item.worker.push(worker)
}
})
item.worker.forEach(worker => {
if (
!filteredWorkers.find(a => {
return a.id === worker.id
})
) {
item.worker.splice(item.worker.indexOf(worker), 1)
}
})
})
})
},
updateMonthLocked: (state, { locked, date, getters, from_me }) => {
let mop
if (from_me) {
mop = getters.getDayFromMe(date)
} else {
mop = getters.getDayToMe(date)
}
mop.forEach(a => {
let day = a.day
day.locked = !!locked
})
},
updateMonthJobkind: (state, { data, date, getters, from_me }) => {
let mop
if (from_me) {
mop = getters.getDayFromMe(date)
} else {
mop = getters.getDayToMe(date)
}
mop.forEach(a => {
let day = a.day
day.date = date
var backup = []
for (let jobkind in day.jobkinddate) {
if (day.jobkinddate[jobkind].worker !== undefined) {
backup.push({
id: day.jobkinddate[jobkind].job_kind.id,
worker: day.jobkinddate[jobkind].worker,
backupWorker: day.jobkinddate[jobkind].backupWorker
})
} else {
backup.push({
id: day.jobkinddate[jobkind].job_kind.id,
worker: [],
backupWorker: []
})
}
}
day.jobkinddate = [...data]
var test = day.jobkinddate.find(jobkind => {
return jobkind.job_kind.id === 1
})
if (!test) {
day.jobkinddate.push({
id: -1,
job_kind: { id: 1, name: 'Bardienst' },
maxpersons: 2,
daydate: {
year: date.getFullYear(),
month: date.getMonth() + 1,
day: date.getDate()
},
worker: [],
backupWorker: []
})
}
for (var jobkind in day.jobkinddate) {
var worker = backup.find(item => {
return item.id === day.jobkinddate[jobkind].job_kind.id
})
day.jobkinddate[jobkind].worker = worker ? worker.worker : []
day.jobkinddate[jobkind].backupWorker = worker
? worker.backupWorker
: []
}
})
},
setDayLoading: (state, { getters, date, value }) => {
let day = getters.getDayToMe(date)
day.forEach(a => {
a.day.loading = value
})
},
deleteJobRequestFromMe: (state, jobrequest) => {
var item = state.jobRequestsFromMe.find(item => {
return item.id === jobrequest.id
})
state.jobRequestsFromMe.splice(state.jobRequestsFromMe.indexOf(item), 1)
}
}
const actions = {
async getJobRequests({ commit, dispatch, rootState, getters }) {
try {
commit('setJobRequestsLoading', true)
const date = new Date()
const from_me = await axios.post(
url.user.getJobRequests,
{
from_user: rootState.user.user,
date: {
year: date.getFullYear(),
month: date.getMonth() + 1,
day: date.getDate()
}
},
{ headers: { Token: rootState.login.user.accessToken }, timeout }
)
const workers_from_me = await axios.post(
url.user.getJobOnDates,
from_me.data,
{ headers: { Token: rootState.login.user.accessToken }, timeout }
)
commit('setJobRequestsFromMe', from_me.data)
workers_from_me.data.forEach(item => {
var date = new Date(
item.day.date.year,
item.day.date.month - 1,
item.day.date.day
)
commit('updateMonthJobkind', {
data: item.jobkinddate,
date,
getters,
from_me: true
})
commit('updateMonthWorker', {
workers: item.worker,
date,
getters,
from_me: true
})
commit('updateMonthLocked', {
locked: item.day.locked,
date,
getters,
from_me: true
})
})
const to_me = await axios.post(
url.user.getJobRequests,
{
to_user: rootState.user.user,
date: {
year: date.getFullYear(),
month: date.getMonth() + 1,
day: date.getDate()
}
},
{ headers: { Token: rootState.login.user.accessToken }, timeout }
)
const workers_to_me = await axios.post(
url.user.getJobOnDates,
to_me.data,
{ headers: { Token: rootState.login.user.accessToken }, timeout }
)
commit('setJobRequestsToMe', to_me.data)
workers_to_me.data.forEach(item => {
var date = new Date(
item.day.date.year,
item.day.date.month - 1,
item.day.date.day
)
commit('updateMonthJobkind', {
data: item.jobkinddate,
date,
getters,
from_me: false
})
commit('updateMonthWorker', {
workers: item.worker,
date,
getters,
from_me: false
})
commit('updateMonthLocked', {
locked: item.day.locked,
date,
getters,
from_me: false
})
})
commit('setJobRequestsLoading', false)
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
},
async setJobRequests({ commit, dispatch, rootState }, data) {
try {
commit('setJobRequestsLoading', true)
const response = await axios.put(url.user.setJobRequests, data, {
headers: { Token: rootState.login.user.accessToken },
timeout
})
commit('setJobRequestsFromMe', response.data)
commit('setJobRequestsLoading', false)
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
},
async updateJobRequestToMe({ commit, rootState, dispatch }, data) {
try {
commit('setJobRequestsLoading', true)
data.on_date = {
year: data.on_date.getFullYear(),
month: data.on_date.getMonth() + 1,
day: data.on_date.getDate()
}
const response = await axios.post(url.user.setJobRequests, data, {
headers: { Token: rootState.login.user.accessToken },
timeout
})
response.data.on_date = new Date(
response.data.on_date.year,
response.data.on_date.month - 1,
response.data.on_date.day
)
commit('updateJobRequestToMe', response.data)
commit('setJobRequestsLoading', false)
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
},
async deleteJobRequestFromMe({ commit, rootState, dispatch }, data) {
try {
commit('setJobRequestsLoading', true)
await axios.post(url.user.deletJobRequest, data, {
headers: { Token: rootState.login.user.accessToken },
timeout
})
commit('deleteJobRequestFromMe', data)
commit('setJobRequestsLoading', false)
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
}
}
const getters = {
jobRequestsFromMe: state => {
return state.jobRequestsFromMe
},
jobRequestsToMe: state => {
return state.jobRequestsToMe
},
jobRequestsLoading: state => {
return state.jobRequestsLoading
},
getDayToMe: state => {
return date => {
return state.jobRequestsToMe.filter(item => {
return item.on_date - date === 0
})
}
},
getDayFromMe: state => {
return date => {
return state.jobRequestsFromMe.filter(item => {
return item.on_date - date === 0
})
}
},
getDayWorkerFromMe: state => {
return date => {
return state.jobRequestsFromMe.filter(jobRequest => {
return jobRequest.on_date - date === 0
})
}
},
news: state => {
var test = state.jobRequestsToMe.filter(item => {
return !item.watched
})
return test.length
}
}
export default {
namespaced: true,
state,
mutations,
actions,
getters
}

View File

@ -0,0 +1,132 @@
import url from '@/plugins/routes'
import axios from 'axios'
const timeout = 20000
const state = {
jobkinds: [],
jobkindLoading: false
}
const mutations = {
setJobkinds: (state, jobkinds) => {
state.jobkinds = jobkinds
},
updateJobKind: (state, jobkind) => {
console.log(jobkind)
const exists = state.jobkinds.find(a => {
return a.id === jobkind.id
})
console.log(exists)
if (exists) {
exists.name = jobkind.name
exists.workgroup = jobkind.workgroup
} else {
state.jobkinds.push(jobkind)
}
},
deleteJobKind: (state, jobkind) => {
const exists = state.jobkinds.indexOf(
state.jobkinds.find(a => {
return a.id === jobkind.id
})
)
state.jobkinds.splice(exists, 1)
},
setJobkindsLoading: (state, value) => {
state.jobkindLoading = value
}
}
const actions = {
async getAllJobKinds({ commit, rootState, dispatch }) {
try {
commit('setJobkindsLoading', true)
const response = await axios.get(url.vorstand.sm.getAllJobKindsbKinds, {
headers: { Token: rootState.login.user.accessToken },
timeout
})
commit('setJobkinds', response.data)
commit('setJobkindsLoading', false)
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
},
async addJobKind({ commit, rootState, dispatch }, data) {
try {
commit('setJobkindsLoading', true)
const response = await axios.put(
url.vorstand.sm.jobkind,
{ ...data },
{ headers: { Token: rootState.login.user.accessToken }, timeout }
)
commit('updateJobKind', response.data)
commit('setJobkindsLoading', false)
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
},
async updateJobKind({ commit, rootState, dispatch }, data) {
try {
commit('setJobkindsLoading', true)
const response = await axios.post(
url.vorstand.sm.jobkind,
{ ...data },
{ headers: { Token: rootState.login.user.accessToken }, timeout }
)
commit('updateJobKind', response.data)
commit('setJobkindsLoading', false)
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
},
async deleteJobKind({ commit, rootState, dispatch }, data) {
try {
commit('setJobkindsLoading', true)
await axios.post(
url.vorstand.sm.deleteJobKind,
{ ...data },
{ headers: { Token: rootState.login.user.accessToken }, timeout }
)
commit('deleteJobKind', data)
commit('setJobkindsLoading', false)
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
}
}
const getters = {
jobkinds: state => {
return state.jobkinds
},
jobkindsLoading: state => {
return state.jobkindLoading
}
}
export default {
namespaced: true,
state,
mutations,
actions,
getters
}

476
src/store/modules/jobs.js Normal file
View File

@ -0,0 +1,476 @@
import axios from 'axios'
import url from '@/plugins/routes'
const timeout = 20000
const state = {
month: [],
allUsers: [],
disabled: false
}
const mutations = {
setAllUsers: (state, data) => {
state.allUsers = []
state.allUsers = data.users
const index = state.allUsers.indexOf(
state.allUsers.find(a => a.username === data.username)
)
state.allUsers.splice(index, 1)
for (let i = 0; i < state.allUsers.length; i++) {
state.allUsers[i].fullName =
state.allUsers[i].firstname + ' ' + state.allUsers[i].lastname
}
},
createMonth: (state, date) => {
let month = []
let id = 0
const year = date.getFullYear()
const mon = date.getMonth()
let a = new Date(year, mon + 1, 0)
let days = a.getDate()
let startDate = 1
for (let intDay = 1; intDay <= days; intDay++) {
if (new Date(year, mon, intDay).getDay() === 3) {
startDate = intDay
break
}
}
let end = false
let week = { id: id, days: {} }
for (let intDay = startDate; intDay <= days + 7; intDay++) {
if (end) break
let currentDate = new Date(year, mon, intDay)
switch (currentDate.getDay()) {
case 1:
mutations.setStartEndDate(week)
month.push(week)
id++
week = { id: id, days: {} }
week.days.monday = {
id: currentDate.getDay(),
date: currentDate,
name: 'Montag',
worker: [],
loading: false,
locked: false,
jobkinddate: []
}
break
case 2:
week.days.tuesday = {
id: currentDate.getDay(),
date: currentDate,
name: 'Dienstag',
worker: [],
loading: false,
locked: false,
jobkinddate: []
}
break
case 3:
if (currentDate.getMonth() === mon + 1) {
end = true
mutations.setStartEndDate(week)
month.push(week)
} else {
week.days.wednesday = {
id: currentDate.getDay(),
date: currentDate,
name: 'Mittwoch',
worker: [],
loading: false,
locked: false,
jobkinddate: []
}
}
break
case 4:
week.days.thursday = {
id: currentDate.getDay(),
date: currentDate,
name: 'Donnerstag',
worker: [],
loading: false,
locked: false,
jobkinddate: []
}
break
case 5:
week.days.friday = {
id: currentDate.getDay(),
date: currentDate,
name: 'Freitag',
worker: [],
loading: false,
locked: false,
jobkinddate: []
}
break
case 6:
week.days.satturday = {
id: currentDate.getDay(),
date: currentDate,
name: 'Samstag',
worker: [],
loading: false,
locked: false,
jobkinddate: []
}
break
case 0:
week.days.sunday = {
id: currentDate.getDay(),
date: currentDate,
name: 'Sonntag',
worker: [],
loading: false,
locked: false,
jobkinddate: []
}
break
}
}
state.month = month
},
updateMonth: (state, data) => {
const date = new Date(data.start.year, data.start.month - 1, data.start.day)
const user = data.user
for (let week = 0; week < state.month.length; week++) {
for (let day in state.month[week].days) {
if (state.month[week].days[day].date - date === 0) {
if (user) {
let worker = state.month[week].days[day].worker.find(a => {
return a.username === user.username
})
if (!worker && data.com === 'add') {
state.month[week].days[day].worker.push({
firstname: user.firstname,
lastname: user.lastname,
username: user.username,
fullName: user.firstname + ' ' + user.lastname
})
}
if (worker && data.com === 'delete') {
const index = state.month[week].days[day].worker.indexOf(worker)
state.month[week].days[day].worker.splice(index, 1)
}
}
if (data.day) {
state.month[week].days[day].locked = data.day.locked
}
}
}
}
},
// eslint-disable-next-line no-unused-vars
updateMonthWorker: (state, { workers, date, getters }) => {
var day = getters.getDay(date)
day.jobkinddate.forEach(item => {
var filtered = workers.filter(worker => {
return item.job_kind.id === (worker.job_kind ? worker.job_kind.id : 1)
})
var filteredWorkers = []
filtered.forEach(item => {
filteredWorkers.push(item.user)
})
filteredWorkers.forEach(worker => {
if (
!item.worker.find(a => {
return a.id === worker.id
})
) {
item.worker.push(worker)
}
})
item.worker.forEach(worker => {
if (
!filteredWorkers.find(a => {
return a.id === worker.id
})
) {
item.worker.splice(item.worker.indexOf(worker), 1)
}
})
})
},
updateMonthLocked: (state, { locked, date, getters }) => {
var day = getters.getDay(date)
day.locked = !!locked
},
updateMonthJobkind: (state, { data, date, getters }) => {
let day = getters.getDay(date)
var backup = []
for (let jobkind in day.jobkinddate) {
if (day.jobkinddate[jobkind].worker !== undefined) {
backup.push({
id: day.jobkinddate[jobkind].job_kind.id,
worker: day.jobkinddate[jobkind].worker,
backupWorker: day.jobkinddate[jobkind].backupWorker
})
} else {
backup.push({
id: day.jobkinddate[jobkind].job_kind.id,
worker: [],
backupWorker: []
})
}
}
day.jobkinddate = [...data]
var test = day.jobkinddate.find(jobkind => {
return jobkind.job_kind.id === 1
})
if (!test) {
day.jobkinddate.push({
id: -1,
job_kind: { id: 1, name: 'Bardienst' },
maxpersons: 2,
daydate: {
year: date.getFullYear(),
month: date.getMonth() + 1,
day: date.getDate()
},
worker: [],
backupWorker: []
})
}
for (var jobkind in day.jobkinddate) {
var worker = backup.find(item => {
return item.id === day.jobkinddate[jobkind].job_kind.id
})
day.jobkinddate[jobkind].worker = worker ? worker.worker : []
day.jobkinddate[jobkind].backupWorker = worker ? worker.backupWorker : []
}
},
setAllDayLoading: state => {
for (let week = 0; week < state.month.length; week++) {
for (let day in state.month[week].days) {
state.month[week].days[day].loading = true
}
}
},
setDayLoading: (state, { date, getters }) => {
let day = getters.getDay(date)
day.loading = true
},
setDayNotLoading: (state, { date, getters }) => {
let day = getters.getDay(date)
day.loading = false
},
setDisabled: (state, data) => {
state.disabled = data
},
setStartEndDate: week => {
if (week.days.monday) {
week.startDate = week.days.monday.date
} else if (week.days.tuesday) {
week.startDate = week.days.tuesday.date
} else if (week.days.wednesday) {
week.startDate = week.days.wednesday.date
} else if (week.days.thursday) {
week.startDate = week.days.thursday.date
} else if (week.days.friday) {
week.startDate = week.days.friday.date
} else if (week.days.satturday) {
week.startDate = week.days.satturday.date
} else if (week.days.sunday) {
week.startDate = week.days.sunday.date
}
if (week.days.sunday) {
week.endDate = week.days.sunday.date
} else if (week.days.satturday) {
week.endDate = week.days.satturday.date
} else if (week.days.friday) {
week.endDate = week.days.friday.date
} else if (week.days.thursday) {
week.endDate = week.days.thursday.date
} else if (week.days.wednesday) {
week.endDate = week.days.wednesday.date
} else if (week.days.tuesday) {
week.endDate = week.days.tuesday.date
} else if (week.days.monday) {
week.endDate = week.days.monday.date
}
}
}
const actions = {
async getAllUsers({ commit, rootState, dispatch }) {
try {
const response = await axios.get(url.searchUser, {
headers: { Token: rootState.login.user.accessToken },
timeout
})
commit('setAllUsers', {
users: response.data,
username: rootState.login.user.username
})
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (e.response)
if (e.response.data === 401) dispatch('logout', null, { root: true })
}
},
createMonth({ commit }, date) {
commit('setDisabled', true)
commit('createMonth', date)
commit('setDisabled', false)
},
setDayLoading({ commit, getters }, date) {
commit('setDayLoading', { date, getters })
},
setDayNotLoading({ commit, getters }, date) {
commit('setDayNotLoading', { date, getters })
},
async getUsers({ commit, rootState, dispatch, getters }, data) {
commit('setAllDayLoading')
try {
const response = await axios.post(
url.vorstand.sm.getUsers,
{ ...data },
{ headers: { Token: rootState.login.user.accessToken }, timeout }
)
for (var day in response.data) {
var date = new Date(
response.data[day].day.date.year,
response.data[day].day.date.month - 1,
response.data[day].day.date.day
)
commit('updateMonthJobkind', {
data: [...response.data[day].jobkinddate],
date,
getters
})
commit('updateMonthWorker', {
workers: [...response.data[day].worker],
date,
getters
})
commit('updateMonthLocked', {
locked: response.data[day].day.locked,
date,
getters
})
commit('setDayNotLoading', { date, getters })
}
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
},
async addJob({ commit, rootState, dispatch, getters }, data) {
var date = new Date(data.year, data.month - 1, data.day)
commit('setDayLoading', { date, getters })
try {
const response = await axios.post(
url.user.addJob,
{ ...data },
{
headers: { Token: rootState.login.user.accessToken },
timeout
}
)
commit('updateMonthWorker', {
workers: [...response.data],
date: new Date(data.year, data.month - 1, data.day),
getters
})
commit('setDayNotLoading', { date, getters })
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
},
// eslint-disable-next-line no-unused-vars
async deleteJob({ commit, rootState, dispatch, getters }, data) {
var date = new Date(data.year, data.month - 1, data.day)
commit('setDayLoading', { date, getters })
try {
const response = await axios.post(
url.user.deleteJob,
{ ...data },
{
headers: { Token: rootState.login.user.accessToken },
timeout
}
)
console.log(response.data)
commit('updateMonthWorker', {
workers: [...response.data],
date: new Date(data.year, data.month - 1, data.day),
getters
})
commit('setDayNotLoading', { date, getters })
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
console.log(e)
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
},
async transactJob({ rootState, dispatch }, data) {
try {
await axios.post(
url.user.transactJob,
{ ...data },
{ headers: { Token: rootState.login.user.accessToken }, timeout }
)
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
}
}
const getters = {
month: state => {
return state.month
},
getDay: state => date => {
for (let week = 0; week < state.month.length; week++) {
for (let day in state.month[week].days) {
if (state.month[week].days[day].date - date === 0) {
return state.month[week].days[day]
}
}
}
},
disabled: state => {
return state.disabled
},
allUsers: state => {
return state.allUsers
},
getStartDate: state => {
return state.month[0].startDate
},
getEndDate: state => {
return state.month[state.month.length - 1].endDate
}
}
export default {
namespaced: true,
state,
mutations,
actions,
getters
}

268
src/store/modules/login.js Normal file
View File

@ -0,0 +1,268 @@
import axios from 'axios'
import router from '@/router'
import url from '@/plugins/routes'
const timeout = 20000
const state = {
user: {
username: null,
firstname: null,
lastname: null,
accessToken: null,
group: null
},
loggingIn: false,
loginError: null,
cookieNotification: true,
cookieAccepted: false,
lifeTime: 1800
}
const mutations = {
loginStart: state => (state.loggingIn = true),
loginStop(state, errorMessage) {
state.loggingIn = false
state.loginError = errorMessage
},
updateAccessToken(state, data) {
if (typeof data === typeof '') {
data = JSON.parse(data)
}
if (data === null || data === undefined) {
state.user.username = null
state.user.accessToken = null
state.user.group = null
} else {
state.user.username = data.username
state.user.accessToken = data.accessToken
state.user.group = data.group
state.user.firstname = data.firstname
state.user.lastname = data.lastname
}
},
logout(state) {
state.user.accessToken = null
state.user.username = null
state.user.group = null
state.user.firstname = null
state.user.lastname = null
},
setCookieNotification(state, value) {
state.cookieNotification = value
},
setCookieAccepted(state, value) {
state.cookieAccepted = value
},
setLifeTime(state, value) {
state.lifeTime = value
}
}
const actions = {
async doLogin({ commit, dispatch }, loginData) {
commit('loginStart')
try {
const response = await axios.post(url.login, { ...loginData })
/*const cookieA = localStorage.getItem('cookie:accepted')
if (!cookieA) {
commit('loginStop', 'Sie müssen die Cookies akzeptieren!')
commit('setCookieNotification', true)
commit('setCookieAccepted', false)
return
}*/
localStorage.setItem(
'user',
JSON.stringify({
username: response.data.username,
accessToken: response.data.token,
group: response.data.group,
firstname: response.data.firstname,
lastname: response.data.lastname
})
)
commit('loginStop', null)
commit('updateAccessToken', response.data)
if (state.user.group.includes('bar')) {
router.push('/main/bar/geruecht')
} else if (state.user.group.includes('user')) {
router.push('/main/user/add')
} else if (state.user.group.includes('extern')) {
router.push('/main')
}
} catch (err) {
if (err.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
commit('loginStop', err.response.data.error)
commit('updateAccessToken', {
username: null,
accessToken: null,
group: null,
firstname: null,
lastname: null
})
}
},
fetchAccessToken({ commit }) {
commit('updateAccessToken', localStorage.getItem('user'))
},
logout({ commit, rootState }) {
var accessToken = rootState.login.user.accessToken
localStorage.removeItem('user')
localStorage.removeItem('cookie:accepted')
commit('setCookieNotification', true)
commit('setCookieAccepted', false)
commit('logout')
router.push('/login')
axios.get(url.logout, {
headers: { Token: accessToken }
})
},
resetLoginError({ commit }) {
commit('loginStop')
},
acceptNotification({ commit }) {
localStorage.setItem('cookie:accepted', true)
commit('setCookieAccepted', true)
commit('setCookieNotification', false)
},
disableNotification({ commit }) {
commit('setCookieNotification', false)
},
getCookieAccepted({ commit }) {
var cookie = localStorage.getItem('cookie:accepted')
commit('setCookieAccepted', cookie)
},
setLifeTime({ commit }, value) {
commit('setLifeTime', value)
},
async saveLifeTime({ commit, rootState, dispatch }, value) {
try {
const response = await axios.post(
url.saveLifeTime,
{ value: value },
{ headers: { Token: rootState.login.user.accessToken }, timeout }
)
commit('setLifeTime', response.data.value)
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
},
async getLifeTime({ commit, rootState, dispatch }) {
try {
if (!rootState.login.user.accessToken) {
return
}
const response = await axios.get(url.getLifeTime, {
headers: { Token: rootState.login.user.accessToken },
timeout
})
commit('setLifeTime', response.data.value)
var user = JSON.parse(localStorage.getItem('user'))
user.group = response.data.group
localStorage.setItem('user', JSON.stringify(user))
commit('updateAccessToken', user)
dispatch('barUsers/setLockStatus', response.data.lock_bar, {
root: true
})
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
}
}
const getters = {
loggingIn: state => {
return state.loggingIn
},
getGroup: state => {
return state.user.group
},
group: state => {
return state.user.group
},
getToken: state => {
return state.user.accessToken
},
token: state => {
return state.user.accessToken
},
loginError: state => {
return state.loginError
},
isBar: state => {
try {
return state.user.group.includes('bar')
} catch (e) {
return false
}
},
isFinanzer: state => {
try {
return state.user.group.includes('moneymaster')
} catch (e) {
return false
}
},
isUser: state => {
try {
return state.user.group.includes('user')
} catch (e) {
return false
}
},
isGastro: state => {
try {
return state.user.group.includes('gastro')
} catch (e) {
return false
}
},
isExtern: state => {
try {
return state.user.group.includes('extern')
} catch (e) {
return false
}
},
isManagement: state => {
try {
return (
state.user.group.includes('vorstand') ||
state.user.group.includes('gastro') ||
state.user.group.includes('moneymaster')
)
} catch (e) {
return false
}
},
isLoggedIn: state => {
return state.user.accessToken
},
user: state => {
return state.user
},
cookieNotification: state => {
return state.cookieNotification
},
cookieAccepted: state => {
return state.cookieAccepted
},
lifeTime: state => {
return state.lifeTime
}
}
export default {
state,
mutations,
actions,
getters
}

View File

@ -0,0 +1,269 @@
import url from '@/plugins/routes'
import axios from 'axios'
const timeout = 20000
const state = {
priceListLoading: false,
typesLoading: false,
priceList: [],
types: []
}
const mutations = {
setPriceList: (state, priceList) => {
state.priceList = priceList
},
setTypes: (state, types) => {
state.types = types
state.types.sort((a, b) => {
const low = b.name.toLowerCase()
const high = a.name.toLowerCase()
if (high < low) return -1
if (high > low) return 1
return 0
})
},
updatePriceList: (state, drink) => {
var a = state.priceList.find(b => {
return b.id === drink.id
})
if (a) {
a.name = drink.name
a.type = drink.type
a.price = drink.price
a.price_big = drink.price_big
a.price_club = drink.price_club
a.price_club_big = drink.price_club_big
a.premium = drink.premium
a.premium_club = drink.premium_club
a.price_extern_club = drink.price_extern_club
} else {
state.priceList.push({
id: drink.id,
name: drink.name,
type: drink.type,
price: drink.price,
price_big: drink.price_big,
price_club: drink.price_club,
price_club_big: drink.price_club_big,
premium: drink.premium,
premium_club: drink.premium_club,
price_extern_club: drink.price_extern_club
})
}
},
deleteDrinkPrice: (state, data) => {
var index = state.priceList.indexOf(
state.priceList.find(a => {
return a.id === data.id
})
)
state.priceList.splice(index, 1)
},
updateDrinkType: (state, type) => {
var a = state.types.find(b => {
return b.id === type.id
})
if (a) {
a.name = type.name
} else {
state.types.push({
...type
})
}
state.types.sort((a, b) => {
const low = b.name.toLowerCase()
const high = a.name.toLowerCase()
if (high < low) return -1
if (high > low) return 1
return 0
})
},
deleteDrinkType: (state, type) => {
var index = state.types.indexOf(
state.types.find(a => {
return a.id === type.id
})
)
state.types.splice(index, 1)
},
setPriceListLoading: (state, value) => {
state.priceListLoading = value
},
setTypesLoading: (state, value) => {
state.typesLoading = value
}
}
const actions = {
async getPriceList({ commit, dispatch }) {
try {
commit('setPriceListLoading', true)
const response = await axios.get(url.pricelist, { timeout })
commit('setPriceList', response.data)
commit('setPriceListLoading', false)
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
commit('setPriceListLoading', false)
}
},
async getTypes({ commit, dispatch }) {
try {
commit('setTypesLoading', true)
const response = await axios.get(url.getTypes, { timeout })
commit('setTypes', response.data)
commit('setTypesLoading', false)
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
commit('setTypesLoading', false)
}
},
async setDrink({ commit, rootState, dispatch }, data) {
try {
commit('setPriceListLoading', true)
const response = await axios.post(
url.gastro.setDrink,
{ ...data },
{ headers: { Token: rootState.login.user.accessToken }, timeout }
)
commit('updatePriceList', response.data)
commit('setPriceListLoading', false)
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
commit('setPriceListLoading', false)
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
},
async updateDrink({ commit, rootState, dispatch }, data) {
try {
commit('setPriceListLoading', true)
const response = await axios.post(
url.gastro.updateDrink,
{ ...data },
{ headers: { Token: rootState.login.user.accessToken }, timeout }
)
commit('updatePriceList', response.data)
commit('setPriceListLoading', false)
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
commit('setPriceListLoading', false)
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
},
async deleteDrink({ commit, rootState, dispatch }, data) {
try {
commit('setPriceListLoading', true)
await axios.post(
url.gastro.deleteDrink,
{ ...data },
{ headers: { Token: rootState.login.user.accessToken }, timeout }
)
commit('deleteDrinkPrice', data)
commit('setPriceListLoading', false)
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
commit('setPriceListLoading', false)
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
},
async setDrinkType({ commit, rootState, dispatch }, data) {
try {
commit('setTypesLoading', true)
const response = await axios.post(
url.gastro.setType,
{ ...data },
{ headers: { Token: rootState.login.user.accessToken }, timeout }
)
commit('updateDrinkType', response.data)
commit('setTypesLoading', false)
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
commit('setTypesLoading', false)
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
},
async updateDrinkType({ commit, rootState, dispatch }, data) {
try {
commit('setTypesLoading', true)
const response = await axios.post(
url.gastro.updateType,
{ ...data },
{ headers: { Token: rootState.login.user.accessToken }, timeout }
)
commit('updateDrinkType', response.data)
commit('setTypesLoading', false)
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
commit('setTypesLoading', false)
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
},
async deleteDrinkType({ commit, rootState, dispatch }, data) {
try {
commit('setTypesLoading', true)
await axios.post(
url.gastro.deleteType,
{ ...data },
{ headers: { Token: rootState.login.user.accessToken }, timeout }
)
commit('deleteDrinkType', data)
commit('setTypesLoading', false)
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
commit('setTypesLoading', false)
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
}
}
const getters = {
priceList: state => {
return state.priceList
},
types: state => {
return state.types
},
priceListLoading: state => {
return state.priceListLoading
},
typesLoading: state => {
return state.typesLoading
}
}
export default {
namespaced: true,
state,
mutations,
actions,
getters
}

View File

@ -0,0 +1,460 @@
import axios from 'axios'
import url from '@/plugins/routes'
const timeout = 20000
const state = {
month: [],
allUsers: [],
disabled: false
}
const mutations = {
setAllUsers: (state, users) => {
state.allUsers = []
state.allUsers = users
for (let i = 0; i < state.allUsers.length; i++) {
state.allUsers[i].fullName =
state.allUsers[i].firstname + ' ' + state.allUsers[i].lastname
}
},
createMonth: (state, date) => {
let month = []
let id = 0
const year = date.getFullYear()
const mon = date.getMonth()
let a = new Date(year, mon + 1, 0)
let days = a.getDate()
let startDate = 1
for (let intDay = 1; intDay <= days; intDay++) {
if (new Date(year, mon, intDay).getDay() === 3) {
startDate = intDay
break
}
}
let end = false
let week = { id: id, days: {} }
for (let intDay = startDate; intDay <= days + 7; intDay++) {
if (end) break
let currentDate = new Date(year, mon, intDay)
switch (currentDate.getDay()) {
case 1:
mutations.setStartEndDate(week)
month.push(week)
id++
week = { id: id, days: {} }
week.days.monday = {
id: currentDate.getDay(),
date: currentDate,
name: 'Montag',
worker: [],
loading: false,
locked: false,
jobkinddate: []
}
break
case 2:
week.days.tuesday = {
id: currentDate.getDay(),
date: currentDate,
name: 'Dienstag',
worker: [],
loading: false,
locked: false,
jobkinddate: []
}
break
case 3:
if (currentDate.getMonth() === mon + 1) {
end = true
mutations.setStartEndDate(week)
month.push(week)
} else {
week.days.wednesday = {
id: currentDate.getDay(),
date: currentDate,
name: 'Mittwoch',
worker: [],
loading: false,
locked: false,
jobkinddate: []
}
}
break
case 4:
week.days.thursday = {
id: currentDate.getDay(),
date: currentDate,
name: 'Donnerstag',
worker: [],
loading: false,
locked: false,
jobkinddate: []
}
break
case 5:
week.days.friday = {
id: currentDate.getDay(),
date: currentDate,
name: 'Freitag',
worker: [],
loading: false,
locked: false,
jobkinddate: []
}
break
case 6:
week.days.satturday = {
id: currentDate.getDay(),
date: currentDate,
name: 'Samstag',
worker: [],
loading: false,
locked: false,
jobkinddate: []
}
break
case 0:
week.days.sunday = {
id: currentDate.getDay(),
date: currentDate,
name: 'Sonntag',
worker: [],
loading: false,
locked: false,
jobkinddate: []
}
break
}
}
state.month = month
},
setStartEndDate: week => {
if (week.days.monday) {
week.startDate = week.days.monday.date
} else if (week.days.tuesday) {
week.startDate = week.days.tuesday.date
} else if (week.days.wednesday) {
week.startDate = week.days.wednesday.date
} else if (week.days.thursday) {
week.startDate = week.days.thursday.date
} else if (week.days.friday) {
week.startDate = week.days.friday.date
} else if (week.days.satturday) {
week.startDate = week.days.satturday.date
} else if (week.days.sunday) {
week.startDate = week.days.sunday.date
}
if (week.days.sunday) {
week.endDate = week.days.sunday.date
} else if (week.days.satturday) {
week.endDate = week.days.satturday.date
} else if (week.days.friday) {
week.endDate = week.days.friday.date
} else if (week.days.thursday) {
week.endDate = week.days.thursday.date
} else if (week.days.wednesday) {
week.endDate = week.days.wednesday.date
} else if (week.days.tuesday) {
week.endDate = week.days.tuesday.date
} else if (week.days.monday) {
week.endDate = week.days.monday.date
}
},
// eslint-disable-next-line no-unused-vars
updateMonthWorker: (state, { workers, date, getters }) => {
var day = getters.getDay(date)
day.jobkinddate.forEach(item => {
var filtered = workers.filter(worker => {
return item.job_kind.id === (worker.job_kind ? worker.job_kind.id : 1)
})
var filteredWorkers = []
filtered.forEach(item => {
filteredWorkers.push(item.user)
})
filteredWorkers.forEach(worker => {
if (
!item.worker.find(a => {
return a.id === worker.id
})
) {
item.worker.push(worker)
item.backupWorker.push(worker)
}
})
item.worker.forEach(worker => {
if (
!filteredWorkers.find(a => {
return a.id === worker.id
})
) {
item.worker.splice(item.worker.indexOf(worker), 1)
}
})
})
},
updateMonthLocked: (state, { locked, date, getters }) => {
var day = getters.getDay(date)
day.locked = !!locked
},
updateMonthJobkind: (state, { data, date, getters }) => {
let day = getters.getDay(date)
var backup = []
for (let jobkind in day.jobkinddate) {
if (day.jobkinddate[jobkind].worker !== undefined) {
backup.push({
id: day.jobkinddate[jobkind].job_kind.id,
worker: day.jobkinddate[jobkind].worker,
backupWorker: day.jobkinddate[jobkind].backupWorker
})
} else {
backup.push({
id: day.jobkinddate[jobkind].job_kind.id,
worker: [],
backupWorker: []
})
}
}
day.jobkinddate = [...data]
var test = day.jobkinddate.find(jobkind => {
return jobkind.job_kind.id === 1
})
if (!test) {
day.jobkinddate.push({
id: -1,
job_kind: { id: 1, name: 'Bardienst' },
maxpersons: 2,
daydate: {
year: date.getFullYear(),
month: date.getMonth() + 1,
day: date.getDate()
},
worker: [],
backupWorker: []
})
}
for (var jobkind in day.jobkinddate) {
var worker = backup.find(item => {
return item.id === day.jobkinddate[jobkind].job_kind.id
})
day.jobkinddate[jobkind].worker = worker ? worker.worker : []
day.jobkinddate[jobkind].backupWorker = worker ? worker.backupWorker : []
}
},
setAllDayLoading: state => {
for (let week = 0; week < state.month.length; week++) {
for (let day in state.month[week].days) {
state.month[week].days[day].loading = true
}
}
},
setDayLoading: (state, { date, getters }) => {
let day = getters.getDay(date)
day.loading = true
},
setDayNotLoading: (state, { date, getters }) => {
let day = getters.getDay(date)
day.loading = false
},
setDisabled: (state, data) => {
state.disabled = data
}
}
const actions = {
createMonth({ commit }, date) {
commit('setDisabled', true)
commit('createMonth', date)
commit('setDisabled', false)
},
async getAllUsers({ commit, rootState, dispatch }) {
try {
const response = await axios.get(url.vorstand.sm.searchUser, {
headers: { Token: rootState.login.user.accessToken },
timeout
})
commit('setAllUsers', response.data)
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (e.response)
if (e.response.data === 401) dispatch('logout', null, { root: true })
}
},
// eslint-disable-next-line no-unused-vars
async addUser({ commit, rootState, dispatch }, data) {
try {
// eslint-disable-next-line no-unused-vars
const response = await axios.post(
url.vorstand.sm.addUser,
{ ...data },
{
headers: { Token: rootState.login.user.accessToken },
timeout
}
)
//commit('updateMonth', { ...response.data[0], com: 'add' })
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
},
// eslint-disable-next-line no-unused-vars
async getUsers({ commit, rootState, dispatch, getters }, data) {
commit('setAllDayLoading')
try {
const response = await axios.post(
url.vorstand.sm.getUsers,
{ ...data },
{ headers: { Token: rootState.login.user.accessToken }, timeout }
)
for (var day in response.data) {
var date = new Date(
response.data[day].day.date.year,
response.data[day].day.date.month - 1,
response.data[day].day.date.day
)
commit('updateMonthJobkind', {
data: [...response.data[day].jobkinddate],
date,
getters
})
commit('updateMonthWorker', {
workers: [...response.data[day].worker],
date,
getters
})
commit('updateMonthLocked', {
locked: response.data[day].day.locked,
date,
getters
})
commit('setDayNotLoading', { date, getters })
}
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
},
// eslint-disable-next-line no-unused-vars
async deleteUser({ commit, rootState, dispatch }, data) {
try {
// eslint-disable-next-line no-unused-vars
const response = await axios.post(
url.vorstand.sm.deleteUser,
{ ...data },
{ headers: { Token: rootState.login.user.accessToken }, timeout }
)
//commit('updateMonth', { ...data, com: 'delete' })
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
},
async lockDay({ commit, rootState, dispatch, getters }, data) {
try {
const response = await axios.post(
url.vorstand.sm.lockDay,
{ ...data },
{ headers: { Token: rootState.login.user.accessToken }, timeout }
)
console.log(response.data)
let date = new Date(
response.data.date.year,
response.data.date.month - 1,
response.data.date.day
)
commit('updateMonthLocked', {
locked: response.data.locked,
date,
getters
})
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
},
async updateJobKindDate(
{ commit, rootState, dispatch, getters },
{ data, date }
) {
try {
commit('setDayLoading', { date, getters })
const response = await axios.post(
url.vorstand.sm.updateJobKindDates,
[...data],
{ headers: { Token: rootState.login.user.accessToken }, timeout }
)
commit('updateMonthJobkind', { data: response.data, date, getters })
commit('setDayNotLoading', { date, getters })
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
},
setDayLoading({ commit, getters }, date) {
commit('setDayLoading', { date, getters })
},
setDayNotLoading({ commit, getters }, date) {
commit('setDayNotLoading', { date, getters })
}
}
const getters = {
month: state => {
return state.month
},
allUsers: state => {
return state.allUsers
},
getDayLoading: (state, getters) => date => {
let day = getters.getDay(date)
return day.loading
},
getDay: state => date => {
for (let week = 0; week < state.month.length; week++) {
for (let day in state.month[week].days) {
if (state.month[week].days[day].date - date === 0) {
return state.month[week].days[day]
}
}
}
},
disabled: state => {
return state.disabled
},
getStartDate: state => {
return state.month[0].startDate
},
getEndDate: state => {
return state.month[state.month.length - 1].endDate
}
}
export default {
namespaced: true,
state,
mutations,
actions,
getters
}

430
src/store/modules/user.js Normal file
View File

@ -0,0 +1,430 @@
import axios from 'axios'
import url from '@/plugins/routes'
const timeout = 20000
const state = {
user: null,
creditList: [],
loading: false,
addLoading: false,
error: null,
days: [],
messages: [],
status: [],
tokens: []
}
const mutations = {
setStatus: (state, status) => {
state.status = status
},
setUser: (state, user) => {
state.user = user
let list = {}
for (let creditList in user['creditList']) {
let amount = mutations.createAmount(user['creditList'][creditList])
let credit = mutations.createCredit(user['creditList'][creditList])
let sum = mutations.createSum(credit, amount)
list[creditList] = [{ ...credit }, { ...amount }, { ...sum }]
}
state.user.creditList = list
state.creditList = []
state.error = ''
},
setTokens: (state, tokens) => {
state.tokens = tokens
},
createAmount(creditList) {
let amount = {
type: 'Schulden',
jan_amount: 0 - creditList.jan.depts,
feb_amount: 0 - creditList.feb.depts,
maer_amount: 0 - creditList.maer.depts,
apr_amount: 0 - creditList.apr.depts,
mai_amount: 0 - creditList.mai.depts,
jun_amount: 0 - creditList.jun.depts,
jul_amount: 0 - creditList.jul.depts,
aug_amount: 0 - creditList.aug.depts,
sep_amount: 0 - creditList.sep.depts,
okt_amount: 0 - creditList.okt.depts,
nov_amount: 0 - creditList.nov.depts,
dez_amount: 0 - creditList.dez.depts,
last: 0 - creditList['last']
}
amount.sum =
amount.jan_amount +
amount.feb_amount +
amount.maer_amount +
amount.apr_amount +
amount.mai_amount +
amount.jun_amount +
amount.jul_amount +
amount.aug_amount +
amount.sep_amount +
amount.okt_amount +
amount.nov_amount +
amount.dez_amount
return amount
},
createCredit(creditList) {
let credit = {
type: 'Guthaben',
jan_amount: creditList.jan.credit,
feb_amount: creditList.feb.credit,
maer_amount: creditList.maer.credit,
apr_amount: creditList.apr.credit,
mai_amount: creditList.mai.credit,
jun_amount: creditList.jun.credit,
jul_amount: creditList.jul.credit,
aug_amount: creditList.aug.credit,
sep_amount: creditList.sep.credit,
okt_amount: creditList.okt.credit,
nov_amount: creditList.nov.credit,
dez_amount: creditList.dez.credit
}
credit.sum =
credit.jan_amount +
credit.feb_amount +
credit.maer_amount +
credit.apr_amount +
credit.mai_amount +
credit.jun_amount +
credit.jul_amount +
credit.aug_amount +
credit.sep_amount +
credit.okt_amount +
credit.nov_amount +
credit.dez_amount
return credit
},
createSum(credit, amount) {
let sum = {
type: 'Summe',
jan_amount: credit.jan_amount + amount.jan_amount,
feb_amount: credit.feb_amount + amount.feb_amount,
maer_amount: credit.maer_amount + amount.maer_amount,
apr_amount: credit.apr_amount + amount.apr_amount,
mai_amount: credit.mai_amount + amount.mai_amount,
jun_amount: credit.jun_amount + amount.jun_amount,
jul_amount: credit.jul_amount + amount.jul_amount,
aug_amount: credit.aug_amount + amount.aug_amount,
sep_amount: credit.sep_amount + amount.sep_amount,
okt_amount: credit.okt_amount + amount.okt_amount,
nov_amount: credit.nov_amount + amount.nov_amount,
dez_amount: credit.dez_amount + amount.dez_amount
}
sum.sum =
sum.jan_amount +
sum.feb_amount +
sum.maer_amount +
sum.apr_amount +
sum.mai_amount +
sum.jun_amount +
sum.jul_amount +
sum.aug_amount +
sum.sep_amount +
sum.okt_amount +
sum.nov_amount +
sum.dez_amount
return sum
},
setLoading(state, value) {
state.loading = value
},
setAddLoading(state, value) {
state.addLoading = value
},
setError(state, { value, error }) {
//clearTimeout(state.error? state.error.timeout : null)
state.error = { value, error }
state.error.timeout = setTimeout(() => {
state.error = null
}, 6000)
},
createDays(state, date) {
let days = []
for (let i = 0; i <= 10; i++) {
days.push({
date: new Date(
date.getFullYear(),
date.getMonth(),
date.getDate() + i,
12
),
job: false,
workers: []
})
}
state.days = days
},
updateDay(state, data) {
const date = data.date
for (let day in state.days) {
if (state.days[day].date - date === 0) {
state.days[day].job = data.job
if (data.workers) state.days[day].workers = data.workers
}
}
},
addMessage: (state, data) => {
var message = null
if (state.messages.length > 0) {
if (
state.messages[0].user.username === data.user.username &&
!data.error
) {
message = state.messages[0]
if ((new Date() - state.messages[0].date) / 1000 < 2) {
clearTimeout(message.timeout)
message.amount = message.amount + data.amount
message.visible = true
message.date = new Date()
message.timeout = setTimeout(() => {
message.visible = false
}, 300000)
return
} else {
message.visible = false
}
}
}
let message2 = {
user: data.user,
error: data.error,
storno: false,
loading: false,
visible: true,
amount: data.amount,
date: new Date(),
timeout: setTimeout(() => {
message2.visible = false
}, 300000)
}
state.messages.unshift(message2)
},
updateMessage: (state, data) => {
var message = state.messages.find(msg => {
return msg.date - data.date === 0 ? true : false
})
if (message) {
if (data.storno !== undefined) message.storno = data.storno
if (data.loading !== undefined) message.loading = data.loading
}
}
}
const actions = {
async getUser({ commit, rootState, dispatch }) {
commit('setLoading', true)
try {
const response = await axios.get(url.userMain, {
headers: { Token: rootState.login.user.accessToken },
timeout
})
commit('setUser', response.data)
commit('setError', '')
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
commit('setLoading', false)
},
async addAmount({ commit, rootState, dispatch }, amount) {
commit('setAddLoading', true)
try {
const response = await axios.post(
url.userAddAmount,
{ amount: amount },
{ headers: { Token: rootState.login.user.accessToken }, timeout }
)
commit('setUser', response.data)
commit('addMessage', {
user: rootState.login.user,
amount: amount,
error: false
})
commit('setError', '')
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
commit('addMessage', {
user: rootState.login.user,
amount: amount,
error: true
})
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
commit('setAddLoading', false)
},
async saveConfig({ commit, rootState, dispatch }, data) {
commit('setLoading', true)
try {
const response = await axios.post(
url.user.config,
{ ...data },
{ headers: { Token: rootState.login.user.accessToken }, timeout }
)
console.log(response.data)
commit('setUser', response.data)
commit('setError', { value: 'Daten gespeichert', error: false })
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (e.response) {
if (e.response.status === 401) dispatch('logout', null, { root: true })
if (e.response.data) {
commit('setError', { value: e.response.data.error, error: true })
}
}
}
commit('setLoading', false)
},
createDays({ commit }, date) {
commit('createDays', date)
},
async updateDay({ commit, rootState, dispatch }, data) {
commit('setLoading', true)
try {
const response = await axios.post(
url.user.job,
{ date: data.date.getTime() / 1000 },
{ headers: { Token: rootState.login.user.accessToken }, timeout }
)
commit('updateDay', { ...response.data, date: data.date })
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (e.response) {
if (e.response.status === 401) dispatch('logout', null, { root: true })
if (e.response.data) {
commit('setError', e.response.data.error)
}
}
}
commit('setLoading', false)
},
async storno({ commit, rootState, dispatch }, data) {
commit('updateMessage', { date: data.date, loading: true })
try {
const response = await axios.post(
url.user.storno,
{
amount: data.amount
},
{ headers: { Token: rootState.login.user.accessToken }, timeout }
)
commit('setUser', response.data)
commit('updateMessage', { date: data.date, storno: true })
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
commit('updateMessage', { date: data.date, loading: false })
},
async getStatus({ commit, rootState, dispatch }) {
try {
const response = await axios.get(url.user.getAllStatus, {
headers: { Token: rootState.login.user.accessToken },
timeout
})
commit('setStatus', response.data)
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
},
async getTokens({ commit, rootState, dispatch }) {
try {
const response = await axios.get(url.user.getAccessTokens, {
headers: { Token: rootState.login.user.accessToken },
timeout
})
commit('setTokens', response.data)
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
},
async deleteToken({ commit, rootState, dispatch }, token) {
try {
const response = await axios.post(url.user.getAccessTokens, token, {
headers: { Token: rootState.login.user.accessToken },
timeout
})
commit('setTokens', response.data)
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
}
}
const getters = {
user: state => {
return state.user
},
year: state => {
let year = 0
for (let creditList in state.user.creditList) {
let currentYear = parseInt(creditList)
if (currentYear > year) year = currentYear
}
return year
},
loading: state => {
return state.loading
},
addLoading: state => {
return state.addLoading
},
error: state => {
return state.error
},
days: state => {
return state.days
},
messages: state => {
return state.messages
},
status: state => {
return state.status
},
tokens: state => {
return state.tokens
}
}
export default {
namespaced: true,
state,
mutations,
actions,
getters
}

View File

@ -0,0 +1,216 @@
import url from '@/plugins/routes'
import axios from 'axios'
const timeout = 20000
const state = {
users: [],
status: [],
usersLoading: false,
statusLoading: false
}
const mutations = {
setUsers: (state, users) => {
state.users = users
},
setStatus: (state, status) => {
state.status = status
},
updateUser: (state, user) => {
let exists = state.users.find(a => {
return a.username === user.username
})
if (exists) {
exists.firstname = user.firstname
exists.lastname = user.lastname
exists.mail = user.mail
exists.statusgroup = user.statusgroup
exists.voting = user.voting
exists.workgroups = user.workgroup
} else {
state.users.push({
username: user.username,
firstname: user.firstname,
lastname: user.lastname,
mail: user.mail,
statusgroup: user.statusgroup,
voting: user.voting,
workgroups: user.workgroups
})
}
},
updateStatus: (state, status) => {
let exists = state.status.find(a => {
return a.id === status.id
})
if (exists) {
exists.name = status.name
} else {
state.status.push(status)
}
},
deleteStatus: (state, status) => {
let index = state.status.indexOf(
state.status.find(a => {
return a.id === status.id
})
)
state.status.splice(index, 1)
},
setUsersLoading: (state, value) => {
state.usersLoading = value
},
setStatusLoading: (state, value) => {
state.statusLoading = value
},
updateWorkgroups: (state, { id, workgroups }) => {
let exists = state.users.find(a => {
return a.id === id
})
if (exists) {
exists.workgroups = workgroups
}
}
}
const actions = {
async getUsers({ commit, rootState, dispatch }) {
try {
commit('setUsersLoading', true)
const response = await axios.get(url.getUsers, {
headers: { Token: rootState.login.user.accessToken },
timeout
})
commit('setUsers', response.data)
commit('setUsersLoading', false)
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
commit('setUsersLoading', false)
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
},
async getUsersWithExtern({ commit, rootState, dispatch }) {
try {
commit('setUsersLoading', true)
const response = await axios.get(url.getUsers + '?extern=1', {
headers: { Token: rootState.login.user.accessToken },
timeout
})
commit('setUsers', response.data)
commit('setUsersLoading', false)
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
commit('setUsersLoading', false)
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
},
async getStatus({ commit, rootState, dispatch }) {
try {
commit('setStatusLoading', true)
const response = await axios.get(url.user.getAllStatus, {
headers: { Token: rootState.login.user.accessToken },
timeout
})
commit('setStatus', response.data)
commit('setStatusLoading', false)
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
commit('setStatusLoading', false)
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
},
async updateStatusUser({ commit, rootState, dispatch }, data) {
try {
commit('setUsersLoading', true)
const response = await axios.post(
url.vorstand.um.updateStatusUser,
{ ...data },
{ headers: { Token: rootState.login.user.accessToken }, timeout }
)
commit('updateUser', response.data)
commit('setUsersLoading', false)
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
commit('setUsersLoading', false)
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
},
async updateVoting({ commit, rootState, dispatch }, data) {
try {
commit('setUsersLoading', true)
const response = await axios.post(
url.vorstand.um.updateVoting,
{ ...data },
{ headers: { Token: rootState.login.user.accessToken }, timeout }
)
commit('updateUser', response.data)
commit('setUsersLoading', false)
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
commit('setUsersLoading', false)
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
},
async updateWorkgroups({ commit, rootState, dispatch }, data) {
try {
commit('setUsersLoading', true)
const response = await axios.post(
url.vorstand.um.updateWorkgroups,
{ ...data },
{ headers: { Token: rootState.login.user.accessToken }, timeout }
)
commit('updateWorkgroups', { id: data.id, workgroups: response.data })
commit('setUsersLoading', false)
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
commit('setUsersLoading', false)
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
}
}
const getters = {
users: state => {
return state.users
},
status: state => {
return state.status
},
usersLoading: state => {
return state.usersLoading
},
statusLoading: state => {
return state.statusLoading
}
}
export default {
namespaced: true,
state,
mutations,
actions,
getters
}

View File

@ -0,0 +1,133 @@
import url from '@/plugins/routes'
import axios from 'axios'
const timeout = 20000
const state = {
workgroupsLoading: false,
workgroups: []
}
const mutations = {
setWorkgroups: (state, workgroups) => {
state.workgroups = workgroups
},
updateWorkgroup: (state, workgroup) => {
console.log('workgroup is', workgroup)
let exists = state.workgroups.find(a => {
return a.id === workgroup.id
})
console.log('exists is', exists)
if (exists) {
exists.name = workgroup.name
exists.boss = workgroup.boss
} else {
state.workgroups.push(workgroup)
}
},
deleteWorkgroup: (state, workergroup) => {
let index = state.workgroups.indexOf(
state.workgroups.find(a => {
return a.id === workergroup.id
})
)
state.workgroups.splice(index, 1)
},
setWorkgroupLoading: (state, value) => {
state.workgroupsLoading = value
}
}
const actions = {
async getAllWorkgroups({ commit, rootState, dispatch }) {
try {
commit('setWorkgroupLoading', true)
const response = await axios.get(url.vorstand.wm.getAllWorkgroups, {
headers: { Token: rootState.login.user.accessToken },
timeout
})
commit('setWorkgroups', response.data)
commit('setWorkgroupLoading', false)
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
commit('setWorkgroupLoading', false)
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
},
async setWorkgroup({ commit, rootState, dispatch }, data) {
try {
commit('setWorkgroupLoading', true)
const response = await axios.put(
url.vorstand.wm.workgroup,
{ ...data },
{ headers: { Token: rootState.login.user.accessToken }, timeout }
)
commit('updateWorkgroup', response.data)
commit('setWorkgroupLoading', false)
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
},
async updateWorkgroup({ commit, rootState, dispatch }, data) {
try {
commit('setWorkgroupLoading', true)
const repsonse = await axios.post(
url.vorstand.wm.workgroup,
{ ...data },
{ headers: { Token: rootState.login.user.accessToken }, timeout }
)
commit('updateWorkgroup', repsonse.data)
commit('setWorkgroupLoading', false)
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
},
async deleteWorkgroup({ commit, rootState, dispatch }, data) {
try {
commit('setWorkgroupLoading', true)
await axios.post(
url.vorstand.wm.deleteWorkgroup,
{ ...data },
{ headers: { Token: rootState.login.user.accessToken }, timeout }
)
commit('deleteWorkgroup', data)
commit('setWorkgroupLoading', false)
dispatch('getLifeTime', null, { root: true })
} catch (e) {
if (e.message == 'Network Error') {
dispatch('connectionError/addError', null, { root: true })
}
if (e.response)
if (e.response.status === 401) dispatch('logout', null, { root: true })
}
}
}
const getters = {
workgroups: state => {
return state.workgroups
},
workgroupLoading: state => {
return state.workgroupsLoading
}
}
export default {
namespaced: true,
state,
mutations,
actions,
getters
}

View File

@ -1,38 +1,13 @@
<template>
<div>
<TitleBar/>
<CreditLists></CreditLists>
</div>
<v-content>
<router-view/>
</v-content>
</template>
<script>
import TitleBar from "@/components/TitleBar";
import axios from 'axios'
import CreditLists from "@/components/baruser/CreditLists";
export default {
name: "BarView",
components: {CreditLists, TitleBar},
created() {
this.getUser()
},
methods: {
getUser() {
// eslint-disable-next-line no-console
console.log(this.$store.getters.getToken)
axios.get("http://localhost:5000/bar", {headers: {Token: this.$store.getters.getToken}})
.then(response => {
// eslint-disable-next-line no-console
console.log(response.data)
})
.catch(error => {
// eslint-disable-next-line no-console
console.log(error)
})
}
}
}
export default {
name: 'BarView'
}
</script>
<style scoped>
</style>
<style scoped></style>

View File

@ -1,61 +1,27 @@
<template>
<div>
<TitleBar/>
<v-navigation-drawer permanent width="auto" app clipped class="elevation-2">
<v-container>
<h1 v-for="user in users" v-bind:key="user.id">{{user.firstname}} {{user.lastname}}</h1>
</v-container>
</v-navigation-drawer>
<v-content>
<v-container>
</v-container>
</v-content>
</div>
<div>
<router-view />
</div>
</template>
<script>
import TitleBar from "@/components/TitleBar";
import axios from 'axios'
import { mapActions } from 'vuex'
export default {
name: "FinanzerView",
components: {TitleBar},
created() {
this.getUser()
},
data () {
return {
users: [],
}
},
methods: {
getUser() {
axios.get("http://localhost:5000/getFinanzerMain", {headers: {Token: this.$store.getters.getToken}})
.then(response => {
// eslint-disable-next-line no-console
console.log(response.data)
for (let user in response.data) {
// eslint-disable-next-line no-console
console.log(response.data[user])
const lastId = this.users.length > 0 ? this.users[this.users.length - 1].id : 0
this.users.push({id: lastId + 1, username: response.data[user].username, firstname: response.data[user].firstname, lastname: response.data[user].lastname})
}
// eslint-disable-next-line no-console
console.log(this.users)
})
.catch(error => {
// eslint-disable-next-line no-console
console.log("error: ", error.response.data.error)
})
},
}
}
export default {
name: 'FinanzerView',
components: {},
created() {
this.getAllUsers()
this.getUsers()
this.createYears()
},
methods: mapActions({
getAllUsers: 'finanzerUsers/getAllUsers',
getUsers: 'finanzerUsers/getUsers',
createYears: 'finanzerUsers/createYears',
logout: 'logout'
})
}
</script>
<style scoped>
</style>
<style scoped></style>

View File

@ -1,17 +0,0 @@
<template>
<div>
<TitleBar/>
</div>
</template>
<script>
// @ is an alias to /src
import TitleBar from "@/components/TitleBar";
export default {
name: 'home',
components: {
TitleBar
}
}
</script>

View File

@ -1,96 +1,93 @@
<template>
<div>
<TitleBar/>
<div>
<v-content>
<v-container
class="fill-height"
fluid
>
<v-row
align="center"
justify="center"
>
<v-col
cols="12"
sm="8"
md="4"
>
<v-card class="elevation-12">
<v-toolbar
color="blue accent-4"
dark
flat
>
<v-toolbar-title>Login form</v-toolbar-title>
<v-spacer />
</v-toolbar>
<v-card-text>
<v-form >
<v-text-field
label="Login"
name="login"
prepend-icon="person"
type="text"
v-model="username"
ref="first"
@keyup.enter="login"
@change="resetError"
/>
<v-container class="fill-height" fluid>
<v-row align="center" justify="center">
<v-col cols="12" sm="8" md="4">
<v-card class="elevation-12">
<v-toolbar color="blue accent-4" dark flat>
<v-toolbar-title>Login form</v-toolbar-title>
<v-spacer />
</v-toolbar>
<v-card-text>
<v-form>
<v-text-field
label="Login"
name="login"
type="text"
v-model="username"
ref="first"
@keyup.enter="
doLogin({ username: username, password: password })
"
@input="resetLoginError"
>
<template v-slot:prepend-inner>
<v-icon>{{account}}</v-icon>
</template>
</v-text-field>
<v-text-field
id="password"
label="Password"
name="password"
prepend-icon="lock"
type="password"
v-model="password"
@keyup.enter="login"
@change="resetError"
/>
</v-form>
</v-card-text>
<v-alert v-if="loginFail" dense type="error">{{ loginFail }}</v-alert>
<v-card-actions>
<v-spacer />
<v-btn @click="login" @submit.prevent="login" color="primary">Login</v-btn>
</v-card-actions>
</v-card>
</v-col>
</v-row>
</v-container>
<v-text-field
id="password"
label="Password"
name="password"
type="password"
v-model="password"
@keyup.enter="
doLogin({ username: username, password: password })
"
@input="resetLoginError"
>
<template v-slot:prepend-inner>
<v-icon>{{lock}}</v-icon>
</template>
</v-text-field>
</v-form>
<div class="text-center">
<v-progress-circular indeterminate v-if="loggingIn" />
</div>
</v-card-text>
<v-alert v-if="loginError" dense type="error">{{
loginError
}}</v-alert>
<v-card-actions>
<v-btn x-small text class="text-capitalize caption" :to="{name: 'resetPassword'}">Password vergessen?</v-btn>
<v-spacer />
<v-btn
@click="doLogin({ username: username, password: password })"
@submit.prevent="
doLogin({ username: username, password: password })
"
color="primary"
>Login</v-btn
>
</v-card-actions>
</v-card>
</v-col>
</v-row>
</v-container>
</v-content>
</div>
</div>
</template>
<script>
import TitleBar from "@/components/TitleBar";
export default {
name: "Login",
components: {TitleBar},
data() {
return {
username: null,
password: null
}
},
methods: {
login() {
// eslint-disable-next-line no-console
let o = {username: this.username, password: this.password}
this.$store.dispatch("doLogin", o)
},
resetError() {
this.$store.dispatch("resetLoginError")
}
},
computed: {
loginFail() {
return this.$store.state.loginError
}
}
// eslint-disable-next-line no-unused-vars
import { mapActions, mapGetters } from 'vuex'
import { mdiAccount, mdiLock } from '@mdi/js'
export default {
name: 'Login',
components: {},
data() {
return {
username: null,
password: null,
account: mdiAccount,
lock: mdiLock
}
},
methods: mapActions(['doLogin', 'resetLoginError']),
computed: mapGetters(['loginError', 'loggingIn'])
}
</script>
<style scoped>
</style>
<style scoped></style>

117
src/views/MainView.vue Normal file
View File

@ -0,0 +1,117 @@
<template>
<div>
<v-navigation-drawer
v-if="isLoggedIn"
mini-variant
expand-on-hover
app
clipped
permanent
overflow
>
<v-list>
<v-list-item v-if="isExtern" class="title">
<v-list-item-icon>
<v-icon>{{person}}</v-icon>
</v-list-item-icon>
<v-list-item-title>
{{user.firstname}} {{user.lastname}}
</v-list-item-title>
</v-list-item>
<v-list-item :disabled="lockedBar" v-if="isUser" class="title" link :to="{name: 'add'}">
<v-list-item-icon>
<v-icon>{{person}}</v-icon>
</v-list-item-icon>
<v-list-item-title>{{user.firstname}} {{user.lastname}}</v-list-item-title>
</v-list-item>
<v-list-item v-if="isBar" class="title" link :to="{name: 'geruecht'}">
<v-list-item-icon>
<v-icon>{{glass_cocktail}}</v-icon>
</v-list-item-icon>
<v-list-item-title>
Bar
</v-list-item-title>
</v-list-item>
<v-list-item :disabled="lockedBar" v-if="isManagement" class="title" link :to="{name: 'serviceManagement', params: {year: new Date().getFullYear(), month: new Date().getMonth() + 1}}">
<v-list-item-icon>
<v-icon>{{king}}</v-icon>
</v-list-item-icon>
<v-list-item-title>
Vorstand
</v-list-item-title>
</v-list-item>
<v-list-item :disabled="lockedBar" v-if="isGastro" class="title" link :to="{name: 'gastroPricelist'}">
<v-list-item-icon>
<v-icon>{{gastro}}</v-icon>
</v-list-item-icon>
<v-list-item-title>
Gastro
</v-list-item-title>
</v-list-item>
<v-list-item :disabled="lockedBar" v-if="isFinanzer" class="title" link :to="{name: 'overview'}">
<v-list-item-icon>
<v-icon>{{attach_money}}</v-icon>
</v-list-item-icon>
<v-list-item-title>Finanzer</v-list-item-title>
</v-list-item>
</v-list>
<v-divider />
<router-view name="nav" />
<template v-slot:append>
<v-list>
<v-list-item>
<v-list-item-icon>
<v-icon>{{exit_to_app}}</v-icon>
</v-list-item-icon>
<v-list-item-title>
<v-btn block text @click="logout">Logout</v-btn>
</v-list-item-title>
</v-list-item>
</v-list>
</template>
</v-navigation-drawer>
<router-view />
</div>
</template>
<script>
import { mapActions, mapGetters } from 'vuex'
import {mdiAccount, mdiCurrencyEur, mdiExitToApp, mdiGlassCocktail, mdiChessKing, mdiFoodForkDrink} from '@mdi/js'
export default {
name: 'MainView',
data () {
return {
person: mdiAccount,
attach_money: mdiCurrencyEur,
exit_to_app: mdiExitToApp,
glass_cocktail: mdiGlassCocktail,
king: mdiChessKing,
gastro: mdiFoodForkDrink
}
},
components: { },
created() {
},
methods: {
...mapActions({
logout: 'logout'
})
},
computed: {
...mapGetters({
group: 'group',
isBar: 'isBar',
isUser: 'isUser',
isFinanzer: 'isFinanzer',
isGastro: 'isGastro',
isManagement: 'isManagement',
isLoggedIn: 'isLoggedIn',
isExtern: 'isExtern',
user: 'user',
lockedBar: 'barUsers/locked'
})
}
}
</script>
<style scoped></style>

27
src/views/UserView.vue Normal file
View File

@ -0,0 +1,27 @@
<template>
<v-content>
<router-view/>
</v-content>
</template>
<script>
import { mapActions, mapGetters } from 'vuex'
export default {
name: 'UserView',
created() {
this.getUser()
},
methods: {
...mapActions({
getUser: 'user/getUser'
})
},
computed: {
...mapGetters({
user: 'user/user'
})
}
}
</script>
<style scoped></style>

View File

@ -0,0 +1,27 @@
<template>
<div>
<SearchBar />
<CreditLists></CreditLists>
</div>
</template>
<script>
import CreditLists from '@/components/baruser/CreditLists'
import { mapActions } from 'vuex'
// eslint-disable-next-line no-unused-vars
import axios from 'axios'
import SearchBar from '../../components/baruser/SearchBar'
export default {
name: 'GeruechteView',
components: { SearchBar, CreditLists },
created() {},
data() {
return {}
},
methods: {
...mapActions(['logout'])
}
}
</script>
<style scoped></style>

View File

@ -0,0 +1,17 @@
<template>
<v-content>
<PriceList />
</v-content>
</template>
<script>
import PriceList from "@/components/pricelist/PriceList";
export default {
name: "PriceListView",
components: {PriceList}
}
</script>
<style scoped>
</style>

View File

@ -1,5 +1,15 @@
//const fs = require('fs')
module.exports = {
"transpileDependencies": [
"vuetify"
]
}
transpileDependencies: ['vuetify'],
devServer: {
disableHostCheck: true
// https: {
// key: fs.readFileSync('./cert/server.key'),
// cert: fs.readFileSync('./cert/server.crt')
// }
},
configureWebpack: {
devtool: 'source-map'
}
}