update
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
import { computed, nextTick, ref } from 'vue'
|
||||
import { chatBaustein, createVertiefung, fetchVertiefung, pruefeBaustein } from '../api.js'
|
||||
import { renderMarkdown } from '../markdown.js'
|
||||
import { useChat } from '../composables/useChat.js'
|
||||
import { useChat, istUnten } from '../composables/useChat.js'
|
||||
|
||||
const props = defineProps({
|
||||
topic: { type: String, required: true },
|
||||
@@ -80,15 +80,20 @@ const letztesFeedback = ref('') // Kontext für die Diskussion über eine Bewer
|
||||
const scoreVorFrage = ref(0) // Score, als die aktuelle Frage gestellt wurde → driftfreies (Re-)Bewerten
|
||||
const pruefMessagesEl = ref(null)
|
||||
const pruefInputEl = ref(null)
|
||||
const pruefStick = ref(true) // nur auto-scrollen, wenn der Nutzer (fast) unten ist
|
||||
let pruefRun = 0
|
||||
|
||||
function onPruefScroll() {
|
||||
if (pruefMessagesEl.value) pruefStick.value = istUnten(pruefMessagesEl.value)
|
||||
}
|
||||
|
||||
function applyPruefung(res) {
|
||||
emit('statusChanged', { ...st.value, gute_antworten: res.gute_antworten, absolviert: res.absolviert, verstanden: res.verstanden })
|
||||
}
|
||||
|
||||
async function pruefScroll() {
|
||||
await nextTick()
|
||||
if (pruefMessagesEl.value) pruefMessagesEl.value.scrollTop = pruefMessagesEl.value.scrollHeight
|
||||
if (pruefMessagesEl.value && pruefStick.value) pruefMessagesEl.value.scrollTop = pruefMessagesEl.value.scrollHeight
|
||||
}
|
||||
|
||||
// Nur echte Gesprächs-Turns ans Backend; Feedback bleibt reines UI-Artefakt.
|
||||
@@ -201,7 +206,7 @@ function neuBewerten() {
|
||||
|
||||
<!-- Bausteinchat -->
|
||||
<div v-else-if="activeTab === 'chat'">
|
||||
<div :ref="chat.messagesEl" class="bp-messages">
|
||||
<div :ref="chat.messagesEl" class="bp-messages" @scroll="chat.onScroll">
|
||||
<p v-if="!chat.messages.value.length" class="bp-hint">Frag etwas zu diesem Baustein. Der Verlauf wird nicht gespeichert.</p>
|
||||
<template v-for="(m, i) in chat.messages.value" :key="i">
|
||||
<div v-if="m.role === 'assistant'" class="bp-msg assistant markdown" v-html="renderMarkdown(m.content)"></div>
|
||||
@@ -232,7 +237,7 @@ function neuBewerten() {
|
||||
<template v-else>{{ Math.min(st.gute_antworten, NOETIG) }}/{{ NOETIG }} guten Antworten. Frag nach, wenn etwas unklar ist — diskutieren ist erlaubt.</template>
|
||||
</p>
|
||||
|
||||
<div v-if="pruefMessages.length" :ref="pruefMessagesEl" class="bp-messages">
|
||||
<div v-if="pruefMessages.length" :ref="pruefMessagesEl" class="bp-messages" @scroll="onPruefScroll">
|
||||
<template v-for="(m, i) in pruefMessages" :key="i">
|
||||
<div v-if="m.kind === 'feedback'" class="bp-feedback" :class="m.bewertung">{{ m.content }}</div>
|
||||
<div v-else-if="m.kind === 'fehler'" class="bp-error">{{ m.content }}</div>
|
||||
|
||||
@@ -68,7 +68,7 @@ const chat = useChat((msgs) => {
|
||||
section, outline, messages: msgs, provider: props.provider,
|
||||
})
|
||||
})
|
||||
const { messages, input, loading, messagesEl, inputEl, send } = chat
|
||||
const { messages, input, loading, messagesEl, inputEl, onScroll, send } = chat
|
||||
const autoGrow = () => chat.autoGrow()
|
||||
const chatOpen = ref(false)
|
||||
const panelEl = ref(null)
|
||||
@@ -199,7 +199,7 @@ function extractContext() {
|
||||
<span>Fragen zum Guide</span>
|
||||
<button class="chat-close" title="Chat beenden" @click="closeChat">×</button>
|
||||
</header>
|
||||
<div ref="messagesEl" class="chat-messages">
|
||||
<div ref="messagesEl" class="chat-messages" @scroll="onScroll">
|
||||
<p v-if="!messages.length" class="chat-hint">Stell eine Frage zum aktuellen Abschnitt.</p>
|
||||
<template v-for="(m, i) in messages" :key="i">
|
||||
<div v-if="m.role === 'assistant'" class="chat-msg assistant markdown" v-html="renderMarkdown(m.content)"></div>
|
||||
|
||||
@@ -11,7 +11,7 @@ const props = defineProps({
|
||||
const emit = defineEmits(['changes'])
|
||||
|
||||
const chat = useChat((msgs) => chatElement(props.element.id, msgs, props.provider))
|
||||
const { messages, input, loading, messagesEl, inputEl } = chat
|
||||
const { messages, input, loading, messagesEl, inputEl, onScroll } = chat
|
||||
|
||||
// Anderes Element gewählt → Verlauf verwerfen
|
||||
watch(() => props.element.id, () => chat.reset())
|
||||
@@ -24,7 +24,7 @@ async function send() {
|
||||
|
||||
<template>
|
||||
<div class="el-chat">
|
||||
<div ref="messagesEl" class="chat-messages">
|
||||
<div ref="messagesEl" class="chat-messages" @scroll="onScroll">
|
||||
<p v-if="!messages.length" class="chat-hint">Schreib, was am Element geändert werden soll.</p>
|
||||
<template v-for="(m, i) in messages" :key="i">
|
||||
<div :class="['chat-msg', m.role]">{{ m.content }}</div>
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
import { ref, nextTick } from 'vue'
|
||||
|
||||
// (Fast) am unteren Rand? Schwelle fängt Sub-Pixel und kleine Abstände ab.
|
||||
export function istUnten(el, schwelle = 60) {
|
||||
return el.scrollHeight - el.scrollTop - el.clientHeight < schwelle
|
||||
}
|
||||
|
||||
// Gemeinsame Chat-Mechanik: senden, abbrechen (Run-Counter), scrollen, Fokus.
|
||||
// performRequest(messages) → Promise<{ reply, … }>; send() gibt die Antwort
|
||||
// zurück, damit der Aufrufer Extras (z. B. changes) auswerten kann.
|
||||
@@ -9,11 +14,17 @@ export function useChat(performRequest) {
|
||||
const loading = ref(false)
|
||||
const messagesEl = ref(null) // Template-Ref: Nachrichten-Container
|
||||
const inputEl = ref(null) // Template-Ref: Textarea
|
||||
const stick = ref(true) // an den Boden „gepinnt" — nur dann auto-scrollen
|
||||
let run = 0 // laufende Anfrage identifizieren; Abbruch ignoriert ihr Ergebnis
|
||||
|
||||
// @scroll-Handler: pinnt nur, wenn der Nutzer (fast) unten ist.
|
||||
function onScroll() {
|
||||
if (messagesEl.value) stick.value = istUnten(messagesEl.value)
|
||||
}
|
||||
|
||||
async function scrollToBottom() {
|
||||
await nextTick()
|
||||
if (messagesEl.value) messagesEl.value.scrollTop = messagesEl.value.scrollHeight
|
||||
if (messagesEl.value && stick.value) messagesEl.value.scrollTop = messagesEl.value.scrollHeight
|
||||
}
|
||||
|
||||
function autoGrow(max = 140) {
|
||||
@@ -73,5 +84,5 @@ export function useChat(performRequest) {
|
||||
}
|
||||
}
|
||||
|
||||
return { messages, input, loading, messagesEl, inputEl, send, cancel, reset, scrollToBottom, autoGrow }
|
||||
return { messages, input, loading, messagesEl, inputEl, stick, onScroll, send, cancel, reset, scrollToBottom, autoGrow }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user