365 lines
9.6 KiB
Vue
365 lines
9.6 KiB
Vue
<template>
|
||
<div class="patient-test">
|
||
<el-card>
|
||
<template #header>
|
||
<div class="card-header">
|
||
<span>患者端测试 - 接听来电</span>
|
||
</div>
|
||
</template>
|
||
|
||
<el-alert
|
||
type="info"
|
||
:closable="false"
|
||
class="mb-4"
|
||
>
|
||
<p>此页面用于测试音视频通话功能</p>
|
||
<p>页面打开后会自动初始化患者端,等待医生端发起通话</p>
|
||
</el-alert>
|
||
|
||
<div v-if="!initialized" class="init-section">
|
||
<el-alert
|
||
type="info"
|
||
:closable="false"
|
||
class="mb-4"
|
||
>
|
||
<p><strong>当前登录用户:</strong> {{ currentUser.nickname || currentUser.name || '未知' }}</p>
|
||
<p><strong>用户ID:</strong> {{ currentUser.id || '未获取' }}</p>
|
||
<p><strong>状态:</strong> 正在初始化...</p>
|
||
</el-alert>
|
||
|
||
<el-button
|
||
type="primary"
|
||
@click="initPatient"
|
||
:loading="loading"
|
||
size="large"
|
||
v-if="!loading"
|
||
>
|
||
重新初始化
|
||
</el-button>
|
||
</div>
|
||
|
||
<div v-if="initialized" class="status">
|
||
<el-alert
|
||
:type="hasIncomingCall ? 'warning' : 'success'"
|
||
:closable="false"
|
||
>
|
||
<template #title>
|
||
<div class="flex items-center">
|
||
<el-icon class="mr-2" :class="{ 'animate-pulse': hasIncomingCall }">
|
||
<Phone />
|
||
</el-icon>
|
||
<span>{{ hasIncomingCall ? '收到来电!' : '患者端已初始化,等待来电...' }}</span>
|
||
</div>
|
||
</template>
|
||
<div class="mt-2">
|
||
<p><strong>患者ID:</strong> {{ currentUserId }}</p>
|
||
<p><strong>状态:</strong> {{ hasIncomingCall ? '来电中' : '在线' }}</p>
|
||
<p v-if="hasIncomingCall && incomingCallInfo">
|
||
<strong>通话类型:</strong> 视频通话
|
||
</p>
|
||
</div>
|
||
</el-alert>
|
||
|
||
<!-- 来电操作按钮 -->
|
||
<div v-if="hasIncomingCall" class="call-actions mt-4">
|
||
<el-button
|
||
type="success"
|
||
size="large"
|
||
@click="acceptCall"
|
||
:icon="Phone"
|
||
>
|
||
接听
|
||
</el-button>
|
||
<el-button
|
||
type="danger"
|
||
size="large"
|
||
@click="rejectCall"
|
||
>
|
||
拒绝
|
||
</el-button>
|
||
</div>
|
||
|
||
<el-button
|
||
v-else
|
||
type="danger"
|
||
@click="reset"
|
||
class="mt-4"
|
||
>
|
||
重置
|
||
</el-button>
|
||
</div>
|
||
|
||
<div id="call-container" class="call-container">
|
||
<TUICallKit v-if="initialized" />
|
||
</div>
|
||
</el-card>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { ref, onUnmounted, computed, onMounted } from 'vue'
|
||
import { Phone } from '@element-plus/icons-vue'
|
||
import { TUICallKitAPI, TUICallKit, STATUS } from '@trtc/calls-uikit-vue'
|
||
import { ElMessage, ElNotification } from 'element-plus'
|
||
import request from '@/utils/request'
|
||
import useUserStore from '@/stores/modules/user'
|
||
|
||
const userStore = useUserStore()
|
||
const currentUser = computed(() => userStore.userInfo)
|
||
|
||
const form = ref({
|
||
patientId: computed(() => currentUser.value.id?.toString() || '1')
|
||
})
|
||
|
||
const loading = ref(false)
|
||
const initialized = ref(false)
|
||
const currentUserId = ref('')
|
||
const hasIncomingCall = ref(false)
|
||
const incomingCallInfo = ref<any>(null)
|
||
|
||
// 页面加载时自动初始化
|
||
onMounted(() => {
|
||
initPatient()
|
||
})
|
||
|
||
// 监听状态变化
|
||
const handleStatusChange = ({ oldStatus, newStatus }: any) => {
|
||
console.log('通话状态变化:', { oldStatus, newStatus })
|
||
|
||
// 收到来电邀请
|
||
if (newStatus === STATUS.BE_INVITED) {
|
||
hasIncomingCall.value = true
|
||
incomingCallInfo.value = { oldStatus, newStatus }
|
||
|
||
// 显示来电通知
|
||
ElNotification({
|
||
title: '来电提醒',
|
||
message: '收到视频通话请求',
|
||
type: 'info',
|
||
duration: 0, // 不自动关闭
|
||
position: 'top-right'
|
||
})
|
||
|
||
ElMessage.success('收到来电,请点击接听按钮')
|
||
}
|
||
|
||
// 通话结束,回到空闲状态
|
||
if (newStatus === STATUS.IDLE && hasIncomingCall.value) {
|
||
hasIncomingCall.value = false
|
||
incomingCallInfo.value = null
|
||
ElMessage.info('通话已结束')
|
||
}
|
||
}
|
||
|
||
const initPatient = async () => {
|
||
try {
|
||
loading.value = true
|
||
|
||
const patientId = currentUser.value.id
|
||
if (!patientId) {
|
||
throw new Error('未获取到当前用户ID,请重新登录')
|
||
}
|
||
|
||
ElMessage.info('正在获取签名...')
|
||
|
||
// 获取患者签名
|
||
const result = await request.get({
|
||
url: '/tcm.diagnosis/getDoctorSignature',
|
||
params: {
|
||
patient_id: patientId
|
||
}
|
||
})
|
||
|
||
if (!result) {
|
||
throw new Error('获取签名失败')
|
||
}
|
||
|
||
const { sdkAppId, userId, userSig } = result
|
||
currentUserId.value = userId
|
||
|
||
console.log('患者签名获取成功:', { userId, sdkAppId, userSigLength: userSig.length })
|
||
ElMessage.info('正在初始化通话组件...')
|
||
|
||
// 设置状态变化回调
|
||
TUICallKitAPI.setCallback({
|
||
statusChanged: handleStatusChange
|
||
})
|
||
|
||
// 初始化(注意:SDKAppID必须是数字类型)
|
||
await TUICallKitAPI.init({
|
||
userID: userId,
|
||
userSig: userSig,
|
||
SDKAppID: Number(sdkAppId) // 转换为数字类型
|
||
})
|
||
|
||
console.log('TUICallKitAPI.init 完成')
|
||
console.log('已注册状态监听回调')
|
||
ElMessage.info('等待初始化完成...')
|
||
|
||
// 等待初始化完成
|
||
await new Promise(resolve => setTimeout(resolve, 2000))
|
||
|
||
initialized.value = true
|
||
ElMessage.success('患者端初始化成功,等待来电...')
|
||
|
||
console.log('患者端初始化完成,userId:', userId)
|
||
|
||
} catch (error: any) {
|
||
console.error('初始化失败:', error)
|
||
ElMessage.error(error.message || '初始化失败')
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
}
|
||
|
||
// 接听来电
|
||
const acceptCall = async () => {
|
||
try {
|
||
console.log('接听来电')
|
||
await TUICallKitAPI.accept()
|
||
ElMessage.success('已接听通话')
|
||
hasIncomingCall.value = false
|
||
} catch (error: any) {
|
||
console.error('接听失败:', error)
|
||
ElMessage.error(error.message || '接听失败')
|
||
}
|
||
}
|
||
|
||
// 拒绝来电
|
||
const rejectCall = async () => {
|
||
try {
|
||
console.log('拒绝来电')
|
||
await TUICallKitAPI.reject()
|
||
ElMessage.info('已拒绝通话')
|
||
hasIncomingCall.value = false
|
||
incomingCallInfo.value = null
|
||
} catch (error: any) {
|
||
console.error('拒绝失败:', error)
|
||
ElMessage.error(error.message || '拒绝失败')
|
||
}
|
||
}
|
||
|
||
const reset = () => {
|
||
initialized.value = false
|
||
currentUserId.value = ''
|
||
hasIncomingCall.value = false
|
||
incomingCallInfo.value = null
|
||
}
|
||
|
||
// 组件卸载时清理
|
||
onUnmounted(() => {
|
||
if (initialized.value) {
|
||
// 清理资源
|
||
hasIncomingCall.value = false
|
||
incomingCallInfo.value = null
|
||
}
|
||
})
|
||
</script>
|
||
|
||
<style scoped>
|
||
.patient-test {
|
||
padding: 20px;
|
||
max-width: 1200px;
|
||
margin: 0 auto;
|
||
}
|
||
|
||
.card-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
font-size: 18px;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.init-section {
|
||
text-align: center;
|
||
padding: 20px;
|
||
}
|
||
|
||
.status {
|
||
margin: 20px 0;
|
||
}
|
||
|
||
.call-actions {
|
||
display: flex;
|
||
gap: 16px;
|
||
justify-content: center;
|
||
}
|
||
|
||
.call-container {
|
||
width: 100%;
|
||
min-height: 500px;
|
||
margin-top: 20px;
|
||
background: #f5f5f5;
|
||
border-radius: 8px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
overflow: hidden;
|
||
}
|
||
|
||
/* 确保 TUICallKit 组件正确显示 */
|
||
:deep(.call-container) {
|
||
.tui-call-kit {
|
||
width: 100%;
|
||
height: 500px;
|
||
}
|
||
|
||
video {
|
||
width: 100%;
|
||
height: 100%;
|
||
object-fit: cover;
|
||
}
|
||
}
|
||
|
||
.mb-4 {
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.mt-2 {
|
||
margin-top: 8px;
|
||
}
|
||
|
||
.mt-4 {
|
||
margin-top: 16px;
|
||
}
|
||
|
||
.mr-2 {
|
||
margin-right: 8px;
|
||
}
|
||
|
||
.flex {
|
||
display: flex;
|
||
}
|
||
|
||
.items-center {
|
||
align-items: center;
|
||
}
|
||
|
||
.animate-pulse {
|
||
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
||
}
|
||
|
||
@keyframes pulse {
|
||
0%, 100% {
|
||
opacity: 1;
|
||
}
|
||
50% {
|
||
opacity: 0.5;
|
||
}
|
||
}
|
||
|
||
:deep(.el-alert__description) {
|
||
margin-top: 8px;
|
||
}
|
||
|
||
:deep(.el-alert__description ol) {
|
||
margin: 8px 0;
|
||
padding-left: 20px;
|
||
}
|
||
|
||
:deep(.el-alert__description li) {
|
||
margin: 4px 0;
|
||
}
|
||
</style>
|