# 能力问卷数据加载调试指南 ## 🔍 问题描述 管理端员工信息面板中,复用的 `@employee-detail-panel` 组件无法显示能力问卷数据,显示"该员工尚未完成能力问卷",但实际上该员工已经完成了问卷。 --- ## 📊 数据流转链路 ``` 1. employees.ts: viewEmployee() ↓ 调用 loadEmployeeSurvey() 2. employees.ts: loadEmployeeSurvey() ↓ 查询 Profile 和 SurveyLog 表 ↓ 返回 { completed, data, profileId } 3. employees.ts: selectedEmployeeForPanel ↓ 包含 surveyCompleted 和 surveyData 4. employee-info-panel.component.html ↓ [employee]="selectedEmployeeForPanel" 5. employee-info-panel.component.ts: employeeDetailForTeamLeader getter ↓ 转换为 TeamLeaderEmployeeDetail 格式 6. ↓ [employeeDetail]="employeeDetailForTeamLeader" 7. employee-detail-panel.html ↓ @if (employeeDetail.surveyCompleted && employeeDetail.surveyData) ``` --- ## 🐛 可能的问题点 ### 问题点 1: Profile 查询失败 **位置**: `employees.ts: loadEmployeeSurvey()` (行 507-558) **检查方法**: ```typescript // 打开浏览器控制台,查找以下日志 🔍 [loadEmployeeSurvey] 查找员工 徐福静 (employeeId),找到 X 个结果 ``` **预期结果**: 找到 1 个结果 **问题结果**: 找到 0 个结果 **原因**: - Employee.id 与 Profile.objectId 不匹配 - Employee.realname 与 Profile.realname/name 不匹配 **解决方案**: ```typescript // 需要确认数据库中的映射关系 // 方法1: 使用 Employee.userid (企微ID) 查询 const useridQuery = new Parse.Query('Profile'); useridQuery.equalTo('userid', emp.userid); // 方法2: 使用 Employee.wxworkId 查询 const wxworkQuery = new Parse.Query('Profile'); wxworkQuery.equalTo('wxworkId', emp.wxworkId); ``` --- ### 问题点 2: SurveyLog 查询失败 **位置**: `employees.ts: loadEmployeeSurvey()` (行 528-539) **检查方法**: ```typescript // 控制台日志 📝 [loadEmployeeSurvey] 找到 X 条问卷记录 ``` **预期结果**: 找到至少 1 条记录 **问题结果**: 找到 0 条记录 **原因**: - `type = 'survey-profile'` 不匹配(可能是其他 type 值) - `profile` Pointer 不匹配 **解决方案**: ```typescript // 先查询所有该用户的 SurveyLog const allSurveyQuery = new Parse.Query('SurveyLog'); allSurveyQuery.equalTo('profile', profile.toPointer()); allSurveyQuery.descending('createdAt'); const allSurveys = await allSurveyQuery.find(); console.log('📝 所有问卷记录:', allSurveys.map(s => ({ type: s.get('type'), answers: s.get('answers')?.length }))); ``` --- ### 问题点 3: surveyCompleted 标记错误 **位置**: `employees.ts: loadEmployeeSurvey()` (行 522) **检查方法**: ```typescript // 控制台日志 📋 [loadEmployeeSurvey] Profile ID: xxx, surveyCompleted: false ``` **预期结果**: `surveyCompleted: true` **问题结果**: `surveyCompleted: false` **原因**: - Profile 表中的 `surveyCompleted` 字段未正确更新 - 字段名称不匹配(可能是 `survey_completed` 或其他) **解决方案**: ```typescript // 检查 Profile 的所有字段 const profile = profileResults[0]; console.log('📋 Profile 所有字段:', profile.attributes); console.log('📋 surveyCompleted 字段值:', profile.get('surveyCompleted')); console.log('📋 survey_completed 字段值:', profile.get('survey_completed')); ``` --- ### 问题点 4: 数据传递丢失 **位置**: `employee-info-panel.component.ts: employeeDetailForTeamLeader` (行 149-180) **检查方法**: ```typescript // 控制台日志 ✅ [employeeDetailForTeamLeader] 转换完成: { surveyCompleted: true/false, hasSurveyData: true/false } ``` **预期结果**: ```javascript surveyCompleted: true hasSurveyData: true surveyData: { answers: [...], createdAt: Date } ``` **问题结果**: ```javascript surveyCompleted: false hasSurveyData: false surveyData: undefined ``` **原因**: - `this.employee` 中没有 `surveyCompleted` 或 `surveyData` 字段 - 数据在 `employees.ts` 到 `employee-info-panel` 的传递中丢失 **解决方案**: ```typescript // 在 employees.ts 中添加更详细的日志 console.log('🎯 [Employees] selectedEmployeeForPanel 完整内容:', { ...this.selectedEmployeeForPanel, surveyCompleted: this.selectedEmployeeForPanel.surveyCompleted, surveyData: this.selectedEmployeeForPanel.surveyData }); ``` --- ## 🔧 调试步骤 ### 步骤 1: 打开浏览器控制台 按 `F12` 打开开发者工具,切换到 `Console` 标签。 ### 步骤 2: 清空控制台 点击控制台左上角的 🚫 图标,清空所有日志。 ### 步骤 3: 点击员工"徐福静" 在员工列表中点击"徐福静",打开员工信息面板。 ### 步骤 4: 查看控制台输出 按照以下顺序查找日志: #### 日志 1: 员工数据加载开始 ```javascript 🚀 [Employees] 开始打开员工信息面板: 徐福静 (employeeId) ``` #### 日志 2: 问卷数据查询 ```javascript 🔍 [loadEmployeeSurvey] 查找员工 徐福静 (employeeId),找到 X 个结果 ``` - ✅ 如果 X = 1,继续 - ❌ 如果 X = 0,问题在 Profile 查询,跳到**问题点 1** #### 日志 3: Profile 信息 ```javascript 📋 [loadEmployeeSurvey] Profile ID: xxx, surveyCompleted: true/false ``` - ✅ 如果 `surveyCompleted: true`,继续 - ❌ 如果 `surveyCompleted: false`,问题在 Profile 标记,跳到**问题点 3** #### 日志 4: SurveyLog 查询 ```javascript 📝 [loadEmployeeSurvey] 找到 X 条问卷记录 ``` - ✅ 如果 X >= 1,继续 - ❌ 如果 X = 0,问题在 SurveyLog 查询,跳到**问题点 2** #### 日志 5: 问卷数据加载成功 ```javascript ✅ [loadEmployeeSurvey] 问卷数据加载成功,共 X 道题 ``` - ✅ 如果 X > 0,继续 - ❌ 如果 X = 0,问题在答案数据 #### 日志 6: 完整数据准备 ```javascript 📝 [Employees] 问卷数据加载完成: { completed: true, answers: X } 🎯 [Employees] 完整数据准备完成,打开面板: { surveyData: '✅' } ``` - ✅ 如果 `surveyData: '✅'`,继续 - ❌ 如果 `surveyData: '❌'`,数据未正确传递 #### 日志 7: 数据转换 ```javascript ✅ [employeeDetailForTeamLeader] 转换完成: { surveyCompleted: true, hasSurveyData: true } ``` - ✅ 如果两者都是 true,数据传递成功 - ❌ 如果任一为 false,跳到**问题点 4** #### 日志 8: 完整数据结构 ```javascript 📦 [employeeDetailForTeamLeader] 完整数据结构: { employee: {...}, result: { surveyCompleted: true, surveyData: {...} } } ``` - ✅ 展开查看 `result.surveyData` 是否包含 `answers` 数组 --- ## 🛠️ 快速修复方案 ### 方案 A: 增强日志(推荐) 在 `employees.ts` 的 `loadEmployeeSurvey` 方法中添加更多日志: ```typescript // 在 line 507 附近添加 console.log('🔍 [loadEmployeeSurvey] 查询参数:', { employeeId, employeeName, useridQuery: emp.userid, wxworkId: emp.wxworkId }); // 在 line 514 附近添加 if (profileResults.length > 0) { const profile = profileResults[0]; console.log('📋 [loadEmployeeSurvey] Profile 完整信息:', { id: profile.id, realname: profile.get('realname'), name: profile.get('name'), surveyCompleted: profile.get('surveyCompleted'), allAttributes: profile.attributes }); } // 在 line 528 附近添加 console.log('📝 [loadEmployeeSurvey] SurveyLog 查询参数:', { profileId: profile.id, profilePointer: profile.toPointer(), type: 'survey-profile' }); // 在 line 531 附近添加 console.log('📝 [loadEmployeeSurvey] SurveyLog 查询结果:', { count: surveyResults.length, surveys: surveyResults.map(s => ({ id: s.id, type: s.get('type'), answersCount: s.get('answers')?.length, createdAt: s.get('createdAt') })) }); ``` ### 方案 B: 备用查询逻辑 如果 `type = 'survey-profile'` 查询不到,尝试其他 type: ```typescript // 在 loadEmployeeSurvey 方法中,line 528 附近 if (surveyCompleted) { // 先尝试 'survey-profile' type let surveyQuery = new Parse.Query('SurveyLog'); surveyQuery.equalTo('profile', profile.toPointer()); surveyQuery.equalTo('type', 'survey-profile'); surveyQuery.descending('createdAt'); surveyQuery.limit(1); let surveyResults = await surveyQuery.find(); console.log(`📝 [loadEmployeeSurvey] 找到 'survey-profile' 类型: ${surveyResults.length} 条`); // 如果找不到,尝试不限制 type if (surveyResults.length === 0) { console.warn(`⚠️ [loadEmployeySurvey] 'survey-profile' 类型未找到,尝试查询所有类型`); surveyQuery = new Parse.Query('SurveyLog'); surveyQuery.equalTo('profile', profile.toPointer()); surveyQuery.descending('createdAt'); surveyQuery.limit(1); surveyResults = await surveyQuery.find(); console.log(`📝 [loadEmployeeSurvey] 找到所有类型: ${surveyResults.length} 条`); } if (surveyResults.length > 0) { const survey = surveyResults[0]; const surveyData = { answers: survey.get('answers') || [], createdAt: survey.get('createdAt'), updatedAt: survey.get('updatedAt') }; console.log(`✅ [loadEmployeeSurvey] 问卷数据加载成功,type: ${survey.get('type')}, 共 ${surveyData.answers.length} 道题`); return { completed: true, data: surveyData, profileId }; } } ``` ### 方案 C: 直接使用组长端逻辑 组长端的 `dashboard.ts` 中已经有正确的查询逻辑(line 3184-3237),可以完全复用: ```typescript // 在 employees.ts 中,复制组长端的查询逻辑 private async loadEmployeeSurvey(employeeId: string, employeeName: string): Promise<{ completed: boolean; data: any; profileId: string }> { try { const Parse = await import('fmode-ng/parse').then(m => m.FmodeParse.with('nova')); // 💡 完全复用组长端的查询逻辑 // 通过员工名字查找Profile(同时查询 realname 和 name 字段) const realnameQuery = new Parse.Query('Profile'); realnameQuery.equalTo('realname', employeeName); const nameQuery = new Parse.Query('Profile'); nameQuery.equalTo('name', employeeName); // 使用 or 查询 const profileQuery = Parse.Query.or(realnameQuery, nameQuery); profileQuery.limit(1); const profileResults = await profileQuery.find(); console.log(`🔍 查找员工 ${employeeName},找到 ${profileResults.length} 个结果`); if (profileResults.length > 0) { const profile = profileResults[0]; const profileId = profile.id; const surveyCompleted = profile.get('surveyCompleted') || false; console.log(`📋 Profile ID: ${profileId}, surveyCompleted: ${surveyCompleted}`); // 如果已完成问卷,加载问卷答案 if (surveyCompleted) { const surveyQuery = new Parse.Query('SurveyLog'); surveyQuery.equalTo('profile', profile.toPointer()); surveyQuery.equalTo('type', 'survey-profile'); surveyQuery.descending('createdAt'); surveyQuery.limit(1); const surveyResults = await surveyQuery.find(); console.log(`📝 找到 ${surveyResults.length} 条问卷记录`); if (surveyResults.length > 0) { const survey = surveyResults[0]; const surveyData = { answers: survey.get('answers') || [], createdAt: survey.get('createdAt'), updatedAt: survey.get('updatedAt') }; console.log(`✅ 加载问卷数据成功,共 ${surveyData.answers.length} 道题`); return { completed: true, data: surveyData, profileId }; } } return { completed: false, data: null, profileId }; } else { console.warn(`⚠️ 未找到员工 ${employeeName} 的 Profile`); return { completed: false, data: null, profileId: '' }; } } catch (error) { console.error(`❌ 加载员工 ${employeeName} 问卷数据失败:`, error); return { completed: false, data: null, profileId: '' }; } } ``` --- ## 📋 检查清单 在提交问题或进行修复前,请完成以下检查: - [ ] 确认控制台中有 "🔍 [loadEmployeeSurvey] 查找员工..." 日志 - [ ] 确认 Profile 查询结果 > 0 - [ ] 确认 `surveyCompleted` 字段为 `true` - [ ] 确认 SurveyLog 查询结果 > 0 - [ ] 确认 `answers` 数组有数据 - [ ] 确认 `selectedEmployeeForPanel.surveyData` 有值 - [ ] 确认 `employeeDetailForTeamLeader.surveyData` 有值 - [ ] 确认 HTML 模板中的条件 `@if (employeeDetail.surveyCompleted && employeeDetail.surveyData)` 被满足 --- ## 🎯 预期结果 修复后,在控制台应该看到完整的数据链路: ```javascript 🚀 [Employees] 开始打开员工信息面板: 徐福静 🔄 [Employees] 预加载员工数据... ✅ [Employees] 项目数据加载完成: { currentProjects: 3, ... } 📅 [Employees] 日历数据生成完成: { days: 42, 有项目的天数: 15 } 🔍 [loadEmployeeSurvey] 查找员工 徐福静,找到 1 个结果 📋 [loadEmployeeSurvey] Profile ID: xxx, surveyCompleted: true 📝 [loadEmployeeSurvey] 找到 1 条问卷记录 ✅ [loadEmployeeSurvey] 问卷数据加载成功,共 25 道题 // ✅ 关键 📝 [Employees] 问卷数据加载完成: { completed: true, answers: 25 } 🎯 [Employees] 完整数据准备完成,打开面板: { surveyData: '✅' } ✅ [Employees] 面板已显示 🔍 [employeeDetailForTeamLeader] 开始转换 ✅ [employeeDetailForTeamLeader] 转换完成: { surveyCompleted: true, // ✅ 关键 hasSurveyData: true // ✅ 关键 } ``` 然后在页面上应该能看到: - ✅ "已完成问卷" 状态 - ✅ 问卷完成时间 - ✅ 能力画像摘要 - ✅ "查看完整问卷(共 25 道题)" 按钮 --- **文档版本**: v1.0 **创建日期**: 2025-11-10 **状态**: 调试指南