agent-Specialization/static/demo/minimal-mode/script.js

334 lines
9.8 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 全局状态
let currentStep = 0;
let isExpanded = false;
let demoRunning = false;
// 步骤配置
const steps = [
{
type: 'thinking',
icon: 'brain',
summary: '正在思考如何搜索...',
duration: 2000
},
{
type: 'tool',
icon: 'search',
summary: '搜索AI技术发展趋势 2026',
duration: 2500
},
{
type: 'thinking',
icon: 'brain',
summary: '搜索结果显示了一些有价值的信息。现在我需要执行...',
duration: 2000
},
{
type: 'tool',
icon: 'terminal',
summary: '执行命令:获取网页内容并分析',
duration: 2500
},
{
type: 'thinking',
icon: 'brain',
summary: '很好,我已经收集到了足够的信息。现在我可以整理...',
duration: 2000
}
];
// 开始演示
async function startDemo() {
if (demoRunning) return;
demoRunning = true;
resetDemo();
// 显示等待动画
const placeholder = document.getElementById('generatingPlaceholder');
placeholder.style.display = 'flex';
await sleep(1500);
// 隐藏等待动画,显示摘要行
placeholder.style.display = 'none';
const summaryLine = document.getElementById('summaryLine');
summaryLine.style.display = 'flex';
// 执行每个步骤
for (let i = 0; i < steps.length; i++) {
currentStep = i;
await executeStep(i);
}
// 完成后显示最终输出
await sleep(1000);
summaryLine.classList.add('completed');
// 如果展开状态,显示最后一步
if (isExpanded) {
await showDetailStep(currentStep, true);
}
// 淡化摘要并显示第一个步骤(极快)
await fadeAndSwitch(summaryLine, steps[0].summary, true);
await sleep(800);
// 显示最终输出
const textOutput = document.getElementById('textOutput');
textOutput.style.display = 'block';
setTimeout(() => {
textOutput.classList.add('show');
}, 50);
demoRunning = false;
}
// 执行单个步骤
async function executeStep(stepIndex) {
const step = steps[stepIndex];
// 更新摘要文本
updateSummary(step);
// 如果展开状态,显示详细内容
if (isExpanded) {
await showDetailStep(stepIndex);
}
await sleep(step.duration);
}
// 更新摘要
function updateSummary(step) {
const summaryText = document.getElementById('summaryText');
const summaryIcon = document.querySelector('.summary-icon');
// 更新图标
summaryIcon.innerHTML = getIconSVG(step.icon);
// 更新文本
summaryText.textContent = step.summary;
}
// 显示详细步骤
async function showDetailStep(stepIndex, isNewStep = false) {
const timelineItem = document.querySelector(`.timeline-item[data-step="${stepIndex}"]`);
const contentItem = document.querySelector(`.content-item[data-step="${stepIndex}"]`);
if (!timelineItem || !contentItem) return;
// 添加动画类
if (isNewStep) {
timelineItem.classList.add('animated');
contentItem.classList.add('animated');
} else {
timelineItem.classList.add('instant');
contentItem.classList.add('instant');
}
// 显示时间线项和内容
timelineItem.style.display = 'flex';
contentItem.style.display = 'block';
// 计算并设置竖线高度
await sleep(isNewStep ? 100 : 10);
updateLineHeight(stepIndex);
await sleep(isNewStep ? 200 : 10);
}
// 更新竖线高度
function updateLineHeight(stepIndex) {
const timelineItem = document.querySelector(`.timeline-item[data-step="${stepIndex}"]`);
const contentItem = document.querySelector(`.content-item[data-step="${stepIndex}"]`);
if (!timelineItem || !contentItem) return;
const line = timelineItem.querySelector('.timeline-line');
if (!line) return;
// 获取内容的实际高度
const contentHeight = contentItem.offsetHeight;
// 对于第一个步骤(没有图标),竖线从顶部开始
if (stepIndex === 0) {
const gap = 20; // 到下一个步骤的间距
const lineHeight = contentHeight + gap;
line.style.height = `${lineHeight}px`;
return;
}
// 对于其他步骤,计算竖线高度
const iconHeight = 20; // 图标高度
const gap = 20; // 间距
// 如果是最后一个步骤,不需要竖线
if (stepIndex >= steps.length - 1) {
line.style.height = '0';
return;
}
// 计算竖线应该的高度:内容高度 + 间距 - 图标高度
const lineHeight = Math.max(contentHeight + gap - iconHeight, 40);
line.style.height = `${lineHeight}px`;
}
// 切换展开/折叠
async function toggleSummary() {
const summaryLine = document.getElementById('summaryLine');
const detailView = document.getElementById('detailView');
if (summaryLine.style.display === 'none') return;
isExpanded = !isExpanded;
if (isExpanded) {
// 展开:极快淡化当前摘要,显示第一个步骤的内容
summaryLine.classList.add('expanded');
await fadeAndSwitch(summaryLine, steps[0].summary, true);
// 显示详细视图(快速)
detailView.style.display = 'block';
setTimeout(() => {
detailView.classList.add('show');
}, 10);
// 已完成的步骤快速显示,当前步骤慢速动画
for (let i = 0; i <= currentStep; i++) {
const isCurrentStep = i === currentStep && demoRunning;
await showDetailStep(i, isCurrentStep);
if (isCurrentStep) {
await sleep(400); // 只有新步骤才有较慢的动画
} else {
await sleep(50); // 已有内容快速出现
}
}
} else {
// 折叠:极快淡化第一个步骤,显示当前摘要
summaryLine.classList.remove('expanded');
await fadeAndSwitch(summaryLine, steps[currentStep].summary, true);
// 隐藏详细视图(快速)
detailView.classList.remove('show');
await sleep(150);
detailView.style.display = 'none';
// 重置所有步骤显示
document.querySelectorAll('.timeline-item').forEach(item => {
item.style.display = 'none';
item.classList.remove('instant', 'animated');
});
document.querySelectorAll('.content-item').forEach(item => {
item.style.display = 'none';
item.classList.remove('instant', 'animated');
});
}
}
// 淡化并切换文本
async function fadeAndSwitch(element, newText, fast = false) {
const summaryText = element.querySelector('.summary-text');
const duration = fast ? 75 : 200;
// 淡出
element.style.opacity = '0.3';
await sleep(duration);
// 切换文本
summaryText.textContent = newText;
// 淡入
element.style.opacity = '1';
await sleep(duration);
}
// 展开思考内容
function expandThinking(stepIndex) {
const thinkingContent = document.getElementById(`thinkingContent${stepIndex}`);
const thinkingContentFull = document.getElementById(`thinkingContentFull${stepIndex}`);
thinkingContent.style.display = 'none';
thinkingContentFull.style.display = 'block';
// 重新计算并更新竖线高度
setTimeout(() => {
updateLineHeight(stepIndex);
}, 50);
}
// 收起思考内容
function collapseThinking(stepIndex) {
const thinkingContent = document.getElementById(`thinkingContent${stepIndex}`);
const thinkingContentFull = document.getElementById(`thinkingContentFull${stepIndex}`);
thinkingContent.style.display = 'block';
thinkingContentFull.style.display = 'none';
// 重新计算并更新竖线高度
setTimeout(() => {
updateLineHeight(stepIndex);
}, 50);
}
// 重置演示
function resetDemo() {
currentStep = 0;
isExpanded = false;
demoRunning = false;
// 隐藏所有元素
document.getElementById('generatingPlaceholder').style.display = 'none';
const summaryLine = document.getElementById('summaryLine');
summaryLine.style.display = 'none';
summaryLine.classList.remove('completed', 'expanded');
summaryLine.style.opacity = '1';
document.getElementById('detailView').style.display = 'none';
document.getElementById('detailView').classList.remove('show');
document.getElementById('textOutput').style.display = 'none';
document.getElementById('textOutput').classList.remove('show');
// 重置所有步骤
document.querySelectorAll('.timeline-item').forEach(item => {
item.style.display = 'none';
item.classList.remove('instant', 'animated');
const line = item.querySelector('.timeline-line');
if (line) {
line.style.height = '0';
}
});
document.querySelectorAll('.content-item').forEach(item => {
item.style.display = 'none';
item.classList.remove('instant', 'animated');
});
// 重置思考内容
document.querySelectorAll('.thinking-content').forEach(item => {
item.style.display = 'block';
});
document.querySelectorAll('.thinking-content-full').forEach(item => {
item.style.display = 'none';
});
}
// 获取图标SVG
function getIconSVG(iconType) {
const icons = {
brain: '<path d="M12 2a10 10 0 1 0 10 10A10 10 0 0 0 12 2z"></path><path d="M12 6v6l4 2"></path>',
search: '<circle cx="11" cy="11" r="8"></circle><path d="m21 21-4.35-4.35"></path>',
terminal: '<polyline points="4 17 10 11 4 5"></polyline><line x1="12" y1="19" x2="20" y2="19"></line>'
};
return icons[iconType] || icons.brain;
}
// 工具函数:延迟
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// 点击摘要行切换展开/折叠
document.getElementById('summaryLine').addEventListener('click', toggleSummary);