Browse Source

优化消息列表排序

master
xie.bx 2 years ago
parent
commit
5009eebf4b
  1. 4
      im-ui/src/App.vue
  2. 2
      im-ui/src/components/chat/ChatPrivateVideo.vue
  3. 3
      im-ui/src/components/common/RightMenu.vue
  4. 39
      im-ui/src/components/group/AddGroupMember.vue
  5. 58
      im-ui/src/store/chatStore.js
  6. 27
      im-ui/src/store/friendStore.js
  7. 19
      im-ui/src/store/groupStore.js
  8. 19
      im-ui/src/view/Chat.vue
  9. 23
      im-ui/src/view/Friend.vue
  10. 11
      im-ui/src/view/Group.vue
  11. 1
      im-ui/src/view/Register.vue

4
im-ui/src/App.vue

@ -26,4 +26,8 @@ export default {
height: 100%; height: 100%;
width: 100%; width: 100%;
} }
.el-message {
z-index: 99999999 !important;
}
</style> </style>

2
im-ui/src/components/chat/ChatPrivateVideo.vue

@ -67,7 +67,7 @@
methods: { methods: {
init() { init() {
if (!this.hasUserMedia() || !this.hasRTCPeerConnection()) { if (!this.hasUserMedia() || !this.hasRTCPeerConnection()) {
this.$message.error("您的浏览器不支持WebRTC"); this.$message.error("初始化失败,原因可能是: 1.未部署ssl证书 2.您的浏览器不支持WebRTC");
if (!this.master) { if (!this.master) {
this.sendFailed("对方浏览器不支持WebRTC") this.sendFailed("对方浏览器不支持WebRTC")
} }

3
im-ui/src/components/common/RightMenu.vue

@ -3,7 +3,7 @@
<div class="right-menu" :style="{'left':pos.x+'px','top':pos.y+'px'}"> <div class="right-menu" :style="{'left':pos.x+'px','top':pos.y+'px'}">
<el-menu text-color="#333333"> <el-menu text-color="#333333">
<el-menu-item v-for="(item) in items" :key="item.key" :title="item.name" <el-menu-item v-for="(item) in items" :key="item.key" :title="item.name"
@click="onSelectMenu(item)"> @click.native.stop="onSelectMenu(item)">
<span :class="item.icon"></span> <span :class="item.icon"></span>
<span>{{item.name}}</span> <span>{{item.name}}</span>
@ -33,6 +33,7 @@
}, },
onSelectMenu(item) { onSelectMenu(item) {
this.$emit("select", item); this.$emit("select", item);
this.close();
} }
} }
} }

39
im-ui/src/components/group/AddGroupMember.vue

@ -2,26 +2,28 @@
<el-dialog title="邀请好友" :visible.sync="visible" width="50%" :before-close="onClose"> <el-dialog title="邀请好友" :visible.sync="visible" width="50%" :before-close="onClose">
<div class="agm-container"> <div class="agm-container">
<div class="agm-l-box"> <div class="agm-l-box">
<el-input width="200px" placeholder="搜索好友" class="input-with-select" v-model="searchText" @keyup.enter.native="onSearch()"> <el-input width="200px" placeholder="搜索好友" class="input-with-select" v-model="searchText"
@keyup.enter.native="onSearch()">
<el-button slot="append" icon="el-icon-search" @click="onSearch()"></el-button> <el-button slot="append" icon="el-icon-search" @click="onSearch()"></el-button>
</el-input> </el-input>
<el-scrollbar style="height:400px;"> <el-scrollbar style="height:400px;">
<div v-for="(friend,index) in friends" :key="friend.id"> <div v-for="(friend,index) in friends" :key="friend.id">
<friend-item v-show="friend.nickName.startsWith(searchText)" :showDelete="false" @click.native="onSwitchCheck(friend)" <friend-item v-show="friend.nickName.startsWith(searchText)" :showDelete="false"
:menu="false" :friend="friend" :index="index" :active="index === activeIndex"> @click.native="onSwitchCheck(friend)" :menu="false" :friend="friend" :index="index"
<el-checkbox :disabled="friend.disabled" @click.native.stop="" class="agm-friend-checkbox" v-model="friend.isCheck" :active="false">
size="medium"></el-checkbox> <el-checkbox :disabled="friend.disabled" @click.native.stop="" class="agm-friend-checkbox"
v-model="friend.isCheck" size="medium"></el-checkbox>
</friend-item> </friend-item>
</div> </div>
</el-scrollbar> </el-scrollbar>
</div> </div>
<div class="agm-arrow el-icon-d-arrow-right"></div>
<div class="agm-r-box"> <div class="agm-r-box">
<div class="agm-select-tip"> 已勾选{{checkCount}}位好友</div> <div class="agm-select-tip"> 已勾选{{checkCount}}位好友</div>
<el-scrollbar style="height:400px;"> <el-scrollbar style="height:400px;">
<div v-for="(friend,index) in friends" :key="friend.id"> <div v-for="(friend,index) in friends" :key="friend.id">
<friend-item v-if="friend.isCheck && !friend.disabled" :friend="friend" <friend-item v-if="friend.isCheck && !friend.disabled" :friend="friend" :index="index"
:index="index" :active="false" @del="onRemoveFriend(friend,index)" :active="false" @del="onRemoveFriend(friend,index)" :menu="false">
:menu="false">
</friend-item> </friend-item>
</div> </div>
</el-scrollbar> </el-scrollbar>
@ -45,7 +47,6 @@
data() { data() {
return { return {
searchText: "", searchText: "",
activeIndex: -1,
friends: [] friends: []
} }
}, },
@ -130,11 +131,11 @@
<style lang="scss"> <style lang="scss">
.agm-container { .agm-container {
display: flex; display: flex;
.agm-l-box { .agm-l-box {
flex: 1; flex: 1;
border: #dddddd solid 1px; border: #53a0e79c solid 1px;
border-radius: 5px;
overflow: hidden;
.el-checkbox { .el-checkbox {
display: flex; display: flex;
align-items: center; align-items: center;
@ -164,14 +165,22 @@
.agm-friend-checkbox { .agm-friend-checkbox {
margin-right: 20px; margin-right: 20px;
} }
} }
.agm-arrow {
display: flex;
align-items: center;
font-size: 20px;
padding: 5px;
font-weight: 600;
color: #53a0e7cc;
}
.agm-r-box { .agm-r-box {
flex: 1; flex: 1;
border: #dddddd solid 1px; border: #53a0e79c solid 1px;
border-radius: 5px;
.agm-select-tip { .agm-select-tip {
text-align: left; text-align: left;

58
im-ui/src/store/chatStore.js

@ -6,7 +6,7 @@ import userStore from './userStore';
export default { export default {
state: { state: {
activeIndex: -1, activeChat: null,
privateMsgMaxId: 0, privateMsgMaxId: 0,
groupMsgMaxId: 0, groupMsgMaxId: 0,
loadingPrivateMsg: false, loadingPrivateMsg: false,
@ -30,14 +30,12 @@ export default {
}, },
openChat(state, chatInfo) { openChat(state, chatInfo) {
let chat = null; let chat = null;
let activeChat = state.activeIndex >= 0 ? state.chats[state.activeIndex] : null; for (let idx in state.chats) {
for (let i in state.chats) { if (state.chats[idx].type == chatInfo.type &&
if (state.chats[i].type == chatInfo.type && state.chats[idx].targetId === chatInfo.targetId) {
state.chats[i].targetId === chatInfo.targetId) { chat = state.chats[idx];
chat = state.chats[i];
// 放置头部 // 放置头部
state.chats.splice(i, 1); this.commit("moveTop", idx)
state.chats.unshift(chat);
break; break;
} }
} }
@ -55,18 +53,9 @@ export default {
}; };
state.chats.unshift(chat); state.chats.unshift(chat);
} }
// 选中会话保持不变
if (activeChat) {
state.chats.forEach((chat, idx) => {
if (activeChat.type == chat.type &&
activeChat.targetId == chat.targetId) {
state.activeIndex = idx;
}
})
}
}, },
activeChat(state, idx) { activeChat(state, idx) {
state.activeIndex = idx; state.activeChat = state.chats[idx];
}, },
resetUnreadCount(state, chatInfo) { resetUnreadCount(state, chatInfo) {
for (let idx in state.chats) { for (let idx in state.chats) {
@ -93,18 +82,23 @@ export default {
this.commit("saveToStorage"); this.commit("saveToStorage");
}, },
removeChat(state, idx) { removeChat(state, idx) {
state.chats.splice(idx, 1); if (state.chats[idx] == state.activeChat) {
if (state.activeIndex >= state.chats.length) { state.activeChat = null;
state.activeIndex = state.chats.length - 1;
} }
state.chats.splice(idx, 1);
this.commit("saveToStorage"); this.commit("saveToStorage");
}, },
moveTop(state, idx) { moveTop(state, idx) {
// 加载中不移动,很耗性能
if(state.loadingPrivateMsg || state.loadingGroupMsg){
return ;
}
if (idx > 0) {
let chat = state.chats[idx]; let chat = state.chats[idx];
// 放置头部
state.chats.splice(idx, 1); state.chats.splice(idx, 1);
state.chats.unshift(chat); state.chats.unshift(chat);
this.commit("saveToStorage"); this.commit("saveToStorage");
}
}, },
removeGroupChat(state, groupId) { removeGroupChat(state, groupId) {
for (let idx in state.chats) { for (let idx in state.chats) {
@ -131,6 +125,7 @@ export default {
if (state.chats[idx].type == type && if (state.chats[idx].type == type &&
state.chats[idx].targetId === targetId) { state.chats[idx].targetId === targetId) {
chat = state.chats[idx]; chat = state.chats[idx];
this.commit("moveTop", idx)
break; break;
} }
} }
@ -151,13 +146,13 @@ export default {
chat.unreadCount++; chat.unreadCount++;
} }
// 是否有人@我 // 是否有人@我
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 userId = userStore.state.userInfo.id;
if(msgInfo.atUserIds.indexOf(userId)>=0){ if (msgInfo.atUserIds.indexOf(userId) >= 0) {
chat.atMe = true; chat.atMe = true;
} }
if(msgInfo.atUserIds.indexOf(-1)>=0){ if (msgInfo.atUserIds.indexOf(-1) >= 0) {
chat.atAll = true; chat.atAll = true;
} }
} }
@ -248,9 +243,18 @@ export default {
loadingPrivateMsg(state, loadding) { loadingPrivateMsg(state, loadding) {
state.loadingPrivateMsg = loadding; state.loadingPrivateMsg = loadding;
if(!state.loadingPrivateMsg && !state.loadingGroupMsg){
this.commit("sort")
}
}, },
loadingGroupMsg(state, loadding) { loadingGroupMsg(state, loadding) {
state.loadingGroupMsg = loadding; state.loadingGroupMsg = loadding;
if(!state.loadingPrivateMsg && !state.loadingGroupMsg){
this.commit("sort")
}
},
sort(state){
state.chats.sort((c1,c2)=>c2.lastSendTime-c1.lastSendTime);
}, },
saveToStorage(state) { saveToStorage(state) {
let userId = userStore.state.userInfo.id; let userId = userStore.state.userInfo.id;
@ -263,7 +267,7 @@ export default {
localStorage.setItem(key, JSON.stringify(chatsData)); localStorage.setItem(key, JSON.stringify(chatsData));
}, },
clear(state) { clear(state) {
state.activeIndex = -1; state.activeChat = null;
state.chats = []; state.chats = [];
} }
}, },

27
im-ui/src/store/friendStore.js

@ -5,7 +5,7 @@ export default {
state: { state: {
friends: [], friends: [],
activeIndex: -1, activeFriend: null,
timer: null timer: null
}, },
mutations: { mutations: {
@ -22,12 +22,14 @@ export default {
} }
}) })
}, },
activeFriend(state, index) { activeFriend(state, idx) {
state.activeIndex = index; state.activeFriend = state.friends[idx];
}, },
removeFriend(state, index) { removeFriend(state, idx) {
state.friends.splice(index, 1); if (state.friends[idx] == state.activeFriend) {
state.activeIndex = -1; state.activeFriend = null;
}
state.friends.splice(idx, 1);
}, },
addFriend(state, friend) { addFriend(state, friend) {
state.friends.push(friend); state.friends.push(friend);
@ -67,7 +69,7 @@ export default {
f.onlineApp = false; f.onlineApp = false;
} }
}); });
let activeFriend = state.friends[state.activeIndex]; // 在线的在前面
state.friends.sort((f1,f2)=>{ state.friends.sort((f1,f2)=>{
if(f1.online&&!f2.online){ if(f1.online&&!f2.online){
return -1; return -1;
@ -77,21 +79,12 @@ export default {
} }
return 0; return 0;
}); });
// 重新排序后,activeIndex指向的好友可能会变化,需要重新指定
if(state.activeIndex >=0){
state.friends.forEach((f,i)=>{
if(f.id == activeFriend.id){
state.activeIndex = i;
}
})
}
}, },
clear(state) { clear(state) {
clearTimeout(state.timer); clearTimeout(state.timer);
state.friends = []; state.friends = [];
state.timer = null; state.timer = null;
state.activeIndex = -1; state.activeFriend = [];
} }
}, },
actions: { actions: {

19
im-ui/src/store/groupStore.js

@ -4,26 +4,27 @@ export default {
state: { state: {
groups: [], groups: [],
activeIndex: -1, activeGroup: null,
}, },
mutations: { mutations: {
setGroups(state, groups) { setGroups(state, groups) {
state.groups = groups; state.groups = groups;
}, },
activeGroup(state, index) { activeGroup(state, idx) {
state.activeIndex = index; state.activeGroup = state.groups[idx];
}, },
addGroup(state, group) { addGroup(state, group) {
state.groups.unshift(group); state.groups.unshift(group);
}, },
removeGroup(state, groupId) { removeGroup(state, groupId) {
state.groups.forEach((g, index) => { state.groups.forEach((g, idx) => {
if (g.id == groupId) { if (g.id == groupId) {
state.groups.splice(index, 1); state.groups.splice(idx, 1);
state.activeIndex = -1;
} }
}) })
if (state.activeGroup.id == groupId) {
state.activeGroup = null;
}
}, },
updateGroup(state, group) { updateGroup(state, group) {
state.groups.forEach((g, idx) => { state.groups.forEach((g, idx) => {
@ -33,9 +34,9 @@ export default {
} }
}) })
}, },
clear(state){ clear(state) {
state.groups = []; state.groups = [];
state.activeGroup = -1; state.activeGroup = null;
} }
}, },
actions: { actions: {

19
im-ui/src/view/Chat.vue

@ -14,12 +14,12 @@
<div v-for="(chat,index) in chatStore.chats" :key="index"> <div v-for="(chat,index) in chatStore.chats" :key="index">
<chat-item v-show="chat.showName.startsWith(searchText)" :chat="chat" :index="index" <chat-item v-show="chat.showName.startsWith(searchText)" :chat="chat" :index="index"
@click.native="onActiveItem(index)" @delete="onDelItem(index)" @top="onTop(index)" @click.native="onActiveItem(index)" @delete="onDelItem(index)" @top="onTop(index)"
:active="index === chatStore.activeIndex"></chat-item> :active="chat === chatStore.activeChat"></chat-item>
</div> </div>
</el-scrollbar> </el-scrollbar>
</el-aside> </el-aside>
<el-container class="chat-box"> <el-container class="chat-box">
<chat-box v-show="activeChat.targetId>0" :chat="activeChat"></chat-box> <chat-box v-if="chatStore.activeChat" :chat="chatStore.activeChat"></chat-box>
</el-container> </el-container>
</el-container> </el-container>
</template> </template>
@ -57,21 +57,6 @@
chatStore() { chatStore() {
return this.$store.state.chatStore; return this.$store.state.chatStore;
}, },
activeChat() {
let index = this.chatStore.activeIndex;
let chats = this.chatStore.chats
if (index >= 0 && chats.length > 0) {
return chats[index];
}
//
let emptyChat = {
targetId: -1,
showName: "",
headImage: "",
messages: []
}
return emptyChat;
},
loading(){ loading(){
return this.chatStore.loadingGroupMsg || this.chatStore.loadingPrivateMsg return this.chatStore.loadingGroupMsg || this.chatStore.loadingPrivateMsg
} }

23
im-ui/src/view/Friend.vue

@ -15,7 +15,7 @@
<el-scrollbar class="friend-list-items"> <el-scrollbar class="friend-list-items">
<div v-for="(friend,index) in $store.state.friendStore.friends" :key="index"> <div v-for="(friend,index) in $store.state.friendStore.friends" :key="index">
<friend-item v-show="friend.nickName.startsWith(searchText)" :index="index" <friend-item v-show="friend.nickName.startsWith(searchText)" :index="index"
:active="index === $store.state.friendStore.activeIndex" @chat="onSendMessage(friend)" :active="friend === $store.state.friendStore.activeFriend" @chat="onSendMessage(friend)"
@delete="onDelItem(friend,index)" @click.native="onActiveItem(friend,index)"> @delete="onDelItem(friend,index)" @click.native="onActiveItem(friend,index)">
</friend-item> </friend-item>
</div> </div>
@ -46,7 +46,7 @@
<div class="frient-btn-group"> <div class="frient-btn-group">
<el-button v-show="isFriend" icon="el-icon-chat-dot-round" type="primary" @click="onSendMessage(userInfo)">发送消息</el-button> <el-button v-show="isFriend" icon="el-icon-chat-dot-round" type="primary" @click="onSendMessage(userInfo)">发送消息</el-button>
<el-button v-show="!isFriend" icon="el-icon-plus" type="primary" @click="onAddFriend(userInfo)">加为好友</el-button> <el-button v-show="!isFriend" icon="el-icon-plus" type="primary" @click="onAddFriend(userInfo)">加为好友</el-button>
<el-button v-show="isFriend" icon="el-icon-delete" type="danger" @click="onDelItem(userInfo,friendStore.activeIndex)">删除好友</el-button> <el-button v-show="isFriend" icon="el-icon-delete" type="danger" @click="onDelItem(userInfo,activeIdx)">删除好友</el-button>
</div> </div>
</div> </div>
</div> </div>
@ -74,6 +74,7 @@
return { return {
searchText: "", searchText: "",
showAddFriend: false, showAddFriend: false,
activeIdx: -1,
userInfo: {} userInfo: {}
} }
}, },
@ -84,11 +85,12 @@
onCloseAddFriend() { onCloseAddFriend() {
this.showAddFriend = false; this.showAddFriend = false;
}, },
onActiveItem(friend, index) { onActiveItem(friend, idx) {
this.$store.commit("activeFriend", index); this.$store.commit("activeFriend", idx);
this.loadUserInfo(friend, index); this.activeIdx = idx
this.loadUserInfo(friend, idx);
}, },
onDelItem(friend, index) { onDelItem(friend, idx) {
this.$confirm(`确认要解除与 '${friend.nickName}'的好友关系吗?`, '确认解除?', { this.$confirm(`确认要解除与 '${friend.nickName}'的好友关系吗?`, '确认解除?', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
@ -99,7 +101,7 @@
method: 'delete' method: 'delete'
}).then((data) => { }).then((data) => {
this.$message.success("删除好友成功"); this.$message.success("删除好友成功");
this.$store.commit("removeFriend", index); this.$store.commit("removeFriend", idx);
this.$store.commit("removePrivateChat", friend.id); this.$store.commit("removePrivateChat", friend.id);
}) })
}) })
@ -173,14 +175,7 @@
isFriend(){ isFriend(){
return this.friendStore.friends.find((f)=>f.id==this.userInfo.id); return this.friendStore.friends.find((f)=>f.id==this.userInfo.id);
} }
},
mounted() {
if (this.friendStore.activeIndex >= 0) {
let friend = this.friendStore.friends[this.friendStore.activeIndex];
this.loadUserInfo(friend, this.friendStore.activeIndex);
}
} }
} }
</script> </script>

11
im-ui/src/view/Group.vue

@ -13,7 +13,7 @@
<el-scrollbar class="group-list-items"> <el-scrollbar class="group-list-items">
<div v-for="(group,index) in groupStore.groups" :key="index"> <div v-for="(group,index) in groupStore.groups" :key="index">
<group-item v-show="group.remark.startsWith(searchText)" :group="group" <group-item v-show="group.remark.startsWith(searchText)" :group="group"
:active="index === groupStore.activeIndex" @click.native="onActiveItem(group,index)"> :active="group === groupStore.activeGroup" @click.native="onActiveItem(group,index)">
</group-item> </group-item>
</div> </div>
</el-scrollbar> </el-scrollbar>
@ -269,15 +269,6 @@
imageAction() { imageAction() {
return `/image/upload`; return `/image/upload`;
} }
},
mounted() {
if (this.groupStore.activeIndex >= 0) {
let activeGroup = this.groupStore.groups[this.groupStore.activeIndex];
// store
this.activeGroup = JSON.parse(JSON.stringify(activeGroup));
//
this.loadGroupMembers();
}
} }
} }
</script> </script>

1
im-ui/src/view/Register.vue

@ -56,7 +56,6 @@
}; };
var checkConfirmPassword = (rule, value, callback) => { var checkConfirmPassword = (rule, value, callback) => {
console.log("checkConfirmPassword");
if (value === '') { if (value === '') {
return callback(new Error('请输入密码')); return callback(new Error('请输入密码'));
} }

Loading…
Cancel
Save