Files
zyt/admin/src/views/test/patient-call.vue
T
2026-03-11 14:33:49 +08:00

365 lines
9.6 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<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>