package com.dy.pmsProduct.process; import com.dy.common.webFilter.UserTokenContext; import com.dy.common.webUtil.QueryResultVo; import com.dy.pmsGlobal.daoOth.OthFileMapper; import com.dy.pmsGlobal.daoPr.PrAssemblyPlanMapper; import com.dy.pmsGlobal.daoPr.PrProductionNodeMapper; import com.dy.pmsGlobal.daoPr.PrProductionProcessMapper; import com.dy.pmsGlobal.daoPr.PrWorkingInstructionMapper; import com.dy.pmsGlobal.dyFile.FileOperate; import com.dy.pmsGlobal.dyFile.FileRestVo; import com.dy.pmsGlobal.pojoBa.BaUser; import com.dy.pmsGlobal.pojoOth.OthFile; import com.dy.pmsGlobal.pojoPr.PrAssemblyPlan; import com.dy.pmsGlobal.pojoPr.PrProductionNode; import com.dy.pmsGlobal.pojoPr.PrProductionProcess; import com.dy.pmsGlobal.pojoPr.PrWorkingInstruction; import com.dy.pmsGlobal.util.UserUtil; import com.dy.pmsProduct.taskPlan.PlanStatusEnum; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; import org.apache.dubbo.common.utils.PojoUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.dao.DuplicateKeyException; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; @Slf4j @Service public class ProcessSv { private PrAssemblyPlanMapper assemblyDao; private PrProductionProcessMapper processDao; private PrProductionNodeMapper nodeDao; private PrWorkingInstructionMapper workDao; private UserUtil userUtil; private FileOperate fileOperate; private OthFileMapper othFileMapper; @Value("${dy.webFile.fmUrl}") private String fmUrl; @Autowired public void setAssemblyDao(PrAssemblyPlanMapper assemblyDao) { this.assemblyDao = assemblyDao; } @Autowired public void setProcessDao(PrProductionProcessMapper dao) { processDao = dao; } @Autowired public void setNodeDao(PrProductionNodeMapper dao) { nodeDao = dao; } @Autowired public void setWorkDao(PrWorkingInstructionMapper dao) { workDao = dao; } @Autowired public void setUserUtil(UserUtil userUtil) { this.userUtil = userUtil; } @Autowired public void setFileOperate(FileOperate fileOperate) { this.fileOperate = fileOperate; } @Autowired public void setOthFileMapper(OthFileMapper othFileMapper) { this.othFileMapper = othFileMapper; } @Transactional public int save(PrProductionProcess process) { //流程名称不能重复 if (processDao.exists(process.name, process.id)) { throw new RuntimeException("流程名称不能重复"); } prepareProcess(process); int count = processDao.insertSelective(process); saveNodesAndInstructions(process); return count; } @Transactional public int update(PrProductionProcess process) { //流程名称不能重复 if (processDao.exists(process.name, process.id)) { throw new RuntimeException("流程名称不能重复"); } PrProductionProcess originProductionProcess = processDao.selectByPrimaryKey(process.id); //如果已经绑定组装任务计划(目前不包括暂停\结束状态 投入数为0的任务 以外的 所有任务),产品\节点id不能删除不能修改 PrAssemblyPlan params = new PrAssemblyPlan(); params.setProcessId(process.id); List planList = assemblyDao.selectAssyPlanSimplify(params); List onlinePlanList = planList.stream().filter(plan -> plan.getStatus() == PlanStatusEnum.NORMAL.getCode()).collect(Collectors.toList()); if (CollectionUtils.isNotEmpty(planList)) { if (planList.stream().anyMatch(plan -> plan.getInputNumber() > 0)) { //存在任务已经投入生产 if (!originProductionProcess.getProId().equals(process.getProId())) { throw new RuntimeException("存在已经投入生产的绑定任务,产品不能修改"); } //节点id不能删除 if (!originProductionProcess.getNodes().stream().allMatch(node -> process.getNodes().stream().anyMatch(newNode -> node.getId().equals(newNode.getId())))) { throw new RuntimeException("已有绑定的任务投入生产,节点不能删除"); } } else if (CollectionUtils.isNotEmpty(onlinePlanList)) { //先将组装任务置为暂停状态 onlinePlanList.forEach(plan -> { plan.status = PlanStatusEnum.PAUSE.getCode(); assemblyDao.updateByPrimaryKeySelective(plan); }); } } prepareProcess(process); int count = processDao.updateByPrimaryKeySelective(process); // 优化:只有当节点有变更时 根据ID更新内容 没有匹配到的ID 删除 多余的ID 新增 List nodeIdsToDelete = originProductionProcess.getNodes().stream() .filter(node -> process.nodes.stream().filter(newNode -> node.getId().equals(newNode.getId())).count() == 0) .map(PrProductionNode::getId) // 映射节点到其ID .collect(Collectors.toList()); if (CollectionUtils.isNotEmpty(nodeIdsToDelete)) { nodeDao.deleteByNodeId(nodeIdsToDelete); } //原来节点的SOP全部删除 List originNodeIds = originProductionProcess.getNodes().stream() .map(PrProductionNode::getId) // 映射节点到其ID .collect(Collectors.toList()); if (CollectionUtils.isNotEmpty(originNodeIds)) { workDao.deleteByNodeId(originNodeIds); } saveNodesAndInstructions(process); return count; } // 提取共通逻辑到单独方法以减少代码重复 private void prepareProcess(PrProductionProcess process) { process.disabled = false; process.deleted = false; BaUser loginUser = userUtil.getUser(UserTokenContext.get()); if (loginUser != null) { process.creator = loginUser.id; } AtomicInteger startCount = new AtomicInteger(); AtomicInteger endCount = new AtomicInteger(); process.nodes.forEach(node -> { node.processId = process.id; node.deleted = false; if(node.isStart){ startCount.getAndIncrement(); } if(node.isEnd){ endCount.getAndIncrement(); } }); if (startCount.get() != 1 || endCount.get() != 1) { throw new RuntimeException("节点开始和结束节点有且只能有一个"); } } // 将节点和工作指示的保存逻辑封装到一个方法中 private void saveNodesAndInstructions(PrProductionProcess process) { List haveIdList = new ArrayList<>(); List noIdList = new ArrayList<>(); process.nodes.forEach(node -> { node.processId = process.id; if (node.getId() != null && node.getId() != 0) { haveIdList.add(node); } else { noIdList.add(node); } }); try { if (haveIdList.size() > 0) { for (int i = 0; i < haveIdList.size(); i++) { nodeDao.updateByPrimaryKeySelective(haveIdList.get(i)); } } if (noIdList.size() > 0) {//CollectionUtils.isNotEmpty(noIdList) nodeDao.insertMany(noIdList); } } catch (DuplicateKeyException e) { throw new RuntimeException("节点顺序重复"); } List workList = process.nodes.stream().map(node -> { if (node.instruction != null) { node.instruction.nodeId = node.id; return node.instruction; } return null; }).filter(work -> work != null).toList(); if (CollectionUtils.isNotEmpty(workList)) { workDao.insertMany(workList); } } public int delete(Long id) { return processDao.deleteLogicById(id); } public PrProductionProcess selectById(Long id) { PrProductionProcess process = processDao.selectByPrimaryKey(id); if (process != null) { process.nodes.forEach(node -> { if (node.instruction != null) { addUrl(node.instruction); } }); } return process; } public QueryResultVo> selectSome(QueryVo queryVo) { Map params = (Map) PojoUtils.generalize(queryVo); //查询符合条件的记录总数 Long itemTotal = processDao.selectSomeCount(params); QueryResultVo> rsVo = new QueryResultVo<>(queryVo.pageSize, queryVo.pageCurr); //计算分页等信息 rsVo.calculateAndSet(itemTotal, params); //查询符合条件的记录 rsVo.obj = processDao.selectSome(params); rsVo.obj.stream().forEach(process -> { process.nodes.forEach(node -> { if (node.instruction != null) { addUrl(node.instruction); } }); }); return rsVo; } public List> queryAll(Long proId) { return processDao.queryAll(proId); } private void addUrl(PrWorkingInstruction ins) { if (ins == null || ins.fileId == null) { return; } OthFile file = othFileMapper.selectByPrimaryKey(ins.fileId); if (file == null) { return; } FileRestVo fileRestVo = fileOperate.parseHashcode(fmUrl, file.hash); ins.webUrl = fileRestVo.fileSysRestUrl + fileRestVo.fileWebDownloadPath + ins.fileId; ins.orgName = file.orgName; ins.extName = file.extName; } }