feat: auto-scroll thinking block with per-block lock
This commit is contained in:
parent
e7a81f00e7
commit
05b404687a
@ -202,6 +202,8 @@ async function bootstrapApp() {
|
||||
|
||||
// 设置菜单状态
|
||||
settingsOpen: false,
|
||||
// 思考块滚动锁
|
||||
thinkingScrollLocks: new Map(),
|
||||
|
||||
// 工具控制菜单
|
||||
toolMenuOpen: false,
|
||||
@ -732,6 +734,7 @@ async function bootstrapApp() {
|
||||
this.autoScrollEnabled = true;
|
||||
this.userScrolling = false;
|
||||
this.scrollToBottom();
|
||||
this.thinkingScrollLocks.set(blockId, true);
|
||||
this.$forceUpdate();
|
||||
}
|
||||
});
|
||||
@ -747,8 +750,12 @@ async function bootstrapApp() {
|
||||
lastAction.content += data.content;
|
||||
}
|
||||
this.$forceUpdate();
|
||||
if (lastAction && lastAction.blockId) {
|
||||
this.$nextTick(() => this.scrollThinkingToBottom(lastAction.blockId));
|
||||
} else {
|
||||
this.conditionalScrollToBottom();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 思考结束
|
||||
@ -765,6 +772,7 @@ async function bootstrapApp() {
|
||||
this.expandedBlocks.delete(lastAction.blockId);
|
||||
this.$forceUpdate();
|
||||
}, 1000);
|
||||
this.$nextTick(() => this.scrollThinkingToBottom(lastAction.blockId));
|
||||
}
|
||||
}
|
||||
msg.streamingThinking = '';
|
||||
@ -1295,6 +1303,7 @@ async function bootstrapApp() {
|
||||
if (this.markdownCache) {
|
||||
this.markdownCache.clear();
|
||||
}
|
||||
this.thinkingScrollLocks.clear();
|
||||
|
||||
// 强制更新视图
|
||||
this.$forceUpdate();
|
||||
@ -3001,6 +3010,23 @@ async function bootstrapApp() {
|
||||
}
|
||||
},
|
||||
|
||||
scrollThinkingToBottom(blockId) {
|
||||
if (!this.thinkingScrollLocks.get(blockId)) return;
|
||||
const refName = `thinkingContent-${blockId}`;
|
||||
const elRef = this.$refs[refName];
|
||||
const el = Array.isArray(elRef) ? elRef[0] : elRef;
|
||||
if (el) {
|
||||
el.scrollTop = el.scrollHeight;
|
||||
}
|
||||
},
|
||||
|
||||
handleThinkingScroll(blockId, event) {
|
||||
const el = event.target;
|
||||
const threshold = 12;
|
||||
const atBottom = el.scrollHeight - el.scrollTop - el.clientHeight < threshold;
|
||||
this.thinkingScrollLocks.set(blockId, atBottom);
|
||||
},
|
||||
|
||||
// 面板调整方法
|
||||
startResize(panel, event) {
|
||||
this.isResizing = true;
|
||||
|
||||
@ -298,7 +298,10 @@
|
||||
<span class="status-text">{{ action.streaming ? '正在思考...' : '思考过程' }}</span>
|
||||
</div>
|
||||
<div class="collapsible-content">
|
||||
<div class="content-inner thinking-content">
|
||||
<div class="content-inner thinking-content"
|
||||
:ref="`thinkingContent-${index}-thinking-${actionIndex}`"
|
||||
@scroll="handleThinkingScroll(`${index}-thinking-${actionIndex}`, $event)"
|
||||
style="max-height: 240px; overflow-y: auto;">
|
||||
{{ action.content }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -239,6 +239,7 @@ async function bootstrapApp() {
|
||||
|
||||
// 设置菜单状态
|
||||
settingsOpen: false,
|
||||
thinkingScrollLocks: new Map(),
|
||||
|
||||
// 工具控制菜单
|
||||
toolMenuOpen: false,
|
||||
@ -1089,6 +1090,7 @@ async function bootstrapApp() {
|
||||
this.autoScrollEnabled = true;
|
||||
this.userScrolling = false;
|
||||
this.scrollToBottom();
|
||||
this.thinkingScrollLocks.set(blockId, true);
|
||||
this.$forceUpdate();
|
||||
}
|
||||
});
|
||||
@ -1104,8 +1106,12 @@ async function bootstrapApp() {
|
||||
lastAction.content += data.content;
|
||||
}
|
||||
this.$forceUpdate();
|
||||
if (lastAction && lastAction.blockId) {
|
||||
this.$nextTick(() => this.scrollThinkingToBottom(lastAction.blockId));
|
||||
} else {
|
||||
this.conditionalScrollToBottom();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 思考结束
|
||||
@ -1122,6 +1128,7 @@ async function bootstrapApp() {
|
||||
this.expandedBlocks.delete(lastAction.blockId);
|
||||
this.$forceUpdate();
|
||||
}, 1000);
|
||||
this.$nextTick(() => this.scrollThinkingToBottom(lastAction.blockId));
|
||||
}
|
||||
}
|
||||
msg.streamingThinking = '';
|
||||
@ -1645,6 +1652,7 @@ async function bootstrapApp() {
|
||||
if (this.markdownCache) {
|
||||
this.markdownCache.clear();
|
||||
}
|
||||
this.thinkingScrollLocks.clear();
|
||||
|
||||
// 强制更新视图
|
||||
this.$forceUpdate();
|
||||
@ -3204,6 +3212,23 @@ async function bootstrapApp() {
|
||||
}
|
||||
},
|
||||
|
||||
scrollThinkingToBottom(blockId) {
|
||||
if (!this.thinkingScrollLocks.get(blockId)) return;
|
||||
const refName = `thinkingContent-${blockId}`;
|
||||
const elRef = this.$refs[refName];
|
||||
const el = Array.isArray(elRef) ? elRef[0] : elRef;
|
||||
if (el) {
|
||||
el.scrollTop = el.scrollHeight;
|
||||
}
|
||||
},
|
||||
|
||||
handleThinkingScroll(blockId, event) {
|
||||
const el = event.target;
|
||||
const threshold = 12;
|
||||
const atBottom = el.scrollHeight - el.scrollTop - el.clientHeight < threshold;
|
||||
this.thinkingScrollLocks.set(blockId, atBottom);
|
||||
},
|
||||
|
||||
// 面板调整方法
|
||||
startResize(panel, event) {
|
||||
this.isResizing = true;
|
||||
|
||||
@ -270,7 +270,10 @@
|
||||
<span class="status-text">{{ action.streaming ? '正在思考...' : '思考过程' }}</span>
|
||||
</div>
|
||||
<div class="collapsible-content">
|
||||
<div class="content-inner thinking-content">
|
||||
<div class="content-inner thinking-content"
|
||||
:ref="`thinkingContent-${index}-thinking-${actionIndex}`"
|
||||
@scroll="handleThinkingScroll(`${index}-thinking-${actionIndex}`, $event)"
|
||||
style="max-height: 240px; overflow-y: auto;">
|
||||
{{ action.content }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user