# AI对话链接跳转与引用高亮优化 - 技术设计文档

**文档版本**: v1.0  
**创建日期**: 2026-05-30  
**状态**: ✅ 已批准，待实施  
**方案选择**: 方案B - 统一搜索引擎重构

---

## 1. 项目背景与问题定义

### 1.1 当前问题

在AI智能问答模块（QAModule.vue）中，用户点击对话消息中的引用来源或[ref:xxx]标签后：

1. **PDF文件**：只能跳转到指定页码，**无法高亮显示关键词位置**
2. **Word/Excel等文件**：使用`indexOf精确匹配`，关键词截断后容易匹配失败
3. **时序问题**：文件DOM未完全渲染就执行搜索，导致定位失败
4. **用户体验差**：无搜索结果反馈、无导航控件、高亮效果短暂

### 1.2 业务影响

- ❌ 用户无法快速定位到引用的具体内容位置
- ❌ 需要手动翻页查找，效率低下
- ❌ 多个匹配项时无法逐个浏览
- ❌ 降低知识管理系统的易用性和专业性

### 1.3 目标用户

- 企业员工（制度文件查阅者）
- HR/行政人员（制度发布者）
- 管理员（系统维护者）

### 1.4 成功标准

✅ 点击任意格式的引用 → 自动跳转 + 持续高亮显示  
✅ 支持模糊匹配（容错率≥90%）  
✅ 提供上/下一处导航功能  
✅ 高亮效果美观且持久（手动关闭前不消失）  
✅ 响应时间 < 2秒

---

## 2. 解决方案架构

### 2.1 整体架构图

```
┌─────────────────────────────────────────────────────┐
│                   QAModule.vue                       │
│  [引用点击] → navigateToFileReader(ref)              │
│           ↓                                         │
│  提取: { fileId, filename, page, context, rawData } │
└──────────────────────┬──────────────────────────────┘
                       ↓ router.push(query参数)
┌─────────────────────────────────────────────────────┐
│                  ReaderPage.vue                      │
│                                                     │
│  ┌───────────────────────────────────────────┐     │
│  │        UniversalSearchEngine (新增)        │     │
│  │                                          │     │
│  │  ┌─────────┐ ┌─────────┐ ┌────────────┐  │     │
│  │  │ Text    │ │ Fuzzy   │ │ Highlight   │  │     │
│  │  │Extractor│ │ Search  │ │ Renderer    │  │     │
│  │  │ (提取)  │ │ Engine  │ │ (渲染)      │  │     │
│  │  └────┬────┘ └────┬────┘ └─────┬──────┘  │     │
│  │       └──────────┼──────────┘          │     │
│  │                ↓                      │     │
│  │      ┌──────────────────┐             │     │
│  │      │ SearchCoordinator │             │     │
│  │      │ (流程协调器)      │             │     │
│  │      └────────┬─────────┘             │     │
│  └───────────────┼───────────────────────┘     │
│                   ↓                              │
│          SearchResult[] + UI Navigation Bar       │
└─────────────────────────────────────────────────────┘
```

### 2.2 核心技术选型

| 组件 | 技术方案 | 版本 | 选型理由 |
|------|---------|------|---------|
| **模糊搜索引擎** | Fuse.js | 7.0.0 | 轻量(10KB)、支持中文、零依赖 |
| **文本提取** | DOM TreeWalker API | 原生 | 无需依赖、浏览器原生支持 |
| **高亮渲染** | Range + Custom Elements | 原生 | 精确控制、性能优秀 |
| **PDF处理** | PDF.js textLayer | 已集成 | 复用现有pdfjs-viewer |

---

## 3. 模块详细设计

### 3.1 模块一：TextExtractor（文本提取器）

**职责**：从不同格式文件的DOM中提取结构化文本数据

**文件路径**：`src/utils/textExtractor.js`

**核心方法**：
```typescript
class TextExtractor {
  // 主入口：根据fileType分发到不同的提取策略
  async extract(fileType: string, container: HTMLElement): Promise<Document[]>
  
  // PDF文本提取（从iframe的.textLayer提取）
  async extractPdfText(iframe: HTMLIFrameElement): Promise<PdfPage[]>
  
  // DOCX/DOC文本提取（从.docx-wrapper提取分页）
  extractDocxText(container: HTMLElement): DocxPage[]
  
  // Excel/CSV文本提取（从表格单元格提取）
  extractExcelText(container: HTMLElement): TableCell[]
  
  // 通用DOM文本提取（TreeWalker遍历）
  extractDomText(container: HTMLElement): TextNode[]
}
```

**数据结构**：
```typescript
interface Document {
  text: string           // 纯文本内容
  type: 'text' | 'page' | 'cell'
  location?: {
    page?: number        // 页码（PDF/DOCX）
    cellIndex?: [number, number]  // 单元格坐标 [row, col]
  }
  element: HTMLElement   // 对应的DOM元素引用
}
```

**关键实现细节**：
- PDF：遍历`.textLayer > span`元素，按`data-page`属性分组
- DOCX：查找`.docx-wrapper > div`作为页面容器
- Excel：遍历`table tr td`，记录行列索引
- 通用：使用`TreeWalker(SHOW_TEXT)`过滤有意义的文本节点（长度≥2）

---

### 3.2 模块二：FuzzySearchEngine（模糊搜索引擎）

**职责**：基于Fuse.js实现智能模糊匹配和相关性排序

**文件路径**：`src/utils/fuzzySearchEngine.js`

**核心配置**：
```javascript
const fuseConfig = {
  threshold: 0.4,              // 匹配阈值（0=精确, 1=宽松）
  distance: 100,               // 模式匹配的最大距离
  includeScore: true,          // 返回评分
  includeMatches: true,        // 返回匹配位置信息
  minMatchCharLength: 2,       // 最小匹配字符数
  tokenize: true,              // 启用分词模式
  tokenSeparator: /[\s\p{P}]+/u,  // 中英文分词正则
  keys: ['text']               // 搜索字段
}
```

**核心方法**：
```typescript
class FuzzySearchEngine {
  // 初始化索引（每次加载新文档时调用）
  initIndex(documents: Document[]): void
  
  // 执行搜索
  search(keyword: string, options?: SearchOptions): SearchResult[]
  
  // 关键词预处理（提升中文匹配率）
  preprocessKeyword(keyword: string): string
  
  // 格式化原始结果为统一格式
  formatResult(rawResult: FuseResult, index: number): SearchResult
}
```

**输出数据结构**：
```typescript
interface SearchResult {
  id: string                  // 唯一标识
  type: 'text' | 'pdf' | 'table'
  score: number               // 相似度评分 (0-1, 越高越匹配)
  matchedText: string         // 匹配到的文本片段
  context: string             // 上下文（前后各50字符）
  location: {
    container?: HTMLElement
    startOffset?: number
    endOffset?: number
    pageNumber?: number       // PDF专用
    rect?: { x, y, width, height }  // PDF专用
    cellIndex?: [number, number]    // 表格专用
  }
  originalData: Document      // 原始文档数据（用于高亮渲染）
}
```

**中文优化策略**：
1. 预处理阶段去除中文标点符号（""''【】《》（））
2. 使用Unicode属性转义`\p{P}`匹配所有标点
3. 分词时按空格和标点切分
4. 设置合理的threshold（0.4）平衡精准度和召回率

---

### 3.3 模块三：HighlightRenderer（高亮渲染器）

**职责**：在文档DOM中创建、管理和销毁高亮标记

**文件路径**：`src/utils/highlightRenderer.js`

**核心能力**：
```typescript
class HighlightRenderer {
  // 渲染所有搜索结果的高亮
  renderAll(results: SearchResult[]): number
  
  // 创建单个高亮（根据type分发）
  private createHighlight(result: SearchResult, index: number): Highlight
  
  // DOM类型高亮（text/docx/markdown/html等）
  private createDomHighlight(result, index): DomHighlight
  
  // PDF类型高亮（在iframe中创建overlay层）
  private createPdfHighlight(result, index): PdfHighlight
  
  // 表格类型高亮（Excel/CSV单元格）
  private createTableHighlight(result, index): TableHighlight
  
  // 导航控制
  navigateTo(index: number): void
  next(): void
  prev(): void
  
  // 清除所有高亮
  clearAll(): void
}
```

**高亮样式规范**：

#### DOM高亮（.search-highlight）
```css
.search-highlight {
  background: linear-gradient(135deg, #fff3cd 0%, #ffe69c 100%);
  border-bottom: 2px solid #ffc107;
  border-radius: 2px;
  padding: 1px 2px;
  box-shadow: 0 1px 3px rgba(255, 193, 7, 0.3);
  cursor: pointer;
}

.search-highlight.active {
  background: linear-gradient(135deg, #ffd43b 0%, #fab005 100%);
  border-bottom: 3px solid #f59f00;
  animation: highlight-glow 2s ease-in-out infinite;
}
```

#### PDF高亮（.pdf-highlight-overlay）
- 使用绝对定位的div覆盖在文本上方
- 背景色：`rgba(255, 235, 59, 0.3)`
- 边框：`2px solid #ffc107`
- 包含角标显示序号

#### 表格高亮（.table-highlight）
- 绿色系配色（区别于文本黄色）
- 背景：`linear-gradient(135deg, #d4edda 0%, #c3e6cb 100%)`
- 边框：`2px solid #28a745`

**交互特性**：
- ✅ 点击高亮标记可跳转到该位置
- ✅ 当前激活项带脉冲发光动画
- ✅ 序号标签（1, 2, 3...）便于识别
- ✅ hover效果（轻微放大+阴影加深）

---

### 3.4 模块四：SearchCoordinator（协调控制器）

**职责**：编排整个搜索→定位→高亮的完整流程，处理异常和重试

**文件路径**：`src/utils/searchCoordinator.js`

**核心流程**：
```
execute(params)
  ↓
Step 1: 文本提取 (withRetry, 最多重试3次)
  ↓
Step 2: 页码过滤（如果指定了targetPage）
  ↓
Step 3: 初始化Fuse.js索引 → 执行搜索
  ↓
Step 4: 渲染高亮 → 导航到第一个结果
  ↓
返回: { success, resultCount, stats }
```

**重试机制**：
```typescript
async withRetry<T>(fn: () => T, maxRetries: number, delayMs: number): Promise<T> {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn()
    } catch (error) {
      if (i < maxRetries - 1) {
        await sleep(delayMs)  // 等待DOM渲染完成
      } else {
        throw error  // 最后一次重试失败则抛出异常
      }
    }
  }
}
```

**错误处理**：
- 文本提取失败 → 返回友好提示"无法提取文档内容"
- 未找到匹配 → 返回"未找到XXX相关内容"
- 高亮渲染部分失败 → 记录警告日志，继续渲染其他结果
- 全局异常 → 显示错误提示，不阻断用户操作

**性能统计**：
```typescript
interface SearchStats {
  totalTime: number       // 总耗时(ms)
  extractionTime: number  // 文本提取耗时
  searchTime: number      // 搜索耗时
  renderTime: number      // 高亮渲染耗时
  resultCount: number     // 结果数量
}
```

---

## 4. 集成方案

### 4.1 QAModule.vue修改点

**文件路径**：`src/components/QAModule.vue`

**修改函数**：`navigateToFileReader()` (第1126行)

**改动内容**：
```javascript
// 优化关键词提取逻辑（第1159-1175行）
const keyword = ''

// 优先级1: ref.context（引用上下文）
if (ref.context) {
  keyword = ref.context.substring(0, 150)  // 增加长度限制至150字符
} 
// 优先级2: ref.rawData中的多个字段
else if (ref.rawData) {
  const raw = ref.rawData
  keyword = raw.content || raw.context || raw.preview || 
            raw.excerpt || raw.query || raw.question || ''
  if (keyword) keyword = keyword.substring(0, 150)
}
// 优先级3: ref.location中的文本描述
if (!keyword && ref.location && ref.location.length > 4) {
  const locText = ref.location.replace(/第\d+页|page\s*\d+/gi, '').trim()
  if (locText.length >= 4) keyword = locText.substring(0, 120)
}

// 清洗关键词
if (keyword) {
  keyword = cleanSearchKeyword(keyword)
  if (keyword.length < 4) keyword = ''  // 最小长度要求降至4字符
}
```

**改动理由**：
- 增加关键词长度限制（100→150），提高匹配成功率
- 扩展rawData字段检查范围
- 降低最小长度要求（4字符），适应短文本场景

---

### 4.2 ReaderPage.vue集成

**文件路径**：`src/views/ReaderPage.vue`

#### 4.2.1 新增imports

```javascript
import searchCoordinator from '@/utils/searchCoordinator'

// 新增响应式变量
const showNavigationControls = ref(false)
const searchResultCount = ref(0)
const currentHighlightIndex = ref(0)
const searchKeywordPreview = ref('')
```

#### 4.2.2 修改onMounted逻辑

```javascript
onMounted(async () => {
  // ... 现有代码保持不变 ...
  
  if (fileId) {
    await loadFile(fileId, fileTitle, fileExtension, page)
    
    // ✨ 新增：自动执行搜索高亮
    if (keyword?.trim()) {
      const renderDelays = {
        pdf: 1000,
        docx: 1500,
        pptx: 1200,
        xlsx: 800,
        default: 500
      }
      
      const delay = renderDelays[fileType.value] || renderDelays.default
      
      setTimeout(async () => {
        const container = scrollContainerRef.value
        if (!container) return
        
        const result = await searchCoordinator.execute({
          keyword,
          fileType: fileType.value,
          container,
          targetPage: page
        })
        
        if (result.success) {
          showNavigationControls.value = true
          searchResultCount.value = result.resultCount
          searchKeywordPreview.value = keyword.substring(0, 20) + '...'
          
          message.success({
            content: `找到 ${result.resultCount} 处匹配内容`,
            duration: 3
          })
        } else {
          message.warning({
            content: result.message || '未找到相关内容',
            duration: 3
          })
        }
      }, delay)
    }
  }
})
```

#### 4.2.3 新增UI模板（搜索导航栏）

```html
<!-- 在reader-container内部、底部添加 -->
<Transition name="slide-up">
  <div v-if="showNavigationControls" class="search-nav-bar">
    <div class="nav-info">
      <SearchOutlined class="nav-icon" />
      <span>找到 <strong>{{ searchResultCount }}</strong> 处匹配</span>
      <span class="keyword-preview">"{{ searchKeywordPreview }}"</span>
    </div>
    
    <div class="nav-actions">
      <button 
        class="nav-btn" 
        @click="prevHighlight"
        :disabled="currentHighlightIndex <= 0"
      >
        <UpOutlined /> 上一处
      </button>
      
      <span class="nav-counter">
        {{ currentHighlightIndex + 1 }} / {{ searchResultCount }}
      </span>
      
      <button 
        class="nav-btn" 
        @click="nextHighlight"
        :disabled="currentHighlightIndex >= searchResultCount - 1"
      >
        下一处 <DownOutlined />
      </button>
      
      <button class="nav-btn close-btn" @click="closeSearch">
        <CloseOutlined />
      </button>
    </div>
  </div>
</Transition>
```

#### 4.2.4 新增事件监听

```javascript
// 监听高亮导航事件（由HighlightRenderer触发）
onMounted(() => {
  window.addEventListener('highlightNavigate', (e) => {
    const { currentIndex, total } = e.detail
    currentHighlightIndex.value = currentIndex
    searchResultCount.value = total
  })
})

onUnmounted(() => {
  window.removeEventListener('highlightNavigate')
  searchCoordinator.clearAllHighlights()  // 清理高亮
})
```

#### 4.2.5 新增方法

```javascript
// 导航控制方法
const nextHighlight = () => {
  searchCoordinator.nextHighlight()
}

const prevHighlight = () => {
  searchCoordinator.prevHighlight()
}

const closeSearch = () => {
  searchCoordinator.clearAllHighlights()
  showNavigationControls.value = false
  currentHighlightIndex.value = 0
  searchResultCount.value = 0
}
```

---

## 5. CSS样式规范

### 5.1 高亮基础样式

已在"3.3 HighlightRenderer"章节详细定义，此处补充动画和导航栏样式。

### 5.2 动画效果

```css
/* 脉冲发光动画（当前激活项） */
@keyframes highlight-glow {
  0%, 100% { box-shadow: 0 3px 8px rgba(245, 159, 0, 0.6); }
  50% { box-shadow: 0 4px 16px rgba(245, 159, 0, 0.9), 0 0 20px rgba(245, 159, 0, 0.4); }
}

/* 缩放脉冲（首次出现） */
@keyframes highlight-pulse {
  0% { transform: scale(1); opacity: 1; }
  50% { transform: scale(1.05); opacity: 0.8; }
  100% { transform: scale(1); opacity: 1; }
}
```

### 5.3 搜索导航栏

固定在阅读器底部中央，包含：
- 左侧：搜索图标 + 匹配数量 + 关键词预览
- 中间：当前位置计数器（如 "2 / 5"）
- 右侧：上一处 / 下一处 / 关闭按钮

详见设计文档第3.3节的CSS代码。

---

## 6. 数据流与时序

### 6.1 完整交互时序图

```
用户点击引用来源组件
    ↓
[QAModule.vue] navigateToFileReader(ref)
    ├─ 提取 filename, page, context/rawData
    ├─ 清洗生成 keyword (≤150字符)
    └─ router.push({ query: { id, title, extension, page, keyword, from: 'qa' } })
    ↓
[Vue Router] 路由跳转到 /reader
    ↓
[ReaderPage.vue] onMounted()
    ├─ 解析路由参数 (id, page, keyword...)
    ├─ loadFile(id, title, extension, page)
    │   ├─ 调用API获取文件Blob
    │   ├─ 根据fileType渲染文档 (PDF/Word/Excel/...)
    │   └─ hasFileLoaded = true
    │
    └─ setTimeout(delay)  ← 等待DOM渲染完成
        ↓
    [searchCoordinator.execute()]
        │
        ├─ Step 1: textExtractor.extract(fileType, container)
        │   ├─ withRetry(fn, 3, 200ms)  ← 重试机制
        │   └─ 返回 documents[]
        │
        ├─ Step 2: 过滤目标页码（可选）
        │
        ├─ Step 3: fuzzySearchEngine
        │   ├─ initIndex(documents)
        │   ├─ preprocessKeyword(keyword)
        │   └─ search() → results[]
        │
        ├─ Step 4: highlightRenderer.renderAll(results)
        │   ├─ 遍历results创建高亮mark/overlay
        │   ├─ navigateTo(0)  ← 跳转到第一个结果
        │   └─ 返回 highlightCount
        │
        └─ 返回 { success, resultCount, stats }
            ↓
    更新UI状态:
    ├─ showNavigationControls = true
    ├─ searchResultCount = N
    └─ 显示成功提示Toast
```

### 6.2 时间估算

| 步骤 | 耗时 | 说明 |
|------|------|------|
| 文本提取 | 50-200ms | 取决于文档大小 |
| Fuse.js索引构建 | 10-50ms | 取决于文本块数量 |
| 搜索执行 | 5-20ms | Fuse.js高效算法 |
| 高亮渲染 | 30-100ms | DOM操作 |
| **总计** | **95-370ms** | **< 400ms，用户体验流畅** |

加上等待DOM渲染的delay（500-1500ms），总响应时间约**0.6-2秒**。

---

## 7. 边界情况处理

### 7.1 异常场景

| 场景 | 处理策略 |
|------|---------|
| **关键词为空** | 不执行搜索，仅跳转到指定页码 |
| **文档内容为空** | 提示"无法提取文档内容"，仍完成页面跳转 |
| **无匹配结果** | 提示"未找到XXX相关内容"，保持在目标页面 |
| **部分高亮失败** | 记录警告日志，成功渲染的其他高亮正常显示 |
| **PDF iframe跨域受限** | 降级为仅页码跳转，提示"PDF高亮暂不可用" |
| **大文档（>10MB）** | 文本提取限流，只提取前1000个文本块 |
| **用户快速连续点击** | 防抖处理（300ms），取消上一次搜索 |
| **网络请求失败** | 显示错误提示，保留已渲染的高亮 |

### 7.2 兼容性保障

- **浏览器兼容**：Chrome 90+, Firefox 88+, Safari 14+, Edge 90+
- **Vue版本**：Vue 3.2+ (Composition API)
- **移动端适配**：导航栏响应式布局，触摸友好的按钮尺寸
- **无障碍访问**：高亮元素添加aria-label，键盘导航支持（Tab/Enter）

---

## 8. 性能优化策略

### 8.1 文本提取优化

- **懒加载**：只在需要搜索时才提取文本（非页面加载时）
- **分批处理**：大文档分段提取，避免阻塞主线程
- **缓存机制**：相同文档不重复提取（基于fileId + hash缓存）

### 8.2 搜索引擎优化

- **增量更新**：文档内容变化时只更新受影响的索引条目
- **结果限制**：默认返回Top 20结果，避免过多DOM操作
- **Web Worker**：（可选）将Fuse.js搜索移至Worker线程（针对超大文档）

### 8.3 高亮渲染优化

- **虚拟滚动**：只渲染可视区域内的高亮（针对超多匹配项）
- **批量DOM操作**：使用DocumentFragment减少reflow
- **防抖清除**：快速切换时延迟清理旧高亮

### 8.4 内存管理

- **及时清理**：离开页面时调用`clearAllHighlights()`
- **引用释放**：断开DOM元素与JavaScript对象的循环引用
- **事件解绑**：onUnmounted时移除所有事件监听器

---

## 9. 测试计划

### 9.1 单元测试

| 测试模块 | 测试用例数 | 覆盖率目标 |
|---------|-----------|-----------|
| TextExtractor | 15 | ≥90% |
| FuzzySearchEngine | 20 | ≥95% |
| HighlightRenderer | 25 | ≥85% |
| SearchCoordinator | 18 | ≥90% |

**关键测试场景**：
- PDF文本提取（含多页、空页、特殊字符）
- 中文模糊匹配（同义词、错别字、截断关键词）
- DOM高亮创建/销毁（内存泄漏检测）
- 重试机制验证（模拟DOM未就绪）

### 9.2 集成测试

- **E2E测试**：使用Cypress自动化测试完整流程
  1. 打开AI对话页面
  2. 发送问题获得带引用的回答
  3. 点击引用来源
  4. 验证：页面跳转 + 高亮显示 + 导航栏出现
  5. 点击"下一处"，验证高亮切换

- **兼容性测试**：BrowserStack云测试平台
  - Chrome/Firefox/Safari/Edge 最新3个版本
  - Windows/macOS/Linux 桌面端
  - iOS/Android 移动端（可选）

### 9.3 性能测试

- **加载性能**：Lighthouse Performance Score ≥ 90
- **搜索响应时间**：P99 < 2秒
- **内存占用**：高亮渲染后内存增长 < 50MB
- **CPU占用**：搜索过程中CPU峰值 < 60%

---

## 10. 实施路线图

### Phase 1：核心引擎开发（Day 1-2）

**Day 1上午**：
- [ ] 安装依赖：`npm install fuse.js@7.0.0`
- [ ] 创建`src/utils/textExtractor.js`
- [ ] 实现PDF/DOCX/Excel/DOM文本提取方法
- [ ] 编写单元测试（TextExtractor）

**Day 1下午**：
- [ ] 创建`src/utils/fuzzySearchEngine.js`
- [ ] 配置Fuse.js中文优化参数
- [ ] 实现`preprocessKeyword`和`search`方法
- [ ] 编写单元测试（FuzzySearchEngine）

**Day 2上午**：
- [ ] 创建`src/utils/highlightRenderer.js`
- [ ] 实现DOM/PDF/表格三种高亮类型
- [ ] 添加导航控制逻辑
- [ ] 编写单元测试（HighlightRenderer）

**Day 2下午**：
- [ ] 创建`src/utils/searchCoordinator.js`
- [ ] 实现编排逻辑和重试机制
- [ ] 集成测试（4个模块联调）

### Phase 2：UI集成与调试（Day 3）

**Day 3上午**：
- [ ] 修改`QAModule.vue`的`navigateToFileReader`
- [ ] 修改`ReaderPage.vue`的`onMounted`
- [ ] 添加搜索导航栏UI模板
- [ ] 编写CSS样式（高亮+导航栏+动画）

**Day 3下午**：
- [ ] 本地开发环境调试
- [ ] 测试PDF高亮功能（重点）
- [ ] 测试Word/Excel/TXT等多种格式
- [ ] 修复发现的bug

### Phase 3：打磨与优化（Day 4）

**Day 4上午**：
- [ ] 错误处理完善（边界情况）
- [ ] 性能优化（内存/CPU）
- [ ] 用户反馈收集（内部测试）

**Day 4下午**：
- [ ] 代码审查和重构
- [ ] 文档编写（使用指南）
- [ ] 准备发布

---

## 11. 风险评估与应对

### 11.1 技术风险

| 风险项 | 概率 | 影响 | 应对措施 |
|--------|------|------|---------|
| **PDF iframe跨域限制** | 中 | 高 | 降级方案：仅页码跳转 + Toast提示 |
| **Fuse.js中文分词不准** | 低 | 中 | 自定义tokenizer或引入jieba分词 |
| **大文档性能问题** | 中 | 中 | 分批处理 + Web Worker + 虚拟滚动 |
| **DOM高亮破坏文档结构** | 低 | 高 | 使用Range API + 异常捕获回滚 |

### 11.2 进度风险

- **风险**：Phase 2集成调试超出预期
- **应对**：预留1天buffer time，优先保证核心功能可用

---

## 12. 成功验收标准

### 功能完整性 ✅

- [ ] 点击PDF引用 → 跳转页码 + overlay高亮显示
- [ ] 点击Word引用 → DOM高亮 + 持续显示
- [ ] 点击Excel引用 → 单元格高亮 + 角标序号
- [ ] 模糊匹配成功率 ≥ 90%（测试集验证）
- [ ] 导航栏正确显示匹配数量和当前位置
- [ ] 上/下一处按钮工作正常

### 性能指标 ⚡

- [ ] 搜索+高亮总耗时 < 2秒（P99）
- [ ] 内存增长 < 50MB（相对于无高亮状态）
- [ ] CPU峰值 < 60%（搜索过程中）
- [ ] Lighthouse Performance Score ≥ 90

### 用户体验 😊

- [ ] 高亮视觉效果醒目但不刺眼
- [ ] 动画流畅（60fps）
- [ ] 错误提示友好清晰
- [ ] 移动端触摸操作顺畅
- [ ] 键盘可访问（Tab/Enter导航）

### 代码质量 🔧

- [ ] 单元测试覆盖率 ≥ 85%
- [ ] 无console警告（生产环境）
- [ ] ESLint检查通过（0 error, 0 warning）
- [ ] 代码注释完整（JSDoc标准）

---

## 13. 后续迭代方向（可选）

### Phase 4：增强功能（v2.0）

- [ ] **多关键词同时高亮**：支持AND/OR逻辑组合
- [ ] **高亮导出**：将高亮标注导出为PDF注释
- [ ] **历史记录**：保存用户的搜索历史和高亮偏好
- [ ] **快捷键支持**：Ctrl+F唤起搜索框，F3跳转下一个
- [ ] **AI语义搜索**：升级为向量相似度匹配（需后端支持）

### Phase 5：平台扩展（v3.0）

- [ ] **Web Worker迁移**：将搜索引擎移至Worker线程
- [ ] **IndexedDB缓存**：离线缓存文本提取结果
- [ ] **PWA支持**：离线模式下仍可使用基本搜索功能
- [ ] **插件机制**：允许第三方开发者自定义高亮样式

---

## 附录A：关键技术参考

### A.1 Fuse.js官方文档
https://fusejs.io/

### A.2 Range API（MDN）
https://developer.mozilla.org/en-US/docs/Web/API/Range

### A.3 TreeWalker API（MDN）
https://developer.mozilla.org/en-US/docs/Web/API/TreeWalker

### A.4 PDF.js textLayer
https://github.com/nickmoss/pdfjs-viewer-textlayer

---

## 附录B：术语表

| 术语 | 定义 |
|------|------|
| **RAG** | Retrieval-Augmented Generation（检索增强生成） |
| **SSE** | Server-Sent Events（服务器推送事件） |
| **Fuse.js** | 轻量级模糊搜索库 |
| **TreeWalker** | DOM树遍历API |
| **Range** | DOM范围选择API |
| **Overlay** | 覆盖层（用于PDF高亮） |

---

**文档维护者**：AI Code Assistant  
**最后更新**：2026-05-30  
**下次评审日期**：实施完成后3天内
