/** * Dashboard页面 JavaScript - 增强动效版 */ // DOM加载完成后初始化 document.addEventListener('DOMContentLoaded', function() { initializeDashboard(); loadVoiceStatus(); bindEvents(); }); /** * 初始化Dashboard - 增强版 */ function initializeDashboard() { // 添加页面加载动画类 document.body.classList.add('page-loading'); // 为所有主要元素添加渐入动画类 setTimeout(() => { document.querySelectorAll('.welcome-card-kid, .scenario-card-kid, .voice-clone-card, .quick-action-card-kid, .achievement-card').forEach((el, index) => { el.classList.add('fade-in-up'); el.style.animationDelay = `${index * 0.1}s`; }); }, 100); // 移除加载状态 setTimeout(() => { document.body.classList.remove('page-loading'); }, 2000); // 添加页面加载动画 animateCards(); // 初始化成就数据 animateAchievements(); } /** * 绑定事件 */ function bindEvents() { // 场景卡片点击事件 document.querySelectorAll('[data-scenario]').forEach(btn => { btn.addEventListener('click', function() { const scenarioId = this.getAttribute('data-scenario'); handleScenarioClick(scenarioId); }); }); // 快速测试按钮 const quickTestBtn = document.getElementById('quick-test-btn'); if (quickTestBtn) { quickTestBtn.addEventListener('click', handleQuickTest); } } /** * 卡片加载动画 */ function animateCards() { const cards = document.querySelectorAll('.scenario-card-kid, .quick-action-card-kid, .achievement-card'); cards.forEach((card, index) => { card.style.opacity = '0'; card.style.transform = 'translateY(30px)'; setTimeout(() => { card.style.transition = 'all 0.5s ease'; card.style.opacity = '1'; card.style.transform = 'translateY(0)'; }, index * 100); }); } /** * 成就数据动画 */ function animateAchievements() { const achievements = [ { selector: '.time-card .achievement-number', target: 0, suffix: '' }, { selector: '.conversation-card .achievement-number', target: 0, suffix: '' }, { selector: '.star-card .achievement-number', target: 0, suffix: '' }, { selector: '.medal-card .achievement-number', target: 0, suffix: '' } ]; achievements.forEach((achievement, index) => { setTimeout(() => { animateNumber(achievement.selector, 0, achievement.target, 1000, achievement.suffix); }, index * 200); }); } /** * 数字动画 */ function animateNumber(selector, start, end, duration, suffix = '') { const element = document.querySelector(selector); if (!element) return; const range = end - start; const minTimer = 50; const stepTime = Math.abs(Math.floor(duration / range)); const timer = stepTime < minTimer ? minTimer : stepTime; const startTime = new Date().getTime(); const endTime = startTime + duration; function run() { const now = new Date().getTime(); const remaining = Math.max((endTime - now) / duration, 0); const value = Math.round(end - (remaining * range)); element.textContent = value + suffix; if (value === end) { return; } setTimeout(run, timer); } run(); } /** * 加载语音状态 */ async function loadVoiceStatus() { try { const response = await fetch('/voice-clone/api/voice-clone/status'); const result = await response.json(); updateVoiceStatusDisplay(result); } catch (error) { console.error('加载语音状态失败:', error); updateVoiceStatusDisplay({ success: false, has_sample: false, message: '无法加载语音状态' }); } } /** * 更新语音状态显示 */ function updateVoiceStatusDisplay(result) { const display = document.getElementById('voice-status-display'); const quickTestBtn = document.getElementById('quick-test-btn'); if (result.has_sample && result.success) { display.innerHTML = `

你的专属声音已就绪!

AI已经学会了你的声音:「${result.recognized_text}」

录制时间:${result.upload_time} `; if (quickTestBtn) { quickTestBtn.disabled = false; } // 激活语音波浪动画 document.querySelectorAll('.voice-wave').forEach((wave, index) => { wave.style.animationDelay = `${index * 0.2}s`; wave.style.animationPlayState = 'running'; }); } else { display.innerHTML = `

还没有录制语音样本

录制你的专属声音,让AI学会模仿你说话!

`; if (quickTestBtn) { quickTestBtn.disabled = true; } } } /** * 处理场景点击 */ function handleScenarioClick(scenarioId) { // 显示动画效果 showComingSoonAnimation(); } /** * 快速测试语音克隆 */ async function handleQuickTest() { const btn = document.getElementById('quick-test-btn'); const originalText = btn.innerHTML; btn.disabled = true; btn.innerHTML = '测试中...'; try { const response = await fetch('/voice-clone/api/voice-clone/generate', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ text: '你好,这是我的专属声音测试!' }) }); const result = await response.json(); if (result.success) { showSuccess('快速测试成功!播放你的专属声音'); // 播放生成的音频 const audio = new Audio(); const filename = result.audio_url.split('/').pop(); audio.src = `/voice-test/download-audio/${filename}`; audio.play().catch(e => console.error('播放失败:', e)); } else { showError(result.message || '测试失败'); } } catch (error) { showError('测试失败,请检查网络连接'); console.error('快速测试失败:', error); } finally { btn.disabled = false; btn.innerHTML = originalText; } } /** * 显示即将上线动画 */ function showComingSoonAnimation() { const modal = document.createElement('div'); modal.className = 'modal fade'; modal.innerHTML = ` `; document.body.appendChild(modal); const bsModal = new bootstrap.Modal(modal); bsModal.show(); // 自动清理 modal.addEventListener('hidden.bs.modal', () => { document.body.removeChild(modal); }); } /** * 显示成功消息 */ function showSuccess(message) { showToast(message, 'success'); } /** * 显示错误消息 */ function showError(message) { showToast(message, 'danger'); } /** * 显示Toast消息 */ function showToast(message, type = 'info') { const colors = { 'success': 'bg-success', 'danger': 'bg-danger', 'warning': 'bg-warning', 'info': 'bg-info' }; const toast = document.createElement('div'); toast.className = `toast align-items-center text-white ${colors[type]} border-0 position-fixed top-0 end-0 m-3`; toast.style.zIndex = '9999'; toast.innerHTML = `
${message}
`; document.body.appendChild(toast); const bsToast = new bootstrap.Toast(toast); bsToast.show(); setTimeout(() => { if (toast.parentNode) { toast.parentNode.removeChild(toast); } }, 3000); } // 添加鼠标交互效果 document.addEventListener('mousemove', function(e) { // 鼠标跟随效果(轻微) const shapes = document.querySelectorAll('.shape'); shapes.forEach((shape, index) => { const speed = (index + 1) * 0.01; const x = e.clientX * speed; const y = e.clientY * speed; shape.style.transform += ` translate(${x}px, ${y}px)`; }); });