|
@@ -4,20 +4,32 @@ import type { IAgoraRTCClient, IMicrophoneAudioTrack, ICameraVideoTrack } from "
|
|
|
import { CHAT_STATUS, CHAT_OPERATION } from '~/types';
|
|
|
import { UseDraggable } from '@vueuse/components'
|
|
|
import request from '~/utils/request';
|
|
|
-import type { type_dyaw_xlfw_zxhd } from '~/types';
|
|
|
+import type { type_dyaw_xlfw_zxhd, type_dyaw_xlfw_zxhd_log } from '~/types';
|
|
|
import user, { UserRole } from '~/store/user';
|
|
|
import { socketSend } from '~/utils/ws';
|
|
|
|
|
|
-// const props = defineProps<{
|
|
|
-// mode: 'audio' | 'video'
|
|
|
-// }>()
|
|
|
+const emits = defineEmits<{
|
|
|
+ (event: 'update-info', info: type_dyaw_xlfw_zxhd_log): void;
|
|
|
+}>()
|
|
|
+
|
|
|
+let reqDate: Partial<type_dyaw_xlfw_zxhd_log>
|
|
|
+// = {
|
|
|
+// dxz_id: dyaw_xlfw_zxhd.dxz_id,
|
|
|
+// dxzl_stu_user_id: dyaw_xlfw_zxhd.dxz_stu_user_id,
|
|
|
+// dxzl_stu_user_realname: dyaw_xlfw_zxhd.dxz_stu_user_realname,
|
|
|
+// dxzl_tea_user_id: dyaw_xlfw_zxhd.dxz_tea_user_id,
|
|
|
+// dxzl_tea_user_realname: dyaw_xlfw_zxhd.dxz_tea_user_realname,
|
|
|
+// dxzl_last_msg_content: encodeURIComponent(inputValue),
|
|
|
+// dxzl_type: inputValue.includes('><img') ? '2' : '1'
|
|
|
+// }
|
|
|
|
|
|
let dyaw_xlfw_zxhd = $ref<type_dyaw_xlfw_zxhd>()
|
|
|
+let mode = $ref<'audio' | 'video'>()
|
|
|
|
|
|
const otherInfo = $computed(() => {
|
|
|
- if (UserRole === 'teacher')
|
|
|
- return { id: dyaw_xlfw_zxhd?.dxz_tea_user_id, realname: dyaw_xlfw_zxhd?.dxz_tea_user_realname, avatar: dyaw_xlfw_zxhd?.dxx_tea_avatar }
|
|
|
if (UserRole === 'student')
|
|
|
+ return { id: dyaw_xlfw_zxhd?.dxz_tea_user_id, realname: dyaw_xlfw_zxhd?.dxz_tea_user_realname, avatar: dyaw_xlfw_zxhd?.dxx_tea_avatar }
|
|
|
+ if (UserRole === 'teacher')
|
|
|
return { id: dyaw_xlfw_zxhd?.dxz_stu_user_id, realname: dyaw_xlfw_zxhd?.dxz_stu_user_realname, avatar: dyaw_xlfw_zxhd?.dxx_user_avatar }
|
|
|
})
|
|
|
|
|
@@ -29,31 +41,71 @@ function handleClose() {
|
|
|
isOpen = false
|
|
|
}
|
|
|
defineExpose({
|
|
|
- open(d: type_dyaw_xlfw_zxhd, mode: 'audio' | 'video') {
|
|
|
+ init(ws: WebSocket) {
|
|
|
+ ws2 = ws
|
|
|
+ },
|
|
|
+ open(d: type_dyaw_xlfw_zxhd, _mode: 'audio' | 'video') {
|
|
|
+ if (isOpen) return;
|
|
|
// isOpen = true
|
|
|
dyaw_xlfw_zxhd = d
|
|
|
+ reqDate = {
|
|
|
+ dxz_id: dyaw_xlfw_zxhd.dxz_id,
|
|
|
+ dxzl_stu_user_id: dyaw_xlfw_zxhd.dxz_stu_user_id,
|
|
|
+ dxzl_stu_user_realname: dyaw_xlfw_zxhd.dxz_stu_user_realname,
|
|
|
+ dxzl_tea_user_id: dyaw_xlfw_zxhd.dxz_tea_user_id,
|
|
|
+ dxzl_tea_user_realname: dyaw_xlfw_zxhd.dxz_tea_user_realname,
|
|
|
+ }
|
|
|
+
|
|
|
+ mode = _mode
|
|
|
handleAudioChatStart()
|
|
|
},
|
|
|
close() {
|
|
|
handleClose()
|
|
|
},
|
|
|
- publisher(ws: WebSocket, operate: CHAT_OPERATION) {
|
|
|
- ws2 = ws
|
|
|
+ publisher(
|
|
|
+ content:
|
|
|
+ // type_dyaw_xlfw_zxhd_log &
|
|
|
+ {
|
|
|
+ operate: CHAT_OPERATION,
|
|
|
+ rtcOptions?: TRtcOptions,
|
|
|
+ mode?: 'audio' | 'video',
|
|
|
+ dyaw_xlfw_zxhd?: type_dyaw_xlfw_zxhd,
|
|
|
+ fullSendData?: type_dyaw_xlfw_zxhd_log
|
|
|
+ }
|
|
|
+ ) {
|
|
|
+ console.log('publisher');
|
|
|
+ //
|
|
|
+ const { operate } = content
|
|
|
switch (operate) {
|
|
|
case CHAT_OPERATION.START:
|
|
|
audioChatStatus = CHAT_STATUS.WAITING_YOU_ACCEPT
|
|
|
+ rtcOptions = content.rtcOptions!;
|
|
|
+ mode = content.mode!;
|
|
|
+ dyaw_xlfw_zxhd = content.dyaw_xlfw_zxhd!
|
|
|
+ reqDate = {
|
|
|
+ dxz_id: dyaw_xlfw_zxhd.dxz_id,
|
|
|
+ dxzl_stu_user_id: dyaw_xlfw_zxhd.dxz_stu_user_id,
|
|
|
+ dxzl_stu_user_realname: dyaw_xlfw_zxhd.dxz_stu_user_realname,
|
|
|
+ dxzl_tea_user_id: dyaw_xlfw_zxhd.dxz_tea_user_id,
|
|
|
+ dxzl_tea_user_realname: dyaw_xlfw_zxhd.dxz_tea_user_realname,
|
|
|
+ }
|
|
|
isOpen = true
|
|
|
+ emits('update-info', content.fullSendData!)
|
|
|
+
|
|
|
break;
|
|
|
case CHAT_OPERATION.CANCEL:
|
|
|
+ // emits('update-info', content.fullSendData!)
|
|
|
isOpen = false
|
|
|
break;
|
|
|
case CHAT_OPERATION.ACCEPT:
|
|
|
audioChatStatus = CHAT_STATUS.CHATING
|
|
|
break;
|
|
|
case CHAT_OPERATION.DENY:
|
|
|
+ // emits('update-info', content.fullSendData!)
|
|
|
isOpen = false
|
|
|
break;
|
|
|
case CHAT_OPERATION.END:
|
|
|
+ // emits('update-info', content.fullSendData!)
|
|
|
isOpen = false
|
|
|
break;
|
|
|
default:
|
|
@@ -62,6 +114,42 @@ defineExpose({
|
|
|
}
|
|
|
})
|
|
|
|
|
|
+function handleInfoAdd(tip: string) {
|
|
|
+ const _reqDate = Object.assign({
|
|
|
+ dxzl_type: mode === 'audio' ? '3' : '4',
|
|
|
+ dxzl_last_msg_content: encodeURIComponent(`【${mode === 'audio' ? '语音通话' : '视频通话'}】`),
|
|
|
+ }, reqDate)
|
|
|
+ return request({
|
|
|
+ url: '/dyaw/xlfw_zxhd_log/add',
|
|
|
+ data: {
|
|
|
+ dyaw_xlfw_zxhd_log: _reqDate
|
|
|
+ }
|
|
|
+ }).then(res => {
|
|
|
+ if (res.code === '1') {
|
|
|
+ const fullSendData = {
|
|
|
+ create_user_id: user.user_id,
|
|
|
+ create_dateline: Date.now().toString().slice(0, 10),
|
|
|
+ ..._reqDate,
|
|
|
+ dxzl_id: `${res.data.insert_id}`
|
|
|
+ } as type_dyaw_xlfw_zxhd_log
|
|
|
+ emits('update-info', fullSendData)
|
|
|
+ return fullSendData
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+function handleInfoEdit(id: string, data: Partial<type_dyaw_xlfw_zxhd_log>, tip?: string) {
|
|
|
+ const _reqDate = Object.assign({
|
|
|
+ dxzl_last_msg_content: tip ?? encodeURIComponent(`【${mode === 'audio' ? '语音通话' : '视频通话'}】 ${tip}`),
|
|
|
+ }, data)
|
|
|
+ return request({
|
|
|
+ url: '/dyaw/xlfw_zxhd_log/edit',
|
|
|
+ data: {
|
|
|
+ dxzl_id: id,
|
|
|
+ dyaw_xlfw_zxhd_log: _reqDate
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
|
|
|
const LocalPlayerContainerRef = $ref<HTMLElement>()
|
|
|
const RemotePlayerContainerRef = $ref<HTMLElement>()
|
|
@@ -77,71 +165,106 @@ let rtcInstance: {
|
|
|
localAudioTrack: undefined,
|
|
|
localVideoTrack: undefined,
|
|
|
}
|
|
|
+type TRtcOptions = {
|
|
|
+ appId: string;
|
|
|
+ channel: string;
|
|
|
+ token: string;
|
|
|
+}
|
|
|
+let rtcOptions: TRtcOptions;
|
|
|
+
|
|
|
+function initRtcClient() {
|
|
|
+ if (rtcInstance.client) return;
|
|
|
+ let client = rtcInstance.client = AgoraRTC.createClient({ mode: "rtc", codec: "vp8" });
|
|
|
+
|
|
|
+ client.on("user-published", async (user, mediaType) => {
|
|
|
+
|
|
|
+ await client.subscribe(user, mediaType);
|
|
|
+
|
|
|
+ if (mediaType === "audio") {
|
|
|
+ const audioTrack = user.audioTrack;
|
|
|
+ audioTrack?.play();
|
|
|
+ } else {
|
|
|
+ const videoTrack = user.videoTrack;
|
|
|
+ videoTrack?.play(RemotePlayerContainerRef as HTMLElement);
|
|
|
+ }
|
|
|
+ });
|
|
|
+}
|
|
|
|
|
|
|
|
|
async function handleAudioChatStart() {
|
|
|
try {
|
|
|
- await AgoraRTC.getMicrophones()
|
|
|
- // await AgoraRTC.getCameras()
|
|
|
- let rtcOptions;
|
|
|
+ audioChatStatus = CHAT_STATUS.WAITING_OTHERS_ACCEPT
|
|
|
+ let isBusy;
|
|
|
await request({
|
|
|
- url: '/dyaw/xlfw_zxhd/get_rtc_token',
|
|
|
+ url: '/dyaw/xlfw_zxhd/get_user_status',
|
|
|
data: {
|
|
|
- dxz_id: dyaw_xlfw_zxhd?.dxz_id
|
|
|
+ user_id: otherInfo?.id
|
|
|
}
|
|
|
- }).then(async res => {
|
|
|
+ }).then(res => {
|
|
|
if (res.code === '1') {
|
|
|
- let resp: { jgim_roomid: string; rtc_appid: string; rtc_token: string } = res.data.one_info
|
|
|
- rtcOptions = {
|
|
|
- appId: resp.rtc_appid,
|
|
|
- // channel: resp.jgim_roomid,
|
|
|
- channel: dyaw_xlfw_zxhd!.dxz_id,
|
|
|
- token: resp.rtc_token,
|
|
|
- uid: user.user_id
|
|
|
- }
|
|
|
-
|
|
|
- let client = rtcInstance.client = AgoraRTC.createClient({ mode: "rtc", codec: "vp8" });
|
|
|
-
|
|
|
- client.on("user-published", async (user, mediaType) => {
|
|
|
- // 发起订阅
|
|
|
- await client.subscribe(user, mediaType);
|
|
|
-
|
|
|
- // 如果订阅的是音频轨道
|
|
|
- if (mediaType === "audio") {
|
|
|
- const audioTrack = user.audioTrack;
|
|
|
- // 自动播放音频
|
|
|
- audioTrack?.play();
|
|
|
- } else {
|
|
|
- const videoTrack = user.videoTrack;
|
|
|
- // 自动播放视频
|
|
|
- videoTrack?.play(RemotePlayerContainerRef as HTMLElement);
|
|
|
- }
|
|
|
- });
|
|
|
-
|
|
|
- await rtcInstance.client!.join(rtcOptions.appId, rtcOptions.channel, rtcOptions?.token, rtcOptions.uid);
|
|
|
- rtcInstance.localAudioTrack = await AgoraRTC.createMicrophoneAudioTrack();
|
|
|
- // rtcInstance.localVideoTrack = await AgoraRTC.createCameraVideoTrack();
|
|
|
- await rtcInstance.client!.publish([rtcInstance.localAudioTrack]);
|
|
|
- // rtcInstance.localVideoTrack.play(LocalPlayerContainerRef as HTMLElement);
|
|
|
+ isBusy = !!res.data.status
|
|
|
}
|
|
|
})
|
|
|
+ if (isBusy) {
|
|
|
+ // busy operation
|
|
|
+ audioChatStatus = CHAT_STATUS.WAITING_BUSY
|
|
|
+ setTimeout(() => {
|
|
|
+ handleClose()
|
|
|
+ }, 2000)
|
|
|
+ return
|
|
|
+ };
|
|
|
+ // await AgoraRTC.getMicrophones()
|
|
|
+ // await AgoraRTC.getCameras()
|
|
|
+ // await request({
|
|
|
+ // url: '/dyaw/xlfw_zxhd/get_rtc_token',
|
|
|
+ // data: {
|
|
|
+ // dxz_id: dyaw_xlfw_zxhd?.dxz_id
|
|
|
+ // }
|
|
|
+ // }).then(async res => {
|
|
|
+ // if (res.code === '1') {
|
|
|
+ // let resp: { jgim_roomid: string; rtc_appid: string; rtc_token: string } = res.data.one_info
|
|
|
+ // rtcOptions = {
|
|
|
+ // appId: resp.rtc_appid,
|
|
|
+ // // channel: resp.jgim_roomid,
|
|
|
+ // channel: dyaw_xlfw_zxhd!.dxz_id,
|
|
|
+ // token: resp.rtc_token,
|
|
|
+ // // uid: user.user_id
|
|
|
+ // }
|
|
|
+
|
|
|
+ // initRtcClient()
|
|
|
+
|
|
|
+ // await rtcInstance.client!.join(rtcOptions.appId, rtcOptions.channel, rtcOptions?.token, /*rtcOptions.uid*/ user.user_id);
|
|
|
+ // rtcInstance.localAudioTrack = await AgoraRTC.createMicrophoneAudioTrack();
|
|
|
+ // await rtcInstance.client!.publish(rtcInstance.localAudioTrack);
|
|
|
+ // // rtcInstance.localVideoTrack = await AgoraRTC.createCameraVideoTrack();
|
|
|
+ // // rtcInstance.localVideoTrack.play(LocalPlayerContainerRef as HTMLElement);
|
|
|
+ // // await rtcInstance.client!.publish(rtcInstance.localVideoTrack);
|
|
|
+ // }
|
|
|
+ // })
|
|
|
+ const fullSendData = await handleInfoAdd('拨号中')
|
|
|
+
|
|
|
isOpen = true
|
|
|
socketSend(ws2, {
|
|
|
dxzl_stu_user_id: dyaw_xlfw_zxhd!.dxz_stu_user_id,
|
|
|
dxzl_tea_user_id: dyaw_xlfw_zxhd!.dxz_tea_user_id,
|
|
|
operate: CHAT_OPERATION.START,
|
|
|
- rtcOptions
|
|
|
+ mode,
|
|
|
+ rtcOptions,
|
|
|
+ dyaw_xlfw_zxhd,
|
|
|
+ dxzl_id: fullSendData?.dxzl_id
|
|
|
})
|
|
|
} catch (error) {
|
|
|
console.error(error);
|
|
|
}
|
|
|
|
|
|
}
|
|
|
-function handleAudioChatCancel() {
|
|
|
+async function handleAudioChatCancel() {
|
|
|
+ const fullSendData = await handleInfoEdit('已取消')
|
|
|
socketSend(ws2, {
|
|
|
dxzl_stu_user_id: dyaw_xlfw_zxhd!.dxz_stu_user_id,
|
|
|
dxzl_tea_user_id: dyaw_xlfw_zxhd!.dxz_tea_user_id,
|
|
|
- operate: CHAT_OPERATION.CANCEL
|
|
|
+ operate: CHAT_OPERATION.CANCEL,
|
|
|
+ fullSendData
|
|
|
})
|
|
|
isOpen = false
|
|
|
}
|
|
@@ -153,19 +276,23 @@ function handleAudioChatAccept() {
|
|
|
})
|
|
|
audioChatStatus = CHAT_STATUS.CHATING
|
|
|
}
|
|
|
-function handleAudioChatDeny() {
|
|
|
+async function handleAudioChatDeny() {
|
|
|
+ const fullSendData = await handleInfoEdit('已拒接')
|
|
|
socketSend(ws2, {
|
|
|
dxzl_stu_user_id: dyaw_xlfw_zxhd!.dxz_stu_user_id,
|
|
|
dxzl_tea_user_id: dyaw_xlfw_zxhd!.dxz_tea_user_id,
|
|
|
- operate: CHAT_OPERATION.DENY
|
|
|
+ operate: CHAT_OPERATION.DENY,
|
|
|
+ fullSendData
|
|
|
})
|
|
|
isOpen = false
|
|
|
}
|
|
|
-function handleAudioChatEnd() {
|
|
|
+async function handleAudioChatEnd() {
|
|
|
+ const fullSendData = await handleInfoEdit('已结束')
|
|
|
socketSend(ws2, {
|
|
|
dxzl_stu_user_id: dyaw_xlfw_zxhd!.dxz_stu_user_id,
|
|
|
dxzl_tea_user_id: dyaw_xlfw_zxhd!.dxz_tea_user_id,
|
|
|
- operate: CHAT_OPERATION.END
|
|
|
+ operate: CHAT_OPERATION.END,
|
|
|
+ fullSendData
|
|
|
})
|
|
|
isOpen = false
|
|
|
}
|
|
@@ -198,8 +325,8 @@ function handleAudioChatEnd() {
|
|
|
</div>
|
|
|
<div class="text-hex-909090 flex_center flex-col space-y-2 h-16"
|
|
|
v-show="audioChatStatus === CHAT_STATUS.WAITING_BUSY">
|
|
|
- <div class="text-red-500">对方忙线中请等待</div>
|
|
|
- <div class="text-red-500">当前排队:{{ 4 }}</div>
|
|
|
+ <div class="text-red-500">对方忙线中</div>
|
|
|
+ <div class="text-red-500">请稍后再试</div>
|
|
|
<i:line-md:loading-alt-loop class="text-xl" />
|
|
|
</div>
|
|
|
<div class="text-hex-909090 flex_center flex-col space-y-2 h-16"
|