7. Auswertung einer Übung
Die Auswertung (evaluateUebung) ist der letzte Schritt im Übungsprozess. Die UebungenAPI kümmert sich um die komplexe Logik und gibt strukturierte Daten mit automatisch generiertem Feedback zurück.
7.1 Backend: Die evaluateUebung Methode
7.1.1 Minimale Implementierung
In /modules/Uebungen/UebungVokabeltrainer/app/Models/UebungVokabeltrainer.php:
public function evaluateUebung(?Request $request = null): mixed
{
// Hole die Evaluation-Daten (automatisch von der API bereitgestellt)
$EvaluationData = $this->getEvaluationData($request->input_data);
// Belohne den Nutzer mit Gravitas
$this->rewardUser($EvaluationData);
// Speichere den Übungs-Datensatz
$this->setAbsolved($EvaluationData);
// Gib die Daten ans Frontend zurück
return $EvaluationData;
}7.1.2 Die reviewInput Methode
Diese Methode muss implementiert werden und vergleicht die Nutzereingaben:
public function reviewInput(array $input_data): Collection
{
$InputDataCollection = collect($input_data);
$ContentDataCollection = collect($this->content_data);
return $InputDataCollection->map(function ($InputItem) use ($ContentDataCollection) {
$ContentItem = $ContentDataCollection->firstWhere('value_given', $InputItem['value_given']);
// Prüfe: 1 = richtig, 0 = falsch, null = nicht beantwortet
$IsCorrect = ($InputItem['value_input'] === $ContentItem['value_expected']) ? 1 :
(($InputItem['value_input'] === null || $InputItem['value_input'] === '') ? null : 0);
return [
"value_given" => $ContentItem['value_given'],
"value_expected" => $ContentItem['value_expected'],
"value_input" => $InputItem['value_input'],
"correct" => $IsCorrect
];
});
}7.1.3 Die calculateCorrectRatio Methode (optional)
Falls Sie die Standard-Berechnung überschreiben möchten:
public function calculateCorrectRatio(Collection $reviewedInputData): float
{
$CorrectAnswers = $reviewedInputData->where('correct', 1)->count();
return round($CorrectAnswers / $reviewedInputData->count(), 2);
}7.2 Was die UebungenAPI automatisch zurückgibt
Die getEvaluationData() Methode des Evaluable-Traits gibt ein komplexes Objekt zurück mit:
7.2.1 Die Hauptstruktur
{
"scoreData": {
"score_correct_ratio": 0.75, // 75% richtig
"score_time_ratio": 1.1, // 10% schneller als Richtzeit
"score_total_ratio": 0.83, // Gesamtscore
"score_total_points": 83, // Punkte (score_total_ratio * 100)
"score_gravitas": 25 // Erhaltene Gravitas
},
"feedbackData": {
"generalFeedback": "Bene fecisti! Gut gemacht! Ad astra per aspera.",
"correctnessFeedback": "Egregie! (75%) Sehr gut! Fast alles richtig.",
"timeFeedback": "Bene et celeriter! Schneller als die Richtzeit!",
"pointsFeedback": "Du hast insgesamt 83 Punkte erreicht.",
"gravitasFeedback": "Für dieses Ergebnis erhältst du 25 Gravitas-Punkte."
},
"reviewData": {
"ReviewedInputData": [
{
"value_given": "laudare",
"value_expected": "loben",
"value_input": "loben",
"correct": 1
},
{
"value_given": "amare",
"value_expected": "lieben",
"value_input": "mögen",
"correct": 0
}
],
"ReviewStats": {
"total_answers": 4,
"total_answers_correct": 3,
"total_answers_semi_correct": 0,
"total_answers_incorrect": 1,
"total_answers_unanswered": 0
}
}
}7.2.2 Automatisches Feedback
Die UebungenAPIEvaluationData Klasse generiert automatisch Feedback basierend auf der Leistung:
- 100%: "Optime! Hervorragende Arbeit!"
- ≥70%: "Bene fecisti! Gut gemacht! Ad astra per aspera."
- ≥50%: "Satis bene. Solide Leistung."
- <50%: "Heu! Das war noch nicht ganz optimal. Repetitio est mater studiorum."
7.3 Frontend: Die Evaluate-Komponente
<template>
<div v-if="evaluateData">
<h2>Übung abgeschlossen!</h2>
<!-- Automatisches Feedback -->
<div>
<p>{{ evaluateData.feedbackData.generalFeedback }}</p>
<p>{{ evaluateData.feedbackData.correctnessFeedback }}</p>
<p v-if="evaluateData.feedbackData.timeFeedback">
{{ evaluateData.feedbackData.timeFeedback }}
</p>
<p>{{ evaluateData.feedbackData.gravitasFeedback }}</p>
</div>
<!-- Review der Antworten -->
<h3>Deine Antworten:</h3>
<div v-for="item in evaluateData.reviewData.ReviewedInputData">
<div>
<strong>{{ item.value_given }}</strong>
<span v-if="item.correct === 1">✓ Richtig</span>
<span v-else-if="item.correct === 0">✗ Falsch</span>
<span v-else>- Nicht beantwortet</span>
</div>
<div>
Deine Antwort: {{ item.value_input || '(keine Antwort)' }}
</div>
<div v-if="item.correct === 0">
Richtige Antwort: {{ item.value_expected }}
</div>
</div>
<!-- Statistik -->
<div>
<p>Richtig: {{ evaluateData.reviewData.ReviewStats.total_answers_correct }}</p>
<p>Falsch: {{ evaluateData.reviewData.ReviewStats.total_answers_incorrect }}</p>
<p>Gesamt: {{ evaluateData.reviewData.ReviewStats.total_answers }}</p>
</div>
<button @click="backToLibrary">Zurück zur Übungsbibliothek</button>
</div>
</template>
<script>
export default {
props: ['evaluate_data'],
computed: {
evaluateData() {
return this.evaluate_data;
}
},
methods: {
backToLibrary() {
EventBus.$emit('close-absolve-uebung-modal');
}
}
}
</script>7.4 Frontend: Verwendung der Hermeneus-Komponenten
Für eine professionellere Darstellung können Sie die vorgefertigten Komponenten nutzen:
<template>
<div>
<!-- Feedback Komponente (zeigt alle Feedback-Texte) -->
<uebung-feedback-component
:feedback-data="evaluateData.feedbackData"
:config="config"
/>
<!-- Score Komponente (zeigt Punkte und Gravitas) -->
<uebung-score-component
:score-data="evaluateData.scoreData"
:feedback-data="evaluateData.feedbackData"
:config="config"
/>
</div>
</template>
<script>
import UebungFeedbackComponent from "@/uebungen-library/components/EvaluationComponents/UebungFeedbackComponent.vue"
import UebungScoreComponent from "@/uebungen-library/components/EvaluationComponents/UebungScoreComponent.vue"
export default {
components: {
'uebung-feedback-component': UebungFeedbackComponent,
'uebung-score-component': UebungScoreComponent
},
props: ['evaluate_data'],
computed: {
evaluateData() {
return this.evaluate_data;
},
config() {
return this.evaluate_data?.config || {};
}
}
}
</script>7.5 Wichtige Punkte
- Sie müssen nur
reviewInput()implementieren - alles andere macht die API - Die Traits berechnen automatisch:
- Score basierend auf richtigen Antworten
- Zeitbonus/Malus (wenn
cfg_avg_time_secondsgesetzt) - Gravitas basierend auf
cfg_max_gravitas_level
- Feedback wird automatisch generiert in lateinischen Phrasen
- ReviewStats werden automatisch berechnet aus den ReviewedInputData
7.6 Erweiterte Anpassung: Hook-Methoden
Der Evaluable Trait bietet drei Hook-Methoden, die Sie überschreiben können, um die Evaluation komplett zu individualisieren. Dies ermöglicht es Ihnen, die drei Evaluations-Objekte (reviewData, scoreData, feedbackData) unabhängig voneinander anzupassen.
7.6.1 Übersicht der Hook-Methoden
// 1. buildReviewData() - Erstellt ReviewData aus Eingabedaten
protected function buildReviewData(mixed $DataToEvaluate): UebungenAPIReviewData
// 2. buildScoreData() - Erstellt ScoreData basierend auf ReviewData
protected function buildScoreData(UebungenAPIReviewData $reviewData, float|false $seconds_elapsed = false): UebungenAPIScoreData
// 3. buildFeedbackData() - Erstellt FeedbackData basierend auf ScoreData und ReviewData
protected function buildFeedbackData(UebungenAPIScoreData $scoreData, UebungenAPIReviewData $reviewData): UebungenAPIFeedbackData7.6.2 Beispiel 1: Nur ScoreData anpassen (Gewichtete Bewertung)
Wenn Sie eine eigene Score-Berechnung benötigen (z.B. schwierige Fragen zählen doppelt):
protected function buildScoreData(UebungenAPIReviewData $reviewData, float|false $seconds_elapsed = false): UebungenAPIScoreData
{
// Eigene Logik: Schwierige Fragen zählen doppelt
$scoreData = new UebungenAPIScoreData($reviewData);
$weightedCorrect = 0;
$totalWeight = 0;
foreach ($reviewData->ReviewedInputData as $item) {
$weight = $item['difficulty'] ?? 1; // Standard-Gewicht = 1
$totalWeight += $weight;
if ($item['correct'] === 1) {
$weightedCorrect += $weight;
}
}
// Eigene Berechnung
$scoreData->setScoreCorrectRatio($weightedCorrect / $totalWeight);
$scoreData->setScoreTimeRatio(1.0); // Keine Zeitwertung
$scoreData->setScoreTotalRatio($scoreData->score_correct_ratio);
$scoreData->setScoreTotalPoints((int)round($scoreData->score_total_ratio * 100));
$scoreData->setScoreGravitas((int)round($scoreData->score_total_ratio * 50));
return $scoreData;
}7.6.3 Beispiel 2: Nur FeedbackData anpassen (Spezifisches Feedback)
Wenn Sie eigene Feedback-Texte mit spezifischen Hinweisen generieren möchten:
protected function buildFeedbackData(UebungenAPIScoreData $scoreData, UebungenAPIReviewData $reviewData): UebungenAPIFeedbackData
{
// Standard-Feedback erstellen
$feedbackData = new UebungenAPIFeedbackData($scoreData, true, true);
$feedbackData->generateDefaultFeedback();
// Zusätzliche spezifische Hinweise basierend auf falschen Antworten
$wrongAnswers = $reviewData->ReviewedInputData->filter(fn($item) => $item['correct'] === 0);
if ($wrongAnswers->count() > 0) {
$hints = $this->generateGrammarHints($wrongAnswers);
$feedbackData->setCorrectnessFeedback(
$feedbackData->correctnessFeedback . "\n\nHinweise: " . $hints
);
}
return $feedbackData;
}
private function generateGrammarHints(Collection $wrongAnswers): string
{
// Analysiere falsche Antworten und gib Grammatik-Tipps
return "Wiederhole die Deklinationen der a-Deklination.";
}7.6.4 Beispiel 3: ReviewData komplett neu implementieren
Wenn Sie eine komplett eigene Review-Logik benötigen (z.B. mit KI-Bewertung):
protected function buildReviewData(mixed $DataToEvaluate): UebungenAPIReviewData
{
// Komplett eigene Review-Logik mit KI-Bewertung
$aiReviewResults = $this->evaluateWithAI($DataToEvaluate);
$reviewData = new UebungenAPIReviewData(collect($aiReviewResults));
$reviewData->setStatTotalAnswers(count($aiReviewResults));
$reviewData->setStatTotalAnswersCorrect($this->countCorrect($aiReviewResults));
$reviewData->setStatTotalAnswersIncorrect($this->countIncorrect($aiReviewResults));
$reviewData->setStatTotalAnswersUnanswered($this->countUnanswered($aiReviewResults));
return $reviewData;
}
private function evaluateWithAI(array $data): array
{
// Ihre KI-Bewertungslogik hier
// ...
}7.6.5 Wichtige Punkte zu Hook-Methoden
- Bestehende Module funktionieren weiterhin: Sie müssen nur
reviewInput()implementieren - die Hook-Methoden sind optional - Selektives Überschreiben: Sie können nur die Hook-Methode überschreiben, die Sie anpassen möchten
- Unabhängige Objekte: Jede Hook-Methode kann unabhängig überschrieben werden
- Kontext verfügbar:
buildScoreData()erhältReviewData,buildFeedbackData()erhält beide Objekte als Kontext - Rückgabetypen beachten: Die Hook-Methoden müssen die entsprechenden DataObjects zurückgeben
7.7 Die config.json Komponente
Vergessen Sie nicht, die Evaluate-Komponente zu registrieren:
"components": {
"evaluate": {
"path": "resources/vue/UebungVokabeltrainerEvaluateComponent.vue",
"alias": "uebung-vokabeltrainer-evaluate-component",
"title": "Vokabeltrainer: Auswertung"
}
}