mdm-im-v3 2.1.0 → 2.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +50 -1
  3. package/dist/{FilePreview-dpnc9m3Z.js → FilePreview-CJdqlDs0.js} +2 -2
  4. package/dist/core.es.js +2 -2
  5. package/dist/{index-D5S79LNp.js → index-BLdSVjT-.js} +682 -332
  6. package/dist/{index-CsaYx_7b.js → index-CrMTFmHU.js} +2 -2
  7. package/dist/{index-CNxeqkio.js → index-VIcWin6Y.js} +68 -54
  8. package/dist/index.es.js +1 -1
  9. package/dist/style/index.css +1 -1
  10. package/dist-h5/{ChatHistoryH5-BhrGF5WR.js → ChatHistoryH5-BeCSVzKZ.js} +2 -2
  11. package/dist-h5/{ChatPageH5-B3azJu7O.js → ChatPageH5-GUblGkKv.js} +12 -7
  12. package/dist-h5/{ChatSettingsH5-CFr9Bn69.js → ChatSettingsH5-wyQ01zjO.js} +3 -2
  13. package/dist-h5/{CreateGroupH5-a16jkObH.js → CreateGroupH5-CCtTCnLG.js} +2 -2
  14. package/dist-h5/{GroupAnnouncementH5-B-Qfzoy2.js → GroupAnnouncementH5-BYN-HzX0.js} +1 -1
  15. package/dist-h5/{GroupInfoDialogH5-BHLKs62Z.js → GroupInfoDialogH5-DDjYHm7i.js} +1 -1
  16. package/dist-h5/{GroupMembersH5-D_f1RFjO.js → GroupMembersH5-DUWs89a3.js} +1 -1
  17. package/dist-h5/{GroupNoticeH5-46ZjBe92.js → GroupNoticeH5-C6hNtZzy.js} +1 -1
  18. package/dist-h5/{MemberDetailH5-B7nlr8ZT.js → MemberDetailH5-BZlExAgj.js} +16 -3
  19. package/dist-h5/{SearchPageH5-hYxNItvz.js → SearchPageH5-CjBq_40x.js} +2 -2
  20. package/dist-h5/{SelectMembersH5-DQIfX_w4.js → SelectMembersH5-BSLarLGK.js} +2 -2
  21. package/dist-h5/{imChat-Bfl2JS8Q.js → imChat-CdmqPGQ6.js} +40 -7
  22. package/dist-h5/index.es.js +2 -2
  23. package/dist-h5/{indexH5-CUQe-Ize.js → indexH5-CCseQmQb.js} +9 -4
  24. package/dist-h5/{indexH5-DAnvVyZ1.js → indexH5-DikfbMIK.js} +524 -166
  25. package/dist-h5/style/index-h5.css +1 -1
  26. package/package.json +72 -71
  27. package/dist-h5/request-CK8gkCRf.js +0 -44
@@ -7,6 +7,74 @@ import { showToast } from "vant";
7
7
  import { defineStore } from "pinia";
8
8
  import axios from "axios";
9
9
  import { ElMessage } from "element-plus";
10
+ function normalizeIMIdentity(config = {}) {
11
+ const version = Number(config.imIdentityVersion || 1);
12
+ const tenantID = String(config.tenantID || "");
13
+ const userID = version === 2 ? String(config.imUserID || "") : String(config.userID || "");
14
+ if (![1, 2].includes(version)) throw new Error("不支持的 IM 身份版本");
15
+ if (version === 2 && (!tenantID || !/^mdm2u_[a-f0-9]{48}$/.test(userID))) {
16
+ throw new Error("租户 IM 身份信息不完整");
17
+ }
18
+ return { imIdentityVersion: version, tenantID, userID, imUserID: version === 2 ? userID : "" };
19
+ }
20
+ function imSessionScope(config = {}) {
21
+ if (!config.userID && !config.imUserID) return "";
22
+ const identity = normalizeIMIdentity(config);
23
+ return JSON.stringify([
24
+ config.apiUrl || "",
25
+ config.wsUrl || "",
26
+ identity.tenantID,
27
+ identity.imIdentityVersion,
28
+ identity.userID,
29
+ config.platformID ?? 5
30
+ ]);
31
+ }
32
+ function imCacheNamespace(config = {}) {
33
+ if (!config.tenantID || !config.userID && !config.imUserID) return "";
34
+ return `scope2:${imSessionScope(config)}`;
35
+ }
36
+ function nextIMSession(current, input = {}) {
37
+ const merged = { ...current, ...input };
38
+ if (Number(merged.imIdentityVersion) === 2 && String(current.tenantID || "") !== String(merged.tenantID || "") && !Object.hasOwn(input, "imUserID")) {
39
+ throw new Error("切换租户必须提供目标 IM 身份");
40
+ }
41
+ const next = { ...merged, ...normalizeIMIdentity(merged) };
42
+ if (imSessionScope(current) !== imSessionScope(next)) {
43
+ for (const key of ["imToken", "satoken", "chatToken", "nickname", "faceURL", "remoteConnectUrl", "remoteConnectToken", "businessUserID", "loginCode"]) {
44
+ next[key] = Object.hasOwn(input, key) ? input[key] : "";
45
+ }
46
+ next.loginStatus = 1;
47
+ next.groupStatus = 0;
48
+ next.currentChatId = "";
49
+ next.unReadCount = 0;
50
+ next.isViewingChat = false;
51
+ }
52
+ return next;
53
+ }
54
+ function parseIMBusinessData(value) {
55
+ try {
56
+ const result = typeof value === "string" ? JSON.parse(value) : value;
57
+ return result && typeof result === "object" && !Array.isArray(result) ? result : null;
58
+ } catch {
59
+ return null;
60
+ }
61
+ }
62
+ function shouldHandleLoginNotice(notice, session) {
63
+ if (Number(session.imIdentityVersion) === 2) return false;
64
+ if (!notice || notice.event !== "LOGIN_NOTICE") return false;
65
+ if (notice.tenantID != null && String(notice.tenantID) !== String(session.tenantID)) return false;
66
+ return Boolean(notice.sendUserID && notice.imToken && session.imToken && notice.sendUserID === session.userID && notice.imToken !== session.imToken);
67
+ }
68
+ function assertIMTarget(value, kind = "user") {
69
+ const pattern = kind === "group" ? /^mdm2g_[a-f0-9]{48}$/ : /^mdm2u_[a-f0-9]{48}$/;
70
+ if (!pattern.test(String(value || ""))) throw new Error(kind === "group" ? "请先通过服务端预留租户群组身份" : "消息目标缺少租户 IM 身份");
71
+ }
72
+ function shouldHandleRemoteNotice(notice, session) {
73
+ if (!notice) return false;
74
+ if (Number(session.imIdentityVersion) !== 2) return notice.sendUserID !== session.userID;
75
+ const own = session.imUserID || session.userID;
76
+ return Boolean(own && String(notice.tenantID || "") === String(session.tenantID || "") && /^mdm2u_[a-f0-9]{48}$/.test(notice.sendIMUserID || "") && notice.recvIMUserID === own && notice.sendIMUserID !== own);
77
+ }
10
78
  function transformStatusList(input) {
11
79
  const output = {
12
80
  values: [],
@@ -306,7 +374,11 @@ const useChatStore = defineStore("chatMessage", {
306
374
  state: () => {
307
375
  return {
308
376
  userID: "",
309
- // 用户ID
377
+ // SDK IM identity (legacy hosts still supply loginCode)
378
+ imUserID: "",
379
+ businessUserID: "",
380
+ loginCode: "",
381
+ imIdentityVersion: 1,
310
382
  nickname: "",
311
383
  // 用户昵称
312
384
  faceURL: "",
@@ -368,6 +440,10 @@ const useChatStore = defineStore("chatMessage", {
368
440
  getUserInfo(state) {
369
441
  return {
370
442
  userID: state.userID,
443
+ imUserID: state.imUserID,
444
+ businessUserID: state.businessUserID,
445
+ loginCode: state.loginCode,
446
+ imIdentityVersion: state.imIdentityVersion,
371
447
  nickname: state.nickname,
372
448
  faceURL: state.faceURL,
373
449
  loginStatus: state.loginStatus,
@@ -406,7 +482,10 @@ const useChatStore = defineStore("chatMessage", {
406
482
  },
407
483
  // 更新未读总数
408
484
  setUnReadCount(count = 0) {
409
- this.unReadCount = count;
485
+ const next = Number(count) || 0;
486
+ if (this.unReadCount === next) return;
487
+ console.log("[IM][unread] store 未读总数更新", { from: this.unReadCount, to: next });
488
+ this.unReadCount = next;
410
489
  },
411
490
  // 更新用户的登录状态
412
491
  setLoginStatus(val) {
@@ -418,16 +497,8 @@ const useChatStore = defineStore("chatMessage", {
418
497
  },
419
498
  // 保存登录用户信息
420
499
  setUserInfo(obj) {
421
- this.userID = (obj == null ? void 0 : obj.userID) || this.userID;
422
- this.nickname = (obj == null ? void 0 : obj.nickname) || this.nickname;
423
- this.faceURL = (obj == null ? void 0 : obj.faceURL) || this.faceURL;
424
- this.imToken = (obj == null ? void 0 : obj.imToken) || this.imToken;
425
- this.chatToken = (obj == null ? void 0 : obj.chatToken) || this.chatToken;
426
- this.satoken = (obj == null ? void 0 : obj.satoken) || this.satoken;
427
- this.apiUrl = (obj == null ? void 0 : obj.apiUrl) || this.apiUrl;
428
- this.wsUrl = (obj == null ? void 0 : obj.wsUrl) || this.wsUrl;
429
- this.tenantID = (obj == null ? void 0 : obj.tenantID) || this.tenantID;
430
- this.platformID = obj.platformID || this.platformID;
500
+ const next = nextIMSession(this.$state, obj);
501
+ this.$patch(next);
431
502
  },
432
503
  // 设置窗口聚焦状态
433
504
  setIsFocused(val) {
@@ -456,7 +527,7 @@ const useChatStore = defineStore("chatMessage", {
456
527
  storage: localStorage,
457
528
  // 存储位置(默认 localStorage)
458
529
  // HttpOnly Cookie 认证:satoken 和 imToken 不再持久化到 localStorage,仅保留在 Pinia 内存中
459
- paths: ["userID", "nickname", "faceURL", "platformID", "apiUrl", "wsUrl", "tenantID"]
530
+ paths: ["userID", "nickname", "faceURL", "platformID", "apiUrl", "wsUrl", "tenantID", "imUserID", "businessUserID", "loginCode", "imIdentityVersion"]
460
531
  }
461
532
  ]
462
533
  }
@@ -9947,6 +10018,68 @@ class EventEmitter {
9947
10018
  this.emitter.all.clear();
9948
10019
  }
9949
10020
  }
10021
+ const requestInstance = axios.create({
10022
+ baseURL: "",
10023
+ timeout: 6e4,
10024
+ withCredentials: true
10025
+ // HttpOnly Cookie 认证:自动携带会话 Cookie
10026
+ });
10027
+ requestInstance.defaults.headers.post["Content-Type"] = "application/json; charset=utf-8";
10028
+ requestInstance.interceptors.request.use(
10029
+ function(config) {
10030
+ config.headers["X-Login-Type"] = "3";
10031
+ const chatStore = useChatStore();
10032
+ if (chatStore.satoken) {
10033
+ config.headers["satoken"] = chatStore.satoken;
10034
+ }
10035
+ return config;
10036
+ },
10037
+ function(error) {
10038
+ return Promise.reject(error);
10039
+ }
10040
+ );
10041
+ requestInstance.interceptors.response.use(
10042
+ function(response) {
10043
+ if ((response == null ? void 0 : response.status) == 200) {
10044
+ const code = response == null ? void 0 : response.data.code;
10045
+ if (EXIT_CODE.values.includes(code)) {
10046
+ if (EXIT_CODE[code] !== "token") {
10047
+ ElMessage.error(EXIT_CODE.label[code]);
10048
+ }
10049
+ }
10050
+ } else {
10051
+ ElMessage.error("接口出错,请检查网络后重试");
10052
+ }
10053
+ return response;
10054
+ },
10055
+ function(error) {
10056
+ return Promise.reject(error);
10057
+ }
10058
+ );
10059
+ class IMSessionChangedError extends Error {
10060
+ constructor() {
10061
+ super("IM 会话已切换,请重试");
10062
+ this.name = "IMSessionChangedError";
10063
+ }
10064
+ }
10065
+ function guardIMSDK(sdk, isCurrent) {
10066
+ const lifecycle = /* @__PURE__ */ new Set(["on", "off", "logout"]);
10067
+ return new Proxy(sdk, {
10068
+ get(target, key) {
10069
+ const value = Reflect.get(target, key);
10070
+ if (typeof value !== "function") return value;
10071
+ return (...args) => {
10072
+ if (!lifecycle.has(key) && !isCurrent()) return Promise.reject(new IMSessionChangedError());
10073
+ const result = Reflect.apply(value, target, args);
10074
+ if (!result || typeof result.then !== "function" || lifecycle.has(key)) return result;
10075
+ return result.then((data) => {
10076
+ if (!isCurrent()) throw new IMSessionChangedError();
10077
+ return data;
10078
+ });
10079
+ };
10080
+ }
10081
+ });
10082
+ }
9950
10083
  const HEX = "0123456789abcdef";
9951
10084
  function randomBytes(length) {
9952
10085
  if (typeof crypto !== "undefined" && crypto.getRandomValues) {
@@ -9980,7 +10113,9 @@ class ImKit extends EventEmitter {
9980
10113
  dataDir = "./",
9981
10114
  userID,
9982
10115
  imToken,
9983
- chatToken
10116
+ chatToken,
10117
+ imIdentityVersion = 1,
10118
+ isCurrentSession = () => true
9984
10119
  }) {
9985
10120
  super();
9986
10121
  __publicField(this, "apiUrl", "");
@@ -10004,6 +10139,11 @@ class ImKit extends EventEmitter {
10004
10139
  __publicField(this, "loginStatus", IM_LOGIN_STATUS.Logout);
10005
10140
  // 1 未登录 2 登录中 3 已登录
10006
10141
  __publicField(this, "groupStatus", IM_GROUP_STATUS.Nomal);
10142
+ this.imIdentityVersion = Number(imIdentityVersion);
10143
+ this.isCurrentSession = isCurrentSession;
10144
+ this.disposed = false;
10145
+ this.pendingGroupCreates = /* @__PURE__ */ new Map();
10146
+ this.businessApiUrl = apiUrl;
10007
10147
  this.apiUrl = `${apiUrl}/imapi`;
10008
10148
  this.wsUrl = `${wsUrl}/imws`;
10009
10149
  this.platformID = platformID;
@@ -10039,7 +10179,8 @@ class ImKit extends EventEmitter {
10039
10179
  // @openim/client-sdk和@openim/wasm-client-sdk 不需要初始化,直接调用 login 即可。
10040
10180
  initSDK() {
10041
10181
  try {
10042
- this.IMSDK = Ot();
10182
+ this.disposed = false;
10183
+ this.IMSDK = guardIMSDK(Ot(), () => !this.disposed && this.isCurrentSession());
10043
10184
  this.bindEvent();
10044
10185
  } catch (err) {
10045
10186
  console.error(err);
@@ -10079,6 +10220,7 @@ class ImKit extends EventEmitter {
10079
10220
  }
10080
10221
  // 清空即时通信实例
10081
10222
  clearSDK() {
10223
+ this.disposed = true;
10082
10224
  this.unbindEvent();
10083
10225
  this.IMSDK = null;
10084
10226
  }
@@ -10308,8 +10450,9 @@ class ImKit extends EventEmitter {
10308
10450
  console.log("请先初始化SDK");
10309
10451
  return;
10310
10452
  }
10311
- this.IMSDK.logout().then(() => {
10312
- this.getLoginStatus();
10453
+ return this.IMSDK.logout().then(() => {
10454
+ this.loginStatus = IM_LOGIN_STATUS.Logout;
10455
+ this.emit("updateStatus", this.loginStatus);
10313
10456
  return true;
10314
10457
  }).catch((error) => {
10315
10458
  console.log("IM登出异常:", error);
@@ -10681,20 +10824,20 @@ class ImKit extends EventEmitter {
10681
10824
  }
10682
10825
  /**
10683
10826
  * 获取所有会话的未读消息总数
10684
- * @returns {Number}
10827
+ * @returns {Number|null} 未读总数;获取失败返回 null(调用方不应把 null 当成 0 覆盖本地值)
10685
10828
  */
10686
10829
  async getTotalUnreadMsgCount(operationID = uuidv4()) {
10687
10830
  var _a;
10688
10831
  if (!this.IMSDK) {
10689
- return 0;
10832
+ return null;
10690
10833
  }
10691
10834
  try {
10692
10835
  const res = await ((_a = this.IMSDK) == null ? void 0 : _a.getTotalUnreadMsgCount(operationID));
10693
- return (res == null ? void 0 : res.data) || 0;
10836
+ return Number(res == null ? void 0 : res.data) || 0;
10694
10837
  } catch (error) {
10695
- console.error("获取未读消息总数失败:", error);
10838
+ console.error("[IM][unread] 获取未读消息总数失败:", error);
10696
10839
  this.handleError(error);
10697
- return 0;
10840
+ return null;
10698
10841
  }
10699
10842
  }
10700
10843
  /**
@@ -10982,6 +11125,10 @@ class ImKit extends EventEmitter {
10982
11125
  }
10983
11126
  // 发送消息,发送通过 create***Message 创建的消息,offlinePushInfo-离线消息体,groupID-发送单聊消息时传空字符串
10984
11127
  async sendMessage({ recvID, groupID, offlinePushInfo, message }, operationID = uuidv4()) {
11128
+ if (this.imIdentityVersion === 2) {
11129
+ if (groupID) assertIMTarget(groupID, "group");
11130
+ else assertIMTarget(recvID);
11131
+ }
10985
11132
  try {
10986
11133
  const res = await this.IMSDK.sendMessage({ recvID, groupID, offlinePushInfo, message }, operationID);
10987
11134
  if (res.data) {
@@ -11156,9 +11303,26 @@ class ImKit extends EventEmitter {
11156
11303
  * @param {String} operationID
11157
11304
  */
11158
11305
  async createGroup({ groupInfo, memberUserIDs, ownerUserID, adminUserIDs }, operationID = uuidv4()) {
11159
- var _a;
11306
+ var _a, _b, _c;
11307
+ if (this.imIdentityVersion === 2) {
11308
+ if (this.disposed || !this.isCurrentSession()) throw new IMSessionChangedError();
11309
+ if (ownerUserID !== this.userID) throw new Error("群主必须是当前用户");
11310
+ if (adminUserIDs == null ? void 0 : adminUserIDs.length) throw new Error("请在建群后设置管理员");
11311
+ const spec = JSON.stringify([groupInfo == null ? void 0 : groupInfo.groupName, ownerUserID, [...memberUserIDs || []].sort()]);
11312
+ const requestID = String((groupInfo == null ? void 0 : groupInfo.groupID) || this.pendingGroupCreates.get(spec) || operationID);
11313
+ this.pendingGroupCreates.set(spec, requestID);
11314
+ const result = await requestInstance.post(`${this.businessApiUrl}/api/v1/openim/createTenantGroup`, {
11315
+ requestID,
11316
+ groupName: groupInfo == null ? void 0 : groupInfo.groupName,
11317
+ members: memberUserIDs || []
11318
+ });
11319
+ if (this.disposed || !this.isCurrentSession()) throw new IMSessionChangedError();
11320
+ if (((_a = result.data) == null ? void 0 : _a.code) !== 200) throw new Error(((_b = result.data) == null ? void 0 : _b.msg) || "建群失败");
11321
+ this.pendingGroupCreates.delete(spec);
11322
+ return true;
11323
+ }
11160
11324
  try {
11161
- const res = await ((_a = this.IMSDK) == null ? void 0 : _a.createGroup(
11325
+ const res = await ((_c = this.IMSDK) == null ? void 0 : _c.createGroup(
11162
11326
  {
11163
11327
  groupInfo,
11164
11328
  memberUserIDs,
@@ -11227,6 +11391,10 @@ class ImKit extends EventEmitter {
11227
11391
  * @param {String} operationID
11228
11392
  */
11229
11393
  async inviteUserToGroup({ groupID, userIDList: userIDList2, reason }, operationID = uuidv4()) {
11394
+ if (this.imIdentityVersion === 2) {
11395
+ assertIMTarget(groupID, "group");
11396
+ for (const id of userIDList2 || []) assertIMTarget(id);
11397
+ }
11230
11398
  if (!groupID || !this.IMSDK) return;
11231
11399
  try {
11232
11400
  const res = await this.IMSDK.inviteUserToGroup({ groupID, userIDList: userIDList2, reason }, operationID);
@@ -11610,7 +11778,12 @@ const useUsers = () => {
11610
11778
  const getAllUserStatus = () => {
11611
11779
  return userOnlineStatus.value;
11612
11780
  };
11613
- return { updateUserList, getUserIds, updateUserStatus, getCurrentUserInfo, getAllUserStatus, getUserStatus };
11781
+ const resetUsers = () => {
11782
+ userList.value = [];
11783
+ userIDList.value = [];
11784
+ userOnlineStatus.value = {};
11785
+ };
11786
+ return { resetUsers, updateUserList, getUserIds, updateUserStatus, getCurrentUserInfo, getAllUserStatus, getUserStatus };
11614
11787
  };
11615
11788
  function getDefaultExportFromCjs(x3) {
11616
11789
  return x3 && x3.__esModule && Object.prototype.hasOwnProperty.call(x3, "default") ? x3["default"] : x3;
@@ -36259,7 +36432,12 @@ const toPinyin = (text) => {
36259
36432
  const conversationList = ref([]);
36260
36433
  const skipSortIds = /* @__PURE__ */ new Set();
36261
36434
  const currentConversation = ref({});
36262
- ref([]);
36435
+ const currentConversationUsers = ref([]);
36436
+ let conversationListReady = false;
36437
+ const setConversationListReady = (value) => {
36438
+ conversationListReady = Boolean(value);
36439
+ };
36440
+ const isConversationListReady = () => conversationListReady;
36263
36441
  const useConversations = () => {
36264
36442
  const chatMessage = useChatStore();
36265
36443
  const baseUrl = chatMessage.getBaseUrl;
@@ -36388,8 +36566,12 @@ const useConversations = () => {
36388
36566
  currentConversation.value = curCvs;
36389
36567
  }
36390
36568
  const unreadCount = getUnReadMessageCount();
36391
- if (chatMessage.setUnReadCount) {
36392
- chatMessage.setUnReadCount(unreadCount);
36569
+ if (conversationListReady) {
36570
+ if (chatMessage.setUnReadCount) {
36571
+ chatMessage.setUnReadCount(unreadCount);
36572
+ }
36573
+ } else {
36574
+ console.log("[IM][unread] 会话列表未加载完成,跳过列表汇总覆盖", { listCount: unreadCount });
36393
36575
  }
36394
36576
  };
36395
36577
  const getCurrentConversation = (id) => {
@@ -36448,6 +36630,9 @@ const useConversations = () => {
36448
36630
  if (id) skipSortIds.add(id);
36449
36631
  };
36450
36632
  const clearConversationList = () => {
36633
+ skipSortIds.clear();
36634
+ conversationListReady = false;
36635
+ currentConversationUsers.value = [];
36451
36636
  conversationList.value = [];
36452
36637
  currentConversation.value = {};
36453
36638
  chatMessage.setUnReadCount(0);
@@ -36462,7 +36647,9 @@ const useConversations = () => {
36462
36647
  getConversationIDBySessionType,
36463
36648
  getConversationByKey,
36464
36649
  markSkipNextSort,
36465
- clearConversationList
36650
+ clearConversationList,
36651
+ setConversationListReady,
36652
+ isConversationListReady
36466
36653
  };
36467
36654
  };
36468
36655
  const ga1 = "data:image/png;base64,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";
@@ -36797,9 +36984,10 @@ const handleLinks = (text = "") => {
36797
36984
  });
36798
36985
  };
36799
36986
  const NOTICE_AGENT_PREFIX = "agent_";
36987
+ const isNoticeAgentUser = (userID) => String(userID || "").startsWith(NOTICE_AGENT_PREFIX);
36800
36988
  const isNoticeAgentConversation = (cvs) => {
36801
36989
  if (!cvs || cvs.conversationType !== IM_CVS_TYPE.Single) return false;
36802
- return String(cvs.userID || "").startsWith(NOTICE_AGENT_PREFIX);
36990
+ return isNoticeAgentUser(cvs.userID);
36803
36991
  };
36804
36992
  const createCvsId = (msg) => {
36805
36993
  if (msg.sessionType === IM_CVS_TYPE.Single) {
@@ -37090,7 +37278,14 @@ const useMsgList = () => {
37090
37278
  }
37091
37279
  return obj.sessionType === IM_CVS_TYPE.Group ? `${obj.senderNickname}: [未知消息]` : `${obj.senderNickname}发送了消息`;
37092
37280
  };
37281
+ const clearMessageList = () => {
37282
+ messageList.value = [];
37283
+ startClientMsgID.value = "";
37284
+ isLastMessage.value = true;
37285
+ isFirstMessage.value = false;
37286
+ };
37093
37287
  return {
37288
+ clearMessageList,
37094
37289
  messageList,
37095
37290
  startClientMsgID,
37096
37291
  isLastMessage,
@@ -37271,7 +37466,7 @@ const useBurnAfterReading = () => {
37271
37466
  const origin = Number(startAt) || Date.now();
37272
37467
  const deadline = origin + duration * 1e3;
37273
37468
  if (deadline <= Date.now()) {
37274
- setTimeout(() => runHandlers(conversationID, msg.clientMsgID), 0);
37469
+ timers.set(key, setTimeout(() => fireBurn(conversationID, msg.clientMsgID), 0));
37275
37470
  return;
37276
37471
  }
37277
37472
  deadlines.set(key, deadline);
@@ -39524,13 +39719,14 @@ async function clearCache(userID) {
39524
39719
  function useMessageCache() {
39525
39720
  const chatMessage = useChatStore();
39526
39721
  function _getUserID() {
39527
- return chatMessage.userID || "";
39722
+ return imCacheNamespace(chatMessage);
39528
39723
  }
39529
39724
  async function loadConversationsFromCache() {
39530
39725
  const userID = _getUserID();
39531
39726
  if (!userID) return null;
39532
39727
  try {
39533
39728
  const list = await loadConversations(userID);
39729
+ if (userID !== _getUserID()) return null;
39534
39730
  if (list && Array.isArray(list) && list.length > 0) {
39535
39731
  console.log(
39536
39732
  `[MessageCache] Loaded ${list.length} conversations from IndexedDB cache`
@@ -39558,6 +39754,7 @@ function useMessageCache() {
39558
39754
  if (!userID || !conversationID) return null;
39559
39755
  try {
39560
39756
  const list = await loadMessages(userID, conversationID);
39757
+ if (userID !== _getUserID()) return null;
39561
39758
  if (list && Array.isArray(list) && list.length > 0) {
39562
39759
  console.log(
39563
39760
  `[MessageCache] Loaded ${list.length} messages for ${conversationID} from IndexedDB cache`
@@ -39601,12 +39798,26 @@ function useMessageCache() {
39601
39798
  const mittBus = mitt();
39602
39799
  const newMsgAudioUrl = "data:audio/mpeg;base64,SUQzAwAAAAAgAFRJVDMAAAAYAAAA1b6zpMvYssQoc2MuY2hpbmF6LmNvbSlUUFVCAAAAGAAAANW+s6TL2LLEKHNjLmNoaW5hei5jb20pV09BUgAAABcAANW+s6TL2LLEKHNjLmNoaW5hei5jb20pVEVOQwAAABgAAADVvrOky9iyxChzYy5jaGluYXouY29tKVRBTEIAAAAYAAAA1b6zpMvYssQoc2MuY2hpbmF6LmNvbSlUWUVSAAAABQAAADIwMjBUUEUyAAAAGAAAANW+s6TL2LLEKHNjLmNoaW5hei5jb20pVElUMgAAABgAAADVvrOky9iyxChzYy5jaGluYXouY29tKVRDT04AAAAYAAAA1b6zpMvYssQoc2MuY2hpbmF6LmNvbSlDT01NAAAAHAAAAGNoaQDVvrOky9iyxChzYy5jaGluYXouY29tKVRQRTEAAAAYAAAA1b6zpMvYssQoc2MuY2hpbmF6LmNvbSkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJRDMEAAAAADYkVFhYWAAAAAsAAANUREFUADMwMDYAVFhYWAAAAAsAAANUSU1FADIxMzEAVFhYWAAAAAoAAANjb21tZW50AABQUklWAAA1OQAAWE1QADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+Cjx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTQzIDc5LjE2MTIxMCwgMjAxNy8wOC8xMS0xMDoyODozNiAgICAgICAgIj4KIDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+CiAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIgogICAgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIKICAgIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIgogICAgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIgogICAgeG1sbnM6eG1wRE09Imh0dHA6Ly9ucy5hZG9iZS5jb20veG1wLzEuMC9EeW5hbWljTWVkaWEvIgogICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICAgeG1sbnM6Y3JlYXRvckF0b209Imh0dHA6Ly9ucy5hZG9iZS5jb20vY3JlYXRvckF0b20vMS4wLyIKICAgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo3YjdlYjE0OC03ZTllLTA3NDctYTNlNS05NzlmN2IzZTQ4ODEiCiAgIHhtcE1NOkRvY3VtZW50SUQ9ImU4YTMzOWUyLWI5YjQtM2I5MC02OTFkLWMwZWMwMDAwMDAzZCIKICAgeG1wTU06T3JpZ2luYWxEb2N1bWVudElEPSJ4bXAuZGlkOjM2ZDgxZDUxLWYxM2QtMWQ0MS1hODYxLWIxZTlmZDEyMzgxOCIKICAgeG1wOk1ldGFkYXRhRGF0ZT0iMjAyMC0wNi0zMFQyMTozMTozNCswODowMCIKICAgeG1wOk1vZGlmeURhdGU9IjIwMjAtMDYtMzBUMjE6MzE6MzQrMDg6MDAiCiAgIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUHJlbWllcmUgUHJvIENDIDIwMTguMCAoV2luZG93cykiCiAgIHhtcDpDcmVhdGVEYXRlPSIyMDIwLTA2LTMwVDIxOjMxOjA0KzA4OjAwIgogICB4bXBETTphdWRpb1NhbXBsZVJhdGU9Ii0xIgogICB4bXBETTphdWRpb1NhbXBsZVR5cGU9IjE2SW50IgogICB4bXBETTphdWRpb0NoYW5uZWxUeXBlPSJTdGVyZW8iCiAgIHhtcERNOnN0YXJ0VGltZVNjYWxlPSIzMDAwMCIKICAgeG1wRE06c3RhcnRUaW1lU2FtcGxlU2l6ZT0iMTAwMSIKICAgZGM6Zm9ybWF0PSJNUDMiPgogICA8eG1wTU06SGlzdG9yeT4KICAgIDxyZGY6U2VxPgogICAgIDxyZGY6bGkKICAgICAgc3RFdnQ6YWN0aW9uPSJzYXZlZCIKICAgICAgc3RFdnQ6aW5zdGFuY2VJRD0iZDEwNTQ1NzMtNjlmMS02Y2M2LTJhYTItNzk0ZDAwMDAwMDZhIgogICAgICBzdEV2dDp3aGVuPSIyMDIwLTA2LTMwVDIxOjMxOjM0KzA4OjAwIgogICAgICBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQcmVtaWVyZSBQcm8gQ0MgMjAxOC4wIChXaW5kb3dzKSIKICAgICAgc3RFdnQ6Y2hhbmdlZD0iLyIvPgogICAgIDxyZGY6bGkKICAgICAgc3RFdnQ6YWN0aW9uPSJjcmVhdGVkIgogICAgICBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOjIwYWNhNWE3LTAwMzQtNDM0OC05ZWQ4LTBlMWY3Y2IwOGVhZCIKICAgICAgc3RFdnQ6d2hlbj0iMjAyMC0wNi0zMFQyMTozMTozNCswODowMCIKICAgICAgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUHJlbWllcmUgUHJvIENDIDIwMTguMCAoV2luZG93cykiLz4KICAgICA8cmRmOmxpCiAgICAgIHN0RXZ0OmFjdGlvbj0ic2F2ZWQiCiAgICAgIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6ZmYxY2M1NmItMmUyMS1kMTRlLThhMGEtYTZlYWVjY2ZjODVmIgogICAgICBzdEV2dDp3aGVuPSIyMDIwLTA2LTMwVDIxOjMxOjM0KzA4OjAwIgogICAgICBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQcmVtaWVyZSBQcm8gQ0MgMjAxOC4wIChXaW5kb3dzKSIKICAgICAgc3RFdnQ6Y2hhbmdlZD0iLyIvPgogICAgIDxyZGY6bGkKICAgICAgc3RFdnQ6YWN0aW9uPSJzYXZlZCIKICAgICAgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDo3YjdlYjE0OC03ZTllLTA3NDctYTNlNS05NzlmN2IzZTQ4ODEiCiAgICAgIHN0RXZ0OndoZW49IjIwMjAtMDYtMzBUMjE6MzE6MzQrMDg6MDAiCiAgICAgIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFByZW1pZXJlIFBybyBDQyAyMDE4LjAgKFdpbmRvd3MpIgogICAgICBzdEV2dDpjaGFuZ2VkPSIvbWV0YWRhdGEiLz4KICAgIDwvcmRmOlNlcT4KICAgPC94bXBNTTpIaXN0b3J5PgogICA8eG1wTU06SW5ncmVkaWVudHM+CiAgICA8cmRmOkJhZz4KICAgICA8cmRmOmxpCiAgICAgIHN0UmVmOmluc3RhbmNlSUQ9IjBmODZjODFiLTgxYzAtOTY2Mi1lNGZlLTcyOTMwMDAwMDA2YSIKICAgICAgc3RSZWY6ZG9jdW1lbnRJRD0iZjNjYTE3ZDItZjhlNi1lNjY1LTMyZmEtYTI3ZDAwMDAwMDNkIgogICAgICBzdFJlZjpmcm9tUGFydD0idGltZTo1MDU1NzM4NjQ5NTBmMjU0MDE2MDAwMDAwZDIwOTIwMjk3ODYwMGYyNTQwMTYwMDAwMDAiCiAgICAgIHN0UmVmOnRvUGFydD0idGltZTowZDIwOTIwMjk3ODYwMGYyNTQwMTYwMDAwMDAiCiAgICAgIHN0UmVmOmZpbGVQYXRoPSLlvq7kv6HmnaXkv6Hmga8ubXA0IgogICAgICBzdFJlZjptYXNrTWFya2Vycz0iTm9uZSIvPgogICAgPC9yZGY6QmFnPgogICA8L3htcE1NOkluZ3JlZGllbnRzPgogICA8eG1wTU06UGFudHJ5PgogICAgPHJkZjpCYWc+CiAgICAgPHJkZjpsaT4KICAgICAgPHJkZjpEZXNjcmlwdGlvbgogICAgICAgeG1wOkNyZWF0ZURhdGU9IjE5MDQtMDEtMDFUMDA6MDBaIgogICAgICAgeG1wOk1vZGlmeURhdGU9IjIwMjAtMDYtMzBUMjE6MzA6MzQrMDg6MDAiCiAgICAgICB4bXA6TWV0YWRhdGFEYXRlPSIyMDIwLTA2LTMwVDIxOjMwOjM0KzA4OjAwIgogICAgICAgeG1wRE06bG9nQ29tbWVudD0i5pys6KeG6aKR55Sx5rmW5Y2X5LiA5ZSv5L+h5oGv56eR5oqA5byA5Y+R55qERVblvZXlsY/ova/ku7blvZXliLbvvIx3d3cuaWV3YXkuY24iCiAgICAgICB4bXBNTTpJbnN0YW5jZUlEPSIwZjg2YzgxYi04MWMwLTk2NjItZTRmZS03MjkzMDAwMDAwNmEiCiAgICAgICB4bXBNTTpEb2N1bWVudElEPSJmM2NhMTdkMi1mOGU2LWU2NjUtMzJmYS1hMjdkMDAwMDAwM2QiCiAgICAgICB4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6OTk4YTUwOGUtY2IxMC01ODQ1LWI3YmItYzBhMTg2Yjk5YmJkIj4KICAgICAgPHhtcERNOmR1cmF0aW9uCiAgICAgICB4bXBETTp2YWx1ZT0iMTAyMTkiCiAgICAgICB4bXBETTpzY2FsZT0iMS8xMDAwIi8+CiAgICAgIDxkYzp0aXRsZT4KICAgICAgIDxyZGY6QWx0PgogICAgICAgIDxyZGY6bGkgeG1sOmxhbmc9IngtZGVmYXVsdCI+RVblvZXlsY8zLjkuN+i9r+S7tuW9leWItjwvcmRmOmxpPgogICAgICAgPC9yZGY6QWx0PgogICAgICA8L2RjOnRpdGxlPgogICAgICA8eG1wTU06SGlzdG9yeT4KICAgICAgIDxyZGY6U2VxPgogICAgICAgIDxyZGY6bGkKICAgICAgICAgc3RFdnQ6YWN0aW9uPSJzYXZlZCIKICAgICAgICAgc3RFdnQ6aW5zdGFuY2VJRD0iMGY4NmM4MWItODFjMC05NjYyLWU0ZmUtNzI5MzAwMDAwMDZhIgogICAgICAgICBzdEV2dDp3aGVuPSIyMDIwLTA2LTMwVDIxOjMwOjM0KzA4OjAwIgogICAgICAgICBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQcmVtaWVyZSBQcm8gQ0MgMjAxOC4wIChXaW5kb3dzKSIKICAgICAgICAgc3RFdnQ6Y2hhbmdlZD0iLyIvPgogICAgICAgPC9yZGY6U2VxPgogICAgICA8L3htcE1NOkhpc3Rvcnk+CiAgICAgIDwvcmRmOkRlc2NyaXB0aW9uPgogICAgIDwvcmRmOmxpPgogICAgPC9yZGY6QmFnPgogICA8L3htcE1NOlBhbnRyeT4KICAgPHhtcE1NOkRlcml2ZWRGcm9tCiAgICBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjIwYWNhNWE3LTAwMzQtNDM0OC05ZWQ4LTBlMWY3Y2IwOGVhZCIKICAgIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MjBhY2E1YTctMDAzNC00MzQ4LTllZDgtMGUxZjdjYjA4ZWFkIgogICAgc3RSZWY6b3JpZ2luYWxEb2N1bWVudElEPSJ4bXAuZGlkOjIwYWNhNWE3LTAwMzQtNDM0OC05ZWQ4LTBlMWY3Y2IwOGVhZCIvPgogICA8Y3JlYXRvckF0b206d2luZG93c0F0b20KICAgIGNyZWF0b3JBdG9tOmV4dGVuc2lvbj0iLnBycHJvaiIKICAgIGNyZWF0b3JBdG9tOmludm9jYXRpb25GbGFncz0iL0wiCiAgICBjcmVhdG9yQXRvbTp1bmNQcm9qZWN0UGF0aD0iXFw/XEM6XFVzZXJzXEFkbWluaXN0cmF0b3JcRGVza3RvcFzpn7PmlYgucHJwcm9qIi8+CiAgIDxjcmVhdG9yQXRvbTptYWNBdG9tCiAgICBjcmVhdG9yQXRvbTphcHBsaWNhdGlvbkNvZGU9IjEzNDc0NDk0NTUiCiAgICBjcmVhdG9yQXRvbTppbnZvY2F0aW9uQXBwbGVFdmVudD0iMTEyOTQ2ODAxOCIvPgogICA8eG1wRE06cHJvamVjdFJlZgogICAgeG1wRE06dHlwZT0ibW92aWUiLz4KICAgPHhtcERNOmR1cmF0aW9uCiAgICB4bXBETTp2YWx1ZT0iMjQiCiAgICB4bXBETTpzY2FsZT0iMTAwMS8zMDAwMCIvPgogICA8eG1wRE06c3RhcnRUaW1lY29kZQogICAgeG1wRE06dGltZUZvcm1hdD0iMjk5N0Ryb3BUaW1lY29kZSIKICAgIHhtcERNOnRpbWVWYWx1ZT0iMDA7MDA7MDA7MDAiLz4KICAgPHhtcERNOmFsdFRpbWVjb2RlCiAgICB4bXBETTp0aW1lVmFsdWU9IjAwOzAwOzAwOzAwIgogICAgeG1wRE06dGltZUZvcm1hdD0iMjk5N0Ryb3BUaW1lY29kZSIvPgogIDwvcmRmOkRlc2NyaXB0aW9uPgogPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAg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R+ysrWhKgCe0AAAE////qEyAWeDSGdWZw2wAAAAAAA7PDy2vdviCQp8RAEQmECDyBc0BSO/M6dMN+qqSJlakAAgAYNLPMBcAqVkgNNRfSGxEAVUdCVoDEYqqM/kx96JCmFQDo5y2hvcRYcEUqljw70MeUb1TjyqNJFYy0te9HIr9amt56hKwQlBiAAOqUP+gJNVXC8qDUFX/yj2/T///9cUqAUFriUAu//uUZOiAAs400H1poAomobnNpAgBFw0hSfm8AkCqBqi/DDABgrUeDsQ1TEFNRTMuMTAwVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVMQU1FMy4xMDBVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//tUZOSD8lwZSU8kYAAbgTk54YAAAWwBJwAAACAAAD/AAAAEVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//sUZOGP8AAAf4AAAAgAAA/wAAABAAABpAAAACAAADSAAAAEVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV";
39603
39800
  let imInstance = null;
39801
+ let failedLogoutClient = null;
39802
+ let sessionRevision = 0;
39803
+ let sessionQueue = Promise.resolve();
39804
+ let pendingSessionKey = "";
39805
+ const subscribedStores = /* @__PURE__ */ new WeakSet();
39806
+ let activeSessionScope = "";
39807
+ let reloginTimer = null;
39808
+ const enqueueSession = (operation) => {
39809
+ const result = sessionQueue.then(operation, operation);
39810
+ sessionQueue = result.catch(() => {
39811
+ });
39812
+ return result;
39813
+ };
39604
39814
  let initPromise = null;
39605
39815
  let httpAuthBroken = false;
39606
39816
  let syncFinished = false;
39607
39817
  let syncWaiters = [];
39608
39818
  let conversationBusBound = false;
39609
39819
  let burnHandlerBound = false;
39820
+ let lastUnreadCount = null;
39610
39821
  const resolveSyncWaiters = (ok) => {
39611
39822
  syncFinished = true;
39612
39823
  const waiters = syncWaiters.splice(0);
@@ -39620,7 +39831,8 @@ const resolveSyncWaiters = (ok) => {
39620
39831
  };
39621
39832
  const resetSyncState = () => {
39622
39833
  syncFinished = false;
39623
- syncWaiters = [];
39834
+ const waiters = syncWaiters.splice(0);
39835
+ waiters.forEach((done) => done(false));
39624
39836
  };
39625
39837
  const buildConversationFromMessage = (msg, selfUserID) => {
39626
39838
  if (!msg) return null;
@@ -39698,13 +39910,14 @@ const useMessage = (config = {}) => {
39698
39910
  }
39699
39911
  const loginStatus = computed(() => messageStore.loginStatus);
39700
39912
  let msgAudioEl = null;
39913
+ let initTimer = null;
39701
39914
  const getMsgAudio = () => {
39702
39915
  if (!msgAudioEl) {
39703
39916
  msgAudioEl = new Audio(newMsgAudioUrl);
39704
39917
  }
39705
39918
  return msgAudioEl;
39706
39919
  };
39707
- const { updateUserStatus } = useUsers();
39920
+ const { updateUserStatus, resetUsers } = useUsers();
39708
39921
  const {
39709
39922
  conversationList: conversationList2,
39710
39923
  currentConversation: currentConversation2,
@@ -39712,10 +39925,13 @@ const useMessage = (config = {}) => {
39712
39925
  updateConversationLatestMessage,
39713
39926
  getConversationIDBySessionType,
39714
39927
  getConversationByKey,
39715
- clearConversationList
39928
+ clearConversationList,
39929
+ setConversationListReady: setConversationListReady2,
39930
+ isConversationListReady: isConversationListReady2
39716
39931
  } = useConversations();
39717
39932
  const {
39718
39933
  messageList: messageList2,
39934
+ clearMessageList,
39719
39935
  updateMessageList,
39720
39936
  updateMessageIsRead,
39721
39937
  handleMessage,
@@ -39730,6 +39946,8 @@ const useMessage = (config = {}) => {
39730
39946
  onBurn(async (conversationID, clientMsgID) => {
39731
39947
  var _a;
39732
39948
  if (!conversationID || !clientMsgID) return;
39949
+ const burnScope = imSessionScope(messageStore);
39950
+ const burnRevision = sessionRevision;
39733
39951
  const inCurrentList = messageList2.value.some((item) => item.clientMsgID === clientMsgID);
39734
39952
  if (inCurrentList) deleteMessageById(clientMsgID);
39735
39953
  try {
@@ -39737,6 +39955,7 @@ const useMessage = (config = {}) => {
39737
39955
  } catch (error) {
39738
39956
  console.error("[IM] 删除焚毁消息失败:", error);
39739
39957
  }
39958
+ if (burnRevision !== sessionRevision || burnScope !== imSessionScope(messageStore)) return;
39740
39959
  if (inCurrentList) {
39741
39960
  const rest = JSON.parse(JSON.stringify(messageList2.value));
39742
39961
  saveMessagesToCache(conversationID, rest);
@@ -39746,6 +39965,7 @@ const useMessage = (config = {}) => {
39746
39965
  }
39747
39966
  try {
39748
39967
  const cached = await loadMessagesFromCache(conversationID);
39968
+ if (burnRevision !== sessionRevision || burnScope !== imSessionScope(messageStore)) return;
39749
39969
  if ((_a = cached == null ? void 0 : cached.list) == null ? void 0 : _a.length) {
39750
39970
  const rest = cached.list.filter((item) => item.clientMsgID !== clientMsgID);
39751
39971
  saveMessagesToCache(conversationID, rest);
@@ -39767,20 +39987,64 @@ const useMessage = (config = {}) => {
39767
39987
  if (((_a = currentConversation2.value) == null ? void 0 : _a.conversationID) === data.conversationID) {
39768
39988
  currentConversation2.value = { ...currentConversation2.value, ...data };
39769
39989
  }
39990
+ refreshUnreadCount();
39770
39991
  });
39771
39992
  }
39772
- const getUnReadMessageCount = async (bool = false) => {
39993
+ const publishUnreadCount = (reason = "update", extra = {}) => {
39994
+ if (reason === "init") {
39995
+ setConversationListReady2(true);
39996
+ if (conversationList2.value.length > 0) {
39997
+ const listCount = conversationList2.value.reduce(
39998
+ (pre, cur) => pre + (cur.unreadCount > 0 ? cur.unreadCount : 0),
39999
+ 0
40000
+ );
40001
+ messageStore.setUnReadCount(listCount);
40002
+ }
40003
+ }
40004
+ const count = Number(messageStore.getUnReadCount) || 0;
40005
+ lastUnreadCount = count;
40006
+ const payload = { count, reason, time: Date.now(), ...extra };
40007
+ console.log("[IM][unread] 广播未读消息事件", payload);
40008
+ mittBus.emit("IM_UNREAD_COUNT_CHANGED", payload);
40009
+ };
40010
+ const publishUnreadIfChanged = (reason = "update") => {
40011
+ if ((Number(messageStore.getUnReadCount) || 0) === lastUnreadCount) return;
40012
+ publishUnreadCount(reason);
40013
+ };
40014
+ const refreshUnreadCount = () => {
40015
+ if (isConversationListReady2()) {
40016
+ publishUnreadIfChanged("update");
40017
+ } else {
40018
+ getUnReadMessageCount(true);
40019
+ }
40020
+ };
40021
+ const getUnReadMessageCount = async (bool = false, reason = "update", extra = {}) => {
39773
40022
  if (bool) {
39774
40023
  if (!imInstance) return;
40024
+ const countScope = imSessionScope(messageStore);
40025
+ const countRevision = sessionRevision;
39775
40026
  const count = await (imInstance == null ? void 0 : imInstance.getTotalUnreadMsgCount());
40027
+ if (countRevision !== sessionRevision || countScope !== imSessionScope(messageStore)) return;
40028
+ if (count == null) {
40029
+ console.warn("[IM][unread] SDK 未读总数获取失败,保留当前未读数", {
40030
+ current: messageStore.getUnReadCount
40031
+ });
40032
+ return;
40033
+ }
40034
+ console.log("[IM][unread] 重新计算未读总数", { source: "sdk", count: count || 0, reason });
39776
40035
  messageStore.setUnReadCount(count || 0);
39777
40036
  } else {
39778
40037
  const count = conversationList2.value.reduce((pre, cur) => {
39779
40038
  return pre + (cur.unreadCount > 0 ? cur.unreadCount : 0);
39780
40039
  }, 0);
39781
- console.log("全部未读消息1:", count);
40040
+ console.log("[IM][unread] 重新计算未读总数", { source: "conversationList", count, reason });
39782
40041
  messageStore.setUnReadCount(count || 0);
39783
40042
  }
40043
+ if (reason === "receive") {
40044
+ publishUnreadCount(reason, extra);
40045
+ } else {
40046
+ publishUnreadIfChanged(reason);
40047
+ }
39784
40048
  };
39785
40049
  const setConversationMsgAsRead = async (id) => {
39786
40050
  var _a;
@@ -39802,47 +40066,91 @@ const useMessage = (config = {}) => {
39802
40066
  }
39803
40067
  return bool;
39804
40068
  };
39805
- const initIMSDK = async (force = false) => {
39806
- if (initPromise) return initPromise;
39807
- const sameSession = !force && !!imInstance && messageStore.loginStatus === IM_LOGIN_STATUS.Logged && imInstance.userID === String(messageStore.userID || "") && imInstance.imToken === messageStore.imToken && imInstance.apiUrl === `${messageStore.apiUrl}/imapi` && imInstance.wsUrl === `${messageStore.wsUrl}/imws`;
39808
- if (sameSession) {
39809
- window["imInstance"] = imInstance;
39810
- return true;
39811
- }
39812
- initPromise = (async () => {
39813
- if (messageStore.loginStatus === IM_LOGIN_STATUS.Logged) {
39814
- await clearInstance();
40069
+ const disposeInstance = async (clearData = true) => {
40070
+ if (reloginTimer) clearTimeout(reloginTimer);
40071
+ reloginTimer = null;
40072
+ if (initTimer) clearTimeout(initTimer);
40073
+ initTimer = null;
40074
+ unbindMessageEvent();
40075
+ cancelAllBurns();
40076
+ const previous = imInstance || failedLogoutClient;
40077
+ previous == null ? void 0 : previous.removeAllListeners();
40078
+ let loggedOut = false;
40079
+ try {
40080
+ const result = await (previous == null ? void 0 : previous.logout());
40081
+ if (result === false) throw new Error("IM 退出失败,请重试后再切换");
40082
+ loggedOut = true;
40083
+ } catch (error) {
40084
+ failedLogoutClient = previous;
40085
+ throw error;
40086
+ } finally {
40087
+ if (loggedOut) {
40088
+ previous == null ? void 0 : previous.clearSDK();
40089
+ if (failedLogoutClient === previous) failedLogoutClient = null;
39815
40090
  }
40091
+ if (imInstance === previous) imInstance = null;
40092
+ if (typeof window !== "undefined" && window.imInstance === previous) window.imInstance = null;
39816
40093
  resetSyncState();
39817
- if (!imInstance) {
39818
- imInstance = new ImKit({
39819
- userID: messageStore.userID,
39820
- imToken: messageStore.imToken,
39821
- chatToken: messageStore.chatToken,
39822
- apiUrl: messageStore.apiUrl,
39823
- wsUrl: messageStore.wsUrl
39824
- });
39825
- } else {
39826
- imInstance.userID = String(messageStore.userID || "");
39827
- imInstance.imToken = messageStore.imToken;
39828
- imInstance.chatToken = messageStore.chatToken;
39829
- imInstance.apiUrl = `${messageStore.apiUrl}/imapi`;
39830
- imInstance.wsUrl = `${messageStore.wsUrl}/imws`;
40094
+ lastUnreadCount = null;
40095
+ if (clearData) {
40096
+ clearConversationList();
40097
+ clearMessageList();
40098
+ resetUsers();
40099
+ messageStore.currentChatId = "";
40100
+ messageStore.remoteConnectUrl = "";
40101
+ messageStore.remoteConnectToken = "";
40102
+ messageStore.isViewingChat = false;
40103
+ }
40104
+ messageStore.setLoginStatus(IM_LOGIN_STATUS.Logout);
40105
+ }
40106
+ };
40107
+ const initIMSDK = async (force = false) => {
40108
+ const snapshot = { ...messageStore.$state, ...normalizeIMIdentity(messageStore) };
40109
+ const scope = imSessionScope(snapshot);
40110
+ if (!scope || !snapshot.imToken) return false;
40111
+ const key = JSON.stringify([scope, snapshot.imToken]);
40112
+ if (initPromise && pendingSessionKey === key) return initPromise;
40113
+ const sameSession = !force && imInstance && activeSessionScope === scope && messageStore.loginStatus === IM_LOGIN_STATUS.Logged && imInstance.imToken === snapshot.imToken;
40114
+ if (sameSession && !initPromise) return true;
40115
+ const revision = ++sessionRevision;
40116
+ pendingSessionKey = key;
40117
+ const operation = enqueueSession(async () => {
40118
+ if (revision !== sessionRevision || imSessionScope(messageStore) !== scope) return false;
40119
+ await disposeInstance(activeSessionScope !== scope);
40120
+ if (revision !== sessionRevision || imSessionScope(messageStore) !== scope) return false;
40121
+ activeSessionScope = scope;
40122
+ const client = new ImKit({
40123
+ userID: snapshot.userID,
40124
+ imToken: snapshot.imToken,
40125
+ chatToken: snapshot.chatToken,
40126
+ imIdentityVersion: snapshot.imIdentityVersion,
40127
+ apiUrl: snapshot.apiUrl,
40128
+ wsUrl: snapshot.wsUrl,
40129
+ platformID: snapshot.platformID,
40130
+ isCurrentSession: () => revision === sessionRevision && imSessionScope(messageStore) === scope
40131
+ });
40132
+ imInstance = client;
40133
+ client.initSDK();
40134
+ bindMessageEvent(client, revision, scope);
40135
+ const loginOk = await client.login();
40136
+ if (revision !== sessionRevision || imSessionScope(messageStore) !== scope) {
40137
+ await disposeInstance(true);
40138
+ return false;
39831
40139
  }
39832
- imInstance == null ? void 0 : imInstance.initSDK();
39833
- bindMessageEvent();
39834
- const loginOk = await (imInstance == null ? void 0 : imInstance.login());
39835
40140
  if (loginOk !== false) httpAuthBroken = false;
39836
- window["imInstance"] = imInstance;
40141
+ if (typeof window !== "undefined") window.imInstance = client;
39837
40142
  return loginOk !== false;
39838
- })();
40143
+ });
40144
+ initPromise = operation;
39839
40145
  try {
39840
- return await initPromise;
40146
+ return await operation;
39841
40147
  } finally {
39842
- initPromise = null;
40148
+ if (initPromise === operation) {
40149
+ initPromise = null;
40150
+ pendingSessionKey = "";
40151
+ }
39843
40152
  }
39844
40153
  };
39845
- let reloginTimer = null;
39846
40154
  let reloginAttempts = 0;
39847
40155
  let tokenInvalidNotified = false;
39848
40156
  let recoveredToken = "";
@@ -39859,11 +40167,17 @@ const useMessage = (config = {}) => {
39859
40167
  notifyTokenInvalid({ errMsg: "auto relogin exhausted" });
39860
40168
  return;
39861
40169
  }
40170
+ const recoveryScope = imSessionScope(messageStore);
40171
+ const recoveryRevision = sessionRevision;
39862
40172
  reloginTimer = setTimeout(async () => {
39863
40173
  reloginTimer = null;
40174
+ if (recoveryRevision !== sessionRevision || recoveryScope !== imSessionScope(messageStore)) return;
39864
40175
  reloginAttempts += 1;
39865
40176
  console.warn(`[IM] token 已失效,自动重新登录(第 ${reloginAttempts} 次)`);
39866
40177
  const ok = await initIMSDK(true);
40178
+ const recoveryClient = imInstance;
40179
+ const currentRevision = sessionRevision;
40180
+ if (recoveryScope !== imSessionScope(messageStore) || !recoveryClient) return;
39867
40181
  if (!ok) {
39868
40182
  tryRelogin();
39869
40183
  return;
@@ -39872,7 +40186,9 @@ const useMessage = (config = {}) => {
39872
40186
  tokenInvalidNotified = false;
39873
40187
  try {
39874
40188
  await waitForSyncFinish(8e3);
39875
- const list = await (imInstance == null ? void 0 : imInstance.getConversationListSplit(0, 200));
40189
+ if (currentRevision !== sessionRevision || recoveryScope !== imSessionScope(messageStore)) return;
40190
+ const list = await recoveryClient.getConversationListSplit(0, 200);
40191
+ if (currentRevision !== sessionRevision || recoveryScope !== imSessionScope(messageStore)) return;
39876
40192
  if (list == null ? void 0 : list.length) {
39877
40193
  handleConversationList(list, "init", handleMessage);
39878
40194
  }
@@ -39906,34 +40222,31 @@ const useMessage = (config = {}) => {
39906
40222
  tokenInvalidNotified = false;
39907
40223
  tryRelogin();
39908
40224
  };
39909
- const clearInstance = async (bool) => {
39910
- unbindMessageEvent();
39911
- cancelAllBurns();
39912
- imInstance == null ? void 0 : imInstance.removeAllListeners();
39913
- await (imInstance == null ? void 0 : imInstance.logout());
39914
- imInstance == null ? void 0 : imInstance.clearSDK();
39915
- if (imInstance) {
39916
- imInstance.syncFinished = false;
39917
- }
39918
- resetSyncState();
39919
- if (bool) {
39920
- imInstance = null;
39921
- window.imInstance = null;
39922
- clearConversationList();
39923
- }
39924
- messageStore.setLoginStatus(IM_LOGIN_STATUS.Logout);
40225
+ const clearInstance = async () => {
40226
+ ++sessionRevision;
40227
+ pendingSessionKey = "";
40228
+ if (reloginTimer) clearTimeout(reloginTimer);
40229
+ reloginTimer = null;
40230
+ return enqueueSession(async () => {
40231
+ await disposeInstance(true);
40232
+ activeSessionScope = "";
40233
+ });
39925
40234
  };
39926
- const bindMessageEvent = () => {
39927
- if (!imInstance || !imInstance.on) return;
39928
- imInstance.on("im-error", handleImError);
40235
+ const bindMessageEvent = (client, revision, scope) => {
40236
+ const isActive = () => revision === sessionRevision && client === imInstance && imSessionScope(messageStore) === scope;
40237
+ const onSessionEvent = (event, handler) => client.on(event, (...args) => {
40238
+ if (isActive()) return handler(...args);
40239
+ });
40240
+ if (!client || !client.on) return;
40241
+ onSessionEvent("im-error", handleImError);
39929
40242
  bindUnhandledRejection(handleImError);
39930
- imInstance.on(CbEvents.OnUserTokenExpired, () => {
40243
+ onSessionEvent(CbEvents.OnUserTokenExpired, () => {
39931
40244
  console.log("用户授权信息过期,重新登录");
39932
40245
  });
39933
- imInstance.on(CbEvents.OnSelfInfoUpdated, (data) => {
40246
+ onSessionEvent(CbEvents.OnSelfInfoUpdated, (data) => {
39934
40247
  console.log("用户资料更新:", data);
39935
40248
  });
39936
- imInstance.on(CbEvents.OnUserStatusChanged, (data) => {
40249
+ onSessionEvent(CbEvents.OnUserStatusChanged, (data) => {
39937
40250
  console.log("用户在线状态变化:", data);
39938
40251
  if (data == null ? void 0 : data.userID) {
39939
40252
  updateUserStatus([data]);
@@ -39955,11 +40268,10 @@ const useMessage = (config = {}) => {
39955
40268
  }
39956
40269
  });
39957
40270
  const handleSunloginEvent = (data) => {
39958
- var _a;
39959
- const info = typeof data.data === "string" && data.data.indexOf("{") > -1 ? JSON.parse(data.data) : {};
40271
+ const info = parseIMBusinessData(data.data);
40272
+ if (!info) return;
39960
40273
  const { event, sendUserID, recvUserID, sendUserName, address, session } = info;
39961
- const currentUserId = (_a = messageStore.getUserInfo) == null ? void 0 : _a.userID;
39962
- if (sendUserID === currentUserId) return;
40274
+ if (!shouldHandleRemoteNotice(info, messageStore.getUserInfo)) return;
39963
40275
  const SUN_EVENTS = {
39964
40276
  "create-sl-remote": () => mittBus.emit("createSLRemote", { address, session }),
39965
40277
  "apply-sl-control": () => mittBus.emit("applySLControl", { sendUserName, sendUserID, recvUserID }),
@@ -39973,17 +40285,13 @@ const useMessage = (config = {}) => {
39973
40285
  if (handler) handler();
39974
40286
  };
39975
40287
  const handleImNoticeEvent = (data) => {
39976
- var _a, _b;
39977
- const info = typeof data.data === "string" && data.data.indexOf("{") > -1 ? JSON.parse(data.data) : {};
39978
- const { event, sendUserID, imToken } = info;
39979
- if (event !== "LOGIN_NOTICE") return;
39980
- const currentUserId = (_a = messageStore.getUserInfo) == null ? void 0 : _a.userID;
39981
- const curImToken = (_b = messageStore.getUserInfo) == null ? void 0 : _b.imToken;
39982
- if (sendUserID === currentUserId && imToken !== curImToken) {
40288
+ const info = parseIMBusinessData(data.data);
40289
+ if (!info) return;
40290
+ if (shouldHandleLoginNotice(info, messageStore.getUserInfo)) {
39983
40291
  mittBus.emit("LOGOUT_NOTICE");
39984
40292
  }
39985
40293
  };
39986
- imInstance.on(CbEvents.OnRecvCustomBusinessMessage, (data) => {
40294
+ onSessionEvent(CbEvents.OnRecvCustomBusinessMessage, (data) => {
39987
40295
  if (data.key === "sunlogin") {
39988
40296
  handleSunloginEvent(data);
39989
40297
  } else if (data.key === "imNotice") {
@@ -39993,13 +40301,14 @@ const useMessage = (config = {}) => {
39993
40301
  const resolveConversationIDs = async (list) => {
39994
40302
  var _a;
39995
40303
  for (let i3 = 0; i3 < list.length; i3++) {
40304
+ if (!isActive()) return;
39996
40305
  const item = list[i3];
39997
40306
  let cvsId = getConversationIDBySessionType(item, "sendID");
39998
40307
  if (!cvsId) {
39999
40308
  let info = null;
40000
40309
  if (!httpAuthBroken) {
40001
40310
  try {
40002
- info = await (imInstance == null ? void 0 : imInstance.getOneConversation(
40311
+ info = await (client == null ? void 0 : client.getOneConversation(
40003
40312
  item.sessionType === IM_CVS_TYPE.Single ? item.sendID : item.groupID,
40004
40313
  item == null ? void 0 : item.sessionType
40005
40314
  ));
@@ -40007,6 +40316,7 @@ const useMessage = (config = {}) => {
40007
40316
  console.warn("[IM] 获取会话信息失败,改用消息数据兜底:", error);
40008
40317
  }
40009
40318
  }
40319
+ if (!isActive()) return;
40010
40320
  if (info == null ? void 0 : info.conversationID) {
40011
40321
  item.showName = info.showName;
40012
40322
  item.faceURL = info.faceURL;
@@ -40015,7 +40325,8 @@ const useMessage = (config = {}) => {
40015
40325
  handleConversationList([info], "add", handleMessage);
40016
40326
  if (info.ex) {
40017
40327
  const clearedEx = preserveBurnInEx("", info.ex);
40018
- await (imInstance == null ? void 0 : imInstance.setConversation({ conversationID: cvsId, ex: clearedEx }));
40328
+ await (client == null ? void 0 : client.setConversation({ conversationID: cvsId, ex: clearedEx }));
40329
+ if (!isActive()) return;
40019
40330
  info.ex = clearedEx;
40020
40331
  }
40021
40332
  } else {
@@ -40050,6 +40361,7 @@ const useMessage = (config = {}) => {
40050
40361
  for (const [cvsID, items] of grouped) {
40051
40362
  try {
40052
40363
  const cached = ((_a = await loadMessagesFromCache(cvsID)) == null ? void 0 : _a.list) || [];
40364
+ if (!isActive()) return;
40053
40365
  saveMessagesToCache(cvsID, dedupeMessages([...cached, ...items]));
40054
40366
  } catch (error) {
40055
40367
  console.warn("[IM] 兜底会话消息写入缓存失败:", error);
@@ -40060,6 +40372,7 @@ const useMessage = (config = {}) => {
40060
40372
  const curMsgList = [];
40061
40373
  const cvs = currentConversation2.value;
40062
40374
  for (let i3 = 0; i3 < list.length; i3++) {
40375
+ if (!isActive()) return;
40063
40376
  const item = list[i3];
40064
40377
  const cvsId = item.conversationID;
40065
40378
  if (item.sessionType === IM_CVS_TYPE.Single && (cvs == null ? void 0 : cvs.userID) === item.sendID || item.groupID && cvs.groupID === item.groupID) {
@@ -40077,11 +40390,14 @@ const useMessage = (config = {}) => {
40077
40390
  }
40078
40391
  return curMsgList;
40079
40392
  };
40080
- imInstance.on(CbEvents.OnRecvNewMessages, async (list) => {
40393
+ onSessionEvent(CbEvents.OnRecvNewMessages, async (list) => {
40394
+ var _a;
40081
40395
  console.log("批量接收消息:", list);
40082
40396
  if ((list == null ? void 0 : list.length) > 0) {
40083
40397
  await resolveConversationIDs(list);
40398
+ if (!isActive()) return;
40084
40399
  await cacheFallbackMessages(list);
40400
+ if (!isActive()) return;
40085
40401
  const curMsgList = routeMessages(list);
40086
40402
  if (curMsgList.length > 0) {
40087
40403
  const cvs = currentConversation2.value;
@@ -40090,9 +40406,12 @@ const useMessage = (config = {}) => {
40090
40406
  const latestMsg = curMsgList[curMsgList.length - 1];
40091
40407
  updateConversationLatestMessage(cvs.conversationID, latestMsg, handleMessage(latestMsg));
40092
40408
  }
40409
+ if (!isActive()) return;
40410
+ const cvsId = ((_a = list[list.length - 1]) == null ? void 0 : _a.conversationID) || "";
40411
+ await getUnReadMessageCount(!isConversationListReady2(), "receive", { conversationID: cvsId });
40093
40412
  }
40094
40413
  });
40095
- imInstance.on(CbEvents.OnRecvC2CReadReceipt, async (list) => {
40414
+ onSessionEvent(CbEvents.OnRecvC2CReadReceipt, async (list) => {
40096
40415
  if ((list == null ? void 0 : list.length) > 0) {
40097
40416
  const cvs = currentConversation2.value;
40098
40417
  const curList = list.filter((item) => item.userID === (cvs == null ? void 0 : cvs.userID) && item.sessionType === IM_CVS_TYPE.Single);
@@ -40107,45 +40426,52 @@ const useMessage = (config = {}) => {
40107
40426
  setConversationMsgAsRead(cvs.conversationID);
40108
40427
  }
40109
40428
  });
40110
- imInstance.on(CbEvents.OnNewRecvMessageRevoked, (data) => {
40429
+ onSessionEvent(CbEvents.OnNewRecvMessageRevoked, (data) => {
40111
40430
  if (data == null ? void 0 : data.clientMsgID) {
40112
40431
  revokeMessage(data);
40113
40432
  }
40114
40433
  });
40115
- imInstance.on("updateStatus", (val = 1) => {
40434
+ onSessionEvent("updateStatus", (val = 1) => {
40116
40435
  console.log("登录状态", val);
40117
40436
  messageStore.setLoginStatus(val);
40118
40437
  if (val === IM_LOGIN_STATUS.Logged) {
40119
- setTimeout(() => {
40120
- getUnReadMessageCount();
40438
+ initTimer = setTimeout(() => {
40439
+ if (!isActive()) return;
40440
+ getUnReadMessageCount(true);
40121
40441
  }, 1e3);
40122
40442
  } else if (val === IM_LOGIN_STATUS.Logout) {
40123
40443
  mittBus.emit("IM_LOGOUT");
40124
40444
  }
40125
40445
  });
40126
- imInstance.on(CbEvents.OnSyncServerStart, () => {
40446
+ onSessionEvent(CbEvents.OnSyncServerStart, () => {
40127
40447
  console.log("IM 服务端同步开始");
40128
40448
  syncFinished = false;
40129
40449
  });
40130
- imInstance.on(CbEvents.OnSyncServerFinish, () => {
40450
+ onSessionEvent(CbEvents.OnSyncServerFinish, () => {
40131
40451
  console.log("IM 服务端同步完成");
40132
40452
  resolveSyncWaiters(true);
40133
40453
  mittBus.emit("IM_SYNC_SERVER_FINISH", true);
40454
+ getUnReadMessageCount(true);
40134
40455
  });
40135
- imInstance.on(CbEvents.OnSyncServerFailed, (data) => {
40456
+ onSessionEvent(CbEvents.OnSyncServerFailed, (data) => {
40136
40457
  console.warn("IM 服务端同步失败:", data);
40137
40458
  resolveSyncWaiters(false);
40138
40459
  mittBus.emit("IM_SYNC_SERVER_FINISH", false);
40139
40460
  });
40140
- imInstance.on("im-error", async (err) => {
40461
+ onSessionEvent("im-error", async (err) => {
40462
+ if (initTimer) {
40463
+ clearTimeout(initTimer);
40464
+ initTimer = null;
40465
+ }
40141
40466
  });
40142
- imInstance.on(CbEvents.OnConversationChanged, (data) => {
40467
+ onSessionEvent(CbEvents.OnConversationChanged, (data) => {
40143
40468
  if (Array.isArray(data) && (data == null ? void 0 : data.length)) {
40144
40469
  console.log("会话状态改变:", data);
40145
40470
  handleConversationList(data, "update", handleMessage);
40471
+ refreshUnreadCount();
40146
40472
  }
40147
40473
  });
40148
- imInstance.on(CbEvents.OnNewConversation, async (data) => {
40474
+ onSessionEvent(CbEvents.OnNewConversation, async (data) => {
40149
40475
  console.log("新会话:", data);
40150
40476
  if (data == null ? void 0 : data.length) {
40151
40477
  const cvsIds = conversationList2.value.map((item) => item.conversationID);
@@ -40153,7 +40479,8 @@ const useMessage = (config = {}) => {
40153
40479
  const userIds = newList.filter((item) => item.conversationType === IM_CVS_TYPE.Single).map((item) => item.userID);
40154
40480
  let statusInfo = {};
40155
40481
  if (userIds.length > 0) {
40156
- const statusList = await (imInstance == null ? void 0 : imInstance.subscribeUsersStatus(userIds));
40482
+ const statusList = await (client == null ? void 0 : client.subscribeUsersStatus(userIds));
40483
+ if (!isActive()) return;
40157
40484
  statusInfo = updateUserStatus(statusList);
40158
40485
  }
40159
40486
  newList.forEach((item) => {
@@ -40166,51 +40493,52 @@ const useMessage = (config = {}) => {
40166
40493
  } else if (newList.length > 0) {
40167
40494
  handleConversationList(newList, "add", handleMessage);
40168
40495
  }
40496
+ refreshUnreadCount();
40169
40497
  mittBus.emit("OnNewConversationCreated", data);
40170
40498
  }
40171
40499
  });
40172
- imInstance.on(CbEvents.OnGroupInfoChanged, (data) => {
40500
+ onSessionEvent(CbEvents.OnGroupInfoChanged, (data) => {
40173
40501
  if (data == null ? void 0 : data.groupID) {
40174
40502
  mittBus.emit("OnGroupInfoChanged", data);
40175
40503
  }
40176
40504
  });
40177
- imInstance.on(CbEvents.OnGroupMemberInfoChanged, (data) => {
40505
+ onSessionEvent(CbEvents.OnGroupMemberInfoChanged, (data) => {
40178
40506
  if (data == null ? void 0 : data.groupID) {
40179
40507
  updateMessageSenderInfo(data);
40180
40508
  mittBus.emit("OnGroupMemberInfoChanged", data);
40181
40509
  }
40182
40510
  });
40183
- imInstance.on(CbEvents.OnJoinedGroupAdded, (data) => {
40511
+ onSessionEvent(CbEvents.OnJoinedGroupAdded, (data) => {
40184
40512
  if (data == null ? void 0 : data.groupID) {
40185
40513
  mittBus.emit("OnJoinedGroupAdded", data.groupID);
40186
40514
  }
40187
40515
  });
40188
- imInstance.on(CbEvents.OnGroupMemberAdded, (data) => {
40516
+ onSessionEvent(CbEvents.OnGroupMemberAdded, (data) => {
40189
40517
  if (data == null ? void 0 : data.groupID) {
40190
40518
  mittBus.emit("OnGroupMemberAdded", data);
40191
40519
  }
40192
40520
  });
40193
- imInstance.on(CbEvents.OnGroupApplicationAdded, (data) => {
40521
+ onSessionEvent(CbEvents.OnGroupApplicationAdded, (data) => {
40194
40522
  console.log("收到入群申请通知:", data);
40195
40523
  mittBus.emit("OnGroupApplicationAdded", data);
40196
40524
  });
40197
- imInstance.on(CbEvents.OnGroupApplicationAccepted, (data) => {
40525
+ onSessionEvent(CbEvents.OnGroupApplicationAccepted, (data) => {
40198
40526
  console.log("入群申请被同意:", data);
40199
40527
  mittBus.emit("OnGroupApplicationAccepted", data);
40200
40528
  });
40201
- imInstance.on(CbEvents.OnGroupApplicationRejected, (data) => {
40529
+ onSessionEvent(CbEvents.OnGroupApplicationRejected, (data) => {
40202
40530
  console.log("入群申请被拒绝:", data);
40203
40531
  mittBus.emit("OnGroupApplicationRejected", data);
40204
40532
  });
40205
- imInstance.on(CbEvents.OnJoinedGroupDeleted, (data) => {
40533
+ onSessionEvent(CbEvents.OnJoinedGroupDeleted, (data) => {
40206
40534
  if (data.groupID) {
40207
40535
  mittBus.emit("OnJoinedGroupDeleted", data.groupID);
40208
40536
  }
40209
40537
  });
40210
- imInstance.on(CbEvents.OnGroupMemberDeleted, (data) => {
40538
+ onSessionEvent(CbEvents.OnGroupMemberDeleted, (data) => {
40211
40539
  mittBus.emit("OnGroupMemberDeleted", data);
40212
40540
  });
40213
- imInstance.on(CbEvents.OnGroupDismissed, (data) => {
40541
+ onSessionEvent(CbEvents.OnGroupDismissed, (data) => {
40214
40542
  if (data && data.groupID) {
40215
40543
  data.status = IM_GROUP_STATUS.Dismissed;
40216
40544
  mittBus.emit("OnGroupInfoChanged", data);
@@ -40245,6 +40573,24 @@ const useMessage = (config = {}) => {
40245
40573
  imInstance.off(CbEvents.OnGroupApplicationAccepted);
40246
40574
  imInstance.off(CbEvents.OnGroupApplicationRejected);
40247
40575
  };
40576
+ if (!subscribedStores.has(messageStore)) {
40577
+ subscribedStores.add(messageStore);
40578
+ let previousScope = imSessionScope(messageStore);
40579
+ messageStore.$subscribe((_mutation, state) => {
40580
+ let nextScope = "";
40581
+ try {
40582
+ nextScope = imSessionScope(state);
40583
+ } catch {
40584
+ }
40585
+ if (previousScope === nextScope) return;
40586
+ previousScope = nextScope;
40587
+ clearConversationList();
40588
+ clearMessageList();
40589
+ resetUsers();
40590
+ cancelAllBurns();
40591
+ void clearInstance().catch((error) => console.error("[IM] 会话切换清理失败:", error));
40592
+ }, { detached: true, flush: "sync" });
40593
+ }
40248
40594
  return {
40249
40595
  messageStore,
40250
40596
  loginStatus,
@@ -40252,6 +40598,7 @@ const useMessage = (config = {}) => {
40252
40598
  initIMSDK,
40253
40599
  clearInstance,
40254
40600
  getUnReadMessageCount,
40601
+ publishUnreadCount,
40255
40602
  setConversationMsgAsRead,
40256
40603
  waitForSyncFinish
40257
40604
  };
@@ -40295,13 +40642,13 @@ const _sfc_main = {
40295
40642
  default: "1"
40296
40643
  }
40297
40644
  },
40298
- emits: ["send-chat-text", "invite-member"],
40645
+ emits: ["send-chat-text", "invite-member", "unread-change"],
40299
40646
  setup(__props, { expose: __expose, emit: __emit }) {
40300
40647
  const routes = [
40301
40648
  {
40302
40649
  path: "/messages",
40303
40650
  name: "Messages",
40304
- component: () => import("./indexH5-CUQe-Ize.js"),
40651
+ component: () => import("./indexH5-CCseQmQb.js"),
40305
40652
  meta: { title: "消息" }
40306
40653
  },
40307
40654
  // 根路径重定向到会话列表页
@@ -40312,61 +40659,61 @@ const _sfc_main = {
40312
40659
  {
40313
40660
  path: "/chat",
40314
40661
  name: "Chat",
40315
- component: () => import("./ChatPageH5-B3azJu7O.js"),
40662
+ component: () => import("./ChatPageH5-GUblGkKv.js"),
40316
40663
  meta: { title: "聊天" }
40317
40664
  },
40318
40665
  {
40319
40666
  path: "/search",
40320
40667
  name: "Search",
40321
- component: () => import("./SearchPageH5-hYxNItvz.js"),
40668
+ component: () => import("./SearchPageH5-CjBq_40x.js"),
40322
40669
  meta: { title: "搜索" }
40323
40670
  },
40324
40671
  {
40325
40672
  path: "/notice",
40326
40673
  name: "Notice",
40327
- component: () => import("./GroupNoticeH5-46ZjBe92.js"),
40674
+ component: () => import("./GroupNoticeH5-C6hNtZzy.js"),
40328
40675
  meta: { title: "群通知" }
40329
40676
  },
40330
40677
  {
40331
40678
  path: "/create-group",
40332
40679
  name: "CreateGroup",
40333
- component: () => import("./CreateGroupH5-a16jkObH.js"),
40680
+ component: () => import("./CreateGroupH5-CCtTCnLG.js"),
40334
40681
  meta: { title: "创建群组" }
40335
40682
  },
40336
40683
  {
40337
40684
  path: "/select-members",
40338
40685
  name: "SelectMembers",
40339
- component: () => import("./SelectMembersH5-DQIfX_w4.js"),
40686
+ component: () => import("./SelectMembersH5-BSLarLGK.js"),
40340
40687
  meta: { title: "成员选择" }
40341
40688
  },
40342
40689
  {
40343
40690
  path: "/member-detail",
40344
40691
  name: "MemberDetail",
40345
- component: () => import("./MemberDetailH5-B7nlr8ZT.js"),
40692
+ component: () => import("./MemberDetailH5-BZlExAgj.js"),
40346
40693
  meta: { title: "个人详情" }
40347
40694
  },
40348
40695
  {
40349
40696
  path: "/chat-settings",
40350
40697
  name: "ChatSettings",
40351
- component: () => import("./ChatSettingsH5-CFr9Bn69.js"),
40698
+ component: () => import("./ChatSettingsH5-wyQ01zjO.js"),
40352
40699
  meta: { title: "聊天设置" }
40353
40700
  },
40354
40701
  {
40355
40702
  path: "/group-announcement",
40356
40703
  name: "GroupAnnouncement",
40357
- component: () => import("./GroupAnnouncementH5-B-Qfzoy2.js"),
40704
+ component: () => import("./GroupAnnouncementH5-BYN-HzX0.js"),
40358
40705
  meta: { title: "群公告" }
40359
40706
  },
40360
40707
  {
40361
40708
  path: "/chat-history",
40362
40709
  name: "ChatHistory",
40363
- component: () => import("./ChatHistoryH5-BhrGF5WR.js"),
40710
+ component: () => import("./ChatHistoryH5-BeCSVzKZ.js"),
40364
40711
  meta: { title: "聊天记录" }
40365
40712
  },
40366
40713
  {
40367
40714
  path: "/group-members",
40368
40715
  name: "GroupMembers",
40369
- component: () => import("./GroupMembersH5-D_f1RFjO.js"),
40716
+ component: () => import("./GroupMembersH5-DUWs89a3.js"),
40370
40717
  meta: { title: "群成员" }
40371
40718
  }
40372
40719
  ];
@@ -40389,6 +40736,7 @@ const _sfc_main = {
40389
40736
  provide(routeLocationKey, routeLocation);
40390
40737
  const props = __props;
40391
40738
  const emits = __emit;
40739
+ const handleUnreadCountChanged = (payload) => emits("unread-change", payload);
40392
40740
  const onSendChatText = (payload) => emits("send-chat-text", payload);
40393
40741
  const onInviteMember = (memberIds) => emits("invite-member", memberIds);
40394
40742
  provide("h5RootConfig", {
@@ -40426,6 +40774,11 @@ const _sfc_main = {
40426
40774
  }
40427
40775
  chatMessage.setUserInfo({
40428
40776
  userID: obj.loginCode || props.baseConfig.loginCode,
40777
+ imIdentityVersion: obj.imIdentityVersion || 1,
40778
+ imUserID: obj.imUserID || "",
40779
+ tenantID: obj.tenantID || "",
40780
+ businessUserID: obj.businessUserID || "",
40781
+ loginCode: obj.loginCode || "",
40429
40782
  nickname: obj.userName || props.baseConfig.userName,
40430
40783
  apiUrl: obj.apiUrl || props.baseConfig.apiUrl,
40431
40784
  wsUrl: ((_a = obj.apiUrl) == null ? void 0 : _a.replace(/^http/, "ws")) || ((_b = props.baseConfig.apiUrl) == null ? void 0 : _b.replace(/^http/, "ws")),
@@ -40437,11 +40790,13 @@ const _sfc_main = {
40437
40790
  checkLogin();
40438
40791
  };
40439
40792
  onMounted(() => {
40793
+ mittBus.on("IM_UNREAD_COUNT_CHANGED", handleUnreadCountChanged);
40440
40794
  if (chatMessage.getLoginStatus === IM_LOGIN_STATUS.Logged && window["imInstance"]) {
40441
40795
  router.replace("/messages");
40442
40796
  }
40443
40797
  });
40444
40798
  onBeforeUnmount(() => {
40799
+ mittBus.off("IM_UNREAD_COUNT_CHANGED", handleUnreadCountChanged);
40445
40800
  if (_loginTimer) {
40446
40801
  clearTimeout(_loginTimer);
40447
40802
  _loginTimer = null;
@@ -40460,33 +40815,36 @@ const _sfc_main = {
40460
40815
  }
40461
40816
  };
40462
40817
  export {
40463
- useBurnAfterReading as A,
40464
- dedupeMessages as B,
40465
- getDefaultExportFromCjs as C,
40466
- getMediaDuration as D,
40467
- getReplyDetail as E,
40468
- IM_FONT_FAMILY as F,
40469
- IM_FONT_SIZE as G,
40470
- IM_FONT_STYLE as H,
40818
+ requestInstance as $,
40819
+ isNoticeAgentUser as A,
40820
+ useBurnAfterReading as B,
40821
+ dedupeMessages as C,
40822
+ getDefaultExportFromCjs as D,
40823
+ getMediaDuration as E,
40824
+ getReplyDetail as F,
40825
+ IM_FONT_FAMILY as G,
40826
+ IM_FONT_SIZE as H,
40471
40827
  IM_CVS_TYPE as I,
40472
- IM_GROUP_STATUS as J,
40473
- uuidv4 as K,
40474
- debounce as L,
40475
- handleDateUtil as M,
40476
- GROUP_JOIN_SOURCE as N,
40477
- IM_GROUP_MEMBER_ROLE as O,
40478
- GROUP_VERIFICATION_TYPE as P,
40479
- IM_GROUP_TYPE as Q,
40480
- BURN_DEFAULT as R,
40481
- BURN_PRESETS as S,
40482
- formatBurnDuration as T,
40483
- copyToClipboard as U,
40484
- clampBurnDuration as V,
40485
- buildBurnEx as W,
40486
- downloadFileByBlob as X,
40487
- EXIT_CODE as Y,
40488
- _sfc_main as _,
40828
+ IM_FONT_STYLE as J,
40829
+ IM_GROUP_STATUS as K,
40830
+ uuidv4 as L,
40831
+ debounce as M,
40832
+ handleDateUtil as N,
40833
+ GROUP_JOIN_SOURCE as O,
40834
+ IM_GROUP_MEMBER_ROLE as P,
40835
+ GROUP_VERIFICATION_TYPE as Q,
40836
+ IM_GROUP_TYPE as R,
40837
+ BURN_DEFAULT as S,
40838
+ BURN_PRESETS as T,
40839
+ formatBurnDuration as U,
40840
+ copyToClipboard as V,
40841
+ clampBurnDuration as W,
40842
+ buildBurnEx as X,
40843
+ downloadFileByBlob as Y,
40844
+ imSessionScope as Z,
40845
+ IMSessionChangedError as _,
40489
40846
  getAvatarBg as a,
40847
+ _sfc_main as a0,
40490
40848
  getAvatarText as b,
40491
40849
  cloneDeep as c,
40492
40850
  getConversationBurnSetting as d,