# 修复SDKAppID类型错误 ## 问题描述 在启动视频通话时,TUICallKit报错: ``` Error: 【CallService】API: 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` ```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 方法 ```php // 修改前 return [ 'sdkAppId' => $config['sdkAppId'], // ❌ 可能是字符串 // ... ]; // 修改后 return [ 'sdkAppId' => (int)$config['sdkAppId'], // ✅ 确保返回整数 // ... ]; ``` #### getPatientSignature 方法 ```php // 从数据库读取时 return [ 'sdkAppId' => (int)$patientTrtc->sdk_app_id, // ✅ 确保返回整数 // ... ]; // 新生成时 return [ 'sdkAppId' => (int)$config['sdkAppId'], // ✅ 确保返回整数 // ... ]; ``` ### 3. 前端转换(第三道防线) **文件**:`admin/src/components/video-call/index.vue` ```typescript // 修改前 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. 清除配置缓存 ```bash # 如果使用了配置缓存 cd server php think clear ``` ### 2. 测试医生通话 ```bash # 登录管理后台 # 进入诊单详情 # 点击"视频通话"按钮 # 查看浏览器控制台 ``` **预期输出**: ``` 签名获取成功: { userId: "doctor_1", sdkAppId: 1600127710 } TUICallKit init 方法调用完成 等待完成,准备显示通话界面 初始化完成,准备发起通话... ``` **不应该出现**: ``` ❌ Error: SDKAppID must be Number, current SDKAppID is string ``` ### 3. 测试患者通话 ```bash # 打开患者测试页面 # 点击"初始化"按钮 # 查看浏览器控制台 ``` 应该能正常初始化,不报类型错误。 ### 4. 验证数据类型 在浏览器控制台执行: ```javascript // 获取签名后 console.log(typeof res.sdkAppId) // 应该输出 "number" // 传递给TUICallKit前 console.log(typeof Number(res.sdkAppId)) // 应该输出 "number" ``` ## 技术细节 ### PHP类型转换 ```php // 方式1:强制类型转换(推荐) $intValue = (int)$stringValue; // 方式2:intval函数 $intValue = intval($stringValue); // 示例 $str = "1600127710"; $int = (int)$str; // 1600127710 (整数) ``` ### JavaScript类型转换 ```javascript // 方式1:Number构造函数(推荐) const numValue = Number(strValue) // 方式2:parseInt函数 const numValue = parseInt(strValue, 10) // 方式3:一元加号运算符 const numValue = +strValue // 示例 const str = "1600127710" const num = Number(str) // 1600127710 (数字) ``` ### 类型检查 ```javascript // JavaScript typeof 1600127710 // "number" ✅ typeof "1600127710" // "string" ❌ typeof Number("1600127710") // "number" ✅ ``` ```php // 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" ## 相关文档 - [FIX_ADMIN_ID.md](./FIX_ADMIN_ID.md) - 管理员ID获取修复 - [DOCTOR_IM_ACCOUNT.md](./DOCTOR_IM_ACCOUNT.md) - 医生账号导入功能 - [QUICK_START.md](./QUICK_START.md) - 快速开始指南 ## 更新日志 ### 2026-03-02 - ✅ 修复配置层:添加 `(int)` 转换 - ✅ 修复Logic层:3处返回值添加 `(int)` 转换 - ✅ 修复前端层:添加 `Number()` 转换 - ✅ 采用多层防护策略,确保类型正确 --- **现在SDKAppID类型正确,TUICallKit应该能正常初始化了!** ✅