This commit is contained in:
team3
2026-07-08 21:14:33 +02:00
parent 9a6ab0937b
commit f9d77a113b
30 changed files with 1064 additions and 654 deletions

View File

@@ -69,33 +69,36 @@ const pct = (note) => Math.round(note * 10) + ' %'
// ── Laufzeit + Tokens aus /api/runs (5s-Takt, unabhängig vom 1,2s-Board-Poll) ──────
const run = ref(null)
const latest = ref(null) // jüngster Lauf MIT Daten je Ebene — überlebt „Nur Artefakte"-Läufe
const now = ref(Date.now())
let clock = null
async function loadRun() {
try {
const { runs } = await fetchRuns(props.topic, 1)
run.value = runs[0] || null
} catch { run.value = null }
const res = await fetchRuns(props.topic, 1)
run.value = res.runs[0] || null
latest.value = res.latest || null
} catch { run.value = null; latest.value = null }
}
const { start: startRunPoll } = usePolling(loadRun, () => props.generating, 5000)
// Per-Ebene: Zeit + Tokens getrennt für Inventar vs. Artefakte (aus run.boards).
// Per-Ebene: Zeit + Tokens getrennt für Inventar vs. Artefakte. Live tickt nur die Ebene,
// deren Lauf der AKTUELLE ist (b.aktiv) — sonst zählt die alte Inventar-Zeile mit hoch.
function boardZeit(b) {
if (!b?.start) return null
const start = Date.parse(b.start)
const ende = run.value?.aktiv ? now.value : Date.parse(b.ende || b.start)
const ende = b.aktiv ? now.value : Date.parse(b.ende || b.start)
return fmtRuntime((ende - start) / 1000)
}
function boardTokens(b) {
const t = b?.tokens
return t && (t.input || t.output) ? fmtTokens((t.input || 0) + (t.output || 0)) : null
}
const invStat = computed(() => run.value?.boards?.inventory)
const artStat = computed(() => run.value?.boards?.artefacts)
const invStat = computed(() => latest.value?.inventory)
const artStat = computed(() => latest.value?.artefacts)
watch(() => props.generating, (g) => {
if (g) { startRunPoll(); if (!clock) clock = setInterval(() => { now.value = Date.now() }, 1000) }
else { loadRun(); if (clock) { clearInterval(clock); clock = null } } // Endstand
}, { immediate: true })
watch(() => props.topic, () => { run.value = null; loadRun() })
watch(() => props.topic, () => { run.value = null; latest.value = null; loadRun() })
onUnmounted(() => { if (clock) clearInterval(clock) })
const { isArmed, armOrRun, reset: resetConfirm } = useConfirm() // 2-Klick-Bestätigung
@@ -134,7 +137,7 @@ async function repairClick(ebene) {
const suffix = max > 1 ? ` — Runde ${i + 1}${note != null ? ` (${Math.round(note * 10)} %)` : ''}` : ''
repairInfo.value = { ...repairInfo.value, [ebene]: repairText(r) + suffix }
if (note == null || note >= 10) break // 100 % erreicht
if (prev != null && note <= prev) break // Stillstand: Repair bewegt nichts mehr
if (r.aktionen === 0 && prev != null && note <= prev) break // Stillstand: nichts getan, Note steht
prev = note
}
} catch (e) {

View File

@@ -41,14 +41,14 @@ const progressValue = computed(() => (total.value ? done.value / total.value : 0
// QA-Badge nur wenn es ein Board gibt — sonst zeigt ein verwaister Report eine alte Note.
const qaNote = computed(() => (total.value ? board.value?.qa_guide : null))
// Laufzeit + Tokens aus /api/runs (deckt auch Guide-Läufe ab — beide setzen run_id)
// Laufzeit + Tokens aus /api/runs — `latest.guide` ist der jüngste GUIDE-Lauf
// (der jüngste Lauf insgesamt kann ein Blocks-Lauf sein und zeigte hier dessen Zahlen).
const run = ref(null)
const now = ref(Date.now())
let clock = null
async function loadRun() {
try {
const { runs } = await fetchRuns(props.topic, 1)
run.value = runs[0] || null
run.value = (await fetchRuns(props.topic, 1)).latest?.guide || null
} catch { run.value = null }
}
const { start: startRunPoll } = usePolling(loadRun, () => generating.value, 5000)