Initial Commit
This commit is contained in:
commit
1d71a02738
237 changed files with 64293 additions and 0 deletions
699
utils/group-chat-manager.js
Normal file
699
utils/group-chat-manager.js
Normal file
|
|
@ -0,0 +1,699 @@
|
|||
// 群聊管理器 - 微信小程序专用
|
||||
// 处理群聊创建、管理、成员管理、权限控制等功能
|
||||
|
||||
const apiClient = require('./api-client.js');
|
||||
|
||||
/**
|
||||
* 群聊管理器
|
||||
* 功能:
|
||||
* 1. 群聊创建和解散
|
||||
* 2. 群成员管理
|
||||
* 3. 群信息设置
|
||||
* 4. 群权限管理
|
||||
* 5. @提醒功能
|
||||
* 6. 群公告管理
|
||||
*/
|
||||
class GroupChatManager {
|
||||
constructor() {
|
||||
this.isInitialized = false;
|
||||
|
||||
// 群聊配置
|
||||
this.groupConfig = {
|
||||
// 群聊基本配置
|
||||
maxMembers: 500, // 最大成员数
|
||||
maxGroupNameLength: 20, // 群名称最大长度
|
||||
maxDescriptionLength: 200, // 群描述最大长度
|
||||
maxAnnouncementLength: 500, // 群公告最大长度
|
||||
|
||||
// 权限配置
|
||||
permissions: {
|
||||
owner: {
|
||||
name: '群主',
|
||||
level: 3,
|
||||
canInvite: true,
|
||||
canRemove: true,
|
||||
canSetAdmin: true,
|
||||
canEditInfo: true,
|
||||
canDissolve: true,
|
||||
canMute: true,
|
||||
canSetAnnouncement: true
|
||||
},
|
||||
admin: {
|
||||
name: '管理员',
|
||||
level: 2,
|
||||
canInvite: true,
|
||||
canRemove: true,
|
||||
canSetAdmin: false,
|
||||
canEditInfo: true,
|
||||
canDissolve: false,
|
||||
canMute: true,
|
||||
canSetAnnouncement: true
|
||||
},
|
||||
member: {
|
||||
name: '普通成员',
|
||||
level: 1,
|
||||
canInvite: false,
|
||||
canRemove: false,
|
||||
canSetAdmin: false,
|
||||
canEditInfo: false,
|
||||
canDissolve: false,
|
||||
canMute: false,
|
||||
canSetAnnouncement: false
|
||||
}
|
||||
},
|
||||
|
||||
// @提醒配置
|
||||
mention: {
|
||||
enabled: true,
|
||||
maxMentions: 10, // 单条消息最多@10个人
|
||||
allMemberKeyword: '所有人' // @全体成员关键词
|
||||
},
|
||||
|
||||
// 群设置默认值
|
||||
defaultSettings: {
|
||||
allowMemberInvite: true, // 允许成员邀请
|
||||
allowMemberModifyInfo: false, // 允许成员修改群信息
|
||||
muteAll: false, // 全员禁言
|
||||
showMemberNickname: true, // 显示成员昵称
|
||||
saveToContacts: true, // 保存到通讯录
|
||||
showQRCode: true // 显示群二维码
|
||||
}
|
||||
};
|
||||
|
||||
// 群聊缓存
|
||||
this.groupCache = new Map();
|
||||
this.memberCache = new Map();
|
||||
|
||||
// 当前用户信息
|
||||
this.currentUserId = null;
|
||||
|
||||
this.init();
|
||||
}
|
||||
|
||||
// 初始化群聊管理器
|
||||
async init() {
|
||||
if (this.isInitialized) return;
|
||||
|
||||
console.log('👥 初始化群聊管理器...');
|
||||
|
||||
try {
|
||||
// 获取当前用户ID
|
||||
this.currentUserId = wx.getStorageSync('userId');
|
||||
|
||||
// 加载群聊缓存
|
||||
await this.loadGroupCache();
|
||||
|
||||
this.isInitialized = true;
|
||||
console.log('✅ 群聊管理器初始化完成');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 群聊管理器初始化失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// 👥 ===== 群聊创建和管理 =====
|
||||
|
||||
// 创建群聊
|
||||
async createGroup(groupInfo) {
|
||||
try {
|
||||
console.log('👥 创建群聊:', groupInfo);
|
||||
|
||||
// 验证群聊信息
|
||||
const validation = this.validateGroupInfo(groupInfo);
|
||||
if (!validation.valid) {
|
||||
return { success: false, error: validation.error };
|
||||
}
|
||||
|
||||
// 调用API创建群聊
|
||||
const response = await apiClient.request({
|
||||
url: '/api/v1/groups',
|
||||
method: 'POST',
|
||||
data: {
|
||||
name: groupInfo.name,
|
||||
description: groupInfo.description || '',
|
||||
avatar: groupInfo.avatar || '',
|
||||
memberIds: groupInfo.memberIds || [],
|
||||
settings: { ...this.groupConfig.defaultSettings, ...groupInfo.settings }
|
||||
}
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
const group = response.data;
|
||||
|
||||
// 更新本地缓存
|
||||
this.updateGroupCache(group);
|
||||
|
||||
console.log('✅ 群聊创建成功:', group.groupId);
|
||||
return { success: true, data: group };
|
||||
} else {
|
||||
throw new Error(response.error || '创建群聊失败');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 创建群聊失败:', error);
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
}
|
||||
|
||||
// 解散群聊
|
||||
async dissolveGroup(groupId) {
|
||||
try {
|
||||
console.log('👥 解散群聊:', groupId);
|
||||
|
||||
// 检查权限
|
||||
const hasPermission = await this.checkPermission(groupId, 'canDissolve');
|
||||
if (!hasPermission) {
|
||||
return { success: false, error: '没有解散群聊的权限' };
|
||||
}
|
||||
|
||||
// 调用API解散群聊
|
||||
const response = await apiClient.request({
|
||||
url: `/api/v1/groups/${groupId}/dissolve`,
|
||||
method: 'POST'
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
// 清除本地缓存
|
||||
this.groupCache.delete(groupId);
|
||||
this.memberCache.delete(groupId);
|
||||
|
||||
console.log('✅ 群聊解散成功');
|
||||
return { success: true };
|
||||
} else {
|
||||
throw new Error(response.error || '解散群聊失败');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 解散群聊失败:', error);
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
}
|
||||
|
||||
// 退出群聊
|
||||
async leaveGroup(groupId) {
|
||||
try {
|
||||
console.log('👥 退出群聊:', groupId);
|
||||
|
||||
// 调用API退出群聊
|
||||
const response = await apiClient.request({
|
||||
url: `/api/v1/groups/${groupId}/leave`,
|
||||
method: 'POST'
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
// 清除本地缓存
|
||||
this.groupCache.delete(groupId);
|
||||
this.memberCache.delete(groupId);
|
||||
|
||||
console.log('✅ 退出群聊成功');
|
||||
return { success: true };
|
||||
} else {
|
||||
throw new Error(response.error || '退出群聊失败');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 退出群聊失败:', error);
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
}
|
||||
|
||||
// 👤 ===== 群成员管理 =====
|
||||
|
||||
// 邀请成员
|
||||
async inviteMembers(groupId, memberIds) {
|
||||
try {
|
||||
console.log('👤 邀请成员:', groupId, memberIds);
|
||||
|
||||
// 检查权限
|
||||
const hasPermission = await this.checkPermission(groupId, 'canInvite');
|
||||
if (!hasPermission) {
|
||||
return { success: false, error: '没有邀请成员的权限' };
|
||||
}
|
||||
|
||||
// 检查成员数量限制
|
||||
const currentMembers = await this.getGroupMembers(groupId);
|
||||
if (currentMembers.data && currentMembers.data.length + memberIds.length > this.groupConfig.maxMembers) {
|
||||
return { success: false, error: `群成员数量不能超过${this.groupConfig.maxMembers}人` };
|
||||
}
|
||||
|
||||
// 调用API邀请成员
|
||||
const response = await apiClient.request({
|
||||
url: `/api/v1/groups/${groupId}/members`,
|
||||
method: 'POST',
|
||||
data: {
|
||||
memberIds: memberIds
|
||||
}
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
// 更新成员缓存
|
||||
this.updateMemberCache(groupId, response.data.members);
|
||||
|
||||
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 removeMember(groupId, memberId) {
|
||||
try {
|
||||
console.log('👤 移除成员:', groupId, memberId);
|
||||
|
||||
// 检查权限
|
||||
const hasPermission = await this.checkPermission(groupId, 'canRemove');
|
||||
if (!hasPermission) {
|
||||
return { success: false, error: '没有移除成员的权限' };
|
||||
}
|
||||
|
||||
// 不能移除自己
|
||||
if (memberId === this.currentUserId) {
|
||||
return { success: false, error: '不能移除自己,请使用退出群聊功能' };
|
||||
}
|
||||
|
||||
// 调用API移除成员
|
||||
const response = await apiClient.request({
|
||||
url: `/api/v1/groups/${groupId}/members/${memberId}`,
|
||||
method: 'DELETE'
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
// 更新成员缓存
|
||||
this.removeMemberFromCache(groupId, memberId);
|
||||
|
||||
console.log('✅ 移除成员成功');
|
||||
return { success: true };
|
||||
} else {
|
||||
throw new Error(response.error || '移除成员失败');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 移除成员失败:', error);
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
}
|
||||
|
||||
// 设置管理员
|
||||
async setAdmin(groupId, memberId, isAdmin) {
|
||||
try {
|
||||
console.log('👤 设置管理员:', groupId, memberId, isAdmin);
|
||||
|
||||
// 检查权限
|
||||
const hasPermission = await this.checkPermission(groupId, 'canSetAdmin');
|
||||
if (!hasPermission) {
|
||||
return { success: false, error: '没有设置管理员的权限' };
|
||||
}
|
||||
|
||||
// 调用API设置管理员
|
||||
const response = await apiClient.request({
|
||||
url: `/api/v1/groups/${groupId}/members/${memberId}/admin`,
|
||||
method: 'PUT',
|
||||
data: {
|
||||
isAdmin: isAdmin
|
||||
}
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
// 更新成员缓存
|
||||
this.updateMemberRole(groupId, memberId, isAdmin ? 'admin' : 'member');
|
||||
|
||||
console.log('✅ 设置管理员成功');
|
||||
return { success: true };
|
||||
} else {
|
||||
throw new Error(response.error || '设置管理员失败');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 设置管理员失败:', error);
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
}
|
||||
|
||||
// 获取群成员列表
|
||||
async getGroupMembers(groupId, useCache = true) {
|
||||
try {
|
||||
// 先从缓存获取
|
||||
if (useCache && this.memberCache.has(groupId)) {
|
||||
const cached = this.memberCache.get(groupId);
|
||||
if (Date.now() - cached.timestamp < 300000) { // 5分钟缓存
|
||||
return { success: true, data: cached.members };
|
||||
}
|
||||
}
|
||||
|
||||
// 从服务器获取
|
||||
const response = await apiClient.request({
|
||||
url: `/api/v1/groups/${groupId}/members`,
|
||||
method: 'GET'
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
const members = response.data || [];
|
||||
|
||||
// 更新缓存
|
||||
this.memberCache.set(groupId, {
|
||||
members: members,
|
||||
timestamp: Date.now()
|
||||
});
|
||||
|
||||
return { success: true, data: members };
|
||||
} else {
|
||||
throw new Error(response.error || '获取群成员失败');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 获取群成员失败:', error);
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
}
|
||||
|
||||
// ⚙️ ===== 群信息设置 =====
|
||||
|
||||
// 更新群信息
|
||||
async updateGroupInfo(groupId, updates) {
|
||||
try {
|
||||
console.log('⚙️ 更新群信息:', groupId, updates);
|
||||
|
||||
// 检查权限
|
||||
const hasPermission = await this.checkPermission(groupId, 'canEditInfo');
|
||||
if (!hasPermission) {
|
||||
return { success: false, error: '没有修改群信息的权限' };
|
||||
}
|
||||
|
||||
// 验证更新信息
|
||||
const validation = this.validateGroupUpdates(updates);
|
||||
if (!validation.valid) {
|
||||
return { success: false, error: validation.error };
|
||||
}
|
||||
|
||||
// 调用API更新群信息
|
||||
const response = await apiClient.request({
|
||||
url: `/api/v1/groups/${groupId}`,
|
||||
method: 'PUT',
|
||||
data: updates
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
// 更新群聊缓存
|
||||
this.updateGroupCache(response.data);
|
||||
|
||||
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 setGroupAnnouncement(groupId, announcement) {
|
||||
try {
|
||||
console.log('⚙️ 设置群公告:', groupId);
|
||||
|
||||
// 检查权限
|
||||
const hasPermission = await this.checkPermission(groupId, 'canSetAnnouncement');
|
||||
if (!hasPermission) {
|
||||
return { success: false, error: '没有设置群公告的权限' };
|
||||
}
|
||||
|
||||
// 验证公告长度
|
||||
if (announcement.length > this.groupConfig.maxAnnouncementLength) {
|
||||
return { success: false, error: `群公告不能超过${this.groupConfig.maxAnnouncementLength}字符` };
|
||||
}
|
||||
|
||||
// 调用API设置群公告
|
||||
const response = await apiClient.request({
|
||||
url: `/api/v1/groups/${groupId}/announcement`,
|
||||
method: 'PUT',
|
||||
data: {
|
||||
announcement: announcement
|
||||
}
|
||||
});
|
||||
|
||||
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 };
|
||||
}
|
||||
}
|
||||
|
||||
// 📢 ===== @提醒功能 =====
|
||||
|
||||
// 解析@提醒
|
||||
parseMentions(content) {
|
||||
const mentions = [];
|
||||
const mentionRegex = /@([^\s@]+)/g;
|
||||
let match;
|
||||
|
||||
while ((match = mentionRegex.exec(content)) !== null) {
|
||||
const mentionText = match[1];
|
||||
|
||||
if (mentionText === this.groupConfig.mention.allMemberKeyword) {
|
||||
// @全体成员
|
||||
mentions.push({
|
||||
type: 'all',
|
||||
text: mentionText,
|
||||
start: match.index,
|
||||
end: match.index + match[0].length
|
||||
});
|
||||
} else {
|
||||
// @特定成员
|
||||
mentions.push({
|
||||
type: 'user',
|
||||
text: mentionText,
|
||||
start: match.index,
|
||||
end: match.index + match[0].length
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return mentions;
|
||||
}
|
||||
|
||||
// 验证@提醒
|
||||
async validateMentions(groupId, mentions) {
|
||||
try {
|
||||
if (mentions.length > this.groupConfig.mention.maxMentions) {
|
||||
return { valid: false, error: `单条消息最多只能@${this.groupConfig.mention.maxMentions}个人` };
|
||||
}
|
||||
|
||||
// 获取群成员列表
|
||||
const membersResult = await this.getGroupMembers(groupId);
|
||||
if (!membersResult.success) {
|
||||
return { valid: false, error: '获取群成员列表失败' };
|
||||
}
|
||||
|
||||
const members = membersResult.data;
|
||||
const validMentions = [];
|
||||
|
||||
for (const mention of mentions) {
|
||||
if (mention.type === 'all') {
|
||||
// 检查@全体成员权限
|
||||
const hasPermission = await this.checkPermission(groupId, 'canMentionAll');
|
||||
if (hasPermission) {
|
||||
validMentions.push({
|
||||
...mention,
|
||||
userIds: members.map(m => m.userId)
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// 查找对应的成员
|
||||
const member = members.find(m =>
|
||||
m.nickname === mention.text ||
|
||||
m.username === mention.text ||
|
||||
m.userId === mention.text
|
||||
);
|
||||
|
||||
if (member) {
|
||||
validMentions.push({
|
||||
...mention,
|
||||
userId: member.userId,
|
||||
userIds: [member.userId]
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { valid: true, mentions: validMentions };
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 验证@提醒失败:', error);
|
||||
return { valid: false, error: '验证@提醒失败' };
|
||||
}
|
||||
}
|
||||
|
||||
// 🔧 ===== 工具方法 =====
|
||||
|
||||
// 验证群聊信息
|
||||
validateGroupInfo(groupInfo) {
|
||||
if (!groupInfo.name || groupInfo.name.trim().length === 0) {
|
||||
return { valid: false, error: '群名称不能为空' };
|
||||
}
|
||||
|
||||
if (groupInfo.name.length > this.groupConfig.maxGroupNameLength) {
|
||||
return { valid: false, error: `群名称不能超过${this.groupConfig.maxGroupNameLength}字符` };
|
||||
}
|
||||
|
||||
if (groupInfo.description && groupInfo.description.length > this.groupConfig.maxDescriptionLength) {
|
||||
return { valid: false, error: `群描述不能超过${this.groupConfig.maxDescriptionLength}字符` };
|
||||
}
|
||||
|
||||
if (groupInfo.memberIds && groupInfo.memberIds.length > this.groupConfig.maxMembers) {
|
||||
return { valid: false, error: `群成员数量不能超过${this.groupConfig.maxMembers}人` };
|
||||
}
|
||||
|
||||
return { valid: true };
|
||||
}
|
||||
|
||||
// 验证群信息更新
|
||||
validateGroupUpdates(updates) {
|
||||
if (updates.name !== undefined) {
|
||||
if (!updates.name || updates.name.trim().length === 0) {
|
||||
return { valid: false, error: '群名称不能为空' };
|
||||
}
|
||||
|
||||
if (updates.name.length > this.groupConfig.maxGroupNameLength) {
|
||||
return { valid: false, error: `群名称不能超过${this.groupConfig.maxGroupNameLength}字符` };
|
||||
}
|
||||
}
|
||||
|
||||
if (updates.description !== undefined && updates.description.length > this.groupConfig.maxDescriptionLength) {
|
||||
return { valid: false, error: `群描述不能超过${this.groupConfig.maxDescriptionLength}字符` };
|
||||
}
|
||||
|
||||
return { valid: true };
|
||||
}
|
||||
|
||||
// 检查权限
|
||||
async checkPermission(groupId, permission) {
|
||||
try {
|
||||
const userRole = await this.getUserRole(groupId, this.currentUserId);
|
||||
if (!userRole) return false;
|
||||
|
||||
const roleConfig = this.groupConfig.permissions[userRole];
|
||||
return roleConfig && roleConfig[permission];
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 检查权限失败:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 获取用户在群中的角色
|
||||
async getUserRole(groupId, userId) {
|
||||
try {
|
||||
const membersResult = await this.getGroupMembers(groupId);
|
||||
if (!membersResult.success) return null;
|
||||
|
||||
const member = membersResult.data.find(m => m.userId === userId);
|
||||
return member ? member.role : null;
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 获取用户角色失败:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// 更新群聊缓存
|
||||
updateGroupCache(group) {
|
||||
this.groupCache.set(group.groupId, {
|
||||
...group,
|
||||
timestamp: Date.now()
|
||||
});
|
||||
}
|
||||
|
||||
// 更新成员缓存
|
||||
updateMemberCache(groupId, members) {
|
||||
this.memberCache.set(groupId, {
|
||||
members: members,
|
||||
timestamp: Date.now()
|
||||
});
|
||||
}
|
||||
|
||||
// 从缓存中移除成员
|
||||
removeMemberFromCache(groupId, memberId) {
|
||||
const cached = this.memberCache.get(groupId);
|
||||
if (cached) {
|
||||
cached.members = cached.members.filter(m => m.userId !== memberId);
|
||||
this.memberCache.set(groupId, cached);
|
||||
}
|
||||
}
|
||||
|
||||
// 更新成员角色
|
||||
updateMemberRole(groupId, memberId, role) {
|
||||
const cached = this.memberCache.get(groupId);
|
||||
if (cached) {
|
||||
const member = cached.members.find(m => m.userId === memberId);
|
||||
if (member) {
|
||||
member.role = role;
|
||||
this.memberCache.set(groupId, cached);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 加载群聊缓存
|
||||
async loadGroupCache() {
|
||||
try {
|
||||
const cached = wx.getStorageSync('groupCache') || {};
|
||||
this.groupCache = new Map(Object.entries(cached));
|
||||
} catch (error) {
|
||||
console.error('❌ 加载群聊缓存失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// 保存群聊缓存
|
||||
saveGroupCache() {
|
||||
try {
|
||||
const cacheObj = Object.fromEntries(this.groupCache);
|
||||
wx.setStorageSync('groupCache', cacheObj);
|
||||
} catch (error) {
|
||||
console.error('❌ 保存群聊缓存失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取群聊管理器状态
|
||||
getStatus() {
|
||||
return {
|
||||
isInitialized: this.isInitialized,
|
||||
groupCount: this.groupCache.size,
|
||||
memberCacheCount: this.memberCache.size,
|
||||
currentUserId: this.currentUserId,
|
||||
config: this.groupConfig
|
||||
};
|
||||
}
|
||||
|
||||
// 清除所有缓存
|
||||
clearAllCache() {
|
||||
this.groupCache.clear();
|
||||
this.memberCache.clear();
|
||||
wx.removeStorageSync('groupCache');
|
||||
console.log('👥 已清除所有群聊缓存');
|
||||
}
|
||||
|
||||
// 重置管理器
|
||||
reset() {
|
||||
this.clearAllCache();
|
||||
this.currentUserId = null;
|
||||
this.isInitialized = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 创建全局实例
|
||||
const groupChatManager = new GroupChatManager();
|
||||
|
||||
module.exports = groupChatManager;
|
||||
Loading…
Add table
Add a link
Reference in a new issue