import { useLayoutEffect, useRef, useState, useCallback } from 'react'; import { useLanguage } from '../contexts/LanguageContext'; interface GlobalDragDropProps { onFilesSelected: (files: FileList) => void; isAdmin: boolean; } // 添加一个模块级变量来跟踪当前是否允许显示拖拽覆盖层 let isDragDropEnabled = true; // 添加一个模块级变量来存储强制隐藏的回调函数 let forceHideCallback: (() => void) | null = null; // 提供外部控制该状态的函数 export const setDragDropEnabled = (enabled: boolean) => { isDragDropEnabled = enabled; // 当禁用时,立即强制隐藏覆盖层 if (!enabled && forceHideCallback) { forceHideCallback(); } }; export const GlobalDragDropOverlay: React.FC = ({ onFilesSelected, isAdmin }) => { const { t } = useLanguage(); const overlayRef = useRef(null); const [isVisible, setIsVisible] = useState(false); const dragCounterRef = useRef(0); const isDragActiveRef = useRef(false); const hasFiles = useCallback((dt: DataTransfer | null) => { if (!dt) return false; // より厳格なチェック: typesにFilesが含まれることを確認 const hasFileType = dt.types && dt.types.includes('Files'); if (!hasFileType) return false; // itemsが存在する場合、実際にファイルがあるかチェック if (dt.items && dt.items.length > 0) { // 少なくとも1つのファイルアイテムがあることを確認 for (let i = 0; i < dt.items.length; i++) { if (dt.items[i].kind === 'file') { return true; } } return false; } // itemsがない場合はtypesのみで判断(後方互換性) return hasFileType; }, []); const handleDragEnter = useCallback((e: DragEvent) => { // 如果拖放功能被禁用,则忽略事件 if (!isDragDropEnabled) return; // 只有当数据传输包含文件时才处理 if (!hasFiles(e.dataTransfer)) return; e.preventDefault(); e.stopPropagation(); dragCounterRef.current++; if (dragCounterRef.current === 1) { // 立即显示覆盖层,依赖强制隐藏机制来处理误触发 setIsVisible(true); if (overlayRef.current) { overlayRef.current.style.opacity = '1'; overlayRef.current.style.visibility = 'visible'; } isDragActiveRef.current = true; } }, [hasFiles]); const handleDragOver = useCallback((e: DragEvent) => { // 如果拖放功能被禁用,则忽略事件 if (!isDragDropEnabled) return; // 只有当数据传输包含文件时才处理 if (!hasFiles(e.dataTransfer)) return; e.preventDefault(); e.stopPropagation(); e.dataTransfer!.dropEffect = 'copy'; }, [hasFiles]); const handleDragLeave = useCallback((e: DragEvent) => { // 如果拖放功能被禁用,则忽略事件 if (!isDragDropEnabled) return; // 只有当数据传输包含文件时才处理 if (!hasFiles(e.dataTransfer)) return; e.preventDefault(); e.stopPropagation(); dragCounterRef.current = Math.max(0, dragCounterRef.current - 1); if (dragCounterRef.current === 0 && isDragActiveRef.current) { // 隐藏全局拖拽上传覆盖层 if (overlayRef.current) { overlayRef.current.style.opacity = '0'; overlayRef.current.style.visibility = 'hidden'; } setIsVisible(false); // 通过状态控制隐藏 isDragActiveRef.current = false; } }, [hasFiles]); const handleDrop = useCallback((e: DragEvent) => { // 如果拖放功能被禁用,则忽略事件 if (!isDragDropEnabled) return; // 只有当数据传输包含文件时才处理 if (!hasFiles(e.dataTransfer)) return; e.preventDefault(); e.stopPropagation(); dragCounterRef.current = 0; // 隐藏全局拖拽上传覆盖层 if (overlayRef.current) { overlayRef.current.style.opacity = '0'; overlayRef.current.style.visibility = 'hidden'; } setIsVisible(false); isDragActiveRef.current = false; // 处理文件 if (e.dataTransfer?.files && e.dataTransfer.files.length > 0) { onFilesSelected(e.dataTransfer.files); } }, [hasFiles, onFilesSelected]); useLayoutEffect(() => { if (!isAdmin) return; // 初始化时确保dragCounter和isDragActive为初始值 dragCounterRef.current = 0; isDragActiveRef.current = false; // 注册强制隐藏回调 forceHideCallback = () => { dragCounterRef.current = 0; isDragActiveRef.current = false; setIsVisible(false); if (overlayRef.current) { overlayRef.current.style.opacity = '0'; overlayRef.current.style.visibility = 'hidden'; } }; // 添加全局事件监听器 document.addEventListener('dragenter', handleDragEnter); document.addEventListener('dragover', handleDragOver); document.addEventListener('dragleave', handleDragLeave); document.addEventListener('drop', handleDrop); // 清理函数 return () => { document.removeEventListener('dragenter', handleDragEnter); document.removeEventListener('dragover', handleDragOver); document.removeEventListener('dragleave', handleDragLeave); document.removeEventListener('drop', handleDrop); // 清除回调引用 forceHideCallback = null; // 确保在组件卸载时重置状态和清除任何可能的显示 dragCounterRef.current = 0; isDragActiveRef.current = false; if (overlayRef.current) { overlayRef.current.style.opacity = '0'; overlayRef.current.style.visibility = 'hidden'; } setIsVisible(false); }; }, [isAdmin, handleDragEnter, handleDragOver, handleDragLeave, handleDrop]); // 添加运行时检查,确保只有在适当情况下才渲染 if (!isAdmin || typeof window === 'undefined') { return null; } // 只有当 isVisible 为 true 时才渲染组件内容 if (!isVisible) { return null; } return (

{t('dragDropUploadTitle')}

{t('dragDropUploadDesc')}

{t('supportedFormats')}
PDF, DOC, XLS, PPT, TXT, Images...
); };