package cn.iocoder.yudao.module.mes.service.safety;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
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.train.*;
import cn.iocoder.yudao.module.mes.dal.dataobject.safety.SafetyAccidentDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.safety.SafetyDrillDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.safety.SafetyTrainingDO;
import cn.iocoder.yudao.module.mes.dal.mysql.safety.SafetyAccidentMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.safety.SafetyDrillMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.safety.SafetyTrainingMapper;
import cn.iocoder.yudao.module.mes.enums.safety.*;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.mes.enums.SafetyErrorCodeConstants.*;
/**
* 安全生产 - 培训、演练、事故登记 Service
*
*
三类记录统一归档,供标准化台账导出使用。
*
* @author 超级管理员
*/
@Service
@Validated
public class SafetyTrainingService {
private static final DateTimeFormatter CODE_DATE = DateTimeFormatter.ofPattern("yyyyMMdd");
@Resource
private SafetyTrainingMapper trainingMapper;
@Resource
private SafetyRefResolver refResolver;
@Resource
private SafetyDrillMapper drillMapper;
@Resource
private SafetyAccidentMapper accidentMapper;
// ==================== 培训 ====================
public Long createTraining(SafetyTrainingSaveReqVO reqVO) {
reqVO.setId(null);
SafetyTrainingDO training = BeanUtils.toBean(reqVO, SafetyTrainingDO.class);
training.setTitle(StrUtil.trim(reqVO.getTitle()));
training.setTrainingType(StrUtil.blankToDefault(reqVO.getTrainingType(), SafetyTrainingTypeEnum.SAFETY.getType()));
training.setTrainerId(reqVO.getTrainerId());
training.setTrainer(reqVO.getTrainerId() == null ? ""
: refResolver.requireEmployee(reqVO.getTrainerId(), SAFETY_EMPLOYEE_REQUIRED).getName());
training.setParticipantCount(resolveCount(reqVO.getParticipantCount(), reqVO.getParticipants()));
training.setRemark(reqVO.getRemark() == null ? "" : reqVO.getRemark().trim());
trainingMapper.insert(training);
return training.getId();
}
public void updateTraining(SafetyTrainingSaveReqVO reqVO) {
validateTrainingExists(reqVO.getId());
SafetyTrainingDO training = BeanUtils.toBean(reqVO, SafetyTrainingDO.class);
training.setTitle(StrUtil.trim(reqVO.getTitle()));
training.setParticipantCount(resolveCount(reqVO.getParticipantCount(), reqVO.getParticipants()));
trainingMapper.updateById(training);
}
public void deleteTraining(Long id) {
validateTrainingExists(id);
trainingMapper.deleteById(id);
}
public SafetyTrainingDO getTraining(Long id) {
return validateTrainingExists(id);
}
public PageResult getTrainingPage(SafetyTrainingPageReqVO reqVO) {
return trainingMapper.selectPage(reqVO);
}
/**
* 事故的主数据引用:所属车间 + 登记人
*/
private void applyAccidentRefs(SafetyAccidentDO accident, SafetyAccidentSaveReqVO reqVO) {
accident.setWorkshopId(reqVO.getWorkshopId());
accident.setWorkshopName(reqVO.getWorkshopId() == null ? ""
: refResolver.requireWorkshop(reqVO.getWorkshopId()).getName());
accident.setReporterId(reqVO.getReporterId());
accident.setReporter(reqVO.getReporterId() == null ? ""
: refResolver.requireEmployee(reqVO.getReporterId(), SAFETY_EMPLOYEE_REQUIRED).getName());
}
/** 批量回填培训讲师最新姓名 */
public void fillTrainers(List trainings) {
if (CollUtil.isEmpty(trainings)) return;
var employeeMap = refResolver.employeeMap(trainings.stream().map(SafetyTrainingDO::getTrainerId).toList());
trainings.forEach(t -> {
var e = employeeMap.get(t.getTrainerId());
if (e != null) t.setTrainer(e.getName());
});
}
/** 批量回填演练组织人最新姓名 */
public void fillOrganizers(List drills) {
if (CollUtil.isEmpty(drills)) return;
var employeeMap = refResolver.employeeMap(drills.stream().map(SafetyDrillDO::getOrganizerId).toList());
drills.forEach(d -> {
var e = employeeMap.get(d.getOrganizerId());
if (e != null) d.setOrganizer(e.getName());
});
}
/** 批量回填事故的车间名与登记人姓名 */
public void fillAccidentRefs(List accidents) {
if (CollUtil.isEmpty(accidents)) return;
var workshopMap = refResolver.workshopMap(accidents.stream().map(SafetyAccidentDO::getWorkshopId).toList());
var employeeMap = refResolver.employeeMap(accidents.stream().map(SafetyAccidentDO::getReporterId).toList());
accidents.forEach(a -> {
var w = workshopMap.get(a.getWorkshopId());
if (w != null) a.setWorkshopName(w.getName());
var e = employeeMap.get(a.getReporterId());
if (e != null) a.setReporter(e.getName());
});
}
public static void fillTrainingDisplay(SafetyTrainingDO training, SafetyTrainingRespVO respVO) {
respVO.setTrainingTypeName(SafetyTrainingTypeEnum.getNameByType(training.getTrainingType()));
}
// ==================== 演练 ====================
public Long createDrill(SafetyDrillSaveReqVO reqVO) {
reqVO.setId(null);
SafetyDrillDO drill = BeanUtils.toBean(reqVO, SafetyDrillDO.class);
drill.setTitle(StrUtil.trim(reqVO.getTitle()));
drill.setDrillType(StrUtil.blankToDefault(reqVO.getDrillType(), SafetyDrillTypeEnum.FIRE.getType()));
drill.setOrganizerId(reqVO.getOrganizerId());
drill.setOrganizer(reqVO.getOrganizerId() == null ? ""
: refResolver.requireEmployee(reqVO.getOrganizerId(), SAFETY_EMPLOYEE_REQUIRED).getName());
drill.setParticipantCount(resolveCount(reqVO.getParticipantCount(), reqVO.getParticipants()));
drill.setRemark(reqVO.getRemark() == null ? "" : reqVO.getRemark().trim());
drillMapper.insert(drill);
return drill.getId();
}
public void updateDrill(SafetyDrillSaveReqVO reqVO) {
validateDrillExists(reqVO.getId());
SafetyDrillDO drill = BeanUtils.toBean(reqVO, SafetyDrillDO.class);
drill.setTitle(StrUtil.trim(reqVO.getTitle()));
drill.setParticipantCount(resolveCount(reqVO.getParticipantCount(), reqVO.getParticipants()));
drillMapper.updateById(drill);
}
public void deleteDrill(Long id) {
validateDrillExists(id);
drillMapper.deleteById(id);
}
public SafetyDrillDO getDrill(Long id) {
return validateDrillExists(id);
}
public PageResult getDrillPage(SafetyDrillPageReqVO reqVO) {
return drillMapper.selectPage(reqVO);
}
public static void fillDrillDisplay(SafetyDrillDO drill, SafetyDrillRespVO respVO) {
respVO.setDrillTypeName(SafetyDrillTypeEnum.getNameByType(drill.getDrillType()));
}
// ==================== 事故 ====================
public Long createAccident(SafetyAccidentSaveReqVO reqVO) {
reqVO.setId(null);
SafetyAccidentDO accident = BeanUtils.toBean(reqVO, SafetyAccidentDO.class);
accident.setCode(accidentMapper.selectNextCode("AC" + LocalDate.now().format(CODE_DATE)));
accident.setTitle(StrUtil.trim(reqVO.getTitle()));
accident.setLevel(StrUtil.blankToDefault(reqVO.getLevel(), SafetyAccidentLevelEnum.GENERAL.getLevel()));
accident.setStatus(StrUtil.blankToDefault(reqVO.getStatus(), SafetyAccidentStatusEnum.REPORTED.getStatus()));
applyAccidentRefs(accident, reqVO);
accident.setReportTime(reqVO.getReportTime() == null ? LocalDateTime.now() : reqVO.getReportTime());
accident.setRemark(reqVO.getRemark() == null ? "" : reqVO.getRemark().trim());
accidentMapper.insert(accident);
return accident.getId();
}
public void updateAccident(SafetyAccidentSaveReqVO reqVO) {
validateAccidentExists(reqVO.getId());
SafetyAccidentDO accident = BeanUtils.toBean(reqVO, SafetyAccidentDO.class);
accident.setCode(null);
applyAccidentRefs(accident, reqVO);
accidentMapper.updateById(accident);
}
public void deleteAccident(Long id) {
validateAccidentExists(id);
accidentMapper.deleteById(id);
}
public SafetyAccidentDO getAccident(Long id) {
return validateAccidentExists(id);
}
public PageResult getAccidentPage(SafetyAccidentPageReqVO reqVO) {
return accidentMapper.selectPage(reqVO);
}
public static void fillAccidentDisplay(SafetyAccidentDO accident, SafetyAccidentRespVO respVO) {
respVO.setAccidentTypeName(SafetyAccidentTypeEnum.getNameByType(accident.getAccidentType()));
respVO.setLevelName(SafetyAccidentLevelEnum.getNameByLevel(accident.getLevel()));
respVO.setStatusName(SafetyAccidentStatusEnum.getNameByStatus(accident.getStatus()));
}
// ==================== 台账导出用查询 ====================
public List listTrainingBetween(LocalDate begin, LocalDate end) {
return trainingMapper.selectListBetween(begin, end);
}
public List listDrillBetween(LocalDate begin, LocalDate end) {
return drillMapper.selectListBetween(begin, end);
}
public List listAccidentBetween(LocalDate begin, LocalDate end) {
return accidentMapper.selectListBetween(
begin == null ? null : begin.atStartOfDay(),
end == null ? null : end.atTime(23, 59, 59));
}
// ==================== 私有 ====================
/** 参加人数未填时,按姓名逗号分隔数量推断 */
private static int resolveCount(Integer count, String participants) {
if (count != null && count > 0) {
return count;
}
if (StrUtil.isBlank(participants)) {
return 0;
}
return (int) java.util.Arrays.stream(participants.split("[,,、]"))
.map(String::trim).filter(StrUtil::isNotBlank).count();
}
private SafetyTrainingDO validateTrainingExists(Long id) {
SafetyTrainingDO training = id == null ? null : trainingMapper.selectById(id);
if (training == null) {
throw exception(SAFETY_TRAINING_NOT_EXISTS);
}
return training;
}
private SafetyDrillDO validateDrillExists(Long id) {
SafetyDrillDO drill = id == null ? null : drillMapper.selectById(id);
if (drill == null) {
throw exception(SAFETY_DRILL_NOT_EXISTS);
}
return drill;
}
private SafetyAccidentDO validateAccidentExists(Long id) {
SafetyAccidentDO accident = id == null ? null : accidentMapper.selectById(id);
if (accident == null) {
throw exception(SAFETY_ACCIDENT_NOT_EXISTS);
}
return accident;
}
}