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
|
*
|
* <p>动火、高压带电、有限空间等作业的线上审批与电子留存。
|
* 状态流转:草稿 → 待审批 → 已批准 → 作业中 → 已完结;驳回/作废为终止态。</p>
|
*
|
* @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());
|
}
|
|
/**
|
* 审批作业票
|
*
|
* <p>批准时校验高危作业(动火/高压带电/有限空间)必须指定监护人,
|
* 保证作业票电子留存的完整性。</p>
|
*/
|
@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<SafetyWorkPermitDO> getPermitPage(SafetyWorkPermitPageReqVO reqVO) {
|
return permitMapper.selectPage(reqVO);
|
}
|
|
// ==================== 监护记录 ====================
|
|
public Long createMonitor(SafetyWorkPermitMonitorSaveReqVO reqVO) {
|
SafetyWorkPermitDO permit = validatePermitExists(reqVO.getPermitId());
|
if (!SafetyPermitStatusEnum.IN_PROGRESS.getStatus().equals(permit.getStatus())
|
&& !SafetyPermitStatusEnum.APPROVED.getStatus().equals(permit.getStatus())) {
|
throw exception(SAFETY_PERMIT_STATUS_ERROR);
|
}
|
SafetyWorkPermitMonitorDO monitor = BeanUtils.toBean(reqVO, SafetyWorkPermitMonitorDO.class);
|
monitor.setId(null);
|
var guardian = refResolver.requireEmployee(reqVO.getGuardianId(), SAFETY_EMPLOYEE_REQUIRED);
|
monitor.setGuardianId(guardian.getId());
|
monitor.setGuardian(guardian.getName());
|
monitor.setMonitorTime(reqVO.getMonitorTime() == null ? LocalDateTime.now() : reqVO.getMonitorTime());
|
monitorMapper.insert(monitor);
|
return monitor.getId();
|
}
|
|
public void deleteMonitor(Long id) {
|
if (id == null || monitorMapper.selectById(id) == null) {
|
throw exception(SAFETY_PERMIT_MONITOR_NOT_EXISTS);
|
}
|
monitorMapper.deleteById(id);
|
}
|
|
public List<SafetyWorkPermitMonitorDO> getMonitorList(Long permitId) {
|
return monitorMapper.selectListByPermitId(permitId);
|
}
|
|
// ==================== 展示字段 ====================
|
|
/**
|
* 批量回填作业票的车间名与三个人员姓名(申请人/审批人/监护人)
|
*/
|
public void fillPermitRefs(List<SafetyWorkPermitDO> permits) {
|
if (CollUtil.isEmpty(permits)) {
|
return;
|
}
|
var workshopMap = refResolver.workshopMap(permits.stream().map(SafetyWorkPermitDO::getWorkshopId).toList());
|
var ids = new java.util.ArrayList<Long>(permits.size() * 3);
|
permits.forEach(p -> { ids.add(p.getApplicantId()); ids.add(p.getApproverId()); ids.add(p.getGuardianId()); });
|
var employeeMap = refResolver.employeeMap(ids);
|
permits.forEach(permit -> {
|
var workshop = workshopMap.get(permit.getWorkshopId());
|
if (workshop != null) permit.setWorkshopName(workshop.getName());
|
var applicant = employeeMap.get(permit.getApplicantId());
|
if (applicant != null) permit.setApplicant(applicant.getName());
|
var approver = employeeMap.get(permit.getApproverId());
|
if (approver != null) permit.setApprover(approver.getName());
|
var guardian = employeeMap.get(permit.getGuardianId());
|
if (guardian != null) permit.setGuardian(guardian.getName());
|
});
|
}
|
|
/**
|
* 批量回填监护记录的监护人最新姓名
|
*/
|
public void fillMonitorGuardians(List<SafetyWorkPermitMonitorDO> monitors) {
|
if (CollUtil.isEmpty(monitors)) {
|
return;
|
}
|
var employeeMap = refResolver.employeeMap(
|
monitors.stream().map(SafetyWorkPermitMonitorDO::getGuardianId).toList());
|
monitors.forEach(monitor -> {
|
var employee = employeeMap.get(monitor.getGuardianId());
|
if (employee != null) monitor.setGuardian(employee.getName());
|
});
|
}
|
|
public static void fillPermitDisplay(SafetyWorkPermitDO permit, SafetyWorkPermitRespVO respVO) {
|
respVO.setPermitTypeName(SafetyPermitTypeEnum.getNameByType(permit.getPermitType()));
|
respVO.setRiskLevelName(SafetyRiskLevelEnum.getNameByLevel(permit.getRiskLevel()));
|
respVO.setStatusName(SafetyPermitStatusEnum.getNameByStatus(permit.getStatus()));
|
respVO.setGuardianRequired(SafetyPermitTypeEnum.requiresGuardian(permit.getPermitType()));
|
}
|
|
private void validateTimeRange(SafetyWorkPermitSaveReqVO reqVO) {
|
if (reqVO.getPlanStartTime() != null && reqVO.getPlanEndTime() != null
|
&& !reqVO.getPlanEndTime().isAfter(reqVO.getPlanStartTime())) {
|
throw exception(SAFETY_PERMIT_TIME_INVALID);
|
}
|
}
|
|
private void ensureStatus(SafetyWorkPermitDO permit, SafetyPermitStatusEnum... allowed) {
|
for (SafetyPermitStatusEnum status : allowed) {
|
if (status.getStatus().equals(permit.getStatus())) {
|
return;
|
}
|
}
|
throw exception(SAFETY_PERMIT_STATUS_ERROR);
|
}
|
|
private SafetyWorkPermitDO validatePermitExists(Long id) {
|
SafetyWorkPermitDO permit = id == null ? null : permitMapper.selectById(id);
|
if (permit == null) {
|
throw exception(SAFETY_PERMIT_NOT_EXISTS);
|
}
|
return permit;
|
}
|
|
}
|