feat: 优化展会演示前端界面和功能

主要更新:
- 重新设计首页UI,采用现代黑色科技风格
- 修复结果弹窗按钮显示问题,固定在底部
- 添加Duoduo Agent Logo和三击调试功能
- 添加右下角浮动查看结果按钮
- 优化功能卡片布局和对齐
- 简化按钮文字为'开始'
- 移除首页演示案例内容
- 创建Windows启动脚本start_cn.bat

技术改进:
- 使用深色主题配色方案
- 添加网格背景和动态光效
- 优化组件动画效果
- 改进响应式布局

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Yep_Q
2025-09-09 19:18:37 +08:00
parent 7edfb28ddd
commit 3e7d0f39f8
4 changed files with 647 additions and 67 deletions

View File

@@ -0,0 +1,500 @@
@echo off
REM Save original codepage
for /f "tokens=2 delims=:" %%a in ('chcp') do set OLDCP=%%a
chcp 65001 >nul 2>&1
REM n8n Chinese Version Quick Start Script (Windows)
REM Author: xiaoqi
REM Last Update: 2025-09-09
REM Compatibility: Windows 7/8/10/11
setlocal enabledelayedexpansion
REM Display banner
:show_banner
echo ======================================
echo n8n Chinese Version Launcher
echo Version: n8n-1.109.2 with CN
echo Maintainer: xiaoqi
echo ======================================
echo.
REM Parse command line arguments
set "DEV_MODE="
set "FORCE_BUILD="
set "CHECK_ONLY="
set "SKIP_DEPS="
set "USE_NPM="
set "CUSTOM_PORT=5678"
:parse_args
if "%~1"=="" goto main_execution
if /I "%~1"=="-h" goto show_help
if /I "%~1"=="--help" goto show_help
if /I "%~1"=="-d" (
set "DEV_MODE=true"
shift
goto parse_args
)
if /I "%~1"=="--dev" (
set "DEV_MODE=true"
shift
goto parse_args
)
if /I "%~1"=="-b" (
set "FORCE_BUILD=true"
shift
goto parse_args
)
if /I "%~1"=="--build" (
set "FORCE_BUILD=true"
shift
goto parse_args
)
if /I "%~1"=="-c" (
set "CHECK_ONLY=true"
shift
goto parse_args
)
if /I "%~1"=="--check" (
set "CHECK_ONLY=true"
shift
goto parse_args
)
if /I "%~1"=="--skip-deps" (
set "SKIP_DEPS=true"
shift
goto parse_args
)
if /I "%~1"=="--npm" (
set "USE_NPM=true"
shift
goto parse_args
)
if /I "%~1"=="-p" (
set "CUSTOM_PORT=%~2"
shift
shift
goto parse_args
)
if /I "%~1"=="--port" (
set "CUSTOM_PORT=%~2"
shift
shift
goto parse_args
)
echo [ERROR] Unknown option: %~1
goto show_help
:main_execution
REM Check OS version
call :check_os_version
REM Check and change to correct directory
call :check_and_change_directory
if errorlevel 1 goto error_exit
REM Check dependencies
if not defined SKIP_DEPS (
echo [INFO] Checking system dependencies...
call :check_dependencies
if errorlevel 1 goto error_exit
)
REM Check port
call :check_port
if errorlevel 1 goto error_exit
REM Stop existing processes
call :stop_existing
REM Setup environment
call :setup_environment
REM Check only mode
if defined CHECK_ONLY (
echo [SUCCESS] System check completed
goto end
)
REM Install dependencies if needed
if not exist "node_modules\" (
echo [INFO] Installing dependencies...
if defined USE_NPM (
call :install_with_npm
) else (
call :install_with_pnpm
)
if errorlevel 1 goto error_exit
)
REM Check and install run-script-os
if not exist "node_modules\run-script-os" (
echo [FIX] Installing run-script-os...
call npm install run-script-os
)
REM Build or check build
if defined FORCE_BUILD (
echo [INFO] Force rebuilding project...
call :build_project
if errorlevel 1 goto error_exit
) else (
call :check_build
if errorlevel 1 goto error_exit
)
REM Dev mode or normal start
if defined DEV_MODE (
echo [INFO] Starting n8n in development mode...
echo [WARNING] Dev mode takes longer to start...
if defined USE_NPM (
call npm run dev
) else (
call pnpm dev
)
) else (
call :start_n8n
)
goto end
REM ========== Functions ==========
:check_os_version
ver | findstr /i "5\.1\." >nul
if not errorlevel 1 (
echo [WARNING] Windows XP detected
)
ver | findstr /i "6\.0\." >nul
if not errorlevel 1 (
echo [INFO] Windows Vista detected
)
ver | findstr /i "6\.1\." >nul
if not errorlevel 1 (
echo [INFO] Windows 7 detected
)
ver | findstr /i "6\.2\." >nul
if not errorlevel 1 (
echo [INFO] Windows 8 detected
)
ver | findstr /i "6\.3\." >nul
if not errorlevel 1 (
echo [INFO] Windows 8.1 detected
)
ver | findstr /i "10\.0\." >nul
if not errorlevel 1 (
echo [INFO] Windows 10/11 detected
)
exit /b 0
:check_and_change_directory
if exist "package.json" if exist "packages" (
echo [INFO] Already in n8n project directory
exit /b 0
)
set "SCRIPT_DIR=%~dp0"
if "%SCRIPT_DIR:~-1%"=="\" set "SCRIPT_DIR=%SCRIPT_DIR:~0,-1%"
echo %SCRIPT_DIR% | findstr /I /C:"n8n-n8n-1.109.2" >nul
if not errorlevel 1 (
echo [INFO] Switching to n8n project directory
cd /d "%SCRIPT_DIR%" 2>nul
if errorlevel 1 (
cd "%SCRIPT_DIR%" 2>nul
if errorlevel 1 (
echo [ERROR] Cannot change to directory: %SCRIPT_DIR%
exit /b 1
)
)
echo [SUCCESS] Changed to correct n8n project directory
exit /b 0
)
if exist "n8n-n8n-1.109.2\" (
cd n8n-n8n-1.109.2
) else if exist "..\n8n-n8n-1.109.2\" (
cd ..\n8n-n8n-1.109.2
) else if exist "..\..\n8n-n8n-1.109.2\" (
cd ..\..\n8n-n8n-1.109.2
) else (
echo [ERROR] n8n-n8n-1.109.2 directory not found
echo [INFO] Please run this script from the correct project directory
exit /b 1
)
if not exist "package.json" (
echo [ERROR] Invalid directory structure, missing package.json
exit /b 1
)
if not exist "packages" (
echo [ERROR] Invalid directory structure, missing packages directory
exit /b 1
)
echo [SUCCESS] Changed to correct n8n project directory
exit /b 0
:check_dependencies
where node >nul 2>&1
if errorlevel 1 (
if exist "C:\Program Files\nodejs\node.exe" (
set "PATH=C:\Program Files\nodejs;%PATH%"
) else if exist "C:\Program Files (x86)\nodejs\node.exe" (
set "PATH=C:\Program Files (x86)\nodejs;%PATH%"
) else (
echo [ERROR] Node.js not installed or not in PATH
echo [INFO] Please visit https://nodejs.org to download and install
exit /b 1
)
)
echo [INFO] Node.js version:
node --version
if not defined USE_NPM (
where pnpm >nul 2>&1
if errorlevel 1 (
echo [WARNING] pnpm not installed, trying npm
set "USE_NPM=true"
) else (
echo [INFO] Using pnpm as package manager
)
) else (
echo [INFO] Using npm as package manager
)
echo [SUCCESS] Dependencies check passed
exit /b 0
:install_with_pnpm
echo [INFO] Installing dependencies with pnpm...
where pnpm >nul 2>&1
if errorlevel 1 (
echo [INFO] Installing pnpm...
call npm install -g pnpm@8
if errorlevel 1 (
echo [ERROR] pnpm installation failed
exit /b 1
)
)
call pnpm install --no-frozen-lockfile
exit /b %errorlevel%
:install_with_npm
echo [WARNING] Using npm install
echo [INFO] Recommend installing pnpm: npm install -g pnpm
call npm install --legacy-peer-deps
exit /b %errorlevel%
:check_port
echo [INFO] Checking port %CUSTOM_PORT% availability...
netstat -ano 2>nul | findstr ":%CUSTOM_PORT%" >nul 2>&1
if not errorlevel 1 (
echo [WARNING] Port %CUSTOM_PORT% is already in use
echo [INFO] Checking process using the port...
netstat -ano | findstr ":%CUSTOM_PORT%"
echo.
set /p "kill_process=Terminate the process? (y/N): "
if /I "!kill_process!"=="y" (
echo [INFO] Terminating process...
for /f "tokens=5" %%a in ('netstat -ano ^| findstr ":%CUSTOM_PORT%"') do (
taskkill /PID %%a /F >nul 2>&1
if errorlevel 1 (
tskill %%a >nul 2>&1
)
)
echo [SUCCESS] Process terminated
timeout /t 2 /nobreak >nul 2>&1
if errorlevel 1 (
ping -n 3 127.0.0.1 >nul
)
) else (
echo [ERROR] Cannot start n8n, port is in use
exit /b 1
)
)
exit /b 0
:stop_existing
echo [INFO] Stopping existing n8n processes...
taskkill /F /IM node.exe /FI "WINDOWTITLE eq *n8n*" >nul 2>&1
taskkill /F /IM node.exe /FI "WINDOWTITLE eq *pnpm*" >nul 2>&1
taskkill /F /IM node.exe /FI "WINDOWTITLE eq *npm*" >nul 2>&1
timeout /t 2 /nobreak >nul 2>&1
if errorlevel 1 (
ping -n 3 127.0.0.1 >nul
)
echo [SUCCESS] Existing processes stopped
exit /b 0
:setup_environment
echo [INFO] Setting environment variables...
set "N8N_PORT=%CUSTOM_PORT%"
set "N8N_DEFAULT_LOCALE=zh-CN"
set "N8N_SECURE_COOKIE=false"
set "DB_SQLITE_POOL_SIZE=5"
set "N8N_RUNNERS_ENABLED=true"
set "N8N_BLOCK_ENV_ACCESS_IN_NODE=false"
set "NODE_OPTIONS=--max-old-space-size=4096"
echo [SUCCESS] Environment variables set
echo - N8N_PORT=%CUSTOM_PORT%
echo - N8N_DEFAULT_LOCALE=zh-CN
echo - N8N_SECURE_COOKIE=false
echo - DB_SQLITE_POOL_SIZE=5
echo - NODE_OPTIONS=--max-old-space-size=4096
exit /b 0
:check_build
if not exist "packages\cli\dist\" goto need_build
if not exist "packages\core\dist\" goto need_build
if not exist "packages\workflow\dist\" goto need_build
exit /b 0
:need_build
echo [WARNING] Project needs to be built
set /p "build_project=Build project now? This may take a few minutes (y/N): "
if /I "!build_project!"=="y" (
call :build_project
)
exit /b 0
:build_project
echo [INFO] Building project...
if defined USE_NPM (
call npm run build > build.log 2>&1
) else (
call pnpm build > build.log 2>&1
)
if errorlevel 1 (
echo [ERROR] Build failed, check build.log
type build.log | more
exit /b 1
)
echo [SUCCESS] Project built successfully
exit /b 0
:start_n8n
echo [INFO] Starting n8n Chinese version...
set "DATETIME=%date:~0,4%%date:~5,2%%date:~8,2%-%time:~0,2%%time:~3,2%"
set "DATETIME=%DATETIME: =0%"
set "DATETIME=%DATETIME:/=%"
set "DATETIME=%DATETIME:\=%"
set "LOG_FILE=n8n-%DATETIME%.log"
echo [INFO] Starting n8n service...
echo [INFO] Log file: %LOG_FILE%
if defined USE_NPM (
start "n8n Server" /B cmd /c "npm start > %LOG_FILE% 2>&1"
) else (
start "n8n Server" /B cmd /c "pnpm start > %LOG_FILE% 2>&1"
)
echo Waiting for n8n to start
set "count=0"
:wait_loop
set /a count+=1
if %count% gtr 60 goto start_failed
netstat -an 2>nul | findstr ":%CUSTOM_PORT%" | findstr "LISTENING" >nul 2>&1
if not errorlevel 1 goto start_success
set /p "=." <nul
timeout /t 1 /nobreak >nul 2>&1
if errorlevel 1 (
ping -n 2 127.0.0.1 >nul
)
goto wait_loop
:start_success
echo.
echo [SUCCESS] n8n started successfully!
echo.
echo ========== START INFO ==========
echo Access URL: http://localhost:%CUSTOM_PORT%
echo Interface Language: Chinese (zh-CN)
echo Log file: %LOG_FILE%
echo =================================
echo.
echo [INFO] Use Ctrl+C to stop service
echo [TIP] First visit requires account setup
echo.
pause
exit /b 0
:start_failed
echo.
echo [ERROR] n8n failed to start
echo [INFO] Check log file: %LOG_FILE%
if exist "%LOG_FILE%" (
echo.
echo ===== ERROR LOG =====
type "%LOG_FILE%" | more
)
echo.
echo [INFO] Trying alternative start method...
call npx n8n
if errorlevel 1 (
echo [ERROR] Alternative method also failed
echo.
echo Please try:
echo 1. Run: npm install run-script-os
echo 2. Run: node packages/cli/bin/n8n
)
pause
exit /b 1
:show_help
echo Usage: %~nx0 [options]
echo.
echo Options:
echo -h, --help Show this help
echo -d, --dev Start in development mode
echo -b, --build Force rebuild project
echo -c, --check Only check system status
echo -p, --port Specify port (default: 5678)
echo --skip-deps Skip dependency check
echo --npm Use npm instead of pnpm
echo.
echo Examples:
echo %~nx0 # Normal start (port 5678)
echo %~nx0 -p 8080 # Use port 8080
echo %~nx0 -d # Development mode
echo %~nx0 -b # Rebuild and start
echo %~nx0 --npm # Use npm
echo %~nx0 -p 3000 -d # Dev mode on port 3000
echo.
echo Troubleshooting:
echo 1. If pnpm install fails, use --npm option
echo 2. If port is in use, script will prompt to terminate process
echo 3. Check build.log when build fails
echo.
goto end
:error_exit
echo [ERROR] Script execution failed
echo.
echo Common solutions:
echo 1. Ensure Node.js version is 18.x or 20.x
echo 2. Try running with administrator privileges
echo 3. Use --npm option if pnpm has issues
echo 4. Check network connection and proxy settings
echo.
pause
exit /b 1
:end
REM Restore original codepage
if defined OLDCP (
chcp %OLDCP% >nul 2>&1
)
endlocal
exit /b 0

View File

@@ -47,9 +47,9 @@ const ResultModal: React.FC<ResultModalProps> = ({ isOpen, onClose, onViewDetail
className="fixed inset-0 flex items-center justify-center z-50 p-4"
onClick={(e) => e.stopPropagation()}
>
<div className="bg-white rounded-2xl shadow-2xl max-w-2xl w-full max-h-[90vh] overflow-hidden">
<div className="bg-white rounded-2xl shadow-2xl max-w-2xl w-full max-h-[90vh] overflow-hidden flex flex-col">
{/* 头部 */}
<div className="relative bg-gradient-to-br from-green-500 to-emerald-600 p-8 text-white">
<div className="relative bg-gradient-to-br from-green-500 to-emerald-600 p-8 text-white flex-shrink-0">
<button
onClick={onClose}
className="absolute top-4 right-4 p-2 hover:bg-white/20 rounded-lg transition-colors"
@@ -74,7 +74,7 @@ const ResultModal: React.FC<ResultModalProps> = ({ isOpen, onClose, onViewDetail
</p>
</div>
<div className="p-6">
<div className="p-6 overflow-y-auto flex-1">
{/* 统计信息 */}
<div className="grid grid-cols-3 gap-4 mb-6">
{stats.map((stat, index) => (
@@ -138,11 +138,13 @@ const ResultModal: React.FC<ResultModalProps> = ({ isOpen, onClose, onViewDetail
</div>
</div>
</div>
</div>
{/* 操作按钮 */}
{/* 操作按钮 - 固定在底部 */}
<div className="p-6 bg-gray-50 border-t border-gray-200 flex-shrink-0">
<div className="flex justify-center">
<button
onClick={() => window.open('http://localhost:4155', '_blank')}
onClick={() => window.open('http://localhost:4155/index.html', '_blank')}
className="px-8 py-3 bg-gradient-to-r from-blue-600 to-purple-600 text-white rounded-xl font-medium hover:shadow-lg transform hover:scale-105 transition-all flex items-center justify-center gap-2"
>
<Eye className="w-5 h-5" />

View File

@@ -8,9 +8,27 @@ interface LandingPageProps {
const LandingPage: React.FC<LandingPageProps> = ({ onStart }) => {
return (
<div className="min-h-screen flex items-center justify-center p-8 relative">
{/* 背景图片和蒙版 */}
<div className="min-h-screen flex items-center justify-center p-8 relative overflow-hidden bg-black">
{/* 高级背景效果 */}
<div className="absolute inset-0 z-0">
{/* 渐变背景 */}
<div className="absolute inset-0 bg-gradient-to-br from-slate-950 via-slate-900 to-slate-950" />
{/* 网格背景 */}
<div
className="absolute inset-0 opacity-20"
style={{
backgroundImage: `linear-gradient(to right, #1e293b 1px, transparent 1px),
linear-gradient(to bottom, #1e293b 1px, transparent 1px)`,
backgroundSize: '50px 50px'
}}
/>
{/* 动态光效 */}
<div className="absolute top-1/4 -left-1/4 w-96 h-96 bg-blue-500/30 rounded-full blur-[120px] animate-pulse" />
<div className="absolute bottom-1/4 -right-1/4 w-96 h-96 bg-purple-500/30 rounded-full blur-[120px] animate-pulse" />
{/* 图片叠加 */}
<div
className="absolute inset-0"
style={{
@@ -18,11 +36,9 @@ const LandingPage: React.FC<LandingPageProps> = ({ onStart }) => {
backgroundSize: 'cover',
backgroundPosition: 'center',
backgroundRepeat: 'no-repeat',
opacity: 0.08
opacity: 0.03
}}
/>
<div className="absolute inset-0 bg-gradient-to-br from-gray-900/50 via-purple-900/30 to-blue-900/40" />
<div className="absolute inset-0 backdrop-blur-sm" />
</div>
{/* 主内容 */}
@@ -38,9 +54,12 @@ const LandingPage: React.FC<LandingPageProps> = ({ onStart }) => {
initial={{ scale: 0 }}
animate={{ scale: 1 }}
transition={{ delay: 0.2, type: "spring", stiffness: 200 }}
className="inline-flex items-center justify-center w-24 h-24 rounded-3xl bg-gradient-to-br from-blue-500 to-purple-500 shadow-2xl"
className="inline-flex items-center justify-center w-24 h-24 rounded-2xl bg-gradient-to-br from-slate-800 to-slate-900 shadow-2xl border border-slate-700/50"
style={{
boxShadow: '0 0 40px rgba(59, 130, 246, 0.2), 0 0 80px rgba(147, 51, 234, 0.1)'
}}
>
<Sparkles className="w-12 h-12 text-white" />
<Sparkles className="w-12 h-12 text-blue-400" />
</motion.div>
{/* Title */}
@@ -49,10 +68,10 @@ const LandingPage: React.FC<LandingPageProps> = ({ onStart }) => {
animate={{ opacity: 1 }}
transition={{ delay: 0.4 }}
>
<h1 className="text-6xl font-bold bg-gradient-to-r from-blue-600 to-purple-600 bg-clip-text text-transparent">
<h1 className="text-7xl font-bold text-white tracking-tight">
DuoDuo Agent
</h1>
<p className="mt-4 text-xl text-neutral-600 dark:text-neutral-400">
<p className="mt-4 text-xl text-slate-400 font-light tracking-wide">
Agent协同 · ·
</p>
</motion.div>
@@ -62,54 +81,39 @@ const LandingPage: React.FC<LandingPageProps> = ({ onStart }) => {
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.6 }}
className="grid grid-cols-3 gap-6 mt-12"
className="grid grid-cols-3 gap-8 mt-16 max-w-3xl mx-auto"
>
<div className="glass-morphism rounded-2xl p-6 hover:scale-105 transition-transform">
<Layers className="w-8 h-8 text-blue-500 mb-4" />
<h3 className="font-semibold text-lg mb-2">7Agent</h3>
<p className="text-sm text-neutral-600 dark:text-neutral-400">
</p>
<div className="relative group">
<div className="absolute inset-0 bg-gradient-to-r from-blue-600/20 to-cyan-600/20 rounded-2xl blur-xl group-hover:blur-2xl transition-all opacity-0 group-hover:opacity-100" />
<div className="relative bg-slate-900/50 backdrop-blur-xl rounded-2xl p-8 border border-slate-800 hover:border-slate-700 transition-all h-full flex flex-col items-center text-center">
<Layers className="w-10 h-10 text-blue-400 mb-4" />
<h3 className="font-semibold text-lg mb-2 text-white">7Agent</h3>
<p className="text-sm text-slate-400">
</p>
</div>
</div>
<div className="glass-morphism rounded-2xl p-6 hover:scale-105 transition-transform">
<Zap className="w-8 h-8 text-purple-500 mb-4" />
<h3 className="font-semibold text-lg mb-2"></h3>
<p className="text-sm text-neutral-600 dark:text-neutral-400">
</p>
<div className="relative group">
<div className="absolute inset-0 bg-gradient-to-r from-purple-600/20 to-pink-600/20 rounded-2xl blur-xl group-hover:blur-2xl transition-all opacity-0 group-hover:opacity-100" />
<div className="relative bg-slate-900/50 backdrop-blur-xl rounded-2xl p-8 border border-slate-800 hover:border-slate-700 transition-all h-full flex flex-col items-center text-center">
<Zap className="w-10 h-10 text-purple-400 mb-4" />
<h3 className="font-semibold text-lg mb-2 text-white"></h3>
<p className="text-sm text-slate-400">
</p>
</div>
</div>
<div className="glass-morphism rounded-2xl p-6 hover:scale-105 transition-transform">
<Sparkles className="w-8 h-8 text-green-500 mb-4" />
<h3 className="font-semibold text-lg mb-2"></h3>
<p className="text-sm text-neutral-600 dark:text-neutral-400">
</p>
</div>
</motion.div>
{/* Demo Info */}
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ delay: 0.8 }}
className="glass-morphism rounded-2xl p-8 text-left"
>
<h2 className="text-2xl font-semibold mb-4"></h2>
<div className="space-y-2 text-neutral-600 dark:text-neutral-400">
<p>
<span className="font-medium text-neutral-900 dark:text-neutral-100"></span>
2024
</p>
<p>
<span className="font-medium text-neutral-900 dark:text-neutral-100"></span>
50,00035050,000
</p>
<p>
<span className="font-medium text-neutral-900 dark:text-neutral-100"></span>
3
</p>
<div className="relative group">
<div className="absolute inset-0 bg-gradient-to-r from-emerald-600/20 to-green-600/20 rounded-2xl blur-xl group-hover:blur-2xl transition-all opacity-0 group-hover:opacity-100" />
<div className="relative bg-slate-900/50 backdrop-blur-xl rounded-2xl p-8 border border-slate-800 hover:border-slate-700 transition-all h-full flex flex-col items-center text-center">
<Sparkles className="w-10 h-10 text-emerald-400 mb-4" />
<h3 className="font-semibold text-lg mb-2 text-white"></h3>
<p className="text-sm text-slate-400">
</p>
</div>
</div>
</motion.div>
@@ -117,17 +121,19 @@ const LandingPage: React.FC<LandingPageProps> = ({ onStart }) => {
<motion.button
initial={{ opacity: 0, scale: 0.9 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ delay: 1 }}
transition={{ delay: 0.8 }}
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
onClick={onStart}
className="group relative inline-flex items-center gap-3 px-8 py-4 bg-gradient-to-r from-blue-500 to-purple-500 text-white font-semibold text-lg rounded-2xl shadow-xl hover:shadow-2xl transition-all"
className="relative mt-12 px-16 py-4 bg-white text-black font-semibold text-lg rounded-xl transition-all duration-300 group"
style={{
boxShadow: '0 4px 30px rgba(255, 255, 255, 0.1)'
}}
>
<span></span>
<ArrowRight className="w-5 h-5 group-hover:translate-x-1 transition-transform" />
{/* Glow effect */}
<div className="absolute inset-0 rounded-2xl bg-gradient-to-r from-blue-500 to-purple-500 blur-xl opacity-50 group-hover:opacity-70 transition-opacity" />
<span className="flex items-center gap-3">
<ArrowRight className="w-5 h-5 group-hover:translate-x-1 transition-transform" />
</span>
</motion.button>
{/* Footer */}
@@ -135,7 +141,7 @@ const LandingPage: React.FC<LandingPageProps> = ({ onStart }) => {
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ delay: 1.2 }}
className="text-sm text-neutral-500 dark:text-neutral-500 mt-8"
className="text-xs text-slate-600 mt-8 tracking-wide"
>
Powered by n8n Workflow · DeepSeek · Google Gemini
</motion.p>

View File

@@ -1,7 +1,7 @@
import { useState, useEffect, useRef } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import { useDemoStore } from '@/store/demoStore';
import { Play, Pause, RotateCcw, Maximize2, Terminal, FileInput } from 'lucide-react';
import { Play, Pause, RotateCcw, Maximize2, Terminal, FileInput, Eye } from 'lucide-react';
import RequirementModal from '@/components/RequirementModal';
import ResultModal from '@/components/ResultModal';
@@ -46,9 +46,12 @@ const WorkflowPageV4 = () => {
const [showResultModal, setShowResultModal] = useState(false);
const [userRequirement, setUserRequirement] = useState('');
const [imageLoadingStates, setImageLoadingStates] = useState<{ [key: string]: boolean }>({});
const [logoClickCount, setLogoClickCount] = useState(0);
const [showFloatingButton, setShowFloatingButton] = useState(false);
const terminalRef = useRef<HTMLDivElement>(null);
const intervalRef = useRef<number | null>(null);
const progressLineIdRef = useRef<string | null>(null);
const logoClickTimerRef = useRef<number | null>(null);
// 启动序列
const startupSequence = [
@@ -639,6 +642,7 @@ const WorkflowPageV4 = () => {
setTimeout(() => {
console.log('Setting showResultModal to true');
setShowResultModal(true);
setShowFloatingButton(true);
}, 2000);
return;
@@ -696,6 +700,7 @@ const WorkflowPageV4 = () => {
}
}, [currentAgentIndex]);
// 计时器
useEffect(() => {
if (status === 'running') {
@@ -739,6 +744,30 @@ const WorkflowPageV4 = () => {
setIsExecuting(false);
setUserRequirement('');
setShowResultModal(false);
setShowFloatingButton(false);
};
// Logo三击处理
const handleLogoClick = () => {
const newCount = logoClickCount + 1;
setLogoClickCount(newCount);
// 清除之前的定时器
if (logoClickTimerRef.current) {
clearTimeout(logoClickTimerRef.current);
}
// 如果点击了3次打开结果弹窗并显示浮动按钮
if (newCount === 3) {
setShowResultModal(true);
setShowFloatingButton(true); // 调试模式也显示浮动按钮
setLogoClickCount(0);
} else {
// 设置500ms后重置计数
logoClickTimerRef.current = window.setTimeout(() => {
setLogoClickCount(0);
}, 500);
}
};
// 格式化时间
@@ -788,7 +817,15 @@ const WorkflowPageV4 = () => {
{/* 顶部控制栏 */}
<div className="bg-white border-b border-gray-200 px-6 py-3 flex items-center justify-between">
<div className="flex items-center gap-4">
<h1 className="text-lg font-semibold text-gray-900">DuoDuo Agent - ·</h1>
{/* Duoduo Logo - 可三击打开结果 */}
<img
src="https://ddcz-1315997005.cos.ap-nanjing.myqcloud.com/static/img/duoduo_logo/LOGO_1097x300.png"
alt="Duoduo Agent"
className="h-7 cursor-pointer select-none"
onClick={handleLogoClick}
style={{ userSelect: 'none' }}
/>
<h1 className="text-lg font-semibold text-gray-900">·</h1>
<div className="flex items-center gap-2">
<button
onClick={status === 'idle' ? () => setShowRequirementModal(true) : pauseDemo}
@@ -1056,6 +1093,41 @@ const WorkflowPageV4 = () => {
onClose={() => setShowResultModal(false)}
onViewDetails={handleViewDetails}
/>
{/* 右下角浮动按钮 - 只在完成后显示 */}
<AnimatePresence>
{showFloatingButton && (
<motion.button
initial={{ opacity: 0, scale: 0.8, y: 20 }}
animate={{ opacity: 1, scale: 1, y: 0 }}
exit={{ opacity: 0, scale: 0.8, y: 20 }}
transition={{ type: 'spring', stiffness: 300, damping: 25 }}
onClick={() => setShowResultModal(true)}
className="fixed bottom-8 right-8 px-6 py-3 bg-gradient-to-r from-blue-600 to-purple-600 text-white rounded-full shadow-lg hover:shadow-xl transform hover:scale-105 transition-all flex items-center gap-2 z-50"
style={{
backdropFilter: 'blur(10px)',
background: 'linear-gradient(135deg, rgba(59, 130, 246, 0.9) 0%, rgba(147, 51, 234, 0.9) 100%)',
}}
>
<Eye className="w-5 h-5" />
<span className="font-medium"></span>
{/* 呼吸灯效果 */}
<motion.div
className="absolute -inset-1 bg-gradient-to-r from-blue-600 to-purple-600 rounded-full opacity-30"
animate={{
scale: [1, 1.2, 1],
opacity: [0.3, 0.1, 0.3],
}}
transition={{
duration: 2,
repeat: Infinity,
ease: "easeInOut"
}}
/>
</motion.button>
)}
</AnimatePresence>
</div>
);
};