import React, { useState, useEffect, useRef } from 'react'; import { IcAccessibility, IcClose, IcRotateCcw } from '../res/icons'; interface CaptchaModalProps { open: boolean; onClose: () => void; onSuccess: () => void; } export const CaptchaModal: React.FC = ({ open, onClose, onSuccess }) => { const [sliderValue, setSliderValue] = useState(0); const [isDragging, setIsDragging] = useState(false); const [success, setSuccess] = useState(false); const [refreshKey, setRefreshKey] = useState(0); const [targetPct, setTargetPct] = useState(() => 35 + Math.random() * 35); const [trackWidth, setTrackWidth] = useState(0); const sliderRef = useRef(null); useEffect(() => { if (open) { setSliderValue(0); setSuccess(false); setTargetPct(35 + Math.random() * 35); setRefreshKey(k => k + 1); } }, [open]); useEffect(() => { if (!open) return; const el = sliderRef.current; if (!el) return; const update = () => { const rect = el.getBoundingClientRect(); setTrackWidth(rect.width); }; update(); window.addEventListener('resize', update); return () => window.removeEventListener('resize', update); }, [open, refreshKey]); if (!open) return null; const handleDragStart = (e: React.MouseEvent | React.TouchEvent) => { setIsDragging(true); }; const handleDragMove = (e: React.MouseEvent | React.TouchEvent) => { if (!isDragging || !sliderRef.current) return; const clientX = 'touches' in e ? e.touches[0].clientX : (e as React.MouseEvent).clientX; const rect = sliderRef.current.getBoundingClientRect(); const knobWidth = 54; const usableWidth = Math.max(1, rect.width - knobWidth); const x = Math.max(0, Math.min(clientX - rect.left, usableWidth)); const percent = (x / usableWidth) * 100; setSliderValue(percent); }; const handleDragEnd = () => { if (!isDragging) return; setIsDragging(false); const piecePos = Math.min(78, Math.max(0, sliderValue * 0.78)); if (Math.abs(piecePos - targetPct) < 5) { setSuccess(true); setTimeout(() => { onSuccess(); }, 500); } else { setSliderValue(0); } }; const handleRefresh = () => { setSliderValue(0); setSuccess(false); setTargetPct(35 + Math.random() * 35); setRefreshKey(k => k + 1); }; const puzzleLeftPct = Math.min(72, Math.max(0, sliderValue * 0.78)); const knobWidth = 54; const usableWidth = Math.max(1, trackWidth - knobWidth); const knobLeftPx = Math.max(0, Math.min((sliderValue / 100) * usableWidth, usableWidth)); const progressWidthPx = Math.max(0, Math.min(knobLeftPx + knobWidth, trackWidth)); return (
安全验证
拖动下方滑块完成拼图
混元AI生成
{success ? '验证通过' : ''}
|||
); };