334 lines
9.8 KiB
JavaScript
334 lines
9.8 KiB
JavaScript
// 全局状态
|
||
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);
|