员工问卷是内部技术组员的专业特长及偏好调研工具,通过系统化问卷了解员工的技术能力、项目经验、承接偏好和协作习惯,为客服智能分配订单提供数据支撑。
| 字段名 | 类型 | 必填 | 说明 | 示例值 |
|---|---|---|---|---|
| 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 字段结构示例:
{
"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进行渲染;希望多承接新中式风格项目,进一步提升该风格的方案深化与软装搭配能力;针对老人房、儿童房等特殊功能空间,可提供符合使用者生理与心理需求的细节优化建议。"
}
// 路由: /wxwork/:cid/survey/profile
{
path: 'wxwork/:cid',
children: [
{
path: 'survey/profile',
loadComponent: () => import('../modules/profile/pages/profile-survey/profile-survey.component'),
title: '员工技能调研'
}
]
}
组件包含三种状态,通过 currentState 控制:
type SurveyState = 'welcome' | 'questionnaire' | 'result';
currentState: SurveyState = 'welcome';
状态转换流程:
[欢迎页] --点击开始--> [答题页] --提交完成--> [结果页]
↑ ↓
└──────────────── 重新填写 ──────────────────┘
┌─────────────────────────────────┐
│ 员工问卷欢迎页 │
├─────────────────────────────────┤
│ [员工头像] │
│ 您好,张三 │
│ │
│ 《技术组员偏好及状况调研表》 │
│ │
│ 尊敬的伙伴: │
│ 为了更精准地匹配项目与您的专业能力│
│ 请完成本次能力调研。您的选择将帮助│
│ 我们合理分配订单,避免不匹配项目导│
│ 致返工,让您的优势得到充分发挥! │
│ │
│ • 预计用时: 8-10分钟 │
│ • 题目数量: 17题 │
│ • 题型: 选择题为主,少量填空题 │
│ │
│ [开始填写] │
│ │
│ [已填写过? 查看/更新答案] │
└─────────────────────────────────┘
用户识别:
WxworkAuth.currentProfile() 获取当前登录员工profile.id 用于后续保存数据检查:
type == 'survey-profile' AND profile == profileIdisCompleted == true,显示"查看/更新答案"入口开始按钮:
startSurvey()currentState = 'questionnaire'currentQuestionIndex = 0┌─────────────────────────────────┐
│ 进度: 1/17 ●○○○○○○○○○○○○○○○○ │
├─────────────────────────────────┤
│ 一、核心技术能力 │
│ │
│ 1. 您最擅长的家装风格? │
│ (可多选,优先选3项) │
│ │
│ ☑ 奶油风 │
│ ☑ 极简风(含侘寂风) │
│ ☑ 新中式 │
│ □ 轻奢风 │
│ □ 美式/欧式 │
│ □ 复古风(如法式、美式复古) │
│ □ 其他: [____________] │
│ │
│ [← 上一题] [下一题 →] │
└─────────────────────────────────┘
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; // 输入框占位符
}
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
}
];
单选题:
answers[questionId]多选题:
maxSelections 限制,达到上限后禁用其他选项已选 2/3 项文本题/数字题:
多行文本题:
进度指示:
currentQuestionIndex / totalQuestions导航按钮:
自动保存:
保存方式:
surveyLog.set('data', {
...surveyLog.get('data'),
[questionId]: answer
});
await surveyLog.save();
完成标记:
isCompleted = truecompletedAt = new Date()version = 1(用于后续问卷更新迭代)┌─────────────────────────────────┐
│ ✓ 问卷提交成功 │
├─────────────────────────────────┤
│ 感谢您的反馈! │
│ 系统已记录您的能力画像,客服将根据│
│ 您的专长合理分配订单。 │
│ │
│ 【您的能力画像】 │
│ ━━━━━━━━━━━━━━━━━━━━━━━ │
│ 擅长风格: 奶油风、极简风、新中式 │
│ 擅长空间: 常规住宅、特殊功能空间 │
│ 技术优势: 渲染精度高、方案深化能力│
│ 项目难度: 中等难度 │
│ 周承接量: 1-2个(中等难度) │
│ 紧急订单: 愿意承接(每月不超过2次)│
│ 进度同步: 关键节点同步 │
│ 沟通方式: 群内文字、短语音、会议 │
│ ━━━━━━━━━━━━━━━━━━━━━━━ │
│ │
│ 提示:您可以随时重新填写问卷更新信息│
│ │
│ [返回首页] [重新填写] │
└─────────────────────────────────┘
结果展示:
权限控制:
操作按钮:
在 employees.component.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>
在 employee-detail-modal.component.html 中增加问卷答案Tab:
<!-- 员工详情弹窗 -->
<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>
在 employee-detail-modal.component.ts 中添加:
// 问卷状态
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('已通知员工更新问卷');
}
[企微端首次登录]
↓
[检测是否填写问卷]
↓ 否
[引导页:请完善您的能力画像]
↓
[跳转到问卷填写页]
↓
[填写完成]
↓
[进入工作台]
在 src/modules/wxwork/pages/home/home.component.ts 中添加:
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']);
}
<!-- 问卷引导弹窗 -->
@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>
}
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();
}
// 查询现有问卷
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';
}
// 多选题选择逻辑
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} 项`;
}
在管理后台增加"团队能力分析"页面:
基于问卷数据优化订单分配逻辑:
// 订单智能匹配算法
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名候选人
}
文档版本: v1.0
创建时间: 2025-10-30
作者: AI Assistant
审核状态: 待审核