#2-protocol #6
14 changed files with 708 additions and 24 deletions
156
package-lock.json
generated
156
package-lock.json
generated
|
@ -11,7 +11,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@headlessui/vue": "^1.7.13",
|
"@headlessui/vue": "^1.7.13",
|
||||||
"@heroicons/vue": "^2.1.5",
|
"@heroicons/vue": "^2.1.5",
|
||||||
"@types/lodash.isequal": "^4.5.8",
|
"@vueup/vue-quill": "^1.2.0",
|
||||||
"axios": "^0.26.1",
|
"axios": "^0.26.1",
|
||||||
"jwt-decode": "^4.0.0",
|
"jwt-decode": "^4.0.0",
|
||||||
"lodash.clonedeep": "^4.5.0",
|
"lodash.clonedeep": "^4.5.0",
|
||||||
|
@ -31,6 +31,7 @@
|
||||||
"@tsconfig/node20": "^20.1.4",
|
"@tsconfig/node20": "^20.1.4",
|
||||||
"@types/eslint": "~9.6.0",
|
"@types/eslint": "~9.6.0",
|
||||||
"@types/lodash.clonedeep": "^4.5.9",
|
"@types/lodash.clonedeep": "^4.5.9",
|
||||||
|
"@types/lodash.isequal": "^4.5.8",
|
||||||
"@types/node": "^20.14.5",
|
"@types/node": "^20.14.5",
|
||||||
"@types/nprogress": "^0.2.0",
|
"@types/nprogress": "^0.2.0",
|
||||||
"@types/qrcode": "^1.5.5",
|
"@types/qrcode": "^1.5.5",
|
||||||
|
@ -3070,6 +3071,7 @@
|
||||||
"version": "4.17.7",
|
"version": "4.17.7",
|
||||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.7.tgz",
|
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.7.tgz",
|
||||||
"integrity": "sha512-8wTvZawATi/lsmNu10/j2hk1KEP0IvjubqPE3cu1Xz7xfXXt5oCq3SNUz4fMIP4XGF9Ky+Ue2tBA3hcS7LSBlA==",
|
"integrity": "sha512-8wTvZawATi/lsmNu10/j2hk1KEP0IvjubqPE3cu1Xz7xfXXt5oCq3SNUz4fMIP4XGF9Ky+Ue2tBA3hcS7LSBlA==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/lodash.clonedeep": {
|
"node_modules/@types/lodash.clonedeep": {
|
||||||
|
@ -3086,6 +3088,7 @@
|
||||||
"version": "4.5.8",
|
"version": "4.5.8",
|
||||||
"resolved": "https://registry.npmjs.org/@types/lodash.isequal/-/lodash.isequal-4.5.8.tgz",
|
"resolved": "https://registry.npmjs.org/@types/lodash.isequal/-/lodash.isequal-4.5.8.tgz",
|
||||||
"integrity": "sha512-uput6pg4E/tj2LGxCZo9+y27JNyB2OZuuI/T5F+ylVDYuqICLG2/ktjxx0v6GvVntAf8TvEzeQLcV0ffRirXuA==",
|
"integrity": "sha512-uput6pg4E/tj2LGxCZo9+y27JNyB2OZuuI/T5F+ylVDYuqICLG2/ktjxx0v6GvVntAf8TvEzeQLcV0ffRirXuA==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/lodash": "*"
|
"@types/lodash": "*"
|
||||||
|
@ -3680,6 +3683,19 @@
|
||||||
"integrity": "sha512-VcZK7MvpjuTPx2w6blwnwZAu5/LgBUtejFOi3pPGQFXQN5Ela03FUtd2Qtg4yWGGissVL0dr6Ro1LfOFh+PCuQ==",
|
"integrity": "sha512-VcZK7MvpjuTPx2w6blwnwZAu5/LgBUtejFOi3pPGQFXQN5Ela03FUtd2Qtg4yWGGissVL0dr6Ro1LfOFh+PCuQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@vueup/vue-quill": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@vueup/vue-quill/-/vue-quill-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-kd5QPSHMDpycklojPXno2Kw2JSiKMYduKYQckTm1RJoVDA557MnyUXgcuuDpry4HY/Rny9nGNcK+m3AHk94wag==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"quill": "^1.3.7",
|
||||||
|
"quill-delta": "^4.2.2"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"vue": "^3.2.41"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/acorn": {
|
"node_modules/acorn": {
|
||||||
"version": "8.12.1",
|
"version": "8.12.1",
|
||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz",
|
||||||
|
@ -4311,6 +4327,15 @@
|
||||||
"wrap-ansi": "^6.2.0"
|
"wrap-ansi": "^6.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/clone": {
|
||||||
|
"version": "2.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
|
||||||
|
"integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/color": {
|
"node_modules/color": {
|
||||||
"version": "4.2.3",
|
"version": "4.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
|
||||||
|
@ -4589,6 +4614,26 @@
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/deep-equal": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-5tdhKF6DbU7iIzrIOa1AOUt39ZRm13cmL1cGEh//aqR8x9+tNfbywRf0n5FD/18OKMdo7DNEtrX2t22ZAkI+eg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"is-arguments": "^1.1.1",
|
||||||
|
"is-date-object": "^1.0.5",
|
||||||
|
"is-regex": "^1.1.4",
|
||||||
|
"object-is": "^1.1.5",
|
||||||
|
"object-keys": "^1.1.1",
|
||||||
|
"regexp.prototype.flags": "^1.5.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/deep-extend": {
|
"node_modules/deep-extend": {
|
||||||
"version": "0.6.0",
|
"version": "0.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
|
||||||
|
@ -4673,7 +4718,6 @@
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
|
||||||
"integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
|
"integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"define-data-property": "^1.0.1",
|
"define-data-property": "^1.0.1",
|
||||||
"has-property-descriptors": "^1.0.0",
|
"has-property-descriptors": "^1.0.0",
|
||||||
|
@ -5237,6 +5281,12 @@
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/eventemitter3": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-2.0.3.tgz",
|
||||||
|
"integrity": "sha512-jLN68Dx5kyFHaePoXWPsCGW5qdyZQtLYHkxkg02/Mz6g0kYpDx4FyP6XfArhQdlOC4b8Mv+EMxPo/8La7Tzghg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/execa": {
|
"node_modules/execa": {
|
||||||
"version": "8.0.1",
|
"version": "8.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz",
|
||||||
|
@ -5269,6 +5319,12 @@
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/extend": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/fast-deep-equal": {
|
"node_modules/fast-deep-equal": {
|
||||||
"version": "3.1.3",
|
"version": "3.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||||
|
@ -5550,7 +5606,6 @@
|
||||||
"version": "1.2.3",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
|
||||||
"integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
|
"integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
|
||||||
"dev": true,
|
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
|
@ -5815,7 +5870,6 @@
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
|
||||||
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
|
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"has-symbols": "^1.0.3"
|
"has-symbols": "^1.0.3"
|
||||||
},
|
},
|
||||||
|
@ -5976,6 +6030,22 @@
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/is-arguments": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"call-bind": "^1.0.2",
|
||||||
|
"has-tostringtag": "^1.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/is-array-buffer": {
|
"node_modules/is-array-buffer": {
|
||||||
"version": "3.0.4",
|
"version": "3.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz",
|
||||||
|
@ -6099,7 +6169,6 @@
|
||||||
"version": "1.0.5",
|
"version": "1.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
|
||||||
"integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==",
|
"integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"has-tostringtag": "^1.0.0"
|
"has-tostringtag": "^1.0.0"
|
||||||
},
|
},
|
||||||
|
@ -6236,7 +6305,6 @@
|
||||||
"version": "1.1.4",
|
"version": "1.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
|
||||||
"integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
|
"integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"call-bind": "^1.0.2",
|
"call-bind": "^1.0.2",
|
||||||
"has-tostringtag": "^1.0.0"
|
"has-tostringtag": "^1.0.0"
|
||||||
|
@ -6996,11 +7064,26 @@
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/object-is": {
|
||||||
|
"version": "1.1.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz",
|
||||||
|
"integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"call-bind": "^1.0.7",
|
||||||
|
"define-properties": "^1.2.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/object-keys": {
|
"node_modules/object-keys": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
|
||||||
"integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
|
"integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
|
||||||
"dev": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
|
@ -7126,6 +7209,12 @@
|
||||||
"integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==",
|
"integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/parchment": {
|
||||||
|
"version": "1.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/parchment/-/parchment-1.1.4.tgz",
|
||||||
|
"integrity": "sha512-J5FBQt/pM2inLzg4hEWmzQx/8h8D0CiDxaG3vyp9rKrQRSDgBlhjdP5jQGgosEajXPSQouXGHOmVdgo7QmJuOg==",
|
||||||
|
"license": "BSD-3-Clause"
|
||||||
|
},
|
||||||
"node_modules/parent-module": {
|
"node_modules/parent-module": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
||||||
|
@ -7669,6 +7758,57 @@
|
||||||
"integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==",
|
"integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/quill": {
|
||||||
|
"version": "1.3.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/quill/-/quill-1.3.7.tgz",
|
||||||
|
"integrity": "sha512-hG/DVzh/TiknWtE6QmWAF/pxoZKYxfe3J/d/+ShUWkDvvkZQVTPeVmUJVu1uE6DDooC4fWTiCLh84ul89oNz5g==",
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"dependencies": {
|
||||||
|
"clone": "^2.1.1",
|
||||||
|
"deep-equal": "^1.0.1",
|
||||||
|
"eventemitter3": "^2.0.3",
|
||||||
|
"extend": "^3.0.2",
|
||||||
|
"parchment": "^1.1.4",
|
||||||
|
"quill-delta": "^3.6.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/quill-delta": {
|
||||||
|
"version": "4.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/quill-delta/-/quill-delta-4.2.2.tgz",
|
||||||
|
"integrity": "sha512-qjbn82b/yJzOjstBgkhtBjN2TNK+ZHP/BgUQO+j6bRhWQQdmj2lH6hXG7+nwwLF41Xgn//7/83lxs9n2BkTtTg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"fast-diff": "1.2.0",
|
||||||
|
"lodash.clonedeep": "^4.5.0",
|
||||||
|
"lodash.isequal": "^4.5.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/quill-delta/node_modules/fast-diff": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==",
|
||||||
|
"license": "Apache-2.0"
|
||||||
|
},
|
||||||
|
"node_modules/quill/node_modules/fast-diff": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-KaJUt+M9t1qaIteSvjc6P3RbMdXsNhK61GRftR6SNxqmhthcd9MGIi4T+o0jD8LUSpSnSKXE20nLtJ3fOHxQig==",
|
||||||
|
"license": "Apache-2.0"
|
||||||
|
},
|
||||||
|
"node_modules/quill/node_modules/quill-delta": {
|
||||||
|
"version": "3.6.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/quill-delta/-/quill-delta-3.6.3.tgz",
|
||||||
|
"integrity": "sha512-wdIGBlcX13tCHOXGMVnnTVFtGRLoP0imqxM696fIPwIf5ODIYUHIvHbZcyvGlZFiFhK5XzDC2lpjbxRhnM05Tg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"deep-equal": "^1.0.1",
|
||||||
|
"extend": "^3.0.2",
|
||||||
|
"fast-diff": "1.1.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/randombytes": {
|
"node_modules/randombytes": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
||||||
|
@ -7787,7 +7927,6 @@
|
||||||
"version": "1.5.2",
|
"version": "1.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz",
|
||||||
"integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==",
|
"integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"call-bind": "^1.0.6",
|
"call-bind": "^1.0.6",
|
||||||
"define-properties": "^1.2.1",
|
"define-properties": "^1.2.1",
|
||||||
|
@ -8090,7 +8229,6 @@
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz",
|
||||||
"integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==",
|
"integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"define-data-property": "^1.1.4",
|
"define-data-property": "^1.1.4",
|
||||||
"es-errors": "^1.3.0",
|
"es-errors": "^1.3.0",
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@headlessui/vue": "^1.7.13",
|
"@headlessui/vue": "^1.7.13",
|
||||||
"@heroicons/vue": "^2.1.5",
|
"@heroicons/vue": "^2.1.5",
|
||||||
|
"@vueup/vue-quill": "^1.2.0",
|
||||||
"axios": "^0.26.1",
|
"axios": "^0.26.1",
|
||||||
"jwt-decode": "^4.0.0",
|
"jwt-decode": "^4.0.0",
|
||||||
"lodash.clonedeep": "^4.5.0",
|
"lodash.clonedeep": "^4.5.0",
|
||||||
|
|
27
src/components/admin/club/protocol/ProtocolListItem.vue
Normal file
27
src/components/admin/club/protocol/ProtocolListItem.vue
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<template>
|
||||||
|
<div class="flex flex-col h-fit w-full border border-primary rounded-md">
|
||||||
|
<RouterLink
|
||||||
|
:to="{ name: 'admin-club-protocol-overview', params: { protocolId: protocol.id } }"
|
||||||
|
class="bg-primary p-2 text-white flex flex-row justify-between items-center"
|
||||||
|
>
|
||||||
|
<p>{{ protocol.title }}</p>
|
||||||
|
</RouterLink>
|
||||||
|
<div class="p-2">
|
||||||
|
<p>Infos</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { defineComponent, type PropType } from "vue";
|
||||||
|
import { mapState, mapActions } from "pinia";
|
||||||
|
import type { ProtocolViewModel } from "../../../../viewmodels/admin/protocol.models";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
export default defineComponent({
|
||||||
|
props: {
|
||||||
|
protocol: { type: Object as PropType<ProtocolViewModel>, default: {} },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -1,12 +1,8 @@
|
||||||
import type { AxiosInstance } from "axios";
|
|
||||||
import type { NProgress } from "nprogress";
|
|
||||||
import type { RouteLocationNormalizedLoaded, Router } from "vue-router";
|
import type { RouteLocationNormalizedLoaded, Router } from "vue-router";
|
||||||
|
|
||||||
declare module "@vue/runtime-core" {
|
declare module "@vue/runtime-core" {
|
||||||
interface ComponentCustomProperties {
|
interface ComponentCustomProperties {
|
||||||
$dev: boolean;
|
$dev: boolean;
|
||||||
$http: AxiosInstance;
|
|
||||||
$progress: NProgress;
|
|
||||||
$router: Router;
|
$router: Router;
|
||||||
$route: RouteLocationNormalizedLoaded;
|
$route: RouteLocationNormalizedLoaded;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { isSetup } from "./setupGuard";
|
||||||
import { abilityAndNavUpdate } from "./adminGuard";
|
import { abilityAndNavUpdate } from "./adminGuard";
|
||||||
import type { PermissionType, PermissionSection, PermissionModule } from "@/types/permissionTypes";
|
import type { PermissionType, PermissionSection, PermissionModule } from "@/types/permissionTypes";
|
||||||
import { resetMemberStores, setMemberId } from "./memberGuard";
|
import { resetMemberStores, setMemberId } from "./memberGuard";
|
||||||
|
import { resetProtocolStores, setProtocolId } from "./protocolGuard";
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHistory(import.meta.env.BASE_URL),
|
history: createWebHistory(import.meta.env.BASE_URL),
|
||||||
|
@ -148,10 +149,41 @@ const router = createRouter({
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "protocol",
|
path: "protocol",
|
||||||
name: "admin-club-protocol",
|
name: "admin-club-protocol-route",
|
||||||
component: () => import("@/views/admin/members/Overview.vue"),
|
component: () => import("@/views/RouterView.vue"),
|
||||||
meta: { type: "read", section: "club", module: "protocoll" },
|
meta: { type: "read", section: "club", module: "protocol" },
|
||||||
beforeEnter: [abilityAndNavUpdate],
|
beforeEnter: [abilityAndNavUpdate],
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: "",
|
||||||
|
name: "admin-club-protocol",
|
||||||
|
component: () => import("@/views/admin/protocol/Protocol.vue"),
|
||||||
|
beforeEnter: [resetProtocolStores],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: ":protocolId",
|
||||||
|
name: "admin-club-protocol-routing",
|
||||||
|
component: () => import("@/views/admin/protocol/ProtocolRouting.vue"),
|
||||||
|
beforeEnter: [setProtocolId],
|
||||||
|
props: true,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: "overview",
|
||||||
|
name: "admin-club-protocol-overview",
|
||||||
|
component: () => import("@/views/admin/protocol/ProtocolOverview.vue"),
|
||||||
|
props: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "edit",
|
||||||
|
name: "admin-club-protocol-edit",
|
||||||
|
component: () => import("@/views/admin/protocol/ProtocolEdit.vue"),
|
||||||
|
meta: { type: "update", section: "club", module: "member" },
|
||||||
|
beforeEnter: [abilityAndNavUpdate],
|
||||||
|
props: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
16
src/router/protocolGuard.ts
Normal file
16
src/router/protocolGuard.ts
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import { useProtocolStore } from "@/stores/admin/protocol";
|
||||||
|
|
||||||
|
export async function setProtocolId(to: any, from: any, next: any) {
|
||||||
|
const protocol = useProtocolStore();
|
||||||
|
protocol.activeProtocol = to.params?.protocolId ?? null;
|
||||||
|
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function resetProtocolStores(to: any, from: any, next: any) {
|
||||||
|
const protocol = useProtocolStore();
|
||||||
|
protocol.activeProtocol = null;
|
||||||
|
protocol.activeProtocolObj = null;
|
||||||
|
|
||||||
|
next();
|
||||||
|
}
|
80
src/stores/admin/protocol.ts
Normal file
80
src/stores/admin/protocol.ts
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
import { defineStore } from "pinia";
|
||||||
|
import type { CreateProtocolViewModel, UpdateProtocolViewModel } from "@/viewmodels/admin/protocol.models";
|
||||||
|
import { http } from "@/serverCom";
|
||||||
|
import type { AxiosResponse } from "axios";
|
||||||
|
import type { ProtocolViewModel } from "@/viewmodels/admin/protocol.models";
|
||||||
|
|
||||||
|
export const useProtocolStore = defineStore("protocol", {
|
||||||
|
state: () => {
|
||||||
|
return {
|
||||||
|
protocols: [] as Array<ProtocolViewModel & { tab_pos: number }>,
|
||||||
|
totalCount: 0 as number,
|
||||||
|
loading: "loading" as "loading" | "fetched" | "failed",
|
||||||
|
activeProtocol: null as number | null,
|
||||||
|
activeProtocolObj: null as ProtocolViewModel | null,
|
||||||
|
loadingActive: "loading" as "loading" | "fetched" | "failed",
|
||||||
|
};
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
fetchProtocols(offset = 0, count = 25, clear = false) {
|
||||||
|
if (clear) this.protocols = [];
|
||||||
|
this.loading = "loading";
|
||||||
|
http
|
||||||
|
.get(`/admin/protocol?offset=${offset}&count=${count}`)
|
||||||
|
.then((result) => {
|
||||||
|
this.totalCount = result.data.total;
|
||||||
|
result.data.protocols
|
||||||
|
.filter((elem: ProtocolViewModel) => this.protocols.findIndex((m) => m.id == elem.id) == -1)
|
||||||
|
.map((elem: ProtocolViewModel, index: number): ProtocolViewModel & { tab_pos: number } => {
|
||||||
|
return {
|
||||||
|
...elem,
|
||||||
|
tab_pos: index + offset,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.forEach((elem: ProtocolViewModel & { tab_pos: number }) => {
|
||||||
|
this.protocols.push(elem);
|
||||||
|
});
|
||||||
|
this.loading = "fetched";
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
this.loading = "failed";
|
||||||
|
});
|
||||||
|
},
|
||||||
|
fetchProtocolByActiveId() {
|
||||||
|
this.loadingActive = "loading";
|
||||||
|
http
|
||||||
|
.get(`/admin/protocol/${this.activeProtocol}`)
|
||||||
|
.then((res) => {
|
||||||
|
this.activeProtocolObj = res.data;
|
||||||
|
this.loadingActive = "fetched";
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
this.loadingActive = "failed";
|
||||||
|
});
|
||||||
|
},
|
||||||
|
fetchProtocolById(id: number) {
|
||||||
|
return http.get(`/admin/protocol/${id}`);
|
||||||
|
},
|
||||||
|
async createProtocol(protocol: CreateProtocolViewModel): Promise<AxiosResponse<any, any>> {
|
||||||
|
const result = await http.post(`/admin/protocol`, {
|
||||||
|
title: protocol.title,
|
||||||
|
date: protocol.date,
|
||||||
|
});
|
||||||
|
this.fetchProtocols();
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
async updateActiveProtocol(protocol: UpdateProtocolViewModel): Promise<AxiosResponse<any, any>> {
|
||||||
|
const result = await http.patch(`/admin/protocol/${protocol.id}`, {
|
||||||
|
title: protocol.title,
|
||||||
|
date: protocol.date,
|
||||||
|
});
|
||||||
|
this.fetchProtocols();
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
async deleteProtocol(protocol: number): Promise<AxiosResponse<any, any>> {
|
||||||
|
const result = await http.delete(`/admin/protocol/${protocol}`);
|
||||||
|
this.fetchProtocols();
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
|
@ -4,7 +4,7 @@ export type PermissionModule =
|
||||||
| "member"
|
| "member"
|
||||||
| "calendar"
|
| "calendar"
|
||||||
| "newsletter"
|
| "newsletter"
|
||||||
| "protocoll"
|
| "protocol"
|
||||||
| "qualification"
|
| "qualification"
|
||||||
| "award"
|
| "award"
|
||||||
| "executive_position"
|
| "executive_position"
|
||||||
|
@ -39,7 +39,7 @@ export const permissionModules: Array<PermissionModule> = [
|
||||||
"member",
|
"member",
|
||||||
"calendar",
|
"calendar",
|
||||||
"newsletter",
|
"newsletter",
|
||||||
"protocoll",
|
"protocol",
|
||||||
"qualification",
|
"qualification",
|
||||||
"award",
|
"award",
|
||||||
"executive_position",
|
"executive_position",
|
||||||
|
@ -50,7 +50,7 @@ export const permissionModules: Array<PermissionModule> = [
|
||||||
];
|
];
|
||||||
export const permissionTypes: Array<PermissionType> = ["read", "create", "update", "delete"];
|
export const permissionTypes: Array<PermissionType> = ["read", "create", "update", "delete"];
|
||||||
export const sectionsAndModules: SectionsAndModulesObject = {
|
export const sectionsAndModules: SectionsAndModulesObject = {
|
||||||
club: ["member", "calendar", "newsletter", "protocoll"],
|
club: ["member", "calendar", "newsletter", "protocol"],
|
||||||
settings: ["qualification", "award", "executive_position", "communication", "membership_status"],
|
settings: ["qualification", "award", "executive_position", "communication", "membership_status"],
|
||||||
user: ["user", "role"],
|
user: ["user", "role"],
|
||||||
};
|
};
|
||||||
|
|
16
src/viewmodels/admin/protocol.models.ts
Normal file
16
src/viewmodels/admin/protocol.models.ts
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
export interface ProtocolViewModel {
|
||||||
|
id: number;
|
||||||
|
title: string;
|
||||||
|
date: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CreateProtocolViewModel {
|
||||||
|
title: string;
|
||||||
|
date: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UpdateProtocolViewModel {
|
||||||
|
id: number;
|
||||||
|
title: string;
|
||||||
|
date: Date;
|
||||||
|
}
|
|
@ -69,8 +69,8 @@ export default defineComponent({
|
||||||
})
|
})
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
this.loginStatus = "success";
|
this.loginStatus = "success";
|
||||||
localStorage.setItem("accessToken", result.data.accessToken),
|
localStorage.setItem("accessToken", result.data.accessToken);
|
||||||
localStorage.setItem("refreshToken", result.data.refreshToken),
|
localStorage.setItem("refreshToken", result.data.refreshToken);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.$router.push(`/admin`);
|
this.$router.push(`/admin`);
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
|
151
src/views/admin/protocol/Protocol.vue
Normal file
151
src/views/admin/protocol/Protocol.vue
Normal file
|
@ -0,0 +1,151 @@
|
||||||
|
<template>
|
||||||
|
<MainTemplate>
|
||||||
|
<template #topBar>
|
||||||
|
<div class="flex flex-row items-center justify-between pt-5 pb-3 px-7">
|
||||||
|
<h1 class="font-bold text-xl h-8">Protokolle</h1>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #diffMain>
|
||||||
|
<div class="flex flex-col w-full h-full gap-2 justify-center px-7">
|
||||||
|
<div class="flex flex-col w-full grow gap-2 pr-2 overflow-y-scroll">
|
||||||
|
<ProtocolListItem v-for="protocol in protocols" :key="protocol.id" :protocol="protocol" />
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-row w-full justify-between select-none">
|
||||||
|
<p class="text-sm font-normal text-gray-500">
|
||||||
|
Elemente <span class="font-semibold text-gray-900">{{ showingText }}</span> von
|
||||||
|
<span class="font-semibold text-gray-900">{{ entryCount }}</span>
|
||||||
|
</p>
|
||||||
|
<ul class="flex flex-row text-sm h-8">
|
||||||
|
<li
|
||||||
|
class="flex h-8 w-8 items-center justify-center text-gray-500 bg-white border border-gray-300 first:rounded-s-lg last:rounded-e-lg"
|
||||||
|
:class="[currentPage > 0 ? 'cursor-pointer hover:bg-gray-100 hover:text-gray-700' : 'opacity-50']"
|
||||||
|
@click="loadPage(currentPage - 1)"
|
||||||
|
>
|
||||||
|
<ChevronLeftIcon class="h-4" />
|
||||||
|
</li>
|
||||||
|
<li
|
||||||
|
v-for="page in displayedPagesNumbers"
|
||||||
|
:key="page"
|
||||||
|
class="flex h-8 w-8 items-center justify-center text-gray-500 bg-white border border-gray-300 hover:bg-gray-100 hover:text-gray-700 first:rounded-s-lg last:rounded-e-lg"
|
||||||
|
:class="[currentPage == page ? 'font-bold border-primary' : '', page != '.' ? ' cursor-pointer' : '']"
|
||||||
|
@click="loadPage(page)"
|
||||||
|
>
|
||||||
|
{{ typeof page == "number" ? page + 1 : "..." }}
|
||||||
|
</li>
|
||||||
|
<li
|
||||||
|
class="flex h-8 w-8 items-center justify-center text-gray-500 bg-white border border-gray-300 first:rounded-s-lg last:rounded-e-lg"
|
||||||
|
:class="[
|
||||||
|
currentPage + 1 < countOfPages ? 'cursor-pointer hover:bg-gray-100 hover:text-gray-700' : 'opacity-50',
|
||||||
|
]"
|
||||||
|
@click="loadPage(currentPage + 1)"
|
||||||
|
>
|
||||||
|
<ChevronRightIcon class="h-4" />
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-row gap-4">
|
||||||
|
<button primary class="!w-fit" @click="openCreateModal">Protokoll erstellen</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</MainTemplate>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { defineAsyncComponent, defineComponent, markRaw } from "vue";
|
||||||
|
import { mapActions, mapState } from "pinia";
|
||||||
|
import MainTemplate from "@/templates/Main.vue";
|
||||||
|
import { ChevronRightIcon, ChevronLeftIcon } from "@heroicons/vue/20/solid";
|
||||||
|
import { useProtocolStore } from "@/stores/admin/protocol";
|
||||||
|
import ProtocolListItem from "@/components/admin/club/protocol/ProtocolListItem.vue";
|
||||||
|
import { useModalStore } from "@/stores/modal";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
export default defineComponent({
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
currentPage: 0,
|
||||||
|
maxEntriesPerPage: 25,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState(useProtocolStore, ["protocols", "totalCount"]),
|
||||||
|
entryCount() {
|
||||||
|
return this.totalCount ?? this.protocols.length;
|
||||||
|
},
|
||||||
|
showingStart() {
|
||||||
|
return this.currentPage * this.maxEntriesPerPage;
|
||||||
|
},
|
||||||
|
showingEnd() {
|
||||||
|
let max = this.currentPage * this.maxEntriesPerPage + this.maxEntriesPerPage;
|
||||||
|
if (max > this.entryCount) max = this.entryCount;
|
||||||
|
return max;
|
||||||
|
},
|
||||||
|
showingText() {
|
||||||
|
return `${this.entryCount != 0 ? this.showingStart + 1 : 0} - ${this.showingEnd}`;
|
||||||
|
},
|
||||||
|
countOfPages() {
|
||||||
|
return Math.ceil(this.entryCount / this.maxEntriesPerPage);
|
||||||
|
},
|
||||||
|
displayedPagesNumbers(): Array<number | "."> {
|
||||||
|
//indicate if "." or page number gets pushed
|
||||||
|
let stateOfPush = false;
|
||||||
|
|
||||||
|
return [...new Array(this.countOfPages)].reduce((acc, curr, index) => {
|
||||||
|
if (
|
||||||
|
// always display first 2 pages
|
||||||
|
index <= 1 ||
|
||||||
|
// always display last 2 pages
|
||||||
|
index >= this.countOfPages - 2 ||
|
||||||
|
// always display 1 pages around current page
|
||||||
|
(this.currentPage - 1 <= index && index <= this.currentPage + 1)
|
||||||
|
) {
|
||||||
|
acc.push(index);
|
||||||
|
stateOfPush = false;
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
|
// abort if placeholder already added to array
|
||||||
|
if (stateOfPush == true) return acc;
|
||||||
|
// show placeholder if pagenumber is not actively rendered
|
||||||
|
acc.push(".");
|
||||||
|
stateOfPush = true;
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, []);
|
||||||
|
},
|
||||||
|
visibleRows() {
|
||||||
|
return this.filterData(this.protocols, this.showingStart, this.showingEnd);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.fetchProtocols(0, this.maxEntriesPerPage, true);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions(useProtocolStore, ["fetchProtocols"]),
|
||||||
|
...mapActions(useModalStore, ["openModal"]),
|
||||||
|
loadPage(newPage: number | ".") {
|
||||||
|
if (newPage == ".") return;
|
||||||
|
if (newPage < 0 || newPage >= this.countOfPages) return;
|
||||||
|
|
||||||
|
let pageStart = newPage * this.maxEntriesPerPage;
|
||||||
|
let pageEnd = newPage * this.maxEntriesPerPage + this.maxEntriesPerPage;
|
||||||
|
if (pageEnd > this.entryCount) pageEnd = this.entryCount;
|
||||||
|
|
||||||
|
let loadedElementCount = this.filterData(this.protocols, pageStart, pageEnd).length;
|
||||||
|
if (loadedElementCount < this.maxEntriesPerPage) this.fetchProtocols(pageStart, this.maxEntriesPerPage);
|
||||||
|
|
||||||
|
this.currentPage = newPage;
|
||||||
|
},
|
||||||
|
filterData(array: Array<any>, start: number, end: number): Array<any> {
|
||||||
|
return array.filter((elem, index) => (elem?.tab_pos ?? index) >= start && (elem?.tab_pos ?? index) < end);
|
||||||
|
},
|
||||||
|
openCreateModal() {
|
||||||
|
// this.openModal(
|
||||||
|
// markRaw(defineAsyncComponent(() => import("@/components/admin/club/protocol/CreateProtocolModal.vue")))
|
||||||
|
// );
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
111
src/views/admin/protocol/ProtocolEdit.vue
Normal file
111
src/views/admin/protocol/ProtocolEdit.vue
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
<template>
|
||||||
|
<div class="flex flex-col gap-2 h-full w-full overflow-y-auto">
|
||||||
|
<Spinner v-if="loading == 'loading'" class="mx-auto" />
|
||||||
|
<p v-else-if="loading == 'failed'">laden fehlgeschlagen</p>
|
||||||
|
<form
|
||||||
|
v-else-if="protocol != null"
|
||||||
|
class="flex flex-col gap-4 py-2 w-full max-w-xl mx-auto"
|
||||||
|
@submit.prevent="triggerUpdate"
|
||||||
|
>
|
||||||
|
<p class="mx-auto">Protokoll bearbeiten</p>
|
||||||
|
|
||||||
|
<div class="flex flex-row justify-end gap-2">
|
||||||
|
<button primary-outline type="reset" class="!w-fit" :disabled="canSaveOrReset" @click="resetForm">
|
||||||
|
verwerfen
|
||||||
|
</button>
|
||||||
|
<button primary type="submit" class="!w-fit" :disabled="status == 'loading' || canSaveOrReset">
|
||||||
|
speichern
|
||||||
|
</button>
|
||||||
|
<Spinner v-if="status == 'loading'" class="my-auto" />
|
||||||
|
<SuccessCheckmark v-else-if="status?.status == 'success'" />
|
||||||
|
<FailureXMark v-else-if="status?.status == 'failed'" />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { defineComponent } from "vue";
|
||||||
|
import { mapActions, mapState } from "pinia";
|
||||||
|
import MainTemplate from "@/templates/Main.vue";
|
||||||
|
import { useProtocolStore } from "@/stores/admin/protocol";
|
||||||
|
import type { ProtocolViewModel, UpdateProtocolViewModel } from "@/viewmodels/admin/protocol.models";
|
||||||
|
import Spinner from "@/components/Spinner.vue";
|
||||||
|
import SuccessCheckmark from "@/components/SuccessCheckmark.vue";
|
||||||
|
import FailureXMark from "@/components/FailureXMark.vue";
|
||||||
|
import cloneDeep from "lodash.clonedeep";
|
||||||
|
import isEqual from "lodash.isEqual";
|
||||||
|
import { Salutation } from "@/enums/salutation";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
export default defineComponent({
|
||||||
|
props: {
|
||||||
|
protocolId: String,
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
loadingActive() {
|
||||||
|
if (this.loading == "loading") {
|
||||||
|
this.loading = this.loadingActive;
|
||||||
|
}
|
||||||
|
if (this.loadingActive == "fetched") this.protocol = cloneDeep(this.activeProtocolObj);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
loading: "loading" as "loading" | "fetched" | "failed",
|
||||||
|
status: null as null | "loading" | { status: "success" | "failed"; reason?: string },
|
||||||
|
protocol: null as null | ProtocolViewModel,
|
||||||
|
timeout: null as any,
|
||||||
|
salutations: [] as Array<string>,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
canSaveOrReset(): boolean {
|
||||||
|
return isEqual(this.activeProtocolObj, this.protocol);
|
||||||
|
},
|
||||||
|
...mapState(useProtocolStore, ["activeProtocolObj", "loadingActive"]),
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.fetchItem();
|
||||||
|
this.salutations = Object.values(Salutation);
|
||||||
|
},
|
||||||
|
beforeUnmount() {
|
||||||
|
try {
|
||||||
|
clearTimeout(this.timeout);
|
||||||
|
} catch (error) {}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions(useProtocolStore, ["fetchProtocolByActiveId", "updateActiveProtocol"]),
|
||||||
|
resetForm() {
|
||||||
|
this.protocol = cloneDeep(this.activeProtocolObj);
|
||||||
|
},
|
||||||
|
fetchItem() {
|
||||||
|
this.fetchProtocolByActiveId();
|
||||||
|
},
|
||||||
|
triggerUpdate(e: any) {
|
||||||
|
if (this.protocol == null) return;
|
||||||
|
let formData = e.target.elements;
|
||||||
|
let updateProtocol: UpdateProtocolViewModel = {
|
||||||
|
id: this.protocol.id,
|
||||||
|
title: formData.title.value,
|
||||||
|
date: formData.date.value,
|
||||||
|
};
|
||||||
|
this.status = "loading";
|
||||||
|
this.updateActiveProtocol(updateProtocol)
|
||||||
|
.then(() => {
|
||||||
|
this.fetchItem();
|
||||||
|
this.status = { status: "success" };
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
this.status = { status: "failed" };
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.timeout = setTimeout(() => {
|
||||||
|
this.status = null;
|
||||||
|
}, 2000);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
34
src/views/admin/protocol/ProtocolOverview.vue
Normal file
34
src/views/admin/protocol/ProtocolOverview.vue
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
<template>
|
||||||
|
<div class="flex flex-col gap-2 h-full w-full overflow-y-auto">
|
||||||
|
<div v-if="activeProtocol != null" class="flex flex-col gap-2 w-full">Protokoll Details</div>
|
||||||
|
|
||||||
|
<Spinner v-if="loadingActive == 'loading'" class="mx-auto" />
|
||||||
|
<p v-else-if="loadingActive == 'failed'" @click="fetchProtocolByActiveId" class="cursor-pointer">
|
||||||
|
↺ laden fehlgeschlagen
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { defineComponent } from "vue";
|
||||||
|
import { mapActions, mapState } from "pinia";
|
||||||
|
import Spinner from "@/components/Spinner.vue";
|
||||||
|
import { useProtocolStore } from "@/stores/admin/protocol";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
export default defineComponent({
|
||||||
|
props: {
|
||||||
|
protocolId: String,
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState(useProtocolStore, ["activeProtocol", "loadingActive"]),
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.fetchProtocolByActiveId();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions(useProtocolStore, ["fetchProtocolByActiveId"]),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
82
src/views/admin/protocol/ProtocolRouting.vue
Normal file
82
src/views/admin/protocol/ProtocolRouting.vue
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
<template>
|
||||||
|
<MainTemplate>
|
||||||
|
<template #headerInsert>
|
||||||
|
<RouterLink to="../" class="text-primary">zurück zur Liste</RouterLink>
|
||||||
|
</template>
|
||||||
|
<template #topBar>
|
||||||
|
<div class="flex flex-row gap-2 items-center justify-between pt-5 pb-3 px-7">
|
||||||
|
<h1 class="font-bold text-xl h-8 min-h-fit grow">
|
||||||
|
{{ activeProtocolObj?.title }}, {{ activeProtocolObj?.date }}
|
||||||
|
</h1>
|
||||||
|
<RouterLink :to="{ name: 'admin-club-protocol-edit' }">
|
||||||
|
<PencilIcon class="w-5 h-5" />
|
||||||
|
</RouterLink>
|
||||||
|
<TrashIcon class="w-5 h-5 cursor-pointer" @click="openDeleteModal" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #diffMain>
|
||||||
|
<div class="flex flex-col gap-2 grow px-7 overflow-hidden">
|
||||||
|
<div class="flex flex-col grow gap-2 overflow-hidden">
|
||||||
|
<div class="w-full flex flex-row max-lg:flex-wrap justify-center">
|
||||||
|
<RouterLink
|
||||||
|
v-for="tab in tabs"
|
||||||
|
:key="tab.route"
|
||||||
|
v-slot="{ isActive }"
|
||||||
|
:to="{ name: tab.route }"
|
||||||
|
class="w-1/2 md:w-1/3 lg:w-full p-0.5 first:pl-0 last:pr-0"
|
||||||
|
>
|
||||||
|
<p
|
||||||
|
:class="[
|
||||||
|
'w-full rounded-lg py-2.5 text-sm text-center font-medium leading-5 focus:ring-0 outline-none',
|
||||||
|
isActive ? 'bg-red-200 shadow border-b-2 border-primary rounded-b-none' : ' hover:bg-red-200',
|
||||||
|
]"
|
||||||
|
>
|
||||||
|
{{ tab.title }}
|
||||||
|
</p>
|
||||||
|
</RouterLink>
|
||||||
|
</div>
|
||||||
|
<RouterView />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</MainTemplate>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { defineAsyncComponent, defineComponent, markRaw } from "vue";
|
||||||
|
import { mapActions, mapState } from "pinia";
|
||||||
|
import MainTemplate from "@/templates/Main.vue";
|
||||||
|
import { RouterLink, RouterView } from "vue-router";
|
||||||
|
import { useProtocolStore } from "@/stores/admin/protocol";
|
||||||
|
import { PencilIcon, TrashIcon } from "@heroicons/vue/24/outline";
|
||||||
|
import { useModalStore } from "@/stores/modal";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
export default defineComponent({
|
||||||
|
props: {
|
||||||
|
protocolId: String,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
tabs: [{ route: "admin-club-protocol-overview", title: "Übersicht" }],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState(useProtocolStore, ["activeProtocolObj"]),
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.fetchProtocolByActiveId();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions(useProtocolStore, ["fetchProtocolByActiveId"]),
|
||||||
|
...mapActions(useModalStore, ["openModal"]),
|
||||||
|
openDeleteModal() {
|
||||||
|
// this.openModal(
|
||||||
|
// markRaw(defineAsyncComponent(() => import("@/components/admin/club/protocol/DeleteProtocolModal.vue"))),
|
||||||
|
// parseInt(this.protocolId ?? "")
|
||||||
|
// );
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
Loading…
Reference in a new issue