miniprogramme/utils/message-interaction-manager.js

726 lines
20 KiB
JavaScript
Raw Normal View History

2025-09-12 16:08:17 +08:00
// 消息交互管理器 - 微信小程序专用
// 处理消息表情回应、引用回复、撤回、转发等交互功能
const apiClient = require('./api-client.js');
/**
* 消息交互管理器
* 功能
* 1. 消息表情回应
* 2. 消息引用回复
* 3. 消息撤回功能
* 4. 消息转发功能
* 5. 消息收藏功能
* 6. 消息多选操作
*/
class MessageInteractionManager {
constructor() {
this.isInitialized = false;
// 交互配置
this.interactionConfig = {
// 表情回应配置
reactions: {
enabled: true,
maxReactions: 6, // 每条消息最多6种表情
maxUsersPerReaction: 100, // 每种表情最多100个用户
commonEmojis: ['👍', '❤️', '😂', '😮', '😢', '😡'], // 常用表情
customEmojis: [] // 自定义表情
},
// 引用回复配置
quote: {
enabled: true,
maxQuoteLength: 100, // 引用内容最大长度
showOriginalSender: true, // 显示原发送者
showTimestamp: true // 显示时间戳
},
// 撤回配置
recall: {
enabled: true,
timeLimit: 2 * 60 * 1000, // 2分钟内可撤回
showRecallMessage: true, // 显示撤回提示
allowRecallOthers: false // 是否允许撤回他人消息(群主/管理员)
},
// 转发配置
forward: {
enabled: true,
maxForwardCount: 5, // 最多同时转发5条消息
preserveFormat: true, // 保持原格式
showForwardSource: true // 显示转发来源
},
// 收藏配置
favorite: {
enabled: true,
maxFavorites: 1000, // 最多收藏1000条
syncToCloud: true // 同步到云端
}
};
// 当前操作状态
this.currentOperation = {
type: null, // 'reaction', 'quote', 'forward', 'select'
messageId: null,
data: null
};
// 多选状态
this.multiSelectMode = false;
this.selectedMessages = new Set();
// 表情回应缓存
this.reactionsCache = new Map();
this.init();
}
// 初始化交互管理器
async init() {
if (this.isInitialized) return;
console.log('✨ 初始化消息交互管理器...');
try {
// 加载用户收藏
await this.loadUserFavorites();
// 加载表情回应缓存
await this.loadReactionsCache();
this.isInitialized = true;
console.log('✅ 消息交互管理器初始化完成');
} catch (error) {
console.error('❌ 消息交互管理器初始化失败:', error);
}
}
// 👍 ===== 表情回应功能 =====
// 添加表情回应
async addReaction(messageId, emoji, userId) {
try {
console.log('👍 添加表情回应:', messageId, emoji, userId);
// 验证参数
if (!messageId || !emoji || !userId) {
throw new Error('参数不完整');
}
// 检查是否已经回应过
const existingReaction = await this.getUserReaction(messageId, userId);
if (existingReaction === emoji) {
console.log('⚠️ 用户已经添加过相同表情');
return { success: false, error: '已经添加过相同表情' };
}
// 如果用户已有其他表情回应,先移除
if (existingReaction) {
await this.removeReaction(messageId, existingReaction, userId);
}
// 调用API添加表情回应
const response = await apiClient.request({
url: '/api/v1/messages/reactions',
method: 'POST',
data: {
messageId: messageId,
emoji: emoji,
userId: userId
}
});
if (response.success) {
// 更新本地缓存
this.updateReactionCache(messageId, emoji, userId, 'add');
console.log('✅ 表情回应添加成功');
return { success: true, data: response.data };
} else {
throw new Error(response.error || '添加表情回应失败');
}
} catch (error) {
console.error('❌ 添加表情回应失败:', error);
return { success: false, error: error.message };
}
}
// 移除表情回应
async removeReaction(messageId, emoji, userId) {
try {
console.log('👎 移除表情回应:', messageId, emoji, userId);
// 调用API移除表情回应
const response = await apiClient.request({
url: '/api/v1/messages/reactions',
method: 'DELETE',
data: {
messageId: messageId,
emoji: emoji,
userId: userId
}
});
if (response.success) {
// 更新本地缓存
this.updateReactionCache(messageId, emoji, userId, 'remove');
console.log('✅ 表情回应移除成功');
return { success: true };
} else {
throw new Error(response.error || '移除表情回应失败');
}
} catch (error) {
console.error('❌ 移除表情回应失败:', error);
return { success: false, error: error.message };
}
}
// 获取消息的所有表情回应
async getMessageReactions(messageId) {
try {
// 先从缓存获取
const cached = this.reactionsCache.get(messageId);
if (cached && (Date.now() - cached.timestamp) < 60000) { // 1分钟缓存
return { success: true, data: cached.reactions };
}
// 从服务器获取
const response = await apiClient.request({
url: `/api/v1/messages/${messageId}/reactions`,
method: 'GET'
});
if (response.success) {
const reactions = response.data || [];
// 更新缓存
this.reactionsCache.set(messageId, {
reactions: reactions,
timestamp: Date.now()
});
return { success: true, data: reactions };
} else {
throw new Error(response.error || '获取表情回应失败');
}
} catch (error) {
console.error('❌ 获取表情回应失败:', error);
return { success: false, error: error.message };
}
}
// 获取用户对消息的表情回应
async getUserReaction(messageId, userId) {
try {
const result = await this.getMessageReactions(messageId);
if (result.success) {
const userReaction = result.data.find(reaction =>
reaction.users && reaction.users.includes(userId)
);
return userReaction ? userReaction.emoji : null;
}
return null;
} catch (error) {
console.error('❌ 获取用户表情回应失败:', error);
return null;
}
}
// 更新表情回应缓存
updateReactionCache(messageId, emoji, userId, action) {
const cached = this.reactionsCache.get(messageId);
if (!cached) return;
let reactions = cached.reactions;
let emojiReaction = reactions.find(r => r.emoji === emoji);
if (action === 'add') {
if (emojiReaction) {
// 添加用户到现有表情
if (!emojiReaction.users.includes(userId)) {
emojiReaction.users.push(userId);
emojiReaction.count = emojiReaction.users.length;
}
} else {
// 创建新的表情回应
reactions.push({
emoji: emoji,
count: 1,
users: [userId]
});
}
} else if (action === 'remove') {
if (emojiReaction) {
// 从表情中移除用户
emojiReaction.users = emojiReaction.users.filter(id => id !== userId);
emojiReaction.count = emojiReaction.users.length;
// 如果没有用户了,移除整个表情
if (emojiReaction.count === 0) {
reactions = reactions.filter(r => r.emoji !== emoji);
}
}
}
// 更新缓存
this.reactionsCache.set(messageId, {
reactions: reactions,
timestamp: Date.now()
});
}
// 💬 ===== 引用回复功能 =====
// 创建引用回复
createQuoteReply(originalMessage, replyContent) {
try {
console.log('💬 创建引用回复:', originalMessage.messageId);
// 生成引用内容
const quoteContent = this.generateQuoteContent(originalMessage);
// 构建引用回复消息
const quoteReply = {
type: 'quote',
content: replyContent,
quote: {
messageId: originalMessage.messageId,
senderId: originalMessage.senderId,
senderName: originalMessage.senderName,
content: quoteContent,
timestamp: originalMessage.timestamp,
msgType: originalMessage.msgType
}
};
console.log('✅ 引用回复创建成功');
return { success: true, data: quoteReply };
} catch (error) {
console.error('❌ 创建引用回复失败:', error);
return { success: false, error: error.message };
}
}
// 生成引用内容
generateQuoteContent(message) {
let content = '';
switch (message.msgType) {
case 'text':
content = message.content;
// 限制长度
if (content.length > this.interactionConfig.quote.maxQuoteLength) {
content = content.substring(0, this.interactionConfig.quote.maxQuoteLength) + '...';
}
break;
case 'image':
content = '[图片]';
break;
case 'video':
content = '[视频]';
break;
case 'voice':
content = '[语音]';
break;
case 'file':
content = '[文件]';
break;
case 'location':
content = '[位置]';
break;
default:
content = '[消息]';
}
return content;
}
// 🔄 ===== 消息撤回功能 =====
// 撤回消息
async recallMessage(messageId, userId) {
try {
console.log('🔄 撤回消息:', messageId, userId);
// 检查撤回权限和时间限制
const canRecall = await this.checkRecallPermission(messageId, userId);
if (!canRecall.allowed) {
return { success: false, error: canRecall.reason };
}
// 调用API撤回消息
const response = await apiClient.request({
url: `/api/v1/messages/${messageId}/recall`,
method: 'POST',
data: {
userId: userId
}
});
if (response.success) {
console.log('✅ 消息撤回成功');
return { success: true, data: response.data };
} else {
throw new Error(response.error || '撤回消息失败');
}
} catch (error) {
console.error('❌ 撤回消息失败:', error);
return { success: false, error: error.message };
}
}
// 检查撤回权限
async checkRecallPermission(messageId, userId) {
try {
// 获取消息信息
const messageInfo = await this.getMessageInfo(messageId);
if (!messageInfo) {
return { allowed: false, reason: '消息不存在' };
}
// 检查是否是消息发送者
if (messageInfo.senderId !== userId) {
// 检查是否有管理员权限
if (!this.interactionConfig.recall.allowRecallOthers) {
return { allowed: false, reason: '只能撤回自己的消息' };
}
}
// 检查时间限制
const now = Date.now();
const messageTime = messageInfo.timestamp;
const timeDiff = now - messageTime;
if (timeDiff > this.interactionConfig.recall.timeLimit) {
return { allowed: false, reason: '超过撤回时间限制' };
}
return { allowed: true };
} catch (error) {
console.error('❌ 检查撤回权限失败:', error);
return { allowed: false, reason: '检查权限失败' };
}
}
// 📤 ===== 消息转发功能 =====
// 转发消息
async forwardMessages(messageIds, targetConversations) {
try {
console.log('📤 转发消息:', messageIds, targetConversations);
// 验证参数
if (!messageIds.length || !targetConversations.length) {
throw new Error('参数不完整');
}
// 检查转发数量限制
if (messageIds.length > this.interactionConfig.forward.maxForwardCount) {
throw new Error(`最多只能同时转发${this.interactionConfig.forward.maxForwardCount}条消息`);
}
// 获取消息详情
const messages = await this.getMessagesInfo(messageIds);
if (!messages.length) {
throw new Error('获取消息信息失败');
}
// 执行转发
const results = [];
for (const targetId of targetConversations) {
const result = await this.forwardToConversation(messages, targetId);
results.push({
targetId: targetId,
success: result.success,
error: result.error
});
}
console.log('✅ 消息转发完成');
return { success: true, data: results };
} catch (error) {
console.error('❌ 转发消息失败:', error);
return { success: false, error: error.message };
}
}
// 转发到指定会话
async forwardToConversation(messages, targetConversationId) {
try {
// 构建转发消息
const forwardMessages = messages.map(msg => this.buildForwardMessage(msg));
// 调用API转发
const response = await apiClient.request({
url: '/api/v1/messages/forward',
method: 'POST',
data: {
messages: forwardMessages,
targetConversationId: targetConversationId,
preserveFormat: this.interactionConfig.forward.preserveFormat,
showSource: this.interactionConfig.forward.showForwardSource
}
});
if (response.success) {
return { success: true, data: response.data };
} else {
throw new Error(response.error || '转发失败');
}
} catch (error) {
console.error('❌ 转发到会话失败:', error);
return { success: false, error: error.message };
}
}
// 构建转发消息
buildForwardMessage(originalMessage) {
return {
originalMessageId: originalMessage.messageId,
content: originalMessage.content,
msgType: originalMessage.msgType,
originalSender: originalMessage.senderName,
originalTimestamp: originalMessage.timestamp,
forwardedAt: Date.now()
};
}
// ⭐ ===== 消息收藏功能 =====
// 收藏消息
async favoriteMessage(messageId, userId) {
try {
console.log('⭐ 收藏消息:', messageId, userId);
// 检查是否已收藏
const isFavorited = await this.isMessageFavorited(messageId, userId);
if (isFavorited) {
return { success: false, error: '消息已收藏' };
}
// 调用API收藏
const response = await apiClient.request({
url: '/api/v1/messages/favorite',
method: 'POST',
data: {
messageId: messageId,
userId: userId
}
});
if (response.success) {
console.log('✅ 消息收藏成功');
return { success: true, data: response.data };
} else {
throw new Error(response.error || '收藏失败');
}
} catch (error) {
console.error('❌ 收藏消息失败:', error);
return { success: false, error: error.message };
}
}
// 取消收藏消息
async unfavoriteMessage(messageId, userId) {
try {
console.log('⭐ 取消收藏消息:', messageId, userId);
// 调用API取消收藏
const response = await apiClient.request({
url: `/api/v1/messages/favorite/${messageId}`,
method: 'DELETE',
data: {
userId: userId
}
});
if (response.success) {
console.log('✅ 取消收藏成功');
return { success: true };
} else {
throw new Error(response.error || '取消收藏失败');
}
} catch (error) {
console.error('❌ 取消收藏失败:', error);
return { success: false, error: error.message };
}
}
// 检查消息是否已收藏
async isMessageFavorited(messageId, userId) {
try {
const response = await apiClient.request({
url: `/api/v1/messages/favorite/check`,
method: 'GET',
data: {
messageId: messageId,
userId: userId
}
});
return response.success && response.data.favorited;
} catch (error) {
console.error('❌ 检查收藏状态失败:', error);
return false;
}
}
// 📋 ===== 多选操作功能 =====
// 进入多选模式
enterMultiSelectMode(initialMessageId = null) {
console.log('📋 进入多选模式');
this.multiSelectMode = true;
this.selectedMessages.clear();
if (initialMessageId) {
this.selectedMessages.add(initialMessageId);
}
this.currentOperation = {
type: 'select',
messageId: null,
data: {
selectedCount: this.selectedMessages.size
}
};
}
// 退出多选模式
exitMultiSelectMode() {
console.log('📋 退出多选模式');
this.multiSelectMode = false;
this.selectedMessages.clear();
this.currentOperation = {
type: null,
messageId: null,
data: null
};
}
// 切换消息选择状态
toggleMessageSelection(messageId) {
if (this.selectedMessages.has(messageId)) {
this.selectedMessages.delete(messageId);
} else {
this.selectedMessages.add(messageId);
}
this.currentOperation.data.selectedCount = this.selectedMessages.size;
console.log('📋 消息选择状态切换:', messageId, this.selectedMessages.size);
}
// 获取选中的消息
getSelectedMessages() {
return Array.from(this.selectedMessages);
}
// 🔧 ===== 工具方法 =====
// 获取消息信息
async getMessageInfo(messageId) {
try {
const response = await apiClient.request({
url: `/api/v1/messages/${messageId}`,
method: 'GET'
});
return response.success ? response.data : null;
} catch (error) {
console.error('❌ 获取消息信息失败:', error);
return null;
}
}
// 获取多条消息信息
async getMessagesInfo(messageIds) {
try {
const response = await apiClient.request({
url: '/api/v1/messages/batch',
method: 'POST',
data: {
messageIds: messageIds
}
});
return response.success ? response.data : [];
} catch (error) {
console.error('❌ 获取消息信息失败:', error);
return [];
}
}
// 加载用户收藏
async loadUserFavorites() {
try {
const favorites = wx.getStorageSync('userFavorites') || [];
this.userFavorites = new Set(favorites);
} catch (error) {
console.error('❌ 加载用户收藏失败:', error);
}
}
// 加载表情回应缓存
async loadReactionsCache() {
try {
const cached = wx.getStorageSync('reactionsCache') || {};
this.reactionsCache = new Map(Object.entries(cached));
} catch (error) {
console.error('❌ 加载表情回应缓存失败:', error);
}
}
// 保存表情回应缓存
saveReactionsCache() {
try {
const cacheObj = Object.fromEntries(this.reactionsCache);
wx.setStorageSync('reactionsCache', cacheObj);
} catch (error) {
console.error('❌ 保存表情回应缓存失败:', error);
}
}
// 获取当前操作状态
getCurrentOperation() {
return { ...this.currentOperation };
}
// 获取交互配置
getInteractionConfig() {
return { ...this.interactionConfig };
}
// 重置管理器
reset() {
this.exitMultiSelectMode();
this.reactionsCache.clear();
this.currentOperation = {
type: null,
messageId: null,
data: null
};
}
}
// 创建全局实例
const messageInteractionManager = new MessageInteractionManager();
module.exports = messageInteractionManager;