# Bug 修复 v3 - 刷新后重复加载问题 ## 修复的问题 ### 刷新后加载两遍内容 **原因**: 1. `loadInitialData()` 会调用 `fetchAndDisplayHistory()` 加载历史记录 2. 1 秒后 `restoreTaskState()` 启动轮询 3. `loadRunningTask()` 设置 `lastEventIndex = 0`,从头开始获取所有事件 4. 导致已经在历史中的事件被重复处理 **解决方案**: #### 1. 等待历史加载完成 在 `restoreTaskState()` 中检查历史是否已加载: ```javascript async restoreTaskState() { // 检查历史是否已加载 const hasMessages = Array.isArray(this.messages) && this.messages.length > 0; if (!hasMessages) { // 等待历史加载完成后再恢复 setTimeout(() => { this.restoreTaskState(); }, 500); return; } // 历史已加载,启动轮询 taskStore.startPolling(...); } ``` #### 2. 计算正确的事件偏移量 在 `loadRunningTask()` 中获取任务详情,计算已处理的事件数量: ```javascript async loadRunningTask(conversationId) { // 查找运行中的任务 const runningTask = result.data.find(...); if (runningTask) { // 获取任务详情,计算已处理的事件数量 const detailResponse = await fetch(`/api/tasks/${runningTask.task_id}`); const detailResult = await detailResponse.json(); // 设置为当前事件数量,只获取新事件 this.lastEventIndex = detailResult.data.next_offset || detailResult.data.events.length; debugLog('[Task] 设置起始偏移量:', this.lastEventIndex); } } ``` ## 工作流程 ### 页面刷新恢复流程(修复后) 1. **页面加载** (`mounted()`) - 调用 `loadInitialData()` - 加载历史记录(`fetchAndDisplayHistory()`) - 1 秒后调用 `restoreTaskState()` 2. **任务恢复** (`restoreTaskState()`) - 检查是否已在流式输出中 → 跳过 - 查找运行中的任务 - **检查历史是否已加载** → 如果未加载,等待 500ms 后重试 - 历史已加载 → 继续 3. **加载任务详情** (`loadRunningTask()`) - 查找运行中的任务 - **获取任务详情** - **计算已处理的事件数量** - 设置 `lastEventIndex` 为当前事件数量 4. **启动轮询** (`startPolling()`) - 从 `lastEventIndex` 开始轮询 - **只获取新事件** - 每 150ms 轮询一次 5. **处理新事件** - 只处理新产生的事件 - 追加到已有的历史记录后面 - 不重复显示已有内容 ## 关键改进 ### 1. 等待历史加载 - 在 `restoreTaskState()` 中检查 `messages` 是否已加载 - 如果未加载,延迟 500ms 后重试 - 确保历史加载完成后再启动轮询 ### 2. 正确的事件偏移量 - 在 `loadRunningTask()` 中获取任务详情 - 计算已处理的事件数量(`next_offset` 或 `events.length`) - 设置 `lastEventIndex` 为当前事件数量 - 轮询只获取新事件(`from=lastEventIndex`) ### 3. 避免重复处理 - 历史记录由 `fetchAndDisplayHistory()` 加载 - 轮询只处理新事件 - 不会重复显示已有内容 ## 修改的文件 ### 1. static/src/app/methods/taskPolling.ts **等待历史加载**: ```javascript async restoreTaskState() { // 检查历史是否已加载 const hasMessages = Array.isArray(this.messages) && this.messages.length > 0; if (!hasMessages) { debugLog('[TaskPolling] 历史未加载,等待历史加载完成'); setTimeout(() => { this.restoreTaskState(); }, 500); return; } debugLog('[TaskPolling] 历史已加载,启动轮询'); // ... 启动轮询 } ``` ### 2. static/src/stores/task.ts **计算事件偏移量**: ```javascript async loadRunningTask(conversationId) { const runningTask = result.data.find(...); if (runningTask) { // 获取任务详情 const detailResponse = await fetch(`/api/tasks/${runningTask.task_id}`); const detailResult = await detailResponse.json(); // 设置为当前事件数量 this.lastEventIndex = detailResult.data.next_offset || detailResult.data.events.length; debugLog('[Task] 设置起始偏移量:', this.lastEventIndex); } } ``` ## 测试场景 ### 1. 正常发送消息 - 发送消息 - 观察输出是否正常 - 观察是否只显示一次 ### 2. 刷新页面(任务进行中) - 任务执行中刷新页面 - 观察历史记录是否正确显示 - 观察是否只显示一次 - 观察新内容是否正常追加 - 观察工具块是否保留 ### 3. 刷新页面(任务完成后) - 任务完成后刷新页面 - 观察历史记录是否完整 - 观察是否没有重复内容 ### 4. 多次刷新 - 任务执行中多次刷新 - 观察每次刷新是否正常 - 观察是否有累积的重复内容 ## 构建 ```bash cd static npm run build ``` 构建成功! - `static/dist/assets/main.js` (690.04 kB) - `static/dist/assets/task.js` (4.01 kB) ## 最终效果 - ✅ 刷新后不重复显示内容 - ✅ 历史记录正确加载 - ✅ 新事件正常追加 - ✅ 工具块正确显示 - ✅ 流畅的输出效果(150ms 轮询) 现在可以测试了!刷新页面应该只显示一次内容,新内容会正常追加。