import React, { useEffect, useRef, useState, RefObject } from "react"; import { motion, useAnimation, AnimatePresence } from "framer-motion"; import { TriangleAlert } from "lucide-react"; // 人物框组件 const PersonBox = React.forwardRef(({ person }, ref) => { return ( ); }); PersonBox.displayName = 'PersonBox'; export type PersonDetection = { id: string; name: string; position: { top: number; left: number; width: number; height: number; }; }; type Props = { backgroundImage?: string; videoSrc?: string; detections: PersonDetection[]; triggerScan: boolean; triggerSuccess: boolean; onScanStart?: (currentTime?: number) => void; onScanTimeout?: () => void; onScanExit?: () => void; // 扫描退出回调 scanTimeout?: number; isScanFailed?: boolean; // 外部传入的失败状态 onDetectionsChange?: (detections: PersonDetection[]) => void; onPersonClick?: (person: PersonDetection) => void; }; export const PersonDetectionScene: React.FC = ({ backgroundImage, videoSrc, detections, triggerScan, triggerSuccess, onScanStart, onScanTimeout, onScanExit, scanTimeout = 100000, isScanFailed = false, onDetectionsChange, onPersonClick }) => { const scanControls = useAnimation(); const videoRef = useRef(null); const [scanStatus, setScanStatus] = useState<'idle' | 'scanning' | 'timeout' | 'failed'>('idle'); const timeoutRef = useRef(); const exitTimeoutRef = useRef(); // 处理扫描状态 useEffect(() => { if (triggerScan && detections.length === 0) { setScanStatus('scanning'); // 设置超时定时器 timeoutRef.current = setTimeout(() => { setScanStatus('timeout'); onScanTimeout?.(); }, scanTimeout); } else { // 清除所有定时器 if (timeoutRef.current) { clearTimeout(timeoutRef.current); } if (exitTimeoutRef.current) { clearTimeout(exitTimeoutRef.current); } setScanStatus('idle'); } return () => { if (timeoutRef.current) { clearTimeout(timeoutRef.current); } if (exitTimeoutRef.current) { clearTimeout(exitTimeoutRef.current); } }; }, [triggerScan, detections.length, scanTimeout, onScanTimeout]); // 处理外部失败状态 useEffect(() => { if (isScanFailed && scanStatus === 'scanning') { console.log('roleRecognitionResponse---isScanFailed', isScanFailed); setScanStatus('failed'); } }, [isScanFailed, scanStatus]); // 处理失败/超时自动退出 useEffect(() => { if (scanStatus === 'timeout' || scanStatus === 'failed') { exitTimeoutRef.current = setTimeout(() => { setScanStatus('idle'); onScanExit?.(); }, 3000); } return () => { if (exitTimeoutRef.current) { clearTimeout(exitTimeoutRef.current); } }; }, [scanStatus, onScanExit]); // 处理视频/图片源变化 useEffect(() => { setScanStatus('idle'); if (timeoutRef.current) { clearTimeout(timeoutRef.current); } if (exitTimeoutRef.current) { clearTimeout(exitTimeoutRef.current); } }, [videoSrc, backgroundImage]); useEffect(() => { if (scanStatus !== 'idle') { if (videoRef.current) { videoRef.current.pause(); onScanStart?.(videoRef.current.currentTime); } else { onScanStart?.(); } scanControls.start({ opacity: [0, 1, 1, 0], scale: [0.98, 1, 1, 0.98], y: ["-120%", "120%"], transition: { duration: 3, repeat: Infinity, repeatType: "loop", times: [0, 0.2, 0.8, 1], ease: "easeInOut" } }); } else { scanControls.stop(); } }, [triggerScan, scanStatus, scanControls, onScanStart]); // 监听检测结果变化 useEffect(() => { onDetectionsChange?.(detections); }, [detections, onDetectionsChange]); const isShowError = scanStatus === 'timeout' || scanStatus === 'failed'; const isShowScan = scanStatus !== 'idle'; return (
{/* 背景层 */} {backgroundImage && (
)} {videoSrc && (