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.permit.*; import cn.iocoder.yudao.module.mes.dal.dataobject.safety.SafetyWorkPermitDO; import cn.iocoder.yudao.module.mes.dal.dataobject.safety.SafetyWorkPermitMonitorDO; import cn.iocoder.yudao.module.mes.dal.mysql.safety.SafetyWorkPermitMapper; import cn.iocoder.yudao.module.mes.dal.mysql.safety.SafetyWorkPermitMonitorMapper; import cn.iocoder.yudao.module.mes.enums.safety.SafetyPermitStatusEnum; import cn.iocoder.yudao.module.mes.enums.safety.SafetyPermitTypeEnum; import cn.iocoder.yudao.module.mes.enums.safety.SafetyRiskLevelEnum; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; 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 SafetyWorkPermitService { private static final DateTimeFormatter CODE_DATE = DateTimeFormatter.ofPattern("yyyyMMdd"); @Resource private SafetyWorkPermitMapper permitMapper; @Resource private SafetyRefResolver refResolver; @Resource private SafetyWorkPermitMonitorMapper monitorMapper; /** * 提交作业申请(草稿或待审批) */ @Transactional(rollbackFor = Exception.class) public Long createPermit(SafetyWorkPermitSaveReqVO reqVO) { reqVO.setId(null); validateTimeRange(reqVO); SafetyWorkPermitDO permit = BeanUtils.toBean(reqVO, SafetyWorkPermitDO.class); permit.setCode(permitMapper.selectNextCode("WP" + LocalDate.now().format(CODE_DATE))); permit.setTitle(StrUtil.trim(reqVO.getTitle())); applyPermitRefs(permit, reqVO); permit.setApplyTime(reqVO.getApplyTime() == null ? LocalDateTime.now() : reqVO.getApplyTime()); permit.setRiskLevel(StrUtil.blankToDefault(reqVO.getRiskLevel(), SafetyRiskLevelEnum.NORMAL.getLevel())); permit.setStatus(SafetyPermitStatusEnum.PENDING.getStatus()); permit.setRemark(reqVO.getRemark() == null ? "" : reqVO.getRemark().trim()); permitMapper.insert(permit); return permit.getId(); } /** * 修改作业票(仅草稿/待审批可改) */ public void updatePermit(SafetyWorkPermitSaveReqVO reqVO) { SafetyWorkPermitDO old = validatePermitExists(reqVO.getId()); ensureStatus(old, SafetyPermitStatusEnum.DRAFT, SafetyPermitStatusEnum.PENDING); validateTimeRange(reqVO); SafetyWorkPermitDO update = BeanUtils.toBean(reqVO, SafetyWorkPermitDO.class); update.setCode(null); update.setStatus(null); applyPermitRefs(update, reqVO); permitMapper.updateById(update); } /** * 作业票的主数据引用:作业车间 + 申请人 + 监护人,从主数据带出名称落快照 */ private void applyPermitRefs(SafetyWorkPermitDO permit, SafetyWorkPermitSaveReqVO reqVO) { permit.setWorkshopId(reqVO.getWorkshopId()); permit.setWorkshopName(reqVO.getWorkshopId() == null ? "" : refResolver.requireWorkshop(reqVO.getWorkshopId()).getName()); var applicant = refResolver.requireEmployee(reqVO.getApplicantId(), SAFETY_EMPLOYEE_REQUIRED); permit.setApplicantId(applicant.getId()); permit.setApplicant(applicant.getName()); permit.setGuardianId(reqVO.getGuardianId()); permit.setGuardian(reqVO.getGuardianId() == null ? "" : refResolver.requireEmployee(reqVO.getGuardianId(), SAFETY_EMPLOYEE_REQUIRED).getName()); } /** * 审批作业票 * *批准时校验高危作业(动火/高压带电/有限空间)必须指定监护人, * 保证作业票电子留存的完整性。
*/ @Transactional(rollbackFor = Exception.class) public void approvePermit(SafetyWorkPermitApproveReqVO reqVO) { SafetyWorkPermitDO permit = validatePermitExists(reqVO.getId()); ensureStatus(permit, SafetyPermitStatusEnum.PENDING); var approver = refResolver.requireEmployee(reqVO.getApproverId(), SAFETY_EMPLOYEE_REQUIRED); // 申请人不能审批自己的作业票(按员工编号比较,避免同名误判) if (permit.getApplicantId() != null && permit.getApplicantId().equals(approver.getId())) { throw exception(SAFETY_PERMIT_SELF_APPROVE); } boolean approved = "APPROVED".equals(reqVO.getDecision()); if (approved && SafetyPermitTypeEnum.requiresGuardian(permit.getPermitType()) && permit.getGuardianId() == null) { throw exception(SAFETY_PERMIT_GUARDIAN_REQUIRED); } SafetyWorkPermitDO update = new SafetyWorkPermitDO(); update.setId(permit.getId()); update.setApproverId(approver.getId()); update.setApprover(approver.getName()); update.setApproveTime(LocalDateTime.now()); update.setApproveComment(reqVO.getApproveComment()); update.setStatus(approved ? SafetyPermitStatusEnum.APPROVED.getStatus() : SafetyPermitStatusEnum.REJECTED.getStatus()); permitMapper.updateById(update); } /** * 开始作业(须已批准) */ public void startPermit(Long id) { SafetyWorkPermitDO permit = validatePermitExists(id); if (!SafetyPermitStatusEnum.APPROVED.getStatus().equals(permit.getStatus())) { throw exception(SAFETY_PERMIT_NOT_APPROVED); } SafetyWorkPermitDO update = new SafetyWorkPermitDO(); update.setId(id); update.setActualStartTime(LocalDateTime.now()); update.setStatus(SafetyPermitStatusEnum.IN_PROGRESS.getStatus()); permitMapper.updateById(update); } /** * 结束作业并归档 */ public void closePermit(Long id) { SafetyWorkPermitDO permit = validatePermitExists(id); ensureStatus(permit, SafetyPermitStatusEnum.IN_PROGRESS); SafetyWorkPermitDO update = new SafetyWorkPermitDO(); update.setId(id); update.setActualEndTime(LocalDateTime.now()); update.setStatus(SafetyPermitStatusEnum.CLOSED.getStatus()); permitMapper.updateById(update); } /** * 作废作业票(未完结前均可作废) */ public void cancelPermit(Long id) { SafetyWorkPermitDO permit = validatePermitExists(id); if (SafetyPermitStatusEnum.CLOSED.getStatus().equals(permit.getStatus()) || SafetyPermitStatusEnum.CANCELLED.getStatus().equals(permit.getStatus())) { throw exception(SAFETY_PERMIT_STATUS_ERROR); } SafetyWorkPermitDO update = new SafetyWorkPermitDO(); update.setId(id); update.setStatus(SafetyPermitStatusEnum.CANCELLED.getStatus()); permitMapper.updateById(update); } @Transactional(rollbackFor = Exception.class) public void deletePermit(Long id) { validatePermitExists(id); monitorMapper.deleteByPermitId(id); permitMapper.deleteById(id); } public SafetyWorkPermitDO getPermit(Long id) { return validatePermitExists(id); } public PageResult