Browse Source

工程文件及流程相关

huangjn 3 years ago
parent
commit
a575ca4ba3
18 changed files with 492 additions and 54 deletions
  1. 14 0
      blade-common/src/main/java/org/springblade/common/utils/CommonUtil.java
  2. 18 0
      blade-ops-api/blade-resource-api/src/main/java/org/springblade/resource/feign/NewIOSSClient.java
  3. 1 0
      blade-ops-api/blade-resource-api/src/main/java/org/springblade/resource/vo/NewBladeFile.java
  4. 167 34
      blade-ops/blade-resource/src/main/java/org/springblade/resource/endpoint/OssEndpoint.java
  5. 35 0
      blade-ops/blade-resource/src/main/java/org/springblade/resource/feign/NewIOSSClientClient.java
  6. 6 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/entity/ArchiveFile.java
  7. 6 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/entity/Task.java
  8. 7 1
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/vo/TaskApprovalVO.java
  9. 8 1
      blade-service/blade-business/src/main/java/org/springblade/business/controller/ArchiveFileController.java
  10. 4 0
      blade-service/blade-business/src/main/java/org/springblade/business/controller/InformationWriteQueryController.java
  11. 100 5
      blade-service/blade-business/src/main/java/org/springblade/business/controller/TaskController.java
  12. 2 1
      blade-service/blade-business/src/main/java/org/springblade/business/controller/TreeContractFirstController.java
  13. 16 0
      blade-service/blade-business/src/main/java/org/springblade/business/feignClient/ClientTreePublicCodeClientImpl.java
  14. 9 8
      blade-service/blade-business/src/main/java/org/springblade/business/mapper/ArchiveFileMapper.xml
  15. 1 0
      blade-service/blade-business/src/main/java/org/springblade/business/mapper/TaskMapper.xml
  16. 1 1
      blade-service/blade-business/src/main/java/org/springblade/business/service/impl/ArchiveFileServiceImpl.java
  17. 40 3
      blade-service/blade-business/src/main/java/org/springblade/business/service/impl/TaskServiceImpl.java
  18. 57 0
      blade-service/blade-business/src/main/java/org/springblade/business/utils/FileUtils.java

+ 14 - 0
blade-common/src/main/java/org/springblade/common/utils/CommonUtil.java

@@ -2,7 +2,10 @@ package org.springblade.common.utils;
 
 import org.apache.commons.lang.StringUtils;
 
+import java.io.InputStream;
 import java.math.BigDecimal;
+import java.net.HttpURLConnection;
+import java.net.URL;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Random;
@@ -14,6 +17,17 @@ import java.util.Random;
  */
 public class CommonUtil {
 
+    /**
+     * 根据OSS文件路径获取文件输入流
+     */
+    public static InputStream getOSSInputStream(String urlStr) throws Exception {
+        //获取OSS文件流
+        URL imageUrl = new URL(urlStr);
+        HttpURLConnection conn = (HttpURLConnection) imageUrl.openConnection();
+        conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
+        return conn.getInputStream();
+    }
+
     /**
      * 随机生成短信验证码
      * @param length 生成长度

+ 18 - 0
blade-ops-api/blade-resource-api/src/main/java/org/springblade/resource/feign/NewIOSSClient.java

@@ -0,0 +1,18 @@
+package org.springblade.resource.feign;
+
+import org.springblade.core.launch.constant.AppConstant;
+import org.springblade.core.oss.model.BladeFile;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+
+@FeignClient(value = AppConstant.APPLICATION_RESOURCE_NAME)
+public interface NewIOSSClient {
+
+    String API_PREFIX = "/newClient";
+    String UPLOAD_FILE_INFO = API_PREFIX + "/uploadFileInfo";
+
+    @PostMapping(UPLOAD_FILE_INFO)
+    BladeFile uploadFile(@RequestParam String fileName, @RequestParam String localFileUrl);
+
+}

+ 1 - 0
blade-ops-api/blade-resource-api/src/main/java/org/springblade/resource/vo/NewBladeFile.java

@@ -5,6 +5,7 @@ import lombok.Data;
 @Data
 public class NewBladeFile {
     private String link;
+    private String pdfUrl;
     private String domain;
     private String name;
     private String originalName;

+ 167 - 34
blade-ops/blade-resource/src/main/java/org/springblade/resource/endpoint/OssEndpoint.java

@@ -16,19 +16,16 @@
  */
 package org.springblade.resource.endpoint;
 
-import cn.hutool.poi.excel.WorkbookUtil;
-import com.aliyun.oss.OSSClient;
-import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
-import com.itextpdf.text.pdf.PdfReader;
+import com.aspose.cells.SaveFormat;
+import com.aspose.words.DocumentBuilder;
+import com.itextpdf.text.Image;
+import com.itextpdf.text.Rectangle;
+import com.itextpdf.text.pdf.PdfWriter;
 import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
 import lombok.AllArgsConstructor;
 import lombok.SneakyThrows;
-import org.apache.poi.POIXMLDocument;
-import org.apache.poi.hwpf.extractor.WordExtractor;
-import org.apache.poi.ss.usermodel.Workbook;
-import org.apache.poi.xwpf.usermodel.XWPFDocument;
-import org.springblade.core.oss.AliossTemplate;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.WorkbookFactory;
 import org.springblade.core.oss.model.BladeFile;
 import org.springblade.core.oss.model.OssFile;
 import org.springblade.core.secure.annotation.PreAuth;
@@ -45,7 +42,8 @@ import org.springframework.beans.BeanUtils;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
 
-import java.io.FileInputStream;
+import java.io.*;
+import java.util.Objects;
 
 /**
  * 对象存储端点
@@ -176,38 +174,173 @@ public class OssEndpoint {
 	}
 
 	/**
-	 * 上传文件
+	 * 上传文件(兼容工程文件需求)
 	 */
 	@SneakyThrows
 	@PostMapping("/upload-file")
 	public R<NewBladeFile> uploadFile(@RequestParam MultipartFile file){
-//		BladeFile bladeFile = ossBuilder.template().putFile(file.getOriginalFilename(), file.getInputStream());
-
-		int pageCount = 0;
-		if(file.getOriginalFilename().contains(".docx")){
-			XWPFDocument document = new XWPFDocument(file.getInputStream());
-			//文件页数
-			pageCount = document.getProperties().getExtendedProperties().getUnderlyingProperties().getPages();
-		} else if(file.getOriginalFilename().contains(".doc")){
-			WordExtractor word = new WordExtractor(file.getInputStream());
-			//文件页数
-			pageCount = word.getSummaryInformation().getPageCount();
-		} else if(file.getOriginalFilename().contains(".pdf")){
-			PdfReader pdf = new PdfReader(file.getInputStream());
-			pageCount = pdf.getNumberOfPages();
-		} else if(file.getOriginalFilename().contains(".xlsx")){
-			Workbook workbook = WorkbookUtil.createBook(file.getInputStream());
-		} else {
-			pageCount = 1;
-		}
-		//转换实体
+		//上传原文件
+		BladeFile bladeFile = ossBuilder.template().putFile(file.getOriginalFilename(), file.getInputStream());
+
+		//处理PDF文件
+		String originalFilename = "";
 		NewBladeFile newBladeFile = new NewBladeFile();
-//		BeanUtils.copyProperties(bladeFile, newBladeFile);
-		newBladeFile.setPage(pageCount);
+		if(Objects.requireNonNull(file.getOriginalFilename()).contains("xlsx")){
+			originalFilename = file.getOriginalFilename().replaceAll(".xlsx", ".pdf");
+			newBladeFile = this.excelToPdf(originalFilename, file.getInputStream());
+
+		} else if(file.getOriginalFilename().contains("xls")){
+			originalFilename = file.getOriginalFilename().replaceAll(".xls", ".pdf");
+			newBladeFile = this.excelToPdf(originalFilename, file.getInputStream());
+
+		} else if(file.getOriginalFilename().contains("docx")){
+			originalFilename = file.getOriginalFilename().replaceAll(".docx", ".pdf");
+			newBladeFile = this.wordToPdf(originalFilename, file.getInputStream());
 
+		} else if(file.getOriginalFilename().contains("png") || file.getOriginalFilename().contains("jpg")){
+			originalFilename = file.getOriginalFilename().replaceAll(".png", ".pdf").replaceAll(".jpg", ".pdf");
+			newBladeFile = this.pngOrJpgToPdf(originalFilename, file.getInputStream());
+		}
+
+		BeanUtils.copyProperties(bladeFile, newBladeFile);
 		return R.data(newBladeFile);
 	}
 
+	/**
+	 * png 和 jpg 转 pdf
+	 * @param originalFilename 文件名称
+	 * @param is 文件输入流
+	 * @return 上传结果对象
+	 */
+	private NewBladeFile pngOrJpgToPdf(String originalFilename, InputStream is){
+		String pdfFileUrl = "";
+		try{
+			com.itextpdf.text.Document document = new com.itextpdf.text.Document();
+			document.setMargins(0,0,0,0);
+			ByteArrayOutputStream bos = new ByteArrayOutputStream();
+			PdfWriter.getInstance(document, bos);
+			document.open();
+			Image image = Image.getInstance(this.InputStreamToBytes(is));
+			// 设置页面宽高与图片一致
+			document.setPageSize(new Rectangle(image.getScaledWidth(), image.getScaledHeight()));
+			// 图片居中(感觉没啥用)
+			image.setAlignment(Image.ALIGN_CENTER);
+			// 新建一页添加图片
+			document.newPage();
+			document.add(image);
+			document.close();
+
+			//上传文件
+			InputStream pdfInput = new ByteArrayInputStream(bos.toByteArray());
+			BladeFile bladeFile = this.ossBuilder.template().putFile(originalFilename,pdfInput);
+			pdfFileUrl = bladeFile.getLink();
+
+		}catch (Exception e){
+			e.printStackTrace();
+		}
+
+		NewBladeFile newBladeFile = new NewBladeFile();
+		newBladeFile.setPdfUrl(pdfFileUrl);
+		newBladeFile.setPage(1);
+
+		return newBladeFile;
+	}
+
+	/**
+	 * 获取字节数组
+	 */
+	private byte[] InputStreamToBytes(InputStream is) throws IOException {
+		BufferedInputStream bis = new BufferedInputStream(is);
+		ByteArrayOutputStream os = new ByteArrayOutputStream();
+		int date = -1;
+		while ((date = bis.read()) != -1) {
+			os.write(date);
+		}
+		return os.toByteArray();
+	}
+
+	/**
+	 * word 转 pdf
+	 * @param originalFilename 文件名称
+	 * @param is 文件输入流
+	 * @return 上传结果对象
+	 */
+	private NewBladeFile wordToPdf(String originalFilename, InputStream is){
+		String pdfFileUrl = "";
+		int page = 0;
+		try{
+			com.aspose.words.Document document = new com.aspose.words.Document(is);
+
+			DocumentBuilder documentBuilder = new DocumentBuilder(document);
+			com.aspose.words.Font font = documentBuilder.getFont();
+
+			font.setName("宋体");
+
+			ByteArrayOutputStream bos = new ByteArrayOutputStream();
+			document.save(bos,com.aspose.words.SaveFormat.PDF);
+
+			//上传文件
+			InputStream pdfInput = new ByteArrayInputStream(bos.toByteArray());
+			BladeFile bladeFile = this.ossBuilder.template().putFile(originalFilename,pdfInput);
+			pdfFileUrl = bladeFile.getLink();
+
+			//获取页数
+			page = document.getPageCount();
+
+		}catch (Exception e){
+			e.printStackTrace();
+		}
+		NewBladeFile newBladeFile = new NewBladeFile();
+		newBladeFile.setPdfUrl(pdfFileUrl);
+		newBladeFile.setPage(page);
+		return newBladeFile;
+	}
+
+	/**
+	 * excel 转 pdf
+	 * @param originalFilename 文件名称
+	 * @param is 文件输入流
+	 * @return 上传结果对象
+	 */
+	private NewBladeFile excelToPdf(String originalFilename, InputStream is){
+		String pdfFileUrl = "";
+		int page = 0;
+		try{
+			org.apache.poi.ss.usermodel.Workbook ss = WorkbookFactory.create(is);
+
+			for(int i = 0, l = ss.getNumberOfSheets(); i < l; i ++){
+				Sheet sheet = ss.getSheetAt(i);
+				//去掉表格虚线
+				sheet.setPrintGridlines(false);
+				//设置 整个工作表为一页
+				sheet.setFitToPage(true);
+			}
+
+			ByteArrayOutputStream outReport = new ByteArrayOutputStream();
+			ss.write(outReport);
+			com.aspose.cells.Workbook wb = new com.aspose.cells.Workbook(new ByteArrayInputStream(outReport.toByteArray()));
+
+			ByteArrayOutputStream bos = new ByteArrayOutputStream();
+			wb.save(bos, SaveFormat.PDF);
+			bos.flush();
+			//上传文件
+			InputStream pdfInput = new ByteArrayInputStream(bos.toByteArray());
+			BladeFile bladeFile = this.ossBuilder.template().putFile(originalFilename,pdfInput);
+			pdfFileUrl = bladeFile.getLink();
+
+			//获取页数
+			page = wb.getWorksheets().getActiveSheetIndex() + 1;
+
+			bos.close();
+		}catch (Exception e){
+			e.printStackTrace();
+		}
+		NewBladeFile newBladeFile = new NewBladeFile();
+		newBladeFile.setPdfUrl(pdfFileUrl);
+		newBladeFile.setPage(page);
+		return  newBladeFile;
+	}
+
 	/**
 	 * 上传文件
 	 *

+ 35 - 0
blade-ops/blade-resource/src/main/java/org/springblade/resource/feign/NewIOSSClientClient.java

@@ -0,0 +1,35 @@
+package org.springblade.resource.feign;
+
+import lombok.AllArgsConstructor;
+import org.springblade.common.utils.SnowFlakeUtil;
+import org.springblade.core.oss.model.BladeFile;
+import org.springblade.core.tenant.annotation.NonDS;
+import org.springblade.resource.builder.oss.OssBuilder;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+
+@NonDS
+@RestController
+@AllArgsConstructor
+public class NewIOSSClientClient implements NewIOSSClient {
+
+    /**
+     * 对象存储构建类
+     */
+    private final OssBuilder ossBuilder;
+
+    @Override
+    public BladeFile uploadFile(String fileName, String localFileUrl) {
+        try{
+            //获取文件流
+            InputStream inputStream = new FileInputStream(new File(localFileUrl));
+            return this.ossBuilder.template().putFile(fileName, inputStream);
+        }catch (Exception e){
+            e.printStackTrace();
+        }
+        return null;
+    }
+}

+ 6 - 0
blade-service-api/blade-business-api/src/main/java/org/springblade/business/entity/ArchiveFile.java

@@ -80,6 +80,12 @@ public class ArchiveFile extends BaseEntity {
 	@ApiModelProperty("文件路径")
     private String fileUrl;
 
+    /**
+     * PDF文件路径
+     */
+    @ApiModelProperty("PDF文件路径")
+    private String pdfFileUrl;
+
     /**
      * 文件页数
      */

+ 6 - 0
blade-service-api/blade-business-api/src/main/java/org/springblade/business/entity/Task.java

@@ -117,6 +117,12 @@ public class Task extends BaseEntity {
     @ApiModelProperty("类型,1普通任务,2验收任务,3移交任务")
     private Integer type;
 
+    /**
+     * 上报类型,1填报资料,2工程文件
+     */
+    @ApiModelProperty("上报类型,1填报资料,2工程文件")
+    private Integer approvalType;
+
     @ApiModelProperty("项目ID")
     private String projectId;
 

+ 7 - 1
blade-service-api/blade-business-api/src/main/java/org/springblade/business/vo/TaskApprovalVO.java

@@ -21,6 +21,12 @@ public class TaskApprovalVO {
     @ApiModelProperty("待审批列表中对应的parallelProcessInstanceId字段值")
     private String parallelProcessInstanceId;
 
+    @ApiModelProperty("数据源")
+    private String formDataId;
+
+    @ApiModelProperty("上报类型")
+    private Integer approvalType;
+
     @ApiModelProperty("审批意见")
     private String comment;
 
@@ -38,7 +44,7 @@ public class TaskApprovalVO {
     }
 
     @Data
-    private class ApprovalFile {
+    public class ApprovalFile {
 
         private String fileName;
 

+ 8 - 1
blade-service/blade-business/src/main/java/org/springblade/business/controller/ArchiveFileController.java

@@ -99,7 +99,14 @@ public class ArchiveFileController extends BladeController {
 	@ApiOperationSupport(order = 3)
 	@ApiOperation(value = "批量新增")
 	public R<Boolean> batchSave(@RequestBody ArchiveFileVO vo){
-		return R.data(this.archiveFileService.saveBatch(JSONArray.parseArray(JSONObject.toJSONString(vo.getList()), ArchiveFile.class)));
+		List<ArchiveFileVO> saveList = vo.getList();
+		if(saveList != null && saveList.size() > 0){
+			for(ArchiveFileVO saveVo : saveList){
+				saveVo.setStatus(new Integer("0").equals(saveVo.getIsApproval()) ? 2 : 0);
+				saveVo.setIsCertification(new Integer("0").equals(saveVo.getIsNeedCertification()) ? 1 : 0);
+			}
+		}
+		return R.data(this.archiveFileService.saveBatch(JSONArray.parseArray(JSONObject.toJSONString(saveList), ArchiveFile.class)));
 	}
 
 	/**

+ 4 - 0
blade-service/blade-business/src/main/java/org/springblade/business/controller/InformationWriteQueryController.java

@@ -119,6 +119,10 @@ public class InformationWriteQueryController extends BladeController {
 				//如果子节点还是只有一个,则进一步向下查询
 				this.foreachQueryChildNode(child, contractId);
 			}
+			//判断当前节点是否被标记为首件
+			TreeContractFirst first = this.treeContractFirstService.getOne(Wrappers.<TreeContractFirst>lambdaQuery().eq(TreeContractFirst::getIsDeleted, 0).eq(TreeContractFirst::getWbsNodeId, vos.getPrimaryKeyId()));
+			vos.setIsFirst(first != null);
+
 			vos.setChildren(child);
 		});
 	}

+ 100 - 5
blade-service/blade-business/src/main/java/org/springblade/business/controller/TaskController.java

@@ -12,20 +12,26 @@ import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
 import lombok.AllArgsConstructor;
 import org.apache.commons.lang.StringUtils;
 import org.jetbrains.annotations.NotNull;
+import org.springblade.business.entity.ArchiveFile;
 import org.springblade.business.entity.TaskParallel;
+import org.springblade.business.service.IArchiveFileService;
 import org.springblade.business.service.ITaskParallelService;
+import org.springblade.business.utils.FileUtils;
 import org.springblade.business.vo.BatchTaskVO;
 import org.springblade.business.vo.TaskApprovalVO;
 import org.springblade.business.vo.TaskQueryVO;
 import org.springblade.common.utils.CommonUtil;
+import org.springblade.common.utils.SnowFlakeUtil;
 import org.springblade.core.mp.support.Condition;
 import org.springblade.core.mp.support.Query;
+import org.springblade.core.oss.model.BladeFile;
 import org.springblade.core.secure.utils.AuthUtil;
 import org.springblade.core.sms.model.SmsResponse;
 import org.springblade.core.tool.api.R;
 import org.springblade.core.tool.jackson.JsonUtil;
 import org.springblade.flow.core.entity.BladeFlow;
 import org.springblade.flow.core.feign.NewFlowClient;
+import org.springblade.resource.feign.NewIOSSClient;
 import org.springblade.resource.feign.NewISmsClient;
 import org.springblade.system.entity.DictBiz;
 import org.springblade.system.feign.IDictBizClient;
@@ -36,7 +42,6 @@ import org.springblade.business.entity.Task;
 import org.springblade.business.vo.TaskVO;
 import org.springblade.business.service.ITaskService;
 import org.springblade.core.boot.ctrl.BladeController;
-
 import java.util.*;
 import java.util.stream.Collectors;
 
@@ -62,6 +67,44 @@ public class TaskController extends BladeController {
 
 	private final NewISmsClient newSmsClient;
 
+	private final IArchiveFileService archiveFileService;
+
+	private final NewIOSSClient newIOSSClient;
+
+	/**
+	 * 批量审批详情
+	 */
+	@GetMapping
+	@ApiOperationSupport(order = 11)
+	@ApiOperation(value = "批量页详情")
+	@ApiImplicitParams({
+			@ApiImplicitParam(name = "formDataId", value = "数据源", required = true),
+			@ApiImplicitParam(name = "approvalType", value = "上报类型", required = true)
+	})
+	public R<TaskApprovalVO> getBatchApprovalTaskParameter(@RequestParam String formDataId, @RequestParam Integer approvalType){
+		TaskApprovalVO result = new TaskApprovalVO();
+		result.setFormDataId(formDataId);
+		result.setApprovalType(approvalType);
+
+		TaskApprovalVO vo = this.queryBusinessData(result);
+		//所有文件集合
+		List<String> urlList = new ArrayList<>();
+		if(vo != null && vo.getApprovalFileList().size() > 0){
+			vo.getApprovalFileList().forEach(file -> urlList.add(file.getFileUrl()));
+			String fileName = SnowFlakeUtil.getId() + ".pdf";
+			String localImgUrl = "D:/project/file/" + fileName;
+			//合并方法
+			FileUtils.mergePdfPublicMethods(urlList, localImgUrl);
+
+			BladeFile bladeFile = this.newIOSSClient.uploadFile(fileName, localImgUrl);
+			if(bladeFile != null && StringUtils.isNotEmpty(bladeFile.getLink())){
+				result.setApprovalFileList(fileName, bladeFile.getLink());
+			}
+		}
+
+		return R.data(result);
+	}
+
 	/**
 	 * 短信验证
 	 */
@@ -163,6 +206,12 @@ public class TaskController extends BladeController {
 				approvalVO.setParallelProcessInstanceId(parallelProcessInstanceIdArray[i]);
 				approvalVO.setFlag(batchTaskVO.getFlag());
 				approvalVO.setComment(batchTaskVO.getComment());
+				//查询业务数据
+//				TaskApprovalVO vo = this.queryBusinessData(formDataIds[i]);
+//				if(vo != null){
+//					//设置文件集合
+//					approvalVO.setApprovalFileList(vo.getApprovalFileList());
+//				}
 
 				//批量审批
 				this.taskService.completeApprovalTask(approvalVO);
@@ -224,9 +273,15 @@ public class TaskController extends BladeController {
 	@GetMapping("/query-approval-parameter")
 	@ApiOperationSupport(order = 4)
 	@ApiOperation(value = "审批页详情(单任务时)")
-	public R<TaskApprovalVO> getApprovalTaskParameter(String parallelProcessInstanceId){
+	public R<TaskApprovalVO> getApprovalTaskParameter(@RequestParam String parallelProcessInstanceId, @RequestParam String formDataId, @RequestParam Integer approvalType){
+		TaskApprovalVO vo = new TaskApprovalVO();
+		vo.setFormDataId(formDataId);
+		vo.setApprovalType(approvalType);
 
-		return R.data(null);
+		////获取具体业务数据
+		vo = this.queryBusinessData(vo);
+
+		return R.data(vo);
 	}
 
 	/**
@@ -379,6 +434,13 @@ public class TaskController extends BladeController {
 	@ApiOperationSupport(order = 2)
 	@ApiOperation(value = "完成/审批任务")
 	public R<Boolean> completeApprovalTask(@RequestBody TaskApprovalVO taskApprovalVO){
+		//工程文件
+		TaskApprovalVO archiveFileVO = this.queryBusinessData(taskApprovalVO);
+		if(archiveFileVO != null){
+			//获取相关联的pdf
+			taskApprovalVO.setApprovalFileList(archiveFileVO.getApprovalFileList());
+		}
+
 		return R.data(this.taskService.completeApprovalTask(taskApprovalVO));
 	}
 
@@ -389,7 +451,40 @@ public class TaskController extends BladeController {
 	@ApiOperationSupport(order = 1)
 	@ApiOperation(value = "上报", notes = "taskVO对象")
 	public R<Boolean> startApproval(@RequestBody TaskVO taskVO){
-		return R.data(this.taskService.startApproval(taskVO));
+		return this.taskService.startApproval(taskVO) ? R.data(200, true, "操作成功") : R.data(200, false, "操作失败,请联系管理员");
+	}
+
+	/**
+	 * 查询业务数据对外接口
+	 * @param taskApprovalVO 上报信息
+	 */
+	private TaskApprovalVO queryBusinessData(TaskApprovalVO taskApprovalVO){
+		switch (taskApprovalVO.getApprovalType()){
+			case 1:
+				//填报数据
+				return null;
+			case 2:
+				//工程文件
+				return this.queryArchiveFileBusinessData(taskApprovalVO.getFormDataId());
+			default:
+				return null;
+		}
 	}
-	
+
+	/**
+	 * 查询工程文件
+	 */
+	private TaskApprovalVO queryArchiveFileBusinessData(String formDataId){
+		List<ArchiveFile> archiveFileList = this.archiveFileService.list(Wrappers.<ArchiveFile>lambdaQuery().in(ArchiveFile::getId, Arrays.asList(formDataId.split(","))).eq(ArchiveFile::getIsDeleted, 0));
+		if(archiveFileList != null && archiveFileList.size() > 0){
+			//转换数据
+			TaskApprovalVO vo = new TaskApprovalVO();
+			for(ArchiveFile archiveFile : archiveFileList){
+				vo.setApprovalFileList(archiveFile.getFileName(), archiveFile.getPdfFileUrl());
+			}
+			return vo;
+		}
+		return null;
+	}
+
 }

+ 2 - 1
blade-service/blade-business/src/main/java/org/springblade/business/controller/TreeContractFirstController.java

@@ -146,7 +146,8 @@ public class TreeContractFirstController extends BladeController {
 			//检查当前请求的节点是否已经被关联
 			TreeContractFirst firstData = this.treeContractFirstService.getOne(Wrappers.<TreeContractFirst>lambdaQuery().eq(TreeContractFirst::getIsDeleted, 0).eq(TreeContractFirst::getWbsNodeId, primaryKeyId));
 			if(firstData != null){
-				return R.data(JSONArray.parseArray(JSONObject.toJSONString(primaryKeyId), String.class));
+				String[] primaryKeyIds = primaryKeyId.split(",");
+				return R.data(JSONArray.parseArray(JSONObject.toJSONString(primaryKeyIds), String.class));
 			}
 
 			//新增集合

+ 16 - 0
blade-service/blade-business/src/main/java/org/springblade/business/feignClient/ClientTreePublicCodeClientImpl.java

@@ -1,6 +1,9 @@
 package org.springblade.business.feignClient;
 
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import lombok.AllArgsConstructor;
+import org.springblade.business.entity.TreeContractFirst;
+import org.springblade.business.service.ITreeContractFirstService;
 import org.springblade.manager.feign.WbsTreeContractClient;
 import org.springblade.manager.vo.WbsTreeContractTreeVOS;
 import org.springframework.web.bind.annotation.RestController;
@@ -12,6 +15,8 @@ import java.util.List;
 public class ClientTreePublicCodeClientImpl {
 
     private final WbsTreeContractClient wbsTreeContractClient;
+
+    private final ITreeContractFirstService treeContractFirstService;
     
     public List<WbsTreeContractTreeVOS> queryContractWbsTreeByContractIdAndType(String contractId, Integer wbsType, String parentId){
         List<WbsTreeContractTreeVOS> rootTreeNode = this.wbsTreeContractClient.queryContractWbsTreeByContractIdAndType(contractId, wbsType, parentId);
@@ -20,8 +25,19 @@ public class ClientTreePublicCodeClientImpl {
                 //获取一级子节点
                 List<WbsTreeContractTreeVOS> treeNodes = this.wbsTreeContractClient.queryContractWbsTreeByContractIdAndType(contractId, wbsType, vo.getId());
                 if(treeNodes != null && treeNodes.size() != 0){
+                    treeNodes.forEach(child -> {
+                        //判断当前节点是否被标记为首件
+                        TreeContractFirst first = this.treeContractFirstService.getOne(Wrappers.<TreeContractFirst>lambdaQuery().eq(TreeContractFirst::getIsDeleted, 0).eq(TreeContractFirst::getWbsNodeId, child.getPrimaryKeyId()));
+                        child.setIsFirst(first != null);
+                    });
+
                     vo.setChildren(treeNodes);
                 }
+
+                //判断当前节点是否被标记为首件
+                TreeContractFirst first = this.treeContractFirstService.getOne(Wrappers.<TreeContractFirst>lambdaQuery().eq(TreeContractFirst::getIsDeleted, 0).eq(TreeContractFirst::getWbsNodeId, vo.getPrimaryKeyId()));
+                vo.setIsFirst(first != null);
+
             });
         }
         return rootTreeNode;

+ 9 - 8
blade-service/blade-business/src/main/java/org/springblade/business/mapper/ArchiveFileMapper.xml

@@ -24,15 +24,16 @@
         <result column="is_certification" property="isCertification"/>
         <result column="is_need_certification" property="isNeedCertification"/>
         <result column="duty_user" property="dutyUser"/>
+        <result column="pdf_file_url" property="pdfFileUrl"/>
     </resultMap>
 
     <select id="selectArchiveFileCount" resultMap="archiveFileResultMap">
         select count(id) from u_archive_file where is_deleted = 0
-        <if test="vo.status != null">
-            and status = #{vo.status}
+        <if test="vo.isApprovalValue != null and vo.isApprovalValue != ''">
+            and status = #{vo.isApprovalValue}
         </if>
-        <if test="vo.isCertification != null">
-            and is_certification = #{vo.isCertification}
+        <if test="vo.isCertificationValue != null and vo.isCertificationValue != ''">
+            and is_certification = #{vo.isCertificationValue}
         </if>
         <if test="vo.nodeIds != null and vo.nodeIds != ''">
             and node_id in
@@ -44,11 +45,11 @@
 
     <select id="selectArchiveFilePage" resultMap="archiveFileResultMap">
         select * from u_archive_file where is_deleted = 0
-        <if test="vo.status != null">
-            and status = #{vo.status}
+        <if test="vo.isApprovalValue != null and vo.isApprovalValue != ''">
+            and status = #{vo.isApprovalValue}
         </if>
-        <if test="vo.isCertification != null">
-            and is_certification = #{vo.isCertification}
+        <if test="vo.isCertificationValue != null and vo.isCertificationValue != ''">
+            and is_certification = #{vo.isCertificationValue}
         </if>
         <if test="vo.nodeIds != null and vo.nodeIds != ''">
             and node_id in

+ 1 - 0
blade-service/blade-business/src/main/java/org/springblade/business/mapper/TaskMapper.xml

@@ -27,6 +27,7 @@
         <result column="type" property="type"/>
         <result column="project_id" property="projectId"/>
         <result column="contract_id" property="contractId"/>
+        <result column="approval_type" property="approvalType"/>
     </resultMap>
 
     <select id="queryBatchList" resultMap="taskResultMap">

+ 1 - 1
blade-service/blade-business/src/main/java/org/springblade/business/service/impl/ArchiveFileServiceImpl.java

@@ -50,7 +50,7 @@ public class ArchiveFileServiceImpl extends BaseServiceImpl<ArchiveFileMapper, A
 		iPage.setTotal(total);
 		List<ArchiveFileVO> pageVoList = JSONArray.parseArray(JSONObject.toJSONString(pageList), ArchiveFileVO.class);
 		pageVoList.forEach(vos -> {
-			vos.setIsApprovalValue(new Integer("0").equals(vos.getStatus()) ? "未上报" : new Integer("1").equals(vos.getStatus()) ? "待审批" : "已审批");
+			vos.setIsApprovalValue(new Integer("0").equals(vos.getStatus()) ? "未上报" : new Integer("1").equals(vos.getStatus()) ? "待审批" : new Integer("2").equals(vos.getStatus()) ? "已审批" : "已废除");
 			vos.setIsCertificationValue(new Integer("1").equals(vos.getIsCertification()) ? "已认证" : "未认证");
 		});
 

+ 40 - 3
blade-service/blade-business/src/main/java/org/springblade/business/service/impl/TaskServiceImpl.java

@@ -21,10 +21,12 @@ import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang.StringUtils;
 import org.apache.commons.lang.time.DateUtils;
+import org.springblade.business.entity.ArchiveFile;
 import org.springblade.business.entity.FixedFlowLink;
 import org.springblade.business.entity.Task;
 import org.springblade.business.entity.TaskParallel;
 import org.springblade.business.mapper.TaskMapper;
+import org.springblade.business.service.IArchiveFileService;
 import org.springblade.business.service.IFixedFlowLinkService;
 import org.springblade.business.service.ITaskParallelService;
 import org.springblade.business.service.ITaskService;
@@ -50,6 +52,7 @@ import org.springframework.beans.BeanUtils;
 import org.springframework.stereotype.Service;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Date;
 import java.util.List;
 
@@ -72,6 +75,8 @@ public class TaskServiceImpl extends BaseServiceImpl<TaskMapper, Task> implement
 
     private final ITaskParallelService taskParallelService;
 
+    private final IArchiveFileService archiveFileService;
+
     @Override
     public List<Task> queryBatchList(String projectId, String contract) {
         return this.baseMapper.queryBatchList(projectId, contract);
@@ -90,6 +95,9 @@ public class TaskServiceImpl extends BaseServiceImpl<TaskMapper, Task> implement
         }
         //获取当前分支信息
         TaskParallel currentLink = this.taskParallelService.getOne(Wrappers.<TaskParallel>lambdaQuery().eq(TaskParallel::getParallelProcessInstanceId, parallelProcessInstanceId).eq(TaskParallel::getIsDeleted, 0));
+        if(currentLink == null){
+            return false;
+        }
 
         if("OK".equals(taskApprovalVO.getFlag())){
             //同意,执行签章
@@ -99,7 +107,7 @@ public class TaskServiceImpl extends BaseServiceImpl<TaskMapper, Task> implement
             //todo ============================ 执行电签区域 ============================
 
             //电签状态为999(错误状态)的就需要重新提交请求
-            if(!"999".equals(eVisaStatus) && currentLink != null){
+            if(!"999".equals(eVisaStatus)){
                 //完成/审批当前分支流程
                 this.newFlowClient.completeApprovalTask(taskId, parallelProcessInstanceId, comment).getData();
                 //修改分支状态,改为已完成
@@ -119,13 +127,15 @@ public class TaskServiceImpl extends BaseServiceImpl<TaskMapper, Task> implement
                         this.newFlowClient.completeApprovalTask(taskId, task.getProcessInstanceId(), "审批完成");
                         //修改主流程状态为已完成
                         this.update(Wrappers.<Task>lambdaUpdate().set(Task::getStatus, 2).set(Task::getUpdateTime, new Date()).eq(Task::getId, task.getId()));
+                        //修改对应的业务数据状态为已审批
+                        this.updateBusinessDataByFormDataId(task, 2);
                     }
                 }
             } else {
                 System.out.println("循环调用电签");
             }
         } else {
-            //废除,遵循只要某一个分支流程废除,则主流程及其所有分支流程均废除
+            //废除,遵循只要某一个分支流程废除,则主流程废除、其它分支流程均自动结束
             //完成/审批当前分支流程
             this.newFlowClient.completeApprovalTask(taskId, parallelProcessInstanceId, comment).getData();
             //将分支状态更改为已废除
@@ -172,6 +182,8 @@ public class TaskServiceImpl extends BaseServiceImpl<TaskMapper, Task> implement
                 this.newFlowClient.completeApprovalTask(masterTaskId, masterProcessInstanceId, "废除任务");
             }
             this.update(Wrappers.<Task>lambdaUpdate().set(Task::getStatus, 3).set(Task::getUpdateTime, new Date()).eq(Task::getProcessInstanceId, masterProcessInstanceId));
+            //修改对应的业务数据状态为已废除
+            this.updateBusinessDataByFormDataId(this.getOne(Wrappers.<Task>lambdaQuery().eq(Task::getProcessInstanceId, masterProcessInstanceId)), 3);
         }
 
         return true;
@@ -231,7 +243,7 @@ public class TaskServiceImpl extends BaseServiceImpl<TaskMapper, Task> implement
                 Kv variables = Kv.create()
                         //下一步流程审批人
                         .set("taskUser", TaskUtil.getTaskUser(link.getFixedFlowLinkUser().toString()));
-                R<BladeFlow> linkResult = flowClient.startProcessInstanceById(taskFlowId, FlowUtil.getBusinessKey(businessTable, String.valueOf(vo.getId())), variables);
+                R<BladeFlow> linkResult = this.flowClient.startProcessInstanceById(taskFlowId, FlowUtil.getBusinessKey(businessTable, String.valueOf(vo.getId())), variables);
                 if (result.isSuccess()) {
                     log.debug("并行流程已启动,流程ID:" + linkResult.getData().getProcessInstanceId());
                     taskParallelArray.add(new TaskParallel(vo.getProcessInstanceId(), linkResult.getData().getProcessInstanceId(), link.getFixedFlowLinkUser().toString(), link.getFixedFlowLinkUserName()));
@@ -260,4 +272,29 @@ public class TaskServiceImpl extends BaseServiceImpl<TaskMapper, Task> implement
         }
         return true;
     }
+
+    /**
+     * 修改业务数据状态
+     */
+    private void updateBusinessDataByFormDataId(Task task, Integer status){
+        switch (task.getApprovalType()){
+            case 1:
+                //填报数据
+                break;
+            case 2:
+                //工程文件
+                this.updateArchiveFileBusinessDatStatus(task.getFormDataId(), status);
+                break;
+            default:
+                break;
+        }
+    }
+
+    /**
+     * 工程文件
+     */
+    private void updateArchiveFileBusinessDatStatus(String formDataId, Integer status){
+        this.archiveFileService.update(Wrappers.<ArchiveFile>lambdaUpdate().set(ArchiveFile::getStatus, status).in(ArchiveFile::getId, Arrays.asList(formDataId.split(","))));
+    }
+
 }

+ 57 - 0
blade-service/blade-business/src/main/java/org/springblade/business/utils/FileUtils.java

@@ -0,0 +1,57 @@
+package org.springblade.business.utils;
+
+import cfca.com.itextpdf.text.Document;
+import cfca.com.itextpdf.text.pdf.PdfCopy;
+import cfca.com.itextpdf.text.pdf.PdfReader;
+import org.springblade.common.utils.CommonUtil;
+
+import java.io.FileOutputStream;
+import java.util.List;
+
+public class FileUtils {
+
+    /**
+     * 合并方法
+     */
+    public static void mergePdfPublicMethods(List<String> urlList, String localImgUrl){
+        PdfReader reader = null;
+
+        Document doc = new Document();
+        PdfCopy pdfCopy = null;
+        try{
+            pdfCopy = new PdfCopy(doc, new FileOutputStream(localImgUrl));
+            int pageCount;
+            doc.open();
+
+            for(String urlStr : urlList){
+                try{
+                    //获取OSS文件输入流
+                    reader = new PdfReader(CommonUtil.getOSSInputStream(urlStr));
+
+                    pageCount = reader.getNumberOfPages();
+
+                    for(int i = 0; i < pageCount; ++i){
+                        int is = i + 1;
+                        pdfCopy.addPage(pdfCopy.getImportedPage(reader,is));
+                    }
+                }catch (Exception e){
+                    e.printStackTrace();
+                } finally {
+                    if(reader != null){
+                        reader.close();
+                    }
+                }
+            }
+
+        }catch (Exception e){
+            e.printStackTrace();
+        } finally {
+            if(pdfCopy != null){
+                pdfCopy.flush();
+                pdfCopy.close();
+            }
+            doc.close();
+        }
+    }
+
+}