Files
aue/docs/superpowers/specs/2026-05-30-ai-chat-link-highlight-design.md
2026-06-03 13:16:30 +08:00

876 lines
27 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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. 设置合理的threshold0.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渲染的delay500-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 2UI集成与调试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 APIMDN
https://developer.mozilla.org/en-US/docs/Web/API/Range
### A.3 TreeWalker APIMDN
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天内