feature/im-0602-ch
ch 3 years ago
parent 0bdab1c4bf
commit 51ee94d573

@ -2,7 +2,7 @@
* @Author: ch * @Author: ch
* @Date: 2022-05-05 14:40:00 * @Date: 2022-05-05 14:40:00
* @LastEditors: ch * @LastEditors: ch
* @LastEditTime: 2022-06-02 15:09:46 * @LastEditTime: 2022-06-09 11:25:44
* @Description: 根据git分支生成对应环境的环境变量 * @Description: 根据git分支生成对应环境的环境变量
* 开发时如果环境变量换了可以不用重启服务直接运行node env.config.js即可 * 开发时如果环境变量换了可以不用重启服务直接运行node env.config.js即可
*/ */
@ -13,8 +13,8 @@ const envConfig = {
dev : { dev : {
baseUrl: 'https://k8s-horse-gateway.mashibing.cn', baseUrl: 'https://k8s-horse-gateway.mashibing.cn',
staticUrl : 'https://k8s-shop-app.mashibing.cn', staticUrl : 'https://k8s-shop-app.mashibing.cn',
imUrl : 'ws://192.168.10.94:8090' // imUrl : 'ws://192.168.10.94:8090'
// imUrl : 'wss://k8s-horse-gateway.mashibing.cn' imUrl : 'wss://k8s-horse-gateway.mashibing.cn'
}, },
test : { test : {
baseUrl: 'https://k8s-horse-gateway.mashibing.cn', baseUrl: 'https://k8s-horse-gateway.mashibing.cn',

@ -2,7 +2,7 @@
* @Author: ch * @Author: ch
* @Date: 2022-05-27 17:44:36 * @Date: 2022-05-27 17:44:36
* @LastEditors: ch * @LastEditors: ch
* @LastEditTime: 2022-06-02 14:45:51 * @LastEditTime: 2022-06-09 11:34:36
* @Description: file content * @Description: file content
*/ */
import {ToAsyncAwait, MsbRequestTk} from '@/common/utils'; import {ToAsyncAwait, MsbRequestTk} from '@/common/utils';
@ -11,4 +11,6 @@ const BASE_URL = '/mall/im';
/** /**
* 获取soket登录秘钥 * 获取soket登录秘钥
*/ */
export const ApiGetSoketTicket = () => ToAsyncAwait(MsbRequestTk.get(`${BASE_URL}/ticket`)); export const ApiGetSoketTicket = () => ToAsyncAwait(MsbRequestTk.get(`${BASE_URL}/ticket`, {
ticketType: 'CONNECT_TICKET'
}));

@ -2,18 +2,15 @@
* @Author: ch * @Author: ch
* @Date: 2022-05-18 14:54:47 * @Date: 2022-05-18 14:54:47
* @LastEditors: ch * @LastEditors: ch
* @LastEditTime: 2022-06-07 19:28:14 * @LastEditTime: 2022-06-09 11:38:48
* @Description: file content * @Description: file content
*/ */
import { CreateUUID, FormatDate, ToAsyncAwait } from "@/common/utils"; import { CreateUUID, FormatDate, ToAsyncAwait } from "@/common/utils";
import './potoReq'; import './potoReq';
import './protoRsp' import './protoRsp'
const connect = Symbol('connect'), const connect = Symbol('connect');
send = Symbol('send'), const send = Symbol('send');
onResponse = Symbol('onResponse'), const onMessage = Symbol('onMessage');
onMessage = Symbol('onMessage'),
updateData = Symbol('updateData')
;
const fromatPotoReq = (traceId, traceType, content) => { const fromatPotoReq = (traceId, traceType, content) => {
let messageModel = new proto.ReqModel(); let messageModel = new proto.ReqModel();
messageModel.setTraceid(traceId); messageModel.setTraceid(traceId);
@ -26,86 +23,101 @@ fromatPotoRsp = (data)=>{
let ctx = res.getContent(); let ctx = res.getContent();
ctx = ctx ? JSON.parse(ctx) : {}; ctx = ctx ? JSON.parse(ctx) : {};
if (ctx.payload) { if (ctx.payload) {
ctx.payload = JSON.parse(ctx.payload) ctx.payload = JSON.parse(ctx.payload);
} }
return { return {
content: ctx, content: ctx,
traceId: res.getTraceid(), traceId: res.getTraceid(),
traceType: res.getTracetype(), traceType: res.getTracetype(),
code: res.getCode(), code: res.getCode(),
message : res.getMessage() message: res.getMessage(),
} };
} };
export default class MsbIm { class MsbIm {
option = { defaultOption = {
ioKey: 'traceId', ioKey: 'traceId',
reconnect: true, reconnect: true,
logout : false };
}
socket = null; socket = null;
isOpen = false; isOpen = false;
queue = {}; queue = {};
interceptors = { interceptors = {
dataChangeBefore: null, dataChangeBefore: null,
dataChangeAfter: null, dataChangeAfter: null,
onLogout : null, onClose: null,
onMessage: null onMessage: null,
}; };
sessionData = []; sessionData = [];
curSessionId = null; curSessionId = null;
constructor(option) { constructor(option) {
this.option = { this.option = {
...this.option, ...this.defaultOption,
...option ...option,
} };
} }
/** /**
* 创建连接返回一个Promise 创建成功并成功打开连接算连接成功 * 创建连接返回一个Promise 创建成功并成功打开连接算连接成功
* @param {*} option * @param {*} option
*/ */
[connect](option) { [connect](option) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.socket = uni.connectSocket({ const open = () => {
...option, console.log('[im] open');
fail(e){ this.isOpen = true;
reject(e); resolve(this.socket);
} };
}); const message = async (res) => {
this.socket.onOpen(() => {
this.socket.onMessage(async (res) => {
console.log(res.data,'apppppppp');
const result = fromatPotoRsp(res.data); const result = fromatPotoRsp(res.data);
// if (result.content?.payload) {
// result.content.payload = JSON.parse(result.content.payload);
// }
// 401主动退出
if (result.code === 401) {
this.logout();
return false;
}
this.interceptors.onMessage && this.interceptors.onMessage(result); this.interceptors.onMessage && this.interceptors.onMessage(result);
// 处理服务端主动推送的消息 // 处理服务端主动推送的消息
this[onMessage](result); this[onMessage](result);
// 如果再消息堆里有此消息回调,则执行回调,并删除 // 如果再消息堆里有此消息回调,则执行回调,并删除
const cbk = this.queue[result[this.option.ioKey]]; const cbk = this.queue[result[this.option.ioKey]];
if (cbk) { if (cbk) {
cbk(result.code !== 200 ? { error: result } : { result: result }); cbk(result.code !== 200 ? { error: result } : { result: result });
delete this.queue[result[this.option.ioKey]]; delete this.queue[result[this.option.ioKey]];
} }
}) };
resolve(this.socket); const close = () => {
console.log('[im] close');
this.interceptors.onClose && this.interceptors.onClose();
};
if (uni) {
this.socket = uni.connectSocket({
...this.option,
fail(e) {
reject(e);
},
});
this.socket.onOpen(() => {
open();
this.socket.onMessage((res) => {
message(res);
});
}); });
this.socket.onClose(() => { this.socket.onClose(() => {
if (this.option.reconnect && !this.option.logout) { close();
this[connect]();
}
this.option.logout = false;
}); });
} else if (WebSocket) {
try {
this.socket = new WebSocket(this.option.url);
this.socket.binaryType = 'arraybuffer';
this.socket.onopen = () => {
open();
};
this.socket.onmessage = (res) => {
message(res);
};
this.socket.onclose = () => {
close();
};
} catch (e) {
reject(e);
}
}
}); });
} }
/** /**
@ -114,6 +126,9 @@ export default class MsbIm {
*/ */
[send](data) { [send](data) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (!this.isOpen) {
return reject('连接未打开');
}
this.queue[data[this.option.ioKey]] = ({ result, error }) => { this.queue[data[this.option.ioKey]] = ({ result, error }) => {
if (result) { if (result) {
resolve(result); resolve(result);
@ -122,13 +137,18 @@ export default class MsbIm {
} }
}; };
const par = fromatPotoReq(data.traceId, data.traceType, data.content);
if (uni) {
this.socket.send({ this.socket.send({
data : fromatPotoReq(data.traceId, data.traceType, data.content), data: par,
fail(e) { fail(e) {
reject({ error: e }); reject({ error: e });
},
});
} else if (WebSocket) {
this.socket.send(par);
} }
}); });
})
} }
/** /**
* 服务端推送消息只处理服务端主动推送的消息 * 服务端推送消息只处理服务端主动推送的消息
@ -142,7 +162,7 @@ export default class MsbIm {
let ctx = data.content; let ctx = data.content;
let historyData = [...this.sessionData], let historyData = [...this.sessionData],
newData = []; newData = [];
const hisIndex = historyData.findIndex(i => i.id === ctx.sessionId); const hisIndex = historyData.findIndex((i) => i.id === ctx.sessionId);
if (hisIndex >= 0) { if (hisIndex >= 0) {
// 存在会话往现有会话增加一条消息,并修改最后一条消息为当前消息 // 存在会话往现有会话增加一条消息,并修改最后一条消息为当前消息
const curHisData = historyData[hisIndex]; const curHisData = historyData[hisIndex];
@ -155,51 +175,57 @@ export default class MsbIm {
newData = historyData; newData = historyData;
} else { } else {
// 会话列表不存在,则创建一个会话 // 会话列表不存在,则创建一个会话
newData = [...historyData, { newData = [
...historyData,
{
fromAvatar: ctx.fromAvatar, fromAvatar: ctx.fromAvatar,
fromId: ctx.fromId, fromId: ctx.fromId,
fromNickname: ctx.fromNickname, fromNickname: ctx.fromNickname,
id: ctx.id, id: ctx.id,
lastMessage: ctx, lastMessage: ctx,
messageList: [ctx], messageList: [ctx],
unreadCount : 1 unreadCount: 1,
}] },
];
} }
this.setSessionData(newData) this.setSessionData(newData);
} }
init(config) { init(config) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const heart = () => { const heart = () => {
// 要优化 心跳没回复需要重连
setTimeout(async () => { setTimeout(async () => {
if (this.isOpen) {
await this[send]({ await this[send]({
traceId: CreateUUID(), traceId: CreateUUID(),
traceType: 0, traceType: 0,
content: { text: "ping" } content: { text: 'ping' },
}).catch((e)=>{}); });
heart();
},1000)
} }
this[connect]({ heart();
}, 1000);
};
this.option = {
...this.option,
...config, ...config,
}).then(() => { };
this[connect]()
.then((res) => {
resolve(res);
heart(); heart();
resolve(this);
}).catch((e)=>{});
}) })
.catch((e) => {
} console.log('eeeee', e);
logout() { });
this.option.logout = true; });
this.socket.close();
this.interceptors.onLogout && this.interceptors.onLogout();
} }
/** /**
* 设置数据 * 设置数据
*/ */
setSessionData(data) { setSessionData(data) {
this.interceptors.dataChangeBefore && this.interceptors.dataChangeBefore(data, this.sessionData); let newData = JSON.parse(JSON.stringify(data));
this.sessionData = data; this.interceptors.dataChangeBefore && this.interceptors.dataChangeBefore(newData, this.sessionData);
this.sessionData = newData;
this.interceptors.dataChangeAfter && this.interceptors.dataChangeAfter(this.sessionData); this.interceptors.dataChangeAfter && this.interceptors.dataChangeAfter(this.sessionData);
} }
/** /**
@ -218,29 +244,30 @@ export default class MsbIm {
const par = { const par = {
traceId: CreateUUID(), traceId: CreateUUID(),
traceType: 1, traceType: 1,
...params ...params,
}; };
console.log('[im] 获取会话列表--start', par);
let { error, result } = await ToAsyncAwait(this[send](par)); let { error, result } = await ToAsyncAwait(this[send](par));
console.log('[im] 获取会话列表--end', result, error);
if (error) { if (error) {
return Promise.reject(error); return Promise.reject(error);
} }
const { content } = result; const { content } = result;
console.log('获取会话列表', par, result); content.sessionVOS.forEach((item) => {
content.sessionVOS.forEach(item => {
if (item.lastMessage) { if (item.lastMessage) {
item.lastMessage.payload = JSON.parse(item.lastMessage.payload || {}); item.lastMessage.payload = JSON.parse(item.lastMessage.payload || {});
} }
let historyData = this.sessionData; let historyData = this.sessionData;
let hisIndex = historyData.findIndex(i => i.id === item.id); let hisIndex = historyData.findIndex((i) => i.id === item.id);
if (hisIndex >= 0) { if (hisIndex >= 0) {
historyData[hisIndex].lastMessage = item.lastMessage; historyData[hisIndex].lastMessage = item.lastMessage;
historyData[hisIndex].unreadCount++; historyData[hisIndex].unreadCount++;
this.setSessionData(historyData) this.setSessionData(historyData);
} else { } else {
item.messageList = []; item.messageList = [];
const newData = [...historyData, item] const newData = [...historyData, item];
this.setSessionData(newData); this.setSessionData(newData);
} }
}); });
@ -251,33 +278,33 @@ export default class MsbIm {
* @param {*} params * @param {*} params
*/ */
async getHistoryMsg() { async getHistoryMsg() {
const curSessionIdx = this.sessionData.findIndex(i => i.id === this.curSessionId); const curSessionIdx = this.sessionData.findIndex((i) => i.id === this.curSessionId);
const curSession = this.sessionData[curSessionIdx]; const curSession = this.sessionData[curSessionIdx];
const msgList = curSession.messageList || []; const msgList = curSession.messageList || [];
const par = { const par = {
traceId: CreateUUID(), traceId: CreateUUID(),
traceType: 23, traceType: 2,
content: { content: {
sessionId: this.curSessionId, sessionId: this.curSessionId,
topMessageId: msgList.length ? msgList[0].id : null topMessageId: msgList.length ? msgList[0].id : null,
} },
}; };
console.log('[im] 获取会话历史消息--start', par);
const { error, result } = await ToAsyncAwait(this[send](par)); const { error, result } = await ToAsyncAwait(this[send](par));
console.log('[im] 获取会话历史消息--end', result, error);
if (error) { if (error) {
return Promise.reject(error); return Promise.reject(error);
} }
const { content } = result; const { content } = result;
console.log('获取会话历史消息',par, result);
if (content.length) { if (content.length) {
let newData = this.sessionData; let newData = this.sessionData;
content.forEach(item => { content.forEach((item) => {
item.payload = JSON.parse(item.payload) item.payload = JSON.parse(item.payload);
}) });
newData[curSessionIdx].messageList = content.concat(newData[curSessionIdx].messageList); newData[curSessionIdx].messageList = content.concat(newData[curSessionIdx].messageList);
this.setSessionData(newData); this.setSessionData(newData);
} }
return Promise.resolve(result); return Promise.resolve(result);
} }
/** /**
* 会话已读 * 会话已读
@ -286,14 +313,14 @@ export default class MsbIm {
async setRead(params) { async setRead(params) {
const par = { const par = {
traceId: CreateUUID(), traceId: CreateUUID(),
traceType : "6", traceType: '6',
...params ...params,
} };
console.log('[im] 会话已读--start', par);
const { error, result } = await this[send](par); const { error, result } = await this[send](par);
console.log('[im] 会话已读--end', result, error);
console.log('会话已读', par, result); let newData = this.sessionData.map((item) => {
let newData = this.sessionData.map(item => {
if (item.id == params.content.sessionId) { if (item.id == params.content.sessionId) {
item.unreadCount = 0; item.unreadCount = 0;
} }
@ -307,28 +334,28 @@ export default class MsbIm {
* @param {*} params * @param {*} params
*/ */
async sendMsg(params) { async sendMsg(params) {
const index = this.sessionData.findIndex(i => i.id === this.curSessionId) const index = this.sessionData.findIndex((i) => i.id === this.curSessionId);
let curSession = this.sessionData[index]; let curSession = this.sessionData[index];
// 临时消息体 // 临时消息体
let par = { let par = {
...params, ...params,
traceId: CreateUUID(), traceId: CreateUUID(),
traceType: 20, traceType: 3,
} };
let msgCtx = { let msgCtx = {
...params.content, ...params.content,
...par, ...par,
fromId: params.fromId, createTimeStamp: new Date().getTime(),
createTimeStamp : (new Date()).getTime(), sendStatus: 'loading',
sendStatus : 'loading' };
}
// 点发送,立即把消息加入消息列表,标记为发送中状态 // 点发送,立即把消息加入消息列表,标记为发送中状态
curSession.messageList.push(msgCtx); curSession.messageList.push(msgCtx);
// 超过时间未返回视为发送失败 // 超过时间未返回视为发送失败
this.timerStatus(msgCtx); this.timerStatus(msgCtx);
const { error, result } = await ToAsyncAwait(this[send](par));
console.log('发送消息', par, result); console.log('[im] 发送消息--start', par);
const { error, result } = await ToAsyncAwait(this[send](par));
console.log('[im] 发送消息--end', result, error);
// 接到通知,标记消息是否发送成功 // 接到通知,标记消息是否发送成功
for (let i = curSession.messageList.length; i--; ) { for (let i = curSession.messageList.length; i--; ) {
const item = curSession.messageList[i]; const item = curSession.messageList[i];
@ -352,12 +379,17 @@ export default class MsbIm {
*/ */
async resend(params) { async resend(params) {
params.sendStatus = 'loading'; params.sendStatus = 'loading';
this.timerStatus(params) this.timerStatus(params);
const { error, result } = await ToAsyncAwait(this[send]({
console.log('[im] 重新发送消息--start', params);
const { error, result } = await ToAsyncAwait(
this[send]({
traceId: params.traceId, traceId: params.traceId,
traceType: params.traceType, traceType: params.traceType,
content : params.content content: params.content,
})); })
);
console.log('[im] 重新发送消息--end', result, error);
params.createTimeStamp = result.createTimeStamp; params.createTimeStamp = result.createTimeStamp;
if (error) { if (error) {
params.sendStatus = 'fail'; params.sendStatus = 'fail';
@ -367,7 +399,6 @@ export default class MsbIm {
return Promise.resolve(result); return Promise.resolve(result);
} }
timerStatus(msg) { timerStatus(msg) {
setTimeout(() => { setTimeout(() => {
if (msg.sendStatus === 'loading') { if (msg.sendStatus === 'loading') {
msg.sendStatus = 'fail'; msg.sendStatus = 'fail';
@ -380,28 +411,30 @@ export default class MsbIm {
* @param {*} params * @param {*} params
*/ */
async createSession(params) { async createSession(params) {
const { result, error } = await ToAsyncAwait(this[send]({ const par = {
traceId: CreateUUID(), traceId: CreateUUID(),
traceType : 21, traceType: 9,
...params ...params,
})); };
console.log('[im] 主动创建会话--start', par);
const { result, error } = await ToAsyncAwait(this[send](par));
console.log('[im] 主动创建会话--end', result, error);
if (error) { if (error) {
return Promise.reject(error); return Promise.reject(error);
} }
const { content } = result; const { content } = result;
let historyData = this.sessionData; let historyData = this.sessionData;
let curSession = historyData.find(i => i.id === content.id); let curSession = historyData.find((i) => i.id === content.id);
if (!curSession) { if (!curSession) {
curSession = { curSession = {
...content, ...content,
unreadCount: 0, unreadCount: 0,
messageList : [] messageList: [],
} };
const newData = [...historyData, curSession]; const newData = [...historyData, curSession];
this.setSessionData(newData); this.setSessionData(newData);
} }
return Promise.resolve(result); return Promise.resolve(result);
} }
} }
export default MsbIm;

@ -2,7 +2,7 @@
* @Author: ch * @Author: ch
* @Date: 2022-05-20 11:00:07 * @Date: 2022-05-20 11:00:07
* @LastEditors: ch * @LastEditors: ch
* @LastEditTime: 2022-06-09 10:00:15 * @LastEditTime: 2022-06-09 11:32:37
* @Description: file content * @Description: file content
*/ */

@ -2,7 +2,7 @@
* @Author: ch * @Author: ch
* @Date: 2021-07-26 23:22:16 * @Date: 2021-07-26 23:22:16
* @LastEditors: ch * @LastEditors: ch
* @LastEditTime: 2022-06-02 16:11:56 * @LastEditTime: 2022-06-09 11:43:04
* @Description: file content * @Description: file content
*/ */
import Vue from 'vue'; import Vue from 'vue';

@ -2,7 +2,7 @@
* @Author: ch * @Author: ch
* @Date: 2022-03-26 14:32:03 * @Date: 2022-03-26 14:32:03
* @LastEditors: ch * @LastEditors: ch
* @LastEditTime: 2022-06-02 17:33:13 * @LastEditTime: 2022-06-09 11:41:50
* @Description: file content * @Description: file content
--> -->
<template> <template>
@ -138,7 +138,8 @@ export default {
async createSessionMain(){ async createSessionMain(){
const {error, result} = await ToAsyncAwait(Im.createSession({ const {error, result} = await ToAsyncAwait(Im.createSession({
content : { content : {
storeId : 1 // storeId : 1,
sessionType : 3
} }
})); }));

Loading…
Cancel
Save