package cn.com.qmth.scancentral.service.impl; import cn.com.qmth.scancentral.dao.OmrGroupDao; import cn.com.qmth.scancentral.entity.OmrGroupEntity; import cn.com.qmth.scancentral.entity.OmrTaskEntity; import cn.com.qmth.scancentral.enums.ConditionType; import cn.com.qmth.scancentral.enums.LockType; import cn.com.qmth.scancentral.enums.Stage; import cn.com.qmth.scancentral.enums.TaskStatus; import cn.com.qmth.scancentral.model.OmrCondition; import cn.com.qmth.scancentral.service.OmrGroupService; import cn.com.qmth.scancentral.service.OmrTaskService; import cn.com.qmth.scancentral.service.StudentPaperService; import cn.com.qmth.scancentral.util.BatchSetDataUtil; import cn.com.qmth.scancentral.vo.OmrConditionVo; import cn.com.qmth.scancentral.vo.OmrGroupVo; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.qmth.boot.core.concurrent.service.ConcurrentService; import com.qmth.boot.core.exception.ParameterException; import com.qmth.boot.core.exception.ReentrantException; import com.qmth.boot.core.exception.StatusException; import org.apache.commons.collections4.CollectionUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; @Service public class OmrGroupServiceImpl extends ServiceImpl implements OmrGroupService { protected static Logger log = LoggerFactory.getLogger(OmrGroupService.class); @Autowired private ConcurrentService concurrentService; @Autowired private OmrTaskService taskService; @Autowired private StudentPaperService studentPaperService; @Transactional @Override public void deleteById(Long id) { taskService.deleteByGroupId(id); this.removeById(id); } @Transactional @Override public void resetById(Long id) { OmrGroupEntity group = this.getById(id); if (group == null) { throw new ParameterException("分组不存在"); } taskService.resetByGroup(group); } @Override public void buildTaskById(Long groupId) { OmrGroupEntity group = this.getById(groupId); long start = System.currentTimeMillis(); List studentIds = studentPaperService.findStudentIdByExamId(group.getExamId()); long end = System.currentTimeMillis(); if (CollectionUtils.isEmpty(studentIds)) { log.info("OmrGroup[" + groupId + "] get studentIds finish | time cost(s):" + ((end - start) / 1000) + " | count:0"); return; } log.info("OmrGroup[" + groupId + "] get studentIds finish | time cost(s):" + ((end - start) / 1000) + " | count:" + studentIds.size()); new BatchSetDataUtil() { @Override protected void setData(List dataList) { buildTaskByStudent(group, dataList); } }.setDataForBatch(studentIds, 1000); } private void buildTaskByStudent(OmrGroupEntity group, List studentIds) { if (CollectionUtils.isEmpty(studentIds)) { return; } List saveList = new ArrayList(); for (Long studentId : studentIds) { try { concurrentService.getLock(LockType.STUDENT + "-" + studentId).lock(); List task = taskService.buildTask(group, studentId); if (task != null && !task.isEmpty()) { saveList.addAll(task); } } finally { concurrentService.getLock(LockType.STUDENT + "-" + studentId).unlock(); } } taskService.saveBatch(saveList); this.updateTotalCount(group.getId()); } @Override public List listByExamId(Long examId) { QueryWrapper wrapper = new QueryWrapper<>(); LambdaQueryWrapper lw = wrapper.lambda(); lw.eq(OmrGroupEntity::getExamId, examId); List groups = this.list(wrapper); List list = new ArrayList(); for (OmrGroupEntity group : groups) { OmrGroupVo groupVo = new OmrGroupVo(); groupVo.setId(group.getId()); List conditions = new ArrayList(); for (OmrCondition c : group.getConditions()) { conditions.add(new OmrConditionVo(c)); } groupVo.setConditions(conditions); groupVo.setStage(group.getStage()); groupVo.setFixed(group.getFixed()); groupVo.setBuilding( !concurrentService.getSemaphore(LockType.OMR_GROUP_BUILD + "-" + group.getId()).isAvailable()); groupVo.setDeleting( !concurrentService.getSemaphore(LockType.OMR_GROUP_DELETE + "-" + group.getId()).isAvailable()); groupVo.setReseting( !concurrentService.getSemaphore(LockType.OMR_GROUP_RESET + "-" + group.getId()).isAvailable()); groupVo.setTotalCount(group.getTotalCount()); groupVo.setFinishCount( taskService.getCountByExamAndGroupAndStatus(examId, group.getId(), TaskStatus.PROCESSED)); groupVo.setUnarbitrateCount( taskService.getCountByExamAndGroupAndStatus(examId, group.getId(), TaskStatus.WAIT_ARBITRATE)); groupVo.setArbitratedCount( taskService.getCountByExamAndGroupAndStatus(examId, group.getId(), TaskStatus.ARBITRATED)); groupVo.setUpdateTime(group.getUpdateTime()); list.add(groupVo); } return list; } @Transactional @Override public void updateStage(Long id, Long userId) { OmrGroupEntity group = this.getById(id); if (group == null) { throw new ParameterException("分组不存在"); } if (!Stage.FIRST.equals(group.getStage())) { throw new StatusException("分组不在第一阶段,无法切换"); } if (group.getTotalCount() == 0) { throw new StatusException("分组下没有任务,无法切换"); } Integer finishCount = taskService.getCountByExamAndGroupAndStatus(group.getExamId(), id, TaskStatus.PROCESSED, TaskStatus.ARBITRATED); if (group.getTotalCount() - finishCount != 0) { throw new StatusException("识别对照任务未完成,无法切换"); } group.setStage(Stage.SECOND); group.setUpdaterId(userId); group.setUpdateTime(System.currentTimeMillis()); this.saveOrUpdate(group); taskService.waitingByGroupToggle(id); } @Override public OmrGroupEntity save(Long id, Long examId, List conditions, Long userId) { if (examId == null) { throw new ParameterException("examId不能为空"); } if (conditions == null || conditions.isEmpty()) { throw new ParameterException("识别对照条件不能为空"); } for (OmrCondition omrCondition : conditions) { if (ConditionType.FILL_SUSPECT.equals(omrCondition.getCode())) { throw new ParameterException("识别对照条件不能重复"); } if (ConditionType.QUESTION_SINGLE_BLANK.equals(omrCondition.getCode()) || ConditionType.QUESTION_MULTI_BLANK.equals(omrCondition.getCode()) || ConditionType.SELECTIVE_EXCEED.equals(omrCondition.getCode()) || ConditionType.SELECTIVE_BLANK.equals(omrCondition.getCode())) { if (omrCondition.getValue() == null) { throw new ParameterException("参数不能为空"); } if (omrCondition.getValue() < 0) { throw new ParameterException("参数不能小于0"); } } } checkOmrCondition(id, examId, conditions); if (id != null) { OmrGroupEntity group = this.getById(id); if (group.getFixed()) { throw new ParameterException("默认分组不能修改"); } if (group.getTotalCount() != null && group.getTotalCount() > 0) { throw new ParameterException("已生成任务的分组不能修改"); } if (concurrentService.getLock(LockType.OMR_GROUP + "-" + id).tryLock()) { group.setConditions(conditions); group.setUpdaterId(userId); group.setUpdateTime(System.currentTimeMillis()); this.saveOrUpdate(group); concurrentService.getLock(LockType.OMR_GROUP + "-" + id).unlock(); return group; } else { throw new ReentrantException("该分组数据操作繁忙,请稍后重试"); } } else { OmrGroupEntity group = new OmrGroupEntity(); group.setExamId(examId); group.setConditions(conditions); group.setCreateTime(System.currentTimeMillis()); group.setFixed(false); group.setStage(Stage.FIRST); group.setTotalCount(0); group.setCreatorId(userId); group.setCreateTime(System.currentTimeMillis()); this.save(group); return group; } } @Override public List findByExamIdAndFixed(Long examId, Boolean fixed) { QueryWrapper wrapper = new QueryWrapper<>(); LambdaQueryWrapper lw = wrapper.lambda(); lw.eq(OmrGroupEntity::getExamId, examId); lw.eq(OmrGroupEntity::getFixed, fixed); return baseMapper.selectList(wrapper); } private void checkOmrCondition(Long id, Long examId, List conditions) { List list = findByExamId(examId); if (CollectionUtils.isEmpty(list)) { return; } Set codes = new HashSet<>(); for (OmrCondition oc : conditions) { codes.add(oc.getCode().name()); } for (OmrGroupEntity g : list) { for (OmrCondition oc : g.getConditions()) { if (codes.contains(oc.getCode().name()) && (id == null || g.getId().longValue() != id.longValue())) { throw new ParameterException("已存在识别对照条件"); } } } } private List findByExamId(Long examId) { QueryWrapper wrapper = new QueryWrapper<>(); LambdaQueryWrapper lw = wrapper.lambda(); lw.eq(OmrGroupEntity::getExamId, examId); return baseMapper.selectList(wrapper); } @Transactional @Override public void updateTotalCount(Long id) { if (id == null) { throw new ParameterException("Id不能为空"); } baseMapper.updateTotalCount(id); } @Override public void addFixOmrCondition(Long userId, Long examId) { OmrGroupEntity group = new OmrGroupEntity(); group.setExamId(examId); List conditions = new ArrayList(); OmrCondition omrCondition = new OmrCondition(); omrCondition.setCode(ConditionType.FILL_SUSPECT); conditions.add(omrCondition); group.setConditions(conditions); group.setCreateTime(System.currentTimeMillis()); group.setFixed(true); group.setStage(Stage.FIRST); group.setTotalCount(0); group.setCreatorId(userId); group.setCreateTime(System.currentTimeMillis()); this.save(group); } @Transactional @Override public void updateTotalCountByExamId(Long examId) { List list = this.findByExamId(examId); for (OmrGroupEntity omrGroupEntity : list) { this.updateTotalCount(omrGroupEntity.getId()); } } }