import { ArrowRightOutlined, DashboardOutlined, FileSearchOutlined, PlayCircleOutlined, PlusOutlined, ShoppingOutlined, ThunderboltOutlined, } from "@ant-design/icons"; import { useCallback, useEffect, useMemo, useRef, useState, type CSSProperties } from "react"; import type { WebViewKey, WebImageWorkbenchTool } from "../../types"; import WelcomeSplash from "./WelcomeSplash"; import ToolboxSection from "./ToolboxSection"; import ScriptReviewVisual from "./ScriptReviewVisual"; const OSS_MUBAN = "https://stringtest.oss-cn-hangzhou.aliyuncs.com/muban"; const heroImage1 = `${OSS_MUBAN}/hero-1.png`; const heroImage2 = `${OSS_MUBAN}/hero-2.png`; const heroImage3 = `${OSS_MUBAN}/hero-3.png`; const featureEcommerceImage = `${OSS_MUBAN}/feature-ecommerce.jpg`; const featureScriptImage = `${OSS_MUBAN}/feature-script.jpg`; const featureTokenImage = `${OSS_MUBAN}/feature-token.jpg`; interface HomePageProps { onOpenGenerate: () => void; onOpenCanvas?: () => void; onOpenEcommerce: () => void; onOpenScriptReview?: () => void; onOpenTokenMonitor?: () => void; onSelectView: (view: WebViewKey) => void; onOpenImageTool?: (tool: WebImageWorkbenchTool) => void; } const HOME_BACKGROUND_VIDEO = "https://stringtest.oss-cn-hangzhou.aliyuncs.com/%E6%A0%B7%E7%89%87.mp4"; const HOME_CAROUSEL_IMAGES = [ { imageUrl: heroImage1, title: "灵感生成" }, { imageUrl: heroImage2, title: "画布创作" }, { imageUrl: heroImage3, title: "商业素材" }, ]; const HOME_FEATURES = [ { key: "script", eyebrow: "Script Review", title: "剧本智能测评", description: "用六维雷达评分拆解剧本质量,从结构、节奏、人物到商业潜力给出可执行的优化路径。", imageUrl: featureScriptImage, actionLabel: "开始测评", icon: , stats: ["六维评分", "质量量化", "逐项优化"], }, { key: "token", eyebrow: "Team Tokens", title: "团队 Token 监控", description: "实时追踪团队 Token 消耗、项目分布和成员使用情况,让预算、配额和成本都能被清楚管理。", imageUrl: featureTokenImage, actionLabel: "查看面板", icon: , stats: ["实时概览", "成员明细", "成本分析"], }, { key: "ecommerce", eyebrow: "AI Commerce", title: "AI 电商生成", description: "上传产品图后自动生成主图、场景图、详情素材和短视频方案,快速覆盖多平台商品视觉。", imageUrl: featureEcommerceImage, actionLabel: "开始生成", icon: , stats: ["多场景", "多角度", "批量输出"], }, ]; const HOME_EXPERIENCE_POINTS = [ { label: "生成", meta: "图像 / 视频", tone: "green" }, { label: "测评", meta: "剧本质量", tone: "cyan" }, { label: "成本", meta: "Token 用量", tone: "violet" }, { label: "电商", meta: "商品视觉", tone: "amber" }, ]; const HOME_CAROUSEL_SLOTS = [-4, -3, -2, -1, 0, 1, 2, 3, 4]; const HOME_CAROUSEL_TRANSITION_MS = 860; interface HomeCarouselMotion { direction: number; progress: 0 | 1; } function getPositiveModulo(value: number, length: number) { return ((value % length) + length) % length; } function getHomeCarouselCardStyle(offset: number): CSSProperties { const depth = Math.abs(offset); const direction = Math.sign(offset); const isActive = depth === 0; const xByDepth = [0, 286, 456, 610, 735, 840]; const yByDepth = [8, -2, -8, -13, -18, -24]; const scaleByDepth = [1, 0.98, 0.94, 0.91, 0.88, 0.84]; const x = direction * (xByDepth[depth] ?? xByDepth[xByDepth.length - 1]!); const y = yByDepth[depth] ?? yByDepth[yByDepth.length - 1]!; const z = isActive ? 90 : 28 - depth; const scale = scaleByDepth[depth] ?? scaleByDepth[scaleByDepth.length - 1]!; return { "--apple-card-offset": offset, "--apple-card-depth": depth, "--apple-card-z": 80 - depth, "--apple-card-x": `${x}px`, "--apple-card-y": `${y}px`, "--apple-card-z-offset": `${z}px`, "--apple-card-rotate-y": "0deg", "--apple-card-rotate-z": "0deg", "--apple-card-scale": String(scale), "--apple-card-opacity": String(depth > 4 ? 0 : 1), } as CSSProperties; } function HomePage({ onOpenGenerate, onOpenEcommerce, onOpenScriptReview, onOpenTokenMonitor, onSelectView, onOpenImageTool }: HomePageProps) { const [splashDismissed, setSplashDismissed] = useState(() => sessionStorage.getItem("omniai:splash-seen") === "1"); const [activeSlideIndex, setActiveSlideIndex] = useState(0); const [carouselMotion, setCarouselMotion] = useState(null); const [carouselIsResetting, setCarouselIsResetting] = useState(false); const carouselFrameRef = useRef(null); const carouselResetFrameRef = useRef(null); const carouselTimerRef = useRef(null); const carouselSlotOffsets = useMemo(() => { const direction = carouselMotion?.direction ?? 0; const minSlot = HOME_CAROUSEL_SLOTS[0]! + Math.min(direction, 0); const maxSlot = HOME_CAROUSEL_SLOTS[HOME_CAROUSEL_SLOTS.length - 1]! + Math.max(direction, 0); return Array.from({ length: maxSlot - minSlot + 1 }, (_, index) => minSlot + index); }, [carouselMotion?.direction]); const startCarouselShift = useCallback( (rawDirection: number) => { const direction = Math.sign(rawDirection); if (!direction || HOME_CAROUSEL_IMAGES.length <= 1 || carouselMotion) return; if (carouselFrameRef.current !== null) { window.cancelAnimationFrame(carouselFrameRef.current); } if (carouselTimerRef.current !== null) { window.clearTimeout(carouselTimerRef.current); } if (carouselResetFrameRef.current !== null) { window.cancelAnimationFrame(carouselResetFrameRef.current); } setCarouselIsResetting(false); setCarouselMotion({ direction, progress: 0 }); carouselFrameRef.current = window.requestAnimationFrame(() => { carouselFrameRef.current = window.requestAnimationFrame(() => { setCarouselMotion((current) => (current?.direction === direction ? { direction, progress: 1 } : current)); }); }); carouselTimerRef.current = window.setTimeout(() => { setCarouselIsResetting(true); setActiveSlideIndex((current) => getPositiveModulo(current + direction, HOME_CAROUSEL_IMAGES.length)); setCarouselMotion(null); carouselResetFrameRef.current = window.requestAnimationFrame(() => { carouselResetFrameRef.current = window.requestAnimationFrame(() => { setCarouselIsResetting(false); }); }); }, HOME_CAROUSEL_TRANSITION_MS); }, [carouselMotion], ); useEffect(() => { const timerId = window.setInterval(() => { startCarouselShift(-1); }, 2600); return () => window.clearInterval(timerId); }, [startCarouselShift]); useEffect( () => () => { if (carouselFrameRef.current !== null) { window.cancelAnimationFrame(carouselFrameRef.current); } if (carouselTimerRef.current !== null) { window.clearTimeout(carouselTimerRef.current); } if (carouselResetFrameRef.current !== null) { window.cancelAnimationFrame(carouselResetFrameRef.current); } }, [], ); const handleFeatureOpen = (featureKey: string) => { if (featureKey === "script") { (onOpenScriptReview ?? onOpenGenerate)(); return; } if (featureKey === "token") { (onOpenTokenMonitor ?? onOpenGenerate)(); return; } if (featureKey === "ecommerce") { onOpenEcommerce(); return; } onOpenGenerate(); }; return ( <> {!splashDismissed && ( { sessionStorage.setItem("omniai:splash-seen", "1"); setSplashDismissed(true); }} /> )} {splashDismissed && ( )} OmniAI 创作中心 从灵感、生成、画布到商业素材,所有创作入口保持在一个安静的暗绿工作台里。 {carouselSlotOffsets.map((slotOffset) => { const itemIndex = getPositiveModulo(activeSlideIndex + slotOffset, HOME_CAROUSEL_IMAGES.length); const slide = HOME_CAROUSEL_IMAGES[itemIndex]; const visualOffset = slotOffset - (carouselMotion?.direction ?? 0) * (carouselMotion?.progress ?? 0); const isActive = visualOffset === 0; if (!slide) return null; return ( { if (!isActive) startCarouselShift(slotOffset); }} > ); })} 新手 老手 电商 {HOME_FEATURES.map((feature, index) => ( {feature.icon} {feature.eyebrow} {feature.title} {feature.description} handleFeatureOpen(feature.key)}> {feature.actionLabel} {feature.key === "script" ? ( ) : ( )} {feature.stats.map((item) => ( {item} ))} ))} Click To Experience 一站进入 OmniAI 选择入口,直接开始生成、评测、监控或电商作图。 {HOME_EXPERIENCE_POINTS.map((point) => ( {point.label} {point.meta} ))} 立即体验生成 体验电商生成 > ); } export default HomePage;
从灵感、生成、画布到商业素材,所有创作入口保持在一个安静的暗绿工作台里。
{feature.description}
选择入口,直接开始生成、评测、监控或电商作图。