Browse Source

修改切换账号功能可以删除账号,新增撤回消息语言

master
[yxf] 4 weeks ago
parent
commit
62fc8c7caf
  1. 37
      im-platform/src/main/java/com/bx/implatform/controller/UserController.java
  2. 170
      im-uniapp/App.vue
  3. 18
      im-uniapp/pages/chat/chat-box.vue
  4. 6
      im-uniapp/static/i18n/ara.json
  5. 6
      im-uniapp/static/i18n/de.json
  6. 7
      im-uniapp/static/i18n/en.json
  7. 6
      im-uniapp/static/i18n/fra.json
  8. 34
      im-uniapp/static/i18n/jp.json
  9. 34
      im-uniapp/static/i18n/kor.json
  10. 6
      im-uniapp/static/i18n/pt.json
  11. 22
      im-uniapp/static/i18n/ru.json
  12. 14
      im-uniapp/static/i18n/vie.json
  13. 9
      im-uniapp/static/i18n/zh.json
  14. 147
      im-uniapp/store/chatStore.js
  15. 128
      im-web/src/components/account/AccountSwitchMenu.vue

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

@ -304,5 +304,40 @@ public class UserController {
return ResultUtils.success(vo); return ResultUtils.success(vo);
} }
} @PostMapping("/deleteSwitchAccount")
@Operation(summary = "删除可切换账号", description = "从当前客服的可切换列表中移除指定账号")
public Result<?> deleteSwitchAccount(@RequestBody JSONObject jsonObject) {
Long targetUserId = jsonObject.getLong("targetUserId");
if (ObjectUtil.isNull(targetUserId)) {
return ResultUtils.error(XSS_PARAM_ERROR, "参数错误");
}
UserSession session = SessionContext.getSession();
Long currentUserId = session.getUserId();
User currentUser = userService.getById(currentUserId);
if (currentUser == null) {
return ResultUtils.error(XSS_PARAM_ERROR);
}
// 取出可切换账号并移除目标ID
String switchableIdsStr = currentUser.getSwitchableAccountIds();
if (StrUtil.isBlank(switchableIdsStr)) {
return ResultUtils.success("移除成功");
}
List<Long> idList = Arrays.stream(switchableIdsStr.split(","))
.filter(StrUtil::isNotBlank)
.map(Long::parseLong)
.filter(id -> !id.equals(targetUserId))
.collect(Collectors.toList());
String newIds = idList.stream().map(String::valueOf).collect(Collectors.joining(","));
// 更新到数据库
currentUser.setSwitchableAccountIds(newIds);
userService.updateById(currentUser);
return ResultUtils.success("移除成功");
}
}

170
im-uniapp/App.vue

@ -99,26 +99,37 @@ export default {
}); });
}, },
// //
//
handleCustomerChanged(msgInfo) { handleCustomerChanged(msgInfo) {
console.log('客服已变更,刷新聊天记录:', msgInfo); console.log('【客服转接】后台下发变更通知', msgInfo);
// msgInfo oldKfId idnewKfId id
// const oldKfId = msgInfo.oldKfId;
const newKfId = msgInfo.newKfId;
// ========== -> ==========
if (oldKfId && newKfId && oldKfId != newKfId) {
const oldChat = this.chatStore.findChatByFriend(oldKfId);
const newChat = this.chatStore.findChatByFriend(newKfId);
if (oldChat && oldChat.messages.length > 0) {
console.log('【开始强制合并】旧客服', oldKfId, '→ 新客服', newKfId);
//
this.chatStore.mergeOldCustomerToNew(oldKfId, newKfId);
}
}
//
this.friendStore.loadFriend().then(() => { this.friendStore.loadFriend().then(() => {
//
this.chatStore.refreshChats(); this.chatStore.refreshChats();
//
const pages = getCurrentPages(); const pages = getCurrentPages();
const currentPage = pages[pages.length - 1]; const currentPage = pages[pages.length - 1];
if (currentPage.route === 'pages/chat/chat-box') { if (currentPage.route === 'pages/chat/chat-box') {
//
const targetId = currentPage.options.targetId; const targetId = currentPage.options.targetId;
this.reloadChatMessages(targetId); this.reloadChatMessages(targetId);
} }
}); });
}, },
// //
reloadChatMessages(targetId) { reloadChatMessages(targetId) {
// //
@ -201,77 +212,76 @@ export default {
}) })
}, },
handlePrivateMessage(msg) { handlePrivateMessage(msg) {
// //
msg.selfSend = msg.sendId == this.userStore.userInfo.id; msg.selfSend = msg.sendId == this.userStore.userInfo.id;
// id // id
let friendId = msg.selfSend ? msg.recvId : msg.sendId; let friendId = msg.selfSend ? msg.recvId : msg.sendId;
//
let existingFriend = this.friendStore.findFriend(friendId);
if (!existingFriend && !msg.selfSend) { //
console.log("收到未知用户消息,刷新应用:", friendId); let existingFriend = this.friendStore.findFriend(friendId);
if (!existingFriend && !msg.selfSend) {
// console.log("收到未知用户消息,刷新应用:", friendId);
this.loadStore().then(() => {
// this.loadStore().then(() => {
// #ifdef H5 // #ifdef H5
window.location.reload(); window.location.reload();
// #endif // #endif
// #ifdef APP-PLUS // #ifdef APP-PLUS
plus.runtime.restart(); plus.runtime.restart();
// #endif // #endif
// #ifdef MP-WEIXIN // #ifdef MP-WEIXIN
// uni.reLaunch({
uni.reLaunch({ url: '/pages/chat/chat'
url: '/pages/chat/chat' });
}); // #endif
// #endif });
});
return;
return; }
} //
// let chatInfo = {
let chatInfo = { type: 'PRIVATE',
type: 'PRIVATE', targetId: friendId
targetId: friendId }
} //
// if (msg.type == enums.MESSAGE_TYPE.READED) {
if (msg.type == enums.MESSAGE_TYPE.READED) { this.chatStore.resetUnreadCount(chatInfo);
this.chatStore.resetUnreadCount(chatInfo); return;
return; }
} // ,
// , if (msg.type == enums.MESSAGE_TYPE.RECEIPT) {
if (msg.type == enums.MESSAGE_TYPE.RECEIPT) { this.chatStore.readedMessage({
this.chatStore.readedMessage({ friendId: msg.sendId
friendId: msg.sendId })
}) return;
return; }
} //
// if (msg.type == enums.MESSAGE_TYPE.RECALL) {
if (msg.type == enums.MESSAGE_TYPE.RECALL) { this.chatStore.recallMessage(msg, chatInfo);
this.chatStore.recallMessage(msg, chatInfo); return;
return; }
} //
// if (msg.type == enums.MESSAGE_TYPE.FRIEND_NEW) {
if (msg.type == enums.MESSAGE_TYPE.FRIEND_NEW) { this.friendStore.addFriend(JSON.parse(msg.content));
this.friendStore.addFriend(JSON.parse(msg.content)); return;
return; }
} //
// if (msg.type == enums.MESSAGE_TYPE.FRIEND_DEL) {
if (msg.type == enums.MESSAGE_TYPE.FRIEND_DEL) { this.friendStore.removeFriend(friendId);
this.friendStore.removeFriend(friendId); return;
return; }
} //
// if (msg.type == enums.MESSAGE_TYPE.FRIEND_DND) {
if (msg.type == enums.MESSAGE_TYPE.FRIEND_DND) { this.friendStore.setDnd(friendId, JSON.parse(msg.content));
this.friendStore.setDnd(friendId, JSON.parse(msg.content)); this.chatStore.setDnd(chatInfo, JSON.parse(msg.content));
this.chatStore.setDnd(chatInfo, JSON.parse(msg.content)); return;
return; }
} //
// let friend = this.loadFriendInfo(friendId);
let friend = this.loadFriendInfo(friendId); this.insertPrivateMessage(friend, msg);
this.insertPrivateMessage(friend, msg);
}, },
insertPrivateMessage(friend, msg) { insertPrivateMessage(friend, msg) {
// //

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

@ -1592,6 +1592,7 @@ export default {
}, },
}, },
async onLoad(options) { async onLoad(options) {
try { try {
this.currentLang = uni.getStorageSync("app_language") || "zh"; this.currentLang = uni.getStorageSync("app_language") || "zh";
uni.showLoading({ title: this.$t('common.loading'), mask: true }); uni.showLoading({ title: this.$t('common.loading'), mask: true });
@ -1658,6 +1659,23 @@ 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 {

6
im-uniapp/static/i18n/ara.json

@ -33,7 +33,11 @@
"album": "ألبوم", "album": "ألبوم",
"camera": "كاميرا", "camera": "كاميرا",
"noFriends": "لا أصدقاء", "noFriends": "لا أصدقاء",
"title": "دردشة" "title": "دردشة",
"you": "أنت",
"other": "الطرف الآخر",
"recalledMessage": "قام بتراجع رسالة",
"quoteRecalled": "تم تراجع المحتوى المقتبس"
}, },
"common": { "common": {
"confirm": "موافق", "confirm": "موافق",

6
im-uniapp/static/i18n/de.json

@ -33,7 +33,11 @@
"album": "Album", "album": "Album",
"camera": "Kamera", "camera": "Kamera",
"noFriends": "Keine Freunde", "noFriends": "Keine Freunde",
"title": "Chat" "title": "Chat",
"you": "Du",
"other": "Gegenüber",
"recalledMessage": "hat eine Nachricht zurückgenommen",
"quoteRecalled": "Zitat zurückgenommen"
}, },
"common": { "common": {
"confirm": "OK", "confirm": "OK",

7
im-uniapp/static/i18n/en.json

@ -7,7 +7,6 @@
"read": "Read", "read": "Read",
"unread": "Unread", "unread": "Unread",
"readedCount": "{count} read", "readedCount": "{count} read",
"guessWantAsk": "You may want to ask", "guessWantAsk": "You may want to ask",
"typing": "typing...", "typing": "typing...",
"autoReplyFailed": "Auto reply failed", "autoReplyFailed": "Auto reply failed",
@ -34,7 +33,11 @@
"album": "Album", "album": "Album",
"camera": "Camera", "camera": "Camera",
"noFriends": "No friends", "noFriends": "No friends",
"title": "Chat" "title": "Chat",
"you": "You",
"other": "Other",
"recalledMessage": "recalled a message",
"quoteRecalled": "Quote recalled"
}, },
"common": { "common": {
"confirm": "OK", "confirm": "OK",

6
im-uniapp/static/i18n/fra.json

@ -33,7 +33,11 @@
"album": "Album", "album": "Album",
"camera": "Caméra", "camera": "Caméra",
"noFriends": "Pas d'amis", "noFriends": "Pas d'amis",
"title": "Discussion" "title": "Discussion",
"you": "Vous",
"other": "Interlocuteur",
"recalledMessage": "a rappelé un message",
"quoteRecalled": "Citation rappelée"
}, },
"common": { "common": {
"confirm": "OK", "confirm": "OK",

34
im-uniapp/static/i18n/jp.json

@ -9,31 +9,35 @@
"readedCount": "{count}人が既読", "readedCount": "{count}人が既読",
"guessWantAsk": "質問したいこと", "guessWantAsk": "質問したいこと",
"typing": "入力中...", "typing": "入力中...",
"autoReplyFailed": "自動返信失敗", "autoReplyFailed": "自動返信失敗しました",
"receiptMessage": "【既読確認】", "receiptMessage": "【既読確認】",
"inputPlaceholder": "メッセージを入力", "inputPlaceholder": "メッセージを入力",
"send": "送信", "send": "送信",
"newMessages": "{count}件の新着メッセージ", "newMessages": "{count}件の新着メッセージ",
"cannotSendBlank": "空メッセージは送信できません", "cannotSendBlank": "空メッセージは送信できません",
"copySuccess": "コピー成功", "copySuccess": "コピーしました",
"copyFailed": "コピー失敗", "copyFailed": "コピー失敗",
"downloadFailed": "ダウンロード失敗", "downloadFailed": "ダウンロード失敗",
"deleteMessage": "メッセージ削除", "deleteMessage": "メッセージ削除",
"confirmDelete": "このメッセージを削除しますか?", "confirmDelete": "このメッセージを削除しますか?",
"recallMessage": "メッセージ取り消し", "recallMessage": "メッセージを取り消す",
"confirmRecall": "このメッセージを取り消しますか?", "confirmRecall": "このメッセージを取り消しますか?",
"deleteSuccess": "削除成功", "deleteSuccess": "削除しました",
"resendNotSupported": "再送信に対応していません", "resendNotSupported": "このメッセージの再送信に対応していません",
"sendFailed": "送信失敗", "sendFailed": "送信失敗",
"uploadFailed": "アップロード失敗", "uploadFailed": "アップロード失敗",
"userBanned": "発言禁止されています: {reason}", "userBanned": "発言を禁止されています:{reason}",
"groupBanned": "グループで発言禁止: {reason}", "groupBanned": "グループで発言を禁止されています:{reason}",
"atAll": "全員", "atAll": "全員",
"file": "ファイル", "file": "ファイル",
"album": "アルバム", "album": "アルバム",
"camera": "カメラ", "camera": "カメラ",
"noFriends": "友達なし", "noFriends": "友達がいません",
"title": "チャット" "title": "チャット",
"you": "あなた",
"other": "相手",
"recalledMessage": "メッセージを取り消しました",
"quoteRecalled": "引用メッセージは取り消されました"
}, },
"common": { "common": {
"confirm": "確定", "confirm": "確定",

34
im-uniapp/static/i18n/kor.json

@ -1,39 +1,43 @@
{ {
"chat": { "chat": {
"copy": "복사", "copy": "복사",
"recall": "취소", "recall": "회수",
"delete": "삭제", "delete": "삭제",
"download": "다운로드 열기", "download": "다운로드 열기",
"read": "읽음", "read": "읽음",
"unread": "읽음", "unread": "읽지 않음",
"readedCount": "{count}명 읽음", "readedCount": "{count}명 읽음",
"guessWantAsk": "물어보고 싶은 것", "guessWantAsk": "물어볼 내용",
"typing": "입력 중...", "typing": "입력 중...",
"autoReplyFailed": "자동 회신 실패", "autoReplyFailed": "자동 회신 실패",
"receiptMessage": "【읽음 확인】", "receiptMessage": "【읽음 확인】",
"inputPlaceholder": "메시지 입력", "inputPlaceholder": "메시지 입력하세요",
"send": "전송", "send": "전송",
"newMessages": "{count}개의 새 메시지", "newMessages": "{count}개의 새 메시지",
"cannotSendBlank": "빈 메시지는 보낼 수 없습니다", "cannotSendBlank": "빈 메시지는 보낼 수 없습니다",
"copySuccess": "복사 성공", "copySuccess": "복사 완료",
"copyFailed": "복사 실패", "copyFailed": "복사 실패",
"downloadFailed": "다운로드 실패", "downloadFailed": "다운로드 실패",
"deleteMessage": "메시지 삭제", "deleteMessage": "메시지 삭제",
"confirmDelete": "메시지를 삭제할까요?", "confirmDelete": "메시지를 삭제할까요?",
"recallMessage": "메시지 취소", "recallMessage": "메시지 회수",
"confirmRecall": "이 메시지를 취소할까요?", "confirmRecall": "메시지를 회수할까요?",
"deleteSuccess": "삭제 성공", "deleteSuccess": "삭제 완료",
"resendNotSupported": "재전송 지원 안됨", "resendNotSupported": "해당 메시지는 재전송할 수 없습니다",
"sendFailed": "전송 실패", "sendFailed": "전송 실패",
"uploadFailed": "업로드 실패", "uploadFailed": "업로드 실패",
"userBanned": "채팅 금지: {reason}", "userBanned": "채팅이 제한되었습니다: {reason}",
"groupBanned": "그룹 채팅 금지: {reason}", "groupBanned": "그룹 채팅이 제한되었습니다: {reason}",
"atAll": "모두", "atAll": "모두",
"file": "파일", "file": "파일",
"album": "앨범", "album": "앨범",
"camera": "카메라", "camera": "카메라",
"noFriends": "친구 없음", "noFriends": "친구가 없습니다",
"title": "채팅" "title": "채팅",
"you": "당신",
"other": "상대방",
"recalledMessage": "메시지를 회수했습니다",
"quoteRecalled": "인용 내용이 회수되었습니다"
}, },
"common": { "common": {
"confirm": "확인", "confirm": "확인",

6
im-uniapp/static/i18n/pt.json

@ -33,7 +33,11 @@
"album": "Álbum", "album": "Álbum",
"camera": "Câmera", "camera": "Câmera",
"noFriends": "Sem amigos", "noFriends": "Sem amigos",
"title": "Chat" "title": "Chat",
"you": "Você",
"other": "Outro",
"recalledMessage": "retirou uma mensagem",
"quoteRecalled": "Citação retirada"
}, },
"common": { "common": {
"confirm": "OK", "confirm": "OK",

22
im-uniapp/static/i18n/ru.json

@ -6,41 +6,45 @@
"download": "Скачать и открыть", "download": "Скачать и открыть",
"read": "Прочитано", "read": "Прочитано",
"unread": "Не прочитано", "unread": "Не прочитано",
"readedCount": "{count} человек прочитало", "readedCount": "{count} человек прочитали",
"guessWantAsk": "Возможно, вы хотите спросить", "guessWantAsk": "Возможно, вы хотите спросить",
"typing": "Печатает...", "typing": "Печатает...",
"autoReplyFailed": "Автоответ не удался", "autoReplyFailed": "Ошибка автоответа",
"receiptMessage": "【Прочитано】", "receiptMessage": "【Прочитано】",
"inputPlaceholder": "Введите сообщение", "inputPlaceholder": "Введите сообщение",
"send": "Отправить", "send": "Отправить",
"newMessages": "{count} новых сообщений", "newMessages": "{count} новых сообщений",
"cannotSendBlank": "Нельзя отправить пустое", "cannotSendBlank": "Нельзя отправить пустое сообщение",
"copySuccess": "Скопировано", "copySuccess": "Скопировано",
"copyFailed": "Ошибка копирования", "copyFailed": "Ошибка копирования",
"downloadFailed": "Ошибка загрузки", "downloadFailed": "Ошибка загрузки",
"deleteMessage": "Удалить сообщение", "deleteMessage": "Удалить сообщение",
"confirmDelete": "Удалить это сообщение?", "confirmDelete": "Удалить сообщение?",
"recallMessage": "Отозвать сообщение", "recallMessage": "Отозвать сообщение",
"confirmRecall": "Отозвать это сообщение?", "confirmRecall": "Отозвать сообщение?",
"deleteSuccess": "Удалено", "deleteSuccess": "Удалено",
"resendNotSupported": "Не поддерживается", "resendNotSupported": "Повторная отправка не поддерживается",
"sendFailed": "Ошибка отправки", "sendFailed": "Ошибка отправки",
"uploadFailed": "Ошибка загрузки", "uploadFailed": "Ошибка загрузки",
"userBanned": "Вы заблокированы: {reason}", "userBanned": "Вы заблокированы: {reason}",
"groupBanned": "В группе блокировка: {reason}", "groupBanned": "Заблокировано в группе: {reason}",
"atAll": "Все", "atAll": "Все",
"file": "Файл", "file": "Файл",
"album": "Альбом", "album": "Альбом",
"camera": "Камера", "camera": "Камера",
"noFriends": "Нет друзей", "noFriends": "Нет друзей",
"title": "Чат" "title": "Чат",
"you": "Вы",
"other": "Собеседник",
"recalledMessage": "отозвал сообщение",
"quoteRecalled": "Цитата отозвана"
}, },
"common": { "common": {
"confirm": "ОК", "confirm": "ОК",
"cancel": "Отмена", "cancel": "Отмена",
"loading": "Загрузка...", "loading": "Загрузка...",
"justNow": "Только что", "justNow": "Только что",
"minutesAgo": "мин назад", "minutesAgo": "мин. назад",
"yesterday": "Вчера" "yesterday": "Вчера"
} }
} }

14
im-uniapp/static/i18n/vie.json

@ -19,21 +19,25 @@
"copyFailed": "Sao chép thất bại", "copyFailed": "Sao chép thất bại",
"downloadFailed": "Tải thất bại", "downloadFailed": "Tải thất bại",
"deleteMessage": "Xóa tin nhắn", "deleteMessage": "Xóa tin nhắn",
"confirmDelete": "Xóa tin này?", "confirmDelete": "Xóa tin nhắn này?",
"recallMessage": "Thu hồi tin nhắn", "recallMessage": "Thu hồi tin nhắn",
"confirmRecall": "Thu hồi tin này?", "confirmRecall": "Thu hồi tin nhắn này?",
"deleteSuccess": "Xóa thành công", "deleteSuccess": "Đã xóa",
"resendNotSupported": "Không hỗ trợ gửi lại", "resendNotSupported": "Không hỗ trợ gửi lại",
"sendFailed": "Gửi thất bại", "sendFailed": "Gửi thất bại",
"uploadFailed": "Tải lên thất bại", "uploadFailed": "Tải lên thất bại",
"userBanned": "Bạn bị cấm nói: {reason}", "userBanned": "Bạn bị cấm trò chuyện: {reason}",
"groupBanned": "Bị cấm trong nhóm: {reason}", "groupBanned": "Bị cấm trong nhóm: {reason}",
"atAll": "Tất cả", "atAll": "Tất cả",
"file": "Tệp", "file": "Tệp",
"album": "Thư viện", "album": "Thư viện",
"camera": "Máy ảnh", "camera": "Máy ảnh",
"noFriends": "Chưa có bạn bè", "noFriends": "Chưa có bạn bè",
"title": "Trò chuyện" "title": "Trò chuyện",
"you": "Bạn",
"other": "Người kia",
"recalledMessage": "đã thu hồi một tin nhắn",
"quoteRecalled": "Nội dung trích dẫn đã được thu hồi"
}, },
"common": { "common": {
"confirm": "Xác nhận", "confirm": "Xác nhận",

9
im-uniapp/static/i18n/zh.json

@ -7,7 +7,6 @@
"read": "已读", "read": "已读",
"unread": "未读", "unread": "未读",
"readedCount": "{count}人已读", "readedCount": "{count}人已读",
"guessWantAsk": "你可能想问", "guessWantAsk": "你可能想问",
"typing": "正在输入...", "typing": "正在输入...",
"autoReplyFailed": "自动回复失败", "autoReplyFailed": "自动回复失败",
@ -24,7 +23,7 @@
"recallMessage": "撤回消息", "recallMessage": "撤回消息",
"confirmRecall": "确定撤回此消息?", "confirmRecall": "确定撤回此消息?",
"deleteSuccess": "删除成功", "deleteSuccess": "删除成功",
"resendNotSupported": "暂不支持重发该类型消息", "resendNotSupported": "暂不支持重发该消息",
"sendFailed": "发送失败", "sendFailed": "发送失败",
"uploadFailed": "上传失败", "uploadFailed": "上传失败",
"userBanned": "你已被禁言,原因:{reason}", "userBanned": "你已被禁言,原因:{reason}",
@ -34,7 +33,11 @@
"album": "相册", "album": "相册",
"camera": "相机", "camera": "相机",
"noFriends": "暂无好友", "noFriends": "暂无好友",
"title": "聊天" "title": "聊天",
"you": "你",
"other": "对方",
"recalledMessage": "撤回了一条消息",
"quoteRecalled": "引用内容已撤回"
}, },
"common": { "common": {
"confirm": "确定", "confirm": "确定",

147
im-uniapp/store/chatStore.js

@ -3,6 +3,7 @@ import { MESSAGE_TYPE, MESSAGE_STATUS } from '@/common/enums.js';
import useFriendStore from './friendStore.js'; import useFriendStore from './friendStore.js';
import useGroupStore from './groupStore.js'; import useGroupStore from './groupStore.js';
import useUserStore from './userStore'; import useUserStore from './userStore';
import { i18n } from '@/main.js'
let cacheChats = []; let cacheChats = [];
export default defineStore('chatStore', { export default defineStore('chatStore', {
@ -20,9 +21,7 @@ export default defineStore('chatStore', {
this.chats = []; this.chats = [];
for (let chat of chatsData.chats) { for (let chat of chatsData.chats) {
chat.stored = false; chat.stored = false;
// 暂存至缓冲区
cacheChats.push(JSON.parse(JSON.stringify(chat))); cacheChats.push(JSON.parse(JSON.stringify(chat)));
// 加载期间显示只前15个会话做做样子,一切都为了加快初始化时间
if (this.chats.length < 15) { if (this.chats.length < 15) {
this.chats.push(chat); this.chats.push(chat);
} }
@ -31,28 +30,35 @@ export default defineStore('chatStore', {
this.groupMsgMaxId = chatsData.groupMsgMaxId || 0; this.groupMsgMaxId = chatsData.groupMsgMaxId || 0;
}, },
// 客服转接:合并旧客服会话到新客服(你要的功能)
mergeOldCustomerToNew(oldKfId, newKfId) { mergeOldCustomerToNew(oldKfId, newKfId) {
const oldChat = this.findChatByFriend(oldKfId); const oldChat = this.findChatByFriend(oldKfId);
const newChat = this.findChatByFriend(newKfId); const newChat = this.findChatByFriend(newKfId);
if (!oldChat || !newChat) {
console.warn('合并失败:旧/新会话不存在', oldKfId, newKfId);
return;
}
if (!oldChat || !newChat) return; newChat.messages = [...oldChat.messages, ...newChat.messages];
newChat.messages = [...oldChat.messages, ...newChat.messages];
newChat.unreadCount += oldChat.unreadCount; newChat.unreadCount += oldChat.unreadCount;
newChat.lastContent = oldChat.lastContent || newChat.lastContent; newChat.lastContent = oldChat.lastContent || newChat.lastContent;
newChat.lastSendTime = Math.max(oldChat.lastSendTime || 0, newChat.lastSendTime || 0); newChat.lastSendTime = Math.max(oldChat.lastSendTime || 0, newChat.lastSendTime || 0);
newChat.atMe = newChat.atMe || oldChat.atMe;
newChat.atAll = newChat.atAll || oldChat.atAll;
newChat.stored = false; const keepHot = 300;
oldChat.stored = false; const totalMsg = newChat.messages.length;
newChat.hotMinIdx = totalMsg <= keepHot ? 0 : Math.max(0, totalMsg - keepHot);
newChat.readedMessageIdx = Math.min(oldChat.readedMessageIdx || 0, newChat.readedMessageIdx || 0);
this.removePrivateChat(oldKfId); this.clearCustomerCache(oldKfId);
this.removePrivateChat(oldKfId);
this.saveToStorage(true); newChat.stored = false;
this.saveToStorage(true);
console.log('【合并完成】旧客服消息全部转入新客服', newChat.messages.length);
}, },
// 强制清理某个用户的本地缓存(清理旧客服)
clearCustomerCache(userId) { clearCustomerCache(userId) {
const userStore = useUserStore(); const userStore = useUserStore();
const currentUserId = userStore.userInfo.id; const currentUserId = userStore.userInfo.id;
@ -68,12 +74,10 @@ export default defineStore('chatStore', {
if (chats[idx].type == chatInfo.type && if (chats[idx].type == chatInfo.type &&
chats[idx].targetId === chatInfo.targetId) { chats[idx].targetId === chatInfo.targetId) {
chat = chats[idx]; chat = chats[idx];
// 放置头部
this.moveTop(idx) this.moveTop(idx)
break; break;
} }
} }
// 创建会话
if (chat == null) { if (chat == null) {
chat = { chat = {
targetId: chatInfo.targetId, targetId: chatInfo.targetId,
@ -121,7 +125,6 @@ export default defineStore('chatStore', {
for (let idx = chat.readedMessageIdx; idx < chat.messages.length; idx++) { for (let idx = chat.readedMessageIdx; idx < chat.messages.length; idx++) {
let m = chat.messages[idx]; let m = chat.messages[idx];
if (m.id && m.selfSend && m.status < MESSAGE_STATUS.RECALL) { if (m.id && 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 m.status = MESSAGE_STATUS.READED
chat.readedMessageIdx = idx; chat.readedMessageIdx = idx;
@ -183,63 +186,54 @@ export default defineStore('chatStore', {
} }
}, },
insertMessage(msgInfo, chatInfo) { insertMessage(msgInfo, chatInfo) {
// 获取对方id或群id const t = i18n.global.t;
let type = chatInfo.type; let type = chatInfo.type;
// 记录消息的最大id
if (msgInfo.id && type == "PRIVATE" && msgInfo.id > this.privateMsgMaxId) { if (msgInfo.id && type == "PRIVATE" && msgInfo.id > this.privateMsgMaxId) {
this.privateMsgMaxId = msgInfo.id; this.privateMsgMaxId = msgInfo.id;
} }
if (msgInfo.id && type == "GROUP" && msgInfo.id > this.groupMsgMaxId) { if (msgInfo.id && type == "GROUP" && msgInfo.id > this.groupMsgMaxId) {
this.groupMsgMaxId = msgInfo.id; this.groupMsgMaxId = msgInfo.id;
} }
// 如果是已存在消息,则覆盖旧的消息数据
let chat = this.findChat(chatInfo); let chat = this.findChat(chatInfo);
let message = this.findMessage(chat, msgInfo); let message = this.findMessage(chat, msgInfo);
if (message) { if (message) {
console.log("message:", message) const msgIndex = chat.messages.findIndex(m =>
(m.id && m.id === msgInfo.id) ||
// ✅ 方式1:使用 Vue.set 或 $set 确保响应式更新 (m.tmpId && m.tmpId === msgInfo.tmpId)
// 先删除旧消息 );
const msgIndex = chat.messages.findIndex(m => if (msgIndex !== -1) {
(m.id && m.id === msgInfo.id) || const updatedMessage = { ...message, ...msgInfo };
(m.tmpId && m.tmpId === msgInfo.tmpId) chat.messages.splice(msgIndex, 1, updatedMessage);
); }
chat.stored = false;
if (msgIndex !== -1) { this.saveToStorage();
// 创建新对象而不是修改原对象 return;
const updatedMessage = { ...message, ...msgInfo }; }
// 使用 splice 替换,确保响应式
chat.messages.splice(msgIndex, 1, updatedMessage); // ====================== 多语言消息类型 ======================
}
chat.stored = false;
this.saveToStorage();
return;
}
// 会话列表内容
if (msgInfo.type == MESSAGE_TYPE.IMAGE) { if (msgInfo.type == MESSAGE_TYPE.IMAGE) {
chat.lastContent = "[图片]"; chat.lastContent = t('chat.image');
} else if (msgInfo.type == MESSAGE_TYPE.FILE) { } else if (msgInfo.type == MESSAGE_TYPE.FILE) {
chat.lastContent = "[文件]"; chat.lastContent = t('chat.file');
} else if (msgInfo.type == MESSAGE_TYPE.AUDIO) { } else if (msgInfo.type == MESSAGE_TYPE.AUDIO) {
chat.lastContent = "[语音]"; chat.lastContent = t('chat.voice');
} else if (msgInfo.type == MESSAGE_TYPE.ACT_RT_VOICE) { } else if (msgInfo.type == MESSAGE_TYPE.ACT_RT_VOICE) {
chat.lastContent = "[语音通话]"; chat.lastContent = t('chat.voiceCall');
} else if (msgInfo.type == MESSAGE_TYPE.ACT_RT_VIDEO) { } else if (msgInfo.type == MESSAGE_TYPE.ACT_RT_VIDEO) {
chat.lastContent = "[视频通话]"; chat.lastContent = t('chat.videoCall');
} else if (msgInfo.type == MESSAGE_TYPE.TEXT || } else if (msgInfo.type == MESSAGE_TYPE.TEXT ||
msgInfo.type == MESSAGE_TYPE.RECALL || msgInfo.type == MESSAGE_TYPE.RECALL ||
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;
// 未读加1
if (!msgInfo.selfSend && msgInfo.status != MESSAGE_STATUS.READED && if (!msgInfo.selfSend && msgInfo.status != MESSAGE_STATUS.READED &&
msgInfo.status != MESSAGE_STATUS.RECALL && msgInfo.type != MESSAGE_TYPE.TIP_TEXT) { msgInfo.status != MESSAGE_STATUS.RECALL && msgInfo.type != MESSAGE_TYPE.TIP_TEXT) {
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) {
const userStore = useUserStore(); const userStore = useUserStore();
@ -251,7 +245,6 @@ export default defineStore('chatStore', {
chat.atAll = true; chat.atAll = true;
} }
} }
// 间隔大于10分钟插入时间显示
if (!chat.lastTimeTip || (chat.lastTimeTip < msgInfo.sendTime - 600 * 1000)) { if (!chat.lastTimeTip || (chat.lastTimeTip < msgInfo.sendTime - 600 * 1000)) {
chat.messages.push({ chat.messages.push({
sendTime: msgInfo.sendTime, sendTime: msgInfo.sendTime,
@ -259,17 +252,14 @@ export default defineStore('chatStore', {
}); });
chat.lastTimeTip = msgInfo.sendTime; chat.lastTimeTip = msgInfo.sendTime;
} }
// 插入消息
chat.messages.push(msgInfo); chat.messages.push(msgInfo);
chat.stored = false; chat.stored = false;
this.saveToStorage(); this.saveToStorage();
}, },
updateMessage(msgInfo, chatInfo) { updateMessage(msgInfo, chatInfo) {
// 获取对方id或群id
let chat = this.findChat(chatInfo); let chat = this.findChat(chatInfo);
let message = this.findMessage(chat, msgInfo); let message = this.findMessage(chat, msgInfo);
if (message) { if (message) {
// 属性拷贝
Object.assign(message, msgInfo); Object.assign(message, msgInfo);
chat.stored = false; chat.stored = false;
this.saveToStorage(); this.saveToStorage();
@ -280,12 +270,10 @@ export default defineStore('chatStore', {
let chat = this.findChat(chatInfo); let chat = this.findChat(chatInfo);
let delIdx = -1; let delIdx = -1;
for (let idx in chat.messages) { for (let idx in chat.messages) {
// 已经发送成功的,根据id删除
if (chat.messages[idx].id && chat.messages[idx].id == msgInfo.id) { if (chat.messages[idx].id && chat.messages[idx].id == msgInfo.id) {
delIdx = idx; delIdx = idx;
break; break;
} }
// 正在发送中的消息可能没有id,只有临时id
if (chat.messages[idx].tmpId && chat.messages[idx].tmpId == msgInfo.tmpId) { if (chat.messages[idx].tmpId && chat.messages[idx].tmpId == msgInfo.tmpId) {
delIdx = idx; delIdx = idx;
break; break;
@ -304,21 +292,20 @@ export default defineStore('chatStore', {
this.saveToStorage(isColdMessage); this.saveToStorage(isColdMessage);
} }
}, },
recallMessage(msgInfo, chatInfo) { recallMessage(msgInfo, chatInfo) {
const t = i18n.global.t;
let chat = this.findChat(chatInfo); let chat = this.findChat(chatInfo);
if (!chat) return; if (!chat) return;
let isColdMessage = false; let isColdMessage = false;
// 要撤回的消息id
let id = msgInfo.content; let id = msgInfo.content;
let name = msgInfo.selfSend ? '你' : chat.type == 'PRIVATE' ? '对方' : msgInfo.sendNickName; let name = msgInfo.selfSend ? t('chat.you') : (chat.type == 'PRIVATE' ? t('chat.other') : msgInfo.sendNickName);
for (let idx in chat.messages) { for (let idx in chat.messages) {
let m = chat.messages[idx]; let m = chat.messages[idx];
if (m.id && m.id == id) { if (m.id && m.id == id) {
// 改造成一条提示消息
m.status = MESSAGE_STATUS.RECALL; m.status = MESSAGE_STATUS.RECALL;
m.content = name + "撤回了一条消息"; m.content = `${name}${t('chat.recalledMessage')}`;
m.type = MESSAGE_TYPE.TIP_TEXT m.type = MESSAGE_TYPE.TIP_TEXT
// 会话列表
chat.lastContent = m.content; chat.lastContent = m.content;
chat.lastSendTime = msgInfo.sendTime; chat.lastSendTime = msgInfo.sendTime;
chat.sendNickName = ''; chat.sendNickName = '';
@ -327,9 +314,8 @@ export default defineStore('chatStore', {
} }
isColdMessage = idx < chat.hotMinIdx; isColdMessage = idx < chat.hotMinIdx;
} }
// 被引用的消息也要撤回
if (m.quoteMessage && m.quoteMessage.id == msgInfo.id) { if (m.quoteMessage && m.quoteMessage.id == msgInfo.id) {
m.quoteMessage.content = "引用内容已撤回"; m.quoteMessage.content = t('chat.quoteRecalled');
m.quoteMessage.status = MESSAGE_STATUS.RECALL; m.quoteMessage.status = MESSAGE_STATUS.RECALL;
m.quoteMessage.type = MESSAGE_TYPE.TIP_TEXT m.quoteMessage.type = MESSAGE_TYPE.TIP_TEXT
} }
@ -341,7 +327,6 @@ export default defineStore('chatStore', {
let chat = this.findChatByFriend(friend.id) let chat = this.findChatByFriend(friend.id)
if (chat && (chat.headImage != friend.headImage || if (chat && (chat.headImage != friend.headImage ||
chat.showName != friend.nickName)) { chat.showName != friend.nickName)) {
// 更新会话中的群名和头像
chat.headImage = friend.headImage; chat.headImage = friend.headImage;
chat.showName = friend.nickName; chat.showName = friend.nickName;
chat.stored = false; chat.stored = false;
@ -350,7 +335,6 @@ export default defineStore('chatStore', {
}, },
updateChatFromUser(user) { updateChatFromUser(user) {
let chat = this.findChatByFriend(user.id); let chat = this.findChatByFriend(user.id);
// 更新会话中的昵称和头像
if (chat && (chat.headImage != user.headImageThumb || if (chat && (chat.headImage != user.headImageThumb ||
chat.showName != user.nickName)) { chat.showName != user.nickName)) {
chat.headImage = user.headImageThumb; chat.headImage = user.headImageThumb;
@ -363,7 +347,6 @@ export default defineStore('chatStore', {
let chat = this.findChatByGroup(group.id); let chat = this.findChatByGroup(group.id);
if (chat && (chat.headImage != group.headImageThumb || if (chat && (chat.headImage != group.headImageThumb ||
chat.showName != group.showGroupName)) { chat.showName != group.showGroupName)) {
// 更新会话中的群名称和头像
chat.headImage = group.headImageThumb; chat.headImage = group.headImageThumb;
chat.showName = group.showGroupName; chat.showName = group.showGroupName;
chat.stored = false; chat.stored = false;
@ -381,7 +364,6 @@ export default defineStore('chatStore', {
}, },
refreshChats() { refreshChats() {
let chats = cacheChats || this.chats; let chats = cacheChats || this.chats;
// 更新会话免打扰状态
const friendStore = useFriendStore(); const friendStore = useFriendStore();
const groupStore = useGroupStore(); const groupStore = useGroupStore();
chats.forEach(chat => { chats.forEach(chat => {
@ -397,36 +379,23 @@ export default defineStore('chatStore', {
} }
} }
}) })
// 排序
chats.sort((chat1, chat2) => chat2.lastSendTime - chat1.lastSendTime); chats.sort((chat1, chat2) => chat2.lastSendTime - chat1.lastSendTime);
// #ifndef APP-PLUS
// h5和小程序的stroge一般只有5m,大约只能存储1w条消息,所以可能需要清理部分历史消息
const storageInfo = uni.getStorageInfoSync(); const storageInfo = uni.getStorageInfoSync();
console.log(`storage缓存: ${storageInfo.currentSize} KB`)
// 空间不足(大于3mb)时,清理这个设备登录过其他账户的消息
if (storageInfo && storageInfo.currentSize > 3000) { if (storageInfo && storageInfo.currentSize > 3000) {
console.log("storage空间不足,清理其他用户缓存..")
this.cleanOtherUserCache(); this.cleanOtherUserCache();
} }
// 保证消息总数量不超过3000条,每个会话不超过500条
this.fliterMessage(chats, 3000, 500); this.fliterMessage(chats, 3000, 500);
// #endif
// 记录热数据索引位置
chats.forEach(chat => { chats.forEach(chat => {
if (!chat.hotMinIdx || chat.hotMinIdx != chat.messages.length) { if (!chat.hotMinIdx || chat.hotMinIdx != chat.messages.length) {
chat.hotMinIdx = chat.messages.length; chat.hotMinIdx = chat.messages.length;
chat.stored = false; chat.stored = false;
} }
}); });
// 将消息一次性装载回来
this.chats = chats; this.chats = chats;
// 清空缓存,不再使用
cacheChats = null; cacheChats = null;
// 消息持久化
this.saveToStorage(true); this.saveToStorage(true);
}, },
fliterMessage(chats, maxTotalSize, maxPerChatSize) { fliterMessage(chats, maxTotalSize, maxPerChatSize) {
// 每个会话只保留maxPerChatSize条消息
let remainTotalSize = 0; let remainTotalSize = 0;
chats.forEach(chat => { chats.forEach(chat => {
if (chat.messages.length > maxPerChatSize) { if (chat.messages.length > maxPerChatSize) {
@ -435,12 +404,9 @@ export default defineStore('chatStore', {
} }
remainTotalSize += chat.messages.length; remainTotalSize += chat.messages.length;
}) })
// 保证消息总数不超过maxTotalSize条,否则继续清理
if (remainTotalSize > maxTotalSize) { if (remainTotalSize > maxTotalSize) {
this.fliterMessage(chats, maxTotalSize, maxPerChatSize / 2); this.fliterMessage(chats, maxTotalSize, maxPerChatSize / 2);
} }
console.log("消息留存总数量:", remainTotalSize)
console.log("单会话消息数量:", maxPerChatSize)
}, },
cleanOtherUserCache() { cleanOtherUserCache() {
const userStore = useUserStore(); const userStore = useUserStore();
@ -448,15 +414,12 @@ export default defineStore('chatStore', {
const prefix = "chats-app-" + userId; const prefix = "chats-app-" + userId;
const res = uni.getStorageInfoSync(); const res = uni.getStorageInfoSync();
res.keys.forEach(key => { res.keys.forEach(key => {
// 清理其他用户的消息
if (key.startsWith("chats-app") && !key.startsWith(prefix)) { if (key.startsWith("chats-app") && !key.startsWith(prefix)) {
uni.removeStorageSync(key); uni.removeStorageSync(key);
console.log("清理key:", key)
} }
}) })
}, },
saveToStorage(withColdMessage) { saveToStorage(withColdMessage) {
// 加载中不保存,防止卡顿
if (this.loading) { if (this.loading) {
return; return;
} }
@ -464,20 +427,17 @@ export default defineStore('chatStore', {
let userId = userStore.userInfo.id; let userId = userStore.userInfo.id;
let key = "chats-app-" + userId; let key = "chats-app-" + userId;
let chatKeys = []; let chatKeys = [];
// 按会话为单位存储,只存储有改动的会话
this.chats.forEach((chat) => { this.chats.forEach((chat) => {
let chatKey = `${key}-${chat.type}-${chat.targetId}` let chatKey = `${key}-${chat.type}-${chat.targetId}`
if (!chat.stored) { if (!chat.stored) {
if (chat.delete) { if (chat.delete) {
uni.removeStorageSync(chatKey); uni.removeStorageSync(chatKey);
} else { } else {
// 存储冷数据
if (withColdMessage) { if (withColdMessage) {
let coldChat = Object.assign({}, chat); let coldChat = Object.assign({}, chat);
coldChat.messages = chat.messages.slice(0, chat.hotMinIdx); coldChat.messages = chat.messages.slice(0, chat.hotMinIdx);
uni.setStorageSync(chatKey, coldChat) uni.setStorageSync(chatKey, coldChat)
} }
// 存储热消息
let hotKey = chatKey + '-hot'; let hotKey = chatKey + '-hot';
let hotChat = Object.assign({}, chat); let hotChat = Object.assign({}, chat);
hotChat.messages = chat.messages.slice(chat.hotMinIdx) hotChat.messages = chat.messages.slice(chat.hotMinIdx)
@ -489,14 +449,12 @@ export default defineStore('chatStore', {
chatKeys.push(chatKey); chatKeys.push(chatKey);
} }
}) })
// 会话核心信息
let chatsData = { let chatsData = {
privateMsgMaxId: this.privateMsgMaxId, privateMsgMaxId: this.privateMsgMaxId,
groupMsgMaxId: this.groupMsgMaxId, groupMsgMaxId: this.groupMsgMaxId,
chatKeys: chatKeys chatKeys: chatKeys
} }
uni.setStorageSync(key, chatsData) uni.setStorageSync(key, chatsData)
// 清理已删除的会话
this.chats = this.chats.filter(chat => !chat.delete) this.chats = this.chats.filter(chat => !chat.delete)
}, },
clear(state) { clear(state) {
@ -521,18 +479,15 @@ export default defineStore('chatStore', {
if (!coldChat && !hotChat) { if (!coldChat && !hotChat) {
return; return;
} }
// 防止消息一直处在发送中状态
hotChat && hotChat.messages.forEach(msg => { hotChat && hotChat.messages.forEach(msg => {
if (msg.status == MESSAGE_STATUS.SENDING) { if (msg.status == MESSAGE_STATUS.SENDING) {
msg.status = MESSAGE_STATUS.FAILED msg.status = MESSAGE_STATUS.FAILED
} }
}) })
// 冷热消息合并
let chat = Object.assign({}, coldChat, hotChat); let chat = Object.assign({}, coldChat, hotChat);
if (hotChat && coldChat) { if (hotChat && coldChat) {
chat.messages = coldChat.messages.concat(hotChat.messages) chat.messages = coldChat.messages.concat(hotChat.messages)
} }
// 历史版本没有readedMessageIdx字段,做兼容一下
chat.readedMessageIdx = chat.readedMessageIdx || 0; chat.readedMessageIdx = chat.readedMessageIdx || 0;
chatsData.chats.push(chat); chatsData.chats.push(chat);
}) })
@ -577,20 +532,17 @@ export default defineStore('chatStore', {
if (!chat) { if (!chat) {
return null; return null;
} }
// 通过id判断
if (msgInfo.id) { if (msgInfo.id) {
for (let idx = chat.messages.length - 1; idx >= 0; idx--) { for (let idx = chat.messages.length - 1; idx >= 0; idx--) {
let m = chat.messages[idx]; let m = chat.messages[idx];
if (m.id && msgInfo.id == m.id) { if (m.id && msgInfo.id == m.id) {
return m; return m;
} }
// 如果id比要查询的消息小,说明没有这条消息
if (m.id && m.id < msgInfo.id) { if (m.id && m.id < msgInfo.id) {
break; break;
} }
} }
} }
// 正在发送中的临时消息可能没有id,只有tmpId
if (msgInfo.selfSend && msgInfo.tmpId) { if (msgInfo.selfSend && msgInfo.tmpId) {
for (let idx = chat.messages.length - 1; idx >= 0; idx--) { for (let idx = chat.messages.length - 1; idx >= 0; idx--) {
let m = chat.messages[idx]; let m = chat.messages[idx];
@ -600,7 +552,6 @@ export default defineStore('chatStore', {
if (msgInfo.tmpId == m.tmpId) { if (msgInfo.tmpId == m.tmpId) {
return m; return m;
} }
// 如果id比要查询的消息小,说明没有这条消息
if (m.tmpId && m.tmpId < msgInfo.tmpId) { if (m.tmpId && m.tmpId < msgInfo.tmpId) {
break; break;
} }

128
im-web/src/components/account/AccountSwitchMenu.vue

@ -65,11 +65,13 @@
@click.stop="handleSwitch(account)"> @click.stop="handleSwitch(account)">
切换 切换
</el-button> </el-button>
<i <el-button
class="el-icon-close delete-icon" type="danger"
@click.stop="handleRemove(account)" size="small"
title="移除可切换账号"> @click.stop="handleDeleteAccount(account)"
</i> >
删除
</el-button>
</div> </div>
</div> </div>
</div> </div>
@ -97,7 +99,6 @@
</div> </div>
</div> </div>
<!-- 添加账号登录对话框 -->
<el-dialog <el-dialog
title="添加账号" title="添加账号"
:visible.sync="addAccountDialogVisible" :visible.sync="addAccountDialogVisible"
@ -138,7 +139,7 @@
</template> </template>
<script> <script>
const ACCOUNTS_CACHE_KEY = 'switchable_accounts_cache'; // key const ACCOUNTS_CACHE_KEY = 'switchable_accounts_cache';
export default { export default {
name: 'AccountSwitchMenu', name: 'AccountSwitchMenu',
@ -228,7 +229,6 @@ export default {
// //
saveCachedAccounts(accounts) { saveCachedAccounts(accounts) {
try { try {
//
const cacheData = accounts.map(a => ({ const cacheData = accounts.map(a => ({
id: a.id, id: a.id,
userName: a.userName, userName: a.userName,
@ -245,7 +245,6 @@ export default {
// //
addAccountToCache(account) { addAccountToCache(account) {
const accounts = this.getCachedAccounts(); const accounts = this.getCachedAccounts();
//
const exists = accounts.some(a => a.id === account.id); const exists = accounts.some(a => a.id === account.id);
if (!exists) { if (!exists) {
accounts.push({ accounts.push({
@ -265,19 +264,45 @@ export default {
accounts = accounts.filter(a => a.id !== accountId); accounts = accounts.filter(a => a.id !== accountId);
this.saveCachedAccounts(accounts); this.saveCachedAccounts(accounts);
}, },
async handleDeleteAccount(account) {
try {
await this.$confirm(
`确定要删除账号【${account.nickName}】吗?\n删除后将不再显示此账号`,
'删除账号',
{
confirmButtonText: '确定删除',
cancelButtonText: '取消',
type: 'warning'
}
)
try {
await this.$http({
url: '/user/deleteSwitchAccount',
method: 'post',
data: { targetUserId: account.id }
})
} catch (err) {
console.log('后端删除失败,继续清理本地')
}
this.removeAccountFromCache(account.id)
await this.loadAccountList()
this.$message.success('删除账号成功')
} catch (error) {
//
}
},
async loadAccountList() { async loadAccountList() {
this.loading = true; this.loading = true;
try { try {
// 1.
let accounts = this.getCachedAccounts(); let accounts = this.getCachedAccounts();
// 2.
accounts = accounts.filter(a => a.id !== this.currentUser.id); accounts = accounts.filter(a => a.id !== this.currentUser.id);
console.log('从缓存加载账号列表:', accounts);
// 3.
try { try {
const res = await this.$http({ const res = await this.$http({
url: '/user/getSwitchableAccounts', url: '/user/getSwitchableAccounts',
@ -287,9 +312,7 @@ export default {
const data = res.data || res || {}; const data = res.data || res || {};
const serverAccounts = data.switchableUsers || []; const serverAccounts = data.switchableUsers || [];
//
if (serverAccounts.length > 0) { if (serverAccounts.length > 0) {
//
const mergedAccounts = this.mergeAccounts(accounts, serverAccounts); const mergedAccounts = this.mergeAccounts(accounts, serverAccounts);
this.saveCachedAccounts(mergedAccounts); this.saveCachedAccounts(mergedAccounts);
accounts = mergedAccounts.filter(a => a.id !== this.currentUser.id); accounts = mergedAccounts.filter(a => a.id !== this.currentUser.id);
@ -298,7 +321,6 @@ export default {
console.log('后端接口获取失败,使用缓存数据:', error); console.log('后端接口获取失败,使用缓存数据:', error);
} }
// 4.
if (accounts.length > 0) { if (accounts.length > 0) {
accounts = await this.fetchUnreadCounts(accounts); accounts = await this.fetchUnreadCounts(accounts);
} }
@ -307,7 +329,6 @@ export default {
} catch (error) { } catch (error) {
console.error('加载账号列表失败:', error); console.error('加载账号列表失败:', error);
//
const cached = this.getCachedAccounts(); const cached = this.getCachedAccounts();
this.allAccounts = cached.filter(a => a.id !== this.currentUser.id); this.allAccounts = cached.filter(a => a.id !== this.currentUser.id);
} finally { } finally {
@ -315,17 +336,13 @@ export default {
} }
}, },
//
mergeAccounts(cached, server) { mergeAccounts(cached, server) {
const map = new Map(); const map = new Map();
//
cached.forEach(a => map.set(a.id, a)); cached.forEach(a => map.set(a.id, a));
// /
server.forEach(a => map.set(a.id, a)); server.forEach(a => map.set(a.id, a));
return Array.from(map.values()); return Array.from(map.values());
}, },
//
async refreshUnreadCounts() { async refreshUnreadCounts() {
if (this.allAccounts.length === 0) return; if (this.allAccounts.length === 0) return;
@ -337,7 +354,6 @@ export default {
} }
}, },
//
async fetchUnreadCounts(accounts) { async fetchUnreadCounts(accounts) {
try { try {
const userIds = accounts.map(a => a.id); const userIds = accounts.map(a => a.id);
@ -345,9 +361,7 @@ export default {
const res = await this.$http({ const res = await this.$http({
url: '/message/private/unreadCounts', url: '/message/private/unreadCounts',
method: 'post', method: 'post',
data: { data: { userIds }
userIds: userIds
}
}); });
const unreadMap = res.data || res || {}; const unreadMap = res.data || res || {};
@ -359,10 +373,7 @@ export default {
} catch (error) { } catch (error) {
console.error('获取未读消息数失败:', error); console.error('获取未读消息数失败:', error);
return accounts.map(account => ({ return accounts.map(account => ({ ...account, unreadCount: 0 }));
...account,
unreadCount: 0
}));
} }
}, },
@ -442,7 +453,6 @@ export default {
handleClickOutside(event) { handleClickOutside(event) {
if (!this.visible) return; if (!this.visible) return;
if (this.addAccountDialogVisible) return;
const menu = this.$refs.menu || this.$el; const menu = this.$refs.menu || this.$el;
if (menu && !menu.contains(event.target)) { if (menu && !menu.contains(event.target)) {
@ -454,11 +464,11 @@ export default {
} }
}, },
// ========== ==========
handleAddAccount() { handleAddAccount() {
this.loginForm = { this.loginForm = { userName: '', password: '' };
userName: '', //
password: '' this.$emit('close');
};
this.addAccountDialogVisible = true; this.addAccountDialogVisible = true;
this.$nextTick(() => { this.$nextTick(() => {
@ -484,10 +494,8 @@ export default {
} }
}); });
//
const accountData = res.data || res || {}; const accountData = res.data || res || {};
//
if (accountData.user) { if (accountData.user) {
this.addAccountToCache(accountData.user); this.addAccountToCache(accountData.user);
} else if (accountData.id) { } else if (accountData.id) {
@ -502,11 +510,7 @@ export default {
} catch (error) { } catch (error) {
console.error('添加失败:', error); console.error('添加失败:', error);
if (error.response && error.response.data) { this.$message.error(error?.response?.data?.message || '添加失败');
this.$message.error(error.response.data.message || '添加失败');
} else {
this.$message.error('添加失败');
}
} finally { } finally {
this.adding = false; this.adding = false;
} }
@ -514,22 +518,15 @@ export default {
}, },
handleSwitch(account) { handleSwitch(account) {
//
this.addAccountToCache(account); this.addAccountToCache(account);
//
this.addAccountToCache(this.currentUser); this.addAccountToCache(this.currentUser);
this.$emit('switch', account); this.$emit('switch', account);
}, },
getTerminalType() { getTerminalType() {
const userAgent = navigator.userAgent; const userAgent = navigator.userAgent;
if (/mobile/i.test(userAgent)) { if (/mobile/i.test(userAgent)) return 2;
return 2; if (/tablet/i.test(userAgent)) return 3;
}
if (/tablet/i.test(userAgent)) {
return 3;
}
return 1; return 1;
}, },
@ -541,17 +538,13 @@ export default {
type: 'warning' type: 'warning'
}); });
//
this.removeAccountFromCache(account.id); this.removeAccountFromCache(account.id);
//
try { try {
await this.$http({ await this.$http({
url: '/user/removeSwitchableAccount', url: '/user/removeSwitchableAccount',
method: 'post', method: 'post',
data: { data: { targetUserId: account.id }
targetUserId: account.id
}
}); });
} catch (error) { } catch (error) {
console.log('后端移除失败,已从本地缓存移除'); console.log('后端移除失败,已从本地缓存移除');
@ -572,9 +565,7 @@ export default {
}; };
</script> </script>
<style lang="scss"> <style lang="scss">
.add-account-dialog { .add-account-dialog {
border-radius: 10px !important; border-radius: 10px !important;
} }
@ -696,10 +687,6 @@ export default {
&:hover { &:hover {
background: #f5f7fa; background: #f5f7fa;
.delete-icon {
opacity: 1;
}
} }
.chat-left { .chat-left {
@ -770,21 +757,6 @@ export default {
align-items: center; align-items: center;
gap: 8px; gap: 8px;
flex-shrink: 0; flex-shrink: 0;
.delete-icon {
opacity: 0;
color: #999;
font-size: 16px;
padding: 6px;
cursor: pointer;
transition: all 0.2s;
border-radius: 50%;
&:hover {
color: #f56c6c;
background: rgba(245, 108, 108, 0.1);
}
}
} }
} }
} }

Loading…
Cancel
Save