许鹏程
2023-06-29 cb4df5a1c9cda76e828fa202990df33be0735105
poi、easyexcel、poi-tl升级 ,合并空调中的报表、数据源模块
已修改11个文件
已删除1个文件
3365 ■■■■■ 文件已修改
DOC/报表设计.docx 补丁 | 查看 | 原始文档 | blame | 历史
pom.xml 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/product/server/report/config/CmnConst.java 464 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/product/server/report/config/SystemCode.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/product/server/report/controller/DataListReportController.java 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/product/server/report/controller/ReportDatasourceController.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/product/server/report/entity/ReportColumn.java 53 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/product/server/report/service/CommonReportService.java 635 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/product/server/report/service/DataListReportService.java 477 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/product/server/report/service/GroupReportService.java 572 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/product/server/report/service/ReportConfigService.java 1038 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/product/server/report/service/ReportDatasourceService.java 88 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
DOC/±¨±íÉè¼Æ.docx
Binary files differ
pom.xml
@@ -1,6 +1,5 @@
<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
         xmlns="http://maven.apache.org/POM/4.0.0"
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <modelVersion>4.0.0</modelVersion>
    <parent>
@@ -19,7 +18,6 @@
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
@@ -42,5 +40,13 @@
            <groupId>com.lx</groupId>
            <artifactId>product-server-data-export-import</artifactId>
        </dependency>
        <dependency>
            <groupId>com.lx</groupId>
            <artifactId>product-server-datasource</artifactId>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
        </dependency>
    </dependencies>
</project>
src/main/java/com/product/server/report/config/CmnConst.java
@@ -1,260 +1,264 @@
package com.product.server.report.config;
public class CmnConst {
import com.product.core.config.CoreConst;
    // è¡¨åå¸¸é‡å®šä¹‰
    public static final String PRODUCT_SYS_PRODUCTS = "product_sys_products"; // äº§å“è¡¨å
    public static final String PRODUCT_SYS_REPORT_TYPE_CONFIG = "product_sys_report_type_config";
    public static final String PRODUCT_SYS_REPORT_TYPE_ATTRIBUTE = "product_sys_report_type_attribute";
    public static final String PRODUCT_SYS_REPORT_DATASOURCE_CONFIG = "product_sys_report_datasource_config";
    public static final String PRODUCT_SYS_REPORT_DATASOURCE_CONFIG_FIELD = "product_sys_report_datasource_config_field";
    public static final String PRODUCT_SYS_REPORT_CONFIG = "product_sys_report_config";
    public static final String PRODUCT_SYS_REPORT_CONFIG_CHARTS = "product_sys_report_config_charts";
    public static final String PRODUCT_SYS_REPORT_CONFIG_ATTRIBUTE = "product_sys_report_config_attribute";
    public static final String PRODUCT_SYS_DATAMODEL_FIELD = "product_sys_datamodel_field";
    public static final String PRODUCT_SYS_FUNCTIONS = "product_sys_functions";
    public static final String PRODUCT_SYS_FUNCTION_BUTTONS = "product_sys_function_buttons";
    public static final String PRODUCT_SYS_MVC_PAGE = "product_sys_mvc_page";
    public static final String PRODUCT_SYS_LINK = "product_sys_link";
    public static final String PRODUCT_SYS_FUNCTION_PERMISSION = "product_sys_function_permission";
    public static final String PRODUCT_SYS_MENUS = "product_sys_menus";
    public static final String PRODUCT_SYS_DATAMODEL_TABLE = "product_sys_datamodel_table";
public class CmnConst extends CoreConst {
    //分页常量定义
    public static final String CPAGE = "cpage";        //页数
    public static final String PAGESIZE = "pagesize";    //每页条数
    // è¡¨åå¸¸é‡å®šä¹‰
    public static final String PRODUCT_SYS_PRODUCTS = "product_sys_products"; // äº§å“è¡¨å
    public static final String PRODUCT_SYS_REPORT_TYPE_CONFIG = "product_sys_report_type_config";
    public static final String PRODUCT_SYS_REPORT_TYPE_ATTRIBUTE = "product_sys_report_type_attribute";
    public static final String PRODUCT_SYS_REPORT_DATASOURCE_CONFIG = "product_sys_report_datasource_config";
    public static final String PRODUCT_SYS_REPORT_DATASOURCE_CONFIG_FIELD = "product_sys_report_datasource_config_field";
    public static final String PRODUCT_SYS_REPORT_CONFIG = "product_sys_report_config";
    public static final String PRODUCT_SYS_REPORT_CONFIG_CHARTS = "product_sys_report_config_charts";
    public static final String PRODUCT_SYS_REPORT_CONFIG_ATTRIBUTE = "product_sys_report_config_attribute";
    public static final String PRODUCT_SYS_DATAMODEL_FIELD = "product_sys_datamodel_field";
    public static final String PRODUCT_SYS_FUNCTIONS = "product_sys_functions";
    public static final String PRODUCT_SYS_FUNCTION_BUTTONS = "product_sys_function_buttons";
    public static final String PRODUCT_SYS_MVC_PAGE = "product_sys_mvc_page";
    public static final String PRODUCT_SYS_LINK = "product_sys_link";
    public static final String PRODUCT_SYS_FUNCTION_PERMISSION = "product_sys_function_permission";
    public static final String PRODUCT_SYS_MENUS = "product_sys_menus";
    public static final String PRODUCT_SYS_DATAMODEL_TABLE = "product_sys_datamodel_table";
    //分页常量定义
    public static final String CPAGE = "cpage";        //页数
    public static final String PAGESIZE = "pagesize";    //每页条数
    //特殊常量定义
    public static final String TYPE = "~type~";
    public static final String DEL = "del";
    public static final String UUID = "uuid";
    public static final String ID = "id";
    public static final String OPTION = "option";
    //数据库类型
    public static final String MYSQL = "mysql";
    //特殊常量定义
    public static final String TYPE = "~type~";
    public static final String DEL = "del";
    public static final String UUID = "uuid";
    public static final String ID = "id";
    public static final String OPTION = "option";
    public static final String TABLE_NAME = "table_name";
    //数据库类型
    public static final String MYSQL = "mysql";
    //常量字段定义
    public static final String RELATED_TABLE = "related_table";
    public static final String TYPE_GROUP = "type_group";
    public static final String TYPE_UUID = "type_uuid";
    public static final String FIELD_TYPE = "field_type";
    public static final String FIELD_LENGTH = "field_length";
    public static final String FIELD_UNIT = "field_unit";
    public static final String FIELD_DESCRIPTION = "field_description";
    public static final String FIELD_TEXT = "field_text";
    public static final String IS_VALID = "is_valid";
    public static final String CREATED_BY = "created_by";
    public static final String UPDATED_BY = "updated_by";
    public static final String CREATED_UTC_DATETIME = "created_utc_dateime";
    public static final String UPDATED_UTC_DATETIME = "updated_utc_datetime";
    public static final String NAME = "name";
    public static final String VALUE = "value";
    public static final String TRICODE = "tricode";
    public static final String MODULE_UUID = "module_uuid";
    public static final String TABLE_UUID = "table_uuid";
    public static final String FUNCTION_NAME = "function_name";
    public static final String FUNCTION_DESCRIPTION = "function_description";
    public static final String REPORT_NAME = "report_name";
    public static final String STATUS_UUID = "status_uuid";
    public static final String FUNCTION_TYPE_UUID = "function_type_uuid";
    public static final String CLIENT_TYPE_UUID = "client_type_uuid";
    public static final String BUTTON_NAME = "button_name";
    public static final String BUTTON_TITLE = "button_title";
    public static final String BUTTON_TYPE = "button_type";
    public static final String BUTTON_CATEGORY_UUID = "button_category_uuid";
    public static final String ROUTE_NAME = "route_name";
    public static final String IS_MAIN = "is_main";
    public static final String PAGE_NAME = "page_name";
    public static final String LINK_TYPE = "link_type";
    public static final String FUNCTION_UUID = "function_uuid";
    public static final String SUB_REPORT = "sub_report";
    public static final String LINE_FROM = "line_from";
    public static final String FROM_TYPE = "from_type";
    public static final String LINE_TO = "line_to";
    public static final String TO_TYPE = "to_type";
    public static final String BUTTON_UUID = "button_uuid";
    public static final String ROLE_UUID = "role_uuid";
    public static final String MENU_NAME = "menu_name";
    public static final String MENU_ICON = "menu_icon";
    public static final String TRICODE_PARENT = "tricode_parent";
    public static final String IS_CATALOG = "is_catalog";
    public static final String IS_SHOW = "is_show";
    public static final String TOP_LOCATION = "top_location";
    public static final String LEFT_LOCATION = "left_location";
    public static final String VERSION_UUID = "version_uuid";
    public static final String PAGE_TYPE = "page_type";
    public static final String PAGE_URL = "page_url";
    public static final String UPLOAD_API_URL = "upload_api_url";
    public static final String PARAMS = "params";
    public static final String SEQUENCE = "sequence";
    public static final String REPORT_WIDTH_TYPE = "report_width_type";
    public static final String REPORT_WIDTH_VALUE = "report_width_value";
    public static final String DATA_TYPE = "data_type";
    public static final String PAGE_OPEN_WITH = "page_open_with";
    public static final String RELATE_FLAG = "relate_flag";
    public static final String LOGICAL_OPERATOR = "logical_operator";
    public static final String LOGICAL_VALUE = "logical_value";
    public static final String FIRST_LOAD = "first_load";
    //常量字段定义
    public static final String RELATED_TABLE = "related_table";
    public static final String TYPE_GROUP = "type_group";
    public static final String TYPE_UUID = "type_uuid";
    public static final String FIELD_TYPE = "field_type";
    public static final String FIELD_LENGTH = "field_length";
    public static final String FIELD_UNIT = "field_unit";
    public static final String FIELD_DESCRIPTION = "field_description";
    public static final String FIELD_TEXT = "field_text";
    public static final String IS_VALID = "is_valid";
    public static final String CREATED_BY = "created_by";
    public static final String UPDATED_BY = "updated_by";
    public static final String CREATED_UTC_DATETIME = "created_utc_dateime";
    public static final String UPDATED_UTC_DATETIME = "updated_utc_datetime";
    public static final String NAME = "name";
    public static final String VALUE = "value";
    public static final String TRICODE = "tricode";
    public static final String MODULE_UUID = "module_uuid";
    public static final String TABLE_UUID = "table_uuid";
    public static final String FUNCTION_NAME = "function_name";
    public static final String FUNCTION_DESCRIPTION = "function_description";
    public static final String REPORT_NAME = "report_name";
    public static final String STATUS_UUID = "status_uuid";
    public static final String FUNCTION_TYPE_UUID = "function_type_uuid";
    public static final String CLIENT_TYPE_UUID = "client_type_uuid";
    public static final String BUTTON_NAME = "button_name";
    public static final String BUTTON_TITLE = "button_title";
    public static final String BUTTON_TYPE = "button_type";
    public static final String BUTTON_CATEGORY_UUID = "button_category_uuid";
    public static final String ROUTE_NAME = "route_name";
    public static final String IS_MAIN = "is_main";
    public static final String PAGE_NAME = "page_name";
    public static final String LINK_TYPE = "link_type";
    public static final String FUNCTION_UUID = "function_uuid";
    public static final String SUB_REPORT = "sub_report";
    public static final String LINE_FROM = "line_from";
    public static final String FROM_TYPE = "from_type";
    public static final String LINE_TO = "line_to";
    public static final String TO_TYPE = "to_type";
    public static final String BUTTON_UUID = "button_uuid";
    public static final String ROLE_UUID = "role_uuid";
    public static final String MENU_NAME = "menu_name";
    public static final String MENU_ICON = "menu_icon";
    public static final String TRICODE_PARENT = "tricode_parent";
    public static final String IS_CATALOG = "is_catalog";
    public static final String IS_SHOW = "is_show";
    public static final String TOP_LOCATION = "top_location";
    public static final String LEFT_LOCATION = "left_location";
    public static final String VERSION_UUID = "version_uuid";
    public static final String PAGE_TYPE = "page_type";
    public static final String PAGE_URL = "page_url";
    public static final String UPLOAD_API_URL = "upload_api_url";
    public static final String PARAMS = "params";
    public static final String SEQUENCE = "sequence";
    public static final String REPORT_WIDTH_TYPE = "report_width_type";
    public static final String REPORT_WIDTH_VALUE = "report_width_value";
    public static final String DATA_TYPE = "data_type";
    public static final String PAGE_OPEN_WITH = "page_open_with";
    public static final String RELATE_FLAG = "relate_flag";
    public static final String LOGICAL_OPERATOR = "logical_operator";
    public static final String LOGICAL_VALUE = "logical_value";
    public static final String FIRST_LOAD = "first_load";
    //PRODUCT_SYS_report_config  é…ç½®ä¸»è¡¨å­—段
    public static final String DATASOURCE_UUID = "datasource_uuid";
    //数据源uuid
    public static final String REPORT_DATASOURCE_UUID = "report_datasource_uuid";
    //表类型uuid
    public static final String REPORT_TYPE_CONFIG_UUID = "report_type_config_uuid";
    //PRODUCT_SYS_report_datasource_config æŠ¥è¡¨æ•°æ®æºé…ç½®è¡¨å­—段
    public static final String SQL_TEXT = "sql_text";
    //PRODUCT_SYS_report_datasource_config_field æŠ¥è¡¨æ•°æ®æºå­—段信息表字段
    public static final String FIELD_NAME = "field_name";
    public static final String FIELD_FORMAT = "field_format";
    public static final String FIELD_PROMPT = "field_prompt";
    public static final String SEARCH_TYPE = "search_type";
    public static final String TABLE_NAME = "table_name";
    //PRODUCT_SYS_report_type_attribute æŠ¥è¡¨é…ç½®å±žæ€§è¡¨å­—段
    public static final String REPORT_TYPE_ATTR = "report_type_attr";
    public static final String ATTRIBUTE_NAME = "attribute_name";
    //PRODUCT_SYS_report_config  é…ç½®ä¸»è¡¨å­—段
    public static final String DATASOURCE_UUID = "datasource_uuid";
    //数据源uuid
    public static final String REPORT_DATASOURCE_UUID = "report_datasource_uuid";
    //表类型uuid
    public static final String REPORT_TYPE_CONFIG_UUID = "report_type_config_uuid";
    //PRODUCT_SYS_report_datasource_config æŠ¥è¡¨æ•°æ®æºé…ç½®è¡¨å­—段
    public static final String SQL_TEXT = "sql_text";
    //PRODUCT_SYS_report_datasource_config_field æŠ¥è¡¨æ•°æ®æºå­—段信息表字段
    public static final String FIELD_NAME = "field_name";
    public static final String FIELD_FORMAT = "field_format";
    public static final String FIELD_PROMPT = "field_prompt";
    public static final String SEARCH_TYPE = "search_type";
    //PRODUCT_SYS_report_type_attribute æŠ¥è¡¨é…ç½®å±žæ€§è¡¨å­—段
    public static final String REPORT_TYPE_ATTR = "report_type_attr";
    public static final String ATTRIBUTE_NAME = "attribute_name";
    public static final String UNPIVOT_INFO = "unpivot_info";
    public static final String IS_UNPIVOT = "is_unpivot";
    public static final String REPORT_TYPE = "report_type";
    public static final String REPORT_TYPE_COMMON = "普通数据列表";
    public static final String REPORT_TYPE_GROUP = "分组报表";
    public static final String REPORT_TYPE_CROSS = "交叉报表";
    public static final String REPORT_TYPE = "report_type";
    public static final String REPORT_TYPE_COMMON = "普通数据列表";
    public static final String REPORT_TYPE_GROUP = "分组报表";
    public static final String REPORT_TYPE_CROSS = "交叉报表";
    // ç¼“å­˜
    public static final String CACHE_REPORT_CONFIG = "报表配置";
    public static final String CACHE_REPORT_DATASOURCE_CONFIG = "数据源配置";
    public static final String CACHE_REPORT_DATASOURCE_FIELD_CONFIG = "数据源字段配置";
    public static final String CACHE_REPORT_TYPE = "报表类型";
    public static final String CACHE_REPORT_TYPE_ATTR = "报表类型属性表";
    // ç¼“å­˜
    public static final String CACHE_REPORT_CONFIG = "报表配置";
    public static final String CACHE_REPORT_DATASOURCE_CONFIG = "数据源配置";
    public static final String CACHE_REPORT_DATASOURCE_FIELD_CONFIG = "数据源字段配置";
    public static final String CACHE_REPORT_TYPE = "报表类型";
    public static final String CACHE_REPORT_TYPE_ATTR = "报表类型属性表";
    // å­—段
    public static final String REPORT_TYPE_ATTR_VALUE = "report_type_attr_value";
    public static final String CELL_POSITION_X = "cell_position_x";
    public static final String CELL_POSITION_Y = "cell_position_y";
    public static final String REPORT_AREA = "report_area";
    public static final String LAST_TOTAL = "last_total";
    public static final String TOTAL_NAME = "total_name";
    public static final String IS_PAGE = "is_page";
    public static final String PAGE_SIZE = "page_size";
    public static final String TYPE_NAME = "type_name";
    public static final String SYSTEM_SENIOR_QUERY_STRING = "systemSeniorQueryString";
    public static final String REPORT_DATASOURCE_NAME = "report_datasource_name";
    // å­—段
    public static final String REPORT_TYPE_ATTR_VALUE = "report_type_attr_value";
    public static final String CELL_POSITION_X = "cell_position_x";
    public static final String CELL_POSITION_Y = "cell_position_y";
    public static final String REPORT_AREA = "report_area";
    public static final String LAST_TOTAL = "last_total";
    public static final String TOTAL_NAME = "total_name";
    public static final String IS_PAGE = "is_page";
    public static final String PAGE_SIZE = "page_size";
    public static final String TYPE_NAME = "type_name";
    public static final String SYSTEM_SENIOR_QUERY_STRING = "systemSeniorQueryString";
    public static final String REPORT_DATASOURCE_NAME = "report_datasource_name";
    // å±žæ€§-label
    public static final String ATTR_COLSPAN = "colspan";
    public static final String ATTR_ROWSPAN = "rowspan";
    public static final String ATTR_FIELD_INFO = "field_info";
    public static final String ATTR_DATA_AREA_GROUP_FIELD = "data_area_group_field";
    public static final String ATTR_GROUP_AREA_GROUP_FIELD = "group_area_group_field";
    public static final String ATTR_STATISTICS = "statistics";
    public static final String ATTR_X = "x";
    public static final String ATTR_Y = "y";
    public static final String ATTR_SORT = "sort";
    public static final String ATTR_SHOW_NAME = "show_name";
    public static final String ATTR_IS_GROUP = "is_group";
    public static final String ATTR_IS_CUSTOM_FIELD = "is_custom_field";
    public static final String ATTR_SP_TIME_STATISTICS_WAY = "sp_time_statistics_way";
    public static final String ATTR_RELATE_TIME_FIELD = "relate_time_field";
    public static final String ATTR_RELATE_COMMON_FIELD = "relate_common_field";
    public static final String ATTR_HEAD_LAST_YEAR = "last_year__";
    public static final String ATTR_HEAD_PRE_PERIOD = "pre_period__";
    // å±žæ€§-label
    public static final String ATTR_COLSPAN = "colspan";
    public static final String ATTR_ROWSPAN = "rowspan";
    public static final String ATTR_FIELD_INFO = "field_info";
    public static final String ATTR_DATA_AREA_GROUP_FIELD = "data_area_group_field";
    public static final String ATTR_GROUP_AREA_GROUP_FIELD = "group_area_group_field";
    public static final String ATTR_STATISTICS = "statistics";
    public static final String ATTR_X = "x";
    public static final String ATTR_Y = "y";
    public static final String ATTR_SORT = "sort";
    public static final String ATTR_SHOW_NAME = "show_name";
    public static final String ATTR_IS_GROUP = "is_group";
    public static final String ATTR_IS_CUSTOM_FIELD = "is_custom_field";
    public static final String ATTR_SP_TIME_STATISTICS_WAY = "sp_time_statistics_way";
    public static final String ATTR_RELATE_TIME_FIELD = "relate_time_field";
    public static final String ATTR_RELATE_COMMON_FIELD = "relate_common_field";
    public static final String ATTR_HEAD_LAST_YEAR = "last_year__";
    public static final String ATTR_HEAD_PRE_PERIOD = "pre_period__";
    public static final String ATTR_FORMULA = "formula";
    public static final String ATTR_IS_STATISTICS = "is_statistics";
    public static final String ATTR_IS_STATISTICS_FIELD = "is_statistics_field";
    public static final String ATTR_DECIMAL_DIGITS = "decimal_digits";
    public static final String ATTR_AVG_TYPE = "avg_type";
    public static final String ATTR_ENUM_TYPE = "enum_type";
    public static final String ATTR_IS_TOTAL_STATISTICS = "is_total_statistics";
    public static final String ATTR_IS_TITLE = "is_title";
    public static final String ATTR_GROUP_AREA_SUB_CNT = "group_area_sub_cnt";
    public static final String ATTR_DATA_AREA_SUB_CNT = "data_area_sub_cnt";
    public static final String ATTR_SIZE = "size";
    public static final String ATTR_STATISTICS_FIELD = "statistics_field";
    public static final String ATTR_ORDER_BY = "order_by";
    public static final String ATTR_DATE_FORMAT = "date_format";
    public static final String ATTR_NUM_FORMAT = "num_format";
    public static final String ATTR_DATA_TYPE = "data_type";
    public static final String ATTR_WIDTH = "width";
    public static final String ATTR_URL = "url";
    public static final String ATTR_REAL_VALUE = "real_value";
    public static final String ATTR_TOTAL_COUNT = "total_count";
    public static final String ATTR_TOTAL_PAGE = "total_page";
    public static final String ATTR_URL_PARAM = "url_param";
    public static final String ATTR_FORMULA = "formula";
    public static final String ATTR_IS_STATISTICS = "is_statistics";
    public static final String ATTR_IS_STATISTICS_FIELD = "is_statistics_field";
    public static final String ATTR_DECIMAL_DIGITS = "decimal_digits";
    public static final String ATTR_AVG_TYPE = "avg_type";
    public static final String ATTR_ENUM_TYPE = "enum_type";
    public static final String ATTR_IS_TOTAL_STATISTICS = "is_total_statistics";
    public static final String ATTR_IS_TITLE = "is_title";
    public static final String ATTR_GROUP_AREA_SUB_CNT = "group_area_sub_cnt";
    public static final String ATTR_DATA_AREA_SUB_CNT = "data_area_sub_cnt";
    public static final String ATTR_SIZE = "size";
    public static final String ATTR_STATISTICS_FIELD = "statistics_field";
    public static final String ATTR_ORDER_BY = "order_by";
    public static final String ATTR_DATE_FORMAT = "date_format";
    public static final String ATTR_NUM_FORMAT = "num_format";
    public static final String ATTR_DATA_TYPE = "data_type";
    public static final String ATTR_WIDTH = "width";
    public static final String ATTR_URL = "url";
    public static final String ATTR_REAL_VALUE = "real_value";
    public static final String ATTR_TOTAL_COUNT = "total_count";
    public static final String ATTR_TOTAL_PAGE = "total_page";
    public static final String ATTR_URL_PARAM = "url_param";
    public static final String ATTR_REPORT_AREA = "report_area";
    public static final String ATTR_NAME = "name";
    public static final String ATTR_VALUE = "value";
    public static final String ATTR_FINAL_VALUE = "final_value";
    public static final String ATTR_REPORT_AREA = "report_area";
    public static final String ATTR_NAME = "name";
    public static final String ATTR_VALUE = "value";
    public static final String ATTR_FINAL_VALUE = "final_value";
    public static final String ATTR_STATISTICS_DEFAULT = "default";
    public static final String ATTR_STATISTICS_SUM = "sum";
    public static final String ATTR_STATISTICS_MAX = "max";
    public static final String ATTR_STATISTICS_MIN = "min";
    public static final String ATTR_STATISTICS_CNT = "cnt";
    public static final String ATTR_STATISTICS_AVG = "avg";
    public static final String ATTR_STATISTICS_ENUM = "enum";
    public static final String ATTR_STATISTICS_FINAL_STATISTICS = "final_statistics";
    public static final String ATTR_STATISTICS_SUB_CNT = "sub_cnt";
    public static final String ATTR_STATISTICS_GROUP_AREA_AVG = "group_area_avg";
    public static final String ATTR_STATISTICS_DATA_AREA_AVG = "data_area_avg";
    public static final String ATTR_STATISTICS_DEFAULT = "default";
    public static final String ATTR_STATISTICS_SUM = "sum";
    public static final String ATTR_STATISTICS_MAX = "max";
    public static final String ATTR_STATISTICS_MIN = "min";
    public static final String ATTR_STATISTICS_CNT = "cnt";
    public static final String ATTR_STATISTICS_AVG = "avg";
    public static final String ATTR_STATISTICS_ENUM = "enum";
    public static final String ATTR_STATISTICS_FINAL_STATISTICS = "final_statistics";
    public static final String ATTR_STATISTICS_SUB_CNT = "sub_cnt";
    public static final String ATTR_STATISTICS_GROUP_AREA_AVG = "group_area_avg";
    public static final String ATTR_STATISTICS_DATA_AREA_AVG = "data_area_avg";
    public static final String ATTR_DATA_TYPE_STRING = "string";
    public static final String ATTR_DATA_TYPE_NUM = "num";
    public static final String ATTR_DATA_TYPE_DATE = "date";
    public static final String ATTR_DATA_TYPE_STRING = "string";
    public static final String ATTR_DATA_TYPE_NUM = "num";
    public static final String ATTR_DATA_TYPE_DATE = "date";
    public static final String STATISTICS_NAME = "统计";
    public static final String STATISTICS_NAME = "统计";
    public static final String ONCLICK_FUNC_NAME = "turn_2_other_page";
    public static final String ONCLICK_FUNC_NAME = "turn_2_other_page";
    public static final String RETURN_ATTR_RESULT = "result";
    public static final String RETURN_ATTR_MESSAGE = "message";
    public static final String RETURN_ATTR_HTML = "html";
    public static final String RETURN_ATTR_RESULT = "result";
    public static final String RETURN_ATTR_MESSAGE = "message";
    public static final String RETURN_ATTR_HTML = "html";
    public static final String REGEXP_FORM_FIELD = "\\{#\\w+#}";
    public static final String REGEXP_SYS_FIELD = "\\{%\\w+%}";
    public static final String REGEXP_NUMBER = "-?[0-9]+\\.?[0-9]*";
    public static final String REGEXP_FORM_FIELD = "\\{#\\w+#}";
    public static final String REGEXP_SYS_FIELD = "\\{%\\w+%}";
    public static final String REGEXP_NUMBER = "-?[0-9]+\\.?[0-9]*";
    public static final String FALSE = "false";
    public static final String TRUE = "true";
    public static final String FALSE = "false";
    public static final String TRUE = "true";
    public static final String FULL_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
    public static final String FULL_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
    public static final String MIN_X = "min_x";
    public static final String MAX_X = "max_x";
    public static final String MAX_Y = "max_y";
    public static final String MIN_X = "min_x";
    public static final String MAX_X = "max_x";
    public static final String MAX_Y = "max_y";
    public static final String CLASS_TR_REPORT_TITLE = "report_title";
    public static final String CLASS_TR_HEAD = "head";
    public static final String CLASS_TR_DATA_TITLE = "data_title";
    public static final String CLASS_TR_DATA_STATISTICS = "data_statistics";
    public static final String CLASS_TR_DATA_COMMON = "data_common";
    public static final String CLASS_TR_TAIL = "tail";
    public static final String CLASS_TD_CAN_TURN = "can_turn";
    public static final String PROMPT_REAL_VALUE_TAIL = "_save_value";
    public static final String CLASS_TR_REPORT_TITLE = "report_title";
    public static final String CLASS_TR_HEAD = "head";
    public static final String CLASS_TR_DATA_TITLE = "data_title";
    public static final String CLASS_TR_DATA_STATISTICS = "data_statistics";
    public static final String CLASS_TR_DATA_COMMON = "data_common";
    public static final String CLASS_TR_TAIL = "tail";
    public static final String CLASS_TD_CAN_TURN = "can_turn";
    public static final String REGEXP_FILTER_AREA = "\\[\\[((?!\\[).)+\\]\\]";
    public static final String REGEXP_ALL_AREA = "(\\[\\[((?!\\[).)+\\]\\])|(\\{\\$((?!\\$).)+\\$\\})|(\\{\\^((?!\\^).)+\\^\\})|(\\{\\&((?!\\&).)+\\&\\})";
    public static final String REGEXP_SP_SIGN_AREA = "(\\{\\$((?!\\$).)+\\$\\})|(\\{\\^((?!\\^).)+\\^\\})|(\\{\\&((?!\\&).)+\\&\\})";
    public static final String REGEXP_ONLY_VALUE = "\\{\\$((?!\\$).)+\\$\\}";
    public static final String REGEXP_EXCEPT_FIELD = "\\{\\^((?!\\^).)+\\^\\}";
    public static final String REGEXP_FULL_CONTENT = "\\{\\&((?!\\&).)+\\&\\}";
    public static final String REGEXP_ALL_TERNARY_OPERATOR = "\\{@((?!(\\{@)|(@\\})|(\\[\\[)|(\\]\\])).)+@\\}";
    public static final String REGEXP_TERNARY_OPERATOR = "((?!\\?|(\\[)).)+\\?((?!:).)+:((?!(\\]\\])).)+";
    public static final String REGEXP_ALL_TYPE = "(\\{\\$((?!(\\{\\$)).)+\\$\\})|(\\{\\^((?!(\\{\\^)).)+\\^\\})|(\\{\\&((?!(\\{\\&)).)+\\&\\})";
    public static final String REGEXP_ALWAYS_TRUE = "and\\s+1\\s*=\\s*1";
    public static final String PROMPT_REAL_VALUE_TAIL = "_save_value";
    public static final String TERNARY_OPERATOR_LEFT = "{@";
    public static final String TERNARY_OPERATOR_RIGHT = "@}";
    public static final String CONTENT_PAGE_AREA = "[[page_area]]";
    public static final String REGEXP_FILTER_AREA = "\\[\\[((?!\\[).)+\\]\\]";
    public static final String REGEXP_ALL_AREA = "(\\[\\[((?!\\[).)+\\]\\])|(\\{\\$((?!\\$).)+\\$\\})|(\\{\\^((?!\\^).)+\\^\\})|(\\{\\&((?!\\&).)+\\&\\})";
    public static final String REGEXP_SP_SIGN_AREA = "(\\{\\$((?!\\$).)+\\$\\})|(\\{\\^((?!\\^).)+\\^\\})|(\\{\\&((?!\\&).)+\\&\\})";
    public static final String REGEXP_ONLY_VALUE = "\\{\\$((?!\\$).)+\\$\\}";
    public static final String REGEXP_EXCEPT_FIELD = "\\{\\^((?!\\^).)+\\^\\}";
    public static final String REGEXP_FULL_CONTENT = "\\{\\&((?!\\&).)+\\&\\}";
    public static final String REGEXP_ALL_TERNARY_OPERATOR = "\\{@((?!(\\{@)|(@\\})|(\\[\\[)|(\\]\\])).)+@\\}";
    public static final String REGEXP_TERNARY_OPERATOR = "((?!\\?|(\\[)).)+\\?((?!:).)+:((?!(\\]\\])).)+";
    public static final String REGEXP_ALL_TYPE = "(\\{\\$((?!(\\{\\$)).)+\\$\\})|(\\{\\^((?!(\\{\\^)).)+\\^\\})|(\\{\\&((?!(\\{\\&)).)+\\&\\})";
    public static final String REGEXP_ALWAYS_TRUE = "and\\s+1\\s*=\\s*1";
    public static final String ADDRESS_INIT_INTERFENCE = "api/report/data-list/get-report";
    public static final String ADDRESS_REPORT_SHOW = "system/reportForms/dataReport/preview";
    public static final String ADDRESS_INIT_CHART = "/api/report/EChart/generatePieEChart";
    public static final String ADDRESS_CHART_VIEW = "system/reportForms/chartReport/previewTwo";
    public static final String TERNARY_OPERATOR_LEFT = "{@";
    public static final String TERNARY_OPERATOR_RIGHT = "@}";
    public static final String CONTENT_PAGE_AREA = "[[page_area]]";
    public static final String FIELD_TYPE_NUM_STR = "bigint,decimal,double,float,int,integer,tinyint";
    public static final String FIELD_TYPE_DATE_STR = "date,datetime,time,timestamp";
    public static final String ADDRESS_INIT_INTERFENCE = "api/report/data-list/get-report";
    public static final String ADDRESS_REPORT_SHOW = "system/reportForms/dataReport/preview";
    public static final String ADDRESS_INIT_CHART = "/api/report/EChart/generatePieEChart";
    public static final String ADDRESS_CHART_VIEW = "system/reportForms/chartReport/previewTwo";
    public static final String FIELD_TYPE_NUM_STR = "bigint,decimal,double,float,int,integer,tinyint";
    public static final String FIELD_TYPE_DATE_STR = "date,datetime,time,timestamp";
}
src/main/java/com/product/server/report/config/SystemCode.java
@@ -26,8 +26,8 @@
    SYTEM_REPORT_DATASOURCE_UPDATE_ERROR("报表数据源修改失败!",ModuleEnum.REPORT.getValue()+"003"),
    SYTEM_REPORT_DATASOURCE_DELETE_ERROR("报表数据源删除失败!",ModuleEnum.REPORT.getValue()+"004"),
    SYTEM_REPORT_DATA_PROCESS_ERROR("报表数据处理失败",ModuleEnum.REPORT.getValue()+"005"),
    PUBLISH_REPORT_FAIL_MODULE_NO_EXIST("图标发布失败,指定模块不存在", ModuleEnum.REPORT.getValue()+"005"),
    NO_MATCH_TABLE("未匹配到表名",ModuleEnum.REPORT.getValue()+"006"),
    PUBLISH_REPORT_FAIL_MODULE_NO_EXIST("图标发布失败,指定模块不存在", ModuleEnum.REPORT.getValue()+"007"),
    ;
    private String text;
src/main/java/com/product/server/report/controller/DataListReportController.java
@@ -1,7 +1,5 @@
package com.product.server.report.controller;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.product.core.config.CoreConst;
import com.product.core.controller.support.AbstractBaseController;
import com.product.core.entity.FieldSetEntity;
@@ -9,13 +7,10 @@
import com.product.core.exception.BaseException;
import com.product.core.spring.context.SpringMVCContextHolder;
import com.product.module.data.config.CmnCode;
import com.product.module.data.config.CmnConst;
import com.product.module.data.service.SystemDataExportService;
import com.product.module.sys.version.ApiVersion;
import com.product.server.report.config.CmnConst;
import com.product.server.report.config.ReportCode;
import com.product.server.report.config.SystemCode;
import com.product.server.report.entity.ReportColumn;
import com.product.server.report.entity.ReportEntity;
import com.product.server.report.service.DataListReportService;
import com.product.util.BaseUtil;
import org.springframework.beans.factory.annotation.Autowired;
@@ -24,12 +19,8 @@
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.TimeZone;
import java.util.stream.Collectors;
/**
 * Copyright Â© 6c
@@ -89,7 +80,7 @@
     */
    @RequestMapping(value = "/get-report/{version}", method = RequestMethod.POST)
    @ApiVersion(1)
    public String getReport(HttpServletRequest request) {
    public String getTableInfo(HttpServletRequest request) {
        try {
            FieldSetEntity fse = null;
            Object bean = request.getAttribute(CoreConst.API_POST_REQUEST_DATA);
@@ -101,7 +92,7 @@
                SpringMVCContextHolder.getSystemLogger().error(SystemCode.SYSTEM_FORM_NODATA.getValue(), SystemCode.SYSTEM_FORM_NODATA.getText());
                return this.error(SystemCode.SYSTEM_FORM_NODATA.getValue(), SystemCode.SYSTEM_FORM_NODATA.getText());
            }
            return BaseUtil.success(dataListReportService.getReportEntity(fse));
            return BaseUtil.success(dataListReportService.getReport(fse));
        } catch (BaseException e) {
            SpringMVCContextHolder.getSystemLogger().error(e);
            return this.error(e.getCode(), e.getMessageInfo());
@@ -128,8 +119,8 @@
                fse.setValue(CmnConst.CPAGE, 1);
                fse.setValue(CmnConst.PAGESIZE, Integer.MAX_VALUE);
            }
             dataListReportService.outReportExcel(response,fse);
                return OK();
            dataListReportService.outReportExcel(response, fse);
            return OK();
        } catch (BaseException e) {
            e.printStackTrace();
            SpringMVCContextHolder.getSystemLogger().error(e);
@@ -140,5 +131,4 @@
            return error(CmnCode.EXPORT_GENERAL_LIST_DATA_IMPORT_FIAL.getValue(), CmnCode.EXPORT_GENERAL_LIST_DATA_IMPORT_FIAL.getText() + e.getMessage());
        }
    }
}
src/main/java/com/product/server/report/controller/ReportDatasourceController.java
@@ -257,7 +257,7 @@
            return OK_List(dt);
        } catch (BaseException e) {
            e.printStackTrace();
            return this.error(e.getCode());
            return this.error(e);
        }  catch (Exception e) {
            e.printStackTrace();
            return this.error("", ReportCode.REPORT_DATASOURCE_ERROR.getText()+e.getMessage());
src/main/java/com/product/server/report/entity/ReportColumn.java
@@ -13,9 +13,9 @@
 */
public class ReportColumn {
    //跨列
    private int colspan = 1;
    private String colspan = "1";
    //跨行
    private int rowspan = 1;
    private String rowspan = "1";
    //单元格内容
    private String content;
    //穿透字段
@@ -31,14 +31,30 @@
    private Map<String, String> otherParams = new HashMap<>();
    public ReportColumn() {
    }
    public ReportColumn(String content) {
        this.content = content;
    }
    public ReportColumn(int colspan, int rowspan) {
        this.colspan = String.valueOf(colspan);
        this.rowspan = String.valueOf(rowspan);
    }
    public ReportColumn(String content, int colspan, int rowspan) {
        this.content = content;
        this.colspan = String.valueOf(colspan);
        this.rowspan = String.valueOf(rowspan);
    }
    public void replace(String key, String value) {
        if (!otherParams.isEmpty()) {
            Map<String, String> otherParams = this.otherParams;
            this.otherParams = new HashMap<>();
            otherParams.forEach((k, v) -> {
                if ("rowspan".equals(v) && NumberUtil.isNumber(value) && k.equals(key)) {
                    this.rowspan = NumberUtil.parseInt(value);
                }
                this.otherParams.put(k.replace(key, value), v.replace(key, value));
            });
        }
@@ -51,28 +67,49 @@
        if (!StringUtils.isEmpty(content)) {
            content = content.replace(key, value);
        }
        if (key.equals(this.colspan)) {
            this.colspan = value;
        }
        if (key.equals(this.rowspan)) {
            this.rowspan = value;
        }
    }
    public void addProperty(String key, String value) {
        otherParams.put(key, value);
    }
    public int getColspan() {
    public String getColspan() {
        return colspan;
    }
    public void setColspan(int colspan) {
        this.colspan = String.valueOf(colspan);
    }
    public void setColspan(String colspan) {
        this.colspan = colspan;
    }
    public int getRowspan() {
    public String getRowspan() {
        return rowspan;
    }
    public void setRowspan(int rowspan) {
    public int getRowspanInt() {
        return NumberUtil.parseInt(rowspan);
    }
    public int getColspanInt() {
        return NumberUtil.parseInt(colspan);
    }
    public void setRowspan(String rowspan) {
        this.rowspan = rowspan;
    }
    public void setRowspan(int rowspan) {
        this.rowspan = String.valueOf(rowspan);
    }
    public String getContent() {
        return getContent(false);
    }
src/main/java/com/product/server/report/service/CommonReportService.java
@@ -1,6 +1,5 @@
package com.product.server.report.service;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.NumberUtil;
import com.alibaba.fastjson.JSONObject;
@@ -14,9 +13,7 @@
import com.product.core.spring.context.SpringMVCContextHolder;
import com.product.server.report.config.CmnConst;
import com.product.server.report.entity.ReportColumn;
import com.product.server.report.entity.ReportEntity;
import com.product.util.BaseUtil;
import com.product.util.SystemParamReplace;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -34,92 +31,49 @@
    @Autowired
    private DataListReportService dataListReportService;
    /**
     * æŠ¥è¡¨-解析
     *
     * @param recordDte           ä¸šåŠ¡æ•°æ®dte
     * @param totalStatisticsFlag æ˜¯å¦åˆè®¡æ ‡è¯†
     * @param reportConfigMap     æŠ¥è¡¨é…ç½®ç¼“å­˜map
     * @return
     */
    public ReportEntity getReportEntity(DataTableEntity recordDte, String totalName, Map<Integer, List<JSONObject>> reportConfigMap) {
        ReportEntity report = null;
        Map<String, Set<String>> headAndTailTitleDataMap = Maps.newHashMap();
        // æ•°æ®åŒº
        report = getDataArea(reportConfigMap, headAndTailTitleDataMap, recordDte, totalName);
        int totalColCount = reportConfigMap.get(0).size();
        // å¤´éƒ¨æ ‡é¢˜åŒº
        List<List<ReportColumn>> headTitleRows = null;
        if (!reportConfigMap.get(1).isEmpty()) {
            headTitleRows = dataListReportService.getTitle(reportConfigMap.get(1), totalColCount, headAndTailTitleDataMap, "head");
        }
        // åº•部标题区
        List<List<ReportColumn>> tailTitleRows = null;
        if (!reportConfigMap.get(3).isEmpty()) {
            tailTitleRows = dataListReportService.getTitle(reportConfigMap.get(3), totalColCount, headAndTailTitleDataMap, "tail");
        }
        if (!CollectionUtil.isEmpty(headTitleRows)) {
            List<List<ReportColumn>> reportHeader = report.getReportHeader();
            if (reportHeader != null) {
                headTitleRows.addAll(reportHeader);
            }
            report.setReportHeader(headTitleRows);
        }
        if (!CollectionUtil.isEmpty(tailTitleRows)) {
            report.setReportTail(tailTitleRows);
        }
        return report;
    }
    /**
     * æŠ¥è¡¨-解析
     *
     * @param recordDte           ä¸šåŠ¡æ•°æ®dte
     * @param totalStatisticsFlag æ˜¯å¦åˆè®¡æ ‡è¯†
     * @param reportConfigMap     æŠ¥è¡¨é…ç½®ç¼“å­˜map
     * @param tableStyle
     * @param recordDte            ä¸šåŠ¡æ•°æ®dte
     * @param totalName            æ€»è®¡åç§°
     * @param reportConfigMap      æŠ¥è¡¨é…ç½®ç¼“å­˜map
     * @param unpivotInfoContainer è¡Œåˆ—转换信息
     * @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();
    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);
        int totalColCount = reportConfigMap.get(0).size();
        List<List<ReportColumn>> reportRows = getDataArea(reportConfigMap, headAndTailTitleDataMap, recordDte, totalName, unpivotInfoContainer);
        int totalColCount = reportConfigMap.get(0).size() + unpivotInfoContainer.size() - 1;
        // å¤´éƒ¨æ ‡é¢˜åŒº
        StringBuilder headTitleHtml = null;
        if (!reportConfigMap.get(1).isEmpty()) {
            headTitleHtml = dataListReportService.getTitleHtml(reportConfigMap.get(1), totalColCount, headAndTailTitleDataMap, "head");
            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;
        // åº•部标题区
        StringBuilder tailTitleHtml = null;
        if (!reportConfigMap.get(3).isEmpty()) {
            tailTitleHtml = dataListReportService.getTitleHtml(reportConfigMap.get(3), totalColCount, headAndTailTitleDataMap, "tail");
            reportColumnList[2] = (dataListReportService.getTitleRows(reportConfigMap.get(3), totalColCount, headAndTailTitleDataMap, "tail"));
        }
        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>");
        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;
//        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;
    }
    /**
@@ -131,7 +85,8 @@
     * @param totalName               æ€»è®¡åç§°ï¼Œéžç©º-需要总计
     * @return
     */
    private String getDataAreaHtml(Map<Integer, List<JSONObject>> reportConfigMap, Map<String, Set<String>> headAndTailTitleDataMap, DataTableEntity recordDte, String totalName) {
    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));
        // èŽ·å–æŒ‡å®šæ•°æ®é›†ä¸­åŒ…å«çš„æ•°æ®åŒºå­—æ®µé›†åˆ
@@ -141,358 +96,42 @@
        // ç»Ÿè®¡map
        Map<JSONObject, JSONObject> statisticsMap = Maps.newLinkedHashMap();
        StringBuilder dataAreaHtml = new StringBuilder(1024);
        // æ ‡é¢˜
        dataAreaHtml.append(getDataAreaTitleHtml(dataAreaFieldConfigMap));
        // å†…容
        dataAreaHtml.append(getDataAreaDataHtml(dataAreaFieldConfigMap, recordDte, headAndTailTitleDataMap, headAndTailFieldSet, statisticsMap, totalName));
        return dataAreaHtml.toString();
    }
    private ReportEntity getDataArea(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();
        List<ReportColumn> reportHeader = getReportHeader(dataAreaFieldConfigMap);
        List<List<ReportColumn>> reportData = getReportData(dataAreaFieldConfigMap, recordDte, headAndTailTitleDataMap, headAndTailFieldSet, statisticsMap, totalName);
        ReportEntity report = new ReportEntity();
        report.addReportHeader(reportHeader);
        report.setReportData(reportData);
        return report;
    }
    private List<ReportColumn> getReportHeader(Map<String, JSONObject> dataAreaFieldConfigMap) {
        if (CollectionUtil.isEmpty(dataAreaFieldConfigMap)) {
            return null;
        // å°†è¡Œåˆ—转换的信息添加到数据区字段缓存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;
        }
        List<ReportColumn> reportColumnList = new ArrayList<>();
        dataAreaFieldConfigMap.forEach((k, v) -> {
            ReportColumn column = new ReportColumn();
            column.setContent(v.getString(CmnConst.ATTR_SHOW_NAME));
            column.setColumnWidth(NumberUtil.isNumber(v.getString(CmnConst.ATTR_WIDTH)) ? NumberUtil.parseInt(v.getString(CmnConst.ATTR_WIDTH)) : 0);
            reportColumnList.add(column);
        });
        // æ ‡é¢˜
        reportColumnList.add(getDataAreaTitle(newDataAreaFieldConfigMap));
        // å†…容
        List<List<ReportColumn>> dataAreaData = getDataAreaData(newDataAreaFieldConfigMap, recordDte, headAndTailTitleDataMap, headAndTailFieldSet, statisticsMap, totalName);
        reportColumnList.addAll(dataAreaData);
        return reportColumnList;
    }
    private List<List<ReportColumn>> getReportData(Map<String, JSONObject> dataAreaFieldConfigMap, DataTableEntity recordDte, Map<String, Set<String>> headAndTailTitleDataMap, Set<String> headAndTailFieldSet, Map<JSONObject, JSONObject> statisticsMap, String totalName) {
        List<List<ReportColumn>> reportData = new ArrayList<>();
        // æ•°æ®åŒºåˆ†ç»„统计字段名称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);
                }
            }
        });
        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);
            combineFlag = true;
            List<ReportColumn> columns = new ArrayList<>();
            for (Map.Entry<String, JSONObject> entry : dataAreaFieldConfigMap.entrySet()) {
                ReportColumn column = new ReportColumn();
                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) {
                            reportData.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);
                    if (NumberUtil.isNumber(paramKey)) {
                        column.setRowspan(NumberUtil.parseInt(paramKey));
                    } else {
                        column.addProperty(paramKey, "rowspan");
                    }
                    replaceMap.put(paramKey, "1");
                }
                // class
                if (!StringUtils.isEmpty(dataAreaFieldConfigObj.getString(CmnConst.ATTR_URL))) {
                    //子报表
                    String url = dataAreaFieldConfigObj.getString(CmnConst.ATTR_URL);
                    url = SystemParamReplace.replaceParams(url, recordFse);
                    column.setSubReport("true".equals(dataAreaFieldConfigObj.getString("~isSubReport~")));
                    if (!column.isSubReport()) {
                        column.setPenetrate(true);
                        column.setPenetrateProperty(url);
                    } else {
                        column.setSubReportProperty(url);
                    }
                }
                String attrValue = recordFse.getString(dataAreaFieldName + CmnConst.PROMPT_REAL_VALUE_TAIL);
                if (StringUtils.isEmpty(attrValue)) {
                    attrValue = recordFse.getString(dataAreaFieldName);
                }
                column.addProperty(dataAreaFieldName, attrValue);
                // æ ¼å¼
                value = dataListReportService.formatValue(dataAreaFieldConfigObj, value);
                column.setContent(value);
                columns.add(column);
            }
            reportData.add(columns);
            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) {
                    reportData.add(getDataAreaGroupStatisticsFieldStatisticsRow(dataAreaClosestGroupStatisticsFieldValueMap.get(tempFieldName), statisticsMap, dataAreaFieldConfigMap, tempFieldName, preFse, dataAreaGroupFieldNameList, replaceMap, dataAreaGroupFieldRecordObj));
                }
            }
        }
        // æ€»è®¡
        if (!StringUtils.isEmpty(totalName)) {
            reportData.add(getDataAreaTotalStatistics(statisticsMap, dataAreaFieldConfigMap, dataAreaGroupFieldNameList, preFse, dataAreaGroupFieldRecordObj, totalName));
        }
        reportData.stream().forEach(item -> {
            item.stream().forEach(column -> {
                for (Map.Entry<String, String> entry : replaceMap.entrySet()) {
                    column.replace(entry.getKey(), entry.getValue());
                }
            });
        });
        return reportData;
    }
    /**
     * èŽ·å–æ€»è®¡è¡Œ
     *
     * @param statisticsMap               ç»Ÿè®¡map
     * @param dataAreaFieldConfigMap      æ•°æ®åŒºå­—段缓存map
     * @param dataAreaGroupFieldNameList  æ•°æ®åŒºåˆ†ç»„字段名称list
     * @param preFse                      æœ€è¿‘操作的数据fse
     * @param dataAreaGroupFieldRecordObj æ•°æ®åŒºåˆ†ç»„字段记录obj
     * @param totalName                   æ€»è®¡åç§°
     * @return
     */
    private List<ReportColumn> getDataAreaTotalStatistics(Map<JSONObject, JSONObject> statisticsMap, Map<String, JSONObject> dataAreaFieldConfigMap, List<String> dataAreaGroupFieldNameList, FieldSetEntity preFse, JSONObject dataAreaGroupFieldRecordObj, String totalName) {
        List<ReportColumn> columns = new ArrayList<>();
//        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 null;
        }
        int index = 0;
        for (Map.Entry<String, JSONObject> entry : dataAreaFieldConfigMap.entrySet()) {
            ReportColumn column = new ReportColumn();
            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);
                column.setContent(value);
//                html.append("<td>").append(value == null ? "" : value).append("</td>");
            } else {
                if (index == 1) {
                    column.setColspan(dataAreaGroupFieldNameList.size());
                    column.setContent(totalName);
//                    html.append("<td colspan=\"").append(dataAreaGroupFieldNameList.size()).append("\">").append(totalName).append("</td>");
                }
            }
            columns.add(column);
        }
//        html.append("\n</tr>");
        return columns;
    }
    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> columns = new ArrayList<>();
//        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()) {
            ReportColumn column = new ReportColumn();
            index++;
            dataAreaFieldName = entry.getKey();
            if (!flag) {
                if (dataAreaGroupFieldNameList.contains(dataAreaFieldName)) {
                    keyObj.put(dataAreaFieldName, recordFse.getString(dataAreaFieldName));
                    if (dataAreaFieldName.equals(tempFieldName)) {
                        column.setColspan(dataAreaGroupFieldNameList.size() - index + 1);
                        column.setContent(waitStatisticsValue + CmnConst.STATISTICS_NAME);
                    }
                    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);
                    column.setContent(value);
//                    html.append("<td>").append(value == null ? "" : value).append("</td>");
                }
            }
            columns.add(column);
        }
//        html.append("\n</tr>");
        dealReplaceMapAddRowspan(replaceMap, needAddRowspanDataAreaGroupFieldNameList, recordFse, false);
        return null;
    }
    /**
     * èŽ·å–æ ‡é¢˜
@@ -500,14 +139,20 @@
     * @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("\">");
    private List<ReportColumn> getDataAreaTitle(Map<String, JSONObject> dataAreaFieldConfigMap) {
        List<ReportColumn> columnRow = new ArrayList<>();
        dataAreaFieldConfigMap.forEach((dataAreaFieldName, dataAreaFieldConfigObj) -> {
            html.append("<td>").append(dataListReportService.dealTdWidth(dataAreaFieldConfigObj, dataAreaFieldConfigObj.getString(CmnConst.ATTR_SHOW_NAME))).append("</td>");
            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);
        });
        html.append("</tr>");
        return html;
        return columnRow;
    }
    /**
@@ -520,7 +165,8 @@
     * @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) {
    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
@@ -534,8 +180,9 @@
            }
        });
        StringBuilder dataAreaDataHtml = new StringBuilder(1024);
        StringBuilder curRowHtml = new StringBuilder(256);
//        StringBuilder dataAreaDataHtml = new StringBuilder(1024);
//        StringBuilder curRowHtml = new StringBuilder(256);
        List<ReportColumn> curRowColumn = new ArrayList<>();
        FieldSetEntity recordFse;
        FieldSetEntity preFse = null;
        String dataAreaFieldName;
@@ -550,15 +197,18 @@
        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);
            curRowHtml.setLength(0);
//            curRowHtml.setLength(0);
            curRowColumn = new ArrayList<>();
            String rowUuid = IdUtil.simpleUUID();
            curRowHtml.append("\n<tr rowIndex=\"" + (i + 1) + "\" id=\"" + rowUuid + "\" class=\"").append(CmnConst.CLASS_TR_DATA_COMMON).append("\">\n    ");
//            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();
@@ -598,7 +248,7 @@
                    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));
                            reportColumnList.add(getDataAreaGroupStatisticsFieldStatisticsRow(dataAreaClosestGroupStatisticsFieldValueMap.get(tempFieldName), statisticsMap, dataAreaFieldConfigMap, tempFieldName, preFse, dataAreaGroupFieldNameList, replaceMap, dataAreaGroupFieldRecordObj));
                            dataAreaClosestGroupStatisticsFieldValueMap.remove(tempFieldName);
                        }
                    }
@@ -640,28 +290,55 @@
                        }
                    }
                    paramKey = dataListReportService.concat(keyObj, CmnConst.ATTR_ROWSPAN);
                    curRowHtml.append("<td rowspan=\"").append(paramKey).append("\"");
//                    curRowHtml.append("<td rowspan=\"").append(paramKey).append("\"");
                    currentColumn.setRowspan(paramKey);
                    replaceMap.put(paramKey, "1");
                } else {
                    curRowHtml.append("<td");
                }
//                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("\"");
                    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);
                }
                curRowHtml.append(" ").append(dataAreaFieldName).append("=\"").append(attrValue).append("\"");
                curRowHtml.append(">");
                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>");
//                curRowHtml.append(value == null ? "" : value);
//                curRowHtml.append("</td>");
                currentColumn.setContent(value);
                curRowColumn.add(currentColumn);
                currentColumn = new ReportColumn();
            }
            curRowHtml.append("\n</tr>");
            dataAreaDataHtml.append(curRowHtml);
//            curRowHtml.append("\n</tr>");
//            dataAreaDataHtml.append(curRowHtml);
            reportColumnList.add(curRowColumn);
            preFse = recordFse;
        }
@@ -677,22 +354,34 @@
            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));
                    reportColumnList.add(getDataAreaGroupStatisticsFieldStatisticsRow(dataAreaClosestGroupStatisticsFieldValueMap.get(tempFieldName), statisticsMap, dataAreaFieldConfigMap, tempFieldName, preFse, dataAreaGroupFieldNameList, replaceMap, dataAreaGroupFieldRecordObj));
                }
            }
        }
        // æ€»è®¡
        if (!StringUtils.isEmpty(totalName)) {
            dataAreaDataHtml.append(getDataAreaTotalStatisticsHtml(statisticsMap, dataAreaFieldConfigMap, dataAreaGroupFieldNameList, preFse, dataAreaGroupFieldRecordObj, 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) {
                        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;
    }
    /**
@@ -781,10 +470,9 @@
     * @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    ");
    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;
@@ -800,8 +488,12 @@
                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>");
                        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);
@@ -812,7 +504,8 @@
                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>");
//                        html.append("<td></td>");
                        columnRow.add(new ReportColumn());
                    }
                } else {
                    keyObj.put(CmnConst.ATTR_FIELD_INFO, dataListReportService.fieldName2FieldInfo(dataAreaFieldName));
@@ -832,13 +525,13 @@
                    }
                    // æ ¼å¼
                    value = dataListReportService.formatValue(dataAreaFieldConfigObj, value);
                    html.append("<td>").append(value == null ? "" : value).append("</td>");
//                    html.append("<td>").append(value == null ? "" : value).append("</td>");
                    columnRow.add(new ReportColumn(value == null ? "" : value));
                }
            }
        }
        html.append("\n</tr>");
        dealReplaceMapAddRowspan(replaceMap, needAddRowspanDataAreaGroupFieldNameList, recordFse, false);
        return html;
        return columnRow;
    }
    /**
@@ -852,16 +545,16 @@
     * @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);
    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    ");
//        html.append("\n<tr class=\"").append(CmnConst.CLASS_TR_DATA_STATISTICS).append("\">\n    ");
        if (preFse == null) {
            return html.toString();
            return null;
        }
        int index = 0;
        for (Map.Entry<String, JSONObject> entry : dataAreaFieldConfigMap.entrySet()) {
@@ -887,15 +580,17 @@
                }
                // æ ¼å¼
                value = dataListReportService.formatValue(dataAreaFieldConfigObj, value);
                html.append("<td>").append(value == null ? "" : value).append("</td>");
                reportColumns.add(new ReportColumn(value == null ? "" : value));
            } else {
                if (index == 1) {
                    html.append("<td colspan=\"").append(dataAreaGroupFieldNameList.size()).append("\">").append(totalName).append("</td>");
                    ReportColumn column = new ReportColumn();
                    column.setColspan(dataAreaGroupFieldNameList.size());
                    column.setContent(totalName);
                    reportColumns.add(column);
                }
            }
        }
        html.append("\n</tr>");
        return html.toString();
        return reportColumns;
    }
    /**
src/main/java/com/product/server/report/service/DataListReportService.java
@@ -1,8 +1,6 @@
package com.product.server.report.service;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.util.NumberUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
@@ -26,8 +24,13 @@
import com.product.server.report.config.ReportCode;
import com.product.server.report.entity.ReportColumn;
import com.product.server.report.entity.ReportEntity;
import com.product.server.report.util.QuerySqlParseUtil;
import com.product.util.BaseUtil;
import com.product.util.SystemParamReplace;
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;
@@ -66,7 +69,7 @@
    private SystemDataExportService exportService;
    public void outReportExcel(HttpServletResponse response, FieldSetEntity fse) throws BaseException, IOException {
        ReportEntity reportEntity = getReportEntity(fse);
        ReportEntity reportEntity = getReport(fse);
        List<List<ReportColumn>> reportHeader = reportEntity.getReportHeader();
        List<List<String>> headerTemp = processingMergeData(reportHeader);
@@ -97,9 +100,9 @@
            List<ReportColumn> columns = data.get(i);
            for (ReportColumn column : columns) {
                //跨行
                int rowspan = column.getRowspan() < 1 ? 1 : column.getRowspan();
                int rowspan = column.getRowspanInt() < 1 ? 1 : column.getRowspanInt();
                //跨列
                int colspan = column.getColspan() < 1 ? 1 : column.getColspan();
                int colspan = column.getColspanInt() < 1 ? 1 : column.getColspanInt();
                List<String> currentCell = new ArrayList<>();
                for (int k = 0; k < colspan; k++) {
                    currentCell.add(column.getContent(true));
@@ -107,7 +110,6 @@
                for (int j = 0; j < rowspan; j++) {
                    resultData.get(j + i).addAll(currentCell);
                }
                System.out.println(resultData);
            }
        }
        return resultData;
@@ -133,36 +135,7 @@
    }
    /**
     * @param target
     * @param content
     * @param colspan
     * @param rowspan
     * @param currentColspan
     * @param currentRowsSpan
     */
    private void rowspanAndColspan(String[][] target, String content, int colspan, int rowspan, int currentColspan, int currentRowsSpan) {
        int k = currentColspan;
        int i = currentRowsSpan;
        if (colspan > 1) {
            for (int j = 1; j < colspan; j++) {
                int index = j + k;
                while (target[i][index] != null) {
                    index++;
                }
                target[i][index] = content;
            }
        }
        if (rowspan > 1) {
            for (int j = 1; j < rowspan; j++) {
                int index = i + k;
                while (target[index][k] != null) {
                    index++;
                }
                target[index][k] = content;
            }
        }
    }
    /**
     * åŠ è½½æ‰€æœ‰ç¼“å­˜
@@ -244,8 +217,8 @@
                fieldConfigObj = new JSONObject();
                areaList.add(fieldConfigObj);
            } else {
                fieldConfigObj = areaList.get(areaList.size() - 1);
            }
                fieldConfigObj = areaList.get(areaList.size() - 1);
            }
            fieldConfigObj.put(attrFse.getString(CmnConst.ATTR_NAME), attrFse.getString(CmnConst.ATTR_VALUE));
            fieldConfigObj.put(CmnConst.ATTR_X, x);
            fieldConfigObj.put(CmnConst.ATTR_Y, y);
@@ -360,14 +333,13 @@
        }
    }
    /**
     * èŽ·å–æŠ¥è¡¨
     *
     * @return
     */
    public ReportEntity getReportEntity(FieldSetEntity fse) {
        ReportEntity report = null;
    public ReportEntity getReport(FieldSetEntity fse) {
        ReportEntity reportEntity = new ReportEntity();
        String reportConfigUUID = fse.getUUID();
        if (!StringUtils.isEmpty(fse.getString("~report_config_uuid~"))) {
            //子报表会传入此key作为报表的uuid è§„避参数中有uuid的key
@@ -439,9 +411,8 @@
        FieldSetEntity reportSourceFse = reportSourceDte.getFieldSetEntity(0);
        int curPage = fse.getInteger(CmnConst.CPAGE) == null ? 1 : fse.getInteger(CmnConst.CPAGE);
        JSONObject resultObj = new JSONObject();
//        JSONObject resultObj = new JSONObject();
        // é¦–次加载,默认添加条件
        Map<String, Map<String, String>> outerMap = Maps.newHashMap();
        if (fse.getBoolean(CmnConst.FIRST_LOAD)) {
            DataTableEntity allFilterDte = getDefaultSearchFilter(reportSourceFse.getUUID());
            Map<String, DataTableEntity> subMap = Maps.newHashMap();
@@ -451,7 +422,7 @@
            DataTableEntity defaultFilterDte = new DataTableEntity();
            FieldSetEntity tempFse;
            Map<String, Map<String, String>> outerMap = Maps.newHashMap();
            Map<String, String> innerMap;
            for (int i = 0; i < allFilterDte.getRows(); i++) {
                tempFse = allFilterDte.getFieldSetEntity(i);
@@ -466,22 +437,18 @@
                outerMap.put(tempFse.getString(CmnConst.FIELD_NAME), innerMap);
            }
//            resultObj.put("filterInfo", outerMap);
            reportEntity.setFilterInfo(outerMap);
            if (!DataTableEntity.isEmpty(defaultFilterDte)) {
                subMap.put("systemSeniorQueryString", defaultFilterDte);
            }
            fse.setSubData(subMap);
        }
        DataTableEntity recordDte = getRecordDte(sort, curPage, reportSourceFse, fse, reportConfigFse, null);
        List<String> unpivotInfoContainer = Lists.newArrayList();
        DataTableEntity recordDte = getRecordDte(sort, curPage, reportSourceFse, fse, reportConfigFse, null, unpivotInfoContainer);
        // æ˜¯å¦æ·»åŠ æ€»åˆè®¡
        boolean totalStatisticsFlag = "1".equalsIgnoreCase(reportConfigFse.getString(CmnConst.LAST_TOTAL));
        String totalName = totalStatisticsFlag ? (StringUtils.isEmpty(reportConfigFse.getString(CmnConst.TOTAL_NAME)) ? "总计" : reportConfigFse.getString(CmnConst.TOTAL_NAME)) : "";
//        JSONObject checkObj = checkRecordDte(recordDte);
//        if (CmnConst.FALSE.equals(checkObj.getString(CmnConst.RETURN_ATTR_RESULT))) {
//            return checkObj;
//        }
//        StringBuilder tableStyle = new StringBuilder(32);
//        String widthType = reportConfigFse.getString(CmnConst.REPORT_WIDTH_TYPE);
@@ -493,50 +460,46 @@
//                tableStyle.append(" style=\"width:").append(width).append("px\"");
//            }
//        }
        List<List<ReportColumn>>[] report = null;
        if (CmnConst.REPORT_TYPE_COMMON.equals(reportType)) {
            report = commonReportService.getReportEntity(recordDte, totalName, reportConfigMap);
            report.setFilterInfo(outerMap);
            report = commonReportService.getReport(recordDte, totalName, reportConfigMap, unpivotInfoContainer);
        } else if (CmnConst.REPORT_TYPE_GROUP.equals(reportType)) {
            // ç‰¹æ®Šå¤„理额外查询内容
            recordDte.addFieldSetEntity(getRecordDte(sort, curPage, reportSourceFse, fse, reportConfigFse, reportConfigMap));
            report = groupReportService.getReportEntity(recordDte, totalName, reportConfigMap);
//            resultObj.putAll(groupReportService.getReport(recordDte, totalName, reportConfigMap, tableStyle));
            recordDte.addFieldSetEntity(getRecordDte(sort, curPage, reportSourceFse, fse, reportConfigFse, reportConfigMap, null));
            report = groupReportService.getReport(recordDte, totalName, reportConfigMap);
        }
        report.setReportConfigUid(reportConfigFse.getUUID());
        report.setReportName(reportConfigFse.getString(CmnConst.REPORT_NAME));
//        report.setFilterInfo(outerMap);
        if (CmnConst.FALSE.equals(resultObj.getString(CmnConst.RETURN_ATTR_RESULT))) {
            resultObj.put(CmnConst.RETURN_ATTR_RESULT, true);
            resultObj.put(CmnConst.RETURN_ATTR_MESSAGE, "获取报表失败!");
        if (report != null) {
            List<List<ReportColumn>> head = report[0];
            List<List<ReportColumn>> data = report[1];
            List<List<ReportColumn>> tail = report[2];
            reportEntity.setReportHeader(head);
            reportEntity.setReportData(data);
            reportEntity.setReportTail(tail);
        }
        reportEntity.setReportConfigUid(reportConfigFse.getUUID());
        reportEntity.setReportName(reportConfigFse.getString(CmnConst.REPORT_NAME));
        // åˆ†é¡µå‚æ•°
        SQLEntity sqlEntity = recordDte.getSqle();
        if ("1".equals(reportConfigFse.getString(CmnConst.IS_PAGE)) && sqlEntity != null) {
            reportEntity.setPage(true);
            reportEntity.setPageIndex(curPage);
            reportEntity.setTotalCount(sqlEntity.getTotalCount());
            reportEntity.setPageSize(StringUtils.isEmpty(reportConfigFse.getString(CmnConst.PAGE_SIZE)) ? 0 : reportConfigFse.getInteger(CmnConst.PAGE_SIZE));
        } else {
            // åˆ†é¡µå‚æ•°
            SQLEntity sqlEntity = recordDte.getSqle();
            if ("1".equals(reportConfigFse.getString(CmnConst.IS_PAGE)) && sqlEntity != null) {
                report.setPage(true);
                report.setTotalCount(sqlEntity.getTotalCount());
                report.setPageSize(StringUtils.isEmpty(reportConfigFse.getString(CmnConst.PAGE_SIZE)) ? 0 : reportConfigFse.getInteger(CmnConst.PAGE_SIZE));
                report.setPageIndex(curPage);
//                resultObj.put(CmnConst.IS_PAGE, 1);
//                resultObj.put(CmnConst.CPAGE, curPage);
//                resultObj.put("totalCount", sqlEntity.getTotalCount());
//                resultObj.put("totalpage", sqlEntity.getTotalpage());
//                resultObj.put("pagesize", StringUtils.isEmpty(reportConfigFse.getString(CmnConst.PAGE_SIZE)) ? 0 : reportConfigFse.getInteger(CmnConst.PAGE_SIZE));
            }
            reportEntity.setPage(false);
        }
//        if (!DataTableEntity.isEmpty(recordDte)) {
//            resultObj.put("current_page_count", recordDte.getRows());
//
//        }
        report.setSystemFieldMeta(getSearchInfo(reportSourceFse.getUUID()));
        report.setReportType(reportConfigFse.getString("type_uuid"));
//        resultObj.put("systemFieldMeta", );
//        resultObj.put("report_type", reportConfigFse.getString("type_uuid"));
//        System.out.println(resultObj.getString("html"));
        return report;
        reportEntity.setReportType(reportConfigFse.getString("type_uuid"));
        reportEntity.setSystemFieldMeta(getSearchInfo(reportSourceFse.getUUID()));
        return reportEntity;
    }
    /**
     * èŽ·å–æŠ¥è¡¨ç¼“å­˜ä¿¡æ¯
@@ -578,12 +541,17 @@
     * @param reportConfigFse
     * @return
     */
    private DataTableEntity getRecordDte(StringBuilder sort, int curPage, FieldSetEntity
            reportSourceFse, FieldSetEntity fse, FieldSetEntity
                                                 reportConfigFse, Map<Integer, List<JSONObject>> reportConfigMap) {
    private DataTableEntity getRecordDte(StringBuilder sort, int curPage, FieldSetEntity reportSourceFse, FieldSetEntity fse, FieldSetEntity reportConfigFse, Map<Integer, List<JSONObject>> reportConfigMap, Collection<String> unpivotInfoContainer) {
        boolean spTimeFlag = reportConfigMap != null;
        String sql;
        String sqlText = reportSourceFse.getString(CmnConst.SQL_TEXT);
        Map<String, List<String>> queryFilterMap = queryFilterService.getQueryFilterMore(fse);
        // [=table_name=]写法处理——替换为对应的with语句,0-近期,1-所有
        int year = queryFilterMap == null || queryFilterMap.get("query_time") == null || "0".equals(queryFilterMap.get("query_time").get(0)) ? 2 : 0;
        sqlText = QuerySqlParseUtil.parseSplitTableSql(baseDao, sqlText, year);
        // {==}写法处理-替换为对应的行列转换语句
        sqlText = dealUnpivot(sqlText, queryFilterMap, unpivotInfoContainer);
        DataTableEntity recordDte = new DataTableEntity();
        if (spTimeFlag) {
@@ -593,7 +561,6 @@
            Set<String> spTimeStatisticsTypeSet = Sets.newHashSet();
            spTimeStatisticsTypeSet.addAll(getFieldAndSpTimeStatisticsTypeSet(baseFieldSet, spTimeStatisticsFieldMap, reportConfigMap.get(0)));
            spTimeStatisticsTypeSet.addAll(getFieldAndSpTimeStatisticsTypeSet(baseFieldSet, spTimeStatisticsFieldMap, reportConfigMap.get(2)));
            Map<String, List<String>> queryFilterMap = queryFilterService.getQueryFilterMore(fse);
            Set<String> selectedFieldSet;
            String headContent;
            DataTableEntity tempDte;
@@ -678,6 +645,154 @@
    }
    /**
     * å­æ–¹æ³•-处理行列转换的语句
     *
     * @param sql                  å¾…处理的sql
     * @param queryFilterMap       è¿‡æ»¤æ¡ä»¶map
     * @param unpivotInfoContainer è¡Œåˆ—转换容器,该方法会将处理好了的内容直接放入该容器中
     * @return
     */
    private String dealUnpivot(String sql, Map<String, List<String>> queryFilterMap, Collection<String> unpivotInfoContainer) {
        String regexp = "\\{=.+=\\}";
        List<String> suitList = getSuitContent(sql, regexp);
        String tempStr;
        List<String> fieldInfoList;
        String[] fieldArr;
        String filter;
        String startTimeStr;
        String finalTimeStr;
        int beginIndex;
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        List<String> timeList;
        for (String content : suitList) {
            tempStr = content.substring(2, content.length() - 2).trim();
            fieldInfoList = getSuitContent(tempStr, "\\{\\$((?!\\{\\$).)+\\$\\}");
            for (String fieldInfo : fieldInfoList) {
                fieldArr = fieldInfo.substring(2, fieldInfo.length() - 2).trim().split(" ");
                if (fieldArr.length != 3) {
                    continue;
                }
                if ("date".equalsIgnoreCase(fieldArr[1])) {
                    if (queryFilterMap == null || queryFilterMap.isEmpty()) {
                        return sql.replaceAll(regexp, "");
                    }
                    filter = queryFilterMap.get(fieldArr[0]).get(0);
                    beginIndex = filter.indexOf("str_to_date('") + "str_to_date('".length();
                    startTimeStr = filter.substring(beginIndex, beginIndex + 19);
                    beginIndex = filter.lastIndexOf("str_to_date('") + "str_to_date('".length();
                    finalTimeStr = filter.substring(beginIndex, beginIndex + 19);
                    try {
                        timeList = enumTime(dateFormat.parse(startTimeStr), dateFormat.parse(finalTimeStr), fieldArr[2]);
                    } catch (Exception e) {
                        SpringMVCContextHolder.getSystemLogger().error("transfer error: " + filter);
                        timeList = Lists.newArrayList();
                    }
                    unpivotInfoContainer.addAll(timeList);
                    tempStr = joinSql(timeList, tempStr, fieldInfo);
                } else if ("prompt".equalsIgnoreCase(fieldArr[1])) {
                    String promptName = fieldArr[2];
                    DataTableEntity dte;
                    StringBuilder promptSql = new StringBuilder();
                    FieldSetEntity fse;
                    if (promptName.startsWith("《")) {
                        promptSql.append("select dict_label show_value,dict_value real_value from product_sys_dict where is_used=1 and dict_name=?");
                        if (queryFilterMap != null && !queryFilterMap.isEmpty() && queryFilterMap.get(fieldArr[0]) != null && !StringUtils.isEmpty(queryFilterMap.get(fieldArr[0]).get(1))) {
                            promptSql.append(" and (dict_value").append(queryFilterMap.get(fieldArr[0]).get(1)).append(")");
                        }
                        dte = baseDao.listTable(promptSql.toString(), new Object[]{promptName.substring(1, promptName.length() - 1)});
                    } else {
                        fse = baseDao.getFieldSetEntityByFilter("product_sys_prompt", "prompt_name=?", new Object[]{promptName}, false);
                        promptSql.append("select ").append(fse.getString("view_fields")).append(" show_value,").append(fse.getString("value_field")).append(" real_value from ").append(fse.getString("source_table"));
                        if (!StringUtils.isEmpty(fse.getString("filter"))) {
                            promptSql.append(" where (").append(fse.getString("filter")).append(")");
                        }
                        if (queryFilterMap != null && !queryFilterMap.isEmpty() && queryFilterMap.get(fieldArr[0]) != null && !StringUtils.isEmpty(queryFilterMap.get(fieldArr[0]).get(1))) {
                            if (!StringUtils.isEmpty(fse.getString("filter"))) {
                                promptSql.append(" and");
                            } else {
                                promptSql.append(" where");
                            }
                            promptSql.append(" (").append(fse.getString("value_field")).append(queryFilterMap.get(fieldArr[0]).get(1)).append(")");
                        }
                        dte = baseDao.listTable(promptSql.toString(), new Object[]{});
                    }
                    for (int i = 0; i < dte.getRows(); i++) {
                        fse = dte.getFieldSetEntity(i);
                        unpivotInfoContainer.add(fse.getString("show_value"));
                    }
                    tempStr = joinSql(dte, tempStr, fieldInfo);
                }
            }
            sql = sql.replace(content, tempStr.contains("{$") ? "" : tempStr);
        }
        return sql;
    }
    private String joinSql(Collection<String> collection, String unpivotContent, String fieldInfo) {
        StringBuilder unpivotSb = new StringBuilder(128);
        for (String singleStr : collection) {
            if (unpivotSb.length() > 0) {
                unpivotSb.append("\n    ");
            }
            unpivotSb.append(unpivotContent.replace(fieldInfo, singleStr)).append(" '").append(singleStr).append("'");
        }
        return unpivotSb.toString();
    }
    private String joinSql(DataTableEntity dte, String unpivotContent, String fieldInfo) {
        StringBuilder unpivotSb = new StringBuilder(128);
        for (int i = 0; i < dte.getRows(); i++) {
            FieldSetEntity fse = dte.getFieldSetEntity(i);
            if (unpivotSb.length() > 0) {
                unpivotSb.append("\n    ");
            }
            unpivotSb.append(unpivotContent.replace(fieldInfo, fse.getString("real_value"))).append(" '").append(fse.getString("show_value")).append("'");
        }
        return unpivotSb.toString();
    }
    /**
     * æŒ‰ç…§æ—¶é—´æ­¥é•¿æžšä¸¾æ—¶é—´èŒƒå›´ä¹‹å†…的时间
     *
     * @param startTime
     * @param finalTime
     * @param formatInfo
     * @return
     */
    public static List<String> enumTime(Date startTime, Date finalTime, String formatInfo) {
        Calendar c1 = Calendar.getInstance();
        Calendar c2 = Calendar.getInstance();
        c1.setTime(startTime);
        c2.setTime(finalTime);
        int step = 1;
        String format = formatInfo;
        if (formatInfo.contains("[")) {
            step = Integer.parseInt(formatInfo.substring(formatInfo.indexOf("[") + 1, formatInfo.indexOf("]")));
            format = formatInfo.substring(0, formatInfo.indexOf("["));
        }
        SimpleDateFormat dateFormat = new SimpleDateFormat(format);
        List<String> timeList = Lists.newArrayList();
        if (formatInfo.contains("H")) {
            enumTime(c1, c2, timeList, dateFormat, step, Calendar.HOUR);
        } else if (formatInfo.contains("d")) {
            enumTime(c1, c2, timeList, dateFormat, step, Calendar.DATE);
        } else if (formatInfo.contains("M")) {
            enumTime(c1, c2, timeList, dateFormat, step, Calendar.MONTH);
        } else if (formatInfo.contains("y")) {
            enumTime(c1, c2, timeList, dateFormat, step, Calendar.YEAR);
        }
        return timeList;
    }
    private static void enumTime(Calendar c1, Calendar c2, List<String> timeList, SimpleDateFormat dateFormat, int step, int param) {
        if (c1.compareTo(c2) <= 0) {
            timeList.add(dateFormat.format(c1.getTime()));
            c1.add(param, step);
            enumTime(c1, c2, timeList, dateFormat, step, param);
        }
    }
    /**
     * å­æ–¹æ³•-getRecordDte-加载参照
     *
     * @param recordDte
@@ -718,9 +833,10 @@
     * @param sort
     * @return
     */
    private String replaceSqlContent(String sqlText, FieldSetEntity fse, StringBuilder sort, FieldSetEntity
            reportConfigFse, int curPage, String selectedFields, Map<String, List<String>> queryFilterMap) {
    private String replaceSqlContent(String sqlText, FieldSetEntity fse, StringBuilder sort, FieldSetEntity reportConfigFse, int curPage, String selectedFields, Map<String, List<String>> queryFilterMap) {
        queryFilterMap = queryFilterMap == null ? queryFilterService.getQueryFilterMore(fse) : queryFilterMap;
        // å¤„理掉近期和所有的过滤条件
        queryFilterMap.remove("query_time");
        selectedFields = StringUtils.isEmpty(selectedFields) ? "*" : selectedFields;
        // æ›¿æ¢sql中的系统参数
        sqlText = SystemParamReplace.replaceParams(sqlText, fse);
@@ -765,7 +881,7 @@
            }
        }
        // å‰”除异常区域
        sqlText = sqlText.replaceAll(CmnConst.REGEXP_FILTER_AREA, "").replaceAll(CmnConst.REGEXP_ALL_TYPE, "null").replaceAll(CmnConst.REGEXP_ALWAYS_TRUE, "");
        sqlText = sqlText.replaceAll(CmnConst.REGEXP_FILTER_AREA, "").replaceAll(CmnConst.REGEXP_ALL_TYPE, "null").replaceAll(CmnConst.REGEXP_ALWAYS_TRUE, "").replaceAll("(\\t*\\n){2,}", "\n");
        String queryFilter = "";
        if (signCount > 0) {
            for (Map.Entry<String, List<String>> entry : residueQueryFilterMap.entrySet()) {
@@ -778,7 +894,7 @@
                queryFilter += " (" + entry.getValue().get(2) + ") ";
            }
        } else {
            queryFilter = queryFilterMap.isEmpty() ? queryFilterService.getQueryFilter(fse) : queryFilterMap.get(CmnConst.SYSTEM_SENIOR_QUERY_STRING).get(0);
            queryFilter = queryFilterMap.isEmpty() || queryFilterMap.size() == 1 ? queryFilterService.getQueryFilter(fse) : queryFilterMap.get(CmnConst.SYSTEM_SENIOR_QUERY_STRING).get(0);
        }
        StringBuilder sql = new StringBuilder(1024);
@@ -794,8 +910,7 @@
        return sql.toString();
    }
    private String replaceSqlContent(String sqlText, FieldSetEntity fse, StringBuilder sort, FieldSetEntity
            reportConfigFse, int curPage) {
    private String replaceSqlContent(String sqlText, FieldSetEntity fse, StringBuilder sort, FieldSetEntity reportConfigFse, int curPage) {
        return replaceSqlContent(sqlText, fse, sort, reportConfigFse, curPage, null, null);
    }
@@ -808,8 +923,7 @@
     * @param queryFilterMap
     * @return
     */
    private String spReplaceSqlContent(String suitContent, String regexp, int num, Map<
            String, List<String>> queryFilterMap, Map<String, List<String>> residueQueryFilterMap) {
    private String spReplaceSqlContent(String suitContent, String regexp, int num, Map<String, List<String>> queryFilterMap, Map<String, List<String>> residueQueryFilterMap) {
        List<String> innerSuitList = getSuitContent(suitContent, regexp);
        String curField;
        String filter;
@@ -844,9 +958,17 @@
                        // ä¸ŠæœŸ
                        spDealFilterForPrePeriod(tempQueryFilterMap, queryFilterMap, curField);
                    }
                    filter = tempQueryFilterMap.get(curField).get(num);
                    suitContent = suitContent.replace(innerSuitContent, filter);
                } else if ("split".equals(spStatisticsWay)) {
                    // åªæ˜¯æ‹†åˆ†å¹¶æå–区域的值,只有获取范围的值的时候可以这样操作
                    List<String> paramList = tempQueryFilterMap.get(curField);
                    String[] timeArr = paramList.get(0).split("~");
                    suitContent = suitContent.replace(innerSuitContent, timeArr[Integer.parseInt(spStatisticsWayValue)]);
                } else {
                    filter = tempQueryFilterMap.get(curField).get(num);
                    suitContent = suitContent.replace(innerSuitContent, filter);
                }
                filter = tempQueryFilterMap.get(curField).get(num);
                suitContent = suitContent.replace(innerSuitContent, filter);
                residueQueryFilterMap.remove(curField);
                if (getSuitContent(suitContent, CmnConst.REGEXP_ALL_TYPE).isEmpty() && suitContent.matches(CmnConst.REGEXP_FILTER_AREA)) {
                    suitContent = suitContent.substring(2, suitContent.length() - 2);
@@ -888,9 +1010,7 @@
     * @param queryFilterMap
     * @param curFieldName
     */
    private void spDealFilterForLastYear
    (Map<String, List<String>> tempQueryFilterMap, Map<String, List<String>> queryFilterMap, String
            curFieldName) {
    private void spDealFilterForLastYear(Map<String, List<String>> tempQueryFilterMap, Map<String, List<String>> queryFilterMap, String curFieldName) {
        List<String> paramList = tempQueryFilterMap.get(curFieldName);
        for (int i = 0; i < paramList.size(); i++) {
            paramList.set(i, paramList.get(i).replace("str_to_date(", "date_add(str_to_date(")
@@ -911,9 +1031,7 @@
     * @param queryFilterMap
     * @param curFieldName
     */
    private void spDealFilterForPrePeriod
    (Map<String, List<String>> tempQueryFilterMap, Map<String, List<String>> queryFilterMap, String
            curFieldName) {
    private void spDealFilterForPrePeriod(Map<String, List<String>> tempQueryFilterMap, Map<String, List<String>> queryFilterMap, String curFieldName) {
        List<String> paramList = tempQueryFilterMap.get(curFieldName);
        String[] timeArr = paramList.get(0).split("~");
        try {
@@ -946,8 +1064,7 @@
     * @param dataList
     * @return
     */
    private Set<String> getFieldAndSpTimeStatisticsTypeSet
    (Set<String> baseFieldSet, Map<String, Map<String, JSONObject>> spTimeStatisticsFieldMap, List<JSONObject> dataList) {
    private Set<String> getFieldAndSpTimeStatisticsTypeSet(Set<String> baseFieldSet, Map<String, Map<String, JSONObject>> spTimeStatisticsFieldMap, List<JSONObject> dataList) {
        Set<String> spTimeStatisticsTypeSet = Sets.newHashSet();
        JSONObject curFieldObj;
        String fieldName;
@@ -1029,6 +1146,7 @@
                    tempObj.put("table_name", reportSourceFieldFse.getString(CmnConst.TABLE_NAME));
                    tempObj.put(CmnConst.SEARCH_TYPE, reportSourceFieldFse.getObject(CmnConst.SEARCH_TYPE));
                    tempObj.put("is_multiple", "2".equals(reportSourceFieldFse.getString(CmnConst.SEARCH_TYPE)));
                    tempObj.put("field_prompt_filter", reportSourceFieldFse.getString("field_prompt_filter"));
                }
            }
        }
@@ -1093,8 +1211,8 @@
     * @param locationType            ä½ç½®ç±»åž‹ï¼Œhead-头部,tail-尾部
     * @return
     */
    public StringBuilder getTitleHtml(List<JSONObject> list, int totalColCount, Map<
            String, Set<String>> headAndTailTitleDataMap, String locationType) {
    public List<List<ReportColumn>> getTitleRows(List<JSONObject> list, int totalColCount, Map<String, Set<String>> headAndTailTitleDataMap, String locationType) {
        List<List<ReportColumn>> reportColumnList = new ArrayList<>();
        StringBuilder html = new StringBuilder(1024);
        int colspan;
        int preRow = 0;
@@ -1102,7 +1220,6 @@
        int curRow;
        int curCol;
        String value;
        String style;
        for (JSONObject singleObj : list) {
            curRow = singleObj.getIntValue(CmnConst.ATTR_Y);
            curCol = singleObj.getIntValue(CmnConst.ATTR_X);
@@ -1110,15 +1227,6 @@
            colspan = colspan < 0 ? totalColCount : Math.max(1, colspan);
            value = replaceFormDataAndSysData(singleObj.getString(CmnConst.ATTR_SHOW_NAME), headAndTailTitleDataMap, singleObj);
            value = value == null ? "" : value;
            if ("1".equals(singleObj.getString(CmnConst.ATTR_IS_TITLE))) {
                style = " class=\"" + CmnConst.CLASS_TR_REPORT_TITLE + "\"";
            } else {
                if ("head".equals(locationType)) {
                    style = " class=\"" + CmnConst.CLASS_TR_HEAD + "\"";
                } else {
                    style = " class=\"" + CmnConst.CLASS_TR_TAIL + "\"";
                }
            }
            if (preRow < curRow) {
                if (preRow == 0) {
                    html.append("\n<tr ");
@@ -1126,7 +1234,7 @@
                    html.append(getAimNumTdPlaceholder(totalColCount - preCol, 1));
                    html.append("\n</tr>\n<tr ");
                }
                html.append(style).append(">\n    ");
                html.append(">\n    ");
                if (preRow == 0 && preCol == 0 && preCol < curCol - 1) {
                    html.append(getAimNumTdPlaceholder(curCol - preCol - 1, 1));
                }
@@ -1150,80 +1258,25 @@
        }
        html.append(getAimNumTdPlaceholder(totalColCount - preCol, 1));
        html.append("\n</tr>");
        return html;
    }
    /**
     * æŠ¥è¡¨-解析-获取头部或者尾部标题Html
     *
     * @param list                    æŠ¥è¡¨é…ç½®ä¿¡æ¯ï¼Œç¼“å­˜list
     * @param totalColCount           æ€»åˆ—æ•°
     * @param headAndTailTitleDataMap å¤´éƒ¨ã€å°¾éƒ¨æ ‡é¢˜åŒºæ•°æ®å­—段map
     * @param locationType            ä½ç½®ç±»åž‹ï¼Œhead-头部,tail-尾部
     * @return
     */
    public List<List<ReportColumn>> getTitle(List<JSONObject> list, int totalColCount, Map<
            String, Set<String>> headAndTailTitleDataMap, String locationType) {
        List<List<ReportColumn>> row = new ArrayList<>();
//        StringBuilder html = new StringBuilder(1024);
        int colspan;
        int preRow = 0;
        int preCol = 0;
        int curRow;
        int curCol;
        String value;
//        String style;
        List<ReportColumn> reportColumns = new ArrayList<>();
        for (JSONObject singleObj : list) {
            curRow = singleObj.getIntValue(CmnConst.ATTR_Y);
            curCol = singleObj.getIntValue(CmnConst.ATTR_X);
            colspan = singleObj.getIntValue(CmnConst.ATTR_COLSPAN);
            colspan = colspan < 0 ? totalColCount : Math.max(1, colspan);
            value = replaceFormDataAndSysData(singleObj.getString(CmnConst.ATTR_SHOW_NAME), headAndTailTitleDataMap, singleObj);
            value = value == null ? "" : value;
//            if ("1".equals(singleObj.getString(CmnConst.ATTR_IS_TITLE))) {
//                style = " class=\"" + CmnConst.CLASS_TR_REPORT_TITLE + "\"";
//            } else {
//                if ("head".equals(locationType)) {
//                    style = " class=\"" + CmnConst.CLASS_TR_HEAD + "\"";
//                } else {
//                    style = " class=\"" + CmnConst.CLASS_TR_TAIL + "\"";
//                }
//            }
            if (preRow < curRow) {
                if(!reportColumns.isEmpty()){
                    row.add(reportColumns);
                    reportColumns=new ArrayList<>();
                }
//                if (preRow != 0) {
//                    row.add(getAimNumTdPlaceholderColumn(totalColCount - preCol, 1));
//                }
//                if (preRow == 0 && preCol == 0 && preCol < curCol - 1) {
//                    row.add(getAimNumTdPlaceholderColumn(curCol - preCol - 1, 1));
//                }
                preCol = curCol;
        // è§£æžhtml
        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")));
                column.setContent(td.text());
                reportColumn.add(column);
            }
            if (preCol < curCol - 1) {
                row.add(getAimNumTdPlaceholderColumn(curCol - preCol - 1, 1));
            }
            if ("1".equals(singleObj.getString(CmnConst.ATTR_IS_TITLE))) {
                colspan = totalColCount;
            }
            ReportColumn column = new ReportColumn();
            column.setColspan(colspan);
            column.setContent(value);
            reportColumns.add(column);
            preRow = curRow;
            preCol = curCol + singleObj.getIntValue(CmnConst.ATTR_COLSPAN) - 1;
            if ("1".equals(singleObj.getString(CmnConst.ATTR_IS_TITLE))) {
                preCol = totalColCount;
            }
            reportColumnList.add(reportColumn);
        }
        row.add(reportColumns);
//        reportColumns.addAll(getAimNumTdPlaceholderColumn(totalColCount - preCol, 1));
//        row.add();
        return row;
        return reportColumnList;
    }
    /**
@@ -1261,8 +1314,7 @@
     * @param lastStageFlag          æ˜¯å¦æœ«çº§ï¼ˆæ•°æ®åŒºåˆ†ç»„字段末级和分组表头区字段都是末级才为末级)
     * @return
     */
    public JSONObject getStatisticsValueObj(JSONObject valueJsonObject, JSONObject dataAreaFieldConfigObj, String
            actualValue, String type, boolean lastStageFlag) {
    public JSONObject getStatisticsValueObj(JSONObject valueJsonObject, JSONObject dataAreaFieldConfigObj, String actualValue, String type, boolean lastStageFlag) {
        if (valueJsonObject == null) {
            valueJsonObject = new JSONObject();
        }
@@ -1323,8 +1375,7 @@
     * @param set
     * @param recordFse
     */
    public void getHeadAndTailTitleDataMap
    (Map<String, Set<String>> headAndTailTitleDataMap, Set<String> set, FieldSetEntity recordFse) {
    public void getHeadAndTailTitleDataMap(Map<String, Set<String>> headAndTailTitleDataMap, Set<String> set, FieldSetEntity recordFse) {
        for (String fieldName : set) {
            headAndTailTitleDataMap.computeIfAbsent(fieldName, k -> Sets.newLinkedHashSet()).add(recordFse.getString(fieldName));
        }
@@ -1466,10 +1517,6 @@
        return dealedValueSb.toString();
    }
    public int dealColumnWidth(JSONObject dataAreaFieldConfigObj) {
        return NumberUtil.isNumber(dataAreaFieldConfigObj.getString(CmnConst.ATTR_WIDTH)) ? NumberUtil.parseInt(dataAreaFieldConfigObj.getString(CmnConst.ATTR_WIDTH)) : 0;
    }
    /**
     * èŽ·å–td的属性
     *
@@ -1549,8 +1596,7 @@
     * @param singleObj
     * @return
     */
    public String replaceFormDataAndSysData(String
                                                    str, Map<String, Set<String>> headAndTailTitleDataMap, JSONObject singleObj) {
    public String replaceFormDataAndSysData(String str, Map<String, Set<String>> headAndTailTitleDataMap, JSONObject singleObj) {
        if (StringUtils.isEmpty(str)) {
            return "";
        }
@@ -1717,30 +1763,6 @@
     * @param num
     * @return
     */
    public List<ReportColumn> getAimNumTdPlaceholderColumn(int num, int type) {
        List<ReportColumn> columns = new ArrayList<>();
        if (num <= 0) {
            return columns;
        }
        if (type == 0) {
            for (int i = 0; i < num; i++) {
                columns.add(new ReportColumn());
            }
        } else {
            ReportColumn column = new ReportColumn();
            column.setColspan(num);
            columns.add(column);
        }
        return columns;
    }
    /**
     * èŽ·å–æŒ‡å®šä¸ªæ•°çš„td占位
     *
     * @param num
     * @return
     */
    public String getAimNumTdPlaceholder(int num, int type) {
        StringBuilder result = new StringBuilder(64);
        if (num <= 0) {
@@ -1798,8 +1820,7 @@
     * @param type      ç±»åž‹ï¼š1-获取目标属性,其他-排除目标属性
     * @return
     */
    public JSONObject extendJSONObject(JSONObject aimObj, JSONObject sourceObj, Collection<String> aimAttr,
                                       int type) {
    public JSONObject extendJSONObject(JSONObject aimObj, JSONObject sourceObj, Collection<String> aimAttr, int type) {
        if (aimObj == null) {
            aimObj = new JSONObject();
        }
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;
@@ -11,8 +12,11 @@
import com.product.core.spring.context.SpringMVCContextHolder;
import com.product.server.report.config.CmnConst;
import com.product.server.report.entity.ReportColumn;
import com.product.server.report.entity.ReportEntity;
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;
@@ -38,112 +42,54 @@
     * @param reportConfigMap æŠ¥è¡¨é…ç½®ç¼“å­˜map
     * @return èŽ·å–åˆ†ç»„æŠ¥è¡¨çš„è¯¦æƒ…
     */
    public ReportEntity getReportEntity(DataTableEntity recordDte, String totalName, Map<Integer, List<JSONObject>> reportConfigMap) {
    public List<List<ReportColumn>>[] getReport(DataTableEntity recordDte, String totalName, Map<Integer, List<JSONObject>> reportConfigMap) {
//        StringBuilder reportHtml = new StringBuilder(4096);
        ReportEntity report = new ReportEntity();
        List<List<ReportColumn>>[] reportColumnList = new List[]{new ArrayList(), new ArrayList(), new ArrayList()};
        // css
//        StringBuilder cssHtml = dataListReportService.getCssHtml();
//        StringBuilder cssHtml = dataListReportService.getCssHtml();
        // åˆ†ç»„表头区和数据区
//        StringBuilder groupAndDataAreaHtml = new StringBuilder(1024);
        List<List<ReportColumn>>[] rows = new List[2];
        Map<String, Set<String>> headAndTailTitleDataMap = Maps.newHashMap();
        int totalColCount = reportConfigMap.get(0).size();
        int dataAreaColCount = getGroupAndDataAreaAndReturnDataAreaColCount(rows, reportConfigMap, headAndTailTitleDataMap, recordDte, totalName);
        //数据区域数据
        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;
        // å¤´éƒ¨æ ‡é¢˜åŒº
        List<List<ReportColumn>> headTitle = null;
        if (!reportConfigMap.get(1).isEmpty()) {
            headTitle = dataListReportService.getTitle(reportConfigMap.get(1), totalColCount, headAndTailTitleDataMap, "head");
            reportColumnList[0] = dataListReportService.getTitleRows(reportConfigMap.get(1), totalColCount, headAndTailTitleDataMap, "head");
        }
        // åº•部标题区
        List<List<ReportColumn>> tailTitle = null;
        if (!reportConfigMap.get(3).isEmpty()) {
            tailTitle = dataListReportService.getTitle(reportConfigMap.get(3), totalColCount, headAndTailTitleDataMap, "tail");
        }
//        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>");
        if (rows[0] != null) {
            if (headTitle == null) {
                headTitle = new ArrayList<>();
        //从数据区域取出标题行放入头部标题区并将标题行从数据区域删除
        if (titleAreaRow > 0) {
            for (int i = 0; i < titleAreaRow; i++) {
                reportColumnList[0].add(dataAreaList.get(0));
                dataAreaList.remove(0);
            }
            headTitle.addAll(rows[0]);
        }
        report.setReportHeader(headTitle);
        report.setReportData(rows[1]);
        report.setReportTail(tailTitle);
        return report;
    }
    /**
     * æŠ¥è¡¨-解析
     *
     * @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);
        // css
        StringBuilder cssHtml = dataListReportService.getCssHtml();
        // åˆ†ç»„表头区和数据区
        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);
        // å¤´éƒ¨æ ‡é¢˜åŒº
        StringBuilder headTitleHtml = null;
        if (!reportConfigMap.get(1).isEmpty()) {
            headTitleHtml = dataListReportService.getTitleHtml(reportConfigMap.get(1), totalColCount, headAndTailTitleDataMap, "head");
        }
        // åº•部标题区
        StringBuilder tailTitleHtml = null;
        if (!reportConfigMap.get(3).isEmpty()) {
            tailTitleHtml = dataListReportService.getTitleHtml(reportConfigMap.get(3), totalColCount, headAndTailTitleDataMap, "tail");
            reportColumnList[2] = dataListReportService.getTitleRows(reportConfigMap.get(3), totalColCount, headAndTailTitleDataMap, "tail");
        }
        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>");
        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;
        return reportColumnList;
    }
    /**
     * æŠ¥è¡¨-解析-放入分组表头区和数据Html,返回列数
     *
     * @param groupAndDataAreaHtml    html容器
     * @param dataAreaList            æ•°æ®åŒºåŸŸæ•°æ®
     * @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) {
    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
@@ -235,120 +181,13 @@
        // æ•°æ®æ ‡é¢˜list
        List<JSONObject> dataTitleList = Lists.newArrayList();
        // èŽ·å–æ ‡é¢˜html
        groupAndDataAreaHtml.append(getDataAreaTitleHtml(dataTitleList, groupAreaFieldRecordObj, dataAreaFieldConfigMap, groupAreaRangeObj, dataAreaCommonStatisticsFieldNameList));
        List<List<ReportColumn>> dataAreaTitleRows = getDataAreaTitleRows(dataTitleList, groupAreaFieldRecordObj, dataAreaFieldConfigMap, groupAreaRangeObj, dataAreaCommonStatisticsFieldNameList);
        dataAreaList.addAll(dataAreaTitleRows);
        // èŽ·å–å†…å®¹html
        groupAndDataAreaHtml.append(getDataAreaDataHtml(dataTitleList, dataAreaFieldRecordObj, statisticsMap, totalName, dataAreaGroupFieldNameList, dataAreaFieldConfigMap));
        List<List<ReportColumn>> dataAreaDataRows = getDataAreaDataRows(dataTitleList, dataAreaFieldRecordObj, statisticsMap, totalName, dataAreaGroupFieldNameList, dataAreaFieldConfigMap);
        dataAreaList.addAll(dataAreaDataRows);
        return totalColCount;
    }
    /**
     * æŠ¥è¡¨-解析-放入分组表头区和数据,返回列数
     *
     * @param groupAndDataArea        å®¹å™¨
     * @param reportConfigMap         æŠ¥è¡¨ç¼“存数据map
     * @param headAndTailTitleDataMap å¤´éƒ¨ã€å°¾éƒ¨æ ‡é¢˜åŒºæ•°æ®å­—段map容器
     * @param recordDte               æ•°æ®æºé›†åˆ
     * @param totalName               æ€»è®¡åç§°
     * @return æ•°æ®åŒºæ€»åˆ—æ•°
     */
    private int getGroupAndDataAreaAndReturnDataAreaColCount(List<List<ReportColumn>>[] groupAndDataArea, 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));
        // åˆ†ç»„表头区分组统计字段名称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));
        });
        // æ•°æ®åŒºåˆ†ç»„统计字段名称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);
                }
            }
        });
        // èŽ·å–åˆ†ç»„è¡¨å¤´ç»Ÿè®¡å­—æ®µå¯¹åº”çš„æ•°æ®åŒºå­—æ®µmap
        Map<String, List<String>> groupAreaStatisticsField2DataAreaFieldMap = getGroupAreaStatisticsField2DataAreaFieldMap(groupAreaFieldConfigMap, dataAreaFieldConfigMap);
        // èŽ·å–åˆ†ç»„è¡¨å¤´åŒºæœ«è¡Œåˆ†ç»„å­—æ®µå¯¹åº”æ•°æ®åŒºå­—æ®µmap
        Map<String, List<String>> groupAreaLastStageField2DataAreaFieldMap = getGroupAreaLastStageField2DataAreaFieldMap(groupAreaFieldConfigMap, dataAreaFieldConfigMap, groupAreaRangeObj);
        // èŽ·å–æŒ‡å®šæ•°æ®é›†ä¸­åŒ…å«çš„æ•°æ®åŒºå­—æ®µé›†åˆ
        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();
        // åˆ†ç»„表头区数据obj
        JSONObject groupAreaFieldRecordObj = new JSONObject(Maps.newTreeMap((o1, o2) -> dataListReportService.compare(o1, o2)));
        // æ•°æ®åŒºåˆ†ç»„字段obj
        JSONObject dataAreaFieldRecordObj = new JSONObject(Maps.newLinkedHashMap());
        FieldSetEntity recordFse;
        for (int i = 0; i < recordDte.getRows(); i++) {
            recordFse = recordDte.getFieldSetEntity(i);
            // èŽ·å–å¤´éƒ¨ã€å°¾éƒ¨æ ‡é¢˜åŒºæ•°æ®å­—æ®µ
            dataListReportService.getHeadAndTailTitleDataMap(headAndTailTitleDataMap, headAndTailFieldSet, recordFse);
            // èŽ·å–åˆ†ç»„è¡¨å¤´åŒºæ•°æ®obj
            getGroupAreaFieldRecordObj(groupAreaFieldRecordObj, groupAreaFieldConfigMap, recordFse, groupAreaStatisticsField2DataAreaFieldMap, groupAreaLastStageField2DataAreaFieldMap);
            // èŽ·å–æ•°æ®åŒºåˆ†ç»„å­—æ®µobj
            getDataAreaGroupFieldRecordObj(dataAreaFieldRecordObj, dataAreaFieldConfigMap, recordFse);
            // èŽ·å–æ•°æ®åŒºç‰¹æ®Šå­—æ®µçš„ç»Ÿè®¡
            statisticsDataAreaSpField(statisticsMap, dataAreaFieldConfigMap, dataAreaSpStatisticsFieldNameList, recordFse);
            // èŽ·å–æ•°æ®åŒºæ™®é€šå­—æ®µçš„ç»Ÿè®¡
            statisticsDataAreaCommonField(statisticsMap, dataAreaFieldConfigMap, dataAreaCommonStatisticsFieldNameList, recordFse);
        }
        // èŽ·å–åˆ†ç»„è¡¨å¤´åŒºå’Œæ•°æ®åŒºæ€»åˆ—æ•°
        int totalColCount = getTotalColCount(groupAreaFieldRecordObj, dataAreaGroupFieldNameList.size(), dataAreaCommonStatisticsFieldNameList.size());
        // æ•°æ®æ ‡é¢˜list
        List<JSONObject> dataTitleList = Lists.newArrayList();
        // èŽ·å–æ ‡é¢˜html
        groupAndDataArea[0] = (getDataAreaTitle(dataTitleList, groupAreaFieldRecordObj, dataAreaFieldConfigMap, groupAreaRangeObj, dataAreaCommonStatisticsFieldNameList));
        // èŽ·å–å†…å®¹html
        groupAndDataArea[1] = (getDataAreaData(dataTitleList, dataAreaFieldRecordObj, statisticsMap, totalName, dataAreaGroupFieldNameList, dataAreaFieldConfigMap));
        return totalColCount;
        return new int[]{totalColCount, dataAreaTitleRows.size()};
    }
    /**
@@ -664,95 +503,6 @@
    }
    /**
     * èŽ·å–æ ‡é¢˜
     *
     * @param dataTitleList                         æ•°æ®æ ‡é¢˜list
     * @param groupAreaFieldRecordObj               åˆ†ç»„表头区字段记录obj
     * @param dataAreaFieldConfigMap                æ•°æ®åŒºå­—段缓存map
     * @param groupAreaRangeObj                     åˆ†ç»„表头去范围obj
     * @param dataAreaCommonStatisticsFieldNameList æ•°æ®åŒºæ™®é€šç»Ÿè®¡å­—段名称list
     * @return æ•°æ®æ ‡é¢˜html
     */
    private List<List<ReportColumn>> getDataAreaTitle(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();
//            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);
                }
            }
        }
        dataTitleList.addAll(groupAreaRangeTitleList.get(maxRow));
        dataTitleList.addAll(afterGroupAreaTitleList);
        List<JSONObject> firstList = Lists.newArrayList();
        firstList.addAll(beforeGroupAreaTitleList);
        firstList.addAll(groupAreaRangeTitleList.get(0));
        firstList.addAll(afterGroupAreaTitleList);
        groupAreaRangeTitleList.set(0, firstList);
//        StringBuilder html = new StringBuilder(1024);
        int rowspan;
        int colspan;
        String value;
        List<List<ReportColumn>> rowColumn = new ArrayList<>();
        for (List<JSONObject> rowList : groupAreaRangeTitleList) {
            List<ReportColumn> columns = new ArrayList<>();
//            html.append("\n<tr class=\"").append(CmnConst.CLASS_TR_DATA_TITLE).append("\">\n    ");
            for (JSONObject dataTitleObj : rowList) {
                ReportColumn column = new ReportColumn();
                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));
                    column.setColumnWidth(dataListReportService.dealColumnWidth(dataAreaFieldConfigMap.get(dataAreaFieldName)));
//                    value = dataListReportService.dealTdWidth(dataAreaFieldConfigMap.get(dataAreaFieldName), value);
                }
                column.setRowspan(rowspan);
                column.setColspan(colspan);
                column.setContent(value);
                columns.add(column);
//                html.append("<td rowspan=\"").append(rowspan).append("\" colspan=\"").append(colspan).append("\">").append(value == null ? "" : value).append("</td>");
            }
            rowColumn.add(columns);
//            html.append("\n</tr>");
        }
        return rowColumn;
    }
    /**
     * èŽ·å–æ ‡é¢˜html
     *
     * @param dataTitleList                         æ•°æ®æ ‡é¢˜list
@@ -762,7 +512,8 @@
     * @param dataAreaCommonStatisticsFieldNameList æ•°æ®åŒºæ™®é€šç»Ÿè®¡å­—段名称list
     * @return æ•°æ®æ ‡é¢˜html
     */
    private StringBuilder getDataAreaTitleHtml(List<JSONObject> dataTitleList, JSONObject groupAreaFieldRecordObj, Map<String, JSONObject> dataAreaFieldConfigMap, JSONObject groupAreaRangeObj, List<String> dataAreaCommonStatisticsFieldNameList) {
    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++) {
@@ -816,20 +567,27 @@
        int colspan;
        String value;
        for (List<JSONObject> rowList : groupAreaRangeTitleList) {
            html.append("\n<tr class=\"").append(CmnConst.CLASS_TR_DATA_TITLE).append("\">\n    ");
            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));
                    value = dataListReportService.dealTdWidth(dataAreaFieldConfigMap.get(dataAreaFieldName), value);
                    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));
                    }
                }
                html.append("<td rowspan=\"").append(rowspan).append("\" colspan=\"").append(colspan).append("\">").append(value == null ? "" : value).append("</td>");
                column.setContent(value);
                reportColumns.add(column);
            }
            html.append("\n</tr>");
            reportColumnList.add(reportColumns);
        }
        return html;
        return reportColumnList;
    }
    /**
@@ -935,7 +693,7 @@
     * @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) {
    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);
@@ -1037,144 +795,34 @@
        if (!StringUtils.isEmpty(totalName)) {
            html.append(getTotalStatisticsHtml(statisticsMap, dataTitleList, dataAreaFieldConfigMap, dataAreaGroupFieldNameList.size(), getSubCnt(dataAreaFieldRecordObj), totalName));
        }
        return html;
    }
    /**
     * èŽ·å–å†…å®¹html
     *
     * @param dataTitleList              æ•°æ®æ ‡é¢˜list
     * @param dataAreaFieldRecordObj     æ•°æ®åŒºå­—段记录obj
     * @param statisticsMap              ç»Ÿè®¡map
     * @param totalName                  æ€»è®¡åç§°ï¼Œéžç©º-需要总计
     * @param dataAreaGroupFieldNameList æ•°æ®åŒºåˆ†ç»„字段名称list
     * @param dataAreaFieldConfigMap     æ•°æ®åŒºå­—段缓存map
     * @return ä¸šåŠ¡æ•°æ®å†…å®¹html
     */
    private List<List<ReportColumn>> getDataAreaData(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<List<ReportColumn>> dataRows = new ArrayList<>();
        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++) {
            List<ReportColumn> columns = new ArrayList<>();
            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);
                    ReportColumn column = new ReportColumn();
                    column.setRowspan(rowspan);
                    column.setColspan(colspan);
                    column.setContent(value);
                    columns.add(column);
//                    html.append("<td rowspan=\"").append(rowspan).append("\" colspan=\"").append(colspan).append("\">").append(value == null ? "" : value).append("</td>");
                    index++;
        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);
            }
//            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");
                ReportColumn column = new ReportColumn();
                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);
                    String attrUrL = keyObj.getString(CmnConst.ATTR_URL);
                    if (!StringUtils.isEmpty(attrUrL)) {
                        column.setPenetrateProperty(attrUrL.toString());
                        column.setPenetrate(true);
                    }
                    for (String key : keyObj.keySet()) {
                        column.addProperty(key, keyObj.getString(key));
                    }
//                    html.append(dataListReportService.getTdAttrByObj(keyObj));
                    // æ ¼å¼
                    value = dataListReportService.formatValue(dataAreaFieldConfigObj, value);
                }
//                html.append(">").append(value == null ? "" : value).append("</td>");
                column.setContent(value);
                columns.add(column);
            }
//            html.append("\n</tr>");
            dataRows.add(columns);
            reportColumnList.add(reportColumn);
        }
        // æ€»è®¡
        if (!StringUtils.isEmpty(totalName)) {
            dataRows.add(getTotalStatistics(statisticsMap, dataTitleList, dataAreaFieldConfigMap, dataAreaGroupFieldNameList.size(), getSubCnt(dataAreaFieldRecordObj), totalName));
        }
        return dataRows;
        return reportColumnList;
    }
    /**
@@ -1275,86 +923,6 @@
            }
        }
        return row;
    }
    /**
     * èŽ·å–æ€»è®¡html
     *
     * @param statisticsMap           ç»Ÿè®¡map
     * @param dataTitleList           æ•°æ®æ ‡é¢˜list
     * @param dataAreaFieldConfigMap  æ•°æ®åŒºå­—段缓存map
     * @param dataAreaGroupFieldCount æ•°æ®åŒºåˆ†ç»„字段个数
     * @param dataAreaSubCnt          æ•°æ®åŒºä¸‹çº§åˆ†ç»„项数
     * @param totalName               æ€»è®¡åç§°
     * @return
     */
    private List<ReportColumn> getTotalStatistics(Map<JSONObject, JSONObject> statisticsMap, List<JSONObject> dataTitleList, Map<String, JSONObject> dataAreaFieldConfigMap, int dataAreaGroupFieldCount, int dataAreaSubCnt, String totalName) {
        List<ReportColumn> columns = new ArrayList<>();
//        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>");
        ReportColumn column = new ReportColumn();
        columns.add(column);
        column.setColspan(dataAreaGroupFieldCount);
        column.setContent(totalName);
        JSONObject dataTitleObj;
        JSONObject keyObj;
        JSONObject dataAreaFieldConfigObj;
        String statisticsType;
        JSONObject valueObj;
        String value;
        int groupAreaSubCnt;
        for (int i = 0; i < dataTitleList.size(); i++) {
            column = new ReportColumn();
            columns.add(column);
            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);
                String attrUrL = keyObj.getString(CmnConst.ATTR_URL);
                if (!StringUtils.isEmpty(attrUrL)) {
                    column.setPenetrateProperty(attrUrL.toString());
                    column.setPenetrate(true);
                }
                for (String key : keyObj.keySet()) {
                    column.addProperty(key, keyObj.getString(key));
                }
//                html.append(dataListReportService.getTdAttrByObj(keyObj));
                // æ ¼å¼
                value = dataListReportService.formatValue(dataAreaFieldConfigObj, value);
            }
            column.setContent(value);
//            html.append(">").append(value == null ? "" : value).append("</td>");
        }
//        html.append("\n</tr>");
        return columns;
    }
    /**
src/main/java/com/product/server/report/service/ReportConfigService.java
@@ -8,7 +8,6 @@
import com.product.admin.service.UpdateLoginUserInfoService;
import com.product.common.lang.StringUtils;
import com.product.core.cache.DataPoolCacheImpl;
import com.product.core.config.CoreConst;
import com.product.core.dao.BaseDao;
import com.product.core.entity.DataTableEntity;
import com.product.core.entity.FieldSetEntity;
@@ -24,595 +23,576 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.xml.crypto.Data;
import java.util.*;
import java.util.Date;
import java.util.List;
import java.util.Map;
@Component
public class ReportConfigService extends AbstractBaseService implements IReportConfigService {
    @Autowired
    BaseDao baseDao;
    @Autowired
    CodeService codeService;
    @Autowired
    public QueryFilterService queryFilterService;
    @Autowired
    public DataListReportService dataListReportService;
    @Autowired
    BaseDao baseDao;
    @Autowired
    CodeService codeService;
    @Autowired
    public QueryFilterService queryFilterService;
    @Autowired
    public DataListReportService dataListReportService;
    /**
     * æŠ¥è¡¨åˆ—表
     *
     * @param cpage
     * @param pageSize
     * @return
     */
    public DataTableEntity listReportConfig(Integer cpage, Integer pageSize, FieldSetEntity fse) {
        cpage = cpage == null ? 1 : cpage;
        pageSize = pageSize == null ? 20 : pageSize;
    /**
     * æŠ¥è¡¨åˆ—表
     *
     * @param cpage
     * @param pageSize
     * @return
     */
    public DataTableEntity listReportConfig(Integer cpage, Integer pageSize, FieldSetEntity fse) {
        cpage = cpage == null ? 1 : cpage;
        pageSize = pageSize == null ? 20 : pageSize;
        List<Object> paramList = Lists.newArrayList();
        StringBuilder sql = new StringBuilder(512);
        String queryFilter = " ";
        if(!BaseUtil.dataTableIsEmpty(fse.getSubDataTable("systemSeniorQueryString"))){
            queryFilter ="AND"+ queryFilterService.getQueryFilter(fse);
        }
        sql.append("\nSELECT a.uuid,a.type_uuid,a.is_valid,a.org_level_uuid,a.report_name,b.type_name,b.type_group")
                .append("\nFROM product_sys_report_config a")
                .append("\nLEFT JOIN product_sys_report_type_config b ON a.type_uuid = b.uuid")
                .append("\nwhere (function_uuid is null or function_uuid='') ")
                .append(queryFilter);
        List<Object> paramList = Lists.newArrayList();
        StringBuilder sql = new StringBuilder(512);
        sql.append("\nSELECT a.uuid,a.type_uuid,a.is_valid,a.org_level_uuid,a.report_name,b.type_name,b.type_group")
                .append("\nFROM product_sys_report_config a")
                .append("\nLEFT JOIN product_sys_report_type_config b ON a.type_uuid = b.uuid")
                .append("\nwhere (function_uuid is null or function_uuid='') ");
        if (!StringUtils.isEmpty(fse.getString(CmnConst.TYPE_UUID))) {
            sql.append("\nand b.type_group=?");
            paramList.add(fse.getString(CmnConst.TYPE_UUID));
        }
        return baseDao.listTable(sql.toString(), paramList.toArray(), pageSize, cpage);
    }
        if (!StringUtils.isEmpty(fse.getString(CmnConst.TYPE_UUID))) {
            sql.append("\nand b.type_group=? ");
            paramList.add(fse.getString(CmnConst.TYPE_UUID));
        }
        return baseDao.listTable(sql.toString(), paramList.toArray(), pageSize, cpage);
    }
    /**
     * æŠ¥è¡¨è¯¦æƒ…
     *
     * @param uuid
     * @return
     */
    public FieldSetEntity findReportConfig(String uuid) {
        StringBuilder sql = new StringBuilder(256);
        sql.append("\nselect report_area,cell_position_y,cell_position_x,attribute_name,report_type_attr_value")
                .append("\nfrom (")
                .append("\n    select report_area,cell_position_y,cell_position_x,report_type_attr_value,report_type_attr FROM product_sys_report_config_attribute ca")
                .append("\n    where report_config_uuid=?")
                .append("\n) ca")
                .append("\nleft join (")
                .append("\n    select uuid,attribute_name FROM product_sys_report_type_attribute where type_group='DataList'")
                .append("\n) ta on ca.report_type_attr=ta.uuid")
                .append("\nwhere attribute_name is not null ")
                .append("\norder by report_area,cell_position_y,cell_position_x");
        DataTableEntity tempDte = baseDao.listTable(sql.toString(), new Object[]{uuid});
        DataTableEntity reportConfigAttrDte = new DataTableEntity();
        FieldSetEntity tempFse;
        FieldSetEntity reportConfigAttrFse = new FieldSetEntity();
        String curReportArea;
        String curX;
        String curY;
        String preReportArea = "";
        String preX = "";
        String preY = "";
        for (int i = 0; i < tempDte.getRows(); i++) {
            tempFse = tempDte.getFieldSetEntity(i);
            curReportArea = tempFse.getString(CmnConst.ATTR_REPORT_AREA);
            curX = tempFse.getString(CmnConst.CELL_POSITION_X);
            curY = tempFse.getString(CmnConst.CELL_POSITION_Y);
            if (curReportArea == null || curX == null || curY == null) {
                continue;
            }
            if (!preReportArea.equals(curReportArea) || !preX.equals(curX) || !preY.equals(curY)) {
                reportConfigAttrFse = new FieldSetEntity();
                reportConfigAttrDte.addFieldSetEntity(reportConfigAttrFse);
                reportConfigAttrFse.setTableName(CmnConst.PRODUCT_SYS_REPORT_CONFIG_ATTRIBUTE);
                reportConfigAttrFse.setValue(CmnConst.ATTR_X, curX);
                reportConfigAttrFse.setValue(CmnConst.ATTR_Y, curY);
                reportConfigAttrFse.setValue(CmnConst.ATTR_REPORT_AREA, curReportArea);
            }
            reportConfigAttrFse.setValue(tempFse.getString(CmnConst.ATTRIBUTE_NAME), tempFse.getString(CmnConst.REPORT_TYPE_ATTR_VALUE));
            preReportArea = curReportArea;
            preX = curX;
            preY = curY;
        }
    /**
     * æŠ¥è¡¨è¯¦æƒ…
     *
     * @param uuid
     * @return
     */
    public FieldSetEntity findReportConfig(String uuid) {
        StringBuilder sql = new StringBuilder(256);
        sql.append("\nselect report_area,cell_position_y,cell_position_x,attribute_name,report_type_attr_value")
                .append("\nfrom (")
                .append("\n    select report_area,cell_position_y,cell_position_x,report_type_attr_value,report_type_attr FROM product_sys_report_config_attribute ca")
                .append("\n    where report_config_uuid=?")
                .append("\n) ca")
                .append("\nleft join (")
                .append("\n    select uuid,attribute_name FROM product_sys_report_type_attribute where type_group='DataList'")
                .append("\n) ta on ca.report_type_attr=ta.uuid")
                .append("\nwhere attribute_name is not null ")
                .append("\norder by report_area,cell_position_y,cell_position_x");
        DataTableEntity tempDte = baseDao.listTable(sql.toString(), new Object[]{uuid});
        DataTableEntity reportConfigAttrDte = new DataTableEntity();
        FieldSetEntity tempFse;
        FieldSetEntity reportConfigAttrFse = new FieldSetEntity();
        String curReportArea;
        String curX;
        String curY;
        String preReportArea = "";
        String preX = "";
        String preY = "";
        for (int i = 0; i < tempDte.getRows(); i++) {
            tempFse = tempDte.getFieldSetEntity(i);
            curReportArea = tempFse.getString(CmnConst.ATTR_REPORT_AREA);
            curX = tempFse.getString(CmnConst.CELL_POSITION_X);
            curY = tempFse.getString(CmnConst.CELL_POSITION_Y);
            if (curReportArea == null || curX == null || curY == null) {
                continue;
            }
            if (!preReportArea.equals(curReportArea) || !preX.equals(curX) || !preY.equals(curY)) {
                reportConfigAttrFse = new FieldSetEntity();
                reportConfigAttrDte.addFieldSetEntity(reportConfigAttrFse);
                reportConfigAttrFse.setTableName(CmnConst.PRODUCT_SYS_REPORT_CONFIG_ATTRIBUTE);
                reportConfigAttrFse.setValue(CmnConst.ATTR_X, curX);
                reportConfigAttrFse.setValue(CmnConst.ATTR_Y, curY);
                reportConfigAttrFse.setValue(CmnConst.ATTR_REPORT_AREA, curReportArea);
            }
            reportConfigAttrFse.setValue(tempFse.getString(CmnConst.ATTRIBUTE_NAME), tempFse.getString(CmnConst.REPORT_TYPE_ATTR_VALUE));
            preReportArea = curReportArea;
            preX = curX;
            preY = curY;
        }
        FieldSetEntity reportConfigFse = baseDao.getFieldSetEntity(CmnConst.PRODUCT_SYS_REPORT_CONFIG, uuid, false);
        reportConfigFse.addSubDataTable(reportConfigAttrDte);
        FieldSetEntity reportConfigFse = baseDao.getFieldSetEntity(CmnConst.PRODUCT_SYS_REPORT_CONFIG, uuid, false);
        reportConfigFse.addSubDataTable(reportConfigAttrDte);
        return reportConfigFse;
    }
        return reportConfigFse;
    }
    /**
     * æŠ¥è¡¨æ–°å¢ž
     *
     * @param fse
     * @return
     */
    @Transactional
    public String addReportConfig(FieldSetEntity fse) {
        fse.setValue(CmnConst.CREATED_BY, SpringMVCContextHolder.getCurrentUserId());
        fse.setValue(CmnConst.CREATED_UTC_DATETIME, new Date());
        fse.setValue(CmnConst.IS_VALID, 1);
    /**
     * æŠ¥è¡¨æ–°å¢ž
     *
     * @param fse
     * @return
     */
    @Transactional
    public String addReportConfig(FieldSetEntity fse) {
        fse.setValue(CmnConst.CREATED_BY, SpringMVCContextHolder.getCurrentUserId());
        fse.setValue(CmnConst.CREATED_UTC_DATETIME, new Date());
        fse.setValue(CmnConst.IS_VALID, 1);
        replaceAttrName2UUID(fse);
        replaceAttrName2UUID(fse);
        if (StringUtils.isEmpty(fse.getString(CmnConst.PAGE_SIZE))) {
            fse.setValue(CmnConst.PAGE_SIZE, null);
        }
        if (StringUtils.isEmpty(fse.getString(CmnConst.PAGE_SIZE))) {
            fse.setValue(CmnConst.PAGE_SIZE, null);
        }
        System.out.println(System.currentTimeMillis());
        String uuid = baseDao.add(fse);
        System.out.println(System.currentTimeMillis());
        String uuid = baseDao.add(fse);
        if ("1".equals(fse.getString(CmnConst.RELATE_FLAG))) {
            // é‡æ–°è®¾ç½®ç¼“å­˜
            dataListReportService.setConfig(fse.getUUID());
        }
        if ("1".equals(fse.getString(CmnConst.RELATE_FLAG))) {
            // é‡æ–°è®¾ç½®ç¼“å­˜
            dataListReportService.setConfig(fse.getUUID());
        }
        return uuid;
    }
        return uuid;
    }
    /**
     * æŠ¥è¡¨ä¿®æ”¹
     *
     * @param fse
     * @return
     */
    @Transactional
    public boolean updateReportConfig(FieldSetEntity fse) {
        fse.setValue(CmnConst.UPDATED_BY, SpringMVCContextHolder.getCurrentUserId());
        fse.setValue(CmnConst.UPDATED_UTC_DATETIME, new Date());
    /**
     * æŠ¥è¡¨ä¿®æ”¹
     *
     * @param fse
     * @return
     */
    @Transactional
    public boolean updateReportConfig(FieldSetEntity fse) {
        fse.setValue(CmnConst.UPDATED_BY, SpringMVCContextHolder.getCurrentUserId());
        fse.setValue(CmnConst.UPDATED_UTC_DATETIME, new Date());
        replaceAttrName2UUID(fse);
        replaceAttrName2UUID(fse);
        if (StringUtils.isEmpty(fse.getString(CmnConst.PAGE_SIZE))) {
            fse.setValue(CmnConst.PAGE_SIZE, null);
        }
        if (StringUtils.isEmpty(fse.getString(CmnConst.PAGE_SIZE))) {
            fse.setValue(CmnConst.PAGE_SIZE, null);
        }
        boolean result = baseDao.update(fse);
        boolean result = baseDao.update(fse);
        if ("1".equals(fse.getString(CmnConst.RELATE_FLAG)) || !StringUtils.isEmpty(fse.getString(CmnConst.FUNCTION_UUID))) {
            // é‡æ–°è®¾ç½®ç¼“å­˜
            dataListReportService.setConfig(fse.getUUID());
        }
        if ("1".equals(fse.getString(CmnConst.RELATE_FLAG)) || !StringUtils.isEmpty(fse.getString(CmnConst.FUNCTION_UUID))) {
            // é‡æ–°è®¾ç½®ç¼“å­˜
            dataListReportService.setConfig(fse.getUUID());
        }
        return result;
    }
        return result;
    }
    /**
     * æ›¿æ¢å±žæ€§åç§°ä¸ºuuid
     *
     * @param fse
     */
    private void replaceAttrName2UUID(FieldSetEntity fse) {
        DataTableEntity reportTypeAttrDte = baseDao.listTable(CmnConst.PRODUCT_SYS_REPORT_TYPE_ATTRIBUTE, "type_group='DataList'", new Object[]{}, new Object[]{CmnConst.ATTRIBUTE_NAME, CmnConst.UUID});
        if (!BaseUtil.dataTableIsEmpty(reportTypeAttrDte)) {
            Map<String, String> reportTypeAttrMap = Maps.newHashMap();
            FieldSetEntity tempFse;
            for (int i = 0; i < reportTypeAttrDte.getRows(); i++) {
                tempFse = reportTypeAttrDte.getFieldSetEntity(i);
                reportTypeAttrMap.put(tempFse.getString(CmnConst.ATTRIBUTE_NAME), tempFse.getUUID());
            }
            DataTableEntity preReportAttrDte = baseDao.listTable(CmnConst.PRODUCT_SYS_REPORT_CONFIG_ATTRIBUTE, "report_config_uuid=?", new Object[]{fse.getUUID()});
            Map<JSONObject, String> preReportAttrMap = Maps.newHashMap();
            JSONObject tempObj;
            if (!BaseUtil.dataTableIsEmpty(preReportAttrDte)) {
                for (int i = 0; i < preReportAttrDte.getRows(); i++) {
                    tempFse = preReportAttrDte.getFieldSetEntity(i);
                    tempObj = new JSONObject();
                    tempObj.put(CmnConst.ATTR_REPORT_AREA, tempFse.getString(CmnConst.ATTR_REPORT_AREA));
                    tempObj.put(CmnConst.CELL_POSITION_X, tempFse.getString(CmnConst.CELL_POSITION_X));
                    tempObj.put(CmnConst.CELL_POSITION_Y, tempFse.getString(CmnConst.CELL_POSITION_Y));
                    tempObj.put(CmnConst.REPORT_TYPE_ATTR, tempFse.getString(CmnConst.REPORT_TYPE_ATTR));
                    preReportAttrMap.put(tempObj, tempFse.getUUID());
                }
            }
            DataTableEntity reportAttrDte = fse.getSubDataTable(CmnConst.PRODUCT_SYS_REPORT_CONFIG_ATTRIBUTE);
            if (!BaseUtil.dataTableIsEmpty(reportAttrDte)) {
                String tempUUID;
                for (int i = 0; i < reportAttrDte.getRows(); i++) {
                    tempFse = reportAttrDte.getFieldSetEntity(i);
                    tempFse.setValue("report_type_attr_show_name", tempFse.getString(CmnConst.REPORT_TYPE_ATTR));
                    tempFse.setValue(CmnConst.REPORT_TYPE_ATTR, reportTypeAttrMap.get(tempFse.getString(CmnConst.REPORT_TYPE_ATTR)));
                    tempFse.setValue(CmnConst.CELL_POSITION_X, tempFse.getString(CmnConst.ATTR_X));
                    tempFse.setValue(CmnConst.CELL_POSITION_Y, tempFse.getString(CmnConst.ATTR_Y));
                    String x = tempFse.getString(CmnConst.ATTR_X);
                    tempObj = new JSONObject();
                    tempObj.put(CmnConst.ATTR_REPORT_AREA, tempFse.getString(CmnConst.ATTR_REPORT_AREA));
                    tempObj.put(CmnConst.CELL_POSITION_X, tempFse.getString(CmnConst.CELL_POSITION_X));
                    tempObj.put(CmnConst.CELL_POSITION_Y, tempFse.getString(CmnConst.CELL_POSITION_Y));
                    tempObj.put(CmnConst.REPORT_TYPE_ATTR, tempFse.getString(CmnConst.REPORT_TYPE_ATTR));
    /**
     * æ›¿æ¢å±žæ€§åç§°ä¸ºuuid
     *
     * @param fse
     */
    private void replaceAttrName2UUID(FieldSetEntity fse) {
        DataTableEntity reportTypeAttrDte = baseDao.listTable(CmnConst.PRODUCT_SYS_REPORT_TYPE_ATTRIBUTE, "type_group='DataList'", new Object[]{}, new Object[]{CmnConst.ATTRIBUTE_NAME, CmnConst.UUID});
        if (!BaseUtil.dataTableIsEmpty(reportTypeAttrDte)) {
            Map<String, String> reportTypeAttrMap = Maps.newHashMap();
            FieldSetEntity tempFse;
            for (int i = 0; i < reportTypeAttrDte.getRows(); i++) {
                tempFse = reportTypeAttrDte.getFieldSetEntity(i);
                reportTypeAttrMap.put(tempFse.getString(CmnConst.ATTRIBUTE_NAME), tempFse.getUUID());
            }
            DataTableEntity preReportAttrDte = baseDao.listTable(CmnConst.PRODUCT_SYS_REPORT_CONFIG_ATTRIBUTE, "report_config_uuid=?", new Object[]{fse.getUUID()});
            Map<JSONObject, String> preReportAttrMap = Maps.newHashMap();
            JSONObject tempObj;
            if (!BaseUtil.dataTableIsEmpty(preReportAttrDte)) {
                for (int i = 0; i < preReportAttrDte.getRows(); i++) {
                    tempFse = preReportAttrDte.getFieldSetEntity(i);
                    tempObj = new JSONObject();
                    tempObj.put(CmnConst.ATTR_REPORT_AREA, tempFse.getString(CmnConst.ATTR_REPORT_AREA));
                    tempObj.put(CmnConst.CELL_POSITION_X, tempFse.getString(CmnConst.CELL_POSITION_X));
                    tempObj.put(CmnConst.CELL_POSITION_Y, tempFse.getString(CmnConst.CELL_POSITION_Y));
                    tempObj.put(CmnConst.REPORT_TYPE_ATTR, tempFse.getString(CmnConst.REPORT_TYPE_ATTR));
                    preReportAttrMap.put(tempObj, tempFse.getUUID());
                }
            }
            DataTableEntity reportAttrDte = fse.getSubDataTable(CmnConst.PRODUCT_SYS_REPORT_CONFIG_ATTRIBUTE);
            if (!BaseUtil.dataTableIsEmpty(reportAttrDte)) {
                String tempUUID;
                for (int i = 0; i < reportAttrDte.getRows(); i++) {
                    tempFse = reportAttrDte.getFieldSetEntity(i);
                    tempFse.setValue(CmnConst.REPORT_TYPE_ATTR, reportTypeAttrMap.get(tempFse.getString(CmnConst.REPORT_TYPE_ATTR)));
                    tempFse.setValue(CmnConst.CELL_POSITION_X, tempFse.getString(CmnConst.ATTR_X));
                    tempFse.setValue(CmnConst.CELL_POSITION_Y, tempFse.getString(CmnConst.ATTR_Y));
                    tempUUID = preReportAttrMap.get(tempObj);
                    if (!StringUtils.isEmpty(tempUUID)) {
                        tempFse.setValue(CmnConst.UUID, tempUUID);
                    }
                    if (StringUtils.isEmpty(tempFse.getString(CmnConst.REPORT_TYPE_ATTR_VALUE))) {
                        //属性值是否为空
                        if (StringUtils.isEmpty(tempFse.getUUID())) {
                            //没有保存过的属性
                            reportAttrDte.removeFieldSetEntity(i);
                            i--;
                        } else {
                            //标记为删除
                            tempFse.setValue(CoreConst.SYSTEM_DATA_OPERATE_TYPE, "del");
                        }
                        continue;
                    }
                }
            }
        }
    }
                    tempObj = new JSONObject();
                    tempObj.put(CmnConst.ATTR_REPORT_AREA, tempFse.getString(CmnConst.ATTR_REPORT_AREA));
                    tempObj.put(CmnConst.CELL_POSITION_X, tempFse.getString(CmnConst.CELL_POSITION_X));
                    tempObj.put(CmnConst.CELL_POSITION_Y, tempFse.getString(CmnConst.CELL_POSITION_Y));
                    tempObj.put(CmnConst.REPORT_TYPE_ATTR, tempFse.getString(CmnConst.REPORT_TYPE_ATTR));
    /**
     * æŠ¥è¡¨åˆ é™¤
     *
     * @param uuid
     * @return
     */
    @Transactional
    public boolean deleteReportConfig(String uuid) {
        return baseDao.delete(CmnConst.PRODUCT_SYS_REPORT_CONFIG, "uuid=?", new Object[]{uuid});
    }
                    tempUUID = preReportAttrMap.get(tempObj);
                    if (!StringUtils.isEmpty(tempUUID)) {
                        tempFse.setValue(CmnConst.UUID, tempUUID);
                    }
                }
            }
        }
    }
    @Autowired
    UpdateLoginUserInfoService updateLoginUserInfoService;
    /**
     * æŠ¥è¡¨åˆ é™¤
     *
     * @param uuid
     * @return
     */
    @Transactional
    public boolean deleteReportConfig(String uuid) {
        return baseDao.delete(CmnConst.PRODUCT_SYS_REPORT_CONFIG, "uuid=?", new Object[]{uuid});
    }
    /**
     * å–消报表发布
     *
     * @param fse
     * @return
     */
    @Transactional
    public boolean cancelRelease(FieldSetEntity fse) {
        DataTableEntity reportConfigDte = DataPoolCacheImpl.getInstance().getCacheData(CmnConst.CACHE_REPORT_CONFIG, new String[]{fse.getUUID()});
        if (BaseUtil.dataTableIsEmpty(reportConfigDte)) {
            throw new BaseException(ReportCode.GET_REPORT_CONFIG_FIAL.getValue(), ReportCode.GET_REPORT_CONFIG_FIAL.getText());
        }
        FieldSetEntity reportConfigFse = reportConfigDte.getFieldSetEntity(0);
        String functionUUID = reportConfigFse.getString(CmnConst.FUNCTION_UUID);
        if (StringUtils.isEmpty(functionUUID)) {
            return false;
        }
    @Autowired
    UpdateLoginUserInfoService updateLoginUserInfoService;
        DataTableEntity dt = baseDao.listTable(CmnConst.PRODUCT_SYS_FUNCTION_PERMISSION, "function_uuid=?", new Object[]{functionUUID}, new Object[]{"role_uuid uuid"});
        //从角色权限中移除
        baseDao.delete(CmnConst.PRODUCT_SYS_FUNCTION_PERMISSION, "function_uuid=?", new Object[]{functionUUID});
        //删除连线
        baseDao.delete(CmnConst.PRODUCT_SYS_LINK, "function_uuid=?", new Object[]{functionUUID});
        //删除按钮
        baseDao.delete(CmnConst.PRODUCT_SYS_FUNCTION_BUTTONS, "function_uuid=?", new Object[]{functionUUID});
        //删除页面
        baseDao.delete(CmnConst.PRODUCT_SYS_MVC_PAGE, "function_uuid=?", new Object[]{functionUUID});
    /**
     * å–消报表发布
     *
     * @param fse
     * @return
     */
    @Transactional
    public boolean cancelRelease(FieldSetEntity fse) {
        DataTableEntity reportConfigDte = DataPoolCacheImpl.getInstance().getCacheData(CmnConst.CACHE_REPORT_CONFIG, new String[]{fse.getUUID()});
        if (BaseUtil.dataTableIsEmpty(reportConfigDte)) {
            throw new BaseException(ReportCode.GET_REPORT_CONFIG_FIAL.getValue(), ReportCode.GET_REPORT_CONFIG_FIAL.getText());
        }
        FieldSetEntity reportConfigFse = reportConfigDte.getFieldSetEntity(0);
        String functionUUID = reportConfigFse.getString(CmnConst.FUNCTION_UUID);
        if (StringUtils.isEmpty(functionUUID)) {
            return false;
        }
        //删除菜单
        baseDao.delete(CmnConst.PRODUCT_SYS_MENUS, "function_uuid=?", new Object[]{functionUUID});
        //删除功能
        baseDao.delete(CmnConst.PRODUCT_SYS_FUNCTIONS, "uuid=?", new Object[]{functionUUID});
        DataTableEntity dt = baseDao.listTable(CmnConst.PRODUCT_SYS_FUNCTION_PERMISSION, "function_uuid=?", new Object[]{functionUUID}, new Object[]{"role_uuid uuid"});
        //从角色权限中移除
        baseDao.delete(CmnConst.PRODUCT_SYS_FUNCTION_PERMISSION, "function_uuid=?", new Object[]{functionUUID});
        //删除连线
        baseDao.delete(CmnConst.PRODUCT_SYS_LINK, "function_uuid=?", new Object[]{functionUUID});
        //删除按钮
        baseDao.delete(CmnConst.PRODUCT_SYS_FUNCTION_BUTTONS, "function_uuid=?", new Object[]{functionUUID});
        //删除页面
        baseDao.delete(CmnConst.PRODUCT_SYS_MVC_PAGE, "function_uuid=?", new Object[]{functionUUID});
        //数据回写
        fse.setValue(CmnConst.FUNCTION_UUID, "");
        //删除菜单
        baseDao.delete(CmnConst.PRODUCT_SYS_MENUS, "function_uuid=?", new Object[]{functionUUID});
        //删除功能
        baseDao.delete(CmnConst.PRODUCT_SYS_FUNCTIONS, "uuid=?", new Object[]{functionUUID});
        if (!DataTableEntity.isEmpty(dt)) {
            updateLoginUserInfoService.updateUserInfoByUpdateRole(dt.getUuids(), true);
        }
        return baseDao.update(fse);
    }
        //数据回写
        fse.setValue(CmnConst.FUNCTION_UUID, "");
    /**
     * æŠ¥è¡¨å‘布
     *
     * @param fse
     * @return
     */
    @Transactional
    public boolean releaseConfig(FieldSetEntity fse) {
        if (!DataTableEntity.isEmpty(dt)) {
            updateLoginUserInfoService.updateUserInfoByUpdateRole(dt.getUuids(), true);
        }
        return baseDao.update(fse);
    }
        FieldSetEntity fseReport = baseDao.getFieldSetEntity(CmnConst.PRODUCT_SYS_REPORT_CONFIG, fse.getUUID(), false);
    /**
     * æŠ¥è¡¨å‘布
     *
     * @param fse
     * @return
     */
    @Transactional
    public boolean releaseConfig(FieldSetEntity fse) {
        //创建MVCC保存对象
        FieldSetEntity fseFunction = new FieldSetEntity();
        //1.创建MVC(系统MVC目录下)
        //生成功能编码
        String defaultCode = "001-005";
        fseFunction.setTableName(CmnConst.PRODUCT_SYS_FUNCTIONS);
        codeService.createCode(fseFunction, CmnConst.PRODUCT_SYS_FUNCTIONS, CmnConst.TRICODE, defaultCode);
        fseFunction.setValue(CmnConst.TABLE_UUID, CmnConst.PRODUCT_SYS_REPORT_CONFIG);            //功能关联表
        fseFunction.setValue(CmnConst.FUNCTION_NAME, fseReport.getString(CmnConst.REPORT_NAME));    //功能名称
        fseFunction.setValue(CmnConst.FUNCTION_DESCRIPTION, fseReport.getString(CmnConst.REPORT_NAME));    //功能描述
        fseFunction.setValue(CmnConst.STATUS_UUID, 1);            //是否启用
        fseFunction.setValue(CmnConst.FUNCTION_TYPE_UUID, 5);    //功能类型-业务后台管理 ç®¡ç†å‘˜å’Œæ™®é€šç”¨æˆ·éƒ½èƒ½åˆ†é…è¯¥æŠ¥è¡¨çš„æƒé™
        fseFunction.setValue(CmnConst.CLIENT_TYPE_UUID, "Web");        //客户端类型
        fseFunction.setValue(CmnConst.VERSION_UUID, "001");
        fseFunction.setValue(CmnConst.DATA_TYPE, 1);// æ•°æ®ç±»åž‹
        fseFunction.setValue(CmnConst.TRICODE_PARENT, defaultCode);// ä¸Šçº§æ¨¡å—code
        fseFunction.setValue("terminal_type", 1);
        BaseUtil.createCreatorAndCreationTime(SpringMVCContextHolder.getCurrentUser(), fseFunction);
        FieldSetEntity fseReport = baseDao.getFieldSetEntity(CmnConst.PRODUCT_SYS_REPORT_CONFIG, fse.getUUID(), false);
        //创建按钮保存对象
        DataTableEntity dtButton = new DataTableEntity();
        FieldSetEntity fseButton = new FieldSetEntity();
        fseButton.setTableName(CmnConst.PRODUCT_SYS_FUNCTION_BUTTONS);
        fseButton.setValue(CmnConst.IS_MAIN, 1);        //是否入口
        fseButton.setValue(CmnConst.STATUS_UUID, 1);    //是否启用
        fseButton.setValue(CmnConst.CLIENT_TYPE_UUID, "Web");    //客户端类型
        fseButton.setValue(CmnConst.BUTTON_NAME, "入口");    //按钮名称
        fseButton.setValue(CmnConst.BUTTON_TITLE, "entrance");    //按钮标题
        fseButton.setValue(CmnConst.BUTTON_TYPE, 1);            //按钮类型
        fseButton.setValue(CmnConst.BUTTON_CATEGORY_UUID, "main");    //按钮分类
        fseButton.setValue(CmnConst.ROUTE_NAME, BaseUtil.getPageCode());    //路由名称
        fseButton.setValue(CmnConst.UPLOAD_API_URL, CmnConst.ADDRESS_INIT_INTERFENCE);// å…¥å£æŽ¥å£åœ°å€
        fseButton.setValue("terminal_type", 1);
        JSONObject paramObj = new JSONObject();
        paramObj.put(CmnConst.UUID, fse.getUUID());
        fseButton.setValue(CmnConst.PARAMS, paramObj.toString());// æŽ¥å£å‚æ•°
        fseButton.setValue(CmnConst.TOP_LOCATION, "100px");
        fseButton.setValue(CmnConst.LEFT_LOCATION, "100px");
        dtButton.setMeta(fseButton.getMeta());
        dtButton.addFieldSetEntity(fseButton);
        //创建MVCC保存对象
        FieldSetEntity fseFunction = new FieldSetEntity();
        //1.创建MVC(系统MVC目录下)
        //生成功能编码
        String defaultCode = "001-005";
        fseFunction.setTableName(CmnConst.PRODUCT_SYS_FUNCTIONS);
        codeService.createCode(fseFunction, CmnConst.PRODUCT_SYS_FUNCTIONS, CmnConst.TRICODE, defaultCode);
        fseFunction.setValue(CmnConst.TABLE_UUID, CmnConst.PRODUCT_SYS_REPORT_CONFIG);            //功能关联表
        fseFunction.setValue(CmnConst.FUNCTION_NAME, fseReport.getString(CmnConst.REPORT_NAME));    //功能名称
        fseFunction.setValue(CmnConst.FUNCTION_DESCRIPTION, fseReport.getString(CmnConst.REPORT_NAME));    //功能描述
        fseFunction.setValue(CmnConst.STATUS_UUID, 1);            //是否启用
        fseFunction.setValue(CmnConst.FUNCTION_TYPE_UUID, 5);    //功能类型-业务后台管理 ç®¡ç†å‘˜å’Œæ™®é€šç”¨æˆ·éƒ½èƒ½åˆ†é…è¯¥æŠ¥è¡¨çš„æƒé™
        fseFunction.setValue(CmnConst.CLIENT_TYPE_UUID, "Web");        //客户端类型
        fseFunction.setValue(CmnConst.VERSION_UUID, "001");
        fseFunction.setValue(CmnConst.DATA_TYPE, 1);// æ•°æ®ç±»åž‹
        fseFunction.setValue(CmnConst.TRICODE_PARENT, defaultCode);// ä¸Šçº§æ¨¡å—code
        fseFunction.setValue("terminal_type", 1);
        BaseUtil.createCreatorAndCreationTime(SpringMVCContextHolder.getCurrentUser(), fseFunction);
        //创建页面保存对象
        DataTableEntity dtPage = new DataTableEntity();
        FieldSetEntity fsePage = new FieldSetEntity();
        fsePage.setTableName(CmnConst.PRODUCT_SYS_MVC_PAGE);
        //创建按钮保存对象
        DataTableEntity dtButton = new DataTableEntity();
        FieldSetEntity fseButton = new FieldSetEntity();
        fseButton.setTableName(CmnConst.PRODUCT_SYS_FUNCTION_BUTTONS);
        fseButton.setValue(CmnConst.IS_MAIN, 1);        //是否入口
        fseButton.setValue(CmnConst.STATUS_UUID, 1);    //是否启用
        fseButton.setValue(CmnConst.CLIENT_TYPE_UUID, "Web");    //客户端类型
        fseButton.setValue(CmnConst.BUTTON_NAME, "入口");    //按钮名称
        fseButton.setValue(CmnConst.BUTTON_TITLE, "entrance");    //按钮标题
        fseButton.setValue(CmnConst.BUTTON_TYPE, 1);            //按钮类型
        fseButton.setValue(CmnConst.BUTTON_CATEGORY_UUID, "main");    //按钮分类
        fseButton.setValue(CmnConst.ROUTE_NAME, BaseUtil.getPageCode());    //路由名称
        fseButton.setValue(CmnConst.UPLOAD_API_URL, CmnConst.ADDRESS_INIT_INTERFENCE);// å…¥å£æŽ¥å£åœ°å€
        fseButton.setValue("terminal_type", 1);
        JSONObject paramObj = new JSONObject();
        paramObj.put(CmnConst.UUID, fse.getUUID());
        fseButton.setValue(CmnConst.PARAMS, paramObj.toString());// æŽ¥å£å‚æ•°
        fseButton.setValue(CmnConst.TOP_LOCATION, "100px");
        fseButton.setValue(CmnConst.LEFT_LOCATION, "100px");
        dtButton.setMeta(fseButton.getMeta());
        dtButton.addFieldSetEntity(fseButton);
        //创建页面保存对象
        DataTableEntity dtPage = new DataTableEntity();
        FieldSetEntity fsePage = new FieldSetEntity();
        fsePage.setTableName(CmnConst.PRODUCT_SYS_MVC_PAGE);
//        fsePage.setValue(CmnConst.PAGE_NAME, "报表展示");
        fsePage.setValue(CmnConst.PAGE_NAME, fse.getString(CmnConst.MENU_NAME));
        fsePage.setValue(CmnConst.PAGE_TYPE, 2);
        fsePage.setValue(CmnConst.PAGE_URL, CmnConst.ADDRESS_REPORT_SHOW);
        fsePage.setValue(CmnConst.TOP_LOCATION, "300px");
        fsePage.setValue(CmnConst.LEFT_LOCATION, "100px");
        fsePage.setValue(CmnConst.PAGE_OPEN_WITH, 0);
        fsePage.setValue(CmnConst.PAGE_TYPE, 0);
        fsePage.setValue("terminal_type", 1);
        dtPage.addFieldSetEntity(fsePage);
        fsePage.setValue(CmnConst.PAGE_NAME, fse.getString(CmnConst.MENU_NAME));
        fsePage.setValue(CmnConst.PAGE_TYPE, 2);
        fsePage.setValue(CmnConst.PAGE_URL, CmnConst.ADDRESS_REPORT_SHOW);
        fsePage.setValue(CmnConst.TOP_LOCATION, "300px");
        fsePage.setValue(CmnConst.LEFT_LOCATION, "100px");
        fsePage.setValue(CmnConst.PAGE_OPEN_WITH, 0);
        fsePage.setValue(CmnConst.PAGE_TYPE, 0);
        fsePage.setValue("terminal_type", 1);
        dtPage.addFieldSetEntity(fsePage);
        fseFunction.addSubDataTable(dtButton);
        fseFunction.addSubDataTable(dtPage);
        fseFunction.addSubDataTable(dtButton);
        fseFunction.addSubDataTable(dtPage);
        String functionUUID = baseDao.add(fseFunction);
        String functionUUID = baseDao.add(fseFunction);
        //创建连线保存对象
        FieldSetEntity fseLink = new FieldSetEntity();
        fseLink.setTableName(CmnConst.PRODUCT_SYS_LINK);
        fseLink.setValue(CmnConst.LINK_TYPE, 0);        //连线类型
        fseLink.setValue(CmnConst.FUNCTION_UUID, functionUUID);    //所属功能UUID
        fseLink.setValue(CmnConst.LINE_FROM, fseButton.getUUID());    //起始端
        fseLink.setValue(CmnConst.FROM_TYPE, 0);                    //起始端类型
        fseLink.setValue(CmnConst.LINE_TO, fsePage.getUUID());        //结束端
        fseLink.setValue(CmnConst.TO_TYPE, 2);                        //结束端类型
        fseLink.setValue("terminal_type", 1);
        BaseUtil.createCreatorAndCreationTime(SpringMVCContextHolder.getCurrentUser(), fseLink);
        //创建连线保存对象
        FieldSetEntity fseLink = new FieldSetEntity();
        fseLink.setTableName(CmnConst.PRODUCT_SYS_LINK);
        fseLink.setValue(CmnConst.LINK_TYPE, 0);        //连线类型
        fseLink.setValue(CmnConst.FUNCTION_UUID, functionUUID);    //所属功能UUID
        fseLink.setValue(CmnConst.LINE_FROM, fseButton.getUUID());    //起始端
        fseLink.setValue(CmnConst.FROM_TYPE, 0);                    //起始端类型
        fseLink.setValue(CmnConst.LINE_TO, fsePage.getUUID());        //结束端
        fseLink.setValue(CmnConst.TO_TYPE, 2);                        //结束端类型
        fseLink.setValue("terminal_type", 1);
        BaseUtil.createCreatorAndCreationTime(SpringMVCContextHolder.getCurrentUser(), fseLink);
        baseDao.add(fseLink);
        baseDao.add(fseLink);
        // æå–发布的角色相关数据
        List<String> roleUUIDList = Lists.newArrayList();
        List<String> clientUUIDList = Lists.newArrayList();
        clientUUIDList.add(SpringMVCContextHolder.getCurrentUser().getClientUuid());
//        String[] singleRoleInfoArr;
        for (String singleRoleInfo : fse.getString(CmnConst.ROLE_UUID).split("#")) {
//            singleRoleInfoArr = singleRoleInfo.split(",");
            roleUUIDList.add(singleRoleInfo);
        }
        // æå–发布的角色相关数据
        List<String> roleUUIDList = Lists.newArrayList();
        List<String> clientUUIDList = Lists.newArrayList();
        clientUUIDList.add(SpringMVCContextHolder.getCurrentUser().getClientUuid());
//        String[] singleRoleInfoArr;
        for (String singleRoleInfo : fse.getString(CmnConst.ROLE_UUID).split("#")) {
//            singleRoleInfoArr = singleRoleInfo.split(",");
            roleUUIDList.add(singleRoleInfo);
        }
        // 2.绑定角色(给某一角色赋予该功能)
        for (String roleUUID : roleUUIDList) {
            FieldSetEntity fseFunctionButton = new FieldSetEntity();
            fseFunctionButton.setTableName(CmnConst.PRODUCT_SYS_FUNCTION_PERMISSION);
            fseFunctionButton.setValue(CmnConst.FUNCTION_UUID, functionUUID);// æ‰€å±žåŠŸèƒ½UUID
            fseFunctionButton.setValue(CmnConst.BUTTON_UUID, fseButton.getUUID());// æŒ‰é’®UUID
            fseFunctionButton.setValue(CmnConst.ROLE_UUID, roleUUID);// æ‰€å±žè§’色UUID
            baseDao.add(fseFunctionButton);
        }
        // 2.绑定角色(给某一角色赋予该功能)
        for (String roleUUID : roleUUIDList) {
            FieldSetEntity fseFunctionButton = new FieldSetEntity();
            fseFunctionButton.setTableName(CmnConst.PRODUCT_SYS_FUNCTION_PERMISSION);
            fseFunctionButton.setValue(CmnConst.FUNCTION_UUID, functionUUID);// æ‰€å±žåŠŸèƒ½UUID
            fseFunctionButton.setValue(CmnConst.BUTTON_UUID, fseButton.getUUID());// æŒ‰é’®UUID
            fseFunctionButton.setValue(CmnConst.ROLE_UUID, roleUUID);// æ‰€å±žè§’色UUID
            baseDao.add(fseFunctionButton);
        }
        // 3.绑定客户角色(给某一客户角色赋予该功能)
        for (String clientUUID : clientUUIDList) {
            DataTableEntity clientDte = DataPoolCacheImpl.getInstance().getCacheData("客户信息", new String[]{clientUUID});
            if (BaseUtil.dataTableIsEmpty(clientDte)) {
                continue;
            }
            FieldSetEntity clientFse = clientDte.getFieldSetEntity(0);
            FieldSetEntity fseClientFunctionButton = new FieldSetEntity();
            fseClientFunctionButton.setTableName(CmnConst.PRODUCT_SYS_FUNCTION_PERMISSION);
            fseClientFunctionButton.setValue(CmnConst.FUNCTION_UUID, functionUUID);// æ‰€å±žåŠŸèƒ½UUID
            fseClientFunctionButton.setValue(CmnConst.BUTTON_UUID, fseButton.getUUID());// æŒ‰é’®UUID
            fseClientFunctionButton.setValue(CmnConst.ROLE_UUID, clientFse.getString(CmnConst.ROLE_UUID));// æ‰€å±žè§’色UUID
            baseDao.add(fseClientFunctionButton);
        }
        // 3.绑定客户角色(给某一客户角色赋予该功能)
        for (String clientUUID : clientUUIDList) {
            DataTableEntity clientDte = DataPoolCacheImpl.getInstance().getCacheData("客户信息", new String[]{clientUUID});
            if (BaseUtil.dataTableIsEmpty(clientDte)) {
                continue;
            }
            FieldSetEntity clientFse = clientDte.getFieldSetEntity(0);
            FieldSetEntity fseClientFunctionButton = new FieldSetEntity();
            fseClientFunctionButton.setTableName(CmnConst.PRODUCT_SYS_FUNCTION_PERMISSION);
            fseClientFunctionButton.setValue(CmnConst.FUNCTION_UUID, functionUUID);// æ‰€å±žåŠŸèƒ½UUID
            fseClientFunctionButton.setValue(CmnConst.BUTTON_UUID, fseButton.getUUID());// æŒ‰é’®UUID
            fseClientFunctionButton.setValue(CmnConst.ROLE_UUID, clientFse.getString(CmnConst.ROLE_UUID));// æ‰€å±žè§’色UUID
            baseDao.add(fseClientFunctionButton);
        }
        //4.创建菜单(根据前端所选父级菜单)
        FieldSetEntity fseMenu = new FieldSetEntity();
        fseMenu.setTableName(CmnConst.PRODUCT_SYS_MENUS);
        codeService.createCode(fseMenu, CmnConst.PRODUCT_SYS_MENUS, CmnConst.TRICODE, fse.getString(CmnConst.TRICODE_PARENT));
        fseMenu.setValue(CmnConst.TRICODE_PARENT, fse.getString(CmnConst.TRICODE_PARENT));
        fseMenu.setValue(CmnConst.MENU_NAME, fse.getString(CmnConst.MENU_NAME));
        fseMenu.setValue(CmnConst.FUNCTION_UUID, functionUUID);
        fseMenu.setValue(CmnConst.SEQUENCE, fse.getString(CmnConst.SEQUENCE));
        fseMenu.setValue(CmnConst.IS_CATALOG, 0);
        fseMenu.setValue(CmnConst.IS_SHOW, StringUtils.isEmpty(fse.getString(CmnConst.IS_SHOW)) ? 1 : fse.getString(CmnConst.IS_SHOW));
        fseMenu.setValue(CmnConst.MENU_ICON, fse.getString(CmnConst.MENU_ICON));
        BaseUtil.createCreatorAndCreationTime(SpringMVCContextHolder.getCurrentUser(), fseMenu);
        //4.创建菜单(根据前端所选父级菜单)
        FieldSetEntity fseMenu = new FieldSetEntity();
        fseMenu.setTableName(CmnConst.PRODUCT_SYS_MENUS);
        codeService.createCode(fseMenu, CmnConst.PRODUCT_SYS_MENUS, CmnConst.TRICODE, fse.getString(CmnConst.TRICODE_PARENT));
        fseMenu.setValue(CmnConst.TRICODE_PARENT, fse.getString(CmnConst.TRICODE_PARENT));
        fseMenu.setValue(CmnConst.MENU_NAME, fse.getString(CmnConst.MENU_NAME));
        fseMenu.setValue(CmnConst.FUNCTION_UUID, functionUUID);
        fseMenu.setValue(CmnConst.SEQUENCE, fse.getString(CmnConst.SEQUENCE));
        fseMenu.setValue(CmnConst.IS_CATALOG, 0);
        fseMenu.setValue(CmnConst.IS_SHOW, StringUtils.isEmpty(fse.getString(CmnConst.IS_SHOW)) ? 1 : fse.getString(CmnConst.IS_SHOW));
        fseMenu.setValue(CmnConst.MENU_ICON, fse.getString(CmnConst.MENU_ICON));
        BaseUtil.createCreatorAndCreationTime(SpringMVCContextHolder.getCurrentUser(), fseMenu);
        baseDao.add(fseMenu);
        baseDao.add(fseMenu);
        //数据回写
        fseReport.setValue(CmnConst.FUNCTION_UUID, functionUUID);
        //数据回写
        fseReport.setValue(CmnConst.FUNCTION_UUID, functionUUID);
        boolean result = baseDao.update(fseReport);
        boolean result = baseDao.update(fseReport);
        // é‡æ–°è®¾ç½®ç¼“å­˜
        dataListReportService.setConfig(fseReport.getUUID());
        // é‡æ–°è®¾ç½®ç¼“å­˜
        dataListReportService.setConfig(fseReport.getUUID());
        return result;
    }
        return result;
    }
    /**
     * æŠ¥è¡¨copy
     *
     * @param uuid
     * @return
     */
    public String copyConfig(String uuid) {
        FieldSetEntity fse = baseDao.getFieldSetEntity(CmnConst.PRODUCT_SYS_REPORT_CONFIG, uuid, true);
        FieldSetEntity fseCopy = fse;
        fseCopy.remove(CmnConst.ID);
        fseCopy.remove(CmnConst.UUID);
        DataTableEntity dtSub = fseCopy.getSubDataTable(CmnConst.PRODUCT_SYS_REPORT_CONFIG_ATTRIBUTE);
        if (dtSub != null && dtSub.getRows() > 0) {
            for (int i = 0; i < dtSub.getRows(); i++) {
                FieldSetEntity fseSub = dtSub.getFieldSetEntity(i);
                fseSub.remove(CmnConst.ID);
                fseSub.remove(CmnConst.UUID);
            }
        }
        return baseDao.add(fseCopy, true);
    }
    /**
     * æŠ¥è¡¨copy
     *
     * @param uuid
     * @return
     */
    public String copyConfig(String uuid) {
        FieldSetEntity fse = baseDao.getFieldSetEntity(CmnConst.PRODUCT_SYS_REPORT_CONFIG, uuid, true);
        FieldSetEntity fseCopy = fse;
        fseCopy.remove(CmnConst.ID);
        fseCopy.remove(CmnConst.UUID);
        DataTableEntity dtSub = fseCopy.getSubDataTable(CmnConst.PRODUCT_SYS_REPORT_CONFIG_ATTRIBUTE);
        if (dtSub != null && dtSub.getRows() > 0) {
            for (int i = 0; i < dtSub.getRows(); i++) {
                FieldSetEntity fseSub = dtSub.getFieldSetEntity(i);
                fseSub.remove(CmnConst.ID);
                fseSub.remove(CmnConst.UUID);
            }
        }
        return baseDao.add(fseCopy, true);
    }
    /**
     * é…ç½®æŠ¥è¡¨-引用
     *
     * @param fse
     * @return
     */
    public FieldSetEntity quoteReportConfig(FieldSetEntity fse) {
        FieldSetEntity sourceFse = findReportConfig(fse.getUUID());
        sourceFse.setValue(CmnConst.DATASOURCE_UUID, fse.getString(CmnConst.DATASOURCE_UUID));
        sourceFse.remove(new String[]{CmnConst.ID, CmnConst.UUID, CmnConst.CREATED_BY, CmnConst.CREATED_UTC_DATETIME, CmnConst.UPDATED_BY, CmnConst.CREATED_UTC_DATETIME, CmnConst.REPORT_NAME});
        DataTableEntity subDte = sourceFse.getSubDataTable(CmnConst.PRODUCT_SYS_REPORT_CONFIG_ATTRIBUTE);
        FieldSetEntity subFse;
        for (int i = 0; i < subDte.getRows(); i++) {
            subFse = subDte.getFieldSetEntity(i);
            subFse.remove(new String[]{CmnConst.ID, CmnConst.UUID, CmnConst.CREATED_BY, CmnConst.CREATED_UTC_DATETIME, CmnConst.UPDATED_BY, CmnConst.CREATED_UTC_DATETIME});
        }
        return sourceFse;
    }
    /**
     * é…ç½®æŠ¥è¡¨-引用
     *
     * @param fse
     * @return
     */
    public FieldSetEntity quoteReportConfig(FieldSetEntity fse) {
        FieldSetEntity sourceFse = findReportConfig(fse.getUUID());
        sourceFse.setValue(CmnConst.DATASOURCE_UUID, fse.getString(CmnConst.DATASOURCE_UUID));
        sourceFse.remove(new String[]{CmnConst.ID, CmnConst.UUID, CmnConst.CREATED_BY, CmnConst.CREATED_UTC_DATETIME, CmnConst.UPDATED_BY, CmnConst.CREATED_UTC_DATETIME, CmnConst.REPORT_NAME});
        DataTableEntity subDte = sourceFse.getSubDataTable(CmnConst.PRODUCT_SYS_REPORT_CONFIG_ATTRIBUTE);
        FieldSetEntity subFse;
        for (int i = 0; i < subDte.getRows(); i++) {
            subFse = subDte.getFieldSetEntity(i);
            subFse.remove(new String[]{CmnConst.ID, CmnConst.UUID, CmnConst.CREATED_BY, CmnConst.CREATED_UTC_DATETIME, CmnConst.UPDATED_BY, CmnConst.CREATED_UTC_DATETIME});
        }
        return sourceFse;
    }
    /**
     * èŽ·å–æŠ¥è¡¨å‘å¸ƒä¿¡æ¯-发布
     *
     * @return
     */
    public JSONArray getReportReleaseInfo() {
        StringBuilder sql = new StringBuilder(256);
        DataTableEntity aimDte = new DataTableEntity();
        DataTableEntity dte;
        Object[] arr;
        String filter;
        sql.append("select distinct null pid,uuid sid,client_name name FROM product_sys_clients c")
                .append("\ninner join (")
                .append("\n    select client_uuid pid,uuid sid,org_level_name FROM product_sys_org_levels where org_level_status=0 order by org_level_code")
                .append("\n) o on o.pid=c.uuid")
                .append("\ninner join (")
                .append("\n    select org_level_uuid pid,uuid sid,role_name FROM product_sys_role where is_used=1")
                .append("\n) r on r.pid=o.sid");
        // åŽ»æŽ‰admin所属客户
    /**
     * èŽ·å–æŠ¥è¡¨å‘å¸ƒä¿¡æ¯-发布
     *
     * @return
     */
    public JSONArray getReportReleaseInfo() {
        StringBuilder sql = new StringBuilder(256);
        DataTableEntity aimDte = new DataTableEntity();
        DataTableEntity dte;
        Object[] arr;
        String filter;
        sql.append("select distinct null pid,uuid sid,client_name name FROM product_sys_clients c")
                .append("\ninner join (")
                .append("\n    select client_uuid pid,uuid sid,org_level_name FROM product_sys_org_levels where org_level_status=0 order by org_level_code")
                .append("\n) o on o.pid=c.uuid")
                .append("\ninner join (")
                .append("\n    select org_level_uuid pid,uuid sid,role_name FROM product_sys_role where is_used=1")
                .append("\n) r on r.pid=o.sid");
        // åŽ»æŽ‰admin所属客户
//                .append("\nwhere c.uuid!='4d4679ed-c4c3-41b8-abfe-451a66fd4043'");
        dte = baseDao.listTable(sql.toString(), new Object[]{});
        dte = baseDao.listTable(sql.toString(), new Object[]{});
        aimDte.addFieldSetEntity(dte);
        aimDte.addFieldSetEntity(dte);
        arr = dte.getFieldAllValues("sid");
        filter = BaseUtil.buildQuestionMarkFilter("client_uuid", arr.length, true);
        sql.setLength(0);
        sql.append("\nselect distinct o.* from (")
                .append("\n    select client_uuid pid,uuid sid,org_level_name name FROM product_sys_org_levels where org_level_status=0")
                .append("\n    and ").append(filter)
                .append("\n    order by org_level_code")
                .append("\n) o")
                .append("\ninner join (")
                .append("\n    select org_level_uuid pid,uuid sid,role_name FROM product_sys_role where is_used=1")
                .append("\n) r on r.pid=o.sid");
        dte = baseDao.listTable(sql.toString(), arr);
        aimDte.addFieldSetEntity(dte);
        arr = dte.getFieldAllValues("sid");
        filter = BaseUtil.buildQuestionMarkFilter("client_uuid", arr.length, true);
        sql.setLength(0);
        sql.append("\nselect distinct o.* from (")
                .append("\n    select client_uuid pid,uuid sid,org_level_name name FROM product_sys_org_levels where org_level_status=0")
                .append("\n    and ").append(filter)
                .append("\n    order by org_level_code")
                .append("\n) o")
                .append("\ninner join (")
                .append("\n    select org_level_uuid pid,uuid sid,role_name FROM product_sys_role where is_used=1")
                .append("\n) r on r.pid=o.sid");
        dte = baseDao.listTable(sql.toString(), arr);
        aimDte.addFieldSetEntity(dte);
        arr = dte.getFieldAllValues("sid");
        filter = BaseUtil.buildQuestionMarkFilter("org_level_uuid", arr.length, true);
        sql.setLength(0);
        sql.append("\nselect org_level_uuid pid,uuid sid,role_name name FROM product_sys_role where is_used=1").append(" and ").append(filter);
        dte = baseDao.listTable(sql.toString(), arr);
        aimDte.addFieldSetEntity(dte);
        arr = dte.getFieldAllValues("sid");
        filter = BaseUtil.buildQuestionMarkFilter("org_level_uuid", arr.length, true);
        sql.setLength(0);
        sql.append("\nselect org_level_uuid pid,uuid sid,role_name name FROM product_sys_role where is_used=1").append(" and ").append(filter);
        dte = baseDao.listTable(sql.toString(), arr);
        aimDte.addFieldSetEntity(dte);
        return BaseUtil.dataTableToTreeData(aimDte, "sid", "pid", null, false);
    }
        return BaseUtil.dataTableToTreeData(aimDte, "sid", "pid", null, false);
    }
    /**
     * èŽ·å–æŠ¥è¡¨å‘å¸ƒä¿¡æ¯-发布后查看信息
     *
     * @return
     */
    public JSONObject viewReportReleaseInfo(FieldSetEntity fse) {
        DataTableEntity reportConfigDte = DataPoolCacheImpl.getInstance().getCacheData(CmnConst.CACHE_REPORT_CONFIG, new String[]{fse.getUUID()});
        if (BaseUtil.dataTableIsEmpty(reportConfigDte)) {
            throw new BaseException(ReportCode.GET_REPORT_RELEASE_INFO_FAIL.getValue(), ReportCode.GET_REPORT_RELEASE_INFO_FAIL.getText());
        }
        FieldSetEntity reportConfigFse = reportConfigDte.getFieldSetEntity(0);
        StringBuilder sql = new StringBuilder(256);
        sql.append("\nselect group_concat(single_role_uuid separator '#') role_uuid")
                .append("\nfrom (")
                .append("\n    select concat(client_uuid,',',uuid,',',role_uuid) single_role_uuid")
                .append("\n    FROM product_sys_org_levels o")
                .append("\n    inner join (")
                .append("\n        select org_level_uuid,uuid role_uuid,role_name")
                .append("\n        FROM product_sys_role r")
                .append("\n        inner join (")
                .append("\n            select role_uuid FROM product_sys_function_permission where function_uuid=?")
                .append("\n        ) p on r.uuid=p.role_uuid")
                .append("\n    ) r1 on o.uuid=r1.org_level_uuid")
                .append("\n) t");
        String functionUUID = reportConfigFse.getString(CmnConst.FUNCTION_UUID);
        DataTableEntity dte = baseDao.listTable(sql.toString(), new Object[]{functionUUID});
    /**
     * èŽ·å–æŠ¥è¡¨å‘å¸ƒä¿¡æ¯-发布后查看信息
     *
     * @return
     */
    public JSONObject viewReportReleaseInfo(FieldSetEntity fse) {
        DataTableEntity reportConfigDte = DataPoolCacheImpl.getInstance().getCacheData(CmnConst.CACHE_REPORT_CONFIG, new String[]{fse.getUUID()});
        if (BaseUtil.dataTableIsEmpty(reportConfigDte)) {
            throw new BaseException(ReportCode.GET_REPORT_RELEASE_INFO_FAIL.getValue(), ReportCode.GET_REPORT_RELEASE_INFO_FAIL.getText());
        }
        FieldSetEntity reportConfigFse = reportConfigDte.getFieldSetEntity(0);
        StringBuilder sql = new StringBuilder(256);
        sql.append("\nselect group_concat(single_role_uuid separator '#') role_uuid")
                .append("\nfrom (")
                .append("\n    select concat(client_uuid,',',uuid,',',role_uuid) single_role_uuid")
                .append("\n    FROM product_sys_org_levels o")
                .append("\n    inner join (")
                .append("\n        select org_level_uuid,uuid role_uuid,role_name")
                .append("\n        FROM product_sys_role r")
                .append("\n        inner join (")
                .append("\n            select role_uuid FROM product_sys_function_permission where function_uuid=?")
                .append("\n        ) p on r.uuid=p.role_uuid")
                .append("\n    ) r1 on o.uuid=r1.org_level_uuid")
                .append("\n) t");
        String functionUUID = reportConfigFse.getString(CmnConst.FUNCTION_UUID);
        DataTableEntity dte = baseDao.listTable(sql.toString(), new Object[]{functionUUID});
        FieldSetEntity menuFse = baseDao.getFieldSetEntityByFilter(CmnConst.PRODUCT_SYS_MENUS, "function_uuid=?", new Object[]{functionUUID}, false);
        FieldSetEntity menuFse = baseDao.getFieldSetEntityByFilter(CmnConst.PRODUCT_SYS_MENUS, "function_uuid=?", new Object[]{functionUUID}, false);
        JSONObject resultObj = new JSONObject();
        resultObj.put(CmnConst.UUID, fse.getUUID());
        resultObj.put(CmnConst.ROLE_UUID, dte.getFieldSetEntity(0).getString(CmnConst.ROLE_UUID));
        resultObj.put(CmnConst.TRICODE_PARENT, menuFse.getString(CmnConst.TRICODE_PARENT));
        resultObj.put(CmnConst.MENU_ICON, menuFse.getString(CmnConst.MENU_ICON));
        resultObj.put(CmnConst.MENU_NAME, menuFse.getString(CmnConst.MENU_NAME));
        JSONObject resultObj = new JSONObject();
        resultObj.put(CmnConst.UUID, fse.getUUID());
        resultObj.put(CmnConst.ROLE_UUID, dte.getFieldSetEntity(0).getString(CmnConst.ROLE_UUID));
        resultObj.put(CmnConst.TRICODE_PARENT, menuFse.getString(CmnConst.TRICODE_PARENT));
        resultObj.put(CmnConst.MENU_ICON, menuFse.getString(CmnConst.MENU_ICON));
        resultObj.put(CmnConst.MENU_NAME, menuFse.getString(CmnConst.MENU_NAME));
        return resultObj;
    }
        return resultObj;
    }
    /**
     * å·²å‘布列表界面
     *
     * @param fse
     * @return
     */
    public DataTableEntity releasedListReportConfig(FieldSetEntity fse) {
        String filter = queryFilterService.getQueryFilter(fse);
        StringBuilder sql = new StringBuilder(256);
    /**
     * å·²å‘布列表界面
     *
     * @param fse
     * @return
     */
    public DataTableEntity releasedListReportConfig(FieldSetEntity fse) {
        String filter = queryFilterService.getQueryFilter(fse);
        StringBuilder sql = new StringBuilder(256);
//        sql.append("select * from ( ");
        sql.append("\n    select rc.uuid,rc.report_name,rtc.type_name,t1.role_info,mp.menu_name tricode_parent,m.menu_icon,m.menu_name ");
        sql.append("\n    FROM product_sys_report_config rc ");
        sql.append("\n    inner join ( ");
        sql.append("\n        select function_uuid,group_concat(role_info separator ',') role_info ");
        sql.append("\n        from ( ");
        sql.append("\n            select function_uuid,concat(c.client_name,'/',o.org_level_name,'/',role_name) role_info ");
        sql.append("\n                        FROM product_sys_clients c ");
        sql.append("\n                        inner join product_sys_org_levels o on o.client_uuid=c.uuid ");
        sql.append("\n                        inner join ( ");
        sql.append("\n                                select function_uuid,org_level_uuid,uuid role_uuid,role_name ");
        sql.append("\n                                FROM product_sys_role r ");
        sql.append("\n                                inner join ( ");
        sql.append("\n                                        select function_uuid,role_uuid FROM product_sys_function_permission ");
        sql.append("\n                                ) p on r.uuid=p.role_uuid ");
        sql.append("\n                        ) r1 on o.uuid=r1.org_level_uuid ");
        sql.append("\n        ) t ");
        sql.append("\n        group by function_uuid ");
        sql.append("\n    ) t1 on rc.function_uuid=t1.function_uuid ");
        sql.append("\n    inner join product_sys_menus m on rc.function_uuid=m.function_uuid ");
        sql.append("\n    inner join product_sys_report_type_config rtc on rc.type_uuid=rtc.uuid ");
        sql.append("\n    inner join product_sys_menus mp on m.tricode_parent=mp.tricode ");
        sql.append("\n    select rc.uuid,rc.report_name,rtc.type_name,t1.role_info,mp.menu_name tricode_parent,m.menu_icon,m.menu_name ");
        sql.append("\n    FROM product_sys_report_config rc ");
        sql.append("\n    inner join ( ");
        sql.append("\n        select function_uuid,group_concat(role_info separator ',') role_info ");
        sql.append("\n        from ( ");
        sql.append("\n            select function_uuid,concat(c.client_name,'/',o.org_level_name,'/',role_name) role_info ");
        sql.append("\n                        FROM product_sys_clients c ");
        sql.append("\n                        inner join product_sys_org_levels o on o.client_uuid=c.uuid ");
        sql.append("\n                        inner join ( ");
        sql.append("\n                                select function_uuid,org_level_uuid,uuid role_uuid,role_name ");
        sql.append("\n                                FROM product_sys_role r ");
        sql.append("\n                                inner join ( ");
        sql.append("\n                                        select function_uuid,role_uuid FROM product_sys_function_permission ");
        sql.append("\n                                ) p on r.uuid=p.role_uuid ");
        sql.append("\n                        ) r1 on o.uuid=r1.org_level_uuid ");
        sql.append("\n        ) t ");
        sql.append("\n        group by function_uuid ");
        sql.append("\n    ) t1 on rc.function_uuid=t1.function_uuid ");
        sql.append("\n    inner join product_sys_menus m on rc.function_uuid=m.function_uuid ");
        sql.append("\n    inner join product_sys_report_type_config rtc on rc.type_uuid=rtc.uuid ");
        sql.append("\n    inner join product_sys_menus mp on m.tricode_parent=mp.tricode ");
//        sql.append("\n) t2 ");
        if (!StringUtils.isEmpty(filter)) {
            sql.append(" WHERE " + filter);
        }
        Integer curPage = fse.getInteger(CmnConst.CPAGE);
        Integer pageSize = fse.getInteger(CmnConst.PAGESIZE);
        return baseDao.listTable(sql.toString(), new Object[]{}, pageSize == null ? Integer.MAX_VALUE : pageSize, curPage == null ? 1 : curPage);
    }
        if (!StringUtils.isEmpty(filter)) {
            sql.append(" WHERE " + filter);
        }
        Integer curPage = fse.getInteger(CmnConst.CPAGE);
        Integer pageSize = fse.getInteger(CmnConst.PAGESIZE);
        return baseDao.listTable(sql.toString(), new Object[]{}, pageSize == null ? Integer.MAX_VALUE : pageSize, curPage == null ? 1 : curPage);
    }
}
src/main/java/com/product/server/report/service/ReportDatasourceService.java
@@ -1,18 +1,16 @@
package com.product.server.report.service;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.*;
import java.util.*;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.product.core.entity.RequestParameterEntity;
import com.product.core.service.support.QueryFilterService;
import com.product.server.report.util.QuerySqlParseUtil;
import com.product.util.BaseUtil;
import com.product.util.CallBack;
import org.springframework.beans.factory.annotation.Autowired;
@@ -148,7 +146,7 @@
    /**
     * sql解析与验证
     *
     * @param sqlText
     * @param fse
     * @return
     */
    public DataTableEntity sqlVerify(FieldSetEntity fse) throws SQLException {
@@ -266,47 +264,51 @@
                sql = sql.replace(ternaryOperator, "");
            }
        }
        sql = sql.replaceAll("\\[\\[((?!\\[).)+\\]\\]", "");
        sql = sql.replaceAll("\\[\\[((?!\\[).)+\\]\\]", "")
                .replaceAll("and\\s+1\\s*=\\s*1", "")
                .replaceAll("\\{=.+=\\}", "")
                .replaceAll("(\\t*\\n){2,}", "\n");
        sql = QuerySqlParseUtil.parseSplitTableSql(baseDao, sql, true);
        SpringMVCContextHolder.getSystemLogger().info(sql);
        //与数据库的连接
        PreparedStatement ps = null;
        Connection con = null;
        con = ConnectionManager.getConnection();
        sql = sql.replaceAll("and\\s+1\\s*=\\s*1", "");
        ps = con.prepareStatement(sql);
        //结果集元数据
        ResultSetMetaData rsmd = ps.getMetaData();
        //表列数
        int size = rsmd.getColumnCount();
        Set<String> fieldNameSet = Sets.newHashSet();
        for (int i = 1; i <= size; i++) {
            FieldSetEntity fieldSetEntity = new FieldSetEntity();
            FieldMetaEntity f = new FieldMetaEntity();
            f.setTableName(new Object[]{CmnConst.PRODUCT_SYS_DATAMODEL_FIELD});
            fieldSetEntity.setMeta(f);
            fieldSetEntity.setValue(CmnConst.TABLE_NAME, rsmd.getTableName(i));//获取表名
            //字段名或别名
            fieldSetEntity.setValue(CmnConst.FIELD_NAME, rsmd.getColumnLabel(i));
            //字段类型
            fieldSetEntity.setValue(CmnConst.FIELD_FORMAT, "string");
            // æŸ¥è¯¢ç±»åž‹
            fieldSetEntity.setValue(CmnConst.SEARCH_TYPE, -1);
            //获取指定列的指定列大小
        try (Connection con = ConnectionManager.getConnection();
            PreparedStatement ps = con.prepareStatement(sql);
            ResultSet rs = ps.executeQuery()) {
            //结果集元数据
            ResultSetMetaData rsmd = rs.getMetaData();
            //表列数
            int size = rsmd.getColumnCount();
            Set<String> fieldNameSet = Sets.newHashSet();
            for (int i = 1; i <= size; i++) {
                FieldSetEntity fieldSetEntity = new FieldSetEntity();
                FieldMetaEntity f = new FieldMetaEntity();
                f.setTableName(new Object[]{CmnConst.PRODUCT_SYS_DATAMODEL_FIELD});
                fieldSetEntity.setMeta(f);
                fieldSetEntity.setValue(CmnConst.TABLE_NAME, rsmd.getTableName(i));//获取表名
                //字段名或别名
                fieldSetEntity.setValue(CmnConst.FIELD_NAME, rsmd.getColumnLabel(i));
                //字段类型
                fieldSetEntity.setValue(CmnConst.FIELD_FORMAT, "string");
                // æŸ¥è¯¢ç±»åž‹
                fieldSetEntity.setValue(CmnConst.SEARCH_TYPE, -1);
                //获取指定列的指定列大小
//            fieldSetEntity.setValue(CmnConst.FIELD_LENGTH, rsmd.getPrecision(i));
            dataTableEntity.addFieldSetEntity(fieldSetEntity);
            fieldNameSet.add(fieldSetEntity.getString(CmnConst.FIELD_NAME));
        }
        for (String columnName : customColumnName) {
            if (fieldNameSet.contains(columnName)) {
                continue;
                dataTableEntity.addFieldSetEntity(fieldSetEntity);
                fieldNameSet.add(fieldSetEntity.getString(CmnConst.FIELD_NAME));
            }
            FieldSetEntity fs = new FieldSetEntity();
            fs.setTableName(CmnConst.PRODUCT_SYS_DATAMODEL_FIELD);
            fs.setValue(CmnConst.FIELD_NAME, columnName);
            fs.setValue(CmnConst.FIELD_FORMAT, "string");
            fs.setValue(CmnConst.SEARCH_TYPE, -1);
            dataTableEntity.addFieldSetEntity(fs);
            for (String columnName : customColumnName) {
                if (fieldNameSet.contains(columnName)) {
                    continue;
                }
                FieldSetEntity fs = new FieldSetEntity();
                fs.setTableName(CmnConst.PRODUCT_SYS_DATAMODEL_FIELD);
                fs.setValue(CmnConst.FIELD_NAME, columnName);
                fs.setValue(CmnConst.FIELD_FORMAT, "string");
                fs.setValue(CmnConst.SEARCH_TYPE, -1);
                dataTableEntity.addFieldSetEntity(fs);
            }
            return dataTableEntity;
        }
        return dataTableEntity;
    }
    /**