feat: 实现骨架屏的渲染
This commit is contained in:
@@ -19,8 +19,11 @@
|
||||
</view>
|
||||
|
||||
<template v-for="section in contentSections" :key="section.contentKey">
|
||||
<ParsedValueView
|
||||
v-if="shouldUseParsedValueView(section)"
|
||||
<LongAnswerSectionSkeleton
|
||||
v-if="shouldRenderSectionSkeleton(section)"
|
||||
/>
|
||||
|
||||
<ParsedValueView v-else-if="shouldUseParsedValueView(section)"
|
||||
:field-key="section.contentKey"
|
||||
:value="section.parsedValue !== null ? section.parsedValue : section.contentValue"
|
||||
/>
|
||||
@@ -41,6 +44,7 @@
|
||||
<script setup>
|
||||
import TopNavBar from "@/components/TopNavBar/index.vue";
|
||||
import ChatMarkdown from "../ChatMarkdown/index.vue";
|
||||
import LongAnswerSectionSkeleton from "./LongAnswerSectionSkeleton.vue";
|
||||
import ParsedValueView from "./ParsedValueView.vue";
|
||||
import { defineProps, ref, nextTick, computed } from "vue";
|
||||
import { onLoad, onUnload } from "@dcloudio/uni-app";
|
||||
@@ -62,6 +66,7 @@ const props = defineProps({
|
||||
const answerText = ref(props.answerText || "");
|
||||
const title = ref("");
|
||||
const longTextData = ref(null);
|
||||
const streamFinished = ref(false);
|
||||
const longAnswerTagColor = ref(pickRandomTagToneColor());
|
||||
const longAnswerTagStyle = computed(() => buildTagToneStyle(longAnswerTagColor.value));
|
||||
|
||||
@@ -110,6 +115,47 @@ const contentSections = computed(() => {
|
||||
);
|
||||
});
|
||||
|
||||
const getSectionIndex = (section) => {
|
||||
return contentSections.value.findIndex((item) => item.contentKey === section?.contentKey);
|
||||
};
|
||||
|
||||
const hasSectionAfter = (section) => {
|
||||
const sectionIndex = getSectionIndex(section);
|
||||
return sectionIndex >= 0 && sectionIndex < contentSections.value.length - 1;
|
||||
};
|
||||
|
||||
const isNonStringSectionValue = (value) => {
|
||||
return value !== undefined && value !== null && typeof value !== "string";
|
||||
};
|
||||
|
||||
const isPendingStructuredText = (value) => {
|
||||
const text = typeof value === "string" ? value.trim() : "";
|
||||
return text.startsWith("{") || text.startsWith("[");
|
||||
};
|
||||
|
||||
const isStructuredSection = (section) => {
|
||||
return (
|
||||
section?.fromLongTextData &&
|
||||
(
|
||||
(section.parsedValue !== null && isNonStringSectionValue(section.parsedValue)) ||
|
||||
isPendingStructuredText(section.contentValue)
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
const isSectionReady = (section) => {
|
||||
if (!isStructuredSection(section)) return true;
|
||||
return (
|
||||
streamFinished.value ||
|
||||
(section.parsedValue !== null && isNonStringSectionValue(section.parsedValue)) ||
|
||||
hasSectionAfter(section)
|
||||
);
|
||||
};
|
||||
|
||||
const shouldRenderSectionSkeleton = (section) => {
|
||||
return isStructuredSection(section) && !isSectionReady(section);
|
||||
};
|
||||
|
||||
/** ✅ scroll-into-view 控制 */
|
||||
const scrollIntoViewId = ref("");
|
||||
|
||||
@@ -208,6 +254,7 @@ const scrollToBottom = () => {
|
||||
onLoad(({ message = "", streamId = "", finished = "0", tagToneColor = "" }) => {
|
||||
// 记录初始完成状态
|
||||
isFinishedOnInit = finished === "1";
|
||||
streamFinished.value = isFinishedOnInit;
|
||||
longAnswerTagColor.value = tagToneColor ? decodeURIComponent(tagToneColor) : longAnswerTagColor.value;
|
||||
|
||||
console.log("LongAnswer onLoad with params:", { message, streamId, finished, tagToneColor });
|
||||
@@ -222,6 +269,7 @@ onLoad(({ message = "", streamId = "", finished = "0", tagToneColor = "" }) => {
|
||||
unsubscribe = StreamManager.subscribe(
|
||||
streamId,
|
||||
(text = "", finished = false, payload = null) => {
|
||||
streamFinished.value = !!finished;
|
||||
answerText.value = text || "";
|
||||
longTextData.value = payload || null;
|
||||
title.value = computeTitle(
|
||||
@@ -247,6 +295,7 @@ onLoad(({ message = "", streamId = "", finished = "0", tagToneColor = "" }) => {
|
||||
// ✅ 非流式
|
||||
answerText.value = decodeURIComponent(message || "");
|
||||
longTextData.value = null;
|
||||
streamFinished.value = true;
|
||||
title.value = computeTitle(answerText.value);
|
||||
|
||||
nextTick(() => {
|
||||
|
||||
Reference in New Issue
Block a user