Files
zyt/FIX_SDKAPPID_TYPE.md
T
2026-03-04 15:32:30 +08:00

6.8 KiB
Raw Blame History

修复SDKAppID类型错误

问题描述

在启动视频通话时,TUICallKit报错:

Error: 【CallService】API<init>: SDKAppID must be Number, current SDKAppID is string.

问题原因

TUICallKit的 init() 方法要求 SDKAppID 参数必须是 Number(数字)类型,但系统传递的是 String(字符串)类型

问题链路

.env 文件
    ↓ (env() 函数读取,返回字符串)
config/project.php
    ↓ (配置读取)
DiagnosisLogic.php
    ↓ (API返回)
前端 video-call 组件
    ↓ (传递给TUICallKit)
❌ 类型错误:期望Number,实际String

根本原因

  1. 环境变量读取env() 函数从 .env 文件读取的值默认是字符串
  2. 配置未转换config/project.php 中没有将字符串转换为整数
  3. 前端未转换:前端组件直接使用后端返回的值

解决方案

采用多层防护策略,在多个位置确保类型正确:

1. 配置层转换(第一道防线)

文件server/config/project.php

// 修改前
'trtc' => [
    'sdkAppId' => env('trtc.sdk_app_id', 1600127710),  // ❌ 可能返回字符串
    // ...
]

// 修改后
'trtc' => [
    'sdkAppId' => (int)env('trtc.sdk_app_id', 1600127710),  // ✅ 强制转换为整数
    // ...
]

2. Logic层转换(第二道防线)

文件server/app/adminapi/logic/tcm/DiagnosisLogic.php

getCallSignature 方法

// 修改前
return [
    'sdkAppId' => $config['sdkAppId'],  // ❌ 可能是字符串
    // ...
];

// 修改后
return [
    'sdkAppId' => (int)$config['sdkAppId'],  // ✅ 确保返回整数
    // ...
];

getPatientSignature 方法

// 从数据库读取时
return [
    'sdkAppId' => (int)$patientTrtc->sdk_app_id,  // ✅ 确保返回整数
    // ...
];

// 新生成时
return [
    'sdkAppId' => (int)$config['sdkAppId'],  // ✅ 确保返回整数
    // ...
];

3. 前端转换(第三道防线)

文件admin/src/components/video-call/index.vue

// 修改前
await TUICallKitServer.init({
    userID: res.userId,
    userSig: res.userSig,
    SDKAppID: res.sdkAppId  // ❌ 可能是字符串
})

// 修改后
await TUICallKitServer.init({
    userID: res.userId,
    userSig: res.userSig,
    SDKAppID: Number(res.sdkAppId)  // ✅ 强制转换为数字
})

修改的文件

  1. server/config/project.php - 配置层转换
  2. server/app/adminapi/logic/tcm/DiagnosisLogic.php - Logic层转换(3处)
  3. admin/src/components/video-call/index.vue - 前端转换

为什么需要多层防护?

单层防护的风险

如果只在一个地方转换,可能会遇到:

  1. 配置缓存问题:配置文件修改后可能需要清除缓存
  2. 数据库存储问题:数据库中可能存储了字符串类型
  3. API传输问题JSON传输可能改变数据类型
  4. 前端解析问题:JavaScript可能将数字解析为字符串

多层防护的优势

配置层 ✅ → Logic层 ✅ → 前端 ✅ → TUICallKit ✅

即使某一层失效,其他层仍能保证类型正确。

测试方法

1. 清除配置缓存

# 如果使用了配置缓存
cd server
php think clear

2. 测试医生通话

# 登录管理后台
# 进入诊单详情
# 点击"视频通话"按钮
# 查看浏览器控制台

预期输出

签名获取成功: { userId: "doctor_1", sdkAppId: 1600127710 }
TUICallKit init 方法调用完成
等待完成,准备显示通话界面
初始化完成,准备发起通话...

不应该出现

❌ Error: SDKAppID must be Number, current SDKAppID is string

3. 测试患者通话

# 打开患者测试页面
# 点击"初始化"按钮
# 查看浏览器控制台

应该能正常初始化,不报类型错误。

4. 验证数据类型

在浏览器控制台执行:

// 获取签名后
console.log(typeof res.sdkAppId)  // 应该输出 "number"

// 传递给TUICallKit前
console.log(typeof Number(res.sdkAppId))  // 应该输出 "number"

技术细节

PHP类型转换

// 方式1:强制类型转换(推荐)
$intValue = (int)$stringValue;

// 方式2intval函数
$intValue = intval($stringValue);

// 示例
$str = "1600127710";
$int = (int)$str;  // 1600127710 (整数)

JavaScript类型转换

// 方式1:Number构造函数(推荐)
const numValue = Number(strValue)

// 方式2parseInt函数
const numValue = parseInt(strValue, 10)

// 方式3:一元加号运算符
const numValue = +strValue

// 示例
const str = "1600127710"
const num = Number(str)  // 1600127710 (数字)

类型检查

// JavaScript
typeof 1600127710        // "number" ✅
typeof "1600127710"      // "string" ❌
typeof Number("1600127710")  // "number" ✅
// PHP
is_int(1600127710)       // true ✅
is_int("1600127710")     // false ❌
is_int((int)"1600127710")  // true ✅

常见问题

Q1: 为什么env()返回字符串?

.env 文件是纯文本文件,所有值都是字符串。PHP的 env() 函数不会自动转换类型。

Q2: 配置文件修改后需要重启吗?

  • 开发环境:不需要,每次请求都会重新读取
  • 生产环境:如果使用了配置缓存,需要清除缓存

Q3: 数据库中的sdk_app_id是什么类型?

  • 如果字段类型是 int,存储的是整数
  • 如果字段类型是 varchar,存储的是字符串
  • 读取时需要转换:(int)$model->sdk_app_id

Q4: JSON传输会改变类型吗?

  • PHP的 json_encode() 会保持整数类型
  • JavaScript的 JSON.parse() 也会保持整数类型
  • 但如果PHP端是字符串,传到前端也是字符串

Q5: 为什么前端还要转换?

  • 防御性编程,确保类型正确
  • 即使后端返回字符串,前端也能处理
  • 提高代码健壮性

验证清单

  • 配置文件已添加 (int) 转换
  • Logic层所有返回都添加了 (int) 转换
  • 前端组件添加了 Number() 转换
  • 清除了配置缓存(如果有)
  • 测试医生通话,不报类型错误
  • 测试患者通话,不报类型错误
  • 浏览器控制台验证类型为 "number"

相关文档

更新日志

2026-03-02

  • 修复配置层:添加 (int) 转换
  • 修复Logic层:3处返回值添加 (int) 转换
  • 修复前端层:添加 Number() 转换
  • 采用多层防护策略,确保类型正确

现在SDKAppID类型正确,TUICallKit应该能正常初始化了!