fix(滚动控制): 优化滚动逻辑并修复流式消息时的滚动问题
This commit is contained in:
parent
04b0f92c2e
commit
e51d0dccdd
@ -34,7 +34,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="header__center" @mouseenter="uiState.showRenameButton = true" @mouseleave="uiState.showRenameButton = false">
|
||||
<div @click="console.log(agentStore.currentThread)" class="center-title">
|
||||
<div @click="logConversationInfo" class="center-title">
|
||||
{{ agentStore.currentThread?.title }}
|
||||
</div>
|
||||
<div class="rename-button" v-if="currentChatId" :class="{ 'visible': uiState.showRenameButton }" @click="handleRenameChat">
|
||||
@ -234,6 +234,8 @@ const selectChat = async (chatId) => {
|
||||
if (!AgentValidator.validateAgentIdWithError(agentStore.selectedAgentId, '选择对话', handleValidationError)) return;
|
||||
agentStore.selectThread(chatId);
|
||||
await agentStore.fetchThreadMessages(chatId);
|
||||
await nextTick();
|
||||
scrollController.scrollToBottomStaticForce();
|
||||
};
|
||||
|
||||
const deleteChat = async (chatId) => {
|
||||
@ -262,7 +264,6 @@ const handleSendMessage = async () => {
|
||||
|
||||
userInput.value = '';
|
||||
// Enable auto scroll before sending message to ensure proper scrolling during streaming
|
||||
scrollController.enableAutoScroll();
|
||||
await nextTick();
|
||||
await scrollController.scrollToBottom(true);
|
||||
|
||||
@ -328,6 +329,27 @@ const toggleSidebar = () => {
|
||||
|
||||
const openAgentModal = () => emit('open-agent-modal');
|
||||
|
||||
// ==================== CONVERSATION INFO LOGGING ====================
|
||||
|
||||
const logConversationInfo = () => {
|
||||
console.log(agentStore.currentThread);
|
||||
|
||||
// 输出对话历史消息
|
||||
console.group('📜 对话历史消息');
|
||||
console.log('原始消息数组:', agentStore.currentThreadMessages);
|
||||
console.log('消息总数:', agentStore.currentThreadMessages.length);
|
||||
console.groupEnd();
|
||||
|
||||
// 输出流式对话状态
|
||||
if (agentStore.isStreaming || agentStore.onGoingConvMessages.length > 0) {
|
||||
console.log('进行中的消息:', agentStore.onGoingConvMessages);
|
||||
console.log('消息块:', agentStore.onGoingConv.msgChunks);
|
||||
console.groupEnd();
|
||||
}
|
||||
|
||||
console.groupEnd();
|
||||
};
|
||||
|
||||
// ==================== HELPER FUNCTIONS ====================
|
||||
|
||||
const getLastMessage = (conv) => {
|
||||
@ -375,14 +397,19 @@ const loadChatsList = async () => {
|
||||
|
||||
onMounted(async () => {
|
||||
await initAll();
|
||||
scrollController.enableAutoScroll();
|
||||
watch(() => agentStore.selectedAgentId, (newAgentId, oldAgentId) => {
|
||||
if (newAgentId && newAgentId !== oldAgentId) {
|
||||
initAll();
|
||||
}
|
||||
});
|
||||
|
||||
// 只监听streaming状态,用于流式消息的智能滚动
|
||||
watch(conversations, () => {
|
||||
scrollController.scrollToBottom();
|
||||
}, { deep: true });
|
||||
if (isProcessing.value) {
|
||||
scrollController.scrollToBottom();
|
||||
}
|
||||
}, { deep: true, flush: 'post' });
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
@ -546,6 +546,19 @@ const toggleToolCall = (toolCallId) => {
|
||||
color: var(--main-700);
|
||||
}
|
||||
|
||||
.md-editor-code {
|
||||
border: var(--gray-50);
|
||||
border-radius: 8px;
|
||||
|
||||
.md-editor-code-head {
|
||||
background-color: var(--gray-50);
|
||||
|
||||
.md-editor-collapse-tips {
|
||||
color: var(--gray-400);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
code {
|
||||
font-size: 13px;
|
||||
font-family: 'Menlo', 'Monaco', 'Consolas', 'PingFang SC', 'Noto Sans SC', 'Microsoft YaHei', 'Hiragino Sans GB', 'Source Han Sans CN', 'Courier New', monospace;
|
||||
@ -553,7 +566,7 @@ const toggleToolCall = (toolCallId) => {
|
||||
letter-spacing: 0.025em;
|
||||
tab-size: 4;
|
||||
-moz-tab-size: 4;
|
||||
background-color: var(--gray-100);
|
||||
background-color: var(--gray-25);
|
||||
}
|
||||
|
||||
p:last-child {
|
||||
|
||||
@ -241,7 +241,7 @@ watch(inputValue, () => {
|
||||
|
||||
// Wait for component to mount before setting up onStartTyping
|
||||
onMounted(() => {
|
||||
console.log('Component mounted');
|
||||
// console.log('Component mounted');
|
||||
checkOptionsLeft();
|
||||
nextTick(() => {
|
||||
if (inputRef.value) {
|
||||
|
||||
@ -8,14 +8,15 @@ export class ScrollController {
|
||||
this.containerSelector = containerSelector;
|
||||
this.options = {
|
||||
threshold: 100,
|
||||
scrollDelay: 150,
|
||||
retryDelays: [50, 150, 300],
|
||||
scrollDelay: 100,
|
||||
retryDelays: [50, 150],
|
||||
...options
|
||||
};
|
||||
|
||||
|
||||
this.scrollTimer = null;
|
||||
this.isUserScrolling = false;
|
||||
this.shouldAutoScroll = true;
|
||||
this.isProgrammaticScroll = false;
|
||||
|
||||
// Bind the context of 'this' for the event handler
|
||||
this.handleScroll = this.handleScroll.bind(this);
|
||||
@ -49,12 +50,17 @@ export class ScrollController {
|
||||
clearTimeout(this.scrollTimer);
|
||||
}
|
||||
|
||||
// 如果是程序性滚动,忽略此次事件
|
||||
if (this.isProgrammaticScroll) {
|
||||
this.isProgrammaticScroll = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// 标记用户正在滚动
|
||||
this.isUserScrolling = true;
|
||||
|
||||
// 检查是否在底部
|
||||
const atBottom = this.isAtBottom();
|
||||
this.shouldAutoScroll = atBottom;
|
||||
this.shouldAutoScroll = this.isAtBottom();
|
||||
|
||||
// 滚动结束后一段时间重置用户滚动状态
|
||||
this.scrollTimer = setTimeout(() => {
|
||||
@ -75,9 +81,12 @@ export class ScrollController {
|
||||
const container = this.getContainer();
|
||||
if (!container) return;
|
||||
|
||||
const scrollOptions = {
|
||||
top: container.scrollHeight,
|
||||
behavior: 'smooth'
|
||||
// 标记为程序性滚动
|
||||
this.isProgrammaticScroll = true;
|
||||
|
||||
const scrollOptions = {
|
||||
top: container.scrollHeight,
|
||||
behavior: 'smooth'
|
||||
};
|
||||
|
||||
// 立即滚动
|
||||
@ -87,16 +96,32 @@ export class ScrollController {
|
||||
this.options.retryDelays.forEach((delay, index) => {
|
||||
setTimeout(() => {
|
||||
if (force || this.shouldAutoScroll) {
|
||||
this.isProgrammaticScroll = true;
|
||||
const behavior = index === this.options.retryDelays.length - 1 ? 'auto' : 'smooth';
|
||||
container.scrollTo({
|
||||
top: container.scrollHeight,
|
||||
behavior
|
||||
container.scrollTo({
|
||||
top: container.scrollHeight,
|
||||
behavior
|
||||
});
|
||||
}
|
||||
}, delay);
|
||||
});
|
||||
}
|
||||
|
||||
async scrollToBottomStaticForce() {
|
||||
const container = this.getContainer();
|
||||
if (!container) return;
|
||||
|
||||
// 标记为程序性滚动
|
||||
this.isProgrammaticScroll = true;
|
||||
|
||||
const scrollOptions = {
|
||||
top: container.scrollHeight,
|
||||
behavior: 'auto'
|
||||
};
|
||||
|
||||
container.scrollTo(scrollOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* 启用自动滚动
|
||||
*/
|
||||
@ -139,6 +164,7 @@ export class ScrollController {
|
||||
this.cleanup();
|
||||
this.isUserScrolling = false;
|
||||
this.shouldAutoScroll = true;
|
||||
this.isProgrammaticScroll = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user