许鹏程
2023-06-29 cb4df5a1c9cda76e828fa202990df33be0735105
src/main/java/com/product/server/report/service/CommonReportService.java
@@ -1,6 +1,7 @@
package com.product.server.report.service;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.NumberUtil;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
@@ -11,6 +12,7 @@
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.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -26,556 +28,644 @@
 */
@Component
public class CommonReportService extends AbstractBaseService {
    @Autowired
    private DataListReportService dataListReportService;
   @Autowired
   private DataListReportService dataListReportService;
    /**
     * 报表-解析
     *
     * @param recordDte           业务数据dte
     * @param totalStatisticsFlag 是否合计标识
     * @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);
        // css
        StringBuilder cssHtml = dataListReportService.getCssHtml();
   /**
    * 报表-解析
    *
    * @param recordDte            业务数据dte
    * @param totalName            总计名称
    * @param reportConfigMap      报表配置缓存map
    * @param unpivotInfoContainer 行列转换信息
    * @return
    */
   public List<List<ReportColumn>>[] getReport(DataTableEntity recordDte, String totalName, Map<Integer, List<JSONObject>> reportConfigMap, Collection<String> unpivotInfoContainer) {
      List<List<ReportColumn>>[] reportColumnList = new List[]{new ArrayList(), new ArrayList(), new ArrayList()};
        // 数据区
        Map<String, Set<String>> headAndTailTitleDataMap = Maps.newHashMap();
        String dataAreaHtml = getDataAreaHtml(reportConfigMap, headAndTailTitleDataMap, recordDte, totalName);
      // 数据区
      Map<String, Set<String>> headAndTailTitleDataMap = Maps.newHashMap();
      List<List<ReportColumn>> reportRows = getDataArea(reportConfigMap, headAndTailTitleDataMap, recordDte, totalName, unpivotInfoContainer);
      int totalColCount = reportConfigMap.get(0).size() + unpivotInfoContainer.size() - 1;
      // 头部标题区
      if (!reportConfigMap.get(1).isEmpty()) {
         reportColumnList[0] = (dataListReportService.getTitleRows(reportConfigMap.get(1), totalColCount, headAndTailTitleDataMap, "head"));
      }
      //如果reportRows 行数大于0将第一行的数据放入头部标题区
      if (reportRows.size() >= 0) {
         reportColumnList[0].add(reportRows.get(0));
         reportRows.remove(0);
      }
      reportColumnList[1] = reportRows;
      // 底部标题区
      if (!reportConfigMap.get(3).isEmpty()) {
         reportColumnList[2] = (dataListReportService.getTitleRows(reportConfigMap.get(3), totalColCount, headAndTailTitleDataMap, "tail"));
      }
        int totalColCount = reportConfigMap.get(0).size();
        // 头部标题区
        StringBuilder headTitleHtml = null;
        if (!reportConfigMap.get(1).isEmpty()) {
            headTitleHtml = dataListReportService.getTitleHtml(reportConfigMap.get(1), totalColCount, headAndTailTitleDataMap, "head");
        }
//      reportHtml.append("\n<body>\n<table class=\"report_main\"").append(tableStyle).append(">")
//            .append(headTitleHtml == null ? "" : headTitleHtml)
//            .append(dataAreaHtml)
//            .append(tailTitleHtml == null ? "" : tailTitleHtml)
//            .append("\n</table>\n</body>");
//
//      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 reportColumnList;
   }
        // 底部标题区
        StringBuilder tailTitleHtml = null;
        if (!reportConfigMap.get(3).isEmpty()) {
            tailTitleHtml = dataListReportService.getTitleHtml(reportConfigMap.get(3), totalColCount, headAndTailTitleDataMap, "tail");
        }
   /**
    * 获取报表数据区html
    *
    * @param reportConfigMap         报表缓存map
    * @param headAndTailTitleDataMap 头部、尾部标题区数据字段map
    * @param recordDte               业务数据集合
    * @param totalName               总计名称,非空-需要总计
    * @return
    */
   private List<List<ReportColumn>> getDataArea(Map<Integer, List<JSONObject>> reportConfigMap, Map<String, Set<String>> headAndTailTitleDataMap, DataTableEntity recordDte, String totalName, Collection<String> unpivotInfoContainer) {
      List<List<ReportColumn>> reportColumnList = Lists.newArrayList();
      // 数据区字段缓存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)));
      // 统计map
      Map<JSONObject, JSONObject> statisticsMap = Maps.newLinkedHashMap();
        reportHtml.append("\n<body>\n<table class=\"report_main\"").append(tableStyle).append(">")
                .append(cssHtml)
                .append(headTitleHtml == null ? "" : headTitleHtml)
                .append(dataAreaHtml)
                .append(tailTitleHtml == null ? "" : tailTitleHtml)
                .append("\n</table>\n</body>");
      // 将行列转换的信息添加到数据区字段缓存map里面
      Map<String, JSONObject> newDataAreaFieldConfigMap = Maps.newLinkedHashMap();
      int x = 0;
      if (!unpivotInfoContainer.isEmpty()) {
         for (Map.Entry<String, JSONObject> entry : dataAreaFieldConfigMap.entrySet()) {
            String fieldName = entry.getKey();
            JSONObject fieldConfigObj = entry.getValue();
            if (fieldConfigObj.getIntValue(CmnConst.IS_UNPIVOT) == 1) {
               x = fieldConfigObj.getIntValue(CmnConst.ATTR_X);
               fieldConfigObj.put(CmnConst.IS_UNPIVOT, 0);
               fieldConfigObj.put(CmnConst.ATTR_IS_CUSTOM_FIELD, 0);
               for (String unpivotField : unpivotInfoContainer) {
                  JSONObject newFieldConfigObj = new JSONObject();
                  newFieldConfigObj.putAll(fieldConfigObj);
                  newFieldConfigObj.put(CmnConst.ATTR_X, ++x);
                  newFieldConfigObj.put(CmnConst.ATTR_SHOW_NAME, newFieldConfigObj.getString(CmnConst.ATTR_SHOW_NAME).replace("{#unpivot_name#}", unpivotField));
                  newDataAreaFieldConfigMap.put(unpivotField, newFieldConfigObj);
               }
            } else {
               if (x > fieldConfigObj.getIntValue(CmnConst.ATTR_X)) {
                  fieldConfigObj.put(CmnConst.ATTR_X, ++x);
               }
               newDataAreaFieldConfigMap.put(fieldName, fieldConfigObj);
            }
         }
      } else {
         newDataAreaFieldConfigMap = dataAreaFieldConfigMap;
      }
        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;
    }
      // 标题
      reportColumnList.add(getDataAreaTitle(newDataAreaFieldConfigMap));
      // 内容
      List<List<ReportColumn>> dataAreaData = getDataAreaData(newDataAreaFieldConfigMap, recordDte, headAndTailTitleDataMap, headAndTailFieldSet, statisticsMap, totalName);
      reportColumnList.addAll(dataAreaData);
      return reportColumnList;
   }
    /**
     * 获取报表数据区html
     *
     * @param reportConfigMap         报表缓存map
     * @param headAndTailTitleDataMap 头部、尾部标题区数据字段map
     * @param recordDte               业务数据集合
     * @param totalName               总计名称,非空-需要总计
     * @return
     */
    private String getDataAreaHtml(Map<Integer, List<JSONObject>> reportConfigMap, Map<String, Set<String>> headAndTailTitleDataMap, DataTableEntity recordDte, String totalName) {
        // 数据区字段缓存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)));
        // 统计map
        Map<JSONObject, JSONObject> statisticsMap = Maps.newLinkedHashMap();
   /**
    * 获取标题
    *
    * @param dataAreaFieldConfigMap 数据区字段缓存map
    * @return
    */
   private List<ReportColumn> getDataAreaTitle(Map<String, JSONObject> dataAreaFieldConfigMap) {
      List<ReportColumn> columnRow = new ArrayList<>();
      dataAreaFieldConfigMap.forEach((dataAreaFieldName, dataAreaFieldConfigObj) -> {
         ReportColumn column = new ReportColumn();
         column.setContent(dataAreaFieldConfigObj.getString(CmnConst.ATTR_SHOW_NAME));
         String width = dataAreaFieldConfigObj.getString(CmnConst.ATTR_WIDTH);
         //判断宽度是否为空并且是数字(正整数和小数都可以)
         if (StringUtils.isNotBlank(width) && width.matches("^[0-9]+(.[0-9]+)?$")) {
            //将宽度转换为double类型
            column.setColumnWidth(NumberUtil.parseInt(width));
         }
         columnRow.add(column);
      });
      return columnRow;
   }
        StringBuilder dataAreaHtml = new StringBuilder(1024);
        // 标题
        dataAreaHtml.append(getDataAreaTitleHtml(dataAreaFieldConfigMap));
        // 内容
        dataAreaHtml.append(getDataAreaDataHtml(dataAreaFieldConfigMap, recordDte, headAndTailTitleDataMap, headAndTailFieldSet, statisticsMap, totalName));
        return dataAreaHtml.toString();
    }
   /**
    * 获取内容,包含统计
    *
    * @param dataAreaFieldConfigMap 数据区字段缓存map
    * @param recordDte              业务数据集合
    * @param headAndTailFieldSet    头部、尾部标题区字段set
    * @param statisticsMap          统计map
    * @param totalName              总计名称
    * @return
    */
   private List<List<ReportColumn>> getDataAreaData(Map<String, JSONObject> dataAreaFieldConfigMap, DataTableEntity recordDte, Map<String, Set<String>> headAndTailTitleDataMap, Set<String> headAndTailFieldSet, Map<JSONObject, JSONObject> statisticsMap, String totalName) {
      List<List<ReportColumn>> reportColumnList = Lists.newArrayList();
      // 数据区分组统计字段名称list
      List<String> dataAreaGroupStatisticsFieldNameList = Lists.newArrayList();
      // 数据区分组字段名称list
      List<String> dataAreaGroupFieldNameList = Lists.newArrayList();
      dataAreaFieldConfigMap.forEach((dataAreaFieldName, dataAreaFieldConfigObj) -> {
         if ("1".equals(dataAreaFieldConfigObj.getString(CmnConst.ATTR_IS_GROUP))) {
            dataAreaGroupFieldNameList.add(dataAreaFieldName);
            if ("1".equals(dataAreaFieldConfigObj.getString(CmnConst.ATTR_IS_STATISTICS))) {
               dataAreaGroupStatisticsFieldNameList.add(dataAreaFieldName);
            }
         }
      });
    /**
     * 获取标题
     *
     * @param dataAreaFieldConfigMap 数据区字段缓存map
     * @return
     */
    private StringBuilder getDataAreaTitleHtml(Map<String, JSONObject> dataAreaFieldConfigMap) {
        StringBuilder html = new StringBuilder(256);
        html.append("<tr class=\"").append(CmnConst.CLASS_TR_DATA_TITLE).append("\">");
        dataAreaFieldConfigMap.forEach((dataAreaFieldName, dataAreaFieldConfigObj) -> {
            html.append("<td>").append(dataListReportService.dealTdWidth(dataAreaFieldConfigObj, dataAreaFieldConfigObj.getString(CmnConst.ATTR_SHOW_NAME))).append("</td>");
        });
        html.append("</tr>");
        return html;
    }
//      StringBuilder dataAreaDataHtml = new StringBuilder(1024);
//      StringBuilder curRowHtml = new StringBuilder(256);
      List<ReportColumn> curRowColumn = new ArrayList<>();
      FieldSetEntity recordFse;
      FieldSetEntity preFse = null;
      String dataAreaFieldName;
      JSONObject dataAreaFieldConfigObj;
      String value;
      JSONObject keyObj;
      Map<String, String> replaceMap = Maps.newHashMap();
      Map<String, String> dataAreaClosestGroupStatisticsFieldValueMap = Maps.newHashMap();
      Map<String, String> dataAreaClosestGroupFieldValueMap = Maps.newHashMap();
      String closestGroupStatisticsFieldName = null;
      String closestGroupFieldName = null;
      String tempFieldName;
      String paramKey;
      boolean combineFlag;
      ReportColumn currentColumn = new ReportColumn();
      JSONObject dataAreaGroupFieldRecordObj = new JSONObject();
      for (int i = 0; i < recordDte.getRows(); i++) {
         recordFse = recordDte.getFieldSetEntity(i);
         // 获取头部、尾部标题区数据字段
         dataListReportService.getHeadAndTailTitleDataMap(headAndTailTitleDataMap, headAndTailFieldSet, recordFse);
    /**
     * 获取内容,包含统计
     *
     * @param dataAreaFieldConfigMap 数据区字段缓存map
     * @param recordDte              业务数据集合
     * @param headAndTailFieldSet    头部、尾部标题区字段set
     * @param statisticsMap          统计map
     * @param totalName              总计名称
     * @return
     */
    private String getDataAreaDataHtml(Map<String, JSONObject> dataAreaFieldConfigMap, DataTableEntity recordDte, Map<String, Set<String>> headAndTailTitleDataMap, Set<String> headAndTailFieldSet, Map<JSONObject, JSONObject> statisticsMap, String totalName) {
        // 数据区分组统计字段名称list
        List<String> dataAreaGroupStatisticsFieldNameList = Lists.newArrayList();
        // 数据区分组字段名称list
        List<String> dataAreaGroupFieldNameList = Lists.newArrayList();
        dataAreaFieldConfigMap.forEach((dataAreaFieldName, dataAreaFieldConfigObj) -> {
            if ("1".equals(dataAreaFieldConfigObj.getString(CmnConst.ATTR_IS_GROUP))) {
                dataAreaGroupFieldNameList.add(dataAreaFieldName);
                if ("1".equals(dataAreaFieldConfigObj.getString(CmnConst.ATTR_IS_STATISTICS))) {
                    dataAreaGroupStatisticsFieldNameList.add(dataAreaFieldName);
                }
            }
        });
//         curRowHtml.setLength(0);
         curRowColumn = new ArrayList<>();
        StringBuilder dataAreaDataHtml = new StringBuilder(1024);
        StringBuilder curRowHtml = new StringBuilder(256);
        FieldSetEntity recordFse;
        FieldSetEntity preFse = null;
        String dataAreaFieldName;
        JSONObject dataAreaFieldConfigObj;
        String value;
        JSONObject keyObj;
        Map<String, String> replaceMap = Maps.newHashMap();
        Map<String, String> dataAreaClosestGroupStatisticsFieldValueMap = Maps.newHashMap();
        Map<String, String> dataAreaClosestGroupFieldValueMap = Maps.newHashMap();
        String closestGroupStatisticsFieldName = null;
        String closestGroupFieldName = null;
        String tempFieldName;
        String paramKey;
        boolean combineFlag;
        JSONObject dataAreaGroupFieldRecordObj = new JSONObject();
        for (int i = 0; i < recordDte.getRows(); i++) {
            recordFse = recordDte.getFieldSetEntity(i);
            // 获取头部、尾部标题区数据字段
            dataListReportService.getHeadAndTailTitleDataMap(headAndTailTitleDataMap, headAndTailFieldSet, recordFse);
         String rowUuid = IdUtil.simpleUUID();
//         curRowHtml.append("\n<tr rowIndex=\"" + (i + 1) + "\" id=\"" + rowUuid + "\" class=\"").append(CmnConst.CLASS_TR_DATA_COMMON).append("\">\n    ");
         combineFlag = true;
         for (Map.Entry<String, JSONObject> entry : dataAreaFieldConfigMap.entrySet()) {
            dataAreaFieldName = entry.getKey();
            dataAreaFieldConfigObj = entry.getValue();
            value = dataListReportService.getValue(dataAreaFieldConfigObj, recordFse, dataAreaFieldName);
            // 若是自定义字段,则放入业务数据记录中
            if ("1".equals(dataAreaFieldConfigObj.getString(CmnConst.ATTR_IS_CUSTOM_FIELD))) {
               recordFse.setValue(dataAreaFieldName, value);
            }
            if (dataAreaGroupFieldNameList.contains(dataAreaFieldName)) {
               int curFieldIndex = dataAreaGroupFieldNameList.indexOf(dataAreaFieldName);
               // 记录分组字段
               recordDataAreaGroupField(dataAreaGroupFieldRecordObj, dataAreaGroupFieldNameList, curFieldIndex, recordFse);
            curRowHtml.setLength(0);
            String rowUuid = IdUtil.simpleUUID();
            curRowHtml.append("\n<tr rowIndex=\"" + (i + 1) + "\" id=\"" + rowUuid + "\" class=\"").append(CmnConst.CLASS_TR_DATA_COMMON).append("\">\n    ");
            combineFlag = true;
            for (Map.Entry<String, JSONObject> entry : dataAreaFieldConfigMap.entrySet()) {
                dataAreaFieldName = entry.getKey();
                dataAreaFieldConfigObj = entry.getValue();
                value = dataListReportService.getValue(dataAreaFieldConfigObj, recordFse, dataAreaFieldName);
                // 若是自定义字段,则放入业务数据记录中
                if ("1".equals(dataAreaFieldConfigObj.getString(CmnConst.ATTR_IS_CUSTOM_FIELD))) {
                    recordFse.setValue(dataAreaFieldName, value);
                }
                if (dataAreaGroupFieldNameList.contains(dataAreaFieldName)) {
                    int curFieldIndex = dataAreaGroupFieldNameList.indexOf(dataAreaFieldName);
                    // 记录分组字段
                    recordDataAreaGroupField(dataAreaGroupFieldRecordObj, dataAreaGroupFieldNameList, curFieldIndex, recordFse);
               // 分组合字段并
               closestGroupFieldName = dataAreaFieldName;
               if (preFse != null && combineFlag) {
                  if (value.equals(dataAreaClosestGroupFieldValueMap.get(closestGroupFieldName))) {
                     dealReplaceMapAddRowspan(replaceMap, dataAreaGroupFieldNameList.subList(0, curFieldIndex + 1), preFse, true);
                     continue;
                  } else {
                     combineFlag = false;
                  }
               }
               dataAreaClosestGroupFieldValueMap.put(dataAreaFieldName, value);
            }
            // 分组统计
            if (dataAreaGroupStatisticsFieldNameList.contains(dataAreaFieldName)) {
               int minK = dataAreaGroupStatisticsFieldNameList.size();
               for (int j = 0; j < dataAreaGroupStatisticsFieldNameList.size(); j++) {
                  tempFieldName = dataAreaGroupStatisticsFieldNameList.get(j);
                  if (!StringUtils.isEmpty(dataAreaClosestGroupStatisticsFieldValueMap.get(tempFieldName)) && !recordFse.getString(tempFieldName).equals(dataAreaClosestGroupStatisticsFieldValueMap.get(tempFieldName))) {
                     minK = j;
                     break;
                  }
               }
               for (int k = dataAreaGroupStatisticsFieldNameList.size() - 1; k >= minK; k--) {
                  tempFieldName = dataAreaGroupStatisticsFieldNameList.get(k);
                  if (preFse != null && dataAreaClosestGroupStatisticsFieldValueMap.get(tempFieldName) != null) {
                     reportColumnList.add(getDataAreaGroupStatisticsFieldStatisticsRow(dataAreaClosestGroupStatisticsFieldValueMap.get(tempFieldName), statisticsMap, dataAreaFieldConfigMap, tempFieldName, preFse, dataAreaGroupFieldNameList, replaceMap, dataAreaGroupFieldRecordObj));
                     dataAreaClosestGroupStatisticsFieldValueMap.remove(tempFieldName);
                  }
               }
               closestGroupStatisticsFieldName = dataAreaFieldName;
               dataAreaClosestGroupStatisticsFieldValueMap.put(dataAreaFieldName, value);
            }
            // 非分组统计字段(普通+自定义)
            if (!"1".equals(dataAreaFieldConfigObj.getString(CmnConst.ATTR_IS_GROUP)) && !StringUtils.isEmpty(dataAreaFieldConfigObj.getString(CmnConst.ATTR_STATISTICS))) {
               addStatisticsRowInfo(statisticsMap, dataAreaGroupStatisticsFieldNameList, recordFse, dataAreaFieldConfigObj, dataAreaFieldName, value);
            }
            // 自定义统计字段(未指定统计类型,使用基础字段公式进行计算)
            if ("1".equals(dataAreaFieldConfigObj.getString(CmnConst.ATTR_IS_CUSTOM_FIELD))
                  && StringUtils.isEmpty(dataAreaFieldConfigObj.getString(CmnConst.ATTR_STATISTICS))
                  && !StringUtils.isEmpty(dataAreaFieldConfigObj.getString(CmnConst.ATTR_FORMULA))) {
               String formula = dataAreaFieldConfigObj.getString(CmnConst.ATTR_FORMULA);
               List<String> formFieldList = dataListReportService.getSuitContent(formula, CmnConst.REGEXP_FORM_FIELD);
               Map<String, String> formulaMap = Maps.newHashMap();
               boolean statisticsFlag = true;
               JSONObject tempObj;
               for (String formFieldInfo : formFieldList) {
                  tempObj = dataAreaFieldConfigMap.get(dataListReportService.fieldInfo2FieldName(formFieldInfo));
                  if (tempObj == null || StringUtils.isEmpty(tempObj.getString(CmnConst.ATTR_STATISTICS))) {
                     statisticsFlag = false;
                     break;
                  }
                  formulaMap.put(formFieldInfo, tempObj.getString(CmnConst.ATTR_STATISTICS));
               }
               if (statisticsFlag) {
                  addStatisticsRowInfo(statisticsMap, dataAreaGroupStatisticsFieldNameList, recordFse, dataAreaFieldConfigObj, dataAreaFieldName, value, formulaMap);
               }
            }
            if ("1".equals(dataAreaFieldConfigObj.getString(CmnConst.ATTR_IS_GROUP))) {
               keyObj = new JSONObject();
               for (String dataAreaGroupFieldName : dataAreaGroupFieldNameList) {
                  keyObj.put(dataAreaGroupFieldName, recordFse.getString(dataAreaGroupFieldName));
                  if (dataAreaGroupFieldName.equals(dataAreaFieldName)) {
                     keyObj.put(CmnConst.ATTR_FIELD_INFO, dataListReportService.fieldName2FieldInfo(dataAreaGroupFieldName));
                     break;
                  }
               }
               paramKey = dataListReportService.concat(keyObj, CmnConst.ATTR_ROWSPAN);
//               curRowHtml.append("<td rowspan=\"").append(paramKey).append("\"");
               currentColumn.setRowspan(paramKey);
               replaceMap.put(paramKey, "1");
            }
//            else {
//               curRowHtml.append("<td");
//            }
            // class
            if (!StringUtils.isEmpty(dataAreaFieldConfigObj.getString(CmnConst.ATTR_URL))) {
               currentColumn.setSubReport("true".equals(dataAreaFieldConfigObj.getString("~isSubReport~")));
               if (!currentColumn.isSubReport()) {
                  currentColumn.setPenetrate(true);
                  currentColumn.setPenetrateProperty(dataAreaFieldConfigObj.getString(CmnConst.ATTR_URL));
               } else {
                  currentColumn.setSubReportProperty(dataAreaFieldConfigObj.getString(CmnConst.ATTR_URL));
               }
//               curRowHtml.append(" class=\"").append(CmnConst.CLASS_TD_CAN_TURN).append("true".equals(dataAreaFieldConfigObj.getString("~isSubReport~")) ? "\"skipSubReport=true" : "\"").append(" router=\"").append(dataAreaFieldConfigObj.getString(CmnConst.ATTR_URL)).append("\"");
            }
            String attrValue = recordFse.getString(dataAreaFieldName + CmnConst.PROMPT_REAL_VALUE_TAIL);
            if (StringUtils.isEmpty(attrValue)) {
               attrValue = recordFse.getString(dataAreaFieldName);
            }
            if (!dataAreaFieldName.matches("\\d+")) {
               currentColumn.addProperty(dataAreaFieldName, attrValue);
//               curRowHtml.append(" ").append(dataAreaFieldName).append("=\"").append(attrValue).append("\"");
            }
            // 解析穿透参数
            String urlParam = dataAreaFieldConfigObj.getString(CmnConst.ATTR_URL_PARAM);
            String attrParam;
            if (!StringUtils.isEmpty(urlParam)) {
               List<String> suitFieldList = BaseUtil.getSuitContent(urlParam, "\\{#\\w+#\\}");
               for (String singleSuitFieldName : suitFieldList) {
                  attrParam = singleSuitFieldName.substring(2, singleSuitFieldName.length() - 2);
                  currentColumn.addProperty(attrParam, recordFse.getString(attrParam));
//                  curRowHtml.append(" ").append(attrParam).append("=\"").append(recordFse.getString(attrParam)).append("\"");
               }
            }
//            curRowHtml.append(">");
            // 格式
            value = dataListReportService.formatValue(dataAreaFieldConfigObj, value);
//            curRowHtml.append(value == null ? "" : value);
//            curRowHtml.append("</td>");
            currentColumn.setContent(value);
            curRowColumn.add(currentColumn);
            currentColumn = new ReportColumn();
         }
//         curRowHtml.append("\n</tr>");
//         dataAreaDataHtml.append(curRowHtml);
         reportColumnList.add(curRowColumn);
         preFse = recordFse;
      }
                    // 分组合字段并
                    closestGroupFieldName = dataAreaFieldName;
                    if (preFse != null && combineFlag) {
                        if (value.equals(dataAreaClosestGroupFieldValueMap.get(closestGroupFieldName))) {
                            dealReplaceMapAddRowspan(replaceMap, dataAreaGroupFieldNameList.subList(0, curFieldIndex + 1), preFse, true);
                            continue;
                        } else {
                            combineFlag = false;
                        }
                    }
                    dataAreaClosestGroupFieldValueMap.put(dataAreaFieldName, value);
                }
                // 分组统计
                if (dataAreaGroupStatisticsFieldNameList.contains(dataAreaFieldName)) {
                    int minK = dataAreaGroupStatisticsFieldNameList.size();
                    for (int j = 0; j < dataAreaGroupStatisticsFieldNameList.size(); j++) {
                        tempFieldName = dataAreaGroupStatisticsFieldNameList.get(j);
                        if (!StringUtils.isEmpty(dataAreaClosestGroupStatisticsFieldValueMap.get(tempFieldName)) && !recordFse.getString(tempFieldName).equals(dataAreaClosestGroupStatisticsFieldValueMap.get(tempFieldName))) {
                            minK = j;
                            break;
                        }
                    }
                    for (int k = dataAreaGroupStatisticsFieldNameList.size() - 1; k >= minK; k--) {
                        tempFieldName = dataAreaGroupStatisticsFieldNameList.get(k);
                        if (preFse != null && dataAreaClosestGroupStatisticsFieldValueMap.get(tempFieldName) != null) {
                            dataAreaDataHtml.append(getDataAreaGroupStatisticsFieldStatisticsRowHtml(dataAreaClosestGroupStatisticsFieldValueMap.get(tempFieldName), statisticsMap, dataAreaFieldConfigMap, tempFieldName, preFse, dataAreaGroupFieldNameList, replaceMap, dataAreaGroupFieldRecordObj));
                            dataAreaClosestGroupStatisticsFieldValueMap.remove(tempFieldName);
                        }
                    }
                    closestGroupStatisticsFieldName = dataAreaFieldName;
                    dataAreaClosestGroupStatisticsFieldValueMap.put(dataAreaFieldName, value);
                }
                // 非分组统计字段(普通+自定义)
                if (!"1".equals(dataAreaFieldConfigObj.getString(CmnConst.ATTR_IS_GROUP)) && !StringUtils.isEmpty(dataAreaFieldConfigObj.getString(CmnConst.ATTR_STATISTICS))) {
                    addStatisticsRowInfo(statisticsMap, dataAreaGroupStatisticsFieldNameList, recordFse, dataAreaFieldConfigObj, dataAreaFieldName, value);
                }
                // 自定义统计字段(未指定统计类型,使用基础字段公式进行计算)
                if ("1".equals(dataAreaFieldConfigObj.getString(CmnConst.ATTR_IS_CUSTOM_FIELD))
                        && StringUtils.isEmpty(dataAreaFieldConfigObj.getString(CmnConst.ATTR_STATISTICS))
                        && !StringUtils.isEmpty(dataAreaFieldConfigObj.getString(CmnConst.ATTR_FORMULA))) {
                    String formula = dataAreaFieldConfigObj.getString(CmnConst.ATTR_FORMULA);
                    List<String> formFieldList = dataListReportService.getSuitContent(formula, CmnConst.REGEXP_FORM_FIELD);
                    Map<String, String> formulaMap = Maps.newHashMap();
                    boolean statisticsFlag = true;
                    JSONObject tempObj;
                    for (String formFieldInfo : formFieldList) {
                        tempObj = dataAreaFieldConfigMap.get(dataListReportService.fieldInfo2FieldName(formFieldInfo));
                        if (tempObj == null || StringUtils.isEmpty(tempObj.getString(CmnConst.ATTR_STATISTICS))) {
                            statisticsFlag = false;
                            break;
                        }
                        formulaMap.put(formFieldInfo, tempObj.getString(CmnConst.ATTR_STATISTICS));
                    }
                    if (statisticsFlag) {
                        addStatisticsRowInfo(statisticsMap, dataAreaGroupStatisticsFieldNameList, recordFse, dataAreaFieldConfigObj, dataAreaFieldName, value, formulaMap);
                    }
                }
                if ("1".equals(dataAreaFieldConfigObj.getString(CmnConst.ATTR_IS_GROUP))) {
                    keyObj = new JSONObject();
                    for (String dataAreaGroupFieldName : dataAreaGroupFieldNameList) {
                        keyObj.put(dataAreaGroupFieldName, recordFse.getString(dataAreaGroupFieldName));
                        if (dataAreaGroupFieldName.equals(dataAreaFieldName)) {
                            keyObj.put(CmnConst.ATTR_FIELD_INFO, dataListReportService.fieldName2FieldInfo(dataAreaGroupFieldName));
                            break;
                        }
                    }
                    paramKey = dataListReportService.concat(keyObj, CmnConst.ATTR_ROWSPAN);
                    curRowHtml.append("<td rowspan=\"").append(paramKey).append("\"");
                    replaceMap.put(paramKey, "1");
                } else {
                    curRowHtml.append("<td");
                }
                // class
                if (!StringUtils.isEmpty(dataAreaFieldConfigObj.getString(CmnConst.ATTR_URL))) {
                    curRowHtml.append(" class=\"").append(CmnConst.CLASS_TD_CAN_TURN).append("true".equals(dataAreaFieldConfigObj.getString("~isSubReport~")) ? "\"skipSubReport=true" : "\"").append(" router=\"").append(dataAreaFieldConfigObj.getString(CmnConst.ATTR_URL)).append("\"");
                }
                String attrValue = recordFse.getString(dataAreaFieldName + CmnConst.PROMPT_REAL_VALUE_TAIL);
                if (StringUtils.isEmpty(attrValue)) {
                    attrValue = recordFse.getString(dataAreaFieldName);
                }
                curRowHtml.append(" ").append(dataAreaFieldName).append("=\"").append(attrValue).append("\"");
                curRowHtml.append(">");
                // 格式
                value = dataListReportService.formatValue(dataAreaFieldConfigObj, value);
                curRowHtml.append(value == null ? "" : value);
                curRowHtml.append("</td>");
            }
            curRowHtml.append("\n</tr>");
            dataAreaDataHtml.append(curRowHtml);
            preFse = recordFse;
        }
      // 补全末尾统计
      if (!StringUtils.isEmpty(closestGroupStatisticsFieldName)) {
         int maxK = -1;
         for (int j = 0; j < dataAreaGroupStatisticsFieldNameList.size(); j++) {
            tempFieldName = dataAreaGroupStatisticsFieldNameList.get(j);
            if (closestGroupStatisticsFieldName.equals(tempFieldName)) {
               maxK = j;
            }
         }
         for (int k = maxK; k >= 0; k--) {
            tempFieldName = dataAreaGroupStatisticsFieldNameList.get(k);
            if (preFse != null) {
               reportColumnList.add(getDataAreaGroupStatisticsFieldStatisticsRow(dataAreaClosestGroupStatisticsFieldValueMap.get(tempFieldName), statisticsMap, dataAreaFieldConfigMap, tempFieldName, preFse, dataAreaGroupFieldNameList, replaceMap, dataAreaGroupFieldRecordObj));
            }
         }
      }
        // 补全末尾统计
        if (!StringUtils.isEmpty(closestGroupStatisticsFieldName)) {
            int maxK = -1;
            for (int j = 0; j < dataAreaGroupStatisticsFieldNameList.size(); j++) {
                tempFieldName = dataAreaGroupStatisticsFieldNameList.get(j);
                if (closestGroupStatisticsFieldName.equals(tempFieldName)) {
                    maxK = j;
                }
            }
            for (int k = maxK; k >= 0; k--) {
                tempFieldName = dataAreaGroupStatisticsFieldNameList.get(k);
                if (preFse != null) {
                    dataAreaDataHtml.append(getDataAreaGroupStatisticsFieldStatisticsRowHtml(dataAreaClosestGroupStatisticsFieldValueMap.get(tempFieldName), statisticsMap, dataAreaFieldConfigMap, tempFieldName, preFse, dataAreaGroupFieldNameList, replaceMap, dataAreaGroupFieldRecordObj));
                }
            }
        }
      // 总计
      if (!StringUtils.isEmpty(totalName)) {
         List<ReportColumn> reportColumns = getDataAreaTotalStatisticsRow(statisticsMap, dataAreaFieldConfigMap, dataAreaGroupFieldNameList, preFse, dataAreaGroupFieldRecordObj, totalName);
         if (reportColumns != null && reportColumns.size() > 0) {
            reportColumnList.add(reportColumns);
         }
      }
      //循环所有的column进行参数替换
      for (List<ReportColumn> reportColumns : reportColumnList) {
         if (reportColumns != null) {
            for (ReportColumn reportColumn : reportColumns) {
               if (reportColumn != null) {
        // 总计
        if (!StringUtils.isEmpty(totalName)) {
            dataAreaDataHtml.append(getDataAreaTotalStatisticsHtml(statisticsMap, dataAreaFieldConfigMap, dataAreaGroupFieldNameList, preFse, dataAreaGroupFieldRecordObj, totalName));
        }
                  for (Map.Entry<String, String> entry : replaceMap.entrySet()) {
                     reportColumn.replace(entry.getKey(), entry.getValue());
                  }
               }
            }
        String str = dataAreaDataHtml.toString();
        for (Map.Entry<String, String> entry : replaceMap.entrySet()) {
            str = str.replace(entry.getKey(), entry.getValue());
        }
         }
      }
        return str;
    }
      return reportColumnList;
   }
    /**
     * 添加分组统计信息
     * @param statisticsMap                         统计map
     * @param dataAreaGroupStatisticsFieldNameList  数据区分组统计字段名称list
     * @param recordFse                             业务数据fse
     * @param dataAreaFieldConfigObj                数据区字段obj
     * @param dataAreaFieldName                     数据区字段名称
     * @param value                                 值
     * @param formulaMap                            公式map,字段info和统计类型的映射
     */
    private void addStatisticsRowInfo(Map<JSONObject, JSONObject> statisticsMap, List<String> dataAreaGroupStatisticsFieldNameList, FieldSetEntity recordFse, JSONObject dataAreaFieldConfigObj, String dataAreaFieldName, String value, Map<String, String> formulaMap) {
        JSONObject keyObj = new JSONObject();
        keyObj.put(CmnConst.ATTR_FIELD_INFO, dataListReportService.fieldName2FieldInfo(dataAreaFieldName));
        String statisticsType = dataAreaFieldConfigObj.getString(CmnConst.ATTR_STATISTICS);
        if (StringUtils.isEmpty(statisticsType) && "1".equals(dataAreaFieldConfigObj.getString(CmnConst.ATTR_IS_STATISTICS))) {
            statisticsType = CmnConst.ATTR_STATISTICS_DEFAULT;
        }
        String statisticsValue;
        String formula = dataAreaFieldConfigObj.getString(CmnConst.ATTR_FORMULA);
        JSONObject formulaFieldKeyObj = new JSONObject();
        // 总计
        JSONObject cloneKeyObj = (JSONObject) keyObj.clone();
        JSONObject valueObj = statisticsMap.computeIfAbsent(cloneKeyObj, k -> new JSONObject());
        statisticsValue = getStatisticsValue(statisticsMap, formulaMap, formulaFieldKeyObj, formula, value);
        statisticsMap.put(keyObj, dataListReportService.getStatisticsValueObj(valueObj, dataAreaFieldConfigObj, statisticsValue, statisticsType, true));
        // 分组统计
        for (String dataAreaGroupStatisticsFieldName : dataAreaGroupStatisticsFieldNameList) {
            keyObj.put(dataAreaGroupStatisticsFieldName, recordFse.getString(dataAreaGroupStatisticsFieldName));
            formulaFieldKeyObj.put(dataAreaGroupStatisticsFieldName, recordFse.getString(dataAreaGroupStatisticsFieldName));
            cloneKeyObj = (JSONObject) keyObj.clone();
            valueObj = statisticsMap.computeIfAbsent(cloneKeyObj, k -> new JSONObject());
            statisticsValue = getStatisticsValue(statisticsMap, formulaMap, formulaFieldKeyObj, formula, value);
            statisticsMap.put(keyObj, dataListReportService.getStatisticsValueObj(valueObj, dataAreaFieldConfigObj, statisticsValue, statisticsType, true));
        }
    }
    private void addStatisticsRowInfo(Map<JSONObject, JSONObject> statisticsMap, List<String> dataAreaGroupStatisticsFieldNameList, FieldSetEntity recordFse, JSONObject dataAreaFieldConfigObj, String dataAreaFieldName, String value) {
        addStatisticsRowInfo(statisticsMap, dataAreaGroupStatisticsFieldNameList, recordFse, dataAreaFieldConfigObj, dataAreaFieldName, value, null);
    }
   /**
    * 添加分组统计信息
    *
    * @param statisticsMap                        统计map
    * @param dataAreaGroupStatisticsFieldNameList 数据区分组统计字段名称list
    * @param recordFse                            业务数据fse
    * @param dataAreaFieldConfigObj               数据区字段obj
    * @param dataAreaFieldName                    数据区字段名称
    * @param value                                值
    * @param formulaMap                           公式map,字段info和统计类型的映射
    */
   private void addStatisticsRowInfo(Map<JSONObject, JSONObject> statisticsMap, List<String> dataAreaGroupStatisticsFieldNameList, FieldSetEntity recordFse, JSONObject dataAreaFieldConfigObj, String dataAreaFieldName, String value, Map<String, String> formulaMap) {
      JSONObject keyObj = new JSONObject();
      keyObj.put(CmnConst.ATTR_FIELD_INFO, dataListReportService.fieldName2FieldInfo(dataAreaFieldName));
      String statisticsType = dataAreaFieldConfigObj.getString(CmnConst.ATTR_STATISTICS);
      if (StringUtils.isEmpty(statisticsType) && "1".equals(dataAreaFieldConfigObj.getString(CmnConst.ATTR_IS_STATISTICS))) {
         statisticsType = CmnConst.ATTR_STATISTICS_DEFAULT;
      }
      String statisticsValue;
      String formula = dataAreaFieldConfigObj.getString(CmnConst.ATTR_FORMULA);
      JSONObject formulaFieldKeyObj = new JSONObject();
      // 总计
      JSONObject cloneKeyObj = (JSONObject) keyObj.clone();
      JSONObject valueObj = statisticsMap.computeIfAbsent(cloneKeyObj, k -> new JSONObject());
      statisticsValue = getStatisticsValue(statisticsMap, formulaMap, formulaFieldKeyObj, formula, value);
      statisticsMap.put(keyObj, dataListReportService.getStatisticsValueObj(valueObj, dataAreaFieldConfigObj, statisticsValue, statisticsType, true));
      // 分组统计
      for (String dataAreaGroupStatisticsFieldName : dataAreaGroupStatisticsFieldNameList) {
         keyObj.put(dataAreaGroupStatisticsFieldName, recordFse.getString(dataAreaGroupStatisticsFieldName));
         formulaFieldKeyObj.put(dataAreaGroupStatisticsFieldName, recordFse.getString(dataAreaGroupStatisticsFieldName));
         cloneKeyObj = (JSONObject) keyObj.clone();
         valueObj = statisticsMap.computeIfAbsent(cloneKeyObj, k -> new JSONObject());
         statisticsValue = getStatisticsValue(statisticsMap, formulaMap, formulaFieldKeyObj, formula, value);
         statisticsMap.put(keyObj, dataListReportService.getStatisticsValueObj(valueObj, dataAreaFieldConfigObj, statisticsValue, statisticsType, true));
      }
   }
    /**
     * 获取统计行的公式计算值
     * @param statisticsMap         统计map
     * @param formulaMap            公式map
     * @param formulaFieldKeyObj    公式字段keyobj
     * @param formula               公式
     * @param value                 原本的值
     * @return
     */
    private String getStatisticsValue(Map<JSONObject, JSONObject> statisticsMap, Map<String, String> formulaMap, JSONObject formulaFieldKeyObj, String formula, String value) {
        String statisticsValue = "";
        String formulaFieldValue;
        if (formulaMap != null && !formulaMap.isEmpty()) {
            for (Map.Entry<String, String> entry : formulaMap.entrySet()) {
                formulaFieldKeyObj.put(CmnConst.ATTR_FIELD_INFO, entry.getKey());
                formulaFieldValue = statisticsMap.get(formulaFieldKeyObj).getString(entry.getValue());
                if (formulaFieldValue != null && formulaFieldValue.matches(CmnConst.REGEXP_NUMBER)) {
                    formulaFieldValue += "d";
                }
                formula = formula.replace(entry.getKey(),  StringUtils.isEmpty(formulaFieldValue) ? "" : formulaFieldValue);
            }
            try {
                statisticsValue = BaseUtil.executeExpression(formula, Maps.newHashMap()).toString();
            } catch (Exception e) {
                SpringMVCContextHolder.getSystemLogger().error(e);
                statisticsValue = "";
            }
        }
        return StringUtils.isEmpty(statisticsValue) ? value : statisticsValue;
    }
   private void addStatisticsRowInfo(Map<JSONObject, JSONObject> statisticsMap, List<String> dataAreaGroupStatisticsFieldNameList, FieldSetEntity recordFse, JSONObject dataAreaFieldConfigObj, String dataAreaFieldName, String value) {
      addStatisticsRowInfo(statisticsMap, dataAreaGroupStatisticsFieldNameList, recordFse, dataAreaFieldConfigObj, dataAreaFieldName, value, null);
   }
    /**
     * 获取数据区分组统计字段统计行html
     *
     * @param waitStatisticsValue         待统计的值
     * @param statisticsMap               统计map
     * @param dataAreaFieldConfigMap      数据区字段缓存map
     * @param tempFieldName               本次操作的字段名称
     * @param recordFse                   业务数据记录
     * @param dataAreaGroupFieldNameList  数据区分组字段名称list
     * @param replaceMap                  替换map
     * @param dataAreaGroupFieldRecordObj 数据区分组字段记录obj
     * @return
     */
    private StringBuilder getDataAreaGroupStatisticsFieldStatisticsRowHtml(String waitStatisticsValue, Map<JSONObject, JSONObject> statisticsMap, Map<String, JSONObject> dataAreaFieldConfigMap,
                                                                           String tempFieldName, FieldSetEntity recordFse, List<String> dataAreaGroupFieldNameList, Map<String, String> replaceMap, JSONObject dataAreaGroupFieldRecordObj) {
        StringBuilder html = new StringBuilder();
        html.append("\n<tr class=\"").append(CmnConst.CLASS_TR_DATA_STATISTICS).append("\">\n    ");
        String dataAreaFieldName;
        JSONObject dataAreaFieldConfigObj;
        boolean flag = false;
        JSONObject keyObj = new JSONObject();
        String value;
        String statisticsType;
        int index = 0;
        List<String> needAddRowspanDataAreaGroupFieldNameList = Lists.newArrayList();
        for (Map.Entry<String, JSONObject> entry : dataAreaFieldConfigMap.entrySet()) {
            index++;
            dataAreaFieldName = entry.getKey();
            if (!flag) {
                if (dataAreaGroupFieldNameList.contains(dataAreaFieldName)) {
                    keyObj.put(dataAreaFieldName, recordFse.getString(dataAreaFieldName));
                    if (dataAreaFieldName.equals(tempFieldName)) {
                        html.append("<td colspan=\"").append(dataAreaGroupFieldNameList.size() - index + 1).append("\">").append(waitStatisticsValue).append(CmnConst.STATISTICS_NAME).append("</td>");
                        flag = true;
                    }
                    if (!flag) {
                        needAddRowspanDataAreaGroupFieldNameList.add(dataAreaFieldName);
                    }
                }
            } else {
                dataAreaFieldConfigObj = entry.getValue();
                statisticsType = dataAreaFieldConfigObj.getString(CmnConst.ATTR_STATISTICS);
                if (!"1".equals(dataAreaFieldConfigObj.getString(CmnConst.ATTR_IS_CUSTOM_FIELD)) && StringUtils.isEmpty(statisticsType)) {
                    if (!"1".equals(dataAreaFieldConfigObj.getString(CmnConst.ATTR_IS_GROUP))) {
                        html.append("<td></td>");
                    }
                } else {
                    keyObj.put(CmnConst.ATTR_FIELD_INFO, dataListReportService.fieldName2FieldInfo(dataAreaFieldName));
                    if (statisticsMap.get(keyObj) == null) {
                        value = "";
                    } else {
                        JSONObject valueObj = statisticsMap.get(keyObj);
                        if (StringUtils.isEmpty(statisticsType)) {
                            statisticsType = CmnConst.ATTR_STATISTICS_DEFAULT;
                        }
                        if (CmnConst.ATTR_STATISTICS_AVG.equals(statisticsType) && "1".equals(dataAreaFieldConfigObj.getString(CmnConst.ATTR_AVG_TYPE))) {
                            int subCnt = getAimSubCnt(keyObj, dataAreaGroupFieldNameList, dataAreaGroupFieldRecordObj);
                            valueObj.put(CmnConst.ATTR_STATISTICS_SUB_CNT, subCnt);
                            dataListReportService.getAvgValue(valueObj, dataAreaFieldConfigObj, false);
                        }
                        value = valueObj.getString(statisticsType);
                    }
                    // 格式
                    value = dataListReportService.formatValue(dataAreaFieldConfigObj, value);
                    html.append("<td>").append(value == null ? "" : value).append("</td>");
                }
            }
        }
        html.append("\n</tr>");
        dealReplaceMapAddRowspan(replaceMap, needAddRowspanDataAreaGroupFieldNameList, recordFse, false);
        return html;
    }
   /**
    * 获取统计行的公式计算值
    *
    * @param statisticsMap      统计map
    * @param formulaMap         公式map
    * @param formulaFieldKeyObj 公式字段keyobj
    * @param formula            公式
    * @param value              原本的值
    * @return
    */
   private String getStatisticsValue(Map<JSONObject, JSONObject> statisticsMap, Map<String, String> formulaMap, JSONObject formulaFieldKeyObj, String formula, String value) {
      String statisticsValue = "";
      String formulaFieldValue;
      if (formulaMap != null && !formulaMap.isEmpty()) {
         for (Map.Entry<String, String> entry : formulaMap.entrySet()) {
            formulaFieldKeyObj.put(CmnConst.ATTR_FIELD_INFO, entry.getKey());
            formulaFieldValue = statisticsMap.get(formulaFieldKeyObj).getString(entry.getValue());
            if (formulaFieldValue != null && formulaFieldValue.matches(CmnConst.REGEXP_NUMBER)) {
               formulaFieldValue += "d";
            }
            formula = formula.replace(entry.getKey(), StringUtils.isEmpty(formulaFieldValue) ? "" : formulaFieldValue);
         }
         try {
            statisticsValue = BaseUtil.executeExpression(formula, Maps.newHashMap()).toString();
         } catch (Exception e) {
            SpringMVCContextHolder.getSystemLogger().error(e);
            statisticsValue = "";
         }
      }
      return StringUtils.isEmpty(statisticsValue) ? value : statisticsValue;
   }
    /**
     * 获取总计html
     *
     * @param statisticsMap               统计map
     * @param dataAreaFieldConfigMap      数据区字段缓存map
     * @param dataAreaGroupFieldNameList  数据区分组字段名称list
     * @param preFse                      最近操作的数据fse
     * @param dataAreaGroupFieldRecordObj 数据区分组字段记录obj
     * @param totalName                   总计名称
     * @return
     */
    private String getDataAreaTotalStatisticsHtml(Map<JSONObject, JSONObject> statisticsMap, Map<String, JSONObject> dataAreaFieldConfigMap, List<String> dataAreaGroupFieldNameList, FieldSetEntity preFse, JSONObject dataAreaGroupFieldRecordObj, String totalName) {
        StringBuilder html = new StringBuilder(512);
        String dataAreaFieldName;
        JSONObject dataAreaFieldConfigObj;
        String value;
        JSONObject keyObj = new JSONObject();
        String statisticsType;
        html.append("\n<tr class=\"").append(CmnConst.CLASS_TR_DATA_STATISTICS).append("\">\n    ");
        if (preFse == null) {
            return html.toString();
        }
        int index = 0;
        for (Map.Entry<String, JSONObject> entry : dataAreaFieldConfigMap.entrySet()) {
            index++;
            dataAreaFieldName = entry.getKey();
            if (!dataAreaGroupFieldNameList.contains(dataAreaFieldName)) {
                dataAreaFieldConfigObj = entry.getValue();
                statisticsType = dataAreaFieldConfigObj.getString(CmnConst.ATTR_STATISTICS);
                keyObj.put(CmnConst.ATTR_FIELD_INFO, dataAreaFieldConfigObj.getString(CmnConst.ATTR_FIELD_INFO));
                if ((!"1".equals(dataAreaFieldConfigObj.getString(CmnConst.ATTR_IS_CUSTOM_FIELD)) && StringUtils.isEmpty(statisticsType)) || statisticsMap.get(keyObj) == null) {
                    value = "";
                } else {
                    JSONObject valueObj = statisticsMap.get(keyObj);
                    if (StringUtils.isEmpty(statisticsType)) {
                        statisticsType = CmnConst.ATTR_STATISTICS_DEFAULT;
                    }
                    if (CmnConst.ATTR_STATISTICS_AVG.equals(statisticsType) && "1".equals(dataAreaFieldConfigObj.getString(CmnConst.ATTR_AVG_TYPE))) {
                        int subCnt = dataAreaGroupFieldRecordObj.size();
                        valueObj.put(CmnConst.ATTR_STATISTICS_SUB_CNT, subCnt);
                        dataListReportService.getAvgValue(valueObj, dataAreaFieldConfigObj, false);
                    }
                    value = valueObj.getString(statisticsType);
                }
                // 格式
                value = dataListReportService.formatValue(dataAreaFieldConfigObj, value);
                html.append("<td>").append(value == null ? "" : value).append("</td>");
            } else {
                if (index == 1) {
                    html.append("<td colspan=\"").append(dataAreaGroupFieldNameList.size()).append("\">").append(totalName).append("</td>");
                }
            }
        }
        html.append("\n</tr>");
        return html.toString();
    }
   /**
    * 获取数据区分组统计字段统计行html
    *
    * @param waitStatisticsValue         待统计的值
    * @param statisticsMap               统计map
    * @param dataAreaFieldConfigMap      数据区字段缓存map
    * @param tempFieldName               本次操作的字段名称
    * @param recordFse                   业务数据记录
    * @param dataAreaGroupFieldNameList  数据区分组字段名称list
    * @param replaceMap                  替换map
    * @param dataAreaGroupFieldRecordObj 数据区分组字段记录obj
    * @return
    */
   private List<ReportColumn> getDataAreaGroupStatisticsFieldStatisticsRow(String waitStatisticsValue, Map<JSONObject, JSONObject> statisticsMap, Map<String, JSONObject> dataAreaFieldConfigMap,
                                                         String tempFieldName, FieldSetEntity recordFse, List<String> dataAreaGroupFieldNameList, Map<String, String> replaceMap, JSONObject dataAreaGroupFieldRecordObj) {
      List<ReportColumn> columnRow = new ArrayList<>();
      String dataAreaFieldName;
      JSONObject dataAreaFieldConfigObj;
      boolean flag = false;
      JSONObject keyObj = new JSONObject();
      String value;
      String statisticsType;
      int index = 0;
      List<String> needAddRowspanDataAreaGroupFieldNameList = Lists.newArrayList();
      for (Map.Entry<String, JSONObject> entry : dataAreaFieldConfigMap.entrySet()) {
         index++;
         dataAreaFieldName = entry.getKey();
         if (!flag) {
            if (dataAreaGroupFieldNameList.contains(dataAreaFieldName)) {
               keyObj.put(dataAreaFieldName, recordFse.getString(dataAreaFieldName));
               if (dataAreaFieldName.equals(tempFieldName)) {
                  ReportColumn column = new ReportColumn();
                  column.setColspan(dataAreaGroupFieldNameList.size() - index + 1);
                  column.setContent(waitStatisticsValue);
//                  html.append("<td colspan=\"").append(dataAreaGroupFieldNameList.size() - index + 1).append("\">").append(waitStatisticsValue).append(CmnConst.STATISTICS_NAME).append("</td>");
                  flag = true;
                  columnRow.add(column);
               }
               if (!flag) {
                  needAddRowspanDataAreaGroupFieldNameList.add(dataAreaFieldName);
               }
            }
         } else {
            dataAreaFieldConfigObj = entry.getValue();
            statisticsType = dataAreaFieldConfigObj.getString(CmnConst.ATTR_STATISTICS);
            if (!"1".equals(dataAreaFieldConfigObj.getString(CmnConst.ATTR_IS_CUSTOM_FIELD)) && StringUtils.isEmpty(statisticsType)) {
               if (!"1".equals(dataAreaFieldConfigObj.getString(CmnConst.ATTR_IS_GROUP))) {
//                  html.append("<td></td>");
                  columnRow.add(new ReportColumn());
               }
            } else {
               keyObj.put(CmnConst.ATTR_FIELD_INFO, dataListReportService.fieldName2FieldInfo(dataAreaFieldName));
               if (statisticsMap.get(keyObj) == null) {
                  value = "";
               } else {
                  JSONObject valueObj = statisticsMap.get(keyObj);
                  if (StringUtils.isEmpty(statisticsType)) {
                     statisticsType = CmnConst.ATTR_STATISTICS_DEFAULT;
                  }
                  if (CmnConst.ATTR_STATISTICS_AVG.equals(statisticsType) && "1".equals(dataAreaFieldConfigObj.getString(CmnConst.ATTR_AVG_TYPE))) {
                     int subCnt = getAimSubCnt(keyObj, dataAreaGroupFieldNameList, dataAreaGroupFieldRecordObj);
                     valueObj.put(CmnConst.ATTR_STATISTICS_SUB_CNT, subCnt);
                     dataListReportService.getAvgValue(valueObj, dataAreaFieldConfigObj, false);
                  }
                  value = valueObj.getString(statisticsType);
               }
               // 格式
               value = dataListReportService.formatValue(dataAreaFieldConfigObj, value);
//               html.append("<td>").append(value == null ? "" : value).append("</td>");
               columnRow.add(new ReportColumn(value == null ? "" : value));
            }
         }
      }
      dealReplaceMapAddRowspan(replaceMap, needAddRowspanDataAreaGroupFieldNameList, recordFse, false);
      return columnRow;
   }
    /**
     * 处理参数替换map-添加数据区分组字段的占行
     *
     * @param replaceMap                            替换map
     * @param needAddRowspanDataAreaGroupFieldNames 需要添加占行的数据区分组字段名称集合
     * @param recordFse                             业务数据记录
     */
    private void dealReplaceMapAddRowspan(Map<String, String> replaceMap, Collection<String> needAddRowspanDataAreaGroupFieldNames, FieldSetEntity recordFse, boolean commonFieldFlag) {
        JSONObject keyObj = new JSONObject();
        String value;
        int rowspan;
        String paramKey;
        int index = 0;
        for (String fieldName : needAddRowspanDataAreaGroupFieldNames) {
            index++;
            keyObj.put(fieldName, recordFse.getString(fieldName));
            if (commonFieldFlag && index != needAddRowspanDataAreaGroupFieldNames.size()) {
                continue;
            }
            keyObj.put(CmnConst.ATTR_FIELD_INFO, dataListReportService.fieldName2FieldInfo(fieldName));
            paramKey = dataListReportService.concat(keyObj, CmnConst.ATTR_ROWSPAN);
            value = replaceMap.get(paramKey);
            rowspan = StringUtils.isEmpty(value) ? 1 : Integer.parseInt(value) + 1;
            replaceMap.put(paramKey, String.valueOf(rowspan));
        }
    }
   /**
    * 获取总计html
    *
    * @param statisticsMap               统计map
    * @param dataAreaFieldConfigMap      数据区字段缓存map
    * @param dataAreaGroupFieldNameList  数据区分组字段名称list
    * @param preFse                      最近操作的数据fse
    * @param dataAreaGroupFieldRecordObj 数据区分组字段记录obj
    * @param totalName                   总计名称
    * @return
    */
   private List<ReportColumn> getDataAreaTotalStatisticsRow(Map<JSONObject, JSONObject> statisticsMap, Map<String, JSONObject> dataAreaFieldConfigMap, List<String> dataAreaGroupFieldNameList, FieldSetEntity preFse, JSONObject dataAreaGroupFieldRecordObj, String totalName) {
      List<ReportColumn> reportColumns = new ArrayList<>();
      String dataAreaFieldName;
      JSONObject dataAreaFieldConfigObj;
      String value;
      JSONObject keyObj = new JSONObject();
      String statisticsType;
//      html.append("\n<tr class=\"").append(CmnConst.CLASS_TR_DATA_STATISTICS).append("\">\n    ");
      if (preFse == null) {
         return null;
      }
      int index = 0;
      for (Map.Entry<String, JSONObject> entry : dataAreaFieldConfigMap.entrySet()) {
         index++;
         dataAreaFieldName = entry.getKey();
         if (!dataAreaGroupFieldNameList.contains(dataAreaFieldName)) {
            dataAreaFieldConfigObj = entry.getValue();
            statisticsType = dataAreaFieldConfigObj.getString(CmnConst.ATTR_STATISTICS);
            keyObj.put(CmnConst.ATTR_FIELD_INFO, dataAreaFieldConfigObj.getString(CmnConst.ATTR_FIELD_INFO));
            if ((!"1".equals(dataAreaFieldConfigObj.getString(CmnConst.ATTR_IS_CUSTOM_FIELD)) && StringUtils.isEmpty(statisticsType)) || statisticsMap.get(keyObj) == null) {
               value = "";
            } else {
               JSONObject valueObj = statisticsMap.get(keyObj);
               if (StringUtils.isEmpty(statisticsType)) {
                  statisticsType = CmnConst.ATTR_STATISTICS_DEFAULT;
               }
               if (CmnConst.ATTR_STATISTICS_AVG.equals(statisticsType) && "1".equals(dataAreaFieldConfigObj.getString(CmnConst.ATTR_AVG_TYPE))) {
                  int subCnt = dataAreaGroupFieldRecordObj.size();
                  valueObj.put(CmnConst.ATTR_STATISTICS_SUB_CNT, subCnt);
                  dataListReportService.getAvgValue(valueObj, dataAreaFieldConfigObj, false);
               }
               value = valueObj.getString(statisticsType);
            }
            // 格式
            value = dataListReportService.formatValue(dataAreaFieldConfigObj, value);
            reportColumns.add(new ReportColumn(value == null ? "" : value));
         } else {
            if (index == 1) {
               ReportColumn column = new ReportColumn();
               column.setColspan(dataAreaGroupFieldNameList.size());
               column.setContent(totalName);
               reportColumns.add(column);
            }
         }
      }
      return reportColumns;
   }
    /**
     * 记录分组字段
     *
     * @param dataAreaGroupFieldRecordObj 数据区分组字段记录obj
     * @param dataAreaGroupFieldNameList  数据区分组字段名称list
     * @param curFieldIndex               当前字段下标
     * @param recordFse                   业务数据记录
     */
    private void recordDataAreaGroupField(JSONObject dataAreaGroupFieldRecordObj, List<String> dataAreaGroupFieldNameList, int curFieldIndex, FieldSetEntity recordFse) {
        String tempFieldName;
        JSONObject parentObj = dataAreaGroupFieldRecordObj;
        JSONObject subObj;
        String value;
        for (int j = 0; j <= curFieldIndex; j++) {
            tempFieldName = dataAreaGroupFieldNameList.get(j);
            value = recordFse.getString(tempFieldName);
            subObj = parentObj.getJSONObject(value);
            if (subObj == null) {
                subObj = new JSONObject();
                parentObj.put(value, subObj);
            }
            parentObj = subObj;
        }
    }
   /**
    * 处理参数替换map-添加数据区分组字段的占行
    *
    * @param replaceMap                            替换map
    * @param needAddRowspanDataAreaGroupFieldNames 需要添加占行的数据区分组字段名称集合
    * @param recordFse                             业务数据记录
    */
   private void dealReplaceMapAddRowspan(Map<String, String> replaceMap, Collection<String> needAddRowspanDataAreaGroupFieldNames, FieldSetEntity recordFse, boolean commonFieldFlag) {
      JSONObject keyObj = new JSONObject();
      String value;
      int rowspan;
      String paramKey;
      int index = 0;
      for (String fieldName : needAddRowspanDataAreaGroupFieldNames) {
         index++;
         keyObj.put(fieldName, recordFse.getString(fieldName));
         if (commonFieldFlag && index != needAddRowspanDataAreaGroupFieldNames.size()) {
            continue;
         }
         keyObj.put(CmnConst.ATTR_FIELD_INFO, dataListReportService.fieldName2FieldInfo(fieldName));
         paramKey = dataListReportService.concat(keyObj, CmnConst.ATTR_ROWSPAN);
         value = replaceMap.get(paramKey);
         rowspan = StringUtils.isEmpty(value) ? 1 : Integer.parseInt(value) + 1;
         replaceMap.put(paramKey, String.valueOf(rowspan));
      }
   }
    /**
     * 获取指定的下级分组项
     *
     * @param keyObj                      指定的key
     * @param dataAreaGroupFieldNameList  数据区分组字段名称list
     * @param dataAreaGroupFieldRecordObj 数据区分组字段记录obj
     * @return
     */
    private int getAimSubCnt(JSONObject keyObj, List<String> dataAreaGroupFieldNameList, JSONObject dataAreaGroupFieldRecordObj) {
        String value;
        JSONObject parentObj = dataAreaGroupFieldRecordObj;
        JSONObject subObj = null;
        for (String fieldName : dataAreaGroupFieldNameList) {
            value = keyObj.getString(fieldName);
            if (value != null) {
                subObj = parentObj.getJSONObject(value);
            } else {
                break;
            }
            parentObj = subObj;
        }
        return subObj == null ? 0 : subObj.size();
    }
   /**
    * 记录分组字段
    *
    * @param dataAreaGroupFieldRecordObj 数据区分组字段记录obj
    * @param dataAreaGroupFieldNameList  数据区分组字段名称list
    * @param curFieldIndex               当前字段下标
    * @param recordFse                   业务数据记录
    */
   private void recordDataAreaGroupField(JSONObject dataAreaGroupFieldRecordObj, List<String> dataAreaGroupFieldNameList, int curFieldIndex, FieldSetEntity recordFse) {
      String tempFieldName;
      JSONObject parentObj = dataAreaGroupFieldRecordObj;
      JSONObject subObj;
      String value;
      for (int j = 0; j <= curFieldIndex; j++) {
         tempFieldName = dataAreaGroupFieldNameList.get(j);
         value = recordFse.getString(tempFieldName);
         subObj = parentObj.getJSONObject(value);
         if (subObj == null) {
            subObj = new JSONObject();
            parentObj.put(value, subObj);
         }
         parentObj = subObj;
      }
   }
   /**
    * 获取指定的下级分组项
    *
    * @param keyObj                      指定的key
    * @param dataAreaGroupFieldNameList  数据区分组字段名称list
    * @param dataAreaGroupFieldRecordObj 数据区分组字段记录obj
    * @return
    */
   private int getAimSubCnt(JSONObject keyObj, List<String> dataAreaGroupFieldNameList, JSONObject dataAreaGroupFieldRecordObj) {
      String value;
      JSONObject parentObj = dataAreaGroupFieldRecordObj;
      JSONObject subObj = null;
      for (String fieldName : dataAreaGroupFieldNameList) {
         value = keyObj.getString(fieldName);
         if (value != null) {
            subObj = parentObj.getJSONObject(value);
         } else {
            break;
         }
         parentObj = subObj;
      }
      return subObj == null ? 0 : subObj.size();
   }
}