yangys
2025-09-20 fcee672452c02cc29e0e17ebc27a8c51698c6d0d
blade-service/blade-mdm/src/main/java/org/springblade/mdm/program/service/DncBackFileService.java
@@ -1,99 +1,173 @@
package org.springblade.mdm.program.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.flowable.engine.HistoryService;
import org.flowable.engine.ProcessEngine;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.mp.base.BizServiceImpl;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.oss.OssTemplate;
import org.springblade.core.tool.utils.DateUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.mdm.flow.service.CureFlowService;
import org.springblade.core.oss.model.BladeFile;
import org.springblade.core.tool.utils.FileUtil;
import org.springblade.mdm.flow.entity.FlowProgramFile;
import org.springblade.mdm.flow.service.FlowBusinessService;
import org.springblade.mdm.program.entity.DncBackFile;
import org.springblade.mdm.program.entity.NcProgram;
import org.springblade.mdm.program.entity.NcNode;
import org.springblade.mdm.program.mapper.DncBackFileMapper;
import org.springblade.mdm.program.vo.DncBackFileQueryVO;
import org.springblade.mdm.program.vo.DncBackFileVO;
import org.springframework.beans.BeanUtils;
import org.springblade.mdm.program.vo.DncSendBackFile;
import org.springblade.mdm.utils.FileContentUtil;
import org.springblade.mdm.utils.ZipTextFileContentUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Optional;
import java.util.zip.ZipEntry;
@AllArgsConstructor
/**
 * DNC回传文件处理服务
 *
 * @author yangys
 */
@Slf4j
@Service
@AllArgsConstructor
public class DncBackFileService extends BizServiceImpl<DncBackFileMapper, DncBackFile> {
   private final NcProgramService progService;
   private final NcNodeService ncNodeService;
   private final OssTemplate ossTemplate;
   private final CureFlowService cureFlowService;
   /**
    * 接受
    * @param ids
    */
   public void accept(String ids) {
      List<Long> idList = Func.toLongList(ids);
      for(Long id : idList){
         DncBackFile backFile = this.getById(id);
         backFile.setStatus(DncBackFile.STATUS_ACCEPTED);
         backFile.setConfirmTime(DateUtil.now());
         this.updateById(backFile);
         //新建一个程序,将老的程序isLastEditon设置未0,然后启动流程
         this.upgradeProgramAndStartCure(backFile.getNcProgramId(),backFile);
      }
   }
   void upgradeProgramAndStartCure(long ncProgramId,DncBackFile backFile) {
      NcProgram oldProgram = this.progService.getById(ncProgramId);
      //更新文件信息
      oldProgram.setOssName(backFile.getOssName());
      oldProgram.setUrl(backFile.getUrl());
      //TODO,是否删除原来的文件?
      progService.updateById(oldProgram);
      /*
      NcProgram newProgram = new NcProgram();
      BeanUtils.copyProperties(oldProgram,newProgram);
      oldProgram.setIsLastEdition(0);
      progService.updateById(oldProgram);
      newProgram.setId(null);
      newProgram.setIsLastEdition(1);
      progService.updateById(newProgram);
       */
      cureFlowService.startOne(oldProgram);//启动一个程序的固化流程
   }
   /**
    * 拒绝
    * @param ids
    */
   public void reject(String ids) {
      List<Long> idList = Func.toLongList(ids);
      for(Long id : idList){
         DncBackFile backFile = this.getById(id);
         backFile.setStatus(DncBackFile.STATUS_REJECTED);
         backFile.setConfirmTime(DateUtil.now());
         this.ossTemplate.removeFile(backFile.getOssName());
         this.updateById(backFile);
      }
   }
   /**
    * DNC回传程序处理分页查询
    * @param query 查询参数
    * @return 分页数据
    */
   private final HistoryService historyService;
   private final FlowBusinessService businessService;
   public IPage<DncBackFileVO> pageQuery(DncBackFileQueryVO query) {
      /*
      IPage<DncBackFileVO> page = this.getBaseMapper().pageQuery(Condition.getPage(query),query);
      */
      return this.getBaseMapper().pageQuery(Condition.getPage(query),query);
      IPage<DncBackFileVO> page=  this.baseMapper.pageQuery(Condition.getPage(query),query);
      page.getRecords().forEach(item->{
         item.setProcessExecuted(isProcessExecuted(item.getProcessInstanceId()));
      });
      return page;
   }
   /**
    * 检查流程实例是否被执行过(通过历史记录)
    */
   public boolean isProcessExecuted(String processInstanceId) {
      // 检查是否有历史活动记录
      /*
      long activityCount = historyService.createHistoricActivityInstanceQuery()
         .processInstanceId(processInstanceId)
         .count();
   */
      // 检查是否有历史任务记录
      long taskCount = historyService.createHistoricTaskInstanceQuery()
         .processInstanceId(processInstanceId)
         .count();
      //多于一个任务被处理,说明至少流转到第二个节点了
      return taskCount > 1;
   }
   /**
    * 取消流程
    * @param id 回传记录id
    */
   @Transactional
   public void cancelProcess(long id) {
      DncBackFile backFIle = this.getById(id);
      NcNode packageNode = ncNodeService.getById(backFIle.getNcNodeId());
      //多于一个任务被处理,说明至少流转到第二个节点了
      if(isProcessExecuted(packageNode.getProcessInstanceId())){
         throw new ServiceException("流程已经开始处理,不可取消");
      }
      businessService.deleteProcessInstance(packageNode.getProcessInstanceId());
      this.baseMapper.deleteById(id);
   }
   /**
    * 获取回传记录的文件列表
    * @param id 回传记录id
    * @return
    */
   public List<DncSendBackFile> filesById(long id) throws IOException {
      List<DncSendBackFile> fileList = new ArrayList<>();
      DncBackFile backFIle = this.getById(id);
      InputStream inputStream = this.ossTemplate.statFileStream(backFIle.getOssName());
      Path tempZipFile = createTempFile(inputStream);
      List<String> entryNameList = new ArrayList<>();
      NcNode packageNode =  this.ncNodeService.getById(backFIle.getNcNodeId());
      String targetFolder = packageNode.getName()+"-"+packageNode.getProcessEdition()+"/";
      ZipEntry entry;
      try (java.util.zip.ZipFile zipFile = new java.util.zip.ZipFile(tempZipFile.toFile())) {
         Enumeration<? extends ZipEntry> entries = zipFile.entries();
         while(entries.hasMoreElements()) {
            entry = entries.nextElement();
            if(!entry.isDirectory() && entry.getName().startsWith(targetFolder)){
               //这里面之前时入库的文件
               DncSendBackFile file = new DncSendBackFile();
               file.setName(entry.getName().substring(targetFolder.length()));
               file.setEntryName(entry.getName());
               fileList.add(file);
            }
         }
      }
      return fileList;
   }
   Path createTempFile(InputStream inputStream) throws IOException {
      byte[] zipData = FileUtil.copyToByteArray(inputStream);
      Path tempFile = Files.createTempFile("tempzip"+System.currentTimeMillis(), ".zip");
      // 写入字节数据到临时文件
      Files.write(tempFile, zipData, StandardOpenOption.WRITE);
      return tempFile;
   }
   /**
    * 从文件夹名解析出程序包名和和工序版次
    * @param folderName 文件夹名
    * @return 结构数据
    */
   PackageAndProcessEdition parseProgramPackageFromFolderName(String folderName){
      int index = StringUtils.lastIndexOf(folderName,'-');
      String processEditon = "";
      String temp;
      String packageName = "";
      if(index != -1){
         processEditon = folderName.substring(index+1);
         packageName = folderName.substring(0,index);
      }
      PackageAndProcessEdition result = new PackageAndProcessEdition();;
      result.setProgramPackageName(packageName);
      result.setProcessEdition(processEditon);
      return result;
   }
   /**
    * 获取历史记录中的文件内容
    * @param id 回传历史记录id
    * @param entryName 压缩包文件路径
    * @return
    */
   public String getEntryFileContent(long id, String entryName) throws IOException {
      DncBackFile backFIle = this.getById(id);
      return ZipTextFileContentUtil.getTextContent(this.ossTemplate.statFileStream(backFIle.getOssName()),entryName);
   }
}