需要添加的字段:
Profile.data.hrData {
// 现有字段
employeeId: string,
level: 'junior' | 'intermediate' | 'senior',
hireDate: Date,
employmentStatus: string,
// 🆕 新增字段
mentor: Pointer<Profile>, // 导师(用于新人管理)
resignationDate: Date, // 离职日期
probationEndDate: Date, // 试用期结束日期
convertedDate: Date // 转正日期
}
实施代码:
// dashboard.ts
async loadBasicStatistics() {
// 1. 职级分布
const rankDist = await this.loadRankDistribution();
// 2. 入离职趋势
const monthlyTrend = await this.loadMonthlyTrend();
// 3. 新人列表
const newbies = await this.loadNewbieList();
return { rankDist, monthlyTrend, newbies };
}
// 职级分布(立即可用)
async loadRankDistribution() {
const query = new Parse.Query('Profile');
query.equalTo('isActivated', true);
query.notEqualTo('isDeleted', true);
query.equalTo('data.hrData.employmentStatus', 'active');
const profiles = await query.find();
const dist = { junior: 0, intermediate: 0, senior: 0 };
profiles.forEach(p => {
const level = p.get('data')?.hrData?.level || 'junior';
dist[level]++;
});
return Object.entries(dist).map(([level, count]) => ({
level: level === 'junior' ? '初级' : level === 'intermediate' ? '中级' : '高级',
count,
percentage: ((count / profiles.length) * 100).toFixed(1)
}));
}
# Parse Dashboard 操作步骤
1. 打开 Parse Dashboard
2. 选择数据库 → 创建新Class → "Resume"
3. 添加以下字段:
字段名 类型 说明
candidateName String 候选人姓名
contact Object 联系方式
resumeText String 简历文本
resumeFileUrl File 简历文件
uploadDate Date 上传日期
status String 状态
education Object 教育背景
experience Object 工作经验
skills Array 技能列表
projects Array 项目经历
jobPosition String 应聘职位
expectedSalary Number 期望薪资
字段名 类型 说明
resume Pointer 关联简历
analysisDate Date 分析时间
overallScore Number 综合评分
dimensions Object 多维度评分
recommendation Object AI推荐
screeningResults Array 筛选结果
文件:dashboard.ts
import { DoubaoAiService } from '../../../services/doubao-ai.service';
export class HRDashboard {
constructor(
private doubaoAi: DoubaoAiService
) {}
// 上传并分析简历
async uploadAndAnalyzeResume(file: File, jobPosition: string) {
// 1. 读取简历文件
const resumeText = await this.extractTextFromFile(file);
// 2. 创建简历记录
const Resume = Parse.Object.extend('Resume');
const resume = new Resume();
const parseFile = new Parse.File(file.name, file);
await parseFile.save();
resume.set('candidateName', this.extractNameFromResume(resumeText));
resume.set('resumeText', resumeText);
resume.set('resumeFileUrl', parseFile);
resume.set('uploadDate', new Date());
resume.set('status', 'pending');
resume.set('jobPosition', jobPosition);
await resume.save();
// 3. 调用 AI 分析
const analysisRequest = {
resumeText,
jobPosition,
jobRequirements: this.getJobRequirements(jobPosition)
};
const aiResult = await this.doubaoAi
.analyzeResume(analysisRequest)
.toPromise();
// 4. 保存分析结果
const Analysis = Parse.Object.extend('ResumeAnalysis');
const analysis = new Analysis();
analysis.set('resume', resume);
analysis.set('analysisDate', new Date());
analysis.set('overallScore', aiResult.overallScore);
analysis.set('dimensions', this.buildDimensionsObject(aiResult));
analysis.set('recommendation', aiResult.recommendation);
analysis.set('screeningResults', aiResult.screeningInfo);
await analysis.save();
// 5. 更新简历状态
resume.set('status', 'analyzed');
await resume.save();
return { resume, analysis };
}
// 构建多维度评分对象
buildDimensionsObject(aiResult: any) {
return {
education: this.extractDimension(aiResult, '学历'),
skills: this.extractDimension(aiResult, '技能'),
projectExperience: this.extractDimension(aiResult, '项目经验'),
workExperience: this.extractDimension(aiResult, '工作经验'),
capability: this.extractDimension(aiResult, '综合能力'),
cultureFit: this.extractDimension(aiResult, '文化匹配')
};
}
extractDimension(aiResult: any, dimensionName: string) {
const dimension = aiResult.matchDimensions.find(d =>
d.name.includes(dimensionName)
);
if (!dimension) {
return {
score: 0,
level: 'low',
detail: '暂无数据'
};
}
return {
score: dimension.score,
level: dimension.level,
detail: dimension.description || ''
};
}
// 获取职位要求
getJobRequirements(jobPosition: string): string[] {
const requirementsMap = {
'设计师': [
'本科及以上学历,设计相关专业优先',
'3年以上室内设计经验',
'精通 Photoshop, Illustrator, Sketch, AutoCAD',
'有住宅或商业空间设计经验',
'良好的审美能力和创新思维',
'良好的沟通能力和团队协作精神',
'能承受工作压力,按时完成任务'
],
'高级设计师': [
'本科及以上学历,设计相关专业',
'5年以上室内设计经验',
'精通各类设计软件',
'有大型项目独立设计经验',
'优秀的设计能力和项目管理能力',
'可以带领团队完成项目',
'有成功案例和作品集'
],
'客服专员': [
'大专及以上学历',
'1年以上客服经验',
'熟练使用办公软件',
'良好的沟通能力和服务意识',
'耐心细致,抗压能力强'
]
};
return requirementsMap[jobPosition] || requirementsMap['设计师'];
}
}
字段名 类型 说明
profile Pointer 关联员工
department Pointer 部门
period Object 时期(年月季度)
projectMetrics Object 项目指标
capabilities Object 能力评估
overallScore Number 综合评分
rank String 排名
level String 等级
// 自动生成月度绩效(定时任务,每月1日执行)
async generateMonthlyPerformance() {
const lastMonth = this.getLastMonthPeriod();
const designers = await this.getActiveDesigners();
for (const designer of designers) {
// 查询该设计师上月的项目
const projectQuery = new Parse.Query('Project');
projectQuery.equalTo('assignee', designer);
projectQuery.greaterThanOrEqualTo('createdAt', lastMonth.start);
projectQuery.lessThan('createdAt', lastMonth.end);
const projects = await projectQuery.find();
// 计算项目指标
const metrics = {
totalProjects: projects.length,
completedProjects: projects.filter(p =>
p.get('status') === 'completed'
).length,
excellentProjects: projects.filter(p =>
p.get('data')?.quality?.isExcellent
).length,
overdueProjects: projects.filter(p => {
const expected = p.get('data')?.timeline?.expectedDate;
const actual = p.get('data')?.timeline?.actualDate;
return actual && expected && actual > expected;
}).length,
averageQuality: this.calculateAverage(
projects, p => p.get('data')?.quality?.score || 0
),
averageSatisfaction: this.calculateAverage(
projects, p => p.get('data')?.clientSatisfaction || 0
)
};
// 计算能力评估(基于项目反馈)
const capabilities = await this.calculateCapabilities(designer, projects);
// 计算综合评分
const overallScore = this.calculateOverallScore(metrics, capabilities);
// 保存绩效记录
const Performance = Parse.Object.extend('PerformanceRecord');
const record = new Performance();
record.set('profile', designer);
record.set('department', designer.get('department'));
record.set('period', {
year: lastMonth.year,
month: lastMonth.month,
quarter: Math.ceil(lastMonth.month / 3)
});
record.set('projectMetrics', metrics);
record.set('capabilities', capabilities);
record.set('overallScore', overallScore);
record.set('level', this.getLevel(overallScore));
await record.save();
}
// 计算排名
await this.calculateRankings(lastMonth);
}
// 计算综合评分
calculateOverallScore(metrics: any, capabilities: any): number {
// 项目指标权重 60%
const projectScore = (
(metrics.completedProjects / metrics.totalProjects) * 20 + // 完成率 20%
(metrics.excellentProjects / metrics.totalProjects) * 15 + // 优秀率 15%
metrics.averageQuality * 0.15 + // 质量 15%
metrics.averageSatisfaction * 0.10 // 满意度 10%
);
// 能力指标权重 40%
const capabilityScore = (
capabilities.design * 0.10 + // 设计能力 10%
capabilities.communication * 0.08 + // 沟通能力 8%
capabilities.execution * 0.10 + // 执行能力 10%
capabilities.innovation * 0.06 + // 创新能力 6%
capabilities.teamwork * 0.04 + // 团队协作 4%
capabilities.growth * 0.02 // 成长潜力 2%
);
return Math.round(projectScore + capabilityScore);
}
// 从项目反馈计算能力评估
async calculateCapabilities(designer: any, projects: any[]): Promise<any> {
// 这里需要从项目反馈、客户评价等数据中提取
// 暂时使用基础算法
const capabilities = {
design: 0,
communication: 0,
execution: 0,
innovation: 0,
teamwork: 0,
growth: 0
};
if (projects.length === 0) {
return capabilities;
}
// 从项目质量推断设计能力
capabilities.design = this.calculateAverage(
projects, p => p.get('data')?.quality?.score || 60
);
// 从客户满意度推断沟通能力
capabilities.communication = this.calculateAverage(
projects, p => p.get('data')?.clientSatisfaction || 70
);
// 从完成率推断执行能力
const completionRate = projects.filter(p =>
p.get('status') === 'completed'
).length / projects.length;
capabilities.execution = completionRate * 100;
// 从优秀作品率推断创新能力
const excellentRate = projects.filter(p =>
p.get('data')?.quality?.isExcellent
).length / projects.length;
capabilities.innovation = excellentRate * 100;
// 团队协作和成长潜力需要更复杂的评估
capabilities.teamwork = 75; // 默认值
capabilities.growth = 70; // 默认值
return capabilities;
}
doubao-ai.service.ts 增强:
// 增加多维度分析逻辑
performIntelligentAnalysis(request: ResumeAnalysisRequest): ResumeAnalysisResponse {
const resumeText = request.resumeText.toLowerCase();
const requirements = request.jobRequirements;
// 1. 学历维度分析
const educationScore = this.analyzeEducation(resumeText);
// 2. 技能维度分析
const skillsAnalysis = this.analyzeSkills(resumeText, requirements);
// 3. 项目经验分析
const projectAnalysis = this.analyzeProjects(resumeText);
// 4. 工作经验分析
const workAnalysis = this.analyzeWorkExperience(resumeText);
// 5. 综合能力分析
const capabilityAnalysis = this.analyzeCapability(resumeText);
// 6. 计算总分
const overallScore = this.calculateOverallScore({
education: educationScore,
skills: skillsAnalysis.score,
project: projectAnalysis.score,
work: workAnalysis.score,
capability: capabilityAnalysis.score
});
return {
overallScore,
matchDimensions: [
{
id: 1,
name: '学历背景',
score: educationScore.score,
level: this.getLevel(educationScore.score),
icon: 'school',
description: educationScore.detail
},
{
id: 2,
name: '技能匹配',
score: skillsAnalysis.score,
level: this.getLevel(skillsAnalysis.score),
icon: 'verified',
description: `匹配${skillsAnalysis.matchedCount}/${skillsAnalysis.totalCount}项技能`
},
// ... 其他维度
],
recommendation: this.generateRecommendation(overallScore),
screeningInfo: this.generateScreeningInfo({
education: educationScore,
skills: skillsAnalysis,
work: workAnalysis
}),
analysisTime: new Date()
};
}
// 学历分析
analyzeEducation(resumeText: string) {
const degrees = {
'博士': 100,
'phd': 100,
'硕士': 90,
'master': 90,
'本科': 80,
'bachelor': 80,
'大专': 60,
'college': 60
};
let score = 50; // 默认分数
let degree = '未知';
for (const [key, value] of Object.entries(degrees)) {
if (resumeText.includes(key)) {
score = value;
degree = key;
break;
}
}
return {
score,
degree,
detail: `学历:${degree},评分:${score}`
};
}
// 技能分析
analyzeSkills(resumeText: string, requirements: string[]) {
const commonSkills = [
'photoshop', 'ps', 'illustrator', 'ai',
'sketch', 'autocad', 'cad', '3dmax',
'vray', 'sketchup', 'lumion', 'enscape'
];
const matchedSkills = commonSkills.filter(skill =>
resumeText.includes(skill)
);
const score = (matchedSkills.length / commonSkills.length) * 100;
return {
score: Math.round(score),
matchedCount: matchedSkills.length,
totalCount: commonSkills.length,
matchedSkills,
missingSkills: commonSkills.filter(s => !matchedSkills.includes(s))
};
}
使用 Chart.js:
// dashboard.ts
import { Chart, ChartConfiguration } from 'chart.js';
@ViewChild('radarChart') radarCanvas: ElementRef;
@ViewChild('pieChart') pieCanvas: ElementRef;
@ViewChild('lineChart') lineCanvas: ElementRef;
ngAfterViewInit() {
this.renderCharts();
}
renderCharts() {
// 雷达图
this.renderRadarChart();
// 饼图
this.renderPieChart();
// 折线图
this.renderLineChart();
}
renderRadarChart() {
const ctx = this.radarCanvas.nativeElement.getContext('2d');
new Chart(ctx, {
type: 'radar',
data: {
labels: ['完成率', '优秀率', '满意度', '延期率'],
datasets: this.departmentPerformance.map(dept => ({
label: dept.department,
data: [
dept.completionRate,
dept.excellentWorkRate,
dept.satisfactionRate,
100 - dept.overdueRate
],
backgroundColor: this.getDepartmentColor(dept.department, 0.2),
borderColor: this.getDepartmentColor(dept.department),
borderWidth: 2
}))
},
options: {
scales: {
r: {
beginAtZero: true,
max: 100
}
}
}
});
}
待续第4部分:测试方案和部署指南...