init
This commit is contained in:
commit
498fe2220a
34 files changed
+3608
No files matched your search
@@ -0,0 +1,105 @@
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import { render } from '../markdown.js'
|
||||
|
||||
const props = defineProps({ state: Object })
|
||||
const emit = defineEmits(['start', 'pause', 'reset'])
|
||||
|
||||
const laeuft = computed(() => props.state?.status === 'laeuft')
|
||||
const fertig = computed(() => props.state?.status === 'fertig')
|
||||
const begonnen = computed(() => ['pausiert', 'fehler', 'fertig'].includes(props.state?.status)
|
||||
|| (props.state?.stufen || []).some((s) => s.status !== 'offen'))
|
||||
|
||||
function usd(n) { return (n || 0).toFixed(2) + ' $' }
|
||||
function tokens(n) { return n >= 1e6 ? (n / 1e6).toFixed(2) + ' M' : n >= 1e3 ? Math.round(n / 1e3) + ' k' : String(n || 0) }
|
||||
function dauer(s) {
|
||||
if (!s.gestartet) return ''
|
||||
const a = new Date(s.gestartet)
|
||||
const b = s.beendet ? new Date(s.beendet) : new Date()
|
||||
const sek = Math.max(0, Math.round((b - a) / 1000))
|
||||
return sek < 90 ? `${sek} s` : `${Math.round(sek / 60)} min`
|
||||
}
|
||||
function uhr(t) { return t ? new Date(t).toLocaleTimeString('de-DE') : '' }
|
||||
const statusText = { offen: 'wartet', laeuft: 'läuft', fertig: 'fertig', pausiert: 'pausiert', fehler: 'Fehler', abgebrochen: 'abgebrochen' }
|
||||
const statusFarbe = { laeuft: 'blau', fertig: 'gruen', fehler: 'rot', abgebrochen: 'gelb', pausiert: 'gelb' }
|
||||
|
||||
// Laufende Agenten zuerst, danach die übrigen nach Stufe (in Stufenreihenfolge)
|
||||
const gruppen = computed(() => {
|
||||
const ag = props.state?.agenten || []
|
||||
const out = [{ titel: 'Läuft gerade', agenten: ag.filter((a) => a.status === 'laeuft') }]
|
||||
const rest = ag.filter((a) => a.status !== 'laeuft')
|
||||
const stufen = (props.state?.stufen || []).map((s) => s.id)
|
||||
for (const id of stufen) out.push({ titel: props.state.stufen.find((s) => s.id === id).titel, agenten: rest.filter((a) => a.stufe === id) })
|
||||
out.push({ titel: 'Sonstige', agenten: rest.filter((a) => !stufen.includes(a.stufe)) })
|
||||
return out.filter((g) => g.agenten.length)
|
||||
})
|
||||
const ereignisse = computed(() => (props.state?.ereignisse || []).slice(-100).reverse())
|
||||
|
||||
function reset() { if (confirm('Lauf zurücksetzen? Alles außer dem Thema wird gelöscht.')) emit('reset') }
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="lauf">
|
||||
<div class="aktionen">
|
||||
<button v-if="!laeuft && !fertig" @click="emit('start')">{{ begonnen ? 'Fortsetzen' : 'Buch erzeugen' }}</button>
|
||||
<button v-if="laeuft" class="sekundaer" @click="emit('pause')">Pause</button>
|
||||
<button v-if="!laeuft && begonnen" class="sekundaer" @click="reset">Zurücksetzen</button>
|
||||
<span class="spacer"></span>
|
||||
<span class="badge" :class="statusFarbe[state.status]">{{ statusText[state.status] || state.status }}<template v-if="state.stufe && laeuft"> · {{ state.stufe }}</template></span>
|
||||
<span class="badge">{{ usd(state.kosten_usd) }}</span>
|
||||
<span class="badge">{{ tokens(state.tokens) }} Tokens</span>
|
||||
</div>
|
||||
<div v-if="state.grund" class="grund">{{ state.grund }}</div>
|
||||
|
||||
<div v-if="state.deutung" class="deutung">
|
||||
<div class="titel">{{ state.deutung.titel }}</div>
|
||||
<div v-if="state.deutung.untertitel" class="sub">{{ state.deutung.untertitel }}</div>
|
||||
<p v-if="state.deutung.deutung">{{ state.deutung.deutung }}</p>
|
||||
<div class="fakten">
|
||||
<span v-if="state.deutung.buchtyp"><b>Buchtyp</b> {{ state.deutung.buchtyp === 'werkzeug' ? 'Werkzeug' : state.deutung.buchtyp === 'wissen' ? 'Wissen' : state.deutung.buchtyp }}</span>
|
||||
<span v-if="state.deutung.zielgruppe"><b>Zielgruppe</b> {{ state.deutung.zielgruppe }}</span>
|
||||
<span v-if="state.deutung.referenz"><b>Referenz</b> {{ state.deutung.referenz }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="stufen">
|
||||
<div v-for="s in state.stufen" :key="s.id" class="stufe" :class="s.status">
|
||||
<div class="kreis">{{ s.status === 'fertig' ? '✓' : '' }}</div>
|
||||
<div>
|
||||
<div class="name">{{ s.titel }}</div>
|
||||
<div class="sub">{{ statusText[s.status] || s.status }}<template v-if="s.gesamt"> · {{ s.fertig }} / {{ s.gesamt }}</template></div>
|
||||
<div v-if="s.gesamt" class="balken"><i :style="{ width: Math.min(100, 100 * s.fertig / s.gesamt) + '%' }"></i></div>
|
||||
</div>
|
||||
<div class="sub rechts">{{ s.tokens ? usd(s.kosten_usd) + ' · ' + tokens(s.tokens) + ' Tokens' : '' }}</div>
|
||||
<div class="sub rechts">{{ dauer(s) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="gruppen.length" class="agenten">
|
||||
<template v-for="g in gruppen" :key="g.titel">
|
||||
<h3>{{ g.titel }}</h3>
|
||||
<details v-for="a in g.agenten" :key="a.id" class="agent" :class="a.status">
|
||||
<summary>
|
||||
<span class="name">{{ a.name }}</span>
|
||||
<span class="badge" :class="statusFarbe[a.status]">{{ statusText[a.status] || a.status }}</span>
|
||||
<span class="sub">{{ usd(a.kosten_usd) }}</span>
|
||||
<span class="sub">{{ tokens(a.tokens) }} Tokens</span>
|
||||
<span class="sub">{{ a.werkzeuge || 0 }} Werkzeuge</span>
|
||||
<span class="sub">{{ dauer(a) }}</span>
|
||||
</summary>
|
||||
<div v-if="a.bericht" class="bericht md" v-html="render(a.bericht)"></div>
|
||||
<div v-else class="bericht sub">Noch kein Abschlussbericht.</div>
|
||||
</details>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<details v-if="ereignisse.length" class="ereignisse">
|
||||
<summary>Ereignisse ({{ ereignisse.length }})</summary>
|
||||
<div v-for="(e, i) in ereignisse" :key="i" class="ereignis" :class="e.art">
|
||||
<span class="zeit">{{ uhr(e.zeit) }}</span>
|
||||
<span class="wer">{{ e.agent }}</span>
|
||||
<span class="text">{{ e.text }}</span>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
</template>
|
||||
Reference in new issue
Block a user