Skip to content

人力资源管理系统 - HR 流程自动化

人力资源管理涉及员工生命周期的各个环节,从招聘到离职都需要大量的流程化工作。今天我们来构建一个智能化的HR管理系统,实现人力资源管理的全流程自动化。

系统架构设计

HR自动化流程概览

mermaid
graph TD
    A[职位发布] --> B[简历筛选]
    B --> C[面试安排]
    C --> D[录用决定]
    D --> E[入职流程]
    E --> F[培训安排]
    F --> G[考勤管理]
    G --> H[绩效评估]
    H --> I[薪资计算]

    J[简历解析] --> B
    K[背景调查] --> D
    L[系统账号] --> E
    M[设备分配] --> E
    N[自动打卡] --> G

数据模型设计

员工数据模型

javascript
const employeeSchema = {
  id: 'string',
  employeeNumber: 'string',
  personalInfo: {
    name: 'string',
    gender: 'string',
    birthDate: 'date',
    idNumber: 'string',
    phone: 'string',
    email: 'string'
  },

  // 工作信息
  workInfo: {
    department: 'string',
    position: 'string',
    level: 'string',
    manager: 'string',
    hireDate: 'date',
    probationEndDate: 'date',
    contractType: 'string',    // permanent, contract, intern
    workLocation: 'string',
    salary: {
      base: 'number',
      allowances: 'number',
      bonus: 'number'
    }
  },

  // 状态信息
  status: 'string',            // active, probation, resigned, terminated

  createdAt: 'date',
  updatedAt: 'date'
};

招聘流程自动化

智能简历筛选

简历解析和筛选系统

javascript
// 招聘管理器
class RecruitmentManager {
  constructor() {
    this.resumeParser = new ResumeParser();
    this.candidateScorer = new CandidateScorer();
    this.interviewScheduler = new InterviewScheduler();
  }

  // 处理新简历
  async processNewResume(resumeFile, jobId) {
    const processingResult = {
      candidateId: this.generateCandidateId(),
      jobId: jobId,
      status: 'processing',
      score: 0,
      recommendation: 'pending'
    };

    try {
      // 解析简历
      const parsedResume = await this.resumeParser.parse(resumeFile);

      // 创建候选人记录
      const candidate = await this.createCandidate(parsedResume, jobId);
      processingResult.candidateId = candidate.id;

      // 评分
      const scoringResult = await this.candidateScorer.score(candidate, jobId);
      processingResult.score = scoringResult.totalScore;
      processingResult.scoreBreakdown = scoringResult.breakdown;

      // 生成推荐
      processingResult.recommendation = this.generateRecommendation(scoringResult);

      // 自动筛选
      if (scoringResult.totalScore >= 80) {
        // 高分候选人自动进入面试流程
        await this.scheduleInterview(candidate.id, jobId);
        processingResult.status = 'interview_scheduled';
      } else if (scoringResult.totalScore >= 60) {
        // 中等分数需要HR审核
        await this.flagForHRReview(candidate.id, jobId);
        processingResult.status = 'hr_review';
      } else {
        // 低分自动拒绝
        await this.rejectCandidate(candidate.id, '不符合基本要求');
        processingResult.status = 'rejected';
      }

    } catch (error) {
      processingResult.status = 'failed';
      processingResult.error = error.message;
    }

    return processingResult;
  }
}

面试安排自动化

智能面试调度系统

javascript
// 面试调度管理器
class InterviewScheduler {
  constructor() {
    this.calendarService = new CalendarService();
    this.notificationService = new NotificationService();
    this.videoConferenceService = new VideoConferenceService();
  }

  // 安排面试
  async scheduleInterview(candidateId, jobId, interviewType = 'technical') {
    const candidate = await this.getCandidate(candidateId);
    const job = await this.getJob(jobId);

    // 确定面试官
    const interviewers = await this.selectInterviewers(job, interviewType);

    // 查找可用时间
    const availableSlots = await this.findAvailableTimeSlots(
      interviewers,
      candidate.preferredTimes
    );

    if (availableSlots.length === 0) {
      throw new Error('无法找到合适的面试时间');
    }

    const selectedSlot = availableSlots[0];

    // 创建面试记录
    const interview = {
      id: this.generateInterviewId(),
      candidateId: candidateId,
      jobId: jobId,
      type: interviewType,
      scheduledTime: selectedSlot.startTime,
      duration: selectedSlot.duration,
      interviewers: interviewers.map(i => i.id),
      location: selectedSlot.isRemote ? 'online' : job.workLocation,
      status: 'scheduled'
    };

    // 创建会议室/视频会议
    if (selectedSlot.isRemote) {
      const meetingInfo = await this.videoConferenceService.createMeeting({
        title: `${candidate.personalInfo.name} - ${job.title} 面试`,
        startTime: selectedSlot.startTime,
        duration: selectedSlot.duration,
        participants: [
          candidate.personalInfo.email,
          ...interviewers.map(i => i.email)
        ]
      });

      interview.meetingUrl = meetingInfo.joinUrl;
      interview.meetingId = meetingInfo.meetingId;
    } else {
      const room = await this.bookMeetingRoom(selectedSlot);
      interview.location = room.name;
      interview.roomId = room.id;
    }

    // 保存面试记录
    await this.saveInterview(interview);

    // 发送通知
    await this.sendInterviewNotifications(interview, candidate, job);

    // 添加到日历
    await this.addToCalendars(interview, candidate, interviewers);

    return interview;
  }

  // 选择面试官
  async selectInterviewers(job, interviewType) {
    const interviewers = [];

    // 根据面试类型选择面试官
    switch (interviewType) {
      case 'hr':
        const hrManager = await this.getHRManager(job.department);
        interviewers.push(hrManager);
        break;

      case 'technical':
        const techLead = await this.getTechnicalLead(job.department);
        const seniorDev = await this.getSeniorDeveloper(job.requiredSkills);
        interviewers.push(techLead, seniorDev);
        break;

      case 'final':
        const deptManager = await this.getDepartmentManager(job.department);
        const hrDirector = await this.getHRDirector();
        interviewers.push(deptManager, hrDirector);
        break;
    }

    return interviewers.filter(i => i !== null);
  }

  // 查找可用时间段
  async findAvailableTimeSlots(interviewers, preferredTimes) {
    const slots = [];
    const duration = 60; // 60分钟面试

    // 获取所有面试官的日历
    const calendars = await Promise.all(
      interviewers.map(interviewer =>
        this.calendarService.getCalendar(interviewer.id, {
          startDate: new Date(),
          endDate: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000) // 未来7天
        })
      )
    );

    // 查找共同空闲时间
    const workingHours = { start: 9, end: 18 }; // 9:00-18:00
    const workingDays = [1, 2, 3, 4, 5]; // 周一到周五

    for (let day = 0; day < 7; day++) {
      const date = new Date();
      date.setDate(date.getDate() + day);

      if (!workingDays.includes(date.getDay())) continue;

      for (let hour = workingHours.start; hour < workingHours.end; hour++) {
        const slotStart = new Date(date);
        slotStart.setHours(hour, 0, 0, 0);

        const slotEnd = new Date(slotStart);
        slotEnd.setMinutes(slotEnd.getMinutes() + duration);

        // 检查所有面试官是否都有空
        const isAvailable = calendars.every(calendar =>
          this.isTimeSlotAvailable(calendar, slotStart, slotEnd)
        );

        if (isAvailable) {
          slots.push({
            startTime: slotStart,
            endTime: slotEnd,
            duration: duration,
            isRemote: this.shouldUseRemoteInterview(date)
          });
        }
      }
    }

    return slots.slice(0, 5); // 返回前5个可用时间段
  }
}

入职流程自动化

新员工入职涉及多个部门和系统,我们需要建立自动化的入职流程。

入职手续自动化

入职流程管理器

javascript
// 入职流程管理器
class OnboardingManager {
  constructor() {
    this.accountManager = new AccountManager();
    this.equipmentManager = new EquipmentManager();
    this.trainingManager = new TrainingManager();
    this.documentManager = new DocumentManager();
  }

  // 启动入职流程
  async startOnboarding(employeeId) {
    const onboardingProcess = {
      id: this.generateOnboardingId(),
      employeeId: employeeId,
      status: 'in_progress',
      startDate: new Date(),
      tasks: [],
      completedTasks: [],
      pendingTasks: []
    };

    try {
      const employee = await this.getEmployee(employeeId);

      // 生成入职任务清单
      const tasks = await this.generateOnboardingTasks(employee);
      onboardingProcess.tasks = tasks;
      onboardingProcess.pendingTasks = [...tasks];

      // 执行自动化任务
      for (const task of tasks) {
        if (task.automated) {
          await this.executeAutomatedTask(task, employee);
          this.markTaskCompleted(onboardingProcess, task.id);
        }
      }

      // 发送入职欢迎邮件
      await this.sendWelcomeEmail(employee);

      // 通知相关人员
      await this.notifyStakeholders(employee, onboardingProcess);

    } catch (error) {
      onboardingProcess.status = 'failed';
      onboardingProcess.error = error.message;
    }

    await this.saveOnboardingProcess(onboardingProcess);
    return onboardingProcess;
  }

  // 生成入职任务清单
  async generateOnboardingTasks(employee) {
    const tasks = [
      // IT相关任务
      {
        id: 'create_accounts',
        title: '创建系统账号',
        description: '为新员工创建邮箱、OA、ERP等系统账号',
        category: 'it',
        automated: true,
        priority: 'high',
        estimatedDuration: 30,
        assignee: 'it_admin'
      },
      {
        id: 'setup_equipment',
        title: '设备配置',
        description: '分配和配置工作设备(电脑、手机等)',
        category: 'it',
        automated: true,
        priority: 'high',
        estimatedDuration: 60,
        assignee: 'it_admin'
      },

      // HR相关任务
      {
        id: 'collect_documents',
        title: '收集入职文件',
        description: '收集身份证、学历证明、银行卡等文件',
        category: 'hr',
        automated: false,
        priority: 'high',
        estimatedDuration: 30,
        assignee: 'hr_specialist'
      },
      {
        id: 'sign_contract',
        title: '签署劳动合同',
        description: '签署正式劳动合同和保密协议',
        category: 'hr',
        automated: false,
        priority: 'high',
        estimatedDuration: 45,
        assignee: 'hr_manager'
      },

      // 培训相关任务
      {
        id: 'orientation_training',
        title: '新员工培训',
        description: '参加公司介绍、制度培训等',
        category: 'training',
        automated: true,
        priority: 'medium',
        estimatedDuration: 240,
        assignee: 'training_coordinator'
      },

      // 部门相关任务
      {
        id: 'team_introduction',
        title: '团队介绍',
        description: '与团队成员见面,了解工作内容',
        category: 'department',
        automated: false,
        priority: 'medium',
        estimatedDuration: 60,
        assignee: employee.workInfo.manager
      }
    ];

    return tasks;
  }

  // 执行自动化任务
  async executeAutomatedTask(task, employee) {
    switch (task.id) {
      case 'create_accounts':
        await this.createSystemAccounts(employee);
        break;

      case 'setup_equipment':
        await this.setupEquipment(employee);
        break;

      case 'orientation_training':
        await this.scheduleOrientationTraining(employee);
        break;
    }
  }

  // 创建系统账号
  async createSystemAccounts(employee) {
    const accounts = [];

    // 创建邮箱账号
    const emailAccount = await this.accountManager.createEmailAccount({
      username: this.generateUsername(employee.personalInfo.name),
      displayName: employee.personalInfo.name,
      department: employee.workInfo.department,
      manager: employee.workInfo.manager
    });
    accounts.push(emailAccount);

    // 创建OA账号
    const oaAccount = await this.accountManager.createOAAccount({
      employeeId: employee.id,
      username: emailAccount.username,
      department: employee.workInfo.department,
      position: employee.workInfo.position
    });
    accounts.push(oaAccount);

    // 创建ERP账号
    if (this.needsERPAccess(employee.workInfo.department)) {
      const erpAccount = await this.accountManager.createERPAccount({
        employeeId: employee.id,
        username: emailAccount.username,
        roles: this.getERPRoles(employee.workInfo.position)
      });
      accounts.push(erpAccount);
    }

    // 发送账号信息
    await this.sendAccountInfo(employee, accounts);

    return accounts;
  }
}

培训管理自动化

智能培训系统

javascript
// 培训管理器
class TrainingManager {
  constructor() {
    this.lmsService = new LMSService(); // 学习管理系统
    this.calendarService = new CalendarService();
    this.progressTracker = new ProgressTracker();
  }

  // 安排新员工培训
  async scheduleOrientationTraining(employee) {
    const trainingPlan = {
      id: this.generateTrainingPlanId(),
      employeeId: employee.id,
      type: 'orientation',
      status: 'scheduled',
      courses: [],
      startDate: new Date(),
      estimatedCompletionDate: null
    };

    // 根据职位确定培训课程
    const courses = await this.getOrientationCourses(employee.workInfo.position);

    for (const course of courses) {
      const enrollment = await this.enrollInCourse(employee.id, course.id);
      trainingPlan.courses.push({
        courseId: course.id,
        courseName: course.name,
        enrollmentId: enrollment.id,
        status: 'enrolled',
        dueDate: this.calculateDueDate(course.duration),
        progress: 0
      });
    }

    // 计算预计完成时间
    const totalDuration = courses.reduce((sum, course) => sum + course.duration, 0);
    trainingPlan.estimatedCompletionDate = new Date(Date.now() + totalDuration * 24 * 60 * 60 * 1000);

    // 安排培训时间
    await this.scheduleTrainingTime(employee, trainingPlan);

    // 发送培训通知
    await this.sendTrainingNotification(employee, trainingPlan);

    await this.saveTrainingPlan(trainingPlan);
    return trainingPlan;
  }

  // 获取入职培训课程
  async getOrientationCourses(position) {
    const baseCourses = [
      {
        id: 'company_intro',
        name: '公司介绍',
        duration: 2, // 小时
        type: 'video',
        mandatory: true
      },
      {
        id: 'company_culture',
        name: '企业文化',
        duration: 1,
        type: 'video',
        mandatory: true
      },
      {
        id: 'hr_policies',
        name: '人事制度',
        duration: 3,
        type: 'document',
        mandatory: true
      },
      {
        id: 'safety_training',
        name: '安全培训',
        duration: 2,
        type: 'interactive',
        mandatory: true
      }
    ];

    // 根据职位添加专业课程
    const professionalCourses = await this.getProfessionalCourses(position);

    return [...baseCourses, ...professionalCourses];
  }

  // 跟踪培训进度
  async trackTrainingProgress(employeeId) {
    const trainingPlans = await this.getEmployeeTrainingPlans(employeeId);
    const progressReport = {
      employeeId: employeeId,
      overallProgress: 0,
      completedCourses: 0,
      totalCourses: 0,
      plans: []
    };

    for (const plan of trainingPlans) {
      const planProgress = {
        planId: plan.id,
        type: plan.type,
        progress: 0,
        courses: []
      };

      for (const course of plan.courses) {
        const courseProgress = await this.lmsService.getCourseProgress(
          employeeId,
          course.courseId
        );

        planProgress.courses.push({
          courseId: course.courseId,
          courseName: course.courseName,
          progress: courseProgress.progress,
          status: courseProgress.status,
          completedAt: courseProgress.completedAt,
          timeSpent: courseProgress.timeSpent
        });

        if (courseProgress.status === 'completed') {
          progressReport.completedCourses++;
        }
        progressReport.totalCourses++;
      }

      planProgress.progress = this.calculatePlanProgress(planProgress.courses);
      progressReport.plans.push(planProgress);
    }

    progressReport.overallProgress = progressReport.totalCourses > 0
      ? (progressReport.completedCourses / progressReport.totalCourses) * 100
      : 0;

    return progressReport;
  }
}

考勤管理

考勤管理是HR日常工作的重要组成部分,我们需要建立智能化的考勤系统。

智能考勤系统

考勤管理器

javascript
// 考勤管理器
class AttendanceManager {
  constructor() {
    this.clockingDevices = new ClockingDeviceManager();
    this.scheduleManager = new ScheduleManager();
    this.leaveManager = new LeaveManager();
    this.overtimeManager = new OvertimeManager();
  }

  // 处理打卡记录
  async processClockingRecord(record) {
    const processResult = {
      recordId: record.id,
      employeeId: record.employeeId,
      status: 'processed',
      attendanceStatus: null,
      anomalies: []
    };

    try {
      const employee = await this.getEmployee(record.employeeId);
      const workSchedule = await this.scheduleManager.getSchedule(
        employee.id,
        record.clockingTime
      );

      // 验证打卡记录
      const validation = await this.validateClockingRecord(record, workSchedule);
      if (!validation.isValid) {
        processResult.anomalies.push(...validation.anomalies);
      }

      // 计算考勤状态
      const attendanceStatus = await this.calculateAttendanceStatus(
        record,
        workSchedule
      );
      processResult.attendanceStatus = attendanceStatus;

      // 检查异常情况
      const anomalies = await this.detectAnomalies(record, workSchedule, attendanceStatus);
      processResult.anomalies.push(...anomalies);

      // 更新考勤记录
      await this.updateAttendanceRecord(record.employeeId, record.clockingTime, {
        status: attendanceStatus.status,
        workingHours: attendanceStatus.workingHours,
        overtimeHours: attendanceStatus.overtimeHours,
        anomalies: processResult.anomalies
      });

      // 发送异常通知
      if (processResult.anomalies.length > 0) {
        await this.sendAnomalyNotification(employee, processResult.anomalies);
      }

    } catch (error) {
      processResult.status = 'failed';
      processResult.error = error.message;
    }

    return processResult;
  }

  // 计算考勤状态
  async calculateAttendanceStatus(record, schedule) {
    const clockingTime = new Date(record.clockingTime);
    const scheduledStart = new Date(schedule.startTime);
    const scheduledEnd = new Date(schedule.endTime);

    const status = {
      status: 'normal',
      workingHours: 0,
      overtimeHours: 0,
      lateMinutes: 0,
      earlyLeaveMinutes: 0
    };

    if (record.type === 'clock_in') {
      // 计算迟到时间
      if (clockingTime > scheduledStart) {
        status.lateMinutes = Math.floor((clockingTime - scheduledStart) / (1000 * 60));
        if (status.lateMinutes > 0) {
          status.status = 'late';
        }
      }
    } else if (record.type === 'clock_out') {
      // 计算早退时间
      if (clockingTime < scheduledEnd) {
        status.earlyLeaveMinutes = Math.floor((scheduledEnd - clockingTime) / (1000 * 60));
        if (status.earlyLeaveMinutes > 0) {
          status.status = 'early_leave';
        }
      }

      // 计算加班时间
      if (clockingTime > scheduledEnd) {
        status.overtimeHours = (clockingTime - scheduledEnd) / (1000 * 60 * 60);
      }

      // 计算工作时间
      const clockInRecord = await this.getClockInRecord(record.employeeId, clockingTime);
      if (clockInRecord) {
        const actualStart = Math.max(new Date(clockInRecord.clockingTime), scheduledStart);
        const actualEnd = Math.min(clockingTime, scheduledEnd);
        status.workingHours = Math.max(0, (actualEnd - actualStart) / (1000 * 60 * 60));
      }
    }

    return status;
  }

  // 检测考勤异常
  async detectAnomalies(record, schedule, attendanceStatus) {
    const anomalies = [];

    // 检查重复打卡
    const duplicateCheck = await this.checkDuplicateClocking(record);
    if (duplicateCheck.isDuplicate) {
      anomalies.push({
        type: 'duplicate_clocking',
        severity: 'medium',
        message: '检测到重复打卡记录',
        details: duplicateCheck.details
      });
    }

    // 检查异常时间
    const timeCheck = this.checkAbnormalTime(record, schedule);
    if (timeCheck.isAbnormal) {
      anomalies.push({
        type: 'abnormal_time',
        severity: 'high',
        message: timeCheck.message,
        details: timeCheck.details
      });
    }

    // 检查地理位置
    if (record.location) {
      const locationCheck = await this.checkLocation(record.location, schedule.workLocation);
      if (!locationCheck.isValid) {
        anomalies.push({
          type: 'location_mismatch',
          severity: 'high',
          message: '打卡地点异常',
          details: locationCheck.details
        });
      }
    }

    return anomalies;
  }
}

// 请假管理器
class LeaveManager {
  constructor() {
    this.leaveTypes = this.getLeaveTypes();
    this.approvalWorkflow = new ApprovalWorkflow();
  }

  // 处理请假申请
  async processLeaveApplication(application) {
    const processResult = {
      applicationId: application.id,
      status: 'processing',
      approvalRequired: false,
      autoApproved: false
    };

    try {
      // 验证请假申请
      const validation = await this.validateLeaveApplication(application);
      if (!validation.isValid) {
        processResult.status = 'rejected';
        processResult.rejectionReason = validation.errors.join(', ');
        return processResult;
      }

      // 检查请假余额
      const balanceCheck = await this.checkLeaveBalance(
        application.employeeId,
        application.leaveType,
        application.days
      );

      if (!balanceCheck.sufficient) {
        processResult.status = 'rejected';
        processResult.rejectionReason = '请假余额不足';
        return processResult;
      }

      // 确定是否需要审批
      const approvalRequired = this.requiresApproval(application);
      processResult.approvalRequired = approvalRequired;

      if (!approvalRequired) {
        // 自动批准
        await this.approveLeave(application);
        processResult.status = 'approved';
        processResult.autoApproved = true;
      } else {
        // 启动审批流程
        const approvalResult = await this.approvalWorkflow.startApproval(application);
        processResult.status = 'pending_approval';
        processResult.approvalWorkflowId = approvalResult.workflowId;
      }

    } catch (error) {
      processResult.status = 'failed';
      processResult.error = error.message;
    }

    return processResult;
  }

  // 获取请假类型
  getLeaveTypes() {
    return {
      annual: {
        name: '年假',
        maxDays: 15,
        requiresApproval: true,
        advanceNotice: 3 // 需要提前3天申请
      },
      sick: {
        name: '病假',
        maxDays: 30,
        requiresApproval: false,
        advanceNotice: 0
      },
      personal: {
        name: '事假',
        maxDays: 10,
        requiresApproval: true,
        advanceNotice: 1
      },
      maternity: {
        name: '产假',
        maxDays: 128,
        requiresApproval: true,
        advanceNotice: 30
      }
    };
  }
}

薪资管理

薪资管理是HR工作的核心环节,需要准确计算和及时发放。

薪资计算自动化

薪资计算引擎

javascript
// 薪资管理器
class PayrollManager {
  constructor() {
    this.attendanceManager = new AttendanceManager();
    this.taxCalculator = new TaxCalculator();
    this.bankingService = new BankingService();
  }

  // 计算月度薪资
  async calculateMonthlyPayroll(employeeId, year, month) {
    const payrollResult = {
      employeeId: employeeId,
      period: { year, month },
      baseSalary: 0,
      allowances: 0,
      overtime: 0,
      deductions: 0,
      tax: 0,
      netPay: 0,
      breakdown: {}
    };

    try {
      const employee = await this.getEmployee(employeeId);
      const attendanceData = await this.attendanceManager.getMonthlyAttendance(
        employeeId, year, month
      );

      // 基本工资
      payrollResult.baseSalary = employee.workInfo.salary.base;

      // 津贴补助
      payrollResult.allowances = this.calculateAllowances(employee, attendanceData);

      // 加班费
      payrollResult.overtime = this.calculateOvertimePay(employee, attendanceData);

      // 扣款项目
      payrollResult.deductions = this.calculateDeductions(employee, attendanceData);

      // 税前工资
      const grossPay = payrollResult.baseSalary + payrollResult.allowances +
                      payrollResult.overtime - payrollResult.deductions;

      // 计算个人所得税
      payrollResult.tax = await this.taxCalculator.calculateIncomeTax(
        grossPay,
        employee.personalInfo
      );

      // 净工资
      payrollResult.netPay = grossPay - payrollResult.tax;

      // 详细分解
      payrollResult.breakdown = {
        workingDays: attendanceData.workingDays,
        actualWorkingDays: attendanceData.actualWorkingDays,
        overtimeHours: attendanceData.overtimeHours,
        leaveDays: attendanceData.leaveDays,
        absentDays: attendanceData.absentDays
      };

      // 保存薪资记录
      await this.savePayrollRecord(payrollResult);

    } catch (error) {
      payrollResult.error = error.message;
    }

    return payrollResult;
  }

  // 计算津贴
  calculateAllowances(employee, attendanceData) {
    let totalAllowances = 0;

    // 基础津贴
    totalAllowances += employee.workInfo.salary.allowances || 0;

    // 全勤奖
    if (attendanceData.absentDays === 0 && attendanceData.lateDays === 0) {
      totalAllowances += 500; // 全勤奖500元
    }

    // 交通补助
    totalAllowances += 300;

    // 餐补
    totalAllowances += attendanceData.actualWorkingDays * 25;

    return totalAllowances;
  }

  // 计算加班费
  calculateOvertimePay(employee, attendanceData) {
    const hourlyRate = employee.workInfo.salary.base / (22 * 8); // 月薪转时薪
    let overtimePay = 0;

    // 平时加班 1.5倍
    overtimePay += attendanceData.weekdayOvertimeHours * hourlyRate * 1.5;

    // 周末加班 2倍
    overtimePay += attendanceData.weekendOvertimeHours * hourlyRate * 2;

    // 节假日加班 3倍
    overtimePay += attendanceData.holidayOvertimeHours * hourlyRate * 3;

    return Math.round(overtimePay * 100) / 100; // 保留两位小数
  }

  // 计算扣款
  calculateDeductions(employee, attendanceData) {
    let totalDeductions = 0;

    // 社保扣款
    const socialInsurance = this.calculateSocialInsurance(employee.workInfo.salary.base);
    totalDeductions += socialInsurance.total;

    // 公积金扣款
    const housingFund = employee.workInfo.salary.base * 0.12; // 12%
    totalDeductions += housingFund;

    // 迟到扣款
    totalDeductions += attendanceData.lateMinutes * 2; // 每分钟扣2元

    // 早退扣款
    totalDeductions += attendanceData.earlyLeaveMinutes * 2;

    // 缺勤扣款
    const dailySalary = employee.workInfo.salary.base / 22;
    totalDeductions += attendanceData.absentDays * dailySalary;

    return Math.round(totalDeductions * 100) / 100;
  }

  // 计算社保
  calculateSocialInsurance(baseSalary) {
    const rates = {
      pension: 0.08,      // 养老保险 8%
      medical: 0.02,      // 医疗保险 2%
      unemployment: 0.005, // 失业保险 0.5%
      workInjury: 0,      // 工伤保险 个人不缴费
      maternity: 0        // 生育保险 个人不缴费
    };

    const insurance = {};
    let total = 0;

    for (const [type, rate] of Object.entries(rates)) {
      insurance[type] = baseSalary * rate;
      total += insurance[type];
    }

    insurance.total = total;
    return insurance;
  }
}

// 个税计算器
class TaxCalculator {
  constructor() {
    this.taxBrackets = [
      { min: 0, max: 3000, rate: 0.03, deduction: 0 },
      { min: 3000, max: 12000, rate: 0.10, deduction: 210 },
      { min: 12000, max: 25000, rate: 0.20, deduction: 1410 },
      { min: 25000, max: 35000, rate: 0.25, deduction: 2660 },
      { min: 35000, max: 55000, rate: 0.30, deduction: 4410 },
      { min: 55000, max: 80000, rate: 0.35, deduction: 7160 },
      { min: 80000, max: Infinity, rate: 0.45, deduction: 15160 }
    ];
  }

  // 计算个人所得税
  async calculateIncomeTax(grossIncome, personalInfo) {
    // 基本减除费用
    const basicDeduction = 5000;

    // 专项扣除(社保公积金)
    const specialDeduction = await this.getSpecialDeduction(personalInfo);

    // 专项附加扣除
    const additionalDeduction = await this.getAdditionalDeduction(personalInfo);

    // 应纳税所得额
    const taxableIncome = Math.max(0,
      grossIncome - basicDeduction - specialDeduction - additionalDeduction
    );

    // 计算税额
    let tax = 0;
    for (const bracket of this.taxBrackets) {
      if (taxableIncome > bracket.min) {
        tax = taxableIncome * bracket.rate - bracket.deduction;
        break;
      }
    }

    return Math.max(0, Math.round(tax * 100) / 100);
  }
}

薪资发放自动化

银行批量转账系统

javascript
// 薪资发放管理器
class PayrollDistributionManager {
  constructor() {
    this.bankingService = new BankingService();
    this.notificationService = new NotificationService();
  }

  // 批量发放薪资
  async distributePayroll(payrollBatch) {
    const distributionResult = {
      batchId: payrollBatch.id,
      totalEmployees: payrollBatch.employees.length,
      successCount: 0,
      failureCount: 0,
      totalAmount: 0,
      results: []
    };

    try {
      // 验证批次
      const validation = await this.validatePayrollBatch(payrollBatch);
      if (!validation.isValid) {
        throw new Error(`批次验证失败: ${validation.errors.join(', ')}`);
      }

      // 生成银行转账文件
      const transferFile = await this.generateBankTransferFile(payrollBatch);

      // 执行批量转账
      const transferResult = await this.bankingService.batchTransfer(transferFile);

      // 处理转账结果
      for (const result of transferResult.results) {
        if (result.success) {
          distributionResult.successCount++;
          distributionResult.totalAmount += result.amount;

          // 发送工资条
          await this.sendPayslip(result.employeeId, result.payrollData);
        } else {
          distributionResult.failureCount++;
        }

        distributionResult.results.push(result);
      }

      // 更新发放状态
      await this.updatePayrollStatus(payrollBatch.id, 'distributed');

      // 发送完成通知
      await this.sendDistributionNotification(distributionResult);

    } catch (error) {
      distributionResult.error = error.message;
      await this.updatePayrollStatus(payrollBatch.id, 'failed');
    }

    return distributionResult;
  }

  // 发送电子工资条
  async sendPayslip(employeeId, payrollData) {
    const employee = await this.getEmployee(employeeId);

    // 生成工资条PDF
    const payslipPDF = await this.generatePayslipPDF(payrollData);

    // 发送邮件
    await this.notificationService.sendEmail({
      to: employee.personalInfo.email,
      subject: `工资条 - ${payrollData.period.year}年${payrollData.period.month}月`,
      html: this.generatePayslipEmailTemplate(payrollData),
      attachments: [{
        filename: `工资条_${employee.employeeNumber}_${payrollData.period.year}${payrollData.period.month}.pdf`,
        content: payslipPDF
      }]
    });
  }
}

小结

通过本文的人力资源管理系统实战,我们学会了:

  1. 招聘流程自动化:智能简历筛选和面试安排系统
  2. 入职流程自动化:系统账号创建和培训安排
  3. 培训管理:个性化培训计划和进度跟踪
  4. 考勤管理:智能打卡识别和异常检测
  5. 请假管理:自动化请假审批和余额管理
  6. 薪资管理:精确的薪资计算和自动发放
  7. 数据集成:与各种HR系统的无缝集成

这个HR管理系统展示了如何将复杂的人力资源流程完全自动化,大大提升了HR工作的效率和准确性。

关键要点:

  • 流程标准化:建立标准化的HR流程和操作规范
  • 数据准确性:确保员工数据的准确性和一致性
  • 合规性控制:遵循劳动法规和公司制度
  • 用户体验:为员工和HR提供友好的操作界面

下一篇文章我们将学习运维监控系统,了解如何自动化IT运维管理。