|
|
Page({ data: { // 专家信息
expertInfo: { id: 1, name: '张明专家', title: '资深畜牧兽医', expertise: '牛羊疾病防治', avatar: '/images/avatars/expert1.png', online: true, phone: '13800138000' }, // 用户信息
userInfo: { id: 1001, name: '养殖户', avatar: '/images/avatars/user.png' }, // 消息列表
messageList: [], scrollTop: 0, scrollAnimate: false, // 输入相关 - 优化
inputValue: '', inputFocus: false, // 多媒体
showMediaSheet: false, // 页面状态
showDateDivider: true, todayDate: '', loading: false, loadingMore: false, // 滚动相关
isScrolling: false, lastScrollTop: 0, // 当前专家ID
currentExpertId: 1, // 分页相关
page: 1, pageSize: 20, hasMore: true, // 时间显示间隔
timeInterval: 5, lastShowTimeStamp: 0, // 键盘高度
keyboardHeight: 0 },
onLoad: function(options) { this.setTodayDate(); this.loadUserInfo(); if (options.expertId) { this.setData({ currentExpertId: options.expertId }); this.loadExpertInfo(options.expertId); } else { this.loadChatHistory(); } wx.onKeyboardHeightChange(this.onKeyboardHeightChange.bind(this)); },
onUnload: function() { wx.offKeyboardHeightChange(); },
// ========== 输入框相关方法 ==========
// 输入处理
onInput: function(e) { this.setData({ inputValue: e.detail.value }); },
// 输入框获得焦点
onInputFocus: function() { this.setData({ inputFocus: true }, () => { setTimeout(() => { this.scrollToBottom(); }, 200); }); },
// 输入框失去焦点
onInputBlur: function() { this.setData({ inputFocus: false }); },
// 清除输入
clearInput: function() { this.setData({ inputValue: '', inputFocus: true }); },
// 发送文本消息
sendTextMessage: function() { const content = this.data.inputValue.trim(); if (!content) return; const newMessage = { id: 'msg-' + Date.now(), sender: 'user', type: 'text', content: content, timestamp: Date.now(), status: 'sending' }; this.addMessageToList(newMessage); // 清空输入框
this.setData({ inputValue: '', inputFocus: false }); // 模拟发送成功
setTimeout(() => { this.updateMessageStatus(newMessage.id, 'success'); setTimeout(() => { this.receiveExpertReply(); }, 1000); }, 500); },
// 添加消息到列表
addMessageToList: function(message) { const { messageList } = this.data; const processedMessage = this.processSingleMessageTime(message, messageList); messageList.push(processedMessage); this.setData({ messageList }, () => { this.scrollToBottom(); }); },
// 更新消息状态
updateMessageStatus: function(messageId, status) { const { messageList } = this.data; const index = messageList.findIndex(msg => msg.id === messageId); if (index !== -1) { messageList[index].status = status; this.setData({ messageList }); } },
// 接收专家回复
receiveExpertReply: function() { const replies = [ '收到您的消息,让我分析一下您说的情况。', '建议您提供更多细节,比如发病时间、具体症状等。', '根据描述,可能是饲料问题引起的,建议调整饲料配方。', '可以考虑添加一些维生素补充剂,改善食欲问题。', '最好能提供照片,这样我可以更准确地判断情况。' ]; const randomReply = replies[Math.floor(Math.random() * replies.length)]; const newMessage = { id: 'exp-' + Date.now(), sender: 'expert', type: 'text', content: randomReply, timestamp: Date.now(), status: 'success' }; this.addMessageToList(newMessage); },
// ========== 滚动相关 ==========
// 滚动事件
onScroll: function(e) { const scrollTop = e.detail.scrollTop; this.setData({ lastScrollTop: scrollTop, isScrolling: true }); clearTimeout(this.scrollTimer); this.scrollTimer = setTimeout(() => { this.setData({ isScrolling: false }); }, 200); if (scrollTop <= 100 && !this.data.loadingMore && this.data.hasMore) { this.loadMoreMessages(); } },
// 加载更多消息
loadMoreMessages: function() { if (this.data.loadingMore || !this.data.hasMore) return; this.setData({ loadingMore: true, page: this.data.page + 1 }, () => { this.loadChatHistory(); }); },
// 滚动到底部
scrollToBottom: function(animate = true) { if (this.data.isScrolling) return; this.setData({ scrollAnimate: animate }, () => { setTimeout(() => { this.setData({ scrollTop: 999999 }); }, 50); }); },
// 键盘高度变化
onKeyboardHeightChange: function(res) { this.setData({ keyboardHeight: res.height }); if (res.height > 0) { this.setData({ showMediaSheet: false }); setTimeout(() => { this.scrollToBottom(); }, 100); } },
// ========== 多媒体相关 ==========
// 显示多媒体选择面板
showMediaActionSheet: function() { this.setData({ showMediaSheet: true, inputFocus: false }); },
// 隐藏多媒体选择面板
hideMediaActionSheet: function() { this.setData({ showMediaSheet: false }); },
// 选择图片
chooseImage: function() { this.hideMediaActionSheet(); wx.chooseImage({ count: 9, sizeType: ['compressed'], sourceType: ['album'], success: (res) => { this.uploadImages(res.tempFilePaths); }, fail: (err) => { wx.showToast({ title: '选择图片失败', icon: 'none' }); } }); },
// 选择视频
chooseVideo: function() { this.hideMediaActionSheet(); wx.chooseVideo({ sourceType: ['album'], compressed: true, maxDuration: 60, success: (res) => { this.uploadVideo(res.tempFilePath, res.thumbTempFilePath); }, fail: (err) => { wx.showToast({ title: '选择视频失败', icon: 'none' }); } }); },
// 选择文件
chooseFile: function() { this.hideMediaActionSheet(); wx.chooseMessageFile({ count: 1, type: 'all', success: (res) => { const file = res.tempFiles[0]; this.uploadFile(file.path, file.name, file.size); }, fail: (err) => { wx.showToast({ title: '选择文件失败', icon: 'none' }); } }); },
// 上传图片
uploadImages: function(tempFilePaths) { tempFilePaths.forEach((tempFilePath, index) => { const fileName = `image_${Date.now()}_${index}.jpg`; this.uploadFile(tempFilePath, fileName, 0, 'image'); }); },
// 上传视频
uploadVideo: function(tempFilePath, thumbPath) { const fileName = `video_${Date.now()}.mp4`; this.uploadFile(tempFilePath, fileName, 0, 'video', thumbPath); },
// 通用文件上传
uploadFile: function(tempFilePath, fileName, fileSize = 0, type = 'file', thumbPath = '') { const messageId = 'file-' + Date.now(); const message = { id: messageId, sender: 'user', type: type, content: tempFilePath, thumb: thumbPath, fileName: fileName, fileSize: fileSize, extension: fileName.split('.').pop().toLowerCase(), timestamp: Date.now(), status: 'uploading', progress: 0 }; this.addMessageToList(message); this.simulateUpload(messageId, type); },
// 模拟上传过程
simulateUpload: function(messageId, type) { let progress = 0; const uploadInterval = setInterval(() => { progress += Math.random() * 20 + 10; if (progress >= 100) { progress = 100; clearInterval(uploadInterval); setTimeout(() => { this.updateMessageStatus(messageId, 'success'); const { messageList } = this.data; const index = messageList.findIndex(msg => msg.id === messageId); if (index !== -1) { delete messageList[index].progress; this.setData({ messageList }); if (type === 'image' || type === 'video') { setTimeout(() => { this.receiveMediaReply(type); }, 800); } } }, 200); } const { messageList } = this.data; const index = messageList.findIndex(msg => msg.id === messageId); if (index !== -1) { messageList[index].progress = Math.min(progress, 100); this.setData({ messageList }); } }, 100); },
// 接收媒体回复
receiveMediaReply: function(type) { const imageReplies = [ '照片收到了,牛的状况看起来确实不太理想。', '从照片看,饲养环境需要改善一下。', '图片清晰,我可以更准确地判断问题了。' ]; const videoReplies = [ '视频看到了,动物的精神状态需要关注。', '从视频可以观察到更多细节,这很有帮助。', '视频内容很有价值,让我了解了具体情况。' ]; const replies = type === 'image' ? imageReplies : videoReplies; const randomReply = replies[Math.floor(Math.random() * replies.length)]; const newMessage = { id: 'exp-media-' + Date.now(), sender: 'expert', type: 'text', content: randomReply, timestamp: Date.now(), status: 'success' }; this.addMessageToList(newMessage); },
// 预览图片
previewImage: function(e) { const url = e.currentTarget.dataset.url; wx.previewImage({ current: url, urls: [url] }); },
// ========== 数据初始化 ==========
// 设置今天日期
setTodayDate: function() { const now = new Date(); const month = now.getMonth() + 1; const date = now.getDate(); const week = ['日', '一', '二', '三', '四', '五', '六'][now.getDay()]; this.setData({ todayDate: `${month}月${date}日 星期${week}` }); },
// 加载用户信息
loadUserInfo: function() { try { const userInfo = wx.getStorageSync('userInfo'); if (userInfo) { this.setData({ userInfo }); } } catch (e) { console.error('加载用户信息失败:', e); } },
// 加载专家信息
loadExpertInfo: function(expertId) { wx.showLoading({ title: '加载中...' }); // 模拟网络请求
setTimeout(() => { this.setData({ expertInfo: { id: Number(expertId), name: '张明专家', title: '资深畜牧兽医', expertise: '牛羊疾病防治', avatar: '/images/avatars/expert1.png', online: true, phone: '13800138000' }, loading: false }); wx.hideLoading(); this.loadChatHistory(); }, 500); },
// 加载聊天记录
loadChatHistory: function() { this.setData({ loading: true }); // 模拟历史消息
setTimeout(() => { const now = Date.now(); const mockMessages = [ { id: 'msg-1', sender: 'expert', type: 'text', content: '您好,我是张明专家,有什么可以帮您?', timestamp: now - 10 * 60 * 1000, status: 'success' }, { id: 'msg-2', sender: 'user', type: 'text', content: '您好,我养的牛最近食欲不振,请问是什么原因?', timestamp: now - 9 * 60 * 1000, status: 'success' }, { id: 'msg-3', sender: 'expert', type: 'text', content: '可能是饲料问题或环境变化引起的,请描述一下具体情况。', timestamp: now - 7 * 60 * 1000, status: 'success' }, { id: 'msg-4', sender: 'user', type: 'text', content: '具体症状是拉稀,体温偏高,精神状态不好。', timestamp: now - 2 * 60 * 1000, status: 'success' }, { id: 'msg-5', sender: 'expert', type: 'text', content: '明白了,建议您调整饲料配方,添加一些益生菌。', timestamp: now - 1 * 60 * 1000, status: 'success' } ]; const processedMessages = this.processMessageTimes(mockMessages); this.setData({ messageList: processedMessages, loading: false, hasMore: false }, () => { this.scrollToBottom(true); }); }, 800); },
// 处理消息时间显示
processMessageTimes: function(messages) { if (!messages || messages.length === 0) return []; const sortedMessages = [...messages].sort((a, b) => a.timestamp - b.timestamp); const processedMessages = []; let lastShowTime = null; for (let i = 0; i < sortedMessages.length; i++) { const msg = { ...sortedMessages[i] }; if (!msg.timestamp || isNaN(msg.timestamp) || msg.timestamp <= 0) { msg.timestamp = Date.now() - (sortedMessages.length - i) * 60000; } if (i === 0) { msg.showTime = true; lastShowTime = msg.timestamp; } else { const timeDiffMinutes = (msg.timestamp - lastShowTime) / (1000 * 60); msg.showTime = timeDiffMinutes >= this.data.timeInterval; if (msg.showTime) lastShowTime = msg.timestamp; } processedMessages.push(msg); } if (lastShowTime) { this.setData({ lastShowTimeStamp: lastShowTime }); } return processedMessages; },
// 处理单条消息时间
processSingleMessageTime: function(message, messageList) { const msg = { ...message }; if (!msg.timestamp || isNaN(msg.timestamp) || msg.timestamp <= 0) { msg.timestamp = Date.now(); } if (messageList.length === 0) { msg.showTime = true; this.setData({ lastShowTimeStamp: msg.timestamp }); return msg; } const lastShowTime = this.data.lastShowTimeStamp; const timeDiffMinutes = (msg.timestamp - lastShowTime) / (1000 * 60); msg.showTime = timeDiffMinutes >= this.data.timeInterval; if (msg.showTime) { this.setData({ lastShowTimeStamp: msg.timestamp }); } return msg; },
// ========== 工具方法 ==========
// 格式化时间
formatTime: function(timestamp) { if (!timestamp || timestamp <= 0) return '未知时间'; const date = new Date(Number(timestamp)); if (isNaN(date.getTime())) return '未知时间'; const hours = date.getHours().toString().padStart(2, '0'); const minutes = date.getMinutes().toString().padStart(2, '0'); return `${hours}:${minutes}`; },
// 格式化文件大小
formatFileSize: function(bytes) { if (!bytes || bytes === 0) return '0B'; const units = ['B', 'KB', 'MB', 'GB']; let size = bytes; let unitIndex = 0; while (size >= 1024 && unitIndex < units.length - 1) { size /= 1024; unitIndex++; } return size.toFixed(1) + units[unitIndex]; },
// 阻止事件冒泡
stopPropagation: function() {}});
|