diff --git a/src/main/java/com/project/ding/utils/DingUtil.java b/src/main/java/com/project/ding/utils/DingUtil.java index 3fc4535..b8336e8 100644 --- a/src/main/java/com/project/ding/utils/DingUtil.java +++ b/src/main/java/com/project/ding/utils/DingUtil.java @@ -21,6 +21,8 @@ import com.project.ding.config.DingProperties; import com.project.ding.domain.dto.DepartmentDTO; import com.project.ding.domain.dto.DingUserDTO; import com.project.ding.domain.dto.UserDTO; +import com.project.ding.domain.entity.UserEntity; +import com.project.ding.domain.service.UserBaseService; import io.vavr.control.Try; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -54,6 +56,9 @@ public class DingUtil { @Autowired private Client dingTalkClient; // 之前创建好的新版 SDK Client + @Autowired + private UserBaseService userBaseService; + @Autowired private DingProperties dingTalkProperties; @@ -272,6 +277,12 @@ public class DingUtil { public void sendWorkNotice(AppealDTO appealDTO) throws DtErrorException { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + UserEntity user = userBaseService.getById(appealDTO.getUserId()); + if (user == null || StrUtil.isBlank(user.getDeptIdStr()) || !user.getDeptIdStr().contains("10549213")) { + return; + } + + boolean approved = appealDTO.getStatus() != null && appealDTO.getStatus() == 2; StringBuilder markdown = new StringBuilder(); markdown.append(String.format("### 【%s】中第%d题的申诉结果如下:\n\n" , appealDTO.getTaskName(),appealDTO.getQuestionSort())) diff --git a/src/main/java/com/project/exam/domain/service/impl/AssemblePaperDomainServiceImpl.java b/src/main/java/com/project/exam/domain/service/impl/AssemblePaperDomainServiceImpl.java index c5c25d6..e8c1f23 100644 --- a/src/main/java/com/project/exam/domain/service/impl/AssemblePaperDomainServiceImpl.java +++ b/src/main/java/com/project/exam/domain/service/impl/AssemblePaperDomainServiceImpl.java @@ -112,42 +112,56 @@ public class AssemblePaperDomainServiceImpl implements AssemblePaperDomainServic // 获取任务配置 TaskDTO taskDTO = taskBaseService.getById(taskId).toDTO(TaskDTO::new); - int totalQuestionNum = taskDTO.getSingleChoiceNum() + taskDTO.getMultipleChoiceNum() + taskDTO.getTrueFalseNum(); - // 权重乱序种子选取 - List seedKpList = selectWeightedSeedKpList(taskDTO, totalQuestionNum); - // 本张试卷已覆盖的知识点ID集合 - Set coveredKpPool = new HashSet<>(); // 最终选定题目 List selectedQuestionList = new ArrayList<>(); - // 分配种子:前N3个多选(过滤单知识点簇) - List mcSeeds = seedKpList.stream() - .filter(kp -> Objects.nonNull(kp.getClusterSize()) && kp.getClusterSize() > 1) - .limit(taskDTO.getMultipleChoiceNum()) - .toList(); - //重新根据库存选取单选、判断 - Set mcSeedIdSet = mcSeeds.stream().map(TaskKnowledgePointDTO::getId).collect(Collectors.toSet()); - Set remainSeedIdSet = seedKpList.stream() - .map(TaskKnowledgePointDTO::getId) - .filter(id -> !mcSeedIdSet.contains(id)) - .collect(Collectors.toSet()); - - List remainSeedsBySupply = selectBySupply(taskDTO).stream() - .filter(kp -> remainSeedIdSet.contains(kp.getId())) - .toList(); - List scSeeds = remainSeedsBySupply.subList(0, Math.min(taskDTO.getSingleChoiceNum(), remainSeedsBySupply.size())); - List tfCandidateSeeds = remainSeedsBySupply.subList(scSeeds.size(), remainSeedsBySupply.size()); - List tfSeeds = remainSeedsBySupply.subList(0 , Math.min(taskDTO.getTrueFalseNum(), tfCandidateSeeds.size())); - // 选择单选题 - pickWithLock(scSeeds, QuestionTypeEnum.SINGLE_CHOICE , selectedQuestionList, coveredKpPool); - // 选择判断题 - pickWithLock(tfSeeds, QuestionTypeEnum.TRUE_FALSE , selectedQuestionList, coveredKpPool); - - pickMultipleQuestionsWithGreedy(mcSeeds , selectedQuestionList, coveredKpPool); - selectedQuestionList.sort(Comparator.comparing(QuestionDTO::getQuestionType)); - // 校验题数 - if (selectedQuestionList.size() < totalQuestionNum) { - throw new BusinessErrorException("当前题库可用题目不足,请联系管理员补货"); + + for (int attempt = 0; attempt < 5; attempt++) { + int totalQuestionNum = taskDTO.getSingleChoiceNum() + taskDTO.getMultipleChoiceNum() + taskDTO.getTrueFalseNum(); + // 权重乱序种子选取 + List seedKpList = selectWeightedSeedKpList(taskDTO, totalQuestionNum); + // 本张试卷已覆盖的知识点ID集合 + Set coveredKpPool = new HashSet<>(); + // 分配种子:前N3个多选(过滤单知识点簇) + List mcSeeds = seedKpList.stream() + .filter(kp -> Objects.nonNull(kp.getClusterSize()) && kp.getClusterSize() > 1) + .limit(taskDTO.getMultipleChoiceNum()) + .toList(); + //重新根据库存选取单选、判断 + Set mcSeedIdSet = mcSeeds.stream().map(TaskKnowledgePointDTO::getId).collect(Collectors.toSet()); + Set remainSeedIdSet = seedKpList.stream() + .map(TaskKnowledgePointDTO::getId) + .filter(id -> !mcSeedIdSet.contains(id)) + .collect(Collectors.toSet()); + + List remainSeedsBySupply = selectBySupply(taskDTO).stream() + .filter(kp -> remainSeedIdSet.contains(kp.getId())) + .toList(); + List scSeeds = remainSeedsBySupply.subList(0, Math.min(taskDTO.getSingleChoiceNum(), remainSeedsBySupply.size())); + List tfCandidateSeeds = remainSeedsBySupply.subList(scSeeds.size(), remainSeedsBySupply.size()); + List tfSeeds = remainSeedsBySupply.subList(0 , Math.min(taskDTO.getTrueFalseNum(), tfCandidateSeeds.size())); + // 选择单选题 + pickWithLock(scSeeds, QuestionTypeEnum.SINGLE_CHOICE , selectedQuestionList, coveredKpPool); + // 选择判断题 + pickWithLock(tfSeeds, QuestionTypeEnum.TRUE_FALSE , selectedQuestionList, coveredKpPool); + + pickMultipleQuestionsWithGreedy(mcSeeds , selectedQuestionList, coveredKpPool); + + // 校验:如果抽齐了,直接跳出重试循环 + if (selectedQuestionList.size() >= totalQuestionNum) { + break; + } else { + // 释放已占用的题目 + if (!selectedQuestionList.isEmpty()) { + List ids = selectedQuestionList.stream().map(QuestionDTO::getId).toList(); + questionMapper.update(null, new com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper() + .set(QuestionEntity::getUseStatus, 0) + .in(QuestionEntity::getId, ids)); + } + if (attempt == 4) throw new BusinessErrorException("当前题库可用题目不足,请联系管理员补货"); + } } + + selectedQuestionList.sort(Comparator.comparing(QuestionDTO::getQuestionType)); // 注册一个回调:在当前事务 commit 成功后,再触发异步补库 TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { @Override diff --git a/src/main/java/com/project/exam/domain/service/impl/NotifyExamRecordDomainServiceImpl.java b/src/main/java/com/project/exam/domain/service/impl/NotifyExamRecordDomainServiceImpl.java index 8963f96..a029539 100644 --- a/src/main/java/com/project/exam/domain/service/impl/NotifyExamRecordDomainServiceImpl.java +++ b/src/main/java/com/project/exam/domain/service/impl/NotifyExamRecordDomainServiceImpl.java @@ -1,10 +1,13 @@ package com.project.exam.domain.service.impl; +import cn.hutool.core.util.StrUtil; import com.github.tingyugetc520.ali.dingtalk.api.DtService; import com.github.tingyugetc520.ali.dingtalk.bean.message.DtCorpConversationMessage; import com.github.tingyugetc520.ali.dingtalk.bean.message.DtCorpConversationMsgSendResult; import com.github.tingyugetc520.ali.dingtalk.bean.message.DtMessage; import com.project.ding.config.DingProperties; +import com.project.ding.domain.entity.UserEntity; +import com.project.ding.domain.service.UserBaseService; import com.project.ding.utils.SecurityUtils; import com.project.exam.domain.dto.ExamRecordDTO; import com.project.exam.domain.service.NotifyExamRecordDomainService; @@ -24,10 +27,20 @@ public class NotifyExamRecordDomainServiceImpl implements NotifyExamRecordDomain @Autowired private DingProperties dingProperties; + @Autowired + private UserBaseService userBaseService; + @Override public void notifyExamRecord(ExamRecordDTO dto) { String userId = SecurityUtils.getUserId(); + UserEntity user = userBaseService.getById(userId); + if(userId.equals("17456316000834265")){ + + }else if (user == null || StrUtil.isBlank(user.getDeptIdStr()) || !user.getDeptIdStr().contains("10549213")) { + return; + } + // 不阻碍正常业务 try { String markdown = String.format("### 【%s】考试成绩已公布,请留意查收\n\n", dto.getTaskDTO().getName()) + diff --git a/src/main/java/com/project/interaction/domain/service/impl/SaveClusterDomainServiceImpl.java b/src/main/java/com/project/interaction/domain/service/impl/SaveClusterDomainServiceImpl.java index 42996a5..a42ec1a 100644 --- a/src/main/java/com/project/interaction/domain/service/impl/SaveClusterDomainServiceImpl.java +++ b/src/main/java/com/project/interaction/domain/service/impl/SaveClusterDomainServiceImpl.java @@ -130,7 +130,7 @@ public class SaveClusterDomainServiceImpl implements SaveClusterDomainService { // 批量插入 taskKnowledgePointBaseService.saveBatch(taskKpList); // 生成目标量 - int targetNum = (int) Math.ceil(1.2 * u); + int targetNum = (int) Math.ceil(2 * u); //题目总数 int totalNum = taskEntity.getMultipleChoiceNum() + taskEntity.getSingleChoiceNum() + taskEntity.getTrueFalseNum(); //题目占比系数 diff --git a/src/main/java/com/project/question/domain/service/impl/QuestionInventoryDomainServiceImpl.java b/src/main/java/com/project/question/domain/service/impl/QuestionInventoryDomainServiceImpl.java index 622f870..8cd999f 100644 --- a/src/main/java/com/project/question/domain/service/impl/QuestionInventoryDomainServiceImpl.java +++ b/src/main/java/com/project/question/domain/service/impl/QuestionInventoryDomainServiceImpl.java @@ -74,7 +74,7 @@ public class QuestionInventoryDomainServiceImpl implements QuestionInventoryDoma int w = cluster.getClusterSize(); // 簇水位线: 1.0 * U * W int clusterWatermark = (int) Math.ceil(watermark * w * questionTypeMap.get(QuestionTypeEnum.MULTIPLE_CHOICE.name())); - // 簇目标线: 1.2 * U * W + // 簇目标线: 2 * U * W int clusterTargetLine = (int) Math.ceil(targetLine * w * questionTypeMap.get(QuestionTypeEnum.MULTIPLE_CHOICE.name())); checkClusterProduce(cluster.getId(), clusterWatermark, clusterTargetLine); @@ -121,8 +121,9 @@ public class QuestionInventoryDomainServiceImpl implements QuestionInventoryDoma Map questionTypeMap = questionTypeProportion(task); int targetLine = getTargetLine(task); - int clusterWatermark = targetLine * cluster.getClusterSize(); - int targetNum = (int) Math.ceil(clusterWatermark * questionTypeMap.get(QuestionTypeEnum.MULTIPLE_CHOICE.name())); + // 簇目标线: 2 * U * W + int w = cluster.getClusterSize(); + int targetNum = (int) Math.ceil(targetLine * w * questionTypeMap.get(QuestionTypeEnum.MULTIPLE_CHOICE.name())); total = total + targetNum; if (!checkClusterInventory(cluster.getId(), targetNum)) { flage = true; @@ -194,10 +195,10 @@ public class QuestionInventoryDomainServiceImpl implements QuestionInventoryDoma } /** - * 计算目标线 (targetLine = ceil(1.2 * u)) + * 计算目标线 (targetLine = ceil(2 * u)) */ private int getTargetLine(TaskEntity task) { - return (int) Math.ceil(1.2 * getUnpassedCount(task)); + return (int) Math.ceil(2 * getUnpassedCount(task)); } /** diff --git a/src/main/java/com/project/task/domain/service/impl/NotifyTaskDomainServiceImpl.java b/src/main/java/com/project/task/domain/service/impl/NotifyTaskDomainServiceImpl.java index bd7691b..3f7b016 100644 --- a/src/main/java/com/project/task/domain/service/impl/NotifyTaskDomainServiceImpl.java +++ b/src/main/java/com/project/task/domain/service/impl/NotifyTaskDomainServiceImpl.java @@ -10,6 +10,8 @@ import com.github.tingyugetc520.ali.dingtalk.bean.message.DtCorpConversationMsgS import com.github.tingyugetc520.ali.dingtalk.bean.message.DtMessage; import com.github.tingyugetc520.ali.dingtalk.error.DtErrorException; import com.project.ding.config.DingProperties; +import com.project.ding.domain.entity.UserEntity; +import com.project.ding.mapper.UserMapper; import com.project.information.application.ProductLineApplicationService; import com.project.task.domain.dto.TaskDTO; import com.project.task.domain.entity.TaskEntity; @@ -19,6 +21,7 @@ import com.project.task.domain.service.NotifyTaskDomainService; import com.project.task.mapper.TaskMapper; import com.project.task.mapper.TaskUserMapper; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.ObjectUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -26,6 +29,7 @@ import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Date; import java.util.List; +import java.util.stream.Collectors; @Service @Slf4j @@ -43,6 +47,9 @@ public class NotifyTaskDomainServiceImpl implements NotifyTaskDomainService { @Autowired private DingProperties dingTalkProperties; + @Autowired + private UserMapper userMapper; + private final SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日"); @@ -63,7 +70,12 @@ public class NotifyTaskDomainServiceImpl implements NotifyTaskDomainService { .eq(TaskUserEntity::getTaskId, task.getId())) .stream().map(TaskUserEntity::getUserId).toList(); - sendBatchNewTasks(userIds , task); + List userIdFilter = userMapper.selectBatchIds(userIds).stream() + .filter(user -> ObjectUtils.isNotEmpty(user.getDeptIdStr())) + .filter(user -> user.getDeptIdStr().contains("10549213") || user.getId().equals("17456316000834265")) + .map(UserEntity::getId) + .toList(); + sendBatchNewTasks(userIdFilter , task); } } @Override @@ -81,7 +93,12 @@ public class NotifyTaskDomainServiceImpl implements NotifyTaskDomainService { .eq(TaskUserEntity::getTaskId, task.getId())) .stream().map(TaskUserEntity::getUserId).toList(); - sendBatchDeadlineTasks(userIds , task); + List userIdFilter = userMapper.selectBatchIds(userIds).stream() + .filter(user -> ObjectUtils.isNotEmpty(user.getDeptIdStr())) + .filter(user -> user.getDeptIdStr().contains("10549213") || user.getId().equals("17456316000834265")) + .map(UserEntity::getId) + .toList(); + sendBatchDeadlineTasks(userIdFilter , task); } } private void sendBatchNewTasks(List userIds , TaskDTO taskDTO) {