316 lines
7.7 KiB
Vue
316 lines
7.7 KiB
Vue
<template>
|
||
<view class="page-container">
|
||
<!-- TUICallKit 组件 - 确保在最上层 -->
|
||
<view class="call-kit-wrapper" v-if="isLogin">
|
||
<TUICallKit></TUICallKit>
|
||
</view>
|
||
|
||
<!-- 登录界面 -->
|
||
<view class="loginBox">
|
||
<input
|
||
class="input-box"
|
||
v-model="patientId"
|
||
:placeholder="!isLogin ? '请输入患者ID(数字)' : '输入医生ID或完整userId(如:doctor_1)'"
|
||
placeholder-style="color:#BBBBBB;"
|
||
/>
|
||
<view class="login">
|
||
<button
|
||
class="loginBtn"
|
||
@click="!isLogin ? loginHandler() : callHandler()"
|
||
:disabled="loading"
|
||
>
|
||
{{ loading ? '加载中...' : (!isLogin ? "登录" : "呼叫") }}
|
||
</button>
|
||
</view>
|
||
<view v-if="isLogin" class="status-info">
|
||
<text>当前登录: {{ currentUserId }}</text>
|
||
<text>通话状态: {{ callStatus }}</text>
|
||
<text class="tip">提示:呼叫医生请输入医生ID(如:1)或完整ID(如:doctor_1)</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, computed, onMounted, onUnmounted, nextTick } from "vue";
|
||
import { TUICallKitAPI, TUIStore, StoreName, NAME } from "../src/index";
|
||
import TUICallKit from "../src/Components/TUICallKit";
|
||
|
||
let patientId = ref("2"); // 患者ID(数字)
|
||
let currentUserId = ref(""); // 当前登录的userId
|
||
let isLogin = ref(false);
|
||
let loading = ref(false);
|
||
|
||
// 计算属性 - 通话状态
|
||
const callStatus = computed(() => {
|
||
const status = TUIStore.getData(StoreName.CALL, NAME.CALL_STATUS);
|
||
return status || 'IDLE';
|
||
});
|
||
|
||
// 监听通话状态
|
||
onMounted(() => {
|
||
console.log('=== 页面已挂载 ===');
|
||
|
||
// 设置详细日志级别
|
||
try {
|
||
TUICallKitAPI.setLogLevel(1); // 0: 普通, 1: 详细
|
||
console.log('=== 已设置详细日志级别 ===');
|
||
} catch (error) {
|
||
console.log('设置日志级别失败:', error);
|
||
}
|
||
|
||
TUIStore.watch(StoreName.CALL, {
|
||
[NAME.CALL_STATUS]: (newStatus) => {
|
||
console.log('=== 通话状态变化 ===', newStatus);
|
||
console.log('可能的状态值: idle, calling, connected');
|
||
},
|
||
[NAME.IS_GROUP]: (isGroup) => {
|
||
console.log('=== 是否群组通话 ===', isGroup);
|
||
},
|
||
[NAME.CALL_ROLE]: (role) => {
|
||
console.log('=== 通话角色 ===', role);
|
||
},
|
||
[NAME.CALL_MEDIA_TYPE]: (type) => {
|
||
console.log('=== 通话类型 ===', type);
|
||
}
|
||
});
|
||
});
|
||
|
||
onUnmounted(() => {
|
||
TUIStore.unwatch(StoreName.CALL, {
|
||
[NAME.CALL_STATUS]: () => {},
|
||
[NAME.IS_GROUP]: () => {},
|
||
[NAME.CALL_ROLE]: () => {},
|
||
[NAME.CALL_MEDIA_TYPE]: () => {}
|
||
});
|
||
});
|
||
|
||
// 从后端获取签名
|
||
const getSignatureFromServer = async (patientId) => {
|
||
return new Promise((resolve, reject) => {
|
||
uni.request({
|
||
url: 'https://api.zzzhengyangtang.cn/api/tcm/getPatientSignature', // 后端接口地址 // 替换为你的后端地址
|
||
method: 'GET',
|
||
data: {
|
||
patient_id: patientId
|
||
},
|
||
success: (res) => {
|
||
if (res.data && res.data.code === 1) {
|
||
resolve(res.data.data);
|
||
} else {
|
||
reject(new Error(res.data.msg || '获取签名失败'));
|
||
}
|
||
},
|
||
fail: (err) => {
|
||
reject(err);
|
||
}
|
||
});
|
||
});
|
||
};
|
||
|
||
const loginHandler = async () => {
|
||
if (!patientId.value) {
|
||
uni.showToast({
|
||
title: '请输入患者ID',
|
||
icon: 'none'
|
||
});
|
||
return;
|
||
}
|
||
|
||
try {
|
||
loading.value = true;
|
||
|
||
uni.showLoading({
|
||
title: '正在获取签名...'
|
||
});
|
||
|
||
// 从后端获取签名
|
||
const signatureData = await getSignatureFromServer(patientId.value);
|
||
|
||
console.log('获取签名成功:', signatureData);
|
||
|
||
const { sdkAppId, userId, userSig } = signatureData;
|
||
currentUserId.value = userId;
|
||
|
||
console.log('=== 小程序端登录信息 ===');
|
||
console.log('sdkAppId:', sdkAppId);
|
||
console.log('userId:', userId);
|
||
console.log('userSig 长度:', userSig?.length);
|
||
|
||
uni.showLoading({
|
||
title: '正在初始化...'
|
||
});
|
||
|
||
// 初始化 TUICallKit
|
||
await TUICallKitAPI.init({
|
||
sdkAppID: Number(sdkAppId), // 确保是数字类型
|
||
userID: userId, // 应该是 patient_2 格式
|
||
userSig: userSig,
|
||
});
|
||
|
||
console.log('TUICallKit 初始化成功, userId:', userId);
|
||
|
||
// 等待一下确保初始化完成
|
||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||
|
||
// 小程序端使用 TUIStore 监听状态变化,而不是 .on() 方法
|
||
// TUICallKit 组件会自动处理来电显示
|
||
console.log('=== TUICallKit 初始化完成,等待来电 ===');
|
||
|
||
isLogin.value = true;
|
||
|
||
// 等待组件挂载
|
||
await nextTick();
|
||
|
||
console.log('=== TUICallKit 组件已挂载 ===');
|
||
console.log('当前通话状态:', callStatus.value);
|
||
console.log('完整状态信息:', {
|
||
callStatus: TUIStore.getData(StoreName.CALL, NAME.CALL_STATUS),
|
||
isGroup: TUIStore.getData(StoreName.CALL, NAME.IS_GROUP),
|
||
callRole: TUIStore.getData(StoreName.CALL, NAME.CALL_ROLE),
|
||
callMediaType: TUIStore.getData(StoreName.CALL, NAME.CALL_MEDIA_TYPE),
|
||
localUserInfo: TUIStore.getData(StoreName.CALL, NAME.LOCAL_USER_INFO)
|
||
});
|
||
|
||
uni.hideLoading();
|
||
uni.showToast({
|
||
title: '登录成功',
|
||
icon: 'success'
|
||
});
|
||
|
||
// 清空输入框,准备输入呼叫目标
|
||
patientId.value = "";
|
||
|
||
} catch (error) {
|
||
console.error('登录失败:', error);
|
||
uni.hideLoading();
|
||
uni.showToast({
|
||
title: '登录失败: ' + (error.message || '未知错误'),
|
||
icon: 'none',
|
||
duration: 3000
|
||
});
|
||
} finally {
|
||
loading.value = false;
|
||
}
|
||
};
|
||
|
||
const callHandler = async () => {
|
||
if (!patientId.value) {
|
||
uni.showToast({
|
||
title: '请输入要呼叫的用户ID',
|
||
icon: 'none'
|
||
});
|
||
return;
|
||
}
|
||
|
||
try {
|
||
loading.value = true;
|
||
|
||
// 构建目标用户ID - 确保格式一致
|
||
// 如果输入的是纯数字,转换为 doctor_X 格式(假设呼叫医生)
|
||
// 如果已经包含前缀,直接使用
|
||
let targetUserId = patientId.value;
|
||
if (/^\d+$/.test(patientId.value)) {
|
||
// 纯数字,添加 doctor_ 前缀(患者呼叫医生)
|
||
targetUserId = `doctor_${patientId.value}`;
|
||
}
|
||
|
||
console.log('准备呼叫用户:', targetUserId);
|
||
|
||
// 发起通话
|
||
await TUICallKitAPI.calls({
|
||
userIDList: [targetUserId],
|
||
type: 2, // 2 表示视频通话
|
||
});
|
||
|
||
console.log('发起通话成功, 目标用户:', targetUserId);
|
||
|
||
uni.showToast({
|
||
title: '正在呼叫...',
|
||
icon: 'none'
|
||
});
|
||
|
||
} catch (error) {
|
||
console.error('发起通话失败:', error);
|
||
uni.showToast({
|
||
title: '发起通话失败: ' + (error.message || '未知错误'),
|
||
icon: 'none',
|
||
duration: 3000
|
||
});
|
||
} finally {
|
||
loading.value = false;
|
||
}
|
||
};
|
||
</script>
|
||
|
||
<style>
|
||
.page-container {
|
||
width: 100vw;
|
||
height: 100vh;
|
||
position: relative;
|
||
}
|
||
|
||
.call-kit-wrapper {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100vw;
|
||
height: 100vh;
|
||
z-index: 9999;
|
||
}
|
||
|
||
.loginBox {
|
||
margin-top: 200px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
position: relative;
|
||
z-index: 1;
|
||
}
|
||
|
||
input {
|
||
display: flex;
|
||
font-size: 20px;
|
||
}
|
||
|
||
.login {
|
||
width: 100vw;
|
||
bottom: 5vh;
|
||
margin: 70rpx;
|
||
}
|
||
|
||
.login button {
|
||
width: 80%;
|
||
background-color: #006eff;
|
||
border-radius: 50px;
|
||
color: white;
|
||
}
|
||
|
||
.login button:disabled {
|
||
background-color: #cccccc;
|
||
}
|
||
|
||
.status-info {
|
||
margin-top: 20px;
|
||
padding: 10px;
|
||
background-color: #f0f0f0;
|
||
border-radius: 5px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
gap: 8px;
|
||
}
|
||
|
||
.status-info text {
|
||
font-size: 14px;
|
||
color: #666;
|
||
}
|
||
|
||
.status-info .tip {
|
||
font-size: 12px;
|
||
color: #999;
|
||
text-align: center;
|
||
line-height: 1.5;
|
||
}
|
||
</style> |