@@ -6,6 +6,41 @@ interface FileUploadProps {
66    onFilesUploaded : ( files : FileInfo [ ] )  =>  void ; 
77} 
88
9+ const  getFilesFromDirectory  =  async  ( directory : FileSystemDirectoryEntry ) : Promise < File [ ] >  =>  { 
10+     return  new  Promise ( ( resolve )  =>  { 
11+         const  files : File [ ]  =  [ ] ; 
12+         const  reader  =  directory . createReader ( ) ; 
13+ 
14+         const  readEntries  =  ( )  =>  { 
15+             reader . readEntries ( async  ( entries )  =>  { 
16+                 if  ( ! entries . length )  { 
17+                     resolve ( files ) ; 
18+                 }  else  { 
19+                     await  Promise . all ( entries . map ( async  ( entry )  =>  { 
20+                         if  ( entry . isFile )  { 
21+                             await  new  Promise ( ( fileResolve )  =>  { 
22+                                 ( entry  as  FileSystemFileEntry ) . file ( ( file )  =>  { 
23+                                     const  mappedFile  =  new  File ( [ file ] ,  entry . fullPath ,  { 
24+                                         type : file . type , 
25+                                         lastModified : file . lastModified 
26+                                     } ) ; 
27+                                     files . push ( mappedFile ) ; 
28+                                     fileResolve ( null ) ; 
29+                                 } ) ; 
30+                             } ) ; 
31+                         }  else  if  ( entry . isDirectory )  { 
32+                             const  subFiles  =  await  getFilesFromDirectory ( entry  as  FileSystemDirectoryEntry ) ; 
33+                             files . push ( ...subFiles ) ; 
34+                         } 
35+                     } ) ) ; 
36+                     readEntries ( ) ; 
37+                 } 
38+             } ) ; 
39+         } ; 
40+         readEntries ( ) ; 
41+     } ) ; 
42+ } ; 
43+ 
944const  FileUpload : React . FC < FileUploadProps >  =  ( { onFilesUploaded} )  =>  { 
1045    const  [ isDragging ,  setIsDragging ]  =  useState ( false ) ; 
1146    const  fileInputRef  =  useRef < HTMLInputElement > ( null ) ; 
@@ -16,7 +51,7 @@ const FileUpload: React.FC<FileUploadProps> = ({onFilesUploaded}) => {
1651            reader . onload  =  ( e )  =>  { 
1752                resolve ( { 
1853                    name : file . name , 
19-                     path : ( file  as  any ) . path  ||  file . name ,   // 获取完整路径 
54+                     path : file . webkitRelativePath   ||   ( file  as  any ) . path  ||  file . name , 
2055                    size : file . size , 
2156                    extension : file . name . split ( '.' ) . pop ( )  ||  '' , 
2257                    content : e . target ?. result  as  string 
@@ -26,10 +61,32 @@ const FileUpload: React.FC<FileUploadProps> = ({onFilesUploaded}) => {
2661        } ) ; 
2762    } ; 
2863
64+     const  processEntries  =  async  ( items : DataTransferItemList )  =>  { 
65+         const  files : File [ ]  =  [ ] ; 
66+ 
67+         await  Promise . all ( Array . from ( items ) . map ( async  ( item )  =>  { 
68+             if  ( item . webkitGetAsEntry )  { 
69+                 const  entry  =  item . webkitGetAsEntry ( ) ; 
70+                 if  ( entry ?. isDirectory )  { 
71+                     const  directoryFiles  =  await  getFilesFromDirectory ( entry  as  FileSystemDirectoryEntry ) ; 
72+                     files . push ( ...directoryFiles ) ; 
73+                 }  else  if  ( entry ?. isFile )  { 
74+                     const  file  =  item . getAsFile ( ) ; 
75+                     if  ( file )  files . push ( file ) ; 
76+                 } 
77+             }  else  { 
78+                 const  file  =  item . getAsFile ( ) ; 
79+                 if  ( file )  files . push ( file ) ; 
80+             } 
81+         } ) ) ; 
82+ 
83+         return  files ; 
84+     } ; 
85+ 
2986    const  handleFileDrop  =  async  ( e : React . DragEvent )  =>  { 
3087        e . preventDefault ( ) ; 
3188        setIsDragging ( false ) ; 
32-         const  files  =  Array . from ( e . dataTransfer . files ) ; 
89+         const  files  =  await   processEntries ( e . dataTransfer . items ) ; 
3390        const  processedFiles  =  await  Promise . all ( files . map ( readFileContent ) ) ; 
3491        onFilesUploaded ( processedFiles ) ; 
3592    } ; 
@@ -38,16 +95,13 @@ const FileUpload: React.FC<FileUploadProps> = ({onFilesUploaded}) => {
3895        const  files  =  Array . from ( e . target . files  ||  [ ] ) ; 
3996        const  processedFiles  =  await  Promise . all ( files . map ( readFileContent ) ) ; 
4097        onFilesUploaded ( processedFiles ) ; 
41-         // 清空input值以允许重复选择相同文件 
4298        if  ( fileInputRef . current )  { 
4399            fileInputRef . current . value  =  '' ; 
44100        } 
45101    } ; 
46102
47103    const  handleClick  =  ( )  =>  { 
48-         if  ( fileInputRef . current )  { 
49-             fileInputRef . current . click ( ) ; 
50-         } 
104+         fileInputRef . current ?. click ( ) ; 
51105    } ; 
52106
53107    return  ( 
@@ -65,11 +119,12 @@ const FileUpload: React.FC<FileUploadProps> = ({onFilesUploaded}) => {
65119            < input 
66120                type = "file" 
67121                multiple 
122+                 // webkitdirectory="" 
68123                onChange = { handleFileSelect } 
69124                className = "file-input" 
70125                ref = { fileInputRef } 
71126            /> 
72-             < p > 拖放AI参考代码文件到这里或点击此处选择文件 (参考上下文越完整,AI推理结果越好)</ p > 
127+             < p > 拖放AI参考代码文件/文件夹到这里或点击此处选择 (参考上下文越完整,AI推理结果越好)</ p > 
73128        </ div > 
74129    ) ; 
75130} ; 
0 commit comments