package cn.com.qmth.mps.service.impl; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DuplicateKeyException; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.interceptor.TransactionAspectSupport; import org.springframework.web.multipart.MultipartFile; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.qmth.boot.core.collection.PageResult; import com.qmth.boot.core.exception.StatusException; import com.qmth.boot.tools.excel.ExcelReader; import com.qmth.boot.tools.excel.enums.ExcelType; import com.qmth.boot.tools.excel.model.DataMap; import cn.com.qmth.mps.bean.PaperDetail; import cn.com.qmth.mps.bean.PaperDetailUnit; import cn.com.qmth.mps.bean.User; import cn.com.qmth.mps.dao.PaperDao; import cn.com.qmth.mps.entity.CourseEntity; import cn.com.qmth.mps.entity.ExamEntity; import cn.com.qmth.mps.entity.PaperEntity; import cn.com.qmth.mps.enums.ExamStatus; import cn.com.qmth.mps.enums.Role; import cn.com.qmth.mps.service.CourseService; import cn.com.qmth.mps.service.ExamService; import cn.com.qmth.mps.service.PaperDetailService; import cn.com.qmth.mps.service.PaperGroupService; import cn.com.qmth.mps.service.PaperService; import cn.com.qmth.mps.util.BatchSetDataUtil; import cn.com.qmth.mps.util.Calculator; import cn.com.qmth.mps.util.PageUtil; import cn.com.qmth.mps.vo.exam.ExamPaperCountVo; import cn.com.qmth.mps.vo.paper.GroupCountVo; import cn.com.qmth.mps.vo.paper.PaperInfoVo; import cn.com.qmth.mps.vo.paper.PaperQuery; import cn.com.qmth.mps.vo.paper.PaperStructInfoVo; import cn.com.qmth.mps.vo.paper.PaperVo; import cn.com.qmth.mps.vo.paper.StructDomain; @Service public class PaperServiceImpl extends ServiceImpl implements PaperService { @Autowired private ExamService examService; @Autowired private CourseService courseService; @Autowired private PaperGroupService paperGroupService; @Autowired private PaperDetailService paperDetailService; @Transactional @Override public List importPaper(Long examId, User user, MultipartFile file) { ExamEntity exam = examService.getById(examId); if (exam == null) { throw new StatusException("未找到考试批次"); } if(!ExamStatus.EDIT.equals(exam.getExamStatus())) { throw new StatusException("考试未开放上报,不能设置结构信息或分组信息"); } if (!user.getRole().equals(Role.SUPER_ADMIN) && !user.getSchoolId().equals(exam.getSchoolId())) { throw new StatusException("没有权限"); } InputStream inputStream = null; try { inputStream = file.getInputStream(); List lineList = ExcelReader.create(ExcelType.XLSX, inputStream, 0).getDataMapList(); if (CollectionUtils.isEmpty(lineList)) { throw new StatusException("Excel无内容"); } if (1001 < lineList.size()) { throw new StatusException("数据行数不能超过1000"); } List failRecords = new ArrayList<>(); List ret = new ArrayList<>(); for (int i = 0; i < lineList.size(); i++) { DataMap line = lineList.get(i); StringBuilder msg = new StringBuilder(); PaperEntity imp = new PaperEntity(); imp.setTotalScore(0.0); imp.setObjectiveScore(0.0); imp.setSubjectiveScore(0.0); imp.setSchoolId(exam.getSchoolId()); imp.setGroupFinish(false); imp.setStructFinish(false); imp.setExamId(examId); String code = trimAndNullIfBlank(line.getValue(0)); if (StringUtils.isBlank(code)) { msg.append(" 科目代码不能为空"); } else if (code.length() > 20) { msg.append(" 科目代码不能超过20个字符"); } String name = trimAndNullIfBlank(line.getValue(1)); if (StringUtils.isBlank(name)) { msg.append(" 科目名称不能为空"); } else if (name.length() > 20) { msg.append(" 科目名称不能超过20个字符"); } if (msg.length() == 0) { CourseEntity course = courseService.saveOrGet(exam.getSchoolId(), code, name); imp.setCourseId(course.getId()); } if (msg.length() > 0) { failRecords.add(newError(i + 1, msg.toString())); } else { ret.add(imp); } } if (CollectionUtils.isNotEmpty(failRecords)) { return failRecords; } for (int i = 0; i < ret.size(); i++) { PaperEntity cur = ret.get(i); try { this.save(cur); } catch (DuplicateKeyException e) { failRecords.add(newError(i + 1, "科目已存在")); } catch (Exception e) { failRecords.add(newError(i + 1, "系统异常")); log.error("科目导入系统异常", e); } } if (CollectionUtils.isNotEmpty(failRecords)) { TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); } return failRecords; } catch (StatusException e) { throw e; } catch (Exception e) { throw new RuntimeException("系统错误", e); } finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { } } } } private String trimAndNullIfBlank(String s) { if (StringUtils.isBlank(s)) { return null; } return s.trim(); } private String newError(int lineNum, String msg) { return "第" + lineNum + "行" + msg; } @Override public List findPaperCount(List examIds) { return this.baseMapper.findPaperCount(examIds); } @Override public Integer findPaperCount(Long examId) { QueryWrapper wrapper = new QueryWrapper<>(); LambdaQueryWrapper lw = wrapper.lambda(); lw.eq(PaperEntity::getExamId, examId); return this.count(wrapper); } private PaperEntity findByExamAndCourse(Long examId, Long courseId) { QueryWrapper wrapper = new QueryWrapper<>(); LambdaQueryWrapper lw = wrapper.lambda(); lw.eq(PaperEntity::getExamId, examId); lw.eq(PaperEntity::getCourseId, courseId); return this.getOne(wrapper); } private PaperEntity saveOrGet(Long schoolId, Long examId, Long courseId) { PaperEntity ret = findByExamAndCourse(examId, courseId); if (ret != null) { return ret; } PaperEntity imp = new PaperEntity(); imp.setTotalScore(0.0); imp.setObjectiveScore(0.0); imp.setSubjectiveScore(0.0); imp.setSchoolId(schoolId); imp.setGroupFinish(false); imp.setCourseId(courseId); imp.setExamId(examId); imp.setStructFinish(true); this.save(imp); return imp; } @Override public PageResult page(PaperQuery query, User user) { if (query.getSchoolId() == null) { throw new StatusException("学校不能为空"); } if (!user.getRole().equals(Role.SUPER_ADMIN) && !user.getSchoolId().equals(query.getSchoolId())) { throw new StatusException("没有权限"); } IPage iPage = this.baseMapper.page(new Page(query.getPageNumber(), query.getPageSize()), query); if (CollectionUtils.isNotEmpty(iPage.getRecords())) { new BatchSetDataUtil() { @Override protected void setData(List dataList) { List paperIds = dataList.stream().map(dto -> dto.getId()).distinct() .collect(Collectors.toList()); List ret = paperGroupService.findGroupCount(paperIds); if (ret != null && ret.size() > 0) { Map countMap = new HashMap<>(); for (GroupCountVo item : ret) { countMap.put(item.getPaperId(), item.getGroupCount()); } for (PaperVo vo : dataList) { vo.setGroupCount(countMap.get(vo.getId())); } } } }.setDataForBatch(iPage.getRecords(), 20); for (PaperVo vo : iPage.getRecords()) { if(vo.getGroupCount()==null) { vo.setGroupCount(0); } } } return PageUtil.of(iPage); } @Override public List list(Long examId, User user) { ExamEntity exam = examService.getById(examId); if (exam == null) { throw new StatusException("未找到考试批次"); } if (!user.getRole().equals(Role.SUPER_ADMIN) && !user.getSchoolId().equals(exam.getSchoolId())) { throw new StatusException("没有权限"); } List ret=this.baseMapper.myPaperlist(examId,user.getId()); if (CollectionUtils.isNotEmpty(ret)) { new BatchSetDataUtil() { @Override protected void setData(List dataList) { List paperIds = dataList.stream().map(dto -> dto.getId()).distinct() .collect(Collectors.toList()); List ret = paperGroupService.findGroupCount(paperIds); if (ret != null && ret.size() > 0) { Map countMap = new HashMap<>(); for (GroupCountVo item : ret) { countMap.put(item.getPaperId(), item.getGroupCount()); } for (PaperVo vo : dataList) { vo.setGroupCount(countMap.get(vo.getId())); } } } }.setDataForBatch(ret, 20); } return ret; } @Override public PaperInfoVo info(Long id, User user) { PaperEntity paper = this.getById(id); if (paper == null) { throw new StatusException("未找到试卷结构信息"); } if (!user.getRole().equals(Role.SUPER_ADMIN) && !user.getSchoolId().equals(paper.getSchoolId())) { throw new StatusException("没有权限"); } PaperInfoVo vo = new PaperInfoVo(); BeanUtils.copyProperties(paper, vo); CourseEntity course = courseService.getById(vo.getCourseId()); vo.setCourseCode(course.getCode()); vo.setCourseName(course.getName()); vo.setStructInfo(paperDetailService.getStructInfo(vo.getId())); vo.setGroupInfo(paperGroupService.getGroupInfo(vo.getId())); return vo; } @Transactional @Override public List importSubjectStruct(Long examId, User user, MultipartFile file) { ExamEntity exam = examService.getById(examId); if (exam == null) { throw new StatusException("未找到考试批次"); } if(!ExamStatus.EDIT.equals(exam.getExamStatus())) { throw new StatusException("考试未开放上报,不能设置结构信息或分组信息"); } if (!user.getRole().equals(Role.SUPER_ADMIN) && !user.getSchoolId().equals(exam.getSchoolId())) { throw new StatusException("没有权限"); } InputStream inputStream = null; try { inputStream = file.getInputStream(); List lineList = ExcelReader.create(ExcelType.XLSX, inputStream, 0).getDataMapList(); if (CollectionUtils.isEmpty(lineList)) { throw new StatusException("Excel无内容"); } if (10001 < lineList.size()) { throw new StatusException("数据行数不能超过10000"); } List failRecords = new ArrayList<>(); List ret = new ArrayList<>(); for (int i = 0; i < lineList.size(); i++) { DataMap line = lineList.get(i); StringBuilder msg = new StringBuilder(); PaperStructInfoVo imp = new PaperStructInfoVo(); String code = trimAndNullIfBlank(line.getValue(0)); if (StringUtils.isBlank(code)) { msg.append(" 科目代码不能为空"); } else if (code.length() > 20) { msg.append(" 科目代码不能超过20个字符"); } imp.setCourseCode(code); String name = trimAndNullIfBlank(line.getValue(1)); if (StringUtils.isBlank(name)) { msg.append(" 科目名称不能为空"); } else if (name.length() > 20) { msg.append(" 科目名称不能超过20个字符"); } if (msg.length() == 0) { CourseEntity course = courseService.saveOrGet(exam.getSchoolId(), code, name); PaperEntity paper = saveOrGet(exam.getSchoolId(), examId, course.getId()); imp.setPaperId(paper.getId()); } String detailName = trimAndNullIfBlank(line.getValue(2)); if (StringUtils.isBlank(detailName)) { msg.append(" 大题名称不能为空"); } else if (detailName.length() > 50) { msg.append(" 大题名称不能超过50个字符"); } imp.setDetailName(detailName); String detailNumber = trimAndNullIfBlank(line.getValue(3)); if (StringUtils.isBlank(detailNumber)) { msg.append(" 大题号不能为空"); } else { try { int n = Integer.valueOf(detailNumber); if (n <= 0) { msg.append(" 大题号不能小于0"); } else { imp.setDetailNumber(n); } } catch (Exception e) { msg.append(" 大题号只能是整数"); } } String unitNumber = trimAndNullIfBlank(line.getValue(4)); if (StringUtils.isBlank(unitNumber)) { msg.append(" 小题号不能为空"); } else { try { int n = Integer.valueOf(unitNumber); if (n <= 0) { msg.append(" 小题号不能小于0"); } else { imp.setUnitNumber(n); } } catch (Exception e) { msg.append(" 小题号只能是整数"); } } String score = trimAndNullIfBlank(line.getValue(5)); if (StringUtils.isBlank(score)) { msg.append(" 小题满分不能为空"); } else { try { Double n = Double.valueOf(score); if (n <= 0) { msg.append(" 小题满分不能小于0"); } else { if (score.indexOf(".") < score.length() - 2) { msg.append("小题满分只能有一位小数"); } else { imp.setScore(n); } } } catch (Exception e) { msg.append(" 小题满分格式错误"); } } String scoreStep = trimAndNullIfBlank(line.getValue(6)); if (StringUtils.isBlank(scoreStep)) { msg.append(" 间隔分不能为空"); } else { try { Double n = Double.valueOf(scoreStep); if (n <= 0) { msg.append(" 间隔分不能小于0"); } else { if (scoreStep.indexOf(".") < scoreStep.length() - 2) { msg.append("小间隔分只能有一位小数"); } else { imp.setScoreStep(n); } } } catch (Exception e) { msg.append(" 间隔分格式错误"); } } if (msg.length() > 0) { failRecords.add(newError(i + 1, msg.toString())); } else { ret.add(imp); } } if (CollectionUtils.isNotEmpty(failRecords)) { return failRecords; } this.saveStruct(ret, user, failRecords); if (CollectionUtils.isNotEmpty(failRecords)) { TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); } return failRecords; } catch (StatusException e) { throw e; } catch (Exception e) { throw new RuntimeException("系统错误", e); } finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { } } } } private void saveStruct(List cards, User user, List failRecords) { Map map=new HashMap<>(); for(PaperStructInfoVo vo:cards) { map.put(vo.getPaperId(), vo.getCourseCode()); } List ces = getBeans(cards); checkStruct(ces, failRecords,map); if (CollectionUtils.isNotEmpty(failRecords)) { return; } for (StructDomain domain : ces) { try { paperDetailService.structSubmit(domain, user); } catch (StatusException e) { failRecords.add("科目:"+map.get(domain.getPaperId())+" "+e.getMessage()); } catch (Exception e) { throw new RuntimeException("系统错误", e); } } } private void checkStruct(List ces, List failRecords,Map courseMap) { for (StructDomain card : ces) { int lastDetailNum = 0; for (PaperDetail detail : card.getStructInfo()) { if (detail.getNumber() - lastDetailNum != 1) { failRecords.add( "科目:" + courseMap.get(card.getPaperId()) + ",大题号" + detail.getNumber() + "错误"); } lastDetailNum = detail.getNumber(); int lastUnitNum = 0; for (PaperDetailUnit unit : detail.getUnits()) { if (unit.getNumber() - lastUnitNum != 1) { failRecords.add("科目:" + courseMap.get(card.getPaperId()) + ",大题号:" + detail.getNumber() + ",小题号" + unit.getNumber() + "错误"); } lastUnitNum = unit.getNumber(); } } } } private List getBeans(List cards) { cards.sort(new Comparator() { @Override public int compare(PaperStructInfoVo o1, PaperStructInfoVo o2) { long c1 = o1.getPaperId(); long c2 = o2.getPaperId(); if (c1 < c2) { return -1; } else if (c1 > c2) { return 1; } else { int indx1 = o1.getDetailNumber(); int indx2 = o2.getDetailNumber(); if (indx1 < indx2) { return -1; } else if (indx1 > indx2) { return 1; } else { int u1 = o1.getUnitNumber(); int u2 = o2.getUnitNumber(); if (u1 < u2) { return -1; } else if (u1 > u2) { return 1; } else { return 0; } } } } }); List ces = new ArrayList<>(); StructDomain curCard = null; PaperDetail curDetail = null; for (PaperStructInfoVo info : cards) { if (curCard == null || !info.getPaperId().equals(curCard.getPaperId())) { curCard = new StructDomain(); curCard.setPaperId(info.getPaperId()); curCard.setStructInfo(new ArrayList<>()); ces.add(curCard); curDetail = null; } if (curDetail == null || !info.getDetailNumber().equals(curDetail.getNumber())) { curDetail = new PaperDetail(); curDetail.setName(info.getDetailName()); curDetail.setNumber(info.getDetailNumber()); curDetail.setUnits(new ArrayList<>()); curCard.getStructInfo().add(curDetail); } PaperDetailUnit unit = new PaperDetailUnit(); curDetail.getUnits().add(unit); unit.setNumber(info.getUnitNumber()); unit.setScore(info.getScore()); unit.setScoreStep(info.getScoreStep()); } for (StructDomain sd : ces) { setTotalScore(sd); } return ces; } private void setTotalScore(StructDomain domain) { double total = 0.0; for (PaperDetail detial : domain.getStructInfo()) { for (PaperDetailUnit unit : detial.getUnits()) { total = Calculator.add(total, unit.getScore(), 1); } } domain.setTotalScore(total); } @Override public List subjectiveList(PaperQuery query, User user) { if (query.getSchoolId() == null) { throw new StatusException("学校不能为空"); } if (!user.getRole().equals(Role.SUPER_ADMIN) && !user.getSchoolId().equals(query.getSchoolId())) { throw new StatusException("没有权限"); } List ret = this.baseMapper.subjectiveList(query); if (CollectionUtils.isNotEmpty(ret)) { } return ret; } }