yangys
2025-08-30 86c8efdb19a2f4be79a947650ef62ed79382011b
blade-service/blade-mdm/src/main/java/org/springblade/mdm/flow/service/ApproveTableService.java
@@ -1,30 +1,35 @@
package org.springblade.mdm.flow.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.flowable.task.api.Task;
import org.springblade.core.mp.base.BizServiceImpl;
import org.springblade.core.secure.utils.AuthUtil;
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.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.flow.entity.ApproveRecord;
import org.springblade.mdm.flow.mapper.ApproveRecordMapper;
import org.springblade.mdm.flow.vo.ApproveRecordVO;
import org.springblade.mdm.program.entity.NcProgram;
import org.springblade.mdm.program.entity.ProcessProgRef;
import org.springblade.mdm.program.service.NcProgramService;
import org.springblade.mdm.program.service.ProcessProgRefService;
import org.springframework.beans.BeanUtils;
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;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;
/**
@@ -34,72 +39,104 @@
 */
@Slf4j
@Service
@AllArgsConstructor
public class ApproveTableService{
   private final ProcessProgRefService processProgRefService;
   private final FlowCommonService flowCommonService;
   private final ApproveRecordService approveRecordService;
   private final NcProgramService ncProgramService;
   private final MachineService machineService;
public class ApproveTableService {
   @Autowired
   private FlowCommonService flowCommonService;
   @Autowired
   private NcNodeService ncNodeService;
   @Autowired
   private MachineService machineService;
   @Autowired
   private HistoryService historyService;
   @Autowired
   private IUserClient useClient;
   @Autowired
   private NcProgramApprovedService programApprovedService;
   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)); // 带勾方框
   //static SimpleDateFormat
   BaseFont getBaseFont() throws DocumentException, IOException {
      return BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
   }
   Font getChineseFont() throws DocumentException, IOException {
      BaseFont bfChinese = getBaseFont();
      return new Font(bfChinese, 12, Font.NORMAL);
   }
   /**
    * 导出审批确认表
    * @param processInstanceId
    */
   public void exportApproveTable(String processInstanceId, OutputStream os) throws DocumentException, IOException {
      BaseFont bfChinese =  getBaseFont();
      BaseFont bfChinese = getBaseFont();
      Document document = new Document(PageSize.B5.rotate());
      PdfWriter.getInstance(document,os);
      PdfWriter.getInstance(document, os);
      document.open();
      List<ApproveRecord> records = approveRecordService.lambdaQuery().eq(ApproveRecord::getProcessInstanceId, processInstanceId).orderByAsc(ApproveRecord::getCreateTime).list();
      for(int i=0;i<records.size();i++){
         ApproveRecord record = records.get(i);
         printStep(document,bfChinese,record);
         if(i<records.size()-1){
            document.newPage();
         }
      }
      FlowProgramProperties props = flowCommonService.getProgramPropertiesFromHis(processInstanceId);
      ApproveTableInfo appInfo = getApproveInfo(props);
      Machine machine;
      String machineCode = props.getMachineCode();
      machine = machineService.getByCode(machineCode);
      int flag = props.getProcessDefinitionKey().equals(FlowContants.TRY_PROCESS_KEY)?1:2;
      printPage(document, bfChinese, props, machine, flag, appInfo);
      //document.newPage();
      //printPage(document, bfChinese, props, machine, 2, appInfo);
      document.close();
   }
   void printStep(Document document,BaseFont bfChinese,ApproveRecord record) throws DocumentException, IOException {
      NcProgram ncProgram;
      Machine machine;
      if(record.getNcProgramId() !=null ) {
         ncProgram = ncProgramService.getById(record.getNcProgramId());
         machine = machineService.getByCode(ncProgram.getMachineCode());
      }else{
         ncProgram = new NcProgram();
         machine = new Machine();
      }
   /**
    * 打印一个步骤(编制/校对)
    * @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.setAlignment(Element.ALIGN_CENTER);
      title.setLeading(40f, 0f);
      Paragraph title = new Paragraph("数控程序审批单", titleFont);
      //title.setLeading(40f, 0f);
      tip.setSpacingBefore(-0.5f);
      title.setSpacingAfter(10); // 段后间距
      document.add(title);
      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[]{2,1.2f, 1.2f, 1.2f,2});
      table.setWidths(new float[]{1.5f, 1.4f, 1.4f, 1.4f, 1.5f});
      Font ft = this.getChineseFont();
      // 添加表头
@@ -107,25 +144,24 @@
      tempCell.setHorizontalAlignment(Element.ALIGN_CENTER);
      tempCell.setVerticalAlignment(Element.ALIGN_MIDDLE);
      Phrase pt1 = new Phrase("零组件号",ft);
      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("工序号", ft));
      table.addCell(getCell("工艺版次", ft));
      table.addCell(getCell("机床型号", ft));
      table.addCell(getCell("工段负责人/单元负\n责人派出时间", ft));
      //PdfPCell cell12 = new PdfPCell();
      //cell12.setColspan(2);
      //cell12.addElement(new Phrase(ncProgram.getDrawingNo()));
      table.addCell(getCell(ncProgram.getDrawingNo(),ft));//零组件号
      table.addCell(getCell(ncProgram.getProcessNo(),ft));//工序号
      table.addCell(getCell(ncProgram.getCraftEdition(),ft));//工艺版次
      table.addCell(getCell(machine.getName(),ft));//机床型号
      table.addCell("");//负责人,工段负责人派出时间
      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();
@@ -153,27 +189,32 @@
      Font underLineFt = new Font(bfChinese, 12, Font.UNDERLINE);
      String personName = record.getUserNickname();
      //String personName = record.getUserNickname();
      Chunk block1 = square;
      Chunk block2 = square;
      Date programDate = null;
      Date checkDate = null;
      if(StringUtils.equals(record.getTaskDefinitionId(),"programmingTask")){
         block1 = check;
         programDate = record.getCreateTime();
      }else if(StringUtils.equals(record.getTaskDefinitionId(),"check")){
         block2 = check;
         checkDate = record.getCreateTime();
      }
      Phrase p = new Phrase("       "+personName+"        ",underLineFt);
      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("负责数控程序(编制");
      p2.add(block1);
      p2.add(new Chunk("   校对",ft));
      p2.add(block2);
      p2.add(new Chunk(")",ft));
      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);
@@ -187,38 +228,50 @@
      fangzhen.setFont(ft);
      fangzhen.setLeading(30f, 0f);
      fangzhen.add("是否需要仿真(是");
      fangzhen.add(check);//固定是仿真
      fangzhen.add(" 否");
      fangzhen.add(square);
      fangzhen.add(";否");
      fangzhen.add(square);
      fangzhen.add(")\n");
      fangzhen.add(")\n\n");
      cell.addElement(fangzhen);
      table.addCell(cell);
      //下一行
      PdfPCell cell21 = getCell("数控程序编号",ft);// PdfPCell();
      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));
      table.addCell(getCell("编制/日期", ft));
      table.addCell(getCell("校对/日期", ft));
      table.addCell(getCell("批准/日期", ft));
      PdfPCell cell2 = new PdfPCell();
      PdfPCell cell2 = getCell("00001", ft);
      cell2.setColspan(2);
      cell2.addElement(new Phrase(ncProgram.getCode(),ft));//数控程序编号
      //cell2.addElement(new Phrase(programPackageNode.getProgramNo(),ft));//数控程序编号
      //cell2.addElement(new Phrase("00001",ft));
      table.addCell(cell2);
      String pDateStr = " ";
      if(programDate!=null){
         pDateStr = DateUtil.format(programDate,"yyyy-MM-dd");
      if (programDate != null) {
         pDateStr = DateUtil.format(programDate, "yyyy-MM-dd");
      }
      String checkDateStr = " ";
      if(checkDate!=null){
         checkDateStr = DateUtil.format(programDate,"yyyy-MM-dd");
      if (checkDate != null) {
         checkDateStr = DateUtil.format(programDate, "yyyy-MM-dd");
      }
      table.addCell(getCell(pDateStr,ft));//编制日期
      table.addCell(getCell(checkDateStr,ft));
      table.addCell(getCell(" ",ft));
      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);
@@ -226,17 +279,17 @@
      // 添加表格到文档
      document.add(table);
      Phrase lastPhrase = new Phrase("注:工段派工应预先计划、合理安排数控程序编制。立加、数铣、数车等单道工序程序(两轴程序)需提前1个工作日,卧式加工中心单道工序(含多轴程序)需提前3个工作日。 ",ft);
      Phrase lastPhrase = new Phrase("注:工段派工应预先计划、合理安排数控程序编制。立加、数铣、数车等单道工序程序(两轴程序)需提前1个工作日,卧式加工中心单道工序(含多轴程序)需提前3个工作日。 ", ft);
      document.add(lastPhrase);
   }
   PdfPCell getCell(String text,Font font) throws DocumentException, IOException {
   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);
      if (StringUtils.isNotBlank(text)) {
         Phrase p = new Phrase(text, font);
         p.setLeading(25);
         cell.setPhrase(p);
      }
@@ -244,5 +297,68 @@
      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.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;
   }
}