浏览代码

移植通话功能

rolyat 2 月之前
父节点
当前提交
4941c3306a

+ 10 - 12
config/dev.env.ts

@@ -1,13 +1,11 @@
+const serveIp = "20.189.74.163";
+
 export default {
-	NODE_ENV: 'development',
-	CHAT_URL: 'https://openimadmin.app12345.cn/chat',
-	API_URL: 'https://openimadmin.app12345.cn/api',
-	WS_URL: 'wss://openimadmin.app12345.cn/msg_gateway',
-	//CHAT_URL: "http://120.77.93.35:10008",
-	//API_URL: "http://120.77.93.35:10002",
-	//WS_URL: "ws://120.77.93.35:10001",
-	OBJECT_STORAGE: 'minio',
-	AMAP_KEY: '36e6a7bb847411f06258d03b066ecc67',//jsapi
-	AMAP_SNAP_KEY: '39b41b2a48453d7e66007c6f45d26a12',
-	VERSION: 'HI.CHAT 1.0.50',
-}
+  NODE_ENV: "development",
+  CHAT_URL: `http://${serveIp}:10008`,
+  API_URL: `http://${serveIp}:10002`,
+  WS_URL: `ws://${serveIp}:10001`,
+  AMAP_KEY: "key",
+  AMAP_SNAP_KEY: "key",
+  VERSION: "OpenCorp-H5-Demo",
+};

+ 16 - 0
src/api/im.ts

@@ -0,0 +1,16 @@
+import request from "@utils/request";
+import { getChatToken } from "@/utils/storage";
+
+export const getRtcConnectData = (room: string, identity: string) =>
+  request.post<{ serverUrl: string; token: string }>(
+    "/user/rtc/get_token",
+    JSON.stringify({
+      room,
+      identity,
+    }),
+    {
+      headers: {
+        token: getChatToken(),
+      },
+    }
+  );

+ 8 - 0
src/constants/enum.ts

@@ -1,5 +1,13 @@
 import { MessageType, SessionType } from 'open-im-sdk-wasm'
 
+export enum CustomType {
+  CallingInvite = 200,
+  CallingAccept = 201,
+  CallingReject = 202,
+  CallingCancel = 203,
+  CallingHungup = 204,
+}
+
 export const CustomMessageType = {
   Call: 100,
   MassMsg: 903,

+ 2 - 1
src/hooks/useInviteRtc.ts

@@ -19,7 +19,8 @@ export const useInviteRtc = () => {
         inviterUserID: userStore.selfInfo.userID,
         inviteeUserIDList: userIDList,
         groupID,
-        roomID: uuidV4(),
+        // roomID: uuidV4(),
+        roomID: `room-${userStore.selfInfo.userID}`,
         timeout: 60,
         mediaType,
         sessionType: isGroup ? SessionType.WorkingGroup : SessionType.Single,

+ 53 - 31
src/layout/CommonModal.vue

@@ -3,47 +3,69 @@
 </template>
 
 <script setup lang="ts">
-import { InviteData, ParticipantInfo } from '@/pages/rtc/data'
-import rtcModal from '@/pages/rtc/index.vue'
-import emitter from '@/utils/events'
-import { IMSDK } from '@/utils/imCommon'
-import { CbEvents } from 'open-im-sdk-wasm'
+import { getBusinessInfo } from "@/api/user";
+import { CustomType } from "@/constants/enum";
+import { InviteData, ParticipantInfo } from "@/pages/rtc/data";
+import rtcModal from "@/pages/rtc/index.vue";
+import emitter from "@/utils/events";
+import { IMSDK } from "@/utils/imCommon";
+import { CbEvents, MessageType } from 'open-im-sdk-wasm'
 import type { RtcInvite, WSEvent } from 'open-im-sdk-wasm/lib/types/entity'
 
-const showRtcModal = ref(false)
-const inviteData = reactive<InviteData>({})
-
-const recvInvitationHandler = ({
-  data,
-}: WSEvent<{ participant: ParticipantInfo; invitation: RtcInvite }>) => {
-  inviteData.invitation = data.invitation
-  inviteData.participant = data.participant
-  showRtcModal.value = true
-}
+const showRtcModal = ref(false);
+const inviteData = reactive<InviteData>({});
 
 const openRtcModalHandler = (data: InviteData) => {
-  if (showRtcModal.value) return
-  inviteData.invitation = data.invitation
-  inviteData.participant = data.participant
-  inviteData.isJoin = data.isJoin
-  showRtcModal.value = true
-}
+  if (showRtcModal.value) return;
+  inviteData.invitation = data.invitation;
+  inviteData.participant = data.participant;
+  inviteData.isJoin = data.isJoin;
+  showRtcModal.value = true;
+};
 
 const closeRtcModalHandler = () => {
-  showRtcModal.value = false
-}
+  showRtcModal.value = false;
+};
+
+const newMessageHandler = ({ data }: WSEvent<MessageItem[]>) => {
+  if (showRtcModal.value) return;
+  let rtcInvite = undefined as undefined | RtcInvite;
+  data.map((message) => {
+    if (message.contentType === MessageType.CustomMessage) {
+      const customData = JSON.parse(message.customElem!.data);
+      if (customData.customType === CustomType.CallingInvite) {
+        rtcInvite = customData.data;
+      }
+    }
+  });
+  if (rtcInvite) {
+    getBusinessInfo(rtcInvite.inviterUserID).then(({ data: { users } }) => {
+      if (users.length === 0) return;
+      inviteData.invitation = rtcInvite;
+      inviteData.participant = {
+        userInfo: {
+          nickname: users[0].nickname,
+          faceURL: users[0].faceURL,
+          userID: users[0].userID,
+          ex: "",
+        },
+      };
+      showRtcModal.value = true;
+    });
+  }
+};
 
 onMounted(() => {
-  IMSDK.on(CbEvents.OnReceiveNewInvitation, recvInvitationHandler)
-  emitter.on('OPEN_RTC_MODAL', openRtcModalHandler)
-  emitter.on('CLOSE_RTC_MODAL', closeRtcModalHandler)
-})
+  IMSDK.on(CbEvents.OnRecvNewMessages, newMessageHandler);
+  emitter.on("OPEN_RTC_MODAL", openRtcModalHandler);
+  emitter.on("CLOSE_RTC_MODAL", closeRtcModalHandler);
+});
 
 onUnmounted(() => {
-  IMSDK.off(CbEvents.OnReceiveNewInvitation, recvInvitationHandler)
-  emitter.off('OPEN_RTC_MODAL', openRtcModalHandler)
-  emitter.off('CLOSE_RTC_MODAL', closeRtcModalHandler)
-})
+  IMSDK.off(CbEvents.OnRecvNewMessages, newMessageHandler);
+  emitter.off("OPEN_RTC_MODAL", openRtcModalHandler);
+  emitter.off("CLOSE_RTC_MODAL", closeRtcModalHandler);
+});
 </script>
 
 <style lang="scss" scoped></style>

+ 153 - 283
src/pages/conversation/chat/components/ChatContent.vue

@@ -1,290 +1,160 @@
 <template>
-	<div class="relative flex-1 overflow-hidden">
-		<div v-if="!callingData && showGroupAnnouncement" class="group_announcement_tab" @click="toGroupAnnouncement">
-			<div class="flex w-full flex-row items-center justify-between">
-				<div class="flex flex-row">
-					<img :src="announce" width="24" alt="announce" />
-					<span class="ml-2 text-primary">{{ $t('popover.groupAnnouncement') }}</span>
-				</div>
-				<div @click.stop="resetGroupAnnouncement">
-					<img :src="announce_close" width="16" alt="announce_close" />
-				</div>
-			</div>
-			<div class="mt-2 px-1">
-				{{ conversationStore.storeCurrentGroupInfo.notification }}
-			</div>
-		</div>
-		<div class="group_rtc_tab" v-if="callingData">
-			<div class="flex w-full flex-row items-center justify-between">
-				<div class="flex w-[260px] flex-row">
-					<span class="truncate text-sm text-[#8E9AB0]">
-						{{
-              callingData?.invitation?.mediaType === 'video'
-                ? $t('rtc.groupInVideoCall', { num: callingData?.participant?.length })
-                : $t('rtc.groupInVoiceCall', { num: callingData?.participant?.length })
-            }}
-					</span>
-				</div>
-				<div @click.stop="showMoreMember = !showMoreMember">
-					<img :src="arrow" :class="{ 'rotate-180': !showMoreMember }" width="16" alt="arrow" />
-				</div>
-			</div>
-
-			<template v-if="showMoreMember">
-				<div class="mt-3 flex w-full flex-row justify-start px-1">
-					<div class="flex w-1/6 justify-center" v-for="item in callingData!.participant!.slice(0, 5)"
-						:key="item.userInfo.userID">
-						<Avatar :size="44" :src="item!.groupMemberInfo!.faceURL"
-							:desc="item!.groupMemberInfo!.nickname" />
-					</div>
-					<div class="flex w-1/6 justify-center" v-if="callingData!.participant!.length > 5">
-						<img :src="more" class="h-11 w-11" alt="more" />
-					</div>
-				</div>
-				<div class="mt-2 w-full text-center text-[#02C25F]" @click="joinRtc">
-					{{ $t('rtc.joinCall') }}
-				</div>
-			</template>
-		</div>
-		<virtual-list :class="{ '!flex-col': overflow }" ref="vsl" class="my_scrollbar h-full overflow-y-auto"
-			:data-key="'clientMsgID'" :data-sources="messageStore.storeHistoryMessageList" :topThreshold="120"
-			:keeps="50" :data-component="
-        (message: MessageItem) =>
-          checkIsNotification(message) ? SystemNotificationItem : MessageItemVue
-      " :extra-props="{
-        showCheck: multipleCheckVisible,
-      }" :estimate-size="80" @totop="onTotop" @resized="onItemRendered" @scroll="onScoll">
-			<template #header>
-				<div v-if="overflow && !initLoading" class="pt-2">
-					<div class="spinner" v-show="loadState.loading"></div>
-					<div class="finished" v-show="!messageStore.storeHistoryMessageHasMore">
-						{{ $t('noMore') }}
-					</div>
-				</div>
-			</template>
-		</virtual-list>
-		<div v-show="unReadCount && notScroll"
-			class="absolute bottom-5 left-1/2 flex -translate-x-1/2 items-center rounded-xl bg-white py-2 px-3 shadow-md"
-			@click="scrollToUnread">
-			<img width="17" :src="arrow_icon" alt="" />
-			<span class="ml-2 text-xs text-[#02C25F]">{{
-        $t('someNewMessage', { count: unReadCount })
-      }}</span>
-		</div>
-		<div v-show="initLoading" class="!absolute top-0 flex h-full w-full items-center justify-center bg-white">
-			<van-loading type="spinner" />
-		</div>
-	</div>
+  <div class="flex-1 overflow-hidden relative">
+    <virtual-list :class="{ '!flex-col': overflow }" ref="vsl" class="my_scrollbar h-full overflow-y-auto"
+      :data-key="'clientMsgID'" :data-sources="messageStore.storeHistoryMessageList" :topThreshold="120" :keeps="50"
+      :data-component="(message: MessageItem) => checkIsNotification(message) ? SystemNotificationItem : MessageItemVue"
+      :extra-props="{}" :estimate-size="80" @totop="onTotop" @resized="onItemRendered" @scroll="onScoll">
+      <template #header>
+        <div v-if="overflow && !initLoading" class="pt-2">
+          <div class="spinner" v-show="loadState.loading"></div>
+          <div class="finished" v-show="!messageStore.storeHistoryMessageHasMore">
+            {{ $t("noMore") }}
+          </div>
+        </div>
+      </template>
+    </virtual-list>
+    <div v-show="unReadCount && notScroll"
+      class="flex items-center py-2 px-3 rounded-xl shadow-md absolute bottom-5 left-1/2 -translate-x-1/2 bg-white"
+      @click="scrollToUnread">
+      <img width="17" :src="arrow_icon" alt="">
+      <span class="text-xs text-[#0089FF] ml-2">{{ $t('someNewMessage', { count: unReadCount }) }}</span>
+    </div>
+    <div v-show="initLoading" class="!absolute top-0 h-full w-full flex justify-center items-center bg-white">
+      <van-loading type="spinner" />
+    </div>
+  </div>
 </template>
 
-<script setup lang="ts">
-	import announce from '@/assets/images/messageItem/announce.png'
-	import announce_close from '@/assets/images/messageItem/announce_close.png'
-	import arrow from '@/assets/images/rtc/group_tab_arrow.png'
-	import more from '@/assets/images/rtc/group_tab_more.png'
-	import { TipTypes } from '@/constants/enum'
-	import Avatar from '@/components/Avatar/index.vue'
-	import useMessageStore from '@/store/modules/message'
-	import VirtualList from '@components/VirtualList'
-	import type { MessageItem } from 'open-im-sdk-wasm/lib/types/entity'
-	import useHistoryMessageList from '../useHistoryMessageList'
-	import { useMessageReceipt } from '../useMessageReceipt'
-	import MessageItemVue from './MessageItem/MessageItem.vue'
-	import SystemNotificationItem from './SystemNotificationItem.vue'
-	import { GroupAtType, MessageType } from 'open-im-sdk-wasm'
-	import arrow_icon from '@assets/images/conversation/arrow.png'
-	import useConversationStore from '@/store/modules/conversation'
-	import { IMSDK } from '@/utils/imCommon'
-	import useCurrentMemberRole from '@/hooks/useCurrentMemberRole'
-	import { CallingRoomData } from '@/pages/rtc/data'
-	import emitter from '@/utils/events'
-
-	type ChatContentProps = {
-		multipleCheckVisible : boolean
-	}
-
-	const emit = defineEmits([])
-	const props = defineProps<ChatContentProps>()
-
-	const router = useRouter()
-	const messageStore = useMessageStore()
-	const conversationStore = useConversationStore()
-	const { isNomal } = useCurrentMemberRole()
-
-	const showMoreMember = ref(false)
-
-	const cancelMultiple = () => { }
-
-	useMessageReceipt()
-	const historyMessageState = useHistoryMessageList({ cancelMultiple })
-	const { onItemRendered, onTotop, onScoll, scrollToUnread } = historyMessageState
-	const vsl = toRef(historyMessageState, 'vsl')
-	const overflow = toRef(historyMessageState, 'overflow')
-	const loadState = toRef(historyMessageState, 'loadState')
-	const notScroll = toRef(historyMessageState, 'notScroll')
-	const unReadCount = toRef(historyMessageState, 'unReadCount')
-	const initLoading = toRef(historyMessageState, 'initLoading')
-
-	const showGroupAnnouncement = computed(
-		() =>
-			conversationStore.storeCurrentConversation.groupAtType ===
-			GroupAtType.AtGroupNotice,
-	)
-
-	const resetGroupAnnouncement = () => {
-		IMSDK.resetConversationGroupAtType(
-			conversationStore.storeCurrentConversation.conversationID,
-		)
-	}
-
-	const toGroupAnnouncement = () => {
-		resetGroupAnnouncement()
-		router.push({
-			path: 'groupAnnouncement',
-			query: {
-				isNomal: isNomal.value + '',
-			},
-		})
-	}
-
-	const checkIsNotification = computed(() => (message : MessageItem) => {
-		if (message.contentType === MessageType.GroupInfoUpdated) {
-			let detail
-			try {
-				detail = JSON.parse(message.notificationElem?.detail)
-			} catch (e) { }
-			return detail?.group?.notification === undefined
-		}
-		return TipTypes.includes(message.contentType)
-	})
-
-	const timer = ref<NodeJS.Timer | null>(null)
-	const callingData = ref<CallingRoomData | null>(null)
-	const nativeCallEndHandler = async () => {
-		const { data } = await IMSDK.signalingGetRoomByGroupID<CallingRoomData>(
-			conversationStore.currentConversation.groupID,
-		)
-		if (data.invitation) {
-			callingData.value = data
-		} else {
-			callingData.value = null
-		}
-	}
+<script setup lang='ts'>
+import { TipTypes } from '@/constants/enum';
+import useMessageStore from '@/store/modules/message';
+import VirtualList from '@components/VirtualList';
+import { useMessageReceipt } from '../useMessageReceipt'
+import type { MessageItem } from 'open-im-sdk-wasm/lib/types/entity';
+import useHistoryMessageList from '../useHistoryMessageList';
+import MessageItemVue from './MessageItem/MessageItem.vue';
+import SystemNotificationItem from './SystemNotificationItem.vue';
+import { MessageType } from 'open-im-sdk-wasm';
+import arrow_icon from '@assets/images/conversation/arrow.png'
+
+
+const emit = defineEmits([]);
+defineProps();
+
+useMessageReceipt()
+const messageStore = useMessageStore();
+
+const cancelMultiple = () => { }
+
+const historyMessageState = useHistoryMessageList({ cancelMultiple });
+const {
+  onItemRendered,
+  onTotop,
+  onScoll,
+  scrollToUnread
+} = historyMessageState;
+const vsl = toRef(historyMessageState, "vsl");
+const overflow = toRef(historyMessageState, "overflow");
+const loadState = toRef(historyMessageState, "loadState");
+const notScroll = toRef(historyMessageState, "notScroll");
+const unReadCount = toRef(historyMessageState, "unReadCount");
+const initLoading = toRef(
+  historyMessageState,
+  "initLoading"
+);
+
+const checkIsNotification = computed(() => (message: MessageItem) => {
+  if (message.contentType === MessageType.GroupInfoUpdated) {
+    let detail
+    try {
+      detail = JSON.parse(message.notificationElem?.detail!)
+    } catch (e) {
+    }
+    return detail?.group?.notification === undefined
+  }
+  return TipTypes.includes(message.contentType)
+})
 
-	const joinRtc = () => {
-		emitter.emit('OPEN_RTC_MODAL', {
-			invitation: callingData!.value!.invitation,
-			participant: callingData!.value!.participant?.[0],
-			isJoin: true,
-		})
-	}
-
-	onActivated(() => {
-		if (!conversationStore.currentConversation.groupID) return
-		nativeCallEndHandler()
-		timer.value = setInterval(nativeCallEndHandler, 3000)
-	})
-
-	onDeactivated(() => {
-		if (timer.value) {
-			clearInterval(timer.value)
-		}
-	})
 </script>
 
-<style lang="scss" scoped>
-	.finished {
-		font-size: 14px;
-		text-align: center;
-		color: #bfbfbf;
-	}
-
-	.spinner {
-		font-size: 10px;
-		margin: 0px auto;
-		text-indent: -9999em;
-		width: 15px;
-		height: 15px;
-		border-radius: 50%;
-		background: #ffffff;
-		background: linear-gradient(to right, #ccc 10%, rgba(255, 255, 255, 0) 42%);
-		position: relative;
-		animation: load3 1.4s infinite linear;
-		transform: translateZ(0);
-	}
-
-	.spinner:before {
-		width: 50%;
-		height: 50%;
-		background: #ccc;
-		border-radius: 100% 0 0 0;
-		position: absolute;
-		top: 0;
-		left: 0;
-		content: '';
-	}
-
-	.spinner:after {
-		background: #ffffff;
-		width: 75%;
-		height: 75%;
-		border-radius: 50%;
-		content: '';
-		margin: auto;
-		position: absolute;
-		top: 0;
-		left: 0;
-		bottom: 0;
-		right: 0;
-	}
-
-	@-webkit-keyframes load3 {
-		0% {
-			transform: rotate(0deg);
-		}
-
-		100% {
-			transform: rotate(360deg);
-		}
-	}
-
-	@keyframes load3 {
-		0% {
-			transform: rotate(0deg);
-		}
-
-		100% {
-			transform: rotate(360deg);
-		}
-	}
-
-	.group_announcement_tab {
-		display: flex;
-		position: absolute;
-		top: 6px;
-		z-index: 10;
-		flex-direction: column;
-		align-items: flex-start;
-		width: 90%;
-		left: 50%;
-		transform: translateX(-50%);
-		background-color: #f2f8ff;
-		padding: 8px 12px;
-		border-radius: 6px;
-	}
-
-	.group_rtc_tab {
-		display: flex;
-		position: absolute;
-		top: 6px;
-		z-index: 11;
-		flex-direction: column;
-		align-items: flex-start;
-		width: 90%;
-		left: 50%;
-		transform: translateX(-50%);
-		background-color: #f2f8ff;
-		padding: 8px 12px;
-		border-radius: 6px;
-	}
+<style lang='scss' scoped>
+.finished {
+  font-size: 14px;
+  text-align: center;
+  color: #bfbfbf;
+}
+
+.spinner {
+  font-size: 10px;
+  margin: 0px auto;
+  text-indent: -9999em;
+  width: 15px;
+  height: 15px;
+  border-radius: 50%;
+  background: #ffffff;
+  background: linear-gradient(to right, #ccc 10%, rgba(255, 255, 255, 0) 42%);
+  position: relative;
+  animation: load3 1.4s infinite linear;
+  transform: translateZ(0);
+}
+
+.spinner:before {
+  width: 50%;
+  height: 50%;
+  background: #ccc;
+  border-radius: 100% 0 0 0;
+  position: absolute;
+  top: 0;
+  left: 0;
+  content: '';
+}
+
+.spinner:after {
+  background: #ffffff;
+  width: 75%;
+  height: 75%;
+  border-radius: 50%;
+  content: '';
+  margin: auto;
+  position: absolute;
+  top: 0;
+  left: 0;
+  bottom: 0;
+  right: 0;
+}
+
+@-webkit-keyframes load3 {
+  0% {
+    transform: rotate(0deg);
+  }
+
+  100% {
+    transform: rotate(360deg);
+  }
+}
+
+@keyframes load3 {
+  0% {
+    transform: rotate(0deg);
+  }
+
+  100% {
+    transform: rotate(360deg);
+  }
+}
+
+.group_announcement_tab {
+  display: flex;
+  position: absolute;
+  top: 6px;
+  z-index: 10;
+  flex-direction: column;
+  align-items: flex-start;
+  width: 90%;
+  left: 50%;
+  transform: translateX(-50%);
+  background-color: #F2F8FF;
+  padding: 8px 12px;
+  border-radius: 6px;
+}
 </style>

+ 1 - 0
src/pages/conversation/chat/components/ChatFooter/ChatFooterAction.vue

@@ -167,6 +167,7 @@
 			actionSheetVisible.value = false
 			if (isSingle.value) {
 				const rtcType = type === ChatFooterActionType.VoiceCall ? RtcType.VoiceCall : RtcType.VideoCall
+				console.log('rtcType', rtcType)
 				inviteRtc(rtcType, '', [conversationStore.currentConversation.userID])
 			} else {
 				router.push({

+ 11 - 2
src/pages/conversation/chat/components/MessageItem/CatchMsgRenderer.vue

@@ -1,7 +1,16 @@
 <template>
-  <div class="need_bg">{{ $t('messageDescription.notSupMessage') }}</div>
+  <div v-if="message.contentType === 110" class="need_bg">[通话结束]</div>
+  <div v-else class="need_bg">{{ $t('messageDescription.notSupMessage') }}</div>
 </template>
 
-<script setup lang="ts"></script>
+<script setup lang="ts">
+	import { ExedMessageItem } from './data'
+		type CustomMessageSwitcherProps = {
+		message : ExedMessageItem
+		disabled : boolean
+		isSelfMsg : boolean
+	}
+	const props = defineProps<CustomMessageSwitcherProps>()
+</script>
 
 <style lang="scss" scoped></style>

+ 11 - 4
src/pages/conversation/chat/components/MessageItem/CustomMessageSwitcherer.vue

@@ -6,7 +6,7 @@
 	import RtcMessageRenderer from './RtcMessageRenderer.vue'
 	import CatchMsgRenderer from './CatchMsgRenderer.vue'
 	import { ExedMessageItem } from './data'
-	import { CustomMessageType } from '@/constants/enum'
+	import { CustomMessageType, CustomType } from '@/constants/enum'
 
 	type CustomMessageSwitcherProps = {
 		message : ExedMessageItem
@@ -15,10 +15,17 @@
 	}
 	const props = defineProps<CustomMessageSwitcherProps>()
 
-	const customData = JSON.parse(props.message.customElem.data)
-
+	const customData = ref(JSON.parse(props.message.customElem.data))
+	console.log('3. props.message', props.message)
 	const getRenderComp = computed(() => {
-		switch (customData.customType) {
+		// return [ 
+		// 	CustomType.CallingInvite,
+		// 	CustomType.CallingAccept,
+		// 	CustomType.CallingReject,
+		// 	CustomType.CallingCancel,
+		// 	CustomType.CallingHungup
+		// ].includes(customData.customType) ? '' : CatchMsgRenderer
+		switch (customData.value.customType) {
 			case CustomMessageType.Call:
 				return RtcMessageRenderer
 			default:

+ 1 - 0
src/pages/conversation/chat/components/MessageItem/MessageItem.vue

@@ -125,6 +125,7 @@
 	})
 
 	const getRenderComp = computed(() => {
+		console.log('props.source.contentType',props.source.contentType)
 		switch (props.source.contentType) {
 			case MessageType.TextMessage:
 			case MessageType.AtTextMessage:

+ 163 - 290
src/pages/rtc/RtcControl/index.vue

@@ -1,294 +1,167 @@
 <template>
-	<Connected v-if="showConnected" :room="room" @disconnect="disconnect" />
-
-	<div v-if="showAccept" class="mb-[64px] flex flex-row justify-around px-2">
-		<div class="flex flex-col items-center" @click.stop="disconnect">
-			<img class="h-[62px] w-[62px]" :src="hungup" alt="hungup" />
-			<span class="mt-2 text-sm text-white">{{ $t('rtc.hungup') }}</span>
-		</div>
-		<div class="flex flex-col items-center" @click.stop="acceptInvitation">
-			<img class="h-[62px] w-[62px]" :src="accept" alt="accept" />
-			<span class="mt-2 text-sm text-white">{{ $t('rtc.accept') }}</span>
-		</div>
-	</div>
+  <Connected v-if="showConnected" :room="room" @disconnect="disconnect" />
+
+  <div v-if="showAccept" class="mb-[64px] flex flex-row justify-around px-2">
+    <div class="flex flex-col items-center" @click.stop="disconnect">
+      <img class="h-[62px] w-[62px]" :src="hungup" alt="hungup" />
+      <span class="mt-2 text-sm text-white">{{ $t("rtc.hungup") }}</span>
+    </div>
+    <div class="flex flex-col items-center" @click.stop="acceptInvitation">
+      <img class="h-[62px] w-[62px]" :src="accept" alt="accept" />
+      <span class="mt-2 text-sm text-white">{{ $t("rtc.accept") }}</span>
+    </div>
+  </div>
 </template>
 
 <script lang="ts" setup>
-	import hungup from '@/assets/images/rtc/hungup.png'
-	import accept from '@/assets/images/rtc/accept.png'
-	import type { RtcInvite, WSEvent } from 'open-im-sdk-wasm/lib/types/entity'
-	import { AuthData, InviteData, RtcInviteResults } from '../data'
-	import { IMSDK } from '@/utils/imCommon'
-	import useUserStore from '@/store/modules/user'
-	import { SessionType, CbEvents } from 'open-im-sdk-wasm'
-	import { CustomMessageType, RtcMessageStatus } from '@/constants/enum'
-	import useMessageStore, { ExMessageItem } from '@/store/modules/message'
-	import useConversationStore from '@/store/modules/conversation'
-	import emitter from '@/utils/events'
-	import { RemoteParticipant, Room, RoomEvent } from 'livekit-client'
-	import Connected from './Connected.vue'
-	import { getBusinessInfo } from '@/api/user'
-
-	type IRtcControlEmits = {
-		(event : 'connectRtc', data ?: AuthData) : void
-		(event : 'closeOverlay') : void
-	}
-	type IRtcControlProps = {
-		room : Room
-		isWaiting : boolean
-		isConnected : boolean
-		duration : string
-		invitation : RtcInvite
-		inviteData : InviteData
-	}
-	const emit = defineEmits<IRtcControlEmits>()
-	const props = defineProps<IRtcControlProps>()
-
-	const hasJoin = ref(false)
-	const isAccept = ref(false)
-	const isSingle = computed(() => props.invitation.sessionType === SessionType.Single)
-	const isRecv = computed(
-		() => userStore.selfInfo.userID !== props.invitation?.inviterUserID,
-	)
-	const showAccept = computed(() => {
-		if (props.inviteData.isJoin) {
-			return false
-		}
-		if (!isRecv.value) {
-			return false
-		}
-		return !props.isConnected
-	})
-	const showConnected = computed(() => props.isConnected || !isRecv.value)
-
-	const userStore = useUserStore()
-	const messageStore = useMessageStore()
-	const conversationStore = useConversationStore()
-
-	const insertRtcMessage = async (status : RtcMessageStatus) => {
-		if (props.invitation.sessionType !== SessionType.Single) return
-		const message = (
-			await IMSDK.createCustomMessage({
-				data: JSON.stringify({
-					customType: CustomMessageType.Call,
-					data: {
-						duration: props.duration,
-						mediaType: props.invitation.mediaType,
-						status,
-					},
-				}),
-				extension: '',
-				description: '',
-			})
-		).data
-		if (!message) return
-
-		const fullMessage = (
-			await IMSDK.insertSingleMessageToLocalStorage<ExMessageItem>({
-				recvID: props.invitation.inviteeUserIDList[0],
-				sendID: props.invitation.inviterUserID,
-				message,
-			})
-		).data
-
-		const userInfo = {
-			id: '',
-			name: '',
-			faceUrl: '',
-		}
-
-		const getUserInfo = async () => {
-			if (props.invitation.inviterUserID === userStore.selfInfo.userID) {
-				const res = await getBusinessInfo(props.invitation.inviteeUserIDList[0])
-				const businessData = res.data.users[0] ?? {}
-				userInfo.id = props.invitation.inviteeUserIDList[0]
-				userInfo.name = businessData.nickname
-				userInfo.faceUrl = businessData.faceURL
-			} else {
-				const res = await getBusinessInfo(props.invitation.inviterUserID)
-				const businessData = res.data.users[0] ?? {}
-				userInfo.id = props.invitation.inviterUserID
-				userInfo.name = businessData.nickname
-				userInfo.faceUrl = businessData.faceURL
-			}
-		}
-		await getUserInfo()
-
-		insertRtcMessageToLocalStorage({ ...fullMessage, status, userInfo })
-
-		const conversation = conversationStore.currentConversation
-		if (
-			props.invitation.inviterUserID === conversation?.userID ||
-			props.invitation.inviteeUserIDList[0] === conversation?.userID
-		) {
-			messageStore.pushNewMessage(fullMessage)
-		}
-	}
-
-	const insertRtcMessageToLocalStorage = (fullMessage : any) => {
-		let historyList = []
-		try {
-			const storedHistory = localStorage.getItem(
-				`${userStore.selfInfo.userID}_rtc_historyList`,
-			)
-			if (storedHistory) {
-				historyList = JSON.parse(storedHistory)
-			}
-		} catch (e) { }
-		historyList.push({
-			...fullMessage,
-			time: new Date().getTime(),
-		})
-		localStorage.setItem(
-			`${userStore.selfInfo.userID}_rtc_historyList`,
-			JSON.stringify(historyList),
-		)
-	}
-
-	const acceptInvitation = () => {
-		if (isAccept.value) return
-		isAccept.value = true
-		IMSDK.signalingAccept<RtcInviteResults>({
-			opUserID: userStore.selfInfo.userID,
-			invitation: props.invitation,
-		})
-			.then(({ data }) => {
-				emit('connectRtc', {
-					liveURL: data.liveURL,
-					token: data.token,
-				})
-			})
-			.catch((error) => console.log(error))
-	}
-
-	const disconnect = () => {
-		const data = {
-			opUserID: userStore.selfInfo.userID,
-			invitation: props.invitation,
-		}
-		if (props.isWaiting) {
-			const funcName = isRecv.value ? 'signalingReject' : 'signalingCancel'
-			IMSDK[funcName](data)
-			insertRtcMessage(
-				isRecv.value ? RtcMessageStatus.Refused : RtcMessageStatus.Canceled,
-			)
-			emitter.emit('CLOSE_RTC_MODAL')
-			return
-		}
-		IMSDK.signalingHungUp(data)
-		insertRtcMessage(RtcMessageStatus.Successed)
-		props.room.disconnect()
-		emitter.emit('CLOSE_RTC_MODAL')
-	}
-
-	const acceptHandler = ({
-		data: {
-			invitation: { roomID },
-		},
-	} : WSEvent<{ invitation : RtcInvite }>) => {
-		if (props.invitation.roomID !== roomID) return
-
-		if (isSingle.value) {
-			emit('connectRtc', undefined)
-		} else {
-			hasJoin.value = true
-		}
-	}
-
-	const rejectHandler = ({
-		data: {
-			invitation: { roomID },
-		},
-	} : WSEvent<{ invitation : RtcInvite }>) => {
-		if (props.invitation.roomID !== roomID || !isSingle.value) return
-		insertRtcMessage(RtcMessageStatus.Refused)
-		emitter.emit('CLOSE_RTC_MODAL')
-	}
-
-	const hangupHandler = ({
-		data: {
-			invitation: { roomID },
-		},
-	} : WSEvent<{ invitation : RtcInvite }>) => {
-		if ((!isSingle.value && !props.isWaiting) || props.invitation.roomID !== roomID)
-			return
-		insertRtcMessage(RtcMessageStatus.Successed)
-		props.room.disconnect()
-		emitter.emit('CLOSE_RTC_MODAL')
-	}
-
-	const cancelHandler = ({
-		data: {
-			invitation: { roomID },
-		},
-	} : WSEvent<{ invitation : RtcInvite }>) => {
-		if (props.invitation.roomID !== roomID) return
-		if (!isSingle.value && !props.isWaiting) return
-		insertRtcMessage(RtcMessageStatus.Canceled)
-		emitter.emit('CLOSE_RTC_MODAL')
-	}
-
-	const timeoutHandler = ({
-		data: {
-			invitation: { roomID },
-		},
-	} : WSEvent<{ invitation : RtcInvite }>) => {
-		if (props.invitation.roomID !== roomID) return
-
-		if (isSingle.value || !hasJoin.value) {
-			insertRtcMessage(RtcMessageStatus.Timeout)
-			IMSDK.signalingCancel({
-				opUserID: userStore.selfInfo.userID,
-				invitation: props.invitation,
-			})
-			if (!isSingle.value) props.room.disconnect()
-			emitter.emit('CLOSE_RTC_MODAL')
-		}
-	}
-
-	const handleByOtherDevice = ({
-		data: {
-			invitation: { roomID },
-		},
-	} : WSEvent<{ invitation : RtcInvite }>) => {
-		if (props.invitation.roomID !== roomID) return
-		insertRtcMessage(RtcMessageStatus.HandleByOtherDevice)
-		emitter.emit('CLOSE_RTC_MODAL')
-	}
-
-	const participantDisconnectedHandler = (remoteParticipant : RemoteParticipant) => {
-		if (!isSingle.value) return
-
-		const identity = remoteParticipant.identity
-		if (
-			identity === props.invitation.inviterUserID ||
-			identity === props.invitation.inviteeUserIDList[0]
-		) {
-			insertRtcMessage(RtcMessageStatus.Successed)
-			props.room.disconnect()
-			emitter.emit('CLOSE_RTC_MODAL')
-		}
-	}
-
-	onMounted(() => {
-		IMSDK.on(CbEvents.OnInviteeAccepted, acceptHandler)
-		IMSDK.on(CbEvents.OnInviteeRejected, rejectHandler)
-		IMSDK.on(CbEvents.OnHangUp, hangupHandler)
-		IMSDK.on(CbEvents.OnInvitationCancelled, cancelHandler)
-		IMSDK.on(CbEvents.OnInvitationTimeout, timeoutHandler)
-		IMSDK.on(CbEvents.OnInviteeAcceptedByOtherDevice, handleByOtherDevice)
-		IMSDK.on(CbEvents.OnInviteeRejectedByOtherDevice, handleByOtherDevice)
-		props.room.on(RoomEvent.ParticipantDisconnected, participantDisconnectedHandler)
-	})
-
-	onUnmounted(() => {
-		IMSDK.off(CbEvents.OnInviteeAccepted, acceptHandler)
-		IMSDK.off(CbEvents.OnInviteeRejected, rejectHandler)
-		IMSDK.off(CbEvents.OnHangUp, hangupHandler)
-		IMSDK.off(CbEvents.OnInvitationCancelled, cancelHandler)
-		IMSDK.off(CbEvents.OnInvitationTimeout, timeoutHandler)
-		IMSDK.off(CbEvents.OnInviteeAcceptedByOtherDevice, handleByOtherDevice)
-		IMSDK.off(CbEvents.OnInviteeRejectedByOtherDevice, handleByOtherDevice)
-		props.room.off(RoomEvent.ParticipantDisconnected, participantDisconnectedHandler)
-	})
-</script>
+import hungup from "@/assets/images/rtc/hungup.png";
+import accept from "@/assets/images/rtc/accept.png";
+import type { RtcInvite, WSEvent } from 'open-im-sdk-wasm/lib/types/entity'
+import { AuthData, InviteData } from "../data";
+import { IMSDK } from "@/utils/imCommon";
+import useUserStore from "@/store/modules/user";
+import { SessionType, CbEvents, MessageType } from "open-im-sdk-wasm";
+import { CustomType } from "@/constants/enum";
+import { ExMessageItem } from "@/store/modules/message";
+import emitter from "@/utils/events";
+import { RemoteParticipant, Room, RoomEvent } from "livekit-client";
+import Connected from "./Connected.vue";
+import { getRtcConnectData } from "@/api/im";
+import { v4 as uuidV4 } from "uuid";
+
+type IRtcControlEmits = {
+  (event: "connectRtc", data?: AuthData): void;
+  (event: "closeOverlay"): void;
+};
+type IRtcControlProps = {
+  room: Room;
+  isWaiting: boolean;
+  isConnected: boolean;
+  duration: string;
+  invitation: RtcInvite;
+  inviteData: InviteData;
+  sendCustomSignal: (recvID: string, customType: CustomType) => Promise<void>;
+};
+const emit = defineEmits<IRtcControlEmits>();
+const props = defineProps<IRtcControlProps>();
+
+const userStore = useUserStore();
+
+const isRecv = computed(
+  () => userStore.selfInfo.userID !== props.invitation?.inviterUserID
+);
+const recvID = isRecv.value
+  ? props.invitation.inviterUserID
+  : props.invitation.inviteeUserIDList[0];
+const showAccept = computed(() => {
+  if (!isRecv.value) {
+    return false;
+  }
+  return !props.isConnected;
+});
+const showConnected = computed(() => props.isConnected || !isRecv.value);
+
+const acceptInvitation = async () => {
+  try {
+    await props.sendCustomSignal(recvID, CustomType.CallingAccept);
+    const { data } = await getRtcConnectData(
+      `room-${recvID}`, // 房间号
+      userStore.selfInfo.userID
+    );
+    emit("connectRtc", {
+      liveURL: data.serverUrl,
+      token: data.token,
+    });
+  } catch (error) {
+    console.log(error);
+    emitter.emit("CLOSE_RTC_MODAL");
+  }
+};
+
+const disconnect = () => {
+  if (props.isWaiting) {
+    const customType = isRecv
+      ? CustomType.CallingReject
+      : CustomType.CallingCancel;
+    props.sendCustomSignal(recvID, customType);
+    emitter.emit("CLOSE_RTC_MODAL");
+    return;
+  }
+  props.sendCustomSignal(recvID, CustomType.CallingHungup);
+  emitter.emit("CLOSE_RTC_MODAL");
+};
+
+const acceptHandler = async ({ roomID }: RtcInvite) => {
+  if (props.invitation.roomID !== roomID) return;
+  emit("connectRtc", undefined);
+};
+
+const rejectHandler = ({ roomID }: RtcInvite) => {
+  if (props.invitation.roomID !== roomID) return;
+  emitter.emit("CLOSE_RTC_MODAL");
+};
+
+const hangupHandler = ({ roomID }: RtcInvite) => {
+  if (props.invitation.roomID !== roomID) return;
+  props.room.disconnect();
+  emitter.emit("CLOSE_RTC_MODAL");
+};
+
+const cancelHandler = ({ roomID }: RtcInvite) => {
+  if (props.invitation.roomID !== roomID) return;
+  if (!props.isWaiting) return;
+  emitter.emit("CLOSE_RTC_MODAL");
+};
+
+const participantDisconnectedHandler = (
+  remoteParticipant: RemoteParticipant
+) => {
+  const identity = remoteParticipant.identity;
+  if (
+    identity === props.invitation.inviterUserID ||
+    identity === props.invitation.inviteeUserIDList[0]
+  ) {
+    props.room.disconnect();
+    emitter.emit("CLOSE_RTC_MODAL");
+  }
+};
+
+const newMessageHandler = ({ data }: WSEvent<ExMessageItem[]>) => {
+  data.map((message) => {
+    if (message.contentType === MessageType.CustomMessage) {
+      const customData = JSON.parse(message.customElem!.data) as {
+        data: RtcInvite;
+        customType: CustomType;
+      };
+      if (customData.customType === CustomType.CallingAccept) {
+        acceptHandler(customData.data);
+      }
+      if (customData.customType === CustomType.CallingReject) {
+        rejectHandler(customData.data);
+      }
+      if (customData.customType === CustomType.CallingCancel) {
+        cancelHandler(customData.data);
+      }
+      if (customData.customType === CustomType.CallingHungup) {
+        hangupHandler(customData.data);
+      }
+    }
+  });
+};
+
+onMounted(() => {
+  IMSDK.on(CbEvents.OnRecvNewMessages, newMessageHandler);
+  props.room.on(
+    RoomEvent.ParticipantDisconnected,
+    participantDisconnectedHandler
+  );
+});
+
+onUnmounted(() => {
+  IMSDK.off(CbEvents.OnRecvNewMessages, newMessageHandler);
+  props.room.off(
+    RoomEvent.ParticipantDisconnected,
+    participantDisconnectedHandler
+  );
+});
+</script>

+ 5 - 1
src/pages/rtc/RtcLayout/index.vue

@@ -32,6 +32,7 @@
           :duration="duration"
           @connectRtc="connectRtc"
           :room="room"
+          :sendCustomSignal="sendCustomSignal"
         />
         <RtcRoom v-if="isConnected && !isGroup" :room="room" :isVideo="isVideo" />
       </template>
@@ -65,8 +66,10 @@ import RtcProfile from '../RtcProfile/index.vue'
 import { AuthData, InviteData } from '../data'
 import { useDraggable } from '@vueuse/core'
 import { Room } from 'livekit-client'
+import { CustomType } from '@/constants/enum'
 import useInviteData from '../useInviteData'
 import Camera from './Camera.vue'
+import emitter from "@utils/events";
 
 type IRtcLayoutEmits = {
   (event: 'connectRtc', data?: AuthData): void
@@ -75,7 +78,8 @@ type IRtcLayoutProps = {
   connect: boolean
   isConnected: boolean
   inviteData: InviteData
-  room: Room
+  room: Room,
+  sendCustomSignal: (recvID: string, customType: CustomType) => Promise<void>;
 }
 const emit = defineEmits<IRtcLayoutEmits>()
 const props = defineProps<IRtcLayoutProps>()

+ 126 - 94
src/pages/rtc/index.vue

@@ -1,107 +1,139 @@
 <template>
-	<RtcLayout :inviteData="inviteData" :authData="config" :connect="connect" :isConnected="isConnected"
-		@connectRtc="connectRtc" :room="room!" />
+  <RtcLayout
+    :inviteData="inviteData"
+    :authData="config"
+    :connect="connect"
+    :isConnected="isConnected"
+    @connectRtc="connectRtc"
+    :room="room"
+    :sendCustomSignal="sendCustomSignal"
+  />
 </template>
 
 <script setup lang="ts">
-	import { useRoom } from '@/utils/open-im-rtc'
-	import { IMSDK } from '@/utils/imCommon'
-	import { InviteData, RtcInviteResults } from './data'
-	import useUserStore from '@/store/modules/user'
-	import RtcLayout from './RtcLayout/index.vue'
-	import emitter from '@/utils/events'
-	import { feedbackToast } from '@/utils/common'
-	import { SessionType } from 'open-im-sdk-wasm'
+import { useRoom } from "@/utils/open-im-rtc";
+import { IMSDK } from "@/utils/imCommon";
+import { InviteData } from "./data";
+import useUserStore from "@/store/modules/user";
+import RtcLayout from "./RtcLayout/index.vue";
+import emitter from "@/utils/events";
+import { feedbackToast } from "@/utils/common";
+import { CustomType } from "@/constants/enum";
+import { getRtcConnectData } from "@/api/im";
+import { v4 as uuidV4 } from "uuid";
 
-	type RtcProps = {
-		inviteData : InviteData
-	}
-	const props = defineProps<RtcProps>()
+type RtcProps = {
+  inviteData: InviteData;
+};
+const props = defineProps<RtcProps>();
 
-	const { t } = useI18n()
-	const userStore = useUserStore()
+const { t } = useI18n();
+const userStore = useUserStore();
 
-	const connect = ref(false)
-	const isConnected = ref(false)
-	const config = reactive({
-		serverUrl: '',
-		token: '',
-		connect: false,
-		audio: true,
-		video: props.inviteData.invitation?.mediaType === 'video',
-	})
-	const isRecv = computed(
-		() => userStore.selfInfo.userID !== props.inviteData.invitation?.inviterUserID,
-	)
-	const isGroup = computed(
-		() => props.inviteData.invitation?.sessionType !== SessionType.Single,
-	)
+const connect = ref(false);
+const isConnected = ref(false);
+const config = reactive({
+  serverUrl: "",
+  token: "",
+  connect: false,
+  audio: true,
+  video: props.inviteData.invitation?.mediaType === "video",
+});
+const isRecv = computed(
+  () => userStore.selfInfo.userID !== props.inviteData.invitation?.inviterUserID
+);
 
-	const room = useRoom({
-		refConfig: config,
-		onConnected: () => {
-			isConnected.value = true
-		},
-		onDisconnected: () => {
-			connect.value = false
-			isConnected.value = false
-			config.connect = false
-		},
-		onError: (error) => {
-			feedbackToast({ message: t('rtc.joinFailed'), error })
-			emitter.emit('CLOSE_RTC_MODAL')
-		},
-	})
+const room = useRoom({
+  refConfig: config,
+  onConnected: () => {
+    isConnected.value = true;
+  },
+  onDisconnected: () => {
+    connect.value = false;
+    isConnected.value = false;
+    config.connect = false;
+  },
+  onError: (error) => {
+    console.error(error);
+  },
+});
 
-	const connectRtc = (data ?: any) => {
-		if (data) {
-			config.serverUrl = data.liveURL
-			config.token = data.token
-			config.connect = true
-		}
-		connect.value = true
-	}
+const connectRtc = (data?: any) => {
+  if (data) {
+    config.serverUrl = data.liveURL;
+    config.token = data.token;
+    config.connect = true;
+  }
+  connect.value = true;
+};
 
-	const tryInvite = async () => {
-		if (props.inviteData.isJoin && props.inviteData.invitation?.roomID) {
-			IMSDK.signalingGetTokenByRoomID<RtcInviteResults>(
-				props.inviteData.invitation.roomID,
-			)
-				.then(({ data }) => {
-					config.serverUrl = data.liveURL
-					config.token = data.token
-					config.connect = true
-					if (isGroup.value) {
-						connect.value = true
-					}
-				})
-				.catch((error) => {
-					feedbackToast({ message: t('rtc.joinFailed'), error })
-					emitter.emit('CLOSE_RTC_MODAL')
-				})
-		}
-		if (!isRecv.value) {
-			const funcName = isGroup.value ? 'signalingInviteInGroup' : 'signalingInvite'
-			try {
-				const { data } = await IMSDK[funcName]<RtcInviteResults>({
-					invitation: props.inviteData.invitation!,
-				})
-				config.serverUrl = data.liveURL
-				config.token = data.token
-				config.connect = true
-				if (isGroup.value) {
-					connect.value = true
-				}
-			} catch (error) {
-				feedbackToast({ message: t('rtc.invitationFailed'), error })
-				emitter.emit('CLOSE_RTC_MODAL')
-			}
-		}
-	}
+const timer = ref<NodeJS.Timeout>();
+const clearTimer = () => clearTimeout(timer.value!);
+const checkTimeout = () => {
+  if (timer.value) clearTimer();
+  timer.value = setTimeout(() => {
+    clearTimer();
 
-	onMounted(() => {
-		tryInvite()
-	})
+    if (!props.inviteData.invitation) return;
+
+    sendCustomSignal(
+      props.inviteData.invitation?.inviteeUserIDList[0],
+      CustomType.CallingCancel
+    );
+  }, (props.inviteData.invitation?.timeout ?? 30) * 1000);
+};
+
+const tryInvite = async () => {
+  if (!isRecv.value) {
+    try {
+      const { data } = await getRtcConnectData(
+        // uuidV4(),
+        `room-${userStore.selfInfo.userID}`, // 房间号
+        userStore.selfInfo.userID
+      );
+      config.serverUrl = data.serverUrl;
+      config.token = data.token;
+      config.connect = true;
+      console.log(
+        "props.inviteData.invitation!.inviteeUserIDList",
+        props.inviteData.invitation!.inviteeUserIDList
+      );
+      await sendCustomSignal(
+        props.inviteData.invitation!.inviteeUserIDList[0],
+        CustomType.CallingInvite
+      );
+      checkTimeout();
+    } catch (error) {
+      feedbackToast({ message: t("rtc.invitationFailed"), error });
+      emitter.emit("CLOSE_RTC_MODAL");
+    }
+  }
+};
+
+const sendCustomSignal = async (recvID: string, customType: CustomType) => {
+  const data = {
+    customType,
+    data: {	
+      ...props.inviteData.invitation,
+    },
+  };
+  const { data: message } = await IMSDK.createCustomMessage({
+    data: JSON.stringify(data),
+    extension: "",
+    description: "",
+  });
+  await IMSDK.sendMessage({
+    recvID,
+    message,
+    groupID: "",
+    isOnlineOnly: true,
+  });
+};
+
+onMounted(() => {
+  tryInvite();
+	console.log('1. props.inviteData',props.inviteData)
+});
 </script>
 
-<style lang="scss" scoped></style>
+<style lang="scss" scoped></style>

+ 2 - 0
src/utils/open-im-rtc/hooks/useRoom.ts

@@ -104,6 +104,7 @@ export function useRoom(props: LiveKitRoomProps) {
   watch(
     props.refConfig,
     (newConfig) => {
+      console.log('2. props.refConfig', newConfig)
       room.value = passedRoom ?? new Room(options)
 
       const { className } = setupLiveKitRoom()
@@ -146,6 +147,7 @@ export function useRoom(props: LiveKitRoomProps) {
           .connect(newConfig.serverUrl, newConfig.token, connectOptions)
           .catch((e: Error) => {
             log.warn(e)
+            console.log('3. error', e)
             onError?.(e)
           })
       } else {