<template>
    <base-container>
        <h2 class="pt-5 pb-5">流式显示文本(需先启动node-local-server项目作为本地服务端)</h2>
        <div>
            <el-button
                type="primary"
                @click="handleSend"
                >问个问题</el-button
            >
            <el-button
                type="primary"
                @click="handleClose"
                >停止</el-button
            >
        </div>
        <div
            class="wordbox"
            ref="contentRef"
            @scroll="contentScrollFN"
        >
            <div
                id="content"
                v-html="content"
            ></div>
        </div>
    </base-container>
</template>

<script setup>
import { ref } from 'vue';
import { fetchEventSource } from '@microsoft/fetch-event-source';
import { useAutoScroll } from '@/hooks/useAutoScroll';
const { canAutoScroll, contentRef, contentScrollFN } = useAutoScroll();

const content = ref('');
const controller = ref(null);

const updateContent = (event) => {
    content.value += event.data;
    if (event.data === 'End') {
        /**
         * 注释部分为前端手动关闭sse连接的实现
         * 这里不手动关闭原因是@microsoft/fetch-event-source这个框架可以正确检测后段服务端是否关闭了连接，所以不需要手动关闭
         * 浏览器原生new EventSource()方法无法检测后端服务端是否关闭连接，所以需要手动关闭(每次后段关闭都会进onerror事件)
         * 具体请看另外一个demo sseNative.vue
         */
        // handleClose();
    }
};

const handleError = (event) => {
    console.log(event);
    console.log('sse连接出错');
};

const handleClose = () => {
    console.log('sse关闭');
    controller.value.abort();
};

const handleSend = () => {
    canAutoScroll.value = true;
    controller.value = new AbortController();
    const signal = controller.value.signal;
    /** @microsoft/fetch-event-source该框架支持POST方法，并且支持传参 */
    fetchEventSource('http://localhost:3000/events', {
        method: 'POST',
        body: JSON.stringify({
            question: '你好，我是小雅，请问有什么可以帮助您？',
            token: 'xxxx',
        }),
        onmessage: updateContent,
        onerror: handleError,
        onclose: handleClose,
        signal,
    });
};
</script>

<style lang="scss" scoped>
.wordbox {
    width: 100%;
    height: 200px;
    position: relative;
    overflow-y: auto;
    overflow-x: hidden;
    padding: 20px;
    border: 1px solid #ccc;
    margin: 20px 0;
    border-radius: 5px;
    scrollbar-width: none;
    word-break: break-all;
}

.wordbox::-webkit-scrollbar {
    display: none; /* 隐藏滚动条 */
}

@media screen and (min-width: 768px) {
    .wordbox {
        width: 400px;
    }
}
</style>
