package cn.iocoder.yudao.module.mes.service.safety; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.mes.controller.admin.safety.vo.training.MesSafetyTrainingAttendeeSaveReqVO; import cn.iocoder.yudao.module.mes.controller.admin.safety.vo.training.MesSafetyTrainingPageReqVO; import cn.iocoder.yudao.module.mes.controller.admin.safety.vo.training.MesSafetyTrainingSaveReqVO; import cn.iocoder.yudao.module.mes.dal.dataobject.safety.MesSafetyTrainingAttendeeDO; import cn.iocoder.yudao.module.mes.dal.dataobject.safety.MesSafetyTrainingDO; import cn.iocoder.yudao.module.mes.dal.mysql.safety.MesSafetyTrainingAttendeeMapper; import cn.iocoder.yudao.module.mes.dal.mysql.safety.MesSafetyTrainingMapper; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import java.math.BigDecimal; import java.math.RoundingMode; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; import java.util.Objects; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; /** * 安全生产 - 培训 Service 实现 * * @author 超级管理员 */ @Service @Validated public class MesSafetyTrainingServiceImpl implements MesSafetyTrainingService { @Resource private MesSafetyTrainingMapper trainingMapper; @Resource private MesSafetyTrainingAttendeeMapper attendeeMapper; @Override public PageResult getTrainingPage(MesSafetyTrainingPageReqVO pageReqVO) { return trainingMapper.selectPage(pageReqVO); } @Override public MesSafetyTrainingDO getTraining(Long id) { return trainingMapper.selectById(id); } @Override public Long createTraining(MesSafetyTrainingSaveReqVO createReqVO) { validateCodeUnique(null, createReqVO.getCode()); validateTimeRange(createReqVO); MesSafetyTrainingDO training = BeanUtils.toBean(createReqVO, MesSafetyTrainingDO.class); training.setAttendeeCount(0); training.setSignedCount(0); trainingMapper.insert(training); return training.getId(); } @Override public void updateTraining(MesSafetyTrainingSaveReqVO updateReqVO) { validateTrainingExists(updateReqVO.getId()); validateCodeUnique(updateReqVO.getId(), updateReqVO.getCode()); validateTimeRange(updateReqVO); MesSafetyTrainingDO updateObj = BeanUtils.toBean(updateReqVO, MesSafetyTrainingDO.class); // 统计字段由参训人员维护,不通过此接口修改 updateObj.setAttendeeCount(null); updateObj.setSignedCount(null); updateObj.setAvgScore(null); trainingMapper.updateById(updateObj); } @Override @Transactional(rollbackFor = Exception.class) public void deleteTraining(Long id) { validateTrainingExists(id); // 级联删除参训记录,避免孤儿数据 attendeeMapper.deleteByTrainingId(id); trainingMapper.deleteById(id); } @Override public MesSafetyTrainingDO validateTrainingExists(Long id) { if (id == null) { throw exception(MES_SAFETY_TRAINING_NOT_EXISTS); } MesSafetyTrainingDO training = trainingMapper.selectById(id); if (training == null) { throw exception(MES_SAFETY_TRAINING_NOT_EXISTS); } return training; } @Override public List getAttendeeList(Long trainingId) { return attendeeMapper.selectListByTrainingId(trainingId); } @Override @Transactional(rollbackFor = Exception.class) public void saveAttendees(Long trainingId, List attendees) { validateTrainingExists(trainingId); // 全量覆盖:先清空再插入,保证与前端列表一致 attendeeMapper.deleteByTrainingId(trainingId); if (attendees != null && !attendees.isEmpty()) { List list = new ArrayList<>(attendees.size()); for (MesSafetyTrainingAttendeeSaveReqVO vo : attendees) { MesSafetyTrainingAttendeeDO attendee = BeanUtils.toBean(vo, MesSafetyTrainingAttendeeDO.class); attendee.setId(null); attendee.setTrainingId(trainingId); if (attendee.getSignStatus() == null) { attendee.setSignStatus(MesSafetyTrainingAttendeeDO.SIGN_NONE); } if (attendee.getPassed() == null) { attendee.setPassed(MesSafetyTrainingAttendeeDO.PASS_NONE); } list.add(attendee); } attendeeMapper.insertBatch(list); } refreshStatistics(trainingId); } @Override public void updateAttendee(MesSafetyTrainingAttendeeSaveReqVO reqVO) { if (reqVO.getId() == null) { throw exception(MES_SAFETY_TRAINING_ATTENDEE_NOT_EXISTS); } MesSafetyTrainingAttendeeDO exists = attendeeMapper.selectById(reqVO.getId()); if (exists == null) { throw exception(MES_SAFETY_TRAINING_ATTENDEE_NOT_EXISTS); } MesSafetyTrainingAttendeeDO updateObj = new MesSafetyTrainingAttendeeDO(); updateObj.setId(reqVO.getId()); updateObj.setSignStatus(reqVO.getSignStatus()); updateObj.setSignTime(reqVO.getSignTime()); updateObj.setScore(reqVO.getScore()); updateObj.setPassed(reqVO.getPassed()); updateObj.setRemark(reqVO.getRemark()); attendeeMapper.updateById(updateObj); refreshStatistics(exists.getTrainingId()); } @Override public void deleteAttendee(Long id) { MesSafetyTrainingAttendeeDO exists = attendeeMapper.selectById(id); if (exists == null) { throw exception(MES_SAFETY_TRAINING_ATTENDEE_NOT_EXISTS); } attendeeMapper.deleteById(id); refreshStatistics(exists.getTrainingId()); } @Override public void refreshStatistics(Long trainingId) { Long total = attendeeMapper.selectCountByTrainingId(trainingId); Long signed = attendeeMapper.selectCountSignedByTrainingId(trainingId); List list = attendeeMapper.selectListByTrainingId(trainingId); // 平均分只统计有成绩的 BigDecimal sum = BigDecimal.ZERO; int scored = 0; for (MesSafetyTrainingAttendeeDO a : list) { if (a.getScore() != null) { sum = sum.add(a.getScore()); scored++; } } BigDecimal avg = scored > 0 ? sum.divide(BigDecimal.valueOf(scored), 2, RoundingMode.HALF_UP) : null; MesSafetyTrainingDO updateObj = new MesSafetyTrainingDO(); updateObj.setId(trainingId); updateObj.setAttendeeCount(total == null ? 0 : total.intValue()); updateObj.setSignedCount(signed == null ? 0 : signed.intValue()); updateObj.setAvgScore(avg); trainingMapper.updateById(updateObj); } /** * 校验培训时间区间 */ private void validateTimeRange(MesSafetyTrainingSaveReqVO reqVO) { LocalDateTime start = reqVO.getStartTime(); LocalDateTime end = reqVO.getEndTime(); if (start != null && end != null && !end.isAfter(start)) { throw exception(MES_SAFETY_TRAINING_TIME_INVALID); } } private void validateCodeUnique(Long id, String code) { MesSafetyTrainingDO exists = trainingMapper.selectByCode(code); if (exists == null) { return; } if (id == null || !Objects.equals(exists.getId(), id)) { throw exception(MES_SAFETY_TRAINING_CODE_DUPLICATE); } } }