jssz-meeting-component 1.1.42 → 1.2.0

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.
package/dist/index.esm.js CHANGED
@@ -20374,6 +20374,31 @@ function normalizeRoleCodes(value) {
20374
20374
  }
20375
20375
  return text.split(",").map((item) => item.trim()).filter(Boolean);
20376
20376
  }
20377
+ function normalizeBrokerUrl(baseUrl) {
20378
+ const trimmed = toText(baseUrl).trim();
20379
+ if (!trimmed) {
20380
+ throw new Error("MQTT 初始化失败:mqttUrl 为空");
20381
+ }
20382
+ const normalizedScheme = trimmed.startsWith("tcp://") ? `mqtt://${trimmed.slice("tcp://".length)}` : trimmed;
20383
+ console.log("normalizedScheme:", normalizedScheme);
20384
+ const withoutTrailingSlash = normalizedScheme.replace(/\/+$/g, "");
20385
+ if (withoutTrailingSlash.endsWith(DEFAULT_MQTT_PATH)) {
20386
+ return withoutTrailingSlash;
20387
+ }
20388
+ return `${withoutTrailingSlash}${DEFAULT_MQTT_PATH}`;
20389
+ }
20390
+ async function getMeetingWsMqttUrl() {
20391
+ const response = await getMqttConfig();
20392
+ if (response.code !== 200 || !response.data) {
20393
+ throw new Error(response.message || "获取 MQTT 配置失败");
20394
+ }
20395
+ const data = response.data;
20396
+ const wsMqttUrl = toText(data.wsMqttUrl).trim();
20397
+ if (wsMqttUrl) {
20398
+ return wsMqttUrl;
20399
+ }
20400
+ throw new Error("获取 MQTT 配置失败:wsMqttUrl 为空");
20401
+ }
20377
20402
  function buildRequestId() {
20378
20403
  return `mqtt-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
20379
20404
  }
@@ -20420,13 +20445,6 @@ function buildClientId(currentDevice) {
20420
20445
  const devicePart = safeDeviceId.slice(0, maxDeviceLength) || "meeting";
20421
20446
  return `${devicePart}_${safeInstanceId}`;
20422
20447
  }
20423
- function buildDefaultBrokerUrl() {
20424
- if (typeof window === "undefined") {
20425
- return DEFAULT_MQTT_PATH;
20426
- }
20427
- const wsProtocol = window.location.protocol === "https:" ? "wss:" : "ws:";
20428
- return `${wsProtocol}//${window.location.host}${DEFAULT_MQTT_PATH}`;
20429
- }
20430
20448
  function clearPendingRequests(reason) {
20431
20449
  pendingRequests.forEach((request) => {
20432
20450
  clearTimeout(request.timeoutId);
@@ -20489,7 +20507,9 @@ async function initializeMeetingMQTT(options = {}) {
20489
20507
  const myInfo = options.myInfo || await readMyInfo();
20490
20508
  const loginDevice = toText(myInfo.currentDevice).trim();
20491
20509
  const roleCodes = normalizeRoleCodes(myInfo.roleCodes);
20492
- const brokerUrl = toText(options.brokerUrl).trim() || buildDefaultBrokerUrl();
20510
+ const mqttUrl = toText(options.mqttUrl).trim() || await getMeetingWsMqttUrl();
20511
+ const brokerUrl = normalizeBrokerUrl(mqttUrl);
20512
+ console.log("brokerUrl:", brokerUrl);
20493
20513
  const responseTopic = buildResponseTopic(loginDevice);
20494
20514
  const nextRuntime = {
20495
20515
  brokerUrl,
@@ -20615,6 +20635,9 @@ const getUploadFile = (data) => {
20615
20635
  const getMyInfo = () => {
20616
20636
  return http.request("get", "/meeting/api/v2/contact/myInfo");
20617
20637
  };
20638
+ const getMqttConfig = () => {
20639
+ return http.request("get", "/meeting/config/detail");
20640
+ };
20618
20641
  const getCreateMeeting = (data) => {
20619
20642
  return http.request(
20620
20643
  "post",
@@ -40538,7 +40561,7 @@ const _sfc_main$s = /* @__PURE__ */ defineComponent({
40538
40561
  "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => searchKeyword.value = $event),
40539
40562
  type: "text",
40540
40563
  placeholder: "搜索用户",
40541
- class: "search-input",
40564
+ class: "js-search-input",
40542
40565
  onMousedown: _cache[1] || (_cache[1] = withModifiers(() => {
40543
40566
  }, ["stop"])),
40544
40567
  onClick: _cache[2] || (_cache[2] = withModifiers(() => {
@@ -40681,7 +40704,7 @@ const _sfc_main$s = /* @__PURE__ */ defineComponent({
40681
40704
  };
40682
40705
  }
40683
40706
  });
40684
- const JSUser = /* @__PURE__ */ _export_sfc(_sfc_main$s, [["__scopeId", "data-v-23a8a167"]]);
40707
+ const JSUser = /* @__PURE__ */ _export_sfc(_sfc_main$s, [["__scopeId", "data-v-3cb577c5"]]);
40685
40708
  var RoomModalSelectType = /* @__PURE__ */ ((RoomModalSelectType2) => {
40686
40709
  RoomModalSelectType2["microphoneClick"] = "microphoneClick";
40687
40710
  RoomModalSelectType2["cameraClick"] = "cameraClick";
@@ -41455,405 +41478,96 @@ const _sfc_main$q = /* @__PURE__ */ defineComponent({
41455
41478
  }
41456
41479
  });
41457
41480
  const JSCall = /* @__PURE__ */ _export_sfc(_sfc_main$q, [["__scopeId", "data-v-e1585009"]]);
41458
- const HANDOFF_SOURCE_TAB_ID_KEY = "JS_MEETING_MQTT_HANDOFF_SOURCE_TAB_ID";
41459
- const HANDOFF_TARGET_TAB_ID_KEY = "JS_MEETING_MQTT_HANDOFF_TARGET_TAB_ID";
41460
- const HANDOFF_ID_KEY = "JS_MEETING_MQTT_HANDOFF_ID";
41461
- const RECONNECT_SIGNAL_KEY = "JS_MEETING_MQTT_RECONNECT_SIGNAL";
41462
- const TARGET_HEARTBEAT_KEY = "JS_MEETING_MQTT_HANDOFF_HEARTBEAT";
41463
- const TARGET_TAB_STATUS_KEY = "JS_MEETING_NEW_TAB_STATUS";
41464
- const TARGET_HEARTBEAT_INTERVAL_MS = 1e3;
41465
- const RECONNECT_CHECK_DELAY_MS = 1500;
41466
- const TARGET_TAB_STATUS_CLOSED = 0;
41467
- const TARGET_TAB_STATUS_OPEN = 1;
41468
- let installed = false;
41469
- let closeSignalSent = false;
41470
- let heartbeatTimer = null;
41471
- let lastHandledReconnectSignalTs = 0;
41472
- let leaveRequestSent = false;
41473
- function safeSessionStorageGetItem(key) {
41474
- try {
41475
- return sessionStorage.getItem(key);
41476
- } catch {
41477
- return null;
41478
- }
41479
- }
41480
- function safeLocalStorageSetItem(key, value) {
41481
- try {
41482
- localStorage.setItem(key, value);
41483
- } catch {
41484
- }
41485
- }
41486
- function safeLocalStorageGetItem(key) {
41487
- try {
41488
- return localStorage.getItem(key);
41489
- } catch {
41490
- return null;
41491
- }
41492
- }
41493
- function getMeetingMqttHandoffContext() {
41494
- const sourceTabId = safeSessionStorageGetItem(HANDOFF_SOURCE_TAB_ID_KEY) || "";
41495
- const targetTabId = safeSessionStorageGetItem(HANDOFF_TARGET_TAB_ID_KEY) || "";
41496
- const handoffId = safeSessionStorageGetItem(HANDOFF_ID_KEY) || "";
41497
- if (!sourceTabId || !targetTabId || !handoffId) {
41498
- return null;
41499
- }
41500
- return {
41501
- sourceTabId,
41502
- targetTabId,
41503
- handoffId
41504
- };
41505
- }
41506
- function readTargetHeartbeat() {
41507
- const raw = safeLocalStorageGetItem(TARGET_HEARTBEAT_KEY);
41508
- if (!raw) {
41509
- return null;
41510
- }
41511
- try {
41512
- const parsed = JSON.parse(raw);
41513
- if (!(parsed == null ? void 0 : parsed.targetTabId) || !(parsed == null ? void 0 : parsed.handoffId) || !(parsed == null ? void 0 : parsed.ts)) {
41514
- return null;
41515
- }
41516
- return {
41517
- targetTabId: parsed.targetTabId,
41518
- handoffId: parsed.handoffId,
41519
- ts: Number(parsed.ts)
41520
- };
41521
- } catch {
41522
- return null;
41523
- }
41524
- }
41525
- function writeTargetHeartbeat(context) {
41526
- safeLocalStorageSetItem(
41527
- TARGET_HEARTBEAT_KEY,
41528
- JSON.stringify({
41529
- targetTabId: context.targetTabId,
41530
- handoffId: context.handoffId,
41531
- ts: Date.now()
41532
- })
41533
- );
41534
- }
41535
- function writeTargetTabStatus(status, context) {
41536
- safeLocalStorageSetItem(
41537
- TARGET_TAB_STATUS_KEY,
41538
- JSON.stringify({
41539
- sourceTabId: context.sourceTabId,
41540
- targetTabId: context.targetTabId,
41541
- handoffId: context.handoffId,
41542
- status,
41543
- ts: Date.now()
41544
- })
41545
- );
41546
- }
41547
- function sendReconnectSignal(context) {
41548
- if (closeSignalSent) {
41549
- return;
41550
- }
41551
- closeSignalSent = true;
41552
- console.warn("[MQTT_HANDOFF] 目标页关闭,通知来源页恢复 MQTT", {
41553
- sourceTabId: context.sourceTabId,
41554
- targetTabId: context.targetTabId,
41555
- handoffId: context.handoffId
41556
- });
41557
- safeLocalStorageSetItem(
41558
- RECONNECT_SIGNAL_KEY,
41559
- JSON.stringify({
41560
- ...context,
41561
- ts: Date.now()
41562
- })
41563
- );
41564
- }
41565
- function stopTargetHeartbeat() {
41566
- if (heartbeatTimer) {
41567
- clearInterval(heartbeatTimer);
41568
- heartbeatTimer = null;
41569
- }
41570
- }
41571
- function startTargetHeartbeat() {
41572
- const context = getMeetingMqttHandoffContext();
41573
- if (!context) {
41574
- return;
41575
- }
41576
- const currentTabId = getCurrentMeetingTabId();
41577
- if (currentTabId !== context.targetTabId) {
41578
- return;
41579
- }
41580
- closeSignalSent = false;
41581
- console.info("[MQTT_HANDOFF] 目标页心跳已启动", {
41582
- sourceTabId: context.sourceTabId,
41583
- targetTabId: context.targetTabId,
41584
- handoffId: context.handoffId
41585
- });
41586
- writeTargetTabStatus(TARGET_TAB_STATUS_OPEN, context);
41587
- writeTargetHeartbeat(context);
41588
- stopTargetHeartbeat();
41589
- heartbeatTimer = setInterval(() => {
41590
- writeTargetHeartbeat(context);
41591
- }, TARGET_HEARTBEAT_INTERVAL_MS);
41592
- }
41593
- function notifySourceTabForReconnect() {
41594
- const context = getMeetingMqttHandoffContext();
41595
- if (!context) {
41596
- return;
41597
- }
41598
- const currentTabId = getCurrentMeetingTabId();
41599
- if (currentTabId !== context.targetTabId) {
41600
- return;
41601
- }
41602
- sendReconnectSignal(context);
41603
- }
41604
- function shouldWarnBeforeUnload() {
41605
- const context = getMeetingMqttHandoffContext();
41606
- if (!context) {
41607
- return false;
41608
- }
41609
- const currentTabId = getCurrentMeetingTabId();
41610
- return currentTabId === context.targetTabId;
41611
- }
41612
- function buildMeetingLeavePayload() {
41613
- try {
41614
- const meetingInfo = JSON.parse(sessionStorage.getItem("JS_MEETING_INFO") || "{}");
41615
- const meetingId = String((meetingInfo == null ? void 0 : meetingInfo.meetingId) || "").trim();
41616
- const memberId = String(getUserId() || "").trim();
41617
- if (!meetingId || !memberId) {
41618
- return null;
41619
- }
41620
- return { meetingId, memberId, force: true };
41621
- } catch {
41622
- return null;
41623
- }
41624
- }
41625
- function sendMeetingLeaveOnClose() {
41626
- if (leaveRequestSent) {
41627
- return;
41628
- }
41629
- const payload = buildMeetingLeavePayload();
41630
- if (!payload) {
41631
- return;
41632
- }
41633
- leaveRequestSent = true;
41634
- const body = JSON.stringify(payload);
41635
- const token = getSdkToken();
41636
- const authHeader = token ? { Authorization: `Bearer ${token}` } : {};
41637
- const requestUrl = "/meeting/api/v2/meeting/leave";
41638
- try {
41639
- fetch(requestUrl, {
41640
- method: "POST",
41641
- headers: {
41642
- "Content-Type": "application/json",
41643
- Accept: "application/json, text/plain, */*",
41644
- "X-Requested-With": "XMLHttpRequest",
41645
- ...authHeader
41646
- },
41647
- body,
41648
- keepalive: true,
41649
- credentials: "same-origin"
41650
- }).catch(() => {
41651
- });
41652
- console.warn("[MQTT_HANDOFF] 页面关闭触发离会请求(keepalive)", payload);
41653
- } catch {
41654
- }
41655
- try {
41656
- if (typeof navigator !== "undefined" && typeof navigator.sendBeacon === "function") {
41657
- const beaconData = new Blob([body], { type: "application/json" });
41658
- const sent = navigator.sendBeacon(requestUrl, beaconData);
41659
- console.warn("[MQTT_HANDOFF] 页面关闭触发离会请求(beacon)", {
41660
- ...payload,
41661
- sent
41662
- });
41663
- }
41664
- } catch {
41665
- }
41666
- }
41667
- function shouldReconnectForSignal(signal) {
41668
- const currentTabId = getCurrentMeetingTabId();
41669
- if (!signal.sourceTabId || signal.sourceTabId !== currentTabId) {
41670
- return false;
41671
- }
41672
- const latestHeartbeat = readTargetHeartbeat();
41673
- if (!latestHeartbeat) {
41674
- return true;
41675
- }
41676
- if (latestHeartbeat.targetTabId !== signal.targetTabId) {
41677
- return true;
41678
- }
41679
- if (latestHeartbeat.handoffId !== signal.handoffId) {
41680
- return true;
41681
- }
41682
- return latestHeartbeat.ts <= signal.ts;
41683
- }
41684
- function installMeetingMqttHandoffBridge(onReconnectRequested) {
41685
- if (installed || typeof window === "undefined") {
41686
- return;
41687
- }
41688
- installed = true;
41689
- startTargetHeartbeat();
41690
- window.addEventListener("storage", (event) => {
41691
- if (event.key !== RECONNECT_SIGNAL_KEY || !event.newValue) {
41692
- return;
41693
- }
41694
- let signal = null;
41695
- try {
41696
- signal = JSON.parse(event.newValue);
41697
- } catch {
41698
- return;
41699
- }
41700
- if (!(signal == null ? void 0 : signal.sourceTabId) || !signal.targetTabId || !signal.handoffId) {
41701
- return;
41702
- }
41703
- const signalTs = Number(signal.ts);
41704
- if (!signalTs || signalTs <= lastHandledReconnectSignalTs) {
41705
- return;
41706
- }
41707
- lastHandledReconnectSignalTs = signalTs;
41708
- console.warn("[MQTT_HANDOFF] 收到 MQTT 恢复信号,等待确认目标页是否真的关闭", {
41709
- sourceTabId: signal.sourceTabId,
41710
- targetTabId: signal.targetTabId,
41711
- handoffId: signal.handoffId,
41712
- signalTs
41713
- });
41714
- window.setTimeout(() => {
41715
- if (!shouldReconnectForSignal(signal)) {
41716
- console.info("[MQTT_HANDOFF] 忽略 MQTT 恢复,本次更像是目标页刷新/重载", {
41717
- sourceTabId: signal.sourceTabId,
41718
- targetTabId: signal.targetTabId,
41719
- handoffId: signal.handoffId
41720
- });
41721
- return;
41722
- }
41723
- console.warn("[MQTT_HANDOFF] 确认目标页已关闭,准备恢复来源页 MQTT", {
41724
- sourceTabId: signal.sourceTabId,
41725
- targetTabId: signal.targetTabId,
41726
- handoffId: signal.handoffId
41727
- });
41728
- void onReconnectRequested();
41729
- }, RECONNECT_CHECK_DELAY_MS);
41730
- });
41731
- window.addEventListener("beforeunload", (event) => {
41732
- if (!shouldWarnBeforeUnload()) {
41733
- return;
41734
- }
41735
- event.preventDefault();
41736
- event.returnValue = "";
41737
- });
41738
- window.addEventListener("pagehide", (event) => {
41739
- const context = getMeetingMqttHandoffContext();
41740
- const shouldHandleTargetTabClose = !!context && getCurrentMeetingTabId() === context.targetTabId;
41741
- if (shouldHandleTargetTabClose && context) {
41742
- writeTargetTabStatus(TARGET_TAB_STATUS_CLOSED, context);
41743
- sendMeetingLeaveOnClose();
41744
- }
41745
- stopTargetHeartbeat();
41746
- if (event.persisted) {
41747
- return;
41748
- }
41749
- notifySourceTabForReconnect();
41750
- });
41751
- }
41752
- const _hoisted_1$n = { class: "js-dialog-header-title" };
41753
- const _hoisted_2$l = { class: "js-dialog-header-actions" };
41754
- const _sfc_main$p = /* @__PURE__ */ defineComponent({
41755
- __name: "meeting-header",
41756
- props: {
41757
- theme: {},
41758
- isMaximized: { type: Boolean }
41759
- },
41760
- emits: ["onChange"],
41761
- setup(__props, { emit: __emit }) {
41762
- const props = __props;
41763
- const { meState: meState2 } = storeToRefs(useMeetingStore());
41764
- const meetingInfo = computed(() => {
41765
- return JSON.parse(sessionStorage.getItem("JS_MEETING_INFO") || "{}");
41766
- });
41767
- const emit = __emit;
41768
- const closeRef = ref(null);
41769
- const showCloseConfirm = ref(false);
41770
- const themeClass = computed(() => `theme-${props.theme || "dark"}`);
41771
- const hasOpenedNewTab = ref(false);
41772
- const getNewTabFlagFromLocation = () => {
41773
- if (typeof window === "undefined") return false;
41774
- const searchParams = new URLSearchParams(window.location.search || "");
41775
- if (searchParams.get("newTab") === "true") return true;
41776
- const hash = window.location.hash || "";
41777
- const hashQueryIndex = hash.indexOf("?");
41778
- if (hashQueryIndex === -1) return false;
41779
- const hashQuery = hash.slice(hashQueryIndex + 1);
41780
- const hashParams = new URLSearchParams(hashQuery);
41781
- return hashParams.get("newTab") === "true";
41782
- };
41783
- computed(() => {
41784
- if (hasOpenedNewTab.value) return false;
41785
- return !getNewTabFlagFromLocation();
41786
- });
41787
- const handleCloseClick = async () => {
41788
- showCloseConfirm.value = !showCloseConfirm.value;
41789
- };
41790
- const handleEndMeeting = () => {
41791
- showCloseConfirm.value = false;
41792
- emit("onChange", RoomModalSelectType.endClick);
41793
- };
41794
- const handleLeaveMeeting = () => {
41795
- showCloseConfirm.value = false;
41796
- emit("onChange", RoomModalSelectType.leaveClick);
41797
- };
41798
- return (_ctx, _cache) => {
41799
- return openBlock(), createElementBlock("div", {
41800
- class: normalizeClass(["js-dialog-header", themeClass.value])
41801
- }, [
41802
- createElementVNode("div", _hoisted_1$n, toDisplayString(meetingInfo.value.meetingName), 1),
41803
- createElementVNode("div", _hoisted_2$l, [
41804
- createElementVNode("div", {
41805
- title: "最小化",
41806
- onClick: _cache[0] || (_cache[0] = ($event) => emit("onChange", unref(RoomModalSelectType).minimizeClick))
41807
- }, [
41808
- createVNode(SvgIcon, {
41809
- name: "MinimizeIcon",
41810
- size: 16
41811
- })
41812
- ]),
41813
- createElementVNode("div", {
41814
- ref_key: "closeRef",
41815
- ref: closeRef,
41816
- title: "关闭",
41817
- onClick: handleCloseClick
41818
- }, [
41819
- createVNode(SvgIcon, {
41820
- name: "CloseIcon",
41821
- size: 17
41822
- })
41823
- ], 512)
41824
- ]),
41825
- createVNode(SmartPopup, {
41826
- visible: showCloseConfirm.value,
41827
- "onUpdate:visible": _cache[2] || (_cache[2] = ($event) => showCloseConfirm.value = $event),
41828
- trigger: closeRef.value,
41829
- gap: 10
41830
- }, {
41831
- default: withCtx(() => [
41832
- createElementVNode("div", {
41833
- class: normalizeClass(["close-confirm-dropdown", themeClass.value])
41834
- }, [
41835
- unref(meState2).roleType == "1" ? (openBlock(), createElementBlock("div", {
41836
- key: 0,
41837
- class: "close-confirm-option danger",
41838
- onClick: withModifiers(handleEndMeeting, ["stop"])
41839
- }, " 结束会议 ")) : createCommentVNode("", true),
41840
- createElementVNode("div", {
41841
- class: "close-confirm-option simple",
41842
- onClick: withModifiers(handleLeaveMeeting, ["stop"])
41843
- }, " 离开会议 "),
41844
- createElementVNode("div", {
41845
- class: "close-confirm-option simple",
41846
- onClick: _cache[1] || (_cache[1] = ($event) => showCloseConfirm.value = false)
41847
- }, " 取消 ")
41848
- ], 2)
41849
- ]),
41850
- _: 1
41851
- }, 8, ["visible", "trigger"])
41852
- ], 2);
41481
+ const _hoisted_1$n = { class: "js-dialog-header-title" };
41482
+ const _hoisted_2$l = { class: "js-dialog-header-actions" };
41483
+ const _sfc_main$p = /* @__PURE__ */ defineComponent({
41484
+ __name: "meeting-header",
41485
+ props: {
41486
+ theme: {},
41487
+ isMaximized: { type: Boolean }
41488
+ },
41489
+ emits: ["onChange"],
41490
+ setup(__props, { emit: __emit }) {
41491
+ const props = __props;
41492
+ const { meState: meState2 } = storeToRefs(useMeetingStore());
41493
+ const meetingInfo = computed(() => {
41494
+ return JSON.parse(sessionStorage.getItem("JS_MEETING_INFO") || "{}");
41495
+ });
41496
+ const emit = __emit;
41497
+ const closeRef = ref(null);
41498
+ const showCloseConfirm = ref(false);
41499
+ const themeClass = computed(() => `theme-${props.theme || "dark"}`);
41500
+ ref(false);
41501
+ const handleCloseClick = async () => {
41502
+ showCloseConfirm.value = !showCloseConfirm.value;
41503
+ };
41504
+ const handleEndMeeting = () => {
41505
+ showCloseConfirm.value = false;
41506
+ emit("onChange", RoomModalSelectType.endClick);
41507
+ };
41508
+ const handleLeaveMeeting = () => {
41509
+ showCloseConfirm.value = false;
41510
+ emit("onChange", RoomModalSelectType.leaveClick);
41511
+ };
41512
+ return (_ctx, _cache) => {
41513
+ return openBlock(), createElementBlock("div", {
41514
+ class: normalizeClass(["js-dialog-header", themeClass.value])
41515
+ }, [
41516
+ createElementVNode("div", _hoisted_1$n, toDisplayString(meetingInfo.value.meetingName), 1),
41517
+ createElementVNode("div", _hoisted_2$l, [
41518
+ createElementVNode("div", {
41519
+ title: "最小化",
41520
+ onClick: _cache[0] || (_cache[0] = ($event) => emit("onChange", unref(RoomModalSelectType).minimizeClick))
41521
+ }, [
41522
+ createVNode(SvgIcon, {
41523
+ name: "MinimizeIcon",
41524
+ size: 16
41525
+ })
41526
+ ]),
41527
+ createElementVNode("div", {
41528
+ ref_key: "closeRef",
41529
+ ref: closeRef,
41530
+ title: "关闭",
41531
+ onClick: handleCloseClick
41532
+ }, [
41533
+ createVNode(SvgIcon, {
41534
+ name: "CloseIcon",
41535
+ size: 17
41536
+ })
41537
+ ], 512)
41538
+ ]),
41539
+ createVNode(SmartPopup, {
41540
+ visible: showCloseConfirm.value,
41541
+ "onUpdate:visible": _cache[2] || (_cache[2] = ($event) => showCloseConfirm.value = $event),
41542
+ trigger: closeRef.value,
41543
+ gap: 10
41544
+ }, {
41545
+ default: withCtx(() => [
41546
+ createElementVNode("div", {
41547
+ class: normalizeClass(["close-confirm-dropdown", themeClass.value])
41548
+ }, [
41549
+ unref(meState2).roleType == "1" ? (openBlock(), createElementBlock("div", {
41550
+ key: 0,
41551
+ class: "close-confirm-option danger",
41552
+ onClick: withModifiers(handleEndMeeting, ["stop"])
41553
+ }, " 结束会议 ")) : createCommentVNode("", true),
41554
+ createElementVNode("div", {
41555
+ class: "close-confirm-option simple",
41556
+ onClick: withModifiers(handleLeaveMeeting, ["stop"])
41557
+ }, " 离开会议 "),
41558
+ createElementVNode("div", {
41559
+ class: "close-confirm-option simple",
41560
+ onClick: _cache[1] || (_cache[1] = ($event) => showCloseConfirm.value = false)
41561
+ }, " 取消 ")
41562
+ ], 2)
41563
+ ]),
41564
+ _: 1
41565
+ }, 8, ["visible", "trigger"])
41566
+ ], 2);
41853
41567
  };
41854
41568
  }
41855
41569
  });
41856
- const MeetingHeader = /* @__PURE__ */ _export_sfc(_sfc_main$p, [["__scopeId", "data-v-8296cfa6"]]);
41570
+ const MeetingHeader = /* @__PURE__ */ _export_sfc(_sfc_main$p, [["__scopeId", "data-v-28fc3b9d"]]);
41857
41571
  const _hoisted_1$m = ["title"];
41858
41572
  const _hoisted_2$k = {
41859
41573
  class: "signal-bars",
@@ -42959,17 +42673,17 @@ const _sfc_main$l = /* @__PURE__ */ defineComponent({
42959
42673
  }
42960
42674
  });
42961
42675
  const MeetingFooter = /* @__PURE__ */ _export_sfc(_sfc_main$l, [["__scopeId", "data-v-480c2c76"]]);
42962
- const _hoisted_1$i = { class: "search" };
42963
- const _hoisted_2$h = { class: "custom-tabs" };
42964
- const _hoisted_3$h = { class: "member-list" };
42676
+ const _hoisted_1$i = { class: "js-search" };
42677
+ const _hoisted_2$h = { class: "js-custom-tabs" };
42678
+ const _hoisted_3$h = { class: "js-member-list" };
42965
42679
  const _hoisted_4$f = ["onMouseenter"];
42966
- const _hoisted_5$d = { class: "default-avatar" };
42967
- const _hoisted_6$c = { class: "info" };
42968
- const _hoisted_7$b = { class: "name-line" };
42969
- const _hoisted_8$a = { class: "name" };
42680
+ const _hoisted_5$d = { class: "js-default-avatar" };
42681
+ const _hoisted_6$c = { class: "js-info" };
42682
+ const _hoisted_7$b = { class: "js-name-line" };
42683
+ const _hoisted_8$a = { class: "js-name" };
42970
42684
  const _hoisted_9$8 = { key: 0 };
42971
42685
  const _hoisted_10$8 = { key: 1 };
42972
- const _hoisted_11$7 = { class: "member-actions" };
42686
+ const _hoisted_11$7 = { class: "js-member-actions" };
42973
42687
  const _hoisted_12$7 = ["onClick"];
42974
42688
  const _hoisted_13$6 = ["onClick"];
42975
42689
  const _hoisted_14$5 = ["onClick"];
@@ -42979,9 +42693,9 @@ const _hoisted_17$3 = ["onClick"];
42979
42693
  const _hoisted_18$3 = ["onClick"];
42980
42694
  const _hoisted_19$3 = {
42981
42695
  key: 0,
42982
- class: "empty-tip"
42696
+ class: "js-empty-tip"
42983
42697
  };
42984
- const _hoisted_20$3 = { class: "footer-btns" };
42698
+ const _hoisted_20$3 = { class: "js-footer-btns" };
42985
42699
  const _sfc_main$k = /* @__PURE__ */ defineComponent({
42986
42700
  __name: "ManageMembers",
42987
42701
  props: {
@@ -43134,10 +42848,10 @@ const _sfc_main$k = /* @__PURE__ */ defineComponent({
43134
42848
  }
43135
42849
  activeMoreMenuId.value = memberId;
43136
42850
  await nextTick();
43137
- const menuEl = document.getElementById(`dropdown-menu-${memberId}`);
42851
+ const menuEl = document.getElementById(`js-dropdown-menu-${memberId}`);
43138
42852
  const anchorEl = event.currentTarget;
43139
42853
  const listEl = document.querySelector(
43140
- ".manage-members .member-list"
42854
+ ".js-manage-members .js-member-list"
43141
42855
  );
43142
42856
  if (!menuEl || !anchorEl || !listEl) {
43143
42857
  moreMenuPlacement.value = "down";
@@ -43186,30 +42900,30 @@ const _sfc_main$k = /* @__PURE__ */ defineComponent({
43186
42900
  };
43187
42901
  return (_ctx, _cache) => {
43188
42902
  return openBlock(), createElementBlock("div", {
43189
- class: normalizeClass(["manage-members", themeClass.value])
42903
+ class: normalizeClass(["js-manage-members", themeClass.value])
43190
42904
  }, [
43191
42905
  createElementVNode("div", _hoisted_1$i, [
43192
42906
  withDirectives(createElementVNode("input", {
43193
42907
  "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => search.value = $event),
43194
42908
  type: "text",
43195
42909
  placeholder: "搜索用户",
43196
- class: "search-input"
42910
+ class: "js-search-input"
43197
42911
  }, null, 512), [
43198
42912
  [vModelText, search.value]
43199
42913
  ]),
43200
42914
  createVNode(SvgIcon, {
43201
42915
  name: "SearchIcon",
43202
- class: "search-icon",
42916
+ class: "js-search-icon",
43203
42917
  size: 16
43204
42918
  })
43205
42919
  ]),
43206
42920
  createElementVNode("div", _hoisted_2$h, [
43207
42921
  createElementVNode("div", {
43208
- class: normalizeClass(["tab-item", { active: activeTab.value === "inMeeting" }]),
42922
+ class: normalizeClass(["js-tab-item", { active: activeTab.value === "inMeeting" }]),
43209
42923
  onClick: _cache[1] || (_cache[1] = ($event) => activeTab.value = "inMeeting")
43210
42924
  }, " 会议中·" + toDisplayString(inMeetingCount.value), 3),
43211
42925
  createElementVNode("div", {
43212
- class: normalizeClass(["tab-item", { active: activeTab.value === "notJoined" }]),
42926
+ class: normalizeClass(["js-tab-item", { active: activeTab.value === "notJoined" }]),
43213
42927
  onClick: _cache[2] || (_cache[2] = ($event) => activeTab.value = "notJoined")
43214
42928
  }, " 未进入 ", 2)
43215
42929
  ]),
@@ -43217,7 +42931,7 @@ const _sfc_main$k = /* @__PURE__ */ defineComponent({
43217
42931
  (openBlock(true), createElementBlock(Fragment, null, renderList(filteredMembers.value, (member) => {
43218
42932
  return openBlock(), createElementBlock("div", {
43219
42933
  key: member.member.memberId,
43220
- class: "member-item",
42934
+ class: "js-member-item",
43221
42935
  onMouseenter: ($event) => hoveredMemberId.value = member.member.memberId,
43222
42936
  onMouseleave: handleMouseLeave
43223
42937
  }, [
@@ -43235,33 +42949,33 @@ const _sfc_main$k = /* @__PURE__ */ defineComponent({
43235
42949
  hoveredMemberId.value === member.member.memberId && member.member.memberId !== unref(userId) && isCurrentUserHost.value ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [
43236
42950
  member.audioStatus == "1" && member.roleType !== "5" ? (openBlock(), createElementBlock("div", {
43237
42951
  key: 0,
43238
- class: "action-btn",
42952
+ class: "js-action-btn",
43239
42953
  onClick: ($event) => controlMember("1", "0", member.member.memberId)
43240
42954
  }, " 静音 ", 8, _hoisted_12$7)) : createCommentVNode("", true),
43241
42955
  member.audioStatus !== "1" && member.roleType !== "5" ? (openBlock(), createElementBlock("div", {
43242
42956
  key: 1,
43243
- class: "action-btn",
42957
+ class: "js-action-btn",
43244
42958
  onClick: ($event) => controlMember("1", "1", member.member.memberId)
43245
42959
  }, " 解除静音 ", 8, _hoisted_13$6)) : createCommentVNode("", true),
43246
42960
  member.member.memberId !== unref(userId) ? (openBlock(), createElementBlock("div", {
43247
42961
  key: 2,
43248
- class: "more-dropdown",
42962
+ class: "js-more-dropdown",
43249
42963
  onClick: withModifiers(($event) => toggleMoreMenu(member.member.memberId, $event), ["stop"])
43250
42964
  }, [
43251
42965
  _cache[4] || (_cache[4] = createElementVNode("span", null, "更多", -1)),
43252
- _cache[5] || (_cache[5] = createElementVNode("div", { class: "dropdown-arrow" }, "▼", -1)),
42966
+ _cache[5] || (_cache[5] = createElementVNode("div", { class: "js-dropdown-arrow" }, "▼", -1)),
43253
42967
  activeMoreMenuId.value === member.member.memberId ? (openBlock(), createElementBlock("div", {
43254
42968
  key: 0,
43255
- id: `dropdown-menu-${member.member.memberId}`,
43256
- class: normalizeClass(["dropdown-menu", { up: moreMenuPlacement.value === "up" }])
42969
+ id: `js-dropdown-menu-${member.member.memberId}`,
42970
+ class: normalizeClass(["js-dropdown-menu", { up: moreMenuPlacement.value === "up" }])
43257
42971
  }, [
43258
42972
  member.roleType !== "5" ? (openBlock(), createElementBlock("div", {
43259
42973
  key: 0,
43260
- class: "dropdown-item",
42974
+ class: "js-dropdown-item",
43261
42975
  onClick: ($event) => transferHost(member.member.memberId)
43262
42976
  }, " 设为主持人 ", 8, _hoisted_16$4)) : createCommentVNode("", true),
43263
42977
  createElementVNode("div", {
43264
- class: "dropdown-item",
42978
+ class: "js-dropdown-item",
43265
42979
  onClick: ($event) => kickOut(member.member.memberId)
43266
42980
  }, " 移出会议 ", 8, _hoisted_17$3)
43267
42981
  ], 10, _hoisted_15$4)) : createCommentVNode("", true)
@@ -43281,7 +42995,7 @@ const _sfc_main$k = /* @__PURE__ */ defineComponent({
43281
42995
  ], 64)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [
43282
42996
  unref(meState2).roleType == "1" ? (openBlock(), createElementBlock("button", {
43283
42997
  key: 0,
43284
- class: "action-btn",
42998
+ class: "js-action-btn",
43285
42999
  onClick: ($event) => inviteMember(member)
43286
43000
  }, " 邀请 ", 8, _hoisted_18$3)) : createCommentVNode("", true)
43287
43001
  ], 64))
@@ -43293,12 +43007,12 @@ const _sfc_main$k = /* @__PURE__ */ defineComponent({
43293
43007
  createElementVNode("div", _hoisted_20$3, [
43294
43008
  activeTab.value === "inMeeting" && canTakeBackHost.value ? (openBlock(), createElementBlock("div", {
43295
43009
  key: 0,
43296
- class: "btn",
43010
+ class: "js-btn",
43297
43011
  onClick: _cache[3] || (_cache[3] = ($event) => takeBack())
43298
43012
  }, " 收回主持人 ")) : createCommentVNode("", true),
43299
43013
  activeTab.value === "inMeeting" && isCurrentUserHost.value ? (openBlock(), createElementBlock("div", {
43300
43014
  key: 1,
43301
- class: normalizeClass(["btn", { disabled: allMutedExceptMe.value }]),
43015
+ class: normalizeClass(["js-btn", { disabled: allMutedExceptMe.value }]),
43302
43016
  onClick: handleToggleAllMute
43303
43017
  }, toDisplayString(allMutedExceptMe.value ? "已全体静音" : "全体静音"), 3)) : createCommentVNode("", true)
43304
43018
  ])
@@ -43306,7 +43020,7 @@ const _sfc_main$k = /* @__PURE__ */ defineComponent({
43306
43020
  };
43307
43021
  }
43308
43022
  });
43309
- const ManageMembers = /* @__PURE__ */ _export_sfc(_sfc_main$k, [["__scopeId", "data-v-a5de6239"]]);
43023
+ const ManageMembers = /* @__PURE__ */ _export_sfc(_sfc_main$k, [["__scopeId", "data-v-497b82f0"]]);
43310
43024
  const _hoisted_1$h = { class: "chat-container" };
43311
43025
  const _hoisted_2$g = { class: "chat-content" };
43312
43026
  const _hoisted_3$g = { class: "chat-meta" };
@@ -44109,14 +43823,14 @@ const _sfc_main$g = /* @__PURE__ */ defineComponent({
44109
43823
  }
44110
43824
  });
44111
43825
  const ScreenSharingIndicator = /* @__PURE__ */ _export_sfc(_sfc_main$g, [["__scopeId", "data-v-c5d77535"]]);
44112
- const _hoisted_1$e = { class: "video-container" };
43826
+ const _hoisted_1$e = { class: "js-video-container" };
44113
43827
  const _hoisted_2$d = {
44114
43828
  id: "my-video",
44115
43829
  class: "video-element"
44116
43830
  };
44117
43831
  const _hoisted_3$d = { class: "avatar-container" };
44118
43832
  const _hoisted_4$b = { class: "avatar small" };
44119
- const _hoisted_5$a = { class: "minimized-actions" };
43833
+ const _hoisted_5$a = { class: "js-minimized-actions" };
44120
43834
  const _hoisted_6$9 = ["title"];
44121
43835
  const _hoisted_7$8 = ["title"];
44122
43836
  const _hoisted_8$7 = ["title"];
@@ -44173,7 +43887,7 @@ const _sfc_main$f = /* @__PURE__ */ defineComponent({
44173
43887
  return openBlock(), createBlock(Teleport, { to: "body" }, [
44174
43888
  _ctx.visible ? withDirectives((openBlock(), createElementBlock("div", {
44175
43889
  key: 0,
44176
- class: normalizeClass(["minimized-meeting", themeClass.value]),
43890
+ class: normalizeClass(["js-minimized-meeting", themeClass.value]),
44177
43891
  style: normalizeStyle({ height: componentHeight.value })
44178
43892
  }, [
44179
43893
  withDirectives(createElementVNode("div", _hoisted_1$e, [
@@ -44190,7 +43904,7 @@ const _sfc_main$f = /* @__PURE__ */ defineComponent({
44190
43904
  ]),
44191
43905
  createElementVNode("div", _hoisted_5$a, [
44192
43906
  createElementVNode("div", {
44193
- class: "action-btn",
43907
+ class: "js-action-btn",
44194
43908
  title: ((_c2 = unref(meState2)) == null ? void 0 : _c2.microPhoneState) == "1" ? "静音" : "取消静音",
44195
43909
  onClick: withModifiers(toggleMic, ["stop"])
44196
43910
  }, [
@@ -44200,7 +43914,7 @@ const _sfc_main$f = /* @__PURE__ */ defineComponent({
44200
43914
  }, null, 8, ["name"])
44201
43915
  ], 8, _hoisted_6$9),
44202
43916
  createElementVNode("div", {
44203
- class: "action-btn",
43917
+ class: "js-action-btn",
44204
43918
  title: ((_e = unref(meState2)) == null ? void 0 : _e.cameraState) == "1" ? "关闭摄像头" : "打开摄像头",
44205
43919
  onClick: withModifiers(toggleCamera, ["stop"])
44206
43920
  }, [
@@ -44210,7 +43924,7 @@ const _sfc_main$f = /* @__PURE__ */ defineComponent({
44210
43924
  }, null, 8, ["name"])
44211
43925
  ], 8, _hoisted_7$8),
44212
43926
  createElementVNode("div", {
44213
- class: "action-btn",
43927
+ class: "js-action-btn",
44214
43928
  title: "返回会议",
44215
43929
  onClick: withModifiers(handleRestore, ["stop"])
44216
43930
  }, [
@@ -44220,7 +43934,7 @@ const _sfc_main$f = /* @__PURE__ */ defineComponent({
44220
43934
  })
44221
43935
  ]),
44222
43936
  createElementVNode("div", {
44223
- class: "action-btn",
43937
+ class: "js-action-btn",
44224
43938
  title: isCollapsed.value ? "展开画面小窗" : "收起画面小窗",
44225
43939
  onClick: withModifiers(handleToggleCollapse, ["stop"])
44226
43940
  }, [
@@ -44237,7 +43951,7 @@ const _sfc_main$f = /* @__PURE__ */ defineComponent({
44237
43951
  };
44238
43952
  }
44239
43953
  });
44240
- const MinimizedMeeting = /* @__PURE__ */ _export_sfc(_sfc_main$f, [["__scopeId", "data-v-5489e659"]]);
43954
+ const MinimizedMeeting = /* @__PURE__ */ _export_sfc(_sfc_main$f, [["__scopeId", "data-v-ec9b81c5"]]);
44241
43955
  const _hoisted_1$d = {
44242
43956
  key: 0,
44243
43957
  class: "toggle"
@@ -44757,7 +44471,7 @@ const _sfc_main$c = /* @__PURE__ */ defineComponent({
44757
44471
  "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => searchKeyword.value = $event),
44758
44472
  type: "text",
44759
44473
  placeholder: "搜索用户",
44760
- class: "search-input",
44474
+ class: "js-search-input",
44761
44475
  onInput: handleSearch
44762
44476
  }, null, 544), [
44763
44477
  [vModelText, searchKeyword.value]
@@ -44833,19 +44547,19 @@ const _sfc_main$c = /* @__PURE__ */ defineComponent({
44833
44547
  };
44834
44548
  }
44835
44549
  });
44836
- const Invite = /* @__PURE__ */ _export_sfc(_sfc_main$c, [["__scopeId", "data-v-8d4f89eb"]]);
44837
- const _hoisted_1$a = { class: "meeting-invite-modal" };
44838
- const _hoisted_2$a = { class: "meeting-invite-modal-header" };
44839
- const _hoisted_3$a = { class: "meeting-invite-modal-title" };
44550
+ const Invite = /* @__PURE__ */ _export_sfc(_sfc_main$c, [["__scopeId", "data-v-b2cd501c"]]);
44551
+ const _hoisted_1$a = { class: "js-meeting-invite-modal" };
44552
+ const _hoisted_2$a = { class: "js-meeting-invite-modal-header" };
44553
+ const _hoisted_3$a = { class: "js-meeting-invite-modal-title" };
44840
44554
  const _hoisted_4$8 = { class: "js-invite-modal-header-close" };
44841
- const _hoisted_5$7 = { class: "meeting-invite-modal-content" };
44842
- const _hoisted_6$7 = { class: "meeting-info" };
44843
- const _hoisted_7$6 = { class: "meeting-name" };
44844
- const _hoisted_8$5 = { class: "meeting-details" };
44845
- const _hoisted_9$5 = { class: "meeting-detail-item" };
44846
- const _hoisted_10$5 = { class: "value" };
44847
- const _hoisted_11$4 = { class: "meeting-detail-item" };
44848
- const _hoisted_12$4 = { class: "value" };
44555
+ const _hoisted_5$7 = { class: "js-meeting-invite-modal-content" };
44556
+ const _hoisted_6$7 = { class: "js-meeting-info" };
44557
+ const _hoisted_7$6 = { class: "js-meeting-name" };
44558
+ const _hoisted_8$5 = { class: "js-meeting-details" };
44559
+ const _hoisted_9$5 = { class: "js-meeting-detail-item" };
44560
+ const _hoisted_10$5 = { class: "js-value" };
44561
+ const _hoisted_11$4 = { class: "js-meeting-detail-item" };
44562
+ const _hoisted_12$4 = { class: "js-value" };
44849
44563
  const _sfc_main$b = /* @__PURE__ */ defineComponent({
44850
44564
  __name: "MeetingInviteModal",
44851
44565
  props: {
@@ -44914,7 +44628,7 @@ const _sfc_main$b = /* @__PURE__ */ defineComponent({
44914
44628
  return (_ctx, _cache) => {
44915
44629
  return _ctx.visible ? (openBlock(), createElementBlock("div", {
44916
44630
  key: 0,
44917
- class: normalizeClass(["meeting-invite-modal-overlay", themeClass.value])
44631
+ class: normalizeClass(["js-meeting-invite-modal-overlay", themeClass.value])
44918
44632
  }, [
44919
44633
  createElementVNode("div", _hoisted_1$a, [
44920
44634
  createElementVNode("div", _hoisted_2$a, [
@@ -44939,24 +44653,24 @@ const _sfc_main$b = /* @__PURE__ */ defineComponent({
44939
44653
  createElementVNode("div", _hoisted_7$6, toDisplayString(_ctx.meetingInfo.meetingName || "未知会议"), 1),
44940
44654
  createElementVNode("div", _hoisted_8$5, [
44941
44655
  createElementVNode("div", _hoisted_9$5, [
44942
- _cache[1] || (_cache[1] = createElementVNode("span", { class: "label" }, "邀请人:", -1)),
44656
+ _cache[1] || (_cache[1] = createElementVNode("span", { class: "js-label" }, "邀请人:", -1)),
44943
44657
  createElementVNode("span", _hoisted_10$5, toDisplayString(_ctx.meetingInfo.inviterName || "未知"), 1)
44944
44658
  ]),
44945
44659
  createElementVNode("div", _hoisted_11$4, [
44946
- _cache[2] || (_cache[2] = createElementVNode("span", { class: "label" }, "邀请时间:", -1)),
44660
+ _cache[2] || (_cache[2] = createElementVNode("span", { class: "js-label" }, "邀请时间:", -1)),
44947
44661
  createElementVNode("span", _hoisted_12$4, toDisplayString(formatTime(_ctx.meetingInfo.inviteTime)), 1)
44948
44662
  ])
44949
44663
  ])
44950
44664
  ]),
44951
- createElementVNode("div", { class: "meeting-invite-modal-actions" }, [
44665
+ createElementVNode("div", { class: "js-meeting-invite-modal-actions" }, [
44952
44666
  createElementVNode("button", {
44953
- class: "btn btn-accept",
44667
+ class: "js-btn js-btn-accept",
44954
44668
  onClick: handleAccept
44955
44669
  }, [..._cache[4] || (_cache[4] = [
44956
44670
  createElementVNode("span", null, "接受邀请", -1)
44957
44671
  ])]),
44958
44672
  createElementVNode("button", {
44959
- class: "btn btn-decline",
44673
+ class: "js-btn js-btn-decline",
44960
44674
  onClick: handleDecline
44961
44675
  }, [..._cache[5] || (_cache[5] = [
44962
44676
  createElementVNode("span", null, "拒绝邀请", -1)
@@ -44968,7 +44682,7 @@ const _sfc_main$b = /* @__PURE__ */ defineComponent({
44968
44682
  };
44969
44683
  }
44970
44684
  });
44971
- const MeetingInviteModal = /* @__PURE__ */ _export_sfc(_sfc_main$b, [["__scopeId", "data-v-891c0b93"]]);
44685
+ const MeetingInviteModal = /* @__PURE__ */ _export_sfc(_sfc_main$b, [["__scopeId", "data-v-397c4954"]]);
44972
44686
  const _hoisted_1$9 = {
44973
44687
  key: 0,
44974
44688
  class: "js-dialog-overlay"
@@ -46263,7 +45977,7 @@ const _sfc_main$7 = /* @__PURE__ */ defineComponent({
46263
45977
  "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => searchKeyword.value = $event),
46264
45978
  type: "text",
46265
45979
  placeholder: "搜索用户",
46266
- class: "search-input"
45980
+ class: "js-search-input"
46267
45981
  }, null, 512), [
46268
45982
  [vModelText, searchKeyword.value]
46269
45983
  ]),
@@ -46330,7 +46044,7 @@ const _sfc_main$7 = /* @__PURE__ */ defineComponent({
46330
46044
  };
46331
46045
  }
46332
46046
  });
46333
- const JSUnattendedSetting = /* @__PURE__ */ _export_sfc(_sfc_main$7, [["__scopeId", "data-v-bd4919c7"]]);
46047
+ const JSUnattendedSetting = /* @__PURE__ */ _export_sfc(_sfc_main$7, [["__scopeId", "data-v-1a8b386c"]]);
46334
46048
  const _hoisted_1$5 = { class: "notification-container" };
46335
46049
  const _hoisted_2$5 = ["onClick"];
46336
46050
  const _hoisted_3$5 = { class: "notification-content" };
@@ -46583,7 +46297,7 @@ const _sfc_main$4 = /* @__PURE__ */ defineComponent({
46583
46297
  };
46584
46298
  }
46585
46299
  });
46586
- const GlobalIncomingCallModal = /* @__PURE__ */ _export_sfc(_sfc_main$4, [["__scopeId", "data-v-de2969ec"]]);
46300
+ const GlobalIncomingCallModal = /* @__PURE__ */ _export_sfc(_sfc_main$4, [["__scopeId", "data-v-0803c0d7"]]);
46587
46301
  const _hoisted_1$2 = {
46588
46302
  key: 0,
46589
46303
  class: "unattended-display"
@@ -47301,26 +47015,321 @@ function scheduleJoinRoom() {
47301
47015
  }
47302
47016
  }, 1e3);
47303
47017
  }
47304
- let authToken = null;
47305
- async function restoreMeetingMqttConnection() {
47306
- console.warn("[MQTT_RESTORE] 收到恢复请求,开始重连 MQTT");
47018
+ const HANDOFF_SOURCE_TAB_ID_KEY = "JS_MEETING_MQTT_HANDOFF_SOURCE_TAB_ID";
47019
+ const HANDOFF_TARGET_TAB_ID_KEY = "JS_MEETING_MQTT_HANDOFF_TARGET_TAB_ID";
47020
+ const HANDOFF_ID_KEY = "JS_MEETING_MQTT_HANDOFF_ID";
47021
+ const RECONNECT_SIGNAL_KEY = "JS_MEETING_MQTT_RECONNECT_SIGNAL";
47022
+ const TARGET_HEARTBEAT_KEY = "JS_MEETING_MQTT_HANDOFF_HEARTBEAT";
47023
+ const TARGET_TAB_STATUS_KEY = "JS_MEETING_NEW_TAB_STATUS";
47024
+ const TARGET_HEARTBEAT_INTERVAL_MS = 1e3;
47025
+ const RECONNECT_CHECK_DELAY_MS = 1500;
47026
+ const TARGET_TAB_STATUS_CLOSED = 0;
47027
+ const TARGET_TAB_STATUS_OPEN = 1;
47028
+ let installed = false;
47029
+ let closeSignalSent = false;
47030
+ let heartbeatTimer = null;
47031
+ let lastHandledReconnectSignalTs = 0;
47032
+ let leaveRequestSent = false;
47033
+ function safeSessionStorageGetItem(key) {
47307
47034
  try {
47308
- await initializeMeetingMQTT();
47309
- installMeetingMessageHandlers();
47310
- console.info("[MQTT_RESTORE] MQTT 恢复成功,消息监听已恢复");
47311
- } catch (error) {
47312
- console.error("[MQTT_RESTORE] MQTT 恢复失败", error);
47035
+ return sessionStorage.getItem(key);
47036
+ } catch {
47037
+ return null;
47313
47038
  }
47314
47039
  }
47315
- function clearSdkStorages() {
47316
- if (typeof window === "undefined") return;
47040
+ function safeLocalStorageSetItem(key, value) {
47317
47041
  try {
47318
- sessionStorage.removeItem("JS_MEETING_INFO");
47319
- sessionStorage.removeItem("JS_INCOMING_CALL_INFO");
47320
- sessionStorage.removeItem("joinTime");
47321
- sessionStorage.removeItem("JS_USER_ID");
47322
- sessionStorage.removeItem("JS_USER_NAME");
47323
- localStorage.removeItem("device_id");
47042
+ localStorage.setItem(key, value);
47043
+ } catch {
47044
+ }
47045
+ }
47046
+ function safeLocalStorageGetItem(key) {
47047
+ try {
47048
+ return localStorage.getItem(key);
47049
+ } catch {
47050
+ return null;
47051
+ }
47052
+ }
47053
+ function getMeetingMqttHandoffContext() {
47054
+ const sourceTabId = safeSessionStorageGetItem(HANDOFF_SOURCE_TAB_ID_KEY) || "";
47055
+ const targetTabId = safeSessionStorageGetItem(HANDOFF_TARGET_TAB_ID_KEY) || "";
47056
+ const handoffId = safeSessionStorageGetItem(HANDOFF_ID_KEY) || "";
47057
+ if (!sourceTabId || !targetTabId || !handoffId) {
47058
+ return null;
47059
+ }
47060
+ return {
47061
+ sourceTabId,
47062
+ targetTabId,
47063
+ handoffId
47064
+ };
47065
+ }
47066
+ function readTargetHeartbeat() {
47067
+ const raw = safeLocalStorageGetItem(TARGET_HEARTBEAT_KEY);
47068
+ if (!raw) {
47069
+ return null;
47070
+ }
47071
+ try {
47072
+ const parsed = JSON.parse(raw);
47073
+ if (!(parsed == null ? void 0 : parsed.targetTabId) || !(parsed == null ? void 0 : parsed.handoffId) || !(parsed == null ? void 0 : parsed.ts)) {
47074
+ return null;
47075
+ }
47076
+ return {
47077
+ targetTabId: parsed.targetTabId,
47078
+ handoffId: parsed.handoffId,
47079
+ ts: Number(parsed.ts)
47080
+ };
47081
+ } catch {
47082
+ return null;
47083
+ }
47084
+ }
47085
+ function writeTargetHeartbeat(context) {
47086
+ safeLocalStorageSetItem(
47087
+ TARGET_HEARTBEAT_KEY,
47088
+ JSON.stringify({
47089
+ targetTabId: context.targetTabId,
47090
+ handoffId: context.handoffId,
47091
+ ts: Date.now()
47092
+ })
47093
+ );
47094
+ }
47095
+ function writeTargetTabStatus(status, context) {
47096
+ safeLocalStorageSetItem(
47097
+ TARGET_TAB_STATUS_KEY,
47098
+ JSON.stringify({
47099
+ sourceTabId: context.sourceTabId,
47100
+ targetTabId: context.targetTabId,
47101
+ handoffId: context.handoffId,
47102
+ status,
47103
+ ts: Date.now()
47104
+ })
47105
+ );
47106
+ }
47107
+ function sendReconnectSignal(context) {
47108
+ if (closeSignalSent) {
47109
+ return;
47110
+ }
47111
+ closeSignalSent = true;
47112
+ console.warn("[MQTT_HANDOFF] 目标页关闭,通知来源页恢复 MQTT", {
47113
+ sourceTabId: context.sourceTabId,
47114
+ targetTabId: context.targetTabId,
47115
+ handoffId: context.handoffId
47116
+ });
47117
+ safeLocalStorageSetItem(
47118
+ RECONNECT_SIGNAL_KEY,
47119
+ JSON.stringify({
47120
+ ...context,
47121
+ ts: Date.now()
47122
+ })
47123
+ );
47124
+ }
47125
+ function stopTargetHeartbeat() {
47126
+ if (heartbeatTimer) {
47127
+ clearInterval(heartbeatTimer);
47128
+ heartbeatTimer = null;
47129
+ }
47130
+ }
47131
+ function startTargetHeartbeat() {
47132
+ const context = getMeetingMqttHandoffContext();
47133
+ if (!context) {
47134
+ return;
47135
+ }
47136
+ const currentTabId = getCurrentMeetingTabId();
47137
+ if (currentTabId !== context.targetTabId) {
47138
+ return;
47139
+ }
47140
+ closeSignalSent = false;
47141
+ console.info("[MQTT_HANDOFF] 目标页心跳已启动", {
47142
+ sourceTabId: context.sourceTabId,
47143
+ targetTabId: context.targetTabId,
47144
+ handoffId: context.handoffId
47145
+ });
47146
+ writeTargetTabStatus(TARGET_TAB_STATUS_OPEN, context);
47147
+ writeTargetHeartbeat(context);
47148
+ stopTargetHeartbeat();
47149
+ heartbeatTimer = setInterval(() => {
47150
+ writeTargetHeartbeat(context);
47151
+ }, TARGET_HEARTBEAT_INTERVAL_MS);
47152
+ }
47153
+ function notifySourceTabForReconnect() {
47154
+ const context = getMeetingMqttHandoffContext();
47155
+ if (!context) {
47156
+ return;
47157
+ }
47158
+ const currentTabId = getCurrentMeetingTabId();
47159
+ if (currentTabId !== context.targetTabId) {
47160
+ return;
47161
+ }
47162
+ sendReconnectSignal(context);
47163
+ }
47164
+ function shouldWarnBeforeUnload() {
47165
+ const context = getMeetingMqttHandoffContext();
47166
+ if (!context) {
47167
+ return false;
47168
+ }
47169
+ const currentTabId = getCurrentMeetingTabId();
47170
+ return currentTabId === context.targetTabId;
47171
+ }
47172
+ function buildMeetingLeavePayload() {
47173
+ try {
47174
+ const meetingInfo = JSON.parse(sessionStorage.getItem("JS_MEETING_INFO") || "{}");
47175
+ const meetingId = String((meetingInfo == null ? void 0 : meetingInfo.meetingId) || "").trim();
47176
+ const memberId = String(getUserId() || "").trim();
47177
+ if (!meetingId || !memberId) {
47178
+ return null;
47179
+ }
47180
+ return { meetingId, memberId, force: true };
47181
+ } catch {
47182
+ return null;
47183
+ }
47184
+ }
47185
+ function sendMeetingLeaveOnClose() {
47186
+ if (leaveRequestSent) {
47187
+ return;
47188
+ }
47189
+ const payload = buildMeetingLeavePayload();
47190
+ if (!payload) {
47191
+ return;
47192
+ }
47193
+ leaveRequestSent = true;
47194
+ const body = JSON.stringify(payload);
47195
+ const token = getSdkToken();
47196
+ const authHeader = token ? { Authorization: `Bearer ${token}` } : {};
47197
+ const requestUrl = "/meeting/api/v2/meeting/leave";
47198
+ try {
47199
+ fetch(requestUrl, {
47200
+ method: "POST",
47201
+ headers: {
47202
+ "Content-Type": "application/json",
47203
+ Accept: "application/json, text/plain, */*",
47204
+ "X-Requested-With": "XMLHttpRequest",
47205
+ ...authHeader
47206
+ },
47207
+ body,
47208
+ keepalive: true,
47209
+ credentials: "same-origin"
47210
+ }).catch(() => {
47211
+ });
47212
+ console.warn("[MQTT_HANDOFF] 页面关闭触发离会请求(keepalive)", payload);
47213
+ } catch {
47214
+ }
47215
+ try {
47216
+ if (typeof navigator !== "undefined" && typeof navigator.sendBeacon === "function") {
47217
+ const beaconData = new Blob([body], { type: "application/json" });
47218
+ const sent = navigator.sendBeacon(requestUrl, beaconData);
47219
+ console.warn("[MQTT_HANDOFF] 页面关闭触发离会请求(beacon)", {
47220
+ ...payload,
47221
+ sent
47222
+ });
47223
+ }
47224
+ } catch {
47225
+ }
47226
+ }
47227
+ function shouldReconnectForSignal(signal) {
47228
+ const currentTabId = getCurrentMeetingTabId();
47229
+ if (!signal.sourceTabId || signal.sourceTabId !== currentTabId) {
47230
+ return false;
47231
+ }
47232
+ const latestHeartbeat = readTargetHeartbeat();
47233
+ if (!latestHeartbeat) {
47234
+ return true;
47235
+ }
47236
+ if (latestHeartbeat.targetTabId !== signal.targetTabId) {
47237
+ return true;
47238
+ }
47239
+ if (latestHeartbeat.handoffId !== signal.handoffId) {
47240
+ return true;
47241
+ }
47242
+ return latestHeartbeat.ts <= signal.ts;
47243
+ }
47244
+ function installMeetingMqttHandoffBridge(onReconnectRequested) {
47245
+ if (installed || typeof window === "undefined") {
47246
+ return;
47247
+ }
47248
+ installed = true;
47249
+ startTargetHeartbeat();
47250
+ window.addEventListener("storage", (event) => {
47251
+ if (event.key !== RECONNECT_SIGNAL_KEY || !event.newValue) {
47252
+ return;
47253
+ }
47254
+ let signal = null;
47255
+ try {
47256
+ signal = JSON.parse(event.newValue);
47257
+ } catch {
47258
+ return;
47259
+ }
47260
+ if (!(signal == null ? void 0 : signal.sourceTabId) || !signal.targetTabId || !signal.handoffId) {
47261
+ return;
47262
+ }
47263
+ const signalTs = Number(signal.ts);
47264
+ if (!signalTs || signalTs <= lastHandledReconnectSignalTs) {
47265
+ return;
47266
+ }
47267
+ lastHandledReconnectSignalTs = signalTs;
47268
+ console.warn("[MQTT_HANDOFF] 收到 MQTT 恢复信号,等待确认目标页是否真的关闭", {
47269
+ sourceTabId: signal.sourceTabId,
47270
+ targetTabId: signal.targetTabId,
47271
+ handoffId: signal.handoffId,
47272
+ signalTs
47273
+ });
47274
+ window.setTimeout(() => {
47275
+ if (!shouldReconnectForSignal(signal)) {
47276
+ console.info("[MQTT_HANDOFF] 忽略 MQTT 恢复,本次更像是目标页刷新/重载", {
47277
+ sourceTabId: signal.sourceTabId,
47278
+ targetTabId: signal.targetTabId,
47279
+ handoffId: signal.handoffId
47280
+ });
47281
+ return;
47282
+ }
47283
+ console.warn("[MQTT_HANDOFF] 确认目标页已关闭,准备恢复来源页 MQTT", {
47284
+ sourceTabId: signal.sourceTabId,
47285
+ targetTabId: signal.targetTabId,
47286
+ handoffId: signal.handoffId
47287
+ });
47288
+ void onReconnectRequested();
47289
+ }, RECONNECT_CHECK_DELAY_MS);
47290
+ });
47291
+ window.addEventListener("beforeunload", (event) => {
47292
+ if (!shouldWarnBeforeUnload()) {
47293
+ return;
47294
+ }
47295
+ event.preventDefault();
47296
+ event.returnValue = "";
47297
+ });
47298
+ window.addEventListener("pagehide", (event) => {
47299
+ const context = getMeetingMqttHandoffContext();
47300
+ const shouldHandleTargetTabClose = !!context && getCurrentMeetingTabId() === context.targetTabId;
47301
+ if (shouldHandleTargetTabClose && context) {
47302
+ writeTargetTabStatus(TARGET_TAB_STATUS_CLOSED, context);
47303
+ sendMeetingLeaveOnClose();
47304
+ }
47305
+ stopTargetHeartbeat();
47306
+ if (event.persisted) {
47307
+ return;
47308
+ }
47309
+ notifySourceTabForReconnect();
47310
+ });
47311
+ }
47312
+ let authToken = null;
47313
+ async function restoreMeetingMqttConnection() {
47314
+ console.warn("[MQTT_RESTORE] 收到恢复请求,开始重连 MQTT");
47315
+ try {
47316
+ const wsMqttUrl = await getMeetingWsMqttUrl();
47317
+ await initializeMeetingMQTT({ mqttUrl: wsMqttUrl });
47318
+ installMeetingMessageHandlers();
47319
+ console.info("[MQTT_RESTORE] MQTT 恢复成功,消息监听已恢复");
47320
+ } catch (error) {
47321
+ console.error("[MQTT_RESTORE] MQTT 恢复失败", error);
47322
+ }
47323
+ }
47324
+ function clearSdkStorages() {
47325
+ if (typeof window === "undefined") return;
47326
+ try {
47327
+ sessionStorage.removeItem("JS_MEETING_INFO");
47328
+ sessionStorage.removeItem("JS_INCOMING_CALL_INFO");
47329
+ sessionStorage.removeItem("joinTime");
47330
+ sessionStorage.removeItem("JS_USER_ID");
47331
+ sessionStorage.removeItem("JS_USER_NAME");
47332
+ localStorage.removeItem("device_id");
47324
47333
  } catch {
47325
47334
  }
47326
47335
  }
@@ -47430,9 +47439,8 @@ const JSSZMeeting = {
47430
47439
  }
47431
47440
  }
47432
47441
  }
47433
- await initializeMeetingMQTT({
47434
- myInfo: myInfo.data
47435
- });
47442
+ const wsMqttUrl = await getMeetingWsMqttUrl();
47443
+ await initializeMeetingMQTT({ myInfo: myInfo.data, mqttUrl: wsMqttUrl });
47436
47444
  installMeetingMessageHandlers();
47437
47445
  },
47438
47446
  //宿主退出登陆时