企业微信身份激活与问卷调试指南.md 17 KB

企业微信身份激活与问卷整合调试指南

📋 目录

  1. 功能概述
  2. 调试方法总览
  3. 方法1:使用测试工具页面(推荐)
  4. 方法2:浏览器Console调试
  5. 方法3:真实企微环境测试
  6. 常见问题排查
  7. 数据库Schema说明

功能概述

完整流程

员工扫码进入企微应用
    ↓
WxworkAuth.authenticateAndLogin()
    ↓
身份激活/Profile同步
    ↓
跳转到设计师工作台
    ↓
检查 Profile.surveyCompleted
    ↓
未完成 → 显示问卷引导弹窗 → 跳转问卷页面
    ↓
已完成 → 正常使用工作台

涉及的核心代码文件

  1. 身份激活

    • src/app/pages/designer/dashboard/dashboard.ts - 工作台认证逻辑
    • fmode-ng/coreWxworkAuth - 企微SDK
  2. 问卷功能

    • src/modules/profile/pages/profile-survey/profile-survey.component.ts - 问卷组件
    • src/app/pages/designer/dashboard/dashboard.ts - 问卷引导逻辑
  3. 组长查看

    • src/app/pages/team-leader/dashboard/dashboard.ts - 组长端查看问卷

调试方法总览

方法 适用场景 优点 缺点
测试工具页面 本地开发调试 可视化、直观、易操作 需要编译运行
Console调试 快速验证 最快速、无需额外代码 需要手动输入命令
真实企微环境 最终验证 最真实 需要配置外网域名

方法1:使用测试工具页面(推荐)

1.1 启动测试工具

步骤1:启动开发服务器

ng serve

步骤2:访问测试页面

浏览器打开:
http://localhost:4200/test-wxwork-activation/test

其中 test 是公司ID(cid),可以替换为:

  • test - 测试公司
  • demo - 演示公司
  • 或您的真实公司ID

1.2 测试工具功能

测试页面提供以下功能:

📊 显示测试步骤进度

✓ 1. 初始化企微认证
✓ 2. 执行身份激活
✓ 3. 检查问卷状态
✓ 4. 跳转到相应页面

📝 实时执行日志

10:30:15  获取公司ID: test
10:30:16  初始化企微认证...
10:30:17  ✅ 企微认证初始化成功
10:30:18  执行身份激活...
10:30:19  ✅ 身份激活成功: 王刚
10:30:20     角色: 组员
10:30:21  检查问卷状态...
10:30:22  ⚠️ 问卷未完成
10:30:23  测试完成!

👤 员工信息展示

员工ID:    woAs2qCQAAPjkaSBZg3GVdXjIG3vxAOg
姓名:      王刚
角色:      组员
问卷状态:  ❌ 未完成

🔧 测试操作按钮

  1. 开始测试 - 执行完整的激活+问卷检查流程
  2. 重置问卷状态 - 将问卷状态改为未完成(用于重复测试)
  3. 前往问卷页面 - 跳转到问卷填写页面
  4. 前往工作台 - 跳转到设计师工作台

1.3 测试场景示例

场景1:测试首次激活流程

1. 访问测试页面
2. 点击"开始测试"
3. 等待测试完成
4. 查看员工信息,确认问卷状态为"未完成"
5. 点击"前往工作台"
6. 验证是否显示问卷引导弹窗

场景2:测试问卷填写流程

1. 在测试页面点击"前往问卷页面"
2. 填写21个问题
3. 提交问卷
4. 返回测试页面
5. 点击"开始测试"刷新状态
6. 确认问卷状态变为"已完成"

场景3:测试重复激活

1. 完成问卷后,点击"重置问卷状态"
2. 点击"前往工作台"
3. 验证是否再次显示问卷引导弹窗

方法2:浏览器Console调试

2.1 重置问卷状态

打开任意页面,按 F12 打开Console,粘贴以下代码:

// 重置问卷状态函数
async function resetSurvey() {
  // 动态加载Parse SDK
  const Parse = (await import('https://api.fmode.cn/parse/sdk.js')).default;
  Parse.initialize('nova');
  Parse.serverURL = 'https://api.fmode.cn/parse';
  
  // 获取当前Profile ID
  const profileId = localStorage.getItem('Parse/ProfileId');
  
  if (!profileId) {
    console.error('❌ 未找到Profile ID,请先登录');
    return;
  }
  
  // 查询并更新Profile
  const Profile = Parse.Object.extend('Profile');
  const query = new Parse.Query(Profile);
  
  try {
    const profile = await query.get(profileId);
    
    console.log('当前问卷状态:', profile.get('surveyCompleted'));
    
    // 重置为未完成
    profile.set('surveyCompleted', false);
    profile.unset('surveyCompletedAt');
    profile.unset('surveyLogId');
    
    await profile.save();
    
    console.log('✅ 问卷状态已重置为未完成');
    console.log('🔄 刷新页面以查看效果');
    
    // 自动刷新
    setTimeout(() => location.reload(), 1000);
    
  } catch (error) {
    console.error('❌ 重置失败:', error);
  }
}

// 执行重置
resetSurvey();

2.2 查看问卷状态

async function checkSurveyStatus() {
  const Parse = (await import('https://api.fmode.cn/parse/sdk.js')).default;
  Parse.initialize('nova');
  Parse.serverURL = 'https://api.fmode.cn/parse';
  
  const profileId = localStorage.getItem('Parse/ProfileId');
  
  if (!profileId) {
    console.error('❌ 未找到Profile ID');
    return;
  }
  
  const Profile = Parse.Object.extend('Profile');
  const query = new Parse.Query(Profile);
  
  try {
    const profile = await query.get(profileId);
    
    console.log('==== 员工信息 ====');
    console.log('员工ID:', profile.id);
    console.log('姓名:', profile.get('realname') || profile.get('name'));
    console.log('角色:', profile.get('roleName'));
    console.log('问卷状态:', profile.get('surveyCompleted') ? '✅ 已完成' : '❌ 未完成');
    
    if (profile.get('surveyCompletedAt')) {
      console.log('完成时间:', profile.get('surveyCompletedAt'));
    }
    
    // 如果已完成,查询问卷答案
    if (profile.get('surveyCompleted')) {
      const SurveyLog = Parse.Object.extend('SurveyLog');
      const surveyQuery = new Parse.Query(SurveyLog);
      surveyQuery.equalTo('profile', profile.toPointer());
      surveyQuery.equalTo('type', 'survey-profile');
      surveyQuery.descending('createdAt');
      surveyQuery.limit(1);
      
      const survey = await surveyQuery.first();
      
      if (survey) {
        console.log('==== 问卷答案 ====');
        const answers = survey.get('answers') || [];
        answers.forEach((answer, index) => {
          console.log(`Q${index + 1}: ${answer.question}`);
          console.log(`A${index + 1}:`, answer.answer);
          console.log('---');
        });
      }
    }
    
  } catch (error) {
    console.error('❌ 查询失败:', error);
  }
}

checkSurveyStatus();

2.3 手动触发问卷引导

如果您在工作台页面,可以手动触发问卷引导弹窗:

// 在设计师工作台页面的Console执行
// 注意:这个方法需要页面已经加载完成

// 方法1:直接修改组件状态(仅演示用)
// 实际需要通过Angular的机制访问组件实例

// 方法2:直接跳转到问卷页面
const cid = location.pathname.split('/')[2] || 'test';
location.href = `/wxwork/${cid}/survey/profile`;

方法3:真实企微环境测试

3.1 环境准备

1. 使用内网穿透工具

由于企微需要访问公网域名,需要使用内网穿透:

# 安装 ngrok
brew install ngrok  # macOS
# 或从 https://ngrok.com 下载

# 启动穿透
ngrok http 4200

会得到一个公网URL,例如:

https://abc123.ngrok.io

2. 配置企业微信应用

登录企业微信管理后台 (https://work.weixin.qq.com):

  1. 进入"应用管理" → 找到您的CRM应用
  2. 设置"应用主页":

    https://abc123.ngrok.io/wxwork/你的公司ID
    
  3. 设置"可信域名":

    abc123.ngrok.io
    
  4. 保存配置

3.2 扫码测试

步骤1:在手机企微中打开应用

打开企业微信 → 工作台 → 找到CRM应用 → 点击进入

步骤2:观察激活流程

在浏览器开发者工具 Network 标签中观察:

1. GET /wxwork/:cid/designer/dashboard
   → 加载工作台页面
   
2. POST /parse/functions/wxworkAuth
   → 执行企微认证
   
3. GET /parse/classes/Profile?where=...
   → 查询Profile
   
4. GET /parse/classes/Profile/:id
   → 检查问卷状态

步骤3:验证问卷引导

  • 如果 Profile.surveyCompletedfalse,应该显示问卷引导弹窗
  • 点击"立即填写",应该跳转到 /wxwork/:cid/survey/profile
  • 填写完问卷后,返回工作台,不应再显示引导

3.3 真机调试技巧

在企微内使用vConsole

在页面HTML的 <head> 中临时添加:

<script src="https://unpkg.com/vconsole@latest/dist/vconsole.min.js"></script>
<script>
  if (location.href.includes('wxwork')) {
    new VConsole();
  }
</script>

这样在手机上可以查看Console日志。


常见问题排查

Q1: 测试页面显示"企微认证初始化失败"

原因: WxworkAuth 初始化失败

解决方法:

  1. 检查 cid 参数是否正确
  2. 确认 fmode-ng/core 已正确安装
  3. 查看Console是否有详细错误信息

    # 重新安装依赖
    npm install fmode-ng@latest
    

Q2: 显示"未能获取Profile信息"

原因:

  • 数据库中没有对应的Profile记录
  • 企微认证失败
  • 权限问题

解决方法:

  1. 使用测试模式(cid设为testdemo
  2. 检查数据库中是否有对应的Profile记录
  3. 确认当前用户有查询权限

    // Console中手动创建测试Profile
    async function createTestProfile() {
    const Parse = (await import('https://api.fmode.cn/parse/sdk.js')).default;
    Parse.initialize('nova');
    Parse.serverURL = 'https://api.fmode.cn/parse';
      
    const Profile = Parse.Object.extend('Profile');
    const profile = new Profile();
      
    profile.set('name', '测试员工');
    profile.set('realname', '王刚');
    profile.set('roleName', '组员');
    profile.set('company', {
    __type: 'Pointer',
    className: 'Company',
    objectId: 'test_company_001'
    });
    profile.set('surveyCompleted', false);
      
    const saved = await profile.save();
      
    console.log('✅ 测试Profile已创建:', saved.id);
    localStorage.setItem('Parse/ProfileId', saved.id);
      
    return saved;
    }
    
    createTestProfile();
    

Q3: 工作台不显示问卷引导弹窗

原因:

  • surveyCompleted 字段为 true
  • 检查逻辑未执行
  • 弹窗被CSS隐藏

解决方法:

// 1. 检查状态
checkSurveyStatus();

// 2. 如果状态错误,重置
resetSurvey();

// 3. 检查DOM
document.querySelector('.survey-guide-overlay');
// 应该返回弹窗元素,如果为null说明未渲染

Q4: 组长端看不到问卷答案

原因:

  • 员工名字不匹配
  • SurveyLog记录不存在
  • 数据加载失败

解决方法:

// 在组长工作台Console执行
async function debugEmployeeSurvey(employeeName) {
  const Parse = (await import('https://api.fmode.cn/parse/sdk.js')).default;
  Parse.initialize('nova');
  Parse.serverURL = 'https://api.fmode.cn/parse';
  
  console.log('==== 调试员工问卷 ====');
  console.log('查找员工:', employeeName);
  
  // 1. 查找Profile
  const Profile = Parse.Object.extend('Profile');
  const profileQuery = new Parse.Query(Profile);
  profileQuery.equalTo('realname', employeeName);
  profileQuery.limit(1);
  
  const profile = await profileQuery.first();
  
  if (!profile) {
    console.error('❌ 未找到员工Profile,请检查名字是否正确');
    return;
  }
  
  console.log('✅ 找到Profile:', profile.id);
  console.log('   问卷状态:', profile.get('surveyCompleted'));
  
  // 2. 查找SurveyLog
  if (profile.get('surveyCompleted')) {
    const SurveyLog = Parse.Object.extend('SurveyLog');
    const surveyQuery = new Parse.Query(SurveyLog);
    surveyQuery.equalTo('profile', profile.toPointer());
    surveyQuery.equalTo('type', 'survey-profile');
    surveyQuery.descending('createdAt');
    surveyQuery.limit(1);
    
    const survey = await surveyQuery.first();
    
    if (survey) {
      console.log('✅ 找到问卷记录:', survey.id);
      console.log('   答案数量:', survey.get('answers')?.length || 0);
      console.log('   提交时间:', survey.get('createdAt'));
    } else {
      console.error('❌ 未找到问卷记录');
    }
  }
}

// 使用:替换为实际员工名字
debugEmployeeSurvey('王刚');

Q5: 问卷提交失败

原因:

  • 必填题未填写
  • 网络问题
  • 权限问题

解决方法:

  1. 打开Console查看错误信息
  2. 检查必填题是否都已填写
  3. 检查网络连接
  4. 确认Parse权限配置

    // 手动测试提交问卷
    async function testSubmitSurvey() {
    const Parse = (await import('https://api.fmode.cn/parse/sdk.js')).default;
    Parse.initialize('nova');
    Parse.serverURL = 'https://api.fmode.cn/parse';
      
    const profileId = localStorage.getItem('Parse/ProfileId');
      
    const SurveyLog = Parse.Object.extend('SurveyLog');
    const surveyLog = new SurveyLog();
      
    const Profile = Parse.Object.extend('Profile');
    const profile = new Profile();
    profile.id = profileId;
      
    surveyLog.set('type', 'survey-profile');
    surveyLog.set('profile', profile.toPointer());
    surveyLog.set('answers', [
    {
      question: '测试问题',
      type: 'single',
      answer: '测试答案'
    }
    ]);
      
    try {
    await surveyLog.save();
    console.log('✅ 问卷提交成功');
    } catch (error) {
    console.error('❌ 提交失败:', error);
    }
    }
    
    testSubmitSurvey();
    

数据库Schema说明

Profile 表新增字段

{
  surveyCompleted: Boolean,     // 是否完成问卷
  surveyCompletedAt: Date,      // 问卷完成时间
  surveyLogId: String          // 关联的SurveyLog ID
}

添加字段SQL(如果使用PostgreSQL):

-- 添加问卷相关字段到Profile表
ALTER TABLE "Profile" 
  ADD COLUMN IF NOT EXISTS "surveyCompleted" BOOLEAN DEFAULT false,
  ADD COLUMN IF NOT EXISTS "surveyCompletedAt" TIMESTAMP,
  ADD COLUMN IF NOT EXISTS "surveyLogId" VARCHAR(255);

-- 添加索引
CREATE INDEX IF NOT EXISTS "idx_profile_survey_completed" 
  ON "Profile" ("surveyCompleted");

SurveyLog 表结构

{
  type: 'survey-profile',       // 问卷类型
  profile: Pointer<Profile>,    // 关联员工
  company: Pointer<Company>,    // 所属公司
  answers: Array<{
    question: string,           // 问题文本
    type: 'single' | 'multiple' | 'scale',  // 题型
    answer: string | string[] | number,     // 答案
    options?: string[]          // 选项列表(可选)
  }>,
  createdAt: Date,             // 提交时间
  updatedAt: Date              // 更新时间
}

创建表SQL:

-- SurveyLog表已存在,只需确认type字段支持'survey-profile'
-- 可以添加检查约束
ALTER TABLE "SurveyLog"
  ADD CONSTRAINT "check_survey_type" 
  CHECK ("type" IN ('survey-project', 'survey-contact', 'survey-profile'));

📊 调试检查清单

在提交测试报告前,请确认以下各项:

设计师端测试

  • 测试工具页面能正常访问
  • "开始测试"按钮能成功执行
  • 员工信息正确显示
  • 问卷状态正确反映
  • "重置问卷状态"功能正常
  • 首次登录显示问卷引导弹窗
  • 弹窗UI正常,无样式错误
  • "稍后填写"按钮关闭弹窗
  • "立即填写"按钮正确跳转
  • 完成问卷后不再显示引导

问卷填写测试

  • 问卷页面能正常访问
  • 所有21个问题正常显示
  • 单选题可以选择
  • 多选题可以多选
  • 评分题滑块正常工作
  • 必填验证正常工作
  • 提交按钮正常工作
  • 提交成功有反馈
  • Profile.surveyCompleted更新为true
  • SurveyLog记录已创建

组长端测试

  • 能正常打开员工详情面板
  • "能力问卷"部分正常显示
  • 已完成问卷的员工显示答案
  • 答案格式正确(单选/多选/评分)
  • 未完成的员工显示提示
  • 移动端显示正常

数据一致性

  • Profile.surveyCompleted与SurveyLog一致
  • 时间戳正确记录
  • 答案数据完整
  • 没有重复记录

🎯 总结

推荐的调试流程:

1. 使用测试工具页面 (http://localhost:4200/test-wxwork-activation/test)
   → 快速验证核心流程
   
2. 使用Console命令
   → 精细控制和调试
   
3. 真机企微测试
   → 最终验收

关键调试点

  • ✅ Profile.surveyCompleted 状态正确
  • ✅ 问卷引导在正确时机显示
  • ✅ 问卷数据正确保存
  • ✅ 组长端能正确查看

遇到问题时

  1. 查看Console日志
  2. 检查Network请求
  3. 验证数据库记录
  4. 参考本文档的"常见问题排查"

祝调试顺利!🎉