feat(XPack): 定时报告支持自定义过滤组件值

This commit is contained in:
wangjiahao 2024-06-26 10:56:50 +08:00
commit 0c5e724a15
62 changed files with 2678 additions and 113 deletions

View File

@ -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> T formatAxis(ChartViewDTO view);
public abstract <T extends CustomFilterResult, K extends AxisFormatResult> T customFilter(ChartViewDTO view, List<ChartExtFilterDTO> filterList, K formatResult);
public abstract <T extends ChartCalcDataResult> T calcChartResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, Map<String, Object> sqlMap, SQLMeta sqlMeta, CalciteProvider provider);
}

View File

@ -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<String, AbstractChartHandler> 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;
}
}

View File

@ -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<ChartAxis, List<ChartViewFieldDTO>>();
var context = new HashMap<String, Object>();
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 extends CustomFilterResult, K extends AxisFormatResult> T customFilter(ChartViewDTO view, List<ChartExtFilterDTO> filterList, K formatResult) {
return (T) new CustomFilterResult(filterList, formatResult.getContext());
}
public Map<String, Object> buildResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, List<String[]> 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<String, Object> result = ChartDataBuild.transChartData(xAxis, yAxis, view, data, isDrill);
return result;
}
@Override
public <T extends ChartCalcDataResult> T calcChartResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, Map<String, Object> sqlMap, SQLMeta sqlMeta, CalciteProvider provider) {
var dsMap = (Map<Long, DatasourceSchemaDTO>) sqlMap.get("dsMap");
List<String> dsList = new ArrayList<>();
for (Map.Entry<Long, DatasourceSchemaDTO> 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<String[]> data = (List<String[]>) 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<ChartViewFieldDTO> getAllChartFields(ChartViewDTO view) {
// get all fields
Map<String, List<ChartViewFieldDTO>> stringListMap = chartViewManege.listByDQ(view.getTableId(), view.getId(), view);
List<ChartViewFieldDTO> dimensionList = stringListMap.get("dimensionList");
List<ChartViewFieldDTO> quotaList = stringListMap.get("quotaList");
List<ChartViewFieldDTO> allFields = new ArrayList<>();
allFields.addAll(dimensionList);
allFields.addAll(quotaList);
return allFields.stream().filter(ele -> ele.getId() != -1L).collect(Collectors.toList());
}
protected List<ChartSeniorAssistDTO> getDynamicAssistFields(ChartViewDTO view) throws Exception {
List<ChartSeniorAssistDTO> list = new ArrayList<>();
Map<String, Object> 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<ChartSeniorAssistDTO> 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<ChartViewFieldDTO> getAssistFields(List<ChartSeniorAssistDTO> list, List<ChartViewFieldDTO> yAxis) {
List<ChartViewFieldDTO> 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<ChartViewFieldDTO> 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<ChartViewFieldDTO> xAxis, List<ChartViewFieldDTO> yAxis, List<String[]> 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<ChartViewFieldDTO> 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<String, String> 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<ChartExtFilterDTO> filter, List<ChartViewFieldDTO> 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<ChartViewFieldDTO> xAxis,
List<ChartExtFilterDTO> filterList,
List<ChartViewFieldDTO> fieldsToFilter,
List<ChartViewFieldDTO> drillFields,
List<ChartDrillRequest> drillRequestList) {
var fields = xAxis.stream().map(ChartViewFieldDTO::getId).collect(Collectors.toSet());
ChartDrillRequest head = drillRequestList.get(0);
Map<Long, String> dimValMap = new HashMap<>();
head.getDimensionList().forEach(item -> dimValMap.put(item.getId(), item.getValue()));
Map<Long, ChartViewFieldDTO> 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<String, Long> 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<ChartViewFieldDTO> 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;
}
}

View File

@ -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;
}
}

View File

@ -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<ChartViewFieldDTO>(view.getXAxis());
xAxis.addAll(view.getXAxisExt());
result.getAxisMap().put(ChartAxis.xAxis, xAxis);
return result;
}
}

View File

@ -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 extends CustomFilterResult, K extends AxisFormatResult> T customFilter(ChartViewDTO view, List<ChartExtFilterDTO> filterList, K formatResult) {
var yAxis = formatResult.getAxisMap().get(ChartAxis.yAxis);
String originFilterJson = (String) JsonUtil.toJSONString(filterList);
// 如果设置了同环比的指标字段设置了过滤器那就需要把该过滤器的时间往前回调一年
// 计算完同环比之后再把计算结果和原有的过滤结果对比去除不该出现的前一年的数据
boolean yoyFiltered = checkYoyFilter(filterList, yAxis);
if (yoyFiltered) {
List<ChartExtFilterDTO> 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<String, Object> buildResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, List<String[]> data) {
var yoyFiltered = filterResult.getContext().get("yoyFiltered") != null;
// 带过滤同环比直接返回原始数据,再由视图重新组装
if (yoyFiltered) {
var result = new HashMap<String, Object>();
result.put("data", data);
return result;
}
return buildNormalResult(view, formatResult, filterResult, data);
}
/**
* 构建同环比类型的数据
* @param view 视图对象
* @param formatResult 处理后的轴
* @param filterResult 处理后的过滤器
* @param data 原始数据
* @return 视图构建结果
*/
public Map<String, Object> buildNormalResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, List<String[]> data) {
return super.buildResult(view, formatResult, filterResult, data);
}
@Override
public <T extends ChartCalcDataResult> T calcChartResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, Map<String, Object> sqlMap, SQLMeta sqlMeta, CalciteProvider provider) {
var dsMap = (Map<Long, DatasourceSchemaDTO>) sqlMap.get("dsMap");
List<String> dsList = new ArrayList<>();
for (Map.Entry<Long, DatasourceSchemaDTO> 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<ChartExtFilterDTO>) filterResult.getContext().get("originFilter");
var allFields = (List<ChartViewFieldDTO>) 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<String[]>) provider.fetchResultField(request).get("data");
List<String[]> resultData = new ArrayList<>();
// 包含一年前的数据, 已计算同环比
var yoyData = (List<String[]>) 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;
}
}

View File

@ -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 extends ChartCalcDataResult> T calcChartResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, Map<String, Object> sqlMap, SQLMeta sqlMeta, CalciteProvider provider) {
var dsMap = (Map<Long, DatasourceSchemaDTO>) sqlMap.get("dsMap");
List<String> dsList = new ArrayList<>();
for (Map.Entry<Long, DatasourceSchemaDTO> 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<String[]>) provider.fetchResultField(req).get("data");
result.setAssistData(assistData);
result.setDynamicAssistFields(dynamicAssistFields);
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
}

View File

@ -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";
}

View File

@ -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 extends CustomFilterResult, K extends AxisFormatResult> T customFilter(ChartViewDTO view, List<ChartExtFilterDTO> filterList, K formatResult) {
var result = super.customFilter(view, filterList, formatResult);
List<ChartDrillRequest> drillRequestList = view.getChartExtRequest().getDrill();
var drillFields = formatResult.getAxisMap().get(ChartAxis.drill);
// 分组维度下钻
if (ObjectUtils.isNotEmpty(drillRequestList) && (drillFields.size() > drillRequestList.size())) {
List<ChartExtFilterDTO> 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<ChartExtFilterDTO> drillFilters = new ArrayList<>();
ArrayList<ChartViewFieldDTO> 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<String, Object> buildNormalResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, List<String[]> 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);
}
}

View File

@ -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<String, Object> buildNormalResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, List<String[]> 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<String, Object> result = ChartDataBuild.transMixChartDataAntV(xAxis, xAxis, new ArrayList<>(), yAxis, view, data, isDrill);
return result;
}
}

View File

@ -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<ChartViewFieldDTO>();
var xAxis = new ArrayList<ChartViewFieldDTO>(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<String, Object> buildNormalResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, List<String[]> 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<String, Object> result = ChartDataBuild.transBarRangeDataAntV(skipBarRange, barRangeDate, xAxis, xAxis, yAxis, view, data, isDrill);
return result;
}
@Override
public <T extends ChartCalcDataResult> T calcChartResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, Map<String, Object> sqlMap, SQLMeta sqlMeta, CalciteProvider provider) {
sqlMeta.setChartType(this.type);
return super.calcChartResult(view, formatResult, filterResult, sqlMap, sqlMeta, provider);
}
}

View File

@ -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 extends CustomFilterResult, K extends AxisFormatResult> T customFilter(ChartViewDTO view, List<ChartExtFilterDTO> filterList, K formatResult) {
var result = super.customFilter(view, filterList, formatResult);
List<ChartDrillRequest> drillRequestList = view.getChartExtRequest().getDrill();
var drillFields = formatResult.getAxisMap().get(ChartAxis.drill);
// 堆叠维度下钻
if (ObjectUtils.isNotEmpty(drillRequestList) && (drillFields.size() > drillRequestList.size())) {
List<ChartExtFilterDTO> 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<ChartExtFilterDTO> drillFilters = new ArrayList<>();
ArrayList<ChartViewFieldDTO> 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<String, Object> buildNormalResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, List<String[]> 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);
}
}

View File

@ -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 extends CustomFilterResult, K extends AxisFormatResult> T customFilter(ChartViewDTO view, List<ChartExtFilterDTO> filterList, K formatResult) {
var result = super.customFilter(view, filterList, formatResult);
List<ChartDrillRequest> drillRequestList = view.getChartExtRequest().getDrill();
var drillFields = formatResult.getAxisMap().get(ChartAxis.drill);
// 分组维度下钻
if (ObjectUtils.isNotEmpty(drillRequestList) && (drillFields.size() > drillRequestList.size())) {
List<ChartExtFilterDTO> 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<ChartExtFilterDTO> drillFilters = new ArrayList<>();
ArrayList<ChartViewFieldDTO> 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<String, Object> buildNormalResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, List<String[]> 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);
}
}

View File

@ -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<String, Object> buildNormalResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, List<String[]> 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);
}
}

View File

@ -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<String, Object> buildNormalResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, List<String[]> 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 extends ChartCalcDataResult> T calcChartResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, Map<String, Object> sqlMap, SQLMeta sqlMeta, CalciteProvider provider) {
var dsMap = (Map<Long, DatasourceSchemaDTO>) sqlMap.get("dsMap");
List<String> dsList = new ArrayList<>();
for (Map.Entry<Long, DatasourceSchemaDTO> 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<String[]>) provider.fetchResultField(req).get("data");
result.setAssistData(assistData);
result.setDynamicAssistFields(dynamicAssistFields);
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
}

View File

@ -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<String, Object> buildNormalResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, List<String[]> 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 extends CustomFilterResult, K extends AxisFormatResult> T customFilter(ChartViewDTO view, List<ChartExtFilterDTO> filterList, K formatResult) {
var result = super.customFilter(view, filterList, formatResult);
List<ChartDrillRequest> drillRequestList = view.getChartExtRequest().getDrill();
var drillFields = formatResult.getAxisMap().get(ChartAxis.drill);
// 堆叠维度下钻
if (ObjectUtils.isNotEmpty(drillRequestList) && (drillFields.size() > drillRequestList.size())) {
List<ChartExtFilterDTO> 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<ChartExtFilterDTO> drillFilters = new ArrayList<>();
ArrayList<ChartViewFieldDTO> 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 extends ChartCalcDataResult> T calcChartResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, Map<String, Object> sqlMap, SQLMeta sqlMeta, CalciteProvider provider) {
var dsMap = (Map<Long, DatasourceSchemaDTO>) sqlMap.get("dsMap");
List<String> dsList = new ArrayList<>();
for (Map.Entry<Long, DatasourceSchemaDTO> 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<String[]>) provider.fetchResultField(req).get("data");
result.setAssistData(assistData);
result.setDynamicAssistFields(dynamicAssistFields);
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
}

View File

@ -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";
}

View File

@ -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<String, Object> buildResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, List<String[]> 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<String, Object> result = ChartDataBuild.transHeatMapChartDataAntV(xAxis, xAxis, yAxis, view, data, isDrill);
return result;
}
}

View File

@ -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";
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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<ChartAxis, List<ChartViewFieldDTO>>();
var yAxis = new ArrayList<>(view.getYAxis());
Map<String, Object> customAttr = view.getCustomAttr();
Map<String, Object> size = (Map<String, Object>) 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<String, Object>();
var result = new AxisFormatResult(axisMap, context);
return result;
}
}

View File

@ -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";
}

View File

@ -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<ChartAxis, List<ChartViewFieldDTO>>();
var yAxis = new ArrayList<>(view.getYAxis());
Map<String, Object> customAttr = view.getCustomAttr();
Map<String, Object> misc = (Map<String, Object>) 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<String, Object>();
var result = new AxisFormatResult(axisMap, context);
return result;
}
}

View File

@ -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 extends ChartCalcDataResult> T calcChartResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, Map<String, Object> sqlMap, SQLMeta sqlMeta, CalciteProvider provider) {
var dsMap = (Map<Long, DatasourceSchemaDTO>) sqlMap.get("dsMap");
List<String> dsList = new ArrayList<>();
for (Map.Entry<Long, DatasourceSchemaDTO> 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<String[]> data = (List<String[]>) provider.fetchResultField(datasourceRequest).get("data");
boolean isdrill = filterResult
.getFilterList()
.stream()
.anyMatch(ele -> ele.getFilterType() == 1);
Map<String, Object> 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<String, Object> target, String type, String field) {
String maxType = (String) target.get(type);
if (StringUtils.equalsIgnoreCase("dynamic", maxType)) {
Map<String, Object> maxField = (Map<String, Object>) 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;
}
}

View File

@ -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";
}

View File

@ -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;
}
}

View File

@ -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";
}

View File

@ -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";
}

View File

@ -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";
}

View File

@ -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;
}
}

View File

@ -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<String, Object> buildNormalResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, List<String[]> 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<String, Object> result = ChartDataBuild.transMixChartDataAntV(xAxis, xAxis, new ArrayList<>(), yAxis, view, data, isDrill);
return result;
}
}

View File

@ -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<String, Object> buildNormalResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, List<String[]> 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<String, Object> result = ChartDataBuild.transScatterDataAntV(xAxis, yAxis, view, data, extBubble, isDrill);
return result;
}
}

View File

@ -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 extends CustomFilterResult, K extends AxisFormatResult> T customFilter(ChartViewDTO view, List<ChartExtFilterDTO> filterList, K formatResult) {
var chartExtRequest = view.getChartExtRequest();
Map<String, Object> mapAttr = view.getCustomAttr();
Map<String, Object> mapSize = (Map<String, Object>) 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 extends ChartCalcDataResult> T calcChartResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, Map<String, Object> sqlMap, SQLMeta sqlMeta, CalciteProvider provider) {
var chartExtRequest = view.getChartExtRequest();
var dsMap = (Map<Long, DatasourceSchemaDTO>) sqlMap.get("dsMap");
List<String> dsList = new ArrayList<>();
for (Map.Entry<Long, DatasourceSchemaDTO> 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<String[]> tmpData = (List<String[]>) 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<String[]> data = (List<String[]>) 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;
}
}

View File

@ -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";
}

View File

@ -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<ChartViewFieldDTO> allFields = getAllChartFields(view);
ChartViewDTO chartViewDTO = null;
if (ObjectUtils.isNotEmpty(view.getIsPlugin()) && view.getIsPlugin()) {
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<ChartViewFieldDTO> allFields, List<ChartViewFieldDTO> 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<String, ColumnPermissionItem> desensitizationList = new HashMap<>();
List<DatasetTableFieldDTO> columnPermissionFields = permissionManage.filterColumnPermissions(transFields(allFields), desensitizationList, table.getId(), chartExtRequest.getUser());
// row permission
List<DataSetRowPermissionsTreeDTO> rowPermissionsTree = permissionManage.getRowPermissionsTree(table.getId(), chartExtRequest.getUser());
//将没有权限的列删掉
List<String> dataeaseNames = columnPermissionFields.stream().map(DatasetTableFieldDTO::getDataeaseName).collect(Collectors.toList());
dataeaseNames.add("*");
var axisMap = formatResult.getAxisMap();
axisMap.forEach((axis, fields) -> {
Iterator<ChartViewFieldDTO> 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<ChartExtFilterDTO> 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<SqlVariableDetails> 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<Long> 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<ChartExtFilterDTO> 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<ChartDrillRequest> 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<String, Long> 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<String> 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<String, Object> sqlMap = datasetSQLManage.getUnionSQLForEdit(table, chartExtRequest);
String sql = (String) sqlMap.get("sql");
Map<Long, DatasourceSchemaDTO> dsMap = (Map<Long, DatasourceSchemaDTO>) sqlMap.get("dsMap");
List<String> dsList = new ArrayList<>();
for (Map.Entry<Long, DatasourceSchemaDTO> 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<ChartViewFieldDTO> detailFieldList = new ArrayList<>();
String detailFieldSql = null;
List<String[]> detailData = new ArrayList<>();
if (ObjectUtils.isEmpty(dsMap)) {
DEException.throwException(ResultCode.DATA_IS_WRONG.code(), Translator.get("i18n_datasource_delete"));
}
for (Map.Entry<Long, DatasourceSchemaDTO> 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<Long, String> 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<String, Object> sourceInfo = ChartDataBuild.transTableNormal(xAxis, yAxis, view, calcResult.getOriginData(), extStack, desensitizationList);
sourceInfo.put("sourceData", calcResult.getOriginData());
view.setData(sourceInfo);
return view;
}
// 构建结果
Map<String, Object> map = new TreeMap<>();
// 图表组件可再扩展
Map<String, Object> 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<ChartViewFieldDTO> allFields, List<ChartViewFieldDTO> viewFields) throws Exception {
List<ChartViewFieldDTO> xAxisBase = null;
List<ChartViewFieldDTO> xAxis = null;
List<ChartViewFieldDTO> 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);

View File

@ -699,28 +699,38 @@ public class ChartDataBuild {
public static Map<String, Object> transChartData(List<ChartViewFieldDTO> xAxis, List<ChartViewFieldDTO> yAxis, ChartViewDTO view, List<String[]> data, boolean isDrill) {
Map<String, Object> map = new HashMap<>();
List<String> x = new ArrayList<>();
List<Series> 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<AxisChartDataAntVDTO> 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<ChartDimensionDTO> dimensionList = new ArrayList<>();
List<ChartQuotaDTO> 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;
}

View File

@ -41,6 +41,9 @@ public class ApiUtils {
};
List<ApiDefinition> 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<ApiDefinition> 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<String[]> 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<Map<String, Object>> field){
private static void previewNum(List<Map<String, Object>> field) {
for (Map<String, Object> stringObjectMap : field) {
JSONArray newArray = new JSONArray();
if (stringObjectMap.get("value") != null) {
@ -202,7 +224,7 @@ public class ApiUtils {
TypeReference<JSONArray> listTypeReference = new TypeReference<JSONArray>() {
};
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<ApiDefinition> params(DatasourceRequest datasourceRequest) {
TypeReference<List<ApiDefinition>> listTypeReference = new TypeReference<List<ApiDefinition>>() {
};
List<ApiDefinition> 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<ApiDefinition> apiDefinitionList = new ArrayList<>();
TypeReference<List<ApiDefinition>> listTypeReference = new TypeReference<List<ApiDefinition>>() {

View File

@ -107,6 +107,8 @@ public class DatasourceServer implements DatasourceApi {
all_scope, add_scope
}
private TypeReference<List<ApiDefinition>> listTypeReference = new TypeReference<List<ApiDefinition>>() {
};
@Resource
private CommonThreadPool commonThreadPool;
@ -505,11 +507,11 @@ public class DatasourceServer implements DatasourceApi {
DEException.throwException("不存在的数据源!");
}
BeanUtils.copyBean(datasourceDTO, datasource);
TypeReference<List<ApiDefinition>> listTypeReference = new TypeReference<List<ApiDefinition>>() {
};
if (datasourceDTO.getType().equalsIgnoreCase(DatasourceConfiguration.DatasourceType.API.toString())) {
List<ApiDefinition> apiDefinitionList = JsonUtil.parseList(datasourceDTO.getConfiguration(), listTypeReference);
List<ApiDefinition> apiDefinitionListWithStatus = new ArrayList<>();
List<ApiDefinition> 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<String, String> 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<ApiDefinition> 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())));

View File

@ -4,7 +4,7 @@
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/dataease.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>DataEase</title>
<title></title>
</head>
<body>
<div id="app"></div>

View File

@ -19,7 +19,7 @@ export const useAppStore = defineStore('app', {
return {
size: true, // 尺寸图标
pageLoading: false, // 路由跳转loading
title: 'DataEase',
title: '',
dekey: 'DataEaseKey',
isDataEaseBi: false,
isIframe: false,

View File

@ -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"]')

View File

@ -394,7 +394,6 @@ export class RangeBar extends G2PlotChartView<BarOptions, Bar> {
this.configXAxis,
this.configYAxis,
this.configSlider,
this.configAnalyseHorizontal,
this.configEmptyDataStrategy
)(chart, options)
}

View File

@ -238,12 +238,19 @@ export const quotaViews = ['label', 'richTextView', 'indicator', 'gauge', 'liqui
export function handleEmptyDataStrategy<O extends PickOptions>(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<string, any>[])
}
} else {
handleIgnoreData(data)
}
return options
}
const { yAxis, xAxisExt, extStack } = chart
@ -252,7 +259,13 @@ export function handleEmptyDataStrategy<O extends PickOptions>(chart: Chart, opt
case 'breakLine': {
if (multiDimension) {
// 多维度保持空
handleBreakLineMultiDimension(data)
if (isChartMix) {
for (let i = 0; i < data.length; i++) {
handleBreakLineMultiDimension(data[i] as Record<string, any>[])
}
} else {
handleBreakLineMultiDimension(data)
}
}
return {
...options,
@ -262,10 +275,22 @@ export function handleEmptyDataStrategy<O extends PickOptions>(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<string, any>[])
}
} else {
handleSetZeroMultiDimension(data)
}
} else {
// 单维度置0
handleSetZeroSingleDimension(data)
if (isChartMix) {
for (let i = 0; i < data.length; i++) {
handleSetZeroSingleDimension(data[i] as Record<string, any>[])
}
} else {
handleSetZeroSingleDimension(data)
}
}
break
}

View File

@ -80,6 +80,7 @@
min="0"
max="1440"
size="small"
@input="v => handleInput(v, scope.$index)"
@change="val => validateExp(val, scope.$index)"
/>
<span v-else>
@ -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

View File

@ -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<ApiConfiguration[]>([])
let paramsList = reactive<ApiConfiguration[]>([])
let apiItem = reactive<ApiItem>({
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<FormInstance>()
const isNumber = (rule, value, callback) => {
@ -152,9 +156,16 @@ const rule = reactive<FormRules>({
})
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({
<api-http-request-form
v-if="edit_api_item"
:request="apiItem.request"
:value-list="valueList"
@changeId="changeId"
/>
</el-form-item>
@ -572,7 +586,11 @@ defineExpose({
</template>
</el-table-column>
<el-table-column prop="deExtractType" :label="t('datasource.field_type')">
<el-table-column
prop="deExtractType"
:label="t('datasource.field_type')"
:disabled="apiItem.type == 'params'"
>
<template #default="scope">
<el-select
v-model="scope.row.deExtractType"

View File

@ -22,6 +22,10 @@ const props = defineProps({
type: Boolean,
default: true
},
valueList: {
type: Array as PropType<Item[]>,
default: () => []
},
request: {
type: Object as PropType<ApiRequest>,
default: () => ({
@ -143,6 +147,7 @@ const emits = defineEmits(['changeId'])
:show-desc="true"
:suggestions="headerSuggestions"
:items="apiRequest.headers"
:value-list="valueList"
/>
</el-tab-pane>

View File

@ -22,6 +22,10 @@ const props = defineProps({
type: Array as PropType<Item[]>,
default: () => []
},
valueList: {
type: Array as PropType<Item[]>,
default: () => []
},
suggestions: {
type: Array,
default: () => []
@ -78,7 +82,6 @@ const options = [
value: 'fixed'
}
]
const value = ref('')
</script>
@ -91,7 +94,7 @@ const value = ref('')
<el-icon class="drag handle">
<Icon name="icon_drag_outlined"></Icon>
</el-icon>
<el-col :span="activeName === 'third' ? 8 : 6" v-if="!unShowSelect">
<el-col :span="activeName === 'params' ? 8 : 6" v-if="!unShowSelect">
<el-input
v-if="!suggestions"
v-model="element.name"
@ -110,8 +113,8 @@ const value = ref('')
show-word-limit
/>
</el-col>
<el-col :span="3" v-if="activeName === 'fourth'">
<el-select v-model="value">
<el-col :span="3" v-if="activeName === 'table'">
<el-select v-model="element.nameType">
<el-option
v-for="item in options"
:key="item.value"
@ -131,19 +134,31 @@ const value = ref('')
/>
</el-col>
<el-col :span="activeName === 'third' ? 7 : 6">
<el-col :span="activeName === 'params' ? 7 : 6">
<el-input
v-if="!needMock && activeName === 'third'"
v-if="!needMock && activeName === 'params'"
v-model="element.value"
:disabled="isReadOnly"
:placeholder="unShowSelect ? t('common.description') : valueText"
show-word-limit
/>
<el-select
v-model="element.value"
v-if="!needMock && activeName === 'table' && element.nameType === 'params'"
>
<el-option
v-for="item in valueList"
:key="item.originName"
:label="item.name"
:value="item.originName"
/>
</el-select>
<el-input
v-if="!needMock && activeName === 'fourth'"
v-if="!needMock && activeName === 'table' && element.nameType !== 'params'"
v-model="element.value"
:disabled="isReadOnly"
:placeholder="value === 'params' ? '参数名称' : '值'"
:placeholder="'值'"
show-word-limit
/>
</el-col>

View File

@ -27,6 +27,7 @@ const prop = defineProps({
syncSetting?: SyncSetting
configuration?: Configuration
apiConfiguration?: ApiConfiguration[]
paramsConfiguration?: ApiConfiguration[]
}>({
id: 0,
name: '',
@ -80,6 +81,7 @@ const defaultApiItem = {
name: '',
deTableName: '',
url: '',
type: '',
serialNumber: 0,
method: 'GET',
request: {
@ -319,17 +321,24 @@ const addApiItem = item => {
apiItem = cloneDeep(item)
} else {
apiItem = cloneDeep(defaultApiItem)
apiItem.serialNumber =
apiItem.type = activeName.value
let serialNumber1 =
form.value.apiConfiguration.length > 0
? form.value.apiConfiguration[form.value.apiConfiguration.length - 1].serialNumber + 1
: 0
let serialNumber2 =
form.value.paramsConfiguration.length > 0
? form.value.paramsConfiguration[form.value.paramsConfiguration.length - 1].serialNumber + 1
: 0
apiItem.serialNumber = serialNumber1 + serialNumber2
}
nextTick(() => {
editApiItem.value.initApiItem(apiItem, form.value.apiConfiguration, activeName.value)
editApiItem.value.initApiItem(apiItem, form.value, activeName.value)
})
}
const activeName = ref('third')
const activeName = ref('table')
const showPriority = ref(false)
const deleteItem = (item, idx) => {
@ -354,15 +363,28 @@ const resetForm = () => {
const returnItem = apiItem => {
var find = false
for (let i = 0; i < form.value.apiConfiguration.length; i++) {
if (form.value.apiConfiguration[i].serialNumber === apiItem.serialNumber) {
find = true
form.value.apiConfiguration[i] = apiItem
if (apiItem.type !== 'params') {
for (let i = 0; i < form.value.apiConfiguration.length; i++) {
if (form.value.apiConfiguration[i].serialNumber === apiItem.serialNumber) {
find = true
form.value.apiConfiguration[i] = apiItem
}
}
if (!find) {
state.itemRef = []
form.value.apiConfiguration.push(apiItem)
}
} else {
for (let i = 0; i < form.value.paramsConfiguration.length; i++) {
if (form.value.paramsConfiguration[i].serialNumber === apiItem.serialNumber) {
find = true
form.value.paramsConfiguration[i] = apiItem
}
}
if (!find) {
state.itemRef = []
form.value.paramsConfiguration.push(apiItem)
}
}
if (!find) {
state.itemRef = []
form.value.apiConfiguration.push(apiItem)
}
}
@ -476,12 +498,6 @@ const apiRule = {
const dialogEditParams = ref(false)
const dialogRenameApi = ref(false)
const activeParamsName = ref('')
const apiParams = ref([
{
id: 1,
name: '接口1'
}
])
const paramsObj = ref({
name: '',
id: 1,
@ -490,7 +506,7 @@ const paramsObj = ref({
const apiObj = ref({
name: '',
id: 1
serialNumber: 1
})
const paramsObjRules = {
name: [
@ -524,6 +540,7 @@ const apiObjRules = {
]
}
const setActiveName = val => {
gridData.value = val.fields
activeParamsName.value = val.name
}
@ -545,12 +562,13 @@ const saveParamsObj = () => {
const saveApiObj = () => {
apiObjRef.value.validate(result => {
if (result) {
apiParams.value.forEach(ele => {
if (ele.id === apiObj.value.id) {
form.value.paramsConfiguration.forEach(ele => {
if (ele.serialNumber === apiObj.value.serialNumber) {
ele.name = apiObj.value.name
}
})
}
dialogRenameApi.value = false
})
}
@ -562,17 +580,12 @@ const apiResetForm = () => {
dialogRenameApi.value = false
}
const gridData = ref([
{
name: 'name',
deType: 0,
id: 0
}
])
const gridData = ref([])
const handleApiParams = (cmd: string, data) => {
if (cmd === 'rename') {
dialogRenameApi.value = true
paramsObj.value.name = data.name
apiObj.value.name = data.name
apiObj.value.serialNumber = data.serialNumber
}
if (cmd === 'delete') {
ElMessageBox.confirm('确定删除吗?', {
@ -581,7 +594,10 @@ const handleApiParams = (cmd: string, data) => {
autofocus: false,
showClose: false
}).then(() => {
apiParams.value.splice(0, 1)
form.value.paramsConfiguration.splice(0, 1)
if (activeParamsName.value === data.name) {
gridData.value = []
}
})
}
@ -601,7 +617,7 @@ const delParams = data => {
autofocus: false,
showClose: false
}).then(() => {
apiParams.value.splice(0, 1)
gridData.value.splice(0, 1)
})
}
const datasetTypeList = [
@ -668,8 +684,8 @@ defineExpose({
<template v-if="form.type === 'API'">
<div class="title-form_primary flex-space table-info-mr" v-show="activeStep !== 2">
<el-tabs v-model="activeName" class="api-tabs">
<el-tab-pane :label="t('datasource.data_table')" name="third"></el-tab-pane>
<el-tab-pane label="接口参数" name="fourth"></el-tab-pane>
<el-tab-pane :label="t('datasource.data_table')" name="table"></el-tab-pane>
<el-tab-pane label="接口参数" name="params"></el-tab-pane>
</el-tabs>
<el-button type="primary" style="margin-left: auto" @click="() => addApiItem(null)">
<template #icon>
@ -680,11 +696,11 @@ defineExpose({
</div>
<empty-background
v-show="activeStep !== 2"
v-if="!form.apiConfiguration.length"
v-if="!form.apiConfiguration.length && activeName === 'table'"
:description="t('datasource.no_data_table')"
img-type="noneWhite"
/>
<template v-if="form.type === 'API' && activeStep === 1 && activeName === 'third'">
<template v-if="form.type === 'API' && activeStep === 1 && activeName === 'table'">
<div class="api-card-content">
<div
v-for="(api, idx) in form.apiConfiguration"
@ -759,11 +775,11 @@ defineExpose({
</template>
<div
style="display: flex"
v-if="form.type === 'API' && activeStep === 1 && activeName === 'fourth'"
v-if="form.type === 'API' && activeStep === 1 && activeName === 'params'"
>
<div class="left-api_params">
<div
v-for="ele in apiParams"
v-for="ele in form.paramsConfiguration"
:class="[{ active: activeParamsName === ele.name }]"
class="list-item_primary"
:title="ele.name"
@ -812,12 +828,6 @@ defineExpose({
<el-table-column :label="t('common.operate')">
<template #default="scope">
<el-button text @click.stop="editParams(scope.row)">
<template #icon>
<Icon name="icon_edit_outlined"></Icon>
</template>
</el-button>
<el-button text @click.stop="delParams(scope.row)">
<template #icon>
<Icon name="icon_delete-trash_outlined"></Icon>
@ -1217,7 +1227,7 @@ defineExpose({
<el-form
label-position="top"
require-asterisk-position="right"
ref="paramsObjRef"
ref="apiObjRef"
@keydown.stop.prevent.enter
:model="apiObj"
:rules="apiObjRules"

View File

@ -36,6 +36,7 @@ interface Form {
type: string
configuration?: Configuration
apiConfiguration?: ApiConfiguration[]
paramsConfiguration?: ApiConfiguration[]
syncSetting?: SyncSetting
}
@ -353,7 +354,10 @@ const saveDS = () => {
request.apiConfiguration[i].fields[j].value = []
}
}
request.configuration = Base64.encode(JSON.stringify(request.apiConfiguration))
let apiItems = []
apiItems = apiItems.concat(request.apiConfiguration)
apiItems = apiItems.concat(request.paramsConfiguration)
request.configuration = Base64.encode(JSON.stringify(apiItems))
request.syncSetting.startTime = new Date(request.syncSetting.startTime).getTime()
request.syncSetting.endTime = new Date(request.syncSetting.endTime).getTime()
} else {
@ -421,7 +425,8 @@ const defaultForm = {
name: '',
description: '',
type: 'API',
apiConfiguration: []
apiConfiguration: [],
paramsConfiguration: []
}
const form = reactive<Form>(cloneDeep(defaultForm))
const defaultForm2 = {

View File

@ -141,6 +141,7 @@ export interface Configuration {
export interface ApiConfiguration {
id: string
name: string
type: string
deTableName: string
method: string
url: string
@ -176,6 +177,7 @@ export interface Node {
editType?: number
configuration?: Configuration
apiConfiguration?: ApiConfiguration[]
paramsConfiguration?: ApiConfiguration[]
weight?: number
lastSyncTime?: number | string
}

View File

@ -471,6 +471,7 @@ const handleNodeClick = data => {
configuration,
syncSetting,
apiConfigurationStr,
paramsStr,
fileName,
size,
description,
@ -482,6 +483,9 @@ const handleNodeClick = data => {
if (apiConfigurationStr) {
apiConfigurationStr = JSON.parse(Base64.decode(apiConfigurationStr))
}
if (paramsStr) {
paramsStr = JSON.parse(Base64.decode(paramsStr))
}
Object.assign(nodeInfo, {
name,
pid,
@ -496,6 +500,7 @@ const handleNodeClick = data => {
configuration,
syncSetting,
apiConfiguration: apiConfigurationStr,
paramsConfiguration: paramsStr,
weight: data.weight,
lastSyncTime
})
@ -587,6 +592,7 @@ const editDatasource = (editType?: number) => {
configuration,
syncSetting,
apiConfigurationStr,
paramsStr,
fileName,
size,
description,
@ -595,6 +601,9 @@ const editDatasource = (editType?: number) => {
if (configuration) {
configuration = JSON.parse(Base64.decode(configuration))
}
if (paramsStr) {
paramsStr = JSON.parse(Base64.decode(paramsStr))
}
if (apiConfigurationStr) {
apiConfigurationStr = JSON.parse(Base64.decode(apiConfigurationStr))
}
@ -613,6 +622,7 @@ const editDatasource = (editType?: number) => {
configuration,
syncSetting,
apiConfiguration: apiConfigurationStr,
paramsConfiguration: paramsStr,
lastSyncTime
})
datasourceEditor.value.init(datasource)

View File

@ -28,4 +28,5 @@ public class ApiDefinition {
private String orgName;
private boolean showApiStructure;
private Long updateTime;
private String type = "table";
}

View File

@ -46,6 +46,7 @@ public class DatasourceDTO implements Serializable {
private String configuration;
private String apiConfigurationStr;
private String paramsStr;
/**
* Create timestamp

View File

@ -0,0 +1,14 @@
package io.dataease.extensions.view.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.List;
import java.util.Map;
@Data
@AllArgsConstructor
public class AxisFormatResult {
private Map<ChartAxis, List<ChartViewFieldDTO>> axisMap;
private Map<String, Object> context;
}

View File

@ -0,0 +1,13 @@
package io.dataease.extensions.view.dto;
public enum ChartAxis {
xAxis,
xAxisExt,
extStack,
extLabel,
extTooltip,
yAxis,
yAxisExt,
drill,
extBubble;
}

View File

@ -0,0 +1,18 @@
package io.dataease.extensions.view.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.List;
import java.util.Map;
@Data
public class ChartCalcDataResult {
private Map<String, Object> data;
private List<String[]> originData;
private List<String[]> assistData;
private List<ChartSeniorAssistDTO> dynamicAssistFields;
private Map<String, Object> context;
// TODO 数据源插件化之后换成整个请求对象
private String querySql;
}

View File

@ -1,5 +1,6 @@
package io.dataease.extensions.view.dto;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import java.io.Serializable;
@ -23,4 +24,10 @@ public class ChartViewFieldDTO extends ChartViewFieldBaseDTO implements Serializ
private String busiType;
private boolean isAgg;
/**
* 字段来源
*/
@JsonIgnore
private FieldSource source;
}

View File

@ -0,0 +1,14 @@
package io.dataease.extensions.view.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.List;
import java.util.Map;
@Data
@AllArgsConstructor
public class CustomFilterResult {
private List<ChartExtFilterDTO> filterList;
private Map<String, Object> context;
}

View File

@ -0,0 +1,5 @@
package io.dataease.extensions.view.dto;
public enum FieldSource {
DRILL
}

View File

@ -0,0 +1,87 @@
package io.dataease.extensions.view.util;
import io.dataease.extensions.view.dto.ChartViewFieldDTO;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import java.util.*;
public class ChartDataUtil {
// 对结果排序
public static List<String[]> resultCustomSort(List<ChartViewFieldDTO> xAxis, List<String[]> data) {
List<String[]> res = new ArrayList<>(data);
if (xAxis.size() > 0) {
// 找到对应维度
for (int i = 0; i < xAxis.size(); i++) {
ChartViewFieldDTO item = xAxis.get(i);
if (StringUtils.equalsIgnoreCase(item.getSort(), "custom_sort")) {
// 获取自定义值与data对应列的结果
if (i > 0) {
// 首先根据优先级高的字段分类在每个前置字段相同的组里排序
Map<String, List<String[]>> map = new LinkedHashMap<>();
for (String[] d : res) {
StringBuilder stringBuilder = new StringBuilder();
for (int j = 0; j < i; j++) {
if (StringUtils.equalsIgnoreCase(xAxis.get(j).getSort(), "none")) {
continue;
}
stringBuilder.append(d[j]);
}
if (ObjectUtils.isEmpty(map.get(stringBuilder.toString()))) {
map.put(stringBuilder.toString(), new ArrayList<>());
}
map.get(stringBuilder.toString()).add(d);
}
Iterator<Map.Entry<String, List<String[]>>> iterator = map.entrySet().iterator();
List<String[]> list = new ArrayList<>();
while (iterator.hasNext()) {
Map.Entry<String, List<String[]>> next = iterator.next();
list.addAll(customSort(Optional.ofNullable(item.getCustomSort()).orElse(new ArrayList<>()), next.getValue(), i));
}
res.clear();
res.addAll(list);
} else {
res = customSort(Optional.ofNullable(item.getCustomSort()).orElse(new ArrayList<>()), res, i);
}
}
}
}
return res;
}
public static List<String[]> customSort(List<String> custom, List<String[]> data, int index) {
List<String[]> res = new ArrayList<>();
List<Integer> indexArr = new ArrayList<>();
List<String[]> joinArr = new ArrayList<>();
for (int i = 0; i < custom.size(); i++) {
String ele = custom.get(i);
for (int j = 0; j < data.size(); j++) {
String[] d = data.get(j);
if (StringUtils.equalsIgnoreCase(ele, d[index])) {
joinArr.add(d);
indexArr.add(j);
}
}
}
// 取得 joinArr 就是两者的交集
List<Integer> indexArrData = new ArrayList<>();
for (int i = 0; i < data.size(); i++) {
indexArrData.add(i);
}
List<Integer> indexResult = new ArrayList<>();
for (int i = 0; i < indexArrData.size(); i++) {
if (!indexArr.contains(indexArrData.get(i))) {
indexResult.add(indexArrData.get(i));
}
}
List<String[]> subArr = new ArrayList<>();
for (int i = 0; i < indexResult.size(); i++) {
subArr.add(data.get(indexResult.get(i)));
}
res.addAll(joinArr);
res.addAll(subArr);
return res;
}
}

View File

@ -0,0 +1,18 @@
package io.dataease.extensions.view.util;
import io.dataease.extensions.view.dto.ChartViewFieldBaseDTO;
import io.dataease.extensions.view.dto.DatasetTableFieldDTO;
import org.springframework.beans.BeanUtils;
import java.util.List;
import java.util.stream.Collectors;
public class FieldUtil {
public static List<DatasetTableFieldDTO> transFields(List<? extends ChartViewFieldBaseDTO> list) {
return list.stream().map(ele -> {
DatasetTableFieldDTO dto = new DatasetTableFieldDTO();
BeanUtils.copyProperties(dto, ele);
return dto;
}).collect(Collectors.toList());
}
}