@@ -18,27 +18,47 @@ export function useClipImport() {
1818 const [ clipLoading , setClipLoading ] = useState ( false ) ;
1919
2020 const handleClipUrl = useCallback ( async ( ) => {
21- if ( ! clipUrl . trim ( ) || ! window . electronAPI ?. invoke ) return ;
21+ if ( ! clipUrl . trim ( ) ) return ;
2222 setClipLoading ( true ) ;
2323 try {
24- const result = await window . electronAPI . invoke ( 'import:fetch-url' , { url : clipUrl . trim ( ) } ) as { success : boolean ; content ?: { title : string ; text : string } ; error ?: string } ;
25- if ( result . success && result . content ) {
26- const { title, text } = result . content ;
27- await createNote ( { title : title . slice ( 0 , 100 ) , content : text , template : 'blank' , folderId : selectedFolderId ?? undefined } ) ;
28- toast ( { type : 'success' , message : `网页已剪藏为笔记:${ title . slice ( 0 , 30 ) } ` , silent : true } ) ;
29- setClipUrl ( '' ) ;
24+ let title = '' ;
25+ let text = '' ;
26+ if ( window . electronAPI ?. invoke ) {
27+ // Electron:主进程 fetch(无 CORS 限制)+ 解析
28+ const result = await window . electronAPI . invoke ( 'import:fetch-url' , { url : clipUrl . trim ( ) } ) as { success : boolean ; content ?: { title : string ; text : string } ; error ?: string } ;
29+ if ( ! result . success || ! result . content ) {
30+ toast ( { type : 'warning' , message : result . error || '剪藏失败,请手动粘贴内容' } ) ;
31+ return ;
32+ }
33+ title = result . content . title ;
34+ text = result . content . text ;
3035 } else {
31- toast ( { type : 'warning' , message : result . error || '剪藏失败,请手动粘贴内容' } ) ;
36+ // PWA/浏览器:直接 fetch + DOMParser 提取标题与正文(受 CORS 限制,
37+ // 目标站点不允许跨域时抛出并降级为手动粘贴提示)
38+ const resp = await fetch ( clipUrl . trim ( ) , { signal : AbortSignal . timeout ( 10000 ) } ) ;
39+ if ( ! resp . ok ) throw new Error ( `HTTP ${ resp . status } ` ) ;
40+ const html = await resp . text ( ) ;
41+ const doc = new DOMParser ( ) . parseFromString ( html , 'text/html' ) ;
42+ title = doc . title || new URL ( clipUrl . trim ( ) ) . hostname ;
43+ text = doc . body ?. innerText ?. trim ( ) ?? '' ;
44+ if ( ! text ) throw new Error ( 'empty page' ) ;
3245 }
46+ await createNote ( { title : title . slice ( 0 , 100 ) || '未命名剪藏' , content : text , template : 'blank' , folderId : selectedFolderId ?? undefined } ) ;
47+ toast ( { type : 'success' , message : `网页已剪藏为笔记:${ title . slice ( 0 , 30 ) } ` , silent : true } ) ;
48+ setClipUrl ( '' ) ;
3349 } catch {
34- toast ( { type : 'error ' , message : '剪藏失败,请检查网络或手动粘贴 ' } ) ;
50+ toast ( { type : 'warning ' , message : '剪藏失败:该网站不允许直接抓取,请手动复制内容 ' } ) ;
3551 } finally {
3652 setClipLoading ( false ) ;
3753 }
3854 } , [ clipUrl , createNote , selectedFolderId , toast ] ) ;
3955
4056 const handleClipPdf = useCallback ( async ( ) => {
41- if ( ! window . electronAPI ?. invoke ) return ;
57+ if ( ! window . electronAPI ?. invoke ) {
58+ // PWA/浏览器:明确降级提示(浏览器无内置 PDF 文本解析,MVP 阶段引导桌面端导入)
59+ toast ( { type : 'warning' , message : '移动端暂不支持 PDF 直接导入,请用桌面端导入或复制文本' } ) ;
60+ return ;
61+ }
4262 setClipLoading ( true ) ;
4363 try {
4464 const result = await window . electronAPI . invoke ( 'import:parse-pdf' ) as { success : boolean ; content ?: { title : string ; text : string } ; canceled ?: boolean ; error ?: string } ;
0 commit comments