Просмотр исходного кода

feat: 从文档中的 toc_item 元素提取目录,支持层级推断

何文松 4 недель назад
Родитель
Сommit
27cea68dac
1 измененных файлов с 46 добавлено и 17 удалено
  1. 46 17
      frontend/vue-demo/src/views/Editor.vue

+ 46 - 17
frontend/vue-demo/src/views/Editor.vue

@@ -501,30 +501,41 @@ const tocItems = computed(() => {
   if (!blocks.value || blocks.value.length === 0) return items
   
   for (const block of blocks.value) {
-    // 检查是否是目录块
-    if (block.type === 'toc' && block.tocEntries) {
-      for (const entry of block.tocEntries) {
-        items.push({
-          level: entry.level || 1,
-          text: entry.title || entry.text,
-          page: entry.page,
-          blockId: block.id
-        })
+    // 遍历块中的元素,查找 toc_item 类型
+    if (block.elements && Array.isArray(block.elements)) {
+      for (const el of block.elements) {
+        if (el.type === 'toc_item') {
+          const text = el.content || el.text || ''
+          if (text.trim()) {
+            // 从文本中推断层级(根据开头数字格式)
+            const level = detectTocLevel(text.trim())
+            items.push({
+              level: level,
+              text: text.trim(),
+              page: el.style?.tocPageNum || '',
+              blockId: block.id
+            })
+          }
+        }
       }
     }
-    // 检查是否是标题块 (type: heading1, heading2, heading3...)
-    else if (block.type && block.type.startsWith('heading')) {
+    
+    // 也检查标题块作为备用 (type: heading1, heading2, heading3...)
+    if (block.type && block.type.startsWith('heading')) {
       const levelMatch = block.type.match(/heading(\d+)/)
       const level = levelMatch ? parseInt(levelMatch[1]) : 1
-      // 只提取1-3级标题
       if (level <= 3) {
         const text = block.plainText || getBlockPlainText(block)
         if (text && text.trim()) {
-          items.push({
-            level: level,
-            text: text.trim(),
-            blockId: block.id
-          })
+          // 避免重复添加(如果已经从 toc_item 中添加过)
+          const exists = items.some(item => item.text === text.trim())
+          if (!exists) {
+            items.push({
+              level: level,
+              text: text.trim(),
+              blockId: block.id
+            })
+          }
         }
       }
     }
@@ -532,6 +543,24 @@ const tocItems = computed(() => {
   return items
 })
 
+// 检测目录项层级(根据编号格式推断)
+function detectTocLevel(text) {
+  // 一级标题:1 xxx, 第一章 xxx
+  if (/^(\d+)\s+[^\d]/.test(text) || /^第[一二三四五六七八九十\d]+[章节部篇]/.test(text)) {
+    return 1
+  }
+  // 二级标题:1.1 xxx, 1-1 xxx
+  if (/^\d+\.\d+\s+/.test(text) || /^\d+-\d+\s+/.test(text)) {
+    return 2
+  }
+  // 三级标题:1.1.1 xxx
+  if (/^\d+\.\d+\.\d+\s+/.test(text)) {
+    return 3
+  }
+  // 默认一级
+  return 1
+}
+
 // 获取块的纯文本内容
 function getBlockPlainText(block) {
   if (!block.elements) return ''