yangys
2025-09-01 8c76f15964fd35832c07ce7dd417c1289e744ec4
blade-service/blade-mdm/src/main/java/org/springblade/mdm/flow/service/ApproveTableService.java
@@ -3,26 +3,16 @@
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.flowable.engine.HistoryService;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.springblade.core.oss.OssTemplate;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.DateUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.mdm.basesetting.machine.MachineService;
import org.springblade.mdm.basesetting.machine.entity.Machine;
import org.springblade.mdm.commons.service.ParamService;
import org.springblade.mdm.commons.support.TemplatedPdfWriter;
import org.springblade.mdm.flow.constants.FlowContants;
import org.springblade.mdm.flow.vo.ApproveTableInfo;
import org.springblade.mdm.program.entity.NcNode;
import org.springblade.mdm.program.entity.NcProgramApproved;
import org.springblade.mdm.program.service.NcNodeService;
import org.springblade.mdm.program.service.NcProgramApprovedService;
import org.springblade.system.feign.IUserClient;
import org.springblade.system.pojo.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -30,10 +20,8 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.util.*;
import java.util.List;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;
/**
 * 审批记录,用于查询执行轨迹
 *
@@ -49,23 +37,20 @@
   @Autowired
   private MachineService machineService;
   @Autowired
   private HistoryService historyService;
   @Autowired
   private IUserClient useClient;
   @Autowired
   private NcProgramApprovedService programApprovedService;
   @Autowired
   private ParamService paramService;
   @Autowired
   private OssTemplate ossTemplate;
   private final String DATE_PATTERN = "yyyy-M-d";
   @Autowired
   private ApproveInfoQueryService approveInfoQueryService;
   private static final String UNCHECK_BOX = "☐";
   private static final String CHECKED_BOX = "☑";
   static Chunk square = new Chunk("o", new Font(Font.FontFamily.ZAPFDINGBATS, 12)); // 空方框
   static Chunk check = new Chunk("4", new Font(Font.FontFamily.ZAPFDINGBATS, 12)); // 带勾方框
   //private static final String UNCHECK_BOX = "☐";
   //private static final String CHECKED_BOX = "☑";
   //static Chunk square = new Chunk("o", new Font(Font.FontFamily.ZAPFDINGBATS, 12)); // 空方框
   //static Chunk check = new Chunk("4", new Font(Font.FontFamily.ZAPFDINGBATS, 12)); // 带勾方框
   /*
   BaseFont getBaseFont() throws DocumentException, IOException {
      return BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
   }
@@ -73,12 +58,33 @@
   Font getChineseFont() throws DocumentException, IOException {
      BaseFont bfChinese = getBaseFont();
      return new Font(bfChinese, 12, Font.NORMAL);
   }
   }*/
   public void exportApproveTable(String processInstanceId, OutputStream os) throws IOException, DocumentException {
      FlowProgramProperties props = flowCommonService.getProgramPropertiesFromHis(processInstanceId);
      ApproveTableInfo approveInfo = getApproveInfo(props);
      TemplatedPdfWriter pdfWriter = new TemplatedPdfWriter(getTemplateBytes());
      pdfWriter.write(getPdfData(props),os);
   }
   /**
    * 获取pdf模板的字节数组
    * @return 模板字节数组
    * @throws IOException
    */
   private byte[] getTemplateBytes() throws IOException {
      String tplOssName = paramService.approveTableTemplateOssFileName();
      try (InputStream inputStream = this.ossTemplate.statFileStream(tplOssName)) {
         return inputStream.readAllBytes();
      }
   }
   /**
    * 获取填充数据
    */
   Map<String,String> getPdfData(FlowProgramProperties props){
      ApproveTableInfo approveInfo = approveInfoQueryService.getApproveInfo(props);
      Machine machine;
      String machineCode = props.getMachineCode();
      machine = machineService.getByCode(machineCode);
@@ -88,6 +94,8 @@
      pdfData.put("processNo",props.getProcessNo());
      pdfData.put("craftEdition",props.getCraftEdition());
      pdfData.put("machineMode",machine.getName());
      String DATE_PATTERN = "yyyy-M-d";
      String dispatchDateStr = " ";
      if (approveInfo.getDispatchDate() != null) {
@@ -100,10 +108,12 @@
         pdfData.put("fuzeren",approveInfo.getCheckerName());
         pdfData.put("checkY","Y");//固化,属于校对任务
      }else{
         pdfData.put("fuzeren",approveInfo.getProgrammerName());
         pdfData.put("fuzeren",approveInfo.getProgrammerName());//负责人
         pdfData.put("programY","Y");//其他,属于编制任务
      }
      pdfData.put("fangzhenY","Y");
      pdfData.put("programNo",approveInfo.getProgramNo());
      Date programDate = approveInfo.getCheckDate();
      Date checkDate = approveInfo.getCheckDate();
@@ -128,17 +138,10 @@
      pdfData.put("sendDir",machine.getProgSendDir()!=null?machine.getProgSendDir():"");
      TemplatedPdfWriter pdfWriter = new TemplatedPdfWriter(getTemplateBytes());
      pdfWriter.write(pdfData,os);
   }
   private byte[] getTemplateBytes() throws IOException {
      String tplOssName = paramService.approveTableTemplateOssFileName();
      try (InputStream inputStream = this.ossTemplate.statFileStream(tplOssName)) {
         return inputStream.readAllBytes();
      }
      return pdfData;
   }
   /*
   public void exportApproveTableOld(String processInstanceId, OutputStream os) throws DocumentException, IOException {
      BaseFont bfChinese = getBaseFont();
@@ -164,277 +167,7 @@
      document.close();
   }
   */
   /**
    * 打印一个步骤(编制/校对)
    * @param document
    * @param bfChinese
    * @param props
    * @param machine
    * @param flag
    * @param approveInfo
    * @throws DocumentException
    * @throws IOException
    */
   void printPage(Document document, BaseFont bfChinese, FlowProgramProperties props, Machine machine, int flag, ApproveTableInfo approveInfo) throws DocumentException, IOException {
      Font tipFont = new Font(bfChinese, 10, Font.NORMAL);
      Paragraph tip = new Paragraph("艺表6", tipFont);
      tip.setAlignment(Element.ALIGN_RIGHT);
      tip.setSpacingAfter(-5); // 段后间距
      tip.setIndentationRight(220f);
      // 设置行距(行间距)
      //mixedParagraph.setLeading(24f); // 绝对行距
      //mixedParagraph.setLeading(1.5f, 2f);
      // 也可以使用相对行距:mixedParagraph.setLeading(1.5f, 24f);
      // 第一个参数是文本高度的倍数,第二个参数是额外的固定行距
      Font titleFont = new Font(bfChinese, 14, Font.NORMAL);
      Paragraph title = new Paragraph("数控程序审批单", titleFont);
      //title.setLeading(40f, 0f);
      tip.setSpacingBefore(-0.5f);
      title.setSpacingAfter(10); // 段后间距
      title.setAlignment(Element.ALIGN_CENTER);
      title.setPaddingTop(-0.6f);
      Paragraph mixedParagraph = new Paragraph();
      mixedParagraph.add(tip);
      mixedParagraph.add(title);
      mixedParagraph.setSpacingAfter(10);
      document.add(mixedParagraph);
      //document.add(title);
      // 创建表格(4列)
      PdfPTable table = new PdfPTable(5);
      table.setWidths(new float[]{1.5f, 1.4f, 1.4f, 1.4f, 1.5f});
      Font ft = this.getChineseFont();
      // 添加表头
      PdfPCell tempCell = new PdfPCell();//getCell("零组件号");
      tempCell.setHorizontalAlignment(Element.ALIGN_CENTER);
      tempCell.setVerticalAlignment(Element.ALIGN_MIDDLE);
      Phrase pt1 = new Phrase("零组件号", ft);
      tempCell.setPhrase(pt1);
      //tempCell.addElement(pt1);
      //
      table.addCell(tempCell);
      table.addCell(getCell("工序号", ft));
      table.addCell(getCell("工艺版次", ft));
      table.addCell(getCell("机床型号", ft));
      table.addCell(getCell("工段负责人/单元负\n责人派出时间", ft));
      table.addCell(getCell(props.getDrawingNo(), ft));//零组件号
      table.addCell(getCell(props.getProcessNo(), ft));//工序号
      table.addCell(getCell(props.getCraftEdition(), ft));//工艺版次
      table.addCell(getCell(machine.getName(), ft));//机床型号
      table.addCell(getCell(approveInfo.getTeamLeaderName(), ft));//负责人,工段负责人派出时间
      //中间大格
      PdfPCell cell = new PdfPCell();
      cell.setColspan(5);
      cell.setCalculatedHeight(400);
      Paragraph mainPara1 = new Paragraph();
      mainPara1.setLeading(30f, 0f);
      mainPara1.setFont(ft);
      mainPara1.setAlignment(Element.ALIGN_LEFT); // 对齐方式
      mainPara1.setIndentationLeft(20); // 左缩进(像素)
      mainPara1.setIndentationRight(20); // 右缩进
      mainPara1.setSpacingBefore(10); // 段前间距
      mainPara1.setSpacingAfter(10); // 段后间距
      mainPara1.add("数控程序编制任务安排:\n");
      cell.addElement(mainPara1);
      Paragraph line2Para = new Paragraph();
      line2Para.setLeading(30f, 0f);
      line2Para.setFont(ft);
      line2Para.setAlignment(Element.ALIGN_LEFT); // 对齐方式
      line2Para.setIndentationLeft(40); // 左缩进(像素)
      line2Para.add("请");
      Font underLineFt = new Font(bfChinese, 12, Font.UNDERLINE);
      //String personName = record.getUserNickname();
      Chunk block1 = square;
      Chunk block2 = check;
      Date programDate = approveInfo.getProgrammingDate(); //TODO 查询时间
      Date checkDate = approveInfo.getCheckDate();
      Phrase p;
      if (1 == flag) {
         p = new Phrase("       " + approveInfo.getProgrammerName() + "        ", underLineFt);
      } else {
         p = new Phrase("       " + approveInfo.getCheckerName() + "        ", underLineFt);
      }
      line2Para.add(p);
      Phrase p2 = new Phrase("负责数控程序(编制");
      if (flag == 1) {
         p2.add(block2);
         p2.add(new Chunk("   校对", ft));
         p2.add(block1);
      } else {
         p2.add(block1);
         p2.add(new Chunk("   校对", ft));
         p2.add(block2);
      }
      p2.add(new Chunk(")", ft));
      line2Para.add(p2);
      cell.addElement(line2Para);
      Paragraph fangzhen = new Paragraph();
      fangzhen.setAlignment(Element.ALIGN_LEFT); // 对齐方式
      fangzhen.setIndentationLeft(20); // 左缩进(像素)
      fangzhen.setIndentationRight(20); // 右缩进
      fangzhen.setSpacingBefore(10); // 段前间距
      fangzhen.setSpacingAfter(10); // 段后间距
      fangzhen.setFont(ft);
      fangzhen.setLeading(30f, 0f);
      fangzhen.add("是否需要仿真(是");
      fangzhen.add(check);//固定是仿真
      fangzhen.add(" 否");
      fangzhen.add(square);
      fangzhen.add(")\n\n");
      cell.addElement(fangzhen);
      table.addCell(cell);
      //下一行
      PdfPCell cell21 = getCell("数控程序编号", ft);// PdfPCell();
      cell21.setColspan(2);
      //cell21.setPhrase(new Phrase("数控程序编号",ft));
      table.addCell(cell21);
      table.addCell(getCell("编制/日期", ft));
      table.addCell(getCell("校对/日期", ft));
      table.addCell(getCell("批准/日期", ft));
      PdfPCell cell2 = getCell("00001", ft);
      cell2.setColspan(2);
      table.addCell(cell2);
      String pDateStr = " ";
      if (programDate != null) {
         pDateStr = DateUtil.format(programDate, "yyyy-MM-dd");
      }
      String checkDateStr = " ";
      if (checkDate != null) {
         checkDateStr = DateUtil.format(programDate, "yyyy-MM-dd");
      }
      String approveDateStr = " ";
      if (approveInfo.getApproveDate() != null) {
         approveDateStr = DateUtil.format(approveInfo.getApproveDate(), "yyyy-MM-dd");
      }
      table.addCell(getCell(approveInfo.getProgrammerName()+" " +pDateStr, ft));//编制/日期
      table.addCell(getCell(approveInfo.getCheckerName()+" " +checkDateStr, ft));
      table.addCell(getCell(approveInfo.getSeniorName()+" " +approveDateStr, ft));
      PdfPCell sendPathCell = getCell("数控程序传输路径:" + (machine.getProgSendDir() == null ? "" : machine.getProgSendDir()), ft);// PdfPCell();
      sendPathCell.setHorizontalAlignment(Element.ALIGN_LEFT);
      sendPathCell.setColspan(5);
      table.addCell(sendPathCell);
      // 设置表格宽度占页面宽度的100%
      table.setWidthPercentage(100);
      // 添加表格到文档
      document.add(table);
      Phrase lastPhrase = new Phrase("注:工段派工应预先计划、合理安排数控程序编制。立加、数铣、数车等单道工序程序(两轴程序)需提前1个工作日,卧式加工中心单道工序(含多轴程序)需提前3个工作日。 ", ft);
      document.add(lastPhrase);
   }
   PdfPCell getCell(String text, Font font) throws DocumentException, IOException {
      PdfPCell cell = new PdfPCell();
      cell.setPadding(10);
      cell.setHorizontalAlignment(Element.ALIGN_CENTER);
      cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
      if (StringUtils.isNotBlank(text)) {
         Phrase p = new Phrase(text, font);
         p.setLeading(25);
         cell.setPhrase(p);
      }
      return cell;
   }
   ApproveTableInfo getApproveInfo(FlowProgramProperties props){
      //编制
      R<User> leaderR = useClient.userInfoById(props.getTeamLeaderId());
      String leaderName = "";
      if (leaderR.isSuccess()) {
         leaderName = leaderR.getData().getName();
      }
      //编制
      R<User> programmerR = useClient.userInfoById(props.getProgrammerId());
      String programmerName = "";
      if (programmerR.isSuccess()) {
         programmerName = programmerR.getData().getName();
      }
      Machine machine;
      String machineCode = props.getMachineCode();
      machine = machineService.getByCode(machineCode);
      //校对
      R<User> checkerR = useClient.userInfoById(props.getCheckerId());
      String checkerName = "";
      if (checkerR.isSuccess()) {
         checkerName = checkerR.getData().getName();
      }
      //审核
      R<User> seniorR = useClient.userInfoById(props.getCheckerId());
      String senioirName = "";
      if (seniorR.isSuccess()) {
         senioirName = seniorR.getData().getName();
      }
      ApproveTableInfo appInfo = new ApproveTableInfo();
      appInfo.setTeamLeaderName(leaderName);
      appInfo.setProgrammerName(programmerName);
      appInfo.setCheckerName(checkerName);
      appInfo.setSeniorName(senioirName);
      //获取时间信息
      List<HistoricTaskInstance> hisTasks = historyService.createHistoricTaskInstanceQuery()
         .processInstanceId(props.getProcessInstanceId()).orderByTaskCreateTime().desc().list();
      for(HistoricTaskInstance task : hisTasks){
         if(appInfo.getDispatchDate()== null && task.getTaskDefinitionKey().contains("teamLeaderTask")){
            appInfo.setDispatchDate(task.getEndTime());
         }
         if(appInfo.getProgrammingDate()== null && task.getTaskDefinitionKey().contains("program")){
            appInfo.setProgrammingDate(task.getEndTime());
         }
         if(appInfo.getCheckDate()== null && task.getTaskDefinitionKey().contains("check")){
            appInfo.setCheckDate(task.getEndTime());
         }
         if(appInfo.getApproveDate()== null && task.getTaskDefinitionKey().contains("approve")){
            appInfo.setApproveDate(task.getEndTime());
         }
      }
      //查询数控程序编号
      Optional<NcProgramApproved> appOpt = programApprovedService.lambdaQuery().eq(NcProgramApproved::getProcessInstanceId, props.getProcessInstanceId()).oneOpt();
      if(appOpt.isEmpty()){
         appInfo.setProgramNo("(未生成)");
      }else{
         NcNode programPkgNameNode = this.ncNodeService.getById(appOpt.get().getNcNodeId());
         appInfo.setProgramNo(programPkgNameNode.getProgramNo());
      }
      return appInfo;
   }
}