# 企业微信SDK初始化问题修复 **日期**: 2025-10-24 **问题**: 访问项目详情页面时报错 `TypeError: Cannot set properties of null (setting 'cid')` --- ## 🔴 问题分析 ### 错误现场 - **URL**: `http://localhost:4200/admin/project-detail/iKvYck89zE/order` - **错误**: `TypeError: Cannot set properties of null (setting 'cid')` - **错误位置**: - `wxwork.auth.mjs:8:1666` - `wxwork.sdk.mjs:8:4611` - `project-detail.component.ts:236` ### 根本原因 #### 1. **ProjectService 数据源问题** (已解决) **问题**: - 项目管理页面使用 `admin/services/ProjectService`,从Parse数据库查询真实数据 - 项目ID是真实的Parse objectId:`7EFEsEd0ht`, `iKvYck89zE` 等 - 项目详情页面使用通用的 `services/ProjectService`,只有模拟数据 - 模拟数据ID:`proj-001`, `2`, `3` 等 - 结果:查询返回 `undefined`,导致后续操作失败 **解决方案**: 修改 `src/app/services/project.service.ts` 的 `getProjectById` 方法,优先从Parse查询真实数据: ```typescript getProjectById(id: string): Observable { return new Observable(observer => { this.getProjectFromParse(id).then(project => { if (project) { observer.next(project); } else { // 降级:使用模拟数据 observer.next(this.projects.find(project => project.id === id)); } observer.complete(); }).catch(error => { console.error('查询项目失败,使用模拟数据:', error); observer.next(this.projects.find(project => project.id === id)); observer.complete(); }); }); } ``` #### 2. **企业微信SDK初始化缺少cid参数** (本次修复重点) **问题**: 管理员端项目详情页 (`modules/project/pages/project-detail/project-detail.component.ts`) 在初始化企微SDK时: ```typescript // ❌ 旧代码 async initWxworkAuth() { let cid = this.cid || localStorage.getItem("company") || ""; this.wxAuth = new WxworkAuth({ cid: cid}); // cid为空时会报错 this.wxwork = new WxworkSDK({ cid: cid, appId: 'crm' }); this.wecorp = new WxworkCorp(cid); } ``` **原因**: 1. 管理员端路由是 `/admin/project-detail/:projectId`,没有 `:cid` 参数 2. `this.cid` 从路由获取为空 3. 如果 `localStorage.getItem("company")` 也为空,`cid` 就是空字符串 4. 传入空字符串到 `WxworkSDK` 导致内部初始化失败:`Cannot set properties of null (setting 'cid')` **错误链**: ``` ngOnInit() → initWxworkAuth() → new WxworkSDK({ cid: "" }) → 内部尝试设置 null.cid → TypeError ``` --- ## ✅ 解决方案 ### 1. 修复 modules/project 的项目详情组件 **文件**: `src/modules/project/pages/project-detail/project-detail.component.ts` **修改点**: #### A. 添加cid空值检查 ```typescript async initWxworkAuth() { try { let cid = this.cid || localStorage.getItem("company") || ""; // ✅ 如果没有cid,记录警告但不抛出错误 if (!cid) { console.warn('⚠️ 未找到company ID (cid),企微功能将不可用'); return; // 不初始化SDK,避免错误 } this.wxAuth = new WxworkAuth({ cid: cid }); this.wxwork = new WxworkSDK({ cid: cid, appId: 'crm' }); this.wecorp = new WxworkCorp(cid); console.log('✅ 企微SDK初始化成功,cid:', cid); } catch (error) { console.error('❌ 企微SDK初始化失败:', error); // 不阻塞页面加载 } } ``` #### B. 添加获取用户Profile的错误处理 ```typescript // 2. 获取当前用户(优先从全局服务获取) if (!this.currentUser?.id && this.wxAuth) { try { this.currentUser = await this.wxAuth.currentProfile(); } catch (error) { console.warn('⚠️ 获取当前用户Profile失败:', error); } } ``` ### 2. 修复 designer 的项目详情组件 **文件**: `src/app/pages/designer/project-detail/project-detail.ts` **修改点**:在 constructor 中添加企微认证初始化 ```typescript constructor( private route: ActivatedRoute, private projectService: ProjectService, private router: Router, private fb: FormBuilder, private cdr: ChangeDetectorRef, private paymentVoucherService: PaymentVoucherRecognitionService, private projectReviewService: ProjectReviewService, private colorAnalysisService: ColorAnalysisService ) { // 初始化企业微信认证 this.loadProfile(); } // 当前用户信息 currentUser: any = {}; /** * 加载当前用户Profile */ async loadProfile() { try { const cid = localStorage.getItem("company"); if (cid) { const { WxworkAuth } = await import('fmode-ng/core'); const wwAuth = new WxworkAuth({ cid: cid }); const profile = await wwAuth.currentProfile(); if (profile) { this.currentUser = { name: profile.get("name") || profile.get("mobile"), avatar: profile.get("avatar"), roleName: profile.get("roleName") }; console.log('✅ 用户Profile加载成功:', this.currentUser); } } else { console.warn('⚠️ localStorage中未找到company(cid)'); } } catch (error) { console.error('❌ 加载用户Profile失败:', error); } } ``` --- ## 📋 涉及文件 ### 修改的文件 1. ✅ `src/app/services/project.service.ts` - 修改 `getProjectById()` 方法 - 添加 `getProjectFromParse()` 私有方法 2. ✅ `src/modules/project/pages/project-detail/project-detail.component.ts` - 修改 `initWxworkAuth()` 方法,添加cid空值检查 - 修改 `loadData()` 方法,添加获取用户错误处理 3. ✅ `src/app/pages/designer/project-detail/project-detail.ts` - 修改 constructor,添加企微认证初始化 - 添加 `loadProfile()` 方法 - 添加 `currentUser` 属性 --- ## 🎯 核心原则 ### 企业微信SDK初始化最佳实践 根据 `rules/wxwork/auth.md` 和 `rules/wxwork/guard-wxwork.md`: #### 1. **必须提供cid参数** ```typescript // ✅ 正确 const cid = localStorage.getItem("company"); if (cid) { const wxAuth = new WxworkAuth({ cid: cid }); } // ❌ 错误:可能传入空字符串 const cid = this.cid || ""; // cid可能为空 const wxAuth = new WxworkAuth({ cid: cid }); // 会报错 ``` #### 2. **参考客服端和管理员端的正确写法** **客服端** (`customer-service/dashboard/dashboard.ts`): ```typescript async loadProfile() { let cid = localStorage.getItem("company"); if (cid) { let wwAuth = new WxworkAuth({cid:cid}) let profile = await wwAuth.currentProfile(); this.currentUser = { name: profile?.get("name") || profile?.get("mobile"), avatar: profile?.get("avatar"), roleName: profile?.get("roleName") } } } ``` **管理员端** (`admin/dashboard/dashboard.ts`): ```typescript import { WxworkAuth } from 'fmode-ng/core'; // 使用时先检查cid ``` #### 3. **错误处理原则** ```typescript // ✅ 推荐:try-catch包裹,不阻塞页面 try { const cid = localStorage.getItem("company"); if (!cid) { console.warn('未找到cid,企微功能不可用'); return; // 提前返回,不初始化 } const wxAuth = new WxworkAuth({ cid }); // ... 其他初始化 } catch (error) { console.error('初始化失败:', error); // 页面仍然可以继续加载 } ``` --- ## 🧪 测试验证 ### 测试步骤 1. **清除localStorage中的company** ```javascript localStorage.removeItem("company"); ``` 2. **访问管理员项目详情页** ``` http://localhost:4200/admin/project-detail/iKvYck89zE/order ``` 3. **预期结果** - ✅ 页面正常加载,不报错 - ✅ 控制台显示警告:`⚠️ 未找到company ID (cid),企微功能将不可用` - ✅ 项目数据正常显示(从Parse查询) - ⚠️ 企微相关功能不可用(用户头像、企微聊天等) 4. **设置cid后重新测试** ```javascript localStorage.setItem("company", "cDL6R1hgSi"); // 使用真实的公司ID ``` 5. **刷新页面** - ✅ 企微SDK初始化成功 - ✅ 用户Profile加载成功 - ✅ 所有功能正常 --- ## 📖 相关文档 - `rules/wxwork/guard-wxwork.md` - 企业微信路由守卫使用指南 - `rules/wxwork/auth.md` - 企业微信认证方法文档 - `docs/task/2025102216-team-leader-database-integration.md` - Parse数据库集成文档 --- ## 🎉 总结 ### 修复前 - ❌ 访问项目详情页报错 `TypeError: Cannot set properties of null` - ❌ 页面无法正常加载 - ❌ 项目数据查询失败(数据源不一致) ### 修复后 - ✅ 页面正常加载,不再报错 - ✅ 企微SDK初始化有完善的错误处理 - ✅ cid缺失时给出友好提示,不阻塞页面 - ✅ 项目数据从Parse数据库正确查询 - ✅ 用户Profile加载有错误处理机制 ### 核心改进 1. **防御性编程**: 所有企微SDK初始化都添加了空值检查 2. **优雅降级**: cid缺失时不初始化SDK,但不影响页面基本功能 3. **错误隔离**: 企微相关错误不会影响项目数据加载 4. **统一模式**: 所有页面遵循相同的初始化模式 --- **修复完成!** ✨