# 智能翻译文档对比页前端重构实施方案

## 方案进度概述
- 当前阶段：重构方案定稿
- 目标：将现有全量渲染的文档对比页重构为页级懒加载架构
- 面向对象：大模型执行与前端开发协作
- 约束：原有接口不能改，只能基于新增接口重构

## 1. 需求理解
当前页面的核心问题不是单纯“慢”，而是：
1. 整包数据过大
2. 页和块一次性全量挂载
3. 富文本、图片、表格混合渲染
4. 目录与滚动状态依赖大量 DOM

因此前端重构的目标不是“微调样式”，而是从渲染架构上切换到更适合大文档的方式。

## 2. 最终结论
> 以“页”为最小渲染单位，采用“页级懒加载 + 视口内挂载 + 页外轻量壳 + 页内二级懒加载”的混合方案。

这是当前场景下最稳、最容易落地、也最符合文档阅读习惯的方案。

## 3. 重构目标
### 3.1 功能目标
- 支持超长文档平稳展示
- 支持目录跳转
- 支持页码同步
- 支持图片、表格、标题、正文正常展示
- 支持当前页高亮与章节高亮

### 3.2 性能目标
- 首屏加载更快
- 滚动更稳定
- 大文档不掉帧
- 降低一次性 DOM 规模

### 3.3 可维护性目标
- 页、块、节点职责分离
- 渲染逻辑可分层扩展
- 后续方便接搜索、高亮、差异对比

## 4. 重构原则
1. 页是最小渲染单位
2. 目录只负责导航，不参与重渲染
3. 可见页才挂载真实内容
4. 页外只保留占位壳
5. 图片、表格、富文本做二级懒加载
6. 原始完整结果保留，但不直接驱动 UI 全量渲染

## 5. 页面结构设计
### 5.1 页面容器
文件建议：`src/views/intelligentTranslation/documentCompare.vue`

职责：
- 请求文档摘要、目录、页索引、页内容
- 管理当前页、当前章节、加载状态
- 维护滚动容器
- 协调页面跳转和状态同步

### 5.2 页列表组件
文件建议：`PageList.vue`

职责：
- 遍历页元信息
- 判断页是否进入视口附近
- 决定挂载真实内容还是仅显示页壳
- 控制页缓存策略

### 5.3 页内容组件
文件建议：`PageBlock.vue`

职责：
- 渲染单页内部节点
- 按 `semantic_type` 分发渲染子组件
- 处理 absolute 与 flow 两种布局模式

### 5.4 节点子组件
建议拆分：
- `HeadingNode.vue`
- `TextNode.vue`
- `ImageNode.vue`
- `TableNode.vue`
- `RichHtmlNode.vue`

职责：
- 各类节点独立渲染
- 减少单组件复杂度
- 控制 `v-html` 使用范围

### 5.5 目录树组件
文件建议：`ArticleNavTree.vue`

职责：
- 渲染标题目录
- 点击跳页
- 当前章节高亮

## 6. 状态设计
建议状态如下：

```js
const rawResult = ref(null)
const summary = ref(null)
const pageIndexList = ref([])
const outlineTree = ref([])
const pageBlockMap = ref(new Map())
const visiblePageSet = ref(new Set())
const mountedPageCache = ref(new Map())
const currentPageId = ref('')
const currentNodeKey = ref('')
const compareScrollRef = ref(null)
```

### 状态含义
- `rawResult`：原始完整结果，兼容旧逻辑
- `summary`：文档摘要数据
- `pageIndexList`：页级索引列表
- `outlineTree`：目录树
- `pageBlockMap`：页到节点的映射
- `visiblePageSet`：当前需要挂载的页集合
- `mountedPageCache`：已挂载页缓存
- `currentPageId`：当前激活页
- `currentNodeKey`：当前目录高亮节点
- `compareScrollRef`：滚动容器引用

## 7. 数据获取顺序
### 7.1 初始化顺序
1. 请求 `document-meta`
2. 解析出摘要、页索引、目录树
3. 请求首屏页内容 `document-page`
4. 根据滚动位置继续按需请求其他页

### 7.2 页内按需顺序
当某页进入视口附近：
1. 请求该页完整内容
2. 挂载页真实 DOM

### 7.3 目录跳转顺序
点击目录节点时：
1. 根据 `page_idx` 找目标页
2. 若该页未挂载，先请求页内容
3. 滚动到目标页
4. 更新当前页和章节高亮

## 8. 渲染策略
### 8.1 首屏策略
首屏只挂载：
- 当前页
- 当前页前 1 页
- 当前页后 2 页

其他页只渲染页壳，不渲染真实内容。

### 8.2 视口内挂载策略
使用 `IntersectionObserver` 或滚动监听判断页面是否进入视口附近：
- 进入可视区：挂载真实内容
- 离开较远：保留占位或卸载

### 8.3 页内二级懒加载策略
页内对重资源进一步控制：
- 图片 `loading="lazy"`
- 表格默认只渲染摘要或首屏片段
- 富文本仅对必要节点使用 `v-html`

### 8.4 页外壳策略
未挂载页仍保留：
- 页码
- 页面尺寸占位
- 可选的轻量标题摘要

这样可以保证滚动长度和定位稳定。

## 9. 现有代码改造重点
### 9.1 不再全量 `v-for` 渲染所有页内容
当前逻辑需要从“所有页一次性渲染”改成“页壳 + 条件挂载”。

### 9.2 控制 `v-html` 范围
只在确实需要富文本还原的节点使用 `v-html`，且尽量局部化。

### 9.3 目录与页级状态绑定
当前页、章节高亮、跳转定位统一使用页级索引，不再依赖海量 block DOM 计算。

### 9.4 图片和表格独立组件化
图片和表格不要和普通文本混成一个大渲染函数，必须独立拆组件。

## 10. 推荐组件结构
```text
documentCompare.vue
├── ArticleNavTree.vue
├── PageList.vue
│   ├── PageShell.vue
│   └── PageBlock.vue
│       ├── HeadingNode.vue
│       ├── TextNode.vue
│       ├── ImageNode.vue
│       ├── TableNode.vue
│       └── RichHtmlNode.vue
└── ComparePanel.vue
```

## 11. 实施步骤
### 第 1 步：接入新接口，但不改 UI
目标：先把数据链路切到新接口，保留现有页面结构。

验收：
- 能拿到摘要、页索引、目录
- 能按页拿到内容

### 第 2 步：改成页壳 + 条件挂载
目标：只挂载视口附近页。

验收：
- 非可见页不再创建真实 DOM
- 首屏明显变快

### 第 3 步：拆分页内节点组件
目标：降低单文件复杂度。

验收：
- 标题、正文、图片、表格分组件渲染

### 第 4 步：改造目录跳转和滚动同步
目标：按页同步当前章节。

验收：
- 点击目录可准确跳转
- 滚动时高亮正确

### 第 5 步：增加页内二级懒加载
目标：处理大图、大表和富文本。

验收：
- 长文档滚动更流畅
- 图片/表格不会拖慢主线程

## 12. 风险与注意事项
- 不能直接把整包 JSON 当唯一 UI 数据源长期使用
- 需要保证 `page_idx` 和 `node_id` 稳定唯一
- `bbox_norm` 优先使用，缺失时再由 `bbox` 换算
- `reading_order` 必须稳定，否则页内顺序会错乱
- `style_spans` 的字符区间必须与文本严格对齐

## 13. 验收标准
### 功能验收
- 文档正常渲染
- 目录可跳转
- 当前页可同步
- 图片、表格、标题、正文正常展示

### 性能验收
- 首屏快于原方案
- 长文档滚动不卡顿
- 不再出现明显“截断感”

### 结构验收
- 组件职责清晰
- 渲染链路分层明确
- 后续可继续拓展搜索和对比能力

## 14. 结论
前端最终采用：

> 页级懒加载渲染架构。

即：
- 页作为最小渲染单位
- 可见页才挂载真实内容
- 页外只保留轻量壳
- 目录和滚动按页同步
- 图片、表格、富文本做二级懒加载

这是当前场景下最稳妥、最可落地、最利于后续扩展的方案。
