// pages/ai-assistant/ai-assistant.js const aiService = require('../../utils/aiService.js') const learningTracker = require('../../utils/learningTracker.js') const util = require('../../utils/util'); Page({ data: { // 场景列表 scenarios: [], currentScenario: null, // 消息列表 messages: [], // 输入框 inputValue: '', inputPlaceholder: '输入你的问题...', // 状态 isThinking: false, scrollIntoView: '', // 打字机效果 typewriterTimer: null, currentTypingMessage: '' }, onLoad(options) { // 加载场景列表 const scenarios = aiService.getScenarios(); this.setData({ scenarios }); // 从存储加载历史对话 this.loadHistory(); // 如果从其他页面传入场景 if (options.scenario) { this.selectScenario({ currentTarget: { dataset: { id: options.scenario } } }); } }, onShow() { // 开始跟踪学习时间 learningTracker.onPageShow('ai') }, onHide() { // 停止跟踪学习时间 learningTracker.onPageHide() }, onUnload() { // 记录学习时长 learningTracker.onPageUnload() // 清理打字机定时器 if (this.data.typewriterTimer) { clearTimeout(this.data.typewriterTimer); } // 保存对话历史 this.saveHistory(); }, /** * 选择场景 */ selectScenario(e) { const scenarioId = e.currentTarget.dataset.id; const scenario = this.data.scenarios.find(s => s.id === scenarioId); if (!scenario) return; // 触觉反馈 wx.vibrateShort({ type: 'light' }); // 设置当前场景 this.setData({ currentScenario: scenarioId, inputPlaceholder: `${scenario.name} - 输入你的问题...` }); // 如果有预设提示词,自动发送 if (scenario.prompt && this.data.messages.length === 0) { this.setData({ inputValue: scenario.prompt }); // 延迟发送,让用户看到输入 setTimeout(() => { this.sendMessage(); }, 500); } }, /** * 输入框变化 */ onInput(e) { this.setData({ inputValue: e.detail.value }); }, /** * 发送消息 */ async sendMessage() { const content = this.data.inputValue.trim(); if (!content || this.data.isThinking) return; // 触觉反馈 wx.vibrateShort({ type: 'medium' }); // 添加用户消息 const userMessage = { role: 'user', content: content, time: util.formatTime(new Date(), 'hh:mm') }; const messages = [...this.data.messages, userMessage]; this.setData({ messages, inputValue: '', isThinking: true }); // 滚动到底部 this.scrollToBottom(); try { // 调用AI服务 const reply = await aiService.chat( messages.map(m => ({ role: m.role, content: m.content })), this.data.currentScenario ); // 添加AI回复(带打字机效果) const assistantMessage = { role: 'assistant', content: '', // 初始为空,打字机逐步显示 time: util.formatTime(new Date(), 'hh:mm') }; this.setData({ messages: [...this.data.messages, assistantMessage], isThinking: false }); // 启动打字机效果 this.typewriterEffect(reply, this.data.messages.length - 1); } catch (error) { // 错误处理 const errorMessage = { role: 'assistant', content: aiService.getErrorMessage(error), time: util.formatTime(new Date(), 'hh:mm') }; this.setData({ messages: [...this.data.messages, errorMessage], isThinking: false }); this.scrollToBottom(); wx.showToast({ title: '发送失败', icon: 'error' }); } }, /** * 打字机效果 */ typewriterEffect(text, messageIndex, currentIndex = 0) { if (currentIndex >= text.length) { // 打字完成,保存历史 this.saveHistory(); return; } // 每次显示2-3个字符(中文)或5-8个字符(英文) const charsToAdd = text[currentIndex].match(/[\u4e00-\u9fa5]/) ? Math.min(2, text.length - currentIndex) : Math.min(6, text.length - currentIndex); const newText = text.substring(0, currentIndex + charsToAdd); // 更新消息内容 const messages = this.data.messages; messages[messageIndex].content = newText; this.setData({ messages }); this.scrollToBottom(); // 继续打字 const delay = text[currentIndex].match(/[,。!?;:,.]/) ? 150 : 50; this.data.typewriterTimer = setTimeout(() => { this.typewriterEffect(text, messageIndex, currentIndex + charsToAdd); }, delay); }, /** * 清空对话 */ clearMessages() { wx.showModal({ title: '确认清空', content: '确定要清空所有对话记录吗?', confirmColor: '#FF3B30', success: (res) => { if (res.confirm) { this.setData({ messages: [], currentScenario: null, inputPlaceholder: '输入你的问题...' }); // 清除存储 wx.removeStorageSync('ai_chat_history'); wx.showToast({ title: '已清空', icon: 'success' }); } } }); }, /** * 滚动到底部 */ scrollToBottom() { const query = wx.createSelectorQuery(); query.select('.message-list').boundingClientRect(); query.selectViewport().scrollOffset(); setTimeout(() => { this.setData({ scrollIntoView: `msg-${this.data.messages.length - 1}` }); }, 100); }, /** * 保存对话历史 */ saveHistory() { try { wx.setStorageSync('ai_chat_history', { messages: this.data.messages, scenario: this.data.currentScenario, timestamp: Date.now() }); } catch (error) { console.error('保存历史失败:', error); } }, /** * 加载对话历史 */ loadHistory() { try { const history = wx.getStorageSync('ai_chat_history'); if (history && history.messages) { // 只加载24小时内的历史 const hoursPassed = (Date.now() - history.timestamp) / (1000 * 60 * 60); if (hoursPassed < 24) { this.setData({ messages: history.messages, currentScenario: history.scenario }); setTimeout(() => this.scrollToBottom(), 300); } } } catch (error) { console.error('加载历史失败:', error); } } });