fix(chat): 运行期间恢复旧滚动逻辑,堆叠块更多按钮也接入锚定

This commit is contained in:
JOJO 2026-06-17 16:25:02 +08:00
parent edb557bdd3
commit f43b5ea73b
2 changed files with 42 additions and 16 deletions

View File

@ -131,6 +131,7 @@
:format-search-topic="formatSearchTopic"
:format-search-time="formatSearchTime"
:format-search-domains="formatSearchDomains"
@more-toggle="handleStackedMoreToggle"
/>
<div
v-else-if="isActionVisible(group.action)"
@ -914,6 +915,7 @@ function attachBounceListener() {
const now = Date.now();
lastUserWheelUpTs = now;
stopScroll();
stopBlockExpansionAnchors();
emit('user-scroll-intent', {
ts: now,
delta: deltaY,
@ -977,6 +979,7 @@ function attachBounceListener() {
if (shouldTreatAsUserIntent) {
// stick
stopScroll();
stopBlockExpansionAnchors();
lastUserDownScrollTs = now;
emit('user-scroll-intent', {
ts: lastUserDownScrollTs,
@ -1078,14 +1081,6 @@ function escapeBlockSelector(value: string) {
return value.replace(/["\\]/g, '\\$&');
}
function elementLooksStreaming(el: HTMLElement) {
return (
el.classList.contains('processing') ||
el.classList.contains('running') ||
!!el.querySelector('.processing, .running, .thinking-animation')
);
}
const prevExpandedBlocks = ref(new Set<string>());
watch(
@ -1102,6 +1097,10 @@ watch(
prevExpandedBlocks.value = new Set(newSet);
if (changed.size === 0) return;
// stick-to-bottom
if (props.streamingMessage) return;
const container = scrollRef.value;
if (!container) return;
@ -1110,13 +1109,10 @@ watch(
`[data-block-id="${escapeBlockSelector(id)}"]`
) as HTMLElement | null;
if (el) {
const isExpanding = newSet.has(id);
const streaming = elementLooksStreaming(el);
anchorBlockElement(el, id, {
direction: 'auto',
duration: streaming ? 5000 : 260,
extendOnGrowth: streaming,
phase: isExpanding ? 'expand' : 'collapse'
duration: 260,
phase: newSet.has(id) ? 'expand' : 'collapse'
});
}
}
@ -1124,7 +1120,25 @@ watch(
{ flush: 'post' }
);
function handleStackedMoreToggle(payload: {
element: HTMLElement;
expanded: boolean;
stackKey: string;
}) {
//
if (props.streamingMessage) return;
anchorBlockElement(payload.element, `more-${payload.stackKey}`, {
direction: 'auto',
duration: 260,
phase: expanded ? 'expand' : 'collapse'
});
}
function handleMinimalGroupToggle(payload: { groupId: string; expanded: boolean }) {
//
if (props.streamingMessage) return;
const { groupId, expanded } = payload;
const container = scrollRef.value;
if (!container) return;
@ -1132,11 +1146,9 @@ function handleMinimalGroupToggle(payload: { groupId: string; expanded: boolean
`[data-group-id="${escapeBlockSelector(groupId)}"]`
) as HTMLElement | null;
if (el) {
const streaming = elementLooksStreaming(el);
anchorBlockElement(el, groupId, {
direction: 'auto',
duration: streaming ? 5000 : 300,
extendOnGrowth: streaming,
duration: 300,
phase: expanded ? 'expand' : 'collapse'
});
}

View File

@ -177,6 +177,16 @@ const props = defineProps<{
formatSearchDomains: (filters: Record<string, any>) => string;
}>();
const emit = defineEmits<{
(
event: 'more-toggle',
payload: { element: HTMLElement; expanded: boolean; stackKey: string }
): void;
}>();
let stackInstanceCounter = 0;
const stackKey = `stacked-${++stackInstanceCounter}`;
// personalization store
const personalizationStore = usePersonalizationStore();
@ -253,6 +263,10 @@ const isToolCompleted = (action: any) => action?.tool?.status === 'completed';
const toggleMore = () => {
showAll.value = !showAll.value;
scheduleMeasure();
const el = moreBlock.value;
if (el instanceof HTMLElement) {
emit('more-toggle', { element: el, expanded: showAll.value, stackKey });
}
};
const toggleBlock = (blockId: string) => {