mirror of
https://gitee.com/beijing_hongye_huicheng/lilishop-ui.git
synced 2025-12-18 08:55:52 +08:00
IM
This commit is contained in:
62
im/src/im-server/event/base.js
Normal file
62
im/src/im-server/event/base.js
Normal file
@@ -0,0 +1,62 @@
|
||||
import store from "@/store";
|
||||
import router from "@/router";
|
||||
import { Notification } from "element-ui";
|
||||
|
||||
class Base {
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
constructor() {
|
||||
this.$notify = Notification;
|
||||
}
|
||||
|
||||
getStoreInstance() {
|
||||
return store;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前登录用户的ID
|
||||
*/
|
||||
getAccountId() {
|
||||
console.log("store.state", store.state.user);
|
||||
return store.state.user.id;
|
||||
}
|
||||
|
||||
getTalkParams() {
|
||||
let { talk_type, receiver_id, index_name } = store.state.dialogue;
|
||||
|
||||
return { talk_type, receiver_id, index_name };
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断消息是否来自当前对话
|
||||
*
|
||||
* @param {Number} talk_type 聊天消息类型[1:私信;2:群聊;]
|
||||
* @param {Number} sender_id 发送者ID
|
||||
* @param {Number} receiver_id 接收者ID
|
||||
*/
|
||||
isTalk(talk_type, sender_id, receiver_id) {
|
||||
let params = this.getTalkParams();
|
||||
|
||||
if (talk_type != params.talk_type) {
|
||||
return false;
|
||||
} else if (
|
||||
params.receiver_id == receiver_id ||
|
||||
params.receiver_id == sender_id
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断用户是否打开对话页
|
||||
*/
|
||||
isTalkPage() {
|
||||
let path = router.currentRoute.path;
|
||||
return !(path != "/message" && path != "/");
|
||||
}
|
||||
}
|
||||
|
||||
export default Base;
|
||||
47
im/src/im-server/event/friend-apply.js
Normal file
47
im/src/im-server/event/friend-apply.js
Normal file
@@ -0,0 +1,47 @@
|
||||
import Base from './base'
|
||||
import store from '@/store'
|
||||
import router from '@/router'
|
||||
|
||||
/**
|
||||
* 好友邀请消息处理
|
||||
*/
|
||||
class FriendApply extends Base {
|
||||
/**
|
||||
* @var resource 资源
|
||||
*/
|
||||
resource
|
||||
|
||||
/**
|
||||
* 初始化构造方法
|
||||
*
|
||||
* @param {Object} resource Socket消息
|
||||
*/
|
||||
constructor(resource) {
|
||||
super()
|
||||
|
||||
this.resource = resource
|
||||
}
|
||||
|
||||
handle() {
|
||||
store.commit('INCR_APPLY_NUM')
|
||||
|
||||
this.$notify({
|
||||
title: '好友申请',
|
||||
dangerouslyUseHTMLString: true,
|
||||
message: `<p style="color:red;margin-top:10px;">您有一条好友申请消息,请注意查收...</p>`,
|
||||
duration: 0,
|
||||
type: 'info',
|
||||
customClass: 'pointer',
|
||||
onClick: function() {
|
||||
store.commit('SET_APPLY_NUM', 0)
|
||||
router.push({
|
||||
path: '/contacts/apply',
|
||||
query: { t: new Date().getTime() },
|
||||
})
|
||||
this.close()
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default FriendApply
|
||||
31
im/src/im-server/event/group-join.js
Normal file
31
im/src/im-server/event/group-join.js
Normal file
@@ -0,0 +1,31 @@
|
||||
import Base from './base'
|
||||
|
||||
/**
|
||||
* 好友邀请消息处理
|
||||
*/
|
||||
class GroupJoin extends Base {
|
||||
/**
|
||||
* @var resource 资源
|
||||
*/
|
||||
resource
|
||||
|
||||
/**
|
||||
* 初始化构造方法
|
||||
*
|
||||
* @param {Object} resource Socket消息
|
||||
*/
|
||||
constructor(resource) {
|
||||
super()
|
||||
|
||||
this.resource = resource
|
||||
}
|
||||
|
||||
handle() {
|
||||
this.$notify({
|
||||
message: '您有一条入群消息通知,请注意查收...',
|
||||
duration: 5000,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default GroupJoin
|
||||
47
im/src/im-server/event/keyboard.js
Normal file
47
im/src/im-server/event/keyboard.js
Normal file
@@ -0,0 +1,47 @@
|
||||
import Base from './base'
|
||||
|
||||
/**
|
||||
* 键盘输入事件
|
||||
*/
|
||||
class Keyboard extends Base {
|
||||
/**
|
||||
* @var resource 资源
|
||||
*/
|
||||
resource
|
||||
|
||||
/**
|
||||
* 初始化构造方法
|
||||
*
|
||||
* @param {Object} resource Socket消息
|
||||
*/
|
||||
constructor(resource) {
|
||||
super()
|
||||
|
||||
this.resource = resource
|
||||
}
|
||||
|
||||
handle() {
|
||||
let params = this.getTalkParams()
|
||||
|
||||
// 判断当前是否正在对话
|
||||
if (params.index_name === null) {
|
||||
return false
|
||||
}
|
||||
|
||||
// 判断是否是私信
|
||||
if (params.talk_type != 1) {
|
||||
return false
|
||||
}
|
||||
|
||||
// 判断消息是否来当前对话
|
||||
if (params.receiver_id != this.resource.sender_id) {
|
||||
return false
|
||||
}
|
||||
|
||||
let store = this.getStoreInstance()
|
||||
|
||||
store.commit('UPDATE_KEYBOARD_EVENT')
|
||||
}
|
||||
}
|
||||
|
||||
export default Keyboard
|
||||
31
im/src/im-server/event/login.js
Normal file
31
im/src/im-server/event/login.js
Normal file
@@ -0,0 +1,31 @@
|
||||
import Base from './base'
|
||||
|
||||
/**
|
||||
* 好友状态事件
|
||||
*/
|
||||
class Login extends Base {
|
||||
/**
|
||||
* @var resource 资源
|
||||
*/
|
||||
resource
|
||||
|
||||
/**
|
||||
* 初始化构造方法
|
||||
*
|
||||
* @param {Object} resource Socket消息
|
||||
*/
|
||||
constructor(resource) {
|
||||
super()
|
||||
|
||||
this.resource = resource
|
||||
}
|
||||
|
||||
handle() {
|
||||
this.getStoreInstance().dispatch('ACT_UPDATE_FRIEND_STATUS', {
|
||||
status: this.resource.status,
|
||||
friend_id: parseInt(this.resource.user_id),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default Login
|
||||
42
im/src/im-server/event/revoke.js
Normal file
42
im/src/im-server/event/revoke.js
Normal file
@@ -0,0 +1,42 @@
|
||||
import Base from './base'
|
||||
import store from '@/store'
|
||||
|
||||
/**
|
||||
* 好友邀请消息处理
|
||||
*/
|
||||
class Revoke extends Base {
|
||||
/**
|
||||
* @var resource 资源
|
||||
*/
|
||||
resource
|
||||
|
||||
/**
|
||||
* 初始化构造方法
|
||||
*
|
||||
* @param {Object} resource Socket消息
|
||||
*/
|
||||
constructor(resource) {
|
||||
super()
|
||||
|
||||
this.resource = resource
|
||||
}
|
||||
|
||||
handle() {
|
||||
if (
|
||||
!this.isTalk(
|
||||
this.resource.talk_type,
|
||||
this.resource.receiver_id,
|
||||
this.resource.sender_id
|
||||
)
|
||||
) {
|
||||
return false
|
||||
}
|
||||
|
||||
store.commit('UPDATE_DIALOGUE', {
|
||||
id: this.resource.record_id,
|
||||
is_revoke: 1,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default Revoke
|
||||
256
im/src/im-server/event/talk.js
Normal file
256
im/src/im-server/event/talk.js
Normal file
@@ -0,0 +1,256 @@
|
||||
import Base from "./base";
|
||||
import Vue from "vue";
|
||||
import router from "@/router";
|
||||
import vm from "@/main";
|
||||
import NewMessageNotify from "@/components/notify/NewMessageNotify";
|
||||
import { ServeClearTalkUnreadNum, ServeCreateTalkList } from "@/api/chat";
|
||||
import { formatTalkItem, findTalkIndex, toTalk } from "@/utils/talk";
|
||||
import { parseTime } from "@/utils/functions";
|
||||
|
||||
import mixin from '@/mixins/main-mixin'
|
||||
/**
|
||||
* 好友状态事件
|
||||
*/
|
||||
class Talk extends Base {
|
||||
/**
|
||||
* @var resource 资源
|
||||
*/
|
||||
resource;
|
||||
|
||||
/**
|
||||
* 发送者ID
|
||||
*/
|
||||
sender_id = 0;
|
||||
|
||||
/**
|
||||
* 接收者ID
|
||||
*/
|
||||
receiver_id = 0;
|
||||
|
||||
/**
|
||||
* 聊天类型[1:私聊;2:群聊;]
|
||||
*/
|
||||
talk_type = 0;
|
||||
|
||||
/**
|
||||
* 初始化构造方法
|
||||
*
|
||||
* @param {Object} resource Socket消息
|
||||
*/
|
||||
constructor(resource) {
|
||||
super();
|
||||
console.log("接口构造 resource", resource);
|
||||
this.sender_id = resource.fromUser; //发送
|
||||
this.receiver_id = resource.toUser; //接收
|
||||
this.talk_type = resource.messageType; //类型
|
||||
|
||||
this.resource = resource;
|
||||
|
||||
// 判断发送者消息是否在当前用户列表中
|
||||
if(this.sender_id && !vm.$store.state.talks.items.find(item=>{
|
||||
return item.userId == this.sender_id
|
||||
})){
|
||||
// 没有当前用户,未在当前列表 进行重新加载
|
||||
vm.loadUserSetting('update')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断消息发送者是否来自于我
|
||||
* @returns
|
||||
*/
|
||||
isCurrSender() {
|
||||
console.log("sender_id", this.sender_id);
|
||||
return this.sender_id == this.getAccountId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取对话索引
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
getIndexName() {
|
||||
if (this.talk_type == 2) {
|
||||
return `${this.talk_type}_${this.receiver_id}`;
|
||||
}
|
||||
|
||||
let receiver_id = this.isCurrSender() ? this.receiver_id : this.sender_id;
|
||||
|
||||
return `${this.talk_type}_${receiver_id}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息浮动方式
|
||||
*
|
||||
* @returns
|
||||
*/
|
||||
getFloatType() {
|
||||
let userId = this.resource.userId;
|
||||
|
||||
if (userId == 0) return "center";
|
||||
|
||||
return userId == this.getAccountId() ? "right" : "left";
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取聊天列表左侧的对话信息
|
||||
*/
|
||||
getTalkText() {
|
||||
let text = this.resource.content || this.resource.text;
|
||||
switch (this.resource.msg_type) {
|
||||
case 'GOODS':
|
||||
text = "[商品链接]";
|
||||
break;
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
handle() {
|
||||
let store = this.getStoreInstance();
|
||||
console.log("触发handle");
|
||||
// 判断当前是否在聊天页面
|
||||
if (!this.isTalkPage()) {
|
||||
store.commit("INCR_UNREAD_NUM");
|
||||
|
||||
// 判断消息是否来自于我自己,否则会提示消息通知
|
||||
return !this.isCurrSender() && this.showMessageNocice();
|
||||
}
|
||||
console.log("this.receiver_id", this.receiver_id);
|
||||
console.log("this.sender_id", this.sender_id);
|
||||
let isTrue = this.isTalk(1, this.receiver_id, this.sender_id);
|
||||
console.log("判断当前是否正在和好友对话", isTrue);
|
||||
// 判断当前是否正在和好友对话
|
||||
if (isTrue) {
|
||||
this.insertTalkRecord();
|
||||
} else {
|
||||
this.updateTalkItem();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示消息提示
|
||||
* @returns
|
||||
*/
|
||||
showMessageNocice() {
|
||||
let avatar = this.resource.avatar;
|
||||
let nickname = this.resource.nickname;
|
||||
let talk_type = this.resource.talk_type;
|
||||
let receiver_id = this.receiver_id;
|
||||
|
||||
if (talk_type == 2) {
|
||||
avatar = this.resource.group_avatar;
|
||||
nickname += `【 ${this.resource.group_name} 】`;
|
||||
} else {
|
||||
receiver_id = this.sender_id;
|
||||
}
|
||||
|
||||
this.$notify({
|
||||
message: vm.$createElement(NewMessageNotify, {
|
||||
props: {
|
||||
avatar,
|
||||
talk_type,
|
||||
nickname,
|
||||
content: this.getTalkText(),
|
||||
datetime: this.resource.created_at,
|
||||
},
|
||||
}),
|
||||
customClass: "im-notify",
|
||||
duration: 3000,
|
||||
position: "top-right",
|
||||
onClick: function () {
|
||||
this.close();
|
||||
toTalk(talk_type, receiver_id);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载对接节点
|
||||
*/
|
||||
addTalkItem() {
|
||||
let receiver_id = this.sender_id;
|
||||
let talk_type = this.talk_type;
|
||||
|
||||
if (talk_type == 1 && this.receiver_id != this.getAccountId()) {
|
||||
receiver_id = this.receiver_id;
|
||||
} else if (talk_type == 2) {
|
||||
receiver_id = this.receiver_id;
|
||||
}
|
||||
console.log("加载对接节点", this.resource);
|
||||
|
||||
ServeCreateTalkList(receiver_id).then(({ code, data }) => {
|
||||
if (code == 200) {
|
||||
this.getStoreInstance().commit("PUSH_TALK_ITEM", formatTalkItem(data));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 插入对话记录
|
||||
*/
|
||||
insertTalkRecord() {
|
||||
let store = this.getStoreInstance();
|
||||
let record = this.resource;
|
||||
console.log("插入谈话记录", record);
|
||||
|
||||
record.float = this.getFloatType();
|
||||
|
||||
store.commit("PUSH_DIALOGUE", record);
|
||||
|
||||
// 获取聊天面板元素节点
|
||||
let el = document.getElementById("lumenChatPanel");
|
||||
|
||||
// 判断的滚动条是否在底部
|
||||
let isBottom = Math.ceil(el.scrollTop) + el.clientHeight >= el.scrollHeight;
|
||||
|
||||
if (
|
||||
isBottom ||
|
||||
record.userId == this.getAccountId() ||
|
||||
record.fromUser == this.getAccountId()
|
||||
) {
|
||||
Vue.nextTick(() => {
|
||||
el.scrollTop = el.scrollHeight;
|
||||
});
|
||||
} else {
|
||||
console.log("%c SET_TLAK_UNREAD_MESSAGE %c", "color:red");
|
||||
store.commit("SET_TLAK_UNREAD_MESSAGE", {
|
||||
content: this.getTalkText(),
|
||||
nickname: record.name,
|
||||
});
|
||||
}
|
||||
console.log("%c 准备更新...UPDATE_TALK_ITEM ", "color:red");
|
||||
|
||||
store.commit("UPDATE_TALK_ITEM", {
|
||||
index_name: this.getIndexName(),
|
||||
msg_text: this.getTalkText() || record.text,
|
||||
updated_at: parseTime(new Date()),
|
||||
});
|
||||
|
||||
if (this.talk_type == 1 && this.getAccountId() !== this.sender_id) {
|
||||
console.log("%c 清除 未读数...ServeClearTalkUnreadNum ", "color:blue");
|
||||
ServeClearTalkUnreadNum({
|
||||
talk_type: 1,
|
||||
receiver_id: this.sender_id,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新对话列表记录
|
||||
*/
|
||||
updateTalkItem() {
|
||||
console.log("%c 更新对话列表记录", "color:#32ccbc");
|
||||
let store = this.getStoreInstance();
|
||||
|
||||
store.commit("INCR_UNREAD_NUM");
|
||||
|
||||
store.commit("UPDATE_TALK_MESSAGE", {
|
||||
index_name: this.getIndexName(),
|
||||
msg_text: this.getTalkText(),
|
||||
updated_at: parseTime(new Date()),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default Talk;
|
||||
117
im/src/im-server/socket-instance.js
Normal file
117
im/src/im-server/socket-instance.js
Normal file
@@ -0,0 +1,117 @@
|
||||
import store from "@/store";
|
||||
import config from "@/config/config";
|
||||
import WsSocket from "@/plugins/ws-socket";
|
||||
import { getToken } from "@/utils/auth";
|
||||
import { Notification } from "element-ui";
|
||||
|
||||
// 引入消息处理类
|
||||
import KeyboardEvent from "@/im-server/event/keyboard";
|
||||
import LoginEvent from "@/im-server/event/login";
|
||||
import TalkEvent from "@/im-server/event/talk";
|
||||
import RevokeEvent from "@/im-server/event/revoke";
|
||||
import GroupJoinEvent from "@/im-server/event/group-join";
|
||||
import FriendApplyEvent from "@/im-server/event/friend-apply";
|
||||
|
||||
/**
|
||||
* SocketInstance 连接实例
|
||||
*
|
||||
* 注释: 所有 WebSocket 消息接收处理在此实例中处理
|
||||
*/
|
||||
class SocketInstance {
|
||||
/**
|
||||
* WsSocket 实例
|
||||
*/
|
||||
socket;
|
||||
|
||||
/**
|
||||
* SocketInstance 初始化实例
|
||||
*/
|
||||
constructor() {
|
||||
this.socket = new WsSocket(
|
||||
() => {
|
||||
return `${config.BASE_WS_URL}/` + getToken();
|
||||
},
|
||||
{
|
||||
onError: (evt) => {
|
||||
console.log("Websocket 连接失败回调方法");
|
||||
},
|
||||
// Websocket 连接成功回调方法
|
||||
onOpen: (evt) => {
|
||||
this.updateSocketStatus(true);
|
||||
},
|
||||
// Websocket 断开连接回调方法
|
||||
onClose: (evt) => {
|
||||
this.updateSocketStatus(false);
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
this.registerEvents();
|
||||
}
|
||||
|
||||
// 连接 WebSocket 服务
|
||||
connect() {
|
||||
console.log("🔗连接 WebSocket");
|
||||
this.socket.connection();
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册回调消息处理事件
|
||||
*/
|
||||
registerEvents() {
|
||||
this.socket.on("event_talk", (data) => {
|
||||
console.log("接收到消息,event_talk", data);
|
||||
new TalkEvent(data).handle();
|
||||
});
|
||||
|
||||
this.socket.on("event_online_status", (data) => {
|
||||
new LoginEvent(data).handle();
|
||||
});
|
||||
|
||||
this.socket.on("event_keyboard", (data) => {
|
||||
console.log("推送", data);
|
||||
new KeyboardEvent(data).handle();
|
||||
});
|
||||
|
||||
this.socket.on("event_revoke_talk", (data) => {
|
||||
new RevokeEvent(data).handle();
|
||||
});
|
||||
|
||||
this.socket.on("event_friend_apply", (data) => {
|
||||
new FriendApplyEvent(data).handle();
|
||||
});
|
||||
|
||||
this.socket.on("join_group", (data) => {
|
||||
new GroupJoinEvent(data).handle();
|
||||
});
|
||||
|
||||
this.socket.on("event_error", (data) => {
|
||||
Notification({
|
||||
title: "友情提示",
|
||||
message: data.message,
|
||||
type: "warning",
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新 WebSocket 连接状态
|
||||
*
|
||||
* @param {Boolean} status 连接状态
|
||||
*/
|
||||
updateSocketStatus(status) {
|
||||
store.commit("UPDATE_SOCKET_STATUS", status);
|
||||
}
|
||||
|
||||
/**
|
||||
* 推送消息
|
||||
*
|
||||
* @param {String} event 事件名
|
||||
* @param {Object} data 数据
|
||||
*/
|
||||
emit(event, data) {
|
||||
this.socket.emit(event, data);
|
||||
}
|
||||
}
|
||||
|
||||
export default new SocketInstance();
|
||||
1
im/src/im-server/util.js
Normal file
1
im/src/im-server/util.js
Normal file
@@ -0,0 +1 @@
|
||||
// IM 助手
|
||||
Reference in New Issue
Block a user