|  |  | 
 |  |  | 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.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.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 FileOperate fileOperate; | 
 |  |  |     private OthFileMapper othFileMapper; | 
 |  |  |     @Value("${dy.webFile.fmUrl}") | 
 |  |  |     private String fmUrl ; | 
 |  |  |     private String fmUrl; | 
 |  |  |  | 
 |  |  |     @Autowired | 
 |  |  |     public void setProcessDao(PrProductionProcessMapper dao){ | 
 |  |  |     public void setAssemblyDao(PrAssemblyPlanMapper assemblyDao) { | 
 |  |  |         this.assemblyDao = assemblyDao; | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     @Autowired | 
 |  |  |     public void setProcessDao(PrProductionProcessMapper dao) { | 
 |  |  |         processDao = dao; | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     @Autowired | 
 |  |  |     public void setNodeDao(PrProductionNodeMapper dao){ | 
 |  |  |     public void setNodeDao(PrProductionNodeMapper dao) { | 
 |  |  |         nodeDao = dao; | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     @Autowired | 
 |  |  |     public void setWorkDao(PrWorkingInstructionMapper dao){ | 
 |  |  |     public void setWorkDao(PrWorkingInstructionMapper dao) { | 
 |  |  |         workDao = dao; | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     @Autowired | 
 |  |  |     public void setUserUtil(UserUtil userUtil){ | 
 |  |  |     public void setUserUtil(UserUtil userUtil) { | 
 |  |  |         this.userUtil = userUtil; | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     @Autowired | 
 |  |  |     public void setFileOperate(FileOperate fileOperate){ | 
 |  |  |     public void setFileOperate(FileOperate fileOperate) { | 
 |  |  |         this.fileOperate = fileOperate; | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     @Autowired | 
 |  |  |     public void setOthFileMapper(OthFileMapper othFileMapper){ | 
 |  |  |     public void setOthFileMapper(OthFileMapper othFileMapper) { | 
 |  |  |         this.othFileMapper = othFileMapper; | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     @Transactional | 
 |  |  |     public int save(PrProductionProcess process){ | 
 |  |  |     public int save(PrProductionProcess process) { | 
 |  |  |         //流程名称不能重复 | 
 |  |  |         if (processDao.exists(process.name, process.id)) { | 
 |  |  |             throw new RuntimeException("流程名称不能重复"); | 
 |  |  |         } | 
 |  |  |         prepareProcess(process); | 
 |  |  |         int count = processDao.insertSelective(process); | 
 |  |  |         saveNodesAndInstructions(process); | 
 |  |  | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     @Transactional | 
 |  |  |     public int update(PrProductionProcess process){ | 
 |  |  |     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<PrAssemblyPlan> planList = assemblyDao.selectAssyPlanSimplify(params); | 
 |  |  |         List<PrAssemblyPlan> 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); | 
 |  |  |         // 优化:只有当节点有变更时才删除并重新插入 | 
 |  |  |         if (!process.nodes.isEmpty()) { | 
 |  |  |             List<Long> nodeIdsToDelete = process.getNodes().stream() | 
 |  |  |                     .map(PrProductionNode::getId) // 映射节点到其ID | 
 |  |  |                     .collect(Collectors.toList()); | 
 |  |  |             workDao.deleteByNodeId(nodeIdsToDelete); | 
 |  |  |             nodeDao.deleteByProcessId(process.id); | 
 |  |  |         // 优化:只有当节点有变更时    根据ID更新内容 没有匹配到的ID 删除  多余的ID 新增 | 
 |  |  |  | 
 |  |  |         List<Long> 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<Long> 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){ | 
 |  |  |     private void prepareProcess(PrProductionProcess process) { | 
 |  |  |         process.disabled = false; | 
 |  |  |         process.deleted = false; | 
 |  |  |         BaUser loginUser = userUtil.getUser(UserTokenContext.get()); | 
 |  |  |         if(loginUser!=null){ | 
 |  |  |         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; | 
 |  |  |             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){ | 
 |  |  |         try{ | 
 |  |  |             nodeDao.insertMany(process.nodes); | 
 |  |  |         }catch (DuplicateKeyException e){ | 
 |  |  |     private void saveNodesAndInstructions(PrProductionProcess process) { | 
 |  |  |         List<PrProductionNode> haveIdList = new ArrayList<>(); | 
 |  |  |         List<PrProductionNode> 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<PrWorkingInstruction> workList = process.nodes.stream().map(node -> { | 
 |  |  |             if(node.instruction !=null){ | 
 |  |  |             if (node.instruction != null) { | 
 |  |  |                 node.instruction.nodeId = node.id; | 
 |  |  |                 return node.instruction; | 
 |  |  |             } | 
 |  |  |             return null; | 
 |  |  |         }).filter(work -> work != null).toList(); | 
 |  |  |         workDao.insertMany(workList); | 
 |  |  |         if (CollectionUtils.isNotEmpty(workList)) { | 
 |  |  |             workDao.insertMany(workList); | 
 |  |  |         } | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |  | 
 |  |  |  | 
 |  |  |     public int delete(Long id){ | 
 |  |  |     public int delete(Long id) { | 
 |  |  |         return processDao.deleteLogicById(id); | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     public PrProductionProcess selectById(Long id){ | 
 |  |  |     public PrProductionProcess selectById(Long id) { | 
 |  |  |         PrProductionProcess process = processDao.selectByPrimaryKey(id); | 
 |  |  |         if(process != null){ | 
 |  |  |         if (process != null) { | 
 |  |  |             process.nodes.forEach(node -> { | 
 |  |  |                 if(node.instruction != null){ | 
 |  |  |                 if (node.instruction != null) { | 
 |  |  |                     addUrl(node.instruction); | 
 |  |  |                 } | 
 |  |  |             }); | 
 |  |  | 
 |  |  |         return process; | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     public QueryResultVo<List<PrProductionProcess>> selectSome(QueryVo queryVo){ | 
 |  |  |     public QueryResultVo<List<PrProductionProcess>> selectSome(QueryVo queryVo) { | 
 |  |  |         Map<String, Object> params = (Map<String, Object>) PojoUtils.generalize(queryVo); | 
 |  |  |  | 
 |  |  |         //查询符合条件的记录总数 | 
 |  |  |         Long itemTotal = processDao.selectSomeCount(params); | 
 |  |  |  | 
 |  |  |         QueryResultVo<List<PrProductionProcess>> rsVo = new QueryResultVo<>(queryVo.pageSize, queryVo.pageCurr) ; | 
 |  |  |         QueryResultVo<List<PrProductionProcess>> 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){ | 
 |  |  |                 if (node.instruction != null) { | 
 |  |  |                     addUrl(node.instruction); | 
 |  |  |                 } | 
 |  |  |             }); | 
 |  |  |         }); | 
 |  |  |         return rsVo ; | 
 |  |  |         return rsVo; | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     public List<Map<String,String>> queryAll(){ | 
 |  |  |         return processDao.queryAll(); | 
 |  |  |     public List<Map<String, String>> queryAll(Long proId) { | 
 |  |  |         return processDao.queryAll(proId); | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     private void addUrl(PrWorkingInstruction ins){ | 
 |  |  |     private void addUrl(PrWorkingInstruction ins) { | 
 |  |  |         if (ins == null || ins.fileId == null) { | 
 |  |  |             return; | 
 |  |  |         } |