Browse Source

用pinia代理vuex

master
xsx 10 months ago
parent
commit
75db96f39b
  1. 3
      im-web/package.json
  2. 4
      im-web/src/components/chat/ChatAtBox.vue
  3. 50
      im-web/src/components/chat/ChatBox.vue
  4. 2
      im-web/src/components/chat/ChatGroupReaded.vue
  5. 8
      im-web/src/components/chat/ChatGroupSide.vue
  6. 2
      im-web/src/components/chat/ChatHistory.vue
  7. 8
      im-web/src/components/common/UserInfo.vue
  8. 6
      im-web/src/components/friend/AddFriend.vue
  9. 2
      im-web/src/components/group/AddGroupMember.vue
  10. 2
      im-web/src/components/rtc/RtcGroupJoin.vue
  11. 2
      im-web/src/components/rtc/RtcPrivateVideo.vue
  12. 7
      im-web/src/components/setting/Setting.vue
  13. 21
      im-web/src/main.js
  14. 233
      im-web/src/store/chatStore.js
  15. 25
      im-web/src/store/configStore.js
  16. 115
      im-web/src/store/friendStore.js
  17. 60
      im-web/src/store/groupStore.js
  18. 11
      im-web/src/store/uiStore.js
  19. 40
      im-web/src/store/userStore.js
  20. 9
      im-web/src/view/Chat.vue
  21. 19
      im-web/src/view/Friend.vue
  22. 28
      im-web/src/view/Group.vue
  23. 107
      im-web/src/view/Home.vue

3
im-web/package.json

@ -19,8 +19,7 @@
"vue": "2.7.16", "vue": "2.7.16",
"vue-axios": "3.5.2", "vue-axios": "3.5.2",
"vue-router": "3.6.5", "vue-router": "3.6.5",
"vuex": "3.6.2", "pinia": "^2.1.7"
"vuex-persist": "3.1.3"
}, },
"devDependencies": { "devDependencies": {
"@vue/cli-plugin-babel": "~4.5.12", "@vue/cli-plugin-babel": "~4.5.12",

4
im-web/src/components/chat/ChatAtBox.vue

@ -42,7 +42,7 @@ export default {
init() { init() {
this.$refs.scrollBox.wrap.scrollTop = 0; this.$refs.scrollBox.wrap.scrollTop = 0;
this.showMembers = []; this.showMembers = [];
let userId = this.$store.state.userStore.userInfo.id; let userId = this.userStore.userInfo.id;
let name = "全体成员"; let name = "全体成员";
if (this.ownerId == userId && name.startsWith(this.searchText)) { if (this.ownerId == userId && name.startsWith(this.searchText)) {
this.showMembers.push({ this.showMembers.push({
@ -108,7 +108,7 @@ export default {
}, },
computed: { computed: {
isOwner() { isOwner() {
return this.$store.state.userStore.userInfo.id == this.ownerId; return this.userStore.userInfo.id == this.ownerId;
} }
}, },
watch: { watch: {

50
im-web/src/components/chat/ChatBox.vue

@ -140,8 +140,8 @@ export default {
}, },
methods: { methods: {
moveChatToTop() { moveChatToTop() {
let chatIdx = this.$store.getters.findChatIdx(this.chat); let chatIdx = this.chatStore.findChatIdx(this.chat);
this.$store.commit("moveTop", chatIdx); this.chatStore.moveTop(chatIdx);
}, },
closeRefBox() { closeRefBox() {
this.$refs.emoBox.close(); this.$refs.emoBox.close();
@ -166,13 +166,13 @@ export default {
msgInfo.loadStatus = 'ok'; msgInfo.loadStatus = 'ok';
msgInfo.id = m.id; msgInfo.id = m.id;
this.isReceipt = false; this.isReceipt = false;
this.$store.commit("insertMessage", [msgInfo, file.chat]); this.chatStore.insertMessage(msgInfo, file.chat);
}) })
}, },
onImageFail(e, file) { onImageFail(e, file) {
let msgInfo = JSON.parse(JSON.stringify(file.msgInfo)); let msgInfo = JSON.parse(JSON.stringify(file.msgInfo));
msgInfo.loadStatus = 'fail'; msgInfo.loadStatus = 'fail';
this.$store.commit("insertMessage", [msgInfo, file.chat]); this.chatStore.insertMessage(msgInfo, file.chat);
}, },
onImageBefore(file) { onImageBefore(file) {
// //
@ -201,7 +201,7 @@ export default {
// id // id
this.fillTargetId(msgInfo, this.chat.targetId); this.fillTargetId(msgInfo, this.chat.targetId);
// //
this.$store.commit("insertMessage", [msgInfo, this.chat]); this.chatStore.insertMessage(msgInfo, this.chat);
// //
this.moveChatToTop(); this.moveChatToTop();
// //
@ -224,13 +224,13 @@ export default {
msgInfo.id = m.id; msgInfo.id = m.id;
this.isReceipt = false; this.isReceipt = false;
this.refreshPlaceHolder(); this.refreshPlaceHolder();
this.$store.commit("insertMessage", [msgInfo, file.chat]); this.chatStore.insertMessage(msgInfo, file.chat);
}) })
}, },
onFileFail(e, file) { onFileFail(e, file) {
let msgInfo = JSON.parse(JSON.stringify(file.msgInfo)); let msgInfo = JSON.parse(JSON.stringify(file.msgInfo));
msgInfo.loadStatus = 'fail'; msgInfo.loadStatus = 'fail';
this.$store.commit("insertMessage", [msgInfo, file.chat]); this.chatStore.insertMessage(msgInfo, file.chat);
}, },
onFileBefore(file) { onFileBefore(file) {
// //
@ -259,7 +259,7 @@ export default {
// id // id
this.fillTargetId(msgInfo, this.chat.targetId); this.fillTargetId(msgInfo, this.chat.targetId);
// //
this.$store.commit("insertMessage", [msgInfo, this.chat]); this.chatStore.insertMessage(msgInfo, this.chat);
// //
this.moveChatToTop(); this.moveChatToTop();
// //
@ -330,7 +330,7 @@ export default {
} }
// //
let ids = [this.mine.id]; let ids = [this.mine.id];
let maxChannel = this.$store.state.configStore.webrtc.maxChannel; let maxChannel = this.configStore.webrtc.maxChannel;
this.$refs.rtcSel.open(maxChannel, ids, ids, []); this.$refs.rtcSel.open(maxChannel, ids, ids, []);
}, },
onInviteOk(members) { onInviteOk(members) {
@ -375,9 +375,9 @@ export default {
} }
// id // id
this.fillTargetId(msgInfo, this.chat.targetId); this.fillTargetId(msgInfo, this.chat.targetId);
this.sendMessageRequest(msgInfo).then((m) => { this.sendMessageRequest(msgInfo).then(m => {
m.selfSend = true; m.selfSend = true;
this.$store.commit("insertMessage", [m, this.chat]); this.chatStore.insertMessage(m, this.chat);
// //
this.moveChatToTop(); this.moveChatToTop();
// //
@ -462,7 +462,7 @@ export default {
this.lockMessage = true; this.lockMessage = true;
this.sendMessageRequest(msgInfo).then((m) => { this.sendMessageRequest(msgInfo).then((m) => {
m.selfSend = true; m.selfSend = true;
this.$store.commit("insertMessage", [m, this.chat]); this.chatStore.insertMessage(m, this.chat);
// //
this.moveChatToTop(); this.moveChatToTop();
}).finally(() => { }).finally(() => {
@ -487,7 +487,7 @@ export default {
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning'
}).then(() => { }).then(() => {
this.$store.commit("deleteMessage", [msgInfo, this.chat]); this.chatStore.deleteMessage(msgInfo, this.chat);
}); });
}, },
recallMessage(msgInfo) { recallMessage(msgInfo) {
@ -503,7 +503,7 @@ export default {
}).then((m) => { }).then((m) => {
this.$message.success("消息已撤回"); this.$message.success("消息已撤回");
m.selfSend = true; m.selfSend = true;
this.$store.commit("recallMessage", [m, this.chat]); this.chatStore.recallMessage(m, this.chat);
}) })
}); });
}, },
@ -511,7 +511,7 @@ export default {
if (this.chat.unreadCount == 0) { if (this.chat.unreadCount == 0) {
return; return;
} }
this.$store.commit("resetUnreadCount", this.chat) this.chatStore.resetUnreadCount(this.chat)
if (this.chat.type == "GROUP") { if (this.chat.type == "GROUP") {
var url = `/message/group/readed?groupId=${this.chat.targetId}` var url = `/message/group/readed?groupId=${this.chat.targetId}`
} else { } else {
@ -527,7 +527,7 @@ export default {
url: `/message/private/maxReadedId?friendId=${fId}`, url: `/message/private/maxReadedId?friendId=${fId}`,
method: 'get' method: 'get'
}).then((id) => { }).then((id) => {
this.$store.commit("readedMessage", { this.chatStore.readedMessage({
friendId: fId, friendId: fId,
maxId: id maxId: id
}); });
@ -539,8 +539,8 @@ export default {
method: 'get' method: 'get'
}).then((group) => { }).then((group) => {
this.group = group; this.group = group;
this.$store.commit("updateChatFromGroup", group); this.chatStore.updateChatFromGroup(group);
this.$store.commit("updateGroup", group); this.groupStore.updateGroup(group);
}); });
this.$http({ this.$http({
@ -557,10 +557,10 @@ export default {
friend.headImage = this.userInfo.headImageThumb; friend.headImage = this.userInfo.headImageThumb;
friend.nickName = this.userInfo.nickName; friend.nickName = this.userInfo.nickName;
friend.showNickName = friend.remarkNickName ? friend.remarkNickName : friend.nickName; friend.showNickName = friend.remarkNickName ? friend.remarkNickName : friend.nickName;
this.$store.commit("updateChatFromFriend", friend); this.chatStore.updateChatFromFriend(friend);
this.$store.commit("updateFriend", friend); this.friendStore.updateFriend(friend);
} else { } else {
this.$store.commit("updateChatFromUser", this.userInfo); this.chatStore.updateChatFromUser(this.userInfo);
} }
}, },
loadFriend(friendId) { loadFriend(friendId) {
@ -653,7 +653,7 @@ export default {
msgInfo.groupId = this.group.id; msgInfo.groupId = this.group.id;
msgInfo.content = "本群聊已被管理员封禁,原因:" + this.group.reason msgInfo.content = "本群聊已被管理员封禁,原因:" + this.group.reason
} }
this.$store.commit("insertMessage", [msgInfo, this.chat]); this.chatStore.insertMessage(msgInfo, this.chat);
}, },
generateId() { generateId() {
// id // id
@ -662,13 +662,13 @@ export default {
}, },
computed: { computed: {
mine() { mine() {
return this.$store.state.userStore.userInfo; return this.userStore.userInfo;
}, },
isFriend() { isFriend() {
return this.$store.getters.isFriend(this.userInfo.id); return this.friendStore.isFriend(this.userInfo.id);
}, },
friend() { friend() {
return this.$store.getters.findFriend(this.userInfo.id) return this.friendStore.findFriend(this.userInfo.id)
}, },
title() { title() {
let title = this.chat.showName; let title = this.chat.showName;

2
im-web/src/components/chat/ChatGroupReaded.vue

@ -115,7 +115,7 @@ export default {
type: 'GROUP', type: 'GROUP',
targetId: this.msgInfo.groupId targetId: this.msgInfo.groupId
} }
this.$store.commit("updateMessage", [msgInfo, chatInfo]) this.chatStore.updateMessage(msgInfo, chatInfo)
}) })
} }
} }

8
im-web/src/components/chat/ChatGroupSide.vue

@ -124,7 +124,7 @@ export default {
data: vo data: vo
}).then((group) => { }).then((group) => {
this.editing = !this.editing this.editing = !this.editing
this.$store.commit("updateGroup", group); this.groupStore.updateGroup(group);
this.$emit('reload'); this.$emit('reload');
this.$message.success("修改成功"); this.$message.success("修改成功");
}) })
@ -139,8 +139,8 @@ export default {
url: `/group/quit/${this.group.id}`, url: `/group/quit/${this.group.id}`,
method: 'delete' method: 'delete'
}).then(() => { }).then(() => {
this.$store.commit("removeGroup", this.group.id); this.groupStore.removeGroup(this.group.id);
this.$store.commit("removeGroupChat", this.group.id); this.chatStore.removeGroupChat(this.group.id);
}); });
}) })
}, },
@ -156,7 +156,7 @@ export default {
}, },
computed: { computed: {
mine() { mine() {
return this.$store.state.userStore.userInfo; return this.userStore.userInfo;
}, },
ownerName() { ownerName() {
let member = this.groupMembers.find((m) => m.userId == this.group.ownerId); let member = this.groupMembers.find((m) => m.userId == this.group.ownerId);

2
im-web/src/components/chat/ChatHistory.vue

@ -126,7 +126,7 @@ export default {
}, },
computed: { computed: {
mine() { mine() {
return this.$store.state.userStore.userInfo; return this.userStore.userInfo;
}, },
histroyAction() { histroyAction() {
return `/message/${this.chat.type.toLowerCase()}/history`; return `/message/${this.chat.type.toLowerCase()}/history`;

8
im-web/src/components/common/UserInfo.vue

@ -59,8 +59,8 @@ export default {
showName: user.nickName, showName: user.nickName,
headImage: user.headImage, headImage: user.headImage,
}; };
this.$store.commit("openChat", chat); this.chatStore.openChat(chat);
this.$store.commit("activeChat", 0); this.chatStore.setActiveChat(0);
if (this.$route.path != "/home/chat") { if (this.$route.path != "/home/chat") {
this.$router.push("/home/chat"); this.$router.push("/home/chat");
} }
@ -82,7 +82,7 @@ export default {
online: this.user.online, online: this.user.online,
deleted: false deleted: false
} }
this.$store.commit("addFriend", friend); this.friendStore.addFriend(friend);
}) })
}, },
showFullImage() { showFullImage() {
@ -93,7 +93,7 @@ export default {
}, },
computed: { computed: {
isFriend() { isFriend() {
return this.$store.getters.isFriend(this.user.id); return this.friendStore.isFriend(this.user.id);
} }
} }
} }

6
im-web/src/components/friend/AddFriend.vue

@ -6,7 +6,7 @@
<i class="el-icon-search el-input__icon" slot="suffix" @click="onSearch()"> </i> <i class="el-icon-search el-input__icon" slot="suffix" @click="onSearch()"> </i>
</el-input> </el-input>
<el-scrollbar style="height:400px"> <el-scrollbar style="height:400px">
<div v-for="(user) in users" :key="user.id" v-show="user.id != $store.state.userStore.userInfo.id"> <div v-for="(user) in users" :key="user.id" v-show="user.id != userStore.userInfo.id">
<div class="item"> <div class="item">
<div class="avatar"> <div class="avatar">
<head-image :name="user.nickName" :url="user.headImage" :online="user.online"></head-image> <head-image :name="user.nickName" :url="user.headImage" :online="user.online"></head-image>
@ -83,11 +83,11 @@ export default {
online: user.online, online: user.online,
deleted: false deleted: false
} }
this.$store.commit("addFriend", friend); this.friendStore.addFriend(friend);
}) })
}, },
isFriend(userId) { isFriend(userId) {
return this.$store.getters.isFriend(userId); return this.friendStore.isFriend(userId);
} }
} }
} }

2
im-web/src/components/group/AddGroupMember.vue

@ -55,7 +55,7 @@ export default {
open() { open() {
this.show = true; this.show = true;
this.friends = []; this.friends = [];
this.$store.state.friendStore.friends.forEach((f) => { this.friendStore.friends.forEach((f) => {
if (f.deleted) { if (f.deleted) {
return; return;
} }

2
im-web/src/components/rtc/RtcGroupJoin.vue

@ -52,7 +52,7 @@ export default {
onOk() { onOk() {
this.isShow = false; this.isShow = false;
let userInfos = this.rtcInfo.userInfos; let userInfos = this.rtcInfo.userInfos;
let mine = this.$store.state.userStore.userInfo; let mine = this.userStore.userInfo;
if (!userInfos.find((user) => user.id == mine.id)) { if (!userInfos.find((user) => user.id == mine.id)) {
// //
userInfos.push({ userInfos.push({

2
im-web/src/components/rtc/RtcPrivateVideo.vue

@ -383,7 +383,7 @@ export default {
return strTime; return strTime;
}, },
configuration() { configuration() {
const iceServers = this.$store.state.configStore.webrtc.iceServers; const iceServers = this.configStore.webrtc.iceServers;
return { return {
iceServers: iceServers iceServers: iceServers
} }

7
im-web/src/components/setting/Setting.vue

@ -56,7 +56,6 @@ export default {
} }
}, },
methods: { methods: {
onClose() { onClose() {
this.$emit("close"); this.$emit("close");
}, },
@ -70,7 +69,7 @@ export default {
method: "put", method: "put",
data: this.userInfo data: this.userInfo
}).then(() => { }).then(() => {
this.$store.commit("setUserInfo", this.userInfo); this.userStore.setUserInfo(this.userInfo);
this.$emit("close"); this.$emit("close");
this.$message.success("修改成功"); this.$message.success("修改成功");
}) })
@ -92,9 +91,9 @@ export default {
} }
}, },
watch: { watch: {
visible: function(newData, oldData) { visible: function () {
// //
let mine = this.$store.state.userStore.userInfo; let mine = this.userStore.userInfo;
this.userInfo = JSON.parse(JSON.stringify(mine)); this.userInfo = JSON.parse(JSON.stringify(mine));
} }
} }

21
im-web/src/main.js

@ -4,18 +4,26 @@ import router from './router'
import ElementUI from 'element-ui'; import ElementUI from 'element-ui';
import './assets/style/im.scss'; import './assets/style/im.scss';
import './assets/iconfont/iconfont.css'; import './assets/iconfont/iconfont.css';
import { createPinia, PiniaVuePlugin } from 'pinia'
import httpRequest from './api/httpRequest'; import httpRequest from './api/httpRequest';
import * as socketApi from './api/wssocket'; import * as socketApi from './api/wssocket';
import * as messageType from './api/messageType'; import * as messageType from './api/messageType';
import emotion from './api/emotion.js'; import emotion from './api/emotion.js';
import url from './api/url.js'; import url from './api/url.js';
import element from './api/element.js'; import element from './api/element.js';
import store from './store';
import * as enums from './api/enums.js'; import * as enums from './api/enums.js';
import * as date from './api/date.js'; import * as date from './api/date.js';
import './utils/directive/dialogDrag'; import './utils/directive/dialogDrag';
import useChatStore from './store/chatStore.js'
import useFriendStore from './store/friendStore.js'
import useGroupStore from './store/groupStore.js'
import useUserStore from './store/userStore.js'
import useConfigStore from './store/configStore.js'
import useUiStore from './store/uiStore.js'
Vue.use(PiniaVuePlugin)
const pinia = createPinia()
Vue.use(ElementUI); Vue.use(ElementUI);
// 挂载全局 // 挂载全局
Vue.prototype.$wsApi = socketApi; Vue.prototype.$wsApi = socketApi;
@ -33,7 +41,14 @@ new Vue({
el: '#app', el: '#app',
// 配置路由 // 配置路由
router, router,
store, pinia,
render: h => h(App) render: h => h(App)
}) })
// 挂载全局的pinia
Vue.prototype.chatStore = useChatStore();
Vue.prototype.friendStore = useFriendStore();
Vue.prototype.groupStore = useGroupStore();
Vue.prototype.userStore = useUserStore();
Vue.prototype.configStore = useConfigStore();
Vue.prototype.uiStore = useUiStore();

233
im-web/src/store/chatStore.js

@ -1,26 +1,42 @@
import { defineStore } from 'pinia';
import { MESSAGE_TYPE, MESSAGE_STATUS } from "../api/enums.js" import { MESSAGE_TYPE, MESSAGE_STATUS } from "../api/enums.js"
import userStore from './userStore'; import useUserStore from './userStore.js';
import localForage from 'localforage'; import localForage from 'localforage';
/* 线cacheChats, /**
待所有离线消息拉取完成后再统一放至vuex中进行渲染*/ * 优化1(冷热消息分区):
* 热消息登录后的消息
* 冷消息: 登录前的消息
* 每个会话的冷热消息分别用一个key进行存储当有新的消息时只更新热消息key冷消息key保持不变
* 由于热消息数量不会很大所以localForage.setItem耗时很低可以防止消息过多时出现卡顿的情况
*
* 优化2(延迟渲染):
* 拉取消息时如果直接用state.chats接收页面就开始渲染一边渲染页面一边大量接消息会导致很严重的卡顿
* 为了加速拉取离线消息效率拉取时消息暂时存储到cacheChats,等待所有离线消息拉取完成后再统一放至state中进行渲染
*
* 优化3(pinia代替vuex)
* 实测pinia的远超vuex,且语法更简洁清晰
*
* */
let cacheChats = []; let cacheChats = [];
export default { export default defineStore('chatStore', {
state: { state: () => {
return {
activeChat: null, activeChat: null,
privateMsgMaxId: 0, privateMsgMaxId: 0,
groupMsgMaxId: 0, groupMsgMaxId: 0,
loadingPrivateMsg: false, loadingPrivateMsg: false,
loadingGroupMsg: false, loadingGroupMsg: false,
chats: [] chats: []
}
}, },
actions: {
mutations: { initChats(chatsData) {
initChats(state, chatsData) { this.chats = [];
state.chats = []; this.privateMsgMaxId = chatsData.privateMsgMaxId || 0;
state.privateMsgMaxId = chatsData.privateMsgMaxId || 0; this.groupMsgMaxId = chatsData.groupMsgMaxId || 0;
state.groupMsgMaxId = chatsData.groupMsgMaxId || 0;
cacheChats = chatsData.chats || []; cacheChats = chatsData.chats || [];
// 防止图片一直处在加载中状态 // 防止图片一直处在加载中状态
cacheChats.forEach((chat) => { cacheChats.forEach((chat) => {
@ -31,15 +47,15 @@ export default {
}) })
}) })
}, },
openChat(state, chatInfo) { openChat(chatInfo) {
let chats = this.getters.findChats() let chats = this.findChats()
let chat = null; let chat = null;
for (let idx in chats) { for (let idx in chats) {
if (chats[idx].type == chatInfo.type && if (chats[idx].type == chatInfo.type &&
chats[idx].targetId === chatInfo.targetId) { chats[idx].targetId === chatInfo.targetId) {
chat = chats[idx]; chat = chats[idx];
// 放置头部 // 放置头部
this.commit("moveTop", idx) this.moveTop(idx)
break; break;
} }
} }
@ -62,12 +78,12 @@ export default {
chats.unshift(chat); chats.unshift(chat);
} }
}, },
activeChat(state, idx) { setActiveChat(idx) {
let chats = this.getters.findChats(); let chats = this.findChats();
state.activeChat = chats[idx]; this.activeChat = chats[idx];
}, },
resetUnreadCount(state, chatInfo) { resetUnreadCount(chatInfo) {
let chats = this.getters.findChats(); let chats = this.findChats();
for (let idx in chats) { for (let idx in chats) {
if (chats[idx].type == chatInfo.type && if (chats[idx].type == chatInfo.type &&
chats[idx].targetId == chatInfo.targetId) { chats[idx].targetId == chatInfo.targetId) {
@ -75,13 +91,13 @@ export default {
chats[idx].atMe = false; chats[idx].atMe = false;
chats[idx].atAll = false; chats[idx].atAll = false;
chats[idx].stored = false; chats[idx].stored = false;
this.commit("saveToStorage"); this.saveToStorage();
break; break;
} }
} }
}, },
readedMessage(state, pos) { readedMessage(pos) {
let chat = this.getters.findChatByFriend(pos.friendId); let chat = this.findChatByFriend(pos.friendId);
if (!chat) return; if (!chat) return;
chat.messages.forEach((m) => { chat.messages.forEach((m) => {
if (m.id && m.selfSend && m.status < MESSAGE_STATUS.RECALL) { if (m.id && m.selfSend && m.status < MESSAGE_STATUS.RECALL) {
@ -92,68 +108,69 @@ export default {
} }
} }
}) })
this.commit("saveToStorage"); this.saveToStorage();
}, },
removeChat(state, idx) { removeChat(idx) {
let chats = this.getters.findChats(); let chats = this.findChats();
if (chats[idx] == state.activeChat) { if (chats[idx] == this.activeChat) {
state.activeChat = null; this.activeChat = null;
} }
chats[idx].delete = true; chats[idx].delete = true;
chats[idx].stored = false; chats[idx].stored = false;
this.commit("saveToStorage"); this.saveToStorage();
}, },
removePrivateChat(state, friendId) { removePrivateChat(friendId) {
let chats = this.getters.findChats(); let chats = this.findChats();
for (let idx in chats) { for (let idx in chats) {
if (chats[idx].type == 'PRIVATE' && if (chats[idx].type == 'PRIVATE' &&
chats[idx].targetId === friendId) { chats[idx].targetId === friendId) {
this.commit("removeChat", idx) this.removeChat(idx);
break; break;
} }
} }
}, },
removeGroupChat(state, groupId) { removeGroupChat(groupId) {
let chats = this.getters.findChats(); let chats = this.findChats();
for (let idx in chats) { for (let idx in chats) {
if (chats[idx].type == 'GROUP' && if (chats[idx].type == 'GROUP' &&
chats[idx].targetId === groupId) { chats[idx].targetId === groupId) {
this.commit("removeChat", idx) this.removeChat(idx);
break; break;
} }
} }
}, },
moveTop(state, idx) { moveTop(idx) {
// 加载中不移动,很耗性能 // 加载中不移动,很耗性能
if (this.getters.isLoading()) { if (this.isLoading()) {
return; return;
} }
if (idx > 0) { if (idx > 0) {
let chats = this.getters.findChats(); let chats = this.findChats();
let chat = chats[idx]; let chat = chats[idx];
chats.splice(idx, 1); chats.splice(idx, 1);
chats.unshift(chat); chats.unshift(chat);
chat.lastSendTime = new Date().getTime(); chat.lastSendTime = new Date().getTime();
chat.stored = false; chat.stored = false;
this.commit("saveToStorage"); this.saveToStorage();
} }
}, },
insertMessage(state, [msgInfo, chatInfo]) { insertMessage(msgInfo, chatInfo) {
let time = new Date().getTime()
let type = chatInfo.type; let type = chatInfo.type;
// 记录消息的最大id // 记录消息的最大id
if (msgInfo.id && type == "PRIVATE" && msgInfo.id > state.privateMsgMaxId) { if (msgInfo.id && type == "PRIVATE" && msgInfo.id > this.privateMsgMaxId) {
state.privateMsgMaxId = msgInfo.id; this.privateMsgMaxId = msgInfo.id;
} }
if (msgInfo.id && type == "GROUP" && msgInfo.id > state.groupMsgMaxId) { if (msgInfo.id && type == "GROUP" && msgInfo.id > this.groupMsgMaxId) {
state.groupMsgMaxId = msgInfo.id; this.groupMsgMaxId = msgInfo.id;
} }
// 如果是已存在消息,则覆盖旧的消息数据 // 如果是已存在消息,则覆盖旧的消息数据
let chat = this.getters.findChat(chatInfo); let chat = this.findChat(chatInfo);
let message = this.getters.findMessage(chat, msgInfo); let message = this.findMessage(chat, msgInfo);
if (message) { if (message) {
Object.assign(message, msgInfo); Object.assign(message, msgInfo);
chat.stored = false; chat.stored = false;
this.commit("saveToStorage"); this.saveToStorage();
return; return;
} }
// 插入新的数据 // 插入新的数据
@ -182,7 +199,8 @@ export default {
// 是否有人@我 // 是否有人@我
if (!msgInfo.selfSend && chat.type == "GROUP" && msgInfo.atUserIds && if (!msgInfo.selfSend && chat.type == "GROUP" && msgInfo.atUserIds &&
msgInfo.status != MESSAGE_STATUS.READED) { msgInfo.status != MESSAGE_STATUS.READED) {
let userId = userStore.state.userInfo.id; let userStore = useUserStore();
let userId = userStore.userInfo.id;
if (msgInfo.atUserIds.indexOf(userId) >= 0) { if (msgInfo.atUserIds.indexOf(userId) >= 0) {
chat.atMe = true; chat.atMe = true;
} }
@ -212,21 +230,22 @@ export default {
} }
chat.messages.splice(insertPos, 0, msgInfo); chat.messages.splice(insertPos, 0, msgInfo);
chat.stored = false; chat.stored = false;
this.commit("saveToStorage"); this.saveToStorage();
console.log("耗时:", new Date().getTime() - time)
}, },
updateMessage(state, [msgInfo, chatInfo]) { updateMessage(msgInfo, chatInfo) {
// 获取对方id或群id // 获取对方id或群id
let chat = this.getters.findChat(chatInfo); let chat = this.findChat(chatInfo);
let message = this.getters.findMessage(chat, msgInfo); let message = this.findMessage(chat, msgInfo);
if (message) { if (message) {
// 属性拷贝 // 属性拷贝
Object.assign(message, msgInfo); Object.assign(message, msgInfo);
chat.stored = false; chat.stored = false;
this.commit("saveToStorage"); this.saveToStorage();
} }
}, },
deleteMessage(state, [msgInfo, chatInfo]) { deleteMessage(msgInfo, chatInfo) {
let chat = this.getters.findChat(chatInfo); let chat = this.findChat(chatInfo);
for (let idx in chat.messages) { for (let idx in chat.messages) {
// 已经发送成功的,根据id删除 // 已经发送成功的,根据id删除
if (chat.messages[idx].id && chat.messages[idx].id == msgInfo.id) { if (chat.messages[idx].id && chat.messages[idx].id == msgInfo.id) {
@ -240,10 +259,10 @@ export default {
} }
} }
chat.stored = false; chat.stored = false;
this.commit("saveToStorage"); this.saveToStorage();
}, },
recallMessage(state, [msgInfo, chatInfo]) { recallMessage(msgInfo, chatInfo) {
let chat = this.getters.findChat(chatInfo); let chat = this.findChat(chatInfo);
if (!chat) return; if (!chat) return;
// 要撤回的消息id // 要撤回的消息id
let id = msgInfo.content; let id = msgInfo.content;
@ -271,21 +290,21 @@ export default {
} }
} }
chat.stored = false; chat.stored = false;
this.commit("saveToStorage"); this.saveToStorage();
}, },
updateChatFromFriend(state, friend) { updateChatFromFriend(friend) {
let chat = this.getters.findChatByFriend(friend.id); let chat = this.findChatByFriend(friend.id);
// 更新会话中的群名和头像 // 更新会话中的群名和头像
if (chat && (chat.headImage != friend.headImage || if (chat && (chat.headImage != friend.headImage ||
chat.showName != friend.nickName)) { chat.showName != friend.nickName)) {
chat.headImage = friend.headImage; chat.headImage = friend.headImage;
chat.showName = friend.nickName; chat.showName = friend.nickName;
chat.stored = false; chat.stored = false;
this.commit("saveToStorage") this.saveToStorage()
} }
}, },
updateChatFromUser(user) { updateChatFromUser(user) {
let chat = this.getters.findChatByFriend(user.id); let chat = this.findChatByFriend(user.id);
// 更新会话中的昵称和头像 // 更新会话中的昵称和头像
if (chat && (chat.headImage != user.headImageThumb || if (chat && (chat.headImage != user.headImageThumb ||
chat.showName != user.nickName)) { chat.showName != user.nickName)) {
@ -295,30 +314,30 @@ export default {
this.saveToStorage(); this.saveToStorage();
} }
}, },
updateChatFromGroup(state, group) { updateChatFromGroup(group) {
let chat = this.getters.findChatByGroup(group.id); let chat = this.findChatByGroup(group.id);
if (chat && (chat.headImage != group.headImageThumb || if (chat && (chat.headImage != group.headImageThumb ||
chat.showName != group.showGroupName)) { chat.showName != group.showGroupName)) {
// 更新会话中的群名称和头像 // 更新会话中的群名称和头像
chat.headImage = group.headImageThumb; chat.headImage = group.headImageThumb;
chat.showName = group.showGroupName; chat.showName = group.showGroupName;
chat.stored = false; chat.stored = false;
this.commit("saveToStorage") this.saveToStorage()
} }
}, },
loadingPrivateMsg(state, loading) { setLoadingPrivateMsg(loading) {
state.loadingPrivateMsg = loading; this.loadingPrivateMsg = loading;
if (!this.getters.isLoading()) { if (!this.isLoading()) {
this.commit("refreshChats") this.refreshChats();
} }
}, },
loadingGroupMsg(state, loading) { setLoadingGroupMsg(loading) {
state.loadingGroupMsg = loading; this.loadingGroupMsg = loading;
if (!this.getters.isLoading()) { if (!this.isLoading()) {
this.commit("refreshChats") this.refreshChats();
} }
}, },
refreshChats(state) { refreshChats() {
if (!cacheChats) { if (!cacheChats) {
return; return;
} }
@ -327,21 +346,22 @@ export default {
return chat2.lastSendTime - chat1.lastSendTime; return chat2.lastSendTime - chat1.lastSendTime;
}); });
// 将消息一次性装载回来 // 将消息一次性装载回来
state.chats = cacheChats; this.chats = cacheChats;
// 清空缓存 // 清空缓存
cacheChats = null; cacheChats = null;
this.commit("saveToStorage"); this.saveToStorage();
}, },
saveToStorage(state) { saveToStorage() {
// 加载中不保存,防止卡顿 // 加载中不保存,防止卡顿
if (this.getters.isLoading()) { if (this.isLoading()) {
return; return;
} }
let userId = userStore.state.userInfo.id; let userStore = useUserStore();
let userId = userStore.userInfo.id;
let key = "chats-" + userId; let key = "chats-" + userId;
let chatKeys = []; let chatKeys = [];
// 按会话为单位存储, // 按会话为单位存储,
state.chats.forEach((chat) => { this.chats.forEach((chat) => {
// 只存储有改动的会话 // 只存储有改动的会话
let chatKey = `${key}-${chat.type}-${chat.targetId}` let chatKey = `${key}-${chat.type}-${chat.targetId}`
if (!chat.stored) { if (!chat.stored) {
@ -358,32 +378,27 @@ export default {
}) })
// 会话核心信息 // 会话核心信息
let chatsData = { let chatsData = {
privateMsgMaxId: state.privateMsgMaxId, privateMsgMaxId: this.privateMsgMaxId,
groupMsgMaxId: state.groupMsgMaxId, groupMsgMaxId: this.groupMsgMaxId,
chatKeys: chatKeys chatKeys: chatKeys
} }
localForage.setItem(key, chatsData) localForage.setItem(key, chatsData)
// 清理已删除的会话 // 清理已删除的会话
state.chats = state.chats.filter(chat => !chat.delete) this.chats = this.chats.filter(chat => !chat.delete)
}, },
clear(state) { clear() {
cacheChats = [] cacheChats = []
state.chats = []; this.chats = [];
state.activeChat = null; this.activeChat = null;
}
}, },
actions: { loadChat() {
loadChat(context) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let userId = userStore.state.userInfo.id; let userStore = useUserStore();
let userId = userStore.userInfo.id;
let key = "chats-" + userId; let key = "chats-" + userId;
localForage.getItem(key).then((chatsData) => { localForage.getItem(key).then((chatsData) => {
if (!chatsData) { if (!chatsData) {
resolve(); resolve();
} else if (chatsData.chats) {
// 兼容旧版本
context.commit("initChats", chatsData);
resolve();
} else if (chatsData.chatKeys) { } else if (chatsData.chatKeys) {
const promises = []; const promises = [];
chatsData.chatKeys.forEach(key => { chatsData.chatKeys.forEach(key => {
@ -391,13 +406,13 @@ export default {
}) })
Promise.all(promises).then(chats => { Promise.all(promises).then(chats => {
chatsData.chats = chats.filter(o => o); chatsData.chats = chats.filter(o => o);
context.commit("initChats", chatsData); this.initChats(chatsData);
resolve(); resolve();
}) })
} }
}).catch((e) => { }).catch(e => {
console.log("加载消息失败") console.log("加载消息失败")
reject(); reject(e);
}) })
}) })
} }
@ -406,14 +421,14 @@ export default {
isLoading: (state) => () => { isLoading: (state) => () => {
return state.loadingPrivateMsg || state.loadingGroupMsg return state.loadingPrivateMsg || state.loadingGroupMsg
}, },
findChats: (state, getters) => () => { findChats: (state) => () => {
if (cacheChats && getters.isLoading()) { if (cacheChats && state.isLoading()) {
return cacheChats; return cacheChats;
} }
return state.chats; return state.chats;
}, },
findChatIdx: (state, getters) => (chat) => { findChatIdx: (state) => (chat) => {
let chats = getters.findChats(); let chats = state.findChats();
for (let idx in chats) { for (let idx in chats) {
if (chats[idx].type == chat.type && if (chats[idx].type == chat.type &&
chats[idx].targetId === chat.targetId) { chats[idx].targetId === chat.targetId) {
@ -422,18 +437,18 @@ export default {
} }
} }
}, },
findChat: (state, getters) => (chat) => { findChat: (state) => (chat) => {
let chats = getters.findChats(); let chats = state.findChats();
let idx = getters.findChatIdx(chat); let idx = state.findChatIdx(chat);
return chats[idx]; return chats[idx];
}, },
findChatByFriend: (state, getters) => (fid) => { findChatByFriend: (state) => (fid) => {
let chats = getters.findChats(); let chats = state.findChats();
return chats.find(chat => chat.type == 'PRIVATE' && return chats.find(chat => chat.type == 'PRIVATE' &&
chat.targetId == fid) chat.targetId == fid)
}, },
findChatByGroup: (state, getters) => (gid) => { findChatByGroup: (state) => (gid) => {
let chats = getters.findChats(); let chats = state.findChats();
return chats.find(chat => chat.type == 'GROUP' && return chats.find(chat => chat.type == 'GROUP' &&
chat.targetId == gid) chat.targetId == gid)
}, },
@ -454,4 +469,4 @@ export default {
} }
} }
} }
} });

25
im-web/src/store/configStore.js

@ -1,26 +1,24 @@
import { defineStore } from 'pinia';
import http from '../api/httpRequest.js' import http from '../api/httpRequest.js'
export default { export default defineStore('configStore', {
state: { state: () => {
return {
webrtc: {} webrtc: {}
},
mutations: {
setConfig(state, config) {
state.webrtc = config.webrtc;
},
clear(state) {
state.webrtc = {};
} }
}, },
actions: { actions: {
loadConfig(context) { setConfig(config) {
this.webrtc = config.webrtc;
},
loadConfig() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
http({ http({
url: '/system/config', url: '/system/config',
method: 'GET' method: 'GET'
}).then((config) => { }).then(config => {
console.log("系统配置", config) console.log("系统配置", config)
context.commit("setConfig", config); this.setConfig(config);
resolve(); resolve();
}).catch((res) => { }).catch((res) => {
reject(res); reject(res);
@ -28,5 +26,4 @@ export default {
}) })
} }
} }
});
}

115
im-web/src/store/friendStore.js

@ -1,101 +1,62 @@
import { defineStore } from 'pinia';
import http from '../api/httpRequest.js' import http from '../api/httpRequest.js'
import { TERMINAL_TYPE } from "../api/enums.js" import { TERMINAL_TYPE } from "../api/enums.js"
export default { export default defineStore('friendStore', {
state: () => {
state: { return {
friends: [], friends: [], // 好友列表
timer: null timer: null
}
}, },
mutations: { actions: {
setFriends(state, friends) { setFriends(friends) {
friends.forEach((f) => { this.friends = friends;
f.online = false;
f.onlineWeb = false;
f.onlineApp = false;
})
state.friends = friends;
}, },
updateFriend(state, friend) { updateFriend(friend) {
state.friends.forEach((f, index) => { this.friends.forEach((f, index) => {
if (f.id == friend.id) { if (f.id == friend.id) {
// 拷贝属性 // 拷贝属性
let online = state.friends[index].online; let online = this.friends[index].online;
Object.assign(state.friends[index], friend); Object.assign(this.friends[index], friend);
state.friends[index].online = online; this.friends[index].online = online;
} }
}) })
}, },
removeFriend(state, id) { removeFriend(id) {
state.friends.filter(f => f.id == id).forEach(f => f.deleted = true); this.friends.filter(f => f.id == id).forEach(f => f.deleted = true);
}, },
addFriend(state, friend) { addFriend(friend) {
if (state.friends.some((f) => f.id == friend.id)) { if (this.friends.some(f => f.id == friend.id)) {
this.commit("updateFriend", friend) this.updateFriend(friend)
} else { } else {
state.friends.unshift(friend); this.friends.unshift(friend);
} }
}, },
refreshOnlineStatus(state) { updateOnlineStatus(onlineData) {
let userIds = state.friends.filter((f) => !f.deleted).map((f) => f.id); let friend = this.findFriend(onlineData.userId);
if (userIds.length == 0) { if (onlineData.terminal == TERMINAL_TYPE.WEB) {
return; friend.onlineWeb = onlineData.online;
} else if (onlineData.terminal == TERMINAL_TYPE.APP) {
friend.onlineApp = onlineData.online;
} }
http({ friend.online = friend.onlineWeb || friend.onlineApp;
url: '/user/terminal/online',
method: 'get',
params: { userIds: userIds.join(',') }
}).then((onlineTerminals) => {
this.commit("setOnlineStatus", onlineTerminals);
})
// 30s后重新拉取
state.timer && clearTimeout(state.timer);
state.timer = setTimeout(() => {
this.commit("refreshOnlineStatus");
}, 30000)
}, },
setOnlineStatus(state, onlineTerminals) { clear() {
state.friends.forEach((f) => { this.timer && clearTimeout(this.timer);
let userTerminal = onlineTerminals.find((o) => f.id == o.userId); this.friends = [];
if (userTerminal) { this.timer = null;
f.online = true;
f.onlineWeb = userTerminal.terminals.indexOf(TERMINAL_TYPE.WEB) >= 0
f.onlineApp = userTerminal.terminals.indexOf(TERMINAL_TYPE.APP) >= 0
} else {
f.online = false;
f.onlineWeb = false;
f.onlineApp = false;
}
});
// 在线的在前面
state.friends.sort((f1, f2) => {
if (f1.online && !f2.online) {
return -1;
}
if (f2.online && !f1.online) {
return 1;
}
return 0;
});
},
clear(state) {
state.timer && clearTimeout(state.timer);
state.friends = [];
state.timer = null;
}
}, },
actions: { loadFriend() {
loadFriend(context) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
http({ http({
url: '/friend/list', url: '/friend/list',
method: 'GET' method: 'GET'
}).then((friends) => { }).then(async (friends) => {
context.commit("setFriends", friends); this.setFriends(friends);
context.commit("refreshOnlineStatus"); resolve();
resolve() }).catch(e => {
}).catch(() => { reject(e);
reject();
}) })
}); });
} }
@ -108,4 +69,4 @@ export default {
return state.friends.find((f) => f.id == userId); return state.friends.find((f) => f.id == userId);
} }
} }
} });

60
im-web/src/store/groupStore.js

@ -1,53 +1,63 @@
import { defineStore } from 'pinia';
import http from '../api/httpRequest.js' import http from '../api/httpRequest.js'
export default { export default defineStore('groupStore', {
state: { state: () => {
return {
groups: [] groups: []
}
}, },
mutations: { actions: {
setGroups(state, groups) { setGroups(groups) {
state.groups = groups; this.groups = groups;
}, },
addGroup(state, group) { addGroup(group) {
if (state.groups.some((g) => g.id == group.id)) { if (this.groups.some(g => g.id == group.id)) {
this.commit("updateGroup", group) this.updateGroup(group)
} else { } else {
state.groups.unshift(group); this.groups.unshift(group);
} }
}, },
removeGroup(state, id) { removeGroup(id) {
state.groups.filter(g => g.id == id).forEach(g => g.quit = true); this.groups.filter(g => g.id == id).forEach(g => g.quit = true);
}, },
updateGroup(state, group) { updateGroup(group) {
state.groups.forEach((g, idx) => { this.groups.forEach((g, idx) => {
if (g.id == group.id) { if (g.id == group.id) {
// 拷贝属性 // 拷贝属性
Object.assign(state.groups[idx], group); Object.assign(this.groups[idx], group);
} }
}) })
}, },
clear(state) { updateTopMessage(id, topMessage) {
state.groups = []; let group = this.findGroup(id);
if (group) {
group.topMessage = topMessage;
} }
}, },
actions: { clear() {
loadGroup(context) { this.groups = [];
},
loadGroup() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
http({ http({
url: '/group/list', url: '/group/list',
method: 'GET' method: 'GET'
}).then((groups) => { }).then(groups => {
context.commit("setGroups", groups); this.setGroups(groups);
resolve(); resolve();
}).catch((res) => { }).catch(e => {
reject(res); reject(e);
}) })
}); });
} }
}, },
getters: { getters: {
findGroup: (state) => (id) => { findGroup: (state) => (id) => {
return state.groups.find((g) => g.id == id); return state.groups.find(g => g.id == id);
} },
} isGroup: (state) => (id) => {
return state.groups.filter(g => !g.quit).some(g => g.id == id);
},
} }
});

11
im-web/src/store/uiStore.js

@ -1,5 +1,7 @@
export default { import { defineStore } from 'pinia';
state: { export default defineStore('groupStore', {
state: () => {
return {
userInfo: { // 用户信息窗口 userInfo: { // 用户信息窗口
show: false, show: false,
user: {}, user: {},
@ -12,8 +14,9 @@ export default {
show: false, show: false,
url: "" url: ""
} }
}
}, },
mutations: { actions: {
showUserInfoBox(state, user) { showUserInfoBox(state, user) {
state.userInfo.show = true; state.userInfo.show = true;
state.userInfo.user = user; state.userInfo.user = user;
@ -36,4 +39,4 @@ export default {
state.fullImage.show = false; state.fullImage.show = false;
} }
} }
} })

40
im-web/src/store/userStore.js

@ -1,45 +1,43 @@
import { defineStore } from 'pinia';
import http from '../api/httpRequest.js' import http from '../api/httpRequest.js'
import { RTC_STATE } from "../api/enums.js" import { RTC_STATE } from "../api/enums.js"
export default {
state: { export default defineStore('userStore', {
userInfo: { state: () => {
return {
}, userInfo: {},
rtcInfo: { rtcInfo: {
friend: {}, // 好友信息 friend: {}, // 好友信息
mode: "video", // 模式 video:视频 voice:语音 mode: "video", // 模式 video:视频 voice:语音
state: RTC_STATE.FREE // FREE:空闲 WAIT_CALL:呼叫方等待 WAIT_ACCEPT: 被呼叫方等待接听 CHATING:聊天中 state: RTC_STATE.FREE // FREE:空闲 WAIT_CALL:呼叫方等待 WAIT_ACCEPT: 被呼叫方等待接听 CHATING:聊天中
} }
}
}, },
actions: {
mutations: { setUserInfo(userInfo) {
setUserInfo(state, userInfo) { this.userInfo = userInfo
state.userInfo = userInfo
}, },
setRtcInfo(state, rtcInfo) { setRtcInfo(rtcInfo) {
state.rtcInfo = rtcInfo; this.rtcInfo = rtcInfo;
}, },
setRtcState(state, rtcState) { setRtcState(rtcState) {
state.rtcInfo.state = rtcState; this.rtcInfo.state = rtcState;
}, },
clear(state) { clear() {
state.userInfo = {}; this.userInfo = {};
state.rtcInfo = { this.rtcInfo = {
friend: {}, friend: {},
mode: "video", mode: "video",
state: RTC_STATE.FREE state: RTC_STATE.FREE
}; };
}
}, },
actions: { loadUser() {
loadUser(context) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
http({ http({
url: '/user/self', url: '/user/self',
method: 'GET' method: 'GET'
}).then((userInfo) => { }).then((userInfo) => {
context.commit("setUserInfo", userInfo); this.setUserInfo(userInfo);
resolve(); resolve();
}).catch((res) => { }).catch((res) => {
reject(res); reject(res);
@ -47,4 +45,4 @@ export default {
}) })
} }
} }
} });

9
im-web/src/view/Chat.vue

@ -43,19 +43,16 @@ export default {
}, },
methods: { methods: {
onActiveItem(index) { onActiveItem(index) {
this.$store.commit("activeChat", index); this.chatStore.setActiveChat(index);
}, },
onDelItem(index) { onDelItem(index) {
this.$store.commit("removeChat", index); this.chatStore.removeChat(index);
}, },
onTop(chatIdx) { onTop(chatIdx) {
this.$store.commit("moveTop", chatIdx); this.chatStore.moveTop(chatIdx);
}, },
}, },
computed: { computed: {
chatStore() {
return this.$store.state.chatStore;
},
loading() { loading() {
return this.chatStore.loadingGroupMsg || this.chatStore.loadingPrivateMsg return this.chatStore.loadingGroupMsg || this.chatStore.loadingPrivateMsg
} }

19
im-web/src/view/Friend.vue

@ -101,8 +101,8 @@ export default {
method: 'delete' method: 'delete'
}).then(() => { }).then(() => {
this.$message.success("删除好友成功"); this.$message.success("删除好友成功");
this.$store.commit("removeFriend", friend.id); this.friendStore.removeFriend(friend.id);
this.$store.commit("removePrivateChat", friend.id); this.chatStore.removePrivateChat(friend.id);
}) })
}) })
}, },
@ -121,7 +121,7 @@ export default {
headImage: user.headImage, headImage: user.headImage,
online: user.online online: user.online
} }
this.$store.commit("addFriend", friend); this.friendStore.addFriend(friend);
}) })
}, },
onSendMessage(user) { onSendMessage(user) {
@ -131,8 +131,8 @@ export default {
showName: user.nickName, showName: user.nickName,
headImage: user.headImageThumb, headImage: user.headImageThumb,
}; };
this.$store.commit("openChat", chat); this.chatStore.openChat(chat);
this.$store.commit("activeChat", 0); this.chatStore.setActiveChat(0);
this.$router.push("/home/chat"); this.$router.push("/home/chat");
}, },
showFullImage() { showFullImage() {
@ -146,8 +146,8 @@ export default {
let friend = JSON.parse(JSON.stringify(this.activeFriend)); let friend = JSON.parse(JSON.stringify(this.activeFriend));
friend.headImage = this.userInfo.headImageThumb; friend.headImage = this.userInfo.headImageThumb;
friend.nickName = this.userInfo.nickName; friend.nickName = this.userInfo.nickName;
this.$store.commit("updateChatFromFriend", friend); this.chatStore.updateChatFromFriend(friend);
this.$store.commit("updateFriend", friend); this.friendStore.updateFriend(friend);
} }
}, },
loadUserInfo(id) { loadUserInfo(id) {
@ -174,11 +174,8 @@ export default {
} }
}, },
computed: { computed: {
friendStore() {
return this.$store.state.friendStore;
},
isFriend() { isFriend() {
return this.$store.getters.isFriend(this.userInfo.id); return this.friendStore.isFriend(this.userInfo.id);
}, },
friendMap() { friendMap() {
// //

28
im-web/src/view/Group.vue

@ -50,7 +50,7 @@
</el-form-item> </el-form-item>
<el-form-item label="我在本群的昵称"> <el-form-item label="我在本群的昵称">
<el-input v-model="activeGroup.remarkNickName" maxlength="20" <el-input v-model="activeGroup.remarkNickName" maxlength="20"
:placeholder="$store.state.userStore.userInfo.nickName"></el-input> :placeholder="userStore.userInfo.nickName"></el-input>
</el-form-item> </el-form-item>
<el-form-item label="群公告"> <el-form-item label="群公告">
<el-input v-model="activeGroup.notice" :disabled="!isOwner" type="textarea" :rows="3" <el-input v-model="activeGroup.notice" :disabled="!isOwner" type="textarea" :rows="3"
@ -137,8 +137,7 @@ export default {
cancelButtonText: '取消', cancelButtonText: '取消',
inputPattern: /\S/, inputPattern: /\S/,
inputErrorMessage: '请输入群聊名称' inputErrorMessage: '请输入群聊名称'
}).then((o) => { }).then(o => {
let userInfo = this.$store.state.userStore.userInfo;
let data = { let data = {
name: o.value name: o.value
} }
@ -147,7 +146,9 @@ export default {
method: 'post', method: 'post',
data: data data: data
}).then((group) => { }).then((group) => {
this.$store.commit("addGroup", group); this.groupStore.addGroup(group);
this.onActiveItem(group)
this.$message.success('创建成功');
}) })
}) })
}, },
@ -195,7 +196,7 @@ export default {
method: "put", method: "put",
data: vo data: vo
}).then((group) => { }).then((group) => {
this.$store.commit("updateGroup", group); this.groupStore.updateGroup(group);
this.$message.success("修改成功"); this.$message.success("修改成功");
}) })
} }
@ -212,7 +213,7 @@ export default {
method: 'delete' method: 'delete'
}).then(() => { }).then(() => {
this.$message.success(`群聊'${this.activeGroup.name}'已解散`); this.$message.success(`群聊'${this.activeGroup.name}'已解散`);
this.$store.commit("removeGroup", this.activeGroup.id); this.groupStore.removeGroup(this.activeGroup.id);
this.reset(); this.reset();
}); });
}) })
@ -228,8 +229,8 @@ export default {
method: 'delete' method: 'delete'
}).then(() => { }).then(() => {
this.$message.success(`您已退出'${this.activeGroup.name}'`); this.$message.success(`您已退出'${this.activeGroup.name}'`);
this.$store.commit("removeGroup", this.activeGroup.id); this.groupStore.removeGroup(this.activeGroup.id);
this.$store.commit("removeGroupChat", this.activeGroup.id); this.chatStore.removeGroupChat(this.activeGroup.id);
this.reset(); this.reset();
}); });
}) })
@ -241,8 +242,8 @@ export default {
showName: this.activeGroup.showGroupName, showName: this.activeGroup.showGroupName,
headImage: this.activeGroup.headImage, headImage: this.activeGroup.headImage,
}; };
this.$store.commit("openChat", chat); this.chatStore.openChat(chat);
this.$store.commit("activeChat", 0); this.chatStore.setActiveChat(0);
this.$router.push("/home/chat"); this.$router.push("/home/chat");
}, },
onScroll(e) { onScroll(e) {
@ -280,15 +281,12 @@ export default {
} }
}, },
computed: { computed: {
groupStore() {
return this.$store.state.groupStore;
},
ownerName() { ownerName() {
let member = this.groupMembers.find((m) => m.userId == this.activeGroup.ownerId); let member = this.groupMembers.find(m => m.userId == this.activeGroup.ownerId);
return member && member.showNickName; return member && member.showNickName;
}, },
isOwner() { isOwner() {
return this.activeGroup.ownerId == this.$store.state.userStore.userInfo.id; return this.activeGroup.ownerId == this.userStore.userInfo.id;
}, },
imageAction() { imageAction() {
return `/image/upload`; return `/image/upload`;

107
im-web/src/view/Home.vue

@ -1,16 +1,14 @@
<template> <template>
<div class="home-page" @click="$store.commit('closeUserInfoBox')"> <div class="home-page" @click="uiStore.closeUserInfoBox()">
<div class="app-container" :class="{ fullscreen: isFullscreen }"> <div class="app-container" :class="{ fullscreen: isFullscreen }">
<div class="navi-bar"> <div class="navi-bar">
<div class="navi-bar-box"> <div class="navi-bar-box">
<div class="top"> <div class="top">
<div class="user-head-image"> <div class="user-head-image">
<head-image :name="$store.state.userStore.userInfo.nickName" :size="38" <head-image :name="userStore.userInfo.nickName" :size="38"
:url="$store.state.userStore.userInfo.headImageThumb" :url="userStore.userInfo.headImageThumb" @click.native="showSettingDialog = true">
@click.native="showSettingDialog = true">
</head-image> </head-image>
</div> </div>
<div class="menu"> <div class="menu">
<router-link class="link" v-bind:to="'/home/chat'"> <router-link class="link" v-bind:to="'/home/chat'">
<div class="menu-item"> <div class="menu-item">
@ -48,10 +46,10 @@
<router-view></router-view> <router-view></router-view>
</div> </div>
<setting :visible="showSettingDialog" @close="closeSetting()"></setting> <setting :visible="showSettingDialog" @close="closeSetting()"></setting>
<user-info v-show="uiStore.userInfo.show" :pos="uiStore.userInfo.pos" :user="uiStore.userInfo.user" <!-- <user-info v-show="uiStore.userInfo.show" :pos="uiStore.userInfo.pos" :user="uiStore.userInfo.user"
@close="$store.commit('closeUserInfoBox')"></user-info> @close="uiStore.closeUserInfoBox()"></user-info> -->
<full-image :visible="uiStore.fullImage.show" :url="uiStore.fullImage.url" <!-- <full-image :visible="uiStore.fullImage.show" :url="uiStore.fullImage.url"
@close="$store.commit('closeFullImageBox')"></full-image> @close="uiStore.closeFullImageBox()"></full-image> -->
<rtc-private-video ref="rtcPrivateVideo"></rtc-private-video> <rtc-private-video ref="rtcPrivateVideo"></rtc-private-video>
<rtc-group-video ref="rtcGroupVideo"></rtc-group-video> <rtc-group-video ref="rtcGroupVideo"></rtc-group-video>
</div> </div>
@ -66,6 +64,7 @@ import FullImage from '../components/common/FullImage.vue';
import RtcPrivateVideo from '../components/rtc/RtcPrivateVideo.vue'; import RtcPrivateVideo from '../components/rtc/RtcPrivateVideo.vue';
import RtcPrivateAcceptor from '../components/rtc/RtcPrivateAcceptor.vue'; import RtcPrivateAcceptor from '../components/rtc/RtcPrivateAcceptor.vue';
import RtcGroupVideo from '../components/rtc/RtcGroupVideo.vue'; import RtcGroupVideo from '../components/rtc/RtcGroupVideo.vue';
import uiStore from '../store/uiStore';
export default { export default {
components: { components: {
@ -96,7 +95,7 @@ export default {
this.$refs.rtcGroupVideo.open(rctInfo); this.$refs.rtcGroupVideo.open(rctInfo);
}); });
this.$store.dispatch("load").then(() => { this.loadStore().then(() => {
// ws // ws
this.$wsApi.connect(process.env.VUE_APP_WS_URL, sessionStorage.getItem("accessToken")); this.$wsApi.connect(process.env.VUE_APP_WS_URL, sessionStorage.getItem("accessToken"));
this.$wsApi.onConnect(() => { this.$wsApi.onConnect(() => {
@ -104,8 +103,8 @@ export default {
this.onReconnectWs(); this.onReconnectWs();
} else { } else {
// 线 // 线
this.pullPrivateOfflineMessage(this.$store.state.chatStore.privateMsgMaxId); this.pullPrivateOfflineMessage(this.chatStore.privateMsgMaxId);
this.pullGroupOfflineMessage(this.$store.state.chatStore.groupMsgMaxId); this.pullGroupOfflineMessage(this.chatStore.groupMsgMaxId);
} }
}); });
this.$wsApi.onMessage((cmd, msgInfo) => { this.$wsApi.onMessage((cmd, msgInfo) => {
@ -145,7 +144,7 @@ export default {
// //
this.reconnecting = true; this.reconnecting = true;
// token // token
this.$store.dispatch("loadUser").then(() => { this.userStore.loadUser().then(() => {
// 线 // 线
this.$message.error("连接断开,正在尝试重新连接..."); this.$message.error("连接断开,正在尝试重新连接...");
this.$wsApi.reconnect(process.env.VUE_APP_WS_URL, sessionStorage.getItem( this.$wsApi.reconnect(process.env.VUE_APP_WS_URL, sessionStorage.getItem(
@ -160,39 +159,55 @@ export default {
this.reconnecting = false; this.reconnecting = false;
// //
const promises = []; const promises = [];
promises.push(this.$store.dispatch("loadFriend")); promises.push(this.friendStore.loadFriend());
promises.push(this.$store.dispatch("loadGroup")); promises.push(this.groupStore.loadGroup());
Promise.all(promises).then(() => { Promise.all(promises).then(() => {
// 线 // 线
this.pullPrivateOfflineMessage(this.$store.state.chatStore.privateMsgMaxId); this.pullPrivateOfflineMessage(this.chatStore.privateMsgMaxId);
this.pullGroupOfflineMessage(this.$store.state.chatStore.groupMsgMaxId); this.pullGroupOfflineMessage(this.chatStore.groupMsgMaxId);
this.$message.success("重新连接成功"); this.$message.success("重新连接成功");
}).catch(() => { }).catch(() => {
this.$message.error("初始化失败"); this.$message.error("初始化失败");
this.onExit(); this.onExit();
}) })
}, },
loadStore() {
return this.userStore.loadUser().then(() => {
const promises = [];
promises.push(this.friendStore.loadFriend());
promises.push(this.groupStore.loadGroup());
promises.push(this.chatStore.loadChat());
promises.push(this.configStore.loadConfig());
return Promise.all(promises);
})
},
unloadStore() {
this.friendStore.clear();
this.groupStore.clear();
this.chatStore.clear();
this.userStore.clear();
},
pullPrivateOfflineMessage(minId) { pullPrivateOfflineMessage(minId) {
this.$store.commit("loadingPrivateMsg", true) this.chatStore.setLoadingPrivateMsg(true)
this.$http({ this.$http({
url: "/message/private/pullOfflineMessage?minId=" + minId, url: "/message/private/pullOfflineMessage?minId=" + minId,
method: 'GET' method: 'GET'
}).catch(() => { }).catch(() => {
this.$store.commit("loadingPrivateMsg", false) this.chatStore.setLoadingPrivateMsg(false)
}) })
}, },
pullGroupOfflineMessage(minId) { pullGroupOfflineMessage(minId) {
this.$store.commit("loadingGroupMsg", true) this.chatStore.setLoadingGroupMsg(true)
this.$http({ this.$http({
url: "/message/group/pullOfflineMessage?minId=" + minId, url: "/message/group/pullOfflineMessage?minId=" + minId,
method: 'GET' method: 'GET'
}).catch(() => { }).catch(() => {
this.$store.commit("loadingGroupMsg", false) this.chatStore.setLoadingGroupMsg(false)
}) })
}, },
handlePrivateMessage(msg) { handlePrivateMessage(msg) {
// //
msg.selfSend = msg.sendId == this.$store.state.userStore.userInfo.id; msg.selfSend = msg.sendId == this.userStore.userInfo.id;
// id // id
let friendId = msg.selfSend ? msg.recvId : msg.sendId; let friendId = msg.selfSend ? msg.recvId : msg.sendId;
// //
@ -202,34 +217,34 @@ export default {
} }
// //
if (msg.type == this.$enums.MESSAGE_TYPE.LOADING) { if (msg.type == this.$enums.MESSAGE_TYPE.LOADING) {
this.$store.commit("loadingPrivateMsg", JSON.parse(msg.content)) this.chatStore.setLoadingPrivateMsg(JSON.parse(msg.content))
return; return;
} }
// //
if (msg.type == this.$enums.MESSAGE_TYPE.READED) { if (msg.type == this.$enums.MESSAGE_TYPE.READED) {
this.$store.commit("resetUnreadCount", chatInfo) this.chatStore.resetUnreadCount(chatInfo)
return; return;
} }
// , // ,
if (msg.type == this.$enums.MESSAGE_TYPE.RECEIPT) { if (msg.type == this.$enums.MESSAGE_TYPE.RECEIPT) {
this.$store.commit("readedMessage", { this.chatStore.readedMessage({
friendId: msg.sendId friendId: msg.sendId
}) })
return; return;
} }
// //
if (msg.type == this.$enums.MESSAGE_TYPE.RECALL) { if (msg.type == this.$enums.MESSAGE_TYPE.RECALL) {
this.$store.commit("recallMessage", [msg, chatInfo]) this.chatStore.recallMessage(msg, chatInfo)
return; return;
} }
// //
if (msg.type == this.$enums.MESSAGE_TYPE.FRIEND_NEW) { if (msg.type == this.$enums.MESSAGE_TYPE.FRIEND_NEW) {
this.$store.commit("addFriend", JSON.parse(msg.content)); this.friendStore.addFriend(JSON.parse(msg.content));
return; return;
} }
// //
if (msg.type == this.$enums.MESSAGE_TYPE.FRIEND_DEL) { if (msg.type == this.$enums.MESSAGE_TYPE.FRIEND_DEL) {
this.$store.commit("removeFriend", friendId); this.friendStore.removeFriend(friendId);
return; return;
} }
// webrtc // webrtc
@ -251,9 +266,9 @@ export default {
headImage: friend.headImage headImage: friend.headImage
}; };
// //
this.$store.commit("openChat", chatInfo); this.chatStore.openChat(chatInfo);
// //
this.$store.commit("insertMessage", [msg, chatInfo]); this.chatStore.insertMessage(msg, chatInfo);
// //
if (!msg.selfSend && this.$msgType.isNormal(msg.type) && if (!msg.selfSend && this.$msgType.isNormal(msg.type) &&
msg.status != this.$enums.MESSAGE_STATUS.READED) { msg.status != this.$enums.MESSAGE_STATUS.READED) {
@ -262,20 +277,20 @@ export default {
}, },
handleGroupMessage(msg) { handleGroupMessage(msg) {
// //
msg.selfSend = msg.sendId == this.$store.state.userStore.userInfo.id; msg.selfSend = msg.sendId == this.userStore.userInfo.id;
let chatInfo = { let chatInfo = {
type: 'GROUP', type: 'GROUP',
targetId: msg.groupId targetId: msg.groupId
} }
// //
if (msg.type == this.$enums.MESSAGE_TYPE.LOADING) { if (msg.type == this.$enums.MESSAGE_TYPE.LOADING) {
this.$store.commit("loadingGroupMsg", JSON.parse(msg.content)) this.chatStore.setLoadingGroupMsg(JSON.parse(msg.content))
return; return;
} }
// //
if (msg.type == this.$enums.MESSAGE_TYPE.READED) { if (msg.type == this.$enums.MESSAGE_TYPE.READED) {
// //
this.$store.commit("resetUnreadCount", chatInfo) this.chatStore.resetUnreadCount(chatInfo)
return; return;
} }
// //
@ -287,22 +302,22 @@ export default {
readedCount: msg.readedCount, readedCount: msg.readedCount,
receiptOk: msg.receiptOk receiptOk: msg.receiptOk
}; };
this.$store.commit("updateMessage", [msgInfo, chatInfo]) this.chatStore.updateMessage(msgInfo, chatInfo)
return; return;
} }
// //
if (msg.type == this.$enums.MESSAGE_TYPE.RECALL) { if (msg.type == this.$enums.MESSAGE_TYPE.RECALL) {
this.$store.commit("recallMessage", [msg, chatInfo]) this.chatStore.recallMessage(msg, chatInfo)
return; return;
} }
// //
if (msg.type == this.$enums.MESSAGE_TYPE.GROUP_NEW) { if (msg.type == this.$enums.MESSAGE_TYPE.GROUP_NEW) {
this.$store.commit("addGroup", JSON.parse(msg.content)); this.chatStore.addGroup(JSON.parse(msg.content));
return; return;
} }
// //
if (msg.type == this.$enums.MESSAGE_TYPE.GROUP_DEL) { if (msg.type == this.$enums.MESSAGE_TYPE.GROUP_DEL) {
this.$store.commit("removeGroup", msg.groupId); this.groupStore.removeGroup(msg.groupId);
return; return;
} }
// //
@ -326,9 +341,9 @@ export default {
headImage: group.headImageThumb headImage: group.headImageThumb
}; };
// //
this.$store.commit("openChat", chatInfo); this.chatStore.openChat(chatInfo);
// //
this.$store.commit("insertMessage", [msg, chatInfo]); this.chatStore.insertMessage(msg, chatInfo);
// //
if (!msg.selfSend && msg.type <= this.$enums.MESSAGE_TYPE.VIDEO && if (!msg.selfSend && msg.type <= this.$enums.MESSAGE_TYPE.VIDEO &&
msg.status != this.$enums.MESSAGE_STATUS.READED) { msg.status != this.$enums.MESSAGE_STATUS.READED) {
@ -341,7 +356,7 @@ export default {
this.$wsApi.close(3000); this.$wsApi.close(3000);
this.$alert("您的账号已被管理员封禁,原因:" + msg.content, "账号被封禁", { this.$alert("您的账号已被管理员封禁,原因:" + msg.content, "账号被封禁", {
confirmButtonText: '确定', confirmButtonText: '确定',
callback: action => { callback: () => {
this.onExit(); this.onExit();
} }
}); });
@ -349,13 +364,14 @@ export default {
} }
}, },
onExit() { onExit() {
this.unloadStore();
this.$wsApi.close(3000); this.$wsApi.close(3000);
sessionStorage.removeItem("accessToken"); sessionStorage.removeItem("accessToken");
location.href = "/"; location.href = "/";
}, },
playAudioTip() { playAudioTip() {
// 线 // 线
if (this.$store.getters.isLoading()) { if (this.chatStore.isLoading()) {
return; return;
} }
// //
@ -375,7 +391,7 @@ export default {
this.showSettingDialog = false; this.showSettingDialog = false;
}, },
loadFriendInfo(id) { loadFriendInfo(id) {
let friend = this.$store.getters.findFriend(id); let friend = this.friendStore.findFriend(id);
if (!friend) { if (!friend) {
friend = { friend = {
id: id, id: id,
@ -386,7 +402,7 @@ export default {
return friend; return friend;
}, },
loadGroupInfo(id) { loadGroupInfo(id) {
let group = this.$store.getters.findGroup(id); let group = this.groupStore.findGroup(id);
if (!group) { if (!group) {
group = { group = {
id: id, id: id,
@ -398,12 +414,9 @@ export default {
} }
}, },
computed: { computed: {
uiStore() {
return this.$store.state.uiStore;
},
unreadCount() { unreadCount() {
let unreadCount = 0; let unreadCount = 0;
let chats = this.$store.state.chatStore.chats; let chats = this.chatStore.chats;
chats.forEach((chat) => { chats.forEach((chat) => {
if (!chat.delete) { if (!chat.delete) {
unreadCount += chat.unreadCount unreadCount += chat.unreadCount

Loading…
Cancel
Save