فهرست منبع

feat:
新增导出excel时级联操作

18339543638 2 سال پیش
والد
کامیت
331a0107c6

+ 1 - 1
tr-modules-api/tr-module-export-api/src/main/java/cn/tr/module/export/handler/AbstractSelectConverter.java

@@ -160,7 +160,7 @@ public abstract class AbstractSelectConverter<T> implements Converter<T> {
      * [{"",["是","否"]}]
      * <pre/>
      */
-    public abstract List<Pair<String,List<String>>>  buildLinkageSelectList(Collection<String> params);
+    public List<Pair<String,List<String>>>  buildLinkageSelectList(Collection<String> params){return new ArrayList<>();};
 
     public abstract Class<T> doSupportJavaTypeKey();
 }

+ 144 - 66
tr-modules/tr-module-export/src/main/java/cn/tr/module/excel/core/handler/write/CustomCellWriteHandler.java

@@ -2,10 +2,9 @@ package cn.tr.module.excel.core.handler.write;
 
 import cn.hutool.core.collection.CollectionUtil;
 import cn.hutool.core.lang.Pair;
-import cn.hutool.core.util.CharUtil;
-import cn.hutool.core.util.ClassUtil;
-import cn.hutool.core.util.ReflectUtil;
-import cn.hutool.core.util.StrUtil;
+import cn.hutool.core.util.*;
+import cn.tr.core.tree.TreeNode;
+import cn.tr.core.utils.TreeUtil;
 import cn.tr.module.export.annotation.ExcelSelect;
 import cn.tr.module.export.annotation.ExcelPropertySupport;
 import cn.tr.module.export.handler.AbstractSelectConverter;
@@ -13,19 +12,19 @@ import cn.tr.module.export.handler.NoneSelectConverter;
 import cn.tr.module.constant.ExcelConstant;
 import com.alibaba.excel.annotation.ExcelProperty;
 import com.alibaba.excel.converters.Converter;
-import com.alibaba.excel.metadata.data.WriteCellData;
 import com.alibaba.excel.write.handler.CellWriteHandler;
 import com.alibaba.excel.write.handler.context.CellWriteHandlerContext;
-import com.alibaba.excel.write.metadata.style.WriteCellStyle;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.poi.ss.usermodel.*;
 import org.apache.poi.ss.util.CellRangeAddressList;
 import org.apache.poi.xssf.usermodel.*;
-import reactor.util.function.Tuple2;
 
 import javax.validation.constraints.NotNull;
 import java.lang.reflect.Field;
 import java.time.temporal.Temporal;
 import java.util.*;
+import java.util.stream.Collectors;
 
 /**
  * @ClassName : CustomSheetWriteHandler
@@ -33,22 +32,16 @@ import java.util.*;
  * @Author : LF
  * @Date: 2023年05月19日
  */
-
+@Slf4j
 public class CustomCellWriteHandler implements CellWriteHandler {
     //excel中的属性列的位置
-   private final Map<String, Integer> excelColumnProperty;
-
+    private final Map<String, Integer> excelColumnProperty = new HashMap<>();
     //级联属性映射集合   map("下级属性","上级属性")
-    private final Map<String, String> linkagePropertyMap;
-
+    private final Map<String, String> linkagePropertyMap = new HashMap<>();
     //属性所对应的级联集合
-    private final Map<String, List<Pair<String, List<String>>>> selectPropertyMap ;
+    private final Map<String, List<Pair<String, List<String>>>> selectPropertyMap = new HashMap<>();
 
-    public CustomCellWriteHandler(Map<String, Integer> excelColumnProperty, Map<String, String> linkagePropertyMap, Map<String,List<Pair<String, List<String>>>> selectPropertyMap) {
-        this.excelColumnProperty = excelColumnProperty;
-        this.linkagePropertyMap = linkagePropertyMap;
-        this.selectPropertyMap = selectPropertyMap;
-    }
+    boolean  setSelectColumn=false;
 
     @Override
     public void afterCellDispose(CellWriteHandlerContext context) {
@@ -64,27 +57,11 @@ public class CustomCellWriteHandler implements CellWriteHandler {
             createComboColumn(field,cell);
             //进行日期格式校验
             createDateColumn(field,cell);
-        }
-    }
-
-    /**
-     * 锁定表头单元格
-     * @param sheet
-     */
-    private void clockHead(CellWriteHandlerContext context,Sheet sheet,Cell cell,boolean head){
-        if(head){
-            CellStyle clockStyle =sheet.getWorkbook().createCellStyle();
-            clockStyle.setLocked(true);
-            CellStyle unClockStyle =sheet.getWorkbook().createCellStyle();
-            unClockStyle.setLocked(false);
-
-            sheet.setDefaultColumnStyle(cell.getColumnIndex(),unClockStyle);
-            cell.setCellStyle(clockStyle);
         }else {
-            WriteCellData<?> cellData = context.getFirstCellData();
-            WriteCellStyle style = cellData.getOrCreateStyle();
-            style.setLocked(false);
-            cellData.setWriteCellStyle(style);
+            if(!setSelectColumn){
+                createLinkageSelectColumn(cell.getSheet());
+                setSelectColumn=true;
+            }
         }
     }
 
@@ -130,16 +107,10 @@ public class CustomCellWriteHandler implements CellWriteHandler {
         AbstractSelectConverter<?> converter = ReflectUtil.newInstance(converterClass);
         List<Pair<String, List<String>>> linkageSelectList = converter.buildLinkageSelectList(Arrays.asList(select.param()));
 
+
         excelColumnProperty.put(field.getName(),cell.getColumnIndex());
         linkagePropertyMap.put(field.getName(),select.linkageParentProperty());
         selectPropertyMap.put(field.getName(),linkageSelectList);
-//        List<String> values = converter.comboList(Arrays.asList(select.param()));
-//        if(CollectionUtil.isEmpty(values)){
-//            return;
-//        }
-
-
-//        generateRangeList( cell.getSheet(),values,cell.getColumnIndex(),cell.getSheet().getWorkbook());
     }
 
     /**
@@ -204,18 +175,115 @@ public class CustomCellWriteHandler implements CellWriteHandler {
         setComment(cell,columnIndex,promptMsg,allowEmpty);
     }
 
+
+    private void setComment(Cell cell,int columnIndex,String msg,boolean allowEmpty){
+        Comment comment = cell.getCellComment();
+        Drawing<?> drawingPatriarch = cell.getSheet().createDrawingPatriarch();
+        // 在第一行 第二列创建一个批注
+        comment =comment==null? drawingPatriarch.createCellComment(new XSSFClientAnchor(0, 0, 0, 0, columnIndex, 0, columnIndex, 0)):comment;
+        // 输入批注信息
+        msg=allowEmpty?msg:"---必输项---\n"+msg;
+        comment.setString(new XSSFRichTextString(msg));
+        // 将批注添加到单元格对象中
+        cell.setCellComment(comment);
+    }
+
+
     /**
-     * 构造有效性数据约束
+     * 创建级联搜索列
+     * @param sheet
      */
-    private void generateRangeList(Sheet sheet, Collection<String> options, int column, Workbook wb) {
-        if (CollectionUtil.size(options)== 0){
+    private void createLinkageSelectColumn(Sheet sheet){
+        //没有级联
+        if(CollectionUtil.isEmpty(linkagePropertyMap)){
             return;
         }
-        //获取所有sheet页个数
-        String hiddenSheetName = "hiddenSheet";
-        Sheet hiddenSheet = wb.getSheet(hiddenSheetName);
+        List<LinkageSelectNode> selectNodes = new ArrayList<>();
+        //已经处理过的字段
+        linkagePropertyMap.forEach((currentProperty,parentProperty)->{
+            selectNodes.add(new LinkageSelectNode(currentProperty,parentProperty,selectPropertyMap.get(currentProperty)));
+        });
+        List<LinkageSelectNode>  treeNode=TreeUtil.buildTree(selectNodes);
+        List<String> doneProperty = new ArrayList<>();
+        linkagePropertyMap.forEach((currentProperty,parentProperty)->{
+            if(StrUtil.isBlank(parentProperty)){
+                //非级联
+                noneLinkageSelectColumn(sheet,currentProperty);
+            }else {
+                //级联,针对本级
+
+            }
+        });
+    }
+
+    /**
+     * 级联下拉选择框
+     * @param sheet         当前工作簿
+     * @param parentProperty 父级级联参数
+     * @param property      当前需要处理的属性名称
+     * @param doneProperty  已经设置过下拉选择框的属性名称
+     */
+    private void linkageSelectColumn(Sheet sheet,String parentProperty,String property,Set<String> doneProperty ){
+        Integer columnIndex = excelColumnProperty.get(property);
+        if(ObjectUtil.isNull(columnIndex)){
+            log.warn("[execl文件导出],property:{}显示为级联属性,找不到对应的列数",property);
+            return;
+        }
+        //级联时构造一颗级联树
+
+        if(doneProperty.contains(property)){
+            //该属性已经处理过
+
+        }else {
+            //该属性尚未处理
+            List<Pair<String, List<String>>> optionalSelectValues = selectPropertyMap.get(property);
+            //创建工作簿
+            Workbook workbook = sheet.getWorkbook();
+            Sheet selectPropertySheet =workbook.createSheet(property);
+            Sheet parentSelectPropertySheet = workbook.getSheet(parentProperty);
+            if(ObjectUtil.isNotNull(parentSelectPropertySheet)){
+                //若父级工作簿已存在,重置,级联时两字段只能一一对应
+
+            }
+
+
+            workbook.setSheetHidden(workbook.getSheetIndex(selectPropertySheet),true);
+
+        }
+
+    }
+
+
+    /**
+     * 非级联下拉选择框
+     * @param sheet
+     * @param property
+     */
+    private void noneLinkageSelectColumn(Sheet sheet,String property){
+        Integer columnIndex = excelColumnProperty.get(property);
+        if(ObjectUtil.isNull(columnIndex)){
+            log.warn("[execl文件导出],property:{}显示为级联属性,找不到对应的列数",property);
+            return;
+        }
+        List<Pair<String, List<String>>> optionalSelectValues = selectPropertyMap.get(property);
+        List<String> selectValues = new ArrayList<>();
+        if(CollectionUtil.isEmpty(optionalSelectValues)){
+            selectValues.add("--- 暂无数据 ---");
+        }else {
+            optionalSelectValues.forEach(pair->{
+                if(CollectionUtil.isNotEmpty(pair.getValue())){
+                    selectValues.addAll(pair.getValue());
+                }
+            });
+        }
+        doCreateNoneLinkageSelectColumn(property,sheet,selectValues,columnIndex,sheet.getWorkbook());
+    }
+
+
+    private void doCreateNoneLinkageSelectColumn(String propertyName,Sheet sheet, Collection<String> options, int column, Workbook wb) {
+        Sheet hiddenSheet = wb.getSheet(propertyName);
         if(hiddenSheet==null){
-            hiddenSheet = wb.createSheet(hiddenSheetName);
+            hiddenSheet = wb.createSheet(propertyName);
         }
         Row row;
         //写入下拉数据到新的sheet页中
@@ -228,7 +296,7 @@ public class CustomCellWriteHandler implements CellWriteHandler {
             cell.setCellValue(CollectionUtil.get(options,i));
         }
         //获取新sheet页内容
-        String strFormula = hiddenSheetName + "!$"+CharUtil.toString((char)(65+column))+"$1:$"+CharUtil.toString((char)(65+column))+"$65535";
+        String strFormula = propertyName + "!$"+ CharUtil.toString((char)(65+column))+"$1:$"+CharUtil.toString((char)(65+column))+"$65535";
         XSSFDataValidationConstraint constraint = new XSSFDataValidationConstraint(DataValidationConstraint.ValidationType.LIST,strFormula);
         // 设置数据有效性加载在哪个单元格上,四个参数分别是:起始行、终止行、起始列、终止列
         CellRangeAddressList regions = createColumnCellRange(column);
@@ -245,22 +313,10 @@ public class CustomCellWriteHandler implements CellWriteHandler {
         // 作用在目标sheet上
         sheet.addValidationData(dataValidation);
         //将新建的sheet页隐藏掉
-        wb.setSheetHidden(1, true);
+        wb.setSheetHidden(wb.getSheetIndex(propertyName), true);
     }
 
 
-    private void setComment(Cell cell,int columnIndex,String msg,boolean allowEmpty){
-        Comment comment = cell.getCellComment();
-        Drawing<?> drawingPatriarch = cell.getSheet().createDrawingPatriarch();
-        // 在第一行 第二列创建一个批注
-        comment =comment==null? drawingPatriarch.createCellComment(new XSSFClientAnchor(0, 0, 0, 0, columnIndex, 0, columnIndex, 0)):comment;
-        // 输入批注信息
-        msg=allowEmpty?msg:"---必输项---\n"+msg;
-        comment.setString(new XSSFRichTextString(msg));
-        // 将批注添加到单元格对象中
-        cell.setCellComment(comment);
-    }
-
     private CellRangeAddressList createHeadCellRange(int column){
         return new CellRangeAddressList(0, 0,column,column);
     }
@@ -268,4 +324,26 @@ public class CustomCellWriteHandler implements CellWriteHandler {
     private CellRangeAddressList createColumnCellRange(int column){
         return new CellRangeAddressList(1, ExcelConstant.MAX_ROW,column,column);
     }
+
+    @Data
+    static class  LinkageSelectNode extends TreeNode<String> {
+
+        private String name;
+
+        /**
+         * 当前级联节点所拥有的选择项
+         */
+        private List<Pair<String, List<String>>> selectValues;
+
+        public LinkageSelectNode(String name, String parentId,List<Pair<String, List<String>>> selectValues) {
+            this.setParentId(parentId);
+            this.name = name;
+            this.selectValues = selectValues;
+        }
+
+        @Override
+        public String getId() {
+            return name;
+        }
+    }
 }

+ 0 - 113
tr-modules/tr-module-export/src/main/java/cn/tr/module/excel/core/handler/write/CustomSheetWriteHandler.java

@@ -1,24 +1,10 @@
 package cn.tr.module.excel.core.handler.write;
 
-import cn.hutool.core.collection.CollectionUtil;
-import cn.hutool.core.lang.Pair;
-import cn.hutool.core.util.CharUtil;
-import cn.hutool.core.util.ObjectUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.tr.module.constant.ExcelConstant;
 import com.alibaba.excel.write.handler.SheetWriteHandler;
 import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
 import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.poi.ss.usermodel.*;
-import org.apache.poi.ss.util.CellRangeAddressList;
-import org.apache.poi.xssf.usermodel.XSSFDataValidation;
-import org.apache.poi.xssf.usermodel.XSSFDataValidationConstraint;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
 
 
 /**
@@ -28,22 +14,6 @@ import java.util.Map;
 public class CustomSheetWriteHandler implements SheetWriteHandler {
 
     public int colSplit = 0, rowSplit = 1, leftmostColumn = 0, topRow = 1;
-
-    //excel中的属性列的位置
-    private final Map<String, Integer> excelColumnProperty;
-
-    //级联属性映射集合   map("下级属性","上级属性")
-    private final Map<String, String> linkagePropertyMap;
-
-    //属性所对应的级联集合
-    private final Map<String, List<Pair<String, List<String>>>> selectPropertyMap ;
-
-    public CustomSheetWriteHandler(Map<String, Integer> excelColumnProperty, Map<String, String> linkagePropertyMap, Map<String, List<Pair<String, List<String>>>> selectPropertyMap) {
-        this.excelColumnProperty = excelColumnProperty;
-        this.linkagePropertyMap = linkagePropertyMap;
-        this.selectPropertyMap = selectPropertyMap;
-    }
-
     @Override
     public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
 
@@ -53,89 +23,6 @@ public class CustomSheetWriteHandler implements SheetWriteHandler {
     public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
         Sheet sheet = writeSheetHolder.getSheet();
         sheet.createFreezePane(colSplit, rowSplit, leftmostColumn, topRow);
-        createLinkageSelectColumn(sheet);
-    }
-
-    /**
-     * 创建级联搜索列
-     * @param sheet
-     */
-    private void createLinkageSelectColumn(Sheet sheet){
-        //没有级联
-        if(CollectionUtil.isEmpty(linkagePropertyMap)){
-            return;
-        }
-        //已经处理过的字段
-        List<Object> doneProperty = new ArrayList<>();
-        linkagePropertyMap.forEach((currentProperty,parentProperty)->{
-            if(StrUtil.isBlank(parentProperty)){
-                //非级联
-                noneLinkageSelectColumn(sheet,currentProperty);
-            }else {
-                //级联
-            }
-        });
-    }
-
-    private void noneLinkageSelectColumn(Sheet sheet,String property){
-        Integer columnIndex = excelColumnProperty.get(property);
-        if(ObjectUtil.isNull(columnIndex)){
-            log.warn("[execl文件导出],property:{}显示为级联属性,找不到对应的列数",property);
-            return;
-        }
-        List<Pair<String, List<String>>> optionalSelectValues = selectPropertyMap.get(property);
-        List<String> selectValues = new ArrayList<>();
-        if(CollectionUtil.isEmpty(optionalSelectValues)){
-            selectValues.add("--- 暂无数据 ---");
-        }else {
-            optionalSelectValues.forEach(pair->{
-                if(CollectionUtil.isNotEmpty(pair.getValue())){
-                    selectValues.addAll(pair.getValue());
-                }
-            });
-        }
-        doCreateNoneLinkageSelectColumn(property,sheet,selectValues,columnIndex,sheet.getWorkbook());
-    }
-
-
-    private void doCreateNoneLinkageSelectColumn(String propertyName,Sheet sheet, Collection<String> options, int column, Workbook wb) {
-        Sheet hiddenSheet = wb.getSheet(propertyName);
-        if(hiddenSheet==null){
-            hiddenSheet = wb.createSheet(propertyName);
-        }
-        Row row;
-        //写入下拉数据到新的sheet页中
-        for (int i = 0; i < options.size(); i++) {
-            row = hiddenSheet.getRow(i);
-            if(row==null){
-                row=hiddenSheet.createRow(i);
-            }
-            Cell cell = row.createCell(column);
-            cell.setCellValue(CollectionUtil.get(options,i));
-        }
-        //获取新sheet页内容
-        String strFormula = propertyName + "!$"+ CharUtil.toString((char)(65+column))+"$1:$"+CharUtil.toString((char)(65+column))+"$65535";
-        XSSFDataValidationConstraint constraint = new XSSFDataValidationConstraint(DataValidationConstraint.ValidationType.LIST,strFormula);
-        // 设置数据有效性加载在哪个单元格上,四个参数分别是:起始行、终止行、起始列、终止列
-        CellRangeAddressList regions = createColumnCellRange(column);
-        // 数据有效性对象
-        DataValidationHelper helper = sheet.getDataValidationHelper();
-        DataValidation dataValidation = helper.createValidation(constraint, regions);
-        if (dataValidation instanceof XSSFDataValidation) {
-            // 数据校验
-            dataValidation.setSuppressDropDownArrow(true);
-            dataValidation.setShowErrorBox(true);
-        } else {
-            dataValidation.setSuppressDropDownArrow(false);
-        }
-        // 作用在目标sheet上
-        sheet.addValidationData(dataValidation);
-        //将新建的sheet页隐藏掉
-        wb.setSheetHidden(wb.getSheetIndex(propertyName), true);
-    }
-
-    private CellRangeAddressList createColumnCellRange(int column){
-        return new CellRangeAddressList(1, ExcelConstant.MAX_ROW,column,column);
     }
 
 

+ 2 - 2
tr-modules/tr-module-export/src/main/java/cn/tr/module/excel/core/service/ExcelService.java

@@ -143,8 +143,8 @@ public class ExcelService {
                 .registerWriteHandler(StrUtil.contains(sheetName, "样例")?horizontalSampleCellStyleStrategy:horizontalCellStyleStrategy)
                 .registerWriteHandler(new SimpleColumnWidthStyleStrategy(13))
                 .registerWriteHandler(new SimpleRowHeightStyleStrategy((short) 20, (short) 20))
-                .registerWriteHandler(new CustomCellWriteHandler(excelColumnProperty,linkagePropertyMap,selectPropertyMap))
-                .registerWriteHandler(new CustomSheetWriteHandler(excelColumnProperty,linkagePropertyMap,selectPropertyMap))
+                .registerWriteHandler(new CustomCellWriteHandler())
+                .registerWriteHandler(new CustomSheetWriteHandler())
                 .head(aClass).build();
         excelWriter.write(data,writeSheet);
     }