Преглед на файлове

批量下载EXCEL导入模板

cr преди 1 седмица
родител
ревизия
2552aa2ec3

+ 193 - 19
blade-service/blade-manager/src/main/java/org/springblade/manager/controller/WbsTreeContractController.java

@@ -1,12 +1,5 @@
 package org.springblade.manager.controller;
-
-import com.alibaba.fastjson.JSONObject;
-import com.aspose.cells.LoadFormat;
-import com.aspose.cells.LoadOptions;
-import com.aspose.cells.SaveFormat;
 import com.aspose.cells.Workbook;
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
 import com.google.common.collect.Lists;
@@ -20,10 +13,8 @@ import io.swagger.annotations.ApiOperation;
 import lombok.AllArgsConstructor;
 import lombok.SneakyThrows;
 import org.apache.commons.lang.StringUtils;
-import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
 import org.apache.poi.ss.usermodel.*;
 import org.apache.poi.ss.util.CellRangeAddress;
-import org.apache.poi.ss.util.WorkbookUtil;
 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
 import org.jsoup.Jsoup;
 import org.jsoup.nodes.Document;
@@ -31,8 +22,6 @@ import org.jsoup.nodes.Element;
 import org.jsoup.select.Elements;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springblade.business.vo.NeiYeLedgerVO1;
-import org.springblade.common.utils.CommonUtil;
 import org.springblade.common.utils.SnowFlakeUtil;
 import org.springblade.core.boot.ctrl.BladeController;
 import org.springblade.core.log.exception.ServiceException;
@@ -47,21 +36,14 @@ import org.springblade.manager.dto.TableSortDTO;
 import org.springblade.manager.dto.WbsTreeContractDTO2;
 import org.springblade.manager.entity.*;
 import org.springblade.manager.feign.ContractClient;
-import org.springblade.manager.service.INodeBaseInfoService;
 import org.springblade.manager.service.IWbsParamService;
 import org.springblade.manager.service.IWbsTreeContractService;
-import org.springblade.manager.service.IWbsTreePrivateService;
-import org.springblade.manager.service.impl.NodeBaseInfoServiceImpl;
 import org.springblade.manager.service.impl.WbsTreeContractServiceImpl;
 import org.springblade.manager.utils.FileUtils;
 import org.springblade.manager.utils.RandomNumberHolder;
 import org.springblade.manager.vo.*;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.core.io.ByteArrayResource;
 import org.springframework.core.io.Resource;
 import org.springframework.dao.DataAccessException;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
 import org.springframework.jdbc.core.BeanPropertyRowMapper;
 import org.springframework.jdbc.core.JdbcTemplate;
@@ -84,7 +66,20 @@ import java.util.*;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
-import org.springframework.http.ContentDisposition;
+import org.apache.poi.xssf.streaming.SXSSFWorkbook;
+
+
+
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.util.List;
+
+import static com.aspose.cells.HtmlLinkTargetType.BLANK;
+import static com.aspose.cells.LoadDataFilterOptions.FORMULA;
+import static com.aspose.cells.PropertyType.BOOLEAN;
+import static com.aspose.cells.PropertyType.STRING;
+import static java.sql.Types.NUMERIC;
+
 
 @RestController
 @AllArgsConstructor
@@ -429,8 +424,187 @@ public class WbsTreeContractController extends BladeController {
             }
         }
     }
+    @SneakyThrows
+    @GetMapping("/download-node-excel")
+    @ApiOperationSupport(order = 14)
+    @ApiOperation(value = "客户端-下载节点下所有表单为多sheet excel", notes = "传入节点ID和分类")
+    public void downloadNodeExcel(@RequestParam Long nodeId, @RequestParam Integer classify, HttpServletResponse response) {
+        // 构建Excel文件名
+        StringBuilder excelName = new StringBuilder();
+        // 获取节点下所有表单
+        List<WbsTreeContract> formList = wbsTreeContractServiceImpl.selectAllPkeyIdByNodeId(nodeId, classify);
+        if (ObjectUtil.isEmpty(formList)) {
+            throw new ServiceException("该节点下没有找到对应的表单数据");
+        }
+
+        // 获取节点及祖先节点信息用于构建文件名
+        WbsTreeContract node = wbsTreeContractServiceImpl.getById(nodeId);
+        List<WbsTreeContract> ancestorsList = wbsTreeContractServiceImpl.getAncestorsList(node.getAncestorsPId());
+        for (WbsTreeContract ancestor : ancestorsList) {
+            if (2 == ancestor.getNodeType()) {
+                excelName.append(ancestor.getNodeName());
+            } else if (4 == ancestor.getNodeType()) {
+                excelName.append("-" + ancestor.getNodeName());
+            }
+        }
+        excelName.append("-" + node.getNodeName());
+
+        // 创建主工作簿(用于合并多sheet)
+        XSSFWorkbook mainWorkbook = new XSSFWorkbook();
+
+        try {
+            // 遍历所有表单,生成对应的sheet
+            for (WbsTreeContract form : formList) {
+                String pKeyId = form.getPKeyId()+"";
+                String sheetName = form.getNodeName();
+                // 处理sheet名称中的特殊字符(Excel不允许的字符)
+                sheetName = sheetName.replaceAll("[\\\\/:*?\"<>|]", "_");
+
+                // 1. 获取当前表单的htmlUrl(复用downloadExcel的逻辑)
+                String htmlUrl = "";
+                WbsTreeContract contractTab = iWbsTreeContractService.getBaseMapper()
+                        .selectOne(Wrappers.<WbsTreeContract>lambdaQuery().eq(WbsTreeContract::getPKeyId, pKeyId));
+
+                if (ObjectUtil.isEmpty(contractTab)) {
+                    // 尝试从试验表获取
+                    WbsTreePrivate privateTab = jdbcTemplate.query(
+                                    "select * from m_wbs_tree_private where p_key_id = ?",
+                                    new BeanPropertyRowMapper<>(WbsTreePrivate.class),
+                                    pKeyId)
+                            .stream().findAny().orElse(null);
+                    if (privateTab != null && privateTab.getHtmlUrl() != null) {
+                        htmlUrl = privateTab.getHtmlUrl();
+                    }
+                } else {
+                    htmlUrl = contractTab.getHtmlUrl();
+                }
+
+                // 跳过无html信息的表单
+                if (ObjectUtil.isEmpty(htmlUrl)) {
+                    logger.warn("表单pKeyId:{} 未获取到html信息,已跳过", pKeyId);
+                    continue;
+                }
+
+                // 2. 转换html为单个sheet的工作簿
+                InputStream htmlStream = FileUtils.getInputStreamByUrl(htmlUrl);
+                String htmlContent = IoUtil.readToString(htmlStream);
+                org.apache.poi.ss.usermodel.Workbook singleSheetWorkbook = HtmlTableToExcelConverter.convertHtmlTableToExcel(htmlContent);
 
+                // 3. 将单个sheet复制到主工作簿
+                if (singleSheetWorkbook.getNumberOfSheets() > 0) {
+                    Sheet sourceSheet = singleSheetWorkbook.getSheetAt(0);
+                    Sheet targetSheet = mainWorkbook.createSheet(sheetName);
+                    copySheetContent(mainWorkbook, sourceSheet, targetSheet);
+                }
 
+                // 关闭临时工作簿释放资源
+                singleSheetWorkbook.close();
+            }
+
+            // 4. 输出主工作簿到响应
+            if (mainWorkbook.getNumberOfSheets() == 0) {
+                throw new ServiceException("所有表单均无法生成有效Excel内容");
+            }
+
+            // 设置响应头
+            String encodedFileName = URLEncoder.encode(excelName + ".xlsx", "UTF-8")
+                    .replaceAll("\\+", " ")
+                    .replaceAll("%2B", "+");
+            response.setHeader("Content-Disposition", "attachment; filename=" + encodedFileName);
+            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
+
+            // 写入输出流
+            try (ServletOutputStream outputStream = response.getOutputStream()) {
+                mainWorkbook.write(outputStream);
+                outputStream.flush(); // 强制刷出所有数据
+            }
+
+        } catch (Exception e) {
+            logger.error("下载节点多sheet Excel异常", e);
+            throw new ServiceException("下载失败:" + e.getMessage());
+        } finally {
+            if (mainWorkbook != null) {
+                mainWorkbook.close();
+            }
+        }
+    }
+
+    /**
+     * 复制sheet内容(包括样式、合并区域、行高列宽)
+     */
+    private void copySheetContent(XSSFWorkbook targetWorkbook, Sheet sourceSheet, Sheet targetSheet) {
+        // 复制合并区域
+        for (int i = 0; i < sourceSheet.getNumMergedRegions(); i++) {
+            CellRangeAddress mergedRegion = sourceSheet.getMergedRegion(i);
+            targetSheet.addMergedRegion(mergedRegion);
+        }
+
+        // 复制列宽
+        for (int col = 0; col <= sourceSheet.getLastRowNum(); col++) {
+            targetSheet.setColumnWidth(col, sourceSheet.getColumnWidth(col));
+        }
+
+        // 复制行数据及样式
+        for (int rowIdx = 0; rowIdx <= sourceSheet.getLastRowNum(); rowIdx++) {
+            Row sourceRow = sourceSheet.getRow(rowIdx);
+            if (sourceRow == null) continue;
+
+            Row targetRow = targetSheet.createRow(rowIdx);
+            targetRow.setHeight(sourceRow.getHeight());
+
+            // 复制单元格
+            for (int cellIdx = 0; cellIdx < sourceRow.getLastCellNum(); cellIdx++) {
+                Cell sourceCell = sourceRow.getCell(cellIdx);
+                if (sourceCell == null) continue;
+
+                Cell targetCell = targetRow.createCell(cellIdx);
+                copyCellContent(targetWorkbook, sourceCell, targetCell);
+            }
+        }
+    }
+
+    private void copyCellContent(XSSFWorkbook targetWorkbook, Cell sourceCell, Cell targetCell) {
+        // 复制样式
+        CellStyle targetStyle = targetWorkbook.createCellStyle();
+        targetStyle.cloneStyleFrom(sourceCell.getCellStyle());
+        targetCell.setCellStyle(targetStyle);
+
+        // 复制单元格值(完善类型处理)
+        CellType cellType = CellType.forInt(sourceCell.getCellType());
+        // 公式单元格需要先获取计算后的值
+        if (cellType == CellType.FORMULA) {
+            cellType = CellType.forInt(sourceCell.getCachedFormulaResultType());
+        }
+
+        switch (cellType) {
+            case STRING:
+                targetCell.setCellValue(sourceCell.getStringCellValue());
+                break;
+            case NUMERIC:
+                if (DateUtil.isCellDateFormatted(sourceCell)) {
+                    targetCell.setCellValue(sourceCell.getDateCellValue());
+                } else {
+                    targetCell.setCellValue(sourceCell.getNumericCellValue());
+                }
+                break;
+            case BOOLEAN:
+                targetCell.setCellValue(sourceCell.getBooleanCellValue());
+                break;
+            case FORMULA:
+                // 公式单元格同时复制公式和缓存结果
+                targetCell.setCellFormula(sourceCell.getCellFormula());
+                targetCell.setCellValue(sourceCell.getNumericCellValue()); // 补充缓存值
+                break;
+            case BLANK:
+                break;
+            case ERROR:
+                targetCell.setCellErrorValue(sourceCell.getErrorCellValue());
+                break;
+            default:
+                // 兜底处理,避免遗漏
+                targetCell.setCellValue(sourceCell.toString());
+        }
+    }
 
 
     // 计算最大列数以对齐所有行

+ 2 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/WbsTreeContractMapper.java

@@ -187,4 +187,6 @@ public interface WbsTreeContractMapper extends EasyBaseMapper<WbsTreeContract> {
     void updateAncestorsPid(@Param("ancestorsPId") String ancestorsPId, @Param("ancestors") String ancestors,@Param("pKeyId")Long pKeyId);
 
     void updateWbsTreeAncestors(@Param("contract")WbsTreeContract contract);
+
+    List<WbsTreeContract> getAncestorsList(@Param("pKeyIds") List<Long> longList);
 }

+ 8 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/WbsTreeContractMapper.xml

@@ -1077,5 +1077,13 @@
     <select id="getChildWbsTreeContracts" resultType="org.springblade.manager.entity.WbsTreeContract">
         select p_key_id,ancestors,ancestors_p_id from m_wbs_tree_contract where FIND_IN_SET(#{pKeyId}, ancestors_p_id)   and is_deleted=0
     </select>
+    <select id="getAncestorsList" resultType="org.springblade.manager.entity.WbsTreeContract">
+        select * from m_wbs_tree_contract where p_key_id in (
+        <foreach collection="pKeyIds" item="pkeyId" separator=",">
+            #{pkeyId}
+        </foreach>
+        ) and is_deleted=0
+        order by node_type
+    </select>
 
 </mapper>

+ 18 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/WbsTreeContractServiceImpl.java

@@ -724,6 +724,24 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
         }
     }
 
+    public List<WbsTreeContract> selectAllPkeyIdByNodeId(Long nodeId,Integer classify) {
+        Object[] params;
+        if (classify == 1) {
+            params = new Object[]{nodeId, 1, 2, 3};
+        } else {
+            params = new Object[]{nodeId, 4, 5, 6};
+        }
+
+        return jdbcTemplate.query(
+                "select * from m_wbs_tree_contract where p_id = ? and is_deleted = 0 and type = 2 and table_owner in (?,?,?) order by sort",
+                new BeanPropertyRowMapper<>(WbsTreeContract.class),
+                params);
+    }
+
+    public List<WbsTreeContract> getAncestorsList(String ancestorsPId) {
+        return baseMapper.getAncestorsList(Func.toLongList(ancestorsPId));
+    }
+
 
     public static class WbsTreeContractComparator implements Comparator<AppWbsTreeContractVO> {