qiangdanxitong/扣分逻辑说明.md

10 KiB
Raw Permalink Blame History

由壹点「视觉需求」系统扣分逻辑说明

一、当前系统扣分机制概述

系统采用按比例扣分的机制,扣分主要包含两部分:

  1. 延误扣分 - 任务超时完成或进行中任务已超时
  2. 进度未更新扣分 - 设计师未按时更新任务进度

二、延误扣分计算规则

1. 扣分公式

延误扣分 = 任务积分 × 延误工作小时数 × 扣分比例(%)

重要说明:

  • 延误工作小时数:只计算工作时间内的延误,非工作时间不计入(工作时间默认为 9:00-18:00,可在系统设置中配置)
  • 扣分比例:默认为 1%(即每延误1个工作小时,扣任务积分的1%)
  • 扣分上限:单个任务的扣分不能超过该任务的积分

2. 扣分比例配置

配置级别 说明
默认值 1%(每延误1小时扣任务积分的1%)
部门配置 可在部门目标积分设置中配置 deductionRate 字段
继承规则 三级部门继承二级部门的配置,如果二级部门未配置则使用默认值

3. 扣分场景

场景A:已完成任务延误扣分

适用条件:

  • 任务状态为 completed(已完成)
  • 完成时间晚于截止时间

计算方式:

延误小时数 = 工作时间计算器.计算延误小时(截止时间, 实际完成时间)
扣分 = 任务积分 × 延误小时数 × 扣分比例 / 100

场景B:进行中任务延误扣分

适用条件:

  • 任务状态为 in_progress(进行中)
  • 当前时间已超过截止时间

计算方式:

延误小时数 = 工作时间计算器.计算延误小时(截止时间, 当前时间)
扣分 = 任务积分 × 延误小时数 × 扣分比例 / 100

注意:进行中任务的延误扣分是实时计算的,会随着时间推移而增加。

4. 主任务与子任务扣分

系统同时计算主任务和子任务的延误扣分:

任务类型 截止时间来源 完成时间来源
主任务 task.deadline 字段 task.actualEndTime 字段
子任务 根据 createTime + estimatedHours 计算 taskItem.completeTime 字段

5. 扣分计算示例

示例1:任务按时完成

  • 任务积分:10分
  • 截止时间:2026-01-15 18:00
  • 完成时间:2026-01-15 17:30
  • 延误扣分:0分(未延误)

示例2:任务延误2小时

  • 任务积分:10分
  • 截止时间:2026-01-15 16:00
  • 完成时间:2026-01-15 18:00
  • 延误小时数:2小时(工作时间内)
  • 扣分比例:1%
  • 延误扣分:10 × 2 × 1% = 0.20分

示例3:任务延误跨天

  • 任务积分:20分
  • 截止时间:2026-01-15 17:00
  • 完成时间:2026-01-16 11:00
  • 延误工作小时数:1小时(15日17:00-18:00)+ 2小时(16日9:00-11:00)= 3小时
  • 扣分比例:1%
  • 延误扣分:20 × 3 × 1% = 0.60分

示例4:延误扣分达到上限

  • 任务积分:5分
  • 延误小时数:1000小时
  • 理论扣分:5 × 1000 × 1% = 50分
  • 实际扣分:5分(不能超过任务积分)

三、进度未更新扣分

1. 触发条件

  • 设计师每日 17:30 后首次登录需要更新进行中任务的进度
  • 如果未更新进度,系统将记录扣分

2. 扣分记录

  • 存储在 progress_deduction_log 表中
  • 按月汇总计入设计师的总扣分

3. 查询方式

SELECT SUM(deduction_amount) 
FROM progress_deduction_log 
WHERE user_id = ? 
  AND YEAR(deduction_date) = ? 
  AND MONTH(deduction_date) = ?

四、净积分计算

计算公式

总扣分 = 延误扣分 + 进度未更新扣分
净积分 = 获得积分 - 总扣分
如果净积分 < 0,则净积分 = 0

数据展示

在数据分析页面的设计师绩效排行榜中:

  • 获得积分:当月完成的所有任务(主任务+子任务)的积分总和
  • 延误扣分:当月所有任务的延误扣分总和
  • 净积分:获得积分 - 延误扣分(最小为0)

五、任务截止时间计算

1. 计算公式

截止时间 = 接单时间 + 预估工时(只计算工作时间段)

核心原则:截止时间的计算只累加工作时间段内的小时数,非工作时间(下班后、周末)自动跳过。

2. 计算逻辑详解

步骤1:确定起始点

接单时间 起始点处理
在工作时间内(9:00-18:00) 从接单时间开始计算
在上班前(如 8:00) 从当天 9:00 开始计算
在下班后(如 19:00) 从次日 9:00 开始计算

步骤2:累加工时

从起始点开始,逐步累加工作小时数:

  1. 计算当天剩余工作时间
  2. 如果当天工作时间足够,直接加上剩余工时
  3. 如果当天工作时间不够,移动到下一个工作日继续累加

3. 计算示例

示例1:当天可完成

接单时间:2026-01-15 10:00(周三)
预估工时:5小时
当天剩余工作时间:18:00 - 10:00 = 8小时 ✓ 足够

截止时间 = 10:00 + 5小时 = 2026-01-15 15:00

示例2:需要跨天

接单时间:2026-01-15 16:00(周三)
预估工时:5小时
当天剩余工作时间:18:00 - 16:00 = 2小时 ✗ 不够

计算过程:
- 第1天(周三):消耗 2小时,剩余 3小时
- 第2天(周四):从 9:00 开始,消耗 3小时

截止时间 = 2026-01-16 12:00

示例3:下班后接单

接单时间:2026-01-15 19:00(周三,下班后)
预估工时:3小时

计算过程:
- 起始点移动到次日 9:00
- 从 2026-01-16 09:00 开始计算

截止时间 = 2026-01-16 12:00

示例4:跨多天

接单时间:2026-01-15 16:00(周三)
预估工时:12小时
当天剩余工作时间:18:00 - 16:00 = 2小时 ✗ 不够

计算过程:
- 第1天(周三):消耗 2小时,剩余 10小时
- 第2天(周四):消耗 9小时(9:00-18:00),剩余 1小时
- 第3天(周五):从 9:00 开始,消耗 1小时

截止时间 = 2026-01-17 10:00(周五)

注意:当前系统按每天 9:00-18:00 计算工作时间,周六周日也按正常工作日计算,暂未配置节假日跳过功能。

4. 主任务与子任务的区别

任务类型 截止时间设置方式 说明
主任务 发布时直接设置 deadline 由任务发布者手动设置
子任务 系统自动计算 接单时间 + 预估工时

子任务截止时间触发时机

子任务的截止时间在以下场景自动计算:

  1. 接单部门审核通过时 - 子任务状态变为 in_progress
  2. 设计师接单时 - 从任务大厅抢单

5. 代码实现

核心方法:WorkHoursCalculator.calculateDeadline()

/**
 * 计算截止时间(只计算工作时间段)
 * @param startTime 开始时间(接单时间)
 * @param workHours 需要的工作小时数
 * @return 截止时间
 */
public LocalDateTime calculateDeadline(LocalDateTime startTime, BigDecimal workHours) {
    // 1. 获取工作时间配置(默认 9:00-18:00)
    // 2. 如果开始时间不在工作时间内,移动到下一个工作时段
    // 3. 循环累加工时,只在工作时间段内计算
    // 4. 返回最终截止时间
}

调用位置:

  • TaskService.updatePipelineSubTasksForAssigned() - 审核通过时设置
  • TaskItemService.approveTaskItemGroup() - 指派设计师时设置

六、工作时间配置

1. 配置位置

系统设置 → 工作时间配置

2. 配置项

配置键 说明 默认值
work_hours.start_time 上班开始时间 09:00
work_hours.end_time 下班结束时间 18:00

3. 影响范围

  • 任务截止时间计算
  • 延误小时数计算(只计算工作时间内的延误)
  • 延误扣分计算

七、代码位置参考

核心扣分计算

  • 文件:backend/src/main/java/com/designhub/service/AnalyticsService.java
  • 方法:getDesignerPerformance()
  • 扣分比例获取:getDeductionRate() 方法(第1325行)

工作时间计算器

  • 文件:backend/src/main/java/com/designhub/util/WorkHoursCalculator.java
  • 截止时间计算:calculateDeadline() 方法
  • 延误小时计算:calculateDelayHours() 方法

进度未更新扣分

  • 记录表:progress_deduction_log
  • 汇总查询:ProgressDeductionLogMapper.sumMonthlyDeduction()

八、扣分规则对比(历史参考)

当前实现(按比例扣分)

扣分 = 任务积分 × 延误工作小时数 × 扣分比例(1%)
扣分上限 = 任务积分

优点:

  • 与任务价值挂钩,公平合理
  • 扣分上限明确,不会出现扣分超过任务价值的情况
  • 只计算工作时间,更加人性化

历史设计(按等级固定扣分,已废弃)

延误程度 延误时长 扣分规则
轻微延误 < 2小时 每小时扣2分
一般延误 2-8小时 每小时扣3分
严重延误 8-24小时 每小时扣5分
重大延误 > 24小时 基础50分+每天10分

注意:此规则定义在 DelayPenaltyService.java 中,但当前数据分析页面未使用。


九、常见问题

Q1:为什么扣分等于获得积分?

原因:扣分达到上限(任务积分)

示例:

  • 任务积分:10分
  • 延误100小时
  • 理论扣分:10 × 100 × 1% = 10分
  • 实际扣分:10分(达到上限)

Q2:非工作时间(下班后)延误怎么计算?

原因:系统只计算工作时间内的延误(9:00-18:00)

示例:

  • 截止时间:周三 17:00
  • 完成时间:周四 11:00
  • 延误工作小时:1小时(周三 17:00-18:00)+ 2小时(周四 9:00-11:00)= 3小时
  • 晚上 18:00 到次日 9:00 的时间不计入延误

注意:当前系统周六周日也按正常工作日计算,暂未配置周末跳过功能。

Q3:子任务没有设置截止时间怎么计算?

方式:根据子任务的创建时间 + 预估工时自动计算截止时间

子任务截止时间 = 创建时间 + 预估工时(按工作时间计算)

文档更新时间:2026-01-15 文档版本:v2.1