// ✨ 消息操作菜单组件逻辑 const messageInteractionManager = require('../../utils/message-interaction-manager.js'); Component({ properties: { // 是否显示菜单 visible: { type: Boolean, value: false }, // 消息对象 message: { type: Object, value: {} }, // 是否是自己的消息 isOwnMessage: { type: Boolean, value: false }, // 可用的操作 actions: { type: Object, value: { quote: true, // 引用回复 forward: true, // 转发 favorite: true, // 收藏 multiSelect: true, // 多选 copy: true, // 复制 recall: true, // 撤回 delete: true, // 删除 report: true // 举报 } }, // 是否显示表情回应 showReactions: { type: Boolean, value: true }, // 是否显示消息信息 showMessageInfo: { type: Boolean, value: false } }, data: { // 常用表情 commonEmojis: ['👍', '❤️', '😂', '😮', '😢', '😡'], // 是否可以撤回 canRecall: false, // 表情选择器 showEmojiPicker: false, currentEmojiCategory: 'recent', currentEmojiList: [], // 表情分类 emojiCategories: { recent: ['👍', '❤️', '😂', '😮', '😢', '😡', '🎉', '🔥'], smileys: ['😀', '😃', '😄', '😁', '😆', '😅', '😂', '🤣', '😊', '😇', '🙂', '🙃', '😉', '😌', '😍', '🥰', '😘', '😗', '😙', '😚', '😋', '😛', '😝', '😜', '🤪', '🤨', '🧐', '🤓', '😎', '🤩', '🥳'], gestures: ['👍', '👎', '👌', '✌️', '🤞', '🤟', '🤘', '🤙', '👈', '👉', '👆', '🖕', '👇', '☝️', '👋', '🤚', '🖐️', '✋', '🖖', '👏', '🙌', '🤲', '🤝', '🙏'], hearts: ['❤️', '🧡', '💛', '💚', '💙', '💜', '🖤', '🤍', '🤎', '💔', '❣️', '💕', '💞', '💓', '💗', '💖', '💘', '💝', '💟'] } }, observers: { 'message, isOwnMessage': function(message, isOwnMessage) { if (message && message.messageId) { this.checkRecallPermission(); } } }, lifetimes: { attached() { console.log('✨ 消息操作菜单组件已加载'); this.initEmojiList(); } }, methods: { // ✨ ===== 基础操作 ===== // 阻止事件冒泡 stopPropagation() { // 阻止点击事件冒泡到遮罩层 }, // 遮罩点击 onMaskTap() { this.closeMenu(); }, // 关闭菜单 closeMenu() { this.setData({ visible: false, showEmojiPicker: false }); this.triggerEvent('close'); }, // 👍 ===== 表情回应操作 ===== // 表情点击 async onReactionTap(e) { const emoji = e.currentTarget.dataset.emoji; console.log('👍 表情点击:', emoji); try { const userId = wx.getStorageSync('userId'); if (!userId) { wx.showToast({ title: '请先登录', icon: 'none' }); return; } // 添加表情回应 const result = await messageInteractionManager.addReaction( this.data.message.messageId, emoji, userId ); if (result.success) { // 触发表情回应事件 this.triggerEvent('reaction', { messageId: this.data.message.messageId, emoji: emoji, action: 'add' }); // 关闭菜单 this.closeMenu(); wx.showToast({ title: '表情回应已添加', icon: 'success' }); } else { wx.showToast({ title: result.error || '添加失败', icon: 'none' }); } } catch (error) { console.error('❌ 添加表情回应失败:', error); wx.showToast({ title: '操作失败', icon: 'none' }); } }, // 显示更多表情 showMoreEmojis() { this.setData({ showEmojiPicker: true, currentEmojiCategory: 'recent' }); this.updateEmojiList(); }, // 关闭表情选择器 closeEmojiPicker() { this.setData({ showEmojiPicker: false }); }, // 切换表情分类 switchEmojiCategory(e) { const category = e.currentTarget.dataset.category; this.setData({ currentEmojiCategory: category }); this.updateEmojiList(); }, // 表情选择 async onEmojiSelect(e) { const emoji = e.currentTarget.dataset.emoji; // 添加到最近使用 this.addToRecentEmojis(emoji); // 执行表情回应 await this.onReactionTap({ currentTarget: { dataset: { emoji } } }); }, // 初始化表情列表 initEmojiList() { this.setData({ currentEmojiList: this.data.emojiCategories.recent }); }, // 更新表情列表 updateEmojiList() { const category = this.data.currentEmojiCategory; const emojiList = this.data.emojiCategories[category] || []; this.setData({ currentEmojiList: emojiList }); }, // 添加到最近使用表情 addToRecentEmojis(emoji) { let recentEmojis = [...this.data.emojiCategories.recent]; // 移除已存在的 recentEmojis = recentEmojis.filter(e => e !== emoji); // 添加到开头 recentEmojis.unshift(emoji); // 限制数量 if (recentEmojis.length > 20) { recentEmojis = recentEmojis.slice(0, 20); } // 更新数据 this.setData({ [`emojiCategories.recent`]: recentEmojis }); // 如果当前显示的是最近分类,更新列表 if (this.data.currentEmojiCategory === 'recent') { this.setData({ currentEmojiList: recentEmojis }); } }, // 🎯 ===== 操作按钮处理 ===== // 操作点击 async onActionTap(e) { const action = e.currentTarget.dataset.action; console.log('🎯 操作点击:', action); switch (action) { case 'quote': this.handleQuote(); break; case 'forward': this.handleForward(); break; case 'favorite': this.handleFavorite(); break; case 'multiSelect': this.handleMultiSelect(); break; case 'copy': this.handleCopy(); break; case 'recall': this.handleRecall(); break; case 'delete': this.handleDelete(); break; case 'report': this.handleReport(); break; default: console.warn('⚠️ 未知操作:', action); } }, // 处理引用回复 handleQuote() { console.log('💬 处理引用回复'); this.triggerEvent('action', { action: 'quote', message: this.data.message }); this.closeMenu(); }, // 处理转发 handleForward() { console.log('📤 处理转发'); this.triggerEvent('action', { action: 'forward', message: this.data.message }); this.closeMenu(); }, // 处理收藏 async handleFavorite() { console.log('⭐ 处理收藏'); try { const userId = wx.getStorageSync('userId'); const messageId = this.data.message.messageId; const isFavorited = this.data.message.favorited; let result; if (isFavorited) { result = await messageInteractionManager.unfavoriteMessage(messageId, userId); } else { result = await messageInteractionManager.favoriteMessage(messageId, userId); } if (result.success) { this.triggerEvent('action', { action: 'favorite', message: this.data.message, favorited: !isFavorited }); wx.showToast({ title: isFavorited ? '已取消收藏' : '已收藏', icon: 'success' }); } else { wx.showToast({ title: result.error || '操作失败', icon: 'none' }); } } catch (error) { console.error('❌ 收藏操作失败:', error); wx.showToast({ title: '操作失败', icon: 'none' }); } this.closeMenu(); }, // 处理多选 handleMultiSelect() { console.log('📋 处理多选'); this.triggerEvent('action', { action: 'multiSelect', message: this.data.message }); this.closeMenu(); }, // 处理复制 handleCopy() { console.log('📄 处理复制'); if (this.data.message.msgType === 'text') { wx.setClipboardData({ data: this.data.message.content, success: () => { wx.showToast({ title: '已复制到剪贴板', icon: 'success' }); } }); } this.closeMenu(); }, // 处理撤回 async handleRecall() { console.log('🔄 处理撤回'); try { const userId = wx.getStorageSync('userId'); const messageId = this.data.message.messageId; const result = await messageInteractionManager.recallMessage(messageId, userId); if (result.success) { this.triggerEvent('action', { action: 'recall', message: this.data.message }); wx.showToast({ title: '消息已撤回', icon: 'success' }); } else { wx.showToast({ title: result.error || '撤回失败', icon: 'none' }); } } catch (error) { console.error('❌ 撤回消息失败:', error); wx.showToast({ title: '撤回失败', icon: 'none' }); } this.closeMenu(); }, // 处理删除 handleDelete() { console.log('🗑️ 处理删除'); wx.showModal({ title: '删除消息', content: '确定要删除这条消息吗?', success: (res) => { if (res.confirm) { this.triggerEvent('action', { action: 'delete', message: this.data.message }); } } }); this.closeMenu(); }, // 处理举报 handleReport() { console.log('⚠️ 处理举报'); wx.showActionSheet({ itemList: ['垃圾信息', '违法违规', '色情内容', '暴力内容', '其他'], success: (res) => { const reasons = ['spam', 'illegal', 'sexual', 'violence', 'other']; const reason = reasons[res.tapIndex]; this.triggerEvent('action', { action: 'report', message: this.data.message, reason: reason }); } }); this.closeMenu(); }, // 🔧 ===== 工具方法 ===== // 检查撤回权限 async checkRecallPermission() { try { const userId = wx.getStorageSync('userId'); const messageId = this.data.message.messageId; if (!userId || !messageId) { this.setData({ canRecall: false }); return; } const result = await messageInteractionManager.checkRecallPermission(messageId, userId); this.setData({ canRecall: result.allowed }); } catch (error) { console.error('❌ 检查撤回权限失败:', error); this.setData({ canRecall: false }); } }, // 格式化时间 formatTime(timestamp) { if (!timestamp) return ''; const date = new Date(timestamp); const now = new Date(); const diffMs = now.getTime() - date.getTime(); const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24)); if (diffDays === 0) { // 今天 return date.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' }); } else if (diffDays === 1) { // 昨天 return '昨天 ' + date.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' }); } else { // 更早 return date.toLocaleDateString('zh-CN') + ' ' + date.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' }); } }, // 获取消息类型文本 getMessageTypeText(msgType) { const typeMap = { 'text': '文本', 'image': '图片', 'video': '视频', 'voice': '语音', 'file': '文件', 'location': '位置', 'card': '名片' }; return typeMap[msgType] || '未知'; }, // 格式化文件大小 formatFileSize(size) { if (!size) return ''; const units = ['B', 'KB', 'MB', 'GB']; let unitIndex = 0; let fileSize = size; while (fileSize >= 1024 && unitIndex < units.length - 1) { fileSize /= 1024; unitIndex++; } return `${fileSize.toFixed(1)} ${units[unitIndex]}`; } } });