fix: 修复工具下拉框展开/折叠功能

- 修复工具下拉框无法打开的问题,添加正确的图标元素结构
   - 实现状态持久化机制,解决新内容产出时下拉框自动关闭的问题
   - 优化图标显示逻辑,使用 CSS transform 实现平滑旋转动画
   - 折叠状态图标向左旋转 90 度,展开状态图标向下
This commit is contained in:
Roe-xin
2025-12-31 09:57:48 +08:00
parent 5287d483d8
commit 2587018405

View File

@ -410,7 +410,7 @@ export function getMessageAreaStyles(): string {
display: block; display: block;
} }
.tool-segment-header.collapsed .tool-collapse-icon { .tool-segment-header.collapsed .tool-collapse-icon {
transform: rotate(0deg); transform: rotate(-90deg);
} }
.tool-segment-header:not(.collapsed) .tool-collapse-icon { .tool-segment-header:not(.collapsed) .tool-collapse-icon {
transform: rotate(0deg); transform: rotate(0deg);
@ -890,6 +890,9 @@ export function getMessageAreaScript(): string {
// 存储已回答问题的状态 // 存储已回答问题的状态
const answeredQuestions = new Map(); // askId -> answer const answeredQuestions = new Map(); // askId -> answer
// 存储工具展开/折叠状态
const toolCollapseStates = new Map(); // index -> isCollapsed
// 实时更新分段消息(按后端返回顺序) // 实时更新分段消息(按后端返回顺序)
function updateSegmentsRealtime(segments, isComplete) { function updateSegmentsRealtime(segments, isComplete) {
console.log('[WebView] updateSegmentsRealtime 被调用, segments:', segments, 'isComplete:', isComplete); console.log('[WebView] updateSegmentsRealtime 被调用, segments:', segments, 'isComplete:', isComplete);
@ -921,9 +924,19 @@ export function getMessageAreaScript(): string {
messagesEl.appendChild(currentSegmentedMessage); messagesEl.appendChild(currentSegmentedMessage);
} }
// 保存当前所有工具的展开/折叠状态
if (currentSegmentedMessage) {
const toolHeaders = currentSegmentedMessage.querySelectorAll('.tool-segment-header[data-collapsible="true"]');
toolHeaders.forEach((header, idx) => {
const isCollapsed = header.classList.contains('collapsed');
toolCollapseStates.set(idx, isCollapsed);
});
}
// 清空容器并重新渲染所有段落 // 清空容器并重新渲染所有段落
currentSegmentedMessage.innerHTML = ''; currentSegmentedMessage.innerHTML = '';
let toolIndex = 0; // 用于跟踪工具段落的索引
segments.forEach((segment, index) => { segments.forEach((segment, index) => {
const segmentDiv = document.createElement('div'); const segmentDiv = document.createElement('div');
segmentDiv.className = 'message-segment segment-' + segment.type; segmentDiv.className = 'message-segment segment-' + segment.type;
@ -942,13 +955,19 @@ export function getMessageAreaScript(): string {
// 检查工具结果是否过长(超过一行显示不下) // 检查工具结果是否过长(超过一行显示不下)
const shouldCollapse = toolResult && toolResult.length > 60; const shouldCollapse = toolResult && toolResult.length > 60;
// 恢复之前保存的展开/折叠状态
const savedState = toolCollapseStates.get(toolIndex);
const isCollapsed = savedState !== undefined ? savedState : shouldCollapse;
const currentToolIndex = toolIndex;
toolIndex++; // 递增工具索引
segmentDiv.innerHTML = \` segmentDiv.innerHTML = \`
<div class="tool-segment-header\${shouldCollapse ? ' collapsed' : ''}" data-collapsible="\${shouldCollapse}"> <div class="tool-segment-header\${isCollapsed ? ' collapsed' : ''}" data-collapsible="\${shouldCollapse}" data-tool-index="\${currentToolIndex}">
\${shouldCollapse ? collapseIconSvg : getToolIcon(segment.toolName)} \${shouldCollapse ? \`<span class="tool-collapse-icon">\${collapseIconSvg}</span>\` : getToolIcon(segment.toolName)}
<span class="tool-segment-name">\${getToolDisplayName(segment.toolName) || '工具'}</span> <span class="tool-segment-name">\${getToolDisplayName(segment.toolName) || '工具'}</span>
\${toolResult && !shouldCollapse ? \`<span class="tool-segment-result">\${toolResult}</span>\` : ''} \${toolResult && !shouldCollapse ? \`<span class="tool-segment-result">\${toolResult}</span>\` : ''}
</div> </div>
\${shouldCollapse ? \`<div class="tool-segment-content collapsed"><span class="tool-segment-result" style="display:block;white-space:pre-wrap;max-width:100%;margin-top:8px;margin-left:18px;">\${toolResult}</span></div>\` : ''} \${shouldCollapse ? \`<div class="tool-segment-content\${isCollapsed ? ' collapsed' : ''}" style="max-height:\${isCollapsed ? '0' : 'none'}"><span class="tool-segment-result" style="display:block;white-space:pre-wrap;max-width:100%;margin-top:8px;margin-left:18px;">\${toolResult}</span></div>\` : ''}
\`; \`;
// 如果是仿真工具且成功完成,尝试添加波形预览 // 如果是仿真工具且成功完成,尝试添加波形预览
@ -974,27 +993,24 @@ export function getMessageAreaScript(): string {
setTimeout(() => { setTimeout(() => {
const header = segmentDiv.querySelector('.tool-segment-header'); const header = segmentDiv.querySelector('.tool-segment-header');
const content = segmentDiv.querySelector('.tool-segment-content'); const content = segmentDiv.querySelector('.tool-segment-content');
const iconCollapsed = segmentDiv.querySelector('.icon-collapsed');
const iconExpanded = segmentDiv.querySelector('.icon-expanded');
if (header && content) { if (header && content) {
header.addEventListener('click', function() { header.addEventListener('click', function() {
const isCollapsed = header.classList.contains('collapsed'); const isCollapsed = header.classList.contains('collapsed');
const toolIdx = parseInt(header.getAttribute('data-tool-index') || '0');
if (isCollapsed) { if (isCollapsed) {
// 展开 // 展开
header.classList.remove('collapsed'); header.classList.remove('collapsed');
content.classList.remove('collapsed'); content.classList.remove('collapsed');
content.style.maxHeight = content.scrollHeight + 'px'; content.style.maxHeight = content.scrollHeight + 'px';
if (iconCollapsed) iconCollapsed.style.display = 'none'; toolCollapseStates.set(toolIdx, false);
if (iconExpanded) iconExpanded.style.display = 'block';
} else { } else {
// 折叠 // 折叠
header.classList.add('collapsed'); header.classList.add('collapsed');
content.classList.add('collapsed'); content.classList.add('collapsed');
content.style.maxHeight = '0'; content.style.maxHeight = '0';
if (iconCollapsed) iconCollapsed.style.display = 'block'; toolCollapseStates.set(toolIdx, true);
if (iconExpanded) iconExpanded.style.display = 'none';
} }
}); });
} }
@ -1149,7 +1165,7 @@ export function getMessageAreaScript(): string {
segmentDiv.innerHTML = \` segmentDiv.innerHTML = \`
<div class="tool-segment-header\${shouldCollapse ? ' collapsed' : ''}" data-collapsible="\${shouldCollapse}"> <div class="tool-segment-header\${shouldCollapse ? ' collapsed' : ''}" data-collapsible="\${shouldCollapse}">
\${shouldCollapse ? collapseIconSvg : getToolIcon(segment.toolName)} \${shouldCollapse ? \`<span class="icon-collapsed" style="display:block;width:16px;height:16px;flex-shrink:0;">\${collapseIconSvg}</span><span class="icon-expanded" style="display:none;width:16px;height:16px;flex-shrink:0;">\${collapseIconSvg}</span>\` : getToolIcon(segment.toolName)}
<span class="tool-segment-name">\${getToolDisplayName(segment.toolName) || '工具'}</span> <span class="tool-segment-name">\${getToolDisplayName(segment.toolName) || '工具'}</span>
\${toolResult && !shouldCollapse ? \`<span class="tool-segment-result">\${toolResult}</span>\` : ''} \${toolResult && !shouldCollapse ? \`<span class="tool-segment-result">\${toolResult}</span>\` : ''}
</div> </div>
@ -1179,27 +1195,24 @@ export function getMessageAreaScript(): string {
setTimeout(() => { setTimeout(() => {
const header = segmentDiv.querySelector('.tool-segment-header'); const header = segmentDiv.querySelector('.tool-segment-header');
const content = segmentDiv.querySelector('.tool-segment-content'); const content = segmentDiv.querySelector('.tool-segment-content');
const iconCollapsed = segmentDiv.querySelector('.icon-collapsed');
const iconExpanded = segmentDiv.querySelector('.icon-expanded');
if (header && content) { if (header && content) {
header.addEventListener('click', function() { header.addEventListener('click', function() {
const isCollapsed = header.classList.contains('collapsed'); const isCollapsed = header.classList.contains('collapsed');
const toolIdx = parseInt(header.getAttribute('data-tool-index') || '0');
if (isCollapsed) { if (isCollapsed) {
// 展开 // 展开
header.classList.remove('collapsed'); header.classList.remove('collapsed');
content.classList.remove('collapsed'); content.classList.remove('collapsed');
content.style.maxHeight = content.scrollHeight + 'px'; content.style.maxHeight = content.scrollHeight + 'px';
if (iconCollapsed) iconCollapsed.style.display = 'none'; toolCollapseStates.set(toolIdx, false);
if (iconExpanded) iconExpanded.style.display = 'block';
} else { } else {
// 折叠 // 折叠
header.classList.add('collapsed'); header.classList.add('collapsed');
content.classList.add('collapsed'); content.classList.add('collapsed');
content.style.maxHeight = '0'; content.style.maxHeight = '0';
if (iconCollapsed) iconCollapsed.style.display = 'block'; toolCollapseStates.set(toolIdx, true);
if (iconExpanded) iconExpanded.style.display = 'none';
} }
}); });
} }