欢迎光临
我们一直在努力

点狮HRM-360度绩效评估系统设计与实现

一、业务背景与挑战

1.1 绩效管理的痛点

在企业人力资源管理中,绩效管理是最具挑战性的核心业务之一。传统的绩效管理模式存在诸多问题:

传统绩效评估的局限性:

  • 单一视角:仅由上级评估,缺乏全面性
  • 主观偏差:评估者个人偏好影响评估结果
  • 反馈延迟:年度或季度评估,反馈周期过长
  • 缺乏数据:凭印象评估,缺乏客观数据支撑
  • 发展导向弱:重考核轻发展,难以促进员工成长
  • 形式主义:评估流于形式,难以反映真实绩效

相关链接:

  • 🌐 官网:http://www.dianshixinxi.com/
  • 📱 演示站:http://cloud.dianshixinxi.com:90/
  • 🎨 Gitee:https://gitee.com/glorylion/JFinalOA
  • 💻 GitCode:https://gitcode.com/Glory_Lion/pointlion-cloud

在这里插入图片描述

1.2 360度评估的价值

什么是360度绩效评估: 360度绩效评估(360-Degree Feedback)是一种全方位的绩效评估方法,通过被评估者的上级、下级、同事、自评、客户等多维度角色进行评估,全面、客观地反映员工的工作表现和能力素质。

360度评估的价值:

  • 全面性:多视角评估,全方位了解员工表现
  • 客观性:多人评估,减少个人偏见影响
  • 发展性:帮助员工识别优势与改进空间
  • 参与性:促进团队沟通,增强组织凝聚力
  • 数据化:量化评估结果,便于分析和决策
  • 持续性:支持持续评估,及时反馈改进
  • 1.3 技术挑战

    实现360度评估系统面临的技术挑战:

  • 评估模型设计复杂

    • 如何设计科学合理的评估维度?
    • 如何平衡不同评估者的权重?
    • 如何处理评估者之间的评分差异?
  • 数据计算量大

    • 评估者数量多:一个员工可能有10+个评估者
    • 评估指标多:几十个评估指标
    • 计算复杂:权重计算、异常值处理、数据聚合
  • 实时性要求高

    • 评估流程实时推进
    • 评估进度实时跟踪
    • 评估结果实时计算
  • 数据隐私敏感

    • 评估结果涉及个人隐私
    • 需要严格的权限控制
    • 匿名评估的技术实现
  • 业务流程复杂

    • 评估周期管理
    • 评估者选择策略
    • 异常情况处理(评估者离职、请假等)

  • 二、整体架构设计

    2.1 系统架构全景

    ┌─────────────────────────────────────────────────────────────────┐
    │ 360度绩效评估系统 │
    ├─────────────────────────────────────────────────────────────────┤
    │ │
    │ ┌──────────────────────────────────────────────────────────┐ │
    │ │ 评估配置管理层 │ │
    │ │ ┌──────────────┐ ┌──────────────┐ ┌─────────────────┐ │ │
    │ │ │ 评估项目配置 │ │ 评估维度配置 │ │ 评估指标配置 │ │ │
    │ │ │(Project) │ │(Dimension) │ │(Indicator) │ │ │
    │ │ └──────────────┘ └──────────────┘ └─────────────────┘ │ │
    │ │ ┌──────────────┐ ┌──────────────┐ ┌─────────────────┐ │ │
    │ │ │ 评估流程配置 │ │ 权重规则配置 │ │ 评估者选择规则 │ │ │
    │ │ │(Workflow) │ │(Weight Rule) │ │(Selector Rule) │ │ │
    │ │ └──────────────┘ └──────────────┘ └─────────────────┘ │ │
    │ └──────────────────────────────────────────────────────────┘ │
    │ │ │
    │ ▼ │
    │ ┌──────────────────────────────────────────────────────────┐ │
    │ │ 评估执行引擎层 │ │
    │ │ ┌──────────────┐ ┌──────────────┐ ┌─────────────────┐ │ │
    │ │ │ 评估任务调度 │ │ 评估流程引擎 │ │ 进度监控引擎 │ │ │
    │ │ │(Scheduler) │ │(Workflow) │ │(Monitor) │ │ │
    │ │ └──────────────┘ └──────────────┘ └─────────────────┘ │ │
    │ │ ┌──────────────┐ ┌──────────────┐ ┌─────────────────┐ │ │
    │ │ │ 提醒通知引擎 │ │ 异常处理引擎 │ │ 权限控制引擎 │ │ │
    │ │ │(Notifier) │ │(Handler) │ │(Permission) │ │ │
    │ │ └──────────────┘ └──────────────┘ └─────────────────┘ │ │
    │ └──────────────────────────────────────────────────────────┘ │
    │ │ │
    │ ▼ │
    │ ┌──────────────────────────────────────────────────────────┐ │
    │ │ 数据计算分析层 │ │
    │ │ ┌──────────────┐ ┌──────────────┐ ┌─────────────────┐ │ │
    │ │ │ 评估数据聚合 │ │ 权重计算引擎 │ │ 异常值检测引擎 │ │ │
    │ │ │(Aggregator) │ │(Weight Calc) │ │(Outlier Detect) │ │ │
    │ │ └──────────────┘ └──────────────┘ └─────────────────┘ │ │
    │ │ ┌──────────────┐ ┌──────────────┐ ┌─────────────────┐ │ │
    │ │ │ 评分计算引擎 │ │ 结果排名引擎 │ │ 报表生成引擎 │ │ │
    │ │ │(Score Calc) │ │(Ranking) │ │(Report) │ │ │
    │ │ └──────────────┘ └──────────────┘ └─────────────────┘ │ │
    │ └──────────────────────────────────────────────────────────┘ │
    │ │ │
    │ ▼ │
    │ ┌──────────────────────────────────────────────────────────┐ │
    │ │ 结果应用层 │ │
    │ │ ┌──────────────┐ ┌──────────────┐ ┌─────────────────┐ │ │
    │ │ │ 结果反馈查看 │ │ 绩效改进计划 │ │ 人才盘点分析 │ │ │
    │ │ │(Feedback) │ │(Improve Plan)│ │(Talent Review) │ │ │
    │ │ └──────────────┘ └──────────────┘ └─────────────────┘ │ │
    │ │ ┌──────────────┐ ┌──────────────┐ ┌─────────────────┐ │ │
    │ │ │ 数据可视化 │ │ 趋势分析 │ │ 对比分析 │ │ │
    │ │ │(Dashboard) │ │(Trend) │ │(Comparison) │ │ │
    │ │ └──────────────┘ └──────────────┘ └─────────────────┘ │ │
    │ └──────────────────────────────────────────────────────────┘ │
    │ │
    └─────────────────────────────────────────────────────────────────┘

    在这里插入图片描述

    2.2 核心领域模型

    评估项目模型(EvaluationProject):

    /**
    * 360度评估项目
    * 表示一次完整的360度评估活动
    */

    @Data
    @Entity
    @Table(name = "hrm_evaluation_project")
    public class EvaluationProject {
    /**
    * 项目ID
    */

    @Id
    @GeneratedValue(strategy = GenerationType.UUID)
    private String id;

    /**
    * 项目名称
    */

    private String name;

    /**
    * 项目编码
    */

    @Column(unique = true, nullable = false)
    private String code;

    /**
    * 项目描述
    */

    @Lob
    private String description;

    /**
    * 评估周期类型:ANNUAL(年度), QUARTERLY(季度),
    * MONTHLY(月度), ON_DEMAND(按需)
    */

    @Enumerated(EnumType.STRING)
    private PeriodType periodType;

    /**
    * 评估开始时间
    */

    private LocalDateTime startTime;

    /**
    * 评估结束时间
    */

    private LocalDateTime endTime;

    /**
    * 项目状态:DRAFT(草稿), PENDING(待开始),
    * IN_PROGRESS(进行中), COMPLETED(已完成), ARCHIVED(已归档)
    */

    @Enumerated(EnumType.STRING)
    private ProjectStatus status;

    /**
    * 适用范围类型:ALL(全员), DEPARTMENT(部门),
    * POSITION(岗位), EMPLOYEE(指定员工)
    */

    @Enumerated(EnumType.STRING)
    private ScopeType scopeType;

    /**
    * 适用范围配置(JSON格式)
    * 示例:{"departmentIds": ["dept001", "dept002"]}
    */

    @Lob
    private String scopeConfig;

    /**
    * 评估模板ID
    */

    private String templateId;

    /**
    * 是否匿名评估
    */

    private Boolean anonymous;

    /**
    * 是否启用自评
    */

    private Boolean enableSelfEvaluation;

    /**
    * 是否启用上级评估
    */

    private Boolean enableSuperiorEvaluation;

    /**
    * 是否启用下级评估
    */

    private Boolean enableSubordinateEvaluation;

    /**
    * 是否启用同事评估
    */

    private Boolean enablePeerEvaluation;

    /**
    * 是否启用客户评估
    */

    private Boolean enableCustomerEvaluation;

    /**
    * 评估者最小数量
    */

    private Integer minRaterCount;

    /**
    * 评估者最大数量
    */

    private Integer maxRaterCount;

    /**
    * 创建人
    */

    private String creator;

    /**
    * 创建时间
    */

    private LocalDateTime createTime;

    /**
    * 更新时间
    */

    private LocalDateTime updateTime;

    /**
    * 扩展配置(JSON格式)
    */

    @Lob
    private String extConfig;
    }

    /**
    * 周期类型枚举
    */

    public enum PeriodType {
    /** 年度评估 */
    ANNUAL,

    /** 季度评估 */
    QUARTERLY,

    /** 月度评估 */
    MONTHLY,

    /** 按需评估 */
    ON_DEMAND
    }

    /**
    * 项目状态枚举
    */

    public enum ProjectStatus {
    /** 草稿 */
    DRAFT,

    /** 待开始 */
    PENDING,

    /** 进行中 */
    IN_PROGRESS,

    /** 已完成 */
    COMPLETED,

    /** 已归档 */
    ARCHIVED
    }

    /**
    * 范围类型枚举
    */

    public enum ScopeType {
    /** 全员 */
    ALL,

    /** 部门 */
    DEPARTMENT,

    /** 岗位 */
    POSITION,

    /** 指定员工 */
    EMPLOYEE
    }

    评估维度模型(EvaluationDimension):

    /**
    * 评估维度
    * 表示评估的一级分类,如:工作业绩、工作能力、工作态度等
    */

    @Data
    @Entity
    @Table(name = "hrm_evaluation_dimension")
    public class EvaluationDimension {
    /**
    * 维度ID
    */

    @Id
    @GeneratedValue(strategy = GenerationType.UUID)
    private String id;

    /**
    * 维度编码
    */

    @Column(unique = true, nullable = false)
    private String code;

    /**
    * 维度名称
    */

    private String name;

    /**
    * 维度描述
    */

    @Lob
    private String description;

    /**
    * 所属模板ID
    */

    private String templateId;

    /**
    * 父维度ID(支持多级维度)
    */

    private String parentId;

    /**
    * 维度类型:CORE(核心维度), OPTIONAL(可选维度), CUSTOM(自定义维度)
    */

    @Enumerated(EnumType.STRING)
    private DimensionType type;

    /**
    * 维度权重(0-100)
    */

    private BigDecimal weight;

    /**
    * 最小分值
    */

    private Integer minScore;

    /**
    * 最大分值
    */

    private Integer maxScore;

    /**
    * 显示顺序
    */

    private Integer sortOrder;

    /**
    * 是否启用
    */

    private Boolean enabled;

    /**
    * 创建时间
    */

    private LocalDateTime createTime;

    /**
    * 更新时间
    */

    private LocalDateTime updateTime;

    /**
    * 扩展配置(JSON格式)
    */

    @Lob
    private String extConfig;
    }

    /**
    * 维度类型枚举
    */

    public enum DimensionType {
    /** 核心维度 */
    CORE,

    /** 可选维度 */
    OPTIONAL,

    /** 自定义维度 */
    CUSTOM
    }

    评估指标模型(EvaluationIndicator):

    /**
    * 评估指标
    * 表示具体的评估项,如:工作完成质量、团队协作能力等
    */

    @Data
    @Entity
    @Table(name = "hrm_evaluation_indicator")
    public class EvaluationIndicator {
    /**
    * 指标ID
    */

    @Id
    @GeneratedValue(strategy = GenerationType.UUID)
    private String id;

    /**
    * 指标编码
    */

    @Column(unique = true, nullable = false)
    private String code;

    /**
    * 指标名称
    */

    private String name;

    /**
    * 指标描述
    */

    @Lob
    private String description;

    /**
    * 所属维度ID
    */

    private String dimensionId;

    /**
    * 指标类型:QUANTITATIVE(定量), QUALITATIVE(定性)
    */

    @Enumerated(EnumType.STRING)
    private IndicatorType type;

    /**
    * 评分方式:SCORE(打分制), RANKING(等级制),
    * CHOICE(选择制), TEXT(文本制)
    */

    @Enumerated(EnumType.STRING)
    private ScoringType scoringType;

    /**
    * 指标权重(0-100)
    */

    private BigDecimal weight;

    /**
    * 最小分值
    */

    private Integer minScore;

    /**
    * 最大分值
    */

    private Integer maxScore;

    /**
    * 评分等级定义(JSON格式)
    * 示例:[{"level":5,"name":"优秀","description":"表现卓越"}]
    */

    @Lob
    private String scoreLevels;

    /**
    * 是否必填
    */

    private Boolean required;

    /**
    * 显示顺序
    */

    private Integer sortOrder;

    /**
    * 是否启用
    */

    private Boolean enabled;

    /**
    * 创建时间
    */

    private LocalDateTime createTime;

    /**
    * 更新时间
    */

    private LocalDateTime updateTime;

    /**
    * 扩展配置(JSON格式)
    */

    @Lob
    private String extConfig;
    }

    /**
    * 指标类型枚举
    */

    public enum IndicatorType {
    /** 定量指标 */
    QUANTITATIVE,

    /** 定性指标 */
    QUALITATIVE
    }

    /**
    * 评分方式枚举
    */

    public enum ScoringType {
    /** 打分制 */
    SCORE,

    /** 等级制 */
    RANKING,

    /** 选择制 */
    CHOICE,

    /** 文本制 */
    TEXT
    }

    评估记录模型(EvaluationRecord):

    /**
    * 评估记录
    * 存储一次评估的完整数据
    */

    @Data
    @Entity
    @Table(name = "hrm_evaluation_record")
    public class EvaluationRecord {
    /**
    * 记录ID
    */

    @Id
    @GeneratedValue(strategy = GenerationType.UUID)
    private String id;

    /**
    * 评估项目ID
    */

    private String projectId;

    /**
    * 被评估者ID
    */

    private String evaluateeId;

    /**
    * 被评估者姓名
    */

    private String evaluateeName;

    /**
    * 评估者ID
    */

    private String raterId;

    /**
    * 评估者姓名
    */

    private String raterName;

    /**
    * 评估关系类型:SELF(自评), SUPERIOR(上级),
    * SUBORDINATE(下级), PEER(同事), CUSTOMER(客户)
    */

    @Enumerated(EnumType.STRING)
    private RaterType raterType;

    /**
    * 是否匿名
    */

    private Boolean anonymous;

    /**
    * 评估状态:PENDING(待评估), IN_PROGRESS(评估中),
    * COMPLETED(已完成), SKIPPED(已跳过)
    */

    @Enumerated(EnumType.STRING)
    private EvaluationStatus status;

    /**
    * 评估开始时间
    */

    private LocalDateTime startTime;

    /**
    * 评估完成时间
    */

    private LocalDateTime completeTime;

    /**
    * 评估用时(秒)
    */

    private Long duration;

    /**
    * 总分
    */

    private BigDecimal totalScore;

    /**
    * 各维度得分(JSON格式)
    */

    @Lob
    private String dimensionScores;

    /**
    * 评估备注
    */

    @Lob
    private String remark;

    /**
    * 创建时间
    */

    private LocalDateTime createTime;

    /**
    * 更新时间
    */

    private LocalDateTime updateTime;

    /**
    * 扩展配置(JSON格式)
    */

    @Lob
    private String extConfig;

    /**
    * 评估明细列表
    */

    @OneToMany(mappedBy = "evaluationRecord", cascade = CascadeType.ALL)
    private List<EvaluationDetail> details;
    }

    /**
    * 评估关系类型枚举
    */

    public enum RaterType {
    /** 自评 */
    SELF,

    /** 上级 */
    SUPERIOR,

    /** 下级 */
    SUBORDINATE,

    /** 同事 */
    PEER,

    /** 客户 */
    CUSTOMER
    }

    /**
    * 评估状态枚举
    */

    public enum EvaluationStatus {
    /** 待评估 */
    PENDING,

    /** 评估中 */
    IN_PROGRESS,

    /** 已完成 */
    COMPLETED,

    /** 已跳过 */
    SKIPPED
    }

    评估明细模型(EvaluationDetail):

    /**
    * 评估明细
    * 存储对单个指标的评分
    */

    @Data
    @Entity
    @Table(name = "hrm_evaluation_detail")
    public class EvaluationDetail {
    /**
    * 明细ID
    */

    @Id
    @GeneratedValue(strategy = GenerationType.UUID)
    private String id;

    /**
    * 评估记录ID
    */

    private String evaluationRecordId;

    /**
    * 关联的评估记录
    */

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "evaluation_record_id")
    private EvaluationRecord evaluationRecord;

    /**
    * 指标ID
    */

    private String indicatorId;

    /**
    * 维度ID
    */

    private String dimensionId;

    /**
    * 指标名称
    */

    private String indicatorName;

    /**
    * 维度名称
    */

    private String dimensionName;

    /**
    * 评分
    */

    private BigDecimal score;

    /**
    * 评语
    */

    @Lob
    private String comment;

    /**
    * 附件列表(JSON格式)
    */

    @Lob
    private String attachments;

    /**
    * 创建时间
    */

    private LocalDateTime createTime;

    /**
    * 更新时间
    */

    private LocalDateTime updateTime;
    }

    2.3 数据模型关系图

    ┌────────────────────────────────────────────────────────────────┐
    │ 评估数据模型关系 │
    ├────────────────────────────────────────────────────────────────┤
    │ │
    │ EvaluationProject(评估项目) │
    │ │ │
    │ ├──► EvaluationTemplate(评估模板) │
    │ │ │ │
    │ │ ├──► EvaluationDimension(评估维度) │
    │ │ │ │ │
    │ │ │ └──► EvaluationIndicator(评估指标) │
    │ │ │
    │ └──► EvaluationRecord(评估记录) │
    │ │ │
    │ ├──► EvaluationDetail(评估明细) │
    │ │ │ │
    │ │ └──► Indicator, Dimension │
    │ │ │
    │ └──► EvaluationResult(评估结果) │
    │ │ │
    │ ├──► ResultDimension(维度结果) │
    │ └──► ImprovementPlan(改进计划) │
    │ │
    └────────────────────────────────────────────────────────────────┘


    三、核心模块实现

    3.1 评估任务调度引擎

    评估任务调度器:

    /**
    * 评估任务调度引擎
    * 负责创建和分配评估任务
    */

    @Component
    @Slf4j
    public class EvaluationTaskScheduler {

    @Autowired
    private EvaluationProjectRepository projectRepository;

    @Autowired
    private EvaluationRecordRepository recordRepository;

    @Autowired
    private RaterSelectorEngine raterSelectorEngine;

    @Autowired
    private ApplicationEventPublisher eventPublisher;

    /**
    * 启动评估项目
    *
    * @param projectId 项目ID
    * @return 启动结果
    */

    @Transactional(rollbackFor = Exception.class)
    public LaunchResult launchProject(String projectId) {
    log.info("启动评估项目: projectId={}", projectId);

    try {
    // 1. 获取项目信息
    EvaluationProject project = projectRepository.findById(projectId)
    .orElseThrow(() -> new BusinessException("评估项目不存在"));

    // 2. 验证项目状态
    if (project.getStatus() != ProjectStatus.PENDING) {
    throw new BusinessException("项目状态不允许启动");
    }

    // 3. 获取被评估者列表
    List<Employee> evaluatees = getEvaluatees(project);
    log.info("获取被评估者列表: count={}", evaluatees.size());

    // 4. 为每个被评估者创建评估任务
    List<EvaluationRecord> allRecords = new ArrayList<>();
    int successCount = 0;
    int failCount = 0;

    for (Employee evaluatee : evaluatees) {
    try {
    // 选择评估者
    List<RaterSelectionResult> raterSelections =
    raterSelectorEngine.selectRaters(project, evaluatee);

    // 验证评估者数量
    if (raterSelections.size() < project.getMinRaterCount()) {
    log.warn("评估者数量不足: evaluateeId={}, raterCount={}",
    evaluatee.getId(), raterSelections.size());
    failCount++;
    continue;
    }

    // 创建评估记录
    for (RaterSelectionResult selection : raterSelections) {
    EvaluationRecord record = createEvaluationRecord(
    project, evaluatee, selection
    );
    allRecords.add(record);
    }

    successCount++;

    } catch (Exception e) {
    log.error("创建评估任务失败: evaluateeId={}, error={}",
    evaluatee.getId(), e.getMessage());
    failCount++;
    }
    }

    // 5. 批量保存评估记录
    if (!allRecords.isEmpty()) {
    recordRepository.saveAll(allRecords);
    }

    // 6. 更新项目状态
    project.setStatus(ProjectStatus.IN_PROGRESS);
    project.setUpdateTime(LocalDateTime.now());
    projectRepository.save(project);

    // 7. 发布项目启动事件
    eventPublisher.publishEvent(new ProjectLaunchedEvent(
    projectId, evaluatees.size(), allRecords.size()
    ));

    log.info("评估项目启动成功: projectId={}, successCount={}, failCount={}",
    projectId, successCount, failCount);

    return LaunchResult.builder()
    .projectId(projectId)
    .success(successCount)
    .failed(failCount)
    .totalRecords(allRecords.size())
    .build();

    } catch (Exception e) {
    log.error("启动评估项目失败: projectId={}, error={}", projectId, e.getMessage());
    throw new BusinessException("启动评估项目失败", e);
    }
    }

    /**
    * 获取被评估者列表
    */

    private List<Employee> getEvaluatees(EvaluationProject project) {
    ScopeType scopeType = project.getScopeType();
    String scopeConfig = project.getScopeConfig();

    // 解析范围配置
    JSONObject scopeJson = JSON.parseObject(scopeConfig);

    switch (scopeType) {
    case ALL:
    // 获取所有在职员工
    return employeeRepository.findAllActiveEmployees();

    case DEPARTMENT:
    // 获取指定部门的员工
    List<String> departmentIds = scopeJson.getJSONArray("departmentIds")
    .toJavaList(String.class);
    return employeeRepository.findByDepartmentIds(departmentIds);

    case POSITION:
    // 获取指定岗位的员工
    List<String> positionIds = scopeJson.getJSONArray("positionIds")
    .toJavaList(String.class);
    return employeeRepository.findByPositionIds(positionIds);

    case EMPLOYEE:
    // 获取指定员工
    List<String> employeeIds = scopeJson.getJSONArray("employeeIds")
    .toJavaList(String.class);
    return employeeRepository.findByEmployeeIds(employeeIds);

    default:
    throw new BusinessException("不支持的评估范围类型: " + scopeType);
    }
    }

    /**
    * 创建评估记录
    */

    private EvaluationRecord createEvaluationRecord(
    EvaluationProject project,
    Employee evaluatee,
    RaterSelectionResult selection
    ) {
    EvaluationRecord record = new EvaluationRecord();
    record.setProjectId(project.getId());
    record.setEvaluateeId(evaluatee.getId());
    record.setEvaluateeName(evaluatee.getName());
    record.setRaterId(selection.getRater().getId());
    record.setRaterName(selection.getRater().getName());
    record.setRaterType(selection.getRaterType());
    record.setAnonymous(project.getAnonymous() && selection.isAnonymous());
    record.setStatus(EvaluationStatus.PENDING);
    record.setCreateTime(LocalDateTime.now());

    return record;
    }

    /**
    * 发送评估提醒
    *
    * @param recordId 评估记录ID
    */

    public void sendEvaluationReminder(String recordId) {
    EvaluationRecord record = recordRepository.findById(recordId)
    .orElseThrow(() -> new BusinessException("评估记录不存在"));

    // 发送提醒通知
    notificationService.sendEvaluationReminder(record);

    // 记录提醒日志
    reminderLogRepository.save(ReminderLog.builder()
    .recordId(recordId)
    .raterId(record.getRaterId())
    .reminderTime(LocalDateTime.now())
    .build());
    }
    }

    /**
    * 评估者选择结果
    */

    @Data
    @Builder
    public class RaterSelectionResult {
    /**
    * 评估者
    */

    private Employee rater;

    /**
    * 评估关系类型
    */

    private RaterType raterType;

    /**
    * 是否匿名
    */

    private boolean anonymous;

    /**
    * 权重
    */

    private BigDecimal weight;
    }

    评估者选择引擎:

    /**
    * 评估者选择引擎
    * 根据配置规则选择合适的评估者
    */

    @Component
    @Slf4j
    public class RaterSelectorEngine {

    @Autowired
    private EmployeeRepository employeeRepository;

    @Autowired
    private OrganizationService organizationService;

    /**
    * 选择评估者
    *
    * @param project 评估项目
    * @param evaluatee 被评估者
    * @return 评估者选择结果列表
    */

    public List<RaterSelectionResult> selectRaters(
    EvaluationProject project,
    Employee evaluatee
    ) {
    List<RaterSelectionResult> results = new ArrayList<>();

    // 1. 自评
    if (project.getEnableSelfEvaluation()) {
    results.add(RaterSelectionResult.builder()
    .rater(evaluatee)
    .raterType(RaterType.SELF)
    .anonymous(false)
    .weight(BigDecimal.ZERO) // 自评不参与加权计算
    .build());
    }

    // 2. 上级评估
    if (project.getEnableSuperiorEvaluation()) {
    List<Employee> superiors = getSuperiors(evaluatee);
    for (Employee superior : superiors) {
    results.add(RaterSelectionResult.builder()
    .rater(superior)
    .raterType(RaterType.SUPERIOR)
    .anonymous(false) // 上级评估不匿名
    .weight(new BigDecimal("0.4")) // 上级权重40%
    .build());
    }
    }

    // 3. 下级评估
    if (project.getEnableSubordinateEvaluation()) {
    List<Employee> subordinates = getSubordinates(evaluatee);
    int maxCount = Math.min(subordinates.size(), project.getMaxRaterCount() / 3);
    for (int i = 0; i < maxCount; i++) {
    results.add(RaterSelectionResult.builder()
    .rater(subordinates.get(i))
    .raterType(RaterType.SUBORDINATE)
    .anonymous(true) // 下级评估匿名
    .weight(new BigDecimal("0.2")) // 下级权重20%
    .build());
    }
    }

    // 4. 同事评估
    if (project.getEnablePeerEvaluation()) {
    List<Employee> peers = getPeers(evaluatee);
    int maxCount = Math.min(peers.size(), project.getMaxRaterCount() / 3);
    // 随机选择同事
    Collections.shuffle(peers);
    for (int i = 0; i < maxCount; i++) {
    results.add(RaterSelectionResult.builder()
    .rater(peers.get(i))
    .raterType(RaterType.PEER)
    .anonymous(true) // 同事评估匿名
    .weight(new BigDecimal("0.2")) // 同事权重20%
    .build());
    }
    }

    // 5. 客户评估
    if (project.getEnableCustomerEvaluation()) {
    List<Employee> customers = getCustomers(evaluatee);
    for (Employee customer : customers) {
    results.add(RaterSelectionResult.builder()
    .rater(customer)
    .raterType(RaterType.CUSTOMER)
    .anonymous(true) // 客户评估匿名
    .weight(new BigDecimal("0.2")) // 客户权重20%
    .build());
    }
    }

    // 验证评估者数量
    if (results.size() < project.getMinRaterCount()) {
    log.warn("评估者数量不足: evaluateeId={}, count={}, min={}",
    evaluatee.getId(), results.size(), project.getMinRaterCount());
    }

    return results;
    }

    /**
    * 获取上级
    */

    private List<Employee> getSuperiors(Employee employee) {
    // 获取直接上级
    Employee directSuperior = employeeRepository.findById(employee.getSuperiorId())
    .orElse(null);

    if (directSuperior == null) {
    return Collections.emptyList();
    }

    List<Employee> superiors = new ArrayList<>();
    superiors.add(directSuperior);

    // 可选:获取更高级别的上级
    if (directSuperior.getSuperiorId() != null) {
    Employee grandSuperior = employeeRepository.findById(directSuperior.getSuperiorId())
    .orElse(null);
    if (grandSuperior != null) {
    superiors.add(grandSuperior);
    }
    }

    return superiors;
    }

    /**
    * 获取下级
    */

    private List<Employee> getSubordinates(Employee employee) {
    return employeeRepository.findBySuperiorId(employee.getId());
    }

    /**
    * 获取同事
    */

    private List<Employee> getPeers(Employee employee) {
    // 获取同一部门的其他同事
    List<Employee> departmentEmployees = employeeRepository
    .findByDepartmentId(employee.getDepartmentId());

    // 排除自己和上级下级关系
    return departmentEmployees.stream()
    .filter(e -> !e.getId().equals(employee.getId()))
    .filter(e -> !e.getSuperiorId().equals(employee.getId()))
    .filter(e -> !employee.getId().equals(e.getSuperiorId()))
    .collect(Collectors.toList());
    }

    /**
    * 获取客户
    */

    private List<Employee> getCustomers(Employee employee) {
    // 根据业务场景获取客户
    // 这里简化处理,实际可能需要从客户管理系统获取
    return Collections.emptyList();
    }
    }

    3.2 评估数据聚合引擎

    评估数据聚合器:

    /**
    * 评估数据聚合引擎
    * 负责聚合多个评估者的评分,计算最终得分
    */

    @Component
    @Slf4j
    public class EvaluationDataAggregator {

    @Autowired
    private EvaluationRecordRepository recordRepository;

    @Autowired
    private EvaluationDetailRepository detailRepository;

    /**
    * 聚合评估数据
    *
    * @param projectId 项目ID
    * @param evaluateeId 被评估者ID
    * @return 聚合结果
    */

    @Transactional(rollbackFor = Exception.class)
    public EvaluationAggregationResult aggregateEvaluation(
    String projectId,
    String evaluateeId
    ) {
    log.info("开始聚合评估数据: projectId={}, evaluateeId={}", projectId, evaluateeId);

    try {
    // 1. 获取所有已完成的评估记录
    List<EvaluationRecord> records = recordRepository
    .findByProjectIdAndEvaluateeIdAndStatus(
    projectId, evaluateeId, EvaluationStatus.COMPLETED
    );

    if (records.isEmpty()) {
    log.warn("没有已完成的评估记录: projectId={}, evaluateeId={}",
    projectId, evaluateeId);
    return EvaluationAggregationResult.empty();
    }

    // 2. 聚合维度得分
    Map<String, DimensionAggregation> dimensionAggregations =
    aggregateDimensionScores(records);

    // 3. 聚合指标得分
    Map<String, IndicatorAggregation> indicatorAggregations =
    aggregateIndicatorScores(records);

    // 4. 按评估关系类型聚合
    Map<RaterType, RaterTypeAggregation> raterTypeAggregations =
    aggregateByRaterType(records);

    // 5. 计算总分
    BigDecimal totalScore = calculateTotalScore(dimensionAggregations);

    // 6. 聚合评语
    List<String> comments = aggregateComments(records);

    // 7. 构建聚合结果
    EvaluationAggregationResult result = EvaluationAggregationResult.builder()
    .projectId(projectId)
    .evaluateeId(evaluateeId)
    .totalScore(totalScore)
    .dimensionAggregations(new ArrayList<>(dimensionAggregations.values()))
    .indicatorAggregations(new ArrayList<>(indicatorAggregations.values()))
    .raterTypeAggregations(new ArrayList<>(raterTypeAggregations.values()))
    .comments(comments)
    .raterCount(records.size())
    .aggregateTime(LocalDateTime.now())
    .build();

    log.info("评估数据聚合完成: projectId={}, evaluateeId={}, totalScore={}",
    projectId, evaluateeId, totalScore);

    return result;

    } catch (Exception e) {
    log.error("聚合评估数据失败: projectId={}, evaluateeId={}, error={}",
    projectId, evaluateeId, e.getMessage());
    throw new AggregationException("聚合评估数据失败", e);
    }
    }

    /**
    * 聚合维度得分
    */

    private Map<String, DimensionAggregation> aggregateDimensionScores(
    List<EvaluationRecord> records
    ) {
    Map<String, DimensionAggregation> aggregations = new LinkedHashMap<>();

    // 按维度分组聚合
    for (EvaluationRecord record : records) {
    String dimensionScores = record.getDimensionScores();
    if (StringUtils.isBlank(dimensionScores)) {
    continue;
    }

    // 解析维度得分
    JSONObject scoresJson = JSON.parseObject(dimensionScores);

    for (String dimensionId : scoresJson.keySet()) {
    BigDecimal score = scoresJson.getBigDecimal(dimensionId);

    DimensionAggregation aggregation = aggregations.computeIfAbsent(
    dimensionId,
    k -> DimensionAggregation.builder()
    .dimensionId(dimensionId)
    .scores(new ArrayList<>())
    .build()
    );

    aggregation.getScores().add(score);
    }
    }

    // 计算统计值
    for (DimensionAggregation aggregation : aggregations.values()) {
    List<BigDecimal> scores = aggregation.getScores();

    if (!scores.isEmpty()) {
    // 计算平均分(加权平均)
    BigDecimal avgScore = calculateWeightedAverage(scores);
    aggregation.setAverageScore(avgScore);

    // 计算最高分
    BigDecimal maxScore = scores.stream().max(BigDecimal::compareTo)
    .orElse(BigDecimal.ZERO);
    aggregation.setMaxScore(maxScore);

    // 计算最低分
    BigDecimal minScore = scores.stream().min(BigDecimal::compareTo)
    .orElse(BigDecimal.ZERO);
    aggregation.setMinScore(minScore);

    // 计算标准差
    BigDecimal stdDev = calculateStandardDeviation(scores, avgScore);
    aggregation.setStandardDeviation(stdDev);
    }
    }

    return aggregations;
    }

    /**
    * 聚合指标得分
    */

    private Map<String, IndicatorAggregation> aggregateIndicatorScores(
    List<EvaluationRecord> records
    ) {
    Map<String, IndicatorAggregation> aggregations = new LinkedHashMap<>();

    // 获取所有评估明细
    List<String> recordIds = records.stream()
    .map(EvaluationRecord::getId)
    .collect(Collectors.toList());

    List<EvaluationDetail> details = detailRepository.findByRecordIds(recordIds);

    // 按指标分组聚合
    Map<String, List<EvaluationDetail>> groupedDetails = details.stream()
    .collect(Collectors.groupingBy(EvaluationDetail::getIndicatorId));

    for (Map.Entry<String, List<EvaluationDetail>> entry : groupedDetails.entrySet()) {
    String indicatorId = entry.getKey();
    List<EvaluationDetail> indicatorDetails = entry.getValue();

    // 提取评分
    List<BigDecimal> scores = indicatorDetails.stream()
    .map(EvaluationDetail::getScore)
    .filter(Objects::nonNull)
    .collect(Collectors.toList());

    if (scores.isEmpty()) {
    continue;
    }

    IndicatorAggregation aggregation = IndicatorAggregation.builder()
    .indicatorId(indicatorId)
    .indicatorName(indicatorDetails.get(0).getIndicatorName())
    .dimensionId(indicatorDetails.get(0).getDimensionId())
    .dimensionName(indicatorDetails.get(0).getDimensionName())
    .scores(scores)
    .build();

    // 计算统计值
    BigDecimal avgScore = calculateWeightedAverage(scores);
    aggregation.setAverageScore(avgScore);

    BigDecimal maxScore = scores.stream().max(BigDecimal::compareTo)
    .orElse(BigDecimal.ZERO);
    aggregation.setMaxScore(maxScore);

    BigDecimal minScore = scores.stream().min(BigDecimal::compareTo)
    .orElse(BigDecimal.ZERO);
    aggregation.setMinScore(minScore);

    aggregations.put(indicatorId, aggregation);
    }

    return aggregations;
    }

    /**
    * 按评估关系类型聚合
    */

    private Map<RaterType, RaterTypeAggregation> aggregateByRaterType(
    List<EvaluationRecord> records
    ) {
    Map<RaterType, RaterTypeAggregation> aggregations = new LinkedHashMap<>();

    // 按评估关系类型分组
    Map<RaterType, List<EvaluationRecord>> groupedRecords = records.stream()
    .collect(Collectors.groupingBy(EvaluationRecord::getRaterType));

    for (Map.Entry<RaterType, List<EvaluationRecord>> entry : groupedRecords.entrySet()) {
    RaterType raterType = entry.getKey();
    List<EvaluationRecord> typeRecords = entry.getValue();

    // 提取总分
    List<BigDecimal> scores = typeRecords.stream()
    .map(EvaluationRecord::getTotalScore)
    .filter(Objects::nonNull)
    .collect(Collectors.toList());

    if (scores.isEmpty()) {
    continue;
    }

    // 计算平均分
    BigDecimal avgScore = scores.stream()
    .reduce(BigDecimal.ZERO, BigDecimal::add)
    .divide(new BigDecimal(scores.size()), 2, RoundingMode.HALF_UP);

    RaterTypeAggregation aggregation = RaterTypeAggregation.builder()
    .raterType(raterType)
    .raterCount(typeRecords.size())
    .averageScore(avgScore)
    .scores(scores)
    .build();

    aggregations.put(raterType, aggregation);
    }

    return aggregations;
    }

    /**
    * 计算总分
    */

    private BigDecimal calculateTotalScore(
    Map<String, DimensionAggregation> dimensionAggregations
    ) {
    // 获取维度权重配置
    // 这里简化处理,实际应从配置获取
    Map<String, BigDecimal> dimensionWeights = getDimensionWeights();

    BigDecimal totalScore = BigDecimal.ZERO;
    BigDecimal totalWeight = BigDecimal.ZERO;

    for (DimensionAggregation aggregation : dimensionAggregations.values()) {
    BigDecimal weight = dimensionWeights.getOrDefault(
    aggregation.getDimensionId(),
    new BigDecimal("1.0")
    );

    totalScore = totalScore.add(
    aggregation.getAverageScore().multiply(weight)
    );
    totalWeight = totalWeight.add(weight);
    }

    // 归一化
    if (totalWeight.compareTo(BigDecimal.ZERO) > 0) {
    totalScore = totalScore.divide(totalWeight, 2, RoundingMode.HALF_UP);
    }

    return totalScore;
    }

    /**
    * 聚合评语
    */

    private List<String> aggregateComments(List<EvaluationRecord> records) {
    List<String> comments = new ArrayList<>();

    // 获取所有评估明细
    List<String> recordIds = records.stream()
    .map(EvaluationRecord::getId)
    .collect(Collectors.toList());

    List<EvaluationDetail> details = detailRepository.findByRecordIds(recordIds);

    // 提取评语
    for (EvaluationDetail detail : details) {
    if (StringUtils.isNotBlank(detail.getComment())) {
    comments.add(detail.getComment());
    }
    }

    return comments;
    }

    /**
    * 计算加权平均
    */

    private BigDecimal calculateWeightedAverage(List<BigDecimal> values) {
    if (values.isEmpty()) {
    return BigDecimal.ZERO;
    }

    BigDecimal sum = values.stream()
    .reduce(BigDecimal.ZERO, BigDecimal::add);

    return sum.divide(
    new BigDecimal(values.size()),
    2,
    RoundingMode.HALF_UP
    );
    }

    /**
    * 计算标准差
    */

    private BigDecimal calculateStandardDeviation(
    List<BigDecimal> values,
    BigDecimal mean
    ) {
    if (values.isEmpty()) {
    return BigDecimal.ZERO;
    }

    // 计算方差
    BigDecimal variance = values.stream()
    .map(value -> value.subtract(mean).pow(2))
    .reduce(BigDecimal.ZERO, BigDecimal::add)
    .divide(new BigDecimal(values.size()), 2, RoundingMode.HALF_UP);

    // 计算标准差(方差开方)
    return new BigDecimal(Math.sqrt(variance.doubleValue()))
    .setScale(2, RoundingMode.HALF_UP);
    }

    /**
    * 获取维度权重
    */

    private Map<String, BigDecimal> getDimensionWeights() {
    // 从配置或数据库获取
    // 这里返回默认权重
    Map<String, BigDecimal> weights = new HashMap<>();
    weights.put("WORK_PERFORMANCE", new BigDecimal("0.4")); // 工作业绩40%
    weights.put("WORK_ABILITY", new BigDecimal("0.3")); // 工作能力30%
    weights.put("WORK_ATTITUDE", new BigDecimal("0.2")); // 工作态度20%
    weights.put("TEAM_COLLABORATION", new BigDecimal("0.1")); // 团队协作10%
    return weights;
    }
    }

    /**
    * 评估聚合结果
    */

    @Data
    @Builder
    public class EvaluationAggregationResult {
    /**
    * 项目ID
    */

    private String projectId;

    /**
    * 被评估者ID
    */

    private String evaluateeId;

    /**
    * 总分
    */

    private BigDecimal totalScore;

    /**
    * 维度聚合结果列表
    */

    private List<DimensionAggregation> dimensionAggregations;

    /**
    * 指标聚合结果列表
    */

    private List<IndicatorAggregation> indicatorAggregations;

    /**
    * 评估关系类型聚合结果列表
    */

    private List<RaterTypeAggregation> raterTypeAggregations;

    /**
    * 评语列表
    */

    private List<String> comments;

    /**
    * 评估者数量
    */

    private Integer raterCount;

    /**
    * 聚合时间
    */

    private LocalDateTime aggregateTime;

    public static EvaluationAggregationResult empty() {
    return EvaluationAggregationResult.builder()
    .totalScore(BigDecimal.ZERO)
    .dimensionAggregations(Collections.emptyList())
    .indicatorAggregations(Collections.emptyList())
    .raterTypeAggregations(Collections.emptyList())
    .comments(Collections.emptyList())
    .raterCount(0)
    .build();
    }
    }

    /**
    * 维度聚合结果
    */

    @Data
    @Builder
    public class DimensionAggregation {
    /**
    * 维度ID
    */

    private String dimensionId;

    /**
    * 维度名称
    */

    private String dimensionName;

    /**
    * 评分列表
    */

    private List<BigDecimal> scores;

    /**
    * 平均分
    */

    private BigDecimal averageScore;

    /**
    * 最高分
    */

    private BigDecimal maxScore;

    /**
    * 最低分
    */

    private BigDecimal minScore;

    /**
    * 标准差
    */

    private BigDecimal standardDeviation;
    }

    /**
    * 指标聚合结果
    */

    @Data
    @Builder
    public class IndicatorAggregation {
    /**
    * 指标ID
    */

    private String indicatorId;

    /**
    * 指标名称
    */

    private <span class=\"token cla

    赞(0)
    未经允许不得转载:171主机测评 » 点狮HRM-360度绩效评估系统设计与实现
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址