|
@@ -0,0 +1,706 @@
|
|
|
|
|
+# 企业微信身份激活与问卷整合调试指南
|
|
|
|
|
+
|
|
|
|
|
+## 📋 目录
|
|
|
|
|
+
|
|
|
|
|
+1. [功能概述](#功能概述)
|
|
|
|
|
+2. [调试方法总览](#调试方法总览)
|
|
|
|
|
+3. [方法1:使用测试工具页面(推荐)](#方法1使用测试工具页面推荐)
|
|
|
|
|
+4. [方法2:浏览器Console调试](#方法2浏览器console调试)
|
|
|
|
|
+5. [方法3:真实企微环境测试](#方法3真实企微环境测试)
|
|
|
|
|
+6. [常见问题排查](#常见问题排查)
|
|
|
|
|
+7. [数据库Schema说明](#数据库schema说明)
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 功能概述
|
|
|
|
|
+
|
|
|
|
|
+### 完整流程
|
|
|
|
|
+
|
|
|
|
|
+```
|
|
|
|
|
+员工扫码进入企微应用
|
|
|
|
|
+ ↓
|
|
|
|
|
+WxworkAuth.authenticateAndLogin()
|
|
|
|
|
+ ↓
|
|
|
|
|
+身份激活/Profile同步
|
|
|
|
|
+ ↓
|
|
|
|
|
+跳转到设计师工作台
|
|
|
|
|
+ ↓
|
|
|
|
|
+检查 Profile.surveyCompleted
|
|
|
|
|
+ ↓
|
|
|
|
|
+未完成 → 显示问卷引导弹窗 → 跳转问卷页面
|
|
|
|
|
+ ↓
|
|
|
|
|
+已完成 → 正常使用工作台
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 涉及的核心代码文件
|
|
|
|
|
+
|
|
|
|
|
+1. **身份激活**
|
|
|
|
|
+ - `src/app/pages/designer/dashboard/dashboard.ts` - 工作台认证逻辑
|
|
|
|
|
+ - `fmode-ng/core` 的 `WxworkAuth` - 企微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:启动开发服务器**
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+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,粘贴以下代码:
|
|
|
|
|
+
|
|
|
|
|
+```javascript
|
|
|
|
|
+// 重置问卷状态函数
|
|
|
|
|
+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 查看问卷状态
|
|
|
|
|
+
|
|
|
|
|
+```javascript
|
|
|
|
|
+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 手动触发问卷引导
|
|
|
|
|
+
|
|
|
|
|
+如果您在工作台页面,可以手动触发问卷引导弹窗:
|
|
|
|
|
+
|
|
|
|
|
+```javascript
|
|
|
|
|
+// 在设计师工作台页面的Console执行
|
|
|
|
|
+// 注意:这个方法需要页面已经加载完成
|
|
|
|
|
+
|
|
|
|
|
+// 方法1:直接修改组件状态(仅演示用)
|
|
|
|
|
+// 实际需要通过Angular的机制访问组件实例
|
|
|
|
|
+
|
|
|
|
|
+// 方法2:直接跳转到问卷页面
|
|
|
|
|
+const cid = location.pathname.split('/')[2] || 'test';
|
|
|
|
|
+location.href = `/wxwork/${cid}/survey/profile`;
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 方法3:真实企微环境测试
|
|
|
|
|
+
|
|
|
|
|
+### 3.1 环境准备
|
|
|
|
|
+
|
|
|
|
|
+**1. 使用内网穿透工具**
|
|
|
|
|
+
|
|
|
|
|
+由于企微需要访问公网域名,需要使用内网穿透:
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+# 安装 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.surveyCompleted` 为 `false`,应该显示问卷引导弹窗
|
|
|
|
|
+- 点击"立即填写",应该跳转到 `/wxwork/:cid/survey/profile`
|
|
|
|
|
+- 填写完问卷后,返回工作台,不应再显示引导
|
|
|
|
|
+
|
|
|
|
|
+### 3.3 真机调试技巧
|
|
|
|
|
+
|
|
|
|
|
+**在企微内使用vConsole**
|
|
|
|
|
+
|
|
|
|
|
+在页面HTML的 `<head>` 中临时添加:
|
|
|
|
|
+
|
|
|
|
|
+```html
|
|
|
|
|
+<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是否有详细错误信息
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+# 重新安装依赖
|
|
|
|
|
+npm install fmode-ng@latest
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### Q2: 显示"未能获取Profile信息"
|
|
|
|
|
+
|
|
|
|
|
+**原因**:
|
|
|
|
|
+- 数据库中没有对应的Profile记录
|
|
|
|
|
+- 企微认证失败
|
|
|
|
|
+- 权限问题
|
|
|
|
|
+
|
|
|
|
|
+**解决方法**:
|
|
|
|
|
+1. 使用测试模式(cid设为`test`或`demo`)
|
|
|
|
|
+2. 检查数据库中是否有对应的Profile记录
|
|
|
|
|
+3. 确认当前用户有查询权限
|
|
|
|
|
+
|
|
|
|
|
+```javascript
|
|
|
|
|
+// 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隐藏
|
|
|
|
|
+
|
|
|
|
|
+**解决方法**:
|
|
|
|
|
+
|
|
|
|
|
+```javascript
|
|
|
|
|
+// 1. 检查状态
|
|
|
|
|
+checkSurveyStatus();
|
|
|
|
|
+
|
|
|
|
|
+// 2. 如果状态错误,重置
|
|
|
|
|
+resetSurvey();
|
|
|
|
|
+
|
|
|
|
|
+// 3. 检查DOM
|
|
|
|
|
+document.querySelector('.survey-guide-overlay');
|
|
|
|
|
+// 应该返回弹窗元素,如果为null说明未渲染
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### Q4: 组长端看不到问卷答案
|
|
|
|
|
+
|
|
|
|
|
+**原因**:
|
|
|
|
|
+- 员工名字不匹配
|
|
|
|
|
+- SurveyLog记录不存在
|
|
|
|
|
+- 数据加载失败
|
|
|
|
|
+
|
|
|
|
|
+**解决方法**:
|
|
|
|
|
+
|
|
|
|
|
+```javascript
|
|
|
|
|
+// 在组长工作台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权限配置
|
|
|
|
|
+
|
|
|
|
|
+```javascript
|
|
|
|
|
+// 手动测试提交问卷
|
|
|
|
|
+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 表新增字段
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+{
|
|
|
|
|
+ surveyCompleted: Boolean, // 是否完成问卷
|
|
|
|
|
+ surveyCompletedAt: Date, // 问卷完成时间
|
|
|
|
|
+ surveyLogId: String // 关联的SurveyLog ID
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**添加字段SQL(如果使用PostgreSQL)**:
|
|
|
|
|
+
|
|
|
|
|
+```sql
|
|
|
|
|
+-- 添加问卷相关字段到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 表结构
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+{
|
|
|
|
|
+ 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**:
|
|
|
|
|
+
|
|
|
|
|
+```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. 参考本文档的"常见问题排查"
|
|
|
|
|
+
|
|
|
|
|
+祝调试顺利!🎉
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|