diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/common/constant/CommonConst.java b/pmapi/src/main/java/com/ningdatech/pmapi/common/constant/CommonConst.java index 953d02c..67df739 100644 --- a/pmapi/src/main/java/com/ningdatech/pmapi/common/constant/CommonConst.java +++ b/pmapi/src/main/java/com/ningdatech/pmapi/common/constant/CommonConst.java @@ -39,6 +39,8 @@ public interface CommonConst { String TITLE = "title"; String FILE_NAME_STR = "fileName"; + String FILE_ID_STR = "fileId"; + String ID_STR = "id"; String FILE_LIST = "fileList"; String ITEM_BASED = "依据项:"; String ITEM_BASED_FILE_NAME = "依据文件名:"; diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/common/util/ExcelDownUtil.java b/pmapi/src/main/java/com/ningdatech/pmapi/common/util/ExcelDownUtil.java index bc6f5a3..05e10b6 100644 --- a/pmapi/src/main/java/com/ningdatech/pmapi/common/util/ExcelDownUtil.java +++ b/pmapi/src/main/java/com/ningdatech/pmapi/common/util/ExcelDownUtil.java @@ -46,7 +46,7 @@ import org.assertj.core.util.Lists; @Slf4j public class ExcelDownUtil { - private static String encodeName(String name) { + public static String encodeName(String name) { String fileName; try { fileName = URLEncoder.encode(name, "UTF-8"); diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/filemanage/controller/ProjectFileController.java b/pmapi/src/main/java/com/ningdatech/pmapi/filemanage/controller/ProjectFileController.java index 3bc5a69..f89fe7d 100644 --- a/pmapi/src/main/java/com/ningdatech/pmapi/filemanage/controller/ProjectFileController.java +++ b/pmapi/src/main/java/com/ningdatech/pmapi/filemanage/controller/ProjectFileController.java @@ -12,6 +12,8 @@ import lombok.AllArgsConstructor; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import javax.servlet.http.HttpServletResponse; + /** * @Classname ProjectFileController * @Description @@ -46,4 +48,10 @@ public class ProjectFileController { String instanceId = projectFileManage.startApplyBorrowProcess(projectId); return "启动申请借阅流程实例 【" + instanceId + "】 成功"; } + + @PostMapping("/download/{projectId}") + @ApiOperation(value = "档案下载",notes = "档案下载") + public void downloadFile(@PathVariable Long projectId,HttpServletResponse response){ + projectFileManage.downloadFile(projectId, response); + } } diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/filemanage/manage/ProjectFileManage.java b/pmapi/src/main/java/com/ningdatech/pmapi/filemanage/manage/ProjectFileManage.java index bdba048..3083c8c 100644 --- a/pmapi/src/main/java/com/ningdatech/pmapi/filemanage/manage/ProjectFileManage.java +++ b/pmapi/src/main/java/com/ningdatech/pmapi/filemanage/manage/ProjectFileManage.java @@ -1,14 +1,26 @@ package com.ningdatech.pmapi.filemanage.manage; import cn.hutool.core.collection.CollUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.toolkit.Wrappers; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.google.common.collect.Lists; +import com.ningdatech.basic.exception.BizException; import com.ningdatech.basic.function.VUtils; import com.ningdatech.basic.model.PageVo; +import com.ningdatech.basic.util.CollUtils; +import com.ningdatech.file.entity.File; +import com.ningdatech.file.entity.vo.result.AttachFileVo; +import com.ningdatech.file.service.FileService; +import com.ningdatech.file.utils.StrPool; import com.ningdatech.pmapi.common.constant.BizConst; +import com.ningdatech.pmapi.common.constant.CommonConst; import com.ningdatech.pmapi.common.enumeration.ProjectProcessStageEnum; import com.ningdatech.pmapi.common.helper.UserInfoHelper; +import com.ningdatech.pmapi.common.util.ExcelDownUtil; +import com.ningdatech.pmapi.expert.manage.ExpertReviewManage; +import com.ningdatech.pmapi.expert.model.vo.ExpertReviewDetailVO; +import com.ningdatech.pmapi.expert.model.vo.ProjectReviewDetailVO; import com.ningdatech.pmapi.filemanage.model.entity.ProjectApplyBorrow; import com.ningdatech.pmapi.filemanage.model.param.ProjectFileListParam; import com.ningdatech.pmapi.filemanage.model.vo.ProjectFileListVO; @@ -17,12 +29,18 @@ import com.ningdatech.pmapi.filemanage.service.INdProjectApplyBorrowService; import com.ningdatech.pmapi.organization.model.entity.DingOrganization; import com.ningdatech.pmapi.organization.service.IDingOrganizationService; import com.ningdatech.pmapi.projectdeclared.manage.DefaultDeclaredProjectManage; +import com.ningdatech.pmapi.projectdeclared.model.entity.Contract; +import com.ningdatech.pmapi.projectdeclared.model.entity.Purchase; +import com.ningdatech.pmapi.projectdeclared.service.IContractService; +import com.ningdatech.pmapi.projectdeclared.service.IPurchaseService; import com.ningdatech.pmapi.projectlib.enumeration.InstTypeEnum; import com.ningdatech.pmapi.projectlib.enumeration.ProjectStatusEnum; import com.ningdatech.pmapi.projectlib.manage.ProjectLibManage; import com.ningdatech.pmapi.projectlib.model.entity.Project; +import com.ningdatech.pmapi.projectlib.model.entity.ProjectApplication; import com.ningdatech.pmapi.projectlib.model.entity.ProjectInst; import com.ningdatech.pmapi.projectlib.model.vo.ProjectDetailVO; +import com.ningdatech.pmapi.projectlib.service.IProjectApplicationService; import com.ningdatech.pmapi.projectlib.service.IProjectInstService; import com.ningdatech.pmapi.projectlib.service.IProjectService; import com.ningdatech.pmapi.staging.enums.MsgTypeEnum; @@ -34,20 +52,34 @@ import com.wflow.bean.entity.WflowModels; import com.wflow.contants.HisProInsEndActId; import com.wflow.exception.BusinessException; import com.wflow.workflow.bean.dto.OrgInfoDTO; +import com.wflow.workflow.bean.process.FileBasicInfo; +import com.wflow.workflow.bean.process.ProcessComment; import com.wflow.workflow.bean.vo.ProcessStartParamsVo; import com.wflow.workflow.service.ProcessInstanceService; import com.wflow.workflow.service.ProcessModelService; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; +import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream; +import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.checkerframework.checker.nullness.qual.Nullable; import org.flowable.engine.HistoryService; +import org.flowable.engine.TaskService; import org.flowable.engine.history.HistoricProcessInstance; +import org.flowable.engine.task.Comment; import org.springframework.stereotype.Component; -import java.time.LocalDateTime; +import javax.servlet.http.HttpServletResponse; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; import java.util.*; import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; /** * @Classname ProjectFileManage @@ -71,6 +103,12 @@ public class ProjectFileManage { private final HistoryService historyService; private final INdProjectApplyBorrowService projectApplyBorrowService; private final IDingOrganizationService dingOrganizationService; + private final IProjectApplicationService projectApplicationService; + private final TaskService taskService; + private final IPurchaseService purchaseService; + private final IContractService contractService; + private final ExpertReviewManage expertReviewManage; + private final FileService fileService; public PageVo list(ProjectFileListParam param) { @@ -141,7 +179,7 @@ public class ProjectFileManage { return vo; }).collect(Collectors.toList()); - return PageVo.of(vos, projectList.size()); + return PageVo.of(vos, projects.size()); } private Set getSubOrgList(String empPosUnitCode) { @@ -211,4 +249,227 @@ public class ProjectFileManage { return instanceId; } + + public void downloadFile(Long projectId,HttpServletResponse response) { + Project project = projectService.getById(projectId); + // 获取项目各阶段上传文件ID + List fileIdList = Lists.newArrayList(); + getProjectAppendix(project, fileIdList); + + String zipFileName = "项目档案"; + + // 设置response的header + response.setContentType("application/zip"); + response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + ExcelDownUtil.encodeName(zipFileName) + ".zip"); + //response.setHeader("Content-Disposition", "attachment;filename=" + zipFileName); + + try { + // 创建ZipOutputStream + ZipOutputStream zos = new ZipOutputStream(response.getOutputStream()); + if (CollUtil.isNotEmpty(fileIdList)){ + // 获取文件输入流 + for (Long fileId : fileIdList) { + File file = fileService.getById(fileId); + // 文件不存在,跳过 + if (Objects.isNull(file)){ + continue; + } + String originalFileName = file.getOriginalFileName(); + String name = originalFileName.substring(0, originalFileName.indexOf(StrPool.DOT)); + String fileName = name + StrPool.UNDERSCORE + fileId + originalFileName.substring(originalFileName.indexOf(StrPool.DOT)); + InputStream fileInputStream = fileService.getFileInputStream(file); + // 文件 + ZipEntry zipEntry = new ZipEntry(fileName); + zos.putNextEntry(zipEntry); + byte[] bytes = new byte[1024]; + int length; + while ((length = fileInputStream.read(bytes)) >= 0) { + zos.write(bytes, 0, length); + } + fileInputStream.close(); + zos.closeEntry(); + } + zos.close(); + } + } catch (IOException e) { + throw new BizException(e.getMessage()); + } + } + + private void getProjectAppendix(Project project, List fileIdList) { + Long projectId = project.getId(); + // 项目申报阶段 + // 获取立项依据 + String buildBasis = project.getBuildBasis(); + List buildBasisFileArray = JSON.parseArray(buildBasis, JSONObject.class); + for (JSONObject jsonObject : buildBasisFileArray) { + String fileInfo = jsonObject.getString(CommonConst.FILE_LIST); + List buildBasisFileIdList = getFileIdList(fileInfo); + fileIdList.addAll(buildBasisFileIdList); + } + // 获取附件-初步方案 + String preliminaryPlanFile = project.getPreliminaryPlanFile(); + List prePlanFileIdList = getFileIdList(preliminaryPlanFile); + fileIdList.addAll(prePlanFileIdList); + // 获取附件-佐证材料 + String supMaterialsFile = project.getSupportingMaterialsFile(); + List supMaterialFileIdList = getFileIdList(supMaterialsFile); + fileIdList.addAll(supMaterialFileIdList); + // 获取附件-项目总投资测算明细 + String calTotalInvestFile = project.getCalculationTotalInvestmentFile(); + List calTotalInvestFileIdList = getFileIdList(calTotalInvestFile); + fileIdList.addAll(calTotalInvestFileIdList); + // 获取附件-申报单位主要职责(单位三定方案) + String mainResAppFile = project.getMainResponsibilitiesApplicantFile(); + List mainResAppFileIdList = getFileIdList(mainResAppFile); + fileIdList.addAll(mainResAppFileIdList); + // 获取附件-项目申报书 + String projectApplicationForm = project.getProjectApplicationForm(); + List projectAppFormFileIdList = getFileIdList(projectApplicationForm); + fileIdList.addAll(projectAppFormFileIdList); + // 获取项目应用信息中的文件 + List applicationList = projectApplicationService + .list(Wrappers.lambdaQuery(ProjectApplication.class).eq(ProjectApplication::getProjectId, projectId)); + for (ProjectApplication projectApplication : applicationList) { + // 获取试点文件 + String experimentsFile = projectApplication.getExperimentsFile(); + List experimentsFileIdList = getFileIdList(experimentsFile); + fileIdList.addAll(experimentsFileIdList); + // 获取应用总投资测算明细 + String appEstimateFile = projectApplication.getApplicationEstimateFile(); + List appEstimateFileIdList = getFileIdList(appEstimateFile); + fileIdList.addAll(appEstimateFileIdList); + } + // 流程审核意见文件 + // 获取项目关联的流程实例 + List projectInstList = + projectInstService.list(Wrappers.lambdaQuery(ProjectInst.class).eq(ProjectInst::getProjectId, projectId)); + // 从历史评论表中获取对应流程实例的评论附件信息 + for (ProjectInst projectInst : projectInstList) { + String instanceId = projectInst.getInstCode(); + List commentList = taskService.getProcessInstanceComments(instanceId); + for (Comment comment : commentList) { + ProcessComment processComment = JSONObject.parseObject(comment.getFullMessage(), ProcessComment.class); + List attachments = processComment.getAttachments(); + if (CollUtil.isNotEmpty(attachments)){ + List idList = attachments.stream().map(FileBasicInfo::getFileId).collect(Collectors.toList()); + fileIdList.addAll(idList); + } + } + } + + // 预审申报阶段 + // 预审申报上级条线主管单位审核意见 + String higherLineSuperOrgReviewComments = project.getHigherLineSuperOrgReviewComments(); + if (StringUtils.isNotBlank(higherLineSuperOrgReviewComments)){ + List highSuperOrgFileIdList = getFileIdList(higherLineSuperOrgReviewComments); + fileIdList.addAll(highSuperOrgFileIdList); + } + + // 方案申报阶段 + // 获取建设方案文件 + String constructionPlanFile = project.getConstructionPlanFile(); + JSONObject jsonObject = JSON.parseObject(constructionPlanFile, JSONObject.class); + Long constructFileId = jsonObject.getLong(CommonConst.FILE_ID_STR); + fileIdList.add(constructFileId); + + // 立项批复阶段 + // 获取批复文件 + String approvedFile = project.getApprovedFile(); + fileIdList.add(Long.valueOf(approvedFile)); + // 获取建设方案文件 + String approvedConstructionPlanFile = project.getApprovedConstructionPlanFile(); + fileIdList.add(Long.valueOf(approvedConstructionPlanFile)); + + // 采购结果备案阶段 + Purchase purchase = purchaseService.getOne(Wrappers.lambdaQuery(Purchase.class) + .eq(Purchase::getProjectId, projectId) + .last(BizConst.LIMIT_1)); + // 获取投标文件 + String biddingDoc = purchase.getBiddingDoc(); + List biddingFileIdList = getFileIdList(biddingDoc); + fileIdList.addAll(biddingFileIdList); + // 获取招标文件 + String bidDoc = purchase.getBidDoc(); + List bidFileIdList = getFileIdList(bidDoc); + fileIdList.addAll(bidFileIdList); + // 获取中标通知书 + String acceptanceLetter = purchase.getAcceptanceLetter(); + List acceptFileIdList = getFileIdList(acceptanceLetter); + fileIdList.addAll(acceptFileIdList); + + // 合同备案阶段 + Contract contract = contractService.getOne(Wrappers.lambdaQuery(Contract.class) + .eq(Contract::getProjectId, projectId) + .last(BizConst.LIMIT_1)); + // 获取合同附件 + String attachment = contract.getAttachment(); + List contractFileIdList = getFileIdList(attachment); + fileIdList.addAll(contractFileIdList); + // 初验备案阶段 + // 获取初验材料 + String preliminaryInspectionMaterials = project.getPreliminaryInspectionMaterials(); + getInspectionMaterials(fileIdList, preliminaryInspectionMaterials); + + // 终验申报阶段 + // 获取终验材料 + String finalAcceptanceMaterials = project.getFinalAcceptanceMaterials(); + getInspectionMaterials(fileIdList, finalAcceptanceMaterials); + + // 专家评审记录-如果有初步方案评审会议、部门联审评审会议、建设方案评审会议、验收评审会议对应的附件 + // 获取项目的所有评审意见 + String projectCode = project.getProjectCode(); + ProjectReviewDetailVO projectReviewDetailVO = expertReviewManage.projectExpertReviewDetail(projectCode); + Collection reviews = projectReviewDetailVO.getReviews(); + // 获取最终评审意见附件 + if (CollUtil.isNotEmpty(reviews)) { + List finalReviewFileIdList = reviews.stream().map(r -> { + ExpertReviewDetailVO finalReview = r.getFinalReview(); + return finalReview.getAttachFileId(); + }).collect(Collectors.toList()); + fileIdList.addAll(finalReviewFileIdList); + // 获取组员评审意见 + for (ProjectReviewDetailVO.ReviewDetailByTypeVO review : reviews) { + List teamMemberReviews = review.getTeamMemberReviews(); + for (ExpertReviewDetailVO teamMemberReview : teamMemberReviews) { + Long attachFileId = teamMemberReview.getAttachFileId(); + fileIdList.add(attachFileId); + } + } + } + } + + private void getInspectionMaterials(List fileIdList, String preliminaryInspectionMaterials) { + List fileStrList = JSON.parseArray(preliminaryInspectionMaterials, String.class); + if (CollUtil.isNotEmpty(fileStrList)) { + for (String fileStr : fileStrList) { + JSONObject object = JSON.parseObject(fileStr, JSONObject.class); + String dataStr = object.getString("data"); + List array = JSON.parseArray(dataStr, String.class); + for (String file : array) { + JSONObject fileObject = JSON.parseObject(file, JSONObject.class); + String filesStr = fileObject.getString("files"); + List jsonObjects = JSON.parseArray(filesStr, JSONObject.class); + if (CollUtil.isEmpty(jsonObjects)) { + // 如果没有上传附件,跳过 + continue; + } + for (JSONObject json : jsonObjects) { + String response = json.getString("response"); + JSONObject responseJson = JSON.parseObject(response, JSONObject.class); + String fileData = responseJson.getString("data"); + JSONObject fileInfoObject = JSON.parseObject(fileData, JSONObject.class); + Long fileId = fileInfoObject.getLong("id"); + fileIdList.add(fileId); + } + } + } + } + } + + private List getFileIdList(String buildBasis) { + List prePlanFileArray = JSON.parseArray(buildBasis, JSONObject.class); + List prePlanFileIdList = CollUtils.fieldList(prePlanFileArray, w -> w.getLong(CommonConst.ID_STR)); + return prePlanFileIdList; + } } diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/projectlib/handle/ProjectFinalInspectionHandle.java b/pmapi/src/main/java/com/ningdatech/pmapi/projectlib/handle/ProjectFinalInspectionHandle.java index 8d93f02..0d4265e 100644 --- a/pmapi/src/main/java/com/ningdatech/pmapi/projectlib/handle/ProjectFinalInspectionHandle.java +++ b/pmapi/src/main/java/com/ningdatech/pmapi/projectlib/handle/ProjectFinalInspectionHandle.java @@ -89,7 +89,7 @@ public class ProjectFinalInspectionHandle extends AbstractProcessBusinessHandle processDetailVO.setFinishTime(finishTime); } processDetailVO.setProcessProgressVo(instanceDetail); - processDetailVO.setProcessName(CommonConst.PRELIMINARY_PREVIEW); + processDetailVO.setProcessName(CommonConst.PROJECT_FINAL_INSPECTION); processSchedule.add(processDetailVO); } } diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/projectlib/handle/ProjectPreliminaryInspectionHandle.java b/pmapi/src/main/java/com/ningdatech/pmapi/projectlib/handle/ProjectPreliminaryInspectionHandle.java index beffe7a..38b768a 100644 --- a/pmapi/src/main/java/com/ningdatech/pmapi/projectlib/handle/ProjectPreliminaryInspectionHandle.java +++ b/pmapi/src/main/java/com/ningdatech/pmapi/projectlib/handle/ProjectPreliminaryInspectionHandle.java @@ -74,7 +74,7 @@ public class ProjectPreliminaryInspectionHandle extends AbstractProcessBusinessH .last("limit 1")); processDetailVO.setFinishTime(projectStatusChange.getCreateOn()); } - processDetailVO.setProcessName(CommonConst.TENDER_PURCHASE); + processDetailVO.setProcessName(CommonConst.PROJECT_PRELIMINARY_INSPECTION); processSchedule.add(processDetailVO); } }