This commit is contained in:
team3
2026-06-24 21:27:11 +02:00
parent c802c7fd02
commit e0f1b59707
5 changed files with 57 additions and 5 deletions

View File

@@ -170,6 +170,14 @@ export async function uebernehmeBlock(id, { baustein, stelle, alt, neu, provider
return jsonOrThrow(res)
}
// Lern-Fortschritt eines Bausteins auf null setzen (Score/Streak/Flags/offene Frage).
export async function resetBausteinFortschritt(topic, baustein) {
const res = await fetch(`${BASE}/bausteine/fortschritt?topic=${encodeURIComponent(topic)}&baustein=${encodeURIComponent(baustein)}`, {
method: 'DELETE',
})
return jsonOrThrow(res)
}
export async function fetchTopics() {
const res = await fetch(`${BASE}/topics`)
return res.json()

View File

@@ -2,7 +2,9 @@
import BausteinPanel from './BausteinPanel.vue'
import { renderMarkdown, renderBloecke } from '../markdown.js'
import { stufeFuer, STUFEN } from '../stufen.js'
import { pruefeBlock, uebernehmeBlock } from '../api.js'
import { pruefeBlock, uebernehmeBlock, resetBausteinFortschritt } from '../api.js'
import { clearPruef } from '../pruefungCache.js'
import { useConfirm } from '../composables/useConfirm.js'
const props = defineProps({
baustein: { type: Object, required: true }, // { title, md, num }
@@ -22,6 +24,27 @@ import { computed, onMounted, onUnmounted, reactive, ref, watch } from 'vue'
const emit = defineEmits(['close', 'prev', 'next', 'statusChanged', 'setAnsicht', 'openSidebar', 'sectionUpdated'])
// --- Reset pro Baustein: Fragen-Session (Slot) bzw. Fortschritt (Score) ---
const { isArmed, armOrRun } = useConfirm()
const resetN = ref(0) // Hochzählen → Panel-Remount (frischer Slot, Muster neu)
const pruefKey = computed(() => `${props.topic}::${props.baustein.title}`)
// Frage-Session neu: Slot verwerfen → Remount lädt Muster + Pool frisch (behebt Erklären-only).
function fragenResetten() {
clearPruef(pruefKey.value)
resetN.value++
}
// Fortschritt auf 0: DB-Zeile löschen, Badge/Lernstand nullen, Session frisch.
async function fortschrittResetten() {
try {
await resetBausteinFortschritt(props.topic, props.baustein.title)
emit('statusChanged', { baustein: props.baustein.title, gute_antworten: 0, streak: 0, cap: props.cap })
clearPruef(pruefKey.value)
resetN.value++
} catch (e) { /* still bleiben — Reset fehlgeschlagen */ }
}
const guideEl = ref(null) // linke Guide-Spalte (Scroll-Ziel für ALT+↑/↓)
const rightEl = ref(null) // rechte Spalte (Prüfungs-Panel mit Eingabefeld)
@@ -134,6 +157,13 @@ watch(() => `${props.baustein.title}|${props.baustein.md}|${props.baustein.kompa
<span class="fokus-titel">{{ baustein.title }}</span>
<span v-if="stufe" class="stand-badge" :style="{ color: stufe.farbe, borderColor: stufe.farbe }">{{ stufe.kurz }} {{ stufe.label }}</span>
<span class="fokus-spacer"></span>
<button class="fokus-btn" title="Fragen resetten (neue Frage-Session)" @click="fragenResetten"></button>
<button
class="fokus-btn"
:class="{ armed: isArmed('reset-fortschritt') }"
:title="isArmed('reset-fortschritt') ? 'Nochmal klicken: Fortschritt auf 0 setzen' : 'Fortschritt resetten (Score auf 0)'"
@click="armOrRun('reset-fortschritt', fortschrittResetten)"
></button>
<button class="fokus-btn" title="Vollansicht beenden" @click="$emit('close')"></button>
</div>
</div>
@@ -175,7 +205,7 @@ watch(() => `${props.baustein.title}|${props.baustein.md}|${props.baustein.kompa
<div ref="rightEl" class="fokus-col right">
<BausteinPanel
mode="full"
:key="baustein.title + '|' + tab"
:key="baustein.title + '|' + tab + '|' + resetN"
:initial-tab="tab"
:topic="topic"
:baustein="baustein.title"
@@ -263,6 +293,7 @@ watch(() => `${props.baustein.title}|${props.baustein.md}|${props.baustein.kompa
}
.fokus-btn:hover { border-color: var(--accent); }
.fokus-btn:disabled { opacity: 0.4; cursor: default; }
.fokus-btn.armed { border-color: var(--danger, #dc2626); color: var(--danger, #dc2626); background: color-mix(in srgb, var(--danger, #dc2626) 12%, var(--panel)); }
/* Zwei abgehobene Karten auf grauem „Schreibtisch" (--bg-preview vom Overlay). */
.fokus-body {

View File

@@ -206,10 +206,10 @@ async function musterLaden() {
try {
const res = await fetchFrageMuster(props.topic, props.baustein)
musterQuelle.value = (res.muster || []).map((m) => (m.frage || '').trim()).filter(Boolean)
musterGeladen.value = true // NUR bei Erfolg — sonst friert ein Fehlversuch die Session auf Erklären-only
} catch {
musterQuelle.value = []
musterQuelle.value = [] // musterGeladen bleibt false → nächster Zug versucht erneut
}
musterGeladen.value = true
}
function mischen(arr) { // Fisher-Yates