fix: 按完成时间归属月度积分

确保主任务/子任务的月度积分按完成时间入账,并补充修正脚本。
This commit is contained in:
Your Name 2026-02-04 18:55:48 +08:00
parent 96e8040af5
commit 67b8cb7991
4 changed files with 115 additions and 20 deletions

View File

@ -1,6 +1,5 @@
package com.designhub.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.designhub.entity.Department;
import com.designhub.entity.DeptMonthlyScore;
import com.designhub.mapper.DepartmentMapper;
@ -26,13 +25,13 @@ public class DeptMonthlyScoreService {
private final DepartmentMapper departmentMapper;
/**
* 获取或创建当月积分记录
* 获取或创建指定月份积分记录(基于完成时间)
*/
@Transactional(rollbackFor = Exception.class)
public DeptMonthlyScore getOrCreateCurrentMonth(Long deptId) {
LocalDateTime now = LocalDateTime.now();
int year = now.getYear();
int month = now.getMonthValue();
public DeptMonthlyScore getOrCreateMonth(Long deptId, LocalDateTime scoreTime) {
LocalDateTime targetTime = scoreTime != null ? scoreTime : LocalDateTime.now();
int year = targetTime.getYear();
int month = targetTime.getMonthValue();
DeptMonthlyScore record = deptMonthlyScoreMapper.getByDeptAndMonth(deptId, year, month);
if (record == null) {
@ -53,20 +52,28 @@ public class DeptMonthlyScoreService {
record.setCompletedTaskCount(0);
record.setDelayedTaskCount(0);
record.setTotalDelayHours(BigDecimal.ZERO);
record.setCreateTime(now);
record.setUpdateTime(now);
record.setCreateTime(targetTime);
record.setUpdateTime(targetTime);
deptMonthlyScoreMapper.insert(record);
}
return record;
}
/**
* 获取或创建当月积分记录
*/
@Transactional(rollbackFor = Exception.class)
public DeptMonthlyScore getOrCreateCurrentMonth(Long deptId) {
return getOrCreateMonth(deptId, LocalDateTime.now());
}
/**
* 增加部门获得积分(任务完成时调用)
*/
@Transactional(rollbackFor = Exception.class)
public void addEarnedScore(Long deptId, BigDecimal score, boolean isDelayed, BigDecimal delayHours) {
DeptMonthlyScore record = getOrCreateCurrentMonth(deptId);
public void addEarnedScore(Long deptId, BigDecimal score, boolean isDelayed, BigDecimal delayHours, LocalDateTime scoreTime) {
DeptMonthlyScore record = getOrCreateMonth(deptId, scoreTime);
// 增加获得积分
record.setEarnedScore(record.getEarnedScore().add(score));
@ -87,12 +94,20 @@ public class DeptMonthlyScoreService {
deptMonthlyScoreMapper.updateById(record);
}
/**
* 增加部门获得积分(兼容旧调用,使用当前时间)
*/
@Transactional(rollbackFor = Exception.class)
public void addEarnedScore(Long deptId, BigDecimal score, boolean isDelayed, BigDecimal delayHours) {
addEarnedScore(deptId, score, isDelayed, delayHours, LocalDateTime.now());
}
/**
* 增加部门扣除积分(延误扣分时调用)
*/
@Transactional(rollbackFor = Exception.class)
public void addDeductedScore(Long deptId, BigDecimal deductedScore) {
DeptMonthlyScore record = getOrCreateCurrentMonth(deptId);
public void addDeductedScore(Long deptId, BigDecimal deductedScore, LocalDateTime scoreTime) {
DeptMonthlyScore record = getOrCreateMonth(deptId, scoreTime);
record.setDeductedScore(record.getDeductedScore().add(deductedScore));
// 重新计算净积分
@ -102,12 +117,20 @@ public class DeptMonthlyScoreService {
deptMonthlyScoreMapper.updateById(record);
}
/**
* 增加部门扣除积分(兼容旧调用,使用当前时间)
*/
@Transactional(rollbackFor = Exception.class)
public void addDeductedScore(Long deptId, BigDecimal deductedScore) {
addDeductedScore(deptId, deductedScore, LocalDateTime.now());
}
/**
* 扣除部门获得积分(删除已完成任务时调用,用于回退积分)
*/
@Transactional(rollbackFor = Exception.class)
public void deductEarnedScore(Long deptId, BigDecimal score) {
DeptMonthlyScore record = getOrCreateCurrentMonth(deptId);
public void deductEarnedScore(Long deptId, BigDecimal score, LocalDateTime scoreTime) {
DeptMonthlyScore record = getOrCreateMonth(deptId, scoreTime);
// 扣除获得积分(不能小于0)
BigDecimal newEarnedScore = record.getEarnedScore().subtract(score);
@ -131,6 +154,14 @@ public class DeptMonthlyScoreService {
log.info("已扣除部门月度积分: deptId={}, score={}, newEarnedScore={}", deptId, score, newEarnedScore);
}
/**
* 扣除部门获得积分(兼容旧调用,使用当前时间)
*/
@Transactional(rollbackFor = Exception.class)
public void deductEarnedScore(Long deptId, BigDecimal score) {
deductEarnedScore(deptId, score, LocalDateTime.now());
}
/**
* 获取部门当月积分
*/

View File

@ -818,7 +818,8 @@ public class TaskItemService {
item.getReceiverDeptId(),
item.getTotalScore(),
isDelayed,
delayHours
delayHours,
item.getCompleteTime()
);
log.info("🎉 子任务 {} 积分已发放: deptId={}, score={}, isDelayed={}, delayHours={}",

View File

@ -3684,15 +3684,16 @@ public class TaskService {
if (task.getReceiverDeptId() != null) {
try {
deptMonthlyScoreService.addEarnedScore(
task.getReceiverDeptId(),
task.getReceiverDeptId(),
task.getScoreReward() != null ? task.getScoreReward() : BigDecimal.ZERO,
isDelayed,
delayHours
delayHours,
completeTime
);
// 如果有延误扣分,单独记录扣除
if (deductedScore.compareTo(BigDecimal.ZERO) > 0) {
deptMonthlyScoreService.addDeductedScore(task.getReceiverDeptId(), deductedScore);
deptMonthlyScoreService.addDeductedScore(task.getReceiverDeptId(), deductedScore, completeTime);
}
log.info("更新部门月度积分: deptId={}, earned={}, deducted={}",
@ -4275,7 +4276,11 @@ public class TaskService {
log.info("已回退主任务积分: deptId={}, score={}", task.getReceiverDeptId(), task.getScoreReward());
// 回退部门月度积分统计
deptMonthlyScoreService.deductEarnedScore(task.getReceiverDeptId(), task.getScoreReward());
deptMonthlyScoreService.deductEarnedScore(
task.getReceiverDeptId(),
task.getScoreReward(),
task.getCompleteTime()
);
log.info("已回退部门月度积分: deptId={}, score={}", task.getReceiverDeptId(), task.getScoreReward());
} else {
log.warn("部门积分池不存在,跳过主任务积分回退: deptId={}", task.getReceiverDeptId());
@ -4304,7 +4309,11 @@ public class TaskService {
item.getItemNo(), item.getReceiverDeptId(), item.getTotalScore());
// 回退部门月度积分统计
deptMonthlyScoreService.deductEarnedScore(item.getReceiverDeptId(), item.getTotalScore());
deptMonthlyScoreService.deductEarnedScore(
item.getReceiverDeptId(),
item.getTotalScore(),
item.getCompleteTime()
);
} else {
log.warn("部门积分池不存在,跳过子任务积分回退: itemNo={}, deptId={}", item.getItemNo(), item.getReceiverDeptId());
}

View File

@ -0,0 +1,54 @@
-- 按完成时间修正部门月度积分(earned_score / completed_task_count)
-- 注意:本脚本不会修改 deducted_score / 延误统计,仅重算 earned_score 与 net_score
-- 1) 设定需要修正的年月
SET @year = 2026;
SET @month = 2;
SET @start = STR_TO_DATE(CONCAT(@year, '-', LPAD(@month, 2, '0'), '-01 00:00:00'), '%Y-%m-%d %H:%i:%s');
SET @end = DATE_ADD(@start, INTERVAL 1 MONTH);
-- 2) 汇总该月完成的主任务/子任务积分(主任务排除流水线任务)
CREATE TEMPORARY TABLE tmp_monthly_earned AS
SELECT dept_id, SUM(score) AS earned_score, COUNT(*) AS completed_task_count
FROM (
SELECT t.receiver_dept_id AS dept_id, t.score_reward AS score
FROM task t
WHERE t.status = 'completed'
AND t.receiver_dept_id IS NOT NULL
AND t.score_reward IS NOT NULL
AND t.score_reward > 0
AND (t.is_pipeline IS NULL OR t.is_pipeline = 0)
AND t.complete_time >= @start AND t.complete_time < @end
UNION ALL
SELECT ti.receiver_dept_id AS dept_id, ti.total_score AS score
FROM task_item ti
WHERE ti.status = 'completed'
AND ti.receiver_dept_id IS NOT NULL
AND ti.total_score IS NOT NULL
AND ti.total_score > 0
AND ti.complete_time >= @start AND ti.complete_time < @end
) u
GROUP BY dept_id;
-- 3) 更新已有记录
UPDATE dept_monthly_score d
JOIN tmp_monthly_earned e
ON d.dept_id = e.dept_id AND d.year = @year AND d.month = @month
SET d.earned_score = e.earned_score,
d.completed_task_count = e.completed_task_count,
d.net_score = e.earned_score - d.deducted_score,
d.update_time = NOW();
-- 4) 插入缺失记录
INSERT INTO dept_monthly_score
(dept_id, dept_name, year, month, earned_score, deducted_score, net_score,
completed_task_count, delayed_task_count, total_delay_hours, create_time, update_time)
SELECT e.dept_id, dept.dept_name, @year, @month, e.earned_score, 0,
e.earned_score, e.completed_task_count, 0, 0, NOW(), NOW()
FROM tmp_monthly_earned e
JOIN department dept ON dept.id = e.dept_id
LEFT JOIN dept_monthly_score d
ON d.dept_id = e.dept_id AND d.year = @year AND d.month = @month
WHERE d.id IS NULL;
DROP TEMPORARY TABLE tmp_monthly_earned;