You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
shop-app/common/plugins/msbIm.js

319 lines
7.5 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
* @Author: ch
* @Date: 2022-05-18 14:54:47
* @LastEditors: ch
* @LastEditTime: 2022-05-21 19:32:49
* @Description: file content
*/
import { CreateUUID, FormatDate, ToAsyncAwait } from "@/common/utils";
const connect = Symbol('connect'),
send = Symbol('send'),
onResponse = Symbol('onResponse'),
onMessage = Symbol('onMessage'),
updateData = Symbol('updateData')
;
export default class MsbIm {
option = {
ioKey : 'traceId',
reconnect: true,
logout : false
}
socket = null;
queue = {};
interceptors = {
dataChangeBefore: null,
dataChangeAfter: null,
onLogout : null,
onMessage: null
};
sessionData = [];
curSessionId = null;
constructor(option) {
this.option = {
...this.option,
...option
}
}
/**
* 创建连接返回一个Promise 创建成功并成功打开连接算连接成功
* @param {*} option
*/
[connect](option) {
return new Promise((resolve, reject) => {
this.socket = uni.connectSocket({
...option,
fail(e){
reject(e);
}
});
this.socket.onOpen(() => {
this.socket.onMessage(async (res) => {
const result = JSON.parse(res.data);
// 401主动退出
if (result.code === 401) {
this.logout();
return false;
}
this.interceptors.onMessage && this.interceptors.onMessage(result);
// 处理服务端主动推送的消息
this[onMessage](result);
// 如果再消息堆里有此消息回调,则执行回调,并删除
const cbk = this.queue[result[this.option.ioKey]];
if (cbk) {
cbk(result.code !== 200 ? {error:result} : {result:result});
delete this.queue[result[this.option.ioKey]];
}
})
resolve(this.socket);
});
this.socket.onClose(() => {
if (this.option.reconnect && !this.option.logout) {
this[connect]();
}
this.option.logout = false;
});
});
}
/**
* 向服务端发送消息||请求返回一个Promise对象收到ioKey对应的消息会算一个同步完成
* @param {*} data
*/
[send](data) {
return new Promise((resolve, reject) => {
this.queue[data[this.option.ioKey]] = ({result, error}) => {
if (result) {
resolve(result);
} else {
reject(error);
}
};
this.socket.send({
data : JSON.stringify(data),
fail(e) {
reject({error : e});
}
});
})
}
/**
* 服务端推送消息,只处理服务端主动推送的消息
* @param {*} data
*/
[onMessage](data) {
// 判断非服务端主动推送消息不做处理
if (data[this.option.ioKey] || data.code !== 200) {
return false;
}
let ctx = data.content;
ctx.payload = JSON.parse(ctx.payload || {});
let historyData = [...this.sessionData],
newData = [];
const hisIndex = historyData.findIndex(i => i.id === ctx.sessionId);
if(hisIndex >= 0){
// 存在会话往现有会话增加一条消息,并修改最后一条消息为当前消息
const curHisData = historyData[hisIndex];
curHisData.messageList.push(ctx);
curHisData.lastMessage = ctx;
// 不在当前会话窗口则向会话消息加1条未读
if(ctx.sessionId !== this.curSessionId){
curHisData.unreadCount++;
}
newData = historyData;
}else{
// 会话列表不存在,则创建一个会话
newData = [...historyData, {
fromAvatar : ctx.fromAvatar,
fromId : ctx.fromId,
fromNickname : ctx.fromNickname,
id : ctx.id,
lastMessage : ctx,
messageList : [ctx],
unreadCount : 1
}]
}
this.setSessionData(newData)
}
init (config) {
return new Promise((resolve, reject) => {
const heart = () => {
setTimeout(async () => {
await this[send]({
traceId: CreateUUID(),
traceType: '0',
content: { text: "ping" }
}).catch((e)=>{});
heart();
},5000)
}
this[connect]({
...config,
}).then(() => {
heart();
resolve(this);
}).catch((e)=>{});
})
}
logout() {
this.option.logout = true;
this.socket.close();
this.interceptors.onLogout && this.interceptors.onLogout();
}
/**
* 设置数据
*/
setSessionData(data) {
this.interceptors.dataChangeBefore && this.interceptors.dataChangeBefore(data, this.sessionData);
this.sessionData = data;
this.interceptors.dataChangeAfter && this.interceptors.dataChangeAfter(this.sessionData);
}
/**
* 设置当前聊天窗口
* Data为Session数据
* @param {*} data
*/
setCurSessionId(id) {
this.curSessionId = id;
}
/**
* 获取会话列表
* @param {*} params
*/
async getSessionList(params) {
let {error, result} = await ToAsyncAwait(this[send]({
traceId: CreateUUID(),
traceType : 1,
...params
}));
if (error) {
return Promise.reject(error);
}
const { content } = result;
content.sessionVOS.forEach(item => {
if (item.lastMessage) {
item.lastMessage.payload = JSON.parse(item.lastMessage.payload || {});
}
let historyData = this.sessionData;
let hisIndex = historyData.findIndex(i => i.id === item.id);
if(hisIndex >= 0){
historyData[hisIndex].lastMessage = item.lastMessage;
historyData[hisIndex].unreadCount++;
this.setSessionData(historyData)
}else{
item.messageList = [];
const newData = [...historyData, item]
this.setSessionData(newData);
}
});
return Promise.resolve(result);
}
/**
* 获取会话的历史消息记录
* @param {*} params
*/
async getHistoryMsg(params) {
const {error, result} = await ToAsyncAwait(this[send]({
traceId: CreateUUID(),
traceType: 23,
...params
}));
if (error) {
return Promise.reject(error);
}
const { content } = result;
if (content.length) {
let newData = this.sessionData;
const hisIdx = newData.findIndex(i => i.id === content[0].sessionId);
content.forEach(item => {
item.payload = JSON.parse(item.payload)
})
newData[hisIdx].messageList = newData[hisIdx].messageList.concat(content);
this.setSessionData(newData);
}
return Promise.resolve(result);
}
/**
* 会话已读
* @param {*} params
*/
async setRead (params){
await this[send]({
traceId : CreateUUID(),
traceType : "6",
...params
});
let newData = this.sessionData.map(item => {
if (item.id == params.content.sessionId) {
item.unreadCount = 0;
}
return item;
});
this.setSessionData(newData);
}
/**
* 发送消息
* @param {*} params
*/
async sendMsg(params) {
let curSession = this.sessionData.find(i => i.id === this.curSessionId);
curSession.messageList.push({
...params.content,
fromId: params.fromId,
createTimeStamp : (new Date()).getTime(),
sendStatus : 'loading'
});
const { error, result } = await ToAsyncAwait(this[send]({
traceId: CreateUUID(),
traceType: 20,
...params
}));
for (let item of curSession.messageList) {
if (item[this.option.ioKey] === params[this.option.ioKey]) {
item.sendStatus = error ? 'fail' : 'success';
break;
}
}
if (error) {
return Promise.reject(error);
}
return Promise.resolve(result);
}
/**
* 主动创建会话
* @param {*} params
*/
async createSession (params){
const { result, error } = await ToAsyncAwait(this[send]({
traceId : CreateUUID(),
traceType : 21,
...params
}));
if (error) {
return Promise.reject(error);
}
const { content } = result;
let historyData = this.sessionData;
let curSession = historyData.find(i => i.id === content.id);
if (!curSession) {
curSession = {
...content,
unreadCount: 0,
messageList : []
}
const newData = [...historyData, curSession];
this.setSessionData(newData);
}
return Promise.resolve(result);
}
}