许鹏程
2023-06-29 cb4df5a1c9cda76e828fa202990df33be0735105
src/main/java/com/product/server/report/service/GroupReportService.java
@@ -1,5 +1,6 @@
package com.product.server.report.service;
import cn.hutool.core.util.NumberUtil;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
@@ -10,7 +11,12 @@
import com.product.core.service.support.AbstractBaseService;
import com.product.core.spring.context.SpringMVCContextHolder;
import com.product.server.report.config.CmnConst;
import com.product.server.report.entity.ReportColumn;
import com.product.util.BaseUtil;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -25,993 +31,1045 @@
 */
@Component
public class GroupReportService extends AbstractBaseService {
    @Autowired
    private DataListReportService dataListReportService;
   @Autowired
   private DataListReportService dataListReportService;
    /**
     * 报表-解析
     * @param recordDte             业务数据dte
     * @param totalName             总计名称
     * @param reportConfigMap       报表配置缓存map
     * @param tableStyle
     * @return                      获取分组报表的详情
     */
    public JSONObject getReport(DataTableEntity recordDte, String totalName, Map<Integer, List<JSONObject>> reportConfigMap, StringBuilder tableStyle) {
        StringBuilder reportHtml = new StringBuilder(4096);
   /**
    * 报表-解析
    *
    * @param recordDte       业务数据dte
    * @param totalName       总计名称
    * @param reportConfigMap 报表配置缓存map
    * @return 获取分组报表的详情
    */
   public List<List<ReportColumn>>[] getReport(DataTableEntity recordDte, String totalName, Map<Integer, List<JSONObject>> reportConfigMap) {
//      StringBuilder reportHtml = new StringBuilder(4096);
      List<List<ReportColumn>>[] reportColumnList = new List[]{new ArrayList(), new ArrayList(), new ArrayList()};
      // css
//      StringBuilder cssHtml = dataListReportService.getCssHtml();
        // css
        StringBuilder cssHtml = dataListReportService.getCssHtml();
      // 分组表头区和数据区
//      StringBuilder groupAndDataAreaHtml = new StringBuilder(1024);
      Map<String, Set<String>> headAndTailTitleDataMap = Maps.newHashMap();
      int totalColCount = reportConfigMap.get(0).size();
      //数据区域数据
      List<List<ReportColumn>> dataAreaList = new ArrayList<>();
      int[] number = getGroupAndDataAreaHtmlAndReturnDataAreaColCount(dataAreaList, reportConfigMap, headAndTailTitleDataMap, recordDte, totalName);
      int dataAreaColCount = number[0];
      //标题行数
      int titleAreaRow = number[1];
      totalColCount = Math.max(totalColCount, dataAreaColCount);
      reportColumnList[1] = dataAreaList;
      // 头部标题区
      if (!reportConfigMap.get(1).isEmpty()) {
         reportColumnList[0] = dataListReportService.getTitleRows(reportConfigMap.get(1), totalColCount, headAndTailTitleDataMap, "head");
      }
      //从数据区域取出标题行放入头部标题区并将标题行从数据区域删除
      if (titleAreaRow > 0) {
         for (int i = 0; i < titleAreaRow; i++) {
            reportColumnList[0].add(dataAreaList.get(0));
            dataAreaList.remove(0);
         }
      }
      // 底部标题区
      if (!reportConfigMap.get(3).isEmpty()) {
         reportColumnList[2] = dataListReportService.getTitleRows(reportConfigMap.get(3), totalColCount, headAndTailTitleDataMap, "tail");
      }
        // 分组表头区和数据区
        StringBuilder groupAndDataAreaHtml = new StringBuilder(1024);
        Map<String, Set<String>> headAndTailTitleDataMap = Maps.newHashMap();
        int totalColCount = reportConfigMap.get(0).size();
        int dataAreaColCount = getGroupAndDataAreaHtmlAndReturnDataAreaColCount(groupAndDataAreaHtml, reportConfigMap, headAndTailTitleDataMap, recordDte, totalName);
        totalColCount = Math.max(totalColCount, dataAreaColCount);
      return reportColumnList;
   }
        // 头部标题区
        StringBuilder headTitleHtml = null;
        if (!reportConfigMap.get(1).isEmpty()) {
            headTitleHtml = dataListReportService.getTitleHtml(reportConfigMap.get(1), totalColCount, headAndTailTitleDataMap, "head");
        }
   /**
    * 报表-解析-放入分组表头区和数据Html,返回列数
    *
    * @param dataAreaList            数据区域数据
    * @param reportConfigMap         报表缓存数据map
    * @param headAndTailTitleDataMap 头部、尾部标题区数据字段map容器
    * @param recordDte               数据源集合
    * @param totalName               总计名称
    * @return 数据区总列数
    */
   private int[] getGroupAndDataAreaHtmlAndReturnDataAreaColCount(List<List<ReportColumn>> dataAreaList, Map<Integer, List<JSONObject>> reportConfigMap, Map<String, Set<String>> headAndTailTitleDataMap, DataTableEntity recordDte, String totalName) {
      // 分组表头区字段缓存map
      Map<String, JSONObject> groupAreaFieldConfigMap = dataListReportService.groupAndDataJSONObject2Map(reportConfigMap.get(2));
      // 数据区字段缓存map
      Map<String, JSONObject> dataAreaFieldConfigMap = dataListReportService.groupAndDataJSONObject2Map(reportConfigMap.get(0));
        // 底部标题区
        StringBuilder tailTitleHtml = null;
        if (!reportConfigMap.get(3).isEmpty()) {
            tailTitleHtml = dataListReportService.getTitleHtml(reportConfigMap.get(3), totalColCount, headAndTailTitleDataMap, "tail");
        }
      // 分组表头区分组统计字段名称list
      List<String> groupAreaGroupStatisticsFieldNameList = Lists.newArrayList();
      // 分组表头区分组字段名称list
      List<String> groupAreaGroupFieldNameList = Lists.newArrayList();
      // 分组表头区区域范围obj
      JSONObject groupAreaRangeObj = new JSONObject();
      groupAreaFieldConfigMap.forEach((fieldName, fieldConfigObj) -> {
         groupAreaGroupFieldNameList.add(fieldName);
         if ("1".equals(fieldConfigObj.getString(CmnConst.ATTR_IS_STATISTICS))) {
            groupAreaGroupStatisticsFieldNameList.add(fieldName);
         }
         if (groupAreaRangeObj.getIntValue(CmnConst.MIN_X) == 0) {
            groupAreaRangeObj.put(CmnConst.MIN_X, fieldConfigObj.getIntValue(CmnConst.ATTR_X));
         } else {
            groupAreaRangeObj.put(CmnConst.MIN_X, Math.min(groupAreaRangeObj.getIntValue(CmnConst.MIN_X), fieldConfigObj.getIntValue(CmnConst.ATTR_X)));
         }
         groupAreaRangeObj.put(CmnConst.MAX_X, Math.max(groupAreaRangeObj.getIntValue(CmnConst.MAX_X), fieldConfigObj.getIntValue(CmnConst.ATTR_X) + Math.max(1, fieldConfigObj.getIntValue(CmnConst.ATTR_COLSPAN)) - 1));
         groupAreaRangeObj.put(CmnConst.MAX_Y, Math.max(groupAreaRangeObj.getIntValue(CmnConst.MAX_Y), fieldConfigObj.getIntValue(CmnConst.ATTR_Y) + Math.max(1, fieldConfigObj.getIntValue(CmnConst.ATTR_ROWSPAN)) - 1));
      });
        reportHtml.append("\n<body>\n<table").append(tableStyle).append(">")
                .append(cssHtml)
                .append(headTitleHtml == null ? "" : headTitleHtml)
                .append(groupAndDataAreaHtml)
                .append(tailTitleHtml == null ? "" : tailTitleHtml)
                .append("\n</table>\n</body>");
      // 数据区分组统计字段名称list
      List<String> dataAreaGroupStatisticsFieldNameList = Lists.newArrayList();
      // 数据区分组字段名称list
      List<String> dataAreaGroupFieldNameList = Lists.newArrayList();
      // 数据区特殊统计字段名称list-分组表头区下统计字段
      List<String> dataAreaSpStatisticsFieldNameList = Lists.newArrayList();
      // 数据区普通统计字段名称list-非数据区分组字段,非分组表头区下统计字段
      List<String> dataAreaCommonStatisticsFieldNameList = Lists.newArrayList();
      dataAreaFieldConfigMap.forEach((fieldName, fieldConfigObj) -> {
         if ("1".equals(fieldConfigObj.getString(CmnConst.ATTR_IS_GROUP))) {
            dataAreaGroupFieldNameList.add(fieldName);
            if ("1".equals(fieldConfigObj.getString(CmnConst.ATTR_IS_STATISTICS))) {
               dataAreaGroupStatisticsFieldNameList.add(fieldName);
            }
         } else {
            if (fieldConfigObj.getIntValue(CmnConst.ATTR_X) < groupAreaRangeObj.getIntValue(CmnConst.MIN_X) || fieldConfigObj.getIntValue(CmnConst.ATTR_X) > groupAreaRangeObj.getIntValue(CmnConst.MAX_X)) {
               dataAreaCommonStatisticsFieldNameList.add(fieldName);
            } else {
               dataAreaSpStatisticsFieldNameList.add(fieldName);
            }
         }
      });
        JSONObject resultObj = new JSONObject();
        resultObj.put(CmnConst.RETURN_ATTR_RESULT, true);
        resultObj.put(CmnConst.RETURN_ATTR_MESSAGE, "获取报表成功!");
        resultObj.put(CmnConst.RETURN_ATTR_HTML, reportHtml);
        return resultObj;
    }
      // 获取分组表头统计字段对应的数据区字段map
      Map<String, List<String>> groupAreaStatisticsField2DataAreaFieldMap = getGroupAreaStatisticsField2DataAreaFieldMap(groupAreaFieldConfigMap, dataAreaFieldConfigMap);
      // 获取分组表头区末行分组字段对应数据区字段map
      Map<String, List<String>> groupAreaLastStageField2DataAreaFieldMap = getGroupAreaLastStageField2DataAreaFieldMap(groupAreaFieldConfigMap, dataAreaFieldConfigMap, groupAreaRangeObj);
    /**
     * 报表-解析-放入分组表头区和数据Html,返回列数
     * @param groupAndDataAreaHtml          html容器
     * @param reportConfigMap               报表缓存数据map
     * @param headAndTailTitleDataMap       头部、尾部标题区数据字段map容器
     * @param recordDte                     数据源集合
     * @param totalName                     总计名称
     * @return                              数据区总列数
     */
    private int getGroupAndDataAreaHtmlAndReturnDataAreaColCount(StringBuilder groupAndDataAreaHtml, Map<Integer, List<JSONObject>> reportConfigMap, Map<String, Set<String>> headAndTailTitleDataMap, DataTableEntity recordDte, String totalName) {
        // 分组表头区字段缓存map
        Map<String, JSONObject> groupAreaFieldConfigMap = dataListReportService.groupAndDataJSONObject2Map(reportConfigMap.get(2));
        // 数据区字段缓存map
        Map<String, JSONObject> dataAreaFieldConfigMap = dataListReportService.groupAndDataJSONObject2Map(reportConfigMap.get(0));
      // 获取指定数据集中包含的数据区字段集合
      Set<String> headAndTailFieldSet = Sets.newHashSet();
      headAndTailFieldSet.addAll(dataListReportService.getDataFields(reportConfigMap.get(1)));
      headAndTailFieldSet.addAll(dataListReportService.getDataFields(reportConfigMap.get(3)));
        // 分组表头区分组统计字段名称list
        List<String> groupAreaGroupStatisticsFieldNameList = Lists.newArrayList();
        // 分组表头区分组字段名称list
        List<String> groupAreaGroupFieldNameList = Lists.newArrayList();
        // 分组表头区区域范围obj
        JSONObject groupAreaRangeObj = new JSONObject();
        groupAreaFieldConfigMap.forEach((fieldName, fieldConfigObj) -> {
            groupAreaGroupFieldNameList.add(fieldName);
            if ("1".equals(fieldConfigObj.getString(CmnConst.ATTR_IS_STATISTICS))) {
                groupAreaGroupStatisticsFieldNameList.add(fieldName);
            }
            if (groupAreaRangeObj.getIntValue(CmnConst.MIN_X) == 0) {
                groupAreaRangeObj.put(CmnConst.MIN_X, fieldConfigObj.getIntValue(CmnConst.ATTR_X));
            } else {
                groupAreaRangeObj.put(CmnConst.MIN_X, Math.min(groupAreaRangeObj.getIntValue(CmnConst.MIN_X), fieldConfigObj.getIntValue(CmnConst.ATTR_X)));
            }
            groupAreaRangeObj.put(CmnConst.MAX_X, Math.max(groupAreaRangeObj.getIntValue(CmnConst.MAX_X), fieldConfigObj.getIntValue(CmnConst.ATTR_X) + Math.max(1, fieldConfigObj.getIntValue(CmnConst.ATTR_COLSPAN)) - 1));
            groupAreaRangeObj.put(CmnConst.MAX_Y, Math.max(groupAreaRangeObj.getIntValue(CmnConst.MAX_Y), fieldConfigObj.getIntValue(CmnConst.ATTR_Y) + Math.max(1, fieldConfigObj.getIntValue(CmnConst.ATTR_ROWSPAN)) - 1));
        });
      // 统计map
      Map<JSONObject, JSONObject> statisticsMap = Maps.newLinkedHashMap();
      // 分组表头区数据obj
      JSONObject groupAreaFieldRecordObj = new JSONObject(Maps.newTreeMap((o1, o2) -> dataListReportService.compare(o1, o2)));
      // 数据区分组字段obj
      JSONObject dataAreaFieldRecordObj = new JSONObject(Maps.newLinkedHashMap());
        // 数据区分组统计字段名称list
        List<String> dataAreaGroupStatisticsFieldNameList = Lists.newArrayList();
        // 数据区分组字段名称list
        List<String> dataAreaGroupFieldNameList = Lists.newArrayList();
        // 数据区特殊统计字段名称list-分组表头区下统计字段
        List<String> dataAreaSpStatisticsFieldNameList = Lists.newArrayList();
        // 数据区普通统计字段名称list-非数据区分组字段,非分组表头区下统计字段
        List<String> dataAreaCommonStatisticsFieldNameList = Lists.newArrayList();
        dataAreaFieldConfigMap.forEach((fieldName, fieldConfigObj) -> {
            if ("1".equals(fieldConfigObj.getString(CmnConst.ATTR_IS_GROUP))) {
                dataAreaGroupFieldNameList.add(fieldName);
                if ("1".equals(fieldConfigObj.getString(CmnConst.ATTR_IS_STATISTICS))) {
                    dataAreaGroupStatisticsFieldNameList.add(fieldName);
                }
            } else {
                if (fieldConfigObj.getIntValue(CmnConst.ATTR_X) < groupAreaRangeObj.getIntValue(CmnConst.MIN_X) || fieldConfigObj.getIntValue(CmnConst.ATTR_X) > groupAreaRangeObj.getIntValue(CmnConst.MAX_X)) {
                    dataAreaCommonStatisticsFieldNameList.add(fieldName);
                } else {
                    dataAreaSpStatisticsFieldNameList.add(fieldName);
                }
            }
        });
      FieldSetEntity recordFse;
      for (int i = 0; i < recordDte.getRows(); i++) {
         recordFse = recordDte.getFieldSetEntity(i);
        // 获取分组表头统计字段对应的数据区字段map
        Map<String, List<String>> groupAreaStatisticsField2DataAreaFieldMap = getGroupAreaStatisticsField2DataAreaFieldMap(groupAreaFieldConfigMap, dataAreaFieldConfigMap);
        // 获取分组表头区末行分组字段对应数据区字段map
        Map<String, List<String>> groupAreaLastStageField2DataAreaFieldMap = getGroupAreaLastStageField2DataAreaFieldMap(groupAreaFieldConfigMap, dataAreaFieldConfigMap, groupAreaRangeObj);
         // 获取头部、尾部标题区数据字段
         dataListReportService.getHeadAndTailTitleDataMap(headAndTailTitleDataMap, headAndTailFieldSet, recordFse);
        // 获取指定数据集中包含的数据区字段集合
        Set<String> headAndTailFieldSet = Sets.newHashSet();
        headAndTailFieldSet.addAll(dataListReportService.getDataFields(reportConfigMap.get(1)));
        headAndTailFieldSet.addAll(dataListReportService.getDataFields(reportConfigMap.get(3)));
         // 获取分组表头区数据obj
         getGroupAreaFieldRecordObj(groupAreaFieldRecordObj, groupAreaFieldConfigMap, recordFse, groupAreaStatisticsField2DataAreaFieldMap, groupAreaLastStageField2DataAreaFieldMap);
        // 统计map
        Map<JSONObject, JSONObject> statisticsMap = Maps.newLinkedHashMap();
        // 分组表头区数据obj
        JSONObject groupAreaFieldRecordObj = new JSONObject(Maps.newTreeMap((o1, o2) -> dataListReportService.compare(o1, o2)));
        // 数据区分组字段obj
        JSONObject dataAreaFieldRecordObj = new JSONObject(Maps.newLinkedHashMap());
         // 获取数据区分组字段obj
         getDataAreaGroupFieldRecordObj(dataAreaFieldRecordObj, dataAreaFieldConfigMap, recordFse);
        FieldSetEntity recordFse;
        for (int i = 0;i < recordDte.getRows();i++) {
            recordFse = recordDte.getFieldSetEntity(i);
         // 获取数据区特殊字段的统计
         statisticsDataAreaSpField(statisticsMap, dataAreaFieldConfigMap, dataAreaSpStatisticsFieldNameList, recordFse);
            // 获取头部、尾部标题区数据字段
            dataListReportService.getHeadAndTailTitleDataMap(headAndTailTitleDataMap, headAndTailFieldSet, recordFse);
         // 获取数据区普通字段的统计
         statisticsDataAreaCommonField(statisticsMap, dataAreaFieldConfigMap, dataAreaCommonStatisticsFieldNameList, recordFse);
      }
            // 获取分组表头区数据obj
            getGroupAreaFieldRecordObj(groupAreaFieldRecordObj, groupAreaFieldConfigMap, recordFse, groupAreaStatisticsField2DataAreaFieldMap, groupAreaLastStageField2DataAreaFieldMap);
      // 获取分组表头区和数据区总列数
      int totalColCount = getTotalColCount(groupAreaFieldRecordObj, dataAreaGroupFieldNameList.size(), dataAreaCommonStatisticsFieldNameList.size());
            // 获取数据区分组字段obj
            getDataAreaGroupFieldRecordObj(dataAreaFieldRecordObj, dataAreaFieldConfigMap, recordFse);
      // 数据标题list
      List<JSONObject> dataTitleList = Lists.newArrayList();
      // 获取标题html
      List<List<ReportColumn>> dataAreaTitleRows = getDataAreaTitleRows(dataTitleList, groupAreaFieldRecordObj, dataAreaFieldConfigMap, groupAreaRangeObj, dataAreaCommonStatisticsFieldNameList);
      dataAreaList.addAll(dataAreaTitleRows);
      // 获取内容html
      List<List<ReportColumn>> dataAreaDataRows = getDataAreaDataRows(dataTitleList, dataAreaFieldRecordObj, statisticsMap, totalName, dataAreaGroupFieldNameList, dataAreaFieldConfigMap);
      dataAreaList.addAll(dataAreaDataRows);
            // 获取数据区特殊字段的统计
            statisticsDataAreaSpField(statisticsMap, dataAreaFieldConfigMap, dataAreaSpStatisticsFieldNameList, recordFse);
      return new int[]{totalColCount, dataAreaTitleRows.size()};
   }
            // 获取数据区普通字段的统计
            statisticsDataAreaCommonField(statisticsMap, dataAreaFieldConfigMap, dataAreaCommonStatisticsFieldNameList, recordFse);
        }
   /**
    * 获取分组表头统计字段对应的数据区字段map
    *
    * @param groupAreaFieldConfigMap 分组表头区字段缓存map
    * @param dataAreaFieldConfigMap  数据区字段缓存map
    * @return 分组表头统计字段对应的数据区字段map
    */
   private Map<String, List<String>> getGroupAreaStatisticsField2DataAreaFieldMap(Map<String, JSONObject> groupAreaFieldConfigMap, Map<String, JSONObject> dataAreaFieldConfigMap) {
      Map<String, List<String>> resultMap = Maps.newLinkedHashMap();
      String groupAreaFieldName;
      JSONObject groupAreaFieldConfigObj;
      JSONObject dataAreaFieldConfigObj;
      for (Map.Entry<String, JSONObject> groupAreaFieldConfigEntry : groupAreaFieldConfigMap.entrySet()) {
         groupAreaFieldConfigObj = groupAreaFieldConfigEntry.getValue();
         if (!"1".equals(groupAreaFieldConfigObj.getString(CmnConst.ATTR_IS_STATISTICS))) {
            continue;
         }
         groupAreaFieldName = groupAreaFieldConfigEntry.getKey();
         for (Map.Entry<String, JSONObject> dataAreaFieldConfigEntry : dataAreaFieldConfigMap.entrySet()) {
            dataAreaFieldConfigObj = dataAreaFieldConfigEntry.getValue();
            if (dataListReportService.transfer2List(dataAreaFieldConfigObj.get(CmnConst.ATTR_GROUP_AREA_GROUP_FIELD)).contains(groupAreaFieldName)) {
               resultMap.computeIfAbsent(groupAreaFieldName, k -> Lists.newArrayList()).add(dataAreaFieldConfigEntry.getKey());
            }
         }
      }
      return resultMap;
   }
        // 获取分组表头区和数据区总列数
        int totalColCount = getTotalColCount(groupAreaFieldRecordObj, dataAreaGroupFieldNameList.size(), dataAreaCommonStatisticsFieldNameList.size());
   /**
    * 获取分组表头区末行分组字段对应数据区字段map
    *
    * @param groupAreaFieldConfigMap 分组表头区字段缓存map
    * @param dataAreaFieldConfigMap  数据区字段缓存map
    * @param groupAreaRangeObj       分组表头区范围obj
    * @return 分组表头区末行分组字段对应数据区字段map
    */
   private Map<String, List<String>> getGroupAreaLastStageField2DataAreaFieldMap(Map<String, JSONObject> groupAreaFieldConfigMap, Map<String, JSONObject> dataAreaFieldConfigMap, JSONObject groupAreaRangeObj) {
      Map<String, List<String>> resultMap = Maps.newLinkedHashMap();
      String groupFieldName;
      JSONObject groupAreaFieldConfigObj;
      JSONObject dataAreaFieldConfigObj;
      for (Map.Entry<String, JSONObject> groupAreaFieldConfigEntry : groupAreaFieldConfigMap.entrySet()) {
         groupAreaFieldConfigObj = groupAreaFieldConfigEntry.getValue();
         if (groupAreaFieldConfigObj.getIntValue(CmnConst.ATTR_Y) + Math.max(1, groupAreaFieldConfigObj.getIntValue(CmnConst.ATTR_ROWSPAN)) - 1 < groupAreaRangeObj.getIntValue(CmnConst.MAX_Y)) {
            continue;
         }
         groupFieldName = groupAreaFieldConfigEntry.getKey();
         for (Map.Entry<String, JSONObject> dataAreaFieldConfigEntry : dataAreaFieldConfigMap.entrySet()) {
            dataAreaFieldConfigObj = dataAreaFieldConfigEntry.getValue();
            if (dataListReportService.transfer2List(dataAreaFieldConfigObj.get(CmnConst.ATTR_GROUP_AREA_GROUP_FIELD)).contains(groupFieldName)) {
               resultMap.computeIfAbsent(groupFieldName, k -> Lists.newArrayList()).add(dataAreaFieldConfigEntry.getKey());
            }
         }
        // 数据标题list
        List<JSONObject> dataTitleList = Lists.newArrayList();
        // 获取标题html
        groupAndDataAreaHtml.append(getDataAreaTitleHtml(dataTitleList, groupAreaFieldRecordObj, dataAreaFieldConfigMap, groupAreaRangeObj, dataAreaCommonStatisticsFieldNameList));
        // 获取内容html
        groupAndDataAreaHtml.append(getDataAreaDataHtml(dataTitleList, dataAreaFieldRecordObj, statisticsMap, totalName, dataAreaGroupFieldNameList, dataAreaFieldConfigMap));
      }
      return resultMap;
   }
        return totalColCount;
    }
   /**
    * 获取标题-分组表头区数据obj
    *
    * @param groupAreaFieldRecordObj                   分组表头区字段记录obj
    * @param groupAreaFieldConfigMap                   分组表头区字段缓存map
    * @param recordFse                                 业务数据记录
    * @param groupAreaStatisticsField2DataAreaFieldMap 分组表头区统计字段对应数据区字段map
    * @param groupAreaLastStageField2DataAreaFieldMap  分组表头区末级字段对应数据区字段map
    */
   private void getGroupAreaFieldRecordObj(JSONObject groupAreaFieldRecordObj, Map<String, JSONObject> groupAreaFieldConfigMap, FieldSetEntity recordFse,
                                 Map<String, List<String>> groupAreaStatisticsField2DataAreaFieldMap, Map<String, List<String>> groupAreaLastStageField2DataAreaFieldMap) {
      JSONObject parentObj = groupAreaFieldRecordObj;
      JSONObject subObj;
      String value;
      List<String> list;
      String groupAreaGroupFieldName;
      int i = 0;
      List<String> statisticsFieldList;
      String realValue;
      for (Map.Entry<String, JSONObject> entry : groupAreaFieldConfigMap.entrySet()) {
         list = Lists.newArrayList();
         list.addAll(dataListReportService.transfer2List(entry.getValue().get(CmnConst.ATTR_GROUP_AREA_GROUP_FIELD)));
         list.add(entry.getKey());
         for (; i < list.size(); i++) {
            groupAreaGroupFieldName = list.get(i);
            realValue = dataListReportService.getRealValue(recordFse, groupAreaGroupFieldName);
            value = recordFse.getString(groupAreaGroupFieldName);
    /**
     * 获取分组表头统计字段对应的数据区字段map
     * @param groupAreaFieldConfigMap       分组表头区字段缓存map
     * @param dataAreaFieldConfigMap        数据区字段缓存map
     * @return                              分组表头统计字段对应的数据区字段map
     */
    private Map<String,List<String>> getGroupAreaStatisticsField2DataAreaFieldMap(Map<String, JSONObject> groupAreaFieldConfigMap, Map<String, JSONObject> dataAreaFieldConfigMap) {
        Map<String, List<String>> resultMap = Maps.newLinkedHashMap();
        String groupAreaFieldName;
        JSONObject groupAreaFieldConfigObj;
        JSONObject dataAreaFieldConfigObj;
        for (Map.Entry<String, JSONObject> groupAreaFieldConfigEntry : groupAreaFieldConfigMap.entrySet()) {
            groupAreaFieldConfigObj = groupAreaFieldConfigEntry.getValue();
            if (!"1".equals(groupAreaFieldConfigObj.getString(CmnConst.ATTR_IS_STATISTICS))) {
                continue;
            }
            groupAreaFieldName = groupAreaFieldConfigEntry.getKey();
            for (Map.Entry<String, JSONObject> dataAreaFieldConfigEntry : dataAreaFieldConfigMap.entrySet()) {
                dataAreaFieldConfigObj = dataAreaFieldConfigEntry.getValue();
                if (dataListReportService.transfer2List(dataAreaFieldConfigObj.get(CmnConst.ATTR_GROUP_AREA_GROUP_FIELD)).contains(groupAreaFieldName)) {
                    resultMap.computeIfAbsent(groupAreaFieldName, k -> Lists.newArrayList()).add(dataAreaFieldConfigEntry.getKey());
                }
            }
        }
        return resultMap;
    }
            if (parentObj.get(value) == null) {
               subObj = new JSONObject(Maps.newTreeMap((o1, o2) -> dataListReportService.compare(o1, o2)));
               parentObj.put(value, subObj);
               // 添加分组表头区分组统计字段对应数据区字段
               if (groupAreaStatisticsField2DataAreaFieldMap.containsKey(groupAreaGroupFieldName)) {
                  parentObj.put(value + CmnConst.STATISTICS_NAME, groupAreaStatisticsField2DataAreaFieldMap.get(groupAreaGroupFieldName));
                  statisticsFieldList = dataListReportService.transfer2List(parentObj.get(CmnConst.ATTR_STATISTICS_FIELD));
                  if (statisticsFieldList.isEmpty()) {
                     parentObj.put(CmnConst.ATTR_STATISTICS_FIELD, statisticsFieldList);
                  }
                  if (!statisticsFieldList.contains(value + CmnConst.STATISTICS_NAME)) {
                     statisticsFieldList.add(value + CmnConst.STATISTICS_NAME);
                  }
               }
               // 添加分组表头区末级字段对应数据区字段
               if (groupAreaLastStageField2DataAreaFieldMap.containsKey(groupAreaGroupFieldName)) {
                  parentObj.put(value, groupAreaLastStageField2DataAreaFieldMap.get(groupAreaGroupFieldName));
               }
               // 添加field_info
               if (StringUtils.isEmpty(parentObj.getString(CmnConst.ATTR_FIELD_INFO))) {
                  parentObj.put(CmnConst.ATTR_FIELD_INFO, dataListReportService.fieldName2FieldInfo(groupAreaGroupFieldName));
               }
               if (!StringUtils.isEmpty(realValue)) {
                  subObj.put(CmnConst.ATTR_REAL_VALUE, realValue);
               }
            } else {
               if (!(parentObj.get(value) instanceof JSONObject)) {
                  continue;
               }
               subObj = parentObj.getJSONObject(value);
            }
            parentObj = subObj;
         }
      }
   }
    /**
     * 获取分组表头区末行分组字段对应数据区字段map
     * @param groupAreaFieldConfigMap       分组表头区字段缓存map
     * @param dataAreaFieldConfigMap        数据区字段缓存map
     * @param groupAreaRangeObj             分组表头区范围obj
     * @return                              分组表头区末行分组字段对应数据区字段map
     */
    private Map<String,List<String>> getGroupAreaLastStageField2DataAreaFieldMap(Map<String, JSONObject> groupAreaFieldConfigMap, Map<String, JSONObject> dataAreaFieldConfigMap, JSONObject groupAreaRangeObj) {
        Map<String, List<String>> resultMap = Maps.newLinkedHashMap();
        String groupFieldName;
        JSONObject groupAreaFieldConfigObj;
        JSONObject dataAreaFieldConfigObj;
        for (Map.Entry<String, JSONObject> groupAreaFieldConfigEntry : groupAreaFieldConfigMap.entrySet()) {
            groupAreaFieldConfigObj = groupAreaFieldConfigEntry.getValue();
            if (groupAreaFieldConfigObj.getIntValue(CmnConst.ATTR_Y) + Math.max(1, groupAreaFieldConfigObj.getIntValue(CmnConst.ATTR_ROWSPAN)) - 1 < groupAreaRangeObj.getIntValue(CmnConst.MAX_Y)) {
                continue;
            }
            groupFieldName = groupAreaFieldConfigEntry.getKey();
            for (Map.Entry<String, JSONObject> dataAreaFieldConfigEntry : dataAreaFieldConfigMap.entrySet()) {
                dataAreaFieldConfigObj = dataAreaFieldConfigEntry.getValue();
                if (dataListReportService.transfer2List(dataAreaFieldConfigObj.get(CmnConst.ATTR_GROUP_AREA_GROUP_FIELD)).contains(groupFieldName)) {
                    resultMap.computeIfAbsent(groupFieldName, k -> Lists.newArrayList()).add(dataAreaFieldConfigEntry.getKey());
                }
            }
   /**
    * 获取数据区分组字段obj
    *
    * @param dataAreaFieldRecordObj 数据区字段记录obj
    * @param dataAreaFieldConfigMap 数据区字段缓存map
    * @param recordFse              业务数据记录
    */
   private void getDataAreaGroupFieldRecordObj(JSONObject dataAreaFieldRecordObj, Map<String, JSONObject> dataAreaFieldConfigMap, FieldSetEntity recordFse) {
      JSONObject parentObj = dataAreaFieldRecordObj;
      JSONObject subObj;
      String value;
      List<String> list;
      String groupAreaGroupFieldName;
      int i = 0;
      String dataAreaFieldName;
      JSONObject dataAreaFieldConfigObj;
      List<String> statisticsFieldList;
      String realValue;
      for (Map.Entry<String, JSONObject> entry : dataAreaFieldConfigMap.entrySet()) {
         dataAreaFieldConfigObj = entry.getValue();
         if (!"1".equals(dataAreaFieldConfigObj.getString(CmnConst.ATTR_IS_GROUP))) {
            break;
         }
         dataAreaFieldName = entry.getKey();
         realValue = dataListReportService.getRealValue(recordFse, dataAreaFieldName);
         list = Lists.newArrayList();
         list.addAll(dataListReportService.transfer2List(dataAreaFieldConfigObj.get(CmnConst.ATTR_DATA_AREA_GROUP_FIELD)));
         list.add(dataAreaFieldName);
         for (; i < list.size(); i++) {
            groupAreaGroupFieldName = list.get(i);
            value = recordFse.getString(groupAreaGroupFieldName);
            subObj = parentObj.getJSONObject(value);
            if (subObj == null) {
               subObj = new JSONObject(Maps.newLinkedHashMap());
               parentObj.put(value, subObj);
            }
            // 添加数据区分组统计字段
            if ("1".equals(dataAreaFieldConfigObj.getString(CmnConst.ATTR_IS_STATISTICS))) {
               parentObj.put(value + CmnConst.STATISTICS_NAME, new JSONObject());
               statisticsFieldList = dataListReportService.transfer2List(parentObj.get(CmnConst.ATTR_STATISTICS_FIELD));
               if (statisticsFieldList.isEmpty()) {
                  parentObj.put(CmnConst.ATTR_STATISTICS_FIELD, statisticsFieldList);
               }
               if (!statisticsFieldList.contains(value + CmnConst.STATISTICS_NAME)) {
                  statisticsFieldList.add(value + CmnConst.STATISTICS_NAME);
               }
            }
            // 添加field_info
            if (StringUtils.isEmpty(parentObj.getString(CmnConst.ATTR_FIELD_INFO))) {
               parentObj.put(CmnConst.ATTR_FIELD_INFO, dataListReportService.fieldName2FieldInfo(groupAreaGroupFieldName));
            }
            if (!StringUtils.isEmpty(realValue)) {
               subObj.put(CmnConst.ATTR_REAL_VALUE, realValue);
            }
            parentObj = subObj;
         }
      }
   }
        }
        return resultMap;
    }
   /**
    * 获取数据区特殊字段的统计
    *
    * @param statisticsMap                     统计map
    * @param dataAreaFieldConfigMap            数据区字段缓存map
    * @param dataAreaSpStatisticsFieldNameList 数据区特殊统计字段名称list(分组表头区下统计字段)
    * @param recordFse                         业务数据记录
    */
   private void statisticsDataAreaSpField(Map<JSONObject, JSONObject> statisticsMap, Map<String, JSONObject> dataAreaFieldConfigMap, List<String> dataAreaSpStatisticsFieldNameList, FieldSetEntity recordFse) {
      JSONObject dataAreaFieldConfigObj;
      List<String> groupAreaGroupFieldNameList;
      List<String> dataAreaGroupFieldNameList;
      String value;
      JSONObject keyObj;
      JSONObject valueObj;
      JSONObject groupAreaKeyObj;
      JSONObject dataAreaKeyObj;
      String statisticsType;
      for (String dataAreaFieldName : dataAreaSpStatisticsFieldNameList) {
         keyObj = new JSONObject();
         groupAreaKeyObj = new JSONObject();
         keyObj.put(CmnConst.ATTR_FIELD_INFO, dataListReportService.fieldName2FieldInfo(dataAreaFieldName));
         dataAreaFieldConfigObj = dataAreaFieldConfigMap.get(dataAreaFieldName);
         groupAreaGroupFieldNameList = dataListReportService.transfer2List(dataAreaFieldConfigObj.get(CmnConst.ATTR_GROUP_AREA_GROUP_FIELD));
         dataAreaGroupFieldNameList = dataListReportService.transfer2List(dataAreaFieldConfigObj.get(CmnConst.ATTR_DATA_AREA_GROUP_FIELD));
         value = dataListReportService.getValue(dataAreaFieldConfigObj, recordFse, dataAreaFieldName);
         statisticsType = dataAreaFieldConfigObj.getString(CmnConst.ATTR_STATISTICS);
         for (String groupAreaGroupFieldName : groupAreaGroupFieldNameList) {
            dataAreaKeyObj = new JSONObject();
            for (String dataAreaGroupFieldName : dataAreaGroupFieldNameList) {
               keyObj.remove(dataAreaGroupFieldName);
            }
            groupAreaKeyObj.put(groupAreaGroupFieldName, recordFse.getString(groupAreaGroupFieldName));
            dataListReportService.extendJSONObject(keyObj, groupAreaKeyObj, null);
            valueObj = statisticsMap.get(keyObj);
            valueObj = dataListReportService.getStatisticsValueObj(valueObj, dataAreaFieldConfigObj, value, statisticsType, true);
            statisticsMap.put((JSONObject) keyObj.clone(), valueObj);
            for (String dataAreaGroupFieldName : dataAreaGroupFieldNameList) {
               dataAreaKeyObj.put(dataAreaGroupFieldName, recordFse.getString(dataAreaGroupFieldName));
               keyObj = dataListReportService.extendJSONObject(keyObj, dataAreaKeyObj, null);
               valueObj = statisticsMap.get(keyObj);
               valueObj = dataListReportService.getStatisticsValueObj(valueObj, dataAreaFieldConfigObj, value, statisticsType, true);
               statisticsMap.put((JSONObject) keyObj.clone(), valueObj);
            }
         }
      }
   }
    /**
     * 获取标题-分组表头区数据obj
     * @param groupAreaFieldRecordObj                       分组表头区字段记录obj
     * @param groupAreaFieldConfigMap                       分组表头区字段缓存map
     * @param recordFse                                     业务数据记录
     * @param groupAreaStatisticsField2DataAreaFieldMap     分组表头区统计字段对应数据区字段map
     * @param groupAreaLastStageField2DataAreaFieldMap      分组表头区末级字段对应数据区字段map
     */
    private void getGroupAreaFieldRecordObj(JSONObject groupAreaFieldRecordObj, Map<String, JSONObject> groupAreaFieldConfigMap, FieldSetEntity recordFse,
                                            Map<String, List<String>> groupAreaStatisticsField2DataAreaFieldMap, Map<String, List<String>> groupAreaLastStageField2DataAreaFieldMap) {
        JSONObject parentObj = groupAreaFieldRecordObj;
        JSONObject subObj;
        String value;
        List<String> list;
        String groupAreaGroupFieldName;
        int i = 0;
        List<String> statisticsFieldList;
        String realValue;
        for (Map.Entry<String, JSONObject> entry : groupAreaFieldConfigMap.entrySet()) {
            list = Lists.newArrayList();
            list.addAll(dataListReportService.transfer2List(entry.getValue().get(CmnConst.ATTR_GROUP_AREA_GROUP_FIELD)));
            list.add(entry.getKey());
            for (;i < list.size();i++) {
                groupAreaGroupFieldName = list.get(i);
                realValue = dataListReportService.getRealValue(recordFse, groupAreaGroupFieldName);
                value = recordFse.getString(groupAreaGroupFieldName);
   /**
    * 取数据区普通字段的统计
    *
    * @param statisticsMap                         统计map
    * @param dataAreaFieldConfigMap                数据区字段缓存map
    * @param dataAreaCommonStatisticsFieldNameList 数据区普通统计字段名称list
    * @param recordFse                             业务数据记录
    */
   private void statisticsDataAreaCommonField(Map<JSONObject, JSONObject> statisticsMap, Map<String, JSONObject> dataAreaFieldConfigMap, List<String> dataAreaCommonStatisticsFieldNameList, FieldSetEntity recordFse) {
      JSONObject dataAreaFieldConfigObj;
      List<String> dataAreaGroupFieldNameList;
      String value;
      JSONObject dataAreaKeyObj = new JSONObject();
      JSONObject keyObj;
      JSONObject valueObj;
      String statisticsType;
      int i;
      for (String dataAreaFieldName : dataAreaCommonStatisticsFieldNameList) {
         i = 0;
         keyObj = new JSONObject();
         dataAreaFieldConfigObj = dataAreaFieldConfigMap.get(dataAreaFieldName);
         dataAreaGroupFieldNameList = dataListReportService.transfer2List(dataAreaFieldConfigObj.get(CmnConst.ATTR_DATA_AREA_GROUP_FIELD));
         statisticsType = dataAreaFieldConfigObj.getString(CmnConst.ATTR_STATISTICS);
         value = dataListReportService.getValue(dataAreaFieldConfigObj, recordFse, dataAreaFieldName);
         keyObj.put(CmnConst.ATTR_FIELD_INFO, dataListReportService.fieldName2FieldInfo(dataAreaFieldName));
         valueObj = statisticsMap.get(keyObj);
         valueObj = dataListReportService.getStatisticsValueObj(valueObj, dataAreaFieldConfigObj, value, statisticsType, false);
         statisticsMap.put((JSONObject) keyObj.clone(), valueObj);
         for (String dataAreaGroupFieldName : dataAreaGroupFieldNameList) {
            i++;
            dataAreaKeyObj.put(dataAreaGroupFieldName, recordFse.getString(dataAreaGroupFieldName));
            keyObj = dataListReportService.extendJSONObject(keyObj, dataAreaKeyObj, null);
            valueObj = statisticsMap.get(keyObj);
            valueObj = dataListReportService.getStatisticsValueObj(valueObj, dataAreaFieldConfigObj, value, statisticsType, i == dataAreaGroupFieldNameList.size());
            statisticsMap.put((JSONObject) keyObj.clone(), valueObj);
         }
      }
   }
                if (parentObj.get(value) == null) {
                    subObj = new JSONObject(Maps.newTreeMap((o1, o2) -> dataListReportService.compare(o1, o2)));
                    parentObj.put(value, subObj);
                    // 添加分组表头区分组统计字段对应数据区字段
                    if (groupAreaStatisticsField2DataAreaFieldMap.containsKey(groupAreaGroupFieldName)) {
                        parentObj.put(value + CmnConst.STATISTICS_NAME, groupAreaStatisticsField2DataAreaFieldMap.get(groupAreaGroupFieldName));
                        statisticsFieldList = dataListReportService.transfer2List(parentObj.get(CmnConst.ATTR_STATISTICS_FIELD));
                        if (statisticsFieldList.isEmpty()) {
                            parentObj.put(CmnConst.ATTR_STATISTICS_FIELD, statisticsFieldList);
                        }
                        if (!statisticsFieldList.contains(value + CmnConst.STATISTICS_NAME)) {
                            statisticsFieldList.add(value + CmnConst.STATISTICS_NAME);
                        }
                    }
                    // 添加分组表头区末级字段对应数据区字段
                    if (groupAreaLastStageField2DataAreaFieldMap.containsKey(groupAreaGroupFieldName)) {
                        parentObj.put(value, groupAreaLastStageField2DataAreaFieldMap.get(groupAreaGroupFieldName));
                    }
                    // 添加field_info
                    if (StringUtils.isEmpty(parentObj.getString(CmnConst.ATTR_FIELD_INFO))) {
                        parentObj.put(CmnConst.ATTR_FIELD_INFO, dataListReportService.fieldName2FieldInfo(groupAreaGroupFieldName));
                    }
                    if (!StringUtils.isEmpty(realValue)) {
                        subObj.put(CmnConst.ATTR_REAL_VALUE, realValue);
                    }
                } else {
                    if (!(parentObj.get(value) instanceof JSONObject)) {
                        continue;
                    }
                    subObj = parentObj.getJSONObject(value);
                }
                parentObj = subObj;
            }
        }
    }
   /**
    * 获取分组表头区和数据区总列数
    *
    * @param groupAreaFieldRecordObj            分组表头区字段记录obj
    * @param dataAreaGroupFieldCount            数据区分组字段个数
    * @param dataAreaCommonStatisticsFieldCount 数据区普通统计字段个数
    * @return 分组表头区和数据区总列数
    */
   private int getTotalColCount(JSONObject groupAreaFieldRecordObj, int dataAreaGroupFieldCount, int dataAreaCommonStatisticsFieldCount) {
      int groupAreaColCount = getGroupAreaColCount(groupAreaFieldRecordObj, 0);
      return groupAreaColCount + dataAreaGroupFieldCount + dataAreaCommonStatisticsFieldCount;
   }
    /**
     * 获取数据区分组字段obj
     * @param dataAreaFieldRecordObj    数据区字段记录obj
     * @param dataAreaFieldConfigMap    数据区字段缓存map
     * @param recordFse                 业务数据记录
     */
    private void getDataAreaGroupFieldRecordObj(JSONObject dataAreaFieldRecordObj, Map<String, JSONObject> dataAreaFieldConfigMap, FieldSetEntity recordFse) {
        JSONObject parentObj = dataAreaFieldRecordObj;
        JSONObject subObj;
        String value;
        List<String> list;
        String groupAreaGroupFieldName;
        int i = 0;
        String dataAreaFieldName;
        JSONObject dataAreaFieldConfigObj;
        List<String> statisticsFieldList;
        String realValue;
        for (Map.Entry<String, JSONObject> entry : dataAreaFieldConfigMap.entrySet()) {
            dataAreaFieldConfigObj = entry.getValue();
            if (!"1".equals(dataAreaFieldConfigObj.getString(CmnConst.ATTR_IS_GROUP))) {
                break;
            }
            dataAreaFieldName = entry.getKey();
            realValue = dataListReportService.getRealValue(recordFse, dataAreaFieldName);
            list = Lists.newArrayList();
            list.addAll(dataListReportService.transfer2List(dataAreaFieldConfigObj.get(CmnConst.ATTR_DATA_AREA_GROUP_FIELD)));
            list.add(dataAreaFieldName);
            for (;i < list.size();i++) {
                groupAreaGroupFieldName = list.get(i);
                value = recordFse.getString(groupAreaGroupFieldName);
                subObj = parentObj.getJSONObject(value);
                if (subObj == null) {
                    subObj = new JSONObject(Maps.newLinkedHashMap());
                    parentObj.put(value, subObj);
                }
                // 添加数据区分组统计字段
                if ("1".equals(dataAreaFieldConfigObj.getString(CmnConst.ATTR_IS_STATISTICS))) {
                    parentObj.put(value + CmnConst.STATISTICS_NAME, new JSONObject());
                    statisticsFieldList = dataListReportService.transfer2List(parentObj.get(CmnConst.ATTR_STATISTICS_FIELD));
                    if (statisticsFieldList.isEmpty()) {
                        parentObj.put(CmnConst.ATTR_STATISTICS_FIELD, statisticsFieldList);
                    }
                    if (!statisticsFieldList.contains(value + CmnConst.STATISTICS_NAME)) {
                        statisticsFieldList.add(value + CmnConst.STATISTICS_NAME);
                    }
                }
                // 添加field_info
                if (StringUtils.isEmpty(parentObj.getString(CmnConst.ATTR_FIELD_INFO))) {
                    parentObj.put(CmnConst.ATTR_FIELD_INFO, dataListReportService.fieldName2FieldInfo(groupAreaGroupFieldName));
                }
                if (!StringUtils.isEmpty(realValue)) {
                    subObj.put(CmnConst.ATTR_REAL_VALUE, realValue);
                }
                parentObj = subObj;
            }
        }
    }
   /**
    * 获取分组表头区总列数
    *
    * @param curOperateObj     当前操作的obj
    * @param groupAreaColCount 分组表头区列数
    * @return 分组表头区总列数
    */
   private int getGroupAreaColCount(JSONObject curOperateObj, int groupAreaColCount) {
      if (curOperateObj == null) {
         return groupAreaColCount;
      }
      String key;
      Object value;
      for (Map.Entry<String, Object> entry : curOperateObj.entrySet()) {
         key = entry.getKey();
         if (CmnConst.ATTR_FIELD_INFO.equals(key) || CmnConst.ATTR_STATISTICS_FIELD.equals(key)) {
            continue;
         }
         value = entry.getValue();
         if (value == null) {
            continue;
         }
         if (value instanceof List) {
            groupAreaColCount += ((List) value).size();
         } else if (value instanceof JSONObject) {
            groupAreaColCount = getGroupAreaColCount((JSONObject) value, groupAreaColCount);
         }
      }
      return groupAreaColCount;
   }
    /**
     * 获取数据区特殊字段的统计
     * @param statisticsMap                         统计map
     * @param dataAreaFieldConfigMap                数据区字段缓存map
     * @param dataAreaSpStatisticsFieldNameList     数据区特殊统计字段名称list(分组表头区下统计字段)
     * @param recordFse                             业务数据记录
     */
    private void statisticsDataAreaSpField(Map<JSONObject, JSONObject> statisticsMap, Map<String, JSONObject> dataAreaFieldConfigMap, List<String> dataAreaSpStatisticsFieldNameList, FieldSetEntity recordFse) {
        JSONObject dataAreaFieldConfigObj;
        List<String> groupAreaGroupFieldNameList;
        List<String> dataAreaGroupFieldNameList;
        String value;
        JSONObject keyObj;
        JSONObject valueObj;
        JSONObject groupAreaKeyObj;
        JSONObject dataAreaKeyObj;
        String statisticsType;
        for (String dataAreaFieldName : dataAreaSpStatisticsFieldNameList) {
            keyObj = new JSONObject();
            groupAreaKeyObj = new JSONObject();
            keyObj.put(CmnConst.ATTR_FIELD_INFO, dataListReportService.fieldName2FieldInfo(dataAreaFieldName));
            dataAreaFieldConfigObj = dataAreaFieldConfigMap.get(dataAreaFieldName);
            groupAreaGroupFieldNameList = dataListReportService.transfer2List(dataAreaFieldConfigObj.get(CmnConst.ATTR_GROUP_AREA_GROUP_FIELD));
            dataAreaGroupFieldNameList = dataListReportService.transfer2List(dataAreaFieldConfigObj.get(CmnConst.ATTR_DATA_AREA_GROUP_FIELD));
            value = dataListReportService.getValue(dataAreaFieldConfigObj, recordFse, dataAreaFieldName);
            statisticsType = dataAreaFieldConfigObj.getString(CmnConst.ATTR_STATISTICS);
            for (String groupAreaGroupFieldName : groupAreaGroupFieldNameList) {
                dataAreaKeyObj = new JSONObject();
                for (String dataAreaGroupFieldName : dataAreaGroupFieldNameList) {
                    keyObj.remove(dataAreaGroupFieldName);
                }
                groupAreaKeyObj.put(groupAreaGroupFieldName, recordFse.getString(groupAreaGroupFieldName));
                dataListReportService.extendJSONObject(keyObj, groupAreaKeyObj, null);
                valueObj = statisticsMap.get(keyObj);
                valueObj = dataListReportService.getStatisticsValueObj(valueObj, dataAreaFieldConfigObj, value, statisticsType, true);
                statisticsMap.put((JSONObject) keyObj.clone(), valueObj);
                for (String dataAreaGroupFieldName : dataAreaGroupFieldNameList) {
                    dataAreaKeyObj.put(dataAreaGroupFieldName, recordFse.getString(dataAreaGroupFieldName));
                    keyObj = dataListReportService.extendJSONObject(keyObj, dataAreaKeyObj, null);
                    valueObj = statisticsMap.get(keyObj);
                    valueObj = dataListReportService.getStatisticsValueObj(valueObj, dataAreaFieldConfigObj, value, statisticsType, true);
                    statisticsMap.put((JSONObject) keyObj.clone(), valueObj);
                }
            }
        }
    }
   /**
    * 获取标题html
    *
    * @param dataTitleList                         数据标题list
    * @param groupAreaFieldRecordObj               分组表头区字段记录obj
    * @param dataAreaFieldConfigMap                数据区字段缓存map
    * @param groupAreaRangeObj                     分组表头去范围obj
    * @param dataAreaCommonStatisticsFieldNameList 数据区普通统计字段名称list
    * @return 数据标题html
    */
   private List<List<ReportColumn>> getDataAreaTitleRows(List<JSONObject> dataTitleList, JSONObject groupAreaFieldRecordObj, Map<String, JSONObject> dataAreaFieldConfigMap, JSONObject groupAreaRangeObj, List<String> dataAreaCommonStatisticsFieldNameList) {
      List<List<ReportColumn>> reportColumnList = Lists.newArrayList();
      int maxRow = groupAreaRangeObj.getIntValue(CmnConst.MAX_Y);
      List<List<JSONObject>> groupAreaRangeTitleList = Lists.newArrayList();
      for (int i = 0; i <= maxRow; i++) {
         groupAreaRangeTitleList.add(Lists.newArrayList());
      }
      getGroupAreaRangeTitleList(dataAreaFieldConfigMap, groupAreaFieldRecordObj, groupAreaRangeTitleList, new JSONObject(), 0, maxRow, null);
    /**
     * 取数据区普通字段的统计
     * @param statisticsMap                             统计map
     * @param dataAreaFieldConfigMap                    数据区字段缓存map
     * @param dataAreaCommonStatisticsFieldNameList     数据区普通统计字段名称list
     * @param recordFse                                 业务数据记录
     */
    private void statisticsDataAreaCommonField(Map<JSONObject, JSONObject> statisticsMap, Map<String, JSONObject> dataAreaFieldConfigMap, List<String> dataAreaCommonStatisticsFieldNameList, FieldSetEntity recordFse) {
        JSONObject dataAreaFieldConfigObj;
        List<String> dataAreaGroupFieldNameList;
        String value;
        JSONObject dataAreaKeyObj = new JSONObject();
        JSONObject keyObj;
        JSONObject valueObj;
        String statisticsType;
        int i;
        for (String dataAreaFieldName : dataAreaCommonStatisticsFieldNameList) {
            i = 0;
            keyObj = new JSONObject();
            dataAreaFieldConfigObj = dataAreaFieldConfigMap.get(dataAreaFieldName);
            dataAreaGroupFieldNameList = dataListReportService.transfer2List(dataAreaFieldConfigObj.get(CmnConst.ATTR_DATA_AREA_GROUP_FIELD));
            statisticsType = dataAreaFieldConfigObj.getString(CmnConst.ATTR_STATISTICS);
            value = dataListReportService.getValue(dataAreaFieldConfigObj, recordFse, dataAreaFieldName);
            keyObj.put(CmnConst.ATTR_FIELD_INFO, dataListReportService.fieldName2FieldInfo(dataAreaFieldName));
            valueObj = statisticsMap.get(keyObj);
            valueObj = dataListReportService.getStatisticsValueObj(valueObj, dataAreaFieldConfigObj, value, statisticsType, false);
            statisticsMap.put((JSONObject) keyObj.clone(), valueObj);
            for (String dataAreaGroupFieldName : dataAreaGroupFieldNameList) {
                i++;
                dataAreaKeyObj.put(dataAreaGroupFieldName, recordFse.getString(dataAreaGroupFieldName));
                keyObj = dataListReportService.extendJSONObject(keyObj, dataAreaKeyObj, null);
                valueObj = statisticsMap.get(keyObj);
                valueObj = dataListReportService.getStatisticsValueObj(valueObj, dataAreaFieldConfigObj, value, statisticsType, i == dataAreaGroupFieldNameList.size());
                statisticsMap.put((JSONObject) keyObj.clone(), valueObj);
            }
        }
    }
      List<JSONObject> beforeGroupAreaTitleList = Lists.newArrayList();
      List<JSONObject> afterGroupAreaTitleList = Lists.newArrayList();
    /**
     * 获取分组表头区和数据区总列数
     * @param groupAreaFieldRecordObj               分组表头区字段记录obj
     * @param dataAreaGroupFieldCount               数据区分组字段个数
     * @param dataAreaCommonStatisticsFieldCount    数据区普通统计字段个数
     * @return                                      分组表头区和数据区总列数
     */
    private int getTotalColCount(JSONObject groupAreaFieldRecordObj, int dataAreaGroupFieldCount, int dataAreaCommonStatisticsFieldCount) {
        int groupAreaColCount = getGroupAreaColCount(groupAreaFieldRecordObj, 0);
        return groupAreaColCount + dataAreaGroupFieldCount + dataAreaCommonStatisticsFieldCount;
    }
    /**
     * 获取分组表头区总列数
     * @param curOperateObj         当前操作的obj
     * @param groupAreaColCount     分组表头区列数
     * @return                      分组表头区总列数
     */
    private int getGroupAreaColCount(JSONObject curOperateObj, int groupAreaColCount) {
        if (curOperateObj == null) {
            return groupAreaColCount;
        }
        String key;
        Object value;
        for (Map.Entry<String, Object> entry : curOperateObj.entrySet()) {
            key = entry.getKey();
            if (CmnConst.ATTR_FIELD_INFO.equals(key) || CmnConst.ATTR_STATISTICS_FIELD.equals(key)) {
                continue;
            }
            value = entry.getValue();
            if (value == null) {
                continue;
            }
            if (value instanceof List) {
                groupAreaColCount += ((List) value).size();
            } else if (value instanceof JSONObject) {
                groupAreaColCount = getGroupAreaColCount((JSONObject) value, groupAreaColCount);
            }
        }
        return groupAreaColCount;
    }
    /**
     * 获取标题html
     * @param dataTitleList                             数据标题list
     * @param groupAreaFieldRecordObj                   分组表头区字段记录obj
     * @param dataAreaFieldConfigMap                    数据区字段缓存map
     * @param groupAreaRangeObj                         分组表头去范围obj
     * @param dataAreaCommonStatisticsFieldNameList     数据区普通统计字段名称list
     * @return                                          数据标题html
     */
    private StringBuilder getDataAreaTitleHtml(List<JSONObject> dataTitleList, JSONObject groupAreaFieldRecordObj, Map<String, JSONObject> dataAreaFieldConfigMap, JSONObject groupAreaRangeObj, List<String> dataAreaCommonStatisticsFieldNameList) {
        int maxRow = groupAreaRangeObj.getIntValue(CmnConst.MAX_Y);
        List<List<JSONObject>> groupAreaRangeTitleList = Lists.newArrayList();
        for (int i = 0;i <= maxRow;i++) {
            groupAreaRangeTitleList.add(Lists.newArrayList());
        }
        getGroupAreaRangeTitleList(dataAreaFieldConfigMap, groupAreaFieldRecordObj, groupAreaRangeTitleList, new JSONObject(), 0, maxRow, null);
        List<JSONObject> beforeGroupAreaTitleList = Lists.newArrayList();
        List<JSONObject> afterGroupAreaTitleList = Lists.newArrayList();
        String dataAreaFieldName;
        JSONObject dataAreaFieldConfigObj;
        JSONObject titleObj;
        for (Map.Entry<String, JSONObject> entry : dataAreaFieldConfigMap.entrySet()) {
            dataAreaFieldName = entry.getKey();
            dataAreaFieldConfigObj = entry.getValue();
            titleObj = new JSONObject();
      String dataAreaFieldName;
      JSONObject dataAreaFieldConfigObj;
      JSONObject titleObj;
      for (Map.Entry<String, JSONObject> entry : dataAreaFieldConfigMap.entrySet()) {
         dataAreaFieldName = entry.getKey();
         dataAreaFieldConfigObj = entry.getValue();
         titleObj = new JSONObject();
//            titleObj.put(CmnConst.ATTR_FIELD_INFO, getFieldInfo(dataAreaFieldConfigObj));
            titleObj.put(CmnConst.ATTR_FIELD_INFO, dataListReportService.fieldName2FieldInfo(dataAreaFieldName));
            if (dataAreaCommonStatisticsFieldNameList.contains(dataAreaFieldName)) {
                titleObj.put(CmnConst.ATTR_SHOW_NAME, dataListReportService.getStatisticsDesc(dataAreaFieldConfigObj.getString(CmnConst.ATTR_STATISTICS), dataAreaFieldConfigObj.getString(CmnConst.ATTR_SHOW_NAME)));
            } else {
                titleObj.put(CmnConst.ATTR_SHOW_NAME, dataAreaFieldConfigObj.getString(CmnConst.ATTR_SHOW_NAME));
            }
            titleObj.put(CmnConst.ATTR_ROWSPAN, maxRow + 1);
            titleObj.put(CmnConst.ATTR_COLSPAN, 1);
            if (dataAreaFieldConfigObj.getIntValue(CmnConst.ATTR_X) < groupAreaRangeObj.getIntValue(CmnConst.MIN_X)) {
                beforeGroupAreaTitleList.add(titleObj);
            }
            if (dataAreaFieldConfigObj.getIntValue(CmnConst.ATTR_X) > groupAreaRangeObj.getIntValue(CmnConst.MAX_X)) {
                if ("1".equals(dataAreaFieldConfigObj.getString(CmnConst.ATTR_IS_GROUP))) {
                    beforeGroupAreaTitleList.add(titleObj);
                } else {
                    afterGroupAreaTitleList.add(titleObj);
                }
            }
        }
         titleObj.put(CmnConst.ATTR_FIELD_INFO, dataListReportService.fieldName2FieldInfo(dataAreaFieldName));
         if (dataAreaCommonStatisticsFieldNameList.contains(dataAreaFieldName)) {
            titleObj.put(CmnConst.ATTR_SHOW_NAME, dataListReportService.getStatisticsDesc(dataAreaFieldConfigObj.getString(CmnConst.ATTR_STATISTICS), dataAreaFieldConfigObj.getString(CmnConst.ATTR_SHOW_NAME)));
         } else {
            titleObj.put(CmnConst.ATTR_SHOW_NAME, dataAreaFieldConfigObj.getString(CmnConst.ATTR_SHOW_NAME));
         }
         titleObj.put(CmnConst.ATTR_ROWSPAN, maxRow + 1);
         titleObj.put(CmnConst.ATTR_COLSPAN, 1);
         if (dataAreaFieldConfigObj.getIntValue(CmnConst.ATTR_X) < groupAreaRangeObj.getIntValue(CmnConst.MIN_X)) {
            beforeGroupAreaTitleList.add(titleObj);
         }
         if (dataAreaFieldConfigObj.getIntValue(CmnConst.ATTR_X) > groupAreaRangeObj.getIntValue(CmnConst.MAX_X)) {
            if ("1".equals(dataAreaFieldConfigObj.getString(CmnConst.ATTR_IS_GROUP))) {
               beforeGroupAreaTitleList.add(titleObj);
            } else {
               afterGroupAreaTitleList.add(titleObj);
            }
         }
      }
        dataTitleList.addAll(groupAreaRangeTitleList.get(maxRow));
        dataTitleList.addAll(afterGroupAreaTitleList);
      dataTitleList.addAll(groupAreaRangeTitleList.get(maxRow));
      dataTitleList.addAll(afterGroupAreaTitleList);
        List<JSONObject> firstList = Lists.newArrayList();
        firstList.addAll(beforeGroupAreaTitleList);
        firstList.addAll(groupAreaRangeTitleList.get(0));
        firstList.addAll(afterGroupAreaTitleList);
      List<JSONObject> firstList = Lists.newArrayList();
      firstList.addAll(beforeGroupAreaTitleList);
      firstList.addAll(groupAreaRangeTitleList.get(0));
      firstList.addAll(afterGroupAreaTitleList);
        groupAreaRangeTitleList.set(0, firstList);
      groupAreaRangeTitleList.set(0, firstList);
        StringBuilder html = new StringBuilder(1024);
        int rowspan;
        int colspan;
        String value;
        for (List<JSONObject> rowList : groupAreaRangeTitleList) {
            html.append("\n<tr class=\"").append(CmnConst.CLASS_TR_DATA_TITLE).append("\">\n    ");
            for (JSONObject dataTitleObj : rowList) {
                rowspan = Math.max(1, dataTitleObj.getIntValue(CmnConst.ATTR_ROWSPAN));
                colspan = Math.max(1, dataTitleObj.getIntValue(CmnConst.ATTR_COLSPAN));
                value = dataTitleObj.getString(CmnConst.ATTR_SHOW_NAME);
                if (!StringUtils.isEmpty(dataTitleObj.getString(CmnConst.ATTR_FIELD_INFO))) {
                    dataAreaFieldName = dataListReportService.fieldInfo2FieldName(dataTitleObj.getString(CmnConst.ATTR_FIELD_INFO));
                    value = dataListReportService.dealTdWidth(dataAreaFieldConfigMap.get(dataAreaFieldName), value);
                }
                html.append("<td rowspan=\"").append(rowspan).append("\" colspan=\"").append(colspan).append("\">").append(value == null ? "" : value).append("</td>");
            }
            html.append("\n</tr>");
        }
        return html;
    }
      StringBuilder html = new StringBuilder(1024);
      int rowspan;
      int colspan;
      String value;
      for (List<JSONObject> rowList : groupAreaRangeTitleList) {
         List<ReportColumn> reportColumns = new ArrayList<>();
//         html.append("\n<tr class=\"").append(CmnConst.CLASS_TR_DATA_TITLE).append("\">\n    ");
         for (JSONObject dataTitleObj : rowList) {
            rowspan = Math.max(1, dataTitleObj.getIntValue(CmnConst.ATTR_ROWSPAN));
            colspan = Math.max(1, dataTitleObj.getIntValue(CmnConst.ATTR_COLSPAN));
            value = dataTitleObj.getString(CmnConst.ATTR_SHOW_NAME);
            ReportColumn column = new ReportColumn(colspan, rowspan);
            if (!StringUtils.isEmpty(dataTitleObj.getString(CmnConst.ATTR_FIELD_INFO))) {
               dataAreaFieldName = dataListReportService.fieldInfo2FieldName(dataTitleObj.getString(CmnConst.ATTR_FIELD_INFO));
               JSONObject dataAreaFieldConfigObjTemp = dataAreaFieldConfigMap.get(dataAreaFieldName);
               String width = dataAreaFieldConfigObjTemp == null ? null : dataAreaFieldConfigObjTemp.getString(CmnConst.ATTR_WIDTH);
               if (!StringUtils.isEmpty(width) && NumberUtil.isNumber(width)) {
                  column.setColumnWidth(NumberUtil.parseInt(width));
               }
            }
            column.setContent(value);
            reportColumns.add(column);
         }
         reportColumnList.add(reportColumns);
      }
      return reportColumnList;
   }
    /**
     * 获取分组表头区范围的标题list
     * @param dataAreaFieldConfigMap        数据区字段缓存map
     * @param curOperateObj                 当前操作obj
     * @param groupAreaRangeTitleList       分组表头区范围下数据标题list
     * @param preTitleObj                   最近操作的标题obj
     * @param row                           当前行数
     * @param maxRow                        最大行数
     */
    private void getGroupAreaRangeTitleList(Map<String, JSONObject> dataAreaFieldConfigMap, JSONObject curOperateObj, List<List<JSONObject>> groupAreaRangeTitleList, JSONObject preTitleObj, int row, int maxRow, String parentFieldName) {
        if (curOperateObj == null || curOperateObj.isEmpty()) {
            return;
        }
        String key;
        Object value;
        JSONObject curTitleObj;
        String groupAreaFieldName = dataListReportService.fieldInfo2FieldName(curOperateObj.getString(CmnConst.ATTR_FIELD_INFO));
        List<String> statisticsFieldList = dataListReportService.transfer2List(curOperateObj.get(CmnConst.ATTR_STATISTICS_FIELD));
        String realValue = curOperateObj.getString(CmnConst.ATTR_REAL_VALUE);
        String fieldName = dataListReportService.fieldInfo2FieldName(curOperateObj.getString(CmnConst.ATTR_FIELD_INFO));
        String newKey;
        JSONObject realValueObj;
        for (Map.Entry<String, Object> entry : curOperateObj.entrySet()) {
            curTitleObj = dataListReportService.extendJSONObject(null, preTitleObj, null);
            if (!StringUtils.isEmpty(realValue) && !StringUtils.isEmpty(parentFieldName)) {
                if (curTitleObj.get(CmnConst.ATTR_REAL_VALUE) == null) {
                    realValueObj = new JSONObject();
                    curTitleObj.put(CmnConst.ATTR_REAL_VALUE, realValueObj);
                } else {
                    realValueObj = (JSONObject) curTitleObj.get(CmnConst.ATTR_REAL_VALUE);
                }
                realValueObj.put(parentFieldName, realValue);
            }
            key = entry.getKey();
            if (CmnConst.ATTR_FIELD_INFO.equals(key) || CmnConst.ATTR_STATISTICS_FIELD.equals(key) || CmnConst.ATTR_REAL_VALUE.equals(key)) {
                continue;
            }
            value = entry.getValue();
            if (value == null) {
                continue;
            }
            curTitleObj.put(CmnConst.ATTR_SHOW_NAME, key);
            if (statisticsFieldList.contains(key)) {
                curTitleObj.put(CmnConst.ATTR_IS_STATISTICS_FIELD, "1");
                newKey = key.replace(CmnConst.STATISTICS_NAME, "");
                curTitleObj.put(groupAreaFieldName, newKey);
                curTitleObj.put(CmnConst.ATTR_GROUP_AREA_SUB_CNT, getSubCnt(curOperateObj.getJSONObject(newKey)));
            } else {
                curTitleObj.put(groupAreaFieldName, key);
            }
            groupAreaRangeTitleList.get(row).add(curTitleObj);
            if (value instanceof List) {
                curTitleObj.put(CmnConst.ATTR_COLSPAN, ((List) value).size());
                curTitleObj.put(CmnConst.ATTR_ROWSPAN, maxRow - row);
                for (String dataAreaFieldName : (List<String>) value) {
                    JSONObject cloneTitleObj = (JSONObject) curTitleObj.clone();
                    cloneTitleObj.put(CmnConst.ATTR_FIELD_INFO, dataListReportService.fieldName2FieldInfo(dataAreaFieldName));
                    cloneTitleObj.put(CmnConst.ATTR_COLSPAN, 1);
                    cloneTitleObj.put(CmnConst.ATTR_ROWSPAN, 1);
                    JSONObject dataAreaFieldConfigObj = dataAreaFieldConfigMap.get(dataAreaFieldName);
                    cloneTitleObj.put(CmnConst.ATTR_SHOW_NAME, dataListReportService.getStatisticsDesc(dataAreaFieldConfigObj.getString(CmnConst.ATTR_STATISTICS), dataAreaFieldConfigObj.getString(CmnConst.ATTR_SHOW_NAME)));
                    groupAreaRangeTitleList.get(maxRow).add(cloneTitleObj);
                }
            } else {
                if (value instanceof JSONObject) {
                    curTitleObj.put(CmnConst.ATTR_COLSPAN, getGroupAreaColCount((JSONObject) value, 0));
                    curTitleObj.put(CmnConst.ATTR_ROWSPAN, 1);
                    getGroupAreaRangeTitleList(dataAreaFieldConfigMap, (JSONObject) value, groupAreaRangeTitleList, curTitleObj, row + 1, maxRow, fieldName);
                }
            }
        }
    }
   /**
    * 获取分组表头区范围的标题list
    *
    * @param dataAreaFieldConfigMap  数据区字段缓存map
    * @param curOperateObj           当前操作obj
    * @param groupAreaRangeTitleList 分组表头区范围下数据标题list
    * @param preTitleObj             最近操作的标题obj
    * @param row                     当前行数
    * @param maxRow                  最大行数
    */
   private void getGroupAreaRangeTitleList(Map<String, JSONObject> dataAreaFieldConfigMap, JSONObject curOperateObj, List<List<JSONObject>> groupAreaRangeTitleList, JSONObject preTitleObj, int row, int maxRow, String parentFieldName) {
      if (curOperateObj == null || curOperateObj.isEmpty()) {
         return;
      }
      String key;
      Object value;
      JSONObject curTitleObj;
      String groupAreaFieldName = dataListReportService.fieldInfo2FieldName(curOperateObj.getString(CmnConst.ATTR_FIELD_INFO));
      List<String> statisticsFieldList = dataListReportService.transfer2List(curOperateObj.get(CmnConst.ATTR_STATISTICS_FIELD));
      String realValue = curOperateObj.getString(CmnConst.ATTR_REAL_VALUE);
      String fieldName = dataListReportService.fieldInfo2FieldName(curOperateObj.getString(CmnConst.ATTR_FIELD_INFO));
      String newKey;
      JSONObject realValueObj;
      for (Map.Entry<String, Object> entry : curOperateObj.entrySet()) {
         curTitleObj = dataListReportService.extendJSONObject(null, preTitleObj, null);
         if (!StringUtils.isEmpty(realValue) && !StringUtils.isEmpty(parentFieldName)) {
            if (curTitleObj.get(CmnConst.ATTR_REAL_VALUE) == null) {
               realValueObj = new JSONObject();
               curTitleObj.put(CmnConst.ATTR_REAL_VALUE, realValueObj);
            } else {
               realValueObj = (JSONObject) curTitleObj.get(CmnConst.ATTR_REAL_VALUE);
            }
            realValueObj.put(parentFieldName, realValue);
         }
         key = entry.getKey();
         if (CmnConst.ATTR_FIELD_INFO.equals(key) || CmnConst.ATTR_STATISTICS_FIELD.equals(key) || CmnConst.ATTR_REAL_VALUE.equals(key)) {
            continue;
         }
         value = entry.getValue();
         if (value == null) {
            continue;
         }
         curTitleObj.put(CmnConst.ATTR_SHOW_NAME, key);
         if (statisticsFieldList.contains(key)) {
            curTitleObj.put(CmnConst.ATTR_IS_STATISTICS_FIELD, "1");
            newKey = key.replace(CmnConst.STATISTICS_NAME, "");
            curTitleObj.put(groupAreaFieldName, newKey);
            curTitleObj.put(CmnConst.ATTR_GROUP_AREA_SUB_CNT, getSubCnt(curOperateObj.getJSONObject(newKey)));
         } else {
            curTitleObj.put(groupAreaFieldName, key);
         }
         groupAreaRangeTitleList.get(row).add(curTitleObj);
         if (value instanceof List) {
            curTitleObj.put(CmnConst.ATTR_COLSPAN, ((List) value).size());
            curTitleObj.put(CmnConst.ATTR_ROWSPAN, maxRow - row);
            for (String dataAreaFieldName : (List<String>) value) {
               JSONObject cloneTitleObj = (JSONObject) curTitleObj.clone();
               cloneTitleObj.put(CmnConst.ATTR_FIELD_INFO, dataListReportService.fieldName2FieldInfo(dataAreaFieldName));
               cloneTitleObj.put(CmnConst.ATTR_COLSPAN, 1);
               cloneTitleObj.put(CmnConst.ATTR_ROWSPAN, 1);
               JSONObject dataAreaFieldConfigObj = dataAreaFieldConfigMap.get(dataAreaFieldName);
               cloneTitleObj.put(CmnConst.ATTR_SHOW_NAME, dataListReportService.getStatisticsDesc(dataAreaFieldConfigObj.getString(CmnConst.ATTR_STATISTICS), dataAreaFieldConfigObj.getString(CmnConst.ATTR_SHOW_NAME)));
               groupAreaRangeTitleList.get(maxRow).add(cloneTitleObj);
            }
         } else {
            if (value instanceof JSONObject) {
               curTitleObj.put(CmnConst.ATTR_COLSPAN, getGroupAreaColCount((JSONObject) value, 0));
               curTitleObj.put(CmnConst.ATTR_ROWSPAN, 1);
               getGroupAreaRangeTitleList(dataAreaFieldConfigMap, (JSONObject) value, groupAreaRangeTitleList, curTitleObj, row + 1, maxRow, fieldName);
            }
         }
      }
   }
    /**
     * 获取下级分组项数
     * @param obj       待操作的obj
     * @return          下级分组项数
     */
    private int getSubCnt(JSONObject obj) {
        int count = 0;
        List<String> statisticsFieldList = dataListReportService.transfer2List(obj.get(CmnConst.ATTR_STATISTICS_FIELD));
        for (String key : obj.keySet()) {
            if (CmnConst.ATTR_FIELD_INFO.equals(key) || CmnConst.ATTR_STATISTICS_FIELD.equals(key) || statisticsFieldList.contains(key)) {
                continue;
            }
            count++;
        }
        return count;
    }
   /**
    * 获取下级分组项数
    *
    * @param obj 待操作的obj
    * @return 下级分组项数
    */
   private int getSubCnt(JSONObject obj) {
      int count = 0;
      List<String> statisticsFieldList = dataListReportService.transfer2List(obj.get(CmnConst.ATTR_STATISTICS_FIELD));
      for (String key : obj.keySet()) {
         if (CmnConst.ATTR_FIELD_INFO.equals(key) || CmnConst.ATTR_STATISTICS_FIELD.equals(key) || statisticsFieldList.contains(key)) {
            continue;
         }
         count++;
      }
      return count;
   }
    /**
     * 获取内容html
     * @param dataTitleList                 数据标题list
     * @param dataAreaFieldRecordObj        数据区字段记录obj
     * @param statisticsMap                 统计map
     * @param totalName                     总计名称,非空-需要总计
     * @param dataAreaGroupFieldNameList    数据区分组字段名称list
     * @param dataAreaFieldConfigMap        数据区字段缓存map
     * @return                              业务数据内容html
     */
    private StringBuilder getDataAreaDataHtml(List<JSONObject> dataTitleList, JSONObject dataAreaFieldRecordObj, Map<JSONObject, JSONObject> statisticsMap, String totalName, List<String> dataAreaGroupFieldNameList, Map<String, JSONObject> dataAreaFieldConfigMap) {
        List<List<JSONObject>> dataAreaGroupFieldDataList = Lists.newArrayList();
        getDataAreaGroupFieldDataList(dataAreaFieldRecordObj, dataAreaGroupFieldDataList, new JSONObject(), 1, 1, dataAreaGroupFieldNameList.size(), null);
   /**
    * 获取内容html
    *
    * @param dataTitleList              数据标题list
    * @param dataAreaFieldRecordObj     数据区字段记录obj
    * @param statisticsMap              统计map
    * @param totalName                  总计名称,非空-需要总计
    * @param dataAreaGroupFieldNameList 数据区分组字段名称list
    * @param dataAreaFieldConfigMap     数据区字段缓存map
    * @return 业务数据内容html
    */
   private List<List<ReportColumn>> getDataAreaDataRows(List<JSONObject> dataTitleList, JSONObject dataAreaFieldRecordObj, Map<JSONObject, JSONObject> statisticsMap, String totalName, List<String> dataAreaGroupFieldNameList, Map<String, JSONObject> dataAreaFieldConfigMap) {
      List<List<JSONObject>> dataAreaGroupFieldDataList = Lists.newArrayList();
      getDataAreaGroupFieldDataList(dataAreaFieldRecordObj, dataAreaGroupFieldDataList, new JSONObject(), 1, 1, dataAreaGroupFieldNameList.size(), null);
        List<JSONObject> groupTitleList = Lists.newArrayList();
        JSONObject obj;
        for (List<JSONObject> rowList : dataAreaGroupFieldDataList) {
            obj = dataListReportService.extendJSONObject(null, rowList.get(rowList.size() - 1), Arrays.asList(CmnConst.ATTR_ROWSPAN, CmnConst.ATTR_COLSPAN, CmnConst.ATTR_SHOW_NAME, CmnConst.ATTR_IS_STATISTICS_FIELD), -1);
            groupTitleList.add(obj);
        }
      List<JSONObject> groupTitleList = Lists.newArrayList();
      JSONObject obj;
      for (List<JSONObject> rowList : dataAreaGroupFieldDataList) {
         obj = dataListReportService.extendJSONObject(null, rowList.get(rowList.size() - 1), Arrays.asList(CmnConst.ATTR_ROWSPAN, CmnConst.ATTR_COLSPAN, CmnConst.ATTR_SHOW_NAME, CmnConst.ATTR_IS_STATISTICS_FIELD), -1);
         groupTitleList.add(obj);
      }
        StringBuilder html = new StringBuilder(1024);
        JSONObject dataAreaGroupFieldObj;
        int rowspan;
        int colspan;
        String value;
        JSONObject groupTitleObj;
        JSONObject keyObj;
        JSONObject valueObj;
        String statisticsType;
        JSONObject dataAreaFieldConfigObj;
        int groupAreaSubCnt;
        int dataAreaSubCnt;
        List<JSONObject> curRowList;
        int index;
        for (int i = 0;i < dataAreaGroupFieldDataList.size();i++) {
            index = 0;
            curRowList = dataAreaGroupFieldDataList.get(i);
            if (!curRowList.isEmpty()) {
                for (int j = 0; j < curRowList.size(); j++) {
                    dataAreaGroupFieldObj = curRowList.get(j);
                    if (dataAreaGroupFieldObj.isEmpty()) {
                        continue;
                    }
                    if (index == 0) {
                        if ("1".equals(dataAreaGroupFieldObj.getString(CmnConst.ATTR_IS_STATISTICS_FIELD))) {
                            html.append("\n<tr class=\"").append(CmnConst.CLASS_TR_DATA_STATISTICS).append("\">\n    ");
                        } else {
                            html.append("\n<tr class=\"").append(CmnConst.CLASS_TR_DATA_COMMON).append("\">\n    ");
                        }
                    }
                    rowspan = Math.max(1, dataAreaGroupFieldObj.getIntValue(CmnConst.ATTR_ROWSPAN));
                    colspan = Math.max(1, dataAreaGroupFieldObj.getIntValue(CmnConst.ATTR_COLSPAN));
                    value = dataAreaGroupFieldObj.getString(CmnConst.ATTR_SHOW_NAME);
                    html.append("<td rowspan=\"").append(rowspan).append("\" colspan=\"").append(colspan).append("\">").append(value == null ? "" : value).append("</td>");
                    index++;
                }
            } else {
                html.append("\n<tr class=\"").append(CmnConst.CLASS_TR_DATA_COMMON).append("\">\n    ");
            }
            groupTitleObj = groupTitleList.get(i);
            for (JSONObject dataTitleObj : dataTitleList) {
                keyObj = dataListReportService.extendJSONObject((JSONObject) groupTitleObj.clone(), dataTitleObj, Arrays.asList(CmnConst.ATTR_ROWSPAN, CmnConst.ATTR_COLSPAN, CmnConst.ATTR_SHOW_NAME, CmnConst.ATTR_IS_STATISTICS_FIELD, CmnConst.ATTR_REAL_VALUE), -1);
                dataAreaFieldConfigObj = dataAreaFieldConfigMap.get(dataListReportService.fieldInfo2FieldName(dataTitleObj.getString(CmnConst.ATTR_FIELD_INFO)));
                if (dataAreaFieldConfigObj != null) {
                    groupAreaSubCnt = keyObj.getIntValue(CmnConst.ATTR_GROUP_AREA_SUB_CNT);
                    dataAreaSubCnt = keyObj.getIntValue(CmnConst.ATTR_DATA_AREA_SUB_CNT);
                    keyObj.remove(CmnConst.ATTR_GROUP_AREA_SUB_CNT);
                    keyObj.remove(CmnConst.ATTR_DATA_AREA_SUB_CNT);
                    keyObj.remove(CmnConst.ATTR_REAL_VALUE);
                    statisticsType = dataAreaFieldConfigObj.getString(CmnConst.ATTR_STATISTICS);
                    valueObj = statisticsMap.get(keyObj);
                    if (valueObj == null || valueObj.isEmpty()) {
                        value = getFinalValue(keyObj, dataAreaFieldConfigObj, statisticsMap);
                    } else {
                        if (CmnConst.ATTR_STATISTICS_AVG.equals(statisticsType) && "1".equals(dataAreaFieldConfigObj.getString(CmnConst.ATTR_AVG_TYPE))) {
                            if (dataAreaSubCnt == 0 && groupAreaSubCnt == 0) {
                                value = valueObj.getString(statisticsType);
                            } else {
                                value = getTwoTypesGroupAvgStatisticsValue(dataAreaSubCnt, groupAreaSubCnt, valueObj, dataAreaFieldConfigObj, statisticsType);
                            }
                        } else {
                            value = valueObj.getString(statisticsType);
                        }
                        valueObj.put(CmnConst.ATTR_FINAL_VALUE, value);
                    }
                } else {
                    value = "";
                }
                html.append("<td");
                if (!StringUtils.isEmpty(value)) {
                    // class
                    if (!StringUtils.isEmpty(dataAreaFieldConfigObj.getString(CmnConst.ATTR_URL))) {
                        dataListReportService.extendJSONObject(keyObj, dataAreaFieldConfigObj, Collections.singletonList(CmnConst.ATTR_URL));
                        html.append(" class=\"").append(CmnConst.CLASS_TD_CAN_TURN).append("\"");
                    }
                    // 字段属性
                    dataListReportService.getTdAttrObj(keyObj, groupTitleObj);
                    dataListReportService.getTdAttrObj(keyObj, dataTitleObj);
                    html.append(dataListReportService.getTdAttrByObj(keyObj));
                    // 格式
                    value = dataListReportService.formatValue(dataAreaFieldConfigObj, value);
                }
                html.append(">").append(value == null ? "" : value).append("</td>");
            }
            html.append("\n</tr>");
        }
      StringBuilder html = new StringBuilder(1024);
      JSONObject dataAreaGroupFieldObj;
      int rowspan;
      int colspan;
      String value;
      JSONObject groupTitleObj;
      JSONObject keyObj;
      JSONObject valueObj;
      String statisticsType;
      JSONObject dataAreaFieldConfigObj;
      int groupAreaSubCnt;
      int dataAreaSubCnt;
      List<JSONObject> curRowList;
      int index;
      for (int i = 0; i < dataAreaGroupFieldDataList.size(); i++) {
         index = 0;
         curRowList = dataAreaGroupFieldDataList.get(i);
         if (!curRowList.isEmpty()) {
            for (int j = 0; j < curRowList.size(); j++) {
               dataAreaGroupFieldObj = curRowList.get(j);
               if (dataAreaGroupFieldObj.isEmpty()) {
                  continue;
               }
               if (index == 0) {
                  if ("1".equals(dataAreaGroupFieldObj.getString(CmnConst.ATTR_IS_STATISTICS_FIELD))) {
                     html.append("\n<tr class=\"").append(CmnConst.CLASS_TR_DATA_STATISTICS).append("\">\n    ");
                  } else {
                     html.append("\n<tr class=\"").append(CmnConst.CLASS_TR_DATA_COMMON).append("\">\n    ");
                  }
               }
               rowspan = Math.max(1, dataAreaGroupFieldObj.getIntValue(CmnConst.ATTR_ROWSPAN));
               colspan = Math.max(1, dataAreaGroupFieldObj.getIntValue(CmnConst.ATTR_COLSPAN));
               value = dataAreaGroupFieldObj.getString(CmnConst.ATTR_SHOW_NAME);
               html.append("<td rowspan=\"").append(rowspan).append("\" colspan=\"").append(colspan).append("\">").append(value == null ? "" : value).append("</td>");
               index++;
            }
         } else {
            html.append("\n<tr class=\"").append(CmnConst.CLASS_TR_DATA_COMMON).append("\">\n    ");
         }
         groupTitleObj = groupTitleList.get(i);
         for (JSONObject dataTitleObj : dataTitleList) {
            keyObj = dataListReportService.extendJSONObject((JSONObject) groupTitleObj.clone(), dataTitleObj, Arrays.asList(CmnConst.ATTR_ROWSPAN, CmnConst.ATTR_COLSPAN, CmnConst.ATTR_SHOW_NAME, CmnConst.ATTR_IS_STATISTICS_FIELD, CmnConst.ATTR_REAL_VALUE), -1);
            dataAreaFieldConfigObj = dataAreaFieldConfigMap.get(dataListReportService.fieldInfo2FieldName(dataTitleObj.getString(CmnConst.ATTR_FIELD_INFO)));
            if (dataAreaFieldConfigObj != null) {
               groupAreaSubCnt = keyObj.getIntValue(CmnConst.ATTR_GROUP_AREA_SUB_CNT);
               dataAreaSubCnt = keyObj.getIntValue(CmnConst.ATTR_DATA_AREA_SUB_CNT);
               keyObj.remove(CmnConst.ATTR_GROUP_AREA_SUB_CNT);
               keyObj.remove(CmnConst.ATTR_DATA_AREA_SUB_CNT);
               keyObj.remove(CmnConst.ATTR_REAL_VALUE);
               statisticsType = dataAreaFieldConfigObj.getString(CmnConst.ATTR_STATISTICS);
               valueObj = statisticsMap.get(keyObj);
               if (valueObj == null || valueObj.isEmpty()) {
                  value = getFinalValue(keyObj, dataAreaFieldConfigObj, statisticsMap);
               } else {
                  if (CmnConst.ATTR_STATISTICS_AVG.equals(statisticsType) && "1".equals(dataAreaFieldConfigObj.getString(CmnConst.ATTR_AVG_TYPE))) {
                     if (dataAreaSubCnt == 0 && groupAreaSubCnt == 0) {
                        value = valueObj.getString(statisticsType);
                     } else {
                        value = getTwoTypesGroupAvgStatisticsValue(dataAreaSubCnt, groupAreaSubCnt, valueObj, dataAreaFieldConfigObj, statisticsType);
                     }
                  } else {
                     value = valueObj.getString(statisticsType);
                  }
                  valueObj.put(CmnConst.ATTR_FINAL_VALUE, value);
               }
            } else {
               value = "";
            }
            html.append("<td");
            if (!StringUtils.isEmpty(value)) {
               // class
               if (!StringUtils.isEmpty(dataAreaFieldConfigObj.getString(CmnConst.ATTR_URL))) {
                  dataListReportService.extendJSONObject(keyObj, dataAreaFieldConfigObj, Collections.singletonList(CmnConst.ATTR_URL));
                  html.append(" class=\"").append(CmnConst.CLASS_TD_CAN_TURN).append("\"");
               }
               // 字段属性
               dataListReportService.getTdAttrObj(keyObj, groupTitleObj);
               dataListReportService.getTdAttrObj(keyObj, dataTitleObj);
               html.append(dataListReportService.getTdAttrByObj(keyObj));
               // 格式
               value = dataListReportService.formatValue(dataAreaFieldConfigObj, value);
            }
            html.append(">").append(value == null ? "" : value).append("</td>");
         }
         html.append("\n</tr>");
      }
        // 总计
        if (!StringUtils.isEmpty(totalName)) {
            html.append(getTotalStatisticsHtml(statisticsMap, dataTitleList, dataAreaFieldConfigMap, dataAreaGroupFieldNameList.size(), getSubCnt(dataAreaFieldRecordObj), totalName));
        }
      // 总计
      if (!StringUtils.isEmpty(totalName)) {
         html.append(getTotalStatisticsHtml(statisticsMap, dataTitleList, dataAreaFieldConfigMap, dataAreaGroupFieldNameList.size(), getSubCnt(dataAreaFieldRecordObj), totalName));
      }
      List<List<ReportColumn>> reportColumnList = new ArrayList<>();
      //解析html
      //在html前面拼接一个table标签和tbody,否则Jsoup解析会报错
      html.insert(0, "<table><tbody>");
      html.append("</tbody></table>");
      Document doc = Jsoup.parse(html.toString());
      Elements trs = doc.select("tr");
      Elements tds;
      List<ReportColumn> reportColumn;
      ReportColumn column;
      for (Element tr : trs) {
         tds = tr.select("td");
         reportColumn = new ArrayList<>();
         for (Element td : tds) {
            column = new ReportColumn();
            column.setColspan(Integer.parseInt(BaseUtil.ifNull(td.attr("colspan"), "1")));
            column.setRowspan(Integer.parseInt(BaseUtil.ifNull(td.attr("rowspan"), "1")));
            Set<String> classNames = td.classNames();
            if (classNames.contains(CmnConst.CLASS_TD_CAN_TURN)) {
               column.setPenetrate(true);
               column.setPenetrateProperty(td.attr("router"));
            }
            column.setContent(td.text());
            reportColumn.add(column);
         }
         reportColumnList.add(reportColumn);
      }
      return reportColumnList;
   }
        return html;
    }
   /**
    * 获取数据区分组字段数据list
    *
    * @param curOperateObj              当前操作obj
    * @param dataAreaGroupFieldDataList 数据区分组字段数据list
    * @param preObj                     最近操作的obj
    * @param row                        当前行数
    * @param maxCol                     最大列数
    * @return 数据区分组字段数据list
    */
   private int getDataAreaGroupFieldDataList(JSONObject curOperateObj, List<List<JSONObject>> dataAreaGroupFieldDataList, JSONObject preObj, int row, int col, int maxCol, String parentFieldName) {
      String key;
      Object value;
      JSONObject curObj;
      JSONObject topLeftCornerObj;
      String dataAreaFieldName = dataListReportService.fieldInfo2FieldName(curOperateObj.getString(CmnConst.ATTR_FIELD_INFO));
      List<String> statisticsFieldList = dataListReportService.transfer2List(curOperateObj.get(CmnConst.ATTR_STATISTICS_FIELD));
      String realValue = curOperateObj.getString(CmnConst.ATTR_REAL_VALUE);
      JSONObject objValue;
      String newKey;
      List<JSONObject> curRowList;
      JSONObject realValueObj;
      for (Map.Entry<String, Object> entry : curOperateObj.entrySet()) {
         curObj = dataListReportService.extendJSONObject(null, preObj, null);
         key = entry.getKey();
         if (CmnConst.ATTR_FIELD_INFO.equals(key) || CmnConst.ATTR_STATISTICS_FIELD.equals(key) || CmnConst.ATTR_REAL_VALUE.equals(key)) {
            continue;
         }
         value = entry.getValue();
         if (value == null) {
            continue;
         }
         if (!StringUtils.isEmpty(realValue) && !StringUtils.isEmpty(parentFieldName)) {
            if (curObj.get(CmnConst.ATTR_REAL_VALUE) == null) {
               realValueObj = new JSONObject();
               curObj.put(CmnConst.ATTR_REAL_VALUE, realValueObj);
            } else {
               realValueObj = (JSONObject) curObj.get(CmnConst.ATTR_REAL_VALUE);
            }
            realValueObj.put(parentFieldName, realValue);
         }
         if (dataAreaGroupFieldDataList.size() < row) {
            curRowList = Lists.newArrayList();
            dataAreaGroupFieldDataList.add(curRowList);
         } else {
            curRowList = dataAreaGroupFieldDataList.get(row - 1);
         }
         if (curRowList.size() < col - 1) {
            for (int i = 0; i < col - 1; i++) {
               curRowList.add(new JSONObject());
            }
         }
         curObj.put(CmnConst.ATTR_SHOW_NAME, key);
         if (statisticsFieldList.contains(key)) {
            curObj.put(CmnConst.ATTR_IS_STATISTICS_FIELD, "1");
            newKey = key.replace(CmnConst.STATISTICS_NAME, "");
            curObj.put(dataAreaFieldName, newKey);
            curObj.put(CmnConst.ATTR_DATA_AREA_SUB_CNT, getSubCnt(curOperateObj.getJSONObject(newKey)));
         } else {
            curObj.put(dataAreaFieldName, key);
         }
         curObj.put(CmnConst.ATTR_ROWSPAN, 1);
         curObj.put(CmnConst.ATTR_COLSPAN, 1);
         curRowList.add(curObj);
         if (value instanceof JSONObject) {
            objValue = (JSONObject) value;
            if (objValue.isEmpty()) {
               curObj.put(CmnConst.ATTR_COLSPAN, maxCol - col + 1);
               if (row > 1 && col > 1) {
                  int emptyCount = 0;
                  for (JSONObject obj : curRowList) {
                     if (obj.isEmpty()) {
                        emptyCount++;
                     } else {
                        break;
                     }
                  }
                  for (int j = 0; j < emptyCount; j++) {
                     int curRow = row - 2;
                     topLeftCornerObj = dataAreaGroupFieldDataList.get(curRow).get(j);
                     while (topLeftCornerObj.isEmpty() && curRow > 0) {
                        curRow--;
                        topLeftCornerObj = dataAreaGroupFieldDataList.get(curRow).get(j);
                     }
                     topLeftCornerObj.put(CmnConst.ATTR_ROWSPAN, topLeftCornerObj.getIntValue(CmnConst.ATTR_ROWSPAN) + 1);
                  }
               }
               row++;
               continue;
            }
            if (objValue.size() == 1 && objValue.containsKey(CmnConst.ATTR_REAL_VALUE)) {
               row++;
               continue;
            }
            row = getDataAreaGroupFieldDataList(objValue, dataAreaGroupFieldDataList, curObj, row, col + 1, maxCol, dataAreaFieldName);
         }
      }
      return row;
   }
    /**
     * 获取数据区分组字段数据list
     * @param curOperateObj                 当前操作obj
     * @param dataAreaGroupFieldDataList    数据区分组字段数据list
     * @param preObj                        最近操作的obj
     * @param row                           当前行数
     * @param maxCol                        最大列数
     * @return                              数据区分组字段数据list
     */
    private int getDataAreaGroupFieldDataList(JSONObject curOperateObj, List<List<JSONObject>> dataAreaGroupFieldDataList, JSONObject preObj, int row, int col, int maxCol, String parentFieldName) {
        String key;
        Object value;
        JSONObject curObj;
        JSONObject topLeftCornerObj;
        String dataAreaFieldName = dataListReportService.fieldInfo2FieldName(curOperateObj.getString(CmnConst.ATTR_FIELD_INFO));
        List<String> statisticsFieldList = dataListReportService.transfer2List(curOperateObj.get(CmnConst.ATTR_STATISTICS_FIELD));
        String realValue = curOperateObj.getString(CmnConst.ATTR_REAL_VALUE);
        JSONObject objValue;
        String newKey;
        List<JSONObject> curRowList;
        JSONObject realValueObj;
        for (Map.Entry<String, Object> entry : curOperateObj.entrySet()) {
            curObj = dataListReportService.extendJSONObject(null, preObj, null);
            key = entry.getKey();
            if (CmnConst.ATTR_FIELD_INFO.equals(key) || CmnConst.ATTR_STATISTICS_FIELD.equals(key) || CmnConst.ATTR_REAL_VALUE.equals(key)) {
                continue;
            }
            value = entry.getValue();
            if (value == null) {
                continue;
            }
            if (!StringUtils.isEmpty(realValue) && !StringUtils.isEmpty(parentFieldName)) {
                if (curObj.get(CmnConst.ATTR_REAL_VALUE) == null) {
                    realValueObj = new JSONObject();
                    curObj.put(CmnConst.ATTR_REAL_VALUE, realValueObj);
                } else {
                    realValueObj = (JSONObject) curObj.get(CmnConst.ATTR_REAL_VALUE);
                }
                realValueObj.put(parentFieldName, realValue);
            }
            if (dataAreaGroupFieldDataList.size() < row) {
                curRowList = Lists.newArrayList();
                dataAreaGroupFieldDataList.add(curRowList);
            } else {
                curRowList = dataAreaGroupFieldDataList.get(row - 1);
            }
            if (curRowList.size() < col - 1) {
                for (int i = 0; i < col - 1; i++) {
                    curRowList.add(new JSONObject());
                }
            }
            curObj.put(CmnConst.ATTR_SHOW_NAME, key);
            if (statisticsFieldList.contains(key)) {
                curObj.put(CmnConst.ATTR_IS_STATISTICS_FIELD, "1");
                newKey = key.replace(CmnConst.STATISTICS_NAME, "");
                curObj.put(dataAreaFieldName, newKey);
                curObj.put(CmnConst.ATTR_DATA_AREA_SUB_CNT, getSubCnt(curOperateObj.getJSONObject(newKey)));
            } else {
                curObj.put(dataAreaFieldName, key);
            }
            curObj.put(CmnConst.ATTR_ROWSPAN, 1);
            curObj.put(CmnConst.ATTR_COLSPAN, 1);
            curRowList.add(curObj);
            if (value instanceof JSONObject) {
                objValue = (JSONObject) value;
                if (objValue.isEmpty()) {
                    curObj.put(CmnConst.ATTR_COLSPAN, maxCol - col + 1);
                    if (row > 1 && col > 1) {
                        int emptyCount = 0;
                        for (JSONObject obj : curRowList) {
                            if (obj.isEmpty()) {
                                emptyCount++;
                            } else {
                                break;
                            }
                        }
                        for (int j = 0; j < emptyCount; j++) {
                            int curRow = row - 2;
                            topLeftCornerObj = dataAreaGroupFieldDataList.get(curRow).get(j);
                            while (topLeftCornerObj.isEmpty() && curRow > 0) {
                                curRow--;
                                topLeftCornerObj = dataAreaGroupFieldDataList.get(curRow).get(j);
                            }
                            topLeftCornerObj.put(CmnConst.ATTR_ROWSPAN, topLeftCornerObj.getIntValue(CmnConst.ATTR_ROWSPAN) + 1);
                        }
                    }
                    row++;
                    continue;
                }
                if (objValue.size() == 1&& objValue.containsKey(CmnConst.ATTR_REAL_VALUE)) {
                    row++;
                    continue;
                }
                row = getDataAreaGroupFieldDataList(objValue, dataAreaGroupFieldDataList, curObj, row, col + 1, maxCol, dataAreaFieldName);
            }
        }
        return row;
    }
   /**
    * 获取总计html
    *
    * @param statisticsMap           统计map
    * @param dataTitleList           数据标题list
    * @param dataAreaFieldConfigMap  数据区字段缓存map
    * @param dataAreaGroupFieldCount 数据区分组字段个数
    * @param dataAreaSubCnt          数据区下级分组项数
    * @param totalName               总计名称
    * @return
    */
   private StringBuilder getTotalStatisticsHtml(Map<JSONObject, JSONObject> statisticsMap, List<JSONObject> dataTitleList, Map<String, JSONObject> dataAreaFieldConfigMap, int dataAreaGroupFieldCount, int dataAreaSubCnt, String totalName) {
      StringBuilder html = new StringBuilder(256);
      html.append("\n<tr class=\"").append(CmnConst.CLASS_TR_DATA_STATISTICS).append("\">\n    ");
      html.append("<td colspan=\"").append(dataAreaGroupFieldCount).append("\">").append(totalName).append("</td>");
      JSONObject dataTitleObj;
      JSONObject keyObj;
      JSONObject dataAreaFieldConfigObj;
      String statisticsType;
      JSONObject valueObj;
      String value;
      int groupAreaSubCnt;
      for (int i = 0; i < dataTitleList.size(); i++) {
         dataTitleObj = dataTitleList.get(i);
         keyObj = dataListReportService.extendJSONObject(null, dataTitleObj, Arrays.asList(CmnConst.ATTR_ROWSPAN, CmnConst.ATTR_COLSPAN, CmnConst.ATTR_SHOW_NAME, CmnConst.ATTR_IS_STATISTICS_FIELD, CmnConst.ATTR_REAL_VALUE), -1);
         dataAreaFieldConfigObj = dataAreaFieldConfigMap.get(dataListReportService.fieldInfo2FieldName(dataTitleObj.getString(CmnConst.ATTR_FIELD_INFO)));
         if (dataAreaFieldConfigObj != null) {
            groupAreaSubCnt = keyObj.getIntValue(CmnConst.ATTR_GROUP_AREA_SUB_CNT);
            keyObj.remove(CmnConst.ATTR_GROUP_AREA_SUB_CNT);
            statisticsType = dataAreaFieldConfigObj.getString(CmnConst.ATTR_STATISTICS);
            valueObj = statisticsMap.get(keyObj);
            if (valueObj == null || valueObj.isEmpty()) {
               value = getFinalValue(keyObj, dataAreaFieldConfigObj, statisticsMap);
            } else {
               if (CmnConst.ATTR_STATISTICS_AVG.equals(statisticsType) && "1".equals(dataAreaFieldConfigObj.getString(CmnConst.ATTR_AVG_TYPE))) {
                  value = getTwoTypesGroupAvgStatisticsValue(dataAreaSubCnt, groupAreaSubCnt, valueObj, dataAreaFieldConfigObj, statisticsType);
               } else {
                  value = valueObj.getString(statisticsType);
               }
               valueObj.put(CmnConst.ATTR_FINAL_VALUE, value);
            }
         } else {
            value = "";
         }
         html.append("<td");
         if (!StringUtils.isEmpty(value)) {
            // class
            if (!StringUtils.isEmpty(dataAreaFieldConfigObj.getString(CmnConst.ATTR_URL))) {
               dataListReportService.extendJSONObject(keyObj, dataAreaFieldConfigObj, Collections.singletonList(CmnConst.ATTR_URL));
               html.append(" class=\"").append(CmnConst.CLASS_TD_CAN_TURN).append("\"");
            }
            // 字段属性
            dataListReportService.getTdAttrObj(keyObj, dataTitleObj);
            html.append(dataListReportService.getTdAttrByObj(keyObj));
            // 格式
            value = dataListReportService.formatValue(dataAreaFieldConfigObj, value);
         }
         html.append(">").append(value == null ? "" : value).append("</td>");
      }
      html.append("\n</tr>");
      return html;
   }
    /**
     * 获取总计html
     * @param statisticsMap             统计map
     * @param dataTitleList             数据标题list
     * @param dataAreaFieldConfigMap    数据区字段缓存map
     * @param dataAreaGroupFieldCount   数据区分组字段个数
     * @param dataAreaSubCnt            数据区下级分组项数
     * @param totalName                 总计名称
     * @return
     */
    private StringBuilder getTotalStatisticsHtml(Map<JSONObject, JSONObject> statisticsMap, List<JSONObject> dataTitleList, Map<String, JSONObject> dataAreaFieldConfigMap, int dataAreaGroupFieldCount, int dataAreaSubCnt, String totalName) {
        StringBuilder html = new StringBuilder(256);
        html.append("\n<tr class=\"").append(CmnConst.CLASS_TR_DATA_STATISTICS).append("\">\n    ");
        html.append("<td colspan=\"").append(dataAreaGroupFieldCount).append("\">").append(totalName).append("</td>");
        JSONObject dataTitleObj;
        JSONObject keyObj;
        JSONObject dataAreaFieldConfigObj;
        String statisticsType;
        JSONObject valueObj;
        String value;
        int groupAreaSubCnt;
        for (int i = 0;i < dataTitleList.size();i++) {
            dataTitleObj = dataTitleList.get(i);
            keyObj = dataListReportService.extendJSONObject(null, dataTitleObj, Arrays.asList(CmnConst.ATTR_ROWSPAN, CmnConst.ATTR_COLSPAN, CmnConst.ATTR_SHOW_NAME, CmnConst.ATTR_IS_STATISTICS_FIELD, CmnConst.ATTR_REAL_VALUE), -1);
            dataAreaFieldConfigObj = dataAreaFieldConfigMap.get(dataListReportService.fieldInfo2FieldName(dataTitleObj.getString(CmnConst.ATTR_FIELD_INFO)));
            if (dataAreaFieldConfigObj != null) {
                groupAreaSubCnt = keyObj.getIntValue(CmnConst.ATTR_GROUP_AREA_SUB_CNT);
                keyObj.remove(CmnConst.ATTR_GROUP_AREA_SUB_CNT);
                statisticsType = dataAreaFieldConfigObj.getString(CmnConst.ATTR_STATISTICS);
                valueObj = statisticsMap.get(keyObj);
                if (valueObj == null || valueObj.isEmpty()) {
                    value = getFinalValue(keyObj, dataAreaFieldConfigObj, statisticsMap);
                } else {
                    if (CmnConst.ATTR_STATISTICS_AVG.equals(statisticsType) && "1".equals(dataAreaFieldConfigObj.getString(CmnConst.ATTR_AVG_TYPE))) {
                        value = getTwoTypesGroupAvgStatisticsValue(dataAreaSubCnt, groupAreaSubCnt, valueObj, dataAreaFieldConfigObj, statisticsType);
                    } else {
                        value = valueObj.getString(statisticsType);
                    }
                    valueObj.put(CmnConst.ATTR_FINAL_VALUE, value);
                }
            } else {
                value = "";
            }
            html.append("<td");
            if (!StringUtils.isEmpty(value)) {
                // class
                if (!StringUtils.isEmpty(dataAreaFieldConfigObj.getString(CmnConst.ATTR_URL))) {
                    dataListReportService.extendJSONObject(keyObj, dataAreaFieldConfigObj, Collections.singletonList(CmnConst.ATTR_URL));
                    html.append(" class=\"").append(CmnConst.CLASS_TD_CAN_TURN).append("\"");
                }
                // 字段属性
                dataListReportService.getTdAttrObj(keyObj, dataTitleObj);
                html.append(dataListReportService.getTdAttrByObj(keyObj));
                // 格式
                value = dataListReportService.formatValue(dataAreaFieldConfigObj, value);
            }
            html.append(">").append(value == null ? "" : value).append("</td>");
        }
        html.append("\n</tr>");
        return html;
    }
   /**
    * 获取统计方式为“最终统计”的值
    *
    * @param keyObj
    * @param dataAreaFieldConfigObj
    * @param statisticsMap
    * @return
    */
   private String getFinalValue(JSONObject keyObj, JSONObject dataAreaFieldConfigObj, Map<JSONObject, JSONObject> statisticsMap) {
      JSONObject valueObj;
      String value;
      if (CmnConst.ATTR_STATISTICS_FINAL_STATISTICS.equals(dataAreaFieldConfigObj.getString(CmnConst.ATTR_STATISTICS))
            && "1".equals(dataAreaFieldConfigObj.getString(CmnConst.ATTR_IS_CUSTOM_FIELD)) && !StringUtils.isEmpty(dataAreaFieldConfigObj.getString(CmnConst.ATTR_FORMULA))) {
         // 统计方式为“最终统计”
         String formula = dataAreaFieldConfigObj.getString(CmnConst.ATTR_FORMULA);
         List<String> suitList = dataListReportService.getSuitContent(formula, "\\{#((?!\\{).)+#\\}");
         JSONObject tempObj = (JSONObject) keyObj.clone();
         for (String suitContent : suitList) {
            tempObj.put(CmnConst.ATTR_FIELD_INFO, suitContent);
            valueObj = statisticsMap.get(tempObj);
            formula = formula.replace(suitContent, (valueObj == null || valueObj.getString(CmnConst.ATTR_FINAL_VALUE) == null ? "0" : valueObj.getString(CmnConst.ATTR_FINAL_VALUE)) + "d");
         }
         try {
            value = BaseUtil.executeExpression(formula.replace("/0", "/1").replaceAll("\\/\\{#[\\w]+#}", "/1").replaceAll("\\{#[\\w]+#}", "0"), Maps.newHashMap()).toString();
         } catch (Exception e) {
            SpringMVCContextHolder.getSystemLogger().error(e);
            value = "";
         }
      } else {
         value = "";
      }
      return value;
   }
    /**
     * 获取统计方式为“最终统计”的值
     * @param keyObj
     * @param dataAreaFieldConfigObj
     * @param statisticsMap
     * @return
     */
    private String getFinalValue(JSONObject keyObj, JSONObject dataAreaFieldConfigObj, Map<JSONObject, JSONObject> statisticsMap) {
        JSONObject valueObj;
        String value;
        if (CmnConst.ATTR_STATISTICS_FINAL_STATISTICS.equals(dataAreaFieldConfigObj.getString(CmnConst.ATTR_STATISTICS))
                && "1".equals(dataAreaFieldConfigObj.getString(CmnConst.ATTR_IS_CUSTOM_FIELD)) && !StringUtils.isEmpty(dataAreaFieldConfigObj.getString(CmnConst.ATTR_FORMULA))) {
            // 统计方式为“最终统计”
            String formula = dataAreaFieldConfigObj.getString(CmnConst.ATTR_FORMULA);
            List<String> suitList = dataListReportService.getSuitContent(formula, "\\{#((?!\\{).)+#\\}");
            JSONObject tempObj = (JSONObject) keyObj.clone();
            for (String suitContent : suitList) {
                tempObj.put(CmnConst.ATTR_FIELD_INFO, suitContent);
                valueObj = statisticsMap.get(tempObj);
                formula = formula.replace(suitContent, (valueObj == null || valueObj.getString(CmnConst.ATTR_FINAL_VALUE) == null ? "0" : valueObj.getString(CmnConst.ATTR_FINAL_VALUE)) + "d");
            }
            try {
                value = BaseUtil.executeExpression(formula.replace("/0", "/1").replaceAll("\\/\\{#[\\w]+#}", "/1").replaceAll("\\{#[\\w]+#}", "0"), Maps.newHashMap()).toString();
            } catch (Exception e) {
                SpringMVCContextHolder.getSystemLogger().error(e);
                value = "";
            }
        } else {
            value = "";
        }
        return value;
    }
   /**
    * 获取行列两种不同的下级分组平均值
    *
    * @param dataAreaSubCnt         按照数据区分组的下级分组项数
    * @param groupAreaSubCnt        按照分组表头去分组的下级分组项数
    * @param curFieldStatisticsObj  当前字段统计obj
    * @param dataAreaFieldConfigObj 当前数据区字段缓存obj
    * @param statisticsType         统计类型
    * @return 按照下级分组项进行平均的行列平均值
    */
   private String getTwoTypesGroupAvgStatisticsValue(int dataAreaSubCnt, int groupAreaSubCnt, JSONObject curFieldStatisticsObj, JSONObject dataAreaFieldConfigObj, String statisticsType) {
      // 列下级分组
      StringBuilder value = new StringBuilder(32);
      String dataAreaValue = getGroupAreaGroupAvgStatisticsValue(dataAreaSubCnt, curFieldStatisticsObj, dataAreaFieldConfigObj, statisticsType, CmnConst.ATTR_STATISTICS_DATA_AREA_AVG, dataAreaSubCnt == 0);
      String groupAreaValue = getGroupAreaGroupAvgStatisticsValue(groupAreaSubCnt, curFieldStatisticsObj, dataAreaFieldConfigObj, statisticsType, CmnConst.ATTR_STATISTICS_GROUP_AREA_AVG, groupAreaSubCnt == 0);
    /**
     * 获取行列两种不同的下级分组平均值
     * @param dataAreaSubCnt            按照数据区分组的下级分组项数
     * @param groupAreaSubCnt           按照分组表头去分组的下级分组项数
     * @param curFieldStatisticsObj     当前字段统计obj
     * @param dataAreaFieldConfigObj    当前数据区字段缓存obj
     * @param statisticsType            统计类型
     * @return                          按照下级分组项进行平均的行列平均值
     */
    private String getTwoTypesGroupAvgStatisticsValue(int dataAreaSubCnt, int groupAreaSubCnt, JSONObject curFieldStatisticsObj, JSONObject dataAreaFieldConfigObj, String statisticsType) {
        // 列下级分组
        StringBuilder value = new StringBuilder(32);
        String dataAreaValue = getGroupAreaGroupAvgStatisticsValue(dataAreaSubCnt, curFieldStatisticsObj, dataAreaFieldConfigObj, statisticsType, CmnConst.ATTR_STATISTICS_DATA_AREA_AVG, dataAreaSubCnt == 0);
        String groupAreaValue = getGroupAreaGroupAvgStatisticsValue(groupAreaSubCnt, curFieldStatisticsObj, dataAreaFieldConfigObj, statisticsType, CmnConst.ATTR_STATISTICS_GROUP_AREA_AVG, groupAreaSubCnt == 0);
      if (dataAreaSubCnt > 0) {
         value.append(dataAreaValue);
      }
      if (dataAreaSubCnt > 0 && groupAreaSubCnt > 0) {
         value.append("\\");
      }
      if (groupAreaSubCnt > 0) {
         value.append(groupAreaValue);
      }
      return value.toString();
   }
        if (dataAreaSubCnt > 0) {
            value.append(dataAreaValue);
        }
        if (dataAreaSubCnt > 0 && groupAreaSubCnt > 0) {
            value.append("\\");
        }
        if (groupAreaSubCnt > 0) {
            value.append(groupAreaValue);
        }
        return value.toString();
    }
    /**
     * 获取指定类型的下级分组平均值
     * @param subCnt                    下级分组项数
     * @param curFieldStatisticsObj     当前字段统计obj
     * @param dataAreaFieldConfigObj    当前数据区字段缓存obj
     * @param statisticsType            统计类型
     * @param avgType                   CmnConst.ATTR_STATISTICS_DATA_AREA_AVG-行;CmnConst.ATTR_STATISTICS_GROUP_AREA_AVG-列
     * @return                          按照下级分组项进行平均的平均值
     */
    private String getGroupAreaGroupAvgStatisticsValue(int subCnt, JSONObject curFieldStatisticsObj, JSONObject dataAreaFieldConfigObj, String statisticsType, String avgType, boolean lastStage) {
        String value;
        if (subCnt > 0) {
            curFieldStatisticsObj.put(CmnConst.ATTR_STATISTICS_SUB_CNT, subCnt);
            dataListReportService.getAvgValue(curFieldStatisticsObj, dataAreaFieldConfigObj, lastStage);
            value = curFieldStatisticsObj.getString(statisticsType);
            curFieldStatisticsObj.put(avgType, value);
        } else {
            value = curFieldStatisticsObj.getString(statisticsType);
        }
        return value == null ? "" : value;
    }
   /**
    * 获取指定类型的下级分组平均值
    *
    * @param subCnt                 下级分组项数
    * @param curFieldStatisticsObj  当前字段统计obj
    * @param dataAreaFieldConfigObj 当前数据区字段缓存obj
    * @param statisticsType         统计类型
    * @param avgType                CmnConst.ATTR_STATISTICS_DATA_AREA_AVG-行;CmnConst.ATTR_STATISTICS_GROUP_AREA_AVG-列
    * @return 按照下级分组项进行平均的平均值
    */
   private String getGroupAreaGroupAvgStatisticsValue(int subCnt, JSONObject curFieldStatisticsObj, JSONObject dataAreaFieldConfigObj, String statisticsType, String avgType, boolean lastStage) {
      String value;
      if (subCnt > 0) {
         curFieldStatisticsObj.put(CmnConst.ATTR_STATISTICS_SUB_CNT, subCnt);
         dataListReportService.getAvgValue(curFieldStatisticsObj, dataAreaFieldConfigObj, lastStage);
         value = curFieldStatisticsObj.getString(statisticsType);
         curFieldStatisticsObj.put(avgType, value);
      } else {
         value = curFieldStatisticsObj.getString(statisticsType);
      }
      return value == null ? "" : value;
   }
}