Browse Source

!58 APP卡顿问题优化

Merge pull request !58 from blue/v_2.0.0
master
blue 2 years ago
committed by Gitee
parent
commit
57f29b00d5
No known key found for this signature in database GPG Key ID: 173E9B9CA92EEF8F
  1. 47
      im-client/src/main/java/com/bx/imclient/sender/IMSender.java
  2. 2
      im-platform/src/main/java/com/bx/implatform/controller/GroupMessageController.java
  3. 2
      im-platform/src/main/java/com/bx/implatform/controller/PrivateMessageController.java
  4. 3
      im-platform/src/main/java/com/bx/implatform/service/impl/GroupMessageServiceImpl.java
  5. 6
      im-platform/src/main/java/com/bx/implatform/service/impl/PrivateMessageServiceImpl.java
  6. 9
      im-platform/src/main/java/com/bx/implatform/util/SensitiveFilterUtil.java
  7. 2
      im-ui/src/components/common/HeadImage.vue
  8. 7
      im-ui/src/store/chatStore.js
  9. 2
      im-ui/src/view/Login.vue
  10. 37
      im-uniapp/App.vue
  11. 2
      im-uniapp/common/emotion.js
  12. 24
      im-uniapp/components/chat-item/chat-item.vue
  13. 25
      im-uniapp/components/chat-message-item/chat-message-item.vue
  14. 21
      im-uniapp/components/chat-record/chat-record.vue
  15. 4
      im-uniapp/components/head-image/head-image.vue
  16. 3
      im-uniapp/components/pop-menu/pop-menu.vue
  17. 118
      im-uniapp/components/user-search/user-search.vue
  18. 3
      im-uniapp/package.json
  19. 2
      im-uniapp/pages.json
  20. 38
      im-uniapp/pages/chat/chat-box.vue
  21. 88
      im-uniapp/pages/chat/chat.vue
  22. 5
      im-uniapp/pages/common/user-info.vue
  23. 2
      im-uniapp/pages/friend/friend-add.vue
  24. 5
      im-uniapp/pages/friend/friend-search.vue
  25. 17
      im-uniapp/pages/friend/friend.vue
  26. 3
      im-uniapp/pages/group/group-info.vue
  27. 3
      im-uniapp/pages/group/group-invite.vue
  28. 6
      im-uniapp/pages/group/group.vue
  29. 261
      im-uniapp/store/chatStore.js
  30. 55
      im-uniapp/store/friendStore.js

47
im-client/src/main/java/com/bx/imclient/sender/IMSender.java

@ -30,30 +30,33 @@ public class IMSender {
public<T> void sendPrivateMessage(IMPrivateMessage<T> message) {
List<IMSendResult> results = new LinkedList<>();
for (Integer terminal : message.getRecvTerminals()) {
// 获取对方连接的channelId
String key = String.join(":", IMRedisKey.IM_USER_SERVER_ID, message.getRecvId().toString(), terminal.toString());
Integer serverId = (Integer)redisTemplate.opsForValue().get(key);
// 如果对方在线,将数据存储至redis,等待拉取推送
if (serverId != null) {
String sendKey = String.join(":", IMRedisKey.IM_MESSAGE_PRIVATE_QUEUE, serverId.toString());
IMRecvInfo recvInfo = new IMRecvInfo();
recvInfo.setCmd(IMCmdType.PRIVATE_MESSAGE.code());
recvInfo.setSendResult(message.getSendResult());
recvInfo.setServiceName(appName);
recvInfo.setSender(message.getSender());
recvInfo.setReceivers(Collections.singletonList(new IMUserInfo(message.getRecvId(), terminal)));
recvInfo.setData(message.getData());
redisTemplate.opsForList().rightPush(sendKey, recvInfo);
} else {
IMSendResult result = new IMSendResult();
result.setSender(message.getSender());
result.setReceiver(new IMUserInfo(message.getRecvId(), terminal));
result.setCode(IMSendCode.NOT_ONLINE.code());
result.setData(message.getData());
results.add(result);
if(!Objects.isNull(message.getRecvId())){
for (Integer terminal : message.getRecvTerminals()) {
// 获取对方连接的channelId
String key = String.join(":", IMRedisKey.IM_USER_SERVER_ID, message.getRecvId().toString(), terminal.toString());
Integer serverId = (Integer)redisTemplate.opsForValue().get(key);
// 如果对方在线,将数据存储至redis,等待拉取推送
if (serverId != null) {
String sendKey = String.join(":", IMRedisKey.IM_MESSAGE_PRIVATE_QUEUE, serverId.toString());
IMRecvInfo recvInfo = new IMRecvInfo();
recvInfo.setCmd(IMCmdType.PRIVATE_MESSAGE.code());
recvInfo.setSendResult(message.getSendResult());
recvInfo.setServiceName(appName);
recvInfo.setSender(message.getSender());
recvInfo.setReceivers(Collections.singletonList(new IMUserInfo(message.getRecvId(), terminal)));
recvInfo.setData(message.getData());
redisTemplate.opsForList().rightPush(sendKey, recvInfo);
} else {
IMSendResult result = new IMSendResult();
result.setSender(message.getSender());
result.setReceiver(new IMUserInfo(message.getRecvId(), terminal));
result.setCode(IMSendCode.NOT_ONLINE.code());
result.setData(message.getData());
results.add(result);
}
}
}
// 推送给自己的其他终端
if(message.getSendToSelf()){
for (Integer terminal : IMTerminalType.codes()) {

2
im-platform/src/main/java/com/bx/implatform/controller/GroupMessageController.java

@ -37,7 +37,7 @@ public class GroupMessageController {
@GetMapping("/loadMessage")
@ApiOperation(value = "拉取消息", notes = "拉取消息,一次最多拉取100条")
@ApiOperation(value = "拉取消息(已废弃)", notes = "拉取消息,一次最多拉取100条")
public Result<List<GroupMessageVO>> loadMessage(@RequestParam Long minId) {
return ResultUtils.success(groupMessageService.loadMessage(minId));
}

2
im-platform/src/main/java/com/bx/implatform/controller/PrivateMessageController.java

@ -38,7 +38,7 @@ public class PrivateMessageController {
@GetMapping("/loadMessage")
@ApiOperation(value = "拉取消息", notes = "拉取消息,一次最多拉取100条")
@ApiOperation(value = "拉取消息(已废弃)", notes = "拉取消息,一次最多拉取100条")
public Result<List<PrivateMessageVO>> loadMessage(@RequestParam Long minId) {
return ResultUtils.success(privateMessageService.loadMessage(minId));
}

3
im-platform/src/main/java/com/bx/implatform/service/impl/GroupMessageServiceImpl.java

@ -206,12 +206,13 @@ public class GroupMessageServiceImpl extends ServiceImpl<GroupMessageMapper, Gro
if(!imClient.isOnline(session.getUserId())){
throw new GlobalException(ResultCode.PROGRAM_ERROR, "网络连接失败,无法拉取离线消息");
}
// 查询用户加入的群组
List<GroupMember> members = groupMemberService.findByUserId(session.getUserId());
Map<Long, GroupMember> groupMemberMap = CollStreamUtil.toIdentityMap(members, GroupMember::getGroupId);
Set<Long> groupIds = groupMemberMap.keySet();
if(CollectionUtil.isEmpty(groupIds)){
// 关闭加载中标志
this.sendLoadingMessage(false);
return;
}
// 开启加载中标志

6
im-platform/src/main/java/com/bx/implatform/service/impl/PrivateMessageServiceImpl.java

@ -182,10 +182,11 @@ public class PrivateMessageServiceImpl extends ServiceImpl<PrivateMessageMapper,
if(!imClient.isOnline(session.getUserId())){
throw new GlobalException(ResultCode.PROGRAM_ERROR, "网络连接失败,无法拉取离线消息");
}
// 查询用户好友列表
List<Friend> friends = friendService.findFriendByUserId(session.getUserId());
if (friends.isEmpty()) {
// 关闭加载中标志
this.sendLoadingMessage(false);
return;
}
// 开启加载中标志
@ -237,8 +238,7 @@ public class PrivateMessageServiceImpl extends ServiceImpl<PrivateMessageMapper,
IMPrivateMessage<PrivateMessageVO> sendMessage = new IMPrivateMessage<>();
sendMessage.setData(msgInfo);
sendMessage.setSender(new IMUserInfo(session.getUserId(), session.getTerminal()));
sendMessage.setRecvId(session.getUserId());
sendMessage.setSendToSelf(false);
sendMessage.setSendToSelf(true);
sendMessage.setSendResult(false);
imClient.sendPrivateMessage(sendMessage);
// 推送回执消息给对方,更新已读状态

9
im-platform/src/main/java/com/bx/implatform/util/SensitiveFilterUtil.java

@ -79,11 +79,10 @@ public final class SensitiveFilterUtil {
*/
@PostConstruct
public void init() {
try (
// 类加载器
InputStream is = this.getClass().getClassLoader().getResourceAsStream("sensitive-words.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
) {
try {
// 类加载器
InputStream is = this.getClass().getClassLoader().getResourceAsStream("sensitive-words.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String keyword;
while ((keyword = reader.readLine()) != null) {
// 添加到前缀树

2
im-ui/src/components/common/HeadImage.vue

@ -84,7 +84,7 @@
.avatar-text{
background-color: #f2f2f2; /* 默认背景色 */
border-radius: 50%; /* 圆角效果 */
border-radius: 10%; /* 圆角效果 */
display: flex;
align-items: center;
justify-content: center;

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

@ -176,9 +176,8 @@ export default {
}
// 根据id顺序插入,防止消息乱序
let insertPos = chat.messages.length;
if(msgInfo.id>0){
//防止 图片、文件 在发送方 显示 在顶端 因为还没存库,id=0
// 防止 图片、文件 在发送方 显示 在顶端 因为还没存库,id=0
if(msgInfo.id && msgInfo.id > 0){
for (let idx in chat.messages) {
if (chat.messages[idx].id && msgInfo.id < chat.messages[idx].id) {
insertPos = idx;
@ -187,8 +186,6 @@ export default {
}
}
}
chat.messages.splice(insertPos, 0, msgInfo);
this.commit("saveToStorage");
},

2
im-ui/src/view/Login.vue

@ -20,7 +20,7 @@
<li>web端音视频功能优化:支持语音呼叫会话中加入通话状态消息</li>
<li>uniapp端支持音视频通话并与web端打通</li>
<li>uniapp端音视频源码通话源码暂未开源需付费获取:
<a href="https://www.yuque.com/u1475064/oncgyg/vi7engzluty594s2" target="_blank">uniapp端音视频通源码购买说明</a>
<a href="https://www.yuque.com/u1475064/mufu2a/vi7engzluty594s2" target="_blank">uniapp端音视频通源码购买说明</a>
</li>
</ul>
</div>

37
im-uniapp/App.vue

@ -15,8 +15,6 @@
init() {
//
store.dispatch("load").then(() => {
//
this.initAudit();
// websocket
this.initWebSocket();
}).catch((e) => {
@ -63,16 +61,22 @@
})
},
pullPrivateOfflineMessage(minId) {
store.commit("loadingPrivateMsg",true)
http({
url: "/message/private/pullOfflineMessage?minId=" + minId,
method: 'get'
});
method: 'GET'
}).catch(()=>{
store.commit("loadingPrivateMsg",false)
})
},
pullGroupOfflineMessage(minId) {
store.commit("loadingGroupMsg",true)
http({
url: "/message/group/pullOfflineMessage?minId=" + minId,
method: 'get'
});
method: 'GET'
}).catch(()=>{
store.commit("loadingGroupMsg",false)
})
},
handlePrivateMessage(msg) {
//
@ -195,13 +199,13 @@
},
loadFriendInfo(id) {
return new Promise((resolve, reject) => {
let friend = store.state.friendStore.friends.find((f) => f.id == id);
let friend = store.getters.findFriend(id);
if (friend) {
resolve(friend);
} else {
http({
url: `/friend/find/${id}`,
method: 'get'
method: 'GET'
}).then((friend) => {
store.commit("addFriend", friend);
resolve(friend)
@ -217,7 +221,7 @@
} else {
http({
url: `/group/find/${id}`,
method: 'get'
method: 'GET'
}).then((group) => {
resolve(group)
store.commit("addGroup", group);
@ -239,21 +243,6 @@
// this.audioTip = uni.createInnerAudioContext();
// this.audioTip.src = "/static/audio/tip.wav";
// this.audioTip.play();
},
initAudit() {
if (store.state.userStore.userInfo.type == 1) {
//
uni.setTabBarItem({
index: 2,
text: "群聊"
})
} else {
//
uni.setTabBarItem({
index: 2,
text: "搜索"
})
}
}
},
onLaunch() {

2
im-uniapp/common/emotion.js

@ -25,7 +25,7 @@ let textToImg = (emoText) => {
// 微信小程序不能有前面的'/'
path = path.slice(1);
// #endif
let img = `<img src="${path}" style="with:35px;height:35px;
let img = `<img src="${path}" style="with:30px;height:30px;
margin: 0 -2px;vertical-align:bottom;"/>`;
return img;
}

24
im-uniapp/components/chat-item/chat-item.vue

@ -1,5 +1,5 @@
<template>
<view class="chat-item" @click="showChatBox()">
<view class="chat-item" :class="active?'active':''" @click="showChatBox()">
<view class="left">
<head-image :url="chat.headImage" :name="chat.showName" :size="90"></head-image>
<view v-if="chat.unreadCount>0" class="unread-text">{{chat.unreadCount}}</view>
@ -30,6 +30,10 @@
},
index: {
type: Number
},
active: {
type: Boolean,
default: false
}
},
methods: {
@ -62,11 +66,15 @@
padding-left: 20rpx;
align-items: center;
background-color: white;
white-space: nowrap;
white-space: nowrap;
&:hover {
background-color: #eeeeee;
}
&.active {
background-color: #eeeeee;
}
.left {
position: relative;
@ -100,8 +108,8 @@
.chat-name {
display: flex;
line-height: 50rpx;
height: 50rpx;
line-height: 44rpx;
height: 44rpx;
.chat-name-text {
flex: 1;
@ -122,11 +130,12 @@
.chat-content {
display: flex;
line-height: 44rpx;
line-height: 60rpx;
height: 60rpx;
.chat-at-text {
color: #c70b0b;
font-size: 24rpx;
}
}
.chat-send-name {
font-size: 26rpx;
@ -137,8 +146,7 @@
font-size: 28rpx;
white-space: nowrap;
overflow: hidden;
line-height: 50rpx;
text-overflow: ellipsis;
text-overflow: ellipsis;
}
}
}

25
im-uniapp/components/chat-message-item/chat-message-item.vue

@ -11,16 +11,19 @@
:class="{'chat-msg-mine':msgInfo.selfSend}">
<head-image class="avatar" @longpress.prevent="$emit('longPressHead')" :id="msgInfo.sendId" :url="headImage"
:name="showName" :size="80"></head-image>
<view class="chat-msg-content" @longpress="onShowMenu($event)">
<view class="chat-msg-content">
<view v-if="msgInfo.groupId && !msgInfo.selfSend" class="chat-msg-top">
<text>{{showName}}</text>
</view>
<view class="chat-msg-bottom">
<rich-text class="chat-msg-text" v-if="msgInfo.type==$enums.MESSAGE_TYPE.TEXT"
:nodes="$emo.transform(msgInfo.content)"></rich-text>
<view class="chat-msg-bottom" @touchmove="onHideMenu()">
<view v-if="msgInfo.type==$enums.MESSAGE_TYPE.TEXT" @longpress.native="onShowMenu($event)">
<rich-text class="chat-msg-text"
:nodes="$emo.transform(msgInfo.content)"
></rich-text>
</view>
<view class="chat-msg-image" v-if="msgInfo.type==$enums.MESSAGE_TYPE.IMAGE">
<view class="img-load-box">
<view class="img-load-box" @longpress="onShowMenu($event)">
<image class="send-image" mode="heightFix" :src="JSON.parse(msgInfo.content).thumbUrl"
lazy-load="true" @click.stop="onShowFullImage()">
</image>
@ -30,7 +33,7 @@
class="send-fail iconfont icon-warning-circle-fill"></text>
</view>
<view class="chat-msg-file" v-if="msgInfo.type==$enums.MESSAGE_TYPE.FILE">
<view class="chat-file-box">
<view class="chat-file-box" @longpress="onShowMenu($event)">
<view class="chat-file-info">
<uni-link class="chat-file-name" :text="data.name" showUnderLine="true" color="#007BFF"
:href="data.url"></uni-link>
@ -43,13 +46,14 @@
class="send-fail iconfont icon-warning-circle-fill"></text>
</view>
<view class="chat-msg-audio chat-msg-text" v-if="msgInfo.type==$enums.MESSAGE_TYPE.AUDIO"
@click="onPlayAudio()">
@click="onPlayAudio()" @longpress="onShowMenu($event)">
<text class="iconfont icon-voice-play"></text>
<text class="chat-audio-text">{{JSON.parse(msgInfo.content).duration+'"'}}</text>
<text v-if="audioPlayState=='PAUSE'" class="iconfont icon-play"></text>
<text v-if="audioPlayState=='PLAYING'" class="iconfont icon-pause"></text>
</view>
<view class="chat-realtime chat-msg-text" v-if="isRTMessage" @click="$emit('call')">
<view class="chat-realtime chat-msg-text" v-if="isRTMessage"
@click="$emit('call')" @longpress="onShowMenu($event)">
<text v-if="msgInfo.type==$enums.MESSAGE_TYPE.RT_VOICE" class="iconfont icon-chat-voice"></text>
<text v-if="msgInfo.type==$enums.MESSAGE_TYPE.RT_VIDEO" class="iconfont icon-chat-video"></text>
<text>{{msgInfo.content}}</text>
@ -68,7 +72,7 @@
</view>
</view>
<chat-group-readed ref="chatGroupReaded" :groupMembers="groupMembers" :msgInfo="msgInfo"></chat-group-readed>
<pop-menu v-if="menu.show" :menu-style="menu.style" :items="menuItems" @close="menu.show=false"
<pop-menu v-if="menu.show" :menu-style="menu.style" :items="menuItems" @close="onHideMenu()"
@select="onSelectMenu"></pop-menu>
</view>
</template>
@ -129,6 +133,9 @@
}
})
},
onHideMenu(){
this.menu.show = false;
},
onSendFail() {
uni.showToast({
title: "该文件已发送失败,目前不支持自动重新发送,建议手动重新发送",

21
im-uniapp/components/chat-record/chat-record.vue

@ -1,7 +1,10 @@
<template>
<view class="chat-record">
<view class="chat-record-bar" id="chat-record-bar" :style="recordBarStyle" @touchstart="onStartRecord"
@touchmove="onTouchMove" @touchend.prevent="onEndRecord">{{recording?'正在录音':'长按 说话'}}</view>
<view class="chat-record-bar" id="chat-record-bar" :style="recordBarStyle"
@click.stop=""
@touchstart.prevent="onStartRecord"
@touchmove.prevent="onTouchMove"
@touchend.prevent="onEndRecord">{{recording?'正在录音':'长按 说话'}}</view>
<view v-if="recording" class="chat-record-window" :style="recordWindowStyle">
<view class="rc-wave">
<text class="note" style="--d: 0"></text>
@ -13,7 +16,7 @@
<text class="note" style="--d: 6"></text>
</view>
<view class="rc-tip">{{recordTip}}</view>
<view class="cancel-btn">
<view class="cancel-btn" @click="onCancel">
<uni-icons :class="moveToCancel?'red':'black'" type="clear"
:size="moveToCancel?45:40"></uni-icons>
</view>
@ -40,7 +43,19 @@
const moveY = e.touches[0].clientY;
this.moveToCancel = moveY < this.recordBarTop-40;
},
onCancel(){
if(this.recording){
this.moveToCancel = true;
this.onEndRecord();
}
},
onStartRecord() {
/* 使@touchend
一直处于录音状态这里允许用户再次点击发送语音并结束录音 */
if(this.recording){
this.onEndRecord();
return;
}
console.log("开始录音")
this.moveToCancel = false;
this.initRecordBar();

4
im-uniapp/components/head-image/head-image.vue

@ -83,9 +83,7 @@
.avatar-text {
background-color: #f2f2f2;
/* 默认背景色 */
border-radius: 50%;
/* 圆角效果 */
border-radius: 10%;
display: flex;
align-items: center;
justify-content: center;

3
im-uniapp/components/pop-menu/pop-menu.vue

@ -1,11 +1,10 @@
<template>
<view class="pop-menu" @tap="onClose()" @contextmenu.prevent="">
<view class="pop-menu" @tap="onClose()" @touchmove="onClose" @contextmenu.prevent="">
<view class="menu" :style="menuStyle">
<view class="menu-item" v-for="(item) in items" :key="item.key" @click.prevent="onSelectMenu(item)">
<uni-icons :type="item.icon" size="22"></uni-icons>
<text> {{item.name}}</text>
</view>
</view>
</view>
</template>

118
im-uniapp/components/user-search/user-search.vue

@ -1,118 +0,0 @@
<template>
<!-- for wx audit -->
<view class="page user-search">
<view class="search-bar">
<uni-search-bar v-model="searchText" :focus="true" @confirm="onSearch()" can
cancelButton="none" ceholder="用户名/昵称"></uni-search-bar>
</view>
<view class="user-items">
<scroll-view class="scroll-bar" scroll-with-animation="true" scroll-y="true">
<view v-for="(user) in users" :key="user.id" v-show="user.id != $store.state.userStore.userInfo.id">
<view class="user-item">
<head-image :id="user.id" :name="user.nickName"
:online="user.online" :url="user.headImage"
:size="100"></head-image>
<view class="user-name">{{ user.nickName}}</view>
<view class="user-btns">
<button type="primary" v-show="!isFriend(user.id)" size="mini"
@click.stop="onAddFriend(user)">加为好友</button>
<button type="default" v-show="isFriend(user.id)" size="mini" disabled>已添加</button>
</view>
</view>
</view>
</scroll-view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
searchText: "",
users: []
}
},
methods: {
onSearch() {
this.$http({
url: "/user/findByName?name=" + this.searchText,
method: "GET"
}).then((data) => {
this.users = data;
})
},
onAddFriend(user) {
this.$http({
url: "/friend/add?friendId=" + user.id,
method: "POST"
}).then((data) => {
let friend = {
id: user.id,
nickName: user.nickName,
headImage: user.headImage,
online: user.online
}
this.$store.commit("addFriend", friend);
uni.showToast({
title: "添加成功,对方已成为您的好友",
icon: "none"
})
})
},
onShowUserInfo(user) {
uni.navigateTo({
url: "/pages/common/user-info?id=" + user.id
})
},
isFriend(userId) {
let friends = this.$store.state.friendStore.friends;
let friend = friends.find((f) => f.id == userId);
return friend != undefined;
}
}
}
</script>
<style scoped lang="scss">
.user-search {
position: relative;
border: #dddddd solid 1px;
display: flex;
flex-direction: column;
.search-bar {
background: white;
}
.user-items{
position: relative;
flex: 1;
overflow: hidden;
.user-item {
height: 120rpx;
display: flex;
margin-bottom: 1rpx;
position: relative;
padding: 0 30rpx ;
align-items: center;
background-color: white;
white-space: nowrap;
.user-name {
flex:1;
padding-left: 20rpx;
font-size: 30rpx;
font-weight: 600;
line-height: 60rpx;
white-space: nowrap;
overflow: hidden;
}
}
.scroll-bar {
height: 100%;
}
}
}
</style>

3
im-uniapp/package.json

@ -4,7 +4,6 @@
"scripts": {}
},
"dependencies": {
"js-audio-recorder": "^1.0.7",
"recorder-core": "^1.3.23122400"
"js-audio-recorder": "^1.0.7"
}
}

2
im-uniapp/pages.json

@ -61,7 +61,7 @@
"pagePath": "pages/group/group",
"iconPath": "static/tarbar/group.png",
"selectedIconPath": "static/tarbar/group_active.png",
"text": "搜索"
"text": "群聊"
},
{
"pagePath": "pages/mine/mine",

38
im-uniapp/pages/chat/chat-box.vue

@ -6,10 +6,11 @@
<uni-icons class="btn-side right" type="more-filled" size="30" @click="onShowMore()"></uni-icons>
</view>
<view class="chat-msg" @click="switchChatTabBox('none',true)">
<scroll-view class="scroll-box" scroll-y="true" @scrolltoupper="onScrollToTop"
:scroll-into-view="'chat-item-'+scrollMsgIdx">
<scroll-view class="scroll-box" scroll-y="true"
upper-threshold="200" @scrolltoupper="onScrollToTop"
:scroll-into-view="'chat-item-'+scrollMsgIdx">
<view v-for="(msgInfo,idx) in chat.messages" :key="idx">
<chat-message-item v-if="idx>=showMinIdx" :headImage="headImage(msgInfo)" @call="onRtCall(msgInfo)"
<chat-message-item v-if="idx>=showMinIdx&&!msgInfo.delete" :headImage="headImage(msgInfo)" @call="onRtCall(msgInfo)"
:showName="showName(msgInfo)" @recall="onRecallMessage" @delete="onDeleteMessage"
@longPressHead="onLongPressHead(msgInfo)" @download="onDownloadFile" :id="'chat-item-'+idx"
:msgInfo="msgInfo" :groupMembers="groupMembers">
@ -136,7 +137,6 @@
this.switchChatTabBox('none',false);
},
onSendRecord(data) {
console.log(data);
let msgInfo = {
content: JSON.stringify(data),
type: this.$enums.MESSAGE_TYPE.AUDIO,
@ -496,12 +496,17 @@
});
},
onScrollToTop() {
// #ifdef MP
if(this.showMinIdx==0){
console.log("消息已滚动到顶部")
return;
}
// #ifndef H5
//
this.scrollToMsgIdx(this.showMinIdx);
// #endif
// 10
this.showMinIdx = this.showMinIdx > 10 ? this.showMinIdx - 10 : 0;
// 0
this.showMinIdx = this.showMinIdx > 20 ? this.showMinIdx - 20 : 0;
},
onShowMore() {
if (this.chat.type == "GROUP") {
@ -536,8 +541,14 @@
});
},
readedMessage() {
if(this.unreadCount == 0){
console.log("0000000000")
return;
}
let url = ""
if (this.chat.type == "GROUP") {
var url = `/message/group/readed?groupId=${this.chat.targetId}`
url = `/message/group/readed?groupId=${this.chat.targetId}`
} else {
url = `/message/private/readed?friendId=${this.chat.targetId}`
}
@ -557,12 +568,11 @@
this.group = group;
this.$store.commit("updateChatFromGroup", group);
this.$store.commit("updateGroup", group);
});
this.$http({
url: `/group/members/${groupId}`,
method: 'get'
method: 'GET'
}).then((groupMembers) => {
this.groupMembers = groupMembers;
});
@ -649,11 +659,9 @@
onLoad(options) {
//
this.chat = this.$store.state.chatStore.chats[options.chatIdx];
// 30
// 20
let size = this.chat.messages.length;
this.showMinIdx = size > 30 ? size - 30 : 0;
//
this.$store.commit("activeChat", options.chatIdx);
this.showMinIdx = size > 20 ? size - 20 : 0;
//
this.readedMessage()
//
@ -663,6 +671,8 @@
this.loadFriend(this.chat.targetId);
this.loadReaded(this.chat.targetId)
}
//
this.$store.commit("activeChat", options.chatIdx);
//
this.isReceipt = false;
},

88
im-uniapp/pages/chat/chat.vue

@ -1,8 +1,8 @@
<template>
<view class="tab-page">
<view v-if="loading" class="chat-loading" >
<loading :size="50" :mask="false">
<view v-if="loading" class="chat-loading">
<loading :size="50" :mask="false">
<view>消息接收中...</view>
</loading>
</view>
@ -10,12 +10,14 @@
温馨提示您现在还没有任何聊天消息快跟您的好友发起聊天吧~
</view>
<scroll-view class="scroll-bar" v-else scroll-with-animation="true" scroll-y="true">
<view v-for="(chat,index) in chatStore.chats" :key="index">
<chat-item :chat="chat" :index="index" @longpress.native="onShowMenu($event,index)"></chat-item>
<view v-for="(chatPos,i) in chatsPos" :key="i">
<chat-item v-if="!chatStore.chats[chatPos.idx].delete" :chat="chatStore.chats[chatPos.idx]"
:active="menu.chatIdx==chatPos.idx" :index="chatPos.idx"
@longpress.native="onShowMenu($event,chatPos.idx)"></chat-item>
</view>
</scroll-view>
<pop-menu v-show="menu.show" :menu-style="menu.style" :items="menu.items" @close="menu.show=false"
<pop-menu v-show="menu.show" :menu-style="menu.style" :items="menu.items" @close="onCloseMenu()"
@select="onSelectMenu"></pop-menu>
</view>
</template>
@ -30,12 +32,12 @@
chatIdx: -1,
items: [{
key: 'DELETE',
name: '删除',
name: '删除该聊天',
icon: 'trash'
},
{
key: 'TOP',
name: '置顶',
name: '置顶该聊天',
icon: 'arrow-up'
}
]
@ -57,6 +59,7 @@
this.menu.show = false;
},
onShowMenu(e, chatIdx) {
this.menu.chatIdx = chatIdx;
uni.getSystemInfo({
success: (res) => {
let touches = e.touches[0];
@ -81,6 +84,10 @@
}
})
},
onCloseMenu() {
this.menu.chatIdx = -1;
this.menu.show = false;
},
removeChat(chatIdx) {
this.$store.commit("removeChat", chatIdx);
},
@ -103,13 +110,30 @@
}
},
computed: {
chatsPos() {
//
let chatsPos = [];
let chats = this.chatStore.chats;
chats.forEach((chat, idx) => {
chatsPos.push({
idx: idx,
sendTime: chat.lastSendTime
})
})
chatsPos.sort((chatPos1, chatPos2) => {
return chatPos2.sendTime - chatPos1.sendTime;
});
return chatsPos;
},
chatStore() {
return this.$store.state.chatStore;
},
unreadCount() {
let count = 0;
this.chatStore.chats.forEach(chat => {
count += chat.unreadCount;
if (!chat.delete) {
count += chat.unreadCount;
}
})
return count;
},
@ -129,21 +153,39 @@
</script>
<style scoped lang="scss">
.chat-tip {
position: absolute;
top: 400rpx;
padding: 50rpx;
line-height: 50rpx;
text-align: left;
color: darkblue;
font-size: 30rpx;
}
.chat-loading {
display: block;
height: 100rpx;
background: white;
.tab-page {
position: relative;
color: blue;
border: #dddddd solid 1px;
display: flex;
flex-direction: column;
.chat-tip {
position: absolute;
top: 400rpx;
padding: 50rpx;
line-height: 50rpx;
text-align: left;
color: darkblue;
font-size: 30rpx;
}
.chat-loading {
display: block;
width: 100%;
height: 100rpx;
background: white;
position: relative;
color: blue;
.loading-box {
position: relative;
}
}
.scroll-bar {
flex: 1;
height: 100%;
}
}
</style>

5
im-uniapp/pages/common/user-info.vue

@ -55,8 +55,9 @@
headImage: this.userInfo.headImage,
};
this.$store.commit("openChat", chat);
let chatIdx = this.$store.getters.findChatIdx(chat);
uni.navigateTo({
url:"/pages/chat/chat-box?chatIdx=0"
url:"/pages/chat/chat-box?chatIdx=" + chatIdx
})
},
onAddFriend() {
@ -130,7 +131,7 @@
},
computed: {
isFriend() {
return this.friendInfo != undefined;
return this.friendInfo&&!this.friendInfo.delete;
},
friendInfo(){
let friends = this.$store.state.friendStore.friends;

2
im-uniapp/pages/friend/friend-add.vue

@ -70,7 +70,7 @@
isFriend(userId) {
let friends = this.$store.state.friendStore.friends;
let friend = friends.find((f) => f.id == userId);
return friend != undefined;
return friend&&!friend.delete;
}
}
}

5
im-uniapp/pages/friend/friend-search.vue

@ -5,8 +5,9 @@
</view>
<view class="friend-items">
<scroll-view class="scroll-bar" scroll-with-animation="true" scroll-y="true">
<view v-for="(friend,index) in $store.state.friendStore.friends" v-show="searchText && friend.nickName.startsWith(searchText)" :key="index">
<friend-item :friend="friend" :index="index"></friend-item>
<view v-for="(friend,index) in $store.state.friendStore.friends" :key="index">
<friend-item v-if="searchText&&!friend.delete&&friend.nickName.startsWith(searchText)"
:friend="friend" :index="index"></friend-item>
</view>
</scroll-view>
</view>

17
im-uniapp/pages/friend/friend.vue

@ -8,13 +8,18 @@
<uni-icons type="personadd" size="30"></uni-icons>
</view>
</view>
<view class="friend-tip" v-if="$store.state.friendStore.friends.length==0">
<view class="friend-tip" v-if="friends.length==0">
温馨提示您现在还没有任何好友快点击右上方'+'按钮添加好友吧~
</view>
<view class="friend-items" v-else>
<scroll-view class="scroll-bar" scroll-with-animation="true" scroll-y="true">
<view v-for="(friend,index) in $store.state.friendStore.friends" :key="index">
<friend-item :friend="friend"></friend-item>
<!-- 先展示在线好友-->
<view v-for="(friend,index) in friends" :key="index">
<friend-item v-if="!friend.delete&&friend.online" :friend="friend"></friend-item>
</view>
<!-- 再展示离线好友-->
<view v-for="(friend,index) in friends" :key="index">
<friend-item v-if="!friend.delete&&!friend.online" :friend="friend"></friend-item>
</view>
</scroll-view>
</view>
@ -40,8 +45,12 @@
url: "/pages/friend/friend-add"
})
}
},
computed:{
friends(){
return this.$store.state.friendStore.friends;
}
}
}
</script>

3
im-uniapp/pages/group/group-info.vue

@ -86,8 +86,9 @@
headImage: this.group.headImage,
};
this.$store.commit("openChat", chat);
let chatIdx = this.$store.getters.findChatIdx(chat);
uni.navigateTo({
url: "/pages/chat/chat-box?chatIdx=0"
url: "/pages/chat/chat-box?chatIdx=" + chatIdx
})
},
onQuitGroup() {

3
im-uniapp/pages/group/group-invite.vue

@ -84,6 +84,9 @@
this.friendItems = [];
let friends = this.$store.state.friendStore.friends;
friends.forEach((f => {
if(f.delete){
return
}
let item = {
id: f.id,
headImage: f.headImage,

6
im-uniapp/pages/group/group.vue

@ -1,5 +1,5 @@
<template>
<view v-if="$store.state.userStore.userInfo.type == 1" class="tab-page group">
<view class="tab-page group">
<view class="nav-bar">
<view class="nav-search">
<uni-search-bar @focus="onFocusSearch" cancelButton="none" placeholder="点击搜索群聊"></uni-search-bar>
@ -19,10 +19,6 @@
</scroll-view>
</view>
</view>
<!-- wx audit -->
<view v-else>
<user-search></user-search>
</view>
</template>
<script>

261
im-uniapp/store/chatStore.js

@ -1,9 +1,22 @@
import { MESSAGE_TYPE, MESSAGE_STATUS } from '@/common/enums.js';
import {
MESSAGE_TYPE,
MESSAGE_STATUS
} from '@/common/enums.js';
import userStore from './userStore';
/*
uniapp性能优化
1.由于uniapp渲染消息性能非常拉胯,所以先把离线消息存储到cacheChats,
待所有离线消息拉取完成后再统一进行渲染
2.在vuex中对数组进行unshift,splice特别卡所以删除会话会话置顶
除消息等操作进行优化不通过unshift,splice实现改造方案如下
删除会话 通过delete标志判断是否删除
删除消息通过delete标志判断是否删除
会话置顶通过lastSendTime排序确定会话顺序
*/
let cacheChats = [];
export default {
state: {
activeIndex: -1,
chats: [],
privateMsgMaxId: 0,
groupMsgMaxId: 0,
@ -13,26 +26,42 @@ export default {
mutations: {
initChats(state, chatsData) {
state.chats = chatsData.chats ||[];
state.privateMsgMaxId = chatsData.privateMsgMaxId||0;
state.groupMsgMaxId = chatsData.groupMsgMaxId||0;
cacheChats = [];
for (let chat of chatsData.chats) {
// 已删除的会话直接丢弃
if (chat.delete) {
continue;
}
// 暂存至缓冲区
cacheChats.push(JSON.parse(JSON.stringify(chat)));
// 加载期间显示只前15个会话做做样子,一切都为了加快初始化时间
if (state.chats.length < 15) {
chat.messages = [];
state.chats.push(chat);
}
}
state.privateMsgMaxId = chatsData.privateMsgMaxId || 0;
state.groupMsgMaxId = chatsData.groupMsgMaxId || 0;
// 防止图片一直处在加载中状态
state.chats.forEach((chat) => {
cacheChats.forEach((chat) => {
chat.messages.forEach((msg) => {
if (msg.loadStatus == "loading") {
msg.loadStatus = "fail"
}
})
})
},
openChat(state, chatInfo) {
let chats = this.getters.findChats();
let chat = null;
for (let idx in state.chats) {
if (state.chats[idx].type == chatInfo.type &&
state.chats[idx].targetId === chatInfo.targetId) {
chat = state.chats[idx];
for (let idx in chats) {
if (chats[idx].type == chatInfo.type &&
chats[idx].targetId === chatInfo.targetId) {
chat = chats[idx];
chat.delete = false;
// 放置头部
this.commit("moveTop",idx)
this.commit("moveTop", idx)
break;
}
}
@ -48,40 +77,42 @@ export default {
unreadCount: 0,
messages: [],
atMe: false,
atAll: false
atAll: false,
delete: false
};
state.chats.unshift(chat);
chats.push(chat);
this.commit("moveTop", chats.length - 1)
}
this.commit("saveToStorage");
},
activeChat(state, idx) {
state.activeIndex = idx;
let chats = this.getters.findChats();
if (idx >= 0) {
state.chats[idx].unreadCount = 0;
chats[idx].unreadCount = 0;
}
},
resetUnreadCount(state, chatInfo) {
for (let idx in state.chats) {
if (state.chats[idx].type == chatInfo.type &&
state.chats[idx].targetId == chatInfo.targetId) {
state.chats[idx].unreadCount = 0;
state.chats[idx].atMe = false;
state.chats[idx].atAll = false;
let chats = this.getters.findChats();
for (let idx in chats) {
if (chats[idx].type == chatInfo.type &&
chats[idx].targetId == chatInfo.targetId) {
chats[idx].unreadCount = 0;
chats[idx].atMe = false;
chats[idx].atAll = false;
}
}
this.commit("saveToStorage");
},
readedMessage(state, pos) {
for (let idx in state.chats) {
if (state.chats[idx].type == 'PRIVATE' &&
state.chats[idx].targetId == pos.friendId) {
state.chats[idx].messages.forEach((m) => {
let chats = this.getters.findChats();
for (let idx in chats) {
if (chats[idx].type == 'PRIVATE' &&
chats[idx].targetId == pos.friendId) {
chats[idx].messages.forEach((m) => {
if (m.selfSend && m.status != MESSAGE_STATUS.RECALL) {
// pos.maxId为空表示整个会话已读
if(!pos.maxId || m.id <= pos.maxId){
if (!pos.maxId || m.id <= pos.maxId) {
m.status = MESSAGE_STATUS.READED
}
}
})
}
@ -89,28 +120,25 @@ export default {
this.commit("saveToStorage");
},
removeChat(state, idx) {
state.chats.splice(idx, 1);
let chats = this.getters.findChats();
chats[idx].delete = true;
this.commit("saveToStorage");
},
removePrivateChat(state, userId) {
for (let idx in state.chats) {
if (state.chats[idx].type == 'PRIVATE' &&
state.chats[idx].targetId == userId) {
let chats = this.getters.findChats();
for (let idx in chats) {
if (chats[idx].type == 'PRIVATE' &&
chats[idx].targetId == userId) {
this.commit("removeChat", idx);
}
}
},
moveTop(state, idx) {
// 加载中不移动,很耗性能
if(state.loadingPrivateMsg || state.loadingGroupMsg){
return ;
}
if (idx > 0) {
let chat = state.chats[idx];
state.chats.splice(idx, 1);
state.chats.unshift(chat);
this.commit("saveToStorage");
}
let chats = this.getters.findChats();
let chat = chats[idx];
// 最新的时间会显示在顶部
chat.lastSendTime = new Date().getTime();
this.commit("saveToStorage");
},
insertMessage(state, msgInfo) {
// 获取对方id或群id
@ -125,46 +153,45 @@ export default {
// 如果是已存在消息,则覆盖旧的消息数据
let chat = this.getters.findChat(msgInfo);
let message = this.getters.findMessage(chat, msgInfo);
if(message){
if (message) {
Object.assign(message, msgInfo);
// 撤回消息需要显示
if(msgInfo.type == MESSAGE_TYPE.RECALL){
if (msgInfo.type == MESSAGE_TYPE.RECALL) {
chat.lastContent = msgInfo.content;
}
this.commit("saveToStorage");
return;
}
// 会话列表内容
if(!state.loadingPrivateMsg && !state.loadingGroupMsg){
if (msgInfo.type == MESSAGE_TYPE.IMAGE) {
chat.lastContent = "[图片]";
} else if (msgInfo.type == MESSAGE_TYPE.FILE) {
chat.lastContent = "[文件]";
} else if (msgInfo.type == MESSAGE_TYPE.AUDIO) {
chat.lastContent = "[语音]";
} else if (msgInfo.type == MESSAGE_TYPE.TEXT || msgInfo.type == MESSAGE_TYPE.RECALL) {
chat.lastContent = msgInfo.content;
} else if (msgInfo.type == MESSAGE_TYPE.RT_VOICE) {
chat.lastContent = "[语音通话]";
} else if (msgInfo.type == MESSAGE_TYPE.RT_VIDEO) {
chat.lastContent = "[视频通话]";
}
chat.lastSendTime = msgInfo.sendTime;
chat.sendNickName = msgInfo.sendNickName;
if (msgInfo.type == MESSAGE_TYPE.IMAGE) {
chat.lastContent = "[图片]";
} else if (msgInfo.type == MESSAGE_TYPE.FILE) {
chat.lastContent = "[文件]";
} else if (msgInfo.type == MESSAGE_TYPE.AUDIO) {
chat.lastContent = "[语音]";
} else if (msgInfo.type == MESSAGE_TYPE.TEXT || msgInfo.type == MESSAGE_TYPE.RECALL) {
chat.lastContent = msgInfo.content;
} else if (msgInfo.type == MESSAGE_TYPE.RT_VOICE) {
chat.lastContent = "[语音通话]";
} else if (msgInfo.type == MESSAGE_TYPE.RT_VIDEO) {
chat.lastContent = "[视频通话]";
}
chat.lastSendTime = msgInfo.sendTime;
chat.sendNickName = msgInfo.sendNickName;
// 未读加1
if (!msgInfo.selfSend && msgInfo.status != MESSAGE_STATUS.READED
&& msgInfo.type != MESSAGE_TYPE.TIP_TEXT) {
if (!msgInfo.selfSend && msgInfo.status != MESSAGE_STATUS.READED &&
msgInfo.type != MESSAGE_TYPE.TIP_TEXT) {
chat.unreadCount++;
}
// 是否有人@我
if(!msgInfo.selfSend && chat.type=="GROUP" && msgInfo.atUserIds
&& msgInfo.status != MESSAGE_STATUS.READED){
if (!msgInfo.selfSend && chat.type == "GROUP" && msgInfo.atUserIds &&
msgInfo.status != MESSAGE_STATUS.READED) {
let userId = userStore.state.userInfo.id;
if(msgInfo.atUserIds.indexOf(userId)>=0){
if (msgInfo.atUserIds.indexOf(userId) >= 0) {
chat.atMe = true;
}
if(msgInfo.atUserIds.indexOf(-1)>=0){
if (msgInfo.atUserIds.indexOf(-1) >= 0) {
chat.atAll = true;
}
}
@ -178,21 +205,29 @@ export default {
}
// 根据id顺序插入,防止消息乱序
let insertPos = chat.messages.length;
for (let idx in chat.messages) {
if (chat.messages[idx].id && msgInfo.id < chat.messages[idx].id) {
insertPos = idx;
console.log(`消息出现乱序,位置:${chat.messages.length},修正至:${insertPos}`);
break;
// 防止 图片、文件 在发送方 显示 在顶端 因为还没存库,id=0
if (msgInfo.id && msgInfo.id > 0) {
for (let idx in chat.messages) {
if (chat.messages[idx].id && msgInfo.id < chat.messages[idx].id) {
insertPos = idx;
console.log(`消息出现乱序,位置:${chat.messages.length},修正至:${insertPos}`);
break;
}
}
}
chat.messages.splice(insertPos, 0, msgInfo);
if (insertPos == chat.messages.length) {
// 这种赋值效率最高
chat.messages[insertPos] = msgInfo;
} else {
chat.messages.splice(insertPos, 0, msgInfo);
}
this.commit("saveToStorage");
},
updateMessage(state, msgInfo) {
// 获取对方id或群id
let chat = this.getters.findChat(msgInfo);
let message = this.getters.findMessage(chat, msgInfo);
if(message){
if (message) {
// 属性拷贝
Object.assign(message, msgInfo);
this.commit("saveToStorage");
@ -204,21 +239,22 @@ export default {
for (let idx in chat.messages) {
// 已经发送成功的,根据id删除
if (chat.messages[idx].id && chat.messages[idx].id == msgInfo.id) {
chat.messages.splice(idx, 1);
chat.messages[idx].delete = true;
break;
}
// 正在发送中的消息可能没有id,根据发送时间删除
if (msgInfo.selfSend && chat.messages[idx].selfSend &&
chat.messages[idx].sendTime == msgInfo.sendTime) {
chat.messages.splice(idx, 1);
chat.messages[idx].delete = true;
break;
}
}
this.commit("saveToStorage");
},
updateChatFromFriend(state, friend) {
for (let i in state.chats) {
let chat = state.chats[i];
let chats = this.getters.findChats();
for (let i in chats) {
let chat = chats[i];
if (chat.type == 'PRIVATE' && chat.targetId == friend.id) {
chat.headImage = friend.headImageThumb;
chat.showName = friend.nickName;
@ -228,8 +264,9 @@ export default {
this.commit("saveToStorage");
},
updateChatFromGroup(state, group) {
for (let i in state.chats) {
let chat = state.chats[i];
let chats = this.getters.findChats();
for (let i in chats) {
let chat = chats[i];
if (chat.type == 'GROUP' && chat.targetId == group.id) {
chat.headImage = group.headImageThumb;
chat.showName = group.remark;
@ -240,40 +277,30 @@ export default {
},
loadingPrivateMsg(state, loadding) {
state.loadingPrivateMsg = loadding;
if(!state.loadingPrivateMsg && !state.loadingGroupMsg){
if (!this.getters.isLoading()) {
this.commit("refreshChats")
}
},
loadingGroupMsg(state, loadding) {
state.loadingGroupMsg = loadding;
if(!state.loadingPrivateMsg && !state.loadingGroupMsg){
if (!this.getters.isLoading()) {
this.commit("refreshChats")
}
},
refreshChats(state){
state.chats.forEach((chat)=>{
if(chat.messages.length>0){
let msgInfo = chat.messages[chat.messages.length-1];
if (msgInfo.type == MESSAGE_TYPE.IMAGE) {
chat.lastContent = "[图片]";
} else if (msgInfo.type == MESSAGE_TYPE.FILE) {
chat.lastContent = "[文件]";
} else if (msgInfo.type == MESSAGE_TYPE.AUDIO) {
chat.lastContent = "[语音]";
} else if (msgInfo.type == MESSAGE_TYPE.TEXT || msgInfo.type == MESSAGE_TYPE.RECALL) {
chat.lastContent = msgInfo.content;
}
chat.lastSendTime = msgInfo.sendTime;
}else{
chat.lastContent = "";
chat.lastSendTime = new Date().getTime()
}
})
state.chats.sort((chat1, chat2) => {
return chat2.lastSendTime-chat1.lastSendTime;
refreshChats(state) {
// 排序
cacheChats.sort((chat1, chat2) => {
return chat2.lastSendTime - chat1.lastSendTime;
});
// 将消息一次性装载回来
state.chats = cacheChats;
this.commit("saveToStorage");
},
saveToStorage(state) {
// 加载中不保存,防止卡顿
if (this.getters.isLoading()) {
return;
}
let userId = userStore.state.userInfo.id;
let key = "chats-" + userId;
let chatsData = {
@ -283,12 +310,12 @@ export default {
}
uni.setStorage({
key: key,
data: chatsData
data: chatsData ,
})
},
clear(state) {
cacheChats = [];
state.chats = [];
state.activeIndex = -1;
state.privateMsgMaxId = 0;
state.groupMsgMaxId = 0;
state.loadingPrivateMsg = false;
@ -313,24 +340,32 @@ export default {
}
},
getters: {
findChatIdx: (state) => (chat) => {
for (let idx in state.chats) {
if (state.chats[idx].type == chat.type &&
state.chats[idx].targetId === chat.targetId) {
isLoading: (state) => () => {
return state.loadingPrivateMsg || state.loadingGroupMsg
},
findChats: (state, getters) => () => {
return getters.isLoading() ? cacheChats : state.chats;
},
findChatIdx: (state, getters) => (chat) => {
let chats = getters.findChats();
for (let idx in chats) {
if (chats[idx].type == chat.type &&
chats[idx].targetId === chat.targetId) {
chat = state.chats[idx];
return idx;
}
}
},
findChat: (state) => (msgInfo) => {
findChat: (state, getters) => (msgInfo) => {
let chats = getters.findChats();
// 获取对方id或群id
let type = msgInfo.groupId ? 'GROUP' : 'PRIVATE';
let targetId = msgInfo.groupId ? msgInfo.groupId : msgInfo.selfSend ? msgInfo.recvId : msgInfo.sendId;
let chat = null;
for (let idx in state.chats) {
if (state.chats[idx].type == type &&
state.chats[idx].targetId === targetId) {
chat = state.chats[idx];
for (let idx in chats) {
if (chats[idx].type == type &&
chats[idx].targetId === targetId) {
chat = chats[idx];
break;
}
}

55
im-uniapp/store/friendStore.js

@ -13,7 +13,7 @@ export default {
},
updateFriend(state, friend) {
state.friends.forEach((f, index) => {
if (f.id == friend.id) {
if (!f.delete && f.id == friend.id) {
// 拷贝属性
let online = state.friends[index].online;
Object.assign(state.friends[index], friend);
@ -22,40 +22,24 @@ export default {
})
},
removeFriend(state, id) {
state.friends.forEach((f, idx) => {
if (f.id == id) {
state.friends.splice(idx, 1)
}
});
let friend = this.getters.findFriend(id);
if(friend){
friend.delete = true;
}
},
addFriend(state, friend) {
state.friends.push(friend);
let f = this.getters.findFriend(friend.id);
if(f){
Object.assign(f, friend);
f.delete = false;
}else{
state.friends.push(friend);
}
},
setOnlineStatus(state, onlineTerminals) {
setOnlineStatus(state, onlineUsers) {
state.friends.forEach((f) => {
let userTerminal = onlineTerminals.find((o) => f.id == o.userId);
if (userTerminal) {
f.online = true;
f.onlineTerminals = userTerminal.terminals;
f.onlineWeb = userTerminal.terminals.indexOf(TERMINAL_TYPE.WEB) >= 0
f.onlineApp = userTerminal.terminals.indexOf(TERMINAL_TYPE.APP) >= 0
} else {
f.online = false;
f.onlineTerminals = [];
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;
let onlineUser = onlineUsers.find((o) => f.id == o.userId);
f.online = !!onlineUser
});
},
refreshOnlineStatus(state) {
@ -67,8 +51,8 @@ export default {
http({
url: '/user/terminal/online?userIds=' + userIds.join(','),
method: 'GET'
}).then((onlineTerminals) => {
this.commit("setOnlineStatus", onlineTerminals);
}).then((onlineUsers) => {
this.commit("setOnlineStatus", onlineUsers);
})
}
// 30s后重新拉取
@ -98,5 +82,10 @@ export default {
})
});
}
},
getters:{
findFriend: (state) => (id) => {
return state.friends.find((f)=>f.id==id);
}
}
}
Loading…
Cancel
Save