浏览代码

1.新增一对多导出工具类
2.资产与大中型结算导出改为一对多导出
3.修复资产市场结算不显示项目名称

GouGengquan 1 年之前
父节点
当前提交
b6651faf6d

+ 10 - 4
biz-base/src/main/java/com/dayou/controller/FinanceRealFundController.java

@@ -1,6 +1,7 @@
 package com.dayou.controller;
 
 import cn.hutool.core.collection.CollectionUtil;
+import com.dayou.utils.ExcelOneToManyExport;
 import com.dayou.vo.*;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -13,6 +14,7 @@ import com.dayou.common.RestResponse;
 import org.springframework.web.bind.annotation.*;
 
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.List;
 
 import javax.servlet.http.HttpServletResponse;
@@ -121,7 +123,8 @@ public class FinanceRealFundController extends BaseController {
     @GetMapping("/major/evaluator/settle/export")
     public void majorEvaluatorSettleExport(SettleMajorProductionVO production, HttpServletResponse response)throws IOException {
         List<SettleMajorProductionVO> result = financeRealFundService.majorEvaluatorSettleExport(production);
-        exportPlus(response,"大中型评估人员结算项目",result, SettleMajorProductionVO.class);
+//        exportPlus(response,"大中型评估人员结算项目",result, SettleMajorProductionVO.class);
+        ExcelOneToManyExport.exportWithParentChild(response,result, SettleMajorProductionVO.class, SettleProInvoiceVo.class,"大中型评估人员结算项目", "invoices");
     }
 
     /**
@@ -144,7 +147,8 @@ public class FinanceRealFundController extends BaseController {
     @GetMapping("/major/market/settle/export")
     public void majorMarketSettleExport(SettleMajorProductionVO production, HttpServletResponse response)throws IOException {
         List<SettleMajorProductionVO> result = financeRealFundService.majorMarketSettleExport(production);
-        exportPlus(response,"大中型市场人员结算项目",result, SettleMajorProductionVO.class);
+//        exportPlus(response,"大中型市场人员结算项目",result, SettleMajorProductionVO.class);
+        ExcelOneToManyExport.exportWithParentChild(response,result, SettleMajorProductionVO.class, SettleProInvoiceVo.class,"大中型市场人员结算项目", "invoices");
     }
 
     /**
@@ -451,7 +455,8 @@ public class FinanceRealFundController extends BaseController {
     @GetMapping("/assets/market/settle/export")
     public void assetsMarketSettleExport(SettleAssetsProductionVO settleVO, HttpServletResponse response)throws IOException {
         List<SettleAssetsProductionVO> result = financeRealFundService.assetsMarketSettleExport(settleVO);
-        exportPlus(response,"资产市场人员结算项目",result, SettleAssetsProductionVO.class);
+//        exportPlus(response,"资产市场人员结算项目",result, SettleAssetsProductionVO.class);
+        ExcelOneToManyExport.exportWithParentChild(response,result, SettleAssetsProductionVO.class, SettleProInvoiceVo.class,"资产市场人员结算项目", "invoices");
     }
 
     /**
@@ -473,7 +478,8 @@ public class FinanceRealFundController extends BaseController {
     @GetMapping("/assets/evaluator/settle/export")
     public void assetsEvaluatorSettleExport(SettleAssetsProductionVO settleVO, HttpServletResponse response)throws IOException {
         List<SettleAssetsProductionVO> result = financeRealFundService.assetsEvaluatorSettleExport(settleVO);
-        exportPlus(response,"资产评估人员结算项目",result, SettleAssetsProductionVO.class);
+//        exportPlus(response,"资产评估人员结算项目",result, SettleAssetsProductionVO.class);
+        ExcelOneToManyExport.exportWithParentChild(response,result, SettleAssetsProductionVO.class, SettleProInvoiceVo.class,"资产评估人员结算项目", "invoices");
     }
 }
 

+ 38 - 51
biz-base/src/test/java/TestAssets.java

@@ -1,51 +1,38 @@
-//import com.dayou.BaseApplication;
-//import lombok.extern.slf4j.Slf4j;
-//import org.junit.Test;
-//import org.junit.runner.RunWith;
-//import org.springframework.boot.test.context.SpringBootTest;
-//import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
-//
-//import java.util.Arrays;
-//import java.util.List;
-//import java.util.regex.Matcher;
-//import java.util.regex.Pattern;
-//
-//@Slf4j
-//@SpringBootTest(classes = BaseApplication.class)
-//@RunWith(value = SpringJUnit4ClassRunner.class)
-//public class TestAssets {
-//
-//    @Test
-//    public void test1(){
-//        // 示例字符串列表,包含被短横线-后面的数字
-//        List<String> stringList = Arrays.asList("item-123", "product-45号", "sample-6789号", "code-109898号");
-//
-//        // 初始化最大数字为Integer.MIN_VALUE
-//        int maxNumber = Integer.MIN_VALUE;
-//
-//        // 正则表达式,用于匹配短横线-后面的数字
-//        Pattern pattern = Pattern.compile("-(\\d+)");
-//
-//        // 遍历字符串列表
-//        for (String str : stringList) {
-//            // 创建匹配器
-//            Matcher matcher = pattern.matcher(str);
-//            // 在字符串中查找短横线后面的数字
-//            while (matcher.find()) {
-//                // 将找到的数字字符串转换为整数
-//                int number = Integer.parseInt(matcher.group(1));
-//                // 更新最大数字
-//                if (number > maxNumber) {
-//                    maxNumber = number;
-//                }
-//            }
-//        }
-//
-//        // 输出最大数字
-//        if (maxNumber == Integer.MIN_VALUE) {
-//            System.out.println("没有找到数字或者输入的列表为空。");
-//        } else {
-//            System.out.println("最大的数字是: " + maxNumber);
-//        }
-//    }
-//}
+import java.lang.reflect.Field;
+
+public class TestAssets {
+
+    public static Object getFieldValueByName(Object obj, String fieldName) {
+        Object fieldValue = null;
+        try {
+            // 获取对象的Class对象
+            Class<?> clazz = obj.getClass();
+            // 通过反射获取指定名称的字段
+            Field field = clazz.getDeclaredField(fieldName);
+            // 设置字段可访问,以便能够访问私有字段
+            field.setAccessible(true);
+            // 获取字段值
+            fieldValue = field.get(obj);
+        } catch (NoSuchFieldException e) {
+            System.out.println("字段 " + fieldName + " 在类 " + obj.getClass().getName() + " 中不存在.");
+        } catch (IllegalAccessException e) {
+            System.out.println("无法访问字段 " + fieldName + " 的值.");
+        }
+        return fieldValue;
+    }
+
+
+
+    public static void main(String[] args) {
+        Object person = new Object() {
+            private String name = "John Doe";
+            private int age = 30;
+        };
+
+        Object nameValue = getFieldValueByName(person, "name");
+        Object ageValue = getFieldValueByName(person, "age");
+
+        System.out.println("name = " + nameValue);
+        System.out.println("age = " + ageValue);
+    }
+}

+ 265 - 0
common/src/main/java/com/dayou/utils/ExcelOneToManyExport.java

@@ -0,0 +1,265 @@
+package com.dayou.utils;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.dayou.annotation.Excel;
+import org.apache.poi.ss.usermodel.*;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.reflect.Field;
+import java.net.URLEncoder;
+import java.util.ArrayList;
+import java.util.List;
+
+public class ExcelOneToManyExport {
+
+    /**
+     * 导出一对多excel
+     *
+     * @param response    response
+     * @param parentList  数据
+     * @param parentClazz 父级类
+     * @param childClazz  子级类
+     * @param title       标题
+     * @param listName    子级的集合字段(属性)名
+     */
+    public static void exportWithParentChild(HttpServletResponse response, List<?> parentList, Class<?> parentClazz, Class<?> childClazz, String title, String listName) throws IOException {
+        // 获取注解信息
+        List<Excel> annoFieldInfo = new ArrayList<>();
+        annoFieldInfo.addAll(getAnnotatedFieldNames(parentClazz));
+        annoFieldInfo.addAll(getAnnotatedFieldNames(childClazz));
+
+        // 父级字段(属性)名
+        List<String> parentFieldNames = getFieldNames(parentClazz);
+
+        // 子级字段(属性)名
+        List<String> childFieldNames = getFieldNames(childClazz);
+
+        XSSFWorkbook workbook = new XSSFWorkbook();
+        // 创建表
+        Sheet sheet = workbook.createSheet(title);
+        // 创建标题行(表头)
+        Row titleRow = sheet.createRow(0);
+        int nameIndex = 0;
+        for (Excel excelInfo : annoFieldInfo) {
+            titleRow.createCell(nameIndex).setCellValue(excelInfo.name());
+            titleRow.getCell(nameIndex).setCellStyle(getCellStyleBorderWithColor(workbook, IndexedColors.GREY_50_PERCENT.getIndex(), IndexedColors.WHITE.getIndex()));
+            sheet.setColumnWidth(nameIndex, (int) ((excelInfo.width() + 0.72) * 256));
+            nameIndex++;
+        }
+        int rowIndex = 1; // 开始数据行的索引
+        for (Object parent : parentList) {
+            // 创建行
+            Row parentRow = sheet.createRow(rowIndex++);
+            // 填充父对象数据
+            int dataIndex = 0;
+            for (String fieldName : parentFieldNames) {
+                // 判断数据是否为空
+                Object parentValue = getFieldValueByName(parent, fieldName);
+                if (ObjectUtil.isNotNull(parentValue)) {
+                    parentRow.createCell(dataIndex).setCellValue(parentValue.toString());
+                } else {
+                    parentRow.createCell(dataIndex).setCellValue("");
+                }
+                parentRow.getCell(dataIndex).setCellStyle(getNormalCellStyle(workbook));
+
+                // 父级写入完成,获取子级数据
+                if (dataIndex + 1 == parentFieldNames.size()) {
+                    // 获取子级集合
+                    List<?> children = (List<?>) getFieldValueByName(parent, listName);
+                    int childWriteLoop = 0;
+                    // 循环子级集合
+                    for (Object child : children) {
+                        // 判断是否第一次循环子级集合
+                        if (childWriteLoop > 0) { // 非第一次循环
+                            int childDataIndex = dataIndex + 1;
+                            // 新建行
+                            Row childRow = sheet.createRow(rowIndex++);
+                            // 需要写入空数据,否则设置样式会空指针异常
+                            for (int nullIndex = 0; nullIndex <= dataIndex; nullIndex++) {
+                                childRow.createCell(nullIndex).setCellValue("");
+                                childRow.getCell(nullIndex).setCellStyle(getNormalCellStyle(workbook));
+                            }
+                            for (String childFieldName : childFieldNames) {
+                                // 判断数据是否为空
+                                Object childValue = getFieldValueByName(child, childFieldName);
+                                if (ObjectUtil.isNotNull(childValue)) {
+                                    childRow.createCell(childDataIndex).setCellValue(childValue.toString());
+                                } else {
+                                    childRow.createCell(childDataIndex).setCellValue("");
+                                }
+                                childRow.getCell(childDataIndex).setCellStyle(getNormalCellStyle(workbook));
+                                childDataIndex++;
+                            }
+                        } else { // 第一次循环不新建行,直接跟在父级行后面填充数据
+                            int childDataIndex = dataIndex + 1;
+                            for (String childFieldName : childFieldNames) {
+                                // 判断数据是否为空
+                                Object childValue = getFieldValueByName(child, childFieldName);
+                                if (ObjectUtil.isNotNull(childValue)) {
+                                    parentRow.createCell(childDataIndex).setCellValue(childValue.toString());
+                                } else {
+                                    parentRow.createCell(childDataIndex).setCellValue("");
+                                }
+                                parentRow.getCell(childDataIndex).setCellStyle(getNormalCellStyle(workbook));
+                                childDataIndex++;
+                            }
+                        }
+                        childWriteLoop++;
+                    }
+                    // 如果子级数据是空的,也需要填充空数据,否侧设置样式会空指针
+                    if (children.isEmpty()) {
+                        int childDataIndex = dataIndex + 1;
+                        for (String childFieldName : childFieldNames) {
+                            parentRow.createCell(childDataIndex).setCellValue("");
+                            parentRow.getCell(childDataIndex).setCellStyle(getNormalCellStyle(workbook));
+                            childDataIndex++;
+                        }
+                    }
+                    // 子级数据填充完成后,且子数据集合大于一合并父级对象单元格
+                    if (!children.isEmpty() && children.size() > 1) {
+                        for (int i = 0; i < parentFieldNames.size(); i++) {
+                            sheet.addMergedRegion(new CellRangeAddress(rowIndex - 2, rowIndex - 1, i, i));
+                        }
+                    }
+                }
+                dataIndex++;
+            }
+        }
+
+        // 设置响应头
+        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
+        response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(title, "UTF-8") + ".xlsx");
+
+        // 写入Excel文件
+        OutputStream outputStream = response.getOutputStream();
+        workbook.write(outputStream);
+
+    }
+
+    /**
+     * 通过字段(属性)名获取指定字段的值
+     *
+     * @param obj       对象
+     * @param fieldName 字段名
+     * @return String
+     */
+    public static Object getFieldValueByName(Object obj, String fieldName) {
+        Object fieldValue = null;
+        try {
+            // 获取对象的Class对象
+            Class<?> clazz = obj.getClass();
+            // 通过反射获取指定名称的字段
+            Field field = clazz.getDeclaredField(fieldName);
+            // 设置字段可访问,以便能够访问私有字段
+            field.setAccessible(true);
+            // 获取字段值
+            fieldValue = field.get(obj);
+        } catch (NoSuchFieldException e) {
+            System.out.println("字段 " + fieldName + " 在类 " + obj.getClass().getName() + " 中不存在.");
+        } catch (IllegalAccessException e) {
+            System.out.println("无法访问字段 " + fieldName + " 的值.");
+        }
+        return fieldValue;
+    }
+
+    /**
+     * 获取类的字段名
+     *
+     * @param clazz class
+     * @return List<String>
+     */
+    public static List<String> getFieldNames(Class<?> clazz) {
+
+        List<String> fieldNames = new ArrayList<>();
+
+        // 获取类的所有声明字段(不包括继承的字段)
+        Field[] declaredFields = clazz.getDeclaredFields();
+        for (Field field : declaredFields) {
+            if (field.isAnnotationPresent(Excel.class)) {
+                fieldNames.add(field.getName());
+            }
+        }
+        return fieldNames;
+    }
+
+    /**
+     * 获取clazz的注解name属性的值
+     *
+     * @param clazz 类
+     * @return List<String>
+     */
+    public static List<Excel> getAnnotatedFieldNames(Class<?> clazz) {
+        List<Excel> annoFieldInfo = new ArrayList<>();
+        Field[] fields = clazz.getDeclaredFields();
+
+        for (Field field : fields) {
+            field.setAccessible(true); // 确保可以访问私有字段
+            if (field.isAnnotationPresent(Excel.class)) {
+                Excel excelAnnotation = field.getAnnotation(Excel.class);
+                annoFieldInfo.add(excelAnnotation);
+            }
+        }
+
+        return annoFieldInfo;
+    }
+
+    /**
+     * 设置单元格边框线与字体、颜色等
+     *
+     * @param workbook  工作簿
+     * @param backColor 背景色
+     * @param textColor 字体颜色
+     * @return CellStyle
+     */
+    public static CellStyle getCellStyleBorderWithColor(XSSFWorkbook workbook, Short backColor, Short textColor) {
+        // 设置边框样式
+        CellStyle style = workbook.createCellStyle();
+        if (ObjectUtil.isNotNull(backColor)) {
+            style.setFillBackgroundColor(backColor);
+        }
+        Font headerFont = workbook.createFont();
+        headerFont.setFontName("Arial");
+        headerFont.setFontHeightInPoints((short) 10);
+        if (ObjectUtil.isNotNull(textColor)) {
+            headerFont.setBold(true);
+        }
+        style.setFont(headerFont);
+        style.setAlignment(HorizontalAlignment.CENTER);
+        style.setVerticalAlignment(VerticalAlignment.CENTER);
+        style.setBorderRight(BorderStyle.THIN);
+        style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
+        style.setBorderLeft(BorderStyle.THIN);
+        style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
+        style.setBorderTop(BorderStyle.THIN);
+        style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
+        style.setBorderBottom(BorderStyle.THIN);
+        style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
+        return style;
+    }
+
+    /**
+     * 设置单元格边框线
+     *
+     * @param workbook  工作簿
+     * @return CellStyle
+     */
+    public static CellStyle getNormalCellStyle(XSSFWorkbook workbook) {
+        CellStyle style = workbook.createCellStyle();
+        style.setAlignment(HorizontalAlignment.CENTER);
+        style.setVerticalAlignment(VerticalAlignment.CENTER);
+        style.setBorderRight(BorderStyle.THIN);
+        style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
+        style.setBorderLeft(BorderStyle.THIN);
+        style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
+        style.setBorderTop(BorderStyle.THIN);
+        style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
+        style.setBorderBottom(BorderStyle.THIN);
+        style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
+        return style;
+    }
+}
+

+ 1 - 1
dao/src/main/resources/mapper/FinanceRealFundMapper.xml

@@ -1396,7 +1396,7 @@
         ap.save_file_date,
         IF
         ( fc.claim_datetime > ap.delivery_date, fc.claim_datetime, ap.delivery_date ) AS settleDate,
-        ap.assets_name,
+        ap.assets_name AS projectName,
         a.bailor,
         ap.evaluate_amount,
         u.name AS principal,

+ 2 - 2
domain/src/main/java/com/dayou/vo/SettleMajorProductionVO.java

@@ -23,7 +23,7 @@ public class SettleMajorProductionVO {
     @Excel(name = "项目编号")
     private String orderId;
 
-    @Excel(name = "产品号")
+    @Excel(name = "产品号", width = 30)
     private String reportNo;
 
     @Excel(name = "结算日期")
@@ -38,7 +38,7 @@ public class SettleMajorProductionVO {
     @Excel(name = "送达日期")
     private LocalDate deliveryDate;
 
-    @Excel(name = "项目名称")
+    @Excel(name = "项目名称", width = 30)
     private String name;
 
     @Excel(name = "客户名称")

+ 1 - 1
domain/src/main/java/com/dayou/vo/SettleProInvoiceVo.java

@@ -16,7 +16,7 @@ public class SettleProInvoiceVo {
     @Excel(name = "开票人")
     private String invoiceUser;
 
-    @Excel(name = "发票号")
+    @Excel(name = "发票号", width = 30)
     private String invoiceNo;
 
 }