新增功能
This commit is contained in:
@@ -0,0 +1,334 @@
|
||||
# Web端呼叫小程序端通话问题修复指南
|
||||
|
||||
## 问题描述
|
||||
Web端可以呼叫Web端,但无法呼叫小程序端。
|
||||
|
||||
## 原因分析
|
||||
|
||||
### 1. 用户ID格式不一致
|
||||
- Web端医生: `doctor_{admin_id}`
|
||||
- 小程序端患者: 需要确认格式是否为 `patient_{patient_id}` 或其他格式
|
||||
|
||||
### 2. 小程序端未登录IM
|
||||
- 小程序端必须先登录腾讯云IM才能接收通话邀请
|
||||
- 需要在小程序启动时初始化 TUICallKit
|
||||
|
||||
### 3. 跨平台通话配置
|
||||
- 需要确保 SDKAppID 一致
|
||||
- 需要确保 UserSig 生成方式一致
|
||||
- 需要确保双方都使用相同的通话协议版本
|
||||
|
||||
## 解决方案
|
||||
|
||||
### 步骤1: 确认小程序端用户ID格式
|
||||
|
||||
检查小程序端的用户ID生成逻辑,确保与Web端一致。
|
||||
|
||||
**后端代码检查点:**
|
||||
```php
|
||||
// server/app/adminapi/logic/tcm/DiagnosisLogic.php
|
||||
// 查找 createPatientTrtcAccount 方法
|
||||
// 确认患者的 userId 格式
|
||||
```
|
||||
|
||||
**预期格式:**
|
||||
- 医生: `doctor_{admin_id}`
|
||||
- 患者: `patient_{patient_id}`
|
||||
|
||||
### 步骤2: 检查小程序端是否正确初始化
|
||||
|
||||
小程序端需要在 `app.js` 或页面 `onLoad` 时初始化 TUICallKit:
|
||||
|
||||
```javascript
|
||||
// 小程序端代码示例
|
||||
import { TUICallKit } from '@tencentcloud/call-uikit-wechat'
|
||||
|
||||
// 初始化
|
||||
await TUICallKit.init({
|
||||
SDKAppID: YOUR_SDKAPPID,
|
||||
userID: 'patient_123', // 患者ID
|
||||
userSig: 'YOUR_USERSIG' // 从后端获取
|
||||
})
|
||||
|
||||
// 监听来电
|
||||
TUICallKit.on('onCallReceived', (event) => {
|
||||
console.log('收到来电', event)
|
||||
})
|
||||
```
|
||||
|
||||
### 步骤3: 确保小程序端在线
|
||||
|
||||
小程序端必须:
|
||||
1. 已登录到腾讯云IM
|
||||
2. 保持在线状态
|
||||
3. 正确监听来电事件
|
||||
|
||||
### 步骤4: 检查Web端发起通话的userId
|
||||
|
||||
在Web端发起通话时,确保使用正确的患者userId:
|
||||
|
||||
```typescript
|
||||
// admin/src/components/video-call/index.vue
|
||||
// 检查 startCall 方法中的 userId
|
||||
|
||||
// 应该使用患者的 IM userId,而不是患者的数据库ID
|
||||
await TUICallKitServer.call({
|
||||
userID: 'patient_123', // 必须是小程序端登录IM时使用的userId
|
||||
type: TUICallType.VIDEO_CALL
|
||||
})
|
||||
```
|
||||
|
||||
### 步骤5: 后端返回正确的患者userId
|
||||
|
||||
修改后端逻辑,在获取签名时同时返回患者的userId:
|
||||
|
||||
```php
|
||||
// server/app/adminapi/logic/tcm/DiagnosisLogic.php
|
||||
|
||||
public static function getCallSignature(array $params)
|
||||
{
|
||||
// ... 现有代码 ...
|
||||
|
||||
// 获取患者信息
|
||||
$patientId = $params['patient_id'] ?? 0;
|
||||
$patientUserId = 'patient_' . $patientId;
|
||||
|
||||
return [
|
||||
'sdkAppId' => (int)$config['sdkAppId'],
|
||||
'userId' => $userId, // 医生的userId
|
||||
'userSig' => $userSig,
|
||||
'patientUserId' => $patientUserId, // 添加患者的userId
|
||||
'expireTime' => 86400
|
||||
];
|
||||
}
|
||||
```
|
||||
|
||||
### 步骤6: 前端使用患者userId发起通话
|
||||
|
||||
修改前端代码,使用后端返回的患者userId:
|
||||
|
||||
```typescript
|
||||
// admin/src/components/video-call/index.vue
|
||||
|
||||
const startCall = async () => {
|
||||
try {
|
||||
// ... 获取签名 ...
|
||||
|
||||
const res = await getCallSignature({
|
||||
diagnosis_id: callInfo.value.diagnosisId,
|
||||
patient_id: callInfo.value.patientId
|
||||
})
|
||||
|
||||
// ... 初始化 ...
|
||||
|
||||
// 发起通话时使用后端返回的 patientUserId
|
||||
await TUICallKitServer.call({
|
||||
userID: res.patientUserId, // 使用后端返回的患者userId
|
||||
type: TUICallType.VIDEO_CALL
|
||||
})
|
||||
} catch (error) {
|
||||
// ... 错误处理 ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 调试步骤
|
||||
|
||||
### 1. 检查患者是否在线
|
||||
|
||||
在Web端发起通话前,可以先检查患者是否在线:
|
||||
|
||||
```typescript
|
||||
// 可以通过腾讯云IM的REST API查询用户在线状态
|
||||
// 或者在发起通话时捕获 60011 错误码(用户不在线)
|
||||
```
|
||||
|
||||
### 2. 查看控制台日志
|
||||
|
||||
**Web端:**
|
||||
- 打开浏览器控制台
|
||||
- 查看发起通话时的userId
|
||||
- 查看是否有错误提示
|
||||
|
||||
**小程序端:**
|
||||
- 打开微信开发者工具控制台
|
||||
- 查看是否收到来电事件
|
||||
- 查看IM登录状态
|
||||
|
||||
### 3. 常见错误码
|
||||
|
||||
- `60011`: 对方不在线 - 小程序端未登录IM或已退出
|
||||
- `60010`: 对方忙线中 - 小程序端正在通话中
|
||||
- `60008`: 对方拒绝了通话
|
||||
- `60009`: 对方未接听(超时)
|
||||
|
||||
## 完整修复代码
|
||||
|
||||
### 后端修改
|
||||
|
||||
```php
|
||||
// server/app/adminapi/logic/tcm/DiagnosisLogic.php
|
||||
|
||||
public static function getCallSignature(array $params)
|
||||
{
|
||||
try {
|
||||
$config = self::getTrtcConfig();
|
||||
|
||||
if (!$config) {
|
||||
self::setError('请先配置腾讯云TRTC参数');
|
||||
return false;
|
||||
}
|
||||
|
||||
$adminId = $params['admin_id'] ?? 0;
|
||||
$patientId = $params['patient_id'] ?? 0;
|
||||
|
||||
if (!$adminId) {
|
||||
self::setError('获取管理员信息失败');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$patientId) {
|
||||
self::setError('获取患者信息失败');
|
||||
return false;
|
||||
}
|
||||
|
||||
// 医生userId
|
||||
$doctorUserId = 'doctor_' . $adminId;
|
||||
|
||||
// 患者userId(必须与小程序端一致)
|
||||
$patientUserId = 'patient_' . $patientId;
|
||||
|
||||
// 生成医生的 UserSig
|
||||
$userSig = self::generateUserSig(
|
||||
$config['sdkAppId'],
|
||||
$config['secretKey'],
|
||||
$doctorUserId
|
||||
);
|
||||
|
||||
if (!$userSig) {
|
||||
self::setError('生成签名失败');
|
||||
return false;
|
||||
}
|
||||
|
||||
// 导入医生账号到IM
|
||||
self::importDoctorAccountToIm($adminId, $doctorUserId);
|
||||
|
||||
// 确保患者账号也已导入IM
|
||||
self::ensurePatientImAccount($patientId, $patientUserId);
|
||||
|
||||
return [
|
||||
'sdkAppId' => (int)$config['sdkAppId'],
|
||||
'userId' => $doctorUserId,
|
||||
'userSig' => $userSig,
|
||||
'patientUserId' => $patientUserId, // 返回患者userId
|
||||
'expireTime' => 86400
|
||||
];
|
||||
} catch (\Exception $e) {
|
||||
self::setError($e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes 确保患者IM账号存在
|
||||
*/
|
||||
private static function ensurePatientImAccount(int $patientId, string $userId): bool
|
||||
{
|
||||
try {
|
||||
// 获取患者信息
|
||||
$diagnosis = Diagnosis::where('patient_id', $patientId)->find();
|
||||
$nick = $diagnosis ? $diagnosis->patient_name : '患者' . $patientId;
|
||||
|
||||
// 调用IM服务导入账号
|
||||
$imService = new \app\common\service\TencentImService();
|
||||
$result = $imService->importAccount($userId, $nick);
|
||||
|
||||
return $result['success'];
|
||||
} catch (\Exception $e) {
|
||||
\think\facade\Log::error('导入患者IM账号失败: ' . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 前端修改
|
||||
|
||||
```typescript
|
||||
// admin/src/components/video-call/index.vue
|
||||
|
||||
const startCall = async () => {
|
||||
try {
|
||||
initializing.value = true
|
||||
callRejected.value = false
|
||||
statusText.value = '正在获取签名...'
|
||||
|
||||
// 获取腾讯云签名
|
||||
const res = await getCallSignature({
|
||||
diagnosis_id: callInfo.value.diagnosisId,
|
||||
patient_id: callInfo.value.patientId
|
||||
})
|
||||
|
||||
if (!res || !res.userSig || !res.patientUserId) {
|
||||
throw new Error('获取签名失败,返回数据不完整')
|
||||
}
|
||||
|
||||
console.log('签名获取成功:', {
|
||||
doctorUserId: res.userId,
|
||||
patientUserId: res.patientUserId,
|
||||
sdkAppId: res.sdkAppId
|
||||
})
|
||||
|
||||
// ... 初始化代码 ...
|
||||
|
||||
// 发起通话 - 使用后端返回的 patientUserId
|
||||
console.log('准备发起通话,目标用户:', res.patientUserId)
|
||||
|
||||
await TUICallKitServer.call({
|
||||
userID: res.patientUserId, // 使用后端返回的患者userId
|
||||
type: TUICallType.VIDEO_CALL
|
||||
})
|
||||
|
||||
console.log('通话已发起')
|
||||
statusText.value = '等待对方接听...'
|
||||
feedback.msgSuccess('通话已发起,等待对方接听...')
|
||||
|
||||
} catch (error: any) {
|
||||
console.error('启动通话失败:', error)
|
||||
|
||||
// 特殊处理用户不在线的情况
|
||||
if (error.code === 60011) {
|
||||
feedback.msgError('患者不在线,请确认患者已打开小程序')
|
||||
} else {
|
||||
const errorMessage = error.message || '启动通话失败,请稍后重试'
|
||||
feedback.msgError(errorMessage)
|
||||
}
|
||||
|
||||
// ... 错误处理 ...
|
||||
} finally {
|
||||
initializing.value = false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 测试清单
|
||||
|
||||
- [ ] 后端返回正确的 patientUserId
|
||||
- [ ] 小程序端使用相同的 userId 格式登录IM
|
||||
- [ ] 小程序端保持在线状态
|
||||
- [ ] Web端使用 patientUserId 发起通话
|
||||
- [ ] 小程序端能收到来电通知
|
||||
- [ ] 小程序端能正常接听
|
||||
- [ ] 视频和音频正常传输
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **userId格式必须完全一致**:Web端和小程序端必须使用相同的userId格式
|
||||
2. **小程序端必须先登录**:在发起通话前,确保小程序端已登录IM
|
||||
3. **检查网络环境**:小程序端需要在HTTPS环境或微信开发者工具中测试
|
||||
4. **版本兼容性**:确保Web端和小程序端使用兼容的TUICallKit版本
|
||||
|
||||
## 相关文档
|
||||
|
||||
- [TUICallKit Web端文档](https://www.tencentcloud.com/document/product/647/50993)
|
||||
- [TUICallKit 小程序端文档](https://www.tencentcloud.com/document/product/647/50994)
|
||||
- [腾讯云IM跨平台通话](https://www.tencentcloud.com/document/product/1047/45907)
|
||||
Reference in New Issue
Block a user