"use client"; import { useState, useRef, useEffect } from "react"; import { motion, AnimatePresence } from "framer-motion"; import { X, Maximize2, Minimize2 } from "lucide-react"; import clsx from "clsx"; // 展台四模块视频配置(请将对应 mp4/webm 文件放入 public/videos/ 下) const videos = [ { key: "mechanics", title: "力学 · 单摆高精度测量", src: "/videos/mechanics.mp4", desc: "CV 追踪 + AI 拟合:g 误差压至 0.43%,提取阻尼 γ 与品质因数 Q。探究傅科摆效应。" }, { key: "circuit", title: "电路 · 实物 → 虚拟转换", src: "/videos/circuit.mp4", desc: "YOLO 识别元件与连线,自动生成可交互虚拟电路 + AI 问答辅导。" }, { key: "electromag", title: "电磁 · 能量转换优化", src: "/videos/electromag.mp4", desc: "视觉 + 单片机测电磁转换效率 + 未来 BO/RL 迭代脉冲参数,提高加速/制动能量效率。" }, { key: "optics", title: "光学 · 分光计智能辅助", src: "/videos/optics.mp4", desc: "十字像追踪 + 分步引导 + PID 调节。" } ]; interface VideoStateRef { currentTime: number; wasPlaying: boolean; } export default function ExpoPage() { const [active, setActive] = useState(null); const [isFullscreen, setIsFullscreen] = useState(false); const timeRefs = useRef>({}); const containerRefs = useRef>({}); const mainRef = useRef(null); // 记录时间用于在放大时继续播放(非严格同步,够展示用) const handleBeforeExpand = (key: string) => { const vid = containerRefs.current[key]; if (vid) { timeRefs.current[key] = { currentTime: vid.currentTime, wasPlaying: !vid.paused }; } setActive(key); }; const handleRestore = () => { setActive(null); }; // 在放大的 video 元素上恢复播放进度 const expandedVideoRef = useRef(null); useEffect(() => { if (active && expandedVideoRef.current) { const state = timeRefs.current[active]; if (state) { try { expandedVideoRef.current.currentTime = state.currentTime; } catch (_) { /* Safari 某些情况下可能阻止精确跳转,忽略 */ } if (state.wasPlaying) expandedVideoRef.current.play().catch(() => {}); } } }, [active]); // ESC 关闭 useEffect(() => { const onKey = (e: KeyboardEvent) => { if (e.key === "Escape" && active) setActive(null); }; window.addEventListener("keydown", onKey); return () => window.removeEventListener("keydown", onKey); }, [active]); // Fullscreen 监听 useEffect(() => { const handler = () => { const fsEl = document.fullscreenElement || (document as any).webkitFullscreenElement; setIsFullscreen(!!fsEl); }; document.addEventListener("fullscreenchange", handler); document.addEventListener("webkitfullscreenchange", handler as any); return () => { document.removeEventListener("fullscreenchange", handler); document.removeEventListener("webkitfullscreenchange", handler as any); }; }, []); const enterFs = async () => { const el = mainRef.current; if (!el) return; try { if (el.requestFullscreen) await el.requestFullscreen(); else if ((el as any).webkitRequestFullscreen) (el as any).webkitRequestFullscreen(); } catch (_) { /* ignore */ } }; const exitFs = async () => { try { if (document.exitFullscreen) await document.exitFullscreen(); else if ((document as any).webkitExitFullscreen) (document as any).webkitExitFullscreen(); } catch (_) { /* ignore */ } }; const toggleFs = () => { if (isFullscreen) exitFs(); else enterFs(); }; return (
{/* 全屏按钮 */} {/* 2x2 全屏栅格 */}
{videos.map(v => ( handleBeforeExpand(v.key)} > ))}
{active && ( <> {videos.filter(v => v.key === active).map(v => (
{/* 居中容器:使用 max-* 避免视频固有尺寸撑大父容器 */}
))} )}
); }