11import React , { useState , useEffect , useMemo } from 'react' ;
22import { MarkdownRenderer } from '../markdown/MarkdownRenderer' ;
33import { BacklinksPanel } from './BacklinksPanel' ;
4+ import { DocumentGraph } from './DocumentGraph' ;
45import { loadAllMarkdownFiles , loadFolderMarkdownFiles } from '../../utils/markdownIndex' ;
56import { filterMarkdownByLanguage } from '../../utils/i18nMarkdown' ;
67import { useI18n } from '../../i18n/I18nContext' ;
@@ -11,7 +12,8 @@ import {
1112 findDocumentById ,
1213 getDocumentPath as getDocPath ,
1314 buildBacklinksMap ,
14- getDocumentLinks
15+ getDocumentLinks ,
16+ enhanceDocument
1517} from '../../utils/documentCenter' ;
1618import styles from './DocumentCenter.module.css' ;
1719
@@ -46,6 +48,7 @@ export function DocumentCenter({
4648 className = ''
4749} ) {
4850 const [ documents , setDocuments ] = useState ( [ ] ) ;
51+ const [ allDocuments , setAllDocuments ] = useState ( [ ] ) ; // 所有文档索引,用于链接查找
4952 const [ selectedDoc , setSelectedDoc ] = useState ( null ) ;
5053 const [ loading , setLoading ] = useState ( true ) ;
5154 const [ error , setError ] = useState ( null ) ;
@@ -73,14 +76,19 @@ export function DocumentCenter({
7376 allFiles = await loadAllMarkdownFiles ( ) ;
7477 }
7578
79+ // 增强所有文档(用于全局查找)
80+ const allEnhanced = allFiles . map ( file => enhanceDocument ( file ) ) ;
81+ setAllDocuments ( allEnhanced ) ;
82+
7683 // 2. 根据类型过滤
84+ let filteredFiles = allFiles ;
7785 if ( type !== 'all' ) {
78- allFiles = filterDocumentsByType ( allFiles , type ) ;
86+ filteredFiles = filterDocumentsByType ( allFiles , type ) ;
7987 }
8088
8189 // 3. 根据集合过滤
8290 if ( collection ) {
83- allFiles = allFiles . filter ( file => {
91+ filteredFiles = filteredFiles . filter ( file => {
8492 // 检查 front matter 中的 collection 字段
8593 if ( file . collection === collection ) return true ;
8694 // 检查文件夹名称
@@ -90,29 +98,34 @@ export function DocumentCenter({
9098 }
9199
92100 // 4. 根据语言过滤
93- const filteredFiles = filterMarkdownByLanguage ( allFiles , language , 'zh' ) ;
101+ const languageFiltered = filterMarkdownByLanguage ( filteredFiles , language , 'zh' ) ;
94102
95103 // 5. 应用自定义过滤器
96104 let processedFiles = customFilter
97- ? filteredFiles . filter ( customFilter )
98- : filteredFiles ;
105+ ? languageFiltered . filter ( customFilter )
106+ : languageFiltered ;
99107
100108 // 6. 排序
101109 processedFiles = customSort
102110 ? sortDocuments ( processedFiles , customSort )
103111 : sortDocuments ( processedFiles ) ;
104112
105- console . log ( `文档中心加载: ${ processedFiles . length } 个文档 (类型: ${ type } , 集合: ${ collection || '全部' } )` ) ;
113+ // 7. 增强文档(添加 ID 和 metadata)
114+ const enhancedFiles = processedFiles . map ( file => enhanceDocument ( file ) ) ;
115+
116+ console . log ( `文档中心加载: ${ enhancedFiles . length } 个文档 (类型: ${ type } , 集合: ${ collection || '全部' } )` ) ;
117+ console . log ( '当前集合文档 ID:' , enhancedFiles . map ( d => d . id ) ) ;
118+ console . log ( '所有文档 ID:' , allEnhanced . map ( d => d . id ) ) ;
106119
107- setDocuments ( processedFiles ) ;
120+ setDocuments ( enhancedFiles ) ;
108121
109- // 构建反向链接映射
110- const linksMap = buildBacklinksMap ( processedFiles ) ;
122+ // 构建反向链接映射(使用所有文档)
123+ const linksMap = buildBacklinksMap ( allEnhanced ) ;
111124 setBacklinksMap ( linksMap ) ;
112125
113126 // 默认选择第一个文档
114- if ( processedFiles . length > 0 ) {
115- selectDocument ( processedFiles [ 0 ] ) ;
127+ if ( enhancedFiles . length > 0 ) {
128+ selectDocument ( enhancedFiles [ 0 ] ) ;
116129 }
117130 } catch ( err ) {
118131 console . error ( '加载文档失败:' , err ) ;
@@ -146,11 +159,41 @@ export function DocumentCenter({
146159 }
147160 }
148161
162+ // 处理内部链接点击(从文档内容中)
163+ function handleInternalLinkClick ( docId ) {
164+ console . log ( `点击内部链接, 目标 ID: ${ docId } ` ) ;
165+
166+ // 首先在当前集合中查找
167+ let targetDoc = documents . find ( d => d . id === docId ) ;
168+
169+ // 如果当前集合中没有,在所有文档中查找
170+ if ( ! targetDoc && allDocuments . length > 0 ) {
171+ targetDoc = allDocuments . find ( d => d . id === docId ) ;
172+ if ( targetDoc ) {
173+ console . log ( `在其他集合中找到目标文档: ${ targetDoc . title } (collection: ${ targetDoc . metadata ?. collection || targetDoc . folder } )` ) ;
174+ // 将该文档添加到当前文档列表(临时)
175+ setDocuments ( prev => [ ...prev , targetDoc ] ) ;
176+ }
177+ }
178+
179+ if ( targetDoc ) {
180+ console . log ( `找到目标文档: ${ targetDoc . title } ` ) ;
181+ selectDocument ( targetDoc ) ;
182+ // 滚动到顶部
183+ window . scrollTo ( { top : 0 , behavior : 'smooth' } ) ;
184+ } else {
185+ console . warn ( `无法找到文档 ID: ${ docId } ` ) ;
186+ console . log ( `当前集合文档 ID:` , documents . map ( d => `${ d . id } (${ d . title } )` ) ) ;
187+ console . log ( `所有文档 ID:` , allDocuments . map ( d => `${ d . id } (${ d . title } )` ) ) ;
188+ }
189+ }
190+
149191 // 获取当前文档的链接信息
150192 const currentDocLinks = useMemo ( ( ) => {
151193 if ( ! selectedDoc ) return { outgoing : [ ] , incoming : [ ] } ;
152- return getDocumentLinks ( selectedDoc , backlinksMap , documents ) ;
153- } , [ selectedDoc , backlinksMap , documents ] ) ;
194+ // 使用所有文档来获取链接信息
195+ return getDocumentLinks ( selectedDoc , backlinksMap , allDocuments ) ;
196+ } , [ selectedDoc , backlinksMap , allDocuments ] ) ;
154197
155198 // 切换树节点展开/折叠
156199 function toggleNode ( nodeId ) {
@@ -315,6 +358,16 @@ export function DocumentCenter({
315358 { t ( 'documentCenter.navigation' ) }
316359 </ h2 >
317360 { renderDocumentList ( ) }
361+
362+ { /* 引用关系图谱 - 放在侧边栏底部 */ }
363+ { selectedDoc && (
364+ < DocumentGraph
365+ currentDoc = { selectedDoc }
366+ backlinksMap = { backlinksMap }
367+ allDocuments = { allDocuments }
368+ onNodeClick = { handleInternalLinkClick }
369+ />
370+ ) }
318371 </ aside >
319372 ) }
320373
@@ -339,7 +392,10 @@ export function DocumentCenter({
339392 ) }
340393 </ div >
341394 ) }
342- < MarkdownRenderer content = { selectedDoc . content } />
395+ < MarkdownRenderer
396+ content = { selectedDoc . content }
397+ onInternalLinkClick = { handleInternalLinkClick }
398+ />
343399
344400 { /* 双向链接面板 */ }
345401 < BacklinksPanel
0 commit comments