feat: 调整

This commit is contained in:
2026-04-17 17:07:05 +08:00
parent d666dce813
commit f70920a25c
2 changed files with 47 additions and 20 deletions

View File

@@ -124,7 +124,8 @@ const lookDetailAction = () => {
} catch (e) {}
});
uni.navigateTo({ url: `/pages/long-answer/index?streamId=${encodeURIComponent(streamId)}` });
// 传递 finished 参数,完成状态下不自动滚到底部
uni.navigateTo({ url: `/pages/long-answer/index?streamId=${encodeURIComponent(streamId)}&finished=${props.finish ? '1' : '0'}` });
}
</script>

View File

@@ -49,14 +49,23 @@ const SCROLL_THRESHOLD = 150; // px
const userInteracting = ref(false);
let interactionTimer = null;
/** 是否已完成(从 URL 参数判断),完成状态下不初始初自动滚到底部 */
let isFinishedOnInit = false;
/** ✅ 防抖 */
let scrollTimer = null;
const measureScrollViewHeight = () => {
try {
const sys = uni.getSystemInfoSync() || {};
// 使用窗口高度作为 scroll-view 可视高度的近似,兼容小程序环境
scrollViewHeight.value = sys.windowHeight || 0;
// 使用 uni.createSelectorQuery 获取 scroll-view 的准确高度
uni.createSelectorQuery()
.select(".chat-scroll")
.boundingClientRect((rect) => {
if (rect && rect.height) {
scrollViewHeight.value = rect.height;
}
})
.exec();
} catch (e) { }
}
@@ -69,31 +78,36 @@ const computeTitle = (text = "") => {
const onScroll = (e) => {
try {
const { scrollTop = 0, scrollHeight = 0 } = e.detail || {};
// 标记为用户主动滚动,短时内不触发自动滚动
userInteracting.value = true;
clearTimeout(interactionTimer);
interactionTimer = setTimeout(() => (userInteracting.value = false), 1200);
// 更新距离底部的判断(使用 windowHeight 作为近似
const distanceToBottom = scrollHeight - (scrollTop + (scrollViewHeight.value || uni.getSystemInfoSync().windowHeight || 0));
isNearBottom.value = distanceToBottom <= SCROLL_THRESHOLD;
// 计算距离底部的距离(使用准确的 scroll-view 高度)
const viewHeight = scrollViewHeight.value;
const distanceToBottom = scrollHeight - scrollTop - viewHeight;
// 判断是否在底部附近(允许 SCROLL_THRESHOLD 的误差范围
// 注意:只更新 isNearBottom不在滚动时强制改变 userInteracting
const atBottom = distanceToBottom <= SCROLL_THRESHOLD;
isNearBottom.value = atBottom;
} catch (e) { }
}
const onTouchStart = () => {
// 触摸开始时,立即标记为用户交互状态
userInteracting.value = true;
clearTimeout(interactionTimer);
}
const onTouchEnd = () => {
// 触摸结束后延迟一段时间再取消交互状态
// 这样即使用户快速滚动,也不会被中途打断
clearTimeout(interactionTimer);
interactionTimer = setTimeout(() => {
userInteracting.value = false;
}, 800);
}, 600);
}
const scrollToBottom = () => {
if (scrollTimer) return;
if (isFinishedOnInit) return;
scrollTimer = setTimeout(() => {
// ❗关键:强制触发滚动(小程序必须这样)
@@ -118,7 +132,17 @@ const scrollToBottom = () => {
}, 100);
}
onLoad(({ message = "", streamId = "" }) => {
onLoad(({ message = "", streamId = "", finished = "0" }) => {
// 记录初始完成状态
isFinishedOnInit = finished === "1";
console.log("LongAnswer onLoad with params:", { message, streamId, finished });
// 初次测量 scroll-view 高度
nextTick(() => {
measureScrollViewHeight();
});
if (streamId) {
// ✅ 流式数据
unsubscribe = StreamManager.subscribe(
@@ -128,10 +152,15 @@ onLoad(({ message = "", streamId = "" }) => {
title.value = computeTitle(answerText.value);
nextTick(() => {
// 仅在用户处于接近底部时自动滚动,避免每次流式更新都打断用户阅读
// 每次接收数据都重新测量高度content size 可能变化,比如加载图)
measureScrollViewHeight();
// 流式完成时强制滚动到底部
if (finished) {
scrollToBottom();
} else if (isNearBottom.value) {
}
// 流式中的数据更新:只有在用户未交互且接近底部时才自动滚动
else if (!userInteracting.value && isNearBottom.value) {
scrollToBottom();
}
});
@@ -143,13 +172,10 @@ onLoad(({ message = "", streamId = "" }) => {
title.value = computeTitle(answerText.value);
nextTick(() => {
// 初始非流式情况仍保持自动滚动
// 只有在初始化为非完成状态时才自动滚到底部
scrollToBottom();
});
}
// 初次测量 scroll-view 高度
nextTick(() => measureScrollViewHeight());
});
onUnload(() => {