diff --git a/README.md b/README.md index 557affa2f9..7129f2ac8b 100644 --- a/README.md +++ b/README.md @@ -22,16 +22,16 @@ DataEase 是开源的数据可视化分析工具( BI 工具 ),帮助用户 **DataEase 支持的数据源:** -- OLTP 数据库: MySQL、Oracle、SQL Server、PostgreSQL、MariaDB、Db2、TiDB、MongoDB-BI 等; -- OLAP 数据库: ClickHouse、Apache Doris、Apache Impala、StarRocks 等; -- 数据仓库/数据湖: Amazon RedShift 等; -- 数据文件: Excel、CSV 等; +- OLTP 数据库: MySQL、Oracle、SQL Server、PostgreSQL、MariaDB、Db2、TiDB、MongoDB-BI 等; +- OLAP 数据库: ClickHouse、Apache Doris、Apache Impala、StarRocks 等; +- 数据仓库/数据湖: Amazon RedShift 等; +- 数据文件: Excel、CSV 等; - API 数据源。 ## 快速开始 ``` -# 准备一台 2核4G 以上 Linux 服务器,以 root 运行以下一键安装脚本: +# 准备一台 2 核 4G 以上的 Linux 服务器,并以 root 用户运行以下一键安装脚本: curl -sSL https://dataease.oss-cn-hangzhou.aliyuncs.com/quick_start_v2.sh | bash @@ -74,12 +74,12 @@ curl -sSL https://dataease.oss-cn-hangzhou.aliyuncs.com/quick_start_v2.sh | bash - 数据处理:[Apache Calcite](https://github.com/apache/calcite/)、[Apache SeaTunnel](https://github.com/apache/seatunnel) - 基础设施:[Docker](https://www.docker.com/) -## 我们的其他明星开源项目 +## 飞致云的其他明星项目 -- [JumpServer](https://github.com/jumpserver/jumpserver/) - 广受欢迎的开源堡垒机 - [1Panel](https://github.com/1panel-dev/1panel/) - 现代化、开源的 Linux 服务器运维管理面板 -- [Halo](https://github.com/halo-dev/halo/) - 强大易用的开源建站工具 - [MaxKB](https://github.com/1panel-dev/MaxKB/) - 基于 LLM 大语言模型的开源知识库问答系统 +- [JumpServer](https://github.com/jumpserver/jumpserver/) - 广受欢迎的开源堡垒机 +- [Halo](https://github.com/halo-dev/halo/) - 强大易用的开源建站工具 - [MeterSphere](https://github.com/metersphere/metersphere/) - 开源的测试管理和接口测试工具 ## License diff --git a/core/core-backend/src/main/java/io/dataease/MybatisPlusGenerator.java b/core/core-backend/src/main/java/io/dataease/MybatisPlusGenerator.java index 2c7d9c5aa8..3e5d0ddc25 100644 --- a/core/core-backend/src/main/java/io/dataease/MybatisPlusGenerator.java +++ b/core/core-backend/src/main/java/io/dataease/MybatisPlusGenerator.java @@ -14,18 +14,18 @@ public class MybatisPlusGenerator { * 第一 我嫌麻烦 * 第二 后面配置会放到nacos读起来更麻烦了 */ - private static final String url = "jdbc:mysql://localhost:3306/de_standalone?autoReconnect=false&useUnicode=true&characterEncoding=UTF-8&characterSetResults=UTF-8&zeroDateTimeBehavior=convertToNull&useSSL=false"; + private static final String url = "jdbc:mysql://localhost:3306/dataease?autoReconnect=false&useUnicode=true&characterEncoding=UTF-8&characterSetResults=UTF-8&zeroDateTimeBehavior=convertToNull&useSSL=false"; private static final String username = "root"; - private static final String password = "Password123@mysql"; + private static final String password = "123456"; /** * 业务模块例如datasource,dataset,panel等 */ - private static final String busi = "share"; + private static final String busi = "visualization"; /** * 这是要生成代码的表名称 */ - private static final String TABLE_NAME = "xpack_share"; + private static final String TABLE_NAME = "visualization_report_filter"; /** * 下面两个配置基本上不用动 diff --git a/core/core-backend/src/main/java/io/dataease/chart/charts/AbstractChartHandler.java b/core/core-backend/src/main/java/io/dataease/chart/charts/AbstractChartHandler.java new file mode 100644 index 0000000000..c8cac291ab --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/chart/charts/AbstractChartHandler.java @@ -0,0 +1,14 @@ +package io.dataease.chart.charts; + +import io.dataease.datasource.provider.CalciteProvider; +import io.dataease.extensions.view.dto.*; +import io.dataease.extensions.view.model.SQLMeta; + +import java.util.List; +import java.util.Map; + +public abstract class AbstractChartHandler { + public abstract T formatAxis(ChartViewDTO view); + public abstract T customFilter(ChartViewDTO view, List filterList, K formatResult); + public abstract T calcChartResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, Map sqlMap, SQLMeta sqlMeta, CalciteProvider provider); +} diff --git a/core/core-backend/src/main/java/io/dataease/chart/charts/ChartHandlerManager.java b/core/core-backend/src/main/java/io/dataease/chart/charts/ChartHandlerManager.java new file mode 100644 index 0000000000..a59cd0a239 --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/chart/charts/ChartHandlerManager.java @@ -0,0 +1,28 @@ +package io.dataease.chart.charts; + +import io.dataease.chart.charts.impl.DefaultChartHandler; +import jakarta.annotation.Resource; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; + +import java.util.concurrent.ConcurrentHashMap; + +@Component +public class ChartHandlerManager { + @Lazy + @Resource + private DefaultChartHandler defaultChartHandler; + private static final ConcurrentHashMap CHART_HANDLER_MAP = new ConcurrentHashMap<>(); + + public void registerChartHandler(String render, String type, AbstractChartHandler chartHandler) { + CHART_HANDLER_MAP.put(render + "-" + type, chartHandler); + } + + public AbstractChartHandler getChartHandler(String render, String type) { + var handler = CHART_HANDLER_MAP.get(render + "-" + type); + if (handler == null) { + return defaultChartHandler; + } + return handler; + } +} diff --git a/core/core-backend/src/main/java/io/dataease/chart/charts/impl/DefaultChartHandler.java b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/DefaultChartHandler.java new file mode 100644 index 0000000000..04521cef18 --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/DefaultChartHandler.java @@ -0,0 +1,495 @@ +package io.dataease.chart.charts.impl; + +import io.dataease.chart.charts.AbstractChartHandler; +import io.dataease.chart.constant.ChartConstants; +import io.dataease.chart.manage.ChartViewManege; +import io.dataease.chart.utils.ChartDataBuild; +import io.dataease.dataset.dto.DatasourceSchemaDTO; +import io.dataease.dataset.manage.DatasetTableFieldManage; +import io.dataease.dataset.utils.SqlUtils; +import io.dataease.datasource.provider.CalciteProvider; +import io.dataease.datasource.request.DatasourceRequest; +import io.dataease.engine.constant.SQLConstants; +import io.dataease.engine.sql.SQLProvider; +import io.dataease.engine.trans.Dimension2SQLObj; +import io.dataease.engine.trans.Quota2SQLObj; +import io.dataease.engine.utils.Utils; +import io.dataease.extensions.view.dto.*; +import io.dataease.chart.charts.ChartHandlerManager; +import io.dataease.extensions.view.model.SQLMeta; +import io.dataease.extensions.view.util.ChartDataUtil; +import io.dataease.extensions.view.util.FieldUtil; +import io.dataease.utils.BeanUtils; +import io.dataease.utils.JsonUtil; +import jakarta.annotation.PostConstruct; +import jakarta.annotation.Resource; +import lombok.Getter; +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Component; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +@Component +public class DefaultChartHandler extends AbstractChartHandler { + @Resource + protected ChartHandlerManager chartHandlerManager; + @Resource + protected DatasetTableFieldManage datasetTableFieldManage; + @Resource + protected ChartViewManege chartViewManege; + @Getter + private String render = "antv"; + @Getter + private String type = "*"; + + @PostConstruct + public void init(){ + chartHandlerManager.registerChartHandler(this.getRender(), this.getType(), this); + } + + @Override + public AxisFormatResult formatAxis(ChartViewDTO view) { + var axisMap = new HashMap>(); + var context = new HashMap(); + var result = new AxisFormatResult(axisMap, context); + axisMap.put(ChartAxis.xAxis, new ArrayList<>(view.getXAxis())); + axisMap.put(ChartAxis.yAxis, new ArrayList<>(view.getYAxis())); + axisMap.put(ChartAxis.drill, new ArrayList<>(view.getDrillFields())); + return result; + } + + @Override + public T customFilter(ChartViewDTO view, List filterList, K formatResult) { + return (T) new CustomFilterResult(filterList, formatResult.getContext()); + } + + public Map buildResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, List data) { + boolean isDrill = filterResult + .getFilterList() + .stream() + .anyMatch(ele -> ele.getFilterType() == 1); + var xAxis = formatResult.getAxisMap().get(ChartAxis.xAxis); + var yAxis = formatResult.getAxisMap().get(ChartAxis.yAxis); + Map result = ChartDataBuild.transChartData(xAxis, yAxis, view, data, isDrill); + return result; + } + + @Override + public T calcChartResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, Map sqlMap, SQLMeta sqlMeta, CalciteProvider provider) { + var dsMap = (Map) sqlMap.get("dsMap"); + List dsList = new ArrayList<>(); + for (Map.Entry next : dsMap.entrySet()) { + dsList.add(next.getValue().getType()); + } + boolean needOrder = Utils.isNeedOrder(dsList); + boolean crossDs = Utils.isCrossDs(dsMap); + DatasourceRequest datasourceRequest = new DatasourceRequest(); + datasourceRequest.setDsList(dsMap); + var xAxis = formatResult.getAxisMap().get(ChartAxis.xAxis); + var yAxis = formatResult.getAxisMap().get(ChartAxis.yAxis); + var allFields = getAllChartFields(view); + filterResult.getContext().put("allFields", allFields); + Dimension2SQLObj.dimension2sqlObj(sqlMeta, xAxis, FieldUtil.transFields(allFields), crossDs, dsMap); + Quota2SQLObj.quota2sqlObj(sqlMeta, yAxis, FieldUtil.transFields(allFields), crossDs, dsMap); + String querySql = SQLProvider.createQuerySQL(sqlMeta, true, needOrder, view); + querySql = SqlUtils.rebuildSQL(querySql, sqlMeta, crossDs, dsMap); + datasourceRequest.setQuery(querySql); + List data = (List) provider.fetchResultField(datasourceRequest).get("data"); + //自定义排序 + data = ChartDataUtil.resultCustomSort(xAxis, data); + //快速计算 + quickCalc(xAxis, yAxis, data); + //数据重组逻辑可重载 + var result = this.buildResult(view, formatResult, filterResult, data); + T calcResult = (T) new ChartCalcDataResult(); + calcResult.setData(result); + calcResult.setContext(filterResult.getContext()); + calcResult.setQuerySql(querySql); + calcResult.setOriginData(data); + return calcResult; + } + + protected List getAllChartFields(ChartViewDTO view) { + // get all fields + Map> stringListMap = chartViewManege.listByDQ(view.getTableId(), view.getId(), view); + List dimensionList = stringListMap.get("dimensionList"); + List quotaList = stringListMap.get("quotaList"); + List allFields = new ArrayList<>(); + allFields.addAll(dimensionList); + allFields.addAll(quotaList); + return allFields.stream().filter(ele -> ele.getId() != -1L).collect(Collectors.toList()); + } + + protected List getDynamicAssistFields(ChartViewDTO view) throws Exception { + List list = new ArrayList<>(); + + Map senior = view.getSenior(); + if (ObjectUtils.isEmpty(senior)) { + return list; + } + + ChartSeniorAssistCfgDTO assistLineCfg = JsonUtil.parseObject((String) JsonUtil.toJSONString(senior.get("assistLineCfg")), ChartSeniorAssistCfgDTO.class); + if (null == assistLineCfg || !assistLineCfg.isEnable()) { + return list; + } + List assistLines = assistLineCfg.getAssistLine(); + + if (ObjectUtils.isEmpty(assistLines)) { + return list; + } + + for (ChartSeniorAssistDTO dto : assistLines) { + if (StringUtils.equalsIgnoreCase(dto.getField(), "0")) { + continue; + } + Long fieldId = dto.getFieldId(); + String summary = dto.getSummary(); + if (ObjectUtils.isEmpty(fieldId) || StringUtils.isEmpty(summary)) { + continue; + } + + DatasetTableFieldDTO datasetTableFieldDTO = datasetTableFieldManage.selectById(fieldId); + + if (ObjectUtils.isEmpty(datasetTableFieldDTO)) { + continue; + } + list.add(dto); + } + return list; + } + + protected List getAssistFields(List list, List yAxis) { + List res = new ArrayList<>(); + for (ChartSeniorAssistDTO dto : list) { + DatasetTableFieldDTO curField = dto.getCurField(); + ChartViewFieldDTO yField = null; + String alias = ""; + for (int i = 0; i < yAxis.size(); i++) { + ChartViewFieldDTO field = yAxis.get(i); + if (Objects.equals(field.getId(), curField.getId())) { + yField = field; + alias = String.format(SQLConstants.FIELD_ALIAS_Y_PREFIX, i); + break; + } + } + if (ObjectUtils.isEmpty(yField)) { + continue; + } + + ChartViewFieldDTO chartViewFieldDTO = new ChartViewFieldDTO(); + BeanUtils.copyBean(chartViewFieldDTO, curField); + chartViewFieldDTO.setSummary(dto.getSummary()); + chartViewFieldDTO.setOriginName(alias);// yAxis的字段别名,就是查找的字段名 + res.add(chartViewFieldDTO); + } + return res; + } + + protected String assistSQL(String sql, List assistFields) { + StringBuilder stringBuilder = new StringBuilder(); + for (int i = 0; i < assistFields.size(); i++) { + ChartViewFieldDTO dto = assistFields.get(i); + if (i == (assistFields.size() - 1)) { + stringBuilder.append(dto.getSummary() + "(" + dto.getOriginName() + ")"); + } else { + stringBuilder.append(dto.getSummary() + "(" + dto.getOriginName() + "),"); + } + } + return "SELECT " + stringBuilder + " FROM (" + sql + ") tmp"; + } + + protected void quickCalc(List xAxis, List yAxis, List data) { + for (int i = 0; i < yAxis.size(); i++) { + ChartViewFieldDTO chartViewFieldDTO = yAxis.get(i); + ChartFieldCompareDTO compareCalc = chartViewFieldDTO.getCompareCalc(); + if (ObjectUtils.isEmpty(compareCalc)) { + continue; + } + if (StringUtils.isNotEmpty(compareCalc.getType()) + && !StringUtils.equalsIgnoreCase(compareCalc.getType(), "none")) { + Long compareFieldId = compareCalc.getField();// 选中字段 + // 数据字段下标 + int dataIndex = xAxis.size() + i; + if (Arrays.asList(ChartConstants.M_Y).contains(compareCalc.getType())) { + String resultData = compareCalc.getResultData();// 数据设置 + // 获取选中字段以及下标 + List checkedField = new ArrayList<>(xAxis); + int timeIndex = 0;// 时间字段下标 + ChartViewFieldDTO timeField = null; + for (int j = 0; j < checkedField.size(); j++) { + if (Objects.equals(checkedField.get(j).getId(), compareFieldId)) { + timeIndex = j; + timeField = checkedField.get(j); + } + } + // 无选中字段,或者选中字段已经不在维度list中,或者选中字段日期格式不符合对比类型的,直接将对应数据置为null + if (ObjectUtils.isEmpty(timeField) || !checkCalcType(timeField.getDateStyle(), compareCalc.getType())) { + // set null + for (String[] item : data) { + item[dataIndex] = null; + } + } else { + // 计算 同比/环比 + // 1,处理当期数据;2,根据type计算上一期数据;3,根据resultData计算结果 + Map currentMap = new LinkedHashMap<>(); + for (String[] item : data) { + String[] dimension = Arrays.copyOfRange(item, 0, checkedField.size()); + currentMap.put(StringUtils.join(dimension, "-"), item[dataIndex]); + } + + for (int index = 0; index < data.size(); index++) { + String[] item = data.get(index); + String cTime = item[timeIndex]; + String cValue = item[dataIndex]; + + // 获取计算后的时间,并且与所有维度拼接 + String lastTime = calcLastTime(cTime, compareCalc.getType(), timeField.getDateStyle(), timeField.getDatePattern()); + String[] dimension = Arrays.copyOfRange(item, 0, checkedField.size()); + dimension[timeIndex] = lastTime; + + String lastValue = currentMap.get(StringUtils.join(dimension, "-")); + if (StringUtils.isEmpty(cValue) || StringUtils.isEmpty(lastValue)) { + item[dataIndex] = null; + } else { + if (StringUtils.equalsIgnoreCase(resultData, "sub")) { + item[dataIndex] = new BigDecimal(cValue).subtract(new BigDecimal(lastValue)).toString(); + } else if (StringUtils.equalsIgnoreCase(resultData, "percent")) { + if (new BigDecimal(lastValue).compareTo(BigDecimal.ZERO) == 0) { + item[dataIndex] = null; + } else { + item[dataIndex] = new BigDecimal(cValue) + .divide(new BigDecimal(lastValue).abs(), 8, RoundingMode.HALF_UP) + .subtract(new BigDecimal(1)) + .setScale(8, RoundingMode.HALF_UP) + .toString(); + } + } + } + } + } + } else if (StringUtils.equalsIgnoreCase(compareCalc.getType(), "percent")) { + // 求和 + BigDecimal sum = new BigDecimal(0); + for (int index = 0; index < data.size(); index++) { + String[] item = data.get(index); + String cValue = item[dataIndex]; + if (StringUtils.isEmpty(cValue)) { + continue; + } + sum = sum.add(new BigDecimal(cValue)); + } + // 计算占比 + for (int index = 0; index < data.size(); index++) { + String[] item = data.get(index); + String cValue = item[dataIndex]; + if (StringUtils.isEmpty(cValue)) { + continue; + } + item[dataIndex] = new BigDecimal(cValue) + .divide(sum, 8, RoundingMode.HALF_UP) + .toString(); + } + } + } + } + } + + private String calcLastTime(String cTime, String type, String dateStyle, String datePattern) { + try { + String lastTime = null; + Calendar calendar = Calendar.getInstance(); + if (StringUtils.equalsIgnoreCase(type, ChartConstants.YEAR_MOM)) { + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy"); + Date date = simpleDateFormat.parse(cTime); + calendar.setTime(date); + calendar.add(Calendar.YEAR, -1); + lastTime = simpleDateFormat.format(calendar.getTime()); + } else if (StringUtils.equalsIgnoreCase(type, ChartConstants.MONTH_MOM)) { + SimpleDateFormat simpleDateFormat = null; + if (StringUtils.equalsIgnoreCase(datePattern, "date_split")) { + simpleDateFormat = new SimpleDateFormat("yyyy/MM"); + } else { + simpleDateFormat = new SimpleDateFormat("yyyy-MM"); + } + Date date = simpleDateFormat.parse(cTime); + calendar.setTime(date); + calendar.add(Calendar.MONTH, -1); + lastTime = simpleDateFormat.format(calendar.getTime()); + } else if (StringUtils.equalsIgnoreCase(type, ChartConstants.YEAR_YOY)) { + SimpleDateFormat simpleDateFormat = null; + if (StringUtils.equalsIgnoreCase(dateStyle, "y_M")) { + if (StringUtils.equalsIgnoreCase(datePattern, "date_split")) { + simpleDateFormat = new SimpleDateFormat("yyyy/MM"); + } else { + simpleDateFormat = new SimpleDateFormat("yyyy-MM"); + } + } else if (StringUtils.equalsIgnoreCase(dateStyle, "y_M_d")) { + if (StringUtils.equalsIgnoreCase(datePattern, "date_split")) { + simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd"); + } else { + simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); + } + } + Date date = simpleDateFormat.parse(cTime); + calendar.setTime(date); + calendar.add(Calendar.YEAR, -1); + lastTime = simpleDateFormat.format(calendar.getTime()); + } else if (StringUtils.equalsIgnoreCase(type, ChartConstants.DAY_MOM)) { + SimpleDateFormat simpleDateFormat = null; + if (StringUtils.equalsIgnoreCase(datePattern, "date_split")) { + simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd"); + } else { + simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); + } + Date date = simpleDateFormat.parse(cTime); + calendar.setTime(date); + calendar.add(Calendar.DAY_OF_MONTH, -1); + lastTime = simpleDateFormat.format(calendar.getTime()); + } else if (StringUtils.equalsIgnoreCase(type, ChartConstants.MONTH_YOY)) { + SimpleDateFormat simpleDateFormat = null; + if (StringUtils.equalsIgnoreCase(dateStyle, "y_M")) { + if (StringUtils.equalsIgnoreCase(datePattern, "date_split")) { + simpleDateFormat = new SimpleDateFormat("yyyy/MM"); + } else { + simpleDateFormat = new SimpleDateFormat("yyyy-MM"); + } + } else if (StringUtils.equalsIgnoreCase(dateStyle, "y_M_d")) { + if (StringUtils.equalsIgnoreCase(datePattern, "date_split")) { + simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd"); + } else { + simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); + } + } + Date date = simpleDateFormat.parse(cTime); + calendar.setTime(date); + calendar.add(Calendar.MONTH, -1); + lastTime = simpleDateFormat.format(calendar.getTime()); + } + return lastTime; + } catch (Exception e) { + return cTime; + } + } + + private boolean checkCalcType(String dateStyle, String calcType) { + switch (dateStyle) { + case "y": + return StringUtils.equalsIgnoreCase(calcType, "year_mom"); + case "y_M": + return StringUtils.equalsIgnoreCase(calcType, "month_mom") + || StringUtils.equalsIgnoreCase(calcType, "year_yoy"); + case "y_M_d": + return StringUtils.equalsIgnoreCase(calcType, "day_mom") + || StringUtils.equalsIgnoreCase(calcType, "month_yoy") + || StringUtils.equalsIgnoreCase(calcType, "year_yoy"); + } + return false; + } + + protected boolean checkYoyFilter(List filter, List yoyAxis){ + boolean flag = false; + for (ChartExtFilterDTO filterDTO : filter) { + for (ChartViewFieldDTO chartViewFieldDTO : yoyAxis) { + ChartFieldCompareDTO compareCalc = chartViewFieldDTO.getCompareCalc(); + if (ObjectUtils.isEmpty(compareCalc)) { + continue; + } + if (StringUtils.isNotEmpty(compareCalc.getType()) + && !StringUtils.equalsIgnoreCase(compareCalc.getType(), "none")) { + if (Arrays.asList(ChartConstants.M_Y).contains(compareCalc.getType())) { + if (StringUtils.equalsIgnoreCase(compareCalc.getField() + "", filterDTO.getFieldId()) && filterDTO.getFilterType() == 0) { + // -1 year + try { + Calendar calendar = Calendar.getInstance(); + calendar.setTime(new Date(Long.parseLong(filterDTO.getValue().getFirst()))); + calendar.add(Calendar.YEAR, -1); + filterDTO.getValue().set(0, String.valueOf(calendar.getTime().getTime())); + flag = true; + } catch (Exception e) { + } + } + } + } + } + } + return flag; + }; + + protected void groupStackDrill(List xAxis, + List filterList, + List fieldsToFilter, + List drillFields, + List drillRequestList) { + var fields = xAxis.stream().map(ChartViewFieldDTO::getId).collect(Collectors.toSet()); + ChartDrillRequest head = drillRequestList.get(0); + Map dimValMap = new HashMap<>(); + head.getDimensionList().forEach(item -> dimValMap.put(item.getId(), item.getValue())); + Map fieldMap = xAxis.stream().collect(Collectors.toMap(ChartViewFieldDTO::getId, o -> o, ((p, n) -> p))); + for (int i = 0; i < drillRequestList.size(); i++) { + ChartDrillRequest request = drillRequestList.get(i); + ChartViewFieldDTO chartViewFieldDTO = drillFields.get(i); + for (ChartDimensionDTO requestDimension : request.getDimensionList()) { + // 将钻取值作为条件传递,将所有钻取字段作为xAxis并加上下一个钻取字段 + if (Objects.equals(requestDimension.getId(), chartViewFieldDTO.getId())) { + fieldsToFilter.add(chartViewFieldDTO); + dimValMap.put(requestDimension.getId(), requestDimension.getValue()); + if (!fields.contains(requestDimension.getId())) { + fieldMap.put(chartViewFieldDTO.getId(), chartViewFieldDTO); + chartViewFieldDTO.setSource(FieldSource.DRILL); + xAxis.add(chartViewFieldDTO); + fields.add(requestDimension.getId()); + } + if (i == drillRequestList.size() - 1) { + ChartViewFieldDTO nextDrillField = drillFields.get(i + 1); + if (!fields.contains(nextDrillField.getId())) { + // get drill list first element's sort,then assign to nextDrillField + nextDrillField.setSort(getDrillSort(xAxis, drillFields.get(0))); + nextDrillField.setSource(FieldSource.DRILL); + xAxis.add(nextDrillField); + fields.add(nextDrillField.getId()); + } + } + } + } + } + for (int i = 0; i < fieldsToFilter.size(); i++) { + ChartViewFieldDTO tmpField = fieldsToFilter.get(i); + ChartExtFilterDTO tmpFilter = new ChartExtFilterDTO(); + DatasetTableFieldDTO datasetTableField = datasetTableFieldManage.selectById(tmpField.getId()); + tmpFilter.setDatasetTableField(datasetTableField); + tmpFilter.setDateStyle(fieldMap.get(tmpField.getId()).getDateStyle()); + tmpFilter.setDatePattern(fieldMap.get(tmpField.getId()).getDatePattern()); + tmpFilter.setFieldId(String.valueOf(tmpField.getId())); + tmpFilter.setFilterType(1); + if (datasetTableField.getDeType() == 1) { + tmpFilter.setOperator("between"); + // 把value类似过滤组件处理,获得start time和end time + Map stringLongMap = Utils.parseDateTimeValue(dimValMap.get(tmpField.getId())); + tmpFilter.setValue(Arrays.asList(String.valueOf(stringLongMap.get("startTime")), String.valueOf(stringLongMap.get("endTime")))); + } else { + tmpFilter.setOperator("in"); + tmpFilter.setValue(Collections.singletonList(dimValMap.get(tmpField.getId()))); + } + filterList.add(tmpFilter); + } + } + + private String getDrillSort(List xAxis, ChartViewFieldDTO field) { + String res = ""; + for (ChartViewFieldDTO f : xAxis) { + if (Objects.equals(f.getId(), field.getId())) { + if (StringUtils.equalsIgnoreCase(f.getSort(), "asc") || StringUtils.equalsIgnoreCase(f.getSort(), "desc")) { + res = f.getSort(); + break; + } + } + } + return res; + } +} diff --git a/core/core-backend/src/main/java/io/dataease/chart/charts/impl/ExtQuotaChartHandler.java b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/ExtQuotaChartHandler.java new file mode 100644 index 0000000000..d0fbaa51b5 --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/ExtQuotaChartHandler.java @@ -0,0 +1,21 @@ +package io.dataease.chart.charts.impl; + +import io.dataease.extensions.view.dto.AxisFormatResult; +import io.dataease.extensions.view.dto.ChartAxis; +import io.dataease.extensions.view.dto.ChartViewDTO; +import io.dataease.extensions.view.dto.ChartViewFieldDTO; + +import java.util.ArrayList; + +public class ExtQuotaChartHandler extends DefaultChartHandler { + @Override + public AxisFormatResult formatAxis(ChartViewDTO view) { + var result = super.formatAxis(view); + var yAxis = result.getAxisMap().get(ChartAxis.yAxis); + yAxis.addAll(view.getExtLabel()); + yAxis.addAll(view.getExtTooltip()); + result.getAxisMap().put(ChartAxis.extLabel, view.getExtLabel()); + result.getAxisMap().put(ChartAxis.extTooltip, view.getExtTooltip()); + return result; + } +} diff --git a/core/core-backend/src/main/java/io/dataease/chart/charts/impl/GroupChartHandler.java b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/GroupChartHandler.java new file mode 100644 index 0000000000..fd45d9ad42 --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/GroupChartHandler.java @@ -0,0 +1,20 @@ +package io.dataease.chart.charts.impl; + + +import io.dataease.extensions.view.dto.AxisFormatResult; +import io.dataease.extensions.view.dto.ChartAxis; +import io.dataease.extensions.view.dto.ChartViewDTO; +import io.dataease.extensions.view.dto.ChartViewFieldDTO; + +import java.util.ArrayList; + +public class GroupChartHandler extends DefaultChartHandler { + @Override + public AxisFormatResult formatAxis(ChartViewDTO view) { + var result = super.formatAxis(view); + var xAxis = new ArrayList(view.getXAxis()); + xAxis.addAll(view.getXAxisExt()); + result.getAxisMap().put(ChartAxis.xAxis, xAxis); + return result; + } +} diff --git a/core/core-backend/src/main/java/io/dataease/chart/charts/impl/YoyChartHandler.java b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/YoyChartHandler.java new file mode 100644 index 0000000000..ce1793a1ce --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/YoyChartHandler.java @@ -0,0 +1,121 @@ +package io.dataease.chart.charts.impl; + + +import com.fasterxml.jackson.core.type.TypeReference; +import io.dataease.dataset.dto.DatasourceSchemaDTO; +import io.dataease.dataset.utils.SqlUtils; +import io.dataease.datasource.provider.CalciteProvider; +import io.dataease.datasource.request.DatasourceRequest; +import io.dataease.engine.sql.SQLProvider; +import io.dataease.engine.trans.ExtWhere2Str; +import io.dataease.engine.utils.Utils; +import io.dataease.extensions.view.dto.*; +import io.dataease.extensions.view.model.SQLMeta; +import io.dataease.extensions.view.util.FieldUtil; +import io.dataease.utils.JsonUtil; +import org.apache.commons.lang3.StringUtils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 带同环比计算的图表处理器 + */ +public class YoyChartHandler extends DefaultChartHandler { + @Override + public T customFilter(ChartViewDTO view, List filterList, K formatResult) { + var yAxis = formatResult.getAxisMap().get(ChartAxis.yAxis); + String originFilterJson = (String) JsonUtil.toJSONString(filterList); + // 如果设置了同环比的指标字段设置了过滤器,那就需要把该过滤器的时间往前回调一年 + // 计算完同环比之后,再把计算结果和原有的过滤结果对比,去除不该出现的前一年的数据 + boolean yoyFiltered = checkYoyFilter(filterList, yAxis); + if (yoyFiltered) { + List originFilter = JsonUtil.parseList(originFilterJson, new TypeReference<>() { + }); + formatResult.getContext().put("originFilter", originFilter); + formatResult.getContext().put("yoyFiltered", true); + } + return (T) new CustomFilterResult(filterList, formatResult.getContext()); + } + + @Override + public Map buildResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, List data) { + var yoyFiltered = filterResult.getContext().get("yoyFiltered") != null; + // 带过滤同环比直接返回原始数据,再由视图重新组装 + if (yoyFiltered) { + var result = new HashMap(); + result.put("data", data); + return result; + } + return buildNormalResult(view, formatResult, filterResult, data); + } + + /** + * 构建同环比类型的数据 + * @param view 视图对象 + * @param formatResult 处理后的轴 + * @param filterResult 处理后的过滤器 + * @param data 原始数据 + * @return 视图构建结果 + */ + public Map buildNormalResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, List data) { + return super.buildResult(view, formatResult, filterResult, data); + } + + @Override + public T calcChartResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, Map sqlMap, SQLMeta sqlMeta, CalciteProvider provider) { + var dsMap = (Map) sqlMap.get("dsMap"); + List dsList = new ArrayList<>(); + for (Map.Entry next : dsMap.entrySet()) { + dsList.add(next.getValue().getType()); + } + boolean needOrder = Utils.isNeedOrder(dsList); + boolean crossDs = Utils.isCrossDs(dsMap); + // 这里拿到的可能有一年前的数据 + var expandedResult = (T) super.calcChartResult(view, formatResult, filterResult, sqlMap, sqlMeta, provider); + // 检查同环比过滤,拿到实际数据 + var yoyFiltered = filterResult.getContext().get("yoyFiltered") != null; + if (yoyFiltered) { + var originFilter = (List) filterResult.getContext().get("originFilter"); + var allFields = (List) filterResult.getContext().get("allFields"); + ExtWhere2Str.extWhere2sqlOjb(sqlMeta, originFilter, FieldUtil.transFields(allFields), crossDs, dsMap); + var originSql = SQLProvider.createQuerySQL(sqlMeta, true, needOrder, view); + originSql = SqlUtils.rebuildSQL(originSql, sqlMeta, crossDs, dsMap); + var request = new DatasourceRequest(); + request.setDsList(dsMap); + request.setQuery(originSql); + // 实际过滤后的数据 + var originData = (List) provider.fetchResultField(request).get("data"); + List resultData = new ArrayList<>(); + // 包含一年前的数据, 已计算同环比 + var yoyData = (List) expandedResult.getData().get("data"); + var xAxis = formatResult.getAxisMap().get(ChartAxis.xAxis); + // 对比维度,只保留实际过滤后的数据 + for (String[] yoyDataLine : yoyData) { + StringBuilder x1 = new StringBuilder(); + for (int i = 0; i < xAxis.size(); i++) { + x1.append(yoyDataLine[i]); + } + for (String[] originDataLine : originData) { + StringBuilder x2 = new StringBuilder(); + for (int i = 0; i < xAxis.size(); i++) { + x2.append(originDataLine[i]); + } + if (StringUtils.equals(x1, x2)) { + resultData.add(yoyDataLine); + break; + } + } + } + yoyData.clear(); + yoyData.addAll(resultData); + var result = this.buildNormalResult(view, formatResult, filterResult, yoyData); + expandedResult.setData(result); + expandedResult.setOriginData(originData); + expandedResult.setQuerySql(originSql); + } + return expandedResult; + } +} diff --git a/core/core-backend/src/main/java/io/dataease/chart/charts/impl/bar/BarHandler.java b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/bar/BarHandler.java new file mode 100644 index 0000000000..a57fa02882 --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/bar/BarHandler.java @@ -0,0 +1,77 @@ +package io.dataease.chart.charts.impl.bar; + +import com.fasterxml.jackson.core.type.TypeReference; +import io.dataease.chart.charts.impl.YoyChartHandler; +import io.dataease.chart.constant.ChartConstants; +import io.dataease.dataset.dto.DatasourceSchemaDTO; +import io.dataease.dataset.utils.SqlUtils; +import io.dataease.datasource.provider.CalciteProvider; +import io.dataease.datasource.request.DatasourceRequest; +import io.dataease.engine.sql.SQLProvider; +import io.dataease.engine.trans.ExtWhere2Str; +import io.dataease.engine.utils.SQLUtils; +import io.dataease.engine.utils.Utils; +import io.dataease.extensions.view.dto.*; +import io.dataease.chart.charts.impl.DefaultChartHandler; +import io.dataease.extensions.view.model.SQLMeta; +import io.dataease.extensions.view.util.FieldUtil; +import io.dataease.utils.JsonUtil; +import lombok.Getter; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Component; + +import java.util.*; + +@Component +public class BarHandler extends YoyChartHandler { + + @Override + public void init() { + chartHandlerManager.registerChartHandler(this.getRender(), "bar", this); + chartHandlerManager.registerChartHandler(this.getRender(), "bar-horizontal", this); + } + + @Override + public AxisFormatResult formatAxis(ChartViewDTO view) { + var result = super.formatAxis(view); + var yAxis = result.getAxisMap().get(ChartAxis.yAxis); + yAxis.addAll(view.getExtLabel()); + yAxis.addAll(view.getExtTooltip()); + result.getAxisMap().put(ChartAxis.extLabel, view.getExtLabel()); + result.getAxisMap().put(ChartAxis.extTooltip, view.getExtTooltip()); + return result; + } + + @Override + public T calcChartResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, Map sqlMap, SQLMeta sqlMeta, CalciteProvider provider) { + var dsMap = (Map) sqlMap.get("dsMap"); + List dsList = new ArrayList<>(); + for (Map.Entry next : dsMap.entrySet()) { + dsList.add(next.getValue().getType()); + } + boolean needOrder = Utils.isNeedOrder(dsList); + boolean crossDs = Utils.isCrossDs(dsMap); + var result = (T) super.calcChartResult(view, formatResult, filterResult, sqlMap, sqlMeta, provider); + try { + //如果有同环比过滤,应该用原始sql + var originSql = result.getQuerySql(); + var dynamicAssistFields = getDynamicAssistFields(view); + var yAxis = formatResult.getAxisMap().get(ChartAxis.yAxis); + var assistFields = getAssistFields(dynamicAssistFields, yAxis); + if (CollectionUtils.isNotEmpty(assistFields)) { + var req = new DatasourceRequest(); + req.setDsList(dsMap); + var assistSql = assistSQL(originSql, assistFields); + req.setQuery(assistSql); + var assistData = (List) provider.fetchResultField(req).get("data"); + result.setAssistData(assistData); + result.setDynamicAssistFields(dynamicAssistFields); + } + } catch (Exception e) { + e.printStackTrace(); + } + return result; + } +} diff --git a/core/core-backend/src/main/java/io/dataease/chart/charts/impl/bar/BidirectionalBarHandler.java b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/bar/BidirectionalBarHandler.java new file mode 100644 index 0000000000..1b04272928 --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/bar/BidirectionalBarHandler.java @@ -0,0 +1,10 @@ +package io.dataease.chart.charts.impl.bar; + +import lombok.Getter; +import org.springframework.stereotype.Component; + +@Component +public class BidirectionalBarHandler extends ProgressBarHandler { + @Getter + private String type = "bidirectional-bar"; +} diff --git a/core/core-backend/src/main/java/io/dataease/chart/charts/impl/bar/GroupBarHandler.java b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/bar/GroupBarHandler.java new file mode 100644 index 0000000000..7547813156 --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/bar/GroupBarHandler.java @@ -0,0 +1,75 @@ +package io.dataease.chart.charts.impl.bar; + +import io.dataease.chart.utils.ChartDataBuild; +import io.dataease.engine.utils.Utils; +import io.dataease.extensions.view.dto.*; +import lombok.Getter; +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Component; + +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +@Component +public class GroupBarHandler extends BarHandler { + @Getter + private String type = "bar-group"; + + @Override + public AxisFormatResult formatAxis(ChartViewDTO view) { + var result = super.formatAxis(view); + var xAxis = result.getAxisMap().get(ChartAxis.xAxis); + xAxis.addAll(view.getXAxisExt()); + result.getAxisMap().put(ChartAxis.xAxisExt, view.getXAxisExt()); + return result; + } + + @Override + public void init() { + chartHandlerManager.registerChartHandler(this.getRender(), this.getType(), this); + } + + @Override + public T customFilter(ChartViewDTO view, List filterList, K formatResult) { + var result = super.customFilter(view, filterList, formatResult); + List drillRequestList = view.getChartExtRequest().getDrill(); + var drillFields = formatResult.getAxisMap().get(ChartAxis.drill); + // 分组维度下钻 + if (ObjectUtils.isNotEmpty(drillRequestList) && (drillFields.size() > drillRequestList.size())) { + List noDrillFilterList = filterList + .stream() + .filter(ele -> ele.getFilterType() != 1) + .collect(Collectors.toList()); + var noDrillFieldAxis = formatResult.getAxisMap().get(ChartAxis.xAxis) + .stream() + .filter(ele -> ele.getSource() != FieldSource.DRILL) + .collect(Collectors.toList()); + List drillFilters = new ArrayList<>(); + ArrayList fieldsToFilter = new ArrayList<>(); + var xAxisExt = formatResult.getAxisMap().get(ChartAxis.xAxisExt); + if (ObjectUtils.isNotEmpty(xAxisExt) && + Objects.equals(drillFields.get(0).getId(), xAxisExt.get(0).getId())) { + fieldsToFilter.addAll(view.getXAxis()); + } + groupStackDrill(noDrillFieldAxis, noDrillFilterList, fieldsToFilter, drillFields, drillRequestList); + formatResult.getAxisMap().put(ChartAxis.xAxis, noDrillFieldAxis); + result.setFilterList(noDrillFilterList); + } + return (T) result; + } + + @Override + public Map buildNormalResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, List data) { + boolean isDrill = filterResult + .getFilterList() + .stream() + .anyMatch(ele -> ele.getFilterType() == 1); + var xAxis = formatResult.getAxisMap().get(ChartAxis.xAxis); + var xAxisExt = formatResult.getAxisMap().get(ChartAxis.xAxisExt); + var yAxis = formatResult.getAxisMap().get(ChartAxis.yAxis); + var xAxisBase = xAxis.subList(0, xAxis.size() - xAxisExt.size()); + return ChartDataBuild.transBaseGroupDataAntV(xAxisBase, xAxis, xAxisExt, yAxis, view, data, isDrill); + } +} diff --git a/core/core-backend/src/main/java/io/dataease/chart/charts/impl/bar/ProgressBarHandler.java b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/bar/ProgressBarHandler.java new file mode 100644 index 0000000000..49fc7e7bc0 --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/bar/ProgressBarHandler.java @@ -0,0 +1,44 @@ +package io.dataease.chart.charts.impl.bar; + +import io.dataease.chart.utils.ChartDataBuild; +import io.dataease.extensions.view.dto.*; +import lombok.Getter; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +@Component +public class ProgressBarHandler extends BarHandler { + @Getter + private String type = "progress-bar"; + + @Override + public void init() { + chartHandlerManager.registerChartHandler(this.getRender(), this.getType(), this); + } + + @Override + public AxisFormatResult formatAxis(ChartViewDTO view) { + var result = super.formatAxis(view); + var yAxis = new ArrayList<>(view.getYAxis()); + yAxis.addAll(view.getYAxisExt()); + yAxis.addAll(view.getExtTooltip()); + result.getAxisMap().put(ChartAxis.yAxis, yAxis); + result.getAxisMap().put(ChartAxis.yAxisExt, view.getYAxisExt()); + return result; + } + + @Override + public Map buildNormalResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, List data) { + boolean isDrill = filterResult + .getFilterList() + .stream() + .anyMatch(ele -> ele.getFilterType() == 1); + var xAxis = formatResult.getAxisMap().get(ChartAxis.xAxis); + var yAxis = formatResult.getAxisMap().get(ChartAxis.yAxis); + Map result = ChartDataBuild.transMixChartDataAntV(xAxis, xAxis, new ArrayList<>(), yAxis, view, data, isDrill); + return result; + } +} diff --git a/core/core-backend/src/main/java/io/dataease/chart/charts/impl/bar/RangeBarHandler.java b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/bar/RangeBarHandler.java new file mode 100644 index 0000000000..5e05016e9d --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/bar/RangeBarHandler.java @@ -0,0 +1,81 @@ +package io.dataease.chart.charts.impl.bar; + +import io.dataease.chart.charts.impl.DefaultChartHandler; +import io.dataease.chart.charts.impl.YoyChartHandler; +import io.dataease.chart.utils.ChartDataBuild; +import io.dataease.datasource.provider.CalciteProvider; +import io.dataease.extensions.view.dto.*; +import io.dataease.extensions.view.model.SQLMeta; +import lombok.Getter; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.BooleanUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +@Component +public class RangeBarHandler extends YoyChartHandler { + @Getter + private String type = "bar-range"; + + @Override + public AxisFormatResult formatAxis(ChartViewDTO view) { + var result = super.formatAxis(view); + var yAxis = new ArrayList(); + var xAxis = new ArrayList(view.getXAxis()); + boolean skipBarRange = false; + boolean barRangeDate = false; + if (CollectionUtils.isNotEmpty(view.getYAxis()) && CollectionUtils.isNotEmpty(view.getYAxisExt())) { + ChartViewFieldDTO axis1 = view.getYAxis().get(0); + ChartViewFieldDTO axis2 = view.getYAxisExt().get(0); + + if (StringUtils.equalsIgnoreCase(axis1.getGroupType(), "q") && StringUtils.equalsIgnoreCase(axis2.getGroupType(), "q")) { + yAxis.add(axis1); + yAxis.add(axis2); + } else if (StringUtils.equalsIgnoreCase(axis1.getGroupType(), "d") && axis1.getDeType() == 1 && StringUtils.equalsIgnoreCase(axis2.getGroupType(), "d") && axis2.getDeType() == 1) { + barRangeDate = true; + if (BooleanUtils.isTrue(view.getAggregate())) { + axis1.setSummary("min"); + axis2.setSummary("max"); + yAxis.add(axis1); + yAxis.add(axis2); + } else { + xAxis.add(axis1); + xAxis.add(axis2); + } + } else { + skipBarRange = true; + } + } else { + skipBarRange = true; + } + result.getContext().put("skipBarRange", skipBarRange); + result.getContext().put("barRangeDate", barRangeDate); + result.getAxisMap().put(ChartAxis.xAxis, xAxis); + result.getAxisMap().put(ChartAxis.yAxis, yAxis); + return result; + } + + @Override + public Map buildNormalResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, List data) { + boolean isDrill = filterResult + .getFilterList() + .stream() + .anyMatch(ele -> ele.getFilterType() == 1); + var xAxis = formatResult.getAxisMap().get(ChartAxis.xAxis); + var yAxis = formatResult.getAxisMap().get(ChartAxis.yAxis); + var skipBarRange = (boolean) formatResult.getContext().get("skipBarRange"); + var barRangeDate = (boolean) formatResult.getContext().get("barRangeDate"); + Map result = ChartDataBuild.transBarRangeDataAntV(skipBarRange, barRangeDate, xAxis, xAxis, yAxis, view, data, isDrill); + return result; + } + + @Override + public T calcChartResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, Map sqlMap, SQLMeta sqlMeta, CalciteProvider provider) { + sqlMeta.setChartType(this.type); + return super.calcChartResult(view, formatResult, filterResult, sqlMap, sqlMeta, provider); + } +} diff --git a/core/core-backend/src/main/java/io/dataease/chart/charts/impl/bar/StackBarHandler.java b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/bar/StackBarHandler.java new file mode 100644 index 0000000000..614a865cec --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/bar/StackBarHandler.java @@ -0,0 +1,71 @@ +package io.dataease.chart.charts.impl.bar; + +import io.dataease.chart.utils.ChartDataBuild; +import io.dataease.extensions.view.dto.*; +import lombok.Getter; +import org.apache.commons.lang3.ObjectUtils; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +@Component +public class StackBarHandler extends BarHandler { + @Getter + private String type = "bar-stack"; + @Override + public void init() { + chartHandlerManager.registerChartHandler(this.getRender(), "bar-stack", this); + chartHandlerManager.registerChartHandler(this.getRender(), "bar-stack-horizontal", this); + chartHandlerManager.registerChartHandler(this.getRender(), "percentage-bar-stack", this); + chartHandlerManager.registerChartHandler(this.getRender(), "percentage-bar-stack-horizontal", this); + } + @Override + public AxisFormatResult formatAxis(ChartViewDTO view) { + var result = super.formatAxis(view); + var xAxis = result.getAxisMap().get(ChartAxis.xAxis); + xAxis.addAll(view.getExtStack()); + result.getAxisMap().put(ChartAxis.extStack, view.getExtStack()); + return result; + } + @Override + public T customFilter(ChartViewDTO view, List filterList, K formatResult) { + var result = super.customFilter(view, filterList, formatResult); + List drillRequestList = view.getChartExtRequest().getDrill(); + var drillFields = formatResult.getAxisMap().get(ChartAxis.drill); + // 堆叠维度下钻 + if (ObjectUtils.isNotEmpty(drillRequestList) && (drillFields.size() > drillRequestList.size())) { + List noDrillFilterList = filterList + .stream() + .filter(ele -> ele.getFilterType() != 1) + .collect(Collectors.toList()); + var noDrillFieldAxis = formatResult.getAxisMap().get(ChartAxis.xAxis) + .stream() + .filter(ele -> ele.getSource() != FieldSource.DRILL) + .collect(Collectors.toList()); + List drillFilters = new ArrayList<>(); + ArrayList fieldsToFilter = new ArrayList<>(); + var extStack = formatResult.getAxisMap().get(ChartAxis.extStack); + if (ObjectUtils.isNotEmpty(extStack) && + Objects.equals(drillFields.get(0).getId(), extStack.get(0).getId())) { + fieldsToFilter.addAll(view.getXAxis()); + } + groupStackDrill(noDrillFieldAxis, noDrillFilterList, fieldsToFilter, drillFields, drillRequestList); + formatResult.getAxisMap().put(ChartAxis.xAxis, noDrillFieldAxis); + result.setFilterList(noDrillFilterList); + } + return (T) result; + } + @Override + public Map buildNormalResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, List data) { + boolean isDrill = filterResult.getFilterList().stream().anyMatch(ele -> ele.getFilterType() == 1); + var xAxis = formatResult.getAxisMap().get(ChartAxis.xAxis); + var extStack = formatResult.getAxisMap().get(ChartAxis.extStack); + var yAxis = formatResult.getAxisMap().get(ChartAxis.yAxis); + var xAxisBase = xAxis.subList(0, xAxis.size() - extStack.size()); + return ChartDataBuild.transStackChartDataAntV(xAxisBase, yAxis, view, data, extStack, isDrill); + } +} diff --git a/core/core-backend/src/main/java/io/dataease/chart/charts/impl/bar/StackGroupBarHandler.java b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/bar/StackGroupBarHandler.java new file mode 100644 index 0000000000..1badf8d5a0 --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/bar/StackGroupBarHandler.java @@ -0,0 +1,90 @@ +package io.dataease.chart.charts.impl.bar; + +import io.dataease.chart.utils.ChartDataBuild; +import io.dataease.extensions.view.dto.*; +import lombok.Getter; +import org.apache.commons.lang3.ObjectUtils; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import static io.dataease.extensions.view.dto.ChartAxis.extStack; +import static io.dataease.extensions.view.dto.ChartAxis.xAxisExt; + +@Component +public class StackGroupBarHandler extends BarHandler { + @Getter + private String type = "bar-group-stack"; + + @Override + public void init() { + chartHandlerManager.registerChartHandler(this.getRender(), this.getType(), this); + } + + @Override + public AxisFormatResult formatAxis(ChartViewDTO view) { + var result = super.formatAxis(view); + var xAxis = result.getAxisMap().get(ChartAxis.xAxis); + xAxis.addAll(view.getXAxisExt()); + xAxis.addAll(view.getExtStack()); + result.getAxisMap().put(ChartAxis.xAxisExt, view.getExtStack()); + result.getAxisMap().put(ChartAxis.extStack, view.getExtStack()); + result.getAxisMap().put(ChartAxis.xAxisExt, view.getXAxisExt()); + return result; + } + + @Override + public T customFilter(ChartViewDTO view, List filterList, K formatResult) { + var result = super.customFilter(view, filterList, formatResult); + List drillRequestList = view.getChartExtRequest().getDrill(); + var drillFields = formatResult.getAxisMap().get(ChartAxis.drill); + // 分组维度下钻 + if (ObjectUtils.isNotEmpty(drillRequestList) && (drillFields.size() > drillRequestList.size())) { + List noDrillFilterList = filterList + .stream() + .filter(ele -> ele.getFilterType() != 1) + .collect(Collectors.toList()); + var noDrillFieldAxis = formatResult.getAxisMap().get(ChartAxis.xAxis) + .stream() + .filter(ele -> ele.getSource() != FieldSource.DRILL) + .collect(Collectors.toList()); + List drillFilters = new ArrayList<>(); + ArrayList fieldsToFilter = new ArrayList<>(); + var xAxisExt = formatResult.getAxisMap().get(ChartAxis.xAxisExt); + var extStack = formatResult.getAxisMap().get(ChartAxis.extStack); + if (ObjectUtils.isNotEmpty(xAxisExt) && ObjectUtils.isNotEmpty(extStack)) { + if (Objects.equals(drillFields.get(0).getId(), xAxisExt.get(0).getId())) { + fieldsToFilter.addAll(view.getXAxis()); + fieldsToFilter.addAll(extStack); + } + if (Objects.equals(drillFields.get(0).getId(), extStack.get(0).getId())) { + fieldsToFilter.addAll(view.getXAxis()); + fieldsToFilter.addAll(xAxisExt); + } + } + groupStackDrill(noDrillFieldAxis, noDrillFilterList, fieldsToFilter, drillFields, drillRequestList); + formatResult.getAxisMap().put(ChartAxis.xAxis, noDrillFieldAxis); + result.setFilterList(noDrillFilterList); + } + return (T) result; + } + + @Override + public Map buildNormalResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, List data) { + boolean isDrill = filterResult + .getFilterList() + .stream() + .anyMatch(ele -> ele.getFilterType() == 1); + var xAxis = formatResult.getAxisMap().get(ChartAxis.xAxis); + var xAxisExt = formatResult.getAxisMap().get(ChartAxis.xAxisExt); + var extStack = formatResult.getAxisMap().get(ChartAxis.extStack); + var yAxis = formatResult.getAxisMap().get(ChartAxis.yAxis); + var xAxisBase = xAxis.subList(0, xAxis.size() - xAxisExt.size() - extStack.size()); + var xAxisMain = xAxis.subList(0, xAxis.size() - extStack.size()); + return ChartDataBuild.transGroupStackDataAntV(xAxisBase, xAxisMain, xAxisExt, yAxis, extStack, data, view, isDrill); + } +} diff --git a/core/core-backend/src/main/java/io/dataease/chart/charts/impl/line/AreaHandler.java b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/line/AreaHandler.java new file mode 100644 index 0000000000..ea1787df99 --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/line/AreaHandler.java @@ -0,0 +1,31 @@ +package io.dataease.chart.charts.impl.line; + +import io.dataease.chart.utils.ChartDataBuild; +import io.dataease.extensions.view.dto.*; +import lombok.Getter; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; + +@Component +public class AreaHandler extends LineHandler { + @Getter + private String type = "area"; + + @Override + public AxisFormatResult formatAxis(ChartViewDTO view) { + var result = super.formatAxis(view); + result.getAxisMap().put(ChartAxis.xAxis, view.getXAxis()); + return result; + } + + + @Override + public Map buildNormalResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, List data) { + boolean isDrill = filterResult.getFilterList().stream().anyMatch(ele -> ele.getFilterType() == 1); + var xAxis = formatResult.getAxisMap().get(ChartAxis.xAxis); + var yAxis = formatResult.getAxisMap().get(ChartAxis.yAxis); + return ChartDataBuild.transChartData(xAxis, yAxis, view, data, isDrill); + } +} diff --git a/core/core-backend/src/main/java/io/dataease/chart/charts/impl/line/LineHandler.java b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/line/LineHandler.java new file mode 100644 index 0000000000..57ed1522dd --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/line/LineHandler.java @@ -0,0 +1,83 @@ +package io.dataease.chart.charts.impl.line; + +import io.dataease.chart.charts.impl.GroupChartHandler; +import io.dataease.chart.charts.impl.YoyChartHandler; +import io.dataease.chart.utils.ChartDataBuild; +import io.dataease.dataset.dto.DatasourceSchemaDTO; +import io.dataease.datasource.provider.CalciteProvider; +import io.dataease.datasource.request.DatasourceRequest; +import io.dataease.engine.utils.Utils; +import io.dataease.extensions.view.dto.*; +import io.dataease.extensions.view.model.SQLMeta; +import lombok.Getter; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +@Component +public class LineHandler extends YoyChartHandler { + @Getter + private String type = "line"; + + @Override + public AxisFormatResult formatAxis(ChartViewDTO view) { + var result = super.formatAxis(view); + var xAxis = result.getAxisMap().get(ChartAxis.xAxis); + xAxis.addAll(view.getXAxisExt()); + var yAxis = result.getAxisMap().get(ChartAxis.yAxis); + yAxis.addAll(view.getExtLabel()); + yAxis.addAll(view.getExtTooltip()); + result.getAxisMap().put(ChartAxis.xAxisExt, view.getXAxisExt()); + result.getAxisMap().put(ChartAxis.extLabel, view.getExtLabel()); + result.getAxisMap().put(ChartAxis.extTooltip, view.getExtTooltip()); + return result; + } + + @Override + public Map buildNormalResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, List data) { + boolean isDrill = filterResult + .getFilterList() + .stream() + .anyMatch(ele -> ele.getFilterType() == 1); + var xAxis = formatResult.getAxisMap().get(ChartAxis.xAxis); + var xAxisExt = formatResult.getAxisMap().get(ChartAxis.xAxisExt); + var yAxis = formatResult.getAxisMap().get(ChartAxis.yAxis); + var xAxisBase = xAxis.subList(0, xAxis.size() - xAxisExt.size()); + return ChartDataBuild.transBaseGroupDataAntV(xAxisBase, xAxis, xAxisExt, yAxis, view, data, isDrill); + } + + @Override + public T calcChartResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, Map sqlMap, SQLMeta sqlMeta, CalciteProvider provider) { + var dsMap = (Map) sqlMap.get("dsMap"); + List dsList = new ArrayList<>(); + for (Map.Entry next : dsMap.entrySet()) { + dsList.add(next.getValue().getType()); + } + boolean needOrder = Utils.isNeedOrder(dsList); + boolean crossDs = Utils.isCrossDs(dsMap); + var result = (T) super.calcChartResult(view, formatResult, filterResult, sqlMap, sqlMeta, provider); + try { + //如果有同环比过滤,应该用原始sql + var originSql = result.getQuerySql(); + var dynamicAssistFields = getDynamicAssistFields(view); + var yAxis = formatResult.getAxisMap().get(ChartAxis.yAxis); + var assistFields = getAssistFields(dynamicAssistFields, yAxis); + if (CollectionUtils.isNotEmpty(assistFields)) { + var req = new DatasourceRequest(); + req.setDsList(dsMap); + var assistSql = assistSQL(originSql, assistFields); + req.setQuery(assistSql); + var assistData = (List) provider.fetchResultField(req).get("data"); + result.setAssistData(assistData); + result.setDynamicAssistFields(dynamicAssistFields); + } + } catch (Exception e) { + e.printStackTrace(); + } + return result; + } +} diff --git a/core/core-backend/src/main/java/io/dataease/chart/charts/impl/line/StackAreaHandler.java b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/line/StackAreaHandler.java new file mode 100644 index 0000000000..a39e01c238 --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/line/StackAreaHandler.java @@ -0,0 +1,114 @@ +package io.dataease.chart.charts.impl.line; + +import io.dataease.chart.charts.impl.YoyChartHandler; +import io.dataease.chart.utils.ChartDataBuild; +import io.dataease.dataset.dto.DatasourceSchemaDTO; +import io.dataease.datasource.provider.CalciteProvider; +import io.dataease.datasource.request.DatasourceRequest; +import io.dataease.engine.utils.Utils; +import io.dataease.extensions.view.dto.*; +import io.dataease.extensions.view.model.SQLMeta; +import lombok.Getter; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +@Component +public class StackAreaHandler extends YoyChartHandler { + @Getter + private String type = "area-stack"; + + @Override + public AxisFormatResult formatAxis(ChartViewDTO view) { + var result = super.formatAxis(view); + var xAxis = result.getAxisMap().get(ChartAxis.xAxis); + xAxis.addAll(view.getExtStack()); + var yAxis = result.getAxisMap().get(ChartAxis.yAxis); + yAxis.addAll(view.getExtLabel()); + yAxis.addAll(view.getExtTooltip()); + result.getAxisMap().put(ChartAxis.extStack, view.getExtStack()); + result.getAxisMap().put(ChartAxis.extLabel, view.getExtLabel()); + result.getAxisMap().put(ChartAxis.extTooltip, view.getExtTooltip()); + return result; + } + + @Override + public Map buildNormalResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, List data) { + boolean isDrill = filterResult + .getFilterList() + .stream() + .anyMatch(ele -> ele.getFilterType() == 1); + var xAxis = formatResult.getAxisMap().get(ChartAxis.xAxis); + var extStack = formatResult.getAxisMap().get(ChartAxis.extStack); + var axisBase = xAxis.subList(0, xAxis.size() - extStack.size()); + var yAxis = formatResult.getAxisMap().get(ChartAxis.yAxis); + return ChartDataBuild.transStackChartDataAntV(axisBase, yAxis, view, data, extStack, isDrill); + } + + @Override + public T customFilter(ChartViewDTO view, List filterList, K formatResult) { + var result = super.customFilter(view, filterList, formatResult); + List drillRequestList = view.getChartExtRequest().getDrill(); + var drillFields = formatResult.getAxisMap().get(ChartAxis.drill); + // 堆叠维度下钻 + if (ObjectUtils.isNotEmpty(drillRequestList) && (drillFields.size() > drillRequestList.size())) { + List noDrillFilterList = filterList + .stream() + .filter(ele -> ele.getFilterType() != 1) + .collect(Collectors.toList()); + var noDrillFieldAxis = formatResult.getAxisMap().get(ChartAxis.xAxis) + .stream() + .filter(ele -> ele.getSource() != FieldSource.DRILL) + .collect(Collectors.toList()); + List drillFilters = new ArrayList<>(); + ArrayList fieldsToFilter = new ArrayList<>(); + var extStack = formatResult.getAxisMap().get(ChartAxis.extStack); + if (ObjectUtils.isNotEmpty(extStack) && + Objects.equals(drillFields.get(0).getId(), extStack.get(0).getId())) { + fieldsToFilter.addAll(view.getXAxis()); + } + groupStackDrill(noDrillFieldAxis, noDrillFilterList, fieldsToFilter, drillFields, drillRequestList); + formatResult.getAxisMap().put(ChartAxis.xAxis, noDrillFieldAxis); + result.setFilterList(noDrillFilterList); + } + return (T) result; + } + + @Override + public T calcChartResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, Map sqlMap, SQLMeta sqlMeta, CalciteProvider provider) { + var dsMap = (Map) sqlMap.get("dsMap"); + List dsList = new ArrayList<>(); + for (Map.Entry next : dsMap.entrySet()) { + dsList.add(next.getValue().getType()); + } + boolean needOrder = Utils.isNeedOrder(dsList); + boolean crossDs = Utils.isCrossDs(dsMap); + var result = (T) super.calcChartResult(view, formatResult, filterResult, sqlMap, sqlMeta, provider); + try { + //如果有同环比过滤,应该用原始sql + var originSql = result.getQuerySql(); + var dynamicAssistFields = getDynamicAssistFields(view); + var yAxis = formatResult.getAxisMap().get(ChartAxis.yAxis); + var assistFields = getAssistFields(dynamicAssistFields, yAxis); + if (CollectionUtils.isNotEmpty(assistFields)) { + var req = new DatasourceRequest(); + req.setDsList(dsMap); + var assistSql = assistSQL(originSql, assistFields); + req.setQuery(assistSql); + var assistData = (List) provider.fetchResultField(req).get("data"); + result.setAssistData(assistData); + result.setDynamicAssistFields(dynamicAssistFields); + } + } catch (Exception e) { + e.printStackTrace(); + } + return result; + } +} diff --git a/core/core-backend/src/main/java/io/dataease/chart/charts/impl/map/FlowMapHandler.java b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/map/FlowMapHandler.java new file mode 100644 index 0000000000..aa0963e0c4 --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/map/FlowMapHandler.java @@ -0,0 +1,11 @@ +package io.dataease.chart.charts.impl.map; + +import io.dataease.chart.charts.impl.GroupChartHandler; +import lombok.Getter; +import org.springframework.stereotype.Component; + +@Component +public class FlowMapHandler extends GroupChartHandler { + @Getter + private String type = "flow-map"; +} diff --git a/core/core-backend/src/main/java/io/dataease/chart/charts/impl/map/HeatMapHandler.java b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/map/HeatMapHandler.java new file mode 100644 index 0000000000..e210bf9254 --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/map/HeatMapHandler.java @@ -0,0 +1,28 @@ +package io.dataease.chart.charts.impl.map; + +import io.dataease.chart.charts.impl.DefaultChartHandler; +import io.dataease.chart.utils.ChartDataBuild; +import io.dataease.extensions.view.dto.*; +import lombok.Getter; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; + +@Component +public class HeatMapHandler extends DefaultChartHandler { + @Getter + private String type = "heat-map"; + + @Override + public Map buildResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, List data) { + boolean isDrill = filterResult + .getFilterList() + .stream() + .anyMatch(ele -> ele.getFilterType() == 1); + var xAxis = formatResult.getAxisMap().get(ChartAxis.xAxis); + var yAxis = formatResult.getAxisMap().get(ChartAxis.yAxis); + Map result = ChartDataBuild.transHeatMapChartDataAntV(xAxis, xAxis, yAxis, view, data, isDrill); + return result; + } +} diff --git a/core/core-backend/src/main/java/io/dataease/chart/charts/impl/map/MapHandler.java b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/map/MapHandler.java new file mode 100644 index 0000000000..02581ff07c --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/map/MapHandler.java @@ -0,0 +1,15 @@ +package io.dataease.chart.charts.impl.map; + +import io.dataease.chart.charts.impl.ExtQuotaChartHandler; +import io.dataease.extensions.view.dto.AxisFormatResult; +import io.dataease.extensions.view.dto.ChartAxis; +import io.dataease.chart.charts.impl.DefaultChartHandler; +import io.dataease.extensions.view.dto.ChartViewDTO; +import lombok.Getter; +import org.springframework.stereotype.Component; + +@Component +public class MapHandler extends ExtQuotaChartHandler { + @Getter + private String type = "map"; +} diff --git a/core/core-backend/src/main/java/io/dataease/chart/charts/impl/map/SymbolicMapHandler.java b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/map/SymbolicMapHandler.java new file mode 100644 index 0000000000..47cc138fbe --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/map/SymbolicMapHandler.java @@ -0,0 +1,22 @@ +package io.dataease.chart.charts.impl.map; + +import io.dataease.chart.charts.impl.GroupChartHandler; +import io.dataease.extensions.view.dto.AxisFormatResult; +import io.dataease.extensions.view.dto.ChartAxis; +import io.dataease.extensions.view.dto.ChartViewDTO; +import lombok.Getter; +import org.springframework.stereotype.Component; + +@Component +public class SymbolicMapHandler extends GroupChartHandler { + @Getter + private String type = "symbolic-map"; + + @Override + public AxisFormatResult formatAxis(ChartViewDTO view) { + var result = super.formatAxis(view); + var yAxis = result.getAxisMap().get(ChartAxis.yAxis); + yAxis.addAll(view.getExtBubble()); + return result; + } +} diff --git a/core/core-backend/src/main/java/io/dataease/chart/charts/impl/mix/ChartMixHandler.java b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/mix/ChartMixHandler.java new file mode 100644 index 0000000000..96963add3c --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/mix/ChartMixHandler.java @@ -0,0 +1,21 @@ +package io.dataease.chart.charts.impl.mix; + +import io.dataease.chart.charts.impl.YoyChartHandler; +import io.dataease.extensions.view.dto.AxisFormatResult; +import io.dataease.chart.charts.impl.DefaultChartHandler; +import io.dataease.extensions.view.dto.ChartViewDTO; +import lombok.Getter; +import org.springframework.stereotype.Component; + +@Component +public class ChartMixHandler extends DefaultChartHandler { + @Getter + private final String type = "chart-mix"; + + @Override + public AxisFormatResult formatAxis(ChartViewDTO view) { + var result = super.formatAxis(view); + return result; + } + +} diff --git a/core/core-backend/src/main/java/io/dataease/chart/charts/impl/numberic/GaugeHandler.java b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/numberic/GaugeHandler.java new file mode 100644 index 0000000000..71a65e7210 --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/numberic/GaugeHandler.java @@ -0,0 +1,45 @@ +package io.dataease.chart.charts.impl.numberic; + +import io.dataease.extensions.view.dto.AxisFormatResult; +import io.dataease.extensions.view.dto.ChartAxis; +import io.dataease.dataset.manage.DatasetTableFieldManage; +import io.dataease.extensions.view.dto.ChartViewDTO; +import io.dataease.extensions.view.dto.ChartViewFieldDTO; +import jakarta.annotation.Resource; +import lombok.Getter; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Component +public class GaugeHandler extends NumbericChartHandler { + @Getter + private String type = "gauge"; + @Resource + private DatasetTableFieldManage datasetTableFieldManage; + + @Override + public AxisFormatResult formatAxis(ChartViewDTO view) { + var axisMap = new HashMap>(); + var yAxis = new ArrayList<>(view.getYAxis()); + Map customAttr = view.getCustomAttr(); + Map size = (Map) customAttr.get("misc"); + ChartViewFieldDTO gaugeMinViewField = getDynamicField(size, "gaugeMinType", "gaugeMinField"); + if (gaugeMinViewField != null) { + yAxis.add(gaugeMinViewField); + } + ChartViewFieldDTO gaugeMaxViewField = getDynamicField(size, "gaugeMaxType", "gaugeMaxField"); + if (gaugeMaxViewField != null) { + yAxis.add(gaugeMaxViewField); + } + axisMap.put(ChartAxis.xAxis, new ArrayList<>()); + axisMap.put(ChartAxis.yAxis, yAxis); + var context = new HashMap(); + var result = new AxisFormatResult(axisMap, context); + return result; + } + +} diff --git a/core/core-backend/src/main/java/io/dataease/chart/charts/impl/numberic/IndicatorHandler.java b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/numberic/IndicatorHandler.java new file mode 100644 index 0000000000..2e1de08453 --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/numberic/IndicatorHandler.java @@ -0,0 +1,13 @@ +package io.dataease.chart.charts.impl.numberic; + +import io.dataease.chart.charts.impl.DefaultChartHandler; +import lombok.Getter; +import org.springframework.stereotype.Component; + +@Component +public class IndicatorHandler extends NumbericChartHandler { + @Getter + private String render = "custom"; + @Getter + private String type = "indicator"; +} diff --git a/core/core-backend/src/main/java/io/dataease/chart/charts/impl/numberic/LiquidHandler.java b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/numberic/LiquidHandler.java new file mode 100644 index 0000000000..8d4d2d36c0 --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/numberic/LiquidHandler.java @@ -0,0 +1,36 @@ +package io.dataease.chart.charts.impl.numberic; + +import io.dataease.extensions.view.dto.AxisFormatResult; +import io.dataease.extensions.view.dto.ChartAxis; +import io.dataease.extensions.view.dto.ChartViewDTO; +import io.dataease.extensions.view.dto.ChartViewFieldDTO; +import lombok.Getter; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Component +public class LiquidHandler extends NumbericChartHandler { + @Getter + private String type = "liquid"; + + @Override + public AxisFormatResult formatAxis(ChartViewDTO view) { + var axisMap = new HashMap>(); + var yAxis = new ArrayList<>(view.getYAxis()); + Map customAttr = view.getCustomAttr(); + Map misc = (Map) customAttr.get("misc"); + ChartViewFieldDTO liquidMaxViewField = getDynamicField(misc, "liquidMaxType", "liquidMaxField"); + if (liquidMaxViewField != null) { + yAxis.add(liquidMaxViewField); + } + axisMap.put(ChartAxis.xAxis, new ArrayList<>()); + axisMap.put(ChartAxis.yAxis, yAxis); + var context = new HashMap(); + var result = new AxisFormatResult(axisMap, context); + return result; + } +} diff --git a/core/core-backend/src/main/java/io/dataease/chart/charts/impl/numberic/NumbericChartHandler.java b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/numberic/NumbericChartHandler.java new file mode 100644 index 0000000000..9f3ebb1391 --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/numberic/NumbericChartHandler.java @@ -0,0 +1,82 @@ +package io.dataease.chart.charts.impl.numberic; + +import io.dataease.chart.charts.impl.DefaultChartHandler; +import io.dataease.chart.utils.ChartDataBuild; +import io.dataease.dataset.dto.DatasourceSchemaDTO; +import io.dataease.dataset.utils.SqlUtils; +import io.dataease.datasource.provider.CalciteProvider; +import io.dataease.datasource.request.DatasourceRequest; +import io.dataease.engine.sql.SQLProvider; +import io.dataease.engine.trans.Quota2SQLObj; +import io.dataease.engine.utils.Utils; +import io.dataease.exception.DEException; +import io.dataease.extensions.view.dto.*; +import io.dataease.extensions.view.model.SQLMeta; +import io.dataease.extensions.view.util.FieldUtil; +import io.dataease.i18n.Translator; +import io.dataease.utils.BeanUtils; +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class NumbericChartHandler extends DefaultChartHandler { + @Override + public T calcChartResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, Map sqlMap, SQLMeta sqlMeta, CalciteProvider provider) { + var dsMap = (Map) sqlMap.get("dsMap"); + List dsList = new ArrayList<>(); + for (Map.Entry next : dsMap.entrySet()) { + dsList.add(next.getValue().getType()); + } + boolean needOrder = Utils.isNeedOrder(dsList); + boolean crossDs = Utils.isCrossDs(dsMap); + DatasourceRequest datasourceRequest = new DatasourceRequest(); + datasourceRequest.setDsList(dsMap); + var xAxis = formatResult.getAxisMap().get(ChartAxis.xAxis); + var yAxis = formatResult.getAxisMap().get(ChartAxis.yAxis); + var allFields = getAllChartFields(view); + Quota2SQLObj.quota2sqlObj(sqlMeta, yAxis, FieldUtil.transFields(allFields), crossDs, dsMap); + String querySql = SQLProvider.createQuerySQL(sqlMeta, true, needOrder, view); + querySql = SqlUtils.rebuildSQL(querySql, sqlMeta, crossDs, dsMap); + datasourceRequest.setQuery(querySql); + List data = (List) provider.fetchResultField(datasourceRequest).get("data"); + boolean isdrill = filterResult + .getFilterList() + .stream() + .anyMatch(ele -> ele.getFilterType() == 1); + Map result = ChartDataBuild.transNormalChartData(xAxis, yAxis, view, data, isdrill); + T calcResult = (T) new ChartCalcDataResult(); + calcResult.setData(result); + calcResult.setContext(filterResult.getContext()); + calcResult.setQuerySql(querySql); + calcResult.setOriginData(data); + return calcResult; + } + + protected ChartViewFieldDTO getDynamicField(Map target, String type, String field) { + String maxType = (String) target.get(type); + if (StringUtils.equalsIgnoreCase("dynamic", maxType)) { + Map maxField = (Map) target.get(field); + Long id = Long.valueOf((String) maxField.get("id")); + String summary = (String) maxField.get("summary"); + DatasetTableFieldDTO datasetTableField = datasetTableFieldManage.selectById(id); + if (ObjectUtils.isNotEmpty(datasetTableField)) { + if (datasetTableField.getDeType() == 0 || datasetTableField.getDeType() == 1 || datasetTableField.getDeType() == 5) { + if (!StringUtils.containsIgnoreCase(summary, "count")) { + DEException.throwException(Translator.get("i18n_gauge_field_change")); + } + } + ChartViewFieldDTO dto = new ChartViewFieldDTO(); + BeanUtils.copyBean(dto, datasetTableField); + dto.setSummary(summary); + return dto; + } else { + DEException.throwException(Translator.get("i18n_gauge_field_delete")); + } + } + return null; + } +} diff --git a/core/core-backend/src/main/java/io/dataease/chart/charts/impl/others/FunnelHandler.java b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/others/FunnelHandler.java new file mode 100644 index 0000000000..b5f6434b4f --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/others/FunnelHandler.java @@ -0,0 +1,11 @@ +package io.dataease.chart.charts.impl.others; + +import io.dataease.chart.charts.impl.ExtQuotaChartHandler; +import lombok.Getter; +import org.springframework.stereotype.Component; + +@Component +public class FunnelHandler extends ExtQuotaChartHandler { + @Getter + private String type = "funnel"; +} diff --git a/core/core-backend/src/main/java/io/dataease/chart/charts/impl/others/RadarHandler.java b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/others/RadarHandler.java new file mode 100644 index 0000000000..c84f12da12 --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/others/RadarHandler.java @@ -0,0 +1,26 @@ +package io.dataease.chart.charts.impl.others; + +import io.dataease.chart.charts.impl.DefaultChartHandler; +import io.dataease.chart.charts.impl.YoyChartHandler; +import io.dataease.extensions.view.dto.AxisFormatResult; +import io.dataease.extensions.view.dto.ChartAxis; +import io.dataease.extensions.view.dto.ChartViewDTO; +import lombok.Getter; +import org.springframework.stereotype.Component; + +@Component +public class RadarHandler extends YoyChartHandler { + @Getter + private String type = "radar"; + + @Override + public AxisFormatResult formatAxis(ChartViewDTO view) { + var result = super.formatAxis(view); + var yAxis = result.getAxisMap().get(ChartAxis.yAxis); + yAxis.addAll(view.getExtLabel()); + yAxis.addAll(view.getExtTooltip()); + result.getAxisMap().put(ChartAxis.extLabel, view.getExtLabel()); + result.getAxisMap().put(ChartAxis.extTooltip, view.getExtTooltip()); + return result; + } +} diff --git a/core/core-backend/src/main/java/io/dataease/chart/charts/impl/others/SankeyHandler.java b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/others/SankeyHandler.java new file mode 100644 index 0000000000..788644caed --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/others/SankeyHandler.java @@ -0,0 +1,11 @@ +package io.dataease.chart.charts.impl.others; + +import io.dataease.chart.charts.impl.GroupChartHandler; +import lombok.Getter; +import org.springframework.stereotype.Component; + +@Component +public class SankeyHandler extends GroupChartHandler { + @Getter + private String type = "sankey"; +} diff --git a/core/core-backend/src/main/java/io/dataease/chart/charts/impl/others/WaterfallHandler.java b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/others/WaterfallHandler.java new file mode 100644 index 0000000000..76a0ae2aae --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/others/WaterfallHandler.java @@ -0,0 +1,11 @@ +package io.dataease.chart.charts.impl.others; + +import io.dataease.chart.charts.impl.ExtQuotaChartHandler; +import lombok.Getter; +import org.springframework.stereotype.Component; + +@Component +public class WaterfallHandler extends ExtQuotaChartHandler { + @Getter + private String type = "waterfall"; +} diff --git a/core/core-backend/src/main/java/io/dataease/chart/charts/impl/others/WordCloudHandler.java b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/others/WordCloudHandler.java new file mode 100644 index 0000000000..599509181c --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/others/WordCloudHandler.java @@ -0,0 +1,15 @@ +package io.dataease.chart.charts.impl.others; + +import io.dataease.chart.charts.impl.DefaultChartHandler; +import io.dataease.chart.charts.impl.ExtQuotaChartHandler; +import io.dataease.extensions.view.dto.AxisFormatResult; +import io.dataease.extensions.view.dto.ChartAxis; +import io.dataease.extensions.view.dto.ChartViewDTO; +import lombok.Getter; +import org.springframework.stereotype.Component; + +@Component +public class WordCloudHandler extends ExtQuotaChartHandler { + @Getter + private String type = "word-cloud"; +} diff --git a/core/core-backend/src/main/java/io/dataease/chart/charts/impl/pie/PieHandler.java b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/pie/PieHandler.java new file mode 100644 index 0000000000..b72db58f6b --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/pie/PieHandler.java @@ -0,0 +1,31 @@ +package io.dataease.chart.charts.impl.pie; + +import io.dataease.chart.charts.impl.DefaultChartHandler; +import io.dataease.chart.charts.impl.ExtQuotaChartHandler; +import io.dataease.chart.charts.impl.YoyChartHandler; +import io.dataease.extensions.view.dto.AxisFormatResult; +import io.dataease.extensions.view.dto.ChartAxis; +import io.dataease.extensions.view.dto.ChartViewDTO; +import org.springframework.stereotype.Component; + +@Component +public class PieHandler extends YoyChartHandler { + @Override + public void init() { + chartHandlerManager.registerChartHandler(this.getRender(), "pie", this); + chartHandlerManager.registerChartHandler(this.getRender(), "pie-rose", this); + chartHandlerManager.registerChartHandler(this.getRender(), "pie-donut", this); + chartHandlerManager.registerChartHandler(this.getRender(), "pie-rose-donut", this); + } + + @Override + public AxisFormatResult formatAxis(ChartViewDTO view) { + var result = super.formatAxis(view); + var yAxis = result.getAxisMap().get(ChartAxis.yAxis); + yAxis.addAll(view.getExtLabel()); + yAxis.addAll(view.getExtTooltip()); + result.getAxisMap().put(ChartAxis.extLabel, view.getExtLabel()); + result.getAxisMap().put(ChartAxis.extTooltip, view.getExtTooltip()); + return result; + } +} diff --git a/core/core-backend/src/main/java/io/dataease/chart/charts/impl/scatter/QuadrantHandler.java b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/scatter/QuadrantHandler.java new file mode 100644 index 0000000000..8017af4b0e --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/scatter/QuadrantHandler.java @@ -0,0 +1,40 @@ +package io.dataease.chart.charts.impl.scatter; + +import io.dataease.chart.charts.impl.YoyChartHandler; +import io.dataease.chart.utils.ChartDataBuild; +import io.dataease.extensions.view.dto.*; +import lombok.Getter; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +@Component +public class QuadrantHandler extends YoyChartHandler { + @Getter + private String type = "quadrant"; + + @Override + public AxisFormatResult formatAxis(ChartViewDTO view) { + var result = super.formatAxis(view); + var yAxis = new ArrayList<>(view.getYAxis()); + yAxis.addAll(view.getYAxisExt()); + yAxis.addAll(view.getExtBubble()); + yAxis.addAll(view.getExtTooltip()); + result.getAxisMap().put(ChartAxis.yAxis, yAxis); + result.getAxisMap().put(ChartAxis.extBubble, view.getExtBubble()); + result.getAxisMap().put(ChartAxis.extTooltip, view.getExtTooltip()); + result.getAxisMap().put(ChartAxis.yAxisExt, view.getYAxisExt()); + return result; + } + + @Override + public Map buildNormalResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, List data) { + boolean isDrill = filterResult.getFilterList().stream().anyMatch(ele -> ele.getFilterType() == 1); + var xAxis = formatResult.getAxisMap().get(ChartAxis.xAxis); + var yAxis = formatResult.getAxisMap().get(ChartAxis.yAxis); + Map result = ChartDataBuild.transMixChartDataAntV(xAxis, xAxis, new ArrayList<>(), yAxis, view, data, isDrill); + return result; + } +} diff --git a/core/core-backend/src/main/java/io/dataease/chart/charts/impl/scatter/ScatterHandler.java b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/scatter/ScatterHandler.java new file mode 100644 index 0000000000..7ce7b0f7ad --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/scatter/ScatterHandler.java @@ -0,0 +1,41 @@ +package io.dataease.chart.charts.impl.scatter; + +import io.dataease.chart.charts.impl.YoyChartHandler; +import io.dataease.chart.utils.ChartDataBuild; +import io.dataease.extensions.view.dto.*; +import lombok.Getter; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +@Component +public class ScatterHandler extends YoyChartHandler { + @Getter + private String type = "scatter"; + + @Override + public AxisFormatResult formatAxis(ChartViewDTO view) { + var result = super.formatAxis(view); + var yAxis = new ArrayList<>(view.getYAxis()); + yAxis.addAll(view.getExtBubble()); + yAxis.addAll(view.getExtLabel()); + yAxis.addAll(view.getExtTooltip()); + result.getAxisMap().put(ChartAxis.yAxis, yAxis); + result.getAxisMap().put(ChartAxis.extBubble, view.getExtBubble()); + result.getAxisMap().put(ChartAxis.extTooltip, view.getExtTooltip()); + result.getAxisMap().put(ChartAxis.extLabel, view.getExtLabel()); + return result; + } + + @Override + public Map buildNormalResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, List data) { + boolean isDrill = filterResult.getFilterList().stream().anyMatch(ele -> ele.getFilterType() == 1); + var xAxis = formatResult.getAxisMap().get(ChartAxis.xAxis); + var yAxis = formatResult.getAxisMap().get(ChartAxis.yAxis); + var extBubble = formatResult.getAxisMap().get(ChartAxis.extBubble); + Map result = ChartDataBuild.transScatterDataAntV(xAxis, yAxis, view, data, extBubble, isDrill); + return result; + } +} diff --git a/core/core-backend/src/main/java/io/dataease/chart/charts/impl/table/TableInfoHandler.java b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/table/TableInfoHandler.java new file mode 100644 index 0000000000..6cb1677cd4 --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/table/TableInfoHandler.java @@ -0,0 +1,125 @@ +package io.dataease.chart.charts.impl.table; + +import io.dataease.api.chart.dto.PageInfo; +import io.dataease.chart.charts.impl.DefaultChartHandler; +import io.dataease.dataset.dto.DatasourceSchemaDTO; +import io.dataease.dataset.utils.SqlUtils; +import io.dataease.datasource.provider.CalciteProvider; +import io.dataease.datasource.request.DatasourceRequest; +import io.dataease.engine.sql.SQLProvider; +import io.dataease.engine.trans.Dimension2SQLObj; +import io.dataease.engine.trans.Quota2SQLObj; +import io.dataease.engine.utils.Utils; +import io.dataease.extensions.view.dto.*; +import io.dataease.extensions.view.model.SQLMeta; +import io.dataease.extensions.view.util.ChartDataUtil; +import io.dataease.extensions.view.util.FieldUtil; +import lombok.Getter; +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +@Component +public class TableInfoHandler extends DefaultChartHandler { + @Getter + private String type = "table-info"; + + @Override + public AxisFormatResult formatAxis(ChartViewDTO view) { + var result = super.formatAxis(view); + result.getAxisMap().put(ChartAxis.yAxis, new ArrayList<>()); + return result; + } + + @Override + public T customFilter(ChartViewDTO view, List filterList, K formatResult) { + var chartExtRequest = view.getChartExtRequest(); + Map mapAttr = view.getCustomAttr(); + Map mapSize = (Map) mapAttr.get("basicStyle"); + var tablePageMode = (String) mapSize.get("tablePageMode"); + formatResult.getContext().put("tablePageMode", tablePageMode); + if (StringUtils.equalsIgnoreCase(tablePageMode, "page") && !view.getIsExcelExport()) { + if (chartExtRequest.getGoPage() == null) { + chartExtRequest.setGoPage(1L); + } + if (chartExtRequest.getPageSize() == null) { + int pageSize = (int) mapSize.get("tablePageSize"); + if (StringUtils.equalsIgnoreCase(view.getResultMode(), "custom")) { + chartExtRequest.setPageSize(Math.min(pageSize, view.getResultCount().longValue())); + } else { + chartExtRequest.setPageSize((long) pageSize); + } + } + } else { + if (StringUtils.equalsIgnoreCase(view.getResultMode(), "custom")) { + chartExtRequest.setGoPage(1L); + chartExtRequest.setPageSize(view.getResultCount().longValue()); + } else if (!view.getIsExcelExport()) { + chartExtRequest.setGoPage(null); + chartExtRequest.setPageSize(null); + } + } + return super.customFilter(view, filterList, formatResult); + } + + @Override + public T calcChartResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, Map sqlMap, SQLMeta sqlMeta, CalciteProvider provider) { + var chartExtRequest = view.getChartExtRequest(); + var dsMap = (Map) sqlMap.get("dsMap"); + List dsList = new ArrayList<>(); + for (Map.Entry next : dsMap.entrySet()) { + dsList.add(next.getValue().getType()); + } + boolean needOrder = Utils.isNeedOrder(dsList); + boolean crossDs = Utils.isCrossDs(dsMap); + DatasourceRequest datasourceRequest = new DatasourceRequest(); + datasourceRequest.setDsList(dsMap); + var xAxis = formatResult.getAxisMap().get(ChartAxis.xAxis); + var allFields = getAllChartFields(view); + PageInfo pageInfo = new PageInfo(); + pageInfo.setGoPage(chartExtRequest.getGoPage()); + if (StringUtils.equalsIgnoreCase(view.getResultMode(), "custom")) { + pageInfo.setPageSize(Math.min(view.getResultCount() - (chartExtRequest.getGoPage() - 1) * chartExtRequest.getPageSize(), chartExtRequest.getPageSize())); + } else { + pageInfo.setPageSize(chartExtRequest.getPageSize()); + } + Dimension2SQLObj.dimension2sqlObj(sqlMeta, xAxis, FieldUtil.transFields(allFields), crossDs, dsMap); + String originSql = SQLProvider.createQuerySQL(sqlMeta, false, true, view);// 明细表强制加排序 + String limit = ((pageInfo.getGoPage() != null && pageInfo.getPageSize() != null) ? " LIMIT " + pageInfo.getPageSize() + " OFFSET " + (pageInfo.getGoPage() - 1) * pageInfo.getPageSize() : ""); + var querySql = originSql + limit; + + var tablePageMode = (String) filterResult.getContext().get("tablePageMode"); + var totalPageSql = "SELECT COUNT(*) FROM (" + SQLProvider.createQuerySQL(sqlMeta, false, false, view) + ") COUNT_TEMP"; + if (StringUtils.isNotEmpty(totalPageSql) && StringUtils.equalsIgnoreCase(tablePageMode, "page")) { + totalPageSql = SqlUtils.rebuildSQL(totalPageSql, sqlMeta, crossDs, dsMap); + datasourceRequest.setQuery(totalPageSql); + datasourceRequest.setTotalPageFlag(true); + List tmpData = (List) provider.fetchResultField(datasourceRequest).get("data"); + var totalItems = ObjectUtils.isEmpty(tmpData) ? 0 : Long.valueOf(tmpData.get(0)[0]); + if (StringUtils.equalsIgnoreCase(view.getResultMode(), "custom")) { + totalItems = totalItems <= view.getResultCount() ? totalItems : view.getResultCount(); + } + var totalPage = (totalItems / pageInfo.getPageSize()) + (totalItems % pageInfo.getPageSize() > 0 ? 1 : 0); + view.setTotalItems(totalItems); + view.setTotalPage(totalPage); + } + + querySql = SqlUtils.rebuildSQL(querySql, sqlMeta, crossDs, dsMap); + datasourceRequest.setQuery(querySql); + List data = (List) provider.fetchResultField(datasourceRequest).get("data"); + //自定义排序 + data = ChartDataUtil.resultCustomSort(xAxis, data); + //数据重组逻辑可重载 + var result = this.buildResult(view, formatResult, filterResult, data); + T calcResult = (T) new ChartCalcDataResult(); + calcResult.setData(result); + calcResult.setContext(filterResult.getContext()); + calcResult.setQuerySql(querySql); + calcResult.setOriginData(data); + return calcResult; + } +} diff --git a/core/core-backend/src/main/java/io/dataease/chart/charts/impl/table/TablePivotHandler.java b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/table/TablePivotHandler.java new file mode 100644 index 0000000000..2980fda8f5 --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/chart/charts/impl/table/TablePivotHandler.java @@ -0,0 +1,11 @@ +package io.dataease.chart.charts.impl.table; + +import io.dataease.chart.charts.impl.GroupChartHandler; +import lombok.Getter; +import org.springframework.stereotype.Component; + +@Component +public class TablePivotHandler extends GroupChartHandler { + @Getter + private String type = "table-pivot"; +} diff --git a/core/core-backend/src/main/java/io/dataease/chart/manage/ChartDataManage.java b/core/core-backend/src/main/java/io/dataease/chart/manage/ChartDataManage.java index 44318e010c..73a0a49dc6 100644 --- a/core/core-backend/src/main/java/io/dataease/chart/manage/ChartDataManage.java +++ b/core/core-backend/src/main/java/io/dataease/chart/manage/ChartDataManage.java @@ -6,6 +6,8 @@ import io.dataease.api.chart.dto.PageInfo; import io.dataease.api.dataset.union.DatasetGroupInfoDTO; import io.dataease.api.permissions.auth.dto.BusiPerCheckDTO; import io.dataease.api.permissions.dataset.dto.DataSetRowPermissionsTreeDTO; +import io.dataease.chart.charts.AbstractChartHandler; +import io.dataease.chart.charts.ChartHandlerManager; import io.dataease.chart.constant.ChartConstants; import io.dataease.chart.utils.ChartDataBuild; import io.dataease.constant.AuthEnum; @@ -51,6 +53,8 @@ import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; +import static io.dataease.extensions.view.dto.ChartAxis.*; + /** * @Author Junjun */ @@ -70,6 +74,8 @@ public class ChartDataManage { private PermissionManage permissionManage; @Resource private ChartFilterTreeService chartFilterTreeService; + @Resource + private ChartHandlerManager chartHandlerManager; @Resource private CorePermissionManage corePermissionManage; @@ -115,6 +121,9 @@ public class ChartDataManage { List allFields = getAllChartFields(view); ChartViewDTO chartViewDTO = null; + if (ObjectUtils.isNotEmpty(view.getIsPlugin()) && view.getIsPlugin()) { + return calcData1(view, chartExtRequest, allFields, viewFields); + } if (StringUtils.containsIgnoreCase(view.getType(), "chart-mix")) { // 需要排除掉除类别轴以外所有的排序 view.getXAxisExt().forEach(dto -> dto.setSort("none")); @@ -145,7 +154,7 @@ public class ChartDataManage { view1.getSenior().put("assistLineCfg", assistLineCfg1); } } - ChartViewDTO left = calcData(view1, chartExtRequest, allFields, viewFields); + ChartViewDTO left = calcData1(view1, chartExtRequest, allFields, viewFields); data.put("left", left.getData()); //针对右轴,删除yAxis ChartViewDTO view2 = JsonUtil.parseObject(viewJson, ChartViewDTO.class); @@ -162,7 +171,7 @@ public class ChartDataManage { view2.setXAxisExt(view2.getExtBubble()); view2.setExtStack(new ArrayList<>()); view2.setExtBubble(new ArrayList<>()); - ChartViewDTO right = calcData(view2, chartExtRequest, allFields, viewFields); + ChartViewDTO right = calcData1(view2, chartExtRequest, allFields, viewFields); data.put("right", right.getData()); //重新组装 @@ -181,6 +190,273 @@ public class ChartDataManage { } public ChartViewDTO calcData(ChartViewDTO view, ChartExtRequest chartExtRequest, List allFields, List viewFields) throws Exception { + AbstractChartHandler chartHandler = chartHandlerManager.getChartHandler(view.getRender(), view.getType()); + AxisFormatResult formatResult = chartHandler.formatAxis(view); + var xAxis = formatResult.getAxisMap().get(ChartAxis.xAxis); + var yAxis = formatResult.getAxisMap().get(ChartAxis.yAxis); + + DatasetGroupInfoDTO table = datasetGroupManage.getDatasetGroupInfoDTO(view.getTableId(), null); + if (table == null) { + DEException.throwException(ResultCode.DATA_IS_WRONG.code(), Translator.get("i18n_no_ds")); + } + // check permission + BusiPerCheckDTO dto = new BusiPerCheckDTO(); + dto.setId(table.getId()); + dto.setAuthEnum(AuthEnum.READ); + boolean checked = corePermissionManage.checkAuth(dto); + if (!checked) { + DEException.throwException(Translator.get("i18n_no_datasource_permission")); + } + + // column permission + Map desensitizationList = new HashMap<>(); + List columnPermissionFields = permissionManage.filterColumnPermissions(transFields(allFields), desensitizationList, table.getId(), chartExtRequest.getUser()); + // row permission + List rowPermissionsTree = permissionManage.getRowPermissionsTree(table.getId(), chartExtRequest.getUser()); + //将没有权限的列删掉 + List dataeaseNames = columnPermissionFields.stream().map(DatasetTableFieldDTO::getDataeaseName).collect(Collectors.toList()); + dataeaseNames.add("*"); + var axisMap = formatResult.getAxisMap(); + axisMap.forEach((axis, fields) -> { + Iterator iterator = fields.iterator(); + while (iterator.hasNext()) { + ChartViewFieldDTO fieldDTO = iterator.next(); + if (desensitizationList.containsKey(fieldDTO.getDataeaseName()) || !dataeaseNames.contains(fieldDTO.getDataeaseName())) { + iterator.remove(); + } + } + }); + + if (ObjectUtils.isEmpty(xAxis) && ObjectUtils.isEmpty(yAxis)) { + return emptyChartViewDTO(view); + } + + // 过滤来自仪表板的条件 + List extFilterList = new ArrayList<>(); + //组件过滤条件 + if (ObjectUtils.isNotEmpty(chartExtRequest.getFilter())) { + for (ChartExtFilterDTO request : chartExtRequest.getFilter()) { + // 解析多个fieldId,fieldId是一个逗号分隔的字符串 + String fieldId = request.getFieldId(); + if (request.getIsTree() == null) { + request.setIsTree(false); + } + + boolean hasParameters = false; + List sqlVariables = datasetGroupManage.getSqlParams(Arrays.asList(view.getTableId())); + if (CollectionUtils.isNotEmpty(sqlVariables)) { + for (SqlVariableDetails parameter : Optional.ofNullable(request.getParameters()).orElse(new ArrayList<>())) { + String parameterId = StringUtils.endsWith(parameter.getId(), START_END_SEPARATOR) ? parameter.getId().split(START_END_SEPARATOR)[0] : parameter.getId(); + if (sqlVariables.stream().map(SqlVariableDetails::getId).collect(Collectors.toList()).contains(parameterId)) { + hasParameters = true; + } + } + } + + if (hasParameters) { + continue; + } + + if (StringUtils.isNotEmpty(fieldId)) { + List fieldIds = Arrays.stream(fieldId.split(",")).map(Long::valueOf).collect(Collectors.toList()); + + if (request.getIsTree()) { + ChartExtFilterDTO filterRequest = new ChartExtFilterDTO(); + BeanUtils.copyBean(filterRequest, request); + filterRequest.setFilterType(0); + filterRequest.setDatasetTableFieldList(new ArrayList<>()); + for (Long fId : fieldIds) { + DatasetTableFieldDTO datasetTableField = datasetTableFieldManage.selectById(fId); + if (datasetTableField == null) { + continue; + } + if (Objects.equals(datasetTableField.getDatasetTableId(), view.getTableId())) { + if (ObjectUtils.isNotEmpty(filterRequest.getViewIds())) { + if (filterRequest.getViewIds().contains(view.getId())) { + filterRequest.getDatasetTableFieldList().add(datasetTableField); + } + } else { + filterRequest.getDatasetTableFieldList().add(datasetTableField); + } + } + } + if (ObjectUtils.isNotEmpty(filterRequest.getDatasetTableFieldList())) { + extFilterList.add(filterRequest); + } + } else { + for (Long fId : fieldIds) { + ChartExtFilterDTO filterRequest = new ChartExtFilterDTO(); + BeanUtils.copyBean(filterRequest, request); + filterRequest.setFilterType(0); + filterRequest.setFieldId(fId + ""); + + DatasetTableFieldDTO datasetTableField = datasetTableFieldManage.selectById(fId); + if (datasetTableField == null) { + continue; + } + filterRequest.setDatasetTableField(datasetTableField); + if (Objects.equals(datasetTableField.getDatasetGroupId(), view.getTableId())) { + if (ObjectUtils.isNotEmpty(filterRequest.getViewIds())) { + if (filterRequest.getViewIds().contains(view.getId())) { + extFilterList.add(filterRequest); + } + } else { + extFilterList.add(filterRequest); + } + } + } + } + } + } + } + + List filters = new ArrayList<>(); + // 联动条件 + if (ObjectUtils.isNotEmpty(chartExtRequest.getLinkageFilters())) { + filters.addAll(chartExtRequest.getLinkageFilters()); + } + + // 外部参数条件 + if (ObjectUtils.isNotEmpty(chartExtRequest.getOuterParamsFilters())) { + filters.addAll(chartExtRequest.getOuterParamsFilters()); + } + + //联动过滤条件和外部参数过滤条件全部加上 + if (ObjectUtils.isNotEmpty(filters)) { + for (ChartExtFilterDTO request : filters) { + DatasetTableFieldDTO datasetTableField = datasetTableFieldManage.selectById(Long.valueOf(request.getFieldId())); + request.setDatasetTableField(datasetTableField); + request.setFilterType(2); + // 相同数据集 + if (Objects.equals(datasetTableField.getDatasetGroupId(), view.getTableId())) { + if (ObjectUtils.isNotEmpty(request.getViewIds())) { + if (request.getViewIds().contains(view.getId())) { + extFilterList.add(request); + } + } else { + extFilterList.add(request); + } + } + } + } + + // 下钻 + List drillRequestList = chartExtRequest.getDrill(); + var drill = formatResult.getAxisMap().get(ChartAxis.drill); + if (ObjectUtils.isNotEmpty(drillRequestList) && (drill.size() > drillRequestList.size())) { + var fields = xAxis.stream().map(ChartViewFieldDTO::getId).collect(Collectors.toSet()); + for (int i = 0; i < drillRequestList.size(); i++) { + ChartDrillRequest request = drillRequestList.get(i); + for (ChartDimensionDTO dim : request.getDimensionList()) { + ChartViewFieldDTO viewField = drill.get(i); + // 将钻取值作为条件传递,将所有钻取字段作为xAxis并加上下一个钻取字段 + if (Objects.equals(dim.getId(), viewField.getId())) { + DatasetTableFieldDTO datasetTableField = datasetTableFieldManage.selectById(dim.getId()); + ChartViewFieldDTO d = new ChartViewFieldDTO(); + BeanUtils.copyBean(d, datasetTableField); + + ChartExtFilterDTO drillFilter = new ChartExtFilterDTO(); + drillFilter.setFieldId(String.valueOf(dim.getId())); + drillFilter.setDatasetTableField(datasetTableField); + drillFilter.setDatePattern(viewField.getDatePattern()); + drillFilter.setDateStyle(viewField.getDateStyle()); + drillFilter.setFilterType(1); + if (datasetTableField.getDeType() == 1) { + drillFilter.setOperator("between"); + // 把value类似过滤组件处理,获得start time和end time + Map stringLongMap = Utils.parseDateTimeValue(dim.getValue()); + drillFilter.setValue(Arrays.asList(String.valueOf(stringLongMap.get("startTime")), String.valueOf(stringLongMap.get("endTime")))); + } else { + drillFilter.setOperator("in"); + drillFilter.setValue(Collections.singletonList(dim.getValue())); + } + extFilterList.add(drillFilter); + + if (!fields.contains(dim.getId())) { + viewField.setSource(FieldSource.DRILL); + xAxis.add(viewField); + fields.add(dim.getId()); + } + if (i == drillRequestList.size() - 1) { + ChartViewFieldDTO nextDrillField = drill.get(i + 1); + if (!fields.contains(nextDrillField.getId())) { + viewField.setSource(FieldSource.DRILL); + nextDrillField.setSort(getDrillSort(xAxis, drill.get(0))); + xAxis.add(nextDrillField); + fields.add(nextDrillField.getId()); + } + } + } + } + } + } + //转义特殊字符 + extFilterList = extFilterList.stream().peek(ele -> { + if (ObjectUtils.isNotEmpty(ele.getValue())) { + List collect = ele.getValue().stream().map(SQLUtils::transKeyword).collect(Collectors.toList()); + ele.setValue(collect); + } + }).collect(Collectors.toList()); + // 视图自定义过滤逻辑 + CustomFilterResult filterResult = chartHandler.customFilter(view, extFilterList, formatResult); + // 字段过滤器 + FilterTreeObj fieldCustomFilter = view.getCustomFilter(); + chartFilterTreeService.searchFieldAndSet(fieldCustomFilter); + fieldCustomFilter = chartFilterTreeService.charReplace(fieldCustomFilter); + // 获取dsMap,union sql + Map sqlMap = datasetSQLManage.getUnionSQLForEdit(table, chartExtRequest); + String sql = (String) sqlMap.get("sql"); + Map dsMap = (Map) sqlMap.get("dsMap"); + List dsList = new ArrayList<>(); + for (Map.Entry next : dsMap.entrySet()) { + dsList.add(next.getValue().getType()); + } + boolean needOrder = Utils.isNeedOrder(dsList); + boolean crossDs = Utils.isCrossDs(dsMap); + if (!crossDs) { + sql = Utils.replaceSchemaAlias(sql, dsMap); + } + + List detailFieldList = new ArrayList<>(); + String detailFieldSql = null; + List detailData = new ArrayList<>(); + if (ObjectUtils.isEmpty(dsMap)) { + DEException.throwException(ResultCode.DATA_IS_WRONG.code(), Translator.get("i18n_datasource_delete")); + } + for (Map.Entry next : dsMap.entrySet()) { + DatasourceSchemaDTO ds = next.getValue(); + if (StringUtils.isNotEmpty(ds.getStatus()) && "Error".equalsIgnoreCase(ds.getStatus())) { + DEException.throwException(ResultCode.DATA_IS_WRONG.code(), Translator.get("i18n_invalid_ds")); + } + } + + SQLMeta sqlMeta = new SQLMeta(); + Table2SQLObj.table2sqlobj(sqlMeta, null, "(" + sql + ")", crossDs); + CustomWhere2Str.customWhere2sqlObj(sqlMeta, fieldCustomFilter, transFields(allFields), crossDs, dsMap); + ExtWhere2Str.extWhere2sqlOjb(sqlMeta, extFilterList, transFields(allFields), crossDs, dsMap); + WhereTree2Str.transFilterTrees(sqlMeta, rowPermissionsTree, transFields(allFields), crossDs, dsMap); + Map dsTypeMap = dsMap.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().getType())); + ChartCalcDataResult calcResult = chartHandler.calcChartResult(view, formatResult, filterResult, sqlMap, sqlMeta, calciteProvider); + // 如果是表格导出查询 则在此处直接就可以返回 + var extStack = formatResult.getAxisMap().get(ChartAxis.extStack); + if (view.getIsExcelExport()) { + Map sourceInfo = ChartDataBuild.transTableNormal(xAxis, yAxis, view, calcResult.getOriginData(), extStack, desensitizationList); + sourceInfo.put("sourceData", calcResult.getOriginData()); + view.setData(sourceInfo); + return view; + } + + // 构建结果 + Map map = new TreeMap<>(); + // 图表组件可再扩展 + Map mapTableNormal = ChartDataBuild.transTableNormal(xAxis, yAxis, view, calcResult.getOriginData(), extStack, desensitizationList); + var drillFilters = filterResult.getFilterList().stream().filter(f -> f.getFilterType() == 1).collect(Collectors.toList()); + var isDrill = CollectionUtils.isNotEmpty(drillFilters); + ChartViewDTO chartViewDTO = uniteViewResult(calcResult.getQuerySql(), calcResult.getData(), mapTableNormal, view, isDrill, drillFilters, calcResult.getDynamicAssistFields(), calcResult.getAssistData()); + return chartViewDTO; + } + + public ChartViewDTO calcData1(ChartViewDTO view, ChartExtRequest chartExtRequest, List allFields, List viewFields) throws Exception { List xAxisBase = null; List xAxis = null; List xAxisExt = null; @@ -413,7 +689,7 @@ public class ChartDataManage { if (datasetTableField == null) { continue; } - if (Objects.equals(datasetTableField.getDatasetTableId(), view.getTableId())) { + if (Objects.equals(datasetTableField.getDatasetGroupId(), view.getTableId())) { if (ObjectUtils.isNotEmpty(filterRequest.getViewIds())) { if (filterRequest.getViewIds().contains(view.getId())) { filterRequest.getDatasetTableFieldList().add(datasetTableField); diff --git a/core/core-backend/src/main/java/io/dataease/chart/utils/ChartDataBuild.java b/core/core-backend/src/main/java/io/dataease/chart/utils/ChartDataBuild.java index 4c7eb56ca1..69eb672e74 100644 --- a/core/core-backend/src/main/java/io/dataease/chart/utils/ChartDataBuild.java +++ b/core/core-backend/src/main/java/io/dataease/chart/utils/ChartDataBuild.java @@ -699,28 +699,38 @@ public class ChartDataBuild { public static Map transChartData(List xAxis, List yAxis, ChartViewDTO view, List data, boolean isDrill) { Map map = new HashMap<>(); - List x = new ArrayList<>(); - List series = new ArrayList<>(); - for (ChartViewFieldDTO y : yAxis) { - Series series1 = new Series(); - series1.setName(y.getName()); - series1.setType(view.getType()); - series1.setData(new ArrayList<>()); - series.add(series1); - } + List dataList = new ArrayList<>(); for (int i1 = 0; i1 < data.size(); i1++) { - String[] d = data.get(i1); + String[] row = data.get(i1); StringBuilder a = new StringBuilder(); - for (int i = xAxis.size(); i < xAxis.size() + yAxis.size(); i++) { + if (isDrill) { + a.append(row[xAxis.size() - 1]); + } else { + for (int i = 0; i < xAxis.size(); i++) { + if (i == xAxis.size() - 1) { + a.append(row[i]); + } else { + a.append(row[i]).append("\n"); + } + } + } + // yAxis最后的数据对应extLabel和extTooltip,将他们从yAxis中去掉,同时转换成动态值 + int size = xAxis.size() + yAxis.size(); + int extSize = view.getExtLabel().size() + view.getExtTooltip().size(); + + for (int i = xAxis.size(); i < size - extSize; i++) { + AxisChartDataAntVDTO axisChartDataDTO = new AxisChartDataAntVDTO(); + axisChartDataDTO.setField(a.toString()); + axisChartDataDTO.setName(a.toString()); + List dimensionList = new ArrayList<>(); List quotaList = new ArrayList<>(); - AxisChartDataDTO axisChartDataDTO = new AxisChartDataDTO(); for (int j = 0; j < xAxis.size(); j++) { ChartDimensionDTO chartDimensionDTO = new ChartDimensionDTO(); chartDimensionDTO.setId(xAxis.get(j).getId()); - chartDimensionDTO.setValue(d[j]); + chartDimensionDTO.setValue(row[j]); dimensionList.add(chartDimensionDTO); } axisChartDataDTO.setDimensionList(dimensionList); @@ -731,28 +741,16 @@ public class ChartDataBuild { quotaList.add(chartQuotaDTO); axisChartDataDTO.setQuotaList(quotaList); try { - axisChartDataDTO.setValue(StringUtils.isEmpty(d[i]) ? null : new BigDecimal(d[i])); + axisChartDataDTO.setValue(StringUtils.isEmpty(row[i]) ? null : new BigDecimal(row[i])); } catch (Exception e) { axisChartDataDTO.setValue(new BigDecimal(0)); } - series.get(j).getData().add(axisChartDataDTO); + axisChartDataDTO.setCategory(StringUtils.defaultIfBlank(yAxis.get(j).getChartShowName(), yAxis.get(j).getName())); + buildDynamicValue(view, axisChartDataDTO, row, size, extSize); + dataList.add(axisChartDataDTO); } - if (isDrill) { - a.append(d[xAxis.size() - 1]); - } else { - for (int i = 0; i < xAxis.size(); i++) { - if (i == xAxis.size() - 1) { - a.append(d[i]); - } else { - a.append(d[i]).append("\n"); - } - } - } - x.add(a.toString()); } - - map.put("x", x); - map.put("series", series); + map.put("data", dataList); return map; } diff --git a/core/core-backend/src/main/java/io/dataease/commons/constants/DataVisualizationConstants.java b/core/core-backend/src/main/java/io/dataease/commons/constants/DataVisualizationConstants.java index 19cc6e310c..8be7710b92 100644 --- a/core/core-backend/src/main/java/io/dataease/commons/constants/DataVisualizationConstants.java +++ b/core/core-backend/src/main/java/io/dataease/commons/constants/DataVisualizationConstants.java @@ -2,6 +2,16 @@ package io.dataease.commons.constants; public class DataVisualizationConstants { + //新建仪表板来源 + public static final class QUERY_SOURCE { + + // 定时报告 + public static final String REPORT = "report"; + + // 主工程 + public static final String MAIN = "main"; + } + //新建仪表板来源 public static final class NEW_PANEL_FROM { diff --git a/core/core-backend/src/main/java/io/dataease/commons/utils/SqlparserUtils.java b/core/core-backend/src/main/java/io/dataease/commons/utils/SqlparserUtils.java index 83c744b1f4..001ac67382 100644 --- a/core/core-backend/src/main/java/io/dataease/commons/utils/SqlparserUtils.java +++ b/core/core-backend/src/main/java/io/dataease/commons/utils/SqlparserUtils.java @@ -561,7 +561,7 @@ public class SqlparserUtils { if (sqlVariableDetails.getOperator().equals("in")) { return "'" + String.join("','", sqlVariableDetails.getValue()) + "'"; } else if (sqlVariableDetails.getOperator().equals("between")) { - SimpleDateFormat simpleDateFormat = new SimpleDateFormat(sqlVariableDetails.getType().size() > 1 ? (String) sqlVariableDetails.getType().get(1).replace("DD", "dd") : "YYYY"); + SimpleDateFormat simpleDateFormat = new SimpleDateFormat(sqlVariableDetails.getType().size() > 1 ? (String) sqlVariableDetails.getType().get(1).replace("DD", "dd").replace("YYYY", "yyyy") : "yyyy"); if (StringUtils.endsWith(sqlVariableDetails.getId(), START_END_SEPARATOR)) { return simpleDateFormat.format(new Date(Long.parseLong((String) sqlVariableDetails.getValue().get(1)))); } else { diff --git a/core/core-backend/src/main/java/io/dataease/dataset/manage/DatasetDataManage.java b/core/core-backend/src/main/java/io/dataease/dataset/manage/DatasetDataManage.java index 6fe82437da..16a18de088 100644 --- a/core/core-backend/src/main/java/io/dataease/dataset/manage/DatasetDataManage.java +++ b/core/core-backend/src/main/java/io/dataease/dataset/manage/DatasetDataManage.java @@ -1,13 +1,10 @@ package io.dataease.dataset.manage; -import io.dataease.extensions.view.dto.ChartExtFilterDTO; import io.dataease.api.chart.dto.ColumnPermissionItem; import io.dataease.api.chart.dto.DeSortField; -import io.dataease.extensions.view.dto.ChartExtRequest; import io.dataease.api.dataset.dto.*; import io.dataease.api.dataset.union.DatasetGroupInfoDTO; import io.dataease.api.dataset.union.DatasetTableInfoDTO; -import io.dataease.extensions.view.model.SQLMeta; import io.dataease.api.ds.vo.TableField; import io.dataease.api.permissions.dataset.dto.DataSetRowPermissionsTreeDTO; import io.dataease.auth.bo.TokenUserBO; @@ -16,16 +13,13 @@ import io.dataease.chart.utils.ChartDataBuild; import io.dataease.commons.utils.SqlparserUtils; import io.dataease.dataset.constant.DatasetTableType; import io.dataease.dataset.dto.DatasourceSchemaDTO; -import io.dataease.dataset.utils.FieldUtils; -import io.dataease.dataset.utils.SqlUtils; -import io.dataease.dataset.utils.TableUtils; +import io.dataease.dataset.utils.*; import io.dataease.datasource.dao.auto.entity.CoreDatasource; import io.dataease.datasource.dao.auto.mapper.CoreDatasourceMapper; import io.dataease.datasource.manage.EngineManage; import io.dataease.datasource.provider.CalciteProvider; import io.dataease.datasource.request.DatasourceRequest; import io.dataease.datasource.utils.DatasourceUtils; -import io.dataease.extensions.view.dto.DatasetTableFieldDTO; import io.dataease.engine.constant.ExtFieldConstant; import io.dataease.engine.constant.SQLConstants; import io.dataease.engine.constant.SqlPlaceholderConstants; @@ -34,11 +28,16 @@ import io.dataease.engine.trans.*; import io.dataease.engine.utils.SQLUtils; import io.dataease.engine.utils.Utils; import io.dataease.exception.DEException; +import io.dataease.extensions.view.dto.ChartExtFilterDTO; +import io.dataease.extensions.view.dto.ChartExtRequest; +import io.dataease.extensions.view.dto.DatasetTableFieldDTO; import io.dataease.extensions.view.dto.SqlVariableDetails; +import io.dataease.extensions.view.model.SQLMeta; import io.dataease.i18n.Translator; import io.dataease.utils.AuthUtils; import io.dataease.utils.BeanUtils; import io.dataease.utils.JsonUtil; +import io.dataease.utils.TreeUtils; import jakarta.annotation.Resource; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; @@ -733,4 +732,114 @@ public class DatasetDataManage { } return previewData; } + + public List getFieldValueTree(List ids) throws Exception { + if (ids.isEmpty()) { + DEException.throwException("no field selected."); + } + // 根据前端传的查询组件field ids,获取所有字段枚举值并去重合并 + List> list = new ArrayList<>(); + List fields = new ArrayList<>(); + + // 根据图表计算字段,获取数据集 + List allFields = new ArrayList<>(); + DatasetTableFieldDTO field = datasetTableFieldManage.selectById(ids.getFirst()); + Long datasetGroupId = field.getDatasetGroupId(); + if (field.getChartId() != null) { + allFields.addAll(datasetTableFieldManage.getChartCalcFields(field.getChartId())); + } + DatasetGroupInfoDTO datasetGroupInfoDTO = datasetGroupManage.get(datasetGroupId, null); + + Map sqlMap = datasetSQLManage.getUnionSQLForEdit(datasetGroupInfoDTO, new ChartExtRequest()); + String sql = (String) sqlMap.get("sql"); + + allFields.addAll(datasetGroupInfoDTO.getAllFields()); + + Map dsMap = (Map) sqlMap.get("dsMap"); + boolean crossDs = Utils.isCrossDs(dsMap); + if (!crossDs) { + sql = Utils.replaceSchemaAlias(sql, dsMap); + } + + // build query sql + SQLMeta sqlMeta = new SQLMeta(); + Table2SQLObj.table2sqlobj(sqlMeta, null, "(" + sql + ")", crossDs); + + for (Long id : ids) { + DatasetTableFieldDTO f = datasetTableFieldManage.selectById(id); + if (f == null) { + DEException.throwException(Translator.get("i18n_no_field")); + } + // 获取allFields + fields.add(f); + } + + Map desensitizationList = new HashMap<>(); + fields = permissionManage.filterColumnPermissions(fields, desensitizationList, datasetGroupInfoDTO.getId(), null); + if (ObjectUtils.isEmpty(fields)) { + DEException.throwException(Translator.get("i18n_no_column_permission")); + } + buildFieldName(sqlMap, fields); + + List dsList = new ArrayList<>(); + for (Map.Entry next : dsMap.entrySet()) { + dsList.add(next.getValue().getType()); + } + boolean needOrder = Utils.isNeedOrder(dsList); + + List rowPermissionsTree = new ArrayList<>(); + TokenUserBO user = AuthUtils.getUser(); + if (user != null) { + rowPermissionsTree = permissionManage.getRowPermissionsTree(datasetGroupInfoDTO.getId(), user.getUserId()); + } + + Field2SQLObj.field2sqlObj(sqlMeta, fields, allFields, crossDs, dsMap); + WhereTree2Str.transFilterTrees(sqlMeta, rowPermissionsTree, allFields, crossDs, dsMap); + Order2SQLObj.getOrders(sqlMeta, datasetGroupInfoDTO.getSortFields(), allFields, crossDs, dsMap); + String querySQL = SQLProvider.createQuerySQLWithLimit(sqlMeta, false, needOrder, false, 0, 1000); + querySQL = SqlUtils.rebuildSQL(querySQL, sqlMeta, crossDs, dsMap); + logger.info("filter tree sql: " + querySQL); + + // 通过数据源请求数据 + // 调用数据源的calcite获得data + DatasourceRequest datasourceRequest = new DatasourceRequest(); + datasourceRequest.setQuery(querySQL); + datasourceRequest.setDsList(dsMap); + Map data = calciteProvider.fetchResultField(datasourceRequest); + List rows = (List) data.get("data"); + + // 重新构造data + Set pkSet = new HashSet<>(); + rows = rows.stream().filter(row -> { + boolean allEmpty = true; + for (String s : row) { + if (StringUtils.isNotBlank(s)) { + allEmpty = false; + } + } + return !allEmpty; + }).toList(); + List treeNodes = rows.stream().map(row -> buildTreeNode(row, pkSet)).flatMap(Collection::stream).collect(Collectors.toList()); + List tree = DatasetUtils.mergeDuplicateTree(treeNodes, "root"); + return tree; + } + + private List buildTreeNode(String[] row, Set pkSet) { + List nodes = new ArrayList<>(); + List parentPkList = new ArrayList<>(); + for (int i = 0; i < row.length; i++) { + String text = row[i]; + + parentPkList.add(text); + String val = String.join(TreeUtils.SEPARATOR, parentPkList); + String parentVal = i == 0 ? TreeUtils.DEFAULT_ROOT : row[i - 1]; + String pk = String.join(TreeUtils.SEPARATOR, parentPkList); + if (pkSet.contains(pk)) continue; + pkSet.add(pk); + BaseTreeNodeDTO node = new BaseTreeNodeDTO(val, parentVal, StringUtils.isNotBlank(text) ? text.trim() : text, pk + TreeUtils.SEPARATOR + i); + nodes.add(node); + } + return nodes; + + } } diff --git a/core/core-backend/src/main/java/io/dataease/dataset/server/DatasetDataServer.java b/core/core-backend/src/main/java/io/dataease/dataset/server/DatasetDataServer.java index 60e9740c32..7f13ed268c 100644 --- a/core/core-backend/src/main/java/io/dataease/dataset/server/DatasetDataServer.java +++ b/core/core-backend/src/main/java/io/dataease/dataset/server/DatasetDataServer.java @@ -1,6 +1,7 @@ package io.dataease.dataset.server; import io.dataease.api.dataset.DatasetDataApi; +import io.dataease.api.dataset.dto.BaseTreeNodeDTO; import io.dataease.api.dataset.dto.DatasetTableDTO; import io.dataease.api.dataset.dto.EnumValueRequest; import io.dataease.api.dataset.dto.PreviewSqlDTO; @@ -70,4 +71,15 @@ public class DatasetDataServer implements DatasetDataApi { public Long getDatasetCount(DatasetGroupInfoDTO datasetGroupInfoDTO) throws Exception { return datasetDataManage.getDatasetTotal(datasetGroupInfoDTO.getId()); } + + @Override + public List getFieldValueTree(List ids) throws Exception { + try { + return datasetDataManage.getFieldValueTree(ids); + } catch (Exception e) { + e.printStackTrace(); + LogUtil.error(e); + return null; + } + } } diff --git a/core/core-backend/src/main/java/io/dataease/dataset/utils/DatasetUtils.java b/core/core-backend/src/main/java/io/dataease/dataset/utils/DatasetUtils.java new file mode 100644 index 0000000000..d11571a87e --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/dataset/utils/DatasetUtils.java @@ -0,0 +1,56 @@ +package io.dataease.dataset.utils; + +import io.dataease.api.dataset.dto.BaseTreeNodeDTO; +import io.dataease.utils.TreeUtils; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.ObjectUtils; +import org.springframework.util.Assert; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * @Author Junjun + */ +public class DatasetUtils { + public final static String SEPARATOR = "-de-"; + + public static List mergeDuplicateTree(List tree, String... rootPid) { + Assert.notNull(rootPid, "Root Pid cannot be null"); + if (CollectionUtils.isEmpty(tree)) { + return null; + } + List result = new ArrayList<>(); + // 构建id-节点map映射 + Map treePidMap = tree.stream().collect(Collectors.toMap(node -> node.getNodeType(), t -> t)); + tree.stream().filter(item -> ObjectUtils.isNotEmpty(item.getId())).forEach(node -> { + + String nodeType = node.getNodeType(); + String[] links = nodeType.split(SEPARATOR); + int length = links.length; + int level = Integer.parseInt(links[length - 1]); + // 判断根节点 + if (Arrays.asList(rootPid).contains(node.getPid()) && 0 == level) { + result.add(node); + } else { + //找到父元素 + String[] pLinks = new String[level]; + System.arraycopy(links, 0, pLinks, 0, level); + String parentType = Arrays.stream(pLinks).collect(Collectors.joining(SEPARATOR)) + TreeUtils.SEPARATOR + (level - 1); + BaseTreeNodeDTO parentNode = treePidMap.get(parentType); + if (parentNode == null) { + // 可能出现 rootPid 更高的节点 这个操作相当于截断 + return; + } + if (parentNode.getChildren() == null) { + parentNode.setChildren(new ArrayList()); + } + parentNode.getChildren().add(node); + } + }); + return result; + } +} diff --git a/core/core-backend/src/main/java/io/dataease/datasource/provider/ApiUtils.java b/core/core-backend/src/main/java/io/dataease/datasource/provider/ApiUtils.java index d6317d83cc..8bc6e4f259 100644 --- a/core/core-backend/src/main/java/io/dataease/datasource/provider/ApiUtils.java +++ b/core/core-backend/src/main/java/io/dataease/datasource/provider/ApiUtils.java @@ -41,6 +41,9 @@ public class ApiUtils { }; List apiDefinitionList = JsonUtil.parseList(datasourceRequest.getDatasource().getConfiguration(), listTypeReference); for (ApiDefinition apiDefinition : apiDefinitionList) { + if (StringUtils.isNotEmpty(apiDefinition.getType()) && apiDefinition.getType().equalsIgnoreCase("params")) { + continue; + } DatasetTableDTO datasetTableDTO = new DatasetTableDTO(); datasetTableDTO.setTableName(apiDefinition.getDeTableName()); datasetTableDTO.setName(apiDefinition.getName()); @@ -59,7 +62,7 @@ public class ApiUtils { if (apiDefinition == null) { DEException.throwException("未找到"); } - String response = execHttpRequest(apiDefinition, apiDefinition.getApiQueryTimeout() == null || apiDefinition.getApiQueryTimeout() <= 0 ? 10 : apiDefinition.getApiQueryTimeout()); + String response = execHttpRequest(apiDefinition, apiDefinition.getApiQueryTimeout() == null || apiDefinition.getApiQueryTimeout() <= 0 ? 10 : apiDefinition.getApiQueryTimeout(), params(datasourceRequest)); fieldList = getTableFields(apiDefinition); result.put("fieldList", fieldList); dataList = fetchResult(response, apiDefinition); @@ -116,19 +119,38 @@ public class ApiUtils { if (apiDefinition == null) { DEException.throwException("未找到"); } - String response = execHttpRequest(apiDefinition, apiDefinition.getApiQueryTimeout() == null || apiDefinition.getApiQueryTimeout() <= 0 ? 10 : apiDefinition.getApiQueryTimeout()); + String response = execHttpRequest(apiDefinition, apiDefinition.getApiQueryTimeout() == null || apiDefinition.getApiQueryTimeout() <= 0 ? 10 : apiDefinition.getApiQueryTimeout(), params(datasourceRequest)); return fetchResult(response, apiDefinition); } - public static String execHttpRequest(ApiDefinition apiDefinition, int socketTimeout) { + public static String execHttpRequest(ApiDefinition apiDefinition, int socketTimeout, List paramsList) { String response = ""; HttpClientConfig httpClientConfig = new HttpClientConfig(); httpClientConfig.setSocketTimeout(socketTimeout * 1000); ApiDefinitionRequest apiDefinitionRequest = apiDefinition.getRequest(); for (Map header : apiDefinitionRequest.getHeaders()) { if (header.get("name") != null && StringUtils.isNotEmpty(header.get("name").toString()) && header.get("value") != null && StringUtils.isNotEmpty(header.get("value").toString())) { - httpClientConfig.addHeader(header.get("name").toString(), header.get("value").toString()); + if (header.get("nameType") != null && header.get("nameType").toString().equalsIgnoreCase("params")) { + String param = header.get("value").toString(); + for (ApiDefinition definition : paramsList) { + for (int i = 0; i < definition.getFields().size(); i++) { + TableField field = definition.getFields().get(i); + if (field.getOriginName().equalsIgnoreCase(param)) { + String resultStr = execHttpRequest(definition, definition.getApiQueryTimeout() == null || apiDefinition.getApiQueryTimeout() <= 0 ? 10 : apiDefinition.getApiQueryTimeout(), null); + List dataList = fetchResult(resultStr, definition); + System.out.println(dataList.get(0)[i]); + if (dataList.size() > 0) { + httpClientConfig.addHeader(header.get("name").toString(), dataList.get(0)[i]); + } + } + } + + } + } else { + httpClientConfig.addHeader(header.get("name").toString(), header.get("value").toString()); + } + } } if (apiDefinitionRequest.getAuthManager() != null @@ -194,7 +216,7 @@ public class ApiUtils { return response; } - private static void previewNum(List> field){ + private static void previewNum(List> field) { for (Map stringObjectMap : field) { JSONArray newArray = new JSONArray(); if (stringObjectMap.get("value") != null) { @@ -202,7 +224,7 @@ public class ApiUtils { TypeReference listTypeReference = new TypeReference() { }; JSONArray array = objectMapper.readValue(stringObjectMap.get("value").toString(), listTypeReference); - if(array.size() > 100){ + if (array.size() > 100) { for (int i = 0; i < Math.min(100, array.size()); i++) { newArray.add(array.get(i)); } @@ -254,8 +276,8 @@ public class ApiUtils { } int i = 0; try { - LinkedHashMap data = currentData.get(0); - }catch (Exception e){ + LinkedHashMap data = currentData.get(0); + } catch (Exception e) { DEException.throwException("数据不符合规范, " + e.getMessage()); } for (LinkedHashMap data : currentData) { @@ -540,6 +562,18 @@ public class ApiUtils { } + private static List params(DatasourceRequest datasourceRequest) { + TypeReference> listTypeReference = new TypeReference>() { + }; + List apiDefinitionListTemp = null; + try { + apiDefinitionListTemp = objectMapper.readValue(datasourceRequest.getDatasource().getConfiguration(), listTypeReference); + } catch (Exception e) { + DEException.throwException(e); + } + return apiDefinitionListTemp.stream().filter(apiDefinition -> apiDefinition.getType() != null && apiDefinition.getType().equalsIgnoreCase("params")).collect(Collectors.toList()); + } + private static ApiDefinition checkApiDefinition(DatasourceRequest datasourceRequest) throws DEException { List apiDefinitionList = new ArrayList<>(); TypeReference> listTypeReference = new TypeReference>() { diff --git a/core/core-backend/src/main/java/io/dataease/datasource/provider/CalciteProvider.java b/core/core-backend/src/main/java/io/dataease/datasource/provider/CalciteProvider.java index 947ec1c0cd..e0af11c435 100644 --- a/core/core-backend/src/main/java/io/dataease/datasource/provider/CalciteProvider.java +++ b/core/core-backend/src/main/java/io/dataease/datasource/provider/CalciteProvider.java @@ -393,7 +393,7 @@ public class CalciteProvider { configuration = JsonUtil.parseObject(datasourceDTO.getConfiguration(), Impala.class); if (StringUtils.isNotEmpty(configuration.getUrlType()) && configuration.getUrlType().equalsIgnoreCase("jdbcUrl")) { if (configuration.getJdbcUrl().contains("password=")) { - String[] params = configuration.getJdbcUrl().split(";")[1].split("&"); + String[] params = configuration.getJdbcUrl().split(";"); String pd = ""; for (int i = 0; i < params.length; i++) { if (params[i].contains("password=")) { diff --git a/core/core-backend/src/main/java/io/dataease/datasource/server/DatasourceServer.java b/core/core-backend/src/main/java/io/dataease/datasource/server/DatasourceServer.java index bbc252b61e..33697e9c02 100644 --- a/core/core-backend/src/main/java/io/dataease/datasource/server/DatasourceServer.java +++ b/core/core-backend/src/main/java/io/dataease/datasource/server/DatasourceServer.java @@ -107,6 +107,8 @@ public class DatasourceServer implements DatasourceApi { all_scope, add_scope } + private TypeReference> listTypeReference = new TypeReference>() { + }; @Resource private CommonThreadPool commonThreadPool; @@ -505,11 +507,11 @@ public class DatasourceServer implements DatasourceApi { DEException.throwException("不存在的数据源!"); } BeanUtils.copyBean(datasourceDTO, datasource); - TypeReference> listTypeReference = new TypeReference>() { - }; + if (datasourceDTO.getType().equalsIgnoreCase(DatasourceConfiguration.DatasourceType.API.toString())) { List apiDefinitionList = JsonUtil.parseList(datasourceDTO.getConfiguration(), listTypeReference); List apiDefinitionListWithStatus = new ArrayList<>(); + List params = new ArrayList<>(); int success = 0; for (ApiDefinition apiDefinition : apiDefinitionList) { String status = null; @@ -534,9 +536,16 @@ public class DatasourceServer implements DatasourceApi { if (log != null) { apiDefinition.setUpdateTime(log.getStartTime()); } - apiDefinitionListWithStatus.add(apiDefinition); + + + if (StringUtils.isEmpty(apiDefinition.getType()) || apiDefinition.getType().equalsIgnoreCase("table")) { + apiDefinitionListWithStatus.add(apiDefinition); + } else { + params.add(apiDefinition); + } } datasourceDTO.setApiConfigurationStr(new String(Base64.getEncoder().encode(Objects.requireNonNull(JsonUtil.toJSONString(apiDefinitionListWithStatus)).toString().getBytes()))); + datasourceDTO.setParamsStr(new String(Base64.getEncoder().encode(Objects.requireNonNull(JsonUtil.toJSONString(params)).toString().getBytes()))); if (success == apiDefinitionList.size()) { datasourceDTO.setStatus("Success"); } else { @@ -847,12 +856,13 @@ public class DatasourceServer implements DatasourceApi { } public ApiDefinition checkApiDatasource(Map request) throws DEException { + ApiDefinition apiDefinition = JsonUtil.parseObject(new String(java.util.Base64.getDecoder().decode(request.get("data"))), ApiDefinition.class); - String response = ApiUtils.execHttpRequest(apiDefinition, apiDefinition.getApiQueryTimeout() == null || apiDefinition.getApiQueryTimeout() <= 0 ? 10 : apiDefinition.getApiQueryTimeout()); + List paramsList = JsonUtil.parseList(new String(java.util.Base64.getDecoder().decode(request.get("paramsList"))), listTypeReference); + String response = ApiUtils.execHttpRequest(apiDefinition, apiDefinition.getApiQueryTimeout() == null || apiDefinition.getApiQueryTimeout() <= 0 ? 10 : apiDefinition.getApiQueryTimeout(), paramsList); if (request.keySet().contains("type") && request.get("type").equals("apiStructure")) { apiDefinition.setShowApiStructure(true); } - ApiUtils.checkApiDefinition(apiDefinition, response); if (apiDefinition.getRequest().getAuthManager() != null && StringUtils.isNotBlank(apiDefinition.getRequest().getAuthManager().getUsername()) && StringUtils.isNotBlank(apiDefinition.getRequest().getAuthManager().getPassword()) && apiDefinition.getRequest().getAuthManager().getVerification().equals("Basic Auth")) { apiDefinition.getRequest().getAuthManager().setUsername(new String(Base64.getEncoder().encode(apiDefinition.getRequest().getAuthManager().getUsername().getBytes()))); diff --git a/core/core-backend/src/main/java/io/dataease/menu/manage/MenuManage.java b/core/core-backend/src/main/java/io/dataease/menu/manage/MenuManage.java index 5245e80cec..3319213d2f 100644 --- a/core/core-backend/src/main/java/io/dataease/menu/manage/MenuManage.java +++ b/core/core-backend/src/main/java/io/dataease/menu/manage/MenuManage.java @@ -87,12 +87,12 @@ public class MenuManage { } private boolean isXpackMenu(CoreMenu coreMenu) { + if (coreMenu.getId().equals(21L)) return false; return coreMenu.getId().equals(7L) || coreMenu.getPid().equals(7L) || coreMenu.getId().equals(14L) || coreMenu.getId().equals(17L) || coreMenu.getId().equals(18L) - || coreMenu.getId().equals(21L) || coreMenu.getPid().equals(21L) || coreMenu.getId().equals(25L) || coreMenu.getId().equals(26L) diff --git a/core/core-backend/src/main/java/io/dataease/visualization/dao/auto/entity/VisualizationReportFilter.java b/core/core-backend/src/main/java/io/dataease/visualization/dao/auto/entity/VisualizationReportFilter.java new file mode 100644 index 0000000000..baa6456131 --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/visualization/dao/auto/entity/VisualizationReportFilter.java @@ -0,0 +1,150 @@ +package io.dataease.visualization.dao.auto.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import java.io.Serializable; + +/** + *

+ * + *

+ * + * @author fit2cloud + * @since 2024-06-25 + */ +@TableName("visualization_report_filter") +public class VisualizationReportFilter implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 报告ID + */ + private Long id; + + /** + * 资源id + */ + private Long resourceId; + + /** + * 资源类型 + */ + private String dvType; + + /** + * 组件id + */ + private Long componentId; + + /** + * 过滤项id + */ + private Long filterId; + + /** + * 过滤组件内容 + */ + private String filterInfo; + + /** + * 过滤组件版本 + */ + private Integer filterVersion; + + /** + * 创建时间 + */ + private Long createTime; + + /** + * 创建人 + */ + private String createUser; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getResourceId() { + return resourceId; + } + + public void setResourceId(Long resourceId) { + this.resourceId = resourceId; + } + + public String getDvType() { + return dvType; + } + + public void setDvType(String dvType) { + this.dvType = dvType; + } + + public Long getComponentId() { + return componentId; + } + + public void setComponentId(Long componentId) { + this.componentId = componentId; + } + + public Long getFilterId() { + return filterId; + } + + public void setFilterId(Long filterId) { + this.filterId = filterId; + } + + public String getFilterInfo() { + return filterInfo; + } + + public void setFilterInfo(String filterInfo) { + this.filterInfo = filterInfo; + } + + public Integer getFilterVersion() { + return filterVersion; + } + + public void setFilterVersion(Integer filterVersion) { + this.filterVersion = filterVersion; + } + + public Long getCreateTime() { + return createTime; + } + + public void setCreateTime(Long createTime) { + this.createTime = createTime; + } + + public String getCreateUser() { + return createUser; + } + + public void setCreateUser(String createUser) { + this.createUser = createUser; + } + + @Override + public String toString() { + return "VisualizationReportFilter{" + + "id = " + id + + ", resourceId = " + resourceId + + ", dvType = " + dvType + + ", componentId = " + componentId + + ", filterId = " + filterId + + ", filterInfo = " + filterInfo + + ", filterVersion = " + filterVersion + + ", createTime = " + createTime + + ", createUser = " + createUser + + "}"; + } +} diff --git a/core/core-backend/src/main/java/io/dataease/visualization/dao/auto/mapper/VisualizationReportFilterMapper.java b/core/core-backend/src/main/java/io/dataease/visualization/dao/auto/mapper/VisualizationReportFilterMapper.java new file mode 100644 index 0000000000..2d4ad4c351 --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/visualization/dao/auto/mapper/VisualizationReportFilterMapper.java @@ -0,0 +1,18 @@ +package io.dataease.visualization.dao.auto.mapper; + +import io.dataease.visualization.dao.auto.entity.VisualizationReportFilter; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; + +/** + *

+ * Mapper 接口 + *

+ * + * @author fit2cloud + * @since 2024-06-25 + */ +@Mapper +public interface VisualizationReportFilterMapper extends BaseMapper { + +} diff --git a/core/core-backend/src/main/java/io/dataease/visualization/dao/ext/mapper/ExtDataVisualizationMapper.java b/core/core-backend/src/main/java/io/dataease/visualization/dao/ext/mapper/ExtDataVisualizationMapper.java index d823ec0db2..bc2bda435a 100644 --- a/core/core-backend/src/main/java/io/dataease/visualization/dao/ext/mapper/ExtDataVisualizationMapper.java +++ b/core/core-backend/src/main/java/io/dataease/visualization/dao/ext/mapper/ExtDataVisualizationMapper.java @@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage; import io.dataease.api.visualization.dto.VisualizationViewTableDTO; import io.dataease.api.visualization.vo.DataVisualizationBaseVO; import io.dataease.api.visualization.vo.DataVisualizationVO; +import io.dataease.api.visualization.vo.VisualizationReportFilterVO; import io.dataease.api.visualization.vo.VisualizationResourceVO; import io.dataease.chart.dao.auto.entity.CoreChartView; import io.dataease.visualization.dao.ext.po.StorePO; @@ -48,5 +49,7 @@ public interface ExtDataVisualizationMapper { List getVisualizationViewDetails(@Param("dvId") Long dvId); + List queryReportFilter(@Param("dvId") Long dvId,@Param("reportId") Long reportId); + } diff --git a/core/core-backend/src/main/java/io/dataease/visualization/server/DataVisualizationServer.java b/core/core-backend/src/main/java/io/dataease/visualization/server/DataVisualizationServer.java index 275494ddda..3143814dd4 100644 --- a/core/core-backend/src/main/java/io/dataease/visualization/server/DataVisualizationServer.java +++ b/core/core-backend/src/main/java/io/dataease/visualization/server/DataVisualizationServer.java @@ -2,6 +2,7 @@ package io.dataease.visualization.server; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; +import io.dataease.api.visualization.vo.VisualizationReportFilterVO; import io.dataease.extensions.view.dto.ChartViewDTO; import io.dataease.api.template.dto.TemplateManageFileDTO; import io.dataease.api.template.dto.VisualizationTemplateExtendDataDTO; @@ -35,6 +36,7 @@ import io.dataease.utils.*; import io.dataease.visualization.dao.auto.entity.DataVisualizationInfo; import io.dataease.visualization.dao.auto.entity.VisualizationWatermark; import io.dataease.visualization.dao.auto.mapper.DataVisualizationInfoMapper; +import io.dataease.visualization.dao.auto.mapper.VisualizationReportFilterMapper; import io.dataease.visualization.dao.auto.mapper.VisualizationWatermarkMapper; import io.dataease.visualization.dao.ext.mapper.ExtDataVisualizationMapper; import io.dataease.visualization.manage.CoreVisualizationManage; @@ -90,9 +92,12 @@ public class DataVisualizationServer implements DataVisualizationApi { @Resource private VisualizationWatermarkMapper watermarkMapper; + @Resource + private VisualizationReportFilterMapper reportFilterMapper; + @Override public DataVisualizationVO findCopyResource(Long dvId, String busiFlag) { - DataVisualizationVO result = findById(dvId, busiFlag); + DataVisualizationVO result = findById(new DataVisualizationBaseRequest(dvId, busiFlag)); if (result != null && result.getPid() == -1) { return result; } else { @@ -100,10 +105,12 @@ public class DataVisualizationServer implements DataVisualizationApi { } } - @DeLog(id = "#p0", ot = LogOT.READ, stExp = "#p1") + @DeLog(id = "#p0.id", ot = LogOT.READ, stExp = "#p0.busiFlag") @Override @XpackInteract(value = "dataVisualizationServer", original = true) - public DataVisualizationVO findById(Long dvId, String busiFlag) { + public DataVisualizationVO findById(DataVisualizationBaseRequest request) { + Long dvId = request.getId(); + String busiFlag = request.getBusiFlag(); DataVisualizationVO result = extDataVisualizationMapper.findDvInfo(dvId, busiFlag); if (result != null) { //获取图表信息 @@ -116,6 +123,16 @@ public class DataVisualizationServer implements DataVisualizationApi { VisualizationWatermarkVO watermarkVO = new VisualizationWatermarkVO(); BeanUtils.copyBean(watermarkVO, watermark); result.setWatermarkInfo(watermarkVO); + + if(DataVisualizationConstants.QUERY_SOURCE.REPORT.equals(request.getSource()) && request.getReportId() != null){ + //获取定时报告过自定义过滤组件信息 + List filterVOS = extDataVisualizationMapper.queryReportFilter(dvId,request.getReportId()); + if (!CollectionUtils.isEmpty(filterVOS)) { + Map reportFilterInfo = filterVOS.stream().collect(Collectors.toMap(VisualizationReportFilterVO::getFilterId, filterVo ->filterVo)); + result.setReportFilterInfo(reportFilterInfo); + } + } + return result; } else { DEException.throwException("资源不存在或已经被删除..."); diff --git a/core/core-backend/src/main/resources/db/desktop/V2.8__ddl.sql b/core/core-backend/src/main/resources/db/desktop/V2.8__ddl.sql new file mode 100644 index 0000000000..6f4a6902cb --- /dev/null +++ b/core/core-backend/src/main/resources/db/desktop/V2.8__ddl.sql @@ -0,0 +1,50 @@ +ALTER TABLE `core_export_task` + ADD COLUMN `msg` LONGTEXT NULL COMMENT '错误信息' AFTER `params`; + + +DROP TABLE IF EXISTS `xpack_plugin`; +CREATE TABLE `xpack_plugin` +( + `id` bigint NOT NULL COMMENT 'ID', + `name` varchar(255) NOT NULL COMMENT '插件名称', + `icon` longtext NOT NULL COMMENT '图标', + `version` varchar(255) NOT NULL COMMENT '版本', + `install_time` bigint NOT NULL COMMENT '安装时间', + `flag` varchar(255) NOT NULL COMMENT '类型', + `developer` varchar(255) NOT NULL COMMENT '开发者', + `config` longtext NOT NULL COMMENT '插件配置', + `require_version` varchar(255) NOT NULL COMMENT 'DE最低版本', + `module_name` varchar(255) NOT NULL COMMENT '模块名称', + `jar_name` varchar(255) NOT NULL COMMENT 'Jar包名称', + PRIMARY KEY (`id`) +) COMMENT ='插件表'; + +ALTER TABLE `xpack_share` + ADD COLUMN `ticket_require` tinyint(1) NOT NULL DEFAULT 0 COMMENT 'ticket必须' AFTER `auto_pwd`; + + +DROP TABLE IF EXISTS `core_share_ticket`; +CREATE TABLE `core_share_ticket` +( + `id` bigint NOT NULL COMMENT 'ID', + `uuid` varchar(255) NOT NULL COMMENT '分享uuid', + `ticket` varchar(255) NOT NULL COMMENT 'ticket', + `exp` bigint DEFAULT NULL COMMENT 'ticket有效期', + `args` longtext COMMENT 'ticket参数', + `access_time` bigint DEFAULT NULL COMMENT '首次访问时间', + PRIMARY KEY (`id`) +) COMMENT ='分享Ticket表'; + +DROP TABLE IF EXISTS `visualization_report_filter`; +CREATE TABLE `visualization_report_filter` ( + `id` bigint NOT NULL COMMENT '报告ID', + `resource_id` bigint DEFAULT NULL COMMENT '资源id', + `dv_type` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '资源类型', + `component_id` bigint DEFAULT NULL COMMENT '组件id', + `filter_id` bigint DEFAULT NULL COMMENT '过滤项id', + `filter_info` longtext COLLATE utf8mb4_general_ci COMMENT '过滤组件内容', + `filter_version` int DEFAULT NULL COMMENT '过滤组件版本', + `create_time` bigint DEFAULT NULL COMMENT '创建时间', + `create_user` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '创建人', + PRIMARY KEY (`id`) +); \ No newline at end of file diff --git a/core/core-backend/src/main/resources/db/migration/V2.8__ddl.sql b/core/core-backend/src/main/resources/db/migration/V2.8__ddl.sql index 6dcf4ba043..6f4a6902cb 100644 --- a/core/core-backend/src/main/resources/db/migration/V2.8__ddl.sql +++ b/core/core-backend/src/main/resources/db/migration/V2.8__ddl.sql @@ -33,4 +33,18 @@ CREATE TABLE `core_share_ticket` `args` longtext COMMENT 'ticket参数', `access_time` bigint DEFAULT NULL COMMENT '首次访问时间', PRIMARY KEY (`id`) -) COMMENT ='分享Ticket表'; \ No newline at end of file +) COMMENT ='分享Ticket表'; + +DROP TABLE IF EXISTS `visualization_report_filter`; +CREATE TABLE `visualization_report_filter` ( + `id` bigint NOT NULL COMMENT '报告ID', + `resource_id` bigint DEFAULT NULL COMMENT '资源id', + `dv_type` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '资源类型', + `component_id` bigint DEFAULT NULL COMMENT '组件id', + `filter_id` bigint DEFAULT NULL COMMENT '过滤项id', + `filter_info` longtext COLLATE utf8mb4_general_ci COMMENT '过滤组件内容', + `filter_version` int DEFAULT NULL COMMENT '过滤组件版本', + `create_time` bigint DEFAULT NULL COMMENT '创建时间', + `create_user` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '创建人', + PRIMARY KEY (`id`) +); \ No newline at end of file diff --git a/core/core-backend/src/main/resources/mybatis/ExtDataVisualizationMapper.xml b/core/core-backend/src/main/resources/mybatis/ExtDataVisualizationMapper.xml index 76729f21a3..55958b2a87 100644 --- a/core/core-backend/src/main/resources/mybatis/ExtDataVisualizationMapper.xml +++ b/core/core-backend/src/main/resources/mybatis/ExtDataVisualizationMapper.xml @@ -403,4 +403,20 @@ WHERE core_chart_view.scene_id = #{dvId} AND core_chart_view.id IS NOT NULL and core_chart_view.`type` != 'VQuery' + + diff --git a/core/core-frontend/index.html b/core/core-frontend/index.html index 96958cb56f..946a05d659 100644 --- a/core/core-frontend/index.html +++ b/core/core-frontend/index.html @@ -4,7 +4,7 @@ - DataEase +
diff --git a/core/core-frontend/src/api/visualization/dataVisualization.ts b/core/core-frontend/src/api/visualization/dataVisualization.ts index d5f3d71fe7..3998639690 100644 --- a/core/core-frontend/src/api/visualization/dataVisualization.ts +++ b/core/core-frontend/src/api/visualization/dataVisualization.ts @@ -20,14 +20,15 @@ export const findCopyResource = async (dvId, busiFlag): Promise => { return request.get({ url: '/dataVisualization/findCopyResource/' + dvId + '/' + busiFlag }) } -export const findById = async (dvId, busiFlag): Promise => { +export const findById = async (dvId, busiFlag, source = 'main'): Promise => { let busiFlagResult = busiFlag if (!busiFlagResult) { await findDvType(dvId).then(res => { busiFlagResult = res.data }) } - return request.get({ url: '/dataVisualization/findById/' + dvId + '/' + busiFlagResult }) + const data = { id: dvId, busiFlag: busiFlagResult, source } + return request.post({ url: '/dataVisualization/findById', data }) } export const queryTreeApi = async (data: BusiTreeRequest): Promise => { diff --git a/core/core-frontend/src/custom-component/v-query/Component.vue b/core/core-frontend/src/custom-component/v-query/Component.vue index eeeee78f7b..bcdd6617ca 100644 --- a/core/core-frontend/src/custom-component/v-query/Component.vue +++ b/core/core-frontend/src/custom-component/v-query/Component.vue @@ -289,6 +289,8 @@ const updateQueryCriteria = () => { ele.checkedFields = checkedFields ele.checkedFieldsMap = checkedFieldsMap } else { + if (!ele.dataset.id || ele.optionValueSource !== 1 || ![0, 2, 5].includes(+ele.displayType)) + return const checkedFields = [] datasetFieldList.value.forEach(itx => { if (itx.tableId === ele.dataset.id) { diff --git a/core/core-frontend/src/layout/components/LayoutTransition.vue b/core/core-frontend/src/layout/components/LayoutTransition.vue new file mode 100644 index 0000000000..594a48b0ad --- /dev/null +++ b/core/core-frontend/src/layout/components/LayoutTransition.vue @@ -0,0 +1,7 @@ + + diff --git a/core/core-frontend/src/router/establish.ts b/core/core-frontend/src/router/establish.ts index 271dc4f375..c7e5023466 100644 --- a/core/core-frontend/src/router/establish.ts +++ b/core/core-frontend/src/router/establish.ts @@ -4,6 +4,7 @@ import { XpackComponent } from '@/components/plugin' const modules = import.meta.glob('../views/**/*.vue') export const Layout = () => import('@/layout/index.vue') const xpackComName = 'components/plugin' +export const LayoutTransition = () => import('@/layout/components/LayoutTransition.vue') // 后端控制路由生成 export const generateRoutesFn2 = (routes: AppCustomRouteRecordRaw[]): AppRouteRecordRaw[] => { const res: AppRouteRecordRaw[] = [] @@ -37,12 +38,14 @@ export const generateRoutesFn2 = (routes: AppCustomRouteRecordRaw[]): AppRouteRe let comModule = null if (route.component === xpackComName) { comModule = XpackComponent - } else { + } else if (!route.component.startsWith('Layout')) { comModule = modules[`../views/${route.component}/index.vue`] } if (route.component === 'Layout') { data.component = Layout + } else if (route.component === 'LayoutTransition') { + data.component = LayoutTransition } else if (!comModule) { } else { data.component = comModule diff --git a/core/core-frontend/src/store/modules/app.ts b/core/core-frontend/src/store/modules/app.ts index 01af127df8..e922b1f92a 100644 --- a/core/core-frontend/src/store/modules/app.ts +++ b/core/core-frontend/src/store/modules/app.ts @@ -19,7 +19,7 @@ export const useAppStore = defineStore('app', { return { size: true, // 尺寸图标 pageLoading: false, // 路由跳转loading - title: 'DataEase', + title: '', dekey: 'DataEaseKey', isDataEaseBi: false, isIframe: false, diff --git a/core/core-frontend/src/store/modules/appearance.ts b/core/core-frontend/src/store/modules/appearance.ts index f7954baf59..fc0f50a600 100644 --- a/core/core-frontend/src/store/modules/appearance.ts +++ b/core/core-frontend/src/store/modules/appearance.ts @@ -152,10 +152,12 @@ export const useAppearanceStore = defineStore('appearanceStore', { if (this.loaded) { return } + document.title = '' const res = await uiLoadApi() this.loaded = true const resData = res.data if (!resData?.length) { + document.title = 'DataEase' return } const data: AppearanceState = { loaded: false, community: true } @@ -223,6 +225,8 @@ export const useAppearanceStore = defineStore('appearanceStore', { this.footContent = data.footContent if (this.name) { document.title = this.name + } else { + document.title = 'DataEase' } if (isDataEaseBi) return const link = document.querySelector('link[rel="icon"]') diff --git a/core/core-frontend/src/utils/CanvasInfoTransUtils.ts b/core/core-frontend/src/utils/CanvasInfoTransUtils.ts new file mode 100644 index 0000000000..075ec9a493 --- /dev/null +++ b/core/core-frontend/src/utils/CanvasInfoTransUtils.ts @@ -0,0 +1,27 @@ +import { deepCopy } from '@/utils/utils' + +export default function defaultConditionTrans(canvasInfo) { + const { reportFilterInfo, componentData } = canvasInfo + const componentDataArray = JSON.parse(componentData) + const allFilter = [] + // 获取所有查询条件 + componentDataArray.forEach(item => { + if (item.component === 'VQuery') { + Array.prototype.push.apply(allFilter, item.propValue) + } + }) + + const allDefaultFilter = deepCopy(allFilter) + if (reportFilterInfo) { + allFilter.forEach((itemFilter, index) => { + if (reportFilterInfo[itemFilter.id]) { + allDefaultFilter.splice(index, 1, JSON.parse(reportFilterInfo[itemFilter.id])) + } + }) + } + + return { + sourceFilter: allFilter, + defaultFilter: allDefaultFilter + } +} diff --git a/core/core-frontend/src/views/chart/components/js/panel/charts/bar/range-bar.ts b/core/core-frontend/src/views/chart/components/js/panel/charts/bar/range-bar.ts index a6d81e77eb..7f24cb8390 100644 --- a/core/core-frontend/src/views/chart/components/js/panel/charts/bar/range-bar.ts +++ b/core/core-frontend/src/views/chart/components/js/panel/charts/bar/range-bar.ts @@ -394,7 +394,6 @@ export class RangeBar extends G2PlotChartView { this.configXAxis, this.configYAxis, this.configSlider, - this.configAnalyseHorizontal, this.configEmptyDataStrategy )(chart, options) } diff --git a/core/core-frontend/src/views/chart/components/js/util.ts b/core/core-frontend/src/views/chart/components/js/util.ts index f63422c944..281397d5ac 100644 --- a/core/core-frontend/src/views/chart/components/js/util.ts +++ b/core/core-frontend/src/views/chart/components/js/util.ts @@ -238,12 +238,19 @@ export const quotaViews = ['label', 'richTextView', 'indicator', 'gauge', 'liqui export function handleEmptyDataStrategy(chart: Chart, options: O): O { const { data } = options as unknown as Options + const isChartMix = chart.type.includes('chart-mix') if (!data?.length) { return options } const strategy = parseJson(chart.senior).functionCfg.emptyDataStrategy if (strategy === 'ignoreData') { - handleIgnoreData(data) + if (isChartMix) { + for (let i = 0; i < data.length; i++) { + handleIgnoreData(data[i] as Record[]) + } + } else { + handleIgnoreData(data) + } return options } const { yAxis, xAxisExt, extStack } = chart @@ -252,7 +259,13 @@ export function handleEmptyDataStrategy(chart: Chart, opt case 'breakLine': { if (multiDimension) { // 多维度保持空 - handleBreakLineMultiDimension(data) + if (isChartMix) { + for (let i = 0; i < data.length; i++) { + handleBreakLineMultiDimension(data[i] as Record[]) + } + } else { + handleBreakLineMultiDimension(data) + } } return { ...options, @@ -262,10 +275,22 @@ export function handleEmptyDataStrategy(chart: Chart, opt case 'setZero': { if (multiDimension) { // 多维度置0 - handleSetZeroMultiDimension(data) + if (isChartMix) { + for (let i = 0; i < data.length; i++) { + handleSetZeroMultiDimension(data[i] as Record[]) + } + } else { + handleSetZeroMultiDimension(data) + } } else { // 单维度置0 - handleSetZeroSingleDimension(data) + if (isChartMix) { + for (let i = 0; i < data.length; i++) { + handleSetZeroSingleDimension(data[i] as Record[]) + } + } else { + handleSetZeroSingleDimension(data) + } } break } diff --git a/core/core-frontend/src/views/share/share/ShareTicket.vue b/core/core-frontend/src/views/share/share/ShareTicket.vue index 74f733fe8b..22dc519f92 100644 --- a/core/core-frontend/src/views/share/share/ShareTicket.vue +++ b/core/core-frontend/src/views/share/share/ShareTicket.vue @@ -80,6 +80,7 @@ min="0" max="1440" size="small" + @input="v => handleInput(v, scope.$index)" @change="val => validateExp(val, scope.$index)" /> @@ -251,7 +252,12 @@ const refreshTicket = row => { row.ticket = res.data }) } - +const handleInput = (val, index) => { + if (val === null || val === '') { + return + } + state.tableData[index]['exp'] = val.replace(/[^\d]/g, '') +} const validateExp = (val, index) => { const cref = expRefs.value[index] const e = cref.input diff --git a/core/core-frontend/src/views/visualized/data/datasource/form/ApiHttpRequestDraw.vue b/core/core-frontend/src/views/visualized/data/datasource/form/ApiHttpRequestDraw.vue index 80c1bfec5a..0575cf124f 100644 --- a/core/core-frontend/src/views/visualized/data/datasource/form/ApiHttpRequestDraw.vue +++ b/core/core-frontend/src/views/visualized/data/datasource/form/ApiHttpRequestDraw.vue @@ -24,6 +24,7 @@ export interface Field { export interface ApiItem { status: string name: string + type: string deTableName?: string url: string method: string @@ -57,10 +58,12 @@ const originFieldItem = reactive({ }) let apiItemList = reactive([]) +let paramsList = reactive([]) let apiItem = reactive({ status: '', name: '', + type: 'table', url: '', method: 'GET', request: { @@ -95,6 +98,7 @@ const edit_api_item = ref(false) const active = ref(1) const loading = ref(false) const columns = shallowRef([]) +const valueList = shallowRef([]) const tableData = shallowRef([]) const apiItemBasicInfo = ref() const isNumber = (rule, value, callback) => { @@ -152,9 +156,16 @@ const rule = reactive({ }) const activeName = ref('third') provide('api-active-name', activeName) -const initApiItem = (val: ApiItem, apiList, name) => { +const initApiItem = (val: ApiItem, from, name) => { activeName.value = name - apiItemList = apiList + apiItemList = from.apiConfiguration + paramsList = from.paramsConfiguration + if (val.type !== 'params') { + valueList.value = [] + for (let i = 0; i < paramsList.length; i++) { + valueList.value = valueList.value.concat(paramsList[i].fields) + } + } Object.assign(apiItem, val) edit_api_item.value = true active.value = 0 @@ -167,9 +178,10 @@ const showApiData = () => { apiItemBasicInfo.value.validate(valid => { if (valid) { const data = Base64.encode(JSON.stringify(apiItem)) + const params = Base64.encode(JSON.stringify(paramsList)) loading.value = true cancelMap['/datasource/checkApiDatasource']?.() - checkApiItem({ data: data, type: 'apiStructure' }) + checkApiItem({ data: data, type: 'apiStructure', paramsList: params }) .then(response => { originFieldItem.jsonFields = response.data.jsonFields }) @@ -203,7 +215,7 @@ const fieldOptions = [ ] const disabledNext = ref(false) const saveItem = () => { - if (apiItem.fields.length === 0) { + if (apiItem.type !== 'params' && apiItem.fields.length === 0) { ElMessage.error(t('datasource.api_field_not_empty')) return } @@ -239,7 +251,8 @@ const next = () => { } cancelMap['/datasource/checkApiDatasource']?.() - checkApiItem({ data: Base64.encode(JSON.stringify(apiItem)) }) + const params = Base64.encode(JSON.stringify(paramsList)) + checkApiItem({ data: Base64.encode(JSON.stringify(apiItem)), paramsList: params }) .then(response => { apiItem.jsonFields = response.data.jsonFields apiItem.fields = [] @@ -465,6 +478,7 @@ defineExpose({ @@ -572,7 +586,11 @@ defineExpose({ - +