# 取消聊天功能实现文档 ## 功能概述 为 AI 教练聊天界面添加了用户可以取消发送或终止回复的能力,参照业内最佳实践(如 ChatGPT、Claude 等)实现。 ## 主要功能 ### 1. 发送按钮状态切换 - **发送状态**: 绿色背景,显示上箭头图标 - **取消状态**: 红色背景 (#FF4444),显示停止图标 - 根据 `isSending` 或 `isStreaming` 状态自动切换 ### 2. 流式回复中的取消按钮 - 在助手正在思考时显示"正在思考…"和取消按钮 - 在助手正在输出文本时显示"停止生成"按钮 - 取消按钮采用红色主题,与停止操作语义一致 ### 3. 取消逻辑处理 - 调用 `streamAbortRef.current.abort()` 中断 XMLHttpRequest - 清理状态:`isSending`、`isStreaming`、`pendingAssistantIdRef` - 移除正在生成中的助手消息 - 提供触觉反馈(Warning 类型) ### 4. 错误处理优化 - 区分用户主动取消和网络错误 - 对于 AbortError 不进行错误提示和降级处理 - 避免在取消操作后显示"请求失败"等错误信息 ## 技术实现 ### 关键函数 ```typescript function cancelCurrentRequest() { // 中断流式请求 if (streamAbortRef.current) { streamAbortRef.current.abort(); streamAbortRef.current = null; } // 清理状态 setIsSending(false); setIsStreaming(false); // 移除正在生成的消息 if (pendingAssistantIdRef.current) { setMessages(prev => prev.filter(msg => msg.id !== pendingAssistantIdRef.current)); pendingAssistantIdRef.current = null; } // 用户反馈 Haptics.notificationAsync(Haptics.NotificationFeedbackType.Warning); } ``` ### UI 状态管理 1. **发送按钮**: - 背景色:发送时为主题色,取消时为红色 - 图标:发送时为上箭头,取消时为停止图标 - 禁用状态:只在无内容且非发送状态时禁用 2. **流式消息气泡**: - 思考阶段:显示"正在思考…"和取消按钮 - 输出阶段:在消息下方显示"停止生成"按钮 ### 边界情况处理 1. **组件卸载**: 自动清理未完成的请求 2. **新建会话**: 如果有进行中的请求,先取消再创建 3. **切换历史会话**: 取消当前请求后再加载历史会话 4. **多次点击**: 防止重复发送,支持随时取消 ## 用户体验设计 ### 视觉反馈 - 按钮颜色变化(绿色→红色) - 图标变化(发送→停止) - 取消按钮采用一致的红色主题 ### 交互反馈 - 触觉反馈:取消时提供 Warning 类型震动 - 即时响应:点击取消后立即停止生成 - 状态清理:取消后界面回到可输入状态 ### 语义化设计 - "正在思考…" + "取消":在等待响应阶段 - "停止生成":在文本输出阶段 - 红色主题:与停止操作的通用语义保持一致 ## 业内最佳实践对比 ### ChatGPT - ✅ 发送按钮变为停止按钮 - ✅ 红色停止图标 - ✅ 即时响应 ### Claude - ✅ 流式输出过程中显示停止按钮 - ✅ 取消后清理当前消息 - ✅ 明确的视觉区分 ### 我们的实现 - ✅ 发送/取消按钮一体化设计 - ✅ 双重取消入口(发送按钮 + 消息内按钮) - ✅ 完整的状态管理和错误处理 - ✅ 触觉反馈增强用户体验 ## 测试建议 1. **基本功能测试**: - 发送消息后立即点击取消 - 在流式输出过程中点击停止 - 连续发送多条消息并取消 2. **边界情况测试**: - 网络异常时的取消行为 - 快速切换会话时的状态清理 - 组件卸载时的资源清理 3. **用户体验测试**: - 按钮状态变化的流畅性 - 触觉反馈的适当性 - 界面响应的即时性 ## 总结 本实现参照业内主流 AI 聊天应用的最佳实践,提供了完整的取消/终止功能,包括: - 直观的 UI 状态切换 - 完善的取消逻辑处理 - 良好的用户反馈机制 - 健壮的错误处理 - 一致的设计语言 功能实现既保证了技术的正确性,也注重了用户体验的完整性。