Browse Source

修改切换账号功能类似飞机

master
[yxf] 4 weeks ago
parent
commit
efac214d69
  1. 19
      im-platform/src/main/java/com/bx/implatform/controller/PrivateMessageController.java
  2. 111
      im-platform/src/main/java/com/bx/implatform/controller/UserController.java
  3. 3
      im-platform/src/main/java/com/bx/implatform/dto/LoginDTO.java
  4. 7
      im-platform/src/main/java/com/bx/implatform/entity/User.java
  5. 9
      im-platform/src/main/java/com/bx/implatform/service/PrivateMessageService.java
  6. 9
      im-platform/src/main/java/com/bx/implatform/service/UserService.java
  7. 37
      im-platform/src/main/java/com/bx/implatform/service/impl/PrivateMessageServiceImpl.java
  8. 76
      im-platform/src/main/java/com/bx/implatform/service/impl/UserServiceImpl.java
  9. 3
      im-platform/src/main/java/com/bx/implatform/vo/LoginVO.java
  10. 2
      im-web/src/components/setting/Setting.vue
  11. 369
      im-web/src/view/Home.vue

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

@ -12,7 +12,9 @@ import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Tag(name = "私聊消息")
@RestController
@ -48,6 +50,7 @@ public class PrivateMessageController {
return ResultUtils.success();
}
@GetMapping("/maxReadedId")
@Operation(summary = "获取最大已读消息的id", description = "获取某个会话中已读消息的最大id")
public Result<Long> getMaxReadedId(@RequestParam Long friendId) {
@ -63,5 +66,21 @@ public class PrivateMessageController {
return ResultUtils.success(privateMessageService.findHistoryMessage(friendId, page, size));
}
/**
* 批量获取指定用户的未读消息数
*/
@PostMapping("/unreadCounts")
@Operation(summary = "批量获取指定用户的未读消息数", description = "批量获取多个指定用户的未读消息数")
public Result<Map<Long, Integer>> getUnreadCounts(@RequestBody Map<String, List<Long>> params) {
List<Long> userIds = params.get("userIds");
if (userIds == null || userIds.isEmpty()) {
return ResultUtils.success(new HashMap<>());
}
Map<Long, Integer> result = privateMessageService.getUnreadCountsByUserIds(userIds);
return ResultUtils.success(result);
}
}

111
im-platform/src/main/java/com/bx/implatform/controller/UserController.java

@ -1,7 +1,10 @@
package com.bx.implatform.controller;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.bx.implatform.dto.LoginDTO;
import com.bx.implatform.dto.RegisterDTO;
import com.bx.implatform.entity.User;
import com.bx.implatform.result.Result;
@ -24,9 +27,8 @@ import com.alibaba.fastjson.JSON;
import com.bx.imcommon.util.JwtUtil;
import com.bx.implatform.config.props.JwtProperties;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.stream.Collectors;
import static com.bx.implatform.enums.ResultCode.XSS_PARAM_ERROR;
@ -133,6 +135,109 @@ public class UserController {
return ResultUtils.success(result);
}
@PostMapping("/addAccounts")
@Operation(summary = "客服登录", description = "客服登录")
public Result<LoginVO> addAccounts(@Valid @RequestBody LoginDTO dto) {
LoginVO vo = userService.addAccounts(dto);
return ResultUtils.success(vo);
}
@PostMapping("/getSwitchableAccounts")
@Operation(summary = "获取可切换的账号列表", description = "获取当前客服可切换的账号列表")
public Result<Map<String, Object>> getSwitchableAccounts() {
UserSession session = SessionContext.getSession();
Long userId = session.getUserId();
if (ObjectUtil.isNull(userId)) {
return ResultUtils.error(XSS_PARAM_ERROR);
}
// 获取当前用户信息
User currentUser = userService.getById(userId);
if (currentUser == null) {
return ResultUtils.error(XSS_PARAM_ERROR);
}
Map<String, Object> result = new HashMap<>();
// 获取可切换的账号ID列表(逗号分隔的字符串,如 "13,14")
String switchableIdsStr = currentUser.getSwitchableAccountIds();
List<Map<String, Object>> switchableUsers = new ArrayList<>();
if (StrUtil.isNotBlank(switchableIdsStr)) {
String[] idArray = switchableIdsStr.split(",");
List<Long> ids = Arrays.stream(idArray)
.filter(StrUtil::isNotBlank)
.map(Long::parseLong)
.collect(Collectors.toList());
if (!ids.isEmpty()) {
List<User> users = userService.listByIds(ids);
// 过滤掉被封禁的账号
users = users.stream()
.filter(u -> !Boolean.TRUE.equals(u.getIsBanned()))
.collect(Collectors.toList());
switchableUsers = users.stream().map(user -> {
Map<String, Object> map = new HashMap<>();
map.put("id", user.getId());
map.put("userName", user.getUserName());
map.put("nickName", user.getNickName());
map.put("headImage", user.getHeadImage());
map.put("headImageThumb", user.getHeadImageThumb());
return map;
}).collect(Collectors.toList());
}
}
result.put("switchableUsers", switchableUsers);
// 获取当前用户的 unique_token
String currentUserUniqueToken = currentUser.getUniqueToken();
// 构建查询条件
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<User>()
.eq(User::getIsCustomer, 2)
.ne(User::getId, userId)
.eq(User::getIsBanned, 0);
// 添加 unique_token 条件
if (StrUtil.isNotBlank(currentUserUniqueToken)) {
// 当前用户有 unique_token,只查询相同 unique_token 的客服
queryWrapper.eq(User::getUniqueToken, currentUserUniqueToken);
} else {
// 当前用户没有 unique_token,只查询也没有 unique_token 的客服
queryWrapper.isNull(User::getUniqueToken).or().eq(User::getUniqueToken, "");
}
List<User> availableUsers = userService.list(queryWrapper);
// 获取已添加的ID集合
Set<Long> existingIds = new HashSet<>();
if (StrUtil.isNotBlank(switchableIdsStr)) {
Arrays.stream(switchableIdsStr.split(","))
.filter(StrUtil::isNotBlank)
.map(Long::parseLong)
.forEach(existingIds::add);
}
// 标记是否已添加
List<Map<String, Object>> availableUsersList = availableUsers.stream().map(user -> {
Map<String, Object> map = new HashMap<>();
map.put("id", user.getId());
map.put("userName", user.getUserName());
map.put("nickName", user.getNickName());
map.put("headImage", user.getHeadImage());
// map.put("headImageThumb", user.getHeadImageThumb());
map.put("isAdded", existingIds.contains(user.getId()));
return map;
}).collect(Collectors.toList());
result.put("availableUsers", availableUsersList);
return ResultUtils.success(result);
}
@PostMapping("/changeCustomer")
@Operation(summary = "转接客服", description = "转接客服")
public Result register(@RequestBody JSONObject jsonObject) {

3
im-platform/src/main/java/com/bx/implatform/dto/LoginDTO.java

@ -37,4 +37,7 @@ public class LoginDTO {
@Schema(description = "客服ID")
private String keFuId;
@Schema(description = "可切换客服账号")
private String switchableAccountIds;
}

7
im-platform/src/main/java/com/bx/implatform/entity/User.java

@ -129,4 +129,11 @@ public class User {
*/
private String welcomeMsg;
/**
* 可切换的账号IDs列表
*/
private String switchableAccountIds;
}

9
im-platform/src/main/java/com/bx/implatform/service/PrivateMessageService.java

@ -6,6 +6,7 @@ import com.bx.implatform.entity.PrivateMessage;
import com.bx.implatform.vo.PrivateMessageVO;
import java.util.List;
import java.util.Map;
public interface PrivateMessageService extends IService<PrivateMessage> {
@ -63,4 +64,12 @@ public interface PrivateMessageService extends IService<PrivateMessage> {
* @param customerId 客服id
*/
void changeMessageRecord(Long customerId,Long targetId, Long userId);
/**
* 批量获取指定用户的未读消息数
* @param userIds 要查询的用户ID列表
* @return key: 用户ID, value: 该用户的未读消息数
*/
Map<Long, Integer> getUnreadCountsByUserIds(List<Long> userIds);
}

9
im-platform/src/main/java/com/bx/implatform/service/UserService.java

@ -29,6 +29,15 @@ public interface UserService extends IService<User> {
*/
LoginVO loginCustom(LoginDTO dto);
/**
* 客服登录
*
* @param dto 登录dto
* @return 登录token
*/
LoginVO addAccounts(LoginDTO dto);
/**
* 修改用户密码
*

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

@ -32,10 +32,7 @@ import org.apache.commons.lang3.time.DateUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.*;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.stream.Collectors;
@ -242,6 +239,36 @@ public class PrivateMessageServiceImpl extends ServiceImpl<PrivateMessageMapper,
return vos;
}
@Override
public Map<Long, Integer> getUnreadCountsByUserIds(List<Long> userIds) {
if (userIds == null || userIds.isEmpty()) {
return new HashMap<>();
}
Map<Long, Integer> result = new HashMap<>();
// 初始化所有用户为0
for (Long userId : userIds) {
result.put(userId, 0);
}
// 批量查询未读消息(status = 0 表示未读)
LambdaQueryWrapper<PrivateMessage> wrapper = Wrappers.lambdaQuery();
wrapper.in(PrivateMessage::getRecvId, userIds)
.eq(PrivateMessage::getStatus, 0) // 0 表示未读
.select(PrivateMessage::getRecvId);
List<PrivateMessage> messages = this.list(wrapper);
// 统计每个用户的未读消息数
for (PrivateMessage msg : messages) {
Long recvId = msg.getRecvId();
result.put(recvId, result.getOrDefault(recvId, 0) + 1);
}
return result;
}
@Transactional(rollbackFor = Exception.class)
@Override
public void readedMessage(Long friendId) {
@ -307,7 +334,7 @@ public class PrivateMessageServiceImpl extends ServiceImpl<PrivateMessageMapper,
}
@Override
// @Override
public void changeMessageRecord(Long customerId, Long targetId, Long userId) {
List<PrivateMessage> list = new ArrayList<>();

76
im-platform/src/main/java/com/bx/implatform/service/impl/UserServiceImpl.java

@ -225,6 +225,82 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
return randomCustomerId;
}
@Override
@Transactional(rollbackFor = Exception.class)
public LoginVO addAccounts(LoginDTO dto) {
// 获取当前登录用户
UserSession session = SessionContext.getSession();
Long currentUserId = session.getUserId();
if (ObjectUtil.isNull(currentUserId)) {
throw new GlobalException("用户未登录");
}
// 获取当前用户信息
User currentUser = this.getById(currentUserId);
if (ObjectUtil.isNull(currentUser)) {
throw new GlobalException("当前用户不存在");
}
// 验证要添加的账号
User targetUser = this.findUserByUserName(dto.getUserName());
if (Objects.isNull(targetUser)) {
throw new GlobalException("用户不存在");
}
if (targetUser.getIsCustomer() == 1) {
throw new GlobalException("只能添加客服账号");
}
if (targetUser.getIsBanned()) {
String tip = String.format("该账号因'%s'已被管理员封禁", targetUser.getReason());
throw new GlobalException(tip);
}
if (!passwordEncoder.matches(dto.getPassword(), targetUser.getPassword())) {
throw new GlobalException(ResultCode.PASSWOR_ERROR);
}
// 未设置套餐或套餐过期
if (imAgentService.isPackageExpire(targetUser.getUniqueToken())) {
throw new GlobalException("套餐已过期");
}
// 验证是否属于同一个代理(unique_token 相同)
if (!Objects.equals(currentUser.getUniqueToken(), targetUser.getUniqueToken())) {
throw new GlobalException("只能添加同属一个代理的客服账号");
}
// 不能添加自己
if (currentUserId.equals(targetUser.getId())) {
throw new GlobalException("不能添加当前登录的账号");
}
// 获取当前用户的可切换账号ID列表
String switchableIdsStr = currentUser.getSwitchableAccountIds();
Set<String> idSet = new HashSet<>();
if (StrUtil.isNotBlank(switchableIdsStr)) {
idSet.addAll(Arrays.asList(switchableIdsStr.split(",")));
}
// 添加新ID
String newId = String.valueOf(targetUser.getId());
if (idSet.contains(newId)) {
throw new GlobalException("该账号已在切换列表中");
}
idSet.add(newId);
// 更新当前用户的 switchable_account_ids
String newIdsStr = String.join(",", idSet);
currentUser.setSwitchableAccountIds(newIdsStr);
this.updateById(currentUser);
log.info("用户 {} 添加了可切换账号 {},当前可切换账号列表: {}",
currentUserId, targetUser.getId(), newIdsStr);
LoginVO vo = new LoginVO();
return vo;
}
@Override
public LoginVO loginCustom(LoginDTO dto) {
User user = this.findUserByUserName(dto.getUserName());

3
im-platform/src/main/java/com/bx/implatform/vo/LoginVO.java

@ -26,4 +26,7 @@ public class LoginVO {
@Schema(description = "当前登录用户信息")
private User user;
@Schema(description = "可切换客服账号")
private String switchableAccountIds;
}

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

@ -30,7 +30,7 @@
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="onSwitchAccount" style="float: left;">切换账号</el-button>
<!-- <el-button @click="onSwitchAccount" style="float: left;">切换账号</el-button> -->
<el-button @click="onClose()"> </el-button>
<el-button type="primary" @click="onSubmit()"> </el-button>
</span>

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

@ -4,23 +4,34 @@
<div class="navi-bar">
<div class="navi-bar-box">
<div class="top">
<div class="user-head-image">
<head-image :name="userStore.userInfo.nickName" :size="38"
:url="userStore.userInfo.headImageThumb" @click.native="showSettingDialog = true">
<!-- 用户头像区域 - 点击打开账号切换菜单 -->
<div class="user-head-image-wrapper">
<div class="user-head-image" @click.stop="toggleAccountMenu">
<head-image
:name="userStore.userInfo.nickName"
:size="38"
:url="userStore.userInfo.headImageThumb">
</head-image>
<!-- 账号切换标识 -->
<!-- <div class="account-indicator">
<span class="account-name">{{ userStore.userInfo.userName }}</span>
<i class="el-icon-arrow-down" :class="{ active: showAccountMenu }"></i>
</div> -->
</div>
</div>
<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">
<span class="icon iconfont icon-chat"></span>
<div v-show="unreadCount > 0" class="unread-text">{{ unreadCount }}</div>
</div>
</router-link>
<router-link class="link" v-bind:to="'/home/friend'">
</router-link> -->
<!-- <router-link class="link" v-bind:to="'/home/friend'">
<div class="menu-item">
<span class="icon iconfont icon-friend"></span>
</div>
</router-link>
</router-link> -->
<!-- <router-link class="link" v-bind:to="'/home/group'">
<div class="menu-item">
<span class="icon iconfont icon-group" style="font-size: 28px"></span>
@ -42,9 +53,29 @@
</div>
</div>
</div>
<div class="content-box">
<router-view></router-view>
</div>
<!-- 账号切换菜单 -->
<account-switch-menu
:visible="showAccountMenu"
:currentUser="userStore.userInfo"
:position="menuPosition"
@switch="onSwitchAccount"
@add-account="onAddAccount"
@logout="onExit"
@close="showAccountMenu = false">
</account-switch-menu>
<!-- 遮罩层 -->
<div
v-if="showAccountMenu"
class="menu-mask"
@click="showAccountMenu = false">
</div>
<setting :visible="showSettingDialog" @close="closeSetting()"></setting>
<user-info ref="userInfo"></user-info>
<full-image ref="fullImage"></full-image>
@ -62,6 +93,7 @@ import FullImage from '../components/common/FullImage.vue';
import RtcPrivateVideo from '../components/rtc/RtcPrivateVideo.vue';
import RtcPrivateAcceptor from '../components/rtc/RtcPrivateAcceptor.vue';
import RtcGroupVideo from '../components/rtc/RtcGroupVideo.vue';
import AccountSwitchMenu from '../components/account/AccountSwitchMenu.vue';
export default {
components: {
@ -71,11 +103,14 @@ export default {
FullImage,
RtcPrivateVideo,
RtcPrivateAcceptor,
RtcGroupVideo
RtcGroupVideo,
AccountSwitchMenu
},
data() {
return {
showSettingDialog: false,
showAccountMenu: false,
menuPosition: { x: 0, y: 0 },
lastPlayAudioTime: new Date().getTime() - 1000,
reconnecting: false,
privateMessagesBuffer: [],
@ -85,22 +120,20 @@ export default {
methods: {
init() {
this.$eventBus.$on('openPrivateVideo', (rctInfo) => {
//
this.$refs.rtcPrivateVideo.open(rctInfo);
});
this.$eventBus.$on('openGroupVideo', (rctInfo) => {
//
this.$refs.rtcGroupVideo.open(rctInfo);
});
this.$eventBus.$on('openUserInfo', (user, pos) => {
//
this.$refs.userInfo.open(user, pos);
});
this.$eventBus.$on('openFullImage', url => {
//
this.$refs.fullImage.open(url);
});
this.configStore.setAppInit(false)
this.configStore.setAppInit(false);
this.loadStore().then(() => {
// ws
this.$wsApi.connect(process.env.VUE_APP_WS_URL, sessionStorage.getItem("accessToken"));
@ -108,16 +141,14 @@ export default {
if (this.reconnecting) {
this.onReconnectWs();
} else {
// 线
this.pullOfflineMessage();
this.configStore.setAppInit(true);
}
});
this.$wsApi.onMessage((cmd, msgInfo) => {
if (cmd == 2) {
// ws
this.$wsApi.close(3000)
// 线
this.$wsApi.close(3000);
this.$alert("您已在其他地方登录,将被强制下线", "强制下线通知", {
confirmButtonText: '确定',
callback: action => {
@ -126,69 +157,156 @@ export default {
});
} else if (cmd == 3) {
if (!this.configStore.appInit || this.chatStore.loading) {
// 线
this.privateMessagesBuffer.push(msgInfo);
} else {
//
this.handlePrivateMessage(msgInfo);
}
} else if (cmd == 4) {
if (!this.configStore.appInit || this.chatStore.loading) {
// 线
this.groupMessagesBuffer.push(msgInfo);
} else {
//
this.handleGroupMessage(msgInfo);
}
} else if (cmd == 5) {
//
this.handleSystemMessage(msgInfo);
}
});
this.$wsApi.onClose((e) => {
if (e.code != 3000) {
// 线
if (!this.reconnecting) {
this.reconnectWs();
this.configStore.setAppInit(false)
this.configStore.setAppInit(false);
}
}
});
}).catch((e) => {
console.log("初始化失败", e);
})
});
},
//
toggleAccountMenu(event) {
if (this.showAccountMenu) {
this.showAccountMenu = false;
return;
}
const trigger = event.currentTarget;
const rect = trigger.getBoundingClientRect();
//
this.menuPosition = {
x: rect.right + 10,
y: rect.top
};
this.showAccountMenu = true;
},
//
async onSwitchAccount(targetUser) {
this.showAccountMenu = false;
const loading = this.$loading({
lock: true,
text: '正在切换账号...',
spinner: 'el-icon-loading'
});
try {
const res = await this.$http({
url: '/user/switchAccount',
method: 'post',
data: {
targetUserId: targetUser.id,
terminal: this.getTerminalType()
}
});
const loginData = res;
if (loginData.user) {
this.setCookie('username', loginData.user.userName);
sessionStorage.setItem("accessToken", loginData.accessToken);
sessionStorage.setItem("refreshToken", loginData.refreshToken);
localStorage.setItem('userInfo', JSON.stringify(loginData.user));
this.userStore.setUserInfo(loginData.user);
}
loading.close();
this.$message.success(`已切换到客服账号:${targetUser.nickName}`);
// WebSocket
this.$wsApi.close(3000);
setTimeout(() => {
window.location.reload();
}, 300);
} catch (error) {
loading.close();
if (error !== 'cancel') {
console.error('切换账号失败:', error);
this.$message.error('切换账号失败');
}
}
},
//
getTerminalType() {
const userAgent = navigator.userAgent;
if (/mobile/i.test(userAgent)) {
return 2;
}
if (/tablet/i.test(userAgent)) {
return 3;
}
return 1;
},
setCookie(name, value) {
document.cookie = name + "=" + escape(value);
},
//
onAddAccount() {
this.showAccountMenu = false;
//
this.unloadStore();
this.configStore.setAppInit(false);
this.$wsApi.close(3000);
sessionStorage.removeItem("accessToken");
location.href = "/";
},
reconnectWs() {
//
this.reconnecting = true;
// token
this.userStore.loadUser().then(() => {
// 线
this.$message.error("连接断开,正在尝试重新连接...");
this.$wsApi.reconnect(process.env.VUE_APP_WS_URL, sessionStorage.getItem(
"accessToken"));
this.$wsApi.reconnect(process.env.VUE_APP_WS_URL, sessionStorage.getItem("accessToken"));
}).catch(() => {
// 10s
setTimeout(() => this.reconnectWs(), 10000)
})
setTimeout(() => this.reconnectWs(), 10000);
});
},
onReconnectWs() {
//
this.reconnecting = false;
//
const promises = [];
promises.push(this.friendStore.loadFriend());
promises.push(this.groupStore.loadGroup());
Promise.all(promises).then(() => {
// 线
this.pullOfflineMessage();
this.configStore.setAppInit(true)
this.configStore.setAppInit(true);
this.$message.success("重新连接成功");
}).catch(() => {
this.$message.error("初始化失败");
this.onExit();
})
});
},
loadStore() {
return this.userStore.loadUser().then(() => {
const promises = [];
@ -197,105 +315,94 @@ export default {
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();
},
pullOfflineMessage() {
this.chatStore.setLoading(true);
const promises = [];
promises.push(this.pullPrivateOfflineMessage(this.chatStore.privateMsgMaxId));
promises.push(this.pullGroupOfflineMessage(this.chatStore.groupMsgMaxId));
Promise.all(promises).then(messages => {
// 线
messages[0].forEach(m => this.handlePrivateMessage(m));
messages[1].forEach(m => this.handleGroupMessage(m));
//
this.privateMessagesBuffer.forEach(m => this.handlePrivateMessage(m));
this.groupMessagesBuffer.forEach(m => this.handleGroupMessage(m));
//
this.privateMessagesBuffer = [];
this.groupMessagesBuffer = [];
// 线
this.chatStore.setLoading(false);
//
this.chatStore.refreshChats();
}).catch((e) => {
console.log(e)
console.log(e);
this.$message.error("拉取离线消息失败");
this.onExit();
})
});
},
pullPrivateOfflineMessage(minId) {
return this.$http({
url: "/message/private/loadOfflineMessage?minId=" + minId,
method: 'GET'
})
});
},
pullGroupOfflineMessage(minId) {
return this.$http({
url: "/message/group/loadOfflineMessage?minId=" + minId,
method: 'GET'
})
});
},
handlePrivateMessage(msg) {
//
msg.selfSend = msg.sendId == this.userStore.userInfo.id;
// id
let friendId = msg.selfSend ? msg.recvId : msg.sendId;
//
let chatInfo = {
type: 'PRIVATE',
targetId: friendId
}
//
};
if (msg.type == this.$enums.MESSAGE_TYPE.READED) {
this.chatStore.resetUnreadCount(chatInfo)
this.chatStore.resetUnreadCount(chatInfo);
return;
}
// ,
if (msg.type == this.$enums.MESSAGE_TYPE.RECEIPT) {
this.chatStore.readedMessage({
friendId: msg.sendId
})
this.chatStore.readedMessage({ friendId: msg.sendId });
return;
}
//
if (msg.type == this.$enums.MESSAGE_TYPE.RECALL) {
this.chatStore.recallMessage(msg, chatInfo)
this.chatStore.recallMessage(msg, chatInfo);
return;
}
//
if (msg.type == this.$enums.MESSAGE_TYPE.FRIEND_NEW) {
this.friendStore.addFriend(JSON.parse(msg.content));
return;
}
//
if (msg.type == this.$enums.MESSAGE_TYPE.FRIEND_DEL) {
this.friendStore.removeFriend(friendId);
return;
}
//
if (msg.type == this.$enums.MESSAGE_TYPE.FRIEND_DND) {
this.friendStore.setDnd(friendId, JSON.parse(msg.content));
this.chatStore.setDnd(chatInfo, JSON.parse(msg.content));
return;
}
// webrtc
if (this.$msgType.isRtcPrivate(msg.type)) {
this.$refs.rtcPrivateVideo.onRTCMessage(msg)
this.$refs.rtcPrivateVideo.onRTCMessage(msg);
return;
}
//
if (this.$msgType.isNormal(msg.type) || this.$msgType.isTip(msg.type) || this.$msgType.isAction(msg.type)) {
let friend = this.loadFriendInfo(friendId);
this.insertPrivateMessage(friend, msg);
}
},
insertPrivateMessage(friend, msg) {
let chatInfo = {
type: 'PRIVATE',
@ -304,75 +411,64 @@ export default {
headImage: friend.headImage,
isDnd: friend.isDnd
};
//
this.chatStore.openChat(chatInfo);
//
this.chatStore.insertMessage(msg, chatInfo);
//
if (!friend.isDnd && !this.chatStore.loading && !msg.selfSend && this.$msgType.isNormal(msg.type) &&
msg.status != this.$enums.MESSAGE_STATUS.READED) {
if (!friend.isDnd && !this.chatStore.loading && !msg.selfSend &&
this.$msgType.isNormal(msg.type) && msg.status != this.$enums.MESSAGE_STATUS.READED) {
this.playAudioTip();
}
},
handleGroupMessage(msg) {
//
msg.selfSend = msg.sendId == this.userStore.userInfo.id;
let chatInfo = {
type: 'GROUP',
targetId: msg.groupId
}
//
};
if (msg.type == this.$enums.MESSAGE_TYPE.READED) {
//
this.chatStore.resetUnreadCount(chatInfo)
this.chatStore.resetUnreadCount(chatInfo);
return;
}
//
if (msg.type == this.$enums.MESSAGE_TYPE.RECEIPT) {
//
let msgInfo = {
id: msg.id,
groupId: msg.groupId,
readedCount: msg.readedCount,
receiptOk: msg.receiptOk
};
this.chatStore.updateMessage(msgInfo, chatInfo)
this.chatStore.updateMessage(msgInfo, chatInfo);
return;
}
//
if (msg.type == this.$enums.MESSAGE_TYPE.RECALL) {
this.chatStore.recallMessage(msg, chatInfo)
this.chatStore.recallMessage(msg, chatInfo);
return;
}
//
if (msg.type == this.$enums.MESSAGE_TYPE.GROUP_NEW) {
this.groupStore.addGroup(JSON.parse(msg.content));
return;
}
//
if (msg.type == this.$enums.MESSAGE_TYPE.GROUP_DEL) {
this.groupStore.removeGroup(msg.groupId);
return;
}
//
if (msg.type == this.$enums.MESSAGE_TYPE.GROUP_DND) {
this.groupStore.setDnd(msg.groupId, JSON.parse(msg.content));
this.chatStore.setDnd(chatInfo, JSON.parse(msg.content));
return;
}
//
if (this.$msgType.isRtcGroup(msg.type)) {
this.$nextTick(() => {
this.$refs.rtcGroupVideo.onRTCMessage(msg);
})
});
return;
}
//
if (this.$msgType.isNormal(msg.type) || this.$msgType.isTip(msg.type) || this.$msgType.isAction(msg.type)) {
let group = this.loadGroupInfo(msg.groupId);
this.insertGroupMessage(group, msg);
}
},
insertGroupMessage(group, msg) {
let chatInfo = {
type: 'GROUP',
@ -381,19 +477,15 @@ export default {
headImage: group.headImageThumb,
isDnd: group.isDnd
};
//
this.chatStore.openChat(chatInfo);
//
this.chatStore.insertMessage(msg, chatInfo);
//
if (!group.isDnd && !this.chatStore.loading &&
!msg.selfSend && this.$msgType.isNormal(msg.type) &&
msg.status != this.$enums.MESSAGE_STATUS.READED) {
if (!group.isDnd && !this.chatStore.loading && !msg.selfSend &&
this.$msgType.isNormal(msg.type) && msg.status != this.$enums.MESSAGE_STATUS.READED) {
this.playAudioTip();
}
},
handleSystemMessage(msg) {
//
if (msg.type == this.$enums.MESSAGE_TYPE.USER_BANNED) {
this.$wsApi.close(3000);
this.$alert("您的账号已被管理员封禁,原因:" + msg.content, "账号被封禁", {
@ -405,21 +497,28 @@ export default {
return;
}
},
closeUserInfo() {
if (this.$refs.userInfo) {
this.$refs.userInfo.close();
}
this.showAccountMenu = false;
},
onSwtichFullScreen() {
this.configStore.setFullScreen(!this.configStore.fullScreen);
},
onExit() {
this.showAccountMenu = false;
this.unloadStore();
this.configStore.setAppInit(false);
this.$wsApi.close(3000);
sessionStorage.removeItem("accessToken");
location.href = "/";
},
playAudioTip() {
//
if (new Date().getTime() - this.lastPlayAudioTime > 1000) {
this.lastPlayAudioTime = new Date().getTime();
let audio = new Audio();
@ -427,25 +526,28 @@ export default {
audio.src = url;
audio.play();
}
},
showSetting() {
this.showSettingDialog = true;
},
closeSetting() {
this.showSettingDialog = false;
},
loadFriendInfo(id) {
let friend = this.friendStore.findFriend(id);
if (!friend) {
friend = {
id: id,
showNickName: "未知用户",
nickName: "未知用户",
headImage: ""
}
};
}
return friend;
},
loadGroupInfo(id) {
let group = this.groupStore.findGroup(id);
if (!group) {
@ -453,7 +555,7 @@ export default {
id: id,
showGroupName: "未知群聊",
headImageThumb: ""
}
};
}
return group;
}
@ -464,7 +566,7 @@ export default {
let chats = this.chatStore.chats;
chats.forEach(chat => {
if (!chat.delete && !chat.isDnd) {
unreadCount += chat.unreadCount
unreadCount += chat.unreadCount;
}
});
return unreadCount;
@ -485,7 +587,7 @@ export default {
unmounted() {
this.$wsApi.close();
}
}
};
</script>
<style scoped lang="scss">
@ -536,9 +638,57 @@ export default {
}
}
.user-head-image-wrapper {
display: flex;
flex-direction: column;
align-items: center;
.user-head-image {
display: flex;
flex-direction: column;
align-items: center;
cursor: pointer;
transition: all 0.2s;
&:hover {
transform: scale(1.05);
.account-indicator {
background: rgba(255, 255, 255, 0.25);
}
}
.account-indicator {
display: flex;
align-items: center;
justify-content: center;
margin-top: 8px;
padding: 4px 10px;
background: rgba(255, 255, 255, 0.15);
border-radius: 12px;
transition: all 0.2s;
max-width: 65px;
.account-name {
font-size: 11px;
color: #fff;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
margin-right: 3px;
}
.el-icon-arrow-down {
font-size: 12px;
color: rgba(255, 255, 255, 0.8);
transition: transform 0.2s;
&.active {
transform: rotate(180deg);
}
}
}
}
}
.menu {
@ -566,9 +716,8 @@ export default {
.menu-item {
position: relative;
color: #eee;
width: var(--width);
height: 46px;
width: 46px;
height: 46px;
display: flex;
justify-content: center;
align-items: center;
@ -576,7 +725,7 @@ export default {
border-radius: 10px;
.icon {
font-size: var(--icon-font-size)
font-size: var(--icon-font-size);
}
.unread-text {
@ -606,7 +755,7 @@ export default {
font-size: var(--icon-font-size);
.icon {
font-size: var(--icon-font-size)
font-size: var(--icon-font-size);
}
&:hover {
@ -623,4 +772,14 @@ export default {
text-align: center;
}
}
.menu-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 9998;
background: transparent;
}
</style>
Loading…
Cancel
Save