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.risk.MesSafetyRiskPageReqVO;
|
import cn.iocoder.yudao.module.mes.controller.admin.safety.vo.risk.MesSafetyRiskSaveReqVO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.safety.MesSafetyRiskDO;
|
import cn.iocoder.yudao.module.mes.dal.mysql.safety.MesSafetyHazardMapper;
|
import cn.iocoder.yudao.module.mes.dal.mysql.safety.MesSafetyRiskMapper;
|
import jakarta.annotation.Resource;
|
import org.springframework.stereotype.Service;
|
import org.springframework.validation.annotation.Validated;
|
|
import java.math.BigDecimal;
|
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 实现
|
*
|
* LEC 法(格雷厄姆-金尼法):
|
* D = L × E × C
|
* 等级:D≥320 重大(1);160≤D<320 较大(2);70≤D<160 一般(3);D<70 低(4)
|
*
|
* @author 超级管理员
|
*/
|
@Service
|
@Validated
|
public class MesSafetyRiskServiceImpl implements MesSafetyRiskService {
|
|
/** 风险等级阈值 */
|
private static final BigDecimal LEVEL_1_THRESHOLD = new BigDecimal("320");
|
private static final BigDecimal LEVEL_2_THRESHOLD = new BigDecimal("160");
|
private static final BigDecimal LEVEL_3_THRESHOLD = new BigDecimal("70");
|
|
@Resource
|
private MesSafetyRiskMapper riskMapper;
|
|
@Resource
|
private MesSafetyRiskUnitService riskUnitService;
|
|
@Resource
|
private MesSafetyHazardMapper hazardMapper;
|
|
@Override
|
public PageResult<MesSafetyRiskDO> getRiskPage(MesSafetyRiskPageReqVO pageReqVO) {
|
return riskMapper.selectPage(pageReqVO);
|
}
|
|
@Override
|
public MesSafetyRiskDO getRisk(Long id) {
|
return riskMapper.selectById(id);
|
}
|
|
@Override
|
public Long createRisk(MesSafetyRiskSaveReqVO createReqVO) {
|
// 1. 风险单元必须存在
|
riskUnitService.validateRiskUnitExists(createReqVO.getUnitId());
|
// 2. 编码唯一
|
validateCodeUnique(null, createReqVO.getCode());
|
// 3. 转换并计算 LEC
|
MesSafetyRiskDO risk = BeanUtils.toBean(createReqVO, MesSafetyRiskDO.class);
|
applyLecEvaluation(risk);
|
riskMapper.insert(risk);
|
return risk.getId();
|
}
|
|
@Override
|
public void updateRisk(MesSafetyRiskSaveReqVO updateReqVO) {
|
validateRiskExists(updateReqVO.getId());
|
riskUnitService.validateRiskUnitExists(updateReqVO.getUnitId());
|
validateCodeUnique(updateReqVO.getId(), updateReqVO.getCode());
|
MesSafetyRiskDO updateObj = BeanUtils.toBean(updateReqVO, MesSafetyRiskDO.class);
|
applyLecEvaluation(updateObj);
|
riskMapper.updateById(updateObj);
|
}
|
|
@Override
|
public void deleteRisk(Long id) {
|
validateRiskExists(id);
|
// 已被隐患引用的风险不允许删除
|
Long hazardCount = hazardMapper.selectCountByRiskId(id);
|
if (hazardCount != null && hazardCount > 0) {
|
throw exception(MES_SAFETY_HAZARD_HAS_REFERENCE);
|
}
|
riskMapper.deleteById(id);
|
}
|
|
@Override
|
public List<MesSafetyRiskDO> getRiskListByUnitId(Long unitId) {
|
return riskMapper.selectListByUnitId(unitId);
|
}
|
|
@Override
|
public MesSafetyRiskDO validateRiskExists(Long id) {
|
if (id == null) {
|
throw exception(MES_SAFETY_RISK_NOT_EXISTS);
|
}
|
MesSafetyRiskDO risk = riskMapper.selectById(id);
|
if (risk == null) {
|
throw exception(MES_SAFETY_RISK_NOT_EXISTS);
|
}
|
return risk;
|
}
|
|
@Override
|
public BigDecimal calculateRiskValue(BigDecimal likelihood, BigDecimal exposure, BigDecimal consequence) {
|
if (likelihood == null || exposure == null || consequence == null) {
|
return null;
|
}
|
if (likelihood.compareTo(BigDecimal.ZERO) <= 0
|
|| exposure.compareTo(BigDecimal.ZERO) <= 0
|
|| consequence.compareTo(BigDecimal.ZERO) <= 0) {
|
throw exception(MES_SAFETY_RISK_LEC_INVALID);
|
}
|
// D = L × E × C,保留 2 位小数
|
return likelihood.multiply(exposure).multiply(consequence)
|
.setScale(2, java.math.RoundingMode.HALF_UP);
|
}
|
|
@Override
|
public Integer calculateRiskLevel(BigDecimal riskValue) {
|
if (riskValue == null) {
|
return null;
|
}
|
if (riskValue.compareTo(LEVEL_1_THRESHOLD) >= 0) {
|
return 1; // 重大风险
|
}
|
if (riskValue.compareTo(LEVEL_2_THRESHOLD) >= 0) {
|
return 2; // 较大风险
|
}
|
if (riskValue.compareTo(LEVEL_3_THRESHOLD) >= 0) {
|
return 3; // 一般风险
|
}
|
return 4; // 低风险
|
}
|
|
/**
|
* 计算并回填 D 值与风险等级
|
*/
|
private void applyLecEvaluation(MesSafetyRiskDO risk) {
|
// L/E/C 都为空时视为未评估,保持空值
|
if (risk.getLikelihood() == null && risk.getExposure() == null && risk.getConsequence() == null) {
|
risk.setRiskValue(null);
|
risk.setRiskLevel(null);
|
return;
|
}
|
BigDecimal riskValue = calculateRiskValue(risk.getLikelihood(), risk.getExposure(), risk.getConsequence());
|
risk.setRiskValue(riskValue);
|
risk.setRiskLevel(calculateRiskLevel(riskValue));
|
}
|
|
/**
|
* 校验编码唯一(id 为空表示新增)
|
*/
|
private void validateCodeUnique(Long id, String code) {
|
MesSafetyRiskDO exists = riskMapper.selectByCode(code);
|
if (exists == null) {
|
return;
|
}
|
if (id == null || !Objects.equals(exists.getId(), id)) {
|
throw exception(MES_SAFETY_RISK_CODE_DUPLICATE);
|
}
|
}
|
|
}
|