package cn.iocoder.yudao.module.mes.service.safety;
|
|
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.cert.SafetyCertificatePageReqVO;
|
import cn.iocoder.yudao.module.mes.controller.admin.safety.vo.cert.SafetyCertificateRespVO;
|
import cn.iocoder.yudao.module.mes.controller.admin.safety.vo.cert.SafetyCertificateSaveReqVO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.safety.SafetyCertificateDO;
|
import cn.iocoder.yudao.module.mes.dal.mysql.safety.SafetyCertificateMapper;
|
import cn.iocoder.yudao.module.mes.enums.safety.SafetyCertificateStatusEnum;
|
import cn.iocoder.yudao.module.mes.enums.safety.SafetyCertificateTypeEnum;
|
import jakarta.annotation.Resource;
|
import org.springframework.stereotype.Service;
|
import org.springframework.validation.annotation.Validated;
|
|
import java.time.LocalDate;
|
import java.time.temporal.ChronoUnit;
|
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.SafetyErrorCodeConstants.*;
|
|
/**
|
* 安全生产 - 特种作业证台账 Service
|
*
|
* <p>核心能力:证书到期自动预警。状态由 {@link #resolveStatus} 根据有效期实时推导,
|
* 不依赖手工维护,避免过期未及时更新状态。</p>
|
*
|
* @author 超级管理员
|
*/
|
@Service
|
@Validated
|
public class SafetyCertificateService {
|
|
/** 默认提前预警天数 */
|
public static final int DEFAULT_WARN_DAYS = 30;
|
|
@Resource
|
private SafetyCertificateMapper certificateMapper;
|
|
public Long createCertificate(SafetyCertificateSaveReqVO reqVO) {
|
reqVO.setId(null);
|
validateCertificateForCreate(reqVO);
|
SafetyCertificateDO cert = buildCertificate(reqVO);
|
certificateMapper.insert(cert);
|
return cert.getId();
|
}
|
|
public void updateCertificate(SafetyCertificateSaveReqVO reqVO) {
|
SafetyCertificateDO old = validateCertificateExists(reqVO.getId());
|
validateCertificateForUpdate(reqVO, old);
|
SafetyCertificateDO cert = buildCertificate(reqVO);
|
certificateMapper.updateById(cert);
|
}
|
|
public void deleteCertificate(Long id) {
|
validateCertificateExists(id);
|
certificateMapper.deleteById(id);
|
}
|
|
public SafetyCertificateDO getCertificate(Long id) {
|
return validateCertificateExists(id);
|
}
|
|
public PageResult<SafetyCertificateDO> getCertificatePage(SafetyCertificatePageReqVO reqVO) {
|
return certificateMapper.selectPage(reqVO);
|
}
|
|
/**
|
* 查询即将到期 / 已过期的证件列表
|
*
|
* @param days 提前预警天数,为空使用默认 30 天
|
*/
|
public List<SafetyCertificateDO> getExpiringCertificates(Integer days) {
|
int warnDays = days == null || days <= 0 ? DEFAULT_WARN_DAYS : days;
|
return certificateMapper.selectExpiringBefore(LocalDate.now().plusDays(warnDays));
|
}
|
|
/**
|
* 分页结果的展示字段补全(类型名称、状态名称、剩余天数)
|
*/
|
public static void fillDisplayFields(SafetyCertificateDO cert, SafetyCertificateRespVO respVO) {
|
respVO.setCertTypeName(SafetyCertificateTypeEnum.getNameByType(cert.getCertType()));
|
String status = resolveStatus(cert.getExpireDate(), cert.getWarnDays(), cert.getStatus());
|
respVO.setStatus(status);
|
respVO.setStatusName(SafetyCertificateStatusEnum.getNameByStatus(status));
|
if (cert.getExpireDate() != null) {
|
respVO.setRemainingDays(ChronoUnit.DAYS.between(LocalDate.now(), cert.getExpireDate()));
|
}
|
}
|
|
/**
|
* 根据有效期推导状态:已注销保持不变;过期 → EXPIRED;在预警期内 → EXPIRING;否则 VALID
|
*
|
* @param expireDate 有效期
|
* @param warnDays 提前预警天数
|
* @param current 当前状态,用于保护 REVOKED
|
*/
|
public static String resolveStatus(LocalDate expireDate, Integer warnDays, String current) {
|
if (SafetyCertificateStatusEnum.REVOKED.getStatus().equals(current)) {
|
return SafetyCertificateStatusEnum.REVOKED.getStatus();
|
}
|
if (expireDate == null) {
|
return SafetyCertificateStatusEnum.VALID.getStatus();
|
}
|
LocalDate today = LocalDate.now();
|
if (expireDate.isBefore(today)) {
|
return SafetyCertificateStatusEnum.EXPIRED.getStatus();
|
}
|
int days = warnDays == null || warnDays <= 0 ? DEFAULT_WARN_DAYS : warnDays;
|
if (!expireDate.isAfter(today.plusDays(days))) {
|
return SafetyCertificateStatusEnum.EXPIRING.getStatus();
|
}
|
return SafetyCertificateStatusEnum.VALID.getStatus();
|
}
|
|
private SafetyCertificateDO buildCertificate(SafetyCertificateSaveReqVO reqVO) {
|
SafetyCertificateDO cert = BeanUtils.toBean(reqVO, SafetyCertificateDO.class);
|
cert.setEmployeeName(StrUtil.trim(reqVO.getEmployeeName()));
|
cert.setCertNo(StrUtil.trim(reqVO.getCertNo()));
|
cert.setWarnDays(reqVO.getWarnDays() == null ? DEFAULT_WARN_DAYS : reqVO.getWarnDays());
|
cert.setStatus(resolveStatus(reqVO.getExpireDate(), cert.getWarnDays(), reqVO.getStatus()));
|
cert.setRemark(reqVO.getRemark() == null ? "" : reqVO.getRemark().trim());
|
return cert;
|
}
|
|
private void validateCertificateForCreate(SafetyCertificateSaveReqVO reqVO) {
|
validateExpireAfterIssue(reqVO);
|
if (certificateMapper.selectByCertNo(StrUtil.trim(reqVO.getCertNo())) != null) {
|
throw exception(SAFETY_CERT_NO_DUPLICATE);
|
}
|
}
|
|
private void validateCertificateForUpdate(SafetyCertificateSaveReqVO reqVO, SafetyCertificateDO old) {
|
validateExpireAfterIssue(reqVO);
|
SafetyCertificateDO byCertNo = certificateMapper.selectByCertNo(StrUtil.trim(reqVO.getCertNo()));
|
if (byCertNo != null && !byCertNo.getId().equals(old.getId())) {
|
throw exception(SAFETY_CERT_NO_DUPLICATE);
|
}
|
// 保留原状态中的「已注销」,不允许通过编辑随意改回
|
if (SafetyCertificateStatusEnum.REVOKED.getStatus().equals(old.getStatus())
|
&& !SafetyCertificateStatusEnum.REVOKED.getStatus().equals(reqVO.getStatus())) {
|
reqVO.setStatus(SafetyCertificateStatusEnum.REVOKED.getStatus());
|
}
|
}
|
|
private void validateExpireAfterIssue(SafetyCertificateSaveReqVO reqVO) {
|
if (reqVO.getIssueDate() != null && reqVO.getExpireDate() != null
|
&& !Objects.requireNonNull(reqVO.getExpireDate()).isAfter(reqVO.getIssueDate())) {
|
throw exception(SAFETY_CERT_EXPIRE_BEFORE_ISSUE);
|
}
|
}
|
|
private SafetyCertificateDO validateCertificateExists(Long id) {
|
SafetyCertificateDO cert = id == null ? null : certificateMapper.selectById(id);
|
if (cert == null) {
|
throw exception(SAFETY_CERT_NOT_EXISTS);
|
}
|
return cert;
|
}
|
|
}
|