未结算报表zip导出
This commit is contained in:
parent
e298c589cf
commit
88d1c12a64
|
|
@ -1,7 +1,9 @@
|
||||||
package com.bonus.material.basic.domain.report;
|
package com.bonus.material.basic.domain.report;
|
||||||
|
|
||||||
|
import com.bonus.material.settlement.domain.SltAgreementInfo;
|
||||||
import io.swagger.annotations.ApiModelProperty;
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
@ -11,6 +13,8 @@ public class DownloadRequest {
|
||||||
private String zipName;
|
private String zipName;
|
||||||
private List<ItemInfo> items;
|
private List<ItemInfo> items;
|
||||||
|
|
||||||
|
private List<SltAgreementInfo> list;
|
||||||
|
|
||||||
private String taskId;
|
private String taskId;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,15 @@ package com.bonus.material.settlement.controller;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.RoundingMode;
|
import java.math.RoundingMode;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URL;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.time.LocalDate;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
@ -21,13 +26,17 @@ import com.bonus.common.biz.config.PoiOutPage;
|
||||||
import com.bonus.common.biz.constant.GlobalConstants;
|
import com.bonus.common.biz.constant.GlobalConstants;
|
||||||
|
|
||||||
import com.bonus.common.biz.utils.RequestContext;
|
import com.bonus.common.biz.utils.RequestContext;
|
||||||
|
import com.bonus.common.biz.utils.StringHelper;
|
||||||
import com.bonus.common.core.exception.ServiceException;
|
import com.bonus.common.core.exception.ServiceException;
|
||||||
import com.bonus.common.core.utils.ServletUtils;
|
import com.bonus.common.core.utils.ServletUtils;
|
||||||
import com.bonus.common.log.enums.OperaType;
|
import com.bonus.common.log.enums.OperaType;
|
||||||
import com.bonus.common.log.enums.OperatorType;
|
import com.bonus.common.log.enums.OperatorType;
|
||||||
import com.bonus.material.basic.domain.BmProject;
|
import com.bonus.material.basic.domain.BmProject;
|
||||||
|
import com.bonus.material.basic.domain.dto.DownloadProgress;
|
||||||
|
import com.bonus.material.basic.domain.report.DownloadRequest;
|
||||||
import com.bonus.material.common.annotation.PreventRepeatSubmit;
|
import com.bonus.material.common.annotation.PreventRepeatSubmit;
|
||||||
import com.bonus.material.common.domain.dto.SelectDto;
|
import com.bonus.material.common.domain.dto.SelectDto;
|
||||||
|
import com.bonus.material.common.utils.DocxUtil;
|
||||||
import com.bonus.material.part.domain.PartLeaseInfo;
|
import com.bonus.material.part.domain.PartLeaseInfo;
|
||||||
import com.bonus.material.settlement.domain.*;
|
import com.bonus.material.settlement.domain.*;
|
||||||
import com.bonus.material.settlement.domain.dto.ExportProgressManager;
|
import com.bonus.material.settlement.domain.dto.ExportProgressManager;
|
||||||
|
|
@ -42,12 +51,18 @@ import io.swagger.annotations.Api;
|
||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.collections4.CollectionUtils;
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.apache.commons.compress.archivers.zip.Zip64Mode;
|
||||||
|
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
|
||||||
|
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
|
||||||
import org.apache.commons.io.FileUtils;
|
import org.apache.commons.io.FileUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.poi.hssf.usermodel.*;
|
import org.apache.poi.hssf.usermodel.*;
|
||||||
import org.apache.poi.ss.formula.functions.T;
|
import org.apache.poi.ss.formula.functions.T;
|
||||||
|
import org.apache.poi.util.IOUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import com.bonus.common.log.annotation.SysLog;
|
import com.bonus.common.log.annotation.SysLog;
|
||||||
|
|
@ -60,6 +75,7 @@ import com.bonus.common.core.utils.poi.ExcelUtil;
|
||||||
import com.bonus.common.core.web.page.TableDataInfo;
|
import com.bonus.common.core.web.page.TableDataInfo;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.zip.Deflater;
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipOutputStream;
|
import java.util.zip.ZipOutputStream;
|
||||||
|
|
||||||
|
|
@ -93,6 +109,7 @@ public class SltAgreementInfoController extends BaseController {
|
||||||
@Autowired
|
@Autowired
|
||||||
private ExportProgressManager exportProgressManager;
|
private ExportProgressManager exportProgressManager;
|
||||||
|
|
||||||
|
private static final Map<String, DownloadProgress> downloadProgressMap = new ConcurrentHashMap<>();
|
||||||
/**
|
/**
|
||||||
* 查询结算信息列表
|
* 查询结算信息列表
|
||||||
*/
|
*/
|
||||||
|
|
@ -2028,236 +2045,6 @@ public class SltAgreementInfoController extends BaseController {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// /**
|
|
||||||
// * 一键批量导出未结算报表(zip)
|
|
||||||
// */
|
|
||||||
// @ApiOperation(value = "一键批量导出未结算报表")
|
|
||||||
// @PreventRepeatSubmit
|
|
||||||
// @SysLog(title = "结算信息", businessType = OperaType.EXPORT, logType = 1,module = "结算管理->一键批量导出未结算报表")
|
|
||||||
// @PostMapping("/exportUnsettled")
|
|
||||||
// public void exportUnsettled(HttpServletResponse response, @RequestBody List<SltAgreementInfo> list) throws Exception {
|
|
||||||
// // 创建临时文件夹
|
|
||||||
// String tempDir = System.getProperty("java.io.tmpdir") + File.separator + UUID.randomUUID();
|
|
||||||
// new File(tempDir).mkdirs();
|
|
||||||
//
|
|
||||||
// try {
|
|
||||||
// for(SltAgreementInfo info : list){
|
|
||||||
// if(info.getAgreementId() == null){
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
// //根据协议id获取结算单位和结算工程
|
|
||||||
// SltAgreementInfo agreementInfo = sltAgreementInfoMapper.getUnitAndProjectByAgreementId(info.getAgreementId());
|
|
||||||
// // 生成文件名
|
|
||||||
// String fileName = "";
|
|
||||||
// String unitName = "";
|
|
||||||
// String projectName = "";
|
|
||||||
// // 清理非法字符(Windows文件名不允许: \ / : * ? " < > |)
|
|
||||||
// unitName = cleanFileName(agreementInfo.getUnitName());
|
|
||||||
// projectName = cleanFileName(agreementInfo.getProjectName());
|
|
||||||
// String agreementCode = cleanFileName(agreementInfo.getAgreementCode());
|
|
||||||
//
|
|
||||||
// // 构建安全的文件名(限制总长度不超过150字符)
|
|
||||||
// String rawFileName = agreementCode + "-" + unitName + "-" + projectName + "_结算单.xls";
|
|
||||||
// fileName = rawFileName.length() > 150 ?
|
|
||||||
// rawFileName.substring(0, 150) + ".xls" : rawFileName;
|
|
||||||
//
|
|
||||||
// //租赁费用明细
|
|
||||||
// BigDecimal totalCostLease = BigDecimal.valueOf(0.00);
|
|
||||||
// List<SltAgreementInfo> leaseList = new ArrayList<>();
|
|
||||||
// leaseList = sltAgreementInfoMapper.getLeaseList(info);
|
|
||||||
//
|
|
||||||
// for (SltAgreementInfo bean : leaseList) {
|
|
||||||
// if (null == bean.getLeasePrice()) {
|
|
||||||
// bean.setLeasePrice(BigDecimal.valueOf(0.00));
|
|
||||||
// }
|
|
||||||
// if (null == bean.getNum()) {
|
|
||||||
// bean.setNum(BigDecimal.valueOf(0L));
|
|
||||||
// }
|
|
||||||
// if (null == bean.getLeaseDays()) {
|
|
||||||
// bean.setLeaseDay(0L);
|
|
||||||
// }
|
|
||||||
// BigDecimal leasePrice = bean.getLeasePrice();
|
|
||||||
// BigDecimal num = bean.getNum();
|
|
||||||
// BigDecimal leaseDays = new BigDecimal(bean.getLeaseDays());
|
|
||||||
// BigDecimal costs = leasePrice.multiply(num).multiply(leaseDays);
|
|
||||||
// if(costs!=null){
|
|
||||||
// totalCostLease = totalCostLease.add(costs);
|
|
||||||
// }
|
|
||||||
// bean.setCosts(costs);
|
|
||||||
// }
|
|
||||||
// List<SltLeaseInfo> lease = Convert.toList(SltLeaseInfo.class, leaseList);
|
|
||||||
//
|
|
||||||
// //丢失费用明细
|
|
||||||
// BigDecimal totalCostLose = BigDecimal.valueOf(0.00);
|
|
||||||
// List<SltAgreementInfo> loseList = new ArrayList<>();
|
|
||||||
//
|
|
||||||
// loseList = sltAgreementInfoMapper.getLoseList(info);
|
|
||||||
//
|
|
||||||
// for (SltAgreementInfo bean : loseList) {
|
|
||||||
// if (null == bean.getBuyPrice()) {
|
|
||||||
// bean.setBuyPrice(BigDecimal.valueOf(0.00));
|
|
||||||
// }
|
|
||||||
// if (null == bean.getNum()) {
|
|
||||||
// bean.setNum(BigDecimal.valueOf(0L));
|
|
||||||
// }
|
|
||||||
// BigDecimal buyPrice = bean.getBuyPrice();
|
|
||||||
// BigDecimal num = bean.getNum();
|
|
||||||
// // 原价 x 数量
|
|
||||||
// BigDecimal costs = buyPrice.multiply(num);
|
|
||||||
// if(costs!=null){
|
|
||||||
// totalCostLose = totalCostLose.add(costs);
|
|
||||||
// }
|
|
||||||
// //计算租赁费用
|
|
||||||
// bean.setCosts(costs);
|
|
||||||
// }
|
|
||||||
// List<SltLeaseInfo> lose = Convert.toList(SltLeaseInfo.class, loseList);
|
|
||||||
//
|
|
||||||
// //维修费用明细
|
|
||||||
// BigDecimal totalCostRepair = BigDecimal.valueOf(0.00);
|
|
||||||
// List<SltAgreementInfo> repairList = new ArrayList<>();
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// List<TmTask> taskRepairList = taskMapper.getTaskIdList(info);
|
|
||||||
// List<TmTask> taskRepairList2 = new ArrayList<>();
|
|
||||||
// taskRepairList2 = checkTeamAgreementInfo(info);
|
|
||||||
// if (null != taskRepairList && !taskRepairList.isEmpty()) {
|
|
||||||
// if (null != taskRepairList2 && !taskRepairList2.isEmpty()) {
|
|
||||||
// taskRepairList.addAll(taskRepairList2);
|
|
||||||
// }
|
|
||||||
// repairList = sltAgreementInfoMapper.getRepairDetailsList(info, taskRepairList);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// for (SltAgreementInfo bean : repairList) {
|
|
||||||
// if (bean.getCosts()!=null && (bean.getPartType().equals("收费"))) {
|
|
||||||
// totalCostRepair = totalCostRepair.add(bean.getCosts());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// List<SltLeaseInfo> repair = Convert.toList(SltLeaseInfo.class, repairList);
|
|
||||||
//
|
|
||||||
// //报废费用明细
|
|
||||||
// BigDecimal totalCostScrap = BigDecimal.valueOf(0.00);
|
|
||||||
// List<SltAgreementInfo> scrapList = new ArrayList<>();
|
|
||||||
//
|
|
||||||
// List<TmTask> taskScrapList = taskMapper.getTaskIdList(info);
|
|
||||||
//
|
|
||||||
// List<TmTask> taskScrapList2 = new ArrayList<>();
|
|
||||||
// taskScrapList2 = checkTeamAgreementInfo(info);
|
|
||||||
//
|
|
||||||
// if (null != taskScrapList && !taskScrapList.isEmpty()) {
|
|
||||||
//
|
|
||||||
// if (null != taskScrapList2 && !taskScrapList2.isEmpty()) {
|
|
||||||
// taskScrapList.addAll(taskScrapList2);
|
|
||||||
// }
|
|
||||||
// scrapList = sltAgreementInfoMapper.getScrapDetailsList(info, taskScrapList);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// for (SltAgreementInfo bean : scrapList) {
|
|
||||||
// if (bean.getCosts()!=null && (bean.getPartType().equals("收费"))) {
|
|
||||||
// totalCostScrap = totalCostScrap.add(bean.getCosts());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// List<SltLeaseInfo> scrap = Convert.toList(SltLeaseInfo.class, scrapList);
|
|
||||||
//
|
|
||||||
// //减免费用明细
|
|
||||||
// BigDecimal totalCostReduction = BigDecimal.valueOf(0.00);
|
|
||||||
// List<SltAgreementReduce> reductionList = new ArrayList<>();
|
|
||||||
//
|
|
||||||
// if (info.getAgreementId() != null){
|
|
||||||
// SltAgreementReduce bean =new SltAgreementReduce();
|
|
||||||
// bean.setAgreementId(info.getAgreementId());
|
|
||||||
// reductionList = sltAgreementRecudceMapper.getReductionList(bean);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// for (SltAgreementReduce reduction : reductionList) {
|
|
||||||
// if(reduction.getLeaseMoney()!=null){
|
|
||||||
// totalCostReduction = totalCostReduction.add(reduction.getLeaseMoney());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// List<SltLeaseInfo> reduction = Convert.toList(SltLeaseInfo.class, reductionList);
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// List<Map<String, Object>> resultsLease = new ArrayList<>();
|
|
||||||
// List<Map<String, Object>> resultsLose = new ArrayList<>();
|
|
||||||
// List<Map<String, Object>> resultsRepair = new ArrayList<>();
|
|
||||||
// List<Map<String, Object>> resultsScrap = new ArrayList<>();
|
|
||||||
// List<Map<String, Object>> resultsReduction = new ArrayList<>();
|
|
||||||
// if (lease!= null) {
|
|
||||||
// for (SltLeaseInfo bean : lease) {
|
|
||||||
// Map<String, Object> maps = outReceiveDetailsBeanToMap(bean, 1, 1);
|
|
||||||
// resultsLease.add(maps);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// if (lose!= null) {
|
|
||||||
// for (SltLeaseInfo bean : lose) {
|
|
||||||
// Map<String, Object> maps = outReceiveDetailsBeanToMap(bean, 2, 1);
|
|
||||||
// resultsLose.add(maps);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// if (repair!= null) {
|
|
||||||
// for (SltLeaseInfo bean : repair) {
|
|
||||||
// Map<String, Object> maps = outReceiveDetailsBeanToMap(bean, 3, 1);
|
|
||||||
// resultsRepair.add(maps);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// if (scrap!= null) {
|
|
||||||
// for (SltLeaseInfo bean : scrap) {
|
|
||||||
// Map<String, Object> maps = outReceiveDetailsBeanToMap(bean, 4, 1);
|
|
||||||
// resultsScrap.add(maps);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// if (reduction!= null) {
|
|
||||||
// for (SltLeaseInfo bean : reduction) {
|
|
||||||
// Map<String, Object> maps = outReceiveDetailsBeanToMap(bean, 5, 1);
|
|
||||||
// resultsReduction.add(maps);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// List<String> headersLease = receiveDetailsHeader(1,1);
|
|
||||||
// List<String> headersLose = receiveDetailsHeader(2,1);
|
|
||||||
// List<String> headersRepair = receiveDetailsHeader(3,1);
|
|
||||||
// List<String> headersScrap = receiveDetailsHeader(4,1);
|
|
||||||
// List<String> headersReduction = receiveDetailsHeader(5,1);
|
|
||||||
//
|
|
||||||
//// fileName = agreementInfo.getAgreementCode() + "-" + unitName + "-" + projectName+ "_结算单.xls" ;
|
|
||||||
// // 导出单个Excel文件
|
|
||||||
// String filePath = tempDir + File.separator + fileName;
|
|
||||||
// try (FileOutputStream fos = new FileOutputStream(filePath)) {
|
|
||||||
// HSSFWorkbook workbook = PoiOutPage.excelForcheckAll(resultsLease,resultsLose,resultsRepair,resultsScrap,resultsReduction, headersLease,headersLose,headersRepair,headersScrap,headersReduction, "结算明细",projectName,unitName,totalCostLease,totalCostLose,totalCostRepair,totalCostScrap,totalCostReduction);
|
|
||||||
// workbook.write(fos);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
// // 创建压缩包
|
|
||||||
// String zipFileName = "结算单_" + new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + ".zip";
|
|
||||||
// response.setContentType("application/zip");
|
|
||||||
// response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(zipFileName, "UTF-8"));
|
|
||||||
//
|
|
||||||
// try (ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream())) {
|
|
||||||
// File[] files = new File(tempDir).listFiles();
|
|
||||||
// if (files != null) {
|
|
||||||
// for (File file : files) {
|
|
||||||
// zipOut.putNextEntry(new ZipEntry(file.getName()));
|
|
||||||
// try (FileInputStream fis = new FileInputStream(file)) {
|
|
||||||
// byte[] buffer = new byte[1024];
|
|
||||||
// int len;
|
|
||||||
// while ((len = fis.read(buffer)) > 0) {
|
|
||||||
// zipOut.write(buffer, 0, len);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// zipOut.closeEntry();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// } catch (Exception e) {
|
|
||||||
// log.error("一键批量导出未结算报表失败", e);
|
|
||||||
// } finally {
|
|
||||||
// // 删除临时文件
|
|
||||||
// FileUtils.deleteDirectory(new File(tempDir));
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
/************************************************************************/
|
|
||||||
/**
|
/**
|
||||||
* 一键批量导出未结算报表(zip)
|
* 一键批量导出未结算报表(zip)
|
||||||
*/
|
*/
|
||||||
|
|
@ -2265,120 +2052,12 @@ public class SltAgreementInfoController extends BaseController {
|
||||||
@PreventRepeatSubmit
|
@PreventRepeatSubmit
|
||||||
@SysLog(title = "结算信息", businessType = OperaType.EXPORT, logType = 1,module = "结算管理->一键批量导出未结算报表")
|
@SysLog(title = "结算信息", businessType = OperaType.EXPORT, logType = 1,module = "结算管理->一键批量导出未结算报表")
|
||||||
@PostMapping("/exportUnsettled")
|
@PostMapping("/exportUnsettled")
|
||||||
public ResponseEntity<Map<String, String>> exportUnsettled(HttpServletResponse response, @RequestBody List<SltAgreementInfo> list) throws Exception {
|
public void exportUnsettled(HttpServletResponse response, @RequestBody List<SltAgreementInfo> list) throws Exception {
|
||||||
|
// 创建临时文件夹
|
||||||
// 生成任务ID
|
String tempDir = System.getProperty("java.io.tmpdir") + File.separator + UUID.randomUUID();
|
||||||
String taskId = UUID.randomUUID().toString();
|
|
||||||
|
|
||||||
// 初始化进度
|
|
||||||
exportProgressManager.initProgress(taskId, list.size());
|
|
||||||
|
|
||||||
// 异步执行导出任务
|
|
||||||
CompletableFuture.runAsync(() -> {
|
|
||||||
try {
|
|
||||||
executeExport(taskId, list);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("导出任务执行失败, taskId: {}", taskId, e);
|
|
||||||
exportProgressManager.errorProgress(taskId, "导出失败: " + e.getMessage());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 立即返回任务ID
|
|
||||||
Map<String, String> result = new HashMap<>();
|
|
||||||
result.put("taskId", taskId);
|
|
||||||
result.put("message", "导出任务已开始,请通过taskId查询进度");
|
|
||||||
result.put("total", String.valueOf(list.size()));
|
|
||||||
return ResponseEntity.ok(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@ApiOperation(value = "查询导出进度")
|
|
||||||
@PostMapping("/exZipProgress")
|
|
||||||
public ResponseEntity<ExportProgressManager.ExportProgress> getExportProgress(@RequestBody SltAgreementInfo info) {
|
|
||||||
String taskId = info.getTaskId();
|
|
||||||
ExportProgressManager.ExportProgress progress = exportProgressManager.getProgress(taskId);
|
|
||||||
if (progress == null) {
|
|
||||||
return ResponseEntity.notFound().build();
|
|
||||||
}
|
|
||||||
return ResponseEntity.ok(progress);
|
|
||||||
}
|
|
||||||
|
|
||||||
@ApiOperation(value = "下载导出文件")
|
|
||||||
@PostMapping("/dlExProgress")
|
|
||||||
public void downloadExportFile(@RequestBody SltAgreementInfo info, HttpServletResponse response) {
|
|
||||||
try {
|
|
||||||
ExportProgressManager.ExportProgress progress = exportProgressManager.getProgress(info.getTaskId());
|
|
||||||
if (progress == null || !"completed".equals(progress.getStatus())) {
|
|
||||||
response.setStatus(HttpStatus.NOT_FOUND.value());
|
|
||||||
response.getWriter().write("文件不存在或导出未完成");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
File file = new File(progress.getFileUrl());
|
|
||||||
if (!file.exists()) {
|
|
||||||
response.setStatus(HttpStatus.NOT_FOUND.value());
|
|
||||||
response.getWriter().write("文件不存在");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
String fileName = "结算单_" + new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + ".zip";
|
|
||||||
response.setContentType("application/zip");
|
|
||||||
response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8"));
|
|
||||||
|
|
||||||
try (FileInputStream fis = new FileInputStream(file);
|
|
||||||
OutputStream os = response.getOutputStream()) {
|
|
||||||
byte[] buffer = new byte[1024];
|
|
||||||
int len;
|
|
||||||
while ((len = fis.read(buffer)) > 0) {
|
|
||||||
os.write(buffer, 0, len);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("下载文件失败, taskId: {}", info.getTaskId(), e);
|
|
||||||
try {
|
|
||||||
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
|
|
||||||
response.getWriter().write("下载失败: " + e.getMessage());
|
|
||||||
} catch (IOException ex) {
|
|
||||||
log.error("写入响应失败", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@ApiOperation(value = "清理导出任务")
|
|
||||||
@DeleteMapping("/cleanExport/{taskId}")
|
|
||||||
public ResponseEntity<Map<String, String>> cleanExportTask(@PathVariable String taskId) {
|
|
||||||
try {
|
|
||||||
ExportProgressManager.ExportProgress progress = exportProgressManager.getProgress(taskId);
|
|
||||||
if (progress != null && progress.getFileUrl() != null) {
|
|
||||||
File file = new File(progress.getFileUrl());
|
|
||||||
if (file.exists()) {
|
|
||||||
file.delete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exportProgressManager.removeProgress(taskId);
|
|
||||||
|
|
||||||
Map<String, String> result = new HashMap<>();
|
|
||||||
result.put("message", "任务清理成功");
|
|
||||||
return ResponseEntity.ok(result);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("清理任务失败, taskId: {}", taskId, e);
|
|
||||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 执行导出任务的核心方法
|
|
||||||
*/
|
|
||||||
private void executeExport(String taskId, List<SltAgreementInfo> list) throws Exception {
|
|
||||||
String tempDir = System.getProperty("java.io.tmpdir") + File.separator + "export_" + taskId;
|
|
||||||
String zipFilePath = System.getProperty("java.io.tmpdir") + File.separator + "export_" + taskId + ".zip";
|
|
||||||
|
|
||||||
new File(tempDir).mkdirs();
|
new File(tempDir).mkdirs();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
int processed = 0;
|
|
||||||
for(SltAgreementInfo info : list){
|
for(SltAgreementInfo info : list){
|
||||||
if(info.getAgreementId() == null){
|
if(info.getAgreementId() == null){
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -2565,33 +2244,315 @@ public class SltAgreementInfoController extends BaseController {
|
||||||
workbook.write(fos);
|
workbook.write(fos);
|
||||||
}
|
}
|
||||||
|
|
||||||
processed++;
|
|
||||||
exportProgressManager.updateProgress(taskId, 1);
|
|
||||||
|
|
||||||
// 每处理完一个文件,短暂休息以避免资源过度占用
|
|
||||||
Thread.sleep(100);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建压缩包
|
// 创建压缩包
|
||||||
createZipFile(tempDir, zipFilePath);
|
String zipFileName = "结算单_" + new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + ".zip";
|
||||||
|
response.setContentType("application/zip");
|
||||||
|
response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(zipFileName, "UTF-8"));
|
||||||
|
|
||||||
// 标记任务完成
|
try (ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream())) {
|
||||||
exportProgressManager.completeProgress(taskId, zipFilePath);
|
File[] files = new File(tempDir).listFiles();
|
||||||
|
if (files != null) {
|
||||||
} catch (Exception e) {
|
for (File file : files) {
|
||||||
exportProgressManager.errorProgress(taskId, "导出过程发生错误: " + e.getMessage());
|
zipOut.putNextEntry(new ZipEntry(file.getName()));
|
||||||
throw e;
|
try (FileInputStream fis = new FileInputStream(file)) {
|
||||||
} finally {
|
byte[] buffer = new byte[1024];
|
||||||
// 清理临时文件夹,但保留zip文件
|
int len;
|
||||||
try {
|
while ((len = fis.read(buffer)) > 0) {
|
||||||
FileUtils.deleteDirectory(new File(tempDir));
|
zipOut.write(buffer, 0, len);
|
||||||
} catch (IOException e) {
|
}
|
||||||
log.warn("清理临时文件夹失败: {}", e.getMessage());
|
}
|
||||||
|
zipOut.closeEntry();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("一键批量导出未结算报表失败", e);
|
||||||
|
} finally {
|
||||||
|
// 删除临时文件
|
||||||
|
FileUtils.deleteDirectory(new File(tempDir));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ApiOperation(value = "下载导出文件")
|
||||||
|
@PostMapping("/dlExProgress")
|
||||||
|
public void downloadExportFile(@RequestBody DownloadRequest request,HttpServletResponse response) throws IOException {
|
||||||
|
String taskId = request.getTaskId() != null ? request.getTaskId() : UUID.randomUUID().toString();
|
||||||
|
String zipName = request.getZipName() != null ? request.getZipName() : "未结算批量明细导出_" + LocalDate.now();
|
||||||
|
|
||||||
|
// 初始化进度
|
||||||
|
DownloadProgress progress = new DownloadProgress();
|
||||||
|
progress.setTotalFiles(request.getList().size());
|
||||||
|
progress.setStatus("processing");
|
||||||
|
progress.setStartTime(System.currentTimeMillis());
|
||||||
|
downloadProgressMap.put(taskId, progress);
|
||||||
|
|
||||||
|
try {
|
||||||
|
String encoded = java.net.URLEncoder.encode(zipName + ".zip", "UTF-8");
|
||||||
|
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename*=UTF-8''" + encoded);
|
||||||
|
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
|
||||||
|
|
||||||
|
// 设置流式传输相关头部
|
||||||
|
response.setHeader("Transfer-Encoding", "chunked");
|
||||||
|
response.setHeader("X-Content-Type-Options", "nosniff");
|
||||||
|
|
||||||
|
// 使用低压缩级别提高速度
|
||||||
|
try (ZipArchiveOutputStream zipOut = new ZipArchiveOutputStream(response.getOutputStream())) {
|
||||||
|
zipOut.setLevel(Deflater.BEST_SPEED);
|
||||||
|
zipOut.setEncoding("UTF-8");
|
||||||
|
zipOut.setUseZip64(Zip64Mode.AsNeeded);
|
||||||
|
|
||||||
|
AtomicInteger fileCount = new AtomicInteger(0);
|
||||||
|
|
||||||
|
|
||||||
|
for(SltAgreementInfo info : request.getList()){
|
||||||
|
if(info.getAgreementId() == null){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新进度
|
||||||
|
progress.setCurrentFileName("正在生成: " + info.getAgreementCode());
|
||||||
|
progress.setCurrentFile(fileCount.incrementAndGet());
|
||||||
|
progress.setPercentage((int)((fileCount.get() * 100.0) / progress.getTotalFiles()));
|
||||||
|
updateProgress(taskId, progress);
|
||||||
|
|
||||||
|
|
||||||
|
//根据协议id获取结算单位和结算工程
|
||||||
|
SltAgreementInfo agreementInfo = sltAgreementInfoMapper.getUnitAndProjectByAgreementId(info.getAgreementId());
|
||||||
|
// 生成文件名
|
||||||
|
String fileName = "";
|
||||||
|
String unitName = "";
|
||||||
|
String projectName = "";
|
||||||
|
// 清理非法字符(Windows文件名不允许: \ / : * ? " < > |)
|
||||||
|
unitName = cleanFileName(agreementInfo.getUnitName());
|
||||||
|
projectName = cleanFileName(agreementInfo.getProjectName());
|
||||||
|
String agreementCode = cleanFileName(agreementInfo.getAgreementCode());
|
||||||
|
|
||||||
|
// 构建安全的文件名(限制总长度不超过150字符)
|
||||||
|
String rawFileName = agreementCode + "-" + unitName + "-" + projectName + "_结算单.xls";
|
||||||
|
fileName = rawFileName.length() > 150 ?
|
||||||
|
rawFileName.substring(0, 150) + ".xls" : rawFileName;
|
||||||
|
|
||||||
|
//租赁费用明细
|
||||||
|
BigDecimal totalCostLease = BigDecimal.valueOf(0.00);
|
||||||
|
List<SltAgreementInfo> leaseList = new ArrayList<>();
|
||||||
|
leaseList = sltAgreementInfoMapper.getLeaseList(info);
|
||||||
|
|
||||||
|
for (SltAgreementInfo bean : leaseList) {
|
||||||
|
if (null == bean.getLeasePrice()) {
|
||||||
|
bean.setLeasePrice(BigDecimal.valueOf(0.00));
|
||||||
|
}
|
||||||
|
if (null == bean.getNum()) {
|
||||||
|
bean.setNum(BigDecimal.valueOf(0L));
|
||||||
|
}
|
||||||
|
if (null == bean.getLeaseDays()) {
|
||||||
|
bean.setLeaseDay(0L);
|
||||||
|
}
|
||||||
|
BigDecimal leasePrice = bean.getLeasePrice();
|
||||||
|
BigDecimal num = bean.getNum();
|
||||||
|
BigDecimal leaseDays = new BigDecimal(bean.getLeaseDays());
|
||||||
|
BigDecimal costs = leasePrice.multiply(num).multiply(leaseDays);
|
||||||
|
if(costs!=null){
|
||||||
|
totalCostLease = totalCostLease.add(costs);
|
||||||
|
}
|
||||||
|
bean.setCosts(costs);
|
||||||
|
}
|
||||||
|
List<SltLeaseInfo> lease = Convert.toList(SltLeaseInfo.class, leaseList);
|
||||||
|
|
||||||
|
//丢失费用明细
|
||||||
|
BigDecimal totalCostLose = BigDecimal.valueOf(0.00);
|
||||||
|
List<SltAgreementInfo> loseList = new ArrayList<>();
|
||||||
|
|
||||||
|
loseList = sltAgreementInfoMapper.getLoseList(info);
|
||||||
|
|
||||||
|
for (SltAgreementInfo bean : loseList) {
|
||||||
|
if (null == bean.getBuyPrice()) {
|
||||||
|
bean.setBuyPrice(BigDecimal.valueOf(0.00));
|
||||||
|
}
|
||||||
|
if (null == bean.getNum()) {
|
||||||
|
bean.setNum(BigDecimal.valueOf(0L));
|
||||||
|
}
|
||||||
|
BigDecimal buyPrice = bean.getBuyPrice();
|
||||||
|
BigDecimal num = bean.getNum();
|
||||||
|
// 原价 x 数量
|
||||||
|
BigDecimal costs = buyPrice.multiply(num);
|
||||||
|
if(costs!=null){
|
||||||
|
totalCostLose = totalCostLose.add(costs);
|
||||||
|
}
|
||||||
|
//计算租赁费用
|
||||||
|
bean.setCosts(costs);
|
||||||
|
}
|
||||||
|
List<SltLeaseInfo> lose = Convert.toList(SltLeaseInfo.class, loseList);
|
||||||
|
|
||||||
|
//维修费用明细
|
||||||
|
BigDecimal totalCostRepair = BigDecimal.valueOf(0.00);
|
||||||
|
List<SltAgreementInfo> repairList = new ArrayList<>();
|
||||||
|
|
||||||
|
|
||||||
|
List<TmTask> taskRepairList = taskMapper.getTaskIdList(info);
|
||||||
|
List<TmTask> taskRepairList2 = new ArrayList<>();
|
||||||
|
taskRepairList2 = checkTeamAgreementInfo(info);
|
||||||
|
if (null != taskRepairList && !taskRepairList.isEmpty()) {
|
||||||
|
if (null != taskRepairList2 && !taskRepairList2.isEmpty()) {
|
||||||
|
taskRepairList.addAll(taskRepairList2);
|
||||||
|
}
|
||||||
|
repairList = sltAgreementInfoMapper.getRepairDetailsList(info, taskRepairList);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (SltAgreementInfo bean : repairList) {
|
||||||
|
if (bean.getCosts()!=null && (bean.getPartType().equals("收费"))) {
|
||||||
|
totalCostRepair = totalCostRepair.add(bean.getCosts());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
List<SltLeaseInfo> repair = Convert.toList(SltLeaseInfo.class, repairList);
|
||||||
|
|
||||||
|
//报废费用明细
|
||||||
|
BigDecimal totalCostScrap = BigDecimal.valueOf(0.00);
|
||||||
|
List<SltAgreementInfo> scrapList = new ArrayList<>();
|
||||||
|
|
||||||
|
List<TmTask> taskScrapList = taskMapper.getTaskIdList(info);
|
||||||
|
|
||||||
|
List<TmTask> taskScrapList2 = new ArrayList<>();
|
||||||
|
taskScrapList2 = checkTeamAgreementInfo(info);
|
||||||
|
|
||||||
|
if (null != taskScrapList && !taskScrapList.isEmpty()) {
|
||||||
|
|
||||||
|
if (null != taskScrapList2 && !taskScrapList2.isEmpty()) {
|
||||||
|
taskScrapList.addAll(taskScrapList2);
|
||||||
|
}
|
||||||
|
scrapList = sltAgreementInfoMapper.getScrapDetailsList(info, taskScrapList);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for (SltAgreementInfo bean : scrapList) {
|
||||||
|
if (bean.getCosts()!=null && (bean.getPartType().equals("收费"))) {
|
||||||
|
totalCostScrap = totalCostScrap.add(bean.getCosts());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
List<SltLeaseInfo> scrap = Convert.toList(SltLeaseInfo.class, scrapList);
|
||||||
|
|
||||||
|
//减免费用明细
|
||||||
|
BigDecimal totalCostReduction = BigDecimal.valueOf(0.00);
|
||||||
|
List<SltAgreementReduce> reductionList = new ArrayList<>();
|
||||||
|
|
||||||
|
if (info.getAgreementId() != null){
|
||||||
|
SltAgreementReduce bean =new SltAgreementReduce();
|
||||||
|
bean.setAgreementId(info.getAgreementId());
|
||||||
|
reductionList = sltAgreementRecudceMapper.getReductionList(bean);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (SltAgreementReduce reduction : reductionList) {
|
||||||
|
if(reduction.getLeaseMoney()!=null){
|
||||||
|
totalCostReduction = totalCostReduction.add(reduction.getLeaseMoney());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
List<SltLeaseInfo> reduction = Convert.toList(SltLeaseInfo.class, reductionList);
|
||||||
|
|
||||||
|
|
||||||
|
List<Map<String, Object>> resultsLease = new ArrayList<>();
|
||||||
|
List<Map<String, Object>> resultsLose = new ArrayList<>();
|
||||||
|
List<Map<String, Object>> resultsRepair = new ArrayList<>();
|
||||||
|
List<Map<String, Object>> resultsScrap = new ArrayList<>();
|
||||||
|
List<Map<String, Object>> resultsReduction = new ArrayList<>();
|
||||||
|
if (lease!= null) {
|
||||||
|
for (SltLeaseInfo bean : lease) {
|
||||||
|
Map<String, Object> maps = outReceiveDetailsBeanToMap(bean, 1, 1);
|
||||||
|
resultsLease.add(maps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (lose!= null) {
|
||||||
|
for (SltLeaseInfo bean : lose) {
|
||||||
|
Map<String, Object> maps = outReceiveDetailsBeanToMap(bean, 2, 1);
|
||||||
|
resultsLose.add(maps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (repair!= null) {
|
||||||
|
for (SltLeaseInfo bean : repair) {
|
||||||
|
Map<String, Object> maps = outReceiveDetailsBeanToMap(bean, 3, 1);
|
||||||
|
resultsRepair.add(maps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (scrap!= null) {
|
||||||
|
for (SltLeaseInfo bean : scrap) {
|
||||||
|
Map<String, Object> maps = outReceiveDetailsBeanToMap(bean, 4, 1);
|
||||||
|
resultsScrap.add(maps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (reduction!= null) {
|
||||||
|
for (SltLeaseInfo bean : reduction) {
|
||||||
|
Map<String, Object> maps = outReceiveDetailsBeanToMap(bean, 5, 1);
|
||||||
|
resultsReduction.add(maps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> headersLease = receiveDetailsHeader(1,1);
|
||||||
|
List<String> headersLose = receiveDetailsHeader(2,1);
|
||||||
|
List<String> headersRepair = receiveDetailsHeader(3,1);
|
||||||
|
List<String> headersScrap = receiveDetailsHeader(4,1);
|
||||||
|
List<String> headersReduction = receiveDetailsHeader(5,1);
|
||||||
|
|
||||||
|
// fileName = agreementInfo.getAgreementCode() + "-" + unitName + "-" + projectName+ "_结算单.xls" ;
|
||||||
|
// 导出单个Excel文件
|
||||||
|
|
||||||
|
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
|
||||||
|
// 生成Excel工作簿
|
||||||
|
HSSFWorkbook workbook = PoiOutPage.excelForcheckAll(
|
||||||
|
resultsLease, resultsLose, resultsRepair, resultsScrap, resultsReduction,
|
||||||
|
headersLease, headersLose, headersRepair, headersScrap, headersReduction,
|
||||||
|
"结算明细", projectName, unitName,
|
||||||
|
totalCostLease, totalCostLose, totalCostRepair, totalCostScrap, totalCostReduction);
|
||||||
|
|
||||||
|
workbook.write(baos);
|
||||||
|
workbook.close();
|
||||||
|
|
||||||
|
// 将Excel字节流直接添加到ZIP
|
||||||
|
addToZipStream(zipOut, fileName, baos.toByteArray());
|
||||||
|
|
||||||
|
// 定期刷新缓冲区
|
||||||
|
if (fileCount.get() % 5 == 0) {
|
||||||
|
zipOut.flush();
|
||||||
|
response.flushBuffer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 更新进度为完成
|
||||||
|
progress.setStatus("completed");
|
||||||
|
progress.setPercentage(100);
|
||||||
|
progress.setEndTime(System.currentTimeMillis());
|
||||||
|
progress.setCurrentFileName("下载完成");
|
||||||
|
updateProgress(taskId, progress);
|
||||||
|
|
||||||
|
zipOut.finish();
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
progress.setStatus("error");
|
||||||
|
progress.setErrorMessage(e.getMessage());
|
||||||
|
updateProgress(taskId, progress);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
// 清理进度信息(延迟清理,以便前端可以获取最终状态)
|
||||||
|
new Timer().schedule(new TimerTask() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
downloadProgressMap.remove(taskId);
|
||||||
|
}
|
||||||
|
}, 300000); // 5分钟后清理
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建压缩包
|
* 创建压缩包
|
||||||
*/
|
*/
|
||||||
|
|
@ -2617,9 +2578,31 @@ public class SltAgreementInfoController extends BaseController {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private void addToZipStream(ZipArchiveOutputStream zipOut, String path, byte[] bytes) throws IOException {
|
||||||
|
if (bytes == null || bytes.length == 0) return;
|
||||||
|
|
||||||
|
ZipArchiveEntry entry = new ZipArchiveEntry(path);
|
||||||
|
entry.setSize(bytes.length);
|
||||||
|
zipOut.putArchiveEntry(entry);
|
||||||
|
|
||||||
|
try (ByteArrayInputStream in = new ByteArrayInputStream(bytes)) {
|
||||||
|
IOUtils.copy(in, zipOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
zipOut.closeArchiveEntry();
|
||||||
|
zipOut.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新进度信息
|
||||||
|
*/
|
||||||
|
private void updateProgress(String taskId, DownloadProgress progress) {
|
||||||
|
if (taskId != null && progress != null) {
|
||||||
|
downloadProgressMap.put(taskId, progress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue