Implementing Exercise system in database with API and frontend visualization
This commit is contained in:
@@ -5,20 +5,28 @@ defineProps({
|
||||
icon: {
|
||||
type: String
|
||||
},
|
||||
subtitle: {
|
||||
type: String,
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-card
|
||||
variant="tonal"
|
||||
:prepend-icon="icon"
|
||||
:title="title"
|
||||
:subtitle="subtitle"
|
||||
>
|
||||
<v-container class="pt-0">
|
||||
<v-card variant="tonal" >
|
||||
<v-card-title v-if="title || loading" color="primary" class="pa-0">
|
||||
<v-sheet color="primary" class="pl-2 py-1">
|
||||
<v-skeleton-loader
|
||||
type="heading"
|
||||
:loading="loading"
|
||||
style="background-color: transparent"
|
||||
>
|
||||
<v-icon :icon="icon" v-if="icon" /> {{ title }}
|
||||
</v-skeleton-loader>
|
||||
</v-sheet>
|
||||
</v-card-title>
|
||||
|
||||
<v-container>
|
||||
<v-row>
|
||||
<v-col >
|
||||
<slot></slot>
|
||||
|
||||
7
software/src/data/api/exerciseApi.ts
Normal file
7
software/src/data/api/exerciseApi.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import axios from "axios"
|
||||
|
||||
const BASE_URL = "http://localhost:3000/exercises"
|
||||
|
||||
export async function getAllExerciseGroups() {
|
||||
return await axios.get(BASE_URL)
|
||||
}
|
||||
8
software/src/data/models/exercises/exerciseGroupModel.ts
Normal file
8
software/src/data/models/exercises/exerciseGroupModel.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { ExerciseModel } from "./exerciseModel"
|
||||
|
||||
export class ExerciseGroupModel {
|
||||
nameDe: string = ""
|
||||
nameEn: string = ""
|
||||
groupNr: number = 0
|
||||
exercises: Array<ExerciseModel>
|
||||
}
|
||||
8
software/src/data/models/exercises/exerciseModel.ts
Normal file
8
software/src/data/models/exercises/exerciseModel.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
export class ExerciseModel {
|
||||
nameDe: string = ""
|
||||
nameEn: string = ""
|
||||
exerciseNr: number = 0
|
||||
descriptionDe: string = ""
|
||||
descriptionEn: string = ""
|
||||
solved: boolean = false
|
||||
}
|
||||
@@ -159,5 +159,7 @@
|
||||
"seatGroup": "Kategorie",
|
||||
"date": "Datum",
|
||||
"price": "Preis",
|
||||
"standingArea": "Stehbereich"
|
||||
"standingArea": "Stehbereich",
|
||||
"exerciseGroup": "Aufgabengruppe",
|
||||
"exercise": "Aufgabe"
|
||||
}
|
||||
|
||||
@@ -159,5 +159,7 @@
|
||||
"seatGroup": "Category",
|
||||
"date": "Date",
|
||||
"price": "Price",
|
||||
"standingArea": "Standing Area"
|
||||
"standingArea": "Standing Area",
|
||||
"exerciseGroup": "Exercise group",
|
||||
"exercise": "Exercise"
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ function itemPropsGenre(genre: GenreModel) {
|
||||
<card-view
|
||||
variant="tonal"
|
||||
:title="$t('filtering')"
|
||||
subtitle="123"
|
||||
icon="mdi-cog"
|
||||
>
|
||||
<v-row class="d-flex justify-center" >
|
||||
|
||||
@@ -1,49 +1,35 @@
|
||||
<script setup lang="ts">
|
||||
import { getAllExerciseGroups } from '@/data/api/exerciseApi';
|
||||
import scoreCard from './scoreCard.vue';
|
||||
import { ref } from 'vue';
|
||||
import { ExerciseGroupModel } from '@/data/models/exercises/exerciseGroupModel';
|
||||
import { useFeedbackStore } from '@/data/stores/feedbackStore';
|
||||
|
||||
const exerciseGroups = ref<Array<ExerciseGroupModel>>([])
|
||||
const feedbackStore = useFeedbackStore()
|
||||
|
||||
feedbackStore.fetchDataFromServerInProgress = true
|
||||
|
||||
getAllExerciseGroups()
|
||||
.then(result => {
|
||||
exerciseGroups.value = result.data
|
||||
feedbackStore.fetchDataFromServerInProgress = false
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-container max-width="1000">
|
||||
<v-row>
|
||||
<v-row v-if="feedbackStore.fetchDataFromServerInProgress" v-for="i in 3">
|
||||
<v-col>
|
||||
<score-card
|
||||
:title="$t('scoreBoard.exerciseGroup0')"
|
||||
:progress="2"
|
||||
:total-steps="2"
|
||||
:step-names="['Registrieren', 'Bestellung ausführen']"
|
||||
/>
|
||||
<score-card :loading="true"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-row v-for="exerciseGroup in exerciseGroups">
|
||||
<v-col>
|
||||
<score-card
|
||||
:title="$t('scoreBoard.exerciseGroup1')"
|
||||
:progress="1"
|
||||
:total-steps="4"
|
||||
:step-names="['', '']"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col>
|
||||
<score-card
|
||||
:title="$t('scoreBoard.exerciseGroup2')"
|
||||
:progress="1"
|
||||
:total-steps="4"
|
||||
:step-names="['', '']"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col>
|
||||
<score-card
|
||||
:title="$t('scoreBoard.exerciseGroup3')"
|
||||
:progress="0"
|
||||
:total-steps="3"
|
||||
:step-names="['', '', '']"
|
||||
:exercise-group="exerciseGroup"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
@@ -1,46 +1,83 @@
|
||||
<script setup lang="ts">
|
||||
import cardView from '@/components/basics/cardView.vue';
|
||||
import { ExerciseGroupModel } from '@/data/models/exercises/exerciseGroupModel';
|
||||
|
||||
const props = defineProps({
|
||||
exerciseGroup: String,
|
||||
progress: Number,
|
||||
totalSteps: Number,
|
||||
stepNames: Array<String>
|
||||
defineProps({
|
||||
exerciseGroup: ExerciseGroupModel,
|
||||
loading: Boolean
|
||||
})
|
||||
|
||||
function getDotColor(step: number) {
|
||||
if (props.progress >= step) {
|
||||
return "green"
|
||||
} else {
|
||||
return "grey"
|
||||
}
|
||||
}
|
||||
|
||||
function getIcon(step: number) {
|
||||
if (props.progress >= step) {
|
||||
return "mdi-check"
|
||||
} else {
|
||||
return "mdi-pencil"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<card-view :title="exerciseGroup" >
|
||||
<card-view v-if="loading" :loading="loading" >
|
||||
<v-timeline
|
||||
direction="horizontal"
|
||||
side="end"
|
||||
side="start"
|
||||
class="pb-3"
|
||||
>
|
||||
<v-timeline-item
|
||||
v-for="step in totalSteps"
|
||||
:dot-color="getDotColor(step)"
|
||||
:icon="getIcon(step)"
|
||||
v-for="i in 3"
|
||||
dot-color="grey"
|
||||
icon="mdi-pencil"
|
||||
>
|
||||
{{ stepNames[step - 1] }}
|
||||
<v-skeleton-loader
|
||||
type="list-item"
|
||||
:loading="loading"
|
||||
width="200"
|
||||
/>
|
||||
|
||||
<template #opposite>
|
||||
<v-skeleton-loader
|
||||
type="sentences"
|
||||
:loading="loading"
|
||||
width="200"
|
||||
/>
|
||||
</template>
|
||||
</v-timeline-item>
|
||||
</v-timeline>
|
||||
</card-view>
|
||||
|
||||
|
||||
<card-view
|
||||
v-else
|
||||
:title="$t('exerciseGroup') + ' ' + exerciseGroup.groupNr + ': ' + exerciseGroup.nameDe"
|
||||
:loading="loading"
|
||||
>
|
||||
<v-timeline
|
||||
direction="horizontal"
|
||||
side="start"
|
||||
class="pb-3"
|
||||
>
|
||||
<v-timeline-item
|
||||
v-for="exercise in exerciseGroup.exercises"
|
||||
:dot-color="exercise.solved ? 'green' : 'grey'"
|
||||
:icon="exercise.solved ? 'mdi-check' : 'mdi-pencil'"
|
||||
>
|
||||
<v-skeleton-loader
|
||||
type="text"
|
||||
:loading="loading"
|
||||
>
|
||||
<div class="text-h6">
|
||||
{{ $t('exercise') }} {{ exercise.exerciseNr }}
|
||||
</div>
|
||||
</v-skeleton-loader>
|
||||
|
||||
|
||||
<template #opposite>
|
||||
{{ $t('scoreBoard.exercise', [step]) }}
|
||||
<v-skeleton-loader
|
||||
type="text"
|
||||
:loading="loading"
|
||||
>
|
||||
<div class="text-center">
|
||||
<div class="text-h6">
|
||||
{{ exercise.nameDe }}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{{ exercise.descriptionDe }}
|
||||
</div>
|
||||
</div>
|
||||
</v-skeleton-loader>
|
||||
</template>
|
||||
|
||||
</v-timeline-item>
|
||||
|
||||
Reference in New Issue
Block a user