欢迎光临
我们一直在努力

SpringBoot+Vue3 绩效管理系统设计:KPI/OKR + 360 评估 + 绩效校准与申诉全流程

SpringBoot+Vue3 绩效管理系统设计:KPI/OKR + 360 评估 + 绩效校准与申诉全流程

🌐 演示地址:http://ruoyioffice.com | 📦 源码1·GitHub:ruoyi-office | 📦 源码2·GitCode:ruoyi-office | 📦 源码3·Gitee:ruoyi-office | 💬 微信:17156169080(备注「RuoYi Office」)

绩效管理是企业 HRM 里最"得罪人"也最难做对的模块——评什么、谁来评、分怎么算、等级怎么定、员工不服气怎么办,每一步都牵动着钱和人心。多数企业还停留在"季末发一张 Excel、主管凭印象打分、HR 手工汇总"的阶段:标准不透明、评分无依据、等级靠拍脑袋、申诉无渠道。RuoYi Office 用 15 张表把绩效拆成"配置层 + 执行层 + 结果层"三段,KPI/OKR 双评价模式、自评/上级评/360 加权汇总、HR 校准对齐正态分布、结果确认与申诉双 BPM 流程闭环,让绩效从"凭印象"升级为有数据、有留痕、可追溯的引擎。

hrm-performance-architecture.png

▲ 绩效管理功能架构全景:①配置区(周期/方案/模板/指标库/等级规则)→ ②流程区(计划→自评→上级评→360→HR校准→结果确认→申诉)→ ③数据模型(15 张表三层结构)→ ④四大设计亮点

引言:绩效管理到底难在哪?

“不就是给员工打个分吗?”——没真正做过绩效系统的人都这么想。但只要落地一次,就会撞上一连串难题:

评价方法多样,一套表撑不住:有的部门用 KPI(结果指标,如"销售额 ≥ 100 万"),有的团队用 OKR(目标指标,如"上线 3 个核心功能"),还有的混合了行为能力、纪律执行、专项贡献。如果为每种方法各做一套表,系统会迅速膨胀到无法维护。

评分要有依据,不能凭印象:员工自评打 95 分、主管打 60 分,到底听谁的?没有逐项指标、没有权重、没有过程证据,最后变成"谁嗓门大谁赢"。绩效得分必须由指标 × 权重加权算出来,而不是拍一个总分。

等级要对齐,避免"全员优秀":如果各主管各自打分,结果往往是"人人 A、个个优秀",绩效奖金池根本不够分。需要 HR 做一轮校准(Calibration),按部门拉齐 S/A/B/C/D 的比例,对齐正态分布。

结果要确认,异议要有出口:绩效结果直接关联奖金、调薪,员工有权知情并签字确认。一旦不认可,必须有正规的申诉渠道,而不是私下找领导吵。申诉还得二次校准、二次确认,全程留痕。

全程要可追溯:自评分、上级评分、校准分、最终分——每一级都要留底;校准前后、申诉前后的分数变化要留原因;用了哪条等级规则、系数多少、绩效金额多少,都要快照保存,方便复盘和合规审计。

本文以 RuoYi Office 的 yudao-module-hrm 绩效模块为例,完整拆解其数据建模、四级评分加权、等级规则匹配、HR 校准与申诉双流程的设计方案。所有结论均来自真实源码。


一、业务设计:配置层 + 执行层 + 结果层

1.1 核心理念:配置驱动,规则与数据分离

绩效管理 = 一次配置(规则),多次执行(评价),自动产出(结果)。RuoYi Office 把整个模块抽象为三层:

分层职责核心表谁来维护
配置层 定义"评什么、怎么算" 周期 / 方案 / 模板 / 指标库 / 等级规则 HR 管理员,一次配置
执行层 承载"谁在评、评多少" 计划 / 计划项 / 评价单 / 评审记录 / 校准记录 员工、主管、HR 协同
结果层 产出"得几分、什么级、多少钱" 结果 / 批次结果审批单 系统自动 + HR 确认

这种分层的价值:HR 配好一套"乐高积木"(指标库 + 等级规则 + 模板),每个考核周期直接复用,不必重复造轮子。

1.2 KPI / OKR 双评价模式

绩效方案 PerformanceSchemeDO 用一个 evaluationMode 字段切换评价方法论,配合统一的指标库支撑多种考核风格:

evaluationMode含义适用场景
1 KPI 销售、生产等结果导向岗位
2 OKR 研发、创新等目标导向团队
3 KPI + 行为混合 既看结果又看价值观的管理岗
4 OKR + KPI 混合 项目制、矩阵式团队

指标库 PerformanceIndicatorDO 的 indicatorType 把指标统一分为五类,无论 KPI 还是 OKR 都从同一个库里挑:

indicatorType类型说明
1 结果指标(KPI) 可量化的业绩结果
2 目标指标(OKR) 阶段性关键目标
3 行为能力 协作、沟通、专业能力
4 纪律执行 考勤、制度遵守
5 专项贡献 临时项目、创新加分

关键设计:方案还定义了 scoreMode(1 百分制 / 2 等级制)和 salaryLinkMode(1 系数制 / 2 金额制 / 3 人工确认),决定了最终分如何换算成绩效工资——一套引擎跑两套方法论、三种薪资联动。

1.3 评价单状态机:贯穿全流程的主线

执行层的核心是绩效考核评价单 PerformanceAssessmentBillDO,它的 status 字段是一条贯穿始终的状态主线(取自源码常量):

10 待自评 → 20 待上级评 → 30 待校准 → 40 待结果确认 → 50 已完成

员工不认可,发起申诉

60 待发起 → 61 待审核 → 62 待校准 → 63 待确认 → 64 申诉完成

状态码含义当前节点经办人
10 待自评 self_review 自评填报 员工本人
20 待上级评 leader_review 评审填报 直属主管
30 待校准 hr_calibration 校准填报 HR / 校准人
40 待结果确认 result_confirm 结果确认 员工本人
50 已完成 —(终态)
61~64 申诉审核/校准/确认/完成 appeal_* 系列 主管 / HR / 员工

二、系统设计:模块职责与设计决策

2.1 模块组成

绩效管理位于 HRM 人力资源 → 绩效管理 目录下,由配置、执行、结果三类共 13 个页面组成:

子模块页面功能面向角色
设置 指标库 / 模板 / 方案 / 等级规则 维护考核规则 HR 管理员
周期 周期列表 / 详情 创建考核周期、设置截止日期 HR 管理员
计划 计划列表 / 详情 / 过程证据 制定指标计划、目标确认、同步工作汇报 HR + 员工
自评 自评待办 员工逐项打分、填写说明 员工本人
上级评 评审待办 主管逐项复评 直属主管
HR 校准 校准列表 调整分数、对齐等级分布 HR / 校准人
结果 结果列表 / 详情 查看得分、等级、绩效金额 HR + 员工
结果确认 批次审批 / 个人确认 批次走审批、个人签字确认 HR + 员工
申诉 申诉列表 发起申诉、审核、二次校准 员工 + 主管 + HR
统计 绩效统计 周期数、参与人数、平均分、金额合计 HR 管理员

2.2 核心设计决策

决策点方案理由
评价方法 方案级 evaluationMode 切换 KPI/OKR 一套引擎适配多种方法论,指标库统一承载
评分留痕 计划项存自评/上级/校准/最终四级分 每一级独立留底,可追溯、可复盘
成绩计算 ∑(有效分 × 权重) / ∑权重,HALF_UP 两位 加权汇总有据可依,不是拍总分
取值优先级 finalScore > calibratedScore > leaderScore > selfScore 越靠后的环节越权威,自动覆盖前序
等级判定 等级规则区间 [scoreStart, scoreEnd] 匹配 分数→等级→系数全自动,HR 可配
流程编排 主流程 + 申诉流程两条独立 BPM 实例 申诉是支线,独立留痕不污染主流程
结果快照 resultSnapshotJson 存指标明细+校准记录 合规审计、历史复盘不依赖实时计算

三、PC 端功能实现

3.1 绩效方案配置

绩效方案是整个考核体系的"总开关"——它定义了评估方法(KPI / OKR / 360)、周期类型(月度/季度/年度)、评分模式(百分制)与联薪方式(系数制),并关联一套指标模板,后续的批次、计划、评价单都基于方案派生。 hrm-performance-scheme-list.png ▲ 绩效方案列表:“标准月度绩效考核方案"采用 KPI+行为混合评估模式、百分制评分、系数制联薪,关联"通用月度绩效考核模板”;另有标准季度方案,状态均为启用

方案设计要点:

  • 评估模式可切换:方案级 evaluationMode 支持 KPI、OKR、KPI+行为混合等多种方法论,一套引擎适配不同考核体系。
  • 周期与模板绑定:方案绑定周期类型(月度/季度/年度)与指标模板,批次按方案批量生成员工计划,避免重复配置。
  • 联薪方式系数制:评分换算为等级后映射绩效系数,再与薪资联动,把"考核结果"真正落到"绩效金额"。

3.2 绩效计划与 HR 校准

绩效计划是执行层的起点——HR 按模板为每个员工生成"指标 + 权重 + 目标值"的考核计划,员工确认目标后正式进入考核;自评、上级评完成后,HR 校准是绩效系统区别于"简单打分工具"的关键环节,HR 站在全局视角调整分数与等级,对齐部门正态分布。

计划与校准设计要点:

  • 计划项即考核指标:每个计划含若干 plan_item,每项有指标名、权重、目标值,以及自评分/上级分/校准分四级留痕。
  • 目标确认触发评价单:confirmTarget 将计划状态置为"已确认",自动调用 createFromPlanIfAbsent 生成评价单、启动主流程。
  • 同步工作汇报取数:syncWorkReport 拉取 OA 工作汇报作为过程证据,对"系统取数"类指标自动算自评分。
  • 校准前后双留痕:PerformanceCalibrationDO 同时存 beforeScore/beforeLevel 与 afterScore/afterLevel/afterCoefficient,HR 只填校准后分数,后端 resolveGradeSummary 自动匹配等级规则换算等级与系数,且 reason 必填,杜绝暗箱操作。

3.3 绩效统计与结果

绩效统计是结果层的全局视图——基于一期已落地的绩效批次、目标确认、考核结果和确认单据实时聚合批次数、参与人数、平均得分、绩效金额合计,并直接展示绩效结果明细。 hrm-performance-statistics.png

▲ 绩效统计看板:7 个绩效批次、22 名参与人、平均得分 83.75、绩效金额合计 5,600,下方"绩效结果明细"逐行展示员工得分、等级(S/A/B/C/D)、系数、绩效金额与结果状态

统计与结果设计要点:

  • 结果由计划自动汇总:generatePerformanceResultsByPeriod 遍历周期内已校准的计划,按最终分匹配等级规则生成结果,得分取值优先级为 finalScore > calibratedScore > leaderScore > selfScore。
  • 多状态分离:publishStatus(发布)/ signStatus(签字)/ salarySyncStatus(薪资同步)相互独立,对应不同操作节点。
  • 结果快照:resultSnapshotJson 完整保存每项指标的有效分、得分来源、加权贡献、校准记录,详情页直接渲染,不依赖实时计算,满足合规审计与历史复盘。

四、流程设计:主流程 + 申诉流程双 BPM 编排

4.1 主流程:自评 → 上级评 → 校准 → 结果确认

当员工确认目标后,系统自动生成评价单并启动主流程(HRM_PERFORMANCE_ASSESSMENT_BILL)。整条流程由 BPM 节点驱动,每个节点对应一个状态:

[制定计划] 目标确认
│ createFromPlanIfAbsent → 生成评价单 + startMainProcess

[self_review 自评填报] 员工逐项打分 → submitSelfReview → status=20

[leader_review 评审填报] 主管逐项复评 → submitLeaderReview → status=30

[hr_calibration 校准填报] HR 校准 → submitCalibration → status=40

[result_confirm 结果确认] 员工确认 → confirmResult
├─ 认可 → status=50 已完成
└─ 不认可 → startAppeal → 进入申诉支线

关键设计:评价单生成时显式设置 PROCESS_SKIP_START_USER_NODE = false,确保流程不会自动跳过发起人节点,而是稳稳停在"自评填报"等待员工处理。

4.2 申诉流程:独立 BPM 实例,二次校准闭环

员工对结果有异议时,不在主流程里"回退",而是启动一条独立的申诉流程(HRM_PERFORMANCE_APPEAL_BILL):

[result_confirm] 员工不认可 → startAppeal → status=61 待审核

[appeal_audit 申诉审核] 主管审核 → submitAppealAudit
├─ 驳回 → status=50 已完成(维持原结果)
└─ 通过 → status=62 待校准

[appeal_calibration 申诉校准] HR 二次校准 → status=63 待确认

[appeal_result_confirm 申诉结果确认] 员工确认 → status=64 申诉完成

评价单上分别记录了主流程与申诉流程的实例 ID 和状态——mainProcessInstanceId/mainProcessStatus 与 appealProcessInstanceId/appealProcessStatus,两条流程各自独立留痕、互不污染。

4.3 批次结果审批:FlowBillService 回调发布

周期结束后,HR 创建一张批次结果审批单 PerformanceResultConfirmBillDO,走标准 BPM 审批。它实现了 FlowBillService 接口,审批通过时自动回调发布整批结果:

@Override
@Transactional(rollbackFor = Exception.class)
public void onProcessApproved(String businessKey) {
Long id = Long.parseLong(businessKey);
PerformanceResultConfirmBillDO bill = performanceResultConfirmBillMapper.selectById(id);
if (bill == null) {
return;
}
// 审批通过 → 按周期发布全部绩效结果,并把周期状态推进到"已发布"(5)
performanceResultService.publishPerformanceResultsByPeriod(bill.getPeriodId());
performancePeriodMapper.updateById(new PerformancePeriodDO().setId(bill.getPeriodId()).setStatus(5));
}

提交批次审批前,还会校验该周期下所有评价单是否都已走到终态(50 已完成 / 64 申诉完成),否则拒绝提交——避免"有人还没评完就发奖金"。


五、后端核心实现

5.1 成绩计算与等级匹配(核心)

绩效得分不是拍一个总分,而是按"指标 × 权重"加权汇总。calculateStageScore 是整个模块的心脏——遍历计划项,按阶段取有效分,加权平均后保留两位小数:

private BigDecimal calculateStageScore(List<PerformancePlanItemDO> items, String stageKey) {
if (items == null || items.isEmpty()) {
return null;
}
BigDecimal totalWeight = BigDecimal.ZERO;
BigDecimal totalScore = BigDecimal.ZERO;
for (PerformancePlanItemDO item : items) {
if (item.getWeight() == null) {
continue;
}
BigDecimal score = resolveStageItemScore(item, stageKey); // 按阶段取分
if (score == null) {
continue;
}
totalWeight = totalWeight.add(item.getWeight());
totalScore = totalScore.add(score.multiply(item.getWeight()));
}
if (BigDecimal.ZERO.compareTo(totalWeight) == 0) {
return null;
}
// 加权平均:∑(分×权重) / ∑权重
return totalScore.divide(totalWeight, 2, RoundingMode.HALF_UP);
}

不同阶段取不同的"有效分"——这是四级评分留痕的精髓。resolveStageItemScore 用阶段 key 决定取自评分、上级分还是校准分,且后序环节缺分时自动降级取前序分:

private BigDecimal resolveStageItemScore(PerformancePlanItemDO item, String stageKey) {
return switch (stageKey) {
case "self_review" -> item.getSelfScore();
case "leader_review" -> item.getLeaderScore() != null ? item.getLeaderScore() : item.getSelfScore();
case "hr_calibration", "result_confirm", "appeal_calibration", "appeal_result_confirm" ->
item.getCalibratedScore() != null ? item.getCalibratedScore()
: item.getLeaderScore() != null ? item.getLeaderScore() : item.getSelfScore();
default -> item.getFinalScore() != null ? item.getFinalScore()
: item.getCalibratedScore() != null ? item.getCalibratedScore()
: item.getLeaderScore() != null ? item.getLeaderScore() : item.getSelfScore();
};
}

得分算出来后,由 matchGradeRule 在等级规则里找到第一条命中区间的规则,换算等级与系数:

private PerformanceGradeRuleDO matchGradeRule(BigDecimal score, List<PerformanceGradeRuleDO> gradeRules) {
if (score == null || gradeRules == null || gradeRules.isEmpty()) {
return null;
}
return gradeRules.stream()
.filter(rule -> rule.getScoreStart() != null && rule.getScoreEnd() != null
&& score.compareTo(rule.getScoreStart()) >= 0 // score >= start
&& score.compareTo(rule.getScoreEnd()) <= 0) // score <= end
.findFirst()
.orElse(null);
}

等级规则默认按"S(95-100, 系数1.5) / A(85-94.99, 1.2) / B(75-84.99, 1.0) / C(65-74.99, 0.8) / D(0-64.99, 0.5)"五档配置,HR 可按方案自定义区间与系数。

5.2 自评 / 上级评:360 评分回写与加权汇总

自评和上级评提交时,前端传一段评分快照 JSON(每项 planItemId + score + comment)。applyReviewScores 把分数回写到对应计划项,再加权汇总成计划的总分:

private void applyReviewScores(PerformanceReviewDO review) {
// 仅自评(1)/上级评(2)需要回写分数
if (!Integer.valueOf(1).equals(review.getReviewType()) && !Integer.valueOf(2).equals(review.getReviewType())) {
return;
}
PerformancePlanDO plan = performancePlanMapper.selectById(review.getPlanId());
if (plan == null) {
return;
}
List<ScoreSnapshotItem> items = parseScoreItems(review.getScoreSnapshotJson());
for (ScoreSnapshotItem item : items) {
if (item.getPlanItemId() == null) {
continue;
}
PerformancePlanItemDO update = new PerformancePlanItemDO().setId(item.getPlanItemId());
// 自评写 selfScore,上级评写 leaderScore —— 两套分数互不覆盖
if (Integer.valueOf(1).equals(review.getReviewType())) {
update.setSelfScore(item.getScore());
} else {
update.setLeaderScore(item.getScore());
}
if (StringUtils.isNotBlank(item.getComment())) {
update.setScoreComment(item.getComment());
}
performancePlanItemMapper.updateById(update);
}
// 重新加权汇总,更新计划总分与状态
List<PerformancePlanItemDO> planItems = performancePlanItemMapper.selectListByPlanId(plan.getId());
BigDecimal score = calculateWeightedScore(planItems, Integer.valueOf(1).equals(review.getReviewType()));
PerformancePlanDO updatePlan = new PerformancePlanDO().setId(plan.getId()).setFinalScore(score);
if (Integer.valueOf(1).equals(review.getReviewType())) {
updatePlan.setSelfReviewTime(review.getSubmitTime()).setStatus(4);
} else {
updatePlan.setLeaderReviewTime(review.getSubmitTime()).setStatus(5);
}
performancePlanMapper.updateById(updatePlan);
updatePeriodStatus(plan.getPeriodId()); // 全员评完则推进周期状态
}

自评提交前还有一道完整性校验——必须每项指标都打了分、写了说明,否则报错并提示缺失的指标名,杜绝"敷衍打分":

private void validateSelfReviewPayload(PerformanceAssessmentBillDO bill, String scoreSnapshotJson) {
List<ScoreSnapshotItem> snapshotItems = parseScoreSnapshotItems(scoreSnapshotJson);
Map<Long, ScoreSnapshotItem> scoreMap = /* 按 planItemId 建索引 */;
for (PerformancePlanItemDO item : performancePlanItemMapper.selectListByPlanId(bill.getPlanId())) {
ScoreSnapshotItem scoreItem = scoreMap.get(item.getId());
if (scoreItem == null || scoreItem.getScore() == null || StringUtils.isBlank(scoreItem.getComment())) {
throw exception(PERFORMANCE_ASSESSMENT_BILL_SELF_REVIEW_ITEM_INCOMPLETE, item.getIndicatorName());
}
}
}

5.3 HR 校准:填分自动算等级,结果同步回写

HR 校准时只需填校准后分数,submitCalibration 负责把它换算成等级与系数、记录校准留痕、刷新结果、推进流程:

@Override
@Transactional(rollbackFor = Exception.class)
public void submitCalibration(PerformanceAssessmentBillCalibrationReqVO reqVO) {
PerformanceAssessmentBillDO bill = validateBillForAction(reqVO.getBillId(), "hr_calibration");
// 1. 校准后分数 → 自动匹配等级规则得出等级、系数
StageScoreSummary summary = resolveGradeSummary(resolvePlan(bill.getPlanId()), reqVO.getAfterScore());
// 2. 记录校准前后双留痕
PerformanceCalibrationSaveReqVO calibrationReqVO = new PerformanceCalibrationSaveReqVO();
calibrationReqVO.setAssessmentBillId(bill.getId());
calibrationReqVO.setCalibrationType(CALIBRATION_TYPE_MAIN);
calibrationReqVO.setBeforeScore(resolvePlanScore(bill.getPlanId()));
calibrationReqVO.setBeforeLevel(resolvePlan(bill.getPlanId()).getFinalLevel());
calibrationReqVO.setAfterScore(reqVO.getAfterScore());
calibrationReqVO.setAfterLevel(summary.level);
calibrationReqVO.setAfterCoefficient(summary.coefficient);
calibrationReqVO.setReason(reqVO.getReason());
performanceCalibrationService.createPerformanceCalibration(calibrationReqVO); // 回写计划 finalScore/Level
refreshBillFinalResult(bill.getId(), RESULT_TYPE_ORIGINAL, reqVO.getReason()); // 生成原始结果
// 3. 推进到"结果确认",经办人改为员工本人
performanceAssessmentBillMapper.updateById(new PerformanceAssessmentBillDO().setId(bill.getId())
.setStatus(BILL_STATUS_WAIT_RESULT_CONFIRM)
.setCurrentNodeKey("result_confirm")
.setCurrentAssigneeId(resolveEmployeeUserId(bill.getEmployeeId()))
.setFinalScore(reqVO.getAfterScore())
.setFinalLevel(summary.level)
.setFinalCoefficient(summary.coefficient));
}

校准记录落库时,applyCalibration 会把校准后的分数、等级、系数同步回写到计划,并在全员校准完成后自动推进周期状态:

private void applyCalibration(PerformanceCalibrationDO calibration) {
PerformancePlanDO plan = performancePlanMapper.selectById(calibration.getPlanId());
if (plan == null) {
return;
}
performancePlanMapper.updateById(new PerformancePlanDO().setId(plan.getId())
.setFinalScore(calibration.getAfterScore())
.setFinalLevel(calibration.getAfterLevel())
.setFinalCoefficient(calibration.getAfterCoefficient())
.setStatus(6)); // 已校准
List<PerformancePlanDO> plans = performancePlanMapper.selectListByPeriodId(plan.getPeriodId());
boolean allCalibrated = !plans.isEmpty() && plans.stream().allMatch(item -> item.getStatus() != null && item.getStatus() >= 6);
if (allCalibrated) {
performancePeriodMapper.updateById(new PerformancePeriodDO().setId(plan.getPeriodId()).setStatus(4));
}
}

5.4 批次结果汇总:等级分布与绩效金额

批次结果审批单生成时,buildBill 会按周期汇总全员结果——计算平均分、绩效金额合计,并按等级分组统计分布,为审批人提供决策依据:

List<PerformanceResultDO> results = performanceResultMapper.selectListByPeriodId(saveReqVO.getPeriodId());
// 平均分
BigDecimal avgScore = results.isEmpty() ? BigDecimal.ZERO : results.stream()
.map(item -> item.getScore() == null ? BigDecimal.ZERO : item.getScore())
.reduce(BigDecimal.ZERO, BigDecimal::add)
.divide(BigDecimal.valueOf(results.size()), 2, RoundingMode.HALF_UP);
// 绩效金额合计
BigDecimal totalAmount = results.stream()
.map(item -> item.getPerformanceAmount() == null ? BigDecimal.ZERO : item.getPerformanceAmount())
.reduce(BigDecimal.ZERO, BigDecimal::add);
// 等级分布:S:3, A:12, B:25, C:6, D:1
String distribution = results.stream()
.collect(Collectors.groupingBy(item -> item.getLevel() == null ? "未定级" : item.getLevel(), Collectors.counting()))
.entrySet().stream()
.map(entry -> entry.getKey() + ":" + entry.getValue())
.collect(Collectors.joining(", "));

这个等级分布字符串会随流程变量带入审批流,审批人一眼就能看出"S/A 是否超标、是否符合正态分布"。


六、RuoYi Office 的创新设计

6.1 四级评分:自评/上级/校准/最终独立留痕

传统打分系统往往只存一个"最终分",改了就找不回原值。RuoYi Office 在 plan_item 上设了 selfScore / leaderScore / calibratedScore / finalScore 四个独立字段。每一级评分都在自己的字段里,互不覆盖,任何环节都能回溯"员工自己打了多少、主管打了多少、HR 校准成多少"。

计算总分时按 finalScore > calibratedScore > leaderScore > selfScore 的优先级降级取值——越靠后的环节越权威,缺分时自动回退到前序,永远有分可算。

6.2 KPI/OKR 双模:一个库、五类指标、两套方法论

不为 KPI 和 OKR 各做一套表,而是用统一的指标库(五类 indicatorType)+ 方案级 evaluationMode 切换。同一个指标库里,"销售额"是 KPI 结果指标,"上线核心功能"是 OKR 目标指标,"团队协作"是行为能力——HR 按方案自由组合,引擎完全不变。

6.3 HR 校准:对齐正态分布,治理"全员优秀"

如果各主管自行打分,结果一定是"人人 A"。RuoYi Office 把校准做成独立环节:HR 横向对比同部门所有人的分数,按 S/A/B/C/D 的合理比例拉齐,对齐正态分布。校准前后分数、等级、系数全部留痕,原因必填——既治理了分数通胀,又保证了透明可申诉。

6.4 主流程 + 申诉流程:双 BPM 实例不互相污染

申诉不是在主流程里"回退节点",而是启动一条独立的申诉流程实例。评价单上 mainProcessInstanceId 与 appealProcessInstanceId 分开记录,主流程的审批历史保持干净,申诉的审核-校准-确认全程独立留痕。这样既符合"申诉是例外支线"的业务语义,又方便合规审计。

6.5 结果快照:合规审计不依赖实时计算

绩效结果生成时,resultSnapshotJson 完整保存了每项指标的有效分、得分来源(员工自评/上级评分/校准分/最终确认分)、加权贡献、所有校准记录。哪怕日后指标库、等级规则发生变更,历史结果详情依然能原样还原——这对"年终复盘、调薪依据、劳动仲裁举证"等场景至关重要。


七、数据结构

7.1 表结构:hrm_performance_assessment_bill(评价单 · 核心执行表)

字段类型说明
id bigint 主键
bill_code varchar 评价单编号
plan_id bigint 关联绩效计划
period_id bigint 关联周期
employee_id / employee_name bigint/varchar 被考核员工
leader_user_id / leader_user_name bigint/varchar 直属主管
current_node_key / current_node_name varchar 当前节点
current_assignee_id / current_assignee_name bigint/varchar 当前经办人
main_process_instance_id / main_process_status varchar/int 主流程实例
appeal_process_instance_id / appeal_process_status varchar/int 申诉流程实例
status int 状态(10/20/30/40/50/61~64)
final_score / final_level / final_coefficient decimal/varchar/decimal 最终分/级/系数
result_confirm_status int 结果确认状态
appeal_status int 申诉状态
appeal_start_time / appeal_result_confirm_time datetime 申诉时间留痕

7.2 表结构:hrm_performance_plan_item(计划项 · 四级评分留痕)

字段类型说明
id bigint 主键
plan_id bigint 关联计划
indicator_id / indicator_code / indicator_name bigint/varchar 指标
item_type int 指标类型(结果/目标/行为/纪律/专项)
target_value / actual_value varchar 目标值 / 实际值
weight decimal 权重
data_source_type int 数据来源(1手工 2系统取数 3外部联动)
self_score decimal 自评分
leader_score decimal 上级评分
calibrated_score decimal 校准分
final_score decimal 最终确认分
score_comment varchar 评分说明
sort int 排序

7.3 表结构:hrm_performance_grade_rule(等级规则)

字段类型说明
id bigint 主键
scheme_id / scheme_name bigint/varchar 所属方案
rule_name varchar 规则名称
score_start / score_end decimal 得分区间 [start, end]
grade_level varchar 等级(S/A/B/C/D)
coefficient decimal 绩效系数
fixed_amount decimal 固定绩效金额
sort / enabled int 排序 / 是否启用

7.4 表结构:hrm_performance_calibration(校准记录)

字段类型说明
id bigint 主键
assessment_bill_id / plan_id bigint 关联评价单/计划
calibration_type int 校准类型(1主校准 2申诉校准)
before_score / before_level decimal/varchar 校准前分/级
after_score / after_level / after_coefficient decimal/varchar/decimal 校准后分/级/系数
reason varchar 校准原因(必填)
calibration_user_id / calibration_user_name bigint/varchar 校准人
calibration_time datetime 校准时间

7.5 设计要点

  • 四级评分字段并存:self/leader/calibrated/final 四个分数字段互不覆盖,是全程可追溯的根基
  • @TableField(exist=false) 运行时计算:评价单 DO 上的 currentScore/selfReviewScore/leaderReviewScore/calibrationScore 等不落库,在 enrichBill 时按计划项实时加权算出
  • BigDecimal 精度统一:所有得分计算用 divide(…, 2, RoundingMode.HALF_UP),权重/系数用更高精度,避免浮点误差影响奖金
  • 双流程实例字段分离:主流程与申诉流程的实例 ID/状态各占一组字段,互不干扰

八、技术亮点总结

设计要点实现方式价值
三层架构 配置层 / 执行层 / 结果层,15 张表 规则与数据分离,HR 一次配置全员复用
KPI/OKR 双模 方案级 evaluationMode + 五类指标库 一套引擎跑两套方法论
四级评分留痕 self/leader/calibrated/final 四字段 每级独立留底,全程可追溯
加权成绩计算 ∑(分×权重)/∑权重,HALF_UP 两位 评分有据可依,不是拍总分
取值优先级降级 final>calibrated>leader>self 越后越权威,缺分自动回退
等级规则匹配 区间 [start,end] 命中 → 等级+系数 分数→等级→薪资全自动
自评完整性校验 逐项校验分数+说明非空 杜绝敷衍打分
HR 校准 校准前后双留痕 + 原因必填 对齐正态分布,治理分数通胀
双 BPM 流程 主流程 + 申诉流程独立实例 申诉支线不污染主流程
结果快照 resultSnapshotJson 存明细+校准 合规审计不依赖实时计算
批次审批回调 FlowBillService.onProcessApproved 审批通过自动发布整批结果
周期状态自动推进 全员评完/校准完自动进下一阶段 减少 HR 手工操作

九、快速体验

在线演示:http://ruoyioffice.com/web/(账号 admin / 密码 admin123)

操作路径:HRM 人力资源 → 绩效管理

推荐体验流程:

  • 配置规则:进入「设置 → 指标库」维护几个 KPI/OKR 指标,再到「等级规则」配置 S/A/B/C/D 的分数区间与系数
  • 建方案与模板:创建绩效方案,选择 KPI 或 OKR 评价模式,绑定指标项与权重
  • 建周期:新建一个季度周期,绑定方案,设置自评/评审/校准三道截止日期
  • 制定计划:为员工生成考核计划,确认目标后观察评价单自动生成、主流程启动
  • 走流程:依次体验「自评填报 → 上级评分 → HR 校准 → 结果确认」,观察分数如何逐级加权汇总、等级如何自动匹配
  • 试校准:在「HR 校准」里改一个分数,观察等级、系数随之自动变化,校准记录留痕
  • 试申诉:在结果确认时选择"不认可",体验申诉审核 → 二次校准 → 申诉结果确认的完整支线
  • 看结果与统计:到「绩效结果」查看最终得分/等级/金额,到「统计」看周期平均分与等级分布
  • 源码仓库:

    平台地址
    GitHub https://github.com/yuqing2026/ruoyi-office
    GitCode https://gitcode.com/zhouzhongyan/ruoyi-office
    Gitee https://gitee.com/yqzy1688/ruoyi-office

    结语

    绩效管理的难点从来不是"打分"本身,而是让打分有依据、让等级有标准、让结果有出口、让全程可追溯。RuoYi Office 的设计给出了一套务实答案:用三层架构把规则和数据分开,用四级评分字段让每一步打分都留底,用加权成绩 + 等级规则把"主观印象"换成"客观算法",用 HR 校准对齐正态分布治理分数通胀,用主流程 + 申诉流程双 BPM 编排让异议有正规出口。

    这套"配置驱动 + 多级留痕 + 规则匹配 + 流程闭环"的思路不止适用于绩效,也能推广到能力评估、述职评审、供应商考评、项目验收打分等所有"多人评分 + 加权汇总 + 等级判定 + 结果确认"的场景。

    如果你正在设计企业 HRM 的绩效模块,或者对"KPI/OKR 双模、多级评分留痕、校准与申诉流程"感兴趣,欢迎参考源码实现。你们公司的绩效是怎么做校准的?是按部门拉正态分布,还是主管说了算?欢迎在评论区聊聊。


    常见问题(FAQ)

    RuoYi Office 的绩效管理同时支持 KPI 和 OKR 吗?

    支持。绩效方案 PerformanceSchemeDO 提供 evaluationMode 字段,可选 KPI、OKR、KPI+行为混合、OKR+KPI 混合四种模式;指标库统一把指标分为结果(KPI)/目标(OKR)/行为/纪律/专项五类,同一套引擎适配两种方法论。

    绩效得分是怎么算出来的?

    按"指标 × 权重"加权汇总:∑(有效分 × 权重) / ∑权重,保留两位小数(HALF_UP)。有效分按 finalScore > calibratedScore > leaderScore > selfScore 优先取值,再用等级规则的区间 [scoreStart, scoreEnd] 匹配出等级 S/A/B/C/D 与对应系数。

    什么是"绩效校准",为什么需要它?

    绩效校准(Calibration)是 HR 在主管评分后做的一轮全局调整,用于对齐部门内 S/A/B/C/D 的比例、对齐正态分布,治理"全员优秀"的分数通胀。RuoYi Office 的校准会记录校准前后的分数、等级、系数,并要求填写校准原因,全程透明可追溯。

    员工对绩效结果不认可怎么办?

    可以发起申诉。RuoYi Office 用一条独立的申诉 BPM 流程处理:员工发起 → 上级审核 → HR 二次校准 → 员工确认申诉结果。申诉流程与主流程是两条独立的流程实例,各自留痕,互不污染。

    绩效结果能和薪资联动吗?

    能。方案的 salaryLinkMode 支持系数制、金额制、人工确认三种模式;等级规则配置了系数和固定金额,结果生成时自动换算绩效金额,并提供"薪资同步"状态位对接薪资模块。

    这套绩效系统是开源免费的吗?

    是。基于 RuoYi-Vue-Pro / Yudao 架构,后端 Spring Boot 3.5 + 前端 Vue3 + 工作流 Flowable,开源可商用,本地约 10 分钟即可启动。


    💡 想要体验 RuoYi Office 的强大功能?

    🌐 在线演示:http://ruoyioffice.com/web/(账号 admin / admin123)

    📦 源码仓库:GitHub | GitCode | Gitee

    💬 技术咨询:添加微信 17156169080,备注「RuoYi Office」

    ⭐ 如果觉得不错,请给个 Star 支持一下!

    赞(0)
    未经允许不得转载:171主机测评 » SpringBoot+Vue3 绩效管理系统设计:KPI/OKR + 360 评估 + 绩效校准与申诉全流程
    分享到: 更多 (0)

    评论 抢沙发

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