# Swipe 功能测试指南 ## 测试场景 ### 场景1:首次重roll(消息没有swipes数组) **初始状态:** ```javascript message = { id: "ai_123456", floor: 2, mes: "这是AI的第一次回复", is_user: false, // 没有 swipes 字段 } ``` **执行重roll后:** ```javascript message = { id: "ai_123456", floor: 2, mes: "这是AI的第二次回复", // 显示新生成的内容 is_user: false, swipes: [ "这是AI的第一次回复", // 旧版本 "这是AI的第二次回复" // 新版本 ], swipe_id: 1 // 自动切换到新版本 } ``` **前端显示:** - 因为有 `swipes` 数组,所以显示 `swipes[1]` = "这是AI的第二次回复" - 显示 swipe 控制按钮:◀ 2/2 ▶ --- ### 场景2:第二次重roll(消息已有swipes数组) **初始状态:** ```javascript message = { id: "ai_123456", floor: 2, mes: "这是AI的第二次回复", is_user: false, swipes: [ "这是AI的第一次回复", "这是AI的第二次回复" ], swipe_id: 1 } ``` **执行重roll后:** ```javascript message = { id: "ai_123456", floor: 2, mes: "这是AI的第三次回复", // 显示新生成的内容 is_user: false, swipes: [ "这是AI的第一次回复", "这是AI的第二次回复", "这是AI的第三次回复" // 新版本 ], swipe_id: 2 // 自动切换到新版本 } ``` **前端显示:** - 显示 `swipes[2]` = "这是AI的第三次回复" - 显示 swipe 控制按钮:◀ 3/3 ▶ --- ### 场景3:用户手动切换swipe **初始状态:** ```javascript message = { id: "ai_123456", floor: 2, mes: "这是AI的第三次回复", is_user: false, swipes: [ "这是AI的第一次回复", "这是AI的第二次回复", "这是AI的第三次回复" ], swipe_id: 2 } // 用户点击左箭头 currentSwipeId = { 2: 1 } // 切换到第二个版本 ``` **前端显示:** - 因为 `currentSwipeId[2]` 存在,所以使用它而不是 `swipe_id` - 显示 `swipes[1]` = "这是AI的第二次回复" - 显示 swipe 控制按钮:◀ 2/3 ▶ --- ## 关键逻辑说明 ### 1. 后端逻辑(ChatBoxSlice.jsx) #### chunk 事件(流式输出) ```javascript if (isReroll) { // ✅ 重roll模式:不更新 mes,只在内部累积 assistantMessage // mes 保持不变,直到 complete 事件才更新 } else { // 正常模式:更新新创建的消息 set((state) => ({ messages: state.messages.map((msg) => msg.id === newMessageId ? { ...msg, mes: assistantMessage } : msg ) })); } ``` #### complete 事件(生成完成) ```javascript if (isReroll) { const existingSwipes = msg.swipes || []; const currentMes = msg.mes; // 当前显示的内容(旧版本) let updatedSwipes = [...existingSwipes]; // 如果当前 mes 不在 swipes 中,先添加它 if (!updatedSwipes.includes(currentMes)) { updatedSwipes.push(currentMes); } // 添加新生成的内容 updatedSwipes.push(assistantMessage); return { ...msg, mes: assistantMessage, // 显示新生成的内容 swipes: updatedSwipes, // 更新 swipes 数组 swipe_id: updatedSwipes.length - 1 // 自动切换到新版本 }; } ``` ### 2. 前端逻辑(ChatBox.jsx) ```javascript // 确定当前显示的消息内容 let currentMes = message.mes; // 默认使用 mes let hasSwipes = message.swipes && message.swipes.length > 0; let currentSwipeIndex = message.swipe_id; if (hasSwipes) { // 如果有swipes数组 if (currentSwipeId[message.floor] !== undefined) { // 如果用户已经切换过版本,使用用户选择的版本 currentSwipeIndex = currentSwipeId[message.floor]; } else { // 否则使用默认的swipe_id currentSwipeIndex = message.swipe_id; } if (currentSwipeIndex >= 0 && currentSwipeIndex < message.swipes.length) { currentMes = message.swipes[currentSwipeIndex]; // 从 swipes 中读取 } } ``` --- ## 测试步骤 ### 1. 测试首次重roll 1. 发送一条消息,等待AI回复 2. 右键点击AI消息,选择"重roll" 3. 观察: - ✅ 流式输出时,消息内容不变(不显示流式过程) - ✅ 完成后,消息更新为新内容 - ✅ 出现 swipe 控制按钮:◀ 2/2 ▶ - ✅ 点击左箭头可以切换到旧版本 ### 2. 测试多次重roll 1. 继续重roll几次 2. 观察: - ✅ 每次重roll都在 swipes 数组中添加新版本 - ✅ swipe 计数器正确更新:2/3, 3/4, 4/5... - ✅ 可以通过左右箭头切换所有版本 ### 3. 测试手动切换 1. 重roll几次后,有多个版本 2. 点击左箭头切换到旧版本 3. 观察: - ✅ 消息内容切换为旧版本 - ✅ swipe 计数器正确更新 - ✅ 再次重roll时,新版本添加到末尾 ### 4. 测试键盘快捷键 1. 使用左右箭头键切换 swipe 2. 在最后一个版本时按右键触发重roll 3. 观察: - ✅ 左右键正确切换版本 - ✅ 右键在最后一个版本时触发重roll - ✅ 重roll后自动切换到新版本 --- ## 常见问题排查 ### Q1: 重roll后没有出现 swipe 按钮 **原因**:swipes 数组没有正确创建 **检查**: - 查看控制台日志:`[ChatBoxStore] 📊 Swipes 更新:` - 确认 `newCount` 大于 0 - 确认消息对象中有 `swipes` 字段 ### Q2: 重roll后显示的是旧内容 **原因**:`mes` 字段没有更新 **检查**: - 确认 complete 事件中更新了 `mes: assistantMessage` - 确认 `assistantMessage` 有正确的内容 ### Q3: 切换 swipe 后内容不变 **原因**:前端渲染逻辑有问题 **检查**: - 确认 `currentMes` 正确从 `swipes[currentSwipeIndex]` 读取 - 确认 `currentSwipeIndex` 的值正确 - 确认 `currentSwipeId` 状态正确更新 ### Q4: 重roll时看到流式输出覆盖了原内容 **原因**:chunk 事件中错误地更新了 `mes` **检查**: - 确认 chunk 事件中,重roll模式不更新 `mes` - 应该只有正常模式才更新 `mes`