欢迎光临
我们一直在努力

点狮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 String indicatorName;

    /**
    * 维度ID
    */

    private String dimensionId;

    /**
    * 维度名称
    */

    private String dimensionName;

    /**
    * 评分列表
    */

    private List<BigDecimal> scores;

    /**
    * 平均分
    */

    private BigDecimal averageScore;

    /**
    * 最高分
    */

    private BigDecimal maxScore;

    /**
    * 最低分
    */

    private BigDecimal minScore;
    }

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

    @Data
    @Builder
    public class RaterTypeAggregation {
    /**
    * 评估关系类型
    */

    private RaterType raterType;

    /**
    * 评估者数量
    */

    private Integer raterCount;

    /**
    * 平均分
    */

    private BigDecimal averageScore;

    /**
    * 评分列表
    */

    private List<BigDecimal> scores;
    }

    3.3 异常值检测与处理

    异常值检测引擎:

    /**
    * 评估异常值检测引擎
    * 检测和处理异常的评估数据
    */

    @Component
    @Slf4j
    public class EvaluationOutlierDetector {

    /**
    * 检测异常值
    *
    * @param values 数值列表
    * @return 异常值检测结果
    */

    public OutlierDetectionResult detectOutliers(List<BigDecimal> values) {
    if (values == null || values.isEmpty()) {
    return OutlierDetectionResult.empty();
    }

    OutlierDetectionResult result = new OutlierDetectionResult();
    result.setTotalCount(values.size());

    // 1. 使用IQR方法检测异常值
    List<BigDecimal> iqrOutliers = detectByIQR(values);
    result.setIqrOutliers(iqrOutliers);

    // 2. 使用Z-Score方法检测异常值
    List<BigDecimal> zScoreOutliers = detectByZScore(values);
    result.setZScoreOutliers(zScoreOutliers);

    // 3. 合并异常值
    Set<BigDecimal> allOutliers = new HashSet<>();
    allOutliers.addAll(iqrOutliers);
    allOutliers.addAll(zScoreOutliers);
    result.setAllOutliers(new ArrayList<>(allOutliers));

    // 4. 计算异常值比例
    double outlierRatio = (double) allOutliers.size() / values.size();
    result.setOutlierRatio(outlierRatio);

    return result;
    }

    /**
    * 使用IQR(四分位距)方法检测异常值
    *
    * @param values 数值列表
    * @return 异常值列表
    */

    private List<BigDecimal> detectByIQR(List<BigDecimal> values) {
    List<BigDecimal> sortedValues = new ArrayList<>(values);
    Collections.sort(sortedValues);

    // 计算四分位数
    int n = sortedValues.size();
    BigDecimal q1 = sortedValues.get(n / 4);
    BigDecimal q3 = sortedValues.get(3 * n / 4);

    // 计算IQR
    BigDecimal iqr = q3.subtract(q1);

    // 计算上下限
    BigDecimal lowerBound = q1.subtract(iqr.multiply(new BigDecimal("1.5")));
    BigDecimal upperBound = q3.add(iqr.multiply(new BigDecimal("1.5")));

    // 找出异常值
    List<BigDecimal> outliers = sortedValues.stream()
    .filter(value -> value.compareTo(lowerBound) < 0 ||
    value.compareTo(upperBound) > 0)
    .collect(Collectors.toList());

    log.debug("IQR异常值检测: count={}, outliers={}", n, outliers.size());

    return outliers;
    }

    /**
    * 使用Z-Score方法检测异常值
    *
    * @param values 数值列表
    * @return 异常值列表
    */

    private List<BigDecimal> detectByZScore(List<BigDecimal> values) {
    // 计算平均值
    BigDecimal mean = values.stream()
    .reduce(BigDecimal.ZERO, BigDecimal::add)
    .divide(new BigDecimal(values.size()), 2, RoundingMode.HALF_UP);

    // 计算标准差
    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);

    BigDecimal stdDev = new BigDecimal(Math.sqrt(variance.doubleValue()));

    // 计算Z-Score阈值(通常使用3作为阈值)
    BigDecimal threshold = new BigDecimal("3.0");

    // 找出异常值
    List<BigDecimal> outliers = new ArrayList<>();
    for (BigDecimal value : values) {
    BigDecimal zScore = value.subtract(mean)
    .divide(stdDev, 2, RoundingMode.HALF_UP);

    if (zScore.abs().compareTo(threshold) > 0) {
    outliers.add(value);
    }
    }

    log.debug("Z-Score异常值检测: count={}, outliers={}", values.size(), outliers.size());

    return outliers;
    }

    /**
    * 处理异常值
    *
    * @param values 原始数值列表
    * @param strategy 处理策略
    * @return 处理后的数值列表
    */

    public List<BigDecimal> handleOutliers(
    List<BigDecimal> values,
    OutlierHandlingStrategy strategy
    ) {
    OutlierDetectionResult detectionResult = detectOutliers(values);
    List<BigDecimal> outliers = detectionResult.getAllOutliers();

    if (outliers.isEmpty()) {
    return values;
    }

    switch (strategy) {
    case REMOVE:
    // 移除异常值
    return values.stream()
    .filter(value -> !outliers.contains(value))
    .collect(Collectors.toList());

    case REPLACE_WITH_MEAN:
    // 用平均值替换异常值
    BigDecimal mean = values.stream()
    .filter(value -> !outliers.contains(value))
    .reduce(BigDecimal.ZERO, BigDecimal::add)
    .divide(
    new BigDecimal(values.size() outliers.size()),
    2,
    RoundingMode.HALF_UP
    );

    return values.stream()
    .map(value -> outliers.contains(value) ? mean : value)
    .collect(Collectors.toList());

    case REPLACE_WITH_MEDIAN:
    // 用中位数替换异常值
    List<BigDecimal> normalValues = values.stream()
    .filter(value -> !outliers.contains(value))
    .sorted()
    .collect(Collectors.toList());

    BigDecimal median = normalValues.get(normalValues.size() / 2);

    return values.stream()
    .map(value -> outliers.contains(value) ? median : value)
    .collect(Collectors.toList());

    case CAP:
    // 用上下限替换异常值
    List<BigDecimal> sortedValues = new ArrayList<>(values);
    Collections.sort(sortedValues);

    BigDecimal lowerBound = sortedValues.get(1); // 使用次小值作为下限
    BigDecimal upperBound = sortedValues.get(sortedValues.size() 2); // 使用次大值作为上限

    return values.stream()
    .map(value -> {
    if (value.compareTo(lowerBound) < 0) {
    return lowerBound;
    } else if (value.compareTo(upperBound) > 0) {
    return upperBound;
    } else {
    return value;
    }
    })
    .collect(Collectors.toList());

    default:
    return values;
    }
    }
    }

    /**
    * 异常值检测结果
    */

    @Data
    public class OutlierDetectionResult {
    /**
    * 总数量
    */

    private Integer totalCount;

    /**
    * IQR方法检测出的异常值
    */

    private List<BigDecimal> iqrOutliers;

    /**
    * Z-Score方法检测出的异常值
    */

    private List<BigDecimal> zScoreOutliers;

    /**
    * 所有异常值
    */

    private List<BigDecimal> allOutliers;

    /**
    * 异常值比例
    */

    private Double outlierRatio;

    public static OutlierDetectionResult empty() {
    OutlierDetectionResult result = new OutlierDetectionResult();
    result.setTotalCount(0);
    result.setIqrOutliers(Collections.emptyList());
    result.setZScoreOutliers(Collections.emptyList());
    result.setAllOutliers(Collections.emptyList());
    result.setOutlierRatio(0.0);
    return result;
    }
    }

    /**
    * 异常值处理策略枚举
    */

    public enum OutlierHandlingStrategy {
    /** 移除异常值 */
    REMOVE,

    /** 用平均值替换异常值 */
    REPLACE_WITH_MEAN,

    /** 用中位数替换异常值 */
    REPLACE_WITH_MEDIAN,

    /** 用上下限替换异常值 */
    CAP,

    /** 不处理 */
    NONE
    }

    3.4 评估结果排名与分析

    评估结果排名引擎:

    /**
    * 评估结果排名引擎
    * 对评估结果进行排名和对比分析
    */

    @Component
    @Slf4j
    public class EvaluationRankingEngine {

    @Autowired
    private EvaluationResultRepository resultRepository;

    /**
    * 计算排名
    *
    * @param projectId 项目ID
    * @return 排名结果
    */

    public RankingResult calculateRanking(String projectId) {
    log.info("开始计算评估排名: projectId={}", projectId);

    // 1. 获取所有评估结果
    List<EvaluationResult> results = resultRepository.findByProjectId(projectId);

    if (results.isEmpty()) {
    return RankingResult.empty();
    }

    // 2. 按总分排序
    List<EvaluationResult> sortedResults = results.stream()
    .sorted(Comparator.comparing(EvaluationResult::getTotalScore).reversed())
    .collect(Collectors.toList());

    // 3. 计算排名
    List<RankingItem> rankingItems = new ArrayList<>();
    int rank = 1;

    for (int i = 0; i < sortedResults.size(); i++) {
    EvaluationResult result = sortedResults.get(i);

    // 处理并列排名
    if (i > 0) {
    EvaluationResult prevResult = sortedResults.get(i 1);
    if (result.getTotalScore().compareTo(prevResult.getTotalScore()) == 0) {
    // 分数相同,排名相同
    // rank保持不变
    } else {
    // 分数不同,排名更新
    rank = i + 1;
    }
    }

    RankingItem item = RankingItem.builder()
    .rank(rank)
    .evaluateeId(result.getEvaluateeId())
    .evaluateeName(result.getEvaluateeName())
    .departmentId(result.getDepartmentId())
    .departmentName(result.getDepartmentName())
    .positionId(result.getPositionId())
    .positionName(result.getPositionName())
    .totalScore(result.getTotalScore())
    .dimensionScores(result.getDimensionScores())
    .build();

    rankingItems.add(item);
    }

    // 4. 计算百分位排名
    for (RankingItem item : rankingItems) {
    int percentile = calculatePercentile(rank, sortedResults.size());
    item.setPercentile(percentile);
    }

    // 5. 构建排名结果
    RankingResult rankingResult = RankingResult.builder()
    .projectId(projectId)
    .rankingItems(rankingItems)
    .totalCount(sortedResults.size())
    .averageScore(calculateAverageScore(sortedResults))
    .medianScore(calculateMedianScore(sortedResults))
    .maxScore(sortedResults.get(0).getTotalScore())
    .minScore(sortedResults.get(sortedResults.size() 1).getTotalScore())
    .build();

    log.info("评估排名计算完成: projectId={}, count={}", projectId, sortedResults.size());

    return rankingResult;
    }

    /**
    * 计算百分位
    */

    private int calculatePercentile(int rank, int totalCount) {
    if (totalCount == 0) {
    return 0;
    }

    // 百分位 = (1 – rank/totalCount) * 100
    double percentile = (1.0 (double) rank / totalCount) * 100;
    return (int) Math.round(percentile);
    }

    /**
    * 计算平均分
    */

    private BigDecimal calculateAverageScore(List<EvaluationResult> results) {
    BigDecimal sum = results.stream()
    .map(EvaluationResult::getTotalScore)
    .reduce(BigDecimal.ZERO, BigDecimal::add);

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

    /**
    * 计算中位数
    */

    private BigDecimal calculateMedianScore(List<EvaluationResult> results) {
    int size = results.size();
    if (size == 0) {
    return BigDecimal.ZERO;
    }

    if (size % 2 == 0) {
    // 偶数个,取中间两个数的平均值
    BigDecimal score1 = results.get(size / 2 1).getTotalScore();
    BigDecimal score2 = results.get(size / 2).getTotalScore();
    return score1.add(score2)
    .divide(new BigDecimal("2"), 2, RoundingMode.HALF_UP);
    } else {
    // 奇数个,取中间数
    return results.get(size / 2).getTotalScore();
    }
    }

    /**
    * 部门排名对比
    *
    * @param projectId 项目ID
    * @return 部门排名对比结果
    */

    public DepartmentRankingComparison compareDepartmentRanking(String projectId) {
    log.info("开始部门排名对比: projectId={}", projectId);

    // 1. 获取所有评估结果
    List<EvaluationResult> results = resultRepository.findByProjectId(projectId);

    // 2. 按部门分组
    Map<String, List<EvaluationResult>> departmentGroups = results.stream()
    .collect(Collectors.groupingBy(EvaluationResult::getDepartmentId));

    // 3. 计算各部门的平均分
    List<DepartmentRankingItem> departmentRankings = new ArrayList<>();

    for (Map.Entry<String, List<EvaluationResult>> entry : departmentGroups.entrySet()) {
    String departmentId = entry.getKey();
    List<EvaluationResult> departmentResults = entry.getValue();

    BigDecimal avgScore = calculateAverageScore(departmentResults);
    BigDecimal maxScore = departmentResults.stream()
    .map(EvaluationResult::getTotalScore)
    .max(BigDecimal::compareTo)
    .orElse(BigDecimal.ZERO);
    BigDecimal minScore = departmentResults.stream()
    .map(EvaluationResult::getTotalScore)
    .min(BigDecimal::compareTo)
    .orElse(BigDecimal.ZERO);

    DepartmentRankingItem item = DepartmentRankingItem.builder()
    .departmentId(departmentId)
    .departmentName(departmentResults.get(0).getDepartmentName())
    .averageScore(avgScore)
    .maxScore(maxScore)
    .minScore(minScore)
    .participantCount(departmentResults.size())
    .build();

    departmentRankings.add(item);
    }

    // 4. 按平均分排序
    departmentRankings.sort(
    Comparator.comparing(DepartmentRankingItem::getAverageScore).reversed()
    );

    // 5. 构建对比结果
    return DepartmentRankingComparison.builder()
    .projectId(projectId)
    .departmentRankings(departmentRankings)
    .build();
    }
    }

    /**
    * 排名结果
    */

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

    private String projectId;

    /**
    * 排名列表
    */

    private List<RankingItem> rankingItems;

    /**
    * 总人数
    */

    private Integer totalCount;

    /**
    * 平均分
    */

    private BigDecimal averageScore;

    /**
    * 中位数
    */

    private BigDecimal medianScore;

    /**
    * 最高分
    */

    private BigDecimal maxScore;

    /**
    * 最低分
    */

    private BigDecimal minScore;

    public static RankingResult empty() {
    return RankingResult.builder()
    .rankingItems(Collections.emptyList())
    .totalCount(0)
    .averageScore(BigDecimal.ZERO)
    .medianScore(BigDecimal.ZERO)
    .maxScore(BigDecimal.ZERO)
    .minScore(BigDecimal.ZERO)
    .build();
    }
    }

    /**
    * 排名项
    */

    @Data
    @Builder
    public class RankingItem {
    /**
    * 排名
    */

    private Integer rank;

    /**
    * 百分位
    */

    private Integer percentile;

    /**
    * 被评估者ID
    */

    private String evaluateeId;

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

    private String evaluateeName;

    /**
    * 部门ID
    */

    private String departmentId;

    /**
    * 部门名称
    */

    private String departmentName;

    /**
    * 岗位ID
    */

    private String positionId;

    /**
    * 岗位名称
    */

    private String positionName;

    /**
    * 总分
    */

    private BigDecimal totalScore;

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

    private String dimensionScores;
    }

    /**
    * 部门排名对比结果
    */

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

    private String projectId;

    /**
    * 部门排名列表
    */

    private List<DepartmentRankingItem> departmentRankings;
    }

    /**
    * 部门排名项
    */

    @Data
    @Builder
    public class DepartmentRankingItem {
    /**
    * 部门ID
    */

    private String departmentId;

    /**
    * 部门名称
    */

    private String departmentName;

    /**
    * 平均分
    */

    private BigDecimal averageScore;

    /**
    * 最高分
    */

    private BigDecimal maxScore;

    /**
    * 最低分
    */

    private BigDecimal minScore;

    /**
    * 参与人数
    */

    private Integer participantCount;
    }

    3.5 绩效改进计划生成

    改进计划生成引擎:

    /**
    * 绩效改进计划生成引擎
    * 根据评估结果自动生成改进建议
    */

    @Component
    @Slf4j
    public class ImprovementPlanGenerator {

    @Autowired
    private EvaluationResultRepository resultRepository;

    @Autowired
    private ImprovementAdviceRepository adviceRepository;

    /**
    * 生成改进计划
    *
    * @param projectId 项目ID
    * @param evaluateeId 被评估者ID
    * @return 改进计划
    */

    @Transactional(rollbackFor = Exception.class)
    public ImprovementPlan generateImprovementPlan(
    String projectId,
    String evaluateeId
    ) {
    log.info("生成改进计划: projectId={}, evaluateeId={}", projectId, evaluateeId);

    // 1. 获取评估结果
    EvaluationResult result = resultRepository.findByProjectIdAndEvaluateeId(
    projectId, evaluateeId
    ).orElseThrow(() -> new BusinessException("评估结果不存在"));

    // 2. 分析优势和不足
    List<String> strengths = analyzeStrengths(result);
    List<String> weaknesses = analyzeWeaknesses(result);

    // 3. 生成改进建议
    List<ImprovementAdvice> advices = generateAdvices(result, weaknesses);

    // 4. 构建改进计划
    ImprovementPlan plan = ImprovementPlan.builder()
    .projectId(projectId)
    .evaluateeId(evaluateeId)
    .evaluateeName(result.getEvaluateeName())
    .totalScore(result.getTotalScore())
    .strengths(strengths)
    .weaknesses(weaknesses)
    .advices(advices)
    .planStatus(PlanStatus.DRAFT)
    .createTime(LocalDateTime.now())
    .build();

    // 5. 保存改进计划
    improvementPlanRepository.save(plan);

    log.info("改进计划生成完成: projectId={}, evaluateeId={}, adviceCount={}",
    projectId, evaluateeId, advices.size());

    return plan;
    }

    /**
    * 分析优势
    */

    private List<String> analyzeStrengths(EvaluationResult result) {
    List<String> strengths = new ArrayList<>();

    // 解析维度得分
    List<DimensionScore> dimensionScores = parseDimensionScores(
    result.getDimensionScores()
    );

    // 找出得分较高的维度(高于平均分)
    BigDecimal totalScore = result.getTotalScore();

    for (DimensionScore dimensionScore : dimensionScores) {
    if (dimensionScore.getScore().compareTo(totalScore) > 0) {
    // 根据维度ID生成优势描述
    String strength = generateStrengthDescription(dimensionScore);
    strengths.add(strength);
    }
    }

    return strengths;
    }

    /**
    * 分析不足
    */

    private List<String> analyzeWeaknesses(EvaluationResult result) {
    List<String> weaknesses = new ArrayList<>();

    // 解析维度得分
    List<DimensionScore> dimensionScores = parseDimensionScores(
    result.getDimensionScores()
    );

    // 找出得分较低的维度(低于平均分)
    BigDecimal totalScore = result.getTotalScore();

    for (DimensionScore dimensionScore : dimensionScores) {
    if (dimensionScore.getScore().compareTo(totalScore) < 0) {
    // 根据维度ID生成不足描述
    String weakness = generateWeaknessDescription(dimensionScore);
    weaknesses.add(weakness);
    }
    }

    return weaknesses;
    }

    /**
    * 生成改进建议
    */

    private List<ImprovementAdvice> generateAdvices(
    EvaluationResult result,
    List<String> weaknesses
    ) {
    List<ImprovementAdvice> advices = new ArrayList<>();

    // 为每个不足生成改进建议
    for (String weakness : weaknesses) {
    // 根据不足类型获取改进建议模板
    List<AdviceTemplate> templates = adviceRepository
    .findByWeaknessType(weakness);

    if (templates.isEmpty()) {
    // 使用通用建议
    templates = adviceRepository.findGenericAdvices();
    }

    // 选择合适的建议模板
    for (AdviceTemplate template : templates) {
    ImprovementAdvice advice = ImprovementAdvice.builder()
    .adviceType(template.getAdviceType())
    .title(template.getTitle())
    .description(template.getDescription())
    .actionSteps(parseActionSteps(template.getActionSteps()))
    .expectedOutcome(template.getExpectedOutcome())
    .priority(calculateAdvicePriority(result, weakness))
    .estimatedDuration(template.getEstimatedDuration())
    .resources(template.getResources())
    .build();

    advices.add(advice);
    }
    }

    return advices;
    }

    /**
    * 解析维度得分
    */

    private List<DimensionScore> parseDimensionScores(String dimensionScoresJson) {
    if (StringUtils.isBlank(dimensionScoresJson)) {
    return Collections.emptyList();
    }

    JSONObject jsonObject = JSON.parseObject(dimensionScoresJson);
    List<DimensionScore> dimensionScores = new ArrayList<>();

    for (String key : jsonObject.keySet()) {
    JSONObject dimensionObj = jsonObject.getJSONObject(key);
    DimensionScore dimensionScore = DimensionScore.builder()
    .dimensionId(key)
    .dimensionName(dimensionObj.getString("name"))
    .score(dimensionObj.getBigDecimal("score"))
    .build();
    dimensionScores.add(dimensionScore);
    }

    return dimensionScores;
    }

    /**
    * 生成优势描述
    */

    private String generateStrengthDescription(DimensionScore dimensionScore) {
    String dimensionId = dimensionScore.getDimensionId();
    BigDecimal score = dimensionScore.getScore();

    switch (dimensionId) {
    case "WORK_PERFORMANCE":
    return String.format("工作业绩表现优秀,得分为%.2f分,展现出较强的业务能力", score);
    case "WORK_ABILITY":
    return String.format("工作能力突出,得分为%.2f分,具备良好的专业素养", score);
    case "WORK_ATTITUDE":
    return String.format("工作态度积极,得分为%.2f分,表现出高度的责任心", score);
    case "TEAM_COLLABORATION":
    return String.format("团队协作能力强,得分为%.2f分,善于与同事合作", score);
    default:
    return String.format("%s表现优秀,得分为%.2f分",
    dimensionScore.getDimensionName(), score);
    }
    }

    /**
    * 生成不足描述
    */

    private String generateWeaknessDescription(DimensionScore dimensionScore) {
    String dimensionId = dimensionScore.getDimensionId();
    BigDecimal score = dimensionScore.getScore();

    switch (dimensionId) {
    case "WORK_PERFORMANCE":
    return String.format("工作业绩有待提升,当前得分为%.2f分,建议加强业务能力", score);
    case "WORK_ABILITY":
    return String.format("工作能力需要改进,当前得分为%.2f分,建议参加相关培训", score);
    case "WORK_ATTITUDE":
    return String.format("工作态度需要调整,当前得分为%.2f分,建议增强责任心", score);
    case "TEAM_COLLABORATION":
    return String.format("团队协作需要加强,当前得分为%.2f分,建议多与同事沟通", score);
    default:
    return String.format("%s需要改进,当前得分为%.2f分",
    dimensionScore.getDimensionName(), score);
    }
    }

    /**
    * 解析行动步骤
    */

    private List<String> parseActionSteps(String actionStepsJson) {
    if (StringUtils.isBlank(actionStepsJson)) {
    return Collections.emptyList();
    }

    return JSON.parseArray(actionStepsJson, String.class);
    }

    /**
    * 计算建议优先级
    */

    private Priority calculateAdvicePriority(EvaluationResult result, String weakness) {
    // 根据得分差异决定优先级
    BigDecimal scoreGap = result.getTotalScore().subtract(new BigDecimal("60"));

    if (scoreGap.compareTo(new BigDecimal("20")) < 0) {
    return Priority.HIGH;
    } else if (scoreGap.compareTo(new BigDecimal("10")) < 0) {
    return Priority.MEDIUM;
    } else {
    return Priority.LOW;
    }
    }
    }

    /**
    * 改进计划
    */

    @Data
    @Builder
    @Entity
    @Table(name = "hrm_improvement_plan")
    public class ImprovementPlan {
    @Id
    @GeneratedValue(strategy = GenerationType.UUID)
    private String id;

    /**
    * 项目ID
    */

    private String projectId;

    /**
    * 被评估者ID
    */

    private String evaluateeId;

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

    private String evaluateeName;

    /**
    * 总分
    */

    private BigDecimal totalScore;

    /**
    * 优势列表
    */

    @Lob
    private String strengths;

    /**
    * 不足列表
    */

    @Lob
    private String weaknesses;

    /**
    * 改进建议列表
    */

    @OneToMany(mappedBy = "improvementPlan", cascade = CascadeType.ALL)
    private List<ImprovementAdvice> advices;

    /**
    * 计划状态
    */

    @Enumerated(EnumType.STRING)
    private PlanStatus planStatus;

    /**
    * 创建时间
    */

    private LocalDateTime createTime;

    /**
    * 更新时间
    */

    private LocalDateTime updateTime;
    }

    /**
    * 计划状态枚举
    */

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

    /** 进行中 */
    IN_PROGRESS,

    /** 已完成 */
    COMPLETED,

    /** 已归档 */
    ARCHIVED
    }

    /**
    * 改进建议
    */

    @Data
    @Builder
    @Entity
    @Table(name = "hrm_improvement_advice")
    public class ImprovementAdvice {
    @Id
    @GeneratedValue(strategy = GenerationType.UUID)
    private String id;

    /**
    * 改进计划ID
    */

    private String improvementPlanId;

    /**
    * 关联的改进计划
    */

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "improvement_plan_id")
    private ImprovementPlan improvementPlan;

    /**
    * 建议类型:TRAINING(培训), COACHING(辅导), PROJECT(项目),
    * READING(阅读), PRACTICE(练习)
    */

    @Enumerated(EnumType.STRING)
    private AdviceType adviceType;

    /**
    * 标题
    */

    private String title;

    /**
    * 描述
    */

    @Lob
    private String description;

    /**
    * 行动步骤(JSON格式)
    */

    @Lob
    private String actionSteps;

    /**
    * 预期成果
    */

    private String expectedOutcome;

    /**
    * 优先级
    */

    @Enumerated(EnumType.STRING)
    private Priority priority;

    /**
    * 预计时长(天)
    */

    private Integer estimatedDuration;

    /**
    * 资源(JSON格式)
    */

    @Lob
    private String resources;

    /**
    * 完成状态
    */

    @Enumerated(EnumType.STRING)
    private CompletionStatus completionStatus;

    /**
    * 创建时间
    */

    private LocalDateTime createTime;

    /**
    * 更新时间
    */

    private LocalDateTime updateTime;
    }

    /**
    * 建议类型枚举
    */

    public enum AdviceType {
    /** 培训 */
    TRAINING,

    /** 辅导 */
    COACHING,

    /** 项目 */
    PROJECT,

    /** 阅读 */
    READING,

    /** 练习 */
    PRACTICE
    }

    /**
    * 优先级枚举
    */

    public enum Priority {
    /** 高 */
    HIGH,

    /** 中 */
    MEDIUM,

    /** 低 */
    LOW
    }

    /**
    * 完成状态枚举
    */

    public enum CompletionStatus {
    /** 待开始 */
    PENDING,

    /** 进行中 */
    IN_PROGRESS,

    /** 已完成 */
    COMPLETED,

    /** 已跳过 */
    SKIPPED
    }

    /**
    * 维度得分
    */

    @Data
    @Builder
    public class DimensionScore {
    private String dimensionId;
    private String dimensionName;
    private BigDecimal score;
    }


    四、高级特性实现

    4.1 匿名评估实现

    匿名评估处理:

    /**
    * 匿名评估处理器
    * 确保评估者的匿名性
    */

    @Component
    @Slf4j
    public class AnonymousEvaluationHandler {

    @Autowired
    private EvaluationRecordRepository recordRepository;

    /**
    * 脱敏处理评估记录
    *
    * @param record 评估记录
    * @return 脱敏后的评估记录
    */

    public EvaluationRecord maskEvaluationRecord(EvaluationRecord record) {
    // 如果不是匿名评估,直接返回
    if (!record.getAnonymous()) {
    return record;
    }

    // 创建脱敏副本
    EvaluationRecord maskedRecord = new EvaluationRecord();
    BeanUtils.copyProperties(record, maskedRecord);

    // 脱敏评估者信息
    maskedRecord.setRaterId(generateAnonymousId(record.getRaterId()));
    maskedRecord.setRaterName("匿名评估者");

    return maskedRecord;
    }

    /**
    * 批量脱敏处理评估记录
    *
    * @param records 评估记录列表
    * @return 脱敏后的评估记录列表
    */

    public List<EvaluationRecord> maskEvaluationRecords(List<EvaluationRecord> records) {
    return records.stream()
    .map(this::maskEvaluationRecord)
    .collect(Collectors.toList());
    }

    /**
    * 生成匿名ID
    *
    * @param originalId 原始ID
    * @return 匿名ID
    */

    private String generateAnonymousId(String originalId) {
    // 使用哈希算法生成匿名ID
    return DigestUtils.md5Hex(originalId + "_anonymous");
    }

    /**
    * 验证匿名权限
    *
    * @param userId 用户ID
    * @param recordId 评估记录ID
    * @return 是否有权限查看
    */

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

    // 如果不是匿名评估,所有人都可以查看
    if (!record.getAnonymous()) {
    return true;
    }

    // 匿名评估只有以下人员可以查看真实身份:
    // 1. 被评估者本人
    // 2. 系统管理员
    // 3. HR管理员

    return userId.equals(record.getEvaluateeId()) ||
    hasAdminRole(userId) ||
    hasHrAdminRole(userId);
    }

    /**
    * 判断是否为管理员
    */

    private boolean hasAdminRole(String userId) {
    User user = userService.getById(userId);
    return user != null && user.getRoles().contains("ADMIN");
    }

    /**
    * 判断是否为HR管理员
    */

    private boolean hasHrAdminRole(String userId) {
    User user = userService.getById(userId);
    return user != null && user.getRoles().contains("HR_ADMIN");
    }
    }

    4.2 评估进度监控

    评估进度监控器:

    /**
    * 评估进度监控器
    * 实时监控评估进度和异常情况
    */

    @Component
    @Slf4j
    public class EvaluationProgressMonitor {

    @Autowired
    private EvaluationRecordRepository recordRepository;

    @Autowired
    private NotificationService notificationService;

    /**
    * 获取项目评估进度
    *
    * @param projectId 项目ID
    * @return 评估进度
    */

    public ProjectProgress getProjectProgress(String projectId) {
    // 获取所有评估记录
    List<EvaluationRecord> allRecords = recordRepository.findByProjectId(projectId);

    if (allRecords.isEmpty()) {
    return ProjectProgress.empty();
    }

    // 统计各状态的评估记录数量
    Map<EvaluationStatus, Long> statusCounts = allRecords.stream()
    .collect(Collectors.groupingBy(
    EvaluationRecord::getStatus,
    Collectors.counting()
    ));

    // 获取被评估者数量
    long evaluateeCount = allRecords.stream()
    .map(EvaluationRecord::getEvaluateeId)
    .distinct()
    .count();

    // 计算完成率
    long completedCount = statusCounts.getOrDefault(EvaluationStatus.COMPLETED, 0L);
    double completionRate = (double) completedCount / allRecords.size();

    // 构建进度信息
    return ProjectProgress.builder()
    .projectId(projectId)
    .totalRecords(allRecords.size())
    .evaluateeCount((int) evaluateeCount)
    .pendingCount(statusCounts.getOrDefault(EvaluationStatus.PENDING, 0L).intValue())
    .inProgressCount(statusCounts.getOrDefault(EvaluationStatus.IN_PROGRESS, 0L).intValue())
    .completedCount(completedCount)
    .skippedCount(statusCounts.getOrDefault(EvaluationStatus.SKIPPED, 0L).intValue())
    .completionRate(completionRate)
    .build();
    }

    /**
    * 获取被评估者的评估进度
    *
    * @param projectId 项目ID
    * @param evaluateeId 被评估者ID
    * @return 评估进度
    */

    public EvaluateeProgress getEvaluateeProgress(String projectId, String evaluateeId) {
    // 获取该被评估者的所有评估记录
    List<EvaluationRecord> records = recordRepository
    .findByProjectIdAndEvaluateeId(projectId, evaluateeId);

    if (records.isEmpty()) {
    return EvaluateeProgress.empty();
    }

    // 统计各状态的评估记录数量
    Map<EvaluationStatus, Long> statusCounts = records.stream()
    .collect(Collectors.groupingBy(
    EvaluationRecord::getStatus,
    Collectors.counting()
    ));

    // 计算完成率
    long completedCount = statusCounts.getOrDefault(EvaluationStatus.COMPLETED, 0L);
    double completionRate = (double) completedCount / records.size();

    // 构建进度信息
    return EvaluateeProgress.builder()
    .projectId(projectId)
    .evaluateeId(evaluateeId)
    .totalRaters(records.size())
    .completedRaters(completedCount)
    .completionRate(completionRate)
    .statusCounts(statusCounts)
    .build();
    }

    /**
    * 监控异常情况
    *
    * @param projectId 项目ID
    * @return 异常情况列表
    */

    public List<ProgressAlert> checkProgressAlerts(String projectId) {
    List<ProgressAlert> alerts = new ArrayList<>();

    // 获取项目进度
    ProjectProgress progress = getProjectProgress(projectId);

    // 1. 检查是否有评估即将过期
    List<EvaluationRecord> expiringRecords = findExpiringRecords(projectId);
    if (!expiringRecords.isEmpty()) {
    alerts.add(ProgressAlert.builder()
    .alertType(AlertType.EXPIRING_SOON)
    .severity(AlertSeverity.MEDIUM)
    .message(String.format("有%d条评估即将过期", expiringRecords.size()))
    .count(expiringRecords.size())
    .build());
    }

    // 2. 检查完成率是否过低
    if (progress.getCompletionRate() < 0.5) {
    alerts.add(ProgressAlert.builder()
    .alertType(AlertType.LOW_COMPLETION_RATE)
    .severity(AlertSeverity.HIGH)
    .message(String.format("评估完成率仅为%.2f%%,低于50%%",
    progress.getCompletionRate() * 100))
    .build());
    }

    // 3. 检查是否有被评估者缺少足够的评估者
    List<String> insufficientRaters = findEvaluateesWithInsufficientRaters(projectId);
    if (!insufficientRaters.isEmpty()) {
    alerts.add(ProgressAlert.builder()
    .alertType(AlertType.INSUFFICIENT_RATERS)
    .severity(AlertSeverity.HIGH)
    .message(String.format("有%d名被评估者缺少足够的评估者",
    insufficientRaters.size()))
    .count(insufficientRaters.size())
    .build());
    }

    // 4. 检查是否有异常评分
    List<String> outlierEvaluatees = findEvaluateesWithOutlierScores(projectId);
    if (!outlierEvaluatees.isEmpty()) {
    alerts.add(ProgressAlert.builder()
    .alertType(AlertType.OUTLIER_SCORES)
    .severity(AlertSeverity.LOW)
    .message(String.format("有%d名被评估者的评分存在异常",
    outlierEvaluatees.size()))
    .count(outlierEvaluatees.size())
    .build());
    }

    return alerts;
    }

    /**
    * 查找即将过期的评估记录
    */

    private List<EvaluationRecord> findExpiringRecords(String projectId) {
    LocalDateTime threshold = LocalDateTime.now().plusDays(3);

    return recordRepository.findByProjectIdAndStatusAndEndTimeBefore(
    projectId,
    EvaluationStatus.PENDING,
    threshold
    );
    }

    /**
    * 查找评估者数量不足的被评估者
    */

    private List<String> findEvaluateesWithInsufficientRaters(String projectId) {
    // 获取项目配置
    EvaluationProject project = projectRepository.findById(projectId).orElse(null);
    if (project == null) {
    return Collections.emptyList();
    }

    int minRaterCount = project.getMinRaterCount();

    // 按被评估者分组
    Map<String, List<EvaluationRecord>> groupedRecords = recordRepository
    .findByProjectId(projectId).stream()
    .collect(Collectors.groupingBy(EvaluationRecord::getEvaluateeId));

    // 找出评估者数量不足的被评估者
    List<String> insufficientRaters = new ArrayList<>();
    for (Map.Entry<String, List<EvaluationRecord>> entry : groupedRecords.entrySet()) {
    if (entry.getValue().size() < minRaterCount) {
    insufficientRaters.add(entry.getKey());
    }
    }

    return insufficientRaters;
    }

    /**
    * 查找评分存在异常的被评估者
    */

    private List<String> findEvaluateesWithOutlierScores(String projectId) {
    // 获取所有已完成的评估记录
    List<EvaluationRecord> completedRecords = recordRepository
    .findByProjectIdAndStatus(projectId, EvaluationStatus.COMPLETED);

    // 提取所有评分
    List<BigDecimal> allScores = completedRecords.stream()
    .map(EvaluationRecord::getTotalScore)
    .collect(Collectors.toList());

    // 检测异常值
    OutlierDetectionResult detectionResult = outlierDetector.detectOutliers(allScores);

    if (detectionResult.getAllOutliers().isEmpty()) {
    return Collections.emptyList();
    }

    // 找出有异常值的被评估者
    List<String> outlierEvaluatees = completedRecords.stream()
    .filter(record -> detectionResult.getAllOutliers().contains(record.getTotalScore()))
    .map(EvaluationRecord::getEvaluateeId)
    .distinct()
    .collect(Collectors.toList());

    return outlierEvaluatees;
    }
    }

    /**
    * 项目评估进度
    */

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

    private String projectId;

    /**
    * 总评估记录数
    */

    private Integer totalRecords;

    /**
    * 被评估者数量
    */

    private Integer evaluateeCount;

    /**
    * 待评估数量
    */

    private Integer pendingCount;

    /**
    * 评估中数量
    */

    private Integer inProgressCount;

    /**
    * 已完成数量
    */

    private Integer completedCount;

    /**
    * 已跳过数量
    */

    private Integer skippedCount;

    /**
    * 完成率
    */

    private Double completionRate;

    public static ProjectProgress empty() {
    return ProjectProgress.builder()
    .totalRecords(0)
    .evaluateeCount(0)
    .pendingCount(0)
    .inProgressCount(0)
    .completedCount(0)
    .skippedCount(0)
    .completionRate(0.0)
    .build();
    }
    }

    /**
    * 被评估者评估进度
    */

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

    private String projectId;

    /**
    * 被评估者ID
    */

    private String evaluateeId;

    /**
    * 评估者总数
    */

    private Integer totalRaters;

    /**
    * 已完成评估者数量
    */

    private Integer completedRaters;

    /**
    * 完成率
    */

    private Double completionRate;

    /**
    * 各状态数量
    */

    private Map<EvaluationStatus, Long> statusCounts;

    public static EvaluateeProgress empty() {
    return EvaluateeProgress.builder()
    .totalRaters(0)
    .completedRaters(0)
    .completionRate(0.0)
    .statusCounts(Collections.emptyMap())
    .build();
    }
    }

    /**
    * 进度告警
    */

    @Data
    @Builder
    public class ProgressAlert {
    /**
    * 告警类型
    */

    private AlertType alertType;

    /**
    * 告警级别
    */

    private AlertSeverity severity;

    /**
    * 告警消息
    */

    private String message;

    /**
    * 数量
    */

    private Integer count;

    /**
    * 创建时间
    */

    private LocalDateTime createTime;
    }

    /**
    * 告警类型枚举
    */

    public enum AlertType {
    /** 即将过期 */
    EXPIRING_SOON,

    /** 完成率低 */
    LOW_COMPLETION_RATE,

    /** 评估者不足 */
    INSUFFICIENT_RATERS,

    /** 异常评分 */
    OUTLIER_SCORES
    }

    /**
    * 告警级别枚举
    */

    public enum AlertSeverity {
    /** 低 */
    LOW,

    /** 中 */
    MEDIUM,

    /** 高 */
    HIGH
    }

    4.3 数据可视化

    评估结果可视化:

    /**
    * 评估数据可视化服务
    * 生成各种图表和报表
    */

    @Service
    @Slf4j
    public class EvaluationVisualizationService {

    @Autowired
    private EvaluationResultRepository resultRepository;

    /**
    * 生成评分分布图数据
    *
    * @param projectId 项目ID
    * @return 图表数据
    */

    public ChartData generateScoreDistributionChart(String projectId) {
    // 获取所有评估结果
    List<EvaluationResult> results = resultRepository.findByProjectId(projectId);

    // 按分数段分组
    Map<String, Long> distribution = new LinkedHashMap<>();
    distribution.put("90-100", 0L);
    distribution.put("80-89", 0L);
    distribution.put("70-79", 0L);
    distribution.put("60-69", 0L);
    distribution.put("0-59", 0L);

    for (EvaluationResult result : results) {
    BigDecimal score = result.getTotalScore();
    if (score.compareTo(new BigDecimal("90")) >= 0) {
    distribution.put("90-100", distribution.get("90-100") + 1);
    } else if (score.compareTo(new BigDecimal("80")) >= 0) {
    distribution.put("80-89", distribution.get("80-89") + 1);
    } else if (score.compareTo(new BigDecimal("70")) >= 0) {
    distribution.put("70-79", distribution.get("70-79") + 1);
    } else if (score.compareTo(new BigDecimal("60")) >= 0) {
    distribution.put("60-69", distribution.get("60-69") + 1);
    } else {
    distribution.put("0-59", distribution.get("0-59") + 1);
    }
    }

    // 构建图表数据
    List<String> categories = new ArrayList<>(distribution.keySet());
    List<Long> values = new ArrayList<>(distribution.values());

    return ChartData.builder()
    .chartType(ChartType.BAR)
    .title("评分分布")
    .categories(categories)
    .series(List.of(
    ChartSeries.builder()
    .name("人数")
    .data(values)
    .build()
    ))
    .build();
    }

    /**
    * 生成维度对比雷达图数据
    *
    * @param projectId 项目ID
    * @param evaluateeIds 被评估者ID列表
    * @return 图表数据
    */

    public ChartData generateDimensionRadarChart(
    String projectId,
    List<String> evaluateeIds
    ) {
    // 获取评估结果
    List<EvaluationResult> results = evaluateeIds.stream()
    .map(evaluateeId -> resultRepository.findByProjectIdAndEvaluateeId(projectId, evaluateeId))
    .filter(Optional::isPresent)
    .map(Optional::get)
    .collect(Collectors.toList());

    // 提取维度名称
    Set<String> dimensionNames = new LinkedHashSet<>();
    for (EvaluationResult result : results) {
    List<DimensionScore> dimensionScores = parseDimensionScores(result.getDimensionScores());
    dimensionScores.forEach(ds -> dimensionNames.add(ds.getDimensionName()));
    }

    // 构建图表数据
    List<String> categories = new ArrayList<>(dimensionNames);
    List<ChartSeries> series = new ArrayList<>();

    for (EvaluationResult result : results) {
    List<DimensionScore> dimensionScores = parseDimensionScores(result.getDimensionScores());

    // 按维度名称顺序提取分数
    List<BigDecimal> scores = dimensionNames.stream()
    .map(dimName -> {
    return dimensionScores.stream()
    .filter(ds -> ds.getDimensionName().equals(dimName))
    .map(DimensionScore::getScore)
    .findFirst()
    .orElse(BigDecimal.ZERO);
    })
    .collect(Collectors.toList());

    series.add(ChartSeries.builder()
    .name(result.getEvaluateeName())
    .data(scores.stream().map(BigDecimal::doubleValue).collect(Collectors.toList()))
    .build());
    }

    return ChartData.builder()
    .chartType(ChartType.RADAR)
    .title("维度能力对比")
    .categories(categories)
    .series(series)
    .build();
    }

    /**
    * 生成趋势图数据
    *
    * @param evaluateeId 被评估者ID
    * @param projectIds 项目ID列表
    * @return 图表数据
    */

    public ChartData generateTrendChart(
    String evaluateeId,
    List<String> projectIds
    ) {
    // 获取历史评估结果
    List<EvaluationResult> results = projectIds.stream()
    .map(projectId -> resultRepository.findByProjectIdAndEvaluateeId(projectId, evaluateeId))
    .filter(Optional::isPresent)
    .map(Optional::get)
    .sorted(Comparator.comparing(EvaluationResult::getCreateTime))
    .collect(Collectors.toList());

    // 提取数据
    List<String> projectNames = results.stream()
    .map(EvaluationResult::getProjectName)
    .collect(Collectors.toList());

    List<BigDecimal> totalScores = results.stream()
    .map(EvaluationResult::getTotalScore)
    .collect(Collectors.toList());

    // 按维度提取趋势
    Map<String, List<BigDecimal>> dimensionTrends = new LinkedHashMap<>();

    for (EvaluationResult result : results) {
    List<DimensionScore> dimensionScores = parseDimensionScores(result.getDimensionScores());

    for (DimensionScore ds : dimensionScores) {
    dimensionTrends.computeIfAbsent(ds.getDimensionName(), k -> new ArrayList<>())
    .add(ds.getScore());
    }
    }

    // 构建图表数据
    List<ChartSeries> series = new ArrayList<>();

    // 添加总分趋势
    series.add(ChartSeries.builder()
    .name("总分")
    .data(totalScores.stream().map(BigDecimal::doubleValue).collect(Collectors.toList()))
    .build());

    // 添加各维度趋势
    for (Map.Entry<String, List<BigDecimal>> entry : dimensionTrends.entrySet()) {
    series.add(ChartSeries.builder()
    .name(entry.getKey())
    .data(entry.getValue().stream().map(BigDecimal::doubleValue).collect(Collectors.toList()))
    .build());
    }

    return ChartData.builder()
    .chartType(ChartType.LINE)
    .title("绩效趋势")
    .categories(projectNames)
    .series(series)
    .build();
    }

    /**
    * 解析维度得分
    */

    private List<DimensionScore> parseDimensionScores(String dimensionScoresJson) {
    if (StringUtils.isBlank(dimensionScoresJson)) {
    return Collections.emptyList();
    }

    JSONObject jsonObject = JSON.parseObject(dimensionScoresJson);
    List<DimensionScore> dimensionScores = new ArrayList<>();

    for (String key : jsonObject.keySet()) {
    JSONObject dimensionObj = jsonObject.getJSONObject(key);
    DimensionScore dimensionScore = DimensionScore.builder()
    .dimensionId(key)
    .dimensionName(dimensionObj.getString("name"))
    .score(dimensionObj.getBigDecimal("score"))
    .build();
    dimensionScores.add(dimensionScore);
    }

    return dimensionScores;
    }
    }

    /**
    * 图表数据
    */

    @Data
    @Builder
    public class ChartData {
    /**
    * 图表类型
    */

    private ChartType chartType;

    /**
    * 图表标题
    */

    private String title;

    /**
    * 类别标签
    */

    private List<String> categories;

    /**
    * 系列数据
    */

    private List<ChartSeries> series;

    /**
    * 图表配置(JSON格式)
    */

    private String options;
    }

    /**
    * 图表类型枚举
    */

    public enum ChartType {
    /** 柱状图 */
    BAR,

    /** 折线图 */
    LINE,

    /** 饼图 */
    PIE,

    /** 雷达图 */
    RADAR,

    /** 散点图 */
    SCATTER
    }

    /**
    * 图表系列
    */

    @Data
    @Builder
    public class ChartSeries {
    /**
    * 系列名称
    */

    private String name;

    /**
    * 数据
    */

    private List<Double> data;

    /**
    * 颜色
    */

    private String color;
    }


    五、性能优化

    5.1 批量评估处理

    批量评估任务处理器:

    /**
    * 批量评估任务处理器
    * 使用异步处理和消息队列优化大规模评估任务
    */

    @Component
    @Slf4j
    public class BatchEvaluationProcessor {

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    @Autowired
    private EvaluationDataAggregator aggregator;

    /**
    * 批量聚合评估数据
    *
    * @param projectId 项目ID
    * @param evaluateeIds 被评估者ID列表
    */

    public void batchAggregateEvaluation(
    String projectId,
    List<String> evaluateeIds
    ) {
    log.info("开始批量聚合评估数据: projectId={}, count={}",
    projectId, evaluateeIds.size());

    // 分批发送消息到MQ
    int batchSize = 50;
    List<List<String>> batches = Lists.partition(evaluateeIds, batchSize);

    for (int i = 0; i < batches.size(); i++) {
    List<String> batch = batches.get(i);

    EvaluationAggregationMessage message = EvaluationAggregationMessage.builder()
    .projectId(projectId)
    .evaluateeIds(batch)
    .batchNumber(i + 1)
    .totalBatches(batches.size())
    .build();

    rocketMQTemplate.asyncSend(
    "EVALUATION_AGGREGATION_TOPIC",
    message,
    new SendCallback() {
    @Override
    public void onSuccess(SendResult sendResult) {
    log.info("批量聚合消息发送成功: batchNumber={}", i + 1);
    }

    @Override
    public void onException(Throwable e) {
    log.error("批量聚合消息发送失败: batchNumber={}", i + 1, e);
    }
    }
    );
    }
    }
    }

    /**
    * 评估聚合消息监听器
    */

    @Component
    @RocketMQMessageListener(
    topic = "EVALUATION_AGGREGATION_TOPIC",
    consumerGroup = "EVALUATION_AGGREGATION_CONSUMER_GROUP"
    )
    @Slf4j
    public class EvaluationAggregationConsumer implements
    RocketMQListener<EvaluationAggregationMessage> {

    @Autowired
    private EvaluationDataAggregator aggregator;

    @Autowired
    private EvaluationResultRepository resultRepository;

    @Override
    public void onMessage(EvaluationAggregationMessage message) {
    String projectId = message.getProjectId();
    int batchNumber = message.getBatchNumber();

    log.info("处理评估聚合批次: projectId={}, batchNumber={}", projectId, batchNumber);

    try {
    // 并行处理本批次的所有被评估者
    List<EvaluationAggregationResult> results = message.getEvaluateeIds()
    .parallelStream()
    .map(evaluateeId -> aggregator.aggregateEvaluation(projectId, evaluateeId))
    .collect(Collectors.toList());

    // 批量保存聚合结果
    List<EvaluationResult> evaluationResults = results.stream()
    .map(this::convertToEvaluationResult)
    .collect(Collectors.toList());

    resultRepository.saveAll(evaluationResults);

    log.info("评估聚合批次处理完成: projectId={}, batchNumber={}, count={}",
    projectId, batchNumber, evaluationResults.size());

    } catch (Exception e) {
    log.error("评估聚合批次处理失败: projectId={}, batchNumber={}, error={}",
    projectId, batchNumber, e.getMessage());
    }
    }

    /**
    * 转换为评估结果
    */

    private EvaluationResult convertToEvaluationResult(
    EvaluationAggregationResult aggregationResult
    ) {
    EvaluationResult result = new EvaluationResult();
    result.setProjectId(aggregationResult.getProjectId());
    result.setEvaluateeId(aggregationResult.getEvaluateeId());
    result.setTotalScore(aggregationResult.getTotalScore());

    // 转换维度得分
    JSONObject dimensionScores = new JSONObject();
    for (DimensionAggregation dimension : aggregationResult.getDimensionAggregations()) {
    JSONObject dimensionObj = new JSONObject();
    dimensionObj.put("name", dimension.getDimensionName());
    dimensionObj.put("score", dimension.getAverageScore());
    dimensionScores.put(dimension.getDimensionId(), dimensionObj);
    }
    result.setDimensionScores(dimensionScores.toJSONString());

    return result;
    }
    }

    /**
    * 评估聚合消息
    */

    @Data
    @Builder
    public class EvaluationAggregationMessage implements Serializable {
    /**
    * 项目ID
    */

    private String projectId;

    /**
    * 被评估者ID列表
    */

    private List<String> evaluateeIds;

    /**
    * 批次号
    */

    private Integer batchNumber;

    /**
    * 总批次数
    */

    private Integer totalBatches;
    }

    5.2 缓存策略

    评估数据缓存管理:

    /**
    * 评估数据缓存管理器
    * 使用多级缓存提升查询性能
    */

    @Component
    @Slf4j
    public class EvaluationCacheManager {

    /**
    * L1缓存:本地缓存(Caffeine)
    */

    private final Cache<String, Object> localCache;

    /**
    * L2缓存:分布式缓存(Redis)
    */

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    public EvaluationCacheManager() {
    this.localCache = Caffeine.newBuilder()
    .maximumSize(50_000)
    .expireAfterWrite(1, TimeUnit.HOURS)
    .recordStats()
    .build();
    }

    /**
    * 获取项目进度缓存
    *
    * @param projectId 项目ID
    * @return 项目进度
    */

    public ProjectProgress getProjectProgress(String projectId) {
    String cacheKey = buildProjectProgressKey(projectId);

    // 先查L1缓存
    Object cached = localCache.getIfPresent(cacheKey);
    if (cached != null) {
    return (ProjectProgress) cached;
    }

    // 再查L2缓存
    cached = redisTemplate.opsForValue().get(cacheKey);
    if (cached != null) {
    // 回写L1缓存
    localCache.put(cacheKey, cached);
    return (ProjectProgress) cached;
    }

    return null;
    }

    /**
    * 缓存项目进度
    *
    * @param projectId 项目ID
    * @param progress 项目进度
    */

    public void cacheProjectProgress(String projectId, ProjectProgress progress) {
    String cacheKey = buildProjectProgressKey(projectId);

    // 写入L1缓存
    localCache.put(cacheKey, progress);

    // 写入L2缓存
    redisTemplate.opsForValue().set(cacheKey, progress, 30, TimeUnit.MINUTES);
    }

    /**
    * 获取评估结果缓存
    *
    * @param projectId 项目ID
    * @param evaluateeId 被评估者ID
    * @return 评估结果
    */

    public EvaluationResult getEvaluationResult(String projectId, String evaluateeId) {
    String cacheKey = buildEvaluationResultKey(projectId, evaluateeId);

    // 先查L1缓存
    Object cached = localCache.getIfPresent(cacheKey);
    if (cached != null) {
    return (EvaluationResult) cached;
    }

    // 再查L2缓存
    cached = redisTemplate.opsForValue().get(cacheKey);
    if (cached != null) {
    // 回写L1缓存
    localCache.put(cacheKey, cached);
    return (EvaluationResult) cached;
    }

    return null;
    }

    /**
    * 缓存评估结果
    *
    * @param projectId 项目ID
    * @param evaluateeId 被评估者ID
    * @param result 评估结果
    */

    public void cacheEvaluationResult(
    String projectId,
    String evaluateeId,
    EvaluationResult result
    ) {
    String cacheKey = buildEvaluationResultKey(projectId, evaluateeId);

    // 写入L1缓存
    localCache.put(cacheKey, result);

    // 写入L2缓存
    redisTemplate.opsForValue().set(cacheKey, result, 1, TimeUnit.HOURS);
    }

    /**
    * 清除项目相关缓存
    *
    * @param projectId 项目ID
    */

    public void invalidateProjectCache(String projectId) {
    // 清除L1缓存
    Set<String> keys = localCache.asMap().keySet().stream()
    .filter(key -> key.startsWith(projectId))
    .collect(Collectors.toSet());
    localCache.invalidateAll(keys);

    // 清除L2缓存
    Set<String> redisKeys = redisTemplate.keys(projectId + ":*");
    if (redisKeys != null && !redisKeys.isEmpty()) {
    redisTemplate.delete(redisKeys);
    }

    log.info("清除项目缓存: projectId={}", projectId);
    }

    /**
    * 构建项目进度缓存键
    */

    private String buildProjectProgressKey(String projectId) {
    return String.format("evaluation:project:progress:%s", projectId);
    }

    /**
    * 构建评估结果缓存键
    */

    private String buildEvaluationResultKey(String projectId, String evaluateeId) {
    return String.format("evaluation:result:%s:%s", projectId, evaluateeId);
    }
    }


    六、最佳实践

    6.1 评估设计最佳实践

    1. 评估维度设计原则

    – 全面性:覆盖工作业绩、工作能力、工作态度、团队协作等维度
    – 独立性:各维度之间相对独立,避免重复评价
    – 可衡量性:每个维度都可以用具体指标量化
    – 相关性:维度设置与企业战略和岗位要求相关
    – 数量适中:建议4-6个维度,避免评估疲劳

    2. 评估指标设计原则

    – SMART原则:具体、可衡量、可达成、相关性、有时限
    – 行为化:用具体行为描述,而非抽象概念
    – 权重合理:根据指标重要性分配权重
    – 分层设计:核心指标、重要指标、一般指标
    – 可观察性:指标应该是可以直接观察到的

    3. 评估者选择策略

    – 上级评估:1-2人,权重30-40%
    – 同事评估:3-5人,权重20-30%
    – 下级评估:2-3人,权重15-20%
    – 自评:1人,权重5-10%(仅供参考)
    – 客户评估:根据实际情况,权重10-20%

    – 评估者数量:建议5-10人
    – 匿名原则:同事、下级、客户评估匿名
    – 多样性:选择不同背景、不同合作深度的评估者

    6.2 数据分析最佳实践

    1. 异常值处理策略

    // 示例:处理评估异常值
    public class OutlierHandlingExample {

    public void handleOutliers(List<EvaluationRecord> records) {
    // 1. 检测异常值
    EvaluationOutlierDetector detector = new EvaluationOutlierDetector();

    List<BigDecimal> scores = records.stream()
    .map(EvaluationRecord::getTotalScore)
    .collect(Collectors.toList());

    OutlierDetectionResult result = detector.detectOutliers(scores);

    // 2. 根据异常值比例选择处理策略
    if (result.getOutlierRatio() > 0.3) {
    // 异常值比例过高,可能存在系统性问题
    log.warn("异常值比例过高: ratio={}", result.getOutlierRatio());
    // 需要人工复核
    return;
    }

    // 3. 处理异常值
    List<BigDecimal> processedScores = detector.handleOutliers(
    scores,
    OutlierHandlingStrategy.REPLACE_WITH_MEDIAN
    );

    // 4. 使用处理后的数据
    // …
    }
    }

    2. 趋势分析方法

    // 示例:分析绩效趋势
    public class TrendAnalysisExample {

    public TrendAnalysisResult analyzeTrend(String employeeId) {
    // 1. 获取历史评估结果
    List<EvaluationResult> historyResults = getHistoryResults(employeeId);

    // 2. 计算移动平均
    List<BigDecimal> movingAverages = calculateMovingAverage(
    historyResults,
    3 // 3期移动平均
    );

    // 3. 判断趋势
    TrendType trend = determineTrend(movingAverages);

    // 4. 计算趋势强度
    BigDecimal trendStrength = calculateTrendStrength(movingAverages);

    // 5. 预测未来表现
    BigDecimal predictedScore = predictNextScore(movingAverages);

    return TrendAnalysisResult.builder()
    .trendType(trend)
    .trendStrength(trendStrength)
    .predictedScore(predictedScore)
    .build();
    }
    }

    6.3 系统监控最佳实践

    关键监控指标:

    /**
    * 360度评估系统监控指标
    */

    public class EvaluationSystemMetrics {

    /**
    * 核心指标
    */

    public enum CoreMetric {
    /** 评估参与率 */
    EVALUATION_PARTICIPATION_RATE,

    /** 评估完成率 */
    EVALUATION_COMPLETION_RATE,

    /** 平均评估时长 */
    AVERAGE_EVALUATION_DURATION,

    /** 异常评分比例 */
    OUTLIER_SCORE_RATIO,

    /** 缓存命中率 */
    CACHE_HIT_RATE
    }

    /**
    * 业务指标
    */

    public enum BusinessMetric {
    /** 评估项目执行周期 */
    PROJECT_EXECUTION_CYCLE,

    /** 改进计划完成率 */
    IMPROVEMENT_PLAN_COMPLETION_RATE,

    /** 绩效提升率 */
    PERFORMANCE_IMPROVEMENT_RATE,

    /** 员工满意度 */
    EMPLOYEE_SATISFACTION_SCORE
    }
    }


    七、总结

    本文详细介绍了360度绩效评估系统的设计与实现,主要内容包括:

    核心技术点

  • 多维度评估模型:支持工作业绩、工作能力、工作态度、团队协作等多维度评估
  • 智能评估者选择:根据组织结构自动选择合适的评估者
  • 数据聚合算法:加权平均、异常值检测、数据清洗等算法
  • 结果分析引擎:排名计算、趋势分析、对比分析
  • 改进计划生成:基于评估结果自动生成改进建议
  • 业务价值

  • 全面性:多视角评估,全面了解员工表现
  • 客观性:多人评估减少个人偏见
  • 发展性:帮助员工识别优势和改进空间
  • 数据化:量化评估结果,便于决策
  • 自动化:自动化流程降低管理成本
  • 扩展方向

  • AI辅助评估:使用NLP技术分析评语,提取关键信息
  • 智能推荐:根据历史数据推荐改进措施
  • 预测分析:预测员工绩效发展趋势
  • 实时反馈:支持实时评估和即时反馈
  • 移动端优化:优化移动端评估体验

  • 参考资料

  • 360度反馈评估方法论
  • 绩效管理最佳实践
  • 《绩效管理:理论与实践》(第四版)
  • 《组织行为学》(第18版)
  • 《数据化运营:系统方法与实践案例》

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

    评论 抢沙发

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