初始提交: Qihu-AIFlow v2.0.1 完整项目
- 前端 React+TypeScript (源码+构建产物) - 后端 Python FastAPI - 数据库迁移 001-015 - Docker部署配置 - 微信ClawBot API频道绑定 - 项目文档 README.md
This commit is contained in:
commit
78ff261b5a
199 files changed
+69126
No files matched your search
@@ -0,0 +1,370 @@
|
||||
import React, { useState, useEffect, useCallback } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { mockAdBanners, mockApps } from '@/mock/data';
|
||||
import type { AdBanner, MarketApp } from '@/types';
|
||||
import './LandingPage.css';
|
||||
|
||||
const SVGIcon: React.FC<{ children: React.ReactNode; size?: number }> = ({ children, size = 16 }) => (
|
||||
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
{children}
|
||||
</svg>
|
||||
);
|
||||
|
||||
const typeLabels: Record<string, string> = { skill: 'Skill', agent: 'Agent', mcp: 'MCP' };
|
||||
const typeColors: Record<string, string> = { skill: '#10B981', agent: '#5B5FED', mcp: '#F59E0B' };
|
||||
|
||||
const LandingPage: React.FC = () => {
|
||||
const navigate = useNavigate();
|
||||
const [currentSlide, setCurrentSlide] = useState(0);
|
||||
const [isPaused, setIsPaused] = useState(false);
|
||||
const banners = mockAdBanners.filter(b => b.status === 'active');
|
||||
const publishedApps = mockApps.filter(a => a.status === 'published');
|
||||
const [appTypeFilter, setAppTypeFilter] = useState<'' | 'skill' | 'agent' | 'mcp'>('');
|
||||
const [toastMsg, setToastMsg] = useState('');
|
||||
|
||||
const filteredApps = appTypeFilter
|
||||
? publishedApps.filter(a => a.type === appTypeFilter)
|
||||
: publishedApps;
|
||||
|
||||
const showToast = (msg: string) => {
|
||||
setToastMsg(msg);
|
||||
setTimeout(() => setToastMsg(''), 2000);
|
||||
};
|
||||
|
||||
const handleAppClick = (appName: string) => {
|
||||
showToast(`"${appName}" 需登录后使用,即将跳转登录页`);
|
||||
setTimeout(() => navigate('/login'), 800);
|
||||
};
|
||||
|
||||
// Auto rotate carousel
|
||||
const nextSlide = useCallback(() => {
|
||||
if (banners.length === 0) return;
|
||||
setCurrentSlide(prev => (prev + 1) % banners.length);
|
||||
}, [banners.length]);
|
||||
|
||||
useEffect(() => {
|
||||
if (banners.length <= 1 || isPaused) return;
|
||||
const timer = setInterval(nextSlide, 4000);
|
||||
return () => clearInterval(timer);
|
||||
}, [banners.length, isPaused, nextSlide]);
|
||||
|
||||
const goToSlide = (idx: number) => setCurrentSlide(idx);
|
||||
|
||||
const getGradient = (app: MarketApp): string => {
|
||||
const gradients: Record<string, string> = {
|
||||
a1: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
|
||||
a2: 'linear-gradient(135deg, #f093fb 0%, #f5576c 100%)',
|
||||
a3: 'linear-gradient(135deg, #4facfe 0%, #00f2fe 100%)',
|
||||
a4: 'linear-gradient(135deg, #43e97b 0%, #38f9d7 100%)',
|
||||
a5: 'linear-gradient(135deg, #fa709a 0%, #fee140 100%)',
|
||||
a6: 'linear-gradient(135deg, #a18cd1 0%, #fbc2eb 100%)',
|
||||
a8: 'linear-gradient(135deg, #ffecd2 0%, #fcb69f 100%)',
|
||||
};
|
||||
return gradients[app.id] || 'linear-gradient(135deg, #5B5FED 0%, #A78BFA 100%)';
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="landing-page">
|
||||
{/* Toast notification */}
|
||||
{toastMsg && (
|
||||
<div className="landing-toast">{toastMsg}</div>
|
||||
)}
|
||||
|
||||
{/* Hero / Nav bar */}
|
||||
<header className="landing-header">
|
||||
<div className="landing-header-inner">
|
||||
<div className="landing-brand">
|
||||
<svg width="32" height="32" viewBox="0 0 32 32" fill="none">
|
||||
<rect width="32" height="32" rx="8" fill="#5B5FED"/>
|
||||
<path d="M8 20V12l4 4 4-4v8" stroke="white" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" fill="none"/>
|
||||
<path d="M6 22h20" stroke="white" strokeWidth="1.5" strokeLinecap="round" opacity="0.5"/>
|
||||
</svg>
|
||||
<span className="brand-name">Qihu-AIFlow</span>
|
||||
</div>
|
||||
<nav className="landing-nav-links">
|
||||
<a href="#market">应用市场</a>
|
||||
<a href="#features">平台能力</a>
|
||||
</nav>
|
||||
<div className="landing-header-actions">
|
||||
<button className="landing-btn landing-btn-outline" onClick={() => navigate('/login')}>登录</button>
|
||||
<button className="landing-btn landing-btn-primary" onClick={() => navigate('/login')}>免费注册</button>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{/* Hero Section */}
|
||||
<section className="landing-hero">
|
||||
<div className="landing-hero-content">
|
||||
<h1 className="hero-title">
|
||||
用 <span className="hero-accent">AI</span> 构建你的<br/>智能自动化工作流
|
||||
</h1>
|
||||
<p className="hero-desc">
|
||||
Qihu-AIFlow 是一站式AI智能自动化PaaS平台,集成多模态大模型、知识库管理、应用市场,
|
||||
让每个人都能轻松搭建属于自己的AI自动化SOP。
|
||||
</p>
|
||||
<div className="hero-actions">
|
||||
<button className="landing-btn landing-btn-primary landing-btn-lg" onClick={() => navigate('/login')}>
|
||||
免费开始使用
|
||||
</button>
|
||||
<button className="landing-btn landing-btn-outline landing-btn-lg" onClick={() => { document.getElementById('market')?.scrollIntoView({ behavior: 'smooth' }); }}>
|
||||
浏览应用市场
|
||||
</button>
|
||||
</div>
|
||||
<div className="hero-stats">
|
||||
<div className="hero-stat">
|
||||
<span className="stat-number">3,500+</span>
|
||||
<span className="stat-label">活跃用户</span>
|
||||
</div>
|
||||
<div className="hero-stat">
|
||||
<span className="stat-number">120+</span>
|
||||
<span className="stat-label">应用/Skills</span>
|
||||
</div>
|
||||
<div className="hero-stat">
|
||||
<span className="stat-number">99.8%</span>
|
||||
<span className="stat-label">服务可用率</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Carousel Section */}
|
||||
{banners.length > 0 && (
|
||||
<section className="landing-banners">
|
||||
<div className="landing-section-inner">
|
||||
<h2 className="section-title">推荐应用</h2>
|
||||
<div
|
||||
className="carousel-container"
|
||||
onMouseEnter={() => setIsPaused(true)}
|
||||
onMouseLeave={() => setIsPaused(false)}
|
||||
>
|
||||
<div className="carousel-track" style={{ transform: `translateX(-${currentSlide * 100}%)` }}>
|
||||
{banners.map(banner => (
|
||||
<div key={banner.id} className="carousel-slide">
|
||||
<div className="carousel-card" style={{ background: banner.linkAppId ? getGradient({ id: banner.linkAppId } as MarketApp) : 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)' }}>
|
||||
<div className="carousel-card-content">
|
||||
<div className="carousel-badge">推荐</div>
|
||||
<h3 className="carousel-title">{banner.title}</h3>
|
||||
{banner.linkAppName && (
|
||||
<p className="carousel-subtitle">立即体验 {banner.linkAppName}</p>
|
||||
)}
|
||||
<button
|
||||
className="carousel-cta"
|
||||
onClick={() => navigate('/login')}
|
||||
>
|
||||
查看详情
|
||||
<SVGIcon size={14}><polyline points="9 18 15 12 9 6"/></SVGIcon>
|
||||
</button>
|
||||
</div>
|
||||
<div className="carousel-card-visual">
|
||||
<div className="visual-circle c1"/>
|
||||
<div className="visual-circle c2"/>
|
||||
<div className="visual-circle c3"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
{/* Dots */}
|
||||
{banners.length > 1 && (
|
||||
<div className="carousel-dots">
|
||||
{banners.map((_, idx) => (
|
||||
<button
|
||||
key={idx}
|
||||
className={`carousel-dot ${idx === currentSlide ? 'active' : ''}`}
|
||||
onClick={() => goToSlide(idx)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
{/* Arrows */}
|
||||
{banners.length > 1 && (
|
||||
<>
|
||||
<button
|
||||
className="carousel-arrow carousel-arrow-left"
|
||||
onClick={() => setCurrentSlide(prev => (prev - 1 + banners.length) % banners.length)}
|
||||
>
|
||||
<SVGIcon size={20}><polyline points="15 18 9 12 15 6"/></SVGIcon>
|
||||
</button>
|
||||
<button
|
||||
className="carousel-arrow carousel-arrow-right"
|
||||
onClick={() => nextSlide()}
|
||||
>
|
||||
<SVGIcon size={20}><polyline points="9 18 15 12 9 6"/></SVGIcon>
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
|
||||
{/* Market Preview Section */}
|
||||
<section className="landing-market" id="market">
|
||||
<div className="landing-section-inner">
|
||||
<div className="section-header">
|
||||
<h2 className="section-title">应用市场</h2>
|
||||
<p className="section-desc">丰富的 Skills、Agent、MCP 应用,一键接入你的工作流</p>
|
||||
</div>
|
||||
|
||||
{/* Type Filter */}
|
||||
<div className="market-filter-tabs">
|
||||
<button
|
||||
className={`filter-tab ${appTypeFilter === '' ? 'active' : ''}`}
|
||||
onClick={() => setAppTypeFilter('')}
|
||||
>全部</button>
|
||||
<button
|
||||
className={`filter-tab ${appTypeFilter === 'skill' ? 'active' : ''}`}
|
||||
onClick={() => setAppTypeFilter('skill')}
|
||||
>Skills</button>
|
||||
<button
|
||||
className={`filter-tab ${appTypeFilter === 'agent' ? 'active' : ''}`}
|
||||
onClick={() => setAppTypeFilter('agent')}
|
||||
>Agent</button>
|
||||
<button
|
||||
className={`filter-tab ${appTypeFilter === 'mcp' ? 'active' : ''}`}
|
||||
onClick={() => setAppTypeFilter('mcp')}
|
||||
>MCP</button>
|
||||
</div>
|
||||
|
||||
{/* App Grid */}
|
||||
<div className="market-app-grid">
|
||||
{filteredApps.map(app => (
|
||||
<div key={app.id} className="market-app-card" onClick={() => handleAppClick(app.name)}>
|
||||
<div className="app-card-cover" style={{ background: getGradient(app) }}>
|
||||
<span className="app-card-type-badge" style={{ background: typeColors[app.type] }}>
|
||||
{typeLabels[app.type]}
|
||||
</span>
|
||||
{app.price > 0 && (
|
||||
<span className="app-card-price">{app.price} 元</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="app-card-body">
|
||||
<h4 className="app-card-name">{app.name}</h4>
|
||||
<p className="app-card-desc">{app.description}</p>
|
||||
<div className="app-card-meta">
|
||||
<span className="app-card-rating">
|
||||
<SVGIcon size={12}><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></SVGIcon>
|
||||
{app.ratingAvg > 0 ? app.ratingAvg : '-'}
|
||||
</span>
|
||||
<span className="app-card-installs">{app.installCount.toLocaleString()} 次安装</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="market-more">
|
||||
<button className="landing-btn landing-btn-outline" onClick={() => navigate('/login')}>
|
||||
登录查看更多应用
|
||||
<SVGIcon size={14}><polyline points="9 18 15 12 9 6"/></SVGIcon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Features Section */}
|
||||
<section className="landing-features" id="features">
|
||||
<div className="landing-section-inner">
|
||||
<div className="section-header">
|
||||
<h2 className="section-title">平台核心能力</h2>
|
||||
<p className="section-desc">从对话到自动化,Qihu-AIFlow 为你提供完整的 AI 工作流解决方案</p>
|
||||
</div>
|
||||
<div className="features-grid">
|
||||
<div className="feature-card">
|
||||
<div className="feature-icon">
|
||||
<SVGIcon size={28}><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></SVGIcon>
|
||||
</div>
|
||||
<h3 className="feature-title">多模型AI对话</h3>
|
||||
<p className="feature-desc">支持GPT-4o、DeepSeek-R1、Qwen-Max等多种大模型自由切换,按需使用最优模型</p>
|
||||
</div>
|
||||
<div className="feature-card">
|
||||
<div className="feature-icon">
|
||||
<SVGIcon size={28}><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></SVGIcon>
|
||||
</div>
|
||||
<h3 className="feature-title">私有知识库</h3>
|
||||
<p className="feature-desc">上传文档构建专属知识库,AI回答基于你的内容,更精准可靠</p>
|
||||
</div>
|
||||
<div className="feature-card">
|
||||
<div className="feature-icon">
|
||||
<SVGIcon size={28}><rect x="3" y="3" width="7" height="7" rx="1.2"/><rect x="14" y="3" width="7" height="7" rx="1.2"/><rect x="3" y="14" width="7" height="7" rx="1.2"/><rect x="14" y="14" width="7" height="7" rx="1.2"/></SVGIcon>
|
||||
</div>
|
||||
<h3 className="feature-title">应用市场</h3>
|
||||
<p className="feature-desc">丰富的Skills、Agent、MCP应用,一站式接入工作流,即装即用</p>
|
||||
</div>
|
||||
<div className="feature-card">
|
||||
<div className="feature-icon">
|
||||
<SVGIcon size={28}><circle cx="12" cy="12" r="10"/><path d="M12 6v6l4 2"/></SVGIcon>
|
||||
</div>
|
||||
<h3 className="feature-title">Token驾驶舱</h3>
|
||||
<p className="feature-desc">实时监控Token消耗,费用透明可控,每一笔都有据可查</p>
|
||||
</div>
|
||||
<div className="feature-card">
|
||||
<div className="feature-icon">
|
||||
<SVGIcon size={28}><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></SVGIcon>
|
||||
</div>
|
||||
<h3 className="feature-title">IM频道绑定</h3>
|
||||
<p className="feature-desc">支持飞书、钉钉、微信等多平台绑定,AI助手融入日常工作流</p>
|
||||
</div>
|
||||
<div className="feature-card">
|
||||
<div className="feature-icon">
|
||||
<SVGIcon size={28}><polyline points="16 3 21 3 21 8"/><line x1="4" y1="20" x2="21" y2="3"/><polyline points="21 16 21 21 16 21"/><line x1="15" y1="15" x2="21" y2="21"/><line x1="4" y1="4" x2="9" y2="9"/></SVGIcon>
|
||||
</div>
|
||||
<h3 className="feature-title">自动化任务编排</h3>
|
||||
<p className="feature-desc">创建关键词触发、定时执行等自动化任务,让AI按你的节奏工作</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* CTA Section */}
|
||||
<section className="landing-cta">
|
||||
<div className="landing-section-inner">
|
||||
<h2 className="cta-title">准备好开始了吗?</h2>
|
||||
<p className="cta-desc">免费注册即可体验全部功能,无需任何技术背景</p>
|
||||
<button className="landing-btn landing-btn-primary landing-btn-lg" onClick={() => navigate('/login')}>
|
||||
免费注册,立即体验
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Footer */}
|
||||
<footer className="landing-footer">
|
||||
<div className="landing-section-inner">
|
||||
<div className="footer-content">
|
||||
<div className="footer-brand">
|
||||
<div className="landing-brand">
|
||||
<svg width="28" height="28" viewBox="0 0 32 32" fill="none">
|
||||
<rect width="32" height="32" rx="8" fill="#5B5FED"/>
|
||||
<path d="M8 20V12l4 4 4-4v8" stroke="white" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" fill="none"/>
|
||||
</svg>
|
||||
<span className="brand-name" style={{ color: 'var(--color-text-primary)' }}>Qihu-AIFlow</span>
|
||||
</div>
|
||||
<p style={{ color: 'var(--color-text-tertiary)', fontSize: 'var(--text-sm)', marginTop: 'var(--space-md)' }}>
|
||||
AI智能自动化PaaS平台
|
||||
</p>
|
||||
</div>
|
||||
<div className="footer-links">
|
||||
<div className="footer-col">
|
||||
<h4>产品</h4>
|
||||
<a>AI聊天</a>
|
||||
<a>知识库</a>
|
||||
<a>应用市场</a>
|
||||
</div>
|
||||
<div className="footer-col">
|
||||
<h4>支持</h4>
|
||||
<a>帮助文档</a>
|
||||
<a>API参考</a>
|
||||
<a>联系我们</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="footer-bottom">
|
||||
<span>Qihu-AIFlow 2026. All rights reserved.</span>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default LandingPage;
|
||||
Reference in new issue
Block a user