6 changed files with 164 additions and 7 deletions
@ -0,0 +1,5 @@ |
|||||
|
package com.project.question.domain.service; |
||||
|
|
||||
|
public interface QuestionInventoryDomainService { |
||||
|
void checkAndReplenish(Long taskId) throws Exception; |
||||
|
} |
||||
@ -0,0 +1,105 @@ |
|||||
|
package com.project.question.domain.service.impl; |
||||
|
|
||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
||||
|
import com.project.question.domain.entity.TaskKnowledgeClusterEntity; |
||||
|
import com.project.question.domain.entity.TaskKnowledgePointEntity; |
||||
|
import com.project.question.domain.enums.QuestionSourceTypeEnum; |
||||
|
import com.project.question.domain.service.GenerateQuestionDomainService; |
||||
|
import com.project.question.domain.service.QuestionInventoryDomainService; |
||||
|
import com.project.question.mapper.QuestionKpRelMapper; |
||||
|
import com.project.question.mapper.TaskKnowledgeClusterMapper; |
||||
|
import com.project.question.mapper.TaskKnowledgePointMapper; |
||||
|
import com.project.task.domain.entity.TaskEntity; |
||||
|
import com.project.task.domain.enums.QuestionTypeEnum; |
||||
|
import com.project.task.mapper.TaskMapper; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
|
||||
|
import java.util.Date; |
||||
|
import java.util.List; |
||||
|
|
||||
|
@Service |
||||
|
@Slf4j |
||||
|
public class QuestionInventoryDomainServiceImpl implements QuestionInventoryDomainService { |
||||
|
@Autowired |
||||
|
private TaskKnowledgePointMapper taskKpMapper; |
||||
|
|
||||
|
@Autowired |
||||
|
private TaskKnowledgeClusterMapper clusterMapper; |
||||
|
|
||||
|
@Autowired |
||||
|
private QuestionKpRelMapper questionKpMapper; |
||||
|
|
||||
|
@Autowired |
||||
|
private TaskMapper taskMapper; |
||||
|
|
||||
|
@Autowired |
||||
|
private GenerateQuestionDomainService generateQuestionDomainService; |
||||
|
|
||||
|
@Override |
||||
|
public void checkAndReplenish(Long taskId) { |
||||
|
TaskEntity task = taskMapper.selectById(taskId); |
||||
|
if (task == null || task.getEndTime().before(new Date())) { |
||||
|
return; |
||||
|
} |
||||
|
int u = (task.getParticipantNum() == null ? 0 : task.getParticipantNum()) |
||||
|
- (task.getPassNum() == null ? 0 : task.getPassNum()); |
||||
|
if (u <= 0) { |
||||
|
return; |
||||
|
} |
||||
|
int watermark = (int) Math.ceil(1.0 * u); |
||||
|
int targetLine = (int) Math.ceil(1.2 * u); |
||||
|
// 针对每个知识点遍历每种题型
|
||||
|
List<TaskKnowledgePointEntity> kpList = taskKpMapper.selectList( |
||||
|
new LambdaQueryWrapper<TaskKnowledgePointEntity>().eq(TaskKnowledgePointEntity::getTaskId , taskId)); |
||||
|
for (TaskKnowledgePointEntity kp : kpList) { |
||||
|
for (QuestionTypeEnum questionType : QuestionTypeEnum.values()) { |
||||
|
checkAndProduce(kp.getId() , questionType , watermark , targetLine); |
||||
|
} |
||||
|
} |
||||
|
// 针对每一个簇
|
||||
|
List<TaskKnowledgeClusterEntity> clusterList = clusterMapper.selectList( |
||||
|
new LambdaQueryWrapper<TaskKnowledgeClusterEntity>().eq(TaskKnowledgeClusterEntity::getTaskId, taskId)); |
||||
|
|
||||
|
for (TaskKnowledgeClusterEntity cluster : clusterList) { |
||||
|
int w = cluster.getClusterSize(); |
||||
|
// 簇水位线: 1.0 * U * W
|
||||
|
int clusterWatermark = watermark * w; |
||||
|
// 簇目标线: 1.2 * U * W
|
||||
|
int clusterTargetLine = targetLine * w; |
||||
|
|
||||
|
checkClusterProduce(cluster.getId(), clusterWatermark, clusterTargetLine); |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 单知识点补货判定 |
||||
|
*/ |
||||
|
private void checkAndProduce(Long kpId, QuestionTypeEnum type, int watermark , int targetLine) { |
||||
|
int currentStock = questionKpMapper.countAvailableByKp(kpId, type.getValue()); |
||||
|
|
||||
|
if (currentStock < watermark) { |
||||
|
int gap = targetLine - currentStock; |
||||
|
log.info(">>> [自动补库] KP: {}, 题型: {}, 当前库存: {}, 需补货: {}", kpId, type.getDescription(), currentStock, gap); |
||||
|
// 触发异步生产逻辑 (内部带 30 分钟冷却锁)
|
||||
|
generateQuestionDomainService.produce(kpId , type , QuestionSourceTypeEnum.Single_Concept , gap); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 知识点簇补货判定 |
||||
|
*/ |
||||
|
private void checkClusterProduce(Long clusterId, int watermark, int targetLine) { |
||||
|
int currentStock = questionKpMapper.countAvailableByCluster(clusterId); |
||||
|
|
||||
|
if (currentStock < watermark) { |
||||
|
int gap = targetLine - currentStock; |
||||
|
log.info(">>> [自动补库] 簇: {}, 类型: 复合多选, 当前库存: {}, 需补货: {}", clusterId, currentStock, gap); |
||||
|
// 簇维度触发,触发异步生产逻辑
|
||||
|
generateQuestionDomainService.produce(clusterId , QuestionTypeEnum.MULTIPLE_CHOICE , QuestionSourceTypeEnum.Single_Concept , gap); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
Loading…
Reference in new issue