feat: 修复回答组件跳动的问题

This commit is contained in:
2026-05-15 09:56:34 +08:00
parent c777a0122e
commit e3bf1ff682

View File

@@ -2,14 +2,14 @@
<view class="w-full bg-white border-box border-ff overflow-hidden rounded-20 flex flex-col">
<!-- 占位撑开 -->
<view class="w-vw"></view>
<view class="flex flex-col p-16 border-box border-left-4">
<view class="flex flex-col px-12 pb-12 pt-4 border-box border-left-4">
<view v-if="title" class="flex flex-row flex-items-start flex-justify-start mb-8">
<uni-icons class="icon-active" type="fire-filled" size="18" color="opacity" />
<text class="font-size-16 font-500 text-color-900 ml-6"> {{ title }}</text>
</view>
<!-- 文字内容最多显示3行 -->
<view class="answer-content font-size-12 font-color-600">
<ChatMarkdown :key="textKey" :text="processedText" />
<ChatMarkdown :text="processedText" />
</view>
<!-- 超过3行时显示...提示 -->
<view v-if="!finish" class="flex flex-row flex-items-center mt-8">
@@ -27,14 +27,12 @@
</template>
<script setup>
import { defineProps, computed, ref, watch, onBeforeUnmount } from "vue";
import { defineProps, computed, watch, onBeforeUnmount } from "vue";
import ChatMarkdown from "../../ChatMain/ChatMarkdown/index.vue";
import ChatLoading from "../../ChatMain/ChatLoading/index.vue";
import StreamManager from '@/utils/StreamManager.js';
const isOverflow = ref(false)
// 直接根据文字长度判断超过约100个字符认为会溢出约3行
const props = defineProps({
title: {
@@ -51,9 +49,6 @@ const props = defineProps({
},
});
// 用于强制重新渲染的key
const textKey = ref(0);
// 处理文本内容:按行截断以保证预览最多显示三行(更贴近视觉行数)
// 点击“查看详情”会跳转到完整页面(不受预览截断影响)。
const PREVIEW_LINES = 3;
@@ -78,19 +73,27 @@ const processedText = computed(() => {
return txt;
});
// 监听 text 变化:更新 textKey 并同步 isOverflow合并为单一响应函数避免冗余
watch(
() => props.text,
(newText, oldText) => {
const textStr = newText ? String(newText) : "";
const lines = textStr.split(/\r?\n/);
isOverflow.value = lines.length > PREVIEW_LINES || textStr.length > PREVIEW_CHAR_LIMIT;
if (newText !== oldText) {
textKey.value++;
}
},
{ immediate: true }
);
const isOverflow = computed(() => {
const textStr = props.text ? String(props.text) : "";
const lines = textStr.split(/\r?\n/);
return lines.length > PREVIEW_LINES || textStr.length > PREVIEW_CHAR_LIMIT;
});
let stopForwardWatcher = null;
let stopFinishWatcher = null;
const cleanupStreamWatchers = () => {
if (stopForwardWatcher) {
stopForwardWatcher();
stopForwardWatcher = null;
}
if (stopFinishWatcher) {
stopFinishWatcher();
stopFinishWatcher = null;
}
};
onBeforeUnmount(cleanupStreamWatchers);
const lookDetailAction = () => {
const message = props.text ? String(props.text) : "";
@@ -98,31 +101,26 @@ const lookDetailAction = () => {
const streamId = `stream_${Date.now()}_${Math.random().toString(36).slice(2,8)}`;
StreamManager.openStream(streamId, message, !!props.finish);
// 将当前组件后续 props.text/props.finish 的更新转发到 StreamManager
const stopForward = watch(
() => props.text,
(v) => {
StreamManager.updateStream(streamId, v ? String(v) : "", !!props.finish);
}
);
const stopFinishWatcher = watch(
() => props.finish,
(f) => {
StreamManager.updateStream(streamId, props.text ? String(props.text) : "", !!f);
if (f) {
stopForward();
stopFinishWatcher();
}
}
);
cleanupStreamWatchers();
// 清理:组件卸载时停止转发(若仍存在)
onBeforeUnmount(() => {
try {
stopForward && stopForward();
stopFinishWatcher && stopFinishWatcher();
} catch (e) {}
});
if (!props.finish) {
// 将当前组件后续 props.text/props.finish 的更新转发到 StreamManager
stopForwardWatcher = watch(
() => props.text,
(v) => {
StreamManager.updateStream(streamId, v ? String(v) : "", !!props.finish);
}
);
stopFinishWatcher = watch(
() => props.finish,
(f) => {
StreamManager.updateStream(streamId, props.text ? String(props.text) : "", !!f);
if (f) {
cleanupStreamWatchers();
}
}
);
}
// 传递 finished 参数,完成状态下不自动滚到底部
uni.navigateTo({ url: `/pages/ChatMain/ChatLongAnswer/index?streamId=${encodeURIComponent(streamId)}&finished=${props.finish ? '1' : '0'}` });
@@ -147,4 +145,4 @@ const lookDetailAction = () => {
.border-left-4 {
border-left: 4px solid $theme-color-500;
}
</style>
</style>