mdm-im-v3 2.1.2 → 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 (26) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/README.md +50 -1
  3. package/dist/{FilePreview-Cz0KMA_m.js → FilePreview-CJdqlDs0.js} +2 -2
  4. package/dist/core.es.js +2 -2
  5. package/dist/{index-P9_HILzo.js → index-BLdSVjT-.js} +133 -63
  6. package/dist/{index-C8koozDu.js → index-CrMTFmHU.js} +2 -2
  7. package/dist/{index-GiaKeCU7.js → index-VIcWin6Y.js} +25 -11
  8. package/dist/index.es.js +1 -1
  9. package/dist/style/index.css +1 -1
  10. package/dist-h5/{ChatHistoryH5-CKDqKPl-.js → ChatHistoryH5-BeCSVzKZ.js} +2 -2
  11. package/dist-h5/{ChatPageH5-FXZxtcQr.js → ChatPageH5-GUblGkKv.js} +12 -7
  12. package/dist-h5/{ChatSettingsH5-PackrlPt.js → ChatSettingsH5-wyQ01zjO.js} +3 -2
  13. package/dist-h5/{CreateGroupH5-CO_ZH36_.js → CreateGroupH5-CCtTCnLG.js} +2 -2
  14. package/dist-h5/{GroupAnnouncementH5-yUDR5kYW.js → GroupAnnouncementH5-BYN-HzX0.js} +1 -1
  15. package/dist-h5/{GroupInfoDialogH5-BRk-_mEn.js → GroupInfoDialogH5-DDjYHm7i.js} +1 -1
  16. package/dist-h5/{GroupMembersH5-BVHUF2mG.js → GroupMembersH5-DUWs89a3.js} +1 -1
  17. package/dist-h5/{GroupNoticeH5-KA-L2h9r.js → GroupNoticeH5-C6hNtZzy.js} +1 -1
  18. package/dist-h5/{MemberDetailH5-BfAE0nx-.js → MemberDetailH5-BZlExAgj.js} +16 -3
  19. package/dist-h5/{SearchPageH5-B6B_U4hW.js → SearchPageH5-CjBq_40x.js} +2 -2
  20. package/dist-h5/{SelectMembersH5-CrPoBnYp.js → SelectMembersH5-BSLarLGK.js} +2 -2
  21. package/dist-h5/{imChat-pGlpr8Vj.js → imChat-CdmqPGQ6.js} +1 -1
  22. package/dist-h5/index.es.js +2 -2
  23. package/dist-h5/{indexH5-sKvS7t3k.js → indexH5-CCseQmQb.js} +4 -3
  24. package/dist-h5/{indexH5-CCvF1MV7.js → indexH5-DikfbMIK.js} +126 -53
  25. package/dist-h5/style/index-h5.css +1 -1
  26. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -104,3 +104,10 @@
104
104
  ## V2.1.2 2026-11-03
105
105
  - 发布mdm-im-v3@2.1.2版本
106
106
  1. 2.1.1版本作废。
107
+
108
+ ## V2.1.3 2026-11-04
109
+ - 发布mdm-im-v3@2.1.3版本
110
+ 1. 新增 `unread-change` 事件(PC/H5 均支持):IM 初始化加载完成、收到新消息及未读总数变化时向宿主抛出,参数 `{ count, reason, time, conversationID? }`;组件未渲染时宿主可通过 `useMessage().mittBus` 监听未读变化,登录同步完成后自动上报 SDK 未读总数;
111
+ 2. 修复宿主未渲染 IM 页面时未读角标「先显示后消失」的问题:会话列表未加载完成时不再用残缺列表汇总覆盖 SDK 未读总数,SDK 未读总数获取失败时也不再用 0 清零;
112
+ 3. 增加未读数量计算/写入/广播日志(前缀 `[IM][unread]`),便于排查角标跳变;
113
+ 4. 后台通知会话(对方 userID 以 `agent_` 开头):点击通知机器人头像不再打开个人详情、不调用用户详情接口;消息转发弹窗(PC/H5)过滤通知类型会话,禁止转发给通知机器人。
package/README.md CHANGED
@@ -113,6 +113,8 @@ const handleLogin = () => {
113
113
 
114
114
  适用于**先登录 IM 获取未读数 → 再切换到 IM 页面展示内容**的场景:
115
115
 
116
+ > 完整说明与可运行示例见 [获取即时消息组件mdm-im-v3的未读消息数量的调用方式.md](获取即时消息组件mdm-im-v3的未读消息数量的调用方式.md)。
117
+
116
118
  1. 入口处调用 `useMessage(config)` 初始化 IM,获取未读数量
117
119
  2. 用户切换到 IM 菜单时再渲染 `<mdm-im-v3>` 组件
118
120
  3. 组件自动读取 store 中的已登录状态和 `window.imInstance`,无需重复初始化
@@ -342,6 +344,8 @@ h5Ref.value.autoLogin({
342
344
  h5Ref.value.checkLogin()
343
345
  ```
344
346
 
347
+ H5 组件同样支持 `unread-change` 事件(参数与 PC 端一致,见 [组件 Events](#组件-events)),宿主可通过 `@unread-change` 监听未读消息数变化。
348
+
345
349
  ### H5 端与 PC 端差异
346
350
 
347
351
  | 维度 | PC | H5 |
@@ -386,10 +390,53 @@ h5Ref.value.checkLogin()
386
390
 
387
391
  ## 组件 Events
388
392
 
393
+ PC 与 H5 组件支持相同的事件:
394
+
389
395
  | 事件名 | 参数 | 说明 |
390
396
  |--------|------|------|
391
397
  | `send-chat-text` | `{ list, isReply, atUserList }` | `onKeywordCheck` 为 `true` 时,文本发送前触发,用于外部敏感词过滤。过滤后调用 `chatRef.sendCheckedText()` 发送 |
392
398
  | `invite-member` | `memberIds: string[]` | `outsideHandleUser` 为 `true` 时,需要邀请成员时触发,由外部处理人员选择 |
399
+ | `unread-change` | `{ count, reason, time, conversationID? }` | IM 未读消息总数变化时触发,可用于同步宿主的消息红点/角标,见下方说明 |
400
+
401
+ ### `unread-change`(未读消息数)
402
+
403
+ 组件在以下时机向上抛出该事件:
404
+
405
+ | `reason` | 触发时机 |
406
+ |----------|----------|
407
+ | `'init'` | IM 初始化加载完成(登录后会话列表拉取/缓存渲染结束),每次初始化触发一次 |
408
+ | `'receive'` | 收到新消息(SDK 每批推送触发一次,即使未读总数没变) |
409
+ | `'update'` | 未读总数发生变化,如标记已读、其他端已读、新会话等 |
410
+
411
+ 事件载荷:
412
+
413
+ ```ts
414
+ {
415
+ count: number // 当前未读消息总数
416
+ reason: 'init' | 'receive' | 'update'
417
+ time: number // 触发时间戳(毫秒)
418
+ conversationID?: string // 仅 reason='receive':最新消息所属会话 ID
419
+ }
420
+ ```
421
+
422
+ PC / H5 用法一致:
423
+
424
+ ```vue
425
+ <template>
426
+ <mdm-im-v3 ref="chatRef" @unread-change="handleUnreadChange" />
427
+ <!-- H5:<mdm-im-v3-h5 ref="chatRef" @unread-change="handleUnreadChange" /> -->
428
+ </template>
429
+
430
+ <script setup>
431
+ const handleUnreadChange = ({ count, reason, conversationID }) => {
432
+ // 同步宿主菜单/标签页的红点数量
433
+ badgeRef.value = count
434
+ console.log('[IM] 未读数:', count, reason, conversationID)
435
+ }
436
+ </script>
437
+ ```
438
+
439
+ > 未读总数同时保存在 store 的 `unReadCount` 中,可通过 `useChatStore().getUnReadCount` 读取;`unread-change` 事件适用于不便订阅 store 的宿主(如非 Vue 渲染的菜单/角标)。
393
440
 
394
441
  ## 组件暴露的方法
395
442
 
@@ -486,7 +533,8 @@ const { initIMSDK, clearInstance, getUnReadMessageCount, setConversationMsgAsRea
486
533
  | `loginStatus` | IM 登录状态的 `computed` 引用,便于外部 `watch` 监控。值:1-未登录,2-登录中,3-已登录 |
487
534
  | `initIMSDK()` | 初始化 SDK → 绑定所有 OpenIM 事件 → 登录。需先在 store 中设置 userID、imToken、apiUrl 等。返回 `Promise<void>`。 |
488
535
  | `clearInstance(bool)` | 解绑事件 → 登出 → 清除 SDK 实例。传入 `true` 时同时清空会话列表和 `window.imInstance`。 |
489
- | `getUnReadMessageCount(fromServer?)` | 获取未读消息总数。`fromServer=true` 从服务端获取,默认从本地会话列表累计。 |
536
+ | `getUnReadMessageCount(fromServer?)` | 获取未读消息总数。`fromServer=true` 从服务端获取,默认从本地会话列表累计。总数变化时会广播 `IM_UNREAD_COUNT_CHANGED`(组件转发为 `unread-change` 事件)。 |
537
+ | `publishUnreadCount(reason?, extra?)` | 主动向宿主广播一次未读总数,通过 `IM_UNREAD_COUNT_CHANGED` 发给组件并转发为 `unread-change` 事件。`reason` 默认 `'update'`,组件初始化完成时内部使用 `'init'`。 |
490
538
  | `waitForSyncFinish(timeout?)` | 等待登录后的服务端同步(`OnSyncServerFinish`)完成,返回 `Promise<boolean>`。同步完成前 SDK 本地会话缓存为空,此时拉取会话列表只会得到空数组,因此拉取会话列表前应先等待该方法;默认超时 8000ms,超时返回 `false`,按兜底流程继续。 |
491
539
  | `setConversationMsgAsRead(conversationID?)` | 将指定会话的消息标记为已读,不传则使用当前会话。窗口失焦时自动跳过。 |
492
540
  | `mittBus` | 全局事件总线实例,用于监听 IM 自定义事件(见下方事件列表) |
@@ -550,6 +598,7 @@ const chatStore = useChatStore()
550
598
  | `LOGOUT_NOTICE` | 账号在其他设备登录,被强制下线 |
551
599
  | `IM_LOGOUT` | IM 已登出 |
552
600
  | `IM_SYNC_SERVER_FINISH` | 登录后的服务端同步结束(参数 `true`-成功,`false`-失败)。此时会话/消息缓存才就绪,可用于登录后补拉会话列表 |
601
+ | `IM_UNREAD_COUNT_CHANGED` | 未读消息总数变化,参数 `{ count, reason, time, conversationID? }`。组件内部据此转发 `unread-change` 事件,一般无需直接监听 |
553
602
  | `OnGroupInfoChanged` | 群信息变更(名称、头像、公告等) |
554
603
  | `OnJoinedGroupAdded` | 被拉入新群 |
555
604
  | `OnJoinedGroupDeleted` | 退出或被踢出群 |
@@ -1,8 +1,8 @@
1
1
  import { reactive, computed, ref, watch, nextTick, resolveComponent, openBlock, createElementBlock, Fragment, createVNode, withCtx, unref, createElementVNode, withModifiers, toDisplayString, createCommentVNode, normalizeStyle, createBlock, resolveDynamicComponent } from "vue";
2
2
  import { DocumentDelete, ZoomOut, ZoomIn } from "@element-plus/icons-vue";
3
- import { u as useChatStore } from "./index-P9_HILzo.js";
3
+ import { u as useChatStore } from "./index-BLdSVjT-.js";
4
4
  import axios from "axios";
5
- import { _ as _export_sfc } from "./index-GiaKeCU7.js";
5
+ import { _ as _export_sfc } from "./index-VIcWin6Y.js";
6
6
  const _hoisted_1 = { class: "file-preview-box" };
7
7
  const _hoisted_2 = {
8
8
  key: 0,
package/dist/core.es.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import "vue";
2
- import { u, S } from "./index-P9_HILzo.js";
2
+ import { u, T } from "./index-BLdSVjT-.js";
3
3
  export {
4
4
  u as useChatStore,
5
- S as useMessage
5
+ T as useMessage
6
6
  };
@@ -9966,7 +9966,10 @@ const useChatStore = defineStore("chatMessage", {
9966
9966
  },
9967
9967
  // 更新未读总数
9968
9968
  setUnReadCount(count = 0) {
9969
- this.unReadCount = count;
9969
+ const next = Number(count) || 0;
9970
+ if (this.unReadCount === next) return;
9971
+ console.log("[IM][unread] store 未读总数更新", { from: this.unReadCount, to: next });
9972
+ this.unReadCount = next;
9970
9973
  },
9971
9974
  // 更新用户的登录状态
9972
9975
  setLoginStatus(val) {
@@ -10819,20 +10822,20 @@ class ImKit extends EventEmitter {
10819
10822
  }
10820
10823
  /**
10821
10824
  * 获取所有会话的未读消息总数
10822
- * @returns {Number}
10825
+ * @returns {Number|null} 未读总数;获取失败返回 null(调用方不应把 null 当成 0 覆盖本地值)
10823
10826
  */
10824
10827
  async getTotalUnreadMsgCount(operationID = uuidv4()) {
10825
10828
  var _a;
10826
10829
  if (!this.IMSDK) {
10827
- return 0;
10830
+ return null;
10828
10831
  }
10829
10832
  try {
10830
10833
  const res = await ((_a = this.IMSDK) == null ? void 0 : _a.getTotalUnreadMsgCount(operationID));
10831
- return (res == null ? void 0 : res.data) || 0;
10834
+ return Number(res == null ? void 0 : res.data) || 0;
10832
10835
  } catch (error) {
10833
- console.error("获取未读消息总数失败:", error);
10836
+ console.error("[IM][unread] 获取未读消息总数失败:", error);
10834
10837
  this.handleError(error);
10835
- return 0;
10838
+ return null;
10836
10839
  }
10837
10840
  }
10838
10841
  /**
@@ -36428,6 +36431,11 @@ const conversationList = ref([]);
36428
36431
  const skipSortIds = /* @__PURE__ */ new Set();
36429
36432
  const currentConversation = ref({});
36430
36433
  const currentConversationUsers = ref([]);
36434
+ let conversationListReady = false;
36435
+ const setConversationListReady = (value) => {
36436
+ conversationListReady = Boolean(value);
36437
+ };
36438
+ const isConversationListReady = () => conversationListReady;
36431
36439
  const useConversations = () => {
36432
36440
  const chatMessage = useChatStore();
36433
36441
  const baseUrl = chatMessage.getBaseUrl;
@@ -36556,8 +36564,12 @@ const useConversations = () => {
36556
36564
  currentConversation.value = curCvs;
36557
36565
  }
36558
36566
  const unreadCount = getUnReadMessageCount();
36559
- if (chatMessage.setUnReadCount) {
36560
- chatMessage.setUnReadCount(unreadCount);
36567
+ if (conversationListReady) {
36568
+ if (chatMessage.setUnReadCount) {
36569
+ chatMessage.setUnReadCount(unreadCount);
36570
+ }
36571
+ } else {
36572
+ console.log("[IM][unread] 会话列表未加载完成,跳过列表汇总覆盖", { listCount: unreadCount });
36561
36573
  }
36562
36574
  };
36563
36575
  const getCurrentConversation = (id) => {
@@ -36617,6 +36629,7 @@ const useConversations = () => {
36617
36629
  };
36618
36630
  const clearConversationList = () => {
36619
36631
  skipSortIds.clear();
36632
+ conversationListReady = false;
36620
36633
  currentConversationUsers.value = [];
36621
36634
  conversationList.value = [];
36622
36635
  currentConversation.value = {};
@@ -36632,7 +36645,9 @@ const useConversations = () => {
36632
36645
  getConversationIDBySessionType,
36633
36646
  getConversationByKey,
36634
36647
  markSkipNextSort,
36635
- clearConversationList
36648
+ clearConversationList,
36649
+ setConversationListReady,
36650
+ isConversationListReady
36636
36651
  };
36637
36652
  };
36638
36653
  const ga1 = "data:image/png;base64,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";
@@ -37020,9 +37035,10 @@ const getSelectionText = () => {
37020
37035
  return "";
37021
37036
  };
37022
37037
  const NOTICE_AGENT_PREFIX = "agent_";
37038
+ const isNoticeAgentUser = (userID) => String(userID || "").startsWith(NOTICE_AGENT_PREFIX);
37023
37039
  const isNoticeAgentConversation = (cvs) => {
37024
37040
  if (!cvs || cvs.conversationType !== IM_CVS_TYPE.Single) return false;
37025
- return String(cvs.userID || "").startsWith(NOTICE_AGENT_PREFIX);
37041
+ return isNoticeAgentUser(cvs.userID);
37026
37042
  };
37027
37043
  const createCvsId = (msg) => {
37028
37044
  if (msg.sessionType === IM_CVS_TYPE.Single) {
@@ -39852,6 +39868,7 @@ let syncFinished = false;
39852
39868
  let syncWaiters = [];
39853
39869
  let conversationBusBound = false;
39854
39870
  let burnHandlerBound = false;
39871
+ let lastUnreadCount = null;
39855
39872
  const resolveSyncWaiters = (ok) => {
39856
39873
  syncFinished = true;
39857
39874
  const waiters = syncWaiters.splice(0);
@@ -39959,7 +39976,9 @@ const useMessage = (config = {}) => {
39959
39976
  updateConversationLatestMessage,
39960
39977
  getConversationIDBySessionType,
39961
39978
  getConversationByKey,
39962
- clearConversationList
39979
+ clearConversationList,
39980
+ setConversationListReady: setConversationListReady2,
39981
+ isConversationListReady: isConversationListReady2
39963
39982
  } = useConversations();
39964
39983
  const {
39965
39984
  messageList: messageList2,
@@ -40019,23 +40038,64 @@ const useMessage = (config = {}) => {
40019
40038
  if (((_a = currentConversation2.value) == null ? void 0 : _a.conversationID) === data.conversationID) {
40020
40039
  currentConversation2.value = { ...currentConversation2.value, ...data };
40021
40040
  }
40041
+ refreshUnreadCount();
40022
40042
  });
40023
40043
  }
40024
- const getUnReadMessageCount = async (bool = false) => {
40044
+ const publishUnreadCount = (reason = "update", extra = {}) => {
40045
+ if (reason === "init") {
40046
+ setConversationListReady2(true);
40047
+ if (conversationList2.value.length > 0) {
40048
+ const listCount = conversationList2.value.reduce(
40049
+ (pre, cur) => pre + (cur.unreadCount > 0 ? cur.unreadCount : 0),
40050
+ 0
40051
+ );
40052
+ messageStore.setUnReadCount(listCount);
40053
+ }
40054
+ }
40055
+ const count = Number(messageStore.getUnReadCount) || 0;
40056
+ lastUnreadCount = count;
40057
+ const payload = { count, reason, time: Date.now(), ...extra };
40058
+ console.log("[IM][unread] 广播未读消息事件", payload);
40059
+ mittBus.emit("IM_UNREAD_COUNT_CHANGED", payload);
40060
+ };
40061
+ const publishUnreadIfChanged = (reason = "update") => {
40062
+ if ((Number(messageStore.getUnReadCount) || 0) === lastUnreadCount) return;
40063
+ publishUnreadCount(reason);
40064
+ };
40065
+ const refreshUnreadCount = () => {
40066
+ if (isConversationListReady2()) {
40067
+ publishUnreadIfChanged("update");
40068
+ } else {
40069
+ getUnReadMessageCount(true);
40070
+ }
40071
+ };
40072
+ const getUnReadMessageCount = async (bool = false, reason = "update", extra = {}) => {
40025
40073
  if (bool) {
40026
40074
  if (!imInstance) return;
40027
40075
  const countScope = imSessionScope(messageStore);
40028
40076
  const countRevision = sessionRevision;
40029
40077
  const count = await (imInstance == null ? void 0 : imInstance.getTotalUnreadMsgCount());
40030
40078
  if (countRevision !== sessionRevision || countScope !== imSessionScope(messageStore)) return;
40079
+ if (count == null) {
40080
+ console.warn("[IM][unread] SDK 未读总数获取失败,保留当前未读数", {
40081
+ current: messageStore.getUnReadCount
40082
+ });
40083
+ return;
40084
+ }
40085
+ console.log("[IM][unread] 重新计算未读总数", { source: "sdk", count: count || 0, reason });
40031
40086
  messageStore.setUnReadCount(count || 0);
40032
40087
  } else {
40033
40088
  const count = conversationList2.value.reduce((pre, cur) => {
40034
40089
  return pre + (cur.unreadCount > 0 ? cur.unreadCount : 0);
40035
40090
  }, 0);
40036
- console.log("全部未读消息1:", count);
40091
+ console.log("[IM][unread] 重新计算未读总数", { source: "conversationList", count, reason });
40037
40092
  messageStore.setUnReadCount(count || 0);
40038
40093
  }
40094
+ if (reason === "receive") {
40095
+ publishUnreadCount(reason, extra);
40096
+ } else {
40097
+ publishUnreadIfChanged(reason);
40098
+ }
40039
40099
  };
40040
40100
  const setConversationMsgAsRead = async (id) => {
40041
40101
  var _a;
@@ -40082,6 +40142,7 @@ const useMessage = (config = {}) => {
40082
40142
  if (imInstance === previous) imInstance = null;
40083
40143
  if (typeof window !== "undefined" && window.imInstance === previous) window.imInstance = null;
40084
40144
  resetSyncState();
40145
+ lastUnreadCount = null;
40085
40146
  if (clearData) {
40086
40147
  clearConversationList();
40087
40148
  clearMessageList();
@@ -40381,6 +40442,7 @@ const useMessage = (config = {}) => {
40381
40442
  return curMsgList;
40382
40443
  };
40383
40444
  onSessionEvent(CbEvents.OnRecvNewMessages, async (list) => {
40445
+ var _a;
40384
40446
  console.log("批量接收消息:", list);
40385
40447
  if ((list == null ? void 0 : list.length) > 0) {
40386
40448
  await resolveConversationIDs(list);
@@ -40395,6 +40457,9 @@ const useMessage = (config = {}) => {
40395
40457
  const latestMsg = curMsgList[curMsgList.length - 1];
40396
40458
  updateConversationLatestMessage(cvs.conversationID, latestMsg, handleMessage(latestMsg));
40397
40459
  }
40460
+ if (!isActive()) return;
40461
+ const cvsId = ((_a = list[list.length - 1]) == null ? void 0 : _a.conversationID) || "";
40462
+ await getUnReadMessageCount(!isConversationListReady2(), "receive", { conversationID: cvsId });
40398
40463
  }
40399
40464
  });
40400
40465
  onSessionEvent(CbEvents.OnRecvC2CReadReceipt, async (list) => {
@@ -40423,7 +40488,7 @@ const useMessage = (config = {}) => {
40423
40488
  if (val === IM_LOGIN_STATUS.Logged) {
40424
40489
  initTimer = setTimeout(() => {
40425
40490
  if (!isActive()) return;
40426
- getUnReadMessageCount();
40491
+ getUnReadMessageCount(true);
40427
40492
  }, 1e3);
40428
40493
  } else if (val === IM_LOGIN_STATUS.Logout) {
40429
40494
  mittBus.emit("IM_LOGOUT");
@@ -40437,6 +40502,7 @@ const useMessage = (config = {}) => {
40437
40502
  console.log("IM 服务端同步完成");
40438
40503
  resolveSyncWaiters(true);
40439
40504
  mittBus.emit("IM_SYNC_SERVER_FINISH", true);
40505
+ getUnReadMessageCount(true);
40440
40506
  });
40441
40507
  onSessionEvent(CbEvents.OnSyncServerFailed, (data) => {
40442
40508
  console.warn("IM 服务端同步失败:", data);
@@ -40453,6 +40519,7 @@ const useMessage = (config = {}) => {
40453
40519
  if (Array.isArray(data) && (data == null ? void 0 : data.length)) {
40454
40520
  console.log("会话状态改变:", data);
40455
40521
  handleConversationList(data, "update", handleMessage);
40522
+ refreshUnreadCount();
40456
40523
  }
40457
40524
  });
40458
40525
  onSessionEvent(CbEvents.OnNewConversation, async (data) => {
@@ -40477,6 +40544,7 @@ const useMessage = (config = {}) => {
40477
40544
  } else if (newList.length > 0) {
40478
40545
  handleConversationList(newList, "add", handleMessage);
40479
40546
  }
40547
+ refreshUnreadCount();
40480
40548
  mittBus.emit("OnNewConversationCreated", data);
40481
40549
  }
40482
40550
  });
@@ -40581,70 +40649,72 @@ const useMessage = (config = {}) => {
40581
40649
  initIMSDK,
40582
40650
  clearInstance,
40583
40651
  getUnReadMessageCount,
40652
+ publishUnreadCount,
40584
40653
  setConversationMsgAsRead,
40585
40654
  waitForSyncFinish
40586
40655
  };
40587
40656
  };
40588
40657
  export {
40589
- uuidv4 as $,
40590
- getReplyDetail as A,
40658
+ sleep as $,
40659
+ formatSeconds as A,
40591
40660
  BURN_DEFAULT as B,
40592
- useMsgList as C,
40593
- throttle as D,
40594
- isBurnMessage as E,
40595
- formatBurnRemain as F,
40596
- isBurned as G,
40597
- smoothScrollTo as H,
40661
+ getReplyDetail as C,
40662
+ useMsgList as D,
40663
+ throttle as E,
40664
+ isBurnMessage as F,
40665
+ formatBurnRemain as G,
40666
+ isBurned as H,
40598
40667
  IMSessionChangedError as I,
40599
- getJsonDetail as J,
40600
- getSelectionText as K,
40601
- useBurnAfterReading as L,
40602
- createCvsId as M,
40603
- dedupeMessages as N,
40604
- handleUrl as O,
40605
- handleDate as P,
40606
- GROUP_JOIN_SOURCE as Q,
40607
- GROUP_APPLICATION_STATUS as R,
40608
- useMessage as S,
40609
- useUsers as T,
40610
- useConversations as U,
40611
- useMessageCache as V,
40612
- mittBus as W,
40613
- IM_LOGIN_STATUS as X,
40614
- preserveBurnInEx as Y,
40615
- buildBurnEx as Z,
40616
- sleep as _,
40668
+ smoothScrollTo as J,
40669
+ getJsonDetail as K,
40670
+ getSelectionText as L,
40671
+ useBurnAfterReading as M,
40672
+ createCvsId as N,
40673
+ dedupeMessages as O,
40674
+ handleUrl as P,
40675
+ handleDate as Q,
40676
+ GROUP_JOIN_SOURCE as R,
40677
+ GROUP_APPLICATION_STATUS as S,
40678
+ useMessage as T,
40679
+ useUsers as U,
40680
+ useConversations as V,
40681
+ useMessageCache as W,
40682
+ mittBus as X,
40683
+ IM_LOGIN_STATUS as Y,
40684
+ preserveBurnInEx as Z,
40685
+ buildBurnEx as _,
40617
40686
  IM_CVS_TYPE as a,
40618
- GROUP_VERIFICATION_TYPE as a0,
40619
- getDefaultExportFromCjs as a1,
40620
- getMediaDuration as a2,
40621
- IM_FONT_SIZE as a3,
40622
- IM_FONT_FAMILY as a4,
40623
- IM_FONT_STYLE as a5,
40624
- formatFileSize as a6,
40687
+ uuidv4 as a0,
40688
+ GROUP_VERIFICATION_TYPE as a1,
40689
+ getDefaultExportFromCjs as a2,
40690
+ getMediaDuration as a3,
40691
+ IM_FONT_SIZE as a4,
40692
+ IM_FONT_FAMILY as a5,
40693
+ IM_FONT_STYLE as a6,
40694
+ formatFileSize as a7,
40625
40695
  isDefaultAvatar as b,
40626
40696
  getAvatarBg as c,
40627
40697
  getAvatarText as d,
40628
40698
  cloneDeep as e,
40629
40699
  getConversationBurnSetting as f,
40630
40700
  getGroupAvatarBg as g,
40631
- useDate as h,
40701
+ isNoticeAgentUser as h,
40632
40702
  imSessionScope as i,
40633
- isNoticeAgentConversation as j,
40634
- IM_GROUP_MEMBER_ROLE as k,
40635
- IM_MSG_TYPE as l,
40636
- debounce as m,
40637
- IM_GROUP_STATUS as n,
40638
- IM_LOGIN_PLATFORM as o,
40639
- BURN_PRESETS as p,
40640
- formatBurnDuration as q,
40703
+ useDate as j,
40704
+ isNoticeAgentConversation as k,
40705
+ IM_GROUP_MEMBER_ROLE as l,
40706
+ IM_MSG_TYPE as m,
40707
+ debounce as n,
40708
+ IM_GROUP_STATUS as o,
40709
+ IM_LOGIN_PLATFORM as p,
40710
+ BURN_PRESETS as q,
40641
40711
  requestInstance as r,
40642
- BURN_MAX as s,
40643
- BURN_MIN as t,
40712
+ formatBurnDuration as s,
40713
+ BURN_MAX as t,
40644
40714
  useChatStore as u,
40645
- handleLinks as v,
40646
- clampBurnDuration as w,
40647
- copyToClipboard as x,
40648
- downloadFileByBlob as y,
40649
- formatSeconds as z
40715
+ BURN_MIN as v,
40716
+ handleLinks as w,
40717
+ clampBurnDuration as x,
40718
+ copyToClipboard as y,
40719
+ downloadFileByBlob as z
40650
40720
  };
@@ -1,9 +1,9 @@
1
1
  import { computed, reactive, ref, onBeforeMount, watch, resolveComponent, openBlock, createElementBlock, Fragment, renderList, unref, createBlock, withCtx, createElementVNode, createVNode, createSlots, toDisplayString, withModifiers, createCommentVNode, onBeforeUnmount, inject, normalizeClass, createTextVNode, shallowRef, renderSlot, normalizeStyle, Teleport, nextTick } from "vue";
2
- import { _ as _export_sfc, u as uploadFiles, a as useAudioPlayer, b as _imports_0 } from "./index-GiaKeCU7.js";
2
+ import { _ as _export_sfc, u as uploadFiles, a as useAudioPlayer, b as _imports_0 } from "./index-VIcWin6Y.js";
3
3
  import { ElMessage } from "element-plus";
4
4
  import { Promotion } from "@element-plus/icons-vue";
5
5
  import { E as Editor } from "./wangeditor-3yO_BGRp.js";
6
- import { u as useChatStore, a1 as getDefaultExportFromCjs, a2 as getMediaDuration, a as IM_CVS_TYPE, D as throttle, m as debounce, a3 as IM_FONT_SIZE, a4 as IM_FONT_FAMILY, a5 as IM_FONT_STYLE, a6 as formatFileSize } from "./index-P9_HILzo.js";
6
+ import { u as useChatStore, a2 as getDefaultExportFromCjs, a3 as getMediaDuration, a as IM_CVS_TYPE, E as throttle, n as debounce, a4 as IM_FONT_SIZE, a5 as IM_FONT_FAMILY, a6 as IM_FONT_STYLE, a7 as formatFileSize } from "./index-BLdSVjT-.js";
7
7
  const icons = [
8
8
  {
9
9
  title: "表情",