|
|
@@ -0,0 +1,1243 @@
|
|
|
+# 员工问卷组件产品需求文档
|
|
|
+
|
|
|
+## 一、概述
|
|
|
+
|
|
|
+### 1.1 功能定位
|
|
|
+员工问卷是内部技术组员的**专业特长及偏好调研工具**,通过系统化问卷了解员工的技术能力、项目经验、承接偏好和协作习惯,为客服智能分配订单提供数据支撑。
|
|
|
+
|
|
|
+### 1.2 业务价值
|
|
|
+- **员工视角**: 清晰表达技术优势和承接意愿,避免不匹配项目导致返工
|
|
|
+- **管理视角**: 精准掌握团队能力分布,合理分配订单,提升交付质量
|
|
|
+- **客服视角**: 快速匹配设计师特长与客户需求,减少沟通成本
|
|
|
+- **数据视角**: 积累员工能力画像,优化团队培训和项目排期
|
|
|
+
|
|
|
+### 1.3 应用场景
|
|
|
+1. **员工入职时**: 新员工首次登录企微端,完成身份认证后填写问卷
|
|
|
+2. **定期更新**: 员工可更新问卷内容(如新增擅长风格、调整承接意愿)
|
|
|
+3. **订单分配前**: 客服查看员工问卷,匹配合适的设计师
|
|
|
+4. **组长管理**: 组长在员工详情弹窗中查看完整问卷答案和能力画像
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 二、数据范式
|
|
|
+
|
|
|
+### 2.1 SurveyLog 问卷结果表(复用现有表)
|
|
|
+
|
|
|
+| 字段名 | 类型 | 必填 | 说明 | 示例值 |
|
|
|
+|--------|------|------|------|--------|
|
|
|
+| objectId | String | 是 | 主键ID | "survey_profile_001" |
|
|
|
+| **profile** | **Pointer** | **是** | **提交员工** | **→ Profile** |
|
|
|
+| project | Pointer | 否 | 关联项目(员工问卷为null) | null |
|
|
|
+| contact | Pointer | 否 | 关联联系人(员工问卷为null) | null |
|
|
|
+| **company** | **Pointer** | **是** | **所属帐套** | **→ Company** |
|
|
|
+| **type** | **String** | **是** | **问卷类型** | **"survey-profile"** |
|
|
|
+| **data** | **Object** | **是** | **问卷结果** | **{q1: ["奶油风"], ...}** |
|
|
|
+| isCompleted | Boolean | 否 | 是否完整填写 | true |
|
|
|
+| completedAt | Date | 否 | 完成时间 | 2025-10-30T10:00:00.000Z |
|
|
|
+| version | Number | 否 | 问卷版本号 | 1 |
|
|
|
+| isDeleted | Boolean | 否 | 软删除标记 | false |
|
|
|
+| createdAt | Date | 自动 | 创建时间 | 2025-10-30T09:00:00.000Z |
|
|
|
+| updatedAt | Date | 自动 | 更新时间 | 2025-10-30T10:00:00.000Z |
|
|
|
+
|
|
|
+**type 枚举值**:
|
|
|
+- `survey-project`: 项目问卷(客户填写)
|
|
|
+- `survey-contact`: 联系人问卷(暂未实现)
|
|
|
+- `survey-profile`: **员工问卷(本次实现)**
|
|
|
+
|
|
|
+**data 字段结构示例**:
|
|
|
+```json
|
|
|
+{
|
|
|
+ "q1_expertise_styles": ["奶油风", "极简风", "新中式"],
|
|
|
+ "q2_expertise_spaces": ["常规住宅空间", "大平层/别墅复杂空间", "特殊功能空间"],
|
|
|
+ "q3_technical_advantages": ["渲染精度高", "方案深化能力"],
|
|
|
+ "q4_case_1_type": "140㎡极简风四居室",
|
|
|
+ "q4_case_1_highlight": "高还原度材质渲染,精准呈现原木与水泥灰的质感碰撞",
|
|
|
+ "q4_case_2_type": "90㎡奶油风三居室",
|
|
|
+ "q4_case_2_highlight": "方案深化能力突出,优化客餐厅动线并设计嵌入式收纳系统",
|
|
|
+ "q5_project_difficulty": "中等难度",
|
|
|
+ "q6_prefer_project_types": ["擅长风格的常规项目", "新风格探索项目", "需方案深化的项目"],
|
|
|
+ "q7_weekly_capacity": "1-2个(中等难度)",
|
|
|
+ "q8_urgent_willingness": "愿意承接",
|
|
|
+ "q8_urgent_limit": "2",
|
|
|
+ "q9_progress_feedback": "关键节点同步",
|
|
|
+ "q10_delivery_confirmation": ["交付前必同步客服/组长", "参考图逐张确认"],
|
|
|
+ "q11_requirement_clarity": "基础需求+核心偏好",
|
|
|
+ "q12_communication_methods": ["群内文字同步", "短语音快速沟通", "复杂需求开线上会议"],
|
|
|
+ "q13_sensitive_words_awareness": "可识别部分敏感词",
|
|
|
+ "q14_problem_handling": "先尝试自行调整",
|
|
|
+ "q15_task_notification": "工作群@+私信提醒",
|
|
|
+ "q16_cannot_accept": "暂无法承接大型商业空间(如超过500㎡的商场展厅、连锁餐饮门店)项目,以及无任何参考图且客户需求极度模糊的项目。",
|
|
|
+ "q17_additional_notes": "擅长使用SU进行建模,同时熟练运用Lumion、V-Ray进行渲染;希望多承接新中式风格项目,进一步提升该风格的方案深化与软装搭配能力;针对老人房、儿童房等特殊功能空间,可提供符合使用者生理与心理需求的细节优化建议。"
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 三、核心组件设计
|
|
|
+
|
|
|
+### 3.1 ProfileSurveyComponent 员工问卷组件
|
|
|
+
|
|
|
+#### 3.1.1 路由配置
|
|
|
+```typescript
|
|
|
+// 路由: /wxwork/:cid/survey/profile
|
|
|
+{
|
|
|
+ path: 'wxwork/:cid',
|
|
|
+ children: [
|
|
|
+ {
|
|
|
+ path: 'survey/profile',
|
|
|
+ loadComponent: () => import('../modules/profile/pages/profile-survey/profile-survey.component'),
|
|
|
+ title: '员工技能调研'
|
|
|
+ }
|
|
|
+ ]
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+#### 3.1.2 组件状态机
|
|
|
+组件包含三种状态,通过 `currentState` 控制:
|
|
|
+
|
|
|
+```typescript
|
|
|
+type SurveyState = 'welcome' | 'questionnaire' | 'result';
|
|
|
+
|
|
|
+currentState: SurveyState = 'welcome';
|
|
|
+```
|
|
|
+
|
|
|
+**状态转换流程**:
|
|
|
+```
|
|
|
+[欢迎页] --点击开始--> [答题页] --提交完成--> [结果页]
|
|
|
+ ↑ ↓
|
|
|
+ └──────────────── 重新填写 ──────────────────┘
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 3.2 欢迎页 (welcome)
|
|
|
+
|
|
|
+#### 3.2.1 页面布局
|
|
|
+```
|
|
|
+┌─────────────────────────────────┐
|
|
|
+│ 员工问卷欢迎页 │
|
|
|
+├─────────────────────────────────┤
|
|
|
+│ [员工头像] │
|
|
|
+│ 您好,张三 │
|
|
|
+│ │
|
|
|
+│ 《技术组员偏好及状况调研表》 │
|
|
|
+│ │
|
|
|
+│ 尊敬的伙伴: │
|
|
|
+│ 为了更精准地匹配项目与您的专业能力│
|
|
|
+│ 请完成本次能力调研。您的选择将帮助│
|
|
|
+│ 我们合理分配订单,避免不匹配项目导│
|
|
|
+│ 致返工,让您的优势得到充分发挥! │
|
|
|
+│ │
|
|
|
+│ • 预计用时: 8-10分钟 │
|
|
|
+│ • 题目数量: 17题 │
|
|
|
+│ • 题型: 选择题为主,少量填空题 │
|
|
|
+│ │
|
|
|
+│ [开始填写] │
|
|
|
+│ │
|
|
|
+│ [已填写过? 查看/更新答案] │
|
|
|
+└─────────────────────────────────┘
|
|
|
+```
|
|
|
+
|
|
|
+#### 3.2.2 功能实现
|
|
|
+1. **用户识别**:
|
|
|
+ - 通过 `WxworkAuth.currentProfile()` 获取当前登录员工
|
|
|
+ - 显示员工头像和姓名
|
|
|
+ - 记录 `profile.id` 用于后续保存
|
|
|
+
|
|
|
+2. **数据检查**:
|
|
|
+ - 组件初始化时查询 SurveyLog 表
|
|
|
+ - 条件: `type == 'survey-profile' AND profile == profileId`
|
|
|
+ - 如果已存在且 `isCompleted == true`,显示"查看/更新答案"入口
|
|
|
+
|
|
|
+3. **开始按钮**:
|
|
|
+ - 点击后执行 `startSurvey()`
|
|
|
+ - 切换状态: `currentState = 'questionnaire'`
|
|
|
+ - 初始化题目索引: `currentQuestionIndex = 0`
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 3.3 答题页 (questionnaire)
|
|
|
+
|
|
|
+#### 3.3.1 页面布局
|
|
|
+```
|
|
|
+┌─────────────────────────────────┐
|
|
|
+│ 进度: 1/17 ●○○○○○○○○○○○○○○○○ │
|
|
|
+├─────────────────────────────────┤
|
|
|
+│ 一、核心技术能力 │
|
|
|
+│ │
|
|
|
+│ 1. 您最擅长的家装风格? │
|
|
|
+│ (可多选,优先选3项) │
|
|
|
+│ │
|
|
|
+│ ☑ 奶油风 │
|
|
|
+│ ☑ 极简风(含侘寂风) │
|
|
|
+│ ☑ 新中式 │
|
|
|
+│ □ 轻奢风 │
|
|
|
+│ □ 美式/欧式 │
|
|
|
+│ □ 复古风(如法式、美式复古) │
|
|
|
+│ □ 其他: [____________] │
|
|
|
+│ │
|
|
|
+│ [← 上一题] [下一题 →] │
|
|
|
+└─────────────────────────────────┘
|
|
|
+```
|
|
|
+
|
|
|
+#### 3.3.2 题目数据结构
|
|
|
+```typescript
|
|
|
+interface Question {
|
|
|
+ id: string; // 题目ID,如 "q1", "q2"
|
|
|
+ section: string; // 章节,如 "核心技术能力", "项目经验与案例"
|
|
|
+ title: string; // 题目文本
|
|
|
+ subtitle?: string; // 副标题提示
|
|
|
+ type: 'single' | 'multiple' | 'text' | 'number' | 'textarea'; // 题型
|
|
|
+ options?: string[]; // 选项列表
|
|
|
+ hasOther?: boolean; // 是否有"其他"选项
|
|
|
+ required?: boolean; // 是否必填
|
|
|
+ maxSelections?: number; // 多选题最多选择数量
|
|
|
+ placeholder?: string; // 输入框占位符
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+#### 3.3.3 题目列表
|
|
|
+```typescript
|
|
|
+const questions: Question[] = [
|
|
|
+ // ==================== 一、核心技术能力 ====================
|
|
|
+ {
|
|
|
+ id: 'q1_expertise_styles',
|
|
|
+ section: '核心技术能力',
|
|
|
+ title: '您最擅长的家装风格?',
|
|
|
+ subtitle: '可多选,优先选3项',
|
|
|
+ type: 'multiple',
|
|
|
+ maxSelections: 3,
|
|
|
+ options: [
|
|
|
+ '奶油风',
|
|
|
+ '极简风(含侘寂风)',
|
|
|
+ '新中式',
|
|
|
+ '轻奢风',
|
|
|
+ '美式/欧式',
|
|
|
+ '复古风(如法式、美式复古)'
|
|
|
+ ],
|
|
|
+ hasOther: true,
|
|
|
+ required: true
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: 'q2_expertise_spaces',
|
|
|
+ section: '核心技术能力',
|
|
|
+ title: '您擅长的空间类型?',
|
|
|
+ subtitle: '可多选',
|
|
|
+ type: 'multiple',
|
|
|
+ options: [
|
|
|
+ '常规住宅空间(客厅/卧室/厨房)',
|
|
|
+ '大平层/别墅复杂空间(如挑空客厅、独立书房)',
|
|
|
+ '商业空间(民宿/小型展厅/餐饮)',
|
|
|
+ '特殊功能空间(如儿童房、老人房、电竞房)'
|
|
|
+ ],
|
|
|
+ required: true
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: 'q3_technical_advantages',
|
|
|
+ section: '核心技术能力',
|
|
|
+ title: '技术能力优势?',
|
|
|
+ subtitle: '可多选,优先选2项',
|
|
|
+ type: 'multiple',
|
|
|
+ maxSelections: 2,
|
|
|
+ options: [
|
|
|
+ '渲染精度高(光影/材质还原度优)',
|
|
|
+ '建模速度快(高效完成基础建模)',
|
|
|
+ '软装搭配落地性强(贴合实际采购与风格统一)',
|
|
|
+ '方案深化能力(可提供空间优化/灯光布局建议)',
|
|
|
+ '复杂场景处理(如异形吊顶、定制柜体建模)'
|
|
|
+ ],
|
|
|
+ required: true
|
|
|
+ },
|
|
|
+
|
|
|
+ // ==================== 二、项目经验与案例 ====================
|
|
|
+ {
|
|
|
+ id: 'q4_case_1_type',
|
|
|
+ section: '项目经验与案例',
|
|
|
+ title: '代表性案例1:项目类型',
|
|
|
+ subtitle: '例如:120㎡极简风三居室',
|
|
|
+ type: 'text',
|
|
|
+ placeholder: '请输入项目类型...',
|
|
|
+ required: true
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: 'q4_case_1_highlight',
|
|
|
+ section: '项目经验与案例',
|
|
|
+ title: '代表性案例1:核心亮点',
|
|
|
+ subtitle: '例如:高还原度材质渲染/复杂吊顶建模',
|
|
|
+ type: 'textarea',
|
|
|
+ placeholder: '请输入核心亮点...',
|
|
|
+ required: true
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: 'q4_case_2_type',
|
|
|
+ section: '项目经验与案例',
|
|
|
+ title: '代表性案例2:项目类型',
|
|
|
+ subtitle: '选填,便于客服对接同类需求',
|
|
|
+ type: 'text',
|
|
|
+ placeholder: '请输入项目类型...',
|
|
|
+ required: false
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: 'q4_case_2_highlight',
|
|
|
+ section: '项目经验与案例',
|
|
|
+ title: '代表性案例2:核心亮点',
|
|
|
+ subtitle: '选填',
|
|
|
+ type: 'textarea',
|
|
|
+ placeholder: '请输入核心亮点...',
|
|
|
+ required: false
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: 'q5_project_difficulty',
|
|
|
+ section: '项目经验与案例',
|
|
|
+ title: '可独立处理的项目难度?',
|
|
|
+ type: 'single',
|
|
|
+ options: [
|
|
|
+ '基础难度(常规户型、成熟风格、无复杂结构)',
|
|
|
+ '中等难度(复杂户型、小众风格、需基础深化)',
|
|
|
+ '高等难度(别墅/异形空间、高还原度需求、深度方案配合)'
|
|
|
+ ],
|
|
|
+ required: true
|
|
|
+ },
|
|
|
+
|
|
|
+ // ==================== 三、项目承接偏好 ====================
|
|
|
+ {
|
|
|
+ id: 'q6_prefer_project_types',
|
|
|
+ section: '项目承接偏好',
|
|
|
+ title: '您优先想承接的项目类型?',
|
|
|
+ subtitle: '可多选',
|
|
|
+ type: 'multiple',
|
|
|
+ options: [
|
|
|
+ '擅长风格的常规项目(稳定发挥优势)',
|
|
|
+ '新风格探索项目(愿意尝试未接触过的风格)',
|
|
|
+ '需方案深化的项目(可输出技术建议)',
|
|
|
+ '批量小型项目(如多套同户型基础渲染)'
|
|
|
+ ],
|
|
|
+ hasOther: true,
|
|
|
+ required: true
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: 'q7_weekly_capacity',
|
|
|
+ section: '项目承接偏好',
|
|
|
+ title: '您可承接的单周期项目数量上限?',
|
|
|
+ subtitle: '以周为单位',
|
|
|
+ type: 'single',
|
|
|
+ options: [
|
|
|
+ '2-3个(基础难度)',
|
|
|
+ '1-2个(中等难度)',
|
|
|
+ '1个(高等难度)',
|
|
|
+ '可灵活调整(需提前沟通)'
|
|
|
+ ],
|
|
|
+ required: true
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: 'q8_urgent_willingness',
|
|
|
+ section: '项目承接偏好',
|
|
|
+ title: '对紧急订单的承接意愿?',
|
|
|
+ subtitle: '紧急订单:需24-48小时内交付初版',
|
|
|
+ type: 'single',
|
|
|
+ options: [
|
|
|
+ '愿意承接',
|
|
|
+ '暂不承接(优先保证常规订单质量)',
|
|
|
+ '视情况而定(需提前确认时间是否充裕)'
|
|
|
+ ],
|
|
|
+ required: true
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: 'q8_urgent_limit',
|
|
|
+ section: '项目承接偏好',
|
|
|
+ title: '如愿意承接紧急订单,每月上限?',
|
|
|
+ subtitle: '如不承接可跳过',
|
|
|
+ type: 'number',
|
|
|
+ placeholder: '请输入数字(次)',
|
|
|
+ required: false
|
|
|
+ },
|
|
|
+
|
|
|
+ // ==================== 四、协作与交付习惯 ====================
|
|
|
+ {
|
|
|
+ id: 'q9_progress_feedback',
|
|
|
+ section: '协作与交付习惯',
|
|
|
+ title: '项目进度反馈与时效把控?',
|
|
|
+ type: 'single',
|
|
|
+ options: [
|
|
|
+ '每日同步进度(含"建模完成50%"等节点),超时前6小时主动预警',
|
|
|
+ '关键节点同步(建模完成/渲染初版/最终交付前),超时前12小时主动预警',
|
|
|
+ '有问题时即时反馈,无问题则按约定时间交付'
|
|
|
+ ],
|
|
|
+ required: true
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: 'q10_delivery_confirmation',
|
|
|
+ section: '协作与交付习惯',
|
|
|
+ title: '交付前确认流程?',
|
|
|
+ subtitle: '可多选',
|
|
|
+ type: 'multiple',
|
|
|
+ options: [
|
|
|
+ '交付前必同步客服/组长,确认"是否需先给客户预览"后再发送',
|
|
|
+ '若客户明确要参考图,会逐张确认具体参考要求并同步记录至工作群',
|
|
|
+ '简单需求可直接交付,但复杂需求必提前同步确认'
|
|
|
+ ],
|
|
|
+ required: true
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: 'q11_requirement_clarity',
|
|
|
+ section: '协作与交付习惯',
|
|
|
+ title: '对接需求时,您希望获取的客户信息清晰度?',
|
|
|
+ type: 'single',
|
|
|
+ options: [
|
|
|
+ '需详细需求文档(含每张图的参考图、尺寸、风格说明)',
|
|
|
+ '基础需求+核心偏好(可自主补充细节,但需确认"是否符合客户预期")',
|
|
|
+ '灵活(简单沟通后推进,若遇参考要求不明确,会主动向客服/组长确认)'
|
|
|
+ ],
|
|
|
+ required: true
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: 'q12_communication_methods',
|
|
|
+ section: '协作与交付习惯',
|
|
|
+ title: '若项目需协作,您倾向的对接方式?',
|
|
|
+ subtitle: '可多选',
|
|
|
+ type: 'multiple',
|
|
|
+ options: [
|
|
|
+ '群内文字同步(含参考要求、进度节点,便于追溯)',
|
|
|
+ '短语音快速沟通(紧急时)',
|
|
|
+ '复杂需求开线上会议(明确参考细节/深化方向)'
|
|
|
+ ],
|
|
|
+ required: true
|
|
|
+ },
|
|
|
+
|
|
|
+ // ==================== 五、问题应对与风险预警 ====================
|
|
|
+ {
|
|
|
+ id: 'q13_sensitive_words_awareness',
|
|
|
+ section: '问题应对与风险预警',
|
|
|
+ title: '您了解项目中的"敏感词"吗?',
|
|
|
+ subtitle: '如"效果图不满意"、"出图时间拖了"、"参考不对"',
|
|
|
+ type: 'single',
|
|
|
+ options: [
|
|
|
+ '了解,遇到会即时截图反馈客服/组长,触发Issue跟进',
|
|
|
+ '不了解,需提供敏感词清单',
|
|
|
+ '可识别部分敏感词,不确定时会先咨询组长再处理'
|
|
|
+ ],
|
|
|
+ required: true
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: 'q14_problem_handling',
|
|
|
+ section: '问题应对与风险预警',
|
|
|
+ title: '若某个环节出问题,您的处理流程?',
|
|
|
+ subtitle: '如"建模尺寸偏差"、"客户不认可色调"',
|
|
|
+ type: 'single',
|
|
|
+ options: [
|
|
|
+ '先暂停当前工作,即时在群内说明问题+附截图,触发代办任务后等待协调',
|
|
|
+ '先尝试自行调整,调整无效后再反馈(最长不超过2小时)',
|
|
|
+ '优先联系客服了解"客户真实诉求",再同步组长制定解决方案'
|
|
|
+ ],
|
|
|
+ required: true
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: 'q15_task_notification',
|
|
|
+ section: '问题应对与风险预警',
|
|
|
+ title: '您希望的代办任务通知方式?',
|
|
|
+ subtitle: '可多选',
|
|
|
+ type: 'multiple',
|
|
|
+ options: [
|
|
|
+ '工作群@+私信提醒',
|
|
|
+ '电话通知(仅紧急任务)',
|
|
|
+ '企业微信工单提醒'
|
|
|
+ ],
|
|
|
+ required: true
|
|
|
+ },
|
|
|
+
|
|
|
+ // ==================== 六、补充说明 ====================
|
|
|
+ {
|
|
|
+ id: 'q16_cannot_accept',
|
|
|
+ section: '补充说明',
|
|
|
+ title: '暂时无法承接的项目类型?',
|
|
|
+ subtitle: '例如:暂不接商业空间/暂不接无参考图的项目',
|
|
|
+ type: 'textarea',
|
|
|
+ placeholder: '请输入暂时无法承接的项目类型...',
|
|
|
+ required: false
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: 'q17_additional_notes',
|
|
|
+ section: '补充说明',
|
|
|
+ title: '其他项目相关补充?',
|
|
|
+ subtitle: '例如:擅长用SU建模/希望多接新中式项目提升能力',
|
|
|
+ type: 'textarea',
|
|
|
+ placeholder: '请输入其他补充说明...',
|
|
|
+ required: false
|
|
|
+ }
|
|
|
+];
|
|
|
+```
|
|
|
+
|
|
|
+#### 3.3.4 答题交互逻辑
|
|
|
+
|
|
|
+1. **单选题**:
|
|
|
+ - 点击选项后自动保存答案到 `answers[questionId]`
|
|
|
+ - 自动跳转下一题
|
|
|
+
|
|
|
+2. **多选题**:
|
|
|
+ - 可选择多个选项
|
|
|
+ - 如有 `maxSelections` 限制,达到上限后禁用其他选项
|
|
|
+ - 显示选择数量提示:`已选 2/3 项`
|
|
|
+ - 点击"下一题"后保存并跳转
|
|
|
+
|
|
|
+3. **文本题/数字题**:
|
|
|
+ - 输入完成后点击"下一题"
|
|
|
+ - 文本输入框支持单行输入
|
|
|
+
|
|
|
+4. **多行文本题**:
|
|
|
+ - 使用 textarea,支持多行输入
|
|
|
+ - 输入完成后点击"下一题"
|
|
|
+
|
|
|
+5. **进度指示**:
|
|
|
+ - 顶部显示进度条: `currentQuestionIndex / totalQuestions`
|
|
|
+ - 显示当前章节名称
|
|
|
+
|
|
|
+6. **导航按钮**:
|
|
|
+ - "上一题": 返回上一题,可修改答案
|
|
|
+ - "下一题": 保存当前答案并跳转(最后一题显示"提交")
|
|
|
+
|
|
|
+#### 3.3.5 数据保存策略
|
|
|
+
|
|
|
+**自动保存**:
|
|
|
+- 每答完一题后自动保存到 Parse(防止中途退出丢失数据)
|
|
|
+- 保存方式:
|
|
|
+ ```typescript
|
|
|
+ surveyLog.set('data', {
|
|
|
+ ...surveyLog.get('data'),
|
|
|
+ [questionId]: answer
|
|
|
+ });
|
|
|
+ await surveyLog.save();
|
|
|
+ ```
|
|
|
+
|
|
|
+**完成标记**:
|
|
|
+- 最后一题提交后设置 `isCompleted = true`
|
|
|
+- 设置 `completedAt = new Date()`
|
|
|
+- 设置 `version = 1`(用于后续问卷更新迭代)
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 3.4 结果页 (result)
|
|
|
+
|
|
|
+#### 3.4.1 页面布局
|
|
|
+```
|
|
|
+┌─────────────────────────────────┐
|
|
|
+│ ✓ 问卷提交成功 │
|
|
|
+├─────────────────────────────────┤
|
|
|
+│ 感谢您的反馈! │
|
|
|
+│ 系统已记录您的能力画像,客服将根据│
|
|
|
+│ 您的专长合理分配订单。 │
|
|
|
+│ │
|
|
|
+│ 【您的能力画像】 │
|
|
|
+│ ━━━━━━━━━━━━━━━━━━━━━━━ │
|
|
|
+│ 擅长风格: 奶油风、极简风、新中式 │
|
|
|
+│ 擅长空间: 常规住宅、特殊功能空间 │
|
|
|
+│ 技术优势: 渲染精度高、方案深化能力│
|
|
|
+│ 项目难度: 中等难度 │
|
|
|
+│ 周承接量: 1-2个(中等难度) │
|
|
|
+│ 紧急订单: 愿意承接(每月不超过2次)│
|
|
|
+│ 进度同步: 关键节点同步 │
|
|
|
+│ 沟通方式: 群内文字、短语音、会议 │
|
|
|
+│ ━━━━━━━━━━━━━━━━━━━━━━━ │
|
|
|
+│ │
|
|
|
+│ 提示:您可以随时重新填写问卷更新信息│
|
|
|
+│ │
|
|
|
+│ [返回首页] [重新填写] │
|
|
|
+└─────────────────────────────────┘
|
|
|
+```
|
|
|
+
|
|
|
+#### 3.4.2 功能实现
|
|
|
+1. **结果展示**:
|
|
|
+ - 从 SurveyLog.data 读取答案
|
|
|
+ - 格式化显示(选择题显示选项文本,文本题直接显示)
|
|
|
+ - 提取关键信息形成"能力画像摘要"
|
|
|
+
|
|
|
+2. **权限控制**:
|
|
|
+ - 员工本人: 可查看完整结果
|
|
|
+ - 组长: 可查看所有组员的完整结果
|
|
|
+ - 管理员: 可查看所有员工的完整结果
|
|
|
+ - 客服: 可查看受限字段(不含敏感信息)
|
|
|
+
|
|
|
+3. **操作按钮**:
|
|
|
+ - "返回首页": 返回企微端工作台
|
|
|
+ - "重新填写": 重新进入答题页,更新问卷答案
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 四、员工详情弹窗集成
|
|
|
+
|
|
|
+### 4.1 员工列表问卷状态显示
|
|
|
+
|
|
|
+在 `employees.component.html` 的员工列表中增加问卷状态标识:
|
|
|
+
|
|
|
+```html
|
|
|
+<!-- 员工列表表格 -->
|
|
|
+<table class="employee-table">
|
|
|
+ <thead>
|
|
|
+ <tr>
|
|
|
+ <th>头像</th>
|
|
|
+ <th>姓名</th>
|
|
|
+ <th>职位</th>
|
|
|
+ <th>部门</th>
|
|
|
+ <th>问卷状态</th>
|
|
|
+ <th>操作</th>
|
|
|
+ </tr>
|
|
|
+ </thead>
|
|
|
+ <tbody>
|
|
|
+ <tr *ngFor="let employee of employees" (click)="openEmployeeDetail(employee)">
|
|
|
+ <td><img [src]="employee.avatar || 'assets/default-avatar.svg'" /></td>
|
|
|
+ <td>{{ employee.name }}</td>
|
|
|
+ <td>{{ employee.roleName }}</td>
|
|
|
+ <td>{{ employee.department }}</td>
|
|
|
+ <td>
|
|
|
+ <span class="survey-badge" [class.completed]="employee.surveyCompleted">
|
|
|
+ {{ employee.surveyCompleted ? '✓ 已填写' : '未填写' }}
|
|
|
+ </span>
|
|
|
+ </td>
|
|
|
+ <td>
|
|
|
+ <button (click)="openEmployeeDetail(employee); $event.stopPropagation()">
|
|
|
+ 查看详情
|
|
|
+ </button>
|
|
|
+ </td>
|
|
|
+ </tr>
|
|
|
+ </tbody>
|
|
|
+</table>
|
|
|
+```
|
|
|
+
|
|
|
+### 4.2 员工详情弹窗增加问卷答案展示
|
|
|
+
|
|
|
+在 `employee-detail-modal.component.html` 中增加问卷答案Tab:
|
|
|
+
|
|
|
+```html
|
|
|
+<!-- 员工详情弹窗 -->
|
|
|
+<div class="employee-detail-modal">
|
|
|
+ <div class="modal-header">
|
|
|
+ <h2>{{ employee?.name }} 的详细信息</h2>
|
|
|
+ <button (click)="close()">×</button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="modal-tabs">
|
|
|
+ <button [class.active]="currentTab === 'info'" (click)="currentTab = 'info'">
|
|
|
+ 基本信息
|
|
|
+ </button>
|
|
|
+ <button [class.active]="currentTab === 'survey'" (click)="currentTab = 'survey'">
|
|
|
+ 能力问卷
|
|
|
+ @if (!surveyCompleted) {
|
|
|
+ <span class="badge-warning">未填写</span>
|
|
|
+ }
|
|
|
+ </button>
|
|
|
+ <button [class.active]="currentTab === 'projects'" (click)="currentTab = 'projects'">
|
|
|
+ 项目列表
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="modal-body">
|
|
|
+ <!-- 基本信息Tab -->
|
|
|
+ @if (currentTab === 'info') {
|
|
|
+ <div class="info-section">
|
|
|
+ <div class="info-item">
|
|
|
+ <label>手机号:</label>
|
|
|
+ <span>{{ employee?.mobile }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="info-item">
|
|
|
+ <label>邮箱:</label>
|
|
|
+ <span>{{ employee?.email }}</span>
|
|
|
+ </div>
|
|
|
+ <!-- 其他基本信息... -->
|
|
|
+ </div>
|
|
|
+ }
|
|
|
+
|
|
|
+ <!-- 能力问卷Tab -->
|
|
|
+ @if (currentTab === 'survey') {
|
|
|
+ <div class="survey-section">
|
|
|
+ @if (!surveyCompleted) {
|
|
|
+ <div class="empty-state">
|
|
|
+ <ion-icon name="document-text-outline"></ion-icon>
|
|
|
+ <p>该员工尚未填写能力问卷</p>
|
|
|
+ <button (click)="sendSurveyLink()">发送问卷链接</button>
|
|
|
+ </div>
|
|
|
+ } @else {
|
|
|
+ <!-- 能力画像摘要 -->
|
|
|
+ <div class="capability-summary">
|
|
|
+ <h3>能力画像摘要</h3>
|
|
|
+ <div class="summary-grid">
|
|
|
+ <div class="summary-item">
|
|
|
+ <label>擅长风格:</label>
|
|
|
+ <div class="tags">
|
|
|
+ @for (style of surveyData.q1_expertise_styles; track style) {
|
|
|
+ <span class="tag">{{ style }}</span>
|
|
|
+ }
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="summary-item">
|
|
|
+ <label>技术优势:</label>
|
|
|
+ <div class="tags">
|
|
|
+ @for (adv of surveyData.q3_technical_advantages; track adv) {
|
|
|
+ <span class="tag tag-primary">{{ adv }}</span>
|
|
|
+ }
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="summary-item">
|
|
|
+ <label>项目难度:</label>
|
|
|
+ <span class="badge">{{ surveyData.q5_project_difficulty }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="summary-item">
|
|
|
+ <label>周承接量:</label>
|
|
|
+ <span>{{ surveyData.q7_weekly_capacity }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 详细问卷答案 -->
|
|
|
+ <div class="survey-details">
|
|
|
+ <h3>详细问卷答案</h3>
|
|
|
+
|
|
|
+ <div class="survey-section-group">
|
|
|
+ <h4>一、核心技术能力</h4>
|
|
|
+ <div class="answer-item">
|
|
|
+ <label>擅长风格:</label>
|
|
|
+ <span>{{ formatArrayAnswer(surveyData.q1_expertise_styles) }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="answer-item">
|
|
|
+ <label>擅长空间:</label>
|
|
|
+ <span>{{ formatArrayAnswer(surveyData.q2_expertise_spaces) }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="answer-item">
|
|
|
+ <label>技术优势:</label>
|
|
|
+ <span>{{ formatArrayAnswer(surveyData.q3_technical_advantages) }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="survey-section-group">
|
|
|
+ <h4>二、项目经验与案例</h4>
|
|
|
+ <div class="case-card">
|
|
|
+ <h5>代表性案例1</h5>
|
|
|
+ <p><strong>项目类型:</strong> {{ surveyData.q4_case_1_type }}</p>
|
|
|
+ <p><strong>核心亮点:</strong> {{ surveyData.q4_case_1_highlight }}</p>
|
|
|
+ </div>
|
|
|
+ @if (surveyData.q4_case_2_type) {
|
|
|
+ <div class="case-card">
|
|
|
+ <h5>代表性案例2</h5>
|
|
|
+ <p><strong>项目类型:</strong> {{ surveyData.q4_case_2_type }}</p>
|
|
|
+ <p><strong>核心亮点:</strong> {{ surveyData.q4_case_2_highlight }}</p>
|
|
|
+ </div>
|
|
|
+ }
|
|
|
+ <div class="answer-item">
|
|
|
+ <label>可独立处理的项目难度:</label>
|
|
|
+ <span>{{ surveyData.q5_project_difficulty }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 其他章节... -->
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="survey-footer">
|
|
|
+ <p class="survey-time">填写时间: {{ surveyCompletedAt | date:'yyyy-MM-dd HH:mm' }}</p>
|
|
|
+ <button (click)="sendSurveyUpdateLink()">通知员工更新问卷</button>
|
|
|
+ </div>
|
|
|
+ }
|
|
|
+ </div>
|
|
|
+ }
|
|
|
+
|
|
|
+ <!-- 项目列表Tab -->
|
|
|
+ @if (currentTab === 'projects') {
|
|
|
+ <!-- 项目列表内容... -->
|
|
|
+ }
|
|
|
+ </div>
|
|
|
+</div>
|
|
|
+```
|
|
|
+
|
|
|
+### 4.3 查询员工问卷数据
|
|
|
+
|
|
|
+在 `employee-detail-modal.component.ts` 中添加:
|
|
|
+
|
|
|
+```typescript
|
|
|
+// 问卷状态
|
|
|
+surveyCompleted: boolean = false;
|
|
|
+surveyData: any = null;
|
|
|
+surveyCompletedAt: Date | null = null;
|
|
|
+
|
|
|
+async loadEmployeeSurvey() {
|
|
|
+ if (!this.employee?.id) return;
|
|
|
+
|
|
|
+ try {
|
|
|
+ const query = new Parse.Query('SurveyLog');
|
|
|
+ const profilePointer = {
|
|
|
+ __type: 'Pointer',
|
|
|
+ className: 'Profile',
|
|
|
+ objectId: this.employee.id
|
|
|
+ };
|
|
|
+ query.equalTo('profile', profilePointer);
|
|
|
+ query.equalTo('type', 'survey-profile');
|
|
|
+ query.equalTo('isCompleted', true);
|
|
|
+ query.descending('updatedAt'); // 获取最新版本
|
|
|
+
|
|
|
+ const surveyLog = await query.first();
|
|
|
+
|
|
|
+ if (surveyLog) {
|
|
|
+ this.surveyCompleted = true;
|
|
|
+ this.surveyData = surveyLog.get('data') || {};
|
|
|
+ this.surveyCompletedAt = surveyLog.get('completedAt');
|
|
|
+ }
|
|
|
+ } catch (err) {
|
|
|
+ console.error('查询员工问卷失败:', err);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+formatArrayAnswer(arr: string[] | string): string {
|
|
|
+ if (Array.isArray(arr)) {
|
|
|
+ return arr.join('、');
|
|
|
+ }
|
|
|
+ return arr || '未填写';
|
|
|
+}
|
|
|
+
|
|
|
+sendSurveyLink() {
|
|
|
+ const surveyUrl = `${window.location.origin}/wxwork/${this.cid}/survey/profile`;
|
|
|
+ // TODO: 通过企微发送问卷链接给员工
|
|
|
+ window?.fmode?.alert('问卷链接已发送给员工');
|
|
|
+}
|
|
|
+
|
|
|
+sendSurveyUpdateLink() {
|
|
|
+ const surveyUrl = `${window.location.origin}/wxwork/${this.cid}/survey/profile`;
|
|
|
+ // TODO: 通过企微通知员工更新问卷
|
|
|
+ window?.fmode?.alert('已通知员工更新问卷');
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 五、企业微信端员工认证集成
|
|
|
+
|
|
|
+### 5.1 员工首次登录引导流程
|
|
|
+
|
|
|
+```
|
|
|
+[企微端首次登录]
|
|
|
+ ↓
|
|
|
+[检测是否填写问卷]
|
|
|
+ ↓ 否
|
|
|
+[引导页:请完善您的能力画像]
|
|
|
+ ↓
|
|
|
+[跳转到问卷填写页]
|
|
|
+ ↓
|
|
|
+[填写完成]
|
|
|
+ ↓
|
|
|
+[进入工作台]
|
|
|
+```
|
|
|
+
|
|
|
+### 5.2 Wxwork端首页增加问卷入口
|
|
|
+
|
|
|
+在 `src/modules/wxwork/pages/home/home.component.ts` 中添加:
|
|
|
+
|
|
|
+```typescript
|
|
|
+async ngOnInit() {
|
|
|
+ // 1. 企微身份认证
|
|
|
+ await this.wxAuth.authenticate();
|
|
|
+
|
|
|
+ // 2. 获取当前员工Profile
|
|
|
+ this.currentProfile = await this.wxAuth.currentProfile();
|
|
|
+
|
|
|
+ // 3. 检查是否填写问卷
|
|
|
+ await this.checkSurveyStatus();
|
|
|
+
|
|
|
+ // 4. 如果未填写,显示引导弹窗
|
|
|
+ if (!this.surveyCompleted) {
|
|
|
+ this.showSurveyGuide = true;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+async checkSurveyStatus() {
|
|
|
+ if (!this.currentProfile?.id) return;
|
|
|
+
|
|
|
+ try {
|
|
|
+ const query = new Parse.Query('SurveyLog');
|
|
|
+ query.equalTo('profile', this.currentProfile.toPointer());
|
|
|
+ query.equalTo('type', 'survey-profile');
|
|
|
+ query.equalTo('isCompleted', true);
|
|
|
+
|
|
|
+ const surveyLog = await query.first();
|
|
|
+ this.surveyCompleted = !!surveyLog;
|
|
|
+ } catch (err) {
|
|
|
+ console.error('检查问卷状态失败:', err);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+goToSurvey() {
|
|
|
+ this.router.navigate(['/wxwork', this.cid, 'survey', 'profile']);
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 5.3 问卷引导弹窗
|
|
|
+
|
|
|
+```html
|
|
|
+<!-- 问卷引导弹窗 -->
|
|
|
+@if (showSurveyGuide) {
|
|
|
+ <div class="survey-guide-modal">
|
|
|
+ <div class="modal-content">
|
|
|
+ <div class="guide-icon">
|
|
|
+ <ion-icon name="clipboard-outline"></ion-icon>
|
|
|
+ </div>
|
|
|
+ <h2>完善您的能力画像</h2>
|
|
|
+ <p>
|
|
|
+ 为了更精准地为您匹配合适的项目,<br/>
|
|
|
+ 请花8-10分钟完成能力调研问卷。
|
|
|
+ </p>
|
|
|
+ <p class="guide-tip">
|
|
|
+ 您的选择将帮助我们合理分配订单,<br/>
|
|
|
+ 避免不匹配项目导致返工。
|
|
|
+ </p>
|
|
|
+ <div class="guide-actions">
|
|
|
+ <button class="btn-secondary" (click)="showSurveyGuide = false">
|
|
|
+ 稍后填写
|
|
|
+ </button>
|
|
|
+ <button class="btn-primary" (click)="goToSurvey()">
|
|
|
+ 立即填写
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 六、技术实现要点
|
|
|
+
|
|
|
+### 6.1 企微授权集成
|
|
|
+
|
|
|
+```typescript
|
|
|
+import { WxworkAuth } from 'fmode-ng/core';
|
|
|
+
|
|
|
+async ngOnInit() {
|
|
|
+ // 1. 初始化企微授权
|
|
|
+ const cid = this.route.snapshot.paramMap.get('cid') || '';
|
|
|
+ this.wxAuth = new WxworkAuth({ cid, appId: 'crm' });
|
|
|
+
|
|
|
+ // 2. 获取当前登录员工
|
|
|
+ try {
|
|
|
+ this.currentProfile = await this.wxAuth.currentProfile();
|
|
|
+ console.log('当前员工:', this.currentProfile);
|
|
|
+ } catch (error) {
|
|
|
+ console.error('获取员工信息失败:', error);
|
|
|
+ window?.fmode?.alert('无法识别您的身份,请通过企微重新进入');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. 检查是否已填写问卷
|
|
|
+ await this.checkExistingSurvey();
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 6.2 数据查询与保存
|
|
|
+
|
|
|
+```typescript
|
|
|
+// 查询现有问卷
|
|
|
+async checkExistingSurvey() {
|
|
|
+ const query = new Parse.Query('SurveyLog');
|
|
|
+ query.equalTo('profile', this.currentProfile.toPointer());
|
|
|
+ query.equalTo('type', 'survey-profile');
|
|
|
+ query.descending('updatedAt'); // 获取最新版本
|
|
|
+
|
|
|
+ this.surveyLog = await query.first();
|
|
|
+
|
|
|
+ if (this.surveyLog?.get('isCompleted')) {
|
|
|
+ // 已完成,直接显示结果
|
|
|
+ this.currentState = 'result';
|
|
|
+ } else if (this.surveyLog) {
|
|
|
+ // 未完成,恢复进度
|
|
|
+ this.answers = this.surveyLog.get('data') || {};
|
|
|
+ this.currentState = 'questionnaire';
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 保存答案
|
|
|
+async saveAnswer(questionId: string, answer: any) {
|
|
|
+ if (!this.surveyLog) {
|
|
|
+ // 首次保存,创建记录
|
|
|
+ const SurveyLog = Parse.Object.extend('SurveyLog');
|
|
|
+ this.surveyLog = new SurveyLog();
|
|
|
+
|
|
|
+ const company = new Parse.Object('Company');
|
|
|
+ company.id = localStorage.getItem('company') || '';
|
|
|
+
|
|
|
+ this.surveyLog.set('company', company.toPointer());
|
|
|
+ this.surveyLog.set('profile', this.currentProfile.toPointer());
|
|
|
+ this.surveyLog.set('type', 'survey-profile');
|
|
|
+ this.surveyLog.set('version', 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新答案
|
|
|
+ const data = this.surveyLog.get('data') || {};
|
|
|
+ data[questionId] = answer;
|
|
|
+ this.surveyLog.set('data', data);
|
|
|
+
|
|
|
+ await this.surveyLog.save();
|
|
|
+}
|
|
|
+
|
|
|
+// 完成问卷
|
|
|
+async completeSurvey() {
|
|
|
+ if (!this.surveyLog) return;
|
|
|
+
|
|
|
+ this.surveyLog.set('isCompleted', true);
|
|
|
+ this.surveyLog.set('completedAt', new Date());
|
|
|
+ await this.surveyLog.save();
|
|
|
+
|
|
|
+ // 切换到结果页
|
|
|
+ this.currentState = 'result';
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 6.3 多选题选择数量限制
|
|
|
+
|
|
|
+```typescript
|
|
|
+// 多选题选择逻辑
|
|
|
+toggleMultipleOption(option: string) {
|
|
|
+ const question = this.getCurrentQuestion();
|
|
|
+ if (!question) return;
|
|
|
+
|
|
|
+ if (!this.answers[question.id]) {
|
|
|
+ this.answers[question.id] = [];
|
|
|
+ }
|
|
|
+
|
|
|
+ const index = this.answers[question.id].indexOf(option);
|
|
|
+
|
|
|
+ if (index > -1) {
|
|
|
+ // 取消选择
|
|
|
+ this.answers[question.id].splice(index, 1);
|
|
|
+ } else {
|
|
|
+ // 检查是否达到最大选择数
|
|
|
+ if (question.maxSelections &&
|
|
|
+ this.answers[question.id].length >= question.maxSelections) {
|
|
|
+ window?.fmode?.alert(`最多只能选择 ${question.maxSelections} 项`);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 添加选择
|
|
|
+ this.answers[question.id].push(option);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 获取选择进度文本
|
|
|
+getSelectionProgress(question: Question): string {
|
|
|
+ if (!question.maxSelections) return '';
|
|
|
+ const count = this.answers[question.id]?.length || 0;
|
|
|
+ return `已选 ${count}/${question.maxSelections} 项`;
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 七、UI样式设计参考
|
|
|
+
|
|
|
+### 7.1 样式继承客户问卷
|
|
|
+- 保持与客户问卷一致的视觉风格
|
|
|
+- 使用相同的配色方案(紫色主题渐变)
|
|
|
+- 保持相同的卡片布局和进度条样式
|
|
|
+- 统一的按钮风格和交互动效
|
|
|
+
|
|
|
+### 7.2 差异化设计
|
|
|
+- 员工问卷使用蓝色或橙色作为强调色(区别于客户问卷的紫色)
|
|
|
+- 多选题显示选择进度(如"已选 2/3 项")
|
|
|
+- 能力画像摘要卡片使用徽章和标签展示
|
|
|
+- 案例展示使用独立的卡片样式
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 八、数据分析与应用
|
|
|
+
|
|
|
+### 8.1 能力画像统计
|
|
|
+在管理后台增加"团队能力分析"页面:
|
|
|
+
|
|
|
+- **风格分布**: 统计团队擅长的风格分布(饼图)
|
|
|
+- **技术能力矩阵**: 展示不同技术能力的人数分布(雷达图)
|
|
|
+- **承接能力**: 统计团队总承接量和紧急订单承接意愿
|
|
|
+- **协作偏好**: 分析团队沟通方式偏好,优化协作流程
|
|
|
+
|
|
|
+### 8.2 智能订单分配
|
|
|
+基于问卷数据优化订单分配逻辑:
|
|
|
+
|
|
|
+```typescript
|
|
|
+// 订单智能匹配算法
|
|
|
+function matchDesigner(project: Project): Profile[] {
|
|
|
+ const requirements = project.requirements; // 项目需求
|
|
|
+ const candidates: Profile[] = [];
|
|
|
+
|
|
|
+ // 1. 查询所有已填写问卷的设计师
|
|
|
+ const query = new Parse.Query('SurveyLog');
|
|
|
+ query.equalTo('type', 'survey-profile');
|
|
|
+ query.equalTo('isCompleted', true);
|
|
|
+ query.include('profile');
|
|
|
+
|
|
|
+ const surveys = await query.find();
|
|
|
+
|
|
|
+ // 2. 匹配算法
|
|
|
+ for (const survey of surveys) {
|
|
|
+ const data = survey.get('data');
|
|
|
+ let score = 0;
|
|
|
+
|
|
|
+ // 风格匹配 (+30分)
|
|
|
+ if (data.q1_expertise_styles?.includes(requirements.style)) {
|
|
|
+ score += 30;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 空间类型匹配 (+20分)
|
|
|
+ if (data.q2_expertise_spaces?.includes(requirements.spaceType)) {
|
|
|
+ score += 20;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 项目难度匹配 (+20分)
|
|
|
+ if (matchDifficulty(data.q5_project_difficulty, requirements.difficulty)) {
|
|
|
+ score += 20;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 当前负载 (+15分,负载越低分数越高)
|
|
|
+ const currentLoad = await getDesignerLoad(survey.get('profile').id);
|
|
|
+ const maxLoad = parseWeeklyCapacity(data.q7_weekly_capacity);
|
|
|
+ score += (1 - currentLoad / maxLoad) * 15;
|
|
|
+
|
|
|
+ // 紧急订单匹配 (+15分)
|
|
|
+ if (requirements.isUrgent && data.q8_urgent_willingness === '愿意承接') {
|
|
|
+ score += 15;
|
|
|
+ }
|
|
|
+
|
|
|
+ candidates.push({
|
|
|
+ profile: survey.get('profile'),
|
|
|
+ score: score,
|
|
|
+ surveyData: data
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. 按分数排序
|
|
|
+ candidates.sort((a, b) => b.score - a.score);
|
|
|
+
|
|
|
+ return candidates.slice(0, 5); // 返回前5名候选人
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 九、实施步骤
|
|
|
+
|
|
|
+### 9.1 Phase 1: 核心组件开发
|
|
|
+1. 创建 ProfileSurveyComponent 组件
|
|
|
+2. 实现问卷欢迎页、答题页、结果页
|
|
|
+3. 集成企微身份认证
|
|
|
+4. 实现数据保存和查询逻辑
|
|
|
+
|
|
|
+### 9.2 Phase 2: 后台管理集成
|
|
|
+1. 员工列表增加问卷状态标识
|
|
|
+2. 员工详情弹窗增加问卷答案Tab
|
|
|
+3. 实现问卷数据格式化展示
|
|
|
+4. 增加"发送问卷链接"功能
|
|
|
+
|
|
|
+### 9.3 Phase 3: 企微端引导流程
|
|
|
+1. 首页增加问卷状态检测
|
|
|
+2. 实现问卷引导弹窗
|
|
|
+3. 在工作台增加"更新问卷"入口
|
|
|
+4. 问卷填写完成后的引导提示
|
|
|
+
|
|
|
+### 9.4 Phase 4: 数据分析与应用
|
|
|
+1. 开发团队能力分析页面
|
|
|
+2. 优化订单智能分配算法
|
|
|
+3. 增加问卷数据导出功能
|
|
|
+4. 实现问卷版本迭代机制
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 十、测试用例
|
|
|
+
|
|
|
+### 10.1 基本流程测试
|
|
|
+- [ ] 员工首次登录,显示问卷引导弹窗
|
|
|
+- [ ] 填写问卷,每题自动保存
|
|
|
+- [ ] 中途退出后恢复进度
|
|
|
+- [ ] 提交完成,显示结果页
|
|
|
+- [ ] 再次进入,直接显示结果页
|
|
|
+
|
|
|
+### 10.2 题目交互测试
|
|
|
+- [ ] 单选题自动跳转下一题
|
|
|
+- [ ] 多选题达到上限后禁用其他选项
|
|
|
+- [ ] "其他"选项显示输入框
|
|
|
+- [ ] 必填题未填写时提示
|
|
|
+- [ ] 上一题按钮返回上一题
|
|
|
+
|
|
|
+### 10.3 后台管理测试
|
|
|
+- [ ] 员工列表正确显示问卷状态
|
|
|
+- [ ] 员工详情弹窗正确显示问卷答案
|
|
|
+- [ ] 格式化展示多选答案
|
|
|
+- [ ] 案例卡片正确显示
|
|
|
+- [ ] "发送问卷链接"功能正常
|
|
|
+
|
|
|
+### 10.4 权限测试
|
|
|
+- [ ] 员工本人可查看完整问卷
|
|
|
+- [ ] 组长可查看所有组员问卷
|
|
|
+- [ ] 管理员可查看所有员工问卷
|
|
|
+- [ ] 非授权人员无法访问他人问卷
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 十一、后续优化方向
|
|
|
+
|
|
|
+### 11.1 问卷版本管理
|
|
|
+- 支持问卷题目迭代更新
|
|
|
+- 记录员工每次填写的历史版本
|
|
|
+- 对比不同版本的答案变化
|
|
|
+
|
|
|
+### 11.2 智能推荐
|
|
|
+- 基于问卷数据推荐培训课程
|
|
|
+- 推荐适合的项目类型
|
|
|
+- 推荐协作伙伴(能力互补)
|
|
|
+
|
|
|
+### 11.3 数据可视化
|
|
|
+- 个人能力雷达图
|
|
|
+- 团队能力分布热力图
|
|
|
+- 订单匹配成功率趋势
|
|
|
+
|
|
|
+### 11.4 自动化流程
|
|
|
+- 新员工入职自动发送问卷
|
|
|
+- 定期(如每季度)提醒员工更新问卷
|
|
|
+- 问卷未填写自动限制接单
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 附录:问卷完整题目清单
|
|
|
+
|
|
|
+### 一、核心技术能力(3题)
|
|
|
+1. 您最擅长的家装风格?(多选,优先选3项)
|
|
|
+2. 您擅长的空间类型?(多选)
|
|
|
+3. 技术能力优势?(多选,优先选2项)
|
|
|
+
|
|
|
+### 二、项目经验与案例(5题)
|
|
|
+4. 代表性案例1:项目类型(文本)
|
|
|
+5. 代表性案例1:核心亮点(多行文本)
|
|
|
+6. 代表性案例2:项目类型(文本,选填)
|
|
|
+7. 代表性案例2:核心亮点(多行文本,选填)
|
|
|
+8. 可独立处理的项目难度?(单选)
|
|
|
+
|
|
|
+### 三、项目承接偏好(4题)
|
|
|
+9. 您优先想承接的项目类型?(多选)
|
|
|
+10. 您可承接的单周期项目数量上限?(单选)
|
|
|
+11. 对紧急订单的承接意愿?(单选)
|
|
|
+12. 如愿意承接紧急订单,每月上限?(数字,选填)
|
|
|
+
|
|
|
+### 四、协作与交付习惯(4题)
|
|
|
+13. 项目进度反馈与时效把控?(单选)
|
|
|
+14. 交付前确认流程?(多选)
|
|
|
+15. 对接需求时,您希望获取的客户信息清晰度?(单选)
|
|
|
+16. 若项目需协作,您倾向的对接方式?(多选)
|
|
|
+
|
|
|
+### 五、问题应对与风险预警(3题)
|
|
|
+17. 您了解项目中的"敏感词"吗?(单选)
|
|
|
+18. 若某个环节出问题,您的处理流程?(单选)
|
|
|
+19. 您希望的代办任务通知方式?(多选)
|
|
|
+
|
|
|
+### 六、补充说明(2题)
|
|
|
+20. 暂时无法承接的项目类型?(多行文本,选填)
|
|
|
+21. 其他项目相关补充?(多行文本,选填)
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+**文档版本**: v1.0
|
|
|
+**创建时间**: 2025-10-30
|
|
|
+**作者**: AI Assistant
|
|
|
+**审核状态**: 待审核
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|