Browse Source

将用户语言信息保存到数据库

master
[yxf] 4 weeks ago
parent
commit
4c4a84c40f
  1. 46
      im-platform/src/main/java/com/bx/implatform/controller/UserController.java
  2. 6
      im-platform/src/main/java/com/bx/implatform/entity/User.java
  3. 4
      im-platform/src/main/java/com/bx/implatform/vo/UserVO.java
  4. 72
      im-uniapp/pages/chat/chat-box.vue
  5. 4
      im-uniapp/store/chatStore.js
  6. 21
      im-web/src/components/chat/ChatBox.vue

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

@ -68,7 +68,7 @@ public class UserController {
@Operation(summary = "保存用户分组", description = "单个分组,保存到 group_ids 字段") @Operation(summary = "保存用户分组", description = "单个分组,保存到 group_ids 字段")
public Result<?> saveGroup(@RequestBody JSONObject jsonObject) { public Result<?> saveGroup(@RequestBody JSONObject jsonObject) {
Long userId = jsonObject.getLong("userId"); Long userId = jsonObject.getLong("userId");
String groupId = jsonObject.getStr("groupIds"); // 前端传分组ID String groupId = jsonObject.getStr("groupIds");
userService.saveUserGroup(userId, groupId); userService.saveUserGroup(userId, groupId);
return ResultUtils.success(); return ResultUtils.success();
@ -104,6 +104,27 @@ public class UserController {
return ResultUtils.success(); return ResultUtils.success();
} }
@PostMapping("/updateLanguage")
@Operation(summary = "更新用户语言", description = "更新当前用户的语言设置:zh/en/jp/kor等")
public Result<?> updateLanguage(@RequestBody JSONObject jsonObject) {
String language = jsonObject.getStr("language");
if (StrUtil.isBlank(language)) {
return ResultUtils.error(ResultCode.XSS_PARAM_ERROR, "语言不能为空");
}
UserSession session = SessionContext.getSession();
Long userId = session.getUserId();
User user = userService.getById(userId);
if (user == null) {
return ResultUtils.error(ResultCode.XSS_PARAM_ERROR, "用户不存在");
}
user.setLanguage(language);
boolean success = userService.updateById(user);
return success ? ResultUtils.success("语言更新成功") : ResultUtils.error(ResultCode.XSS_PARAM_ERROR, "更新失败");
}
@GetMapping("/findByName") @GetMapping("/findByName")
@Operation(summary = "查找用户", description = "根据用户名或昵称查找用户") @Operation(summary = "查找用户", description = "根据用户名或昵称查找用户")
public Result<List<UserVO>> findByName(@RequestParam String name) { public Result<List<UserVO>> findByName(@RequestParam String name) {
@ -113,18 +134,15 @@ public class UserController {
@PostMapping("/getEnableChangeCustomer") @PostMapping("/getEnableChangeCustomer")
@Operation(summary = "获取可转接的客服", description = "转接客服") @Operation(summary = "获取可转接的客服", description = "转接客服")
public Result<List<Map<String, Object>>> getEnableChangeCustomer() { public Result<List<Map<String, Object>>> getEnableChangeCustomer() {
// 获取当前客服id、转接客服id、转接用户id
UserSession session = SessionContext.getSession(); UserSession session = SessionContext.getSession();
Long userId = session.getUserId(); Long userId = session.getUserId();
if(ObjectUtil.isNull(userId)){ if(ObjectUtil.isNull(userId)){
return ResultUtils.error(XSS_PARAM_ERROR); return ResultUtils.error(XSS_PARAM_ERROR);
} }
List<User> list = userService.getEnableChangeCustomerList(userId); List<User> list = userService.getEnableChangeCustomerList(userId);
//使用Map返回id、昵称
List<Map<String, Object>> result = list.stream().map(user -> { List<Map<String, Object>> result = list.stream().map(user -> {
Map<String, Object> map = new HashMap<>(); Map<String, Object> map = new HashMap<>();
map.put("id", user.getId()); map.put("id", user.getId());
@ -152,7 +170,6 @@ public class UserController {
return ResultUtils.error(XSS_PARAM_ERROR); return ResultUtils.error(XSS_PARAM_ERROR);
} }
// 获取当前用户信息
User currentUser = userService.getById(userId); User currentUser = userService.getById(userId);
if (currentUser == null) { if (currentUser == null) {
return ResultUtils.error(XSS_PARAM_ERROR); return ResultUtils.error(XSS_PARAM_ERROR);
@ -160,7 +177,6 @@ public class UserController {
Map<String, Object> result = new HashMap<>(); Map<String, Object> result = new HashMap<>();
// 获取可切换的账号ID列表(逗号分隔的字符串,如 "13,14")
String switchableIdsStr = currentUser.getSwitchableAccountIds(); String switchableIdsStr = currentUser.getSwitchableAccountIds();
List<Map<String, Object>> switchableUsers = new ArrayList<>(); List<Map<String, Object>> switchableUsers = new ArrayList<>();
@ -173,7 +189,6 @@ public class UserController {
if (!ids.isEmpty()) { if (!ids.isEmpty()) {
List<User> users = userService.listByIds(ids); List<User> users = userService.listByIds(ids);
// 过滤掉被封禁的账号
users = users.stream() users = users.stream()
.filter(u -> !Boolean.TRUE.equals(u.getIsBanned())) .filter(u -> !Boolean.TRUE.equals(u.getIsBanned()))
.collect(Collectors.toList()); .collect(Collectors.toList());
@ -192,27 +207,21 @@ public class UserController {
result.put("switchableUsers", switchableUsers); result.put("switchableUsers", switchableUsers);
// 获取当前用户的 unique_token
String currentUserUniqueToken = currentUser.getUniqueToken(); String currentUserUniqueToken = currentUser.getUniqueToken();
// 构建查询条件
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<User>() LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<User>()
.eq(User::getIsCustomer, 2) .eq(User::getIsCustomer, 2)
.ne(User::getId, userId) .ne(User::getId, userId)
.eq(User::getIsBanned, 0); .eq(User::getIsBanned, 0);
// 添加 unique_token 条件
if (StrUtil.isNotBlank(currentUserUniqueToken)) { if (StrUtil.isNotBlank(currentUserUniqueToken)) {
// 当前用户有 unique_token,只查询相同 unique_token 的客服
queryWrapper.eq(User::getUniqueToken, currentUserUniqueToken); queryWrapper.eq(User::getUniqueToken, currentUserUniqueToken);
} else { } else {
// 当前用户没有 unique_token,只查询也没有 unique_token 的客服
queryWrapper.isNull(User::getUniqueToken).or().eq(User::getUniqueToken, ""); queryWrapper.isNull(User::getUniqueToken).or().eq(User::getUniqueToken, "");
} }
List<User> availableUsers = userService.list(queryWrapper); List<User> availableUsers = userService.list(queryWrapper);
// 获取已添加的ID集合
Set<Long> existingIds = new HashSet<>(); Set<Long> existingIds = new HashSet<>();
if (StrUtil.isNotBlank(switchableIdsStr)) { if (StrUtil.isNotBlank(switchableIdsStr)) {
Arrays.stream(switchableIdsStr.split(",")) Arrays.stream(switchableIdsStr.split(","))
@ -221,14 +230,12 @@ public class UserController {
.forEach(existingIds::add); .forEach(existingIds::add);
} }
// 标记是否已添加
List<Map<String, Object>> availableUsersList = availableUsers.stream().map(user -> { List<Map<String, Object>> availableUsersList = availableUsers.stream().map(user -> {
Map<String, Object> map = new HashMap<>(); Map<String, Object> map = new HashMap<>();
map.put("id", user.getId()); map.put("id", user.getId());
map.put("userName", user.getUserName()); map.put("userName", user.getUserName());
map.put("nickName", user.getNickName()); map.put("nickName", user.getNickName());
map.put("headImage", user.getHeadImage()); map.put("headImage", user.getHeadImage());
// map.put("headImageThumb", user.getHeadImageThumb());
map.put("isAdded", existingIds.contains(user.getId())); map.put("isAdded", existingIds.contains(user.getId()));
return map; return map;
}).collect(Collectors.toList()); }).collect(Collectors.toList());
@ -244,7 +251,6 @@ public class UserController {
UserSession session = SessionContext.getSession(); UserSession session = SessionContext.getSession();
// 获取当前客服id、转接客服id、转接用户id
Long customerId = session.getUserId(); Long customerId = session.getUserId();
Long targetId = jsonObject.getLong("targetId"); Long targetId = jsonObject.getLong("targetId");
Long userId = jsonObject.getLong("userId"); Long userId = jsonObject.getLong("userId");
@ -267,22 +273,18 @@ public class UserController {
Long targetUserId = jsonObject.getLong("targetUserId"); Long targetUserId = jsonObject.getLong("targetUserId");
Integer terminal = jsonObject.getInt("terminal"); Integer terminal = jsonObject.getInt("terminal");
// 获取当前登录用户
UserSession currentSession = SessionContext.getSession(); UserSession currentSession = SessionContext.getSession();
User currentUser = userService.getById(currentSession.getUserId()); User currentUser = userService.getById(currentSession.getUserId());
// 权限校验:只有客服才能切换账号
if (currentUser.getIsCustomer() != 2) { if (currentUser.getIsCustomer() != 2) {
return ResultUtils.error(XSS_PARAM_ERROR, "无权限切换账号"); return ResultUtils.error(XSS_PARAM_ERROR, "无权限切换账号");
} }
// 获取目标用户信息
User targetUser = userService.getById(targetUserId); User targetUser = userService.getById(targetUserId);
if (ObjectUtil.isNull(targetUser)) { if (ObjectUtil.isNull(targetUser)) {
return ResultUtils.error(ResultCode.XSS_PARAM_ERROR, "目标用户不存在"); return ResultUtils.error(ResultCode.XSS_PARAM_ERROR, "目标用户不存在");
} }
// 生成新的token
UserSession newSession = BeanUtils.copyProperties(targetUser, UserSession.class); UserSession newSession = BeanUtils.copyProperties(targetUser, UserSession.class);
newSession.setUserId(targetUser.getId()); newSession.setUserId(targetUser.getId());
newSession.setTerminal(terminal); newSession.setTerminal(terminal);
@ -299,8 +301,6 @@ public class UserController {
vo.setRefreshTokenExpiresIn(jwtProperties.getRefreshTokenExpireIn()); vo.setRefreshTokenExpiresIn(jwtProperties.getRefreshTokenExpireIn());
vo.setUser(targetUser); vo.setUser(targetUser);
// log.info("账号切换:从用户 {} 切换到用户 {}", currentSession.getUserId(), targetUserId);
return ResultUtils.success(vo); return ResultUtils.success(vo);
} }
@ -319,7 +319,6 @@ public class UserController {
return ResultUtils.error(XSS_PARAM_ERROR); return ResultUtils.error(XSS_PARAM_ERROR);
} }
// 取出可切换账号并移除目标ID
String switchableIdsStr = currentUser.getSwitchableAccountIds(); String switchableIdsStr = currentUser.getSwitchableAccountIds();
if (StrUtil.isBlank(switchableIdsStr)) { if (StrUtil.isBlank(switchableIdsStr)) {
return ResultUtils.success("移除成功"); return ResultUtils.success("移除成功");
@ -333,7 +332,6 @@ public class UserController {
String newIds = idList.stream().map(String::valueOf).collect(Collectors.joining(",")); String newIds = idList.stream().map(String::valueOf).collect(Collectors.joining(","));
// 更新到数据库
currentUser.setSwitchableAccountIds(newIds); currentUser.setSwitchableAccountIds(newIds);
userService.updateById(currentUser); userService.updateById(currentUser);

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

@ -134,6 +134,8 @@ public class User {
*/ */
private String switchableAccountIds; private String switchableAccountIds;
/**
* 语言
*/
private String language;
} }

4
im-platform/src/main/java/com/bx/implatform/vo/UserVO.java

@ -78,6 +78,8 @@ public class UserVO {
// 修改为完整的UserGroup列表 // 修改为完整的UserGroup列表
private List<UserLabelVO> labelList; // 完整的分组信息列表 private List<UserLabelVO> labelList; // 完整的分组信息列表
private String platformName; // 新增:平台名称 private String platformName;
private String language;
} }

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

@ -268,8 +268,8 @@ export default {
isFileOpen: false, isFileOpen: false,
isPasting: false, isPasting: false,
hasPasteListener: false, hasPasteListener: false,
currentLang: 'zh',
showLangModal: false, // showLangModal: false, //
currentLang: uni.getStorageSync("app_language") || "zh",
langList: [ langList: [
{ label: "中文", value: "zh" }, { label: "中文", value: "zh" },
{ label: "English", value: "en" }, { label: "English", value: "en" },
@ -285,17 +285,25 @@ export default {
}; };
}, },
methods: { methods: {
// //
selectLang(lang) { selectLang(lang) {
this.currentLang = lang; this.currentLang = lang;
this.$i18n.locale = lang;
uni.setStorageSync("app_language", lang);
this.showLangDrop = false; this.showLangDrop = false;
setTimeout(() => { //
window.location.reload(); // H5 this.$http({
}, 100); url: "/user/updateLanguage",
method: "POST",
data: { language: lang }
}).then(() => {
console.log("语言保存成功");
}).finally(() => {
this.$i18n.locale = lang;
uni.setStorageSync("app_language", lang);
setTimeout(() => {
window.location.reload();
}, 100);
});
}, },
loadCommonQuestions(userId) { loadCommonQuestions(userId) {
this.$http({ this.$http({
@ -1257,13 +1265,18 @@ export default {
this.chatStore.updateChatFromUser(this.userInfo); this.chatStore.updateChatFromUser(this.userInfo);
} }
}, },
loadFriend(friendId) { async loadFriend(friendId) {
this.$http({ return new Promise((resolve) => {
url: `/user/find/${friendId}`, this.$http({
method: "GET", url: `/user/find/${friendId}`,
}).then((userInfo) => { method: "GET",
this.userInfo = userInfo; }).then((userInfo) => {
this.updateFriendInfo(); this.userInfo = userInfo;
this.updateFriendInfo();
resolve(); // then
}).catch(() => {
resolve();
});
}); });
}, },
rpxTopx(rpx) { rpxTopx(rpx) {
@ -1648,7 +1661,9 @@ export default {
} }
this.readedMessage(); this.readedMessage();
this.loadFriend(targetId); // this.loadFriend(targetId);
await this.loadFriend(targetId);
this.loadReaded(targetId); this.loadReaded(targetId);
this.loadCommonQuestions(targetId); this.loadCommonQuestions(targetId);
@ -1659,23 +1674,7 @@ export default {
await this.getSetting(); await this.getSetting();
this.$nextTick(() => this.scrollToBottom()); this.$nextTick(() => this.scrollToBottom());
this.$socket.on('customer_transfer', (data) => {
/**
* data后端返回格式
* { oldKfId: 旧客服ID, newKfId: 新客服ID }
*/
const { oldKfId, newKfId } = data;
if (!oldKfId || !newKfId) return;
// chatStore
this.chatStore.mergeOldCustomerToNew(oldKfId, newKfId);
console.log(data);
//
this.currentTargetId = newKfId;
this.$nextTick(() => {
this.scrollToBottom();
});
})
} catch (err) { } catch (err) {
console.error("错误:", err); console.error("错误:", err);
} finally { } finally {
@ -1696,11 +1695,10 @@ export default {
</script> </script>
<style lang="scss"> <style lang="scss">
/* ========== 右上角语言按钮 ========== */
.lang-wrap { .lang-wrap {
position: fixed; position: fixed;
top: var(--status-bar-height); top: var(--status-bar-height);
right: 40rpx; /* 按钮靠右距离,美观不贴边 */ right: 40rpx;
z-index: 9999 !important; z-index: 9999 !important;
height: $im-nav-bar-height; height: $im-nav-bar-height;
display: flex; display: flex;
@ -1718,11 +1716,10 @@ export default {
cursor: pointer; cursor: pointer;
} }
/* ========== 自定义下拉面板(向左展开!永远不裁切) ========== */
.lang-drop-panel { .lang-drop-panel {
position: absolute; position: absolute;
top: 100%; top: 100%;
right: 0; /* 面板右边缘和按钮右边缘对齐,**向左展开** */ right: 0;
min-width: 180rpx; min-width: 180rpx;
background: #fff; background: #fff;
border-radius: 12rpx; border-radius: 12rpx;
@ -1732,7 +1729,6 @@ export default {
z-index: 10000; z-index: 10000;
} }
/* 下拉每一个语言选项 */
.lang-drop-item { .lang-drop-item {
padding: 24rpx 30rpx; padding: 24rpx 30rpx;
font-size: 28rpx; font-size: 28rpx;
@ -1751,7 +1747,6 @@ export default {
} }
} }
/* ========== 全局遮罩(点击空白关闭下拉) ========== */
.lang-mask { .lang-mask {
position: fixed; position: fixed;
top: 0; top: 0;
@ -1761,7 +1756,6 @@ export default {
z-index: 9998; z-index: 9998;
} }
/* 原有标题样式不动 */
.nav-title-wrapper { .nav-title-wrapper {
width: 100%; width: 100%;
text-align: center; text-align: center;

4
im-uniapp/store/chatStore.js

@ -209,8 +209,6 @@ export default defineStore('chatStore', {
this.saveToStorage(); this.saveToStorage();
return; return;
} }
// ====================== 多语言消息类型 ======================
if (msgInfo.type == MESSAGE_TYPE.IMAGE) { if (msgInfo.type == MESSAGE_TYPE.IMAGE) {
chat.lastContent = t('chat.image'); chat.lastContent = t('chat.image');
} else if (msgInfo.type == MESSAGE_TYPE.FILE) { } else if (msgInfo.type == MESSAGE_TYPE.FILE) {
@ -226,7 +224,6 @@ export default defineStore('chatStore', {
msgInfo.type == MESSAGE_TYPE.TIP_TEXT) { msgInfo.type == MESSAGE_TYPE.TIP_TEXT) {
chat.lastContent = msgInfo.content; chat.lastContent = msgInfo.content;
} }
// ============================================================
chat.lastSendTime = msgInfo.sendTime; chat.lastSendTime = msgInfo.sendTime;
chat.sendNickName = msgInfo.sendNickName; chat.sendNickName = msgInfo.sendNickName;
@ -323,6 +320,7 @@ export default defineStore('chatStore', {
chat.stored = false; chat.stored = false;
this.saveToStorage(isColdMessage); this.saveToStorage(isColdMessage);
}, },
updateChatFromFriend(friend) { updateChatFromFriend(friend) {
let chat = this.findChatByFriend(friend.id) let chat = this.findChatByFriend(friend.id)
if (chat && (chat.headImage != friend.headImage || if (chat && (chat.headImage != friend.headImage ||

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

@ -165,6 +165,10 @@
<div class="info-label">来源地址</div> <div class="info-label">来源地址</div>
<div class="info-value">{{ userInfo.platformName }}</div> <div class="info-value">{{ userInfo.platformName }}</div>
</div> </div>
<div class="info-item">
<div class="info-label">用户语言</div>
<div class="info-value">{{ getLanguageText(userInfo.language) }}</div>
</div>
<div class="info-item"> <div class="info-item">
<div class="info-label">标签</div> <div class="info-label">标签</div>
<div class="info-value"> <div class="info-value">
@ -340,6 +344,7 @@ export default {
maxTmpId: 0, maxTmpId: 0,
countryCode: "en", countryCode: "en",
countryCodeList: [ countryCodeList: [
{ label: "中文", value: "zh" },
{ label: "英语", value: "en" }, { label: "英语", value: "en" },
{ label: "日语", value: "jp" }, { label: "日语", value: "jp" },
{ label: "韩语", value: "kor" }, { label: "韩语", value: "kor" },
@ -353,6 +358,22 @@ export default {
}; };
}, },
methods: { methods: {
getLanguageText(lang) {
if (!lang) return '未知';
const langMap = {
'zh': '中文',
'en': '英语',
'jp': '日语',
'kor': '韩语',
'vie': '越南语',
'ru': '俄语',
'de': '德语',
'fra': '法语',
'pt': '葡萄牙语',
'ara': '阿拉伯语',
};
return langMap[lang.toLowerCase()] || lang;
},
moveChatToTop() { moveChatToTop() {
let chatIdx = this.chatStore.findChatIdx(this.chat); let chatIdx = this.chatStore.findChatIdx(this.chat);
this.chatStore.moveTop(chatIdx); this.chatStore.moveTop(chatIdx);

Loading…
Cancel
Save