|  | @@ -3,12 +3,17 @@ package com.rtrh.projects.web.controller.subject;
 | 
	
		
			
				|  |  |  import java.io.IOException;
 | 
	
		
			
				|  |  |  import java.math.BigDecimal;
 | 
	
		
			
				|  |  |  import java.net.URLEncoder;
 | 
	
		
			
				|  |  | +import java.text.SimpleDateFormat;
 | 
	
		
			
				|  |  |  import java.util.*;
 | 
	
		
			
				|  |  |  import java.util.stream.Collectors;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +import javax.servlet.ServletOutputStream;
 | 
	
		
			
				|  |  |  import javax.servlet.http.HttpServletResponse;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  import cn.afterturn.easypoi.excel.ExcelExportUtil;
 | 
	
		
			
				|  |  | +import cn.hutool.core.collection.CollUtil;
 | 
	
		
			
				|  |  | +import cn.hutool.core.io.IoUtil;
 | 
	
		
			
				|  |  | +import cn.hutool.poi.excel.ExcelUtil;
 | 
	
		
			
				|  |  |  import com.alibaba.excel.EasyExcel;
 | 
	
		
			
				|  |  |  import com.alibaba.excel.EasyExcelFactory;
 | 
	
		
			
				|  |  |  import com.alibaba.excel.ExcelWriter;
 | 
	
	
		
			
				|  | @@ -22,6 +27,7 @@ import com.rtrh.common.util.StringUtil;
 | 
	
		
			
				|  |  |  import com.rtrh.core.vo.ListMessage;
 | 
	
		
			
				|  |  |  import com.rtrh.projects.modules.projects.dao.SubSourceDao;
 | 
	
		
			
				|  |  |  import com.rtrh.projects.modules.projects.enums.ProjectStatusEnum;
 | 
	
		
			
				|  |  | +import com.rtrh.projects.modules.projects.vo.SubInfoTotalExcel;
 | 
	
		
			
				|  |  |  import com.rtrh.projects.modules.projects.vo.export.SubInfoFixVO;
 | 
	
		
			
				|  |  |  import com.rtrh.projects.modules.utils.CustomCellWriteWidthStrategy;
 | 
	
		
			
				|  |  |  import com.rtrh.projects.modules.utils.DateUtils;
 | 
	
	
		
			
				|  | @@ -30,6 +36,8 @@ import com.rtrh.projects.outapi.result.JsonResult;
 | 
	
		
			
				|  |  |  import com.rtrh.projects.web.util.SheetData;
 | 
	
		
			
				|  |  |  import com.rtrh.projects.web.util.SheetHead;
 | 
	
		
			
				|  |  |  import org.apache.poi.ss.usermodel.*;
 | 
	
		
			
				|  |  | +import org.apache.poi.xssf.streaming.SXSSFSheet;
 | 
	
		
			
				|  |  | +import org.apache.poi.xssf.streaming.SXSSFWorkbook;
 | 
	
		
			
				|  |  |  import org.apache.poi.xssf.usermodel.XSSFWorkbook;
 | 
	
		
			
				|  |  |  import org.springframework.beans.BeanUtils;
 | 
	
		
			
				|  |  |  import org.springframework.beans.factory.annotation.Autowired;
 | 
	
	
		
			
				|  | @@ -611,6 +619,179 @@ public class SubInfoExportController extends BaseController {
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    /**
 | 
	
		
			
				|  |  | +     * 导出总表
 | 
	
		
			
				|  |  | +     * @param response
 | 
	
		
			
				|  |  | +     * @param vo
 | 
	
		
			
				|  |  | +     */
 | 
	
		
			
				|  |  | +    @PostMapping("/exportFixTotalExcel")
 | 
	
		
			
				|  |  | +    public void exportFixTotalExcel(HttpServletResponse response, @RequestBody SubInfoQueryTzVO vo) {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        try {
 | 
	
		
			
				|  |  | +            List<SubInfoTotalExcel> subInfoTotalExcel = subInfoService.getFixTotalExcel(vo);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            //获取属地字典
 | 
	
		
			
				|  |  | +            List<TSystable> jsddList = tSysTableService.getByKind(SysTableKind.JSDD);
 | 
	
		
			
				|  |  | +            //获取行业字典
 | 
	
		
			
				|  |  | +            List<TSystable> hyflList = tSysTableService.getByKind(SysTableKind.HYFL);
 | 
	
		
			
				|  |  | +            //遍历subInfoTotalExcel,将subjectId替换为jsddList中code=subjectId的title
 | 
	
		
			
				|  |  | +            for (SubInfoTotalExcel data : subInfoTotalExcel) {
 | 
	
		
			
				|  |  | +                if (data == null){
 | 
	
		
			
				|  |  | +                    continue;
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +                String subjectId = data.getSubjectId();
 | 
	
		
			
				|  |  | +                String induskind = data.getInduskind();
 | 
	
		
			
				|  |  | +                if (StringUtil.isNotEmpty(induskind)) {
 | 
	
		
			
				|  |  | +                    Optional<TSystable> first = hyflList.stream().filter(item -> item.getCode().equals(induskind)).findFirst();
 | 
	
		
			
				|  |  | +                    first.ifPresent(tSystable -> data.setInduskind(tSystable.getTitle()));
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +                if (StringUtil.isNotEmpty(subjectId)) {
 | 
	
		
			
				|  |  | +                    Optional<TSystable> first = jsddList.stream().filter(item -> item.getCode().equals(subjectId)).findFirst();
 | 
	
		
			
				|  |  | +                    first.ifPresent(tSystable -> data.setSubjectId(tSystable.getTitle()));
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            //通过ExcelUtil.getBigWriter()创建Writer对象,BigExcelWriter用于大数据量的导出,不会引起溢出;
 | 
	
		
			
				|  |  | +            cn.hutool.poi.excel.ExcelWriter writer = ExcelUtil.getBigWriter();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            //写入标题
 | 
	
		
			
				|  |  | +            // 写入标题行
 | 
	
		
			
				|  |  | +            List<String> titleRow = CollUtil.newArrayList("储备项目库基本情况");
 | 
	
		
			
				|  |  | +            writer.writeHeadRow(titleRow);
 | 
	
		
			
				|  |  | +            // 合并标题行的所有单元格
 | 
	
		
			
				|  |  | +            writer.merge(0, 0, 0, 3, null, true);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            List<String> rowHead2 = CollUtil.newArrayList("项目分类","项目分类","项目个数","计划总投资(亿元)");
 | 
	
		
			
				|  |  | +            writer.writeHeadRow(rowHead2);
 | 
	
		
			
				|  |  | +            writer.merge(1, 1, 0, 1, null, true);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            // 获取 SXSSFSheet 对象(确保在写入数据之后)
 | 
	
		
			
				|  |  | +            SXSSFSheet sheet = ((SXSSFWorkbook) writer.getWorkbook()).getSheetAt(0);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            // 设置每列的默认宽度
 | 
	
		
			
				|  |  | +            int defaultColumnWidth = 40; // 默认宽度为20个字符
 | 
	
		
			
				|  |  | +            for (int i = 0; i < rowHead2.size(); i++) {
 | 
	
		
			
				|  |  | +                sheet.setColumnWidth(i, defaultColumnWidth * 256); // 其他列保持默认宽度
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            //4、对数据按照属地字段进行分组
 | 
	
		
			
				|  |  | +            LinkedHashMap<String, List<SubInfoTotalExcel>> subjectIdList = subInfoTotalExcel.stream().collect(Collectors.groupingBy(SubInfoTotalExcel::getSubjectId, LinkedHashMap::new, Collectors.toList()));
 | 
	
		
			
				|  |  | +            //5、对数据按照金额1000-3000,3000-5000,5000-10000进行分组
 | 
	
		
			
				|  |  | +            LinkedHashMap<String, List<SubInfoTotalExcel>> moneyList = subInfoTotalExcel.stream().collect(Collectors.groupingBy(data -> {
 | 
	
		
			
				|  |  | +                if (data.getAmtTotal().compareTo(new BigDecimal(1000000)) >= 0) {
 | 
	
		
			
				|  |  | +                    return "100亿元以上";
 | 
	
		
			
				|  |  | +                } else if (data.getAmtTotal().compareTo(new BigDecimal(500000)) >= 0 && data.getAmtTotal().compareTo(new BigDecimal(1000000)) < 0) {
 | 
	
		
			
				|  |  | +                    return "50-100亿元";
 | 
	
		
			
				|  |  | +                } else if (data.getAmtTotal().compareTo(new BigDecimal(100000)) >= 0 && data.getAmtTotal().compareTo(new BigDecimal(500000)) < 0) {
 | 
	
		
			
				|  |  | +                    return "10-50亿元";
 | 
	
		
			
				|  |  | +                } else {
 | 
	
		
			
				|  |  | +                    return "10亿元以下";
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            }, LinkedHashMap::new, Collectors.toList()));
 | 
	
		
			
				|  |  | +            //6、对数据按照行业进行分组
 | 
	
		
			
				|  |  | +            LinkedHashMap<String, List<SubInfoTotalExcel>> industryList = subInfoTotalExcel.stream().collect(Collectors.groupingBy(SubInfoTotalExcel::getInduskind, LinkedHashMap::new, Collectors.toList()));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            //遍历subInfoTotalExcel数据计算总金额
 | 
	
		
			
				|  |  | +            BigDecimal totalAmt = subInfoTotalExcel.stream().map(SubInfoTotalExcel::getAmtTotal).reduce(BigDecimal.ZERO, BigDecimal::add);
 | 
	
		
			
				|  |  | +            Integer totalNum = subInfoTotalExcel.size();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            LinkedHashMap<String, List<List<String>>> finalDataMap = new LinkedHashMap<>();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            //7、需要保存的数据
 | 
	
		
			
				|  |  | +            List<List<String>> areaData = CollUtil.newArrayList();
 | 
	
		
			
				|  |  | +            for (Map.Entry<String, List<SubInfoTotalExcel>> subInfoListEntry : subjectIdList.entrySet()) {
 | 
	
		
			
				|  |  | +                List<String> data = CollUtil.newArrayList();
 | 
	
		
			
				|  |  | +                data.add("按属地分");
 | 
	
		
			
				|  |  | +                data.add(subInfoListEntry.getKey());
 | 
	
		
			
				|  |  | +                data.add(String.valueOf(subInfoListEntry.getValue().size()));
 | 
	
		
			
				|  |  | +                data.add(String.valueOf(subInfoListEntry.getValue().stream().map(SubInfoTotalExcel::getAmtTotal).reduce(BigDecimal.ZERO, BigDecimal::add)));
 | 
	
		
			
				|  |  | +                areaData.add(data);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            finalDataMap.put("按属地划分", areaData);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            List<List<String>> moneyData = CollUtil.newArrayList();
 | 
	
		
			
				|  |  | +            for (Map.Entry<String, List<SubInfoTotalExcel>> subInfoListEntry : moneyList.entrySet()) {
 | 
	
		
			
				|  |  | +                List<String> data = CollUtil.newArrayList();
 | 
	
		
			
				|  |  | +                data.add("按金额分");
 | 
	
		
			
				|  |  | +                data.add(subInfoListEntry.getKey());
 | 
	
		
			
				|  |  | +                data.add(String.valueOf(subInfoListEntry.getValue().size()));
 | 
	
		
			
				|  |  | +                data.add(String.valueOf(subInfoListEntry.getValue().stream().map(SubInfoTotalExcel::getAmtTotal).reduce(BigDecimal.ZERO, BigDecimal::add)));
 | 
	
		
			
				|  |  | +                moneyData.add(data);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            finalDataMap.put("按金额划分", moneyData);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            List<List<String>> industryData = CollUtil.newArrayList();
 | 
	
		
			
				|  |  | +            for (Map.Entry<String, List<SubInfoTotalExcel>> subInfoListEntry : industryList.entrySet()) {
 | 
	
		
			
				|  |  | +                List<String> data = CollUtil.newArrayList();
 | 
	
		
			
				|  |  | +                data.add("按行业分");
 | 
	
		
			
				|  |  | +                data.add(subInfoListEntry.getKey());
 | 
	
		
			
				|  |  | +                data.add(String.valueOf(subInfoListEntry.getValue().size()));
 | 
	
		
			
				|  |  | +                data.add(String.valueOf(subInfoListEntry.getValue().stream().map(SubInfoTotalExcel::getAmtTotal).reduce(BigDecimal.ZERO, BigDecimal::add)));
 | 
	
		
			
				|  |  | +                industryData.add(data);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            finalDataMap.put("按行业划分", industryData);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            ServletOutputStream out = null;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            try {
 | 
	
		
			
				|  |  | +                //6.定义容器保存人物数据
 | 
	
		
			
				|  |  | +                List<List<String>> finalDataRows = new LinkedList<>();
 | 
	
		
			
				|  |  | +                int indexStart = 2;   //行业分类起始行
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                for (Map.Entry<String, List<List<String>>> dataListEntry : finalDataMap.entrySet()) {
 | 
	
		
			
				|  |  | +                    List<List<String>> dataList = dataListEntry.getValue();
 | 
	
		
			
				|  |  | +                    int dataSize = dataList.size();
 | 
	
		
			
				|  |  | +                    if (dataSize == 1){
 | 
	
		
			
				|  |  | +                        indexStart += dataSize;
 | 
	
		
			
				|  |  | +                    }else{
 | 
	
		
			
				|  |  | +                        writer.merge(indexStart, indexStart + dataSize - 1, 0, 0, null, true);
 | 
	
		
			
				|  |  | +                        indexStart += dataSize;
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                    //18.保存数据
 | 
	
		
			
				|  |  | +                    finalDataRows.addAll(dataList);
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +                writer.write(finalDataRows, true);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                // 创建合计行
 | 
	
		
			
				|  |  | +                List<String> totalRow = CollUtil.newArrayList("合计", "合计", totalNum.toString(), totalAmt.toString());
 | 
	
		
			
				|  |  | +                writer.writeHeadRow(totalRow);
 | 
	
		
			
				|  |  | +                writer.merge(indexStart, indexStart, 0, 1, null, true);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                response.setContentType("application/vnd.ms-excel;charset=utf-8");
 | 
	
		
			
				|  |  | +                Date currentDate = new Date();
 | 
	
		
			
				|  |  | +                SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
 | 
	
		
			
				|  |  | +                String date = sdf.format(currentDate);
 | 
	
		
			
				|  |  | +                response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("重点项目调度-项目数据.xlsx", "UTF-8"));
 | 
	
		
			
				|  |  | +                out = response.getOutputStream();
 | 
	
		
			
				|  |  | +                writer.flush(out, true);
 | 
	
		
			
				|  |  | +            }finally {
 | 
	
		
			
				|  |  | +                //关闭输出Servlet流
 | 
	
		
			
				|  |  | +                IoUtil.close(out);
 | 
	
		
			
				|  |  | +                //关闭writer,释放内存
 | 
	
		
			
				|  |  | +                writer.close();
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        } catch (IOException e) {
 | 
	
		
			
				|  |  | +            // 设置错误状态码和消息
 | 
	
		
			
				|  |  | +            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
 | 
	
		
			
				|  |  | +            try {
 | 
	
		
			
				|  |  | +                e.printStackTrace();
 | 
	
		
			
				|  |  | +                response.getWriter().write("导出 Excel 文件时出现错误:" + e.getMessage());
 | 
	
		
			
				|  |  | +            } catch (IOException ex) {
 | 
	
		
			
				|  |  | +                ex.printStackTrace();
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        } catch (Exception e) {
 | 
	
		
			
				|  |  | +            // 处理其他可能的异常
 | 
	
		
			
				|  |  | +            response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
 | 
	
		
			
				|  |  | +            e.printStackTrace();
 | 
	
		
			
				|  |  | +            try {
 | 
	
		
			
				|  |  | +                response.getWriter().write("请求参数错误或发生其他错误:" + e.getMessage());
 | 
	
		
			
				|  |  | +            } catch (IOException ex) {
 | 
	
		
			
				|  |  | +                ex.printStackTrace();
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /**
 | 
	
		
			
				|  |  |       * 导出调度表
 |