feat(优先级):维度权重可配置并即时重算
- 新表 user_priority_weights(每用户一行,默认 0.35/0.25/0.20/0.10/0.10) - PriorityWeightsService:读取/保存权重,权重和必须为 1,保存后重算全部任务 - TaskController:GET/PUT /tasks/priority-weights - CalculatedPriorityTool 支持自定义权重 - 修复 updateTask 不重算优先级的问题
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
package com.guo.learningprogresstracker.service;
|
||||
|
||||
import com.guo.learningprogresstracker.entity.UserPriorityWeightsEntity;
|
||||
import com.guo.learningprogresstracker.exception.ErrorParameterException;
|
||||
|
||||
/**
|
||||
* 优先级权重配置服务
|
||||
*/
|
||||
public interface PriorityWeightsService {
|
||||
|
||||
/**
|
||||
* 获取当前用户的权重配置,不存在时返回系统默认值
|
||||
*/
|
||||
UserPriorityWeightsEntity getWeights();
|
||||
|
||||
/**
|
||||
* 保存权重配置并重算当前用户全部任务的优先级。
|
||||
* 五项权重之和必须为 1(容差 0.001)。
|
||||
*/
|
||||
UserPriorityWeightsEntity saveWeights(UserPriorityWeightsEntity weights) throws ErrorParameterException;
|
||||
}
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
package com.guo.learningprogresstracker.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.guo.learningprogresstracker.dto.PriorityDto;
|
||||
import com.guo.learningprogresstracker.entity.TaskEntity;
|
||||
import com.guo.learningprogresstracker.entity.UserPriorityWeightsEntity;
|
||||
import com.guo.learningprogresstracker.exception.ErrorParameterException;
|
||||
import com.guo.learningprogresstracker.mapper.TasksMapper;
|
||||
import com.guo.learningprogresstracker.mapper.UserPriorityWeightsMapper;
|
||||
import com.guo.learningprogresstracker.service.PriorityWeightsService;
|
||||
import com.guo.learningprogresstracker.utils.CalculatedPriorityTool;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 优先级权重配置服务实现
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class PriorityWeightsServiceImpl implements PriorityWeightsService {
|
||||
|
||||
private static final double SUM_TOLERANCE = 0.001;
|
||||
|
||||
private final UserPriorityWeightsMapper weightsMapper;
|
||||
private final TasksMapper tasksMapper;
|
||||
|
||||
@Override
|
||||
public UserPriorityWeightsEntity getWeights() {
|
||||
UserPriorityWeightsEntity existing = weightsMapper.selectOne(
|
||||
Wrappers.<UserPriorityWeightsEntity>lambdaQuery().last("LIMIT 1"));
|
||||
return existing != null ? existing : UserPriorityWeightsEntity.defaults();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public UserPriorityWeightsEntity saveWeights(UserPriorityWeightsEntity weights) throws ErrorParameterException {
|
||||
validate(weights);
|
||||
|
||||
UserPriorityWeightsEntity existing = weightsMapper.selectOne(
|
||||
Wrappers.<UserPriorityWeightsEntity>lambdaQuery().last("LIMIT 1"));
|
||||
if (existing == null) {
|
||||
weightsMapper.insert(weights);
|
||||
} else {
|
||||
weights.setId(existing.getId());
|
||||
weightsMapper.updateById(weights);
|
||||
}
|
||||
|
||||
recalculateAllTasks(weights);
|
||||
return weights;
|
||||
}
|
||||
|
||||
/** 用新权重重算当前用户的全部任务优先级 */
|
||||
private void recalculateAllTasks(UserPriorityWeightsEntity weights) {
|
||||
List<TaskEntity> tasks = tasksMapper.selectList(Wrappers.lambdaQuery(TaskEntity.class));
|
||||
for (TaskEntity task : tasks) {
|
||||
PriorityDto dto = new PriorityDto();
|
||||
dto.setUrgency(orZero(task.getUrgency()));
|
||||
dto.setImportance(orZero(task.getImportance()));
|
||||
dto.setContentDifficulty(orZero(task.getContentDifficulty()));
|
||||
dto.setFutureValue(orZero(task.getFutureValue()));
|
||||
dto.setSubjectivePriority(orZero(task.getSubjectivePriority()));
|
||||
task.setCalculatedPriority(CalculatedPriorityTool.calculatedPriority(dto, weights));
|
||||
tasksMapper.updateById(task);
|
||||
}
|
||||
log.info("权重更新,已重算 {} 个任务的优先级", tasks.size());
|
||||
}
|
||||
|
||||
private void validate(UserPriorityWeightsEntity weights) throws ErrorParameterException {
|
||||
double[] values = {
|
||||
orZero(weights.getUrgencyWeight()),
|
||||
orZero(weights.getImportanceWeight()),
|
||||
orZero(weights.getContentDifficultyWeight()),
|
||||
orZero(weights.getFutureValueWeight()),
|
||||
orZero(weights.getSubjectivePriorityWeight())};
|
||||
double sum = 0;
|
||||
for (double v : values) {
|
||||
if (v < 0 || v > 1) {
|
||||
throw new ErrorParameterException("权重必须在 0 到 1 之间");
|
||||
}
|
||||
sum += v;
|
||||
}
|
||||
if (Math.abs(sum - 1.0) > SUM_TOLERANCE) {
|
||||
throw new ErrorParameterException("五项权重之和必须为 1,当前为 " + sum);
|
||||
}
|
||||
}
|
||||
|
||||
private static int orZero(Integer v) {
|
||||
return v == null ? 0 : v;
|
||||
}
|
||||
|
||||
private static double orZero(Double v) {
|
||||
return v == null ? 0 : v;
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@ import com.guo.learningprogresstracker.exception.NotFindEntitiesException;
|
||||
import com.guo.learningprogresstracker.mapStruct.RequestConvert;
|
||||
import com.guo.learningprogresstracker.mapStruct.TaskConvert;
|
||||
import com.guo.learningprogresstracker.mapper.TaskApplicationMapper;
|
||||
import com.guo.learningprogresstracker.service.PriorityWeightsService;
|
||||
import com.guo.learningprogresstracker.service.TasksService;
|
||||
import com.guo.learningprogresstracker.mapper.TasksMapper;
|
||||
import com.guo.learningprogresstracker.utils.CalculatedPriorityTool;
|
||||
@@ -42,6 +43,8 @@ public class TasksServiceImpl extends ServiceImpl<TasksMapper, TaskEntity>
|
||||
|
||||
private final TaskApplicationMapper taskApplicationMapper;
|
||||
|
||||
private final PriorityWeightsService priorityWeightsService;
|
||||
|
||||
@Override
|
||||
public Page<TaskInfo> taskList(Integer pageNum, Integer pageSize) {
|
||||
Page<TaskEntity> page = tasksMapper.selectPage(new Page<TaskEntity>(pageNum, pageSize),
|
||||
@@ -62,7 +65,7 @@ public class TasksServiceImpl extends ServiceImpl<TasksMapper, TaskEntity>
|
||||
|
||||
task.setTaskNum(GenerateNumTool.generateNum("TASK"));
|
||||
PriorityDto priorityDto = RequestConvert.MAPPER.taskRequestToPriorityDto(taskRequest);
|
||||
task.setCalculatedPriority(CalculatedPriorityTool.calculatedPriority(priorityDto));
|
||||
task.setCalculatedPriority(CalculatedPriorityTool.calculatedPriority(priorityDto, priorityWeightsService.getWeights()));
|
||||
this.save(task);
|
||||
return task.getTaskNum();
|
||||
}
|
||||
@@ -87,6 +90,9 @@ public class TasksServiceImpl extends ServiceImpl<TasksMapper, TaskEntity>
|
||||
throw new IllegalArgumentException("任务ID格式错误: " + taskId);
|
||||
}
|
||||
taskEntity.setId(id);
|
||||
// 维度数据可能变化,更新时重算优先级
|
||||
PriorityDto priorityDto = RequestConvert.MAPPER.taskRequestToPriorityDto(updatedTask);
|
||||
taskEntity.setCalculatedPriority(CalculatedPriorityTool.calculatedPriority(priorityDto, priorityWeightsService.getWeights()));
|
||||
this.updateById(taskEntity);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user