question_uniapp/static/im/mattermost.js
cansnow 56442ab47d 修正服务器地址,修正聊天内容跟服务器的联动,
服务器有个设置 不会通过ws发送当前发送的信息,目前是关掉的,找不到设置在上面地方了
2025-06-08 21:19:07 +08:00

1069 lines
34 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import store from '@/config/store';
import base from '@/config/baseUrl';
class MattermostClient {
constructor() {
// 基础属性
this.ready = false;
this.userBaseUrl = "https://im.dxmt.io"; // 用户 API
this.adminBaseUrl = "https://api.dxmt.io"; // 管理员 API
this.ws = null;
this.wsUrl = '';
this.userToken = ''; // 用户令牌
this.adminToken = ''; // 管理员令牌
this.connected = false;
this.authenticated = false;
this.sequence = 1;
// 重连相关
this.reconnectAttempts = 0;
this.maxReconnectAttempts = 5;
this.reconnectInterval = 3000;
this.reconnectTimer = null;
// 心跳相关
this.heartbeatInterval = 30000; // 30秒
this.heartbeatTimer = null;
this.lastHeartbeatResponse = Date.now();
// 消息处理
this.messageHandlers = new Map(); // 修改为 Map 类型key 为事件名value 为 Set 类型的处理器集合
this.pendingMessages = new Map(); // 存储等待响应的消息
this.messageTimeoutEnabled = false; // 消息响应超时开关,默认关闭
this.messageTimeout = 10000; // 消息响应超时时间(毫秒)
// 状态回调
this.statusChangeCallbacks = new Set();
// 频道相关
this.channels = new Map(); // 存储频道信息
this.directChannels = new Map(); // 存储私聊频道
this.unreadCounts = new Map(); // 存储未读消息数
// 用户相关
this.currentUser = null;
this.userStatuses = new Map(); // 存储用户在线状态
this.userRoles = new Map(); // 存储用户角色
// 消息相关
this.messageCache = new Map(); // 缓存消息
this.deletedMessages = new Set(); // 记录已删除的消息
this.kown_users={}; // 存储已知的用户信息
}
// 初始化连接
async init() {
if(this.ready){
return;
}
if (!store.state.userInfo || !store.state.userInfo.im_token || !store.state.userInfo.token) {
console.log('用户令牌是必需的');
return ;
}
this.userToken = store.state.userInfo.im_token;
this.adminToken = store.state.userInfo.token;
this.currentUser = store.state.userInfo.im_user;
this.kown_users[this.currentUser.id] = this.currentUser;
this.getCurrentUser();
this.ready = true;
// 根据环境选择 ws 或 wss
const protocol = process.env.NODE_ENV === 'development' ? 'ws' : 'wss';
// 构建 WebSocket URL使用用户 API 域名
const connectionId = Date.now().toString(36) + Math.random().toString(36).substr(2);
this.wsUrl = `${protocol}://im.sjqqzc.top/api/v4/websocket?connection_id=${connectionId}&sequence_number=0`;
// 重置状态
this.sequence = 1;
this.reconnectAttempts = 0;
this.authenticated = false;
// 建立新连接
await this.connect();
// 启动心跳检测
this.startHeartbeat();
}
// 建立 WebSocket 连接
connect() {
return new Promise((resolve, reject) => {
try {
// 清理可能存在的旧连接
if (this.ws) {
return ;
//this.ws.close();
//this.ws = null;
}
this.ws = uni.connectSocket({
url: this.wsUrl,
header: {
'Authorization': `Bearer ${this.userToken}`
},
multiple: true,
success: () => {
console.log('WebSocket 连接创建成功');
},
fail: (error) => {
console.error('WebSocket 连接创建失败:', error);
this.handleConnectionError(error);
reject(error);
}
});
this.ws.onOpen(() => {
console.log('WebSocket 已打开,准备认证');
this.connected = true;
this.notifyStatusChange('connected');
// 发送认证信息,使用正确的认证消息格式
const authMessage = {
action: 'authentication_challenge',
seq: this.sequence,
data: {
token: this.userToken
}
};
this.sequence++;
this.ws.send({
data: JSON.stringify(authMessage),
success: () => {
console.log('认证信息发送成功:', authMessage);
// 注意:这里不立即设置 authenticated 为 true
// 等待服务器的认证响应
},
fail: (error) => {
console.error('认证信息发送失败:', error);
this.handleConnectionError(error);
reject(error);
}
});
});
this.ws.onClose(() => {
console.log('WebSocket 已关闭');
this.handleConnectionClose();
});
this.ws.onError((error) => {
console.error('WebSocket 错误:', error);
this.handleConnectionError(error);
});
this.ws.onMessage((res) => {
try {
const message = JSON.parse(res.data);
console.log('收到消息:', message);
// 处理认证响应
if (message.event === 'hello') {
console.log('认证成功');
this.authenticated = true;
this.notifyStatusChange('authenticated');
this.reconnectAttempts = 0;
resolve();
return;
}
// 处理认证失败
if (message.event === 'authentication_challenge' && message.data && message.data.status !== 'OK') {
console.error('认证失败:', message);
this.handleConnectionError(new Error('认证失败'));
reject(new Error('认证失败'));
return;
}
this.handleMessage(message);
} catch (error) {
console.error('消息解析错误:', error);
}
});
} catch (error) {
console.error('创建 WebSocket 连接失败:', error);
this.handleConnectionError(error);
reject(error);
}
});
}
// 处理连接错误
handleConnectionError(error) {
this.connected = false;
this.authenticated = false;
this.notifyStatusChange('error', error);
this.handleReconnect();
}
// 处理连接关闭
handleConnectionClose() {
this.connected = false;
this.authenticated = false;
this.notifyStatusChange('disconnected');
this.stopHeartbeat();
this.handleReconnect();
}
// 处理重连
handleReconnect() {
if (this.reconnectTimer) {
clearTimeout(this.reconnectTimer);
}
if (this.reconnectAttempts < this.maxReconnectAttempts) {
this.reconnectAttempts++;
console.log(`尝试重连 (${this.reconnectAttempts}/${this.maxReconnectAttempts})...`);
this.notifyStatusChange('reconnecting', this.reconnectAttempts);
this.reconnectTimer = setTimeout(() => {
this.connect().catch(error => {
console.error('重连失败:', error);
});
}, this.reconnectInterval);
} else {
console.error('达到最大重连次数,停止重连');
this.notifyStatusChange('failed');
}
}
// 启动心跳检测
startHeartbeat() {
if (this.heartbeatTimer) {
clearInterval(this.heartbeatTimer);
}
this.heartbeatTimer = setInterval(() => {
if (this.connected && this.authenticated) {
const now = Date.now();
if (now - this.lastHeartbeatResponse > this.heartbeatInterval * 2) {
console.log('心跳超时,准备重连');
this.handleConnectionClose();
return;
}
// 发送 ping 消息
this.sendWebSocketMessage('ping').catch(error => {
console.error('心跳消息发送失败:', error);
});
}
}, this.heartbeatInterval);
}
// 停止心跳检测
stopHeartbeat() {
if (this.heartbeatTimer) {
clearInterval(this.heartbeatTimer);
this.heartbeatTimer = null;
}
}
// 设置消息响应超时开关
setMessageTimeoutEnabled(enabled) {
this.messageTimeoutEnabled = enabled;
console.log(`消息响应超时已${enabled ? '启用' : '禁用'}`);
}
// 设置消息响应超时时间
setMessageTimeout(timeout) {
if (timeout < 1000) {
console.warn('消息响应超时时间不能小于1000毫秒');
return;
}
this.messageTimeout = timeout;
console.log(`消息响应超时时间已设置为${timeout}毫秒`);
}
// 获取消息响应超时设置
getMessageTimeoutSettings() {
return {
enabled: this.messageTimeoutEnabled,
timeout: this.messageTimeout
};
}
// 发送 WebSocket 消息
sendWebSocketMessage(action, data = {}) {
if (!this.connected) {
return Promise.reject(new Error('WebSocket 未连接'));
}
// 构建符合 Mattermost 格式的消息
const message = {
action,
seq: this.sequence
};
// 只有在非 ping 消息时才添加其他数据
if (action !== 'ping' && Object.keys(data).length > 0) {
Object.assign(message, data);
}
// 增加序列号
this.sequence++;
return new Promise((resolve, reject) => {
// 存储等待响应的消息
this.pendingMessages.set(message.seq, { resolve, reject });
// 设置超时处理
let timeout;
if (this.messageTimeoutEnabled) {
timeout = setTimeout(() => {
if (this.pendingMessages.has(message.seq)) {
this.pendingMessages.delete(message.seq);
reject(new Error(`消息 ${message.seq} 响应超时`));
}
}, this.messageTimeout);
}
this.ws.send({
data: JSON.stringify(message),
success: () => {
console.log('WebSocket 消息发送成功:', message);
},
fail: (error) => {
console.error('WebSocket 消息发送失败:', error);
this.pendingMessages.delete(message.seq);
if (timeout) {
clearTimeout(timeout);
}
reject(error);
}
});
});
}
// 处理接收到的消息
handleMessage(message) {
console.log('处理消息:', message);
// 更新心跳时间戳
if (message.action === 'pong') {
this.lastHeartbeatResponse = Date.now();
return;
}
// 处理消息响应
// if (message.seq && this.pendingMessages.has(message.seq)) {
// const { resolve } = this.pendingMessages.get(message.seq);
// this.pendingMessages.delete(message.seq);
// resolve(message);
// return;
// }
// 更新序列号
if (message.seq) {
this.sequence = message.seq + 1;
}
// 处理不同类型的消息
if (message.event === 'posted') {
const post = message.data;
// 更新未读消息数
if (post.channel_id && !this.isCurrentChannel(post.channel_id)) {
const currentCount = this.unreadCounts.get(post.channel_id) || 0;
this.unreadCounts.set(post.channel_id, currentCount + 1);
}
// 缓存消息
this.messageCache.set(post.id, post);
// 如果当前不在聊天页面,增加未读数
const currentPage = getCurrentPages();
const isInChatPage = currentPage.some(page =>
page.route === 'pages/im/chat' &&
((page.$page.options.target_id == this.getCurrentUserId() &&
page.$page.options.target_type === 'private') ||
(page.$page.options.target_id == '3awtqn6b17d4bp8ro68qmzo96o' &&
page.$page.options.target_type === 'group'))
);
if(!isInChatPage){
uni.createPushMessage({
title:post.channel_display_name.substr(0,1).replace("_","@"),
content:post.message,
payload:post,
//icon:'',
//sound:'',
cover:false,
complete(){
}
});
}
} else if (message.event === 'post_deleted') {
// 处理消息删除
const postId = message.data.post_id;
this.deletedMessages.add(postId);
this.messageCache.delete(postId);
} else if (message.event === 'user_updated') {
// 处理用户信息更新
const user = message.data;
if (user.roles) {
this.userRoles.set(user.id, user.roles);
}
} else if (message.event === 'status_change') {
// 处理用户状态变化
const status = message.data;
this.userStatuses.set(status.user_id, status);
}
// 触发消息处理器
if (message.event && this.messageHandlers.has(message.event)) {
console.log(`触发消息处理器: ${message.event}, 处理器数量: ${this.messageHandlers.get(message.event).size}`);
this.messageHandlers.get(message.event).forEach(handler => {
try {
handler(message.data);
} catch (error) {
console.error('消息处理器错误:', error);
}
});
}
}
// 注册状态变化回调
onStatusChange(callback) {
this.statusChangeCallbacks.add(callback);
}
// 移除状态变化回调
offStatusChange(callback) {
this.statusChangeCallbacks.delete(callback);
}
// 通知状态变化
notifyStatusChange(status, data = null) {
this.statusChangeCallbacks.forEach(callback => {
try {
callback(status, data);
} catch (error) {
console.error('状态变化回调错误:', error);
}
});
}
// 注册消息处理器
on(event, handler) {
if (!this.messageHandlers.has(event)) {
this.messageHandlers.set(event, new Set());
}
this.messageHandlers.get(event).add(handler);
console.log(`注册消息处理器: ${event}, 当前处理器数量: ${this.messageHandlers.get(event).size}`);
}
// 移除消息处理器
off(event, handler) {
if (this.messageHandlers.has(event)) {
this.messageHandlers.get(event).delete(handler);
console.log(`移除消息处理器: ${event}, 剩余处理器数量: ${this.messageHandlers.get(event).size}`);
}
}
// 获取连接状态
getConnectionStatus() {
return {
connected: this.connected,
authenticated: this.authenticated,
reconnectAttempts: this.reconnectAttempts,
maxReconnectAttempts: this.maxReconnectAttempts,
wsUrl: this.wsUrl,
lastHeartbeat: this.lastHeartbeatResponse
};
}
// 断开连接
async disconnect() {
this.stopHeartbeat();
if (this.reconnectTimer) {
clearTimeout(this.reconnectTimer);
this.reconnectTimer = null;
}
if (this.ws) {
this.ws.close();
this.ws = null;
}
this.connected = false;
this.authenticated = false;
this.notifyStatusChange('disconnected');
// 清理所有等待响应的消息
this.pendingMessages.forEach(({ reject }) => {
reject(new Error('连接已断开'));
});
this.pendingMessages.clear();
}
async getRecentContacts(){
const channels = await this.request({
url: `/api/v4/users/me/channels`,
method: 'GET'
});
let result = {};
let unkown_user_ids = [];
if (channels && channels.length > 0) {
const dmChannels = channels
.filter(c => c.type === 'D')
.sort((a, b) => b.last_post_at - a.last_post_at); // 按最后消息时间降序
dmChannels.forEach(channel => {
var member_ids = channel.name.replace(this.currentUser.id,'').replace('__','');
if(!this.kown_users[member_ids]){
result[member_ids]={};
unkown_user_ids.push(member_ids);
}else{
result[member_ids]=this.kown_users[member_ids];
}
});
if(unkown_user_ids.length>0){
const users = await this.getUsersByIds(unkown_user_ids);
users.data.forEach(user => {
this.kown_users[user.id]=user;
result[user.id]=user;
});
}
return result;
}
return [];
}
// 获取私聊频道
async getDirectChannels() {
//return [];
try {
const channels = await this.request({
url: `/api/v4/users/me/channels`,
method: 'GET'
});
console.log(channels);
if (channels && channels.length > 0) {
channels.forEach(channel => {
this.directChannels.set(channel.id, channel);
});
return channels;
}
return [];
} catch (error) {
console.error('获取私聊频道错误:', error);
throw error;
}
}
// HTTP 请求封装
async request(options) {
let { url, method = 'GET', data = {}, headers = {},to_server='user' } = options;
let requestHeaders ={};
if(to_server=='user'){
// 添加认证头
requestHeaders = {
'Authorization': `Bearer ${this.userToken}`,
...headers
};
url = this.userBaseUrl + url;
}else{
// 添加认证头
requestHeaders = {
'token': this.adminToken,
...headers
};
url = this.adminBaseUrl + url;
}
const [error, response] = await uni.request({
url,
method,
data,
header: requestHeaders
}).catch(err => [err, null]);
if (error) {
console.error(`请求失败 [${method} ${url}]:`, error);
throw error;
}
if (response.statusCode >= 200 && response.statusCode < 300) {
return response.data;
}
console.error(`请求失败 [${method} ${url}]:`, response);
throw new Error(`请求失败: ${response.statusCode}`);
}
// 文件上传封装
async uploadFile(options) {
const { url, filePath, name = 'files', headers = {} } = options;
// 添加认证头
const requestHeaders = {
'Authorization': `Bearer ${this.userToken}`,
...headers
};
const [error, response] = await uni.uploadFile({
url,
filePath,
name,
header: requestHeaders
}).catch(err => [err, null]);
if (error) {
console.error(`文件上传失败 [${url}]:`, error);
throw error;
}
if (response.statusCode >= 200 && response.statusCode < 300) {
return response.data;
}
console.error(`文件上传失败 [${url}]:`, response);
throw new Error(`文件上传失败: ${response.statusCode}`);
}
// 获取频道消息
async getChannelPosts(channelId, page = 0, perPage = 30) {
try {
const response = await this.request({
url: `/api/v4/channels/${channelId}/posts`,
method: 'GET',
data: {
page,
per_page: perPage,
include_deleted: false
}
});
if (!response || !response.order || !response.posts) {
console.error('无效的消息数据格式:', response);
return [];
}
return response.order.reverse().map(id => response.posts[id]);
} catch (error) {
console.error('获取消息失败:', error);
return [];
}
}
// 发送文本消息
async sendTextMessage(channelId, message) {
return this.request({
url: `/api/v4/posts`,
method: 'POST',
data: {
channel_id: channelId,
message: message,
root_id: '',
file_ids: [],
props: {}
}
});
}
// 发送图片消息
async sendImageMessage(channelId, filePath) {
try {
// 1. 上传文件
const fileData = await this.uploadFile({
url: `${this.userBaseUrl}/api/v4/files`,
filePath
});
const fileInfo = JSON.parse(fileData);
const fileId = fileInfo.file_infos[0].id;
// 2. 发送带图片的消息
return this.request({
url: `${this.userBaseUrl}/api/v4/posts`,
method: 'POST',
data: {
channel_id: channelId,
message: '',
file_ids: [fileId],
props: {}
}
});
} catch (error) {
console.error('发送图片消息失败:', error);
throw error;
}
}
// 标记消息为已读
async markChannelAsViewed(channelId) {
if (!this.authenticated) {
throw new Error('未认证');
}
const response = await this.request({
url: `/api/v4/channels/${channelId}/view`,
method: 'POST',
data: {
channel_id: channelId
}
});
this.unreadCounts.set(channelId, 0);
return response;
}
// 检查是否是当前查看的频道
isCurrentChannel(channelId) {
return this.currentChannelId === channelId;
}
// 获取频道的未读消息数
getUnreadCount(channelId) {
return this.unreadCounts.get(channelId) || 0;
}
// 设置当前查看的频道
setCurrentChannel(channelId) {
this.currentChannelId = channelId;
// 自动标记为已读
if (channelId) {
this.markChannelAsViewed(channelId).catch(console.error);
}
}
// 获取当前用户信息
async getCurrentUser() {
// if (!this.authenticated) {
// throw new Error('未认证');
// }
const user = await this.request({
url: `/api/v4/users/me`,
method: 'GET'
});
this.currentUser = user;
this.userRoles.set(user.id, user.roles);
return user;
}
// 检查用户是否是管理员
isAdmin(userId) {
const roles = this.userRoles.get(userId);
return roles && roles.includes('system_admin');
}
// 检查用户是否是客服
isKefu(userId) {
const roles = this.userRoles.get(userId);
return roles && roles.includes('system_user');
}
// 获取用户状态
async getUserStatus(userId) {
if (!this.authenticated) {
throw new Error('未认证');
}
try {
// 使用用户 API 获取状态
const response = await this.request({
to_server:'admin',
url: `/api/v4/users/${userId}/status`,
method: 'GET'
});
if (response.statusCode === 200) {
this.userStatuses.set(userId, response.data);
return response.data;
}
throw new Error('获取用户状态失败');
} catch (error) {
console.error('获取用户状态错误:', error);
throw error;
}
}
// 获取多个用户状态
async getUsersStatus(userIds) {
if (!this.authenticated) {
throw new Error('未认证');
}
try {
const response = await this.request({
to_server:'admin',
url: `/api/v4/users/status/ids`,
method: 'POST',
data: userIds
});
if (response.statusCode === 200) {
response.data.forEach(status => {
this.userStatuses.set(status.user_id, status);
});
return response.data;
}
throw new Error('获取用户状态失败');
} catch (error) {
console.error('获取用户状态错误:', error);
throw error;
}
}
// 搜索消息
async searchPosts(terms, isOrSearch = false) {
if (!this.authenticated) {
throw new Error('未认证');
}
try {
const response = await this.request({
url: `/api/v4/posts/search`,
method: 'POST',
data: {
terms,
is_or_search: isOrSearch
}
});
if (response.statusCode === 200) {
return response.data;
}
throw new Error('搜索消息失败');
} catch (error) {
console.error('搜索消息错误:', error);
throw error;
}
}
// 删除消息(管理员功能)
async deletePost(postId) {
if (!this.authenticated) {
throw new Error('未认证');
}
if (!this.isAdmin(this.currentUser?.id)) {
throw new Error('没有权限删除消息');
}
try {
const response = await this.request({
to_server:'admin',
url: `/api/v4/posts/${postId}`,
method: 'DELETE',
});
if (response.statusCode === 200) {
this.deletedMessages.add(postId);
return response.data;
}
throw new Error('删除消息失败');
} catch (error) {
console.error('删除消息错误:', error);
throw error;
}
}
// 撤回消息
async editPost(postId, message) {
if (!this.authenticated) {
throw new Error('未认证');
}
try {
const response = await this.request({
url: `/api/v4/posts/${postId}`,
method: 'PUT',
data: {
message,
has_reactions: false
}
});
if (response.statusCode === 200) {
return response.data;
}
throw new Error('撤回消息失败');
} catch (error) {
console.error('撤回消息错误:', error);
throw error;
}
}
// 禁言用户(管理员功能)
async muteUser(userId, channelId) {
if (!this.authenticated) {
throw new Error('未认证');
}
if (!this.isAdmin(this.currentUser?.id)) {
throw new Error('没有权限禁言用户');
}
try {
const response = await this.request({
to_server:'admin',
url: `/api/v4/channels/${channelId}/members/${userId}/roles`,
method: 'PUT',
data: {
roles: 'channel_user channel_muted'
}
});
if (response.statusCode === 200) {
return response.data;
}
throw new Error('禁言用户失败');
} catch (error) {
console.error('禁言用户错误:', error);
throw error;
}
}
// 解除禁言(管理员功能)
async unmuteUser(userId, channelId) {
if (!this.authenticated) {
throw new Error('未认证');
}
if (!this.isAdmin(this.currentUser?.id)) {
throw new Error('没有权限解除禁言');
}
try {
const response = await this.request({
to_server:'admin',
url: `/api/v4/channels/${channelId}/members/${userId}/roles`,
method: 'PUT',
data: {
roles: 'channel_user'
}
});
if (response.statusCode === 200) {
return response.data;
}
throw new Error('解除禁言失败');
} catch (error) {
console.error('解除禁言错误:', error);
throw error;
}
}
// 获取被禁言用户列表(管理员功能)
async getMutedUsers(channelId) {
if (!this.authenticated) {
throw new Error('未认证');
}
if (!this.isAdmin(this.currentUser?.id)) {
throw new Error('没有权限查看禁言列表');
}
try {
const response = await this.request({
to_server:'admin',
url: `/api/v4/channels/${channelId}/members`,
method: 'GET'
});
if (response.statusCode === 200) {
return response.data.filter(member =>
member.roles.includes('channel_muted')
);
}
throw new Error('获取禁言列表失败');
} catch (error) {
console.error('获取禁言列表错误:', error);
throw error;
}
}
// 检查消息是否被删除
isMessageDeleted(postId) {
return this.deletedMessages.has(postId);
}
// 获取缓存的消息
getCachedMessage(postId) {
return this.messageCache.get(postId);
}
// 清理消息缓存
clearMessageCache() {
this.messageCache.clear();
this.deletedMessages.clear();
}
// 获取当前用户ID
getCurrentUserId() {
return this.currentUser?.id;
}
// 检查是否已认证
isAuthenticated() {
return this.authenticated;
}
async getUserInfo(username){
if(username.indexOf('@')!==-1){
return await this.request({
to_server:'admin',
url: `/api/v4/email/${username}`,
method: 'GET'
});
}else{
return await this.request({
to_server:'admin',
url: `/api/v4/users/${username}`,
method: 'GET'
});
}
}
async getUserById(user_id){
if(this.kown_users[user_id]){
return this.kown_users[user_id];
}
var result = await this.getUsersByIds([user_id]);
return result[0];
}
async getUsersByIds(user_ids){
return await this.request({
to_server:'admin',
url: `/api/v4/users/ids`,
method: 'POST',
data:JSON.stringify(user_ids)
});
}
async getChannelById(channel_id){
return await this.request({
url:`/api/v4/channels/${channel_id}`,
method: 'GET'
})
}
async getChannelMembers(channel_id){
return await this.request({
url:`/api/v4/channels/${channel_id}/members`,
method: 'GET'
})
}
async talk_to_user(item){
if (!item.type || item.type!== 'O') {
// 获取当前用户ID
const currentUserId = await this.getCurrentUserId();
// 获取目标用户ID
const targetUserId = item.id;
// 查询直接消息频道
const response = await this.request({
url: `/api/v4/channels/direct`,
method: 'POST',
data: [currentUserId, targetUserId]
});
if (response.id) {
// 使用返回的频道ID进行跳转
return `/pages/im/chat?target_id=${response.id}&target_type=private`;
}
}
// 如果不是私聊或查询失败使用原始ID跳转
return `/pages/im/chat?target_id=${item.id}&target_type=group`;
}
}
// 创建单例
const mattermost = new MattermostClient();
export default mattermost;