This commit is contained in:
team3
2026-06-17 11:54:45 +02:00
parent e8214598ea
commit 390ec12bbf
5 changed files with 69 additions and 25 deletions

View File

@@ -1,5 +1,5 @@
<script setup>
import { computed, nextTick, ref } from 'vue'
import { computed, nextTick, onMounted, onUnmounted, ref } from 'vue'
import { chatBaustein, createVertiefung, fetchVertiefung, pruefeBaustein } from '../api.js'
import { renderMarkdown } from '../markdown.js'
import { useChat, istUnten } from '../composables/useChat.js'
@@ -245,15 +245,17 @@ function antwortPayload() {
}
// Hintergrund: voller Bewerter+Kritiker. Persistiert serverseitig; korrigiert die Anzeige bei Abweichung.
async function verdictPruefen() {
// gruendlich=true: starkes Modell (role guide), manuell ausgelöst → sichtbarer Ladezustand.
async function verdictPruefen(gruendlich = false) {
const meine = ++pruefenRun
const ziel = letzteFeedbackMsg
const warAbsolviert = st.value.absolviert
const warVerstanden = st.value.verstanden
if (gruendlich) pruefLoading.value = true
try {
const res = await pruefeBaustein({
topic: props.topic, baustein: props.baustein, section: props.section,
provider: props.provider, messages: pruefDialog(), ...antwortPayload(), aktion: 'antwort_pruefen',
provider: props.provider, messages: pruefDialog(), ...antwortPayload(), aktion: 'antwort_pruefen', gruendlich,
})
if (meine !== pruefenRun) return // eine neuere Bewertung läuft → diese verwerfen
// Streak driftfrei aus streakVorFrage neu setzen; Reset nur am Deckel der
@@ -275,6 +277,8 @@ async function verdictPruefen() {
}
} catch {
if (meine === pruefenRun && ziel) ziel.geprueft = true
} finally {
if (gruendlich && meine === pruefenRun) pruefLoading.value = false
}
}
@@ -286,9 +290,39 @@ function antwortAbgeben() {
pruefSenden(antwortPayload(), bewerten)
}
function neuBewerten() {
// „Gründlich prüfen": dieselbe Antwort, aber vom starken Modell (role guide) verbindlich neu bewerten.
function gruendlichPruefen() {
if (pruefLoading.value) return
pruefSenden(antwortPayload(), bewerten)
verdictPruefen(true)
}
// Abbruch wie im Chat: Run-Counter hochzählen → laufendes Ergebnis (pruefSenden
// und verdictPruefen) wird verworfen, Buttons sofort frei. Agent läuft serverseitig aus.
function pruefAbbrechen() {
if (!pruefLoading.value) return
pruefRun++
pruefenRun++
pruefLoading.value = false
pruefMessages.value.push({ role: 'assistant', kind: 'fehler', content: 'Abgebrochen.' })
}
// ESC bricht ab — window-Listener, da nach Button-Klick der Fokus das Panel verlässt.
function onWindowKey(e) {
if (e.key === 'Escape' && pruefLoading.value) { e.preventDefault(); pruefAbbrechen() }
}
onMounted(() => window.addEventListener('keydown', onWindowKey))
onUnmounted(() => window.removeEventListener('keydown', onWindowKey))
// ALT+1 Nachfragen/Nachhaken · ALT+2 primär (Antwort abgeben / Nächste Frage) · ALT+3 Gründlich prüfen.
function onPruefKey(e) {
if (!e.altKey || e.repeat) return
if (e.key === '1') { e.preventDefault(); nachfragen() }
else if (e.key === '2') {
e.preventDefault()
pruefPhase.value === 'frage_offen' ? antwortAbgeben() : naechsteFrageZeigen()
} else if (e.key === '3' && pruefPhase.value === 'bewertet') {
e.preventDefault(); gruendlichPruefen()
}
}
</script>
@@ -357,7 +391,7 @@ function neuBewerten() {
</div>
<!-- Prüfung: gesteuerter Dialog -->
<div v-else>
<div v-else @keydown="onPruefKey">
<p class="bp-hint">
<template v-if="st.gemeistert"> Gemeistert ({{ MEISTERN }}/{{ MEISTERN }}) Max. Du kannst dich weiter prüfen, ohne Punkte.</template>
<template v-else-if="st.verstanden && tier3">Meisterpfad: {{ st.gute_antworten }}/{{ MEISTERN }}. Richtig = +1, falsch = 2 (nicht unter {{ MAX }}). Bei {{ MEISTERN }} gemeistert.</template>
@@ -379,7 +413,8 @@ function neuBewerten() {
<!-- Phase idle: Frage anfordern -->
<div v-if="pruefPhase === 'idle'" class="bp-actions">
<button class="bp-action primary" :disabled="pruefLoading" @click="frageAnfordern">Frage anfordern</button>
<button v-if="pruefLoading" class="bp-action cancel" @click="pruefAbbrechen">Abbrechen</button>
<button v-else class="bp-action primary" @click="frageAnfordern">Frage anfordern</button>
</div>
<!-- Phase frage_offen / bewertet: Textfeld + Aktionen -->
@@ -393,14 +428,15 @@ function neuBewerten() {
></textarea>
</div>
<div class="bp-actions">
<template v-if="pruefPhase === 'frage_offen'">
<button class="bp-action" :disabled="pruefLoading || !pruefInput.trim()" @click="nachfragen">Nachfragen</button>
<button class="bp-action primary" :disabled="pruefLoading || !pruefInput.trim()" @click="antwortAbgeben">Antwort abgeben</button>
<button v-if="pruefLoading" class="bp-action cancel" @click="pruefAbbrechen">Abbrechen</button>
<template v-else-if="pruefPhase === 'frage_offen'">
<button class="bp-action" :disabled="!pruefInput.trim()" @click="nachfragen">Nachfragen</button>
<button class="bp-action primary" :disabled="!pruefInput.trim()" @click="antwortAbgeben">Antwort abgeben</button>
</template>
<template v-else>
<button class="bp-action" :disabled="pruefLoading || !pruefInput.trim()" @click="nachfragen">Nachhaken</button>
<button class="bp-action" :disabled="pruefLoading" @click="neuBewerten">Neu bewerten</button>
<button class="bp-action primary" :disabled="pruefLoading" @click="naechsteFrageZeigen">Nächste Frage</button>
<button class="bp-action" :disabled="!pruefInput.trim()" @click="nachfragen">Nachhaken</button>
<button class="bp-action" @click="gruendlichPruefen">Gründlich prüfen</button>
<button class="bp-action primary" @click="naechsteFrageZeigen">Nächste Frage</button>
</template>
</div>
</template>
@@ -463,6 +499,7 @@ function neuBewerten() {
.bp-action:disabled { opacity: 0.5; cursor: default; }
.bp-action.primary { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
.bp-action.primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); }
.bp-action.cancel { background: var(--danger); border-color: var(--danger); color: var(--on-accent); }
.bp-actions { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-top: 0.5rem; }
.bp-actions .bp-action { margin-top: 0; }